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_encrypter.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_EncryptFunction)( 48 PK11SymKey* symKey, CK_MECHANISM_TYPE mechanism, SECItem* param, 49 unsigned char* out, unsigned int* outLen, unsigned int maxLen, 50 const unsigned char* data, unsigned int dataLen); 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_Encrypt with dlsym. 55 56// GcmSupportChecker is a singleton which caches the results of runtime symbol 57// resolution of PK11_Encrypt. 58class GcmSupportChecker { 59 public: 60 static PK11_EncryptFunction pk11_encrypt_func() { 61 return pk11_encrypt_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_encrypt_func_ = PK11_Encrypt; 75#else 76 // Using system NSS libraries and PCKS #11 modules, which may not have the 77 // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM). 78 79 // If PK11_Encrypt() was successfully resolved, then NSS will support 80 // AES-GCM directly. This was introduced in NSS 3.15. 81 pk11_encrypt_func_ = (PK11_EncryptFunction)dlsym(RTLD_DEFAULT, 82 "PK11_Encrypt"); 83 if (pk11_encrypt_func_ == NULL) { 84 aes_key_mechanism_ = CKM_AES_ECB; 85 } 86#endif 87 } 88 89 // |pk11_encrypt_func_| stores the runtime symbol resolution of PK11_Encrypt. 90 static PK11_EncryptFunction pk11_encrypt_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_EncryptFunction GcmSupportChecker::pk11_encrypt_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_Encrypt if it's available. Otherwise, emulates CKM_AES_GCM using 112// CKM_AES_CTR and the GaloisHash class. 113SECStatus My_Encrypt(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* data, 120 unsigned int data_len) { 121 // If PK11_Encrypt() was successfully resolved or if bundled version of NSS is 122 // being used, then NSS will support AES-GCM directly. 123 PK11_EncryptFunction pk11_encrypt_func = 124 GcmSupportChecker::pk11_encrypt_func(); 125 if (pk11_encrypt_func != NULL) { 126 return pk11_encrypt_func(key, mechanism, param, out, out_len, max_len, data, 127 data_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_Encrypt 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 if (max_len < static_cast<unsigned int>(Aes128Gcm12Encrypter::kAuthTagSize)) { 141 DVLOG(1) << "max_len is less than kAuthTagSize"; 142 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 143 return SECFailure; 144 } 145 146 const CK_GCM_PARAMS* gcm_params = 147 reinterpret_cast<CK_GCM_PARAMS*>(param->data); 148 149 DCHECK_EQ(gcm_params->ulTagBits, 150 static_cast<CK_ULONG>(Aes128Gcm12Encrypter::kAuthTagSize * 8)); 151 if (gcm_params->ulIvLen != 12u) { 152 DVLOG(1) << "ulIvLen is not equal to 12"; 153 PORT_SetError(SEC_ERROR_INPUT_LEN); 154 return SECFailure; 155 } 156 157 SECItem my_param = { siBuffer, NULL, 0 }; 158 159 // Step 1. Let H = CIPH_K(128 '0' bits). 160 unsigned char ghash_key[16] = {0}; 161 crypto::ScopedPK11Context ctx(PK11_CreateContextBySymKey( 162 CKM_AES_ECB, CKA_ENCRYPT, key, &my_param)); 163 if (!ctx) { 164 DVLOG(1) << "PK11_CreateContextBySymKey failed"; 165 return SECFailure; 166 } 167 int output_len; 168 if (PK11_CipherOp(ctx.get(), ghash_key, &output_len, sizeof(ghash_key), 169 ghash_key, sizeof(ghash_key)) != SECSuccess) { 170 DVLOG(1) << "PK11_CipherOp failed"; 171 return SECFailure; 172 } 173 174 PK11_Finalize(ctx.get()); 175 176 if (output_len != sizeof(ghash_key)) { 177 DVLOG(1) << "Wrong output length"; 178 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 179 return SECFailure; 180 } 181 182 // Step 2. If len(IV)=96, then let J0 = IV || 31 '0' bits || 1. 183 CK_AES_CTR_PARAMS ctr_params = {0}; 184 ctr_params.ulCounterBits = 32; 185 memcpy(ctr_params.cb, gcm_params->pIv, gcm_params->ulIvLen); 186 ctr_params.cb[12] = 0; 187 ctr_params.cb[13] = 0; 188 ctr_params.cb[14] = 0; 189 ctr_params.cb[15] = 1; 190 191 my_param.type = siBuffer; 192 my_param.data = reinterpret_cast<unsigned char*>(&ctr_params); 193 my_param.len = sizeof(ctr_params); 194 195 ctx.reset(PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, key, 196 &my_param)); 197 if (!ctx) { 198 DVLOG(1) << "PK11_CreateContextBySymKey failed"; 199 return SECFailure; 200 } 201 202 // Step 6. Calculate the encryption mask of GCTR_K(J0, ...). 203 unsigned char tag_mask[16] = {0}; 204 if (PK11_CipherOp(ctx.get(), tag_mask, &output_len, sizeof(tag_mask), 205 tag_mask, sizeof(tag_mask)) != SECSuccess) { 206 DVLOG(1) << "PK11_CipherOp failed"; 207 return SECFailure; 208 } 209 if (output_len != sizeof(tag_mask)) { 210 DVLOG(1) << "Wrong output length"; 211 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 212 return SECFailure; 213 } 214 215 // The const_cast for |data| can be removed if system NSS libraries are 216 // NSS 3.14.1 or later (NSS bug 217 // https://bugzilla.mozilla.org/show_bug.cgi?id=808218). 218 if (PK11_CipherOp(ctx.get(), out, &output_len, max_len, 219 const_cast<unsigned char*>(data), data_len) != SECSuccess) { 220 DVLOG(1) << "PK11_CipherOp failed"; 221 return SECFailure; 222 } 223 224 PK11_Finalize(ctx.get()); 225 226 if (static_cast<unsigned int>(output_len) != data_len) { 227 DVLOG(1) << "Wrong output length"; 228 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 229 return SECFailure; 230 } 231 232 if ((max_len - Aes128Gcm12Encrypter::kAuthTagSize) < 233 static_cast<unsigned int>(output_len)) { 234 DVLOG(1) << "(max_len - kAuthTagSize) is less than output_len"; 235 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 236 return SECFailure; 237 } 238 239 crypto::GaloisHash ghash(ghash_key); 240 ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen); 241 ghash.UpdateCiphertext(out, output_len); 242 ghash.Finish(out + output_len, Aes128Gcm12Encrypter::kAuthTagSize); 243 for (unsigned int i = 0; i < Aes128Gcm12Encrypter::kAuthTagSize; i++) { 244 out[output_len + i] ^= tag_mask[i]; 245 } 246 247 *out_len = output_len + Aes128Gcm12Encrypter::kAuthTagSize; 248 return SECSuccess; 249} 250 251} // namespace 252 253Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() { 254 ignore_result(g_gcm_support_checker.Get()); 255} 256 257Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {} 258 259bool Aes128Gcm12Encrypter::SetKey(StringPiece key) { 260 DCHECK_EQ(key.size(), sizeof(key_)); 261 if (key.size() != sizeof(key_)) { 262 return false; 263 } 264 memcpy(key_, key.data(), key.size()); 265 return true; 266} 267 268bool Aes128Gcm12Encrypter::SetNoncePrefix(StringPiece nonce_prefix) { 269 DCHECK_EQ(nonce_prefix.size(), kNoncePrefixSize); 270 if (nonce_prefix.size() != kNoncePrefixSize) { 271 return false; 272 } 273 COMPILE_ASSERT(sizeof(nonce_prefix_) == kNoncePrefixSize, bad_nonce_length); 274 memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size()); 275 return true; 276} 277 278bool Aes128Gcm12Encrypter::Encrypt(StringPiece nonce, 279 StringPiece associated_data, 280 StringPiece plaintext, 281 unsigned char* output) { 282 if (nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) { 283 return false; 284 } 285 286 size_t ciphertext_size = GetCiphertextSize(plaintext.length()); 287 288 // Import key_ into NSS. 289 SECItem key_item; 290 key_item.type = siBuffer; 291 key_item.data = key_; 292 key_item.len = sizeof(key_); 293 PK11SlotInfo* slot = PK11_GetInternalSlot(); 294 // The exact value of the |origin| argument doesn't matter to NSS as long as 295 // it's not PK11_OriginFortezzaHack, so we pass PK11_OriginUnwrap as a 296 // placeholder. 297 crypto::ScopedPK11SymKey aes_key(PK11_ImportSymKey( 298 slot, GcmSupportChecker::aes_key_mechanism(), PK11_OriginUnwrap, 299 CKA_ENCRYPT, &key_item, NULL)); 300 PK11_FreeSlot(slot); 301 slot = NULL; 302 if (!aes_key) { 303 DVLOG(1) << "PK11_ImportSymKey failed"; 304 return false; 305 } 306 307 CK_GCM_PARAMS gcm_params = {0}; 308 gcm_params.pIv = 309 reinterpret_cast<CK_BYTE*>(const_cast<char*>(nonce.data())); 310 gcm_params.ulIvLen = nonce.size(); 311 gcm_params.pAAD = 312 reinterpret_cast<CK_BYTE*>(const_cast<char*>(associated_data.data())); 313 gcm_params.ulAADLen = associated_data.size(); 314 gcm_params.ulTagBits = kAuthTagSize * 8; 315 316 SECItem param; 317 param.type = siBuffer; 318 param.data = reinterpret_cast<unsigned char*>(&gcm_params); 319 param.len = sizeof(gcm_params); 320 321 unsigned int output_len; 322 if (My_Encrypt(aes_key.get(), CKM_AES_GCM, ¶m, 323 output, &output_len, ciphertext_size, 324 reinterpret_cast<const unsigned char*>(plaintext.data()), 325 plaintext.size()) != SECSuccess) { 326 DVLOG(1) << "My_Encrypt failed"; 327 return false; 328 } 329 330 if (output_len != ciphertext_size) { 331 DVLOG(1) << "Wrong output length"; 332 return false; 333 } 334 335 return true; 336} 337 338QuicData* Aes128Gcm12Encrypter::EncryptPacket( 339 QuicPacketSequenceNumber sequence_number, 340 StringPiece associated_data, 341 StringPiece plaintext) { 342 size_t ciphertext_size = GetCiphertextSize(plaintext.length()); 343 scoped_ptr<char[]> ciphertext(new char[ciphertext_size]); 344 345 // TODO(ianswett): Introduce a check to ensure that we don't encrypt with the 346 // same sequence number twice. 347 uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)]; 348 COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size); 349 memcpy(nonce, nonce_prefix_, kNoncePrefixSize); 350 memcpy(nonce + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); 351 if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce), sizeof(nonce)), 352 associated_data, plaintext, 353 reinterpret_cast<unsigned char*>(ciphertext.get()))) { 354 return NULL; 355 } 356 357 return new QuicData(ciphertext.release(), ciphertext_size, true); 358} 359 360size_t Aes128Gcm12Encrypter::GetKeySize() const { return kKeySize; } 361 362size_t Aes128Gcm12Encrypter::GetNoncePrefixSize() const { 363 return kNoncePrefixSize; 364} 365 366size_t Aes128Gcm12Encrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { 367 return ciphertext_size - kAuthTagSize; 368} 369 370// An AEAD_AES_128_GCM_12 ciphertext is exactly 12 bytes longer than its 371// corresponding plaintext. 372size_t Aes128Gcm12Encrypter::GetCiphertextSize(size_t plaintext_size) const { 373 return plaintext_size + kAuthTagSize; 374} 375 376StringPiece Aes128Gcm12Encrypter::GetKey() const { 377 return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); 378} 379 380StringPiece Aes128Gcm12Encrypter::GetNoncePrefix() const { 381 return StringPiece(reinterpret_cast<const char*>(nonce_prefix_), 382 kNoncePrefixSize); 383} 384 385} // namespace net 386