// Tests that a critical extension not in the id-ce or id-pe arcs (which is // thus unknown to us) is detected and that verification fails with the // appropriate error. TEST_F(pkix_cert_extensions, UnknownCriticalExtension) { static const uint8_t unknownCriticalExtensionBytes[] = { 0x30, 0x19, // SEQUENCE (length = 25) 0x06, 0x12, // OID (length = 18) // 1.3.6.1.4.1.13769.666.666.666.1.500.9.3 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03, 0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE 0x04, 0x00 // OCTET STRING (length = 0) }; static const SECItem unknownCriticalExtension = { siBuffer, const_cast<unsigned char*>(unknownCriticalExtensionBytes), sizeof(unknownCriticalExtensionBytes) }; const char* certCN = "CN=Cert With Unknown Critical Extension"; ScopedSECKEYPrivateKey key; ScopedCERTCertificate cert; ASSERT_TRUE(CreateCert(arena.get(), certCN, &unknownCriticalExtension, key, cert)); ScopedCERTCertList results; ASSERT_SECFailure(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, BuildCertChain(trustDomain, cert.get(), now, EndEntityOrCA::MustBeEndEntity, 0, // key usage KeyPurposeId::anyExtendedKeyUsage, CertPolicyId::anyPolicy, nullptr, // stapled OCSP response results)); }
// Creates a self-signed certificate with the given extension. static bool CreateCert(PLArenaPool* arena, const char* subjectStr, const SECItem* extension, /*out*/ ScopedSECKEYPrivateKey& subjectKey, /*out*/ ScopedCERTCertificate& subjectCert) { static long serialNumberValue = 0; ++serialNumberValue; const SECItem* serialNumber(CreateEncodedSerialNumber(arena, serialNumberValue)); if (!serialNumber) { return false; } const SECItem* issuerDER(ASCIIToDERName(arena, subjectStr)); if (!issuerDER) { return false; } const SECItem* subjectDER(ASCIIToDERName(arena, subjectStr)); if (!subjectDER) { return false; } const SECItem* extensions[2] = { extension, nullptr }; SECItem* certDER(CreateEncodedCertificate(arena, v3, SEC_OID_SHA256, serialNumber, issuerDER, PR_Now() - ONE_DAY, PR_Now() + ONE_DAY, subjectDER, extensions, nullptr, SEC_OID_SHA256, subjectKey)); if (!certDER) { return false; } subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDER, nullptr, false, true); return subjectCert.get() != nullptr; }
NS_IMETHODIMP nsNSSCertificateDB::ImportUserCertificate(uint8_t *data, uint32_t length, nsIInterfaceRequestor *ctx) { if (!NS_IsMainThread()) { NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread"); return NS_ERROR_NOT_SAME_THREAD; } nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) { return NS_ERROR_NOT_AVAILABLE; } ScopedPK11SlotInfo slot; nsAutoCString nickname; nsresult rv = NS_ERROR_FAILURE; int numCACerts; SECItem *CACerts; CERTDERCerts * collectArgs; PLArenaPool *arena; ScopedCERTCertificate cert; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { goto loser; } collectArgs = getCertsFromPackage(arena, data, length, locker); if (!collectArgs) { goto loser; } cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts, nullptr, false, true); if (!cert) { goto loser; } slot = PK11_KeyForCertExists(cert.get(), nullptr, ctx); if (!slot) { nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get()); DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker); goto loser; } slot = nullptr; /* 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.get(), ctx, nickname, locker); } /* user wants to import the cert */ { char *cast_const_away = const_cast<char*>(nickname.get()); slot = PK11_ImportCertForKey(cert.get(), cast_const_away, ctx); } if (!slot) { goto loser; } slot = nullptr; { nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get()); DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker); } rv = NS_OK; numCACerts = collectArgs->numcerts - 1; if (numCACerts) { CACerts = collectArgs->rawCerts+1; rv = ImportValidCACerts(numCACerts, CACerts, ctx, locker); } loser: if (arena) { PORT_FreeArena(arena, false); } return rv; }
SECItemArray * GetOCSPResponseForType(OCSPResponseType aORT, CERTCertificate *aCert, PLArenaPool *aArena, const char *aAdditionalCertName) { if (aORT == ORTNone) { if (gDebugLevel >= DEBUG_WARNINGS) { fprintf(stderr, "GetOCSPResponseForType called with type ORTNone, " "which makes no sense.\n"); } return nullptr; } if (aORT == ORTEmpty) { SECItemArray* arr = SECITEM_AllocArray(aArena, nullptr, 1); arr->items[0].data = nullptr; arr->items[0].len = 0; return arr; } PRTime now = PR_Now(); PRTime oneDay = 60*60*24 * (PRTime)PR_USEC_PER_SEC; PRTime oldNow = now - (8 * oneDay); OCSPResponseContext context(aArena, aCert, now); if (aORT == ORTGoodOtherCert) { context.cert = PK11_FindCertFromNickname(aAdditionalCertName, nullptr); if (!context.cert) { PrintPRError("PK11_FindCertFromNickname failed"); return nullptr; } } // XXX CERT_FindCertIssuer uses the old, deprecated path-building logic ScopedCERTCertificate issuerCert(CERT_FindCertIssuer(aCert, now, certUsageSSLCA)); if (!issuerCert) { PrintPRError("CERT_FindCertIssuer failed"); return nullptr; } context.issuerNameDER = &issuerCert->derSubject; context.issuerSPKI = &issuerCert->subjectPublicKeyInfo; ScopedCERTCertificate signerCert; if (aORT == ORTGoodOtherCA || aORT == ORTDelegatedIncluded || aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissing || aORT == ORTDelegatedMissingMultiple) { signerCert = PK11_FindCertFromNickname(aAdditionalCertName, nullptr); if (!signerCert) { PrintPRError("PK11_FindCertFromNickname failed"); return nullptr; } } const SECItem* certs[5] = { nullptr, nullptr, nullptr, nullptr, nullptr }; if (aORT == ORTDelegatedIncluded) { certs[0] = &signerCert->derCert; context.certs = certs; } if (aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissingMultiple) { certs[0] = &issuerCert->derCert; certs[1] = &context.cert->derCert; certs[2] = &issuerCert->derCert; if (aORT != ORTDelegatedMissingMultiple) { certs[3] = &signerCert->derCert; } context.certs = certs; } switch (aORT) { case ORTMalformed: context.responseStatus = 1; break; case ORTSrverr: context.responseStatus = 2; break; case ORTTryLater: context.responseStatus = 3; break; case ORTNeedsSig: context.responseStatus = 5; break; case ORTUnauthorized: context.responseStatus = 6; break; default: // context.responseStatus is 0 in all other cases, and it has // already been initialized in the constructor. break; } if (aORT == ORTSkipResponseBytes) { context.skipResponseBytes = true; } if (aORT == ORTExpired || aORT == ORTExpiredFreshCA) { context.thisUpdate = oldNow; context.nextUpdate = oldNow + 10 * PR_USEC_PER_SEC; } if (aORT == ORTRevoked) { context.certStatus = 1; } if (aORT == ORTUnknown) { context.certStatus = 2; } if (aORT == ORTBadSignature) { context.badSignature = true; } OCSPResponseExtension extension; if (aORT == ORTCriticalExtension || aORT == ORTNoncriticalExtension) { SECItem oidItem = { siBuffer, nullptr, 0 }; // 1.3.6.1.4.1.13769.666.666.666 is the root of Mozilla's testing OID space static const char* testExtensionOID = "1.3.6.1.4.1.13769.666.666.666.1.500.9.2"; if (SEC_StringToOID(aArena, &oidItem, testExtensionOID, PL_strlen(testExtensionOID)) != SECSuccess) { return nullptr; } DERTemplate oidTemplate[2] = { { DER_OBJECT_ID, 0 }, { 0 } }; extension.id.data = nullptr; extension.id.len = 0; if (DER_Encode(aArena, &extension.id, oidTemplate, &oidItem) != SECSuccess) { return nullptr; } extension.critical = (aORT == ORTCriticalExtension); static const uint8_t value[2] = { 0x05, 0x00 }; extension.value.data = const_cast<uint8_t*>(value); extension.value.len = PR_ARRAY_SIZE(value); extension.next = nullptr; context.extensions = &extension; } if (aORT == ORTEmptyExtensions) { context.includeEmptyExtensions = true; } if (!signerCert) { signerCert = CERT_DupCertificate(issuerCert.get()); } context.signerPrivateKey = PK11_FindKeyByAnyCert(signerCert.get(), nullptr); if (!context.signerPrivateKey) { PrintPRError("PK11_FindKeyByAnyCert failed"); return nullptr; } SECItem* response = CreateEncodedOCSPResponse(context); if (!response) { PrintPRError("CreateEncodedOCSPResponse failed"); return nullptr; } SECItemArray* arr = SECITEM_AllocArray(aArena, nullptr, 1); if (!arr) { PrintPRError("SECITEM_AllocArray failed"); return nullptr; } arr->items[0].data = response->data; arr->items[0].len = response->len; return arr; }