mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1006041: Use mozilla::pkix::der for decoding the extended key usage extension, r=keeler
--HG-- extra : rebase_source : b4b62f117d653784eb6ad058554faf520a1bd90b
This commit is contained in:
parent
f9a6cb7aca
commit
ac79ecb683
@ -605,8 +605,8 @@ VerifySignature(AppTrustedRoot trustedRoot,
|
||||
}
|
||||
if (BuildCertChain(trustDomain, signerCert, PR_Now(),
|
||||
EndEntityOrCA::MustBeEndEntity, KU_DIGITAL_SIGNATURE,
|
||||
SEC_OID_EXT_KEY_USAGE_CODE_SIGN,
|
||||
SEC_OID_X509_ANY_POLICY, nullptr, builtChain)
|
||||
KeyPurposeId::id_kp_codeSigning, SEC_OID_X509_ANY_POLICY,
|
||||
nullptr, builtChain)
|
||||
!= SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ destroyCertListThatShouldNotExist(CERTCertList** certChain)
|
||||
static SECStatus
|
||||
BuildCertChainForOneKeyUsage(TrustDomain& trustDomain, CERTCertificate* cert,
|
||||
PRTime time, KeyUsages ku1, KeyUsages ku2,
|
||||
KeyUsages ku3, SECOidTag eku,
|
||||
KeyUsages ku3, KeyPurposeId eku,
|
||||
SECOidTag requiredPolicy,
|
||||
const SECItem* stapledOCSPResponse,
|
||||
ScopedCERTCertList& builtChain)
|
||||
@ -391,9 +391,9 @@ CertVerifier::MozillaPKIXVerifyCert(
|
||||
pinArg);
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
EndEntityOrCA::MustBeEndEntity, KU_DIGITAL_SIGNATURE,
|
||||
SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH,
|
||||
SEC_OID_X509_ANY_POLICY,
|
||||
stapledOCSPResponse, builtChain);
|
||||
KeyPurposeId::id_kp_clientAuth,
|
||||
SEC_OID_X509_ANY_POLICY, stapledOCSPResponse,
|
||||
builtChain);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -417,7 +417,7 @@ CertVerifier::MozillaPKIXVerifyCert(
|
||||
KU_DIGITAL_SIGNATURE, // ECDHE/DHE
|
||||
KU_KEY_ENCIPHERMENT, // RSA
|
||||
KU_KEY_AGREEMENT, // ECDH/DH
|
||||
SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
evPolicy, stapledOCSPResponse,
|
||||
builtChain);
|
||||
if (rv == SECSuccess) {
|
||||
@ -443,7 +443,7 @@ CertVerifier::MozillaPKIXVerifyCert(
|
||||
KU_DIGITAL_SIGNATURE, // ECDHE/DHE
|
||||
KU_KEY_ENCIPHERMENT, // RSA
|
||||
KU_KEY_AGREEMENT, // ECDH/DH
|
||||
SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
SEC_OID_X509_ANY_POLICY,
|
||||
stapledOCSPResponse, builtChain);
|
||||
break;
|
||||
@ -453,8 +453,7 @@ CertVerifier::MozillaPKIXVerifyCert(
|
||||
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
|
||||
pinArg);
|
||||
rv = BuildCertChain(trustDomain, cert, time, EndEntityOrCA::MustBeCA,
|
||||
KU_KEY_CERT_SIGN,
|
||||
SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
|
||||
KU_KEY_CERT_SIGN, KeyPurposeId::id_kp_serverAuth,
|
||||
SEC_OID_X509_ANY_POLICY,
|
||||
stapledOCSPResponse, builtChain);
|
||||
break;
|
||||
@ -465,8 +464,7 @@ CertVerifier::MozillaPKIXVerifyCert(
|
||||
pinArg);
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
EndEntityOrCA::MustBeEndEntity, KU_DIGITAL_SIGNATURE,
|
||||
SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT,
|
||||
SEC_OID_X509_ANY_POLICY,
|
||||
KeyPurposeId::id_kp_emailProtection, SEC_OID_X509_ANY_POLICY,
|
||||
stapledOCSPResponse, builtChain);
|
||||
break;
|
||||
}
|
||||
@ -481,7 +479,7 @@ CertVerifier::MozillaPKIXVerifyCert(
|
||||
KU_KEY_ENCIPHERMENT, // RSA
|
||||
KU_KEY_AGREEMENT, // ECDH/DH
|
||||
0,
|
||||
SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT,
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
SEC_OID_X509_ANY_POLICY,
|
||||
stapledOCSPResponse, builtChain);
|
||||
break;
|
||||
@ -492,8 +490,7 @@ CertVerifier::MozillaPKIXVerifyCert(
|
||||
mOCSPCache, pinArg);
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
EndEntityOrCA::MustBeEndEntity, KU_DIGITAL_SIGNATURE,
|
||||
SEC_OID_EXT_KEY_USAGE_CODE_SIGN,
|
||||
SEC_OID_X509_ANY_POLICY,
|
||||
KeyPurposeId::id_kp_codeSigning, SEC_OID_X509_ANY_POLICY,
|
||||
stapledOCSPResponse, builtChain);
|
||||
break;
|
||||
}
|
||||
@ -506,15 +503,15 @@ CertVerifier::MozillaPKIXVerifyCert(
|
||||
// interesting, we just try them all.
|
||||
mozilla::pkix::EndEntityOrCA endEntityOrCA;
|
||||
mozilla::pkix::KeyUsages keyUsage;
|
||||
SECOidTag eku;
|
||||
KeyPurposeId eku;
|
||||
if (usage == certificateUsageVerifyCA) {
|
||||
endEntityOrCA = EndEntityOrCA::MustBeCA;
|
||||
keyUsage = KU_KEY_CERT_SIGN;
|
||||
eku = SEC_OID_UNKNOWN;
|
||||
eku = KeyPurposeId::anyExtendedKeyUsage;
|
||||
} else {
|
||||
endEntityOrCA = EndEntityOrCA::MustBeEndEntity;
|
||||
keyUsage = KU_DIGITAL_SIGNATURE;
|
||||
eku = SEC_OID_OCSP_RESPONDER;
|
||||
eku = KeyPurposeId::id_kp_OCSPSigning;
|
||||
}
|
||||
|
||||
NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache,
|
||||
|
@ -24,26 +24,35 @@
|
||||
|
||||
// Work around missing std::bind, std::ref, std::cref in older compilers. This
|
||||
// implementation isn't intended to be complete; rather, it is the minimal
|
||||
// implementation needed to make our use of std::bind work.
|
||||
// implementation needed to make our use of std::bind work for compilers that
|
||||
// lack both C++11 and TR1 support for these features. We cannot even assume
|
||||
// that rvalue references work, which means we don't get perfect forwarding
|
||||
// and thus we basically have to define a new overload for every distinct call
|
||||
// signature.
|
||||
//
|
||||
// A positive side-effect of this code is improved debugging usability; it is
|
||||
// much more convenient to step through code that uses this polyfill than it is
|
||||
// to step through the many nested layers of a real std::bind implementation.
|
||||
//
|
||||
// Build with MOZILLA_PKIX_USE_REAL_FUNCTIONAL defined in order to use the
|
||||
// compiler's definitions of these functions. This is helpful in order to
|
||||
// ensure that the calling code is actually compatible with the real std::bind
|
||||
// and friends.
|
||||
|
||||
#ifndef mozilla_pkix__bind_h
|
||||
#define mozilla_pkix__bind_h
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4275) //Suppress spurious MSVC warning
|
||||
#endif
|
||||
#ifdef MOZILLA_PKIX_USE_REAL_FUNCTIONAL
|
||||
#include <functional>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(default:4275)
|
||||
#endif
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MOZILLA_PKIX_USE_REAL_FUNCTIONAL
|
||||
|
||||
using std::bind;
|
||||
using std::ref;
|
||||
using std::cref;
|
||||
using std::ref;
|
||||
using std::placeholders::_1;
|
||||
|
||||
#else
|
||||
@ -66,6 +75,7 @@ public:
|
||||
private:
|
||||
const F f;
|
||||
B1& b1;
|
||||
void operator=(const Bind1&) /*= delete*/;
|
||||
};
|
||||
|
||||
template <typename R, typename P1, typename B1, typename B2>
|
||||
@ -79,6 +89,40 @@ private:
|
||||
const F f;
|
||||
B1& b1;
|
||||
B2& b2;
|
||||
void operator=(const Bind2&) /*= delete*/;
|
||||
};
|
||||
|
||||
template <typename R, typename P1, typename B1, typename B2, typename B3>
|
||||
class Bind3
|
||||
{
|
||||
public:
|
||||
typedef R (*F)(P1&, B1&, B2&, B3&);
|
||||
Bind3(F f, B1& b1, B2& b2, B3& b3) : f(f), b1(b1), b2(b2), b3(b3) { }
|
||||
R operator()(P1& p1) const { return f(p1, b1, b2, b3); }
|
||||
private:
|
||||
const F f;
|
||||
B1& b1;
|
||||
B2& b2;
|
||||
B3& b3;
|
||||
void operator=(const Bind3&) /*= delete*/;
|
||||
};
|
||||
|
||||
template <typename R, typename P1, typename B1, typename B2, typename B3,
|
||||
typename B4>
|
||||
class Bind4
|
||||
{
|
||||
public:
|
||||
typedef R (*F)(P1&, B1, B2, B3&, B4&);
|
||||
Bind4(F f, B1& b1, B2& b2, B3& b3, B4& b4)
|
||||
: f(f), b1(b1), b2(b2), b3(b3), b4(b4) { }
|
||||
R operator()(P1& p1) const { return f(p1, b1, b2, b3, b4); }
|
||||
private:
|
||||
const F f;
|
||||
B1& b1;
|
||||
B2& b2;
|
||||
B3& b3;
|
||||
B4& b4;
|
||||
void operator=(const Bind4&) /*= delete*/;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
@ -92,12 +136,28 @@ bind(R (*f)(P1&, B1&), Placeholder1&, B1& b1)
|
||||
|
||||
template <typename R, typename P1, typename B1, typename B2>
|
||||
inline internal::Bind2<R, P1, B1, B2>
|
||||
bind(R (*f)(P1&, B1&, B2&), Placeholder1 &, B1 & b1, B2 & b2)
|
||||
bind(R (*f)(P1&, B1&, B2&), Placeholder1&, B1& b1, B2& b2)
|
||||
{
|
||||
return internal::Bind2<R, P1, B1, B2>(f, b1, b2);
|
||||
}
|
||||
|
||||
#endif // _MSC_VER
|
||||
template <typename R, typename P1, typename B1, typename B2, typename B3>
|
||||
inline internal::Bind3<R, P1, B1, B2, B3>
|
||||
bind(R (*f)(P1&, B1&, B2&, B3&), Placeholder1&, B1& b1, B2& b2, B3& b3)
|
||||
{
|
||||
return internal::Bind3<R, P1, B1, B2, B3>(f, b1, b2, b3);
|
||||
}
|
||||
|
||||
template <typename R, typename P1, typename B1, typename B2, typename B3,
|
||||
typename B4>
|
||||
inline internal::Bind4<R, P1, const B1, const B2, B3, B4>
|
||||
bind(R (*f)(P1&, B1, B2, B3&, B4&), Placeholder1&, const B1& b1, const B2& b2,
|
||||
B3& b3, B4& b4)
|
||||
{
|
||||
return internal::Bind4<R, P1, const B1, const B2, B3, B4>(f, b1, b2, b3, b4);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
|
@ -94,7 +94,7 @@ SECStatus BuildCertChain(TrustDomain& trustDomain,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
/*optional*/ KeyUsages requiredKeyUsagesIfPresent,
|
||||
/*optional*/ SECOidTag requiredEKUIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
/*optional*/ SECOidTag requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*out*/ ScopedCERTCertList& results);
|
||||
|
@ -41,9 +41,18 @@ typedef ScopedPtr<CERTCertList, CERT_DestroyCertList> ScopedCERTCertList;
|
||||
typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey>
|
||||
ScopedSECKEYPublicKey;
|
||||
|
||||
MOZILLA_PKIX_ENUM_CLASS EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 };
|
||||
|
||||
typedef unsigned int KeyUsages;
|
||||
|
||||
MOZILLA_PKIX_ENUM_CLASS EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 };
|
||||
MOZILLA_PKIX_ENUM_CLASS KeyPurposeId {
|
||||
anyExtendedKeyUsage = 0,
|
||||
id_kp_serverAuth = 1, // id-kp-serverAuth
|
||||
id_kp_clientAuth = 2, // id-kp-clientAuth
|
||||
id_kp_codeSigning = 3, // id-kp-codeSigning
|
||||
id_kp_emailProtection = 4, // id-kp-emailProtection
|
||||
id_kp_OCSPSigning = 9, // id-kp-OCSPSigning
|
||||
};
|
||||
|
||||
MOZILLA_PKIX_ENUM_CLASS TrustLevel {
|
||||
TrustAnchor = 1, // certificate is a trusted root CA certificate or
|
||||
|
@ -22,7 +22,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifndef MOZILLA_PKIX_USE_REAL_FUNCTIONAL
|
||||
|
||||
#include "pkix/bind.h"
|
||||
|
||||
@ -32,4 +32,4 @@ Placeholder1 _1;
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
#endif // _MSC_VER
|
||||
#endif
|
||||
|
@ -114,7 +114,7 @@ static Result BuildForward(TrustDomain& trustDomain,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyUsages requiredKeyUsagesIfPresent,
|
||||
SECOidTag requiredEKUIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
SECOidTag requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
unsigned int subCACount,
|
||||
@ -126,7 +126,7 @@ BuildForwardInner(TrustDomain& trustDomain,
|
||||
BackCert& subject,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
SECOidTag requiredEKUIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
SECOidTag requiredPolicy,
|
||||
CERTCertificate* potentialIssuerCertToDup,
|
||||
unsigned int subCACount,
|
||||
@ -196,7 +196,7 @@ BuildForward(TrustDomain& trustDomain,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyUsages requiredKeyUsagesIfPresent,
|
||||
SECOidTag requiredEKUIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
SECOidTag requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
unsigned int subCACount,
|
||||
@ -336,7 +336,7 @@ BuildCertChain(TrustDomain& trustDomain,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
/*optional*/ KeyUsages requiredKeyUsagesIfPresent,
|
||||
/*optional*/ SECOidTag requiredEKUIfPresent,
|
||||
/*optional*/ KeyPurposeId requiredEKUIfPresent,
|
||||
/*optional*/ SECOidTag requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*out*/ ScopedCERTCertList& results)
|
||||
@ -355,7 +355,7 @@ BuildCertChain(TrustDomain& trustDomain,
|
||||
// domain name the certificate is valid for.
|
||||
BackCert::IncludeCN includeCN
|
||||
= endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
|
||||
requiredEKUIfPresent == SEC_OID_EXT_KEY_USAGE_SERVER_AUTH
|
||||
requiredEKUIfPresent == KeyPurposeId::id_kp_serverAuth
|
||||
? BackCert::IncludeCN::Yes
|
||||
: BackCert::IncludeCN::No;
|
||||
|
||||
|
@ -335,15 +335,97 @@ CheckNameConstraints(BackCert& cert)
|
||||
}
|
||||
|
||||
// 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage)
|
||||
// 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage)
|
||||
Result
|
||||
CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs,
|
||||
SECOidTag requiredEKU)
|
||||
{
|
||||
// TODO: Either do not allow anyExtendedKeyUsage to be passed as requiredEKU,
|
||||
// or require that callers pass anyExtendedKeyUsage instead of
|
||||
// SEC_OID_UNKNWON and disallow SEC_OID_UNKNWON.
|
||||
|
||||
static der::Result
|
||||
MatchEKU(der::Input& value, KeyPurposeId requiredEKU,
|
||||
EndEntityOrCA endEntityOrCA, /*in/out*/ bool& found,
|
||||
/*in/out*/ bool& foundOCSPSigning)
|
||||
{
|
||||
// See Section 5.9 of "A Layman's Guide to a Subset of ASN.1, BER, and DER"
|
||||
// for a description of ASN.1 DER encoding of OIDs.
|
||||
|
||||
// id-pkix OBJECT IDENTIFIER ::=
|
||||
// { iso(1) identified-organization(3) dod(6) internet(1)
|
||||
// security(5) mechanisms(5) pkix(7) }
|
||||
// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
|
||||
// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
|
||||
// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
|
||||
// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
|
||||
// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
|
||||
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
|
||||
static const uint8_t server[] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 1 };
|
||||
static const uint8_t client[] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 2 };
|
||||
static const uint8_t code [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 3 };
|
||||
static const uint8_t email [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 4 };
|
||||
static const uint8_t ocsp [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 9 };
|
||||
|
||||
// id-Netscape OBJECT IDENTIFIER ::= { 2 16 840 1 113730 }
|
||||
// id-Netscape-policy OBJECT IDENTIFIER ::= { id-Netscape 4 }
|
||||
// id-Netscape-stepUp OBJECT IDENTIFIER ::= { id-Netscape-policy 1 }
|
||||
static const uint8_t serverStepUp[] =
|
||||
{ (40*2)+16, 128+6,72, 1, 128+6,128+120,66, 4, 1 };
|
||||
|
||||
bool match = false;
|
||||
|
||||
if (!found) {
|
||||
switch (requiredEKU) {
|
||||
case KeyPurposeId::id_kp_serverAuth:
|
||||
// Treat CA certs with step-up OID as also having SSL server type.
|
||||
// Comodo has issued certificates that require this behavior that don't
|
||||
// expire until June 2020! TODO(bug 982932): Limit this exception to
|
||||
// old certificates.
|
||||
match = value.MatchBytes(server) ||
|
||||
(endEntityOrCA == EndEntityOrCA::MustBeCA &&
|
||||
value.MatchBytes(serverStepUp));
|
||||
break;
|
||||
|
||||
case KeyPurposeId::id_kp_clientAuth:
|
||||
match = value.MatchBytes(client);
|
||||
break;
|
||||
|
||||
case KeyPurposeId::id_kp_codeSigning:
|
||||
match = value.MatchBytes(code);
|
||||
break;
|
||||
|
||||
case KeyPurposeId::id_kp_emailProtection:
|
||||
match = value.MatchBytes(email);
|
||||
break;
|
||||
|
||||
case KeyPurposeId::id_kp_OCSPSigning:
|
||||
match = value.MatchBytes(ocsp);
|
||||
break;
|
||||
|
||||
case KeyPurposeId::anyExtendedKeyUsage:
|
||||
PR_NOT_REACHED("anyExtendedKeyUsage should start with found==true");
|
||||
return der::Fail(SEC_ERROR_LIBRARY_FAILURE);
|
||||
|
||||
default:
|
||||
PR_NOT_REACHED("unrecognized EKU");
|
||||
return der::Fail(SEC_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
if (value.AtEnd()) {
|
||||
found = true;
|
||||
if (requiredEKU == KeyPurposeId::id_kp_OCSPSigning) {
|
||||
foundOCSPSigning = true;
|
||||
}
|
||||
}
|
||||
} else if (value.MatchBytes(ocsp) && value.AtEnd()) {
|
||||
foundOCSPSigning = true;
|
||||
}
|
||||
|
||||
value.SkipToEnd(); // ignore unmatched OIDs.
|
||||
|
||||
return der::Success;
|
||||
}
|
||||
|
||||
Result
|
||||
CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
|
||||
const SECItem* encodedExtendedKeyUsage,
|
||||
KeyPurposeId requiredEKU)
|
||||
{
|
||||
// XXX: We're using SEC_ERROR_INADEQUATE_CERT_TYPE here so that callers can
|
||||
// distinguish EKU mismatch from KU mismatch from basic constraints mismatch.
|
||||
// We should probably add a new error code that is more clear for this type
|
||||
@ -351,35 +433,22 @@ CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs,
|
||||
|
||||
bool foundOCSPSigning = false;
|
||||
|
||||
if (encodedEKUs) {
|
||||
ScopedPtr<CERTOidSequence, CERT_DestroyOidSequence>
|
||||
seq(CERT_DecodeOidSequence(encodedEKUs));
|
||||
if (!seq) {
|
||||
PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0);
|
||||
return RecoverableError;
|
||||
if (encodedExtendedKeyUsage) {
|
||||
bool found = requiredEKU == KeyPurposeId::anyExtendedKeyUsage;
|
||||
|
||||
der::Input input;
|
||||
if (input.Init(encodedExtendedKeyUsage->data,
|
||||
encodedExtendedKeyUsage->len) != der::Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
// XXX: We allow duplicate entries.
|
||||
for (const SECItem* const* oids = seq->oids; oids && *oids; ++oids) {
|
||||
SECOidTag oidTag = SECOID_FindOIDTag(*oids);
|
||||
if (requiredEKU != SEC_OID_UNKNOWN && oidTag == requiredEKU) {
|
||||
found = true;
|
||||
} else {
|
||||
// Treat CA certs with step-up OID as also having SSL server type.
|
||||
// COMODO has issued certificates that require this behavior
|
||||
// that don't expire until June 2020!
|
||||
// TODO 982932: Limit this expection to old certificates
|
||||
if (endEntityOrCA == EndEntityOrCA::MustBeCA &&
|
||||
requiredEKU == SEC_OID_EXT_KEY_USAGE_SERVER_AUTH &&
|
||||
oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (oidTag == SEC_OID_OCSP_RESPONDER) {
|
||||
foundOCSPSigning = true;
|
||||
}
|
||||
if (der::NestedOf(input, der::SEQUENCE, der::OIDTag, der::EmptyAllowed::No,
|
||||
bind(MatchEKU, _1, requiredEKU, endEntityOrCA,
|
||||
ref(found), ref(foundOCSPSigning)))
|
||||
!= der::Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
}
|
||||
if (der::End(input) != der::Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
}
|
||||
|
||||
// If the EKU extension was included, then the required EKU must be in the
|
||||
@ -404,9 +473,8 @@ CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs,
|
||||
// Allowing this exception does not cause any security issues because we
|
||||
// require delegated OCSP response signing certificates to be end-entity
|
||||
// certificates.
|
||||
if (foundOCSPSigning && requiredEKU != SEC_OID_OCSP_RESPONDER) {
|
||||
PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0);
|
||||
return RecoverableError;
|
||||
if (foundOCSPSigning && requiredEKU != KeyPurposeId::id_kp_OCSPSigning) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
}
|
||||
// http://tools.ietf.org/html/rfc6960#section-4.2.2.2:
|
||||
// "OCSP signing delegation SHALL be designated by the inclusion of
|
||||
@ -417,9 +485,8 @@ CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs,
|
||||
// EKU extension is missing from an end-entity certificate. However, any CA
|
||||
// certificate can issue a delegated OCSP response signing certificate, so
|
||||
// we can't require the EKU be explicitly included for CA certificates.
|
||||
if (!foundOCSPSigning && requiredEKU == SEC_OID_OCSP_RESPONDER) {
|
||||
PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0);
|
||||
return RecoverableError;
|
||||
if (!foundOCSPSigning && requiredEKU == KeyPurposeId::id_kp_OCSPSigning) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,7 +499,7 @@ CheckIssuerIndependentProperties(TrustDomain& trustDomain,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyUsages requiredKeyUsagesIfPresent,
|
||||
SECOidTag requiredEKUIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
SECOidTag requiredPolicy,
|
||||
unsigned int subCACount,
|
||||
/*optional out*/ TrustLevel* trustLevelOut)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#ifndef mozilla_pkix__pkixcheck_h
|
||||
#define mozilla_pkix__pkixcheck_h
|
||||
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "pkixutil.h"
|
||||
#include "certt.h"
|
||||
|
||||
@ -36,7 +37,7 @@ Result CheckIssuerIndependentProperties(
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyUsages requiredKeyUsagesIfPresent,
|
||||
SECOidTag requiredEKUIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
SECOidTag requiredPolicy,
|
||||
unsigned int subCACount,
|
||||
/*optional out*/ TrustLevel* trustLevel = nullptr);
|
||||
|
@ -138,6 +138,19 @@ public:
|
||||
return Success;
|
||||
}
|
||||
|
||||
template <uint16_t N>
|
||||
bool MatchBytes(const uint8_t (&toMatch)[N])
|
||||
{
|
||||
if (EnsureLength(N) != Success) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(input, toMatch, N)) {
|
||||
return false;
|
||||
}
|
||||
input += N;
|
||||
return true;
|
||||
}
|
||||
|
||||
Result Skip(uint16_t len)
|
||||
{
|
||||
if (EnsureLength(len) != Success) {
|
||||
|
@ -146,7 +146,7 @@ CheckOCSPResponseSignerCert(TrustDomain& trustDomain,
|
||||
// are validating for should be passed to CheckIssuerIndependentProperties.
|
||||
rv = CheckIssuerIndependentProperties(trustDomain, cert, time,
|
||||
EndEntityOrCA::MustBeEndEntity, 0,
|
||||
SEC_OID_OCSP_RESPONDER,
|
||||
KeyPurposeId::id_kp_OCSPSigning,
|
||||
SEC_OID_X509_ANY_POLICY, 0);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
|
@ -604,4 +604,57 @@ TEST_F(pkixder_input_tests, NestedOfWithTruncatedData)
|
||||
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||
ASSERT_EQ((size_t) 0, readValues.size());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchBytesAtEnd)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[1] = { };
|
||||
ASSERT_EQ(Success, input.Init(der, 0));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
static const uint8_t toMatch[] = { 1 };
|
||||
ASSERT_FALSE(input.MatchBytes(toMatch));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchBytes1Match)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[] = { 1 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
ASSERT_FALSE(input.AtEnd());
|
||||
ASSERT_TRUE(input.MatchBytes(der));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchBytes1Mismatch)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[] = { 1 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
static const uint8_t toMatch[] = { 2 };
|
||||
ASSERT_FALSE(input.MatchBytes(toMatch));
|
||||
ASSERT_FALSE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchBytes2Match)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[] = { 1, 2, 3 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
static const uint8_t toMatch[] = { 1, 2 };
|
||||
ASSERT_TRUE(input.MatchBytes(toMatch));
|
||||
uint8_t followingByte;
|
||||
ASSERT_EQ(Success, input.Read(followingByte));
|
||||
ASSERT_EQ(3, followingByte);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchBytes2Mismatch)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[] = { 1, 2, 3 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
static const uint8_t toMatchMismatch[] = { 1, 3 };
|
||||
ASSERT_FALSE(input.MatchBytes(toMatchMismatch));
|
||||
ASSERT_TRUE(input.MatchBytes(der));
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
Loading…
Reference in New Issue
Block a user