예제 #1
0
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

}
예제 #2
0
파일: QCNG.cpp 프로젝트: open-eid/qdigidoc
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;
}