[Telemetry] Add interaction_record field to Value
[chromium-blink-merge.git] / media / cdm / json_web_key_unittest.cc
blob07d28c02eefb02ea488ef528478edfb3f046a260
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/logging.h"
9 #include "testing/gtest/include/gtest/gtest.h"
11 namespace media {
13 class JSONWebKeyTest : public testing::Test {
14 public:
15 JSONWebKeyTest() {}
17 protected:
18 void ExtractJWKKeysAndExpect(const std::string& jwk,
19 bool expected_result,
20 size_t expected_number_of_keys) {
21 DCHECK(!jwk.empty());
22 KeyIdAndKeyPairs keys;
23 MediaKeys::SessionType session_type;
24 EXPECT_EQ(expected_result,
25 ExtractKeysFromJWKSet(jwk, &keys, &session_type));
26 EXPECT_EQ(expected_number_of_keys, keys.size());
29 void ExtractSessionTypeAndExpect(const std::string& jwk,
30 bool expected_result,
31 MediaKeys::SessionType expected_type) {
32 DCHECK(!jwk.empty());
33 KeyIdAndKeyPairs keys;
34 MediaKeys::SessionType session_type;
35 EXPECT_EQ(expected_result,
36 ExtractKeysFromJWKSet(jwk, &keys, &session_type));
37 if (expected_result) {
38 // Only check if successful.
39 EXPECT_EQ(expected_type, session_type);
43 void CreateLicenseAndExpect(const uint8* key_id,
44 int key_id_length,
45 MediaKeys::SessionType session_type,
46 const std::string& expected_result) {
47 std::vector<uint8> result;
48 KeyIdList key_ids;
49 key_ids.push_back(std::vector<uint8>(key_id, key_id + key_id_length));
50 CreateLicenseRequest(key_ids, session_type, &result);
51 std::string s(result.begin(), result.end());
52 EXPECT_EQ(expected_result, s);
55 void ExtractKeyFromLicenseAndExpect(const std::string& license,
56 bool expected_result,
57 const uint8* expected_key,
58 int expected_key_length) {
59 std::vector<uint8> license_vector(license.begin(), license.end());
60 std::vector<uint8> key;
61 EXPECT_EQ(expected_result,
62 ExtractFirstKeyIdFromLicenseRequest(license_vector, &key));
63 if (expected_result) {
64 std::vector<uint8> key_result(expected_key,
65 expected_key + expected_key_length);
66 EXPECT_EQ(key_result, key);
71 TEST_F(JSONWebKeyTest, GenerateJWKSet) {
72 const uint8 data1[] = { 0x01, 0x02 };
73 const uint8 data2[] = { 0x01, 0x02, 0x03, 0x04 };
74 const uint8 data3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
75 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };
77 EXPECT_EQ(
78 "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":"
79 "\"oct\"}]}",
80 GenerateJWKSet(data1, arraysize(data1), data1, arraysize(data1)));
81 EXPECT_EQ(
82 "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQIDBA\",\"kid\":\"AQIDBA\","
83 "\"kty\":\"oct\"}]}",
84 GenerateJWKSet(data2, arraysize(data2), data2, arraysize(data2)));
85 EXPECT_EQ(
86 "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQIDBA\",\"kty\":"
87 "\"oct\"}]}",
88 GenerateJWKSet(data1, arraysize(data1), data2, arraysize(data2)));
89 EXPECT_EQ(
90 "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQIDBA\",\"kid\":\"AQI\",\"kty\":"
91 "\"oct\"}]}",
92 GenerateJWKSet(data2, arraysize(data2), data1, arraysize(data1)));
93 EXPECT_EQ(
94 "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQIDBAUGBwgJCgsMDQ4PEA\",\"kid\":"
95 "\"AQIDBAUGBwgJCgsMDQ4PEA\",\"kty\":\"oct\"}]}",
96 GenerateJWKSet(data3, arraysize(data3), data3, arraysize(data3)));
99 TEST_F(JSONWebKeyTest, ExtractValidJWKKeys) {
100 // Try an empty 'keys' dictionary.
101 ExtractJWKKeysAndExpect("{ \"keys\": [] }", true, 0);
103 // Try a key list with one entry.
104 const std::string kJwksOneEntry =
106 " \"keys\": ["
107 " {"
108 " \"kty\": \"oct\","
109 " \"alg\": \"A128KW\","
110 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
111 " \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
112 " }"
113 " ]"
114 "}";
115 ExtractJWKKeysAndExpect(kJwksOneEntry, true, 1);
117 // Try a key list with multiple entries.
118 const std::string kJwksMultipleEntries =
120 " \"keys\": ["
121 " {"
122 " \"kty\": \"oct\","
123 " \"alg\": \"A128KW\","
124 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
125 " \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
126 " },"
127 " {"
128 " \"kty\": \"oct\","
129 " \"alg\": \"A128KW\","
130 " \"kid\": \"JCUmJygpKissLS4vMA\","
131 " \"k\":\"MTIzNDU2Nzg5Ojs8PT4_QA\""
132 " }"
133 " ]"
134 "}";
135 ExtractJWKKeysAndExpect(kJwksMultipleEntries, true, 2);
137 // Try a key with no spaces and some \n plus additional fields.
138 const std::string kJwksNoSpaces =
139 "\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\",\"alg\":\"A128KW\","
140 "\"kid\":\"AAECAwQFBgcICQoLDA0ODxAREhM\",\"k\":\"GawgguFyGrWKav7AX4VKUg"
141 "\",\"foo\":\"bar\"}]}\n\n";
142 ExtractJWKKeysAndExpect(kJwksNoSpaces, true, 1);
144 // Try a list with multiple keys with the same kid.
145 const std::string kJwksDuplicateKids =
147 " \"keys\": ["
148 " {"
149 " \"kty\": \"oct\","
150 " \"alg\": \"A128KW\","
151 " \"kid\": \"JCUmJygpKissLS4vMA\","
152 " \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
153 " },"
154 " {"
155 " \"kty\": \"oct\","
156 " \"alg\": \"A128KW\","
157 " \"kid\": \"JCUmJygpKissLS4vMA\","
158 " \"k\":\"MTIzNDU2Nzg5Ojs8PT4_QA\""
159 " }"
160 " ]"
161 "}";
162 ExtractJWKKeysAndExpect(kJwksDuplicateKids, true, 2);
165 TEST_F(JSONWebKeyTest, ExtractInvalidJWKKeys) {
166 // Try a simple JWK key (i.e. not in a set)
167 const std::string kJwkSimple =
169 " \"kty\": \"oct\","
170 " \"alg\": \"A128KW\","
171 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
172 " \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
173 "}";
174 ExtractJWKKeysAndExpect(kJwkSimple, false, 0);
176 // Try some non-ASCII characters.
177 ExtractJWKKeysAndExpect(
178 "This is not ASCII due to \xff\xfe\xfd in it.", false, 0);
180 // Try some non-ASCII characters in an otherwise valid JWK.
181 const std::string kJwksInvalidCharacters =
182 "\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\",\"alg\":\"A128KW\","
183 "\"kid\":\"AAECAwQFBgcICQoLDA0ODxAREhM\",\"k\":\"\xff\xfe\xfd"
184 "\",\"foo\":\"bar\"}]}\n\n";
185 ExtractJWKKeysAndExpect(kJwksInvalidCharacters, false, 0);
187 // Try a badly formatted key. Assume that the JSON parser is fully tested,
188 // so we won't try a lot of combinations. However, need a test to ensure
189 // that the code doesn't crash if invalid JSON received.
190 ExtractJWKKeysAndExpect("This is not a JSON key.", false, 0);
192 // Try passing some valid JSON that is not a dictionary at the top level.
193 ExtractJWKKeysAndExpect("40", false, 0);
195 // Try an empty dictionary.
196 ExtractJWKKeysAndExpect("{ }", false, 0);
198 // Try with 'keys' not a dictionary.
199 ExtractJWKKeysAndExpect("{ \"keys\":\"1\" }", false, 0);
201 // Try with 'keys' a list of integers.
202 ExtractJWKKeysAndExpect("{ \"keys\": [ 1, 2, 3 ] }", false, 0);
204 // Try padding(=) at end of 'k' base64 string.
205 const std::string kJwksWithPaddedKey =
207 " \"keys\": ["
208 " {"
209 " \"kty\": \"oct\","
210 " \"alg\": \"A128KW\","
211 " \"kid\": \"AAECAw\","
212 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw==\""
213 " }"
214 " ]"
215 "}";
216 ExtractJWKKeysAndExpect(kJwksWithPaddedKey, false, 0);
218 // Try padding(=) at end of 'kid' base64 string.
219 const std::string kJwksWithPaddedKeyId =
221 " \"keys\": ["
222 " {"
223 " \"kty\": \"oct\","
224 " \"alg\": \"A128KW\","
225 " \"kid\": \"AAECAw==\","
226 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
227 " }"
228 " ]"
229 "}";
230 ExtractJWKKeysAndExpect(kJwksWithPaddedKeyId, false, 0);
232 // Try a key with invalid base64 encoding.
233 const std::string kJwksWithInvalidBase64 =
235 " \"keys\": ["
236 " {"
237 " \"kty\": \"oct\","
238 " \"alg\": \"A128KW\","
239 " \"kid\": \"!@#$%^&*()\","
240 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
241 " }"
242 " ]"
243 "}";
244 ExtractJWKKeysAndExpect(kJwksWithInvalidBase64, false, 0);
246 // Empty key id.
247 const std::string kJwksWithEmptyKeyId =
249 " \"keys\": ["
250 " {"
251 " \"kty\": \"oct\","
252 " \"alg\": \"A128KW\","
253 " \"kid\": \"\","
254 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
255 " }"
256 " ]"
257 "}";
258 ExtractJWKKeysAndExpect(kJwksWithEmptyKeyId, false, 0);
261 TEST_F(JSONWebKeyTest, KeyType) {
262 // Valid key type.
263 const std::string kJwksWithValidKeyType =
265 " \"keys\": ["
266 " {"
267 " \"kty\": \"oct\","
268 " \"alg\": \"A128KW\","
269 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
270 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
271 " }"
272 " ]"
273 "}";
274 ExtractJWKKeysAndExpect(kJwksWithValidKeyType, true, 1);
276 // Empty key type.
277 const std::string kJwksWithEmptyKeyType =
279 " \"keys\": ["
280 " {"
281 " \"kty\": \"\","
282 " \"alg\": \"A128KW\","
283 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
284 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
285 " }"
286 " ]"
287 "}";
288 ExtractJWKKeysAndExpect(kJwksWithEmptyKeyType, false, 0);
290 // Key type is case sensitive.
291 const std::string kJwksWithUppercaseKeyType =
293 " \"keys\": ["
294 " {"
295 " \"kty\": \"OCT\","
296 " \"alg\": \"A128KW\","
297 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
298 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
299 " }"
300 " ]"
301 "}";
302 ExtractJWKKeysAndExpect(kJwksWithUppercaseKeyType, false, 0);
304 // Wrong key type.
305 const std::string kJwksWithWrongKeyType =
307 " \"keys\": ["
308 " {"
309 " \"kty\": \"RSA\","
310 " \"alg\": \"A128KW\","
311 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
312 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
313 " }"
314 " ]"
315 "}";
316 ExtractJWKKeysAndExpect(kJwksWithWrongKeyType, false, 0);
319 TEST_F(JSONWebKeyTest, Alg) {
320 // Valid alg.
321 const std::string kJwksWithValidAlg =
323 " \"keys\": ["
324 " {"
325 " \"kty\": \"oct\","
326 " \"alg\": \"A128KW\","
327 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
328 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
329 " }"
330 " ]"
331 "}";
332 ExtractJWKKeysAndExpect(kJwksWithValidAlg, true, 1);
334 // Empty alg.
335 const std::string kJwksWithEmptyAlg =
337 " \"keys\": ["
338 " {"
339 " \"kty\": \"oct\","
340 " \"alg\": \"\","
341 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
342 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
343 " }"
344 " ]"
345 "}";
346 ExtractJWKKeysAndExpect(kJwksWithEmptyAlg, false, 0);
348 // Alg is case sensitive.
349 const std::string kJwksWithLowercaseAlg =
351 " \"keys\": ["
352 " {"
353 " \"kty\": \"oct\","
354 " \"alg\": \"a128kw\","
355 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
356 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
357 " }"
358 " ]"
359 "}";
360 ExtractJWKKeysAndExpect(kJwksWithLowercaseAlg, false, 0);
362 // Wrong alg.
363 const std::string kJwksWithWrongAlg =
365 " \"keys\": ["
366 " {"
367 " \"kty\": \"oct\","
368 " \"alg\": \"RS256\","
369 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
370 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
371 " }"
372 " ]"
373 "}";
374 ExtractJWKKeysAndExpect(kJwksWithWrongAlg, false, 0);
377 TEST_F(JSONWebKeyTest, SessionType) {
378 ExtractSessionTypeAndExpect(
379 "{\"keys\":[{\"alg\": "
380 "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}]}",
381 true, MediaKeys::TEMPORARY_SESSION);
382 ExtractSessionTypeAndExpect(
383 "{\"keys\":[{\"alg\": "
384 "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
385 "\"temporary\"}",
386 true, MediaKeys::TEMPORARY_SESSION);
387 ExtractSessionTypeAndExpect(
388 "{\"keys\":[{\"alg\": "
389 "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
390 "\"persistent-license\"}",
391 true, MediaKeys::PERSISTENT_LICENSE_SESSION);
392 ExtractSessionTypeAndExpect(
393 "{\"keys\":[{\"alg\": "
394 "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
395 "\"persistent-release-message\"}",
396 true, MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION);
397 ExtractSessionTypeAndExpect(
398 "{\"keys\":[{\"alg\": "
399 "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":"
400 "\"unknown\"}",
401 false, MediaKeys::TEMPORARY_SESSION);
402 ExtractSessionTypeAndExpect(
403 "{\"keys\":[{\"alg\": "
404 "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":3}",
405 false, MediaKeys::TEMPORARY_SESSION);
408 TEST_F(JSONWebKeyTest, CreateLicense) {
409 const uint8 data1[] = { 0x01, 0x02 };
410 const uint8 data2[] = { 0x01, 0x02, 0x03, 0x04 };
411 const uint8 data3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
412 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };
414 CreateLicenseAndExpect(data1,
415 arraysize(data1),
416 MediaKeys::TEMPORARY_SESSION,
417 "{\"kids\":[\"AQI\"],\"type\":\"temporary\"}");
418 CreateLicenseAndExpect(
419 data1, arraysize(data1), MediaKeys::PERSISTENT_LICENSE_SESSION,
420 "{\"kids\":[\"AQI\"],\"type\":\"persistent-license\"}");
421 CreateLicenseAndExpect(
422 data1, arraysize(data1), MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION,
423 "{\"kids\":[\"AQI\"],\"type\":\"persistent-release-message\"}");
424 CreateLicenseAndExpect(data2,
425 arraysize(data2),
426 MediaKeys::TEMPORARY_SESSION,
427 "{\"kids\":[\"AQIDBA\"],\"type\":\"temporary\"}");
428 CreateLicenseAndExpect(data3, arraysize(data3),
429 MediaKeys::PERSISTENT_LICENSE_SESSION,
430 "{\"kids\":[\"AQIDBAUGBwgJCgsMDQ4PEA\"],\"type\":"
431 "\"persistent-license\"}");
434 TEST_F(JSONWebKeyTest, ExtractLicense) {
435 const uint8 data1[] = { 0x01, 0x02 };
436 const uint8 data2[] = { 0x01, 0x02, 0x03, 0x04 };
437 const uint8 data3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
438 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };
440 ExtractKeyFromLicenseAndExpect(
441 "{\"kids\":[\"AQI\"],\"type\":\"temporary\"}",
442 true,
443 data1,
444 arraysize(data1));
445 ExtractKeyFromLicenseAndExpect(
446 "{\"kids\":[\"AQIDBA\"],\"type\":\"temporary\"}",
447 true,
448 data2,
449 arraysize(data2));
450 ExtractKeyFromLicenseAndExpect(
451 "{\"kids\":[\"AQIDBAUGBwgJCgsMDQ4PEA\"],\"type\":\"persistent\"}",
452 true,
453 data3,
454 arraysize(data3));
456 // Try some incorrect JSON.
457 ExtractKeyFromLicenseAndExpect("", false, NULL, 0);
458 ExtractKeyFromLicenseAndExpect("!@#$%^&*()", false, NULL, 0);
460 // Valid JSON, but not a dictionary.
461 ExtractKeyFromLicenseAndExpect("6", false, NULL, 0);
462 ExtractKeyFromLicenseAndExpect("[\"AQI\"]", false, NULL, 0);
464 // Dictionary, but missing expected tag.
465 ExtractKeyFromLicenseAndExpect("{\"kid\":[\"AQI\"]}", false, NULL, 0);
467 // Correct tag, but empty list.
468 ExtractKeyFromLicenseAndExpect("{\"kids\":[]}", false, NULL, 0);
470 // Correct tag, but list doesn't contain a string.
471 ExtractKeyFromLicenseAndExpect("{\"kids\":[[\"AQI\"]]}", false, NULL, 0);
473 // Correct tag, but invalid base64 encoding.
474 ExtractKeyFromLicenseAndExpect("{\"kids\":[\"!@#$%^&*()\"]}", false, NULL, 0);
477 TEST_F(JSONWebKeyTest, Base64UrlEncoding) {
478 const uint8 data1[] = { 0xfb, 0xfd, 0xfb, 0xfd, 0xfb, 0xfd, 0xfb };
480 // Verify that |data1| contains invalid base64url characters '+' and '/'
481 // and is padded with = when converted to base64.
482 std::string encoded_text;
483 base::Base64Encode(
484 std::string(reinterpret_cast<const char*>(&data1[0]), arraysize(data1)),
485 &encoded_text);
486 EXPECT_EQ(encoded_text, "+/37/fv9+w==");
487 EXPECT_NE(encoded_text.find('+'), std::string::npos);
488 EXPECT_NE(encoded_text.find('/'), std::string::npos);
489 EXPECT_NE(encoded_text.find('='), std::string::npos);
491 // base64url characters '-' and '_' not in base64 encoding.
492 EXPECT_EQ(encoded_text.find('-'), std::string::npos);
493 EXPECT_EQ(encoded_text.find('_'), std::string::npos);
495 CreateLicenseAndExpect(data1, arraysize(data1), MediaKeys::TEMPORARY_SESSION,
496 "{\"kids\":[\"-_37_fv9-w\"],\"type\":\"temporary\"}");
498 ExtractKeyFromLicenseAndExpect(
499 "{\"kids\":[\"-_37_fv9-w\"],\"type\":\"temporary\"}", true, data1,
500 arraysize(data1));
503 TEST_F(JSONWebKeyTest, MultipleKeys) {
504 const uint8 data1[] = { 0x01, 0x02 };
505 const uint8 data2[] = { 0x01, 0x02, 0x03, 0x04 };
506 const uint8 data3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
507 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };
509 std::vector<uint8> result;
510 KeyIdList key_ids;
511 key_ids.push_back(std::vector<uint8>(data1, data1 + arraysize(data1)));
512 key_ids.push_back(std::vector<uint8>(data2, data2 + arraysize(data2)));
513 key_ids.push_back(std::vector<uint8>(data3, data3 + arraysize(data3)));
514 CreateLicenseRequest(key_ids, MediaKeys::TEMPORARY_SESSION, &result);
515 std::string s(result.begin(), result.end());
516 EXPECT_EQ(
517 "{\"kids\":[\"AQI\",\"AQIDBA\",\"AQIDBAUGBwgJCgsMDQ4PEA\"],\"type\":"
518 "\"temporary\"}",
522 } // namespace media