diff --git a/rtc_base/sslidentity.cc b/rtc_base/sslidentity.cc index e15fde6bf2..41eb35d5f5 100644 --- a/rtc_base/sslidentity.cc +++ b/rtc_base/sslidentity.cc @@ -24,6 +24,82 @@ namespace rtc { +////////////////////////////////////////////////////////////////////// +// Helper Functions +////////////////////////////////////////////////////////////////////// + +namespace { +// Read |n| bytes from ASN1 number string at *|pp| and return the numeric value. +// Update *|pp| and *|np| to reflect number of read bytes. +// TODO(bugs.webrtc.org/9860) - Remove this code. +inline int ASN1ReadInt(const unsigned char** pp, size_t* np, size_t n) { + const unsigned char* p = *pp; + int x = 0; + for (size_t i = 0; i < n; i++) { + x = 10 * x + p[i] - '0'; + } + *pp = p + n; + *np = *np - n; + return x; +} + +} // namespace + +// TODO(bugs.webrtc.org/9860) - Remove this code. +int64_t ASN1TimeToSec(const unsigned char* s, size_t length, bool long_format) { + size_t bytes_left = length; + // Make sure the string ends with Z. Doing it here protects the strspn call + // from running off the end of the string in Z's absense. + if (length == 0 || s[length - 1] != 'Z') { + return -1; + } + // Make sure we only have ASCII digits so that we don't need to clutter the + // code below and ASN1ReadInt with error checking. + size_t n = strspn(reinterpret_cast(s), "0123456789"); + if (n + 1 != length) { + return -1; + } + // Read out ASN1 year, in either 2-char "UTCTIME" or 4-char "GENERALIZEDTIME" + // format. Both format use UTC in this context. + int year = 0; + if (long_format) { + // ASN1 format: yyyymmddhh[mm[ss[.fff]]]Z where the Z is literal, but + // RFC 5280 requires us to only support exactly yyyymmddhhmmssZ. + if (bytes_left < 11) { + return -1; + } + year = ASN1ReadInt(&s, &bytes_left, 4); + year -= 1900; + } else { + // ASN1 format: yymmddhhmm[ss]Z where the Z is literal, but RFC 5280 + // requires us to only support exactly yymmddhhmmssZ. + if (bytes_left < 9) { + return -1; + } + year = ASN1ReadInt(&s, &bytes_left, 2); + // Per RFC 5280 4.1.2.5.1 + if (year < 50) { + year += 100; + } + } + + // Read out remaining ASN1 time data and store it in |tm| in documented + // std::tm format. + tm tm; + tm.tm_year = year; + tm.tm_mon = ASN1ReadInt(&s, &bytes_left, 2) - 1; + tm.tm_mday = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_hour = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_min = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_sec = ASN1ReadInt(&s, &bytes_left, 2); + + // Now just Z should remain. Its existence was asserted above. + if (bytes_left != 1) { + return -1; + } + return TmToSeconds(tm); +} + ////////////////////////////////////////////////////////////////////// // KeyParams ////////////////////////////////////////////////////////////////////// @@ -92,22 +168,21 @@ KeyType IntKeyTypeFamilyToKeyType(int key_type_family) { bool SSLIdentity::PemToDer(const std::string& pem_type, const std::string& pem_string, std::string* der) { - // Find the inner body. We need this to fulfill the contract of - // returning pem_length. + // Find the inner body. We need this to fulfill the contract of returning + // pem_length. size_t header = pem_string.find("-----BEGIN " + pem_type + "-----"); - if (header == std::string::npos) + if (header == std::string::npos) { return false; - + } size_t body = pem_string.find("\n", header); - if (body == std::string::npos) + if (body == std::string::npos) { return false; - + } size_t trailer = pem_string.find("-----END " + pem_type + "-----"); - if (trailer == std::string::npos) + if (trailer == std::string::npos) { return false; - + } std::string inner = pem_string.substr(body + 1, trailer - (body + 1)); - *der = Base64::Decode(inner, Base64::DO_PARSE_WHITE | Base64::DO_PAD_ANY | Base64::DO_TERM_BUFFER); return true; @@ -117,14 +192,12 @@ std::string SSLIdentity::DerToPem(const std::string& pem_type, const unsigned char* data, size_t length) { rtc::StringBuilder result; - result << "-----BEGIN " << pem_type << "-----\n"; std::string b64_encoded; Base64::EncodeFromArray(data, length, &b64_encoded); - - // Divide the Base-64 encoded data into 64-character chunks, as per - // 4.3.2.4 of RFC 1421. + // Divide the Base-64 encoded data into 64-character chunks, as per 4.3.2.4 + // of RFC 1421. static const size_t kChunkSize = 64; size_t chunks = (b64_encoded.size() + (kChunkSize - 1)) / kChunkSize; for (size_t i = 0, chunk_offset = 0; i < chunks; @@ -132,9 +205,7 @@ std::string SSLIdentity::DerToPem(const std::string& pem_type, result << b64_encoded.substr(chunk_offset, kChunkSize); result << "\n"; } - result << "-----END " << pem_type << "-----\n"; - return result.Release(); } @@ -185,78 +256,4 @@ bool operator!=(const SSLIdentity& a, const SSLIdentity& b) { return !(a == b); } -////////////////////////////////////////////////////////////////////// -// Helper Functions -////////////////////////////////////////////////////////////////////// - -// Read |n| bytes from ASN1 number string at *|pp| and return the numeric value. -// Update *|pp| and *|np| to reflect number of read bytes. -static inline int ASN1ReadInt(const unsigned char** pp, size_t* np, size_t n) { - const unsigned char* p = *pp; - int x = 0; - for (size_t i = 0; i < n; i++) - x = 10 * x + p[i] - '0'; - *pp = p + n; - *np = *np - n; - return x; -} - -int64_t ASN1TimeToSec(const unsigned char* s, size_t length, bool long_format) { - size_t bytes_left = length; - - // Make sure the string ends with Z. Doing it here protects the strspn call - // from running off the end of the string in Z's absense. - if (length == 0 || s[length - 1] != 'Z') - return -1; - - // Make sure we only have ASCII digits so that we don't need to clutter the - // code below and ASN1ReadInt with error checking. - size_t n = strspn(reinterpret_cast(s), "0123456789"); - if (n + 1 != length) - return -1; - - int year; - - // Read out ASN1 year, in either 2-char "UTCTIME" or 4-char "GENERALIZEDTIME" - // format. Both format use UTC in this context. - if (long_format) { - // ASN1 format: yyyymmddhh[mm[ss[.fff]]]Z where the Z is literal, but - // RFC 5280 requires us to only support exactly yyyymmddhhmmssZ. - - if (bytes_left < 11) - return -1; - - year = ASN1ReadInt(&s, &bytes_left, 4); - year -= 1900; - } else { - // ASN1 format: yymmddhhmm[ss]Z where the Z is literal, but RFC 5280 - // requires us to only support exactly yymmddhhmmssZ. - - if (bytes_left < 9) - return -1; - - year = ASN1ReadInt(&s, &bytes_left, 2); - if (year < 50) // Per RFC 5280 4.1.2.5.1 - year += 100; - } - - tm tm; - tm.tm_year = year; - - // Read out remaining ASN1 time data and store it in |tm| in documented - // std::tm format. - tm.tm_mon = ASN1ReadInt(&s, &bytes_left, 2) - 1; - tm.tm_mday = ASN1ReadInt(&s, &bytes_left, 2); - tm.tm_hour = ASN1ReadInt(&s, &bytes_left, 2); - tm.tm_min = ASN1ReadInt(&s, &bytes_left, 2); - tm.tm_sec = ASN1ReadInt(&s, &bytes_left, 2); - - if (bytes_left != 1) { - // Now just Z should remain. Its existence was asserted above. - return -1; - } - - return TmToSeconds(tm); -} - } // namespace rtc