Pull to refresh

Разбираем x.509 сертификат

Reading time 11 min
Views 216K

Привет, %username%!

Так уж вышло, что несмотря на относительно неплохое понимание инфраструктуры открытых ключей, содержимое *.crt файлов всегда оставалось для меня полнейшей загадкой.
Нет, не поймите неправильно. Я знаю, что x.509 сертификат содержит информацию о владельце, открытый ключ, сведения об удостоверяющем центре и электронную цифровую подпись. Но при установке очередного сертификата меня всегда мучило любопытство.
Чем отличается идентификатор ключа от отпечатка? Какие данные сертификата подписываются, а какие нет? И что за структура данных позволяет хранить всю эту информацию, сводя избыточность к минимуму.
Но вот наконец-то любопытство перебороло лень и в данном посте я постараюсь описать структуру x.509 сертификатов и ответить на эти и другие вопросы.

Часть 1. Самоподписанный сертификат


Для начала рассмотрим вариант самоподписанного сертификата корневого уровня.
Для упрощения задачи сгенерируем сертификат, который будет содержать только необходимые параметры:
  • Версия сертификата
  • Серийный номер
  • Алгоритм подписи
  • Сведения об издателе
  • Дата начала действия сертификата
  • Дата окончания действия сертификата
  • Сведения о владельце
  • Открытый ключ

Сделать это можно с помощью библиотеки Bouncy Castle, следующим образом:
private void button1_Click(object sender, EventArgs e)
        {            

            var KeyGenerate = new RsaKeyPairGenerator();

            KeyGenerate.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 1024));

            AsymmetricCipherKeyPair kp = KeyGenerate.GenerateKeyPair();

            var gen = new X509V3CertificateGenerator();

            var certName = new X509Name("CN=CA");
            var serialNo = new BigInteger("1",10);            

            gen.SetSerialNumber(serialNo);
            gen.SetSubjectDN(certName);            
            gen.SetIssuerDN(certName);
            gen.SetNotAfter(DateTime.Now.AddYears(100));
            gen.SetNotBefore(DateTime.Now);
            gen.SetSignatureAlgorithm("SHA1WITHRSA");            
            gen.SetPublicKey(kp.Public);     
            var myCert = gen.Generate(kp.Private);
            byte[] result = DotNetUtilities.ToX509Certificate(myCert).Export(X509ContentType.Cert);

            FileStream fs = new FileStream("D:\\test1.crt", FileMode.CreateNew);
            fs.Write(result, 0, result.Length);
            fs.Flush();
            fs.Close();
        }


В результате выполнения данной процедуры будет создан стандартный x.509 сертификат, который, будучи открытым с помощью hex-редактора, выглядит вот таким чудесным образом:
30 82 01 8F 30 81 F9 A0  03 02 01 02 02 01 01 30
0D 06 09 2A 86 48 86 F7  0D 01 01 05 05 00 30 0D
31 0B 30 09 06 03 55 04  03 0C 02 43 41 30 20 17
0D 31 33 30 39 31 35 31  35 33 35 30 32 5A 18 0F
32 31 31 33 30 39 32 32  31 35 33 35 30 32 5A 30
0D 31 0B 30 09 06 03 55  04 03 0C 02 43 41 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 8D 80 B5 8E 80
8E 94 D1 04 03 6A 45 1A  54 5E 7E EE 6D 0C CB 0B
82 03 F1 7D C9 6F ED 52  02 B2 08 C3 48 D1 24 70
C3 50 C2 1C 40 BC B5 9D  F8 E8 A8 41 16 7B 0B 34
1F 27 8D 32 2D 38 BA 18  A5 31 A9 E3 15 20 3D E4
0A DC D8 CD 42 B0 E3 66  53 85 21 7C 90 13 E9 F9
C9 26 5A F3 FF 8C A8 92  25 CD 23 08 69 F4 A2 F8
7B BF CD 45 E8 19 33 F1  AA E0 2B 92 31 22 34 60
27 2E D7 56 04 8B 1B 59  64 77 5F 02 03 01 00 01
30 0D 06 09 2A 86 48 86  F7 0D 01 01 05 05 00 03
81 81 00 0A 1C ED 77 F4  79 D5 EC 73 51 32 25 09
61 F7 00 C4 64 74 29 86  5B 67 F2 3D A9 39 34 6B
3C A9 92 B8 BF 07 13 0B  A0 9B DF 41 E2 8A F6 D3
17 53 E1 BA 7F C0 D0 BC  10 B7 9B 63 4F 06 D0 7B
AC C6 FB CE 95 F7 8A 72  AA 10 EA B0 D1 6D 74 69
5E 20 68 5D 1A 66 28 C5  59 33 43 DB EE DA 00 80
99 5E DD 17 AC 43 36 1E  D0 5B 06 0F 8C 6C 82 D3
BB 3E 2B A5 F1 94 FB 53  7B B0 54 22 6F F6 4C 18
1B 72 1C

Тот же самый сертификат, но уже открытый с помощью стандартных средств windows:
Имя сертификата	CA
Издатель	CA
Версия сертификата	3
Серийный номер	0x1
Недействителен до...	15.09.2013 15:35:00 GMT
Недействителен после...	22.09.2113 15:35:00 GMT
Цифровая подпись (SHA-1)	F9 AD 58 B5 50 3D F6 36 5E B8 89 D4 DC C8 5F CC 25 4B 93 A2
Цифровая подпись (SHA-256)	42 02 24 20 4E 8F 3A 3E 31 38 88 E5 C5 E7 C3 03 14 3A A6 52 EA 78 B9 77 42 5B 99 EB 4B BA 23 82
Открытый ключ(1024 битный)		Алгоритм открытого ключа	rsaEncryption
Модуль	
00: 8D 80 B5 8E 80 8E 94 D1 04 03 6A 45 1A 54 5E 7E
10: EE 6D 0C CB 0B 82 03 F1 7D C9 6F ED 52 02 B2 08
20: C3 48 D1 24 70 C3 50 C2 1C 40 BC B5 9D F8 E8 A8
30: 41 16 7B 0B 34 1F 27 8D 32 2D 38 BA 18 A5 31 A9
40: E3 15 20 3D E4 0A DC D8 CD 42 B0 E3 66 53 85 21
50: 7C 90 13 E9 F9 C9 26 5A F3 FF 8C A8 92 25 CD 23
60: 08 69 F4 A2 F8 7B BF CD 45 E8 19 33 F1 AA E0 2B
70: 92 31 22 34 60 27 2E D7 56 04 8B 1B 59 64 77 5F
Экспонента	01 00 01                                       

Подпись		Алгоритм подписи	sha1WithRSAEncryption
Подпись	
00: 0A 1C ED 77 F4 79 D5 EC 73 51 32 25 09 61 F7 00
10: C4 64 74 29 86 5B 67 F2 3D A9 39 34 6B 3C A9 92
20: B8 BF 07 13 0B A0 9B DF 41 E2 8A F6 D3 17 53 E1
30: BA 7F C0 D0 BC 10 B7 9B 63 4F 06 D0 7B AC C6 FB
40: CE 95 F7 8A 72 AA 10 EA B0 D1 6D 74 69 5E 20 68
50: 5D 1A 66 28 C5 59 33 43 DB EE DA 00 80 99 5E DD
60: 17 AC 43 36 1E D0 5B 06 0F 8C 6C 82 D3 BB 3E 2B
70: A5 F1 94 FB 53 7B B0 54 22 6F F6 4C 18 1B 72 1C

Имея два этих файла, один с двоичными данными, а другой с описанием сертификата, попробуем разобраться что здесь к чему.

Прежде всего, нужно отметить, что файл *.crt хранит информацию о сертификате в закодированном виде. Для кодирования применяется особый язык, называемый ASN.1.
ASN.1 — стандарт записи, описывающий структуры данных для представления, кодирования, передачи и декодирования данных. Wikipedia

С помощью языка ASN.1 можно описывать сложные структуры, состоящие из данных различных типов. Типичный пример ASN.1-файла выглядит как-то так:
ASN.1-файл
SEQUENCE(3 elem)
	SEQUENCE(7 elem)
		[0](1 elem)
			INTEGER 2
		INTEGER 1
		SEQUENCE(2 elem)
			OBJECT IDENTIFIER 1.2.840.113549.1.1.5
			NULL
		SEQUENCE(1 elem)
			SET(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER 2.5.4.3
					UTF8String CA
		SEQUENCE(2 elem)
			UTCTime 13-09-15 15:35:02 UTC
			GeneralizedTime 2113-09-22 15:35:02 UTC
		SEQUENCE(1 elem)
			SET(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER 2.5.4.3
					UTF8String CA
		SEQUENCE(2 elem)
			SEQUENCE(2 elem)
				OBJECT IDENTIFIER 1.2.840.113549.1.1.1
				NULL
			BIT STRING(1 elem)
				SEQUENCE(2 elem)
					INTEGER(1024 bit)
					INTEGER 65537
		SEQUENCE(2 elem)
			OBJECT IDENTIFIER 1.2.840.113549.1.1.5
			NULL
	BIT STRING(1024 bit)


Однако ASN.1 разрабатывался в те светлые времена, когда «640 КБ должно было хватать каждому» и тратить место на такую громоздкую запись не было никакой возможности. Поэтому, в целях экономии места, а также более удобной обработки хранимой в ASN.1-форме информации, был разработан специальный метод кодирования — DER.

DER-кодировка описывается следующим правилом. Первым записывается байт, характеризующий тип данных, затем последовательность байтов хранящих сведения о длине данных и затем уже записываются сами данные.

К примеру, для кодировки целого числа 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


Зная как кодируется каждый из этих типов, мы можем попытаться распарсить наш *.crt файл.
30 82 01 8F 30 81 F9 A0 03 02 01 02 02 01 01 30
0D 06 09 2A 86 48 86 F7 0D 01 01 05 05 00 30 0D
31 0B 30 09 06 03 55 04 03 0C 02 43 41 30 20 17
0D 31 33 30 39 31 35 31 35 33 35 30 32 5A 18 0F
32 31 31 33 30 39 32 32 31 35 33 35 30 32 5A 30
0D 31 0B 30 09 06 03 55 04 03 0C 02 43 41 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 8D 80 B5 8E 80
8E 94 D1 04 03 6A 45 1A 54 5E 7E EE 6D 0C CB 0B
82 03 F1 7D C9 6F ED 52 02 B2 08 C3 48 D1 24 70
C3 50 C2 1C 40 BC B5 9D F8 E8 A8 41 16 7B 0B 34
1F 27 8D 32 2D 38 BA 18 A5 31 A9 E3 15 20 3D E4
0A DC D8 CD 42 B0 E3 66 53 85 21 7C 90 13 E9 F9
C9 26 5A F3 FF 8C A8 92 25 CD 23 08 69 F4 A2 F8
7B BF CD 45 E8 19 33 F1 AA E0 2B 92 31 22 34 60
27 2E D7 56 04 8B 1B 59 64 77 5F 02 03 01 00 01
30 0D 06 09 2A 86 48 86 F7 0D 01 01 05 05 00 03
81 81 00 0A 1C ED 77 F4 79 D5 EC 73 51 32 25 09
61 F7 00 C4 64 74 29 86 5B 67 F2 3D A9 39 34 6B
3C A9 92 B8 BF 07 13 0B A0 9B DF 41 E2 8A F6 D3
17 53 E1 BA 7F C0 D0 BC 10 B7 9B 63 4F 06 D0 7B
AC C6 FB CE 95 F7 8A 72 AA 10 EA B0 D1 6D 74 69
5E 20 68 5D 1A 66 28 C5 59 33 43 DB EE DA 00 80
99 5E DD 17 AC 43 36 1E D0 5B 06 0F 8C 6C 82 D3
BB 3E 2B A5 F1 94 FB 53 7B B0 54 22 6F F6 4C 18
1B 72 1C

Преобразуя байты-идентификаторы типов и убирая байты описывающие длину блоков получим следующую структуру:
SEQUENCE(3 elem)
	SEQUENCE(7 elem)
		[0](1 elem)
			INTEGER 2
		INTEGER 1
		SEQUENCE(2 elem)
			OBJECT IDENTIFIER 1.2.840.113549.1.1.5
			NULL
		SEQUENCE(1 elem)
			SET(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER 2.5.4.3
					UTF8String CA
		SEQUENCE(2 elem)
			UTCTime 13-09-15 15:35:02 UTC
			GeneralizedTime 2113-09-22 15:35:02 UTC
		SEQUENCE(1 elem)
			SET(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER 2.5.4.3
					UTF8String CA
		SEQUENCE(2 elem)
			SEQUENCE(2 elem)
				OBJECT IDENTIFIER 1.2.840.113549.1.1.1
				NULL
			BIT STRING(1 elem)
				SEQUENCE(2 elem)
					INTEGER 00: 8D 80 B5 8E 80 8E 94 D1 04 03 6A 45 1A 54 5E 7E
						        EE 6D 0C CB 0B 82 03 F1 7D C9 6F ED 52 02 B2 08
						        C3 48 D1 24 70 C3 50 C2 1C 40 BC B5 9D F8 E8 A8
						        41 16 7B 0B 34 1F 27 8D 32 2D 38 BA 18 A5 31 A9
						        E3 15 20 3D E4 0A DC D8 CD 42 B0 E3 66 53 85 21
						        7C 90 13 E9 F9 C9 26 5A F3 FF 8C A8 92 25 CD 23
						        08 69 F4 A2 F8 7B BF CD 45 E8 19 33 F1 AA E0 2B
						        92 31 22 34 60 27 2E D7 56 04 8B 1B 59 64 77 5F
					INTEGER 65537
		SEQUENCE(2 elem)
			OBJECT IDENTIFIER 1.2.840.113549.1.1.5
			NULL
	BIT STRING 00: 0A 1C ED 77 F4 79 D5 EC 73 51 32 25 09 61 F7 00
		           C4 64 74 29 86 5B 67 F2 3D A9 39 34 6B 3C A9 92
		           B8 BF 07 13 0B A0 9B DF 41 E2 8A F6 D3 17 53 E1
		           BA 7F C0 D0 BC 10 B7 9B 63 4F 06 D0 7B AC C6 FB
		           CE 95 F7 8A 72 AA 10 EA B0 D1 6D 74 69 5E 20 68
		           5D 1A 66 28 C5 59 33 43 DB EE DA 00 80 99 5E DD
		           17 AC 43 36 1E D0 5B 06 0F 8C 6C 82 D3 BB 3E 2B
		           A5 F1 94 FB 53 7B B0 54 22 6F F6 4C 18 1B 72 1C

Это уже более похоже на то, что мы видим при открытии сертификатов в браузере или Windows. Пробежимся по каждому элементу:
  • INTEGER 2 — целое число, описывающее версию сертификата. Для сертификатов версии 1 равно 0.
  • INTEGER 1 — серийный номер нашего сертификата.
  • OBJECT IDENTIFIER 1.2.840.113549.1.1.5 — последовательность, описывающая алгоритм цифровой подписи. Данная последовательность описывает sha1WithRSAEncryption.
  • OBJECT IDENTIFIER 2.5.4.3 — служит индикатором того, что следующее поле описывает какое либо сведение об издателе. Последовательность 2.5.4.3, описывается свойство CN(common name) — общепринятое имя.
  • UTF8String CA — имя издателя.
  • UTCTime 13-09-15 15:35:02 UTC — дата начала действия сертификата.
  • GeneralizedTime 2113-09-22 15:35:02 UTC — дата окончания действия сертификата.
  • OBJECT IDENTIFIER 2.5.4.3 — описывает тип информации о владельце.
  • UTF8String CA — имя владельца.
  • OBJECT IDENTIFIER 1.2.840.113549.1.1.1 — характеризует алгоритм ключа, в данном случае rsaEncryption.
  • INTEGER 00: — открытый ключ сертификата.
  • BIT STRING 00: — подпись сертификата.


Важным моментом, о котором стоит особенно упомянуть являются данные, для которых вычисляется подпись. Интуитивно может показаться, что подписываются все данные идущие до последнего поля BIT STRING, содержащего подпись. Но на самом деле это не так. В стандарте x.509 подписывается определенная часть сертификата, называемая TBS-сертификат (to be signed). В TSB-сертификат входит последовательность SEQUENCE второго уровня со всеми вложенными данными.
	SEQUENCE(7 elem)
		[0](1 elem)
			INTEGER 2
		INTEGER 1
		SEQUENCE(2 elem)
			OBJECT IDENTIFIER 1.2.840.113549.1.1.5
			NULL
		SEQUENCE(1 elem)
			SET(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER 2.5.4.3
					UTF8String CA
		SEQUENCE(2 elem)
			UTCTime 13-09-15 15:35:02 UTC
			GeneralizedTime 2113-09-22 15:35:02 UTC
		SEQUENCE(1 elem)
			SET(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER 2.5.4.3
					UTF8String CA
		SEQUENCE(2 elem)
			SEQUENCE(2 elem)
				OBJECT IDENTIFIER 1.2.840.113549.1.1.1
				NULL
			BIT STRING(1 elem)
				SEQUENCE(2 elem)
					INTEGER 00: 8D 80 B5 8E 80 8E 94 D1 04 03 6A 45 1A 54 5E 7E
						        EE 6D 0C CB 0B 82 03 F1 7D C9 6F ED 52 02 B2 08
						        C3 48 D1 24 70 C3 50 C2 1C 40 BC B5 9D F8 E8 A8
						        41 16 7B 0B 34 1F 27 8D 32 2D 38 BA 18 A5 31 A9
						        E3 15 20 3D E4 0A DC D8 CD 42 B0 E3 66 53 85 21
						        7C 90 13 E9 F9 C9 26 5A F3 FF 8C A8 92 25 CD 23
						        08 69 F4 A2 F8 7B BF CD 45 E8 19 33 F1 AA E0 2B
						        92 31 22 34 60 27 2E D7 56 04 8B 1B 59 64 77 5F
					INTEGER 65537

Т.о. если перед вами будет стоять задача проверить ЭЦП x.509 сертификата, то для этого сперва необходимо извлечь TBS-сертификат.

Еще одно замечание относится к отпечатку сертификата. Как видите сам сертификат не содержит никаких сведений об отпечатке. Это объясняется тем, что отпечаток представляет собой обычное хеш-значение SHA-1 от всего файла сертификата, со всеми его полями, включая подпись издателя. Поэтому хранить отпечаток не обязательно, можно просто вычислять хеш при каждом просмотре сертификата.

Часть 2. Сертификат 2-го уровня


Мы с вами рассмотрели внутренности самоподписанного сертификата, и нам осталось понять чем отличается структура сертификатов более низкого уровня, от сертификата корневого центра.
Для этого, с помощью имеющегося у нас секретного ключа сертификата CA, создадим подчиненный ему сертификат user. И в этом нам снова поможет Bouncy Castle.
private void button2_Click(object sender, EventArgs e)
        {            

            var KeyGenerate = new RsaKeyPairGenerator();

            KeyGenerate.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 1024));

            AsymmetricCipherKeyPair kp2 = kpgen.GenerateKeyPair();

            var gen2 = new X509V3CertificateGenerator();

            var certName = new X509Name("CN=CA");
            var serialNo = new BigInteger("1",10);   

            var certName2 = new X509Name("CN=User");
            var certNameOwner2 = new X509Name("CN=User");
            var serialNo2 = new BigInteger("2", 10);            

            gen2.SetSerialNumber(serialNo2);
            gen2.SetSubjectDN(certName2);
            gen2.SetIssuerDN(certName);
            gen2.SetNotAfter(DateTime.Now.AddYears(100));
            gen2.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
            gen2.SetSignatureAlgorithm("SHA1WITHRSA");
            gen2.SetPublicKey(kp2.Public);
            gen2.AddExtension(
                X509Extensions.AuthorityKeyIdentifier.Id,
                false,
                new AuthorityKeyIdentifier(
                    SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(kp.Public),
                    new GeneralNames(new GeneralName(certName)),
                    serialNo));

            var newCert2 = gen2.Generate(kp.Private);
            byte[] result = DotNetUtilities.ToX509Certificate(newCert2).Export(X509ContentType.Cert);
            FileStream fs = new FileStream("D:\\FullTest.crt", FileMode.CreateNew);
            fs.Write(result, 0, result.Length);
            fs.Flush();
            fs.Close();
        }


Распарсив наш сертификат и преобразовав его к читаемому виду, получим следующую красоту:
SEQUENCE(3 elem)
	SEQUENCE(8 elem)
		[0](1 elem)
			INTEGER2
		INTEGER2
		SEQUENCE(2 elem)
			OBJECT IDENTIFIER1.2.840.113549.1.1.5
			NULL
		SEQUENCE(1 elem)
			SET(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER2.5.4.3
					UTF8StringCA
		SEQUENCE(2 elem)
			UTCTime13-09-15 15:35:02 UTC
			GeneralizedTime2113-09-22 15:35:02 UTC
		SEQUENCE(1 elem)
			SET(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER2.5.4.3
					UTF8StringUser
		SEQUENCE(2 elem)
			SEQUENCE(2 elem)
				OBJECT IDENTIFIER1.2.840.113549.1.1.1
				NULL
			BIT STRING(1 elem)
				SEQUENCE(2 elem)
					INTEGER(1024 bit)
					INTEGER65537
		[3](1 elem)
			SEQUENCE(1 elem)
				SEQUENCE(2 elem)
					OBJECT IDENTIFIER2.5.29.35
					OCTET STRING(1 elem)
						SEQUENCE(3 elem)
							[0](20 byte) 6FBC9476035CB50061524C4ABE9064C9C4C32E6B
							[1](1 elem)
								[4](1 elem)
									SEQUENCE(1 elem)
										SET(1 elem)
											SEQUENCE(2 elem)
												OBJECT IDENTIFIER2.5.4.3
												UTF8StringCA
							[2](1 byte) 01
	SEQUENCE(2 elem)
		OBJECT IDENTIFIER1.2.840.113549.1.1.5
		NULL
	BIT STRING(1024 bit)

Как видите, единственное отличие от самоподписанного сертификата заключается в наличие дополнительного блока:
[3](1 elem)
	SEQUENCE(1 elem)
		SEQUENCE(2 elem)
			OBJECT IDENTIFIER 2.5.29.35
			OCTET STRING(1 elem)
				SEQUENCE(3 elem)
					[0](20 byte) 6FBC9476035CB50061524C4ABE9064C9C4C32E6B
					[1](1 elem)
						[4](1 elem)
							SEQUENCE(1 elem)
								SET(1 elem)
									SEQUENCE(2 elem)
										OBJECT IDENTIFIER 2.5.4.3
										UTF8String CA
					[2](1 byte) 01

который содержит сведения об издателе сертификата и его открытом ключе. Вот тут я хотел бы добавить одно замечание. Без этого блока сертификат все равно будет оставаться рабочим, т.к. информация хранящаяся здесь считается не более, чем дополнением, более точно указывающим каким из ключей издателя был подписан текущий сертификат. Рассмотрим каждый элемент блока отдельно.

  • OBJECT IDENTIFIER 2.5.29.35 — набор цифр описывает какая информация хранится в блоке. Последовательность 2.5.29.35 означает, что перед нами информация о ключе подписанта.
  • [0](20 byte) 6FBC9476035CB50061524C4ABE9064C9C4C32E6B — идентификатор ключа издателя. SHA-1 хеш от закодированного с помощью DER открытого ключа.
  • OBJECT IDENTIFIER 2.5.4.3 — определяет, что следующее поле представляет имя издателя.
  • [2](1 byte) 01 — серийный номер сертификата издателя.

Напоследок откроем полученный сертификат с помощью стандартных средств и убедимся, что все необходимые данные на месте:
Имя сертификата	User
Издатель	CA
Версия сертификата	3
Серийный номер	0x2
Недействителен до...	15.09.2013 15:35:00 GMT
Недействителен после...	22.09.2113 15:35:00 GMT
Цифровая подпись (SHA-1)	A4 E7 9B AD E7 E2 67 B1 8A D6 6F F9 61 0D 42 A9 DB C3 A9 67
Цифровая подпись (SHA-256)	39 A2 D8 47 CE F7 E7 C3 81 62 8A 4A 65 F3 4A E8 6F 12 B7 8A 1A ED F9 94 6E 57 19 F6 39 DA B7 8F
Открытый ключ(1024 битный)		Алгоритм открытого ключа	rsaEncryption
Модуль	00: A7 BA 25 52 5F 0D 82 EE 2C B1 F0 E1 E2 0D 3F B2
10: 25 06 DB A2 5A B0 D3 00 D7 2C 1F 85 8C 71 73 95
20: 8A 06 6C 04 6D 4B AB 15 50 1E 53 92 9F BA 6E 04
30: 5D 71 6B C0 0A 8E 6C 51 51 2F 27 2E BB 8E C9 FF
40: 9C C2 E2 45 56 26 6B 61 C5 C1 67 0C 6F A9 8A 16
50: 76 8E 12 DB 38 A2 B3 09 6F B3 39 DD 9B EB 98 B7
60: 61 9F 9E 18 65 4F DB AB 74 72 79 AC 14 7C 24 D8
70: 47 16 5B 17 30 CB 6E FB 45 5E D1 04 37 FA 85 C3
Экспонента	01 00 01                                       

Подпись		Алгоритм подписи	sha1WithRSAEncryption
Подпись	00: 2C 1C D9 7F B4 F2 D0 10 16 7A B7 29 D6 89 A4 A1
10: 2B 4A 78 1B 85 38 53 83 4E 71 3C 81 C0 A5 AD A8
20: AB 16 59 F4 D3 A7 7E 83 2F AE 21 75 9E 91 F6 FC
30: 93 A3 AE F5 27 CF 5F 0B C9 5F DC E1 75 26 D5 39
40: 74 32 39 B9 BD 95 79 A7 EE 02 0C 56 0A A9 A5 83
50: F8 86 0D 6F B5 7F C5 FE 23 0B 4B 5C 65 A8 BC 89
60: 36 37 B3 53 74 BB 25 66 10 F8 53 AA EF 05 9E ED
70: 74 04 E9 3D F4 DF 85 71 37 57 5D E7 D8 C6 8E EA

Расширения		X509v3 Authority Key Identifier	keyid:6F:BC:94:76:03:5C:B5:00:61:52:4C:4A:BE:90:64:C9:C4:C3:2E:6B DirName:/CN=CA serial:01


Заключение


Тех усидчивых людей, которые продрались сквозь все эти ASN.1 выражения и шестнадцатеричные наборы данных, я хотел бы поблагодарить за прочтение. Надеюсь вам было хоть немного интересно. И стало чуточку понятнее, что же такое на самом деле X.509 сертификат.

Ну и как всегда немного ссылок для тех, кому хочется больше подробностей.
  1. RFC5280 — спецификация x.509 сертификата и списка отзывов сертификатов.
  2. Руководство по выживанию — SSL/TLS и сертификаты X.509
  3. ASN.1 простыми словами, вариант статьи для хабра
  4. on-line утилита для декодирования DER-файлов
  5. Первичный стандарт ITU-T X.509 (+ русский перевод). Спасибо ystr за ссылку.
Tags:
Hubs:
+71
Comments 31
Comments Comments 31

Articles