8

I'm trying to manually verify signatures of Apple iOS Passbook files, which are PKCS #7 detached signatures of the RSA key of the Apple developer who created the file.

Which means there's a file "signature" which is the detached signature of a "manifest.json" file. I'm using the novelty "Titanic boarding pass" pkpass file from http://www.flonsolutions.com/fantastic_voyages.html for testing. Doing:

openssl smime -verify -in signature -content manifest.json -inform der -noverify

comes back with success, so I know the signature should be valid. Now, parsing apart the signature file, I can have decoded the DER-encoded ASN.1 data and shows that the attribute being signed is a SHA1 digest of the message, resulting in 733538fde88843c7ad24fb71674dbdd372df7b4d1. Running openssl sha1 manifest.json shows that indeed the SHA1 of that file is indeed 7335...b4d1.

Now, parsing out the SignerInfo bits of signature, I can grab the OctetString that's the RSA encryption of their signature:

BC C5 F9 F2 53 FD 2C 13 EA CE 64 BB 89 85 60 82 78 63 5B 04 FA F8 BF 7E 2A 6C 20 
5D C3 C8 E8 8A 2F E3 4D B9 8E 1C A1 42 DF 2B 46 89 76 63 0B 8A DD E5 8A 69 4E D0
CF 3F E7 36 1E F8 7F 49 0D 27 EC 0F 73 76 5D 62 A1 4E 8A 43 AB EC ED 2E CD E7 69
3F AD 32 48 0A 79 52 DB 36 5B 61 94 71 3F B3 09 1E 80 17 94 31 06 AF E6 A3 A5 A0
D6 B7 71 31 ED 4C 6F C1 5C B6 4B 79 E5 7A BA BC 1D AD BB D2 F7 39 05 16 73 2C AE
74 E3 9C 4F 7E A7 B1 90 38 FC 92 78 9F 70 C0 D0 94 83 83 EC 01 F4 B6 16 36 4B EE
BC BA DD AC 23 64 4B C2 93 21 9E 9B 21 64 9E 7C 1B 72 87 0B C1 7D 9C 6A 9B AA AB
36 67 F8 7C 7B 8D 9E 88 FC 95 C8 29 57 8B EB B9 5C F6 AB 59 64 CA 87 ED DE 50 BA
67 C0 26 F8 5B FD 47 10 B0 A6 4E D8 D6 F0 E9 A0 DE 2B 6B D4 84 2A 91 A6 A7 27 22
CE D6 5F D2 C7 87 56 A4 E6 E4 D6 D3 C9

Using the certificate's Public Key from earlier in the signature file:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzEjQiB/QgOWX2QF6CGtCiq1ZDyRzJJKJ
4ZW6cuF2MdtOi4If+IhTHcVkdeJ+/cacuRFcscNOXODjriCbAbmTVYTFx290n4vQ1qvPuu3/T41f
4dZHvAM9dmUHuN7M/f/SyGWJiFSYj3VY7S+jyH5zvskGp84YNkHB/Uky3ZFZElOwoOltRNVL25Rw
52nIMVrqO+Cyn2T2LSkk/6yjSll46TyjYuTDEev4XvYhIQBfbraP9rUabRkf1k0EuXl7qM2GeKGM
vq9sQwMRPVFFM2Fa/8xUeA4D/4AWR4S4shuVUxWOx8bq57RNRDogTr4rotaAOyDACu0aS37fWJmQ
zExr3QIDAQAB
-----END PUBLIC KEY-----

I can successfully decode the RSA encryption and get a result. The result of the decryption is another ASN.1 DER-encoded string, which is:

30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 5B AC 45 51 B9 A5 51 68 28 89
51 59 1F 62 31 9B A7 15 50 CB

Parsing that out, it's indicating that 5bac4551b9a55168288951591f62319ba71550cb is the SHA1 hash of something. But that's not the SHA1 of manifest.json (5bac...50cb != 7335...b4d1).

So, what am I supposed to be comparing that decrypted SHA1 to? I know that the owner of that certificate encrypted this particular DER-encoded string, but I don't see how they match. What part of the RSA/PKCS7 process am I missing here?

mpromonet
  • 107
  • 4

1 Answers1

6

The digest calculation is described in CMS (the new name for PKCS#7), section 5.4. Namely, when there are signed attributes, then what is signed is an encoding of the set of attributes; since one of the attributes contains the hash of the data file on which the signature object applies, this signature extends to the data file. See this paragraph:

A separate encoding of the signedAttrs field is performed for message digest calculation. The IMPLICIT [0] tag in the signedAttrs is not used for the DER encoding, rather an EXPLICIT SET OF tag is used. That is, the DER encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0] tag, MUST be included in the message digest calculation along with the length and content octets of the SignedAttributes value.

so the hash should be computed over the complete encoding of the SignedAttributes value, except that you replace the first byte (which should be 0xA0) with the byte which encodes a universal tag SET OF (that's 0x31, if I remember correctly).

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949