Source release 17.1.0

This commit is contained in:
John "Juce" Bruce
2022-07-07 17:14:31 -07:00
parent 8c17574083
commit 694cf6fb25
2233 changed files with 272026 additions and 223371 deletions

View File

@@ -0,0 +1,61 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_CMAC_H_
#define WVOEC_UTIL_CMAC_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include <openssl/cmac.h>
namespace wvoec {
namespace util {
class Cmac {
public:
// Creates an AES-128-CMAC or an AES-256-CMAC depending on |key_size|.
// Returns an empty pointer if the key size is not valid.
static std::unique_ptr<Cmac> Create(const uint8_t* key, size_t key_size);
static std::unique_ptr<Cmac> Create(const std::vector<uint8_t>& key);
// Updates the CMAC with more data. This allows for streaming or
// scatter-gather based MAC generation.
// Returns true if the data was updated successfully and false
// if any unexpected errors occur.
bool Update(const uint8_t* data, size_t data_length);
bool Update(const std::vector<uint8_t>& data);
bool Update(uint8_t datum);
// Generates the final MAC and stores it in the |mac| output
// parameter.
// After finalizing, one must reset the Cmac instance before it
// can digest additional information.
bool Finalize(std::vector<uint8_t>* mac);
// Similar to Finalize() except that the output is appended to
// the end of the provided |mac| buffer.
bool FinalizeAppend(std::vector<uint8_t>* mac);
// Clears the underlying CMAC without clearing the key. Resetting
// it to its post-initialization state.
void Reset();
~Cmac();
private:
Cmac() {}
// Assumes |key_size| is a valid AES-128 or AES-256 key.
bool Init(const uint8_t* key, size_t key_size);
CMAC_CTX* ctx_ = nullptr;
bool ready_ = false;
};
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_CMAC_H_

View File

@@ -0,0 +1,139 @@
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_HMAC_H_
#define WVOEC_UTIL_HMAC_H_
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <vector>
#include "OEMCryptoCENCCommon.h"
namespace wvoec {
namespace util {
// Size of an HMAC-SHA-1 signature. Same size as a SHA-1 digest.
static constexpr size_t kHmacSha1SignatureSize = 20;
// Size of an HMAC-SHA-256 signature. Same size as a SHA-256 digest.
static constexpr size_t kHmacSha256SignatureSize = 32;
// == Signature Generate ==
// Generates a HMAC-SHA-1 signature using the provided |key| and
// |message|. Both |key| and |message| must be non-zero length.
// The input/output |signature_length| should initially contain the
// size of the |signature| buffer, and the function will assign
// the final length of the signature.
//
// Return values:
// OEMCrypto_SUCCESS if signature is generated successfully;
// |signature_length| may be updated with the actual
// signature size
// OEMCrypto_ERROR_SHORT_BUFFER if the provided |signature| buffer
// is too small to fit an HMAC-SHA-1 signature;
// |signature_length| is updated with the require size
// OEMCrypto_ERROR_INVALID_CONTEXT if any the parameters are
// incorrect
// OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise
OEMCryptoResult HmacSha1(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length);
OEMCryptoResult HmacSha1(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length);
std::vector<uint8_t> HmacSha1(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message);
// Generates a HMAC-SHA-256 signature using the provided |key| and
// |message|. Both |key| and |message| must be non-zero length.
// The input/output |signature_length| should initially contain the
// size of the |signature| buffer, and the function will assign
// the final length of the signature.
//
// Return values:
// OEMCrypto_SUCCESS if signature is generated successfully;
// |signature_length| may be updated with the actual
// signature size
// OEMCrypto_ERROR_SHORT_BUFFER if the provided |signature| buffer
// is too small to fit an HMAC-SHA-256 signature;
// |signature_length| is updated with the require size
// OEMCrypto_ERROR_INVALID_CONTEXT if any the parameters are
// incorrect
// OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise
OEMCryptoResult HmacSha256(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length);
OEMCryptoResult HmacSha256(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length);
bool HmacSha256(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* signature);
bool HmacSha256(const std::vector<uint8_t>& key, const std::string& message,
std::vector<uint8_t>* signature);
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length);
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message);
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const std::string& message);
// == Signature Verification ==
// Verifies an HMAC-SHA-1 signature using the provided |key| and
// |message| against the provided |signature|.
//
// Return values:
// OEMCrypto_SUCCESS if signature is valid
// OEMCrypto_ERROR_SIGNATURE_FAILURE if signature is invalid
// OEMCrypto_ERROR_INVALID_CONTEXT if any the parameters are
// incorrect
// OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise
OEMCryptoResult HmacSha1Verify(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult HmacSha1Verify(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult HmacSha1Verify(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature);
// Verifies an HMAC-SHA-256 signature using the provided |key| and
// |message| against the provided |signature|.
//
// Return values:
// OEMCrypto_SUCCESS if signature is valid
// OEMCrypto_ERROR_SIGNATURE_FAILURE if signature is invalid
// OEMCrypto_ERROR_INVALID_CONTEXT if any the parameters are
// incorrect
// OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise
OEMCryptoResult HmacSha256Verify(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult HmacSha256Verify(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult HmacSha256Verify(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature);
OEMCryptoResult HmacSha256Verify(const std::vector<uint8_t>& key,
const std::string& message,
const std::vector<uint8_t>& signature);
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_HMAC_H_

View File

@@ -0,0 +1,85 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_DRM_KEY_H_
#define WVOEC_UTIL_DRM_KEY_H_
#include <memory>
#include <string>
#include <vector>
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_ecc_key.h"
#include "oemcrypto_rsa_key.h"
namespace wvoec {
namespace util {
// DRM private key performs all of the operations required by an
// OEMCrypto session's RSA/ECC private key.
class DrmPrivateKey {
public:
// Create an RSA-based DRM key.
static std::unique_ptr<DrmPrivateKey> Create(
std::shared_ptr<RsaPrivateKey>&& rsa_key);
static std::unique_ptr<DrmPrivateKey> Create(
std::unique_ptr<RsaPrivateKey>&& rsa_key);
// Create an ECC-based DRM key.
static std::unique_ptr<DrmPrivateKey> Create(
std::shared_ptr<EccPrivateKey>&& ecc_key);
static std::unique_ptr<DrmPrivateKey> Create(
std::unique_ptr<EccPrivateKey>&& ecc_key);
bool IsRsaKey() const { return static_cast<bool>(rsa_key_); }
bool IsEccKey() const { return static_cast<bool>(ecc_key_); }
// Generates a session key from the key source.
// For RSA keys, |key_source| is an encrypted session key.
// For ECC keys, |key_source| is a ephemeral public key to be
// used in ECDH.
OEMCryptoResult GetSessionKey(const uint8_t* key_source,
size_t key_source_size,
std::vector<uint8_t>* session_key) const;
std::vector<uint8_t> GetSessionKey(
const std::vector<uint8_t>& key_source) const;
// Generates a encryption key from the key source.
// For RSA keys, |key_source| is an encrypted encryption key.
// For ECC keys, this method is not supported.
std::vector<uint8_t> GetEncryptionKey(
const std::vector<uint8_t>& key_source) const;
// Generates a signature for the provided message.
// For RSA keys, the signature is RSASSA-PSS.
// For ECC keys, the signature is ECDSA.
OEMCryptoResult GenerateSignature(const uint8_t* message,
size_t message_length, uint8_t* signature,
size_t* signature_length) const;
std::vector<uint8_t> GenerateSignature(
const std::vector<uint8_t>& message) const;
size_t SignatureSize() const;
// Generates a signature for the provided message.
// For RSA keys, the signature is RSASSA-PKCS1.
// For ECC keys, this is not supported.
OEMCryptoResult GenerateRsaSignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) const;
std::vector<uint8_t> GenerateRsaSignature(
const std::vector<uint8_t>& message) const;
~DrmPrivateKey() {}
private:
DrmPrivateKey() {}
// Only one will be set.
std::shared_ptr<EccPrivateKey> ecc_key_;
std::shared_ptr<RsaPrivateKey> rsa_key_;
};
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_DRM_KEY_H_

View File

@@ -0,0 +1,281 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_ECC_KEY_H_
#define WVOEC_UTIL_ECC_KEY_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include <openssl/ec.h>
#include "OEMCryptoCENCCommon.h"
namespace wvoec {
namespace util {
enum EccCurve {
kEccCurveUnknown = 0,
kEccSecp256r1 = 256,
kEccSecp384r1 = 384,
kEccSecp521r1 = 521
};
// Returns the string representation of the provided curve.
// Intended for logging purposes.
std::string EccCurveToString(EccCurve curve);
class EccPrivateKey;
class EccPublicKey {
public:
// Creates a new public key equivalent of the provided private key.
static std::unique_ptr<EccPublicKey> New(const EccPrivateKey& private_key);
// Loads a serialized EC public key.
// The provided |buffer| must contain a valid ASN.1 DER encoded
// SubjectPublicKey. Only supported curves by this API are those
// enumerated by EccCurve.
//
// buffer: SubjectPublicKeyInfo = {
// algorithm: AlgorithmIdentifier = {
// algorithm: OID = id-ecPublicKey,
// parameters: ECParameters = {
// namedCurve: OID = secp256r1 | secp384r1 | secp521r1
// }
// },
// subjectPublicKey: BIT STRING = ... -- SEC1 encoded ECPoint
// }
//
// Failure will occur if the provided |buffer| does not contain a
// valid SubjectPublicKey, or if the specified curve is not
// supported.
static std::unique_ptr<EccPublicKey> Load(const uint8_t* buffer,
size_t length);
static std::unique_ptr<EccPublicKey> Load(const std::string& buffer);
static std::unique_ptr<EccPublicKey> Load(const std::vector<uint8_t>& buffer);
// Loads a serialized ECC private key, but only converting the public key.
static std::unique_ptr<EccPublicKey> LoadPrivateKeyInfo(const uint8_t* buffer,
size_t length);
static std::unique_ptr<EccPublicKey> LoadPrivateKeyInfo(
const std::string& buffer);
static std::unique_ptr<EccPublicKey> LoadPrivateKeyInfo(
const std::vector<uint8_t>& buffer);
EccCurve curve() const { return curve_; }
const EC_KEY* GetEcKey() const { return key_; }
// Checks if the provided |private_key| is the EC private key of this
// public key.
bool IsMatchingPrivateKey(const EccPrivateKey& private_key) const;
// Serializes the public key into an ASN.1 DER encoded SubjectPublicKey
// representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and OEMCrypto_SUCCESS is returned.
// If the provided |buffer_size| is too small, ERROR_SHORT_BUFFER
// is returned and |buffer_size| is set to the required buffer size.
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> Serialize() const;
// Verifies the |signature| matches the provided |message| by the
// private equivalent of this public key.
// The |signature| should be a valid ASN.1 DER encoded
// ECDSA-Sig-Value.
// This implementation uses ECDSA with the following digest
// algorithms for the supported curve types.
// - SHA-256 / secp256r1
// - SHA-384 / secp384r1 (optional support)
// - SHA-512 / secp521r1 (optional support)
// Returns:
// OEMCrypto_SUCCESS if signature is valid
// OEMCrypto_ERROR_SIGNATURE_FAILURE if the signature is invalid
// Any other result indicates an unexpected error
OEMCryptoResult VerifySignature(const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length) const;
OEMCryptoResult VerifySignature(const std::string& message,
const std::string& signature) const;
OEMCryptoResult VerifySignature(const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature) const;
~EccPublicKey();
EccPublicKey(const EccPublicKey&) = delete;
EccPublicKey(EccPublicKey&&) = delete;
const EccPublicKey& operator=(const EccPublicKey&) = delete;
EccPublicKey& operator=(EccPublicKey&&) = delete;
private:
EccPublicKey() {}
// Initializes the public key object using the provided |buffer|.
// In case of any failure, false is return and the key should be
// discarded.
bool InitFromSubjectPublicKeyInfo(const uint8_t* buffer, size_t length);
bool InitFromPrivateKeyInfo(const uint8_t* buffer, size_t length);
// Initializes the public key object from a private.
bool InitFromPrivateKey(const EccPrivateKey& private_key);
// OpenSSL/BoringSSL implementation of an ECC key.
// As a public key, this will only have key point initialized.
EC_KEY* key_ = nullptr;
EccCurve curve_ = kEccCurveUnknown;
}; // class EccPublicKey
class EccPrivateKey {
public:
// Creates a new, pseudorandom ECC private key belonging to the
// curve specified.
static std::unique_ptr<EccPrivateKey> New(EccCurve curve);
// Loads a serialized ECC private key.
// The provided |buffer| must contain a valid ASN.1 DER encoded
// PrivateKeyInfo containing a valid ECC key description. Only
// supported curves by this API are those enumerated by EccCurve.
//
// PrivateKeyInfo := {
// version: INTEGER = v1(0) | v2(1),
// privateKeyAlgorithm: AlgorithmIdentifier := {
// algorithm: OID = id-ecPublicKey,
// parameters: ECParameters = {
// namedCurve: OID = secp256r1 | secp384r1 | secp521r1
// }
// },
// privateKey: OCTET STRING = ..., -- BER encoding of ECPrivateKey
// }
//
// ECPrivateKey := {
// version: INTEGER = ecPrivateKeyVer1(1),
// privateKey: OCTET STRING = ..., -- I2OSP of private key point
// -- |parameters| are obtained from PrivateKeyInfo
// publicKey: BIT STRING OPTIONAL = ... -- SEC1 encoded ECPoint
// }
// Note: If the public key is not included, then it is computed from
// the private key.
//
// References:
// RFC 5208 - Description of PrivateKeyInfo
// RFC 5480 - Curve OIDs
// RFC 5915 - Description of ECPrivateKey in PrivateKeyInfo
//
// Failure will occur if the provided |buffer| does not contain a
// valid PrivateKeyInfo, key is not an ECC key, the specified
// curve is not supported, or the key is not valid.
static std::unique_ptr<EccPrivateKey> Load(const uint8_t* buffer,
size_t length);
static std::unique_ptr<EccPrivateKey> Load(const std::string& buffer);
static std::unique_ptr<EccPrivateKey> Load(
const std::vector<uint8_t>& buffer);
// Creates a new ECC public key of this private key.
// Equivalent to calling EccPublicKey::New with this private
// key.
std::unique_ptr<EccPublicKey> MakePublicKey() const;
EccCurve curve() const { return curve_; }
const EC_KEY* GetEcKey() const { return key_; }
// Checks if the provided |public_key| is the EC public key of this
// private key.
bool IsMatchingPublicKey(const EccPublicKey& public_key) const;
// Serializes the private key into an ASN.1 DER encoded PrivateKeyInfo
// representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and SUCCESS is returned.
// If the provided |buffer_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is
// set to the required buffer size.
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> Serialize() const;
// Serializes the public component of the private key into an ASN.1
// DER encoded SubjectPublicKey representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and SUCCESS is returned.
// If the provided |buffer_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is
// set to the required buffer size.
OEMCryptoResult SerializeAsPublicKey(uint8_t* buffer,
size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> SerializeAsPublicKey() const;
// Signs the provided |message| and serializes the signature
// point to |signature| as a ASN.1 DER encoded ECDSA-Sig-Value.
// This implementation uses ECDSA with the following digest
// algorithms for the supported curve types.
// - SHA-256 / secp256r1
// - SHA-384 / secp384r1 (optional support)
// - SHA-512 / secp521r1 (optional support)
// On success, |signature_length| is populated with the number of
// bytes written to |signature|, and SUCCESS is returned.
// If the provided |signature_length| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |signature_length|
// is set to the required signature size.
OEMCryptoResult GenerateSignature(const uint8_t* message,
size_t message_length, uint8_t* signature,
size_t* signature_length) const;
// Same as above, except directly returns the serialized signature.
// Returns an empty vector on error.
std::vector<uint8_t> GenerateSignature(
const std::vector<uint8_t>& message) const;
std::vector<uint8_t> GenerateSignature(const std::string& message) const;
// Returns an upper bound for the signature size. May be larger than
// the actual signature generated by GenerateSignature().
size_t SignatureSize() const;
// Derives the OEMCrypto session key used for deriving other keys.
// The provided public key must be of the same curve.
// On success, |session_key_size| is populated with the number of
// bytes written to |session_key|, and OEMCrypto_SUCCESS is returned.
// If the provided |session_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |session_key_size|
// is set to the required buffer size.
OEMCryptoResult DeriveSessionKey(const EccPublicKey& public_key,
uint8_t* session_key,
size_t* session_key_size) const;
// Same as above, except directly returns the derived key.
std::vector<uint8_t> DeriveSessionKey(const EccPublicKey& public_key) const;
// Returns the byte length of the symmetric key that would be derived
// by DeriveSymmetricKey().
size_t SessionKeyLength() const;
~EccPrivateKey();
EccPrivateKey(const EccPrivateKey&) = delete;
EccPrivateKey(EccPrivateKey&&) = delete;
const EccPrivateKey& operator=(const EccPrivateKey&) = delete;
EccPrivateKey& operator=(EccPrivateKey&&) = delete;
private:
EccPrivateKey() {}
// Initializes the public key object using the provided |buffer|.
// In case of any failure, false is return and the key should be
// discarded.
bool InitFromPrivateKeyInfo(const uint8_t* buffer, size_t length);
// Generates a new key based on the provided curve.
bool InitFromCurve(EccCurve curve);
// OpenSSL/BoringSSL implementation of an ECC key.
// The public point of the key will always be present.
EC_KEY* key_ = nullptr;
EccCurve curve_ = kEccCurveUnknown;
}; // class EccPrivateKey
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_ECC_KEY_H_

View File

@@ -0,0 +1,61 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_KEY_DERIVER_H_
#define WVOEC_UTIL_KEY_DERIVER_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "cmac.h"
namespace wvoec {
namespace util {
class KeyDeriver {
public:
// Create a new key deriver using either the session key or the device
// key.
// Returns an empty pointer if the key size is not valid.
static std::unique_ptr<KeyDeriver> Create(const uint8_t* key,
size_t key_size);
static std::unique_ptr<KeyDeriver> Create(const std::vector<uint8_t>& key);
// Derive the mac_key[server] from the provided |mac_key_context|.
bool DeriveServerMacKey(const uint8_t* mac_key_context,
size_t mac_key_context_size,
std::vector<uint8_t>* mac_key_server);
bool DeriveServerMacKey(const std::vector<uint8_t>& mac_key_context,
std::vector<uint8_t>* mac_key_server);
// Derive the mac_key[client] from the provided |mac_key_context|.
bool DeriveClientMacKey(const uint8_t* mac_key_context,
size_t mac_key_context_size,
std::vector<uint8_t>* mac_key_client);
bool DeriveClientMacKey(const std::vector<uint8_t>& mac_key_context,
std::vector<uint8_t>* mac_key_client);
// Derive the enc_key from the provided |enc_key_context|.
bool DeriveEncryptionKey(const uint8_t* enc_key_context,
size_t enc_key_context_size,
std::vector<uint8_t>* enc_key);
bool DeriveEncryptionKey(const std::vector<uint8_t>& enc_key_context,
std::vector<uint8_t>* enc_key);
~KeyDeriver() {}
private:
KeyDeriver() {}
bool Init(const uint8_t* key, size_t key_size);
std::unique_ptr<Cmac> cmac_;
};
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_KEY_DERIVER_H_

View File

@@ -0,0 +1,104 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_OEM_CERT_H_
#define WVOEC_UTIL_OEM_CERT_H_
#include <memory>
#include <vector>
#include "OEMCryptoCENCCommon.h"
namespace wvoec {
namespace util {
class OemPublicCertificate;
// An OEM Certificate is a factory provisioned root of trust
// certificate which consists of a public certificate and its
// matching private key.
// The public certificate must be an ASN.1 DER encoded PKCS #7
// ContentInfo of type signedData (RFC2315). The device's X.509
// certificate must be the first certificate in the chain of
// SignedContent |certificates|.
// The certificates are X.509 Certificate as defined in RFC 5280
// signed by the device manufacturers certificate which is signed
// by Google.
// The OEM Public Cert should only contain the device's certificate
// and the OEM's intermediate certificate.
// The private key storage format is at the discretion of the OEM;
// the reference implementation uses PKCS8 PrivateKeyInfo.
class OemCertificate {
public:
enum KeyType {
kNone = 0,
// Private key is an ASN.1 DER encoded PrivateKeyInfo specifying
// an RSA encryption key.
kRsa = 1
};
// Creates a new OEM Certificate and performs basic validation
// to ensure that the private key and public cert are well-formed.
// The |public_cert| provided is parsed as an X.509 Certificate
// and the public key is verified against the private key.
// The |private_key| is parsed depending on the key type.
// If any error occurs or if the provided data is malformed, an
// empty pointer is returned.
static std::unique_ptr<OemCertificate> Create(const uint8_t* private_key,
size_t private_key_size,
const uint8_t* public_cert,
size_t public_cert_size);
static std::unique_ptr<OemCertificate> Create(
const std::vector<uint8_t>& private_key,
const std::vector<uint8_t>& public_cert);
// Returns the key type of the OEM Public key and private key.
// As of OEMCrypto v16, the only supported key type is RSA.
KeyType key_type() const;
// Returns the private key data. Intended to be used for calls
// to OEMCrypto_LoadOEMPrivateKey().
const std::vector<uint8_t>& GetPrivateKey() const { return private_key_; }
// Returns a copy of the ASN.1 DER encoded PKCS #7 certificate chain.
// If |*public_cert_length| is large enough, the complete
// certificate is copied to the buffer specified by |public_cert|,
// |*public_cert_length| is adjusted to the actual size of the
// certificate data, and SUCCESS is returned.
// If |*public_cert_length| is not large enough, then it is
// set to size of the certificate and ERROR_SHORT_BUFFER is
// returned.
OEMCryptoResult GetPublicCertificate(uint8_t* public_cert,
size_t* public_cert_length) const;
// Returns the certificate directly. Intended to be used for
// testing.
const std::vector<uint8_t>& GetPublicCertificate() const;
// Verifies that the RSA key included in the OEM Cert is valid.
// The existence of an OemCertificate already ensures that the
// OEM Public Certificate and private key data are well-formed.
// This takes the check another step further and ensures that
// the private key matches the public key in the public cert
// (ie, same modulos and public exponent).
OEMCryptoResult IsCertificateValid() const;
~OemCertificate();
OemCertificate(const OemCertificate&) = delete;
OemCertificate(OemCertificate&&) = delete;
const OemCertificate& operator=(const OemCertificate&) = delete;
OemCertificate& operator=(OemCertificate&&) = delete;
private:
OemCertificate();
// Serialized private key matching the OEM certificate.
std::vector<uint8_t> private_key_;
// Serialized OEM Certificate.
std::unique_ptr<OemPublicCertificate> public_cert_;
}; // class OemCertificate
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_OEM_CERT_H_

View File

@@ -0,0 +1,376 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_RSA_KEY_H_
#define WVOEC_UTIL_RSA_KEY_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h"
namespace wvoec {
namespace util {
enum RsaFieldSize {
kRsaFieldUnknown = 0,
kRsa2048Bit = 2048,
kRsa3072Bit = 3084
};
// Identifies the RSA signature algorithm to be used when signing
// messages or verifying message signatures.
// The two standard signing algorithms specified by PKCS1 RSA V2.1
// are RSASSA-PKCS1 and RSASSA-PSS. Each require agreement on a
// set of options. For OEMCrypto, only one set of options are agreed
// upon for each RSA signature scheme. CAST receivers specify a
// special implementation of PKCS1 where the message is already
// digested and encoded when provided.
enum RsaSignatureAlgorithm {
// RSASSA-PSS with default options:
// Hash algorithm: SHA-1
// MGF: MGF1 with SHA-1
// Salt length: 20 bytes
// Trailer field: 0xbc
kRsaPssDefault = 0,
// RSASSA-PKCS1 for CAST receivers.
// Assumes message is already digested & encoded. Max message length
// is 83 bytes.
kRsaPkcs1Cast = 1
};
// Returns the string representation of the provided RSA field size.
// Intended for logging purposes.
std::string RsaFieldSizeToString(RsaFieldSize field_size);
// Compares two OpenSSL/BoringSSL RSA keys to see if their public RSA
// components are matching.
// This function assumes both keys are valid.
// Returns true if they are matching, false otherwise.
bool RsaKeysAreMatchingPair(const RSA* public_key, const RSA* private_key);
class RsaPrivateKey;
class RsaPublicKey {
public:
// Creates a new public key equivalent of the provided private key.
static std::unique_ptr<RsaPublicKey> New(const RsaPrivateKey& private_key);
// Creates an RSA public key from a native OpenSSL/BoringSSL RSA key handle.
// Ownership of the handle is NOT transferred.
static std::unique_ptr<RsaPublicKey> FromSslHandle(
const RSA* rsa_handle, uint32_t allowed_schemes = kSign_RSASSA_PSS);
// Loads a serialized RSA public key.
// The provided |buffer| must contain a valid ASN.1 DER encoded
// SubjectPublicKey. This API will reject any RSA key that is not
// approximately to 2048bits or 3072bits.
//
// buffer: SubjectPublicKeyInfo = {
// algorithm: AlgorithmIdentifier = {
// algorithm: OID = rsaEncryption,
// parameters: NULL = null
// },
// subjectPublicKey: BIT STRING = ... -- ASN.1 DER encoded RSAPublicKey
// }
//
// Failure will occur if the provided |buffer| does not contain a
// valid SubjectPublicKey, or if the specified curve is not
// supported.
static std::unique_ptr<RsaPublicKey> Load(const uint8_t* buffer,
size_t length);
static std::unique_ptr<RsaPublicKey> Load(const std::string& buffer);
static std::unique_ptr<RsaPublicKey> Load(const std::vector<uint8_t>& buffer);
// Loads a serialized RSA private key, but only converting the public key.
static std::unique_ptr<RsaPublicKey> LoadPrivateKeyInfo(const uint8_t* buffer,
size_t length);
static std::unique_ptr<RsaPublicKey> LoadPrivateKeyInfo(
const std::string& buffer);
static std::unique_ptr<RsaPublicKey> LoadPrivateKeyInfo(
const std::vector<uint8_t>& buffer);
RsaFieldSize field_size() const { return field_size_; }
uint32_t allowed_schemes() const { return allowed_schemes_; }
const RSA* GetRsaKey() const { return key_; }
// Checks if the provided |private_key| is the RSA private key of this
// public key.
bool IsMatchingPrivateKey(const RsaPrivateKey& private_key) const;
// Serializes the public key into an ASN.1 DER encoded SubjectPublicKey
// representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and OEMCrypto_SUCCESS is returned.
// If the provided |buffer_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is set
// to the required buffer size.
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> Serialize() const;
// Verifies the |signature| matches the provided |message| by the
// private equivalent of this public key.
// The signature algorithm can be specified via the |algorithm| field.
// See RsaSignatureAlgorithm for details on each algorithm.
//
// Returns:
// OEMCrypto_SUCCESS if signature is valid
// OEMCrypto_ERROR_SIGNATURE_FAILURE if the signature is invalid
// OEMCrypto_ERROR_UNKNOWN_FAILURE if any error occurs
OEMCryptoResult VerifySignature(
const uint8_t* message, size_t message_length, const uint8_t* signature,
size_t signature_length,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
OEMCryptoResult VerifySignature(
const std::string& message, const std::string& signature,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
OEMCryptoResult VerifySignature(
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
// Encrypts the OEMCrypto session key used for deriving other keys.
// On success, |enc_session_key_size| is populated with the number
// of bytes written to |enc_session_key|, and OEMCrypto_SUCCESS is
// returned. If the provided |enc_session_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and
// |enc_session_key_size| is set to the required buffer size.
OEMCryptoResult EncryptSessionKey(const uint8_t* session_key,
size_t session_key_size,
uint8_t* enc_session_key,
size_t* enc_session_key_size) const;
// Same as above, except directly returns the encrypted key.
std::vector<uint8_t> EncryptSessionKey(
const std::vector<uint8_t>& session_key) const;
std::vector<uint8_t> EncryptSessionKey(const std::string& session_key) const;
// Encrypts the OEMCrypto encryption key used for encrypting the
// DRM private key.
// On success, |enc_encryption_key_size| is populated with the
// number of bytes written to |enc_encryption_key|, and
// OEMCrypto_SUCCESS is returned.
// If the provided |enc_encryption_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and
// |enc_encryption_key_size| is set to the required buffer size.
OEMCryptoResult EncryptEncryptionKey(const uint8_t* encryption_key,
size_t encryption_key_size,
uint8_t* enc_encryption_key,
size_t* enc_encryption_key_size) const;
// Same as above, except directly returns the encrypted key.
std::vector<uint8_t> EncryptEncryptionKey(
const std::vector<uint8_t>& encryption_key) const;
std::vector<uint8_t> EncryptEncryptionKey(
const std::string& encryption_key) const;
~RsaPublicKey();
RsaPublicKey(const RsaPublicKey&) = delete;
RsaPublicKey(RsaPublicKey&&) = delete;
const RsaPublicKey& operator=(const RsaPublicKey&) = delete;
RsaPublicKey& operator=(RsaPublicKey&&) = delete;
private:
RsaPublicKey() {}
// Initializes the public key object using the provided |buffer|.
// In case of any failure, false is return and the key should be
// discarded.
bool InitFromSubjectPublicKeyInfo(const uint8_t* buffer, size_t length);
bool InitFromPrivateKeyInfo(const uint8_t* buffer, size_t length);
// Initializes the public key object from a private.
bool InitFromPrivateKey(const RsaPrivateKey& private_key);
// Initializes the public key object from an existing
// OpenSSL/BoringSSL RSA key handle. The RSA key must be
// initialized and |allowed_schemes| must be a valid value.
bool InitFromSslHandle(const RSA* rsa_handle, uint32_t allowed_schemes);
// Signature specialization functions.
OEMCryptoResult VerifySignaturePss(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) const;
OEMCryptoResult VerifySignaturePkcs1Cast(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) const;
// RSAES-OAEP encrypt.
OEMCryptoResult EncryptOaep(const uint8_t* message, size_t message_size,
uint8_t* enc_message,
size_t* enc_message_length) const;
// OpenSSL/BoringSSL implementation of an RSA key.
// Will only include components of an RSA public key.
RSA* key_ = nullptr;
uint32_t allowed_schemes_ = 0;
RsaFieldSize field_size_ = kRsaFieldUnknown;
}; // class RsaPublicKey
class RsaPrivateKey {
public:
// Creates a new, pseudorandom RSA private key.
static std::unique_ptr<RsaPrivateKey> New(RsaFieldSize field_size);
// Loads a serialized RSA private key.
// The provided |buffer| must contain a valid ASN.1 DER encoded
// PrivateKeyInfo (RFC 5208).
//
// buffer: PrivateKeyInfo = {
// version: INTEGER = v1(0),
// privateKeyAlgorithm: OID = rsaEncryption,
// privateKey: OCTET STRING = ...,
// -- BER encoding of RSAPrivateKey (RFC 3447)
// attributes: Attributes = ... -- Optional, not used by OEMCrypto
// }
// Note: If the public key is not included, then it is computed from
// the private.
//
// Failure will occur if the provided |buffer| does not contain a
// valid RSAPrivateKey, or if the specified curve is not supported.
static std::unique_ptr<RsaPrivateKey> Load(const uint8_t* buffer,
size_t length);
static std::unique_ptr<RsaPrivateKey> Load(const std::string& buffer);
static std::unique_ptr<RsaPrivateKey> Load(
const std::vector<uint8_t>& buffer);
// Creates a new RSA public key of this private key.
// Equivalent to calling RsaPublicKey::New with this private
// key.
std::unique_ptr<RsaPublicKey> MakePublicKey() const;
RsaFieldSize field_size() const { return field_size_; }
uint32_t allowed_schemes() const { return allowed_schemes_; }
const RSA* GetRsaKey() const { return key_; }
// Checks if the provided |public_key| is the RSA public key of this
// private key.
bool IsMatchingPublicKey(const RsaPublicKey& public_key) const;
// Serializes the private key into an ASN.1 DER encoded X
// representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and OEMCrypto_SUCCESS is returned.
// If the provided |buffer_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is
// set to the required buffer size.
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> Serialize() const;
// Signs the provided |message| using the RSA signing algorithm
// specified by |algorithm|. See RsaSignatureAlgorithm for
// details on each algorithm.
//
// On success, |signature_length| is populated with the number of
// bytes written to |signature|, and OEMCrypto_SUCCESS is returned.
// If the provided |signature_length| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |signature_length|
// is set to the required signature size.
OEMCryptoResult GenerateSignature(const uint8_t* message,
size_t message_length,
RsaSignatureAlgorithm algorithm,
uint8_t* signature,
size_t* signature_length) const;
// Same as above, except directly returns the serialized signature.
// Returns an empty vector on error.
std::vector<uint8_t> GenerateSignature(
const std::vector<uint8_t>& message,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
std::vector<uint8_t> GenerateSignature(
const std::string& message,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
// Returns an upper bound for the signature size. May be larger than
// the actual signature generated by GenerateSignature().
size_t SignatureSize() const;
// Decrypts the OEMCrypto session key used for deriving other keys.
// On success, |session_key_size| is populated with the number of
// bytes written to |session_key|, and OEMCrypto_SUCCESS is returned.
// If the provided |session_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |session_key_size|
// is set to the required buffer size.
OEMCryptoResult DecryptSessionKey(const uint8_t* enc_session_key,
size_t enc_session_key_size,
uint8_t* session_key,
size_t* session_key_size) const;
// Same as above, except directly returns the decrypted key.
std::vector<uint8_t> DecryptSessionKey(
const std::vector<uint8_t>& enc_session_key) const;
std::vector<uint8_t> DecryptSessionKey(
const std::string& enc_session_key) const;
// Returns the byte length of the symmetric key that would be derived
// by DecryptSessionKey().
size_t SessionKeyLength() const;
// Decrypts the OEMCrypto encryption key used for decrypting DRM
// private key.
// On success, |encryption_key_size| is populated with the number of
// bytes written to |encryption_key|, and OEMCrypto_SUCCESS is
// returned.
// If the provided |encryption_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |encryption_key_size|
// is set to the required buffer size.
OEMCryptoResult DecryptEncryptionKey(const uint8_t* enc_encryption_key,
size_t enc_encryption_key_size,
uint8_t* encryption_key,
size_t* encryption_key_size) const;
// Same as above, except directly returns the decrypted key.
std::vector<uint8_t> DecryptEncryptionKey(
const std::vector<uint8_t>& enc_encryption_key) const;
std::vector<uint8_t> DecryptEncryptionKey(
const std::string& enc_encryption_key) const;
~RsaPrivateKey();
RsaPrivateKey(const RsaPrivateKey&) = delete;
RsaPrivateKey(RsaPrivateKey&&) = delete;
const RsaPrivateKey& operator=(const RsaPrivateKey&) = delete;
RsaPrivateKey& operator=(RsaPrivateKey&&) = delete;
private:
RsaPrivateKey() {}
// Initializes the public key object using the provided |buffer|.
// In case of any failure, false is return and the key should be
// discarded.
bool InitFromPrivateKeyInfo(const uint8_t* buffer, size_t length);
// Generates a new key based on the provided field size.
bool InitFromFieldSize(RsaFieldSize field_size);
// Signature specialization functions.
OEMCryptoResult GenerateSignaturePss(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) const;
OEMCryptoResult GenerateSignaturePkcs1Cast(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) const;
// RSAES-OAEP decrypt.
OEMCryptoResult DecryptOaep(const uint8_t* enc_message,
size_t enc_message_size, uint8_t* message,
size_t expected_message_length) const;
// OpenSSL/BoringSSL implementation of an RSA key.
// Will include all components of an RSA private key.
RSA* key_ = nullptr;
uint32_t allowed_schemes_ = 0;
// Set true if the deserialized key contained an allowed schemes.
bool explicit_schemes_ = false;
RsaFieldSize field_size_ = kRsaFieldUnknown;
}; // class RsaPrivateKey
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_RSA_KEY_H_

View File

@@ -0,0 +1,70 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_SCOPED_OBJECT_H_
#define WVOEC_UTIL_SCOPED_OBJECT_H_
namespace wvoec {
namespace util {
// A generic wrapper around pointer. This allows for automatic
// memory clean up when the ScopedObject variable goes out of scope.
// This is intended to be used with OpenSSL/BoringSSL structs.
template <typename Type, void Destructor(Type*)>
class ScopedObject {
public:
ScopedObject() : ptr_(nullptr) {}
ScopedObject(Type* ptr) : ptr_(ptr) {}
~ScopedObject() {
if (ptr_) {
Destructor(ptr_);
ptr_ = nullptr;
}
}
// Copy construction and assignment are not allowed.
ScopedObject(const ScopedObject& other) = delete;
ScopedObject& operator=(const ScopedObject& other) = delete;
// Move construction and assignment are allowed.
ScopedObject(ScopedObject&& other) : ptr_(other.ptr_) {
other.ptr_ = nullptr;
}
ScopedObject& operator=(ScopedObject&& other) {
if (ptr_) {
Destructor(ptr_);
}
ptr_ = other.ptr_;
other.ptr_ = nullptr;
return *this;
}
explicit operator bool() const { return ptr_ != nullptr; }
Type& operator*() { return *ptr_; }
Type* get() const { return ptr_; }
Type* operator->() const { return ptr_; }
// Releasing the pointer will remove the responsibility of the
// ScopedObject to clean up the pointer.
Type* release() {
Type* temp = ptr_;
ptr_ = nullptr;
return temp;
}
void reset(Type* ptr = nullptr) {
if (ptr_) {
Destructor(ptr_);
}
ptr_ = ptr;
}
private:
Type* ptr_ = nullptr;
};
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_SCOPED_OBJECT_H_

View File

@@ -0,0 +1,22 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Compute CRC32/MPEG2 Checksum. Needed for verification of WV Keybox.
//
#ifndef WVOEC_UTIL_WVCRC32_H_
#define WVOEC_UTIL_WVCRC32_H_
#include <stdint.h>
namespace wvoec {
namespace util {
uint32_t wvcrc32(const uint8_t* p_begin, size_t i_count);
uint32_t wvcrc32Init();
uint32_t wvcrc32Cont(const uint8_t* p_begin, size_t i_count, uint32_t prev_crc);
// Convert to network byte order
uint32_t wvcrc32n(const uint8_t* p_begin, size_t i_count);
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_WVCRC32_H_

View File

@@ -0,0 +1,20 @@
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
# source code may only be used and distributed under the Widevine
# License Agreement.
{
'variables': {
'oemcrypto_dir': '..',
'util_dir': '../../util',
},
'targets': [
{
'target_name': 'oec_ref_util',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'includes': [
'oec_ref_util.gypi',
],
},
],
}

View File

@@ -0,0 +1,33 @@
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
# source code may only be used and distributed under the Widevine
# License Agreement.
{
'variables': {
'privacy_crypto_impl%': 'boringssl',
'boringssl_libcrypto_path%': '../../third_party/boringssl/boringssl.gyp:crypto',
},
'include_dirs': [
'<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/util/include',
'<(util_dir)/include',
],
'direct_dependent_settings': {
'include_dirs': [
'<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/util/include',
],
},
'sources': [
'<(oemcrypto_dir)/util/src/cmac.cpp',
'<(oemcrypto_dir)/util/src/hmac.cpp',
'<(oemcrypto_dir)/util/src/oemcrypto_drm_key.cpp',
'<(oemcrypto_dir)/util/src/oemcrypto_ecc_key.cpp',
'<(oemcrypto_dir)/util/src/oemcrypto_key_deriver.cpp',
'<(oemcrypto_dir)/util/src/oemcrypto_oem_cert.cpp',
'<(oemcrypto_dir)/util/src/oemcrypto_rsa_key.cpp',
'<(oemcrypto_dir)/util/src/wvcrc.cpp',
],
'includes': [
'../../util/libcrypto_dependency.gypi',
],
}

View File

@@ -0,0 +1,27 @@
# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
# source code may only be used and distributed under the Widevine License
# Agreement.
{
'include_dirs': [
'<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/util/include',
'<(oemcrypto_dir)/util/test',
'<(util_dir)/include',
],
'direct_dependent_settings': {
'include_dirs': [
'<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/util/include',
],
},
'sources': [
'<(oemcrypto_dir)/util/test/cmac_unittest.cpp',
'<(oemcrypto_dir)/util/test/hmac_unittest.cpp',
'<(oemcrypto_dir)/util/test/oem_cert_test.cpp',
'<(oemcrypto_dir)/util/test/oemcrypto_ecc_key_unittest.cpp',
'<(oemcrypto_dir)/util/test/oemcrypto_oem_cert_unittest.cpp',
'<(oemcrypto_dir)/util/test/oemcrypto_ref_test_utils.cpp',
'<(oemcrypto_dir)/util/test/oemcrypto_rsa_key_unittest.cpp',
'<(oemcrypto_dir)/util/test/oemcrypto_wvcrc32_unittest.cpp',
],
}

173
oemcrypto/util/src/cmac.cpp Normal file
View File

@@ -0,0 +1,173 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "cmac.h"
#include <openssl/evp.h>
#include "log.h"
#include "scoped_object.h"
namespace wvoec {
namespace util {
namespace {
using ScopedCmacCtx = ScopedObject<CMAC_CTX, CMAC_CTX_free>;
constexpr size_t kAes128KeySize = 16;
constexpr size_t kAes256KeySize = 32;
constexpr size_t kCmacOutputSize = 16;
// Gets the appropriate AES block cipher for the CMAC algortihm
// based on the key size.
// Ownership of the pointer returned by this function is retained by
// the OpenSSL/BoringSSL framework.
const EVP_CIPHER* KeySizeToCipher(size_t key_size) {
switch (key_size) {
case kAes128KeySize:
return EVP_aes_128_cbc();
case kAes256KeySize:
return EVP_aes_256_cbc();
}
LOGE("Unexpected key size: size = %zu", key_size);
return nullptr;
}
} // namespace
// static
std::unique_ptr<Cmac> Cmac::Create(const uint8_t* key, size_t key_size) {
std::unique_ptr<Cmac> cmac;
if (key == nullptr) {
LOGE("CMAC key is null");
return cmac;
}
if (key_size != kAes128KeySize && key_size != kAes256KeySize) {
LOGE("Invalid CMAC key size: size = %zu", key_size);
return cmac;
}
cmac.reset(new Cmac());
if (!cmac->Init(key, key_size)) {
cmac.reset();
}
return cmac;
}
// static
std::unique_ptr<Cmac> Cmac::Create(const std::vector<uint8_t>& key) {
if (key.empty()) {
LOGE("CMAC key is empty");
return std::unique_ptr<Cmac>();
}
return Create(key.data(), key.size());
}
bool Cmac::Init(const uint8_t* key, size_t key_size) {
const EVP_CIPHER* const cipher = KeySizeToCipher(key_size);
if (cipher == nullptr) {
LOGE("Failed to get block cipher for CMAC");
return false;
}
ScopedCmacCtx ctx(CMAC_CTX_new());
if (!ctx) {
LOGE("Failed allocate CMAC CTX");
return false;
}
if (!CMAC_Init(ctx.get(), key, key_size, cipher, nullptr)) {
LOGE("Failed to initialize CMAC CTX");
return false;
}
ctx_ = ctx.release();
ready_ = true;
return true;
}
bool Cmac::Update(const uint8_t* data, size_t data_length) {
if (data == nullptr) {
LOGE("Data is null");
return false;
}
if (data_length == 0) {
return true;
}
if (!ready_) {
LOGE("CMAC must be reset before updating");
return false;
}
if (!CMAC_Update(ctx_, data, data_length)) {
LOGE("Failed to update CMAC CTX");
ready_ = false;
return false;
}
return true;
}
bool Cmac::Update(const std::vector<uint8_t>& data) {
return Update(data.data(), data.size());
}
bool Cmac::Update(uint8_t datum) { return Update(&datum, 1); }
bool Cmac::Finalize(std::vector<uint8_t>* mac) {
if (mac == nullptr) {
LOGE("Output MAC buffer is null");
return false;
}
mac->clear();
return FinalizeAppend(mac);
}
bool Cmac::FinalizeAppend(std::vector<uint8_t>* mac) {
if (mac == nullptr) {
LOGE("Output MAC buffer is null");
return false;
}
if (!ready_) {
LOGE("CMAC must be reset before finalizing");
return false;
}
const size_t end = mac->size();
size_t mac_size = kCmacOutputSize;
mac->resize(end + mac_size);
if (!CMAC_Final(ctx_, &mac->at(end), &mac_size)) {
LOGE("Failed to finalize CMAC CTX");
mac->resize(end);
ready_ = false;
return false;
}
ready_ = false;
return true;
}
#ifdef OPENSSL_IS_BORINGSSL
// BoringSSL allows for resetting a CMAC context explicitly, whereas
// OpenSSL does so by reinitializing using all nulls/zeros. This
// causes segfaults on systems using BoringSSL.
void Cmac::Reset() {
if (!CMAC_Reset(ctx_)) {
LOGE("Failed to reset CMAC CTX");
ready_ = false;
} else {
ready_ = true;
}
}
#else // OpenSSL is OpenSSL
void Cmac::Reset() {
if (!CMAC_Init(ctx_, nullptr, 0, nullptr, nullptr)) {
LOGE("Failed to reset CMAC CTX");
ready_ = false;
} else {
ready_ = true;
}
}
#endif
Cmac::~Cmac() {
if (ctx_ != nullptr) {
CMAC_CTX_free(ctx_);
ctx_ = nullptr;
}
ready_ = false;
}
} // namespace util
} // namespace wvoec

269
oemcrypto/util/src/hmac.cpp Normal file
View File

@@ -0,0 +1,269 @@
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "hmac.h"
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include "log.h"
#include "string_conversions.h"
namespace wvoec {
namespace util {
namespace {
constexpr bool kHmacSha256 = true;
constexpr bool kHmacSha1 = false;
const std::vector<uint8_t> kEmptyVector;
// Assumes all parameters are valid.
inline bool HmacShaInternal(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
uint8_t* signature, bool sha256) {
return HMAC(sha256 ? EVP_sha256() : EVP_sha1(), key,
static_cast<int>(key_length), message, message_length, signature,
nullptr) != nullptr;
}
OEMCryptoResult GenerateSignatureInternal(const uint8_t* key, size_t key_length,
const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length,
bool sha256) {
if (key == nullptr || key_length == 0) {
LOGE("Input |key| is %s", key_length == 0 ? "empty" : "null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (message == nullptr || message_length == 0) {
LOGE("Input |message| is %s", message_length == 0 ? "empty" : "null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (signature_length == nullptr) {
LOGE("Input/output |signature_length| is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (signature == nullptr && *signature_length > 0) {
LOGE("Output |signature| is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const size_t required_signature_size =
sha256 ? kHmacSha256SignatureSize : kHmacSha1SignatureSize;
if (*signature_length < required_signature_size) {
*signature_length = required_signature_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (!HmacShaInternal(key, key_length, message, message_length, signature,
sha256)) {
LOGE("Failed to generate signature");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
*signature_length = required_signature_size;
return OEMCrypto_SUCCESS;
}
bool GenerateSignatureInternal(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
std::vector<uint8_t>* signature, bool sha256) {
if (signature == nullptr) {
LOGE("Output |signature| is null");
return false;
}
size_t signature_length =
sha256 ? kHmacSha256SignatureSize : kHmacSha1SignatureSize;
signature->resize(signature_length);
const OEMCryptoResult res =
GenerateSignatureInternal(key, key_length, message, message_length,
signature->data(), &signature_length, sha256);
if (res != OEMCrypto_SUCCESS) {
signature->clear();
return false;
}
return true;
}
// Assumes signature pointers are valid.
inline bool CompareSignatures(const uint8_t* signature_a,
const uint8_t* signature_b, bool sha256) {
const size_t signature_size =
sha256 ? kHmacSha256SignatureSize : kHmacSha1SignatureSize;
return CRYPTO_memcmp(signature_a, signature_b, signature_size) == 0;
}
OEMCryptoResult VerifySignatureInternal(const uint8_t* key, size_t key_length,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length, bool sha256) {
if (signature == nullptr && signature_length > 0) {
LOGE("Input |signature| is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
size_t expected_signature_length =
sha256 ? kHmacSha256SignatureSize : kHmacSha1SignatureSize;
if (signature_length != expected_signature_length) {
LOGE("Invalid signature length: expected = %zu, actual = %zu",
expected_signature_length, signature_length);
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Allocate for the larger of the two.
uint8_t expected_signature[kHmacSha256SignatureSize];
const OEMCryptoResult res = GenerateSignatureInternal(
key, key_length, message, message_length, expected_signature,
&expected_signature_length, sha256);
if (res != OEMCrypto_SUCCESS) return res;
if (!CompareSignatures(signature, expected_signature, sha256)) {
LOGD("Signatures do not match: type = HMAC-SHA-%s", sha256 ? "256" : "1");
LOGD("provided = %s",
wvutil::HexEncode(signature, signature_length).c_str());
LOGD("expected = %s",
wvutil::HexEncode(expected_signature, expected_signature_length)
.c_str());
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
return OEMCrypto_SUCCESS;
}
} // namespace
OEMCryptoResult HmacSha1(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length) {
return GenerateSignatureInternal(key, key_length, message, message_length,
signature, signature_length, kHmacSha1);
}
OEMCryptoResult HmacSha1(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length) {
return GenerateSignatureInternal(key.data(), key.size(), message,
message_length, signature, signature_length,
kHmacSha1);
}
std::vector<uint8_t> HmacSha1(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message) {
std::vector<uint8_t> signature;
const bool res =
GenerateSignatureInternal(key.data(), key.size(), message.data(),
message.size(), &signature, kHmacSha1);
return res ? signature : kEmptyVector;
}
OEMCryptoResult HmacSha256(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length) {
return GenerateSignatureInternal(key, key_length, message, message_length,
signature, signature_length, kHmacSha256);
}
OEMCryptoResult HmacSha256(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length) {
return GenerateSignatureInternal(key.data(), key.size(), message,
message_length, signature, signature_length,
kHmacSha256);
}
bool HmacSha256(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* signature) {
return GenerateSignatureInternal(key.data(), key.size(), message.data(),
message.size(), signature, kHmacSha256);
}
bool HmacSha256(const std::vector<uint8_t>& key, const std::string& message,
std::vector<uint8_t>* signature) {
return GenerateSignatureInternal(
key.data(), key.size(), reinterpret_cast<const uint8_t*>(message.data()),
message.size(), signature, kHmacSha256);
}
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length) {
std::vector<uint8_t> signature;
const bool res = GenerateSignatureInternal(
key.data(), key.size(), message, message_length, &signature, kHmacSha256);
return res ? signature : kEmptyVector;
}
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message) {
std::vector<uint8_t> signature;
const bool res =
GenerateSignatureInternal(key.data(), key.size(), message.data(),
message.size(), &signature, kHmacSha256);
return res ? signature : kEmptyVector;
}
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const std::string& message) {
std::vector<uint8_t> signature;
const bool res = GenerateSignatureInternal(
key.data(), key.size(), reinterpret_cast<const uint8_t*>(message.data()),
message.size(), &signature, kHmacSha256);
return res ? signature : kEmptyVector;
}
OEMCryptoResult HmacSha1Verify(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length) {
return VerifySignatureInternal(key, key_length, message, message_length,
signature, signature_length, kHmacSha1);
}
OEMCryptoResult HmacSha1Verify(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length) {
return VerifySignatureInternal(key.data(), key.size(), message,
message_length, signature, signature_length,
kHmacSha1);
}
OEMCryptoResult HmacSha1Verify(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature) {
return VerifySignatureInternal(key.data(), key.size(), message.data(),
message.size(), signature.data(),
signature.size(), kHmacSha1);
}
OEMCryptoResult HmacSha256Verify(const uint8_t* key, size_t key_length,
const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length) {
return VerifySignatureInternal(key, key_length, message, message_length,
signature, signature_length, kHmacSha256);
}
OEMCryptoResult HmacSha256Verify(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length) {
return VerifySignatureInternal(key.data(), key.size(), message,
message_length, signature, signature_length,
kHmacSha256);
}
OEMCryptoResult HmacSha256Verify(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature) {
return VerifySignatureInternal(key.data(), key.size(), message.data(),
message.size(), signature.data(),
signature.size(), kHmacSha256);
}
OEMCryptoResult HmacSha256Verify(const std::vector<uint8_t>& key,
const std::string& message,
const std::vector<uint8_t>& signature) {
return VerifySignatureInternal(
key.data(), key.size(), reinterpret_cast<const uint8_t*>(message.data()),
message.size(), signature.data(), signature.size(), kHmacSha256);
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,186 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "oemcrypto_drm_key.h"
#include <utility>
#include "OEMCryptoCENC.h"
#include "log.h"
namespace wvoec {
namespace util {
// static
std::unique_ptr<DrmPrivateKey> DrmPrivateKey::Create(
std::shared_ptr<RsaPrivateKey>&& rsa_key) {
if (!rsa_key) {
LOGE("No RSA key provided");
return std::unique_ptr<DrmPrivateKey>();
}
std::unique_ptr<DrmPrivateKey> drm_key(new DrmPrivateKey());
drm_key->rsa_key_ = std::move(rsa_key);
return drm_key;
}
// static
std::unique_ptr<DrmPrivateKey> DrmPrivateKey::Create(
std::unique_ptr<RsaPrivateKey>&& rsa_key) {
if (!rsa_key) {
LOGE("No RSA key provided");
return std::unique_ptr<DrmPrivateKey>();
}
std::unique_ptr<DrmPrivateKey> drm_key(new DrmPrivateKey());
drm_key->rsa_key_ = std::move(rsa_key);
return drm_key;
}
// static
std::unique_ptr<DrmPrivateKey> DrmPrivateKey::Create(
std::shared_ptr<EccPrivateKey>&& ecc_key) {
if (!ecc_key) {
LOGE("No ECC key provided");
return std::unique_ptr<DrmPrivateKey>();
}
std::unique_ptr<DrmPrivateKey> drm_key(new DrmPrivateKey());
drm_key->ecc_key_ = std::move(ecc_key);
return drm_key;
}
// static
std::unique_ptr<DrmPrivateKey> DrmPrivateKey::Create(
std::unique_ptr<EccPrivateKey>&& ecc_key) {
if (!ecc_key) {
LOGE("No ECC key provided");
return std::unique_ptr<DrmPrivateKey>();
}
std::unique_ptr<DrmPrivateKey> drm_key(new DrmPrivateKey());
drm_key->ecc_key_ = std::move(ecc_key);
return drm_key;
}
OEMCryptoResult DrmPrivateKey::GetSessionKey(
const uint8_t* key_source, size_t key_source_size,
std::vector<uint8_t>* session_key) const {
if (session_key == nullptr) {
LOGE("Output session key is null");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// RSA -> Decrypt session key.
if (rsa_key_) {
if (!(rsa_key_->allowed_schemes() & kSign_RSASSA_PSS)) {
LOGE("RSA key cannot be used for session key decryption");
return OEMCrypto_ERROR_INVALID_KEY;
}
size_t session_key_size = rsa_key_->SessionKeyLength();
session_key->resize(session_key_size);
const OEMCryptoResult res = rsa_key_->DecryptSessionKey(
key_source, key_source_size, session_key->data(), &session_key_size);
if (res != OEMCrypto_SUCCESS) {
session_key->clear();
return res;
}
session_key->resize(session_key_size);
return OEMCrypto_SUCCESS;
}
// ECC -> ECDH.
// Step 1: Parse |key_source| as ECC key.
std::unique_ptr<EccPublicKey> ephemeral_ecc_key =
EccPublicKey::Load(key_source, key_source_size);
if (!ephemeral_ecc_key) {
LOGE("Failed to load server's ephemeral ECC key");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 2: Derive session key.
size_t session_key_size = ecc_key_->SessionKeyLength();
session_key->resize(session_key_size);
const OEMCryptoResult res = ecc_key_->DeriveSessionKey(
*ephemeral_ecc_key, session_key->data(), &session_key_size);
if (res != OEMCrypto_SUCCESS) {
session_key->clear();
return res;
}
session_key->resize(session_key_size);
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> DrmPrivateKey::GetSessionKey(
const std::vector<uint8_t>& key_source) const {
// RSA -> Decrypt session key.
if (rsa_key_) {
if (!(rsa_key_->allowed_schemes() & kSign_RSASSA_PSS)) {
LOGE("RSA key cannot be used for session key decryption");
return std::vector<uint8_t>();
}
return rsa_key_->DecryptSessionKey(key_source);
}
// ECC -> ECDH.
// Step 1: Parse |key_source| as ECC key.
std::unique_ptr<EccPublicKey> ephemeral_ecc_key =
EccPublicKey::Load(key_source);
if (!ephemeral_ecc_key) {
LOGE("Failed to load server's ephemeral ECC key");
return std::vector<uint8_t>();
}
// Step 2: Derive session key.
return ecc_key_->DeriveSessionKey(*ephemeral_ecc_key);
}
std::vector<uint8_t> DrmPrivateKey::GetEncryptionKey(
const std::vector<uint8_t>& key_source) const {
if (!rsa_key_) {
LOGE("Only RSA DRM keys can derive an encryption key");
return std::vector<uint8_t>();
}
return rsa_key_->DecryptEncryptionKey(key_source);
}
OEMCryptoResult DrmPrivateKey::GenerateSignature(
const uint8_t* message, size_t message_length, uint8_t* signature,
size_t* signature_length) const {
if (rsa_key_) {
return rsa_key_->GenerateSignature(message, message_length, kRsaPssDefault,
signature, signature_length);
}
return ecc_key_->GenerateSignature(message, message_length, signature,
signature_length);
}
std::vector<uint8_t> DrmPrivateKey::GenerateSignature(
const std::vector<uint8_t>& message) const {
if (rsa_key_) {
return rsa_key_->GenerateSignature(message, kRsaPssDefault);
}
return ecc_key_->GenerateSignature(message);
}
size_t DrmPrivateKey::SignatureSize() const {
if (rsa_key_) {
return rsa_key_->SignatureSize();
}
return ecc_key_->SignatureSize();
}
OEMCryptoResult DrmPrivateKey::GenerateRsaSignature(
const uint8_t* message, size_t message_length, uint8_t* signature,
size_t* signature_length) const {
if (!rsa_key_) {
LOGE("Only RSA DRM keys can generate PKCS1 signatures");
return OEMCrypto_ERROR_INVALID_KEY;
}
return rsa_key_->GenerateSignature(message, message_length, kRsaPkcs1Cast,
signature, signature_length);
}
std::vector<uint8_t> DrmPrivateKey::GenerateRsaSignature(
const std::vector<uint8_t>& message) const {
if (!rsa_key_) {
LOGE("Only RSA DRM keys can generate PKCS1 signatures");
return std::vector<uint8_t>();
}
return rsa_key_->GenerateSignature(message, kRsaPkcs1Cast);
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,931 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "oemcrypto_ecc_key.h"
#include <assert.h>
#include <string.h>
#include <mutex>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
#include "log.h"
#include "scoped_object.h"
namespace wvoec {
namespace util {
namespace {
// Estimated max size (in bytes) of a serialized ECC key (public or
// private). These values are based on rough calculations for
// secp521r1 (largest of the supported curves) and should be slightly
// larger needed.
constexpr size_t kPrivateKeySize = 250;
constexpr size_t kPublicKeySize = 164;
// 256 bit key, intended to be used with CMAC-AES-256.
constexpr size_t kEccSessionKeySize = 32;
using ScopedBigNum = ScopedObject<BIGNUM, BN_free>;
using ScopedBigNumCtx = ScopedObject<BN_CTX, BN_CTX_free>;
using ScopedBio = ScopedObject<BIO, BIO_vfree>;
using ScopedEcKey = ScopedObject<EC_KEY, EC_KEY_free>;
using ScopedEvpMdCtx = ScopedObject<EVP_MD_CTX, EVP_MD_CTX_free>;
using ScopedEvpPkey = ScopedObject<EVP_PKEY, EVP_PKEY_free>;
using ScopedPrivateKeyInfo =
ScopedObject<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
using ScopedSigPoint = ScopedObject<ECDSA_SIG, ECDSA_SIG_free>;
const EC_GROUP* GetEcGroup(EccCurve curve) {
// Creating a named EC_GROUP is an expensive operation, and they
// are always used in a manner which does not transfer ownership.
// Maintaining a process-wide set of supported EC groups reduces
// the overhead of group operations.
static std::mutex group_mutex;
static EC_GROUP* group_256 = nullptr;
static EC_GROUP* group_384 = nullptr;
static EC_GROUP* group_521 = nullptr;
std::lock_guard<std::mutex> group_lock(group_mutex);
switch (curve) {
case kEccSecp256r1: {
if (group_256 == nullptr) {
LOGD("Creating secp256r1 group");
// The curve secp256r1 was originally named prime256v1
// in the X9.62 specification.
group_256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
assert(group_256 != nullptr);
}
return group_256;
}
case kEccSecp384r1: {
if (group_384 == nullptr) {
LOGD("Creating secp384r1 group");
group_384 = EC_GROUP_new_by_curve_name(NID_secp384r1);
assert(group_384 != nullptr);
}
return group_384;
}
case kEccSecp521r1: {
if (group_521 == nullptr) {
LOGD("Creating secp521r1 group");
group_521 = EC_GROUP_new_by_curve_name(NID_secp521r1);
assert(group_521 != nullptr);
}
return group_521;
}
default:
LOGE("Cannot get EC group for unknown curve: curve = %d",
static_cast<int>(curve));
return nullptr;
}
}
// Determines which of the supported ECC curves the provided |key|
// belongs to.
//
// This is intended to be used on keys that have been deserialized
// from an ASN.1 structure which may have contained a key which is
// supported by OpenSSL/BoringSSL but not necessarily by OEMCrypto.
//
// If the key group is unknown to OEMCrypto or if an error occurs,
// kEccCurveUnknown is returned.
EccCurve GetCurveFromKeyGroup(const EC_KEY* key) {
ScopedBigNumCtx ctx(BN_CTX_new());
if (!ctx) {
LOGE("Failed to allocate BN ctx");
return kEccCurveUnknown;
}
const EC_GROUP* group = EC_KEY_get0_group(key);
if (group == nullptr) {
LOGE("Provided key does not have a group");
return kEccCurveUnknown;
}
int rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp256r1), ctx.get());
if (rc == 0) {
return kEccSecp256r1;
}
if (rc == -1) {
LOGE("Error occurred while checking against secp256r1");
return kEccCurveUnknown;
}
rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp384r1), ctx.get());
if (rc == 0) {
return kEccSecp384r1;
}
if (rc == -1) {
LOGE("Error occurred while checking against secp384r1");
return kEccCurveUnknown;
}
rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp521r1), ctx.get());
if (rc == 0) {
return kEccSecp521r1;
}
if (rc == -1) {
LOGE("Error occurred while checking against secp521r1");
return kEccCurveUnknown;
}
LOGW("Unsupported curve group");
return kEccCurveUnknown;
}
// Compares the public EC points of both keys to see if they are the
// equal.
// Both |public_key| and |private_key| must be of the same group.
bool IsMatchingKeyPair(const EC_KEY* public_key, const EC_KEY* private_key) {
ScopedBigNumCtx ctx(BN_CTX_new());
if (!ctx) {
LOGE("Failed to allocate BN ctx");
return false;
}
// Returns: 1 if not equal, 0 if equal, -1 if error.
const int res = EC_POINT_cmp(EC_KEY_get0_group(public_key),
EC_KEY_get0_public_key(public_key),
EC_KEY_get0_public_key(private_key), ctx.get());
if (res == -1) {
LOGE("Error occurred comparing keys");
}
return res == 0;
}
// Performs a SHA2 digest on the provided |message| and outputs the
// computed hash to |digest|.
// The digest algorithm used depends on which curve is used.
// - secp256r1 -> SHA-256
// - secp384r1 -> SHA-384
// - secp521r1 -> SHA-512
// This function assumes that all parameters are valid.
// Returns true on success, false otherwise.
bool DigestMessage(EccCurve curve, const uint8_t* message, size_t message_size,
std::vector<uint8_t>* digest) {
const EVP_MD* md_engine = nullptr;
switch (curve) {
case kEccSecp256r1: {
md_engine = EVP_sha256();
break;
}
case kEccSecp384r1: {
md_engine = EVP_sha384();
break;
}
case kEccSecp521r1: {
md_engine = EVP_sha512();
break;
}
case kEccCurveUnknown:
// This case is to suppress compiler warnings. It will never
// occur.
break;
}
if (md_engine == nullptr) {
LOGE("Failed to get MD engine: curve = %d", static_cast<int>(curve));
return false;
}
ScopedEvpMdCtx md_ctx(EVP_MD_CTX_new());
if (!md_ctx) {
LOGE("Failed to create MD CTX");
return false;
}
if (!EVP_DigestInit_ex(md_ctx.get(), md_engine, nullptr)) {
LOGE("Failed to init MD CTX");
return false;
}
if (message_size > 0 &&
!EVP_DigestUpdate(md_ctx.get(), message, message_size)) {
LOGE("Failed to update");
return false;
}
digest->resize(EVP_MD_CTX_size(md_ctx.get()), 0);
const int res = EVP_DigestFinal_ex(md_ctx.get(), digest->data(), nullptr);
if (!res) {
LOGE("Failed to finalize");
return false;
}
return true;
}
// This KDF function is defined by OEMCrypto ECC specification.
// Function signature is based on the |kdf| parameter of
// ECDH_compute_key(). This function assumes that all pointer
// parameters are not null.
void* WidevineEccKdf(const void* secret, size_t secret_length, void* key,
size_t* key_size) {
if (*key_size < kEccSessionKeySize) {
LOGE("Output buffer is too small: required = %zu, size = %zu",
kEccSessionKeySize, *key_size);
return nullptr;
}
std::vector<uint8_t> digest;
if (!DigestMessage(kEccSecp256r1 /* SHA-256 */,
reinterpret_cast<const uint8_t*>(secret), secret_length,
&digest)) {
LOGE("Cannot derive key: Failed to hash secret");
return nullptr;
}
if (digest.size() != kEccSessionKeySize) {
LOGE("Unexpected hash size: actual = %zu, expected = %zu", digest.size(),
kEccSessionKeySize);
return nullptr;
}
*key_size = kEccSessionKeySize;
memcpy(key, digest.data(), *key_size);
return key;
}
void OpensslFreeU8(uint8_t* ptr) { OPENSSL_free(ptr); }
// Internal ECC public key serialization.
OEMCryptoResult SerializeEccPublicKey(const EC_KEY* key, uint8_t* buffer,
size_t* buffer_size) {
if (buffer_size == nullptr) {
LOGE("Output buffer size is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (buffer == nullptr && *buffer_size > 0) {
LOGE("Output buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* der_key_raw = nullptr;
const int der_res = i2d_EC_PUBKEY(
const_cast<EC_KEY*>(key) /* Does not get modified */, &der_key_raw);
if (der_res < 0) {
LOGE("Public key serialization failed");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
ScopedObject<uint8_t, OpensslFreeU8> der_key(der_key_raw);
der_key_raw = nullptr;
if (!der_key) {
LOGE("Encoded key is unexpectedly null");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (der_res == 0) {
LOGE("Unexpected DER encoded size");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t required_size = static_cast<size_t>(der_res);
if (buffer == nullptr || *buffer_size < required_size) {
*buffer_size = required_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(buffer, der_key.get(), required_size);
*buffer_size = required_size;
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> SerializeEccPublicKey(const EC_KEY* key) {
size_t key_size = kPublicKeySize;
std::vector<uint8_t> key_data(key_size, 0);
const OEMCryptoResult res =
SerializeEccPublicKey(key, key_data.data(), &key_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to serialize public key: result = %d", static_cast<int>(res));
key_data.clear();
} else {
key_data.resize(key_size);
}
return key_data;
}
bool ParseEccPrivateKeyInfo(const uint8_t* buffer, size_t length,
ScopedEcKey* key, EccCurve* curve) {
if (length == 0) {
LOGE("Public key is too small: length = %zu", length);
return false;
}
ScopedBio bio(BIO_new_mem_buf(buffer, static_cast<int>(length)));
if (!bio) {
LOGE("Failed to allocate BIO buffer");
return false;
}
// Step 1: Deserializes PKCS8 PrivateKeyInfo containing an ECC key.
ScopedPrivateKeyInfo priv_info(
d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr));
if (!priv_info) {
LOGE("Failed to parse private key");
return false;
}
// Step 2: Convert to EC_KEY.
ScopedEvpPkey pkey(EVP_PKCS82PKEY(priv_info.get()));
if (!pkey) {
LOGE("Failed to convert PKCS8 to EVP");
return false;
}
const int key_type = EVP_PKEY_base_id(pkey.get());
if (key_type != EVP_PKEY_EC) {
LOGE("Decoded private key is not ECC");
return false;
}
key->reset(EVP_PKEY_get1_EC_KEY(pkey.get()));
if (!*key) {
LOGE("Failed to get ECC key");
return false;
}
// Step 3: Verify key parameters and curve family.
const int check = EC_KEY_check_key(key->get());
if (check == 0) {
LOGE("ECC key parameters are invalid");
return false;
} else if (check == -1) {
LOGE("Failed to check ECC key");
return false;
}
*curve = GetCurveFromKeyGroup(key->get());
if (*curve == kEccCurveUnknown) {
LOGE("Failed to determine key group");
return false;
}
// Required flags for IETF compliance.
EC_KEY_set_asn1_flag(key->get(), OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key->get(), POINT_CONVERSION_UNCOMPRESSED);
return true;
}
} // namespace
std::string EccCurveToString(EccCurve curve) {
switch (curve) {
case kEccSecp256r1:
return "secp256r1";
case kEccSecp384r1:
return "secp384r1";
case kEccSecp521r1:
return "secp521r1";
case kEccCurveUnknown:
return "Unknown";
}
return "Unknown(" + std::to_string(static_cast<int>(curve)) + ")";
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::New(
const EccPrivateKey& private_key) {
std::unique_ptr<EccPublicKey> key(new EccPublicKey());
if (!key->InitFromPrivateKey(private_key)) {
LOGE("Failed to initialize public key from private key");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::Load(const uint8_t* buffer,
size_t length) {
if (buffer == nullptr) {
LOGE("Provided public key buffer is null");
return nullptr;
}
if (length == 0) {
LOGE("Provided public key buffer is zero length");
return nullptr;
}
std::unique_ptr<EccPublicKey> key(new EccPublicKey());
if (!key->InitFromSubjectPublicKeyInfo(buffer, length)) {
LOGE("Failed to initialize public key from SubjectPublicKeyInfo");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::Load(const std::string& buffer) {
if (buffer.empty()) {
LOGE("Provided public key buffer is empty");
return std::unique_ptr<EccPublicKey>();
}
return Load(reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::Load(
const std::vector<uint8_t>& buffer) {
if (buffer.empty()) {
LOGE("Provided public key buffer is empty");
return std::unique_ptr<EccPublicKey>();
}
return Load(buffer.data(), buffer.size());
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::LoadPrivateKeyInfo(
const uint8_t* buffer, size_t length) {
if (buffer == nullptr) {
LOGE("Provided public key buffer is null");
return nullptr;
}
if (length == 0) {
LOGE("Provided public key buffer is zero length");
return nullptr;
}
std::unique_ptr<EccPublicKey> key(new EccPublicKey());
if (!key->InitFromPrivateKeyInfo(buffer, length)) {
LOGE("Failed to initialize public key from PrivateKeyInfo");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::LoadPrivateKeyInfo(
const std::string& buffer) {
if (buffer.empty()) {
LOGE("Provided public key buffer is empty");
return std::unique_ptr<EccPublicKey>();
}
return LoadPrivateKeyInfo(reinterpret_cast<const uint8_t*>(buffer.data()),
buffer.size());
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::LoadPrivateKeyInfo(
const std::vector<uint8_t>& buffer) {
if (buffer.empty()) {
LOGE("Provided public key buffer is empty");
return std::unique_ptr<EccPublicKey>();
}
return LoadPrivateKeyInfo(buffer.data(), buffer.size());
}
bool EccPublicKey::IsMatchingPrivateKey(
const EccPrivateKey& private_key) const {
if (private_key.curve() != curve_) {
return false;
}
return IsMatchingKeyPair(GetEcKey(), private_key.GetEcKey());
}
OEMCryptoResult EccPublicKey::Serialize(uint8_t* buffer,
size_t* buffer_size) const {
return SerializeEccPublicKey(key_, buffer, buffer_size);
}
std::vector<uint8_t> EccPublicKey::Serialize() const {
return SerializeEccPublicKey(key_);
}
OEMCryptoResult EccPublicKey::VerifySignature(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) const {
if (signature == nullptr || signature_length == 0) {
LOGE("Signature is missing");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (message == nullptr && message_length > 0) {
LOGE("Bad message data");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Step 1: Parse signature.
const uint8_t* tp = signature;
ScopedSigPoint sig_point(d2i_ECDSA_SIG(nullptr, &tp, signature_length));
if (!sig_point) {
LOGE("Failed to parse signature");
// Most likely an invalid signature than an OpenSSL error.
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Step 2: Hash message
std::vector<uint8_t> digest;
if (!DigestMessage(curve_, message, message_length, &digest)) {
LOGE("Failed to digest message");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 3: Verify signature
const int res = ECDSA_do_verify(
digest.data(), static_cast<int>(digest.size()), sig_point.get(), key_);
if (res == -1) {
LOGE("Error occurred checking signature");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (res == 0) {
LOGD("Signature did not match");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult EccPublicKey::VerifySignature(
const std::string& message, const std::string& signature) const {
if (signature.empty()) {
LOGE("Signature should not be empty");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return VerifySignature(
reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<const uint8_t*>(signature.data()), signature.size());
}
OEMCryptoResult EccPublicKey::VerifySignature(
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature) const {
if (signature.empty()) {
LOGE("Signature should not be empty");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return VerifySignature(message.data(), message.size(), signature.data(),
signature.size());
}
EccPublicKey::~EccPublicKey() {
if (key_ != nullptr) {
EC_KEY_free(key_);
key_ = nullptr;
}
curve_ = kEccCurveUnknown;
}
bool EccPublicKey::InitFromSubjectPublicKeyInfo(const uint8_t* buffer,
size_t length) {
// Deserialize SubjectPublicKeyInfo
const uint8_t* tp = buffer;
ScopedEcKey key(d2i_EC_PUBKEY(nullptr, &tp, length));
if (!key) {
LOGE("Failed to parse ECC key");
return false;
}
// Verify key parameters and curve family.
const int check = EC_KEY_check_key(key.get());
if (check == 0) {
LOGE("ECC key parameters are invalid");
return false;
} else if (check == -1) {
LOGE("Failed to check ECC key");
return false;
}
curve_ = GetCurveFromKeyGroup(key.get());
if (curve_ == kEccCurveUnknown) {
LOGE("Failed to determine key group");
return false;
}
// Required flags for IETF compliance.
EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED);
key_ = key.release();
return true;
}
bool EccPublicKey::InitFromPrivateKeyInfo(const uint8_t* buffer,
size_t length) {
ScopedEcKey private_key;
if (!ParseEccPrivateKeyInfo(buffer, length, &private_key, &curve_)) {
return false;
}
// TODO(sigquit): Strip private information.
key_ = private_key.release();
return true;
}
bool EccPublicKey::InitFromPrivateKey(const EccPrivateKey& private_key) {
ScopedEcKey key(EC_KEY_new());
if (!key) {
LOGE("Failed to allocate key");
return false;
}
if (!EC_KEY_set_group(key.get(), EC_KEY_get0_group(private_key.GetEcKey()))) {
LOGE("Failed to set group");
return false;
}
if (!EC_KEY_set_public_key(key.get(),
EC_KEY_get0_public_key(private_key.GetEcKey()))) {
LOGE("Failed to set public point");
return false;
}
curve_ = private_key.curve();
// Required flags for IETF compliance.
EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED);
key_ = key.release();
return true;
}
// static
std::unique_ptr<EccPrivateKey> EccPrivateKey::New(EccCurve curve) {
std::unique_ptr<EccPrivateKey> key(new EccPrivateKey());
if (!key->InitFromCurve(curve)) {
LOGE("Failed to initialize private key from curve");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPrivateKey> EccPrivateKey::Load(const uint8_t* buffer,
size_t length) {
if (buffer == nullptr) {
LOGE("Provided private key buffer is null");
return nullptr;
}
if (length == 0) {
LOGE("Provided private key buffer is zero length");
return nullptr;
}
std::unique_ptr<EccPrivateKey> key(new EccPrivateKey());
if (!key->InitFromPrivateKeyInfo(buffer, length)) {
LOGE("Failed to initialize private key from PrivateKeyInfo");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPrivateKey> EccPrivateKey::Load(const std::string& buffer) {
if (buffer.empty()) {
LOGE("Provided private key buffer is empty");
return std::unique_ptr<EccPrivateKey>();
}
return Load(reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
}
// static
std::unique_ptr<EccPrivateKey> EccPrivateKey::Load(
const std::vector<uint8_t>& buffer) {
if (buffer.empty()) {
LOGE("Provided private key buffer is empty");
return std::unique_ptr<EccPrivateKey>();
}
return Load(buffer.data(), buffer.size());
}
std::unique_ptr<EccPublicKey> EccPrivateKey::MakePublicKey() const {
return EccPublicKey::New(*this);
}
bool EccPrivateKey::IsMatchingPublicKey(const EccPublicKey& public_key) const {
if (public_key.curve() != curve_) {
return false;
}
return IsMatchingKeyPair(public_key.GetEcKey(), GetEcKey());
}
OEMCryptoResult EccPrivateKey::Serialize(uint8_t* buffer,
size_t* buffer_size) const {
if (buffer_size == nullptr) {
LOGE("Output buffer size is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (buffer == nullptr && *buffer_size > 0) {
LOGE("Output buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Step 1: Convert EC_KEY key to EVP.
ScopedEvpPkey pkey(EVP_PKEY_new());
if (!pkey) {
LOGE("Failed to allocate EVP");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!EVP_PKEY_set1_EC_KEY(pkey.get(), key_)) {
LOGE("Failed to set EVP ECC key");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 2: Convert ECC EVP to PKCS8 format.
ScopedPrivateKeyInfo priv_info(EVP_PKEY2PKCS8(pkey.get()));
if (!priv_info) {
LOGE("Failed to convert ECC key to PKCS8 info");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 3: Serialize PKCS8 to DER encoding.
ScopedBio bio(BIO_new(BIO_s_mem()));
if (!bio) {
LOGE("Failed to allocate IO buffer for ECC key");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!i2d_PKCS8_PRIV_KEY_INFO_bio(bio.get(), priv_info.get())) {
LOGE("Failed to serialize ECC key");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 4: Determine key size and copy.
char* key_ptr = nullptr;
const long key_size = BIO_get_mem_data(bio.get(), &key_ptr);
if (key_size < 0) {
LOGE("Failed to get ECC key size");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (key_ptr == nullptr) {
LOGE("Encoded key is unexpectedly null");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t required_size = static_cast<size_t>(key_size);
if (*buffer_size < required_size) {
*buffer_size = required_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*buffer_size = required_size;
memcpy(buffer, key_ptr, required_size);
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> EccPrivateKey::Serialize() const {
size_t key_size = kPrivateKeySize;
std::vector<uint8_t> key_data(key_size, 0);
const OEMCryptoResult res = Serialize(key_data.data(), &key_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to serialize private key: result = %d", static_cast<int>(res));
key_data.clear();
} else {
key_data.resize(key_size);
}
return key_data;
}
OEMCryptoResult EccPrivateKey::SerializeAsPublicKey(uint8_t* buffer,
size_t* buffer_size) const {
return SerializeEccPublicKey(key_, buffer, buffer_size);
}
std::vector<uint8_t> EccPrivateKey::SerializeAsPublicKey() const {
return SerializeEccPublicKey(key_);
}
OEMCryptoResult EccPrivateKey::GenerateSignature(
const uint8_t* message, size_t message_length, uint8_t* signature,
size_t* signature_length) const {
if (signature_length == nullptr) {
LOGE("Output signature size is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (signature == nullptr && *signature_length > 0) {
LOGE("Output signature is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (message == nullptr && message_length > 0) {
LOGE("Invalid message data");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const size_t expected_signature_length = ECDSA_size(key_);
if (*signature_length < expected_signature_length) {
*signature_length = expected_signature_length;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
// Step 1: Hash message.
std::vector<uint8_t> digest;
if (!DigestMessage(curve_, message, message_length, &digest)) {
LOGE("Failed to digest message");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 2: Generate signature point.
ScopedSigPoint sig_point(
ECDSA_do_sign(digest.data(), static_cast<int>(digest.size()), key_));
if (!sig_point) {
LOGE("Failed to perform ECDSA");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 3: Serialize
std::vector<uint8_t> temp(expected_signature_length);
uint8_t* sig_ptr = temp.data();
const int res = i2d_ECDSA_SIG(sig_point.get(), &sig_ptr);
if (res <= 0) {
LOGE("Failed to serialize signature");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t required_size = static_cast<size_t>(res);
if (signature == nullptr || *signature_length < required_size) {
*signature_length = required_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(signature, temp.data(), required_size);
*signature_length = required_size;
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> EccPrivateKey::GenerateSignature(
const std::string& message) const {
size_t signature_size = SignatureSize();
std::vector<uint8_t> signature(signature_size, 0);
const OEMCryptoResult res =
GenerateSignature(reinterpret_cast<const uint8_t*>(message.data()),
message.size(), signature.data(), &signature_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to generate signature: result = %d", static_cast<int>(res));
signature.clear();
} else {
signature.resize(signature_size);
}
return signature;
}
std::vector<uint8_t> EccPrivateKey::GenerateSignature(
const std::vector<uint8_t>& message) const {
size_t signature_size = SignatureSize();
std::vector<uint8_t> signature(signature_size, 0);
const OEMCryptoResult res = GenerateSignature(
message.data(), message.size(), signature.data(), &signature_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to generate signature: result = %d", static_cast<int>(res));
signature.clear();
} else {
signature.resize(signature_size);
}
return signature;
}
size_t EccPrivateKey::SignatureSize() const { return ECDSA_size(key_); }
OEMCryptoResult EccPrivateKey::DeriveSessionKey(
const EccPublicKey& public_key, uint8_t* session_key,
size_t* session_key_size) const {
if (public_key.curve() != curve_) {
LOGE("Incompatible ECC keys: public = %s, private = %s",
EccCurveToString(public_key.curve()).c_str(),
EccCurveToString(curve_).c_str());
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (session_key_size == nullptr) {
LOGE("Output session key size buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (session_key == nullptr && *session_key_size > 0) {
LOGE("Output session key buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (*session_key_size < kEccSessionKeySize) {
*session_key_size = kEccSessionKeySize;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
const int res = ECDH_compute_key(
session_key, kEccSessionKeySize,
EC_KEY_get0_public_key(public_key.GetEcKey()), key_, WidevineEccKdf);
if (res < 0) {
LOGE("ECDH error occurred");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (static_cast<size_t>(res) != kEccSessionKeySize) {
LOGE("Unexpected key size: size = %d", res);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
*session_key_size = kEccSessionKeySize;
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> EccPrivateKey::DeriveSessionKey(
const EccPublicKey& public_key) const {
size_t session_key_size = kEccSessionKeySize;
std::vector<uint8_t> session_key(session_key_size, 0);
const OEMCryptoResult res =
DeriveSessionKey(public_key, session_key.data(), &session_key_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to derive session key: result = %d", static_cast<int>(res));
session_key.clear();
} else {
session_key.resize(session_key_size);
}
return session_key;
}
size_t EccPrivateKey::SessionKeyLength() const { return kEccSessionKeySize; }
EccPrivateKey::~EccPrivateKey() {
if (key_ != nullptr) {
EC_KEY_free(key_);
key_ = nullptr;
}
curve_ = kEccCurveUnknown;
}
bool EccPrivateKey::InitFromPrivateKeyInfo(const uint8_t* buffer,
size_t length) {
ScopedEcKey key;
if (!ParseEccPrivateKeyInfo(buffer, length, &key, &curve_)) return false;
key_ = key.release();
return true;
}
bool EccPrivateKey::InitFromCurve(EccCurve curve) {
const EC_GROUP* group = GetEcGroup(curve);
if (group == nullptr) {
LOGE("Failed to get ECC group");
return false;
}
ScopedEcKey key(EC_KEY_new());
if (!key) {
LOGE("Failed to allocate key");
return false;
}
if (!EC_KEY_set_group(key.get(), group)) {
LOGE("Failed to set group");
return false;
}
// Generate random key.
if (!EC_KEY_generate_key(key.get())) {
LOGE("Failed to generate random key");
return false;
}
curve_ = curve;
// Required flags for IETF compliance.
EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED);
key_ = key.release();
return true;
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,154 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "oemcrypto_key_deriver.h"
#include "log.h"
namespace wvoec {
namespace util {
namespace {
bool Derive128KeyAppend(Cmac* cmac, uint8_t counter, const uint8_t* ctx,
size_t ctx_size, std::vector<uint8_t>* derived_key) {
cmac->Reset();
if (!cmac->Update(counter)) {
return false;
}
if (!cmac->Update(ctx, ctx_size)) {
return false;
}
if (!cmac->FinalizeAppend(derived_key)) {
return false;
}
return true;
}
bool Derive128Key(Cmac* cmac, uint8_t counter, const uint8_t* ctx,
size_t ctx_size, std::vector<uint8_t>* derived_key) {
derived_key->clear();
return Derive128KeyAppend(cmac, counter, ctx, ctx_size, derived_key);
}
bool Derive256Key(Cmac* cmac, uint8_t counter_base, const uint8_t* ctx,
size_t ctx_size, std::vector<uint8_t>* derived_key) {
derived_key->clear();
if (!Derive128KeyAppend(cmac, counter_base, ctx, ctx_size, derived_key)) {
return false;
}
return Derive128KeyAppend(cmac, counter_base + 1, ctx, ctx_size, derived_key);
}
} // namespace
// static
std::unique_ptr<KeyDeriver> KeyDeriver::Create(const uint8_t* key,
size_t key_size) {
if (key == nullptr) {
LOGE("Key deriver key is null");
return std::unique_ptr<KeyDeriver>();
}
std::unique_ptr<KeyDeriver> key_deriver(new KeyDeriver());
if (!key_deriver->Init(key, key_size)) {
key_deriver.reset();
}
return key_deriver;
}
// static
std::unique_ptr<KeyDeriver> KeyDeriver::Create(
const std::vector<uint8_t>& key) {
if (key.empty()) {
LOGE("Key deriver key is empty");
return std::unique_ptr<KeyDeriver>();
}
return Create(key.data(), key.size());
}
bool KeyDeriver::Init(const uint8_t* key, size_t key_size) {
cmac_ = Cmac::Create(key, key_size);
if (!cmac_) {
LOGE("Failed to create CMAC for key deriver");
return false;
}
return true;
}
bool KeyDeriver::DeriveServerMacKey(const uint8_t* mac_key_context,
size_t mac_key_context_size,
std::vector<uint8_t>* mac_key_server) {
if (mac_key_context == nullptr) {
LOGE("Server MAC key context is null");
return false;
}
if (mac_key_server == nullptr) {
LOGE("Output server MAC key buffer is null");
return false;
}
return Derive256Key(cmac_.get(), 0x01, mac_key_context, mac_key_context_size,
mac_key_server);
}
bool KeyDeriver::DeriveServerMacKey(const std::vector<uint8_t>& mac_key_context,
std::vector<uint8_t>* mac_key_server) {
if (mac_key_context.empty()) {
LOGE("Server MAC key context is empty");
return false;
}
return DeriveServerMacKey(mac_key_context.data(), mac_key_context.size(),
mac_key_server);
}
bool KeyDeriver::DeriveClientMacKey(const uint8_t* mac_key_context,
size_t mac_key_context_size,
std::vector<uint8_t>* mac_key_client) {
if (mac_key_context == nullptr) {
LOGE("Client MAC key context is null");
return false;
}
if (mac_key_client == nullptr) {
LOGE("Output client MAC key buffer is null");
return false;
}
return Derive256Key(cmac_.get(), 0x03, mac_key_context, mac_key_context_size,
mac_key_client);
}
bool KeyDeriver::DeriveClientMacKey(const std::vector<uint8_t>& mac_key_context,
std::vector<uint8_t>* mac_key_client) {
if (mac_key_context.empty()) {
LOGE("Client MAC key context is empty");
return false;
}
return DeriveClientMacKey(mac_key_context.data(), mac_key_context.size(),
mac_key_client);
}
bool KeyDeriver::DeriveEncryptionKey(const uint8_t* enc_key_context,
size_t enc_key_context_size,
std::vector<uint8_t>* enc_key) {
if (enc_key_context == nullptr) {
LOGE("Encryption key context is null");
return false;
}
if (enc_key == nullptr) {
LOGE("Output encryption key buffer is null");
return false;
}
return Derive128Key(cmac_.get(), 0x01, enc_key_context, enc_key_context_size,
enc_key);
}
bool KeyDeriver::DeriveEncryptionKey(
const std::vector<uint8_t>& enc_key_context,
std::vector<uint8_t>* enc_key) {
if (enc_key_context.empty()) {
LOGE("Encryption key context is empty");
return false;
}
return DeriveEncryptionKey(enc_key_context.data(), enc_key_context.size(),
enc_key);
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,234 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "oemcrypto_oem_cert.h"
#include <string.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include "log.h"
#include "oemcrypto_rsa_key.h"
#include "scoped_object.h"
namespace wvoec {
namespace util {
namespace {
using ScopedCertificate = ScopedObject<X509, X509_free>;
using ScopedEvpKey = ScopedObject<EVP_PKEY, EVP_PKEY_free>;
using ScopedPkcs7 = ScopedObject<PKCS7, PKCS7_free>;
constexpr size_t kExpectedCertCount = 2; // Leaf and intermediate.
constexpr int kDeviceCertIndex = 0;
// Checks that the |public_key| from an X.509 certificate is the
// correct public key of the serialized |private_key_data|.
OEMCryptoResult VerifyRsaKey(const RSA* public_key,
const std::vector<uint8_t>& private_key_data) {
if (public_key == nullptr) {
LOGE("RSA key is null");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
std::unique_ptr<RsaPrivateKey> private_key =
RsaPrivateKey::Load(private_key_data);
if (!private_key) {
LOGE("Failed to parse provided RSA private key");
return OEMCrypto_ERROR_INVALID_KEY;
}
if (!RsaKeysAreMatchingPair(public_key, private_key->GetRsaKey())) {
LOGE("OEM certificate keys do not match");
return OEMCrypto_ERROR_INVALID_KEY;
}
return OEMCrypto_SUCCESS;
}
} // namespace
// This utility class encapsulates the minimum functionality of an
// OEM Public Certificate required to verify a device's OEM Public
// Certificate.
class OemPublicCertificate {
public:
// Loads a PKCS #7 signedData message with certificate chain.
// Minimum validation is performed. Only checks that the
// device's public key is of a known type (RSA).
static std::unique_ptr<OemPublicCertificate> Load(const uint8_t* public_cert,
size_t public_cert_size) {
std::unique_ptr<OemPublicCertificate> oem_public_cert;
if (public_cert == nullptr) {
LOGE("Public cert buffer is null");
return oem_public_cert;
}
if (public_cert_size == 0) {
LOGE("Public cert buffer is empty");
return oem_public_cert;
}
oem_public_cert.reset(new OemPublicCertificate());
if (!oem_public_cert->InitFromBuffer(public_cert, public_cert_size)) {
oem_public_cert.reset();
}
return oem_public_cert;
}
OemCertificate::KeyType key_type() const { return key_type_; }
const std::vector<uint8_t>& cert_data() const { return cert_data_; }
const RSA* GetPublicRsaKey() const {
return EVP_PKEY_get0_RSA(device_public_key_.get());
}
~OemPublicCertificate() = default;
OemPublicCertificate(const OemPublicCertificate&) = delete;
OemPublicCertificate(OemPublicCertificate&&) = delete;
const OemPublicCertificate& operator=(const OemPublicCertificate&) = delete;
OemPublicCertificate& operator=(OemPublicCertificate&&) = delete;
private:
OemPublicCertificate() {}
bool InitFromBuffer(const uint8_t* public_cert, size_t public_cert_size) {
// Step 1: Parse the PKCS7 certificate chain as signedData.
const uint8_t* public_cert_ptr = public_cert;
pkcs7_.reset(d2i_PKCS7(nullptr, &public_cert_ptr, public_cert_size));
if (!pkcs7_) {
LOGE("Failed to parse PKCS#7 certificate chain");
return false;
}
if (!PKCS7_type_is_signed(pkcs7_.get())) {
LOGE("OEM Public Certificate is not PKCS#7 signed data");
return false;
}
PKCS7_SIGNED* signed_data = pkcs7_->d.sign;
// Step 2: Get the leaf certificate.
const size_t cert_count =
static_cast<size_t>(sk_X509_num(signed_data->cert));
if (cert_count != kExpectedCertCount) {
LOGE("Unexpected number of certificates: expected = %zu, actual = %zu",
kExpectedCertCount, cert_count);
return false;
}
X509* leaf_cert = sk_X509_value(signed_data->cert, kDeviceCertIndex);
// Step 3a: Get the device's public key.
device_public_key_.reset(X509_get_pubkey(leaf_cert));
if (!device_public_key_) {
LOGE("Device X.509 certificate is missing a public key");
return false;
}
// Step 3b: Check key type.
if (EVP_PKEY_get0_RSA(device_public_key_.get()) == nullptr) {
LOGE("Device public key is not RSA");
return false;
}
key_type_ = OemCertificate::kRsa;
cert_data_.assign(public_cert, public_cert + public_cert_size);
return true;
}
OemCertificate::KeyType key_type_ = OemCertificate::kNone;
// OpenSSL/BoringSSL's implementation of PKCS7 objects.
ScopedPkcs7 pkcs7_;
ScopedEvpKey device_public_key_;
std::vector<uint8_t> cert_data_;
};
// ===== ===== ===== OEM Certificate ===== ===== =====
// static
std::unique_ptr<OemCertificate> OemCertificate::Create(
const uint8_t* private_key_data, size_t private_key_size,
const uint8_t* public_cert_data, size_t public_cert_size) {
std::unique_ptr<OemCertificate> oem_cert;
// Step 1: Verify public cert is well-formed.
std::unique_ptr<OemPublicCertificate> oem_public_cert =
OemPublicCertificate::Load(public_cert_data, public_cert_size);
if (!oem_public_cert) {
LOGE("Invalid OEM Public Certificate");
return oem_cert;
}
// Step 2: Verify private key is well-formed.
switch (oem_public_cert->key_type()) {
case kRsa: {
std::unique_ptr<RsaPrivateKey> oem_private_key =
RsaPrivateKey::Load(private_key_data, private_key_size);
if (!oem_private_key) {
LOGE("Invalid OEM Private Key");
return oem_cert;
}
} break;
case kNone: // Suppress compiler warnings.
return oem_cert;
}
// Step 3: Copy over data.
oem_cert.reset(new OemCertificate());
oem_cert->private_key_.assign(private_key_data,
private_key_data + private_key_size);
oem_cert->public_cert_ = std::move(oem_public_cert);
return oem_cert;
}
// static
std::unique_ptr<OemCertificate> OemCertificate::Create(
const std::vector<uint8_t>& private_key,
const std::vector<uint8_t>& public_cert) {
if (private_key.empty()) {
LOGE("Private key buffer is empty");
return std::unique_ptr<OemCertificate>();
}
if (public_cert.empty()) {
LOGE("Public cert buffer is empty");
return std::unique_ptr<OemCertificate>();
}
return Create(private_key.data(), private_key.size(), public_cert.data(),
public_cert.size());
}
OemCertificate::KeyType OemCertificate::key_type() const {
return public_cert_->key_type();
}
OEMCryptoResult OemCertificate::GetPublicCertificate(
uint8_t* public_cert, size_t* public_cert_length) const {
if (public_cert_length == nullptr) {
LOGE("Output |public_cert_length| is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (public_cert == nullptr && *public_cert_length > 0) {
LOGE("Output |public_cert| is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const std::vector<uint8_t>& cert_data = public_cert_->cert_data();
if (*public_cert_length < cert_data.size()) {
*public_cert_length = cert_data.size();
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*public_cert_length = cert_data.size();
memcpy(public_cert, cert_data.data(), cert_data.size());
return OEMCrypto_SUCCESS;
}
const std::vector<uint8_t>& OemCertificate::GetPublicCertificate() const {
return public_cert_->cert_data();
}
OEMCryptoResult OemCertificate::IsCertificateValid() const {
switch (key_type()) {
case kRsa:
return VerifyRsaKey(public_cert_->GetPublicRsaKey(), private_key_);
case kNone: // Suppress compiler warnings.
break;
}
LOGE("Unexpected error key type: type = %d", static_cast<int>(key_type()));
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Constructor and destructor do not perform anything special, but
// must be declared within a scope which defines OemPublicCertificate.
OemCertificate::OemCertificate() {}
OemCertificate::~OemCertificate() {}
} // namespace util
} // namespace wvoec

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Compute CRC32/MPEG2 Checksum. Needed for verification of WV Keybox.
//
#include "platform.h"
#include "wvcrc32.h"
namespace wvoec {
namespace util {
#define INIT_CRC32 0xffffffff
uint32_t wvrunningcrc32(const uint8_t* p_begin, size_t i_count,
uint32_t i_crc) {
constexpr uint32_t CRC32[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
/* Calculate the CRC */
while (i_count > 0) {
i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin)];
p_begin++;
i_count--;
}
return(i_crc);
}
uint32_t wvcrc32(const uint8_t* p_begin, size_t i_count) {
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}
uint32_t wvcrc32Init() {
return INIT_CRC32;
}
uint32_t wvcrc32Cont(const uint8_t* p_begin, size_t i_count,
uint32_t prev_crc) {
return(wvrunningcrc32(p_begin, i_count, prev_crc));
}
uint32_t wvcrc32n(const uint8_t* p_begin, size_t i_count) {
return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,129 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "cmac.h"
namespace wvoec {
namespace util {
namespace {
// Test vectors are from NIST Special Publication 800-38B for
// CMAC-AES-128 and CMAC-AES-256. The same data chunks are used
// for both tests.
const uint8_t kDataChunk1[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
const uint8_t kDataChunk2[] = {0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11};
const uint8_t kDataChunk3[] = {0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10};
const uint8_t kKey128[16] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
const uint8_t kKey256[32] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4};
} // namespace
TEST(OEMCryptoCmacTest, BadInit) {
// If the parameters to the Create() function are invalid, the
// Cmac instance is not created.
std::unique_ptr<Cmac> cmac = Cmac::Create(nullptr, sizeof(kKey128));
EXPECT_FALSE(cmac);
cmac = Cmac::Create(nullptr, sizeof(kKey256));
EXPECT_FALSE(cmac);
cmac = Cmac::Create(kKey128, 0);
EXPECT_FALSE(cmac);
cmac = Cmac::Create(kKey256, (sizeof(kKey128) + sizeof(kKey256)) / 2);
EXPECT_FALSE(cmac);
}
TEST(OEMCryptoCmacTest, CmacAes128) {
std::unique_ptr<Cmac> cmac = Cmac::Create(kKey128, sizeof(kKey128));
ASSERT_TRUE(cmac);
std::vector<uint8_t> digest;
ASSERT_TRUE(cmac->Finalize(&digest));
const std::vector<uint8_t> kExpectedEmptyDigest = {
0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46};
EXPECT_EQ(kExpectedEmptyDigest, digest);
cmac->Reset();
ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1)));
ASSERT_TRUE(cmac->Finalize(&digest));
const std::vector<uint8_t> kExpectedDigest1 = {
0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c};
EXPECT_EQ(kExpectedDigest1, digest);
cmac->Reset();
ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1)));
ASSERT_TRUE(cmac->Update(kDataChunk2, sizeof(kDataChunk2)));
ASSERT_TRUE(cmac->Finalize(&digest));
const std::vector<uint8_t> kExpectedDigest2 = {
0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27};
EXPECT_EQ(kExpectedDigest2, digest);
cmac->Reset();
ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1)));
for (size_t i = 0; i < sizeof(kDataChunk2); i++) {
ASSERT_TRUE(cmac->Update(kDataChunk2[i])) << " i = " << i;
}
ASSERT_TRUE(cmac->Update(kDataChunk3, sizeof(kDataChunk3)));
ASSERT_TRUE(cmac->Finalize(&digest));
const std::vector<uint8_t> kExpectedDigest3 = {
0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe};
EXPECT_EQ(kExpectedDigest3, digest);
}
TEST(OEMCryptoCmacTest, CmacAes256) {
std::unique_ptr<Cmac> cmac = Cmac::Create(kKey256, sizeof(kKey256));
ASSERT_TRUE(cmac);
std::vector<uint8_t> digest;
ASSERT_TRUE(cmac->Finalize(&digest));
const std::vector<uint8_t> kExpectedEmptyDigest = {
0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e,
0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83};
EXPECT_EQ(kExpectedEmptyDigest, digest);
cmac->Reset();
ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1)));
ASSERT_TRUE(cmac->Finalize(&digest));
const std::vector<uint8_t> kExpectedDigest1 = {
0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82,
0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c};
EXPECT_EQ(kExpectedDigest1, digest);
cmac->Reset();
ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1)));
ASSERT_TRUE(cmac->Update(kDataChunk2, sizeof(kDataChunk2)));
ASSERT_TRUE(cmac->Finalize(&digest));
const std::vector<uint8_t> kExpectedDigest2 = {
0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2,
0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6};
EXPECT_EQ(kExpectedDigest2, digest);
cmac->Reset();
ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1)));
for (size_t i = 0; i < sizeof(kDataChunk2); i++) {
ASSERT_TRUE(cmac->Update(kDataChunk2[i])) << " i = " << i;
}
ASSERT_TRUE(cmac->Update(kDataChunk3, sizeof(kDataChunk3)));
ASSERT_TRUE(cmac->Finalize(&digest));
const std::vector<uint8_t> kExpectedDigest3 = {
0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5,
0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10};
EXPECT_EQ(kExpectedDigest3, digest);
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,597 @@
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include <ostream>
#include <gtest/gtest.h>
#include "hmac.h"
#include "string_conversions.h"
namespace wvoec {
namespace util {
namespace {
struct HmacTestVector {
std::vector<uint8_t> key;
std::vector<uint8_t> message;
std::vector<uint8_t> signature;
std::vector<uint8_t> signature_sha1;
};
void PrintTo(const HmacTestVector& v, std::ostream* os) {
constexpr size_t kMaxSize = 32;
*os << "{";
if (v.key.size() > kMaxSize) {
std::vector<uint8_t> short_short(v.key.begin(), v.key.begin() + kMaxSize);
*os << "key = " << wvutil::b2a_hex(short_short);
*os << "... (size = " << std::to_string(v.key.size()) << "), ";
} else {
*os << "key = " << wvutil::b2a_hex(v.key) << ", ";
}
if (v.message.size() > kMaxSize) {
std::vector<uint8_t> short_message(v.message.begin(),
v.message.begin() + kMaxSize);
*os << "message = " << wvutil::b2a_hex(short_message);
*os << "... (size = " << std::to_string(v.message.size()) << "), ";
} else {
*os << "message = " << wvutil::b2a_hex(v.message) << ", ";
}
*os << "signature = " << wvutil::b2a_hex(v.signature) << ", ";
*os << "signature_sha1 = " << wvutil::b2a_hex(v.signature_sha1) << "}";
}
std::vector<uint8_t> FromString(const std::string& s) {
return std::vector<uint8_t>(s.begin(), s.end());
}
// Test vectors come from RFC4231 Section 4 (test case 5 is omitted).
const HmacTestVector kHmacTestVectorList[] = {
{/* key = */ wvutil::a2b_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
/* message = */ FromString("Hi There"),
/* signature = */
wvutil::a2b_hex(
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"),
/* signature_sha1 = */
wvutil::a2b_hex("b617318655057264e28bc0b6fb378c8ef146be00")},
{/* key = */ FromString("Jefe"),
/* message = */ FromString("what do ya want for nothing?"),
/* signature = */
wvutil::a2b_hex(
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"),
/* signature_sha1 = */
wvutil::a2b_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")},
{/* key = */ std::vector<uint8_t>(20, 0xaa),
/* message = */ std::vector<uint8_t>(50, 0xdd),
/* signature = */
wvutil::a2b_hex(
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"),
/* signature_sha1 = */
wvutil::a2b_hex("125d7342b9ac11cd91a39af48aa17b4f63f175d3")},
{/* key = */ wvutil::a2b_hex(
"0102030405060708090a0b0c0d0e0f10111213141516171819"),
/* message = */ std::vector<uint8_t>(50, 0xcd),
/* signature = */
wvutil::a2b_hex(
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"),
/* signature_sha1 = */
wvutil::a2b_hex("4c9007f4026250c6bc8414f9bf50c86c2d7235da")},
{/* key = */ std::vector<uint8_t>(131, 0xaa),
/* message = */
FromString("Test Using Larger Than Block-Size Key - Hash Key First"),
/* signature = */
wvutil::a2b_hex(
"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"),
/* signature_sha1 = */
wvutil::a2b_hex("90d0dace1c1bdc957339307803160335bde6df2b")},
{/* key = */ std::vector<uint8_t>(131, 0xaa),
/* message = */
FromString(
"This is a test using a larger than block-size key and a larger "
"than block-size data. The key needs to be hashed before being "
"used by the HMAC algorithm."),
/* signature = */
wvutil::a2b_hex(
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"),
/* signature_sha1 = */
wvutil::a2b_hex("217e44bb08b6e06a2d6c30f3cb9f537f97c63356")}};
const std::vector<uint8_t> kEmptyVector;
const std::string kEmptyString;
} // namespace
TEST(OEMCryptoHmacApiTest, GenerateSignatureSha1_InvalidParameters) {
const std::vector<uint8_t> key = kHmacTestVectorList[0].key;
const std::vector<uint8_t> message = kHmacTestVectorList[0].message;
// Pointers only.
size_t signature_length = kHmacSha256SignatureSize;
std::vector<uint8_t> signature(signature_length);
OEMCryptoResult result =
HmacSha1(nullptr, key.size(), message.data(), message.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = nullptr";
result = HmacSha1(key.data(), 0, message.data(), message.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key_length = 0";
result = HmacSha1(key.data(), key.size(), nullptr, message.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = nullptr";
result = HmacSha1(key.data(), key.size(), message.data(), 0, signature.data(),
&signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message_length = 0";
result = HmacSha1(key.data(), key.size(), message.data(), message.size(),
nullptr, &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "signature = nullptr";
result = HmacSha1(key.data(), key.size(), message.data(), message.size(),
signature.data(), nullptr);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT)
<< "signature_length = nullptr";
// Vector key.
result = HmacSha1(kEmptyVector, message.data(), message.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = <empty>";
result = HmacSha1(key, nullptr, message.size(), signature.data(),
&signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = nullptr";
result =
HmacSha1(key, message.data(), 0, signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message_length = 0";
result =
HmacSha1(key, message.data(), message.size(), nullptr, &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "signature = nullptr";
result =
HmacSha1(key, message.data(), message.size(), signature.data(), nullptr);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT)
<< "signature_length = nullptr";
// Vector message, vector output.
signature = HmacSha1(kEmptyVector, message);
EXPECT_TRUE(signature.empty()) << "key = <empty>";
signature = HmacSha1(key, kEmptyVector);
EXPECT_TRUE(signature.empty()) << "message = <empty>";
}
TEST(OEMCryptoHmacApiTest, GenerateSignature_InvalidParameters) {
const std::vector<uint8_t> key = kHmacTestVectorList[0].key;
const std::vector<uint8_t> message = kHmacTestVectorList[0].message;
// Pointers only.
size_t signature_length = kHmacSha256SignatureSize;
std::vector<uint8_t> signature(signature_length);
OEMCryptoResult result =
HmacSha256(nullptr, key.size(), message.data(), message.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = nullptr";
result = HmacSha256(key.data(), 0, message.data(), message.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key_length = 0";
result = HmacSha256(key.data(), key.size(), nullptr, message.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = nullptr";
result = HmacSha256(key.data(), key.size(), message.data(), 0,
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message_length = 0";
result = HmacSha256(key.data(), key.size(), message.data(), message.size(),
nullptr, &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "signature = nullptr";
result = HmacSha256(key.data(), key.size(), message.data(), message.size(),
signature.data(), nullptr);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT)
<< "signature_length = nullptr";
// Vector key.
result = HmacSha256(kEmptyVector, message.data(), message.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = <empty>";
result = HmacSha256(key, nullptr, message.size(), signature.data(),
&signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = nullptr";
result =
HmacSha256(key, message.data(), 0, signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message_length = 0";
result = HmacSha256(key, message.data(), message.size(), nullptr,
&signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "signature = nullptr";
result = HmacSha256(key, message.data(), message.size(), signature.data(),
nullptr);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT)
<< "signature_length = nullptr";
// Vector message, vector output signature parameter.
signature.clear();
EXPECT_FALSE(HmacSha256(kEmptyVector, message, &signature))
<< "key = <empty>";
EXPECT_FALSE(HmacSha256(key, kEmptyVector, &signature))
<< "message = <empty>";
EXPECT_FALSE(HmacSha256(key, message, nullptr)) << "signature = nullptr";
// String message, vector output signature parameter.
const std::string message_str(message.begin(), message.end());
EXPECT_FALSE(HmacSha256(kEmptyVector, message_str, &signature))
<< "key = <empty>";
EXPECT_FALSE(HmacSha256(key, kEmptyString, &signature))
<< "message = <empty>";
EXPECT_FALSE(HmacSha256(key, message_str, nullptr)) << "signature = nullptr";
// Pointer message, vector output.
signature = HmacSha256(kEmptyVector, message.data(), message.size());
EXPECT_TRUE(signature.empty()) << "key = <empty>";
signature = HmacSha256(key, nullptr, message.size());
EXPECT_TRUE(signature.empty()) << "message = nullptr";
signature = HmacSha256(key, message.data(), 0);
EXPECT_TRUE(signature.empty()) << "message_length = 0";
// Vector message, vector output.
signature = HmacSha256(kEmptyVector, message);
EXPECT_TRUE(signature.empty()) << "key = <empty>";
signature = HmacSha256(key, kEmptyVector);
EXPECT_TRUE(signature.empty()) << "message = <empty>";
// String message, vector output.
signature = HmacSha256(kEmptyVector, message_str);
EXPECT_TRUE(signature.empty()) << "key = <empty>";
signature = HmacSha256(key, kEmptyString);
EXPECT_TRUE(signature.empty()) << "message = <empty>";
}
TEST(OEMCryptoHmacApiTest, VerifySignatureSha1_InvalidParameters) {
const std::vector<uint8_t> key = kHmacTestVectorList[0].key;
const std::vector<uint8_t> message = kHmacTestVectorList[0].message;
const std::vector<uint8_t> signature = kHmacTestVectorList[0].signature_sha1;
// Pointers only.
OEMCryptoResult result =
HmacSha1Verify(nullptr, key.size(), message.data(), message.size(),
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = nullptr";
result = HmacSha1Verify(key.data(), 0, message.data(), message.size(),
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key_length = 0";
result = HmacSha1Verify(key.data(), key.size(), nullptr, message.size(),
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = nullptr";
result = HmacSha1Verify(key.data(), key.size(), message.data(), 0,
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message_length = 0";
result = HmacSha1Verify(key.data(), key.size(), message.data(),
message.size(), nullptr, signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "signature = nullptr";
result = HmacSha1Verify(key.data(), key.size(), message.data(),
message.size(), signature.data(), 0);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE)
<< "signature_length = 0";
// Vector key, pointer others.
result = HmacSha1Verify(kEmptyVector, message.data(), message.size(),
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = <empty>";
result = HmacSha1Verify(key, nullptr, message.size(), signature.data(),
signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = nullptr";
result = HmacSha1Verify(key, message.data(), 0, signature.data(),
signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message_length = 0";
result = HmacSha1Verify(key, message.data(), message.size(), nullptr,
signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "signature = nullptr";
result =
HmacSha1Verify(key, message.data(), message.size(), signature.data(), 0);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE)
<< "signature_length = 0";
// Vector only.
result = HmacSha1Verify(kEmptyVector, message, signature);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = <empty>";
result = HmacSha1Verify(key, kEmptyVector, signature);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = <empty>";
result = HmacSha1Verify(key, message, kEmptyVector);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE) << "signature = <empty>";
}
TEST(OEMCryptoHmacApiTest, VerifySignature_InvalidParameters) {
const std::vector<uint8_t> key = kHmacTestVectorList[0].key;
const std::vector<uint8_t> message = kHmacTestVectorList[0].message;
const std::vector<uint8_t> signature = kHmacTestVectorList[0].signature;
// Pointers only.
OEMCryptoResult result =
HmacSha256Verify(nullptr, key.size(), message.data(), message.size(),
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = nullptr";
result = HmacSha256Verify(key.data(), 0, message.data(), message.size(),
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key_length = 0";
result = HmacSha256Verify(key.data(), key.size(), nullptr, message.size(),
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = nullptr";
result = HmacSha256Verify(key.data(), key.size(), message.data(), 0,
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message_length = 0";
result = HmacSha256Verify(key.data(), key.size(), message.data(),
message.size(), nullptr, signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "signature = nullptr";
result = HmacSha256Verify(key.data(), key.size(), message.data(),
message.size(), signature.data(), 0);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE)
<< "signature_length = 0";
// Vector key, pointer others.
result = HmacSha256Verify(kEmptyVector, message.data(), message.size(),
signature.data(), signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = <empty>";
result = HmacSha256Verify(key, nullptr, message.size(), signature.data(),
signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = nullptr";
result = HmacSha256Verify(key, message.data(), 0, signature.data(),
signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message_length = 0";
result = HmacSha256Verify(key, message.data(), message.size(), nullptr,
signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "signature = nullptr";
result = HmacSha256Verify(key, message.data(), message.size(),
signature.data(), 0);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE)
<< "signature_length = 0";
// Vector only.
result = HmacSha256Verify(kEmptyVector, message, signature);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = <empty>";
result = HmacSha256Verify(key, kEmptyVector, signature);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = <empty>";
result = HmacSha256Verify(key, message, kEmptyVector);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE) << "signature = <empty>";
// String message, vector others.
const std::string message_str(message.begin(), message.end());
result = HmacSha256Verify(kEmptyVector, message_str, signature);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "key = <empty>";
result = HmacSha256Verify(key, kEmptyString, signature);
EXPECT_EQ(result, OEMCrypto_ERROR_INVALID_CONTEXT) << "message = <empty>";
result = HmacSha256Verify(key, message_str, kEmptyVector);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE) << "signature = <empty>";
}
class OEMCryptoHmacTest : public testing::TestWithParam<HmacTestVector> {
public:
void SetUp() override {
HmacTestVector v = GetParam();
key_ = std::move(v.key);
message_ = std::move(v.message);
expected_signature_ = std::move(v.signature);
expected_signature_sha1_ = std::move(v.signature_sha1);
ASSERT_FALSE(key_.empty()) << "Missing test key";
ASSERT_FALSE(message_.empty()) << "Missing test message";
ASSERT_EQ(expected_signature_.size(), kHmacSha256SignatureSize)
<< "Invalid test HMAC-SHA-256 signature";
ASSERT_EQ(expected_signature_sha1_.size(), kHmacSha1SignatureSize)
<< "Invalid test HMAC-SHA-1 signature";
}
void TearDown() override {
key_.clear();
message_.clear();
expected_signature_.clear();
expected_signature_sha1_.clear();
}
std::string GetStringMessage() const {
return std::string(message_.begin(), message_.end());
}
std::vector<uint8_t> GenerateBadSignature() const {
std::vector<uint8_t> bad_signature = expected_signature_;
bad_signature[kHmacSha256SignatureSize / 2] ^= 0x87;
return bad_signature;
}
std::vector<uint8_t> GenerateBadSignatureSha1() const {
std::vector<uint8_t> bad_signature = expected_signature_sha1_;
bad_signature[kHmacSha1SignatureSize / 2] ^= 0x87;
return bad_signature;
}
protected:
std::vector<uint8_t> key_;
std::vector<uint8_t> message_;
std::vector<uint8_t> expected_signature_;
std::vector<uint8_t> expected_signature_sha1_;
};
TEST_P(OEMCryptoHmacTest, GenerateSignatureSha1_PointersOnly) {
size_t signature_length = 0;
OEMCryptoResult result =
HmacSha1(key_.data(), key_.size(), message_.data(), message_.size(),
nullptr, &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER);
EXPECT_EQ(signature_length, kHmacSha1SignatureSize);
signature_length = kHmacSha1SignatureSize * 2;
std::vector<uint8_t> signature(signature_length);
result = HmacSha1(key_.data(), key_.size(), message_.data(), message_.size(),
signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_SUCCESS);
EXPECT_EQ(signature_length, kHmacSha1SignatureSize);
signature.resize(kHmacSha1SignatureSize);
EXPECT_EQ(signature, expected_signature_sha1_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignatureSha1_VectorKeyPointerOther) {
size_t signature_length = 0;
OEMCryptoResult result = HmacSha1(key_, message_.data(), message_.size(),
nullptr, &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER);
EXPECT_EQ(signature_length, kHmacSha1SignatureSize);
signature_length = kHmacSha1SignatureSize * 2;
std::vector<uint8_t> signature(signature_length);
result = HmacSha1(key_, message_.data(), message_.size(), signature.data(),
&signature_length);
EXPECT_EQ(result, OEMCrypto_SUCCESS);
EXPECT_EQ(signature_length, kHmacSha1SignatureSize);
signature.resize(kHmacSha1SignatureSize);
EXPECT_EQ(signature, expected_signature_sha1_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignatureSha1_VectorMessageVectorResult) {
const std::vector<uint8_t> signature = HmacSha1(key_, message_);
EXPECT_EQ(signature.size(), kHmacSha1SignatureSize);
EXPECT_EQ(signature, expected_signature_sha1_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignature_PointersOnly) {
size_t signature_length = 0;
OEMCryptoResult result =
HmacSha256(key_.data(), key_.size(), message_.data(), message_.size(),
nullptr, &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER);
EXPECT_EQ(signature_length, kHmacSha256SignatureSize);
signature_length = kHmacSha256SignatureSize * 2;
std::vector<uint8_t> signature(signature_length);
result = HmacSha256(key_.data(), key_.size(), message_.data(),
message_.size(), signature.data(), &signature_length);
EXPECT_EQ(result, OEMCrypto_SUCCESS);
EXPECT_EQ(signature_length, kHmacSha256SignatureSize);
signature.resize(kHmacSha256SignatureSize);
EXPECT_EQ(signature, expected_signature_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignature_VectorKeyPointerOther) {
size_t signature_length = 0;
OEMCryptoResult result = HmacSha256(key_, message_.data(), message_.size(),
nullptr, &signature_length);
EXPECT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER);
EXPECT_EQ(signature_length, kHmacSha256SignatureSize);
signature_length = kHmacSha256SignatureSize * 2;
std::vector<uint8_t> signature(signature_length);
result = HmacSha256(key_, message_.data(), message_.size(), signature.data(),
&signature_length);
EXPECT_EQ(result, OEMCrypto_SUCCESS);
EXPECT_EQ(signature_length, kHmacSha256SignatureSize);
signature.resize(kHmacSha256SignatureSize);
EXPECT_EQ(signature, expected_signature_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignature_VectorMessageVectorOutputArgument) {
std::vector<uint8_t> signature;
EXPECT_TRUE(HmacSha256(key_, message_, &signature));
EXPECT_EQ(signature.size(), kHmacSha256SignatureSize);
EXPECT_EQ(signature, expected_signature_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignature_StringMessageVectorOutputArgument) {
const std::string message_str = GetStringMessage();
std::vector<uint8_t> signature;
EXPECT_TRUE(HmacSha256(key_, message_str, &signature));
EXPECT_EQ(signature.size(), kHmacSha256SignatureSize);
EXPECT_EQ(signature, expected_signature_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignature_PointerMessageVectorResult) {
const std::vector<uint8_t> signature =
HmacSha256(key_, message_.data(), message_.size());
EXPECT_EQ(signature.size(), kHmacSha256SignatureSize);
EXPECT_EQ(signature, expected_signature_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignature_VectorMessageVectorResult) {
const std::vector<uint8_t> signature = HmacSha256(key_, message_);
EXPECT_EQ(signature.size(), kHmacSha256SignatureSize);
EXPECT_EQ(signature, expected_signature_);
}
TEST_P(OEMCryptoHmacTest, GenerateSignature_StringMessageVectorResult) {
const std::string message_str = GetStringMessage();
const std::vector<uint8_t> signature = HmacSha256(key_, message_str);
EXPECT_EQ(signature.size(), kHmacSha256SignatureSize);
EXPECT_EQ(signature, expected_signature_);
}
TEST_P(OEMCryptoHmacTest, VerifySignatureSha1_PointersOnly) {
OEMCryptoResult result = HmacSha1Verify(
key_.data(), key_.size(), message_.data(), message_.size(),
expected_signature_sha1_.data(), expected_signature_sha1_.size());
EXPECT_EQ(result, OEMCrypto_SUCCESS);
const std::vector<uint8_t> bad_signature = GenerateBadSignatureSha1();
result =
HmacSha1Verify(key_.data(), key_.size(), message_.data(), message_.size(),
bad_signature.data(), bad_signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE);
}
TEST_P(OEMCryptoHmacTest, VerifySignatureSha1_VectorKeyPointerOther) {
OEMCryptoResult result = HmacSha1Verify(
key_, message_.data(), message_.size(), expected_signature_sha1_.data(),
expected_signature_sha1_.size());
EXPECT_EQ(result, OEMCrypto_SUCCESS);
const std::vector<uint8_t> bad_signature = GenerateBadSignatureSha1();
result = HmacSha1Verify(key_, message_.data(), message_.size(),
bad_signature.data(), bad_signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE);
}
TEST_P(OEMCryptoHmacTest, VerifySignatureSha1_VectorsOnly) {
OEMCryptoResult result =
HmacSha1Verify(key_, message_, expected_signature_sha1_);
EXPECT_EQ(result, OEMCrypto_SUCCESS);
const std::vector<uint8_t> bad_signature = GenerateBadSignatureSha1();
result = HmacSha1Verify(key_, message_, bad_signature);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE);
}
TEST_P(OEMCryptoHmacTest, VerifySignature_PointersOnly) {
OEMCryptoResult result = HmacSha256Verify(
key_.data(), key_.size(), message_.data(), message_.size(),
expected_signature_.data(), expected_signature_.size());
EXPECT_EQ(result, OEMCrypto_SUCCESS);
const std::vector<uint8_t> bad_signature = GenerateBadSignature();
result = HmacSha256Verify(key_.data(), key_.size(), message_.data(),
message_.size(), bad_signature.data(),
bad_signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE);
}
TEST_P(OEMCryptoHmacTest, VerifySignature_VectorKeyPointerOther) {
OEMCryptoResult result =
HmacSha256Verify(key_, message_.data(), message_.size(),
expected_signature_.data(), expected_signature_.size());
EXPECT_EQ(result, OEMCrypto_SUCCESS);
const std::vector<uint8_t> bad_signature = GenerateBadSignature();
result = HmacSha256Verify(key_, message_.data(), message_.size(),
bad_signature.data(), bad_signature.size());
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE);
}
TEST_P(OEMCryptoHmacTest, VerifySignature_VectorsOnly) {
OEMCryptoResult result =
HmacSha256Verify(key_, message_, expected_signature_);
EXPECT_EQ(result, OEMCrypto_SUCCESS);
const std::vector<uint8_t> bad_signature = GenerateBadSignature();
result = HmacSha256Verify(key_, message_, bad_signature);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE);
}
TEST_P(OEMCryptoHmacTest, VerifySignature_StringMessageVectorOther) {
const std::string message_str = GetStringMessage();
OEMCryptoResult result =
HmacSha256Verify(key_, message_str, expected_signature_);
EXPECT_EQ(result, OEMCrypto_SUCCESS);
const std::vector<uint8_t> bad_signature = GenerateBadSignature();
result = HmacSha256Verify(key_, message_str, bad_signature);
EXPECT_EQ(result, OEMCrypto_ERROR_SIGNATURE_FAILURE);
}
INSTANTIATE_TEST_SUITE_P(HmacVectors, OEMCryptoHmacTest,
testing::ValuesIn(kHmacTestVectorList));
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,532 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#include "oem_cert.h"
namespace wvoec_ref {
namespace {
const uint32_t kTestOemSystemId = 7913;
// clang-format off
// OEM Certificate private key.
// RSA Private-Key: (2048 bit, 2 primes).
const uint8_t kTestOemPrivateKey[] = {
0x30, 0x82, 0x04, 0xbd, 0x02, 0x01, 0x00, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa7, 0x30, 0x82, 0x04, 0xa3, 0x02, 0x01,
0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa8, 0x75,
0xd5, 0x3d, 0xd3, 0xf3, 0x59, 0xd1, 0x63, 0x0f,
0x5d, 0x5f, 0x2c, 0xaf, 0x80, 0x4e, 0x9a, 0xef,
0x9a, 0x8f, 0x88, 0x37, 0xe5, 0x56, 0xf8, 0x66,
0xcb, 0xa6, 0x61, 0xab, 0xc1, 0xa9, 0x04, 0xc2,
0x12, 0x9d, 0xa6, 0x0c, 0x2c, 0xcb, 0x42, 0x09,
0xd0, 0x36, 0xf0, 0x85, 0x01, 0xdf, 0xd5, 0xbd,
0xaf, 0x82, 0xbb, 0x25, 0xa1, 0x61, 0x17, 0xfe,
0xa1, 0x65, 0x34, 0xda, 0x91, 0xee, 0x91, 0x46,
0xd6, 0x63, 0x47, 0x6a, 0xa5, 0x32, 0x62, 0xe2,
0x4c, 0x7c, 0xf7, 0x76, 0x59, 0xe1, 0x2b, 0x47,
0x8d, 0x1c, 0xe6, 0xa0, 0xbd, 0xc3, 0xc9, 0x36,
0x0e, 0x90, 0x75, 0xba, 0x1c, 0xbd, 0xca, 0x85,
0x0a, 0x4e, 0xcc, 0xfe, 0x91, 0x3f, 0x22, 0x42,
0x96, 0xae, 0xa0, 0x87, 0x82, 0x63, 0x3b, 0x22,
0x54, 0xbc, 0x28, 0xa3, 0x45, 0x4b, 0x34, 0x12,
0x4e, 0xeb, 0x04, 0x4d, 0x29, 0xb3, 0x05, 0x62,
0x0d, 0x51, 0x16, 0x46, 0x98, 0x21, 0xc8, 0x59,
0x96, 0x53, 0x43, 0x38, 0x95, 0x1a, 0x42, 0x94,
0x8b, 0x49, 0x5d, 0x1b, 0x8a, 0xd5, 0x82, 0x6a,
0x32, 0x6f, 0x0e, 0x5a, 0x85, 0x3b, 0xd5, 0x42,
0xc0, 0x4c, 0x34, 0x43, 0x7c, 0x4f, 0xef, 0xca,
0x02, 0x99, 0x38, 0xf9, 0xa5, 0xc0, 0xd8, 0x1d,
0xe7, 0x9e, 0x8c, 0x4d, 0x9c, 0x40, 0xcd, 0x4b,
0x5e, 0x44, 0x37, 0x8d, 0xc5, 0x96, 0xd4, 0xf7,
0xb3, 0x37, 0x4c, 0x2e, 0x2d, 0x30, 0xca, 0x97,
0x39, 0xed, 0xe8, 0x73, 0xc5, 0xe7, 0xcb, 0x95,
0xf0, 0x84, 0x4a, 0x5a, 0x9e, 0x13, 0x19, 0x5f,
0x98, 0xe5, 0xbe, 0x31, 0x5b, 0xff, 0xed, 0x29,
0x26, 0xc4, 0x93, 0x54, 0x49, 0x84, 0xd2, 0xeb,
0x21, 0x40, 0x19, 0x5f, 0xf7, 0x32, 0x67, 0x93,
0xe0, 0xda, 0x77, 0xfc, 0xda, 0x5e, 0xc4, 0x5b,
0x95, 0x2e, 0x46, 0xf3, 0xce, 0xfd, 0x02, 0x03,
0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x01, 0x00,
0x9e, 0x6d, 0x82, 0xc8, 0x0c, 0xc6, 0xb5, 0xd7,
0xa7, 0xb3, 0xd1, 0x7a, 0x2a, 0x8a, 0x3a, 0xbe,
0xb2, 0x13, 0x58, 0x66, 0x58, 0x13, 0x49, 0x4a,
0x0b, 0x7e, 0x91, 0x53, 0xbe, 0x53, 0x4b, 0x63,
0xeb, 0x27, 0xa1, 0x5e, 0x45, 0xc4, 0xf9, 0x73,
0x86, 0x7d, 0xb8, 0x25, 0x92, 0xf9, 0x63, 0x93,
0xe0, 0x6d, 0xed, 0xdb, 0xa2, 0xa9, 0x77, 0x25,
0xda, 0xed, 0x0b, 0x58, 0x24, 0xe6, 0xd1, 0x8b,
0x6d, 0x71, 0x13, 0x3a, 0x76, 0xf5, 0xa2, 0xba,
0xca, 0x28, 0x4d, 0x0a, 0xd1, 0xa7, 0xaa, 0x4b,
0x8a, 0xea, 0x55, 0x99, 0xb2, 0x83, 0xc5, 0x33,
0x95, 0xcd, 0x92, 0xd0, 0xe5, 0x06, 0xcc, 0xf4,
0xe8, 0xbb, 0x49, 0xc0, 0x66, 0x25, 0x9a, 0xef,
0xa7, 0x06, 0xbc, 0xb3, 0x2a, 0x21, 0x86, 0xcc,
0x4f, 0xd6, 0xaf, 0x9d, 0xed, 0x11, 0xef, 0x9f,
0x14, 0x2f, 0x8b, 0xac, 0x96, 0x75, 0x03, 0x1a,
0xe4, 0x5c, 0x48, 0x81, 0x3a, 0x4b, 0x21, 0x6e,
0xad, 0xb3, 0x27, 0x51, 0xe9, 0x35, 0xbe, 0xed,
0x42, 0x5f, 0x8f, 0x83, 0xf0, 0x99, 0xb0, 0xaf,
0xa9, 0x9c, 0x2f, 0xee, 0x5f, 0xee, 0x39, 0x2b,
0x1d, 0xb0, 0xb1, 0xf8, 0x7b, 0x69, 0x38, 0x68,
0xae, 0xa0, 0x36, 0x2a, 0xf5, 0xed, 0x96, 0xfa,
0x7c, 0x1c, 0x59, 0x29, 0xbf, 0xb3, 0x9e, 0x14,
0x97, 0x06, 0xc2, 0x40, 0x30, 0x00, 0x6a, 0x95,
0xd3, 0x86, 0x86, 0xb9, 0x4c, 0xf5, 0x51, 0xa3,
0x6d, 0x5a, 0xd1, 0x46, 0x43, 0x24, 0xa4, 0xa9,
0x59, 0xcf, 0xa2, 0xa7, 0x4e, 0x50, 0x7a, 0xa3,
0x14, 0xe4, 0x4e, 0x32, 0x4d, 0xd4, 0xc2, 0xcf,
0x2d, 0x74, 0xfb, 0x51, 0x34, 0x98, 0x68, 0xc3,
0xd2, 0xb1, 0xd9, 0x38, 0x94, 0x91, 0x28, 0xb1,
0x69, 0x9a, 0xbf, 0xbf, 0x1a, 0xdf, 0xd3, 0xb6,
0x21, 0x38, 0x94, 0x1b, 0x81, 0x00, 0xb5, 0x39,
0x02, 0x81, 0x81, 0x00, 0xdb, 0xe4, 0x83, 0xc5,
0x7a, 0xe0, 0xcf, 0xeb, 0x07, 0x37, 0xfb, 0xf6,
0xfe, 0xb3, 0x62, 0x72, 0x86, 0xd0, 0x12, 0x96,
0x9d, 0xf4, 0x93, 0x90, 0xdc, 0xf6, 0xc6, 0x03,
0x0c, 0x46, 0xb8, 0x66, 0x60, 0xf3, 0x46, 0x5b,
0xab, 0x9f, 0x9d, 0x81, 0xac, 0x26, 0x8f, 0xd7,
0xa3, 0xbd, 0x16, 0xbb, 0xb4, 0x4e, 0xf6, 0xc0,
0x12, 0xb6, 0x99, 0x4a, 0xf5, 0xc1, 0x6c, 0x40,
0x72, 0x18, 0x71, 0x02, 0x65, 0x77, 0xb1, 0xfb,
0xec, 0x19, 0xbb, 0x8c, 0x03, 0xea, 0x7b, 0x17,
0x63, 0xc9, 0xb9, 0x3b, 0x10, 0x56, 0x19, 0xef,
0x86, 0x69, 0x4d, 0x61, 0x03, 0xac, 0x30, 0x65,
0x63, 0xe5, 0xe1, 0x0f, 0xd6, 0xf6, 0x5b, 0xc9,
0x7c, 0xde, 0x9b, 0x26, 0xca, 0x98, 0xda, 0x0c,
0x5b, 0x6f, 0x91, 0x88, 0xbf, 0x98, 0xc3, 0xbc,
0x72, 0x21, 0xa0, 0x07, 0x0a, 0x5e, 0xc7, 0x61,
0x4a, 0xb3, 0x32, 0xc7, 0x02, 0x81, 0x81, 0x00,
0xc4, 0x1f, 0x4a, 0x23, 0xa6, 0x0b, 0xb9, 0xd5,
0xc7, 0xe9, 0x1a, 0x24, 0xe8, 0x2b, 0xf2, 0x1f,
0x17, 0xc3, 0xe6, 0x14, 0x76, 0x71, 0x11, 0x76,
0x8f, 0xfc, 0x66, 0xb8, 0x8c, 0xe2, 0xf5, 0x46,
0x89, 0x0d, 0xd7, 0xe3, 0x56, 0x19, 0xd7, 0x1a,
0xfe, 0x1c, 0xd4, 0x0f, 0x8b, 0x72, 0xd1, 0x20,
0xb0, 0xa4, 0xbe, 0x6b, 0x6b, 0x01, 0x57, 0xe8,
0x6b, 0xdf, 0x89, 0x55, 0x3f, 0x10, 0x41, 0x63,
0xb0, 0x62, 0xa5, 0x7f, 0x4f, 0xe7, 0x42, 0x54,
0xe4, 0x0e, 0x55, 0xae, 0xa2, 0x53, 0x3d, 0xb8,
0x4a, 0xff, 0xeb, 0xe2, 0x8a, 0x71, 0x17, 0x54,
0x20, 0x05, 0x51, 0xed, 0xae, 0xb0, 0xca, 0x7e,
0xc6, 0xd7, 0x09, 0xa8, 0x39, 0x88, 0xac, 0x7f,
0x4b, 0xe0, 0x49, 0xd5, 0x6c, 0x89, 0xf0, 0xbc,
0xe4, 0xe9, 0xb0, 0x29, 0x73, 0x6c, 0x55, 0x7d,
0x8f, 0xbe, 0x32, 0x31, 0x14, 0xd2, 0xec, 0x1b,
0x02, 0x81, 0x80, 0x67, 0xf6, 0x55, 0x5a, 0xa3,
0xaa, 0xf0, 0x82, 0x75, 0x2a, 0x41, 0xe5, 0x58,
0x2c, 0x65, 0xaa, 0x32, 0x14, 0xe4, 0x04, 0xf3,
0xef, 0x33, 0x69, 0x75, 0x1e, 0xf3, 0x25, 0x73,
0xc3, 0x67, 0xe1, 0x77, 0x8a, 0xed, 0x43, 0xe0,
0x13, 0x99, 0xfb, 0x39, 0xf2, 0x0d, 0x65, 0xed,
0x93, 0x33, 0xd1, 0x51, 0x01, 0x58, 0x66, 0x1d,
0x32, 0xd9, 0xac, 0xf8, 0x1e, 0x17, 0xd9, 0x2c,
0x58, 0x63, 0xed, 0xb7, 0x1d, 0x6d, 0x37, 0xe7,
0x3b, 0x8f, 0x51, 0x36, 0x74, 0xc0, 0xf7, 0xa1,
0x05, 0x39, 0x9f, 0x34, 0x2d, 0x11, 0x1c, 0x0e,
0xd7, 0x70, 0x6f, 0x22, 0xb6, 0x61, 0x37, 0x3e,
0x90, 0xeb, 0xe4, 0x7a, 0x44, 0x85, 0xc6, 0xf0,
0x53, 0xaa, 0xd5, 0x1f, 0x4a, 0x3f, 0x25, 0x42,
0x81, 0xb0, 0x34, 0x10, 0x29, 0xe0, 0xb9, 0x12,
0xd8, 0xd4, 0xf9, 0x1f, 0x2d, 0x0a, 0x64, 0xf4,
0x55, 0x5e, 0xf7, 0x02, 0x81, 0x80, 0x3d, 0x06,
0x1f, 0x63, 0x88, 0x3f, 0x0d, 0xcb, 0xdf, 0x30,
0x40, 0xda, 0x4b, 0x03, 0xa1, 0x8a, 0xdb, 0x32,
0x31, 0x5d, 0x1c, 0x9d, 0x81, 0xf9, 0x8a, 0x43,
0xd7, 0x12, 0x85, 0x83, 0xf9, 0x1d, 0xc1, 0x77,
0x75, 0x3d, 0x5f, 0x85, 0x1a, 0xd1, 0x63, 0x50,
0x45, 0x0b, 0xb1, 0x30, 0x40, 0xb2, 0x13, 0x44,
0xaf, 0x9b, 0x6c, 0xe8, 0x36, 0x1a, 0x33, 0xb6,
0x92, 0x5c, 0xdc, 0x0a, 0x8a, 0xce, 0x22, 0x0c,
0x0f, 0xc2, 0xd5, 0x71, 0xf7, 0xc9, 0xc2, 0x4c,
0x53, 0x8c, 0xcb, 0x25, 0x6b, 0x86, 0xf4, 0x8f,
0x3d, 0x2e, 0x78, 0x35, 0x48, 0x34, 0xfc, 0xe1,
0xaa, 0xe4, 0x71, 0xfe, 0xc0, 0x83, 0x42, 0x0b,
0x97, 0x0d, 0xa9, 0x19, 0x45, 0xd3, 0x36, 0x20,
0xcb, 0xd8, 0x84, 0xb5, 0x47, 0x1a, 0xff, 0x7f,
0x57, 0x39, 0x0e, 0x99, 0x1e, 0xe0, 0xba, 0xe1,
0x4b, 0x6c, 0xca, 0x35, 0xf7, 0x11, 0x02, 0x81,
0x80, 0x5a, 0x59, 0xf0, 0x8e, 0x07, 0x9c, 0x1a,
0x83, 0x2b, 0x28, 0xc4, 0x82, 0xcc, 0xb7, 0x9e,
0x41, 0xa5, 0x15, 0xa2, 0x37, 0xa7, 0x0c, 0x77,
0x09, 0x73, 0xf5, 0xb1, 0x3f, 0x7a, 0x55, 0x9f,
0x15, 0x90, 0xa3, 0x5e, 0x6e, 0x19, 0x46, 0x6d,
0x1f, 0x28, 0x64, 0xad, 0xa0, 0xb5, 0xca, 0x7d,
0x06, 0x44, 0x88, 0xae, 0x2b, 0x80, 0x21, 0x84,
0x3d, 0x8d, 0xa5, 0x09, 0x4f, 0xa1, 0xd9, 0x7d,
0x7c, 0x9a, 0x8b, 0x64, 0x8f, 0xf6, 0xa5, 0xce,
0x56, 0x65, 0xba, 0xcb, 0x30, 0x38, 0x53, 0xf8,
0x1b, 0x89, 0x8f, 0xdf, 0xb5, 0xc3, 0x86, 0x3c,
0x24, 0xef, 0xbc, 0xc0, 0xfc, 0x6c, 0xa4, 0xc6,
0x74, 0xbb, 0xeb, 0x79, 0xa9, 0x8e, 0xe5, 0x25,
0xc0, 0x0a, 0xe5, 0x90, 0x08, 0x43, 0x82, 0xec,
0x17, 0x5e, 0x9e, 0xa2, 0x05, 0xc5, 0x03, 0x20,
0x12, 0xf7, 0x86, 0x2e, 0x7e, 0x8e, 0x11, 0xf7,
0x14
};
const size_t kTestOemPrivateKeySize = sizeof(kTestOemPrivateKey);
// OEM Certificate public cert data.
// Leaf (device) certificate:
// version: 2
// serialNumber: 61412119066269531030714093834591281593
// signature algorithm: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
// issuer:
// C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine, CN=system id: 7913
// validity:
// notBefore: Jan 27 15:55:47 2021 GMT
// notAfter: Jan 25 15:55:47 2031 GMT
// subject:
// CN=7913-leaf, C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine
// key: RSA Public key
// extensions:
// - object: Widevine System Id (1.3.6.1.4.1.11129.4.1.1)
// critical: BOOL ABSENT
// value: 02 02 1e e9 (7913)
// sig_alg: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
// signature: ...
//
// Intermediate (manufacturer) certificate:
// version: 2
// serialNumber: 4911737327617104025470773024969385060
// signature: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
// issuer:
// C=US, ST=Washington, L=Kirkland, O=Google, OU=Widevine,
// CN=widevine.com/oem-root-prod
// validity:
// notBefore: Nov 18 01:13:35 2017 GMT
// notAfter: Nov 18 01:13:13 2027 GMT
// subject:
// C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine, CN=system id: 7913
// key: RSA Public key
// extensions:
// - object: X509v3 Basic Constraints (2.5.29.19)
// critical: TRUE
// value: 30 06 01 01 ff 02 01 00
// - object: X509v3 Key Usage (2.5.29.15)
// critical: TRUE
// value: 03 02 02 04
// - object: X509v3 Subject Key Identifier (2.5.29.14)
// critical: BOOL ABSENT
// value:
// 04 14 4b cb df aa 02 de 8d c3 e7 e5 85 db 2e 8a be 75 6b 8a 67-58
// - object: X509v3 Authority Key Identifier (2.5.29.35)
// critical: BOOL ABSENT
// value: ...
// - object: Widevine System Id (1.3.6.1.4.1.11129.4.1.1)
// critical: BOOL ABSENT
// value: 02 02 1e e9 (7913)
// sig_alg: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
// signature: ...
const uint8_t kTestOemPublicCert[] = {
0x30, 0x82, 0x09, 0x28, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
0x82, 0x09, 0x19, 0x30, 0x82, 0x09, 0x15, 0x02,
0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x01, 0xa0, 0x82, 0x08, 0xfd, 0x30, 0x82, 0x03,
0x70, 0x30, 0x82, 0x02, 0x58, 0xa0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x10, 0x2e, 0x33, 0x8b, 0x3d,
0x69, 0x18, 0x4c, 0xf7, 0x78, 0x2e, 0x3b, 0x3b,
0x43, 0xb4, 0x21, 0xb9, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x0b, 0x05, 0x00, 0x30, 0x6b, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61,
0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69,
0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x18,
0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31, 0x33,
0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x31,
0x32, 0x37, 0x31, 0x35, 0x35, 0x35, 0x34, 0x37,
0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x31, 0x32,
0x35, 0x31, 0x35, 0x35, 0x35, 0x34, 0x37, 0x5a,
0x30, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39, 0x31,
0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41,
0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c,
0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06,
0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f,
0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57,
0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa8, 0x75, 0xd5, 0x3d, 0xd3, 0xf3, 0x59, 0xd1,
0x63, 0x0f, 0x5d, 0x5f, 0x2c, 0xaf, 0x80, 0x4e,
0x9a, 0xef, 0x9a, 0x8f, 0x88, 0x37, 0xe5, 0x56,
0xf8, 0x66, 0xcb, 0xa6, 0x61, 0xab, 0xc1, 0xa9,
0x04, 0xc2, 0x12, 0x9d, 0xa6, 0x0c, 0x2c, 0xcb,
0x42, 0x09, 0xd0, 0x36, 0xf0, 0x85, 0x01, 0xdf,
0xd5, 0xbd, 0xaf, 0x82, 0xbb, 0x25, 0xa1, 0x61,
0x17, 0xfe, 0xa1, 0x65, 0x34, 0xda, 0x91, 0xee,
0x91, 0x46, 0xd6, 0x63, 0x47, 0x6a, 0xa5, 0x32,
0x62, 0xe2, 0x4c, 0x7c, 0xf7, 0x76, 0x59, 0xe1,
0x2b, 0x47, 0x8d, 0x1c, 0xe6, 0xa0, 0xbd, 0xc3,
0xc9, 0x36, 0x0e, 0x90, 0x75, 0xba, 0x1c, 0xbd,
0xca, 0x85, 0x0a, 0x4e, 0xcc, 0xfe, 0x91, 0x3f,
0x22, 0x42, 0x96, 0xae, 0xa0, 0x87, 0x82, 0x63,
0x3b, 0x22, 0x54, 0xbc, 0x28, 0xa3, 0x45, 0x4b,
0x34, 0x12, 0x4e, 0xeb, 0x04, 0x4d, 0x29, 0xb3,
0x05, 0x62, 0x0d, 0x51, 0x16, 0x46, 0x98, 0x21,
0xc8, 0x59, 0x96, 0x53, 0x43, 0x38, 0x95, 0x1a,
0x42, 0x94, 0x8b, 0x49, 0x5d, 0x1b, 0x8a, 0xd5,
0x82, 0x6a, 0x32, 0x6f, 0x0e, 0x5a, 0x85, 0x3b,
0xd5, 0x42, 0xc0, 0x4c, 0x34, 0x43, 0x7c, 0x4f,
0xef, 0xca, 0x02, 0x99, 0x38, 0xf9, 0xa5, 0xc0,
0xd8, 0x1d, 0xe7, 0x9e, 0x8c, 0x4d, 0x9c, 0x40,
0xcd, 0x4b, 0x5e, 0x44, 0x37, 0x8d, 0xc5, 0x96,
0xd4, 0xf7, 0xb3, 0x37, 0x4c, 0x2e, 0x2d, 0x30,
0xca, 0x97, 0x39, 0xed, 0xe8, 0x73, 0xc5, 0xe7,
0xcb, 0x95, 0xf0, 0x84, 0x4a, 0x5a, 0x9e, 0x13,
0x19, 0x5f, 0x98, 0xe5, 0xbe, 0x31, 0x5b, 0xff,
0xed, 0x29, 0x26, 0xc4, 0x93, 0x54, 0x49, 0x84,
0xd2, 0xeb, 0x21, 0x40, 0x19, 0x5f, 0xf7, 0x32,
0x67, 0x93, 0xe0, 0xda, 0x77, 0xfc, 0xda, 0x5e,
0xc4, 0x5b, 0x95, 0x2e, 0x46, 0xf3, 0xce, 0xfd,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16, 0x30,
0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01,
0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04,
0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
0x00, 0x04, 0x9e, 0xbb, 0x41, 0x3e, 0x1b, 0x35,
0xca, 0x24, 0xe3, 0xa7, 0x62, 0xf7, 0xbf, 0x54,
0x88, 0x1d, 0xa3, 0x6c, 0x30, 0x1f, 0xb7, 0xe4,
0x2b, 0x76, 0x54, 0x4f, 0xb1, 0x30, 0xba, 0x86,
0x21, 0x12, 0xc3, 0xd9, 0x25, 0xfd, 0x94, 0xab,
0x3c, 0x9d, 0x4d, 0xbc, 0x2b, 0xdc, 0x68, 0x01,
0x8d, 0x59, 0x4f, 0x81, 0xe8, 0x87, 0xbe, 0x05,
0x75, 0x3e, 0x24, 0xd9, 0xf1, 0x55, 0xe3, 0x56,
0x75, 0xa4, 0x7f, 0xb4, 0x50, 0x41, 0x4b, 0x88,
0x0e, 0x8f, 0x6e, 0x10, 0x13, 0x25, 0x24, 0xda,
0x4c, 0x97, 0x0a, 0xdc, 0xbf, 0x2a, 0x1d, 0x4d,
0x02, 0xb3, 0x4b, 0x6a, 0x96, 0xe6, 0x0e, 0xd1,
0x61, 0x80, 0x78, 0xab, 0xf0, 0x7b, 0x8b, 0x1e,
0x99, 0x48, 0x84, 0x31, 0xd2, 0xaf, 0x23, 0x32,
0x01, 0x5e, 0x11, 0x55, 0x06, 0x6e, 0x0e, 0xed,
0x69, 0x7b, 0xb8, 0x41, 0x63, 0x3b, 0x30, 0x05,
0x1e, 0xcd, 0x3e, 0x49, 0xb8, 0x0c, 0x83, 0x50,
0x26, 0x4e, 0xd8, 0x97, 0x9d, 0x89, 0x30, 0x15,
0xb9, 0x20, 0x20, 0xba, 0x5d, 0x8b, 0xad, 0x3d,
0x7f, 0x52, 0xcd, 0x1e, 0xc0, 0x0e, 0xe1, 0xdc,
0x21, 0x9b, 0xb0, 0x89, 0xa0, 0x20, 0xc6, 0x8c,
0x56, 0x39, 0xc3, 0x40, 0x30, 0x40, 0x52, 0x2f,
0x3b, 0x87, 0x96, 0xe2, 0x4d, 0x80, 0x57, 0xb3,
0xb3, 0xe0, 0xb7, 0x5c, 0x55, 0x6a, 0x0f, 0x44,
0x91, 0xe8, 0x98, 0xb3, 0xb4, 0xd3, 0x07, 0x8e,
0x85, 0x8e, 0xc0, 0xcb, 0x85, 0x92, 0x0e, 0xca,
0x7c, 0x03, 0x23, 0xa0, 0x1f, 0x4e, 0x75, 0x01,
0x95, 0x61, 0x2c, 0x21, 0x2f, 0x4f, 0x6d, 0x55,
0xa3, 0xcc, 0x23, 0x62, 0x7f, 0xcb, 0x0a, 0x8a,
0x8b, 0x82, 0xb5, 0x8c, 0x8a, 0xaa, 0x88, 0xb4,
0x65, 0x82, 0x6d, 0x12, 0x4a, 0x06, 0xe7, 0xde,
0xcd, 0x3c, 0xf9, 0x1c, 0x02, 0x9c, 0xf8, 0x21,
0x20, 0x30, 0x82, 0x05, 0x85, 0x30, 0x82, 0x03,
0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10,
0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25,
0x00, 0x0b, 0x10, 0x3d, 0xd5, 0xe6, 0xe4, 0x64,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67,
0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69,
0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f,
0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69,
0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64,
0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f,
0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30,
0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31, 0x31,
0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a,
0x17, 0x0d, 0x32, 0x37, 0x31, 0x31, 0x31, 0x38,
0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a, 0x30,
0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69,
0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f,
0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69,
0x6e, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79, 0x73,
0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20,
0x37, 0x39, 0x31, 0x33, 0x30, 0x82, 0x01, 0x22,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8, 0x71,
0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c,
0xa9, 0x8b, 0xb3, 0xd6, 0x66, 0xe4, 0xf6, 0x08,
0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a, 0x88,
0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19,
0x6c, 0x60, 0xc9, 0xad, 0x91, 0x1c, 0xbf, 0x04,
0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58, 0xc2,
0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14,
0xa8, 0xc2, 0x01, 0xcd, 0xe8, 0x46, 0x60, 0x53,
0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d, 0x0e,
0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43,
0xe3, 0xb0, 0x00, 0x12, 0xb4, 0x05, 0x82, 0x4a,
0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12, 0xaa,
0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c,
0x6c, 0x73, 0xae, 0x56, 0xf8, 0xab, 0xf7, 0x51,
0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01, 0x2c,
0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37,
0x89, 0x05, 0xa9, 0x51, 0x57, 0x72, 0x98, 0x9e,
0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b, 0x2f,
0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf,
0xf5, 0xd6, 0x9c, 0xd5, 0x8c, 0xb8, 0x66, 0x42,
0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e, 0x3e,
0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d,
0xf4, 0x57, 0x7c, 0x6c, 0x33, 0x34, 0x24, 0x45,
0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c, 0x03,
0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87,
0x74, 0x82, 0x1a, 0xbc, 0x0f, 0x76, 0x69, 0xab,
0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8, 0x2c,
0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90,
0xb5, 0x2d, 0x64, 0xba, 0xf7, 0xd2, 0x8a, 0xb4,
0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c, 0x52,
0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70,
0x7e, 0x47, 0x59, 0x94, 0x59, 0x02, 0x03, 0x01,
0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82,
0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d,
0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06,
0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e,
0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x1d,
0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d,
0xc3, 0xe7, 0xe5, 0x85, 0xdb, 0x2e, 0x8a, 0xbe,
0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81, 0xb2,
0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa,
0x30, 0x81, 0xa7, 0x80, 0x14, 0x04, 0x94, 0x66,
0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7,
0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a,
0x8f, 0xa1, 0x81, 0x83, 0xa4, 0x81, 0x80, 0x30,
0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67,
0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69,
0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f,
0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69,
0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64,
0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f,
0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82,
0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe,
0x9a, 0x9a, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06,
0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01,
0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe,
0x66, 0x34, 0xef, 0x92, 0x06, 0xe9, 0x88, 0xba,
0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1, 0x75,
0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36,
0xfd, 0x55, 0xa9, 0x21, 0x0b, 0xdc, 0xf6, 0xae,
0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04, 0x1d,
0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba,
0xe6, 0xdd, 0x19, 0xdd, 0x56, 0xfd, 0xce, 0x06,
0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb, 0x3d,
0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d,
0x4d, 0xcf, 0x7e, 0xf0, 0x91, 0x29, 0xc1, 0x77,
0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8, 0xce,
0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5,
0x9f, 0x9c, 0x1b, 0xc9, 0x4b, 0x58, 0xdf, 0x96,
0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9, 0x14,
0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75,
0x2c, 0x2b, 0xbf, 0x63, 0x7d, 0xc7, 0x4e, 0x7e,
0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5, 0x5a,
0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2,
0x9c, 0x3c, 0x32, 0xed, 0x9d, 0x4b, 0x49, 0x05,
0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82, 0x79,
0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa,
0x4f, 0xef, 0x14, 0x3c, 0x21, 0xf6, 0x72, 0xb2,
0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70, 0xbd,
0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59,
0x0c, 0x0f, 0x11, 0x75, 0xd4, 0xbb, 0xb1, 0xdf,
0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43, 0x17,
0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83,
0x51, 0xfb, 0x16, 0xfb, 0x64, 0xb6, 0x46, 0xda,
0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a, 0x84,
0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde,
0xa5, 0x97, 0x66, 0x79, 0x02, 0xf8, 0x97, 0x17,
0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae, 0x99,
0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5,
0x80, 0xba, 0xbf, 0xdd, 0x24, 0xe5, 0xe6, 0x1e,
0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60, 0x81,
0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c,
0x1a, 0x63, 0xb0, 0xeb, 0xe6, 0x95, 0x86, 0x0d,
0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0, 0xbe,
0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec,
0xf9, 0xcd, 0x49, 0xc6, 0xfe, 0x4d, 0x7f, 0x44,
0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98, 0xe2,
0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc,
0x76, 0x69, 0x51, 0x10, 0x01, 0x46, 0x7d, 0x33,
0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c, 0xc6,
0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a,
0x58, 0x6a, 0xf1, 0x75, 0x9e, 0xea, 0x1b, 0x4c,
0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32, 0x44,
0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2,
0xfa, 0xa1, 0x5f, 0x2e, 0x66, 0xe9, 0x97, 0xcb,
0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86, 0x2c,
0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1,
0xc9, 0x8b, 0x05, 0x92, 0x6f, 0x47, 0x96, 0xce,
0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b, 0xd7,
0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a,
0xf9, 0xb9, 0xb0, 0x93, 0xf0, 0x81, 0x78, 0x10,
0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf, 0xbc,
0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8,
0x13, 0x77, 0x4f, 0x78, 0x9e, 0x40, 0x8d, 0xe6,
0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25, 0x49,
0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd,
0xf5, 0xb1, 0x54, 0x74, 0x1b, 0x67, 0x3c, 0x46,
0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83, 0x30,
0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d,
0xd0, 0x68, 0x31, 0x00
};
// clang-format on
} // namespace
const size_t kTestOemPublicCertSize = sizeof(kTestOemPublicCert);
const uint32_t kOEMSystemId = kTestOemSystemId;
const uint8_t* kOEMPrivateKey = kTestOemPrivateKey;
const uint8_t* kOEMPublicCert = kTestOemPublicCert;
const size_t kOEMPrivateKeySize = kTestOemPrivateKeySize;
const size_t kOEMPublicCertSize = kTestOemPublicCertSize;
} // namespace wvoec_ref

View File

@@ -0,0 +1,258 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_ecc_key.h"
#include "oemcrypto_ref_test_utils.h"
namespace wvoec {
namespace util {
constexpr size_t kMessageSize = 4 * 1024; // 4 kB
class OEMCryptoEccKeyTest : public ::testing::TestWithParam<EccCurve> {
public:
void SetUp() override {
key_ = EccPrivateKey::New(GetParam());
ASSERT_TRUE(key_) << "Key initialization failed: key = "
<< EccCurveToString(GetParam());
}
void TearDown() override { key_.reset(); }
protected:
std::unique_ptr<EccPrivateKey> key_;
};
// Basic verification of ECC private key generation.
TEST_P(OEMCryptoEccKeyTest, KeyProperties) {
const EccCurve expected_curve = GetParam();
EXPECT_EQ(key_->curve(), expected_curve);
EXPECT_NE(nullptr, key_->GetEcKey());
}
// Checks that the private key serialization APIs are compatible
// and performing in a manner that is similar to other OEMCrypto methods
// that retrieve data.
TEST_P(OEMCryptoEccKeyTest, SerializePrivateKey) {
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
key_->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, key_->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = key_->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << i;
}
}
// Checks that a private key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoEccKeyTest, SerializeAndReloadPrivateKey) {
const std::vector<uint8_t> key_data = key_->Serialize();
std::unique_ptr<EccPrivateKey> loaded_key = EccPrivateKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(key_->curve(), loaded_key->curve());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << i;
}
}
// Checks that a private key can be serialized as a public key, and
// that the serialized public key and be reloaded.
TEST_P(OEMCryptoEccKeyTest, SerializePrivateKeyAsPublicKey) {
const std::vector<uint8_t> key_data = key_->SerializeAsPublicKey();
ASSERT_FALSE(key_data.empty()) << "Failed to serialize as public key";
auto loaded_key = EccPublicKey::Load(key_data);
ASSERT_TRUE(loaded_key) << "Failed to deserialize public key";
EXPECT_TRUE(key_->IsMatchingPublicKey(*loaded_key));
EXPECT_TRUE(loaded_key->IsMatchingPrivateKey(*key_));
}
// Checks that a public key can be initialized from a ASN.1 DER encoded
// PrivateKeyInfo message.
TEST_P(OEMCryptoEccKeyTest, SerializePrivateKeyAndReloadAsPublicKey) {
const std::vector<uint8_t> key_data = key_->Serialize();
ASSERT_FALSE(key_data.empty()) << "Failed to serialize as private key";
auto key_by_buffer =
EccPublicKey::LoadPrivateKeyInfo(key_data.data(), key_data.size());
ASSERT_TRUE(key_by_buffer)
<< "Failed to deserialize private key into public key";
EXPECT_TRUE(key_->IsMatchingPublicKey(*key_by_buffer));
key_by_buffer.reset();
auto key_by_vector = EccPublicKey::LoadPrivateKeyInfo(key_data);
ASSERT_TRUE(key_by_vector)
<< "Failed to deserialize private key into public key";
EXPECT_TRUE(key_->IsMatchingPublicKey(*key_by_vector));
key_by_vector.reset();
const std::string key_data_str(key_data.begin(), key_data.end());
auto key_by_string = EccPublicKey::LoadPrivateKeyInfo(key_data_str);
ASSERT_TRUE(key_by_string)
<< "Failed to deserialize private key into public key";
EXPECT_TRUE(key_->IsMatchingPublicKey(*key_by_string));
}
// Checks that a public key can be created from the private key.
TEST_P(OEMCryptoEccKeyTest, DerivePublicKey) {
std::unique_ptr<EccPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_TRUE(key_->IsMatchingPublicKey(*pub_key));
}
// Checks that a public key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoEccKeyTest, SerializePublicKey) {
std::unique_ptr<EccPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
pub_key->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = pub_key->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << i;
}
}
// Checks that a public key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
// It is anticipated that OEMCrypto will need to parse the licensing
// server's ephemerial key when deriving the session key.
TEST_P(OEMCryptoEccKeyTest, SerializeAndReloadPublicKey) {
std::unique_ptr<EccPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
const std::vector<uint8_t> key_data = pub_key->Serialize();
std::unique_ptr<EccPublicKey> loaded_key = EccPublicKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(pub_key->curve(), loaded_key->curve());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << i;
}
}
// Checks that the ECC signature generating API operates similar to
// existing signature generation functions.
TEST_P(OEMCryptoEccKeyTest, GenerateSignature) {
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t signature_size = kInitialBufferSize;
std::vector<uint8_t> signature(signature_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
key_->GenerateSignature(message.data(), message.size(),
signature.data(), &signature_size));
EXPECT_GT(signature_size, kInitialBufferSize);
signature.resize(signature_size);
EXPECT_EQ(OEMCrypto_SUCCESS,
key_->GenerateSignature(message.data(), message.size(),
signature.data(), &signature_size));
signature.resize(signature_size);
EXPECT_LE(signature_size, key_->SignatureSize());
}
// Checks that ECC signatures can be verified by an ECC public key.
TEST_P(OEMCryptoEccKeyTest, VerifySignature) {
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
const std::vector<uint8_t> signature = key_->GenerateSignature(message);
std::unique_ptr<EccPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->VerifySignature(message, signature));
// Check with different message.
const std::vector<uint8_t> message_two = RandomData(kMessageSize);
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message_two, signature));
// Check with bad signature.
const std::vector<uint8_t> bad_signature = RandomData(signature.size());
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message, bad_signature));
}
// Verifies the session key exchange protocol used by the licensing
// server.
TEST_P(OEMCryptoEccKeyTest, DeriveSessionKey) {
// Set up Alice.
EccPrivateKey* alice_private_key = key_.get();
std::unique_ptr<EccPublicKey> alice_public_key =
alice_private_key->MakePublicKey();
ASSERT_TRUE(alice_public_key);
// Set up Bob.
std::unique_ptr<EccPrivateKey> bob_private_key =
EccPrivateKey::New(alice_private_key->curve());
ASSERT_TRUE(bob_private_key);
std::unique_ptr<EccPublicKey> bob_public_key =
bob_private_key->MakePublicKey();
ASSERT_TRUE(bob_public_key);
const size_t session_key_length = alice_private_key->SessionKeyLength();
EXPECT_EQ(session_key_length, bob_private_key->SessionKeyLength());
// From Alice's perspective.
const std::vector<uint8_t> alice_session_key =
alice_private_key->DeriveSessionKey(*bob_public_key);
// From Bob's perspective.
const std::vector<uint8_t> bob_session_key =
bob_private_key->DeriveSessionKey(*alice_public_key);
// Both should have the same session key.
ASSERT_EQ(session_key_length, alice_session_key.size());
ASSERT_EQ(session_key_length, bob_session_key.size());
for (size_t i = 0; i < session_key_length; i++) {
ASSERT_EQ(alice_session_key[i], bob_session_key[i]) << "i = " << i;
}
}
INSTANTIATE_TEST_SUITE_P(AllCurves, OEMCryptoEccKeyTest,
::testing::Values(kEccSecp256r1, kEccSecp384r1,
kEccSecp521r1));
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,124 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "OEMCryptoCENCCommon.h"
#include "oem_cert.h"
#include "oemcrypto_oem_cert.h"
#include "oemcrypto_rsa_key.h"
namespace wvoec {
namespace util {
using wvoec_ref::kOEMPrivateKey;
using wvoec_ref::kOEMPrivateKeySize;
using wvoec_ref::kOEMPublicCert;
using wvoec_ref::kOEMPublicCertSize;
namespace {
const std::vector<uint8_t> kOEMPrivateKeyVector(kOEMPrivateKey,
kOEMPrivateKey +
kOEMPrivateKeySize);
const std::vector<uint8_t> kOEMPublicCertVector(kOEMPublicCert,
kOEMPublicCert +
kOEMPublicCertSize);
} // namespace
// Creates an OemCertificate wrapper around the built-in reference
// OEM cert.
// Creating the OemCertificate should succeed so long as the data
// is well-formed.
// Validating the OEM cert should succeed (assuming built-in cert+key
// are valid).
TEST(OEMCryptoOemCertTest, CreateFromArray) {
std::unique_ptr<OemCertificate> oem_cert = OemCertificate::Create(
kOEMPrivateKey, kOEMPrivateKeySize, kOEMPublicCert, kOEMPublicCertSize);
ASSERT_TRUE(oem_cert);
EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type());
const std::vector<uint8_t> private_key = oem_cert->GetPrivateKey();
EXPECT_EQ(kOEMPrivateKeyVector, private_key);
size_t public_cert_size = 10;
std::vector<uint8_t> public_cert(public_cert_size, 0);
EXPECT_EQ(
OEMCrypto_ERROR_SHORT_BUFFER,
oem_cert->GetPublicCertificate(public_cert.data(), &public_cert_size));
public_cert.resize(public_cert_size);
EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->GetPublicCertificate(
public_cert.data(), &public_cert_size));
EXPECT_EQ(kOEMPublicCertSize, public_cert_size);
EXPECT_EQ(kOEMPublicCertVector, public_cert);
EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->IsCertificateValid());
}
TEST(OEMCryptoOemCertTest, CreateFromVector) {
std::unique_ptr<OemCertificate> oem_cert =
OemCertificate::Create(kOEMPrivateKeyVector, kOEMPublicCertVector);
ASSERT_TRUE(oem_cert);
EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type());
const std::vector<uint8_t> private_key = oem_cert->GetPrivateKey();
EXPECT_EQ(kOEMPrivateKeyVector, private_key);
const std::vector<uint8_t> public_cert = oem_cert->GetPublicCertificate();
EXPECT_EQ(kOEMPublicCertVector, public_cert);
EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->IsCertificateValid());
}
// Creation of OemCertificate wrapper should fail if the provided
// key is not well-formed.
TEST(OEMCryptoOemCertTest, CreateWithABadPrivateKey) {
static const uint8_t kBadPrivateKeyData[] = {'n', 'o', 't', ' ', 'a', ' ',
'p', 'r', 'i', 'v', 'a', 't',
'e', 'k', 'e', 'y'};
std::unique_ptr<OemCertificate> oem_cert =
OemCertificate::Create(kBadPrivateKeyData, sizeof(kBadPrivateKeyData),
kOEMPublicCert, kOEMPublicCertSize);
EXPECT_FALSE(oem_cert);
}
// Creation of OemCertificate wrapper should fail if the provided
// OEM Public Cert is not well-formed.
TEST(OEMCryptoOemCertTest, CreateWithABadPublicCert) {
static const uint8_t kBadPublicCert[] = {'n', 'o', 't', ' ', 'a', ' ', 'o',
'e', 'm', ' ', 'p', 'u', 'b', 'l',
'i', 'c', ' ', 'c', 'e', 'r', 't'};
std::unique_ptr<OemCertificate> oem_cert =
OemCertificate::Create(kOEMPrivateKey, kOEMPrivateKeySize, kBadPublicCert,
sizeof(kBadPublicCert));
EXPECT_FALSE(oem_cert);
}
// It is possible to create an OEM Certificate using a non-matching
// public-private key pair so long as the key types are the same.
// However, OEM Cert validation should catch the problem.
TEST(OEMCryptoOemCertTest, CreateWithDifferentPrivateRsaKey) {
std::unique_ptr<RsaPrivateKey> key = RsaPrivateKey::New(kRsa2048Bit);
ASSERT_TRUE(key);
const std::vector<uint8_t> private_key = key->Serialize();
ASSERT_FALSE(private_key.empty());
// Creating the OEM Certificate should succeed.
std::unique_ptr<OemCertificate> oem_cert =
OemCertificate::Create(private_key, kOEMPublicCertVector);
ASSERT_TRUE(oem_cert);
EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type());
// Validating key should return an error.
OEMCryptoResult status = oem_cert->IsCertificateValid();
// Test still allows deprecated error.
if (status != OEMCrypto_ERROR_INVALID_RSA_KEY) {
EXPECT_EQ(OEMCrypto_ERROR_INVALID_KEY, status);
}
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,20 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "oemcrypto_ref_test_utils.h"
#include <string>
#include "cdm_random.h"
namespace wvoec {
namespace util {
std::vector<uint8_t> RandomData(size_t length) {
const std::string data = wvutil::CdmRandom::RandomData(length);
return std::vector<uint8_t>(data.begin(), data.end());
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,21 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_REF_TEST_UTILS_H_
#define WVOEC_UTIL_REF_TEST_UTILS_H_
#include <stddef.h>
#include <stdint.h>
#include <vector>
namespace wvoec {
namespace util {
// Returns a vector of random bytes.
std::vector<uint8_t> RandomData(size_t length);
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_REF_TEST_UTILS_H_

View File

@@ -0,0 +1,417 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include <stdlib.h>
#include <mutex>
#include <gtest/gtest.h>
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oemcrypto_ref_test_utils.h"
#include "oemcrypto_rsa_key.h"
namespace wvoec {
namespace util {
constexpr size_t kMessageSize = 4 * 1024; // 4 kB
constexpr size_t kCastMessageSize = 83; // Special max size.
class OEMCryptoRsaKeyTest : public ::testing::TestWithParam<RsaFieldSize> {
public:
void SetUp() override {
// RSA key generation is slow (~2 seconds) compared to the
// operations they perform (<50 ms). Each key type is generated
// once and globally stored in serialized form.
// Caching the instance may result in test failures for
// memory-leak detection.
const RsaFieldSize field_size = GetParam();
std::lock_guard<std::mutex> rsa_key_lock(rsa_key_mutex_);
// Use of a switch case is intentional to cause compiler warnings
// if a new field size is introduced without updating the test.
switch (field_size) {
case kRsa2048Bit: {
if (!rsa_2048_key_data_.empty()) {
key_ = RsaPrivateKey::Load(rsa_2048_key_data_);
}
if (!key_) {
key_ = RsaPrivateKey::New(kRsa2048Bit);
}
if (rsa_2048_key_data_.empty() && key_) {
rsa_2048_key_data_ = key_->Serialize();
}
} break;
case kRsa3072Bit: {
if (!rsa_3072_key_data_.empty()) {
key_ = RsaPrivateKey::Load(rsa_3072_key_data_);
}
if (!key_) {
key_ = RsaPrivateKey::New(kRsa3072Bit);
}
if (rsa_3072_key_data_.empty() && key_) {
rsa_3072_key_data_ = key_->Serialize();
}
} break;
case kRsaFieldUnknown: // Suppress compiler warnings
LOGE("RSA test was incorrectly instantiation");
exit(EXIT_FAILURE);
break;
}
ASSERT_TRUE(key_) << "Key initialization failed "
<< RsaFieldSizeToString(field_size);
}
void TearDown() override { key_.reset(); }
protected:
std::unique_ptr<RsaPrivateKey> key_;
static std::mutex rsa_key_mutex_;
static std::vector<uint8_t> rsa_2048_key_data_;
static std::vector<uint8_t> rsa_3072_key_data_;
};
std::mutex OEMCryptoRsaKeyTest::rsa_key_mutex_;
std::vector<uint8_t> OEMCryptoRsaKeyTest::rsa_2048_key_data_;
std::vector<uint8_t> OEMCryptoRsaKeyTest::rsa_3072_key_data_;
// Basic verification of RSA private key generation.
TEST_P(OEMCryptoRsaKeyTest, KeyProperties) {
const RsaFieldSize expected_field_size = GetParam();
EXPECT_EQ(key_->field_size(), expected_field_size);
EXPECT_NE(nullptr, key_->GetRsaKey());
}
// Checks that the private key serialization APIs are compatible
// and performing in a manner that is similar to other OEMCrypto methods
// that retrieve data.
TEST_P(OEMCryptoRsaKeyTest, SerializePrivateKey) {
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
key_->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, key_->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = key_->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a private key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPrivateKey) {
const std::vector<uint8_t> key_data = key_->Serialize();
std::unique_ptr<RsaPrivateKey> loaded_key = RsaPrivateKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(key_->field_size(), loaded_key->field_size());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a private key with explicitly indicated schemes include
// the scheme fields in the reserialized key.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPrivateKeyWithAllowedSchemes) {
const std::vector<uint8_t> raw_key_data = key_->Serialize();
std::vector<uint8_t> key_data = {'S', 'I', 'G', 'N', 0x00, 0x00, 0x00, 0x03};
key_data.insert(key_data.end(), raw_key_data.begin(), raw_key_data.end());
std::unique_ptr<RsaPrivateKey> explicit_key = RsaPrivateKey::Load(key_data);
ASSERT_TRUE(explicit_key);
EXPECT_EQ(key_->field_size(), explicit_key->field_size());
const uint32_t kExpectedSchemes = 0x03;
EXPECT_EQ(explicit_key->allowed_schemes(), kExpectedSchemes);
const std::vector<uint8_t> explicit_key_data = explicit_key->Serialize();
ASSERT_EQ(key_data.size(), explicit_key_data.size());
ASSERT_EQ(key_data, explicit_key_data);
}
// Checks that a public key can be created from the private key.
TEST_P(OEMCryptoRsaKeyTest, DerivePublicKey) {
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_TRUE(key_->IsMatchingPublicKey(*pub_key));
}
// Checks that the public key serialization APIs are compatible
// and performing in a manner that is similar to other OEMCrypto methods
// that retrieve data.
TEST_P(OEMCryptoRsaKeyTest, SerializePublicKey) {
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
pub_key->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = pub_key->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a public key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPublicKey) {
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
const std::vector<uint8_t> key_data = pub_key->Serialize();
std::unique_ptr<RsaPublicKey> loaded_key = RsaPublicKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(pub_key->field_size(), loaded_key->field_size());
EXPECT_EQ(pub_key->allowed_schemes(), loaded_key->allowed_schemes());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a public key can be initialized from a ASN.1 DER encoded
// PrivateKeyInfo message.
TEST_P(OEMCryptoRsaKeyTest, SerializePrivateKeyAndReloadAsPublicKey) {
const std::vector<uint8_t> key_data = key_->Serialize();
ASSERT_FALSE(key_data.empty()) << "Failed to serialize as private key";
auto key_by_buffer =
RsaPublicKey::LoadPrivateKeyInfo(key_data.data(), key_data.size());
ASSERT_TRUE(key_by_buffer)
<< "Failed to deserialize private key into public key";
EXPECT_TRUE(key_->IsMatchingPublicKey(*key_by_buffer));
key_by_buffer.reset();
auto key_by_vector = RsaPublicKey::LoadPrivateKeyInfo(key_data);
ASSERT_TRUE(key_by_vector)
<< "Failed to deserialize private key into public key";
EXPECT_TRUE(key_->IsMatchingPublicKey(*key_by_vector));
key_by_vector.reset();
const std::string key_data_str(key_data.begin(), key_data.end());
auto key_by_string = RsaPublicKey::LoadPrivateKeyInfo(key_data_str);
ASSERT_TRUE(key_by_string)
<< "Failed to deserialize private key into public key";
EXPECT_TRUE(key_->IsMatchingPublicKey(*key_by_string));
}
// Checks that the RSA signature generating API operates similar to
// existing signature generation functions.
TEST_P(OEMCryptoRsaKeyTest, GenerateSignature) {
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t signature_size = kInitialBufferSize;
std::vector<uint8_t> signature(signature_size);
EXPECT_EQ(
OEMCrypto_ERROR_SHORT_BUFFER,
key_->GenerateSignature(message.data(), message.size(), kRsaPssDefault,
signature.data(), &signature_size));
EXPECT_GT(signature_size, kInitialBufferSize);
signature.resize(signature_size);
EXPECT_EQ(
OEMCrypto_SUCCESS,
key_->GenerateSignature(message.data(), message.size(), kRsaPssDefault,
signature.data(), &signature_size));
signature.resize(signature_size);
EXPECT_LE(signature_size, key_->SignatureSize());
}
// Checks that RSA signatures can be verified by an RSA public key.
TEST_P(OEMCryptoRsaKeyTest, VerifySignature) {
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
const std::vector<uint8_t> signature = key_->GenerateSignature(message);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->VerifySignature(message, signature));
// Check with different message.
const std::vector<uint8_t> message_two = RandomData(kMessageSize);
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message_two, signature));
// Check with bad signature.
const std::vector<uint8_t> bad_signature = RandomData(signature.size());
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message, bad_signature));
}
// Checks that the special CAST receiver signature scheme works
// to the degree that it is possible to test.
TEST_P(OEMCryptoRsaKeyTest, GenerateAndVerifyRsaSignature) {
// Key must be enabled for PKCS1 Block 1 padding scheme.
// To do so, the key is serialized and the padding scheme is
// added to the key data.
const std::vector<uint8_t> key_data = key_->Serialize();
ASSERT_FALSE(key_data.empty());
std::vector<uint8_t> pkcs_enabled_key_data = {
'S', 'I', 'G', 'N', 0x00, 0x00, 0x00, kSign_PKCS1_Block1};
pkcs_enabled_key_data.insert(pkcs_enabled_key_data.end(), key_data.begin(),
key_data.end());
std::unique_ptr<RsaPrivateKey> pkcs_enabled_key =
RsaPrivateKey::Load(pkcs_enabled_key_data);
ASSERT_TRUE(pkcs_enabled_key);
// The actual cast message is a domain specific hash of the message,
// however, random data works for testing purposes.
const std::vector<uint8_t> message = RandomData(kCastMessageSize);
// Generate signature.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t signature_size = kInitialBufferSize;
std::vector<uint8_t> signature(signature_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
pkcs_enabled_key->GenerateSignature(message.data(), message.size(),
kRsaPkcs1Cast, signature.data(),
&signature_size));
EXPECT_GT(signature_size, kInitialBufferSize);
signature.resize(signature_size);
EXPECT_EQ(OEMCrypto_SUCCESS,
pkcs_enabled_key->GenerateSignature(message.data(), message.size(),
kRsaPkcs1Cast, signature.data(),
&signature_size));
signature.resize(signature_size);
EXPECT_LE(signature_size, pkcs_enabled_key->SignatureSize());
// Verify signature.
std::unique_ptr<RsaPublicKey> pub_key = pkcs_enabled_key->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_EQ(OEMCrypto_SUCCESS,
pub_key->VerifySignature(message, signature, kRsaPkcs1Cast));
}
// Verifies the session key exchange protocol used by the licensing
// server.
TEST_P(OEMCryptoRsaKeyTest, ShareSessionKey) {
constexpr size_t kSessionKeySize = 16;
std::unique_ptr<RsaPublicKey> public_key = key_->MakePublicKey();
ASSERT_TRUE(public_key);
// Generate session key.
const std::vector<uint8_t> session_key = RandomData(kSessionKeySize);
ASSERT_FALSE(session_key.empty());
// Server's perspective.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t enc_session_key_size = kInitialBufferSize;
std::vector<uint8_t> enc_session_key(enc_session_key_size);
OEMCryptoResult result = public_key->EncryptSessionKey(
session_key.data(), session_key.size(), enc_session_key.data(),
&enc_session_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
enc_session_key.resize(enc_session_key_size);
result = public_key->EncryptSessionKey(session_key.data(), session_key.size(),
enc_session_key.data(),
&enc_session_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
enc_session_key.resize(enc_session_key_size);
// Client's perspective.
size_t received_session_key_size = kInitialBufferSize;
std::vector<uint8_t> received_session_key(received_session_key_size);
result = key_->DecryptSessionKey(
enc_session_key.data(), enc_session_key.size(),
received_session_key.data(), &received_session_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
received_session_key.resize(received_session_key_size);
result = key_->DecryptSessionKey(
enc_session_key.data(), enc_session_key.size(),
received_session_key.data(), &received_session_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
received_session_key.resize(received_session_key_size);
// Compare keys.
ASSERT_EQ(session_key.size(), received_session_key.size());
ASSERT_EQ(session_key, received_session_key);
}
// Verifies the encryption key exchange protocol used by the licensing
// server.
TEST_P(OEMCryptoRsaKeyTest, ShareEncryptionKey) {
constexpr size_t kEncryptionKeySize = 16;
std::unique_ptr<RsaPublicKey> public_key = key_->MakePublicKey();
ASSERT_TRUE(public_key);
// Generate session key.
const std::vector<uint8_t> encryption_key = RandomData(kEncryptionKeySize);
ASSERT_FALSE(encryption_key.empty());
// Server's perspective.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t enc_encryption_key_size = kInitialBufferSize;
std::vector<uint8_t> enc_encryption_key(enc_encryption_key_size);
OEMCryptoResult result = public_key->EncryptEncryptionKey(
encryption_key.data(), encryption_key.size(), enc_encryption_key.data(),
&enc_encryption_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
enc_encryption_key.resize(enc_encryption_key_size);
result = public_key->EncryptEncryptionKey(
encryption_key.data(), encryption_key.size(), enc_encryption_key.data(),
&enc_encryption_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
enc_encryption_key.resize(enc_encryption_key_size);
// Client's perspective.
size_t received_encryption_key_size = kInitialBufferSize;
std::vector<uint8_t> received_encryption_key(received_encryption_key_size);
result = key_->DecryptEncryptionKey(
enc_encryption_key.data(), enc_encryption_key.size(),
received_encryption_key.data(), &received_encryption_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
received_encryption_key.resize(received_encryption_key_size);
result = key_->DecryptEncryptionKey(
enc_encryption_key.data(), enc_encryption_key.size(),
received_encryption_key.data(), &received_encryption_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
received_encryption_key.resize(received_encryption_key_size);
// Compare keys.
ASSERT_EQ(encryption_key.size(), received_encryption_key.size());
ASSERT_EQ(encryption_key, received_encryption_key);
}
INSTANTIATE_TEST_SUITE_P(AllFieldSizes, OEMCryptoRsaKeyTest,
::testing::Values(kRsa2048Bit, kRsa3072Bit));
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,74 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "wvcrc32.h"
namespace wvoec {
namespace util {
uint32_t ComputeCrc32(const std::string& s) {
return wvcrc32(reinterpret_cast<const uint8_t*>(s.data()), s.size());
}
uint32_t ComputeCrc32Cont(const std::string& s, uint32_t prev_crc) {
return wvcrc32Cont(reinterpret_cast<const uint8_t*>(s.data()), s.size(),
prev_crc);
}
TEST(OEMCryptoWvCrc32Test, BasicTest) {
EXPECT_EQ(0xF88AC628u, ComputeCrc32("abcdefg"));
EXPECT_EQ(0xDF520F72u, ComputeCrc32("Widevine"));
EXPECT_EQ(0x0376E6E7u, ComputeCrc32("123456789"));
EXPECT_EQ(0xBA62119Eu,
ComputeCrc32("The quick brown fox jumps over the lazy dog"));
}
TEST(OEMCryptoWvCrc32Test, StreamTest) {
const std::vector<std::string> parts = {"The ", "quick", " brown ",
"fox", " jumps ", "over",
" the ", "lazy", " dog"};
uint32_t crc = wvcrc32Init();
for (const auto& part : parts) {
crc = ComputeCrc32Cont(part, crc);
}
EXPECT_EQ(0xBA62119Eu, crc);
}
TEST(OEMCryptoWvCrc32Test, Keybox) {
// clang-format off
const uint8_t kKeyboxData[128] = {
// deviceID = WidevineCRCTestKeyBox
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
0x43, 0x52, 0x43, 0x54, 0x65, 0x73, 0x74, 0x4b,
0x65, 0x79, 0x62, 0x6f, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// key = random
0x8a, 0x7c, 0xda, 0x3e, 0x09, 0xd9, 0x8e, 0xd5,
0x47, 0x47, 0x00, 0x84, 0x5a, 0x1f, 0x52, 0xd4,
// data = random
0x98, 0xa5, 0x00, 0x19, 0x8b, 0xfe, 0x54, 0xfd,
0xca, 0x4d, 0x26, 0xa3, 0xfa, 0xaa, 0x3b, 0x6c,
0x35, 0xfe, 0x03, 0x7c, 0xbf, 0x35, 0xba, 0xce,
0x31, 0xb5, 0x1e, 0x3c, 0x49, 0xd6, 0x3f, 0x9c,
0x3a, 0xde, 0x9b, 0x58, 0xcc, 0x54, 0x8d, 0xc0,
0x4b, 0x04, 0xcc, 0xee, 0xae, 0x4d, 0x9f, 0x90,
0xd3, 0xf3, 0xfe, 0x23, 0x26, 0x13, 0x56, 0x80,
0xe4, 0x3b, 0x79, 0x22, 0x69, 0x5d, 0xd6, 0xb7,
0xa0, 0x0e, 0x7e, 0x07, 0xcd, 0x1a, 0x15, 0xca,
// magic
'k', 'b', 'o', 'x',
// crc
0x09, 0x7b, 0x7e, 0xcc
};
// clang-format on
const uint32_t crc_computed = wvcrc32n(kKeyboxData, 124);
uint32_t crc_current;
memcpy(&crc_current, &kKeyboxData[124], 4);
EXPECT_EQ(crc_computed, crc_current);
}
} // namespace util
} // namespace wvoec