/** * Loads the public key for the specified cert name from the NSS store. * * @param certData The DER-encoded X509 certificate to extract the key from. * @param certDataSize The size of certData. * @param publicKey Out parameter for the public key to use. * @return CryptoX_Success on success, CryptoX_Error on error. */ CryptoX_Result NSS_LoadPublicKey(const unsigned char *certData, unsigned int certDataSize, SECKEYPublicKey **publicKey) { CERTCertificate * cert; SECItem certDataItem = { siBuffer, (unsigned char*) certData, certDataSize }; if (!certData || !publicKey) { return CryptoX_Error; } cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certDataItem, NULL, PR_FALSE, PR_TRUE); /* Get the cert and embedded public key out of the database */ if (!cert) { return CryptoX_Error; } *publicKey = CERT_ExtractPublicKey(cert); CERT_DestroyCertificate(cert); if (!*publicKey) { return CryptoX_Error; } return CryptoX_Success; }
/* This symbol is exported for backward compatibility. */ CERTCertificate * __CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, char *nickname, PRBool isperm, PRBool copyDER) { return CERT_NewTempCertificate(handle, derCert, nickname, isperm, copyDER); }
SECStatus AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId& policy, const SECItem& candidateCertDER, /*out*/ TrustLevel* trustLevel) { MOZ_ASSERT(policy.IsAnyPolicy()); MOZ_ASSERT(trustLevel); MOZ_ASSERT(mTrustedRoot); if (!trustLevel || !policy.IsAnyPolicy()) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } if (!mTrustedRoot) { PR_SetError(PR_INVALID_STATE_ERROR, 0); return SECFailure; } // Handle active distrust of the certificate. // XXX: This would be cleaner and more efficient if we could get the trust // information without constructing a CERTCertificate here, but NSS doesn't // expose it in any other easy-to-use fashion. ScopedCERTCertificate candidateCert( CERT_NewTempCertificate(CERT_GetDefaultCertDB(), const_cast<SECItem*>(&candidateCertDER), nullptr, false, true)); if (!candidateCert) { return SECFailure; } CERTCertTrust trust; if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) { PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning); // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit, // because we can have active distrust for either type of cert. Note that // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the // relevant trust bit isn't set then that means the cert must be considered // distrusted. PRUint32 relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA ? CERTDB_TRUSTED_CA : CERTDB_TRUSTED; if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD))) == CERTDB_TERMINAL_RECORD) { *trustLevel = TrustLevel::ActivelyDistrusted; return SECSuccess; } } // mTrustedRoot is the only trust anchor for this validation. if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert.get())) { *trustLevel = TrustLevel::TrustAnchor; return SECSuccess; } *trustLevel = TrustLevel::InheritsTrust; return SECSuccess; }
// TODO: Remove #include "pkix/pkixnss.h", #include "cert.h", // #include "ScopedPtr.h", etc. when this is rewritten to be independent of // NSS. Result CheckNameConstraints(Input encodedNameConstraints, const BackCert& firstChild, KeyPurposeId requiredEKUIfPresent) { ScopedPtr<PLArenaPool, PORT_FreeArena_false> arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { return Result::FATAL_ERROR_NO_MEMORY; } SECItem encodedNameConstraintsSECItem = UnsafeMapInputToSECItem(encodedNameConstraints); // Owned by arena const CERTNameConstraints* constraints = CERT_DecodeNameConstraintsExtension(arena.get(), &encodedNameConstraintsSECItem); if (!constraints) { return MapPRErrorCodeToResult(PR_GetError()); } for (const BackCert* child = &firstChild; child; child = child->childCert) { SECItem childCertDER = UnsafeMapInputToSECItem(child->GetDER()); ScopedPtr<CERTCertificate, CERT_DestroyCertificate> nssCert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &childCertDER, nullptr, false, true)); if (!nssCert) { return MapPRErrorCodeToResult(PR_GetError()); } bool includeCN = child->endEntityOrCA == EndEntityOrCA::MustBeEndEntity && requiredEKUIfPresent == KeyPurposeId::id_kp_serverAuth; // owned by arena const CERTGeneralName* names(CERT_GetConstrainedCertificateNames(nssCert.get(), arena.get(), includeCN)); if (!names) { return MapPRErrorCodeToResult(PR_GetError()); } CERTGeneralName* currentName = const_cast<CERTGeneralName*>(names); do { if (CERT_CheckNameSpace(arena.get(), constraints, currentName) != SECSuccess) { // XXX: It seems like CERT_CheckNameSpace doesn't always call // PR_SetError when it fails, so we ignore what PR_GetError would // return. NSS's cert_VerifyCertChainOld does something similar. return Result::ERROR_CERT_NOT_IN_NAME_SPACE; } currentName = CERT_GetNextGeneralName(currentName); } while (currentName != names); } return Success; }
NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName) { NS_ENSURE_ARG_POINTER(aBase64); nsCOMPtr <nsIX509Cert> newCert; nsNSSCertTrust trust; // need to calculate the trust bits from the aTrust string. nsresult rv = CERT_DecodeTrustString(trust.GetTrust(), /* this is const, but not declared that way */(char *) aTrust); NS_ENSURE_SUCCESS(rv, rv); // if bad trust passed in, return error. rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert)); NS_ENSURE_SUCCESS(rv, rv); SECItem der; rv = newCert->GetRawDER(&der.len, (PRUint8 **)&der.data); NS_ENSURE_SUCCESS(rv, rv); PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); CERTCertificate *tmpCert; CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); tmpCert = CERT_FindCertByDERCert(certdb, &der); if (!tmpCert) tmpCert = CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE); nsMemory::Free(der.data); der.data = nsnull; der.len = 0; if (!tmpCert) { NS_ASSERTION(0,"Couldn't create cert from DER blob\n"); return NS_ERROR_FAILURE; } if (tmpCert->isperm) { CERT_DestroyCertificate(tmpCert); return NS_OK; } CERTCertificateCleaner tmpCertCleaner(tmpCert); nsXPIDLCString nickname; nickname.Adopt(CERT_MakeCANickname(tmpCert)); PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); SECStatus srv = CERT_AddTempCertToPerm(tmpCert, const_cast<char*>(nickname.get()), trust.GetTrust()); return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE; }
CERTCertificate * cmmf_CertOrEncCertGetCertificate(CMMFCertOrEncCert *certOrEncCert, CERTCertDBHandle *certdb) { if (certOrEncCert->choice != cmmfCertificate || certOrEncCert->cert.certificate == NULL) { return NULL; } return CERT_NewTempCertificate(certdb, &certOrEncCert->cert.certificate->derCert, NULL, PR_FALSE, PR_TRUE); }
CERTCertificate * getCert(const char *name, PRBool isAscii, const char * progName) { CERTCertificate * cert; CERTCertDBHandle *defaultDB; PRFileDesc* fd; SECStatus rv; SECItem item = {0, NULL, 0}; defaultDB = CERT_GetDefaultCertDB(); /* First, let's try to find the cert in existing DB. */ cert = CERT_FindCertByNicknameOrEmailAddr(defaultDB, name); if (cert) { return cert; } /* Don't have a cert with name "name" in the DB. Try to * open a file with such name and get the cert from there.*/ fd = PR_Open(name, PR_RDONLY, 0777); if (!fd) { PRIntn err = PR_GetError(); fprintf(stderr, "open of %s failed, %d = %s\n", name, err, SECU_Strerror(err)); return cert; } rv = SECU_ReadDERFromFile(&item, fd, isAscii); PR_Close(fd); if (rv != SECSuccess) { fprintf(stderr, "%s: SECU_ReadDERFromFile failed\n", progName); return cert; } if (!item.len) { /* file was empty */ fprintf(stderr, "cert file %s was empty.\n", name); return cert; } cert = CERT_NewTempCertificate(defaultDB, &item, NULL /* nickname */, PR_FALSE /* isPerm */, PR_TRUE /* copyDER */); if (!cert) { PRIntn err = PR_GetError(); fprintf(stderr, "couldn't import %s, %d = %s\n", name, err, SECU_Strerror(err)); } PORT_Free(item.data); return cert; }
bool RTCCertificate::ReadCertificate(JSStructuredCloneReader* aReader, const nsNSSShutDownPreventionLock& /*proof*/) { CryptoBuffer cert; if (!ReadBuffer(aReader, cert) || cert.Length() == 0) { return false; } SECItem der = { siBuffer, cert.Elements(), static_cast<unsigned int>(cert.Length()) }; mCertificate.reset(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der, nullptr, true, true)); return !!mCertificate; }
CryptoCert crypto_cert_read(uint8 * data, uint32 len) { CryptoCert crypto_cert = xmalloc(sizeof(*crypto_cert)); CERTCertDBHandle * handle = CERT_GetDefaultCertDB(); SECItem derCert; derCert.type = siBuffer; derCert.data = data; derCert.len = len; crypto_cert->cert = CERT_NewTempCertificate(handle, &derCert, NULL, PR_FALSE, PR_TRUE); ASSERT(crypto_cert->cert); return crypto_cert; }
SECStatus AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) { SECItem trustedDER; // Load the trusted certificate into the in-memory NSS database so that // CERT_CreateSubjectCertList can find it. switch (trustedRoot) { case nsIX509CertDB::AppMarketplaceProdPublicRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceProdPublicRoot); trustedDER.len = mozilla::ArrayLength(marketplaceProdPublicRoot); break; case nsIX509CertDB::AppMarketplaceProdReviewersRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceProdReviewersRoot); trustedDER.len = mozilla::ArrayLength(marketplaceProdReviewersRoot); break; case nsIX509CertDB::AppMarketplaceDevPublicRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceDevPublicRoot); trustedDER.len = mozilla::ArrayLength(marketplaceDevPublicRoot); break; case nsIX509CertDB::AppMarketplaceDevReviewersRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceDevReviewersRoot); trustedDER.len = mozilla::ArrayLength(marketplaceDevReviewersRoot); break; case nsIX509CertDB::AppXPCShellRoot: trustedDER.data = const_cast<uint8_t*>(xpcshellRoot); trustedDER.len = mozilla::ArrayLength(xpcshellRoot); break; default: PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } mTrustedRoot = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &trustedDER, nullptr, false, true); if (!mTrustedRoot) { return SECFailure; } return SECSuccess; }
CERTCertificate * CERT_ConvertAndDecodeCertificate(char *certstr) { CERTCertificate *cert; SECStatus rv; SECItem der; rv = ATOB_ConvertAsciiToItem(&der, certstr); if (rv != SECSuccess) return NULL; cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der, NULL, PR_FALSE, PR_TRUE); PORT_Free(der.data); return cert; }
/* * read an old style ascii or binary certificate */ CERTCertificate * CERT_DecodeCertFromPackage(char *certbuf, int certlen) { collect_args collectArgs; SECStatus rv; CERTCertificate *cert = NULL; collectArgs.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); rv = CERT_DecodeCertPackage(certbuf, certlen, collect_certs, (void *)&collectArgs); if ( rv == SECSuccess ) { cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &collectArgs.cert, NULL, PR_FALSE, PR_TRUE); } PORT_FreeArena(collectArgs.arena, PR_FALSE); return(cert); }
CERTCertList * cmmf_MakeCertList(CERTCertificate **inCerts) { CERTCertList *certList; CERTCertificate *currCert; SECItem *derCert, *freeCert = NULL; SECStatus rv; int i; certList = CERT_NewCertList(); if (certList == NULL) { return NULL; } for (i = 0; inCerts[i] != NULL; i++) { derCert = &inCerts[i]->derCert; if (derCert->data == NULL) { derCert = freeCert = cmmf_encode_certificate(inCerts[i]); } currCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), derCert, NULL, PR_FALSE, PR_TRUE); if (freeCert != NULL) { SECITEM_FreeItem(freeCert, PR_TRUE); freeCert = NULL; } if (currCert == NULL) { goto loser; } rv = CERT_AddCertToListTail(certList, currCert); if (rv != SECSuccess) { goto loser; } } return certList; loser: CERT_DestroyCertList(certList); return NULL; }
SECStatus AddCertificateFromFile(const char* basePath, const char* filename) { char buf[16384] = { 0 }; SECStatus rv = ReadFileToBuffer(basePath, filename, buf); if (rv != SECSuccess) { return rv; } SECItem certDER; rv = CERT_DecodeCertPackage(buf, strlen(buf), DecodeCertCallback, &certDER); if (rv != SECSuccess) { PrintPRError("CERT_DecodeCertPackage failed"); return rv; } ScopedCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certDER, nullptr, false, true)); PORT_Free(certDER.data); if (!cert) { PrintPRError("CERT_NewTempCertificate failed"); return SECFailure; } ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { PrintPRError("PK11_GetInternalKeySlot failed"); return SECFailure; } // The nickname is the filename without '.pem'. std::string nickname(filename, strlen(filename) - 4); rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, nickname.c_str(), false); if (rv != SECSuccess) { PrintPRError("PK11_ImportCert failed"); return rv; } return SECSuccess; }
/* From certdb.c */ static SECStatus cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted) { SECStatus rv; SECItem *derCert; CERTCertificate *cert = NULL; CERTCertificate *newcert = NULL; CERTCertDBHandle *handle; CERTCertTrust trust; PRBool isca; char *nickname; unsigned int certtype; handle = CERT_GetDefaultCertDB(); while (numcerts--) { derCert = certs; certs++; /* decode my certificate */ /* This use is ok -- only looks at decoded parts, calls NewTemp later */ newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); if ( newcert == NULL ) { goto loser; } if (!trusted) { /* make sure that cert is valid */ rv = CERT_CertTimesValid(newcert); if ( rv == SECFailure ) { goto endloop; } } /* does it have the CA extension */ /* * Make sure that if this is an intermediate CA in the chain that * it was given permission by its signer to be a CA. */ isca = CERT_IsCACert(newcert, &certtype); if ( !isca ) { if (!trusted) { goto endloop; } trust.sslFlags = CERTDB_VALID_CA; trust.emailFlags = CERTDB_VALID_CA; trust.objectSigningFlags = CERTDB_VALID_CA; } else { /* SSL ca's must have the ssl bit set */ if ( ( certUsage == certUsageSSLCA ) && (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) { goto endloop; } /* it passed all of the tests, so lets add it to the database */ /* mark it as a CA */ PORT_Memset((void *)&trust, 0, sizeof(trust)); switch ( certUsage ) { case certUsageSSLCA: trust.sslFlags = CERTDB_VALID_CA; break; case certUsageUserCertImport: if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { trust.sslFlags = CERTDB_VALID_CA; } if ((certtype & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA ) { trust.emailFlags = CERTDB_VALID_CA; } if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) == NS_CERT_TYPE_OBJECT_SIGNING_CA ) { trust.objectSigningFlags = CERTDB_VALID_CA; } break; default: PORT_Assert(0); break; } } cert = CERT_NewTempCertificate(handle, derCert, NULL, PR_FALSE, PR_FALSE); if ( cert == NULL ) { goto loser; } /* if the cert is temp, make it perm; otherwise we're done */ if (cert->istemp) { /* get a default nickname for it */ nickname = CERT_MakeCANickname(cert); rv = CERT_AddTempCertToPerm(cert, nickname, &trust); /* free the nickname */ if ( nickname ) { PORT_Free(nickname); } } else { rv = SECSuccess; } CERT_DestroyCertificate(cert); cert = NULL; if ( rv != SECSuccess ) { goto loser; } endloop: if ( newcert ) { CERT_DestroyCertificate(newcert); newcert = NULL; } } rv = SECSuccess; goto done; loser: rv = SECFailure; done: if ( newcert ) { CERT_DestroyCertificate(newcert); newcert = NULL; } if ( cert ) { CERT_DestroyCertificate(cert); cert = NULL; } return(rv); }
/** * Get certificate from LDAP-Server. */ static int ldap_get_certificate(const char *login) { LDAP *ldap_connection; int entries; LDAPMessage *res; LDAPMessage *entry; struct berval **bvals = NULL; BerElement *ber = NULL; char *name = NULL; char filter_str[100]; char *attrs[2]; int rv = LDAP_SUCCESS; void *bv_val; char uri[4096]; char uribuf[4096]; char *uris[LDAP_CONFIG_URI_MAX + 1]; const char *p; int current_uri = 0, start_uri = 0; char *buffer; size_t buflen; uris[0] = NULL; attrs[0] = (char *)attribute; attrs[1] = NULL; DBG1("ldap_get_certificate(): begin login = %s", login); /* Put the login to the %s in Filterstring */ snprintf(filter_str, sizeof(filter_str), filter, login); DBG1("ldap_get_certificate(): filter_str = %s", filter_str); /* parse and split URI config entry */ buffer = uribuf; buflen = sizeof (uribuf); strncpy(uri, ldapURI, sizeof (uri)-1); /* Add a space separated list of URIs */ /* TODO: no spaces in one URI allowed => URL-encoding? */ if(strncmp(ldapURI,"",1)) for (p = uri; p != NULL; ) { char *q = strchr (p, ' '); if (q != NULL) *q = '\0'; if( strlen(p) > 1 ) /* SAW: don't add spaces */ rv = ldap_add_uri (uris, p, &buffer, &buflen); p = (q != NULL) ? ++q : NULL; if (rv) break; } /* set the default port if no port is given */ if (ldapport == 0) { if (ssl_on == SSL_LDAPS) { ldapport = LDAPS_PORT; } else { ldapport = LDAP_PORT; } } /* add ldaphost to uris if set, nevermind "uri" is set in config */ if( strlen(ldaphost) > 1 ) { /* No port specified in URI and non-default port specified */ snprintf (uri, sizeof (uri), "%s%s:%d", ssl_on == SSL_LDAPS ? "ldaps://" : "ldap://", ldaphost, ldapport); ldap_add_uri (uris, uri, &buffer, &buflen); } if (uris[0] == NULL) { DBG("ldap_get_certificate(): Nor URI or usable Host entry found"); return(-1); } /* Attempt to connect to specified URI in order until do_open succeed */ start_uri = current_uri; do { if(uris[current_uri] != NULL) DBG1("ldap_get_certificate(): try do_open for %s", uris[current_uri]); rv = do_open(&ldap_connection, uris[current_uri], ldapport, ssl_on); /* hot-fix, because in some circumstances an LDAP_SERVER_DOWN is returned */ if (rv != LDAP_UNAVAILABLE && rv != LDAP_SERVER_DOWN) break; current_uri++; if (uris[current_uri] == NULL) current_uri = 0; } while (current_uri != start_uri); if( rv != LDAP_SUCCESS ) { DBG("ldap_get_certificate(): do_open failed"); return(-2); } /* TODO: (1) The problem: if an working uri is found it is used and if there is an (SSL-)error, no other one is tried (2) There is no session, so we don't know which LDAP_Server is the last with a successful connection. So we try the same server again. Perhaps create a state file/smem/etc. ? */ rv = ldap_search_s( ldap_connection, base, sscope[scope], filter_str, attrs, 0, &res); if ( rv != LDAP_SUCCESS ) { DBG1("ldap_search_s() failed: %s", ldap_err2string(rv)); ldap_unbind_s(ldap_connection); return(-3); } else { entries = ldap_count_entries(ldap_connection, res); DBG1("ldap_get_certificate(): entries = %d", entries); if( entries > 1 ) { DBG("! Warning, more than one entry found. Please choose \"filter\" and"); DBG("! \"attribute\" in ldap mapper config section of your config,"); DBG("! that only one entry with one attribute is matched"); DBG("! Maybe there is another problem in ldap with not unique user"); DBG("! entries in your LDAP server."); } /* Only first entry is used. "filter" and "attribute" * should be choosen, so that only one entry with * one attribute is returned */ if ( NULL == (entry = ldap_first_entry(ldap_connection, res))){ DBG("ldap_first_entry() failed: %s"); ldap_unbind_s(ldap_connection); return(-4); } /* Only first attribute is used. See comment above... */ if ( NULL == (name = ldap_first_attribute(ldap_connection, res, &ber))){ DBG("ldap_first_attribute() failed (rc=%d)"); ldap_unbind_s(ldap_connection); return(-5); } DBG1("attribute name = %s", name); bvals = ldap_get_values_len(ldap_connection, entry, name); certcnt = ldap_count_values_len(bvals); DBG1("number of user certificates = %d", certcnt); ldap_x509 = malloc(sizeof(X509*) * certcnt ); if (NULL == ldap_x509) { DBG("not enough memory"); return(-7); } rv = 0; while(rv < certcnt ) { /* SaW: not nifty, but otherwise gcc doesn't optimize */ bv_val = &bvals[rv]->bv_val; #ifdef HAVE_NSS { SECItem derdata; derdata.data = bv_val; derdata.len = bvals[rv]->bv_len; ldap_x509[rv] = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derdata, NULL, 0, 1); } #else ldap_x509[rv] = d2i_X509(NULL, ((const unsigned char **) bv_val), bvals[rv]->bv_len); #endif if (NULL == ldap_x509[rv]) { DBG1("d2i_X509() failed for certificate %d", rv); free(ldap_x509); #ifdef HAVE_NSS { for (rv=0; rv<certcnt; rv++) if (ldap_x509[rv]) CERT_DestroyCertificate(ldap_x509[rv]); } #endif certcnt=0; ldap_msgfree(res); ldap_unbind_s(ldap_connection); return(-6); }else { DBG1("d2i_X509(): success for certificate %d", rv); } rv++; } ldap_msgfree(res); /* TODO: this leads to a segfault, but the doc said ... */ /* ldap_value_free_len(bvals); */ } if ( 0 != ldap_unbind_s(ldap_connection)) { DBG("ldap_unbind_s() failed."); ldap_perror(ldap_connection, "ldap_unbind_s() failed."); return(-1); }; DBG("ldap_get_certificate(): end"); return 1; }
nsresult VerifyCMSDetachedSignatureIncludingCertificate( const SECItem& buffer, const SECItem& detachedDigest, nsresult (*verifyCertificate)(CERTCertificate* cert, void* context, void* pinArg), void *verifyCertificateContext, void* pinArg) { // XXX: missing pinArg is tolerated. if (NS_WARN_IF(!buffer.data && buffer.len > 0) || NS_WARN_IF(!detachedDigest.data && detachedDigest.len > 0) || (!verifyCertificate) || NS_WARN_IF(!verifyCertificateContext)) { return NS_ERROR_INVALID_ARG; } ScopedNSSCMSMessage cmsMsg(NSS_CMSMessage_CreateFromDER(const_cast<SECItem*>(&buffer), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); if (!cmsMsg) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } if (!NSS_CMSMessage_IsSigned(cmsMsg.get())) { return NS_ERROR_CMS_VERIFY_NOT_SIGNED; } NSSCMSContentInfo* cinfo = NSS_CMSMessage_ContentLevel(cmsMsg.get(), 0); if (!cinfo) { return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; } // signedData is non-owning NSSCMSSignedData* signedData = reinterpret_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(cinfo)); if (!signedData) { return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; } // Set digest value. if (NSS_CMSSignedData_SetDigestValue(signedData, SEC_OID_SHA1, const_cast<SECItem*>(&detachedDigest))) { return NS_ERROR_CMS_VERIFY_BAD_DIGEST; } // Parse the certificates into CERTCertificate objects held in memory so // verifyCertificate will be able to find them during path building. ScopedCERTCertList certs(CERT_NewCertList()); if (!certs) { return NS_ERROR_OUT_OF_MEMORY; } if (signedData->rawCerts) { for (size_t i = 0; signedData->rawCerts[i]; ++i) { ScopedCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), signedData->rawCerts[i], nullptr, false, true)); // Skip certificates that fail to parse if (cert) { if (CERT_AddCertToListTail(certs.get(), cert.get()) == SECSuccess) { cert.forget(); // ownership transfered } else { return NS_ERROR_OUT_OF_MEMORY; } } } } // Get the end-entity certificate. int numSigners = NSS_CMSSignedData_SignerInfoCount(signedData); if (NS_WARN_IF(numSigners != 1)) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } // signer is non-owning. NSSCMSSignerInfo* signer = NSS_CMSSignedData_GetSignerInfo(signedData, 0); if (NS_WARN_IF(!signer)) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } CERTCertificate* signerCert = NSS_CMSSignerInfo_GetSigningCertificate(signer, CERT_GetDefaultCertDB()); if (!signerCert) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } nsresult rv = verifyCertificate(signerCert, verifyCertificateContext, pinArg); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // See NSS_CMSContentInfo_GetContentTypeOID, which isn't exported from NSS. SECOidData* contentTypeOidData = SECOID_FindOID(&signedData->contentInfo.contentType); if (!contentTypeOidData) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } return MapSECStatus(NSS_CMSSignerInfo_Verify(signer, const_cast<SECItem*>(&detachedDigest), &contentTypeOidData->oid)); }
nsresult AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) { SECItem trustedDER; // Load the trusted certificate into the in-memory NSS database so that // CERT_CreateSubjectCertList can find it. switch (trustedRoot) { case nsIX509CertDB::AppMarketplaceProdPublicRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceProdPublicRoot); trustedDER.len = mozilla::ArrayLength(marketplaceProdPublicRoot); break; case nsIX509CertDB::AppMarketplaceProdReviewersRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceProdReviewersRoot); trustedDER.len = mozilla::ArrayLength(marketplaceProdReviewersRoot); break; case nsIX509CertDB::AppMarketplaceDevPublicRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceDevPublicRoot); trustedDER.len = mozilla::ArrayLength(marketplaceDevPublicRoot); break; case nsIX509CertDB::AppMarketplaceDevReviewersRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceDevReviewersRoot); trustedDER.len = mozilla::ArrayLength(marketplaceDevReviewersRoot); break; case nsIX509CertDB::AppMarketplaceStageRoot: trustedDER.data = const_cast<uint8_t*>(marketplaceStageRoot); trustedDER.len = mozilla::ArrayLength(marketplaceStageRoot); // The staging root was generated with a 1024-bit key. mMinRSABits = 1024u; break; case nsIX509CertDB::AppXPCShellRoot: trustedDER.data = const_cast<uint8_t*>(xpcshellRoot); trustedDER.len = mozilla::ArrayLength(xpcshellRoot); break; case nsIX509CertDB::AddonsPublicRoot: trustedDER.data = const_cast<uint8_t*>(addonsPublicRoot); trustedDER.len = mozilla::ArrayLength(addonsPublicRoot); break; case nsIX509CertDB::AddonsStageRoot: trustedDER.data = const_cast<uint8_t*>(addonsStageRoot); trustedDER.len = mozilla::ArrayLength(addonsStageRoot); break; case nsIX509CertDB::PrivilegedPackageRoot: trustedDER.data = const_cast<uint8_t*>(privilegedPackageRoot); trustedDER.len = mozilla::ArrayLength(privilegedPackageRoot); break; case nsIX509CertDB::DeveloperImportedRoot: { StaticMutexAutoLock lock(sMutex); if (!sDevImportedDERData) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1")); if (!file) { return NS_ERROR_FAILURE; } nsresult rv = file->InitWithNativePath( Preferences::GetCString(kDevImportedDER)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsIInputStream> inputStream; rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file, -1, -1, nsIFileInputStream::CLOSE_ON_EOF); if (NS_FAILED(rv)) { return rv; } uint64_t length; rv = inputStream->Available(&length); if (NS_FAILED(rv)) { return rv; } auto data = MakeUnique<char[]>(length); rv = inputStream->Read(data.get(), length, &sDevImportedDERLen); if (NS_FAILED(rv)) { return rv; } MOZ_ASSERT(length == sDevImportedDERLen); sDevImportedDERData.reset( BitwiseCast<unsigned char*, char*>(data.release())); } trustedDER.data = sDevImportedDERData.get(); trustedDER.len = sDevImportedDERLen; break; } default: return NS_ERROR_INVALID_ARG; } mTrustedRoot.reset(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &trustedDER, nullptr, false, true)); if (!mTrustedRoot) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } return NS_OK; }
/* * 'clone' a physical card as a virtual card */ static VCard * vcard_emul_mirror_card(VReader *vreader) { /* * lookup certs using the C_FindObjects. The Stan Cert handle won't give * us the real certs until we log in. */ PK11GenericObject *firstObj, *thisObj; int cert_count; unsigned char **certs; int *cert_len; VCardKey **keys; PK11SlotInfo *slot; PRBool ret; VCard *card; slot = vcard_emul_reader_get_slot(vreader); if (slot == NULL) { return NULL; } firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE); if (firstObj == NULL) { return NULL; } /* count the certs */ cert_count = 0; for (thisObj = firstObj; thisObj; thisObj = PK11_GetNextGenericObject(thisObj)) { cert_count++; } if (cert_count == 0) { PK11_DestroyGenericObjects(firstObj); return NULL; } /* allocate the arrays */ ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count); if (ret == PR_FALSE) { return NULL; } /* fill in the arrays */ cert_count = 0; for (thisObj = firstObj; thisObj; thisObj = PK11_GetNextGenericObject(thisObj)) { SECItem derCert; CERTCertificate *cert; SECStatus rv; rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj, CKA_VALUE, &derCert); if (rv != SECSuccess) { continue; } /* create floating temp cert. This gives us a cert structure even if * the token isn't logged in */ cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert, NULL, PR_FALSE, PR_TRUE); SECITEM_FreeItem(&derCert, PR_FALSE); if (cert == NULL) { continue; } certs[cert_count] = cert->derCert.data; cert_len[cert_count] = cert->derCert.len; keys[cert_count] = vcard_emul_make_key(slot, cert); cert_count++; CERT_DestroyCertificate(cert); /* key obj still has a reference */ } /* now create the card */ card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); g_free(certs); g_free(cert_len); g_free(keys); return card; }
/* nsIX509Cert constructX509FromBase64 (in string base64); */ NS_IMETHODIMP nsNSSCertificateDB::ConstructX509FromBase64(const char * base64, nsIX509Cert **_retval) { if (!_retval) { return NS_ERROR_FAILURE; } nsNSSShutDownPreventionLock locker; PRUint32 len = PL_strlen(base64); int adjust = 0; /* Compute length adjustment */ if (base64[len-1] == '=') { adjust++; if (base64[len-2] == '=') adjust++; } nsresult rv = NS_OK; char *certDER = 0; PRInt32 lengthDER = 0; certDER = PL_Base64Decode(base64, len, NULL); if (!certDER || !*certDER) { rv = NS_ERROR_ILLEGAL_VALUE; } else { lengthDER = (len*3)/4 - adjust; SECItem secitem_cert; secitem_cert.type = siDERCertBuffer; secitem_cert.data = (unsigned char*)certDER; secitem_cert.len = lengthDER; CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert, nsnull, PR_FALSE, PR_TRUE); if (!cert) { rv = NS_ERROR_FAILURE; } else { nsNSSCertificate *nsNSS = new nsNSSCertificate(cert); if (!nsNSS) { rv = NS_ERROR_OUT_OF_MEMORY; } else { nsresult rv = nsNSS->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)_retval); if (NS_SUCCEEDED(rv) && *_retval) { NS_ADDREF(*_retval); } NS_RELEASE(nsNSS); } CERT_DestroyCertificate(cert); } } if (certDER) { nsCRT::free(certDER); } return rv; }
nsresult nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs, nsIInterfaceRequestor *ctx) { // First thing we have to do is figure out which certificate we're // gonna present to the user. The CA may have sent down a list of // certs which may or may not be a chained list of certs. Until // the day we can design some solid UI for the general case, we'll // code to the > 90% case. That case is where a CA sends down a // list that is a hierarchy whose root is either the first or // the last cert. What we're gonna do is compare the first // 2 entries, if the second was signed by the first, we assume // the root cert is the first cert and display it. Otherwise, // we compare the last 2 entries, if the second to last cert was // signed by the last cert, then we assume the last cert is the // root and display it. nsNSSShutDownPreventionLock locker; PRUint32 numCerts; x509Certs->GetLength(&numCerts); NS_ASSERTION(numCerts > 0, "Didn't get any certs to import."); if (numCerts == 0) return NS_OK; // Nothing to import, so nothing to do. nsCOMPtr<nsIX509Cert> certToShow; nsCOMPtr<nsISupports> isupports; PRUint32 selCertIndex; if (numCerts == 1) { // There's only one cert, so let's show it. selCertIndex = 0; certToShow = do_QueryElementAt(x509Certs, selCertIndex); } else { nsCOMPtr<nsIX509Cert> cert0; // first cert nsCOMPtr<nsIX509Cert> cert1; // second cert nsCOMPtr<nsIX509Cert> certn_2; // second to last cert nsCOMPtr<nsIX509Cert> certn_1; // last cert cert0 = do_QueryElementAt(x509Certs, 0); cert1 = do_QueryElementAt(x509Certs, 1); certn_2 = do_QueryElementAt(x509Certs, numCerts-2); certn_1 = do_QueryElementAt(x509Certs, numCerts-1); nsXPIDLString cert0SubjectName; nsXPIDLString cert1IssuerName; nsXPIDLString certn_2IssuerName; nsXPIDLString certn_1SubjectName; cert0->GetSubjectName(cert0SubjectName); cert1->GetIssuerName(cert1IssuerName); certn_2->GetIssuerName(certn_2IssuerName); certn_1->GetSubjectName(certn_1SubjectName); if (cert1IssuerName.Equals(cert0SubjectName)) { // In this case, the first cert in the list signed the second, // so the first cert is the root. Let's display it. selCertIndex = 0; certToShow = cert0; } else if (certn_2IssuerName.Equals(certn_1SubjectName)) { // In this case the last cert has signed the second to last cert. // The last cert is the root, so let's display it. selCertIndex = numCerts-1; certToShow = certn_1; } else { // It's not a chain, so let's just show the first one in the // downloaded list. selCertIndex = 0; certToShow = cert0; } } if (!certToShow) return NS_ERROR_FAILURE; nsCOMPtr<nsICertificateDialogs> dialogs; nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs), NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID); if (NS_FAILED(rv)) return rv; SECItem der; rv=certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data); if (NS_FAILED(rv)) return rv; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); CERTCertificate *tmpCert; CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); tmpCert = CERT_FindCertByDERCert(certdb, &der); if (!tmpCert) { tmpCert = CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE); } nsMemory::Free(der.data); der.data = nsnull; der.len = 0; if (!tmpCert) { NS_ERROR("Couldn't create cert from DER blob\n"); return NS_ERROR_FAILURE; } CERTCertificateCleaner tmpCertCleaner(tmpCert); if (!CERT_IsCACert(tmpCert, NULL)) { DisplayCertificateAlert(ctx, "NotACACert", certToShow); return NS_ERROR_FAILURE; } if (tmpCert->isperm) { DisplayCertificateAlert(ctx, "CaCertExists", certToShow); return NS_ERROR_FAILURE; } PRUint32 trustBits; PRBool allows; rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows); if (NS_FAILED(rv)) return rv; if (!allows) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits)); nsXPIDLCString nickname; nickname.Adopt(CERT_MakeCANickname(tmpCert)); PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); nsNSSCertTrust trust; trust.SetValidCA(); trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL), !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL), !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN)); SECStatus srv = CERT_AddTempCertToPerm(tmpCert, const_cast<char*>(nickname.get()), trust.GetTrust()); if (srv != SECSuccess) return NS_ERROR_FAILURE; // Import additional delivered certificates that can be verified. // build a CertList for filtering CERTCertList *certList = CERT_NewCertList(); if (certList == NULL) { return NS_ERROR_FAILURE; } CERTCertListCleaner listCleaner(certList); // get all remaining certs into temp store for (PRUint32 i=0; i<numCerts; i++) { if (i == selCertIndex) { // we already processed that one continue; } certToShow = do_QueryElementAt(x509Certs, i); certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data); CERTCertificate *tmpCert2 = CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE); nsMemory::Free(der.data); der.data = nsnull; der.len = 0; if (!tmpCert2) { NS_ASSERTION(0, "Couldn't create temp cert from DER blob\n"); continue; // Let's try to import the rest of 'em } CERT_AddCertToListTail(certList, tmpCert2); } return ImportValidCACertsInList(certList, ctx); }
NS_IMETHODIMP nsNSSCertificateDB::ImportServerCertificate(PRUint8 * data, PRUint32 length, nsIInterfaceRequestor *ctx) { nsNSSShutDownPreventionLock locker; SECStatus srv = SECFailure; nsresult nsrv = NS_OK; CERTCertificate * cert; SECItem **rawCerts = nsnull; int numcerts; int i; nsNSSCertTrust trust; char *serverNickname = nsnull; PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) return NS_ERROR_OUT_OF_MEMORY; CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length); if (!certCollection) { PORT_FreeArena(arena, PR_FALSE); return NS_ERROR_FAILURE; } cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts, (char *)NULL, PR_FALSE, PR_TRUE); if (!cert) { nsrv = NS_ERROR_FAILURE; goto loser; } numcerts = certCollection->numcerts; rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts); if ( !rawCerts ) { nsrv = NS_ERROR_FAILURE; goto loser; } for ( i = 0; i < numcerts; i++ ) { rawCerts[i] = &certCollection->rawCerts[i]; } serverNickname = nsNSSCertificate::defaultServerNickname(cert); srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageSSLServer, numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE, serverNickname); PR_FREEIF(serverNickname); if ( srv != SECSuccess ) { nsrv = NS_ERROR_FAILURE; goto loser; } trust.SetValidServerPeer(); srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, trust.GetTrust()); if ( srv != SECSuccess ) { nsrv = NS_ERROR_FAILURE; goto loser; } loser: PORT_Free(rawCerts); if (cert) CERT_DestroyCertificate(cert); if (arena) PORT_FreeArena(arena, PR_TRUE); return nsrv; }
NS_IMETHODIMP nsNSSCertificateDB::ImportUserCertificate(PRUint8 *data, PRUint32 length, nsIInterfaceRequestor *ctx) { nsNSSShutDownPreventionLock locker; PK11SlotInfo *slot; nsCAutoString nickname; nsresult rv = NS_ERROR_FAILURE; int numCACerts; SECItem *CACerts; CERTDERCerts * collectArgs; PRArenaPool *arena; CERTCertificate * cert=NULL; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( arena == NULL ) { goto loser; } collectArgs = getCertsFromPackage(arena, data, length); if (!collectArgs) { goto loser; } cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts, (char *)NULL, PR_FALSE, PR_TRUE); if (!cert) { goto loser; } slot = PK11_KeyForCertExists(cert, NULL, ctx); if ( slot == NULL ) { nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert); DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow); goto loser; } PK11_FreeSlot(slot); /* pick a nickname for the cert */ if (cert->nickname) { /* sigh, we need a call to look up other certs with this subject and * identify nicknames from them. We can no longer walk down internal * database structures rjr */ nickname = cert->nickname; } else { get_default_nickname(cert, ctx, nickname); } /* user wants to import the cert */ { char *cast_const_away = const_cast<char*>(nickname.get()); slot = PK11_ImportCertForKey(cert, cast_const_away, ctx); } if (!slot) { goto loser; } PK11_FreeSlot(slot); { nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert); DisplayCertificateAlert(ctx, "UserCertImported", certToShow); } rv = NS_OK; numCACerts = collectArgs->numcerts - 1; if (numCACerts) { CACerts = collectArgs->rawCerts+1; rv = ImportValidCACerts(numCACerts, CACerts, ctx); } loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } if ( cert ) { CERT_DestroyCertificate(cert); } return rv; }
nsresult Generate() { nsresult rv; // Get the key slot for generation later UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Remove existing certs with this name (if any) rv = RemoveExisting(); if (NS_FAILED(rv)) { return rv; } // Generate a new cert NS_NAMED_LITERAL_CSTRING(commonNamePrefix, "CN="); nsAutoCString subjectNameStr(commonNamePrefix + mNickname); UniqueCERTName subjectName(CERT_AsciiToName(subjectNameStr.get())); if (!subjectName) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Use the well-known NIST P-256 curve SECOidData* curveOidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); if (!curveOidData) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Get key params from the curve ScopedAutoSECItem keyParams(2 + curveOidData->oid.len); keyParams.data[0] = SEC_ASN1_OBJECT_ID; keyParams.data[1] = curveOidData->oid.len; memcpy(keyParams.data + 2, curveOidData->oid.data, curveOidData->oid.len); // Generate cert key pair SECKEYPublicKey* tempPublicKey; UniqueSECKEYPrivateKey privateKey( PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &keyParams, &tempPublicKey, true /* token */, true /* sensitive */, nullptr)); UniqueSECKEYPublicKey publicKey(tempPublicKey); tempPublicKey = nullptr; if (!privateKey || !publicKey) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Create subject public key info and cert request UniqueCERTSubjectPublicKeyInfo spki( SECKEY_CreateSubjectPublicKeyInfo(publicKey.get())); if (!spki) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } UniqueCERTCertificateRequest certRequest( CERT_CreateCertificateRequest(subjectName.get(), spki.get(), nullptr)); if (!certRequest) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Valid from one day before to 1 year after 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(365) * oneDay); UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter)); if (!validity) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Generate random serial unsigned long serial; // This serial in principle could collide, but it's unlikely rv = MapSECStatus(PK11_GenerateRandomOnSlot( slot.get(), BitwiseCast<unsigned char*, unsigned long*>(&serial), sizeof(serial))); if (NS_FAILED(rv)) { return rv; } // Create the cert from these pieces UniqueCERTCertificate cert( CERT_CreateCertificate(serial, subjectName.get(), validity.get(), certRequest.get())); if (!cert) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Update the cert version to X509v3 if (!cert->version.data) { return NS_ERROR_INVALID_POINTER; } *(cert->version.data) = SEC_CERTIFICATE_VERSION_3; cert->version.len = 1; // Set cert signature algorithm PLArenaPool* arena = cert->arena; if (!arena) { return NS_ERROR_INVALID_POINTER; } rv = MapSECStatus( SECOID_SetAlgorithmID(arena, &cert->signature, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0)); if (NS_FAILED(rv)) { return rv; } // Encode and self-sign the cert UniqueSECItem certDER( SEC_ASN1EncodeItem(nullptr, nullptr, cert.get(), SEC_ASN1_GET(CERT_CertificateTemplate))); if (!certDER) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } rv = MapSECStatus( SEC_DerSignData(arena, &cert->derCert, certDER->data, certDER->len, privateKey.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE)); if (NS_FAILED(rv)) { return rv; } // Create a CERTCertificate from the signed data UniqueCERTCertificate certFromDER( CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &cert->derCert, nullptr, true /* perm */, true /* copyDER */)); if (!certFromDER) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Save the cert in the DB rv = MapSECStatus(PK11_ImportCert(slot.get(), certFromDER.get(), CK_INVALID_HANDLE, mNickname.get(), false /* unused */)); if (NS_FAILED(rv)) { return rv; } // We should now have cert in the DB, read it back in nsIX509Cert form return GetFromDB(); }
// We assume ext has been zero-initialized by its constructor and otherwise // not modified. // // TODO(perf): This sorting of extensions should be be moved into the // certificate decoder so that the results are cached with the certificate, so // that the decoding doesn't have to happen more than once per cert. Result BackCert::Init(const SECItem& certDER) { // XXX: Currently-known uses of mozilla::pkix create CERTCertificate objects // for all certs anyway, so the overhead of CERT_NewTempCertificate will be // reduced to a lookup in NSS's SECItem* -> CERTCertificate cache and // a CERT_DupCertificate. Eventually, we should parse the certificate using // mozilla::pkix::der and avoid the need to create a CERTCertificate at all. nssCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), const_cast<SECItem*>(&certDER), nullptr, false, true); if (!nssCert) { return MapSECStatus(SECFailure); } const CERTCertExtension* const* exts = nssCert->extensions; if (!exts) { return Success; } // We only decode v3 extensions for v3 certificates for two reasons. // 1. They make no sense in non-v3 certs // 2. An invalid cert can embed a basic constraints extension and the // check basic constrains will asume that this is valid. Making it // posible to create chains with v1 and v2 intermediates with is // not desirable. if (! (nssCert->version.len == 1 && nssCert->version.data[0] == mozilla::pkix::der::Version::v3)) { return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID); } const SECItem* dummyEncodedSubjectKeyIdentifier = nullptr; const SECItem* dummyEncodedAuthorityKeyIdentifier = nullptr; const SECItem* dummyEncodedAuthorityInfoAccess = nullptr; const SECItem* dummyEncodedSubjectAltName = nullptr; for (const CERTCertExtension* ext = *exts; ext; ext = *++exts) { const SECItem** out = nullptr; // python DottedOIDToCode.py id-ce 2.5.29 static const uint8_t id_ce[] = { 0x55, 0x1d }; // python DottedOIDToCode.py id-pe-authorityInfoAccess 1.3.6.1.5.5.7.1.1 static const uint8_t id_pe_authorityInfoAccess[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01 }; if (ext->id.len == PR_ARRAY_SIZE(id_ce) + 1 && !memcmp(ext->id.data, id_ce, PR_ARRAY_SIZE(id_ce))) { switch (ext->id.data[ext->id.len - 1]) { case 14: out = &dummyEncodedSubjectKeyIdentifier; break; // bug 965136 case 15: out = &encodedKeyUsage; break; case 17: out = &dummyEncodedSubjectAltName; break; // bug 970542 case 19: out = &encodedBasicConstraints; break; case 30: out = &encodedNameConstraints; break; case 32: out = &encodedCertificatePolicies; break; case 35: out = &dummyEncodedAuthorityKeyIdentifier; break; // bug 965136 case 37: out = &encodedExtendedKeyUsage; break; case 54: out = &encodedInhibitAnyPolicy; break; // Bug 989051 } } else if (ext->id.len == PR_ARRAY_SIZE(id_pe_authorityInfoAccess) && !memcmp(ext->id.data, id_pe_authorityInfoAccess, PR_ARRAY_SIZE(id_pe_authorityInfoAccess))) { // We should remember the value of the encoded AIA extension here, but // since our TrustDomain implementations get the OCSP URI using // CERT_GetOCSPAuthorityInfoAccessLocation, we currently don't need to. out = &dummyEncodedAuthorityInfoAccess; } // If this is an extension we don't understand and it's marked critical, // we must reject this certificate. // (The only valid explicit value of the critical flag is TRUE because // it is defined as BOOLEAN DEFAULT FALSE, so we just assume it is true.) if (!out && ext->critical.data && ext->critical.len > 0) { return Fail(RecoverableError, SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); } if (out) { // This is an extension we understand. Save it in results unless we've // already found the extension previously. if (*out) { // Duplicate extension return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID); } *out = &ext->value; } } return Success; }