7 #include "packager/media/base/playready_key_source.h" 11 #include "packager/base/base64.h" 12 #include "packager/base/logging.h" 13 #include "packager/base/strings/string_number_conversions.h" 14 #include "packager/base/strings/string_util.h" 15 #include "packager/media/base/buffer_writer.h" 16 #include "packager/media/base/http_key_fetcher.h" 17 #include "packager/media/base/key_source.h" 18 #include "packager/media/base/protection_system_ids.h" 19 #include "packager/status_macros.h" 26 const uint32_t kHttpFetchTimeout = 60;
27 const std::string kAcquireLicenseRequest =
28 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 29 "<soap:Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" " 30 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " 31 "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " 32 "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" 34 "<AcquirePackagingData " 35 "xmlns=\"http://schemas.microsoft.com/DRM/2007/03/protocols\">" 37 "xmlns=\"http://schemas.microsoft.com/DRM" 38 "/2007/03/protocols/AcquirePackagingData/v1.0\">" 40 "<ProtectionSystemId>9A04F079-9840-4286-AB92-E65BE0885F95" 41 "</ProtectionSystemId>" 42 "</ProtectionSystems>" 43 "<StreamProtectionRequests>" 45 "<ProgramIdentifier>$0</ProgramIdentifier>" 46 "<OffsetFromProgramStart>P0S</OffsetFromProgramStart>" 47 "</StreamInformation>" 48 "</StreamProtectionRequests>" 50 "</AcquirePackagingData>" 54 bool Base64StringToBytes(
const std::string& base64_string,
55 std::vector<uint8_t>* bytes) {
58 if (!base::Base64Decode(base64_string, &str))
60 bytes->assign(str.begin(), str.end());
66 int protection_system_flags,
67 FourCC protection_scheme)
69 :
KeySource(protection_system_flags & ~PLAYREADY_PROTECTION_SYSTEM_FLAG,
71 generate_playready_protection_system_(
74 protection_system_flags == NO_PROTECTION_SYSTEM_FLAG ||
75 protection_system_flags & PLAYREADY_PROTECTION_SYSTEM_FLAG),
77 server_url_(server_url) {}
80 const std::string& server_url,
81 const std::string& client_cert_file,
82 const std::string& client_cert_private_key_file,
83 const std::string& client_cert_private_key_password,
84 int protection_system_flags,
85 FourCC protection_scheme)
87 :
KeySource(protection_system_flags & ~PLAYREADY_PROTECTION_SYSTEM_FLAG,
90 server_url_(server_url),
91 client_cert_file_(client_cert_file),
92 client_cert_private_key_file_(client_cert_private_key_file),
93 client_cert_private_key_password_(client_cert_private_key_password) {}
95 PlayReadyKeySource::~PlayReadyKeySource() =
default;
97 Status RetrieveTextInXMLElement(
const std::string& element,
98 const std::string& xml,
100 std::string start_tag =
"<" + element +
">";
101 std::string end_tag =
"</" + element +
">";
102 std::size_t start_pos = xml.find(start_tag);
103 if (start_pos == std::string::npos) {
104 return Status(error::SERVER_ERROR,
105 "Unable to find tag: " + start_tag);
107 start_pos += start_tag.size();
108 std::size_t end_pos = xml.find(end_tag);
109 if (end_pos == std::string::npos) {
110 return Status(error::SERVER_ERROR,
111 "Unable to find tag: " + end_tag);
113 if (start_pos > end_pos) {
114 return Status(error::SERVER_ERROR,
"Invalid positions");
116 std::size_t segment_len = end_pos - start_pos;
117 *value = xml.substr(start_pos, segment_len);
121 Status SetKeyInformationFromServerResponse(
122 const std::string& response,
123 bool generate_playready_protection_system,
129 std::string key_id_hex;
130 RETURN_IF_ERROR(RetrieveTextInXMLElement(
"KeyId", response, &key_id_hex));
132 std::remove(key_id_hex.begin(), key_id_hex.end(),
'-'), key_id_hex.end());
133 if (!base::HexStringToBytes(key_id_hex, &encryption_key->key_id)) {
134 LOG(ERROR) <<
"Cannot parse key_id_hex, " << key_id_hex;
135 return Status(error::SERVER_ERROR,
"Cannot parse key_id_hex.");
138 std::string key_data_b64;
139 RETURN_IF_ERROR(RetrieveTextInXMLElement(
"KeyData", response, &key_data_b64));
140 if (!Base64StringToBytes(key_data_b64, &encryption_key->key)) {
141 LOG(ERROR) <<
"Cannot parse key, " << key_data_b64;
142 return Status(error::SERVER_ERROR,
"Cannot parse key.");
145 if (generate_playready_protection_system) {
146 std::string pssh_data_b64;
147 RETURN_IF_ERROR(RetrieveTextInXMLElement(
"Data", response, &pssh_data_b64));
148 std::vector<uint8_t> pssh_data;
149 if (!Base64StringToBytes(pssh_data_b64, &pssh_data)) {
150 LOG(ERROR) <<
"Cannot parse pssh data, " << pssh_data_b64;
151 return Status(error::SERVER_ERROR,
"Cannot parse pssh.");
155 pssh_builder.add_key_id(encryption_key->key_id);
156 pssh_builder.set_system_id(kPlayReadySystemId,
157 arraysize(kPlayReadySystemId));
158 pssh_builder.set_pssh_data(pssh_data);
159 encryption_key->key_system_info.push_back(
160 {pssh_builder.system_id(), pssh_builder.
CreateBox()});
165 Status PlayReadyKeySource::FetchKeysWithProgramIdentifier(
166 const std::string& program_identifier) {
167 std::unique_ptr<EncryptionKey> encryption_key(
new EncryptionKey);
169 if (!client_cert_file_.empty() && !client_cert_private_key_file_.empty()) {
171 client_cert_private_key_file_,
172 client_cert_private_key_password_);
174 if (!ca_file_.empty()) {
178 std::string acquire_license_request = kAcquireLicenseRequest;
179 base::ReplaceFirstSubstringAfterOffset(
180 &acquire_license_request, 0,
"$0", program_identifier);
181 std::string acquire_license_response;
182 Status status = key_fetcher.
FetchKeys(server_url_, acquire_license_request,
183 &acquire_license_response);
184 VLOG(1) <<
"Server response: " << acquire_license_response;
185 RETURN_IF_ERROR(status);
187 RETURN_IF_ERROR(SetKeyInformationFromServerResponse(
188 acquire_license_response, generate_playready_protection_system_,
189 encryption_key.get()));
192 const char kEmptyDrmLabel[] =
"";
193 EncryptionKeyMap encryption_key_map;
194 encryption_key_map[kEmptyDrmLabel] = std::move(encryption_key);
196 encryption_key_ = std::move(encryption_key_map[kEmptyDrmLabel]);
201 const std::vector<uint8_t>& init_data) {
212 DCHECK(encryption_key_);
213 *key = *encryption_key_;
222 DCHECK(encryption_key_);
223 *key = *encryption_key_;
228 const std::string& stream_label,
231 *key = *encryption_key_;
All the methods that are virtual are virtual for mocking.