/* * Copyright 2003-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * XSEC * * XSECAlgorithmHandlerDefault := Interface class to define handling of * default encryption algorithms * * $Id: DSIGAlgorithmHandlerDefault.cpp 450745 2006-09-28 07:52:38Z blautenb $ * */ // XSEC Includes #include #include #include #include #include #include #include #include #include "DSIGAlgorithmHandlerDefault.hpp" #include #include XERCES_CPP_NAMESPACE_USE // -------------------------------------------------------------------------------- // Some useful utility functions // -------------------------------------------------------------------------------- bool compareBase64StringToRaw(const char * b64Str, unsigned char * raw, unsigned int rawLen, unsigned int maxCompare = 0) { // Decode a base64 buffer and then compare the result to a raw buffer // Compare at most maxCompare bits (if maxComare > 0) // Note - whilst the other parameters are bytes, maxCompare is bits unsigned char outputStr[1024]; unsigned int outputLen = 0; XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64(); if (!b64) { throw XSECException(XSECException::CryptoProviderError, "Error requesting Base64 object from Crypto Provider"); } Janitor j_b64(b64); b64->decodeInit(); outputLen = b64->decode((unsigned char *) b64Str, (unsigned int) strlen((char *) b64Str), outputStr, 1024); outputLen += b64->decodeFinish(&outputStr[outputLen], 1024 - outputLen); // Compare div_t d; d.rem = 0; d.quot = 0; unsigned int maxCompareBytes, maxCompareBits; maxCompareBits = 0; unsigned int size; if (maxCompare > 0) { d = div(maxCompare, 8); maxCompareBytes = d.quot; if (d.rem != 0) maxCompareBytes++; if (rawLen < maxCompareBytes && outputLen < maxCompareBytes) { if (rawLen != outputLen) return false; size = rawLen; } else if (rawLen < maxCompareBytes || outputLen < maxCompareBytes) { return false; } else size = maxCompareBytes; } else { if (rawLen != outputLen) return false; size = rawLen; } // Compare bytes unsigned int i, j; for (i = 0; i < size; ++ i) { if (raw[i] != outputStr[i]) return false; } // Compare bits char mask = 0x01; if (maxCompare != 0) { for (j = 0 ; j < (unsigned int) d.rem; ++i) { if ((raw[i] & mask) != (outputStr[i] & mask)) return false; mask = mask << 1; } } return true; } void convertRawToBase64String(safeBuffer &b64SB, unsigned char * raw, unsigned int rawLen, unsigned int maxBits = 0) { // Translate the rawbuffer (at most maxBits or rawLen - whichever is smaller) // to a base64 string unsigned char b64Str[1024]; unsigned int outputLen = 0; XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64(); if (!b64) { throw XSECException(XSECException::CryptoProviderError, "Error requesting Base64 object from Crypto Provider"); } Janitor j_b64(b64); // Determine length to translate unsigned int size; if (maxBits > 0) { div_t d = div(maxBits, 8); size = d.quot; if (d.rem != 0) ++size; if (size > rawLen) size = rawLen; } else size = rawLen; b64->encodeInit(); outputLen = b64->encode((unsigned char *) raw, rawLen, b64Str, 1024); outputLen += b64->encodeFinish(&b64Str[outputLen], 1024 - outputLen); b64Str[outputLen] = '\0'; // Copy out b64SB.sbStrcpyIn((char *) b64Str); } // -------------------------------------------------------------------------------- // Clone // -------------------------------------------------------------------------------- XSECAlgorithmHandler * DSIGAlgorithmHandlerDefault::clone(void) const { DSIGAlgorithmHandlerDefault * ret; XSECnew(ret, DSIGAlgorithmHandlerDefault); return ret; } // -------------------------------------------------------------------------------- // Add a hash txfm // -------------------------------------------------------------------------------- TXFMBase * addHashTxfm(signatureMethod sm, hashMethod hm, XSECCryptoKey * key, DOMDocument * doc) { // Given a hash method and signature method, create an appropriate TXFM TXFMBase * txfm; switch (hm) { case HASH_MD5 : if (sm == SIGNATURE_HMAC){ if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault::addHashTxfm - non HMAC key passed in to HMAC signature"); } XSECnew(txfm, TXFMMD5(doc, key)); } else { XSECnew(txfm, TXFMMD5(doc)); } break; case HASH_SHA1 : if (sm == SIGNATURE_HMAC){ if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault::addHashTxfm - non HMAC key passed in to HMAC signature"); } XSECnew(txfm, TXFMSHA1(doc, HASH_SHA1, key)); } else { XSECnew(txfm, TXFMSHA1(doc)); } break; case HASH_SHA224 : if (sm == SIGNATURE_HMAC){ if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault::addHashTxfm - non HMAC key passed in to HMAC signature"); } XSECnew(txfm, TXFMSHA1(doc, HASH_SHA224, key)); } else { XSECnew(txfm, TXFMSHA1(doc, HASH_SHA224)); } break; case HASH_SHA256 : if (sm == SIGNATURE_HMAC){ if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault::addHashTxfm - non HMAC key passed in to HMAC signature"); } XSECnew(txfm, TXFMSHA1(doc, HASH_SHA256, key)); } else { XSECnew(txfm, TXFMSHA1(doc, HASH_SHA256)); } break; case HASH_SHA384 : if (sm == SIGNATURE_HMAC){ if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault::addHashTxfm - non HMAC key passed in to HMAC signature"); } XSECnew(txfm, TXFMSHA1(doc, HASH_SHA384, key)); } else { XSECnew(txfm, TXFMSHA1(doc, HASH_SHA384)); } break; case HASH_SHA512 : if (sm == SIGNATURE_HMAC){ if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault::addHashTxfm - non HMAC key passed in to HMAC signature"); } XSECnew(txfm, TXFMSHA1(doc, HASH_SHA512, key)); } else { XSECnew(txfm, TXFMSHA1(doc, HASH_SHA512)); } break; default : throw XSECException(XSECException::AlgorithmMapperError, "Hash method unknown in DSIGAlgorithmHandlerDefault::addHashTxfm"); } return txfm; } // -------------------------------------------------------------------------------- // Map a Signature hash // -------------------------------------------------------------------------------- bool DSIGAlgorithmHandlerDefault::appendSignatureHashTxfm(TXFMChain * inputBytes, const XMLCh * URI, XSECCryptoKey * key) { signatureMethod sm; hashMethod hm; // Map to internal constants if (!XSECmapURIToSignatureMethods(URI, sm, hm)) { safeBuffer sb; sb.sbTranscodeIn("DSIGAlgorithmHandlerDefault - Unknown URI : "); sb.sbXMLChCat(URI); throw XSECException(XSECException::AlgorithmMapperError, sb.rawXMLChBuffer()); } // Now append the appropriate hash transform onto the end of the chain // If this is an HMAC of some kind - this function will add the appropriate key TXFMBase * htxfm = addHashTxfm(sm, hm, key, inputBytes->getLastTxfm()->getDocument()); inputBytes->appendTxfm(htxfm); return true; } // -------------------------------------------------------------------------------- // Sign // -------------------------------------------------------------------------------- unsigned int DSIGAlgorithmHandlerDefault::signToSafeBuffer( TXFMChain * inputBytes, const XMLCh * URI, XSECCryptoKey * key, unsigned int outputLength, safeBuffer & result) { signatureMethod sm; hashMethod hm; // Map to internal constants if (!XSECmapURIToSignatureMethods(URI, sm, hm)) { safeBuffer sb; sb.sbTranscodeIn("DSIGAlgorithmHandlerDefault - Unknown URI : "); sb.sbXMLChCat(URI); throw XSECException(XSECException::AlgorithmMapperError, sb.rawXMLChBuffer()); } // Now append the appropriate hash transform onto the end of the chain // If this is an HMAC of some kind - this function will add the appropriate key TXFMBase * htxfm = addHashTxfm(sm, hm, key, inputBytes->getLastTxfm()->getDocument()); inputBytes->appendTxfm(htxfm); unsigned char hash[4096]; int hashLen = inputBytes->getLastTxfm()->readBytes((XMLByte *) hash, 4096); // Now check the calculated hash char b64Buf[1024]; unsigned int b64Len; safeBuffer b64SB; switch (key->getKeyType()) { case (XSECCryptoKey::KEY_DSA_PRIVATE) : case (XSECCryptoKey::KEY_DSA_PAIR) : if (sm != SIGNATURE_DSA) { throw XSECException(XSECException::AlgorithmMapperError, "Key type does not match signature type"); } b64Len = ((XSECCryptoKeyDSA *) key)->signBase64Signature( hash, hashLen, (char *) b64Buf, 1024); if (b64Len <= 0) { throw XSECException(XSECException::AlgorithmMapperError, "Unknown error occured during a DSA Signing operation"); } if (b64Buf[b64Len-1] == '\n') b64Buf[b64Len-1] = '\0'; else b64Buf[b64Len] = '\0'; break; case (XSECCryptoKey::KEY_RSA_PRIVATE) : case (XSECCryptoKey::KEY_RSA_PAIR) : if (sm != SIGNATURE_RSA) { throw XSECException(XSECException::AlgorithmMapperError, "Key type does not match signature type"); } b64Len = ((XSECCryptoKeyRSA *) key)->signSHA1PKCS1Base64Signature( hash, hashLen, (char *) b64Buf, 1024, hm); if (b64Len <= 0) { throw XSECException(XSECException::AlgorithmMapperError, "Unknown error occured during a RSA Signing operation"); } // Clean up some "funnies" and make sure the string is NULL terminated if (b64Buf[b64Len-1] == '\n') b64Buf[b64Len-1] = '\0'; else b64Buf[b64Len] = '\0'; break; case (XSECCryptoKey::KEY_HMAC) : if (sm != SIGNATURE_HMAC) { throw XSECException(XSECException::AlgorithmMapperError, "Key type does not match signature type"); } // Signature already created, so just translate to base 64 and enter string convertRawToBase64String(b64SB, hash, hashLen, outputLength); strncpy(b64Buf, (char *) b64SB.rawBuffer(), 1024); break; default : throw XSECException(XSECException::AlgorithmMapperError, "Key found, but don't know how to sign the document using it"); } result = b64Buf; return (unsigned int) strlen(b64Buf); } // -------------------------------------------------------------------------------- // Verify // -------------------------------------------------------------------------------- bool DSIGAlgorithmHandlerDefault::verifyBase64Signature( TXFMChain * inputBytes, const XMLCh * URI, const char * sig, unsigned int outputLength, XSECCryptoKey * key) { signatureMethod sm; hashMethod hm; // Map to internal constants if (!XSECmapURIToSignatureMethods(URI, sm, hm)) { safeBuffer sb; sb.sbTranscodeIn("DSIGAlgorithmHandlerDefault - Unknown URI : "); sb.sbXMLChCat(URI); throw XSECException(XSECException::AlgorithmMapperError, sb.rawXMLChBuffer()); } // Now append the appropriate hash transform onto the end of the chain // If this is an HMAC of some kind - this function will add the appropriate key TXFMBase * htxfm = addHashTxfm(sm, hm, key, inputBytes->getLastTxfm()->getDocument()); inputBytes->appendTxfm(htxfm); unsigned char hash[4096]; int hashLen = inputBytes->getLastTxfm()->readBytes((XMLByte *) hash, 4096); // Now check the calculated hash bool sigVfyRet = false; switch (key->getKeyType()) { case (XSECCryptoKey::KEY_DSA_PUBLIC) : case (XSECCryptoKey::KEY_DSA_PAIR) : if (sm != SIGNATURE_DSA) { throw XSECException(XSECException::AlgorithmMapperError, "Key type does not match signature type"); } sigVfyRet = ((XSECCryptoKeyDSA *) key)->verifyBase64Signature( hash, hashLen, (char *) sig, (unsigned int) strlen(sig)); break; case (XSECCryptoKey::KEY_RSA_PUBLIC) : case (XSECCryptoKey::KEY_RSA_PAIR) : if (sm != SIGNATURE_RSA) { throw XSECException(XSECException::AlgorithmMapperError, "Key type does not match signature type"); } sigVfyRet = ((XSECCryptoKeyRSA *) key)->verifySHA1PKCS1Base64Signature( hash, hashLen, sig, (unsigned int) strlen(sig), hm); break; case (XSECCryptoKey::KEY_HMAC) : // Already done - just compare calculated value with read value sigVfyRet = compareBase64StringToRaw(sig, hash, hashLen, outputLength); break; default : throw XSECException(XSECException::AlgorithmMapperError, "Key found, but don't know how to check the signature using it"); } return sigVfyRet; } // -------------------------------------------------------------------------------- // Hash TXFM appenders // -------------------------------------------------------------------------------- bool DSIGAlgorithmHandlerDefault::appendHashTxfm( TXFMChain * inputBytes, const XMLCh * URI) { hashMethod hm; // Is this a URI we recognise? if (!XSECmapURIToHashMethod(URI, hm)) { safeBuffer sb; sb.sbTranscodeIn("DSIGAlgorithmHandlerDefault - Unknown Hash URI : "); sb.sbXMLChCat(URI); throw XSECException(XSECException::AlgorithmMapperError, sb.rawXMLChBuffer()); } TXFMBase * txfm; DOMDocument *d = inputBytes->getLastTxfm()->getDocument(); switch (hm) { case HASH_SHA1 : case HASH_SHA224 : case HASH_SHA256 : case HASH_SHA384 : case HASH_SHA512 : XSECnew(txfm, TXFMSHA1(d, hm)); break; case HASH_MD5 : XSECnew(txfm, TXFMMD5(d)); break; default : safeBuffer sb; sb.sbTranscodeIn("DSIGAlgorithmHandlerDefault - Internal error unknown Hash, but URI known. URI : "); sb.sbXMLChCat(URI); throw XSECException(XSECException::AlgorithmMapperError, sb.rawXMLChBuffer()); } inputBytes->appendTxfm(txfm); return true; } // -------------------------------------------------------------------------------- // SafeBuffer decryption // -------------------------------------------------------------------------------- unsigned int DSIGAlgorithmHandlerDefault::decryptToSafeBuffer( TXFMChain * cipherText, XENCEncryptionMethod * encryptionMethod, XSECCryptoKey * key, DOMDocument * doc, safeBuffer & result ) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault - Encryption operations not supported"); } bool DSIGAlgorithmHandlerDefault::appendDecryptCipherTXFM( TXFMChain * cipherText, XENCEncryptionMethod * encryptionMethod, XSECCryptoKey * key, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * doc ) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault - Encryption operations not supported"); } // -------------------------------------------------------------------------------- // SafeBuffer encryption // -------------------------------------------------------------------------------- bool DSIGAlgorithmHandlerDefault::encryptToSafeBuffer( TXFMChain * plainText, XENCEncryptionMethod * encryptionMethod, XSECCryptoKey * key, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * doc, safeBuffer & result ) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault - Encryption operations not supported"); } // -------------------------------------------------------------------------------- // Key Creation // -------------------------------------------------------------------------------- XSECCryptoKey * DSIGAlgorithmHandlerDefault::createKeyForURI( const XMLCh * uri, const unsigned char * keyBuffer, unsigned int keyLen ) { throw XSECException(XSECException::AlgorithmMapperError, "DSIGAlgorithmHandlerDefault - Key creation operations not supported"); }