Bug 1005142 - Part 1/2 - Add OCSP get capabilities to OCSPRequestor. r=keeler

--HG--
extra : rebase_source : ee4a86bf02a466a31de8b0b6cd7ce375a7f28c6d
This commit is contained in:
Camilo Viecco 2014-05-21 15:42:21 -07:00
parent 6fe994703a
commit f051695b8d
5 changed files with 85 additions and 25 deletions

View File

@ -374,8 +374,10 @@ CertVerifier::MozillaPKIXVerifyCert(
: !mOCSPStrict ? NSSCertDBTrustDomain::FetchOCSPForDVSoftFail
: NSSCertDBTrustDomain::FetchOCSPForDVHardFail;
SECStatus rv;
ocsp_get_config ocspGETConfig = mOCSPGETEnabled ? ocsp_get_enabled
: ocsp_get_disabled;
SECStatus rv;
// TODO(bug 970750): anyExtendedKeyUsage
// TODO: encipherOnly/decipherOnly
// S/MIME Key Usage: http://tools.ietf.org/html/rfc3850#section-4.4.2
@ -390,7 +392,7 @@ CertVerifier::MozillaPKIXVerifyCert(
// XXX: We don't really have a trust bit for SSL client authentication so
// just use trustEmail as it is the closest alternative.
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg);
pinArg, ocspGETConfig);
rv = BuildCertChain(trustDomain, cert, time,
EndEntityOrCA::MustBeEndEntity, KU_DIGITAL_SIGNATURE,
KeyPurposeId::id_kp_clientAuth,
@ -415,7 +417,7 @@ CertVerifier::MozillaPKIXVerifyCert(
ocspFetching == NSSCertDBTrustDomain::NeverFetchOCSP
? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
: NSSCertDBTrustDomain::FetchOCSPForEV,
mOCSPCache, pinArg, &callbackContainer);
mOCSPCache, pinArg, ocspGETConfig, &callbackContainer);
rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
KU_DIGITAL_SIGNATURE, // ECDHE/DHE
KU_KEY_ENCIPHERMENT, // RSA
@ -441,7 +443,8 @@ CertVerifier::MozillaPKIXVerifyCert(
// Now try non-EV.
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
pinArg, &callbackContainer);
pinArg, ocspGETConfig,
&callbackContainer);
rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
KU_DIGITAL_SIGNATURE, // ECDHE/DHE
KU_KEY_ENCIPHERMENT, // RSA
@ -454,7 +457,7 @@ CertVerifier::MozillaPKIXVerifyCert(
case certificateUsageSSLCA: {
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
pinArg);
pinArg, ocspGETConfig);
rv = BuildCertChain(trustDomain, cert, time, EndEntityOrCA::MustBeCA,
KU_KEY_CERT_SIGN, KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy,
@ -464,7 +467,7 @@ CertVerifier::MozillaPKIXVerifyCert(
case certificateUsageEmailSigner: {
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg);
pinArg, ocspGETConfig);
rv = BuildCertChain(trustDomain, cert, time,
EndEntityOrCA::MustBeEndEntity, KU_DIGITAL_SIGNATURE,
KeyPurposeId::id_kp_emailProtection,
@ -478,7 +481,7 @@ CertVerifier::MozillaPKIXVerifyCert(
// usage it is trying to verify for, and base its algorithm choices
// based on the result of the verification(s).
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg);
pinArg, ocspGETConfig);
rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
KU_KEY_ENCIPHERMENT, // RSA
KU_KEY_AGREEMENT, // ECDH/DH
@ -491,7 +494,7 @@ CertVerifier::MozillaPKIXVerifyCert(
case certificateUsageObjectSigner: {
NSSCertDBTrustDomain trustDomain(trustObjectSigning, ocspFetching,
mOCSPCache, pinArg);
mOCSPCache, pinArg, ocspGETConfig);
rv = BuildCertChain(trustDomain, cert, time,
EndEntityOrCA::MustBeEndEntity, KU_DIGITAL_SIGNATURE,
KeyPurposeId::id_kp_codeSigning,
@ -520,20 +523,20 @@ CertVerifier::MozillaPKIXVerifyCert(
}
NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache,
pinArg);
pinArg, ocspGETConfig);
rv = BuildCertChain(sslTrust, cert, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse, builtChain);
if (rv == SECFailure && PR_GetError() == SEC_ERROR_UNKNOWN_ISSUER) {
NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, mOCSPCache,
pinArg);
pinArg, ocspGETConfig);
rv = BuildCertChain(emailTrust, cert, time, endEntityOrCA, keyUsage,
eku, CertPolicyId::anyPolicy,
stapledOCSPResponse, builtChain);
if (rv == SECFailure && SEC_ERROR_UNKNOWN_ISSUER) {
NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
ocspFetching, mOCSPCache,
pinArg);
pinArg, ocspGETConfig);
rv = BuildCertChain(objectSigningTrust, cert, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse, builtChain);

View File

@ -44,11 +44,13 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
OCSPFetching ocspFetching,
OCSPCache& ocspCache,
void* pinArg,
CertVerifier::ocsp_get_config ocspGETConfig,
CERTChainVerifyCallback* checkChainCallback)
: mCertDBTrustType(certDBTrustType)
, mOCSPFetching(ocspFetching)
, mOCSPCache(ocspCache)
, mPinArg(pinArg)
, mOCSPGetConfig(ocspGETConfig)
, mCheckChainCallback(checkChainCallback)
{
}
@ -338,7 +340,8 @@ NSSCertDBTrustDomain::CheckRevocation(
}
response = DoOCSPRequest(arena.get(), url.get(), request,
OCSPFetchingTypeToTimeoutTime(mOCSPFetching));
OCSPFetchingTypeToTimeoutTime(mOCSPFetching),
mOCSPGetConfig == CertVerifier::ocsp_get_enabled);
}
if (!response) {

View File

@ -58,6 +58,7 @@ public:
};
NSSCertDBTrustDomain(SECTrustType certDBTrustType, OCSPFetching ocspFetching,
OCSPCache& ocspCache, void* pinArg,
CertVerifier::ocsp_get_config ocspGETConfig,
CERTChainVerifyCallback* checkChainCallback = nullptr);
virtual SECStatus FindPotentialIssuers(
@ -95,6 +96,7 @@ private:
const OCSPFetching mOCSPFetching;
OCSPCache& mOCSPCache; // non-owning!
void* mPinArg; // non-owning!
const CertVerifier::ocsp_get_config mOCSPGetConfig;
CERTChainVerifyCallback* mCheckChainCallback; // non-owning!
};

View File

@ -6,6 +6,7 @@
#include "OCSPRequestor.h"
#include "mozilla/Base64.h"
#include "nsIURLParser.h"
#include "nsNSSCallbacks.h"
#include "nsNetCID.h"
@ -13,6 +14,10 @@
#include "pkix/ScopedPtr.h"
#include "secerr.h"
#ifdef PR_LOGGING
extern PRLogModuleInfo* gCertVerifierLog;
#endif
namespace mozilla { namespace psm {
using mozilla::pkix::ScopedPtr;
@ -33,8 +38,36 @@ ReleaseHttpRequestSession(nsNSSHttpRequestSession* httpRequestSession)
typedef ScopedPtr<nsNSSHttpRequestSession, ReleaseHttpRequestSession>
ScopedHTTPRequestSession;
SECItem* DoOCSPRequest(PLArenaPool* arena, const char* url,
const SECItem* encodedRequest, PRIntervalTime timeout)
static nsresult
AppendEscapedBase64Item(const SECItem* encodedRequest, nsACString& path)
{
nsresult rv;
nsDependentCSubstring requestAsSubstring(
reinterpret_cast<const char*>(encodedRequest->data), encodedRequest->len);
nsCString base64Request;
rv = Base64Encode(requestAsSubstring, base64Request);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("Setting up OCSP GET path, pre path =%s\n",
PromiseFlatCString(path).get()));
// The path transformation is not a direct url encoding. Three characters
// need change '+' -> "%2B", '/' -> "%2F", and '=' -> '%3D'.
// http://tools.ietf.org/html/rfc5019#section-5
base64Request.ReplaceSubstring("+", "%2B");
base64Request.ReplaceSubstring("/", "%2F");
base64Request.ReplaceSubstring("=", "%3D");
path.Append(base64Request);
return NS_OK;
}
SECItem*
DoOCSPRequest(PLArenaPool* arena, const char* url,
const SECItem* encodedRequest, PRIntervalTime timeout,
bool useGET)
{
nsCOMPtr<nsIURLParser> urlParser = do_GetService(NS_STDURLPARSER_CONTRACTID);
if (!urlParser) {
@ -86,39 +119,56 @@ SECItem* DoOCSPRequest(PLArenaPool* arena, const char* url,
if (port == -1) {
port = 80;
}
nsAutoCString hostname(url + authorityPos + hostnamePos, hostnameLen);
SEC_HTTP_SERVER_SESSION serverSessionPtr = nullptr;
if (nsNSSHttpInterface::createSessionFcn(hostname.BeginReading(), port,
&serverSessionPtr) != SECSuccess) {
PR_SetError(SEC_ERROR_NO_MEMORY, 0);
return nullptr;
}
ScopedHTTPServerSession serverSession(
reinterpret_cast<nsNSSHttpServerSession*>(serverSessionPtr));
nsAutoCString path;
if (pathLen > 0) {
path.Assign(url + pathPos, pathLen);
} else {
path.Assign("/");
}
SEC_HTTP_REQUEST_SESSION requestSessionPtr;
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("Setting up OCSP request: pre all path =%s pathlen=%d\n", path.get(),
pathLen));
nsAutoCString method("POST");
if (useGET) {
method.Assign("GET");
if (!StringEndsWith(path, NS_LITERAL_CSTRING("/"))) {
path.Append("/");
}
nsresult rv = AppendEscapedBase64Item(encodedRequest, path);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
}
SEC_HTTP_REQUEST_SESSION requestSessionPtr = nullptr;
if (nsNSSHttpInterface::createFcn(serverSession.get(), "http",
path.BeginReading(), "POST",
path.get(), method.get(),
timeout, &requestSessionPtr)
!= SECSuccess) {
PR_SetError(SEC_ERROR_NO_MEMORY, 0);
return nullptr;
}
ScopedHTTPRequestSession requestSession(
reinterpret_cast<nsNSSHttpRequestSession*>(requestSessionPtr));
if (nsNSSHttpInterface::setPostDataFcn(requestSession.get(),
reinterpret_cast<char*>(encodedRequest->data), encodedRequest->len,
"application/ocsp-request") != SECSuccess) {
PR_SetError(SEC_ERROR_NO_MEMORY, 0);
return nullptr;
if (!useGET) {
if (nsNSSHttpInterface::setPostDataFcn(requestSession.get(),
reinterpret_cast<char*>(encodedRequest->data), encodedRequest->len,
"application/ocsp-request") != SECSuccess) {
PR_SetError(SEC_ERROR_NO_MEMORY, 0);
return nullptr;
}
}
uint16_t httpResponseCode;

View File

@ -7,13 +7,15 @@
#ifndef mozilla_psm_OCSPRequestor_h
#define mozilla_psm_OCSPRequestor_h
#include "CertVerifier.h"
#include "secmodt.h"
namespace mozilla { namespace psm {
// The memory returned is owned by the given arena.
SECItem* DoOCSPRequest(PLArenaPool* arena, const char* url,
const SECItem* encodedRequest, PRIntervalTime timeout);
const SECItem* encodedRequest, PRIntervalTime timeout,
bool useGET);
} } // namespace mozilla::psm