void GetCertUsageStrings(CERTCertificate* cert, std::vector<std::string>* out) { SECCertificateUsage usages = 0; // TODO(wtc): See if we should use X509Certificate::Verify instead. if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, PR_TRUE, certificateUsageCheckAllUsages, NULL, &usages) == SECSuccess) { static const struct { SECCertificateUsage usage; int string_id; } usage_string_map[] = { {certificateUsageSSLClient, IDS_CERT_USAGE_SSL_CLIENT}, {certificateUsageSSLServer, IDS_CERT_USAGE_SSL_SERVER}, {certificateUsageSSLServerWithStepUp, IDS_CERT_USAGE_SSL_SERVER_WITH_STEPUP}, {certificateUsageEmailSigner, IDS_CERT_USAGE_EMAIL_SIGNER}, {certificateUsageEmailRecipient, IDS_CERT_USAGE_EMAIL_RECEIVER}, {certificateUsageObjectSigner, IDS_CERT_USAGE_OBJECT_SIGNER}, {certificateUsageSSLCA, IDS_CERT_USAGE_SSL_CA}, {certificateUsageStatusResponder, IDS_CERT_USAGE_STATUS_RESPONDER}, }; for (size_t i = 0; i < arraysize(usage_string_map); ++i) { if (usages & usage_string_map[i].usage) out->push_back(l10n_util::GetStringUTF8( usage_string_map[i].string_id)); } } }
nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, PRUint32 aDigestDataLen) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature, content level count %d\n", NSS_CMSMessage_ContentLevelCount(m_cmsMsg))); NSSCMSContentInfo *cinfo = nsnull; NSSCMSSignedData *sigd = nsnull; NSSCMSSignerInfo *si; PRInt32 nsigners; nsresult rv = NS_ERROR_FAILURE; if (!NSS_CMSMessage_IsSigned(m_cmsMsg)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - not signed\n")); return NS_ERROR_CMS_VERIFY_NOT_SIGNED; } cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0); if (cinfo) { // I don't like this hard cast. We should check in some way, that we really have this type. sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo); } if (!sigd) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - no content info\n")); rv = NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; goto loser; } if (aDigestData && aDigestDataLen) { SECItem digest; digest.data = aDigestData; digest.len = aDigestDataLen; if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad digest\n")); rv = NS_ERROR_CMS_VERIFY_BAD_DIGEST; goto loser; } } // Import certs. Note that import failure is not a signature verification failure. // if (NSS_CMSSignedData_ImportCerts(sigd, CERT_GetDefaultCertDB(), certUsageEmailRecipient, PR_TRUE) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not import certs\n")); } nsigners = NSS_CMSSignedData_SignerInfoCount(sigd); PR_ASSERT(nsigners > 0); si = NSS_CMSSignedData_GetSignerInfo(sigd, 0); // See bug 324474. We want to make sure the signing cert is // still valid at the current time. if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), si->cert, PR_TRUE, certificateUsageEmailSigner, si->cmsg->pwfn_arg, NULL) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted now\n")); rv = NS_ERROR_CMS_VERIFY_UNTRUSTED; goto loser; } // We verify the first signer info, only // if (NSS_CMSSignedData_VerifySignerInfo(sigd, 0, CERT_GetDefaultCertDB(), certUsageEmailSigner) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to verify signature\n")); if (NSSCMSVS_SigningCertNotFound == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not found\n")); rv = NS_ERROR_CMS_VERIFY_NOCERT; } else if(NSSCMSVS_SigningCertNotTrusted == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted at signing time\n")); rv = NS_ERROR_CMS_VERIFY_UNTRUSTED; } else if(NSSCMSVS_Unverified == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not verify\n")); rv = NS_ERROR_CMS_VERIFY_ERROR_UNVERIFIED; } else if(NSSCMSVS_ProcessingError == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - processing error\n")); rv = NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } else if(NSSCMSVS_BadSignature == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad signature\n")); rv = NS_ERROR_CMS_VERIFY_BAD_SIGNATURE; } else if(NSSCMSVS_DigestMismatch == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - digest mismatch\n")); rv = NS_ERROR_CMS_VERIFY_DIGEST_MISMATCH; } else if(NSSCMSVS_SignatureAlgorithmUnknown == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo unknown\n")); rv = NS_ERROR_CMS_VERIFY_UNKNOWN_ALGO; } else if(NSSCMSVS_SignatureAlgorithmUnsupported == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo not supported\n")); rv = NS_ERROR_CMS_VERIFY_UNSUPPORTED_ALGO; } else if(NSSCMSVS_MalformedSignature == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - malformed signature\n")); rv = NS_ERROR_CMS_VERIFY_MALFORMED_SIGNATURE; } goto loser; } // Save the profile. Note that save import failure is not a signature verification failure. // if (NSS_SMIMESignerInfo_SaveSMIMEProfile(si) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to save smime profile\n")); } rv = NS_OK; loser: return rv; }
nsresult nsUsageArrayHelper::GetUsagesArray(const char *suffix, bool localOnly, uint32_t outArraySize, uint32_t *_verified, uint32_t *_count, PRUnichar **outUsages) { nsNSSShutDownPreventionLock locker; if (NS_FAILED(m_rv)) return m_rv; if (outArraySize < max_returned_out_array_size) return NS_ERROR_FAILURE; nsCOMPtr<nsINSSComponent> nssComponent; if (!nsNSSComponent::globalConstFlagUsePKIXVerification && localOnly) { nsresult rv; nssComponent = do_GetService(kNSSComponentCID, &rv); if (NS_FAILED(rv)) return rv; if (nssComponent) { nssComponent->SkipOcsp(); } } uint32_t &count = *_count; count = 0; SECCertificateUsage usages = 0; int err = 0; if (!nsNSSComponent::globalConstFlagUsePKIXVerification) { // CERT_VerifyCertificateNow returns SECFailure unless the certificate is // valid for all the given usages. Hoewver, we are only looking for the list // of usages for which the cert *is* valid. (void) CERT_VerifyCertificateNow(defaultcertdb, mCert, true, certificateUsageSSLClient | certificateUsageSSLServer | certificateUsageSSLServerWithStepUp | certificateUsageEmailSigner | certificateUsageEmailRecipient | certificateUsageObjectSigner | certificateUsageSSLCA | certificateUsageStatusResponder, NULL, &usages); err = PR_GetError(); } else { nsresult nsrv; nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv); if (!inss) return nsrv; nsRefPtr<nsCERTValInParamWrapper> survivingParams; if (localOnly) nsrv = inss->GetDefaultCERTValInParamLocalOnly(survivingParams); else nsrv = inss->GetDefaultCERTValInParam(survivingParams); if (NS_FAILED(nsrv)) return nsrv; CERTValOutParam cvout[2]; cvout[0].type = cert_po_usages; cvout[0].value.scalar.usages = 0; cvout[1].type = cert_po_end; CERT_PKIXVerifyCert(mCert, certificateUsageCheckAllUsages, survivingParams->GetRawPointerForNSS(), cvout, NULL); err = PR_GetError(); usages = cvout[0].value.scalar.usages; } // The following list of checks must be < max_returned_out_array_size check(suffix, usages & certificateUsageSSLClient, count, outUsages); check(suffix, usages & certificateUsageSSLServer, count, outUsages); check(suffix, usages & certificateUsageSSLServerWithStepUp, count, outUsages); check(suffix, usages & certificateUsageEmailSigner, count, outUsages); check(suffix, usages & certificateUsageEmailRecipient, count, outUsages); check(suffix, usages & certificateUsageObjectSigner, count, outUsages); #if 0 check(suffix, usages & certificateUsageProtectedObjectSigner, count, outUsages); check(suffix, usages & certificateUsageUserCertImport, count, outUsages); #endif check(suffix, usages & certificateUsageSSLCA, count, outUsages); #if 0 check(suffix, usages & certificateUsageVerifyCA, count, outUsages); #endif check(suffix, usages & certificateUsageStatusResponder, count, outUsages); #if 0 check(suffix, usages & certificateUsageAnyCA, count, outUsages); #endif if (!nsNSSComponent::globalConstFlagUsePKIXVerification && localOnly && nssComponent) { nssComponent->SkipOcspOff(); } if (count == 0) { verifyFailed(_verified, err); } else { *_verified = nsNSSCertificate::VERIFIED_OK; } return NS_OK; }
NS_IMETHODIMP nsNSSCertificate::VerifyForUsage(uint32_t usage, uint32_t *verificationResult) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; NS_ENSURE_ARG(verificationResult); nsresult nsrv; nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv); if (!inss) return nsrv; nsRefPtr<nsCERTValInParamWrapper> survivingParams; nsrv = inss->GetDefaultCERTValInParam(survivingParams); if (NS_FAILED(nsrv)) return nsrv; SECCertificateUsage nss_usage; switch (usage) { case CERT_USAGE_SSLClient: nss_usage = certificateUsageSSLClient; break; case CERT_USAGE_SSLServer: nss_usage = certificateUsageSSLServer; break; case CERT_USAGE_SSLServerWithStepUp: nss_usage = certificateUsageSSLServerWithStepUp; break; case CERT_USAGE_SSLCA: nss_usage = certificateUsageSSLCA; break; case CERT_USAGE_EmailSigner: nss_usage = certificateUsageEmailSigner; break; case CERT_USAGE_EmailRecipient: nss_usage = certificateUsageEmailRecipient; break; case CERT_USAGE_ObjectSigner: nss_usage = certificateUsageObjectSigner; break; case CERT_USAGE_UserCertImport: nss_usage = certificateUsageUserCertImport; break; case CERT_USAGE_VerifyCA: nss_usage = certificateUsageVerifyCA; break; case CERT_USAGE_ProtectedObjectSigner: nss_usage = certificateUsageProtectedObjectSigner; break; case CERT_USAGE_StatusResponder: nss_usage = certificateUsageStatusResponder; break; case CERT_USAGE_AnyCA: nss_usage = certificateUsageAnyCA; break; default: return NS_ERROR_FAILURE; } SECStatus verify_result; if (!nsNSSComponent::globalConstFlagUsePKIXVerification) { CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB(); verify_result = CERT_VerifyCertificateNow(defaultcertdb, mCert, true, nss_usage, NULL, NULL); } else { CERTValOutParam cvout[1]; cvout[0].type = cert_po_end; verify_result = CERT_PKIXVerifyCert(mCert, nss_usage, survivingParams->GetRawPointerForNSS(), cvout, NULL); } if (verify_result == SECSuccess) { *verificationResult = VERIFIED_OK; } else { int err = PR_GetError(); // this list was cloned from verifyFailed switch (err) { case SEC_ERROR_INADEQUATE_KEY_USAGE: case SEC_ERROR_INADEQUATE_CERT_TYPE: *verificationResult = USAGE_NOT_ALLOWED; break; case SEC_ERROR_REVOKED_CERTIFICATE: *verificationResult = CERT_REVOKED; break; case SEC_ERROR_EXPIRED_CERTIFICATE: *verificationResult = CERT_EXPIRED; break; case SEC_ERROR_UNTRUSTED_CERT: *verificationResult = CERT_NOT_TRUSTED; break; case SEC_ERROR_UNTRUSTED_ISSUER: *verificationResult = ISSUER_NOT_TRUSTED; break; case SEC_ERROR_UNKNOWN_ISSUER: *verificationResult = ISSUER_UNKNOWN; break; case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: *verificationResult = SIGNATURE_ALGORITHM_DISABLED; break; case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: *verificationResult = INVALID_CA; break; case SEC_ERROR_CERT_USAGES_INVALID: default: *verificationResult = NOT_VERIFIED_UNKNOWN; break; } } return NS_OK; }
/* Function: SECStatus myAuthCertificate() * * Purpose: This function is our custom certificate authentication handler. * * Note: This implementation is essentially the same as the default * SSL_AuthCertificate(). */ SECStatus myAuthCertificate(void *arg, PRFileDesc *socket, PRBool checksig, PRBool isServer) { SECCertificateUsage certUsage; CERTCertificate * cert; void * pinArg; char * hostName; SECStatus secStatus; if (!arg || !socket) { errWarn("myAuthCertificate"); return SECFailure; } /* Define how the cert is being used based upon the isServer flag. */ certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer; cert = SSL_PeerCertificate(socket); pinArg = SSL_RevealPinArg(socket); if (dumpChain == PR_TRUE) { dumpCertChain(cert, certUsage); } secStatus = CERT_VerifyCertificateNow((CERTCertDBHandle *)arg, cert, checksig, certUsage, pinArg, NULL); /* If this is a server, we're finished. */ if (isServer || secStatus != SECSuccess) { SECU_printCertProblems(stderr, (CERTCertDBHandle *)arg, cert, checksig, certUsage, pinArg, PR_FALSE); CERT_DestroyCertificate(cert); return secStatus; } /* Certificate is OK. Since this is the client side of an SSL * connection, we need to verify that the name field in the cert * matches the desired hostname. This is our defense against * man-in-the-middle attacks. */ /* SSL_RevealURL returns a hostName, not an URL. */ hostName = SSL_RevealURL(socket); if (hostName && hostName[0]) { secStatus = CERT_VerifyCertName(cert, hostName); } else { PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0); secStatus = SECFailure; } if (hostName) PR_Free(hostName); CERT_DestroyCertificate(cert); return secStatus; }