1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <utils/Log.h>
17
18 #include "JsonWebKey.h"
19
20 #include "gtest/gtest.h"
21 #include "Utils.h"
22
23 namespace clearkeydrm {
24 using android::String8;
25 using android::Vector;
26
27 class JsonWebKeyTest : public ::testing::Test {
28 protected:
29 JsonWebKey* jwk;
30
JsonWebKeyTest()31 JsonWebKeyTest() {
32 jwk = new JsonWebKey;
33 }
34
~JsonWebKeyTest()35 virtual ~JsonWebKeyTest() {
36 if (jwk)
37 delete jwk;
38 }
39 };
40
stringFromVector(const Vector<uint8_t> & input,String8 * converted)41 void stringFromVector(const Vector<uint8_t>& input,
42 String8* converted) {
43 converted->clear();
44 if (input.isEmpty()) {
45 return;
46 }
47
48 for (size_t i = 0; i < input.size(); ++i) {
49 converted->appendFormat("%c", input.itemAt(i));
50 }
51 }
52
verifyKeys(const KeyMap & keys,const String8 * clearKeys)53 void verifyKeys(const KeyMap& keys, const String8* clearKeys) {
54 if (keys.isEmpty()) {
55 return;
56 }
57
58 String8 keyString;
59 for (size_t i = 0; i < keys.size(); ++i) {
60 stringFromVector(keys.valueAt(i), &keyString);
61 EXPECT_EQ(keyString, clearKeys[i]);
62 }
63 }
64
TEST_F(JsonWebKeyTest,NoSymmetricKey)65 TEST_F(JsonWebKeyTest, NoSymmetricKey) {
66 const String8 js(
67 "{"
68 "[{"
69 "\"kty\":\"rsa\","
70 "\"alg\":\"A128KW1\","
71 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\","
72 "\"k\":\"1-GawgguFyGrWKav7AX4VKUg\""
73 "}]"
74 "}");
75
76 KeyMap keys;
77 EXPECT_FALSE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
78 EXPECT_TRUE(keys.isEmpty());
79 }
80
TEST_F(JsonWebKeyTest,NoKeysTag)81 TEST_F(JsonWebKeyTest, NoKeysTag) {
82 const String8 js(
83 "{"
84 "[{"
85 "\"kty\":\"oct\","
86 "\"alg\":\"A128KW1\","
87 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\","
88 "\"k\":\"1-GawgguFyGrWKav7AX4VKUg\""
89 "},"
90 "{"
91 "\"kty\":\"oct\","
92 "\"alg\":\"A128KW2\","
93 "\"k\":\"R29vZCBkYXkh\","
94 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
95 "}]"
96 "}");
97
98 KeyMap keys;
99 EXPECT_FALSE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
100 EXPECT_TRUE(keys.isEmpty());
101 }
102
TEST_F(JsonWebKeyTest,NoKeyId)103 TEST_F(JsonWebKeyTest, NoKeyId) {
104 const String8 js(
105 "{"
106 "\"keys\":"
107 "[{"
108 "\"kty\":\"oct\""
109 "\"alg\":\"A128KW1\""
110 "\"k\":\"SGVsbG8gRnJpZW5kISE=\""
111 "}"
112 "{"
113 "\"kty\":\"oct\""
114 "\"alg\":\"A128KW2\""
115 "\"k\":\"R29vZCBkYXkh\""
116 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
117 "}]"
118 "}");
119
120 KeyMap keys;
121 EXPECT_TRUE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
122 EXPECT_TRUE(keys.size() == 1);
123
124 const String8 clearKeys("Good day!");
125 verifyKeys(keys, &clearKeys);
126 }
127
TEST_F(JsonWebKeyTest,NoKey)128 TEST_F(JsonWebKeyTest, NoKey) {
129 const String8 js(
130 "{"
131 "\"keys\":"
132 "[{"
133 "\"kty\":\"oct\""
134 "\"alg\":\"A128KW1\""
135 "\"kid\":\"`\""
136 "}"
137 "{"
138 "\"kty\":\"oct\""
139 "\"alg\":\"A128KW2\""
140 "\"k\":\"R29vZCBkYXkh\""
141 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
142 "}]"
143 "}");
144
145 KeyMap keys;
146 EXPECT_TRUE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
147 EXPECT_TRUE(keys.size() == 1);
148
149 const String8 clearKeys("Good day!");
150 verifyKeys(keys, &clearKeys);
151 }
152
TEST_F(JsonWebKeyTest,MalformedKey)153 TEST_F(JsonWebKeyTest, MalformedKey) {
154 const String8 js(
155 "{"
156 "\"keys\":"
157 "[{"
158 "\"kty\":\"oct\""
159 "\"alg\":\"A128KW1\""
160 "\"k\":\"GawgguFyGrWKav7AX4V???\""
161 "\"kid\":\"67ef0gd8pvfd0=\""
162 "}"
163 "{"
164 "\"kty\":\"oct\""
165 "\"alg\":\"A128KW1\""
166 "\"k\":\"GawgguFyGrWKav7AX4V???\""
167 "\"kid\":"
168 "}"
169 "{"
170 "\"kty\":\"oct\""
171 "\"alg\":\"A128KW1\""
172 ":\"GawgguFyGrWKav7AX4V???\""
173 "\"kid\":\"67ef0gd8pvfd0=\""
174 "}"
175 "{"
176 "\"kty\":\"oct\""
177 "\"alg\":\"A128KW3\""
178 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
179 "\"k\":\"R29vZCBkYXkh\""
180 "}]"
181 "}");
182
183 KeyMap keys;
184 EXPECT_TRUE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
185 EXPECT_TRUE(keys.size() == 1);
186
187 const String8 clearKeys("Good day!");
188 verifyKeys(keys, &clearKeys);
189 }
190
TEST_F(JsonWebKeyTest,EmptyJsonWebKey)191 TEST_F(JsonWebKeyTest, EmptyJsonWebKey) {
192 const String8 js;
193 KeyMap keys;
194 EXPECT_FALSE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
195 EXPECT_TRUE(keys.isEmpty());
196 }
197
TEST_F(JsonWebKeyTest,MalformedJsonWebKey)198 TEST_F(JsonWebKeyTest, MalformedJsonWebKey) {
199 // Missing begin array '['
200 const String8 js(
201 "{"
202 "\"keys\":"
203 "{"
204 "\"kty\":\"oct\""
205 "\"alg\":\"A128KW1\""
206 "\"k\":\"GawgguFyGrWKav7AX4VKUg\""
207 "\"kid\":\"67ef0gd8pvfd0=\""
208 "}"
209 "]"
210 "}");
211
212 KeyMap keys;
213 EXPECT_FALSE(jwk->extractKeysFromJsonWebKeySet(js, &keys));
214 EXPECT_TRUE(keys.isEmpty());
215 }
216
TEST_F(JsonWebKeyTest,SameKeyId)217 TEST_F(JsonWebKeyTest, SameKeyId) {
218 const String8 js(
219 "{"
220 "\"keys\":"
221 "[{"
222 "\"kty\":\"oct\""
223 "\"alg\":\"A128KW1\""
224 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
225 "\"k\":\"SGVsbG8gRnJpZW5kISE\""
226 "}"
227 "{"
228 "\"kty\":\"oct\""
229 "\"alg\":\"A128KW1\""
230 "\"k\":\"SGVsbG8gRnJpZW5kIQ\""
231 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
232 "}"
233 "{"
234 "\"kty\":\"oct\""
235 "\"alg\":\"A128KW3\""
236 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
237 "\"k\":\"R29vZCBkYXkh\""
238 "}]"
239 "}");
240
241 KeyMap keys;
242 jwk->extractKeysFromJsonWebKeySet(js, &keys);
243 EXPECT_TRUE(keys.size() == 2);
244
245 const String8 clearKeys[] =
246 { String8("Hello Friend!"), String8("Good day!") };
247 verifyKeys(keys, clearKeys);
248 }
249
TEST_F(JsonWebKeyTest,ExtractWellFormedKeys)250 TEST_F(JsonWebKeyTest, ExtractWellFormedKeys) {
251 const String8 js(
252 "{"
253 "\"keys\":"
254 "[{"
255 "\"kty\":\"oct\""
256 "\"alg\":\"A128KW1\""
257 "}"
258 "{"
259 "\"kty\":\"oct\""
260 "\"alg\":\"A128KW2\""
261 "\"k\":\"SGVsbG8gRnJpZW5kIQ\""
262 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
263 "}"
264 "{"
265 "\"kty\":\"oct\""
266 "\"alg\":\"A128KW3\""
267 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
268 "\"k\":\"R29vZCBkYXkh\""
269 "}]"
270 "}");
271
272 KeyMap keys;
273 jwk->extractKeysFromJsonWebKeySet(js, &keys);
274 EXPECT_TRUE(keys.size() == 2);
275
276 const String8 clearKeys[] =
277 { String8("Hello Friend!"), String8("Good day!") };
278 verifyKeys(keys, clearKeys);
279 }
280
TEST_F(JsonWebKeyTest,ExtractKeys)281 TEST_F(JsonWebKeyTest, ExtractKeys) {
282 const String8 js(
283 "{"
284 "\"keys\":"
285 "[{"
286 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
287 "\"k\":\"SGVsbG8gRnJpZW5kISE\""
288 "\"kty\":\"oct\""
289 "\"alg\":\"A128KW1\""
290 "}"
291 "{"
292 "\"kty\":\"oct\""
293 "\"alg\":\"A128KW2\""
294 "\"k\":\"SGVsbG8gRnJpZW5kIQ\""
295 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
296 "}"
297 "{"
298 "\"kty\":\"rsa\""
299 "\"alg\":\"A128KW-rsa\""
300 "\"k\":\"R29vZCBkYXkh\""
301 "\"kid\":\"rsa-67ef0gd8pvfd0=\""
302 "}"
303 "{"
304 "\"alg\":\"A128KW3\""
305 "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
306 "\"k\":\"R29vZCBkYXkh\""
307 "\"kty\":\"oct\""
308 "}]"
309 "}");
310
311 KeyMap keys;
312 jwk->extractKeysFromJsonWebKeySet(js, &keys);
313 EXPECT_TRUE(keys.size() == 3);
314
315 const String8 clearKeys[] =
316 { String8("Hello Friend!!"), String8("Hello Friend!"),
317 String8("Good day!") };
318 verifyKeys(keys, clearKeys);
319 }
320
321 } // namespace clearkeydrm
322