1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/tools/flip_server/spdy_ssl.h"
6
7#include "base/logging.h"
8#include "openssl/err.h"
9#include "openssl/ssl.h"
10
11namespace net {
12
13// Each element consists of <the length of the string><string> .
14#define NEXT_PROTO_STRING \
15  "\x08spdy/4a2" \
16  "\x06spdy/3" \
17  "\x06spdy/2" \
18  "\x08http/1.1" \
19  "\x08http/1.0"
20#define SSL_CIPHER_LIST "!aNULL:!ADH:!eNull:!LOW:!EXP:RC4+RSA:MEDIUM:HIGH"
21
22int ssl_set_npn_callback(SSL* s,
23                         const unsigned char** data,
24                         unsigned int* len,
25                         void* arg) {
26  VLOG(1) << "SSL NPN callback: advertising protocols.";
27  *data = (const unsigned char*)NEXT_PROTO_STRING;
28  *len = strlen(NEXT_PROTO_STRING);
29  return SSL_TLSEXT_ERR_OK;
30}
31
32void InitSSL(SSLState* state,
33             std::string ssl_cert_name,
34             std::string ssl_key_name,
35             bool use_npn,
36             int session_expiration_time,
37             bool disable_ssl_compression) {
38  SSL_library_init();
39  PrintSslError();
40
41  SSL_load_error_strings();
42  PrintSslError();
43
44  state->ssl_method = SSLv23_method();
45  state->ssl_ctx = SSL_CTX_new(state->ssl_method);
46  if (!state->ssl_ctx) {
47    PrintSslError();
48    LOG(FATAL) << "Unable to create SSL context";
49  }
50  // Disable SSLv2 support.
51  SSL_CTX_set_options(state->ssl_ctx,
52                      SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE);
53  if (SSL_CTX_use_certificate_chain_file(state->ssl_ctx,
54                                         ssl_cert_name.c_str()) <= 0) {
55    PrintSslError();
56    LOG(FATAL) << "Unable to use cert.pem as SSL cert.";
57  }
58  if (SSL_CTX_use_PrivateKey_file(
59          state->ssl_ctx, ssl_key_name.c_str(), SSL_FILETYPE_PEM) <= 0) {
60    PrintSslError();
61    LOG(FATAL) << "Unable to use key.pem as SSL key.";
62  }
63  if (!SSL_CTX_check_private_key(state->ssl_ctx)) {
64    PrintSslError();
65    LOG(FATAL) << "The cert.pem and key.pem files don't match";
66  }
67  if (use_npn) {
68    SSL_CTX_set_next_protos_advertised_cb(
69        state->ssl_ctx, ssl_set_npn_callback, NULL);
70  }
71  VLOG(1) << "SSL CTX default cipher list: " << SSL_CIPHER_LIST;
72  SSL_CTX_set_cipher_list(state->ssl_ctx, SSL_CIPHER_LIST);
73
74  VLOG(1) << "SSL CTX session expiry: " << session_expiration_time
75          << " seconds";
76  SSL_CTX_set_timeout(state->ssl_ctx, session_expiration_time);
77
78#ifdef SSL_MODE_RELEASE_BUFFERS
79  VLOG(1) << "SSL CTX: Setting Release Buffers mode.";
80  SSL_CTX_set_mode(state->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
81#endif
82
83#if !defined(OPENSSL_IS_BORINGSSL)
84  // Proper methods to disable compression don't exist until 0.9.9+. For now
85  // we must manipulate the stack of compression methods directly.
86  if (disable_ssl_compression) {
87    STACK_OF(SSL_COMP)* ssl_comp_methods = SSL_COMP_get_compression_methods();
88    int num_methods = sk_SSL_COMP_num(ssl_comp_methods);
89    int i;
90    for (i = 0; i < num_methods; i++) {
91      static_cast<void>(sk_SSL_COMP_delete(ssl_comp_methods, i));
92    }
93  }
94#endif
95}
96
97SSL* CreateSSLContext(SSL_CTX* ssl_ctx) {
98  SSL* ssl = SSL_new(ssl_ctx);
99  SSL_set_accept_state(ssl);
100  PrintSslError();
101  return ssl;
102}
103
104void PrintSslError() {
105  char buf[128];  // this buffer must be at least 120 chars long.
106  int error_num = ERR_get_error();
107  while (error_num != 0) {
108    ERR_error_string_n(error_num, buf, sizeof(buf));
109    LOG(ERROR) << buf;
110    error_num = ERR_get_error();
111  }
112}
113
114}  // namespace net
115