| ||||
| ||||
Здравствуйте. Создаю запрос на сертификат с помощью 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 трафика Временный доступ к Центру Регистрации Подпись содержимого сервера Интернет Администратор Центра Регистрации Оператор Центра Регистрации Пользователь Центра Регистрации Центр Регистрации _________________________________ Видимо я не правильно добавляю атрибут. Как добавить правильно? Спасибо. | ||||
Ответы: | ||||
| ||||
Вот описания идентификаторов (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 строку. | ||||
| ||||
Т.е. можно не кодировать атрибут? Если делаю так: 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" Покажите пожалуйста как правильно добавить атрибут, нигде не могу найти примера. | ||||
| ||||
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; } | ||||
| ||||
Этот пример я видел, но тут нет реализации добаления атрибутов: // 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 проходит, но атрибут не добавляется. Что я делаю не так? | ||||
| ||||
Я разобрался. Вот как правильно добавить атрибуты: 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; Спасибо за ответы. | ||||