Home | History | Annotate | Download | only in base
      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 #if HAVE_OPENSSL_SSL_H
     29 
     30 #include "talk/base/opensslidentity.h"
     31 
     32 // Must be included first before openssl headers.
     33 #include "talk/base/win32.h"  // NOLINT
     34 
     35 #include <openssl/bio.h>
     36 #include <openssl/err.h>
     37 #include <openssl/pem.h>
     38 #include <openssl/bn.h>
     39 #include <openssl/rsa.h>
     40 #include <openssl/crypto.h>
     41 
     42 #include "talk/base/checks.h"
     43 #include "talk/base/helpers.h"
     44 #include "talk/base/logging.h"
     45 #include "talk/base/openssl.h"
     46 #include "talk/base/openssldigest.h"
     47 
     48 namespace talk_base {
     49 
     50 // We could have exposed a myriad of parameters for the crypto stuff,
     51 // but keeping it simple seems best.
     52 
     53 // Strength of generated keys. Those are RSA.
     54 static const int KEY_LENGTH = 1024;
     55 
     56 // Random bits for certificate serial number
     57 static const int SERIAL_RAND_BITS = 64;
     58 
     59 // Certificate validity lifetime
     60 static const int CERTIFICATE_LIFETIME = 60*60*24*30;  // 30 days, arbitrarily
     61 // Certificate validity window.
     62 // This is to compensate for slightly incorrect system clocks.
     63 static const int CERTIFICATE_WINDOW = -60*60*24;
     64 
     65 // Generate a key pair. Caller is responsible for freeing the returned object.
     66 static EVP_PKEY* MakeKey() {
     67   LOG(LS_INFO) << "Making key pair";
     68   EVP_PKEY* pkey = EVP_PKEY_new();
     69   // RSA_generate_key is deprecated. Use _ex version.
     70   BIGNUM* exponent = BN_new();
     71   RSA* rsa = RSA_new();
     72   if (!pkey || !exponent || !rsa ||
     73       !BN_set_word(exponent, 0x10001) ||  // 65537 RSA exponent
     74       !RSA_generate_key_ex(rsa, KEY_LENGTH, exponent, NULL) ||
     75       !EVP_PKEY_assign_RSA(pkey, rsa)) {
     76     EVP_PKEY_free(pkey);
     77     BN_free(exponent);
     78     RSA_free(rsa);
     79     return NULL;
     80   }
     81   // ownership of rsa struct was assigned, don't free it.
     82   BN_free(exponent);
     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.
     89 static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) {
     90   LOG(LS_INFO) << "Making certificate for " << params.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()) == NULL ||
    105       !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) ||
    106       (asn1_serial_number = X509_get_serialNumber(x509)) == NULL ||
    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()) == NULL ||
    121       !X509_NAME_add_entry_by_NID(
    122           name, NID_commonName, MBSTRING_UTF8,
    123           (unsigned char*)params.common_name.c_str(), -1, -1, 0) ||
    124       !X509_set_subject_name(x509, name) ||
    125       !X509_set_issuer_name(x509, name))
    126     goto error;
    127 
    128   if (!X509_gmtime_adj(X509_get_notBefore(x509), params.not_before) ||
    129       !X509_gmtime_adj(X509_get_notAfter(x509), params.not_after))
    130     goto error;
    131 
    132   if (!X509_sign(x509, pkey, EVP_sha1()))
    133     goto error;
    134 
    135   BN_free(serial_number);
    136   X509_NAME_free(name);
    137   LOG(LS_INFO) << "Returning certificate";
    138   return x509;
    139 
    140  error:
    141   BN_free(serial_number);
    142   X509_NAME_free(name);
    143   X509_free(x509);
    144   return NULL;
    145 }
    146 
    147 // This dumps the SSL error stack to the log.
    148 static void LogSSLErrors(const std::string& prefix) {
    149   char error_buf[200];
    150   unsigned long err;
    151 
    152   while ((err = ERR_get_error()) != 0) {
    153     ERR_error_string_n(err, error_buf, sizeof(error_buf));
    154     LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
    155   }
    156 }
    157 
    158 OpenSSLKeyPair* OpenSSLKeyPair::Generate() {
    159   EVP_PKEY* pkey = MakeKey();
    160   if (!pkey) {
    161     LogSSLErrors("Generating key pair");
    162     return NULL;
    163   }
    164   return new OpenSSLKeyPair(pkey);
    165 }
    166 
    167 OpenSSLKeyPair::~OpenSSLKeyPair() {
    168   EVP_PKEY_free(pkey_);
    169 }
    170 
    171 void OpenSSLKeyPair::AddReference() {
    172   CRYPTO_add(&pkey_->references, 1, CRYPTO_LOCK_EVP_PKEY);
    173 }
    174 
    175 #ifdef _DEBUG
    176 // Print a certificate to the log, for debugging.
    177 static void PrintCert(X509* x509) {
    178   BIO* temp_memory_bio = BIO_new(BIO_s_mem());
    179   if (!temp_memory_bio) {
    180     LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
    181     return;
    182   }
    183   X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0);
    184   BIO_write(temp_memory_bio, "\0", 1);
    185   char* buffer;
    186   BIO_get_mem_data(temp_memory_bio, &buffer);
    187   LOG(LS_VERBOSE) << buffer;
    188   BIO_free(temp_memory_bio);
    189 }
    190 #endif
    191 
    192 OpenSSLCertificate* OpenSSLCertificate::Generate(
    193     OpenSSLKeyPair* key_pair, const SSLIdentityParams& params) {
    194   SSLIdentityParams actual_params(params);
    195   if (actual_params.common_name.empty()) {
    196     // Use a random string, arbitrarily 8chars long.
    197     actual_params.common_name = CreateRandomString(8);
    198   }
    199   X509* x509 = MakeCertificate(key_pair->pkey(), actual_params);
    200   if (!x509) {
    201     LogSSLErrors("Generating certificate");
    202     return NULL;
    203   }
    204 #ifdef _DEBUG
    205   PrintCert(x509);
    206 #endif
    207   OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
    208   X509_free(x509);
    209   return ret;
    210 }
    211 
    212 OpenSSLCertificate* OpenSSLCertificate::FromPEMString(
    213     const std::string& pem_string) {
    214   BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
    215   if (!bio)
    216     return NULL;
    217   BIO_set_mem_eof_return(bio, 0);
    218   X509 *x509 = PEM_read_bio_X509(bio, NULL, NULL,
    219                                  const_cast<char*>("\0"));
    220   BIO_free(bio);  // Frees the BIO, but not the pointed-to string.
    221 
    222   if (!x509)
    223     return NULL;
    224 
    225   OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
    226   X509_free(x509);
    227   return ret;
    228 }
    229 
    230 // NOTE: This implementation only functions correctly after InitializeSSL
    231 // and before CleanupSSL.
    232 bool OpenSSLCertificate::GetSignatureDigestAlgorithm(
    233     std::string* algorithm) const {
    234   return OpenSSLDigest::GetDigestName(
    235       EVP_get_digestbyobj(x509_->sig_alg->algorithm), algorithm);
    236 }
    237 
    238 bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm,
    239                                        unsigned char* digest,
    240                                        size_t size,
    241                                        size_t* length) const {
    242   return ComputeDigest(x509_, algorithm, digest, size, length);
    243 }
    244 
    245 bool OpenSSLCertificate::ComputeDigest(const X509* x509,
    246                                        const std::string& algorithm,
    247                                        unsigned char* digest,
    248                                        size_t size,
    249                                        size_t* length) {
    250   const EVP_MD *md;
    251   unsigned int n;
    252 
    253   if (!OpenSSLDigest::GetDigestEVP(algorithm, &md))
    254     return false;
    255 
    256   if (size < static_cast<size_t>(EVP_MD_size(md)))
    257     return false;
    258 
    259   X509_digest(x509, md, digest, &n);
    260 
    261   *length = n;
    262 
    263   return true;
    264 }
    265 
    266 OpenSSLCertificate::~OpenSSLCertificate() {
    267   X509_free(x509_);
    268 }
    269 
    270 std::string OpenSSLCertificate::ToPEMString() const {
    271   BIO* bio = BIO_new(BIO_s_mem());
    272   if (!bio) {
    273     UNREACHABLE();
    274     return std::string();
    275   }
    276   if (!PEM_write_bio_X509(bio, x509_)) {
    277     BIO_free(bio);
    278     UNREACHABLE();
    279     return std::string();
    280   }
    281   BIO_write(bio, "\0", 1);
    282   char* buffer;
    283   BIO_get_mem_data(bio, &buffer);
    284   std::string ret(buffer);
    285   BIO_free(bio);
    286   return ret;
    287 }
    288 
    289 void OpenSSLCertificate::ToDER(Buffer* der_buffer) const {
    290   // In case of failure, make sure to leave the buffer empty.
    291   der_buffer->SetData(NULL, 0);
    292 
    293   // Calculates the DER representation of the certificate, from scratch.
    294   BIO* bio = BIO_new(BIO_s_mem());
    295   if (!bio) {
    296     UNREACHABLE();
    297     return;
    298   }
    299   if (!i2d_X509_bio(bio, x509_)) {
    300     BIO_free(bio);
    301     UNREACHABLE();
    302     return;
    303   }
    304   char* data;
    305   size_t length = BIO_get_mem_data(bio, &data);
    306   der_buffer->SetData(data, length);
    307   BIO_free(bio);
    308 }
    309 
    310 void OpenSSLCertificate::AddReference() const {
    311   ASSERT(x509_ != NULL);
    312   CRYPTO_add(&x509_->references, 1, CRYPTO_LOCK_X509);
    313 }
    314 
    315 OpenSSLIdentity* OpenSSLIdentity::GenerateInternal(
    316     const SSLIdentityParams& params) {
    317   OpenSSLKeyPair *key_pair = OpenSSLKeyPair::Generate();
    318   if (key_pair) {
    319     OpenSSLCertificate *certificate = OpenSSLCertificate::Generate(
    320         key_pair, params);
    321     if (certificate)
    322       return new OpenSSLIdentity(key_pair, certificate);
    323     delete key_pair;
    324   }
    325   LOG(LS_INFO) << "Identity generation failed";
    326   return NULL;
    327 }
    328 
    329 OpenSSLIdentity* OpenSSLIdentity::Generate(const std::string& common_name) {
    330   SSLIdentityParams params;
    331   params.common_name = common_name;
    332   params.not_before = CERTIFICATE_WINDOW;
    333   params.not_after = CERTIFICATE_LIFETIME;
    334   return GenerateInternal(params);
    335 }
    336 
    337 OpenSSLIdentity* OpenSSLIdentity::GenerateForTest(
    338     const SSLIdentityParams& params) {
    339   return GenerateInternal(params);
    340 }
    341 
    342 SSLIdentity* OpenSSLIdentity::FromPEMStrings(
    343     const std::string& private_key,
    344     const std::string& certificate) {
    345   scoped_ptr<OpenSSLCertificate> cert(
    346       OpenSSLCertificate::FromPEMString(certificate));
    347   if (!cert) {
    348     LOG(LS_ERROR) << "Failed to create OpenSSLCertificate from PEM string.";
    349     return NULL;
    350   }
    351 
    352   BIO* bio = BIO_new_mem_buf(const_cast<char*>(private_key.c_str()), -1);
    353   if (!bio) {
    354     LOG(LS_ERROR) << "Failed to create a new BIO buffer.";
    355     return NULL;
    356   }
    357   BIO_set_mem_eof_return(bio, 0);
    358   EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL,
    359                                            const_cast<char*>("\0"));
    360   BIO_free(bio);  // Frees the BIO, but not the pointed-to string.
    361 
    362   if (!pkey) {
    363     LOG(LS_ERROR) << "Failed to create the private key from PEM string.";
    364     return NULL;
    365   }
    366 
    367   return new OpenSSLIdentity(new OpenSSLKeyPair(pkey),
    368                              cert.release());
    369 }
    370 
    371 bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
    372   // 1 is the documented success return code.
    373   if (SSL_CTX_use_certificate(ctx, certificate_->x509()) != 1 ||
    374      SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
    375     LogSSLErrors("Configuring key and certificate");
    376     return false;
    377   }
    378   return true;
    379 }
    380 
    381 }  // namespace talk_base
    382 
    383 #endif  // HAVE_OPENSSL_SSL_H
    384