11.04.2005 11:44:36Разница работы через ЦР и без него в УЦ КриптоПРО Ответов: 21
Борис Тюмнев
Сложилась такая специфическая ситуация.
Есть 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).
Есть ли какие-либо обязательные параметры у запроса через ЦР - может какие-либо расширения и т.п. В документации найти не смог (хотя может плохо искал).
 
Ответы:
11.04.2005 15:41:48Василий
Обязательные параметры задаются в свойствах ЦР.
А принципиальным моментом может быть порядок следования полей DN в запросе.
11.04.2005 15:55:21Борис Тюмнев
В настройках ЦР (на вкладке Политики), в графе "Политика имен" задан только CN обязательный. Я уже по разному пробовал - только CN оставлять, комбинировать различными другими элементами DN. Порядок я брал из документации. В частности - сначала C потом CN.
Также пробовал заменять названия на цифровой аналог 2.5.4.6 и 2.5.4.3.
11.04.2005 16:47:14Kirill Sobolev
Какие сообщения пишутся в журнал ЦР и журнал приложений после вызова метода?
11.04.2005 16:59:27Борис Тюмнев
Моя программа сваливается с ошибкой 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&rsquo;е ЦР - нет сообщений
В Event Viewer&rsquo;е, раздел 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..
11.04.2005 17:12:57Kirill Sobolev
Ясно, а как вызывается Registration.CreateRequest?
11.04.2005 17:15:44Борис Тюмнев
RegID := Reg.CreateRequest(Res, &rsquo;&rsquo;, &rsquo;&rsquo;);
где Res - это запрос на сертификат в base64.
11.04.2005 17:18:42Kirill Sobolev
Ну давайте и запрос тоже :)
11.04.2005 17:29:49Борис Тюмнев
Вот функция член класса, формирующая 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 := &rsquo;&rsquo;;
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 <> &rsquo;&rsquo; then Inc(Exts.cExtension);
if FContainerName <> &rsquo;&rsquo; 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 <> &rsquo;&rsquo; 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 <> &rsquo;&rsquo; 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 := &rsquo;Boris 6&rsquo;;
CR.CountryName := &rsquo;RU&rsquo;;
CR.KeySpec := 2;
CR.AddExtKeyUsage(szOID_PKIX_KP_CLIENT_AUTH);
CR.PublicKeyProvider := TCryptProvider.GenNewKey(PROV_GOST_2001_DH);
Res := TCryptConvert.BinaryToBase64(CR.PKCS10);

Либо с помощью XEnroll&rsquo;а:
CEnroll1.ProviderType := PROV_GOST_2001_DH;
CEnroll1.KeySpec := 2;
Res := CEnroll1.createPKCS10(&rsquo;C=RU, CN=Boris 6&rsquo;, szOID_PKIX_KP_CLIENT_AUTH);
11.04.2005 17:33:16Kirill Sobolev
Нет - я имел ввиду запрос, который не проходит в CreateRequest
11.04.2005 17:34:58Борис Тюмнев
Ой... простите :)
MIIBHDCBygIBADAnMQswCQYDVQQGEwJSVTEYMBYGA1UEAxMPQm9yaXMgVHl1bW5ldiA2MGMwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEDQwAEQKGOTpOxTHJg2JcQvtlwOsQUCsYqraIV/6mXjLumE8PBWjhDS8pUl+pnbfGhRdK7cJz8HmsCwM+igEl5G7THj/igNzA1BgorBgEEAYI3AgEOMScwJTAOBgNVHQ8BAf8EBAMCAAEwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCgYGKoUDAgIDBQADQQDtiBPHhPztgkMMFfQvMTaBaZqWqFBkKPeX8PxSz+cGiI3Fr5TnxN0lGpYpa7s5bFn0L4cwh6+SUiAfjtCRO4Rg
11.04.2005 18:27:40Kirill Sobolev
Странный вызов CreateRequest - у нее дб 3 параметра, причем второй как раз не используется.
11.04.2005 18:32:00Борис Тюмнев
Вот мой вызов: Reg.CreateRequest(Res, ’’, ’’);
На сколько я понял из документации:
Первый параметр это запрос на регистрацию пользователя, который может быть запросом на сертификат (PKCS10)
Второй - не используется. Я его оставляю пустой строкой.
Третий - доп. информация о пользователе. Я ее тоже оставляю пустой.
Или я что-то не так понял.
12.04.2005 12:13:47Борис Тюмнев
На что ориентируется ЦР, (ЦС пропускает) в запросе на сертификат, сделанном с помощью XEnroll&rsquo;а.
12.04.2005 12:38:17Kirill Sobolev
Сорри я не воспринял что это Дельфи :) тогда вызов вполне нормальный.
ЦР в т.ч. проверяет, соотвествует ли DN политике имен.
Пока ситуацию воспроизвести не удается, т.е. Ваш запрос вполне корректно обрабатывается.
А какой у Вас билд УЦ?
12.04.2005 12:58:53Борис Тюмнев
А где можно посмотреть номер версии?
12.04.2005 13:02:29Kirill Sobolev
Параметры ЦР - Свойства - Лицензия
12.04.2005 13:06:24Борис Тюмнев
Уникальный номер: 2
Тип лицензии: Расширенная

Номера версии на этой вкладки нет.
12.04.2005 14:16:53Борис Тюмнев
Может необходимо мне обновить ЦР или базу данных?
13.04.2005 11:17:53Борис Тюмнев
Проблема для меня так и не решилась. Каким-образом можно получить обновление КриптоПРО УЦ?
13.04.2005 11:32:14Kirill Sobolev
ftp://ftp.cryptopro.ru/pub/UC/CryptoPro_UC_1_03_429.zip
13.04.2005 12:06:25Борис Тюмнев
Спасибо. Качаю.