Home | History | Annotate | Download | only in tool
      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       "-ocsp-response", kOptionalArgument,
     39       "OCSP response file to send",
     40     },
     41     {
     42      "", kOptionalArgument, "",
     43     },
     44 };
     45 
     46 static bool LoadOCSPResponse(SSL_CTX *ctx, const char *filename) {
     47   void *data = NULL;
     48   bool ret = false;
     49   size_t bytes_read;
     50   long length;
     51 
     52   FILE *f = fopen(filename, "rb");
     53 
     54   if (f == NULL ||
     55       fseek(f, 0, SEEK_END) != 0) {
     56     goto out;
     57   }
     58 
     59   length = ftell(f);
     60   if (length < 0) {
     61     goto out;
     62   }
     63 
     64   data = malloc(length);
     65   if (data == NULL) {
     66     goto out;
     67   }
     68   rewind(f);
     69 
     70   bytes_read = fread(data, 1, length, f);
     71   if (ferror(f) != 0 ||
     72       bytes_read != (size_t)length ||
     73       !SSL_CTX_set_ocsp_response(ctx, (uint8_t*)data, bytes_read)) {
     74     goto out;
     75   }
     76 
     77   ret = true;
     78 out:
     79   if (f != NULL) {
     80       fclose(f);
     81   }
     82   free(data);
     83   return ret;
     84 }
     85 
     86 bool Server(const std::vector<std::string> &args) {
     87   if (!InitSocketLibrary()) {
     88     return false;
     89   }
     90 
     91   std::map<std::string, std::string> args_map;
     92 
     93   if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
     94     PrintUsage(kArguments);
     95     return false;
     96   }
     97 
     98   SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
     99   SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
    100 
    101   // Server authentication is required.
    102   std::string key_file = "server.pem";
    103   if (args_map.count("-key") != 0) {
    104     key_file = args_map["-key"];
    105   }
    106   if (!SSL_CTX_use_PrivateKey_file(ctx, key_file.c_str(), SSL_FILETYPE_PEM)) {
    107     fprintf(stderr, "Failed to load private key: %s\n", key_file.c_str());
    108     return false;
    109   }
    110   if (!SSL_CTX_use_certificate_chain_file(ctx, key_file.c_str())) {
    111     fprintf(stderr, "Failed to load cert chain: %s\n", key_file.c_str());
    112     return false;
    113   }
    114 
    115   if (args_map.count("-cipher") != 0 &&
    116       !SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str())) {
    117     fprintf(stderr, "Failed setting cipher list\n");
    118     return false;
    119   }
    120 
    121   if (args_map.count("-ocsp-response") != 0 &&
    122       !LoadOCSPResponse(ctx, args_map["-ocsp-response"].c_str())) {
    123     fprintf(stderr, "Failed to load OCSP response: %s\n", args_map["-ocsp-response"].c_str());
    124     return false;
    125   }
    126 
    127   int sock = -1;
    128   if (!Accept(&sock, args_map["-accept"])) {
    129     return false;
    130   }
    131 
    132   BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
    133   SSL *ssl = SSL_new(ctx);
    134   SSL_set_bio(ssl, bio, bio);
    135 
    136   int ret = SSL_accept(ssl);
    137   if (ret != 1) {
    138     int ssl_err = SSL_get_error(ssl, ret);
    139     fprintf(stderr, "Error while connecting: %d\n", ssl_err);
    140     ERR_print_errors_cb(PrintErrorCallback, stderr);
    141     return false;
    142   }
    143 
    144   fprintf(stderr, "Connected.\n");
    145   PrintConnectionInfo(ssl);
    146 
    147   bool ok = TransferData(ssl, sock);
    148 
    149   SSL_free(ssl);
    150   SSL_CTX_free(ctx);
    151   return ok;
    152 }
    153