1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 // Handling of certificates and keypairs for SSLStreamAdapter's peer mode.
12 #if HAVE_CONFIG_H
13 #include "config.h"
14 #endif  // HAVE_CONFIG_H
15 
16 #include "webrtc/base/sslidentity.h"
17 
18 #include <ctime>
19 #include <string>
20 
21 #include "webrtc/base/base64.h"
22 #include "webrtc/base/checks.h"
23 #include "webrtc/base/logging.h"
24 #include "webrtc/base/sslconfig.h"
25 
26 #if SSL_USE_OPENSSL
27 
28 #include "webrtc/base/opensslidentity.h"
29 
30 #endif  // SSL_USE_OPENSSL
31 
32 namespace rtc {
33 
34 const char kPemTypeCertificate[] = "CERTIFICATE";
35 const char kPemTypeRsaPrivateKey[] = "RSA PRIVATE KEY";
36 const char kPemTypeEcPrivateKey[] = "EC PRIVATE KEY";
37 
KeyParams(KeyType key_type)38 KeyParams::KeyParams(KeyType key_type) {
39   if (key_type == KT_ECDSA) {
40     type_ = KT_ECDSA;
41     params_.curve = EC_NIST_P256;
42   } else if (key_type == KT_RSA) {
43     type_ = KT_RSA;
44     params_.rsa.mod_size = kRsaDefaultModSize;
45     params_.rsa.pub_exp = kRsaDefaultExponent;
46   } else {
47     RTC_NOTREACHED();
48   }
49 }
50 
51 // static
RSA(int mod_size,int pub_exp)52 KeyParams KeyParams::RSA(int mod_size, int pub_exp) {
53   KeyParams kt(KT_RSA);
54   kt.params_.rsa.mod_size = mod_size;
55   kt.params_.rsa.pub_exp = pub_exp;
56   return kt;
57 }
58 
59 // static
ECDSA(ECCurve curve)60 KeyParams KeyParams::ECDSA(ECCurve curve) {
61   KeyParams kt(KT_ECDSA);
62   kt.params_.curve = curve;
63   return kt;
64 }
65 
IsValid() const66 bool KeyParams::IsValid() const {
67   if (type_ == KT_RSA) {
68     return (params_.rsa.mod_size >= kRsaMinModSize &&
69             params_.rsa.mod_size <= kRsaMaxModSize &&
70             params_.rsa.pub_exp > params_.rsa.mod_size);
71   } else if (type_ == KT_ECDSA) {
72     return (params_.curve == EC_NIST_P256);
73   }
74   return false;
75 }
76 
rsa_params() const77 RSAParams KeyParams::rsa_params() const {
78   RTC_DCHECK(type_ == KT_RSA);
79   return params_.rsa;
80 }
81 
ec_curve() const82 ECCurve KeyParams::ec_curve() const {
83   RTC_DCHECK(type_ == KT_ECDSA);
84   return params_.curve;
85 }
86 
IntKeyTypeFamilyToKeyType(int key_type_family)87 KeyType IntKeyTypeFamilyToKeyType(int key_type_family) {
88   return static_cast<KeyType>(key_type_family);
89 }
90 
PemToDer(const std::string & pem_type,const std::string & pem_string,std::string * der)91 bool SSLIdentity::PemToDer(const std::string& pem_type,
92                            const std::string& pem_string,
93                            std::string* der) {
94   // Find the inner body. We need this to fulfill the contract of
95   // returning pem_length.
96   size_t header = pem_string.find("-----BEGIN " + pem_type + "-----");
97   if (header == std::string::npos)
98     return false;
99 
100   size_t body = pem_string.find("\n", header);
101   if (body == std::string::npos)
102     return false;
103 
104   size_t trailer = pem_string.find("-----END " + pem_type + "-----");
105   if (trailer == std::string::npos)
106     return false;
107 
108   std::string inner = pem_string.substr(body + 1, trailer - (body + 1));
109 
110   *der = Base64::Decode(inner, Base64::DO_PARSE_WHITE |
111                         Base64::DO_PAD_ANY |
112                         Base64::DO_TERM_BUFFER);
113   return true;
114 }
115 
DerToPem(const std::string & pem_type,const unsigned char * data,size_t length)116 std::string SSLIdentity::DerToPem(const std::string& pem_type,
117                                   const unsigned char* data,
118                                   size_t length) {
119   std::stringstream result;
120 
121   result << "-----BEGIN " << pem_type << "-----\n";
122 
123   std::string b64_encoded;
124   Base64::EncodeFromArray(data, length, &b64_encoded);
125 
126   // Divide the Base-64 encoded data into 64-character chunks, as per
127   // 4.3.2.4 of RFC 1421.
128   static const size_t kChunkSize = 64;
129   size_t chunks = (b64_encoded.size() + (kChunkSize - 1)) / kChunkSize;
130   for (size_t i = 0, chunk_offset = 0; i < chunks;
131        ++i, chunk_offset += kChunkSize) {
132     result << b64_encoded.substr(chunk_offset, kChunkSize);
133     result << "\n";
134   }
135 
136   result << "-----END " << pem_type << "-----\n";
137 
138   return result.str();
139 }
140 
SSLCertChain(const std::vector<SSLCertificate * > & certs)141 SSLCertChain::SSLCertChain(const std::vector<SSLCertificate*>& certs) {
142   ASSERT(!certs.empty());
143   certs_.resize(certs.size());
144   std::transform(certs.begin(), certs.end(), certs_.begin(), DupCert);
145 }
146 
SSLCertChain(const SSLCertificate * cert)147 SSLCertChain::SSLCertChain(const SSLCertificate* cert) {
148   certs_.push_back(cert->GetReference());
149 }
150 
~SSLCertChain()151 SSLCertChain::~SSLCertChain() {
152   std::for_each(certs_.begin(), certs_.end(), DeleteCert);
153 }
154 
155 #if SSL_USE_OPENSSL
156 
FromPEMString(const std::string & pem_string)157 SSLCertificate* SSLCertificate::FromPEMString(const std::string& pem_string) {
158   return OpenSSLCertificate::FromPEMString(pem_string);
159 }
160 
Generate(const std::string & common_name,const KeyParams & key_params)161 SSLIdentity* SSLIdentity::Generate(const std::string& common_name,
162                                    const KeyParams& key_params) {
163   return OpenSSLIdentity::Generate(common_name, key_params);
164 }
165 
GenerateForTest(const SSLIdentityParams & params)166 SSLIdentity* SSLIdentity::GenerateForTest(const SSLIdentityParams& params) {
167   return OpenSSLIdentity::GenerateForTest(params);
168 }
169 
FromPEMStrings(const std::string & private_key,const std::string & certificate)170 SSLIdentity* SSLIdentity::FromPEMStrings(const std::string& private_key,
171                                          const std::string& certificate) {
172   return OpenSSLIdentity::FromPEMStrings(private_key, certificate);
173 }
174 
175 #else  // !SSL_USE_OPENSSL
176 
177 #error "No SSL implementation"
178 
179 #endif  // SSL_USE_OPENSSL
180 
181 // Read |n| bytes from ASN1 number string at *|pp| and return the numeric value.
182 // Update *|pp| and *|np| to reflect number of read bytes.
ASN1ReadInt(const unsigned char ** pp,size_t * np,size_t n)183 static inline int ASN1ReadInt(const unsigned char** pp, size_t* np, size_t n) {
184   const unsigned char* p = *pp;
185   int x = 0;
186   for (size_t i = 0; i < n; i++)
187     x = 10 * x + p[i] - '0';
188   *pp = p + n;
189   *np = *np - n;
190   return x;
191 }
192 
ASN1TimeToSec(const unsigned char * s,size_t length,bool long_format)193 int64_t ASN1TimeToSec(const unsigned char* s, size_t length, bool long_format) {
194   size_t bytes_left = length;
195 
196   // Make sure the string ends with Z.  Doing it here protects the strspn call
197   // from running off the end of the string in Z's absense.
198   if (length == 0 || s[length - 1] != 'Z')
199     return -1;
200 
201   // Make sure we only have ASCII digits so that we don't need to clutter the
202   // code below and ASN1ReadInt with error checking.
203   size_t n = strspn(reinterpret_cast<const char*>(s), "0123456789");
204   if (n + 1 != length)
205     return -1;
206 
207   int year;
208 
209   // Read out ASN1 year, in either 2-char "UTCTIME" or 4-char "GENERALIZEDTIME"
210   // format.  Both format use UTC in this context.
211   if (long_format) {
212     // ASN1 format: yyyymmddhh[mm[ss[.fff]]]Z where the Z is literal, but
213     // RFC 5280 requires us to only support exactly yyyymmddhhmmssZ.
214 
215     if (bytes_left < 11)
216       return -1;
217 
218     year = ASN1ReadInt(&s, &bytes_left, 4);
219     year -= 1900;
220   } else {
221     // ASN1 format: yymmddhhmm[ss]Z where the Z is literal, but RFC 5280
222     // requires us to only support exactly yymmddhhmmssZ.
223 
224     if (bytes_left < 9)
225       return -1;
226 
227     year = ASN1ReadInt(&s, &bytes_left, 2);
228     if (year < 50)  // Per RFC 5280 4.1.2.5.1
229       year += 100;
230   }
231 
232   std::tm tm;
233   tm.tm_year = year;
234 
235   // Read out remaining ASN1 time data and store it in |tm| in documented
236   // std::tm format.
237   tm.tm_mon = ASN1ReadInt(&s, &bytes_left, 2) - 1;
238   tm.tm_mday = ASN1ReadInt(&s, &bytes_left, 2);
239   tm.tm_hour = ASN1ReadInt(&s, &bytes_left, 2);
240   tm.tm_min = ASN1ReadInt(&s, &bytes_left, 2);
241   tm.tm_sec = ASN1ReadInt(&s, &bytes_left, 2);
242 
243   if (bytes_left != 1) {
244     // Now just Z should remain.  Its existence was asserted above.
245     return -1;
246   }
247 
248   return TmToSeconds(tm);
249 }
250 
251 }  // namespace rtc
252