📜 ⬆️ ⬇️

PKCS7 file structure

Hello!

It happened to me the other day to encounter such a misfortune as a p7s file and, as a result, with Cryptographic Message Syntax (CMS). On Habré there was an interesting article describing the structure of CMS data, but unfortunately there is no example that allows you to visually demonstrate CMS in practice. I want to add a little to that article and take apart the insides of the p7s digital signature file.

ASN.1


What is Cryptographic Message Syntax? This is a standard that describes the structure of messages received using cryptography.
The standard describes six data types: data, signedData, envelopedData, signedAndEnvelopedData, digestedData, and encryptedData. In this topic, I will talk about the type of signedData (data with electronic signature).

First of all, it should be noted that the standard p7s file has an ASN.1 structure.
ASN.1 is a record format with which you can describe complex data structures consisting of various types.
I will give a brief excerpt from my old topic about x.509 certificates :
ASN.1 encoding is described by the following rule. First bytes are written, characterizing the type of data, then a sequence of bytes that store information about the length of the data, and only then do the data itself follow.
')
For example, the following form is used to encode an integer INTEGER 65537: 02 03 01 00 01.
Here the first byte is 02, it defines the type of INTEGER (you can find the complete type table here, for example), the second byte 03 shows the length of the block. And the following bytes, 01 00 01, are the hexadecimal notation of our number 65537.

In our case, for the description of the simplest self-signed certificate, 9 data types are sufficient. We give the coding table for these types:
Type NameShort descriptionType View in DER Encoding
SEQUENCEUsed to describe a data structure consisting of various types.thirty
INTEGERInteger.02
OBJECT IDENTIFIERA sequence of integers.06
UTCTimeTemporary type, contains 2 digits to determine the year17
GeneralizedtimeExtended time type, contains 4 digits for the year.18
SETDescribes the structure of data of different types.31
UTF8StringDescribes string data.0C
NullActually NULL05
BIT STRINGA type for storing a sequence of bits.03


A detailed description of ASN.1 is given in the article "ASN.1 in simple words . " I’ll just tell you what information can be extracted from the ordinary p7s file.

P7S file structure


The CMS standard describes the structure of the file containing information about the digital signature.
SignedData ::= SEQUENCE { version CMSVersion, digestAlgorithms DigestAlgorithmIdentifiers, encapContentInfo EncapsulatedContentInfo, certificates [0] IMPLICIT CertificateSet OPTIONAL, crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, signerInfos SignerInfos } 

According to the standard, a file with a digital signature in the CSM format must contain the following fields:

In order to understand how it looks in practice, let us sign an arbitrary set of bytes with a test certificate and generate a p7s file with the type SignedData.
The resulting file will have an ASN.1 structure:
The most common file with a digital signature
 30 82 03 99 06 09 2A 86 48 86 F7 0D 01 07 02 A0 82 03 8A 30 82 03 86 02 01 01 31 0B 30 09 06 05 2B 0E 03 02 1A 05 00 30 27 06 09 2A 86 48 86 F7 0D 01 07 01 A0 1A 04 18 54 00 65 00 73 00 74 00 20 00 6D 00 65 00 73 00 73 00 61 00 67 00 65 00 A0 82 02 6B 30 82 02 67 30 82 01 D0 A0 03 02 01 02 02 11 00 D9 01 B8 B8 2F 74 CA 0E 8D 84 48 5A 22 65 E1 C3 30 0D 06 09 2A 86 48 86 F7 0D 01 01 05 05 00 30 21 31 10 30 0E 06 03 55 04 03 0C 07 54 65 73 74 20 43 41 31 0D 30 0B 06 03 55 04 0A 0C 04 54 65 73 74 30 1E 17 0D 31 35 30 34 32 39 31 32 33 33 32 30 5A 17 0D 31 35 30 35 30 36 31 32 33 33 32 30 5A 30 43 31 0D 30 0B 06 03 55 04 0C 0C 04 54 65 73 74 31 0D 30 0B 06 03 55 04 0B 0C 04 54 65 73 74 31 0D 30 0B 06 03 55 04 0A 0C 04 54 65 73 74 31 14 30 12 06 03 55 04 03 0C 0B 5B 54 45 53 54 5D 20 54 65 73 74 30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 81 8D 00 30 81 89 02 81 81 00 92 98 ED 87 B0 E9 DB 66 AB 06 D1 8E 7B 1B 17 40 10 98 81 D3 06 F3 B5 CA A7 FC D4 FF CB A2 2D 98 48 F9 1E 10 25 0F C6 1C 45 5D B7 A6 76 57 60 E7 BF BF DB 66 E0 D7 FC 1F 0B A1 99 1B EE C0 0D AA 76 EE 9A B8 C6 85 5D D5 C8 FA AF F8 FD 12 67 DE 6F 2D BE 5C 3E B1 88 1F 49 B2 90 AA DD B2 85 A6 46 BA 93 14 65 8C C5 20 5A AC 59 62 59 51 F1 7F BC 1E 7A D7 9F F8 8B 3B 48 2A 43 2B 7E 20 44 4B 02 03 01 00 01 A3 7D 30 7B 30 0B 06 03 55 1D 0F 04 04 03 02 04 F0 30 2C 06 03 55 1D 25 01 01 FF 04 22 30 20 06 08 2B 06 01 05 05 07 03 04 06 08 2B 06 01 05 05 07 03 02 06 0A 2B 06 01 04 01 82 37 0A 03 0C 30 1D 06 03 55 1D 0E 04 16 04 14 C7 05 8A 12 A4 B5 B7 3E F4 E5 87 6C 34 B9 BB 32 15 5E 96 91 30 1F 06 03 55 1D 23 04 18 30 16 80 14 6A E7 AB 14 AA E8 B4 C0 A8 9E 18 9D 81 68 B1 19 9F FB 25 B0 30 0D 06 09 2A 86 48 86 F7 0D 01 01 05 05 00 03 81 81 00 20 07 EF BF 72 C4 ED B8 8F B4 03 6A B8 F9 0E 16 84 89 7F B5 C5 0E 31 17 CF 80 9D B1 FB C1 C6 8B CF 3F 9C 34 51 76 21 55 29 30 E9 F3 B7 39 F5 4C E0 81 C1 04 70 67 C5 0C AE 07 80 B2 44 CB 18 3F 0E 68 67 BC EB AA 95 75 8F 7C 18 46 5B AD 96 30 70 CA 63 09 99 54 86 87 27 0A D6 DE 36 26 6A 85 64 53 B5 03 22 59 72 7F 3E 46 43 60 C2 AA EC 70 9E F7 0F 13 F5 D6 66 49 EC FE 7A 52 19 D1 27 40 31 81 DB 30 81 D8 02 01 01 30 36 30 21 31 10 30 0E 06 03 55 04 03 0C 07 54 65 73 74 20 43 41 31 0D 30 0B 06 03 55 04 0A 0C 04 54 65 73 74 02 11 00 D9 01 B8 B8 2F 74 CA 0E 8D 84 48 5A 22 65 E1 C3 30 09 06 05 2B 0E 03 02 1A 05 00 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 04 81 80 57 14 04 A3 2C 01 5B 61 B9 57 F0 02 95 0A 33 E0 94 75 CA 66 DE D0 90 93 8A E2 1A FE 6E 0B 39 C9 02 38 50 DE 7C 38 48 27 36 E9 7B FF 6C B4 DB B0 60 5C CD 78 78 54 52 54 99 A9 C4 2B 28 D7 BA AD 19 B2 6D 0D 43 B6 23 1B 5E DC B2 3E 70 FF B4 68 1D 1C 3B 6F D5 A4 0D 50 8F 55 45 7E 04 7D 2C C5 C3 80 3A 23 27 D2 E2 B4 1A 05 2E D1 3E 3A 1E 97 88 D9 12 AE B3 56 49 E9 34 97 EF 47 70 E1 66 9E 


Using the ASN.1 parser you can easily disassemble what is hidden behind the hexadecimal code.
 SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.7.2 (signedData) [0] { SEQUENCE { INTEGER 0x01 (1 decimal) SET { SEQUENCE { OBJECTIDENTIFIER 1.3.14.3.2.26 (id_sha1) NULL } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.7.1 (data) [0] { OCTETSTRING 540065007300740020006D00650073007300610067006500 } } [0] { SEQUENCE { SEQUENCE { [0] { INTEGER 0x02 (2 decimal) } INTEGER 0x00D901B8B82F74CA0E8D84485A2265E1C3 SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.1.5 (sha1WithRSAEncryption) NULL } SEQUENCE { SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.3 (commonName) UTF8String 'Test CA' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.10 (organizationName) UTF8String 'Test' } } } SEQUENCE { UTCTime '150429123320Z' UTCTime '150506123320Z' } SEQUENCE { SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.12 (title) UTF8String 'Test' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.11 (organizationalUnitName) UTF8String 'Test' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.10 (organizationName) UTF8String 'Test' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.3 (commonName) UTF8String '[TEST] Test' } } } SEQUENCE { SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.1.1 (rsaEncryption) NULL } BITSTRING 0x308189028181009298ED87B0E9DB66AB06D18E7B1B1740109881D306F3B5CAA7FCD4FFCBA22D9848F9 1E10250FC61C455DB7A6765760E7BFBFDB66E0D7FC1F0BA1991BEEC00DAA76EE9AB8C6855DD5C8FAAFF8FD1267D E6F2DBE5C3EB1881F49B290AADDB285A646BA9314658CC5205AAC59625951F17FBC1E7AD79FF88B3B482A432B7E20 444B0203010001 : 0 unused bit(s) } [3] { SEQUENCE { SEQUENCE { OBJECTIDENTIFIER 2.5.29.15 (keyUsage) OCTETSTRING 030204F0 } SEQUENCE { OBJECTIDENTIFIER 2.5.29.37 (extKeyUsage) BOOLEAN TRUE OCTETSTRING 302006082B0601050507030406082B06010505070302060A2B0601040182370A030C } SEQUENCE { OBJECTIDENTIFIER 2.5.29.14 (subjectKeyIdentifier) OCTETSTRING 0414C7058A12A4B5B73EF4E5876C34B9BB32155E9691 } SEQUENCE { OBJECTIDENTIFIER 2.5.29.35 (authorityKeyIdentifier) OCTETSTRING 301680146AE7AB14AAE8B4C0A89E189D8168B1199FFB25B0 } } } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.1.5 (sha1WithRSAEncryption) NULL } BITSTRING 0x2007EFBF72C4EDB88FB4036AB8F90E1684897FB5C50E3117CF809DB1FBC1C68BCF3F9C34517621552930E9F 3B739F54CE081C1047067C50CAE0780B244CB183F0E6867BCEBAA95758F7C18465BAD963070CA630999548687270AD6DE3 6266A856453B5032259727F3E464360C2AAEC709EF70F13F5D66649ECFE7A5219D12740 : 0 unused bit(s) } } SET { SEQUENCE { INTEGER 0x01 (1 decimal) SEQUENCE { SEQUENCE { SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.3 (commonName) UTF8String 'Test CA' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.10 (organizationName) UTF8String 'Test' } } } INTEGER 0x00D901B8B82F74CA0E8D84485A2265E1C3 } SEQUENCE { OBJECTIDENTIFIER 1.3.14.3.2.26 (id_sha1) NULL } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.1.1 (rsaEncryption) NULL } OCTETSTRING 571404A32C015B61B957F002950A33E09475CA66DED090938AE21AFE6E0B39C9023850DE7C38482736E97 BFF6CB4DBB0605CCD787854525499A9C42B28D7BAAD19B26D0D43B6231B5EDCB23E70FFB4681D1C3B6FD5A40D508F55 457E047D2CC5C3803A2327D2E2B41A052ED13E3A1E9788D912AEB35649E93497EF4770E1669E } } } } } 


Let's start in order. As you can see from the example, the p7s file is a single large data structure with the SEQUENCE type, which includes all the fields described in the standard.
Opens the data type OBJECTIDENTIFIER with a value of 1.2.840.113549.1.7.2 (SignedData), which clearly makes it clear what kind of object we are dealing with.
Then, one after another, the blocks follow:


In addition to the above required fields in an object of type SignedData, optional fields can be used, such as signedAttributes, added to the SignerInfo block. SignedAttributes are added when calculating the hash values ​​from the data being signed, so changing these fields makes the signature invalid.
If the SignedAttributes block is used, it must contain at least two fields:

Consider another example of a p7s file created using SignedAttributes.
 SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.7.2 (signedData) [0] { SEQUENCE { INTEGER 0x01 (1 decimal) SET { SEQUENCE { OBJECTIDENTIFIER 1.3.14.3.2.26 (id_sha1) NULL } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.7.1 (data) [0] { OCTETSTRING 540065007300740020006D00650073007300610067006500 } } [0] { SEQUENCE { SEQUENCE { [0] { INTEGER 0x02 (2 decimal) } INTEGER 0x00D901B8B82F74CA0E8D84485A2265E1C3 SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.1.5 (sha1WithRSAEncryption) NULL } SEQUENCE { SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.3 (commonName) UTF8String 'Test CA' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.10 (organizationName) UTF8String 'Test' } } } SEQUENCE { UTCTime '150429123320Z' UTCTime '150506123320Z' } SEQUENCE { SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.12 (title) UTF8String 'Test' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.11 (organizationalUnitName) UTF8String 'Test' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.10 (organizationName) UTF8String 'Test' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.3 (commonName) UTF8String '[TEST] Test' } } } SEQUENCE { SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.1.1 (rsaEncryption) NULL } BITSTRING 0x308189028181009298ED87B0E9DB66AB06D18E7B1B1740109881D306F3B5CAA7FCD4FFCBA22D9848F91E102 50FC61C455DB7A6765760E7BFBFDB66E0D7FC1F0BA1991BEEC00DAA76EE9AB8C6855DD5C8FAAFF8FD1267DE6F2DBE5C 3EB1881F49B290AADDB285A646BA9314658CC5205AAC59625951F17FBC1E7AD79FF88B3B482A432B7E20444B0203010001 : 0 unused bit(s) } [3] { SEQUENCE { SEQUENCE { OBJECTIDENTIFIER 2.5.29.15 (keyUsage) OCTETSTRING 030204F0 } SEQUENCE { OBJECTIDENTIFIER 2.5.29.37 (extKeyUsage) BOOLEAN TRUE OCTETSTRING 302006082B0601050507030406082B06010505070302060A2B0601040182370A030C } SEQUENCE { OBJECTIDENTIFIER 2.5.29.14 (subjectKeyIdentifier) OCTETSTRING 0414C7058A12A4B5B73EF4E5876C34B9BB32155E9691 } SEQUENCE { OBJECTIDENTIFIER 2.5.29.35 (authorityKeyIdentifier) OCTETSTRING 301680146AE7AB14AAE8B4C0A89E189D8168B1199FFB25B0 } } } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.1.5 (sha1WithRSAEncryption) NULL } BITSTRING 0x2007EFBF72C4EDB88FB4036AB8F90E1684897FB5C50E3117CF809DB1FBC1C68BCF3F9C34517621552930E9F 3B739F54CE081C1047067C50CAE0780B244CB183F0E6867BCEBAA95758F7C18465BAD963070CA630999548687270AD6DE3 6266A856453B5032259727F3E464360C2AAEC709EF70F13F5D66649ECFE7A5219D12740 : 0 unused bit(s) } } SET { SEQUENCE { INTEGER 0x01 (1 decimal) SEQUENCE { SEQUENCE { SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.3 (commonName) UTF8String 'Test CA' } } SET { SEQUENCE { OBJECTIDENTIFIER 2.5.4.10 (organizationName) UTF8String 'Test' } } } INTEGER 0x00D901B8B82F74CA0E8D84485A2265E1C3 } SEQUENCE { OBJECTIDENTIFIER 1.3.14.3.2.26 (id_sha1) NULL } [0] { SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.9.3 (contentType) SET { OBJECTIDENTIFIER 1.2.840.113549.1.7.1 (data) } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.9.5 (signingTime) SET { UTCTime '150429124539Z' } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.9.4 (messageDigest) SET { OCTETSTRING F21FA6C3A1A5756D74B11C65B7D38F7EB9F458B5 } } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.1.1 (rsaEncryption) NULL } OCTETSTRING 21D1762506C25894B98E6BD3BB11566719AEBF642B7A4541494C45F181880D936ABC28774BA575C53CC 1CB9551ABA21359FD3FA9013DE4242802674A1C304B2601183EA8015840EEF0D0D0312E361088725A255A869EEC394C 826712F684E0BA22806BD14404EA1DD80601A8C1E6598F1CCF907EE2891FB58683EEEF121D2312 } } } } } 

This example differs from the previous one in the presence of an additional block:
 [0] { SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.9.3 (contentType) SET { OBJECTIDENTIFIER 1.2.840.113549.1.7.1 (data) } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.9.5 (signingTime) SET { UTCTime '150429124539Z' } } SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.9.4 (messageDigest) SET { OCTETSTRING F21FA6C3A1A5756D74B11C65B7D38F7EB9F458B5 } } } 

It contains the SignedAttributes. In addition to the two required attributes, the signedTime attribute was used when signing, which stores the signature time.

findings


Thus, the standard p7s file is much more than the signature and public key information of the signer. It contains a complex data structure, presented in the ASN.1 format and has a number of mandatory fields that provide information about the signatory. As well as several optional fields that are used when calculating the final signature.

Source: https://habr.com/ru/post/256367/


All Articles