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/ssl.h>
     36 #include <openssl/bio.h>
     37 #include <openssl/err.h>
     38 #include <openssl/pem.h>
     39 #include <openssl/bn.h>
     40 #include <openssl/rsa.h>
     41 #include <openssl/crypto.h>
     42 
     43 #include "talk/base/helpers.h"
     44 #include "talk/base/logging.h"
     45 #include "talk/base/openssldigest.h"
     46 
     47 namespace talk_base {
     48 
     49 // We could have exposed a myriad of parameters for the crypto stuff,
     50 // but keeping it simple seems best.
     51 
     52 // Strength of generated keys. Those are RSA.
     53 static const int KEY_LENGTH = 1024;
     54 
     55 // Random bits for certificate serial number
     56 static const int SERIAL_RAND_BITS = 64;
     57 
     58 // Certificate validity lifetime
     59 static const int CERTIFICATE_LIFETIME = 60*60*24*365;  // one year, arbitrarily
     60 // Certificate validity window.
     61 // This is to compensate for slightly incorrect system clocks.
     62 static const int CERTIFICATE_WINDOW = -60*60*24;
     63 
     64 // Generate a key pair. Caller is responsible for freeing the returned object.
     65 static EVP_PKEY* MakeKey() {
     66   LOG(LS_INFO) << "Making key pair";
     67   EVP_PKEY* pkey = EVP_PKEY_new();
     68 #if OPENSSL_VERSION_NUMBER < 0x00908000l
     69   // Only RSA_generate_key is available. Use that.
     70   RSA* rsa = RSA_generate_key(KEY_LENGTH, 0x10001, NULL, NULL);
     71   if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
     72     EVP_PKEY_free(pkey);
     73     RSA_free(rsa);
     74     return NULL;
     75   }
     76 #else
     77   // RSA_generate_key is deprecated. Use _ex version.
     78   BIGNUM* exponent = BN_new();
     79   RSA* rsa = RSA_new();
     80   if (!pkey || !exponent || !rsa ||
     81       !BN_set_word(exponent, 0x10001) ||  // 65537 RSA exponent
     82       !RSA_generate_key_ex(rsa, KEY_LENGTH, exponent, NULL) ||
     83       !EVP_PKEY_assign_RSA(pkey, rsa)) {
     84     EVP_PKEY_free(pkey);
     85     BN_free(exponent);
     86     RSA_free(rsa);
     87     return NULL;
     88   }
     89   // ownership of rsa struct was assigned, don't free it.
     90   BN_free(exponent);
     91 #endif
     92   LOG(LS_INFO) << "Returning key pair";
     93   return pkey;
     94 }
     95 
     96 // Generate a self-signed certificate, with the public key from the
     97 // given key pair. Caller is responsible for freeing the returned object.
     98 static X509* MakeCertificate(EVP_PKEY* pkey, const char* common_name) {
     99   LOG(LS_INFO) << "Making certificate for " << common_name;
    100   X509* x509 = NULL;
    101   BIGNUM* serial_number = NULL;
    102   X509_NAME* name = NULL;
    103 
    104   if ((x509=X509_new()) == NULL)
    105     goto error;
    106 
    107   if (!X509_set_pubkey(x509, pkey))
    108     goto error;
    109 
    110   // serial number
    111   // temporary reference to serial number inside x509 struct
    112   ASN1_INTEGER* asn1_serial_number;
    113   if ((serial_number = BN_new()) == NULL ||
    114       !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) ||
    115       (asn1_serial_number = X509_get_serialNumber(x509)) == NULL ||
    116       !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number))
    117     goto error;
    118 
    119   if (!X509_set_version(x509, 0L))  // version 1
    120     goto error;
    121 
    122   // There are a lot of possible components for the name entries. In
    123   // our P2P SSL mode however, the certificates are pre-exchanged
    124   // (through the secure XMPP channel), and so the certificate
    125   // identification is arbitrary. It can't be empty, so we set some
    126   // arbitrary common_name. Note that this certificate goes out in
    127   // clear during SSL negotiation, so there may be a privacy issue in
    128   // putting anything recognizable here.
    129   if ((name = X509_NAME_new()) == NULL ||
    130       !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8,
    131                                      (unsigned char*)common_name, -1, -1, 0) ||
    132       !X509_set_subject_name(x509, name) ||
    133       !X509_set_issuer_name(x509, name))
    134     goto error;
    135 
    136   if (!X509_gmtime_adj(X509_get_notBefore(x509), CERTIFICATE_WINDOW) ||
    137       !X509_gmtime_adj(X509_get_notAfter(x509), CERTIFICATE_LIFETIME))
    138     goto error;
    139 
    140   if (!X509_sign(x509, pkey, EVP_sha1()))
    141     goto error;
    142 
    143   BN_free(serial_number);
    144   X509_NAME_free(name);
    145   LOG(LS_INFO) << "Returning certificate";
    146   return x509;
    147 
    148  error:
    149   BN_free(serial_number);
    150   X509_NAME_free(name);
    151   X509_free(x509);
    152   return NULL;
    153 }
    154 
    155 // This dumps the SSL error stack to the log.
    156 static void LogSSLErrors(const std::string& prefix) {
    157   char error_buf[200];
    158   unsigned long err;
    159 
    160   while ((err = ERR_get_error()) != 0) {
    161     ERR_error_string_n(err, error_buf, sizeof(error_buf));
    162     LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
    163   }
    164 }
    165 
    166 OpenSSLKeyPair* OpenSSLKeyPair::Generate() {
    167   EVP_PKEY* pkey = MakeKey();
    168   if (!pkey) {
    169     LogSSLErrors("Generating key pair");
    170     return NULL;
    171   }
    172   return new OpenSSLKeyPair(pkey);
    173 }
    174 
    175 OpenSSLKeyPair::~OpenSSLKeyPair() {
    176   EVP_PKEY_free(pkey_);
    177 }
    178 
    179 void OpenSSLKeyPair::AddReference() {
    180   CRYPTO_add(&pkey_->references, 1, CRYPTO_LOCK_EVP_PKEY);
    181 }
    182 
    183 #ifdef _DEBUG
    184 // Print a certificate to the log, for debugging.
    185 static void PrintCert(X509* x509) {
    186   BIO* temp_memory_bio = BIO_new(BIO_s_mem());
    187   if (!temp_memory_bio) {
    188     LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
    189     return;
    190   }
    191   X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0);
    192   BIO_write(temp_memory_bio, "\0", 1);
    193   char* buffer;
    194   BIO_get_mem_data(temp_memory_bio, &buffer);
    195   LOG(LS_VERBOSE) << buffer;
    196   BIO_free(temp_memory_bio);
    197 }
    198 #endif
    199 
    200 OpenSSLCertificate* OpenSSLCertificate::Generate(
    201     OpenSSLKeyPair* key_pair, const std::string& common_name) {
    202   std::string actual_common_name = common_name;
    203   if (actual_common_name.empty())
    204     // Use a random string, arbitrarily 8chars long.
    205     actual_common_name = CreateRandomString(8);
    206   X509* x509 = MakeCertificate(key_pair->pkey(), actual_common_name.c_str());
    207   if (!x509) {
    208     LogSSLErrors("Generating certificate");
    209     return NULL;
    210   }
    211 #ifdef _DEBUG
    212   PrintCert(x509);
    213 #endif
    214   return new OpenSSLCertificate(x509);
    215 }
    216 
    217 OpenSSLCertificate* OpenSSLCertificate::FromPEMString(
    218     const std::string& pem_string) {
    219   BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
    220   if (!bio)
    221     return NULL;
    222   (void)BIO_set_close(bio, BIO_NOCLOSE);
    223   BIO_set_mem_eof_return(bio, 0);
    224   X509 *x509 = PEM_read_bio_X509(bio, NULL, NULL,
    225                                  const_cast<char*>("\0"));
    226   BIO_free(bio);
    227   if (x509)
    228     return new OpenSSLCertificate(x509);
    229   else
    230     return NULL;
    231 }
    232 
    233 bool OpenSSLCertificate::ComputeDigest(const std::string &algorithm,
    234                                        unsigned char *digest,
    235                                        std::size_t size,
    236                                        std::size_t *length) const {
    237   return ComputeDigest(x509_, algorithm, digest, size, length);
    238 }
    239 
    240 bool OpenSSLCertificate::ComputeDigest(const X509 *x509,
    241                                        const std::string &algorithm,
    242                                        unsigned char *digest,
    243                                        std::size_t size,
    244                                        std::size_t *length) {
    245   const EVP_MD *md;
    246   unsigned int n;
    247 
    248   if (!OpenSSLDigest::GetDigestEVP(algorithm, &md))
    249     return false;
    250 
    251   if (size < static_cast<size_t>(EVP_MD_size(md)))
    252     return false;
    253 
    254   X509_digest(x509, md, digest, &n);
    255 
    256   *length = n;
    257 
    258   return true;
    259 }
    260 
    261 OpenSSLCertificate::~OpenSSLCertificate() {
    262   X509_free(x509_);
    263 }
    264 
    265 std::string OpenSSLCertificate::ToPEMString() const {
    266   BIO* bio = BIO_new(BIO_s_mem());
    267   if (!bio)
    268     return NULL;
    269   if (!PEM_write_bio_X509(bio, x509_)) {
    270     BIO_free(bio);
    271     return NULL;
    272   }
    273   BIO_write(bio, "\0", 1);
    274   char* buffer;
    275   BIO_get_mem_data(bio, &buffer);
    276   std::string ret(buffer);
    277   BIO_free(bio);
    278   return ret;
    279 }
    280 
    281 void OpenSSLCertificate::AddReference() const {
    282   CRYPTO_add(&x509_->references, 1, CRYPTO_LOCK_X509);
    283 }
    284 
    285 OpenSSLIdentity* OpenSSLIdentity::Generate(const std::string& common_name) {
    286   OpenSSLKeyPair *key_pair = OpenSSLKeyPair::Generate();
    287   if (key_pair) {
    288     OpenSSLCertificate *certificate =
    289         OpenSSLCertificate::Generate(key_pair, common_name);
    290     if (certificate)
    291       return new OpenSSLIdentity(key_pair, certificate);
    292     delete key_pair;
    293   }
    294   LOG(LS_INFO) << "Identity generation failed";
    295   return NULL;
    296 }
    297 
    298 SSLIdentity* OpenSSLIdentity::FromPEMStrings(
    299     const std::string& private_key,
    300     const std::string& certificate) {
    301   scoped_ptr<OpenSSLCertificate> cert(
    302       OpenSSLCertificate::FromPEMString(certificate));
    303   if (!cert) {
    304     LOG(LS_ERROR) << "Failed to create OpenSSLCertificate from PEM string.";
    305     return NULL;
    306   }
    307 
    308   BIO* bio = BIO_new_mem_buf(const_cast<char*>(private_key.c_str()), -1);
    309   if (!bio) {
    310     LOG(LS_ERROR) << "Failed to create a new BIO buffer.";
    311     return NULL;
    312   }
    313   (void)BIO_set_close(bio, BIO_NOCLOSE);
    314   BIO_set_mem_eof_return(bio, 0);
    315   EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL,
    316                                            const_cast<char*>("\0"));
    317   BIO_free(bio);
    318 
    319   if (!pkey) {
    320     LOG(LS_ERROR) << "Failed to create the private key from PEM string.";
    321     return NULL;
    322   }
    323 
    324   return new OpenSSLIdentity(new OpenSSLKeyPair(pkey),
    325                              cert.release());
    326 }
    327 
    328 bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
    329   // 1 is the documented success return code.
    330   if (SSL_CTX_use_certificate(ctx, certificate_->x509()) != 1 ||
    331      SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
    332     LogSSLErrors("Configuring key and certificate");
    333     return false;
    334   }
    335   return true;
    336 }
    337 
    338 }  // namespace talk_base
    339 
    340 #endif  // HAVE_OPENSSL_SSL_H
    341 
    342 
    343