Source release 17.1.0
This commit is contained in:
61
oemcrypto/util/include/cmac.h
Normal file
61
oemcrypto/util/include/cmac.h
Normal 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_
|
||||
139
oemcrypto/util/include/hmac.h
Normal file
139
oemcrypto/util/include/hmac.h
Normal 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_
|
||||
85
oemcrypto/util/include/oemcrypto_drm_key.h
Normal file
85
oemcrypto/util/include/oemcrypto_drm_key.h
Normal 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_
|
||||
281
oemcrypto/util/include/oemcrypto_ecc_key.h
Normal file
281
oemcrypto/util/include/oemcrypto_ecc_key.h
Normal 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_
|
||||
61
oemcrypto/util/include/oemcrypto_key_deriver.h
Normal file
61
oemcrypto/util/include/oemcrypto_key_deriver.h
Normal 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_
|
||||
104
oemcrypto/util/include/oemcrypto_oem_cert.h
Normal file
104
oemcrypto/util/include/oemcrypto_oem_cert.h
Normal 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_
|
||||
376
oemcrypto/util/include/oemcrypto_rsa_key.h
Normal file
376
oemcrypto/util/include/oemcrypto_rsa_key.h
Normal 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_
|
||||
70
oemcrypto/util/include/scoped_object.h
Normal file
70
oemcrypto/util/include/scoped_object.h
Normal 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_
|
||||
22
oemcrypto/util/include/wvcrc32.h
Normal file
22
oemcrypto/util/include/wvcrc32.h
Normal 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_
|
||||
20
oemcrypto/util/oec_ref_util.gyp
Normal file
20
oemcrypto/util/oec_ref_util.gyp
Normal 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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
33
oemcrypto/util/oec_ref_util.gypi
Normal file
33
oemcrypto/util/oec_ref_util.gypi
Normal 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',
|
||||
],
|
||||
}
|
||||
27
oemcrypto/util/oec_ref_util_unittests.gypi
Normal file
27
oemcrypto/util/oec_ref_util_unittests.gypi
Normal 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
173
oemcrypto/util/src/cmac.cpp
Normal 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
269
oemcrypto/util/src/hmac.cpp
Normal 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
|
||||
186
oemcrypto/util/src/oemcrypto_drm_key.cpp
Normal file
186
oemcrypto/util/src/oemcrypto_drm_key.cpp
Normal 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
|
||||
931
oemcrypto/util/src/oemcrypto_ecc_key.cpp
Normal file
931
oemcrypto/util/src/oemcrypto_ecc_key.cpp
Normal 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
|
||||
154
oemcrypto/util/src/oemcrypto_key_deriver.cpp
Normal file
154
oemcrypto/util/src/oemcrypto_key_deriver.cpp
Normal 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
|
||||
234
oemcrypto/util/src/oemcrypto_oem_cert.cpp
Normal file
234
oemcrypto/util/src/oemcrypto_oem_cert.cpp
Normal 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
|
||||
1287
oemcrypto/util/src/oemcrypto_rsa_key.cpp
Normal file
1287
oemcrypto/util/src/oemcrypto_rsa_key.cpp
Normal file
File diff suppressed because it is too large
Load Diff
88
oemcrypto/util/src/wvcrc.cpp
Normal file
88
oemcrypto/util/src/wvcrc.cpp
Normal 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
|
||||
129
oemcrypto/util/test/cmac_unittest.cpp
Normal file
129
oemcrypto/util/test/cmac_unittest.cpp
Normal 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
|
||||
597
oemcrypto/util/test/hmac_unittest.cpp
Normal file
597
oemcrypto/util/test/hmac_unittest.cpp
Normal 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
|
||||
532
oemcrypto/util/test/oem_cert_test.cpp
Normal file
532
oemcrypto/util/test/oem_cert_test.cpp
Normal 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
|
||||
258
oemcrypto/util/test/oemcrypto_ecc_key_unittest.cpp
Normal file
258
oemcrypto/util/test/oemcrypto_ecc_key_unittest.cpp
Normal 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
|
||||
124
oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp
Normal file
124
oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp
Normal 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
|
||||
20
oemcrypto/util/test/oemcrypto_ref_test_utils.cpp
Normal file
20
oemcrypto/util/test/oemcrypto_ref_test_utils.cpp
Normal 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
|
||||
21
oemcrypto/util/test/oemcrypto_ref_test_utils.h
Normal file
21
oemcrypto/util/test/oemcrypto_ref_test_utils.h
Normal 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_
|
||||
417
oemcrypto/util/test/oemcrypto_rsa_key_unittest.cpp
Normal file
417
oemcrypto/util/test/oemcrypto_rsa_key_unittest.cpp
Normal 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
|
||||
74
oemcrypto/util/test/oemcrypto_wvcrc32_unittest.cpp
Normal file
74
oemcrypto/util/test/oemcrypto_wvcrc32_unittest.cpp
Normal 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
|
||||
Reference in New Issue
Block a user