michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // This is a standalone server that delivers various stapled OCSP responses. michael@0: // The client is expected to connect, initiate an SSL handshake (with SNI michael@0: // to indicate which "server" to connect to), and verify the OCSP response. michael@0: // If all is good, the client then sends one encrypted byte and receives that michael@0: // same byte back. michael@0: // This server also has the ability to "call back" another process waiting on michael@0: // it. That is, when the server is all set up and ready to receive connections, michael@0: // it will connect to a specified port and issue a simple HTTP request. michael@0: michael@0: #include michael@0: michael@0: #include "OCSPCommon.h" michael@0: #include "TLSServer.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::test; michael@0: michael@0: const OCSPHost sOCSPHosts[] = michael@0: { michael@0: { "ocsp-stapling-good.example.com", ORTGood, nullptr }, michael@0: { "ocsp-stapling-revoked.example.com", ORTRevoked, nullptr }, michael@0: { "ocsp-stapling-revoked-old.example.com", ORTRevokedOld, nullptr }, michael@0: { "ocsp-stapling-unknown.example.com", ORTUnknown, nullptr }, michael@0: { "ocsp-stapling-unknown-old.example.com", ORTUnknownOld, nullptr }, michael@0: { "ocsp-stapling-good-other.example.com", ORTGoodOtherCert, "ocspOtherEndEntity" }, michael@0: { "ocsp-stapling-good-other-ca.example.com", ORTGoodOtherCA, "otherCA" }, michael@0: { "ocsp-stapling-expired.example.com", ORTExpired, nullptr }, michael@0: { "ocsp-stapling-expired-fresh-ca.example.com", ORTExpiredFreshCA, nullptr }, michael@0: { "ocsp-stapling-none.example.com", ORTNone, nullptr }, michael@0: { "ocsp-stapling-empty.example.com", ORTEmpty, nullptr }, michael@0: { "ocsp-stapling-malformed.example.com", ORTMalformed, nullptr }, michael@0: { "ocsp-stapling-srverr.example.com", ORTSrverr, nullptr }, michael@0: { "ocsp-stapling-trylater.example.com", ORTTryLater, nullptr }, michael@0: { "ocsp-stapling-needssig.example.com", ORTNeedsSig, nullptr }, michael@0: { "ocsp-stapling-unauthorized.example.com", ORTUnauthorized, nullptr }, michael@0: { "ocsp-stapling-with-intermediate.example.com", ORTGood, "ocspEEWithIntermediate" }, michael@0: { "ocsp-stapling-bad-signature.example.com", ORTBadSignature, nullptr }, michael@0: { "ocsp-stapling-skip-responseBytes.example.com", ORTSkipResponseBytes, nullptr }, michael@0: { "ocsp-stapling-critical-extension.example.com", ORTCriticalExtension, nullptr }, michael@0: { "ocsp-stapling-noncritical-extension.example.com", ORTNoncriticalExtension, nullptr }, michael@0: { "ocsp-stapling-empty-extensions.example.com", ORTEmptyExtensions, nullptr }, michael@0: { "ocsp-stapling-delegated-included.example.com", ORTDelegatedIncluded, "delegatedSigner" }, michael@0: { "ocsp-stapling-delegated-included-last.example.com", ORTDelegatedIncludedLast, "delegatedSigner" }, michael@0: { "ocsp-stapling-delegated-missing.example.com", ORTDelegatedMissing, "delegatedSigner" }, michael@0: { "ocsp-stapling-delegated-missing-multiple.example.com", ORTDelegatedMissingMultiple, "delegatedSigner" }, michael@0: { "ocsp-stapling-delegated-no-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerNoExtKeyUsage" }, michael@0: { "ocsp-stapling-delegated-from-intermediate.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerFromIntermediate" }, michael@0: { "ocsp-stapling-delegated-keyUsage-crlSigning.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerKeyUsageCrlSigning" }, michael@0: { "ocsp-stapling-delegated-wrong-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerWrongExtKeyUsage" }, michael@0: { "ocsp-stapling-ancient-valid.example.com", ORTAncientAlmostExpired, nullptr}, michael@0: { nullptr, ORTNull, nullptr } michael@0: }; michael@0: michael@0: int32_t michael@0: DoSNISocketConfig(PRFileDesc *aFd, const SECItem *aSrvNameArr, michael@0: uint32_t aSrvNameArrSize, void *aArg) michael@0: { michael@0: const OCSPHost *host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize, michael@0: sOCSPHosts); michael@0: if (!host) { michael@0: return SSL_SNI_SEND_ALERT; michael@0: } michael@0: michael@0: if (gDebugLevel >= DEBUG_VERBOSE) { michael@0: fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName); michael@0: } michael@0: michael@0: const char *certNickname; michael@0: if (strcmp(host->mHostName, michael@0: "ocsp-stapling-with-intermediate.example.com") == 0) { michael@0: certNickname = host->mAdditionalCertName; michael@0: } else { michael@0: certNickname = DEFAULT_CERT_NICKNAME; michael@0: } michael@0: michael@0: ScopedCERTCertificate cert; michael@0: SSLKEAType certKEA; michael@0: if (SECSuccess != ConfigSecureServerWithNamedCert(aFd, certNickname, michael@0: &cert, &certKEA)) { michael@0: return SSL_SNI_SEND_ALERT; michael@0: } michael@0: michael@0: // If the OCSP response type is "none", don't staple a response. michael@0: if (host->mORT == ORTNone) { michael@0: return 0; michael@0: } michael@0: michael@0: PLArenaPool *arena = PORT_NewArena(1024); michael@0: if (!arena) { michael@0: PrintPRError("PORT_NewArena failed"); michael@0: return SSL_SNI_SEND_ALERT; michael@0: } michael@0: michael@0: // response is contained by the arena - freeing the arena will free it michael@0: SECItemArray *response = GetOCSPResponseForType(host->mORT, cert, arena, michael@0: host->mAdditionalCertName); michael@0: if (!response) { michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return SSL_SNI_SEND_ALERT; michael@0: } michael@0: michael@0: // SSL_SetStapledOCSPResponses makes a deep copy of response michael@0: SECStatus st = SSL_SetStapledOCSPResponses(aFd, response, certKEA); michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: if (st != SECSuccess) { michael@0: PrintPRError("SSL_SetStapledOCSPResponses failed"); michael@0: return SSL_SNI_SEND_ALERT; michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: int michael@0: main(int argc, char *argv[]) michael@0: { michael@0: if (argc != 2) { michael@0: fprintf(stderr, "usage: %s \n", argv[0]); michael@0: return 1; michael@0: } michael@0: michael@0: return StartServer(argv[1], DoSNISocketConfig, nullptr); michael@0: }