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:
@@ -3,7 +3,7 @@ workspace(name = "provisioning_sdk")
|
|||||||
git_repository(
|
git_repository(
|
||||||
name = "protobuf_repo",
|
name = "protobuf_repo",
|
||||||
remote = "https://github.com/google/protobuf.git",
|
remote = "https://github.com/google/protobuf.git",
|
||||||
tag = "v3.0.0",
|
tag = "v3.2.0",
|
||||||
)
|
)
|
||||||
|
|
||||||
git_repository(
|
git_repository(
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ cc_library(
|
|||||||
srcs = ["sha_util.cc"],
|
srcs = ["sha_util.cc"],
|
||||||
hdrs = ["sha_util.h"],
|
hdrs = ["sha_util.h"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//base",
|
||||||
"//external:openssl",
|
"//external:openssl",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
#include "openssl/aes.h"
|
#include "openssl/aes.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
// License Agreement. For a copy of this agreement, please contact
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
// widevine-licensing@google.com.
|
// widevine-licensing@google.com.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// RAII wrapper classes for cleaning up various OpenSSL dynamically allocated
|
||||||
|
// structures.
|
||||||
|
|
||||||
#ifndef COMMON_OPENSSL_UTIL_H__
|
#ifndef COMMON_OPENSSL_UTIL_H__
|
||||||
#define COMMON_OPENSSL_UTIL_H__
|
#define COMMON_OPENSSL_UTIL_H__
|
||||||
@@ -42,6 +44,7 @@ template <typename StackType>
|
|||||||
using ScopedOpenSSLStackOnly =
|
using ScopedOpenSSLStackOnly =
|
||||||
std::unique_ptr<StackType, OpenSSLStackOnlyDeleter<StackType>>;
|
std::unique_ptr<StackType, OpenSSLStackOnlyDeleter<StackType>>;
|
||||||
|
|
||||||
|
using ScopedBIGNUM = ScopedOpenSSLType<BIGNUM, BN_free>;
|
||||||
using ScopedBIO = ScopedOpenSSLType<BIO, BIO_vfree>;
|
using ScopedBIO = ScopedOpenSSLType<BIO, BIO_vfree>;
|
||||||
using ScopedPKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
|
using ScopedPKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
|
||||||
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
|
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
|
||||||
@@ -54,10 +57,14 @@ using ScopedX509NameEntry =
|
|||||||
using ScopedX509Store = ScopedOpenSSLType<X509_STORE, X509_STORE_free>;
|
using ScopedX509Store = ScopedOpenSSLType<X509_STORE, X509_STORE_free>;
|
||||||
using ScopedX509StoreCtx =
|
using ScopedX509StoreCtx =
|
||||||
ScopedOpenSSLType<X509_STORE_CTX, X509_STORE_CTX_free>;
|
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 ScopedAsn1UtcTime = ScopedOpenSSLType<ASN1_UTCTIME, ASN1_UTCTIME_free>;
|
||||||
using ScopedAsn1Utc8String =
|
using ScopedAsn1Utc8String =
|
||||||
ScopedOpenSSLType<ASN1_UTF8STRING, ASN1_UTF8STRING_free>;
|
ScopedOpenSSLType<ASN1_UTF8STRING, ASN1_UTF8STRING_free>;
|
||||||
using ScopedAsn1Integer = ScopedOpenSSLType<ASN1_INTEGER, ASN1_INTEGER_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
|
// XxxStack deallocates the stack and its members while XxxStackOnly deallocates
|
||||||
// the stack only.
|
// 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);
|
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
|
} // namespace widevine
|
||||||
|
|||||||
@@ -14,9 +14,12 @@
|
|||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
// Generates a random string.
|
// 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);
|
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
|
} // namespace widevine
|
||||||
|
|
||||||
#endif // COMMON_RANDOM_UTIL_H_
|
#endif // COMMON_RANDOM_UTIL_H_
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ namespace widevine {
|
|||||||
|
|
||||||
RsaPrivateKey::RsaPrivateKey(RSA* key) : key_(CHECK_NOTNULL(key)) {}
|
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() { RSA_free(key_); }
|
||||||
|
|
||||||
RsaPrivateKey* RsaPrivateKey::Create(const std::string& serialized_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];
|
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||||
SHA256(reinterpret_cast<const unsigned char*>(message.data()),
|
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
|
||||||
message.size(),
|
|
||||||
digest);
|
digest);
|
||||||
unsigned int sig_len = RSA_size(key_);
|
unsigned int sig_len = RSA_size(key_);
|
||||||
signature->resize(sig_len);
|
signature->resize(sig_len);
|
||||||
return RSA_sign(NID_sha256,
|
return RSA_sign(NID_sha256, digest, sizeof(digest),
|
||||||
digest,
|
reinterpret_cast<unsigned char*>(&(*signature)[0]), &sig_len,
|
||||||
sizeof(digest),
|
|
||||||
reinterpret_cast<unsigned char*>(&(*signature)[0]),
|
|
||||||
&sig_len,
|
|
||||||
key_) == 1;
|
key_) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,8 +155,13 @@ bool RsaPrivateKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
|
|||||||
return RsaKeyMatch(key(), public_key.key());
|
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(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() { RSA_free(key_); }
|
||||||
|
|
||||||
RsaPublicKey* RsaPublicKey::Create(const std::string& serialized_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);
|
std::string message_digest = Sha1_Hash(message);
|
||||||
|
|
||||||
// Verify PSS padding.
|
// Verify PSS padding.
|
||||||
return RSA_verify_PKCS1_PSS_mgf1(
|
if (RSA_verify_PKCS1_PSS_mgf1(
|
||||||
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
|
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
|
||||||
EVP_sha1(), EVP_sha1(),
|
EVP_sha1(), EVP_sha1(),
|
||||||
reinterpret_cast<unsigned char*>(&padded_digest[0]),
|
reinterpret_cast<unsigned char*>(&padded_digest[0]),
|
||||||
kPssSaltLength) != 0;
|
kPssSaltLength) == 0) {
|
||||||
|
LOG(ERROR) << "RSA Verify PSS padding failure: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RsaPublicKey::VerifySignatureSha256Pkcs7(
|
bool RsaPublicKey::VerifySignatureSha256Pkcs7(const std::string& message,
|
||||||
const std::string& message, const std::string& signature) const {
|
const std::string& signature) const {
|
||||||
if (message.empty()) {
|
if (message.empty()) {
|
||||||
LOG(ERROR) << "Empty signature verification message";
|
LOG(ERROR) << "Empty signature verification message";
|
||||||
return false;
|
return false;
|
||||||
@@ -245,15 +254,11 @@ bool RsaPublicKey::VerifySignatureSha256Pkcs7(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
unsigned char digest[SHA256_DIGEST_LENGTH];
|
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||||
SHA256(reinterpret_cast<const unsigned char*>(message.data()),
|
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
|
||||||
message.size(),
|
|
||||||
digest);
|
digest);
|
||||||
return RSA_verify(NID_sha256,
|
return RSA_verify(NID_sha256, digest, sizeof(digest),
|
||||||
digest,
|
|
||||||
sizeof(digest),
|
|
||||||
reinterpret_cast<const unsigned char*>(signature.data()),
|
reinterpret_cast<const unsigned char*>(signature.data()),
|
||||||
signature.size(),
|
signature.size(), key_) == 1;
|
||||||
key_) == 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RsaPublicKey::MatchesPrivateKey(const RsaPrivateKey& private_key) const {
|
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());
|
return RsaKeyMatch(key(), public_key.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t RsaPublicKey::KeySize() const { return RSA_size(key_); }
|
||||||
|
|
||||||
RsaKeyFactory::RsaKeyFactory() {}
|
RsaKeyFactory::RsaKeyFactory() {}
|
||||||
|
|
||||||
RsaKeyFactory::~RsaKeyFactory() {}
|
RsaKeyFactory::~RsaKeyFactory() {}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "openssl/rsa.h"
|
#include "openssl/rsa.h"
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ class RsaPublicKey;
|
|||||||
class RsaPrivateKey {
|
class RsaPrivateKey {
|
||||||
public:
|
public:
|
||||||
explicit RsaPrivateKey(RSA* key);
|
explicit RsaPrivateKey(RSA* key);
|
||||||
|
RsaPrivateKey(const RsaPrivateKey&);
|
||||||
virtual ~RsaPrivateKey();
|
virtual ~RsaPrivateKey();
|
||||||
|
|
||||||
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
|
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
|
||||||
@@ -55,17 +57,26 @@ class RsaPrivateKey {
|
|||||||
// |public_key|.
|
// |public_key|.
|
||||||
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
|
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_; }
|
const RSA* key() const { return key_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RSA* key_;
|
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 {
|
class RsaPublicKey {
|
||||||
public:
|
public:
|
||||||
explicit RsaPublicKey(RSA* key);
|
explicit RsaPublicKey(RSA* key);
|
||||||
|
RsaPublicKey(const RsaPublicKey&);
|
||||||
virtual ~RsaPublicKey();
|
virtual ~RsaPublicKey();
|
||||||
|
|
||||||
// Create an RsaPublicKey object using a DER encoded PKCS#1 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|.
|
// Return true if the underlying key matches with |public_key|.
|
||||||
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
|
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_; }
|
const RSA* key() const { return key_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RSA* key_;
|
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 {
|
class RsaKeyFactory {
|
||||||
@@ -114,7 +133,8 @@ class RsaKeyFactory {
|
|||||||
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs1PrivateKey(
|
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs1PrivateKey(
|
||||||
const std::string& private_key);
|
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(
|
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs8PrivateKey(
|
||||||
const std::string& private_key, const std::string& private_key_passphrase);
|
const std::string& private_key, const std::string& private_key_passphrase);
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,24 @@ class RsaKeyTest : public ::testing::Test {
|
|||||||
RsaKeyFactory factory_;
|
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,
|
void RsaKeyTest::TestEncryption(std::unique_ptr<RsaPrivateKey> private_key,
|
||||||
std::unique_ptr<RsaPublicKey> public_key) {
|
std::unique_ptr<RsaPublicKey> public_key) {
|
||||||
ASSERT_TRUE(private_key);
|
ASSERT_TRUE(private_key);
|
||||||
@@ -203,6 +221,16 @@ TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_2048) {
|
|||||||
factory_.CreateFromPkcs1PublicKey(public_key));
|
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) {
|
TEST_F(RsaKeyTest, RsaKeyMatch) {
|
||||||
std::unique_ptr<RsaPrivateKey> private_key2(
|
std::unique_ptr<RsaPrivateKey> private_key2(
|
||||||
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
|
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
|
||||||
|
|||||||
@@ -8,22 +8,25 @@
|
|||||||
|
|
||||||
#include "common/sha_util.h"
|
#include "common/sha_util.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include "openssl/sha.h"
|
#include "openssl/sha.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
std::string Sha1_Hash(const std::string& message) {
|
std::string Sha1_Hash(const std::string& message) {
|
||||||
return std::string(reinterpret_cast<char*>(
|
std::string digest;
|
||||||
SHA1(reinterpret_cast<const uint8_t*>(message.data()),
|
digest.resize(SHA_DIGEST_LENGTH);
|
||||||
message.size(), nullptr)),
|
SHA1(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
|
||||||
SHA_DIGEST_LENGTH);
|
reinterpret_cast<uint8_t*>(&digest[0]));
|
||||||
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Sha256_Hash(const std::string& message) {
|
std::string Sha256_Hash(const std::string& message) {
|
||||||
return std::string(reinterpret_cast<char*>(
|
std::string digest;
|
||||||
SHA256(reinterpret_cast<const uint8_t*>(message.data()),
|
digest.resize(SHA256_DIGEST_LENGTH);
|
||||||
message.size(), nullptr)),
|
SHA256(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
|
||||||
SHA256_DIGEST_LENGTH);
|
reinterpret_cast<uint8_t*>(&digest[0]));
|
||||||
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
Binary file not shown.
@@ -15,10 +15,19 @@ py_binary(
|
|||||||
srcs = ["oem_certificate.py"],
|
srcs = ["oem_certificate.py"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
py_library(
|
||||||
|
name = "oem_certificate_generator_helper",
|
||||||
|
srcs = ["oem_certificate_generator_helper.py"],
|
||||||
|
deps = [
|
||||||
|
":oem_certificate",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
py_test(
|
py_test(
|
||||||
name = "oem_certificate_test",
|
name = "oem_certificate_test",
|
||||||
srcs = ["oem_certificate_test.py"],
|
srcs = ["oem_certificate_test.py"],
|
||||||
deps = [
|
deps = [
|
||||||
":oem_certificate",
|
":oem_certificate",
|
||||||
|
":oem_certificate_generator_helper",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -196,8 +196,8 @@ def _random_serial_number():
|
|||||||
return utils.int_from_bytes(os.urandom(16), byteorder='big')
|
return utils.int_from_bytes(os.urandom(16), byteorder='big')
|
||||||
|
|
||||||
|
|
||||||
def _build_certificate(subject_name, issuer_name, system_id, not_valid_before,
|
def build_certificate(subject_name, issuer_name, system_id, not_valid_before,
|
||||||
valid_duration, public_key, signing_key, ca):
|
valid_duration, public_key, signing_key, ca):
|
||||||
"""Utility function to build certificate."""
|
"""Utility function to build certificate."""
|
||||||
builder = x509.CertificateBuilder()
|
builder = x509.CertificateBuilder()
|
||||||
builder = builder.subject_name(subject_name).issuer_name(issuer_name)
|
builder = builder.subject_name(subject_name).issuer_name(issuer_name)
|
||||||
@@ -237,10 +237,10 @@ def generate_intermediate_certificate(args):
|
|||||||
raise ValueError('Root certificate does not match with root private key')
|
raise ValueError('Root certificate does not match with root private key')
|
||||||
csr = x509.load_pem_x509_csr(args.csr_file.read(), backends.default_backend())
|
csr = x509.load_pem_x509_csr(args.csr_file.read(), backends.default_backend())
|
||||||
|
|
||||||
certificate = _build_certificate(csr.subject, root_cert.subject,
|
certificate = build_certificate(csr.subject, root_cert.subject,
|
||||||
args.system_id, args.not_valid_before,
|
args.system_id, args.not_valid_before,
|
||||||
args.valid_duration,
|
args.valid_duration,
|
||||||
csr.public_key(), root_private_key, True)
|
csr.public_key(), root_private_key, True)
|
||||||
args.output_certificate_file.write(
|
args.output_certificate_file.write(
|
||||||
certificate.public_bytes(serialization.Encoding.DER))
|
certificate.public_bytes(serialization.Encoding.DER))
|
||||||
|
|
||||||
@@ -282,11 +282,11 @@ def generate_leaf_certificate(args):
|
|||||||
format=serialization.PrivateFormat.PKCS8,
|
format=serialization.PrivateFormat.PKCS8,
|
||||||
encryption_algorithm=_get_encryption_algorithm(args.passphrase)))
|
encryption_algorithm=_get_encryption_algorithm(args.passphrase)))
|
||||||
|
|
||||||
certificate = _build_certificate(subject_name, intermediate_cert.subject,
|
certificate = build_certificate(subject_name, intermediate_cert.subject,
|
||||||
system_id, args.not_valid_before,
|
system_id, args.not_valid_before,
|
||||||
args.valid_duration,
|
args.valid_duration,
|
||||||
leaf_private_key.public_key(),
|
leaf_private_key.public_key(),
|
||||||
intermediate_private_key, False)
|
intermediate_private_key, False)
|
||||||
args.output_certificate_file.write(
|
args.output_certificate_file.write(
|
||||||
X509CertificateChain([certificate, intermediate_cert]).der_bytes())
|
X509CertificateChain([certificate, intermediate_cert]).der_bytes())
|
||||||
|
|
||||||
|
|||||||
154
oem_certificate_generator/oem_certificate_generator_helper.py
Normal file
154
oem_certificate_generator/oem_certificate_generator_helper.py
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
################################################################################
|
||||||
|
# Copyright 2017 Google Inc.
|
||||||
|
#
|
||||||
|
# This software is licensed under the terms defined in the Widevine Master
|
||||||
|
# License Agreement. For a copy of this agreement, please contact
|
||||||
|
# widevine-licensing@google.com.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""Common utility functions for OEM certificate generation."""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import StringIO
|
||||||
|
|
||||||
|
from cryptography import x509
|
||||||
|
from cryptography.hazmat import backends
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
|
from cryptography.x509 import oid
|
||||||
|
|
||||||
|
import oem_certificate
|
||||||
|
|
||||||
|
_COUNTRY_NAME = 'US'
|
||||||
|
_STATE_OR_PROVINCE_NAME = 'WA'
|
||||||
|
_LOCALITY_NAME = 'Kirkland'
|
||||||
|
_ORGANIZATION_NAME = 'CompanyXYZ'
|
||||||
|
_ORGANIZATIONAL_UNIT_NAME = 'ContentProtection'
|
||||||
|
|
||||||
|
|
||||||
|
_NOT_VALID_BEFORE = datetime.datetime(2001, 8, 9)
|
||||||
|
_VALID_DURATION = 100
|
||||||
|
_LEAF_CERT_VALID_DURATION = 8000
|
||||||
|
_SYSTEM_ID = 2001
|
||||||
|
_ROOT_PRIVATE_KEY_PASSPHRASE = 'root_passphrase'
|
||||||
|
|
||||||
|
|
||||||
|
class ArgParseObject(object):
|
||||||
|
"""A convenient object to allow adding arbitrary attribute to it."""
|
||||||
|
|
||||||
|
|
||||||
|
def create_root_certificate_and_key():
|
||||||
|
"""Creates a root certificate and key."""
|
||||||
|
key = rsa.generate_private_key(
|
||||||
|
public_exponent=65537,
|
||||||
|
key_size=3072,
|
||||||
|
backend=backends.default_backend())
|
||||||
|
subject_name = x509.Name(
|
||||||
|
[x509.NameAttribute(oid.NameOID.COMMON_NAME, u'root_cert')])
|
||||||
|
certificate = oem_certificate.build_certificate(
|
||||||
|
subject_name, subject_name, None,
|
||||||
|
datetime.datetime(2001, 8, 9), 1000, key.public_key(), key, True)
|
||||||
|
return (key, certificate)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_csr_rgs(country_name=_COUNTRY_NAME,
|
||||||
|
state_or_province_name=_STATE_OR_PROVINCE_NAME,
|
||||||
|
locality_name=_LOCALITY_NAME,
|
||||||
|
organization_name=_ORGANIZATION_NAME,
|
||||||
|
organizational_unit_name=_ORGANIZATIONAL_UNIT_NAME,
|
||||||
|
key_size=4096,
|
||||||
|
output_csr_file=None,
|
||||||
|
output_private_key_file=None,
|
||||||
|
passphrase=None):
|
||||||
|
"""Sets up arguments to OEM Certificate generator for generating csr."""
|
||||||
|
args = ArgParseObject()
|
||||||
|
args.key_size = key_size
|
||||||
|
args.country_name = country_name
|
||||||
|
args.state_or_province_name = state_or_province_name
|
||||||
|
args.locality_name = locality_name
|
||||||
|
args.organization_name = organization_name
|
||||||
|
args.organizational_unit_name = organizational_unit_name
|
||||||
|
if output_csr_file:
|
||||||
|
args.output_csr_file = output_csr_file
|
||||||
|
else:
|
||||||
|
args.output_csr_file = StringIO.StringIO()
|
||||||
|
if output_private_key_file:
|
||||||
|
args.output_private_key_file = output_private_key_file
|
||||||
|
else:
|
||||||
|
args.output_private_key_file = StringIO.StringIO()
|
||||||
|
args.passphrase = passphrase
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def setup_intermediate_cert_args(
|
||||||
|
csr_bytes, root_key, root_certificate, not_valid_before=_NOT_VALID_BEFORE,
|
||||||
|
valid_duration=_VALID_DURATION, system_id=_SYSTEM_ID,
|
||||||
|
root_private_key_passphrase=_ROOT_PRIVATE_KEY_PASSPHRASE,
|
||||||
|
output_certificate_file=None):
|
||||||
|
"""Sets up args to OEM Cert generator for generating intermediate cert."""
|
||||||
|
args = ArgParseObject()
|
||||||
|
args.not_valid_before = not_valid_before
|
||||||
|
args.valid_duration = valid_duration
|
||||||
|
args.system_id = system_id
|
||||||
|
args.csr_file = StringIO.StringIO(csr_bytes)
|
||||||
|
args.root_private_key_passphrase = root_private_key_passphrase
|
||||||
|
if output_certificate_file:
|
||||||
|
args.output_certificate_file = output_certificate_file
|
||||||
|
else:
|
||||||
|
args.output_certificate_file = StringIO.StringIO()
|
||||||
|
|
||||||
|
serialized_private_key = root_key.private_bytes(
|
||||||
|
serialization.Encoding.DER,
|
||||||
|
format=serialization.PrivateFormat.PKCS8,
|
||||||
|
encryption_algorithm=serialization.BestAvailableEncryption(
|
||||||
|
args.root_private_key_passphrase))
|
||||||
|
serialized_certificate = root_certificate.public_bytes(
|
||||||
|
serialization.Encoding.DER)
|
||||||
|
args.root_certificate_file = StringIO.StringIO(serialized_certificate)
|
||||||
|
args.root_private_key_file = StringIO.StringIO(serialized_private_key)
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def setup_leaf_cert_args(intermediate_key_bytes,
|
||||||
|
intermediate_certificate_bytes,
|
||||||
|
key_size=1024,
|
||||||
|
passphrase=None,
|
||||||
|
not_valid_before=_NOT_VALID_BEFORE,
|
||||||
|
valid_duration=_LEAF_CERT_VALID_DURATION,
|
||||||
|
output_certificate_file=None,
|
||||||
|
output_private_key_file=None):
|
||||||
|
"""Sets up args to OEM Certificate generator for generating leaf cert."""
|
||||||
|
args = ArgParseObject()
|
||||||
|
args.key_size = key_size
|
||||||
|
args.not_valid_before = not_valid_before
|
||||||
|
args.valid_duration = valid_duration
|
||||||
|
args.intermediate_private_key_passphrase = None
|
||||||
|
if output_certificate_file:
|
||||||
|
args.output_certificate_file = output_certificate_file
|
||||||
|
else:
|
||||||
|
args.output_certificate_file = StringIO.StringIO()
|
||||||
|
if output_private_key_file:
|
||||||
|
args.output_private_key_file = output_private_key_file
|
||||||
|
else:
|
||||||
|
args.output_private_key_file = StringIO.StringIO()
|
||||||
|
args.passphrase = passphrase
|
||||||
|
|
||||||
|
args.intermediate_private_key_file = StringIO.StringIO(
|
||||||
|
intermediate_key_bytes)
|
||||||
|
args.intermediate_certificate_file = StringIO.StringIO(
|
||||||
|
intermediate_certificate_bytes)
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def create_intermediate_certificate_and_key_bytes(key_size=4096,
|
||||||
|
passphrase=None):
|
||||||
|
"""Creates an intermediate certificate and key."""
|
||||||
|
csr_args = setup_csr_rgs(key_size=key_size, passphrase=passphrase)
|
||||||
|
oem_certificate.generate_csr(csr_args)
|
||||||
|
csr_bytes = csr_args.output_csr_file.getvalue()
|
||||||
|
|
||||||
|
root_key, root_certificate = create_root_certificate_and_key()
|
||||||
|
args = setup_intermediate_cert_args(csr_bytes, root_key, root_certificate)
|
||||||
|
oem_certificate.generate_intermediate_certificate(args)
|
||||||
|
return (csr_args.output_private_key_file.getvalue(),
|
||||||
|
args.output_certificate_file.getvalue())
|
||||||
@@ -18,10 +18,10 @@ from cryptography import x509
|
|||||||
from cryptography.hazmat import backends
|
from cryptography.hazmat import backends
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric import padding
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
||||||
from cryptography.x509 import oid
|
from cryptography.x509 import oid
|
||||||
|
|
||||||
import oem_certificate
|
import oem_certificate
|
||||||
|
import oem_certificate_generator_helper as oem_cert_gen_helper
|
||||||
|
|
||||||
|
|
||||||
class ArgParseObject(object):
|
class ArgParseObject(object):
|
||||||
@@ -31,19 +31,6 @@ class ArgParseObject(object):
|
|||||||
|
|
||||||
class OemCertificateTest(unittest.TestCase):
|
class OemCertificateTest(unittest.TestCase):
|
||||||
|
|
||||||
def _setup_csr_args(self, key_size=4096, passphrase=None):
|
|
||||||
args = ArgParseObject()
|
|
||||||
args.key_size = key_size
|
|
||||||
args.country_name = 'US'
|
|
||||||
args.state_or_province_name = 'WA'
|
|
||||||
args.locality_name = 'Kirkland'
|
|
||||||
args.organization_name = 'CompanyXYZ'
|
|
||||||
args.organizational_unit_name = 'ContentProtection'
|
|
||||||
args.output_csr_file = StringIO.StringIO()
|
|
||||||
args.output_private_key_file = StringIO.StringIO()
|
|
||||||
args.passphrase = passphrase
|
|
||||||
return args
|
|
||||||
|
|
||||||
def test_widevine_system_id(self):
|
def test_widevine_system_id(self):
|
||||||
system_id = 1234567890123
|
system_id = 1234567890123
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -51,7 +38,7 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
system_id)
|
system_id)
|
||||||
|
|
||||||
def test_generate_csr(self):
|
def test_generate_csr(self):
|
||||||
args = self._setup_csr_args()
|
args = oem_cert_gen_helper.setup_csr_rgs()
|
||||||
oem_certificate.generate_csr(args)
|
oem_certificate.generate_csr(args)
|
||||||
# Verify CSR.
|
# Verify CSR.
|
||||||
csr = x509.load_pem_x509_csr(args.output_csr_file.getvalue(),
|
csr = x509.load_pem_x509_csr(args.output_csr_file.getvalue(),
|
||||||
@@ -84,7 +71,8 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
private_key.public_key().public_numbers())
|
private_key.public_key().public_numbers())
|
||||||
|
|
||||||
def test_generate_csr_with_keysize4096_and_passphrase(self):
|
def test_generate_csr_with_keysize4096_and_passphrase(self):
|
||||||
args = self._setup_csr_args(key_size=4096, passphrase='passphrase_4096')
|
args = oem_cert_gen_helper.setup_csr_rgs(
|
||||||
|
key_size=4096, passphrase='passphrase_4096')
|
||||||
oem_certificate.generate_csr(args)
|
oem_certificate.generate_csr(args)
|
||||||
private_key = serialization.load_der_private_key(
|
private_key = serialization.load_der_private_key(
|
||||||
args.output_private_key_file.getvalue(),
|
args.output_private_key_file.getvalue(),
|
||||||
@@ -98,49 +86,16 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
self.assertEqual(csr.public_key().public_numbers(),
|
self.assertEqual(csr.public_key().public_numbers(),
|
||||||
private_key.public_key().public_numbers())
|
private_key.public_key().public_numbers())
|
||||||
|
|
||||||
def _create_root_certificate_and_key(self):
|
|
||||||
key = rsa.generate_private_key(
|
|
||||||
public_exponent=65537,
|
|
||||||
key_size=3072,
|
|
||||||
backend=backends.default_backend())
|
|
||||||
subject_name = x509.Name(
|
|
||||||
[x509.NameAttribute(oid.NameOID.COMMON_NAME, u'root_cert')])
|
|
||||||
certificate = oem_certificate._build_certificate(
|
|
||||||
subject_name, subject_name, None,
|
|
||||||
datetime.datetime(2001, 8, 9), 1000, key.public_key(), key, True)
|
|
||||||
return (key, certificate)
|
|
||||||
|
|
||||||
def _setup_intermediate_cert_args(self, csr_bytes, root_key,
|
|
||||||
root_certificate):
|
|
||||||
args = ArgParseObject()
|
|
||||||
args.not_valid_before = datetime.datetime(2001, 8, 9)
|
|
||||||
args.valid_duration = 100
|
|
||||||
args.system_id = 1234554321
|
|
||||||
args.csr_file = StringIO.StringIO(csr_bytes)
|
|
||||||
args.root_private_key_passphrase = 'root_passphrase'
|
|
||||||
args.output_certificate_file = StringIO.StringIO()
|
|
||||||
|
|
||||||
serialized_private_key = root_key.private_bytes(
|
|
||||||
serialization.Encoding.DER,
|
|
||||||
format=serialization.PrivateFormat.PKCS8,
|
|
||||||
encryption_algorithm=serialization.BestAvailableEncryption(
|
|
||||||
args.root_private_key_passphrase))
|
|
||||||
serialized_certificate = root_certificate.public_bytes(
|
|
||||||
serialization.Encoding.DER)
|
|
||||||
|
|
||||||
args.root_certificate_file = StringIO.StringIO(serialized_certificate)
|
|
||||||
args.root_private_key_file = StringIO.StringIO(serialized_private_key)
|
|
||||||
return args
|
|
||||||
|
|
||||||
def test_generate_intermediate_certificate(self):
|
def test_generate_intermediate_certificate(self):
|
||||||
csr_args = self._setup_csr_args()
|
csr_args = oem_cert_gen_helper.setup_csr_rgs()
|
||||||
oem_certificate.generate_csr(csr_args)
|
oem_certificate.generate_csr(csr_args)
|
||||||
csr_bytes = csr_args.output_csr_file.getvalue()
|
csr_bytes = csr_args.output_csr_file.getvalue()
|
||||||
csr = x509.load_pem_x509_csr(csr_bytes, backends.default_backend())
|
csr = x509.load_pem_x509_csr(csr_bytes, backends.default_backend())
|
||||||
|
|
||||||
root_key, root_certificate = self._create_root_certificate_and_key()
|
root_key, root_certificate = (
|
||||||
args = self._setup_intermediate_cert_args(csr_bytes, root_key,
|
oem_cert_gen_helper.create_root_certificate_and_key())
|
||||||
root_certificate)
|
args = oem_cert_gen_helper.setup_intermediate_cert_args(
|
||||||
|
csr_bytes, root_key, root_certificate)
|
||||||
oem_certificate.generate_intermediate_certificate(args)
|
oem_certificate.generate_intermediate_certificate(args)
|
||||||
|
|
||||||
cert = x509.load_der_x509_certificate(
|
cert = x509.load_der_x509_certificate(
|
||||||
@@ -162,53 +117,20 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
cert.signature_hash_algorithm)
|
cert.signature_hash_algorithm)
|
||||||
|
|
||||||
def test_generate_intermediate_with_cert_mismatch_root_cert_and_key(self):
|
def test_generate_intermediate_with_cert_mismatch_root_cert_and_key(self):
|
||||||
root_key1, _ = self._create_root_certificate_and_key()
|
root_key1, _ = (
|
||||||
_, root_certificate2 = self._create_root_certificate_and_key()
|
oem_cert_gen_helper.create_root_certificate_and_key())
|
||||||
args = self._setup_intermediate_cert_args('some csr data', root_key1,
|
_, root_certificate2 = oem_cert_gen_helper.create_root_certificate_and_key()
|
||||||
root_certificate2)
|
args = oem_cert_gen_helper.setup_intermediate_cert_args(
|
||||||
|
'some csr data', root_key1, root_certificate2)
|
||||||
with self.assertRaises(ValueError) as context:
|
with self.assertRaises(ValueError) as context:
|
||||||
oem_certificate.generate_intermediate_certificate(args)
|
oem_certificate.generate_intermediate_certificate(args)
|
||||||
self.assertTrue('certificate does not match' in str(context.exception))
|
self.assertTrue('certificate does not match' in str(context.exception))
|
||||||
|
|
||||||
def _setup_leaf_cert_args(self,
|
|
||||||
intermediate_key_bytes,
|
|
||||||
intermediate_certificate_bytes,
|
|
||||||
key_size=1024,
|
|
||||||
passphrase=None):
|
|
||||||
args = ArgParseObject()
|
|
||||||
args.key_size = key_size
|
|
||||||
args.not_valid_before = datetime.datetime(2001, 8, 9)
|
|
||||||
args.valid_duration = 8000
|
|
||||||
args.intermediate_private_key_passphrase = None
|
|
||||||
args.output_certificate_file = StringIO.StringIO()
|
|
||||||
args.output_private_key_file = StringIO.StringIO()
|
|
||||||
args.passphrase = passphrase
|
|
||||||
|
|
||||||
args.intermediate_private_key_file = StringIO.StringIO(
|
|
||||||
intermediate_key_bytes)
|
|
||||||
args.intermediate_certificate_file = StringIO.StringIO(
|
|
||||||
intermediate_certificate_bytes)
|
|
||||||
return args
|
|
||||||
|
|
||||||
def _create_intermediate_certificate_and_key_bytes(self,
|
|
||||||
key_size=4096,
|
|
||||||
passphrase=None):
|
|
||||||
csr_args = self._setup_csr_args(key_size, passphrase)
|
|
||||||
oem_certificate.generate_csr(csr_args)
|
|
||||||
csr_bytes = csr_args.output_csr_file.getvalue()
|
|
||||||
|
|
||||||
root_key, root_certificate = self._create_root_certificate_and_key()
|
|
||||||
args = self._setup_intermediate_cert_args(csr_bytes, root_key,
|
|
||||||
root_certificate)
|
|
||||||
oem_certificate.generate_intermediate_certificate(args)
|
|
||||||
return (csr_args.output_private_key_file.getvalue(),
|
|
||||||
args.output_certificate_file.getvalue())
|
|
||||||
|
|
||||||
def test_generate_leaf_certificate(self):
|
def test_generate_leaf_certificate(self):
|
||||||
intermediate_key_bytes, intermediate_certificate_bytes = (
|
intermediate_key_bytes, intermediate_certificate_bytes = (
|
||||||
self._create_intermediate_certificate_and_key_bytes())
|
oem_cert_gen_helper.create_intermediate_certificate_and_key_bytes())
|
||||||
args = self._setup_leaf_cert_args(intermediate_key_bytes,
|
args = oem_cert_gen_helper.setup_leaf_cert_args(
|
||||||
intermediate_certificate_bytes)
|
intermediate_key_bytes, intermediate_certificate_bytes)
|
||||||
oem_certificate.generate_leaf_certificate(args)
|
oem_certificate.generate_leaf_certificate(args)
|
||||||
|
|
||||||
certificate_chain = oem_certificate.X509CertificateChain.load_der(
|
certificate_chain = oem_certificate.X509CertificateChain.load_der(
|
||||||
@@ -233,7 +155,7 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
oem_certificate.WidevineSystemId.oid).value.value
|
oem_certificate.WidevineSystemId.oid).value.value
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
oem_certificate.WidevineSystemId(system_id_raw_bytes).int_value(),
|
oem_certificate.WidevineSystemId(system_id_raw_bytes).int_value(),
|
||||||
1234554321)
|
2001)
|
||||||
|
|
||||||
leaf_key = serialization.load_der_private_key(
|
leaf_key = serialization.load_der_private_key(
|
||||||
args.output_private_key_file.getvalue(),
|
args.output_private_key_file.getvalue(),
|
||||||
@@ -247,8 +169,8 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_generate_leaf_certificate_with_keysize4096_and_passphrase(self):
|
def test_generate_leaf_certificate_with_keysize4096_and_passphrase(self):
|
||||||
intermediate_key_bytes, intermediate_certificate_bytes = (
|
intermediate_key_bytes, intermediate_certificate_bytes = (
|
||||||
self._create_intermediate_certificate_and_key_bytes())
|
oem_cert_gen_helper.create_intermediate_certificate_and_key_bytes())
|
||||||
args = self._setup_leaf_cert_args(
|
args = oem_cert_gen_helper.setup_leaf_cert_args(
|
||||||
intermediate_key_bytes,
|
intermediate_key_bytes,
|
||||||
intermediate_certificate_bytes,
|
intermediate_certificate_bytes,
|
||||||
key_size=4096,
|
key_size=4096,
|
||||||
@@ -261,7 +183,7 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
self.assertEqual(4096, args.key_size)
|
self.assertEqual(4096, args.key_size)
|
||||||
|
|
||||||
def test_get_csr_info(self):
|
def test_get_csr_info(self):
|
||||||
args = self._setup_csr_args()
|
args = oem_cert_gen_helper.setup_csr_rgs()
|
||||||
oem_certificate.generate_csr(args)
|
oem_certificate.generate_csr(args)
|
||||||
args.file = StringIO.StringIO(args.output_csr_file.getvalue())
|
args.file = StringIO.StringIO(args.output_csr_file.getvalue())
|
||||||
output = StringIO.StringIO()
|
output = StringIO.StringIO()
|
||||||
@@ -278,7 +200,7 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_get_certificate_info(self):
|
def test_get_certificate_info(self):
|
||||||
_, intermediate_certificate_bytes = (
|
_, intermediate_certificate_bytes = (
|
||||||
self._create_intermediate_certificate_and_key_bytes())
|
oem_cert_gen_helper.create_intermediate_certificate_and_key_bytes())
|
||||||
args = ArgParseObject()
|
args = ArgParseObject()
|
||||||
args.file = StringIO.StringIO(intermediate_certificate_bytes)
|
args.file = StringIO.StringIO(intermediate_certificate_bytes)
|
||||||
output = StringIO.StringIO()
|
output = StringIO.StringIO()
|
||||||
@@ -293,23 +215,23 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
Issuer Name:
|
Issuer Name:
|
||||||
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'root_cert')>
|
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'root_cert')>
|
||||||
Key Size: 4096
|
Key Size: 4096
|
||||||
Widevine System Id: 1234554321
|
Widevine System Id: 2001
|
||||||
Not valid before: 2001-08-09 00:00:00
|
Not valid before: 2001-08-09 00:00:00
|
||||||
Not valid after: 2001-11-17 00:00:00"""
|
Not valid after: 2001-11-17 00:00:00"""
|
||||||
self.assertEqual(output.getvalue(), textwrap.dedent(expected_info))
|
self.assertEqual(output.getvalue(), textwrap.dedent(expected_info))
|
||||||
|
|
||||||
def test_get_certificate_chain_info(self):
|
def test_get_certificate_chain_info(self):
|
||||||
intermediate_key_bytes, intermediate_certificate_bytes = (
|
intermediate_key_bytes, intermediate_certificate_bytes = (
|
||||||
self._create_intermediate_certificate_and_key_bytes())
|
oem_cert_gen_helper.create_intermediate_certificate_and_key_bytes())
|
||||||
args = self._setup_leaf_cert_args(intermediate_key_bytes,
|
args = oem_cert_gen_helper.setup_leaf_cert_args(
|
||||||
intermediate_certificate_bytes)
|
intermediate_key_bytes, intermediate_certificate_bytes)
|
||||||
oem_certificate.generate_leaf_certificate(args)
|
oem_certificate.generate_leaf_certificate(args)
|
||||||
args.file = StringIO.StringIO(args.output_certificate_file.getvalue())
|
args.file = StringIO.StringIO(args.output_certificate_file.getvalue())
|
||||||
output = StringIO.StringIO()
|
output = StringIO.StringIO()
|
||||||
oem_certificate.get_info(args, output)
|
oem_certificate.get_info(args, output)
|
||||||
expected_info = """\
|
expected_info = """\
|
||||||
Certificate Subject Name:
|
Certificate Subject Name:
|
||||||
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'1234554321-leaf')>
|
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'2001-leaf')>
|
||||||
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value=u'US')>
|
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value=u'US')>
|
||||||
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.8, name=stateOrProvinceName)>, value=u'WA')>
|
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.8, name=stateOrProvinceName)>, value=u'WA')>
|
||||||
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.7, name=localityName)>, value=u'Kirkland')>
|
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.7, name=localityName)>, value=u'Kirkland')>
|
||||||
@@ -322,7 +244,7 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.10, name=organizationName)>, value=u'CompanyXYZ')>
|
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.10, name=organizationName)>, value=u'CompanyXYZ')>
|
||||||
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.11, name=organizationalUnitName)>, value=u'ContentProtection')>
|
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.11, name=organizationalUnitName)>, value=u'ContentProtection')>
|
||||||
Key Size: 1024
|
Key Size: 1024
|
||||||
Widevine System Id: 1234554321
|
Widevine System Id: 2001
|
||||||
Not valid before: 2001-08-09 00:00:00
|
Not valid before: 2001-08-09 00:00:00
|
||||||
Not valid after: 2023-07-05 00:00:00
|
Not valid after: 2023-07-05 00:00:00
|
||||||
|
|
||||||
@@ -335,7 +257,7 @@ class OemCertificateTest(unittest.TestCase):
|
|||||||
Issuer Name:
|
Issuer Name:
|
||||||
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'root_cert')>
|
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'root_cert')>
|
||||||
Key Size: 4096
|
Key Size: 4096
|
||||||
Widevine System Id: 1234554321
|
Widevine System Id: 2001
|
||||||
Not valid before: 2001-08-09 00:00:00
|
Not valid before: 2001-08-09 00:00:00
|
||||||
Not valid after: 2001-11-17 00:00:00"""
|
Not valid after: 2001-11-17 00:00:00"""
|
||||||
self.assertEqual(output.getvalue(), textwrap.dedent(expected_info))
|
self.assertEqual(output.getvalue(), textwrap.dedent(expected_info))
|
||||||
|
|||||||
@@ -85,8 +85,9 @@ message ProvisioningResponse {
|
|||||||
// The message authentication key.
|
// The message authentication key.
|
||||||
message SignedProvisioningMessage {
|
message SignedProvisioningMessage {
|
||||||
enum ProtocolVersion {
|
enum ProtocolVersion {
|
||||||
VERSION_2 = 2; // Keybox factory-provisioned devices.
|
PROVISIONING_20 = 2; // Keybox factory-provisioned devices.
|
||||||
VERSION_3 = 3; // OEM certificate factory-provisioned devices.
|
PROVISIONING_30 = 3; // OEM certificate factory-provisioned devices.
|
||||||
|
INTEL_SIGMA_101 = 101; // Intel Sigma 1.0.1 protocol.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialized ProvisioningRequest or ProvisioningResponse. Required.
|
// Serialized ProvisioningRequest or ProvisioningResponse. Required.
|
||||||
@@ -94,5 +95,5 @@ message SignedProvisioningMessage {
|
|||||||
// HMAC-SHA256 (Keybox) or RSASSA-PSS (OEM) signature of message. Required.
|
// HMAC-SHA256 (Keybox) or RSASSA-PSS (OEM) signature of message. Required.
|
||||||
optional bytes signature = 2;
|
optional bytes signature = 2;
|
||||||
// Version number of provisioning protocol.
|
// Version number of provisioning protocol.
|
||||||
optional ProtocolVersion protocol_version = 3 [default = VERSION_2];
|
optional ProtocolVersion protocol_version = 3 [default = PROVISIONING_20];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,10 +77,8 @@ bool VerifyAndExtractCertificate(const RsaPublicKey* public_key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GenerateCertificate(DrmDeviceCertificate::CertificateType type,
|
bool GenerateCertificate(DrmDeviceCertificate::CertificateType type,
|
||||||
uint32_t system_id,
|
uint32_t system_id, const std::string& provider_id,
|
||||||
const std::string& provider_id,
|
const std::string& serial_number, const std::string& public_key,
|
||||||
const std::string& serial_number,
|
|
||||||
const std::string& public_key,
|
|
||||||
const RsaPrivateKey& signing_key,
|
const RsaPrivateKey& signing_key,
|
||||||
const SignedDrmDeviceCertificate& signer,
|
const SignedDrmDeviceCertificate& signer,
|
||||||
std::string* certificate) {
|
std::string* certificate) {
|
||||||
@@ -145,10 +143,10 @@ ProvisioningEngineImpl::~ProvisioningEngineImpl() {}
|
|||||||
ProvisioningStatus ProvisioningEngineImpl::Initialize(
|
ProvisioningStatus ProvisioningEngineImpl::Initialize(
|
||||||
CertificateType certificate_type, const std::string& drm_service_certificate,
|
CertificateType certificate_type, const std::string& drm_service_certificate,
|
||||||
const std::string& service_private_key,
|
const std::string& service_private_key,
|
||||||
const std::string& service_private_key_phassphrase,
|
const std::string& service_private_key_passphrase,
|
||||||
const std::string& provisioning_drm_certificate,
|
const std::string& provisioning_drm_certificate,
|
||||||
const std::string& provisioning_private_key,
|
const std::string& provisioning_private_key,
|
||||||
const std::string& provisioning_private_key_phassphrase,
|
const std::string& provisioning_private_key_passphrase,
|
||||||
const std::string& secret_spoid_sauce) {
|
const std::string& secret_spoid_sauce) {
|
||||||
if (!LoadDrmRootPublicKey(certificate_type)) return INVALID_CERTIFICATE_TYPE;
|
if (!LoadDrmRootPublicKey(certificate_type)) return INVALID_CERTIFICATE_TYPE;
|
||||||
|
|
||||||
@@ -167,7 +165,7 @@ ProvisioningStatus ProvisioningEngineImpl::Initialize(
|
|||||||
rsa_key_factory_->CreateFromPkcs1PublicKey(drm_cert.public_key());
|
rsa_key_factory_->CreateFromPkcs1PublicKey(drm_cert.public_key());
|
||||||
if (!service_public_key_) return INVALID_SERVICE_DRM_CERTIFICATE;
|
if (!service_public_key_) return INVALID_SERVICE_DRM_CERTIFICATE;
|
||||||
service_private_key_ = rsa_key_factory_->CreateFromPkcs8PrivateKey(
|
service_private_key_ = rsa_key_factory_->CreateFromPkcs8PrivateKey(
|
||||||
service_private_key, service_private_key_phassphrase);
|
service_private_key, service_private_key_passphrase);
|
||||||
if (!service_private_key_) return INVALID_SERVICE_PRIVATE_KEY;
|
if (!service_private_key_) return INVALID_SERVICE_PRIVATE_KEY;
|
||||||
if (!service_public_key_->MatchesPrivateKey(*service_private_key_)) {
|
if (!service_public_key_->MatchesPrivateKey(*service_private_key_)) {
|
||||||
LOG(WARNING) << "Services public key and private key do not match.";
|
LOG(WARNING) << "Services public key and private key do not match.";
|
||||||
@@ -189,7 +187,7 @@ ProvisioningStatus ProvisioningEngineImpl::Initialize(
|
|||||||
rsa_key_factory_->CreateFromPkcs1PublicKey(drm_cert.public_key());
|
rsa_key_factory_->CreateFromPkcs1PublicKey(drm_cert.public_key());
|
||||||
if (!provisioning_public_key_) return INVALID_PROVISIONER_DRM_CERTIFICATE;
|
if (!provisioning_public_key_) return INVALID_PROVISIONER_DRM_CERTIFICATE;
|
||||||
provisioning_private_key_ = rsa_key_factory_->CreateFromPkcs8PrivateKey(
|
provisioning_private_key_ = rsa_key_factory_->CreateFromPkcs8PrivateKey(
|
||||||
provisioning_private_key, provisioning_private_key_phassphrase);
|
provisioning_private_key, provisioning_private_key_passphrase);
|
||||||
if (!provisioning_private_key_) return INVALID_PROVISIONER_PRIVATE_KEY;
|
if (!provisioning_private_key_) return INVALID_PROVISIONER_PRIVATE_KEY;
|
||||||
if (!provisioning_public_key_->MatchesPrivateKey(
|
if (!provisioning_public_key_->MatchesPrivateKey(
|
||||||
*provisioning_private_key_)) {
|
*provisioning_private_key_)) {
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ class ProvisioningEngineImpl {
|
|||||||
// (creation_time_seconds). Zero means it will never expire.
|
// (creation_time_seconds). Zero means it will never expire.
|
||||||
// * Returns OK on success, or an appropriate error status code otherwise.
|
// * Returns OK on success, or an appropriate error status code otherwise.
|
||||||
ProvisioningStatus SetCertificateStatusList(
|
ProvisioningStatus SetCertificateStatusList(
|
||||||
const std::string& certificate_status_list,
|
const std::string& certificate_status_list, uint32_t expiration_period_seconds);
|
||||||
uint32_t expiration_period_seconds);
|
|
||||||
|
|
||||||
// Generate an intermediate DRM certificate.
|
// Generate an intermediate DRM certificate.
|
||||||
// * |system_id| is the Widevine system ID for the type of device.
|
// * |system_id| is the Widevine system ID for the type of device.
|
||||||
@@ -129,8 +128,7 @@ class ProvisioningEngineImpl {
|
|||||||
const std::string& certificate_serial_number, std::string* certificate) const;
|
const std::string& certificate_serial_number, std::string* certificate) const;
|
||||||
|
|
||||||
// Get the device info for the given |system_id|.
|
// Get the device info for the given |system_id|.
|
||||||
std::shared_ptr<ProvisionedDeviceInfo> GetDeviceInfo(
|
std::shared_ptr<ProvisionedDeviceInfo> GetDeviceInfo(uint32_t system_id) const;
|
||||||
uint32_t system_id) const;
|
|
||||||
|
|
||||||
// Returns the service private key.
|
// Returns the service private key.
|
||||||
const RsaPrivateKey* service_private_key() const {
|
const RsaPrivateKey* service_private_key() const {
|
||||||
|
|||||||
@@ -18,11 +18,11 @@
|
|||||||
#include "common/sha_util.h"
|
#include "common/sha_util.h"
|
||||||
#include "provisioning_sdk/public/provisioning_status.h"
|
#include "provisioning_sdk/public/provisioning_status.h"
|
||||||
|
|
||||||
DEFINE_int32(provisioning_log_every_n, 1,
|
DEFINE_int32(prov_sdk_log_every_n, 1,
|
||||||
"parameter for LOG_EVERY_N to help abate log spamming.");
|
"parameter for LOG_EVERY_N to help abate log spamming.");
|
||||||
|
|
||||||
#define LOG_EVERY_N_WITH_PROTO(message, proto) \
|
#define LOG_EVERY_N_WITH_PROTO(message, proto) \
|
||||||
LOG_EVERY_N(WARNING, FLAGS_provisioning_log_every_n) \
|
LOG_EVERY_N(WARNING, FLAGS_prov_sdk_log_every_n) \
|
||||||
<< (message) << " [proto: " << (proto).ShortDebugString() << "]"
|
<< (message) << " [proto: " << (proto).ShortDebugString() << "]"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
@@ -42,8 +42,10 @@ ProvisioningStatus ProvisioningSessionImpl::Initialize(
|
|||||||
auto rsa_public_key =
|
auto rsa_public_key =
|
||||||
rsa_key_factory_->CreateFromPkcs1PublicKey(device_public_key);
|
rsa_key_factory_->CreateFromPkcs1PublicKey(device_public_key);
|
||||||
if (!rsa_public_key) return INVALID_DEVICE_PUBLIC_KEY;
|
if (!rsa_public_key) return INVALID_DEVICE_PUBLIC_KEY;
|
||||||
auto rsa_private_key =
|
// Use empty std::string to indicate the private key is not encrypted.
|
||||||
rsa_key_factory_->CreateFromPkcs1PrivateKey(device_private_key);
|
const std::string kClearPkcs8PrivateKeyPassphrase;
|
||||||
|
auto rsa_private_key = rsa_key_factory_->CreateFromPkcs8PrivateKey(
|
||||||
|
device_private_key, kClearPkcs8PrivateKeyPassphrase);
|
||||||
if (!rsa_private_key) return INVALID_DEVICE_PRIVATE_KEY;
|
if (!rsa_private_key) return INVALID_DEVICE_PRIVATE_KEY;
|
||||||
if (!rsa_public_key->MatchesPrivateKey(*rsa_private_key)) {
|
if (!rsa_public_key->MatchesPrivateKey(*rsa_private_key)) {
|
||||||
LOG(WARNING) << "Device public key and private key do not match.";
|
LOG(WARNING) << "Device public key and private key do not match.";
|
||||||
@@ -141,7 +143,7 @@ bool ProvisioningSessionImpl::ValidateAndDeserializeRequest(
|
|||||||
const std::string& message, SignedProvisioningMessage* signed_request,
|
const std::string& message, SignedProvisioningMessage* signed_request,
|
||||||
ProvisioningRequest* request) const {
|
ProvisioningRequest* request) const {
|
||||||
if (!signed_request->ParseFromString(message)) {
|
if (!signed_request->ParseFromString(message)) {
|
||||||
LOG_EVERY_N(WARNING, FLAGS_provisioning_log_every_n)
|
LOG_EVERY_N(WARNING, FLAGS_prov_sdk_log_every_n)
|
||||||
<< "Failed to parse SignedProvisioningMessage.";
|
<< "Failed to parse SignedProvisioningMessage.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
using ::testing::ByMove;
|
using ::testing::ByMove;
|
||||||
using ::testing::DoAll;
|
using ::testing::DoAll;
|
||||||
|
using ::testing::IsEmpty;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
using ::testing::SaveArg;
|
using ::testing::SaveArg;
|
||||||
using ::testing::SetArgPointee;
|
using ::testing::SetArgPointee;
|
||||||
@@ -113,7 +114,7 @@ TEST_F(ProvisioningSessionImplTest, InitializeWithInvalidPrivateKey) {
|
|||||||
.WillOnce(
|
.WillOnce(
|
||||||
Return(ByMove(std::unique_ptr<RsaPublicKey>(new MockRsaPublicKey))));
|
Return(ByMove(std::unique_ptr<RsaPublicKey>(new MockRsaPublicKey))));
|
||||||
EXPECT_CALL(*mock_rsa_key_factory_,
|
EXPECT_CALL(*mock_rsa_key_factory_,
|
||||||
CreateFromPkcs1PrivateKey(kDevicePrivateKey))
|
CreateFromPkcs8PrivateKey(kDevicePrivateKey, IsEmpty()))
|
||||||
.WillOnce(Return(ByMove(nullptr)));
|
.WillOnce(Return(ByMove(nullptr)));
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
INVALID_DEVICE_PRIVATE_KEY,
|
INVALID_DEVICE_PRIVATE_KEY,
|
||||||
@@ -127,7 +128,7 @@ TEST_F(ProvisioningSessionImplTest, InitializeWithMismatchPublicPrivateKey) {
|
|||||||
.WillOnce(
|
.WillOnce(
|
||||||
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
|
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
|
||||||
EXPECT_CALL(*mock_rsa_key_factory_,
|
EXPECT_CALL(*mock_rsa_key_factory_,
|
||||||
CreateFromPkcs1PrivateKey(kDevicePrivateKey))
|
CreateFromPkcs8PrivateKey(kDevicePrivateKey, IsEmpty()))
|
||||||
.WillOnce(Return(
|
.WillOnce(Return(
|
||||||
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
|
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
|
||||||
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
|
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
|
||||||
@@ -146,7 +147,7 @@ class ProvisioningSessionImplProcessTest : public ProvisioningSessionImplTest {
|
|||||||
.WillOnce(
|
.WillOnce(
|
||||||
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
|
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
|
||||||
EXPECT_CALL(*mock_rsa_key_factory_,
|
EXPECT_CALL(*mock_rsa_key_factory_,
|
||||||
CreateFromPkcs1PrivateKey(kDevicePrivateKey))
|
CreateFromPkcs8PrivateKey(kDevicePrivateKey, IsEmpty()))
|
||||||
.WillOnce(Return(
|
.WillOnce(Return(
|
||||||
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
|
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
|
||||||
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
|
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ cc_library(
|
|||||||
name = "libprovisioning_sdk",
|
name = "libprovisioning_sdk",
|
||||||
srcs = [":libprovisioning_sdk.so"],
|
srcs = [":libprovisioning_sdk.so"],
|
||||||
hdrs = glob(["*.h"]),
|
hdrs = glob(["*.h"]),
|
||||||
|
deps = ["//base"],
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ProvisioningSession;
|
|||||||
class ProvisioningEngine {
|
class ProvisioningEngine {
|
||||||
public:
|
public:
|
||||||
ProvisioningEngine();
|
ProvisioningEngine();
|
||||||
~ProvisioningEngine();
|
virtual ~ProvisioningEngine();
|
||||||
|
|
||||||
// Initializes the provisioning engine with required credentials.
|
// Initializes the provisioning engine with required credentials.
|
||||||
// * |certificate_type| indicates which type of certificate chains will be
|
// * |certificate_type| indicates which type of certificate chains will be
|
||||||
@@ -66,7 +66,7 @@ class ProvisioningEngine {
|
|||||||
// |certificate_status_list| expires after its creation time
|
// |certificate_status_list| expires after its creation time
|
||||||
// (creation_time_seconds). Zero means it will never expire.
|
// (creation_time_seconds). Zero means it will never expire.
|
||||||
// * Returns OK on success, or an appropriate error status code otherwise.
|
// * Returns OK on success, or an appropriate error status code otherwise.
|
||||||
ProvisioningStatus SetCertificateStatusList(
|
virtual ProvisioningStatus SetCertificateStatusList(
|
||||||
const std::string& certificate_status_list,
|
const std::string& certificate_status_list,
|
||||||
uint32_t expiration_period_seconds);
|
uint32_t expiration_period_seconds);
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ class ProvisioningEngine {
|
|||||||
// * |cert_private_key_passphrase| is the passphrase for cert_private_key,
|
// * |cert_private_key_passphrase| is the passphrase for cert_private_key,
|
||||||
// if any.
|
// if any.
|
||||||
// * Returns OK on success, or an appropriate error status code otherwise.
|
// * Returns OK on success, or an appropriate error status code otherwise.
|
||||||
ProvisioningStatus AddDrmIntermediateCertificate(
|
virtual ProvisioningStatus AddDrmIntermediateCertificate(
|
||||||
const std::string& intermediate_cert,
|
const std::string& intermediate_cert,
|
||||||
const std::string& cert_private_key,
|
const std::string& cert_private_key,
|
||||||
const std::string& cert_private_key_passphrase);
|
const std::string& cert_private_key_passphrase);
|
||||||
@@ -113,7 +113,7 @@ class ProvisioningEngine {
|
|||||||
// message.
|
// message.
|
||||||
// NOTE: All ProvisioningSession objects must be deleted before the
|
// NOTE: All ProvisioningSession objects must be deleted before the
|
||||||
// ProvisioningEngine which created them.
|
// ProvisioningEngine which created them.
|
||||||
ProvisioningStatus NewProvisioningSession(
|
virtual ProvisioningStatus NewProvisioningSession(
|
||||||
const std::string& device_public_key,
|
const std::string& device_public_key,
|
||||||
const std::string& device_private_key,
|
const std::string& device_private_key,
|
||||||
std::unique_ptr<ProvisioningSession>* new_session) const;
|
std::unique_ptr<ProvisioningSession>* new_session) const;
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
|
ProvisioningSession::ProvisioningSession() {}
|
||||||
|
|
||||||
ProvisioningSession::~ProvisioningSession() {}
|
ProvisioningSession::~ProvisioningSession() {}
|
||||||
|
|
||||||
ProvisioningStatus ProvisioningSession::ProcessMessage(const std::string& message,
|
ProvisioningStatus ProvisioningSession::ProcessMessage(const std::string& message,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class ProvisioningSessionImpl;
|
|||||||
// Class which is used to implement the provisioning session state machine.
|
// Class which is used to implement the provisioning session state machine.
|
||||||
class ProvisioningSession {
|
class ProvisioningSession {
|
||||||
public:
|
public:
|
||||||
~ProvisioningSession();
|
virtual ~ProvisioningSession();
|
||||||
|
|
||||||
// Process a message from the client device.
|
// Process a message from the client device.
|
||||||
// * |message| is the message received from the client device.
|
// * |message| is the message received from the client device.
|
||||||
@@ -31,13 +31,16 @@ class ProvisioningSession {
|
|||||||
// * |done| will indicate, upon successful return, whether the provisioning
|
// * |done| will indicate, upon successful return, whether the provisioning
|
||||||
// exchange is complete, and the ProvisioningSession can be deleted.
|
// exchange is complete, and the ProvisioningSession can be deleted.
|
||||||
// Returns OK if successful, or an appropriate error status code otherwise.
|
// Returns OK if successful, or an appropriate error status code otherwise.
|
||||||
ProvisioningStatus ProcessMessage(const std::string& message,
|
virtual ProvisioningStatus ProcessMessage(const std::string& message,
|
||||||
std::string* response,
|
std::string* response,
|
||||||
bool* done);
|
bool* done);
|
||||||
|
|
||||||
// * Returns a ProvisioneddeviceInfo message containing information about the
|
// * Returns a ProvisioneddeviceInfo message containing information about the
|
||||||
// type of device being provisioned. May return nullptr.
|
// type of device being provisioned. May return nullptr.
|
||||||
const ProvisionedDeviceInfo* GetDeviceInfo() const;
|
virtual const ProvisionedDeviceInfo* GetDeviceInfo() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ProvisioningSession(); // To enable mocking.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef SWIGPYTHON
|
#ifndef SWIGPYTHON
|
||||||
|
|||||||
@@ -18,8 +18,13 @@ filegroup(
|
|||||||
|
|
||||||
py_library(
|
py_library(
|
||||||
name = "test_data_utility",
|
name = "test_data_utility",
|
||||||
srcs = ["test_data_utility.py"],
|
srcs = [
|
||||||
data = ["//example:example_data"],
|
"test_data_provider.py",
|
||||||
|
"test_data_utility.py",
|
||||||
|
],
|
||||||
|
data = [
|
||||||
|
"//example:example_data",
|
||||||
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//protos/public:certificate_provisioning_py_pb2",
|
"//protos/public:certificate_provisioning_py_pb2",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -23,5 +23,5 @@ typedef oldtype newtype;
|
|||||||
%apply oldtype & INOUT { newtype & INOUT };
|
%apply oldtype & INOUT { newtype & INOUT };
|
||||||
%enddef
|
%enddef
|
||||||
|
|
||||||
COPY_TYPEMAPS(int, int32);
|
COPY_TYPEMAPS(int, int32_t);
|
||||||
COPY_TYPEMAPS(unsigned int, uint32);
|
COPY_TYPEMAPS(unsigned int, uint32_t);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
"""Utility functions for cryptography."""
|
"""Utility functions for cryptography."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from cryptography.hazmat import backends
|
from cryptography.hazmat import backends
|
||||||
from cryptography.hazmat.primitives import hashes
|
from cryptography.hazmat.primitives import hashes
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
@@ -18,6 +20,7 @@ def VerifySignature(public_key, signature, data):
|
|||||||
hash_algorithm = hashes.SHA1()
|
hash_algorithm = hashes.SHA1()
|
||||||
salt_len = 20
|
salt_len = 20
|
||||||
|
|
||||||
|
logging.info('Verying signature.')
|
||||||
key = serialization.load_der_public_key(
|
key = serialization.load_der_public_key(
|
||||||
public_key, backend=backends.default_backend())
|
public_key, backend=backends.default_backend())
|
||||||
key.verify(signature, data,
|
key.verify(signature, data,
|
||||||
|
|||||||
@@ -9,8 +9,10 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import crypto_utility
|
import crypto_utility
|
||||||
|
import pywrapcertificate_type
|
||||||
import pywrapprovisioning_engine
|
import pywrapprovisioning_engine
|
||||||
import pywrapprovisioning_status
|
import pywrapprovisioning_status
|
||||||
|
import test_data_provider
|
||||||
import test_data_utility
|
import test_data_utility
|
||||||
from protos.public import signed_device_certificate_pb2
|
from protos.public import signed_device_certificate_pb2
|
||||||
|
|
||||||
@@ -25,21 +27,23 @@ class EngineGenerateCertificateTest(unittest.TestCase):
|
|||||||
self._engine, 0, verify_success=True)
|
self._engine, 0, verify_success=True)
|
||||||
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
||||||
self._engine, 2001, verify_success=True)
|
self._engine, 2001, verify_success=True)
|
||||||
|
self._data_provider = test_data_provider.TestDataProvider(
|
||||||
|
pywrapcertificate_type.kCertTesting)
|
||||||
|
|
||||||
def testSuccess(self):
|
def testSuccess(self):
|
||||||
status, signed_cert_string = self._engine.GenerateDeviceDrmCertificate(
|
status, signed_cert_string = self._engine.GenerateDeviceDrmCertificate(
|
||||||
2001, test_data_utility.DEVICE_PUBLIC_KEY, 'DEVICE_SERIAL_NUMBER')
|
2001, self._data_provider.device_public_key, 'DEVICE_SERIAL_NUMBER')
|
||||||
self.assertEqual(pywrapprovisioning_status.OK, status)
|
self.assertEqual(pywrapprovisioning_status.OK, status)
|
||||||
|
|
||||||
signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate()
|
signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate()
|
||||||
signed_cert.ParseFromString(signed_cert_string)
|
signed_cert.ParseFromString(signed_cert_string)
|
||||||
crypto_utility.VerifySignature(test_data_utility.CA_PUBLIC_KEY,
|
crypto_utility.VerifySignature(self._data_provider.ca_public_key,
|
||||||
signed_cert.signature,
|
signed_cert.signature,
|
||||||
signed_cert.drm_certificate)
|
signed_cert.drm_certificate)
|
||||||
|
|
||||||
def testEmptySerialNumber(self):
|
def testEmptySerialNumber(self):
|
||||||
status, _ = self._engine.GenerateDeviceDrmCertificate(
|
status, _ = self._engine.GenerateDeviceDrmCertificate(
|
||||||
2001, test_data_utility.DEVICE_PUBLIC_KEY, '')
|
2001, self._data_provider.device_public_key, '')
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_SERIAL_NUMBER, status)
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERIAL_NUMBER, status)
|
||||||
|
|
||||||
def testEmptyPublicKey(self):
|
def testEmptyPublicKey(self):
|
||||||
@@ -57,7 +61,7 @@ class EngineGenerateCertificateTest(unittest.TestCase):
|
|||||||
|
|
||||||
def testMissingIntermediateCertificate(self):
|
def testMissingIntermediateCertificate(self):
|
||||||
status, _ = self._engine.GenerateDeviceDrmCertificate(
|
status, _ = self._engine.GenerateDeviceDrmCertificate(
|
||||||
2002, test_data_utility.DEVICE_PUBLIC_KEY, 'DEVICE_SERIAL_NUMBER')
|
2002, self._data_provider.device_public_key, 'DEVICE_SERIAL_NUMBER')
|
||||||
self.assertEqual(pywrapprovisioning_status.DEVICE_REVOKED, status)
|
self.assertEqual(pywrapprovisioning_status.DEVICE_REVOKED, status)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import unittest
|
|||||||
import pywrapcertificate_type
|
import pywrapcertificate_type
|
||||||
import pywrapprovisioning_engine
|
import pywrapprovisioning_engine
|
||||||
import pywrapprovisioning_status
|
import pywrapprovisioning_status
|
||||||
|
import test_data_provider
|
||||||
import test_data_utility
|
import test_data_utility
|
||||||
|
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@ class InitEngineTest(unittest.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
|
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
|
||||||
|
self._data_provider = test_data_provider.TestDataProvider(
|
||||||
|
pywrapcertificate_type.kCertTesting)
|
||||||
|
|
||||||
def testInitEngineSucceed(self):
|
def testInitEngineSucceed(self):
|
||||||
test_data_utility.InitProvisionEngineWithTestData(
|
test_data_utility.InitProvisionEngineWithTestData(
|
||||||
@@ -58,112 +61,111 @@ class InitEngineTest(unittest.TestCase):
|
|||||||
def testInitEngineInvalidServiceDrmCert(self):
|
def testInitEngineInvalidServiceDrmCert(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting, 'INVALID_CERT',
|
pywrapcertificate_type.kCertTesting, 'INVALID_CERT',
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY,
|
self._data_provider.service_private_key,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
self._data_provider.service_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_DRM_CERT,
|
self._data_provider.provisioner_drm_cert,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY,
|
self._data_provider.provisioner_private_key,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY_PASS,
|
self._data_provider.provisioner_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_SPOID_SECRET)
|
self._data_provider.provisioner_spoid_secret)
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_DRM_CERTIFICATE,
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_DRM_CERTIFICATE,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
def testInitEngineInvalidServicePrivateKey(self):
|
def testInitEngineInvalidServicePrivateKey(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting,
|
pywrapcertificate_type.kCertTesting,
|
||||||
test_data_utility.SERVICE_DRM_CERT, 'INVALID_KEY',
|
self._data_provider.service_drm_cert, 'INVALID_KEY',
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
self._data_provider.service_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_DRM_CERT,
|
self._data_provider.provisioner_drm_cert,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY,
|
self._data_provider.provisioner_private_key,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY_PASS,
|
self._data_provider.provisioner_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_SPOID_SECRET)
|
self._data_provider.provisioner_spoid_secret)
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
def testInitEngineWrongServicePrivateKey(self):
|
def testInitEngineWrongServicePrivateKey(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting,
|
pywrapcertificate_type.kCertTesting,
|
||||||
test_data_utility.SERVICE_DRM_CERT,
|
self._data_provider.service_drm_cert,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY,
|
self._data_provider.provisioner_private_key,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
self._data_provider.service_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_DRM_CERT,
|
self._data_provider.provisioner_drm_cert,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY,
|
self._data_provider.provisioner_private_key,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY_PASS,
|
self._data_provider.provisioner_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_SPOID_SECRET)
|
self._data_provider.provisioner_spoid_secret)
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
def testInitEngineInvalidServicePrivateKeyPassphrase(self):
|
def testInitEngineInvalidServicePrivateKeyPassphrase(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting,
|
pywrapcertificate_type.kCertTesting,
|
||||||
test_data_utility.SERVICE_DRM_CERT,
|
self._data_provider.service_drm_cert,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY, 'INVALID_PASSPHRASE',
|
self._data_provider.service_private_key, 'INVALID_PASSPHRASE',
|
||||||
test_data_utility.PROVISIONER_DRM_CERT,
|
self._data_provider.provisioner_drm_cert,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY,
|
self._data_provider.provisioner_private_key,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY_PASS,
|
self._data_provider.provisioner_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_SPOID_SECRET)
|
self._data_provider.provisioner_spoid_secret)
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
def testInitEngineInvalidDrmCert(self):
|
def testInitEngineInvalidDrmCert(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting,
|
pywrapcertificate_type.kCertTesting,
|
||||||
test_data_utility.SERVICE_DRM_CERT,
|
self._data_provider.service_drm_cert,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY,
|
self._data_provider.service_private_key,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY_PASS, 'INVALID_CERT',
|
self._data_provider.service_private_key_passphrase, 'INVALID_CERT',
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY,
|
self._data_provider.provisioner_private_key,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY_PASS,
|
self._data_provider.provisioner_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_SPOID_SECRET)
|
self._data_provider.provisioner_spoid_secret)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
pywrapprovisioning_status.INVALID_PROVISIONER_DRM_CERTIFICATE, status)
|
pywrapprovisioning_status.INVALID_PROVISIONER_DRM_CERTIFICATE, status)
|
||||||
|
|
||||||
def testInitEngineInvalidDrmPrivateKey(self):
|
def testInitEngineInvalidDrmPrivateKey(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting,
|
pywrapcertificate_type.kCertTesting,
|
||||||
test_data_utility.SERVICE_DRM_CERT,
|
self._data_provider.service_drm_cert,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY,
|
self._data_provider.service_private_key,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
self._data_provider.service_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_DRM_CERT, 'INVALID_KEY',
|
self._data_provider.provisioner_drm_cert, 'INVALID_KEY',
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY_PASS,
|
self._data_provider.provisioner_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_SPOID_SECRET)
|
self._data_provider.provisioner_spoid_secret)
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
|
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
def testInitEngineWrongDrmPrivateKey(self):
|
def testInitEngineWrongDrmPrivateKey(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting,
|
pywrapcertificate_type.kCertTesting,
|
||||||
test_data_utility.SERVICE_DRM_CERT,
|
self._data_provider.service_drm_cert,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY,
|
self._data_provider.service_private_key,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
self._data_provider.service_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_DRM_CERT,
|
self._data_provider.provisioner_drm_cert,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY,
|
self._data_provider.service_private_key,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY_PASS,
|
self._data_provider.provisioner_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_SPOID_SECRET)
|
self._data_provider.provisioner_spoid_secret)
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
|
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
def testInitEngineInvalidDrmPrivateKeyPassphrase(self):
|
def testInitEngineInvalidDrmPrivateKeyPassphrase(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting,
|
pywrapcertificate_type.kCertTesting,
|
||||||
test_data_utility.SERVICE_DRM_CERT,
|
self._data_provider.service_drm_cert,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY,
|
self._data_provider.service_private_key,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
self._data_provider.service_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_DRM_CERT,
|
self._data_provider.provisioner_drm_cert,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY,
|
self._data_provider.provisioner_private_key_passphrase,
|
||||||
'INVALID_PASSPHRASE',
|
'INVALID_PASSPHRASE',
|
||||||
test_data_utility.PROVISIONER_SPOID_SECRET)
|
self._data_provider.provisioner_spoid_secret)
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
|
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
def testInitEngineInvalidSpoidSecret(self):
|
def testInitEngineInvalidSpoidSecret(self):
|
||||||
status = self._engine.Initialize(
|
status = self._engine.Initialize(
|
||||||
pywrapcertificate_type.kCertTesting,
|
pywrapcertificate_type.kCertTesting,
|
||||||
test_data_utility.SERVICE_DRM_CERT,
|
self._data_provider.service_drm_cert,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY,
|
self._data_provider.service_private_key,
|
||||||
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
self._data_provider.service_private_key_passphrase,
|
||||||
test_data_utility.PROVISIONER_DRM_CERT,
|
self._data_provider.provisioner_drm_cert,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY,
|
self._data_provider.provisioner_private_key,
|
||||||
test_data_utility.PROVISIONER_PRIVATE_KEY_PASS,
|
self._data_provider.provisioner_private_key_passphrase, '')
|
||||||
'')
|
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_SPOID_SAUCE, status)
|
self.assertEqual(pywrapprovisioning_status.INVALID_SPOID_SAUCE, status)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -9,8 +9,10 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import crypto_utility
|
import crypto_utility
|
||||||
|
import pywrapcertificate_type
|
||||||
import pywrapprovisioning_engine
|
import pywrapprovisioning_engine
|
||||||
import pywrapprovisioning_status
|
import pywrapprovisioning_status
|
||||||
|
import test_data_provider
|
||||||
import test_data_utility
|
import test_data_utility
|
||||||
from protos.public import certificate_provisioning_pb2
|
from protos.public import certificate_provisioning_pb2
|
||||||
from protos.public import signed_device_certificate_pb2
|
from protos.public import signed_device_certificate_pb2
|
||||||
@@ -24,6 +26,8 @@ class NewSessionTest(unittest.TestCase):
|
|||||||
self._engine, verify_success=True)
|
self._engine, verify_success=True)
|
||||||
test_data_utility.SetCertificateStatusListWithTestData(
|
test_data_utility.SetCertificateStatusListWithTestData(
|
||||||
self._engine, 0, verify_success=True)
|
self._engine, 0, verify_success=True)
|
||||||
|
self._data_provider = test_data_provider.TestDataProvider(
|
||||||
|
pywrapcertificate_type.kCertTesting)
|
||||||
|
|
||||||
def testNewSessionSuccess(self):
|
def testNewSessionSuccess(self):
|
||||||
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
||||||
@@ -32,11 +36,11 @@ class NewSessionTest(unittest.TestCase):
|
|||||||
(_, new_session) = test_data_utility.NewProvisioningSessionWithTestData(
|
(_, new_session) = test_data_utility.NewProvisioningSessionWithTestData(
|
||||||
self._engine, verify_success=True)
|
self._engine, verify_success=True)
|
||||||
(status, raw_response,
|
(status, raw_response,
|
||||||
_) = new_session.ProcessMessage(test_data_utility.MESSAGE)
|
_) = new_session.ProcessMessage(self._data_provider.message)
|
||||||
test_data_utility.AssertSuccess(status, 'Failed to create session.')
|
test_data_utility.AssertSuccess(status, 'Failed to create session.')
|
||||||
|
|
||||||
signed_request = test_data_utility.ConvertToSignedProvisioningMessage(
|
signed_request = test_data_utility.ConvertToSignedProvisioningMessage(
|
||||||
test_data_utility.MESSAGE)
|
self._data_provider.message)
|
||||||
|
|
||||||
unsigned_request = certificate_provisioning_pb2.ProvisioningRequest()
|
unsigned_request = certificate_provisioning_pb2.ProvisioningRequest()
|
||||||
unsigned_request.ParseFromString(signed_request.message)
|
unsigned_request.ParseFromString(signed_request.message)
|
||||||
@@ -44,7 +48,7 @@ class NewSessionTest(unittest.TestCase):
|
|||||||
signed_response = test_data_utility.ConvertToSignedProvisioningMessage(
|
signed_response = test_data_utility.ConvertToSignedProvisioningMessage(
|
||||||
raw_response)
|
raw_response)
|
||||||
|
|
||||||
self._VerifyMessageSignature(test_data_utility.SERVICE_PUBLIC_KEY,
|
self._VerifyMessageSignature(self._data_provider.service_public_key,
|
||||||
signed_response)
|
signed_response)
|
||||||
|
|
||||||
unsigned_response = certificate_provisioning_pb2.ProvisioningResponse()
|
unsigned_response = certificate_provisioning_pb2.ProvisioningResponse()
|
||||||
@@ -63,7 +67,8 @@ class NewSessionTest(unittest.TestCase):
|
|||||||
def testNewSessionWithoutIntermediateCert(self):
|
def testNewSessionWithoutIntermediateCert(self):
|
||||||
(_, new_session) = test_data_utility.NewProvisioningSessionWithTestData(
|
(_, new_session) = test_data_utility.NewProvisioningSessionWithTestData(
|
||||||
self._engine, verify_success=True)
|
self._engine, verify_success=True)
|
||||||
(status, _, _) = new_session.ProcessMessage(test_data_utility.MESSAGE)
|
(status, _, _) = new_session.ProcessMessage(
|
||||||
|
self._data_provider.message)
|
||||||
self.assertEqual(pywrapprovisioning_status.MISSING_DRM_INTERMEDIATE_CERT,
|
self.assertEqual(pywrapprovisioning_status.MISSING_DRM_INTERMEDIATE_CERT,
|
||||||
status)
|
status)
|
||||||
|
|
||||||
@@ -71,7 +76,7 @@ class NewSessionTest(unittest.TestCase):
|
|||||||
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
||||||
self._engine, 2001, verify_success=True)
|
self._engine, 2001, verify_success=True)
|
||||||
(session_status, _) = self._engine.NewProvisioningSession(
|
(session_status, _) = self._engine.NewProvisioningSession(
|
||||||
'INVALID_PUBLIC_KEY', test_data_utility.DEVICE_PRIVATE_KEY)
|
'INVALID_PUBLIC_KEY', self._data_provider.device_private_key)
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY,
|
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY,
|
||||||
session_status)
|
session_status)
|
||||||
|
|
||||||
@@ -79,7 +84,7 @@ class NewSessionTest(unittest.TestCase):
|
|||||||
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
||||||
self._engine, 2001, verify_success=True)
|
self._engine, 2001, verify_success=True)
|
||||||
(session_status, _) = self._engine.NewProvisioningSession(
|
(session_status, _) = self._engine.NewProvisioningSession(
|
||||||
test_data_utility.DEVICE_PUBLIC_KEY, 'INVALID_PRIVATE_KEY')
|
self._data_provider.device_public_key, 'INVALID_PRIVATE_KEY')
|
||||||
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PRIVATE_KEY,
|
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PRIVATE_KEY,
|
||||||
session_status)
|
session_status)
|
||||||
|
|
||||||
@@ -97,7 +102,8 @@ class NewSessionTest(unittest.TestCase):
|
|||||||
signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate()
|
signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate()
|
||||||
signed_cert.ParseFromString(response.device_certificate)
|
signed_cert.ParseFromString(response.device_certificate)
|
||||||
|
|
||||||
self._VerifyCertSignature(test_data_utility.CA_PUBLIC_KEY, signed_cert)
|
self._VerifyCertSignature(self._data_provider.ca_public_key,
|
||||||
|
signed_cert)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@@ -18,9 +18,6 @@
|
|||||||
UNIQUE_PTR_ARGOUT(widevine::ProvisioningSession, new_session);
|
UNIQUE_PTR_ARGOUT(widevine::ProvisioningSession, new_session);
|
||||||
|
|
||||||
%apply int { CertificateType, ProvisioningStatus };
|
%apply int { CertificateType, ProvisioningStatus };
|
||||||
%apply int32 { int32_t };
|
|
||||||
%apply uint32 { uint32_t };
|
|
||||||
|
|
||||||
%apply std::string* OUTPUT { std::string* certificate };
|
%apply std::string* OUTPUT { std::string* certificate };
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|||||||
101
provisioning_sdk/public/python/test_data_provider.py
Normal file
101
provisioning_sdk/public/python/test_data_provider.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
################################################################################
|
||||||
|
# Copyright 2017 Google Inc.
|
||||||
|
#
|
||||||
|
# This software is licensed under the terms defined in the Widevine Master
|
||||||
|
# License Agreement. For a copy of this agreement, please contact
|
||||||
|
# widevine-licensing@google.com.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""Class that provides test data for Provisioning SDK testing."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pywrapcertificate_type
|
||||||
|
|
||||||
|
_TEST_CERT_DATA_FOLDER = os.path.join('example', 'example_data')
|
||||||
|
_DEV_CERT_DATA_FOLDER = os.path.join('example', 'dev_cert_example_data')
|
||||||
|
|
||||||
|
|
||||||
|
class TestDataProvider(object):
|
||||||
|
"""For for Test Data."""
|
||||||
|
|
||||||
|
def __init__(self, cert_type):
|
||||||
|
"""Initializes the TestData for Provisioning SDK tests."""
|
||||||
|
assert (cert_type in (
|
||||||
|
pywrapcertificate_type.kCertDevelopment,
|
||||||
|
pywrapcertificate_type.kCertTesting))
|
||||||
|
self._cert_type = cert_type
|
||||||
|
|
||||||
|
def _GetTestData(self, filename):
|
||||||
|
"""Helps read test data files such as certs and keys for SDK testing."""
|
||||||
|
current_dir = os.path.realpath(os.path.dirname(__file__))
|
||||||
|
if self._cert_type == pywrapcertificate_type.kCertDevelopment:
|
||||||
|
subfolder_path = _DEV_CERT_DATA_FOLDER
|
||||||
|
elif self._cert_type == pywrapcertificate_type.kCertTesting:
|
||||||
|
subfolder_path = _TEST_CERT_DATA_FOLDER
|
||||||
|
while not os.path.isdir(os.path.join(current_dir, subfolder_path)):
|
||||||
|
current_dir = os.path.dirname(current_dir)
|
||||||
|
filename = os.path.join(current_dir, subfolder_path, filename)
|
||||||
|
with open(filename, 'rb') as data_file:
|
||||||
|
data = data_file.read()
|
||||||
|
return data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_drm_cert(self):
|
||||||
|
return self._GetTestData('service.cert')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_public_key(self):
|
||||||
|
return self._GetTestData('service.public')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_private_key(self):
|
||||||
|
return self._GetTestData('service.encrypted.private')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_private_key_passphrase(self):
|
||||||
|
return self._GetTestData('service.passphrase')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provisioner_drm_cert(self):
|
||||||
|
return self._GetTestData('provisioner.cert')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provisioner_private_key(self):
|
||||||
|
return self._GetTestData('provisioner.encrypted.private')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provisioner_private_key_passphrase(self):
|
||||||
|
return self._GetTestData('provisioner.passphrase')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provisioner_spoid_secret(self):
|
||||||
|
return self._GetTestData('provisioner.spoid_secret')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ca_public_key(self):
|
||||||
|
return self._GetTestData('intermediate.public')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ca_private_key(self):
|
||||||
|
return self._GetTestData('intermediate.encrypted.private')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ca_private_key_passphrase(self):
|
||||||
|
return self._GetTestData('intermediate.passphrase')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_public_key(self):
|
||||||
|
return self._GetTestData('user.public')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_private_key(self):
|
||||||
|
return self._GetTestData('user.private')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def message(self):
|
||||||
|
return self._GetTestData('message')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def certificate_list(self):
|
||||||
|
return self._GetTestData('certificate_list')
|
||||||
@@ -8,63 +8,48 @@
|
|||||||
|
|
||||||
"""Utility class for Provisioning SDK testing."""
|
"""Utility class for Provisioning SDK testing."""
|
||||||
|
|
||||||
import os
|
import logging
|
||||||
|
|
||||||
import pywrapcertificate_type
|
import pywrapcertificate_type
|
||||||
import pywrapprovisioning_status
|
import pywrapprovisioning_status
|
||||||
|
import test_data_provider
|
||||||
from protos.public import certificate_provisioning_pb2
|
from protos.public import certificate_provisioning_pb2
|
||||||
|
|
||||||
TEST_DATA_FOLDER = os.path.join('example', 'example_data')
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
def GetTestData(filename):
|
def InitProvisionEngineWithTestData(
|
||||||
current_dir = os.path.realpath(os.path.dirname(__file__))
|
engine, verify_success=False,
|
||||||
while not os.path.isdir(os.path.join(current_dir, TEST_DATA_FOLDER)):
|
cert_type=pywrapcertificate_type.kCertTesting):
|
||||||
current_dir = os.path.dirname(current_dir)
|
|
||||||
filename = os.path.join(current_dir, TEST_DATA_FOLDER, filename)
|
|
||||||
with open(filename, 'rb') as data_file:
|
|
||||||
data = data_file.read()
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
SERVICE_DRM_CERT = GetTestData('service.cert')
|
|
||||||
SERVICE_PUBLIC_KEY = GetTestData('service.public')
|
|
||||||
SERVICE_PRIVATE_KEY = GetTestData('service.encrypted.private')
|
|
||||||
SERVICE_PRIVATE_KEY_PASS = GetTestData('service.passphrase')
|
|
||||||
PROVISIONER_DRM_CERT = GetTestData('provisioner.cert')
|
|
||||||
PROVISIONER_PRIVATE_KEY = GetTestData('provisioner.encrypted.private')
|
|
||||||
PROVISIONER_PRIVATE_KEY_PASS = GetTestData('provisioner.passphrase')
|
|
||||||
PROVISIONER_SPOID_SECRET = GetTestData('provisioner.spoid_secret')
|
|
||||||
CA_PUBLIC_KEY = GetTestData('intermediate.public')
|
|
||||||
DEVICE_PUBLIC_KEY = GetTestData('user.public')
|
|
||||||
DEVICE_PRIVATE_KEY = GetTestData('user.private')
|
|
||||||
MESSAGE = GetTestData('message')
|
|
||||||
|
|
||||||
|
|
||||||
def InitProvisionEngineWithTestData(engine, verify_success=False):
|
|
||||||
"""Initialize the provisioning engine with sample credentials.
|
"""Initialize the provisioning engine with sample credentials.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
||||||
verify_success: whether to verify that resulting status code equals OK
|
verify_success: whether to verify that resulting status code equals OK
|
||||||
|
cert_type: The type of certificate to use for initializing SDK -
|
||||||
|
{kCertTesting/kCertDevelopment}
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
OK on success, or an appropriate error status code otherwise.
|
OK on success, or an appropriate error status code otherwise.
|
||||||
"""
|
"""
|
||||||
status = engine.Initialize(pywrapcertificate_type.kCertTesting,
|
logging.info('Initializing provisioning engine with test data.')
|
||||||
SERVICE_DRM_CERT, SERVICE_PRIVATE_KEY,
|
data_provider = test_data_provider.TestDataProvider(cert_type)
|
||||||
SERVICE_PRIVATE_KEY_PASS, PROVISIONER_DRM_CERT,
|
status = engine.Initialize(cert_type,
|
||||||
PROVISIONER_PRIVATE_KEY,
|
data_provider.service_drm_cert,
|
||||||
PROVISIONER_PRIVATE_KEY_PASS,
|
data_provider.service_private_key,
|
||||||
PROVISIONER_SPOID_SECRET)
|
data_provider.service_private_key_passphrase,
|
||||||
|
data_provider.provisioner_drm_cert,
|
||||||
|
data_provider.provisioner_private_key,
|
||||||
|
data_provider.provisioner_private_key_passphrase,
|
||||||
|
data_provider.provisioner_spoid_secret)
|
||||||
if verify_success:
|
if verify_success:
|
||||||
AssertSuccess(status, 'Failed to initialize.')
|
AssertSuccess(status, 'Failed to initialize.')
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
||||||
def SetCertificateStatusListWithTestData(engine,
|
def SetCertificateStatusListWithTestData(
|
||||||
expiration_period_seconds,
|
engine, expiration_period_seconds, verify_success=False,
|
||||||
verify_success=False):
|
cert_type=pywrapcertificate_type.kCertTesting):
|
||||||
"""Set the certificate status list with sample certificate status list.
|
"""Set the certificate status list with sample certificate status list.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -72,11 +57,15 @@ def SetCertificateStatusListWithTestData(engine,
|
|||||||
expiration_period_seconds: number of seconds until certificate_status_list
|
expiration_period_seconds: number of seconds until certificate_status_list
|
||||||
expires after its creation time
|
expires after its creation time
|
||||||
verify_success: whether to verify that resulting status code equals OK
|
verify_success: whether to verify that resulting status code equals OK
|
||||||
|
cert_type: The type of certificate to use for initializing SDK -
|
||||||
|
{kCertTesting/kCertDevelopment}
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
OK on success, or an appropriate error status code otherwise.
|
OK on success, or an appropriate error status code otherwise.
|
||||||
"""
|
"""
|
||||||
certificate_status_list = GetTestData('certificate_list')
|
logging.info('Setting certificate status list with test data.')
|
||||||
|
data_provider = test_data_provider.TestDataProvider(cert_type)
|
||||||
|
certificate_status_list = data_provider.certificate_list
|
||||||
|
|
||||||
status = engine.SetCertificateStatusList(certificate_status_list,
|
status = engine.SetCertificateStatusList(certificate_status_list,
|
||||||
expiration_period_seconds)
|
expiration_period_seconds)
|
||||||
@@ -87,9 +76,9 @@ def SetCertificateStatusListWithTestData(engine,
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
||||||
def AddDrmIntermediateCertificateWithTestData(engine,
|
def AddDrmIntermediateCertificateWithTestData(
|
||||||
system_id,
|
engine, system_id, verify_success=False,
|
||||||
verify_success=False):
|
cert_type=pywrapcertificate_type.kCertTesting):
|
||||||
"""Generate an intermediate DRM cert and add it to provisioning engine.
|
"""Generate an intermediate DRM cert and add it to provisioning engine.
|
||||||
|
|
||||||
The intermediate DRM certificate is generated with sample public key and
|
The intermediate DRM certificate is generated with sample public key and
|
||||||
@@ -100,19 +89,23 @@ def AddDrmIntermediateCertificateWithTestData(engine,
|
|||||||
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
||||||
system_id: Widevine system ID for the type of device
|
system_id: Widevine system ID for the type of device
|
||||||
verify_success: whether to verify that resulting status code equals OK
|
verify_success: whether to verify that resulting status code equals OK
|
||||||
|
cert_type: The type of certificate to use for initializing SDK -
|
||||||
|
{kCertTesting/kCertDevelopment}
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
OK on success, or an appropriate error status code otherwise.
|
OK on success, or an appropriate error status code otherwise.
|
||||||
"""
|
"""
|
||||||
ca_private_key = GetTestData('intermediate.encrypted.private')
|
logging.info(
|
||||||
ca_private_key_passphrase = GetTestData('intermediate.passphrase')
|
'Generating DRM intermediate certificate for system_id <%d>.', system_id)
|
||||||
|
data_provider = test_data_provider.TestDataProvider(cert_type)
|
||||||
gen_status, ca_certificate = engine.GenerateDrmIntermediateCertificate(
|
gen_status, ca_certificate = engine.GenerateDrmIntermediateCertificate(
|
||||||
system_id, CA_PUBLIC_KEY)
|
system_id, data_provider.ca_public_key)
|
||||||
AssertSuccess(gen_status, 'Failed to generate intermediate certificate.')
|
AssertSuccess(gen_status, 'Failed to generate intermediate certificate.')
|
||||||
|
|
||||||
|
logging.info('Adding DRM intermediate certificate.')
|
||||||
add_ca_status = engine.AddDrmIntermediateCertificate(
|
add_ca_status = engine.AddDrmIntermediateCertificate(
|
||||||
ca_certificate, ca_private_key, ca_private_key_passphrase)
|
ca_certificate, data_provider.ca_private_key,
|
||||||
|
data_provider.ca_private_key_passphrase)
|
||||||
|
|
||||||
if verify_success:
|
if verify_success:
|
||||||
AssertSuccess(add_ca_status, 'Failed to add intermediate certificate.')
|
AssertSuccess(add_ca_status, 'Failed to add intermediate certificate.')
|
||||||
@@ -120,24 +113,57 @@ def AddDrmIntermediateCertificateWithTestData(engine,
|
|||||||
return add_ca_status
|
return add_ca_status
|
||||||
|
|
||||||
|
|
||||||
def NewProvisioningSessionWithTestData(engine, verify_success=False):
|
def GenerateDeviceDrmCertificate(engine, system_id, serial_number,
|
||||||
|
verify_success=False,
|
||||||
|
cert_type=pywrapcertificate_type.kCertTesting):
|
||||||
|
"""Generate a device DRM certificate.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
||||||
|
system_id: Widevine system ID for the type of device
|
||||||
|
serial_number: The serial number for the device DRM certificate.
|
||||||
|
verify_success: whether to verify that resulting status code equals OK
|
||||||
|
cert_type: The type of certificate to use for initializing SDK -
|
||||||
|
{kCertTesting/kCertDevelopment}
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
OK on success, or an appropriate error status code otherwise.
|
||||||
|
"""
|
||||||
|
logging.info(
|
||||||
|
'Generating Device cert for system_id <%d> and serial_number <%s>.',
|
||||||
|
system_id, serial_number)
|
||||||
|
data_provider = test_data_provider.TestDataProvider(cert_type)
|
||||||
|
gen_status, ca_certificate = engine.GenerateDeviceDrmCertificate(
|
||||||
|
system_id, data_provider.device_public_key, serial_number)
|
||||||
|
if verify_success:
|
||||||
|
AssertSuccess(gen_status, 'Failed to generate device DRM certificate.')
|
||||||
|
return ca_certificate
|
||||||
|
|
||||||
|
|
||||||
|
def NewProvisioningSessionWithTestData(
|
||||||
|
engine, verify_success=False,
|
||||||
|
cert_type=pywrapcertificate_type.kCertTesting):
|
||||||
"""Create a provisioning session with sample device public and private keys.
|
"""Create a provisioning session with sample device public and private keys.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
||||||
verify_success: whether to verify that resulting status code equals OK
|
verify_success: whether to verify that resulting status code equals OK
|
||||||
|
cert_type: The type of certificate to use for initializing SDK -
|
||||||
|
{kCertTesting/kCertDevelopment}
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
status: OK on success, or an appropriate error status code otherwise.
|
status: OK on success, or an appropriate error status code otherwise.
|
||||||
new_session: A new provisioning_session.
|
new_session: A new provisioning_session.
|
||||||
"""
|
"""
|
||||||
status, new_session = engine.NewProvisioningSession(DEVICE_PUBLIC_KEY,
|
logging.info('Starting a new provisioning session with'
|
||||||
DEVICE_PRIVATE_KEY)
|
'sample device public and private keys.')
|
||||||
|
data_provider = test_data_provider.TestDataProvider(cert_type)
|
||||||
|
status, new_session = engine.NewProvisioningSession(
|
||||||
|
data_provider.device_public_key, data_provider.device_private_key)
|
||||||
if verify_success:
|
if verify_success:
|
||||||
AssertSuccess(status, 'Failed to create session.')
|
AssertSuccess(status, 'Failed to create session.')
|
||||||
|
|
||||||
return (status, new_session)
|
return status, new_session
|
||||||
|
|
||||||
|
|
||||||
def AssertSuccess(status, message=None):
|
def AssertSuccess(status, message=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user