mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-06-05 16:09:02 +00:00
117 lines
3.6 KiB
C++
117 lines
3.6 KiB
C++
/* -*- 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 is a standalone server for testing client cert authentication.
|
|
// The client is expected to connect, initiate an SSL handshake (with SNI
|
|
// to indicate which "server" to connect to), and verify the certificate.
|
|
// If all is good, the client then sends one encrypted byte and receives that
|
|
// same byte back.
|
|
// This server also has the ability to "call back" another process waiting on
|
|
// it. That is, when the server is all set up and ready to receive connections,
|
|
// it will connect to a specified port and issue a simple HTTP request.
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "hasht.h"
|
|
#include "ScopedNSSTypes.h"
|
|
#include "ssl.h"
|
|
#include "TLSServer.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::test;
|
|
|
|
struct ClientAuthHost
|
|
{
|
|
const char *mHostName;
|
|
bool mRequestClientAuth;
|
|
bool mRequireClientAuth;
|
|
};
|
|
|
|
// Hostname, cert nickname pairs.
|
|
static const ClientAuthHost sClientAuthHosts[] =
|
|
{
|
|
{ "noclientauth.example.com", false, false },
|
|
{ "requestclientauth.example.com", true, false },
|
|
{ "requireclientauth.example.com", true, true },
|
|
{ nullptr, false, false }
|
|
};
|
|
|
|
static const unsigned char sClientCertFingerprint[] =
|
|
{
|
|
0xD2, 0x2F, 0x00, 0x9A, 0x9E, 0xED, 0x79, 0xDC,
|
|
0x8D, 0x17, 0x98, 0x8E, 0xEC, 0x76, 0x05, 0x91,
|
|
0xA5, 0xF6, 0xC9, 0xFA, 0x16, 0x8B, 0xD2, 0x5F,
|
|
0xE1, 0x52, 0x04, 0x7C, 0xF4, 0x76, 0x42, 0x9D
|
|
};
|
|
|
|
SECStatus
|
|
AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig,
|
|
PRBool isServer)
|
|
{
|
|
ScopedCERTCertificate clientCert(SSL_PeerCertificate(fd));
|
|
|
|
unsigned char certFingerprint[SHA256_LENGTH];
|
|
SECStatus rv = PK11_HashBuf(SEC_OID_SHA256, certFingerprint,
|
|
clientCert->derCert.data,
|
|
clientCert->derCert.len);
|
|
if (rv != SECSuccess) {
|
|
return rv;
|
|
}
|
|
|
|
static_assert(sizeof(sClientCertFingerprint) == SHA256_LENGTH,
|
|
"Ensure fingerprint has corrent length");
|
|
bool match = !memcmp(certFingerprint, sClientCertFingerprint,
|
|
sizeof(certFingerprint));
|
|
return match ? SECSuccess : SECFailure;
|
|
}
|
|
|
|
int32_t
|
|
DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
|
|
uint32_t aSrvNameArrSize, void* aArg)
|
|
{
|
|
const ClientAuthHost *host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize,
|
|
sClientAuthHosts);
|
|
if (!host) {
|
|
return SSL_SNI_SEND_ALERT;
|
|
}
|
|
|
|
if (gDebugLevel >= DEBUG_VERBOSE) {
|
|
fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName);
|
|
}
|
|
|
|
SECStatus srv = ConfigSecureServerWithNamedCert(aFd, DEFAULT_CERT_NICKNAME,
|
|
nullptr, nullptr);
|
|
if (srv != SECSuccess) {
|
|
return SSL_SNI_SEND_ALERT;
|
|
}
|
|
|
|
SSL_OptionSet(aFd, SSL_REQUEST_CERTIFICATE, host->mRequestClientAuth);
|
|
if (host->mRequireClientAuth) {
|
|
SSL_OptionSet(aFd, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS);
|
|
} else {
|
|
SSL_OptionSet(aFd, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
|
|
}
|
|
|
|
// Override default client auth hook to just check fingerprint
|
|
srv = SSL_AuthCertificateHook(aFd, AuthCertificateHook, nullptr);
|
|
if (srv != SECSuccess) {
|
|
return SSL_SNI_SEND_ALERT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
if (argc != 2) {
|
|
fprintf(stderr, "usage: %s <NSS DB directory>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
return StartServer(argv[1], DoSNISocketConfig, nullptr);
|
|
}
|