| ||||
| ||||
Прочитал, что смог найти здесь, но все равно не смог реализовать. Делаю так (выбрал необходимое): 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.) Что я делаю не так? | ||||
Ответы: | ||||
| ||||
значению структуры ReqInf.rgAttribute нужно передавать указатель на структуру типа CRYPT_ATTR_BLOB (а у вас указатель на CRYPT_ATTRIBUTE). Читайте MSDN внимательней :) | ||||
| ||||
ой, извиняюсь не туда посмотрел, со структурами у Вас всё правильно, возможно неправильно кодируется структура OsVer | ||||
| ||||
согласен с Александром. Версия ОС не кодируется совсем, а должна. Т.е. вместо OsVer.pbData := PByte(NewStr(’5.0.2195.2’#0)); OsVer.cbData := StrLen(PChar(OsVer.pbData)); должен быть CryptEncodeObject | ||||
| ||||
Поднимаю вопрос. Создаю запрос вообще без параметров. После CryptSignAndEncodeCertificate получается запрос, на который ругается CryptDecodeObject: CryptDecodeObject returned 2148086027(8009310b) CertUtil: -dump command FAILED: 0x8009310b (ASN: 267) CertUtil: Встречено неверное значение тега ASN1. Кстати, почему 0x8009310b? Моя программа выдает код ошибки 0x80093102. Что означает этот код? Нигде не нашел описания. Что может быть не так с запросом? | ||||
| ||||
0x80093102 - неожиданный конец данных ASN 0x8009310b - неверное значние тэга ASN (про это certutil кстати пишет) обе эти ошибки есть в Platform SDK winerror.h Что не так - допустим неправильная запись в файл, неправильная длина записываемого буфера... да разные могут быть ошибки. | ||||
| ||||
А как-нибудь можно определить, какое именно поле неправильно заполнено? Обпроверялся - запрос кодируется (по крайней мере, без ошибок), в преобразовании в/из 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 - это что за цифра? | ||||
| ||||
а dumpasn1 на неправильный запрос что говорит? | ||||
| ||||
...так я открыл для себя 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.=’ : ’.>.2 . .>.<.0.= ...@.L.5.2.8.G’ : } : } : } 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 : } | ||||
| ||||
<pre> Может, наличие атрибутов в запросе критично для CertUtil? </pre> | ||||
| ||||
возможно на это 363 A0 0: [0] : Error: Object has zero length. : } | ||||
| ||||
Для упрощения: в позапрошлом посте единственное слабое место - отсутствие блока аттрибутов (вероятно, на это и ругается CertUtil). 363 A0 0: [0]: Error: Object has zero length. : } В прошлом посте пытался проверить теги (с форматированием-то всяко лучше), но "проверка выдала отрицательный результат". Есть два вопроса: (возвращаясь к первому посту) В "правильном" запросе расширение выглядит так: _ 399 30 26: SEQUENCE { _ 401 06 10: OBJECT IDENTIFIER ’1 3 6 1 4 1 311 13 2 3’ _ 413 31 12: SET { _ 415 16 10: IA5String ’5.1.2600.2’ _ : } _ : } У меня же что-то не получается IA5String. Какой параметр нужен для CryptEncodeObject? И что кодировать? CRYPT_ATTRIBUTE? CRYPT_ATTR_BLOB? Сначала одно, потом - другое? Как получить информацию о провайдере (для 1.3.6.1.4.1.311.13.2.2)? В смысле, что для этого нужно передать CryptGetProvParam? | ||||
| ||||
Для OSVersion надо кодировать CERT_NAME_VALUE с параметром X509_ANY_STRING. Для информации о провайдере нужно получить PP_KEYSPEC, PP_NAME и PP_SIGNATURE_PIN. Это необязательный атрибут кстати - можно не заморачиваться :) | ||||
| ||||
Никак не получается. ts := GetWinVer; // ts = ’5.0.2195.2’ - проверено 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 В чем может быть дело? | ||||
| ||||
в функции EncodeObj наверное | ||||
| ||||
Вряд ли. Там просто два раза подряд вызывается 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 Это правильно, не подскажете? (я не знаю правил преобразования) | ||||
| ||||
Опа! Ахинею немножко написал, извиняюсь. Кодирую-то я структуру, конечно а не саму строку. В общем, после DecodeObj получается аккурат то же самое, что и перед EncodeObj. Есть непонятки, пока думаю... А есть пример кодирования атрибута запроса через CryptoAPI именно на Delphi? | ||||
| ||||
А сам массив структур CRYPT_ATTRIBUTE после заполнения никак кодировать не надо? А то я уже голову сломал: все, кодируется, после кодирования раскодируется обратно в первозданный вид... А SignAndEncodeCertificate все AccessViolation дает (но если массив с расширениями из запроса убрать, то запрос создается проходит на ура при тех же остальных данных) Что интересно: не я первый на этом форуме такие траблы имею (что характерно, с Delphi), но решения проблемы что-то так никто и не написал. Неужели все забили на это? :-( Откликнитесь, знатоки! | ||||
| ||||
Нет конечно, массив не надо кодировать. Кодируется каждый атрибут отдельно. | ||||
| ||||
YESS!!! Наконец-то заработало. Ошибка была в использовании не того типа для rgValue. Запрос сохраняется, читается, asn1dump не дает ошибок... А вот certutil по-прежнему не сдается: CryptDecodeObject returned 2148086027(8009310b) CertUtil: -dump command FAILED: 0x8009310b (ASN: 267) CertUtil: Встречено неверное значение тега ASN1. С чего бы это? | ||||
| ||||
Мб для начала запрос выложите? Тяжело по сообщению об ошибке сказать откуда она взялась. | ||||
| ||||
Тестовый запрос выслал на почту. Спасибо Вам огромное за ответы. | ||||
| ||||
Имя не так закодировано, certutil не понимает когда все RDN сидят в одном SET. | ||||
| ||||
Имя не так закодировано, certutil не понимает когда все RDN сидят в одном SET. | ||||
| ||||
Я правильно понял, что надо на каждый CERT_RDN_ATTR свой CERT_RDN и кодировать эти атрибуты отдельно отдельно, а потом записать блобы, полученные при кодировании один за другим и закодировать все вместе? | ||||
| ||||
Еще такой вопрос: CryptGetProvParam для PP_SIGNATURE_PIN возвращает false. При этом GetLastError = NTE_BAD_TYPE. (HCRYPTPROV я использую от только что созданной для запроса пары ключей) В чем тут дело? | ||||
| ||||
+ к предыдущему: Для CryptAcquireContext изпользуются ProviderName = PChar(’Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider’) ProviderType = 0x00000047 из флагов - установлен только CRYPT_NEWKEYSET | ||||
| ||||
В общем, остался вопрос только с получением PP_SIGNATURE_PIN. Никак не получается выцепить это поле. Сразу (еще при попытке определить требуемый размер памяти) выдается ошибка NTE_BAD_TYPE. | ||||