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