blob: e91d0f021256612cf5566905236e6eff1b0aa271 [file] [log] [blame]
/**
* 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
*
* NSSCryptoKeyDSA := DSA Keys
*
* Author(s): Milan Tomic
*
*/
#include <xsec/enc/NSS/NSSCryptoKeyDSA.hpp>
#include <xsec/enc/NSS/NSSCryptoProvider.hpp>
#include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
#include <xsec/enc/XSECCryptoException.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xercesc/util/Janitor.hpp>
#if defined (XSEC_HAVE_NSS)
XSEC_USING_XERCES(ArrayJanitor);
// --------------------------------------------------------------------------------
// Constructor
// --------------------------------------------------------------------------------
NSSCryptoKeyDSA::NSSCryptoKeyDSA(SECKEYPublicKey * pubkey, SECKEYPrivateKey * privkey) {
// NOTE - We OWN those handles
mp_pubkey = pubkey;
mp_privkey = privkey;
mp_P = NULL;
mp_Q = NULL;
mp_G = NULL;
mp_Y = NULL;
};
// --------------------------------------------------------------------------------
// Destructor
// --------------------------------------------------------------------------------
NSSCryptoKeyDSA::~NSSCryptoKeyDSA() {
// Clean up
if (mp_pubkey != 0)
SECKEY_DestroyPublicKey(mp_pubkey);
if (mp_privkey != 0)
SECKEY_DestroyPrivateKey(mp_privkey);
if (mp_P != NULL)
SECITEM_FreeItem(mp_P, PR_TRUE);
if (mp_Q != NULL)
SECITEM_FreeItem(mp_Q, PR_TRUE);
if (mp_G != NULL)
SECITEM_FreeItem(mp_G, PR_TRUE);
if (mp_Y != NULL)
SECITEM_FreeItem(mp_Y, PR_TRUE);
};
const XMLCh * NSSCryptoKeyDSA::getProviderName() const {
return DSIGConstants::s_unicodeStrPROVNSS;
}
// --------------------------------------------------------------------------------
// Get key type
// --------------------------------------------------------------------------------
XSECCryptoKey::KeyType NSSCryptoKeyDSA::getKeyType() const {
// Find out what we have
if (mp_pubkey == NULL) {
if (mp_privkey != 0)
return KEY_DSA_PRIVATE;
// Check if we have parameters loaded
if (mp_P == NULL ||
mp_Q == NULL ||
mp_G == NULL ||
mp_Y == NULL)
return KEY_NONE;
else
return KEY_DSA_PUBLIC;
}
if (mp_privkey != 0)
return KEY_DSA_PAIR;
// If we have m_key - it must be public
return KEY_DSA_PUBLIC;
}
// --------------------------------------------------------------------------------
// Load P parameter
// --------------------------------------------------------------------------------
void NSSCryptoKeyDSA::loadPBase64BigNums(const char * b64, unsigned int len) {
if (mp_P != NULL) {
SECITEM_FreeItem(mp_P, PR_TRUE);
mp_P = NULL; // In case we get an exception
}
mp_P = NSSCryptoProvider::b642SI(b64, len);
}
// --------------------------------------------------------------------------------
// Load Q parameter
// --------------------------------------------------------------------------------
void NSSCryptoKeyDSA::loadQBase64BigNums(const char * b64, unsigned int len) {
if (mp_Q != NULL) {
SECITEM_FreeItem(mp_Q, PR_TRUE);
mp_Q = NULL; // In case we get an exception
}
mp_Q = NSSCryptoProvider::b642SI(b64, len);
}
// --------------------------------------------------------------------------------
// Load G parameter
// --------------------------------------------------------------------------------
void NSSCryptoKeyDSA::loadGBase64BigNums(const char * b64, unsigned int len) {
if (mp_G != NULL) {
SECITEM_FreeItem(mp_G, PR_TRUE);
mp_G = NULL; // In case we get an exception
}
mp_G = NSSCryptoProvider::b642SI(b64, len);
}
// --------------------------------------------------------------------------------
// Load Y parameter
// --------------------------------------------------------------------------------
void NSSCryptoKeyDSA::loadYBase64BigNums(const char * b64, unsigned int len) {
if (mp_Y != NULL) {
SECITEM_FreeItem(mp_Y, PR_TRUE);
mp_Y = NULL; // In case we get an exception
}
mp_Y = NSSCryptoProvider::b642SI(b64, len);
}
// --------------------------------------------------------------------------------
// Load Y parameter
// --------------------------------------------------------------------------------
void NSSCryptoKeyDSA::loadJBase64BigNums(const char * b64, unsigned int len) {
//Do nothing
}
// --------------------------------------------------------------------------------
// Import key
// --------------------------------------------------------------------------------
void NSSCryptoKeyDSA::importKey(void) const {
if (mp_pubkey != 0 ||
mp_P == NULL ||
mp_Q == NULL ||
mp_G == NULL ||
mp_Y == NULL)
return;
PRArenaPool * arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if(arena == NULL) {
throw XSECCryptoException(XSECCryptoException::GeneralError,
"NSS:DSA Error attempting create new arena");
}
mp_pubkey = (SECKEYPublicKey*)PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
if(mp_pubkey == NULL ) {
PORT_FreeArena(arena, PR_FALSE);
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting create new arena");
}
mp_pubkey->arena = arena;
mp_pubkey->u.dsa.params.arena = arena;
mp_pubkey->keyType = dsaKey;
SECStatus s = SECITEM_CopyItem(arena, &(mp_pubkey->u.dsa.params.prime), mp_P);
if (s != SECSuccess) {
PORT_FreeArena(arena, PR_FALSE);
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to import P key parameter");
}
s = SECITEM_CopyItem(arena, &(mp_pubkey->u.dsa.params.subPrime), mp_Q);
if (s != SECSuccess) {
PORT_FreeArena(arena, PR_FALSE);
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to import Q key parameter");
}
s = SECITEM_CopyItem(arena, &(mp_pubkey->u.dsa.params.base), mp_G);
if (s != SECSuccess) {
PORT_FreeArena(arena, PR_FALSE);
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to import G key parameter");
}
s = SECITEM_CopyItem(arena, &(mp_pubkey->u.dsa.publicValue), mp_Y);
if (s != SECSuccess) {
PORT_FreeArena(arena, PR_FALSE);
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to import Y key parameter");
}
}
// --------------------------------------------------------------------------------
// Verify a signature encoded as a Base64 string
// --------------------------------------------------------------------------------
bool NSSCryptoKeyDSA::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 (mp_pubkey == 0) {
// Try to import from the parameters
importKey();
if (mp_pubkey == 0) {
throw XSECCryptoException(XSECCryptoException::DSAError,
"NSS:DSA - Attempt to validate signature with empty key");
}
}
// Decode the signature
unsigned char * rawSig;
unsigned int rawSigLen;
XSECnew(rawSig, unsigned char[sigLen]);
ArrayJanitor<unsigned char> 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);
SECItem signature;
signature.type = siBuffer;
signature.data = rawSig;
signature.len = rawSigLen;
SECItem data;
data.type = siBuffer;
data.data = (unsigned char *)hashBuf;
data.len = hashLen;
// Verify signature
SECStatus s = PK11_Verify(mp_pubkey, &signature, &data, NULL);
return s == SECSuccess;
}
// --------------------------------------------------------------------------------
// Sign and encode result as a Base64 string
// --------------------------------------------------------------------------------
unsigned int NSSCryptoKeyDSA::signBase64Signature(unsigned char * hashBuf,
unsigned int hashLen,
char * base64SignatureBuf,
unsigned int base64SignatureBufLen) const {
// Sign a pre-calculated hash using this key
if (mp_privkey == 0) {
throw XSECCryptoException(XSECCryptoException::DSAError,
"NSS:DSA - Attempt to sign data using a public or un-loaded key");
}
unsigned int signatureLen = PK11_SignatureLen(mp_privkey);
unsigned char * rawSig;
XSECnew(rawSig, unsigned char[signatureLen]);
ArrayJanitor<unsigned char> j_rawSig(rawSig);
SECItem signature;
signature.type = siBuffer;
signature.data = rawSig;
signature.len = signatureLen;
SECItem data;
data.type = siBuffer;
data.data = hashBuf;
data.len = hashLen;
SECStatus s = PK11_Sign(mp_privkey, &signature, &data);
if (s != SECSuccess) {
throw XSECCryptoException(XSECCryptoException::DSAError,
"NSS:DSA - Error during signing operation");
}
// Now encode
XSCryptCryptoBase64 b64;
b64.encodeInit();
unsigned int ret = b64.encode(signature.data, signature.len,
(unsigned char *) base64SignatureBuf, base64SignatureBufLen);
ret += b64.encodeFinish((unsigned char *) &base64SignatureBuf[ret],
base64SignatureBufLen - ret);
return ret;
}
// --------------------------------------------------------------------------------
// Clone key
// --------------------------------------------------------------------------------
XSECCryptoKey * NSSCryptoKeyDSA::clone() const {
NSSCryptoKeyDSA * ret = NULL;
XSECnew(ret, NSSCryptoKeyDSA(mp_pubkey, mp_privkey));
// Clone public key
if (mp_pubkey != 0) {
ret->mp_pubkey = SECKEY_CopyPublicKey(mp_pubkey);
if (ret->mp_pubkey == 0) {
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to clone (copy) public key");
}
}
// Clone private key
if (mp_privkey != 0) {
ret->mp_privkey = SECKEY_CopyPrivateKey(mp_privkey);
if (ret->mp_privkey == 0) {
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to clone (copy) private key");
}
}
// Clone parameter P
if (mp_P != 0) {
ret->mp_P = SECITEM_DupItem(mp_P);
if (ret->mp_P == 0) {
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to clone (copy) P key parameter");
}
}
// Clone parameter Q
if (mp_Q != 0) {
ret->mp_Q = SECITEM_DupItem(mp_Q);
if (ret->mp_Q == 0) {
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to clone (copy) Q key parameter");
}
}
// Clone parameter G
if (mp_G != 0) {
ret->mp_G = SECITEM_DupItem(mp_G);
if (ret->mp_G == 0) {
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to clone (copy) G key parameter");
}
}
// Clone parameter Y
if (mp_Y != 0) {
ret->mp_Y = SECITEM_DupItem(mp_Y);
if (ret->mp_Y == 0) {
throw XSECCryptoException(XSECCryptoException::MemoryError,
"NSS:DSA Error attempting to clone (copy) Y key parameter");
}
}
return ret;
}
// --------------------------------------------------------------------------------
// Some utility functions
// --------------------------------------------------------------------------------
void NSSCryptoKeyDSA::loadParamsFromKey(void) {
if (mp_pubkey == 0)
return;
mp_P = SECITEM_DupItem(&(mp_pubkey->u.dsa.params.prime));
if (mp_P == 0) {
throw XSECCryptoException(XSECCryptoException::DSAError,
"NSS:DSA - Error during extracting P from public key");
}
mp_Q = SECITEM_DupItem(&(mp_pubkey->u.dsa.params.subPrime));
if (mp_Q == 0) {
throw XSECCryptoException(XSECCryptoException::DSAError,
"NSS:DSA - Error during extracting Q from public key");
}
mp_G = SECITEM_DupItem(&(mp_pubkey->u.dsa.params.base));
if (mp_G == 0) {
throw XSECCryptoException(XSECCryptoException::DSAError,
"NSS:DSA - Error during extracting G from public key");
}
mp_Y = SECITEM_DupItem(&(mp_pubkey->u.dsa.publicValue));
if (mp_Y == 0) {
throw XSECCryptoException(XSECCryptoException::DSAError,
"NSS:DSA - Error during extracting Y from public key");
}
}
// --------------------------------------------------------------------------------
// Get P parameter
// --------------------------------------------------------------------------------
unsigned int NSSCryptoKeyDSA::getPBase64BigNums(char * b64, unsigned int len) {
if (mp_pubkey == 0 && mp_P == NULL) {
return 0; // Nothing we can do
}
if (mp_P == NULL) {
loadParamsFromKey();
}
unsigned int bLen = 0;
unsigned char * b = NSSCryptoProvider::SI2b64(mp_P, bLen);
if (bLen > len)
bLen = len;
memcpy(b64, b, bLen);
delete[] b;
return bLen;
}
// --------------------------------------------------------------------------------
// Get Q parameter
// --------------------------------------------------------------------------------
unsigned int NSSCryptoKeyDSA::getQBase64BigNums(char * b64, unsigned int len) {
if (mp_pubkey == 0 && mp_Q == NULL) {
return 0; // Nothing we can do
}
if (mp_Q == NULL) {
loadParamsFromKey();
}
unsigned int bLen = 0;
unsigned char * b = NSSCryptoProvider::SI2b64(mp_Q, bLen);
if (bLen > len)
bLen = len;
memcpy(b64, b, bLen);
delete[] b;
return bLen;
}
// --------------------------------------------------------------------------------
// Get G parameter
// --------------------------------------------------------------------------------
unsigned int NSSCryptoKeyDSA::getGBase64BigNums(char * b64, unsigned int len) {
if (mp_pubkey == 0 && mp_G == NULL) {
return 0; // Nothing we can do
}
if (mp_G == NULL) {
loadParamsFromKey();
}
unsigned int bLen = 0;
unsigned char * b = NSSCryptoProvider::SI2b64(mp_G, bLen);
if (bLen > len)
bLen = len;
memcpy(b64, b, bLen);
delete[] b;
return bLen;
}
// --------------------------------------------------------------------------------
// Get Y parameter
// --------------------------------------------------------------------------------
unsigned int NSSCryptoKeyDSA::getYBase64BigNums(char * b64, unsigned int len) {
if (mp_pubkey == 0 && mp_Y == NULL) {
return 0; // Nothing we can do
}
if (mp_Y == NULL) {
loadParamsFromKey();
}
unsigned int bLen = 0;
unsigned char * b = NSSCryptoProvider::SI2b64(mp_Y, bLen);
if (bLen > len)
bLen = len;
memcpy(b64, b, bLen);
delete[] b;
return bLen;
}
#endif /* XSEC_HAVE_NSS */