xref: /aosp_15_r20/external/cronet/third_party/boringssl/src/tool/server.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 /* Copyright (c) 2014, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/base.h>
16 
17 #include <memory>
18 
19 #include <openssl/err.h>
20 #include <openssl/hpke.h>
21 #include <openssl/rand.h>
22 #include <openssl/ssl.h>
23 
24 #include "internal.h"
25 #include "transport_common.h"
26 
27 
28 static const struct argument kArguments[] = {
29     {
30         "-accept", kRequiredArgument,
31         "The port of the server to bind on; eg 45102",
32     },
33     {
34         "-cipher", kOptionalArgument,
35         "An OpenSSL-style cipher suite string that configures the offered "
36         "ciphers",
37     },
38     {
39         "-curves", kOptionalArgument,
40         "An OpenSSL-style ECDH curves list that configures the offered curves",
41     },
42     {
43         "-max-version", kOptionalArgument,
44         "The maximum acceptable protocol version",
45     },
46     {
47         "-min-version", kOptionalArgument,
48         "The minimum acceptable protocol version",
49     },
50     {
51         "-key", kOptionalArgument,
52         "PEM-encoded file containing the private key. A self-signed "
53         "certificate is generated at runtime if this argument is not provided.",
54     },
55     {
56         "-cert", kOptionalArgument,
57         "PEM-encoded file containing the leaf certificate and optional "
58         "certificate chain. This is taken from the -key argument if this "
59         "argument is not provided.",
60     },
61     {
62         "-ocsp-response", kOptionalArgument, "OCSP response file to send",
63     },
64     {
65         "-ech-key",
66         kOptionalArgument,
67         "File containing the private key corresponding to the ECHConfig.",
68     },
69     {
70         "-ech-config",
71         kOptionalArgument,
72         "File containing one ECHConfig.",
73     },
74     {
75         "-loop", kBooleanArgument,
76         "The server will continue accepting new sequential connections.",
77     },
78     {
79         "-early-data", kBooleanArgument, "Allow early data",
80     },
81     {
82         "-www", kBooleanArgument,
83         "The server will print connection information in response to a "
84         "HTTP GET request.",
85     },
86     {
87         "-debug", kBooleanArgument,
88         "Print debug information about the handshake",
89     },
90     {
91         "-require-any-client-cert", kBooleanArgument,
92         "The server will require a client certificate.",
93     },
94     {
95         "-jdk11-workaround", kBooleanArgument,
96         "Enable the JDK 11 workaround",
97     },
98     {
99         "", kOptionalArgument, "",
100     },
101 };
102 
LoadOCSPResponse(SSL_CTX * ctx,const char * filename)103 static bool LoadOCSPResponse(SSL_CTX *ctx, const char *filename) {
104   ScopedFILE f(fopen(filename, "rb"));
105   std::vector<uint8_t> data;
106   if (f == nullptr ||
107       !ReadAll(&data, f.get())) {
108     fprintf(stderr, "Error reading %s.\n", filename);
109     return false;
110   }
111 
112   if (!SSL_CTX_set_ocsp_response(ctx, data.data(), data.size())) {
113     return false;
114   }
115 
116   return true;
117 }
118 
MakeKeyPairForSelfSignedCert()119 static bssl::UniquePtr<EVP_PKEY> MakeKeyPairForSelfSignedCert() {
120   bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
121   if (!ec_key || !EC_KEY_generate_key(ec_key.get())) {
122     fprintf(stderr, "Failed to generate key pair.\n");
123     return nullptr;
124   }
125   bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new());
126   if (!evp_pkey || !EVP_PKEY_assign_EC_KEY(evp_pkey.get(), ec_key.release())) {
127     fprintf(stderr, "Failed to assign key pair.\n");
128     return nullptr;
129   }
130   return evp_pkey;
131 }
132 
MakeSelfSignedCert(EVP_PKEY * evp_pkey,const int valid_days)133 static bssl::UniquePtr<X509> MakeSelfSignedCert(EVP_PKEY *evp_pkey,
134                                                 const int valid_days) {
135   uint64_t serial;
136   bssl::UniquePtr<X509> x509(X509_new());
137   if (!x509 ||  //
138       !X509_set_version(x509.get(), X509_VERSION_3) ||
139       !RAND_bytes(reinterpret_cast<uint8_t *>(&serial), sizeof(serial)) ||
140       !ASN1_INTEGER_set_uint64(X509_get_serialNumber(x509.get()), serial) ||
141       !X509_gmtime_adj(X509_get_notBefore(x509.get()), 0) ||
142       !X509_gmtime_adj(X509_get_notAfter(x509.get()),
143                        60 * 60 * 24 * valid_days)) {
144     return nullptr;
145   }
146 
147   X509_NAME *subject = X509_get_subject_name(x509.get());
148   if (!X509_NAME_add_entry_by_txt(subject, "C", MBSTRING_ASC,
149                                   reinterpret_cast<const uint8_t *>("US"), -1,
150                                   -1, 0) ||
151       !X509_NAME_add_entry_by_txt(
152           subject, "O", MBSTRING_ASC,
153           reinterpret_cast<const uint8_t *>("BoringSSL"), -1, -1, 0) ||
154       !X509_set_issuer_name(x509.get(), subject)) {
155     return nullptr;
156   }
157 
158   // macOS requires an explicit EKU extension.
159   bssl::UniquePtr<STACK_OF(ASN1_OBJECT)> ekus(sk_ASN1_OBJECT_new_null());
160   if (!ekus ||
161       !sk_ASN1_OBJECT_push(ekus.get(), OBJ_nid2obj(NID_server_auth)) ||
162       !X509_add1_ext_i2d(x509.get(), NID_ext_key_usage, ekus.get(), /*crit=*/1,
163                          /*flags=*/0)) {
164     return nullptr;
165   }
166 
167   if (!X509_set_pubkey(x509.get(), evp_pkey)) {
168     fprintf(stderr, "Failed to set public key.\n");
169     return nullptr;
170   }
171   if (!X509_sign(x509.get(), evp_pkey, EVP_sha256())) {
172     fprintf(stderr, "Failed to sign certificate.\n");
173     return nullptr;
174   }
175   return x509;
176 }
177 
InfoCallback(const SSL * ssl,int type,int value)178 static void InfoCallback(const SSL *ssl, int type, int value) {
179   switch (type) {
180     case SSL_CB_HANDSHAKE_START:
181       fprintf(stderr, "Handshake started.\n");
182       break;
183     case SSL_CB_HANDSHAKE_DONE:
184       fprintf(stderr, "Handshake done.\n");
185       break;
186     case SSL_CB_ACCEPT_LOOP:
187       fprintf(stderr, "Handshake progress: %s\n", SSL_state_string_long(ssl));
188       break;
189   }
190 }
191 
192 static FILE *g_keylog_file = nullptr;
193 
KeyLogCallback(const SSL * ssl,const char * line)194 static void KeyLogCallback(const SSL *ssl, const char *line) {
195   fprintf(g_keylog_file, "%s\n", line);
196   fflush(g_keylog_file);
197 }
198 
HandleWWW(SSL * ssl)199 static bool HandleWWW(SSL *ssl) {
200   bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
201   if (!bio) {
202     fprintf(stderr, "Cannot create BIO for response\n");
203     return false;
204   }
205 
206   BIO_puts(bio.get(), "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n");
207   PrintConnectionInfo(bio.get(), ssl);
208 
209   char request[4];
210   size_t request_len = 0;
211   while (request_len < sizeof(request)) {
212     int ssl_ret =
213         SSL_read(ssl, request + request_len, sizeof(request) - request_len);
214     if (ssl_ret <= 0) {
215       int ssl_err = SSL_get_error(ssl, ssl_ret);
216       PrintSSLError(stderr, "Error while reading", ssl_err, ssl_ret);
217       return false;
218     }
219     request_len += static_cast<size_t>(ssl_ret);
220   }
221 
222   // Assume simple HTTP request, print status.
223   if (memcmp(request, "GET ", 4) == 0) {
224     const uint8_t *response;
225     size_t response_len;
226     if (BIO_mem_contents(bio.get(), &response, &response_len)) {
227       SSL_write(ssl, response, response_len);
228     }
229   }
230   return true;
231 }
232 
Server(const std::vector<std::string> & args)233 bool Server(const std::vector<std::string> &args) {
234   if (!InitSocketLibrary()) {
235     return false;
236   }
237 
238   std::map<std::string, std::string> args_map;
239 
240   if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
241     PrintUsage(kArguments);
242     return false;
243   }
244 
245   bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
246 
247   const char *keylog_file = getenv("SSLKEYLOGFILE");
248   if (keylog_file) {
249     g_keylog_file = fopen(keylog_file, "a");
250     if (g_keylog_file == nullptr) {
251       perror("fopen");
252       return false;
253     }
254     SSL_CTX_set_keylog_callback(ctx.get(), KeyLogCallback);
255   }
256 
257   // Server authentication is required.
258   if (args_map.count("-key") != 0) {
259     std::string key = args_map["-key"];
260     if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key.c_str(),
261                                      SSL_FILETYPE_PEM)) {
262       fprintf(stderr, "Failed to load private key: %s\n", key.c_str());
263       return false;
264     }
265     const std::string &cert =
266         args_map.count("-cert") != 0 ? args_map["-cert"] : key;
267     if (!SSL_CTX_use_certificate_chain_file(ctx.get(), cert.c_str())) {
268       fprintf(stderr, "Failed to load cert chain: %s\n", cert.c_str());
269       return false;
270     }
271   } else {
272     bssl::UniquePtr<EVP_PKEY> evp_pkey = MakeKeyPairForSelfSignedCert();
273     if (!evp_pkey) {
274       return false;
275     }
276     bssl::UniquePtr<X509> cert =
277         MakeSelfSignedCert(evp_pkey.get(), 365 /* valid_days */);
278     if (!cert) {
279       return false;
280     }
281     if (!SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get())) {
282       fprintf(stderr, "Failed to set private key.\n");
283       return false;
284     }
285     if (!SSL_CTX_use_certificate(ctx.get(), cert.get())) {
286       fprintf(stderr, "Failed to set certificate.\n");
287       return false;
288     }
289   }
290 
291   if (args_map.count("-ech-key") + args_map.count("-ech-config") == 1) {
292     fprintf(stderr,
293             "-ech-config and -ech-key must be specified together.\n");
294     return false;
295   }
296 
297   if (args_map.count("-ech-key") != 0) {
298     // Load the ECH private key.
299     std::string ech_key_path = args_map["-ech-key"];
300     ScopedFILE ech_key_file(fopen(ech_key_path.c_str(), "rb"));
301     std::vector<uint8_t> ech_key;
302     if (ech_key_file == nullptr ||
303         !ReadAll(&ech_key, ech_key_file.get())) {
304       fprintf(stderr, "Error reading %s\n", ech_key_path.c_str());
305       return false;
306     }
307 
308     // Load the ECHConfig.
309     std::string ech_config_path = args_map["-ech-config"];
310     ScopedFILE ech_config_file(fopen(ech_config_path.c_str(), "rb"));
311     std::vector<uint8_t> ech_config;
312     if (ech_config_file == nullptr ||
313         !ReadAll(&ech_config, ech_config_file.get())) {
314       fprintf(stderr, "Error reading %s\n", ech_config_path.c_str());
315       return false;
316     }
317 
318     bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
319     bssl::ScopedEVP_HPKE_KEY key;
320     if (!keys ||
321         !EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(),
322                            ech_key.data(), ech_key.size()) ||
323         !SSL_ECH_KEYS_add(keys.get(),
324                           /*is_retry_config=*/1, ech_config.data(),
325                           ech_config.size(), key.get()) ||
326         !SSL_CTX_set1_ech_keys(ctx.get(), keys.get())) {
327       fprintf(stderr, "Error setting server's ECHConfig and private key\n");
328       return false;
329     }
330   }
331 
332   if (args_map.count("-cipher") != 0 &&
333       !SSL_CTX_set_strict_cipher_list(ctx.get(), args_map["-cipher"].c_str())) {
334     fprintf(stderr, "Failed setting cipher list\n");
335     return false;
336   }
337 
338   if (args_map.count("-curves") != 0 &&
339       !SSL_CTX_set1_curves_list(ctx.get(), args_map["-curves"].c_str())) {
340     fprintf(stderr, "Failed setting curves list\n");
341     return false;
342   }
343 
344   uint16_t max_version = TLS1_3_VERSION;
345   if (args_map.count("-max-version") != 0 &&
346       !VersionFromString(&max_version, args_map["-max-version"])) {
347     fprintf(stderr, "Unknown protocol version: '%s'\n",
348             args_map["-max-version"].c_str());
349     return false;
350   }
351 
352   if (!SSL_CTX_set_max_proto_version(ctx.get(), max_version)) {
353     return false;
354   }
355 
356   if (args_map.count("-min-version") != 0) {
357     uint16_t version;
358     if (!VersionFromString(&version, args_map["-min-version"])) {
359       fprintf(stderr, "Unknown protocol version: '%s'\n",
360               args_map["-min-version"].c_str());
361       return false;
362     }
363     if (!SSL_CTX_set_min_proto_version(ctx.get(), version)) {
364       return false;
365     }
366   }
367 
368   if (args_map.count("-ocsp-response") != 0 &&
369       !LoadOCSPResponse(ctx.get(), args_map["-ocsp-response"].c_str())) {
370     fprintf(stderr, "Failed to load OCSP response: %s\n", args_map["-ocsp-response"].c_str());
371     return false;
372   }
373 
374   if (args_map.count("-early-data") != 0) {
375     SSL_CTX_set_early_data_enabled(ctx.get(), 1);
376   }
377 
378   if (args_map.count("-debug") != 0) {
379     SSL_CTX_set_info_callback(ctx.get(), InfoCallback);
380   }
381 
382   if (args_map.count("-require-any-client-cert") != 0) {
383     SSL_CTX_set_verify(
384         ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
385     SSL_CTX_set_cert_verify_callback(
386         ctx.get(), [](X509_STORE_CTX *store, void *arg) -> int { return 1; },
387         nullptr);
388   }
389 
390   Listener listener;
391   if (!listener.Init(args_map["-accept"])) {
392     return false;
393   }
394 
395   bool result = true;
396   do {
397     int sock = -1;
398     if (!listener.Accept(&sock)) {
399       return false;
400     }
401 
402     BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
403     bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
404     SSL_set_bio(ssl.get(), bio, bio);
405 
406     if (args_map.count("-jdk11-workaround") != 0) {
407       SSL_set_jdk11_workaround(ssl.get(), 1);
408     }
409 
410     int ret = SSL_accept(ssl.get());
411     if (ret != 1) {
412       int ssl_err = SSL_get_error(ssl.get(), ret);
413       PrintSSLError(stderr, "Error while connecting", ssl_err, ret);
414       result = false;
415       continue;
416     }
417 
418     fprintf(stderr, "Connected.\n");
419     bssl::UniquePtr<BIO> bio_stderr(BIO_new_fp(stderr, BIO_NOCLOSE));
420     PrintConnectionInfo(bio_stderr.get(), ssl.get());
421 
422     if (args_map.count("-www") != 0) {
423       result = HandleWWW(ssl.get());
424     } else {
425       result = TransferData(ssl.get(), sock);
426     }
427   } while (args_map.count("-loop") != 0);
428 
429   return result;
430 }
431