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/aes_128_gcm_12_decrypter.h"
      6 
      7 #include <pk11pub.h>
      8 #include <secerr.h>
      9 
     10 #include "base/lazy_instance.h"
     11 #include "crypto/ghash.h"
     12 #include "crypto/scoped_nss_types.h"
     13 
     14 #if defined(USE_NSS)
     15 #include <dlfcn.h>
     16 #endif
     17 
     18 using base::StringPiece;
     19 
     20 namespace net {
     21 
     22 namespace {
     23 
     24 const size_t kKeySize = 16;
     25 const size_t kNoncePrefixSize = 4;
     26 
     27 // On Linux, dynamically link against the system version of libnss3.so. In
     28 // order to continue working on systems without up-to-date versions of NSS,
     29 // lookup PK11_Decrypt with dlsym.
     30 
     31 // GcmSupportChecker is a singleton which caches the results of runtime symbol
     32 // resolution of PK11_Decrypt.
     33 class GcmSupportChecker {
     34  public:
     35   static PK11_DecryptFunction pk11_decrypt_func() {
     36     return pk11_decrypt_func_;
     37   }
     38 
     39  private:
     40   friend struct base::DefaultLazyInstanceTraits<GcmSupportChecker>;
     41 
     42   GcmSupportChecker() {
     43 #if !defined(USE_NSS)
     44     // Using a bundled version of NSS that is guaranteed to have this symbol.
     45     pk11_decrypt_func_ = PK11_Decrypt;
     46 #else
     47     // Using system NSS libraries and PCKS #11 modules, which may not have the
     48     // necessary function (PK11_Decrypt) or mechanism support (CKM_AES_GCM).
     49 
     50     // If PK11_Decrypt() was successfully resolved, then NSS will support
     51     // AES-GCM directly. This was introduced in NSS 3.15.
     52     pk11_decrypt_func_ = (PK11_DecryptFunction)dlsym(RTLD_DEFAULT,
     53                                                      "PK11_Decrypt");
     54 #endif
     55   }
     56 
     57   // |pk11_decrypt_func_| stores the runtime symbol resolution of PK11_Decrypt.
     58   static PK11_DecryptFunction pk11_decrypt_func_;
     59 };
     60 
     61 // static
     62 PK11_DecryptFunction GcmSupportChecker::pk11_decrypt_func_ = NULL;
     63 
     64 base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker =
     65     LAZY_INSTANCE_INITIALIZER;
     66 
     67 // Calls PK11_Decrypt if it's available.  Otherwise, emulates CKM_AES_GCM using
     68 // CKM_AES_CTR and the GaloisHash class.
     69 SECStatus My_Decrypt(PK11SymKey* key,
     70                      CK_MECHANISM_TYPE mechanism,
     71                      SECItem* param,
     72                      unsigned char* out,
     73                      unsigned int* out_len,
     74                      unsigned int max_len,
     75                      const unsigned char* enc,
     76                      unsigned int enc_len) {
     77   // If PK11_Decrypt() was successfully resolved or if bundled version of NSS is
     78   // being used, then NSS will support AES-GCM directly.
     79   PK11_DecryptFunction pk11_decrypt_func =
     80       GcmSupportChecker::pk11_decrypt_func();
     81   if (pk11_decrypt_func != NULL) {
     82     return pk11_decrypt_func(key, mechanism, param, out, out_len, max_len, enc,
     83                              enc_len);
     84   }
     85 
     86   // Otherwise, the user has an older version of NSS. Regrettably, NSS 3.14.x
     87   // has a bug in the AES GCM code
     88   // (https://bugzilla.mozilla.org/show_bug.cgi?id=853285), as well as missing
     89   // the PK11_Decrypt function
     90   // (https://bugzilla.mozilla.org/show_bug.cgi?id=854063), both of which are
     91   // resolved in NSS 3.15.
     92 
     93   DCHECK_EQ(mechanism, static_cast<CK_MECHANISM_TYPE>(CKM_AES_GCM));
     94   DCHECK_EQ(param->len, sizeof(CK_GCM_PARAMS));
     95 
     96   const CK_GCM_PARAMS* gcm_params =
     97       reinterpret_cast<CK_GCM_PARAMS*>(param->data);
     98 
     99   DCHECK_EQ(gcm_params->ulTagBits,
    100             static_cast<CK_ULONG>(Aes128Gcm12Decrypter::kAuthTagSize * 8));
    101   if (gcm_params->ulIvLen != 12u) {
    102     DVLOG(1) << "ulIvLen is not equal to 12";
    103     PORT_SetError(SEC_ERROR_INPUT_LEN);
    104     return SECFailure;
    105   }
    106 
    107   SECItem my_param = { siBuffer, NULL, 0 };
    108 
    109   // Step 2. Let H = CIPH_K(128 '0' bits).
    110   unsigned char ghash_key[16] = {0};
    111   crypto::ScopedPK11Context ctx(PK11_CreateContextBySymKey(
    112       CKM_AES_ECB, CKA_ENCRYPT, key, &my_param));
    113   if (!ctx) {
    114     DVLOG(1) << "PK11_CreateContextBySymKey failed";
    115     return SECFailure;
    116   }
    117   int output_len;
    118   if (PK11_CipherOp(ctx.get(), ghash_key, &output_len, sizeof(ghash_key),
    119                     ghash_key, sizeof(ghash_key)) != SECSuccess) {
    120     DVLOG(1) << "PK11_CipherOp failed";
    121     return SECFailure;
    122   }
    123 
    124   PK11_Finalize(ctx.get());
    125 
    126   if (output_len != sizeof(ghash_key)) {
    127     DVLOG(1) << "Wrong output length";
    128     PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    129     return SECFailure;
    130   }
    131 
    132   // Step 3. If len(IV)=96, then let J0 = IV || 31 '0' bits || 1.
    133   CK_AES_CTR_PARAMS ctr_params = {0};
    134   ctr_params.ulCounterBits = 32;
    135   memcpy(ctr_params.cb, gcm_params->pIv, gcm_params->ulIvLen);
    136   ctr_params.cb[12] = 0;
    137   ctr_params.cb[13] = 0;
    138   ctr_params.cb[14] = 0;
    139   ctr_params.cb[15] = 1;
    140 
    141   my_param.type = siBuffer;
    142   my_param.data = reinterpret_cast<unsigned char*>(&ctr_params);
    143   my_param.len = sizeof(ctr_params);
    144 
    145   ctx.reset(PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, key,
    146                                        &my_param));
    147   if (!ctx) {
    148     DVLOG(1) << "PK11_CreateContextBySymKey failed";
    149     return SECFailure;
    150   }
    151 
    152   // Step 6. Calculate the encryption mask of GCTR_K(J0, ...).
    153   unsigned char tag_mask[16] = {0};
    154   if (PK11_CipherOp(ctx.get(), tag_mask, &output_len, sizeof(tag_mask),
    155                     tag_mask, sizeof(tag_mask)) != SECSuccess) {
    156     DVLOG(1) << "PK11_CipherOp failed";
    157     return SECFailure;
    158   }
    159   if (output_len != sizeof(tag_mask)) {
    160     DVLOG(1) << "Wrong output length";
    161     PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    162     return SECFailure;
    163   }
    164 
    165   if (enc_len < Aes128Gcm12Decrypter::kAuthTagSize) {
    166     PORT_SetError(SEC_ERROR_INPUT_LEN);
    167     return SECFailure;
    168   }
    169 
    170   // The const_cast for |enc| can be removed if system NSS libraries are
    171   // NSS 3.14.1 or later (NSS bug
    172   // https://bugzilla.mozilla.org/show_bug.cgi?id=808218).
    173   if (PK11_CipherOp(ctx.get(), out, &output_len, max_len,
    174           const_cast<unsigned char*>(enc),
    175           enc_len - Aes128Gcm12Decrypter::kAuthTagSize) != SECSuccess) {
    176     DVLOG(1) << "PK11_CipherOp failed";
    177     return SECFailure;
    178   }
    179 
    180   PK11_Finalize(ctx.get());
    181 
    182   if (static_cast<unsigned int>(output_len) !=
    183       enc_len - Aes128Gcm12Decrypter::kAuthTagSize) {
    184     DVLOG(1) << "Wrong output length";
    185     PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    186     return SECFailure;
    187   }
    188 
    189   crypto::GaloisHash ghash(ghash_key);
    190   ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen);
    191   ghash.UpdateCiphertext(enc, output_len);
    192   unsigned char auth_tag[Aes128Gcm12Decrypter::kAuthTagSize];
    193   ghash.Finish(auth_tag, Aes128Gcm12Decrypter::kAuthTagSize);
    194   for (unsigned int i = 0; i < Aes128Gcm12Decrypter::kAuthTagSize; i++) {
    195     auth_tag[i] ^= tag_mask[i];
    196   }
    197 
    198   if (NSS_SecureMemcmp(auth_tag, enc + output_len,
    199                        Aes128Gcm12Decrypter::kAuthTagSize) != 0) {
    200     PORT_SetError(SEC_ERROR_BAD_DATA);
    201     return SECFailure;
    202   }
    203 
    204   *out_len = output_len;
    205   return SECSuccess;
    206 }
    207 
    208 }  // namespace
    209 
    210 Aes128Gcm12Decrypter::Aes128Gcm12Decrypter()
    211     : AeadBaseDecrypter(CKM_AES_GCM, My_Decrypt, kKeySize, kAuthTagSize,
    212                         kNoncePrefixSize) {
    213   COMPILE_ASSERT(kKeySize <= kMaxKeySize, key_size_too_big);
    214   COMPILE_ASSERT(kNoncePrefixSize <= kMaxNoncePrefixSize,
    215                  nonce_prefix_size_too_big);
    216   ignore_result(g_gcm_support_checker.Get());
    217 }
    218 
    219 Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {}
    220 
    221 void Aes128Gcm12Decrypter::FillAeadParams(StringPiece nonce,
    222                                           StringPiece associated_data,
    223                                           size_t auth_tag_size,
    224                                           AeadParams* aead_params) const {
    225   aead_params->len = sizeof(aead_params->data.gcm_params);
    226   CK_GCM_PARAMS* gcm_params = &aead_params->data.gcm_params;
    227   gcm_params->pIv =
    228       reinterpret_cast<CK_BYTE*>(const_cast<char*>(nonce.data()));
    229   gcm_params->ulIvLen = nonce.size();
    230   gcm_params->pAAD =
    231       reinterpret_cast<CK_BYTE*>(const_cast<char*>(associated_data.data()));
    232   gcm_params->ulAADLen = associated_data.size();
    233   gcm_params->ulTagBits = auth_tag_size * 8;
    234 }
    235 
    236 }  // namespace net
    237