// 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; }
static nsresult AppendErrorTextMismatch(const nsString& host, nsIX509Cert* ix509, nsINSSComponent* component, bool wantsHtml, nsString& returnedMessage) { // Prepare a default "not valid for <hostname>" string in case anything // goes wrong (or in case the certificate is not valid for any hostnames). nsAutoString notValidForHostnameString; const char16_t* params[1]; params[0] = host.get(); nsresult rv = component->PIPBundleFormatStringFromName( "certErrorMismatch", params, 1, notValidForHostnameString); if (NS_FAILED(rv)) { return rv; } notValidForHostnameString.Append('\n'); UniqueCERTCertificate nssCert(ix509->GetCert()); if (!nssCert) { returnedMessage.Append(notValidForHostnameString); return NS_OK; } nsAutoString allNames; uint32_t nameCount = GetSubjectAltNames(nssCert.get(), allNames); if (nameCount == 0) { returnedMessage.Append(notValidForHostnameString); } else if (nameCount > 1) { nsString message; rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple", message); if (NS_FAILED(rv)) { return rv; } returnedMessage.Append(message); returnedMessage.AppendLiteral("\n "); returnedMessage.Append(allNames); returnedMessage.AppendLiteral(" \n"); } else if (nameCount == 1) { params[0] = allNames.get(); const char* stringID = wantsHtml ? "certErrorMismatchSingle2" : "certErrorMismatchSinglePlain"; nsAutoString formattedString; rv = component->PIPBundleFormatStringFromName(stringID, params, 1, formattedString); if (NS_FAILED(rv)) { return rv; } returnedMessage.Append(formattedString); returnedMessage.Append('\n'); } return NS_OK; }
static void AppendErrorTextMismatch(const nsString &host, nsIX509Cert* ix509, nsINSSComponent *component, bool wantsHtml, nsString &returnedMessage) { const char16_t *params[1]; nsresult rv; ScopedCERTCertificate nssCert(ix509->GetCert()); if (!nssCert) { // We are unable to extract the valid names, say "not valid for name". params[0] = host.get(); nsString formattedString; rv = component->PIPBundleFormatStringFromName("certErrorMismatch", params, 1, formattedString); if (NS_SUCCEEDED(rv)) { returnedMessage.Append(formattedString); returnedMessage.Append('\n'); } return; } nsString allNames; uint32_t nameCount = 0; bool useSAN = false; if (nssCert) useSAN = GetSubjectAltNames(nssCert.get(), component, allNames, nameCount); if (!useSAN) { char *certName = CERT_GetCommonName(&nssCert->subject); if (certName) { nsDependentCSubstring commonName(certName, strlen(certName)); if (IsUTF8(commonName)) { // Bug 1024781 // We should actually check that the common name is a valid dns name or // ip address and not any string value before adding it to the display // list. ++nameCount; allNames.Assign(NS_ConvertUTF8toUTF16(commonName)); } PORT_Free(certName); } } if (nameCount > 1) { nsString message; rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple", message); if (NS_SUCCEEDED(rv)) { returnedMessage.Append(message); returnedMessage.AppendLiteral("\n "); returnedMessage.Append(allNames); returnedMessage.AppendLiteral(" \n"); } } else if (nameCount == 1) { const char16_t *params[1]; params[0] = allNames.get(); const char *stringID; if (wantsHtml) stringID = "certErrorMismatchSingle2"; else stringID = "certErrorMismatchSinglePlain"; nsString formattedString; rv = component->PIPBundleFormatStringFromName(stringID, params, 1, formattedString); if (NS_SUCCEEDED(rv)) { returnedMessage.Append(formattedString); returnedMessage.Append('\n'); } } else { // nameCount == 0 nsString message; nsresult rv = component->GetPIPNSSBundleString("certErrorMismatchNoNames", message); if (NS_SUCCEEDED(rv)) { returnedMessage.Append(message); returnedMessage.Append('\n'); } } }