void QCNG::Private::enumKeys( QHash<SslCertificate,QCNGCache> &cache, LPCWSTR provider, LPCWSTR scope ) { QCNGCache c; c.provider = QString::fromWCharArray(provider); NCRYPT_PROV_HANDLE h = 0; SECURITY_STATUS err = NCryptOpenStorageProvider( &h, provider, 0 ); NCryptKeyName *keyname = nullptr; PVOID pos = nullptr; while( NCryptEnumKeys( h, scope, &keyname, &pos, NCRYPT_SILENT_FLAG ) == ERROR_SUCCESS ) { c.key = QString::fromWCharArray(keyname->pszName); c.spec = keyname->dwLegacyKeySpec; qWarning() << "key" << c.key << "spec" << c.spec << "alg" << QString::fromWCharArray(keyname->pszAlgid) << "flags" << keyname->dwFlags; NCRYPT_KEY_HANDLE key = 0; err = NCryptOpenKey( h, &key, keyname->pszName, keyname->dwLegacyKeySpec, NCRYPT_SILENT_FLAG ); NCryptFreeBuffer( keyname ); keyname = nullptr; SslCertificate cert( prop( key, NCRYPT_CERTIFICATE_PROPERTY ), QSsl::Der ); c.guid = prop( h, NCRYPT_SMARTCARD_GUID_PROPERTY ); cache[cert] = c; NCryptFreeObject( key ); } NCryptFreeObject( h ); }
QByteArray QCNG::deriveConcatKDF(const QByteArray &publicKey, const QString &digest, int keySize, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const { d->err = PinUnknown; QByteArray derived; NCRYPT_PROV_HANDLE prov = 0; if(NCryptOpenStorageProvider(&prov, LPCWSTR(d->selected.provider.utf16()), 0)) return derived; NCRYPT_KEY_HANDLE key = 0; if(NCryptOpenKey(prov, &key, LPWSTR(d->selected.key.utf16()), d->selected.spec, 0)) { NCryptFreeObject(prov); return derived; } int err = derive(prov, key, publicKey, digest, keySize, algorithmID, partyUInfo, partyVInfo, derived); NCryptFreeObject(key); switch(err) { case ERROR_SUCCESS: d->err = PinOK; return derived; case SCARD_W_CANCELLED_BY_USER: d->err = PinCanceled; default: return derived; } }
static void setup_x509_schannel_create_ecc_mocks(void) { STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); /*this is creating the handle storage space*/ STRICT_EXPECTED_CALL(CryptStringToBinaryA("certificate", 0, CRYPT_STRING_ANY, NULL, IGNORED_PTR_ARG, NULL, NULL)); /*this is asking for "how big is the certificate binary size?"*/ STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); /*this is creating the binary storage for the certificate*/ STRICT_EXPECTED_CALL(CryptStringToBinaryA("certificate", 0, CRYPT_STRING_ANY, IGNORED_PTR_ARG, IGNORED_PTR_ARG, NULL, NULL)); /*this is asking for "fill in the certificate in this binary buffer"*/ STRICT_EXPECTED_CALL(CryptStringToBinaryA("private key", 0, CRYPT_STRING_ANY, NULL, IGNORED_PTR_ARG, NULL, NULL)); /*this is asking for "how big is the private key binary size?"*/ STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); /*this is creating the binary storage for the private key*/ STRICT_EXPECTED_CALL(CryptStringToBinaryA("private key", 0, CRYPT_STRING_ANY, IGNORED_PTR_ARG, IGNORED_PTR_ARG, NULL, NULL)); /*this is asking for "fill in the private key in this binary buffer"*/ STRICT_EXPECTED_CALL(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, IGNORED_PTR_ARG, IGNORED_NUM_ARG, 0, NULL, NULL, IGNORED_PTR_ARG)).SetReturn(FALSE); /*this is asking "how big is the decoded private key? (from binary)*/ STRICT_EXPECTED_CALL(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_ECC_PRIVATE_KEY, IGNORED_PTR_ARG, IGNORED_NUM_ARG, 0, NULL, NULL, IGNORED_PTR_ARG)); /*this is asking "how big is the decoded private key? (from binary)*/ STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); /*this is allocating space for the decoded private key*/ STRICT_EXPECTED_CALL(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_ECC_PRIVATE_KEY, IGNORED_PTR_ARG, IGNORED_NUM_ARG, 0, NULL, IGNORED_PTR_ARG, IGNORED_PTR_ARG)); /*this is asking "how big is the decoded private key? (from binary)*/ STRICT_EXPECTED_CALL(CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); /*create a certificate context from an encoded certificate*/ STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); STRICT_EXPECTED_CALL(NCryptOpenStorageProvider(IGNORED_PTR_ARG, MS_KEY_STORAGE_PROVIDER, 0)) .IgnoreArgument_pszProviderName(); STRICT_EXPECTED_CALL(NCryptImportKey((NCRYPT_PROV_HANDLE)IGNORED_PTR_ARG, (NCRYPT_KEY_HANDLE)IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_NUM_ARG, NCRYPT_OVERWRITE_KEY_FLAG)) .IgnoreArgument_hProvider() .IgnoreArgument_hImportKey(); STRICT_EXPECTED_CALL(NCryptFreeObject((HCRYPTKEY)IGNORED_PTR_ARG)) .IgnoreArgument_hObject(); STRICT_EXPECTED_CALL(NCryptFreeObject((HCRYPTKEY)IGNORED_PTR_ARG)) .IgnoreArgument_hObject(); STRICT_EXPECTED_CALL(CertSetCertificateContextProperty(IGNORED_PTR_ARG, CERT_KEY_PROV_INFO_PROP_ID, 0, IGNORED_PTR_ARG)); /*give the private key*/ STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); }
NCRYPT_KEY_HANDLE QCNG::Private::key() const { NCRYPT_PROV_HANDLE prov = 0; NCryptOpenStorageProvider( &prov, LPCWSTR(selected.provider.utf16()), 0 ); NCRYPT_KEY_HANDLE key = 0; NCryptOpenKey( prov, &key, LPWSTR(selected.key.utf16()), selected.spec, 0 ); NCryptFreeObject( prov ); return key; }
BOOL isCardInReader(PCCERT_CONTEXT certContext) { #ifndef WIN_XP DWORD flags = CRYPT_ACQUIRE_CACHE_FLAG|CRYPT_ACQUIRE_COMPARE_KEY_FLAG|CRYPT_ACQUIRE_SILENT_FLAG; NCRYPT_KEY_HANDLE key = 0; DWORD spec = 0; BOOL ncrypt = FALSE; CryptAcquireCertificatePrivateKey(certContext, flags, 0, &key, &spec, &ncrypt); if(!key) { return FALSE; } if(ncrypt) { NCryptFreeObject(key); } #endif return TRUE; }
QByteArray QCNG::decrypt( const QByteArray &data ) { d->err = PinUnknown; DWORD size = 256; QByteArray res(int(size), 0); NCRYPT_KEY_HANDLE k = d->key(); SECURITY_STATUS err = NCryptDecrypt(k, PBYTE(data.constData()), DWORD(data.size()), nullptr, PBYTE(res.data()), DWORD(res.size()), &size, NCRYPT_PAD_PKCS1_FLAG); NCryptFreeObject( k ); switch( err ) { case ERROR_SUCCESS: d->err = PinOK; res.resize(int(size)); return res; case SCARD_W_CANCELLED_BY_USER: d->err = PinCanceled; break; default: break; } return QByteArray(); }
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 }
void CEstEIDIEPluginBHO::signWithCNG(BSTR id, BSTR hash, BSTR *signature) { LOG_LOCATION; #ifdef WIN_XP EstEID_log("WARNING: CNG is not supported for windows XP"); #else int methodResult = true; #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) SECURITY_STATUS secStatus = ERROR_SUCCESS; NCRYPT_KEY_HANDLE hKey = NULL; DWORD cbSignature = 0; NTSTATUS status = ((NTSTATUS)0xC0000001L); PBYTE pbSignature = NULL; PCCERT_CONTEXT certContext = NULL; HCERTSTORE cert_store; BOOL must_release_provider; int hashHexLength = _bstr_t(hash).length()/2; BCRYPT_PKCS1_PADDING_INFO padInfo; padInfo.pszAlgId = 0; switch(hashHexLength) { case BINARY_SHA1_LENGTH: padInfo.pszAlgId = NCRYPT_SHA1_ALGORITHM;break; case BINARY_SHA224_LENGTH: padInfo.pszAlgId = L"SHA224"; break; case BINARY_SHA256_LENGTH : padInfo.pszAlgId = NCRYPT_SHA256_ALGORITHM; break; case BINARY_SHA512_LENGTH: padInfo.pszAlgId = NCRYPT_SHA512_ALGORITHM; break; default: break; } try { if(!id || !strlen(CW2A(id))) { throw CryptoException(ESTEID_CERT_NOT_FOUND_ERROR); } EstEID_log("signing started, selected certificate id = %s", CW2A(id)); if(padInfo.pszAlgId == 0) { throw CryptoException(ESTEID_INVALID_HASH_ERROR); } cert_store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG, L"MY"); if(!cert_store) throw CryptoException(); while(certContext = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, certContext)) { if(certificateMatchesId(certContext, id)) { if (!CryptAcquireCertificatePrivateKey(certContext, CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG|CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hKey, NULL, &must_release_provider)) { throw CryptoException(ESTEID_CRYPTO_API_ERROR); } BYTE hashBytes[65]; CryptStringToBinary(hash, hashHexLength*2, CRYPT_STRING_HEX, hashBytes, (DWORD*)&hashHexLength, 0, 0); EstEID_log("Number of bytes stored in hashBytes buffer = %u", hashHexLength); EstEID_log("signing with %s", CW2A(padInfo.pszAlgId)); if(FAILED(secStatus = NCryptSignHash(hKey, &padInfo, (PBYTE)hashBytes, hashHexLength, NULL, 0, &cbSignature, 0))) { throw CryptoException(secStatus); } pbSignature = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbSignature); if(NULL == pbSignature){ throw CryptoException(ESTEID_CRYPTO_API_ERROR); } if(FAILED(secStatus = NCryptSignHash(hKey, &padInfo, (PBYTE)hashBytes, hashHexLength, pbSignature, cbSignature, &cbSignature, BCRYPT_PAD_PKCS1))) { throw CryptoException(secStatus); } std::stringstream ss; for (DWORD i = 0; i < cbSignature; i++) { ss << std::hex << std::setfill('0') << std::setw(2) << (short)pbSignature[i]; } *signature = _bstr_t(ss.str().c_str()).Detach(); } } } catch(CryptoException e) { *signature = _bstr_t("").Detach(); if(pbSignature) HeapFree(GetProcessHeap(), 0, pbSignature); if(hKey) NCryptFreeObject(hKey); if(certContext) CertFreeCertificateContext(certContext); if(must_release_provider && cert_store) CertCloseStore(cert_store, 0); throw CryptoException(e.windowsErrorCode); } CertFreeCertificateContext(certContext); if(must_release_provider) CertCloseStore(cert_store, 0); #endif }
QList<TokenData> QCNG::tokens() const { qWarning() << "Start enumerationg providers"; QHash<SslCertificate,QCNGCache> cache; DWORD count = 0; NCryptProviderName *names = nullptr; NCryptEnumStorageProviders( &count, &names, NCRYPT_SILENT_FLAG ); for( DWORD i = 0; i < count; ++i ) { qWarning() << "Found provider" << QString::fromWCharArray(names[i].pszName); if( wcscmp( names[i].pszName, MS_SMART_CARD_KEY_STORAGE_PROVIDER ) == 0 ) { for( const QString &reader: QPCSC::instance().readers() ) { qWarning() << reader; QString scope = QString(R"(\\.\%1\)").arg(reader); d->enumKeys( cache, names[i].pszName, LPCWSTR(scope.utf16()) ); } } else d->enumKeys( cache, names[i].pszName ); } NCryptFreeBuffer( names ); d->cache = cache; qWarning() << "End enumerationg providers"; QList<TokenData> result; for(QHash<SslCertificate,QCNGCache>::const_iterator i = cache.constBegin(); i != cache.constEnd(); ++i) { TokenData t; t.setCard(i.key().type() & SslCertificate::EstEidType || i.key().type() & SslCertificate::DigiIDType ? i.value().guid : i.key().subjectInfo(QSslCertificate::CommonName)); t.setCert(i.key()); result << t; } return result; } TokenData QCNG::selectCert( const SslCertificate &cert ) { qWarning() << "Select:" << cert.subjectInfo( "CN" ); if( !d->cache.contains( cert ) ) return TokenData(); d->selected = d->cache[cert]; qWarning() << "Found:" << d->selected.guid << d->selected.key; TokenData t; t.setCard( cert.type() & SslCertificate::EstEidType || cert.type() & SslCertificate::DigiIDType ? d->selected.guid : cert.subjectInfo( QSslCertificate::CommonName ) ); t.setCert( cert ); return t; } QByteArray QCNG::sign( int method, const QByteArray &digest ) const { d->err = PinUnknown; BCRYPT_PKCS1_PADDING_INFO padInfo = { NCRYPT_SHA256_ALGORITHM }; switch( method ) { case NID_sha224: padInfo.pszAlgId = L"SHA224"; break; case NID_sha256: padInfo.pszAlgId = NCRYPT_SHA256_ALGORITHM; break; case NID_sha384: padInfo.pszAlgId = NCRYPT_SHA384_ALGORITHM; break; case NID_sha512: padInfo.pszAlgId = NCRYPT_SHA512_ALGORITHM; break; case NID_md5_sha1: //padInfo.pszAlgId = L"SHAMD5"; break; default: break; } DWORD size = 0; QByteArray res; NCRYPT_KEY_HANDLE k = d->key(); QString algo(5, 0); SECURITY_STATUS err = NCryptGetProperty(k, NCRYPT_ALGORITHM_GROUP_PROPERTY, PBYTE(algo.data()), DWORD((algo.size() + 1) * 2), &size, 0); algo.resize(size/2 - 1); bool isRSA = algo == "RSA"; err = NCryptSignHash(k, isRSA ? &padInfo : nullptr, PBYTE(digest.constData()), DWORD(digest.size()), nullptr, 0, &size, isRSA ? BCRYPT_PAD_PKCS1 : 0); if(FAILED(err)) return res; res.resize(int(size)); err = NCryptSignHash(k, isRSA ? &padInfo : nullptr, PBYTE(digest.constData()), DWORD(digest.size()), PBYTE(res.data()), DWORD(res.size()), &size, isRSA ? BCRYPT_PAD_PKCS1 : 0); NCryptFreeObject( k ); switch( err ) { case ERROR_SUCCESS: d->err = PinOK; return res; case SCARD_W_CANCELLED_BY_USER: d->err = PinCanceled; break; default: res.clear(); break; } return res; }