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
00076
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
00133 slots = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,NULL);
00134 if(slots) {
00135
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
00148
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
00153 if(ku) {
00154 SECItem nssKU;
00155 SECStatus rv = CERT_FindKeyUsageExtension(nssCert,&nssKU);
00156 if(SECSuccess == rv) {
00157 if(keyUsageTest(nssKU.data,ku)) {
00158
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
00191
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
00244
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
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 }