security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,170 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 tw=80 et: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* This simple program takes a database directory, and one or more tuples like
    1.11 + * <typeOfResponse> <CertNick> <ExtraCertNick> <outPutFilename>
    1.12 + * to generate (one or more) ocsp responses.
    1.13 + */
    1.14 +
    1.15 +#include <stdio.h>
    1.16 +
    1.17 +#include "mozilla/ArrayUtils.h"
    1.18 +
    1.19 +#include "nspr.h"
    1.20 +#include "nss.h"
    1.21 +#include "plarenas.h"
    1.22 +#include "prerror.h"
    1.23 +#include "ssl.h"
    1.24 +#include "secerr.h"
    1.25 +
    1.26 +#include "OCSPCommon.h"
    1.27 +#include "ScopedNSSTypes.h"
    1.28 +#include "TLSServer.h"
    1.29 +
    1.30 +using namespace mozilla;
    1.31 +using namespace mozilla::test;
    1.32 +
    1.33 +struct OCSPResponseName
    1.34 +{
    1.35 +  const char *mTypeString;
    1.36 +  const OCSPResponseType mORT;
    1.37 +};
    1.38 +
    1.39 +const static OCSPResponseName kOCSPResponseNameList[] = {
    1.40 +  { "good",            ORTGood },          // the certificate is good
    1.41 +  { "revoked",         ORTRevoked},        // the certificate has been revoked
    1.42 +  { "unknown",         ORTUnknown},        // the responder doesn't know if the
    1.43 +                                           //   cert is good
    1.44 +  { "goodotherca",     ORTGoodOtherCA},    // the wrong CA has signed the
    1.45 +                                           //   response
    1.46 +  { "expiredresponse", ORTExpired},        // the signature on the response has
    1.47 +                                           //   expired
    1.48 +  { "oldvalidperiod",  ORTExpiredFreshCA}, // fresh signature, but old validity
    1.49 +                                           //   period
    1.50 +  { "empty",           ORTEmpty},          // an empty stapled response
    1.51 +
    1.52 +  { "malformed",       ORTMalformed},      // the response from the responder
    1.53 +                                           //   was malformed
    1.54 +  { "serverr",         ORTSrverr},         // the response indicates there was a
    1.55 +                                           //   server error
    1.56 +  { "trylater",        ORTTryLater},       // the responder replied with
    1.57 +                                           //   "try again later"
    1.58 +  { "resp-unsigned",   ORTNeedsSig},       // the response needs a signature
    1.59 +  { "unauthorized",    ORTUnauthorized},   // the responder does not know about
    1.60 +                                           //   the cert
    1.61 +  { "bad-signature",   ORTBadSignature},   // the response has a bad signature
    1.62 +  { "longvalidityalmostold", ORTLongValidityAlmostExpired}, // the response is
    1.63 +                                           // still valid, but the generation
    1.64 +                                           // is almost a year old
    1.65 +  { "ancientstillvalid", ORTAncientAlmostExpired}, // The response is still
    1.66 +                                           // valid but the generation is almost
    1.67 +                                           // two years old
    1.68 +};
    1.69 +
    1.70 +
    1.71 +bool
    1.72 +stringToOCSPResponseType(const char* respText,
    1.73 +                         /*out*/ OCSPResponseType* OCSPType)
    1.74 +{
    1.75 +  if (!OCSPType) {
    1.76 +    return false;
    1.77 +  }
    1.78 +  for (uint32_t i = 0; i < mozilla::ArrayLength(kOCSPResponseNameList); i++) {
    1.79 +    if (strcmp(respText, kOCSPResponseNameList[i].mTypeString) == 0) {
    1.80 +      *OCSPType = kOCSPResponseNameList[i].mORT;
    1.81 +      return true;
    1.82 +    }
    1.83 +  }
    1.84 +  return false;
    1.85 +}
    1.86 +
    1.87 +bool
    1.88 +WriteResponse(const char* filename, const SECItem* item)
    1.89 +{
    1.90 +  if (!filename || !item || !item->data) {
    1.91 +    PR_fprintf(PR_STDERR, "invalid parameters to WriteResponse");
    1.92 +    return false;
    1.93 +  }
    1.94 +
    1.95 +  ScopedPRFileDesc outFile(PR_Open(filename,
    1.96 +                                   PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
    1.97 +                                   0644));
    1.98 +  if (!outFile) {
    1.99 +    PrintPRError("cannot open file for writing");
   1.100 +    return false;
   1.101 +  }
   1.102 +  int32_t rv = PR_Write(outFile, item->data, item->len);
   1.103 +  if (rv < 0 || (uint32_t) rv != item->len) {
   1.104 +    PrintPRError("File write failure");
   1.105 +    return false;
   1.106 +  }
   1.107 +
   1.108 +  return true;
   1.109 +}
   1.110 +
   1.111 +
   1.112 +
   1.113 +int
   1.114 +main(int argc, char* argv[])
   1.115 +{
   1.116 +
   1.117 +  if (argc < 6 || (argc - 6) % 4 != 0) {
   1.118 +    PR_fprintf(PR_STDERR, "usage: %s <NSS DB directory> <responsetype> "
   1.119 +                          "<cert_nick> <extranick> <outfilename> [<resptype> "
   1.120 +                          "<cert_nick> <extranick> <outfilename>]* \n",
   1.121 +                          argv[0]);
   1.122 +    exit(EXIT_FAILURE);
   1.123 +  }
   1.124 +  const char* dbdir = argv[1];
   1.125 +
   1.126 +  SECStatus rv;
   1.127 +  rv = NSS_Init(dbdir);
   1.128 +  if (rv != SECSuccess) {
   1.129 +    PrintPRError("Failed to initialize NSS");
   1.130 +    exit(EXIT_FAILURE);
   1.131 +  }
   1.132 +  PLArenaPool* arena = PORT_NewArena(256 * argc);
   1.133 +  if (!arena) {
   1.134 +    PrintPRError("PORT_NewArena failed");
   1.135 +    exit(EXIT_FAILURE);
   1.136 +  }
   1.137 +
   1.138 +  for (int i = 2; i + 3 < argc; i += 4) {
   1.139 +    const char* ocspTypeText  = argv[i];
   1.140 +    const char* certNick      = argv[i + 1];
   1.141 +    const char* extraCertname = argv[i + 2];
   1.142 +    const char* filename      = argv[i + 3];
   1.143 +
   1.144 +    OCSPResponseType ORT;
   1.145 +    if (!stringToOCSPResponseType(ocspTypeText, &ORT)) {
   1.146 +      PR_fprintf(PR_STDERR, "Cannot generate OCSP response of type %s\n",
   1.147 +                 ocspTypeText);
   1.148 +      exit(EXIT_FAILURE);
   1.149 +    }
   1.150 +
   1.151 +    ScopedCERTCertificate cert;
   1.152 +    cert = PK11_FindCertFromNickname(certNick, nullptr);
   1.153 +    if (!cert) {
   1.154 +      PR_fprintf(PR_STDERR, "Failed to find certificate with nick '%s'\n",
   1.155 +                 certNick);
   1.156 +      exit(EXIT_FAILURE);
   1.157 +    }
   1.158 +
   1.159 +    SECItemArray* response = GetOCSPResponseForType(ORT, cert, arena,
   1.160 +                                                    extraCertname);
   1.161 +    if (!response) {
   1.162 +      PR_fprintf(PR_STDERR, "Failed to generate OCSP response of type %s "
   1.163 +                            "for %s\n", ocspTypeText, certNick);
   1.164 +      exit(EXIT_FAILURE);
   1.165 +    }
   1.166 +
   1.167 +    if (!WriteResponse(filename, &response->items[0])) {
   1.168 +      PR_fprintf(PR_STDERR, "Failed to write file %s\n", filename);
   1.169 +      exit(EXIT_FAILURE);
   1.170 +    }
   1.171 +  }
   1.172 +  return 0;
   1.173 +}

mercurial