Import Cobalt 19.master.0.205881
diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn new file mode 100644 index 0000000..f8c9ba8 --- /dev/null +++ b/src/crypto/BUILD.gn
@@ -0,0 +1,222 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/crypto.gni") +import("//testing/test.gni") + +component("crypto") { + output_name = "crcrypto" # Avoid colliding with OpenSSL's libcrypto. + sources = [ + "aead.cc", + "aead.h", + "apple_keychain.h", + "apple_keychain_ios.mm", + "apple_keychain_mac.mm", + "capi_util.cc", + "capi_util.h", + "crypto_export.h", + "ec_private_key.cc", + "ec_private_key.h", + "ec_signature_creator.cc", + "ec_signature_creator.h", + "ec_signature_creator_impl.cc", + "ec_signature_creator_impl.h", + "encryptor.cc", + "encryptor.h", + "hkdf.cc", + "hkdf.h", + "hmac.cc", + "hmac.h", + "mac_security_services_lock.cc", + "mac_security_services_lock.h", + + # TODO(brettw) these mocks should be moved to a test_support_crypto target + # if possible. + "mock_apple_keychain.cc", + "mock_apple_keychain.h", + "mock_apple_keychain_ios.cc", + "mock_apple_keychain_mac.cc", + "nss_crypto_module_delegate.h", + "nss_key_util.cc", + "nss_key_util.h", + "nss_util.cc", + "nss_util.h", + "nss_util_internal.h", + "openssl_util.cc", + "openssl_util.h", + "p224.cc", + "p224.h", + "p224_spake.cc", + "p224_spake.h", + "random.cc", + "random.h", + "rsa_private_key.cc", + "rsa_private_key.h", + "scoped_capi_types.h", + "scoped_nss_types.h", + "secure_hash.cc", + "secure_hash.h", + "secure_util.cc", + "secure_util.h", + "sha2.cc", + "sha2.h", + "signature_creator.cc", + "signature_creator.h", + "signature_verifier.cc", + "signature_verifier.h", + "symmetric_key.cc", + "symmetric_key.h", + "wincrypt_shim.h", + ] + + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + + deps = [ + ":platform", + "//base", + "//base/third_party/dynamic_annotations", + ] + + public_deps = [ + "//third_party/boringssl", + ] + + if (!is_mac && !is_ios) { + sources -= [ + "apple_keychain.h", + "mock_apple_keychain.cc", + "mock_apple_keychain.h", + ] + } else { + libs = [ + "CoreFoundation.framework", + "Security.framework", + ] + } + + if (!is_mac) { + sources -= [ + "mac_security_services_lock.cc", + "mac_security_services_lock.h", + ] + } + if (!is_win) { + sources -= [ + "capi_util.cc", + "capi_util.h", + ] + } + + # Some files are built when NSS is used for the platform certificate library. + if (!use_nss_certs) { + sources -= [ + "nss_key_util.cc", + "nss_key_util.h", + "nss_util.cc", + "nss_util.h", + "nss_util_internal.h", + ] + } + + defines = [ "CRYPTO_IMPLEMENTATION" ] + + if (is_nacl) { + deps += [ "//native_client_sdk/src/libraries/nacl_io" ] + } +} + +test("crypto_unittests") { + sources = [ + "aead_unittest.cc", + "ec_private_key_unittest.cc", + "ec_signature_creator_unittest.cc", + "encryptor_unittest.cc", + "hmac_unittest.cc", + "nss_key_util_unittest.cc", + "nss_util_unittest.cc", + "p224_spake_unittest.cc", + "p224_unittest.cc", + "random_unittest.cc", + "rsa_private_key_unittest.cc", + "secure_hash_unittest.cc", + "sha2_unittest.cc", + "signature_creator_unittest.cc", + "signature_verifier_unittest.cc", + "symmetric_key_unittest.cc", + ] + + # Some files are built when NSS is used for the platform certificate library. + if (!use_nss_certs) { + sources -= [ + "nss_key_util_unittest.cc", + "nss_util_unittest.cc", + ] + } + + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + + deps = [ + ":crypto", + ":platform", + ":test_support", + "//base", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//testing/gmock", + "//testing/gtest", + ] +} + +# This has no sources in some cases so can't be a static library. +source_set("test_support") { + testonly = true + sources = [] + + if (use_nss_certs) { + sources += [ + "scoped_test_nss_db.cc", + "scoped_test_nss_db.h", + ] + } + + if (is_chromeos) { + sources += [ + "scoped_test_nss_chromeos_user.cc", + "scoped_test_nss_chromeos_user.h", + "scoped_test_system_nss_key_slot.cc", + "scoped_test_system_nss_key_slot.h", + ] + } + + deps = [ + ":crypto", + ":platform", + "//base", + ] +} + +config("platform_config") { + if (use_nss_certs && is_clang) { + # There is a broken header guard in /usr/include/nss/secmod.h: + # https://bugzilla.mozilla.org/show_bug.cgi?id=884072 + cflags = [ "-Wno-header-guard" ] + } +} + +# This is a meta-target that forwards to NSS's SSL library or OpenSSL, +# according to the state of the crypto flags. A target just wanting to depend +# on the current SSL library should just depend on this. +group("platform") { + public_deps = [ + "//third_party/boringssl", + ] + + # Link in NSS if it is used for the platform certificate library + # (use_nss_certs). + if (use_nss_certs) { + public_configs = [ ":platform_config" ] + public_configs += [ "//build/config/linux/nss:system_nss_no_ssl_config" ] + } +}
diff --git a/src/crypto/aead.cc b/src/crypto/aead.cc new file mode 100644 index 0000000..884ed15 --- /dev/null +++ b/src/crypto/aead.cc
@@ -0,0 +1,127 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/aead.h" + +#include <string> + +#include "base/strings/string_util.h" +#include "crypto/openssl_util.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/aes.h" +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace crypto { + +Aead::Aead(AeadAlgorithm algorithm) : key_(nullptr) { + EnsureOpenSSLInit(); + switch (algorithm) { + case AES_128_CTR_HMAC_SHA256: + aead_ = EVP_aead_aes_128_ctr_hmac_sha256(); + break; + case AES_256_GCM: + aead_ = EVP_aead_aes_256_gcm(); + break; + case AES_256_GCM_SIV: + aead_ = EVP_aead_aes_256_gcm_siv(); + break; + } +} + +Aead::~Aead() = default; + +void Aead::Init(const std::string* key) { + DCHECK(!key_); + DCHECK_EQ(KeyLength(), key->size()); + key_ = key; +} + +bool Aead::Seal(base::StringPiece plaintext, + base::StringPiece nonce, + base::StringPiece additional_data, + std::string* ciphertext) const { + DCHECK(key_); + DCHECK_EQ(NonceLength(), nonce.size()); + EVP_AEAD_CTX ctx; + + if (!EVP_AEAD_CTX_init(&ctx, aead_, + reinterpret_cast<const uint8_t*>(key_->data()), + key_->size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { + return false; + } + + std::string result; + const size_t max_output_length = + EVP_AEAD_max_overhead(aead_) + plaintext.size(); + size_t output_length; + uint8_t* out_ptr = reinterpret_cast<uint8_t*>( + base::WriteInto(&result, max_output_length + 1)); + + if (!EVP_AEAD_CTX_seal( + &ctx, out_ptr, &output_length, max_output_length, + reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(), + reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size(), + reinterpret_cast<const uint8_t*>(additional_data.data()), + additional_data.size())) { + EVP_AEAD_CTX_cleanup(&ctx); + return false; + } + + DCHECK_LE(output_length, max_output_length); + result.resize(output_length); + + ciphertext->swap(result); + EVP_AEAD_CTX_cleanup(&ctx); + + return true; +} + +bool Aead::Open(base::StringPiece ciphertext, + base::StringPiece nonce, + base::StringPiece additional_data, + std::string* plaintext) const { + DCHECK(key_); + EVP_AEAD_CTX ctx; + + if (!EVP_AEAD_CTX_init(&ctx, aead_, + reinterpret_cast<const uint8_t*>(key_->data()), + key_->size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { + return false; + } + + std::string result; + const size_t max_output_length = ciphertext.size(); + size_t output_length; + uint8_t* out_ptr = reinterpret_cast<uint8_t*>( + base::WriteInto(&result, max_output_length + 1)); + + if (!EVP_AEAD_CTX_open( + &ctx, out_ptr, &output_length, max_output_length, + reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(), + reinterpret_cast<const uint8_t*>(ciphertext.data()), + ciphertext.size(), + reinterpret_cast<const uint8_t*>(additional_data.data()), + additional_data.size())) { + EVP_AEAD_CTX_cleanup(&ctx); + return false; + } + + DCHECK_LE(output_length, max_output_length); + result.resize(output_length); + + plaintext->swap(result); + EVP_AEAD_CTX_cleanup(&ctx); + + return true; +} + +size_t Aead::KeyLength() const { + return EVP_AEAD_key_length(aead_); +} + +size_t Aead::NonceLength() const { + return EVP_AEAD_nonce_length(aead_); +} + +} // namespace crypto
diff --git a/src/crypto/aead.h b/src/crypto/aead.h new file mode 100644 index 0000000..810846c --- /dev/null +++ b/src/crypto/aead.h
@@ -0,0 +1,50 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_AEAD_H_ +#define CRYPTO_AEAD_H_ + +#include <string> + +#include "base/strings/string_piece.h" +#include "crypto/crypto_export.h" +#include "starboard/types.h" + +struct evp_aead_st; + +namespace crypto { + +// This class exposes the AES-128-CTR-HMAC-SHA256 and AES_256_GCM AEAD. +class CRYPTO_EXPORT Aead { + public: + enum AeadAlgorithm { AES_128_CTR_HMAC_SHA256, AES_256_GCM, AES_256_GCM_SIV }; + + explicit Aead(AeadAlgorithm algorithm); + + ~Aead(); + + void Init(const std::string* key); + + bool Seal(base::StringPiece plaintext, + base::StringPiece nonce, + base::StringPiece additional_data, + std::string* ciphertext) const; + + bool Open(base::StringPiece ciphertext, + base::StringPiece nonce, + base::StringPiece additional_data, + std::string* plaintext) const; + + size_t KeyLength() const; + + size_t NonceLength() const; + + private: + const std::string* key_; + const evp_aead_st* aead_; +}; + +} // namespace crypto + +#endif // CRYPTO_AEAD_H_
diff --git a/src/crypto/aead_unittest.cc b/src/crypto/aead_unittest.cc new file mode 100644 index 0000000..559e125 --- /dev/null +++ b/src/crypto/aead_unittest.cc
@@ -0,0 +1,61 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/aead.h" + +#include <string> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const crypto::Aead::AeadAlgorithm kAllAlgorithms[]{ + crypto::Aead::AES_128_CTR_HMAC_SHA256, crypto::Aead::AES_256_GCM, + crypto::Aead::AES_256_GCM_SIV, +}; + +class AeadTest : public testing::TestWithParam<crypto::Aead::AeadAlgorithm> {}; + +INSTANTIATE_TEST_CASE_P(, AeadTest, testing::ValuesIn(kAllAlgorithms)); + +TEST_P(AeadTest, SealOpen) { + crypto::Aead::AeadAlgorithm alg = GetParam(); + crypto::Aead aead(alg); + std::string key(aead.KeyLength(), 0); + aead.Init(&key); + std::string nonce(aead.NonceLength(), 0); + std::string plaintext("this is the plaintext"); + std::string ad("this is the additional data"); + std::string ciphertext; + EXPECT_TRUE(aead.Seal(plaintext, nonce, ad, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + std::string decrypted; + EXPECT_TRUE(aead.Open(ciphertext, nonce, ad, &decrypted)); + + EXPECT_EQ(plaintext, decrypted); +} + +TEST_P(AeadTest, SealOpenWrongKey) { + crypto::Aead::AeadAlgorithm alg = GetParam(); + crypto::Aead aead(alg); + std::string key(aead.KeyLength(), 0); + std::string wrong_key(aead.KeyLength(), 1); + aead.Init(&key); + crypto::Aead aead_wrong_key(alg); + aead_wrong_key.Init(&wrong_key); + + std::string nonce(aead.NonceLength(), 0); + std::string plaintext("this is the plaintext"); + std::string ad("this is the additional data"); + std::string ciphertext; + EXPECT_TRUE(aead.Seal(plaintext, nonce, ad, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + std::string decrypted; + EXPECT_FALSE(aead_wrong_key.Open(ciphertext, nonce, ad, &decrypted)); + EXPECT_EQ(0U, decrypted.size()); +} + +} // namespace
diff --git a/src/crypto/apple_keychain.h b/src/crypto/apple_keychain.h new file mode 100644 index 0000000..778697f --- /dev/null +++ b/src/crypto/apple_keychain.h
@@ -0,0 +1,64 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_APPLE_KEYCHAIN_H_ +#define CRYPTO_APPLE_KEYCHAIN_H_ + +#include <Security/Security.h> + +#include "base/macros.h" +#include "build/build_config.h" +#include "crypto/crypto_export.h" +#include "starboard/types.h" + +namespace crypto { + +#if defined(OS_IOS) +using AppleSecKeychainItemRef = void*; +#else +using AppleSecKeychainItemRef = SecKeychainItemRef; +#endif + +// Wraps the KeychainServices API in a very thin layer, to allow it to be +// mocked out for testing. + +// See Keychain Services documentation for function documentation, as these call +// through directly to their Keychain Services equivalents (Foo -> +// SecKeychainFoo). The only exception is Free, which should be used for +// anything returned from this class that would normally be freed with +// CFRelease (to aid in testing). +class CRYPTO_EXPORT AppleKeychain { + public: + AppleKeychain(); + virtual ~AppleKeychain(); + + virtual OSStatus FindGenericPassword(UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32* passwordLength, + void** passwordData, + AppleSecKeychainItemRef* itemRef) const; + + virtual OSStatus ItemFreeContent(void* data) const; + + virtual OSStatus AddGenericPassword(UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + AppleSecKeychainItemRef* itemRef) const; + +#if !defined(OS_IOS) + virtual OSStatus ItemDelete(AppleSecKeychainItemRef itemRef) const; +#endif // !defined(OS_IOS) + + private: + DISALLOW_COPY_AND_ASSIGN(AppleKeychain); +}; + +} // namespace crypto + +#endif // CRYPTO_APPLE_KEYCHAIN_H_
diff --git a/src/crypto/apple_keychain_ios.mm b/src/crypto/apple_keychain_ios.mm new file mode 100644 index 0000000..e16407d --- /dev/null +++ b/src/crypto/apple_keychain_ios.mm
@@ -0,0 +1,195 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/apple_keychain.h" + +#import <Foundation/Foundation.h> + +#include "base/mac/foundation_util.h" +#include "base/mac/scoped_cftyperef.h" +#include "base/mac/scoped_nsobject.h" + +namespace { + +enum KeychainAction { + kKeychainActionCreate, + kKeychainActionUpdate +}; + +// Creates a dictionary that can be used to query the keystore. +// Ownership follows the Create rule. +CFDictionaryRef CreateGenericPasswordQuery(UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName) { + CFMutableDictionaryRef query = + CFDictionaryCreateMutable(NULL, + 5, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + // Type of element is generic password. + CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword); + + // Set the service name. + base::scoped_nsobject<NSString> service_name_ns( + [[NSString alloc] initWithBytes:serviceName + length:serviceNameLength + encoding:NSUTF8StringEncoding]); + CFDictionarySetValue(query, kSecAttrService, + base::mac::NSToCFCast(service_name_ns)); + + // Set the account name. + base::scoped_nsobject<NSString> account_name_ns( + [[NSString alloc] initWithBytes:accountName + length:accountNameLength + encoding:NSUTF8StringEncoding]); + CFDictionarySetValue(query, kSecAttrAccount, + base::mac::NSToCFCast(account_name_ns)); + + // Use the proper search constants, return only the data of the first match. + CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + return query; +} + +// Creates a dictionary conatining the data to save into the keychain. +// Ownership follows the Create rule. +CFDictionaryRef CreateKeychainData(UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + KeychainAction action) { + CFMutableDictionaryRef keychain_data = + CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + // Set the password. + NSData* password = [NSData dataWithBytes:passwordData length:passwordLength]; + CFDictionarySetValue(keychain_data, kSecValueData, + base::mac::NSToCFCast(password)); + + // If this is not a creation, no structural information is needed. + if (action != kKeychainActionCreate) + return keychain_data; + + // Set the type of the data. + CFDictionarySetValue(keychain_data, kSecClass, kSecClassGenericPassword); + + // Only allow access when the device has been unlocked. + CFDictionarySetValue(keychain_data, + kSecAttrAccessible, + kSecAttrAccessibleWhenUnlocked); + + // Set the service name. + base::scoped_nsobject<NSString> service_name_ns( + [[NSString alloc] initWithBytes:serviceName + length:serviceNameLength + encoding:NSUTF8StringEncoding]); + CFDictionarySetValue(keychain_data, kSecAttrService, + base::mac::NSToCFCast(service_name_ns)); + + // Set the account name. + base::scoped_nsobject<NSString> account_name_ns( + [[NSString alloc] initWithBytes:accountName + length:accountNameLength + encoding:NSUTF8StringEncoding]); + CFDictionarySetValue(keychain_data, kSecAttrAccount, + base::mac::NSToCFCast(account_name_ns)); + + return keychain_data; +} + +} // namespace + +namespace crypto { + +AppleKeychain::AppleKeychain() {} + +AppleKeychain::~AppleKeychain() {} + +OSStatus AppleKeychain::ItemFreeContent(void* data) const { + free(data); + return noErr; +} + +OSStatus AppleKeychain::AddGenericPassword( + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + AppleSecKeychainItemRef* itemRef) const { + base::ScopedCFTypeRef<CFDictionaryRef> query(CreateGenericPasswordQuery( + serviceNameLength, serviceName, accountNameLength, accountName)); + // Check that there is not already a password. + OSStatus status = SecItemCopyMatching(query, NULL); + if (status == errSecItemNotFound) { + // A new entry must be created. + base::ScopedCFTypeRef<CFDictionaryRef> keychain_data( + CreateKeychainData(serviceNameLength, + serviceName, + accountNameLength, + accountName, + passwordLength, + passwordData, + kKeychainActionCreate)); + status = SecItemAdd(keychain_data, NULL); + } else if (status == noErr) { + // The entry must be updated. + base::ScopedCFTypeRef<CFDictionaryRef> keychain_data( + CreateKeychainData(serviceNameLength, + serviceName, + accountNameLength, + accountName, + passwordLength, + passwordData, + kKeychainActionUpdate)); + status = SecItemUpdate(query, keychain_data); + } + + return status; +} + +OSStatus AppleKeychain::FindGenericPassword( + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32* passwordLength, + void** passwordData, + AppleSecKeychainItemRef* itemRef) const { + DCHECK((passwordData && passwordLength) || + (!passwordData && !passwordLength)); + base::ScopedCFTypeRef<CFDictionaryRef> query(CreateGenericPasswordQuery( + serviceNameLength, serviceName, accountNameLength, accountName)); + + // Get the keychain item containing the password. + CFTypeRef resultRef = NULL; + OSStatus status = SecItemCopyMatching(query, &resultRef); + base::ScopedCFTypeRef<CFTypeRef> result(resultRef); + + if (status != noErr) { + if (passwordData) { + *passwordData = NULL; + *passwordLength = 0; + } + return status; + } + + if (passwordData) { + CFDataRef data = base::mac::CFCast<CFDataRef>(result); + NSUInteger length = CFDataGetLength(data); + *passwordData = malloc(length * sizeof(UInt8)); + CFDataGetBytes(data, CFRangeMake(0, length), (UInt8*)*passwordData); + *passwordLength = length; + } + return status; +} + +} // namespace crypto
diff --git a/src/crypto/apple_keychain_mac.mm b/src/crypto/apple_keychain_mac.mm new file mode 100644 index 0000000..5158f48 --- /dev/null +++ b/src/crypto/apple_keychain_mac.mm
@@ -0,0 +1,56 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/apple_keychain.h" + +#import <Foundation/Foundation.h> + +#include "base/synchronization/lock.h" +#include "crypto/mac_security_services_lock.h" + +namespace crypto { + +AppleKeychain::AppleKeychain() {} + +AppleKeychain::~AppleKeychain() {} + +OSStatus AppleKeychain::ItemDelete(AppleSecKeychainItemRef itemRef) const { + base::AutoLock lock(GetMacSecurityServicesLock()); + return SecKeychainItemDelete(itemRef); +} + +OSStatus AppleKeychain::FindGenericPassword( + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32* passwordLength, + void** passwordData, + AppleSecKeychainItemRef* itemRef) const { + base::AutoLock lock(GetMacSecurityServicesLock()); + return SecKeychainFindGenericPassword(nullptr, serviceNameLength, serviceName, + accountNameLength, accountName, + passwordLength, passwordData, itemRef); +} + +OSStatus AppleKeychain::ItemFreeContent(void* data) const { + base::AutoLock lock(GetMacSecurityServicesLock()); + return SecKeychainItemFreeContent(nullptr, data); +} + +OSStatus AppleKeychain::AddGenericPassword( + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + AppleSecKeychainItemRef* itemRef) const { + base::AutoLock lock(GetMacSecurityServicesLock()); + return SecKeychainAddGenericPassword(nullptr, serviceNameLength, serviceName, + accountNameLength, accountName, + passwordLength, passwordData, itemRef); +} + +} // namespace crypto
diff --git a/src/crypto/capi_util.cc b/src/crypto/capi_util.cc new file mode 100644 index 0000000..0182364 --- /dev/null +++ b/src/crypto/capi_util.cc
@@ -0,0 +1,22 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/capi_util.h" + +#include <stdlib.h> + +#include "starboard/memory.h" +#include "starboard/types.h" + +namespace crypto { + +void* WINAPI CryptAlloc(size_t size) { + return SbMemoryAllocate(size); +} + +void WINAPI CryptFree(void* p) { + SbMemoryFree(p); +} + +} // namespace crypto
diff --git a/src/crypto/capi_util.h b/src/crypto/capi_util.h new file mode 100644 index 0000000..9064959 --- /dev/null +++ b/src/crypto/capi_util.h
@@ -0,0 +1,23 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_CAPI_UTIL_H_ +#define CRYPTO_CAPI_UTIL_H_ + +#include <windows.h> + +#include "crypto/crypto_export.h" +#include "starboard/types.h" + +namespace crypto { + +// Wrappers of malloc and free for CryptoAPI routines that need memory +// allocators, such as in CRYPT_DECODE_PARA. Such routines require WINAPI +// calling conventions. +CRYPTO_EXPORT void* WINAPI CryptAlloc(size_t size); +CRYPTO_EXPORT void WINAPI CryptFree(void* p); + +} // namespace crypto + +#endif // CRYPTO_CAPI_UTIL_H_
diff --git a/src/crypto/crypto.gyp b/src/crypto/crypto.gyp index 3705097..354d689 100644 --- a/src/crypto/crypto.gyp +++ b/src/crypto/crypto.gyp
@@ -8,10 +8,10 @@ 'type': '<(component)', 'product_name': 'crcrypto', # Avoid colliding with OpenSSL's libcrypto 'dependencies': [ - '../base/base.gyp:base', - '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - '<(DEPTH)/starboard/starboard.gyp:starboard', + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto', + '<(DEPTH)/starboard/starboard.gyp:starboard', ], 'defines': [ 'CRYPTO_IMPLEMENTATION', @@ -20,22 +20,26 @@ 4018, ], 'sources': [ + 'aead.cc', + 'aead.h', 'crypto_export.h', - 'crypto_module_blocking_password_delegate.h', + 'ec_private_key.cc', 'ec_private_key.h', - 'ec_private_key_openssl.cc', 'ec_signature_creator.cc', 'ec_signature_creator.h', + 'ec_signature_creator_impl.cc', 'ec_signature_creator_impl.h', - 'ec_signature_creator_openssl.cc', 'encryptor.cc', 'encryptor.h', - 'encryptor_openssl.cc', - 'ghash.cc', - 'ghash.h', + 'hkdf.cc', + 'hkdf.h', 'hmac.cc', 'hmac.h', - 'hmac_openssl.cc', + 'mac_security_services_lock.cc', + 'mac_security_services_lock.h', + + # TODO(brettw) these mocks should be moved to a test_support_crypto + # target if possible. 'openssl_util.cc', 'openssl_util.h', 'p224.cc', @@ -46,43 +50,32 @@ 'random.h', 'rsa_private_key.cc', 'rsa_private_key.h', - 'rsa_private_key_ios.cc', - 'rsa_private_key_mac.cc', - 'rsa_private_key_openssl.cc', - 'rsa_private_key_win.cc', - 'scoped_capi_types.h', - 'scoped_nss_types.h', + 'secure_hash.cc', 'secure_hash.h', - 'secure_hash_openssl.cc', 'secure_util.cc', 'secure_util.h', 'sha2.cc', 'sha2.h', + 'signature_creator.cc', 'signature_creator.h', - 'signature_creator_mac.cc', - 'signature_creator_openssl.cc', - 'signature_creator_win.cc', + 'signature_verifier.cc', 'signature_verifier.h', - 'signature_verifier_openssl.cc', + 'symmetric_key.cc', 'symmetric_key.h', - 'symmetric_key_openssl.cc', + 'wincrypt_shim.h', ], }, { 'target_name': 'crypto_unittests', 'type': '<(gtest_target_type)', 'sources': [ - # Infrastructure files. - 'run_all_unittests.cc', - - # Tests. + 'aead_unittest.cc', 'ec_private_key_unittest.cc', 'ec_signature_creator_unittest.cc', 'encryptor_unittest.cc', - 'ghash_unittest.cc', 'hmac_unittest.cc', - 'p224_unittest.cc', 'p224_spake_unittest.cc', + 'p224_unittest.cc', 'random_unittest.cc', 'rsa_private_key_unittest.cc', 'secure_hash_unittest.cc', @@ -93,10 +86,11 @@ ], 'dependencies': [ 'crypto', - '../base/base.gyp:base', - '../base/base.gyp:test_support_base', - '../testing/gmock.gyp:gmock', - '../testing/gtest.gyp:gtest', + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/base/base.gyp:test_support_base', + '<(DEPTH)/base/base.gyp:run_all_unittests', + '<(DEPTH)/testing/gmock.gyp:gmock', + '<(DEPTH)/testing/gtest.gyp:gtest', ], }, ], @@ -112,7 +106,7 @@ 'variables': { 'executable_name': 'crypto_unittests', }, - 'includes': [ '<(DEPTH)/starboard/build/deploy.gypi' ], + 'includes': [ '../starboard/build/deploy.gypi' ], }, ], }],
diff --git a/src/crypto/crypto_export.h b/src/crypto/crypto_export.h index 6b1acc8..605af94 100644 --- a/src/crypto/crypto_export.h +++ b/src/crypto/crypto_export.h
@@ -6,33 +6,27 @@ #define CRYPTO_CRYPTO_EXPORT_H_ // Defines CRYPTO_EXPORT so that functionality implemented by the crypto module -// can be exported to consumers, and CRYPTO_EXPORT_PRIVATE that allows unit -// tests to access features not intended to be used directly by real consumers. +// can be exported to consumers. #if defined(COMPONENT_BUILD) -#if defined(_MSC_VER) +#if defined(WIN32) #if defined(CRYPTO_IMPLEMENTATION) #define CRYPTO_EXPORT __declspec(dllexport) -#define CRYPTO_EXPORT_PRIVATE __declspec(dllexport) #else #define CRYPTO_EXPORT __declspec(dllimport) -#define CRYPTO_EXPORT_PRIVATE __declspec(dllimport) #endif // defined(CRYPTO_IMPLEMENTATION) #else // defined(WIN32) #if defined(CRYPTO_IMPLEMENTATION) #define CRYPTO_EXPORT __attribute__((visibility("default"))) -#define CRYPTO_EXPORT_PRIVATE __attribute__((visibility("default"))) #else #define CRYPTO_EXPORT -#define CRYPTO_EXPORT_PRIVATE #endif #endif #else // defined(COMPONENT_BUILD) #define CRYPTO_EXPORT -#define CRYPTO_EXPORT_PRIVATE #endif #endif // CRYPTO_CRYPTO_EXPORT_H_
diff --git a/src/crypto/crypto_module_blocking_password_delegate.h b/src/crypto/crypto_module_blocking_password_delegate.h deleted file mode 100644 index c4acf1a..0000000 --- a/src/crypto/crypto_module_blocking_password_delegate.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CRYPTO_CRYPTO_MODULE_BLOCKING_PASSWORD_DELEGATE_H_ -#define CRYPTO_CRYPTO_MODULE_BLOCKING_PASSWORD_DELEGATE_H_ - -#include <string> - -namespace crypto { - -// PK11_SetPasswordFunc is a global setting. An implementation of -// CryptoModuleBlockingPasswordDelegate should be passed as the user data -// argument (|wincx|) to relevant NSS functions, which the global password -// handler will call to do the actual work. -class CryptoModuleBlockingPasswordDelegate { - public: - virtual ~CryptoModuleBlockingPasswordDelegate() {} - - // Requests a password to unlock |slot_name|. The interface is - // synchronous because NSS cannot issue an asynchronous - // request. |retry| is true if this is a request for the retry - // and we previously returned the wrong password. - // The implementation should set |*cancelled| to true if the user cancelled - // instead of entering a password, otherwise it should return the password the - // user entered. - virtual std::string RequestPassword(const std::string& slot_name, bool retry, - bool* cancelled) = 0; -}; - -} // namespace crypto - -#endif // CRYPTO_CRYPTO_MODULE_BLOCKING_PASSWORD_DELEGATE_H_
diff --git a/src/crypto/ec_private_key.cc b/src/crypto/ec_private_key.cc new file mode 100644 index 0000000..11110ea --- /dev/null +++ b/src/crypto/ec_private_key.cc
@@ -0,0 +1,173 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/ec_private_key.h" + +#include <utility> + +#include "base/logging.h" +#include "crypto/openssl_util.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/bn.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/ec.h" +#include "third_party/boringssl/src/include/openssl/ec_key.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/mem.h" +#include "third_party/boringssl/src/include/openssl/pkcs8.h" + +namespace crypto { + +ECPrivateKey::~ECPrivateKey() = default; + +// static +std::unique_ptr<ECPrivateKey> ECPrivateKey::Create() { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + + bssl::UniquePtr<EC_KEY> ec_key( + EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + if (!ec_key || !EC_KEY_generate_key(ec_key.get())) + return nullptr; + + std::unique_ptr<ECPrivateKey> result(new ECPrivateKey()); + result->key_.reset(EVP_PKEY_new()); + if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_.get(), ec_key.get())) + return nullptr; + + CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_id(result->key_.get())); + return result; +} + +// static +std::unique_ptr<ECPrivateKey> ECPrivateKey::CreateFromPrivateKeyInfo( + const std::vector<uint8_t>& input) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + + CBS cbs; + CBS_init(&cbs, input.data(), input.size()); + bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs)); + if (!pkey || CBS_len(&cbs) != 0 || EVP_PKEY_id(pkey.get()) != EVP_PKEY_EC) + return nullptr; + + std::unique_ptr<ECPrivateKey> result(new ECPrivateKey()); + result->key_ = std::move(pkey); + return result; +} + +// static +std::unique_ptr<ECPrivateKey> ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + const std::vector<uint8_t>& encrypted_private_key_info) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + + CBS cbs; + CBS_init(&cbs, encrypted_private_key_info.data(), + encrypted_private_key_info.size()); + bssl::UniquePtr<EVP_PKEY> pkey( + PKCS8_parse_encrypted_private_key(&cbs, "", 0)); + + // Hack for reading keys generated by an older version of the OpenSSL code. + // Some implementations encode the empty password as "\0\0" (passwords are + // normally encoded in big-endian UCS-2 with a NUL terminator) and some + // encode as the empty string. PKCS8_parse_encrypted_private_key + // distinguishes the two by whether the password is nullptr. + if (!pkey) { + CBS_init(&cbs, encrypted_private_key_info.data(), + encrypted_private_key_info.size()); + pkey.reset(PKCS8_parse_encrypted_private_key(&cbs, nullptr, 0)); + } + + if (!pkey || CBS_len(&cbs) != 0 || EVP_PKEY_id(pkey.get()) != EVP_PKEY_EC) + return nullptr; + + std::unique_ptr<ECPrivateKey> result(new ECPrivateKey()); + result->key_ = std::move(pkey); + return result; +} + +std::unique_ptr<ECPrivateKey> ECPrivateKey::Copy() const { + std::unique_ptr<ECPrivateKey> copy(new ECPrivateKey()); + copy->key_ = bssl::UpRef(key_); + return copy; +} + +bool ECPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + uint8_t* der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_private_key(cbb.get(), key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + output->assign(der, der + der_len); + OPENSSL_free(der); + return true; +} + +bool ECPrivateKey::ExportEncryptedPrivateKey( + std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + + // Encrypt the object. + // NOTE: NSS uses SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC + // so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL + // equivalent. + uint8_t* der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !PKCS8_marshal_encrypted_private_key( + cbb.get(), NID_pbe_WithSHA1And3_Key_TripleDES_CBC, + nullptr /* cipher */, nullptr /* no password */, 0 /* pass_len */, + nullptr /* salt */, 0 /* salt_len */, 1 /* iterations */, + key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + output->assign(der, der + der_len); + OPENSSL_free(der); + return true; +} + +bool ECPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + uint8_t *der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_public_key(cbb.get(), key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + output->assign(der, der + der_len); + OPENSSL_free(der); + return true; +} + +bool ECPrivateKey::ExportRawPublicKey(std::string* output) const { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + + // Export the x and y field elements as 32-byte, big-endian numbers. (This is + // the same as X9.62 uncompressed form without the leading 0x04 byte.) + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key_.get()); + bssl::UniquePtr<BIGNUM> x(BN_new()); + bssl::UniquePtr<BIGNUM> y(BN_new()); + uint8_t buf[64]; + if (!x || !y || + !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key), + EC_KEY_get0_public_key(ec_key), + x.get(), y.get(), nullptr) || + !BN_bn2bin_padded(buf, 32, x.get()) || + !BN_bn2bin_padded(buf + 32, 32, y.get())) { + return false; + } + + output->assign(reinterpret_cast<const char*>(buf), sizeof(buf)); + return true; +} + +ECPrivateKey::ECPrivateKey() = default; + +} // namespace crypto
diff --git a/src/crypto/ec_private_key.h b/src/crypto/ec_private_key.h index d3f5b73..f3a1cb7 100644 --- a/src/crypto/ec_private_key.h +++ b/src/crypto/ec_private_key.h
@@ -5,22 +5,15 @@ #ifndef CRYPTO_EC_PRIVATE_KEY_H_ #define CRYPTO_EC_PRIVATE_KEY_H_ +#include <memory> #include <string> #include <vector> -#include "base/basictypes.h" +#include "base/macros.h" #include "build/build_config.h" #include "crypto/crypto_export.h" - -#if defined(USE_OPENSSL) -// Forward declaration for openssl/*.h -typedef struct evp_pkey_st EVP_PKEY; -#else -// Forward declaration. -typedef struct CERTSubjectPublicKeyInfoStr CERTSubjectPublicKeyInfo; -typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey; -typedef struct SECKEYPublicKeyStr SECKEYPublicKey; -#endif +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/base.h" namespace crypto { @@ -33,106 +26,54 @@ public: ~ECPrivateKey(); - // Returns whether the system supports elliptic curve cryptography. - static bool IsSupported(); - - // Creates a new random instance. Can return NULL if initialization fails. + // Creates a new random instance. Can return nullptr if initialization fails. // The created key will use the NIST P-256 curve. // TODO(mattm): Add a curve parameter. - static ECPrivateKey* Create(); + static std::unique_ptr<ECPrivateKey> Create(); - // Creates a new random instance. Can return NULL if initialization fails. - // The created key is permanent and is not exportable in plaintext form. - // - // NOTE: Currently only available if USE_NSS is defined. - static ECPrivateKey* CreateSensitive(); + // Create a new instance by importing an existing private key. The format is + // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return + // nullptr if initialization fails. + static std::unique_ptr<ECPrivateKey> CreateFromPrivateKeyInfo( + const std::vector<uint8_t>& input); // Creates a new instance by importing an existing key pair. // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo - // block and an X.509 SubjectPublicKeyInfo block. - // Returns NULL if initialization fails. - static ECPrivateKey* CreateFromEncryptedPrivateKeyInfo( - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info); - - // Creates a new instance by importing an existing key pair. - // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo - // block and an X.509 SubjectPublicKeyInfo block. - // This can return NULL if initialization fails. The created key is permanent - // and is not exportable in plaintext form. + // block with empty password and an X.509 SubjectPublicKeyInfo block. + // Returns nullptr if initialization fails. // - // NOTE: Currently only available if USE_NSS is defined. - static ECPrivateKey* CreateSensitiveFromEncryptedPrivateKeyInfo( - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info); + // This function is deprecated. Use CreateFromPrivateKeyInfo for new code. + // See https://crbug.com/603319. + static std::unique_ptr<ECPrivateKey> CreateFromEncryptedPrivateKeyInfo( + const std::vector<uint8_t>& encrypted_private_key_info); -#if !defined(USE_OPENSSL) - // Imports the key pair and returns in |public_key| and |key|. - // Shortcut for code that needs to keep a reference directly to NSS types - // without having to create a ECPrivateKey object and make a copy of them. - // TODO(mattm): move this function to some NSS util file. - static bool ImportFromEncryptedPrivateKeyInfo( - const std::string& password, - const uint8* encrypted_private_key_info, - size_t encrypted_private_key_info_len, - CERTSubjectPublicKeyInfo* decoded_spki, - bool permanent, - bool sensitive, - SECKEYPrivateKey** key, - SECKEYPublicKey** public_key); -#endif + // Returns a copy of the object. + std::unique_ptr<ECPrivateKey> Copy() const; -#if defined(USE_OPENSSL) - EVP_PKEY* key() { return key_; } -#else - SECKEYPrivateKey* key() { return key_; } - SECKEYPublicKey* public_key() { return public_key_; } -#endif + EVP_PKEY* key() { return key_.get(); } + + // Exports the private key to a PKCS #8 PrivateKeyInfo block. + bool ExportPrivateKey(std::vector<uint8_t>* output) const; // Exports the private key as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo - // block and the public key as an X.509 SubjectPublicKeyInfo block. - // The |password| and |iterations| are used as inputs to the key derivation - // function for generating the encryption key. PKCS #5 recommends a minimum - // of 1000 iterations, on modern systems a larger value may be preferrable. - bool ExportEncryptedPrivateKey(const std::string& password, - int iterations, - std::vector<uint8>* output); + // block wth empty password. This was historically used as a workaround for + // NSS API deficiencies and does not provide security. + // + // This function is deprecated. Use ExportPrivateKey for new code. See + // https://crbug.com/603319. + bool ExportEncryptedPrivateKey(std::vector<uint8_t>* output) const; // Exports the public key to an X.509 SubjectPublicKeyInfo block. - bool ExportPublicKey(std::vector<uint8>* output); + bool ExportPublicKey(std::vector<uint8_t>* output) const; - // Exports private key data for testing. The format of data stored into output - // doesn't matter other than that it is consistent for the same key. - bool ExportValue(std::vector<uint8>* output); - bool ExportECParams(std::vector<uint8>* output); + // Exports the public key as an EC point in the uncompressed point format. + bool ExportRawPublicKey(std::string* output) const; private: // Constructor is private. Use one of the Create*() methods above instead. ECPrivateKey(); - // Shared helper for Create() and CreateSensitive(). - // TODO(cmasone): consider replacing |permanent| and |sensitive| with a - // flags arg created by ORing together some enumerated values. - static ECPrivateKey* CreateWithParams(bool permanent, - bool sensitive); - - // Shared helper for CreateFromEncryptedPrivateKeyInfo() and - // CreateSensitiveFromEncryptedPrivateKeyInfo(). - static ECPrivateKey* CreateFromEncryptedPrivateKeyInfoWithParams( - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info, - bool permanent, - bool sensitive); - -#if defined(USE_OPENSSL) - EVP_PKEY* key_; -#else - SECKEYPrivateKey* key_; - SECKEYPublicKey* public_key_; -#endif + bssl::UniquePtr<EVP_PKEY> key_; DISALLOW_COPY_AND_ASSIGN(ECPrivateKey); };
diff --git a/src/crypto/ec_private_key_openssl.cc b/src/crypto/ec_private_key_openssl.cc deleted file mode 100644 index 20214e6..0000000 --- a/src/crypto/ec_private_key_openssl.cc +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/ec_private_key.h" - -#include "base/logging.h" - -namespace crypto { - -ECPrivateKey::~ECPrivateKey() {} - -// static -bool ECPrivateKey::IsSupported() { - return false; -} - -// static -ECPrivateKey* ECPrivateKey::Create() { - NOTIMPLEMENTED(); - return NULL; -} - -// static -ECPrivateKey* ECPrivateKey::CreateSensitive() { - NOTIMPLEMENTED(); - return NULL; -} - -// static -ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo( - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info) { - NOTIMPLEMENTED(); - return NULL; -} - -bool ECPrivateKey::ExportEncryptedPrivateKey( - const std::string& password, - int iterations, - std::vector<uint8>* output) { - NOTIMPLEMENTED(); - return false; -} - -bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) { - NOTIMPLEMENTED(); - return false; -} - -bool ECPrivateKey::ExportValue(std::vector<uint8>* output) { - NOTIMPLEMENTED(); - return false; -} - -bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { - NOTIMPLEMENTED(); - return false; -} - -} // namespace crypto
diff --git a/src/crypto/ec_private_key_unittest.cc b/src/crypto/ec_private_key_unittest.cc index a052a9a..aa7e774 100644 --- a/src/crypto/ec_private_key_unittest.cc +++ b/src/crypto/ec_private_key_unittest.cc
@@ -4,104 +4,318 @@ #include "crypto/ec_private_key.h" +#include <memory> #include <vector> -#include "base/memory/scoped_ptr.h" +#include "base/macros.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_OPENSSL) -// Once ECPrivateKey is implemented for OpenSSL, remove this #if block. -// TODO(mattm): When that happens, also add some exported keys from each to test -// interop between NSS and OpenSSL. -TEST(ECPrivateKeyUnitTest, OpenSSLStub) { - scoped_ptr<crypto::ECPrivateKey> keypair1( - crypto::ECPrivateKey::Create()); - ASSERT_FALSE(keypair1.get()); -} -#else -// Generate random private keys. Export, then re-import. We should get -// back the same exact public key, and the private key should have the same -// value and elliptic curve params. -TEST(ECPrivateKeyUnitTest, InitRandomTest) { - const std::string password1 = ""; - const std::string password2 = "test"; +namespace { - scoped_ptr<crypto::ECPrivateKey> keypair1( - crypto::ECPrivateKey::Create()); - scoped_ptr<crypto::ECPrivateKey> keypair2( - crypto::ECPrivateKey::Create()); - ASSERT_TRUE(keypair1.get()); - ASSERT_TRUE(keypair2.get()); +void ExpectKeysEqual(const crypto::ECPrivateKey* keypair1, + const crypto::ECPrivateKey* keypair2) { + std::vector<uint8_t> privkey1; + std::vector<uint8_t> privkey2; + EXPECT_TRUE(keypair1->ExportPrivateKey(&privkey1)); + EXPECT_TRUE(keypair2->ExportPrivateKey(&privkey2)); + EXPECT_EQ(privkey1, privkey2); - std::vector<uint8> key1value; - std::vector<uint8> key2value; - std::vector<uint8> key1params; - std::vector<uint8> key2params; - EXPECT_TRUE(keypair1->ExportValue(&key1value)); - EXPECT_TRUE(keypair2->ExportValue(&key2value)); - EXPECT_TRUE(keypair1->ExportECParams(&key1params)); - EXPECT_TRUE(keypair2->ExportECParams(&key2params)); - - std::vector<uint8> privkey1; - std::vector<uint8> privkey2; - std::vector<uint8> pubkey1; - std::vector<uint8> pubkey2; - ASSERT_TRUE(keypair1->ExportEncryptedPrivateKey( - password1, 1, &privkey1)); - ASSERT_TRUE(keypair2->ExportEncryptedPrivateKey( - password2, 1, &privkey2)); + std::vector<uint8_t> pubkey1; + std::vector<uint8_t> pubkey2; EXPECT_TRUE(keypair1->ExportPublicKey(&pubkey1)); EXPECT_TRUE(keypair2->ExportPublicKey(&pubkey2)); + EXPECT_EQ(pubkey1, pubkey2); - scoped_ptr<crypto::ECPrivateKey> keypair3( - crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( - password1, privkey1, pubkey1)); - scoped_ptr<crypto::ECPrivateKey> keypair4( - crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( - password2, privkey2, pubkey2)); - ASSERT_TRUE(keypair3.get()); - ASSERT_TRUE(keypair4.get()); - - std::vector<uint8> key3value; - std::vector<uint8> key4value; - std::vector<uint8> key3params; - std::vector<uint8> key4params; - EXPECT_TRUE(keypair3->ExportValue(&key3value)); - EXPECT_TRUE(keypair4->ExportValue(&key4value)); - EXPECT_TRUE(keypair3->ExportECParams(&key3params)); - EXPECT_TRUE(keypair4->ExportECParams(&key4params)); - - EXPECT_EQ(key1value, key3value); - EXPECT_EQ(key2value, key4value); - EXPECT_EQ(key1params, key3params); - EXPECT_EQ(key2params, key4params); - - std::vector<uint8> pubkey3; - std::vector<uint8> pubkey4; - EXPECT_TRUE(keypair3->ExportPublicKey(&pubkey3)); - EXPECT_TRUE(keypair4->ExportPublicKey(&pubkey4)); - - EXPECT_EQ(pubkey1, pubkey3); - EXPECT_EQ(pubkey2, pubkey4); + std::string raw_pubkey1; + std::string raw_pubkey2; + EXPECT_TRUE(keypair1->ExportRawPublicKey(&raw_pubkey1)); + EXPECT_TRUE(keypair2->ExportRawPublicKey(&raw_pubkey2)); + EXPECT_EQ(raw_pubkey1, raw_pubkey2); } -TEST(ECPrivateKeyUnitTest, BadPasswordTest) { - const std::string password1 = ""; - const std::string password2 = "test"; +} // namespace - scoped_ptr<crypto::ECPrivateKey> keypair1( +// Generate random private keys. Export, then re-import in several ways. We +// should get back the same exact public key, and the private key should have +// the same value and elliptic curve params. +TEST(ECPrivateKeyUnitTest, InitRandomTest) { + std::unique_ptr<crypto::ECPrivateKey> keypair(crypto::ECPrivateKey::Create()); + ASSERT_TRUE(keypair); + + // Re-import as a PrivateKeyInfo. + std::vector<uint8_t> privkey; + EXPECT_TRUE(keypair->ExportPrivateKey(&privkey)); + std::unique_ptr<crypto::ECPrivateKey> keypair_copy = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(privkey); + ASSERT_TRUE(keypair_copy); + ExpectKeysEqual(keypair.get(), keypair_copy.get()); + + // Re-import as an EncryptedPrivateKeyInfo with kPassword1. + std::vector<uint8_t> encrypted_privkey; + EXPECT_TRUE(keypair->ExportEncryptedPrivateKey(&encrypted_privkey)); + keypair_copy = crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + encrypted_privkey); + ASSERT_TRUE(keypair_copy); + ExpectKeysEqual(keypair.get(), keypair_copy.get()); +} + +TEST(ECPrivateKeyUnitTest, Copy) { + std::unique_ptr<crypto::ECPrivateKey> keypair1( crypto::ECPrivateKey::Create()); - ASSERT_TRUE(keypair1.get()); + std::unique_ptr<crypto::ECPrivateKey> keypair2(keypair1->Copy()); + ASSERT_TRUE(keypair1); + ASSERT_TRUE(keypair2); - std::vector<uint8> privkey1; - std::vector<uint8> pubkey1; - ASSERT_TRUE(keypair1->ExportEncryptedPrivateKey( - password1, 1, &privkey1)); - ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1)); - - scoped_ptr<crypto::ECPrivateKey> keypair2( - crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( - password2, privkey1, pubkey1)); - ASSERT_FALSE(keypair2.get()); + ExpectKeysEqual(keypair1.get(), keypair2.get()); } -#endif // !defined(USE_OPENSSL) + +TEST(ECPrivateKeyUnitTest, CreateFromPrivateKeyInfo) { + static const uint8_t kPrivateKeyInfo[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x07, 0x0f, 0x08, 0x72, 0x7a, 0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9, + 0x4d, 0x89, 0x68, 0x77, 0x08, 0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e, + 0xe8, 0xd1, 0xc9, 0xce, 0x0a, 0x8b, 0xb4, 0x6a, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, + 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, + 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, + 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, + 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, + 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, + }; + static const uint8_t kSubjectPublicKeyInfo[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, + 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, + 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, + 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, + 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, + 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, + }; + static const uint8_t kRawPublicKey[] = { + 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, + 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, + 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, + 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, + 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, + 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, + }; + + std::unique_ptr<crypto::ECPrivateKey> key = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(std::vector<uint8_t>( + std::begin(kPrivateKeyInfo), std::end(kPrivateKeyInfo))); + ASSERT_TRUE(key); + + std::vector<uint8_t> public_key; + ASSERT_TRUE(key->ExportPublicKey(&public_key)); + EXPECT_EQ(std::vector<uint8_t>(std::begin(kSubjectPublicKeyInfo), + std::end(kSubjectPublicKeyInfo)), + public_key); + + std::string raw_public_key; + ASSERT_TRUE(key->ExportRawPublicKey(&raw_public_key)); + EXPECT_EQ(std::string(reinterpret_cast<const char*>(kRawPublicKey), + sizeof(kRawPublicKey)), + raw_public_key); +} + +TEST(ECPrivateKeyUnitTest, RSAPrivateKeyInfo) { + static const uint8_t kPrivateKeyInfo[] = { + 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61, + 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, 0x55, 0x84, 0xd5, 0x3a, + 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4, + 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, 0xb0, 0x40, 0x53, 0x3a, + 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f, + 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, 0xde, 0x4e, 0xb9, 0x57, + 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff, + 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, 0x84, 0x32, 0x33, 0xf3, + 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5, + 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, 0x53, 0x56, 0xa6, 0x83, + 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x03, 0x61, 0x89, 0x37, 0xcb, 0xf2, 0x98, + 0xa0, 0xce, 0xb4, 0xcb, 0x16, 0x13, 0xf0, 0xe6, 0xaf, 0x5c, 0xc5, 0xa7, + 0x69, 0x71, 0xca, 0xba, 0x8d, 0xe0, 0x4d, 0xdd, 0xed, 0xb8, 0x48, 0x8b, + 0x16, 0x93, 0x36, 0x95, 0xc2, 0x91, 0x40, 0x65, 0x17, 0xbd, 0x7f, 0xd6, + 0xad, 0x9e, 0x30, 0x28, 0x46, 0xe4, 0x3e, 0xcc, 0x43, 0x78, 0xf9, 0xfe, + 0x1f, 0x33, 0x23, 0x1e, 0x31, 0x12, 0x9d, 0x3c, 0xa7, 0x08, 0x82, 0x7b, + 0x7d, 0x25, 0x4e, 0x5e, 0x19, 0xa8, 0x9b, 0xed, 0x86, 0xb2, 0xcb, 0x3c, + 0xfe, 0x4e, 0xa1, 0xfa, 0x62, 0x87, 0x3a, 0x17, 0xf7, 0x60, 0xec, 0x38, + 0x29, 0xe8, 0x4f, 0x34, 0x9f, 0x76, 0x9d, 0xee, 0xa3, 0xf6, 0x85, 0x6b, + 0x84, 0x43, 0xc9, 0x1e, 0x01, 0xff, 0xfd, 0xd0, 0x29, 0x4c, 0xfa, 0x8e, + 0x57, 0x0c, 0xc0, 0x71, 0xa5, 0xbb, 0x88, 0x46, 0x29, 0x5c, 0xc0, 0x4f, + 0x01, 0x02, 0x41, 0x00, 0xf5, 0x83, 0xa4, 0x64, 0x4a, 0xf2, 0xdd, 0x8c, + 0x2c, 0xed, 0xa8, 0xd5, 0x60, 0x5a, 0xe4, 0xc7, 0xcc, 0x61, 0xcd, 0x38, + 0x42, 0x20, 0xd3, 0x82, 0x18, 0xf2, 0x35, 0x00, 0x72, 0x2d, 0xf7, 0x89, + 0x80, 0x67, 0xb5, 0x93, 0x05, 0x5f, 0xdd, 0x42, 0xba, 0x16, 0x1a, 0xea, + 0x15, 0xc6, 0xf0, 0xb8, 0x8c, 0xbc, 0xbf, 0x54, 0x9e, 0xf1, 0xc1, 0xb2, + 0xb3, 0x8b, 0xb6, 0x26, 0x02, 0x30, 0xc4, 0x81, 0x02, 0x41, 0x00, 0xc0, + 0x60, 0x62, 0x80, 0xe1, 0x22, 0x78, 0xf6, 0x9d, 0x83, 0x18, 0xeb, 0x72, + 0x45, 0xd7, 0xc8, 0x01, 0x7f, 0xa9, 0xca, 0x8f, 0x7d, 0xd6, 0xb8, 0x31, + 0x2b, 0x84, 0x7f, 0x62, 0xd9, 0xa9, 0x22, 0x17, 0x7d, 0x06, 0x35, 0x6c, + 0xf3, 0xc1, 0x94, 0x17, 0x85, 0x5a, 0xaf, 0x9c, 0x5c, 0x09, 0x3c, 0xcf, + 0x2f, 0x44, 0x9d, 0xb6, 0x52, 0x68, 0x5f, 0xf9, 0x59, 0xc8, 0x84, 0x2b, + 0x39, 0x22, 0x8f, 0x02, 0x41, 0x00, 0xb2, 0x04, 0xe2, 0x0e, 0x56, 0xca, + 0x03, 0x1a, 0xc0, 0xf9, 0x12, 0x92, 0xa5, 0x6b, 0x42, 0xb8, 0x1c, 0xda, + 0x4d, 0x93, 0x9d, 0x5f, 0x6f, 0xfd, 0xc5, 0x58, 0xda, 0x55, 0x98, 0x74, + 0xfc, 0x28, 0x17, 0x93, 0x1b, 0x75, 0x9f, 0x50, 0x03, 0x7f, 0x7e, 0xae, + 0xc8, 0x95, 0x33, 0x75, 0x2c, 0xd6, 0xa4, 0x35, 0xb8, 0x06, 0x03, 0xba, + 0x08, 0x59, 0x2b, 0x17, 0x02, 0xdc, 0x4c, 0x7a, 0x50, 0x01, 0x02, 0x41, + 0x00, 0x9d, 0xdb, 0x39, 0x59, 0x09, 0xe4, 0x30, 0xa0, 0x24, 0xf5, 0xdb, + 0x2f, 0xf0, 0x2f, 0xf1, 0x75, 0x74, 0x0d, 0x5e, 0xb5, 0x11, 0x73, 0xb0, + 0x0a, 0xaa, 0x86, 0x4c, 0x0d, 0xff, 0x7e, 0x1d, 0xb4, 0x14, 0xd4, 0x09, + 0x91, 0x33, 0x5a, 0xfd, 0xa0, 0x58, 0x80, 0x9b, 0xbe, 0x78, 0x2e, 0x69, + 0x82, 0x15, 0x7c, 0x72, 0xf0, 0x7b, 0x18, 0x39, 0xff, 0x6e, 0xeb, 0xc6, + 0x86, 0xf5, 0xb4, 0xc7, 0x6f, 0x02, 0x41, 0x00, 0x8d, 0x1a, 0x37, 0x0f, + 0x76, 0xc4, 0x82, 0xfa, 0x5c, 0xc3, 0x79, 0x35, 0x3e, 0x70, 0x8a, 0xbf, + 0x27, 0x49, 0xb0, 0x99, 0x63, 0xcb, 0x77, 0x5f, 0xa8, 0x82, 0x65, 0xf6, + 0x03, 0x52, 0x51, 0xf1, 0xae, 0x2e, 0x05, 0xb3, 0xc6, 0xa4, 0x92, 0xd1, + 0xce, 0x6c, 0x72, 0xfb, 0x21, 0xb3, 0x02, 0x87, 0xe4, 0xfd, 0x61, 0xca, + 0x00, 0x42, 0x19, 0xf0, 0xda, 0x5a, 0x53, 0xe3, 0xb1, 0xc5, 0x15, 0xf3, + }; + + std::unique_ptr<crypto::ECPrivateKey> key = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(std::vector<uint8_t>( + std::begin(kPrivateKeyInfo), std::end(kPrivateKeyInfo))); + EXPECT_FALSE(key); +} + +TEST(ECPrivateKeyUnitTest, LoadNSSKeyTest) { + static const uint8_t kNSSKey[] = { + 0x30, 0x81, 0xb8, 0x30, 0x23, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x15, 0x04, 0x10, 0x3f, 0xac, 0xe9, + 0x38, 0xdb, 0x40, 0x6b, 0x26, 0x89, 0x09, 0x73, 0x18, 0x8d, 0x7f, 0x1c, + 0x82, 0x02, 0x01, 0x01, 0x04, 0x81, 0x90, 0x5e, 0x5e, 0x11, 0xef, 0xbb, + 0x7c, 0x4d, 0xec, 0xc0, 0xdc, 0xc7, 0x23, 0xd2, 0xc4, 0x77, 0xbc, 0xf4, + 0x5d, 0x59, 0x4c, 0x07, 0xc2, 0x8a, 0x26, 0xfa, 0x25, 0x1c, 0xaa, 0x42, + 0xed, 0xd0, 0xed, 0xbb, 0x5c, 0xe9, 0x13, 0x07, 0xaa, 0xdd, 0x52, 0x3c, + 0x65, 0x25, 0xbf, 0x94, 0x02, 0xaf, 0xd6, 0x97, 0xe9, 0x33, 0x00, 0x76, + 0x64, 0x4a, 0x73, 0xab, 0xfb, 0x99, 0x6e, 0x83, 0x12, 0x05, 0x86, 0x72, + 0x6c, 0xd5, 0xa4, 0xcf, 0xb1, 0xd5, 0x4d, 0x54, 0x87, 0x8b, 0x4b, 0x95, + 0x1d, 0xcd, 0xf3, 0xfe, 0xa8, 0xda, 0xe0, 0xb6, 0x72, 0x13, 0x3f, 0x2e, + 0x66, 0xe0, 0xb9, 0x2e, 0xfa, 0x69, 0x40, 0xbe, 0xd7, 0x67, 0x6e, 0x53, + 0x2b, 0x3f, 0x53, 0xe5, 0x39, 0x54, 0x77, 0xe1, 0x1d, 0xe6, 0x81, 0x92, + 0x58, 0x82, 0x14, 0xfb, 0x47, 0x85, 0x3c, 0xc3, 0xdf, 0xdd, 0xcc, 0x79, + 0x9f, 0x41, 0x83, 0x72, 0xf2, 0x0a, 0xe9, 0xe1, 0x2c, 0x12, 0xb0, 0xb0, + 0x0a, 0xb2, 0x1d, 0xca, 0x15, 0xb2, 0xca, + }; + + std::unique_ptr<crypto::ECPrivateKey> keypair_nss( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + std::vector<uint8_t>(std::begin(kNSSKey), std::end(kNSSKey)))); + + EXPECT_TRUE(keypair_nss); +} + +TEST(ECPrivateKeyUnitTest, LoadOpenSSLKeyTest) { + static const uint8_t kOpenSSLKey[] = { + 0x30, 0x81, 0xb0, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0d, 0x04, 0x08, 0xb2, 0xfe, 0x68, + 0xc2, 0xea, 0x0f, 0x10, 0x9c, 0x02, 0x01, 0x01, 0x04, 0x81, 0x90, 0xe2, + 0xf6, 0x1c, 0xca, 0xad, 0x64, 0x30, 0xbf, 0x88, 0x04, 0x35, 0xe5, 0x0f, + 0x11, 0x49, 0x06, 0x01, 0x14, 0x33, 0x80, 0xa2, 0x78, 0x44, 0x5b, 0xaa, + 0x0d, 0xd7, 0x00, 0x36, 0x9d, 0x91, 0x97, 0x37, 0x20, 0x7b, 0x27, 0xc1, + 0xa0, 0xa2, 0x73, 0x06, 0x15, 0xdf, 0xc8, 0x13, 0x9b, 0xc9, 0x8c, 0x9c, + 0xce, 0x00, 0xd0, 0xc8, 0x42, 0xc1, 0xda, 0x2b, 0x07, 0x2b, 0x12, 0xa3, + 0xce, 0x10, 0x39, 0x7a, 0xf1, 0x55, 0x69, 0x8d, 0xa5, 0xc4, 0x2a, 0x00, + 0x0d, 0x94, 0xc6, 0xde, 0x6a, 0x3d, 0xb7, 0xe5, 0x6d, 0x59, 0x3e, 0x09, + 0xb5, 0xe3, 0x3e, 0xfc, 0x50, 0x56, 0xe9, 0x50, 0x42, 0x7c, 0xe7, 0xf0, + 0x19, 0xbd, 0x31, 0xa7, 0x85, 0x47, 0xb3, 0xe9, 0xb3, 0x50, 0x3c, 0xc9, + 0x32, 0x37, 0x1a, 0x93, 0x78, 0x48, 0x78, 0x82, 0xde, 0xad, 0x5c, 0xf2, + 0xcf, 0xf2, 0xbb, 0x2c, 0x44, 0x05, 0x7f, 0x4a, 0xf9, 0xb1, 0x2b, 0xdd, + 0x49, 0xf6, 0x7e, 0xd0, 0x42, 0xaa, 0x14, 0x3c, 0x24, 0x77, 0xb4, + }; + static const uint8_t kOpenSSLPublicKey[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, + 0x67, 0xe7, 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34, + 0xf6, 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6, 0x50, + 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56, 0xfb, 0x33, + 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27, 0xc5, 0xaa, 0x44, + 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d, + }; + static const uint8_t kOpenSSLRawPublicKey[] = { + 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, 0x67, 0xe7, + 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34, 0xf6, + 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6, 0x50, + 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56, 0xfb, + 0x33, 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27, 0xc5, + 0xaa, 0x44, 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d, + }; + + std::unique_ptr<crypto::ECPrivateKey> keypair_openssl( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + std::vector<uint8_t>(std::begin(kOpenSSLKey), + std::end(kOpenSSLKey)))); + + EXPECT_TRUE(keypair_openssl); + + std::vector<uint8_t> public_key; + EXPECT_TRUE(keypair_openssl->ExportPublicKey(&public_key)); + EXPECT_EQ(std::vector<uint8_t>(std::begin(kOpenSSLPublicKey), + std::end(kOpenSSLPublicKey)), + public_key); + + std::string raw_public_key; + EXPECT_TRUE(keypair_openssl->ExportRawPublicKey(&raw_public_key)); + EXPECT_EQ(std::string(reinterpret_cast<const char*>(kOpenSSLRawPublicKey), + arraysize(kOpenSSLRawPublicKey)), + raw_public_key); +} + +// The Android code writes out Channel IDs differently from the NSS +// implementation; the empty password is converted to "\0\0". The OpenSSL port +// should support either. +TEST(ECPrivateKeyUnitTest, LoadOldOpenSSLKeyTest) { + static const uint8_t kOpenSSLKey[] = { + 0x30, 0x82, 0x01, 0xa1, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0d, 0x04, 0x08, 0x86, 0xaa, + 0xd7, 0xdf, 0x3b, 0x91, 0x97, 0x60, 0x02, 0x01, 0x01, 0x04, 0x82, 0x01, + 0x80, 0xcb, 0x2a, 0x14, 0xaa, 0x4f, 0x38, 0x4c, 0xe1, 0x49, 0x00, 0xe2, + 0x1a, 0x3a, 0x75, 0x87, 0x7e, 0x3d, 0xea, 0x4d, 0x53, 0xd4, 0x46, 0x47, + 0x23, 0x8f, 0xa1, 0x72, 0x51, 0x92, 0x86, 0x8b, 0xeb, 0x53, 0xe6, 0x6a, + 0x0a, 0x6b, 0xb6, 0xa0, 0xdc, 0x0f, 0xdc, 0x20, 0xc3, 0x45, 0x85, 0xf1, + 0x95, 0x90, 0x5c, 0xf4, 0xfa, 0xee, 0x47, 0xaf, 0x35, 0xd0, 0xd0, 0xd3, + 0x14, 0xde, 0x0d, 0xca, 0x1b, 0xd3, 0xbb, 0x20, 0xec, 0x9d, 0x6a, 0xd4, + 0xc1, 0xce, 0x60, 0x81, 0xab, 0x0c, 0x72, 0x10, 0xfa, 0x28, 0x3c, 0xac, + 0x87, 0x7b, 0x82, 0x85, 0x00, 0xb8, 0x58, 0x9c, 0x07, 0xc4, 0x7d, 0xa9, + 0xc5, 0x94, 0x95, 0xf7, 0x23, 0x93, 0x3f, 0xed, 0xef, 0x92, 0x55, 0x25, + 0x74, 0xbb, 0xd3, 0xd1, 0x67, 0x3b, 0x3d, 0x5a, 0xfe, 0x84, 0xf8, 0x97, + 0x7d, 0x7c, 0x01, 0xc7, 0xd7, 0x0d, 0xf8, 0xc3, 0x6d, 0xd6, 0xf1, 0xaa, + 0x9d, 0x1f, 0x69, 0x97, 0x45, 0x06, 0xc4, 0x1c, 0x95, 0x3c, 0xe0, 0xef, + 0x11, 0xb2, 0xb3, 0x72, 0x91, 0x9e, 0x7d, 0x0f, 0x7f, 0xc8, 0xf6, 0x64, + 0x49, 0x5e, 0x3c, 0x53, 0x37, 0x79, 0x03, 0x1c, 0x3f, 0x29, 0x6c, 0x6b, + 0xea, 0x4c, 0x35, 0x9b, 0x6d, 0x1b, 0x59, 0x43, 0x4c, 0x14, 0x47, 0x2a, + 0x36, 0x39, 0x2a, 0xd8, 0x96, 0x90, 0xdc, 0xfc, 0xd2, 0xdd, 0x23, 0x0e, + 0x2c, 0xb3, 0x83, 0xf9, 0xf2, 0xe3, 0xe6, 0x99, 0x53, 0x57, 0x33, 0xc5, + 0x5f, 0xf9, 0xfd, 0x56, 0x0b, 0x32, 0xd4, 0xf3, 0x9d, 0x5b, 0x34, 0xe5, + 0x94, 0xbf, 0xb6, 0xc0, 0xce, 0xe1, 0x73, 0x5c, 0x02, 0x7a, 0x4c, 0xed, + 0xde, 0x23, 0x38, 0x89, 0x9f, 0xcd, 0x51, 0xf3, 0x90, 0x80, 0xd3, 0x4b, + 0x83, 0xd3, 0xee, 0xf2, 0x9e, 0x35, 0x91, 0xa5, 0xa3, 0xc0, 0x5c, 0xce, + 0xdb, 0xaa, 0x70, 0x1e, 0x1d, 0xc1, 0x44, 0xea, 0x3b, 0xa7, 0x5a, 0x11, + 0xd1, 0xf3, 0xf3, 0xd0, 0xf4, 0x5a, 0xc4, 0x99, 0xaf, 0x8d, 0xe2, 0xbc, + 0xa2, 0xb9, 0x3d, 0x86, 0x5e, 0xba, 0xa0, 0xdf, 0x78, 0x81, 0x7c, 0x54, + 0x31, 0xe3, 0x98, 0xb5, 0x46, 0xcb, 0x4d, 0x26, 0x4b, 0xf8, 0xac, 0x3a, + 0x54, 0x1b, 0x77, 0x5a, 0x18, 0xa5, 0x43, 0x0e, 0x14, 0xde, 0x7b, 0xb7, + 0x4e, 0x45, 0x99, 0x03, 0xd1, 0x3d, 0x18, 0xb2, 0x36, 0x00, 0x48, 0x07, + 0x72, 0xbb, 0x4f, 0x21, 0x25, 0x3e, 0xda, 0x25, 0x24, 0x5b, 0xc8, 0xa0, + 0x28, 0xd5, 0x9b, 0x96, 0x87, 0x07, 0x77, 0x84, 0xff, 0xd7, 0xac, 0x71, + 0xf6, 0x61, 0x63, 0x0b, 0xfb, 0x42, 0xfd, 0x52, 0xf4, 0xc4, 0x35, 0x0c, + 0xc2, 0xc1, 0x55, 0x22, 0x42, 0x2f, 0x13, 0x7d, 0x93, 0x27, 0xc8, 0x11, + 0x35, 0xc5, 0xe3, 0xc5, 0xaa, 0x15, 0x3c, 0xac, 0x30, 0xbc, 0x45, 0x16, + 0xed, + }; + + std::unique_ptr<crypto::ECPrivateKey> keypair_openssl( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + std::vector<uint8_t>(std::begin(kOpenSSLKey), + std::end(kOpenSSLKey)))); + + EXPECT_TRUE(keypair_openssl); +}
diff --git a/src/crypto/ec_signature_creator.cc b/src/crypto/ec_signature_creator.cc index a6887bc..339a81a 100644 --- a/src/crypto/ec_signature_creator.cc +++ b/src/crypto/ec_signature_creator.cc
@@ -5,21 +5,23 @@ #include "crypto/ec_signature_creator.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "crypto/ec_signature_creator_impl.h" namespace crypto { namespace { -ECSignatureCreatorFactory* g_factory_ = NULL; +ECSignatureCreatorFactory* g_factory_ = nullptr; } // namespace // static -ECSignatureCreator* ECSignatureCreator::Create(ECPrivateKey* key) { +std::unique_ptr<ECSignatureCreator> ECSignatureCreator::Create( + ECPrivateKey* key) { if (g_factory_) return g_factory_->Create(key); - return new ECSignatureCreatorImpl(key); + return std::make_unique<ECSignatureCreatorImpl>(key); } // static
diff --git a/src/crypto/ec_signature_creator.h b/src/crypto/ec_signature_creator.h index 16e64f5..632bd3c 100644 --- a/src/crypto/ec_signature_creator.h +++ b/src/crypto/ec_signature_creator.h
@@ -5,11 +5,12 @@ #ifndef CRYPTO_EC_SIGNATURE_CREATOR_H_ #define CRYPTO_EC_SIGNATURE_CREATOR_H_ +#include <memory> #include <string> #include <vector> -#include "base/basictypes.h" #include "crypto/crypto_export.h" +#include "starboard/types.h" namespace crypto { @@ -20,7 +21,7 @@ public: virtual ~ECSignatureCreatorFactory() {} - virtual ECSignatureCreator* Create(ECPrivateKey* key) = 0; + virtual std::unique_ptr<ECSignatureCreator> Create(ECPrivateKey* key) = 0; }; // Signs data using a bare private key (as opposed to a full certificate). @@ -34,7 +35,7 @@ // instance outlives the created ECSignatureCreator. // TODO(rch): This is currently hard coded to use SHA256. Ideally, we should // pass in the hash algorithm identifier. - static ECSignatureCreator* Create(ECPrivateKey* key); + static std::unique_ptr<ECSignatureCreator> Create(ECPrivateKey* key); // Set a factory to make the Create function return non-standard // ECSignatureCreator objects. Because the ECDSA algorithm involves @@ -48,17 +49,17 @@ // ECDSA-Sig-Value ::= SEQUENCE { // r INTEGER, // s INTEGER } - virtual bool Sign(const uint8* data, + virtual bool Sign(const uint8_t* data, int data_len, - std::vector<uint8>* signature) = 0; + std::vector<uint8_t>* signature) = 0; // DecodeSignature converts from a DER encoded ECDSA-Sig-Value (as produced // by Sign) to a `raw' ECDSA signature which consists of a pair of // big-endian, zero-padded, 256-bit integers, r and s. On success it returns // true and puts the raw signature into |out_raw_sig|. // (Only P-256 signatures are supported.) - virtual bool DecodeSignature(const std::vector<uint8>& signature, - std::vector<uint8>* out_raw_sig) = 0; + virtual bool DecodeSignature(const std::vector<uint8_t>& signature, + std::vector<uint8_t>* out_raw_sig) = 0; }; } // namespace crypto
diff --git a/src/crypto/ec_signature_creator_impl.cc b/src/crypto/ec_signature_creator_impl.cc new file mode 100644 index 0000000..1aa26a6 --- /dev/null +++ b/src/crypto/ec_signature_creator_impl.cc
@@ -0,0 +1,74 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/ec_signature_creator_impl.h" + +#include "base/logging.h" +#include "crypto/ec_private_key.h" +#include "crypto/openssl_util.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/bn.h" +#include "third_party/boringssl/src/include/openssl/ec.h" +#include "third_party/boringssl/src/include/openssl/ecdsa.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/sha.h" + +namespace crypto { + +ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key) + : key_(key) { + EnsureOpenSSLInit(); +} + +ECSignatureCreatorImpl::~ECSignatureCreatorImpl() = default; + +bool ECSignatureCreatorImpl::Sign(const uint8_t* data, + int data_len, + std::vector<uint8_t>* signature) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + bssl::ScopedEVP_MD_CTX ctx; + size_t sig_len = 0; + if (!ctx.get() || + !EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, + key_->key()) || + !EVP_DigestSignUpdate(ctx.get(), data, data_len) || + !EVP_DigestSignFinal(ctx.get(), nullptr, &sig_len)) { + return false; + } + + signature->resize(sig_len); + if (!EVP_DigestSignFinal(ctx.get(), &signature->front(), &sig_len)) + return false; + + // NOTE: A call to EVP_DigestSignFinal() with a nullptr second parameter + // returns a maximum allocation size, while the call without a nullptr + // returns the real one, which may be smaller. + signature->resize(sig_len); + return true; +} + +bool ECSignatureCreatorImpl::DecodeSignature( + const std::vector<uint8_t>& der_sig, + std::vector<uint8_t>* out_raw_sig) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + // Create ECDSA_SIG object from DER-encoded data. + bssl::UniquePtr<ECDSA_SIG> ecdsa_sig( + ECDSA_SIG_from_bytes(der_sig.data(), der_sig.size())); + if (!ecdsa_sig.get()) + return false; + + // The result is made of two 32-byte vectors. + const size_t kMaxBytesPerBN = 32; + std::vector<uint8_t> result(2 * kMaxBytesPerBN); + + if (!BN_bn2bin_padded(&result[0], kMaxBytesPerBN, ecdsa_sig->r) || + !BN_bn2bin_padded(&result[kMaxBytesPerBN], kMaxBytesPerBN, + ecdsa_sig->s)) { + return false; + } + out_raw_sig->swap(result); + return true; +} + +} // namespace crypto
diff --git a/src/crypto/ec_signature_creator_impl.h b/src/crypto/ec_signature_creator_impl.h index f2ef9d6..26d58cf 100644 --- a/src/crypto/ec_signature_creator_impl.h +++ b/src/crypto/ec_signature_creator_impl.h
@@ -5,26 +5,29 @@ #ifndef CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_ #define CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_ +#include <vector> + #include "base/compiler_specific.h" +#include "base/macros.h" #include "crypto/ec_signature_creator.h" +#include "starboard/types.h" namespace crypto { class ECSignatureCreatorImpl : public ECSignatureCreator { public: explicit ECSignatureCreatorImpl(ECPrivateKey* key); - virtual ~ECSignatureCreatorImpl(); + ~ECSignatureCreatorImpl() override; - virtual bool Sign(const uint8* data, - int data_len, - std::vector<uint8>* signature) override; + bool Sign(const uint8_t* data, + int data_len, + std::vector<uint8_t>* signature) override; - virtual bool DecodeSignature(const std::vector<uint8>& der_sig, - std::vector<uint8>* out_raw_sig) override; + bool DecodeSignature(const std::vector<uint8_t>& der_sig, + std::vector<uint8_t>* out_raw_sig) override; private: ECPrivateKey* key_; - size_t signature_len_; DISALLOW_COPY_AND_ASSIGN(ECSignatureCreatorImpl); };
diff --git a/src/crypto/ec_signature_creator_openssl.cc b/src/crypto/ec_signature_creator_openssl.cc deleted file mode 100644 index 8854f5e..0000000 --- a/src/crypto/ec_signature_creator_openssl.cc +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/ec_signature_creator_impl.h" - -#include "base/logging.h" - -namespace crypto { - -ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key) - : key_(key) { - NOTIMPLEMENTED(); -} - -ECSignatureCreatorImpl::~ECSignatureCreatorImpl() {} - -bool ECSignatureCreatorImpl::Sign(const uint8* data, - int data_len, - std::vector<uint8>* signature) { - NOTIMPLEMENTED(); - return false; -} - -bool ECSignatureCreatorImpl::DecodeSignature(const std::vector<uint8>& der_sig, - std::vector<uint8>* out_raw_sig) { - NOTIMPLEMENTED(); - return false; -} - -} // namespace crypto
diff --git a/src/crypto/ec_signature_creator_unittest.cc b/src/crypto/ec_signature_creator_unittest.cc index 9489e3a..f322ae1 100644 --- a/src/crypto/ec_signature_creator_unittest.cc +++ b/src/crypto/ec_signature_creator_unittest.cc
@@ -4,62 +4,48 @@ #include "crypto/ec_signature_creator.h" +#include <memory> #include <string> #include <vector> -#include "base/memory/scoped_ptr.h" #include "crypto/ec_private_key.h" #include "crypto/signature_verifier.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_OPENSSL) -// Once ECSignatureCreator is implemented for OpenSSL, remove this #if block. -// TODO(rch): When that happens, also add some exported keys from each to +// TODO(rch): Add some exported keys from each to // test interop between NSS and OpenSSL. -TEST(ECSignatureCreatorTest, OpenSSLStub) { - scoped_ptr<crypto::ECSignatureCreator> signer( - crypto::ECSignatureCreator::Create(NULL)); - ASSERT_TRUE(signer.get()); - EXPECT_FALSE(signer->Sign(NULL, 0, NULL)); -} -#else + TEST(ECSignatureCreatorTest, BasicTest) { // Do a verify round trip. - scoped_ptr<crypto::ECPrivateKey> key_original( + std::unique_ptr<crypto::ECPrivateKey> key_original( crypto::ECPrivateKey::Create()); - ASSERT_TRUE(key_original.get()); + ASSERT_TRUE(key_original); - std::vector<uint8> key_info; - ASSERT_TRUE(key_original->ExportEncryptedPrivateKey("", 1000, &key_info)); - std::vector<uint8> pubkey_info; - ASSERT_TRUE(key_original->ExportPublicKey(&pubkey_info)); + std::vector<uint8_t> key_info; + ASSERT_TRUE(key_original->ExportPrivateKey(&key_info)); - scoped_ptr<crypto::ECPrivateKey> key( - crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo("", key_info, - pubkey_info)); - ASSERT_TRUE(key.get()); - ASSERT_TRUE(key->key() != NULL); + std::unique_ptr<crypto::ECPrivateKey> key( + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(key_info)); + ASSERT_TRUE(key); + ASSERT_TRUE(key->key()); - scoped_ptr<crypto::ECSignatureCreator> signer( + std::unique_ptr<crypto::ECSignatureCreator> signer( crypto::ECSignatureCreator::Create(key.get())); - ASSERT_TRUE(signer.get()); + ASSERT_TRUE(signer); std::string data("Hello, World!"); - std::vector<uint8> signature; - ASSERT_TRUE(signer->Sign(reinterpret_cast<const uint8*>(data.c_str()), - data.size(), - &signature)); + std::vector<uint8_t> signature; + ASSERT_TRUE(signer->Sign(reinterpret_cast<const uint8_t*>(data.c_str()), + data.size(), &signature)); - std::vector<uint8> public_key_info; + std::vector<uint8_t> public_key_info; ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info)); crypto::SignatureVerifier verifier; - ASSERT_TRUE(verifier.VerifyInit( - crypto::SignatureVerifier::ECDSA_SHA256, &signature[0], signature.size(), - &public_key_info.front(), public_key_info.size())); + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256, + signature, public_key_info)); - verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()), - data.size()); + verifier.VerifyUpdate(base::as_bytes(base::make_span(data))); ASSERT_TRUE(verifier.VerifyFinal()); } -#endif // !defined(USE_OPENSSL)
diff --git a/src/crypto/encryptor.cc b/src/crypto/encryptor.cc index a673f81..390f287 100644 --- a/src/crypto/encryptor.cc +++ b/src/crypto/encryptor.cc
@@ -5,24 +5,60 @@ #include "crypto/encryptor.h" #include "base/logging.h" +#include "base/strings/string_util.h" #include "base/sys_byteorder.h" +#include "crypto/openssl_util.h" +#include "crypto/symmetric_key.h" +#include "starboard/memory.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/aes.h" +#include "third_party/boringssl/src/include/openssl/evp.h" namespace crypto { +namespace { + +const EVP_CIPHER* GetCipherForKey(const SymmetricKey* key) { + switch (key->key().length()) { + case 16: return EVP_aes_128_cbc(); + case 32: return EVP_aes_256_cbc(); + default: + return nullptr; + } +} + +// On destruction this class will cleanup the ctx, and also clear the OpenSSL +// ERR stack as a convenience. +class ScopedCipherCTX { + public: + ScopedCipherCTX() { + EVP_CIPHER_CTX_init(&ctx_); + } + ~ScopedCipherCTX() { + EVP_CIPHER_CTX_cleanup(&ctx_); + ClearOpenSSLERRStack(FROM_HERE); + } + EVP_CIPHER_CTX* get() { return &ctx_; } + + private: + EVP_CIPHER_CTX ctx_; +}; + +} // namespace + ///////////////////////////////////////////////////////////////////////////// // Encyptor::Counter Implementation. -Encryptor::Counter::Counter(const base::StringPiece& counter) { +Encryptor::Counter::Counter(base::StringPiece counter) { CHECK(sizeof(counter_) == counter.length()); - memcpy(&counter_, counter.data(), sizeof(counter_)); + SbMemoryCopy(&counter_, counter.data(), sizeof(counter_)); } -Encryptor::Counter::~Counter() { -} +Encryptor::Counter::~Counter() = default; bool Encryptor::Counter::Increment() { - uint64 low_num = base::NetToHost64(counter_.components64[1]); - uint64 new_low_num = low_num + 1; + uint64_t low_num = base::NetToHost64(counter_.components64[1]); + uint64_t new_low_num = low_num + 1; counter_.components64[1] = base::HostToNet64(new_low_num); // If overflow occured then increment the most significant component. @@ -36,8 +72,8 @@ } void Encryptor::Counter::Write(void* buf) { - uint8* buf_ptr = reinterpret_cast<uint8*>(buf); - memcpy(buf_ptr, &counter_, sizeof(counter_)); + uint8_t* buf_ptr = reinterpret_cast<uint8_t*>(buf); + SbMemoryCopy(buf_ptr, &counter_, sizeof(counter_)); } size_t Encryptor::Counter::GetLengthInBytes() const { @@ -45,9 +81,44 @@ } ///////////////////////////////////////////////////////////////////////////// -// Partial Encryptor Implementation. +// Encryptor Implementation. -bool Encryptor::SetCounter(const base::StringPiece& counter) { +Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {} + +Encryptor::~Encryptor() = default; + +bool Encryptor::Init(const SymmetricKey* key, Mode mode, base::StringPiece iv) { + DCHECK(key); + DCHECK(mode == CBC || mode == CTR); + + EnsureOpenSSLInit(); + if (mode == CBC && iv.size() != AES_BLOCK_SIZE) + return false; + + if (GetCipherForKey(key) == nullptr) + return false; + + key_ = key; + mode_ = mode; + iv.CopyToString(&iv_); + return true; +} + +bool Encryptor::Encrypt(base::StringPiece plaintext, std::string* ciphertext) { + CHECK(!plaintext.empty() || (mode_ == CBC)); + return (mode_ == CTR) ? + CryptCTR(true, plaintext, ciphertext) : + Crypt(true, plaintext, ciphertext); +} + +bool Encryptor::Decrypt(base::StringPiece ciphertext, std::string* plaintext) { + CHECK(!ciphertext.empty()); + return (mode_ == CTR) ? + CryptCTR(false, ciphertext, plaintext) : + Crypt(false, ciphertext, plaintext); +} + +bool Encryptor::SetCounter(base::StringPiece counter) { if (mode_ != CTR) return false; if (counter.length() != 16u) @@ -57,41 +128,92 @@ return true; } -bool Encryptor::GenerateCounterMask(size_t plaintext_len, - uint8* mask, - size_t* mask_len) { - DCHECK_EQ(CTR, mode_); - CHECK(mask); - CHECK(mask_len); +bool Encryptor::Crypt(bool do_encrypt, + base::StringPiece input, + std::string* output) { + DCHECK(key_); // Must call Init() before En/De-crypt. + // Work on the result in a local variable, and then only transfer it to + // |output| on success to ensure no partial data is returned. + std::string result; + output->clear(); - const size_t kBlockLength = counter_->GetLengthInBytes(); - size_t blocks = (plaintext_len + kBlockLength - 1) / kBlockLength; - CHECK(blocks); + const EVP_CIPHER* cipher = GetCipherForKey(key_); + DCHECK(cipher); // Already handled in Init(); - *mask_len = blocks * kBlockLength; + const std::string& key = key_->key(); + DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.length()); + DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.length()); - for (size_t i = 0; i < blocks; ++i) { - counter_->Write(mask); - mask += kBlockLength; + ScopedCipherCTX ctx; + if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, + reinterpret_cast<const uint8_t*>(key.data()), + reinterpret_cast<const uint8_t*>(iv_.data()), + do_encrypt)) + return false; - bool ret = counter_->Increment(); - if (!ret) - return false; - } + // When encrypting, add another block size of space to allow for any padding. + const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0); + CHECK_GT(output_size, 0u); + CHECK_GT(output_size + 1, input.size()); + uint8_t* out_ptr = + reinterpret_cast<uint8_t*>(base::WriteInto(&result, output_size + 1)); + int out_len; + if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len, + reinterpret_cast<const uint8_t*>(input.data()), + input.length())) + return false; + + // Write out the final block plus padding (if any) to the end of the data + // just written. + int tail_len; + if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len)) + return false; + + out_len += tail_len; + DCHECK_LE(out_len, static_cast<int>(output_size)); + result.resize(out_len); + + output->swap(result); return true; } -void Encryptor::MaskMessage(const void* plaintext, - size_t plaintext_len, - const void* mask, - void* ciphertext) const { - DCHECK_EQ(CTR, mode_); - const uint8* plaintext_ptr = reinterpret_cast<const uint8*>(plaintext); - const uint8* mask_ptr = reinterpret_cast<const uint8*>(mask); - uint8* ciphertext_ptr = reinterpret_cast<uint8*>(ciphertext); +bool Encryptor::CryptCTR(bool do_encrypt, + base::StringPiece input, + std::string* output) { + if (!counter_.get()) { + LOG(ERROR) << "Counter value not set in CTR mode."; + return false; + } - for (size_t i = 0; i < plaintext_len; ++i) - ciphertext_ptr[i] = plaintext_ptr[i] ^ mask_ptr[i]; + AES_KEY aes_key; + if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()), + key_->key().size() * 8, &aes_key) != 0) { + return false; + } + + const size_t out_size = input.size(); + CHECK_GT(out_size, 0u); + CHECK_GT(out_size + 1, input.size()); + + std::string result; + uint8_t* out_ptr = + reinterpret_cast<uint8_t*>(base::WriteInto(&result, out_size + 1)); + + uint8_t ivec[AES_BLOCK_SIZE] = { 0 }; + uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 }; + unsigned int block_offset = 0; + + counter_->Write(ivec); + + AES_ctr128_encrypt(reinterpret_cast<const uint8_t*>(input.data()), out_ptr, + input.size(), &aes_key, ivec, ecount_buf, &block_offset); + + // AES_ctr128_encrypt() updates |ivec|. Update the |counter_| here. + SetCounter(base::StringPiece(reinterpret_cast<const char*>(ivec), + AES_BLOCK_SIZE)); + + output->swap(result); + return true; } } // namespace crypto
diff --git a/src/crypto/encryptor.h b/src/crypto/encryptor.h index 798a26f..7034eda 100644 --- a/src/crypto/encryptor.h +++ b/src/crypto/encryptor.h
@@ -5,17 +5,13 @@ #ifndef CRYPTO_ENCRYPTOR_H_ #define CRYPTO_ENCRYPTOR_H_ +#include <memory> #include <string> -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/string_piece.h" +#include "base/strings/string_piece.h" #include "build/build_config.h" #include "crypto/crypto_export.h" - -#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) -#include "crypto/scoped_nss_types.h" -#endif +#include "starboard/types.h" namespace crypto { @@ -32,7 +28,7 @@ // Only 128-bits counter is supported in this class. class CRYPTO_EXPORT Counter { public: - explicit Counter(const base::StringPiece& counter); + explicit Counter(base::StringPiece counter); ~Counter(); // Increment the counter value. @@ -47,24 +43,24 @@ private: union { - uint32 components32[4]; - uint64 components64[2]; + uint32_t components32[4]; + uint64_t components64[2]; } counter_; }; Encryptor(); - virtual ~Encryptor(); + ~Encryptor(); // Initializes the encryptor using |key| and |iv|. Returns false if either the // key or the initialization vector cannot be used. // // If |mode| is CBC, |iv| must not be empty; if it is CTR, then |iv| must be // empty. - bool Init(SymmetricKey* key, Mode mode, const base::StringPiece& iv); + bool Init(const SymmetricKey* key, Mode mode, base::StringPiece iv); // Encrypts |plaintext| into |ciphertext|. |plaintext| may only be empty if // the mode is CBC. - bool Encrypt(const base::StringPiece& plaintext, std::string* ciphertext); + bool Encrypt(base::StringPiece plaintext, std::string* ciphertext); // Decrypts |ciphertext| into |plaintext|. |ciphertext| must not be empty. // @@ -75,58 +71,26 @@ // must either authenticate the ciphertext before decrypting it, or take // care to not report decryption failure. Otherwise it could inadvertently // be used as a padding oracle to attack the cryptosystem. - bool Decrypt(const base::StringPiece& ciphertext, std::string* plaintext); + bool Decrypt(base::StringPiece ciphertext, std::string* plaintext); // Sets the counter value when in CTR mode. Currently only 128-bits // counter value is supported. // // Returns true only if update was successful. - bool SetCounter(const base::StringPiece& counter); + bool SetCounter(base::StringPiece counter); // TODO(albertb): Support streaming encryption. private: - // Generates a mask using |counter_| to be used for encryption in CTR mode. - // Resulting mask will be written to |mask| with |mask_len| bytes. - // - // Make sure there's enough space in mask when calling this method. - // Reserve at least |plaintext_len| + 16 bytes for |mask|. - // - // The generated mask will always have at least |plaintext_len| bytes and - // will be a multiple of the counter length. - // - // This method is used only in CTR mode. - // - // Returns false if this call failed. - bool GenerateCounterMask(size_t plaintext_len, - uint8* mask, - size_t* mask_len); - - // Mask the |plaintext| message using |mask|. The output will be written to - // |ciphertext|. |ciphertext| must have at least |plaintext_len| bytes. - void MaskMessage(const void* plaintext, - size_t plaintext_len, - const void* mask, - void* ciphertext) const; - - SymmetricKey* key_; + const SymmetricKey* key_; Mode mode_; - scoped_ptr<Counter> counter_; + std::unique_ptr<Counter> counter_; -#if defined(USE_OPENSSL) - bool Crypt(bool encrypt, // Pass true to encrypt, false to decrypt. - const base::StringPiece& input, + bool Crypt(bool do_encrypt, // Pass true to encrypt, false to decrypt. + base::StringPiece input, std::string* output); + bool CryptCTR(bool do_encrypt, base::StringPiece input, std::string* output); std::string iv_; -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) - bool Crypt(PK11Context* context, - const base::StringPiece& input, - std::string* output); - bool CryptCTR(PK11Context* context, - const base::StringPiece& input, - std::string* output); - ScopedSECItem param_; -#endif }; } // namespace crypto
diff --git a/src/crypto/encryptor_openssl.cc b/src/crypto/encryptor_openssl.cc deleted file mode 100644 index cb26e22..0000000 --- a/src/crypto/encryptor_openssl.cc +++ /dev/null
@@ -1,135 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/encryptor.h" - -#include <openssl/aes.h> -#include <openssl/evp.h> - -#include "base/logging.h" -#include "base/string_util.h" -#include "crypto/openssl_util.h" -#include "crypto/symmetric_key.h" - -namespace crypto { - -namespace { - -const EVP_CIPHER* GetCipherForKey(SymmetricKey* key) { - switch (key->key().length()) { - case 16: return EVP_aes_128_cbc(); - case 24: return EVP_aes_192_cbc(); - case 32: return EVP_aes_256_cbc(); - default: return NULL; - } -} - -// On destruction this class will cleanup the ctx, and also clear the OpenSSL -// ERR stack as a convenience. -class ScopedCipherCTX { - public: - explicit ScopedCipherCTX() { - EVP_CIPHER_CTX_init(&ctx_); - } - ~ScopedCipherCTX() { - EVP_CIPHER_CTX_cleanup(&ctx_); - ClearOpenSSLERRStack(FROM_HERE); - } - EVP_CIPHER_CTX* get() { return &ctx_; } - - private: - EVP_CIPHER_CTX ctx_; -}; - -} // namespace - -Encryptor::Encryptor() - : key_(NULL), - mode_(CBC) { -} - -Encryptor::~Encryptor() { -} - -bool Encryptor::Init(SymmetricKey* key, - Mode mode, - const base::StringPiece& iv) { - DCHECK(key); - DCHECK_EQ(CBC, mode); - - EnsureOpenSSLInit(); - if (iv.size() != AES_BLOCK_SIZE) - return false; - - if (GetCipherForKey(key) == NULL) - return false; - - key_ = key; - mode_ = mode; - iv.CopyToString(&iv_); - return true; -} - -bool Encryptor::Encrypt(const base::StringPiece& plaintext, - std::string* ciphertext) { - CHECK(!plaintext.empty() || (mode_ == CBC)); - return Crypt(true, plaintext, ciphertext); -} - -bool Encryptor::Decrypt(const base::StringPiece& ciphertext, - std::string* plaintext) { - CHECK(!ciphertext.empty()); - return Crypt(false, ciphertext, plaintext); -} - -bool Encryptor::Crypt(bool do_encrypt, - const base::StringPiece& input, - std::string* output) { - DCHECK(key_); // Must call Init() before En/De-crypt. - // Work on the result in a local variable, and then only transfer it to - // |output| on success to ensure no partial data is returned. - std::string result; - output->clear(); - - const EVP_CIPHER* cipher = GetCipherForKey(key_); - DCHECK(cipher); // Already handled in Init(); - - const std::string& key = key_->key(); - DCHECK_EQ(EVP_CIPHER_iv_length(cipher), static_cast<int>(iv_.length())); - DCHECK_EQ(EVP_CIPHER_key_length(cipher), static_cast<int>(key.length())); - - ScopedCipherCTX ctx; - if (!EVP_CipherInit_ex(ctx.get(), cipher, NULL, - reinterpret_cast<const uint8*>(key.data()), - reinterpret_cast<const uint8*>(iv_.data()), - do_encrypt)) - return false; - - // When encrypting, add another block size of space to allow for any padding. - const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0); - CHECK_GT(output_size, 0u); - CHECK_GT(output_size + 1, input.size()); - uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result, - output_size + 1)); - int out_len; - if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len, - reinterpret_cast<const uint8*>(input.data()), - input.length())) - return false; - - // Write out the final block plus padding (if any) to the end of the data - // just written. - int tail_len; - if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len)) - return false; - - out_len += tail_len; - DCHECK_LE(out_len, static_cast<int>(output_size)); - result.resize(out_len); - - output->swap(result); - return true; -} - -} // namespace crypto
diff --git a/src/crypto/encryptor_unittest.cc b/src/crypto/encryptor_unittest.cc index b0ec4bc..f62947f 100644 --- a/src/crypto/encryptor_unittest.cc +++ b/src/crypto/encryptor_unittest.cc
@@ -4,18 +4,21 @@ #include "crypto/encryptor.h" +#include <memory> #include <string> -#include "base/memory/scoped_ptr.h" -#include "base/string_number_conversions.h" +#include "base/macros.h" +#include "base/strings/string_number_conversions.h" #include "crypto/symmetric_key.h" +#include "starboard/memory.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" TEST(EncryptorTest, EncryptDecrypt) { - scoped_ptr<crypto::SymmetricKey> key( - crypto::SymmetricKey::DeriveKeyFromPassword( + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( crypto::SymmetricKey::AES, "password", "saltiest", 1000, 256)); - EXPECT_TRUE(NULL != key.get()); + EXPECT_TRUE(key.get()); crypto::Encryptor encryptor; // The IV must be exactly as long as the cipher block size. @@ -29,37 +32,37 @@ EXPECT_LT(0U, ciphertext.size()); - std::string decypted; - EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decypted)); + std::string decrypted; + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); - EXPECT_EQ(plaintext, decypted); + EXPECT_EQ(plaintext, decrypted); } TEST(EncryptorTest, DecryptWrongKey) { - scoped_ptr<crypto::SymmetricKey> key( - crypto::SymmetricKey::DeriveKeyFromPassword( + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( crypto::SymmetricKey::AES, "password", "saltiest", 1000, 256)); - EXPECT_TRUE(NULL != key.get()); + EXPECT_TRUE(key.get()); // A wrong key that can be detected by implementations that validate every // byte in the padding. - scoped_ptr<crypto::SymmetricKey> wrong_key( - crypto::SymmetricKey::DeriveKeyFromPassword( - crypto::SymmetricKey::AES, "wrongword", "sweetest", 1000, 256)); - EXPECT_TRUE(NULL != wrong_key.get()); + std::unique_ptr<crypto::SymmetricKey> wrong_key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::AES, "wrongword", "sweetest", 1000, 256)); + EXPECT_TRUE(wrong_key.get()); // A wrong key that can't be detected by any implementation. The password // "wrongword;" would also work. - scoped_ptr<crypto::SymmetricKey> wrong_key2( - crypto::SymmetricKey::DeriveKeyFromPassword( - crypto::SymmetricKey::AES, "wrongword+", "sweetest", 1000, 256)); - EXPECT_TRUE(NULL != wrong_key2.get()); + std::unique_ptr<crypto::SymmetricKey> wrong_key2( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::AES, "wrongword+", "sweetest", 1000, 256)); + EXPECT_TRUE(wrong_key2.get()); // A wrong key that can be detected by all implementations. - scoped_ptr<crypto::SymmetricKey> wrong_key3( - crypto::SymmetricKey::DeriveKeyFromPassword( - crypto::SymmetricKey::AES, "wrongwordx", "sweetest", 1000, 256)); - EXPECT_TRUE(NULL != wrong_key3.get()); + std::unique_ptr<crypto::SymmetricKey> wrong_key3( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::AES, "wrongwordx", "sweetest", 1000, 256)); + EXPECT_TRUE(wrong_key3.get()); crypto::Encryptor encryptor; // The IV must be exactly as long as the cipher block size. @@ -84,7 +87,7 @@ static_cast<unsigned char>(ciphertext[i])); } - std::string decypted; + std::string decrypted; // This wrong key causes the last padding byte to be 5, which is a valid // padding length, and the second to last padding byte to be 137, which is @@ -92,35 +95,197 @@ // determine the padding length without checking every padding byte, // Encryptor::Decrypt() will still return true. This is the case for NSS // (crbug.com/124434). -#if !defined(USE_NSS) && !defined(OS_WIN) && !defined(OS_MACOSX) crypto::Encryptor decryptor; EXPECT_TRUE(decryptor.Init(wrong_key.get(), crypto::Encryptor::CBC, iv)); - EXPECT_FALSE(decryptor.Decrypt(ciphertext, &decypted)); -#endif + EXPECT_FALSE(decryptor.Decrypt(ciphertext, &decrypted)); // This demonstrates that not all wrong keys can be detected by padding // error. This wrong key causes the last padding byte to be 1, which is // a valid padding block of length 1. crypto::Encryptor decryptor2; EXPECT_TRUE(decryptor2.Init(wrong_key2.get(), crypto::Encryptor::CBC, iv)); - EXPECT_TRUE(decryptor2.Decrypt(ciphertext, &decypted)); + EXPECT_TRUE(decryptor2.Decrypt(ciphertext, &decrypted)); // This wrong key causes the last padding byte to be 253, which should be // rejected by all implementations. crypto::Encryptor decryptor3; EXPECT_TRUE(decryptor3.Init(wrong_key3.get(), crypto::Encryptor::CBC, iv)); - EXPECT_FALSE(decryptor3.Decrypt(ciphertext, &decypted)); + EXPECT_FALSE(decryptor3.Decrypt(ciphertext, &decrypted)); } -// CTR mode encryption is only implemented using NSS. -#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) +namespace { + +// From NIST SP 800-38a test cast: +// - F.5.1 CTR-AES128.Encrypt +// - F.5.6 CTR-AES256.Encrypt +// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +const unsigned char kAES128CTRKey[] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; + +const unsigned char kAES256CTRKey[] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 +}; + +const unsigned char kAESCTRInitCounter[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const unsigned char kAESCTRPlaintext[] = { + // Block #1 + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + // Block #2 + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + // Block #3 + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + // Block #4 + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; + +const unsigned char kAES128CTRCiphertext[] = { + // Block #1 + 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, + // Block #2 + 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, + 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff, + // Block #3 + 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, + 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab, + // Block #4 + 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, + 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee +}; + +const unsigned char kAES256CTRCiphertext[] = { + // Block #1 + 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, + 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28, + // Block #2 + 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, + 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5, + // Block #3 + 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, + 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d, + // Block #4 + 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, + 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6 +}; + +void TestAESCTREncrypt( + const unsigned char* key, size_t key_size, + const unsigned char* init_counter, size_t init_counter_size, + const unsigned char* plaintext, size_t plaintext_size, + const unsigned char* ciphertext, size_t ciphertext_size) { + std::string key_str(reinterpret_cast<const char*>(key), key_size); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key_str)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CTR, "")); + + base::StringPiece init_counter_str( + reinterpret_cast<const char*>(init_counter), init_counter_size); + base::StringPiece plaintext_str( + reinterpret_cast<const char*>(plaintext), plaintext_size); + + EXPECT_TRUE(encryptor.SetCounter(init_counter_str)); + std::string encrypted; + EXPECT_TRUE(encryptor.Encrypt(plaintext_str, &encrypted)); + + EXPECT_EQ(ciphertext_size, encrypted.size()); + EXPECT_EQ(0, SbMemoryCompare(encrypted.data(), ciphertext, encrypted.size())); + + std::string decrypted; + EXPECT_TRUE(encryptor.SetCounter(init_counter_str)); + EXPECT_TRUE(encryptor.Decrypt(encrypted, &decrypted)); + + EXPECT_EQ(plaintext_str, decrypted); +} + +void TestAESCTRMultipleDecrypt( + const unsigned char* key, size_t key_size, + const unsigned char* init_counter, size_t init_counter_size, + const unsigned char* plaintext, size_t plaintext_size, + const unsigned char* ciphertext, size_t ciphertext_size) { + std::string key_str(reinterpret_cast<const char*>(key), key_size); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key_str)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CTR, "")); + + // Counter is set only once. + EXPECT_TRUE(encryptor.SetCounter(base::StringPiece( + reinterpret_cast<const char*>(init_counter), init_counter_size))); + + std::string ciphertext_str(reinterpret_cast<const char*>(ciphertext), + ciphertext_size); + + int kTestDecryptSizes[] = { 32, 16, 8 }; + + int offset = 0; + for (size_t i = 0; i < arraysize(kTestDecryptSizes); ++i) { + std::string decrypted; + size_t len = kTestDecryptSizes[i]; + EXPECT_TRUE( + encryptor.Decrypt(ciphertext_str.substr(offset, len), &decrypted)); + EXPECT_EQ(len, decrypted.size()); + EXPECT_EQ(0, SbMemoryCompare(decrypted.data(), plaintext + offset, len)); + offset += len; + } +} + +} // namespace + +TEST(EncryptorTest, EncryptAES128CTR) { + TestAESCTREncrypt( + kAES128CTRKey, arraysize(kAES128CTRKey), + kAESCTRInitCounter, arraysize(kAESCTRInitCounter), + kAESCTRPlaintext, arraysize(kAESCTRPlaintext), + kAES128CTRCiphertext, arraysize(kAES128CTRCiphertext)); +} + +TEST(EncryptorTest, EncryptAES256CTR) { + TestAESCTREncrypt( + kAES256CTRKey, arraysize(kAES256CTRKey), + kAESCTRInitCounter, arraysize(kAESCTRInitCounter), + kAESCTRPlaintext, arraysize(kAESCTRPlaintext), + kAES256CTRCiphertext, arraysize(kAES256CTRCiphertext)); +} + +TEST(EncryptorTest, EncryptAES128CTR_MultipleDecrypt) { + TestAESCTRMultipleDecrypt( + kAES128CTRKey, arraysize(kAES128CTRKey), + kAESCTRInitCounter, arraysize(kAESCTRInitCounter), + kAESCTRPlaintext, arraysize(kAESCTRPlaintext), + kAES128CTRCiphertext, arraysize(kAES128CTRCiphertext)); +} + +TEST(EncryptorTest, EncryptAES256CTR_MultipleDecrypt) { + TestAESCTRMultipleDecrypt( + kAES256CTRKey, arraysize(kAES256CTRKey), + kAESCTRInitCounter, arraysize(kAESCTRInitCounter), + kAESCTRPlaintext, arraysize(kAESCTRPlaintext), + kAES256CTRCiphertext, arraysize(kAES256CTRCiphertext)); +} TEST(EncryptorTest, EncryptDecryptCTR) { - scoped_ptr<crypto::SymmetricKey> key( - crypto::SymmetricKey::GenerateRandomKey( - crypto::SymmetricKey::AES, 128)); + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 128)); - EXPECT_TRUE(NULL != key.get()); + EXPECT_TRUE(key.get()); const std::string kInitialCounter = "0000000000000000"; crypto::Encryptor encryptor; @@ -132,10 +297,10 @@ EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); EXPECT_LT(0U, ciphertext.size()); - std::string decypted; + std::string decrypted; EXPECT_TRUE(encryptor.SetCounter(kInitialCounter)); - EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decypted)); - EXPECT_EQ(plaintext, decypted); + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); + EXPECT_EQ(plaintext, decrypted); plaintext = "0123456789012345"; EXPECT_TRUE(encryptor.SetCounter(kInitialCounter)); @@ -143,8 +308,8 @@ EXPECT_LT(0U, ciphertext.size()); EXPECT_TRUE(encryptor.SetCounter(kInitialCounter)); - EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decypted)); - EXPECT_EQ(plaintext, decypted); + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); + EXPECT_EQ(plaintext, decrypted); } TEST(EncryptorTest, CTRCounter) { @@ -159,8 +324,8 @@ for (int i = 0; i < 10; ++i) counter1.Increment(); counter1.Write(buf); - EXPECT_EQ(0, memcmp(buf, kTest1, 15)); - EXPECT_TRUE(buf[15] == 10); + EXPECT_EQ(0, SbMemoryCompare(buf, kTest1, 15)); + EXPECT_EQ(10, buf[15]); // Check corner cases. const unsigned char kTest2[] = { @@ -173,7 +338,7 @@ std::string(reinterpret_cast<const char*>(kTest2), kCounterSize)); counter2.Increment(); counter2.Write(buf); - EXPECT_EQ(0, memcmp(buf, kExpect2, kCounterSize)); + EXPECT_EQ(0, SbMemoryCompare(buf, kExpect2, kCounterSize)); const unsigned char kTest3[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -185,11 +350,9 @@ std::string(reinterpret_cast<const char*>(kTest3), kCounterSize)); counter3.Increment(); counter3.Write(buf); - EXPECT_EQ(0, memcmp(buf, kExpect3, kCounterSize)); + EXPECT_EQ(0, SbMemoryCompare(buf, kExpect3, kCounterSize)); } -#endif - // TODO(wtc): add more known-answer tests. Test vectors are available from // http://www.ietf.org/rfc/rfc3602 // http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf @@ -199,17 +362,17 @@ // NIST SP 800-38A test vector F.2.5 CBC-AES256.Encrypt. TEST(EncryptorTest, EncryptAES256CBC) { // From NIST SP 800-38a test cast F.2.5 CBC-AES256.Encrypt. - static const unsigned char raw_key[] = { + static const unsigned char kRawKey[] = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 }; - static const unsigned char raw_iv[] = { + static const unsigned char kRawIv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; - static const unsigned char raw_plaintext[] = { + static const unsigned char kRawPlaintext[] = { // Block #1 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, @@ -223,7 +386,7 @@ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, }; - static const unsigned char raw_ciphertext[] = { + static const unsigned char kRawCiphertext[] = { // Block #1 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, @@ -241,29 +404,30 @@ 0xe0, 0xc2, 0xa7, 0x2b, 0x4d, 0x80, 0xe6, 0x44 }; - std::string key(reinterpret_cast<const char*>(raw_key), sizeof(raw_key)); - scoped_ptr<crypto::SymmetricKey> sym_key(crypto::SymmetricKey::Import( - crypto::SymmetricKey::AES, key)); - ASSERT_TRUE(NULL != sym_key.get()); + std::string key(reinterpret_cast<const char*>(kRawKey), sizeof(kRawKey)); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); crypto::Encryptor encryptor; // The IV must be exactly as long a the cipher block size. - std::string iv(reinterpret_cast<const char*>(raw_iv), sizeof(raw_iv)); + std::string iv(reinterpret_cast<const char*>(kRawIv), sizeof(kRawIv)); EXPECT_EQ(16U, iv.size()); EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); - std::string plaintext(reinterpret_cast<const char*>(raw_plaintext), - sizeof(raw_plaintext)); + std::string plaintext(reinterpret_cast<const char*>(kRawPlaintext), + sizeof(kRawPlaintext)); std::string ciphertext; EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); - EXPECT_EQ(sizeof(raw_ciphertext), ciphertext.size()); - EXPECT_EQ(0, memcmp(ciphertext.data(), raw_ciphertext, ciphertext.size())); + EXPECT_EQ(sizeof(kRawCiphertext), ciphertext.size()); + EXPECT_EQ( + 0, SbMemoryCompare(ciphertext.data(), kRawCiphertext, ciphertext.size())); - std::string decypted; - EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decypted)); + std::string decrypted; + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); - EXPECT_EQ(plaintext, decypted); + EXPECT_EQ(plaintext, decrypted); } // Expected output derived from the NSS implementation. @@ -275,9 +439,9 @@ "D4A67A0BA33C30F207344D81D1E944BBE65587C3D7D9939A" "C070C62B9C15A3EA312EA4AD1BC7929F4D3C16B03AD5ADA8"; - scoped_ptr<crypto::SymmetricKey> sym_key(crypto::SymmetricKey::Import( - crypto::SymmetricKey::AES, key)); - ASSERT_TRUE(NULL != sym_key.get()); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); crypto::Encryptor encryptor; // The IV must be exactly as long a the cipher block size. @@ -289,60 +453,33 @@ EXPECT_EQ(expected_ciphertext_hex, base::HexEncode(ciphertext.data(), ciphertext.size())); - std::string decypted; - EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decypted)); - EXPECT_EQ(plaintext, decypted); + std::string decrypted; + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); + EXPECT_EQ(plaintext, decrypted); } -// Expected output derived from the NSS implementation. -TEST(EncryptorTest, EncryptAES192CBCRegression) { - std::string key = "192bitsIsTwentyFourByte!"; - std::string iv = "Sweet Sixteen IV"; - std::string plaintext = "Small text"; - std::string expected_ciphertext_hex = "78DE5D7C2714FC5C61346C5416F6C89A"; - - scoped_ptr<crypto::SymmetricKey> sym_key(crypto::SymmetricKey::Import( - crypto::SymmetricKey::AES, key)); - ASSERT_TRUE(NULL != sym_key.get()); - - crypto::Encryptor encryptor; - // The IV must be exactly as long a the cipher block size. - EXPECT_EQ(16U, iv.size()); - EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); - - std::string ciphertext; - EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); - EXPECT_EQ(expected_ciphertext_hex, base::HexEncode(ciphertext.data(), - ciphertext.size())); - - std::string decypted; - EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decypted)); - EXPECT_EQ(plaintext, decypted); -} - -// Not all platforms allow import/generation of symmetric keys with an -// unsupported size. -#if !defined(USE_NSS) && !defined(OS_WIN) && !defined(OS_MACOSX) +// Symmetric keys with an unsupported size should be rejected. Whether they are +// rejected by SymmetricKey::Import or Encryptor::Init depends on the platform. TEST(EncryptorTest, UnsupportedKeySize) { std::string key = "7 = bad"; std::string iv = "Sweet Sixteen IV"; - scoped_ptr<crypto::SymmetricKey> sym_key(crypto::SymmetricKey::Import( - crypto::SymmetricKey::AES, key)); - ASSERT_TRUE(NULL != sym_key.get()); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + if (!sym_key.get()) + return; crypto::Encryptor encryptor; - // The IV must be exactly as long a the cipher block size. + // The IV must be exactly as long as the cipher block size. EXPECT_EQ(16U, iv.size()); EXPECT_FALSE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); } -#endif // unsupported platforms. TEST(EncryptorTest, UnsupportedIV) { std::string key = "128=SixteenBytes"; std::string iv = "OnlyForteen :("; - scoped_ptr<crypto::SymmetricKey> sym_key(crypto::SymmetricKey::Import( - crypto::SymmetricKey::AES, key)); - ASSERT_TRUE(NULL != sym_key.get()); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); crypto::Encryptor encryptor; EXPECT_FALSE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); @@ -354,9 +491,9 @@ std::string plaintext; std::string expected_ciphertext_hex = "8518B8878D34E7185E300D0FCC426396"; - scoped_ptr<crypto::SymmetricKey> sym_key(crypto::SymmetricKey::Import( - crypto::SymmetricKey::AES, key)); - ASSERT_TRUE(NULL != sym_key.get()); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); crypto::Encryptor encryptor; // The IV must be exactly as long a the cipher block size. @@ -368,3 +505,29 @@ EXPECT_EQ(expected_ciphertext_hex, base::HexEncode(ciphertext.data(), ciphertext.size())); } + +TEST(EncryptorTest, CipherTextNotMultipleOfBlockSize) { + std::string key = "128=SixteenBytes"; + std::string iv = "Sweet Sixteen IV"; + + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + // The IV must be exactly as long a the cipher block size. + EXPECT_EQ(16U, iv.size()); + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); + + // Use a separately allocated array to improve the odds of the memory tools + // catching invalid accesses. + // + // Otherwise when using std::string as the other tests do, accesses several + // bytes off the end of the buffer may fall inside the reservation of + // the string and not be detected. + std::unique_ptr<char[]> ciphertext(new char[1]); + + std::string plaintext; + EXPECT_FALSE( + encryptor.Decrypt(base::StringPiece(ciphertext.get(), 1), &plaintext)); +}
diff --git a/src/crypto/ghash.cc b/src/crypto/ghash.cc deleted file mode 100644 index 99eae03..0000000 --- a/src/crypto/ghash.cc +++ /dev/null
@@ -1,259 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/ghash.h" - -#include <algorithm> - -#include "base/logging.h" -#include "base/sys_byteorder.h" - -namespace crypto { - -// GaloisHash is a polynomial authenticator that works in GF(2^128). -// -// Elements of the field are represented in `little-endian' order (which -// matches the description in the paper[1]), thus the most significant bit is -// the right-most bit. (This is backwards from the way that everybody else does -// it.) -// -// We store field elements in a pair of such `little-endian' uint64s. So the -// value one is represented by {low = 2**63, high = 0} and doubling a value -// involves a *right* shift. -// -// [1] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf - -namespace { - -// Get64 reads a 64-bit, big-endian number from |bytes|. -uint64 Get64(const uint8 bytes[8]) { - uint64 t; - memcpy(&t, bytes, sizeof(t)); - return base::NetToHost64(t); -} - -// Put64 writes |x| to |bytes| as a 64-bit, big-endian number. -void Put64(uint8 bytes[8], uint64 x) { - x = base::HostToNet64(x); - memcpy(bytes, &x, sizeof(x)); -} - -// Reverse reverses the order of the bits of 4-bit number in |i|. -int Reverse(int i) { - i = ((i << 2) & 0xc) | ((i >> 2) & 0x3); - i = ((i << 1) & 0xa) | ((i >> 1) & 0x5); - return i; -} - -} // namespace - -GaloisHash::GaloisHash(const uint8 key[16]) { - Reset(); - - // We precompute 16 multiples of |key|. However, when we do lookups into this - // table we'll be using bits from a field element and therefore the bits will - // be in the reverse order. So normally one would expect, say, 4*key to be in - // index 4 of the table but due to this bit ordering it will actually be in - // index 0010 (base 2) = 2. - FieldElement x = {Get64(key), Get64(key+8)}; - product_table_[0].low = 0; - product_table_[0].hi = 0; - product_table_[Reverse(1)] = x; - - for (int i = 0; i < 16; i += 2) { - product_table_[Reverse(i)] = Double(product_table_[Reverse(i/2)]); - product_table_[Reverse(i+1)] = Add(product_table_[Reverse(i)], x); - } -} - -void GaloisHash::Reset() { - state_ = kHashingAdditionalData; - additional_bytes_ = 0; - ciphertext_bytes_ = 0; - buf_used_ = 0; - y_.low = 0; - y_.hi = 0; -} - -void GaloisHash::UpdateAdditional(const uint8* data, size_t length) { - DCHECK_EQ(state_, kHashingAdditionalData); - additional_bytes_ += length; - Update(data, length); -} - -void GaloisHash::UpdateCiphertext(const uint8* data, size_t length) { - if (state_ == kHashingAdditionalData) { - // If there's any remaining additional data it's zero padded to the next - // full block. - if (buf_used_ > 0) { - memset(&buf_[buf_used_], 0, sizeof(buf_)-buf_used_); - UpdateBlocks(buf_, 1); - buf_used_ = 0; - } - state_ = kHashingCiphertext; - } - - DCHECK_EQ(state_, kHashingCiphertext); - ciphertext_bytes_ += length; - Update(data, length); -} - -void GaloisHash::Finish(void* output, size_t len) { - DCHECK(state_ != kComplete); - - if (buf_used_ > 0) { - // If there's any remaining data (additional data or ciphertext), it's zero - // padded to the next full block. - memset(&buf_[buf_used_], 0, sizeof(buf_)-buf_used_); - UpdateBlocks(buf_, 1); - buf_used_ = 0; - } - - state_ = kComplete; - - // The lengths of the additional data and ciphertext are included as the last - // block. The lengths are the number of bits. - y_.low ^= additional_bytes_*8; - y_.hi ^= ciphertext_bytes_*8; - MulAfterPrecomputation(product_table_, &y_); - - uint8 *result, result_tmp[16]; - if (len >= 16) { - result = reinterpret_cast<uint8*>(output); - } else { - result = result_tmp; - } - - Put64(result, y_.low); - Put64(result + 8, y_.hi); - - if (len < 16) - memcpy(output, result_tmp, len); -} - -// static -GaloisHash::FieldElement GaloisHash::Add( - const FieldElement& x, - const FieldElement& y) { - // Addition in a characteristic 2 field is just XOR. - FieldElement z = {x.low^y.low, x.hi^y.hi}; - return z; -} - -// static -GaloisHash::FieldElement GaloisHash::Double(const FieldElement& x) { - const bool msb_set = x.hi & 1; - - FieldElement xx; - // Because of the bit-ordering, doubling is actually a right shift. - xx.hi = x.hi >> 1; - xx.hi |= x.low << 63; - xx.low = x.low >> 1; - - // If the most-significant bit was set before shifting then it, conceptually, - // becomes a term of x^128. This is greater than the irreducible polynomial - // so the result has to be reduced. The irreducible polynomial is - // 1+x+x^2+x^7+x^128. We can subtract that to eliminate the term at x^128 - // which also means subtracting the other four terms. In characteristic 2 - // fields, subtraction == addition == XOR. - if (msb_set) - xx.low ^= 0xe100000000000000ULL; - - return xx; -} - -void GaloisHash::MulAfterPrecomputation(const FieldElement* table, - FieldElement* x) { - FieldElement z = {0, 0}; - - // In order to efficiently multiply, we use the precomputed table of i*key, - // for i in 0..15, to handle four bits at a time. We could obviously use - // larger tables for greater speedups but the next convenient table size is - // 4K, which is a little large. - // - // In other fields one would use bit positions spread out across the field in - // order to reduce the number of doublings required. However, in - // characteristic 2 fields, repeated doublings are exceptionally cheap and - // it's not worth spending more precomputation time to eliminate them. - for (unsigned i = 0; i < 2; i++) { - uint64 word; - if (i == 0) { - word = x->hi; - } else { - word = x->low; - } - - for (unsigned j = 0; j < 64; j += 4) { - Mul16(&z); - // the values in |table| are ordered for little-endian bit positions. See - // the comment in the constructor. - const FieldElement& t = table[word & 0xf]; - z.low ^= t.low; - z.hi ^= t.hi; - word >>= 4; - } - } - - *x = z; -} - -// kReductionTable allows for rapid multiplications by 16. A multiplication by -// 16 is a right shift by four bits, which results in four bits at 2**128. -// These terms have to be eliminated by dividing by the irreducible polynomial. -// In GHASH, the polynomial is such that all the terms occur in the -// least-significant 8 bits, save for the term at x^128. Therefore we can -// precompute the value to be added to the field element for each of the 16 bit -// patterns at 2**128 and the values fit within 12 bits. -static const uint16 kReductionTable[16] = { - 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, - 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0, -}; - -// static -void GaloisHash::Mul16(FieldElement* x) { - const unsigned msw = x->hi & 0xf; - x->hi >>= 4; - x->hi |= x->low << 60; - x->low >>= 4; - x->low ^= static_cast<uint64>(kReductionTable[msw]) << 48; -} - -void GaloisHash::UpdateBlocks(const uint8* bytes, size_t num_blocks) { - for (size_t i = 0; i < num_blocks; i++) { - y_.low ^= Get64(bytes); - bytes += 8; - y_.hi ^= Get64(bytes); - bytes += 8; - MulAfterPrecomputation(product_table_, &y_); - } -} - -void GaloisHash::Update(const uint8* data, size_t length) { - if (buf_used_ > 0) { - const size_t n = std::min(length, buf_used_); - memcpy(&buf_[buf_used_], data, n); - buf_used_ += n; - length -= n; - data += n; - - if (buf_used_ == sizeof(buf_)) { - UpdateBlocks(buf_, 1); - buf_used_ = 0; - } - } - - if (length >= 16) { - const size_t n = length / 16; - UpdateBlocks(data, n); - length -= n*16; - data += n*16; - } - - if (length > 0) { - memcpy(buf_, data, length); - buf_used_ = length; - } -} - -} // namespace crypto
diff --git a/src/crypto/ghash.h b/src/crypto/ghash.h deleted file mode 100644 index 6dc247b..0000000 --- a/src/crypto/ghash.h +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "crypto/crypto_export.h" - -namespace crypto { - -// GaloisHash implements the polynomial authenticator part of GCM as specified -// in http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf -// Specifically it implements the GHASH function, defined in section 2.3 of -// that document. -// -// In SP-800-38D, GHASH is defined differently and takes only a single data -// argument. But it is always called with an argument of a certain form: -// GHASH_H (A || 0^v || C || 0^u || [len(A)]_64 || [len(C)]_64) -// This mirrors how the gcm-revised-spec.pdf version of GHASH handles its two -// data arguments. The two GHASH functions therefore differ only in whether the -// data is formatted inside or outside of the function. -// -// WARNING: do not use this as a generic authenticator. Polynomial -// authenticators must be used in the correct manner and any use outside of GCM -// requires careful consideration. -// -// WARNING: this code is not constant time. However, in all likelihood, nor is -// the implementation of AES that is used. -class CRYPTO_EXPORT_PRIVATE GaloisHash { - public: - explicit GaloisHash(const uint8 key[16]); - - // Reset prepares to digest a fresh message with the same key. This is more - // efficient than creating a fresh object. - void Reset(); - - // UpdateAdditional hashes in `additional' data. This is data that is not - // encrypted, but is covered by the authenticator. All additional data must - // be written before any ciphertext is written. - void UpdateAdditional(const uint8* data, size_t length); - - // UpdateCiphertext hashes in ciphertext to be authenticated. - void UpdateCiphertext(const uint8* data, size_t length); - - // Finish completes the hash computation and writes at most |len| bytes of - // the result to |output|. - void Finish(void* output, size_t len); - - private: - enum State { - kHashingAdditionalData, - kHashingCiphertext, - kComplete, - }; - - struct FieldElement { - uint64 low, hi; - }; - - // Add returns |x|+|y|. - static FieldElement Add(const FieldElement& x, const FieldElement& y); - // Double returns 2*|x|. - static FieldElement Double(const FieldElement& x); - // MulAfterPrecomputation sets |x| = |x|*h where h is |table[1]| and - // table[i] = i*h for i=0..15. - static void MulAfterPrecomputation(const FieldElement* table, - FieldElement* x); - // Mul16 sets |x| = 16*|x|. - static void Mul16(FieldElement* x); - - // UpdateBlocks processes |num_blocks| 16-bytes blocks from |bytes|. - void UpdateBlocks(const uint8* bytes, size_t num_blocks); - // Update processes |length| bytes from |bytes| and calls UpdateBlocks on as - // much data as possible. It uses |buf_| to buffer any remaining data and - // always consumes all of |bytes|. - void Update(const uint8* bytes, size_t length); - - FieldElement y_; - State state_; - size_t additional_bytes_; - size_t ciphertext_bytes_; - uint8 buf_[16]; - size_t buf_used_; - FieldElement product_table_[16]; -}; - -} // namespace crypto
diff --git a/src/crypto/ghash_unittest.cc b/src/crypto/ghash_unittest.cc deleted file mode 100644 index c491f76..0000000 --- a/src/crypto/ghash_unittest.cc +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/ghash.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace crypto { - -namespace { - -// Test vectors are taken from Appendix B of -// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf - -static const uint8 kKey1[16] = { - 0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b, - 0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e, -}; - -static const uint8 kCiphertext2[] = { - 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, - 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78, -}; - -static const uint8 kKey3[16] = { - 0xb8, 0x3b, 0x53, 0x37, 0x08, 0xbf, 0x53, 0x5d, - 0x0a, 0xa6, 0xe5, 0x29, 0x80, 0xd5, 0x3b, 0x78, -}; - -static const uint8 kCiphertext3[] = { - 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, - 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, - 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, - 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, - 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, - 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, - 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, - 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85, -}; - -static const uint8 kAdditional4[] = { - 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, - 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, - 0xab, 0xad, 0xda, 0xd2, -}; - -struct TestCase { - const uint8* key; - const uint8* additional; - unsigned additional_length; - const uint8* ciphertext; - unsigned ciphertext_length; - const uint8 expected[16]; -}; - -static const TestCase kTestCases[] = { - { - kKey1, - NULL, - 0, - NULL, - 0, - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - }, - { - kKey1, - NULL, - 0, - kCiphertext2, - sizeof(kCiphertext2), - { - 0xf3, 0x8c, 0xbb, 0x1a, 0xd6, 0x92, 0x23, 0xdc, - 0xc3, 0x45, 0x7a, 0xe5, 0xb6, 0xb0, 0xf8, 0x85, - }, - }, - { - kKey3, - NULL, - 0, - kCiphertext3, - sizeof(kCiphertext3), - { - 0x7f, 0x1b, 0x32, 0xb8, 0x1b, 0x82, 0x0d, 0x02, - 0x61, 0x4f, 0x88, 0x95, 0xac, 0x1d, 0x4e, 0xac, - }, - }, - { - kKey3, - kAdditional4, - sizeof(kAdditional4), - kCiphertext3, - sizeof(kCiphertext3) - 4, - { - 0x69, 0x8e, 0x57, 0xf7, 0x0e, 0x6e, 0xcc, 0x7f, - 0xd9, 0x46, 0x3b, 0x72, 0x60, 0xa9, 0xae, 0x5f, - }, - }, -}; - -TEST(GaloisHash, TestCases) { - uint8 out[16]; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - const TestCase& test = kTestCases[i]; - - GaloisHash hash(test.key); - if (test.additional_length) - hash.UpdateAdditional(test.additional, test.additional_length); - if (test.ciphertext_length) - hash.UpdateCiphertext(test.ciphertext, test.ciphertext_length); - hash.Finish(out, sizeof(out)); - EXPECT_TRUE(0 == memcmp(out, test.expected, 16)); - } -} - -TEST(GaloisHash, TestCasesByteAtATime) { - uint8 out[16]; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - const TestCase& test = kTestCases[i]; - - GaloisHash hash(test.key); - for (size_t i = 0; i < test.additional_length; ++i) - hash.UpdateAdditional(test.additional + i, 1); - for (size_t i = 0; i < test.ciphertext_length; ++i) - hash.UpdateCiphertext(test.ciphertext + i, 1); - hash.Finish(out, sizeof(out)); - EXPECT_TRUE(0 == memcmp(out, test.expected, 16)); - } -} - -} // namespace - -} // namespace crypto
diff --git a/src/crypto/hkdf.cc b/src/crypto/hkdf.cc new file mode 100644 index 0000000..21698e6 --- /dev/null +++ b/src/crypto/hkdf.cc
@@ -0,0 +1,32 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/hkdf.h" + +#include <memory> + +#include "base/logging.h" +#include "crypto/hmac.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/hkdf.h" + +namespace crypto { + +std::string HkdfSha256(base::StringPiece secret, + base::StringPiece salt, + base::StringPiece info, + size_t derived_key_size) { + std::string key; + key.resize(derived_key_size); + int result = ::HKDF( + reinterpret_cast<uint8_t*>(&key[0]), derived_key_size, EVP_sha256(), + reinterpret_cast<const uint8_t*>(secret.data()), secret.size(), + reinterpret_cast<const uint8_t*>(salt.data()), salt.size(), + reinterpret_cast<const uint8_t*>(info.data()), info.size()); + DCHECK(result); + return key; +} + +} // namespace crypto
diff --git a/src/crypto/hkdf.h b/src/crypto/hkdf.h new file mode 100644 index 0000000..7fc4381 --- /dev/null +++ b/src/crypto/hkdf.h
@@ -0,0 +1,24 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_HKDF_H_ +#define CRYPTO_HKDF_H_ + +#include <string> + +#include "base/strings/string_piece.h" +#include "crypto/crypto_export.h" +#include "starboard/types.h" + +namespace crypto { + +CRYPTO_EXPORT +std::string HkdfSha256(base::StringPiece secret, + base::StringPiece salt, + base::StringPiece info, + size_t derived_key_size); + +} // namespace crypto + +#endif // CRYPTO_HKDF_H_
diff --git a/src/crypto/hmac.cc b/src/crypto/hmac.cc index 126d124..dcd0386 100644 --- a/src/crypto/hmac.cc +++ b/src/crypto/hmac.cc
@@ -5,20 +5,27 @@ #include "crypto/hmac.h" #include <algorithm> +#include <string> #include "base/logging.h" +#include "base/stl_util.h" +#include "crypto/openssl_util.h" #include "crypto/secure_util.h" #include "crypto/symmetric_key.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/hmac.h" namespace crypto { -bool HMAC::Init(SymmetricKey* key) { - std::string raw_key; - bool result = key->GetRawKey(&raw_key) && Init(raw_key); - // Zero out key copy. This might get optimized away, but one can hope. - // Using std::string to store key info at all is a larger problem. - std::fill(raw_key.begin(), raw_key.end(), 0); - return result; +HMAC::HMAC(HashAlgorithm hash_alg) : hash_alg_(hash_alg), initialized_(false) { + // Only SHA-1 and SHA-256 hash algorithms are supported now. + DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256); +} + +HMAC::~HMAC() { + // Zero out key copy. + key_.assign(key_.size(), 0); + base::STLClearObject(&key_); } size_t HMAC::DigestLength() const { @@ -33,19 +40,42 @@ } } -bool HMAC::Verify(const base::StringPiece& data, - const base::StringPiece& digest) const { +bool HMAC::Init(const unsigned char* key, size_t key_length) { + // Init must not be called more than once on the same HMAC object. + DCHECK(!initialized_); + initialized_ = true; + key_.assign(key, key + key_length); + return true; +} + +bool HMAC::Init(const SymmetricKey* key) { + return Init(key->key()); +} + +bool HMAC::Sign(base::StringPiece data, + unsigned char* digest, + size_t digest_length) const { + DCHECK(initialized_); + + ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest, digest_length); + return !!::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(), key_.data(), + key_.size(), + reinterpret_cast<const unsigned char*>(data.data()), + data.size(), result.safe_buffer(), nullptr); +} + +bool HMAC::Verify(base::StringPiece data, base::StringPiece digest) const { if (digest.size() != DigestLength()) return false; return VerifyTruncated(data, digest); } -bool HMAC::VerifyTruncated(const base::StringPiece& data, - const base::StringPiece& digest) const { +bool HMAC::VerifyTruncated(base::StringPiece data, + base::StringPiece digest) const { if (digest.empty()) return false; size_t digest_length = DigestLength(); - scoped_array<unsigned char> computed_digest( + std::unique_ptr<unsigned char[]> computed_digest( new unsigned char[digest_length]); if (!Sign(data, computed_digest.get(), digest_length)) return false;
diff --git a/src/crypto/hmac.h b/src/crypto/hmac.h index d527d16..608fc4e 100644 --- a/src/crypto/hmac.h +++ b/src/crypto/hmac.h
@@ -8,16 +8,18 @@ #ifndef CRYPTO_HMAC_H_ #define CRYPTO_HMAC_H_ -#include "base/basictypes.h" +#include <memory> +#include <vector> + #include "base/compiler_specific.h" -#include "base/memory/scoped_ptr.h" -#include "base/string_piece.h" +#include "base/macros.h" +#include "base/strings/string_piece.h" #include "crypto/crypto_export.h" +#include "starboard/types.h" namespace crypto { // Simplify the interface and reduce includes by abstracting out the internals. -struct HMACPlatformData; class SymmetricKey; class CRYPTO_EXPORT HMAC { @@ -50,11 +52,11 @@ // Initializes this instance using |key|. Call Init // only once. It returns false on the second or later calls. - bool Init(SymmetricKey* key) WARN_UNUSED_RESULT; + bool Init(const SymmetricKey* key) WARN_UNUSED_RESULT; // Initializes this instance using |key|. Call Init only once. It returns // false on the second or later calls. - bool Init(const base::StringPiece& key) WARN_UNUSED_RESULT { + bool Init(base::StringPiece key) WARN_UNUSED_RESULT { return Init(reinterpret_cast<const unsigned char*>(key.data()), key.size()); } @@ -62,7 +64,8 @@ // Calculates the HMAC for the message in |data| using the algorithm supplied // to the constructor and the key supplied to the Init method. The HMAC is // returned in |digest|, which has |digest_length| bytes of storage available. - bool Sign(const base::StringPiece& data, unsigned char* digest, + bool Sign(base::StringPiece data, + unsigned char* digest, size_t digest_length) const WARN_UNUSED_RESULT; // Verifies that the HMAC for the message in |data| equals the HMAC provided @@ -72,18 +75,18 @@ // comparisons may result in side-channel disclosures, such as timing, that // undermine the cryptographic integrity. |digest| must be exactly // |DigestLength()| bytes long. - bool Verify(const base::StringPiece& data, - const base::StringPiece& digest) const WARN_UNUSED_RESULT; + bool Verify(base::StringPiece data, + base::StringPiece digest) const WARN_UNUSED_RESULT; // Verifies a truncated HMAC, behaving identical to Verify(), except // that |digest| is allowed to be smaller than |DigestLength()|. - bool VerifyTruncated( - const base::StringPiece& data, - const base::StringPiece& digest) const WARN_UNUSED_RESULT; + bool VerifyTruncated(base::StringPiece data, + base::StringPiece digest) const WARN_UNUSED_RESULT; private: HashAlgorithm hash_alg_; - scoped_ptr<HMACPlatformData> plat_; + bool initialized_; + std::vector<unsigned char> key_; DISALLOW_COPY_AND_ASSIGN(HMAC); };
diff --git a/src/crypto/hmac_openssl.cc b/src/crypto/hmac_openssl.cc deleted file mode 100644 index 2494d1c..0000000 --- a/src/crypto/hmac_openssl.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/hmac.h" - -#include <openssl/hmac.h> - -#include <algorithm> -#include <vector> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/stl_util.h" -#include "crypto/openssl_util.h" - -namespace crypto { - -struct HMACPlatformData { - std::vector<unsigned char> key; -}; - -HMAC::HMAC(HashAlgorithm hash_alg) - : hash_alg_(hash_alg), plat_(new HMACPlatformData()) { - // Only SHA-1 and SHA-256 hash algorithms are supported now. - DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256); -} - -bool HMAC::Init(const unsigned char* key, size_t key_length) { - // Init must not be called more than once on the same HMAC object. - DCHECK(plat_->key.empty()); - - plat_->key.assign(key, key + key_length); - return true; -} - -HMAC::~HMAC() { - // Zero out key copy. - plat_->key.assign(plat_->key.size(), 0); - STLClearObject(&plat_->key); -} - -bool HMAC::Sign(const base::StringPiece& data, - unsigned char* digest, - size_t digest_length) const { - DCHECK(!plat_->key.empty()); // Init must be called before Sign. - - ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest, digest_length); - return ::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(), - &plat_->key[0], plat_->key.size(), - reinterpret_cast<const unsigned char*>(data.data()), - data.size(), - result.safe_buffer(), NULL) != NULL; -} - -} // namespace crypto
diff --git a/src/crypto/hmac_unittest.cc b/src/crypto/hmac_unittest.cc index f0844a9..876add1 100644 --- a/src/crypto/hmac_unittest.cc +++ b/src/crypto/hmac_unittest.cc
@@ -4,7 +4,10 @@ #include <string> +#include "base/macros.h" #include "crypto/hmac.h" +#include "starboard/memory.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" static const size_t kSHA1DigestSize = 20; @@ -79,7 +82,8 @@ unsigned char calculated_hmac[kSHA1DigestSize]; EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kSHA1DigestSize)); - EXPECT_EQ(0, memcmp(kReceivedHmac, calculated_hmac, kSHA1DigestSize)); + EXPECT_EQ(0, + SbMemoryCompare(kReceivedHmac, calculated_hmac, kSHA1DigestSize)); } // Test cases from RFC 2202 section 3 @@ -142,14 +146,14 @@ "\xBB\xFF\x1A\x91" } }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { + for (size_t i = 0; i < arraysize(cases); ++i) { crypto::HMAC hmac(crypto::HMAC::SHA1); ASSERT_TRUE(hmac.Init(reinterpret_cast<const unsigned char*>(cases[i].key), cases[i].key_len)); std::string data_string(cases[i].data, cases[i].data_len); unsigned char digest[kSHA1DigestSize]; EXPECT_TRUE(hmac.Sign(data_string, digest, kSHA1DigestSize)); - EXPECT_EQ(0, memcmp(cases[i].digest, digest, kSHA1DigestSize)); + EXPECT_EQ(0, SbMemoryCompare(cases[i].digest, digest, kSHA1DigestSize)); } } @@ -175,7 +179,8 @@ EXPECT_EQ(kSHA256DigestSize, hmac.DigestLength()); EXPECT_TRUE(hmac.Sign(data, calculated_hmac, kSHA256DigestSize)); - EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac, kSHA256DigestSize)); + EXPECT_EQ( + 0, SbMemoryCompare(kKnownHMACSHA256, calculated_hmac, kSHA256DigestSize)); } // Based on NSS's FIPS HMAC power-up self-test. @@ -216,7 +221,8 @@ EXPECT_EQ(kSHA1DigestSize, hmac.DigestLength()); EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kSHA1DigestSize)); - EXPECT_EQ(0, memcmp(kKnownHMACSHA1, calculated_hmac, kSHA1DigestSize)); + EXPECT_EQ(0, + SbMemoryCompare(kKnownHMACSHA1, calculated_hmac, kSHA1DigestSize)); EXPECT_TRUE(hmac.Verify( message_data, base::StringPiece(reinterpret_cast<const char*>(kKnownHMACSHA1), @@ -231,7 +237,8 @@ unsigned char calculated_hmac2[kSHA256DigestSize]; EXPECT_TRUE(hmac2.Sign(message_data, calculated_hmac2, kSHA256DigestSize)); - EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac2, kSHA256DigestSize)); + EXPECT_EQ(0, SbMemoryCompare(kKnownHMACSHA256, calculated_hmac2, + kSHA256DigestSize)); } TEST(HMACTest, HMACObjectReuse) { @@ -239,12 +246,13 @@ ASSERT_TRUE( hmac.Init(reinterpret_cast<const unsigned char*>(kSimpleKey), kSimpleKeyLength)); - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSimpleHmacCases); ++i) { + for (size_t i = 0; i < arraysize(kSimpleHmacCases); ++i) { std::string data_string(kSimpleHmacCases[i].data, kSimpleHmacCases[i].data_len); unsigned char digest[kSHA1DigestSize]; EXPECT_TRUE(hmac.Sign(data_string, digest, kSHA1DigestSize)); - EXPECT_EQ(0, memcmp(kSimpleHmacCases[i].digest, digest, kSHA1DigestSize)); + EXPECT_EQ(0, SbMemoryCompare(kSimpleHmacCases[i].digest, digest, + kSHA1DigestSize)); } } @@ -254,7 +262,7 @@ hmac.Init(reinterpret_cast<const unsigned char*>(kSimpleKey), kSimpleKeyLength)); const char empty_digest[kSHA1DigestSize] = { 0 }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSimpleHmacCases); ++i) { + for (size_t i = 0; i < arraysize(kSimpleHmacCases); ++i) { // Expected results EXPECT_TRUE(hmac.Verify( base::StringPiece(kSimpleHmacCases[i].data, @@ -275,3 +283,21 @@ base::StringPiece(empty_digest, kSHA1DigestSize))); } } + +TEST(HMACTest, EmptyKey) { + // Test vector from https://en.wikipedia.org/wiki/HMAC + const char* kExpectedDigest = + "\xFB\xDB\x1D\x1B\x18\xAA\x6C\x08\x32\x4B\x7D\x64\xB7\x1F\xB7\x63" + "\x70\x69\x0E\x1D"; + base::StringPiece data(""); + + crypto::HMAC hmac(crypto::HMAC::SHA1); + ASSERT_TRUE(hmac.Init(nullptr, 0)); + + unsigned char digest[kSHA1DigestSize]; + EXPECT_TRUE(hmac.Sign(data, digest, kSHA1DigestSize)); + EXPECT_EQ(0, SbMemoryCompare(kExpectedDigest, digest, kSHA1DigestSize)); + + EXPECT_TRUE(hmac.Verify( + data, base::StringPiece(kExpectedDigest, kSHA1DigestSize))); +}
diff --git a/src/crypto/mac_security_services_lock.cc b/src/crypto/mac_security_services_lock.cc new file mode 100644 index 0000000..a9a70cd --- /dev/null +++ b/src/crypto/mac_security_services_lock.cc
@@ -0,0 +1,42 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/mac_security_services_lock.h" + +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "base/synchronization/lock.h" + +namespace { + +class SecurityServicesSingleton { + public: + static SecurityServicesSingleton* GetInstance() { + return base::Singleton< + SecurityServicesSingleton, + base::LeakySingletonTraits<SecurityServicesSingleton>>::get(); + } + + base::Lock& lock() { return lock_; } + + private: + friend struct base::DefaultSingletonTraits<SecurityServicesSingleton>; + + SecurityServicesSingleton() {} + ~SecurityServicesSingleton() {} + + base::Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(SecurityServicesSingleton); +}; + +} // namespace + +namespace crypto { + +base::Lock& GetMacSecurityServicesLock() { + return SecurityServicesSingleton::GetInstance()->lock(); +} + +} // namespace crypto
diff --git a/src/crypto/mac_security_services_lock.h b/src/crypto/mac_security_services_lock.h new file mode 100644 index 0000000..fe56c6f --- /dev/null +++ b/src/crypto/mac_security_services_lock.h
@@ -0,0 +1,25 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_MAC_SECURITY_SERVICES_LOCK_H_ +#define CRYPTO_MAC_SECURITY_SERVICES_LOCK_H_ + +#include "crypto/crypto_export.h" + +namespace base { +class Lock; +} + +namespace crypto { + +// The Mac OS X certificate and key management wrappers over CSSM are not +// thread-safe. In particular, code that accesses the CSSM database is +// problematic. +// +// http://developer.apple.com/mac/library/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html +CRYPTO_EXPORT base::Lock& GetMacSecurityServicesLock(); + +} // namespace crypto + +#endif // CRYPTO_MAC_SECURITY_SERVICES_LOCK_H_
diff --git a/src/crypto/mock_apple_keychain.cc b/src/crypto/mock_apple_keychain.cc new file mode 100644 index 0000000..453114e --- /dev/null +++ b/src/crypto/mock_apple_keychain.cc
@@ -0,0 +1,80 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/mock_apple_keychain.h" + +#include "base/logging.h" +#include "base/macros.h" +#include "base/metrics/histogram_macros.h" +#include "base/time/time.h" + +namespace { + +// Adds an entry to a local histogram to indicate that the Apple Keychain would +// have been accessed, if this class were not a mock of the Apple Keychain. +void IncrementKeychainAccessHistogram() { + // This local histogram is accessed by Telemetry to track the number of times + // the keychain is accessed, since keychain access is known to be synchronous + // and slow. + LOCAL_HISTOGRAM_BOOLEAN("OSX.Keychain.Access", true); +} + +} // namespace + +namespace crypto { + +OSStatus MockAppleKeychain::FindGenericPassword( + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32* passwordLength, + void** passwordData, + AppleSecKeychainItemRef* itemRef) const { + IncrementKeychainAccessHistogram(); + + // When simulating |noErr|, return canned |passwordData| and + // |passwordLength|. Otherwise, just return given code. + if (find_generic_result_ == noErr) { + static const char kPassword[] = "my_password"; + DCHECK(passwordData); + // The function to free this data is mocked so the cast is fine. + *passwordData = const_cast<char*>(kPassword); + DCHECK(passwordLength); + *passwordLength = arraysize(kPassword); + password_data_count_++; + } + + return find_generic_result_; +} + +OSStatus MockAppleKeychain::ItemFreeContent(void* data) const { + // No-op. + password_data_count_--; + return noErr; +} + +OSStatus MockAppleKeychain::AddGenericPassword( + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + AppleSecKeychainItemRef* itemRef) const { + IncrementKeychainAccessHistogram(); + + called_add_generic_ = true; + + DCHECK_GT(passwordLength, 0U); + DCHECK(passwordData); + return noErr; +} + +std::string MockAppleKeychain::GetEncryptionPassword() const { + IncrementKeychainAccessHistogram(); + return "mock_password"; +} + +} // namespace crypto
diff --git a/src/crypto/mock_apple_keychain.h b/src/crypto/mock_apple_keychain.h new file mode 100644 index 0000000..1770026 --- /dev/null +++ b/src/crypto/mock_apple_keychain.h
@@ -0,0 +1,86 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_MOCK_APPLE_KEYCHAIN_H_ +#define CRYPTO_MOCK_APPLE_KEYCHAIN_H_ + +#include <map> +#include <set> +#include <string> +#include <vector> + +#include "base/compiler_specific.h" +#include "crypto/apple_keychain.h" +#include "starboard/types.h" + +namespace crypto { + +// Mock Keychain wrapper for testing code that interacts with the OS X +// Keychain. +// +// Note that "const" is pretty much meaningless for this class; the const-ness +// of AppleKeychain doesn't apply to the actual keychain data, so all of the +// Mock data is mutable; don't assume that it won't change over the life of +// tests. +class CRYPTO_EXPORT MockAppleKeychain : public AppleKeychain { + public: + MockAppleKeychain(); + ~MockAppleKeychain() override; + + // AppleKeychain implementation. + OSStatus FindGenericPassword(UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32* passwordLength, + void** passwordData, + AppleSecKeychainItemRef* itemRef) const override; + OSStatus ItemFreeContent(void* data) const override; + OSStatus AddGenericPassword(UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + AppleSecKeychainItemRef* itemRef) const override; + + // Returns the password that OSCrypt uses to generate its encryption key. + std::string GetEncryptionPassword() const; + +#if !defined(OS_IOS) + OSStatus ItemDelete(SecKeychainItemRef itemRef) const override; +#endif // !defined(OS_IOS) + + // |FindGenericPassword()| can return different results depending on user + // interaction with the system Keychain. For mocking purposes we allow the + // user of this class to specify the result code of the + // |FindGenericPassword()| call so we can simulate the result of different + // user interactions. + void set_find_generic_result(OSStatus result) { + find_generic_result_ = result; + } + + // Returns the true if |AddGenericPassword()| was called. + bool called_add_generic() const { return called_add_generic_; } + + // Returns the number of allocations - deallocations for password data. + int password_data_count() const { return password_data_count_; } + + private: + // Result code for the |FindGenericPassword()| method. + OSStatus find_generic_result_; + + // Records whether |AddGenericPassword()| gets called. + mutable bool called_add_generic_; + + // Tracks the allocations and frees of password data in |FindGenericPassword| + // and |ItemFreeContent|. + mutable int password_data_count_; + + DISALLOW_COPY_AND_ASSIGN(MockAppleKeychain); +}; + +} // namespace crypto + +#endif // CRYPTO_MOCK_APPLE_KEYCHAIN_H_
diff --git a/src/crypto/mock_apple_keychain_ios.cc b/src/crypto/mock_apple_keychain_ios.cc index f94a80d..9e8a164 100644 --- a/src/crypto/mock_apple_keychain_ios.cc +++ b/src/crypto/mock_apple_keychain_ios.cc
@@ -3,7 +3,7 @@ // found in the LICENSE file. #include "base/logging.h" -#include "base/time.h" +#include "base/time/time.h" #include "crypto/mock_apple_keychain.h" namespace crypto {
diff --git a/src/crypto/mock_apple_keychain_mac.cc b/src/crypto/mock_apple_keychain_mac.cc index 181f108..036459a 100644 --- a/src/crypto/mock_apple_keychain_mac.cc +++ b/src/crypto/mock_apple_keychain_mac.cc
@@ -3,507 +3,22 @@ // found in the LICENSE file. #include "base/logging.h" -#include "base/time.h" +#include "base/macros.h" +#include "base/time/time.h" #include "crypto/mock_apple_keychain.h" +#include "starboard/types.h" namespace crypto { -// static -const SecKeychainSearchRef MockAppleKeychain::kDummySearchRef = - reinterpret_cast<SecKeychainSearchRef>(1000); - MockAppleKeychain::MockAppleKeychain() - : next_item_key_(0), - search_copy_count_(0), - keychain_item_copy_count_(0), - attribute_data_copy_count_(0), - find_generic_result_(noErr), + : find_generic_result_(noErr), called_add_generic_(false), password_data_count_(0) {} -void MockAppleKeychain::InitializeKeychainData(MockKeychainItemType key) const { - UInt32 tags[] = { kSecAccountItemAttr, - kSecServerItemAttr, - kSecPortItemAttr, - kSecPathItemAttr, - kSecProtocolItemAttr, - kSecAuthenticationTypeItemAttr, - kSecSecurityDomainItemAttr, - kSecCreationDateItemAttr, - kSecNegativeItemAttr, - kSecCreatorItemAttr }; - keychain_attr_list_[key] = SecKeychainAttributeList(); - keychain_data_[key] = KeychainPasswordData(); - keychain_attr_list_[key].count = arraysize(tags); - keychain_attr_list_[key].attr = static_cast<SecKeychainAttribute*>( - calloc(keychain_attr_list_[key].count, sizeof(SecKeychainAttribute))); - for (unsigned int i = 0; i < keychain_attr_list_[key].count; ++i) { - keychain_attr_list_[key].attr[i].tag = tags[i]; - size_t data_size = 0; - switch (tags[i]) { - case kSecPortItemAttr: - data_size = sizeof(UInt32); - break; - case kSecProtocolItemAttr: - data_size = sizeof(SecProtocolType); - break; - case kSecAuthenticationTypeItemAttr: - data_size = sizeof(SecAuthenticationType); - break; - case kSecNegativeItemAttr: - data_size = sizeof(Boolean); - break; - case kSecCreatorItemAttr: - data_size = sizeof(OSType); - break; - } - if (data_size > 0) { - keychain_attr_list_[key].attr[i].length = data_size; - keychain_attr_list_[key].attr[i].data = calloc(1, data_size); - } - } -} +MockAppleKeychain::~MockAppleKeychain() {} -MockAppleKeychain::~MockAppleKeychain() { - for (MockKeychainAttributesMap::iterator it = keychain_attr_list_.begin(); - it != keychain_attr_list_.end(); - ++it) { - for (unsigned int i = 0; i < it->second.count; ++i) { - if (it->second.attr[i].data) - free(it->second.attr[i].data); - } - free(it->second.attr); - if (keychain_data_[it->first].data) - free(keychain_data_[it->first].data); - } - keychain_attr_list_.clear(); - keychain_data_.clear(); -} - -SecKeychainAttribute* MockAppleKeychain::AttributeWithTag( - const SecKeychainAttributeList& attribute_list, - UInt32 tag) { - int attribute_index = -1; - for (unsigned int i = 0; i < attribute_list.count; ++i) { - if (attribute_list.attr[i].tag == tag) { - attribute_index = i; - break; - } - } - if (attribute_index == -1) { - NOTREACHED() << "Unsupported attribute: " << tag; - return NULL; - } - return &(attribute_list.attr[attribute_index]); -} - -void MockAppleKeychain::SetTestDataBytes(MockKeychainItemType item, - UInt32 tag, - const void* data, - size_t length) { - SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item], - tag); - attribute->length = length; - if (length > 0) { - if (attribute->data) - free(attribute->data); - attribute->data = malloc(length); - CHECK(attribute->data); - memcpy(attribute->data, data, length); - } else { - attribute->data = NULL; - } -} - -void MockAppleKeychain::SetTestDataString(MockKeychainItemType item, - UInt32 tag, - const char* value) { - SetTestDataBytes(item, tag, value, value ? strlen(value) : 0); -} - -void MockAppleKeychain::SetTestDataPort(MockKeychainItemType item, - UInt32 value) { - SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item], - kSecPortItemAttr); - UInt32* data = static_cast<UInt32*>(attribute->data); - *data = value; -} - -void MockAppleKeychain::SetTestDataProtocol(MockKeychainItemType item, - SecProtocolType value) { - SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item], - kSecProtocolItemAttr); - SecProtocolType* data = static_cast<SecProtocolType*>(attribute->data); - *data = value; -} - -void MockAppleKeychain::SetTestDataAuthType(MockKeychainItemType item, - SecAuthenticationType value) { - SecKeychainAttribute* attribute = AttributeWithTag( - keychain_attr_list_[item], kSecAuthenticationTypeItemAttr); - SecAuthenticationType* data = static_cast<SecAuthenticationType*>( - attribute->data); - *data = value; -} - -void MockAppleKeychain::SetTestDataNegativeItem(MockKeychainItemType item, - Boolean value) { - SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item], - kSecNegativeItemAttr); - Boolean* data = static_cast<Boolean*>(attribute->data); - *data = value; -} - -void MockAppleKeychain::SetTestDataCreator(MockKeychainItemType item, - OSType value) { - SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item], - kSecCreatorItemAttr); - OSType* data = static_cast<OSType*>(attribute->data); - *data = value; -} - -void MockAppleKeychain::SetTestDataPasswordBytes(MockKeychainItemType item, - const void* data, - size_t length) { - keychain_data_[item].length = length; - if (length > 0) { - if (keychain_data_[item].data) - free(keychain_data_[item].data); - keychain_data_[item].data = malloc(length); - memcpy(keychain_data_[item].data, data, length); - } else { - keychain_data_[item].data = NULL; - } -} - -void MockAppleKeychain::SetTestDataPasswordString(MockKeychainItemType item, - const char* value) { - SetTestDataPasswordBytes(item, value, value ? strlen(value) : 0); -} - -OSStatus MockAppleKeychain::ItemCopyAttributesAndData( - SecKeychainItemRef itemRef, - SecKeychainAttributeInfo* info, - SecItemClass* itemClass, - SecKeychainAttributeList** attrList, - UInt32* length, - void** outData) const { - DCHECK(itemRef); - MockKeychainItemType key = - reinterpret_cast<MockKeychainItemType>(itemRef) - 1; - if (keychain_attr_list_.find(key) == keychain_attr_list_.end()) - return errSecInvalidItemRef; - - DCHECK(!itemClass); // itemClass not implemented in the Mock. - if (attrList) - *attrList = &(keychain_attr_list_[key]); - if (outData) { - *outData = keychain_data_[key].data; - DCHECK(length); - *length = keychain_data_[key].length; - } - - ++attribute_data_copy_count_; +OSStatus MockAppleKeychain::ItemDelete(AppleSecKeychainItemRef itemRef) const { return noErr; } -OSStatus MockAppleKeychain::ItemModifyAttributesAndData( - SecKeychainItemRef itemRef, - const SecKeychainAttributeList* attrList, - UInt32 length, - const void* data) const { - DCHECK(itemRef); - const char* fail_trigger = "fail_me"; - if (length == strlen(fail_trigger) && - memcmp(data, fail_trigger, length) == 0) { - return errSecAuthFailed; - } - - MockKeychainItemType key = - reinterpret_cast<MockKeychainItemType>(itemRef) - 1; - if (keychain_attr_list_.find(key) == keychain_attr_list_.end()) - return errSecInvalidItemRef; - - MockAppleKeychain* mutable_this = const_cast<MockAppleKeychain*>(this); - if (attrList) { - for (UInt32 change_attr = 0; change_attr < attrList->count; ++change_attr) { - if (attrList->attr[change_attr].tag == kSecCreatorItemAttr) { - void* data = attrList->attr[change_attr].data; - mutable_this->SetTestDataCreator(key, *(static_cast<OSType*>(data))); - } else { - NOTIMPLEMENTED(); - } - } - } - if (data) - mutable_this->SetTestDataPasswordBytes(key, data, length); - return noErr; -} - -OSStatus MockAppleKeychain::ItemFreeAttributesAndData( - SecKeychainAttributeList* attrList, - void* data) const { - --attribute_data_copy_count_; - return noErr; -} - -OSStatus MockAppleKeychain::ItemDelete(SecKeychainItemRef itemRef) const { - MockKeychainItemType key = - reinterpret_cast<MockKeychainItemType>(itemRef) - 1; - - for (unsigned int i = 0; i < keychain_attr_list_[key].count; ++i) { - if (keychain_attr_list_[key].attr[i].data) - free(keychain_attr_list_[key].attr[i].data); - } - free(keychain_attr_list_[key].attr); - if (keychain_data_[key].data) - free(keychain_data_[key].data); - - keychain_attr_list_.erase(key); - keychain_data_.erase(key); - added_via_api_.erase(key); - return noErr; -} - -OSStatus MockAppleKeychain::SearchCreateFromAttributes( - CFTypeRef keychainOrArray, - SecItemClass itemClass, - const SecKeychainAttributeList* attrList, - SecKeychainSearchRef* searchRef) const { - // Figure out which of our mock items matches, and set up the array we'll use - // to generate results out of SearchCopyNext. - remaining_search_results_.clear(); - for (MockKeychainAttributesMap::const_iterator it = - keychain_attr_list_.begin(); - it != keychain_attr_list_.end(); - ++it) { - bool mock_item_matches = true; - for (UInt32 search_attr = 0; search_attr < attrList->count; ++search_attr) { - SecKeychainAttribute* mock_attribute = - AttributeWithTag(it->second, attrList->attr[search_attr].tag); - if (mock_attribute->length != attrList->attr[search_attr].length || - memcmp(mock_attribute->data, attrList->attr[search_attr].data, - attrList->attr[search_attr].length) != 0) { - mock_item_matches = false; - break; - } - } - if (mock_item_matches) - remaining_search_results_.push_back(it->first); - } - - DCHECK(searchRef); - *searchRef = kDummySearchRef; - ++search_copy_count_; - return noErr; -} - -bool MockAppleKeychain::AlreadyContainsInternetPassword( - UInt32 serverNameLength, - const char* serverName, - UInt32 securityDomainLength, - const char* securityDomain, - UInt32 accountNameLength, - const char* accountName, - UInt32 pathLength, - const char* path, - UInt16 port, - SecProtocolType protocol, - SecAuthenticationType authenticationType) const { - for (MockKeychainAttributesMap::const_iterator it = - keychain_attr_list_.begin(); - it != keychain_attr_list_.end(); - ++it) { - SecKeychainAttribute* attribute; - attribute = AttributeWithTag(it->second, kSecServerItemAttr); - if ((attribute->length != serverNameLength) || - (attribute->data == NULL && *serverName != '\0') || - (attribute->data != NULL && *serverName == '\0') || - strncmp(serverName, - (const char*) attribute->data, - serverNameLength) != 0) { - continue; - } - attribute = AttributeWithTag(it->second, kSecSecurityDomainItemAttr); - if ((attribute->length != securityDomainLength) || - (attribute->data == NULL && *securityDomain != '\0') || - (attribute->data != NULL && *securityDomain == '\0') || - strncmp(securityDomain, - (const char*) attribute->data, - securityDomainLength) != 0) { - continue; - } - attribute = AttributeWithTag(it->second, kSecAccountItemAttr); - if ((attribute->length != accountNameLength) || - (attribute->data == NULL && *accountName != '\0') || - (attribute->data != NULL && *accountName == '\0') || - strncmp(accountName, - (const char*) attribute->data, - accountNameLength) != 0) { - continue; - } - attribute = AttributeWithTag(it->second, kSecPathItemAttr); - if ((attribute->length != pathLength) || - (attribute->data == NULL && *path != '\0') || - (attribute->data != NULL && *path == '\0') || - strncmp(path, - (const char*) attribute->data, - pathLength) != 0) { - continue; - } - attribute = AttributeWithTag(it->second, kSecPortItemAttr); - if ((attribute->data == NULL) || - (port != *(static_cast<UInt32*>(attribute->data)))) { - continue; - } - attribute = AttributeWithTag(it->second, kSecProtocolItemAttr); - if ((attribute->data == NULL) || - (protocol != *(static_cast<SecProtocolType*>(attribute->data)))) { - continue; - } - attribute = AttributeWithTag(it->second, kSecAuthenticationTypeItemAttr); - if ((attribute->data == NULL) || - (authenticationType != - *(static_cast<SecAuthenticationType*>(attribute->data)))) { - continue; - } - // The keychain already has this item, since all fields other than the - // password match. - return true; - } - return false; -} - -OSStatus MockAppleKeychain::AddInternetPassword( - SecKeychainRef keychain, - UInt32 serverNameLength, - const char* serverName, - UInt32 securityDomainLength, - const char* securityDomain, - UInt32 accountNameLength, - const char* accountName, - UInt32 pathLength, - const char* path, - UInt16 port, - SecProtocolType protocol, - SecAuthenticationType authenticationType, - UInt32 passwordLength, - const void* passwordData, - SecKeychainItemRef* itemRef) const { - - // Check for the magic duplicate item trigger. - if (strcmp(serverName, "some.domain.com") == 0) - return errSecDuplicateItem; - - // If the account already exists in the keychain, we don't add it. - if (AlreadyContainsInternetPassword(serverNameLength, serverName, - securityDomainLength, securityDomain, - accountNameLength, accountName, - pathLength, path, - port, protocol, - authenticationType)) { - return errSecDuplicateItem; - } - - // Pick the next unused slot. - MockKeychainItemType key = next_item_key_++; - - // Initialize keychain data storage at the target location. - InitializeKeychainData(key); - - MockAppleKeychain* mutable_this = const_cast<MockAppleKeychain*>(this); - mutable_this->SetTestDataBytes(key, kSecServerItemAttr, serverName, - serverNameLength); - mutable_this->SetTestDataBytes(key, kSecSecurityDomainItemAttr, - securityDomain, securityDomainLength); - mutable_this->SetTestDataBytes(key, kSecAccountItemAttr, accountName, - accountNameLength); - mutable_this->SetTestDataBytes(key, kSecPathItemAttr, path, pathLength); - mutable_this->SetTestDataPort(key, port); - mutable_this->SetTestDataProtocol(key, protocol); - mutable_this->SetTestDataAuthType(key, authenticationType); - mutable_this->SetTestDataPasswordBytes(key, passwordData, - passwordLength); - base::Time::Exploded exploded_time; - base::Time::Now().UTCExplode(&exploded_time); - char time_string[128]; - snprintf(time_string, sizeof(time_string), "%04d%02d%02d%02d%02d%02dZ", - exploded_time.year, exploded_time.month, exploded_time.day_of_month, - exploded_time.hour, exploded_time.minute, exploded_time.second); - mutable_this->SetTestDataString(key, kSecCreationDateItemAttr, time_string); - - added_via_api_.insert(key); - - if (itemRef) { - *itemRef = reinterpret_cast<SecKeychainItemRef>(key + 1); - ++keychain_item_copy_count_; - } - return noErr; -} - -OSStatus MockAppleKeychain::SearchCopyNext(SecKeychainSearchRef searchRef, - SecKeychainItemRef* itemRef) const { - if (remaining_search_results_.empty()) - return errSecItemNotFound; - MockKeychainItemType key = remaining_search_results_.front(); - remaining_search_results_.erase(remaining_search_results_.begin()); - *itemRef = reinterpret_cast<SecKeychainItemRef>(key + 1); - ++keychain_item_copy_count_; - return noErr; -} - -void MockAppleKeychain::Free(CFTypeRef ref) const { - if (!ref) - return; - - if (ref == kDummySearchRef) { - --search_copy_count_; - } else { - --keychain_item_copy_count_; - } -} - -int MockAppleKeychain::UnfreedSearchCount() const { - return search_copy_count_; -} - -int MockAppleKeychain::UnfreedKeychainItemCount() const { - return keychain_item_copy_count_; -} - -int MockAppleKeychain::UnfreedAttributeDataCount() const { - return attribute_data_copy_count_; -} - -bool MockAppleKeychain::CreatorCodesSetForAddedItems() const { - for (std::set<MockKeychainItemType>::const_iterator - i = added_via_api_.begin(); - i != added_via_api_.end(); - ++i) { - SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[*i], - kSecCreatorItemAttr); - OSType* data = static_cast<OSType*>(attribute->data); - if (*data == 0) - return false; - } - return true; -} - -void MockAppleKeychain::AddTestItem(const KeychainTestData& item_data) { - MockKeychainItemType key = next_item_key_++; - - InitializeKeychainData(key); - SetTestDataAuthType(key, item_data.auth_type); - SetTestDataString(key, kSecServerItemAttr, item_data.server); - SetTestDataProtocol(key, item_data.protocol); - SetTestDataString(key, kSecPathItemAttr, item_data.path); - SetTestDataPort(key, item_data.port); - SetTestDataString(key, kSecSecurityDomainItemAttr, - item_data.security_domain); - SetTestDataString(key, kSecCreationDateItemAttr, item_data.creation_date); - SetTestDataString(key, kSecAccountItemAttr, item_data.username); - SetTestDataPasswordString(key, item_data.password); - SetTestDataNegativeItem(key, item_data.negative_item); -} - } // namespace crypto
diff --git a/src/crypto/nss_crypto_module_delegate.h b/src/crypto/nss_crypto_module_delegate.h new file mode 100644 index 0000000..cb87070 --- /dev/null +++ b/src/crypto/nss_crypto_module_delegate.h
@@ -0,0 +1,46 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_ +#define CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_ + +#include <string> + +#include "base/memory/ref_counted.h" + +namespace crypto { + +// PK11_SetPasswordFunc is a global setting. An implementation of +// CryptoModuleBlockingPasswordDelegate should be passed using wincx() as the +// user data argument (|wincx|) to relevant NSS functions, which the global +// password handler will call to do the actual work. This delegate should only +// be used in NSS calls on worker threads due to the blocking nature. +class CryptoModuleBlockingPasswordDelegate + : public base::RefCountedThreadSafe<CryptoModuleBlockingPasswordDelegate> { + public: + + // Return a value suitable for passing to the |wincx| argument of relevant NSS + // functions. This should be used instead of passing the object pointer + // directly to avoid accidentally casting a pointer to a subclass to void* and + // then casting back to a pointer of the base class + void* wincx() { return this; } + + // Requests a password to unlock |slot_name|. The interface is synchronous + // because NSS cannot issue an asynchronous request. |retry| is true if this + // is a request for the retry and we previously returned the wrong password. + // The implementation should set |*cancelled| to true if the user cancelled + // instead of entering a password, otherwise it should return the password the + // user entered. + virtual std::string RequestPassword(const std::string& slot_name, bool retry, + bool* cancelled) = 0; + + protected: + friend class base::RefCountedThreadSafe<CryptoModuleBlockingPasswordDelegate>; + + virtual ~CryptoModuleBlockingPasswordDelegate() {} +}; + +} // namespace crypto + +#endif // CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_
diff --git a/src/crypto/nss_key_util.cc b/src/crypto/nss_key_util.cc new file mode 100644 index 0000000..5b43743 --- /dev/null +++ b/src/crypto/nss_key_util.cc
@@ -0,0 +1,154 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/nss_key_util.h" + +#include <cryptohi.h> +#include <keyhi.h> +#include <pk11pub.h> +#include <secmod.h> + +#include <memory> + +#include "base/logging.h" +#include "crypto/nss_util.h" +#include "crypto/nss_util_internal.h" +#include "starboard/types.h" + +namespace crypto { + +namespace { + +struct PublicKeyInfoDeleter { + inline void operator()(CERTSubjectPublicKeyInfo* spki) { + SECKEY_DestroySubjectPublicKeyInfo(spki); + } +}; + +typedef std::unique_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter> + ScopedPublicKeyInfo; + +// Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing +// the CKA_ID of that public key or nullptr on error. +ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t>& input) { + // First, decode and save the public key. + SECItem key_der; + key_der.type = siBuffer; + key_der.data = const_cast<unsigned char*>(input.data()); + key_der.len = input.size(); + + ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der)); + if (!spki) + return nullptr; + + ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get())); + if (!result) + return nullptr; + + // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA keys are + // supported. + if (SECKEY_GetPublicKeyType(result.get()) != rsaKey) + return nullptr; + + return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus)); +} + +} // namespace + +bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot, + uint16_t num_bits, + bool permanent, + ScopedSECKEYPublicKey* public_key, + ScopedSECKEYPrivateKey* private_key) { + DCHECK(slot); + + PK11RSAGenParams param; + param.keySizeInBits = num_bits; + param.pe = 65537L; + SECKEYPublicKey* public_key_raw = nullptr; + private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, + ¶m, &public_key_raw, permanent, + permanent /* sensitive */, nullptr)); + if (!*private_key) + return false; + + public_key->reset(public_key_raw); + return true; +} + +ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo( + PK11SlotInfo* slot, + const std::vector<uint8_t>& input, + bool permanent) { + DCHECK(slot); + + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + DCHECK(arena); + + // Excess data is illegal, but NSS silently accepts it, so first ensure that + // |input| consists of a single ASN.1 element. + SECItem input_item; + input_item.data = const_cast<unsigned char*>(input.data()); + input_item.len = input.size(); + SECItem der_private_key_info; + SECStatus rv = + SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info, + SEC_ASN1_GET(SEC_AnyTemplate), &input_item); + if (rv != SECSuccess) + return nullptr; + + // Allow the private key to be used for key unwrapping, data decryption, + // and signature generation. + const unsigned int key_usage = + KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE; + SECKEYPrivateKey* key_raw = nullptr; + rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot, &der_private_key_info, nullptr, nullptr, permanent, + permanent /* sensitive */, key_usage, &key_raw, nullptr); + if (rv != SECSuccess) + return nullptr; + return ScopedSECKEYPrivateKey(key_raw); +} + +ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo( + const std::vector<uint8_t>& input) { + EnsureNSSInit(); + + ScopedSECItem cka_id(MakeIDFromSPKI(input)); + if (!cka_id) + return nullptr; + + // Search all slots in all modules for the key with the given ID. + AutoSECMODListReadLock auto_lock; + const SECMODModuleList* head = SECMOD_GetDefaultModuleList(); + for (const SECMODModuleList* item = head; item != nullptr; + item = item->next) { + int slot_count = item->module->loaded ? item->module->slotCount : 0; + for (int i = 0; i < slot_count; i++) { + // Look for the key in slot |i|. + ScopedSECKEYPrivateKey key( + PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr)); + if (key) + return key; + } + } + + // The key wasn't found in any module. + return nullptr; +} + +ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot( + const std::vector<uint8_t>& input, + PK11SlotInfo* slot) { + DCHECK(slot); + + ScopedSECItem cka_id(MakeIDFromSPKI(input)); + if (!cka_id) + return nullptr; + + return ScopedSECKEYPrivateKey( + PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr)); +} + +} // namespace crypto
diff --git a/src/crypto/nss_key_util.h b/src/crypto/nss_key_util.h new file mode 100644 index 0000000..da2d271 --- /dev/null +++ b/src/crypto/nss_key_util.h
@@ -0,0 +1,53 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_NSS_KEY_UTIL_H_ +#define CRYPTO_NSS_KEY_UTIL_H_ + +#include <vector> + +#include "build/build_config.h" +#include "crypto/crypto_export.h" +#include "crypto/scoped_nss_types.h" +#include "starboard/types.h" + +typedef struct PK11SlotInfoStr PK11SlotInfo; + +namespace crypto { + +// Generates a new RSA keypair of size |num_bits| in |slot|. Returns true on +// success and false on failure. If |permanent| is true, the resulting key is +// permanent and is not exportable in plaintext form. +CRYPTO_EXPORT bool GenerateRSAKeyPairNSS( + PK11SlotInfo* slot, + uint16_t num_bits, + bool permanent, + ScopedSECKEYPublicKey* out_public_key, + ScopedSECKEYPrivateKey* out_private_key); + +// Imports a private key from |input| into |slot|. |input| is interpreted as a +// DER-encoded PrivateKeyInfo block from PKCS #8. Returns nullptr on error. If +// |permanent| is true, the resulting key is permanent and is not exportable in +// plaintext form. +CRYPTO_EXPORT ScopedSECKEYPrivateKey +ImportNSSKeyFromPrivateKeyInfo(PK11SlotInfo* slot, + const std::vector<uint8_t>& input, + bool permanent); + +// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for +// the private key half in the key database. Returns the private key on success +// or nullptr on error. +CRYPTO_EXPORT ScopedSECKEYPrivateKey +FindNSSKeyFromPublicKeyInfo(const std::vector<uint8_t>& input); + +// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for +// the private key half in the slot specified by |slot|. Returns the private key +// on success or nullptr on error. +CRYPTO_EXPORT ScopedSECKEYPrivateKey +FindNSSKeyFromPublicKeyInfoInSlot(const std::vector<uint8_t>& input, + PK11SlotInfo* slot); + +} // namespace crypto + +#endif // CRYPTO_NSS_KEY_UTIL_H_
diff --git a/src/crypto/nss_key_util_unittest.cc b/src/crypto/nss_key_util_unittest.cc new file mode 100644 index 0000000..874fa98 --- /dev/null +++ b/src/crypto/nss_key_util_unittest.cc
@@ -0,0 +1,86 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/nss_key_util.h" + +#include <keyhi.h> +#include <pk11pub.h> + +#include <vector> + +#include "crypto/nss_util.h" +#include "crypto/scoped_nss_types.h" +#include "starboard/types.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace crypto { + +class NSSKeyUtilTest : public testing::Test { + public: + void SetUp() override { + EnsureNSSInit(); + + internal_slot_.reset(PK11_GetInternalSlot()); + ASSERT_TRUE(internal_slot_); + } + + PK11SlotInfo* internal_slot() { return internal_slot_.get(); } + + private: + ScopedPK11Slot internal_slot_; +}; + +TEST_F(NSSKeyUtilTest, GenerateRSAKeyPairNSS) { + const int kKeySizeBits = 1024; + + ScopedSECKEYPublicKey public_key; + ScopedSECKEYPrivateKey private_key; + ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), kKeySizeBits, + false /* not permanent */, &public_key, + &private_key)); + + EXPECT_EQ(rsaKey, SECKEY_GetPublicKeyType(public_key.get())); + EXPECT_EQ(rsaKey, SECKEY_GetPrivateKeyType(private_key.get())); + EXPECT_EQ((kKeySizeBits + 7) / 8, + PK11_GetPrivateModulusLen(private_key.get())); +} + +TEST_F(NSSKeyUtilTest, FindNSSKeyFromPublicKeyInfo) { + // Create an NSS keypair, which will put the keys in the user's NSSDB. + ScopedSECKEYPublicKey public_key; + ScopedSECKEYPrivateKey private_key; + ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 512, + false /* not permanent */, &public_key, + &private_key)); + + ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get())); + ASSERT_TRUE(item); + std::vector<uint8_t> public_key_der(item->data, item->data + item->len); + + ScopedSECKEYPrivateKey private_key2 = + FindNSSKeyFromPublicKeyInfo(public_key_der); + ASSERT_TRUE(private_key2); + EXPECT_EQ(private_key->pkcs11ID, private_key2->pkcs11ID); +} + +TEST_F(NSSKeyUtilTest, FailedFindNSSKeyFromPublicKeyInfo) { + // Create an NSS keypair, which will put the keys in the user's NSSDB. + ScopedSECKEYPublicKey public_key; + ScopedSECKEYPrivateKey private_key; + ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 512, + false /* not permanent */, &public_key, + &private_key)); + + ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get())); + ASSERT_TRUE(item); + std::vector<uint8_t> public_key_der(item->data, item->data + item->len); + + // Remove the keys from the DB, and make sure we can't find them again. + PK11_DestroyTokenObject(private_key->pkcs11Slot, private_key->pkcs11ID); + PK11_DestroyTokenObject(public_key->pkcs11Slot, public_key->pkcs11ID); + + EXPECT_FALSE(FindNSSKeyFromPublicKeyInfo(public_key_der)); +} + +} // namespace crypto
diff --git a/src/crypto/nss_util.cc b/src/crypto/nss_util.cc new file mode 100644 index 0000000..1416529 --- /dev/null +++ b/src/crypto/nss_util.cc
@@ -0,0 +1,907 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/nss_util.h" + +#include <nss.h> +#include <pk11pub.h> +#include <plarena.h> +#include <prerror.h> +#include <prinit.h> +#include <prtime.h> +#include <secmod.h> + +#include <map> +#include <memory> +#include <utility> +#include <vector> + +#include "starboard/types.h" + +#include "base/base_paths.h" +#include "base/bind.h" +#include "base/debug/alias.h" +#include "base/debug/stack_trace.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/lazy_instance.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/path_service.h" +#include "base/strings/stringprintf.h" +#include "base/task/post_task.h" +#include "base/threading/scoped_blocking_call.h" +#include "base/threading/thread_checker.h" +#include "base/threading/thread_restrictions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "build/build_config.h" +#include "crypto/nss_crypto_module_delegate.h" +#include "crypto/nss_util_internal.h" + +#if defined(OS_CHROMEOS) +#include <dlfcn.h> +#endif + +namespace crypto { + +namespace { + +#if defined(OS_CHROMEOS) +const char kUserNSSDatabaseName[] = "UserNSSDB"; + +// Constants for loading the Chrome OS TPM-backed PKCS #11 library. +const char kChapsModuleName[] = "Chaps"; +const char kChapsPath[] = "libchaps.so"; + +// Fake certificate authority database used for testing. +static const base::FilePath::CharType kReadOnlyCertDB[] = + FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb"); +#endif // defined(OS_CHROMEOS) + +std::string GetNSSErrorMessage() { + std::string result; + if (PR_GetErrorTextLength()) { + std::unique_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]); + PRInt32 copied = PR_GetErrorText(error_text.get()); + result = std::string(error_text.get(), copied); + } else { + result = base::StringPrintf("NSS error code: %d", PR_GetError()); + } + return result; +} + +#if !defined(OS_CHROMEOS) +base::FilePath GetDefaultConfigDirectory() { + base::FilePath dir; + base::PathService::Get(base::DIR_HOME, &dir); + if (dir.empty()) { + LOG(ERROR) << "Failed to get home directory."; + return dir; + } + dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); + if (!base::CreateDirectory(dir)) { + LOG(ERROR) << "Failed to create " << dir.value() << " directory."; + dir.clear(); + } + DVLOG(2) << "DefaultConfigDirectory: " << dir.value(); + return dir; +} +#endif // !defined(OS_CHROMEOS) + +// On non-Chrome OS platforms, return the default config directory. On Chrome OS +// test images, return a read-only directory with fake root CA certs (which are +// used by the local Google Accounts server mock we use when testing our login +// code). On Chrome OS non-test images (where the read-only directory doesn't +// exist), return an empty path. +base::FilePath GetInitialConfigDirectory() { +#if defined(OS_CHROMEOS) + base::FilePath database_dir = base::FilePath(kReadOnlyCertDB); + if (!base::PathExists(database_dir)) + database_dir.clear(); + return database_dir; +#else + return GetDefaultConfigDirectory(); +#endif // defined(OS_CHROMEOS) +} + +// This callback for NSS forwards all requests to a caller-specified +// CryptoModuleBlockingPasswordDelegate object. +char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) { + crypto::CryptoModuleBlockingPasswordDelegate* delegate = + reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg); + if (delegate) { + bool cancelled = false; + std::string password = delegate->RequestPassword(PK11_GetTokenName(slot), + retry != PR_FALSE, + &cancelled); + if (cancelled) + return nullptr; + char* result = PORT_Strdup(password.c_str()); + password.replace(0, password.size(), password.size(), 0); + return result; + } + DLOG(ERROR) << "PK11 password requested with nullptr arg"; + return nullptr; +} + +// A singleton to initialize/deinitialize NSPR. +// Separate from the NSS singleton because we initialize NSPR on the UI thread. +// Now that we're leaking the singleton, we could merge back with the NSS +// singleton. +class NSPRInitSingleton { + private: + friend struct base::LazyInstanceTraitsBase<NSPRInitSingleton>; + + NSPRInitSingleton() { + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + } + + // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS + // to prevent non-joinable threads from using NSS after it's already been + // shut down. + ~NSPRInitSingleton() = delete; +}; + +base::LazyInstance<NSPRInitSingleton>::Leaky + g_nspr_singleton = LAZY_INSTANCE_INITIALIZER; + +// Force a crash with error info on NSS_NoDB_Init failure. +void CrashOnNSSInitFailure() { + int nss_error = PR_GetError(); + int os_error = PR_GetOSError(); + base::debug::Alias(&nss_error); + base::debug::Alias(&os_error); + LOG(ERROR) << "Error initializing NSS without a persistent database: " + << GetNSSErrorMessage(); + LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error; +} + +#if defined(OS_CHROMEOS) +class ChromeOSUserData { + public: + explicit ChromeOSUserData(ScopedPK11Slot public_slot) + : public_slot_(std::move(public_slot)), + private_slot_initialization_started_(false) {} + ~ChromeOSUserData() { + if (public_slot_) { + SECStatus status = SECMOD_CloseUserDB(public_slot_.get()); + if (status != SECSuccess) + PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); + } + } + + ScopedPK11Slot GetPublicSlot() { + return ScopedPK11Slot(public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) + : nullptr); + } + + ScopedPK11Slot GetPrivateSlot( + base::OnceCallback<void(ScopedPK11Slot)> callback) { + if (private_slot_) + return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())); + if (!callback.is_null()) + tpm_ready_callback_list_.push_back(std::move(callback)); + return ScopedPK11Slot(); + } + + void SetPrivateSlot(ScopedPK11Slot private_slot) { + DCHECK(!private_slot_); + private_slot_ = std::move(private_slot); + + SlotReadyCallbackList callback_list; + callback_list.swap(tpm_ready_callback_list_); + for (SlotReadyCallbackList::iterator i = callback_list.begin(); + i != callback_list.end(); + ++i) { + std::move(*i).Run( + ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()))); + } + } + + bool private_slot_initialization_started() const { + return private_slot_initialization_started_; + } + + void set_private_slot_initialization_started() { + private_slot_initialization_started_ = true; + } + + private: + ScopedPK11Slot public_slot_; + ScopedPK11Slot private_slot_; + + bool private_slot_initialization_started_; + + typedef std::vector<base::OnceCallback<void(ScopedPK11Slot)>> + SlotReadyCallbackList; + SlotReadyCallbackList tpm_ready_callback_list_; +}; + +class ScopedChapsLoadFixup { + public: + ScopedChapsLoadFixup(); + ~ScopedChapsLoadFixup(); + + private: +#if defined(COMPONENT_BUILD) + void* chaps_handle_; +#endif +}; + +#if defined(COMPONENT_BUILD) + +ScopedChapsLoadFixup::ScopedChapsLoadFixup() { + // HACK: libchaps links the system protobuf and there are symbol conflicts + // with the bundled copy. Load chaps with RTLD_DEEPBIND to workaround. + chaps_handle_ = dlopen(kChapsPath, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND); +} + +ScopedChapsLoadFixup::~ScopedChapsLoadFixup() { + // LoadModule() will have taken a 2nd reference. + if (chaps_handle_) + dlclose(chaps_handle_); +} + +#else + +ScopedChapsLoadFixup::ScopedChapsLoadFixup() {} +ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {} + +#endif // defined(COMPONENT_BUILD) +#endif // defined(OS_CHROMEOS) + +class NSSInitSingleton { + public: +#if defined(OS_CHROMEOS) + // Used with PostTaskAndReply to pass handles to worker thread and back. + struct TPMModuleAndSlot { + explicit TPMModuleAndSlot(SECMODModule* init_chaps_module) + : chaps_module(init_chaps_module) {} + SECMODModule* chaps_module; + crypto::ScopedPK11Slot tpm_slot; + }; + + ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name, + const base::FilePath& path) { + DCHECK(thread_checker_.CalledOnValidThread()); + // NSS is allowed to do IO on the current thread since dispatching + // to a dedicated thread would still have the affect of blocking + // the current thread, due to NSS's internal locking requirements + base::ThreadRestrictions::ScopedAllowIO allow_io; + + base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb"); + if (!base::CreateDirectory(nssdb_path)) { + LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory."; + return ScopedPK11Slot(); + } + return OpenSoftwareNSSDB(nssdb_path, db_name); + } + + void EnableTPMTokenForNSS() { + DCHECK(thread_checker_.CalledOnValidThread()); + + // If this gets set, then we'll use the TPM for certs with + // private keys, otherwise we'll fall back to the software + // implementation. + tpm_token_enabled_for_nss_ = true; + } + + bool IsTPMTokenEnabledForNSS() { + DCHECK(thread_checker_.CalledOnValidThread()); + return tpm_token_enabled_for_nss_; + } + + void InitializeTPMTokenAndSystemSlot( + int system_slot_id, + base::OnceCallback<void(bool)> callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + // Should not be called while there is already an initialization in + // progress. + DCHECK(!initializing_tpm_token_); + // If EnableTPMTokenForNSS hasn't been called, return false. + if (!tpm_token_enabled_for_nss_) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), false)); + return; + } + + // If everything is already initialized, then return true. + // Note that only |tpm_slot_| is checked, since |chaps_module_| could be + // nullptr in tests while |tpm_slot_| has been set to the test DB. + if (tpm_slot_) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), true)); + return; + } + + // Note that a reference is not taken to chaps_module_. This is safe since + // NSSInitSingleton is Leaky, so the reference it holds is never released. + std::unique_ptr<TPMModuleAndSlot> tpm_args( + new TPMModuleAndSlot(chaps_module_)); + TPMModuleAndSlot* tpm_args_ptr = tpm_args.get(); + base::PostTaskWithTraitsAndReply( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(&NSSInitSingleton::InitializeTPMTokenInThreadPool, + system_slot_id, tpm_args_ptr), + base::BindOnce(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot, + base::Unretained(this), // NSSInitSingleton is leaky + std::move(callback), std::move(tpm_args))); + initializing_tpm_token_ = true; + } + + static void InitializeTPMTokenInThreadPool(CK_SLOT_ID token_slot_id, + TPMModuleAndSlot* tpm_args) { + // NSS functions may reenter //net via extension hooks. If the reentered + // code needs to synchronously wait for a task to run but the thread pool in + // which that task must run doesn't have enough threads to schedule it, a + // deadlock occurs. To prevent that, the base::ScopedBlockingCall below + // increments the thread pool capacity for the duration of the TPM + // initialization. + base::ScopedBlockingCall scoped_blocking_call( + base::BlockingType::WILL_BLOCK); + + if (!tpm_args->chaps_module) { + ScopedChapsLoadFixup chaps_loader; + + DVLOG(3) << "Loading chaps..."; + tpm_args->chaps_module = LoadModule( + kChapsModuleName, + kChapsPath, + // For more details on these parameters, see: + // https://developer.mozilla.org/en/PKCS11_Module_Specs + // slotFlags=[PublicCerts] -- Certificates and public keys can be + // read from this slot without requiring a call to C_Login. + // askpw=only -- Only authenticate to the token when necessary. + "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); + } + if (tpm_args->chaps_module) { + tpm_args->tpm_slot = + GetTPMSlotForIdInThreadPool(tpm_args->chaps_module, token_slot_id); + } + } + + void OnInitializedTPMTokenAndSystemSlot( + base::OnceCallback<void(bool)> callback, + std::unique_ptr<TPMModuleAndSlot> tpm_args) { + DCHECK(thread_checker_.CalledOnValidThread()); + DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module + << ", got tpm slot: " << !!tpm_args->tpm_slot; + + chaps_module_ = tpm_args->chaps_module; + tpm_slot_ = std::move(tpm_args->tpm_slot); + if (!chaps_module_ && test_system_slot_) { + // chromeos_unittests try to test the TPM initialization process. If we + // have a test DB open, pretend that it is the TPM slot. + tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get())); + } + initializing_tpm_token_ = false; + + if (tpm_slot_) + RunAndClearTPMReadyCallbackList(); + + std::move(callback).Run(!!tpm_slot_); + } + + void RunAndClearTPMReadyCallbackList() { + TPMReadyCallbackList callback_list; + callback_list.swap(tpm_ready_callback_list_); + for (TPMReadyCallbackList::iterator i = callback_list.begin(); + i != callback_list.end(); + ++i) { + std::move(*i).Run(); + } + } + + bool IsTPMTokenReady(base::OnceClosure callback) { + if (!callback.is_null()) { + // Cannot DCHECK in the general case yet, but since the callback is + // a new addition to the API, DCHECK to make sure at least the new uses + // don't regress. + DCHECK(thread_checker_.CalledOnValidThread()); + } else if (!thread_checker_.CalledOnValidThread()) { + // TODO(mattm): Change to DCHECK when callers have been fixed. + DVLOG(1) << "Called on wrong thread.\n" + << base::debug::StackTrace().ToString(); + } + + if (tpm_slot_) + return true; + + if (!callback.is_null()) + tpm_ready_callback_list_.push_back(std::move(callback)); + + return false; + } + + // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot + // id as an int. This should be safe since this is only used with chaps, which + // we also control. + static crypto::ScopedPK11Slot GetTPMSlotForIdInThreadPool( + SECMODModule* chaps_module, + CK_SLOT_ID slot_id) { + DCHECK(chaps_module); + + DVLOG(3) << "Poking chaps module."; + SECStatus rv = SECMOD_UpdateSlotList(chaps_module); + if (rv != SECSuccess) + PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); + + PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id); + if (!slot) + LOG(ERROR) << "TPM slot " << slot_id << " not found."; + return crypto::ScopedPK11Slot(slot); + } + + bool InitializeNSSForChromeOSUser(const std::string& username_hash, + const base::FilePath& path) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) { + // This user already exists in our mapping. + DVLOG(2) << username_hash << " already initialized."; + return false; + } + + DVLOG(2) << "Opening NSS DB " << path.value(); + std::string db_name = base::StringPrintf( + "%s %s", kUserNSSDatabaseName, username_hash.c_str()); + ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path)); + chromeos_user_map_[username_hash] = + std::make_unique<ChromeOSUserData>(std::move(public_slot)); + return true; + } + + bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); + + return !chromeos_user_map_[username_hash] + ->private_slot_initialization_started(); + } + + void WillInitializeTPMForChromeOSUser(const std::string& username_hash) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); + + chromeos_user_map_[username_hash] + ->set_private_slot_initialization_started(); + } + + void InitializeTPMForChromeOSUser(const std::string& username_hash, + CK_SLOT_ID slot_id) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); + DCHECK(chromeos_user_map_[username_hash]-> + private_slot_initialization_started()); + + if (!chaps_module_) + return; + + // Note that a reference is not taken to chaps_module_. This is safe since + // NSSInitSingleton is Leaky, so the reference it holds is never released. + std::unique_ptr<TPMModuleAndSlot> tpm_args( + new TPMModuleAndSlot(chaps_module_)); + TPMModuleAndSlot* tpm_args_ptr = tpm_args.get(); + base::PostTaskWithTraitsAndReply( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(&NSSInitSingleton::InitializeTPMTokenInThreadPool, + slot_id, tpm_args_ptr), + base::BindOnce(&NSSInitSingleton::OnInitializedTPMForChromeOSUser, + base::Unretained(this), // NSSInitSingleton is leaky + username_hash, std::move(tpm_args))); + } + + void OnInitializedTPMForChromeOSUser( + const std::string& username_hash, + std::unique_ptr<TPMModuleAndSlot> tpm_args) { + DCHECK(thread_checker_.CalledOnValidThread()); + DVLOG(2) << "Got tpm slot for " << username_hash << " " + << !!tpm_args->tpm_slot; + chromeos_user_map_[username_hash]->SetPrivateSlot( + std::move(tpm_args->tpm_slot)); + } + + void InitializePrivateSoftwareSlotForChromeOSUser( + const std::string& username_hash) { + DCHECK(thread_checker_.CalledOnValidThread()); + VLOG(1) << "using software private slot for " << username_hash; + DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); + DCHECK(chromeos_user_map_[username_hash]-> + private_slot_initialization_started()); + + if (prepared_test_private_slot_) { + chromeos_user_map_[username_hash]->SetPrivateSlot( + std::move(prepared_test_private_slot_)); + return; + } + + chromeos_user_map_[username_hash]->SetPrivateSlot( + chromeos_user_map_[username_hash]->GetPublicSlot()); + } + + ScopedPK11Slot GetPublicSlotForChromeOSUser( + const std::string& username_hash) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (username_hash.empty()) { + DVLOG(2) << "empty username_hash"; + return ScopedPK11Slot(); + } + + if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) { + LOG(ERROR) << username_hash << " not initialized."; + return ScopedPK11Slot(); + } + return chromeos_user_map_[username_hash]->GetPublicSlot(); + } + + ScopedPK11Slot GetPrivateSlotForChromeOSUser( + const std::string& username_hash, + base::OnceCallback<void(ScopedPK11Slot)> callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (username_hash.empty()) { + DVLOG(2) << "empty username_hash"; + if (!callback.is_null()) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), ScopedPK11Slot())); + } + return ScopedPK11Slot(); + } + + DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); + + return chromeos_user_map_[username_hash]->GetPrivateSlot( + std::move(callback)); + } + + void CloseChromeOSUserForTesting(const std::string& username_hash) { + DCHECK(thread_checker_.CalledOnValidThread()); + auto i = chromeos_user_map_.find(username_hash); + DCHECK(i != chromeos_user_map_.end()); + chromeos_user_map_.erase(i); + } + + void SetSystemKeySlotForTesting(ScopedPK11Slot slot) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // Ensure that a previous value of test_system_slot_ is not overwritten. + // Unsetting, i.e. setting a nullptr, however is allowed. + DCHECK(!slot || !test_system_slot_); + test_system_slot_ = std::move(slot); + if (test_system_slot_) { + tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get())); + RunAndClearTPMReadyCallbackList(); + } else { + tpm_slot_.reset(); + } + } + + void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // Ensure that a previous value of prepared_test_private_slot_ is not + // overwritten. Unsetting, i.e. setting a nullptr, however is allowed. + DCHECK(!slot || !prepared_test_private_slot_); + prepared_test_private_slot_ = std::move(slot); + } +#endif // defined(OS_CHROMEOS) + +#if !defined(OS_CHROMEOS) + PK11SlotInfo* GetPersistentNSSKeySlot() { + // TODO(mattm): Change to DCHECK when callers have been fixed. + if (!thread_checker_.CalledOnValidThread()) { + DVLOG(1) << "Called on wrong thread.\n" + << base::debug::StackTrace().ToString(); + } + + return PK11_GetInternalKeySlot(); + } +#endif + +#if defined(OS_CHROMEOS) + void GetSystemNSSKeySlotCallback( + base::OnceCallback<void(ScopedPK11Slot)> callback) { + std::move(callback).Run( + ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get()))); + } + + ScopedPK11Slot GetSystemNSSKeySlot( + base::OnceCallback<void(ScopedPK11Slot)> callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + // TODO(mattm): chromeos::TPMTokenloader always calls + // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is + // disabled, tpm_slot_ will be the first user's slot instead. Can that be + // detected and return nullptr instead? + + base::OnceClosure wrapped_callback; + if (!callback.is_null()) { + wrapped_callback = base::BindOnce( + &NSSInitSingleton::GetSystemNSSKeySlotCallback, + base::Unretained(this) /* singleton is leaky */, std::move(callback)); + } + if (IsTPMTokenReady(std::move(wrapped_callback))) + return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get())); + return ScopedPK11Slot(); + } +#endif + + private: + friend struct base::LazyInstanceTraitsBase<NSSInitSingleton>; + + NSSInitSingleton() + : tpm_token_enabled_for_nss_(false), + initializing_tpm_token_(false), + chaps_module_(nullptr), + root_(nullptr) { + // Initializing NSS causes us to do blocking IO. + // Temporarily allow it until we fix + // http://code.google.com/p/chromium/issues/detail?id=59847 + base::ThreadRestrictions::ScopedAllowIO allow_io; + + // It's safe to construct on any thread, since LazyInstance will prevent any + // other threads from accessing until the constructor is done. + thread_checker_.DetachFromThread(); + + EnsureNSPRInit(); + + // We *must* have NSS >= 3.26 at compile time. + static_assert((NSS_VMAJOR == 3 && NSS_VMINOR >= 26) || (NSS_VMAJOR > 3), + "nss version check failed"); + // Also check the run-time NSS version. + // NSS_VersionCheck is a >= check, not strict equality. + if (!NSS_VersionCheck("3.26")) { + LOG(FATAL) << "NSS_VersionCheck(\"3.26\") failed. NSS >= 3.26 is " + "required. Please upgrade to the latest NSS, and if you " + "still get this error, contact your distribution " + "maintainer."; + } + + SECStatus status = SECFailure; + base::FilePath database_dir = GetInitialConfigDirectory(); + if (!database_dir.empty()) { + // Initialize with a persistent database (likely, ~/.pki/nssdb). + // Use "sql:" which can be shared by multiple processes safely. + std::string nss_config_dir = + base::StringPrintf("sql:%s", database_dir.value().c_str()); +#if defined(OS_CHROMEOS) + status = NSS_Init(nss_config_dir.c_str()); +#else + status = NSS_InitReadWrite(nss_config_dir.c_str()); +#endif + if (status != SECSuccess) { + LOG(ERROR) << "Error initializing NSS with a persistent " + "database (" << nss_config_dir + << "): " << GetNSSErrorMessage(); + } + } + if (status != SECSuccess) { + VLOG(1) << "Initializing NSS without a persistent database."; + status = NSS_NoDB_Init(nullptr); + if (status != SECSuccess) { + CrashOnNSSInitFailure(); + return; + } + } + + PK11_SetPasswordFunc(PKCS11PasswordFunc); + + // If we haven't initialized the password for the NSS databases, + // initialize an empty-string password so that we don't need to + // log in. + PK11SlotInfo* slot = PK11_GetInternalKeySlot(); + if (slot) { + // PK11_InitPin may write to the keyDB, but no other thread can use NSS + // yet, so we don't need to lock. + if (PK11_NeedUserInit(slot)) + PK11_InitPin(slot, nullptr, nullptr); + PK11_FreeSlot(slot); + } + + root_ = InitDefaultRootCerts(); + + // Disable MD5 certificate signatures. (They are disabled by default in + // NSS 3.14.) + NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE); + NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, + 0, NSS_USE_ALG_IN_CERT_SIGNATURE); + } + + // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS + // to prevent non-joinable threads from using NSS after it's already been + // shut down. + ~NSSInitSingleton() = delete; + + // Load nss's built-in root certs. + SECMODModule* InitDefaultRootCerts() { + SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", nullptr); + if (root) + return root; + + // Aw, snap. Can't find/load root cert shared library. + // This will make it hard to talk to anybody via https. + // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed. + return nullptr; + } + + // Load the given module for this NSS session. + static SECMODModule* LoadModule(const char* name, + const char* library_path, + const char* params) { + std::string modparams = base::StringPrintf( + "name=\"%s\" library=\"%s\" %s", + name, library_path, params ? params : ""); + + // Shouldn't need to const_cast here, but SECMOD doesn't properly + // declare input string arguments as const. Bug + // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed + // on NSS codebase to address this. + SECMODModule* module = SECMOD_LoadUserModule( + const_cast<char*>(modparams.c_str()), nullptr, PR_FALSE); + if (!module) { + LOG(ERROR) << "Error loading " << name << " module into NSS: " + << GetNSSErrorMessage(); + return nullptr; + } + if (!module->loaded) { + LOG(ERROR) << "After loading " << name << ", loaded==false: " + << GetNSSErrorMessage(); + SECMOD_DestroyModule(module); + return nullptr; + } + return module; + } + + bool tpm_token_enabled_for_nss_; + bool initializing_tpm_token_; + typedef std::vector<base::OnceClosure> TPMReadyCallbackList; + TPMReadyCallbackList tpm_ready_callback_list_; + SECMODModule* chaps_module_; + crypto::ScopedPK11Slot tpm_slot_; + SECMODModule* root_; +#if defined(OS_CHROMEOS) + std::map<std::string, std::unique_ptr<ChromeOSUserData>> chromeos_user_map_; + ScopedPK11Slot test_system_slot_; + ScopedPK11Slot prepared_test_private_slot_; +#endif + + base::ThreadChecker thread_checker_; +}; + +base::LazyInstance<NSSInitSingleton>::Leaky + g_nss_singleton = LAZY_INSTANCE_INITIALIZER; +} // namespace + +ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path, + const std::string& description) { + const std::string modspec = + base::StringPrintf("configDir='sql:%s' tokenDescription='%s'", + path.value().c_str(), + description.c_str()); + PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); + if (db_slot) { + if (PK11_NeedUserInit(db_slot)) + PK11_InitPin(db_slot, nullptr, nullptr); + } else { + LOG(ERROR) << "Error opening persistent database (" << modspec + << "): " << GetNSSErrorMessage(); + } + return ScopedPK11Slot(db_slot); +} + +void EnsureNSPRInit() { + g_nspr_singleton.Get(); +} + +void EnsureNSSInit() { + g_nss_singleton.Get(); +} + +bool CheckNSSVersion(const char* version) { + return !!NSS_VersionCheck(version); +} + +AutoSECMODListReadLock::AutoSECMODListReadLock() + : lock_(SECMOD_GetDefaultModuleListLock()) { + SECMOD_GetReadLock(lock_); + } + +AutoSECMODListReadLock::~AutoSECMODListReadLock() { + SECMOD_ReleaseReadLock(lock_); +} + +#if defined(OS_CHROMEOS) +ScopedPK11Slot GetSystemNSSKeySlot( + base::OnceCallback<void(ScopedPK11Slot)> callback) { + return g_nss_singleton.Get().GetSystemNSSKeySlot(std::move(callback)); +} + +void SetSystemKeySlotForTesting(ScopedPK11Slot slot) { + g_nss_singleton.Get().SetSystemKeySlotForTesting(std::move(slot)); +} + +void EnableTPMTokenForNSS() { + g_nss_singleton.Get().EnableTPMTokenForNSS(); +} + +bool IsTPMTokenEnabledForNSS() { + return g_nss_singleton.Get().IsTPMTokenEnabledForNSS(); +} + +bool IsTPMTokenReady(base::OnceClosure callback) { + return g_nss_singleton.Get().IsTPMTokenReady(std::move(callback)); +} + +void InitializeTPMTokenAndSystemSlot(int token_slot_id, + base::OnceCallback<void(bool)> callback) { + g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id, + std::move(callback)); +} + +bool InitializeNSSForChromeOSUser(const std::string& username_hash, + const base::FilePath& path) { + return g_nss_singleton.Get().InitializeNSSForChromeOSUser(username_hash, + path); +} + +bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) { + return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser( + username_hash); +} + +void WillInitializeTPMForChromeOSUser(const std::string& username_hash) { + g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash); +} + +void InitializeTPMForChromeOSUser( + const std::string& username_hash, + CK_SLOT_ID slot_id) { + g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id); +} + +void InitializePrivateSoftwareSlotForChromeOSUser( + const std::string& username_hash) { + g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser( + username_hash); +} + +ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) { + return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash); +} + +ScopedPK11Slot GetPrivateSlotForChromeOSUser( + const std::string& username_hash, + base::OnceCallback<void(ScopedPK11Slot)> callback) { + return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser( + username_hash, std::move(callback)); +} + +void CloseChromeOSUserForTesting(const std::string& username_hash) { + g_nss_singleton.Get().CloseChromeOSUserForTesting(username_hash); +} + +void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) { + g_nss_singleton.Get().SetPrivateSoftwareSlotForChromeOSUserForTesting( + std::move(slot)); +} +#endif // defined(OS_CHROMEOS) + +base::Time PRTimeToBaseTime(PRTime prtime) { + return base::Time::FromInternalValue( + prtime + base::Time::UnixEpoch().ToInternalValue()); +} + +PRTime BaseTimeToPRTime(base::Time time) { + return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); +} + +#if !defined(OS_CHROMEOS) +PK11SlotInfo* GetPersistentNSSKeySlot() { + return g_nss_singleton.Get().GetPersistentNSSKeySlot(); +} +#endif + +} // namespace crypto
diff --git a/src/crypto/nss_util.h b/src/crypto/nss_util.h index 7b50781..aa918a6 100644 --- a/src/crypto/nss_util.h +++ b/src/crypto/nss_util.h
@@ -6,15 +6,13 @@ #define CRYPTO_NSS_UTIL_H_ #include <string> -#include "base/basictypes.h" +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/macros.h" #include "crypto/crypto_export.h" - -#if defined(USE_NSS) -class FilePath; -#endif // defined(USE_NSS) +#include "starboard/types.h" namespace base { -class Lock; class Time; } // namespace base @@ -23,160 +21,55 @@ // initialization functions. namespace crypto { -class SymmetricKey; - -#if defined(USE_NSS) -// EarlySetupForNSSInit performs lightweight setup which must occur before the -// process goes multithreaded. This does not initialise NSS. For test, see -// EnsureNSSInit. -CRYPTO_EXPORT void EarlySetupForNSSInit(); -#endif - // Initialize NRPR if it isn't already initialized. This function is // thread-safe, and NSPR will only ever be initialized once. CRYPTO_EXPORT void EnsureNSPRInit(); -// Initialize NSS safely for strict sandboxing. This function tells NSS to not -// load user security modules, and makes sure NSS will have proper entropy in a -// restricted, sandboxed environment. -// -// As a defense in depth measure, this function should be called in a sandboxed -// environment. That way, in the event of a bug, NSS will still not be able to -// load security modules that could expose private data and keys. -// -// Make sure to get an LGTM from the Chrome Security Team if you use this. -CRYPTO_EXPORT void InitNSSSafely(); - // Initialize NSS if it isn't already initialized. This must be called before // any other NSS functions. This function is thread-safe, and NSS will only // ever be initialized once. CRYPTO_EXPORT void EnsureNSSInit(); -// Call this before calling EnsureNSSInit() will force NSS to initialize -// without a persistent DB. This is used for the special case where access of -// persistent DB is prohibited. -// -// TODO(hclam): Isolate loading default root certs. -// -// NSS will be initialized without loading any user security modules, including -// the built-in root certificates module. User security modules need to be -// loaded manually after NSS initialization. -// -// If EnsureNSSInit() is called before then this function has no effect. -// -// Calling this method only has effect on Linux. -// -// WARNING: Use this with caution. -CRYPTO_EXPORT void ForceNSSNoDBInit(); - -// This method is used to disable checks in NSS when used in a forked process. -// NSS checks whether it is running a forked process to avoid problems when -// using user security modules in a forked process. However if we are sure -// there are no modules loaded before the process is forked then there is no -// harm disabling the check. -// -// This method must be called before EnsureNSSInit() to take effect. -// -// WARNING: Use this with caution. -CRYPTO_EXPORT void DisableNSSForkCheck(); - -// Load NSS library files. This function has no effect on Mac and Windows. -// This loads the necessary NSS library files so that NSS can be initialized -// after loading additional library files is disallowed, for example when the -// sandbox is active. -// -// Note that this does not load libnssckbi.so which contains the root -// certificates. -CRYPTO_EXPORT void LoadNSSLibraries(); - // Check if the current NSS version is greater than or equals to |version|. // A sample version string is "3.12.3". bool CheckNSSVersion(const char* version); #if defined(OS_CHROMEOS) -// Open the r/w nssdb that's stored inside the user's encrypted home -// directory. This is the default slot returned by -// GetPublicNSSKeySlot(). -CRYPTO_EXPORT void OpenPersistentNSSDB(); - -// Indicates that NSS should load the Chaps library so that we -// can access the TPM through NSS. Once this is called, -// GetPrivateNSSKeySlot() will return the TPM slot if one was found. +// Indicates that NSS should use the Chaps library so that we +// can access the TPM through NSS. InitializeTPMTokenAndSystemSlot and +// InitializeTPMForChromeOSUser must still be called to load the slots. CRYPTO_EXPORT void EnableTPMTokenForNSS(); -// Get name and user PIN for the built-in TPM token on ChromeOS. -// Either one can safely be NULL. Should only be called after -// EnableTPMTokenForNSS has been called with a non-null delegate. -CRYPTO_EXPORT void GetTPMTokenInfo(std::string* token_name, - std::string* user_pin); +// Returns true if EnableTPMTokenForNSS has been called. +CRYPTO_EXPORT bool IsTPMTokenEnabledForNSS(); // Returns true if the TPM is owned and PKCS#11 initialized with the // user and security officer PINs, and has been enabled in NSS by // calling EnableTPMForNSS, and Chaps has been successfully // loaded into NSS. -CRYPTO_EXPORT bool IsTPMTokenReady(); +// If |callback| is non-null and the function returns false, the |callback| will +// be run once the TPM is ready. |callback| will never be run if the function +// returns true. +CRYPTO_EXPORT bool IsTPMTokenReady(base::OnceClosure callback) + WARN_UNUSED_RESULT; -// Initialize the TPM token. Does nothing if it is already initialized. -CRYPTO_EXPORT bool InitializeTPMToken(const std::string& token_name, - const std::string& user_pin); - -// Gets supplemental user key. Creates one in NSS database if it does not exist. -// The supplemental user key is used for AES encryption of user data that is -// stored and protected by cryptohome. This additional layer of encryption of -// provided to ensure that sensitive data wouldn't be exposed in plain text in -// case when an attacker would somehow gain access to all content within -// cryptohome. -CRYPTO_EXPORT SymmetricKey* GetSupplementalUserKey(); +// Initialize the TPM token and system slot. The |callback| will run on the same +// thread with true if the token and slot were successfully loaded or were +// already initialized. |callback| will be passed false if loading failed. Once +// called, InitializeTPMTokenAndSystemSlot must not be called again until the +// |callback| has been run. +CRYPTO_EXPORT void InitializeTPMTokenAndSystemSlot( + int system_slot_id, + base::OnceCallback<void(bool)> callback); #endif // Convert a NSS PRTime value into a base::Time object. -// We use a int64 instead of PRTime here to avoid depending on NSPR headers. -CRYPTO_EXPORT base::Time PRTimeToBaseTime(int64 prtime); +// We use a int64_t instead of PRTime here to avoid depending on NSPR headers. +CRYPTO_EXPORT base::Time PRTimeToBaseTime(int64_t prtime); // Convert a base::Time object into a PRTime value. -// We use a int64 instead of PRTime here to avoid depending on NSPR headers. -CRYPTO_EXPORT int64 BaseTimeToPRTime(base::Time time); - -#if defined(USE_NSS) -// Exposed for unittests only. -// TODO(mattm): When NSS 3.14 is the minimum version required, -// switch back to using a separate user DB for each test. -// Because of https://bugzilla.mozilla.org/show_bug.cgi?id=588269 , the -// opened user DB is not automatically closed. -class CRYPTO_EXPORT_PRIVATE ScopedTestNSSDB { - public: - ScopedTestNSSDB(); - ~ScopedTestNSSDB(); - - bool is_open() { return is_open_; } - - private: - bool is_open_; - DISALLOW_COPY_AND_ASSIGN(ScopedTestNSSDB); -}; - -// NSS has a bug which can cause a deadlock or stall in some cases when writing -// to the certDB and keyDB. It also has a bug which causes concurrent key pair -// generations to scribble over each other. To work around this, we synchronize -// writes to the NSS databases with a global lock. The lock is hidden beneath a -// function for easy disabling when the bug is fixed. Callers should allow for -// it to return NULL in the future. -// -// See https://bugzilla.mozilla.org/show_bug.cgi?id=564011 -base::Lock* GetNSSWriteLock(); - -// A helper class that acquires the NSS write Lock while the AutoNSSWriteLock -// is in scope. -class CRYPTO_EXPORT AutoNSSWriteLock { - public: - AutoNSSWriteLock(); - ~AutoNSSWriteLock(); - private: - base::Lock *lock_; - DISALLOW_COPY_AND_ASSIGN(AutoNSSWriteLock); -}; - -#endif // defined(USE_NSS) +// We use a int64_t instead of PRTime here to avoid depending on NSPR headers. +CRYPTO_EXPORT int64_t BaseTimeToPRTime(base::Time time); } // namespace crypto
diff --git a/src/crypto/nss_util_internal.h b/src/crypto/nss_util_internal.h new file mode 100644 index 0000000..fdc0035 --- /dev/null +++ b/src/crypto/nss_util_internal.h
@@ -0,0 +1,127 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_NSS_UTIL_INTERNAL_H_ +#define CRYPTO_NSS_UTIL_INTERNAL_H_ + +#include <secmodt.h> + +#include <string> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "crypto/crypto_export.h" +#include "crypto/scoped_nss_types.h" +#include "starboard/types.h" + +namespace base { +class FilePath; +} + +// These functions return a type defined in an NSS header, and so cannot be +// declared in nss_util.h. Hence, they are declared here. + +namespace crypto { + +// Opens an NSS software database in folder |path|, with the (potentially) +// user-visible description |description|. Returns the slot for the opened +// database, or nullptr if the database could not be opened. +CRYPTO_EXPORT ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path, + const std::string& description); + +#if !defined(OS_CHROMEOS) +// Returns a reference to the default NSS key slot for storing persistent data. +// Caller must release returned reference with PK11_FreeSlot. +CRYPTO_EXPORT PK11SlotInfo* GetPersistentNSSKeySlot() WARN_UNUSED_RESULT; +#endif + +// A helper class that acquires the SECMOD list read lock while the +// AutoSECMODListReadLock is in scope. +class CRYPTO_EXPORT AutoSECMODListReadLock { + public: + AutoSECMODListReadLock(); + ~AutoSECMODListReadLock(); + + private: + SECMODListLock* lock_; + DISALLOW_COPY_AND_ASSIGN(AutoSECMODListReadLock); +}; + +#if defined(OS_CHROMEOS) +// Returns a reference to the system-wide TPM slot if it is loaded. If it is not +// loaded and |callback| is non-null, the |callback| will be run once the slot +// is loaded. +CRYPTO_EXPORT ScopedPK11Slot GetSystemNSSKeySlot( + base::OnceCallback<void(ScopedPK11Slot)> callback) WARN_UNUSED_RESULT; + +// Sets the test system slot to |slot|, which means that |slot| will be exposed +// through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will return true. +// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization, +// does not have to be called if the test system slot is set. +// This must must not be called consecutively with a |slot| != nullptr. If +// |slot| is nullptr, the test system slot is unset. +CRYPTO_EXPORT void SetSystemKeySlotForTesting(ScopedPK11Slot slot); + +// Prepare per-user NSS slot mapping. It is safe to call this function multiple +// times. Returns true if the user was added, or false if it already existed. +CRYPTO_EXPORT bool InitializeNSSForChromeOSUser( + const std::string& username_hash, + const base::FilePath& path); + +// Returns whether TPM for ChromeOS user still needs initialization. If +// true is returned, the caller can proceed to initialize TPM slot for the +// user, but should call |WillInitializeTPMForChromeOSUser| first. +// |InitializeNSSForChromeOSUser| must have been called first. +CRYPTO_EXPORT bool ShouldInitializeTPMForChromeOSUser( + const std::string& username_hash) WARN_UNUSED_RESULT; + +// Makes |ShouldInitializeTPMForChromeOSUser| start returning false. +// Should be called before starting TPM initialization for the user. +// Assumes |InitializeNSSForChromeOSUser| had already been called. +CRYPTO_EXPORT void WillInitializeTPMForChromeOSUser( + const std::string& username_hash); + +// Use TPM slot |slot_id| for user. InitializeNSSForChromeOSUser must have been +// called first. +CRYPTO_EXPORT void InitializeTPMForChromeOSUser( + const std::string& username_hash, + CK_SLOT_ID slot_id); + +// Use the software slot as the private slot for user. +// InitializeNSSForChromeOSUser must have been called first. +CRYPTO_EXPORT void InitializePrivateSoftwareSlotForChromeOSUser( + const std::string& username_hash); + +// Returns a reference to the public slot for user. +CRYPTO_EXPORT ScopedPK11Slot GetPublicSlotForChromeOSUser( + const std::string& username_hash) WARN_UNUSED_RESULT; + +// Returns the private slot for |username_hash| if it is loaded. If it is not +// loaded and |callback| is non-null, the |callback| will be run once the slot +// is loaded. +CRYPTO_EXPORT ScopedPK11Slot GetPrivateSlotForChromeOSUser( + const std::string& username_hash, + base::OnceCallback<void(ScopedPK11Slot)> callback) WARN_UNUSED_RESULT; + +// Closes the NSS DB for |username_hash| that was previously opened by the +// *Initialize*ForChromeOSUser functions. +CRYPTO_EXPORT void CloseChromeOSUserForTesting( + const std::string& username_hash); + +// Sets the slot which should be used as private slot for the next +// |InitializePrivateSoftwareSlotForChromeOSUser| called. This is intended for +// simulating a separate private slot in Chrome OS browser tests. +// As a sanity check, it is recommended to check that the private slot of the +// profile's certificate database is set to |slot| when the profile is +// available, because |slot| will be used as private slot for whichever profile +// is initialized next. +CRYPTO_EXPORT void SetPrivateSoftwareSlotForChromeOSUserForTesting( + ScopedPK11Slot slot); + +#endif // defined(OS_CHROMEOS) + +} // namespace crypto + +#endif // CRYPTO_NSS_UTIL_INTERNAL_H_
diff --git a/src/crypto/nss_util_unittest.cc b/src/crypto/nss_util_unittest.cc new file mode 100644 index 0000000..1f4efb3 --- /dev/null +++ b/src/crypto/nss_util_unittest.cc
@@ -0,0 +1,45 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/nss_util.h" + +#include <prtime.h> + +#include "base/time/time.h" +#include "starboard/types.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace crypto { + +TEST(NSSUtilTest, PRTimeConversion) { + EXPECT_EQ(base::Time::UnixEpoch(), PRTimeToBaseTime(0)); + EXPECT_EQ(0, BaseTimeToPRTime(base::Time::UnixEpoch())); + + PRExplodedTime prxtime; + prxtime.tm_params.tp_gmt_offset = 0; + prxtime.tm_params.tp_dst_offset = 0; + base::Time::Exploded exploded; + exploded.year = prxtime.tm_year = 2011; + exploded.month = 12; + prxtime.tm_month = 11; + // PRExplodedTime::tm_wday is a smaller type than Exploded::day_of_week, so + // assigning the two in this order instead of the reverse avoids potential + // warnings about type downcasting. + exploded.day_of_week = prxtime.tm_wday = 0; // Should be unused. + exploded.day_of_month = prxtime.tm_mday = 10; + exploded.hour = prxtime.tm_hour = 2; + exploded.minute = prxtime.tm_min = 52; + exploded.second = prxtime.tm_sec = 19; + exploded.millisecond = 342; + prxtime.tm_usec = 342000; + + PRTime pr_time = PR_ImplodeTime(&prxtime); + base::Time base_time; + EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &base_time)); + + EXPECT_EQ(base_time, PRTimeToBaseTime(pr_time)); + EXPECT_EQ(pr_time, BaseTimeToPRTime(base_time)); +} + +} // namespace crypto
diff --git a/src/crypto/openssl_util.cc b/src/crypto/openssl_util.cc index bdf24e6..295da2f 100644 --- a/src/crypto/openssl_util.cc +++ b/src/crypto/openssl_util.cc
@@ -4,77 +4,18 @@ #include "crypto/openssl_util.h" -#include <openssl/err.h> -#include <openssl/ssl.h> +#include <string> #include "base/logging.h" -#include "base/memory/scoped_vector.h" -#include "base/memory/singleton.h" -#include "base/string_piece.h" -#include "base/synchronization/lock.h" +#include "base/strings/string_piece.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/crypto.h" +#include "third_party/boringssl/src/include/openssl/err.h" namespace crypto { namespace { -unsigned long CurrentThreadId() { - return static_cast<unsigned long>(base::PlatformThread::CurrentId()); -} - -// Singleton for initializing and cleaning up the OpenSSL library. -class OpenSSLInitSingleton { - public: - static OpenSSLInitSingleton* GetInstance() { - // We allow the SSL environment to leak for multiple reasons: - // - it is used from a non-joinable worker thread that is not stopped on - // shutdown, hence may still be using OpenSSL library after the AtExit - // runner has completed. - // - There are other OpenSSL related singletons (e.g. the client socket - // context) who's cleanup depends on the global environment here, but - // we can't control the order the AtExit handlers will run in so - // allowing the global environment to leak at least ensures it is - // available for those other singletons to reliably cleanup. - return Singleton<OpenSSLInitSingleton, - LeakySingletonTraits<OpenSSLInitSingleton> >::get(); - } - private: - friend struct DefaultSingletonTraits<OpenSSLInitSingleton>; - OpenSSLInitSingleton() { - SSL_load_error_strings(); - SSL_library_init(); - OpenSSL_add_all_algorithms(); - int num_locks = CRYPTO_num_locks(); - locks_.reserve(num_locks); - for (int i = 0; i < num_locks; ++i) - locks_.push_back(new base::Lock()); - CRYPTO_set_locking_callback(LockingCallback); - CRYPTO_set_id_callback(CurrentThreadId); - } - - ~OpenSSLInitSingleton() { - CRYPTO_set_locking_callback(NULL); - EVP_cleanup(); - ERR_free_strings(); - } - - static void LockingCallback(int mode, int n, const char* file, int line) { - OpenSSLInitSingleton::GetInstance()->OnLockingCallback(mode, n, file, line); - } - - void OnLockingCallback(int mode, int n, const char* file, int line) { - CHECK_LT(static_cast<size_t>(n), locks_.size()); - if (mode & CRYPTO_LOCK) - locks_[n]->Acquire(); - else - locks_[n]->Release(); - } - - // These locks are used and managed by OpenSSL via LockingCallback(). - ScopedVector<base::Lock> locks_; - - DISALLOW_COPY_AND_ASSIGN(OpenSSLInitSingleton); -}; - // Callback routine for OpenSSL to print error messages. |str| is a // NULL-terminated string of length |len| containing diagnostic information // such as the library, function and reason for the error, the file and line @@ -92,18 +33,17 @@ } // namespace void EnsureOpenSSLInit() { - (void)OpenSSLInitSingleton::GetInstance(); + // CRYPTO_library_init may be safely called concurrently. + CRYPTO_library_init(); } -void ClearOpenSSLERRStack(const tracked_objects::Location& location) { - if (logging::DEBUG_MODE && VLOG_IS_ON(1)) { - int error_num = ERR_peek_error(); +void ClearOpenSSLERRStack(const base::Location& location) { + if (DCHECK_IS_ON() && VLOG_IS_ON(1)) { + uint32_t error_num = ERR_peek_error(); if (error_num == 0) return; - std::string message; - location.Write(true, true, &message); - DVLOG(1) << "OpenSSL ERR_get_error stack from " << message; + DVLOG(1) << "OpenSSL ERR_get_error stack from " << location.ToString(); ERR_print_errors_cb(&OpenSSLErrorCallback, NULL); } else { ERR_clear_error();
diff --git a/src/crypto/openssl_util.h b/src/crypto/openssl_util.h index b390fe7..b546503 100644 --- a/src/crypto/openssl_util.h +++ b/src/crypto/openssl_util.h
@@ -5,40 +5,17 @@ #ifndef CRYPTO_OPENSSL_UTIL_H_ #define CRYPTO_OPENSSL_UTIL_H_ -#include "base/basictypes.h" #include "base/location.h" +#include "base/macros.h" #include "crypto/crypto_export.h" +#include "starboard/memory.h" +#include "starboard/types.h" namespace crypto { -// A helper class that takes care of destroying OpenSSL objects when it goes out -// of scope. -template <typename T, void (*destructor)(T*)> -class ScopedOpenSSL { - public: - ScopedOpenSSL() : ptr_(NULL) { } - explicit ScopedOpenSSL(T* ptr) : ptr_(ptr) { } - ~ScopedOpenSSL() { - reset(NULL); - } - - T* get() const { return ptr_; } - void reset(T* ptr) { - if (ptr != ptr_) { - if (ptr_) (*destructor)(ptr_); - ptr_ = ptr; - } - } - - private: - T* ptr_; - - DISALLOW_COPY_AND_ASSIGN(ScopedOpenSSL); -}; - // Provides a buffer of at least MIN_SIZE bytes, for use when calling OpenSSL's // SHA256, HMAC, etc functions, adapting the buffer sizing rules to meet those -// of the our base wrapper APIs. +// of our base wrapper APIs. // This allows the library to write directly to the caller's buffer if it is of // sufficient size, but if not it will write to temporary |min_sized_buffer_| // of required size and then its content is automatically copied out on @@ -54,7 +31,7 @@ ~ScopedOpenSSLSafeSizeBuffer() { if (output_len_ < MIN_SIZE) { // Copy the temporary buffer out, truncating as needed. - memcpy(output_, min_sized_buffer_, output_len_); + SbMemoryCopy(output_, min_sized_buffer_, output_len_); } // else... any writing already happened directly into |output_|. } @@ -77,16 +54,16 @@ }; // Initialize OpenSSL if it isn't already initialized. This must be called -// before any other OpenSSL functions. +// before any other OpenSSL functions though it is safe and cheap to call this +// multiple times. // This function is thread-safe, and OpenSSL will only ever be initialized once. // OpenSSL will be properly shut down on program exit. -void CRYPTO_EXPORT EnsureOpenSSLInit(); +CRYPTO_EXPORT void EnsureOpenSSLInit(); // Drains the OpenSSL ERR_get_error stack. On a debug build the error codes // are send to VLOG(1), on a release build they are disregarded. In most // cases you should pass FROM_HERE as the |location|. -void CRYPTO_EXPORT ClearOpenSSLERRStack( - const tracked_objects::Location& location); +CRYPTO_EXPORT void ClearOpenSSLERRStack(const base::Location& location); // Place an instance of this class on the call stack to automatically clear // the OpenSSL error stack on function exit. @@ -95,7 +72,7 @@ // Pass FROM_HERE as |location|, to help track the source of OpenSSL error // messages. Note any diagnostic emitted will be tagged with the location of // the constructor call as it's not possible to trace a destructor's callsite. - explicit OpenSSLErrStackTracer(const tracked_objects::Location& location) + explicit OpenSSLErrStackTracer(const base::Location& location) : location_(location) { EnsureOpenSSLInit(); } @@ -104,7 +81,7 @@ } private: - const tracked_objects::Location location_; + const base::Location location_; DISALLOW_IMPLICIT_CONSTRUCTORS(OpenSSLErrStackTracer); };
diff --git a/src/crypto/p224.cc b/src/crypto/p224.cc index f9ee385..52e59ce 100644 --- a/src/crypto/p224.cc +++ b/src/crypto/p224.cc
@@ -12,6 +12,8 @@ #include <string.h> #include "base/sys_byteorder.h" +#include "starboard/memory.h" +#include "starboard/types.h" namespace { @@ -20,11 +22,11 @@ // Field element functions. // -// The field that we're dealing with is Z/pZ where p = 2**224 - 2**96 + 1. +// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1. // // Field elements are represented by a FieldElement, which is a typedef to an -// array of 8 uint32's. The value of a FieldElement, a, is: -// a[0] + 2**28*a[1] + 2**56*a[2] + ... + 2**196*a[7] +// array of 8 uint32_t's. The value of a FieldElement, a, is: +// a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7] // // Using 28-bit limbs means that there's only 4 bits of headroom, which is less // than we would really like. But it has the useful feature that we hit 2**224 @@ -41,12 +43,12 @@ void Contract(FieldElement* inout); // IsZero returns 0xffffffff if a == 0 mod p and 0 otherwise. -uint32 IsZero(const FieldElement& a) { +uint32_t IsZero(const FieldElement& a) { FieldElement minimal; - memcpy(&minimal, &a, sizeof(minimal)); + SbMemoryCopy(&minimal, &a, sizeof(minimal)); Contract(&minimal); - uint32 is_zero = 0, is_p = 0; + uint32_t is_zero = 0, is_p = 0; for (unsigned i = 0; i < 8; i++) { is_zero |= minimal[i]; is_p |= minimal[i] - kP[i]; @@ -68,7 +70,7 @@ // For is_zero and is_p, the LSB is 0 iff all the bits are zero. is_zero &= is_p & 1; is_zero = (~is_zero) << 31; - is_zero = static_cast<int32>(is_zero) >> 31; + is_zero = static_cast<int32_t>(is_zero) >> 31; return is_zero; } @@ -81,9 +83,9 @@ } } -static const uint32 kTwo31p3 = (1u<<31) + (1u<<3); -static const uint32 kTwo31m3 = (1u<<31) - (1u<<3); -static const uint32 kTwo31m15m3 = (1u<<31) - (1u<<15) - (1u<<3); +static const uint32_t kTwo31p3 = (1u << 31) + (1u << 3); +static const uint32_t kTwo31m3 = (1u << 31) - (1u << 3); +static const uint32_t kTwo31m15m3 = (1u << 31) - (1u << 15) - (1u << 3); // kZero31ModP is 0 mod p where bit 31 is set in all limbs so that we can // subtract smaller amounts without underflow. See the section "Subtraction" in // [1] for why. @@ -103,22 +105,22 @@ } } -static const uint64 kTwo63p35 = (1ull<<63) + (1ull<<35); -static const uint64 kTwo63m35 = (1ull<<63) - (1ull<<35); -static const uint64 kTwo63m35m19 = (1ull<<63) - (1ull<<35) - (1ull<<19); +static const uint64_t kTwo63p35 = (1ull << 63) + (1ull << 35); +static const uint64_t kTwo63m35 = (1ull << 63) - (1ull << 35); +static const uint64_t kTwo63m35m19 = (1ull << 63) - (1ull << 35) - (1ull << 19); // kZero63ModP is 0 mod p where bit 63 is set in all limbs. See the section // "Subtraction" in [1] for why. -static const uint64 kZero63ModP[8] = { - kTwo63p35, kTwo63m35, kTwo63m35, kTwo63m35, - kTwo63m35m19, kTwo63m35, kTwo63m35, kTwo63m35, +static const uint64_t kZero63ModP[8] = { + kTwo63p35, kTwo63m35, kTwo63m35, kTwo63m35, + kTwo63m35m19, kTwo63m35, kTwo63m35, kTwo63m35, }; -static const uint32 kBottom28Bits = 0xfffffff; +static const uint32_t kBottom28Bits = 0xfffffff; // LargeFieldElement also represents an element of the field. The limbs are // still spaced 28-bits apart and in little-endian order. So the limbs are at // 0, 28, 56, ..., 392 bits, each 64-bits wide. -typedef uint64 LargeFieldElement[15]; +typedef uint64_t LargeFieldElement[15]; // ReduceLarge converts a LargeFieldElement to a FieldElement. // @@ -144,21 +146,21 @@ // 32-bit operations. for (int i = 1; i < 8; i++) { in[i+1] += in[i] >> 28; - (*out)[i] = static_cast<uint32>(in[i] & kBottom28Bits); + (*out)[i] = static_cast<uint32_t>(in[i] & kBottom28Bits); } // Eliminate the term at 2*224 that we introduced while keeping the same // value mod p. in[0] -= in[8]; // reflection off the "+1" term of p. - (*out)[3] += static_cast<uint32>(in[8] & 0xffff) << 12; // "-2**96" term - (*out)[4] += static_cast<uint32>(in[8] >> 16); // rest of "-2**96" term + (*out)[3] += static_cast<uint32_t>(in[8] & 0xffff) << 12; // "-2**96" term + (*out)[4] += static_cast<uint32_t>(in[8] >> 16); // rest of "-2**96" term // in[0] < 2**64 // out[3] < 2**29 // out[4] < 2**29 // out[1,2,5..7] < 2**28 - (*out)[0] = static_cast<uint32>(in[0] & kBottom28Bits); - (*out)[1] += static_cast<uint32>((in[0] >> 28) & kBottom28Bits); - (*out)[2] += static_cast<uint32>(in[0] >> 56); + (*out)[0] = static_cast<uint32_t>(in[0] & kBottom28Bits); + (*out)[1] += static_cast<uint32_t>((in[0] >> 28) & kBottom28Bits); + (*out)[2] += static_cast<uint32_t>(in[0] >> 56); // out[0] < 2**28 // out[1..4] < 2**29 // out[5..7] < 2**28 @@ -170,11 +172,11 @@ // out[i] < 2**29 void Mul(FieldElement* out, const FieldElement& a, const FieldElement& b) { LargeFieldElement tmp; - memset(&tmp, 0, sizeof(tmp)); + SbMemorySet(&tmp, 0, sizeof(tmp)); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { - tmp[i+j] += static_cast<uint64>(a[i]) * static_cast<uint64>(b[j]); + tmp[i + j] += static_cast<uint64_t>(a[i]) * static_cast<uint64_t>(b[j]); } } @@ -187,11 +189,11 @@ // out[i] < 2**29 void Square(FieldElement* out, const FieldElement& a) { LargeFieldElement tmp; - memset(&tmp, 0, sizeof(tmp)); + SbMemorySet(&tmp, 0, sizeof(tmp)); for (int i = 0; i < 8; i++) { for (int j = 0; j <= i; j++) { - uint64 r = static_cast<uint64>(a[i]) * static_cast<uint64>(a[j]); + uint64_t r = static_cast<uint64_t>(a[i]) * static_cast<uint64_t>(a[j]); if (i == j) { tmp[i+j] += r; } else { @@ -214,16 +216,16 @@ a[i+1] += a[i] >> 28; a[i] &= kBottom28Bits; } - uint32 top = a[7] >> 28; + uint32_t top = a[7] >> 28; a[7] &= kBottom28Bits; // top < 2**4 // Constant-time: mask = (top != 0) ? 0xffffffff : 0 - uint32 mask = top; + uint32_t mask = top; mask |= mask >> 2; mask |= mask >> 1; mask <<= 31; - mask = static_cast<uint32>(static_cast<int32>(mask) >> 31); + mask = static_cast<uint32_t>(static_cast<int32_t>(mask) >> 31); // Eliminate top while maintaining the same value mod p. a[0] -= top; @@ -300,7 +302,7 @@ out[i+1] += out[i] >> 28; out[i] &= kBottom28Bits; } - uint32 top = out[7] >> 28; + uint32_t top = out[7] >> 28; out[7] &= kBottom28Bits; // Eliminate top while maintaining the same value mod p. @@ -311,7 +313,7 @@ // out[0] negative then we know that out[3] is sufficiently positive // because we just added to it. for (int i = 0; i < 3; i++) { - uint32 mask = static_cast<uint32>(static_cast<int32>(out[i]) >> 31); + uint32_t mask = static_cast<uint32_t>(static_cast<int32_t>(out[i]) >> 31); out[i] += (1 << 28) & mask; out[i+1] -= 1 & mask; } @@ -344,7 +346,7 @@ // As before, if we made out[0] negative then we know that out[3] is // sufficiently positive. for (int i = 0; i < 3; i++) { - uint32 mask = static_cast<uint32>(static_cast<int32>(out[i]) >> 31); + uint32_t mask = static_cast<uint32_t>(static_cast<int32_t>(out[i]) >> 31); out[i] += (1 << 28) & mask; out[i+1] -= 1 & mask; } @@ -356,7 +358,7 @@ // equal to bottom28Bits if the whole value is >= p. If top_4_all_ones // ends up with any zero bits in the bottom 28 bits, then this wasn't // true. - uint32 top_4_all_ones = 0xffffffffu; + uint32_t top_4_all_ones = 0xffffffffu; for (int i = 4; i < 8; i++) { top_4_all_ones &= out[i]; } @@ -368,37 +370,39 @@ top_4_all_ones &= top_4_all_ones >> 2; top_4_all_ones &= top_4_all_ones >> 1; top_4_all_ones = - static_cast<uint32>(static_cast<int32>(top_4_all_ones << 31) >> 31); + static_cast<uint32_t>(static_cast<int32_t>(top_4_all_ones << 31) >> 31); // Now we test whether the bottom three limbs are non-zero. - uint32 bottom_3_non_zero = out[0] | out[1] | out[2]; + uint32_t bottom_3_non_zero = out[0] | out[1] | out[2]; bottom_3_non_zero |= bottom_3_non_zero >> 16; bottom_3_non_zero |= bottom_3_non_zero >> 8; bottom_3_non_zero |= bottom_3_non_zero >> 4; bottom_3_non_zero |= bottom_3_non_zero >> 2; bottom_3_non_zero |= bottom_3_non_zero >> 1; bottom_3_non_zero = - static_cast<uint32>(static_cast<int32>(bottom_3_non_zero) >> 31); + static_cast<uint32_t>(static_cast<int32_t>(bottom_3_non_zero) >> 31); // Everything depends on the value of out[3]. // If it's > 0xffff000 and top_4_all_ones != 0 then the whole value is >= p // If it's = 0xffff000 and top_4_all_ones != 0 and bottom_3_non_zero != 0, // then the whole value is >= p // If it's < 0xffff000, then the whole value is < p - uint32 n = out[3] - 0xffff000; - uint32 out_3_equal = n; + uint32_t n = out[3] - 0xffff000; + uint32_t out_3_equal = n; out_3_equal |= out_3_equal >> 16; out_3_equal |= out_3_equal >> 8; out_3_equal |= out_3_equal >> 4; out_3_equal |= out_3_equal >> 2; out_3_equal |= out_3_equal >> 1; out_3_equal = - ~static_cast<uint32>(static_cast<int32>(out_3_equal << 31) >> 31); + ~static_cast<uint32_t>(static_cast<int32_t>(out_3_equal << 31) >> 31); // If out[3] > 0xffff000 then n's MSB will be zero. - uint32 out_3_gt = ~static_cast<uint32>(static_cast<int32>(n << 31) >> 31); + uint32_t out_3_gt = + ~static_cast<uint32_t>(static_cast<int32_t>(n << 31) >> 31); - uint32 mask = top_4_all_ones & ((out_3_equal & bottom_3_non_zero) | out_3_gt); + uint32_t mask = + top_4_all_ones & ((out_3_equal & bottom_3_non_zero) | out_3_gt); out[0] -= 1 & mask; out[3] -= 0xffff000 & mask; out[4] -= 0xfffffff & mask; @@ -421,7 +425,7 @@ 39211076, 180311059, 84673715, 188764328, }; -void CopyConditional(Point* out, const Point& a, uint32 mask); +void CopyConditional(Point* out, const Point& a, uint32_t mask); void DoubleJacobian(Point* out, const Point& a); // AddJacobian computes *out = a+b where a != b. @@ -431,13 +435,13 @@ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl FieldElement z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v; - uint32 z1_is_zero = IsZero(a.z); - uint32 z2_is_zero = IsZero(b.z); + uint32_t z1_is_zero = IsZero(a.z); + uint32_t z2_is_zero = IsZero(b.z); - // Z1Z1 = Z1**2 + // Z1Z1 = Z1² Square(&z1z1, a.z); - // Z2Z2 = Z2**2 + // Z2Z2 = Z2² Square(&z2z2, b.z); // U1 = X1*Z2Z2 @@ -457,11 +461,11 @@ // H = U2-U1 Subtract(&h, u2, u1); Reduce(&h); - uint32 x_equal = IsZero(h); + uint32_t x_equal = IsZero(h); - // I = (2*H)**2 - for (int j = 0; j < 8; j++) { - i[j] = h[j] << 1; + // I = (2*H)² + for (int k = 0; k < 8; k++) { + i[k] = h[k] << 1; } Reduce(&i); Square(&i, i); @@ -471,7 +475,7 @@ // r = 2*(S2-S1) Subtract(&r, s2, s1); Reduce(&r); - uint32 y_equal = IsZero(r); + uint32_t y_equal = IsZero(r); if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) { // The two input points are the same therefore we must use the dedicated @@ -480,15 +484,15 @@ return; } - for (int i = 0; i < 8; i++) { - r[i] <<= 1; + for (int k = 0; k < 8; k++) { + r[k] <<= 1; } Reduce(&r); // V = U1*I Mul(&v, u1, i); - // Z3 = ((Z1+Z2)**2-Z1Z1-Z2Z2)*H + // Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*H Add(&z1z1, z1z1, z2z2); Add(&z2z2, a.z, b.z); Reduce(&z2z2); @@ -497,9 +501,9 @@ Reduce(&out->z); Mul(&out->z, out->z, h); - // X3 = r**2-J-2*V - for (int i = 0; i < 8; i++) { - z1z1[i] = v[i] << 1; + // X3 = r²-J-2*V + for (int k = 0; k < 8; k++) { + z1z1[k] = v[k] << 1; } Add(&z1z1, j, z1z1); Reduce(&z1z1); @@ -508,8 +512,8 @@ Reduce(&out->x); // Y3 = r*(V-X3)-2*S1*J - for (int i = 0; i < 8; i++) { - s1[i] <<= 1; + for (int k = 0; k < 8; k++) { + s1[k] <<= 1; } Mul(&s1, s1, j); Subtract(&z1z1, v, out->x); @@ -541,7 +545,7 @@ Reduce(&alpha); Mul(&alpha, alpha, t); - // Z3 = (Y1+Z1)**2-gamma-delta + // Z3 = (Y1+Z1)²-gamma-delta Add(&out->z, a.y, a.z); Reduce(&out->z); Square(&out->z, out->z); @@ -550,7 +554,7 @@ Subtract(&out->z, out->z, delta); Reduce(&out->z); - // X3 = alpha**2-8*beta + // X3 = alpha²-8*beta for (int i = 0; i < 8; i++) { delta[i] = beta[i] << 3; } @@ -559,7 +563,7 @@ Subtract(&out->x, out->x, delta); Reduce(&out->x); - // Y3 = alpha*(4*beta-X3)-8*(gamma**2) + // Y3 = alpha*(4*beta-X3)-8*gamma² for (int i = 0; i < 8; i++) { beta[i] <<= 2; } @@ -578,9 +582,7 @@ // CopyConditional sets *out=a if mask is 0xffffffff. mask must be either 0 of // 0xffffffff. -void CopyConditional(Point* out, - const Point& a, - uint32 mask) { +void CopyConditional(Point* out, const Point& a, uint32_t mask) { for (int i = 0; i < 8; i++) { out->x[i] ^= mask & (a.x[i] ^ out->x[i]); out->y[i] ^= mask & (a.y[i] ^ out->y[i]); @@ -590,15 +592,17 @@ // ScalarMult calculates *out = a*scalar where scalar is a big-endian number of // length scalar_len and != 0. -void ScalarMult(Point* out, const Point& a, - const uint8* scalar, size_t scalar_len) { - memset(out, 0, sizeof(*out)); +void ScalarMult(Point* out, + const Point& a, + const uint8_t* scalar, + size_t scalar_len) { + SbMemorySet(out, 0, sizeof(*out)); Point tmp; for (size_t i = 0; i < scalar_len; i++) { for (unsigned int bit_num = 0; bit_num < 8; bit_num++) { DoubleJacobian(out, *out); - uint32 bit = static_cast<uint32>(static_cast<int32>( + uint32_t bit = static_cast<uint32_t>(static_cast<int32_t>( (((scalar[i] >> (7 - bit_num)) & 1) << 31) >> 31)); AddJacobian(&tmp, a, *out); CopyConditional(out, tmp, bit); @@ -608,7 +612,7 @@ // Get224Bits reads 7 words from in and scatters their contents in // little-endian form into 8 words at out, 28 bits per output word. -void Get224Bits(uint32* out, const uint32* in) { +void Get224Bits(uint32_t* out, const uint32_t* in) { out[0] = NetToHost32(in[6]) & kBottom28Bits; out[1] = ((NetToHost32(in[5]) << 4) | (NetToHost32(in[6]) >> 28)) & kBottom28Bits; @@ -628,7 +632,7 @@ // Put224Bits performs the inverse operation to Get224Bits: taking 28 bits from // each of 8 input words and writing them in big-endian order to 7 words at // out. -void Put224Bits(uint32* out, const uint32* in) { +void Put224Bits(uint32_t* out, const uint32_t* in) { out[6] = HostToNet32((in[0] >> 0) | (in[1] << 28)); out[5] = HostToNet32((in[1] >> 4) | (in[2] << 24)); out[4] = HostToNet32((in[2] >> 8) | (in[3] << 20)); @@ -638,22 +642,22 @@ out[0] = HostToNet32((in[6] >> 24) | (in[7] << 4)); } -} // anonymous namespace +} // anonymous namespace namespace crypto { namespace p224 { -bool Point::SetFromString(const base::StringPiece& in) { +bool Point::SetFromString(base::StringPiece in) { if (in.size() != 2*28) return false; - const uint32* inwords = reinterpret_cast<const uint32*>(in.data()); + const uint32_t* inwords = reinterpret_cast<const uint32_t*>(in.data()); Get224Bits(x, inwords); Get224Bits(y, inwords + 7); - memset(&z, 0, sizeof(z)); + SbMemorySet(&z, 0, sizeof(z)); z[0] = 1; - // Check that the point is on the curve, i.e. that y**2 = x**3 - 3x + b. + // Check that the point is on the curve, i.e. that y² = x³ - 3x + b. FieldElement lhs; Square(&lhs, y); Contract(&lhs); @@ -672,11 +676,11 @@ ::Add(&rhs, rhs, kB); Contract(&rhs); - return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; + return SbMemoryCompare(&lhs, &rhs, sizeof(lhs)) == 0; } std::string Point::ToString() const { - FieldElement zinv, zinv_sq, x, y; + FieldElement zinv, zinv_sq, xx, yy; // If this is the point at infinity we return a string of all zeros. if (IsZero(this->z)) { @@ -686,20 +690,20 @@ Invert(&zinv, this->z); Square(&zinv_sq, zinv); - Mul(&x, this->x, zinv_sq); + Mul(&xx, x, zinv_sq); Mul(&zinv_sq, zinv_sq, zinv); - Mul(&y, this->y, zinv_sq); + Mul(&yy, y, zinv_sq); - Contract(&x); - Contract(&y); + Contract(&xx); + Contract(&yy); - uint32 outwords[14]; - Put224Bits(outwords, x); - Put224Bits(outwords + 7, y); + uint32_t outwords[14]; + Put224Bits(outwords, xx); + Put224Bits(outwords + 7, yy); return std::string(reinterpret_cast<const char*>(outwords), sizeof(outwords)); } -void ScalarMult(const Point& in, const uint8* scalar, Point* out) { +void ScalarMult(const Point& in, const uint8_t* scalar, Point* out) { ::ScalarMult(out, in, scalar, 28); } @@ -712,7 +716,7 @@ {1, 0, 0, 0, 0, 0, 0, 0}, }; -void ScalarBaseMult(const uint8* scalar, Point* out) { +void ScalarBaseMult(const uint8_t* scalar, Point* out) { ::ScalarMult(out, kBasePoint, scalar, 28); } @@ -734,7 +738,7 @@ Subtract(&out->y, kP, y); Reduce(&out->y); - memset(&out->z, 0, sizeof(out->z)); + SbMemorySet(&out->z, 0, sizeof(out->z)); out->z[0] = 1; }
diff --git a/src/crypto/p224.h b/src/crypto/p224.h index 769d791..6c6948e 100644 --- a/src/crypto/p224.h +++ b/src/crypto/p224.h
@@ -7,9 +7,9 @@ #include <string> -#include "base/basictypes.h" -#include "base/string_piece.h" +#include "base/strings/string_piece.h" #include "crypto/crypto_export.h" +#include "starboard/types.h" namespace crypto { @@ -17,21 +17,21 @@ // in FIPS 186-3, section D.2.2. namespace p224 { -// An element of the field (Z/pZ) is represented with 8, 28-bit limbs in +// An element of the field (ℤ/pℤ) is represented with 8, 28-bit limbs in // little endian order. -typedef uint32 FieldElement[8]; +typedef uint32_t FieldElement[8]; struct CRYPTO_EXPORT Point { // SetFromString the value of the point from the 56 byte, external // representation. The external point representation is an (x, y) pair of a // point on the curve. Each field element is represented as a big-endian // number < p. - bool SetFromString(const base::StringPiece& in); + bool SetFromString(base::StringPiece in); // ToString returns an external representation of the Point. std::string ToString() const; - // An Point is represented in Jacobian form (x/(z**2), y/(z**3)). + // An Point is represented in Jacobian form (x/z², y/z³). FieldElement x, y, z; }; @@ -41,11 +41,13 @@ // ScalarMult computes *out = in*scalar where scalar is a 28-byte, big-endian // number. -void CRYPTO_EXPORT ScalarMult(const Point& in, const uint8* scalar, Point* out); +void CRYPTO_EXPORT ScalarMult(const Point& in, + const uint8_t* scalar, + Point* out); // ScalarBaseMult computes *out = g*scalar where g is the base point of the // curve and scalar is a 28-byte, big-endian number. -void CRYPTO_EXPORT ScalarBaseMult(const uint8* scalar, Point* out); +void CRYPTO_EXPORT ScalarBaseMult(const uint8_t* scalar, Point* out); // Add computes *out = a+b. void CRYPTO_EXPORT Add(const Point& a, const Point& b, Point* out);
diff --git a/src/crypto/p224_spake.cc b/src/crypto/p224_spake.cc index 31109a4..0515b3c 100644 --- a/src/crypto/p224_spake.cc +++ b/src/crypto/p224_spake.cc
@@ -5,19 +5,24 @@ // This code implements SPAKE2, a variant of EKE: // http://www.di.ens.fr/~pointche/pub.php?reference=AbPo04 -#include <crypto/p224_spake.h> +#include "crypto/p224_spake.h" -#include <base/logging.h> -#include <crypto/p224.h> -#include <crypto/random.h> -#include <crypto/secure_util.h> +#include <algorithm> + +#include "starboard/types.h" + +#include "starboard/memory.h" + +#include "base/logging.h" +#include "crypto/p224.h" +#include "crypto/random.h" +#include "crypto/secure_util.h" namespace { // The following two points (M and N in the protocol) are verifiable random // points on the curve and can be generated with the following code: -// #include <stdint.h> // #include <stdio.h> // #include <string.h> // @@ -25,6 +30,9 @@ // #include <openssl/obj_mac.h> // #include <openssl/sha.h> // +// // Silence a presubmit. +// #define PRINTF printf +// // static const char kSeed1[] = "P224 point generation seed (M)"; // static const char kSeed2[] = "P224 point generation seed (N)"; // @@ -50,7 +58,7 @@ // EC_POINT_get_affine_coordinates_GFp(p224, p, &x, &y, NULL); // char* x_str = BN_bn2hex(&x); // char* y_str = BN_bn2hex(&y); -// printf("Found after %u iterations:\n%s\n%s\n", i, x_str, y_str); +// PRINTF("Found after %u iterations:\n%s\n%s\n", i, x_str, y_str); // OPENSSL_free(x_str); // OPENSSL_free(y_str); // BN_free(&x); @@ -80,7 +88,7 @@ 33188520, 48266885, 177021753, 81038478}, {104523827, 245682244, 266509668, 236196369, 28372046, 145351378, 198520366, 113345994}, - {1, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, }; const crypto::p224::Point kN = { @@ -88,31 +96,34 @@ 5034302, 185981975, 171998428, 11653062}, {197567436, 51226044, 60372156, 175772188, 42075930, 8083165, 160827401, 65097570}, - {1, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, }; } // anonymous namespace namespace crypto { -P224EncryptedKeyExchange::P224EncryptedKeyExchange( - PeerType peer_type, const base::StringPiece& password) - : state_(kStateInitial), - is_server_(peer_type == kPeerTypeServer) { - memset(&x_, 0, sizeof(x_)); - memset(&expected_authenticator_, 0, sizeof(expected_authenticator_)); +P224EncryptedKeyExchange::P224EncryptedKeyExchange(PeerType peer_type, + base::StringPiece password) + : state_(kStateInitial), is_server_(peer_type == kPeerTypeServer) { + SbMemorySet(&x_, 0, sizeof(x_)); + SbMemorySet(&expected_authenticator_, 0, sizeof(expected_authenticator_)); // x_ is a random scalar. RandBytes(x_, sizeof(x_)); - // X = g**x_ - p224::Point X; - p224::ScalarBaseMult(x_, &X); - // Calculate |password| hash to get SPAKE password value. SHA256HashString(std::string(password.data(), password.length()), pw_, sizeof(pw_)); + Init(); +} + +void P224EncryptedKeyExchange::Init() { + // X = g**x_ + p224::Point X; + p224::ScalarBaseMult(x_, &X); + // The client masks the Diffie-Hellman value, X, by adding M**pw and the // server uses N**pw. p224::Point MNpw; @@ -125,7 +136,7 @@ next_message_ = Xstar.ToString(); } -const std::string& P224EncryptedKeyExchange::GetMessage() { +const std::string& P224EncryptedKeyExchange::GetNextMessage() { if (state_ == kStateInitial) { state_ = kStateRecvDH; return next_message_; @@ -134,14 +145,14 @@ return next_message_; } - LOG(FATAL) << "P224EncryptedKeyExchange::GetMessage called in" + LOG(FATAL) << "P224EncryptedKeyExchange::GetNextMessage called in" " bad state " << state_; next_message_ = ""; return next_message_; } P224EncryptedKeyExchange::Result P224EncryptedKeyExchange::ProcessMessage( - const base::StringPiece& message) { + base::StringPiece message) { if (state_ == kStateRecvHash) { // This is the final state of the protocol: we are reading the peer's // authentication hash and checking that it matches the one that we expect. @@ -197,18 +208,18 @@ // Now we calculate the hashes that each side will use to prove to the other // that they derived the correct value for K. - uint8 client_hash[kSHA256Length], server_hash[kSHA256Length]; + uint8_t client_hash[kSHA256Length], server_hash[kSHA256Length]; CalculateHash(kPeerTypeClient, client_masked_dh, server_masked_dh, key_, client_hash); CalculateHash(kPeerTypeServer, client_masked_dh, server_masked_dh, key_, server_hash); - const uint8* my_hash = is_server_ ? server_hash : client_hash; - const uint8* their_hash = is_server_ ? client_hash : server_hash; + const uint8_t* my_hash = is_server_ ? server_hash : client_hash; + const uint8_t* their_hash = is_server_ ? client_hash : server_hash; next_message_ = std::string(reinterpret_cast<const char*>(my_hash), kSHA256Length); - memcpy(expected_authenticator_, their_hash, kSHA256Length); + SbMemoryCopy(expected_authenticator_, their_hash, kSHA256Length); state_ = kStateSendHash; return kResultPending; } @@ -218,7 +229,7 @@ const std::string& client_masked_dh, const std::string& server_masked_dh, const std::string& k, - uint8* out_digest) { + uint8_t* out_digest) { std::string hash_contents; if (peer_type == kPeerTypeServer) { @@ -240,9 +251,23 @@ return error_; } -const std::string& P224EncryptedKeyExchange::GetKey() { +const std::string& P224EncryptedKeyExchange::GetKey() const { DCHECK_EQ(state_, kStateDone); + return GetUnverifiedKey(); +} + +const std::string& P224EncryptedKeyExchange::GetUnverifiedKey() const { + // Key is already final when state is kStateSendHash. Subsequent states are + // used only for verification of the key. Some users may combine verification + // with sending verifiable data instead of |expected_authenticator_|. + DCHECK_GE(state_, kStateSendHash); return key_; } +void P224EncryptedKeyExchange::SetXForTesting(const std::string& x) { + SbMemorySet(&x_, 0, sizeof(x_)); + SbMemoryCopy(&x_, x.data(), std::min(x.size(), sizeof(x_))); + Init(); +} + } // namespace crypto
diff --git a/src/crypto/p224_spake.h b/src/crypto/p224_spake.h index 1711d56..1a5fcb0 100644 --- a/src/crypto/p224_spake.h +++ b/src/crypto/p224_spake.h
@@ -5,16 +5,20 @@ #ifndef CRYPTO_P224_SPAKE_H_ #define CRYPTO_P224_SPAKE_H_ -#include <base/string_piece.h> -#include <crypto/p224.h> -#include <crypto/sha2.h> +#include <string> + +#include "base/gtest_prod_util.h" +#include "base/strings/string_piece.h" +#include "crypto/p224.h" +#include "crypto/sha2.h" +#include "starboard/types.h" namespace crypto { // P224EncryptedKeyExchange implements SPAKE2, a variant of Encrypted // Key Exchange. It allows two parties that have a secret common // password to establish a common secure key by exchanging messages -// over unsecure channel without disclosing the password. +// over an insecure channel without disclosing the password. // // The password can be low entropy as authenticating with an attacker only // gives the attacker a one-shot password oracle. No other information about @@ -22,10 +26,10 @@ // permitted authentication attempts otherwise they get many one-shot oracles.) // // The protocol requires several RTTs (actually two, but you shouldn't assume -// that.) To use the object, call GetMessage() and pass that message to the +// that.) To use the object, call GetNextMessage() and pass that message to the // peer. Get a message from the peer and feed it into ProcessMessage. Then // examine the return value of ProcessMessage: -// kResultPending: Another round is required. Call GetMessage and repeat. +// kResultPending: Another round is required. Call GetNextMessage and repeat. // kResultFailed: The authentication has failed. You can get a human readable // error message by calling error(). // kResultSuccess: The authentication was successful. @@ -51,16 +55,15 @@ // password: secret session password. Both parties to the // authentication must pass the same value. For the case of a // TLS connection, see RFC 5705. - P224EncryptedKeyExchange(PeerType peer_type, - const base::StringPiece& password); + P224EncryptedKeyExchange(PeerType peer_type, base::StringPiece password); - // GetMessage returns a byte string which must be passed to the other party - // in the authentication. - const std::string& GetMessage(); + // GetNextMessage returns a byte string which must be passed to the other + // party in the authentication. + const std::string& GetNextMessage(); // ProcessMessage processes a message which must have been generated by a - // call to GetMessage() by the other party. - Result ProcessMessage(const base::StringPiece& message); + // call to GetNextMessage() by the other party. + Result ProcessMessage(base::StringPiece message); // In the event that ProcessMessage() returns kResultFailed, error will // return a human readable error message. @@ -68,7 +71,11 @@ // The key established as result of the key exchange. Must be called // at then end after ProcessMessage() returns kResultSuccess. - const std::string& GetKey(); + const std::string& GetKey() const; + + // The key established as result of the key exchange. Can be called after + // the first ProcessMessage() + const std::string& GetUnverifiedKey() const; private: // The authentication state machine is very simple and each party proceeds @@ -81,30 +88,36 @@ kStateDone, }; + FRIEND_TEST_ALL_PREFIXES(MutualAuth, ExpectedValues); + + void Init(); + + // Sets internal random scalar. Should be used by tests only. + void SetXForTesting(const std::string& x); + State state_; const bool is_server_; - // next_message_ contains a value for GetMessage() to return. + // next_message_ contains a value for GetNextMessage() to return. std::string next_message_; std::string error_; // CalculateHash computes the verification hash for the given peer and writes // |kSHA256Length| bytes at |out_digest|. - void CalculateHash( - PeerType peer_type, - const std::string& client_masked_dh, - const std::string& server_masked_dh, - const std::string& k, - uint8* out_digest); + void CalculateHash(PeerType peer_type, + const std::string& client_masked_dh, + const std::string& server_masked_dh, + const std::string& k, + uint8_t* out_digest); // x_ is the secret Diffie-Hellman exponent (see paper referenced in .cc // file). - uint8 x_[p224::kScalarBytes]; - // pw_ is SHA256(P(password), P(session))[:28] where P() prepends a uint32, - // big-endian length prefix (see paper refereneced in .cc file). - uint8 pw_[p224::kScalarBytes]; + uint8_t x_[p224::kScalarBytes]; + // pw_ is SHA256(P(password), P(session))[:28] where P() prepends a uint32_t, + // big-endian length prefix (see paper referenced in .cc file). + uint8_t pw_[p224::kScalarBytes]; // expected_authenticator_ is used to store the hash value expected from the // other party. - uint8 expected_authenticator_[kSHA256Length]; + uint8_t expected_authenticator_[kSHA256Length]; std::string key_; };
diff --git a/src/crypto/p224_spake_unittest.cc b/src/crypto/p224_spake_unittest.cc index eabc843..db15e33 100644 --- a/src/crypto/p224_spake_unittest.cc +++ b/src/crypto/p224_spake_unittest.cc
@@ -2,45 +2,54 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <crypto/p224_spake.h> +#include "crypto/p224_spake.h" + +#include <string> #include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" namespace crypto { namespace { -bool RunExchange(P224EncryptedKeyExchange* client, - P224EncryptedKeyExchange* server) { +std::string HexEncodeString(const std::string& binary_data) { + return base::HexEncode(binary_data.c_str(), binary_data.size()); +} +bool RunExchange(P224EncryptedKeyExchange* client, + P224EncryptedKeyExchange* server, + bool is_password_same) { for (;;) { std::string client_message, server_message; - client_message = client->GetMessage(); - server_message = server->GetMessage(); + client_message = client->GetNextMessage(); + server_message = server->GetNextMessage(); P224EncryptedKeyExchange::Result client_result, server_result; client_result = client->ProcessMessage(server_message); server_result = server->ProcessMessage(client_message); // Check that we never hit the case where only one succeeds. - if ((client_result == P224EncryptedKeyExchange::kResultSuccess) ^ - (server_result == P224EncryptedKeyExchange::kResultSuccess)) { - CHECK(false) << "Parties differ on whether authentication was successful"; - } + EXPECT_EQ(client_result == P224EncryptedKeyExchange::kResultSuccess, + server_result == P224EncryptedKeyExchange::kResultSuccess); if (client_result == P224EncryptedKeyExchange::kResultFailed || server_result == P224EncryptedKeyExchange::kResultFailed) { return false; } + EXPECT_EQ(is_password_same, + client->GetUnverifiedKey() == server->GetUnverifiedKey()); + if (client_result == P224EncryptedKeyExchange::kResultSuccess && server_result == P224EncryptedKeyExchange::kResultSuccess) { return true; } - CHECK_EQ(P224EncryptedKeyExchange::kResultPending, client_result); - CHECK_EQ(P224EncryptedKeyExchange::kResultPending, server_result); + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, client_result); + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, server_result); } } @@ -54,7 +63,7 @@ P224EncryptedKeyExchange server( P224EncryptedKeyExchange::kPeerTypeServer, kPassword); - EXPECT_TRUE(RunExchange(&client, &server)); + EXPECT_TRUE(RunExchange(&client, &server, true)); EXPECT_EQ(client.GetKey(), server.GetKey()); } @@ -66,7 +75,43 @@ P224EncryptedKeyExchange::kPeerTypeServer, "wrongpassword"); - EXPECT_FALSE(RunExchange(&client, &server)); + EXPECT_FALSE(RunExchange(&client, &server, false)); +} + +TEST(MutualAuth, ExpectedValues) { + P224EncryptedKeyExchange client(P224EncryptedKeyExchange::kPeerTypeClient, + kPassword); + client.SetXForTesting("Client x"); + P224EncryptedKeyExchange server(P224EncryptedKeyExchange::kPeerTypeServer, + kPassword); + server.SetXForTesting("Server x"); + + std::string client_message = client.GetNextMessage(); + EXPECT_EQ( + "3508EF7DECC8AB9F9C439FBB0154288BBECC0A82E8448F4CF29554EB" + "BE9D486686226255EAD1D077C635B1A41F46AC91D7F7F32CED9EC3E0", + HexEncodeString(client_message)); + + std::string server_message = server.GetNextMessage(); + EXPECT_EQ( + "A3088C18B75D2C2B107105661AEC85424777475EB29F1DDFB8C14AFB" + "F1603D0DF38413A00F420ACF2059E7997C935F5A957A193D09A2B584", + HexEncodeString(server_message)); + + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, + client.ProcessMessage(server_message)); + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, + server.ProcessMessage(client_message)); + + EXPECT_EQ(client.GetUnverifiedKey(), server.GetUnverifiedKey()); + // Must stay the same. External implementations should be able to pair with. + EXPECT_EQ( + "CE7CCFC435CDA4F01EC8826788B1F8B82EF7D550A34696B371096E64" + "C487D4FE193F7D1A6FF6820BC7F807796BA3889E8F999BBDEFC32FFA", + HexEncodeString(server.GetUnverifiedKey())); + + EXPECT_TRUE(RunExchange(&client, &server, true)); + EXPECT_EQ(client.GetKey(), server.GetKey()); } TEST(MutualAuth, Fuzz) { @@ -80,16 +125,16 @@ // We'll only be testing small values of i, but we don't want that to bias // the test coverage. So we disperse the value of i by multiplying by the - // FNV, 32-bit prime, producing a poor-man's PRNG. - const uint32 rand = i * 16777619; + // FNV, 32-bit prime, producing a simplistic PRNG. + const uint32_t rand = i * 16777619; for (unsigned round = 0;; round++) { std::string client_message, server_message; - client_message = client.GetMessage(); - server_message = server.GetMessage(); + client_message = client.GetNextMessage(); + server_message = server.GetNextMessage(); if ((rand & 1) == round) { - const bool server_or_client = (rand & 2) != 0; + const bool server_or_client = rand & 2; std::string* m = server_or_client ? &server_message : &client_message; if (rand & 4) { // Truncate
diff --git a/src/crypto/p224_unittest.cc b/src/crypto/p224_unittest.cc index aaf5f59..126b50d 100644 --- a/src/crypto/p224_unittest.cc +++ b/src/crypto/p224_unittest.cc
@@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <string.h> #include <stdio.h> +#include <string.h> #include "crypto/p224.h" +#include "base/macros.h" +#include "starboard/memory.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" namespace crypto { @@ -14,22 +17,20 @@ using p224::Point; // kBasePointExternal is the P224 base point in external representation. -static const uint8 kBasePointExternal[56] = { - 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, - 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, - 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, - 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, - 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, - 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, - 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34, +static const uint8_t kBasePointExternal[56] = { + 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9, + 0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, + 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, + 0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, + 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34, }; // TestVector represents a test of scalar multiplication of the base point. // |scalar| is a big-endian scalar and |affine| is the external representation // of g*scalar. struct TestVector { - uint8 scalar[28]; - uint8 affine[28*2]; + uint8_t scalar[28]; + uint8_t affine[28 * 2]; }; static const int kNumNISTTestVectors = 52; @@ -777,8 +778,8 @@ const std::string external = point.ToString(); ASSERT_EQ(external.size(), 56u); - EXPECT_TRUE(memcmp(external.data(), kBasePointExternal, - sizeof(kBasePointExternal)) == 0); + EXPECT_EQ(0, SbMemoryCompare(external.data(), kBasePointExternal, + sizeof(kBasePointExternal))); } TEST(P224, ScalarBaseMult) { @@ -788,8 +789,8 @@ p224::ScalarBaseMult(kNISTTestVectors[i].scalar, &point); const std::string external = point.ToString(); ASSERT_EQ(external.size(), 56u); - EXPECT_TRUE(memcmp(external.data(), kNISTTestVectors[i].affine, - external.size()) == 0); + EXPECT_EQ(0, SbMemoryCompare(external.data(), kNISTTestVectors[i].affine, + external.size())); } } @@ -803,19 +804,19 @@ p224::Negate(b, &minus_b); p224::Add(a, b, &sum); - EXPECT_TRUE(memcmp(&sum, &a, sizeof(sum)) != 0); + EXPECT_NE(0, SbMemoryCompare(&sum, &a, sizeof(sum))); p224::Add(minus_b, sum, &a_again); - EXPECT_TRUE(a_again.ToString() == a.ToString()); + EXPECT_EQ(a_again.ToString(), a.ToString()); } TEST(P224, Infinity) { char zeros[56]; - memset(zeros, 0, sizeof(zeros)); + SbMemorySet(zeros, 0, sizeof(zeros)); // Test that x^0 = ∞. Point a; - p224::ScalarBaseMult(reinterpret_cast<const uint8*>(zeros), &a); - EXPECT_TRUE(memcmp(zeros, a.ToString().data(), sizeof(zeros)) == 0); + p224::ScalarBaseMult(reinterpret_cast<const uint8_t*>(zeros), &a); + EXPECT_EQ(0, SbMemoryCompare(zeros, a.ToString().data(), sizeof(zeros))); // We shouldn't allow ∞ to be imported. EXPECT_FALSE(a.SetFromString(std::string(zeros, sizeof(zeros))));
diff --git a/src/crypto/random.cc b/src/crypto/random.cc index a19bb1a..daa6481 100644 --- a/src/crypto/random.cc +++ b/src/crypto/random.cc
@@ -5,6 +5,7 @@ #include "crypto/random.h" #include "base/rand_util.h" +#include "starboard/types.h" namespace crypto {
diff --git a/src/crypto/random.h b/src/crypto/random.h index 002616b..e646201 100644 --- a/src/crypto/random.h +++ b/src/crypto/random.h
@@ -5,9 +5,8 @@ #ifndef CRYPTO_RANDOM_H_ #define CRYPTO_RANDOM_H_ -#include <stddef.h> - #include "crypto/crypto_export.h" +#include "starboard/types.h" namespace crypto { @@ -18,4 +17,4 @@ } -#endif +#endif // CRYPTO_RANDOM_H_
diff --git a/src/crypto/random_unittest.cc b/src/crypto/random_unittest.cc index 297f3cc..8ff0915 100644 --- a/src/crypto/random_unittest.cc +++ b/src/crypto/random_unittest.cc
@@ -4,7 +4,10 @@ #include "crypto/random.h" -#include "base/string_util.h" +#include <string> + +#include "base/strings/string_util.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" // Basic functionality tests. Does NOT test the security of the random data. @@ -22,6 +25,6 @@ TEST(RandBytes, RandBytes) { std::string bytes(16, '\0'); - crypto::RandBytes(WriteInto(&bytes, bytes.size()), bytes.size()); + crypto::RandBytes(base::WriteInto(&bytes, bytes.size()), bytes.size()); EXPECT_TRUE(!IsTrivial(bytes)); }
diff --git a/src/crypto/rsa_private_key.cc b/src/crypto/rsa_private_key.cc index 62eb996..d84e460 100644 --- a/src/crypto/rsa_private_key.cc +++ b/src/crypto/rsa_private_key.cc
@@ -4,380 +4,108 @@ #include "crypto/rsa_private_key.h" -#include <algorithm> -#include <list> +#include <memory> +#include <utility> #include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/string_util.h" - -// This file manually encodes and decodes RSA private keys using PrivateKeyInfo -// from PKCS #8 and RSAPrivateKey from PKCS #1. These structures are: -// -// PrivateKeyInfo ::= SEQUENCE { -// version Version, -// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, -// privateKey PrivateKey, -// attributes [0] IMPLICIT Attributes OPTIONAL -// } -// -// RSAPrivateKey ::= SEQUENCE { -// version Version, -// modulus INTEGER, -// publicExponent INTEGER, -// privateExponent INTEGER, -// prime1 INTEGER, -// prime2 INTEGER, -// exponent1 INTEGER, -// exponent2 INTEGER, -// coefficient INTEGER -// } - -namespace { -// Helper for error handling during key import. -#define READ_ASSERT(truth) \ - if (!(truth)) { \ - NOTREACHED(); \ - return false; \ - } -} // namespace +#include "crypto/openssl_util.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/bn.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/mem.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" namespace crypto { -const uint8 PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = { - 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, - 0x05, 0x00 -}; +// static +std::unique_ptr<RSAPrivateKey> RSAPrivateKey::Create(uint16_t num_bits) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); -PrivateKeyInfoCodec::PrivateKeyInfoCodec(bool big_endian) - : big_endian_(big_endian) {} + bssl::UniquePtr<RSA> rsa_key(RSA_new()); + bssl::UniquePtr<BIGNUM> bn(BN_new()); + if (!rsa_key.get() || !bn.get() || !BN_set_word(bn.get(), 65537L)) + return nullptr; -PrivateKeyInfoCodec::~PrivateKeyInfoCodec() {} + if (!RSA_generate_key_ex(rsa_key.get(), num_bits, bn.get(), nullptr)) + return nullptr; -bool PrivateKeyInfoCodec::Export(std::vector<uint8>* output) { - std::list<uint8> content; + std::unique_ptr<RSAPrivateKey> result(new RSAPrivateKey); + result->key_.reset(EVP_PKEY_new()); + if (!result->key_ || !EVP_PKEY_set1_RSA(result->key_.get(), rsa_key.get())) + return nullptr; - // Version (always zero) - uint8 version = 0; - - PrependInteger(coefficient_, &content); - PrependInteger(exponent2_, &content); - PrependInteger(exponent1_, &content); - PrependInteger(prime2_, &content); - PrependInteger(prime1_, &content); - PrependInteger(private_exponent_, &content); - PrependInteger(public_exponent_, &content); - PrependInteger(modulus_, &content); - PrependInteger(&version, 1, &content); - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - PrependTypeHeaderAndLength(kOctetStringTag, content.size(), &content); - - // RSA algorithm OID - for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) - content.push_front(kRsaAlgorithmIdentifier[i - 1]); - - PrependInteger(&version, 1, &content); - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - - // Copy everying into the output. - output->reserve(content.size()); - output->assign(content.begin(), content.end()); - - return true; + return result; } -bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8>* output) { - // Create a sequence with the modulus (n) and public exponent (e). - std::vector<uint8> bit_string; - if (!ExportPublicKey(&bit_string)) - return false; +// static +std::unique_ptr<RSAPrivateKey> RSAPrivateKey::CreateFromPrivateKeyInfo( + const std::vector<uint8_t>& input) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); - // Add the sequence as the contents of a bit string. - std::list<uint8> content; - PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()), - &content); + CBS cbs; + CBS_init(&cbs, input.data(), input.size()); + bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs)); + if (!pkey || CBS_len(&cbs) != 0 || EVP_PKEY_id(pkey.get()) != EVP_PKEY_RSA) + return nullptr; - // Add the RSA algorithm OID. - for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) - content.push_front(kRsaAlgorithmIdentifier[i - 1]); - - // Finally, wrap everything in a sequence. - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - - // Copy everything into the output. - output->reserve(content.size()); - output->assign(content.begin(), content.end()); - - return true; + std::unique_ptr<RSAPrivateKey> result(new RSAPrivateKey); + result->key_ = std::move(pkey); + return result; } -bool PrivateKeyInfoCodec::ExportPublicKey(std::vector<uint8>* output) { - // Create a sequence with the modulus (n) and public exponent (e). - std::list<uint8> content; - PrependInteger(&public_exponent_[0], - static_cast<int>(public_exponent_.size()), - &content); - PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content); - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - - // Copy everything into the output. - output->reserve(content.size()); - output->assign(content.begin(), content.end()); - - return true; +// static +std::unique_ptr<RSAPrivateKey> RSAPrivateKey::CreateFromKey(EVP_PKEY* key) { + DCHECK(key); + if (EVP_PKEY_type(key->type) != EVP_PKEY_RSA) + return nullptr; + std::unique_ptr<RSAPrivateKey> copy(new RSAPrivateKey); + copy->key_ = bssl::UpRef(key); + return copy; } -bool PrivateKeyInfoCodec::Import(const std::vector<uint8>& input) { - if (input.empty()) { +RSAPrivateKey::RSAPrivateKey() = default; + +RSAPrivateKey::~RSAPrivateKey() = default; + +std::unique_ptr<RSAPrivateKey> RSAPrivateKey::Copy() const { + std::unique_ptr<RSAPrivateKey> copy(new RSAPrivateKey); + bssl::UniquePtr<RSA> rsa(EVP_PKEY_get1_RSA(key_.get())); + if (!rsa) + return nullptr; + copy->key_.reset(EVP_PKEY_new()); + if (!EVP_PKEY_set1_RSA(copy->key_.get(), rsa.get())) + return nullptr; + return copy; +} + +bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + uint8_t *der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_private_key(cbb.get(), key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { return false; } - - // Parse the private key info up to the public key values, ignoring - // the subsequent private key values. - uint8* src = const_cast<uint8*>(&input.front()); - uint8* end = src + input.size(); - if (!ReadSequence(&src, end) || - !ReadVersion(&src, end) || - !ReadAlgorithmIdentifier(&src, end) || - !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) || - !ReadSequence(&src, end) || - !ReadVersion(&src, end) || - !ReadInteger(&src, end, &modulus_)) - return false; - - int mod_size = modulus_.size(); - READ_ASSERT(mod_size % 2 == 0); - int primes_size = mod_size / 2; - - if (!ReadIntegerWithExpectedSize(&src, end, 4, &public_exponent_) || - !ReadIntegerWithExpectedSize(&src, end, mod_size, &private_exponent_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime1_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime2_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent1_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent2_) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &coefficient_)) - return false; - - READ_ASSERT(src == end); - - + output->assign(der, der + der_len); + OPENSSL_free(der); return true; } -void PrivateKeyInfoCodec::PrependInteger(const std::vector<uint8>& in, - std::list<uint8>* out) { - uint8* ptr = const_cast<uint8*>(&in.front()); - PrependIntegerImpl(ptr, in.size(), out, big_endian_); -} - -// Helper to prepend an ASN.1 integer. -void PrivateKeyInfoCodec::PrependInteger(uint8* val, - int num_bytes, - std::list<uint8>* data) { - PrependIntegerImpl(val, num_bytes, data, big_endian_); -} - -void PrivateKeyInfoCodec::PrependIntegerImpl(uint8* val, - int num_bytes, - std::list<uint8>* data, - bool big_endian) { - // Reverse input if little-endian. - std::vector<uint8> tmp; - if (!big_endian) { - tmp.assign(val, val + num_bytes); - std::reverse(tmp.begin(), tmp.end()); - val = &tmp.front(); - } - - // ASN.1 integers are unpadded byte arrays, so skip any null padding bytes - // from the most-significant end of the integer. - int start = 0; - while (start < (num_bytes - 1) && val[start] == 0x00) { - start++; - num_bytes--; - } - PrependBytes(val, start, num_bytes, data); - - // ASN.1 integers are signed. To encode a positive integer whose sign bit - // (the most significant bit) would otherwise be set and make the number - // negative, ASN.1 requires a leading null byte to force the integer to be - // positive. - uint8 front = data->front(); - if ((front & 0x80) != 0) { - data->push_front(0x00); - num_bytes++; - } - - PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); -} - -bool PrivateKeyInfoCodec::ReadInteger(uint8** pos, - uint8* end, - std::vector<uint8>* out) { - return ReadIntegerImpl(pos, end, out, big_endian_); -} - -bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize(uint8** pos, - uint8* end, - size_t expected_size, - std::vector<uint8>* out) { - std::vector<uint8> temp; - if (!ReadIntegerImpl(pos, end, &temp, true)) // Big-Endian +bool RSAPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + uint8_t *der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_public_key(cbb.get(), key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { return false; - - int pad = expected_size - temp.size(); - int index = 0; - if (out->size() == expected_size + 1) { - READ_ASSERT(out->front() == 0x00); - pad++; - index++; - } else { - READ_ASSERT(out->size() <= expected_size); } - - out->insert(out->end(), pad, 0x00); - out->insert(out->end(), temp.begin(), temp.end()); - - // Reverse output if little-endian. - if (!big_endian_) - std::reverse(out->begin(), out->end()); - return true; -} - -bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8** pos, - uint8* end, - std::vector<uint8>* out, - bool big_endian) { - uint32 length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length) || !length) - return false; - - // The first byte can be zero to force positiveness. We can ignore this. - if (**pos == 0x00) { - ++(*pos); - --length; - } - - if (length) - out->insert(out->end(), *pos, (*pos) + length); - - (*pos) += length; - - // Reverse output if little-endian. - if (!big_endian) - std::reverse(out->begin(), out->end()); - return true; -} - -void PrivateKeyInfoCodec::PrependBytes(uint8* val, - int start, - int num_bytes, - std::list<uint8>* data) { - while (num_bytes > 0) { - --num_bytes; - data->push_front(val[start + num_bytes]); - } -} - -void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8>* data) { - // The high bit is used to indicate whether additional octets are needed to - // represent the length. - if (size < 0x80) { - data->push_front(static_cast<uint8>(size)); - } else { - uint8 num_bytes = 0; - while (size > 0) { - data->push_front(static_cast<uint8>(size & 0xFF)); - size >>= 8; - num_bytes++; - } - CHECK_LE(num_bytes, 4); - data->push_front(0x80 | num_bytes); - } -} - -void PrivateKeyInfoCodec::PrependTypeHeaderAndLength(uint8 type, - uint32 length, - std::list<uint8>* output) { - PrependLength(length, output); - output->push_front(type); -} - -void PrivateKeyInfoCodec::PrependBitString(uint8* val, - int num_bytes, - std::list<uint8>* output) { - // Start with the data. - PrependBytes(val, 0, num_bytes, output); - // Zero unused bits. - output->push_front(0); - // Add the length. - PrependLength(num_bytes + 1, output); - // Finally, add the bit string tag. - output->push_front((uint8) kBitStringTag); -} - -bool PrivateKeyInfoCodec::ReadLength(uint8** pos, uint8* end, uint32* result) { - READ_ASSERT(*pos < end); - int length = 0; - - // If the MSB is not set, the length is just the byte itself. - if (!(**pos & 0x80)) { - length = **pos; - (*pos)++; - } else { - // Otherwise, the lower 7 indicate the length of the length. - int length_of_length = **pos & 0x7F; - READ_ASSERT(length_of_length <= 4); - (*pos)++; - READ_ASSERT(*pos + length_of_length < end); - - length = 0; - for (int i = 0; i < length_of_length; ++i) { - length <<= 8; - length |= **pos; - (*pos)++; - } - } - - READ_ASSERT(*pos + length <= end); - if (result) *result = length; - return true; -} - -bool PrivateKeyInfoCodec::ReadTypeHeaderAndLength(uint8** pos, - uint8* end, - uint8 expected_tag, - uint32* length) { - READ_ASSERT(*pos < end); - READ_ASSERT(**pos == expected_tag); - (*pos)++; - - return ReadLength(pos, end, length); -} - -bool PrivateKeyInfoCodec::ReadSequence(uint8** pos, uint8* end) { - return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL); -} - -bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8** pos, uint8* end) { - READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end); - READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier, - sizeof(kRsaAlgorithmIdentifier)) == 0); - (*pos) += sizeof(kRsaAlgorithmIdentifier); - return true; -} - -bool PrivateKeyInfoCodec::ReadVersion(uint8** pos, uint8* end) { - uint32 length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) - return false; - - // The version should be zero. - for (uint32 i = 0; i < length; ++i) { - READ_ASSERT(**pos == 0x00); - (*pos)++; - } - + output->assign(der, der + der_len); + OPENSSL_free(der); return true; }
diff --git a/src/crypto/rsa_private_key.h b/src/crypto/rsa_private_key.h index ff368d8..2c6d4e8 100644 --- a/src/crypto/rsa_private_key.h +++ b/src/crypto/rsa_private_key.h
@@ -5,170 +5,17 @@ #ifndef CRYPTO_RSA_PRIVATE_KEY_H_ #define CRYPTO_RSA_PRIVATE_KEY_H_ -#include "build/build_config.h" - -#if defined(USE_OPENSSL) -// Forward declaration for openssl/*.h -typedef struct evp_pkey_st EVP_PKEY; -#elif defined(USE_NSS) -// Forward declaration. -struct SECKEYPrivateKeyStr; -struct SECKEYPublicKeyStr; -#elif defined(OS_IOS) -#include <Security/Security.h> -#elif defined(OS_MACOSX) -#include <Security/cssm.h> -#endif - -#include <list> +#include <memory> #include <vector> -#include "base/basictypes.h" +#include "base/macros.h" +#include "build/build_config.h" #include "crypto/crypto_export.h" - -#if defined(OS_WIN) -#include "crypto/scoped_capi_types.h" -#endif -#if defined(USE_NSS) -#include "base/gtest_prod_util.h" -#endif +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/base.h" namespace crypto { -// Used internally by RSAPrivateKey for serializing and deserializing -// PKCS #8 PrivateKeyInfo and PublicKeyInfo. -class PrivateKeyInfoCodec { - public: - - // ASN.1 encoding of the AlgorithmIdentifier from PKCS #8. - static const uint8 kRsaAlgorithmIdentifier[]; - - // ASN.1 tags for some types we use. - static const uint8 kBitStringTag = 0x03; - static const uint8 kIntegerTag = 0x02; - static const uint8 kNullTag = 0x05; - static const uint8 kOctetStringTag = 0x04; - static const uint8 kSequenceTag = 0x30; - - // |big_endian| here specifies the byte-significance of the integer components - // that will be parsed & serialized (modulus(), etc...) during Import(), - // Export() and ExportPublicKeyInfo() -- not the ASN.1 DER encoding of the - // PrivateKeyInfo/PublicKeyInfo (which is always big-endian). - explicit PrivateKeyInfoCodec(bool big_endian); - - ~PrivateKeyInfoCodec(); - - // Exports the contents of the integer components to the ASN.1 DER encoding - // of the PrivateKeyInfo structure to |output|. - bool Export(std::vector<uint8>* output); - - // Exports the contents of the integer components to the ASN.1 DER encoding - // of the PublicKeyInfo structure to |output|. - bool ExportPublicKeyInfo(std::vector<uint8>* output); - - // Exports the contents of the integer components to the ASN.1 DER encoding - // of the RSAPublicKey structure to |output|. - bool ExportPublicKey(std::vector<uint8>* output); - - // Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input| - // and populates the integer components with |big_endian_| byte-significance. - // IMPORTANT NOTE: This is currently *not* security-approved for importing - // keys from unstrusted sources. - bool Import(const std::vector<uint8>& input); - - // Accessors to the contents of the integer components of the PrivateKeyInfo - // structure. - std::vector<uint8>* modulus() { return &modulus_; }; - std::vector<uint8>* public_exponent() { return &public_exponent_; }; - std::vector<uint8>* private_exponent() { return &private_exponent_; }; - std::vector<uint8>* prime1() { return &prime1_; }; - std::vector<uint8>* prime2() { return &prime2_; }; - std::vector<uint8>* exponent1() { return &exponent1_; }; - std::vector<uint8>* exponent2() { return &exponent2_; }; - std::vector<uint8>* coefficient() { return &coefficient_; }; - - private: - // Utility wrappers for PrependIntegerImpl that use the class's |big_endian_| - // value. - void PrependInteger(const std::vector<uint8>& in, std::list<uint8>* out); - void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data); - - // Prepends the integer stored in |val| - |val + num_bytes| with |big_endian| - // byte-significance into |data| as an ASN.1 integer. - void PrependIntegerImpl(uint8* val, - int num_bytes, - std::list<uint8>* data, - bool big_endian); - - // Utility wrappers for ReadIntegerImpl that use the class's |big_endian_| - // value. - bool ReadInteger(uint8** pos, uint8* end, std::vector<uint8>* out); - bool ReadIntegerWithExpectedSize(uint8** pos, - uint8* end, - size_t expected_size, - std::vector<uint8>* out); - - // Reads an ASN.1 integer from |pos|, and stores the result into |out| with - // |big_endian| byte-significance. - bool ReadIntegerImpl(uint8** pos, - uint8* end, - std::vector<uint8>* out, - bool big_endian); - - // Prepends the integer stored in |val|, starting a index |start|, for - // |num_bytes| bytes onto |data|. - void PrependBytes(uint8* val, - int start, - int num_bytes, - std::list<uint8>* data); - - // Helper to prepend an ASN.1 length field. - void PrependLength(size_t size, std::list<uint8>* data); - - // Helper to prepend an ASN.1 type header. - void PrependTypeHeaderAndLength(uint8 type, - uint32 length, - std::list<uint8>* output); - - // Helper to prepend an ASN.1 bit string - void PrependBitString(uint8* val, int num_bytes, std::list<uint8>* output); - - // Read an ASN.1 length field. This also checks that the length does not - // extend beyond |end|. - bool ReadLength(uint8** pos, uint8* end, uint32* result); - - // Read an ASN.1 type header and its length. - bool ReadTypeHeaderAndLength(uint8** pos, - uint8* end, - uint8 expected_tag, - uint32* length); - - // Read an ASN.1 sequence declaration. This consumes the type header and - // length field, but not the contents of the sequence. - bool ReadSequence(uint8** pos, uint8* end); - - // Read the RSA AlgorithmIdentifier. - bool ReadAlgorithmIdentifier(uint8** pos, uint8* end); - - // Read one of the two version fields in PrivateKeyInfo. - bool ReadVersion(uint8** pos, uint8* end); - - // The byte-significance of the stored components (modulus, etc..). - bool big_endian_; - - // Component integers of the PrivateKeyInfo - std::vector<uint8> modulus_; - std::vector<uint8> public_exponent_; - std::vector<uint8> private_exponent_; - std::vector<uint8> prime1_; - std::vector<uint8> prime2_; - std::vector<uint8> exponent1_; - std::vector<uint8> exponent2_; - std::vector<uint8> coefficient_; - - DISALLOW_COPY_AND_ASSIGN(PrivateKeyInfoCodec); -}; - // Encapsulates an RSA private key. Can be used to generate new keys, export // keys to other formats, or to extract a public key. // TODO(hclam): This class should be ref-counted so it can be reused easily. @@ -177,104 +24,35 @@ ~RSAPrivateKey(); // Create a new random instance. Can return NULL if initialization fails. - static RSAPrivateKey* Create(uint16 num_bits); - - // Create a new random instance. Can return NULL if initialization fails. - // The created key is permanent and is not exportable in plaintext form. - // - // NOTE: Currently only available if USE_NSS is defined. - static RSAPrivateKey* CreateSensitive(uint16 num_bits); + static std::unique_ptr<RSAPrivateKey> Create(uint16_t num_bits); // Create a new instance by importing an existing private key. The format is // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if // initialization fails. - static RSAPrivateKey* CreateFromPrivateKeyInfo( - const std::vector<uint8>& input); + static std::unique_ptr<RSAPrivateKey> CreateFromPrivateKeyInfo( + const std::vector<uint8_t>& input); - // Create a new instance by importing an existing private key. The format is - // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if - // initialization fails. - // The created key is permanent and is not exportable in plaintext form. - // - // NOTE: Currently only available if USE_NSS is defined. - static RSAPrivateKey* CreateSensitiveFromPrivateKeyInfo( - const std::vector<uint8>& input); + // Create a new instance from an existing EVP_PKEY, taking a + // reference to it. |key| must be an RSA key. Returns NULL on + // failure. + static std::unique_ptr<RSAPrivateKey> CreateFromKey(EVP_PKEY* key); - // Import an existing public key, and then search for the private - // half in the key database. The format of the public key blob is is - // an X509 SubjectPublicKeyInfo block. This can return NULL if - // initialization fails or the private key cannot be found. The - // caller takes ownership of the returned object, but nothing new is - // created in the key database. - // - // NOTE: Currently only available if USE_NSS is defined. - static RSAPrivateKey* FindFromPublicKeyInfo( - const std::vector<uint8>& input); - -#if defined(USE_OPENSSL) - EVP_PKEY* key() { return key_; } -#elif defined(USE_NSS) - SECKEYPrivateKeyStr* key() { return key_; } - SECKEYPublicKeyStr* public_key() { return public_key_; } -#elif defined(OS_WIN) - HCRYPTPROV provider() { return provider_; } - HCRYPTKEY key() { return key_; } -#elif defined(OS_IOS) - SecKeyRef key() { return key_; } - SecKeyRef public_key() { return public_key_; } -#elif defined(OS_MACOSX) - CSSM_KEY_PTR key() { return &key_; } - CSSM_KEY_PTR public_key() { return &public_key_; } -#endif + EVP_PKEY* key() { return key_.get(); } // Creates a copy of the object. - RSAPrivateKey* Copy() const; + std::unique_ptr<RSAPrivateKey> Copy() const; - // Exports the private key to a PKCS #1 PrivateKey block. - bool ExportPrivateKey(std::vector<uint8>* output) const; + // Exports the private key to a PKCS #8 PrivateKeyInfo block. + bool ExportPrivateKey(std::vector<uint8_t>* output) const; // Exports the public key to an X509 SubjectPublicKeyInfo block. - bool ExportPublicKey(std::vector<uint8>* output) const; + bool ExportPublicKey(std::vector<uint8_t>* output) const; private: -#if defined(USE_NSS) - FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FindFromPublicKey); - FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FailedFindFromPublicKey); -#endif - - // Constructor is private. Use one of the Create*() or Find*() - // methods above instead. + // Constructor is private. Use one of the Create*() methods above instead. RSAPrivateKey(); - // Shared helper for Create() and CreateSensitive(). - // TODO(cmasone): consider replacing |permanent| and |sensitive| with a - // flags arg created by ORing together some enumerated values. - static RSAPrivateKey* CreateWithParams(uint16 num_bits, - bool permanent, - bool sensitive); - - // Shared helper for CreateFromPrivateKeyInfo() and - // CreateSensitiveFromPrivateKeyInfo(). - static RSAPrivateKey* CreateFromPrivateKeyInfoWithParams( - const std::vector<uint8>& input, bool permanent, bool sensitive); - -#if defined(USE_OPENSSL) - EVP_PKEY* key_; -#elif defined(USE_NSS) - SECKEYPrivateKeyStr* key_; - SECKEYPublicKeyStr* public_key_; -#elif defined(OS_WIN) - bool InitProvider(); - - ScopedHCRYPTPROV provider_; - ScopedHCRYPTKEY key_; -#elif defined(OS_IOS) - SecKeyRef key_; - SecKeyRef public_key_; -#elif defined(OS_MACOSX) - CSSM_KEY key_; - CSSM_KEY public_key_; -#endif + bssl::UniquePtr<EVP_PKEY> key_; DISALLOW_COPY_AND_ASSIGN(RSAPrivateKey); };
diff --git a/src/crypto/rsa_private_key_ios.cc b/src/crypto/rsa_private_key_ios.cc deleted file mode 100644 index d96b3e9..0000000 --- a/src/crypto/rsa_private_key_ios.cc +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/rsa_private_key.h" - -#include "base/logging.h" - -namespace crypto { - -// |RSAPrivateKey| is not used on iOS. This implementation was written so that -// it would compile. It may be possible to use the NSS implementation as a real -// implementation, but it hasn't yet been necessary. - -// static -RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {} - -RSAPrivateKey::~RSAPrivateKey() { - if (public_key_) - CFRelease(public_key_); - if (key_) - CFRelease(key_); -} - -bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const { - NOTIMPLEMENTED(); - return false; -} - -bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const { - NOTIMPLEMENTED(); - return false; -} - -} // namespace base
diff --git a/src/crypto/rsa_private_key_mac.cc b/src/crypto/rsa_private_key_mac.cc deleted file mode 100644 index fbe1491..0000000 --- a/src/crypto/rsa_private_key_mac.cc +++ /dev/null
@@ -1,204 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/rsa_private_key.h" - -#include <list> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "crypto/cssm_init.h" - -namespace crypto { - -// static -RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - - CSSM_CC_HANDLE cc_handle; - CSSM_RETURN crtn; - crtn = CSSM_CSP_CreateKeyGenContext(GetSharedCSPHandle(), CSSM_ALGID_RSA, - num_bits, NULL, NULL, NULL, NULL, NULL, - &cc_handle); - if (crtn) { - NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn; - return NULL; - } - - CSSM_DATA label = { 9, - const_cast<uint8*>(reinterpret_cast<const uint8*>("temp_key")) }; - crtn = CSSM_GenerateKeyPair(cc_handle, - CSSM_KEYUSE_VERIFY, - CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label, - result->public_key(), CSSM_KEYUSE_SIGN, - CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label, NULL, - result->key()); - CSSM_DeleteContext(cc_handle); - if (crtn) { - NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn; - return NULL; - } - - return result.release(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( - const std::vector<uint8>& input) { - if (input.empty()) - return NULL; - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - - CSSM_KEY key; - memset(&key, 0, sizeof(key)); - key.KeyData.Data = const_cast<uint8*>(&input.front()); - key.KeyData.Length = input.size(); - key.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; - key.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION; - key.KeyHeader.BlobType = CSSM_KEYBLOB_RAW; - key.KeyHeader.AlgorithmId = CSSM_ALGID_RSA; - key.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; - key.KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE; - key.KeyHeader.KeyUsage = CSSM_KEYUSE_ANY; - - CSSM_KEY_SIZE key_size; - CSSM_RETURN crtn; - crtn = CSSM_QueryKeySizeInBits( - GetSharedCSPHandle(), CSSM_INVALID_HANDLE, &key, &key_size); - if (crtn) { - NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn; - return NULL; - } - key.KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits; - - // Perform a NULL unwrap operation on the key so that result's key_ - // instance variable points to a key that can be released via CSSM_FreeKey(). - CSSM_ACCESS_CREDENTIALS creds; - memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); - CSSM_CC_HANDLE cc_handle; - crtn = CSSM_CSP_CreateSymmetricContext(GetSharedCSPHandle(), CSSM_ALGID_NONE, - CSSM_ALGMODE_NONE, &creds, NULL, NULL, CSSM_PADDING_NONE, 0, &cc_handle); - if (crtn) { - NOTREACHED() << "CSSM_CSP_CreateSymmetricContext failed: " << crtn; - return NULL; - } - CSSM_DATA label_data, desc_data = { 0, NULL }; - label_data.Data = - const_cast<uint8*>(reinterpret_cast<const uint8*>("unwrapped")); - label_data.Length = 9; - crtn = CSSM_UnwrapKey(cc_handle, NULL, &key, CSSM_KEYUSE_ANY, - CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label_data, - NULL, result->key(), &desc_data); - if (crtn) { - NOTREACHED() << "CSSM_UnwrapKey failed: " << crtn; - return NULL; - } - - // Extract a public key from the private key. - // Apple doesn't accept CSSM_KEYBLOB_RAW_FORMAT_X509 as a valid key - // format when attempting to generate certs, so use PKCS1 instead. - PrivateKeyInfoCodec codec(true); - std::vector<uint8> private_key_data; - private_key_data.assign(key.KeyData.Data, - key.KeyData.Data + key.KeyData.Length); - if (!codec.Import(private_key_data)) { - return NULL; - } - std::vector<uint8> public_key_data; - if (!codec.ExportPublicKey(&public_key_data)) { - return NULL; - } - - CSSM_KEY* public_key = result->public_key(); - size_t size = public_key_data.size(); - public_key->KeyData.Data = reinterpret_cast<uint8*>(CSSMMalloc(size)); - if (!public_key->KeyData.Data) { - NOTREACHED() << "CSSMMalloc failed"; - return NULL; - } - memcpy(public_key->KeyData.Data, &public_key_data.front(), size); - public_key->KeyData.Length = size; - public_key->KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; - public_key->KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION; - public_key->KeyHeader.BlobType = CSSM_KEYBLOB_RAW; - public_key->KeyHeader.AlgorithmId = CSSM_ALGID_RSA; - public_key->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; - public_key->KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE; - public_key->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY; - - crtn = CSSM_QueryKeySizeInBits( - GetSharedCSPHandle(), CSSM_INVALID_HANDLE, public_key, &key_size); - if (crtn) { - DLOG(ERROR) << "CSSM_QueryKeySizeInBits failed " << crtn; - return NULL; - } - public_key->KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits; - - return result.release(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -RSAPrivateKey::RSAPrivateKey() { - memset(&key_, 0, sizeof(key_)); - memset(&public_key_, 0, sizeof(public_key_)); - - EnsureCSSMInit(); -} - -RSAPrivateKey::~RSAPrivateKey() { - if (key_.KeyData.Data) { - CSSM_FreeKey(GetSharedCSPHandle(), NULL, &key_, CSSM_FALSE); - } - if (public_key_.KeyData.Data) { - CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key_, CSSM_FALSE); - } -} - -RSAPrivateKey* RSAPrivateKey::Copy() const { - std::vector<uint8> key_bytes; - if (!ExportPrivateKey(&key_bytes)) - return NULL; - return CreateFromPrivateKeyInfo(key_bytes); -} - -bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const { - if (!key_.KeyData.Data || !key_.KeyData.Length) { - return false; - } - output->clear(); - output->insert(output->end(), key_.KeyData.Data, - key_.KeyData.Data + key_.KeyData.Length); - return true; -} - -bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const { - PrivateKeyInfoCodec private_key_info(true); - std::vector<uint8> private_key_data; - private_key_data.assign(key_.KeyData.Data, - key_.KeyData.Data + key_.KeyData.Length); - return (private_key_info.Import(private_key_data) && - private_key_info.ExportPublicKeyInfo(output)); -} - -} // namespace crypto
diff --git a/src/crypto/rsa_private_key_nss.cc b/src/crypto/rsa_private_key_nss.cc deleted file mode 100644 index 3b8bd44..0000000 --- a/src/crypto/rsa_private_key_nss.cc +++ /dev/null
@@ -1,251 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/rsa_private_key.h" - -#include <cryptohi.h> -#include <keyhi.h> -#include <pk11pub.h> -#include <secmod.h> - -#include <list> - -#include "base/debug/leak_annotations.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/string_util.h" -#include "crypto/nss_util.h" -#include "crypto/nss_util_internal.h" -#include "crypto/scoped_nss_types.h" - -// TODO(rafaelw): Consider refactoring common functions and definitions from -// rsa_private_key_win.cc or using NSS's ASN.1 encoder. -namespace { - -static bool ReadAttribute(SECKEYPrivateKey* key, - CK_ATTRIBUTE_TYPE type, - std::vector<uint8>* output) { - SECItem item; - SECStatus rv; - rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item); - if (rv != SECSuccess) { - NOTREACHED(); - return false; - } - - output->assign(item.data, item.data + item.len); - SECITEM_FreeItem(&item, PR_FALSE); - return true; -} - -} // namespace - -namespace crypto { - -RSAPrivateKey::~RSAPrivateKey() { - if (key_) - SECKEY_DestroyPrivateKey(key_); - if (public_key_) - SECKEY_DestroyPublicKey(public_key_); -} - -// static -RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { - return CreateWithParams(num_bits, - PR_FALSE /* not permanent */, - PR_FALSE /* not sensitive */); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { - return CreateWithParams(num_bits, - PR_TRUE /* permanent */, - PR_TRUE /* sensitive */); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( - const std::vector<uint8>& input) { - return CreateFromPrivateKeyInfoWithParams(input, - PR_FALSE /* not permanent */, - PR_FALSE /* not sensitive */); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( - const std::vector<uint8>& input) { - return CreateFromPrivateKeyInfoWithParams(input, - PR_TRUE /* permanent */, - PR_TRUE /* sensitive */); -} - -// static -RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( - const std::vector<uint8>& input) { - EnsureNSSInit(); - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - - // First, decode and save the public key. - SECItem key_der; - key_der.type = siBuffer; - key_der.data = const_cast<unsigned char*>(&input[0]); - key_der.len = input.size(); - - CERTSubjectPublicKeyInfo* spki = - SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der); - if (!spki) { - NOTREACHED(); - return NULL; - } - - result->public_key_ = SECKEY_ExtractPublicKey(spki); - SECKEY_DestroySubjectPublicKeyInfo(spki); - if (!result->public_key_) { - NOTREACHED(); - return NULL; - } - - // Make sure the key is an RSA key. If not, that's an error - if (result->public_key_->keyType != rsaKey) { - NOTREACHED(); - return NULL; - } - - ScopedSECItem ck_id( - PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus))); - if (!ck_id.get()) { - NOTREACHED(); - return NULL; - } - - // Search all slots in all modules for the key with the given ID. - AutoSECMODListReadLock auto_lock; - SECMODModuleList* head = SECMOD_GetDefaultModuleList(); - for (SECMODModuleList* item = head; item != NULL; item = item->next) { - int slot_count = item->module->loaded ? item->module->slotCount : 0; - for (int i = 0; i < slot_count; i++) { - // Finally...Look for the key! - result->key_ = PK11_FindKeyByKeyID(item->module->slots[i], - ck_id.get(), NULL); - if (result->key_) - return result.release(); - } - } - - // We didn't find the key. - return NULL; -} - -RSAPrivateKey* RSAPrivateKey::Copy() const { - RSAPrivateKey* copy = new RSAPrivateKey(); - copy->key_ = SECKEY_CopyPrivateKey(key_); - copy->public_key_ = SECKEY_CopyPublicKey(public_key_); - return copy; -} - -bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const { - PrivateKeyInfoCodec private_key_info(true); - - // Manually read the component attributes of the private key and build up - // the PrivateKeyInfo. - if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) || - !ReadAttribute(key_, CKA_PUBLIC_EXPONENT, - private_key_info.public_exponent()) || - !ReadAttribute(key_, CKA_PRIVATE_EXPONENT, - private_key_info.private_exponent()) || - !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) || - !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) || - !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) || - !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) || - !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) { - NOTREACHED(); - return false; - } - - return private_key_info.Export(output); -} - -bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const { - ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_)); - if (!der_pubkey.get()) { - NOTREACHED(); - return false; - } - - output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len); - return true; -} - -RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { - EnsureNSSInit(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits, - bool permanent, - bool sensitive) { - EnsureNSSInit(); - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - - ScopedPK11Slot slot(GetPrivateNSSKeySlot()); - if (!slot.get()) - return NULL; - - PK11RSAGenParams param; - param.keySizeInBits = num_bits; - param.pe = 65537L; - result->key_ = PK11_GenerateKeyPair(slot.get(), - CKM_RSA_PKCS_KEY_PAIR_GEN, - ¶m, - &result->public_key_, - permanent, - sensitive, - NULL); - if (!result->key_) - return NULL; - - return result.release(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams( - const std::vector<uint8>& input, bool permanent, bool sensitive) { - // This method currently leaks some memory. - // See http://crbug.com/34742. - ANNOTATE_SCOPED_MEMORY_LEAK; - EnsureNSSInit(); - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - - ScopedPK11Slot slot(GetPrivateNSSKeySlot()); - if (!slot.get()) - return NULL; - - SECItem der_private_key_info; - der_private_key_info.data = const_cast<unsigned char*>(&input.front()); - der_private_key_info.len = input.size(); - // Allow the private key to be used for key unwrapping, data decryption, - // and signature generation. - const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | - KU_DIGITAL_SIGNATURE; - SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( - slot.get(), &der_private_key_info, NULL, NULL, permanent, sensitive, - key_usage, &result->key_, NULL); - if (rv != SECSuccess) { - NOTREACHED(); - return NULL; - } - - result->public_key_ = SECKEY_ConvertToPublicKey(result->key_); - if (!result->public_key_) { - NOTREACHED(); - return NULL; - } - - return result.release(); -} - -} // namespace crypto
diff --git a/src/crypto/rsa_private_key_openssl.cc b/src/crypto/rsa_private_key_openssl.cc deleted file mode 100644 index 0061db1..0000000 --- a/src/crypto/rsa_private_key_openssl.cc +++ /dev/null
@@ -1,146 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/rsa_private_key.h" - -#include <openssl/evp.h> -#include <openssl/pkcs12.h> -#include <openssl/rsa.h> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "crypto/openssl_util.h" - -namespace crypto { - -namespace { - -// Function pointer definition, for injecting the required key export function -// into ExportKey, below. The supplied function should export EVP_PKEY into -// the supplied BIO, returning 1 on success or 0 on failure. -typedef int (ExportFunction)(BIO*, EVP_PKEY*); - -// Helper to export |key| into |output| via the specified ExportFunction. -bool ExportKey(EVP_PKEY* key, - ExportFunction export_fn, - std::vector<uint8>* output) { - if (!key) - return false; - - OpenSSLErrStackTracer err_tracer(FROM_HERE); - ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem())); - - int res = export_fn(bio.get(), key); - if (!res) - return false; - - char* data = NULL; - long len = BIO_get_mem_data(bio.get(), &data); - if (!data || len < 0) - return false; - - output->assign(data, data + len); - return true; -} - -} // namespace - -// static -RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { - OpenSSLErrStackTracer err_tracer(FROM_HERE); - - ScopedOpenSSL<RSA, RSA_free> rsa_key(RSA_new()); - ScopedOpenSSL<BIGNUM, BN_free> bn(BN_new()); - if (!rsa_key.get() || !bn.get() || !BN_set_word(bn.get(), 65537L)) - return NULL; - - if (!RSA_generate_key_ex(rsa_key.get(), num_bits, bn.get(), NULL)) - return NULL; - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - result->key_ = EVP_PKEY_new(); - if (!result->key_ || !EVP_PKEY_set1_RSA(result->key_, rsa_key.get())) - return NULL; - - return result.release(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( - const std::vector<uint8>& input) { - if (input.empty()) - return NULL; - - OpenSSLErrStackTracer err_tracer(FROM_HERE); - // BIO_new_mem_buf is not const aware, but it does not modify the buffer. - char* data = reinterpret_cast<char*>(const_cast<uint8*>(&input[0])); - ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(data, input.size())); - if (!bio.get()) - return NULL; - - // Importing is a little more involved than exporting, as we must first - // PKCS#8 decode the input, and then import the EVP_PKEY from Private Key - // Info structure returned. - ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8inf( - d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL)); - if (!p8inf.get()) - return NULL; - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - result->key_ = EVP_PKCS82PKEY(p8inf.get()); - if (!result->key_) - return NULL; - - return result.release(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -RSAPrivateKey::RSAPrivateKey() - : key_(NULL) { -} - -RSAPrivateKey::~RSAPrivateKey() { - if (key_) - EVP_PKEY_free(key_); -} - -RSAPrivateKey* RSAPrivateKey::Copy() const { - scoped_ptr<RSAPrivateKey> copy(new RSAPrivateKey()); - bssl::UniquePtr<RSA> rsa(EVP_PKEY_get1_RSA(key_)); - if (!rsa) - return NULL; - copy->key_ = EVP_PKEY_new(); - if (!EVP_PKEY_set1_RSA(copy->key_, rsa.get())) - return NULL; - return copy.release(); -} - -bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const { - return ExportKey(key_, i2d_PKCS8PrivateKeyInfo_bio, output); -} - -bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const { - return ExportKey(key_, i2d_PUBKEY_bio, output); -} - -} // namespace crypto
diff --git a/src/crypto/rsa_private_key_unittest.cc b/src/crypto/rsa_private_key_unittest.cc index b981bda..27e8419 100644 --- a/src/crypto/rsa_private_key_unittest.cc +++ b/src/crypto/rsa_private_key_unittest.cc
@@ -4,192 +4,203 @@ #include "crypto/rsa_private_key.h" -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "testing/gtest/include/gtest/gtest.h" +#if defined(STARBOARD) +#include "starboard/client_porting/poem/string_poem.h" +#include "starboard/memory.h" +#include "starboard/types.h" +#endif + namespace { -const uint8 kTestPrivateKeyInfo[] = { - 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, - 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, - 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, - 0x00, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, - 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61, - 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, - 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, - 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4, - 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, - 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, - 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f, - 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, - 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, - 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff, - 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, - 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, - 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5, - 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, - 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, - 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01, - 0x00, 0x01, 0x02, 0x81, 0x80, 0x03, 0x61, 0x89, - 0x37, 0xcb, 0xf2, 0x98, 0xa0, 0xce, 0xb4, 0xcb, - 0x16, 0x13, 0xf0, 0xe6, 0xaf, 0x5c, 0xc5, 0xa7, - 0x69, 0x71, 0xca, 0xba, 0x8d, 0xe0, 0x4d, 0xdd, - 0xed, 0xb8, 0x48, 0x8b, 0x16, 0x93, 0x36, 0x95, - 0xc2, 0x91, 0x40, 0x65, 0x17, 0xbd, 0x7f, 0xd6, - 0xad, 0x9e, 0x30, 0x28, 0x46, 0xe4, 0x3e, 0xcc, - 0x43, 0x78, 0xf9, 0xfe, 0x1f, 0x33, 0x23, 0x1e, - 0x31, 0x12, 0x9d, 0x3c, 0xa7, 0x08, 0x82, 0x7b, - 0x7d, 0x25, 0x4e, 0x5e, 0x19, 0xa8, 0x9b, 0xed, - 0x86, 0xb2, 0xcb, 0x3c, 0xfe, 0x4e, 0xa1, 0xfa, - 0x62, 0x87, 0x3a, 0x17, 0xf7, 0x60, 0xec, 0x38, - 0x29, 0xe8, 0x4f, 0x34, 0x9f, 0x76, 0x9d, 0xee, - 0xa3, 0xf6, 0x85, 0x6b, 0x84, 0x43, 0xc9, 0x1e, - 0x01, 0xff, 0xfd, 0xd0, 0x29, 0x4c, 0xfa, 0x8e, - 0x57, 0x0c, 0xc0, 0x71, 0xa5, 0xbb, 0x88, 0x46, - 0x29, 0x5c, 0xc0, 0x4f, 0x01, 0x02, 0x41, 0x00, - 0xf5, 0x83, 0xa4, 0x64, 0x4a, 0xf2, 0xdd, 0x8c, - 0x2c, 0xed, 0xa8, 0xd5, 0x60, 0x5a, 0xe4, 0xc7, - 0xcc, 0x61, 0xcd, 0x38, 0x42, 0x20, 0xd3, 0x82, - 0x18, 0xf2, 0x35, 0x00, 0x72, 0x2d, 0xf7, 0x89, - 0x80, 0x67, 0xb5, 0x93, 0x05, 0x5f, 0xdd, 0x42, - 0xba, 0x16, 0x1a, 0xea, 0x15, 0xc6, 0xf0, 0xb8, - 0x8c, 0xbc, 0xbf, 0x54, 0x9e, 0xf1, 0xc1, 0xb2, - 0xb3, 0x8b, 0xb6, 0x26, 0x02, 0x30, 0xc4, 0x81, - 0x02, 0x41, 0x00, 0xc0, 0x60, 0x62, 0x80, 0xe1, - 0x22, 0x78, 0xf6, 0x9d, 0x83, 0x18, 0xeb, 0x72, - 0x45, 0xd7, 0xc8, 0x01, 0x7f, 0xa9, 0xca, 0x8f, - 0x7d, 0xd6, 0xb8, 0x31, 0x2b, 0x84, 0x7f, 0x62, - 0xd9, 0xa9, 0x22, 0x17, 0x7d, 0x06, 0x35, 0x6c, - 0xf3, 0xc1, 0x94, 0x17, 0x85, 0x5a, 0xaf, 0x9c, - 0x5c, 0x09, 0x3c, 0xcf, 0x2f, 0x44, 0x9d, 0xb6, - 0x52, 0x68, 0x5f, 0xf9, 0x59, 0xc8, 0x84, 0x2b, - 0x39, 0x22, 0x8f, 0x02, 0x41, 0x00, 0xb2, 0x04, - 0xe2, 0x0e, 0x56, 0xca, 0x03, 0x1a, 0xc0, 0xf9, - 0x12, 0x92, 0xa5, 0x6b, 0x42, 0xb8, 0x1c, 0xda, - 0x4d, 0x93, 0x9d, 0x5f, 0x6f, 0xfd, 0xc5, 0x58, - 0xda, 0x55, 0x98, 0x74, 0xfc, 0x28, 0x17, 0x93, - 0x1b, 0x75, 0x9f, 0x50, 0x03, 0x7f, 0x7e, 0xae, - 0xc8, 0x95, 0x33, 0x75, 0x2c, 0xd6, 0xa4, 0x35, - 0xb8, 0x06, 0x03, 0xba, 0x08, 0x59, 0x2b, 0x17, - 0x02, 0xdc, 0x4c, 0x7a, 0x50, 0x01, 0x02, 0x41, - 0x00, 0x9d, 0xdb, 0x39, 0x59, 0x09, 0xe4, 0x30, - 0xa0, 0x24, 0xf5, 0xdb, 0x2f, 0xf0, 0x2f, 0xf1, - 0x75, 0x74, 0x0d, 0x5e, 0xb5, 0x11, 0x73, 0xb0, - 0x0a, 0xaa, 0x86, 0x4c, 0x0d, 0xff, 0x7e, 0x1d, - 0xb4, 0x14, 0xd4, 0x09, 0x91, 0x33, 0x5a, 0xfd, - 0xa0, 0x58, 0x80, 0x9b, 0xbe, 0x78, 0x2e, 0x69, - 0x82, 0x15, 0x7c, 0x72, 0xf0, 0x7b, 0x18, 0x39, - 0xff, 0x6e, 0xeb, 0xc6, 0x86, 0xf5, 0xb4, 0xc7, - 0x6f, 0x02, 0x41, 0x00, 0x8d, 0x1a, 0x37, 0x0f, - 0x76, 0xc4, 0x82, 0xfa, 0x5c, 0xc3, 0x79, 0x35, - 0x3e, 0x70, 0x8a, 0xbf, 0x27, 0x49, 0xb0, 0x99, - 0x63, 0xcb, 0x77, 0x5f, 0xa8, 0x82, 0x65, 0xf6, - 0x03, 0x52, 0x51, 0xf1, 0xae, 0x2e, 0x05, 0xb3, - 0xc6, 0xa4, 0x92, 0xd1, 0xce, 0x6c, 0x72, 0xfb, - 0x21, 0xb3, 0x02, 0x87, 0xe4, 0xfd, 0x61, 0xca, - 0x00, 0x42, 0x19, 0xf0, 0xda, 0x5a, 0x53, 0xe3, - 0xb1, 0xc5, 0x15, 0xf3 -}; +const uint8_t kTestPrivateKeyInfo[] = { + 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61, + 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, 0x55, 0x84, 0xd5, 0x3a, + 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4, + 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, 0xb0, 0x40, 0x53, 0x3a, + 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f, + 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, 0xde, 0x4e, 0xb9, 0x57, + 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff, + 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, 0x84, 0x32, 0x33, 0xf3, + 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5, + 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, 0x53, 0x56, 0xa6, 0x83, + 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x03, 0x61, 0x89, 0x37, 0xcb, 0xf2, 0x98, + 0xa0, 0xce, 0xb4, 0xcb, 0x16, 0x13, 0xf0, 0xe6, 0xaf, 0x5c, 0xc5, 0xa7, + 0x69, 0x71, 0xca, 0xba, 0x8d, 0xe0, 0x4d, 0xdd, 0xed, 0xb8, 0x48, 0x8b, + 0x16, 0x93, 0x36, 0x95, 0xc2, 0x91, 0x40, 0x65, 0x17, 0xbd, 0x7f, 0xd6, + 0xad, 0x9e, 0x30, 0x28, 0x46, 0xe4, 0x3e, 0xcc, 0x43, 0x78, 0xf9, 0xfe, + 0x1f, 0x33, 0x23, 0x1e, 0x31, 0x12, 0x9d, 0x3c, 0xa7, 0x08, 0x82, 0x7b, + 0x7d, 0x25, 0x4e, 0x5e, 0x19, 0xa8, 0x9b, 0xed, 0x86, 0xb2, 0xcb, 0x3c, + 0xfe, 0x4e, 0xa1, 0xfa, 0x62, 0x87, 0x3a, 0x17, 0xf7, 0x60, 0xec, 0x38, + 0x29, 0xe8, 0x4f, 0x34, 0x9f, 0x76, 0x9d, 0xee, 0xa3, 0xf6, 0x85, 0x6b, + 0x84, 0x43, 0xc9, 0x1e, 0x01, 0xff, 0xfd, 0xd0, 0x29, 0x4c, 0xfa, 0x8e, + 0x57, 0x0c, 0xc0, 0x71, 0xa5, 0xbb, 0x88, 0x46, 0x29, 0x5c, 0xc0, 0x4f, + 0x01, 0x02, 0x41, 0x00, 0xf5, 0x83, 0xa4, 0x64, 0x4a, 0xf2, 0xdd, 0x8c, + 0x2c, 0xed, 0xa8, 0xd5, 0x60, 0x5a, 0xe4, 0xc7, 0xcc, 0x61, 0xcd, 0x38, + 0x42, 0x20, 0xd3, 0x82, 0x18, 0xf2, 0x35, 0x00, 0x72, 0x2d, 0xf7, 0x89, + 0x80, 0x67, 0xb5, 0x93, 0x05, 0x5f, 0xdd, 0x42, 0xba, 0x16, 0x1a, 0xea, + 0x15, 0xc6, 0xf0, 0xb8, 0x8c, 0xbc, 0xbf, 0x54, 0x9e, 0xf1, 0xc1, 0xb2, + 0xb3, 0x8b, 0xb6, 0x26, 0x02, 0x30, 0xc4, 0x81, 0x02, 0x41, 0x00, 0xc0, + 0x60, 0x62, 0x80, 0xe1, 0x22, 0x78, 0xf6, 0x9d, 0x83, 0x18, 0xeb, 0x72, + 0x45, 0xd7, 0xc8, 0x01, 0x7f, 0xa9, 0xca, 0x8f, 0x7d, 0xd6, 0xb8, 0x31, + 0x2b, 0x84, 0x7f, 0x62, 0xd9, 0xa9, 0x22, 0x17, 0x7d, 0x06, 0x35, 0x6c, + 0xf3, 0xc1, 0x94, 0x17, 0x85, 0x5a, 0xaf, 0x9c, 0x5c, 0x09, 0x3c, 0xcf, + 0x2f, 0x44, 0x9d, 0xb6, 0x52, 0x68, 0x5f, 0xf9, 0x59, 0xc8, 0x84, 0x2b, + 0x39, 0x22, 0x8f, 0x02, 0x41, 0x00, 0xb2, 0x04, 0xe2, 0x0e, 0x56, 0xca, + 0x03, 0x1a, 0xc0, 0xf9, 0x12, 0x92, 0xa5, 0x6b, 0x42, 0xb8, 0x1c, 0xda, + 0x4d, 0x93, 0x9d, 0x5f, 0x6f, 0xfd, 0xc5, 0x58, 0xda, 0x55, 0x98, 0x74, + 0xfc, 0x28, 0x17, 0x93, 0x1b, 0x75, 0x9f, 0x50, 0x03, 0x7f, 0x7e, 0xae, + 0xc8, 0x95, 0x33, 0x75, 0x2c, 0xd6, 0xa4, 0x35, 0xb8, 0x06, 0x03, 0xba, + 0x08, 0x59, 0x2b, 0x17, 0x02, 0xdc, 0x4c, 0x7a, 0x50, 0x01, 0x02, 0x41, + 0x00, 0x9d, 0xdb, 0x39, 0x59, 0x09, 0xe4, 0x30, 0xa0, 0x24, 0xf5, 0xdb, + 0x2f, 0xf0, 0x2f, 0xf1, 0x75, 0x74, 0x0d, 0x5e, 0xb5, 0x11, 0x73, 0xb0, + 0x0a, 0xaa, 0x86, 0x4c, 0x0d, 0xff, 0x7e, 0x1d, 0xb4, 0x14, 0xd4, 0x09, + 0x91, 0x33, 0x5a, 0xfd, 0xa0, 0x58, 0x80, 0x9b, 0xbe, 0x78, 0x2e, 0x69, + 0x82, 0x15, 0x7c, 0x72, 0xf0, 0x7b, 0x18, 0x39, 0xff, 0x6e, 0xeb, 0xc6, + 0x86, 0xf5, 0xb4, 0xc7, 0x6f, 0x02, 0x41, 0x00, 0x8d, 0x1a, 0x37, 0x0f, + 0x76, 0xc4, 0x82, 0xfa, 0x5c, 0xc3, 0x79, 0x35, 0x3e, 0x70, 0x8a, 0xbf, + 0x27, 0x49, 0xb0, 0x99, 0x63, 0xcb, 0x77, 0x5f, 0xa8, 0x82, 0x65, 0xf6, + 0x03, 0x52, 0x51, 0xf1, 0xae, 0x2e, 0x05, 0xb3, 0xc6, 0xa4, 0x92, 0xd1, + 0xce, 0x6c, 0x72, 0xfb, 0x21, 0xb3, 0x02, 0x87, 0xe4, 0xfd, 0x61, 0xca, + 0x00, 0x42, 0x19, 0xf0, 0xda, 0x5a, 0x53, 0xe3, 0xb1, 0xc5, 0x15, 0xf3}; } // namespace // Generate random private keys with two different sizes. Reimport, then // export them again. We should get back the same exact bytes. TEST(RSAPrivateKeyUnitTest, InitRandomTest) { - scoped_ptr<crypto::RSAPrivateKey> keypair1( + std::unique_ptr<crypto::RSAPrivateKey> keypair1( crypto::RSAPrivateKey::Create(1024)); - scoped_ptr<crypto::RSAPrivateKey> keypair2( + std::unique_ptr<crypto::RSAPrivateKey> keypair2( crypto::RSAPrivateKey::Create(2048)); ASSERT_TRUE(keypair1.get()); ASSERT_TRUE(keypair2.get()); - std::vector<uint8> privkey1; - std::vector<uint8> privkey2; - std::vector<uint8> pubkey1; - std::vector<uint8> pubkey2; + std::vector<uint8_t> privkey1; + std::vector<uint8_t> privkey2; + std::vector<uint8_t> pubkey1; + std::vector<uint8_t> pubkey2; ASSERT_TRUE(keypair1->ExportPrivateKey(&privkey1)); ASSERT_TRUE(keypair2->ExportPrivateKey(&privkey2)); ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1)); ASSERT_TRUE(keypair2->ExportPublicKey(&pubkey2)); - scoped_ptr<crypto::RSAPrivateKey> keypair3( + std::unique_ptr<crypto::RSAPrivateKey> keypair3( crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey1)); - scoped_ptr<crypto::RSAPrivateKey> keypair4( + std::unique_ptr<crypto::RSAPrivateKey> keypair4( crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey2)); ASSERT_TRUE(keypair3.get()); ASSERT_TRUE(keypair4.get()); - std::vector<uint8> privkey3; - std::vector<uint8> privkey4; + std::vector<uint8_t> privkey3; + std::vector<uint8_t> privkey4; ASSERT_TRUE(keypair3->ExportPrivateKey(&privkey3)); ASSERT_TRUE(keypair4->ExportPrivateKey(&privkey4)); ASSERT_EQ(privkey1.size(), privkey3.size()); ASSERT_EQ(privkey2.size(), privkey4.size()); - ASSERT_TRUE(0 == memcmp(&privkey1.front(), &privkey3.front(), - privkey1.size())); - ASSERT_TRUE(0 == memcmp(&privkey2.front(), &privkey4.front(), - privkey2.size())); + ASSERT_EQ(0, SbMemoryCompare(&privkey1.front(), &privkey3.front(), + privkey1.size())); + ASSERT_EQ(0, SbMemoryCompare(&privkey2.front(), &privkey4.front(), + privkey2.size())); } // Test Copy() method. TEST(RSAPrivateKeyUnitTest, CopyTest) { - std::vector<uint8> input( - kTestPrivateKeyInfo, kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); + std::vector<uint8_t> input(kTestPrivateKeyInfo, + kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); - scoped_ptr<crypto::RSAPrivateKey> key( + std::unique_ptr<crypto::RSAPrivateKey> key( crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); - scoped_ptr<crypto::RSAPrivateKey> key_copy(key->Copy()); + std::unique_ptr<crypto::RSAPrivateKey> key_copy(key->Copy()); ASSERT_TRUE(key_copy.get()); - std::vector<uint8> privkey_copy; + std::vector<uint8_t> privkey_copy; ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy)); ASSERT_EQ(input, privkey_copy); } +// Test that CreateFromPrivateKeyInfo fails if there is extra data after the RSA +// key. +TEST(RSAPrivateKeyUnitTest, ExtraData) { + std::vector<uint8_t> input(kTestPrivateKeyInfo, + kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); + input.push_back(0); + + std::unique_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); + + // Import should fail. + EXPECT_FALSE(key); +} + +TEST(RSAPrivateKeyUnitTest, NotRsaKey) { + // Defines a valid P-256 private key. + const uint8_t kTestEcPrivateKeyInfo[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, + 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x03, 0x01, 0x07, 0x04, 0x6D, 0x30, 0x6B, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x1F, 0xE3, 0x39, 0x50, 0xC5, 0xF4, 0x61, 0x12, 0x4A, 0xE9, 0x92, 0xC2, + 0xBD, 0xFD, 0xF1, 0xC7, 0x3B, 0x16, 0x15, 0xF5, 0x71, 0xBD, 0x56, 0x7E, + 0x60, 0xD1, 0x9A, 0xA1, 0xF4, 0x8C, 0xDF, 0x42, 0xA1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x7C, 0x11, 0x0C, 0x66, 0xDC, 0xFD, 0xA8, 0x07, 0xF6, 0xE6, + 0x9E, 0x45, 0xDD, 0xB3, 0xC7, 0x4F, 0x69, 0xA1, 0x48, 0x4D, 0x20, 0x3E, + 0x8D, 0xC5, 0xAD, 0xA8, 0xE9, 0xA9, 0xDD, 0x7C, 0xB3, 0xC7, 0x0D, 0xF4, + 0x48, 0x98, 0x6E, 0x51, 0xBD, 0xE5, 0xD1, 0x57, 0x6F, 0x99, 0x90, 0x1F, + 0x9C, 0x2C, 0x6A, 0x80, 0x6A, 0x47, 0xFD, 0x90, 0x76, 0x43, 0xA7, 0x2B, + 0x83, 0x55, 0x97, 0xEF, 0xC8, 0xC6}; + + std::vector<uint8_t> input( + kTestEcPrivateKeyInfo, + kTestEcPrivateKeyInfo + sizeof(kTestEcPrivateKeyInfo)); + + std::unique_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); + + // Import should fail as the given PKCS8 bytes were for an EC key not RSA key. + EXPECT_FALSE(key); +} // Verify that generated public keys look good. This test data was generated // with the openssl command line tool. TEST(RSAPrivateKeyUnitTest, PublicKeyTest) { - const uint8 expected_public_key_info[] = { - 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, - 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, - 0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, - 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61, - 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, - 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, - 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4, - 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, - 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, - 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f, - 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, - 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, - 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff, - 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, - 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, - 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5, - 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, - 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, - 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01, - 0x00, 0x01 - }; + const uint8_t expected_public_key_info[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, + 0x0c, 0xdc, 0x51, 0x61, 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, + 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, + 0x13, 0x3f, 0x8d, 0xf4, 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, + 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, + 0xda, 0x8a, 0x31, 0x4f, 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, + 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, + 0x4e, 0xb6, 0x47, 0xff, 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, + 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, + 0x6f, 0x13, 0x8d, 0xc5, 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, + 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, + 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01}; - std::vector<uint8> input( - kTestPrivateKeyInfo, kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); + std::vector<uint8_t> input(kTestPrivateKeyInfo, + kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); - scoped_ptr<crypto::RSAPrivateKey> key( + std::unique_ptr<crypto::RSAPrivateKey> key( crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); ASSERT_TRUE(key.get()); - std::vector<uint8> output; + std::vector<uint8_t> output; ASSERT_TRUE(key->ExportPublicKey(&output)); - ASSERT_TRUE( - memcmp(expected_public_key_info, &output.front(), output.size()) == 0); + ASSERT_EQ(0, SbMemoryCompare(expected_public_key_info, &output.front(), + output.size())); } // These two test keys each contain an integer that has 0x00 for its most @@ -207,199 +218,167 @@ // // This test case verifies these two failures modes don't occur. TEST(RSAPrivateKeyUnitTest, ShortIntegers) { - const uint8 short_integer_with_high_bit[] = { - 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x00, 0x30, - 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, - 0x02, 0x61, 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, - 0x00, 0x02, 0x81, 0x81, 0x00, 0x92, 0x59, 0x32, - 0x7d, 0x8e, 0xaf, 0x2e, 0xd5, 0xb2, 0x5c, 0x67, - 0xc8, 0x7d, 0x48, 0xb7, 0x84, 0x12, 0xd0, 0x76, - 0xda, 0xe1, 0xa3, 0x1e, 0x40, 0x01, 0x14, 0x5c, - 0xef, 0x26, 0x6e, 0x28, 0xa2, 0xf7, 0xa5, 0xb4, - 0x02, 0x37, 0xd0, 0x53, 0x10, 0xcb, 0x7c, 0x6a, - 0xf4, 0x53, 0x9f, 0xb8, 0xe0, 0x83, 0x93, 0xd1, - 0x19, 0xd8, 0x28, 0xd1, 0xd1, 0xd8, 0x87, 0x8f, - 0x92, 0xfd, 0x73, 0xc0, 0x4d, 0x3e, 0x07, 0x22, - 0x1f, 0xc1, 0x20, 0xb0, 0x70, 0xb2, 0x3b, 0xea, - 0xb1, 0xe5, 0x0a, 0xfd, 0x56, 0x49, 0x5e, 0x39, - 0x90, 0x91, 0xce, 0x04, 0x83, 0x29, 0xaa, 0xfd, - 0x12, 0xa4, 0x42, 0x26, 0x6c, 0x6e, 0x79, 0x70, - 0x77, 0x03, 0xb2, 0x07, 0x01, 0x3d, 0x85, 0x81, - 0x95, 0x9e, 0xda, 0x5a, 0xa3, 0xf4, 0x2d, 0x38, - 0x04, 0x58, 0xf5, 0x6b, 0xc9, 0xf1, 0xb5, 0x65, - 0xfe, 0x66, 0x0d, 0xa2, 0xd5, 0x02, 0x03, 0x01, - 0x00, 0x01, 0x02, 0x81, 0x80, 0x5e, 0x01, 0x5f, - 0xb6, 0x59, 0x1d, 0xdc, 0x36, 0xb6, 0x60, 0x36, - 0xe6, 0x08, 0xdb, 0xd9, 0xcd, 0xc3, 0x8c, 0x16, - 0x9c, 0x98, 0x8d, 0x7f, 0xd3, 0xdb, 0x1d, 0xaa, - 0x68, 0x8f, 0xc5, 0xf8, 0xe2, 0x5d, 0xb3, 0x19, - 0xc2, 0xc6, 0xf9, 0x51, 0x32, 0x1b, 0x93, 0x6a, - 0xdc, 0x50, 0x8e, 0xeb, 0x61, 0x84, 0x03, 0x42, - 0x30, 0x98, 0xb1, 0xf7, 0xbd, 0x14, 0x9a, 0x57, - 0x36, 0x33, 0x09, 0xd4, 0x3e, 0x90, 0xda, 0xef, - 0x09, 0x6e, 0xef, 0x49, 0xb6, 0x60, 0x68, 0x5e, - 0x54, 0x17, 0x25, 0x5b, 0x37, 0xe3, 0x35, 0x63, - 0x5b, 0x60, 0x3c, 0xbd, 0x50, 0xdf, 0x46, 0x43, - 0x08, 0xa4, 0x71, 0x21, 0xf1, 0x30, 0x71, 0xdc, - 0xda, 0xd7, 0x6f, 0xd2, 0x18, 0xbd, 0x39, 0xf1, - 0xe1, 0xbe, 0xa8, 0x8d, 0x62, 0xdf, 0xa2, 0x3e, - 0xb6, 0x15, 0x26, 0xb6, 0x57, 0xbd, 0x63, 0xdb, - 0xc1, 0x91, 0xec, 0xb8, 0x01, 0x02, 0x41, 0x00, - 0xc6, 0x1a, 0x06, 0x48, 0xf2, 0x12, 0x1c, 0x9f, - 0x74, 0x20, 0x5c, 0x85, 0xa2, 0xda, 0xe5, 0x62, - 0x96, 0x8d, 0x22, 0x7b, 0x78, 0x73, 0xea, 0xbb, - 0x9f, 0x59, 0x42, 0x13, 0x15, 0xc8, 0x11, 0x50, - 0x6c, 0x55, 0xf6, 0xdf, 0x8b, 0xfe, 0xc7, 0xdd, - 0xa8, 0xca, 0x54, 0x41, 0xe8, 0xce, 0xbe, 0x7d, - 0xbd, 0xe2, 0x13, 0x4b, 0x5b, 0x61, 0xeb, 0x69, - 0x6c, 0xb1, 0x9b, 0x28, 0x68, 0x5b, 0xd6, 0x01, - 0x02, 0x41, 0x00, 0xbd, 0x1e, 0xfe, 0x51, 0x99, - 0xb6, 0xe3, 0x84, 0xfe, 0xf1, 0x9e, 0xfd, 0x9c, - 0xe7, 0x86, 0x43, 0x68, 0x7f, 0x2f, 0x6a, 0x2a, - 0x4c, 0xae, 0xa6, 0x41, 0x1c, 0xf0, 0x10, 0x37, - 0x54, 0x23, 0xba, 0x05, 0x0d, 0x18, 0x27, 0x8d, - 0xb8, 0xe4, 0x8f, 0xf2, 0x25, 0x73, 0x8a, 0xd7, - 0x05, 0x98, 0x6b, 0x3d, 0x55, 0xb7, 0x6f, 0x7c, - 0xec, 0x77, 0x61, 0x54, 0x7b, 0xb6, 0x6b, 0x31, - 0xec, 0x94, 0xd5, 0x02, 0x41, 0x00, 0x90, 0xa2, - 0xa5, 0x9e, 0x12, 0xa7, 0x68, 0xa0, 0x7e, 0xdf, - 0xb5, 0xcd, 0x98, 0x26, 0xab, 0xbd, 0xbc, 0x5f, - 0xd5, 0x22, 0x42, 0xc2, 0x97, 0x4a, 0x5f, 0x40, - 0x82, 0xfe, 0x7e, 0x33, 0xb1, 0x78, 0x7f, 0x70, - 0x90, 0x2b, 0x8d, 0x01, 0xfb, 0x18, 0xfa, 0x48, - 0xa7, 0x15, 0xec, 0x0d, 0x2e, 0x85, 0x8d, 0xe2, - 0x86, 0xe5, 0xc9, 0x15, 0x88, 0x14, 0x53, 0xd8, - 0xa4, 0x88, 0xef, 0x10, 0xc6, 0x01, 0x02, 0x41, - 0x00, 0xba, 0xe4, 0xaf, 0x14, 0xfa, 0xdf, 0xf6, - 0xd5, 0xce, 0x8f, 0xfe, 0xbb, 0xc8, 0x5c, 0x30, - 0x9d, 0xda, 0xdd, 0x9d, 0x80, 0xc0, 0x0e, 0x89, - 0xa5, 0xb8, 0xc1, 0x1d, 0x28, 0x19, 0x55, 0x67, - 0xfd, 0x03, 0xd2, 0xdd, 0xe4, 0xf0, 0xb4, 0x20, - 0x03, 0x74, 0x9b, 0xb8, 0x24, 0x23, 0xbb, 0xde, - 0xd5, 0x53, 0x86, 0xaa, 0xc1, 0x5d, 0x65, 0xdd, - 0xcf, 0xec, 0x8a, 0x59, 0x4a, 0x73, 0xca, 0xc5, - 0x85, 0x02, 0x40, 0x00, 0xc4, 0x5e, 0x8d, 0xa4, - 0xea, 0xbb, 0x6a, 0x9b, 0xe6, 0x3a, 0x4d, 0xc1, - 0xdb, 0xe5, 0x52, 0x38, 0xf9, 0x59, 0x91, 0x2d, - 0x90, 0x82, 0xe3, 0x31, 0x1b, 0x48, 0xb7, 0x42, - 0xfa, 0x1d, 0x83, 0xd5, 0x3d, 0x02, 0xc2, 0x12, - 0x71, 0x10, 0x3a, 0xbd, 0x92, 0x8f, 0x9b, 0xa2, - 0x6b, 0x2d, 0x21, 0xa4, 0x65, 0xe9, 0xfa, 0x8c, - 0x30, 0x2a, 0x89, 0xce, 0xd0, 0xa7, 0x67, 0xd8, - 0x45, 0x84, 0xb0 - }; + const uint8_t short_integer_with_high_bit[] = { + 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x61, 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0x92, 0x59, 0x32, 0x7d, 0x8e, 0xaf, 0x2e, 0xd5, 0xb2, 0x5c, 0x67, + 0xc8, 0x7d, 0x48, 0xb7, 0x84, 0x12, 0xd0, 0x76, 0xda, 0xe1, 0xa3, 0x1e, + 0x40, 0x01, 0x14, 0x5c, 0xef, 0x26, 0x6e, 0x28, 0xa2, 0xf7, 0xa5, 0xb4, + 0x02, 0x37, 0xd0, 0x53, 0x10, 0xcb, 0x7c, 0x6a, 0xf4, 0x53, 0x9f, 0xb8, + 0xe0, 0x83, 0x93, 0xd1, 0x19, 0xd8, 0x28, 0xd1, 0xd1, 0xd8, 0x87, 0x8f, + 0x92, 0xfd, 0x73, 0xc0, 0x4d, 0x3e, 0x07, 0x22, 0x1f, 0xc1, 0x20, 0xb0, + 0x70, 0xb2, 0x3b, 0xea, 0xb1, 0xe5, 0x0a, 0xfd, 0x56, 0x49, 0x5e, 0x39, + 0x90, 0x91, 0xce, 0x04, 0x83, 0x29, 0xaa, 0xfd, 0x12, 0xa4, 0x42, 0x26, + 0x6c, 0x6e, 0x79, 0x70, 0x77, 0x03, 0xb2, 0x07, 0x01, 0x3d, 0x85, 0x81, + 0x95, 0x9e, 0xda, 0x5a, 0xa3, 0xf4, 0x2d, 0x38, 0x04, 0x58, 0xf5, 0x6b, + 0xc9, 0xf1, 0xb5, 0x65, 0xfe, 0x66, 0x0d, 0xa2, 0xd5, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x5e, 0x01, 0x5f, 0xb6, 0x59, 0x1d, 0xdc, + 0x36, 0xb6, 0x60, 0x36, 0xe6, 0x08, 0xdb, 0xd9, 0xcd, 0xc3, 0x8c, 0x16, + 0x9c, 0x98, 0x8d, 0x7f, 0xd3, 0xdb, 0x1d, 0xaa, 0x68, 0x8f, 0xc5, 0xf8, + 0xe2, 0x5d, 0xb3, 0x19, 0xc2, 0xc6, 0xf9, 0x51, 0x32, 0x1b, 0x93, 0x6a, + 0xdc, 0x50, 0x8e, 0xeb, 0x61, 0x84, 0x03, 0x42, 0x30, 0x98, 0xb1, 0xf7, + 0xbd, 0x14, 0x9a, 0x57, 0x36, 0x33, 0x09, 0xd4, 0x3e, 0x90, 0xda, 0xef, + 0x09, 0x6e, 0xef, 0x49, 0xb6, 0x60, 0x68, 0x5e, 0x54, 0x17, 0x25, 0x5b, + 0x37, 0xe3, 0x35, 0x63, 0x5b, 0x60, 0x3c, 0xbd, 0x50, 0xdf, 0x46, 0x43, + 0x08, 0xa4, 0x71, 0x21, 0xf1, 0x30, 0x71, 0xdc, 0xda, 0xd7, 0x6f, 0xd2, + 0x18, 0xbd, 0x39, 0xf1, 0xe1, 0xbe, 0xa8, 0x8d, 0x62, 0xdf, 0xa2, 0x3e, + 0xb6, 0x15, 0x26, 0xb6, 0x57, 0xbd, 0x63, 0xdb, 0xc1, 0x91, 0xec, 0xb8, + 0x01, 0x02, 0x41, 0x00, 0xc6, 0x1a, 0x06, 0x48, 0xf2, 0x12, 0x1c, 0x9f, + 0x74, 0x20, 0x5c, 0x85, 0xa2, 0xda, 0xe5, 0x62, 0x96, 0x8d, 0x22, 0x7b, + 0x78, 0x73, 0xea, 0xbb, 0x9f, 0x59, 0x42, 0x13, 0x15, 0xc8, 0x11, 0x50, + 0x6c, 0x55, 0xf6, 0xdf, 0x8b, 0xfe, 0xc7, 0xdd, 0xa8, 0xca, 0x54, 0x41, + 0xe8, 0xce, 0xbe, 0x7d, 0xbd, 0xe2, 0x13, 0x4b, 0x5b, 0x61, 0xeb, 0x69, + 0x6c, 0xb1, 0x9b, 0x28, 0x68, 0x5b, 0xd6, 0x01, 0x02, 0x41, 0x00, 0xbd, + 0x1e, 0xfe, 0x51, 0x99, 0xb6, 0xe3, 0x84, 0xfe, 0xf1, 0x9e, 0xfd, 0x9c, + 0xe7, 0x86, 0x43, 0x68, 0x7f, 0x2f, 0x6a, 0x2a, 0x4c, 0xae, 0xa6, 0x41, + 0x1c, 0xf0, 0x10, 0x37, 0x54, 0x23, 0xba, 0x05, 0x0d, 0x18, 0x27, 0x8d, + 0xb8, 0xe4, 0x8f, 0xf2, 0x25, 0x73, 0x8a, 0xd7, 0x05, 0x98, 0x6b, 0x3d, + 0x55, 0xb7, 0x6f, 0x7c, 0xec, 0x77, 0x61, 0x54, 0x7b, 0xb6, 0x6b, 0x31, + 0xec, 0x94, 0xd5, 0x02, 0x41, 0x00, 0x90, 0xa2, 0xa5, 0x9e, 0x12, 0xa7, + 0x68, 0xa0, 0x7e, 0xdf, 0xb5, 0xcd, 0x98, 0x26, 0xab, 0xbd, 0xbc, 0x5f, + 0xd5, 0x22, 0x42, 0xc2, 0x97, 0x4a, 0x5f, 0x40, 0x82, 0xfe, 0x7e, 0x33, + 0xb1, 0x78, 0x7f, 0x70, 0x90, 0x2b, 0x8d, 0x01, 0xfb, 0x18, 0xfa, 0x48, + 0xa7, 0x15, 0xec, 0x0d, 0x2e, 0x85, 0x8d, 0xe2, 0x86, 0xe5, 0xc9, 0x15, + 0x88, 0x14, 0x53, 0xd8, 0xa4, 0x88, 0xef, 0x10, 0xc6, 0x01, 0x02, 0x41, + 0x00, 0xba, 0xe4, 0xaf, 0x14, 0xfa, 0xdf, 0xf6, 0xd5, 0xce, 0x8f, 0xfe, + 0xbb, 0xc8, 0x5c, 0x30, 0x9d, 0xda, 0xdd, 0x9d, 0x80, 0xc0, 0x0e, 0x89, + 0xa5, 0xb8, 0xc1, 0x1d, 0x28, 0x19, 0x55, 0x67, 0xfd, 0x03, 0xd2, 0xdd, + 0xe4, 0xf0, 0xb4, 0x20, 0x03, 0x74, 0x9b, 0xb8, 0x24, 0x23, 0xbb, 0xde, + 0xd5, 0x53, 0x86, 0xaa, 0xc1, 0x5d, 0x65, 0xdd, 0xcf, 0xec, 0x8a, 0x59, + 0x4a, 0x73, 0xca, 0xc5, 0x85, 0x02, 0x40, 0x00, 0xc4, 0x5e, 0x8d, 0xa4, + 0xea, 0xbb, 0x6a, 0x9b, 0xe6, 0x3a, 0x4d, 0xc1, 0xdb, 0xe5, 0x52, 0x38, + 0xf9, 0x59, 0x91, 0x2d, 0x90, 0x82, 0xe3, 0x31, 0x1b, 0x48, 0xb7, 0x42, + 0xfa, 0x1d, 0x83, 0xd5, 0x3d, 0x02, 0xc2, 0x12, 0x71, 0x10, 0x3a, 0xbd, + 0x92, 0x8f, 0x9b, 0xa2, 0x6b, 0x2d, 0x21, 0xa4, 0x65, 0xe9, 0xfa, 0x8c, + 0x30, 0x2a, 0x89, 0xce, 0xd0, 0xa7, 0x67, 0xd8, 0x45, 0x84, 0xb0}; - const uint8 short_integer_without_high_bit[] = { - 0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, - 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, - 0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, - 0x00, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x9e, 0x8d, - 0xc4, 0x6d, 0x38, 0xe8, 0x0e, 0x9f, 0x84, 0x03, - 0x40, 0x8e, 0x81, 0x2e, 0x56, 0x67, 0x78, 0x11, - 0x85, 0x27, 0x81, 0x52, 0xf2, 0x1b, 0x3e, 0x5b, - 0xf8, 0xab, 0xfc, 0xaf, 0xca, 0x5c, 0x26, 0xd5, - 0xfa, 0xd4, 0x55, 0x50, 0x38, 0xb9, 0x9d, 0x89, - 0x92, 0x7e, 0x34, 0xcf, 0x37, 0x82, 0x48, 0x2d, - 0xaa, 0xc4, 0x6a, 0x0e, 0x93, 0xea, 0xad, 0x8a, - 0x33, 0xf0, 0x42, 0x23, 0xe0, 0x4c, 0x98, 0xbf, - 0x01, 0x00, 0x1b, 0xfe, 0x06, 0x15, 0xc6, 0xe3, - 0x80, 0x79, 0x6d, 0xfe, 0x48, 0xcd, 0x40, 0xbb, - 0xf9, 0x58, 0xe6, 0xbf, 0xd5, 0x4c, 0x29, 0x48, - 0x53, 0x78, 0x06, 0x03, 0x0d, 0x59, 0xf5, 0x20, - 0xe0, 0xe6, 0x8c, 0xb2, 0xf5, 0xd8, 0x61, 0x52, - 0x7e, 0x40, 0x83, 0xd7, 0x69, 0xae, 0xd7, 0x75, - 0x02, 0x2d, 0x49, 0xd5, 0x15, 0x5b, 0xf1, 0xd9, - 0x4d, 0x60, 0x7d, 0x62, 0xa5, 0x02, 0x03, 0x01, - 0x00, 0x01, 0x02, 0x7f, 0x6d, 0x45, 0x23, 0xeb, - 0x95, 0x17, 0x34, 0x88, 0xf6, 0x91, 0xc7, 0x3f, - 0x48, 0x5a, 0xe0, 0x87, 0x63, 0x44, 0xae, 0x84, - 0xb2, 0x8c, 0x8a, 0xc8, 0xb2, 0x6f, 0x22, 0xf0, - 0xc5, 0x21, 0x61, 0x10, 0xa8, 0x69, 0x09, 0x1e, - 0x13, 0x7d, 0x94, 0x52, 0x1b, 0x5c, 0xe4, 0x7b, - 0xf0, 0x03, 0x8f, 0xbc, 0x72, 0x09, 0xdf, 0x78, - 0x84, 0x3e, 0xb9, 0xe5, 0xe6, 0x31, 0x0a, 0x01, - 0xf9, 0x32, 0xf8, 0xd6, 0x57, 0xa3, 0x87, 0xe6, - 0xf5, 0x98, 0xbc, 0x8e, 0x41, 0xb9, 0x50, 0x17, - 0x7b, 0xd3, 0x97, 0x5a, 0x44, 0x3a, 0xee, 0xff, - 0x6b, 0xb3, 0x3a, 0x52, 0xe7, 0xa4, 0x96, 0x9a, - 0xf6, 0x83, 0xc8, 0x97, 0x1c, 0x63, 0xa1, 0xd6, - 0xb3, 0xa8, 0xb2, 0xc7, 0x73, 0x25, 0x0f, 0x58, - 0x36, 0xb9, 0x7a, 0x47, 0xa7, 0x4d, 0x30, 0xfe, - 0x4d, 0x74, 0x56, 0xe8, 0xfb, 0xd6, 0x50, 0xe5, - 0xe0, 0x28, 0x15, 0x02, 0x41, 0x00, 0xeb, 0x15, - 0x62, 0xb6, 0x37, 0x41, 0x7c, 0xc5, 0x00, 0x22, - 0x2c, 0x5a, 0x5e, 0xe4, 0xb2, 0x11, 0x87, 0x89, - 0xad, 0xf4, 0x57, 0x68, 0x90, 0xb7, 0x9f, 0xe2, - 0x79, 0x20, 0x6b, 0x98, 0x00, 0x0d, 0x3a, 0x3b, - 0xc1, 0xcd, 0x36, 0xf9, 0x27, 0xda, 0x40, 0x36, - 0x1d, 0xb8, 0x5c, 0x96, 0xeb, 0x04, 0x08, 0xe1, - 0x3f, 0xfa, 0x94, 0x8b, 0x0f, 0xa0, 0xff, 0xc1, - 0x51, 0xea, 0x90, 0xad, 0x15, 0xc7, 0x02, 0x41, - 0x00, 0xd5, 0x06, 0x45, 0xd7, 0x55, 0x63, 0x1a, - 0xf0, 0x89, 0x81, 0xae, 0x87, 0x23, 0xa2, 0x39, - 0xfe, 0x3d, 0x82, 0xc7, 0xcb, 0x15, 0xb9, 0xe3, - 0xe2, 0x5b, 0xc6, 0xd2, 0x55, 0xdd, 0xab, 0x55, - 0x29, 0x7c, 0xda, 0x0e, 0x1c, 0x09, 0xfc, 0x73, - 0x0d, 0x01, 0xed, 0x6d, 0x2f, 0x05, 0xd0, 0xd5, - 0x1d, 0xce, 0x18, 0x7f, 0xb0, 0xc8, 0x47, 0x77, - 0xd2, 0xa9, 0x9e, 0xfc, 0x39, 0x4b, 0x3d, 0x94, - 0x33, 0x02, 0x41, 0x00, 0x8f, 0x94, 0x09, 0x2d, - 0x17, 0x44, 0x75, 0x0a, 0xf1, 0x10, 0xee, 0x1b, - 0xe7, 0xd7, 0x2f, 0xf6, 0xca, 0xdc, 0x49, 0x15, - 0x72, 0x09, 0x58, 0x51, 0xfe, 0x61, 0xd8, 0xee, - 0xf7, 0x27, 0xe7, 0xe8, 0x2c, 0x47, 0xf1, 0x0f, - 0x00, 0x63, 0x5e, 0x76, 0xcb, 0x3f, 0x02, 0x19, - 0xe6, 0xda, 0xfa, 0x01, 0x05, 0xd7, 0x65, 0x37, - 0x0b, 0x60, 0x7f, 0x94, 0x2a, 0x80, 0x8d, 0x22, - 0x81, 0x68, 0x65, 0x63, 0x02, 0x41, 0x00, 0xc2, - 0xd4, 0x18, 0xde, 0x47, 0x9e, 0xfb, 0x8d, 0x91, - 0x05, 0xc5, 0x3c, 0x9d, 0xcf, 0x8a, 0x60, 0xc7, - 0x9b, 0x2b, 0xe5, 0xc6, 0xba, 0x1b, 0xfc, 0xf3, - 0xd9, 0x54, 0x97, 0xe9, 0xc4, 0x00, 0x80, 0x90, - 0x4a, 0xd2, 0x6a, 0xbc, 0x8b, 0x62, 0x22, 0x3c, - 0x68, 0x0c, 0xda, 0xdb, 0xe3, 0xd2, 0x76, 0x8e, - 0xff, 0x03, 0x12, 0x09, 0x2a, 0xac, 0x21, 0x44, - 0xb7, 0x3e, 0x91, 0x9c, 0x09, 0xf6, 0xd7, 0x02, - 0x41, 0x00, 0xc0, 0xa1, 0xbb, 0x70, 0xdc, 0xf8, - 0xeb, 0x17, 0x61, 0xd4, 0x8c, 0x7c, 0x3b, 0x82, - 0x91, 0x58, 0xff, 0xf9, 0x19, 0xac, 0x3a, 0x73, - 0xa7, 0x20, 0xe5, 0x22, 0x02, 0xc4, 0xf6, 0xb9, - 0xb9, 0x43, 0x53, 0x35, 0x88, 0xe1, 0x05, 0xb6, - 0x43, 0x9b, 0x39, 0xc8, 0x04, 0x4d, 0x2b, 0x01, - 0xf7, 0xe6, 0x1b, 0x8d, 0x7e, 0x89, 0xe3, 0x43, - 0xd4, 0xf3, 0xab, 0x28, 0xd4, 0x5a, 0x1f, 0x20, - 0xea, 0xbe - }; + const uint8_t short_integer_without_high_bit[] = { + 0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0xc3, 0x9e, 0x8d, 0xc4, 0x6d, 0x38, 0xe8, 0x0e, 0x9f, 0x84, 0x03, + 0x40, 0x8e, 0x81, 0x2e, 0x56, 0x67, 0x78, 0x11, 0x85, 0x27, 0x81, 0x52, + 0xf2, 0x1b, 0x3e, 0x5b, 0xf8, 0xab, 0xfc, 0xaf, 0xca, 0x5c, 0x26, 0xd5, + 0xfa, 0xd4, 0x55, 0x50, 0x38, 0xb9, 0x9d, 0x89, 0x92, 0x7e, 0x34, 0xcf, + 0x37, 0x82, 0x48, 0x2d, 0xaa, 0xc4, 0x6a, 0x0e, 0x93, 0xea, 0xad, 0x8a, + 0x33, 0xf0, 0x42, 0x23, 0xe0, 0x4c, 0x98, 0xbf, 0x01, 0x00, 0x1b, 0xfe, + 0x06, 0x15, 0xc6, 0xe3, 0x80, 0x79, 0x6d, 0xfe, 0x48, 0xcd, 0x40, 0xbb, + 0xf9, 0x58, 0xe6, 0xbf, 0xd5, 0x4c, 0x29, 0x48, 0x53, 0x78, 0x06, 0x03, + 0x0d, 0x59, 0xf5, 0x20, 0xe0, 0xe6, 0x8c, 0xb2, 0xf5, 0xd8, 0x61, 0x52, + 0x7e, 0x40, 0x83, 0xd7, 0x69, 0xae, 0xd7, 0x75, 0x02, 0x2d, 0x49, 0xd5, + 0x15, 0x5b, 0xf1, 0xd9, 0x4d, 0x60, 0x7d, 0x62, 0xa5, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x7f, 0x6d, 0x45, 0x23, 0xeb, 0x95, 0x17, 0x34, 0x88, + 0xf6, 0x91, 0xc7, 0x3f, 0x48, 0x5a, 0xe0, 0x87, 0x63, 0x44, 0xae, 0x84, + 0xb2, 0x8c, 0x8a, 0xc8, 0xb2, 0x6f, 0x22, 0xf0, 0xc5, 0x21, 0x61, 0x10, + 0xa8, 0x69, 0x09, 0x1e, 0x13, 0x7d, 0x94, 0x52, 0x1b, 0x5c, 0xe4, 0x7b, + 0xf0, 0x03, 0x8f, 0xbc, 0x72, 0x09, 0xdf, 0x78, 0x84, 0x3e, 0xb9, 0xe5, + 0xe6, 0x31, 0x0a, 0x01, 0xf9, 0x32, 0xf8, 0xd6, 0x57, 0xa3, 0x87, 0xe6, + 0xf5, 0x98, 0xbc, 0x8e, 0x41, 0xb9, 0x50, 0x17, 0x7b, 0xd3, 0x97, 0x5a, + 0x44, 0x3a, 0xee, 0xff, 0x6b, 0xb3, 0x3a, 0x52, 0xe7, 0xa4, 0x96, 0x9a, + 0xf6, 0x83, 0xc8, 0x97, 0x1c, 0x63, 0xa1, 0xd6, 0xb3, 0xa8, 0xb2, 0xc7, + 0x73, 0x25, 0x0f, 0x58, 0x36, 0xb9, 0x7a, 0x47, 0xa7, 0x4d, 0x30, 0xfe, + 0x4d, 0x74, 0x56, 0xe8, 0xfb, 0xd6, 0x50, 0xe5, 0xe0, 0x28, 0x15, 0x02, + 0x41, 0x00, 0xeb, 0x15, 0x62, 0xb6, 0x37, 0x41, 0x7c, 0xc5, 0x00, 0x22, + 0x2c, 0x5a, 0x5e, 0xe4, 0xb2, 0x11, 0x87, 0x89, 0xad, 0xf4, 0x57, 0x68, + 0x90, 0xb7, 0x9f, 0xe2, 0x79, 0x20, 0x6b, 0x98, 0x00, 0x0d, 0x3a, 0x3b, + 0xc1, 0xcd, 0x36, 0xf9, 0x27, 0xda, 0x40, 0x36, 0x1d, 0xb8, 0x5c, 0x96, + 0xeb, 0x04, 0x08, 0xe1, 0x3f, 0xfa, 0x94, 0x8b, 0x0f, 0xa0, 0xff, 0xc1, + 0x51, 0xea, 0x90, 0xad, 0x15, 0xc7, 0x02, 0x41, 0x00, 0xd5, 0x06, 0x45, + 0xd7, 0x55, 0x63, 0x1a, 0xf0, 0x89, 0x81, 0xae, 0x87, 0x23, 0xa2, 0x39, + 0xfe, 0x3d, 0x82, 0xc7, 0xcb, 0x15, 0xb9, 0xe3, 0xe2, 0x5b, 0xc6, 0xd2, + 0x55, 0xdd, 0xab, 0x55, 0x29, 0x7c, 0xda, 0x0e, 0x1c, 0x09, 0xfc, 0x73, + 0x0d, 0x01, 0xed, 0x6d, 0x2f, 0x05, 0xd0, 0xd5, 0x1d, 0xce, 0x18, 0x7f, + 0xb0, 0xc8, 0x47, 0x77, 0xd2, 0xa9, 0x9e, 0xfc, 0x39, 0x4b, 0x3d, 0x94, + 0x33, 0x02, 0x41, 0x00, 0x8f, 0x94, 0x09, 0x2d, 0x17, 0x44, 0x75, 0x0a, + 0xf1, 0x10, 0xee, 0x1b, 0xe7, 0xd7, 0x2f, 0xf6, 0xca, 0xdc, 0x49, 0x15, + 0x72, 0x09, 0x58, 0x51, 0xfe, 0x61, 0xd8, 0xee, 0xf7, 0x27, 0xe7, 0xe8, + 0x2c, 0x47, 0xf1, 0x0f, 0x00, 0x63, 0x5e, 0x76, 0xcb, 0x3f, 0x02, 0x19, + 0xe6, 0xda, 0xfa, 0x01, 0x05, 0xd7, 0x65, 0x37, 0x0b, 0x60, 0x7f, 0x94, + 0x2a, 0x80, 0x8d, 0x22, 0x81, 0x68, 0x65, 0x63, 0x02, 0x41, 0x00, 0xc2, + 0xd4, 0x18, 0xde, 0x47, 0x9e, 0xfb, 0x8d, 0x91, 0x05, 0xc5, 0x3c, 0x9d, + 0xcf, 0x8a, 0x60, 0xc7, 0x9b, 0x2b, 0xe5, 0xc6, 0xba, 0x1b, 0xfc, 0xf3, + 0xd9, 0x54, 0x97, 0xe9, 0xc4, 0x00, 0x80, 0x90, 0x4a, 0xd2, 0x6a, 0xbc, + 0x8b, 0x62, 0x22, 0x3c, 0x68, 0x0c, 0xda, 0xdb, 0xe3, 0xd2, 0x76, 0x8e, + 0xff, 0x03, 0x12, 0x09, 0x2a, 0xac, 0x21, 0x44, 0xb7, 0x3e, 0x91, 0x9c, + 0x09, 0xf6, 0xd7, 0x02, 0x41, 0x00, 0xc0, 0xa1, 0xbb, 0x70, 0xdc, 0xf8, + 0xeb, 0x17, 0x61, 0xd4, 0x8c, 0x7c, 0x3b, 0x82, 0x91, 0x58, 0xff, 0xf9, + 0x19, 0xac, 0x3a, 0x73, 0xa7, 0x20, 0xe5, 0x22, 0x02, 0xc4, 0xf6, 0xb9, + 0xb9, 0x43, 0x53, 0x35, 0x88, 0xe1, 0x05, 0xb6, 0x43, 0x9b, 0x39, 0xc8, + 0x04, 0x4d, 0x2b, 0x01, 0xf7, 0xe6, 0x1b, 0x8d, 0x7e, 0x89, 0xe3, 0x43, + 0xd4, 0xf3, 0xab, 0x28, 0xd4, 0x5a, 0x1f, 0x20, 0xea, 0xbe}; - std::vector<uint8> input1; - std::vector<uint8> input2; + std::vector<uint8_t> input1; + std::vector<uint8_t> input2; input1.resize(sizeof(short_integer_with_high_bit)); input2.resize(sizeof(short_integer_without_high_bit)); - memcpy(&input1.front(), short_integer_with_high_bit, - sizeof(short_integer_with_high_bit)); - memcpy(&input2.front(), short_integer_without_high_bit, - sizeof(short_integer_without_high_bit)); + SbMemoryCopy(&input1.front(), short_integer_with_high_bit, + sizeof(short_integer_with_high_bit)); + SbMemoryCopy(&input2.front(), short_integer_without_high_bit, + sizeof(short_integer_without_high_bit)); - scoped_ptr<crypto::RSAPrivateKey> keypair1( + std::unique_ptr<crypto::RSAPrivateKey> keypair1( crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input1)); - scoped_ptr<crypto::RSAPrivateKey> keypair2( + std::unique_ptr<crypto::RSAPrivateKey> keypair2( crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input2)); ASSERT_TRUE(keypair1.get()); ASSERT_TRUE(keypair2.get()); - std::vector<uint8> output1; - std::vector<uint8> output2; + std::vector<uint8_t> output1; + std::vector<uint8_t> output2; ASSERT_TRUE(keypair1->ExportPrivateKey(&output1)); ASSERT_TRUE(keypair2->ExportPrivateKey(&output2)); ASSERT_EQ(input1.size(), output1.size()); ASSERT_EQ(input2.size(), output2.size()); - ASSERT_TRUE(0 == memcmp(&output1.front(), &input1.front(), - input1.size())); - ASSERT_TRUE(0 == memcmp(&output2.front(), &input2.front(), - input2.size())); + ASSERT_EQ(0, + SbMemoryCompare(&output1.front(), &input1.front(), input1.size())); + ASSERT_EQ(0, + SbMemoryCompare(&output2.front(), &input2.front(), input2.size())); } + +TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) { + std::unique_ptr<crypto::RSAPrivateKey> key_pair( + crypto::RSAPrivateKey::Create(512)); + ASSERT_TRUE(key_pair.get()); + + std::unique_ptr<crypto::RSAPrivateKey> key_copy( + crypto::RSAPrivateKey::CreateFromKey(key_pair->key())); + ASSERT_TRUE(key_copy.get()); + + std::vector<uint8_t> privkey; + std::vector<uint8_t> pubkey; + ASSERT_TRUE(key_pair->ExportPrivateKey(&privkey)); + ASSERT_TRUE(key_pair->ExportPublicKey(&pubkey)); + + std::vector<uint8_t> privkey_copy; + std::vector<uint8_t> pubkey_copy; + ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy)); + ASSERT_TRUE(key_copy->ExportPublicKey(&pubkey_copy)); + + ASSERT_EQ(privkey, privkey_copy); + ASSERT_EQ(pubkey, pubkey_copy); +} +
diff --git a/src/crypto/rsa_private_key_win.cc b/src/crypto/rsa_private_key_win.cc deleted file mode 100644 index f870f6a..0000000 --- a/src/crypto/rsa_private_key_win.cc +++ /dev/null
@@ -1,238 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/rsa_private_key.h" - -#include <list> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/string_util.h" - -#pragma comment(lib, "crypt32.lib") - -namespace crypto { - -// static -RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - if (!result->InitProvider()) - return NULL; - - DWORD flags = CRYPT_EXPORTABLE; - - // The size is encoded as the upper 16 bits of the flags. :: sigh ::. - flags |= (num_bits << 16); - if (!CryptGenKey(result->provider_, CALG_RSA_SIGN, flags, - result->key_.receive())) - return NULL; - - return result.release(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( - const std::vector<uint8>& input) { - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - if (!result->InitProvider()) - return NULL; - - PrivateKeyInfoCodec pki(false); // Little-Endian - if (!pki.Import(input)) - return NULL; - - size_t blob_size = sizeof(PUBLICKEYSTRUC) + - sizeof(RSAPUBKEY) + - pki.modulus()->size() + - pki.prime1()->size() + - pki.prime2()->size() + - pki.exponent1()->size() + - pki.exponent2()->size() + - pki.coefficient()->size() + - pki.private_exponent()->size(); - scoped_array<BYTE> blob(new BYTE[blob_size]); - - uint8* dest = blob.get(); - PUBLICKEYSTRUC* public_key_struc = reinterpret_cast<PUBLICKEYSTRUC*>(dest); - public_key_struc->bType = PRIVATEKEYBLOB; - public_key_struc->bVersion = 0x02; - public_key_struc->reserved = 0; - public_key_struc->aiKeyAlg = CALG_RSA_SIGN; - dest += sizeof(PUBLICKEYSTRUC); - - RSAPUBKEY* rsa_pub_key = reinterpret_cast<RSAPUBKEY*>(dest); - rsa_pub_key->magic = 0x32415352; - rsa_pub_key->bitlen = pki.modulus()->size() * 8; - int public_exponent_int = 0; - for (size_t i = pki.public_exponent()->size(); i > 0; --i) { - public_exponent_int <<= 8; - public_exponent_int |= (*pki.public_exponent())[i - 1]; - } - rsa_pub_key->pubexp = public_exponent_int; - dest += sizeof(RSAPUBKEY); - - memcpy(dest, &pki.modulus()->front(), pki.modulus()->size()); - dest += pki.modulus()->size(); - memcpy(dest, &pki.prime1()->front(), pki.prime1()->size()); - dest += pki.prime1()->size(); - memcpy(dest, &pki.prime2()->front(), pki.prime2()->size()); - dest += pki.prime2()->size(); - memcpy(dest, &pki.exponent1()->front(), pki.exponent1()->size()); - dest += pki.exponent1()->size(); - memcpy(dest, &pki.exponent2()->front(), pki.exponent2()->size()); - dest += pki.exponent2()->size(); - memcpy(dest, &pki.coefficient()->front(), pki.coefficient()->size()); - dest += pki.coefficient()->size(); - memcpy(dest, &pki.private_exponent()->front(), - pki.private_exponent()->size()); - dest += pki.private_exponent()->size(); - - if (dest != blob.get() + blob_size) { - NOTREACHED(); - return NULL; - } - if (!CryptImportKey(result->provider_, - reinterpret_cast<uint8*>(public_key_struc), - static_cast<DWORD>(blob_size), 0, CRYPT_EXPORTABLE, - result->key_.receive())) { - return NULL; - } - - return result.release(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( - const std::vector<uint8>& input) { - NOTIMPLEMENTED(); - return NULL; -} - -RSAPrivateKey::RSAPrivateKey() : provider_(NULL), key_(NULL) {} - -RSAPrivateKey::~RSAPrivateKey() {} - -bool RSAPrivateKey::InitProvider() { - return FALSE != CryptAcquireContext(provider_.receive(), NULL, NULL, - PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); -} - -RSAPrivateKey* RSAPrivateKey::Copy() const { - scoped_ptr<RSAPrivateKey> copy(new RSAPrivateKey()); - if (!CryptContextAddRef(provider_, NULL, 0)) { - NOTREACHED(); - return NULL; - } - copy->provider_.reset(provider_.get()); - if (!CryptDuplicateKey(key_.get(), NULL, 0, copy->key_.receive())) - return NULL; - return copy.release(); -} - -bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const { - // Export the key - DWORD blob_length = 0; - if (!CryptExportKey(key_, 0, PRIVATEKEYBLOB, 0, NULL, &blob_length)) { - NOTREACHED(); - return false; - } - - scoped_array<uint8> blob(new uint8[blob_length]); - if (!CryptExportKey(key_, 0, PRIVATEKEYBLOB, 0, blob.get(), &blob_length)) { - NOTREACHED(); - return false; - } - - uint8* pos = blob.get(); - PUBLICKEYSTRUC *publickey_struct = reinterpret_cast<PUBLICKEYSTRUC*>(pos); - pos += sizeof(PUBLICKEYSTRUC); - - RSAPUBKEY *rsa_pub_key = reinterpret_cast<RSAPUBKEY*>(pos); - pos += sizeof(RSAPUBKEY); - - int mod_size = rsa_pub_key->bitlen / 8; - int primes_size = rsa_pub_key->bitlen / 16; - - PrivateKeyInfoCodec pki(false); // Little-Endian - - pki.modulus()->assign(pos, pos + mod_size); - pos += mod_size; - - pki.prime1()->assign(pos, pos + primes_size); - pos += primes_size; - pki.prime2()->assign(pos, pos + primes_size); - pos += primes_size; - - pki.exponent1()->assign(pos, pos + primes_size); - pos += primes_size; - pki.exponent2()->assign(pos, pos + primes_size); - pos += primes_size; - - pki.coefficient()->assign(pos, pos + primes_size); - pos += primes_size; - - pki.private_exponent()->assign(pos, pos + mod_size); - pos += mod_size; - - pki.public_exponent()->assign(reinterpret_cast<uint8*>(&rsa_pub_key->pubexp), - reinterpret_cast<uint8*>(&rsa_pub_key->pubexp) + 4); - - CHECK_EQ(pos - blob_length, reinterpret_cast<BYTE*>(publickey_struct)); - - return pki.Export(output); -} - -bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const { - DWORD key_info_len; - if (!CryptExportPublicKeyInfo( - provider_, AT_SIGNATURE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - NULL, &key_info_len)) { - NOTREACHED(); - return false; - } - - scoped_array<uint8> key_info(new uint8[key_info_len]); - if (!CryptExportPublicKeyInfo( - provider_, AT_SIGNATURE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), &key_info_len)) { - NOTREACHED(); - return false; - } - - DWORD encoded_length; - if (!CryptEncodeObject( - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO, - reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), NULL, - &encoded_length)) { - NOTREACHED(); - return false; - } - - scoped_array<BYTE> encoded(new BYTE[encoded_length]); - if (!CryptEncodeObject( - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO, - reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), encoded.get(), - &encoded_length)) { - NOTREACHED(); - return false; - } - - output->assign(encoded.get(), encoded.get() + encoded_length); - return true; -} - -} // namespace crypto
diff --git a/src/crypto/run_all_unittests.cc b/src/crypto/run_all_unittests.cc deleted file mode 100644 index 585601f..0000000 --- a/src/crypto/run_all_unittests.cc +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/main_hook.h" -#include "base/test/test_suite.h" -#include "crypto/nss_util.h" -#include "starboard/client_porting/wrap_main/wrap_main.h" - -int TestSuiteRun(int argc, char** argv) { - MainHook hook(NULL, argc, argv); -#if defined(USE_NSS) - // This is most likely not needed, but it basically replaces a similar call - // that was performed on test_support_base. - // TODO(rvargas) Bug 79359: remove this. - crypto::EnsureNSSInit(); -#endif // defined(USE_NSS) - return base::TestSuite(argc, argv).Run(); -} - -STARBOARD_WRAP_SIMPLE_MAIN(TestSuiteRun);
diff --git a/src/crypto/scoped_capi_types.h b/src/crypto/scoped_capi_types.h index 16a5192..97c7da8 100644 --- a/src/crypto/scoped_capi_types.h +++ b/src/crypto/scoped_capi_types.h
@@ -6,11 +6,13 @@ #define CRYPTO_SCOPED_CAPI_TYPES_H_ #include <windows.h> -#include <wincrypt.h> #include <algorithm> #include "base/logging.h" +#include "base/macros.h" +#include "crypto/wincrypt_shim.h" +#include "starboard/types.h" namespace crypto { @@ -42,8 +44,8 @@ // scoped_ptr-like class for the CryptoAPI cryptography and certificate // handles. Because these handles are defined as integer types, and not -// pointers, the existing scoped classes, such as scoped_ptr_malloc, are -// insufficient. The semantics are the same as scoped_ptr. +// pointers, the existing scoped classes, such as scoped_ptr, are insufficient. +// The semantics are the same as scoped_ptr. template <class CAPIHandle, typename FreeProc> class ScopedCAPIHandle { public:
diff --git a/src/crypto/scoped_nss_types.h b/src/crypto/scoped_nss_types.h index da90fea..775330c 100644 --- a/src/crypto/scoped_nss_types.h +++ b/src/crypto/scoped_nss_types.h
@@ -10,53 +10,55 @@ #include <pk11pub.h> #include <plarena.h> -#include "base/memory/scoped_ptr.h" +#include <memory> + +#include "starboard/types.h" namespace crypto { template <typename Type, void (*Destroyer)(Type*)> struct NSSDestroyer { void operator()(Type* ptr) const { - if (ptr) - Destroyer(ptr); + Destroyer(ptr); } }; template <typename Type, void (*Destroyer)(Type*, PRBool), PRBool freeit> struct NSSDestroyer1 { void operator()(Type* ptr) const { - if (ptr) - Destroyer(ptr, freeit); + Destroyer(ptr, freeit); } }; // Define some convenient scopers around NSS pointers. -typedef scoped_ptr_malloc< - PK11Context, NSSDestroyer1<PK11Context, - PK11_DestroyContext, - PR_TRUE> > ScopedPK11Context; -typedef scoped_ptr_malloc< - PK11SlotInfo, NSSDestroyer<PK11SlotInfo, PK11_FreeSlot> > ScopedPK11Slot; -typedef scoped_ptr_malloc< - PK11SymKey, NSSDestroyer<PK11SymKey, PK11_FreeSymKey> > ScopedPK11SymKey; -typedef scoped_ptr_malloc< - SECKEYPublicKey, NSSDestroyer<SECKEYPublicKey, SECKEY_DestroyPublicKey> > +typedef std::unique_ptr< + PK11Context, + NSSDestroyer1<PK11Context, PK11_DestroyContext, PR_TRUE>> + ScopedPK11Context; +typedef std::unique_ptr<PK11SlotInfo, NSSDestroyer<PK11SlotInfo, PK11_FreeSlot>> + ScopedPK11Slot; +typedef std::unique_ptr<PK11SlotList, + NSSDestroyer<PK11SlotList, PK11_FreeSlotList>> + ScopedPK11SlotList; +typedef std::unique_ptr<PK11SymKey, NSSDestroyer<PK11SymKey, PK11_FreeSymKey>> + ScopedPK11SymKey; +typedef std::unique_ptr<SECKEYPublicKey, + NSSDestroyer<SECKEYPublicKey, SECKEY_DestroyPublicKey>> ScopedSECKEYPublicKey; -typedef scoped_ptr_malloc< - SECKEYPrivateKey, NSSDestroyer<SECKEYPrivateKey, SECKEY_DestroyPrivateKey> > +typedef std::unique_ptr< + SECKEYPrivateKey, + NSSDestroyer<SECKEYPrivateKey, SECKEY_DestroyPrivateKey>> ScopedSECKEYPrivateKey; -typedef scoped_ptr_malloc< - SECAlgorithmID, NSSDestroyer1<SECAlgorithmID, - SECOID_DestroyAlgorithmID, - PR_TRUE> > ScopedSECAlgorithmID; -typedef scoped_ptr_malloc< - SECItem, NSSDestroyer1<SECItem, - SECITEM_FreeItem, - PR_TRUE> > ScopedSECItem; -typedef scoped_ptr_malloc< - PLArenaPool, NSSDestroyer1<PLArenaPool, - PORT_FreeArena, - PR_FALSE> > ScopedPLArenaPool; +typedef std::unique_ptr< + SECAlgorithmID, + NSSDestroyer1<SECAlgorithmID, SECOID_DestroyAlgorithmID, PR_TRUE>> + ScopedSECAlgorithmID; +typedef std::unique_ptr<SECItem, + NSSDestroyer1<SECItem, SECITEM_FreeItem, PR_TRUE>> + ScopedSECItem; +typedef std::unique_ptr<PLArenaPool, + NSSDestroyer1<PLArenaPool, PORT_FreeArena, PR_FALSE>> + ScopedPLArenaPool; } // namespace crypto
diff --git a/src/crypto/scoped_test_nss_chromeos_user.cc b/src/crypto/scoped_test_nss_chromeos_user.cc new file mode 100644 index 0000000..49b92d4 --- /dev/null +++ b/src/crypto/scoped_test_nss_chromeos_user.cc
@@ -0,0 +1,37 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/scoped_test_nss_chromeos_user.h" + +#include "base/logging.h" +#include "crypto/nss_util.h" +#include "crypto/nss_util_internal.h" + +namespace crypto { + +ScopedTestNSSChromeOSUser::ScopedTestNSSChromeOSUser( + const std::string& username_hash) + : username_hash_(username_hash), constructed_successfully_(false) { + if (!temp_dir_.CreateUniqueTempDir()) + return; + // This opens a software DB in the given folder. In production code that is in + // the home folder, but for testing the temp folder is used. + constructed_successfully_ = + InitializeNSSForChromeOSUser(username_hash, temp_dir_.GetPath()); +} + +ScopedTestNSSChromeOSUser::~ScopedTestNSSChromeOSUser() { + if (constructed_successfully_) + CloseChromeOSUserForTesting(username_hash_); +} + +void ScopedTestNSSChromeOSUser::FinishInit() { + DCHECK(constructed_successfully_); + if (!ShouldInitializeTPMForChromeOSUser(username_hash_)) + return; + WillInitializeTPMForChromeOSUser(username_hash_); + InitializePrivateSoftwareSlotForChromeOSUser(username_hash_); +} + +} // namespace crypto
diff --git a/src/crypto/scoped_test_nss_chromeos_user.h b/src/crypto/scoped_test_nss_chromeos_user.h new file mode 100644 index 0000000..9202b0f --- /dev/null +++ b/src/crypto/scoped_test_nss_chromeos_user.h
@@ -0,0 +1,43 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_ +#define CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_ + +#include <string> + +#include "base/files/scoped_temp_dir.h" +#include "base/macros.h" +#include "crypto/crypto_export.h" + +namespace crypto { + +// Opens a persistent NSS software database in a temporary directory for the +// user with |username_hash|. This database will be used for both the user's +// public and private slot. +class CRYPTO_EXPORT ScopedTestNSSChromeOSUser { + public: + // Opens the software database and sets the public slot for the user. The + // private slot will not be initialized until FinishInit() is called. + explicit ScopedTestNSSChromeOSUser(const std::string& username_hash); + ~ScopedTestNSSChromeOSUser(); + + std::string username_hash() const { return username_hash_; } + bool constructed_successfully() const { return constructed_successfully_; } + + // Completes initialization of user. Causes any waiting private slot callbacks + // to run, see GetPrivateSlotForChromeOSUser(). + void FinishInit(); + + private: + const std::string username_hash_; + base::ScopedTempDir temp_dir_; + bool constructed_successfully_; + + DISALLOW_COPY_AND_ASSIGN(ScopedTestNSSChromeOSUser); +}; + +} // namespace crypto + +#endif // CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_
diff --git a/src/crypto/scoped_test_nss_db.cc b/src/crypto/scoped_test_nss_db.cc new file mode 100644 index 0000000..ea953a7 --- /dev/null +++ b/src/crypto/scoped_test_nss_db.cc
@@ -0,0 +1,63 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/scoped_test_nss_db.h" + +#include <cert.h> + +#include "base/logging.h" +#include "base/threading/thread_restrictions.h" +#include "crypto/nss_util.h" +#include "crypto/nss_util_internal.h" +#include "starboard/types.h" + +namespace crypto { + +ScopedTestNSSDB::ScopedTestNSSDB() { + EnsureNSSInit(); + // NSS is allowed to do IO on the current thread since dispatching + // to a dedicated thread would still have the affect of blocking + // the current thread, due to NSS's internal locking requirements + base::ScopedAllowBlockingForTesting allow_blocking; + + if (!temp_dir_.CreateUniqueTempDir()) + return; + + const char kTestDescription[] = "Test DB"; + slot_ = OpenSoftwareNSSDB(temp_dir_.GetPath(), kTestDescription); +} + +ScopedTestNSSDB::~ScopedTestNSSDB() { + // Remove trust from any certs in the test DB before closing it. Otherwise NSS + // may cache verification results even after the test DB is gone. + if (slot_) { + CERTCertList* cert_list = PK11_ListCertsInSlot(slot_.get()); + for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); + !CERT_LIST_END(node, cert_list); + node = CERT_LIST_NEXT(node)) { + CERTCertTrust trust = {0}; + if (CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), node->cert, &trust) != + SECSuccess) { + LOG(ERROR) << "CERT_ChangeCertTrust failed: " << PORT_GetError(); + } + } + CERT_DestroyCertList(cert_list); + } + + // NSS is allowed to do IO on the current thread since dispatching + // to a dedicated thread would still have the affect of blocking + // the current thread, due to NSS's internal locking requirements + base::ScopedAllowBlockingForTesting allow_blocking; + + if (slot_) { + SECStatus status = SECMOD_CloseUserDB(slot_.get()); + if (status != SECSuccess) + PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); + } + + if (!temp_dir_.Delete()) + LOG(ERROR) << "Could not delete temporary directory."; +} + +} // namespace crypto
diff --git a/src/crypto/scoped_test_nss_db.h b/src/crypto/scoped_test_nss_db.h new file mode 100644 index 0000000..c01653f --- /dev/null +++ b/src/crypto/scoped_test_nss_db.h
@@ -0,0 +1,35 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_SCOPED_TEST_NSS_DB_H_ +#define CRYPTO_SCOPED_TEST_NSS_DB_H_ + +#include "base/files/scoped_temp_dir.h" +#include "base/macros.h" +#include "crypto/crypto_export.h" +#include "crypto/scoped_nss_types.h" + +namespace crypto { + +// Opens a persistent NSS database in a temporary directory. +// Prior NSS version 3.15.1, because of http://bugzil.la/875601 , the opened DB +// will not be closed automatically. +class CRYPTO_EXPORT ScopedTestNSSDB { + public: + ScopedTestNSSDB(); + ~ScopedTestNSSDB(); + + bool is_open() const { return !!slot_; } + PK11SlotInfo* slot() const { return slot_.get(); } + + private: + base::ScopedTempDir temp_dir_; + ScopedPK11Slot slot_; + + DISALLOW_COPY_AND_ASSIGN(ScopedTestNSSDB); +}; + +} // namespace crypto + +#endif // CRYPTO_SCOPED_TEST_NSS_DB_H_
diff --git a/src/crypto/scoped_test_system_nss_key_slot.cc b/src/crypto/scoped_test_system_nss_key_slot.cc new file mode 100644 index 0000000..53fbbff --- /dev/null +++ b/src/crypto/scoped_test_system_nss_key_slot.cc
@@ -0,0 +1,32 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/scoped_test_system_nss_key_slot.h" + +#include "crypto/nss_util_internal.h" +#include "crypto/scoped_test_nss_db.h" + +namespace crypto { + +ScopedTestSystemNSSKeySlot::ScopedTestSystemNSSKeySlot() + : test_db_(new ScopedTestNSSDB) { + if (!test_db_->is_open()) + return; + SetSystemKeySlotForTesting( + ScopedPK11Slot(PK11_ReferenceSlot(test_db_->slot()))); +} + +ScopedTestSystemNSSKeySlot::~ScopedTestSystemNSSKeySlot() { + SetSystemKeySlotForTesting(ScopedPK11Slot()); +} + +bool ScopedTestSystemNSSKeySlot::ConstructedSuccessfully() const { + return test_db_->is_open(); +} + +PK11SlotInfo* ScopedTestSystemNSSKeySlot::slot() const { + return test_db_->slot(); +} + +} // namespace crypto
diff --git a/src/crypto/scoped_test_system_nss_key_slot.h b/src/crypto/scoped_test_system_nss_key_slot.h new file mode 100644 index 0000000..ae9b2cd --- /dev/null +++ b/src/crypto/scoped_test_system_nss_key_slot.h
@@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_ +#define CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_ + +#include <memory> + +#include "base/macros.h" +#include "crypto/crypto_export.h" + +// Forward declaration, from <pk11pub.h> +typedef struct PK11SlotInfoStr PK11SlotInfo; + +namespace crypto { + +class ScopedTestNSSDB; + +// Opens a persistent NSS software database in a temporary directory and sets +// the test system slot to the opened database. This helper should be created in +// tests to fake the system token that is usually provided by the Chaps module. +// |slot| is exposed through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will +// return true. +// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization, +// does not have to be called if this helper is used. +// At most one instance of this helper must be used at a time. +class CRYPTO_EXPORT ScopedTestSystemNSSKeySlot { + public: + ScopedTestSystemNSSKeySlot(); + ~ScopedTestSystemNSSKeySlot(); + + bool ConstructedSuccessfully() const; + PK11SlotInfo* slot() const; + + private: + std::unique_ptr<ScopedTestNSSDB> test_db_; + + DISALLOW_COPY_AND_ASSIGN(ScopedTestSystemNSSKeySlot); +}; + +} // namespace crypto + +#endif // CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_
diff --git a/src/crypto/secure_hash.cc b/src/crypto/secure_hash.cc new file mode 100644 index 0000000..18d058a --- /dev/null +++ b/src/crypto/secure_hash.cc
@@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/secure_hash.h" + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/pickle.h" +#include "crypto/openssl_util.h" +#include "starboard/memory.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/mem.h" +#include "third_party/boringssl/src/include/openssl/sha.h" + +namespace crypto { + +namespace { + +class SecureHashSHA256 : public SecureHash { + public: + SecureHashSHA256() { + SHA256_Init(&ctx_); + } + + SecureHashSHA256(const SecureHashSHA256& other) { + SbMemoryCopy(&ctx_, &other.ctx_, sizeof(ctx_)); + } + + ~SecureHashSHA256() override { + OPENSSL_cleanse(&ctx_, sizeof(ctx_)); + } + + void Update(const void* input, size_t len) override { + SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len); + } + + void Finish(void* output, size_t len) override { + ScopedOpenSSLSafeSizeBuffer<SHA256_DIGEST_LENGTH> result( + static_cast<unsigned char*>(output), len); + SHA256_Final(result.safe_buffer(), &ctx_); + } + + std::unique_ptr<SecureHash> Clone() const override { + return std::make_unique<SecureHashSHA256>(*this); + } + + size_t GetHashLength() const override { return SHA256_DIGEST_LENGTH; } + + private: + SHA256_CTX ctx_; +}; + +} // namespace + +std::unique_ptr<SecureHash> SecureHash::Create(Algorithm algorithm) { + switch (algorithm) { + case SHA256: + return std::make_unique<SecureHashSHA256>(); + default: + NOTIMPLEMENTED(); + return nullptr; + } +} + +} // namespace crypto
diff --git a/src/crypto/secure_hash.h b/src/crypto/secure_hash.h index 173fd0a..7e89211 100644 --- a/src/crypto/secure_hash.h +++ b/src/crypto/secure_hash.h
@@ -5,16 +5,17 @@ #ifndef CRYPTO_SECURE_HASH_H_ #define CRYPTO_SECURE_HASH_H_ -#include "base/basictypes.h" -#include "crypto/crypto_export.h" +#include <memory> -class Pickle; -class PickleIterator; +#include "base/macros.h" +#include "crypto/crypto_export.h" +#include "starboard/types.h" namespace crypto { // A wrapper to calculate secure hashes incrementally, allowing to -// be used when the full input is not known in advance. +// be used when the full input is not known in advance. The end result will the +// same as if we have the full input in advance. class CRYPTO_EXPORT SecureHash { public: enum Algorithm { @@ -22,21 +23,16 @@ }; virtual ~SecureHash() {} - static SecureHash* Create(Algorithm type); + static std::unique_ptr<SecureHash> Create(Algorithm type); virtual void Update(const void* input, size_t len) = 0; virtual void Finish(void* output, size_t len) = 0; + virtual size_t GetHashLength() const = 0; - // Serialize the context, so it can be restored at a later time. - // |pickle| will contain the serialized data. - // Returns whether or not |pickle| was filled. - virtual bool Serialize(Pickle* pickle) = 0; - - // Restore the context that was saved earlier. - // |data_iterator| allows this to be used as part of a larger pickle. - // |pickle| holds the saved data. - // Returns success or failure. - virtual bool Deserialize(PickleIterator* data_iterator) = 0; + // Create a clone of this SecureHash. The returned clone and this both + // represent the same hash state. But from this point on, calling + // Update()/Finish() on either doesn't affect the state of the other. + virtual std::unique_ptr<SecureHash> Clone() const = 0; protected: SecureHash() {}
diff --git a/src/crypto/secure_hash_openssl.cc b/src/crypto/secure_hash_openssl.cc deleted file mode 100644 index 743057b..0000000 --- a/src/crypto/secure_hash_openssl.cc +++ /dev/null
@@ -1,102 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/secure_hash.h" - -#include <openssl/crypto.h> -#include <openssl/sha.h> - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/pickle.h" -#include "crypto/openssl_util.h" - -namespace crypto { - -namespace { - -const char kSHA256Descriptor[] = "OpenSSL"; - -class SecureHashSHA256OpenSSL : public SecureHash { - public: - static const int kSecureHashVersion = 1; - - SecureHashSHA256OpenSSL() { - SHA256_Init(&ctx_); - } - - virtual ~SecureHashSHA256OpenSSL() { - OPENSSL_cleanse(&ctx_, sizeof(ctx_)); - } - - virtual void Update(const void* input, size_t len) { - SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len); - } - - virtual void Finish(void* output, size_t len) { - ScopedOpenSSLSafeSizeBuffer<SHA256_DIGEST_LENGTH> result( - static_cast<unsigned char*>(output), len); - SHA256_Final(result.safe_buffer(), &ctx_); - } - - virtual bool Serialize(Pickle* pickle); - virtual bool Deserialize(PickleIterator* data_iterator); - - private: - SHA256_CTX ctx_; -}; - -bool SecureHashSHA256OpenSSL::Serialize(Pickle* pickle) { - if (!pickle) - return false; - - if (!pickle->WriteInt(kSecureHashVersion) || - !pickle->WriteString(kSHA256Descriptor) || - !pickle->WriteBytes(&ctx_, sizeof(ctx_))) { - return false; - } - - return true; -} - -bool SecureHashSHA256OpenSSL::Deserialize(PickleIterator* data_iterator) { - if (!data_iterator) - return false; - - int version; - if (!data_iterator->ReadInt(&version)) - return false; - - if (version > kSecureHashVersion) - return false; // We don't know how to deal with this. - - std::string type; - if (!data_iterator->ReadString(&type)) - return false; - - if (type != kSHA256Descriptor) - return false; // It's the wrong kind. - - const char* data = NULL; - if (!data_iterator->ReadBytes(&data, sizeof(ctx_))) - return false; - - memcpy(&ctx_, data, sizeof(ctx_)); - - return true; -} - -} // namespace - -SecureHash* SecureHash::Create(Algorithm algorithm) { - switch (algorithm) { - case SHA256: - return new SecureHashSHA256OpenSSL(); - default: - NOTIMPLEMENTED(); - return NULL; - } -} - -} // namespace crypto
diff --git a/src/crypto/secure_hash_unittest.cc b/src/crypto/secure_hash_unittest.cc index 42b9ade..cf37b9c 100644 --- a/src/crypto/secure_hash_unittest.cc +++ b/src/crypto/secure_hash_unittest.cc
@@ -4,70 +4,104 @@ #include "crypto/secure_hash.h" -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/pickle.h" +#include <memory> +#include <string> + #include "crypto/sha2.h" +#include "starboard/memory.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" TEST(SecureHashTest, TestUpdate) { // Example B.3 from FIPS 180-2: long message. std::string input3(500000, 'a'); // 'a' repeated half a million times - int expected3[] = { 0xcd, 0xc7, 0x6e, 0x5c, - 0x99, 0x14, 0xfb, 0x92, - 0x81, 0xa1, 0xc7, 0xe2, - 0x84, 0xd7, 0x3e, 0x67, - 0xf1, 0x80, 0x9a, 0x48, - 0xa4, 0x97, 0x20, 0x0e, - 0x04, 0x6d, 0x39, 0xcc, - 0xc7, 0x11, 0x2c, 0xd0 }; + const int kExpectedHashOfInput3[] = { + 0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, + 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, + 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}; - uint8 output3[crypto::kSHA256Length]; + uint8_t output3[crypto::kSHA256Length]; - scoped_ptr<crypto::SecureHash> ctx(crypto::SecureHash::Create( - crypto::SecureHash::SHA256)); + std::unique_ptr<crypto::SecureHash> ctx( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); ctx->Update(input3.data(), input3.size()); ctx->Update(input3.data(), input3.size()); ctx->Finish(output3, sizeof(output3)); for (size_t i = 0; i < crypto::kSHA256Length; i++) - EXPECT_EQ(expected3[i], static_cast<int>(output3[i])); + EXPECT_EQ(kExpectedHashOfInput3[i], static_cast<int>(output3[i])); } -// Save the crypto state mid-stream, and create another instance with the -// saved state. Then feed the same data afterwards to both. -// When done, both should have the same hash value. -TEST(SecureHashTest, TestSerialization) { +TEST(SecureHashTest, TestClone) { std::string input1(10001, 'a'); // 'a' repeated 10001 times - std::string input2(10001, 'b'); // 'b' repeated 10001 times - std::string input3(10001, 'c'); // 'c' repeated 10001 times - std::string input4(10001, 'd'); // 'd' repeated 10001 times - std::string input5(10001, 'e'); // 'e' repeated 10001 times + std::string input2(10001, 'd'); // 'd' repeated 10001 times - uint8 output1[crypto::kSHA256Length]; - uint8 output2[crypto::kSHA256Length]; + const uint8_t kExpectedHashOfInput1[crypto::kSHA256Length] = { + 0x0c, 0xab, 0x99, 0xa0, 0x58, 0x60, 0x0f, 0xfa, 0xad, 0x12, 0x92, + 0xd0, 0xc5, 0x3c, 0x05, 0x48, 0xeb, 0xaf, 0x88, 0xdd, 0x1d, 0x01, + 0x03, 0x03, 0x45, 0x70, 0x5f, 0x01, 0x8a, 0x81, 0x39, 0x09}; + const uint8_t kExpectedHashOfInput1And2[crypto::kSHA256Length] = { + 0x4c, 0x8e, 0x26, 0x5a, 0xc3, 0x85, 0x1f, 0x1f, 0xa5, 0x04, 0x1c, + 0xc7, 0x88, 0x53, 0x1c, 0xc7, 0x80, 0x47, 0x15, 0xfb, 0x47, 0xff, + 0x72, 0xb1, 0x28, 0x37, 0xb0, 0x4d, 0x6e, 0x22, 0x2e, 0x4d}; - scoped_ptr<crypto::SecureHash> ctx1(crypto::SecureHash::Create( - crypto::SecureHash::SHA256)); - scoped_ptr<crypto::SecureHash> ctx2(crypto::SecureHash::Create( - crypto::SecureHash::SHA256)); - Pickle pickle; + uint8_t output1[crypto::kSHA256Length]; + uint8_t output2[crypto::kSHA256Length]; + uint8_t output3[crypto::kSHA256Length]; + + std::unique_ptr<crypto::SecureHash> ctx1( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); ctx1->Update(input1.data(), input1.size()); + + std::unique_ptr<crypto::SecureHash> ctx2(ctx1->Clone()); + std::unique_ptr<crypto::SecureHash> ctx3(ctx2->Clone()); + // At this point, ctx1, ctx2, and ctx3 are all equivalent and represent the + // state after hashing input1. + + // Updating ctx1 and ctx2 with input2 should produce equivalent results. ctx1->Update(input2.data(), input2.size()); - ctx1->Update(input3.data(), input3.size()); - - EXPECT_TRUE(ctx1->Serialize(&pickle)); - ctx1->Update(input4.data(), input4.size()); - ctx1->Update(input5.data(), input5.size()); - ctx1->Finish(output1, sizeof(output1)); - PickleIterator data_iterator(pickle); - EXPECT_TRUE(ctx2->Deserialize(&data_iterator)); - ctx2->Update(input4.data(), input4.size()); - ctx2->Update(input5.data(), input5.size()); - + ctx2->Update(input2.data(), input2.size()); ctx2->Finish(output2, sizeof(output2)); - EXPECT_EQ(0, memcmp(output1, output2, crypto::kSHA256Length)); + EXPECT_EQ(0, SbMemoryCompare(output1, output2, crypto::kSHA256Length)); + EXPECT_EQ(0, SbMemoryCompare(output1, kExpectedHashOfInput1And2, + crypto::kSHA256Length)); + + // Finish() ctx3, which should produce the hash of input1. + ctx3->Finish(&output3, sizeof(output3)); + EXPECT_EQ(0, SbMemoryCompare(output3, kExpectedHashOfInput1, + crypto::kSHA256Length)); +} + +TEST(SecureHashTest, TestLength) { + std::unique_ptr<crypto::SecureHash> ctx( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + EXPECT_EQ(crypto::kSHA256Length, ctx->GetHashLength()); +} + +TEST(SecureHashTest, Equality) { + std::string input1(10001, 'a'); // 'a' repeated 10001 times + std::string input2(10001, 'd'); // 'd' repeated 10001 times + + uint8_t output1[crypto::kSHA256Length]; + uint8_t output2[crypto::kSHA256Length]; + + // Call Update() twice on input1 and input2. + std::unique_ptr<crypto::SecureHash> ctx1( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + ctx1->Update(input1.data(), input1.size()); + ctx1->Update(input2.data(), input2.size()); + ctx1->Finish(output1, sizeof(output1)); + + // Call Update() once one input1 + input2 (concatenation). + std::unique_ptr<crypto::SecureHash> ctx2( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + std::string input3 = input1 + input2; + ctx2->Update(input3.data(), input3.size()); + ctx2->Finish(output2, sizeof(output2)); + + // The hash should be the same. + EXPECT_EQ(0, SbMemoryCompare(output1, output2, crypto::kSHA256Length)); }
diff --git a/src/crypto/secure_util.cc b/src/crypto/secure_util.cc index 3fe8aa9..ac261ab 100644 --- a/src/crypto/secure_util.cc +++ b/src/crypto/secure_util.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "crypto/secure_util.h" +#include "starboard/types.h" namespace crypto {
diff --git a/src/crypto/secure_util.h b/src/crypto/secure_util.h index cfe05ca..1523cc6 100644 --- a/src/crypto/secure_util.h +++ b/src/crypto/secure_util.h
@@ -5,9 +5,8 @@ #ifndef CRYPTO_SECURE_UTIL_H_ #define CRYPTO_SECURE_UTIL_H_ -#include <stddef.h> - #include "crypto/crypto_export.h" +#include "starboard/types.h" namespace crypto {
diff --git a/src/crypto/sha2.cc b/src/crypto/sha2.cc index 6f36237..7c350bf 100644 --- a/src/crypto/sha2.cc +++ b/src/crypto/sha2.cc
@@ -4,21 +4,23 @@ #include "crypto/sha2.h" -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "base/stl_util.h" #include "crypto/secure_hash.h" +#include "starboard/types.h" namespace crypto { -void SHA256HashString(const base::StringPiece& str, void* output, size_t len) { - scoped_ptr<SecureHash> ctx(SecureHash::Create(SecureHash::SHA256)); +void SHA256HashString(base::StringPiece str, void* output, size_t len) { + std::unique_ptr<SecureHash> ctx(SecureHash::Create(SecureHash::SHA256)); ctx->Update(str.data(), str.length()); ctx->Finish(output, len); } -std::string SHA256HashString(const base::StringPiece& str) { +std::string SHA256HashString(base::StringPiece str) { std::string output(kSHA256Length, 0); - SHA256HashString(str, string_as_array(&output), output.size()); + SHA256HashString(str, base::data(output), output.size()); return output; }
diff --git a/src/crypto/sha2.h b/src/crypto/sha2.h index e235f82..6d8f5a3 100644 --- a/src/crypto/sha2.h +++ b/src/crypto/sha2.h
@@ -7,8 +7,9 @@ #include <string> -#include "base/string_piece.h" +#include "base/strings/string_piece.h" #include "crypto/crypto_export.h" +#include "starboard/types.h" namespace crypto { @@ -21,12 +22,13 @@ // Computes the SHA-256 hash of the input string 'str' and stores the first // 'len' bytes of the hash in the output buffer 'output'. If 'len' > 32, // only 32 bytes (the full hash) are stored in the 'output' buffer. -CRYPTO_EXPORT void SHA256HashString(const base::StringPiece& str, - void* output, size_t len); +CRYPTO_EXPORT void SHA256HashString(base::StringPiece str, + void* output, + size_t len); // Convenience version of the above that returns the result in a 32-byte // string. -CRYPTO_EXPORT std::string SHA256HashString(const base::StringPiece& str); +CRYPTO_EXPORT std::string SHA256HashString(base::StringPiece str); } // namespace crypto
diff --git a/src/crypto/sha2_unittest.cc b/src/crypto/sha2_unittest.cc index 78da136..72095e4 100644 --- a/src/crypto/sha2_unittest.cc +++ b/src/crypto/sha2_unittest.cc
@@ -4,7 +4,7 @@ #include "crypto/sha2.h" -#include "base/basictypes.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" TEST(Sha256Test, Test1) { @@ -19,12 +19,12 @@ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }; - uint8 output1[crypto::kSHA256Length]; + uint8_t output1[crypto::kSHA256Length]; crypto::SHA256HashString(input1, output1, sizeof(output1)); for (size_t i = 0; i < crypto::kSHA256Length; i++) EXPECT_EQ(expected1[i], static_cast<int>(output1[i])); - uint8 output_truncated1[4]; // 4 bytes == 32 bits + uint8_t output_truncated1[4]; // 4 bytes == 32 bits crypto::SHA256HashString(input1, output_truncated1, sizeof(output_truncated1)); for (size_t i = 0; i < sizeof(output_truncated1); i++) @@ -47,7 +47,7 @@ std::string output1 = crypto::SHA256HashString(input1); ASSERT_EQ(crypto::kSHA256Length, output1.size()); for (size_t i = 0; i < crypto::kSHA256Length; i++) - EXPECT_EQ(expected1[i], static_cast<uint8>(output1[i])); + EXPECT_EQ(expected1[i], static_cast<uint8_t>(output1[i])); } TEST(Sha256Test, Test2) { @@ -63,12 +63,12 @@ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }; - uint8 output2[crypto::kSHA256Length]; + uint8_t output2[crypto::kSHA256Length]; crypto::SHA256HashString(input2, output2, sizeof(output2)); for (size_t i = 0; i < crypto::kSHA256Length; i++) EXPECT_EQ(expected2[i], static_cast<int>(output2[i])); - uint8 output_truncated2[6]; + uint8_t output_truncated2[6]; crypto::SHA256HashString(input2, output_truncated2, sizeof(output_truncated2)); for (size_t i = 0; i < sizeof(output_truncated2); i++) @@ -87,12 +87,12 @@ 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0 }; - uint8 output3[crypto::kSHA256Length]; + uint8_t output3[crypto::kSHA256Length]; crypto::SHA256HashString(input3, output3, sizeof(output3)); for (size_t i = 0; i < crypto::kSHA256Length; i++) EXPECT_EQ(expected3[i], static_cast<int>(output3[i])); - uint8 output_truncated3[12]; + uint8_t output_truncated3[12]; crypto::SHA256HashString(input3, output_truncated3, sizeof(output_truncated3)); for (size_t i = 0; i < sizeof(output_truncated3); i++)
diff --git a/src/crypto/signature_creator.cc b/src/crypto/signature_creator.cc new file mode 100644 index 0000000..5bab09a --- /dev/null +++ b/src/crypto/signature_creator.cc
@@ -0,0 +1,110 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/signature_creator.h" + +#include "base/logging.h" +#include "crypto/openssl_util.h" +#include "crypto/rsa_private_key.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" + +namespace crypto { + +namespace { + +const EVP_MD* ToOpenSSLDigest(SignatureCreator::HashAlgorithm hash_alg) { + switch (hash_alg) { + case SignatureCreator::SHA1: + return EVP_sha1(); + case SignatureCreator::SHA256: + return EVP_sha256(); + } + return nullptr; +} + +int ToOpenSSLDigestType(SignatureCreator::HashAlgorithm hash_alg) { + switch (hash_alg) { + case SignatureCreator::SHA1: + return NID_sha1; + case SignatureCreator::SHA256: + return NID_sha256; + } + return NID_undef; +} + +} // namespace + +SignatureCreator::~SignatureCreator() { + EVP_MD_CTX_destroy(sign_context_); +} + +// static +std::unique_ptr<SignatureCreator> SignatureCreator::Create( + RSAPrivateKey* key, + HashAlgorithm hash_alg) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + std::unique_ptr<SignatureCreator> result(new SignatureCreator); + const EVP_MD* const digest = ToOpenSSLDigest(hash_alg); + DCHECK(digest); + if (!digest) { + return nullptr; + } + if (!EVP_DigestSignInit(result->sign_context_, nullptr, digest, nullptr, + key->key())) { + return nullptr; + } + return result; +} + +// static +bool SignatureCreator::Sign(RSAPrivateKey* key, + HashAlgorithm hash_alg, + const uint8_t* data, + int data_len, + std::vector<uint8_t>* signature) { + bssl::UniquePtr<RSA> rsa_key(EVP_PKEY_get1_RSA(key->key())); + if (!rsa_key) + return false; + signature->resize(RSA_size(rsa_key.get())); + + unsigned int len = 0; + if (!RSA_sign(ToOpenSSLDigestType(hash_alg), data, data_len, + signature->data(), &len, rsa_key.get())) { + signature->clear(); + return false; + } + signature->resize(len); + return true; +} + +bool SignatureCreator::Update(const uint8_t* data_part, int data_part_len) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + return !!EVP_DigestSignUpdate(sign_context_, data_part, data_part_len); +} + +bool SignatureCreator::Final(std::vector<uint8_t>* signature) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + + // Determine the maximum length of the signature. + size_t len = 0; + if (!EVP_DigestSignFinal(sign_context_, nullptr, &len)) { + signature->clear(); + return false; + } + signature->resize(len); + + // Sign it. + if (!EVP_DigestSignFinal(sign_context_, signature->data(), &len)) { + signature->clear(); + return false; + } + signature->resize(len); + return true; +} + +SignatureCreator::SignatureCreator() : sign_context_(EVP_MD_CTX_create()) {} + +} // namespace crypto
diff --git a/src/crypto/signature_creator.h b/src/crypto/signature_creator.h index 301ab19..f4a43b4 100644 --- a/src/crypto/signature_creator.h +++ b/src/crypto/signature_creator.h
@@ -5,62 +5,58 @@ #ifndef CRYPTO_SIGNATURE_CREATOR_H_ #define CRYPTO_SIGNATURE_CREATOR_H_ -#include "build/build_config.h" - -#if defined(USE_OPENSSL) -// Forward declaration for openssl/*.h -typedef struct env_md_ctx_st EVP_MD_CTX; -#elif defined(USE_NSS) -// Forward declaration. -struct SGNContextStr; -#elif defined(OS_MACOSX) && !defined(OS_IOS) -#include <Security/cssm.h> -#endif - +#include <memory> #include <vector> -#include "base/basictypes.h" +#include "base/macros.h" +#include "build/build_config.h" #include "crypto/crypto_export.h" +#include "starboard/types.h" -#if defined(OS_WIN) -#include "crypto/scoped_capi_types.h" -#endif +// Forward declaration for openssl/*.h +typedef struct env_md_ctx_st EVP_MD_CTX; namespace crypto { class RSAPrivateKey; // Signs data using a bare private key (as opposed to a full certificate). -// Currently can only sign data using SHA-1 with RSA encryption. +// Currently can only sign data using SHA-1 or SHA-256 with RSA PKCS#1v1.5. class CRYPTO_EXPORT SignatureCreator { public: + // The set of supported hash functions. Extend as required. + enum HashAlgorithm { + SHA1, + SHA256, + }; + ~SignatureCreator(); // Create an instance. The caller must ensure that the provided PrivateKey - // instance outlives the created SignatureCreator. - static SignatureCreator* Create(RSAPrivateKey* key); + // instance outlives the created SignatureCreator. Uses the HashAlgorithm + // specified. + static std::unique_ptr<SignatureCreator> Create(RSAPrivateKey* key, + HashAlgorithm hash_alg); + + // Signs the precomputed |hash_alg| digest |data| using private |key| as + // specified in PKCS #1 v1.5. + static bool Sign(RSAPrivateKey* key, + HashAlgorithm hash_alg, + const uint8_t* data, + int data_len, + std::vector<uint8_t>* signature); // Update the signature with more data. - bool Update(const uint8* data_part, int data_part_len); + bool Update(const uint8_t* data_part, int data_part_len); // Finalize the signature. - bool Final(std::vector<uint8>* signature); + bool Final(std::vector<uint8_t>* signature); private: // Private constructor. Use the Create() method instead. SignatureCreator(); - RSAPrivateKey* key_; - -#if defined(USE_OPENSSL) EVP_MD_CTX* sign_context_; -#elif defined(USE_NSS) - SGNContextStr* sign_context_; -#elif defined(OS_MACOSX) && !defined(OS_IOS) - CSSM_CC_HANDLE sig_handle_; -#elif defined(OS_WIN) - ScopedHCRYPTHASH hash_object_; -#endif DISALLOW_COPY_AND_ASSIGN(SignatureCreator); };
diff --git a/src/crypto/signature_creator_mac.cc b/src/crypto/signature_creator_mac.cc deleted file mode 100644 index cdc34f8..0000000 --- a/src/crypto/signature_creator_mac.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/signature_creator.h" - -#include <stdlib.h> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "crypto/cssm_init.h" -#include "crypto/rsa_private_key.h" - -namespace crypto { - -// static -SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { - scoped_ptr<SignatureCreator> result(new SignatureCreator); - result->key_ = key; - - CSSM_RETURN crtn; - crtn = CSSM_CSP_CreateSignatureContext(GetSharedCSPHandle(), - CSSM_ALGID_SHA1WithRSA, - NULL, - key->key(), - &result->sig_handle_); - if (crtn) { - NOTREACHED(); - return NULL; - } - - crtn = CSSM_SignDataInit(result->sig_handle_); - if (crtn) { - NOTREACHED(); - return NULL; - } - - return result.release(); -} - -SignatureCreator::SignatureCreator() : key_(NULL), sig_handle_(0) { - EnsureCSSMInit(); -} - -SignatureCreator::~SignatureCreator() { - CSSM_RETURN crtn; - if (sig_handle_) { - crtn = CSSM_DeleteContext(sig_handle_); - DCHECK_EQ(CSSM_OK, crtn); - } -} - -bool SignatureCreator::Update(const uint8* data_part, int data_part_len) { - CSSM_DATA data; - data.Data = const_cast<uint8*>(data_part); - data.Length = data_part_len; - CSSM_RETURN crtn = CSSM_SignDataUpdate(sig_handle_, &data, 1); - DCHECK_EQ(CSSM_OK, crtn); - return true; -} - -bool SignatureCreator::Final(std::vector<uint8>* signature) { - ScopedCSSMData sig; - CSSM_RETURN crtn = CSSM_SignDataFinal(sig_handle_, sig); - - if (crtn) { - NOTREACHED(); - return false; - } - - signature->assign(sig->Data, sig->Data + sig->Length); - return true; -} - -} // namespace crypto
diff --git a/src/crypto/signature_creator_nss.cc b/src/crypto/signature_creator_nss.cc deleted file mode 100644 index 3a30efb..0000000 --- a/src/crypto/signature_creator_nss.cc +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/signature_creator.h" - -#include <cryptohi.h> -#include <keyhi.h> -#include <stdlib.h> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "crypto/nss_util.h" -#include "crypto/rsa_private_key.h" - -namespace crypto { - -SignatureCreator::~SignatureCreator() { - if (sign_context_) { - SGN_DestroyContext(sign_context_, PR_TRUE); - sign_context_ = NULL; - } -} - -// static -SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { - scoped_ptr<SignatureCreator> result(new SignatureCreator); - result->key_ = key; - - result->sign_context_ = SGN_NewContext(SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, - key->key()); - if (!result->sign_context_) { - NOTREACHED(); - return NULL; - } - - SECStatus rv = SGN_Begin(result->sign_context_); - if (rv != SECSuccess) { - NOTREACHED(); - return NULL; - } - - return result.release(); -} - -bool SignatureCreator::Update(const uint8* data_part, int data_part_len) { - // TODO(wtc): Remove this const_cast when we require NSS 3.12.5. - // See NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=518255 - SECStatus rv = SGN_Update(sign_context_, - const_cast<unsigned char*>(data_part), - data_part_len); - if (rv != SECSuccess) { - NOTREACHED(); - return false; - } - - return true; -} - -bool SignatureCreator::Final(std::vector<uint8>* signature) { - SECItem signature_item; - SECStatus rv = SGN_End(sign_context_, &signature_item); - if (rv != SECSuccess) { - NOTREACHED(); - return false; - } - signature->assign(signature_item.data, - signature_item.data + signature_item.len); - SECITEM_FreeItem(&signature_item, PR_FALSE); - return true; -} - -SignatureCreator::SignatureCreator() - : key_(NULL), - sign_context_(NULL) { - EnsureNSSInit(); -} - -} // namespace crypto
diff --git a/src/crypto/signature_creator_openssl.cc b/src/crypto/signature_creator_openssl.cc deleted file mode 100644 index fa9ba07..0000000 --- a/src/crypto/signature_creator_openssl.cc +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/signature_creator.h" - -#include <openssl/evp.h> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/stl_util.h" -#include "crypto/openssl_util.h" -#include "crypto/rsa_private_key.h" - -namespace crypto { - -// static -SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { - OpenSSLErrStackTracer err_tracer(FROM_HERE); - scoped_ptr<SignatureCreator> result(new SignatureCreator); - result->key_ = key; - if (!EVP_SignInit_ex(result->sign_context_, EVP_sha1(), NULL)) - return NULL; - return result.release(); -} - -SignatureCreator::SignatureCreator() - : sign_context_(EVP_MD_CTX_create()) { -} - -SignatureCreator::~SignatureCreator() { - EVP_MD_CTX_destroy(sign_context_); -} - -bool SignatureCreator::Update(const uint8* data_part, int data_part_len) { - OpenSSLErrStackTracer err_tracer(FROM_HERE); - return EVP_SignUpdate(sign_context_, data_part, data_part_len) == 1; -} - -bool SignatureCreator::Final(std::vector<uint8>* signature) { - OpenSSLErrStackTracer err_tracer(FROM_HERE); - EVP_PKEY* key = key_->key(); - signature->resize(EVP_PKEY_size(key)); - - unsigned int len = 0; - int rv = EVP_SignFinal(sign_context_, vector_as_array(signature), &len, key); - if (!rv) { - signature->clear(); - return false; - } - signature->resize(len); - return true; -} - -} // namespace crypto
diff --git a/src/crypto/signature_creator_unittest.cc b/src/crypto/signature_creator_unittest.cc index 881de91..053137b 100644 --- a/src/crypto/signature_creator_unittest.cc +++ b/src/crypto/signature_creator_unittest.cc
@@ -2,46 +2,115 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "crypto/signature_creator.h" + +#include <memory> +#include <string> #include <vector> -#include "base/memory/scoped_ptr.h" +#include "base/sha1.h" #include "crypto/rsa_private_key.h" -#include "crypto/signature_creator.h" +#include "crypto/sha2.h" #include "crypto/signature_verifier.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" TEST(SignatureCreatorTest, BasicTest) { // Do a verify round trip. - scoped_ptr<crypto::RSAPrivateKey> key_original( + std::unique_ptr<crypto::RSAPrivateKey> key_original( crypto::RSAPrivateKey::Create(1024)); ASSERT_TRUE(key_original.get()); - std::vector<uint8> key_info; + std::vector<uint8_t> key_info; key_original->ExportPrivateKey(&key_info); - scoped_ptr<crypto::RSAPrivateKey> key( + std::unique_ptr<crypto::RSAPrivateKey> key( crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info)); ASSERT_TRUE(key.get()); - scoped_ptr<crypto::SignatureCreator> signer( - crypto::SignatureCreator::Create(key.get())); + std::unique_ptr<crypto::SignatureCreator> signer( + crypto::SignatureCreator::Create(key.get(), + crypto::SignatureCreator::SHA1)); ASSERT_TRUE(signer.get()); std::string data("Hello, World!"); - ASSERT_TRUE(signer->Update(reinterpret_cast<const uint8*>(data.c_str()), + ASSERT_TRUE(signer->Update(reinterpret_cast<const uint8_t*>(data.c_str()), data.size())); - std::vector<uint8> signature; + std::vector<uint8_t> signature; ASSERT_TRUE(signer->Final(&signature)); - std::vector<uint8> public_key_info; + std::vector<uint8_t> public_key_info; ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info)); crypto::SignatureVerifier verifier; - ASSERT_TRUE(verifier.VerifyInit( - crypto::SignatureVerifier::RSA_PKCS1_SHA1, &signature.front(), - signature.size(), &public_key_info.front(), public_key_info.size())); + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, public_key_info)); - verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()), - data.size()); + verifier.VerifyUpdate(base::as_bytes(base::make_span(data))); + ASSERT_TRUE(verifier.VerifyFinal()); +} + +TEST(SignatureCreatorTest, SignDigestTest) { + // Do a verify round trip. + std::unique_ptr<crypto::RSAPrivateKey> key_original( + crypto::RSAPrivateKey::Create(1024)); + ASSERT_TRUE(key_original.get()); + + std::vector<uint8_t> key_info; + key_original->ExportPrivateKey(&key_info); + std::unique_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info)); + ASSERT_TRUE(key.get()); + + std::string data("Hello, World!"); + std::string sha1 = base::SHA1HashString(data); + // Sign sha1 of the input data. + std::vector<uint8_t> signature; + ASSERT_TRUE(crypto::SignatureCreator::Sign( + key.get(), crypto::SignatureCreator::SHA1, + reinterpret_cast<const uint8_t*>(sha1.c_str()), sha1.size(), &signature)); + + std::vector<uint8_t> public_key_info; + ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info)); + + // Verify the input data. + crypto::SignatureVerifier verifier; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, public_key_info)); + + verifier.VerifyUpdate(base::as_bytes(base::make_span(data))); + ASSERT_TRUE(verifier.VerifyFinal()); +} + +TEST(SignatureCreatorTest, SignSHA256DigestTest) { + // Do a verify round trip. + std::unique_ptr<crypto::RSAPrivateKey> key_original( + crypto::RSAPrivateKey::Create(1024)); + ASSERT_TRUE(key_original.get()); + + std::vector<uint8_t> key_info; + key_original->ExportPrivateKey(&key_info); + std::unique_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info)); + ASSERT_TRUE(key.get()); + + std::string data("Hello, World!"); + std::string sha256 = crypto::SHA256HashString(data); + // Sign sha256 of the input data. + std::vector<uint8_t> signature; + ASSERT_TRUE(crypto::SignatureCreator::Sign( + key.get(), crypto::SignatureCreator::HashAlgorithm::SHA256, + reinterpret_cast<const uint8_t*>(sha256.c_str()), sha256.size(), + &signature)); + + std::vector<uint8_t> public_key_info; + ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info)); + + // Verify the input data. + crypto::SignatureVerifier verifier; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA256, + signature, public_key_info)); + + verifier.VerifyUpdate(base::as_bytes(base::make_span(data))); ASSERT_TRUE(verifier.VerifyFinal()); }
diff --git a/src/crypto/signature_creator_win.cc b/src/crypto/signature_creator_win.cc deleted file mode 100644 index 69e6513..0000000 --- a/src/crypto/signature_creator_win.cc +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/signature_creator.h" - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "crypto/rsa_private_key.h" - -namespace crypto { - -// static -SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { - scoped_ptr<SignatureCreator> result(new SignatureCreator); - result->key_ = key; - - if (!CryptCreateHash(key->provider(), CALG_SHA1, 0, 0, - result->hash_object_.receive())) { - NOTREACHED(); - return NULL; - } - - return result.release(); -} - -SignatureCreator::SignatureCreator() : key_(NULL), hash_object_(0) {} - -SignatureCreator::~SignatureCreator() {} - -bool SignatureCreator::Update(const uint8* data_part, int data_part_len) { - if (!CryptHashData(hash_object_, data_part, data_part_len, 0)) { - NOTREACHED(); - return false; - } - - return true; -} - -bool SignatureCreator::Final(std::vector<uint8>* signature) { - DWORD signature_length = 0; - if (!CryptSignHash(hash_object_, AT_SIGNATURE, NULL, 0, NULL, - &signature_length)) { - return false; - } - - std::vector<uint8> temp; - temp.resize(signature_length); - if (!CryptSignHash(hash_object_, AT_SIGNATURE, NULL, 0, &temp.front(), - &signature_length)) { - return false; - } - - temp.resize(signature_length); - for (size_t i = temp.size(); i > 0; --i) - signature->push_back(temp[i - 1]); - - return true; -} - -} // namespace crypto
diff --git a/src/crypto/signature_verifier.cc b/src/crypto/signature_verifier.cc new file mode 100644 index 0000000..fd29bdf --- /dev/null +++ b/src/crypto/signature_verifier.cc
@@ -0,0 +1,104 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/signature_verifier.h" + +#include "base/logging.h" +#include "crypto/openssl_util.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" + +namespace crypto { + +struct SignatureVerifier::VerifyContext { + bssl::ScopedEVP_MD_CTX ctx; +}; + +SignatureVerifier::SignatureVerifier() = default; + +SignatureVerifier::~SignatureVerifier() = default; + +bool SignatureVerifier::VerifyInit(SignatureAlgorithm signature_algorithm, + base::span<const uint8_t> signature, + base::span<const uint8_t> public_key_info) { + OpenSSLErrStackTracer err_tracer(FROM_HERE); + + int pkey_type = EVP_PKEY_NONE; + const EVP_MD* digest = nullptr; + switch (signature_algorithm) { + case RSA_PKCS1_SHA1: + pkey_type = EVP_PKEY_RSA; + digest = EVP_sha1(); + break; + case RSA_PKCS1_SHA256: + case RSA_PSS_SHA256: + pkey_type = EVP_PKEY_RSA; + digest = EVP_sha256(); + break; + case ECDSA_SHA256: + pkey_type = EVP_PKEY_EC; + digest = EVP_sha256(); + break; + } + DCHECK_NE(EVP_PKEY_NONE, pkey_type); + DCHECK(digest); + + if (verify_context_) + return false; + + verify_context_.reset(new VerifyContext); + signature_.assign(signature.data(), signature.data() + signature.size()); + + CBS cbs; + CBS_init(&cbs, public_key_info.data(), public_key_info.size()); + bssl::UniquePtr<EVP_PKEY> public_key(EVP_parse_public_key(&cbs)); + if (!public_key || CBS_len(&cbs) != 0 || + EVP_PKEY_id(public_key.get()) != pkey_type) { + return false; + } + + EVP_PKEY_CTX* pkey_ctx; + if (!EVP_DigestVerifyInit(verify_context_->ctx.get(), &pkey_ctx, digest, + nullptr, public_key.get())) { + return false; + } + + if (signature_algorithm == RSA_PSS_SHA256) { + if (!EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, digest) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen( + pkey_ctx, -1 /* match digest and salt length */)) { + return false; + } + } + + return true; +} + +void SignatureVerifier::VerifyUpdate(base::span<const uint8_t> data_part) { + DCHECK(verify_context_); + OpenSSLErrStackTracer err_tracer(FROM_HERE); + int rv = EVP_DigestVerifyUpdate(verify_context_->ctx.get(), data_part.data(), + data_part.size()); + DCHECK_EQ(rv, 1); +} + +bool SignatureVerifier::VerifyFinal() { + DCHECK(verify_context_); + OpenSSLErrStackTracer err_tracer(FROM_HERE); + int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(), signature_.data(), + signature_.size()); + DCHECK_EQ(static_cast<int>(!!rv), rv); + Reset(); + return rv == 1; +} + +void SignatureVerifier::Reset() { + verify_context_.reset(); + signature_.clear(); +} + +} // namespace crypto
diff --git a/src/crypto/signature_verifier.h b/src/crypto/signature_verifier.h index e181330..02fc400 100644 --- a/src/crypto/signature_verifier.h +++ b/src/crypto/signature_verifier.h
@@ -5,16 +5,13 @@ #ifndef CRYPTO_SIGNATURE_VERIFIER_H_ #define CRYPTO_SIGNATURE_VERIFIER_H_ -#include "build/build_config.h" - +#include <memory> #include <vector> -#include "base/basictypes.h" +#include "base/containers/span.h" +#include "build/build_config.h" #include "crypto/crypto_export.h" - -#if !defined(USE_OPENSSL) -typedef struct VFYContextStr VFYContext; -#endif +#include "starboard/types.h" namespace crypto { @@ -22,19 +19,24 @@ // (as opposed to a certificate). class CRYPTO_EXPORT SignatureVerifier { public: - SignatureVerifier(); - ~SignatureVerifier(); - + // The set of supported signature algorithms. Extend as required. enum SignatureAlgorithm { RSA_PKCS1_SHA1, RSA_PKCS1_SHA256, ECDSA_SHA256, + // This is RSA-PSS with SHA-256 as both signing hash and MGF-1 hash, and the + // salt length matching the hash length. + RSA_PSS_SHA256, }; + SignatureVerifier(); + ~SignatureVerifier(); + // Streaming interface: // Initiates a signature verification operation. This should be followed // by one or more VerifyUpdate calls and a VerifyFinal call. + // // The signature is encoded according to the signature algorithm. // // The public key is specified as a DER encoded ASN.1 SubjectPublicKeyInfo @@ -44,40 +46,24 @@ // algorithm AlgorithmIdentifier, // subjectPublicKey BIT STRING } bool VerifyInit(SignatureAlgorithm signature_algorithm, - const uint8* signature, - int signature_len, - const uint8* public_key_info, - int public_key_info_len); + base::span<const uint8_t> signature, + base::span<const uint8_t> public_key_info); // Feeds a piece of the data to the signature verifier. - void VerifyUpdate(const uint8* data_part, int data_part_len); + void VerifyUpdate(base::span<const uint8_t> data_part); // Concludes a signature verification operation. Returns true if the // signature is valid. Returns false if the signature is invalid or an // error occurred. bool VerifyFinal(); - // Note: we can provide a one-shot interface if there is interest: - // bool Verify(const uint8* data, - // int data_len, - // const uint8* signature_algorithm, - // int signature_algorithm_len, - // const uint8* signature, - // int signature_len, - // const uint8* public_key_info, - // int public_key_info_len); - private: void Reset(); - std::vector<uint8> signature_; + std::vector<uint8_t> signature_; -#if defined(USE_OPENSSL) struct VerifyContext; - VerifyContext* verify_context_; -#else - VFYContext* vfy_context_; -#endif + std::unique_ptr<VerifyContext> verify_context_; }; } // namespace crypto
diff --git a/src/crypto/signature_verifier_nss.cc b/src/crypto/signature_verifier_nss.cc deleted file mode 100644 index 662e8f2..0000000 --- a/src/crypto/signature_verifier_nss.cc +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/signature_verifier.h" - -#include <cryptohi.h> -#include <keyhi.h> -#include <stdlib.h> - -#include "base/logging.h" -#include "crypto/nss_util.h" - -namespace crypto { - -SignatureVerifier::SignatureVerifier() : vfy_context_(NULL) { - EnsureNSSInit(); -} - -SignatureVerifier::~SignatureVerifier() { - Reset(); -} - -bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, - int signature_algorithm_len, - const uint8* signature, - int signature_len, - const uint8* public_key_info, - int public_key_info_len) { - signature_.assign(signature, signature + signature_len); - - CERTSubjectPublicKeyInfo* spki = NULL; - SECItem spki_der; - spki_der.type = siBuffer; - spki_der.data = const_cast<uint8*>(public_key_info); - spki_der.len = public_key_info_len; - spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der); - if (!spki) - return false; - SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki); - SECKEY_DestroySubjectPublicKeyInfo(spki); // Done with spki. - if (!public_key) - return false; - - PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (!arena) { - SECKEY_DestroyPublicKey(public_key); - return false; - } - - SECItem sig_alg_der; - sig_alg_der.type = siBuffer; - sig_alg_der.data = const_cast<uint8*>(signature_algorithm); - sig_alg_der.len = signature_algorithm_len; - SECAlgorithmID sig_alg_id; - SECStatus rv; - rv = SEC_QuickDERDecodeItem(arena, &sig_alg_id, - SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), - &sig_alg_der); - if (rv != SECSuccess) { - SECKEY_DestroyPublicKey(public_key); - PORT_FreeArena(arena, PR_TRUE); - return false; - } - - SECItem sig; - sig.type = siBuffer; - sig.data = const_cast<uint8*>(signature); - sig.len = signature_len; - SECOidTag hash_alg_tag; - vfy_context_ = VFY_CreateContextWithAlgorithmID(public_key, &sig, - &sig_alg_id, &hash_alg_tag, - NULL); - SECKEY_DestroyPublicKey(public_key); // Done with public_key. - PORT_FreeArena(arena, PR_TRUE); // Done with sig_alg_id. - if (!vfy_context_) { - // A corrupted RSA signature could be detected without the data, so - // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE - // (-8182). - return false; - } - - rv = VFY_Begin(vfy_context_); - if (rv != SECSuccess) { - NOTREACHED(); - return false; - } - return true; -} - -void SignatureVerifier::VerifyUpdate(const uint8* data_part, - int data_part_len) { - SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len); - DCHECK_EQ(SECSuccess, rv); -} - -bool SignatureVerifier::VerifyFinal() { - SECStatus rv = VFY_End(vfy_context_); - Reset(); - - // If signature verification fails, the error code is - // SEC_ERROR_BAD_SIGNATURE (-8182). - return (rv == SECSuccess); -} - -void SignatureVerifier::Reset() { - if (vfy_context_) { - VFY_DestroyContext(vfy_context_, PR_TRUE); - vfy_context_ = NULL; - } - signature_.clear(); -} - -} // namespace crypto
diff --git a/src/crypto/signature_verifier_openssl.cc b/src/crypto/signature_verifier_openssl.cc deleted file mode 100644 index 112c4e3..0000000 --- a/src/crypto/signature_verifier_openssl.cc +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/signature_verifier.h" - -#include <openssl/evp.h> -#include <openssl/x509.h> - -#include <vector> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/stl_util.h" -#include "crypto/openssl_util.h" - -namespace crypto { - -struct SignatureVerifier::VerifyContext { - ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> public_key; - ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> ctx; -}; - -SignatureVerifier::SignatureVerifier() - : verify_context_(NULL) { -} - -SignatureVerifier::~SignatureVerifier() { - Reset(); -} - -bool SignatureVerifier::VerifyInit(SignatureAlgorithm signature_algorithm, - const uint8* signature, - int signature_len, - const uint8* public_key_info, - int public_key_info_len) { - DCHECK(!verify_context_); - verify_context_ = new VerifyContext; - OpenSSLErrStackTracer err_tracer(FROM_HERE); - - const EVP_MD* digest = nullptr; - switch (signature_algorithm) { - case RSA_PKCS1_SHA1: - digest = EVP_sha1(); - break; - case RSA_PKCS1_SHA256: - digest = EVP_sha256(); - break; - case ECDSA_SHA256: - digest = EVP_sha256(); - break; - } - DCHECK(digest); - - signature_.assign(signature, signature + signature_len); - - // BIO_new_mem_buf is not const aware, but it does not modify the buffer. - char* data = reinterpret_cast<char*>(const_cast<uint8*>(public_key_info)); - ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(data, - public_key_info_len)); - if (!bio.get()) - return false; - - verify_context_->public_key.reset(d2i_PUBKEY_bio(bio.get(), NULL)); - if (!verify_context_->public_key.get()) - return false; - - verify_context_->ctx.reset(EVP_MD_CTX_create()); - int rv = EVP_VerifyInit_ex(verify_context_->ctx.get(), digest, NULL); - return rv == 1; -} - -void SignatureVerifier::VerifyUpdate(const uint8* data_part, - int data_part_len) { - DCHECK(verify_context_); - OpenSSLErrStackTracer err_tracer(FROM_HERE); - int rv = EVP_VerifyUpdate(verify_context_->ctx.get(), - data_part, data_part_len); - DCHECK_EQ(rv, 1); -} - -bool SignatureVerifier::VerifyFinal() { - DCHECK(verify_context_); - OpenSSLErrStackTracer err_tracer(FROM_HERE); - int rv = EVP_VerifyFinal(verify_context_->ctx.get(), - vector_as_array(&signature_), signature_.size(), - verify_context_->public_key.get()); - DCHECK_GE(rv, 0); - Reset(); - return rv == 1; -} - -void SignatureVerifier::Reset() { - delete verify_context_; - verify_context_ = NULL; - signature_.clear(); -} - -} // namespace crypto
diff --git a/src/crypto/signature_verifier_unittest.cc b/src/crypto/signature_verifier_unittest.cc index a694a1f..58d5d3a 100644 --- a/src/crypto/signature_verifier_unittest.cc +++ b/src/crypto/signature_verifier_unittest.cc
@@ -3,14 +3,20 @@ // found in the LICENSE file. #include "crypto/signature_verifier.h" + +#include "base/logging.h" +#include "base/macros.h" +#include "base/numerics/safe_conversions.h" +#include "starboard/memory.h" +#include "starboard/types.h" #include "testing/gtest/include/gtest/gtest.h" TEST(SignatureVerifierTest, BasicTest) { // The input data in this test comes from real certificates. // - // tbs_certificate ("to-be-signed certificate", the part of a certificate - // that is signed), signature_algorithm, and algorithm come from the - // certificate of bugs.webkit.org. + // tbs_certificate ("to-be-signed certificate", the part of a certificate that + // is signed), signature, and algorithm come from the certificate of + // bugs.webkit.org. // // public_key_info comes from the certificate of the issuer, Go Daddy Secure // Certification Authority. @@ -22,221 +28,383 @@ // TBSCertificate ::= SEQUENCE { // ... -- omitted, not important // } - const uint8 tbs_certificate[1017] = { - 0x30, 0x82, 0x03, 0xf5, // a SEQUENCE of length 1013 (0x3f5) - 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x43, 0xdd, 0x63, 0x30, 0x0d, - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, - 0x00, 0x30, 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, - 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, - 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, - 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, - 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, - 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, - 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, - 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, - 0x69, 0x74, 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, - 0x04, 0x03, 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, - 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, - 0x03, 0x55, 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, - 0x38, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x31, 0x38, - 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, - 0x33, 0x31, 0x38, 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x30, 0x79, - 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, - 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, - 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x12, - 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x43, 0x75, 0x70, - 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, - 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, - 0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b, - 0x13, 0x0c, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x46, 0x6f, 0x72, - 0x67, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, - 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72, - 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, - 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa7, 0x62, 0x79, 0x41, 0xda, 0x28, - 0xf2, 0xc0, 0x4f, 0xe0, 0x25, 0xaa, 0xa1, 0x2e, 0x3b, 0x30, 0x94, 0xb5, - 0xc9, 0x26, 0x3a, 0x1b, 0xe2, 0xd0, 0xcc, 0xa2, 0x95, 0xe2, 0x91, 0xc0, - 0xf0, 0x40, 0x9e, 0x27, 0x6e, 0xbd, 0x6e, 0xde, 0x7c, 0xb6, 0x30, 0x5c, - 0xb8, 0x9b, 0x01, 0x2f, 0x92, 0x04, 0xa1, 0xef, 0x4a, 0xb1, 0x6c, 0xb1, - 0x7e, 0x8e, 0xcd, 0xa6, 0xf4, 0x40, 0x73, 0x1f, 0x2c, 0x96, 0xad, 0xff, - 0x2a, 0x6d, 0x0e, 0xba, 0x52, 0x84, 0x83, 0xb0, 0x39, 0xee, 0xc9, 0x39, - 0xdc, 0x1e, 0x34, 0xd0, 0xd8, 0x5d, 0x7a, 0x09, 0xac, 0xa9, 0xee, 0xca, - 0x65, 0xf6, 0x85, 0x3a, 0x6b, 0xee, 0xe4, 0x5c, 0x5e, 0xf8, 0xda, 0xd1, - 0xce, 0x88, 0x47, 0xcd, 0x06, 0x21, 0xe0, 0xb9, 0x4b, 0xe4, 0x07, 0xcb, - 0x57, 0xdc, 0xca, 0x99, 0x54, 0xf7, 0x0e, 0xd5, 0x17, 0x95, 0x05, 0x2e, - 0xe9, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xce, 0x30, - 0x82, 0x01, 0xca, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, - 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, - 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, - 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, - 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x57, - 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x50, 0x30, 0x4e, 0x30, 0x4c, 0xa0, - 0x4a, 0xa0, 0x48, 0x86, 0x46, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, - 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, - 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x65, 0x78, 0x74, 0x65, 0x6e, - 0x64, 0x65, 0x64, 0x69, 0x73, 0x73, 0x75, 0x69, 0x6e, 0x67, 0x33, 0x2e, - 0x63, 0x72, 0x6c, 0x30, 0x52, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4b, - 0x30, 0x49, 0x30, 0x47, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, - 0x6d, 0x01, 0x07, 0x17, 0x02, 0x30, 0x38, 0x30, 0x36, 0x06, 0x08, 0x2b, - 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2a, 0x68, 0x74, 0x74, - 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, - 0x6f, 0x72, 0x79, 0x30, 0x7f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, - 0x07, 0x01, 0x01, 0x04, 0x73, 0x30, 0x71, 0x30, 0x23, 0x06, 0x08, 0x2b, - 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, - 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, - 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4a, 0x06, 0x08, - 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, 0x74, - 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, - 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x74, - 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x48, - 0xdf, 0x60, 0x32, 0xcc, 0x89, 0x01, 0xb6, 0xdc, 0x2f, 0xe3, 0x73, 0xb5, - 0x9c, 0x16, 0x58, 0x32, 0x68, 0xa9, 0xc3, 0x30, 0x1f, 0x06, 0x03, 0x55, - 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, - 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee, 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, - 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, - 0x1c, 0x30, 0x1a, 0x82, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, - 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x0a, 0x77, 0x65, 0x62, 0x6b, 0x69, - 0x74, 0x2e, 0x6f, 0x72, 0x67 - }; + const uint8_t tbs_certificate[1017] = { + 0x30, 0x82, 0x03, 0xf5, // a SEQUENCE of length 1013 (0x3f5) + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x43, 0xdd, 0x63, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, + 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, + 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, + 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, + 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, + 0x38, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x31, 0x38, + 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, + 0x33, 0x31, 0x38, 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x30, 0x79, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, + 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x43, 0x75, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x0c, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x46, 0x6f, 0x72, + 0x67, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72, + 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, + 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa7, 0x62, 0x79, 0x41, 0xda, 0x28, + 0xf2, 0xc0, 0x4f, 0xe0, 0x25, 0xaa, 0xa1, 0x2e, 0x3b, 0x30, 0x94, 0xb5, + 0xc9, 0x26, 0x3a, 0x1b, 0xe2, 0xd0, 0xcc, 0xa2, 0x95, 0xe2, 0x91, 0xc0, + 0xf0, 0x40, 0x9e, 0x27, 0x6e, 0xbd, 0x6e, 0xde, 0x7c, 0xb6, 0x30, 0x5c, + 0xb8, 0x9b, 0x01, 0x2f, 0x92, 0x04, 0xa1, 0xef, 0x4a, 0xb1, 0x6c, 0xb1, + 0x7e, 0x8e, 0xcd, 0xa6, 0xf4, 0x40, 0x73, 0x1f, 0x2c, 0x96, 0xad, 0xff, + 0x2a, 0x6d, 0x0e, 0xba, 0x52, 0x84, 0x83, 0xb0, 0x39, 0xee, 0xc9, 0x39, + 0xdc, 0x1e, 0x34, 0xd0, 0xd8, 0x5d, 0x7a, 0x09, 0xac, 0xa9, 0xee, 0xca, + 0x65, 0xf6, 0x85, 0x3a, 0x6b, 0xee, 0xe4, 0x5c, 0x5e, 0xf8, 0xda, 0xd1, + 0xce, 0x88, 0x47, 0xcd, 0x06, 0x21, 0xe0, 0xb9, 0x4b, 0xe4, 0x07, 0xcb, + 0x57, 0xdc, 0xca, 0x99, 0x54, 0xf7, 0x0e, 0xd5, 0x17, 0x95, 0x05, 0x2e, + 0xe9, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xce, 0x30, + 0x82, 0x01, 0xca, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, + 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, + 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x57, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x50, 0x30, 0x4e, 0x30, 0x4c, 0xa0, + 0x4a, 0xa0, 0x48, 0x86, 0x46, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x69, 0x73, 0x73, 0x75, 0x69, 0x6e, 0x67, 0x33, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x52, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4b, + 0x30, 0x49, 0x30, 0x47, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, + 0x6d, 0x01, 0x07, 0x17, 0x02, 0x30, 0x38, 0x30, 0x36, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2a, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x30, 0x7f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x73, 0x30, 0x71, 0x30, 0x23, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, + 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4a, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x74, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x48, + 0xdf, 0x60, 0x32, 0xcc, 0x89, 0x01, 0xb6, 0xdc, 0x2f, 0xe3, 0x73, 0xb5, + 0x9c, 0x16, 0x58, 0x32, 0x68, 0xa9, 0xc3, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, + 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee, 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, + 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, + 0x1c, 0x30, 0x1a, 0x82, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, + 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x0a, 0x77, 0x65, 0x62, 0x6b, 0x69, + 0x74, 0x2e, 0x6f, 0x72, 0x67}; // RSA signature, a big integer in the big-endian byte order. - const uint8 signature[256] = { - 0x1e, 0x6a, 0xe7, 0xe0, 0x4f, 0xe7, 0x4d, 0xd0, 0x69, 0x7c, 0xf8, 0x8f, - 0x99, 0xb4, 0x18, 0x95, 0x36, 0x24, 0x0f, 0x0e, 0xa3, 0xea, 0x34, 0x37, - 0xf4, 0x7d, 0xd5, 0x92, 0x35, 0x53, 0x72, 0x76, 0x3f, 0x69, 0xf0, 0x82, - 0x56, 0xe3, 0x94, 0x7a, 0x1d, 0x1a, 0x81, 0xaf, 0x9f, 0xc7, 0x43, 0x01, - 0x64, 0xd3, 0x7c, 0x0d, 0xc8, 0x11, 0x4e, 0x4a, 0xe6, 0x1a, 0xc3, 0x01, - 0x74, 0xe8, 0x35, 0x87, 0x5c, 0x61, 0xaa, 0x8a, 0x46, 0x06, 0xbe, 0x98, - 0x95, 0x24, 0x9e, 0x01, 0xe3, 0xe6, 0xa0, 0x98, 0xee, 0x36, 0x44, 0x56, - 0x8d, 0x23, 0x9c, 0x65, 0xea, 0x55, 0x6a, 0xdf, 0x66, 0xee, 0x45, 0xe8, - 0xa0, 0xe9, 0x7d, 0x9a, 0xba, 0x94, 0xc5, 0xc8, 0xc4, 0x4b, 0x98, 0xff, - 0x9a, 0x01, 0x31, 0x6d, 0xf9, 0x2b, 0x58, 0xe7, 0xe7, 0x2a, 0xc5, 0x4d, - 0xbb, 0xbb, 0xcd, 0x0d, 0x70, 0xe1, 0xad, 0x03, 0xf5, 0xfe, 0xf4, 0x84, - 0x71, 0x08, 0xd2, 0xbc, 0x04, 0x7b, 0x26, 0x1c, 0xa8, 0x0f, 0x9c, 0xd8, - 0x12, 0x6a, 0x6f, 0x2b, 0x67, 0xa1, 0x03, 0x80, 0x9a, 0x11, 0x0b, 0xe9, - 0xe0, 0xb5, 0xb3, 0xb8, 0x19, 0x4e, 0x0c, 0xa4, 0xd9, 0x2b, 0x3b, 0xc2, - 0xca, 0x20, 0xd3, 0x0c, 0xa4, 0xff, 0x93, 0x13, 0x1f, 0xfc, 0xba, 0x94, - 0x93, 0x8c, 0x64, 0x15, 0x2e, 0x28, 0xa9, 0x55, 0x8c, 0x2c, 0x48, 0xd3, - 0xd3, 0xc1, 0x50, 0x69, 0x19, 0xe8, 0x34, 0xd3, 0xf1, 0x04, 0x9f, 0x0a, - 0x7a, 0x21, 0x87, 0xbf, 0xb9, 0x59, 0x37, 0x2e, 0xf4, 0x71, 0xa5, 0x3e, - 0xbe, 0xcd, 0x70, 0x83, 0x18, 0xf8, 0x8a, 0x72, 0x85, 0x45, 0x1f, 0x08, - 0x01, 0x6f, 0x37, 0xf5, 0x2b, 0x7b, 0xea, 0xb9, 0x8b, 0xa3, 0xcc, 0xfd, - 0x35, 0x52, 0xdd, 0x66, 0xde, 0x4f, 0x30, 0xc5, 0x73, 0x81, 0xb6, 0xe8, - 0x3c, 0xd8, 0x48, 0x8a - }; + const uint8_t signature[256] = { + 0x1e, 0x6a, 0xe7, 0xe0, 0x4f, 0xe7, 0x4d, 0xd0, 0x69, 0x7c, 0xf8, 0x8f, + 0x99, 0xb4, 0x18, 0x95, 0x36, 0x24, 0x0f, 0x0e, 0xa3, 0xea, 0x34, 0x37, + 0xf4, 0x7d, 0xd5, 0x92, 0x35, 0x53, 0x72, 0x76, 0x3f, 0x69, 0xf0, 0x82, + 0x56, 0xe3, 0x94, 0x7a, 0x1d, 0x1a, 0x81, 0xaf, 0x9f, 0xc7, 0x43, 0x01, + 0x64, 0xd3, 0x7c, 0x0d, 0xc8, 0x11, 0x4e, 0x4a, 0xe6, 0x1a, 0xc3, 0x01, + 0x74, 0xe8, 0x35, 0x87, 0x5c, 0x61, 0xaa, 0x8a, 0x46, 0x06, 0xbe, 0x98, + 0x95, 0x24, 0x9e, 0x01, 0xe3, 0xe6, 0xa0, 0x98, 0xee, 0x36, 0x44, 0x56, + 0x8d, 0x23, 0x9c, 0x65, 0xea, 0x55, 0x6a, 0xdf, 0x66, 0xee, 0x45, 0xe8, + 0xa0, 0xe9, 0x7d, 0x9a, 0xba, 0x94, 0xc5, 0xc8, 0xc4, 0x4b, 0x98, 0xff, + 0x9a, 0x01, 0x31, 0x6d, 0xf9, 0x2b, 0x58, 0xe7, 0xe7, 0x2a, 0xc5, 0x4d, + 0xbb, 0xbb, 0xcd, 0x0d, 0x70, 0xe1, 0xad, 0x03, 0xf5, 0xfe, 0xf4, 0x84, + 0x71, 0x08, 0xd2, 0xbc, 0x04, 0x7b, 0x26, 0x1c, 0xa8, 0x0f, 0x9c, 0xd8, + 0x12, 0x6a, 0x6f, 0x2b, 0x67, 0xa1, 0x03, 0x80, 0x9a, 0x11, 0x0b, 0xe9, + 0xe0, 0xb5, 0xb3, 0xb8, 0x19, 0x4e, 0x0c, 0xa4, 0xd9, 0x2b, 0x3b, 0xc2, + 0xca, 0x20, 0xd3, 0x0c, 0xa4, 0xff, 0x93, 0x13, 0x1f, 0xfc, 0xba, 0x94, + 0x93, 0x8c, 0x64, 0x15, 0x2e, 0x28, 0xa9, 0x55, 0x8c, 0x2c, 0x48, 0xd3, + 0xd3, 0xc1, 0x50, 0x69, 0x19, 0xe8, 0x34, 0xd3, 0xf1, 0x04, 0x9f, 0x0a, + 0x7a, 0x21, 0x87, 0xbf, 0xb9, 0x59, 0x37, 0x2e, 0xf4, 0x71, 0xa5, 0x3e, + 0xbe, 0xcd, 0x70, 0x83, 0x18, 0xf8, 0x8a, 0x72, 0x85, 0x45, 0x1f, 0x08, + 0x01, 0x6f, 0x37, 0xf5, 0x2b, 0x7b, 0xea, 0xb9, 0x8b, 0xa3, 0xcc, 0xfd, + 0x35, 0x52, 0xdd, 0x66, 0xde, 0x4f, 0x30, 0xc5, 0x73, 0x81, 0xb6, 0xe8, + 0x3c, 0xd8, 0x48, 0x8a}; // The public key is specified as the following ASN.1 structure: // SubjectPublicKeyInfo ::= SEQUENCE { // algorithm AlgorithmIdentifier, // subjectPublicKey BIT STRING } - const uint8 public_key_info[294] = { - 0x30, 0x82, 0x01, 0x22, // a SEQUENCE of length 290 (0x122) + const uint8_t public_key_info[294] = { + 0x30, 0x82, 0x01, 0x22, // a SEQUENCE of length 290 (0x122) // algorithm 0x30, 0x0d, // a SEQUENCE of length 13 - 0x06, 0x09, // an OBJECT IDENTIFIER of length 9 - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, - 0x05, 0x00, // a NULL of length 0 + 0x06, 0x09, // an OBJECT IDENTIFIER of length 9 + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, // a NULL of length 0 // subjectPublicKey 0x03, 0x82, 0x01, 0x0f, // a BIT STRING of length 271 (0x10f) - 0x00, // number of unused bits - 0x30, 0x82, 0x01, 0x0a, // a SEQUENCE of length 266 (0x10a) - // modulus - 0x02, 0x82, 0x01, 0x01, // an INTEGER of length 257 (0x101) - 0x00, 0xc4, 0x2d, 0xd5, 0x15, 0x8c, 0x9c, 0x26, 0x4c, 0xec, - 0x32, 0x35, 0xeb, 0x5f, 0xb8, 0x59, 0x01, 0x5a, 0xa6, 0x61, - 0x81, 0x59, 0x3b, 0x70, 0x63, 0xab, 0xe3, 0xdc, 0x3d, 0xc7, - 0x2a, 0xb8, 0xc9, 0x33, 0xd3, 0x79, 0xe4, 0x3a, 0xed, 0x3c, - 0x30, 0x23, 0x84, 0x8e, 0xb3, 0x30, 0x14, 0xb6, 0xb2, 0x87, - 0xc3, 0x3d, 0x95, 0x54, 0x04, 0x9e, 0xdf, 0x99, 0xdd, 0x0b, - 0x25, 0x1e, 0x21, 0xde, 0x65, 0x29, 0x7e, 0x35, 0xa8, 0xa9, - 0x54, 0xeb, 0xf6, 0xf7, 0x32, 0x39, 0xd4, 0x26, 0x55, 0x95, - 0xad, 0xef, 0xfb, 0xfe, 0x58, 0x86, 0xd7, 0x9e, 0xf4, 0x00, - 0x8d, 0x8c, 0x2a, 0x0c, 0xbd, 0x42, 0x04, 0xce, 0xa7, 0x3f, - 0x04, 0xf6, 0xee, 0x80, 0xf2, 0xaa, 0xef, 0x52, 0xa1, 0x69, - 0x66, 0xda, 0xbe, 0x1a, 0xad, 0x5d, 0xda, 0x2c, 0x66, 0xea, - 0x1a, 0x6b, 0xbb, 0xe5, 0x1a, 0x51, 0x4a, 0x00, 0x2f, 0x48, - 0xc7, 0x98, 0x75, 0xd8, 0xb9, 0x29, 0xc8, 0xee, 0xf8, 0x66, - 0x6d, 0x0a, 0x9c, 0xb3, 0xf3, 0xfc, 0x78, 0x7c, 0xa2, 0xf8, - 0xa3, 0xf2, 0xb5, 0xc3, 0xf3, 0xb9, 0x7a, 0x91, 0xc1, 0xa7, - 0xe6, 0x25, 0x2e, 0x9c, 0xa8, 0xed, 0x12, 0x65, 0x6e, 0x6a, - 0xf6, 0x12, 0x44, 0x53, 0x70, 0x30, 0x95, 0xc3, 0x9c, 0x2b, - 0x58, 0x2b, 0x3d, 0x08, 0x74, 0x4a, 0xf2, 0xbe, 0x51, 0xb0, - 0xbf, 0x87, 0xd0, 0x4c, 0x27, 0x58, 0x6b, 0xb5, 0x35, 0xc5, - 0x9d, 0xaf, 0x17, 0x31, 0xf8, 0x0b, 0x8f, 0xee, 0xad, 0x81, - 0x36, 0x05, 0x89, 0x08, 0x98, 0xcf, 0x3a, 0xaf, 0x25, 0x87, - 0xc0, 0x49, 0xea, 0xa7, 0xfd, 0x67, 0xf7, 0x45, 0x8e, 0x97, - 0xcc, 0x14, 0x39, 0xe2, 0x36, 0x85, 0xb5, 0x7e, 0x1a, 0x37, - 0xfd, 0x16, 0xf6, 0x71, 0x11, 0x9a, 0x74, 0x30, 0x16, 0xfe, - 0x13, 0x94, 0xa3, 0x3f, 0x84, 0x0d, 0x4f, - // public exponent - 0x02, 0x03, // an INTEGER of length 3 - 0x01, 0x00, 0x01 - }; + 0x00, // number of unused bits + 0x30, 0x82, 0x01, 0x0a, // a SEQUENCE of length 266 (0x10a) + // modulus + 0x02, 0x82, 0x01, 0x01, // an INTEGER of length 257 (0x101) + 0x00, 0xc4, 0x2d, 0xd5, 0x15, 0x8c, 0x9c, 0x26, 0x4c, 0xec, 0x32, 0x35, + 0xeb, 0x5f, 0xb8, 0x59, 0x01, 0x5a, 0xa6, 0x61, 0x81, 0x59, 0x3b, 0x70, + 0x63, 0xab, 0xe3, 0xdc, 0x3d, 0xc7, 0x2a, 0xb8, 0xc9, 0x33, 0xd3, 0x79, + 0xe4, 0x3a, 0xed, 0x3c, 0x30, 0x23, 0x84, 0x8e, 0xb3, 0x30, 0x14, 0xb6, + 0xb2, 0x87, 0xc3, 0x3d, 0x95, 0x54, 0x04, 0x9e, 0xdf, 0x99, 0xdd, 0x0b, + 0x25, 0x1e, 0x21, 0xde, 0x65, 0x29, 0x7e, 0x35, 0xa8, 0xa9, 0x54, 0xeb, + 0xf6, 0xf7, 0x32, 0x39, 0xd4, 0x26, 0x55, 0x95, 0xad, 0xef, 0xfb, 0xfe, + 0x58, 0x86, 0xd7, 0x9e, 0xf4, 0x00, 0x8d, 0x8c, 0x2a, 0x0c, 0xbd, 0x42, + 0x04, 0xce, 0xa7, 0x3f, 0x04, 0xf6, 0xee, 0x80, 0xf2, 0xaa, 0xef, 0x52, + 0xa1, 0x69, 0x66, 0xda, 0xbe, 0x1a, 0xad, 0x5d, 0xda, 0x2c, 0x66, 0xea, + 0x1a, 0x6b, 0xbb, 0xe5, 0x1a, 0x51, 0x4a, 0x00, 0x2f, 0x48, 0xc7, 0x98, + 0x75, 0xd8, 0xb9, 0x29, 0xc8, 0xee, 0xf8, 0x66, 0x6d, 0x0a, 0x9c, 0xb3, + 0xf3, 0xfc, 0x78, 0x7c, 0xa2, 0xf8, 0xa3, 0xf2, 0xb5, 0xc3, 0xf3, 0xb9, + 0x7a, 0x91, 0xc1, 0xa7, 0xe6, 0x25, 0x2e, 0x9c, 0xa8, 0xed, 0x12, 0x65, + 0x6e, 0x6a, 0xf6, 0x12, 0x44, 0x53, 0x70, 0x30, 0x95, 0xc3, 0x9c, 0x2b, + 0x58, 0x2b, 0x3d, 0x08, 0x74, 0x4a, 0xf2, 0xbe, 0x51, 0xb0, 0xbf, 0x87, + 0xd0, 0x4c, 0x27, 0x58, 0x6b, 0xb5, 0x35, 0xc5, 0x9d, 0xaf, 0x17, 0x31, + 0xf8, 0x0b, 0x8f, 0xee, 0xad, 0x81, 0x36, 0x05, 0x89, 0x08, 0x98, 0xcf, + 0x3a, 0xaf, 0x25, 0x87, 0xc0, 0x49, 0xea, 0xa7, 0xfd, 0x67, 0xf7, 0x45, + 0x8e, 0x97, 0xcc, 0x14, 0x39, 0xe2, 0x36, 0x85, 0xb5, 0x7e, 0x1a, 0x37, + 0xfd, 0x16, 0xf6, 0x71, 0x11, 0x9a, 0x74, 0x30, 0x16, 0xfe, 0x13, 0x94, + 0xa3, 0x3f, 0x84, 0x0d, 0x4f, + // public exponent + 0x02, 0x03, // an INTEGER of length 3 + 0x01, 0x00, 0x01}; // We use the signature verifier to perform four signature verification // tests. crypto::SignatureVerifier verifier; - bool ok; - // Test 1: feed all of the data to the verifier at once (a single + // Test 1: feed all of the data to the verifier at once (a single // VerifyUpdate call). - ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature, - sizeof(signature), public_key_info, - sizeof(public_key_info)); - EXPECT_TRUE(ok); - verifier.VerifyUpdate(tbs_certificate, sizeof(tbs_certificate)); - ok = verifier.VerifyFinal(); - EXPECT_TRUE(ok); + EXPECT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, public_key_info)); + verifier.VerifyUpdate(tbs_certificate); + EXPECT_TRUE(verifier.VerifyFinal()); // Test 2: feed the data to the verifier in three parts (three VerifyUpdate // calls). - ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature, - sizeof(signature), public_key_info, - sizeof(public_key_info)); - EXPECT_TRUE(ok); - verifier.VerifyUpdate(tbs_certificate, 256); - verifier.VerifyUpdate(tbs_certificate + 256, 256); - verifier.VerifyUpdate(tbs_certificate + 512, sizeof(tbs_certificate) - 512); - ok = verifier.VerifyFinal(); - EXPECT_TRUE(ok); + EXPECT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, public_key_info)); + verifier.VerifyUpdate(base::make_span(tbs_certificate, 256)); + verifier.VerifyUpdate(base::make_span(tbs_certificate + 256, 256)); + verifier.VerifyUpdate( + base::make_span(tbs_certificate + 512, sizeof(tbs_certificate) - 512)); + EXPECT_TRUE(verifier.VerifyFinal()); // Test 3: verify the signature with incorrect data. - uint8 bad_tbs_certificate[sizeof(tbs_certificate)]; - memcpy(bad_tbs_certificate, tbs_certificate, sizeof(tbs_certificate)); + uint8_t bad_tbs_certificate[sizeof(tbs_certificate)]; + SbMemoryCopy(bad_tbs_certificate, tbs_certificate, sizeof(tbs_certificate)); bad_tbs_certificate[10] += 1; // Corrupt one byte of the data. - ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature, - sizeof(signature), public_key_info, - sizeof(public_key_info)); - EXPECT_TRUE(ok); - verifier.VerifyUpdate(bad_tbs_certificate, sizeof(bad_tbs_certificate)); - ok = verifier.VerifyFinal(); - EXPECT_FALSE(ok); + EXPECT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, public_key_info)); + verifier.VerifyUpdate(bad_tbs_certificate); + EXPECT_FALSE(verifier.VerifyFinal()); // Test 4: verify a bad signature. - uint8 bad_signature[sizeof(signature)]; - memcpy(bad_signature, signature, sizeof(signature)); + uint8_t bad_signature[sizeof(signature)]; + SbMemoryCopy(bad_signature, signature, sizeof(signature)); bad_signature[10] += 1; // Corrupt one byte of the signature. - ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, - bad_signature, sizeof(bad_signature), - public_key_info, sizeof(public_key_info)); + EXPECT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + bad_signature, public_key_info)); + verifier.VerifyUpdate(tbs_certificate); + EXPECT_FALSE(verifier.VerifyFinal()); - // A crypto library (e.g., NSS) may detect that the signature is corrupted - // and cause VerifyInit to return false, so it is fine for 'ok' to be false. - if (ok) { - verifier.VerifyUpdate(tbs_certificate, sizeof(tbs_certificate)); - ok = verifier.VerifyFinal(); - EXPECT_FALSE(ok); + // Test 5: import an invalid key. + uint8_t bad_public_key_info[sizeof(public_key_info)]; + SbMemoryCopy(bad_public_key_info, public_key_info, sizeof(public_key_info)); + bad_public_key_info[0] += 1; // Corrupt part of the SPKI syntax. + EXPECT_FALSE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, bad_public_key_info)); + + // Test 6: import a key with extra data. + uint8_t long_public_key_info[sizeof(public_key_info) + 5]; + SbMemorySet(long_public_key_info, 0, sizeof(long_public_key_info)); + SbMemoryCopy(long_public_key_info, public_key_info, sizeof(public_key_info)); + EXPECT_FALSE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, long_public_key_info)); +} + +// The following RSA-PSS tests were generated via the following OpenSSL +// commands: +// +// clang-format off +// openssl genrsa -f4 -out key.pem 2048 +// openssl rsa -in key.pem -pubout -outform der | xxd -i > spki.txt +// openssl rand -out message 50 +// xxd -i message > message.txt +// openssl dgst -sign key.pem -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 < message | xxd -i > sig-good.txt +// openssl dgst -sign key.pem -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:33 < message | xxd -i > sig-bad-saltlen.txt +// clang-format on + +namespace { + +// This is the public key corresponding to the following private key. +// +// -----BEGIN RSA PRIVATE KEY----- +// MIIEowIBAAKCAQEArg5NXFRQQ5QU7dcqqIjZwL4qy4AaJNSPfSPvXmFbK0hDXdp6 +// PdOZ2Wd+lQLZwb7ZQ2ZdqHVK3kZ2sVUlFmngIoEXNhVg+gW2zGPZ1YemwBMdZ/NW +// V2xTX7Y3RrdR/kSccd9ByRTHKb+BCJ2XN5pHu91+LFchahW0lVPHz9DkBPUCThM2 +// I4ZosM3+AcO93RrrcbiQdpuY60Lfg9ZX7+1clM7zhiuOjWNY+FLN4+j4Ec8isiis +// /V1LQyxRZ2t29kto47UJKu0Li7gUvEE1PS/nXBVgEqcSEBBKXa4ahsTqKWJAwvEH +// xaH1t2qhVO1IHcf9FSv5k1T47H7XMLpO2OCPrwIDAQABAoIBAQCXA4exTOHa0Dcc +// aGv1j87GAPimWX3VaKsaGzyKuZNdSTRR0MXwsI+yZa4Y4UFHbSuZ483s499SXPaM +// Q2CLQs8ZgME/xmq+YojIavXL4wcVbUA9OY43CaCI0VLCQzmbj7HgxqCQMzvdh+8P +// J5PUxUHpyHG5TNuL7EsiqG8bapT7ip2+IpKrKjr18gn3k0k9mLNJxK9Qr+CJphwo +// eJgq0Kcjx3bfgDEpPzyvdd+J3e+jclOTYbk2HwJ0FVCrfgJedHFIWUytZoM5783g +// knXzgDyKs65aUDjc/opidXp3WOqfNJUPSiofPYPdYQ26UI0vztL5MBkWCpl+d/55 +// BqxCdDlhAoGBANm90DFUca+7LdnDgj8mWtUIzr+XVzSD9tzOIpcjiPwEnxk8RHrM +// aMHCAKZpbsnX/ikdc2I1OsirPgNFh1q30xgL7oCadzxlwfXnEM0Nff8RJKtN+yI6 +// +nRoOCDGCHBsaa2wyMYRbnanyRDLPIOP4eGQ6Hz/LQJBvhjRyTXlrUU/AoGBAMyj +// ec1ySnlJ2S0JqPBCk14dRsEs/zStgFz1Wdmk7TMRBPUMyhWf8JwNrU5Ppm9biJMo +// MKwkiFjzv/us4ne3wFRsTiKj4uiIwfji7/N2VpbEXSDGtonrX7hES4wQ/s+qr8XJ +// 8ykHrZ9rPOY2lBhxOo+VYE3U6aspAY/qwK8WyumRAoGAMdl+/Iw0quLTkHNuMj75 +// tKQbkUl4sZE0x0B6Mtfz2J7GPeTKWMLLiPB9bZvdvWAx0//mFqnRF3f87orQfjhv +// n6W7qL20ZqN1UHLiKc/Y9LhcCMwFnsSZ6mSh1P8Bl5t6ZkV+8bmz7H5lTe75n7Ul +// JZsjXtqc11NtzgjZY/l9PckCgYAH6ZI+FVs30VkqWqNDlu9nxi4ELh84BDVgYsQ0 +// nCHnxZKxfusZZvPAtO6shnvi9mETf4xSO59iARq9OnQPOPWgzgc/Y6LUZuVJIE0y +// 1rKGZdVL/SL1tjofP9TD96xCj1D4jtRuE7Ps5BKYvCeBwm8HOjldCQx357/9to/4 +// tSLnYQKBgG7STr94Slb3/BzzMxdMLCum1PH73/+IFxu1J0cXxYLP2zEhcSgqGIwm +// aMgdu1L9eE6lJM99AWTEkpcUz8UFwNt+hZW+lZZpex77RMgRl9VCiwid1BNBSU/o +// +lT1mlpDrPCNOge9n6Qvy5waBugB8uNS86w0UImYiKZr+8IQ4EdE +// -----END RSA PRIVATE KEY----- +const uint8_t kPSSPublicKey[] = { + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0x0e, 0x4d, + 0x5c, 0x54, 0x50, 0x43, 0x94, 0x14, 0xed, 0xd7, 0x2a, 0xa8, 0x88, 0xd9, + 0xc0, 0xbe, 0x2a, 0xcb, 0x80, 0x1a, 0x24, 0xd4, 0x8f, 0x7d, 0x23, 0xef, + 0x5e, 0x61, 0x5b, 0x2b, 0x48, 0x43, 0x5d, 0xda, 0x7a, 0x3d, 0xd3, 0x99, + 0xd9, 0x67, 0x7e, 0x95, 0x02, 0xd9, 0xc1, 0xbe, 0xd9, 0x43, 0x66, 0x5d, + 0xa8, 0x75, 0x4a, 0xde, 0x46, 0x76, 0xb1, 0x55, 0x25, 0x16, 0x69, 0xe0, + 0x22, 0x81, 0x17, 0x36, 0x15, 0x60, 0xfa, 0x05, 0xb6, 0xcc, 0x63, 0xd9, + 0xd5, 0x87, 0xa6, 0xc0, 0x13, 0x1d, 0x67, 0xf3, 0x56, 0x57, 0x6c, 0x53, + 0x5f, 0xb6, 0x37, 0x46, 0xb7, 0x51, 0xfe, 0x44, 0x9c, 0x71, 0xdf, 0x41, + 0xc9, 0x14, 0xc7, 0x29, 0xbf, 0x81, 0x08, 0x9d, 0x97, 0x37, 0x9a, 0x47, + 0xbb, 0xdd, 0x7e, 0x2c, 0x57, 0x21, 0x6a, 0x15, 0xb4, 0x95, 0x53, 0xc7, + 0xcf, 0xd0, 0xe4, 0x04, 0xf5, 0x02, 0x4e, 0x13, 0x36, 0x23, 0x86, 0x68, + 0xb0, 0xcd, 0xfe, 0x01, 0xc3, 0xbd, 0xdd, 0x1a, 0xeb, 0x71, 0xb8, 0x90, + 0x76, 0x9b, 0x98, 0xeb, 0x42, 0xdf, 0x83, 0xd6, 0x57, 0xef, 0xed, 0x5c, + 0x94, 0xce, 0xf3, 0x86, 0x2b, 0x8e, 0x8d, 0x63, 0x58, 0xf8, 0x52, 0xcd, + 0xe3, 0xe8, 0xf8, 0x11, 0xcf, 0x22, 0xb2, 0x28, 0xac, 0xfd, 0x5d, 0x4b, + 0x43, 0x2c, 0x51, 0x67, 0x6b, 0x76, 0xf6, 0x4b, 0x68, 0xe3, 0xb5, 0x09, + 0x2a, 0xed, 0x0b, 0x8b, 0xb8, 0x14, 0xbc, 0x41, 0x35, 0x3d, 0x2f, 0xe7, + 0x5c, 0x15, 0x60, 0x12, 0xa7, 0x12, 0x10, 0x10, 0x4a, 0x5d, 0xae, 0x1a, + 0x86, 0xc4, 0xea, 0x29, 0x62, 0x40, 0xc2, 0xf1, 0x07, 0xc5, 0xa1, 0xf5, + 0xb7, 0x6a, 0xa1, 0x54, 0xed, 0x48, 0x1d, 0xc7, 0xfd, 0x15, 0x2b, 0xf9, + 0x93, 0x54, 0xf8, 0xec, 0x7e, 0xd7, 0x30, 0xba, 0x4e, 0xd8, 0xe0, 0x8f, + 0xaf, 0x02, 0x03, 0x01, 0x00, 0x01, +}; + +const uint8_t kPSSMessage[] = { + 0x1e, 0x70, 0xbd, 0xeb, 0x24, 0xf2, 0x9d, 0x05, 0xc5, 0xb5, + 0xf4, 0xca, 0xe6, 0x1d, 0x01, 0x97, 0x29, 0xf4, 0xe0, 0x7c, + 0xfd, 0xcc, 0x97, 0x8d, 0xc2, 0xbb, 0x2d, 0x9b, 0x6b, 0x45, + 0x06, 0xbd, 0x2c, 0x66, 0x10, 0x42, 0x73, 0x8d, 0x88, 0x9b, + 0x18, 0xcc, 0xcb, 0x7e, 0x43, 0x23, 0x06, 0xe9, 0x8f, 0x8f, +}; + +const uint8_t kPSSSignatureGood[] = { + 0x12, 0xa7, 0x6d, 0x9e, 0x8a, 0xea, 0x28, 0xe0, 0x3f, 0x6f, 0x5a, 0xa4, + 0x1b, 0x6a, 0x0a, 0x14, 0xba, 0xfa, 0x84, 0xf6, 0xb7, 0x3c, 0xc9, 0xd6, + 0x84, 0xab, 0x1e, 0x77, 0x88, 0x53, 0x95, 0x43, 0x8e, 0x73, 0xe4, 0x21, + 0xab, 0x69, 0xb2, 0x0c, 0x73, 0x4d, 0x98, 0x42, 0xbd, 0x65, 0xa2, 0x95, + 0x0d, 0x76, 0xb2, 0xbd, 0xe5, 0x9a, 0x6e, 0x9f, 0x72, 0x7f, 0xdd, 0x1e, + 0x9f, 0xda, 0xc8, 0x2e, 0xa3, 0xe6, 0x28, 0x03, 0x98, 0x5c, 0x13, 0xa7, + 0x7d, 0x4e, 0xde, 0xea, 0x35, 0x1b, 0x35, 0x7e, 0xaa, 0x14, 0xf9, 0xfb, + 0xac, 0x61, 0xd0, 0x44, 0x20, 0xd5, 0x52, 0x5b, 0x92, 0x8f, 0xe7, 0x37, + 0xa2, 0x72, 0x7d, 0xe6, 0x0d, 0x81, 0x63, 0xcc, 0x0f, 0xbd, 0xde, 0x25, + 0xe3, 0x3f, 0x89, 0x1b, 0x39, 0x64, 0xfa, 0x21, 0x1d, 0x0f, 0x9b, 0x8a, + 0xc1, 0xad, 0x03, 0x49, 0x96, 0xff, 0x9f, 0x2d, 0x83, 0xee, 0x2d, 0x2a, + 0x1e, 0xc5, 0x73, 0x9f, 0x5b, 0xde, 0xcb, 0xaf, 0x02, 0xbd, 0xc5, 0x9b, + 0x78, 0xb9, 0x8e, 0x01, 0x75, 0x3c, 0xc9, 0x6e, 0x7d, 0x3e, 0x61, 0x62, + 0xc4, 0x8c, 0x9e, 0x76, 0xed, 0x52, 0x5e, 0x80, 0x89, 0xa7, 0x75, 0x5e, + 0xc6, 0x34, 0x97, 0x22, 0x40, 0xb5, 0x0c, 0x77, 0x09, 0x8c, 0xa8, 0xe9, + 0xf6, 0x8d, 0xc0, 0x10, 0x78, 0x92, 0xa9, 0xc6, 0x68, 0xa3, 0x57, 0x6e, + 0x73, 0xb5, 0x73, 0x8d, 0x8e, 0x21, 0xb1, 0xf3, 0xd0, 0x0a, 0x40, 0x68, + 0xfc, 0x3c, 0xeb, 0xd3, 0x48, 0x4a, 0x44, 0xbd, 0xc0, 0x40, 0x5d, 0x9b, + 0x40, 0x6f, 0x45, 0x98, 0x2b, 0xae, 0x58, 0xe8, 0x9d, 0x34, 0x49, 0xd2, + 0xec, 0xdc, 0xd5, 0x98, 0xb4, 0x87, 0x8a, 0xcc, 0x41, 0x3e, 0xd7, 0xe6, + 0x21, 0xd6, 0x4c, 0x89, 0xf1, 0xf4, 0x77, 0x40, 0x3f, 0x9a, 0x28, 0x25, + 0x55, 0x7c, 0xf5, 0x0c, +}; + +const uint8_t kPSSSignatureBadSaltLength[] = { + 0x6e, 0x61, 0xbe, 0x8a, 0x82, 0xbd, 0xed, 0xc6, 0xe4, 0x33, 0x91, 0xa4, + 0x43, 0x57, 0x51, 0x7e, 0xa8, 0x18, 0xbf, 0x20, 0x98, 0xbc, 0x04, 0x50, + 0x06, 0x1b, 0x0b, 0xb6, 0x43, 0xde, 0x58, 0x7f, 0x6b, 0xa5, 0x5e, 0x9d, + 0xd1, 0x75, 0x03, 0xf5, 0x19, 0x8d, 0xdb, 0x2c, 0xd2, 0x9a, 0xf9, 0xbd, + 0x82, 0x8d, 0x32, 0x9d, 0x7d, 0x70, 0x6f, 0x81, 0x95, 0x60, 0x1d, 0x62, + 0x72, 0xf3, 0x95, 0x5b, 0x7a, 0x66, 0x7f, 0x45, 0x94, 0x0c, 0x07, 0xc8, + 0xa7, 0x64, 0x38, 0x57, 0x1a, 0x64, 0x64, 0xf1, 0xe0, 0x45, 0xfe, 0x00, + 0x11, 0x90, 0x57, 0x95, 0x15, 0x21, 0x10, 0x85, 0xc0, 0xbe, 0x53, 0x5b, + 0x3b, 0xa3, 0x57, 0x99, 0x2b, 0x94, 0x6b, 0xbf, 0xa5, 0x55, 0x7d, 0x5a, + 0xcb, 0xa2, 0x73, 0x6b, 0x5f, 0x7b, 0x3f, 0x10, 0x90, 0xd1, 0x26, 0x72, + 0x5e, 0xad, 0xd1, 0x34, 0xe8, 0x8a, 0x33, 0xeb, 0xd2, 0xbf, 0x54, 0x92, + 0xeb, 0x7c, 0xb9, 0x97, 0x80, 0x5a, 0x46, 0xc4, 0xbd, 0xf5, 0x7e, 0xd6, + 0x20, 0x90, 0x92, 0xcb, 0x37, 0x85, 0x9d, 0x81, 0x0a, 0xd0, 0xa5, 0x73, + 0x17, 0x7e, 0xe2, 0x91, 0xef, 0x35, 0x55, 0xc9, 0x5e, 0x87, 0x84, 0x11, + 0xa4, 0x36, 0xf0, 0x2a, 0xa7, 0x7a, 0x83, 0x1d, 0x7a, 0x90, 0x69, 0x22, + 0x5d, 0x3b, 0x30, 0x48, 0x46, 0xd2, 0xd3, 0x49, 0x23, 0x64, 0xa4, 0x6d, + 0xd1, 0xef, 0xb9, 0x1b, 0xa4, 0xd1, 0x92, 0xdd, 0x8c, 0xb2, 0xaa, 0x9f, + 0x6a, 0x2c, 0xc9, 0xdb, 0xa7, 0x35, 0x66, 0x92, 0x8b, 0x73, 0x11, 0x70, + 0x2b, 0xf4, 0x34, 0x3f, 0x9e, 0x15, 0x3e, 0xc0, 0xac, 0x78, 0x6f, 0x74, + 0x8a, 0x6b, 0xe4, 0xf2, 0x7b, 0x10, 0xca, 0x01, 0x3a, 0x3a, 0x88, 0x39, + 0x34, 0xa8, 0x52, 0x4a, 0x76, 0x50, 0xef, 0xdb, 0x91, 0x3c, 0x4a, 0x5c, + 0xe5, 0x43, 0x6f, 0x8e, +}; + +} // namespace + +TEST(SignatureVerifierTest, VerifyRSAPSS) { + // Verify the test vector. + crypto::SignatureVerifier verifier; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + kPSSSignatureGood, kPSSPublicKey)); + verifier.VerifyUpdate(kPSSMessage); + EXPECT_TRUE(verifier.VerifyFinal()); + + // Verify the test vector byte-by-byte. + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + kPSSSignatureGood, kPSSPublicKey)); + for (uint8_t b : kPSSMessage) { + verifier.VerifyUpdate(base::make_span(&b, 1)); } + EXPECT_TRUE(verifier.VerifyFinal()); + + // The bad salt length does not verify. + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + kPSSSignatureBadSaltLength, kPSSPublicKey)); + verifier.VerifyUpdate(kPSSMessage); + EXPECT_FALSE(verifier.VerifyFinal()); + + // Corrupt the message. + std::vector<uint8_t> message(std::begin(kPSSMessage), std::end(kPSSMessage)); + message[0] ^= 1; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + kPSSSignatureGood, kPSSPublicKey)); + verifier.VerifyUpdate(message); + EXPECT_FALSE(verifier.VerifyFinal()); + + // Corrupt the signature. + std::vector<uint8_t> signature(std::begin(kPSSSignatureGood), + std::end(kPSSSignatureGood)); + signature[0] ^= 1; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + signature, kPSSPublicKey)); + verifier.VerifyUpdate(kPSSMessage); + EXPECT_FALSE(verifier.VerifyFinal()); }
diff --git a/src/crypto/symmetric_key.cc b/src/crypto/symmetric_key.cc new file mode 100644 index 0000000..83369b3 --- /dev/null +++ b/src/crypto/symmetric_key.cc
@@ -0,0 +1,141 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/symmetric_key.h" + +#include <algorithm> +#include <utility> + +#include "base/logging.h" +#include "base/strings/string_util.h" +#include "crypto/openssl_util.h" +#include "starboard/types.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/rand.h" + +namespace crypto { + +namespace { + +bool CheckDerivationParameters(SymmetricKey::Algorithm algorithm, + size_t key_size_in_bits) { + switch (algorithm) { + case SymmetricKey::AES: + // Whitelist supported key sizes to avoid accidentally relying on + // algorithms available in NSS but not BoringSSL and vice + // versa. Note that BoringSSL does not support AES-192. + return key_size_in_bits == 128 || key_size_in_bits == 256; + case SymmetricKey::HMAC_SHA1: + return key_size_in_bits % 8 == 0 && key_size_in_bits != 0; + } + + NOTREACHED(); + return false; +} + +} // namespace + +SymmetricKey::~SymmetricKey() { + std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key. +} + +// static +std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey( + Algorithm algorithm, + size_t key_size_in_bits) { + DCHECK_EQ(AES, algorithm); + + // Whitelist supported key sizes to avoid accidentaly relying on + // algorithms available in NSS but not BoringSSL and vice + // versa. Note that BoringSSL does not support AES-192. + if (key_size_in_bits != 128 && key_size_in_bits != 256) + return nullptr; + + size_t key_size_in_bytes = key_size_in_bits / 8; + DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8); + + if (key_size_in_bytes == 0) + return nullptr; + + OpenSSLErrStackTracer err_tracer(FROM_HERE); + std::unique_ptr<SymmetricKey> key(new SymmetricKey); + uint8_t* key_data = reinterpret_cast<uint8_t*>( + base::WriteInto(&key->key_, key_size_in_bytes + 1)); + + int rv = RAND_bytes(key_data, static_cast<int>(key_size_in_bytes)); + return rv == 1 ? std::move(key) : nullptr; +} + +// static +std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + Algorithm algorithm, + const std::string& password, + const std::string& salt, + size_t iterations, + size_t key_size_in_bits) { + if (!CheckDerivationParameters(algorithm, key_size_in_bits)) + return nullptr; + + size_t key_size_in_bytes = key_size_in_bits / 8; + + OpenSSLErrStackTracer err_tracer(FROM_HERE); + std::unique_ptr<SymmetricKey> key(new SymmetricKey); + uint8_t* key_data = reinterpret_cast<uint8_t*>( + base::WriteInto(&key->key_, key_size_in_bytes + 1)); + + int rv = PKCS5_PBKDF2_HMAC_SHA1( + password.data(), password.length(), + reinterpret_cast<const uint8_t*>(salt.data()), salt.length(), + static_cast<unsigned>(iterations), + key_size_in_bytes, key_data); + return rv == 1 ? std::move(key) : nullptr; +} + +// static +std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingScrypt( + Algorithm algorithm, + const std::string& password, + const std::string& salt, + size_t cost_parameter, + size_t block_size, + size_t parallelization_parameter, + size_t max_memory_bytes, + size_t key_size_in_bits) { + if (!CheckDerivationParameters(algorithm, key_size_in_bits)) + return nullptr; + + size_t key_size_in_bytes = key_size_in_bits / 8; + + OpenSSLErrStackTracer err_tracer(FROM_HERE); + std::unique_ptr<SymmetricKey> key(new SymmetricKey); + uint8_t* key_data = reinterpret_cast<uint8_t*>( + base::WriteInto(&key->key_, key_size_in_bytes + 1)); + + int rv = EVP_PBE_scrypt(password.data(), password.length(), + reinterpret_cast<const uint8_t*>(salt.data()), + salt.length(), cost_parameter, block_size, + parallelization_parameter, max_memory_bytes, key_data, + key_size_in_bytes); + return rv == 1 ? std::move(key) : nullptr; +} + +// static +std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm algorithm, + const std::string& raw_key) { + if (algorithm == AES) { + // Whitelist supported key sizes to avoid accidentaly relying on + // algorithms available in NSS but not BoringSSL and vice + // versa. Note that BoringSSL does not support AES-192. + if (raw_key.size() != 128/8 && raw_key.size() != 256/8) + return nullptr; + } + + std::unique_ptr<SymmetricKey> key(new SymmetricKey); + key->key_ = raw_key; + return key; +} + +SymmetricKey::SymmetricKey() = default; + +} // namespace crypto
diff --git a/src/crypto/symmetric_key.h b/src/crypto/symmetric_key.h index cce2a9b..ae4e8d6 100644 --- a/src/crypto/symmetric_key.h +++ b/src/crypto/symmetric_key.h
@@ -5,18 +5,13 @@ #ifndef CRYPTO_SYMMETRIC_KEY_H_ #define CRYPTO_SYMMETRIC_KEY_H_ +#include <memory> #include <string> -#include "base/basictypes.h" +#include "base/macros.h" +#include "build/build_config.h" #include "crypto/crypto_export.h" - -#if defined(NACL_WIN64) -// See comments for crypto_nacl_win64 in crypto.gyp. -// Must test for NACL_WIN64 before OS_WIN since former is a subset of latter. -#include "crypto/scoped_capi_types.h" -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) -#include "crypto/scoped_nss_types.h" -#endif +#include "starboard/types.h" namespace crypto { @@ -36,66 +31,53 @@ // Generates a random key suitable to be used with |algorithm| and of // |key_size_in_bits| bits. |key_size_in_bits| must be a multiple of 8. // The caller is responsible for deleting the returned SymmetricKey. - static SymmetricKey* GenerateRandomKey(Algorithm algorithm, - size_t key_size_in_bits); + static std::unique_ptr<SymmetricKey> GenerateRandomKey( + Algorithm algorithm, + size_t key_size_in_bits); // Derives a key from the supplied password and salt using PBKDF2, suitable // for use with specified |algorithm|. Note |algorithm| is not the algorithm // used to derive the key from the password. |key_size_in_bits| must be a // multiple of 8. The caller is responsible for deleting the returned // SymmetricKey. - static SymmetricKey* DeriveKeyFromPassword(Algorithm algorithm, - const std::string& password, - const std::string& salt, - size_t iterations, - size_t key_size_in_bits); + static std::unique_ptr<SymmetricKey> DeriveKeyFromPasswordUsingPbkdf2( + Algorithm algorithm, + const std::string& password, + const std::string& salt, + size_t iterations, + size_t key_size_in_bits); + + // Derives a key from the supplied password and salt using scrypt, suitable + // for use with specified |algorithm|. Note |algorithm| is not the algorithm + // used to derive the key from the password. |cost_parameter|, |block_size|, + // and |parallelization_parameter| correspond to the parameters |N|, |r|, and + // |p| from the scrypt specification (see RFC 7914). |key_size_in_bits| must + // be a multiple of 8. The caller is responsible for deleting the returned + // SymmetricKey. + static std::unique_ptr<SymmetricKey> DeriveKeyFromPasswordUsingScrypt( + Algorithm algorithm, + const std::string& password, + const std::string& salt, + size_t cost_parameter, + size_t block_size, + size_t parallelization_parameter, + size_t max_memory_bytes, + size_t key_size_in_bits); // Imports an array of key bytes in |raw_key|. This key may have been - // generated by GenerateRandomKey or DeriveKeyFromPassword and exported with - // GetRawKey, or via another compatible method. The key must be of suitable - // size for use with |algorithm|. The caller owns the returned SymmetricKey. - static SymmetricKey* Import(Algorithm algorithm, const std::string& raw_key); + // generated by GenerateRandomKey or DeriveKeyFromPassword{Pbkdf2,Scrypt} and + // exported with key(). The key must be of suitable size for use with + // |algorithm|. The caller owns the returned SymmetricKey. + static std::unique_ptr<SymmetricKey> Import(Algorithm algorithm, + const std::string& raw_key); -#if defined(USE_OPENSSL) - const std::string& key() { return key_; } -#elif defined(NACL_WIN64) - HCRYPTKEY key() const { return key_.get(); } -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) - PK11SymKey* key() const { return key_.get(); } -#endif - - // Extracts the raw key from the platform specific data. - // Warning: |raw_key| holds the raw key as bytes and thus must be handled - // carefully. - bool GetRawKey(std::string* raw_key); - -#if defined(OS_CHROMEOS) - // Creates symmetric key from NSS key. Takes over the ownership of |key|. - static SymmetricKey* CreateFromKey(PK11SymKey* key); -#endif + // Returns the raw platform specific key data. + const std::string& key() const { return key_; } private: -#if defined(USE_OPENSSL) - SymmetricKey() {} + SymmetricKey(); + std::string key_; -#elif defined(NACL_WIN64) - SymmetricKey(HCRYPTPROV provider, HCRYPTKEY key, - const void* key_data, size_t key_size_in_bytes); - - ScopedHCRYPTPROV provider_; - ScopedHCRYPTKEY key_; - - // Contains the raw key, if it is known during initialization and when it - // is likely that the associated |provider_| will be unable to export the - // |key_|. This is the case of HMAC keys when the key size exceeds 16 bytes - // when using the default RSA provider. - // TODO(rsleevi): See if KP_EFFECTIVE_KEYLEN is the reason why CryptExportKey - // fails with NTE_BAD_KEY/NTE_BAD_LEN - std::string raw_key_; -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) - explicit SymmetricKey(PK11SymKey* key); - ScopedPK11SymKey key_; -#endif DISALLOW_COPY_AND_ASSIGN(SymmetricKey); };
diff --git a/src/crypto/symmetric_key_openssl.cc b/src/crypto/symmetric_key_openssl.cc deleted file mode 100644 index 899a942..0000000 --- a/src/crypto/symmetric_key_openssl.cc +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/symmetric_key.h" - -#include <openssl/evp.h> -#include <openssl/rand.h> - -#include <algorithm> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/string_util.h" -#include "crypto/openssl_util.h" - -namespace crypto { - -SymmetricKey::~SymmetricKey() { - std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key. -} - -// static -SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, - size_t key_size_in_bits) { - DCHECK_EQ(AES, algorithm); - size_t key_size_in_bytes = key_size_in_bits / 8; - DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8); - - if (key_size_in_bytes == 0) - return NULL; - - OpenSSLErrStackTracer err_tracer(FROM_HERE); - scoped_ptr<SymmetricKey> key(new SymmetricKey); - uint8* key_data = - reinterpret_cast<uint8*>(WriteInto(&key->key_, key_size_in_bytes + 1)); - - int rv = RAND_bytes(key_data, static_cast<int>(key_size_in_bytes)); - return rv == 1 ? key.release() : NULL; -} - -// static -SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, - const std::string& password, - const std::string& salt, - size_t iterations, - size_t key_size_in_bits) { - DCHECK(algorithm == AES || algorithm == HMAC_SHA1); - size_t key_size_in_bytes = key_size_in_bits / 8; - DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8); - - if (key_size_in_bytes == 0) - return NULL; - - OpenSSLErrStackTracer err_tracer(FROM_HERE); - scoped_ptr<SymmetricKey> key(new SymmetricKey); - uint8* key_data = - reinterpret_cast<uint8*>(WriteInto(&key->key_, key_size_in_bytes + 1)); - int rv = PKCS5_PBKDF2_HMAC_SHA1(password.data(), password.length(), - reinterpret_cast<const uint8*>(salt.data()), - salt.length(), iterations, - static_cast<int>(key_size_in_bytes), - key_data); - return rv == 1 ? key.release() : NULL; -} - -// static -SymmetricKey* SymmetricKey::Import(Algorithm algorithm, - const std::string& raw_key) { - scoped_ptr<SymmetricKey> key(new SymmetricKey); - key->key_ = raw_key; - return key.release(); -} - -bool SymmetricKey::GetRawKey(std::string* raw_key) { - *raw_key = key_; - return true; -} - -} // namespace crypto
diff --git a/src/crypto/symmetric_key_unittest.cc b/src/crypto/symmetric_key_unittest.cc index 389d7f5..6bef6ca 100644 --- a/src/crypto/symmetric_key_unittest.cc +++ b/src/crypto/symmetric_key_unittest.cc
@@ -4,65 +4,51 @@ #include "crypto/symmetric_key.h" +#include <memory> #include <string> -#include "base/memory/scoped_ptr.h" -#include "base/string_number_conversions.h" -#include "base/string_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "testing/gtest/include/gtest/gtest.h" TEST(SymmetricKeyTest, GenerateRandomKey) { - scoped_ptr<crypto::SymmetricKey> key( + std::unique_ptr<crypto::SymmetricKey> key( crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256)); - ASSERT_TRUE(NULL != key.get()); - std::string raw_key; - EXPECT_TRUE(key->GetRawKey(&raw_key)); - EXPECT_EQ(32U, raw_key.size()); + ASSERT_TRUE(key); + EXPECT_EQ(32U, key->key().size()); // Do it again and check that the keys are different. // (Note: this has a one-in-10^77 chance of failure!) - scoped_ptr<crypto::SymmetricKey> key2( + std::unique_ptr<crypto::SymmetricKey> key2( crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256)); - ASSERT_TRUE(NULL != key2.get()); - std::string raw_key2; - EXPECT_TRUE(key2->GetRawKey(&raw_key2)); - EXPECT_EQ(32U, raw_key2.size()); - EXPECT_NE(raw_key, raw_key2); + ASSERT_TRUE(key2); + EXPECT_EQ(32U, key2->key().size()); + EXPECT_NE(key->key(), key2->key()); } TEST(SymmetricKeyTest, ImportGeneratedKey) { - scoped_ptr<crypto::SymmetricKey> key1( + std::unique_ptr<crypto::SymmetricKey> key1( crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256)); - ASSERT_TRUE(NULL != key1.get()); - std::string raw_key1; - EXPECT_TRUE(key1->GetRawKey(&raw_key1)); + ASSERT_TRUE(key1); - scoped_ptr<crypto::SymmetricKey> key2( - crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key1)); - ASSERT_TRUE(NULL != key2.get()); + std::unique_ptr<crypto::SymmetricKey> key2( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key1->key())); + ASSERT_TRUE(key2); - std::string raw_key2; - EXPECT_TRUE(key2->GetRawKey(&raw_key2)); - - EXPECT_EQ(raw_key1, raw_key2); + EXPECT_EQ(key1->key(), key2->key()); } TEST(SymmetricKeyTest, ImportDerivedKey) { - scoped_ptr<crypto::SymmetricKey> key1( - crypto::SymmetricKey::DeriveKeyFromPassword( + std::unique_ptr<crypto::SymmetricKey> key1( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( crypto::SymmetricKey::HMAC_SHA1, "password", "somesalt", 1024, 160)); - ASSERT_TRUE(NULL != key1.get()); - std::string raw_key1; - EXPECT_TRUE(key1->GetRawKey(&raw_key1)); + ASSERT_TRUE(key1); - scoped_ptr<crypto::SymmetricKey> key2( - crypto::SymmetricKey::Import(crypto::SymmetricKey::HMAC_SHA1, raw_key1)); - ASSERT_TRUE(NULL != key2.get()); + std::unique_ptr<crypto::SymmetricKey> key2(crypto::SymmetricKey::Import( + crypto::SymmetricKey::HMAC_SHA1, key1->key())); + ASSERT_TRUE(key2); - std::string raw_key2; - EXPECT_TRUE(key2->GetRawKey(&raw_key2)); - - EXPECT_EQ(raw_key1, raw_key2); + EXPECT_EQ(key1->key(), key2->key()); } struct PBKDF2TestVector { @@ -71,67 +57,77 @@ const char* salt; unsigned int rounds; unsigned int key_size_in_bits; - const char* expected; // ASCII encoded hex bytes + const char* expected; // ASCII encoded hex bytes. }; -class SymmetricKeyDeriveKeyFromPasswordTest - : public testing::TestWithParam<PBKDF2TestVector> { +struct ScryptTestVector { + crypto::SymmetricKey::Algorithm algorithm; + const char* password; + const char* salt; + unsigned int cost_parameter; + unsigned int block_size; + unsigned int parallelization_parameter; + unsigned int key_size_in_bits; + const char* expected; // ASCII encoded hex bytes. }; -TEST_P(SymmetricKeyDeriveKeyFromPasswordTest, DeriveKeyFromPassword) { +class SymmetricKeyDeriveKeyFromPasswordUsingPbkdf2Test + : public testing::TestWithParam<PBKDF2TestVector> {}; + +class SymmetricKeyDeriveKeyFromPasswordUsingScryptTest + : public testing::TestWithParam<ScryptTestVector> {}; + +TEST_P(SymmetricKeyDeriveKeyFromPasswordUsingPbkdf2Test, + DeriveKeyFromPasswordUsingPbkdf2) { PBKDF2TestVector test_data(GetParam()); -#if defined(OS_MACOSX) && !defined(OS_IOS) - // The OS X crypto libraries have minimum salt and iteration requirements - // so some of the tests below will cause them to barf. Skip these. - if (strlen(test_data.salt) < 8 || test_data.rounds < 1000) { - VLOG(1) << "Skipped test vector for " << test_data.expected; - return; - } -#endif // OS_MACOSX - - scoped_ptr<crypto::SymmetricKey> key( - crypto::SymmetricKey::DeriveKeyFromPassword( - test_data.algorithm, - test_data.password, test_data.salt, + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + test_data.algorithm, test_data.password, test_data.salt, test_data.rounds, test_data.key_size_in_bits)); - ASSERT_TRUE(NULL != key.get()); + ASSERT_TRUE(key); - std::string raw_key; - key->GetRawKey(&raw_key); + const std::string& raw_key = key->key(); EXPECT_EQ(test_data.key_size_in_bits / 8, raw_key.size()); EXPECT_EQ(test_data.expected, - StringToLowerASCII(base::HexEncode(raw_key.data(), + base::ToLowerASCII(base::HexEncode(raw_key.data(), raw_key.size()))); } -static const PBKDF2TestVector kTestVectors[] = { - // These tests come from - // http://www.ietf.org/id/draft-josefsson-pbkdf2-test-vectors-00.txt - { - crypto::SymmetricKey::HMAC_SHA1, - "password", - "salt", - 1, - 160, - "0c60c80f961f0e71f3a9b524af6012062fe037a6", - }, - { - crypto::SymmetricKey::HMAC_SHA1, - "password", - "salt", - 2, - 160, - "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957", - }, - { - crypto::SymmetricKey::HMAC_SHA1, - "password", - "salt", - 4096, - 160, - "4b007901b765489abead49d926f721d065a429c1", - }, - // This test takes over 30s to run on the trybots. +TEST_P(SymmetricKeyDeriveKeyFromPasswordUsingScryptTest, + DeriveKeyFromPasswordUsingScrypt) { + const int kScryptMaxMemoryBytes = 128 * 1024 * 1024; // 128 MiB. + + ScryptTestVector test_data(GetParam()); + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingScrypt( + test_data.algorithm, test_data.password, test_data.salt, + test_data.cost_parameter, test_data.block_size, + test_data.parallelization_parameter, kScryptMaxMemoryBytes, + test_data.key_size_in_bits)); + ASSERT_TRUE(key); + + const std::string& raw_key = key->key(); + EXPECT_EQ(test_data.key_size_in_bits / 8, raw_key.size()); + EXPECT_EQ(test_data.expected, base::ToLowerASCII(base::HexEncode( + raw_key.data(), raw_key.size()))); +} + +static const PBKDF2TestVector kTestVectorsPbkdf2[] = { + // These tests come from + // http://www.ietf.org/id/draft-josefsson-pbkdf2-test-vectors-00.txt. + { + crypto::SymmetricKey::HMAC_SHA1, "password", "salt", 1, 160, + "0c60c80f961f0e71f3a9b524af6012062fe037a6", + }, + { + crypto::SymmetricKey::HMAC_SHA1, "password", "salt", 2, 160, + "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957", + }, + { + crypto::SymmetricKey::HMAC_SHA1, "password", "salt", 4096, 160, + "4b007901b765489abead49d926f721d065a429c1", + }, +// This test takes over 30s to run on the trybots. #if 0 { crypto::SymmetricKey::HMAC_SHA1, @@ -143,83 +139,78 @@ }, #endif - // These tests come from RFC 3962, via BSD source code at - // http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/bioctl/pbkdf2.c?rev=HEAD&content-type=text/plain - { - crypto::SymmetricKey::HMAC_SHA1, - "password", - "ATHENA.MIT.EDUraeburn", - 1, - 160, - "cdedb5281bb2f801565a1122b25635150ad1f7a0", - }, - { - crypto::SymmetricKey::HMAC_SHA1, - "password", - "ATHENA.MIT.EDUraeburn", - 2, - 160, - "01dbee7f4a9e243e988b62c73cda935da05378b9", - }, - { - crypto::SymmetricKey::HMAC_SHA1, - "password", - "ATHENA.MIT.EDUraeburn", - 1200, - 160, - "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddb", - }, - { - crypto::SymmetricKey::HMAC_SHA1, - "password", - "\0224VxxV4\022", /* 0x1234567878563412 */ - 5, - 160, - "d1daa78615f287e6a1c8b120d7062a493f98d203", - }, - { - crypto::SymmetricKey::HMAC_SHA1, - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - "pass phrase equals block size", - 1200, - 160, - "139c30c0966bc32ba55fdbf212530ac9c5ec59f1", - }, - { - crypto::SymmetricKey::HMAC_SHA1, - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - "pass phrase exceeds block size", - 1200, - 160, - "9ccad6d468770cd51b10e6a68721be611a8b4d28", - }, - { - crypto::SymmetricKey::HMAC_SHA1, - "\360\235\204\236", /* g-clef (0xf09d849e) */ - "EXAMPLE.COMpianist", - 50, - 160, - "6b9cf26d45455a43a5b8bb276a403b39e7fe37a0", - }, + // These tests come from RFC 3962, via BSD source code at + // http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/bioctl/pbkdf2.c?rev=HEAD&content-type=text/plain. + { + crypto::SymmetricKey::HMAC_SHA1, "password", "ATHENA.MIT.EDUraeburn", 1, + 160, "cdedb5281bb2f801565a1122b25635150ad1f7a0", + }, + { + crypto::SymmetricKey::HMAC_SHA1, "password", "ATHENA.MIT.EDUraeburn", 2, + 160, "01dbee7f4a9e243e988b62c73cda935da05378b9", + }, + { + crypto::SymmetricKey::HMAC_SHA1, "password", "ATHENA.MIT.EDUraeburn", + 1200, 160, "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddb", + }, + { + crypto::SymmetricKey::HMAC_SHA1, "password", + "\022" + "4VxxV4\022", /* 0x1234567878563412 */ + 5, 160, "d1daa78615f287e6a1c8b120d7062a493f98d203", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase equals block size", 1200, 160, + "139c30c0966bc32ba55fdbf212530ac9c5ec59f1", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase exceeds block size", 1200, 160, + "9ccad6d468770cd51b10e6a68721be611a8b4d28", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "\360\235\204\236", /* g-clef (0xf09d849e) */ + "EXAMPLE.COMpianist", 50, 160, + "6b9cf26d45455a43a5b8bb276a403b39e7fe37a0", + }, - // Regression tests for AES keys, derived from the Linux NSS implementation. - { - crypto::SymmetricKey::AES, - "A test password", - "saltsalt", - 1, - 256, - "44899a7777f0e6e8b752f875f02044b8ac593de146de896f2e8a816e315a36de", - }, - { - crypto::SymmetricKey::AES, - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - "pass phrase exceeds block size", - 20, - 256, - "e0739745dc28b8721ba402e05214d2ac1eab54cf72bee1fba388297a09eb493c", - }, + // Regression tests for AES keys, derived from the Linux NSS implementation. + { + crypto::SymmetricKey::AES, "A test password", "saltsalt", 1, 256, + "44899a7777f0e6e8b752f875f02044b8ac593de146de896f2e8a816e315a36de", + }, + { + crypto::SymmetricKey::AES, + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase exceeds block size", 20, 256, + "e0739745dc28b8721ba402e05214d2ac1eab54cf72bee1fba388297a09eb493c", + }, }; -INSTANTIATE_TEST_CASE_P(, SymmetricKeyDeriveKeyFromPasswordTest, - testing::ValuesIn(kTestVectors)); +static const ScryptTestVector kTestVectorsScrypt[] = { + // From RFC 7914, "The scrypt Password-Based Key Derivation Function", + // https://tools.ietf.org/html/rfc7914.html. The fourth test vector is + // intentionally not used, as it would make the test significantly slower, + // due to the very high cost parameter. + {crypto::SymmetricKey::HMAC_SHA1, "", "", 16, 1, 1, 512, + "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069de" + "d0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"}, + {crypto::SymmetricKey::HMAC_SHA1, "password", "NaCl", 1024, 8, 16, 512, + "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92" + "e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"}, + {crypto::SymmetricKey::HMAC_SHA1, "pleaseletmein", "SodiumChloride", 16384, + 8, 1, 512, + "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d54329556" + "13f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"}}; + +INSTANTIATE_TEST_CASE_P(, + SymmetricKeyDeriveKeyFromPasswordUsingPbkdf2Test, + testing::ValuesIn(kTestVectorsPbkdf2)); + +INSTANTIATE_TEST_CASE_P(, + SymmetricKeyDeriveKeyFromPasswordUsingScryptTest, + testing::ValuesIn(kTestVectorsScrypt));
diff --git a/src/crypto/third_party/nss/LICENSE b/src/crypto/third_party/nss/LICENSE deleted file mode 100644 index 0367164..0000000 --- a/src/crypto/third_party/nss/LICENSE +++ /dev/null
@@ -1,35 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */
diff --git a/src/crypto/third_party/nss/README.chromium b/src/crypto/third_party/nss/README.chromium deleted file mode 100644 index f0bb87b..0000000 --- a/src/crypto/third_party/nss/README.chromium +++ /dev/null
@@ -1,14 +0,0 @@ -Name: Network Security Services (NSS) -URL: http://www.mozilla.org/projects/security/pki/nss/ -License: MPL 1.1/GPL 2.0/LGPL 2.1 - -We extracted the SHA-256 source files, eliminated unneeded dependencies, -deleted or commented out unused code, and tweaked them for Chrome's source -tree. sha512.c is renamed sha512.cc so that it can include Chrome's C++ -header "base/basictypes.h". We define NOUNROLL256 to reduce the object code -size. - -In blapi.h and sha512.cc, replaced uint32 by unsigned int so that they can -be compiled with -DNO_NSPR_10_SUPPORT. NO_NSPR_10_SUPPORT turns off the -definition of the NSPR 1.0 types int8 - int64 and uint8 - uint64 to avoid -conflict with the same-named types defined in "base/basictypes.h".
diff --git a/src/crypto/third_party/nss/chromium-blapi.h b/src/crypto/third_party/nss/chromium-blapi.h deleted file mode 100644 index 2ca772e..0000000 --- a/src/crypto/third_party/nss/chromium-blapi.h +++ /dev/null
@@ -1,101 +0,0 @@ -/* - * crypto.h - public data structures and prototypes for the crypto library - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -/* $Id: blapi.h,v 1.27 2007/11/09 18:49:32 wtc%google.com Exp $ */ - -#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_ -#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_ - -#include "crypto/third_party/nss/chromium-blapit.h" - -/******************************************/ - -extern SHA256Context *SHA256_NewContext(void); -extern void SHA256_DestroyContext(SHA256Context *cx, PRBool freeit); -extern void SHA256_Begin(SHA256Context *cx); -extern void SHA256_Update(SHA256Context *cx, const unsigned char *input, - unsigned int inputLen); -extern void SHA256_End(SHA256Context *cx, unsigned char *digest, - unsigned int *digestLen, unsigned int maxDigestLen); -extern SECStatus SHA256_HashBuf(unsigned char *dest, const unsigned char *src, - unsigned int src_length); -extern SECStatus SHA256_Hash(unsigned char *dest, const char *src); -extern void SHA256_TraceState(SHA256Context *cx); -extern unsigned int SHA256_FlattenSize(SHA256Context *cx); -extern SECStatus SHA256_Flatten(SHA256Context *cx,unsigned char *space); -extern SHA256Context * SHA256_Resurrect(unsigned char *space, void *arg); -extern void SHA256_Clone(SHA256Context *dest, SHA256Context *src); - -/******************************************/ - -extern SHA512Context *SHA512_NewContext(void); -extern void SHA512_DestroyContext(SHA512Context *cx, PRBool freeit); -extern void SHA512_Begin(SHA512Context *cx); -extern void SHA512_Update(SHA512Context *cx, const unsigned char *input, - unsigned int inputLen); -extern void SHA512_End(SHA512Context *cx, unsigned char *digest, - unsigned int *digestLen, unsigned int maxDigestLen); -extern SECStatus SHA512_HashBuf(unsigned char *dest, const unsigned char *src, - unsigned int src_length); -extern SECStatus SHA512_Hash(unsigned char *dest, const char *src); -extern void SHA512_TraceState(SHA512Context *cx); -extern unsigned int SHA512_FlattenSize(SHA512Context *cx); -extern SECStatus SHA512_Flatten(SHA512Context *cx,unsigned char *space); -extern SHA512Context * SHA512_Resurrect(unsigned char *space, void *arg); -extern void SHA512_Clone(SHA512Context *dest, SHA512Context *src); - -/******************************************/ - -extern SHA384Context *SHA384_NewContext(void); -extern void SHA384_DestroyContext(SHA384Context *cx, PRBool freeit); -extern void SHA384_Begin(SHA384Context *cx); -extern void SHA384_Update(SHA384Context *cx, const unsigned char *input, - unsigned int inputLen); -extern void SHA384_End(SHA384Context *cx, unsigned char *digest, - unsigned int *digestLen, unsigned int maxDigestLen); -extern SECStatus SHA384_HashBuf(unsigned char *dest, const unsigned char *src, - unsigned int src_length); -extern SECStatus SHA384_Hash(unsigned char *dest, const char *src); -extern void SHA384_TraceState(SHA384Context *cx); -extern unsigned int SHA384_FlattenSize(SHA384Context *cx); -extern SECStatus SHA384_Flatten(SHA384Context *cx,unsigned char *space); -extern SHA384Context * SHA384_Resurrect(unsigned char *space, void *arg); -extern void SHA384_Clone(SHA384Context *dest, SHA384Context *src); - -#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_ */
diff --git a/src/crypto/third_party/nss/chromium-blapit.h b/src/crypto/third_party/nss/chromium-blapit.h deleted file mode 100644 index 669f64d..0000000 --- a/src/crypto/third_party/nss/chromium-blapit.h +++ /dev/null
@@ -1,91 +0,0 @@ -/* - * blapit.h - public data structures for the crypto library - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dr Vipul Gupta <vipul.gupta@sun.com> and - * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -/* $Id: blapit.h,v 1.20 2007/02/28 19:47:37 rrelyea%redhat.com Exp $ */ - -#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_ -#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_ - -#include "base/third_party/nspr/prtypes.h" - -/* -** A status code. Status's are used by procedures that return status -** values. Again the motivation is so that a compiler can generate -** warnings when return values are wrong. Correct testing of status codes: -** -** SECStatus rv; -** rv = some_function (some_argument); -** if (rv != SECSuccess) -** do_an_error_thing(); -** -*/ -typedef enum _SECStatus { - SECWouldBlock = -2, - SECFailure = -1, - SECSuccess = 0 -} SECStatus; - -#define SHA256_LENGTH 32 /* bytes */ -#define SHA384_LENGTH 48 /* bytes */ -#define SHA512_LENGTH 64 /* bytes */ -#define HASH_LENGTH_MAX SHA512_LENGTH - -/* - * Input block size for each hash algorithm. - */ - -#define SHA256_BLOCK_LENGTH 64 /* bytes */ -#define SHA384_BLOCK_LENGTH 128 /* bytes */ -#define SHA512_BLOCK_LENGTH 128 /* bytes */ -#define HASH_BLOCK_LENGTH_MAX SHA512_BLOCK_LENGTH - -/*************************************************************************** -** Opaque objects -*/ - -struct SHA256ContextStr ; -struct SHA512ContextStr ; - -typedef struct SHA256ContextStr SHA256Context; -typedef struct SHA512ContextStr SHA512Context; -/* SHA384Context is really a SHA512ContextStr. This is not a mistake. */ -typedef struct SHA512ContextStr SHA384Context; - -#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_ */
diff --git a/src/crypto/third_party/nss/chromium-nss.h b/src/crypto/third_party/nss/chromium-nss.h deleted file mode 100644 index 5ef28e3..0000000 --- a/src/crypto/third_party/nss/chromium-nss.h +++ /dev/null
@@ -1,70 +0,0 @@ - /* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_ -#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_ - -// This file contains some functions we borrowed from NSS. - -#include <keyhi.h> -#include <secmod.h> - -#include "crypto/crypto_export.h" - -// Like PK11_ImportEncryptedPrivateKeyInfo, but hardcoded for EC, and returns -// the SECKEYPrivateKey. -// See https://bugzilla.mozilla.org/show_bug.cgi?id=211546 -// When we use NSS 3.13.2 or later, -// PK11_ImportEncryptedPrivateKeyInfoAndReturnKey can be used instead. -SECStatus ImportEncryptedECPrivateKeyInfoAndReturnKey( - PK11SlotInfo* slot, - SECKEYEncryptedPrivateKeyInfo* epki, - SECItem* password, - SECItem* nickname, - SECItem* public_value, - PRBool permanent, - PRBool sensitive, - SECKEYPrivateKey** private_key, - void* wincx); - -// Like SEC_DerSignData. -CRYPTO_EXPORT SECStatus DerSignData(PLArenaPool *arena, - SECItem *result, - SECItem *input, - SECKEYPrivateKey *key, - SECOidTag algo_id); - -#endif // CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_
diff --git a/src/crypto/third_party/nss/chromium-sha256.h b/src/crypto/third_party/nss/chromium-sha256.h deleted file mode 100644 index 14661dc..0000000 --- a/src/crypto/third_party/nss/chromium-sha256.h +++ /dev/null
@@ -1,51 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_ -#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_ - -#include "base/third_party/nspr/prtypes.h" - -struct SHA256ContextStr { - union { - PRUint32 w[64]; /* message schedule, input buffer, plus 48 words */ - PRUint8 b[256]; - } u; - PRUint32 h[8]; /* 8 state variables */ - PRUint32 sizeHi,sizeLo; /* 64-bit count of hashed bytes. */ -}; - -#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_ */
diff --git a/src/crypto/third_party/nss/pk11akey.cc b/src/crypto/third_party/nss/pk11akey.cc deleted file mode 100644 index 4db582f..0000000 --- a/src/crypto/third_party/nss/pk11akey.cc +++ /dev/null
@@ -1,98 +0,0 @@ - /* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dr Stephen Henson <stephen.henson@gemplus.com> - * Dr Vipul Gupta <vipul.gupta@sun.com>, and - * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "crypto/third_party/nss/chromium-nss.h" - -#include <pk11pub.h> - -#include "base/logging.h" - -// Based on PK11_ImportEncryptedPrivateKeyInfo function in -// mozilla/security/nss/lib/pk11wrap/pk11akey.c. -SECStatus ImportEncryptedECPrivateKeyInfoAndReturnKey( - PK11SlotInfo* slot, - SECKEYEncryptedPrivateKeyInfo* epki, - SECItem* password, - SECItem* nickname, - SECItem* public_value, - PRBool permanent, - PRBool sensitive, - SECKEYPrivateKey** private_key, - void* wincx) { - SECItem* crypto_param = NULL; - - CK_ATTRIBUTE_TYPE usage = CKA_SIGN; - - PK11SymKey* key = PK11_PBEKeyGen(slot, - &epki->algorithm, - password, - PR_FALSE, // faulty3DES - wincx); - if (key == NULL) { - DLOG(ERROR) << "PK11_PBEKeyGen: " << PORT_GetError(); - return SECFailure; - } - - CK_MECHANISM_TYPE crypto_mech_type = PK11_GetPBECryptoMechanism( - &epki->algorithm, &crypto_param, password); - if (crypto_mech_type == CKM_INVALID_MECHANISM) { - DLOG(ERROR) << "PK11_GetPBECryptoMechanism: " << PORT_GetError(); - PK11_FreeSymKey(key); - return SECFailure; - } - - crypto_mech_type = PK11_GetPadMechanism(crypto_mech_type); - - *private_key = PK11_UnwrapPrivKey(slot, key, crypto_mech_type, crypto_param, - &epki->encryptedData, nickname, - public_value, permanent, sensitive, CKK_EC, - &usage, 1, wincx); - - if (crypto_param != NULL) - SECITEM_ZfreeItem(crypto_param, PR_TRUE); - - PK11_FreeSymKey(key); - - if (!*private_key) { - DLOG(ERROR) << "PK11_UnwrapPrivKey: " << PORT_GetError(); - return SECFailure; - } - - return SECSuccess; -}
diff --git a/src/crypto/third_party/nss/secsign.cc b/src/crypto/third_party/nss/secsign.cc deleted file mode 100644 index a788def..0000000 --- a/src/crypto/third_party/nss/secsign.cc +++ /dev/null
@@ -1,132 +0,0 @@ -/* - * Signature stuff. - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "crypto/third_party/nss/chromium-nss.h" - -#include <vector> - -#include <cryptohi.h> -#include <pk11pub.h> -#include <secerr.h> -#include <sechash.h> - -#include "base/basictypes.h" -#include "base/logging.h" -#include "build/build_config.h" - -SECStatus DerSignData(PLArenaPool *arena, - SECItem *result, - SECItem *input, - SECKEYPrivateKey *key, - SECOidTag algo_id) { - if (key->keyType != ecKey) { - return SEC_DerSignData(arena, result, input->data, input->len, key, - algo_id); - } - - // NSS has a private function sec_DecodeSigAlg it uses to figure out the - // correct hash from the algorithm id. - HASH_HashType hash_type; - switch (algo_id) { - case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: - hash_type = HASH_AlgSHA1; - break; -#ifdef SHA224_LENGTH - case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: - hash_type = HASH_AlgSHA224; - break; -#endif - case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: - hash_type = HASH_AlgSHA256; - break; - case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: - hash_type = HASH_AlgSHA384; - break; - case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: - hash_type = HASH_AlgSHA512; - break; - default: - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); - return SECFailure; - } - - // Hash the input. - std::vector<uint8> hash_data(HASH_ResultLen(hash_type)); - SECStatus rv = HASH_HashBuf( - hash_type, &hash_data[0], input->data, input->len); - if (rv != SECSuccess) - return rv; - SECItem hash = {siBuffer, &hash_data[0], - static_cast<unsigned int>(hash_data.size())}; - - // Compute signature of hash. - int signature_len = PK11_SignatureLen(key); - std::vector<uint8> signature_data(signature_len); - SECItem sig = {siBuffer, &signature_data[0], - static_cast<unsigned int>(signature_len)}; - rv = PK11_Sign(key, &sig, &hash); - if (rv != SECSuccess) - return rv; - - CERTSignedData sd; - PORT_Memset(&sd, 0, sizeof(sd)); - // Fill in tbsCertificate. - sd.data.data = (unsigned char*) input->data; - sd.data.len = input->len; - - // Fill in signatureAlgorithm. - rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algo_id, 0); - if (rv != SECSuccess) - return rv; - - // Fill in signatureValue. - rv = DSAU_EncodeDerSigWithLen(&sd.signature, &sig, sig.len); - if (rv != SECSuccess) - return rv; - sd.signature.len <<= 3; // Convert to bit string. - - // DER encode the signed data object. - void* encode_result = SEC_ASN1EncodeItem( - arena, result, &sd, SEC_ASN1_GET(CERT_SignedDataTemplate)); - - PORT_Free(sd.signature.data); - - return encode_result ? SECSuccess : SECFailure; -}
diff --git a/src/crypto/third_party/nss/sha512.cc b/src/crypto/third_party/nss/sha512.cc deleted file mode 100644 index 976a604..0000000 --- a/src/crypto/third_party/nss/sha512.cc +++ /dev/null
@@ -1,1391 +0,0 @@ -/* - * sha512.c - implementation of SHA256, SHA384 and SHA512 - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -/* $Id: sha512.c,v 1.9 2006/10/13 16:54:04 wtchang%redhat.com Exp $ */ - -// Prevent manual unrolling in the sha256 code, which reduces the binary code -// size from ~10k to ~1k. The performance should be reasonable for our use. -#define NOUNROLL256 1 - -#include "base/third_party/nspr/prtypes.h" /* for PRUintXX */ -#if defined(_X86_) || defined(SHA_NO_LONG_LONG) -#define NOUNROLL512 1 -#undef HAVE_LONG_LONG -#endif -#include "crypto/third_party/nss/chromium-blapi.h" -#include "crypto/third_party/nss/chromium-sha256.h" /* for struct SHA256ContextStr */ - -#include <stdlib.h> -#include <string.h> -#define PORT_New(type) static_cast<type*>(malloc(sizeof(type))) -#define PORT_ZFree(ptr, len) do { memset(ptr, 0, len); free(ptr); } while (0) -#define PORT_Strlen(s) static_cast<unsigned int>(strlen(s)) -#define PORT_Memcpy memcpy - -/* ============= Common constants and defines ======================= */ - -#define W ctx->u.w -#define B ctx->u.b -#define H ctx->h - -#define SHR(x,n) (x >> n) -#define SHL(x,n) (x << n) -#define Ch(x,y,z) ((x & y) ^ (~x & z)) -#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) - -/* Padding used with all flavors of SHA */ -static const PRUint8 pad[240] = { -0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - /* compiler will fill the rest in with zeros */ -}; - -/* ============= SHA256 implemenmtation ================================== */ - -/* SHA-256 constants, K256. */ -static const PRUint32 K256[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -/* SHA-256 initial hash values */ -static const PRUint32 H256[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 -}; - -#if defined(_MSC_VER) && defined(_X86_) -#ifndef FORCEINLINE -#if (_MSC_VER >= 1200) -#define FORCEINLINE __forceinline -#else -#define FORCEINLINE __inline -#endif -#endif -#define FASTCALL __fastcall - -static FORCEINLINE PRUint32 FASTCALL -swap4b(PRUint32 dwd) -{ - __asm { - mov eax,dwd - bswap eax - } -} - -#define SHA_HTONL(x) swap4b(x) -#define BYTESWAP4(x) x = SHA_HTONL(x) - -#elif defined(LINUX) && defined(_X86_) -#undef __OPTIMIZE__ -#define __OPTIMIZE__ 1 -#undef __pentium__ -#define __pentium__ 1 -#include <byteswap.h> -#define SHA_HTONL(x) bswap_32(x) -#define BYTESWAP4(x) x = SHA_HTONL(x) - -#else /* neither windows nor Linux PC */ -#define SWAP4MASK 0x00FF00FF -#define SHA_HTONL(x) (t1 = (x), t1 = (t1 << 16) | (t1 >> 16), \ - ((t1 & SWAP4MASK) << 8) | ((t1 >> 8) & SWAP4MASK)) -#define BYTESWAP4(x) x = SHA_HTONL(x) -#endif - -#if defined(_MSC_VER) && defined(_X86_) -#pragma intrinsic (_lrotr, _lrotl) -#define ROTR32(x,n) _lrotr(x,n) -#define ROTL32(x,n) _lrotl(x,n) -#else -#define ROTR32(x,n) ((x >> n) | (x << ((8 * sizeof x) - n))) -#define ROTL32(x,n) ((x << n) | (x >> ((8 * sizeof x) - n))) -#endif - -/* Capitol Sigma and lower case sigma functions */ -#define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x,22)) -#define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x,25)) -#define s0(x) (t1 = x, ROTR32(t1, 7) ^ ROTR32(t1,18) ^ SHR(t1, 3)) -#define s1(x) (t2 = x, ROTR32(t2,17) ^ ROTR32(t2,19) ^ SHR(t2,10)) - -SHA256Context * -SHA256_NewContext(void) -{ - SHA256Context *ctx = PORT_New(SHA256Context); - return ctx; -} - -void -SHA256_DestroyContext(SHA256Context *ctx, PRBool freeit) -{ - if (freeit) { - PORT_ZFree(ctx, sizeof *ctx); - } -} - -void -SHA256_Begin(SHA256Context *ctx) -{ - memset(ctx, 0, sizeof *ctx); - memcpy(H, H256, sizeof H256); -} - -static void -SHA256_Compress(SHA256Context *ctx) -{ - { - register PRUint32 t1, t2; - -#if defined(IS_LITTLE_ENDIAN) - BYTESWAP4(W[0]); - BYTESWAP4(W[1]); - BYTESWAP4(W[2]); - BYTESWAP4(W[3]); - BYTESWAP4(W[4]); - BYTESWAP4(W[5]); - BYTESWAP4(W[6]); - BYTESWAP4(W[7]); - BYTESWAP4(W[8]); - BYTESWAP4(W[9]); - BYTESWAP4(W[10]); - BYTESWAP4(W[11]); - BYTESWAP4(W[12]); - BYTESWAP4(W[13]); - BYTESWAP4(W[14]); - BYTESWAP4(W[15]); -#endif - -#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16]) - - /* prepare the "message schedule" */ -#ifdef NOUNROLL256 - { - int t; - for (t = 16; t < 64; ++t) { - INITW(t); - } - } -#else - INITW(16); - INITW(17); - INITW(18); - INITW(19); - - INITW(20); - INITW(21); - INITW(22); - INITW(23); - INITW(24); - INITW(25); - INITW(26); - INITW(27); - INITW(28); - INITW(29); - - INITW(30); - INITW(31); - INITW(32); - INITW(33); - INITW(34); - INITW(35); - INITW(36); - INITW(37); - INITW(38); - INITW(39); - - INITW(40); - INITW(41); - INITW(42); - INITW(43); - INITW(44); - INITW(45); - INITW(46); - INITW(47); - INITW(48); - INITW(49); - - INITW(50); - INITW(51); - INITW(52); - INITW(53); - INITW(54); - INITW(55); - INITW(56); - INITW(57); - INITW(58); - INITW(59); - - INITW(60); - INITW(61); - INITW(62); - INITW(63); - -#endif -#undef INITW - } - { - PRUint32 a, b, c, d, e, f, g, h; - - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; - f = H[5]; - g = H[6]; - h = H[7]; - -#define ROUND(n,a,b,c,d,e,f,g,h) \ - h += S1(e) + Ch(e,f,g) + K256[n] + W[n]; \ - d += h; \ - h += S0(a) + Maj(a,b,c); - -#ifdef NOUNROLL256 - { - int t; - for (t = 0; t < 64; t+= 8) { - ROUND(t+0,a,b,c,d,e,f,g,h) - ROUND(t+1,h,a,b,c,d,e,f,g) - ROUND(t+2,g,h,a,b,c,d,e,f) - ROUND(t+3,f,g,h,a,b,c,d,e) - ROUND(t+4,e,f,g,h,a,b,c,d) - ROUND(t+5,d,e,f,g,h,a,b,c) - ROUND(t+6,c,d,e,f,g,h,a,b) - ROUND(t+7,b,c,d,e,f,g,h,a) - } - } -#else - ROUND( 0,a,b,c,d,e,f,g,h) - ROUND( 1,h,a,b,c,d,e,f,g) - ROUND( 2,g,h,a,b,c,d,e,f) - ROUND( 3,f,g,h,a,b,c,d,e) - ROUND( 4,e,f,g,h,a,b,c,d) - ROUND( 5,d,e,f,g,h,a,b,c) - ROUND( 6,c,d,e,f,g,h,a,b) - ROUND( 7,b,c,d,e,f,g,h,a) - - ROUND( 8,a,b,c,d,e,f,g,h) - ROUND( 9,h,a,b,c,d,e,f,g) - ROUND(10,g,h,a,b,c,d,e,f) - ROUND(11,f,g,h,a,b,c,d,e) - ROUND(12,e,f,g,h,a,b,c,d) - ROUND(13,d,e,f,g,h,a,b,c) - ROUND(14,c,d,e,f,g,h,a,b) - ROUND(15,b,c,d,e,f,g,h,a) - - ROUND(16,a,b,c,d,e,f,g,h) - ROUND(17,h,a,b,c,d,e,f,g) - ROUND(18,g,h,a,b,c,d,e,f) - ROUND(19,f,g,h,a,b,c,d,e) - ROUND(20,e,f,g,h,a,b,c,d) - ROUND(21,d,e,f,g,h,a,b,c) - ROUND(22,c,d,e,f,g,h,a,b) - ROUND(23,b,c,d,e,f,g,h,a) - - ROUND(24,a,b,c,d,e,f,g,h) - ROUND(25,h,a,b,c,d,e,f,g) - ROUND(26,g,h,a,b,c,d,e,f) - ROUND(27,f,g,h,a,b,c,d,e) - ROUND(28,e,f,g,h,a,b,c,d) - ROUND(29,d,e,f,g,h,a,b,c) - ROUND(30,c,d,e,f,g,h,a,b) - ROUND(31,b,c,d,e,f,g,h,a) - - ROUND(32,a,b,c,d,e,f,g,h) - ROUND(33,h,a,b,c,d,e,f,g) - ROUND(34,g,h,a,b,c,d,e,f) - ROUND(35,f,g,h,a,b,c,d,e) - ROUND(36,e,f,g,h,a,b,c,d) - ROUND(37,d,e,f,g,h,a,b,c) - ROUND(38,c,d,e,f,g,h,a,b) - ROUND(39,b,c,d,e,f,g,h,a) - - ROUND(40,a,b,c,d,e,f,g,h) - ROUND(41,h,a,b,c,d,e,f,g) - ROUND(42,g,h,a,b,c,d,e,f) - ROUND(43,f,g,h,a,b,c,d,e) - ROUND(44,e,f,g,h,a,b,c,d) - ROUND(45,d,e,f,g,h,a,b,c) - ROUND(46,c,d,e,f,g,h,a,b) - ROUND(47,b,c,d,e,f,g,h,a) - - ROUND(48,a,b,c,d,e,f,g,h) - ROUND(49,h,a,b,c,d,e,f,g) - ROUND(50,g,h,a,b,c,d,e,f) - ROUND(51,f,g,h,a,b,c,d,e) - ROUND(52,e,f,g,h,a,b,c,d) - ROUND(53,d,e,f,g,h,a,b,c) - ROUND(54,c,d,e,f,g,h,a,b) - ROUND(55,b,c,d,e,f,g,h,a) - - ROUND(56,a,b,c,d,e,f,g,h) - ROUND(57,h,a,b,c,d,e,f,g) - ROUND(58,g,h,a,b,c,d,e,f) - ROUND(59,f,g,h,a,b,c,d,e) - ROUND(60,e,f,g,h,a,b,c,d) - ROUND(61,d,e,f,g,h,a,b,c) - ROUND(62,c,d,e,f,g,h,a,b) - ROUND(63,b,c,d,e,f,g,h,a) -#endif - - H[0] += a; - H[1] += b; - H[2] += c; - H[3] += d; - H[4] += e; - H[5] += f; - H[6] += g; - H[7] += h; - } -#undef ROUND -} - -#undef s0 -#undef s1 -#undef S0 -#undef S1 - -void -SHA256_Update(SHA256Context *ctx, const unsigned char *input, - unsigned int inputLen) -{ - unsigned int inBuf = ctx->sizeLo & 0x3f; - if (!inputLen) - return; - - /* Add inputLen into the count of bytes processed, before processing */ - if ((ctx->sizeLo += inputLen) < inputLen) - ctx->sizeHi++; - - /* if data already in buffer, attemp to fill rest of buffer */ - if (inBuf) { - unsigned int todo = SHA256_BLOCK_LENGTH - inBuf; - if (inputLen < todo) - todo = inputLen; - memcpy(B + inBuf, input, todo); - input += todo; - inputLen -= todo; - if (inBuf + todo == SHA256_BLOCK_LENGTH) - SHA256_Compress(ctx); - } - - /* if enough data to fill one or more whole buffers, process them. */ - while (inputLen >= SHA256_BLOCK_LENGTH) { - memcpy(B, input, SHA256_BLOCK_LENGTH); - input += SHA256_BLOCK_LENGTH; - inputLen -= SHA256_BLOCK_LENGTH; - SHA256_Compress(ctx); - } - /* if data left over, fill it into buffer */ - if (inputLen) - memcpy(B, input, inputLen); -} - -void -SHA256_End(SHA256Context *ctx, unsigned char *digest, - unsigned int *digestLen, unsigned int maxDigestLen) -{ - unsigned int inBuf = ctx->sizeLo & 0x3f; - unsigned int padLen = (inBuf < 56) ? (56 - inBuf) : (56 + 64 - inBuf); - PRUint32 hi, lo; -#ifdef SWAP4MASK - PRUint32 t1; -#endif - - hi = (ctx->sizeHi << 3) | (ctx->sizeLo >> 29); - lo = (ctx->sizeLo << 3); - - SHA256_Update(ctx, pad, padLen); - -#if defined(IS_LITTLE_ENDIAN) - W[14] = SHA_HTONL(hi); - W[15] = SHA_HTONL(lo); -#else - W[14] = hi; - W[15] = lo; -#endif - SHA256_Compress(ctx); - - /* now output the answer */ -#if defined(IS_LITTLE_ENDIAN) - BYTESWAP4(H[0]); - BYTESWAP4(H[1]); - BYTESWAP4(H[2]); - BYTESWAP4(H[3]); - BYTESWAP4(H[4]); - BYTESWAP4(H[5]); - BYTESWAP4(H[6]); - BYTESWAP4(H[7]); -#endif - padLen = PR_MIN(SHA256_LENGTH, maxDigestLen); - memcpy(digest, H, padLen); - if (digestLen) - *digestLen = padLen; -} - -/* Comment out unused code, mostly the SHA384 and SHA512 implementations. */ -#if 0 -SECStatus -SHA256_HashBuf(unsigned char *dest, const unsigned char *src, - unsigned int src_length) -{ - SHA256Context ctx; - unsigned int outLen; - - SHA256_Begin(&ctx); - SHA256_Update(&ctx, src, src_length); - SHA256_End(&ctx, dest, &outLen, SHA256_LENGTH); - - return SECSuccess; -} - - -SECStatus -SHA256_Hash(unsigned char *dest, const char *src) -{ - return SHA256_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); -} - - -void SHA256_TraceState(SHA256Context *ctx) { } - -unsigned int -SHA256_FlattenSize(SHA256Context *ctx) -{ - return sizeof *ctx; -} - -SECStatus -SHA256_Flatten(SHA256Context *ctx,unsigned char *space) -{ - PORT_Memcpy(space, ctx, sizeof *ctx); - return SECSuccess; -} - -SHA256Context * -SHA256_Resurrect(unsigned char *space, void *arg) -{ - SHA256Context *ctx = SHA256_NewContext(); - if (ctx) - PORT_Memcpy(ctx, space, sizeof *ctx); - return ctx; -} - -void SHA256_Clone(SHA256Context *dest, SHA256Context *src) -{ - memcpy(dest, src, sizeof *dest); -} - - -/* ======= SHA512 and SHA384 common constants and defines ================= */ - -/* common #defines for SHA512 and SHA384 */ -#if defined(HAVE_LONG_LONG) -#define ROTR64(x,n) ((x >> n) | (x << (64 - n))) -#define ROTL64(x,n) ((x << n) | (x >> (64 - n))) - -#define S0(x) (ROTR64(x,28) ^ ROTR64(x,34) ^ ROTR64(x,39)) -#define S1(x) (ROTR64(x,14) ^ ROTR64(x,18) ^ ROTR64(x,41)) -#define s0(x) (t1 = x, ROTR64(t1, 1) ^ ROTR64(t1, 8) ^ SHR(t1,7)) -#define s1(x) (t2 = x, ROTR64(t2,19) ^ ROTR64(t2,61) ^ SHR(t2,6)) - -#if PR_BYTES_PER_LONG == 8 -#define ULLC(hi,lo) 0x ## hi ## lo ## UL -#elif defined(_MSC_VER) -#define ULLC(hi,lo) 0x ## hi ## lo ## ui64 -#else -#define ULLC(hi,lo) 0x ## hi ## lo ## ULL -#endif - -#define SHA_MASK16 ULLC(0000FFFF,0000FFFF) -#define SHA_MASK8 ULLC(00FF00FF,00FF00FF) -#define SHA_HTONLL(x) (t1 = x, \ - t1 = ((t1 & SHA_MASK8 ) << 8) | ((t1 >> 8) & SHA_MASK8 ), \ - t1 = ((t1 & SHA_MASK16) << 16) | ((t1 >> 16) & SHA_MASK16), \ - (t1 >> 32) | (t1 << 32)) -#define BYTESWAP8(x) x = SHA_HTONLL(x) - -#else /* no long long */ - -#if defined(IS_LITTLE_ENDIAN) -#define ULLC(hi,lo) { 0x ## lo ## U, 0x ## hi ## U } -#else -#define ULLC(hi,lo) { 0x ## hi ## U, 0x ## lo ## U } -#endif - -#define SHA_HTONLL(x) ( BYTESWAP4(x.lo), BYTESWAP4(x.hi), \ - x.hi ^= x.lo ^= x.hi ^= x.lo, x) -#define BYTESWAP8(x) do { PRUint32 tmp; BYTESWAP4(x.lo); BYTESWAP4(x.hi); \ - tmp = x.lo; x.lo = x.hi; x.hi = tmp; } while (0) -#endif - -/* SHA-384 and SHA-512 constants, K512. */ -static const PRUint64 K512[80] = { -#if PR_BYTES_PER_LONG == 8 - 0x428a2f98d728ae22UL , 0x7137449123ef65cdUL , - 0xb5c0fbcfec4d3b2fUL , 0xe9b5dba58189dbbcUL , - 0x3956c25bf348b538UL , 0x59f111f1b605d019UL , - 0x923f82a4af194f9bUL , 0xab1c5ed5da6d8118UL , - 0xd807aa98a3030242UL , 0x12835b0145706fbeUL , - 0x243185be4ee4b28cUL , 0x550c7dc3d5ffb4e2UL , - 0x72be5d74f27b896fUL , 0x80deb1fe3b1696b1UL , - 0x9bdc06a725c71235UL , 0xc19bf174cf692694UL , - 0xe49b69c19ef14ad2UL , 0xefbe4786384f25e3UL , - 0x0fc19dc68b8cd5b5UL , 0x240ca1cc77ac9c65UL , - 0x2de92c6f592b0275UL , 0x4a7484aa6ea6e483UL , - 0x5cb0a9dcbd41fbd4UL , 0x76f988da831153b5UL , - 0x983e5152ee66dfabUL , 0xa831c66d2db43210UL , - 0xb00327c898fb213fUL , 0xbf597fc7beef0ee4UL , - 0xc6e00bf33da88fc2UL , 0xd5a79147930aa725UL , - 0x06ca6351e003826fUL , 0x142929670a0e6e70UL , - 0x27b70a8546d22ffcUL , 0x2e1b21385c26c926UL , - 0x4d2c6dfc5ac42aedUL , 0x53380d139d95b3dfUL , - 0x650a73548baf63deUL , 0x766a0abb3c77b2a8UL , - 0x81c2c92e47edaee6UL , 0x92722c851482353bUL , - 0xa2bfe8a14cf10364UL , 0xa81a664bbc423001UL , - 0xc24b8b70d0f89791UL , 0xc76c51a30654be30UL , - 0xd192e819d6ef5218UL , 0xd69906245565a910UL , - 0xf40e35855771202aUL , 0x106aa07032bbd1b8UL , - 0x19a4c116b8d2d0c8UL , 0x1e376c085141ab53UL , - 0x2748774cdf8eeb99UL , 0x34b0bcb5e19b48a8UL , - 0x391c0cb3c5c95a63UL , 0x4ed8aa4ae3418acbUL , - 0x5b9cca4f7763e373UL , 0x682e6ff3d6b2b8a3UL , - 0x748f82ee5defb2fcUL , 0x78a5636f43172f60UL , - 0x84c87814a1f0ab72UL , 0x8cc702081a6439ecUL , - 0x90befffa23631e28UL , 0xa4506cebde82bde9UL , - 0xbef9a3f7b2c67915UL , 0xc67178f2e372532bUL , - 0xca273eceea26619cUL , 0xd186b8c721c0c207UL , - 0xeada7dd6cde0eb1eUL , 0xf57d4f7fee6ed178UL , - 0x06f067aa72176fbaUL , 0x0a637dc5a2c898a6UL , - 0x113f9804bef90daeUL , 0x1b710b35131c471bUL , - 0x28db77f523047d84UL , 0x32caab7b40c72493UL , - 0x3c9ebe0a15c9bebcUL , 0x431d67c49c100d4cUL , - 0x4cc5d4becb3e42b6UL , 0x597f299cfc657e2aUL , - 0x5fcb6fab3ad6faecUL , 0x6c44198c4a475817UL -#else - ULLC(428a2f98,d728ae22), ULLC(71374491,23ef65cd), - ULLC(b5c0fbcf,ec4d3b2f), ULLC(e9b5dba5,8189dbbc), - ULLC(3956c25b,f348b538), ULLC(59f111f1,b605d019), - ULLC(923f82a4,af194f9b), ULLC(ab1c5ed5,da6d8118), - ULLC(d807aa98,a3030242), ULLC(12835b01,45706fbe), - ULLC(243185be,4ee4b28c), ULLC(550c7dc3,d5ffb4e2), - ULLC(72be5d74,f27b896f), ULLC(80deb1fe,3b1696b1), - ULLC(9bdc06a7,25c71235), ULLC(c19bf174,cf692694), - ULLC(e49b69c1,9ef14ad2), ULLC(efbe4786,384f25e3), - ULLC(0fc19dc6,8b8cd5b5), ULLC(240ca1cc,77ac9c65), - ULLC(2de92c6f,592b0275), ULLC(4a7484aa,6ea6e483), - ULLC(5cb0a9dc,bd41fbd4), ULLC(76f988da,831153b5), - ULLC(983e5152,ee66dfab), ULLC(a831c66d,2db43210), - ULLC(b00327c8,98fb213f), ULLC(bf597fc7,beef0ee4), - ULLC(c6e00bf3,3da88fc2), ULLC(d5a79147,930aa725), - ULLC(06ca6351,e003826f), ULLC(14292967,0a0e6e70), - ULLC(27b70a85,46d22ffc), ULLC(2e1b2138,5c26c926), - ULLC(4d2c6dfc,5ac42aed), ULLC(53380d13,9d95b3df), - ULLC(650a7354,8baf63de), ULLC(766a0abb,3c77b2a8), - ULLC(81c2c92e,47edaee6), ULLC(92722c85,1482353b), - ULLC(a2bfe8a1,4cf10364), ULLC(a81a664b,bc423001), - ULLC(c24b8b70,d0f89791), ULLC(c76c51a3,0654be30), - ULLC(d192e819,d6ef5218), ULLC(d6990624,5565a910), - ULLC(f40e3585,5771202a), ULLC(106aa070,32bbd1b8), - ULLC(19a4c116,b8d2d0c8), ULLC(1e376c08,5141ab53), - ULLC(2748774c,df8eeb99), ULLC(34b0bcb5,e19b48a8), - ULLC(391c0cb3,c5c95a63), ULLC(4ed8aa4a,e3418acb), - ULLC(5b9cca4f,7763e373), ULLC(682e6ff3,d6b2b8a3), - ULLC(748f82ee,5defb2fc), ULLC(78a5636f,43172f60), - ULLC(84c87814,a1f0ab72), ULLC(8cc70208,1a6439ec), - ULLC(90befffa,23631e28), ULLC(a4506ceb,de82bde9), - ULLC(bef9a3f7,b2c67915), ULLC(c67178f2,e372532b), - ULLC(ca273ece,ea26619c), ULLC(d186b8c7,21c0c207), - ULLC(eada7dd6,cde0eb1e), ULLC(f57d4f7f,ee6ed178), - ULLC(06f067aa,72176fba), ULLC(0a637dc5,a2c898a6), - ULLC(113f9804,bef90dae), ULLC(1b710b35,131c471b), - ULLC(28db77f5,23047d84), ULLC(32caab7b,40c72493), - ULLC(3c9ebe0a,15c9bebc), ULLC(431d67c4,9c100d4c), - ULLC(4cc5d4be,cb3e42b6), ULLC(597f299c,fc657e2a), - ULLC(5fcb6fab,3ad6faec), ULLC(6c44198c,4a475817) -#endif -}; - -struct SHA512ContextStr { - union { - PRUint64 w[80]; /* message schedule, input buffer, plus 64 words */ - PRUint32 l[160]; - PRUint8 b[640]; - } u; - PRUint64 h[8]; /* 8 state variables */ - PRUint64 sizeLo; /* 64-bit count of hashed bytes. */ -}; - -/* =========== SHA512 implementation ===================================== */ - -/* SHA-512 initial hash values */ -static const PRUint64 H512[8] = { -#if PR_BYTES_PER_LONG == 8 - 0x6a09e667f3bcc908UL , 0xbb67ae8584caa73bUL , - 0x3c6ef372fe94f82bUL , 0xa54ff53a5f1d36f1UL , - 0x510e527fade682d1UL , 0x9b05688c2b3e6c1fUL , - 0x1f83d9abfb41bd6bUL , 0x5be0cd19137e2179UL -#else - ULLC(6a09e667,f3bcc908), ULLC(bb67ae85,84caa73b), - ULLC(3c6ef372,fe94f82b), ULLC(a54ff53a,5f1d36f1), - ULLC(510e527f,ade682d1), ULLC(9b05688c,2b3e6c1f), - ULLC(1f83d9ab,fb41bd6b), ULLC(5be0cd19,137e2179) -#endif -}; - - -SHA512Context * -SHA512_NewContext(void) -{ - SHA512Context *ctx = PORT_New(SHA512Context); - return ctx; -} - -void -SHA512_DestroyContext(SHA512Context *ctx, PRBool freeit) -{ - if (freeit) { - PORT_ZFree(ctx, sizeof *ctx); - } -} - -void -SHA512_Begin(SHA512Context *ctx) -{ - memset(ctx, 0, sizeof *ctx); - memcpy(H, H512, sizeof H512); -} - -#if defined(SHA512_TRACE) -#if defined(HAVE_LONG_LONG) -#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %016lx, %s = %016lx\n", \ - n, #e, d, #a, h); -#else -#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %08x%08x, %s = %08x%08x\n", \ - n, #e, d.hi, d.lo, #a, h.hi, h.lo); -#endif -#else -#define DUMP(n,a,d,e,h) -#endif - -#if defined(HAVE_LONG_LONG) - -#define ADDTO(x,y) y += x - -#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16]) - -#define ROUND(n,a,b,c,d,e,f,g,h) \ - h += S1(e) + Ch(e,f,g) + K512[n] + W[n]; \ - d += h; \ - h += S0(a) + Maj(a,b,c); \ - DUMP(n,a,d,e,h) - -#else /* use only 32-bit variables, and don't unroll loops */ - -#undef NOUNROLL512 -#define NOUNROLL512 1 - -#define ADDTO(x,y) y.lo += x.lo; y.hi += x.hi + (x.lo > y.lo) - -#define ROTR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n)) -#define ROTR64A(x,n,lo,hi) (x.lo << (64-n) | x.hi >> (n-32)) -#define SHR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n)) - -/* Capitol Sigma and lower case sigma functions */ -#define s0lo(x) (ROTR64a(x,1,lo,hi) ^ ROTR64a(x,8,lo,hi) ^ SHR64a(x,7,lo,hi)) -#define s0hi(x) (ROTR64a(x,1,hi,lo) ^ ROTR64a(x,8,hi,lo) ^ (x.hi >> 7)) - -#define s1lo(x) (ROTR64a(x,19,lo,hi) ^ ROTR64A(x,61,lo,hi) ^ SHR64a(x,6,lo,hi)) -#define s1hi(x) (ROTR64a(x,19,hi,lo) ^ ROTR64A(x,61,hi,lo) ^ (x.hi >> 6)) - -#define S0lo(x)(ROTR64a(x,28,lo,hi) ^ ROTR64A(x,34,lo,hi) ^ ROTR64A(x,39,lo,hi)) -#define S0hi(x)(ROTR64a(x,28,hi,lo) ^ ROTR64A(x,34,hi,lo) ^ ROTR64A(x,39,hi,lo)) - -#define S1lo(x)(ROTR64a(x,14,lo,hi) ^ ROTR64a(x,18,lo,hi) ^ ROTR64A(x,41,lo,hi)) -#define S1hi(x)(ROTR64a(x,14,hi,lo) ^ ROTR64a(x,18,hi,lo) ^ ROTR64A(x,41,hi,lo)) - -/* 32-bit versions of Ch and Maj */ -#define Chxx(x,y,z,lo) ((x.lo & y.lo) ^ (~x.lo & z.lo)) -#define Majx(x,y,z,lo) ((x.lo & y.lo) ^ (x.lo & z.lo) ^ (y.lo & z.lo)) - -#define INITW(t) \ - do { \ - PRUint32 lo, tm; \ - PRUint32 cy = 0; \ - lo = s1lo(W[t-2]); \ - lo += (tm = W[t-7].lo); if (lo < tm) cy++; \ - lo += (tm = s0lo(W[t-15])); if (lo < tm) cy++; \ - lo += (tm = W[t-16].lo); if (lo < tm) cy++; \ - W[t].lo = lo; \ - W[t].hi = cy + s1hi(W[t-2]) + W[t-7].hi + s0hi(W[t-15]) + W[t-16].hi; \ - } while (0) - -#define ROUND(n,a,b,c,d,e,f,g,h) \ - { \ - PRUint32 lo, tm, cy; \ - lo = S1lo(e); \ - lo += (tm = Chxx(e,f,g,lo)); cy = (lo < tm); \ - lo += (tm = K512[n].lo); if (lo < tm) cy++; \ - lo += (tm = W[n].lo); if (lo < tm) cy++; \ - h.lo += lo; if (h.lo < lo) cy++; \ - h.hi += cy + S1hi(e) + Chxx(e,f,g,hi) + K512[n].hi + W[n].hi; \ - d.lo += h.lo; \ - d.hi += h.hi + (d.lo < h.lo); \ - lo = S0lo(a); \ - lo += (tm = Majx(a,b,c,lo)); cy = (lo < tm); \ - h.lo += lo; if (h.lo < lo) cy++; \ - h.hi += cy + S0hi(a) + Majx(a,b,c,hi); \ - DUMP(n,a,d,e,h) \ - } -#endif - -static void -SHA512_Compress(SHA512Context *ctx) -{ -#if defined(IS_LITTLE_ENDIAN) - { -#if defined(HAVE_LONG_LONG) - PRUint64 t1; -#else - PRUint32 t1; -#endif - BYTESWAP8(W[0]); - BYTESWAP8(W[1]); - BYTESWAP8(W[2]); - BYTESWAP8(W[3]); - BYTESWAP8(W[4]); - BYTESWAP8(W[5]); - BYTESWAP8(W[6]); - BYTESWAP8(W[7]); - BYTESWAP8(W[8]); - BYTESWAP8(W[9]); - BYTESWAP8(W[10]); - BYTESWAP8(W[11]); - BYTESWAP8(W[12]); - BYTESWAP8(W[13]); - BYTESWAP8(W[14]); - BYTESWAP8(W[15]); - } -#endif - - { - PRUint64 t1, t2; -#ifdef NOUNROLL512 - { - /* prepare the "message schedule" */ - int t; - for (t = 16; t < 80; ++t) { - INITW(t); - } - } -#else - INITW(16); - INITW(17); - INITW(18); - INITW(19); - - INITW(20); - INITW(21); - INITW(22); - INITW(23); - INITW(24); - INITW(25); - INITW(26); - INITW(27); - INITW(28); - INITW(29); - - INITW(30); - INITW(31); - INITW(32); - INITW(33); - INITW(34); - INITW(35); - INITW(36); - INITW(37); - INITW(38); - INITW(39); - - INITW(40); - INITW(41); - INITW(42); - INITW(43); - INITW(44); - INITW(45); - INITW(46); - INITW(47); - INITW(48); - INITW(49); - - INITW(50); - INITW(51); - INITW(52); - INITW(53); - INITW(54); - INITW(55); - INITW(56); - INITW(57); - INITW(58); - INITW(59); - - INITW(60); - INITW(61); - INITW(62); - INITW(63); - INITW(64); - INITW(65); - INITW(66); - INITW(67); - INITW(68); - INITW(69); - - INITW(70); - INITW(71); - INITW(72); - INITW(73); - INITW(74); - INITW(75); - INITW(76); - INITW(77); - INITW(78); - INITW(79); -#endif - } -#ifdef SHA512_TRACE - { - int i; - for (i = 0; i < 80; ++i) { -#ifdef HAVE_LONG_LONG - printf("W[%2d] = %016lx\n", i, W[i]); -#else - printf("W[%2d] = %08x%08x\n", i, W[i].hi, W[i].lo); -#endif - } - } -#endif - { - PRUint64 a, b, c, d, e, f, g, h; - - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; - f = H[5]; - g = H[6]; - h = H[7]; - -#ifdef NOUNROLL512 - { - int t; - for (t = 0; t < 80; t+= 8) { - ROUND(t+0,a,b,c,d,e,f,g,h) - ROUND(t+1,h,a,b,c,d,e,f,g) - ROUND(t+2,g,h,a,b,c,d,e,f) - ROUND(t+3,f,g,h,a,b,c,d,e) - ROUND(t+4,e,f,g,h,a,b,c,d) - ROUND(t+5,d,e,f,g,h,a,b,c) - ROUND(t+6,c,d,e,f,g,h,a,b) - ROUND(t+7,b,c,d,e,f,g,h,a) - } - } -#else - ROUND( 0,a,b,c,d,e,f,g,h) - ROUND( 1,h,a,b,c,d,e,f,g) - ROUND( 2,g,h,a,b,c,d,e,f) - ROUND( 3,f,g,h,a,b,c,d,e) - ROUND( 4,e,f,g,h,a,b,c,d) - ROUND( 5,d,e,f,g,h,a,b,c) - ROUND( 6,c,d,e,f,g,h,a,b) - ROUND( 7,b,c,d,e,f,g,h,a) - - ROUND( 8,a,b,c,d,e,f,g,h) - ROUND( 9,h,a,b,c,d,e,f,g) - ROUND(10,g,h,a,b,c,d,e,f) - ROUND(11,f,g,h,a,b,c,d,e) - ROUND(12,e,f,g,h,a,b,c,d) - ROUND(13,d,e,f,g,h,a,b,c) - ROUND(14,c,d,e,f,g,h,a,b) - ROUND(15,b,c,d,e,f,g,h,a) - - ROUND(16,a,b,c,d,e,f,g,h) - ROUND(17,h,a,b,c,d,e,f,g) - ROUND(18,g,h,a,b,c,d,e,f) - ROUND(19,f,g,h,a,b,c,d,e) - ROUND(20,e,f,g,h,a,b,c,d) - ROUND(21,d,e,f,g,h,a,b,c) - ROUND(22,c,d,e,f,g,h,a,b) - ROUND(23,b,c,d,e,f,g,h,a) - - ROUND(24,a,b,c,d,e,f,g,h) - ROUND(25,h,a,b,c,d,e,f,g) - ROUND(26,g,h,a,b,c,d,e,f) - ROUND(27,f,g,h,a,b,c,d,e) - ROUND(28,e,f,g,h,a,b,c,d) - ROUND(29,d,e,f,g,h,a,b,c) - ROUND(30,c,d,e,f,g,h,a,b) - ROUND(31,b,c,d,e,f,g,h,a) - - ROUND(32,a,b,c,d,e,f,g,h) - ROUND(33,h,a,b,c,d,e,f,g) - ROUND(34,g,h,a,b,c,d,e,f) - ROUND(35,f,g,h,a,b,c,d,e) - ROUND(36,e,f,g,h,a,b,c,d) - ROUND(37,d,e,f,g,h,a,b,c) - ROUND(38,c,d,e,f,g,h,a,b) - ROUND(39,b,c,d,e,f,g,h,a) - - ROUND(40,a,b,c,d,e,f,g,h) - ROUND(41,h,a,b,c,d,e,f,g) - ROUND(42,g,h,a,b,c,d,e,f) - ROUND(43,f,g,h,a,b,c,d,e) - ROUND(44,e,f,g,h,a,b,c,d) - ROUND(45,d,e,f,g,h,a,b,c) - ROUND(46,c,d,e,f,g,h,a,b) - ROUND(47,b,c,d,e,f,g,h,a) - - ROUND(48,a,b,c,d,e,f,g,h) - ROUND(49,h,a,b,c,d,e,f,g) - ROUND(50,g,h,a,b,c,d,e,f) - ROUND(51,f,g,h,a,b,c,d,e) - ROUND(52,e,f,g,h,a,b,c,d) - ROUND(53,d,e,f,g,h,a,b,c) - ROUND(54,c,d,e,f,g,h,a,b) - ROUND(55,b,c,d,e,f,g,h,a) - - ROUND(56,a,b,c,d,e,f,g,h) - ROUND(57,h,a,b,c,d,e,f,g) - ROUND(58,g,h,a,b,c,d,e,f) - ROUND(59,f,g,h,a,b,c,d,e) - ROUND(60,e,f,g,h,a,b,c,d) - ROUND(61,d,e,f,g,h,a,b,c) - ROUND(62,c,d,e,f,g,h,a,b) - ROUND(63,b,c,d,e,f,g,h,a) - - ROUND(64,a,b,c,d,e,f,g,h) - ROUND(65,h,a,b,c,d,e,f,g) - ROUND(66,g,h,a,b,c,d,e,f) - ROUND(67,f,g,h,a,b,c,d,e) - ROUND(68,e,f,g,h,a,b,c,d) - ROUND(69,d,e,f,g,h,a,b,c) - ROUND(70,c,d,e,f,g,h,a,b) - ROUND(71,b,c,d,e,f,g,h,a) - - ROUND(72,a,b,c,d,e,f,g,h) - ROUND(73,h,a,b,c,d,e,f,g) - ROUND(74,g,h,a,b,c,d,e,f) - ROUND(75,f,g,h,a,b,c,d,e) - ROUND(76,e,f,g,h,a,b,c,d) - ROUND(77,d,e,f,g,h,a,b,c) - ROUND(78,c,d,e,f,g,h,a,b) - ROUND(79,b,c,d,e,f,g,h,a) -#endif - - ADDTO(a,H[0]); - ADDTO(b,H[1]); - ADDTO(c,H[2]); - ADDTO(d,H[3]); - ADDTO(e,H[4]); - ADDTO(f,H[5]); - ADDTO(g,H[6]); - ADDTO(h,H[7]); - } -} - -void -SHA512_Update(SHA512Context *ctx, const unsigned char *input, - unsigned int inputLen) -{ - unsigned int inBuf; - if (!inputLen) - return; - -#if defined(HAVE_LONG_LONG) - inBuf = (unsigned int)ctx->sizeLo & 0x7f; - /* Add inputLen into the count of bytes processed, before processing */ - ctx->sizeLo += inputLen; -#else - inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f; - ctx->sizeLo.lo += inputLen; - if (ctx->sizeLo.lo < inputLen) ctx->sizeLo.hi++; -#endif - - /* if data already in buffer, attemp to fill rest of buffer */ - if (inBuf) { - unsigned int todo = SHA512_BLOCK_LENGTH - inBuf; - if (inputLen < todo) - todo = inputLen; - memcpy(B + inBuf, input, todo); - input += todo; - inputLen -= todo; - if (inBuf + todo == SHA512_BLOCK_LENGTH) - SHA512_Compress(ctx); - } - - /* if enough data to fill one or more whole buffers, process them. */ - while (inputLen >= SHA512_BLOCK_LENGTH) { - memcpy(B, input, SHA512_BLOCK_LENGTH); - input += SHA512_BLOCK_LENGTH; - inputLen -= SHA512_BLOCK_LENGTH; - SHA512_Compress(ctx); - } - /* if data left over, fill it into buffer */ - if (inputLen) - memcpy(B, input, inputLen); -} - -void -SHA512_End(SHA512Context *ctx, unsigned char *digest, - unsigned int *digestLen, unsigned int maxDigestLen) -{ -#if defined(HAVE_LONG_LONG) - unsigned int inBuf = (unsigned int)ctx->sizeLo & 0x7f; - unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf); - PRUint64 lo, t1; - lo = (ctx->sizeLo << 3); -#else - unsigned int inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f; - unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf); - PRUint64 lo = ctx->sizeLo; - PRUint32 t1; - lo.lo <<= 3; -#endif - - SHA512_Update(ctx, pad, padLen); - -#if defined(HAVE_LONG_LONG) - W[14] = 0; -#else - W[14].lo = 0; - W[14].hi = 0; -#endif - - W[15] = lo; -#if defined(IS_LITTLE_ENDIAN) - BYTESWAP8(W[15]); -#endif - SHA512_Compress(ctx); - - /* now output the answer */ -#if defined(IS_LITTLE_ENDIAN) - BYTESWAP8(H[0]); - BYTESWAP8(H[1]); - BYTESWAP8(H[2]); - BYTESWAP8(H[3]); - BYTESWAP8(H[4]); - BYTESWAP8(H[5]); - BYTESWAP8(H[6]); - BYTESWAP8(H[7]); -#endif - padLen = PR_MIN(SHA512_LENGTH, maxDigestLen); - memcpy(digest, H, padLen); - if (digestLen) - *digestLen = padLen; -} - -SECStatus -SHA512_HashBuf(unsigned char *dest, const unsigned char *src, - unsigned int src_length) -{ - SHA512Context ctx; - unsigned int outLen; - - SHA512_Begin(&ctx); - SHA512_Update(&ctx, src, src_length); - SHA512_End(&ctx, dest, &outLen, SHA512_LENGTH); - - return SECSuccess; -} - - -SECStatus -SHA512_Hash(unsigned char *dest, const char *src) -{ - return SHA512_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); -} - - -void SHA512_TraceState(SHA512Context *ctx) { } - -unsigned int -SHA512_FlattenSize(SHA512Context *ctx) -{ - return sizeof *ctx; -} - -SECStatus -SHA512_Flatten(SHA512Context *ctx,unsigned char *space) -{ - PORT_Memcpy(space, ctx, sizeof *ctx); - return SECSuccess; -} - -SHA512Context * -SHA512_Resurrect(unsigned char *space, void *arg) -{ - SHA512Context *ctx = SHA512_NewContext(); - if (ctx) - PORT_Memcpy(ctx, space, sizeof *ctx); - return ctx; -} - -void SHA512_Clone(SHA512Context *dest, SHA512Context *src) -{ - memcpy(dest, src, sizeof *dest); -} - -/* ======================================================================= */ -/* SHA384 uses a SHA512Context as the real context. -** The only differences between SHA384 an SHA512 are: -** a) the intialization values for the context, and -** b) the number of bytes of data produced as output. -*/ - -/* SHA-384 initial hash values */ -static const PRUint64 H384[8] = { -#if PR_BYTES_PER_LONG == 8 - 0xcbbb9d5dc1059ed8UL , 0x629a292a367cd507UL , - 0x9159015a3070dd17UL , 0x152fecd8f70e5939UL , - 0x67332667ffc00b31UL , 0x8eb44a8768581511UL , - 0xdb0c2e0d64f98fa7UL , 0x47b5481dbefa4fa4UL -#else - ULLC(cbbb9d5d,c1059ed8), ULLC(629a292a,367cd507), - ULLC(9159015a,3070dd17), ULLC(152fecd8,f70e5939), - ULLC(67332667,ffc00b31), ULLC(8eb44a87,68581511), - ULLC(db0c2e0d,64f98fa7), ULLC(47b5481d,befa4fa4) -#endif -}; - -SHA384Context * -SHA384_NewContext(void) -{ - return SHA512_NewContext(); -} - -void -SHA384_DestroyContext(SHA384Context *ctx, PRBool freeit) -{ - SHA512_DestroyContext(ctx, freeit); -} - -void -SHA384_Begin(SHA384Context *ctx) -{ - memset(ctx, 0, sizeof *ctx); - memcpy(H, H384, sizeof H384); -} - -void -SHA384_Update(SHA384Context *ctx, const unsigned char *input, - unsigned int inputLen) -{ - SHA512_Update(ctx, input, inputLen); -} - -void -SHA384_End(SHA384Context *ctx, unsigned char *digest, - unsigned int *digestLen, unsigned int maxDigestLen) -{ -#define SHA_MIN(a,b) (a < b ? a : b) - unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH); - SHA512_End(ctx, digest, digestLen, maxLen); -} - -SECStatus -SHA384_HashBuf(unsigned char *dest, const unsigned char *src, - unsigned int src_length) -{ - SHA512Context ctx; - unsigned int outLen; - - SHA384_Begin(&ctx); - SHA512_Update(&ctx, src, src_length); - SHA512_End(&ctx, dest, &outLen, SHA384_LENGTH); - - return SECSuccess; -} - -SECStatus -SHA384_Hash(unsigned char *dest, const char *src) -{ - return SHA384_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); -} - -void SHA384_TraceState(SHA384Context *ctx) { } - -unsigned int -SHA384_FlattenSize(SHA384Context *ctx) -{ - return sizeof(SHA384Context); -} - -SECStatus -SHA384_Flatten(SHA384Context *ctx,unsigned char *space) -{ - return SHA512_Flatten(ctx, space); -} - -SHA384Context * -SHA384_Resurrect(unsigned char *space, void *arg) -{ - return SHA512_Resurrect(space, arg); -} - -void SHA384_Clone(SHA384Context *dest, SHA384Context *src) -{ - memcpy(dest, src, sizeof *dest); -} -#endif /* Comment out unused code. */ - -/* ======================================================================= */ -#ifdef SELFTEST -#include <stdio.h> - -static const char abc[] = { "abc" }; -static const char abcdbc[] = { - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" -}; -static const char abcdef[] = { - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" -}; - -void -dumpHash32(const unsigned char *buf, unsigned int bufLen) -{ - unsigned int i; - for (i = 0; i < bufLen; i += 4) { - printf(" %02x%02x%02x%02x", buf[i], buf[i+1], buf[i+2], buf[i+3]); - } - printf("\n"); -} - -void test256(void) -{ - unsigned char outBuf[SHA256_LENGTH]; - - printf("SHA256, input = %s\n", abc); - SHA256_Hash(outBuf, abc); - dumpHash32(outBuf, sizeof outBuf); - - printf("SHA256, input = %s\n", abcdbc); - SHA256_Hash(outBuf, abcdbc); - dumpHash32(outBuf, sizeof outBuf); -} - -void -dumpHash64(const unsigned char *buf, unsigned int bufLen) -{ - unsigned int i; - for (i = 0; i < bufLen; i += 8) { - if (i % 32 == 0) - printf("\n"); - printf(" %02x%02x%02x%02x%02x%02x%02x%02x", - buf[i ], buf[i+1], buf[i+2], buf[i+3], - buf[i+4], buf[i+5], buf[i+6], buf[i+7]); - } - printf("\n"); -} - -void test512(void) -{ - unsigned char outBuf[SHA512_LENGTH]; - - printf("SHA512, input = %s\n", abc); - SHA512_Hash(outBuf, abc); - dumpHash64(outBuf, sizeof outBuf); - - printf("SHA512, input = %s\n", abcdef); - SHA512_Hash(outBuf, abcdef); - dumpHash64(outBuf, sizeof outBuf); -} - -void time512(void) -{ - unsigned char outBuf[SHA512_LENGTH]; - - SHA512_Hash(outBuf, abc); - SHA512_Hash(outBuf, abcdef); -} - -void test384(void) -{ - unsigned char outBuf[SHA384_LENGTH]; - - printf("SHA384, input = %s\n", abc); - SHA384_Hash(outBuf, abc); - dumpHash64(outBuf, sizeof outBuf); - - printf("SHA384, input = %s\n", abcdef); - SHA384_Hash(outBuf, abcdef); - dumpHash64(outBuf, sizeof outBuf); -} - -int main (int argc, char *argv[], char *envp[]) -{ - int i = 1; - if (argc > 1) { - i = atoi(argv[1]); - } - if (i < 2) { - test256(); - test512(); - test384(); - } else { - while (i-- > 0) { - time512(); - } - printf("done\n"); - } - return 0; -} - -#endif
diff --git a/src/crypto/wincrypt_shim.h b/src/crypto/wincrypt_shim.h new file mode 100644 index 0000000..d131431 --- /dev/null +++ b/src/crypto/wincrypt_shim.h
@@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_WINCRYPT_SHIM_H_ +#define CRYPTO_WINCRYPT_SHIM_H_ + +// wincrypt.h defines macros which conflict with OpenSSL's types. This header +// includes wincrypt and undefines the OpenSSL macros which conflict. Any +// Chromium headers which include wincrypt should instead include this header. + +#include <windows.h> +#include <wincrypt.h> + +#include "starboard/types.h" + +// Undefine the macros which conflict with OpenSSL and define replacements. See +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa378145(v=vs.85).aspx +#undef X509_CERT_PAIR +#undef X509_EXTENSIONS +#undef X509_NAME + +#define WINCRYPT_X509_CERT_PAIR ((LPCSTR) 53) +#define WINCRYPT_X509_EXTENSIONS ((LPCSTR) 5) +#define WINCRYPT_X509_NAME ((LPCSTR) 7) + +#endif // CRYPTO_WINCRYPT_SHIM_H_