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 <nss.h>
8#include <pk11pub.h>
9#include <secerr.h>
10
11#include "base/lazy_instance.h"
12#include "base/memory/scoped_ptr.h"
13#include "crypto/ghash.h"
14#include "crypto/scoped_nss_types.h"
15
16#if defined(USE_NSS)
17#include <dlfcn.h>
18#endif
19
20using base::StringPiece;
21
22namespace net {
23
24namespace {
25
26// The pkcs11t.h header in NSS versions older than 3.14 does not have the CTR
27// and GCM types, so define them here.
28#if !defined(CKM_AES_CTR)
29#define CKM_AES_CTR 0x00001086
30#define CKM_AES_GCM 0x00001087
31
32struct CK_AES_CTR_PARAMS {
33  CK_ULONG ulCounterBits;
34  CK_BYTE cb[16];
35};
36
37struct CK_GCM_PARAMS {
38  CK_BYTE_PTR pIv;
39  CK_ULONG ulIvLen;
40  CK_BYTE_PTR pAAD;
41  CK_ULONG ulAADLen;
42  CK_ULONG ulTagBits;
43};
44#endif  // CKM_AES_CTR
45
46typedef SECStatus
47(*PK11_DecryptFunction)(
48    PK11SymKey* symKey, CK_MECHANISM_TYPE mechanism, SECItem* param,
49    unsigned char* out, unsigned int* outLen, unsigned int maxLen,
50    const unsigned char* enc, unsigned encLen);
51
52// On Linux, dynamically link against the system version of libnss3.so. In
53// order to continue working on systems without up-to-date versions of NSS,
54// lookup PK11_Decrypt with dlsym.
55
56// GcmSupportChecker is a singleton which caches the results of runtime symbol
57// resolution of PK11_Decrypt.
58class GcmSupportChecker {
59 public:
60  static PK11_DecryptFunction pk11_decrypt_func() {
61    return pk11_decrypt_func_;
62  }
63
64  static CK_MECHANISM_TYPE aes_key_mechanism() {
65    return aes_key_mechanism_;
66  }
67
68 private:
69  friend struct base::DefaultLazyInstanceTraits<GcmSupportChecker>;
70
71  GcmSupportChecker() {
72#if !defined(USE_NSS)
73    // Using a bundled version of NSS that is guaranteed to have this symbol.
74    pk11_decrypt_func_ = PK11_Decrypt;
75#else
76    // Using system NSS libraries and PCKS #11 modules, which may not have the
77    // necessary function (PK11_Decrypt) or mechanism support (CKM_AES_GCM).
78
79    // If PK11_Decrypt() was successfully resolved, then NSS will support
80    // AES-GCM directly. This was introduced in NSS 3.15.
81    pk11_decrypt_func_ = (PK11_DecryptFunction)dlsym(RTLD_DEFAULT,
82                                                     "PK11_Decrypt");
83    if (pk11_decrypt_func_ == NULL) {
84      aes_key_mechanism_ = CKM_AES_ECB;
85    }
86#endif
87  }
88
89  // |pk11_decrypt_func_| stores the runtime symbol resolution of PK11_Decrypt.
90  static PK11_DecryptFunction pk11_decrypt_func_;
91
92  // The correct value for |aes_key_mechanism_| is CKM_AES_GCM, but because of
93  // NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=853285 (to be fixed in
94  // NSS 3.15), use CKM_AES_ECB for NSS versions older than 3.15.
95  static CK_MECHANISM_TYPE aes_key_mechanism_;
96};
97
98// static
99PK11_DecryptFunction GcmSupportChecker::pk11_decrypt_func_ = NULL;
100
101// static
102CK_MECHANISM_TYPE GcmSupportChecker::aes_key_mechanism_ = CKM_AES_GCM;
103
104base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker =
105    LAZY_INSTANCE_INITIALIZER;
106
107const size_t kKeySize = 16;
108const size_t kNoncePrefixSize = 4;
109const size_t kAESNonceSize = 12;
110
111// Calls PK11_Decrypt if it's available.  Otherwise, emulates CKM_AES_GCM using
112// CKM_AES_CTR and the GaloisHash class.
113SECStatus My_Decrypt(PK11SymKey* key,
114                     CK_MECHANISM_TYPE mechanism,
115                     SECItem* param,
116                     unsigned char* out,
117                     unsigned int* out_len,
118                     unsigned int max_len,
119                     const unsigned char* enc,
120                     unsigned int enc_len) {
121  // If PK11_Decrypt() was successfully resolved or if bundled version of NSS is
122  // being used, then NSS will support AES-GCM directly.
123  PK11_DecryptFunction pk11_decrypt_func =
124      GcmSupportChecker::pk11_decrypt_func();
125  if (pk11_decrypt_func != NULL) {
126    return pk11_decrypt_func(key, mechanism, param, out, out_len, max_len, enc,
127                             enc_len);
128  }
129
130  // Otherwise, the user has an older version of NSS. Regrettably, NSS 3.14.x
131  // has a bug in the AES GCM code
132  // (https://bugzilla.mozilla.org/show_bug.cgi?id=853285), as well as missing
133  // the PK11_Decrypt function
134  // (https://bugzilla.mozilla.org/show_bug.cgi?id=854063), both of which are
135  // resolved in NSS 3.15.
136
137  DCHECK_EQ(mechanism, static_cast<CK_MECHANISM_TYPE>(CKM_AES_GCM));
138  DCHECK_EQ(param->len, sizeof(CK_GCM_PARAMS));
139
140  const CK_GCM_PARAMS* gcm_params =
141      reinterpret_cast<CK_GCM_PARAMS*>(param->data);
142
143  DCHECK_EQ(gcm_params->ulTagBits,
144            static_cast<CK_ULONG>(Aes128Gcm12Decrypter::kAuthTagSize * 8));
145  if (gcm_params->ulIvLen != 12u) {
146    DLOG(INFO) << "ulIvLen is not equal to 12";
147    PORT_SetError(SEC_ERROR_INPUT_LEN);
148    return SECFailure;
149  }
150
151  SECItem my_param = { siBuffer, NULL, 0 };
152
153  // Step 2. Let H = CIPH_K(128 '0' bits).
154  unsigned char ghash_key[16] = {0};
155  crypto::ScopedPK11Context ctx(PK11_CreateContextBySymKey(
156      CKM_AES_ECB, CKA_ENCRYPT, key, &my_param));
157  if (!ctx) {
158    DLOG(INFO) << "PK11_CreateContextBySymKey failed";
159    return SECFailure;
160  }
161  int output_len;
162  if (PK11_CipherOp(ctx.get(), ghash_key, &output_len, sizeof(ghash_key),
163                    ghash_key, sizeof(ghash_key)) != SECSuccess) {
164    DLOG(INFO) << "PK11_CipherOp failed";
165    return SECFailure;
166  }
167
168  PK11_Finalize(ctx.get());
169
170  if (output_len != sizeof(ghash_key)) {
171    DLOG(INFO) << "Wrong output length";
172    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
173    return SECFailure;
174  }
175
176  // Step 3. If len(IV)=96, then let J0 = IV || 31 '0' bits || 1.
177  CK_AES_CTR_PARAMS ctr_params = {0};
178  ctr_params.ulCounterBits = 32;
179  memcpy(ctr_params.cb, gcm_params->pIv, gcm_params->ulIvLen);
180  ctr_params.cb[12] = 0;
181  ctr_params.cb[13] = 0;
182  ctr_params.cb[14] = 0;
183  ctr_params.cb[15] = 1;
184
185  my_param.type = siBuffer;
186  my_param.data = reinterpret_cast<unsigned char*>(&ctr_params);
187  my_param.len = sizeof(ctr_params);
188
189  ctx.reset(PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, key,
190                                       &my_param));
191  if (!ctx) {
192    DLOG(INFO) << "PK11_CreateContextBySymKey failed";
193    return SECFailure;
194  }
195
196  // Step 6. Calculate the encryption mask of GCTR_K(J0, ...).
197  unsigned char tag_mask[16] = {0};
198  if (PK11_CipherOp(ctx.get(), tag_mask, &output_len, sizeof(tag_mask),
199                    tag_mask, sizeof(tag_mask)) != SECSuccess) {
200    DLOG(INFO) << "PK11_CipherOp failed";
201    return SECFailure;
202  }
203  if (output_len != sizeof(tag_mask)) {
204    DLOG(INFO) << "Wrong output length";
205    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
206    return SECFailure;
207  }
208
209  if (enc_len < Aes128Gcm12Decrypter::kAuthTagSize) {
210    PORT_SetError(SEC_ERROR_INPUT_LEN);
211    return SECFailure;
212  }
213
214  // The const_cast for |enc| can be removed if system NSS libraries are
215  // NSS 3.14.1 or later (NSS bug
216  // https://bugzilla.mozilla.org/show_bug.cgi?id=808218).
217  if (PK11_CipherOp(ctx.get(), out, &output_len, max_len,
218          const_cast<unsigned char*>(enc),
219          enc_len - Aes128Gcm12Decrypter::kAuthTagSize) != SECSuccess) {
220    DLOG(INFO) << "PK11_CipherOp failed";
221    return SECFailure;
222  }
223
224  PK11_Finalize(ctx.get());
225
226  if (static_cast<unsigned int>(output_len) !=
227      enc_len - Aes128Gcm12Decrypter::kAuthTagSize) {
228    DLOG(INFO) << "Wrong output length";
229    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
230    return SECFailure;
231  }
232
233  crypto::GaloisHash ghash(ghash_key);
234  ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen);
235  ghash.UpdateCiphertext(enc, output_len);
236  unsigned char auth_tag[Aes128Gcm12Decrypter::kAuthTagSize];
237  ghash.Finish(auth_tag, Aes128Gcm12Decrypter::kAuthTagSize);
238  for (unsigned int i = 0; i < Aes128Gcm12Decrypter::kAuthTagSize; i++) {
239    auth_tag[i] ^= tag_mask[i];
240  }
241
242  if (NSS_SecureMemcmp(auth_tag, enc + output_len,
243                       Aes128Gcm12Decrypter::kAuthTagSize) != 0) {
244    PORT_SetError(SEC_ERROR_BAD_DATA);
245    return SECFailure;
246  }
247
248  *out_len = output_len;
249  return SECSuccess;
250}
251
252}  // namespace
253
254Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() {
255  ignore_result(g_gcm_support_checker.Get());
256}
257
258Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {}
259
260// static
261bool Aes128Gcm12Decrypter::IsSupported() {
262  // NSS 3.15 supports CKM_AES_GCM directly.
263  // NSS 3.14 supports CKM_AES_CTR, which can be used to emulate CKM_AES_GCM.
264  // Versions earlier than NSS 3.14 are not supported.
265  return NSS_VersionCheck("3.14") != PR_FALSE;
266}
267
268bool Aes128Gcm12Decrypter::SetKey(StringPiece key) {
269  DCHECK_EQ(key.size(), sizeof(key_));
270  if (key.size() != sizeof(key_)) {
271    return false;
272  }
273  memcpy(key_, key.data(), key.size());
274  return true;
275}
276
277bool Aes128Gcm12Decrypter::SetNoncePrefix(StringPiece nonce_prefix) {
278  DCHECK_EQ(nonce_prefix.size(), kNoncePrefixSize);
279  if (nonce_prefix.size() != kNoncePrefixSize) {
280    return false;
281  }
282  COMPILE_ASSERT(sizeof(nonce_prefix_) == kNoncePrefixSize, bad_nonce_length);
283  memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
284  return true;
285}
286
287bool Aes128Gcm12Decrypter::Decrypt(StringPiece nonce,
288                                   StringPiece associated_data,
289                                   StringPiece ciphertext,
290                                   uint8* output,
291                                   size_t* output_length) {
292  if (ciphertext.length() < kAuthTagSize ||
293      nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
294    return false;
295  }
296  // NSS 3.14.x incorrectly requires an output buffer at least as long as
297  // the ciphertext (NSS bug
298  // https://bugzilla.mozilla.org/show_bug.cgi?id= 853674). Fortunately
299  // QuicDecrypter::Decrypt() specifies that |output| must be as long as
300  // |ciphertext| on entry.
301  size_t plaintext_size = ciphertext.length() - kAuthTagSize;
302
303  // Import key_ into NSS.
304  SECItem key_item;
305  key_item.type = siBuffer;
306  key_item.data = key_;
307  key_item.len = sizeof(key_);
308  PK11SlotInfo* slot = PK11_GetInternalSlot();
309  // The exact value of the |origin| argument doesn't matter to NSS as long as
310  // it's not PK11_OriginFortezzaHack, so pass PK11_OriginUnwrap as a
311  // placeholder.
312  crypto::ScopedPK11SymKey aes_key(PK11_ImportSymKey(
313      slot, GcmSupportChecker::aes_key_mechanism(), PK11_OriginUnwrap,
314      CKA_DECRYPT, &key_item, NULL));
315  PK11_FreeSlot(slot);
316  slot = NULL;
317  if (!aes_key) {
318    DLOG(INFO) << "PK11_ImportSymKey failed";
319    return false;
320  }
321
322  CK_GCM_PARAMS gcm_params = {0};
323  gcm_params.pIv =
324      reinterpret_cast<CK_BYTE*>(const_cast<char*>(nonce.data()));
325  gcm_params.ulIvLen = nonce.size();
326  gcm_params.pAAD =
327      reinterpret_cast<CK_BYTE*>(const_cast<char*>(associated_data.data()));
328  gcm_params.ulAADLen = associated_data.size();
329  gcm_params.ulTagBits = kAuthTagSize * 8;
330
331  SECItem param;
332  param.type = siBuffer;
333  param.data = reinterpret_cast<unsigned char*>(&gcm_params);
334  param.len = sizeof(gcm_params);
335
336  unsigned int output_len;
337  // If an incorrect authentication tag causes a decryption failure, the NSS
338  // error is SEC_ERROR_BAD_DATA (-8190).
339  if (My_Decrypt(aes_key.get(), CKM_AES_GCM, &param,
340                 output, &output_len, ciphertext.length(),
341                 reinterpret_cast<const unsigned char*>(ciphertext.data()),
342                 ciphertext.length()) != SECSuccess) {
343    DLOG(INFO) << "My_Decrypt failed: NSS error " << PORT_GetError();
344    return false;
345  }
346
347  if (output_len != plaintext_size) {
348    DLOG(INFO) << "Wrong output length";
349    return false;
350  }
351  *output_length = output_len;
352  return true;
353}
354
355QuicData* Aes128Gcm12Decrypter::DecryptPacket(
356    QuicPacketSequenceNumber sequence_number,
357    StringPiece associated_data,
358    StringPiece ciphertext) {
359  if (ciphertext.length() < kAuthTagSize) {
360    return NULL;
361  }
362  size_t plaintext_size;
363  scoped_ptr<char[]> plaintext(new char[ciphertext.length()]);
364
365  uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)];
366  COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size);
367  memcpy(nonce, nonce_prefix_, kNoncePrefixSize);
368  memcpy(nonce + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
369  if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce), sizeof(nonce)),
370               associated_data, ciphertext,
371               reinterpret_cast<uint8*>(plaintext.get()),
372               &plaintext_size)) {
373    return NULL;
374  }
375  return new QuicData(plaintext.release(), plaintext_size, true);
376}
377
378StringPiece Aes128Gcm12Decrypter::GetKey() const {
379  return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
380}
381
382StringPiece Aes128Gcm12Decrypter::GetNoncePrefix() const {
383  return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
384                     kNoncePrefixSize);
385}
386
387}  // namespace net
388