/* * SecCmsSignedDataEncodeBeforeStart - do all the necessary things to a SignedData * before start of encoding. * * In detail: * - find out about the right value to put into sigd->version * - come up with a list of digestAlgorithms (which should be the union of the algorithms * in the signerinfos). * If we happen to have a pre-set list of algorithms (and digest values!), we * check if we have all the signerinfos' algorithms. If not, this is an error. */ OSStatus SecCmsSignedDataEncodeBeforeStart(SecCmsSignedDataRef sigd) { SecCmsSignerInfoRef signerinfo; SECOidTag digestalgtag; CSSM_DATA_PTR dummy; int version; OSStatus rv; Boolean haveDigests = PR_FALSE; int n, i; PLArenaPool *poolp; poolp = sigd->cmsg->poolp; /* we assume that we have precomputed digests if there is a list of algorithms, and */ /* a chunk of data for each of those algorithms */ if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) { for (i=0; sigd->digestAlgorithms[i] != NULL; i++) { if (sigd->digests[i] == NULL) break; } if (sigd->digestAlgorithms[i] == NULL) /* reached the end of the array? */ haveDigests = PR_TRUE; /* yes: we must have all the digests */ } version = SEC_CMS_SIGNED_DATA_VERSION_BASIC; /* RFC2630 5.1 "version is the syntax version number..." */ if (SecCmsContentInfoGetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA) version = SEC_CMS_SIGNED_DATA_VERSION_EXT; /* prepare all the SignerInfos (there may be none) */ for (i=0; i < SecCmsSignedDataSignerInfoCount(sigd); i++) { signerinfo = SecCmsSignedDataGetSignerInfo(sigd, i); /* RFC2630 5.1 "version is the syntax version number..." */ if (SecCmsSignerInfoGetVersion(signerinfo) != SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN) version = SEC_CMS_SIGNED_DATA_VERSION_EXT; /* collect digestAlgorithms from SignerInfos */ /* (we need to know which algorithms we have when the content comes in) */ /* do not overwrite any existing digestAlgorithms (and digest) */ digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo); n = SecCmsAlgArrayGetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag); if (n < 0 && haveDigests) { /* oops, there is a digestalg we do not have a digest for */ /* but we were supposed to have all the digests already... */ goto loser; } else if (n < 0) { /* add the digestAlgorithm & a NULL digest */ rv = SecCmsSignedDataAddDigest((SecArenaPoolRef)poolp, sigd, digestalgtag, NULL); if (rv != SECSuccess) goto loser; } else { /* found it, nothing to do */ } } dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version); if (dummy == NULL) return SECFailure; /* this is a SET OF, so we need to sort them guys */ rv = SecCmsArraySortByDER((void **)sigd->digestAlgorithms, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), (void **)sigd->digests); if (rv != SECSuccess) return SECFailure; return SECSuccess; loser: return SECFailure; }
NS_IMETHODIMP nsCRLManager::ImportCrl (uint8_t *aData, uint32_t aLength, nsIURI * aURI, uint32_t aType, bool doSilentDownload, const PRUnichar* crlKey) { if (!NS_IsMainThread()) { NS_ERROR("nsCRLManager::ImportCrl called off the main thread"); return NS_ERROR_NOT_SAME_THREAD; } nsNSSShutDownPreventionLock locker; nsresult rv; PRArenaPool *arena = NULL; CERTCertificate *caCert; SECItem derName = { siBuffer, NULL, 0 }; SECItem derCrl; CERTSignedData sd; SECStatus sec_rv; CERTSignedCrl *crl; nsAutoCString url; nsCOMPtr<nsICRLInfo> crlData; bool importSuccessful; int32_t errorCode; nsString errorMessage; nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); if (NS_FAILED(rv)) return rv; aURI->GetSpec(url); arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { goto loser; } memset(&sd, 0, sizeof(sd)); derCrl.data = (unsigned char*)aData; derCrl.len = aLength; sec_rv = CERT_KeyFromDERCrl(arena, &derCrl, &derName); if (sec_rv != SECSuccess) { goto loser; } caCert = CERT_FindCertByName(CERT_GetDefaultCertDB(), &derName); if (!caCert) { if (aType == SEC_KRL_TYPE){ goto loser; } } else { sec_rv = SEC_ASN1DecodeItem(arena, &sd, SEC_ASN1_GET(CERT_SignedDataTemplate), &derCrl); if (sec_rv != SECSuccess) { goto loser; } sec_rv = CERT_VerifySignedData(&sd, caCert, PR_Now(), nullptr); if (sec_rv != SECSuccess) { goto loser; } } crl = SEC_NewCrl(CERT_GetDefaultCertDB(), const_cast<char*>(url.get()), &derCrl, aType); if (!crl) { goto loser; } crlData = new nsCRLInfo(crl); SSL_ClearSessionCache(); SEC_DestroyCrl(crl); importSuccessful = true; goto done; loser: importSuccessful = false; errorCode = PR_GetError(); switch (errorCode) { case SEC_ERROR_CRL_EXPIRED: nssComponent->GetPIPNSSBundleString("CrlImportFailureExpired", errorMessage); break; case SEC_ERROR_CRL_BAD_SIGNATURE: nssComponent->GetPIPNSSBundleString("CrlImportFailureBadSignature", errorMessage); break; case SEC_ERROR_CRL_INVALID: nssComponent->GetPIPNSSBundleString("CrlImportFailureInvalid", errorMessage); break; case SEC_ERROR_OLD_CRL: nssComponent->GetPIPNSSBundleString("CrlImportFailureOld", errorMessage); break; case SEC_ERROR_CRL_NOT_YET_VALID: nssComponent->GetPIPNSSBundleString("CrlImportFailureNotYetValid", errorMessage); break; default: nssComponent->GetPIPNSSBundleString("CrlImportFailureReasonUnknown", errorMessage); errorMessage.AppendInt(errorCode,16); break; } done: if(!doSilentDownload){ if (!importSuccessful){ nsString message; nsString temp; nssComponent->GetPIPNSSBundleString("CrlImportFailure1x", message); message.Append(NS_LITERAL_STRING("\n").get()); message.Append(errorMessage); nssComponent->GetPIPNSSBundleString("CrlImportFailure2", temp); message.Append(NS_LITERAL_STRING("\n").get()); message.Append(temp); nsNSSComponent::ShowAlertWithConstructedString(message); } else { nsCOMPtr<nsICertificateDialogs> certDialogs; // Not being able to display the success dialog should not // be a fatal error, so don't return a failure code. { nsPSMUITracker tracker; if (tracker.isUIForbidden()) { rv = NS_ERROR_NOT_AVAILABLE; } else { rv = ::getNSSDialogs(getter_AddRefs(certDialogs), NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID); } } if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext(); certDialogs->CrlImportStatusDialog(cxt, crlData); } } } else { if(crlKey == nullptr){ return NS_ERROR_FAILURE; } nsCOMPtr<nsIPrefService> prefSvc = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv); nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv); if (NS_FAILED(rv)){ return rv; } nsAutoCString updateErrCntPrefStr(CRL_AUTOUPDATE_ERRCNT_PREF); LossyAppendUTF16toASCII(crlKey, updateErrCntPrefStr); if(importSuccessful){ PRUnichar *updateTime; nsAutoCString updateTimeStr; nsCString updateURL; int32_t timingTypePref; double dayCnt; char *dayCntStr; nsAutoCString updateTypePrefStr(CRL_AUTOUPDATE_TIMIINGTYPE_PREF); nsAutoCString updateTimePrefStr(CRL_AUTOUPDATE_TIME_PREF); nsAutoCString updateUrlPrefStr(CRL_AUTOUPDATE_URL_PREF); nsAutoCString updateDayCntPrefStr(CRL_AUTOUPDATE_DAYCNT_PREF); nsAutoCString updateFreqCntPrefStr(CRL_AUTOUPDATE_FREQCNT_PREF); LossyAppendUTF16toASCII(crlKey, updateTypePrefStr); LossyAppendUTF16toASCII(crlKey, updateTimePrefStr); LossyAppendUTF16toASCII(crlKey, updateUrlPrefStr); LossyAppendUTF16toASCII(crlKey, updateDayCntPrefStr); LossyAppendUTF16toASCII(crlKey, updateFreqCntPrefStr); pref->GetIntPref(updateTypePrefStr.get(),&timingTypePref); //Compute and update the next download instant if(timingTypePref == TYPE_AUTOUPDATE_TIME_BASED){ pref->GetCharPref(updateDayCntPrefStr.get(),&dayCntStr); }else{ pref->GetCharPref(updateFreqCntPrefStr.get(),&dayCntStr); } dayCnt = atof(dayCntStr); nsMemory::Free(dayCntStr); bool toBeRescheduled = false; if(NS_SUCCEEDED(ComputeNextAutoUpdateTime(crlData, timingTypePref, dayCnt, &updateTime))){ updateTimeStr.AssignWithConversion(updateTime); pref->SetCharPref(updateTimePrefStr.get(),updateTimeStr.get()); //Now, check if this update time is already in the past. This would //imply we have downloaded the same crl, or there is something wrong //with the next update date. We will not reschedule this crl in this //session anymore - or else, we land into a loop. It would anyway be //imported once the browser is restarted. if(LL_CMP(updateTime, > , PR_Now())){ toBeRescheduled = true; } nsMemory::Free(updateTime); } //Update the url to download from, next time crlData->GetLastFetchURL(updateURL); pref->SetCharPref(updateUrlPrefStr.get(),updateURL.get()); pref->SetIntPref(updateErrCntPrefStr.get(),0); if (toBeRescheduled) { nsAutoString hashKey(crlKey); nssComponent->RemoveCrlFromList(hashKey); nssComponent->DefineNextTimer(); } } else{
nsresult CryptoKey::PublicKeyToSpki(SECKEYPublicKey* aPubKey, CryptoBuffer& aRetVal, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { ScopedCERTSubjectPublicKeyInfo spki; // NSS doesn't support exporting DH public keys. if (aPubKey->keyType == dhKey) { // Mimic the behavior of SECKEY_CreateSubjectPublicKeyInfo() and create // a new arena for the SPKI object. ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { return NS_ERROR_DOM_OPERATION_ERR; } spki = PORT_ArenaZNew(arena, CERTSubjectPublicKeyInfo); if (!spki) { return NS_ERROR_DOM_OPERATION_ERR; } // Assign |arena| to |spki| and null the variable afterwards so that the // arena created above that holds the SPKI object is free'd when |spki| // goes out of scope, not when |arena| does. spki->arena = arena.forget(); nsresult rv = PublicDhKeyToSpki(aPubKey, spki); NS_ENSURE_SUCCESS(rv, rv); } else { spki = SECKEY_CreateSubjectPublicKeyInfo(aPubKey); if (!spki) { return NS_ERROR_DOM_OPERATION_ERR; } } // Per WebCrypto spec we must export ECDH SPKIs with the algorithm OID // id-ecDH (1.3.132.112) and DH SPKIs with OID dhKeyAgreement // (1.2.840.113549.1.3.1). NSS doesn't know about these OIDs and there is // no way to specify the algorithm to use when exporting a public key. if (aPubKey->keyType == ecKey || aPubKey->keyType == dhKey) { const SECItem* oidData = nullptr; if (aPubKey->keyType == ecKey) { oidData = &SEC_OID_DATA_EC_DH; } else if (aPubKey->keyType == dhKey) { oidData = &SEC_OID_DATA_DH_KEY_AGREEMENT; } else { MOZ_ASSERT(false); } SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm, oidData); if (rv != SECSuccess) { return NS_ERROR_DOM_OPERATION_ERR; } } const SEC_ASN1Template* tpl = SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate); ScopedSECItem spkiItem(SEC_ASN1EncodeItem(nullptr, nullptr, spki, tpl)); if (!aRetVal.Assign(spkiItem.get())) { return NS_ERROR_DOM_OPERATION_ERR; } return NS_OK; }
CRMFEncryptedValue * crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey, SECKEYPublicKey *inCAKey, CRMFEncryptedValue *destValue) { SECItem wrappedPrivKey, wrappedSymKey; SECItem encodedParam, *dummy; SECStatus rv; CK_MECHANISM_TYPE pubMechType, symKeyType; unsigned char *wrappedSymKeyBits; unsigned char *wrappedPrivKeyBits; SECItem *iv = NULL; SECOidTag tag; PK11SymKey *symKey; PK11SlotInfo *slot; SECAlgorithmID *symmAlg; CRMFEncryptedValue *myEncrValue = NULL; encodedParam.data = NULL; wrappedSymKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN); wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN); if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) { goto loser; } if (destValue == NULL) { myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue); if (destValue == NULL) { goto loser; } } pubMechType = crmf_get_mechanism_from_public_key(inCAKey); if (pubMechType == CKM_INVALID_MECHANISM) { /* XXX I should probably do something here for non-RSA * keys that are in certs. (ie DSA) * XXX or at least SET AN ERROR CODE. */ goto loser; } slot = inPrivKey->pkcs11Slot; PORT_Assert(slot != NULL); symKeyType = crmf_get_best_privkey_wrap_mechanism(slot); symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL); if (symKey == NULL) { goto loser; } wrappedSymKey.data = wrappedSymKeyBits; wrappedSymKey.len = MAX_WRAPPED_KEY_LEN; rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey); if (rv != SECSuccess) { goto loser; } /* Make the length of the result a Bit String length. */ wrappedSymKey.len <<= 3; wrappedPrivKey.data = wrappedPrivKeyBits; wrappedPrivKey.len = MAX_WRAPPED_KEY_LEN; iv = crmf_get_iv(symKeyType); rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv, &wrappedPrivKey, NULL); PK11_FreeSymKey(symKey); if (rv != SECSuccess) { goto loser; } /* Make the length of the result a Bit String length. */ wrappedPrivKey.len <<= 3; rv = crmf_make_bitstring_copy(NULL, &destValue->encValue, &wrappedPrivKey); if (rv != SECSuccess) { goto loser; } rv = crmf_make_bitstring_copy(NULL, &destValue->encSymmKey, &wrappedSymKey); if (rv != SECSuccess) { goto loser; } destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID); if (symmAlg == NULL) { goto loser; } dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv, SEC_ASN1_GET(SEC_OctetStringTemplate)); if (dummy != &encodedParam) { SECITEM_FreeItem(dummy, PR_TRUE); goto loser; } symKeyType = crmf_get_non_pad_mechanism(symKeyType); tag = PK11_MechanismToAlgtag(symKeyType); rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam); if (rv != SECSuccess) { goto loser; } SECITEM_FreeItem(&encodedParam, PR_FALSE); PORT_Free(wrappedPrivKeyBits); PORT_Free(wrappedSymKeyBits); SECITEM_FreeItem(iv, PR_TRUE); return destValue; loser: if (iv != NULL) { SECITEM_FreeItem(iv, PR_TRUE); } if (myEncrValue != NULL) { crmf_destroy_encrypted_value(myEncrValue, PR_TRUE); } if (wrappedSymKeyBits != NULL) { PORT_Free(wrappedSymKeyBits); } if (wrappedPrivKeyBits != NULL) { PORT_Free(wrappedPrivKeyBits); } if (encodedParam.data != NULL) { SECITEM_FreeItem(&encodedParam, PR_FALSE); } return NULL; }
RefPtr<DtlsIdentity> DtlsIdentity::Generate() { UniquePK11SlotInfo slot(PK11_GetInternalSlot()); if (!slot) { return nullptr; } uint8_t random_name[16]; SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), random_name, sizeof(random_name)); if (rv != SECSuccess) return nullptr; std::string name; char chunk[3]; for (size_t i = 0; i < sizeof(random_name); ++i) { SprintfLiteral(chunk, "%.2x", random_name[i]); name += chunk; } std::string subject_name_string = "CN=" + name; UniqueCERTName subject_name(CERT_AsciiToName(subject_name_string.c_str())); if (!subject_name) { return nullptr; } unsigned char paramBuf[12]; // OIDs are small SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) }; SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) { return nullptr; } ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID; ecdsaParams.data[1] = oidData->oid.len; memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len); ecdsaParams.len = oidData->oid.len + 2; SECKEYPublicKey *pubkey; UniqueSECKEYPrivateKey private_key( PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey, PR_FALSE, PR_TRUE, nullptr)); if (private_key == nullptr) return nullptr; UniqueSECKEYPublicKey public_key(pubkey); pubkey = nullptr; UniqueCERTSubjectPublicKeyInfo spki( SECKEY_CreateSubjectPublicKeyInfo(public_key.get())); if (!spki) { return nullptr; } UniqueCERTCertificateRequest certreq( CERT_CreateCertificateRequest(subject_name.get(), spki.get(), nullptr)); if (!certreq) { return nullptr; } // From 1 day before todayto 30 days after. // This is a sort of arbitrary range designed to be valid // now with some slack in case the other side expects // some before expiry. // // Note: explicit casts necessary to avoid // warning C4307: '*' : integral constant overflow static const PRTime oneDay = PRTime(PR_USEC_PER_SEC) * PRTime(60) // sec * PRTime(60) // min * PRTime(24); // hours PRTime now = PR_Now(); PRTime notBefore = now - oneDay; PRTime notAfter = now + (PRTime(30) * oneDay); UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter)); if (!validity) { return nullptr; } unsigned long serial; // Note: This serial in principle could collide, but it's unlikely rv = PK11_GenerateRandomOnSlot(slot.get(), reinterpret_cast<unsigned char *>(&serial), sizeof(serial)); if (rv != SECSuccess) { return nullptr; } UniqueCERTCertificate certificate( CERT_CreateCertificate(serial, subject_name.get(), validity.get(), certreq.get())); if (!certificate) { return nullptr; } PLArenaPool *arena = certificate->arena; rv = SECOID_SetAlgorithmID(arena, &certificate->signature, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0); if (rv != SECSuccess) return nullptr; // Set version to X509v3. *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3; certificate->version.len = 1; SECItem innerDER; innerDER.len = 0; innerDER.data = nullptr; if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate.get(), SEC_ASN1_GET(CERT_CertificateTemplate))) { return nullptr; } SECItem *signedCert = PORT_ArenaZNew(arena, SECItem); if (!signedCert) { return nullptr; } rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len, private_key.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE); if (rv != SECSuccess) { return nullptr; } certificate->derCert = *signedCert; RefPtr<DtlsIdentity> identity = new DtlsIdentity(Move(private_key), Move(certificate), ssl_kea_ecdh); return identity.forget(); }