Export media_cas_packager_sdk
This commit is contained in:
261
common/remote_attestation_verifier.cc
Normal file
261
common/remote_attestation_verifier.cc
Normal file
@@ -0,0 +1,261 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 Google LLC.
|
||||
//
|
||||
// This software is licensed under the terms defined in the Widevine Master
|
||||
// License Agreement. For a copy of this agreement, please contact
|
||||
// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "common/remote_attestation_verifier.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <memory>
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "common/client_id_util.h"
|
||||
#include "common/drm_service_certificate.h"
|
||||
#include "common/error_space.h"
|
||||
#include "common/rsa_key.h"
|
||||
#include "protos/public/client_identification.pb.h"
|
||||
#include "protos/public/errors.pb.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
const char kTestRootCaDerCert[] =
|
||||
"30820403308202eba003020102020900a24f94af7ae6831f300d06092a86"
|
||||
"4886f70d0101050500308197310b30090603550406130255533113301106"
|
||||
"035504080c0a57617368696e67746f6e3111300f06035504070c084b6972"
|
||||
"6b6c616e6431133011060355040a0c0a476f6f676c6520496e633111300f"
|
||||
"060355040b0c085769646576696e653115301306035504030c0c54657374"
|
||||
"20526f6f742043413121301f06092a864886f70d010901161274696e736b"
|
||||
"697040676f6f676c652e636f6d301e170d3133303831363030353731305a"
|
||||
"170d3333303831353030353731305a308197310b30090603550406130255"
|
||||
"533113301106035504080c0a57617368696e67746f6e3111300f06035504"
|
||||
"070c084b69726b6c616e6431133011060355040a0c0a476f6f676c652049"
|
||||
"6e633111300f060355040b0c085769646576696e65311530130603550403"
|
||||
"0c0c5465737420526f6f742043413121301f06092a864886f70d01090116"
|
||||
"1274696e736b697040676f6f676c652e636f6d30820122300d06092a8648"
|
||||
"86f70d01010105000382010f003082010a0282010100c6eee629d99f7736"
|
||||
"2db5545ed1d6dfb3616c742c617d5fd48f2fbfcb3f2ec40a080bd04d551c"
|
||||
"e519471a8bb4ec5c2c75bf8a2d2caf3f85d90e9e39391dfbdaae68051319"
|
||||
"0da71b1b2ae4829a15c44bc1b19b17134844b94c6f06d9216333236574f3"
|
||||
"f11b0d10c3c621410e42630c57ce9e901057eda5c3c2203ee2ad805a0d93"
|
||||
"52fa91da45a6f4875b4524c193c42fd9048a10204e5b2c8203402ba760e7"
|
||||
"e1b4126c3e2ab4258f2bf28cd3170de8c738a6a1f4cfcc0649fa95f1414f"
|
||||
"d9d09dd4f511bc0a9bf3a5844a334d9e0a4b9525d2789be6abafe2d0cc20"
|
||||
"79dcf030ffa9be8ae3fe2cab4ebdfa494d48aa8c63264d31e2208a9c28f7"
|
||||
"3e0103ce164683bf0203010001a350304e301d0603551d0e041604144d30"
|
||||
"ff181ac4f10da99e6a12c01e02accadf840a301f0603551d230418301680"
|
||||
"144d30ff181ac4f10da99e6a12c01e02accadf840a300c0603551d130405"
|
||||
"30030101ff300d06092a864886f70d01010505000382010100779e9b98d3"
|
||||
"ec066f29862903a00e9c98259d987c04b9e6a2e6c3381ee59ec1dd0d7dee"
|
||||
"79da612e4dfaa3465c8916993ed7adebb27340de20ca101067f8342b2124"
|
||||
"ec0d5db531277b4653c3bc72b2a8daeae120e5348e1a338f6e68e7129436"
|
||||
"026e78024f04d766b132252ec152402dcec28174346aa0ba997d7f1af140"
|
||||
"ff025bec841f8039ba10d7cc098cf24554f8cbb2aa31875205c67df2f053"
|
||||
"0d8784faf63c4f945e62da374cad6155e6ae44f597bcff4566ea2aac4258"
|
||||
"e4ae81569c0eddd1df6929532b4538bd204b2ff5847cb46ac7383c96fe82"
|
||||
"d22de9a13c5092c92c297021c51a2a0a5250cf26c271ff262f25a7738ae4"
|
||||
"c270d87191c13aefdd177b";
|
||||
|
||||
const char kProdRootCaDerCert[] =
|
||||
"30820408308202f0a003020102020101300d06092a864886f70d01010505"
|
||||
"00307d311830160603550403130f5072697661637920434120526f6f7431"
|
||||
"123010060355040b13094368726f6d65204f5331133011060355040a130a"
|
||||
"476f6f676c6520496e63311630140603550407130d4d6f756e7461696e20"
|
||||
"56696577311330110603550408130a43616c69666f726e6961310b300906"
|
||||
"0355040613025553301e170d3133303231383130313334325a170d333330"
|
||||
"3231333130313334325a307d311830160603550403130f50726976616379"
|
||||
"20434120526f6f7431123010060355040b13094368726f6d65204f533113"
|
||||
"3011060355040a130a476f6f676c6520496e63311630140603550407130d"
|
||||
"4d6f756e7461696e2056696577311330110603550408130a43616c69666f"
|
||||
"726e6961310b300906035504061302555330820122300d06092a864886f7"
|
||||
"0d01010105000382010f003082010a0282010100e10ea6819d3d066b421d"
|
||||
"d7612de3eef9599f5d9a2a24bfd09caab543511cf22f615e29f989425a65"
|
||||
"7396bf33603747719cfb0b4240cd682c7c558fec0176b4793be440752246"
|
||||
"83648f5b12d02a838a2a8e55a4b645ed0a4a52b19252a23d34bf64a17ac7"
|
||||
"11fe93a889086d943211b17d670f96442c9f367d38026000da79664e600e"
|
||||
"e9259348f4fd74108e973d561e624e9f5eda77a085a6eb15fadb2cc7787c"
|
||||
"7f30ef3b196f2a416a76fa9eb30d65753f5039d97bea70e82431d2962396"
|
||||
"a34864f33b74d60707fea794c03c82e547abc2407fa7bad67bd09cdab49b"
|
||||
"26e68754994d12a3845dbeceffe18de0d51fc6fa78676d89ea1e0fcff931"
|
||||
"59bfb809519b0203010001a3819230818f30290603551d0e042204204b1d"
|
||||
"148aa5380938812ed6a763f5dc2c318610d5fa9604d609cb2e0d8cec3289"
|
||||
"302b0603551d230424302280204b1d148aa5380938812ed6a763f5dc2c31"
|
||||
"8610d5fa9604d609cb2e0d8cec3289300e0603551d0f0101ff0404030201"
|
||||
"06300f0603551d130101ff040530030101ff30140603551d200101ff040a"
|
||||
"300830060604551d2000300d06092a864886f70d01010505000382010100"
|
||||
"c40d84bc8d609b1b68b3caa7e841021838d7e392557d40debab3e0685e72"
|
||||
"80541092dc913b0aa6150228d8fe5ab08cceefbac56952fa00ba614294d1"
|
||||
"ba4fa170c86b27f9bf58666c46940f740c4be2795501b25e40b9702af07c"
|
||||
"884926bd8beed036c503e5e42a223ff36271404ca4360a93dec92a02fd8d"
|
||||
"ae8f756fc68aaa647e2159f0a7a95d1446e92362bd512f59daec02c5d152"
|
||||
"c301b9807db998ba70c616364762a0a497aaa92eb7d92f3635169d3f74c6"
|
||||
"40c738941759a8ab43677b80329d015bdcf8922b779a80f85f1e4a677659"
|
||||
"c60de80152e8c526a7de46cac143a75af58f0806de81e15c97f616e1bffa"
|
||||
"1c1c6b0d2438543bdfb2a21bd9bc7ae4";
|
||||
|
||||
const char kServiceIdFieldName[] = "OU";
|
||||
const char kDeviceModeFieldName[] = "O";
|
||||
const char kExpectedDeviceMode[] = "Chrome Device Content Protection";
|
||||
|
||||
RemoteAttestationVerifier& RemoteAttestationVerifier::get() {
|
||||
static RemoteAttestationVerifier instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void RemoteAttestationVerifier::EnableTestCertificates(bool enable) {
|
||||
absl::WriterMutexLock lock(&ca_mutex_);
|
||||
enable_test_certificates_ = enable;
|
||||
ca_.reset();
|
||||
}
|
||||
|
||||
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
||||
std::string* remote_attestation_cert_sn) {
|
||||
DCHECK(remote_attestation_cert_sn);
|
||||
|
||||
// Sanity check RemoteAttestation.
|
||||
if (!remote_attestation.has_certificate()) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
"remote-attestation-certificate-missing"));
|
||||
}
|
||||
if (!remote_attestation.has_salt()) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
"remote-attestation-salt-missing"));
|
||||
}
|
||||
if (!remote_attestation.has_signature()) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
"remote-attestation-signature-missing"));
|
||||
}
|
||||
// Decrypt ClientIdentification containing remote attestation certificate.
|
||||
// A service cert would be looked up first, then that cert will be used
|
||||
// to decrypt the ClientIdentification.
|
||||
ClientIdentification client_id;
|
||||
util::Status status = DrmServiceCertificate::DecryptClientIdentification(
|
||||
remote_attestation.certificate(), &client_id);
|
||||
if (!status.ok()) return status;
|
||||
|
||||
if (client_id.type() !=
|
||||
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
std::string("remote-attestation-invalid-client-id-type (") +
|
||||
absl::StrCat(client_id.type()) + ")"));
|
||||
}
|
||||
return VerifyRemoteAttestation(message, remote_attestation, client_id,
|
||||
remote_attestation_cert_sn);
|
||||
}
|
||||
|
||||
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
||||
const std::string& privacy_key) {
|
||||
// Sanity check RemoteAttestation.
|
||||
if (!remote_attestation.has_certificate()) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
"remote-attestation-certificate-missing"));
|
||||
}
|
||||
if (!remote_attestation.has_salt()) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
"remote-attestation-salt-missing"));
|
||||
}
|
||||
if (!remote_attestation.has_signature()) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
"remote-attestation-signature-missing"));
|
||||
}
|
||||
// Decrypt ClientIdentification containing remote attestation certificate,
|
||||
// directly using an explicitly provided key |privacy_key|.
|
||||
ClientIdentification client_id;
|
||||
util::Status status = DecryptEncryptedClientIdentification(
|
||||
remote_attestation.certificate(), privacy_key, &client_id);
|
||||
if (!status.ok()) return status;
|
||||
|
||||
if (client_id.type() !=
|
||||
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
std::string("remote-attestation-invalid-client-id-type (") +
|
||||
absl::StrCat(client_id.type()) + ")"));
|
||||
}
|
||||
std::string remote_attestation_cert_sn;
|
||||
return VerifyRemoteAttestation(message, remote_attestation, client_id,
|
||||
&remote_attestation_cert_sn);
|
||||
}
|
||||
|
||||
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
||||
const ClientIdentification& client_id, std::string* remote_attestation_cert_sn) {
|
||||
if (!client_id.has_token()) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
"remote-attestation-token-missing"));
|
||||
}
|
||||
// Load and verify the certificate chain.
|
||||
std::unique_ptr<X509CertChain> cert_chain(new X509CertChain);
|
||||
util::Status status = cert_chain->LoadPem(client_id.token());
|
||||
if (!status.ok()) return status;
|
||||
|
||||
if (cert_chain->GetNumCerts() < 1) {
|
||||
return (util::Status(error_space, INVALID_MESSAGE,
|
||||
"remote-attestation-empty-certificate-chain"));
|
||||
}
|
||||
std::string device_mode_string =
|
||||
cert_chain->GetCert(0)->GetSubjectNameField(kDeviceModeFieldName);
|
||||
if (device_mode_string != kExpectedDeviceMode) {
|
||||
return (util::Status(error_space, REMOTE_ATTESTATION_FAILED,
|
||||
std::string("remote-attestation-device-not-verified (") +
|
||||
device_mode_string + " / " + kDeviceModeFieldName +
|
||||
")"));
|
||||
}
|
||||
ca_mutex_.ReaderLock();
|
||||
if (ca_ == NULL) {
|
||||
ca_mutex_.ReaderUnlock();
|
||||
status = LoadCa();
|
||||
if (!status.ok()) return status;
|
||||
ca_mutex_.ReaderLock();
|
||||
}
|
||||
status = ca_->VerifyCertChain(*cert_chain);
|
||||
ca_mutex_.ReaderUnlock();
|
||||
if (!status.ok()) {
|
||||
return (util::Status(
|
||||
error_space, REMOTE_ATTESTATION_FAILED,
|
||||
std::string("remote-attestation-cert-chain-validation-failed: ") +
|
||||
status.error_message()));
|
||||
}
|
||||
// Verify the remote attestation signature.
|
||||
std::unique_ptr<RsaPublicKey> leaf_key;
|
||||
std::string message_with_salt = message + remote_attestation.salt();
|
||||
for (size_t idx = 0; idx < cert_chain->GetNumCerts(); ++idx) {
|
||||
if (!cert_chain->GetCert(idx)->IsCaCertificate()) {
|
||||
leaf_key = cert_chain->GetCert(idx)->GetRsaPublicKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!leaf_key) {
|
||||
return util::Status(error_space, REMOTE_ATTESTATION_FAILED,
|
||||
"remote-attestation-cert-chain-no-leaf");
|
||||
}
|
||||
|
||||
if (!leaf_key->VerifySignatureSha256Pkcs7(message_with_salt,
|
||||
remote_attestation.signature())) {
|
||||
return (util::Status(error_space, REMOTE_ATTESTATION_FAILED,
|
||||
"remote-attestation-signature-verification-failed: "));
|
||||
}
|
||||
|
||||
*remote_attestation_cert_sn = cert_chain->GetCert(0)->GetSerialNumber();
|
||||
return util::OkStatus();
|
||||
}
|
||||
|
||||
util::Status RemoteAttestationVerifier::LoadCa() {
|
||||
absl::WriterMutexLock lock(&ca_mutex_);
|
||||
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||
util::Status status = ca_cert->LoadDer(absl::HexStringToBytes(
|
||||
enable_test_certificates_ ? kTestRootCaDerCert : kProdRootCaDerCert));
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
ca_.reset(new X509CA(ca_cert.release()));
|
||||
return util::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
Reference in New Issue
Block a user