NewProvisioningSession expects pkcs8 private key and SHA race fix
------------- Fix SHA hashing to remove race condition. This change fixes the implementation by passing in the digest buffer. ------------- The input to ProvisioningEngine::NewProvisioningSession should be pkcs8 private key instead of pkcs1 private key ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=151273394 Change-Id: Ibcdff7757b2ac2878ee8b1b88365083964bfa10a
This commit is contained in:
@@ -132,6 +132,7 @@ cc_library(
|
||||
srcs = ["sha_util.cc"],
|
||||
hdrs = ["sha_util.h"],
|
||||
deps = [
|
||||
"//base",
|
||||
"//external:openssl",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <cstdint>
|
||||
#include "glog/logging.h"
|
||||
#include "openssl/aes.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
// License Agreement. For a copy of this agreement, please contact
|
||||
// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// RAII wrapper classes for cleaning up various OpenSSL dynamically allocated
|
||||
// structures.
|
||||
|
||||
#ifndef COMMON_OPENSSL_UTIL_H__
|
||||
#define COMMON_OPENSSL_UTIL_H__
|
||||
@@ -42,6 +44,7 @@ template <typename StackType>
|
||||
using ScopedOpenSSLStackOnly =
|
||||
std::unique_ptr<StackType, OpenSSLStackOnlyDeleter<StackType>>;
|
||||
|
||||
using ScopedBIGNUM = ScopedOpenSSLType<BIGNUM, BN_free>;
|
||||
using ScopedBIO = ScopedOpenSSLType<BIO, BIO_vfree>;
|
||||
using ScopedPKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
|
||||
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
|
||||
@@ -54,10 +57,14 @@ using ScopedX509NameEntry =
|
||||
using ScopedX509Store = ScopedOpenSSLType<X509_STORE, X509_STORE_free>;
|
||||
using ScopedX509StoreCtx =
|
||||
ScopedOpenSSLType<X509_STORE_CTX, X509_STORE_CTX_free>;
|
||||
using ScopedX509Req = ScopedOpenSSLType<X509_REQ, X509_REQ_free>;
|
||||
using ScopedAsn1UtcTime = ScopedOpenSSLType<ASN1_UTCTIME, ASN1_UTCTIME_free>;
|
||||
using ScopedAsn1Utc8String =
|
||||
ScopedOpenSSLType<ASN1_UTF8STRING, ASN1_UTF8STRING_free>;
|
||||
using ScopedAsn1Integer = ScopedOpenSSLType<ASN1_INTEGER, ASN1_INTEGER_free>;
|
||||
using ScopedAsn1Object = ScopedOpenSSLType<ASN1_OBJECT, ASN1_OBJECT_free>;
|
||||
using ScopedAsn1OctetString =
|
||||
ScopedOpenSSLType<ASN1_OCTET_STRING, ASN1_OCTET_STRING_free>;
|
||||
|
||||
// XxxStack deallocates the stack and its members while XxxStackOnly deallocates
|
||||
// the stack only.
|
||||
|
||||
@@ -19,4 +19,9 @@ bool RandomBytes(size_t num_bytes, std::string* output) {
|
||||
return RAND_bytes(reinterpret_cast<uint8_t*>(&(*output)[0]), num_bytes);
|
||||
}
|
||||
|
||||
std::string Random16Bytes() {
|
||||
std::string output;
|
||||
CHECK(RandomBytes(16u, &output));
|
||||
return output;
|
||||
}
|
||||
} // namespace widevine
|
||||
|
||||
@@ -14,9 +14,12 @@
|
||||
namespace widevine {
|
||||
|
||||
// Generates a random string.
|
||||
// Return true on success, false otherwise.
|
||||
// Returns true on success, false otherwise.
|
||||
bool RandomBytes(size_t num_bytes, std::string* output);
|
||||
|
||||
// Returns a 16-byte std::string suitable for use as an AES key
|
||||
std::string Random16Bytes();
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
#endif // COMMON_RANDOM_UTIL_H_
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace widevine {
|
||||
|
||||
RsaPrivateKey::RsaPrivateKey(RSA* key) : key_(CHECK_NOTNULL(key)) {}
|
||||
|
||||
RsaPrivateKey::RsaPrivateKey(const RsaPrivateKey& rsa_key)
|
||||
: key_(CHECK_NOTNULL(RSAPrivateKey_dup(rsa_key.key_))) {}
|
||||
|
||||
RsaPrivateKey::~RsaPrivateKey() { RSA_free(key_); }
|
||||
|
||||
RsaPrivateKey* RsaPrivateKey::Create(const std::string& serialized_key) {
|
||||
@@ -135,16 +138,12 @@ bool RsaPrivateKey::GenerateSignatureSha256Pkcs7(const std::string& message,
|
||||
}
|
||||
|
||||
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||
SHA256(reinterpret_cast<const unsigned char*>(message.data()),
|
||||
message.size(),
|
||||
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
|
||||
digest);
|
||||
unsigned int sig_len = RSA_size(key_);
|
||||
signature->resize(sig_len);
|
||||
return RSA_sign(NID_sha256,
|
||||
digest,
|
||||
sizeof(digest),
|
||||
reinterpret_cast<unsigned char*>(&(*signature)[0]),
|
||||
&sig_len,
|
||||
return RSA_sign(NID_sha256, digest, sizeof(digest),
|
||||
reinterpret_cast<unsigned char*>(&(*signature)[0]), &sig_len,
|
||||
key_) == 1;
|
||||
}
|
||||
|
||||
@@ -156,8 +155,13 @@ bool RsaPrivateKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
|
||||
return RsaKeyMatch(key(), public_key.key());
|
||||
}
|
||||
|
||||
uint32_t RsaPrivateKey::KeySize() const { return RSA_size(key_); }
|
||||
|
||||
RsaPublicKey::RsaPublicKey(RSA* key) : key_(CHECK_NOTNULL(key)) {}
|
||||
|
||||
RsaPublicKey::RsaPublicKey(const RsaPublicKey& rsa_key)
|
||||
: key_(CHECK_NOTNULL(RSAPublicKey_dup(rsa_key.key_))) {}
|
||||
|
||||
RsaPublicKey::~RsaPublicKey() { RSA_free(key_); }
|
||||
|
||||
RsaPublicKey* RsaPublicKey::Create(const std::string& serialized_key) {
|
||||
@@ -222,15 +226,20 @@ bool RsaPublicKey::VerifySignature(const std::string& message,
|
||||
std::string message_digest = Sha1_Hash(message);
|
||||
|
||||
// Verify PSS padding.
|
||||
return RSA_verify_PKCS1_PSS_mgf1(
|
||||
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
|
||||
EVP_sha1(), EVP_sha1(),
|
||||
reinterpret_cast<unsigned char*>(&padded_digest[0]),
|
||||
kPssSaltLength) != 0;
|
||||
if (RSA_verify_PKCS1_PSS_mgf1(
|
||||
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
|
||||
EVP_sha1(), EVP_sha1(),
|
||||
reinterpret_cast<unsigned char*>(&padded_digest[0]),
|
||||
kPssSaltLength) == 0) {
|
||||
LOG(ERROR) << "RSA Verify PSS padding failure: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RsaPublicKey::VerifySignatureSha256Pkcs7(
|
||||
const std::string& message, const std::string& signature) const {
|
||||
bool RsaPublicKey::VerifySignatureSha256Pkcs7(const std::string& message,
|
||||
const std::string& signature) const {
|
||||
if (message.empty()) {
|
||||
LOG(ERROR) << "Empty signature verification message";
|
||||
return false;
|
||||
@@ -245,15 +254,11 @@ bool RsaPublicKey::VerifySignatureSha256Pkcs7(
|
||||
return false;
|
||||
}
|
||||
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||
SHA256(reinterpret_cast<const unsigned char*>(message.data()),
|
||||
message.size(),
|
||||
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
|
||||
digest);
|
||||
return RSA_verify(NID_sha256,
|
||||
digest,
|
||||
sizeof(digest),
|
||||
return RSA_verify(NID_sha256, digest, sizeof(digest),
|
||||
reinterpret_cast<const unsigned char*>(signature.data()),
|
||||
signature.size(),
|
||||
key_) == 1;
|
||||
signature.size(), key_) == 1;
|
||||
}
|
||||
|
||||
bool RsaPublicKey::MatchesPrivateKey(const RsaPrivateKey& private_key) const {
|
||||
@@ -264,6 +269,8 @@ bool RsaPublicKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
|
||||
return RsaKeyMatch(key(), public_key.key());
|
||||
}
|
||||
|
||||
uint32_t RsaPublicKey::KeySize() const { return RSA_size(key_); }
|
||||
|
||||
RsaKeyFactory::RsaKeyFactory() {}
|
||||
|
||||
RsaKeyFactory::~RsaKeyFactory() {}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <cstdint>
|
||||
#include "base/macros.h"
|
||||
#include "openssl/rsa.h"
|
||||
|
||||
@@ -27,6 +28,7 @@ class RsaPublicKey;
|
||||
class RsaPrivateKey {
|
||||
public:
|
||||
explicit RsaPrivateKey(RSA* key);
|
||||
RsaPrivateKey(const RsaPrivateKey&);
|
||||
virtual ~RsaPrivateKey();
|
||||
|
||||
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
|
||||
@@ -55,17 +57,26 @@ class RsaPrivateKey {
|
||||
// |public_key|.
|
||||
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
|
||||
|
||||
// Returns the RSA key size (modulus) in bytes.
|
||||
virtual uint32_t KeySize() const;
|
||||
|
||||
const RSA* key() const { return key_; }
|
||||
|
||||
private:
|
||||
RSA* key_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RsaPrivateKey);
|
||||
// SWIG appears to think this declaration is a syntax error. Excluding it for
|
||||
// python SWIG wrapping.
|
||||
#ifndef SWIG
|
||||
// Disallow assignment operator.
|
||||
RsaPrivateKey& operator=(const RsaPrivateKey&) = delete;
|
||||
#endif // SWIG
|
||||
};
|
||||
|
||||
class RsaPublicKey {
|
||||
public:
|
||||
explicit RsaPublicKey(RSA* key);
|
||||
RsaPublicKey(const RsaPublicKey&);
|
||||
virtual ~RsaPublicKey();
|
||||
|
||||
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
|
||||
@@ -97,12 +108,20 @@ class RsaPublicKey {
|
||||
// Return true if the underlying key matches with |public_key|.
|
||||
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
|
||||
|
||||
// Returns the RSA key size (modulus) in bytes.
|
||||
virtual uint32_t KeySize() const;
|
||||
|
||||
const RSA* key() const { return key_; }
|
||||
|
||||
private:
|
||||
RSA* key_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RsaPublicKey);
|
||||
// SWIG appears to think this declaration is a syntax error. Excluding it for
|
||||
// python SWIG wrapping.
|
||||
#ifndef SWIG
|
||||
// Disallow assignment operator.
|
||||
RsaPublicKey& operator=(const RsaPublicKey&) = delete;
|
||||
#endif // SWIG
|
||||
};
|
||||
|
||||
class RsaKeyFactory {
|
||||
@@ -114,7 +133,8 @@ class RsaKeyFactory {
|
||||
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs1PrivateKey(
|
||||
const std::string& private_key);
|
||||
|
||||
// Create an RsaPrivateKey object using an encrypted PKCS#8 RSAPrivateKey.
|
||||
// Create a PKCS#1 RsaPrivateKey object using an PKCS#8 PrivateKeyInfo or
|
||||
// EncryptedPrivateKeyInfo (if |private_key_passprhase| is not empty).
|
||||
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs8PrivateKey(
|
||||
const std::string& private_key, const std::string& private_key_passphrase);
|
||||
|
||||
|
||||
@@ -38,6 +38,24 @@ class RsaKeyTest : public ::testing::Test {
|
||||
RsaKeyFactory factory_;
|
||||
};
|
||||
|
||||
TEST_F(RsaKeyTest, CopyConstructor) {
|
||||
std::unique_ptr<RsaPrivateKey> private_key(
|
||||
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
|
||||
std::unique_ptr<RsaPublicKey> public_key(
|
||||
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
|
||||
|
||||
std::unique_ptr<RsaPrivateKey> private_key_copy(
|
||||
new RsaPrivateKey(*private_key));
|
||||
std::unique_ptr<RsaPublicKey> public_key_copy(
|
||||
new RsaPublicKey(*public_key));
|
||||
|
||||
EXPECT_TRUE(public_key_copy->MatchesPublicKey(*public_key));
|
||||
EXPECT_TRUE(public_key_copy->MatchesPrivateKey(*private_key));
|
||||
|
||||
EXPECT_TRUE(private_key_copy->MatchesPublicKey(*public_key));
|
||||
EXPECT_TRUE(private_key_copy->MatchesPrivateKey(*private_key));
|
||||
}
|
||||
|
||||
void RsaKeyTest::TestEncryption(std::unique_ptr<RsaPrivateKey> private_key,
|
||||
std::unique_ptr<RsaPublicKey> public_key) {
|
||||
ASSERT_TRUE(private_key);
|
||||
@@ -203,6 +221,16 @@ TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_2048) {
|
||||
factory_.CreateFromPkcs1PublicKey(public_key));
|
||||
}
|
||||
|
||||
TEST_F(RsaKeyTest, KeySize) {
|
||||
std::unique_ptr<RsaPrivateKey> private_key(
|
||||
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
|
||||
std::unique_ptr<RsaPublicKey> public_key(
|
||||
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
|
||||
|
||||
EXPECT_EQ(256, private_key->KeySize());
|
||||
EXPECT_EQ(256, public_key->KeySize());
|
||||
}
|
||||
|
||||
TEST_F(RsaKeyTest, RsaKeyMatch) {
|
||||
std::unique_ptr<RsaPrivateKey> private_key2(
|
||||
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
|
||||
|
||||
@@ -8,22 +8,25 @@
|
||||
|
||||
#include "common/sha_util.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include "openssl/sha.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
std::string Sha1_Hash(const std::string& message) {
|
||||
return std::string(reinterpret_cast<char*>(
|
||||
SHA1(reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), nullptr)),
|
||||
SHA_DIGEST_LENGTH);
|
||||
std::string digest;
|
||||
digest.resize(SHA_DIGEST_LENGTH);
|
||||
SHA1(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
|
||||
reinterpret_cast<uint8_t*>(&digest[0]));
|
||||
return digest;
|
||||
}
|
||||
|
||||
std::string Sha256_Hash(const std::string& message) {
|
||||
return std::string(reinterpret_cast<char*>(
|
||||
SHA256(reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), nullptr)),
|
||||
SHA256_DIGEST_LENGTH);
|
||||
std::string digest;
|
||||
digest.resize(SHA256_DIGEST_LENGTH);
|
||||
SHA256(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
|
||||
reinterpret_cast<uint8_t*>(&digest[0]));
|
||||
return digest;
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
Reference in New Issue
Block a user