Replace hardcoded parameters
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2017 Google LLC.
|
||||
// Copyright 2019 Google LLC.
|
||||
//
|
||||
// This software is licensed under the terms defined in the Widevine Master
|
||||
// License Agreement. For a copy of this agreement, please contact
|
||||
@@ -8,19 +8,19 @@
|
||||
|
||||
#include "common/client_cert.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "strings/serialize.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "util/gtl/map_util.h"
|
||||
#include "common/certificate_client_cert.h"
|
||||
#include "common/crypto_util.h"
|
||||
#include "common/drm_root_certificate.h"
|
||||
#include "common/error_space.h"
|
||||
#include "common/keybox_client_cert.h"
|
||||
#include "common/random_util.h"
|
||||
#include "common/rsa_key.h"
|
||||
#include "common/sha_util.h"
|
||||
#include "common/signing_key_util.h"
|
||||
#include "common/status.h"
|
||||
@@ -30,93 +30,6 @@
|
||||
#include "protos/public/signed_drm_certificate.pb.h"
|
||||
|
||||
namespace widevine {
|
||||
namespace {
|
||||
|
||||
const int kKeyboxSizeBytes = 72;
|
||||
|
||||
} // namespace
|
||||
|
||||
// instead of ClientCert** to explicitly assigning ownership of the created
|
||||
// object to the caller.
|
||||
|
||||
Status ClientCert::Create(const DrmRootCertificate* root_certificate,
|
||||
ClientIdentification::TokenType token_type,
|
||||
const std::string& token, ClientCert** client_cert) {
|
||||
DCHECK(client_cert);
|
||||
if (token_type == ClientIdentification::KEYBOX) {
|
||||
*client_cert = nullptr;
|
||||
if (token.size() < kKeyboxSizeBytes) {
|
||||
return Status(error_space, INVALID_KEYBOX_TOKEN,
|
||||
"keybox-token-is-too-short");
|
||||
}
|
||||
return ClientCert::CreateWithKeybox(token, client_cert);
|
||||
} else if (token_type == ClientIdentification::DRM_DEVICE_CERTIFICATE) {
|
||||
return CreateWithDrmCertificate(root_certificate, token, client_cert);
|
||||
} else {
|
||||
return Status(error_space, error::UNIMPLEMENTED,
|
||||
"client-type-not-implemented");
|
||||
}
|
||||
}
|
||||
|
||||
Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
|
||||
ClientCert** client_cert) {
|
||||
CHECK(client_cert);
|
||||
*client_cert = nullptr;
|
||||
|
||||
std::unique_ptr<KeyboxClientCert> new_client_cert(new KeyboxClientCert);
|
||||
Status status = new_client_cert->Initialize(keybox_token);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
*client_cert = new_client_cert.release();
|
||||
return OkStatus();
|
||||
}
|
||||
|
||||
Status ClientCert::CreateWithDrmCertificate(
|
||||
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
|
||||
ClientCert** client_cert) {
|
||||
CHECK(client_cert);
|
||||
*client_cert = nullptr;
|
||||
|
||||
std::unique_ptr<CertificateClientCert> new_client_cert(
|
||||
new CertificateClientCert);
|
||||
Status status =
|
||||
new_client_cert->Initialize(root_certificate, drm_certificate);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
*client_cert = new_client_cert.release();
|
||||
return OkStatus();
|
||||
}
|
||||
|
||||
void ClientCert::CreateSignature(const std::string& message, std::string* signature) {
|
||||
DCHECK(signature);
|
||||
DCHECK(!signing_key().empty());
|
||||
if (signature == nullptr) {
|
||||
return;
|
||||
}
|
||||
using crypto_util::CreateSignatureHmacSha256;
|
||||
*signature =
|
||||
CreateSignatureHmacSha256(GetServerSigningKey(signing_key()), message);
|
||||
}
|
||||
|
||||
void ClientCert::GenerateSigningKey(const std::string& message,
|
||||
ProtocolVersion protocol_version) {
|
||||
if (!signing_key_.empty()) return;
|
||||
DCHECK(!key().empty());
|
||||
using crypto_util::DeriveKey;
|
||||
using crypto_util::kSigningKeyLabel;
|
||||
set_signing_key(
|
||||
DeriveKey(key(), kSigningKeyLabel,
|
||||
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
|
||||
SigningKeyMaterialSizeBits(protocol_version)));
|
||||
}
|
||||
|
||||
KeyboxClientCert::KeyboxClientCert() {}
|
||||
|
||||
KeyboxClientCert::~KeyboxClientCert() {}
|
||||
|
||||
void KeyboxClientCert::SetPreProvisioningKeys(
|
||||
const std::multimap<uint32_t, std::string>& keymap) {
|
||||
@@ -139,124 +52,50 @@ uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) {
|
||||
return WvmTokenHandler::GetSystemId(keybox_bytes);
|
||||
}
|
||||
|
||||
Status KeyboxClientCert::Initialize(const std::string& keybox_bytes) {
|
||||
if (keybox_bytes.size() < kKeyboxSizeBytes) {
|
||||
return Status(error_space, INVALID_KEYBOX_TOKEN,
|
||||
"keybox-token-is-too-short");
|
||||
}
|
||||
Status ClientCert::Create(
|
||||
const DrmRootCertificate* root_certificate,
|
||||
widevine::ClientIdentification::TokenType token_type,
|
||||
const std::string& token, std::unique_ptr<ClientCert>* client_cert) {
|
||||
CHECK(client_cert);
|
||||
Status status;
|
||||
switch (token_type) {
|
||||
case ClientIdentification::KEYBOX:
|
||||
return CreateWithKeybox(token, client_cert);
|
||||
|
||||
set_system_id(WvmTokenHandler::GetSystemId(keybox_bytes));
|
||||
set_serial_number(WvmTokenHandler::GetEncryptedUniqueId(keybox_bytes));
|
||||
bool insecure_keybox = false;
|
||||
Status status = WvmTokenHandler::DecryptDeviceKey(keybox_bytes, &device_key_,
|
||||
nullptr, &insecure_keybox);
|
||||
if (!status.ok()) {
|
||||
Errors new_code = status.error_code() == error::NOT_FOUND
|
||||
? MISSING_PRE_PROV_KEY
|
||||
: KEYBOX_DECRYPT_ERROR;
|
||||
return Status(error_space, new_code, status.error_message());
|
||||
case ClientIdentification::DRM_DEVICE_CERTIFICATE:
|
||||
return CreateWithDrmCertificate(root_certificate, token, client_cert);
|
||||
|
||||
default:
|
||||
return Status(error_space, error::UNIMPLEMENTED,
|
||||
"client-type-not-implemented");
|
||||
}
|
||||
return OkStatus();
|
||||
}
|
||||
|
||||
Status KeyboxClientCert::VerifySignature(const std::string& message,
|
||||
const std::string& signature,
|
||||
ProtocolVersion protocol_version) {
|
||||
DCHECK(!signing_key().empty());
|
||||
using crypto_util::VerifySignatureHmacSha256;
|
||||
if (!VerifySignatureHmacSha256(
|
||||
GetClientSigningKey(signing_key(), protocol_version), signature,
|
||||
message)) {
|
||||
return Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac");
|
||||
// Creates a Device Certificate based ClientCert. The |client_cert| is a
|
||||
// caller supplied unique_ptr to receive the new ClientCert.
|
||||
Status ClientCert::CreateWithDrmCertificate(
|
||||
const DrmRootCertificate* root_certificate,
|
||||
const std::string& drm_certificate,
|
||||
std::unique_ptr<ClientCert>* client_cert) {
|
||||
CHECK(client_cert);
|
||||
auto device_cert = absl::make_unique<CertificateClientCert>();
|
||||
Status status = device_cert->Initialize(root_certificate, drm_certificate);
|
||||
if (status.ok()) {
|
||||
*client_cert = std::move(device_cert);
|
||||
}
|
||||
return OkStatus();
|
||||
return status;
|
||||
}
|
||||
|
||||
CertificateClientCert::CertificateClientCert() {}
|
||||
|
||||
CertificateClientCert::~CertificateClientCert() {}
|
||||
|
||||
Status CertificateClientCert::Initialize(
|
||||
const DrmRootCertificate* drm_root_certificate,
|
||||
const std::string& serialized_certificate) {
|
||||
CHECK(drm_root_certificate);
|
||||
|
||||
SignedDrmCertificate signed_device_cert;
|
||||
DrmCertificate device_cert;
|
||||
Status status = drm_root_certificate->VerifyCertificate(
|
||||
serialized_certificate, &signed_device_cert, &device_cert);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
|
||||
std::unique_ptr<ClientCert>* client_cert) {
|
||||
CHECK(client_cert);
|
||||
auto kbx_cert = absl::make_unique<KeyboxClientCert>();
|
||||
Status status = kbx_cert->Initialize(keybox_token);
|
||||
if (status.ok()) {
|
||||
*client_cert = std::move(kbx_cert);
|
||||
}
|
||||
|
||||
const SignedDrmCertificate& signer = signed_device_cert.signer();
|
||||
DrmCertificate model_certificate;
|
||||
if (!model_certificate.ParseFromString(signer.drm_certificate())) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"drm-certificate-invalid-signer");
|
||||
}
|
||||
if (!model_certificate.has_serial_number()) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"missing-signer-serial-number");
|
||||
}
|
||||
// Check to see if this model certificate is signed by a
|
||||
// provisioner (entity using Widevine Provisioning Server SDK).
|
||||
if (signer.has_signer()) {
|
||||
DrmCertificate provisioner_certificate;
|
||||
if (!provisioner_certificate.ParseFromString(
|
||||
signer.signer().drm_certificate())) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"model-certificate-invalid-signer");
|
||||
}
|
||||
if (provisioner_certificate.type() == DrmCertificate::PROVISIONER) {
|
||||
set_signed_by_provisioner(true);
|
||||
} else {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"expected-provisioning-provider-certificate-type");
|
||||
}
|
||||
if (!provisioner_certificate.has_provider_id() ||
|
||||
provisioner_certificate.provider_id().empty()) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"missing-provisioning-service-id");
|
||||
}
|
||||
set_service_id(provisioner_certificate.provider_id());
|
||||
}
|
||||
set_signer_serial_number(model_certificate.serial_number());
|
||||
set_signer_creation_time_seconds(model_certificate.creation_time_seconds());
|
||||
if (!model_certificate.has_system_id()) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"model-certificate-missing-system-id");
|
||||
}
|
||||
set_system_id(model_certificate.system_id());
|
||||
set_serial_number(device_cert.serial_number());
|
||||
set_public_key(device_cert.public_key());
|
||||
rsa_public_key_.reset(RsaPublicKey::Create(public_key()));
|
||||
if (rsa_public_key_ == nullptr) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"drm-certificate-public-key-failed");
|
||||
}
|
||||
|
||||
// TODO(user): Move this somewhere else. It is license protocol.
|
||||
set_key(Random16Bytes());
|
||||
if (!rsa_public_key_->Encrypt(key(), &encrypted_session_key_)) {
|
||||
return Status(error_space, ENCRYPT_ERROR,
|
||||
"drm-certificate-failed-encrypt-session-key");
|
||||
}
|
||||
|
||||
return OkStatus();
|
||||
}
|
||||
|
||||
Status CertificateClientCert::VerifySignature(
|
||||
const std::string& message, const std::string& signature,
|
||||
ProtocolVersion protocol_version) {
|
||||
CHECK(rsa_public_key_);
|
||||
|
||||
if (!rsa_public_key_->VerifySignature(
|
||||
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
|
||||
signature)) {
|
||||
return Status(error_space, INVALID_SIGNATURE, "");
|
||||
}
|
||||
return OkStatus();
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
Reference in New Issue
Block a user