1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/pkix/lib/pkixocsp.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1017 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* Copyright 2013 Mozilla Foundation 1.7 + * 1.8 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.9 + * you may not use this file except in compliance with the License. 1.10 + * You may obtain a copy of the License at 1.11 + * 1.12 + * http://www.apache.org/licenses/LICENSE-2.0 1.13 + * 1.14 + * Unless required by applicable law or agreed to in writing, software 1.15 + * distributed under the License is distributed on an "AS IS" BASIS, 1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.17 + * See the License for the specific language governing permissions and 1.18 + * limitations under the License. 1.19 + */ 1.20 + 1.21 +#include <limits> 1.22 + 1.23 +#include "pkix/bind.h" 1.24 +#include "pkix/pkix.h" 1.25 +#include "pkixcheck.h" 1.26 +#include "pkixder.h" 1.27 + 1.28 +#include "hasht.h" 1.29 +#include "pk11pub.h" 1.30 +#include "secder.h" 1.31 + 1.32 +#ifdef _MSC_VER 1.33 +// C4480: nonstandard extension used: specifying underlying type for enum 1.34 +#define ENUM_CLASS __pragma(warning(disable: 4480)) enum 1.35 +#else 1.36 +#define ENUM_CLASS enum class 1.37 +#endif 1.38 + 1.39 +// TODO: use typed/qualified typedefs everywhere? 1.40 +// TODO: When should we return SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE? 1.41 + 1.42 +namespace mozilla { namespace pkix { 1.43 + 1.44 +static const PRTime ONE_DAY 1.45 + = INT64_C(24) * INT64_C(60) * INT64_C(60) * PR_USEC_PER_SEC; 1.46 +static const PRTime SLOP = ONE_DAY; 1.47 + 1.48 +// These values correspond to the tag values in the ASN.1 CertStatus 1.49 +ENUM_CLASS CertStatus : uint8_t { 1.50 + Good = der::CONTEXT_SPECIFIC | 0, 1.51 + Revoked = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, 1.52 + Unknown = der::CONTEXT_SPECIFIC | 2 1.53 +}; 1.54 + 1.55 +class Context 1.56 +{ 1.57 +public: 1.58 + Context(TrustDomain& trustDomain, 1.59 + const CERTCertificate& cert, 1.60 + CERTCertificate& issuerCert, 1.61 + PRTime time, 1.62 + uint16_t maxLifetimeInDays, 1.63 + PRTime* thisUpdate, 1.64 + PRTime* validThrough) 1.65 + : trustDomain(trustDomain) 1.66 + , cert(cert) 1.67 + , issuerCert(issuerCert) 1.68 + , time(time) 1.69 + , maxLifetimeInDays(maxLifetimeInDays) 1.70 + , certStatus(CertStatus::Unknown) 1.71 + , thisUpdate(thisUpdate) 1.72 + , validThrough(validThrough) 1.73 + , expired(false) 1.74 + { 1.75 + if (thisUpdate) { 1.76 + *thisUpdate = 0; 1.77 + } 1.78 + if (validThrough) { 1.79 + *validThrough = 0; 1.80 + } 1.81 + } 1.82 + 1.83 + TrustDomain& trustDomain; 1.84 + const CERTCertificate& cert; 1.85 + CERTCertificate& issuerCert; 1.86 + const PRTime time; 1.87 + const uint16_t maxLifetimeInDays; 1.88 + CertStatus certStatus; 1.89 + PRTime* thisUpdate; 1.90 + PRTime* validThrough; 1.91 + bool expired; 1.92 + 1.93 +private: 1.94 + Context(const Context&); // delete 1.95 + void operator=(const Context&); // delete 1.96 +}; 1.97 + 1.98 +// Verify that potentialSigner is a valid delegated OCSP response signing cert 1.99 +// according to RFC 6960 section 4.2.2.2. 1.100 +static Result 1.101 +CheckOCSPResponseSignerCert(TrustDomain& trustDomain, 1.102 + CERTCertificate& potentialSigner, 1.103 + const CERTCertificate& issuerCert, PRTime time) 1.104 +{ 1.105 + Result rv; 1.106 + 1.107 + BackCert cert(&potentialSigner, nullptr, BackCert::ExcludeCN); 1.108 + rv = cert.Init(); 1.109 + if (rv != Success) { 1.110 + return rv; 1.111 + } 1.112 + 1.113 + // We don't need to do a complete verification of the signer (i.e. we don't 1.114 + // have to call BuildCertChain to verify the entire chain) because we 1.115 + // already know that the issuerCert is valid, since revocation checking is 1.116 + // done from the root to the parent after we've built a complete chain that 1.117 + // we know is otherwise valid. Rather, we just need to do a one-step 1.118 + // validation from potentialSigner to issuerCert. 1.119 + // 1.120 + // It seems reasonable to require the KU_DIGITAL_SIGNATURE key usage on the 1.121 + // OCSP responder certificate if the OCSP responder certificate has a 1.122 + // key usage extension. However, according to bug 240456, some OCSP responder 1.123 + // certificates may have only the nonRepudiation bit set. Also, the OCSP 1.124 + // specification (RFC 6960) does not mandate any particular key usage to be 1.125 + // asserted for OCSP responde signers. Oddly, the CABForum Baseline 1.126 + // Requirements v.1.1.5 do say "If the Root CA Private Key is used for 1.127 + // signing OCSP responses, then the digitalSignature bit MUST be set." 1.128 + // 1.129 + // Note that CheckIssuerIndependentProperties processes 1.130 + // SEC_OID_OCSP_RESPONDER in the way that the OCSP specification requires us 1.131 + // to--in particular, it doesn't allow SEC_OID_OCSP_RESPONDER to be implied 1.132 + // by a missing EKU extension, unlike other EKUs. 1.133 + // 1.134 + // TODO(bug 926261): If we're validating for a policy then the policy OID we 1.135 + // are validating for should be passed to CheckIssuerIndependentProperties. 1.136 + rv = CheckIssuerIndependentProperties(trustDomain, cert, time, 1.137 + MustBeEndEntity, 1.138 + KeyUsage::noParticularKeyUsageRequired, 1.139 + SEC_OID_OCSP_RESPONDER, 1.140 + SEC_OID_X509_ANY_POLICY, 0); 1.141 + if (rv != Success) { 1.142 + return rv; 1.143 + } 1.144 + 1.145 + // It is possible that there exists a certificate with the same key as the 1.146 + // issuer but with a different name, so we need to compare names 1.147 + // TODO: needs test 1.148 + if (!SECITEM_ItemsAreEqual(&cert.GetNSSCert()->derIssuer, 1.149 + &issuerCert.derSubject) && 1.150 + CERT_CompareName(&cert.GetNSSCert()->issuer, 1.151 + &issuerCert.subject) != SECEqual) { 1.152 + return Fail(RecoverableError, SEC_ERROR_OCSP_RESPONDER_CERT_INVALID); 1.153 + } 1.154 + 1.155 + // TODO(bug 926260): check name constraints 1.156 + 1.157 + if (trustDomain.VerifySignedData(&potentialSigner.signatureWrap, 1.158 + &issuerCert) != SECSuccess) { 1.159 + return MapSECStatus(SECFailure); 1.160 + } 1.161 + 1.162 + // TODO: check for revocation of the OCSP responder certificate unless no-check 1.163 + // or the caller forcing no-check. To properly support the no-check policy, we'd 1.164 + // need to enforce policy constraints from the issuerChain. 1.165 + 1.166 + return Success; 1.167 +} 1.168 + 1.169 +//typedef enum { 1.170 +// ocspResponderID_byName = 1, 1.171 +// ocspResponderID_byKey = 2 1.172 +//} ResponderIDType; 1.173 + 1.174 +ENUM_CLASS ResponderIDType : uint8_t 1.175 +{ 1.176 + byName = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, 1.177 + byKey = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 2 1.178 +}; 1.179 + 1.180 +static inline der::Result OCSPResponse(der::Input&, Context&); 1.181 +static inline der::Result ResponseBytes(der::Input&, Context&); 1.182 +static inline der::Result BasicResponse(der::Input&, Context&); 1.183 +static inline der::Result ResponseData( 1.184 + der::Input& tbsResponseData, Context& context, 1.185 + const CERTSignedData& signedResponseData, 1.186 + /*const*/ SECItem* certs, size_t numCerts); 1.187 +static inline der::Result SingleResponse(der::Input& input, 1.188 + Context& context); 1.189 +static inline der::Result CheckExtensionsForCriticality(der::Input&); 1.190 +static inline der::Result CertID(der::Input& input, 1.191 + const Context& context, 1.192 + /*out*/ bool& match); 1.193 +static der::Result MatchIssuerKey(const SECItem& issuerKeyHash, 1.194 + const CERTCertificate& issuer, 1.195 + /*out*/ bool& match); 1.196 + 1.197 +// RFC 6960 section 4.2.2.2: The OCSP responder must either be the issuer of 1.198 +// the cert or it must be a delegated OCSP response signing cert directly 1.199 +// issued by the issuer. If the OCSP responder is a delegated OCSP response 1.200 +// signer, then its certificate is (probably) embedded within the OCSP 1.201 +// response and we'll need to verify that it is a valid certificate that chains 1.202 +// *directly* to issuerCert. 1.203 +static CERTCertificate* 1.204 +GetOCSPSignerCertificate(TrustDomain& trustDomain, 1.205 + ResponderIDType responderIDType, 1.206 + const SECItem& responderIDItem, 1.207 + const SECItem* certs, size_t numCerts, 1.208 + CERTCertificate& issuerCert, PRTime time) 1.209 +{ 1.210 + bool isIssuer = true; 1.211 + size_t i = 0; 1.212 + for (;;) { 1.213 + ScopedCERTCertificate potentialSigner; 1.214 + if (isIssuer) { 1.215 + potentialSigner = CERT_DupCertificate(&issuerCert); 1.216 + } else if (i < numCerts) { 1.217 + potentialSigner = CERT_NewTempCertificate( 1.218 + CERT_GetDefaultCertDB(), 1.219 + /*TODO*/const_cast<SECItem*>(&certs[i]), nullptr, 1.220 + false, false); 1.221 + if (!potentialSigner) { 1.222 + return nullptr; 1.223 + } 1.224 + ++i; 1.225 + } else { 1.226 + PR_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT, 0); 1.227 + return nullptr; 1.228 + } 1.229 + 1.230 + bool match; 1.231 + switch (responderIDType) { 1.232 + case ResponderIDType::byName: 1.233 + // The CA is very likely to have encoded the name in the OCSP response 1.234 + // exactly the same as the name is encoded in the signing certificate. 1.235 + // Consequently, most of the time we will avoid parsing the name 1.236 + // completely. We're assuming here that the signer's subject name is 1.237 + // correctly formatted. 1.238 + // TODO: need test for exact name 1.239 + // TODO: need test for non-exact name match 1.240 + match = SECITEM_ItemsAreEqual(&responderIDItem, 1.241 + &potentialSigner->derSubject); 1.242 + if (!match) { 1.243 + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); 1.244 + if (!arena) { 1.245 + return nullptr; 1.246 + } 1.247 + CERTName name; 1.248 + if (SEC_QuickDERDecodeItem(arena.get(), &name, 1.249 + SEC_ASN1_GET(CERT_NameTemplate), 1.250 + &responderIDItem) != SECSuccess) { 1.251 + return nullptr; 1.252 + } 1.253 + match = CERT_CompareName(&name, &potentialSigner->subject) == SECEqual; 1.254 + } 1.255 + break; 1.256 + 1.257 + case ResponderIDType::byKey: 1.258 + { 1.259 + der::Input responderID; 1.260 + if (responderID.Init(responderIDItem.data, responderIDItem.len) 1.261 + != der::Success) { 1.262 + return nullptr; 1.263 + } 1.264 + SECItem issuerKeyHash; 1.265 + if (der::Skip(responderID, der::OCTET_STRING, issuerKeyHash) != der::Success) { 1.266 + return nullptr; 1.267 + } 1.268 + if (MatchIssuerKey(issuerKeyHash, *potentialSigner.get(), match) 1.269 + != der::Success) { 1.270 + return nullptr; 1.271 + } 1.272 + break; 1.273 + } 1.274 + 1.275 + default: 1.276 + PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0); 1.277 + return nullptr; 1.278 + } 1.279 + 1.280 + if (match && !isIssuer) { 1.281 + Result rv = CheckOCSPResponseSignerCert(trustDomain, 1.282 + *potentialSigner.get(), 1.283 + issuerCert, time); 1.284 + if (rv == RecoverableError) { 1.285 + match = false; 1.286 + } else if (rv != Success) { 1.287 + return nullptr; 1.288 + } 1.289 + } 1.290 + 1.291 + if (match) { 1.292 + return potentialSigner.release(); 1.293 + } 1.294 + 1.295 + isIssuer = false; 1.296 + } 1.297 +} 1.298 + 1.299 +static SECStatus 1.300 +VerifySignature(Context& context, ResponderIDType responderIDType, 1.301 + const SECItem& responderID, const SECItem* certs, 1.302 + size_t numCerts, const CERTSignedData& signedResponseData) 1.303 +{ 1.304 + ScopedCERTCertificate signer( 1.305 + GetOCSPSignerCertificate(context.trustDomain, responderIDType, responderID, 1.306 + certs, numCerts, context.issuerCert, 1.307 + context.time)); 1.308 + if (!signer) { 1.309 + return SECFailure; 1.310 + } 1.311 + 1.312 + if (context.trustDomain.VerifySignedData(&signedResponseData, signer.get()) 1.313 + != SECSuccess) { 1.314 + if (PR_GetError() == SEC_ERROR_BAD_SIGNATURE) { 1.315 + PR_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE, 0); 1.316 + } 1.317 + return SECFailure; 1.318 + } 1.319 + 1.320 + return SECSuccess; 1.321 +} 1.322 + 1.323 +static inline void 1.324 +SetErrorToMalformedResponseOnBadDERError() 1.325 +{ 1.326 + if (PR_GetError() == SEC_ERROR_BAD_DER) { 1.327 + PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0); 1.328 + } 1.329 +} 1.330 + 1.331 +SECStatus 1.332 +VerifyEncodedOCSPResponse(TrustDomain& trustDomain, 1.333 + const CERTCertificate* cert, 1.334 + CERTCertificate* issuerCert, PRTime time, 1.335 + uint16_t maxOCSPLifetimeInDays, 1.336 + const SECItem* encodedResponse, 1.337 + bool& expired, 1.338 + PRTime* thisUpdate, 1.339 + PRTime* validThrough) 1.340 +{ 1.341 + PR_ASSERT(cert); 1.342 + PR_ASSERT(issuerCert); 1.343 + // TODO: PR_Assert(pinArg) 1.344 + PR_ASSERT(encodedResponse); 1.345 + if (!cert || !issuerCert || !encodedResponse || !encodedResponse->data) { 1.346 + PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 1.347 + return SECFailure; 1.348 + } 1.349 + 1.350 + // Always initialize this to something reasonable. 1.351 + expired = false; 1.352 + 1.353 + der::Input input; 1.354 + if (input.Init(encodedResponse->data, encodedResponse->len) != der::Success) { 1.355 + SetErrorToMalformedResponseOnBadDERError(); 1.356 + return SECFailure; 1.357 + } 1.358 + Context context(trustDomain, *cert, *issuerCert, time, maxOCSPLifetimeInDays, 1.359 + thisUpdate, validThrough); 1.360 + 1.361 + if (der::Nested(input, der::SEQUENCE, 1.362 + bind(OCSPResponse, _1, ref(context))) != der::Success) { 1.363 + SetErrorToMalformedResponseOnBadDERError(); 1.364 + return SECFailure; 1.365 + } 1.366 + 1.367 + if (der::End(input) != der::Success) { 1.368 + SetErrorToMalformedResponseOnBadDERError(); 1.369 + return SECFailure; 1.370 + } 1.371 + 1.372 + expired = context.expired; 1.373 + 1.374 + switch (context.certStatus) { 1.375 + case CertStatus::Good: 1.376 + if (expired) { 1.377 + PR_SetError(SEC_ERROR_OCSP_OLD_RESPONSE, 0); 1.378 + return SECFailure; 1.379 + } 1.380 + return SECSuccess; 1.381 + case CertStatus::Revoked: 1.382 + PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0); 1.383 + return SECFailure; 1.384 + case CertStatus::Unknown: 1.385 + PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0); 1.386 + return SECFailure; 1.387 + } 1.388 + 1.389 + PR_NOT_REACHED("unknown CertStatus"); 1.390 + PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0); 1.391 + return SECFailure; 1.392 +} 1.393 + 1.394 +// OCSPResponse ::= SEQUENCE { 1.395 +// responseStatus OCSPResponseStatus, 1.396 +// responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } 1.397 +// 1.398 +static inline der::Result 1.399 +OCSPResponse(der::Input& input, Context& context) 1.400 +{ 1.401 + // OCSPResponseStatus ::= ENUMERATED { 1.402 + // successful (0), -- Response has valid confirmations 1.403 + // malformedRequest (1), -- Illegal confirmation request 1.404 + // internalError (2), -- Internal error in issuer 1.405 + // tryLater (3), -- Try again later 1.406 + // -- (4) is not used 1.407 + // sigRequired (5), -- Must sign the request 1.408 + // unauthorized (6) -- Request unauthorized 1.409 + // } 1.410 + uint8_t responseStatus; 1.411 + 1.412 + if (der::Enumerated(input, responseStatus) != der::Success) { 1.413 + return der::Failure; 1.414 + } 1.415 + switch (responseStatus) { 1.416 + case 0: break; // successful 1.417 + case 1: return der::Fail(SEC_ERROR_OCSP_MALFORMED_REQUEST); 1.418 + case 2: return der::Fail(SEC_ERROR_OCSP_SERVER_ERROR); 1.419 + case 3: return der::Fail(SEC_ERROR_OCSP_TRY_SERVER_LATER); 1.420 + case 5: return der::Fail(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG); 1.421 + case 6: return der::Fail(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST); 1.422 + default: return der::Fail(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS); 1.423 + } 1.424 + 1.425 + return der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0, 1.426 + der::SEQUENCE, bind(ResponseBytes, _1, ref(context))); 1.427 +} 1.428 + 1.429 +// ResponseBytes ::= SEQUENCE { 1.430 +// responseType OBJECT IDENTIFIER, 1.431 +// response OCTET STRING } 1.432 +static inline der::Result 1.433 +ResponseBytes(der::Input& input, Context& context) 1.434 +{ 1.435 + static const uint8_t id_pkix_ocsp_basic[] = { 1.436 + 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 1.437 + }; 1.438 + 1.439 + if (der::OID(input, id_pkix_ocsp_basic) != der::Success) { 1.440 + return der::Failure; 1.441 + } 1.442 + 1.443 + return der::Nested(input, der::OCTET_STRING, der::SEQUENCE, 1.444 + bind(BasicResponse, _1, ref(context))); 1.445 +} 1.446 + 1.447 +// BasicOCSPResponse ::= SEQUENCE { 1.448 +// tbsResponseData ResponseData, 1.449 +// signatureAlgorithm AlgorithmIdentifier, 1.450 +// signature BIT STRING, 1.451 +// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } 1.452 +der::Result 1.453 +BasicResponse(der::Input& input, Context& context) 1.454 +{ 1.455 + der::Input::Mark mark(input.GetMark()); 1.456 + 1.457 + uint16_t length; 1.458 + if (der::ExpectTagAndGetLength(input, der::SEQUENCE, length) 1.459 + != der::Success) { 1.460 + return der::Failure; 1.461 + } 1.462 + 1.463 + // The signature covers the entire DER encoding of tbsResponseData, including 1.464 + // the beginning tag and length. However, when we're parsing tbsResponseData, 1.465 + // we want to strip off the tag and length because we don't need it after 1.466 + // we've confirmed it's there and figured out what length it is. 1.467 + 1.468 + der::Input tbsResponseData; 1.469 + 1.470 + if (input.Skip(length, tbsResponseData) != der::Success) { 1.471 + return der::Failure; 1.472 + } 1.473 + 1.474 + CERTSignedData signedData; 1.475 + 1.476 + input.GetSECItem(siBuffer, mark, signedData.data); 1.477 + 1.478 + if (der::Nested(input, der::SEQUENCE, 1.479 + bind(der::AlgorithmIdentifier, _1, 1.480 + ref(signedData.signatureAlgorithm))) != der::Success) { 1.481 + return der::Failure; 1.482 + } 1.483 + 1.484 + if (der::Skip(input, der::BIT_STRING, signedData.signature) != der::Success) { 1.485 + return der::Failure; 1.486 + } 1.487 + if (signedData.signature.len == 0) { 1.488 + return der::Fail(SEC_ERROR_OCSP_BAD_SIGNATURE); 1.489 + } 1.490 + unsigned int unusedBitsAtEnd = signedData.signature.data[0]; 1.491 + // XXX: Really the constraint should be that unusedBitsAtEnd must be less 1.492 + // than 7. But, we suspect there are no valid OCSP response signatures with 1.493 + // non-zero unused bits. It seems like NSS assumes this in various places, so 1.494 + // we enforce it. If we find compatibility issues, we'll know we're wrong. 1.495 + if (unusedBitsAtEnd != 0) { 1.496 + return der::Fail(SEC_ERROR_OCSP_BAD_SIGNATURE); 1.497 + } 1.498 + ++signedData.signature.data; 1.499 + --signedData.signature.len; 1.500 + signedData.signature.len = (signedData.signature.len << 3); // Bytes to bits 1.501 + 1.502 + // Parse certificates, if any 1.503 + 1.504 + SECItem certs[8]; 1.505 + size_t numCerts = 0; 1.506 + 1.507 + if (!input.AtEnd()) { 1.508 + // We ignore the lengths of the wrappers because we'll detect bad lengths 1.509 + // during parsing--too short and we'll run out of input for parsing a cert, 1.510 + // and too long and we'll have leftover data that won't parse as a cert. 1.511 + 1.512 + // [0] wrapper 1.513 + if (der::ExpectTagAndIgnoreLength( 1.514 + input, der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0) 1.515 + != der::Success) { 1.516 + return der::Failure; 1.517 + } 1.518 + 1.519 + // SEQUENCE wrapper 1.520 + if (der::ExpectTagAndIgnoreLength(input, der::SEQUENCE) != der::Success) { 1.521 + return der::Failure; 1.522 + } 1.523 + 1.524 + // sequence of certificates 1.525 + while (!input.AtEnd()) { 1.526 + if (numCerts == PR_ARRAY_SIZE(certs)) { 1.527 + return der::Fail(SEC_ERROR_BAD_DER); 1.528 + } 1.529 + 1.530 + // Unwrap the SEQUENCE that contains the certificate, which is itself a 1.531 + // SEQUENCE. 1.532 + der::Input::Mark mark(input.GetMark()); 1.533 + if (der::Skip(input, der::SEQUENCE) != der::Success) { 1.534 + return der::Failure; 1.535 + } 1.536 + 1.537 + input.GetSECItem(siBuffer, mark, certs[numCerts]); 1.538 + ++numCerts; 1.539 + } 1.540 + } 1.541 + 1.542 + return ResponseData(tbsResponseData, context, signedData, certs, numCerts); 1.543 +} 1.544 + 1.545 +// ResponseData ::= SEQUENCE { 1.546 +// version [0] EXPLICIT Version DEFAULT v1, 1.547 +// responderID ResponderID, 1.548 +// producedAt GeneralizedTime, 1.549 +// responses SEQUENCE OF SingleResponse, 1.550 +// responseExtensions [1] EXPLICIT Extensions OPTIONAL } 1.551 +static inline der::Result 1.552 +ResponseData(der::Input& input, Context& context, 1.553 + const CERTSignedData& signedResponseData, 1.554 + /*const*/ SECItem* certs, size_t numCerts) 1.555 +{ 1.556 + uint8_t version; 1.557 + if (der::OptionalVersion(input, version) != der::Success) { 1.558 + return der::Failure; 1.559 + } 1.560 + if (version != der::v1) { 1.561 + // TODO: more specific error code for bad version? 1.562 + return der::Fail(SEC_ERROR_BAD_DER); 1.563 + } 1.564 + 1.565 + // ResponderID ::= CHOICE { 1.566 + // byName [1] Name, 1.567 + // byKey [2] KeyHash } 1.568 + SECItem responderID; 1.569 + uint16_t responderIDLength; 1.570 + ResponderIDType responderIDType 1.571 + = input.Peek(static_cast<uint8_t>(ResponderIDType::byName)) 1.572 + ? ResponderIDType::byName 1.573 + : ResponderIDType::byKey; 1.574 + if (ExpectTagAndGetLength(input, static_cast<uint8_t>(responderIDType), 1.575 + responderIDLength) != der::Success) { 1.576 + return der::Failure; 1.577 + } 1.578 + // TODO: responderID probably needs to have another level of ASN1 tag/length 1.579 + // checked and stripped. 1.580 + if (input.Skip(responderIDLength, responderID) != der::Success) { 1.581 + return der::Failure; 1.582 + } 1.583 + 1.584 + // This is the soonest we can verify the signature. We verify the signature 1.585 + // right away to follow the principal of minimizing the processing of data 1.586 + // before verifying its signature. 1.587 + if (VerifySignature(context, responderIDType, responderID, certs, numCerts, 1.588 + signedResponseData) != SECSuccess) { 1.589 + return der::Failure; 1.590 + } 1.591 + 1.592 + // TODO: Do we even need to parse this? Should we just skip it? 1.593 + PRTime producedAt; 1.594 + if (der::GeneralizedTime(input, producedAt) != der::Success) { 1.595 + return der::Failure; 1.596 + } 1.597 + 1.598 + // We don't accept an empty sequence of responses. In practice, a legit OCSP 1.599 + // responder will never return an empty response, and handling the case of an 1.600 + // empty response makes things unnecessarily complicated. 1.601 + if (der::NestedOf(input, der::SEQUENCE, der::SEQUENCE, 1.602 + der::MustNotBeEmpty, 1.603 + bind(SingleResponse, _1, ref(context))) != der::Success) { 1.604 + return der::Failure; 1.605 + } 1.606 + 1.607 + if (!input.AtEnd()) { 1.608 + if (der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, 1.609 + CheckExtensionsForCriticality) != der::Success) { 1.610 + return der::Failure; 1.611 + } 1.612 + } 1.613 + 1.614 + return der::Success; 1.615 +} 1.616 + 1.617 +// SingleResponse ::= SEQUENCE { 1.618 +// certID CertID, 1.619 +// certStatus CertStatus, 1.620 +// thisUpdate GeneralizedTime, 1.621 +// nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, 1.622 +// singleExtensions [1] EXPLICIT Extensions{{re-ocsp-crl | 1.623 +// re-ocsp-archive-cutoff | 1.624 +// CrlEntryExtensions, ...} 1.625 +// } OPTIONAL } 1.626 +static inline der::Result 1.627 +SingleResponse(der::Input& input, Context& context) 1.628 +{ 1.629 + bool match = false; 1.630 + if (der::Nested(input, der::SEQUENCE, 1.631 + bind(CertID, _1, cref(context), ref(match))) 1.632 + != der::Success) { 1.633 + return der::Failure; 1.634 + } 1.635 + 1.636 + if (!match) { 1.637 + // This response does not reference the certificate we're interested in. 1.638 + // By consuming the rest of our input and returning successfully, we can 1.639 + // continue processing and examine another response that might have what 1.640 + // we want. 1.641 + input.SkipToEnd(); 1.642 + return der::Success; 1.643 + } 1.644 + 1.645 + // CertStatus ::= CHOICE { 1.646 + // good [0] IMPLICIT NULL, 1.647 + // revoked [1] IMPLICIT RevokedInfo, 1.648 + // unknown [2] IMPLICIT UnknownInfo } 1.649 + // 1.650 + // In the event of multiple SingleResponses for a cert that have conflicting 1.651 + // statuses, we use the following precedence rules: 1.652 + // 1.653 + // * revoked overrides good and unknown 1.654 + // * good overrides unknown 1.655 + if (input.Peek(static_cast<uint8_t>(CertStatus::Good))) { 1.656 + if (ExpectTagAndLength(input, static_cast<uint8_t>(CertStatus::Good), 0) 1.657 + != der::Success) { 1.658 + return der::Failure; 1.659 + } 1.660 + if (context.certStatus != CertStatus::Revoked) { 1.661 + context.certStatus = CertStatus::Good; 1.662 + } 1.663 + } else if (input.Peek(static_cast<uint8_t>(CertStatus::Revoked))) { 1.664 + // We don't need any info from the RevokedInfo structure, so we don't even 1.665 + // parse it. TODO: We should mention issues like this in the explanation of 1.666 + // why we treat invalid OCSP responses equivalently to revoked for OCSP 1.667 + // stapling. 1.668 + if (der::Skip(input, static_cast<uint8_t>(CertStatus::Revoked)) 1.669 + != der::Success) { 1.670 + return der::Failure; 1.671 + } 1.672 + context.certStatus = CertStatus::Revoked; 1.673 + } else if (ExpectTagAndLength(input, 1.674 + static_cast<uint8_t>(CertStatus::Unknown), 1.675 + 0) != der::Success) { 1.676 + return der::Failure; 1.677 + } 1.678 + 1.679 + // http://tools.ietf.org/html/rfc6960#section-3.2 1.680 + // 5. The time at which the status being indicated is known to be 1.681 + // correct (thisUpdate) is sufficiently recent; 1.682 + // 6. When available, the time at or before which newer information will 1.683 + // be available about the status of the certificate (nextUpdate) is 1.684 + // greater than the current time. 1.685 + 1.686 + const PRTime maxLifetime = 1.687 + context.maxLifetimeInDays * ONE_DAY; 1.688 + 1.689 + PRTime thisUpdate; 1.690 + if (der::GeneralizedTime(input, thisUpdate) != der::Success) { 1.691 + return der::Failure; 1.692 + } 1.693 + 1.694 + if (thisUpdate > context.time + SLOP) { 1.695 + return der::Fail(SEC_ERROR_OCSP_FUTURE_RESPONSE); 1.696 + } 1.697 + 1.698 + PRTime notAfter; 1.699 + static const uint8_t NEXT_UPDATE_TAG = 1.700 + der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0; 1.701 + if (input.Peek(NEXT_UPDATE_TAG)) { 1.702 + PRTime nextUpdate; 1.703 + if (der::Nested(input, NEXT_UPDATE_TAG, 1.704 + bind(der::GeneralizedTime, _1, ref(nextUpdate))) 1.705 + != der::Success) { 1.706 + return der::Failure; 1.707 + } 1.708 + 1.709 + if (nextUpdate < thisUpdate) { 1.710 + return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.711 + } 1.712 + if (nextUpdate - thisUpdate <= maxLifetime) { 1.713 + notAfter = nextUpdate; 1.714 + } else { 1.715 + notAfter = thisUpdate + maxLifetime; 1.716 + } 1.717 + } else { 1.718 + // NSS requires all OCSP responses without a nextUpdate to be recent. 1.719 + // Match that stricter behavior. 1.720 + notAfter = thisUpdate + ONE_DAY; 1.721 + } 1.722 + 1.723 + if (context.time < SLOP) { // prevent underflow 1.724 + return der::Fail(SEC_ERROR_INVALID_ARGS); 1.725 + } 1.726 + 1.727 + if (context.time - SLOP > notAfter) { 1.728 + context.expired = true; 1.729 + } 1.730 + 1.731 + if (!input.AtEnd()) { 1.732 + if (der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, 1.733 + CheckExtensionsForCriticality) != der::Success) { 1.734 + return der::Failure; 1.735 + } 1.736 + } 1.737 + 1.738 + if (context.thisUpdate) { 1.739 + *context.thisUpdate = thisUpdate; 1.740 + } 1.741 + if (context.validThrough) { 1.742 + *context.validThrough = notAfter; 1.743 + } 1.744 + 1.745 + return der::Success; 1.746 +} 1.747 + 1.748 +// CertID ::= SEQUENCE { 1.749 +// hashAlgorithm AlgorithmIdentifier, 1.750 +// issuerNameHash OCTET STRING, -- Hash of issuer's DN 1.751 +// issuerKeyHash OCTET STRING, -- Hash of issuer's public key 1.752 +// serialNumber CertificateSerialNumber } 1.753 +static inline der::Result 1.754 +CertID(der::Input& input, const Context& context, /*out*/ bool& match) 1.755 +{ 1.756 + match = false; 1.757 + 1.758 + SECAlgorithmID hashAlgorithm; 1.759 + if (der::Nested(input, der::SEQUENCE, 1.760 + bind(der::AlgorithmIdentifier, _1, ref(hashAlgorithm))) 1.761 + != der::Success) { 1.762 + return der::Failure; 1.763 + } 1.764 + 1.765 + SECItem issuerNameHash; 1.766 + if (der::Skip(input, der::OCTET_STRING, issuerNameHash) != der::Success) { 1.767 + return der::Failure; 1.768 + } 1.769 + 1.770 + SECItem issuerKeyHash; 1.771 + if (der::Skip(input, der::OCTET_STRING, issuerKeyHash) != der::Success) { 1.772 + return der::Failure; 1.773 + } 1.774 + 1.775 + SECItem serialNumber; 1.776 + if (der::CertificateSerialNumber(input, serialNumber) != der::Success) { 1.777 + return der::Failure; 1.778 + } 1.779 + 1.780 + const CERTCertificate& cert = context.cert; 1.781 + const CERTCertificate& issuerCert = context.issuerCert; 1.782 + 1.783 + if (!SECITEM_ItemsAreEqual(&serialNumber, &cert.serialNumber)) { 1.784 + // This does not reference the certificate we're interested in. 1.785 + // Consume the rest of the input and return successfully to 1.786 + // potentially continue processing other responses. 1.787 + input.SkipToEnd(); 1.788 + return der::Success; 1.789 + } 1.790 + 1.791 + // TODO: support SHA-2 hashes. 1.792 + 1.793 + SECOidTag hashAlg = SECOID_GetAlgorithmTag(&hashAlgorithm); 1.794 + if (hashAlg != SEC_OID_SHA1) { 1.795 + // Again, not interested in this response. Consume input, return success. 1.796 + input.SkipToEnd(); 1.797 + return der::Success; 1.798 + } 1.799 + 1.800 + if (issuerNameHash.len != SHA1_LENGTH) { 1.801 + return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.802 + } 1.803 + 1.804 + // From http://tools.ietf.org/html/rfc6960#section-4.1.1: 1.805 + // "The hash shall be calculated over the DER encoding of the 1.806 + // issuer's name field in the certificate being checked." 1.807 + uint8_t hashBuf[SHA1_LENGTH]; 1.808 + if (PK11_HashBuf(SEC_OID_SHA1, hashBuf, cert.derIssuer.data, 1.809 + cert.derIssuer.len) != SECSuccess) { 1.810 + return der::Failure; 1.811 + } 1.812 + if (memcmp(hashBuf, issuerNameHash.data, issuerNameHash.len)) { 1.813 + // Again, not interested in this response. Consume input, return success. 1.814 + input.SkipToEnd(); 1.815 + return der::Success; 1.816 + } 1.817 + 1.818 + return MatchIssuerKey(issuerKeyHash, issuerCert, match); 1.819 +} 1.820 + 1.821 +// From http://tools.ietf.org/html/rfc6960#section-4.1.1: 1.822 +// "The hash shall be calculated over the value (excluding tag and length) of 1.823 +// the subject public key field in the issuer's certificate." 1.824 +static der::Result 1.825 +MatchIssuerKey(const SECItem& issuerKeyHash, const CERTCertificate& issuer, 1.826 + /*out*/ bool& match) 1.827 +{ 1.828 + if (issuerKeyHash.len != SHA1_LENGTH) { 1.829 + return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.830 + } 1.831 + 1.832 + // TODO(bug 966856): support SHA-2 hashes 1.833 + 1.834 + // Copy just the length and data pointer (nothing needs to be freed) of the 1.835 + // subject public key so we can convert the length from bits to bytes, which 1.836 + // is what the digest function expects. 1.837 + SECItem spk = issuer.subjectPublicKeyInfo.subjectPublicKey; 1.838 + DER_ConvertBitString(&spk); 1.839 + 1.840 + static uint8_t hashBuf[SHA1_LENGTH]; 1.841 + if (PK11_HashBuf(SEC_OID_SHA1, hashBuf, spk.data, spk.len) != SECSuccess) { 1.842 + return der::Failure; 1.843 + } 1.844 + 1.845 + match = !memcmp(hashBuf, issuerKeyHash.data, issuerKeyHash.len); 1.846 + return der::Success; 1.847 +} 1.848 + 1.849 +// Extension ::= SEQUENCE { 1.850 +// extnID OBJECT IDENTIFIER, 1.851 +// critical BOOLEAN DEFAULT FALSE, 1.852 +// extnValue OCTET STRING 1.853 +// } 1.854 +static der::Result 1.855 +CheckExtensionForCriticality(der::Input& input) 1.856 +{ 1.857 + uint16_t toSkip; 1.858 + if (ExpectTagAndGetLength(input, der::OIDTag, toSkip) != der::Success) { 1.859 + return der::Failure; 1.860 + } 1.861 + 1.862 + // TODO: maybe we should check the syntax of the OID value 1.863 + if (input.Skip(toSkip) != der::Success) { 1.864 + return der::Failure; 1.865 + } 1.866 + 1.867 + // The only valid explicit encoding of the value is TRUE, so don't even 1.868 + // bother parsing it, since we're going to fail either way. 1.869 + if (input.Peek(der::BOOLEAN)) { 1.870 + return der::Fail(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); 1.871 + } 1.872 + 1.873 + if (ExpectTagAndGetLength(input, der::OCTET_STRING, toSkip) 1.874 + != der::Success) { 1.875 + return der::Failure; 1.876 + } 1.877 + return input.Skip(toSkip); 1.878 +} 1.879 + 1.880 +// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension 1.881 +static der::Result 1.882 +CheckExtensionsForCriticality(der::Input& input) 1.883 +{ 1.884 + // TODO(bug 997994): some responders include an empty SEQUENCE OF 1.885 + // Extension, which is invalid (der::MayBeEmpty should really be 1.886 + // der::MustNotBeEmpty). 1.887 + return der::NestedOf(input, der::SEQUENCE, der::SEQUENCE, 1.888 + der::MayBeEmpty, CheckExtensionForCriticality); 1.889 +} 1.890 + 1.891 +// 1. The certificate identified in a received response corresponds to 1.892 +// the certificate that was identified in the corresponding request; 1.893 +// 2. The signature on the response is valid; 1.894 +// 3. The identity of the signer matches the intended recipient of the 1.895 +// request; 1.896 +// 4. The signer is currently authorized to provide a response for the 1.897 +// certificate in question; 1.898 +// 5. The time at which the status being indicated is known to be 1.899 +// correct (thisUpdate) is sufficiently recent; 1.900 +// 6. When available, the time at or before which newer information will 1.901 +// be available about the status of the certificate (nextUpdate) is 1.902 +// greater than the current time. 1.903 +// 1.904 +// Responses whose nextUpdate value is earlier than 1.905 +// the local system time value SHOULD be considered unreliable. 1.906 +// Responses whose thisUpdate time is later than the local system time 1.907 +// SHOULD be considered unreliable. 1.908 +// 1.909 +// If nextUpdate is not set, the responder is indicating that newer 1.910 +// revocation information is available all the time. 1.911 +// 1.912 +// http://tools.ietf.org/html/rfc5019#section-4 1.913 + 1.914 +SECItem* 1.915 +CreateEncodedOCSPRequest(PLArenaPool* arena, 1.916 + const CERTCertificate* cert, 1.917 + const CERTCertificate* issuerCert) 1.918 +{ 1.919 + if (!arena || !cert || !issuerCert) { 1.920 + PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 1.921 + return nullptr; 1.922 + } 1.923 + 1.924 + // We do not add any extensions to the request. 1.925 + 1.926 + // RFC 6960 says "An OCSP client MAY wish to specify the kinds of response 1.927 + // types it understands. To do so, it SHOULD use an extension with the OID 1.928 + // id-pkix-ocsp-response." This use of MAY and SHOULD is unclear. MSIE11 1.929 + // on Windows 8.1 does not include any extensions, whereas NSS has always 1.930 + // included the id-pkix-ocsp-response extension. Avoiding the sending the 1.931 + // extension is better for OCSP GET because it makes the request smaller, 1.932 + // and thus more likely to fit within the 255 byte limit for OCSP GET that 1.933 + // is specified in RFC 5019 Section 5. 1.934 + 1.935 + // Bug 966856: Add the id-pkix-ocsp-pref-sig-algs extension. 1.936 + 1.937 + // Since we don't know whether the OCSP responder supports anything other 1.938 + // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and 1.939 + // issuerKeyHash. 1.940 + static const uint8_t hashAlgorithm[11] = { 1.941 + 0x30, 0x09, // SEQUENCE 1.942 + 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJECT IDENTIFIER id-sha1 1.943 + 0x05, 0x00, // NULL 1.944 + }; 1.945 + static const uint8_t hashLen = SHA1_LENGTH; 1.946 + 1.947 + static const unsigned int totalLenWithoutSerialNumberData 1.948 + = 2 // OCSPRequest 1.949 + + 2 // tbsRequest 1.950 + + 2 // requestList 1.951 + + 2 // Request 1.952 + + 2 // reqCert (CertID) 1.953 + + PR_ARRAY_SIZE(hashAlgorithm) // hashAlgorithm 1.954 + + 2 + hashLen // issuerNameHash 1.955 + + 2 + hashLen // issuerKeyHash 1.956 + + 2; // serialNumber (header) 1.957 + 1.958 + // The only way we could have a request this large is if the serialNumber was 1.959 + // ridiculously and unreasonably large. RFC 5280 says "Conforming CAs MUST 1.960 + // NOT use serialNumber values longer than 20 octets." With this restriction, 1.961 + // we allow for some amount of non-conformance with that requirement while 1.962 + // still ensuring we can encode the length values in the ASN.1 TLV structures 1.963 + // in a single byte. 1.964 + if (issuerCert->serialNumber.len > 127u - totalLenWithoutSerialNumberData) { 1.965 + PR_SetError(SEC_ERROR_BAD_DATA, 0); 1.966 + return nullptr; 1.967 + } 1.968 + 1.969 + uint8_t totalLen = static_cast<uint8_t>(totalLenWithoutSerialNumberData + 1.970 + cert->serialNumber.len); 1.971 + 1.972 + SECItem* encodedRequest = SECITEM_AllocItem(arena, nullptr, totalLen); 1.973 + if (!encodedRequest) { 1.974 + return nullptr; 1.975 + } 1.976 + 1.977 + uint8_t* d = encodedRequest->data; 1.978 + *d++ = 0x30; *d++ = totalLen - 2; // OCSPRequest (SEQUENCE) 1.979 + *d++ = 0x30; *d++ = totalLen - 4; // tbsRequest (SEQUENCE) 1.980 + *d++ = 0x30; *d++ = totalLen - 6; // requestList (SEQUENCE OF) 1.981 + *d++ = 0x30; *d++ = totalLen - 8; // Request (SEQUENCE) 1.982 + *d++ = 0x30; *d++ = totalLen - 10; // reqCert (CertID SEQUENCE) 1.983 + 1.984 + // reqCert.hashAlgorithm 1.985 + for (size_t i = 0; i < PR_ARRAY_SIZE(hashAlgorithm); ++i) { 1.986 + *d++ = hashAlgorithm[i]; 1.987 + } 1.988 + 1.989 + // reqCert.issuerNameHash (OCTET STRING) 1.990 + *d++ = 0x04; 1.991 + *d++ = hashLen; 1.992 + if (PK11_HashBuf(SEC_OID_SHA1, d, issuerCert->derSubject.data, 1.993 + issuerCert->derSubject.len) != SECSuccess) { 1.994 + return nullptr; 1.995 + } 1.996 + d += hashLen; 1.997 + 1.998 + // reqCert.issuerKeyHash (OCTET STRING) 1.999 + *d++ = 0x04; 1.1000 + *d++ = hashLen; 1.1001 + SECItem key = issuerCert->subjectPublicKeyInfo.subjectPublicKey; 1.1002 + DER_ConvertBitString(&key); 1.1003 + if (PK11_HashBuf(SEC_OID_SHA1, d, key.data, key.len) != SECSuccess) { 1.1004 + return nullptr; 1.1005 + } 1.1006 + d += hashLen; 1.1007 + 1.1008 + // reqCert.serialNumber (INTEGER) 1.1009 + *d++ = 0x02; // INTEGER 1.1010 + *d++ = static_cast<uint8_t>(cert->serialNumber.len); 1.1011 + for (size_t i = 0; i < cert->serialNumber.len; ++i) { 1.1012 + *d++ = cert->serialNumber.data[i]; 1.1013 + } 1.1014 + 1.1015 + PR_ASSERT(d == encodedRequest->data + totalLen); 1.1016 + 1.1017 + return encodedRequest; 1.1018 +} 1.1019 + 1.1020 +} } // namespace mozilla::pkix