String WebCore::signedPublicKeyAndChallengeString(unsigned index, const String& challenge, const KURL& url) { String keyString; HCRYPTPROV hContext = 0; HCRYPTKEY hKey = 0; PCERT_PUBLIC_KEY_INFO pPubInfo = 0; // Try to delete it if it exists already CryptAcquireContextW(&hContext, L"keygen_container", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET); do { if (!CryptAcquireContextW(&hContext, L"keygen_container", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) break; DWORD dwPubInfoLength = 0; if (!CryptGenKey(hContext, AT_KEYEXCHANGE, 0, &hKey) || !CryptExportPublicKeyInfo(hContext, AT_KEYEXCHANGE, X509_ASN_ENCODING, 0, &dwPubInfoLength)) break; // Use malloc instead of new, because malloc guarantees to return a pointer aligned for all data types. pPubInfo = reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(fastMalloc(dwPubInfoLength)); if (!CryptExportPublicKeyInfo(hContext, AT_KEYEXCHANGE, X509_ASN_ENCODING, pPubInfo, &dwPubInfoLength)) break; CERT_KEYGEN_REQUEST_INFO requestInfo = { 0 }; requestInfo.dwVersion = CERT_KEYGEN_REQUEST_V1; requestInfo.pwszChallengeString = L""; requestInfo.SubjectPublicKeyInfo = *pPubInfo; String localChallenge = challenge; // Windows API won't write to our buffer, although it's not declared with const. requestInfo.pwszChallengeString = const_cast<wchar_t*>(localChallenge.charactersWithNullTermination()); CRYPT_ALGORITHM_IDENTIFIER signAlgo = { 0 }; signAlgo.pszObjId = szOID_RSA_SHA1RSA; DWORD dwEncodedLength; if (!CryptSignAndEncodeCertificate(hContext, AT_KEYEXCHANGE, X509_ASN_ENCODING, X509_KEYGEN_REQUEST_TO_BE_SIGNED, &requestInfo, &signAlgo, 0, 0, &dwEncodedLength)) break; Vector<char> binary(dwEncodedLength); if (!CryptSignAndEncodeCertificate(hContext, AT_KEYEXCHANGE, X509_ASN_ENCODING, X509_KEYGEN_REQUEST_TO_BE_SIGNED, &requestInfo, &signAlgo, 0, reinterpret_cast<LPBYTE>(binary.data()), &dwEncodedLength)) break; keyString = base64Encode(binary); } while(0); if (pPubInfo) fastFree(pPubInfo); if (hKey) CryptDestroyKey(hKey); if (hContext) CryptReleaseContext(hContext, 0); return keyString; }
void ca_generate_root_ca_cert_t::generate_ca_cert_clicked(){ GIE_QT_DEF_EXCEPTION_GUARD_BEGIN stcrypt::cert_name_t cert_subject_name; #define STCRYPT_TOYCA_CP_NAME(x) { auto str = ui.x##_edit->text().toStdWString(); cert_subject_name.set_##x( std::move(str) ); } STCRYPT_TOYCA_CP_NAME(common_name); STCRYPT_TOYCA_CP_NAME(country_name); STCRYPT_TOYCA_CP_NAME(locality_name); STCRYPT_TOYCA_CP_NAME(organization_name); STCRYPT_TOYCA_CP_NAME(organization_unit_name); STCRYPT_TOYCA_CP_NAME(state_or_province_name); STCRYPT_TOYCA_CP_NAME(email_name); #undef STCRYPT_TOYCA_CP_NAME // generate key pair NCRYPT_PROV_HANDLE cng_provider=0; NCRYPT_KEY_HANDLE cng_n_key_pair=0; auto status = NCryptOpenStorageProvider(&cng_provider, CNG_STCRYPT_KEYSTORAGE, 0); STCRYPT_CHECK(!FAILED(status)); BOOST_SCOPE_EXIT((&cng_provider)) { auto const status = NCryptFreeObject (cng_provider); assert( !FAILED(status) ); } BOOST_SCOPE_EXIT_END boost::uuids::uuid const key_container_id( (boost::uuids::random_generator()()) ); auto const& key_pair_container_name = boost::lexical_cast<std::wstring>( key_container_id ); status = NCryptCreatePersistedKey(cng_provider, &cng_n_key_pair, NCNG_DSTU4145, key_pair_container_name.c_str(), AT_KEYEXCHANGE, 0/*NCRYPT_OVERWRITE_KEY_FLAG*/); STCRYPT_CHECK(!FAILED(status)); BOOST_SCOPE_EXIT((&cng_n_key_pair)) { auto const status = NCryptFreeObject (cng_n_key_pair); assert( !FAILED(status) ); } BOOST_SCOPE_EXIT_END status = NCryptFinalizeKey(cng_n_key_pair, 0); STCRYPT_CHECK(!FAILED(status)); auto const& to_be_signed_cert_blob = ms_cert::create_req_blob(cert_subject_name, cng_n_key_pair, cert_subject_name); DWORD size; STCRYPT_CHECK( CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, reinterpret_cast<BYTE const*> (to_be_signed_cert_blob.data()), to_be_signed_cert_blob.size(), CRYPT_DECODE_TO_BE_SIGNED_FLAG, 0, 0, &size) ); STCRYPT_CHECK(size!=0); std::vector<unsigned char> to_be_signed_cert_blob_combined(size); STCRYPT_CHECK( CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, reinterpret_cast<BYTE const*> (to_be_signed_cert_blob.data()), to_be_signed_cert_blob.size(), CRYPT_DECODE_TO_BE_SIGNED_FLAG, 0, to_be_signed_cert_blob_combined.data(), &size) ); to_be_signed_cert_blob_combined.resize(size); CERT_INFO* const cert_to_be_signed = static_cast<CERT_INFO*>( static_cast<void*>( to_be_signed_cert_blob_combined.data() ) ); // do sign CRYPT_ALGORITHM_IDENTIFIER signature_alg={OID_G34311_DSTU4145_SIGN,0}; DWORD encoded_cert_size = 0; if( !CryptSignAndEncodeCertificate(cng_n_key_pair, 0, X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, cert_to_be_signed, &signature_alg, 0, 0, &encoded_cert_size) ){ //TODO: this CryptSignAndEncodeCertificate leaks memory STCRYPT_UNEXPECTED(); } STCRYPT_CHECK(encoded_cert_size!=0); std::vector<BYTE> signed_certificate(encoded_cert_size); if( !CryptSignAndEncodeCertificate(cng_n_key_pair, 0, X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, cert_to_be_signed, &signature_alg, 0, signed_certificate.data(), &encoded_cert_size) ){ STCRYPT_UNEXPECTED(); } signed_certificate.resize(encoded_cert_size); // context from signed blob ms_cert::pccert_context_t signed_cert_context( CertCreateCertificateContext (X509_ASN_ENCODING, reinterpret_cast<BYTE const*>( signed_certificate.data() ), signed_certificate.size() ) ); STCRYPT_CHECK( signed_cert_context ); // assign private key container name CRYPT_KEY_PROV_INFO key_prov_info = {0}; key_prov_info.pwszContainerName = const_cast<wchar_t*>( key_pair_container_name.c_str() ); key_prov_info.pwszProvName = CNG_STCRYPT_KEYSTORAGE; key_prov_info.dwProvType = 0; key_prov_info.dwFlags = 0; key_prov_info.cProvParam = 0; key_prov_info.rgProvParam = 0; key_prov_info.dwKeySpec = 0; STCRYPT_CHECK( CertSetCertificateContextProperty(signed_cert_context.handle(), CERT_KEY_PROV_INFO_PROP_ID, 0, &key_prov_info) ); STCRYPT_CHECK( CryptUIDlgViewContext (CERT_STORE_CERTIFICATE_CONTEXT, signed_cert_context.handle(), this->winId(), L"Generated CA certificate [NOT YET INSTALLED]", 0, 0) ); ms_cert::import_into_ms_store2(signed_cert_context.handle(), L"ROOT"); STCRYPT_CHECK( CryptUIDlgViewContext (CERT_STORE_CERTIFICATE_CONTEXT, signed_cert_context.handle(), this->winId(), L"Generated CA certificate", 0, 0) ); toy_ca::initialize_accept_requests_mode( dynamic_cast<QMainWindow*>( this->parent() ), std::move(signed_cert_context) ); GIE_QT_DEF_EXCEPTION_GUARD_END }