OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/cdm/json_web_key.h" | 5 #include "media/cdm/json_web_key.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
9 #include "base/json/json_string_value_serializer.h" | 9 #include "base/json/json_string_value_serializer.h" |
10 #include "base/json/string_escape.h" | 10 #include "base/json/string_escape.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/strings/string_number_conversions.h" |
13 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
14 #include "base/values.h" | 15 #include "base/values.h" |
15 | 16 |
16 namespace media { | 17 namespace media { |
17 | 18 |
18 const char kKeysTag[] = "keys"; | 19 const char kKeysTag[] = "keys"; |
19 const char kKeyTypeTag[] = "kty"; | 20 const char kKeyTypeTag[] = "kty"; |
20 const char kKeyTypeOct[] = "oct"; // Octet sequence. | 21 const char kKeyTypeOct[] = "oct"; // Octet sequence. |
21 const char kAlgTag[] = "alg"; | 22 const char kAlgTag[] = "alg"; |
22 const char kAlgA128KW[] = "A128KW"; // AES key wrap using a 128-bit key. | 23 const char kAlgA128KW[] = "A128KW"; // AES key wrap using a 128-bit key. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 | 82 |
82 std::string decoded_text; | 83 std::string decoded_text; |
83 if (!base::Base64Decode(modified_text, &decoded_text)) { | 84 if (!base::Base64Decode(modified_text, &decoded_text)) { |
84 DVLOG(1) << "Base64 decoding failed on: " << modified_text; | 85 DVLOG(1) << "Base64 decoding failed on: " << modified_text; |
85 return std::string(); | 86 return std::string(); |
86 } | 87 } |
87 | 88 |
88 return decoded_text; | 89 return decoded_text; |
89 } | 90 } |
90 | 91 |
| 92 static std::string ShortenTo64Characters(const std::string& input) { |
| 93 // Convert |input| into a string with escaped characters replacing any |
| 94 // non-ASCII characters. Limiting |input| to the first 65 characters so |
| 95 // we don't waste time converting a potentially long string and then |
| 96 // throwing away the excess. |
| 97 std::string escaped_str = |
| 98 base::EscapeBytesAsInvalidJSONString(input.substr(0, 65), false); |
| 99 if (escaped_str.length() <= 64u) |
| 100 return escaped_str; |
| 101 |
| 102 // This may end up truncating an escaped character, but the first part of |
| 103 // the string should provide enough information. |
| 104 return escaped_str.substr(0, 61).append("..."); |
| 105 } |
| 106 |
91 std::string GenerateJWKSet(const uint8* key, int key_length, | 107 std::string GenerateJWKSet(const uint8* key, int key_length, |
92 const uint8* key_id, int key_id_length) { | 108 const uint8* key_id, int key_id_length) { |
93 // Both |key| and |key_id| need to be base64 encoded strings in the JWK. | 109 // Both |key| and |key_id| need to be base64 encoded strings in the JWK. |
94 std::string key_base64 = EncodeBase64Url(key, key_length); | 110 std::string key_base64 = EncodeBase64Url(key, key_length); |
95 std::string key_id_base64 = EncodeBase64Url(key_id, key_id_length); | 111 std::string key_id_base64 = EncodeBase64Url(key_id, key_id_length); |
96 | 112 |
97 // Create the JWK, and wrap it into a JWK Set. | 113 // Create the JWK, and wrap it into a JWK Set. |
98 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue()); | 114 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue()); |
99 jwk->SetString(kKeyTypeTag, kKeyTypeOct); | 115 jwk->SetString(kKeyTypeTag, kKeyTypeOct); |
100 jwk->SetString(kAlgTag, kAlgA128KW); | 116 jwk->SetString(kAlgTag, kAlgA128KW); |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 } else { | 235 } else { |
220 DVLOG(1) << "Invalid '" << kTypeTag << "' value: " << session_type_id; | 236 DVLOG(1) << "Invalid '" << kTypeTag << "' value: " << session_type_id; |
221 return false; | 237 return false; |
222 } | 238 } |
223 | 239 |
224 // All done. | 240 // All done. |
225 keys->swap(local_keys); | 241 keys->swap(local_keys); |
226 return true; | 242 return true; |
227 } | 243 } |
228 | 244 |
| 245 bool ExtractKeyIdsFromKeyIdsInitData(const std::string& input, |
| 246 KeyIdList* key_ids, |
| 247 std::string* error_message) { |
| 248 if (!base::IsStringASCII(input)) { |
| 249 error_message->assign("Non ASCII: "); |
| 250 error_message->append(ShortenTo64Characters(input)); |
| 251 return false; |
| 252 } |
| 253 |
| 254 scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(input)); |
| 255 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) { |
| 256 error_message->assign("Not valid JSON: "); |
| 257 error_message->append(ShortenTo64Characters(input)); |
| 258 return false; |
| 259 } |
| 260 |
| 261 // Locate the set from the dictionary. |
| 262 base::DictionaryValue* dictionary = |
| 263 static_cast<base::DictionaryValue*>(root.get()); |
| 264 base::ListValue* list_val = NULL; |
| 265 if (!dictionary->GetList(kKeyIdsTag, &list_val)) { |
| 266 error_message->assign("Missing '"); |
| 267 error_message->append(kKeyIdsTag); |
| 268 error_message->append("' parameter or not a list"); |
| 269 return false; |
| 270 } |
| 271 |
| 272 // Create a local list of key ids, so that |key_ids| only gets updated on |
| 273 // success. |
| 274 KeyIdList local_key_ids; |
| 275 for (size_t i = 0; i < list_val->GetSize(); ++i) { |
| 276 std::string encoded_key_id; |
| 277 if (!list_val->GetString(i, &encoded_key_id)) { |
| 278 error_message->assign("'"); |
| 279 error_message->append(kKeyIdsTag); |
| 280 error_message->append("'["); |
| 281 error_message->append(base::UintToString(i)); |
| 282 error_message->append("] is not string."); |
| 283 return false; |
| 284 } |
| 285 |
| 286 // Key ID is a base64-encoded string, so decode it. |
| 287 std::string raw_key_id = DecodeBase64Url(encoded_key_id); |
| 288 if (raw_key_id.empty()) { |
| 289 error_message->assign("'"); |
| 290 error_message->append(kKeyIdsTag); |
| 291 error_message->append("'["); |
| 292 error_message->append(base::UintToString(i)); |
| 293 error_message->append("] is not valid base64url encoded. Value: "); |
| 294 error_message->append(ShortenTo64Characters(encoded_key_id)); |
| 295 return false; |
| 296 } |
| 297 |
| 298 // Add the decoded key ID to the list. |
| 299 local_key_ids.push_back(std::vector<uint8>( |
| 300 raw_key_id.data(), raw_key_id.data() + raw_key_id.length())); |
| 301 } |
| 302 |
| 303 // All done. |
| 304 key_ids->swap(local_key_ids); |
| 305 error_message->clear(); |
| 306 return true; |
| 307 } |
| 308 |
229 void CreateLicenseRequest(const KeyIdList& key_ids, | 309 void CreateLicenseRequest(const KeyIdList& key_ids, |
230 MediaKeys::SessionType session_type, | 310 MediaKeys::SessionType session_type, |
231 std::vector<uint8>* license) { | 311 std::vector<uint8>* license) { |
232 // Create the license request. | 312 // Create the license request. |
233 scoped_ptr<base::DictionaryValue> request(new base::DictionaryValue()); | 313 scoped_ptr<base::DictionaryValue> request(new base::DictionaryValue()); |
234 scoped_ptr<base::ListValue> list(new base::ListValue()); | 314 scoped_ptr<base::ListValue> list(new base::ListValue()); |
235 for (const auto& key_id : key_ids) | 315 for (const auto& key_id : key_ids) |
236 list->AppendString(EncodeBase64Url(&key_id[0], key_id.size())); | 316 list->AppendString(EncodeBase64Url(&key_id[0], key_id.size())); |
237 request->Set(kKeyIdsTag, list.release()); | 317 request->Set(kKeyIdsTag, list.release()); |
238 | 318 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 DVLOG(1) << "Invalid '" << kKeyIdsTag << "' value: " << encoded_key; | 380 DVLOG(1) << "Invalid '" << kKeyIdsTag << "' value: " << encoded_key; |
301 return false; | 381 return false; |
302 } | 382 } |
303 | 383 |
304 std::vector<uint8> result(decoded_string.begin(), decoded_string.end()); | 384 std::vector<uint8> result(decoded_string.begin(), decoded_string.end()); |
305 first_key->swap(result); | 385 first_key->swap(result); |
306 return true; | 386 return true; |
307 } | 387 } |
308 | 388 |
309 } // namespace media | 389 } // namespace media |
OLD | NEW |