• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
41 namespace 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.
47 static const int KEY_LENGTH = 1024;
48 
49 // Random bits for certificate serial number
50 static const int SERIAL_RAND_BITS = 64;
51 
52 // Certificate validity lifetime
53 static 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.
MakeKey()56 static 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.
MakeCertificate(EVP_PKEY * pkey,const char * common_name)89 static 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.
LogSSLErrors(const std::string & prefix)147 static 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 
Generate()156 OpenSSLKeyPair* 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 
~OpenSSLKeyPair()165 OpenSSLKeyPair::~OpenSSLKeyPair() {
166   EVP_PKEY_free(pkey_);
167 }
168 
AddReference()169 void 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.
PrintCert(X509 * x509)175 static 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 
Generate(OpenSSLKeyPair * key_pair,const std::string & common_name)190 OpenSSLCertificate* 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 
FromPEMString(const std::string & pem_string,int * pem_length)207 OpenSSLCertificate* 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 
~OpenSSLCertificate()227 OpenSSLCertificate::~OpenSSLCertificate() {
228   X509_free(x509_);
229 }
230 
ToPEMString() const231 std::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 
AddReference()247 void OpenSSLCertificate::AddReference() {
248   CRYPTO_add(&x509_->references, 1, CRYPTO_LOCK_X509);
249 }
250 
Generate(const std::string & common_name)251 OpenSSLIdentity* 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 
ConfigureIdentity(SSL_CTX * ctx)264 bool 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