Skip to content
PassMaker

Signing

How to sign a .pkpass file correctly

A focused guide to Pass Type ID certificates, manifest hashing, detached PKCS#7 signatures, WWDR certificates, and final packaging.

By Swapnanil Dhol9 min read

What you’ll leave with

  • Sign manifest.json after every other file is final.
  • Embed the appropriate WWDR intermediate certificate with the signer certificate.
  • Verify certificate identity and the detached signature before shipping.

Prepare the certificate chain

Create a Pass Type ID in the Apple Developer portal and issue a certificate for it. The certificate common name and Pass Type ID extension identify the pass type it may sign, while the organizational unit identifies your Team ID. Those values must agree with passTypeIdentifier and teamIdentifier in pass.json.

Export the private key and certificate into a format your signing environment can use. Protect the private key as a production secret: do not bundle it in an app, commit it to source control, or send it to a browser client.

  • Pass Type ID certificate and matching private key
  • Current Apple WWDR intermediate certificate
  • Unexpired certificates with a chain linked to Apple Root CA
  • pass.json identifiers matching the signer identity

Build manifest.json from final bytes

Hash every file that belongs to the pass except manifest.json and signature. Keys are relative archive paths, including localization directories. Values are lowercase hexadecimal SHA-1 digests of the raw file bytes.

Generate the manifest deterministically so the same input files yield the same JSON bytes and signature. Do not rewrite, pretty-print, or normalize manifest.json after signing; the signature covers its exact bytes.

{
  "pass.json": "4f5d...9c20",
  "icon.png": "a63b...82ea",
  "[email protected]": "27aa...dd14",
  "en.lproj/pass.strings": "1c01...49f2"
}

Create the detached PKCS#7 signature

Create a detached CMS/PKCS#7 signature over manifest.json. The signature payload should include the signer certificate and WWDR intermediate so a verifier can resolve the chain without guessing which intermediate was used.

The resulting binary file is named signature with no extension. A successful signing command is not enough: immediately verify the signature against the manifest and inspect the embedded certificates, signing time, identity fields, and validity dates.

Package and verify the archive

ZIP the pass files themselves, not their parent directory. Preserve case-sensitive filenames and avoid macOS metadata such as __MACOSX and .DS_Store. The final extension is .pkpass, but the internal format remains a ZIP archive.

A complete verifier should recompute every manifest hash, ensure referenced files exist, verify the detached signature, validate certificate dates and the WWDR chain, and compare Team ID and Pass Type ID values with pass.json. Only after those checks pass should the file be distributed.

Put it into practice

Build the JSON, then verify the package.

Use the free browser tools to turn the rules in this guide into a clean starting file and an actionable validation report.

Skip the hand-assembly.

PassMaker does every step on this page on your iPhone — field editor, artwork, manifest, PKCS#7 signing and Add to Wallet — without wiring up a signing environment.

Download on the App Store

Primary references