Home | History | Annotate | Download | only in base
      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 
     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
     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
     60 KeyParams KeyParams::ECDSA(ECCurve curve) {
     61   KeyParams kt(KT_ECDSA);
     62   kt.params_.curve = curve;
     63   return kt;
     64 }
     65 
     66 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 
     77 RSAParams KeyParams::rsa_params() const {
     78   RTC_DCHECK(type_ == KT_RSA);
     79   return params_.rsa;
     80 }
     81 
     82 ECCurve KeyParams::ec_curve() const {
     83   RTC_DCHECK(type_ == KT_ECDSA);
     84   return params_.curve;
     85 }
     86 
     87 KeyType IntKeyTypeFamilyToKeyType(int key_type_family) {
     88   return static_cast<KeyType>(key_type_family);
     89 }
     90 
     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 
    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 
    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 
    147 SSLCertChain::SSLCertChain(const SSLCertificate* cert) {
    148   certs_.push_back(cert->GetReference());
    149 }
    150 
    151 SSLCertChain::~SSLCertChain() {
    152   std::for_each(certs_.begin(), certs_.end(), DeleteCert);
    153 }
    154 
    155 #if SSL_USE_OPENSSL
    156 
    157 SSLCertificate* SSLCertificate::FromPEMString(const std::string& pem_string) {
    158   return OpenSSLCertificate::FromPEMString(pem_string);
    159 }
    160 
    161 SSLIdentity* SSLIdentity::Generate(const std::string& common_name,
    162                                    const KeyParams& key_params) {
    163   return OpenSSLIdentity::Generate(common_name, key_params);
    164 }
    165 
    166 SSLIdentity* SSLIdentity::GenerateForTest(const SSLIdentityParams& params) {
    167   return OpenSSLIdentity::GenerateForTest(params);
    168 }
    169 
    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.
    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 
    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