PKIFNSS.cpp

Go to the documentation of this file.
00001 
00009 #include "PKIFNSS.h"
00010 #include "PKIFNSSHelper.h"
00011 
00012 #include "PKIFNSSDatabase.h"
00013 #include "PKIFNSSCredential.h"
00014 
00015 #include "ToolkitUtils.h"
00016 #include "PKIFCryptoErrors.h"
00017 #include "PKIFNSSErrors.h"
00018 #include "PKIFCryptoException.h"
00019 #include "KeyUsage.h"
00020 
00021 #include <sstream>
00022 
00023 #include "PKIFNSSConfig.h"
00024 #include "PKIFNSSUtils.h"
00025 #include "nspr.h"
00026 
00027 #include "boost/numeric/conversion/cast.hpp"
00028 
00029 using boost::numeric_cast;
00030 using boost::bad_numeric_cast;
00031 
00032 using namespace std;
00033 
00034 static bool s_nssKVHashesBuilt = false;
00036 struct CPKIFNSSImpl
00037 {
00038     string m_dbdir;
00039     CERTCertDBHandle * m_certDbHandle;
00040 
00041 };
00043 
00051 CPKIFNSS::CPKIFNSS(
00053     const std::string & dbdir)
00054 :m_impl(new CPKIFNSSImpl)
00055 {
00056     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_NSS,0,this);
00057     m_impl->m_dbdir = dbdir;
00058 }
00066 CPKIFNSS::~CPKIFNSS()
00067 {
00068     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_NSS,0,this);
00069     if(!m_impl) {
00070         delete m_impl;
00071         m_impl = 0;
00072     }
00073 }
00074 
00075 // make sure NSS has been initialized using the appropriate database directory
00076 // throws if it hasn't
00086 void CPKIFNSS::Initialize()
00087 {
00088     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_NSS,0,this);
00089     if(!CPKIFNSSHelper::NSSAvaliable()) {
00090         RAISE_CRYPTO_EXCEPTION("NSS could not be loaded.",thisComponent,PKIFNSS_INIT_FAILED,this);
00091     }
00092     CPKIFNSSDatabase::GetInstance(m_impl->m_dbdir);
00093     m_impl->m_certDbHandle = CERT_GetDefaultCertDB();
00094 }
00095 
00104 void CPKIFNSS::GetKeyList(
00106     CPKIFCredentialList& v,
00108     CPKIFKeyUsagePtr& ku)
00109 {
00110     bitset<9> tmp = ku->GetKeyUsage();
00111     GetKeyList(v, &tmp);
00112 }
00113 
00122 void CPKIFNSS::GetKeyList(
00124     CPKIFCredentialList& v,
00126     std::bitset<9>* ku)
00127 {
00128     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_NSS,0,this);
00129     PK11SlotList * slots = 0;
00130     PK11SlotListElement * i = 0;
00131     
00132     // this will return all soft and hard tokens in the database
00133     slots = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,NULL);
00134     if(slots) {
00135         // step through each token and list private keys
00136         for(i = slots->head; 0 != i; i = i->next) {
00137             PK11SlotInfo * slot = i->slot;
00138             SECKEYPrivateKeyList * keys = 0;
00139             SECKEYPrivateKeyListNode * j = 0;
00140             if(PK11_NeedLogin(slot)) {
00141                 PK11_Authenticate(slot,PR_TRUE,NULL);
00142             }
00143             keys = PK11_ListPrivateKeysInSlot(slot);
00144             if(!keys) {
00145                 continue;
00146             }
00147             // go through private keys and inspect keys that have an associated cert; we're can't use
00148             // ones that don't anyway
00149             for(j = PRIVKEY_LIST_HEAD(keys); !PRIVKEY_LIST_END(j,keys); j = PRIVKEY_LIST_NEXT(j)) {
00150                 CERTCertificate * nssCert = PK11_GetCertFromPrivateKey(j->key);
00151                 if(nssCert) {
00152                     // if the caller requested a particular key usage, check that
00153                     if(ku) {
00154                         SECItem nssKU;
00155                         SECStatus rv = CERT_FindKeyUsageExtension(nssCert,&nssKU);
00156                         if(SECSuccess == rv) {
00157                             if(keyUsageTest(nssKU.data,ku)) {
00158                                 // got a usable key with appropriate key usage, add it
00159                                 CPKIFCredentialPtr tmp(new CPKIFNSSCredential(j->key,&nssCert->derCert));
00160                                 v.push_back(tmp);
00161                             }
00162                             PR_Free(nssKU.data);
00163                         }
00164                     } else {
00165                         CPKIFCredentialPtr tmp(new CPKIFNSSCredential(j->key,&nssCert->derCert));
00166                         v.push_back(tmp);
00167                     }
00168                     CERT_DestroyCertificate(nssCert);
00169                 }
00170             }
00171             SECKEY_DestroyPrivateKeyList(keys);
00172         }
00173         PK11_FreeSlotList(slots);
00174     }
00175 }
00185 bool CPKIFNSS::OwnsKey(
00187     const CPKIFCredential& keyID) const
00188 {
00189     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_NSS,0,this);
00190     // since there can only be one instance of the NSS database, if we
00191     // see an NSS key we can act like we own it.
00192     const CPKIFNSSCredential * nsskey = dynamic_cast<const CPKIFNSSCredential *>(&keyID);
00193     return (0 != nsskey);
00194 }
00206 CPKIFCredentialPtr CPKIFNSS::MakeKeyID(
00209     const std::string& asciiHexKeyID)
00210 {
00211     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_NSS,0,this);
00212     if(!m_impl->m_certDbHandle) {
00213         RAISE_CRYPTO_EXCEPTION("CPKIFNSS instance not initialized.", thisComponent, COMMON_NOT_INITIALIZED, this);
00214     }
00215     if(!s_nssKVHashesBuilt) {
00216         NSSCMSRecipient * recip = 0;
00217         PK11_FindCertAndKeyByRecipientListNew(&recip,0);
00218         s_nssKVHashesBuilt = true;
00219     }
00220     CPKIFCredentialPtr nullCred;
00221     const char * hex = asciiHexKeyID.c_str();
00222     unsigned int len = 0;
00223 
00224     try 
00225     {
00226         len = numeric_cast<unsigned int>(asciiHexKeyID.length()/2);
00227     }
00228     catch(bad_numeric_cast &) 
00229     {
00230         throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "Key identifier is an impossibly long number.");
00231     }
00232 
00233     unsigned char * bin = new unsigned char[len];
00234     if(0 != atob((char *)bin,const_cast<char *>(hex),&len)) {
00235         delete[] bin;
00236         RAISE_CRYPTO_EXCEPTION("Key ID contains invalid characters.",thisComponent,COMMON_INVALID_INPUT,this);
00237     }
00238     SECItem siSKID;
00239     siSKID.data = bin;
00240     siSKID.len = len;
00241     siSKID.type = siBuffer;
00242 
00243     // XXX TESTING TODO: Confirm that this is the right thing for NSS and SKIDs 
00244     // (i.e. that it doesn't need to be DER-encoded first)
00245     CERTCertificate * nssCert = CERT_FindCertBySubjectKeyID(m_impl->m_certDbHandle,&siSKID);
00246     delete[] bin;
00247     if(!nssCert) {
00248         return nullCred;
00249     }
00250     SECKEYPrivateKey * nssPrivateKey = 0;
00251     nssPrivateKey = PK11_FindKeyByAnyCert(nssCert,0);
00252     if(!nssPrivateKey) {
00253         CERT_DestroyCertificate(nssCert);
00254         return nullCred;
00255     }
00256     CPKIFNSSCredential * cred = new CPKIFNSSCredential(nssPrivateKey,&nssCert->derCert);
00257     CERT_DestroyCertificate(nssCert);
00258     return CPKIFCredentialPtr(cred);
00259 }
00280 void CPKIFNSS::Sign(
00282     const CPKIFCredential& key, 
00284     unsigned char* pHashData, 
00286     int nHashDataLen, 
00288     unsigned char* pSignature, 
00291     int* nSignatureLen,
00293     PKIFCRYPTO::HASH_ALG hashAlg
00294     )
00295 {
00296     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_NSS,0,this);
00297     const CPKIFNSSCredential * nssKey = dynamic_cast<const CPKIFNSSCredential *>(&key);
00298     if(!nssKey) {
00299         RAISE_CRYPTO_EXCEPTION("NSS Crypto colleague was given a non-NSS credential",
00300             thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00301     }
00302     SECItem sig;
00303     sig.len = *nSignatureLen;
00304     sig.data = new unsigned char[sig.len];
00305     sig.type = siBuffer;
00306     SECItem hash;
00307     hash.data = pHashData;
00308     hash.len = nHashDataLen;
00309     hash.type = siBuffer;
00310     sig.len = PK11_SignatureLen(nssKey->m_privateKey);
00311     sig.data = new unsigned char[sig.len];
00312     sig.type = siBuffer;
00313     SECOidTag tag = NSSHashAlg(hashAlg);
00314     //SECStatus rv = PK11_Sign(nssKey->m_privateKey,&sig,&hash);
00315     SECStatus rv = SGN_Digest(nssKey->m_privateKey,tag,&sig,&hash);
00316     if(SECSuccess != rv) {
00317         RAISE_CRYPTO_EXCEPTION("NSS Signature generation failed.",thisComponent,CRYPTO_SIGN_FAILED,this);
00318     }
00319 
00320     try
00321     {
00322         int tmpLen = numeric_cast<int>(sig.len);
00323         if(*nSignatureLen < tmpLen) 
00324         {
00325             PR_Free(sig.data);
00326             RAISE_CRYPTO_EXCEPTION("Supplied signature buffer is too small", thisComponent,COMMON_INVALID_INPUT,this);
00327         }
00328     }
00329     catch(bad_numeric_cast &) 
00330     {
00331         PR_Free(sig.data);
00332         RAISE_CRYPTO_EXCEPTION("Supplied signature size is too large", thisComponent,COMMON_INVALID_INPUT,this);
00333     }
00334     
00335     memcpy(pSignature,sig.data,sig.len);
00336     *nSignatureLen = sig.len;
00337     PR_Free(sig.data);
00338 }
00339 
00357 void CPKIFNSS::Decrypt(
00360     const CPKIFCredential& key,
00362     unsigned char* pData,
00364     int nDataLen, 
00366     unsigned char* pResult,
00369     int* pnResultLen)
00370 {
00371     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_NSS,0,this);
00372     const CPKIFNSSCredential * nssKey = dynamic_cast<const CPKIFNSSCredential *>(&key);
00373     if(!nssKey) {
00374         RAISE_CRYPTO_EXCEPTION("NSS Crypto colleague was given a non-NSS credential",
00375             thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00376     }
00377     int maxLen = *pnResultLen;
00378     unsigned int realOut = 0;
00379     SECStatus rv = PK11_PrivDecryptPKCS1(nssKey->m_privateKey, pResult, &realOut, maxLen, pData, nDataLen);
00380     *pnResultLen = realOut;
00381     if(SECSuccess != rv) {
00382         RAISE_CRYPTO_EXCEPTION("NSS Asymmetric decryption failed.",thisComponent,CRYPTO_DECRYPT_FAILED,this);
00383     }
00384 }
00396 void CPKIFNSS::Encrypt(
00399     const CPKIFCredential& key,
00401     unsigned char* pData, 
00403     int nDataLen, 
00405     unsigned char* pResult, 
00408     int* pnResultLen)
00409 {
00410     RAISE_CRYPTO_EXCEPTION("Encryption is unimplemented for stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00411 }
00425 bool CPKIFNSS::Verify(
00428     const CPKIFCredential& key,
00431     unsigned char* pHashData, 
00433     int nHashDataLen, 
00435     unsigned char* pSignature, 
00437     int nSignatureLen,
00439     PKIFCRYPTO::HASH_ALG hashAlg
00440     )
00441 {
00442     RAISE_CRYPTO_EXCEPTION("Verification is unimplemented for stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00443     return false;
00444 }
00458 IPKIFCryptContext* CPKIFNSS::CryptInit(
00461     CPKIFCredentialPtr& key,
00463     bool pad)
00464 {
00465     RAISE_CRYPTO_EXCEPTION("Context-based operations are unimplemented for NSS stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00466     return 0;
00467 }
00480 void CPKIFNSS::Decrypt(
00483     IPKIFCryptContext* cryptContext, 
00485     unsigned char* pData, 
00487     int nDataLen, 
00489     unsigned char* pResult, 
00492     int* pnResultLen, 
00495     bool final)
00496 {
00497     RAISE_CRYPTO_EXCEPTION("Context-based decryption is unimplemented for stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00498 }
00511 void CPKIFNSS::Encrypt(IPKIFCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)
00512 {
00513     RAISE_CRYPTO_EXCEPTION("Encryption is unimplemented for stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00514 }

Generated on Mon Nov 15 11:15:55 2010 for PublicKeyInfrastructureFramework(PKIF) by  doxygen 1.5.6