00001
00009 #include "PKIFNSSRaw.h"
00010 #include "PKIFNSSRawCryptContext.h"
00011 #include "PKIFNSSHashContext.h"
00012
00013 #include "PKIFCryptoException.h"
00014 #include "PKIFKeyMaterial.h"
00015 #include "PKIFCryptoPPKeyMaterial.h"
00016 #include "PKIFAlgorithm.h"
00017
00018 #include "ToolkitUtils.h"
00019 #include "PKIFNSSErrors.h"
00020 #include "PKIFNSSDatabase.h"
00021 #include "PKIFCryptoErrors.h"
00022 #include "Certificate.h"
00023 #include "Buffer.h"
00024
00025 #include <sstream>
00026
00027 #include "PKIFNSSConfig.h"
00028 #include "PKIFNSSUtils.h"
00029 #include "nspr.h"
00030
00031 using namespace std;
00032
00033 static CK_MECHANISM_TYPE CipherMechForKey(const CPKIFKeyMaterial &key, bool pad = false);
00034 template<bool _CryptDirection>
00035 static void _ASymCrypt(const CPKIFKeyMaterial& key, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool pad = true);
00036
00037
00039 struct CPKIFNSSRawImpl
00040 {
00041 string m_dbdir;
00042 };
00044
00046
00053 CK_MECHANISM_TYPE CipherMechForKey(
00055 const CPKIFKeyMaterial &key,
00057 bool pad)
00058 {
00059 switch(key.GetSymmetricKeyAlgorithm())
00060 {
00061 case PKIFCRYPTO::TDES:
00062 switch(key.GetMode())
00063 {
00064 case PKIFCRYPTO::ECB:
00065 return CKM_DES3_ECB;
00066 break;
00067 case PKIFCRYPTO::CBC:
00068 return pad ? CKM_DES3_CBC_PAD : CKM_DES3_CBC;
00069 break;
00070 default:
00071 break;
00072 }
00073 break;
00074 case PKIFCRYPTO::DES:
00075 switch(key.GetMode())
00076 {
00077 case PKIFCRYPTO::ECB:
00078 return CKM_DES_ECB;
00079 break;
00080 case PKIFCRYPTO::CBC:
00081 return pad ? CKM_DES_CBC_PAD : CKM_DES_CBC;
00082 break;
00083 default:
00084 break;
00085 }
00086 break;
00087 case PKIFCRYPTO::AES:
00088 case PKIFCRYPTO::AES128:
00089 case PKIFCRYPTO::AES192:
00090 case PKIFCRYPTO::AES256:
00091 switch(key.GetMode())
00092 {
00093 case PKIFCRYPTO::ECB:
00094 return CKM_AES_ECB;
00095 break;
00096 case PKIFCRYPTO::CBC:
00097 return pad ? CKM_AES_CBC_PAD : CKM_AES_CBC;
00098 break;
00099 default:
00100 break;
00101 }
00102 break;
00103 default:
00104 break;
00105 }
00106 RAISE_CRYPTO_EXCEPTION("Unsupported algorithm and mode combination", TOOLKIT_CRYPTO_NSSRAW, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00107
00108 return CKM_VENDOR_DEFINED;
00109 }
00110
00111
00122 static SECOidTag NSSPKAlg(PKIFCRYPTO::ASYMKEY_ALG alg)
00123 {
00124 switch(alg)
00125 {
00126 case PKIFCRYPTO::RSA:
00127 return SEC_OID_PKCS1_RSA_ENCRYPTION;
00128 break;
00129 case PKIFCRYPTO::DSS:
00130 return SEC_OID_ANSIX9_DSA_SIGNATURE;
00131 break;
00132 case PKIFCRYPTO::ECC:
00133 return SEC_OID_ANSIX962_EC_PUBLIC_KEY;
00134 break;
00135 }
00136 return SEC_OID_UNKNOWN;
00137 }
00138
00149 static SECOidTag NSSSigAlg(PKIFCRYPTO::ASYMKEY_ALG alg, PKIFCRYPTO::HASH_ALG ha)
00150 {
00151 switch(alg)
00152 {
00153 case PKIFCRYPTO::RSA:
00154 return SEC_OID_PKCS1_RSA_ENCRYPTION;
00155 break;
00156 case PKIFCRYPTO::DSS:
00157 return SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST;
00158 break;
00159 case PKIFCRYPTO::ECC:
00160
00161 return SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST;
00162 break;
00163 }
00164 return SEC_OID_UNKNOWN;
00165 }
00166
00167
00179 CPKIFNSSRaw::CPKIFNSSRaw(
00181 const std::string & dbdir)
00182 :m_impl(new CPKIFNSSRawImpl)
00183 {
00184 LOG_STRING_DEBUG("CPKIFNSSRaw::CPKIFNSSRaw(void)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00185 m_impl->m_dbdir = dbdir;
00186 }
00194 CPKIFNSSRaw::~CPKIFNSSRaw(void)
00195 {
00196 LOG_STRING_DEBUG("CPKIFNSSRaw::~CPKIFNSSRaw(void)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00197 if(!m_impl) {
00198 delete m_impl;
00199 m_impl = 0;
00200 }
00201 }
00209 void CPKIFNSSRaw::Initialize()
00210 {
00211 LOG_STRING_DEBUG("CPKIFNSSRaw::Initialize()", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00212 if(m_impl->m_dbdir == "")
00213 CPKIFNSSDatabase * db = CPKIFNSSDatabase::GetInstance();
00214 else
00215 CPKIFNSSDatabase * db = CPKIFNSSDatabase::GetInstance(m_impl->m_dbdir);
00216 }
00228 bool CPKIFNSSRaw::SupportsAlgorithm(
00230 const CPKIFKeyMaterial& key)
00231 {
00232 LOG_STRING_DEBUG("CPKIFNSSRaw::SupportsAlgorithm(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00233 if(key.ContainsSymmetricKeyMaterial())
00234 {
00235 try
00236 {
00237 if (CKM_VENDOR_DEFINED != CipherMechForKey(key)) return true;
00238 }
00239 catch(CPKIFCryptoException& e)
00240 {
00241 if(CRYPTO_ALG_NOT_SUPPORTED == e.GetErrorCode())
00242 {
00243
00244
00245
00246
00247 return false;
00248 }
00249 else
00250 throw e;
00251 }
00252 }
00253 else if(key.ContainsCertificate())
00254 {
00255 SECItem encCert;
00256
00257 encCert.data = const_cast< unsigned char *>(key.GetCertificate());
00258 encCert.len = key.GetCertificateLength();
00259 encCert.type = siBuffer;
00260 SECItem * encCerts[1];
00261 encCerts[0] = &encCert;
00262
00263
00264
00265
00266 CERTCertificate ** cert = NULL;
00267
00268
00269 SECStatus rv = CERT_ImportCerts(CERT_GetDefaultCertDB(),certUsageUserCertImport,
00270 1,encCerts,&cert,PR_FALSE,PR_FALSE,NULL);
00271
00272 if(rv != SECSuccess || !cert || !cert[0])
00273 {
00274 if(cert) PR_Free(cert);
00275 std::ostringstream os;
00276 os << "CERT_ImportCerts failed: ";
00277 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFNSS_CERT_IMPORT_FAILED, this)
00278 }
00279
00280 SECAlgorithmID alg = cert[0]->subjectPublicKeyInfo.algorithm;
00281 SECOidTag oid = SECOID_GetAlgorithmTag(&alg);
00282 CERT_DestroyCertificate(cert[0]);
00283 PR_Free(cert);
00284 switch(oid) {
00285
00286 case SEC_OID_PKCS1_RSA_ENCRYPTION:
00287 case SEC_OID_ANSIX9_DSA_SIGNATURE:
00288 case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
00289 return true;
00290 break;
00291 default:
00292 return false;
00293 break;
00294 }
00295
00296 }
00297 else
00298 {
00299 RAISE_CRYPTO_EXCEPTION("key parameter contents not recognized.", thisComponent, COMMON_INVALID_INPUT, this);
00300 }
00301 return false;
00302 }
00313 void CPKIFNSSRaw::Sign(
00315 const CPKIFKeyMaterial& key,
00317 unsigned char* pHashData,
00319 int nHashDataLen,
00321 unsigned char* pSignature,
00324 int* nSignatureLen,
00326 PKIFCRYPTO::HASH_ALG hashAlg
00327 )
00328 {
00329 LOG_STRING_DEBUG("CPKIFNSSRaw::Sign(const CPKIFKeyMaterial& key,...)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00330
00331 RAISE_CRYPTO_EXCEPTION("Signing operations are not implemented for raw key material.", thisComponent, COMMON_NOT_IMPLEMENTED, this);
00332 }
00333
00341 void CPKIFNSSRaw::Decrypt(
00343 const CPKIFKeyMaterial& key,
00345 unsigned char* pData,
00347 int nDataLen,
00349 unsigned char* pResult,
00352 int* pnResultLen,
00356 bool pad)
00357 {
00358 if(key.ContainsSymmetricKeyMaterial()) {
00359 CPKIFNSSRawCryptContext * ctx = static_cast<CPKIFNSSRawCryptContext *>(this->CryptInit(key,pad));
00360 try {
00361 Decrypt(ctx,pData,nDataLen,pResult,pnResultLen,true);
00362 } catch(...) {
00363 delete ctx;
00364 throw;
00365 }
00366 delete ctx;
00367 } else {
00368 _ASymCrypt<false>(key, pData, nDataLen, pResult, pnResultLen, pad);
00369 }
00370 }
00378 void CPKIFNSSRaw::Encrypt(
00380 const CPKIFKeyMaterial& key,
00382 unsigned char* pData,
00384 int nDataLen,
00386 unsigned char* pResult,
00389 int* pnResultLen,
00393 bool pad)
00394 {
00395 if(key.ContainsSymmetricKeyMaterial()) {
00396 CPKIFNSSRawCryptContext * ctx = static_cast<CPKIFNSSRawCryptContext *>(this->CryptInit(key,pad));
00397 try {
00398 Encrypt(ctx,pData,nDataLen,pResult,pnResultLen,true);
00399 } catch(...) {
00400 delete ctx;
00401 throw;
00402 }
00403 delete ctx;
00404 } else {
00405 _ASymCrypt<true>(key, pData, nDataLen, pResult, pnResultLen, pad);
00406 }
00407 }
00408
00426 IPKIFRawCryptContext* CPKIFNSSRaw::HMACInit(const CPKIFKeyMaterial &key, PKIFCRYPTO::HASH_ALG ha)
00427 {
00428 LOG_STRING_DEBUG("CPKIFNSSRaw::HMACInit(const CPKIFKeyMaterial& key, HASH_ALG ha)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00429
00430 if(!key.ContainsSymmetricKeyMaterial())
00431 {
00432 throw CPKIFCryptoException(TOOLKIT_CRYPTO_NSSRAW, COMMON_INVALID_INPUT, "HMACInit() only makes sense for symmetric keys.");
00433 }
00434
00435
00436 CK_MECHANISM_TYPE hash_mech = CKM_VENDOR_DEFINED;
00437 switch(ha)
00438 {
00439 case PKIFCRYPTO::SHA1:
00440 hash_mech = CKM_SHA_1_HMAC;
00441 break;
00442 #ifndef FIPS_MODE
00443 case PKIFCRYPTO::MD5:
00444 hash_mech = CKM_MD5_HMAC;
00445 break;
00446 #endif
00447 case PKIFCRYPTO::SHA256:
00448 hash_mech = CKM_SHA256_HMAC;
00449 break;
00450 case PKIFCRYPTO::SHA384:
00451 hash_mech = CKM_SHA384_HMAC;
00452 break;
00453 case PKIFCRYPTO::SHA512:
00454 hash_mech = CKM_SHA512_HMAC;
00455 break;
00456 default:
00457 std::ostringstream os;
00458 os << "Unsupported hash algorithm encountered: " << ha;
00459 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00460 }
00461
00462
00463 CPKIFNSSRawCryptContext * ctx = new CPKIFNSSRawCryptContext();
00464
00465
00466 ctx->m_mech = hash_mech;
00467
00468 ctx->m_slot = PK11_GetBestSlot(ctx->m_mech,NULL);
00469 if(0 == ctx->m_slot)
00470 {
00471 delete ctx;
00472
00473 RAISE_CRYPTO_EXCEPTION("No NSS slot supports this algorithm",TOOLKIT_CRYPTO_NSSRAW,PKIF_NSS_UNSUPPORTED_ALG,NULL);
00474 }
00475
00476 SECItem keyItem;
00477 keyItem.data = const_cast<unsigned char *>(key.GetSymmetricKey());
00478 keyItem.len = key.GetSymmetricKeyLength();
00479 keyItem.type = siBuffer;
00480
00481
00482 ctx->m_sk = PK11_ImportSymKey(ctx->m_slot,ctx->m_mech,PK11_OriginUnwrap,CKA_SIGN, &keyItem, NULL);
00483
00484 if( 0 == ctx->m_sk )
00485 {
00486 delete ctx;
00487 RAISE_CRYPTO_EXCEPTION("Unable to import raw symmetric key",TOOLKIT_CRYPTO_NSSRAW,PKIF_NSS_RAW_IMPORT_FAILED,NULL);
00488 }
00489
00490
00491 ctx->m_param = 0;
00492 SECItem noParams;
00493 noParams.data = 0;
00494 noParams.len = 0;
00495 noParams.type = siBuffer;
00496 ctx->m_bNeedsPad = false;
00497
00498 ctx->m_ctx = PK11_CreateContextBySymKey(hash_mech,CKA_SIGN,ctx->m_sk,&noParams);
00499 if(!ctx->m_ctx)
00500 {
00501 delete ctx;
00502 RAISE_CRYPTO_EXCEPTION("Unable to use raw symmetric key to create HMAC context",TOOLKIT_CRYPTO_NSSRAW,PKIF_NSS_RAW_IMPORT_FAILED,0);
00503 }
00504 SECStatus rv = PK11_DigestBegin(ctx->m_ctx);
00505 if(SECSuccess != rv) {
00506 delete ctx;
00507 RAISE_CRYPTO_EXCEPTION("Unable to use raw symmetric key to create HMAC context",TOOLKIT_CRYPTO_NSSRAW,PKIF_NSS_RAW_IMPORT_FAILED,0);
00508 }
00509
00510
00511 return ctx;
00512 }
00513
00526 void CPKIFNSSRaw::HMACUpdate(IPKIFRawCryptContext* ctx, unsigned char* pData, int nDataLen)
00527 {
00528 LOG_STRING_DEBUG("CPKIFNSSRaw::HMACUpdate(IPKIFRawCryptContext* ctx, unsigned char* pData, int nDataLen)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00529
00530
00531
00532
00533 if(NULL == ctx || 0 > nDataLen)
00534 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HMACUpdate.");
00535
00536
00537
00538 CPKIFNSSRawCryptContext* hmacCtx = dynamic_cast<CPKIFNSSRawCryptContext*>(ctx);
00539 if(NULL == hmacCtx)
00540 throw CPKIFCryptoException(thisComponent, PKIFNSS_INCORRECT_HASH_CONTEXT, "Incorrect context passed to HMACUpdate.");
00541
00542 if(NULL == hmacCtx->m_ctx)
00543 throw CPKIFCryptoException(thisComponent, PKIFNSS_EMPTY_HASH_CONTEXT, "Empty context passed to HMACUpdate.");
00544 SECStatus rv = PK11_DigestOp(hmacCtx->m_ctx,pData,nDataLen);
00545 if(SECSuccess != rv)
00546 {
00547 std::ostringstream os;
00548 os << "PK11_DigestOp failed: ";
00549 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFNSS_DIGEST_OP_FAILED, NULL);
00550 }
00551 }
00552
00565 void CPKIFNSSRaw::HMACFinal(IPKIFRawCryptContext* ctx, unsigned char* pResult, int* pnResultLen)
00566 {
00567 LOG_STRING_DEBUG("CPKIFNSSRaw::HMACFinal(IPKIFRawCryptContext* ctx, unsigned char* pResult, int* pnResultLen)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00568
00569
00570
00571
00572
00573 if(NULL == ctx || NULL == pResult || NULL == pnResultLen || 0 >= *pnResultLen)
00574 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HMACFinal.");
00575
00576 CPKIFNSSRawCryptContext* hmacCtx = dynamic_cast<CPKIFNSSRawCryptContext*>(ctx);
00577 if(NULL == hmacCtx)
00578 throw CPKIFCryptoException(thisComponent, PKIFNSS_INCORRECT_HASH_CONTEXT, "Incorrect context passed to HMACFinal().");
00579
00580 if(NULL == hmacCtx->m_ctx)
00581 throw CPKIFCryptoException(thisComponent, PKIFNSS_EMPTY_HASH_CONTEXT, "Empty context passed to HMACFinal().");
00582
00583
00584 unsigned int outLen = 0;
00585 SECStatus rv = PK11_DigestFinal(hmacCtx->m_ctx,pResult,&outLen,*pnResultLen);
00586 if(SECSuccess != rv)
00587 {
00588 std::ostringstream os;
00589 os << "PK11_DigestFinal failed: ";
00590 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFNSS_DIGEST_OP_FAILED, NULL);
00591 }
00592
00593 *pnResultLen = (int)outLen;
00594
00595 }
00596
00597
00608 static bool _Verify(
00610 const CPKIFKeyMaterial& key,
00613 unsigned char* pHashData,
00615 int nHashDataLen,
00617 unsigned char* pSignature,
00619 int nSignatureLen,
00621 PKIFCRYPTO::HASH_ALG hashAlg)
00622 {
00623 #undef CLEANUP
00624 #define CLEANUP \
00625 { \
00626 if (pk) \
00627 { SECKEY_DestroyPublicKey(pk); pk = 0; } \
00628 }
00629
00630 LOG_STRING_DEBUG("_Verify(const CPKIFKeyMaterial& key, unsigned char* pHashData, int nHashDataLen, unsigned char* pSignature, int nSignatureLen)", TOOLKIT_CRYPTO_NSSRAW, 0, NULL);
00631 if(!key.ContainsCertificate()) {
00632 RAISE_CRYPTO_EXCEPTION("CPKIFNSSRaw _Verify called without a certificate.", TOOLKIT_CRYPTO_NSSRAW, COMMON_INVALID_INPUT, NULL);
00633 }
00634
00635
00636 CERTCertificate ** cert = 0;
00637
00638 SECKEYPublicKey * pk = 0;
00639
00640
00641 CPKIFCryptoPPKeyMaterialPtr cppkm(new CPKIFCryptoPPKeyMaterial(key));
00642 CPKIFBufferPtr derKeyBuf = cppkm->GetRawSPKI();
00643 if(!derKeyBuf) {
00644 CLEANUP;
00645 RAISE_CRYPTO_EXCEPTION("Unable to get SubjectPublicKeyInfo from key material.",
00646 TOOLKIT_CRYPTO_NSSRAW, PKIFNSS_CERT_IMPORT_FAILED, NULL);
00647 }
00648 SECItem derKey;
00649 memset(&derKey,0x00,sizeof(SECItem));
00650 derKey.type = siBuffer;
00651 derKey.data = const_cast< unsigned char *>(derKeyBuf->GetBuffer());
00652 derKey.len = derKeyBuf->GetLength();
00653
00654 CERTSubjectPublicKeyInfo * nssSPKI = SECKEY_DecodeDERSubjectPublicKeyInfo(&derKey);
00655 if(!nssSPKI) {
00656 CLEANUP;
00657 RAISE_CRYPTO_EXCEPTION("Unable to get SubjectPublicKeyInfo from key material.",
00658 TOOLKIT_CRYPTO_NSSRAW, PKIFNSS_CERT_IMPORT_FAILED, NULL);
00659 }
00660 pk = SECKEY_ExtractPublicKey(nssSPKI);
00661 SECKEY_DestroySubjectPublicKeyInfo(nssSPKI);
00662
00663
00664 if(!pk) {
00665 CLEANUP;
00666 RAISE_CRYPTO_EXCEPTION("CERT_ExtractPublicKey failed", TOOLKIT_CRYPTO_NSSRAW, PKIFNSS_CERT_IMPORT_FAILED, NULL);
00667 }
00668
00669
00670 SECItem hash, sig;
00671 hash.data = pHashData;
00672 hash.len = nHashDataLen;
00673 hash.type = siBuffer;
00674 sig.data = pSignature;
00675 sig.len = nSignatureLen;
00676 sig.type = siBuffer;
00677
00678
00679
00680
00681 #if 0
00682 SECItem * decodedSig = 0;
00683
00684 if(PKIFCRYPTO::DSS == cppkm->GetKeyAlg()->AsymkeyAlg())
00685 {
00686 decodedSig = DSAU_DecodeDerSig(&sig);
00687 if(decodedSig) {
00688 sig.len = decodedSig->len;
00689 sig.type = decodedSig->type;
00690 sig.data = decodedSig->data;
00691 } else {
00692 CLEANUP;
00693
00694 return false;
00695 }
00696 }
00697 #endif
00698
00699
00700
00701
00702
00703
00704
00705
00706 SECOidTag sigAlg = NSSSigAlg(cppkm->GetKeyAlg()->AsymkeyAlg(),hashAlg);
00707 SECStatus rv = VFY_VerifyDigest(&hash,pk,&sig,sigAlg,0);
00708
00709
00710
00711 bool sigOK = (rv == SECSuccess);
00712
00713 CLEANUP;
00714 return sigOK;
00715 }
00724 bool CPKIFNSSRaw::VerifyCertificate(
00727 const CPKIFCertificate& issCert,
00730 const CPKIFCertificate& subCert)
00731 {
00732 #undef CLEANUP
00733 #define CLEANUP \
00734 { \
00735 if (cert && cert[1] ) \
00736 { CERT_DestroyCertificate(cert[1]); cert[1] = 0; } \
00737 if (cert && cert[0]) \
00738 { CERT_DestroyCertificate(cert[0]); cert[0] = 0; } \
00739 if (cert) \
00740 { PR_Free(cert); cert = 0; } \
00741 }
00742 LOG_STRING_DEBUG("CPKIFNSSRaw::VerifyCertificate(const CPKIFCertificate& issCert, const CPKIFCertificate& subCert)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00743 CPKIFBufferPtr issDer = issCert.Encoded();
00744 CPKIFBufferPtr subDer = subCert.Encoded();
00745 SECItem issDerSi;
00746 issDerSi.data = const_cast<unsigned char *>(issDer->GetBuffer());
00747 issDerSi.len = issDer->GetLength();
00748 issDerSi.type = siBuffer;
00749 SECItem subDerSi;
00750 subDerSi.data = const_cast<unsigned char *>(subDer->GetBuffer());
00751 subDerSi.len = subDer->GetLength();
00752 subDerSi.type = siBuffer;
00753 SECItem * encCerts[2] = {&issDerSi,&subDerSi};
00754 CERTCertificate ** cert = 0;
00755
00756 SECStatus rv = CERT_ImportCerts(CERT_GetDefaultCertDB(),certUsageUserCertImport,
00757 2,encCerts,&cert,PR_FALSE,PR_FALSE,NULL);
00758
00759 if(rv != SECSuccess || !cert || !cert[0] || !cert[1])
00760 {
00761 CLEANUP;
00762 std::ostringstream os;
00763 os << "CERT_ImportCerts failed: ";
00764 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO_NSSRAW, PKIFNSS_CERT_IMPORT_FAILED, NULL)
00765 }
00766
00767 CERTCertificate * sub = cert[1];
00768 CERTCertificate * iss = cert[0];
00769
00770
00771
00772 rv = CERT_VerifySignedDataWithPublicKeyInfo(&sub->signatureWrap,&iss->subjectPublicKeyInfo,NULL);
00773 CLEANUP;
00774 return rv == SECSuccess;
00775
00776 }
00777
00778
00788 bool CPKIFNSSRaw::Verify(
00790 const CPKIFKeyMaterial& key,
00792 unsigned char* pHashData,
00794 int nHashDataLen,
00796 unsigned char* pSignature,
00798 int nSignatureLen,
00800 PKIFCRYPTO::HASH_ALG hashAlg
00801 )
00802 {
00803
00804 return _Verify(key, pHashData, nHashDataLen, pSignature, nSignatureLen, hashAlg);
00805 }
00816 void CPKIFNSSRaw::GenRandom(
00818 unsigned char* buf,
00820 int len)
00821 {
00822
00823
00824
00825
00826 LOG_STRING_DEBUG("CPKIFNSSRaw::GenRandom(unsigned char* buf, int len)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00827
00828 if(NULL == buf || 0 == len)
00829 return;
00830
00831 SECStatus rv = PK11_GenerateRandom(buf,len);
00832 if(SECSuccess != rv) {
00833 RAISE_CRYPTO_EXCEPTION("PK11_GenerateRandom() failed", thisComponent, PKIFNSS_RNG_FAILED, this);
00834 }
00835 }
00849 IPKIFHashContext* CPKIFNSSRaw::HashInit(
00852 PKIFCRYPTO::HASH_ALG alg)
00853 {
00854 LOG_STRING_DEBUG("CPKIFNSSRaw::HashInit(HASH_ALG alg)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00855
00856
00857 SECOidTag hashAlg;
00858 switch(alg)
00859 {
00860 case PKIFCRYPTO::SHA1:
00861 hashAlg = SEC_OID_SHA1;
00862 break;
00863 #ifndef FIPS_MODE
00864 case PKIFCRYPTO::MD5:
00865 hashAlg = SEC_OID_MD5;
00866 break;
00867 #endif
00868 case PKIFCRYPTO::SHA256:
00869 hashAlg = SEC_OID_SHA256;
00870 break;
00871 case PKIFCRYPTO::SHA384:
00872 hashAlg = SEC_OID_SHA384;
00873 break;
00874 case PKIFCRYPTO::SHA512:
00875 hashAlg = SEC_OID_SHA512;
00876 break;
00877 default:
00878 std::ostringstream os;
00879 os << "Unsupported hash algorithm encountered: " << alg;
00880 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00881 }
00882
00883
00884
00885 CPKIFNSSHashContext* hashCtx = new CPKIFNSSHashContext();
00886 hashCtx->m_hashContext = PK11_CreateDigestContext(hashAlg);
00887 if(!hashCtx->m_hashContext)
00888 {
00889 delete hashCtx;
00890
00891 std::ostringstream os;
00892 os << "PK11_CreateDigestContext failed: ";
00893 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFNSS_CREATE_DIGEST_CONTEXT_FAILED, NULL);
00894 }
00895 SECStatus rv = PK11_DigestBegin(hashCtx->m_hashContext);
00896 if(SECSuccess != rv)
00897 {
00898 delete hashCtx;
00899
00900 std::ostringstream os;
00901 os << "PK11_DigestBegin failed: ";
00902 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFNSS_DIGEST_BEGIN_FAILED, NULL);
00903 }
00904
00905 return hashCtx;
00906 }
00919 void CPKIFNSSRaw::HashUpdate(
00921 IPKIFHashContext* hash,
00923 unsigned char* pData,
00925 int nDataLen)
00926 {
00927 LOG_STRING_DEBUG("CPKIFNSSRaw::HashUpdate(IPKIFHashContext* hash, unsigned char* pData, int nDataLen)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00928
00929
00930
00931
00932 if(NULL == hash || 0 > nDataLen)
00933 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HashUpdate.");
00934
00935
00936
00937 CPKIFNSSHashContext* hashCtx = dynamic_cast<CPKIFNSSHashContext*>(hash);
00938 if(NULL == hashCtx)
00939 throw CPKIFCryptoException(thisComponent, PKIFNSS_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HashUpdate.");
00940
00941 if(NULL == hashCtx->m_hashContext)
00942 throw CPKIFCryptoException(thisComponent, PKIFNSS_EMPTY_HASH_CONTEXT, "Empty hash context passed to HashUpdate.");
00943 SECStatus rv = PK11_DigestOp(hashCtx->m_hashContext,pData,nDataLen);
00944 if(SECSuccess != rv)
00945 {
00946 std::ostringstream os;
00947 os << "PK11_DigestOp failed: ";
00948 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFNSS_DIGEST_OP_FAILED, NULL);
00949 }
00950 }
00964 void CPKIFNSSRaw::HashFinal(
00966 IPKIFHashContext* hash,
00968 unsigned char* pResult,
00971 int* pnResultLen)
00972 {
00973 LOG_STRING_DEBUG("CPKIFNSSRaw::HashFinal(IPKIFHashContext* hash, unsigned char* pResult, int* pnResultLen)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
00974
00975
00976
00977
00978
00979 if(NULL == hash || NULL == pResult || NULL == pnResultLen || 0 >= *pnResultLen)
00980 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HashFinal.");
00981
00982 CPKIFNSSHashContext* hashCtx = dynamic_cast<CPKIFNSSHashContext*>(hash);
00983 if(NULL == hashCtx)
00984 throw CPKIFCryptoException(thisComponent, PKIFNSS_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HashFinal.");
00985
00986 if(NULL == hashCtx->m_hashContext)
00987 throw CPKIFCryptoException(thisComponent, PKIFNSS_EMPTY_HASH_CONTEXT, "Empty hash context passed to HashUpdate.");
00988
00989
00990 unsigned int outLen = 0;
00991 SECStatus rv = PK11_DigestFinal(hashCtx->m_hashContext,pResult,&outLen,*pnResultLen);
00992 if(SECSuccess != rv)
00993 {
00994 std::ostringstream os;
00995 os << "PK11_DigestFinal failed: ";
00996 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFNSS_DIGEST_OP_FAILED, NULL);
00997 }
00998
00999 *pnResultLen = (int)outLen;
01000
01001 }
01019 IPKIFRawCryptContext* CPKIFNSSRaw::CryptInit(
01022 const CPKIFKeyMaterial& key,
01024 bool pad)
01025 {
01026 LOG_STRING_DEBUG("CPKIFNSSRaw::CryptInit(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_NSSRAW, 0, this);
01027
01028
01029 if(!key.ContainsSymmetricKeyMaterial())
01030 {
01031 throw CPKIFCryptoException(TOOLKIT_CRYPTO_NSSRAW, COMMON_INVALID_INPUT, "CryptInit() only makes sense for symmetric keys.");
01032 }
01033
01034
01035 CPKIFNSSRawCryptContext * ctx = new CPKIFNSSRawCryptContext();
01036
01037 ctx->m_mech = CipherMechForKey(key,pad);
01038
01039 if(key.GetMode() == PKIFCRYPTO::CBC && NULL == key.GetIV())
01040 {
01041 delete ctx;
01042 throw CPKIFCryptoException(TOOLKIT_CRYPTO_NSSRAW, CRYPTO_MISSING_IV);
01043 }
01044
01045 ctx->m_slot = PK11_GetBestSlot(ctx->m_mech,NULL);
01046 if(0 == ctx->m_slot)
01047 {
01048 delete ctx;
01049
01050 RAISE_CRYPTO_EXCEPTION("No NSS slot supports this algorithm",TOOLKIT_CRYPTO_NSSRAW,PKIF_NSS_UNSUPPORTED_ALG,NULL);
01051 }
01052
01053 SECItem keyItem, ivItem;
01054 keyItem.data = const_cast<unsigned char *>(key.GetSymmetricKey());
01055 keyItem.len = key.GetSymmetricKeyLength();
01056 keyItem.type = siBuffer;
01057 ivItem.data = const_cast<unsigned char *>(key.GetIV());
01058 ivItem.len = PK11_GetIVLength(ctx->m_mech);
01059 ivItem.type = siBuffer;
01060
01061
01062 ctx->m_sk = PK11_ImportSymKey(ctx->m_slot,ctx->m_mech,PK11_OriginUnwrap,CKA_ENCRYPT, &keyItem, NULL);
01063
01064 if( 0 == ctx->m_sk )
01065 {
01066 delete ctx;
01067 RAISE_CRYPTO_EXCEPTION("Unable to import raw symmetric key",TOOLKIT_CRYPTO_NSSRAW,PKIF_NSS_RAW_IMPORT_FAILED,NULL);
01068 }
01069
01070
01071 ctx->m_param = PK11_ParamFromIV(ctx->m_mech,&ivItem);
01072 if( 0 == ctx->m_param )
01073 {
01074 delete ctx;
01075 RAISE_CRYPTO_EXCEPTION("Unable to import IV into NSS",TOOLKIT_CRYPTO_NSSRAW,PKIF_NSS_IV_IMPORT_FAILED,NULL);
01076 }
01077 if(key.GetMode() == PKIFCRYPTO::ECB)
01078 {
01079
01080 ctx->m_bNeedsPad = pad;
01081 if(pad)
01082 {
01083 ctx->m_blocksize = PK11_GetBlockSize(ctx->m_mech,ctx->m_param);
01084 ctx->m_padbuf = new unsigned char[ctx->m_blocksize];
01085 memset(ctx->m_padbuf,0x00,ctx->m_blocksize);
01086 }
01087
01088 }
01089 return ctx;
01090 }
01099 void CPKIFNSSRaw::Decrypt(
01102 IPKIFRawCryptContext* cryptContext,
01104 unsigned char* pData,
01106 int nDataLen,
01108 unsigned char* pResult,
01111 int* pnResultLen,
01114 bool final)
01115 {
01116 CryptFunc<false>(cryptContext, pData, nDataLen, pResult, pnResultLen, final);
01117 }
01126 void CPKIFNSSRaw::Encrypt(
01129 IPKIFRawCryptContext* cryptContext,
01131 unsigned char* pData,
01133 int nDataLen,
01135 unsigned char* pResult,
01138 int* pnResultLen,
01141 bool final)
01142 {
01143 CryptFunc<true>(cryptContext, pData, nDataLen, pResult, pnResultLen, final);
01144 }
01156 template <bool _CryptDirection>
01157 void CPKIFNSSRaw::CryptFunc(
01160 IPKIFRawCryptContext* cryptContext,
01162 unsigned char* pData,
01164 int nDataLen,
01166 unsigned char* pResult,
01168 int* pnResultLen,
01171 bool final)
01172 {
01173 LOG_STRING_DEBUG("CPKIFNSSRaw CryptFunc(IPKIFRawCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)", TOOLKIT_CRYPTO_NSSRAW, 0, NULL);
01174
01175 CPKIFNSSRawCryptContext* icc = dynamic_cast<CPKIFNSSRawCryptContext*>(cryptContext);
01176 if(!icc || !icc->m_param || !icc->m_slot || !icc->m_sk)
01177 {
01178 RAISE_CRYPTO_EXCEPTION("CPKIFNSSRaw CryptFunc called with an invalid context.", TOOLKIT_CRYPTO_NSSRAW, COMMON_INVALID_INPUT, NULL);
01179 }
01180
01181
01182 if(!icc->m_ctx)
01183 {
01184 icc->m_ctx = PK11_CreateContextBySymKey(icc->m_mech, _CryptDirection ? CKA_ENCRYPT:CKA_DECRYPT,
01185 icc->m_sk,icc->m_param);
01186 if(0 == icc->m_ctx)
01187 {
01188 RAISE_CRYPTO_EXCEPTION("Unable to establish symmetric key cipher context",TOOLKIT_CRYPTO_NSSRAW,PKIFNSS_CREATE_SK_CONTEXT_FAILED,NULL);
01189 }
01190 }
01191
01192 int maxOut = *pnResultLen;
01193 int inLen = nDataLen;
01194 unsigned char * start = pData;
01195 unsigned char * outBuf = pResult;
01196
01197 int updateLen = 0;
01198 int padUpdateLen = 0;
01199 *pnResultLen = 0;
01200 unsigned int finalLen = 0;
01201 SECStatus rv = SECSuccess;
01202
01203 if(_CryptDirection && start && icc->m_bNeedsPad)
01204 {
01205
01206 if(icc->m_padlen > 0)
01207 {
01208 for(int i = icc->m_padlen; inLen != 0 && i < icc->m_blocksize; i++)
01209 {
01210 icc->m_padbuf[i] = *start++;
01211 inLen--;
01212 icc->m_padlen++;
01213 }
01214
01215 if(icc->m_padlen == icc->m_blocksize)
01216 {
01217 rv = PK11_CipherOp(icc->m_ctx,outBuf,&padUpdateLen,maxOut,icc->m_padbuf,icc->m_padlen);
01218 if(SECSuccess != rv)
01219 {
01220 RAISE_CRYPTO_EXCEPTION("Unable to perform cipher operation",TOOLKIT_CRYPTO_NSSRAW,PKIFNSS_CIPHER_OP_FAILED,NULL);
01221 }
01222 outBuf += padUpdateLen;
01223 maxOut -= padUpdateLen;
01224 icc->m_padlen = 0;
01225 *pnResultLen += padUpdateLen;
01226 }
01227
01228 }
01229
01230 if(icc->m_padlen == 0) {
01231 icc->m_padlen = inLen % icc->m_blocksize;
01232 if(icc->m_padlen > 0) {
01233 memcpy(icc->m_padbuf,&start[inLen - icc->m_padlen],icc->m_padlen);
01234 inLen -= icc->m_padlen;
01235 }
01236 }
01237 }
01238
01239
01240 if(start && inLen > 0)
01241 {
01242 rv = PK11_CipherOp(icc->m_ctx,outBuf,&updateLen,maxOut,start,inLen);
01243 if(SECSuccess != rv)
01244 {
01245 RAISE_CRYPTO_EXCEPTION("Unable to perform cipher operation",TOOLKIT_CRYPTO_NSSRAW,PKIFNSS_CIPHER_OP_FAILED,NULL);
01246 }
01247 maxOut -= updateLen;
01248 outBuf += updateLen;
01249 *pnResultLen += updateLen;
01250 }
01251 if(final) {
01252 if(_CryptDirection && icc->m_bNeedsPad)
01253 {
01254
01255 unsigned char padbyte = (unsigned char) icc->m_blocksize - icc->m_padlen;
01256 for(int i = icc->m_padlen; i < icc->m_blocksize; i++)
01257 {
01258 icc->m_padbuf[i] = padbyte;
01259 }
01260 rv = PK11_CipherOp(icc->m_ctx,outBuf,&padUpdateLen,maxOut,icc->m_padbuf,icc->m_blocksize);
01261 if(SECSuccess != rv)
01262 {
01263 RAISE_CRYPTO_EXCEPTION("Unable to perform cipher operation",TOOLKIT_CRYPTO_NSSRAW,PKIFNSS_CIPHER_OP_FAILED,NULL);
01264 }
01265 outBuf += padUpdateLen;
01266 maxOut -= padUpdateLen;
01267 icc->m_padlen = 0;
01268 *pnResultLen += padUpdateLen;
01269 }
01270
01271
01272 rv = PK11_DigestFinal(icc->m_ctx,outBuf,&finalLen,maxOut);
01273 if(SECSuccess != rv)
01274 {
01275 RAISE_CRYPTO_EXCEPTION("Unable to finalize cipher operation",TOOLKIT_CRYPTO_NSSRAW,PKIFNSS_CIPHER_OP_FAILED,NULL);
01276 }
01277 if(finalLen != 0 && !_CryptDirection && icc->m_bNeedsPad)
01278 {
01279 int padCount = (int)outBuf[finalLen-1];
01280 finalLen -= padCount;
01281 }
01282 }
01283 *pnResultLen += finalLen;
01284 if(*pnResultLen != 0 && !_CryptDirection && icc->m_bNeedsPad)
01285 {
01286 int padCount = (int)pResult[*pnResultLen-1];
01287 *pnResultLen -= padCount;
01288 }
01289 }
01290
01302 template<bool _CryptDirection>
01303 void _ASymCrypt(
01305 const CPKIFKeyMaterial& key,
01307 unsigned char* pData,
01309 int nDataLen,
01311 unsigned char* pResult,
01313 int* pnResultLen,
01315 bool pad)
01316 {
01317 if(! _CryptDirection) {
01318 throw CPKIFCryptoException(TOOLKIT_CRYPTO_NSSRAW, COMMON_INVALID_INPUT, "Only encryption is supported for raw public keys.");
01319 }
01320 #undef CLEANUP
01321 #define CLEANUP \
01322 { \
01323 if (cert && cert[0]) \
01324 { CERT_DestroyCertificate(cert[0]); cert[0] = 0; } \
01325 if (cert) \
01326 { PR_Free(cert); cert = 0; } \
01327 if (pk) \
01328 { SECKEY_DestroyPublicKey(pk); pk = 0; } \
01329 }
01330
01331 LOG_STRING_DEBUG("_ASymCrypt(const CPKIFKeyMaterial& key, unsigned char* pHashData, int nHashDataLen, unsigned char* pSignature, int nSignatureLen)", TOOLKIT_CRYPTO_NSSRAW, 0, NULL);
01332 if(!key.ContainsCertificate()) {
01333 RAISE_CRYPTO_EXCEPTION("CPKIFNSSRaw _ASymCrypt called without a certificate.", TOOLKIT_CRYPTO_NSSRAW, COMMON_INVALID_INPUT, NULL);
01334 }
01335 SECItem encCert;
01336
01337 encCert.data = const_cast< unsigned char *>(key.GetCertificate());
01338 encCert.len = key.GetCertificateLength();
01339 encCert.type = siBuffer;
01340 SECItem * encCerts[1];
01341 encCerts[0] = &encCert;
01342
01343
01344 CERTCertificate ** cert = 0;
01345
01346 SECKEYPublicKey * pk = 0;
01347
01348
01349 SECStatus rv = CERT_ImportCerts(CERT_GetDefaultCertDB(),certUsageUserCertImport,
01350 1,encCerts,&cert,PR_FALSE,PR_FALSE,NULL);
01351
01352 if(rv != SECSuccess || !cert || !cert[0])
01353 {
01354 CLEANUP;
01355 std::ostringstream os;
01356 os << "CERT_ImportCerts failed: ";
01357 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO_NSSRAW, PKIFNSS_CERT_IMPORT_FAILED, NULL)
01358 }
01359
01360 pk = CERT_ExtractPublicKey(cert[0]);
01361 if(!pk) {
01362 CLEANUP;
01363 RAISE_CRYPTO_EXCEPTION("CERT_ExtractPublicKey failed", TOOLKIT_CRYPTO_NSSRAW, PKIFNSS_CERT_IMPORT_FAILED, NULL);
01364 }
01365
01366 if(pad) {
01367 rv = PK11_PubEncryptPKCS1(pk,pResult,pData,nDataLen,NULL);
01368 }else {
01369 rv = PK11_PubEncryptRaw(pk,pResult,pData,nDataLen,NULL);
01370 }
01371 *pnResultLen = SECKEY_PublicKeyStrength(pk);
01372 if(rv != SECSuccess)
01373 {
01374 CLEANUP;
01375 std::ostringstream os;
01376 os << "PK11_PubEncrypt failed: ";
01377 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO_NSSRAW, PKIFNSS_PUB_ENCRYPT_FAILED, NULL);
01378 }
01379
01380 CLEANUP;
01381 }