code-signing-certificate - 当我们使用 signtool 签署 msix 应用程序时,是什么决定了附加的字符串
问题描述
我去年买了一个代码签名证书并使用签名工具签署了一个 msix 包
sign /f
"$SigningKeyFilePath" /fd SHA256 /v /a /p $SigningKeyPassword "$Package"
安装后生成的 msix 包在 AppData 目录中创建了一个名为 PackageName_244zpcd23egta 的文件夹,因为证书的有效期只有一年,我们必须获得一个新证书,我们被告知我们不能更新现有的证书。
现在用新证书签名后创建的文件夹不同了PackageName_123zwerd23ewea
,这意味着我们无法更新以前安装的应用程序。MSIX 安装程序返回错误,说明已安装了具有相同名称的先前应用程序。
我想知道我们将来如何防止这个问题?什么决定了文件夹末尾的 _ranowm_looking_number?我注意到新证书没有密码。这能让这件事发生吗?或者我们应该始终坚持更新证书(如果可能的话)而不是获得新证书?
解决方案
附加在字符串末尾的块是发布者哈希,根据您的主题(发布者)计算得出。它是一个 13 个字符的字符串,以 base32 编码表示您的证书专有名称的 SHA-256 哈希的前几个字节。
该算法相对简单:
- 采用包含出版商名称(证书 DN)的 UTF-16 字符串(原样,包含所有空格和标点符号)
- 计算此字符串的字节表示的 SHA-256 哈希
- 取前 8 个字节(64 位)
- 将二进制值向右填充一个零位(= 左移所有位)
- 将位分组为 5 个组(因为我们有 64 + 1 个位,我们应该得到 13 个组,每个组有 5 个字节)
- 对于每个组,将位表示转换为整数,并在将数字映射到字母和数字的替换表中执行查找。
- 将字母连接在一起并将它们变为小写以接收发布者哈希。
例如,这可以通过以下 PowerShell 完成
function Get-PublisherHash($publisherName)
{
$publisherNameAsUnicode = [System.Text.Encoding]::Unicode.GetBytes($publisherName);
$publisherSha256 = [System.Security.Cryptography.HashAlgorithm]::Create("SHA256").ComputeHash($publisherNameAsUnicode);
$publisherSha256First8Bytes = $publisherSha256 | Select-Object -First 8;
$publisherSha256AsBinary = $publisherSha256First8Bytes | ForEach-Object { [System.Convert]::ToString($_, 2).PadLeft(8, '0') };
$asBinaryStringWithPadding = [System.String]::Concat($publisherSha256AsBinary).PadRight(65, '0');
$encodingTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
$result = "";
for ($i = 0; $i -lt $asBinaryStringWithPadding.Length; $i += 5)
{
$asIndex = [System.Convert]::ToInt32($asBinaryStringWithPadding.Substring($i, 5), 2);
$result += $encodingTable[$asIndex];
}
return $result.ToLower();
}
例如:
Get-PublisherHash "CN=SomeName, DN=Some Domain"
> qwz5zh2hhehvm
证书的任何更改(发布者名称更改)都意味着哈希完全不同。由于哈希是 MSIX 系列名称及其完整包名称的一部分,因此新应用程序被视为另一个应用程序。
在最近的一些改变它的努力中(Insider Builds 22000 和更新版本)有一个叫做“持久身份”的功能,即使证书发生变化,它也可以用来提供平滑的升级体验。
资源: