/* * Lookup a certificate in the database by name */ CERTCertificate * CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr) { CERTName *name; SECItem *nameItem; CERTCertificate *cert = NULL; PRArenaPool *arena = NULL; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( arena == NULL ) { goto loser; } name = CERT_AsciiToName(nameStr); if ( name ) { nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name, CERT_NameTemplate); if ( nameItem != NULL ) { cert = CERT_FindCertByName(handle, nameItem); } CERT_DestroyName(name); } loser: if ( arena ) { PORT_FreeArena(arena, PR_FALSE); } return(cert); }
static CERTSignedCrl * FindCRL(CERTCertDBHandle *certHandle, char *name, int type) { CERTSignedCrl *crl = NULL; CERTCertificate *cert = NULL; SECItem derName; derName.data = NULL; derName.len = 0; cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name); if (!cert) { CERTName *certName = NULL; PLArenaPool *arena = NULL; SECStatus rv = SECSuccess; certName = CERT_AsciiToName(name); if (certName) { arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena) { SECItem *nameItem = SEC_ASN1EncodeItem(arena, NULL, (void *)certName, SEC_ASN1_GET(CERT_NameTemplate)); if (nameItem) { rv = SECITEM_CopyItem(NULL, &derName, nameItem); } PORT_FreeArena(arena, PR_FALSE); } CERT_DestroyName(certName); } if (rv != SECSuccess) { SECU_PrintError(progName, "SECITEM_CopyItem failed, out of memory"); return ((CERTSignedCrl *)NULL); } if (!derName.len || !derName.data) { SECU_PrintError(progName, "could not find certificate named '%s'", name); return ((CERTSignedCrl *)NULL); } } else { SECITEM_CopyItem(NULL, &derName, &cert->derSubject); CERT_DestroyCertificate(cert); } crl = SEC_FindCrlByName(certHandle, &derName, type); if (crl == NULL) SECU_PrintError(progName, "could not find %s's CRL", name); if (derName.data) { SECITEM_FreeItem(&derName, PR_FALSE); } return (crl); }
/****************************************************************** * * m a k e _ c e r t _ r e q u e s t */ static CERTCertificateRequest* make_cert_request(char *subject, SECKEYPublicKey *pubk) { CERTName * subj; CERTSubjectPublicKeyInfo * spki; CERTCertificateRequest * req; /* Create info about public key */ spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); if (!spki) { SECU_PrintError(progName, "unable to create subject public key"); exit (ERRX); } subj = CERT_AsciiToName (subject); if (subj == NULL) { FatalError("Invalid data in certificate description"); } /* Generate certificate request */ req = CERT_CreateCertificateRequest(subj, spki, 0); if (!req) { SECU_PrintError(progName, "unable to make certificate request"); exit (ERRX); } SECKEY_DestroySubjectPublicKeyInfo(spki); CERT_DestroyName(subj); if (verbosity >= 0) { PR_fprintf(outputFD, "certificate request generated\n"); } return req; }
static nsresult GetAttestationCertificate(const UniquePK11SlotInfo& aSlot, /*out*/ UniqueSECKEYPrivateKey& aAttestPrivKey, /*out*/ UniqueCERTCertificate& aAttestCert, const nsNSSShutDownPreventionLock& locker) { MOZ_ASSERT(aSlot); if (NS_WARN_IF(!aSlot)) { return NS_ERROR_INVALID_ARG; } UniqueSECKEYPublicKey pubKey; // Construct an ephemeral keypair for this Attestation Certificate nsresult rv = GenEcKeypair(aSlot, aAttestPrivKey, pubKey, locker); if (NS_WARN_IF(NS_FAILED(rv) || !aAttestPrivKey || !pubKey)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen keypair, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } // Construct the Attestation Certificate itself UniqueCERTName subjectName(CERT_AsciiToName(kAttestCertSubjectName.get())); if (NS_WARN_IF(!subjectName)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to set subject name, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } UniqueCERTSubjectPublicKeyInfo spki( SECKEY_CreateSubjectPublicKeyInfo(pubKey.get())); if (NS_WARN_IF(!spki)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to set SPKI, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } UniqueCERTCertificateRequest certreq( CERT_CreateCertificateRequest(subjectName.get(), spki.get(), nullptr)); if (NS_WARN_IF(!certreq)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen CSR, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } PRTime now = PR_Now(); PRTime notBefore = now - kExpirationSlack; PRTime notAfter = now + kExpirationLife; UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter)); if (NS_WARN_IF(!validity)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen validity, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } unsigned long serial; unsigned char* serialBytes = mozilla::BitwiseCast<unsigned char*, unsigned long*>(&serial); SECStatus srv = PK11_GenerateRandomOnSlot(aSlot.get(), serialBytes, sizeof(serial)); if (NS_WARN_IF(srv != SECSuccess)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen serial, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } // Ensure that the most significant bit isn't set (which would // indicate a negative number, which isn't valid for serial // numbers). serialBytes[0] &= 0x7f; // Also ensure that the least significant bit on the most // significant byte is set (to prevent a leading zero byte, // which also wouldn't be valid). serialBytes[0] |= 0x01; aAttestCert = UniqueCERTCertificate( CERT_CreateCertificate(serial, subjectName.get(), validity.get(), certreq.get())); if (NS_WARN_IF(!aAttestCert)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen certificate, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } PLArenaPool* arena = aAttestCert->arena; srv = SECOID_SetAlgorithmID(arena, &aAttestCert->signature, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, /* wincx */ nullptr); if (NS_WARN_IF(srv != SECSuccess)) { return NS_ERROR_FAILURE; } // Set version to X509v3. *(aAttestCert->version.data) = SEC_CERTIFICATE_VERSION_3; aAttestCert->version.len = 1; SECItem innerDER = { siBuffer, nullptr, 0 }; if (NS_WARN_IF(!SEC_ASN1EncodeItem(arena, &innerDER, aAttestCert.get(), SEC_ASN1_GET(CERT_CertificateTemplate)))) { return NS_ERROR_FAILURE; } SECItem* signedCert = PORT_ArenaZNew(arena, SECItem); if (NS_WARN_IF(!signedCert)) { return NS_ERROR_FAILURE; } srv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len, aAttestPrivKey.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE); if (NS_WARN_IF(srv != SECSuccess)) { return NS_ERROR_FAILURE; } aAttestCert->derCert = *signedCert; MOZ_LOG(gNSSTokenLog, LogLevel::Debug, ("U2F Soft Token attestation certificate generated.")); return NS_OK; }
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(); }
/* * FUNCTION: PKIX_PL_GeneralName_Create (see comments in pkix_pl_pki.h) */ PKIX_Error * PKIX_PL_GeneralName_Create( PKIX_UInt32 nameType, PKIX_PL_String *stringRep, PKIX_PL_GeneralName **pGName, void *plContext) { PKIX_PL_X500Name *pkixDN = NULL; PKIX_PL_OID *pkixOID = NULL; SECItem *secItem = NULL; char *asciiString = NULL; PKIX_UInt32 length = 0; PKIX_PL_GeneralName *genName = NULL; CERTGeneralName *nssGenName = NULL; CERTGeneralNameList *nssGenNameList = NULL; CERTName *nssCertName = NULL; PLArenaPool *arena = NULL; PKIX_ENTER(GENERALNAME, "PKIX_PL_GeneralName_Create"); PKIX_NULLCHECK_TWO(pGName, stringRep); PKIX_CHECK(PKIX_PL_String_GetEncoded (stringRep, PKIX_ESCASCII, (void **)&asciiString, &length, plContext), PKIX_STRINGGETENCODEDFAILED); /* Create a temporary CERTGeneralName */ PKIX_GENERALNAME_DEBUG("\t\tCalling PL_strlen).\n"); length = PL_strlen(asciiString); PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_AllocItem).\n"); secItem = SECITEM_AllocItem(NULL, NULL, length); PKIX_GENERALNAME_DEBUG("\t\tCalling PORT_Memcpy).\n"); (void) PORT_Memcpy(secItem->data, asciiString, length); PKIX_CERT_DEBUG("\t\tCalling PORT_NewArena).\n"); arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { PKIX_ERROR(PKIX_OUTOFMEMORY); } PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_NewGeneralName).\n"); nssGenName = CERT_NewGeneralName(arena, nameType); if (nssGenName == NULL) { PKIX_ERROR(PKIX_ALLOCATENEWCERTGENERALNAMEFAILED); } switch (nameType) { case certRFC822Name: case certDNSName: case certURI: nssGenName->name.other = *secItem; break; case certDirectoryName: PKIX_CHECK(PKIX_PL_X500Name_Create (stringRep, &pkixDN, plContext), PKIX_X500NAMECREATEFAILED); PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_AsciiToName).\n"); nssCertName = CERT_AsciiToName(asciiString); nssGenName->name.directoryName = *nssCertName; break; case certRegisterID: PKIX_CHECK(PKIX_PL_OID_Create (asciiString, &pkixOID, plContext), PKIX_OIDCREATEFAILED); nssGenName->name.other = *secItem; break; default: /* including IPAddress, EDIPartyName, OtherName, X400Address */ PKIX_ERROR(PKIX_UNABLETOCREATEGENERALNAMEOFTHISTYPE); } /* create a PKIX_PL_GeneralName object */ PKIX_CHECK(PKIX_PL_Object_Alloc (PKIX_GENERALNAME_TYPE, sizeof (PKIX_PL_GeneralName), (PKIX_PL_Object **)&genName, plContext), PKIX_COULDNOTCREATEOBJECT); /* create a CERTGeneralNameList */ nssGenName->type = nameType; PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_CreateGeneralNameList).\n"); nssGenNameList = CERT_CreateGeneralNameList(nssGenName); if (nssGenNameList == NULL) { PKIX_ERROR(PKIX_CERTCREATEGENERALNAMELISTFAILED); } genName->nssGeneralNameList = nssGenNameList; /* initialize fields */ genName->type = nameType; genName->directoryName = pkixDN; genName->OthName = NULL; genName->other = secItem; genName->oid = pkixOID; *pGName = genName; cleanup: PKIX_FREE(asciiString); if (nssCertName != NULL) { PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyName).\n"); CERT_DestroyName(nssCertName); } if (arena){ /* will free nssGenName */ PKIX_CERT_DEBUG("\t\tCalling PORT_FreeArena).\n"); PORT_FreeArena(arena, PR_FALSE); } if (PKIX_ERROR_RECEIVED){ PKIX_DECREF(pkixDN); PKIX_DECREF(pkixOID); PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); if (secItem){ SECITEM_FreeItem(secItem, PR_TRUE); secItem = NULL; } } PKIX_RETURN(GENERALNAME); }
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(); }