Commit f7bc3cb6 authored by Tim Taubert's avatar Tim Taubert

Bug 1330557 - Add basic TLS client fuzzer r=mt,franziskus

Differential Revision: https://nss-review.dev.mozaws.net/D145

--HG--
rename : gtests/common/scoped_ptrs.h => cpputil/scoped_ptrs.h
parent db98f6aa
......@@ -326,16 +326,22 @@ async function scheduleFuzzing() {
// Schedule fuzzing runs.
let run_base = merge(base, {parent: task_build, kind: "test"});
let mpi_base = merge(run_base, {group: "MPI"});
scheduleFuzzingRun(run_base, "CertDN", "certDN", 4096);
scheduleFuzzingRun(run_base, "Hash", "hash", 4096);
scheduleFuzzingRun(run_base, "QuickDER", "quickder", 10000);
for (let mpi_name of ["add", "addmod", "div", "expmod", "mod", "mulmod",
"sqr", "sqrmod", "sub", "submod"]) {
scheduleFuzzingRun(mpi_base, `MPI (${mpi_name})`, `mpi-${mpi_name}`,
4096, mpi_name);
// Schedule MPI fuzzing runs.
let mpi_base = merge(run_base, {group: "MPI"});
let mpi_names = ["add", "addmod", "div", "expmod", "mod", "mulmod", "sqr",
"sqrmod", "sub", "submod"];
for (let name of mpi_names) {
scheduleFuzzingRun(mpi_base, `MPI (${name})`, `mpi-${name}`, 4096, name);
}
// Schedule TLS fuzzing runs.
let tls_base = merge(run_base, {group: "TLS"});
scheduleFuzzingRun(tls_base, "TLS Client", "tls-client", 20000, "client");
return queue.submit();
}
......
......@@ -42,6 +42,7 @@ else
"$top/gtests/ssl_gtest" \
"$top/gtests/util_gtest" \
"$top/nss-tool" \
"$top/cpputil" \
)
fi
......
---
Language: Cpp
BasedOnStyle: Google
...
######################################
## PLEASE READ BEFORE USING CPPUTIL ##
######################################
This is a static library supposed to be mainly used by NSS internally. We use
it for testing, fuzzing, and a few new tools written in C++ that we're
experimenting with.
You might find it handy to use for your own projects but please be aware that
we will make no promises your application won't break in the future. We will
provide no support if you decide to link against it.
# 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/.
{
'includes': [
'../coreconf/config.gypi',
],
'targets': [
{
'target_name': 'cpputil',
'type': 'static_library',
'sources': [
'dummy_io.cc',
'dummy_io_fwd.cc',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
],
'direct_dependent_settings': {
'include_dirs': [
'<(DEPTH)/cpputil',
],
},
},
],
}
/* 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/. */
#include <assert.h>
#include <iostream>
#include "prerror.h"
#include "prio.h"
#include "dummy_io.h"
#define UNIMPLEMENTED() \
std::cerr << "Unimplemented: " << __FUNCTION__ << std::endl; \
assert(false);
extern const struct PRIOMethods DummyMethodsForward;
ScopedPRFileDesc DummyIOLayerMethods::CreateFD(PRDescIdentity id,
DummyIOLayerMethods *methods) {
ScopedPRFileDesc fd(PR_CreateIOLayerStub(id, &DummyMethodsForward));
fd->secret = reinterpret_cast<PRFilePrivate *>(methods);
return fd;
}
PRStatus DummyIOLayerMethods::Close(PRFileDesc *f) {
f->secret = nullptr;
f->dtor(f);
return PR_SUCCESS;
}
int32_t DummyIOLayerMethods::Read(PRFileDesc *f, void *buf, int32_t length) {
UNIMPLEMENTED();
return -1;
}
int32_t DummyIOLayerMethods::Write(PRFileDesc *f, const void *buf,
int32_t length) {
UNIMPLEMENTED();
return -1;
}
int32_t DummyIOLayerMethods::Available(PRFileDesc *f) {
UNIMPLEMENTED();
return -1;
}
int64_t DummyIOLayerMethods::Available64(PRFileDesc *f) {
UNIMPLEMENTED();
return -1;
}
PRStatus DummyIOLayerMethods::Sync(PRFileDesc *f) {
UNIMPLEMENTED();
return PR_FAILURE;
}
int32_t DummyIOLayerMethods::Seek(PRFileDesc *f, int32_t offset,
PRSeekWhence how) {
UNIMPLEMENTED();
return -1;
}
int64_t DummyIOLayerMethods::Seek64(PRFileDesc *f, int64_t offset,
PRSeekWhence how) {
UNIMPLEMENTED();
return -1;
}
PRStatus DummyIOLayerMethods::FileInfo(PRFileDesc *f, PRFileInfo *info) {
UNIMPLEMENTED();
return PR_FAILURE;
}
PRStatus DummyIOLayerMethods::FileInfo64(PRFileDesc *f, PRFileInfo64 *info) {
UNIMPLEMENTED();
return PR_FAILURE;
}
int32_t DummyIOLayerMethods::Writev(PRFileDesc *f, const PRIOVec *iov,
int32_t iov_size, PRIntervalTime to) {
UNIMPLEMENTED();
return -1;
}
PRStatus DummyIOLayerMethods::Connect(PRFileDesc *f, const PRNetAddr *addr,
PRIntervalTime to) {
UNIMPLEMENTED();
return PR_FAILURE;
}
PRFileDesc *DummyIOLayerMethods::Accept(PRFileDesc *sd, PRNetAddr *addr,
PRIntervalTime to) {
UNIMPLEMENTED();
return nullptr;
}
PRStatus DummyIOLayerMethods::Bind(PRFileDesc *f, const PRNetAddr *addr) {
UNIMPLEMENTED();
return PR_FAILURE;
}
PRStatus DummyIOLayerMethods::Listen(PRFileDesc *f, int32_t depth) {
UNIMPLEMENTED();
return PR_FAILURE;
}
PRStatus DummyIOLayerMethods::Shutdown(PRFileDesc *f, int32_t how) {
return PR_SUCCESS;
}
int32_t DummyIOLayerMethods::Recv(PRFileDesc *f, void *buf, int32_t buflen,
int32_t flags, PRIntervalTime to) {
UNIMPLEMENTED();
return -1;
}
// Note: this is always nonblocking and assumes a zero timeout.
int32_t DummyIOLayerMethods::Send(PRFileDesc *f, const void *buf,
int32_t amount, int32_t flags,
PRIntervalTime to) {
return Write(f, buf, amount);
}
int32_t DummyIOLayerMethods::Recvfrom(PRFileDesc *f, void *buf, int32_t amount,
int32_t flags, PRNetAddr *addr,
PRIntervalTime to) {
UNIMPLEMENTED();
return -1;
}
int32_t DummyIOLayerMethods::Sendto(PRFileDesc *f, const void *buf,
int32_t amount, int32_t flags,
const PRNetAddr *addr, PRIntervalTime to) {
UNIMPLEMENTED();
return -1;
}
int16_t DummyIOLayerMethods::Poll(PRFileDesc *f, int16_t in_flags,
int16_t *out_flags) {
UNIMPLEMENTED();
return -1;
}
int32_t DummyIOLayerMethods::AcceptRead(PRFileDesc *sd, PRFileDesc **nd,
PRNetAddr **raddr, void *buf,
int32_t amount, PRIntervalTime t) {
UNIMPLEMENTED();
return -1;
}
int32_t DummyIOLayerMethods::TransmitFile(PRFileDesc *sd, PRFileDesc *f,
const void *headers, int32_t hlen,
PRTransmitFileFlags flags,
PRIntervalTime t) {
UNIMPLEMENTED();
return -1;
}
// TODO: Modify to return unique names for each channel
// somehow, as opposed to always the same static address. The current
// implementation messes up the session cache, which is why it's off
// elsewhere
PRStatus DummyIOLayerMethods::Getpeername(PRFileDesc *f, PRNetAddr *addr) {
addr->inet.family = PR_AF_INET;
addr->inet.port = 0;
addr->inet.ip = 0;
return PR_SUCCESS;
}
PRStatus DummyIOLayerMethods::Getsockname(PRFileDesc *f, PRNetAddr *addr) {
UNIMPLEMENTED();
return PR_FAILURE;
}
PRStatus DummyIOLayerMethods::Getsockoption(PRFileDesc *f,
PRSocketOptionData *opt) {
switch (opt->option) {
case PR_SockOpt_Nonblocking:
opt->value.non_blocking = PR_TRUE;
return PR_SUCCESS;
default:
UNIMPLEMENTED();
break;
}
return PR_FAILURE;
}
PRStatus DummyIOLayerMethods::Setsockoption(PRFileDesc *f,
const PRSocketOptionData *opt) {
switch (opt->option) {
case PR_SockOpt_Nonblocking:
return PR_SUCCESS;
case PR_SockOpt_NoDelay:
return PR_SUCCESS;
default:
UNIMPLEMENTED();
break;
}
return PR_FAILURE;
}
int32_t DummyIOLayerMethods::Sendfile(PRFileDesc *out, PRSendFileData *in,
PRTransmitFileFlags flags,
PRIntervalTime to) {
UNIMPLEMENTED();
return -1;
}
PRStatus DummyIOLayerMethods::ConnectContinue(PRFileDesc *f, int16_t flags) {
UNIMPLEMENTED();
return PR_FAILURE;
}
int32_t DummyIOLayerMethods::Reserved(PRFileDesc *f) {
UNIMPLEMENTED();
return -1;
}
/* 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/. */
#ifndef dummy_io_h__
#define dummy_io_h__
#include "prerror.h"
#include "prio.h"
#include "scoped_ptrs.h"
class DummyIOLayerMethods {
public:
static ScopedPRFileDesc CreateFD(PRDescIdentity id,
DummyIOLayerMethods *methods);
virtual PRStatus Close(PRFileDesc *f);
virtual int32_t Read(PRFileDesc *f, void *buf, int32_t length);
virtual int32_t Write(PRFileDesc *f, const void *buf, int32_t length);
virtual int32_t Available(PRFileDesc *f);
virtual int64_t Available64(PRFileDesc *f);
virtual PRStatus Sync(PRFileDesc *f);
virtual int32_t Seek(PRFileDesc *f, int32_t offset, PRSeekWhence how);
virtual int64_t Seek64(PRFileDesc *f, int64_t offset, PRSeekWhence how);
virtual PRStatus FileInfo(PRFileDesc *f, PRFileInfo *info);
virtual PRStatus FileInfo64(PRFileDesc *f, PRFileInfo64 *info);
virtual int32_t Writev(PRFileDesc *f, const PRIOVec *iov, int32_t iov_size,
PRIntervalTime to);
virtual PRStatus Connect(PRFileDesc *f, const PRNetAddr *addr,
PRIntervalTime to);
virtual PRFileDesc *Accept(PRFileDesc *sd, PRNetAddr *addr,
PRIntervalTime to);
virtual PRStatus Bind(PRFileDesc *f, const PRNetAddr *addr);
virtual PRStatus Listen(PRFileDesc *f, int32_t depth);
virtual PRStatus Shutdown(PRFileDesc *f, int32_t how);
virtual int32_t Recv(PRFileDesc *f, void *buf, int32_t buflen, int32_t flags,
PRIntervalTime to);
virtual int32_t Send(PRFileDesc *f, const void *buf, int32_t amount,
int32_t flags, PRIntervalTime to);
virtual int32_t Recvfrom(PRFileDesc *f, void *buf, int32_t amount,
int32_t flags, PRNetAddr *addr, PRIntervalTime to);
virtual int32_t Sendto(PRFileDesc *f, const void *buf, int32_t amount,
int32_t flags, const PRNetAddr *addr,
PRIntervalTime to);
virtual int16_t Poll(PRFileDesc *f, int16_t in_flags, int16_t *out_flags);
virtual int32_t AcceptRead(PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
void *buf, int32_t amount, PRIntervalTime t);
virtual int32_t TransmitFile(PRFileDesc *sd, PRFileDesc *f,
const void *headers, int32_t hlen,
PRTransmitFileFlags flags, PRIntervalTime t);
virtual PRStatus Getpeername(PRFileDesc *f, PRNetAddr *addr);
virtual PRStatus Getsockname(PRFileDesc *f, PRNetAddr *addr);
virtual PRStatus Getsockoption(PRFileDesc *f, PRSocketOptionData *opt);
virtual PRStatus Setsockoption(PRFileDesc *f, const PRSocketOptionData *opt);
virtual int32_t Sendfile(PRFileDesc *out, PRSendFileData *in,
PRTransmitFileFlags flags, PRIntervalTime to);
virtual PRStatus ConnectContinue(PRFileDesc *f, int16_t flags);
virtual int32_t Reserved(PRFileDesc *f);
};
#endif // dummy_io_h__
/* 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/. */
#include "prio.h"
#include "dummy_io.h"
static DummyIOLayerMethods *ToMethods(PRFileDesc *f) {
return reinterpret_cast<DummyIOLayerMethods *>(f->secret);
}
static PRStatus DummyClose(PRFileDesc *f) { return ToMethods(f)->Close(f); }
static int32_t DummyRead(PRFileDesc *f, void *buf, int32_t length) {
return ToMethods(f)->Read(f, buf, length);
}
static int32_t DummyWrite(PRFileDesc *f, const void *buf, int32_t length) {
return ToMethods(f)->Write(f, buf, length);
}
static int32_t DummyAvailable(PRFileDesc *f) {
return ToMethods(f)->Available(f);
}
static int64_t DummyAvailable64(PRFileDesc *f) {
return ToMethods(f)->Available64(f);
}
static PRStatus DummySync(PRFileDesc *f) { return ToMethods(f)->Sync(f); }
static int32_t DummySeek(PRFileDesc *f, int32_t offset, PRSeekWhence how) {
return ToMethods(f)->Seek(f, offset, how);
}
static int64_t DummySeek64(PRFileDesc *f, int64_t offset, PRSeekWhence how) {
return ToMethods(f)->Seek64(f, offset, how);
}
static PRStatus DummyFileInfo(PRFileDesc *f, PRFileInfo *info) {
return ToMethods(f)->FileInfo(f, info);
}
static PRStatus DummyFileInfo64(PRFileDesc *f, PRFileInfo64 *info) {
return ToMethods(f)->FileInfo64(f, info);
}
static int32_t DummyWritev(PRFileDesc *f, const PRIOVec *iov, int32_t iov_size,
PRIntervalTime to) {
return ToMethods(f)->Writev(f, iov, iov_size, to);
}
static PRStatus DummyConnect(PRFileDesc *f, const PRNetAddr *addr,
PRIntervalTime to) {
return ToMethods(f)->Connect(f, addr, to);
}
static PRFileDesc *DummyAccept(PRFileDesc *f, PRNetAddr *addr,
PRIntervalTime to) {
return ToMethods(f)->Accept(f, addr, to);
}
static PRStatus DummyBind(PRFileDesc *f, const PRNetAddr *addr) {
return ToMethods(f)->Bind(f, addr);
}
static PRStatus DummyListen(PRFileDesc *f, int32_t depth) {
return ToMethods(f)->Listen(f, depth);
}
static PRStatus DummyShutdown(PRFileDesc *f, int32_t how) {
return ToMethods(f)->Shutdown(f, how);
}
static int32_t DummyRecv(PRFileDesc *f, void *buf, int32_t buflen,
int32_t flags, PRIntervalTime to) {
return ToMethods(f)->Recv(f, buf, buflen, flags, to);
}
static int32_t DummySend(PRFileDesc *f, const void *buf, int32_t amount,
int32_t flags, PRIntervalTime to) {
return ToMethods(f)->Send(f, buf, amount, flags, to);
}
static int32_t DummyRecvfrom(PRFileDesc *f, void *buf, int32_t amount,
int32_t flags, PRNetAddr *addr,
PRIntervalTime to) {
return ToMethods(f)->Recvfrom(f, buf, amount, flags, addr, to);
}
static int32_t DummySendto(PRFileDesc *f, const void *buf, int32_t amount,
int32_t flags, const PRNetAddr *addr,
PRIntervalTime to) {
return ToMethods(f)->Sendto(f, buf, amount, flags, addr, to);
}
static int16_t DummyPoll(PRFileDesc *f, int16_t in_flags, int16_t *out_flags) {
return ToMethods(f)->Poll(f, in_flags, out_flags);
}
static int32_t DummyAcceptRead(PRFileDesc *f, PRFileDesc **nd,
PRNetAddr **raddr, void *buf, int32_t amount,
PRIntervalTime t) {
return ToMethods(f)->AcceptRead(f, nd, raddr, buf, amount, t);
}
static int32_t DummyTransmitFile(PRFileDesc *sd, PRFileDesc *f,
const void *headers, int32_t hlen,
PRTransmitFileFlags flags, PRIntervalTime t) {
return ToMethods(f)->TransmitFile(sd, f, headers, hlen, flags, t);
}
static PRStatus DummyGetpeername(PRFileDesc *f, PRNetAddr *addr) {
return ToMethods(f)->Getpeername(f, addr);
}
static PRStatus DummyGetsockname(PRFileDesc *f, PRNetAddr *addr) {
return ToMethods(f)->Getsockname(f, addr);
}
static PRStatus DummyGetsockoption(PRFileDesc *f, PRSocketOptionData *opt) {
return ToMethods(f)->Getsockoption(f, opt);
}
static PRStatus DummySetsockoption(PRFileDesc *f,
const PRSocketOptionData *opt) {
return ToMethods(f)->Setsockoption(f, opt);
}
static int32_t DummySendfile(PRFileDesc *f, PRSendFileData *in,
PRTransmitFileFlags flags, PRIntervalTime to) {
return ToMethods(f)->Sendfile(f, in, flags, to);
}
static PRStatus DummyConnectContinue(PRFileDesc *f, int16_t flags) {
return ToMethods(f)->ConnectContinue(f, flags);
}
static int32_t DummyReserved(PRFileDesc *f) {
return ToMethods(f)->Reserved(f);
}
extern const struct PRIOMethods DummyMethodsForward = {
PR_DESC_LAYERED, DummyClose,
DummyRead, DummyWrite,
DummyAvailable, DummyAvailable64,
DummySync, DummySeek,
DummySeek64, DummyFileInfo,
DummyFileInfo64, DummyWritev,
DummyConnect, DummyAccept,
DummyBind, DummyListen,
DummyShutdown, DummyRecv,
DummySend, DummyRecvfrom,
DummySendto, DummyPoll,
DummyAcceptRead, DummyTransmitFile,
DummyGetsockname, DummyGetpeername,
DummyReserved, DummyReserved,
DummyGetsockoption, DummySetsockoption,
DummySendfile, DummyConnectContinue,
DummyReserved, DummyReserved,
DummyReserved, DummyReserved};
......@@ -12,8 +12,6 @@
#include "keyhi.h"
#include "pk11pub.h"
namespace nss_test {
struct ScopedDelete {
void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
void operator()(CERTCertificateList* list) {
......@@ -58,6 +56,4 @@ SCOPED(SECKEYPrivateKey);
#undef SCOPED
} // namespace nss_test
#endif
#endif // scoped_ptrs_h__
......@@ -29,6 +29,7 @@
'<(DEPTH)/lib/certdb/certdb.gyp:certdb',
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
'<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
'<(DEPTH)/lib/base/base.gyp:nssb',
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
......@@ -243,6 +244,22 @@
'nssfuzz-mpi-base',
],
},
{
'target_name': 'nssfuzz-tls-client',
'type': 'executable',
'sources': [
'tls_client_socket.cc',
'tls_client_target.cc',
],
'dependencies': [
'<(DEPTH)/cpputil/cpputil.gyp:cpputil',
'<(DEPTH)/exports.gyp:nss_exports',
'fuzz_base',
],
'include_dirs': [
'<(DEPTH)/lib/freebl',
],
},
{
'target_name': 'nssfuzz',
'type': 'none',
......@@ -251,6 +268,7 @@
'nssfuzz-hash',
'nssfuzz-pkcs8',
'nssfuzz-quickder',
'nssfuzz-tls-client',
],
'conditions': [
['OS=="linux"', {
......
[libfuzzer]
max_len = 20000
/* 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/. */
#include <assert.h>
#include <string.h>
#include <algorithm>
#include "prerror.h"
#include "prio.h"
#include "tls_client_socket.h"
int32_t DummyPrSocket::Read(PRFileDesc *f, void *data, int32_t len) {
assert(data && len > 0);
int32_t amount = std::min(len, static_cast<int32_t>(len_));
memcpy(data, buf_, amount);
buf_ += amount;
len_ -= amount;
return amount;
}
int32_t DummyPrSocket::Write(PRFileDesc *f, const void *buf, int32_t length) {
return length;
}
int32_t DummyPrSocket::Recv(PRFileDesc *f, void *buf, int32_t buflen,
int32_t flags, PRIntervalTime to) {
assert(flags == 0);
return Read(f, buf, buflen);
}
/* 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/. */
#ifndef tls_client_socket_h__
#define tls_client_socket_h__
#include "dummy_io.h"
class DummyPrSocket : public DummyIOLayerMethods {
public:
DummyPrSocket(const uint8_t *buf, size_t len) : buf_(buf), len_(len) {}
int32_t Read(PRFileDesc *f, void *data, int32_t len) override;
int32_t Write(PRFileDesc *f, const void *buf, int32_t length) override;
int32_t Recv(PRFileDesc *f, void *buf, int32_t buflen, int32_t flags,
PRIntervalTime to) override;
private:
const uint8_t *buf_;
size_t len_;
};
#endif // tls_client_socket_h__
/* 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/. */
#include <assert.h>
#include <stdint.h>
#include <memory>
#include "blapi.h"
#include "prinit.h"
#include "ssl.h"
#include "shared.h"
#include "tls_client_socket.h"
static PRStatus EnableAllProtocolVersions() {
SSLVersionRange supported;
SECStatus rv = SSL_VersionRangeGetSupported(ssl_variant_stream, &supported);
assert(rv == SECSuccess);
rv = SSL_VersionRangeSetDefault(ssl_variant_stream, &supported);
assert(rv == SECSuccess);
return PR_SUCCESS;
}
static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checksig,
PRBool isServer) {
return SECSuccess;
}
static void SetSocketOptions(PRFileDesc* fd) {
// Disable session cache for now.
SECStatus rv = SSL_OptionSet(fd, SSL_NO_CACHE, true);
assert(rv == SECSuccess);
rv = SSL_OptionSet(fd, SSL_ENABLE_EXTENDED_MASTER_SECRET, true);
assert(rv == SECSuccess);
rv = SSL_OptionSet(fd, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, true);
assert(rv == SECSuccess);
rv = SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true);
assert(rv == SECSuccess);
rv = SSL_OptionSet(fd, SSL_ENABLE_ALPN, true);
assert(rv == SECSuccess);
rv =
SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED);
assert(rv == SECSuccess);
}
static void EnableAllCipherSuites(PRFileDesc* fd) {
for (uint16_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
SECStatus rv = SSL_CipherPrefSet(fd, SSL_ImplementedCiphers[i], true);
assert(rv == SECSuccess);
}
}
static void SetupAuthCertificateHook(PRFileDesc* fd) {
SECStatus rv = SSL_AuthCertificateHook(fd, AuthCertificateHook, nullptr);
assert(rv == SECSuccess);
}
static void DoHandshake(PRFileDesc* fd) {
SECStatus rv = SSL_ResetHandshake(fd, false /* asServer */);
assert(rv == SECSuccess);
do {
rv = SSL_ForceHandshake(fd);
} while (rv != SECSuccess && PR_GetError() == PR_WOULD_BLOCK_ERROR);