Files
android/libwvdrmengine/cdm/core/include/certificate_provisioning.h
Alex Dale b0fa978058 Added state to CertificateProvisioning.
[ Cherry-pick of v19 http://go/wvgerrit/219310 ]
[ Merge of http://go/wvgerrit/219453 ]

To enable the CDM to determine between OEM vs DRM responses,
a state variable was needed in CertificateProvisioning.
Previously, the presence/absence of the OEM certificate in the
file system was used; however, if two apps (or single app with
multiple origins) attempts provisioning simultaneously, the
later response would trigger unexpected failures.

The main functional changes this provides is that a more informative
error will be returned to the app if they provide a provisioning
response without ever creating a provisioning request; and that
if multiple clients attempted first-stage provisioning simultaneously,
fewer errors will occur.

Bug: 391469176
Test: run_prov40_tests
Change-Id: I51a118ce73aa809bad6ecee640139a92d8518575
2025-04-21 17:08:24 -07:00

169 lines
6.6 KiB
C++

// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#ifndef WVCDM_CORE_CERTIFICATE_PROVISIONING_H_
#define WVCDM_CORE_CERTIFICATE_PROVISIONING_H_
#include <memory>
#include <string>
#include "crypto_session.h"
#include "disallow_copy_and_assign.h"
#include "license_protocol.pb.h"
#include "metrics_collections.h"
#include "oemcrypto_adapter.h"
#include "service_certificate.h"
#include "wv_cdm_types.h"
namespace wvutil {
class FileSystem;
}
namespace wvcdm {
class CdmClientPropertySet;
class CdmSession;
class ServiceCertificate;
class CertificateProvisioning {
public:
CertificateProvisioning(metrics::CryptoMetrics* metrics)
: crypto_session_(CryptoSession::MakeCryptoSession(metrics)),
cert_type_(kCertificateWidevine),
service_certificate_(new ServiceCertificate()) {}
~CertificateProvisioning() {}
CdmResponseType Init(const std::string& service_certificate);
// Construct a valid provisioning request.
// The request will be sent to the provisioning server.
CdmResponseType GetProvisioningRequest(
wvutil::FileSystem* file_system,
RequestedSecurityLevel requested_security_level,
CdmCertificateType cert_type, const std::string& cert_authority,
const std::string& origin, const std::string& spoid,
CdmProvisioningRequest* request, std::string* default_url);
// Process the provisioning response.
CdmResponseType HandleProvisioningResponse(
wvutil::FileSystem* file_system, const CdmProvisioningResponse& response,
std::string* cert, std::string* wrapped_key);
// Helper methods
// Extract serial number and system ID from a DRM Device certificate.
// Either |serial_number| or |system_id| may be null, but not both.
// Both |creation_time_seconds| and |expiration_time_seconds| may be null.
// |creation_time_seconds| and |expiration_time_seconds| will be set to -1
// if not present, 0 if unlimited and a valid time otherwise
static bool ExtractDeviceInfo(const std::string& device_certificate,
std::string* serial_number, uint32_t* system_id,
int64_t* creation_time_seconds,
int64_t* expiration_time_seconds);
// Removes json wrapping if applicable to extract the
// SignedProvisioningMessage
static bool ExtractAndDecodeSignedMessage(
const std::string& provisioning_response, std::string* result);
// Retrieve the provisioning server URL used for certificate
// provisioning. This will be the same value as returned in
// |default_url| by GetProvisioningRequest().
static void GetProvisioningServerUrl(std::string* default_url);
enum State {
// Freshly created, not yet initialized.
kUninitialized,
// A successful call to Init() has been made.
kInitialized,
// Has generated a DRM request; apps are allowed generate
// another one even if a response has not been received.
kDrmRequestSent,
// Has received (and successfully loaded) a DRM response.
kDrmResponseReceived,
// Has generated an OEM (Prov 4.0) request; apps are allowed
// generate another one even if a response has not been
// received.
kOemRequestSent,
// Has received (and successfully loaded) an OEM response.
kOemResponseReceived,
};
static const char* StateToString(State state);
// State setter for testing only.
void SetStateForTesting(State state) { state_ = state; }
private:
#if defined(UNIT_TEST)
friend class CertificateProvisioningTest;
#endif
CdmResponseType GetProvisioningRequestInternal(
wvutil::FileSystem* file_system,
RequestedSecurityLevel requested_security_level,
CdmCertificateType cert_type, const std::string& cert_authority,
const std::string& origin, const std::string& spoid,
CdmProvisioningRequest* request, std::string* default_url);
CdmResponseType GetProvisioning40RequestInternal(
wvutil::FileSystem* file_system, const std::string& origin,
const std::string& spoid, CdmProvisioningRequest* request,
std::string* default_url, CdmCertificateType cert_type,
const std::string& cert_authority);
CdmResponseType FillEncryptedClientId(
const std::string& client_token,
video_widevine::ProvisioningRequest& provisioning_request,
const ServiceCertificate& service_certificate);
CdmResponseType FillEncryptedClientIdWithAdditionalParameter(
const std::string& client_token,
const CdmAppParameterMap& additional_parameter,
video_widevine::ProvisioningRequest& provisioning_request,
const ServiceCertificate& service_certificate);
CdmResponseType HandleProvisioning40Response(
wvutil::FileSystem* file_system,
const video_widevine::SignedProvisioningMessage& signed_message,
std::string* cert, std::string* wrapped_key);
// Assign the cert type for provisioning request
// Required by Cast cert provisioning flow
CdmResponseType CertTypeAssign(
video_widevine::ProvisioningRequest& provisioning_request,
CdmCertificateType cert_type, const std::string& cert_authority);
CdmResponseType SetSpoidParameter(
const std::string& origin, const std::string& spoid,
video_widevine::ProvisioningRequest* request);
video_widevine::SignedProvisioningMessage::ProvisioningType
GetProvisioningType();
// Closes crypto session if one is open. Avoid calling this method when
// processing a response. Multiple provisioning responses might be
// simultaneously in flight. Only the response associated with the last
// provisioning request can be processed. All the other responses will
// fail. If the session is closed when these responses fail, even the one
// associated with the last provisioning request may fail.
CdmResponseType CloseSessionOnError(CdmResponseType status);
void CloseSession();
// Tracks the state of CertificateProvisioning.
State state_ = kUninitialized;
std::unique_ptr<CryptoSession> crypto_session_;
CdmCertificateType cert_type_;
std::unique_ptr<ServiceCertificate> service_certificate_;
std::string request_;
// The wrapped private key in provisioning 4 generated by calling
// GenerateCertificateKeyPair. It will be saved to file system if a valid
// response is received.
std::string provisioning_40_wrapped_private_key_;
// Key type of the generated key pair in provisioning 4.
CryptoWrappedKey::Type provisioning_40_key_type_;
// Store the last provisioning request message
std::string provisioning_request_message_;
CORE_DISALLOW_COPY_AND_ASSIGN(CertificateProvisioning);
};
} // namespace wvcdm
#endif // WVCDM_CORE_CERTIFICATE_PROVISIONING_H_