Вопрос или проблема
Итак, OpenSSL может вычислить хеш-значение для X509 сертификатов, которое уникально идентифицирует этот сертификат:
https://www.openssl.org/docs/man1.0.2/man1/x509.html (аргумент -hash или -subject_hash)
Теперь, если у меня есть файл CMS (https://www.rfc-editor.org/rfc/rfc3852) в DER кодировке, который имеет поле SignedData с точно одним SignerInfo, но не содержит фактический сертификат подписи, как я могу вычислить хеш сертификата подписи, идентичный тому, что openssl x509 -hash -noout -in actual_cert.pem
создал бы для данного сертификата?
Просмотр CMS с помощью openssl cms -inform DER -in infile.cms -cmsout -print
дает
CMS_ContentInfo:
contentType: pkcs7-signedData (1.2.840.113549.1.7.2)
d.signedData:
version: 3
digestAlgorithms:
algorithm: sha512 (2.16.840.1.101.3.4.2.3)
parameter: NULL
encapContentInfo:
eContentType: id-smime-ct-TSTInfo (1.2.840.113549.1.9.16.1.4)
eContent:
0000 - 30 82 01 75 02 01 01 06-04 2a 03 04 01 30 31 0..u.....*...01
000f - 30 0d 06 09 60 86 48 01-65 03 04 02 01 05 00 0...`.H.e......
001e - 04 20 89 9b a3 d9 f7 77-e2 a7 4b dd 34 30 2b . .....w..K.40+
002d - c0 6c b3 f7 a4 6a c1 f5-65 ee 12 8f 79 fd 5d .l...j..e...y.]
003c - ab 99 d6 8b 02 03 2d 19-84 18 0f 32 30 32 31 ......-....2021
004b - 30 32 30 34 31 34 33 30-35 36 5a 01 01 ff 02 0204143056Z....
005a - 09 00 83 16 8e 99 d6 23-2e fc a0 82 01 11 a4 .......#.......
0069 - 82 01 0d 30 82 01 09 31-11 30 0f 06 03 55 04 ...0...1.0...U.
0078 - 0a 13 08 46 72 65 65 20-54 53 41 31 0c 30 0a ...Free TSA1.0.
0087 - 06 03 55 04 0b 13 03 54-53 41 31 76 30 74 06 ..U....TSA1v0t.
0096 - 03 55 04 0d 13 6d 54 68-69 73 20 63 65 72 74 .U...mThis cert
00a5 - 69 66 69 63 61 74 65 20-64 69 67 69 74 61 6c ificate digital
00b4 - 6c 79 20 73 69 67 6e 73-20 64 6f 63 75 6d 65 ly signs docume
00c3 - 6e 74 73 20 61 6e 64 20-74 69 6d 65 20 73 74 nts and time st
00d2 - 61 6d 70 20 72 65 71 75-65 73 74 73 20 6d 61 amp requests ma
00e1 - 64 65 20 75 73 69 6e 67-20 74 68 65 20 66 72 de using the fr
00f0 - 65 65 74 73 61 2e 6f 72-67 20 6f 6e 6c 69 6e eetsa.org onlin
00ff - 65 20 73 65 72 76 69 63-65 73 31 18 30 16 06 e services1.0..
010e - 03 55 04 03 13 0f 77 77-77 2e 66 72 65 65 74 .U....www.freet
011d - 73 61 2e 6f 72 67 31 22-30 20 06 09 2a 86 48 sa.org1"0 ..*.H
012c - 86 f7 0d 01 09 01 16 13-62 75 73 69 6c 65 7a ........busilez
013b - 61 73 40 67 6d 61 69 6c-2e 63 6f 6d 31 12 30 [email protected]
014a - 10 06 03 55 04 07 13 09-57 75 65 72 7a 62 75 ...U....Wuerzbu
0159 - 72 67 31 0b 30 09 06 03-55 04 06 13 02 44 45 rg1.0...U....DE
0168 - 31 0f 30 0d 06 03 55 04-08 13 06 42 61 79 65 1.0...U....Baye
0177 - 72 6e rn
certificates:
<ABSENT>
crls:
<ABSENT>
signerInfos:
version: 1
d.issuerAndSerialNumber:
issuer: O=Free TSA, OU=Root CA, CN=www.freetsa.org/[email protected], L=Wuerzburg, ST=Bayern, C=DE
serialNumber: 13972846748170250626
digestAlgorithm:
algorithm: sha512 (2.16.840.1.101.3.4.2.3)
parameter: NULL
signedAttrs:
object: contentType (1.2.840.113549.1.9.3)
set:
OBJECT:id-smime-ct-TSTInfo (1.2.840.113549.1.9.16.1.4)
object: signingTime (1.2.840.113549.1.9.5)
set:
UTCTIME:Feb 4 14:30:56 2021 GMT
object: id-smime-aa-signingCertificate (1.2.840.113549.1.9.16.2.12)
set:
SEQUENCE:
0:d=0 hl=2 l= 26 cons: SEQUENCE
2:d=1 hl=2 l= 24 cons: SEQUENCE
4:d=2 hl=2 l= 22 cons: SEQUENCE
6:d=3 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:916DA3D860ECCA82E34BC59D1793E7E968875F14
object: messageDigest (1.2.840.113549.1.9.4)
set:
OCTET STRING:
0000 - 4d b9 02 47 cb 66 6e 37-48 c7 56 04 1a M..G.fn7H.V..
000d - 77 45 23 95 72 1d 1d e8-62 3e 7b 68 9d wE#.r...b>{h.
001a - 58 43 88 64 a7 b3 1b be-bd 56 8e 58 8d XC.d.....V.X.
0027 - 8d 12 fe 11 dc 68 89 a5-56 aa bd 00 df .....h..V....
0034 - e4 8d f6 3b d8 8e 7d 78-c7 d2 42 a4 ...;..}x..B.
signatureAlgorithm:
algorithm: rsaEncryption (1.2.840.113549.1.1.1)
parameter: NULL
signature:
0000 - 62 39 1e b9 0e e3 ab 74-fa 90 46 bd d6 78 bc b9.....t..F..x.
000f - 2e d6 a4 3a 7b f4 0e 45-11 ba 16 c0 48 46 5a ...:{..E....HFZ
001e - 52 87 c5 3c 9d ae c7 1d-83 dc c8 03 8f 2e 70 R..<..........p
002d - 2c 4e 1f 6a 4e 5e 64 b7-5d 56 5e cb c9 6f af ,N.jN^d.]V^..o.
003c - 17 3d f4 2f c9 a5 b9 5c-d4 a1 03 1f 43 8f a3 .=./...\....C..
004b - 46 13 62 df 4d f6 cc 48-ad 2c c3 43 85 5e 8c F.b.M..H.,.C.^.
005a - 5b da a8 97 8d 3a 06 28-72 56 f3 38 e3 06 ad [....:.(rV.8...
0069 - ca 80 28 28 73 3f 9a 6f-ed ba b9 ac ed f4 6f ..((s?.o......o
0078 - 69 9e 91 d4 d2 4d 6b 1f-98 53 16 66 d7 50 62 i....Mk..S.f.Pb
0087 - 96 61 9f 0f f6 bd 94 19-d6 04 c5 7e f9 3c 89 .a.........~.<.
0096 - 5a 8a d1 a1 05 72 4e 6f-9c 8a a5 ef 6b 36 8d Z....rNo....k6.
00a5 - e5 ee 8a e9 11 8b 1c 70-42 c7 32 6d 27 42 fb .......pB.2m'B.
00b4 - 99 71 25 ae 66 67 48 58-10 df 4a db 08 08 ea .q%.fgHX..J....
00c3 - b1 a0 d5 ca 22 4b 46 ad-12 fd a1 72 91 c4 8b ...."KF....r...
00d2 - 21 d2 ff d8 b3 13 7f f8-31 9c 42 f6 b4 ea b1 !.......1.B....
00e1 - 15 21 8a ed e0 b9 6a 3c-0d 88 03 aa 4a ca f2 .!....j<....J..
00f0 - 13 59 54 99 0b 19 70 4f-91 0a 7e f7 17 92 70 .YT...pO..~...p
00ff - dd 0f 54 cc 1e e7 7b 42-d2 fa c2 53 3a 45 5a ..T...{B...S:EZ
010e - 45 09 c3 7b b5 34 6d 0b-40 82 72 45 4d eb 60 E..{[email protected].`
011d - 00 57 c8 46 77 23 5b 1c-c0 ff 6b 01 5c 0e 2f .W.Fw#[...k.\./
012c - fb 87 b3 e6 42 e5 1b 1d-25 6c c5 43 c4 af b8 ....B...%l.C...
013b - 9b 51 74 f2 c9 85 d2 54-52 ca b6 4e ac a1 83 .Qt....TR..N...
014a - 28 80 99 11 d5 ed a0 82-ad cc df 7d 18 a4 2c (..........}..,
0159 - 05 79 c0 f9 be 7c 52 1e-33 84 0c a5 ae b4 4e .y...|R.3.....N
0168 - 6d 08 ee 68 13 44 35 15-5f e1 3d e5 72 36 72 m..h.D5._.=.r6r
0177 - 05 8e 4c 4d 7f 0d ce 32-23 5c 16 bc 73 99 e6 ..LM...2#\..s..
0186 - 68 ea c5 19 e7 4d d7 0f-22 d5 1c 61 ac a8 cf h....M.."..a...
0195 - b6 70 49 79 3c 22 1a 90-96 cd 3b fb 11 bb 56 .pIy<"....;...V
01a4 - 4f 2a 41 a7 5d 61 f4 81-6a 1c ce 2d f9 0c bb O*A.]a..j..-...
01b3 - 91 80 7a 9d 9c 61 37 81-e1 77 20 d3 06 56 be ..z..a7..w ..V.
01c2 - f3 df 1c 74 47 ee ab 81-7a 03 80 96 95 a0 93 ...tG...z......
01d1 - 4b f4 e6 b9 a2 f4 8b 2f-25 80 2f c9 b5 a3 99 K....../%./....
01e0 - 34 e0 ab 8e 2b fb e3 ce-26 91 0a b3 6d af 18 4...+...&...m..
01ef - 5a d7 a8 7c 3e c6 1c 17-0d e8 30 da df f2 5d Z..|>.....0...]
01fe - 51 3b Q;
unsignedAttrs:
<ABSENT>
Итак, я вижу, что есть один объект SignerInfo.
Согласно 5.3. Тип SignerInfo в https://www.rfc-editor.org/rfc/rfc3852 :
Поля типа SignerInfo имеют следующие значения:
version - это номер версии синтаксиса. Если SignerIdentifier является
CHOICE issuerAndSerialNumber, тогда версия ДОЛЖНА быть 1. Если
SignerIdentifier - это subjectKeyIdentifier, тогда версия
ДОЛЖНА быть 3.
sid указывает на сертификат подписывающего (и таким образом на публичный
ключ подписывающего). Публичный ключ подписывающего необходим получателю
для проверки подписи. SignerIdentifier предоставляет два
альтернативных варианта для указания публичного ключа подписывающего.
Альтернатива issuerAndSerialNumber идентифицирует сертификат подписывающего
по расширенному имени его издателя и серийному номеру сертификата;
subjectKeyIdentifier идентифицирует сертификат подписывающего
по идентификатору ключа.
Таким образом, в предоставленном примере версия SignerInfo равна 1, поэтому сертификат идентифицируется по issuerAndSerialNumber, так как мне вычислить соответствующий X509 хеш? Просто извлечь issuerAndSerialNumber.issuer и вычислить SHA-1? Если так, то как мне это извлечь, используя Openssl?
Если сейчас версия SignerInfo была бы 3 вместо 1, если я правильно понимаю спецификацию, то поля issuerAndSerialNumber не было бы, а вместо этого было бы поле SubjectKeyIdentifier. Будет ли это уже хеш, который openssl x509 -hash -noout -in actual_cert.pem
выдал бы? Если нет, как мне вычислить соответствующий хеш в этом случае?
Как обсуждалось в комментариях, вы не можете сделать это для CMS SignedData в общем, но вы можете сделать это для временной метки RFC3161, которая содержит элемент tsa [0] GeneralName OPTIONAL
, который все, что я смотрел, делает. Поскольку у меня нет ваших токенов, я использовал один, который есть в моих тестовых данных от freetsa:
$ cat se244280.c
/* se244280.c 2021-02-06 */
/* МИНИМАЛЬНАЯ ОБРАБОТКА ОШИБОК ТОЛЬКО ДЛЯ ТЕСТА */
#include <stdio.h>
#include <openssl/err.h>
#include <openssl/pkcs7.h>
#include <openssl/ts.h>
void err (const char *msg, int info){ fprintf (stderr, "%s: %d\n", msg, info); ERR_print_errors_fp(stderr); exit(1); }
int main (int argc, char**argv)
{
BIO *bin = BIO_new_file(argv[1],"rb");
PKCS7 *token;
if( !(token = d2i_PKCS7_bio(bin,NULL)) ) err("d2i_PKCS7_bio",0);
if( !PKCS7_type_is_signed(token)
|| OBJ_obj2nid(token->d.sign->contents->type) != NID_id_smime_ct_TSTInfo
|| token->d.sign->contents->d.other->type != V_ASN1_OCTET_STRING )
printf ("not a token\n"), exit(1);
ASN1_OCTET_STRING econt = * token->d.sign->contents->d.other->value.octet_string;
const unsigned char *ptr = econt.data;
TS_TST_INFO *info;
if( !(info = d2i_TS_TST_INFO(NULL, &ptr, econt.length)) ) err("d2i_TS_TST_INFO",0);
if( !info->tsa || info->tsa->type != GEN_DIRNAME )
printf ("no/bad TSA\n"), exit(1);
printf ("%08lx\n", X509_NAME_hash( info->tsa->d.dirn ) );
return 0;
}
$ gcc se244280.c -o se244280 -lcrypto
$ ./se244280 token0
cc952886
$ openssl x509 -in tokencert0 -inform der -noout -subject_hash
cc952886
$ # tokencert0 - это сертификат подписывающего для этого TSA, полученный из другого токена
$ # где я установил опцию в запросе, чтобы сертификаты были включены --
$ # что является более простым и официальным решением для получения сертификатов подписывающего
$
Ответ или решение
Как получить соответствующее значение subject_hash из CMS SignerInfo с использованием OpenSSL
OpenSSL — это мощный инструмент для работы с криптографией, который позволяет управлять сертификатами и различными стандартами шифрования, включая CMS (Cryptographic Message Syntax). В этом ответе мы подробно разберем, как извлечь соответствующее значение subject_hash из объекта SignerInfo в CMS.
Что такое subject_hash?
subject_hash
— это хэш-значение (SHA-1), которое уникально идентифицирует X.509 сертификат в соответствии с его полем Subject. Это значение, в частности, используется для сравнения сертификатов, чтобы убедиться, что они соответствуют друг другу.
Контекст задачи
Вы имеете CMS файл в DER-формате, который содержит единственный объект SignerInfo, но не включает сертификат. Внутри SignerInfo без вопросов присутствуют issuer
и serialNumber
, которые идентифицируют сертификат.
Для того чтобы получить хэш сертификата безопасной подписи, вам необходимо выполнить несколько шагов.
Шаги для извлечения subject_hash
-
Извлечение данных из CMS:
Сначала извлеките данные из вашего файла CMS. Используйте следующую команду:openssl cms -inform DER -in infile.cms -cmsout -print
Это предоставит вам детализированную информацию о содержимом CMS, включая SignerInfo.
-
Извлечение полей
issuer
иserialNumber
:
Из выведенной информации обратите внимание на поля:issuer
: это Distinguished Name (DN) сертифицированного центра.serialNumber
: это уникальный идентификатор сертификата.
-
Вычисление хэша:
Убедитесь, что у вас есть правильный формат DN, который требуется для вычисления хэша. Далее используйте команду OpenSSL для вычисленияsubject_hash
.openssl x509 -in actual_cert.pem -hash -noout
Если у вас нет физической копии сертификата, вы можете сохранить
issuer
в файл и использоватьopenssl x509
для его обработки. -
Хэш для SubjectKeyIdentifier (версия 3):
Если версияSignerInfo
равна 3, идентификатор будет представлен в форматеSubjectKeyIdentifier
. В этом случае:- Вам необходимо извлечь значение из поля
subjectKeyIdentifier
, которое должно быть в самих данных SignerInfo. Это значение не является хэшем сертификата, и для его получения вам будет нужно сначала получить сам сертификат.
- Вам необходимо извлечь значение из поля
Пример кода на C
Для специалистов, использующих возможность программирования, предварительно установите OpenSSL и используйте следующий пример кода:
#include <stdio.h>
#include <openssl/err.h>
#include <openssl/pkcs7.h>
#include <openssl/x509.h>
// Функция для обработки ошибок
void err(const char *msg) {
fprintf(stderr, "%s\n", msg);
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
// Главная функция для получения хэша
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <CMS file>\n", argv[0]);
return 1;
}
// Здесь код для открытия файла и извлечения SignerInfo...
// Предполагается получение issuer и serialNumber из SignerInfo
// Теперь вы должны вычислить хэш-значение
// На следующем шаге вы можете использовать X509_NAME_hash() чтобы получить нужный хэш.
return 0;
}
Заключение
Извлечение subject_hash
из объекта CMS SignerInfo в OpenSSL может быть выполнено с помощью несколько прямолинейных шагов. Понимание структуры CMS и правильного извлечения информации о сертификате является ключом к успешному выполнению этой задачи. Надеюсь, это руководство было полезным и поможет вам успешно решить вашу задачу.