blautenb 2003/04/11 05:24:06
Added: c/src/enc/WinCAPI WinCAPICryptoKeyRSA.hpp
WinCAPICryptoKeyRSA.cpp
Log:
Full implementation of WinCAPI
Revision Changes Path
1.1 xml-security/c/src/enc/WinCAPI/WinCAPICryptoKeyRSA.hpp
Index: WinCAPICryptoKeyRSA.hpp
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "<WebSig>" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2001, Institute for
* Data Communications Systems, <http://www.nue.et-inf.uni-siegen.de/>.
* The development of this software was partly funded by the European
* Commission in the <WebSig> project in the ISIS Programme.
* For more information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
* XSEC
*
* WinCAPICryptoKeyRSA := Windows implementation of RSA Keys
*
* Author(s): Berin Lautenbach
*
* $Id: WinCAPICryptoKeyRSA.hpp,v 1.1 2003/04/11 12:24:06 blautenb Exp $
*
*/
#ifndef WINCAPICRYPTOKEYRSA_INCLUDE
#define WINCAPICRYPTOKEYRSA_INCLUDE
#include <xsec/enc/XSECCryptoKeyRSA.hpp>
#if !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0400
#endif
#include <wincrypt.h>
class WinCAPICryptoProvider;
class DSIG_EXPORT WinCAPICryptoKeyRSA : public XSECCryptoKeyRSA {
public :
// Constructors/Destructors
WinCAPICryptoKeyRSA(WinCAPICryptoProvider * owner);
/**
* \brief Dedicated WinCAPI constructor
*
* Create a RSA key for use in XSEC from an existing HCRYPTKEY
*
* @param owner The owner provider object (needed to find CSP)
* @param k The key to use
* @param havePrivate The CSP holds the private key as well as public
* @note k is owned by the library. When the wrapper
* WinCAPICryptoKeyRSA is deleted, k will be destroyed using
* CryptDestroyKey()
*/
WinCAPICryptoKeyRSA(WinCAPICryptoProvider * owner, HCRYPTKEY k, bool
havePrivate = false);
virtual ~WinCAPICryptoKeyRSA();
// Generic key functions
virtual XSECCryptoKey::KeyType getKeyType();
virtual const XMLCh * getProviderName() {return
DSIGConstants::s_unicodeStrPROVWinCAPI;}
virtual XSECCryptoKey * clone();
// RSA Specific Functions
virtual void loadPublicModulusBase64BigNums(const char * b64, unsigned
int len);
virtual void loadPublicExponentBase64BigNums(const char * b64, unsigned
int len);
// Signature functions
virtual bool verifySHA1PKCS1Base64Signature(const unsigned char *
hashBuf,
unsigned int
hashLen,
const char *
base64Signature,
unsigned int
sigLen);
virtual unsigned int signSHA1PKCS1Base64Signature(unsigned char *
hashBuf,
unsigned int hashLen,
char * base64SignatureBuf,
unsigned int base64SignatureBufLen);
// "Extra" WinCAPI functions
WinCAPICryptoKeyRSA(HCRYPTKEY k);
// Some useful functions for extracting parameters from a Windows key
unsigned int getExponentBase64BigNums(char * b64, unsigned int len);
unsigned int getModulusBase64BigNums(char * b64, unsigned int len);
private:
HCRYPTKEY m_key;
WinCAPICryptoProvider * mp_ownerProvider;
bool m_havePrivate;
// Do we have the private key?
BYTE * mp_modulus;
BYTE * mp_exponent;
unsigned int m_modulusLen;
unsigned int m_exponentLen;
// Instruct to import from parameters
void importKey(void);
void loadParamsFromKey(void);
};
#endif /* WINCAPICRYPTOKEYRSA_INCLUDE */
1.1 xml-security/c/src/enc/WinCAPI/WinCAPICryptoKeyRSA.cpp
Index: WinCAPICryptoKeyRSA.cpp
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "<WebSig>" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2001, Institute for
* Data Communications Systems, <http://www.nue.et-inf.uni-siegen.de/>.
* The development of this software was partly funded by the European
* Commission in the <WebSig> project in the ISIS Programme.
* For more information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
* XSEC
*
* WinCAPICryptoKeyRSA := RSA Keys
*
* Author(s): Berin Lautenbach
*
* $Id: WinCAPICryptoKeyRSA.cpp,v 1.1 2003/04/11 12:24:06 blautenb Exp $
*
*/
#include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp>
#include <xsec/enc/WinCAPI/WinCAPICryptoKeyRSA.hpp>
#include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
#include <xsec/enc/XSECCryptoException.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xercesc/util/Janitor.hpp>
XSEC_USING_XERCES(ArrayJanitor);
WinCAPICryptoKeyRSA::WinCAPICryptoKeyRSA(WinCAPICryptoProvider * owner) {
// Create a new key to be loaded as we go
m_key = 0;
mp_ownerProvider = owner;
m_havePrivate = false;
mp_exponent = NULL;
m_exponentLen = 0;
mp_modulus = NULL;
m_modulusLen = 0;
};
WinCAPICryptoKeyRSA::~WinCAPICryptoKeyRSA() {
// If we have a RSA, delete it
if (m_key == 0)
CryptDestroyKey(m_key);
if (mp_exponent)
delete[] mp_exponent;
if (mp_modulus)
delete[] mp_modulus;
};
WinCAPICryptoKeyRSA::WinCAPICryptoKeyRSA(WinCAPICryptoProvider * owner,
HCRYPTKEY k,
bool havePrivate) :
mp_ownerProvider(owner),
m_havePrivate(havePrivate) {
mp_ownerProvider = owner;
m_key = k; // NOTE - We OWN this handle
mp_exponent = mp_modulus = NULL;
m_exponentLen = m_modulusLen = 0;
}
// Generic key functions
XSECCryptoKey::KeyType WinCAPICryptoKeyRSA::getKeyType() {
// Find out what we have
if (m_key == 0) {
if (mp_exponent == NULL ||
mp_modulus == NULL)
return KEY_NONE;
else
return KEY_RSA_PUBLIC;
}
if (m_havePrivate == true)
return KEY_RSA_PAIR;
return KEY_RSA_PUBLIC;
}
//
--------------------------------------------------------------------------------
// Load key from parameters
//
--------------------------------------------------------------------------------
void WinCAPICryptoKeyRSA::loadPublicModulusBase64BigNums(const char * b64,
unsigned int len) {
if (mp_modulus != NULL) {
delete[] mp_modulus;
mp_modulus = NULL; // In case we get an exception
}
mp_modulus = WinCAPICryptoProvider::b642WinBN(b64, len, m_modulusLen);
}
void WinCAPICryptoKeyRSA::loadPublicExponentBase64BigNums(const char * b64,
unsigned int len) {
if (mp_exponent != NULL) {
delete[] mp_exponent;
mp_exponent = NULL; // In case we get an exception
}
mp_exponent = WinCAPICryptoProvider::b642WinBN(b64, len, m_exponentLen);
}
void WinCAPICryptoKeyRSA::importKey(void) {
if (m_key != 0 ||
mp_exponent == NULL ||
mp_modulus == NULL)
return;
// Create a RSA Public-Key blob
// First build a buffer to hold everything
BYTE * blobBuffer;
unsigned int blobBufferLen = WINCAPI_BLOBHEADERLEN +
WINCAPI_RSAPUBKEYLEN + m_modulusLen;
XSECnew(blobBuffer, BYTE[blobBufferLen]);
ArrayJanitor<BYTE> j_blobBuffer(blobBuffer);
// Blob header
BLOBHEADER * header = (BLOBHEADER *) blobBuffer;
header->bType = PUBLICKEYBLOB;
header->bVersion = 0x02; // We are using a
version 2 blob
header->reserved = 0;
header->aiKeyAlg = CALG_RSA_SIGN;
// Now the public key header
RSAPUBKEY * pubkey = (RSAPUBKEY *) (blobBuffer + WINCAPI_BLOBHEADERLEN);
pubkey->magic = 0x31415352; // ASCII encoding of
RSA1
pubkey->bitlen = m_modulusLen * 8; // Number of bits in
prime modulus
pubkey->pubexp = 0;
BYTE * i = ((BYTE *) &(pubkey->pubexp));
for (unsigned int j = 0; j < m_exponentLen; ++j)
*i++ = mp_exponent[j];
// Now copy in the modulus
i = (BYTE *) (pubkey);
i += WINCAPI_RSAPUBKEYLEN;
memcpy(i, mp_modulus, m_modulusLen);
// Now that we have the blob, import
BOOL fResult = CryptImportKey(
mp_ownerProvider->getProviderRSA(),
blobBuffer,
blobBufferLen,
0, // Not
signed
0, // No
flags
&m_key);
if (fResult == 0) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA Error attempting to import key
parameters");
}
}
//
--------------------------------------------------------------------------------
// Verify a signature encoded as a Base64 string
//
--------------------------------------------------------------------------------
bool WinCAPICryptoKeyRSA::verifySHA1PKCS1Base64Signature(const unsigned char
* hashBuf,
unsigned int
hashLen,
const char *
base64Signature,
unsigned int
sigLen) {
// 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::RSAError,
"WinCAPI:RSA - 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);
BYTE * rawSigFinal;
XSECnew(rawSigFinal, BYTE[rawSigLen]);
ArrayJanitor<BYTE> j_rawSigFinal(rawSigFinal);
BYTE * j, *l;
j = rawSig;
l = rawSigFinal + rawSigLen - 1;
while (l >= rawSigFinal) {
*l-- = *j++;
}
// Have to create a Windows hash object and feed in the hash
BOOL fResult;
HCRYPTHASH h;
fResult = CryptCreateHash(mp_ownerProvider->getProviderRSA(),
CALG_SHA1,
0,
0,
&h);
if (!fResult) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error creating Windows Hash Object");
}
// Feed the hash value into the newly created hash object
fResult = CryptSetHashParam(
h,
HP_HASHVAL,
(unsigned char *) hashBuf,
0);
if (!fResult) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error Setting Hash Value in Windows Hash
object");
}
// Now validate
fResult = CryptVerifySignature(
h,
rawSigFinal,
rawSigLen,
m_key,
NULL,
0);
if (!fResult) {
DWORD error = GetLastError();
if (error != NTE_BAD_SIGNATURE) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error occurred in RSA validation");
}
return false;
}
return true;
}
//
--------------------------------------------------------------------------------
// Sign and encode result as a Base64 string
//
--------------------------------------------------------------------------------
unsigned int WinCAPICryptoKeyRSA::signSHA1PKCS1Base64Signature(unsigned char
* hashBuf,
unsigned int hashLen,
char * base64SignatureBuf,
unsigned int base64SignatureBufLen) {
// Sign a pre-calculated hash using this key
if (m_key == NULL) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Attempt to sign data with empty key");
}
if (m_havePrivate == false) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Attempt to sign data a public key");
}
// Have to create a Windows hash object and feed in the hash
BOOL fResult;
HCRYPTHASH h;
fResult = CryptCreateHash(mp_ownerProvider->getProviderRSA(),
CALG_SHA1,
0,
0,
&h);
if (!fResult) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error creating Windows Hash Object");
}
// Feed the hash value into the newly created hash object
fResult = CryptSetHashParam(
h,
HP_HASHVAL,
hashBuf,
0);
if (!fResult) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error Setting Hash Value in Windows Hash
object");
}
// Now sign
DWORD rawSigLen;
fResult = CryptSignHash(
h,
AT_SIGNATURE,
NULL,
0,
NULL,
&rawSigLen);
if (!fResult || rawSigLen < 1) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error occurred obtaining RSA sig length");
}
BYTE * rawSig;
XSECnew(rawSig, BYTE[rawSigLen]);
ArrayJanitor<BYTE> j_rawSig(rawSig);
fResult = CryptSignHash(
h,
AT_SIGNATURE,
NULL,
0,
rawSig,
&rawSigLen);
if (!fResult || rawSigLen < 1) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error occurred signing hash");
}
// Now encode into a signature block
BYTE *rawSigFinal;
XSECnew(rawSigFinal, BYTE[rawSigLen]);
ArrayJanitor<BYTE> j_rawSigFinal(rawSigFinal);
BYTE * i, * j;
i = rawSig;
j = rawSigFinal + rawSigLen - 1;
while (j >= rawSigFinal) {
*j-- = *i++;
}
// Now encode
XSCryptCryptoBase64 b64;
b64.encodeInit();
unsigned int ret = b64.encode(rawSigFinal, rawSigLen, (unsigned char *)
base64SignatureBuf, base64SignatureBufLen);
ret += b64.encodeFinish((unsigned char *) &base64SignatureBuf[ret],
base64SignatureBufLen - ret);
return ret;
}
XSECCryptoKey * WinCAPICryptoKeyRSA::clone() {
WinCAPICryptoKeyRSA * ret;
XSECnew(ret, WinCAPICryptoKeyRSA(mp_ownerProvider));
if (m_key != 0) {
// CryptDuplicateKey is not supported in Windows NT, so we need
to export and then
// reimport the key to get a copy
BYTE keyBuf[2048];
DWORD keyBufLen = 2048;
CryptExportKey(m_key, 0, PUBLICKEYBLOB, 0, keyBuf, &keyBufLen);
// Now re-import
CryptImportKey(mp_ownerProvider->getProviderRSA(), keyBuf,
keyBufLen, NULL, 0, &ret->m_key);
}
ret->m_exponentLen = m_exponentLen;
if (mp_exponent != NULL) {
XSECnew(ret->mp_exponent, BYTE[m_exponentLen]);
memcpy(ret->mp_exponent, mp_exponent, m_exponentLen);
}
else
ret->mp_exponent = NULL;
ret->m_modulusLen = m_modulusLen;
if (mp_modulus != NULL) {
XSECnew(ret->mp_modulus, BYTE[m_modulusLen]);
memcpy(ret->mp_modulus, mp_modulus, m_modulusLen);
}
else
ret->mp_modulus = NULL;
return ret;
}
//
--------------------------------------------------------------------------------
// Some utility functions
//
--------------------------------------------------------------------------------
void WinCAPICryptoKeyRSA::loadParamsFromKey(void) {
if (m_key == 0)
return;
// Export key into a keyblob
BOOL fResult;
DWORD blobLen;
fResult = CryptExportKey(
m_key,
0,
PUBLICKEYBLOB,
0,
NULL,
&blobLen);
if (fResult == 0 || blobLen < 1) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error exporting public key");
}
BYTE * blob;
XSECnew(blob, BYTE[blobLen]);
ArrayJanitor<BYTE> j_blob(blob);
fResult = CryptExportKey(
m_key,
0,
PUBLICKEYBLOB,
0,
blob,
&blobLen);
if (fResult == 0 || blobLen < 1) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"WinCAPI:RSA - Error exporting public key");
}
RSAPUBKEY * pk = (RSAPUBKEY *) ( blob + WINCAPI_BLOBHEADERLEN );
DWORD keyLen = pk->bitlen / 8;
// Copy the keys
BYTE * i = (BYTE *) ( pk );
i += WINCAPI_RSAPUBKEYLEN;
if (mp_modulus != NULL)
delete[] mp_modulus;
m_modulusLen = keyLen;
XSECnew(mp_modulus, BYTE[m_modulusLen]);
memcpy(mp_modulus, i, m_modulusLen);
// Take the simple way out
XSECnew(mp_exponent, BYTE[4]);
*((DWORD *) mp_exponent) = pk->pubexp;
// Now cut any leading 0s (Windows is LE, so start least significant
end)
m_exponentLen = 3;
while (m_exponentLen > 0 && mp_exponent[m_exponentLen] == 0)
m_exponentLen--;
m_exponentLen++; // Make it a length as apposed to an offset
}
unsigned int WinCAPICryptoKeyRSA::getExponentBase64BigNums(char * b64,
unsigned int len) {
if (m_key == 0 && mp_exponent == NULL) {
return 0; // Nothing we can do
}
if (mp_exponent == NULL) {
loadParamsFromKey();
}
unsigned int bLen;
unsigned char * b = WinCAPICryptoProvider::WinBN2b64(mp_exponent,
m_exponentLen, bLen);
if (bLen > len)
bLen = len;
memcpy(b64, b, bLen);
delete[] b;
return bLen;
}
unsigned int WinCAPICryptoKeyRSA::getModulusBase64BigNums(char * b64,
unsigned int len) {
if (m_key == 0 && mp_modulus == NULL) {
return 0; // Nothing we can do
}
if (mp_modulus == NULL) {
loadParamsFromKey();
}
unsigned int bLen;
unsigned char * b = WinCAPICryptoProvider::WinBN2b64(mp_modulus,
m_modulusLen, bLen);
if (bLen > len)
bLen = len;
memcpy(b64, b, bLen);
delete[] b;
return bLen;
}