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