18.10.2002 14:58:51Добавление атрибутов в запрос на сертификат Ответов: 5
Валентин
Здравствуйте.
Создаю запрос на сертификат с помощью CryptoAPI на основе приметра из MSDN.
Как задать Enhanced Key Usage в Client Authentication(1.3.6.1.5.5.7.3.2)?
На сколько я понимаю, атрибуты в запросе на сертификат можно указать заполнив CERT_REQUEST_INFO.cAttribute и
CERT_REQUEST_INFO.rgAttribute? Вот как я делаю:
CRYPT_ATTR_BLOB ClientAuth = {0, NULL};

CertStrToName(MY_ENCODING_TYPE,
"OID.1.3.6.1.5.5.7.3.2=",//szOID_PKIX_KP_CLIENT_AUTH
CERT_OID_NAME_STR,
NULL,
NULL,
&ClientAuth.cbData,
NULL);

ClientAuth.pbData = (LPBYTE)malloc(ClientAuth.cbData);

CertStrToName(MY_ENCODING_TYPE,
"OID.1.3.6.1.5.5.7.3.2=",
CERT_OID_NAME_STR,
NULL,
(LPBYTE)ClientAuth.pbData,
&ClientAuth.cbData,
NULL);

CRYPT_ATTRIBUTE rgAttrib[] = {
szOID_ENHANCED_KEY_USAGE,
1,
&ClientAuth};

CertReqInfo.cAttribute = 1;
CertReqInfo.rgAttribute = rgAttrib;

Запрос создается, подписываю у CA, смотрю сертификат, но атрибут не добавился, и в разделе "The certificate is intended to:" перечислены все возможные способы действия сертификата:

Ensures the identity of a remote computer
Proves your identity to a remote computer
Ensures software came from software publisher
Protects software from alteration after publication
Protects e-mail messages
Allows data to be signed with the current time
Allows you to digitally sign a certificate trust list
Allows secure communication on the Internet
Allows data on disk to be encrypted
Windows Hardware Driver Verification
Windows System Component Verification
OEM Windows System Component Verification
Embedded Windows System Component Verification
Key Pack Licenses
License Server Verification
Smart Card Logon
Digital Rights
Аудит TLS трафика
Временный доступ к Центру Регистрации
Подпись содержимого сервера Интернет
Администратор Центра Регистрации
Оператор Центра Регистрации
Пользователь Центра Регистрации
Центр Регистрации



_________________________________

Видимо я не правильно добавляю атрибут. Как добавить правильно?

Спасибо.
 
Ответы:
21.10.2002 21:21:49kure
Вот описания идентификаторов (rfc 2459)
id-pkix OBJECT IDENTIFIER ::=
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) }

id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }

id-kp-serverAuth OBJECT IDENTIFIER ::= {id-kp 1}
-- TLS Web server authentication
-- Key usage bits that may be consistent: digitalSignature,
-- keyEncipherment or keyAgreement
--
id-kp-clientAuth OBJECT IDENTIFIER ::= {id-kp 2}
-- TLS Web client authentication
-- Key usage bits that may be consistent: digitalSignature and/or
-- keyAgreement
--
id-kp-codeSigning OBJECT IDENTIFIER ::= {id-kp 3}
-- Signing of downloadable executable code
-- Key usage bits that may be consistent: digitalSignature
--
id-kp-emailProtection OBJECT IDENTIFIER ::= {id-kp 4}
-- E-mail protection
-- Key usage bits that may be consistent: digitalSignature,
-- nonRepudiation, and/or (keyEncipherment
-- or keyAgreement)
--
id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
-- Binding the hash of an object to a time from an agreed-upon time
-- source. Key usage bits that may be consistent: digitalSignature,
-- nonRepudiation


Если посмотрите повнимательней на пример создания запроса, то в создании имени пишется:
2.5.3 и т.д.

Не надо писать OID.1.2.
Нужно просто идентификатое 1.2.

И потом CertStrToName к идентификаторам использования сертификата не имеет отношения. Она конвертит в Х509 Name строку.
22.10.2002 12:04:15Валентин
Т.е. можно не кодировать атрибут?
Если делаю так:
CRYPT_ATTR_BLOB ClientAuth[] ={strlen(szOID_PKIX_KP_CLIENT_AUTH), (LPBYTE)szOID_PKIX_KP_CLIENT_AUTH};
CRYPT_ATTRIBUTE rgAttrib[] = {
szOID_ENHANCED_KEY_USAGE, 1, &ClientAuth[0]};
CertReqInfo.cAttribute = 1;
CertReqInfo.rgAttribute = &rgAttrib[0];
То при ICertRequest->Submit возникает ошибка:
"ASN1 unexpected end of data."

в wincrypt.h перед объявлением структуры CERT_REQUEST_INFO написано: "The Subject, Algorithm, PublicKey and Attribute BLOBs are the encoded representation of the information"
Покажите пожалуйста как правильно добавить атрибут, нигде не могу найти примера.
22.10.2002 12:33:49kure
BOOL
CryptMakeCertReq(
PCERT_PARAMS pCertParams,
PCERT_BLOB pCertReqBlob
)
{
BOOL MResult=TRUE;

CERT_REQUEST_INFO CertReqInfo;
PCERT_PUBLIC_KEY_INFO pbPublicKeyInfo=NULL;
DWORD cbEncodedCertReqSize;
DWORD cbPublicKeyInfo;

CRYPT_OBJID_BLOB Parameters;
CRYPT_ALGORITHM_IDENTIFIER SigAlg;

CERT_NAME_BLOB SubjNameBlob;
LPBYTE pbNameEncoded=NULL;
DWORD cbNameEncoded=0;
CERT_RDN_ATTR rgNameAttr[4];
CERT_RDN rgRDN[4]={
{1,&rgNameAttr[0]},
{1,&rgNameAttr[1]},
{1,&rgNameAttr[2]},
{1,&rgNameAttr[3]}
};
CERT_NAME_INFO Name={4,&rgRDN[0]};



// Формируем структуру CertReqInfo
// Обнуляем неоходимые структуры
ZeroMemory(&CertReqInfo,sizeof(CERT_REQUEST_INFO));
ZeroMemory(&SubjNameBlob,sizeof(CERT_NAME_BLOB));
ZeroMemory(&Parameters,sizeof(CRYPT_OBJID_BLOB));

// Set the Version member of CERT_REQUEST_INFO as appropriate.
CertReqInfo.dwVersion = CERT_REQUEST_V1;

rgNameAttr[0].pszObjId = szOID_COUNTRY_NAME;
rgNameAttr[0].dwValueType = CERT_RDN_UNICODE_STRING;
rgNameAttr[0].Value.cbData=UniStrLen(pCertParams->SubjectName.pwszCountry);
rgNameAttr[0].Value.pbData=(LPBYTE)pCertParams->SubjectName.pwszCountry;

rgNameAttr[1].pszObjId = szOID_ORGANIZATION_NAME;
rgNameAttr[1].dwValueType = CERT_RDN_UNICODE_STRING;
rgNameAttr[1].Value.cbData=UniStrLen(pCertParams->SubjectName.pwszOrganization);
rgNameAttr[1].Value.pbData=(LPBYTE)pCertParams->SubjectName.pwszOrganization;

rgNameAttr[2].pszObjId = szOID_ORGANIZATIONAL_UNIT_NAME;
rgNameAttr[2].dwValueType = CERT_RDN_UNICODE_STRING;
rgNameAttr[2].Value.cbData=UniStrLen(pCertParams->SubjectName.pwszOrganizationUnit);
rgNameAttr[2].Value.pbData=(LPBYTE)pCertParams->SubjectName.pwszOrganizationUnit;

rgNameAttr[3].pszObjId = szOID_COMMON_NAME;
rgNameAttr[3].dwValueType = CERT_RDN_UNICODE_STRING;
rgNameAttr[3].Value.cbData=UniStrLen(pCertParams->SubjectName.pwszCommonName);
rgNameAttr[3].Value.pbData=(LPBYTE)pCertParams->SubjectName.pwszCommonName;


if (!CryptEncodeObject(
MY_ENCODING_TYPE, // Encoding type
X509_NAME, // Struct type
&Name, // Address of CERT_NAME_INFO struct.
NULL, // pbEncoded
&cbNameEncoded)) { // pbEncoded size
printf("Error: CryptEncodeObject = 0x%X.\n", GetLastError());
MResult=FALSE;
goto ReleaseResource;
}
pbNameEncoded = AllocMemory(cbNameEncoded);
if(!pbNameEncoded){
printf("Error: Out of memory.\n");
MResult=FALSE;
goto ReleaseResource;
}
if(!CryptEncodeObject(
MY_ENCODING_TYPE, // Encoding type
X509_NAME, // Struct type
&Name, // Address of CERT_NAME_INFO struct.
pbNameEncoded, // pbEncoded
&cbNameEncoded)) // pbEncoded size
{
printf("Error: CryptEncodeObject = 0x%X.\n", GetLastError());
MResult=FALSE;
goto ReleaseResource;
}

// Declare a CERT_REQUEST_INFO structure and set the
// Subject member to point to a CERT_NAME_INFO structure.
SubjNameBlob.cbData = cbNameEncoded;
SubjNameBlob.pbData = pbNameEncoded;
CertReqInfo.Subject = SubjNameBlob;

// Generate custom information. This step is not implemented in this code.
CertReqInfo.cAttribute = 0;
CertReqInfo.rgAttribute = NULL;

// Call CryptExportPublicKeyInfo to return an initialized CERT_PUBLIC_KEY_INFO structure.
// Call CryptExportPublicKeyInfo to get the size of the returned information.
if (!CryptExportPublicKeyInfo(
pCertParams->hSubjectProv, // Provider handle
pCertParams->dwSubjectKeySpec, // Key spec
MY_ENCODING_TYPE, // Encoding type
NULL, // pbPublicKeyInfo
&cbPublicKeyInfo)) { // Size of PublicKeyInfo
printf("Error: CryptExportPublicKeyInfo = 0x%X.\n", GetLastError());
MResult=FALSE;
goto ReleaseResource;
}
// Allocate the necessary memory.
pbPublicKeyInfo = (CERT_PUBLIC_KEY_INFO*)AllocMemory(cbPublicKeyInfo);
if (!pbPublicKeyInfo){
printf("Error: Out of memory.\n");
MResult=FALSE;
goto ReleaseResource;
}
// Call CryptExportPublicKeyInfo to get pbPublicKeyInfo.
if (!CryptExportPublicKeyInfo(
pCertParams->hSubjectProv, // Provider handle
pCertParams->dwSubjectKeySpec, // Key spec
MY_ENCODING_TYPE, // Encoding type
pbPublicKeyInfo, // pbPublicKeyInfo
&cbPublicKeyInfo)) { // Size of PublicKeyInfo
printf("Error: CryptExportPublicKeyInfo = 0x%X.\n", GetLastError());
MResult=FALSE;
goto ReleaseResource;
}

// Set the SubjectPublicKeyInfo member of the CERT_REQUEST_INFO
// structure to point to the CERT_PUBLIC_KEY_INFO structure.
CertReqInfo.SubjectPublicKeyInfo = *pbPublicKeyInfo;

// Call CryptSignAndEncodeCertificate to encode, sign,
// and re-encode the CERT_REQUEST_INFO structure and the data pointed to by it.
SigAlg.pszObjId = DEFAULT_SIGN_OID; //szOID_X957_SHA1DSA; //szOID_OIWSEC_sha1RSASign;
SigAlg.Parameters = Parameters;

// Call CryptSignAndEncodeCertificate to get the size of the returned blob.
if (!CryptSignAndEncodeCertificate(
pCertParams->hSubjectProv, // Crypto provider
AT_SIGNATURE, // Key spec.
MY_ENCODING_TYPE, // Encoding type
X509_CERT_REQUEST_TO_BE_SIGNED, // Struct type
&CertReqInfo, // Struct info
&SigAlg, // Signature algorithm
NULL, // Not used
NULL, // pbSignedEncodedCertReq
&cbEncodedCertReqSize)) { // Size of cert req
printf("Error: CryptSignAndEncodeCertificate = 0x%X.\n", GetLastError());
MResult=FALSE;
goto ReleaseResource;
}

if (pCertReqBlob->pbData==NULL) {
pCertReqBlob->cbData=cbEncodedCertReqSize;
goto ReleaseResource;
}
else {
if (pCertReqBlob->cbData < cbEncodedCertReqSize) {
pCertReqBlob->cbData=cbEncodedCertReqSize;
SetLastError(ERROR_MORE_DATA);
MResult=FALSE;
goto ReleaseResource;
}
};

// Call CryptSignAndEncodeCertificate to get the returned blob.
if (!CryptSignAndEncodeCertificate(
pCertParams->hSubjectProv, // Crypto provider
AT_SIGNATURE, // Key spec.
MY_ENCODING_TYPE, // Encoding type
X509_CERT_REQUEST_TO_BE_SIGNED, // Struct type
&CertReqInfo, // Struct info
&SigAlg, // Signature algorithm
NULL, // Not used
pCertReqBlob->pbData, // Pointer
&pCertReqBlob->cbData)) { // Size
printf("Error: CryptSignAndEncodeCertificate = 0x%X.\n", GetLastError());
MResult=FALSE;
goto ReleaseResource;
}

// Возвращаем размер кодированного запроса
pCertReqBlob->cbData=cbEncodedCertReqSize;

ReleaseResource:
if (pbPublicKeyInfo) FreeMemory(pbPublicKeyInfo);
if (pbNameEncoded) FreeMemory(pbNameEncoded);

return MResult;
}
22.10.2002 13:29:10Валентин
Этот пример я видел, но тут нет реализации добаления атрибутов:

// Generate custom information. This step is not implemented in this code.
CertReqInfo.cAttribute = 0;
CertReqInfo.rgAttribute = NULL;

еще раз, как я делаю:
CRYPT_ATTR_BLOB ClientAuth[1] ={wcslen(A2W(szOID_PKIX_KP_CLIENT_AUTH)), (LPBYTE)A2W(szOID_PKIX_KP_CLIENT_AUTH)};


CRYPT_ATTRIBUTE rgAttrib[1] = {
szOID_ENHANCED_KEY_USAGE, 1, &ClientAuth[0]};


DWORD dw = 0;
bResult = CryptEncodeObject(
MY_ENCODING_TYPE, // Encoding type
PKCS_ATTRIBUTE, // Structure type
&rgAttrib, // Address of CRYPT_ATTRIBUTE structure
NULL, // pbEncoded
&dw); // pbEncoded size

LPBYTE pAttr = (LPBYTE)malloc(dw);
bResult = CryptEncodeObject(
MY_ENCODING_TYPE, // Encoding type
PKCS_ATTRIBUTE, // Structure type
&rgAttrib, // Address of CRYPT_ATTRIBUTE structure
pAttr, // pbEncoded
&dw); // pbEncoded size

ClientAuth[0].cbData = dw;
ClientAuth[0].pbData = pAttr;
CertReqInfo.cAttribute = 1;
CertReqInfo.rgAttribute = &rgAttrib[0];


Submit проходит, но атрибут не добавляется.
Что я делаю не так?
22.10.2002 16:01:32Валентин
Я разобрался. Вот как правильно добавить атрибуты:

CERT_ENHKEY_USAGE CertEnhKeyUsage = {0};
CertEnhKeyUsage.cUsageIdentifier = 1;
CertEnhKeyUsage.rgpszUsageIdentifier = (LPSTR*)malloc(sizeof(LPSTR)*CertEnhKeyUsage.cUsageIdentifier);
CertEnhKeyUsage.rgpszUsageIdentifier[0] = szOID_PKIX_KP_CLIENT_AUTH; //аутентификация клиента

CERT_EXTENSION CertExtEnhKeyUsage = {0};
bResult = CryptEncodeObject(MY_ENCODING_TYPE,
X509_ENHANCED_KEY_USAGE,
(LPVOID)&CertEnhKeyUsage,
NULL,
&CertExtEnhKeyUsage.Value.cbData);
CertExtEnhKeyUsage.Value.pbData = (LPBYTE)malloc(CertExtEnhKeyUsage.Value.cbData);
//кодируем
bResult = CryptEncodeObject(MY_ENCODING_TYPE,
X509_ENHANCED_KEY_USAGE,
(LPVOID)&CertEnhKeyUsage,
CertExtEnhKeyUsage.Value.pbData,
&CertExtEnhKeyUsage.Value.cbData);

free(CertEnhKeyUsage.rgpszUsageIdentifier);

CERT_EXTENSIONS CertExtentions;
CertExtEnhKeyUsage.pszObjId = szOID_ENHANCED_KEY_USAGE;
CertExtEnhKeyUsage.fCritical = FALSE;
CertExtentions.cExtension = 1;
CertExtentions.rgExtension = &CertExtEnhKeyUsage;

CRYPT_ATTR_BLOB CertAttrBlob = {0, NULL};
bResult = CryptEncodeObject(
MY_ENCODING_TYPE,
szOID_CERT_EXTENSIONS,
&CertExtentions,
NULL,
&CertAttrBlob.cbData);

CertAttrBlob.pbData = (LPBYTE)malloc(CertAttrBlob.cbData);
bResult = CryptEncodeObject(
MY_ENCODING_TYPE,
szOID_CERT_EXTENSIONS,
&CertExtentions,
CertAttrBlob.pbData,
&CertAttrBlob.cbData);

free(CertExtEnhKeyUsage.Value.pbData);

CRYPT_ATTRIBUTE rgAttrib = {szOID_CERT_EXTENSIONS, 1, &CertAttrBlob};
CertReqInfo.cAttribute = 1;
CertReqInfo.rgAttribute = &rgAttrib;

Спасибо за ответы.