diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-27 19:16:05 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-27 19:16:05 +0000 |
commit | 6963ed20808c69565befb084dc1641a2b6b69f0d (patch) | |
tree | a7b23aa235b2e365f64601080f1f7f5ebc37360d /net/quic/crypto | |
parent | e8e285bb762580dff4e3c880a8ece9e1fa176d29 (diff) | |
download | chromium_src-6963ed20808c69565befb084dc1641a2b6b69f0d.zip chromium_src-6963ed20808c69565befb084dc1641a2b6b69f0d.tar.gz chromium_src-6963ed20808c69565befb084dc1641a2b6b69f0d.tar.bz2 |
Port the AES GCM encrypter and decrypter to NSS.
This requires the NSS patches in
https://codereview.chromium.org/12668022/
R=rsleevi@chromium.org,rtenneti@chromium.org
BUG=none
TEST=net_unittests
Review URL: https://chromiumcodereview.appspot.com/12618012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@190995 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic/crypto')
-rw-r--r-- | net/quic/crypto/aes_128_gcm_decrypter_nss.cc | 74 | ||||
-rw-r--r-- | net/quic/crypto/aes_128_gcm_encrypter_nss.cc | 78 |
2 files changed, 142 insertions, 10 deletions
diff --git a/net/quic/crypto/aes_128_gcm_decrypter_nss.cc b/net/quic/crypto/aes_128_gcm_decrypter_nss.cc index 9706839..f8f156d 100644 --- a/net/quic/crypto/aes_128_gcm_decrypter_nss.cc +++ b/net/quic/crypto/aes_128_gcm_decrypter_nss.cc @@ -4,7 +4,10 @@ #include "net/quic/crypto/aes_128_gcm_decrypter.h" +#include <pk11pub.h> + #include "base/memory/scoped_ptr.h" +#include "crypto/scoped_nss_types.h" using base::StringPiece; @@ -20,7 +23,15 @@ const size_t kAuthTagSize = 16; // static bool Aes128GcmDecrypter::IsSupported() { +#if defined(USE_NSS) + // We're using system NSS libraries. Regrettably NSS 3.14.x has a bug in the + // AES GCM code (NSS bug 853285) and is missing the PK11_DecryptWithSymKey + // function (NSS bug 854063). Both problems should be fixed in NSS 3.15. return false; +#else + // We're using our own copy of NSS. + return true; +#endif } bool Aes128GcmDecrypter::SetKey(StringPiece key) { @@ -63,15 +74,74 @@ StringPiece Aes128GcmDecrypter::GetNoncePrefix() const { QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce, StringPiece associated_data, StringPiece ciphertext) { +#if defined(USE_NSS) + // See the comment in IsSupported(). + return NULL; +#else if (ciphertext.length() < kAuthTagSize) { return NULL; } + // NSS 3.14.x incorrectly requires an output buffer at least as long as + // the ciphertext (NSS bug 853674). So the capacity of the |plaintext| + // buffer needs to be larger than the plaintext size. + size_t plaintext_capacity = ciphertext.length(); size_t plaintext_size = ciphertext.length() - kAuthTagSize; - scoped_ptr<char[]> plaintext(new char[plaintext_size]); + scoped_ptr<char[]> plaintext(new char[plaintext_capacity]); + + // Import key_ into NSS. + SECItem key_item; + key_item.type = siBuffer; + key_item.data = key_; + key_item.len = sizeof(key_); + PK11SlotInfo* slot = PK11_GetInternalSlot(); + // The exact value of the |origin| argument doesn't matter to NSS as long as + // it's not PK11_OriginFortezzaHack, so we pass PK11_OriginUnwrap as a + // placeholder. + crypto::ScopedPK11SymKey aes_key(PK11_ImportSymKey( + slot, CKM_AES_GCM, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL)); + PK11_FreeSlot(slot); + slot = NULL; + if (!aes_key) { + DLOG(INFO) << "PK11_ImportSymKey failed"; + return NULL; + } - // TODO(wtc): implement this function using NSS. + CK_GCM_PARAMS gcm_params; + gcm_params.pIv = + reinterpret_cast<CK_BYTE*>(const_cast<char*>(nonce.data())); + gcm_params.ulIvLen = nonce.size(); + gcm_params.pAAD = + reinterpret_cast<CK_BYTE*>(const_cast<char*>(associated_data.data())); + gcm_params.ulAADLen = associated_data.size(); + gcm_params.ulTagBits = kAuthTagSize * 8; + + SECItem param; + param.type = siBuffer; + param.data = reinterpret_cast<unsigned char*>(&gcm_params); + param.len = sizeof(gcm_params); + + unsigned int output_len; + // If an incorrect authentication tag causes a decryption failure, the NSS + // error is SEC_ERROR_BAD_DATA (-8190). + if (PK11_DecryptWithSymKey(aes_key.get(), CKM_AES_GCM, ¶m, + reinterpret_cast<unsigned char*>( + plaintext.get()), + &output_len, plaintext_capacity, + reinterpret_cast<const unsigned char*>( + ciphertext.data()), + ciphertext.size()) != SECSuccess) { + DLOG(INFO) << "PK11_DecryptWithSymKey failed: NSS error " + << PORT_GetError(); + return NULL; + } + + if (output_len != plaintext_size) { + DLOG(INFO) << "Wrong output length"; + return NULL; + } return new QuicData(plaintext.release(), plaintext_size, true); +#endif } } // namespace net diff --git a/net/quic/crypto/aes_128_gcm_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_encrypter_nss.cc index 7a38e89..05be7c2 100644 --- a/net/quic/crypto/aes_128_gcm_encrypter_nss.cc +++ b/net/quic/crypto/aes_128_gcm_encrypter_nss.cc @@ -4,9 +4,11 @@ #include "net/quic/crypto/aes_128_gcm_encrypter.h" +#include <pk11pub.h> #include <string.h> #include "base/memory/scoped_ptr.h" +#include "crypto/scoped_nss_types.h" using base::StringPiece; @@ -22,7 +24,15 @@ const size_t kAuthTagSize = 16; // static bool Aes128GcmEncrypter::IsSupported() { +#if defined(USE_NSS) + // We're using system NSS libraries. Regrettably NSS 3.14.x has a bug in the + // AES GCM code (NSS bug 853285) and is missing the PK11_EncryptWithSymKey + // function (NSS bug 854063). Both problems should be fixed in NSS 3.15. return false; +#else + // We're using our own copy of NSS. + return true; +#endif } bool Aes128GcmEncrypter::SetKey(StringPiece key) { @@ -72,23 +82,75 @@ size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const { return plaintext_size + kAuthTagSize; } +StringPiece Aes128GcmEncrypter::GetKey() const { + return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); +} + +StringPiece Aes128GcmEncrypter::GetNoncePrefix() const { + return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); +} + QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce, StringPiece associated_data, StringPiece plaintext) { +#if defined(USE_NSS) + // See the comment in IsSupported(). + return NULL; +#else size_t ciphertext_size = GetCiphertextSize(plaintext.length()); scoped_ptr<char[]> ciphertext(new char[ciphertext_size]); - // TODO(wtc): implement this function using NSS. + // Import key_ into NSS. + SECItem key_item; + key_item.type = siBuffer; + key_item.data = key_; + key_item.len = sizeof(key_); + PK11SlotInfo* slot = PK11_GetInternalSlot(); + // The exact value of the |origin| argument doesn't matter to NSS as long as + // it's not PK11_OriginFortezzaHack, so we pass PK11_OriginUnwrap as a + // placeholder. + crypto::ScopedPK11SymKey aes_key(PK11_ImportSymKey( + slot, CKM_AES_GCM, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL)); + PK11_FreeSlot(slot); + slot = NULL; + if (!aes_key) { + DLOG(INFO) << "PK11_ImportSymKey failed"; + return NULL; + } - return new QuicData(ciphertext.release(), ciphertext_size, true); -} + CK_GCM_PARAMS gcm_params; + gcm_params.pIv = + reinterpret_cast<CK_BYTE*>(const_cast<char*>(nonce.data())); + gcm_params.ulIvLen = nonce.size(); + gcm_params.pAAD = + reinterpret_cast<CK_BYTE*>(const_cast<char*>(associated_data.data())); + gcm_params.ulAADLen = associated_data.size(); + gcm_params.ulTagBits = kAuthTagSize * 8; + + SECItem param; + param.type = siBuffer; + param.data = reinterpret_cast<unsigned char*>(&gcm_params); + param.len = sizeof(gcm_params); + + unsigned int output_len; + if (PK11_EncryptWithSymKey(aes_key.get(), CKM_AES_GCM, ¶m, + reinterpret_cast<unsigned char*>( + ciphertext.get()), + &output_len, ciphertext_size, + reinterpret_cast<const unsigned char*>( + plaintext.data()), + plaintext.size()) != SECSuccess) { + DLOG(INFO) << "PK11_EncryptWithSymKey failed"; + return NULL; + } -StringPiece Aes128GcmEncrypter::GetKey() const { - return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_)); -} + if (output_len != ciphertext_size) { + DLOG(INFO) << "Wrong output length"; + return NULL; + } -StringPiece Aes128GcmEncrypter::GetNoncePrefix() const { - return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize); + return new QuicData(ciphertext.release(), ciphertext_size, true); +#endif } } // namespace net |