Integrating CryptoTokenKit with productsign

Hi all,

I'm using a CryptoTokenKit (CTK) extension to perform code signing without having the private key stored on my laptop. The extension currently only supports the rsaSignatureDigestPKCS1v15SHA256 algorithm:

func tokenSession(_ session: TKTokenSession, supports operation: TKTokenOperation, keyObjectID: TKToken.ObjectID, algorithm: TKTokenKeyAlgorithm) -> Bool {
    return algorithm.isAlgorithm(SecKeyAlgorithm.rsaSignatureDigestPKCS1v15SHA256)
}

This setup works perfectly with codesign, and signing completes without any issues.

However, when I try to use productsign, the system correctly detects and delegates signing to my CTK extension, but it seems to always request rsaSignatureDigestPKCS1v15SHA1 instead:

productsign --timestamp --sign <identity> unsigned.pkg signed.pkg
productsign: using timestamp authority for signature
productsign: signing product with identity "Developer ID Installer: <org> (<team>)" from keychain (null)
...
Error Domain=NSOSStatusErrorDomain Code=-50
"algid:sign:RSA:digest-PKCS1v15:SHA1: algorithm not supported by the key"
...
productsign: error: Failed to sign the product.

From what I understand, older versions of macOS used SHA1 for code signing, but codesign has since moved to SHA256 (at least when legacy compatibility isn't a concern). Oddly, productsign still seems to default to SHA1, even in 2025.

Is there a known way to force productsign to use SHA256 instead of SHA1 for the signature digest algorithm? Or is there some flag or configuration I'm missing?

Thanks in advance!

Answered by DTS Engineer in 840447022

I had a chat with our installer folks about this and our current understanding is that there’s no way to sign an installer package without supporting SHA-1. So, if you want to sign installer packages, you’ll have to start doing this:

working with our provider to temporarily support SHA1

)-:

Which leads to this:

which they’ve deprecated for security reasons

That’s completely understandable, and we’re definitely open to improving this on our side. Please file a bug requesting that product{sign,build} support SHA-256. Once you’re done, post your bug number and I’ll make sure the right folks see it.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I’ve not looked into the installer package side of this in depth but, in general, the transition from SHA1 to SHA256 is driven by the deployment target. If your product supports old releases, the system has to include both hashes to ensure compatibility with those systems.

Now, with codesign I’m familiar with how that’s controlled, that is, via various Mach-O load commands. You can dump these using vtool.

For installer packages, the productbuild man page described how you set the minimum supported OS version. Are you doing that?

And just for testing, try setting it way up, to something silly like macOS 15. If that works, you can then step it back to determine the inflexion point.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Unfortunately, I’ve already tried similar approaches. Even when explicitly setting a minimum macOS version of 15.0 in the distribution file, productsign still insists on using SHA1:

<allowed-os-versions>
    <os-version min="15.0"/>
</allowed-os-versions>

So far, this hasn’t had any effect on the digest algorithm used during signing.

@DTS Engineer So far, I haven’t been able to get productsign to work with anything other than algid:sign:RSA:digest-PKCS1v15:SHA1.

Is there any way we could get a definitive confirmation on whether alternative algorithms are supported or not? This would help us decide where to focus our efforts — either on the macOS side, or on working with our provider to temporarily support SHA1 (which they’ve deprecated for security reasons).

Installer packages support two different types of signing:

  • The old school mechanism (prior to macOS 10.8) adds signed data directly.

  • The current mechanism uses CMS.

The current mechanism uses CMS in much the same way as code signing. That’s what allows modern installer packages to include a secure timestamp [1].

It seems that our tools still include both types of signature. I took an installer package I built on macOS 15.4 and dumped the signatures using the <xar/xar.h> API:

  • xar_signature_type returns the signature type.

  • xar_signature_copy_signed_data returns the signature data.

The first signature was of type RSA, and it’s the old school signature I discussed above. The second is of type CMS. Calling xar_signature_copy_signed_data on that, I get back a CMS blob, which I dumped with:

% openssl cms -in sig1.dat -inform der -noout -cmsout -print

Note There’s a bunch of zero padding at the end of the CMS for… well… reasons |-:

AFAICT this has none of the ‘hash agility’ I see in code signatures. It seems to be tied to SHA-1.

But maybe I’m reading this wrong. I’m gonna do a bit more digging and get back to you.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] For an explanation of that concept, see TN3161 Inside Code Signing: Certificates. It’s focus is on code signing but, as I mentioned, the current installer package infrastructure uses a lot of the same mechanics.

I had a chat with our installer folks about this and our current understanding is that there’s no way to sign an installer package without supporting SHA-1. So, if you want to sign installer packages, you’ll have to start doing this:

working with our provider to temporarily support SHA1

)-:

Which leads to this:

which they’ve deprecated for security reasons

That’s completely understandable, and we’re definitely open to improving this on our side. Please file a bug requesting that product{sign,build} support SHA-256. Once you’re done, post your bug number and I’ll make sure the right folks see it.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for the clear answer — I really appreciate it.

In the meantime, I’ll follow up with our provider (AWS KMS) to see if using SHA1 is still possible today.

Also, as requested, here’s the bug report I submitted regarding this issue: FB17682555.

@DTS Engineer

Quick question — is the verification logic already able to verify .pkg files signed with SHA256? If not, that would mean even if Apple updates productsign to stop using NIST-disallowed algorithms, we still wouldn't be able to ship those .pkg files to users who haven't received the corresponding verification update.

Curious to hear your thoughts on this.

Integrating CryptoTokenKit with productsign
 
 
Q