xsec/enc/NSS/NSSCryptoKeyDSA.cpp (320 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 * * 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 */