summaryrefslogtreecommitdiffstats
path: root/net/quic/crypto
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-27 19:16:05 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-27 19:16:05 +0000
commit6963ed20808c69565befb084dc1641a2b6b69f0d (patch)
treea7b23aa235b2e365f64601080f1f7f5ebc37360d /net/quic/crypto
parente8e285bb762580dff4e3c880a8ece9e1fa176d29 (diff)
downloadchromium_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.cc74
-rw-r--r--net/quic/crypto/aes_128_gcm_encrypter_nss.cc78
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, &param,
+ 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, &param,
+ 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