tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

OCSPCommon.cpp (7711B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "OCSPCommon.h"
      6 
      7 #include <stdio.h>
      8 
      9 #include "TLSServer.h"
     10 #include "mozpkix/pkixder.h"
     11 #include "mozpkix/test/pkixtestnss.h"
     12 #include "mozpkix/test/pkixtestutil.h"
     13 #include "nss.h"
     14 #include "secder.h"
     15 #include "secerr.h"
     16 
     17 using namespace mozilla;
     18 using namespace mozilla::pkix;
     19 using namespace mozilla::pkix::test;
     20 using namespace mozilla::test;
     21 
     22 static TestKeyPair* CreateTestKeyPairFromCert(
     23    const UniqueCERTCertificate& cert) {
     24  ScopedSECKEYPrivateKey privateKey(PK11_FindKeyByAnyCert(cert.get(), nullptr));
     25  if (!privateKey) {
     26    return nullptr;
     27  }
     28  ScopedSECKEYPublicKey publicKey(CERT_ExtractPublicKey(cert.get()));
     29  if (!publicKey) {
     30    return nullptr;
     31  }
     32  return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
     33 }
     34 
     35 SECItemArray* GetOCSPResponseForType(OCSPResponseType aORT,
     36                                     const UniqueCERTCertificate& aCert,
     37                                     const UniquePLArenaPool& aArena,
     38                                     const char* aAdditionalCertName,
     39                                     time_t aThisUpdateSkew,
     40                                     ByteString* aSCTList) {
     41  MOZ_ASSERT(aArena);
     42  MOZ_ASSERT(aCert);
     43  // Note: |aAdditionalCertName| may or may not need to be non-null depending
     44  //       on the |aORT| value given.
     45 
     46  // Ensure NSS can sign responses using small RSA keys.
     47  NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 512);
     48 
     49  if (aORT == ORTNone) {
     50    if (gDebugLevel >= DEBUG_WARNINGS) {
     51      fprintf(stderr,
     52              "GetOCSPResponseForType called with type ORTNone, "
     53              "which makes no sense.\n");
     54    }
     55    return nullptr;
     56  }
     57 
     58  if (aORT == ORTEmpty) {
     59    SECItemArray* arr = SECITEM_AllocArray(aArena.get(), nullptr, 1);
     60    arr->items[0].data = nullptr;
     61    arr->items[0].len = 0;
     62    return arr;
     63  }
     64 
     65  time_t now = time(nullptr) + aThisUpdateSkew;
     66  time_t oldNow = now - (8 * Time::ONE_DAY_IN_SECONDS);
     67 
     68  mozilla::UniqueCERTCertificate cert(CERT_DupCertificate(aCert.get()));
     69 
     70  if (aORT == ORTGoodOtherCert) {
     71    cert.reset(PK11_FindCertFromNickname(aAdditionalCertName, nullptr));
     72    if (!cert) {
     73      PrintPRError("PK11_FindCertFromNickname failed");
     74      return nullptr;
     75    }
     76  }
     77  // XXX CERT_FindCertIssuer uses the old, deprecated path-building logic
     78  mozilla::UniqueCERTCertificate issuerCert(
     79      CERT_FindCertIssuer(aCert.get(), PR_Now(), certUsageSSLCA));
     80  if (!issuerCert) {
     81    PrintPRError("CERT_FindCertIssuer failed");
     82    return nullptr;
     83  }
     84  Input issuer;
     85  if (issuer.Init(cert->derIssuer.data, cert->derIssuer.len) != Success) {
     86    return nullptr;
     87  }
     88  Input issuerPublicKey;
     89  if (issuerPublicKey.Init(issuerCert->derPublicKey.data,
     90                           issuerCert->derPublicKey.len) != Success) {
     91    return nullptr;
     92  }
     93  Input serialNumber;
     94  if (serialNumber.Init(cert->serialNumber.data, cert->serialNumber.len) !=
     95      Success) {
     96    return nullptr;
     97  }
     98  CertID certID(issuer, issuerPublicKey, serialNumber);
     99  OCSPResponseContext context(certID, now);
    100 
    101  mozilla::UniqueCERTCertificate signerCert;
    102  if (aORT == ORTGoodOtherCA || aORT == ORTDelegatedIncluded ||
    103      aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissing ||
    104      aORT == ORTDelegatedMissingMultiple) {
    105    signerCert.reset(PK11_FindCertFromNickname(aAdditionalCertName, nullptr));
    106    if (!signerCert) {
    107      PrintPRError("PK11_FindCertFromNickname failed");
    108      return nullptr;
    109    }
    110  }
    111 
    112  ByteString certs[5];
    113 
    114  if (aORT == ORTDelegatedIncluded) {
    115    certs[0].assign(signerCert->derCert.data, signerCert->derCert.len);
    116    context.certs = certs;
    117  }
    118  if (aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissingMultiple) {
    119    certs[0].assign(issuerCert->derCert.data, issuerCert->derCert.len);
    120    certs[1].assign(cert->derCert.data, cert->derCert.len);
    121    certs[2].assign(issuerCert->derCert.data, issuerCert->derCert.len);
    122    if (aORT != ORTDelegatedMissingMultiple) {
    123      certs[3].assign(signerCert->derCert.data, signerCert->derCert.len);
    124    }
    125    context.certs = certs;
    126  }
    127 
    128  switch (aORT) {
    129    case ORTMalformed:
    130      context.responseStatus = 1;
    131      break;
    132    case ORTSrverr:
    133      context.responseStatus = 2;
    134      break;
    135    case ORTTryLater:
    136      context.responseStatus = 3;
    137      break;
    138    case ORTNeedsSig:
    139      context.responseStatus = 5;
    140      break;
    141    case ORTUnauthorized:
    142      context.responseStatus = 6;
    143      break;
    144    default:
    145      // context.responseStatus is 0 in all other cases, and it has
    146      // already been initialized in the constructor.
    147      break;
    148  }
    149  if (aORT == ORTSkipResponseBytes) {
    150    context.skipResponseBytes = true;
    151  }
    152  if (aORT == ORTExpired || aORT == ORTExpiredFreshCA ||
    153      aORT == ORTRevokedOld || aORT == ORTUnknownOld) {
    154    context.thisUpdate = oldNow;
    155    context.nextUpdate = oldNow + Time::ONE_DAY_IN_SECONDS;
    156  }
    157  if (aORT == ORTLongValidityAlmostExpired) {
    158    context.thisUpdate = now - (320 * Time::ONE_DAY_IN_SECONDS);
    159  }
    160  if (aORT == ORTAncientAlmostExpired) {
    161    context.thisUpdate = now - (640 * Time::ONE_DAY_IN_SECONDS);
    162  }
    163  if (aORT == ORTRevoked || aORT == ORTRevokedOld) {
    164    context.certStatus = 1;
    165  }
    166  if (aORT == ORTUnknown || aORT == ORTUnknownOld) {
    167    context.certStatus = 2;
    168  }
    169  if (aORT == ORTBadSignature) {
    170    context.badSignature = true;
    171  }
    172  OCSPResponseExtension extension;
    173  if (aORT == ORTCriticalExtension || aORT == ORTNoncriticalExtension) {
    174    // python DottedOIDToCode.py --tlv
    175    // some-Mozilla-OID 1.3.6.1.4.1.13769.666.666.666.1.500.9.2
    176    static const uint8_t tlv_some_Mozilla_OID[] = {
    177        0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85,
    178        0x1a, 0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x02};
    179 
    180    extension.id.assign(tlv_some_Mozilla_OID, sizeof(tlv_some_Mozilla_OID));
    181    extension.critical = (aORT == ORTCriticalExtension);
    182    extension.value.push_back(0x05);  // tag: NULL
    183    extension.value.push_back(0x00);  // length: 0
    184    extension.next = nullptr;
    185    context.responseExtensions = &extension;
    186  }
    187  if (aORT == ORTEmptyExtensions) {
    188    context.includeEmptyExtensions = true;
    189  }
    190 
    191  if (!signerCert) {
    192    signerCert.reset(CERT_DupCertificate(issuerCert.get()));
    193  }
    194  context.signerKeyPair.reset(CreateTestKeyPairFromCert(signerCert));
    195  if (!context.signerKeyPair) {
    196    PrintPRError("PK11_FindKeyByAnyCert failed");
    197    return nullptr;
    198  }
    199 
    200  OCSPResponseExtension singleExtension;
    201  if (aSCTList) {
    202    // SingleExtension for Signed Certificate Timestamp List.
    203    // See Section 3.3 of RFC 6962.
    204    // python DottedOIDToCode.py --tlv
    205    //   id_ocsp_singleExtensionSctList 1.3.6.1.4.1.11129.2.4.5
    206    static const uint8_t tlv_id_ocsp_singleExtensionSctList[] = {
    207        0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x05};
    208    singleExtension.id.assign(tlv_id_ocsp_singleExtensionSctList,
    209                              sizeof(tlv_id_ocsp_singleExtensionSctList));
    210    singleExtension.critical = true;
    211    singleExtension.value = TLV(der::OCTET_STRING, *aSCTList);
    212    singleExtension.next = nullptr;
    213    context.singleExtensions = &singleExtension;
    214  }
    215 
    216  ByteString response(CreateEncodedOCSPResponse(context));
    217  if (ENCODING_FAILED(response)) {
    218    PrintPRError("CreateEncodedOCSPResponse failed");
    219    return nullptr;
    220  }
    221 
    222  SECItem item = {siBuffer, const_cast<uint8_t*>(response.data()),
    223                  static_cast<unsigned int>(response.length())};
    224  SECItemArray arr = {&item, 1};
    225  return SECITEM_DupArray(aArena.get(), &arr);
    226 }