Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/quic/crypto/crypto_utils.h"
      6 
      7 #include "crypto/hkdf.h"
      8 #include "net/base/net_util.h"
      9 #include "net/quic/crypto/crypto_handshake.h"
     10 #include "net/quic/crypto/crypto_protocol.h"
     11 #include "net/quic/crypto/quic_decrypter.h"
     12 #include "net/quic/crypto/quic_encrypter.h"
     13 #include "net/quic/crypto/quic_random.h"
     14 #include "net/quic/quic_time.h"
     15 #include "url/url_canon.h"
     16 
     17 using base::StringPiece;
     18 using std::numeric_limits;
     19 using std::string;
     20 
     21 namespace net {
     22 
     23 // static
     24 void CryptoUtils::GenerateNonce(QuicWallTime now,
     25                                 QuicRandom* random_generator,
     26                                 StringPiece orbit,
     27                                 string* nonce) {
     28   // a 4-byte timestamp + 28 random bytes.
     29   nonce->reserve(kNonceSize);
     30   nonce->resize(kNonceSize);
     31   uint32 gmt_unix_time = now.ToUNIXSeconds();
     32   // The time in the nonce must be encoded in big-endian because the
     33   // strike-register depends on the nonces being ordered by time.
     34   (*nonce)[0] = static_cast<char>(gmt_unix_time >> 24);
     35   (*nonce)[1] = static_cast<char>(gmt_unix_time >> 16);
     36   (*nonce)[2] = static_cast<char>(gmt_unix_time >> 8);
     37   (*nonce)[3] = static_cast<char>(gmt_unix_time);
     38 
     39   size_t bytes_written = sizeof(gmt_unix_time);
     40   if (orbit.size() == 8) {
     41     memcpy(&(*nonce)[bytes_written], orbit.data(), orbit.size());
     42     bytes_written += orbit.size();
     43   }
     44   random_generator->RandBytes(&(*nonce)[bytes_written],
     45                               kNonceSize - bytes_written);
     46 }
     47 
     48 // static
     49 bool CryptoUtils::IsValidSNI(StringPiece sni) {
     50   // TODO(rtenneti): Support RFC2396 hostname.
     51   // NOTE: Microsoft does NOT enforce this spec, so if we throw away hostnames
     52   // based on the above spec, we may be losing some hostnames that windows
     53   // would consider valid. By far the most common hostname character NOT
     54   // accepted by the above spec is '_'.
     55   url::CanonHostInfo host_info;
     56   string canonicalized_host(CanonicalizeHost(sni.as_string(), &host_info));
     57   return !host_info.IsIPAddress() &&
     58       IsCanonicalizedHostCompliant(canonicalized_host, std::string()) &&
     59       sni.find_last_of('.') != string::npos;
     60 }
     61 
     62 // static
     63 string CryptoUtils::NormalizeHostname(const char* hostname) {
     64   url::CanonHostInfo host_info;
     65   string host(CanonicalizeHost(hostname, &host_info));
     66 
     67   // Walk backwards over the string, stopping at the first trailing dot.
     68   size_t host_end = host.length();
     69   while (host_end != 0 && host[host_end - 1] == '.') {
     70     host_end--;
     71   }
     72 
     73   // Erase the trailing dots.
     74   if (host_end != host.length()) {
     75     host.erase(host_end, host.length() - host_end);
     76   }
     77   return host;
     78 }
     79 
     80 // static
     81 bool CryptoUtils::DeriveKeys(StringPiece premaster_secret,
     82                              QuicTag aead,
     83                              StringPiece client_nonce,
     84                              StringPiece server_nonce,
     85                              const string& hkdf_input,
     86                              Perspective perspective,
     87                              CrypterPair* crypters,
     88                              string* subkey_secret) {
     89   crypters->encrypter.reset(QuicEncrypter::Create(aead));
     90   crypters->decrypter.reset(QuicDecrypter::Create(aead));
     91   size_t key_bytes = crypters->encrypter->GetKeySize();
     92   size_t nonce_prefix_bytes = crypters->encrypter->GetNoncePrefixSize();
     93   size_t subkey_secret_bytes =
     94       subkey_secret == NULL ? 0 : premaster_secret.length();
     95 
     96   StringPiece nonce = client_nonce;
     97   string nonce_storage;
     98   if (!server_nonce.empty()) {
     99     nonce_storage = client_nonce.as_string() + server_nonce.as_string();
    100     nonce = nonce_storage;
    101   }
    102 
    103   crypto::HKDF hkdf(premaster_secret, nonce, hkdf_input, key_bytes,
    104                     nonce_prefix_bytes, subkey_secret_bytes);
    105   if (perspective == SERVER) {
    106     if (!crypters->encrypter->SetKey(hkdf.server_write_key()) ||
    107         !crypters->encrypter->SetNoncePrefix(hkdf.server_write_iv()) ||
    108         !crypters->decrypter->SetKey(hkdf.client_write_key()) ||
    109         !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv())) {
    110       return false;
    111     }
    112   } else {
    113     if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
    114         !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
    115         !crypters->decrypter->SetKey(hkdf.server_write_key()) ||
    116         !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) {
    117       return false;
    118     }
    119   }
    120   if (subkey_secret != NULL) {
    121     hkdf.subkey_secret().CopyToString(subkey_secret);
    122   }
    123 
    124   return true;
    125 }
    126 
    127 // static
    128 bool CryptoUtils::ExportKeyingMaterial(StringPiece subkey_secret,
    129                                        StringPiece label,
    130                                        StringPiece context,
    131                                        size_t result_len,
    132                                        string* result) {
    133   for (size_t i = 0; i < label.length(); i++) {
    134     if (label[i] == '\0') {
    135       LOG(ERROR) << "ExportKeyingMaterial label may not contain NULs";
    136       return false;
    137     }
    138   }
    139   // Create HKDF info input: null-terminated label + length-prefixed context
    140   if (context.length() >= numeric_limits<uint32>::max()) {
    141     LOG(ERROR) << "Context value longer than 2^32";
    142     return false;
    143   }
    144   uint32 context_length = static_cast<uint32>(context.length());
    145   string info = label.as_string();
    146   info.push_back('\0');
    147   info.append(reinterpret_cast<char*>(&context_length), sizeof(context_length));
    148   info.append(context.data(), context.length());
    149 
    150   crypto::HKDF hkdf(subkey_secret,
    151                     StringPiece() /* no salt */,
    152                     info,
    153                     result_len,
    154                     0 /* no fixed IV */,
    155                     0 /* no subkey secret */);
    156   hkdf.client_write_key().CopyToString(result);
    157   return true;
    158 }
    159 
    160 }  // namespace net
    161