Привет!
Довелось мне на днях столкнуться с такой напастью как p7s файл и, как вследствие этого, с Cryptographic Message Syntax (CMS). На хабре нашлась интересная статья описывающая структуру CMS данных, но в ней к сожалению нет примера, позволяющего наглядно продемонстрировать CMS на практике. Я хочу немного дополнить ту статью и разобрать внутренности файла цифровой подписи p7s.
Что же такое Cryptographic Message Syntax? Это стандарт, описывающий структуру сообщений, полученных с использованием криптографии.
В стандарте описывается шесть типов данных: data, signedData, envelopedData, signedAndEnvelopedData, digestedData, and encryptedData. В данном топике я расскажу о типе signedData (данные с электронной подписью).
Прежде всего следует сказать, что стандартный p7s файл имеет ASN.1 структуру.
ASN.1 — формат записи, с помощью которого можно описывать сложные структуры данных, состоящие из различных типов.
Приведу краткую выдержку из своего старого топика про x.509 сертификаты:
Подробное описание ASN.1 дано в статье «ASN.1 простыми словами». Я же просто расскажу какие сведения можно извлечь из самого обыкновенного p7s файла.
В стандарте CMS приводится описание структуры файла содержащего сведения об ЭЦП.
Согласно стандарту, файл с цифровой подписью в CSM формате должен содержать следующие поля:
Для того чтобы понять как это выглядит на практике подпишем произвольный набор байт тестовым сертификатом и сгенерируем p7s файл с типом SignedData.
Получившийся файл будет иметь ASN.1 структуру:
Используя ASN.1-парсер можно легко разобрать что скрывается за шестнадцатеричным кодом.
Начнем по порядку. Как видно из примера, p7s файл представляет собой одну большую структуру данных с типом SEQUENCE, включающую в себя все описанные в стандарте поля.
Открывает блок тип данных OBJECTIDENTIFIER со значением 1.2.840.113549.1.7.2 (SignedData), который однозначно дает понять с какого рода объектом мы имеем дело.
После чего один за другим следуют блоки:
Помимо приведенных выше обязательных полей в объекте с типом SignedData могут использоваться опциональные поля, такие как signedAttributes, добавляемые в блок SignerInfo. SignedAttributes добавляются при вычислении хеш-значения от подписываемых данных, поэтому изменение этих полей делает подпись недействительной.
Если блок SignedAttributes используется, то он должен содержать минимум два поля:
Рассмотрим еще один пример p7s файла, созданного с использованием SignedAttributes.
Этот пример отличается от предыдущего наличием дополнительного блока:
Именно в нем содержатся SignedAttributes. Помимо двух обязательных атрибутов при подписи был использован атрибут signedTime, который хранит время подписи.
Таким образом стандартный p7s файл представляет собой нечто гораздо большее, чем сведения об электронной подписи и открытом ключе подписанта. В нем содержится сложная структура данных, представленная в ASN.1 формате и имеющая ряд обязательных полей, позволяющих получить сведения о подписавшей стороне. А также несколько опциональных полей, которые используются при вычислении итоговой подписи.
Довелось мне на днях столкнуться с такой напастью как p7s файл и, как вследствие этого, с Cryptographic Message Syntax (CMS). На хабре нашлась интересная статья описывающая структуру CMS данных, но в ней к сожалению нет примера, позволяющего наглядно продемонстрировать CMS на практике. Я хочу немного дополнить ту статью и разобрать внутренности файла цифровой подписи p7s.
ASN.1
Что же такое Cryptographic Message Syntax? Это стандарт, описывающий структуру сообщений, полученных с использованием криптографии.
В стандарте описывается шесть типов данных: data, signedData, envelopedData, signedAndEnvelopedData, digestedData, and encryptedData. В данном топике я расскажу о типе signedData (данные с электронной подписью).
Прежде всего следует сказать, что стандартный p7s файл имеет ASN.1 структуру.
ASN.1 — формат записи, с помощью которого можно описывать сложные структуры данных, состоящие из различных типов.
Приведу краткую выдержку из своего старого топика про x.509 сертификаты:
ASN.1-кодировка описывается следующим правилом. Сперва записываются байты, характеризующий тип данных, затем последовательность байтов хранящих сведения о длине данных и лишь после этого следуют сами данные.
К примеру, для кодировки целого числа INTEGER 65537 используется следующая форма: 02 03 01 00 01.
Здесь первый байт 02, определяет тип INTEGER (полную таблицу типов вы можете найти например тут), второй байт 03 показывает длину блока. А следующие за этим байты 01 00 01, являются шестнадцатеричной записью нашего числа 65537.
В нашем случае, для описание простейшего самоподписанного сертификата, достаточно 9 типов данных. Приведем таблицу кодирования для этих типов:
Наименование типа Краткое описание Представление типа в DER-кодировке SEQUENCE Используется для описания структуры данных, состоящей из различных типов. 30 INTEGER Целое число. 02 OBJECT IDENTIFIER Последовательность целых чисел. 06 UTCTime Временной тип, содержит 2 цифры для определения года 17 GeneralizedTime Расширенный временной тип, содержит 4 цифры для обозначения года. 18 SET Описывает структуру данных разных типов. 31 UTF8String Описывает строковые данные. 0C NULL Собственно NULL 05 BIT STRING Тип для хранения последовательности бит. 03
Подробное описание ASN.1 дано в статье «ASN.1 простыми словами». Я же просто расскажу какие сведения можно извлечь из самого обыкновенного p7s файла.
Структура P7S файла
В стандарте CMS приводится описание структуры файла содержащего сведения об ЭЦП.
SignedData ::= SEQUENCE {
version CMSVersion,
digestAlgorithms DigestAlgorithmIdentifiers,
encapContentInfo EncapsulatedContentInfo,
certificates [0] IMPLICIT CertificateSet OPTIONAL,
crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
signerInfos SignerInfos }
Согласно стандарту, файл с цифровой подписью в CSM формате должен содержать следующие поля:
- CMSVersion — целое число, обозначающее версию используемого синтаксиса.
- DigestAlgorithmIdentifiers — идентификатор одной или нескольких хеш-функций которые используются при вычислении подписей.
- EncapsulatedContentInfo — собственно данные, которые были подписаны.
- CertificateSet — набор всех необходимых сертификатов, необходимых для проверки подписей.
- RevocationInfoChoices — набор списков отзыва сертификатов.
- SignerInfos — структура данных содержащая информацию о подписанте.
Для того чтобы понять как это выглядит на практике подпишем произвольный набор байт тестовым сертификатом и сгенерируем p7s файл с типом SignedData.
Получившийся файл будет иметь ASN.1 структуру:
Самый обычный файл с электронной цифровой подписью
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
Используя ASN.1-парсер можно легко разобрать что скрывается за шестнадцатеричным кодом.
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
}
}
}
}
}
Начнем по порядку. Как видно из примера, p7s файл представляет собой одну большую структуру данных с типом SEQUENCE, включающую в себя все описанные в стандарте поля.
Открывает блок тип данных OBJECTIDENTIFIER со значением 1.2.840.113549.1.7.2 (SignedData), который однозначно дает понять с какого рода объектом мы имеем дело.
После чего один за другим следуют блоки:
- version, версия синтаксиса.
INTEGER 0x01 (1 decimal)
- digestAlgorithms — идентификатор хеш-функции использовавшейся в подписи. Имеет значение SEQUENCE с двумя атрибутами: идентификатором алгоритма и пустым атрибутом со значением null.
SET { SEQUENCE { OBJECTIDENTIFIER 1.3.14.3.2.26 (id_sha1) NULL } }
- contentInfo — подписанные данные, представленные в двоичном формате. Следует уточнить, что тип signedData не обязательно должен включать в себя сами данные. В этом случае contentInfo будет включать атрибут OBJECTIDENTIFIER и пустое значение null.
SEQUENCE { OBJECTIDENTIFIER 1.2.840.113549.1.7.1 (data) [0] { OCTETSTRING 540065007300740020006D00650073007300610067006500 } }
- certificates — X509 сертификат подписавшей стороны. Если данные были подписаны несколькими лицами, блок содержит информацию о всех сертификатах, необходимых для проверки подписей.
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) } }
- SignerInfos — информация о подписавшем, содержит сведения об издателе, серийный номер сертификата подписавшего, а также идентификаторы хеш-функции и асимметричного алгоритма шифрования используемых при подписи.
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 }
Помимо приведенных выше обязательных полей в объекте с типом SignedData могут использоваться опциональные поля, такие как signedAttributes, добавляемые в блок SignerInfo. SignedAttributes добавляются при вычислении хеш-значения от подписываемых данных, поэтому изменение этих полей делает подпись недействительной.
Если блок SignedAttributes используется, то он должен содержать минимум два поля:
- Поле описывающее тип данных, содержащихся в блоке contentInfo
- Поле хранящее хеш-значение блока contentInfo
Рассмотрим еще один пример p7s файла, созданного с использованием 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
}
}
}
}
}
Этот пример отличается от предыдущего наличием дополнительного блока:
[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
}
}
}
Именно в нем содержатся SignedAttributes. Помимо двух обязательных атрибутов при подписи был использован атрибут signedTime, который хранит время подписи.
Выводы
Таким образом стандартный p7s файл представляет собой нечто гораздо большее, чем сведения об электронной подписи и открытом ключе подписанта. В нем содержится сложная структура данных, представленная в ASN.1 формате и имеющая ряд обязательных полей, позволяющих получить сведения о подписавшей стороне. А также несколько опциональных полей, которые используются при вычислении итоговой подписи.