xsec/enc/WinCAPI/WinCAPICryptoProvider.cpp (240 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 * * WinCAPICryptoProvider := Provider to support Windows Crypto API * * Author(s): Berin Lautenbach * * $Id$ * */ #include <xsec/framework/XSECError.hpp> #include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp> #include <xsec/enc/WinCAPI/WinCAPICryptoX509.hpp> #include <xsec/enc/WinCAPI/WinCAPICryptoKeyDSA.hpp> #include <xsec/enc/WinCAPI/WinCAPICryptoKeyHMAC.hpp> #include <xsec/enc/WinCAPI/WinCAPICryptoKeyRSA.hpp> #include <xsec/enc/WinCAPI/WinCAPICryptoHash.hpp> #include <xsec/enc/WinCAPI/WinCAPICryptoHashHMAC.hpp> #include <xsec/enc/WinCAPI/WinCAPICryptoSymmetricKey.hpp> #include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp> #include <xsec/enc/XSECCryptoException.hpp> #if defined (XSEC_HAVE_WINCAPI) #include <xercesc/util/Janitor.hpp> XSEC_USING_XERCES(ArrayJanitor); static char s_xsecKeyStoreName[] = "ApacheXML-SecurityKeyStore"; WinCAPICryptoProvider::WinCAPICryptoProvider( LPCSTR provDSSName, LPCSTR provRSAName, DWORD dwFlags) { if (!CryptAcquireContext(&m_provDSS, NULL, provDSSName, PROV_DSS, CRYPT_VERIFYCONTEXT)) { throw XSECException(XSECException::InternalError, "WinCAPICryptoProvider() - Error obtaining default PROV_DSS"); } if (!CryptAcquireContext(&m_provRSA, NULL, provRSAName, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { // Check if we maybe don't understand AES DWORD error = GetLastError(); if (error == NTE_PROV_TYPE_NOT_DEF || error == 0) { // This system does not have AES! m_haveAES = false; m_provRSAType = PROV_RSA_FULL; if (!CryptAcquireContext(&m_provRSA, NULL, provRSAName, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { throw XSECException(XSECException::InternalError, "WinCAPICryptoProvider() - Error obtaining default PROV_RSA_FULL"); } } else { throw XSECException(XSECException::InternalError, "WinCAPICryptoProvider() - Error obtaining default PROV_RSA_AES"); } } else { m_haveAES = true; m_provRSAType = PROV_RSA_AES; } // Now obtain our internal (library) key store if (!CryptAcquireContext(&m_provApacheKeyStore, s_xsecKeyStoreName, provRSAName, m_provRSAType, dwFlags)) { CryptAcquireContext(&m_provApacheKeyStore, s_xsecKeyStoreName, provRSAName, m_provRSAType, CRYPT_DELETEKEYSET); // Try to create if (!CryptAcquireContext(&m_provApacheKeyStore, s_xsecKeyStoreName, provRSAName, m_provRSAType, dwFlags | CRYPT_NEWKEYSET)) { // Prevents failure on mandatory profiles, see SANTUARIO-378. if (GetLastError() != NTE_TEMPORARY_PROFILE) { throw XSECException(XSECException::InternalError, "WinCAPICryptoProvider() - Error obtaining generating internal key store for PROV_RSA_FULL"); } else { m_provApacheKeyStore = NULL; } } else { HCRYPTKEY k; if (!CryptGenKey(m_provApacheKeyStore, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &k)) { throw XSECException(XSECException::InternalError, "WinCAPICryptoProvider() - Error generating internal key set for PROV_RSA_FULL"); } CryptDestroyKey(k); } } // Copy parameters for later use if (provDSSName != NULL) m_provDSSName = strdup(provDSSName); else m_provDSSName = NULL; if (provRSAName != NULL) m_provRSAName = strdup(provRSAName); else m_provRSAName = NULL; } WinCAPICryptoProvider::~WinCAPICryptoProvider() { CryptReleaseContext(m_provRSA, 0); CryptReleaseContext(m_provDSS, 0); if (m_provApacheKeyStore) { CryptReleaseContext(m_provApacheKeyStore, 0); } } const XMLCh* WinCAPICryptoProvider::getProviderName() const { return DSIGConstants::s_unicodeStrPROVWinCAPI; } // Hashing classes unsigned int WinCAPICryptoProvider::getMaxHashSize() const { return WINCAPI_MAX_HASH_SIZE; } XSECCryptoHash* WinCAPICryptoProvider::hash(XSECCryptoHash::HashType type) const { WinCAPICryptoHash* ret = NULL; switch(type) { case XSECCryptoHash::HASH_SHA1: case XSECCryptoHash::HASH_MD5: XSECnew(ret, WinCAPICryptoHash(m_provDSS, type)); break; } return ret; } XSECCryptoHash* WinCAPICryptoProvider::HMAC(XSECCryptoHash::HashType type) const { WinCAPICryptoHashHMAC* ret = NULL; switch(type) { case XSECCryptoHash::HASH_SHA1: case XSECCryptoHash::HASH_MD5: XSECnew(ret, WinCAPICryptoHashHMAC(m_provDSS, type)); break; } return ret; } XSECCryptoKeyHMAC* WinCAPICryptoProvider::keyHMAC(void) const { WinCAPICryptoKeyHMAC * ret; XSECnew(ret, WinCAPICryptoKeyHMAC(m_provDSS)); return ret; } XSECCryptoKeyDSA* WinCAPICryptoProvider::keyDSA() const { WinCAPICryptoKeyDSA * ret; XSECnew(ret, WinCAPICryptoKeyDSA(m_provDSS)); return ret; } XSECCryptoKeyRSA* WinCAPICryptoProvider::keyRSA() const { WinCAPICryptoKeyRSA * ret; XSECnew(ret, WinCAPICryptoKeyRSA(m_provRSA)); return ret; } XSECCryptoKeyEC* WinCAPICryptoProvider::keyEC() const { throw XSECCryptoException(XSECCryptoException::UnsupportedError, "WinCAPICryptoProvider::keyEC - EC support not available"); } XSECCryptoKey* WinCAPICryptoProvider::keyDER(const char* buf, unsigned long len, bool base64) const { throw XSECCryptoException(XSECCryptoException::UnsupportedError, "WinCAPICryptoProvider::keyDER - DER decoding support not available"); } XSECCryptoX509* WinCAPICryptoProvider::X509() const { WinCAPICryptoX509 * ret; XSECnew(ret, WinCAPICryptoX509(m_provRSA, m_provDSS)); return ret; } XSECCryptoBase64* WinCAPICryptoProvider::base64() const { // The Windows CAPI does not provide a Base64 decoder/encoder. // Use the internal implementation. XSCryptCryptoBase64 * ret; XSECnew(ret, XSCryptCryptoBase64()); return ret; } bool WinCAPICryptoProvider::algorithmSupported(XSECCryptoSymmetricKey::SymmetricKeyType alg) const { switch (alg) { case (XSECCryptoSymmetricKey::KEY_AES_128) : case (XSECCryptoSymmetricKey::KEY_AES_192) : case (XSECCryptoSymmetricKey::KEY_AES_256) : return m_haveAES; case (XSECCryptoSymmetricKey::KEY_3DES_192) : return true; default: return false; } return false; } bool WinCAPICryptoProvider::algorithmSupported(XSECCryptoHash::HashType alg) const { switch (alg) { case (XSECCryptoHash::HASH_SHA1) : case (XSECCryptoHash::HASH_MD5) : return true; case (XSECCryptoHash::HASH_SHA224) : case (XSECCryptoHash::HASH_SHA256) : case (XSECCryptoHash::HASH_SHA384) : case (XSECCryptoHash::HASH_SHA512) : return false; default: return false; } return false; } XSECCryptoSymmetricKey* WinCAPICryptoProvider::keySymmetric(XSECCryptoSymmetricKey::SymmetricKeyType alg) const { // Only temporary WinCAPICryptoSymmetricKey * ret; XSECnew(ret, WinCAPICryptoSymmetricKey(m_provApacheKeyStore, alg)); return ret; } unsigned int WinCAPICryptoProvider::getRandom(unsigned char* buffer, unsigned int numOctets) const { if (!CryptGenRandom(m_provApacheKeyStore, numOctets, buffer)) { throw XSECException(XSECException::InternalError, "WinCAPICryptoProvider() - Error generating Random data"); } return numOctets; } // -------------------------------------------------------------------------------- // Translate a Base64 number to a Windows (little endian) integer // -------------------------------------------------------------------------------- BYTE* WinCAPICryptoProvider::b642WinBN(const char* b64, unsigned int b64Len, unsigned int& retLen) { BYTE * os; XSECnew(os, BYTE[b64Len]); ArrayJanitor<BYTE> j_os(os); // Decode XSCryptCryptoBase64 b; b.decodeInit(); retLen = b.decode((unsigned char *) b64, b64Len, os, b64Len); retLen += b.decodeFinish(&os[retLen], b64Len - retLen); BYTE * ret; XSECnew(ret, BYTE[retLen]); BYTE * j = os; BYTE * k = ret + retLen - 1; for (unsigned int i = 0; i < retLen ; ++i) *k-- = *j++; return ret; } // -------------------------------------------------------------------------------- // Translate a Windows integer to a Base64 I2OSP number // -------------------------------------------------------------------------------- unsigned char * WinCAPICryptoProvider::WinBN2b64(BYTE * n, DWORD nLen, unsigned int &retLen) { // First reverse BYTE * rev;; XSECnew(rev, BYTE[nLen]); ArrayJanitor<BYTE> j_rev(rev); BYTE * j = n; BYTE * k = rev + nLen - 1; for (unsigned int i = 0; i < nLen ; ++i) *k-- = *j++; unsigned char * b64; // Naieve length calculation unsigned int bufLen = nLen * 2 + 4; XSECnew(b64, unsigned char[bufLen]); ArrayJanitor<unsigned char> j_b64(b64); XSCryptCryptoBase64 b; b.encodeInit(); retLen = b.encode(rev, (unsigned int) nLen, b64, bufLen); retLen += b.encodeFinish(&b64[retLen], bufLen - retLen); j_b64.release(); return b64; } #endif /* XSEC_HAVE_WINCAPI */