| ||||
| ||||
Здравствуйте. Необходимо создавать запрос на сертификат с парой ключей на дискете, подписывать у Microsoft CA и выдавать клиенту. Создать запрос с помощью XEnroll не получилось (а жаль), т.к. он не позволяет перекрыть интерфейс ввода пароля для пары ключей (или я не прав?). Создаю запрос с помощью CryptoAPI следующим кодом: LPBYTE CreateCertificate(LPCSTR szCerName, DWORD* dwSize) { CERT_RDN_ATTR rgNameAttr[1] = { szOID_COMMON_NAME, // pszObjId CERT_RDN_PRINTABLE_STRING, // dwValueType strlen(szCerName), // value.cbData (BYTE*)szCerName}; // value.pbData CERT_RDN rgRDN[] = { 1, // rgRDN[0].cRDNAttr &rgNameAttr[0]}; // rgRDN[0].rgRDNAttr CERT_NAME_INFO Name = { 1, // Name.cRDN rgRDN}; // Name.rgRDN //------------------------------------------------------------------- // Declare and initialize all other variables and structures. CERT_REQUEST_INFO CertReqInfo; CERT_NAME_BLOB SubjNameBlob; DWORD cbNameEncoded; BYTE* pbNameEncoded; HCRYPTPROV hCryptProv; DWORD cbPublicKeyInfo; CERT_PUBLIC_KEY_INFO* pbPublicKeyInfo; CRYPT_OBJID_BLOB Parameters; CRYPT_ALGORITHM_IDENTIFIER SigAlg; BYTE* pbSignedEncodedCertReq; char* pSignedEncodedCertReqBlob; BOOL bResult = FALSE; LPSTR szContainer = NULL; CHAR* szProvider = CP_DEF_PROV; //CHAR* szProvider = MS_ENHANCED_PROV; DWORD dwProviderType = PROV_GOST_DH; //PROV_RSA_FULL; RPC_STATUS Status; if(CryptEncodeObject( MY_ENCODING_TYPE, // Encoding type X509_NAME, // Structure type &Name, // Address of CERT_NAME_INFO structure NULL, // pbEncoded &cbNameEncoded)) // pbEncoded size { printf("The first call to CryptEncodeObject succeeded. \n"); } else { printf("First call to CryptEncodeObject failed.\ \nA public/private key pair may not exit in the container. \n"); } //------------------------------------------------------------------- // Allocate memory for the encoded name. if(!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded))) printf("pbNamencoded malloc operation failed.\n"); //------------------------------------------------------------------- // Call CryptEncodeObject to do the actual encoding of the name. if(CryptEncodeObject( MY_ENCODING_TYPE, // Encoding type X509_NAME, // Structure type &Name, // Address of CERT_NAME_INFO structure pbNameEncoded, // pbEncoded &cbNameEncoded)) // pbEncoded size { printf("The object is encoded. \n"); } else { free(pbNameEncoded); printf("Second call to CryptEncodeObject failed.\n"); } //-------------------------------------------------------------------- // Set the subject member of CertReqInfo to point to // a CERT_NAME_INFO structure that // has been initialized with the data from cbNameEncoded // and pbNameEncoded. 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; CertReqInfo.dwVersion = CERT_V1; /* Create a random uuid*/ UUID Uuid; Status = UuidCreate(&Uuid); if (Status != RPC_S_OK) { printf("Unable to create random container\n"); } /* convert random uuid to a string, we will use it as a container*/ Status = UuidToString(&Uuid, (unsigned char **)&szContainer); if (Status != RPC_S_OK) { printf("Unable to convert uuid to string\n"); } /* Create new crypto context*/ bResult = CryptAcquireContext(&hCryptProv, szContainer, szProvider, dwProviderType, CRYPT_NEWKEYSET); if (!bResult) { printf("CryptAcquireContext failed with %x\n", GetLastError()); } bResult = CryptSetProvParam(hCryptProv, PP_KEYEXCHANGE_PIN, (BYTE*)"pass", 0); if (!bResult) { printf("CryptSetProvParam failed with %x\n", GetLastError()); } DWORD dwKeyType = AT_KEYEXCHANGE; HCRYPTKEY hPubKey = 0; /* Generate Private/Public key pair*/ bResult = CryptGenKey(hCryptProv, dwKeyType, CRYPT_EXPORTABLE, &hPubKey); if (!bResult) { printf("CryptGenKey failed with %x\n", GetLastError()); } if(CryptExportPublicKeyInfo( hCryptProv, // Provider handle dwKeyType, // Key spec MY_ENCODING_TYPE, // Encoding type NULL, // pbPublicKeyInfo &cbPublicKeyInfo)) // Size of PublicKeyInfo { printf("The keyinfo structure is %d bytes.\n",cbPublicKeyInfo); } else { free(pbNameEncoded); printf("First call to CryptExportPublickKeyInfo failed.\ \nProbable cause: No key pair in the key container. Error = %d\n", GetLastError()); } if(pbPublicKeyInfo = (CERT_PUBLIC_KEY_INFO*)malloc(cbPublicKeyInfo)) { printf("Memory is allocated for the public key structure. \n"); } else { free(pbNameEncoded); printf("Memory allocation failed."); } if(CryptExportPublicKeyInfo( hCryptProv, // Provider handle dwKeyType, // Key spec MY_ENCODING_TYPE, // Encoding type pbPublicKeyInfo, // pbPublicKeyInfo &cbPublicKeyInfo)) // Size of PublicKeyInfo { printf("The key has been exported. \n"); } else { free(pbNameEncoded); free(pbPublicKeyInfo); printf("Second call to CryptExportPublicKeyInfo failed."); } //-------------------------------------------------------------------- // Set the SubjectPublicKeyInfo member of the // CERT_REQUEST_INFO structure to point to the CERT_PUBLIC_KEY_INFO // structure created. CertReqInfo.SubjectPublicKeyInfo = *pbPublicKeyInfo; memset(&Parameters, 0, sizeof(Parameters)); SigAlg.pszObjId = szOID_OIWSEC_sha1RSASign; SigAlg.Parameters = Parameters; //-------------------------------------------------------------------- // Call CryptSignAndEncodeCertificate to get the size of the // returned BLOB. if(CryptSignAndEncodeCertificate( hCryptProv, // Crypto provider AT_KEYEXCHANGE, // Key spec MY_ENCODING_TYPE, // Encoding type X509_CERT_REQUEST_TO_BE_SIGNED, // Structure type &CertReqInfo, // Structure information &SigAlg, // Signature algorithm NULL, // Not used NULL, // pbSignedEncodedCertReq dwSize)) // Size of certificate // required { printf("The size of the encoded certificate is set. \n"); } else { free(pbNameEncoded); free(pbPublicKeyInfo); printf("First call to CryptSignandEncode failed."); } //-------------------------------------------------------------------- // Allocate memory for the encoded certificate request. if(pbSignedEncodedCertReq = (BYTE*)malloc(*dwSize)) { printf("Memory has been allocated.\n"); } else { free(pbNameEncoded); free(pbPublicKeyInfo); printf("Malloc operation failed."); } //-------------------------------------------------------------------- // Call CryptSignAndEncodeCertificate to get the // returned BLOB. if(CryptSignAndEncodeCertificate( hCryptProv, // Crypto provider AT_KEYEXCHANGE, // Key spec MY_ENCODING_TYPE, // Encoding type X509_CERT_REQUEST_TO_BE_SIGNED, // Struct type &CertReqInfo, // Struct info &SigAlg, // Signature algorithm NULL, // Not used pbSignedEncodedCertReq, // Pointer dwSize)) // Length of the message { printf("The message is encoded and signed. \n"); } else { free(pbNameEncoded); free(pbPublicKeyInfo); printf("Second call to CryptSignAndEncode failed."); } DWORD dwSize64 = *dwSize*2; LPBYTE pBase64Req = (LPBYTE)malloc(dwSize64); BOOL isOk = base64_encode(pbSignedEncodedCertReq, *dwSize, pBase64Req, &dwSize64); *dwSize = dwSize64; free(pbSignedEncodedCertReq); free(pbNameEncoded); free(pbPublicKeyInfo); CryptReleaseContext(hCryptProv,0); return pBase64Req; } на выходе получаю BASE64 запрос (base64_encode заимствована из ваших примеров) затем преобразую его в BSTR strCert. далее использую ICertRequest из certcli.dll для подписи сертификата у CA: CERTCLIENTLib::ICertRequestPtr pRequest; pRequest.CreateInstance(CERTCLIENTLib::CLSID_CCertRequest); pRequest->Submit(CR_IN_BASE64 | CR_IN_PKCS7, strCert, L"", L"URAN\\DebugCA"); Submit выдает ошибку: "Ошибка: ASN1 bad tag value met." Что я делаю не так? Спасибо. |