1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include <assert.h>
6 #include <stdint.h>
7 #include <memory>
8
9 #include "blapi.h"
10 #include "prinit.h"
11 #include "ssl.h"
12
13 #include "shared.h"
14 #include "tls_client_config.h"
15 #include "tls_common.h"
16 #include "tls_mutators.h"
17 #include "tls_socket.h"
18
19 #ifdef IS_DTLS
set_is_dtls()20 __attribute__((constructor)) static void set_is_dtls() {
21 TlsMutators::SetIsDTLS();
22 }
23 #endif
24
ImportFD(PRFileDesc * model,PRFileDesc * fd)25 PRFileDesc* ImportFD(PRFileDesc* model, PRFileDesc* fd) {
26 #ifdef IS_DTLS
27 return DTLS_ImportFD(model, fd);
28 #else
29 return SSL_ImportFD(model, fd);
30 #endif
31 }
32
AuthCertificateHook(void * arg,PRFileDesc * fd,PRBool checksig,PRBool isServer)33 static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checksig,
34 PRBool isServer) {
35 assert(!isServer);
36 auto config = reinterpret_cast<ClientConfig*>(arg);
37 return config->FailCertificateAuthentication() ? SECFailure : SECSuccess;
38 }
39
SetSocketOptions(PRFileDesc * fd,std::unique_ptr<ClientConfig> & config)40 static void SetSocketOptions(PRFileDesc* fd,
41 std::unique_ptr<ClientConfig>& config) {
42 SECStatus rv = SSL_OptionSet(fd, SSL_NO_CACHE, config->EnableCache());
43 assert(rv == SECSuccess);
44
45 rv = SSL_OptionSet(fd, SSL_ENABLE_EXTENDED_MASTER_SECRET,
46 config->EnableExtendedMasterSecret());
47 assert(rv == SECSuccess);
48
49 rv = SSL_OptionSet(fd, SSL_REQUIRE_DH_NAMED_GROUPS,
50 config->RequireDhNamedGroups());
51 assert(rv == SECSuccess);
52
53 rv = SSL_OptionSet(fd, SSL_ENABLE_FALSE_START, config->EnableFalseStart());
54 assert(rv == SECSuccess);
55
56 rv = SSL_OptionSet(fd, SSL_ENABLE_DEFLATE, config->EnableDeflate());
57 assert(rv == SECSuccess);
58
59 rv = SSL_OptionSet(fd, SSL_CBC_RANDOM_IV, config->EnableCbcRandomIv());
60 assert(rv == SECSuccess);
61
62 rv = SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION,
63 config->RequireSafeNegotiation());
64 assert(rv == SECSuccess);
65
66 #ifndef IS_DTLS
67 rv =
68 SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED);
69 assert(rv == SECSuccess);
70 #endif
71 }
72
73 // This is only called when we set SSL_ENABLE_FALSE_START=1,
74 // so we can always just set *canFalseStart=true.
CanFalseStartCallback(PRFileDesc * fd,void * arg,PRBool * canFalseStart)75 static SECStatus CanFalseStartCallback(PRFileDesc* fd, void* arg,
76 PRBool* canFalseStart) {
77 *canFalseStart = true;
78 return SECSuccess;
79 }
80
SetupCallbacks(PRFileDesc * fd,ClientConfig * config)81 static void SetupCallbacks(PRFileDesc* fd, ClientConfig* config) {
82 SECStatus rv = SSL_AuthCertificateHook(fd, AuthCertificateHook, config);
83 assert(rv == SECSuccess);
84
85 rv = SSL_SetCanFalseStartCallback(fd, CanFalseStartCallback, nullptr);
86 assert(rv == SECSuccess);
87 }
88
LLVMFuzzerTestOneInput(const uint8_t * data,size_t len)89 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) {
90 static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
91 assert(db != nullptr);
92
93 EnableAllProtocolVersions();
94 std::unique_ptr<ClientConfig> config(new ClientConfig(data, len));
95
96 // Clear the cache. We never want to resume as we couldn't reproduce that.
97 SSL_ClearSessionCache();
98
99 // Reset the RNG state.
100 assert(RNG_RandomUpdate(NULL, 0) == SECSuccess);
101
102 // Create and import dummy socket.
103 std::unique_ptr<DummyPrSocket> socket(new DummyPrSocket(data, len));
104 static PRDescIdentity id = PR_GetUniqueIdentity("fuzz-client");
105 ScopedPRFileDesc fd(DummyIOLayerMethods::CreateFD(id, socket.get()));
106 PRFileDesc* ssl_fd = ImportFD(nullptr, fd.get());
107 assert(ssl_fd == fd.get());
108
109 // Probably not too important for clients.
110 SSL_SetURL(ssl_fd, "server");
111
112 SetSocketOptions(ssl_fd, config);
113 EnableAllCipherSuites(ssl_fd);
114 SetupCallbacks(ssl_fd, config.get());
115 DoHandshake(ssl_fd, false);
116
117 return 0;
118 }
119
LLVMFuzzerCustomMutator(uint8_t * data,size_t size,size_t max_size,unsigned int seed)120 extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
121 size_t max_size, unsigned int seed) {
122 using namespace TlsMutators;
123 return CustomMutate({DropRecord, ShuffleRecords, DuplicateRecord,
124 TruncateRecord, FragmentRecord},
125 data, size, max_size, seed);
126 }
127
LLVMFuzzerCustomCrossOver(const uint8_t * data1,size_t size1,const uint8_t * data2,size_t size2,uint8_t * out,size_t max_out_size,unsigned int seed)128 extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t* data1, size_t size1,
129 const uint8_t* data2, size_t size2,
130 uint8_t* out, size_t max_out_size,
131 unsigned int seed) {
132 return TlsMutators::CrossOver(data1, size1, data2, size2, out, max_out_size,
133 seed);
134 }
135