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:
Kongqun Yang
2017-03-26 15:26:46 -07:00
parent 187d13a5c3
commit 84f66d2320
33 changed files with 620 additions and 310 deletions

View File

@@ -132,6 +132,7 @@ cc_library(
srcs = ["sha_util.cc"],
hdrs = ["sha_util.h"],
deps = [
"//base",
"//external:openssl",
],
)

View File

@@ -10,6 +10,7 @@
#include <vector>
#include <cstdint>
#include "glog/logging.h"
#include "openssl/aes.h"

View File

@@ -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.

View File

@@ -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

View File

@@ -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_

View File

@@ -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() {}

View File

@@ -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);

View File

@@ -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()));

View File

@@ -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