CryptoX_Result NSS_VerifyBegin(VFYContext **ctx, SECKEYPublicKey * const *publicKey) { SECStatus status; if (!ctx || !publicKey || !*publicKey) { return CryptoX_Error; } /* Check that the key length is large enough for our requirements */ if ((SECKEY_PublicKeyStrength(*publicKey) * 8) < XP_MIN_SIGNATURE_LEN_IN_BYTES) { fprintf(stderr, "ERROR: Key length must be >= %d bytes\n", XP_MIN_SIGNATURE_LEN_IN_BYTES); return CryptoX_Error; } *ctx = VFY_CreateContext(*publicKey, NULL, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL); if (*ctx == NULL) { return CryptoX_Error; } status = VFY_Begin(*ctx); return SECSuccess == status ? CryptoX_Success : CryptoX_Error; }
unsigned int NSSCryptoKeyRSA::getLength(void) const { unsigned int ret = 0; if (mp_pubkey != 0) { ret = SECKEY_PublicKeyStrength(mp_pubkey); } else if (mp_privkey != 0) { ret = PK11_GetPrivateModulusLen(mp_privkey); } return ret; }
SECStatus NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp, SECKEYPublicKey *publickey, PK11SymKey *bulkkey, SECItem *encKey) { SECStatus rv; int data_len; KeyType keyType; void *mark = NULL; mark = PORT_ArenaMark(poolp); if (!mark) goto loser; /* sanity check */ keyType = SECKEY_GetPublicKeyType(publickey); PORT_Assert(keyType == rsaKey); if (keyType != rsaKey) { goto loser; } /* allocate memory for the encrypted key */ data_len = SECKEY_PublicKeyStrength(publickey); /* block size (assumed to be > keylen) */ encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len); encKey->len = data_len; if (encKey->data == NULL) goto loser; /* encrypt the key now */ rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(SEC_OID_PKCS1_RSA_ENCRYPTION), publickey, bulkkey, encKey); if (rv != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: if (mark) { PORT_ArenaRelease(poolp, mark); } return SECFailure; }
int crypto_cert_get_pub_exp_mod(CryptoCert cert, uint32 * key_len, uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len) { SECKEYPublicKey * pubkey; SECOidTag tag = SECOID_GetAlgorithmTag(&cert->cert->subjectPublicKeyInfo.algorithm); if ((tag == SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION) || (tag == SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE)) { /* For some reason, Microsoft sets the OID of the Public RSA key to the oid for "MD5 with RSA Encryption" instead of "RSA Encryption". */ SECAlgorithmID org = cert->cert->subjectPublicKeyInfo.algorithm; SECStatus s = SECOID_SetAlgorithmID(cert->cert->subjectPublicKeyInfo.arena, &cert->cert->subjectPublicKeyInfo.algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); check(s, "Error setting temp algo oid"); pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo); SECOID_DestroyAlgorithmID(&cert->cert->subjectPublicKeyInfo.algorithm, False); cert->cert->subjectPublicKeyInfo.algorithm = org; } else { pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo); } ASSERT(pubkey); ASSERT(pubkey->keyType == rsaKey); *key_len = SECKEY_PublicKeyStrength(pubkey); size_t l = pubkey->u.rsa.publicExponent.len; ASSERT(l <= exp_len); memset(exponent, 0, exp_len - l); memcpy(exponent + exp_len - l, pubkey->u.rsa.publicExponent.data, l); l = pubkey->u.rsa.modulus.len; ASSERT(l <= mod_len); ASSERT(*key_len <= mod_len); memset(modulus, 0, *key_len - l); memcpy(modulus + *key_len - l, pubkey->u.rsa.modulus.data, l); SECKEY_DestroyPublicKey(pubkey); return 0; }
static long smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts) { PLArenaPool *poolp; long chosen_cipher; int *cipher_abilities; int *cipher_votes; int strong_mapi; int rcount, mapi, max; if (smime_policy_bits == 0) { PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); return -1; } chosen_cipher = SMIME_RC2_CBC_40; /* the default, LCD */ poolp = PORT_NewArena(1024); /* XXX what is right value? */ if (poolp == NULL) goto done; cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_symmetric_count * sizeof(int)); if (cipher_abilities == NULL) goto done; cipher_votes = (int *)PORT_ArenaZAlloc(poolp, smime_symmetric_count * sizeof(int)); if (cipher_votes == NULL) goto done; /* * XXX Should have a #define somewhere which specifies default * strong cipher. (Or better, a way to configure.) */ /* Make triple-DES the strong cipher. */ strong_mapi = smime_mapi_by_cipher(SMIME_DES_EDE3_168); PORT_Assert(strong_mapi >= 0); for (rcount = 0; rcerts[rcount] != NULL; rcount++) { SECItem *profile; smime_capability **caps; int capi, pref; SECStatus dstat; pref = smime_symmetric_count; profile = CERT_FindSMimeProfile(rcerts[rcount]); if (profile != NULL && profile->data != NULL && profile->len > 0) { caps = NULL; dstat = SEC_QuickDERDecodeItem(poolp, &caps, smime_capabilities_template, profile); if (dstat == SECSuccess && caps != NULL) { for (capi = 0; caps[capi] != NULL; capi++) { smime_fill_capability(caps[capi]); mapi = smime_mapi_by_cipher(caps[capi]->cipher); if (mapi >= 0) { cipher_abilities[mapi]++; cipher_votes[mapi] += pref; --pref; } } } } else { SECKEYPublicKey *key; unsigned int pklen_bits; /* * XXX This is probably only good for RSA keys. What I would * really like is a function to just say; Is the public key in * this cert an export-length key? Then I would not have to * know things like the value 512, or the kind of key, or what * a subjectPublicKeyInfo is, etc. */ key = CERT_ExtractPublicKey(rcerts[rcount]); if (key != NULL) { pklen_bits = SECKEY_PublicKeyStrength(key) * 8; SECKEY_DestroyPublicKey(key); if (pklen_bits > 512) { cipher_abilities[strong_mapi]++; cipher_votes[strong_mapi] += pref; } } } if (profile != NULL) SECITEM_FreeItem(profile, PR_TRUE); } max = 0; for (mapi = 0; mapi < smime_symmetric_count; mapi++) { if (cipher_abilities[mapi] != rcount) continue; if (!smime_cipher_allowed(smime_cipher_maps[mapi].cipher)) continue; if (cipher_votes[mapi] > max) { chosen_cipher = smime_cipher_maps[mapi].cipher; max = cipher_votes[mapi]; } /* XXX else if a tie, let scert break it? */ } done: if (poolp != NULL) PORT_FreeArena(poolp, PR_FALSE); return chosen_cipher; }
SECStatus SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey, PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites, PRBool *pcanbypass, void *pwArg) { SECStatus rv; int i; PRUint16 suite; PK11SymKey * pms = NULL; SECKEYPublicKey * srvPubkey = NULL; KeyType privKeytype; PK11SlotInfo * slot = NULL; SECItem param; CK_VERSION version; CK_MECHANISM_TYPE mechanism_array[2]; SECItem enc_pms = {siBuffer, NULL, 0}; PRBool isTLS = PR_FALSE; SSLCipherSuiteInfo csdef; PRBool testrsa = PR_FALSE; PRBool testrsa_export = PR_FALSE; PRBool testecdh = PR_FALSE; PRBool testecdhe = PR_FALSE; #ifdef NSS_ENABLE_ECC SECKEYECParams ecParams = { siBuffer, NULL, 0 }; #endif if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } srvPubkey = CERT_ExtractPublicKey(cert); if (!srvPubkey) return SECFailure; *pcanbypass = PR_TRUE; rv = SECFailure; /* determine which KEAs to test */ /* 0 (SSL_NULL_WITH_NULL_NULL) is used as a list terminator because * SSL3 and TLS specs forbid negotiating that cipher suite number. */ for (i=0; i < nsuites && (suite = *ciphersuites++) != 0; i++) { /* skip SSL2 cipher suites and ones NSS doesn't support */ if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess || SSL_IS_SSL2_CIPHER(suite) ) continue; switch (csdef.keaType) { case ssl_kea_rsa: switch (csdef.cipherSuite) { case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA: case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA: case SSL_RSA_EXPORT_WITH_RC4_40_MD5: case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: testrsa_export = PR_TRUE; } if (!testrsa_export) testrsa = PR_TRUE; break; case ssl_kea_ecdh: if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */ testecdhe = PR_TRUE; else testecdh = PR_TRUE; break; case ssl_kea_dh: /* this is actually DHE */ default: continue; } } /* For each protocol try to derive and extract an MS. * Failure of function any function except MS extract means * continue with the next cipher test. Stop testing when the list is * exhausted or when the first MS extract--not derive--fails. */ privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey); protocolmask &= SSL_CBP_SSL3|SSL_CBP_TLS1_0; while (protocolmask) { if (protocolmask & SSL_CBP_SSL3) { isTLS = PR_FALSE; protocolmask ^= SSL_CBP_SSL3; } else { isTLS = PR_TRUE; protocolmask ^= SSL_CBP_TLS1_0; } if (privKeytype == rsaKey && testrsa_export) { if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) { *pcanbypass = PR_FALSE; rv = SECSuccess; break; } else testrsa = PR_TRUE; } for (; privKeytype == rsaKey && testrsa; ) { /* TLS_RSA */ unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH]; unsigned int outLen = 0; CK_MECHANISM_TYPE target; SECStatus irv; mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN; mechanism_array[1] = CKM_RSA_PKCS; slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg); if (slot == NULL) { PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND); break; } /* Generate the pre-master secret ... (client side) */ version.major = 3 /*MSB(clientHelloVersion)*/; version.minor = 0 /*LSB(clientHelloVersion)*/; param.data = (unsigned char *)&version; param.len = sizeof version; pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, ¶m, 0, pwArg); PK11_FreeSlot(slot); if (!pms) break; /* now wrap it */ enc_pms.len = SECKEY_PublicKeyStrength(srvPubkey); enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len); if (enc_pms.data == NULL) { PORT_SetError(PR_OUT_OF_MEMORY_ERROR); break; } irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms); if (irv != SECSuccess) break; PK11_FreeSymKey(pms); pms = NULL; /* now do the server side--check the triple bypass first */ rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen, sizeof rsaPmsBuf, (unsigned char *)enc_pms.data, enc_pms.len); /* if decrypt worked we're done with the RSA test */ if (rv == SECSuccess) { *pcanbypass = PR_TRUE; break; } /* check for fallback to double bypass */ target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE : CKM_SSL3_MASTER_KEY_DERIVE; pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms, target, CKA_DERIVE, 0); rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass); if (rv == SECSuccess && *pcanbypass == PR_FALSE) goto done; break; } /* Check for NULL to avoid double free. * SECItem_FreeItem sets data NULL in secitem.c#265 */ if (enc_pms.data != NULL) { SECITEM_FreeItem(&enc_pms, PR_FALSE); } #ifdef NSS_ENABLE_ECC for (; (privKeytype == ecKey && ( testecdh || testecdhe)) || (privKeytype == rsaKey && testecdhe); ) { CK_MECHANISM_TYPE target; SECKEYPublicKey *keapub = NULL; SECKEYPrivateKey *keapriv; SECKEYPublicKey *cpub = NULL; /* client's ephemeral ECDH keys */ SECKEYPrivateKey *cpriv = NULL; SECKEYECParams *pecParams = NULL; if (privKeytype == ecKey && testecdhe) { /* TLS_ECDHE_ECDSA */ pecParams = &srvPubkey->u.ec.DEREncodedParams; } else if (privKeytype == rsaKey && testecdhe) { /* TLS_ECDHE_RSA */ ECName ec_curve; int serverKeyStrengthInBits; int signatureKeyStrength; int requiredECCbits; /* find a curve of equivalent strength to the RSA key's */ requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey); if (requiredECCbits < 0) break; requiredECCbits *= BPB; serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len; if (srvPubkey->u.rsa.modulus.data[0] == 0) { serverKeyStrengthInBits--; } /* convert to strength in bits */ serverKeyStrengthInBits *= BPB; signatureKeyStrength = SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits); if ( requiredECCbits > signatureKeyStrength ) requiredECCbits = signatureKeyStrength; ec_curve = ssl3_GetCurveWithECKeyStrength(SSL3_SUPPORTED_CURVES_MASK, requiredECCbits); rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams); if (rv == SECFailure) { break; } pecParams = &ecParams; } if (testecdhe) { /* generate server's ephemeral keys */ keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL); if (!keapriv || !keapub) { if (keapriv) SECKEY_DestroyPrivateKey(keapriv); if (keapub) SECKEY_DestroyPublicKey(keapub); PORT_SetError(SEC_ERROR_KEYGEN_FAIL); rv = SECFailure; break; } } else { /* TLS_ECDH_ECDSA */ keapub = srvPubkey; keapriv = srvPrivkey; pecParams = &srvPubkey->u.ec.DEREncodedParams; } /* perform client side ops */ /* generate a pair of ephemeral keys using server's parms */ cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL); if (!cpriv || !cpub) { if (testecdhe) { SECKEY_DestroyPrivateKey(keapriv); SECKEY_DestroyPublicKey(keapub); } PORT_SetError(SEC_ERROR_KEYGEN_FAIL); rv = SECFailure; break; } /* now do the server side */ /* determine the PMS using client's public value */ target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH : CKM_SSL3_MASTER_KEY_DERIVE_DH; pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass); SECKEY_DestroyPrivateKey(cpriv); SECKEY_DestroyPublicKey(cpub); if (testecdhe) { SECKEY_DestroyPrivateKey(keapriv); SECKEY_DestroyPublicKey(keapub); } if (rv == SECSuccess && *pcanbypass == PR_FALSE) goto done; break; } /* Check for NULL to avoid double free. */ if (ecParams.data != NULL) { PORT_Free(ecParams.data); ecParams.data = NULL; } #endif /* NSS_ENABLE_ECC */ if (pms) PK11_FreeSymKey(pms); } /* *pcanbypass has been set */ rv = SECSuccess; done: if (pms) PK11_FreeSymKey(pms); /* Check for NULL to avoid double free. * SECItem_FreeItem sets data NULL in secitem.c#265 */ if (enc_pms.data != NULL) { SECITEM_FreeItem(&enc_pms, PR_FALSE); } #ifdef NSS_ENABLE_ECC if (ecParams.data != NULL) { PORT_Free(ecParams.data); ecParams.data = NULL; } #endif /* NSS_ENABLE_ECC */ if (srvPubkey) { SECKEY_DestroyPublicKey(srvPubkey); srvPubkey = NULL; } return rv; }
unsigned int NSSCryptoKeyRSA::publicEncrypt(const unsigned char * inBuf, unsigned char * cipherBuf, unsigned int inLength, unsigned int maxOutLength, PaddingType padding, hashMethod hm) { // Perform an encrypt if (mp_pubkey == 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Attempt to encrypt data with empty key"); } unsigned int encryptSize = SECKEY_PublicKeyStrength(mp_pubkey); if (maxOutLength < encryptSize) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Too small buffer for encrypted buffer output"); } SECStatus s; unsigned char * buf; XSECnew(buf, unsigned char[encryptSize]); ArrayJanitor<unsigned char> j_buf(buf); switch (padding) { case XSECCryptoKeyRSA::PAD_PKCS_1_5 : // do the padding (http://www.w3.org/TR/xmlenc-core/#rsa-1_5) { // generate random data for padding SECStatus s = PK11_GenerateRandom(buf, encryptSize); if (s != SECSuccess) { throw XSECException(XSECException::InternalError, "NSSCryptoKeyRSA() - Error generating Random data"); } // first byte have to be 0x02 buf[0] = 0x00; buf[1] = 0x02; // check that there are no 0x00 bytes among random data for (unsigned int i = 2; i < encryptSize - inLength - 1; i++) { while (buf[i] == 0x00) { // replace all 0x00 occurences in random data with random value PK11_GenerateRandom(&buf[i], 1); } } // before key add 0x00 byte buf[encryptSize - inLength - 1] = 0x00; // at the end of input buffer (to be encrypted) add key memcpy(&buf[encryptSize - inLength], inBuf, inLength); } // encrypt s = PK11_PubEncryptRaw(mp_pubkey, cipherBuf, (unsigned char*)buf, encryptSize, NULL); if (s != SECSuccess) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA publicKeyEncrypt - Error performing encrypt"); } break; case XSECCryptoKeyRSA::PAD_OAEP_MGFP1 : throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - OAEP padding method not supported in NSS yet"); break; default : throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Unknown padding method"); } return encryptSize; }
SECStatus SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey, PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites, PRBool *pcanbypass, void *pwArg) { #ifdef NO_PKCS11_BYPASS if (!pcanbypass) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } *pcanbypass = PR_FALSE; return SECSuccess; #else SECStatus rv; int i; PRUint16 suite; PK11SymKey * pms = NULL; SECKEYPublicKey * srvPubkey = NULL; KeyType privKeytype; PK11SlotInfo * slot = NULL; SECItem param; CK_VERSION version; CK_MECHANISM_TYPE mechanism_array[2]; SECItem enc_pms = {siBuffer, NULL, 0}; PRBool isTLS = PR_FALSE; SSLCipherSuiteInfo csdef; PRBool testrsa = PR_FALSE; PRBool testrsa_export = PR_FALSE; PRBool testecdh = PR_FALSE; PRBool testecdhe = PR_FALSE; #ifdef NSS_ENABLE_ECC SECKEYECParams ecParams = { siBuffer, NULL, 0 }; #endif if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } srvPubkey = CERT_ExtractPublicKey(cert); if (!srvPubkey) return SECFailure; *pcanbypass = PR_TRUE; rv = SECFailure; for (i=0; i < nsuites && (suite = *ciphersuites++) != 0; i++) { if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess || SSL_IS_SSL2_CIPHER(suite) ) continue; switch (csdef.keaType) { case ssl_kea_rsa: switch (csdef.cipherSuite) { case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA: case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA: case SSL_RSA_EXPORT_WITH_RC4_40_MD5: case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: testrsa_export = PR_TRUE; } if (!testrsa_export) testrsa = PR_TRUE; break; case ssl_kea_ecdh: if (strcmp(csdef.keaTypeName, "ECDHE") == 0) testecdhe = PR_TRUE; else testecdh = PR_TRUE; break; case ssl_kea_dh: default: continue; } } privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey); protocolmask &= SSL_CBP_SSL3|SSL_CBP_TLS1_0; while (protocolmask) { if (protocolmask & SSL_CBP_SSL3) { isTLS = PR_FALSE; protocolmask ^= SSL_CBP_SSL3; } else { isTLS = PR_TRUE; protocolmask ^= SSL_CBP_TLS1_0; } if (privKeytype == rsaKey && testrsa_export) { if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) { *pcanbypass = PR_FALSE; rv = SECSuccess; break; } else testrsa = PR_TRUE; } for (; privKeytype == rsaKey && testrsa; ) { unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH]; unsigned int outLen = 0; CK_MECHANISM_TYPE target; SECStatus irv; mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN; mechanism_array[1] = CKM_RSA_PKCS; slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg); if (slot == NULL) { PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND); break; } version.major = 3 ; version.minor = 0 ; param.data = (unsigned char *)&version; param.len = sizeof version; pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, ¶m, 0, pwArg); PK11_FreeSlot(slot); if (!pms) break; enc_pms.len = SECKEY_PublicKeyStrength(srvPubkey); enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len); if (enc_pms.data == NULL) { PORT_SetError(PR_OUT_OF_MEMORY_ERROR); break; } irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms); if (irv != SECSuccess) break; PK11_FreeSymKey(pms); pms = NULL; rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen, sizeof rsaPmsBuf, (unsigned char *)enc_pms.data, enc_pms.len); if (rv == SECSuccess) { *pcanbypass = PR_TRUE; break; } target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE : CKM_SSL3_MASTER_KEY_DERIVE; pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms, target, CKA_DERIVE, 0); rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass); if (rv == SECSuccess && *pcanbypass == PR_FALSE) goto done; break; } if (enc_pms.data != NULL) { SECITEM_FreeItem(&enc_pms, PR_FALSE); } #ifdef NSS_ENABLE_ECC for (; (privKeytype == ecKey && ( testecdh || testecdhe)) || (privKeytype == rsaKey && testecdhe); ) { CK_MECHANISM_TYPE target; SECKEYPublicKey *keapub = NULL; SECKEYPrivateKey *keapriv; SECKEYPublicKey *cpub = NULL; SECKEYPrivateKey *cpriv = NULL; SECKEYECParams *pecParams = NULL; if (privKeytype == ecKey && testecdhe) { pecParams = &srvPubkey->u.ec.DEREncodedParams; } else if (privKeytype == rsaKey && testecdhe) { ECName ec_curve; int serverKeyStrengthInBits; int signatureKeyStrength; int requiredECCbits; requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey); if (requiredECCbits < 0) break; requiredECCbits *= BPB; serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len; if (srvPubkey->u.rsa.modulus.data[0] == 0) { serverKeyStrengthInBits--; } serverKeyStrengthInBits *= BPB; signatureKeyStrength = SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits); if ( requiredECCbits > signatureKeyStrength ) requiredECCbits = signatureKeyStrength; ec_curve = ssl3_GetCurveWithECKeyStrength( ssl3_GetSupportedECCurveMask(NULL), requiredECCbits); rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams); if (rv == SECFailure) { break; } pecParams = &ecParams; } if (testecdhe) { keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL); if (!keapriv || !keapub) { if (keapriv) SECKEY_DestroyPrivateKey(keapriv); if (keapub) SECKEY_DestroyPublicKey(keapub); PORT_SetError(SEC_ERROR_KEYGEN_FAIL); rv = SECFailure; break; } } else { keapub = srvPubkey; keapriv = srvPrivkey; pecParams = &srvPubkey->u.ec.DEREncodedParams; } cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL); if (!cpriv || !cpub) { if (testecdhe) { SECKEY_DestroyPrivateKey(keapriv); SECKEY_DestroyPublicKey(keapub); } PORT_SetError(SEC_ERROR_KEYGEN_FAIL); rv = SECFailure; break; } target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH : CKM_SSL3_MASTER_KEY_DERIVE_DH; pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass); SECKEY_DestroyPrivateKey(cpriv); SECKEY_DestroyPublicKey(cpub); if (testecdhe) { SECKEY_DestroyPrivateKey(keapriv); SECKEY_DestroyPublicKey(keapub); } if (rv == SECSuccess && *pcanbypass == PR_FALSE) goto done; break; } if (ecParams.data != NULL) { PORT_Free(ecParams.data); ecParams.data = NULL; } #endif if (pms) PK11_FreeSymKey(pms); } rv = SECSuccess; done: if (pms) PK11_FreeSymKey(pms); if (enc_pms.data != NULL) { SECITEM_FreeItem(&enc_pms, PR_FALSE); } #ifdef NSS_ENABLE_ECC if (ecParams.data != NULL) { PORT_Free(ecParams.data); ecParams.data = NULL; } #endif if (srvPubkey) { SECKEY_DestroyPublicKey(srvPubkey); srvPubkey = NULL; } return rv; #endif }
static int cmmf_create_witness_and_challenge(PRArenaPool *poolp, CMMFChallenge *challenge, long inRandom, SECItem *senderDER, SECKEYPublicKey *inPubKey, void *passwdArg) { SECItem *encodedRandNum; SECItem encodedRandStr = {siBuffer, NULL, 0}; SECItem *dummy; unsigned char *randHash, *senderHash, *encChal=NULL; unsigned modulusLen = 0; SECStatus rv = SECFailure; CMMFRand randStr= { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}}; PK11SlotInfo *slot; PK11SymKey *symKey = NULL; CK_OBJECT_HANDLE id; CERTSubjectPublicKeyInfo *spki = NULL; encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber, inRandom); encodedRandNum = &challenge->randomNumber; randHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH); senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH); if (randHash == NULL) { goto loser; } rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data, (PRUint32)encodedRandNum->len); if (rv != SECSuccess) { goto loser; } rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data, (PRUint32)senderDER->len); if (rv != SECSuccess) { goto loser; } challenge->witness.data = randHash; challenge->witness.len = SHA1_LENGTH; randStr.integer = *encodedRandNum; randStr.senderHash.data = senderHash; randStr.senderHash.len = SHA1_LENGTH; dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr, CMMFRandTemplate); if (dummy != &encodedRandStr) { rv = SECFailure; goto loser; } /* XXXX Now I have to encrypt encodedRandStr and stash it away. */ modulusLen = SECKEY_PublicKeyStrength(inPubKey); encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen); if (encChal == NULL) { rv = SECFailure; goto loser; } slot =PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg); if (slot == NULL) { rv = SECFailure; goto loser; } id = PK11_ImportPublicKey(slot, inPubKey, PR_FALSE); /* In order to properly encrypt the data, we import as a symmetric * key, and then wrap that key. That in essence encrypts the data. * This is the method recommended in the PK11 world in order * to prevent threading issues as well as breaking any other semantics * the PK11 libraries depend on. */ symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated, CKA_VALUE, &encodedRandStr, passwdArg); if (symKey == NULL) { rv = SECFailure; goto loser; } challenge->challenge.data = encChal; challenge->challenge.len = modulusLen; rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey, &challenge->challenge); PK11_FreeSlot(slot); if (rv != SECSuccess) { goto loser; } rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER); crmf_get_public_value(inPubKey, &challenge->key); /* Fall through */ loser: if (spki != NULL) { SECKEY_DestroySubjectPublicKeyInfo(spki); } if (encodedRandStr.data != NULL) { PORT_Free(encodedRandStr.data); } if (encodedRandNum != NULL) { SECITEM_FreeItem(encodedRandNum, PR_TRUE); } if (symKey != NULL) { PK11_FreeSymKey(symKey); } return rv; }
static sec_PKCS7CipherObject * sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo, PK11SymKey *orig_bulkkey) { SECOidTag kind; sec_PKCS7CipherObject *encryptobj; SEC_PKCS7RecipientInfo **recipientinfos, *ri; SEC_PKCS7EncryptedContentInfo *enccinfo; SECKEYPublicKey *publickey = NULL; SECKEYPrivateKey *ourPrivKey = NULL; PK11SymKey *bulkkey; void *mark, *wincx; int i; PLArenaPool *arena = NULL; /* Get the context in case we need it below. */ wincx = cinfo->pwfn_arg; kind = SEC_PKCS7ContentType (cinfo); switch (kind) { default: case SEC_OID_PKCS7_DATA: case SEC_OID_PKCS7_DIGESTED_DATA: case SEC_OID_PKCS7_SIGNED_DATA: recipientinfos = NULL; enccinfo = NULL; break; case SEC_OID_PKCS7_ENCRYPTED_DATA: { SEC_PKCS7EncryptedData *encdp; /* To do EncryptedData we *must* be given a bulk key. */ PORT_Assert (orig_bulkkey != NULL); if (orig_bulkkey == NULL) { /* XXX error? */ return NULL; } encdp = cinfo->content.encryptedData; recipientinfos = NULL; enccinfo = &(encdp->encContentInfo); } break; case SEC_OID_PKCS7_ENVELOPED_DATA: { SEC_PKCS7EnvelopedData *envdp; envdp = cinfo->content.envelopedData; recipientinfos = envdp->recipientInfos; enccinfo = &(envdp->encContentInfo); } break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { SEC_PKCS7SignedAndEnvelopedData *saedp; saedp = cinfo->content.signedAndEnvelopedData; recipientinfos = saedp->recipientInfos; enccinfo = &(saedp->encContentInfo); } break; } if (enccinfo == NULL) return NULL; bulkkey = orig_bulkkey; if (bulkkey == NULL) { CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg); PK11SlotInfo *slot; slot = PK11_GetBestSlot(type,cinfo->pwfn_arg); if (slot == NULL) { return NULL; } bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8, cinfo->pwfn_arg); PK11_FreeSlot(slot); if (bulkkey == NULL) { return NULL; } } encryptobj = NULL; mark = PORT_ArenaMark (cinfo->poolp); /* * Encrypt the bulk key with the public key of each recipient. */ for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) { CERTCertificate *cert; SECOidTag certalgtag, encalgtag; SECStatus rv; int data_len; SECItem *params = NULL; cert = ri->cert; PORT_Assert (cert != NULL); if (cert == NULL) continue; /* * XXX Want an interface that takes a cert and some data and * fills in an algorithmID and encrypts the data with the public * key from the cert. Or, give me two interfaces -- one which * gets the algorithm tag from a cert (I should not have to go * down into the subjectPublicKeyInfo myself) and another which * takes a public key and algorithm tag and data and encrypts * the data. Or something like that. The point is that all * of the following hardwired RSA stuff should be done elsewhere. */ certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: encalgtag = certalgtag; publickey = CERT_ExtractPublicKey (cert); if (publickey == NULL) goto loser; data_len = SECKEY_PublicKeyStrength(publickey); ri->encKey.data = (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len); ri->encKey.len = data_len; if (ri->encKey.data == NULL) goto loser; rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey, bulkkey,&ri->encKey); SECKEY_DestroyPublicKey(publickey); publickey = NULL; if (rv != SECSuccess) goto loser; params = NULL; /* paranoia */ break; default: PORT_SetError (SEC_ERROR_INVALID_ALGORITHM); goto loser; } rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, params); if (rv != SECSuccess) goto loser; if (arena) PORT_FreeArena(arena,PR_FALSE); arena = NULL; } encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey, enccinfo->encalg, &(enccinfo->contentEncAlg)); if (encryptobj != NULL) { PORT_ArenaUnmark (cinfo->poolp, mark); mark = NULL; /* good one; do not want to release */ } /* fallthru */ loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } if (publickey) { SECKEY_DestroyPublicKey(publickey); } if (ourPrivKey) { SECKEY_DestroyPrivateKey(ourPrivKey); } if (mark != NULL) { PORT_ArenaRelease (cinfo->poolp, mark); } if (orig_bulkkey == NULL) { if (bulkkey) PK11_FreeSymKey(bulkkey); } return encryptobj; }