1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* Copyright (c) 2014, Google Inc.
2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Permission to use, copy, modify, and/or distribute this software for any
4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * purpose with or without fee is hereby granted, provided that the above
5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * copyright notice and this permission notice appear in all copies.
6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/base.h>
16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
17d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/err.h>
18d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/ssl.h>
19d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
20d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include "internal.h"
21d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include "transport_common.h"
22d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
23d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
24d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic const struct argument kArguments[] = {
25d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    {
26e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley     "-accept", kRequiredArgument,
27d9e397b599b13d642138480a28c14db7a136bf0Adam Langley     "The port of the server to bind on; eg 45102",
28d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    },
29d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    {
30e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley     "-cipher", kOptionalArgument,
31d9e397b599b13d642138480a28c14db7a136bf0Adam Langley     "An OpenSSL-style cipher suite string that configures the offered ciphers",
32d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    },
33d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    {
34e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley      "-key", kOptionalArgument,
35d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      "Private-key file to use (default is server.pem)",
36d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    },
37d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    {
38b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      "-ocsp-response", kOptionalArgument,
39b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      "OCSP response file to send",
40b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    },
41b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    {
42e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley     "", kOptionalArgument, "",
43d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    },
44d9e397b599b13d642138480a28c14db7a136bf0Adam Langley};
45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
46b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Rootstatic bool LoadOCSPResponse(SSL_CTX *ctx, const char *filename) {
47b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  void *data = NULL;
48b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  bool ret = false;
49b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  size_t bytes_read;
50b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  long length;
51b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
52b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  FILE *f = fopen(filename, "rb");
53b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
54b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  if (f == NULL ||
55b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      fseek(f, 0, SEEK_END) != 0) {
56b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    goto out;
57b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  }
58b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
59b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  length = ftell(f);
60b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  if (length < 0) {
61b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    goto out;
62b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  }
63b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
64b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  data = malloc(length);
65b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  if (data == NULL) {
66b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    goto out;
67b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  }
68b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  rewind(f);
69b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
70b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  bytes_read = fread(data, 1, length, f);
71b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  if (ferror(f) != 0 ||
72b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      bytes_read != (size_t)length ||
73b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      !SSL_CTX_set_ocsp_response(ctx, (uint8_t*)data, bytes_read)) {
74b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    goto out;
75b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  }
76b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
77b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  ret = true;
78b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Rootout:
79b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  if (f != NULL) {
80b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      fclose(f);
81b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  }
82b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  free(data);
83b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  return ret;
84b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root}
85b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
86d9e397b599b13d642138480a28c14db7a136bf0Adam Langleybool Server(const std::vector<std::string> &args) {
87d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!InitSocketLibrary()) {
88d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return false;
89d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
90d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
91d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  std::map<std::string, std::string> args_map;
92d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
93d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
94d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    PrintUsage(kArguments);
95d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return false;
96d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
97d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
98d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
99d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
100d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
101d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  // Server authentication is required.
102d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  std::string key_file = "server.pem";
103d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (args_map.count("-key") != 0) {
104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    key_file = args_map["-key"];
105d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
1064139edb02e59e7ad48e0a8f4c02e45923bc8a344Adam Langley  if (!SSL_CTX_use_PrivateKey_file(ctx, key_file.c_str(), SSL_FILETYPE_PEM)) {
107d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    fprintf(stderr, "Failed to load private key: %s\n", key_file.c_str());
108d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return false;
109d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
1104139edb02e59e7ad48e0a8f4c02e45923bc8a344Adam Langley  if (!SSL_CTX_use_certificate_chain_file(ctx, key_file.c_str())) {
111d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    fprintf(stderr, "Failed to load cert chain: %s\n", key_file.c_str());
112d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return false;
113d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
114d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
115d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (args_map.count("-cipher") != 0 &&
116d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str())) {
117d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    fprintf(stderr, "Failed setting cipher list\n");
118d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return false;
119d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
120d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
121b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  if (args_map.count("-ocsp-response") != 0 &&
122b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      !LoadOCSPResponse(ctx, args_map["-ocsp-response"].c_str())) {
123b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    fprintf(stderr, "Failed to load OCSP response: %s\n", args_map["-ocsp-response"].c_str());
124b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    return false;
125b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  }
126b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
127d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int sock = -1;
128d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!Accept(&sock, args_map["-accept"])) {
129d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return false;
130d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
131d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
132d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
133d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  SSL *ssl = SSL_new(ctx);
134d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  SSL_set_bio(ssl, bio, bio);
135d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
136d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int ret = SSL_accept(ssl);
137d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (ret != 1) {
138d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    int ssl_err = SSL_get_error(ssl, ret);
139d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    fprintf(stderr, "Error while connecting: %d\n", ssl_err);
140d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    ERR_print_errors_cb(PrintErrorCallback, stderr);
141d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return false;
142d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
143d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
144d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  fprintf(stderr, "Connected.\n");
145d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  PrintConnectionInfo(ssl);
146d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
147d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  bool ok = TransferData(ssl, sock);
148d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
149d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  SSL_free(ssl);
150d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  SSL_CTX_free(ctx);
151d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ok;
152d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
153