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\":\"SGVsbG8gRnJpZW5kICE-Pw\""
288                         "\"kty\":\"oct\""
289                         "\"alg\":\"A128KW1\""
290                     "}"
291                     "{"
292                         "\"kty\":\"oct\""
293                         "\"alg\":\"A128KW2\""
294                         "\"k\":\"SGVsbG8gRnJpZW5kICE_\""
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\":\"SGVsbG8gPz4-IEZyaWVuZCA_Pg\""
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("Hello ?>> Friend ?>") };
318     verifyKeys(keys, clearKeys);
319 }
320 
321 }  // namespace clearkeydrm
322