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/aead_base_decrypter.h"
      6 
      7 #include <pk11pub.h>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "crypto/scoped_nss_types.h"
     11 
     12 using base::StringPiece;
     13 
     14 namespace net {
     15 
     16 AeadBaseDecrypter::AeadBaseDecrypter(CK_MECHANISM_TYPE aead_mechanism,
     17                                      PK11_DecryptFunction pk11_decrypt,
     18                                      size_t key_size,
     19                                      size_t auth_tag_size,
     20                                      size_t nonce_prefix_size)
     21     : aead_mechanism_(aead_mechanism),
     22       pk11_decrypt_(pk11_decrypt),
     23       key_size_(key_size),
     24       auth_tag_size_(auth_tag_size),
     25       nonce_prefix_size_(nonce_prefix_size) {
     26   DCHECK_LE(key_size_, sizeof(key_));
     27   DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_));
     28 }
     29 
     30 AeadBaseDecrypter::~AeadBaseDecrypter() {}
     31 
     32 bool AeadBaseDecrypter::SetKey(StringPiece key) {
     33   DCHECK_EQ(key.size(), key_size_);
     34   if (key.size() != key_size_) {
     35     return false;
     36   }
     37   memcpy(key_, key.data(), key.size());
     38   return true;
     39 }
     40 
     41 bool AeadBaseDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
     42   DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_);
     43   if (nonce_prefix.size() != nonce_prefix_size_) {
     44     return false;
     45   }
     46   memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
     47   return true;
     48 }
     49 
     50 bool AeadBaseDecrypter::Decrypt(StringPiece nonce,
     51                                 StringPiece associated_data,
     52                                 StringPiece ciphertext,
     53                                 uint8* output,
     54                                 size_t* output_length) {
     55   if (ciphertext.length() < auth_tag_size_ ||
     56       nonce.size() != nonce_prefix_size_ + sizeof(QuicPacketSequenceNumber)) {
     57     return false;
     58   }
     59   // NSS 3.14.x incorrectly requires an output buffer at least as long as
     60   // the ciphertext (NSS bug
     61   // https://bugzilla.mozilla.org/show_bug.cgi?id= 853674). Fortunately
     62   // QuicDecrypter::Decrypt() specifies that |output| must be as long as
     63   // |ciphertext| on entry.
     64   size_t plaintext_size = ciphertext.length() - auth_tag_size_;
     65 
     66   // Import key_ into NSS.
     67   SECItem key_item;
     68   key_item.type = siBuffer;
     69   key_item.data = key_;
     70   key_item.len = key_size_;
     71   PK11SlotInfo* slot = PK11_GetInternalSlot();
     72 
     73   // TODO(wtc): For an AES-GCM key, the correct value for |key_mechanism| is
     74   // CKM_AES_GCM, but because of NSS bug
     75   // https://bugzilla.mozilla.org/show_bug.cgi?id=853285, use CKM_AES_ECB as a
     76   // workaround. Remove this when we require NSS 3.15.
     77   CK_MECHANISM_TYPE key_mechanism = aead_mechanism_;
     78   if (key_mechanism == CKM_AES_GCM) {
     79     key_mechanism = CKM_AES_ECB;
     80   }
     81 
     82   // The exact value of the |origin| argument doesn't matter to NSS as long as
     83   // it's not PK11_OriginFortezzaHack, so pass PK11_OriginUnwrap as a
     84   // placeholder.
     85   crypto::ScopedPK11SymKey aead_key(PK11_ImportSymKey(
     86       slot, key_mechanism, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL));
     87   PK11_FreeSlot(slot);
     88   slot = NULL;
     89   if (!aead_key) {
     90     DVLOG(1) << "PK11_ImportSymKey failed";
     91     return false;
     92   }
     93 
     94   AeadParams aead_params = {0};
     95   FillAeadParams(nonce, associated_data, auth_tag_size_, &aead_params);
     96 
     97   SECItem param;
     98   param.type = siBuffer;
     99   param.data = reinterpret_cast<unsigned char*>(&aead_params.data);
    100   param.len = aead_params.len;
    101 
    102   unsigned int output_len;
    103   if (pk11_decrypt_(aead_key.get(), aead_mechanism_, &param,
    104                     output, &output_len, ciphertext.length(),
    105                     reinterpret_cast<const unsigned char*>(ciphertext.data()),
    106                     ciphertext.length()) != SECSuccess) {
    107     return false;
    108   }
    109 
    110   if (output_len != plaintext_size) {
    111     DVLOG(1) << "Wrong output length";
    112     return false;
    113   }
    114   *output_length = output_len;
    115   return true;
    116 }
    117 
    118 QuicData* AeadBaseDecrypter::DecryptPacket(
    119     QuicPacketSequenceNumber sequence_number,
    120     StringPiece associated_data,
    121     StringPiece ciphertext) {
    122   if (ciphertext.length() < auth_tag_size_) {
    123     return NULL;
    124   }
    125   size_t plaintext_size;
    126   scoped_ptr<char[]> plaintext(new char[ciphertext.length()]);
    127 
    128   uint8 nonce[sizeof(nonce_prefix_) + sizeof(sequence_number)];
    129   const size_t nonce_size = nonce_prefix_size_ + sizeof(sequence_number);
    130   DCHECK_LE(nonce_size, sizeof(nonce));
    131   memcpy(nonce, nonce_prefix_, nonce_prefix_size_);
    132   memcpy(nonce + nonce_prefix_size_, &sequence_number, sizeof(sequence_number));
    133   if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce), nonce_size),
    134                associated_data, ciphertext,
    135                reinterpret_cast<uint8*>(plaintext.get()),
    136                &plaintext_size)) {
    137     return NULL;
    138   }
    139   return new QuicData(plaintext.release(), plaintext_size, true);
    140 }
    141 
    142 StringPiece AeadBaseDecrypter::GetKey() const {
    143   return StringPiece(reinterpret_cast<const char*>(key_), key_size_);
    144 }
    145 
    146 StringPiece AeadBaseDecrypter::GetNoncePrefix() const {
    147   if (nonce_prefix_size_ == 0) {
    148     return StringPiece();
    149   }
    150   return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
    151                      nonce_prefix_size_);
    152 }
    153 
    154 }  // namespace net
    155