Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 #include <map> | |
| 9 #include "base/base64.h" | |
| 10 #include "base/json/json_reader.h" | |
| 11 #include "base/logging.h" | |
| 7 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/strings/string_piece.h" | |
| 14 #include "base/values.h" | |
| 8 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 15 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
| 9 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 16 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
| 17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
| 10 #include "third_party/WebKit/public/platform/WebCryptoKey.h" | 18 #include "third_party/WebKit/public/platform/WebCryptoKey.h" |
| 11 | 19 |
| 12 namespace content { | 20 namespace content { |
| 13 | 21 |
| 22 namespace { | |
| 23 | |
| 24 // FIXME! Need WebKit::WebCryptoAlgorithmIdNone | |
|
eroman
2013/10/22 21:49:38
There are other ways of accomplishing this that I
Ryan Sleevi
2013/10/24 01:45:58
There are other formats that may have embedded alg
eroman
2013/10/24 02:35:04
I will make the necessary changes to Blink side.
padolph
2013/10/28 20:35:07
This is addressed by your recent Blink checkin. Th
| |
| 25 const WebKit::WebCryptoAlgorithmId WebCryptoAlgorithmIdNone = | |
| 26 (WebKit::WebCryptoAlgorithmId)99; | |
| 27 | |
| 28 // TODO(padolph) Similar Create*Algorithm() methods are in | |
|
eroman
2013/10/22 21:49:38
What do you think about a renderer/webcrypto/webcr
padolph
2013/10/28 20:35:07
Done.
Should the stuff in webcrypto_util.[h|cc] b
| |
| 29 // webcrypto_impl_unittest.cc. Find a common place to put these. | |
| 30 | |
| 31 WebKit::WebCryptoAlgorithm CreateAlgorithm(WebKit::WebCryptoAlgorithmId id) { | |
| 32 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | |
| 33 } | |
| 34 | |
| 35 WebKit::WebCryptoAlgorithm CreateAlgorithmWithInnerHash( | |
| 36 WebKit::WebCryptoAlgorithmId algorithm_id, | |
| 37 unsigned short hash_key_length) { | |
| 38 WebKit::WebCryptoAlgorithmId hashId; | |
|
eroman
2013/10/22 21:49:38
use hacker_style_variable_naming for chromium code
padolph
2013/10/28 20:35:07
Done.
| |
| 39 switch (hash_key_length) { | |
| 40 case 160: | |
| 41 hashId = WebKit::WebCryptoAlgorithmIdSha1; | |
| 42 break; | |
| 43 case 224: | |
| 44 hashId = WebKit::WebCryptoAlgorithmIdSha224; | |
| 45 break; | |
| 46 case 256: | |
| 47 hashId = WebKit::WebCryptoAlgorithmIdSha256; | |
| 48 break; | |
| 49 case 384: | |
| 50 hashId = WebKit::WebCryptoAlgorithmIdSha384; | |
| 51 break; | |
| 52 case 512: | |
| 53 hashId = WebKit::WebCryptoAlgorithmIdSha384; | |
| 54 break; | |
| 55 } | |
| 56 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | |
|
eroman
2013/10/22 21:49:38
Please add a default case to the switch above (per
padolph
2013/10/28 20:35:07
Done.
| |
| 57 algorithm_id, | |
| 58 new WebKit::WebCryptoHmacParams(CreateAlgorithm(hashId))); | |
| 59 } | |
| 60 | |
| 61 WebKit::WebCryptoAlgorithm CreateHmacAlgorithm(unsigned short hash_key_length) { | |
| 62 return CreateAlgorithmWithInnerHash( | |
| 63 WebKit::WebCryptoAlgorithmIdHmac, | |
| 64 hash_key_length); | |
| 65 } | |
| 66 | |
| 67 WebKit::WebCryptoAlgorithm CreateRsaSsaAlgorithm( | |
| 68 unsigned short hash_key_length) { | |
| 69 return CreateAlgorithmWithInnerHash( | |
| 70 WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | |
| 71 hash_key_length); | |
| 72 } | |
| 73 | |
| 74 WebKit::WebCryptoAlgorithm CreateRsaOaepAlgorithm( | |
| 75 unsigned short hash_key_length) { | |
| 76 return CreateAlgorithmWithInnerHash( | |
| 77 WebKit::WebCryptoAlgorithmIdRsaOaep, | |
| 78 hash_key_length); | |
| 79 } | |
| 80 | |
| 81 WebKit::WebCryptoAlgorithm CreateAesAlgorithm( | |
| 82 WebKit::WebCryptoAlgorithmId aes_alg_id, | |
| 83 unsigned short length) { | |
| 84 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 85 aes_alg_id, | |
| 86 new WebKit::WebCryptoAesKeyGenParams(length)); | |
| 87 } | |
| 88 | |
| 89 WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm(unsigned short length) { | |
| 90 return CreateAesAlgorithm(WebKit::WebCryptoAlgorithmIdAesCbc, length); | |
| 91 } | |
| 92 | |
| 93 WebKit::WebCryptoAlgorithm CreateAesGcmAlgorithm(unsigned short length) { | |
| 94 return CreateAesAlgorithm(WebKit::WebCryptoAlgorithmIdAesGcm, length); | |
| 95 } | |
| 96 | |
| 97 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { | |
|
eroman
2013/10/22 21:49:38
Please provide a comment pointing to the definitio
padolph
2013/10/28 20:35:07
Will do. 'base64url' encoding is relatively common
| |
| 98 std::string base64EncodedText(input); | |
| 99 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+'); | |
|
eroman
2013/10/22 21:49:38
Are these transformations enumerated int he JOSE s
padolph
2013/10/28 20:35:07
Yes, in RFC4648 Section 5.
| |
| 100 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/'); | |
| 101 base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '='); | |
| 102 return base::Base64Decode(base64EncodedText, output); | |
| 103 } | |
| 104 | |
| 105 // Identifiers for all JWK "alg" (algorithm) values handled by this code. The | |
|
eroman
2013/10/22 21:49:38
There is enough JWK stuff, that I suggest moving t
padolph
2013/10/28 20:35:07
Most of this code went away with the function tabl
| |
| 106 // "enum trick" is used to force int type, so a user type is not required in | |
|
eroman
2013/10/22 21:49:38
Not sure I know what the "enum trick" refers to. Y
padolph
2013/10/28 20:35:07
This code went away with the function table refact
| |
| 107 // web_crypto_impl.h | |
| 108 enum { | |
| 109 kJwkAlgorithmHs256, | |
| 110 kJwkAlgorithmHs384, | |
| 111 kJwkAlgorithmHs512, | |
| 112 kJwkAlgorithmRs256, | |
| 113 kJwkAlgorithmRs384, | |
| 114 kJwkAlgorithmRs512, | |
| 115 kJwkAlgorithmRsa1_5, | |
| 116 kJwkAlgorithmRsaOaep, | |
| 117 kJwkAlgorithmA128Kw, | |
| 118 kJwkAlgorithmA256Kw, | |
| 119 kJwkAlgorithmA128Gcm, | |
| 120 kJwkAlgorithmA256Gcm, | |
| 121 kJwkAlgorithmA128Cbc, | |
| 122 kJwkAlgorithmA256Cbc, | |
| 123 kJwkAlgorithmA384Cbc, | |
| 124 kJwkAlgorithmA512Cbc | |
| 125 }; | |
| 126 | |
| 127 WebKit::WebCryptoAlgorithmId JwkAlgIdToWebCryptoAlgId(int jwk_algorithm_id) { | |
|
eroman
2013/10/22 21:49:38
This function appears to be unused
padolph
2013/10/28 20:35:07
Done.
| |
| 128 switch (jwk_algorithm_id) { | |
| 129 case kJwkAlgorithmHs256: | |
| 130 case kJwkAlgorithmHs384: | |
| 131 case kJwkAlgorithmHs512: | |
| 132 return WebKit::WebCryptoAlgorithmIdHmac; | |
| 133 case kJwkAlgorithmRs256: | |
| 134 case kJwkAlgorithmRs384: | |
| 135 case kJwkAlgorithmRs512: | |
| 136 return WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; | |
| 137 case kJwkAlgorithmRsa1_5: | |
| 138 return WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5; | |
| 139 case kJwkAlgorithmRsaOaep: | |
| 140 return WebKit::WebCryptoAlgorithmIdRsaOaep; | |
| 141 case kJwkAlgorithmA128Kw: | |
| 142 case kJwkAlgorithmA256Kw: | |
| 143 // TODO(padolph) Support AES keywrap algorithm, required for JWK but not | |
| 144 // present in the Web Crypto spec. | |
| 145 return WebCryptoAlgorithmIdNone; | |
| 146 case kJwkAlgorithmA128Gcm: | |
| 147 case kJwkAlgorithmA256Gcm: | |
| 148 return WebKit::WebCryptoAlgorithmIdAesGcm; | |
| 149 case kJwkAlgorithmA128Cbc: | |
| 150 case kJwkAlgorithmA256Cbc: | |
| 151 case kJwkAlgorithmA384Cbc: | |
| 152 case kJwkAlgorithmA512Cbc: | |
| 153 return WebKit::WebCryptoAlgorithmIdAesCbc; | |
| 154 default: | |
| 155 DCHECK(false); | |
| 156 return WebCryptoAlgorithmIdNone; | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 unsigned short JwkAlgIdToKeyLengthBits(int jwk_algorithm_id) { | |
| 161 switch (jwk_algorithm_id) { | |
| 162 case kJwkAlgorithmA128Kw: | |
| 163 case kJwkAlgorithmA128Gcm: | |
| 164 case kJwkAlgorithmA128Cbc: | |
| 165 return 128; | |
| 166 case kJwkAlgorithmHs256: | |
| 167 case kJwkAlgorithmA256Kw: | |
| 168 case kJwkAlgorithmRs256: | |
| 169 case kJwkAlgorithmA256Gcm: | |
| 170 case kJwkAlgorithmA256Cbc: | |
| 171 return 256; | |
| 172 case kJwkAlgorithmHs384: | |
| 173 case kJwkAlgorithmRs384: | |
| 174 case kJwkAlgorithmA384Cbc: | |
| 175 return 384; | |
| 176 case kJwkAlgorithmHs512: | |
| 177 case kJwkAlgorithmRs512: | |
| 178 case kJwkAlgorithmA512Cbc: | |
| 179 return 512; | |
| 180 default: | |
| 181 return 0; | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 WebKit::WebCryptoAlgorithm CreateWebCryptoAlgorithmFromJwkAlgorithmId( | |
|
eroman
2013/10/22 21:49:38
I think things would be more readable to have a si
padolph
2013/10/28 20:35:07
Done. But since the creation functions have differ
| |
| 186 int jwk_algorithm_id) { | |
| 187 const unsigned short key_length_bits = | |
| 188 JwkAlgIdToKeyLengthBits(jwk_algorithm_id); | |
| 189 DCHECK(key_length_bits); | |
| 190 switch(jwk_algorithm_id) { | |
| 191 case kJwkAlgorithmHs256: | |
| 192 case kJwkAlgorithmHs384: | |
| 193 case kJwkAlgorithmHs512: | |
| 194 return CreateHmacAlgorithm(key_length_bits); | |
| 195 case kJwkAlgorithmRs256: | |
| 196 case kJwkAlgorithmRs384: | |
| 197 case kJwkAlgorithmRs512: | |
| 198 return CreateRsaSsaAlgorithm(key_length_bits); | |
| 199 case kJwkAlgorithmRsa1_5: | |
| 200 return CreateAlgorithm(WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); | |
| 201 case kJwkAlgorithmRsaOaep: | |
| 202 return CreateRsaOaepAlgorithm(key_length_bits); | |
| 203 case kJwkAlgorithmA128Kw: | |
| 204 case kJwkAlgorithmA256Kw: | |
| 205 // TODO(padolph) Support AES keywrap algorithm, required for JWK but not | |
| 206 // present in the Web Crypto spec. | |
| 207 return CreateAlgorithm(WebCryptoAlgorithmIdNone); | |
| 208 case kJwkAlgorithmA128Gcm: | |
| 209 case kJwkAlgorithmA256Gcm: | |
| 210 return CreateAesGcmAlgorithm(key_length_bits); | |
| 211 case kJwkAlgorithmA128Cbc: | |
| 212 case kJwkAlgorithmA256Cbc: | |
| 213 case kJwkAlgorithmA384Cbc: | |
| 214 case kJwkAlgorithmA512Cbc: | |
| 215 return CreateAesCbcAlgorithm(key_length_bits); | |
| 216 default: | |
| 217 DCHECK(false); | |
|
eroman
2013/10/22 21:49:38
NOTREACHED()
padolph
2013/10/28 20:35:07
This code is now gone.
| |
| 218 return CreateAlgorithm(WebCryptoAlgorithmIdNone); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 typedef std::map<std::string, int> StringIntMap; | |
| 223 | |
| 224 void InitJwkAlgorithmMap(StringIntMap& jwk_algorithm_map) | |
|
eroman
2013/10/22 21:49:38
Chromium style (unlike Blink style) does not like
padolph
2013/10/28 20:35:07
This code is now gone.
| |
| 225 { | |
| 226 // Note: A*CBC are not yet present in the JOSE JWA spec | |
| 227 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 | |
| 228 jwk_algorithm_map["HS256" ] = kJwkAlgorithmHs256; | |
|
eroman
2013/10/22 21:49:38
style nit: remove the space padding (i personally
padolph
2013/10/28 20:35:07
Done.
| |
| 229 jwk_algorithm_map["HS384" ] = kJwkAlgorithmHs384; | |
| 230 jwk_algorithm_map["HS512" ] = kJwkAlgorithmHs512; | |
| 231 jwk_algorithm_map["RS256" ] = kJwkAlgorithmRs256; | |
| 232 jwk_algorithm_map["RS384" ] = kJwkAlgorithmRs384; | |
| 233 jwk_algorithm_map["RS512" ] = kJwkAlgorithmRs512; | |
| 234 jwk_algorithm_map["RSA1_5" ] = kJwkAlgorithmRsa1_5; | |
| 235 jwk_algorithm_map["RSA-OAEP"] = kJwkAlgorithmRsaOaep; | |
| 236 jwk_algorithm_map["A128KW" ] = kJwkAlgorithmA128Kw; | |
| 237 jwk_algorithm_map["A256KW" ] = kJwkAlgorithmA256Kw; | |
| 238 jwk_algorithm_map["A128GCM" ] = kJwkAlgorithmA128Gcm; | |
| 239 jwk_algorithm_map["A256GCM" ] = kJwkAlgorithmA256Gcm; | |
| 240 jwk_algorithm_map["A128CBC" ] = kJwkAlgorithmA128Cbc; | |
| 241 jwk_algorithm_map["A256CBC" ] = kJwkAlgorithmA256Cbc; | |
| 242 jwk_algorithm_map["A384CBC" ] = kJwkAlgorithmA384Cbc; | |
| 243 jwk_algorithm_map["A512CBC" ] = kJwkAlgorithmA512Cbc; | |
| 244 } | |
| 245 | |
| 246 // forward | |
| 247 bool operator!=(const WebKit::WebCryptoAlgorithm& lhs, | |
| 248 const WebKit::WebCryptoAlgorithm& rhs); | |
| 249 | |
| 250 // TODO(padolph) Verify this logic is sufficient to judge algorithm | |
| 251 // "consistency" for JWK import, and for all supported algorithms. | |
| 252 bool operator==(const WebKit::WebCryptoAlgorithm& lhs, | |
|
eroman
2013/10/22 21:49:38
Chromium style guide doesn't like operator overloa
Ryan Sleevi
2013/10/24 01:45:58
Should WebKit::WebCryptoAlgorithm have an Equals()
eroman
2013/10/24 02:35:04
It isn't obvious what equality means, so I think t
padolph
2013/10/28 20:35:07
Function name changed. But I am also very confused
| |
| 253 const WebKit::WebCryptoAlgorithm& rhs) { | |
| 254 if (lhs.id() != rhs.id()) | |
| 255 return false; | |
| 256 if (lhs.id() == WebKit::WebCryptoAlgorithmIdHmac || | |
| 257 lhs.id() == WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | |
| 258 lhs.id() == WebKit::WebCryptoAlgorithmIdRsaOaep) { | |
| 259 if (lhs.hmacParams()->hash() != rhs.hmacParams()->hash()) | |
| 260 return false; | |
| 261 } | |
| 262 return true; | |
|
eroman
2013/10/22 21:49:38
For the sake of future proofing, I would rather ha
padolph
2013/10/28 20:35:07
Done.
| |
| 263 } | |
| 264 | |
| 265 bool operator!=(const WebKit::WebCryptoAlgorithm& lhs, | |
| 266 const WebKit::WebCryptoAlgorithm& rhs) { | |
| 267 return !(lhs == rhs); | |
| 268 } | |
| 269 | |
| 270 } // namespace | |
| 271 | |
| 14 WebCryptoImpl::WebCryptoImpl() { | 272 WebCryptoImpl::WebCryptoImpl() { |
| 15 Init(); | 273 Init(); |
| 274 InitJwkAlgorithmMap(jwk_algorithm_map_); | |
|
eroman
2013/10/22 21:49:38
I would prefer lazy initialization, since JWK may
Ryan Sleevi
2013/10/24 01:45:58
Don't use a function-level static. They're forbidd
eroman
2013/10/24 02:35:04
My mistake! I got muddled with Blink style vs Chro
padolph
2013/10/28 20:35:07
LazyInstance used.
| |
| 16 } | 275 } |
| 17 | 276 |
| 18 void WebCryptoImpl::encrypt( | 277 void WebCryptoImpl::encrypt( |
| 19 const WebKit::WebCryptoAlgorithm& algorithm, | 278 const WebKit::WebCryptoAlgorithm& algorithm, |
| 20 const WebKit::WebCryptoKey& key, | 279 const WebKit::WebCryptoKey& key, |
| 21 const unsigned char* data, | 280 const unsigned char* data, |
| 22 unsigned data_size, | 281 unsigned data_size, |
| 23 WebKit::WebCryptoResult result) { | 282 WebKit::WebCryptoResult result) { |
| 24 WebKit::WebArrayBuffer buffer; | 283 WebKit::WebArrayBuffer buffer; |
| 25 if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) { | 284 if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 WebKit::WebCryptoKeyFormat format, | 336 WebKit::WebCryptoKeyFormat format, |
| 78 const unsigned char* key_data, | 337 const unsigned char* key_data, |
| 79 unsigned key_data_size, | 338 unsigned key_data_size, |
| 80 const WebKit::WebCryptoAlgorithm& algorithm, | 339 const WebKit::WebCryptoAlgorithm& algorithm, |
| 81 bool extractable, | 340 bool extractable, |
| 82 WebKit::WebCryptoKeyUsageMask usage_mask, | 341 WebKit::WebCryptoKeyUsageMask usage_mask, |
| 83 WebKit::WebCryptoResult result) { | 342 WebKit::WebCryptoResult result) { |
| 84 WebKit::WebCryptoKeyType type; | 343 WebKit::WebCryptoKeyType type; |
| 85 scoped_ptr<WebKit::WebCryptoKeyHandle> handle; | 344 scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
| 86 | 345 |
| 87 if (!ImportKeyInternal(format, | 346 if (format == WebKit::WebCryptoKeyFormatJwk) { |
| 88 key_data, | 347 if (!ImportKeyJwk(key_data, |
| 89 key_data_size, | 348 key_data_size, |
| 90 algorithm, | 349 extractable, |
| 91 usage_mask, | 350 algorithm, |
| 92 &handle, | 351 usage_mask, |
| 93 &type)) { | 352 &handle, |
| 94 result.completeWithError(); | 353 &type)) { |
| 95 return; | 354 result.completeWithError(); |
| 355 } | |
| 356 } else { | |
| 357 if (!ImportKeyInternal(format, | |
| 358 key_data, | |
| 359 key_data_size, | |
| 360 algorithm, | |
| 361 usage_mask, | |
| 362 &handle, | |
| 363 &type)) { | |
| 364 result.completeWithError(); | |
| 365 } | |
| 96 } | 366 } |
| 97 | 367 |
| 98 WebKit::WebCryptoKey key( | 368 WebKit::WebCryptoKey key(WebKit::WebCryptoKey::create( |
| 99 WebKit::WebCryptoKey::create( | 369 handle.release(), type, extractable, algorithm, usage_mask)); |
| 100 handle.release(), type, extractable, algorithm, usage_mask)); | |
| 101 | 370 |
| 102 result.completeWithKey(key); | 371 result.completeWithKey(key); |
| 103 } | 372 } |
| 104 | 373 |
| 105 void WebCryptoImpl::sign( | 374 void WebCryptoImpl::sign( |
| 106 const WebKit::WebCryptoAlgorithm& algorithm, | 375 const WebKit::WebCryptoAlgorithm& algorithm, |
| 107 const WebKit::WebCryptoKey& key, | 376 const WebKit::WebCryptoKey& key, |
| 108 const unsigned char* data, | 377 const unsigned char* data, |
| 109 unsigned data_size, | 378 unsigned data_size, |
| 110 WebKit::WebCryptoResult result) { | 379 WebKit::WebCryptoResult result) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 131 signature_size, | 400 signature_size, |
| 132 data, | 401 data, |
| 133 data_size, | 402 data_size, |
| 134 &signature_match)) { | 403 &signature_match)) { |
| 135 result.completeWithError(); | 404 result.completeWithError(); |
| 136 } else { | 405 } else { |
| 137 result.completeWithBoolean(signature_match); | 406 result.completeWithBoolean(signature_match); |
| 138 } | 407 } |
| 139 } | 408 } |
| 140 | 409 |
| 410 bool WebCryptoImpl::ImportKeyJwk( | |
| 411 const unsigned char* key_data, | |
| 412 unsigned key_data_size, | |
| 413 bool extractable, | |
| 414 const WebKit::WebCryptoAlgorithm& algorithm, | |
| 415 WebKit::WebCryptoKeyUsageMask usage_mask, | |
| 416 scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, | |
| 417 WebKit::WebCryptoKeyType* type) { | |
| 418 | |
| 419 // JSON Web Key Format (JWK) | |
|
eroman
2013/10/22 21:49:38
This is a good comment block, thanks!
| |
| 420 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16 | |
| 421 // TODO(padolph) Not all possible values are handled by this code right now | |
| 422 // | |
| 423 // A JWK is a simple JSON dictionary with the following entries | |
| 424 // - "kty" (Key Type) Parameter, REQUIRED | |
| 425 // - <kty-specific parameters, see below>, REQUIRED | |
| 426 // - "use" (Key Use) Parameter, OPTIONAL | |
| 427 // - "alg" (Algorithm) Parameter, OPTIONAL | |
| 428 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE] | |
| 429 // (all other entries are ignored) | |
| 430 // | |
| 431 // Input key_data contains the JWK. To build a Web Crypto Key, the JWK values | |
| 432 // are parsed out and used as follows: | |
| 433 // Web Crypto Key type <-- (deduced) | |
| 434 // Web Crypto Key extractable <-- extractable | |
| 435 // Web Crypto Key algorithm <-- alg | |
| 436 // Web Crypto Key keyUsage <-- usage | |
| 437 // Web Crypto Key keying material <-- kty-specific parameters | |
| 438 // | |
| 439 // Values for each entry are case-sensitive and defined in | |
| 440 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16. | |
| 441 // Note that not all values specified by JOSE are handled by this code. Only | |
| 442 // handled values are listed. | |
| 443 // - kty (Key Type) | |
| 444 // +-------+--------------------------------------------------------------+ | |
| 445 // | "RSA" | RSA [RFC3447] | | |
| 446 // | "oct" | Octet sequence (used to represent symmetric keys) | | |
| 447 // +-------+--------------------------------------------------------------+ | |
| 448 // - use (Key Use) | |
| 449 // +-------+--------------------------------------------------------------+ | |
| 450 // | "enc" | encrypt and decrypt operations | | |
| 451 // | "sig" | sign and verify (MAC) operations | | |
| 452 // | "wrap"| key wrap and unwrap [not yet part of JOSE] | | |
| 453 // +-------+--------------------------------------------------------------+ | |
| 454 // - extractable (Key Exportability) | |
| 455 // +-------+--------------------------------------------------------------+ | |
| 456 // | true | Key may be exported from the trusted environment | | |
| 457 // | false | Key cannot exit the trusted environment | | |
| 458 // +-------+--------------------------------------------------------------+ | |
| 459 // - alg (Algorithm) | |
| 460 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 | |
| 461 // +--------------+-------------------------------------------------------+ | |
| 462 // | Digital Signature or MAC Algorithm | | |
| 463 // +--------------+-------------------------------------------------------+ | |
| 464 // | "HS256" | HMAC using SHA-256 hash algorithm | | |
| 465 // | "HS384" | HMAC using SHA-384 hash algorithm | | |
| 466 // | "HS512" | HMAC using SHA-512 hash algorithm | | |
| 467 // | "RS256" | RSASSA using SHA-256 hash algorithm | | |
| 468 // | "RS384" | RSASSA using SHA-384 hash algorithm | | |
| 469 // | "RS512" | RSASSA using SHA-512 hash algorithm | | |
| 470 // +--------------+-------------------------------------------------------| | |
| 471 // | Key Management Algorithm | | |
| 472 // +--------------+-------------------------------------------------------+ | |
| 473 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] | | |
| 474 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding | | |
| 475 // | | (OAEP) [RFC3447], with the default parameters | | |
| 476 // | | specified by RFC3447 in Section A.2.1 | | |
| 477 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm | | |
| 478 // | | [RFC3394] using 128 bit keys | | |
| 479 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys | | |
| 480 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using | | |
| 481 // | | 128 bit keys | | |
| 482 // | "A256GCM" | AES GCM using 256 bit keys | | |
| 483 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | | |
| 484 // | | padding [NIST.800-38A] [not yet part of JOSE] | | |
| 485 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] | | |
| 486 // | "A384CBC" | AES CBC using 384 bit keys [not yet part of JOSE] | | |
| 487 // | "A512CBC" | AES CBC using 512 bit keys [not yet part of JOSE] | | |
| 488 // +--------------+-------------------------------------------------------+ | |
| 489 // | |
| 490 // kty-specific parameters | |
| 491 // The value of kty determines the type and content of the keying material | |
| 492 // carried in the JWK to be imported. Currently only two possibilities are | |
| 493 // supported: a raw key or an RSA public key. RSA private keys are not | |
| 494 // supported because typical applications seldom need to import a private key, | |
| 495 // and the large number of JWK parameters required to describe one. | |
| 496 // - kty == "oct" (symmetric or other raw key) | |
| 497 // +-------+--------------------------------------------------------------+ | |
| 498 // | "k" | Contains the value of the symmetric (or other single-valued) | | |
| 499 // | | key. It is represented as the base64url encoding of the | | |
| 500 // | | octet sequence containing the key value. | | |
| 501 // +-------+--------------------------------------------------------------+ | |
| 502 // - kty == "RSA" (RSA public key) | |
| 503 // +-------+--------------------------------------------------------------+ | |
| 504 // | "n" | Contains the modulus value for the RSA public key. It is | | |
| 505 // | | represented as the base64url encoding of the value's | | |
| 506 // | | unsigned big endian representation as an octet sequence. | | |
| 507 // +-------+--------------------------------------------------------------+ | |
| 508 // | "e" | Contains the exponent value for the RSA public key. It is | | |
| 509 // | | represented as the base64url encoding of the value's | | |
| 510 // | | unsigned big endian representation as an octet sequence. | | |
| 511 // +-------+--------------------------------------------------------------+ | |
| 512 // | |
| 513 // Conflict resolution | |
| 514 // The type, algorithm, extractable, and usage_mask input parameters may be | |
| 515 // different from similar values inside the JWK. The Web Crypto spec says that | |
| 516 // if a JWK value is present, but is inconsistent with the input value, it is | |
| 517 // an error and the operation must fail. | |
| 518 | |
| 519 const char* const foo = reinterpret_cast<const char *>(key_data); | |
|
eroman
2013/10/22 21:49:38
Please use a variable name other than "foo".
padolph
2013/10/28 20:35:07
Done.
| |
| 520 base::StringPiece json_string(foo, key_data_size); | |
| 521 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); | |
| 522 // Note, bare pointer dict_value is ok since it points into scoped value. | |
| 523 base::DictionaryValue* dict_value = NULL; | |
| 524 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) | |
| 525 return false; | |
| 526 | |
| 527 // JWK "kty". Exit early if this required JWK parameter is missing. | |
| 528 std::string jwk_kty_value; | |
| 529 if (!dict_value->GetString("kty", &jwk_kty_value)) | |
| 530 return false; | |
| 531 | |
| 532 // JWK "extractable" --> extractable parameter | |
| 533 bool jwk_extractable_value; | |
| 534 if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) { | |
| 535 // collision check | |
| 536 if (jwk_extractable_value != extractable) | |
| 537 return false; | |
| 538 } | |
| 539 | |
| 540 // JWK "alg" --> algorithm parameter | |
| 541 std::string jwk_alg_value; | |
| 542 if (dict_value->GetString("alg", &jwk_alg_value)) { | |
| 543 const StringIntMap::iterator pos = jwk_algorithm_map_.find(jwk_alg_value); | |
|
eroman
2013/10/22 21:49:38
const_iterator?
padolph
2013/10/28 20:35:07
Done.
| |
| 544 if (pos == jwk_algorithm_map_.end()) | |
| 545 return false; | |
| 546 const int jwk_algorithm_id = pos->second; | |
| 547 WebKit::WebCryptoAlgorithm webcrypto_algorithm_from_jwk = | |
| 548 CreateWebCryptoAlgorithmFromJwkAlgorithmId(jwk_algorithm_id); | |
| 549 // collision check | |
| 550 if (webcrypto_algorithm_from_jwk != algorithm) | |
| 551 return false; | |
| 552 } | |
| 553 | |
| 554 // JWK "use" --> usage_mask parameter | |
| 555 std::string jwk_use_value; | |
| 556 if (dict_value->GetString("use", &jwk_use_value)) { | |
| 557 unsigned jwk_usage_mask; | |
| 558 if (jwk_use_value == "enc") { | |
| 559 jwk_usage_mask = | |
| 560 WebKit::WebCryptoKeyUsageEncrypt | WebKit::WebCryptoKeyUsageDecrypt; | |
| 561 } else if (jwk_use_value == "sig") { | |
| 562 jwk_usage_mask = | |
| 563 WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify; | |
| 564 } else if (jwk_use_value == "wrap") { | |
| 565 jwk_usage_mask = | |
| 566 WebKit::WebCryptoKeyUsageWrapKey | WebKit::WebCryptoKeyUsageUnwrapKey; | |
| 567 } else { | |
| 568 return false; | |
| 569 } | |
| 570 // collision check | |
| 571 if (!(jwk_usage_mask & usage_mask)) | |
|
eroman
2013/10/22 21:49:38
Do they need to match exactly?
Ryan Sleevi
2013/10/24 01:45:58
No.
The spec merely says that if they conflict in
eroman
2013/10/24 02:35:04
Thanks Ryan!
My understanding then is that we wan
padolph
2013/10/28 20:35:07
Yea, after thinking about it more, subset makes mo
| |
| 572 return false; | |
| 573 } | |
| 574 | |
| 575 // JWK keying material --> ImportKeyInternal() | |
| 576 if (jwk_kty_value == "oct") { | |
| 577 // collision check | |
| 578 if (*type != WebKit::WebCryptoKeyTypeSecret) | |
| 579 return false; | |
| 580 std::string jwk_k_value_url64; | |
| 581 if (!dict_value->GetString("k", &jwk_k_value_url64)) | |
| 582 return false; | |
| 583 std::string jwk_k_value; | |
| 584 if (!Base64DecodeUrlSafe(jwk_k_value_url64, &jwk_k_value)) | |
| 585 return false; | |
| 586 const std::vector<uint8> data(jwk_k_value.begin(), jwk_k_value.end()); | |
|
eroman
2013/10/22 21:49:38
Rather than copying into a std::vector<>, I believ
padolph
2013/10/28 20:35:07
Done.
| |
| 587 if (!ImportKeyInternal(WebKit::WebCryptoKeyFormatRaw, | |
| 588 &data[0], | |
|
eroman
2013/10/22 21:49:38
Is data guaranteed to have at least 1 element?
padolph
2013/10/28 20:35:07
No. I added a check for that plus a unit test. Tha
| |
| 589 data.size(), | |
| 590 algorithm, | |
| 591 usage_mask, | |
| 592 handle, | |
| 593 type)) { | |
| 594 return false; | |
| 595 } | |
| 596 } else if (jwk_kty_value == "RSA") { | |
| 597 // Only an RSA public key is currently handled. | |
| 598 // collision check | |
| 599 if (*type != WebKit::WebCryptoKeyTypePublic) | |
| 600 return false; | |
| 601 // TODO(padolph): JWK import RSA public key | |
| 602 return false; | |
| 603 } else { | |
| 604 return false; | |
| 605 } | |
| 606 | |
| 607 return true; | |
| 608 } | |
| 609 | |
| 141 } // namespace content | 610 } // namespace content |
| OLD | NEW |