06.06.2005 16:52:50Как добавить атрибуты (rgAttribute) в запрос на сертификат? Ответов: 27
SeregaEvg
Прочитал, что смог найти здесь, но все равно не смог реализовать. Делаю так (выбрал необходимое):

var
ReqInf: CERT_REQUEST_INFO;
CryptAttr: array of CRYPT_ATTRIBUTE;
OsVer: CryptoAPI_BLOB;
...

begin
...

SetLength(CryptAttr, 1);

OsVer.pbData := PByte(NewStr(’5.0.2195.2’#0));
OsVer.cbData := StrLen(PChar(OsVer.pbData));

CryptAttr[0].pszObjId := szOID_OS_VERSION;
CryptAttr[0].cValue := 1;
CryptAttr[0].rgValue := @OsVer;

...

ReqInf.cAttribute := 1;
ReqInf.rgAttribute := @CryptAttr[0];
...


Причем если в последних двух строках не добавлять extensions (присвоить 0 и nil соответственно) то запрос нормально кодируется и расшифровывается.

А если добавить, то кодиркется, но не расшифровывается (certutil.exe выдает
CryptDecodeObject returned 2148086027(8009310b)
CertUtil: -dump command FAILED: 0x8009310b (ASN: 267)
CertUtil: Встречено неверное значение тега ASN1.)

Что я делаю не так?
 
Ответы:
07.06.2005 11:27:22Александр
значению структуры ReqInf.rgAttribute
нужно передавать указатель на структуру типа CRYPT_ATTR_BLOB (а у вас указатель на CRYPT_ATTRIBUTE).
Читайте MSDN внимательней :)
07.06.2005 11:32:03Александр
ой, извиняюсь не туда посмотрел, со структурами у Вас всё правильно, возможно неправильно кодируется структура OsVer
07.06.2005 12:08:17Kirill Sobolev
согласен с Александром.
Версия ОС не кодируется совсем, а должна.
Т.е. вместо
OsVer.pbData := PByte(NewStr(’5.0.2195.2’#0));
OsVer.cbData := StrLen(PChar(OsVer.pbData));

должен быть CryptEncodeObject
04.07.2005 12:04:52SeregaEvg
Поднимаю вопрос.

Создаю запрос вообще без параметров. После CryptSignAndEncodeCertificate
получается запрос, на который ругается
CryptDecodeObject:

CryptDecodeObject returned 2148086027(8009310b)
CertUtil: -dump command FAILED: 0x8009310b (ASN: 267)
CertUtil: Встречено неверное значение тега ASN1.

Кстати, почему 0x8009310b? Моя программа выдает код ошибки 0x80093102.

Что означает этот код? Нигде не нашел описания.

Что может быть не так с запросом?
04.07.2005 12:15:15Kirill Sobolev
0x80093102 - неожиданный конец данных ASN
0x8009310b - неверное значние тэга ASN (про это certutil кстати пишет)
обе эти ошибки есть в Platform SDK winerror.h

Что не так - допустим неправильная запись в файл, неправильная длина записываемого буфера... да разные могут быть ошибки.
04.07.2005 16:35:01SeregaEvg
А как-нибудь можно определить, какое именно поле неправильно заполнено? Обпроверялся - запрос кодируется (по крайней мере, без ошибок), в преобразовании в/из BASE64 ошибок нет.

Есть подозрения на ошибку в кодировании RDN. Делаю так:
NameAttr[0].pszObjId := szOID_COUNTRY_NAME; // Страна
NameAttr[0].dwValueType := CERT_RDN_PRINTABLE_STRING;
NameAttr[0].Value.cbData := 3;
NameAttr[0].Value.pbData := PByte(PChar(’RU’#0));

NameAttr[1].pszObjId := szOID_ORGANIZATION_NAME; // Организация
NameAttr[1].dwValueType := CERT_RDN_UNICODE_STRING;
NameAttr[1].Value.cbData := (system.Length(OrgName) + 1) * sizeof(WideChar);
NameAttr[1].Value.pbData := PByte(PWideChar(S2WS(OrgName, 1251)));



Что-то не пойму: моей программой запрос то декодируется, то не декодируется...

А во фразе "-dump command FAILED: 0x80093102 (ASN: 258)" 258 - это что за цифра?
04.07.2005 16:48:19Kirill Sobolev
а dumpasn1 на неправильный запрос что говорит?
04.07.2005 19:36:10SeregaEvg
...так я открыл для себя dumpasn1 :-) Штука знатная. Действительно были проблемы с длинами двух полей.


Но теперь, вроде, запрос хоть и читается, но CertUtil все равно брыкается:
CryptDecodeObject returned 2148086027(8009310b)
CertUtil: -dump command FAILED: 0x8009310b (ASN: 267)
CertUtil: Встречено неверное значение тега ASN1.

При этом ASNDump такой:

0 30 440: SEQUENCE {
4 30 357: SEQUENCE {
8 02 1: INTEGER 0
11 30 181: SEQUENCE {
14 31 178: SET {
17 30 9: SEQUENCE {
19 06 3: OBJECT IDENTIFIER countryName (2 5 4 6)
24 13 2: PrintableString ’RU’
: }
28 30 33: SEQUENCE {
30 06 3: OBJECT IDENTIFIER organizationName (2 5 4 10)
35 1E 26: BMPString ’...... .........". ......’
: }
63 30 33: SEQUENCE {
65 06 3: OBJECT IDENTIFIER organizationalUnitName (2 5 4 11)
70 1E 26: BMPString ’.3.5.=. .4.8.@.5.:.B.>.@’
: }
98 30 95: SEQUENCE {
100 06 3: OBJECT IDENTIFIER commonName (2 5 4 3)
105 1E 88: BMPString
: ’......-........ 3462 .........". ...... ...5.6.=’
: &rsquo;.>.2 . .>.<.0.= ...@.L.5.2.8.G&rsquo;
: }
: }
: }
195 30 165: SEQUENCE {
198 30 28: SEQUENCE {
200 06 6: OBJECT IDENTIFIER szOID_CP_GOST_R3410 (1 2 643 2 2 20)
208 30 18: SEQUENCE {
210 06 7: OBJECT IDENTIFIER
: OID_SignDH128VerbaO (1 2 643 2 2 32 2)
219 06 7: OBJECT IDENTIFIER OID_HashVerbaO (1 2 643 2 2 30 1)
: }
: }
228 03 132: BIT STRING 0 unused bits, encapsulates {
232 04 128: OCTET STRING
: A1 F8 C5 1E 20 04 0A 9D 1B F6 8F 06 F4 89 95 77
: D8 37 16 78 C8 52 83 5A CD 27 43 98 F7 7C 59 88
: 5B 60 D8 C4 49 EF 77 84 DC BE AF 3D 2F E6 44 18
: 83 4F 99 2C AF D3 D4 04 B3 05 FB 3C 46 78 9D 64
: 69 F6 71 00 51 39 12 7F 4B BD B6 8D 17 E4 E5 81
: B5 92 E3 34 48 DF E9 02 05 8E 60 DE 02 F3 3E 35
: B2 25 5B 96 75 18 A5 D9 79 01 85 1D 59 C4 DA D2
: 4D 0F 83 AA 10 65 66 63 F1 4B E8 54 8D F1 2A 29
: }
: }
363 A0 0: [0]
: Error: Object has zero length.
: }
365 30 10: SEQUENCE {
367 06 6: OBJECT IDENTIFIER szOID_CP_GOST_R3411_R3410 (1 2 643 2 2 4)
375 05 0: NULL
: }
377 03 65: BIT STRING 0 unused bits
: 5A D5 A6 DF 6F F8 BE DD AE 2B 1A E8 8C 4B D3 95
: 59 19 0B 03 9B DE A3 BE 9D 0C 9F FD 3E A8 81 8C
: 55 05 70 7C 46 C0 F2 58 FC E3 47 7D CD A7 3D A5
: DC F1 C5 FF C2 A2 B5 03 F7 A9 49 F5 A1 DD BC B8
: }



04.07.2005 19:38:28SeregaEvg
<pre>
Может,
наличие атрибутов в запросе критично для CertUtil?
</pre>
05.07.2005 10:17:46Kirill Sobolev
возможно на это
363 A0 0: [0]
: Error: Object has zero length.
: }
05.07.2005 12:27:35SeregaEvg
Для упрощения: в позапрошлом посте единственное слабое место - отсутствие блока аттрибутов (вероятно, на это и ругается CertUtil).

363 A0 0: [0]: Error: Object has zero length.
: }


В прошлом посте пытался проверить теги (с форматированием-то всяко лучше), но "проверка выдала отрицательный результат".


Есть два вопроса: (возвращаясь к первому посту)

В "правильном" запросе расширение выглядит так:
_ 399 30 26: SEQUENCE {
_ 401 06 10: OBJECT IDENTIFIER &rsquo;1 3 6 1 4 1 311 13 2 3&rsquo;
_ 413 31 12: SET {
_ 415 16 10: IA5String &rsquo;5.1.2600.2&rsquo;
_ : }
_ : }

У меня же что-то не получается IA5String. Какой параметр нужен для CryptEncodeObject? И что кодировать? CRYPT_ATTRIBUTE? CRYPT_ATTR_BLOB? Сначала одно, потом - другое?

Как получить информацию о провайдере (для 1.3.6.1.4.1.311.13.2.2)?
В смысле, что для этого нужно передать
CryptGetProvParam?

05.07.2005 12:44:19Kirill Sobolev
Для OSVersion надо кодировать CERT_NAME_VALUE с параметром X509_ANY_STRING.
Для информации о провайдере нужно получить PP_KEYSPEC, PP_NAME и PP_SIGNATURE_PIN. Это необязательный атрибут кстати - можно не заморачиваться :)
05.07.2005 15:11:26SeregaEvg
Никак не получается.

ts := GetWinVer; // ts = &rsquo;5.0.2195.2&rsquo; - проверено

aOS.dwValueType := CERT_RDN_IA5_STRING;
aOs.Value.cbData := System.Length(ts);
aOS.Value.pbData := PByte(NewStr(PChar(ts)));


mcOS := EncodeObj(X509_ANY_STRING, @aOS);


CryptAttr[0].pszObjId := szOID_OS_VERSION;
CryptAttr[0].cValue := 1;
CryptAttr[0].rgValue := @mcOS;


Возникает AccessViolation при дальнейшей SignAndEncodeCertificate

В чем может быть дело?
05.07.2005 15:18:45Kirill Sobolev
в функции EncodeObj наверное
05.07.2005 15:45:16SeregaEvg
Вряд ли. Там просто два раза подряд вызывается CryptEncodeObject (выделяется память) и подставляется PKCS_7_ASN_ENCODING or X509_ASN_ENCODING как EncodingType.


По крайней мере, в других-то местах (например, при кодировании sibject) эта же функция нареканий не вызывает.


В общем, в результате строка

35 2E 30 2E 32 31 39 35 2E 32 (5.0.2195.2)

преобразуется в
16 0A F8 98 C8 00 0C 00 00 00 42 00

Это правильно, не подскажете?
(я не знаю правил преобразования)
05.07.2005 16:08:50SeregaEvg
Опа! Ахинею немножко написал, извиняюсь. Кодирую-то я структуру, конечно а не саму строку.

В общем, после DecodeObj получается аккурат то же самое, что и перед EncodeObj.

Есть непонятки, пока думаю...

А есть пример кодирования атрибута запроса через CryptoAPI именно на Delphi?
05.07.2005 16:58:52SeregaEvg
А сам массив структур CRYPT_ATTRIBUTE после заполнения никак кодировать не надо?

А то я уже голову сломал: все, кодируется, после кодирования раскодируется обратно в первозданный вид... А SignAndEncodeCertificate все AccessViolation дает (но если массив с расширениями из запроса убрать, то запрос создается проходит на ура при тех же остальных данных)

Что интересно: не я первый на этом форуме такие траблы имею (что характерно, с Delphi), но решения проблемы что-то так никто и не написал. Неужели все забили на это? :-(

Откликнитесь, знатоки!
05.07.2005 17:04:19Kirill Sobolev
Нет конечно, массив не надо кодировать.
Кодируется каждый атрибут отдельно.
05.07.2005 18:15:16SeregaEvg
YESS!!! Наконец-то заработало. Ошибка была в использовании не того типа для rgValue.

Запрос сохраняется, читается, asn1dump не дает ошибок... А вот certutil по-прежнему не сдается:

CryptDecodeObject returned 2148086027(8009310b)
CertUtil: -dump command FAILED: 0x8009310b (ASN: 267)
CertUtil: Встречено неверное значение тега ASN1.

С чего бы это?
05.07.2005 18:18:30Kirill Sobolev
Мб для начала запрос выложите? Тяжело по сообщению об ошибке сказать откуда она взялась.
06.07.2005 12:01:45SeregaEvg
Тестовый запрос выслал на почту.

Спасибо Вам огромное за ответы.

06.07.2005 12:33:28Kirill Sobolev
Имя не так закодировано, certutil не понимает когда все RDN сидят в одном SET.
06.07.2005 12:33:35Kirill Sobolev
Имя не так закодировано, certutil не понимает когда все RDN сидят в одном SET.
06.07.2005 14:15:32SeregaEvg
Я правильно понял, что надо на каждый CERT_RDN_ATTR свой CERT_RDN и кодировать эти атрибуты отдельно отдельно, а потом записать блобы, полученные при кодировании один за другим и закодировать все вместе?
06.07.2005 14:52:26SeregaEvg
Еще такой вопрос:
CryptGetProvParam для PP_SIGNATURE_PIN
возвращает false. При этом GetLastError = NTE_BAD_TYPE.

(HCRYPTPROV я использую от только что созданной для запроса пары ключей)

В чем тут дело?
06.07.2005 14:57:47SeregaEvg
+ к предыдущему:
Для CryptAcquireContext изпользуются
ProviderName = PChar(&rsquo;Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider&rsquo;)
ProviderType = 0x00000047

из флагов - установлен только CRYPT_NEWKEYSET
07.07.2005 17:12:29SeregaEvg
В общем, остался вопрос только с получением PP_SIGNATURE_PIN.

Никак не получается выцепить это поле. Сразу (еще при попытке определить требуемый размер памяти) выдается ошибка NTE_BAD_TYPE.