1/*
2 * libjingle
3 * Copyright 2004--2008, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/base/opensslidentity.h"
29
30#include <openssl/ssl.h>
31#include <openssl/bio.h>
32#include <openssl/err.h>
33#include <openssl/pem.h>
34#include <openssl/bn.h>
35#include <openssl/rsa.h>
36#include <openssl/crypto.h>
37
38#include "talk/base/logging.h"
39#include "talk/base/helpers.h"
40
41namespace talk_base {
42
43// We could have exposed a myriad of parameters for the crypto stuff,
44// but keeping it simple seems best.
45
46// Strength of generated keys. Those are RSA.
47static const int KEY_LENGTH = 1024;
48
49// Random bits for certificate serial number
50static const int SERIAL_RAND_BITS = 64;
51
52// Certificate validity lifetime
53static const int CERTIFICATE_LIFETIME = 60*60*24*365;  // one year, arbitrarily
54
55// Generate a key pair. Caller is responsible for freeing the returned object.
56static EVP_PKEY* MakeKey() {
57  LOG(LS_INFO) << "Making key pair";
58  EVP_PKEY* pkey = EVP_PKEY_new();
59#if OPENSSL_VERSION_NUMBER < 0x00908000l
60  // Only RSA_generate_key is available. Use that.
61  RSA* rsa = RSA_generate_key(KEY_LENGTH, 0x10001, NULL, NULL);
62  if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
63    EVP_PKEY_free(pkey);
64    RSA_free(rsa);
65    return NULL;
66  }
67#else
68  // RSA_generate_key is deprecated. Use _ex version.
69  BIGNUM* exponent = BN_new();
70  RSA* rsa = RSA_new();
71  if (!pkey || !exponent || !rsa ||
72      !BN_set_word(exponent, 0x10001) ||  // 65537 RSA exponent
73      !RSA_generate_key_ex(rsa, KEY_LENGTH, exponent, NULL) ||
74      !EVP_PKEY_assign_RSA(pkey, rsa)) {
75    EVP_PKEY_free(pkey);
76    BN_free(exponent);
77    RSA_free(rsa);
78    return NULL;
79  }
80  // ownership of rsa struct was assigned, don't free it.
81  BN_free(exponent);
82#endif
83  LOG(LS_INFO) << "Returning key pair";
84  return pkey;
85}
86
87// Generate a self-signed certificate, with the public key from the
88// given key pair. Caller is responsible for freeing the returned object.
89static X509* MakeCertificate(EVP_PKEY* pkey, const char* common_name) {
90  LOG(LS_INFO) << "Making certificate for " << common_name;
91  X509* x509 = NULL;
92  BIGNUM* serial_number = NULL;
93  X509_NAME* name = NULL;
94
95  if ((x509=X509_new()) == NULL)
96    goto error;
97
98  if (!X509_set_pubkey(x509, pkey))
99    goto error;
100
101  // serial number
102  // temporary reference to serial number inside x509 struct
103  ASN1_INTEGER* asn1_serial_number;
104  if (!(serial_number = BN_new()) ||
105      !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) ||
106      !(asn1_serial_number = X509_get_serialNumber(x509)) ||
107      !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number))
108    goto error;
109
110  if (!X509_set_version(x509, 0L))  // version 1
111    goto error;
112
113  // There are a lot of possible components for the name entries. In
114  // our P2P SSL mode however, the certificates are pre-exchanged
115  // (through the secure XMPP channel), and so the certificate
116  // identification is arbitrary. It can't be empty, so we set some
117  // arbitrary common_name. Note that this certificate goes out in
118  // clear during SSL negotiation, so there may be a privacy issue in
119  // putting anything recognizable here.
120  if (!(name = X509_NAME_new()) ||
121      !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8,
122                                     (unsigned char*)common_name, -1, -1, 0) ||
123      !X509_set_subject_name(x509, name) ||
124      !X509_set_issuer_name(x509, name))
125    goto error;
126
127  if (!X509_gmtime_adj(X509_get_notBefore(x509), 0) ||
128      !X509_gmtime_adj(X509_get_notAfter(x509), CERTIFICATE_LIFETIME))
129    goto error;
130
131  if (!X509_sign(x509, pkey, EVP_sha1()))
132    goto error;
133
134  BN_free(serial_number);
135  X509_NAME_free(name);
136  LOG(LS_INFO) << "Returning certificate";
137  return x509;
138
139 error:
140  BN_free(serial_number);
141  X509_NAME_free(name);
142  X509_free(x509);
143  return NULL;
144}
145
146// This dumps the SSL error stack to the log.
147static void LogSSLErrors(const std::string& prefix) {
148  char error_buf[200];
149  unsigned long err;
150  while ((err = ERR_get_error())) {
151    ERR_error_string_n(err, error_buf, sizeof(error_buf));
152    LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
153  }
154}
155
156OpenSSLKeyPair* OpenSSLKeyPair::Generate() {
157  EVP_PKEY* pkey = MakeKey();
158  if (!pkey) {
159    LogSSLErrors("Generating key pair");
160    return NULL;
161  }
162  return new OpenSSLKeyPair(pkey);
163}
164
165OpenSSLKeyPair::~OpenSSLKeyPair() {
166  EVP_PKEY_free(pkey_);
167}
168
169void OpenSSLKeyPair::AddReference() {
170  CRYPTO_add(&pkey_->references, 1, CRYPTO_LOCK_EVP_PKEY);
171}
172
173#ifdef _DEBUG
174// Print a certificate to the log, for debugging.
175static void PrintCert(X509* x509) {
176  BIO* temp_memory_bio = BIO_new(BIO_s_mem());
177  if (!temp_memory_bio) {
178    LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
179    return;
180  }
181  X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0);
182  BIO_write(temp_memory_bio, "\0", 1);
183  char* buffer;
184  BIO_get_mem_data(temp_memory_bio, &buffer);
185  LOG(LS_VERBOSE) << buffer;
186  BIO_free(temp_memory_bio);
187}
188#endif
189
190OpenSSLCertificate* OpenSSLCertificate::Generate(
191    OpenSSLKeyPair* key_pair, const std::string& common_name) {
192  std::string actual_common_name = common_name;
193  if (actual_common_name.empty())
194    // Use a random string, arbitrarily 8chars long.
195    actual_common_name = CreateRandomString(8);
196  X509* x509 = MakeCertificate(key_pair->pkey(), actual_common_name.c_str());
197  if (!x509) {
198    LogSSLErrors("Generating certificate");
199    return NULL;
200  }
201#ifdef _DEBUG
202  PrintCert(x509);
203#endif
204  return new OpenSSLCertificate(x509);
205}
206
207OpenSSLCertificate* OpenSSLCertificate::FromPEMString(
208    const std::string& pem_string, int* pem_length) {
209  BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
210  if (!bio)
211    return NULL;
212  (void)BIO_set_close(bio, BIO_NOCLOSE);
213  BIO_set_mem_eof_return(bio, 0);
214  X509 *x509 = PEM_read_bio_X509(bio, NULL, NULL,
215                                 const_cast<char*>("\0"));
216  char *ptr;
217  int remaining_length = BIO_get_mem_data(bio, &ptr);
218  BIO_free(bio);
219  if (pem_length)
220    *pem_length = pem_string.length() - remaining_length;
221  if (x509)
222    return new OpenSSLCertificate(x509);
223  else
224    return NULL;
225}
226
227OpenSSLCertificate::~OpenSSLCertificate() {
228  X509_free(x509_);
229}
230
231std::string OpenSSLCertificate::ToPEMString() const {
232  BIO* bio = BIO_new(BIO_s_mem());
233  if (!bio)
234    return NULL;
235  if (!PEM_write_bio_X509(bio, x509_)) {
236    BIO_free(bio);
237    return NULL;
238  }
239  BIO_write(bio, "\0", 1);
240  char* buffer;
241  BIO_get_mem_data(bio, &buffer);
242  std::string ret(buffer);
243  BIO_free(bio);
244  return ret;
245}
246
247void OpenSSLCertificate::AddReference() {
248  CRYPTO_add(&x509_->references, 1, CRYPTO_LOCK_X509);
249}
250
251OpenSSLIdentity* OpenSSLIdentity::Generate(const std::string& common_name) {
252  OpenSSLKeyPair *key_pair = OpenSSLKeyPair::Generate();
253  if (key_pair) {
254    OpenSSLCertificate *certificate =
255        OpenSSLCertificate::Generate(key_pair, common_name);
256    if (certificate)
257      return new OpenSSLIdentity(key_pair, certificate);
258    delete key_pair;
259  }
260  LOG(LS_INFO) << "Identity generation failed";
261  return NULL;
262}
263
264bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
265  // 1 is the documented success return code.
266  if (SSL_CTX_use_certificate(ctx, certificate_->x509()) != 1 ||
267     SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
268    LogSSLErrors("Configuring key and certificate");
269    return false;
270  }
271  return true;
272}
273
274}  // talk_base namespace
275