| ||||
| ||||
Сложилась такая специфическая ситуация. Есть CA с установленным на него УЦ КриптоПРО ЦР и ЦС. Связь между ними установлена. Формирую самоподписанный запрос на сертификат руками. В запросе только Subject (C=RU, CN=Имя) и одно расширение с enhanced key usage. Посылаю запрос на выпуск на CA через ICertRequest - все работает. Произвожу ту же операцию, только теперь пытаюсь провести этот запрос через ЦР с помощью его API (SOAP). Использую функицю CreateRequest у объекта Registration для регистрации пользователя. Но центр регистрации отвечает грубо "Не указано значение одного из обязательных RDN". Создаю аналогичный запрос с помощью XEnroll. Тот же Subject, тот же вариант использования ключа - регистрация проходит успешно, в дальнейшем и выпуск сертификата то же успешно. Декодуя запросы получаю, что subject одинаковые (2.5.4.6=RU, 2.5.4.3=Boris). Есть ли какие-либо обязательные параметры у запроса через ЦР - может какие-либо расширения и т.п. В документации найти не смог (хотя может плохо искал). | ||||
Ответы: | ||||
| ||||
Обязательные параметры задаются в свойствах ЦР. А принципиальным моментом может быть порядок следования полей DN в запросе. | ||||
| ||||
В настройках ЦР (на вкладке Политики), в графе "Политика имен" задан только CN обязательный. Я уже по разному пробовал - только CN оставлять, комбинировать различными другими элементами DN. Порядок я брал из документации. В частности - сначала C потом CN. Также пробовал заменять названия на цифровой аналог 2.5.4.6 и 2.5.4.3. | ||||
| ||||
Какие сообщения пишутся в журнал ЦР и журнал приложений после вызова метода? | ||||
| ||||
Моя программа сваливается с ошибкой ERemotableException (Delphi 7): Message: Не указано значение одного из обязательных RDN FaultActor: {DNLib}DN.Get DN FaultCode: SOAPSDK4:-2147220986 FauilDetail: <detail><mserror:errorInfo xmlns:mserror="http://schemas.microsoft.com/soap-toolkit/faultdetail/error/"> <mserror:returnCode>-2147220986 : Не указано значение одного из обязательных RDN</mserror:returnCode> <mserror:serverErrorInfo> <mserror:description>Не указано значение одного из обязательных RDN</mserror:description> <mserror:source>{DNLib}DN.Get DN</mserror:source> </mserror:serverErrorInfo> </mserror:errorInfo> </detail> В Log’е ЦР - нет сообщений В Event Viewer’е, раздел Application возникают три сообщения с ошибкой: 1. Source: VBRuntime Description: The VB Application identified by the event source logged this Application Registration: Thread ID: 3220 ,Logged: Ошибка в методе Registration.CreateRequest: (0x80040206) Не указано значение одного из обязательных RDN 2. Source: MSSOAP Description: Soap error: Executing method CreateRequest failed. 3. Source: MSSOAP Description: Soap error: An unanticipated error occurred during the processing of this request.. | ||||
| ||||
Ясно, а как вызывается Registration.CreateRequest? | ||||
| ||||
RegID := Reg.CreateRequest(Res, ’’, ’’); где Res - это запрос на сертификат в base64. | ||||
| ||||
Ну давайте и запрос тоже :) | ||||
| ||||
Вот функция член класса, формирующая PKCS10: function TCryptCertRequest.GetPKCS10: string; var CertReq: CERT_REQUEST_INFO; Subj: PWideChar; KeyUsage: CRYPT_BIT_BLOB; EnhKeyUsage: CERT_ENHKEY_USAGE; ExtKeyUsage, ExtEnhKeyUsage, ExtContainer, ExtTemplate: PCERT_EXTENSION; Template, Container: CERT_NAME_VALUE; Exts: CERT_EXTENSIONS; Attrib: CRYPT_ATTRIBUTE; OSData, ExtData, CSPData: string; AttrBlob, OSBlob, CSPBlob, ExtBlob: CRYPT_ATTR_BLOB; Sign: CRYPT_ALGORITHM_IDENTIFIER; PKCS10: CRYPT_DATA_BLOB; i: Integer; begin Result := ’’; Subj := nil; ZeroMemory(@CertReq, Sizeof(CertReq)); ZeroMemory(@KeyUsage, Sizeof(KeyUsage)); ZeroMemory(@ExtKeyUsage, Sizeof(ExtKeyUsage)); ZeroMemory(@EnhKeyUsage, Sizeof(EnhKeyUsage)); ZeroMemory(@ExtEnhKeyUsage, Sizeof(ExtEnhKeyUsage)); ZeroMemory(@Container, Sizeof(Container)); ZeroMemory(@ExtContainer, Sizeof(ExtContainer)); ZeroMemory(@Template, Sizeof(Template)); ZeroMemory(@ExtTemplate, Sizeof(ExtTemplate)); ZeroMemory(@Exts, Sizeof(Exts)); ZeroMemory(@Attrib, Sizeof(Attrib)); ZeroMemory(@AttrBlob, Sizeof(AttrBlob)); ZeroMemory(@Sign, Sizeof(Sign)); ZeroMemory(@PKCS10, Sizeof(PKCS10)); try try Subj := TCryptConvert.StrToPWideChar(Self.Subject); // Subject CertStrToNameW(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, Subj, CERT_OID_NAME_STR, nil, nil, @CertReq.Subject.cbData, nil); FErrorCode := GetLastError; if CertReq.Subject.cbData > 0 then GetMem(CertReq.Subject.pbData, CertReq.Subject.cbData) else Abort; ZeroMemory(CertReq.Subject.pbData, CertReq.Subject.cbData); CertStrToNameW(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, Subj, CERT_OID_NAME_STR, nil, CertReq.Subject.pbData, @CertReq.Subject.cbData, nil); // Key usage KeyUsage.cbData := 1; GetMem(KeyUsage.pbData, KeyUsage.cbData); KeyUsage.pbData^ := 0; for i := 0 to FKeyUsage.Count - 1 do begin try KeyUsage.pbData^ := KeyUsage.pbData^ or StrToInt(FKeyUsage[i]); except end; end; // Enhanced key usage EnhKeyUsage.cUsageIdentifier := FExtKeyUsage.Count; GetMem(EnhKeyUsage.rgpszUsageIdentifier, Sizeof(PChar) * EnhKeyUsage.cUsageIdentifier); for i := 0 to EnhKeyUsage.cUsageIdentifier - 1 do begin (PPChar(Integer(EnhKeyUsage.rgpszUsageIdentifier) + i*Sizeof(PChar)))^ := PChar(FExtKeyUsage[i]); end; // Extentions Exts.cExtension := 0; if FKeyUsage.Count > 0 then Inc(Exts.cExtension); if FExtKeyUsage.Count > 0 then Inc(Exts.cExtension); if FTemplateName <> ’’ then Inc(Exts.cExtension); if FContainerName <> ’’ then Inc(Exts.cExtension); if Exts.cExtension > 0 then begin GetMem(Exts.rgExtension, Sizeof(CERT_EXTENSION) * Exts.cExtension); end; i := 0; // Key usage if FKeyUsage.Count > 0 then begin ExtKeyUsage := PCERT_EXTENSION(Integer(Exts.rgExtension) + i*Sizeof(CERT_EXTENSION)); ExtKeyUsage.pszObjId := szOID_KEY_USAGE; ExtKeyUsage.fCritical := True; if CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_KEY_USAGE, @KeyUsage, nil, @ExtKeyUsage.Value.cbData) then begin GetMem(ExtKeyUsage.Value.pbData, ExtKeyUsage.Value.cbData); ZeroMemory(ExtKeyUsage.Value.pbData, ExtKeyUsage.Value.cbData); CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_KEY_USAGE, @KeyUsage, ExtKeyUsage.Value.pbData, @ExtKeyUsage.Value.cbData); end else begin FErrorCode := GetLastError; Abort; end; Inc(i); end; // EnhKeyUsage Extention if FExtKeyUsage.Count > 0 then begin ExtEnhKeyUsage := PCERT_EXTENSION(Integer(Exts.rgExtension) + i*Sizeof(CERT_EXTENSION)); ExtEnhKeyUsage.pszObjId := szOID_ENHANCED_KEY_USAGE; ExtEnhKeyUsage.fCritical := False; if CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, @EnhKeyUsage, nil, @ExtEnhKeyUsage.Value.cbData) then begin GetMem(ExtEnhKeyUsage.Value.pbData, ExtEnhKeyUsage.Value.cbData); ZeroMemory(ExtEnhKeyUsage.Value.pbData, ExtEnhKeyUsage.Value.cbData); CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, @EnhKeyUsage, ExtEnhKeyUsage.Value.pbData, @ExtEnhKeyUsage.Value.cbData); end else begin FErrorCode := GetLastError; Abort; end; Inc(i); end; // TemplateName Extention if FTemplateName <> ’’ then begin ExtTemplate := PCERT_EXTENSION(Integer(Exts.rgExtension) + i*Sizeof(CERT_EXTENSION)); Template.dwValueType := CERT_RDN_UNICODE_STRING; Template.Value.pbData := PByte(TCryptConvert.StrToPWideChar(FTemplateName)); Template.Value.cbData := 0; ExtTemplate.pszObjId := szOID_ENROLL_CERTTYPE_EXTENSION; ExtTemplate.fCritical := False; if CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_UNICODE_NAME_VALUE, @Template, nil, @ExtTemplate.Value.cbData) then begin GetMem(ExtTemplate.Value.pbData, ExtTemplate.Value.cbData); ZeroMemory(ExtTemplate.Value.pbData, ExtTemplate.Value.cbData); CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_UNICODE_NAME_VALUE, @Template, ExtTemplate.Value.pbData, @ExtTemplate.Value.cbData); end else begin FErrorCode := GetLastError; Abort; end; Inc(i); end; // ContainerName Extention { if FContainerName <> ’’ then begin ExtContainer := PCERT_EXTENSION(Integer(Exts.rgExtension) + i*Sizeof(CERT_EXTENSION)); Container.dwValueType := CERT_RDN_UNICODE_STRING; Container.Value.pbData := PByte(TCryptConvert.StrToPWideChar(FContainerName)); Container.Value.cbData := 0; ExtContainer.pszObjId := szOID_ADIRECT_CONTAINER_NAME; ExtContainer.fCritical := False; if CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_UNICODE_NAME_VALUE, @Container, nil, @ExtContainer.Value.cbData) then begin GetMem(ExtContainer.Value.pbData, ExtContainer.Value.cbData); ZeroMemory(ExtContainer.Value.pbData, ExtContainer.Value.cbData); CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_UNICODE_NAME_VALUE, @Container, ExtContainer.Value.pbData, @ExtContainer.Value.cbData); end else begin FErrorCode := GetLastError; Abort; end; end;} // Attribute if CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, szOID_CERT_EXTENSIONS, @Exts, nil, @AttrBlob.cbData) then begin GetMem(AttrBlob.pbData, AttrBlob.cbData); ZeroMemory(AttrBlob.pbData, AttrBlob.cbData); CryptEncodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, szOID_CERT_EXTENSIONS, @Exts, AttrBlob.pbData, @AttrBlob.cbData); end else begin FErrorCode := GetLastError; Abort; end; Attrib.pszObjId := szOID_CERT_EXTENSIONS; Attrib.cValue := 1; Attrib.rgValue := @AttrBlob; CertReq.cAttribute := 1; CertReq.rgAttribute := @Attrib; CertReq.dwVersion := CERT_REQUEST_V1; if Assigned(FPublicKeyProv) then CertReq.SubjectPublicKeyInfo := FPublicKeyProv.PublicKey^ else Abort; Sign.pszObjId := PChar(FSignAlg); if CryptSignAndEncodeCertificate(FPublicKeyProv.Context, FKeySpec, X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_CERT_REQUEST_TO_BE_SIGNED, @CertReq, @Sign, nil, nil, @PKCS10.cbData) then begin GetMem(PKCS10.pbData, PKCS10.cbData); ZeroMemory(PKCS10.pbData, PKCS10.cbData); CryptSignAndEncodeCertificate(FPublicKeyProv.Context, FKeySpec, X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, X509_CERT_REQUEST_TO_BE_SIGNED, @CertReq, @Sign, nil, PKCS10.pbData, @PKCS10.cbData); end else begin FErrorCode := GetLastError; Abort; end; FErrorCode := 0; Result := TCryptConvert.PCharToStr(PChar(PKCS10.pbData), PKCS10.cbData); finally if Assigned(Subj) then FreeMem(Subj); if Assigned(CertReq.Subject.pbData) then FreeMem(CertReq.Subject.pbData); if Assigned(KeyUsage.pbData) then FreeMem(KeyUsage.pbData); if Assigned(ExtKeyUsage) and Assigned(ExtKeyUsage.Value.pbData) then FreeMem(ExtKeyUsage.Value.pbData); if Assigned(EnhKeyUsage.rgpszUsageIdentifier) then FreeMem(EnhKeyUsage.rgpszUsageIdentifier); if Assigned(ExtEnhKeyUsage) and Assigned(ExtEnhKeyUsage.Value.pbData) then FreeMem(ExtEnhKeyUsage.Value.pbData); if Assigned(ExtTemplate) and Assigned(ExtTemplate.Value.pbData) then FreeMem(ExtTemplate.Value.pbData); if Assigned(ExtContainer) and Assigned(ExtContainer.Value.pbData) then FreeMem(ExtContainer.Value.pbData); if Assigned(Exts.rgExtension) then FreeMem(Exts.rgExtension); if Assigned(AttrBlob.pbData) then FreeMem(AttrBlob.pbData); if Assigned(PKCS10.pbData) then FreeMem(PKCS10.pbData); end; except end; end; Здесь используются свойства класса: FKeyUsage - список использований ключа FExtKeyUsage - список enh key usage FTemplateName - имя шаблона Использование: CR := TCryptCertRequest.Create; CR.CommonName := ’Boris 6’; CR.CountryName := ’RU’; CR.KeySpec := 2; CR.AddExtKeyUsage(szOID_PKIX_KP_CLIENT_AUTH); CR.PublicKeyProvider := TCryptProvider.GenNewKey(PROV_GOST_2001_DH); Res := TCryptConvert.BinaryToBase64(CR.PKCS10); Либо с помощью XEnroll’а: CEnroll1.ProviderType := PROV_GOST_2001_DH; CEnroll1.KeySpec := 2; Res := CEnroll1.createPKCS10(’C=RU, CN=Boris 6’, szOID_PKIX_KP_CLIENT_AUTH); | ||||
| ||||
Нет - я имел ввиду запрос, который не проходит в CreateRequest | ||||
| ||||
Ой... простите :) MIIBHDCBygIBADAnMQswCQYDVQQGEwJSVTEYMBYGA1UEAxMPQm9yaXMgVHl1bW5ldiA2MGMwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEDQwAEQKGOTpOxTHJg2JcQvtlwOsQUCsYqraIV/6mXjLumE8PBWjhDS8pUl+pnbfGhRdK7cJz8HmsCwM+igEl5G7THj/igNzA1BgorBgEEAYI3AgEOMScwJTAOBgNVHQ8BAf8EBAMCAAEwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCgYGKoUDAgIDBQADQQDtiBPHhPztgkMMFfQvMTaBaZqWqFBkKPeX8PxSz+cGiI3Fr5TnxN0lGpYpa7s5bFn0L4cwh6+SUiAfjtCRO4Rg | ||||
| ||||
Странный вызов CreateRequest - у нее дб 3 параметра, причем второй как раз не используется. | ||||
| ||||
Вот мой вызов: Reg.CreateRequest(Res, ’’, ’’); На сколько я понял из документации: Первый параметр это запрос на регистрацию пользователя, который может быть запросом на сертификат (PKCS10) Второй - не используется. Я его оставляю пустой строкой. Третий - доп. информация о пользователе. Я ее тоже оставляю пустой. Или я что-то не так понял. | ||||
| ||||
На что ориентируется ЦР, (ЦС пропускает) в запросе на сертификат, сделанном с помощью XEnroll’а. | ||||
| ||||
Сорри я не воспринял что это Дельфи :) тогда вызов вполне нормальный. ЦР в т.ч. проверяет, соотвествует ли DN политике имен. Пока ситуацию воспроизвести не удается, т.е. Ваш запрос вполне корректно обрабатывается. А какой у Вас билд УЦ? | ||||
| ||||
А где можно посмотреть номер версии? | ||||
| ||||
Параметры ЦР - Свойства - Лицензия | ||||
| ||||
Уникальный номер: 2 Тип лицензии: Расширенная Номера версии на этой вкладки нет. | ||||
| ||||
Может необходимо мне обновить ЦР или базу данных? | ||||
| ||||
Проблема для меня так и не решилась. Каким-образом можно получить обновление КриптоПРО УЦ? | ||||
| ||||
ftp://ftp.cryptopro.ru/pub/UC/CryptoPro_UC_1_03_429.zip | ||||
| ||||
Спасибо. Качаю. | ||||