bool WinCAPICryptoKeyDSA::verifyBase64Signature()

in xsec/enc/WinCAPI/WinCAPICryptoKeyDSA.cpp [291:418]


bool WinCAPICryptoKeyDSA::verifyBase64Signature(unsigned char * hashBuf, 
								 unsigned int hashLen,
								 char * base64Signature,
								 unsigned int sigLen) const {

	// Use the currently loaded key to validate the Base64 encoded signature

	if (m_key == 0) {

		// Try to import from the parameters
		importKey();

		if (m_key == 0) {
			throw XSECCryptoException(XSECCryptoException::DSAError,
				"WinCAPI:DSA - Attempt to validate signature with empty key");
		}
	}

	// Decode the signature
	unsigned char * rawSig;
	DWORD rawSigLen;
	XSECnew(rawSig, BYTE [sigLen]);
	ArrayJanitor<BYTE> j_rawSig(rawSig);

	// Decode the signature
	XSCryptCryptoBase64 b64;

	b64.decodeInit();
	rawSigLen = b64.decode((unsigned char *) base64Signature, sigLen, rawSig, sigLen);
	rawSigLen += b64.decodeFinish(&rawSig[rawSigLen], sigLen - rawSigLen);

	// Reverse the sig - Windows stores integers as octet streams in little endian
	// order.  The I2OSP algorithm used by XMLDSig to store integers is big endian

	BYTE rawSigFinal[40];
	BYTE * j, *k, *l, *m;

	unsigned char rb[20];
	unsigned char sb[20];

	if (rawSigLen == 40) {

		j = rawSig;
		k = rawSig + 20;

	} else if (rawSigLen == 46 && ASN2DSASig(rawSig, rb, sb) == true) {

		j = rb;
		k = sb;

	} else {

		throw XSECCryptoException(XSECCryptoException::DSAError,
			"WinCAPI:DSA::VerifyBase64Signature - Expect 40 bytes in a DSA signature");
	}

	l = rawSigFinal + 19;
	m = rawSigFinal + 39;
	
	while (l >= rawSigFinal) {
		*l-- = *j++;
		*m-- = *k++;
	}
	
	// Have to create a Windows hash object and feed in the hash
	BOOL fResult;
	HCRYPTHASH h;
	fResult = CryptCreateHash(m_p, 
					CALG_SHA1, 
					0, 
					0,
					&h);

	if (!fResult) {
		throw XSECCryptoException(XSECCryptoException::DSAError,
			"WinCAPI:DSA - Error creating Windows Hash Object");
	}

	// Feed the hash value into the newly created hash object
	fResult = CryptSetHashParam(
					h, 
					HP_HASHVAL, 
					hashBuf, 
					0);

	if (!fResult) {
		if (h)
			CryptDestroyHash(h);
		throw XSECCryptoException(XSECCryptoException::DSAError,
			"WinCAPI:DSA - Error Setting Hash Value in Windows Hash object");
	}

	// Now validate
	fResult = CryptVerifySignature(
				h,
				rawSigFinal,
				40,
				m_key,
				NULL,
				0);

	if (!fResult) {

		DWORD error = GetLastError();

		/* For some reason, the default Microsoft DSS provider generally returns
		 * NTE_FAIL (which denotes an internal failure in the provider) for a 
		 * failed signature rather than NTE_BAD_SIGNATURE
		 */

		if (error != NTE_BAD_SIGNATURE && error != NTE_FAIL) {
			if (h)
				CryptDestroyHash(h);
			throw XSECCryptoException(XSECCryptoException::DSAError,
			"WinCAPI:DSA - Error occurred in DSA validation");
		}

		if (h)
			CryptDestroyHash(h);
		return false;
	}

	if (h)
		CryptDestroyHash(h);

	return true;

}