tor-browser

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

GenerateOCSPResponse.cpp (5924B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 sw=2 tw=80 et: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* This simple program takes a database directory, and one or more tuples like
      8 * <typeOfResponse> <CertNick> <ExtraCertNick> <outPutFilename>
      9 * to generate (one or more) ocsp responses.
     10 */
     11 
     12 #include "cert.h"
     13 #include "nspr.h"
     14 #include "nss.h"
     15 #include "plarenas.h"
     16 #include "prerror.h"
     17 #include "ssl.h"
     18 #include "secerr.h"
     19 
     20 #include "OCSPCommon.h"
     21 #include "ScopedNSSTypes.h"
     22 #include "TLSServer.h"
     23 
     24 using namespace mozilla;
     25 using namespace mozilla::test;
     26 
     27 struct OCSPResponseName {
     28  const char* mTypeString;
     29  const OCSPResponseType mORT;
     30 };
     31 
     32 const static OCSPResponseName kOCSPResponseNameList[] = {
     33    {"good", ORTGood},                         // the certificate is good
     34    {"good-delegated", ORTDelegatedIncluded},  // the certificate is good, using
     35                                               // a delegated signer
     36    {"revoked", ORTRevoked},                // the certificate has been revoked
     37    {"unknown", ORTUnknown},                // the responder doesn't know if the
     38                                            //   cert is good
     39    {"goodotherca", ORTGoodOtherCA},        // the wrong CA has signed the
     40                                            //   response
     41    {"expiredresponse", ORTExpired},        // the signature on the response has
     42                                            //   expired
     43    {"oldvalidperiod", ORTExpiredFreshCA},  // fresh signature, but old validity
     44                                            //   period
     45    {"empty", ORTEmpty},                    // an empty stapled response
     46 
     47    {"malformed", ORTMalformed},         // the response from the responder
     48                                         //   was malformed
     49    {"serverr", ORTSrverr},              // the response indicates there was a
     50                                         //   server error
     51    {"trylater", ORTTryLater},           // the responder replied with
     52                                         //   "try again later"
     53    {"resp-unsigned", ORTNeedsSig},      // the response needs a signature
     54    {"unauthorized", ORTUnauthorized},   // the responder does not know about
     55                                         //   the cert
     56    {"bad-signature", ORTBadSignature},  // the response has a bad signature
     57    {"longvalidityalmostold",
     58     ORTLongValidityAlmostExpired},  // the response is
     59                                     // still valid, but the generation
     60                                     // is almost a year old
     61    {"ancientstillvalid", ORTAncientAlmostExpired},  // The response is still
     62                                                     // valid but the generation
     63                                                     // is almost two years old
     64 };
     65 
     66 bool StringToOCSPResponseType(const char* respText,
     67                              /*out*/ OCSPResponseType* OCSPType) {
     68  if (!OCSPType) {
     69    return false;
     70  }
     71  for (auto ocspResponseName : kOCSPResponseNameList) {
     72    if (strcmp(respText, ocspResponseName.mTypeString) == 0) {
     73      *OCSPType = ocspResponseName.mORT;
     74      return true;
     75    }
     76  }
     77  return false;
     78 }
     79 
     80 bool WriteResponse(const char* filename, const SECItem* item) {
     81  if (!filename || !item || !item->data) {
     82    PR_fprintf(PR_STDERR, "invalid parameters to WriteResponse");
     83    return false;
     84  }
     85 
     86  UniquePRFileDesc outFile(
     87      PR_Open(filename, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0644));
     88  if (!outFile) {
     89    PrintPRError("cannot open file for writing");
     90    return false;
     91  }
     92  int32_t rv = PR_Write(outFile.get(), item->data, item->len);
     93  if (rv < 0 || (uint32_t)rv != item->len) {
     94    PrintPRError("File write failure");
     95    return false;
     96  }
     97 
     98  return true;
     99 }
    100 
    101 int main(int argc, char* argv[]) {
    102  if (argc < 7 || (argc - 7) % 5 != 0) {
    103    PR_fprintf(
    104        PR_STDERR,
    105        "usage: %s <NSS DB directory> <responsetype> "
    106        "<cert_nick> <extranick> <this_update_skew> <outfilename> [<resptype> "
    107        "<cert_nick> <extranick> <this_update_skew> <outfilename>]* \n",
    108        argv[0]);
    109    exit(EXIT_FAILURE);
    110  }
    111  SECStatus rv = InitializeNSS(argv[1]);
    112  if (rv != SECSuccess) {
    113    PR_fprintf(PR_STDERR, "Failed to initialize NSS\n");
    114    exit(EXIT_FAILURE);
    115  }
    116  UniquePLArenaPool arena(PORT_NewArena(256 * argc));
    117  if (!arena) {
    118    PrintPRError("PORT_NewArena failed");
    119    exit(EXIT_FAILURE);
    120  }
    121 
    122  for (int i = 2; i + 3 < argc; i += 5) {
    123    const char* ocspTypeText = argv[i];
    124    const char* certNick = argv[i + 1];
    125    const char* extraCertname = argv[i + 2];
    126    const char* skewChars = argv[i + 3];
    127    const char* filename = argv[i + 4];
    128 
    129    OCSPResponseType ORT;
    130    if (!StringToOCSPResponseType(ocspTypeText, &ORT)) {
    131      PR_fprintf(PR_STDERR, "Cannot generate OCSP response of type %s\n",
    132                 ocspTypeText);
    133      exit(EXIT_FAILURE);
    134    }
    135 
    136    UniqueCERTCertificate cert(PK11_FindCertFromNickname(certNick, nullptr));
    137    if (!cert) {
    138      PrintPRError("PK11_FindCertFromNickname failed");
    139      PR_fprintf(PR_STDERR, "Failed to find certificate with nick '%s'\n",
    140                 certNick);
    141      exit(EXIT_FAILURE);
    142    }
    143 
    144    time_t skew = static_cast<time_t>(atoll(skewChars));
    145 
    146    SECItemArray* response =
    147        GetOCSPResponseForType(ORT, cert, arena, extraCertname, skew);
    148    if (!response) {
    149      PR_fprintf(PR_STDERR,
    150                 "Failed to generate OCSP response of type %s "
    151                 "for %s\n",
    152                 ocspTypeText, certNick);
    153      exit(EXIT_FAILURE);
    154    }
    155 
    156    if (!WriteResponse(filename, &response->items[0])) {
    157      PR_fprintf(PR_STDERR, "Failed to write file %s\n", filename);
    158      exit(EXIT_FAILURE);
    159    }
    160  }
    161  return 0;
    162 }