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 <openssl/err.h>
18 #include <openssl/ssl.h>
19 
20 #include "internal.h"
21 #include "transport_common.h"
22 
23 
24 static const struct argument kArguments[] = {
25     {
26      "-accept", kRequiredArgument,
27      "The port of the server to bind on; eg 45102",
28     },
29     {
30      "-cipher", kOptionalArgument,
31      "An OpenSSL-style cipher suite string that configures the offered ciphers",
32     },
33     {
34       "-key", kOptionalArgument,
35       "Private-key file to use (default is server.pem)",
36     },
37     {
38      "", kOptionalArgument, "",
39     },
40 };
41 
Server(const std::vector<std::string> & args)42 bool Server(const std::vector<std::string> &args) {
43   if (!InitSocketLibrary()) {
44     return false;
45   }
46 
47   std::map<std::string, std::string> args_map;
48 
49   if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
50     PrintUsage(kArguments);
51     return false;
52   }
53 
54   SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
55   SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
56 
57   // Server authentication is required.
58   std::string key_file = "server.pem";
59   if (args_map.count("-key") != 0) {
60     key_file = args_map["-key"];
61   }
62   if (SSL_CTX_use_PrivateKey_file(ctx, key_file.c_str(), SSL_FILETYPE_PEM) <= 0) {
63     fprintf(stderr, "Failed to load private key: %s\n", key_file.c_str());
64     return false;
65   }
66   if (SSL_CTX_use_certificate_chain_file(ctx, key_file.c_str()) != 1) {
67     fprintf(stderr, "Failed to load cert chain: %s\n", key_file.c_str());
68     return false;
69   }
70 
71   if (args_map.count("-cipher") != 0 &&
72       !SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str())) {
73     fprintf(stderr, "Failed setting cipher list\n");
74     return false;
75   }
76 
77   int sock = -1;
78   if (!Accept(&sock, args_map["-accept"])) {
79     return false;
80   }
81 
82   BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
83   SSL *ssl = SSL_new(ctx);
84   SSL_set_bio(ssl, bio, bio);
85 
86   int ret = SSL_accept(ssl);
87   if (ret != 1) {
88     int ssl_err = SSL_get_error(ssl, ret);
89     fprintf(stderr, "Error while connecting: %d\n", ssl_err);
90     ERR_print_errors_cb(PrintErrorCallback, stderr);
91     return false;
92   }
93 
94   fprintf(stderr, "Connected.\n");
95   PrintConnectionInfo(ssl);
96 
97   bool ok = TransferData(ssl, sock);
98 
99   SSL_free(ssl);
100   SSL_CTX_free(ctx);
101   return ok;
102 }
103