Check existence of Widevince CDM/Adapter on load failure on Win.
[chromium-blink-merge.git] / media / cdm / json_web_key.cc
bloba6aa88516faa5295c0b6fe8327c90eb08beb0d59
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
3 // found in the LICENSE file.
5 #include "media/cdm/json_web_key.h"
7 #include "base/base64.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_string_value_serializer.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
15 namespace media {
17 const char kKeysTag[] = "keys";
18 const char kKeyTypeTag[] = "kty";
19 const char kSymmetricKeyValue[] = "oct";
20 const char kKeyTag[] = "k";
21 const char kKeyIdTag[] = "kid";
22 const char kBase64Padding = '=';
24 // Encodes |input| into a base64 string without padding.
25 static std::string EncodeBase64(const uint8* input, int input_length) {
26 std::string encoded_text;
27 base::Base64Encode(
28 std::string(reinterpret_cast<const char*>(input), input_length),
29 &encoded_text);
31 // Remove any padding characters added by Base64Encode().
32 size_t found = encoded_text.find_last_not_of(kBase64Padding);
33 if (found != std::string::npos)
34 encoded_text.erase(found + 1);
36 return encoded_text;
39 // Decodes an unpadded base64 string. Returns empty string on error.
40 static std::string DecodeBase64(const std::string& encoded_text) {
41 // EME spec doesn't allow padding characters.
42 if (encoded_text.find_first_of(kBase64Padding) != std::string::npos)
43 return std::string();
45 // Since base::Base64Decode() requires padding characters, add them so length
46 // of |encoded_text| is exactly a multiple of 4.
47 size_t num_last_grouping_chars = encoded_text.length() % 4;
48 std::string modified_text = encoded_text;
49 if (num_last_grouping_chars > 0)
50 modified_text.append(4 - num_last_grouping_chars, kBase64Padding);
52 std::string decoded_text;
53 if (!base::Base64Decode(modified_text, &decoded_text))
54 return std::string();
56 return decoded_text;
59 std::string GenerateJWKSet(const uint8* key, int key_length,
60 const uint8* key_id, int key_id_length) {
61 // Both |key| and |key_id| need to be base64 encoded strings in the JWK.
62 std::string key_base64 = EncodeBase64(key, key_length);
63 std::string key_id_base64 = EncodeBase64(key_id, key_id_length);
65 // Create the JWK, and wrap it into a JWK Set.
66 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue());
67 jwk->SetString(kKeyTypeTag, kSymmetricKeyValue);
68 jwk->SetString(kKeyTag, key_base64);
69 jwk->SetString(kKeyIdTag, key_id_base64);
70 scoped_ptr<base::ListValue> list(new base::ListValue());
71 list->Append(jwk.release());
72 base::DictionaryValue jwk_set;
73 jwk_set.Set(kKeysTag, list.release());
75 // Finally serialize |jwk_set| into a string and return it.
76 std::string serialized_jwk;
77 JSONStringValueSerializer serializer(&serialized_jwk);
78 serializer.Serialize(jwk_set);
79 return serialized_jwk;
82 // Processes a JSON Web Key to extract the key id and key value. Sets |jwk_key|
83 // to the id/value pair and returns true on success.
84 static bool ConvertJwkToKeyPair(const base::DictionaryValue& jwk,
85 KeyIdAndKeyPair* jwk_key) {
86 // Have found a JWK, start by checking that it is a symmetric key.
87 std::string type;
88 if (!jwk.GetString(kKeyTypeTag, &type) || type != kSymmetricKeyValue) {
89 DVLOG(1) << "JWK is not a symmetric key";
90 return false;
93 // Get the key id and actual key parameters.
94 std::string encoded_key_id;
95 std::string encoded_key;
96 if (!jwk.GetString(kKeyIdTag, &encoded_key_id)) {
97 DVLOG(1) << "Missing '" << kKeyIdTag << "' parameter";
98 return false;
100 if (!jwk.GetString(kKeyTag, &encoded_key)) {
101 DVLOG(1) << "Missing '" << kKeyTag << "' parameter";
102 return false;
105 // Key ID and key are base64-encoded strings, so decode them.
106 std::string raw_key_id = DecodeBase64(encoded_key_id);
107 if (raw_key_id.empty()) {
108 DVLOG(1) << "Invalid '" << kKeyIdTag << "' value: " << encoded_key_id;
109 return false;
112 std::string raw_key = DecodeBase64(encoded_key);
113 if (raw_key.empty()) {
114 DVLOG(1) << "Invalid '" << kKeyTag << "' value: " << encoded_key;
115 return false;
118 // Add the decoded key ID and the decoded key to the list.
119 *jwk_key = std::make_pair(raw_key_id, raw_key);
120 return true;
123 bool ExtractKeysFromJWKSet(const std::string& jwk_set, KeyIdAndKeyPairs* keys) {
124 if (!IsStringASCII(jwk_set))
125 return false;
127 scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(jwk_set));
128 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY)
129 return false;
131 // Locate the set from the dictionary.
132 base::DictionaryValue* dictionary =
133 static_cast<base::DictionaryValue*>(root.get());
134 base::ListValue* list_val = NULL;
135 if (!dictionary->GetList(kKeysTag, &list_val)) {
136 DVLOG(1) << "Missing '" << kKeysTag
137 << "' parameter or not a list in JWK Set";
138 return false;
141 // Create a local list of keys, so that |jwk_keys| only gets updated on
142 // success.
143 KeyIdAndKeyPairs local_keys;
144 for (size_t i = 0; i < list_val->GetSize(); ++i) {
145 base::DictionaryValue* jwk = NULL;
146 if (!list_val->GetDictionary(i, &jwk)) {
147 DVLOG(1) << "Unable to access '" << kKeysTag << "'[" << i
148 << "] in JWK Set";
149 return false;
151 KeyIdAndKeyPair key_pair;
152 if (!ConvertJwkToKeyPair(*jwk, &key_pair)) {
153 DVLOG(1) << "Error from '" << kKeysTag << "'[" << i << "]";
154 return false;
156 local_keys.push_back(key_pair);
159 // Successfully processed all JWKs in the set.
160 keys->swap(local_keys);
161 return true;
164 } // namespace media