Commit 77a6933e authored by Camilo Viecco's avatar Camilo Viecco
Browse files

Bug 938805 - Create standalone oscpResponseGenerator for testing. r=keeler

parent cfec5f44
Loading
Loading
Loading
Loading
+54 −13
Original line number Diff line number Diff line
@@ -242,6 +242,26 @@ function add_connection_test(aHost, aExpectedResult,
  });
}

function _getBinaryUtil(binaryUtilName) {
  let directoryService = Cc["@mozilla.org/file/directory_service;1"]
                           .getService(Ci.nsIProperties);

  let utilBin = directoryService.get("CurProcD", Ci.nsILocalFile);
  utilBin.append(binaryUtilName + (gIsWindows ? ".exe" : ""));
  // If we're testing locally, the above works. If not, the server executable
  // is in another location.
  if (!utilBin.exists()) {
    utilBin = directoryService.get("CurWorkD", Ci.nsILocalFile);
    while (utilBin.path.indexOf("xpcshell") != -1) {
      utilBin = utilBin.parent;
    }
    utilBin.append("bin");
    utilBin.append(binaryUtilName + (gIsWindows ? ".exe" : ""));
  }
  do_check_true(utilBin.exists());
  return utilBin;
}

// Do not call this directly; use add_tls_server_setup
function _setupTLSServerTest(serverBinName)
{
@@ -275,19 +295,7 @@ function _setupTLSServerTest(serverBinName)
      });
  httpServer.start(CALLBACK_PORT);

  let serverBin = directoryService.get("CurProcD", Ci.nsILocalFile);
  serverBin.append(serverBinName + (gIsWindows ? ".exe" : ""));
  // If we're testing locally, the above works. If not, the server executable
  // is in another location.
  if (!serverBin.exists()) {
    serverBin = directoryService.get("CurWorkD", Ci.nsILocalFile);
    while (serverBin.path.indexOf("xpcshell") != -1) {
      serverBin = serverBin.parent;
    }
    serverBin.append("bin");
    serverBin.append(serverBinName + (gIsWindows ? ".exe" : ""));
  }
  do_check_true(serverBin.exists());
  let serverBin = _getBinaryUtil(serverBinName);
  let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
  process.init(serverBin);
  let certDir = directoryService.get("CurWorkD", Ci.nsILocalFile);
@@ -299,3 +307,36 @@ function _setupTLSServerTest(serverBinName)
    process.kill();
  });
}

// Returns an Array of OCSP responses for a given ocspRespArray and a location
// for a nssDB where the certs and public keys are prepopulated.
// ocspRespArray is an array of arrays like:
// [ [typeOfResponse, certnick, extracertnick]...]
function generateOCSPResponses(ocspRespArray, nssDBlocation)
{
  let utilBinName =  "GenerateOCSPResponse";
  let ocspGenBin = _getBinaryUtil(utilBinName);
  let retArray = new Array();

  for (let i = 0; i < ocspRespArray.length; i++) {
    let argArray = new Array();
    let ocspFilepre = do_get_file(i.toString() + ".ocsp", true);
    let filename = ocspFilepre.path;
    argArray.push(nssDBlocation);
    argArray.push(ocspRespArray[i][0]); // ocsRespType;
    argArray.push(ocspRespArray[i][1]); // nick;
    argArray.push(ocspRespArray[i][2]); // extranickname
    argArray.push(filename);
    do_print("arg_array ="+argArray);

    let process = Cc["@mozilla.org/process/util;1"]
                    .createInstance(Ci.nsIProcess);
    process.init(ocspGenBin);
    process.run(true, argArray, 5);
    do_check_eq(0, process.exitValue);
    let ocspFile = do_get_file(i.toString() + ".ocsp", false);
    retArray.push(readFile(ocspFile));
    ocspFile.remove(false);
  }
  return retArray;
}
+164 −0
Original line number Diff line number Diff line
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 tw=80 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* This simple program takes a database directory, and one or more tuples like
 * <typeOfResponse> <CertNick> <ExtraCertNick> <outPutFilename>
 * to generate (one or more) ocsp responses.
 */

#include <stdio.h>

#include "mozilla/Util.h"
#include "nspr.h"
#include "nss.h"
#include "plarenas.h"
#include "prerror.h"
#include "ssl.h"
#include "secerr.h"

#include "OCSPCommon.h"
#include "ScopedNSSTypes.h"
#include "TLSServer.h"

using namespace mozilla;
using namespace mozilla::test;

struct OCSPResponseName
{
  const char *mTypeString;
  const OCSPResponseType mORT;
};

const static OCSPResponseName kOCSPResponseNameList[] = {
  { "good",            ORTGood },          // the certificate is good
  { "revoked",         ORTRevoked},        // the certificate has been revoked
  { "unknown",         ORTUnknown},        // the responder doesn't know if the
                                           //   cert is good
  { "goodotherca",     ORTGoodOtherCA},    // the wrong CA has signed the
                                           //   response
  { "expiredresponse", ORTExpired},        // the signature on the response has
                                           //   expired
  { "oldvalidperiod",  ORTExpiredFreshCA}, // fresh signature, but old validity
                                           //   period
  { "empty",           ORTEmpty},          // an empty stapled response

  { "malformed",       ORTMalformed},      // the response from the responder
                                           //   was malformed
  { "serverr",         ORTSrverr},         // the response indicates there was a
                                           //   server error
  { "trylater",        ORTTryLater},       // the responder replied with
                                           //   "try again later"
  { "resp-unsigned",   ORTNeedsSig},       // the response needs a signature
  { "unauthorized",    ORTUnauthorized},   // the responder does not know about
                                           //   the cert
};


bool
stringToOCSPResponseType(const char* respText,
                         /*out*/ OCSPResponseType* OCSPType)
{
  if (!OCSPType) {
    return false;
  }
  for (uint32_t i = 0; i < mozilla::ArrayLength(kOCSPResponseNameList); i++) {
    if (strcmp(respText, kOCSPResponseNameList[i].mTypeString) == 0) {
      *OCSPType = kOCSPResponseNameList[i].mORT;
      return true;
    }
  }
  return false;
}

bool
WriteResponse(const char* filename, const SECItem* item)
{
  if (!filename || !item || !item->data) {
    PR_fprintf(PR_STDERR, "invalid parameters to WriteResponse");
    return false;
  }

  ScopedPRFileDesc outFile(PR_Open(filename,
                                   PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
                                   0644));
  if (!outFile) {
    PrintPRError("cannot open file for writing");
    return false;
  }
  int32_t rv = PR_Write(outFile, item->data, item->len);
  if (rv < 0 || (uint32_t) rv != item->len) {
    PrintPRError("File write failure");
    return false;
  }

  return true;
}



int
main(int argc, char* argv[])
{

  if (argc < 6 || (argc - 6) % 4 != 0) {
    PR_fprintf(PR_STDERR, "usage: %s <NSS DB directory> <responsetype> "
                          "<cert_nick> <extranick> <outfilename> [<resptype> "
                          "<cert_nick> <extranick> <outfilename>]* \n",
                          argv[0]);
    exit(EXIT_FAILURE);
  }
  const char* dbdir = argv[1];

  SECStatus rv;
  rv = NSS_Init(dbdir);
  if (rv != SECSuccess) {
    PrintPRError("Failed to initialize NSS");
    exit(EXIT_FAILURE);
  }
  PLArenaPool* arena = PORT_NewArena(256 * argc);
  if (!arena) {
    PrintPRError("PORT_NewArena failed");
    exit(EXIT_FAILURE);
  }

  for (int i = 2; i + 3 < argc; i += 4) {
    const char* ocspTypeText  = argv[i];
    const char* certNick      = argv[i + 1];
    const char* extraCertname = argv[i + 2];
    const char* filename      = argv[i + 3];

    OCSPResponseType ORT;
    if (!stringToOCSPResponseType(ocspTypeText, &ORT)) {
      PR_fprintf(PR_STDERR, "Cannot generate OCSP response of type %s\n",
                 ocspTypeText);
      exit(EXIT_FAILURE);
    }

    ScopedCERTCertificate cert;
    cert = PK11_FindCertFromNickname(certNick, nullptr);
    if (!cert) {
      PR_fprintf(PR_STDERR, "Failed to find certificate with nick '%s'\n",
                 certNick);
      exit(EXIT_FAILURE);
    }

    SECItemArray* response = GetOCSPResponseForType(ORT, cert, arena,
                                                    extraCertname);
    if (!response) {
      PR_fprintf(PR_STDERR, "Failed to generate OCSP response of type %s "
                            "for %s\n", ocspTypeText, certNick);
      exit(EXIT_FAILURE);
    }

    if (!WriteResponse(filename, &response->items[0])) {
      PR_fprintf(PR_STDERR, "Failed to write file %s\n", filename);
      exit(EXIT_FAILURE);
    }
  }
  return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
FAIL_ON_WARNINGS = True

SIMPLE_PROGRAMS = [
    'GenerateOCSPResponse',
    'OCSPStaplingServer',
]

+1 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ TEST_HARNESS_BINS := \
  certutil$(BIN_SUFFIX) \
  pk12util$(BIN_SUFFIX) \
  OCSPStaplingServer$(BIN_SUFFIX) \
  GenerateOCSPResponse$(BIN_SUFFIX) \
  fix_stack_using_bpsyms.py \
  $(NULL)

+1 −0
Original line number Diff line number Diff line
@@ -558,6 +558,7 @@ NO_PKG_FILES += \
	certutil* \
	pk12util* \
	OCSPStaplingServer* \
	GenerateOCSPResponse* \
	winEmbed.exe \
	chrome/chrome.rdf \
	chrome/app-chrome.manifest \