Chromium Code Reviews| Index: content/renderer/webcrypto/webcrypto_impl.cc |
| diff --git a/content/renderer/webcrypto/webcrypto_impl.cc b/content/renderer/webcrypto/webcrypto_impl.cc |
| index 6eeb3daf5a0cb07de9dc19128ed3e2913338054b..d4562f8fcc67ee8f46243bc50eb3bf9b6537b95b 100644 |
| --- a/content/renderer/webcrypto/webcrypto_impl.cc |
| +++ b/content/renderer/webcrypto/webcrypto_impl.cc |
| @@ -4,15 +4,242 @@ |
| #include "content/renderer/webcrypto/webcrypto_impl.h" |
| +#include <algorithm> |
| +#include <map> |
| +#include "base/base64.h" |
| +#include "base/json/json_reader.h" |
| +#include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| +#include "base/strings/string_piece.h" |
| +#include "base/values.h" |
| #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
| #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
| +#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
| #include "third_party/WebKit/public/platform/WebCryptoKey.h" |
| namespace content { |
| +namespace { |
| + |
| +// TODO(padolph) Similar Create*Algorithm() methods are in |
| +// webcrypto_impl_unittest.cc. Find a common place to put these. |
| + |
| +WebKit::WebCryptoAlgorithm CreateAlgorithm(WebKit::WebCryptoAlgorithmId id) { |
| + return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); |
| +} |
| + |
| +WebKit::WebCryptoAlgorithm CreateAlgorithmWithInnerHash( |
| + WebKit::WebCryptoAlgorithmId algorithm_id, |
| + unsigned short hash_key_length) { |
| + WebKit::WebCryptoAlgorithmId hashId; |
| + switch (hash_key_length) { |
| + case 160: |
| + hashId = WebKit::WebCryptoAlgorithmIdSha1; |
| + break; |
| + case 224: |
| + hashId = WebKit::WebCryptoAlgorithmIdSha224; |
| + break; |
| + case 256: |
| + hashId = WebKit::WebCryptoAlgorithmIdSha256; |
| + break; |
| + case 384: |
| + hashId = WebKit::WebCryptoAlgorithmIdSha384; |
| + break; |
| + case 512: |
| + hashId = WebKit::WebCryptoAlgorithmIdSha384; |
| + break; |
| + } |
| + return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( |
| + algorithm_id, |
| + new WebKit::WebCryptoHmacParams(CreateAlgorithm(hashId))); |
| +} |
| + |
| +WebKit::WebCryptoAlgorithm CreateHmacAlgorithm(unsigned short hash_key_length) { |
| + return CreateAlgorithmWithInnerHash( |
| + WebKit::WebCryptoAlgorithmIdHmac, |
| + hash_key_length); |
| +} |
| + |
| +WebKit::WebCryptoAlgorithm CreateRsaSsaAlgorithm( |
| + unsigned short hash_key_length) { |
| + return CreateAlgorithmWithInnerHash( |
| + WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| + hash_key_length); |
| +} |
| + |
| +WebKit::WebCryptoAlgorithm CreateRsaOaepAlgorithm( |
| + unsigned short hash_key_length) { |
| + return CreateAlgorithmWithInnerHash( |
| + WebKit::WebCryptoAlgorithmIdRsaOaep, |
| + hash_key_length); |
| +} |
| + |
| +WebKit::WebCryptoAlgorithm CreateAesAlgorithm( |
| + WebKit::WebCryptoAlgorithmId aes_alg_id, |
| + unsigned short length) { |
| + return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( |
| + aes_alg_id, |
| + new WebKit::WebCryptoAesKeyGenParams(length)); |
| +} |
| + |
| +WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm(unsigned short length) { |
| + return CreateAesAlgorithm(WebKit::WebCryptoAlgorithmIdAesCbc, length); |
| +} |
| + |
| +WebKit::WebCryptoAlgorithm CreateAesGcmAlgorithm(unsigned short length) { |
| + return CreateAesAlgorithm(WebKit::WebCryptoAlgorithmIdAesGcm, length); |
| +} |
| + |
| +bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { |
| + std::string base64EncodedText(input); |
| + std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+'); |
| + std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/'); |
| + base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '='); |
| + return base::Base64Decode(base64EncodedText, output); |
| +} |
| + |
| +// Identifiers for all JWK "alg" (algorithm) values handled by this code. The |
| +// "enum trick" is used to force int type, so a user type is not required in |
| +// web_crypto_impl.h |
| +enum { |
| + kJwkAlgorithmHs256, |
| + kJwkAlgorithmHs384, |
| + kJwkAlgorithmHs512, |
| + kJwkAlgorithmRs256, |
| + kJwkAlgorithmRs384, |
| + kJwkAlgorithmRs512, |
| + kJwkAlgorithmRsa1_5, |
| + kJwkAlgorithmRsaOaep, |
| + kJwkAlgorithmA128Kw, |
| + kJwkAlgorithmA256Kw, |
| + kJwkAlgorithmA128Gcm, |
| + kJwkAlgorithmA256Gcm, |
| + kJwkAlgorithmA128Cbc, |
| + kJwkAlgorithmA256Cbc, |
| + kJwkAlgorithmA384Cbc, |
| + kJwkAlgorithmA512Cbc |
| +}; |
| + |
| +WebKit::WebCryptoAlgorithmId JwkAlgIdToWebCryptoAlgId(int jwk_algorithm_id) { |
| + switch (jwk_algorithm_id) { |
| + case kJwkAlgorithmHs256: |
| + case kJwkAlgorithmHs384: |
| + case kJwkAlgorithmHs512: |
| + return WebKit::WebCryptoAlgorithmIdHmac; |
| + case kJwkAlgorithmRs256: |
| + case kJwkAlgorithmRs384: |
| + case kJwkAlgorithmRs512: |
| + return WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; |
| + case kJwkAlgorithmRsa1_5: |
| + return WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5; |
| + case kJwkAlgorithmRsaOaep: |
| + return WebKit::WebCryptoAlgorithmIdRsaOaep; |
| + case kJwkAlgorithmA128Kw: |
| + case kJwkAlgorithmA256Kw: |
| + // TODO(padolph) Support AES keywrap algorithm, required for JWK but not |
| + // present in the Web Crypto spec. |
| + return WebKit::WebCryptoAlgorithmIdNone; |
| + case kJwkAlgorithmA128Gcm: |
| + case kJwkAlgorithmA256Gcm: |
| + return WebKit::WebCryptoAlgorithmIdAesGcm; |
| + case kJwkAlgorithmA128Cbc: |
| + case kJwkAlgorithmA256Cbc: |
| + case kJwkAlgorithmA384Cbc: |
| + case kJwkAlgorithmA512Cbc: |
| + return WebKit::WebCryptoAlgorithmIdAesCbc; |
| + default: |
| + DCHECK(false); |
| + return WebKit::WebCryptoAlgorithmIdNone; |
| + } |
| +} |
| + |
| +unsigned short JwkAlgIdToKeyLengthBits(int jwk_algorithm_id) { |
| + switch (jwk_algorithm_id) { |
| + case kJwkAlgorithmA128Kw: |
| + case kJwkAlgorithmA128Gcm: |
| + case kJwkAlgorithmA128Cbc: |
| + return 128; |
| + case kJwkAlgorithmHs256: |
| + case kJwkAlgorithmA256Kw: |
| + case kJwkAlgorithmRs256: |
| + case kJwkAlgorithmA256Gcm: |
| + case kJwkAlgorithmA256Cbc: |
| + return 256; |
| + case kJwkAlgorithmHs384: |
| + case kJwkAlgorithmRs384: |
| + case kJwkAlgorithmA384Cbc: |
| + return 384; |
| + case kJwkAlgorithmHs512: |
| + case kJwkAlgorithmRs512: |
| + case kJwkAlgorithmA512Cbc: |
| + return 512; |
| + default: |
| + return 0; |
| + } |
| +} |
| + |
| +typedef std::map<std::string, int> StringIntMap; |
| + |
| +// Syntactic sugar to make runtime initialization of a std::map more palatable, |
| +// similar to what you can do in C++11 or with Boost.Assign. |
| +// Example: |
| +// StringIntMap my_map; |
| +// // instead of this |
| +// my_map.insert(std::make_pair("a", 1); |
| +// my_map.insert(std::make_pair("b", 2); |
| +// my_map.insert(std::make_pair("c", 3); |
| +// my_map.insert(std::make_pair("d", 4); |
| +// // do this |
| +// map_fill<StringIntMap> |
| +// ("a", 1) |
| +// ("b", 2) |
| +// ("c", 3) |
| +// ("d", 4) |
| +// .to(my_map); |
|
Ryan Sleevi
2013/10/04 23:19:11
Why is this syntactic sugar needed, when
my_map["
padolph
2013/10/05 02:57:42
Done.
|
| +template <typename MapType> |
| +class FillMap { |
| + public: |
| + typedef typename MapType::key_type KeyType; |
| + typedef typename MapType::mapped_type MappedType; |
| + FillMap(const KeyType& key, const MappedType& val) { operator()(key, val); } |
| + FillMap& operator()(const KeyType& key, const MappedType& val) { |
| + map_.insert(std::make_pair(key, val)); |
| + return *this; |
| + } |
| + void to(MapType& map) { map.swap(map_); } |
| + private: |
| + MapType map_; |
| +}; |
| + |
| +void InitJwkAlgorithmMap(StringIntMap& jwk_algorithm_map) |
| +{ |
| + // Note: A*CBC are not yet present in the JOSE JWA spec |
| + // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 |
| + FillMap<StringIntMap> |
| + ("HS256" , kJwkAlgorithmHs256 ) |
| + ("HS384" , kJwkAlgorithmHs384 ) |
| + ("HS512" , kJwkAlgorithmHs512 ) |
| + ("RS256" , kJwkAlgorithmRs256 ) |
| + ("RS384" , kJwkAlgorithmRs384 ) |
| + ("RS512" , kJwkAlgorithmRs512 ) |
| + ("RSA1_5" , kJwkAlgorithmRsa1_5 ) |
| + ("RSA-OAEP", kJwkAlgorithmRsaOaep) |
| + ("A128KW" , kJwkAlgorithmA128Kw ) |
| + ("A256KW" , kJwkAlgorithmA256Kw ) |
| + ("A128GCM" , kJwkAlgorithmA128Gcm) |
| + ("A256GCM" , kJwkAlgorithmA256Gcm) |
| + ("A128CBC" , kJwkAlgorithmA128Cbc) |
| + ("A256CBC" , kJwkAlgorithmA256Cbc) |
| + ("A384CBC" , kJwkAlgorithmA384Cbc) |
| + ("A512CBC" , kJwkAlgorithmA512Cbc) |
| + .to(jwk_algorithm_map); |
| +} |
| + |
| +} // namespace |
| + |
| WebCryptoImpl::WebCryptoImpl() { |
| Init(); |
| + InitJwkAlgorithmMap(jwk_algorithm_map_); |
| } |
| void WebCryptoImpl::encrypt( |
| @@ -66,21 +293,32 @@ void WebCryptoImpl::importKey( |
| WebKit::WebCryptoResult result) { |
| WebKit::WebCryptoKeyType type; |
| scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
| + WebKit::WebCryptoAlgorithm modified_algorithm = algorithm; |
| - if (!ImportKeyInternal(format, |
| - key_data, |
| - key_data_size, |
| - algorithm, |
| - usage_mask, |
| - &handle, |
| - &type)) { |
| - result.completeWithError(); |
| - return; |
| + if (format == WebKit::WebCryptoKeyFormatJwk) { |
| + if (!ImportKeyJwk(key_data, |
| + key_data_size, |
| + &handle, |
| + &type, |
| + &extractable, |
| + &modified_algorithm, |
| + &usage_mask)) { |
| + result.completeWithError(); |
| + } |
| + } else { |
| + if (!ImportKeyInternal(format, |
| + key_data, |
| + key_data_size, |
| + modified_algorithm, |
| + usage_mask, |
| + &handle, |
| + &type)) { |
| + result.completeWithError(); |
| + } |
| } |
| - WebKit::WebCryptoKey key( |
| - WebKit::WebCryptoKey::create( |
| - handle.release(), type, extractable, algorithm, usage_mask)); |
| + WebKit::WebCryptoKey key(WebKit::WebCryptoKey::create( |
| + handle.release(), type, extractable, modified_algorithm, usage_mask)); |
| result.completeWithKey(key); |
| } |
| @@ -121,4 +359,214 @@ void WebCryptoImpl::verifySignature( |
| } |
| } |
| +bool WebCryptoImpl::ImportKeyJwk( |
| + const unsigned char* key_data, |
| + unsigned key_data_size, |
| + scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, |
| + WebKit::WebCryptoKeyType* type, |
| + bool* extractable, |
| + WebKit::WebCryptoAlgorithm* algorithm, |
| + WebKit::WebCryptoKeyUsageMask* usage_mask) { |
| + |
| + // JSON Web Key Format (JWK) |
| + // http://self-issued.info/docs/draft-ietf-jose-json-web-key.html (JOSE) |
|
Ryan Sleevi
2013/10/04 23:19:11
Let's refer to a canonical draft URL at the IETF,
padolph
2013/10/05 02:57:42
Done.
|
| + // TODO(padolph) Not all possible values are handled by this code right now |
| + // |
| + // A JWK is a simple JSON dictionary with the following entries |
| + // - "kty" (Key Type) Parameter, REQUIRED |
| + // - <kty-specific parameters, see below>, REQUIRED |
| + // - "use" (Key Use) Parameter, OPTIONAL |
| + // - "alg" (Algorithm) Parameter, OPTIONAL |
| + // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE] |
| + // (all other entries are ignored) |
| + // |
| + // Input key_data contains the JWK. To build a Web Crypto Key, the JWK values |
| + // are parsed out and used as follows: |
| + // Web Crypto Key type <-- (deduced) |
| + // Web Crypto Key extractable <-- extractable |
| + // Web Crypto Key algorithm <-- alg |
| + // Web Crypto Key keyUsage <-- usage |
| + // Web Crypto Key keying material <-- kty-specific parameters |
| + // |
| + // Values for each entry are case-sensitive and defined in |
| + // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16. |
| + // Note that not all values specified by JOSE are handled by this code. Only |
| + // handled values are listed. |
| + // - kty (Key Type) |
| + // +-------+--------------------------------------------------------------+ |
| + // | "RSA" | RSA [RFC3447] | |
| + // | "oct" | Octet sequence (used to represent symmetric keys) | |
| + // +-------+--------------------------------------------------------------+ |
| + // - use (Key Use) |
| + // +-------+--------------------------------------------------------------+ |
| + // | "enc" | encrypt and decrypt operations | |
| + // | "sig" | sign and verify (MAC) operations | |
| + // | "wrap"| key wrap and unwrap [not yet part of JOSE] | |
| + // +-------+--------------------------------------------------------------+ |
| + // - extractable (Key Exportability) |
| + // +-------+--------------------------------------------------------------+ |
| + // | true | Key may be exported from the trusted environment | |
| + // | false | Key cannot exit the trusted environment | |
| + // +-------+--------------------------------------------------------------+ |
| + // - alg (Algorithm) |
| + // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 |
| + // +--------------+-------------------------------------------------------+ |
| + // | Digital Signature or MAC Algorithm | |
| + // +--------------+-------------------------------------------------------+ |
| + // | "HS256" | HMAC using SHA-256 hash algorithm | |
| + // | "HS384" | HMAC using SHA-384 hash algorithm | |
| + // | "HS512" | HMAC using SHA-512 hash algorithm | |
| + // | "RS256" | RSASSA using SHA-256 hash algorithm | |
| + // | "RS384" | RSASSA using SHA-384 hash algorithm | |
| + // | "RS512" | RSASSA using SHA-512 hash algorithm | |
| + // +--------------+-------------------------------------------------------| |
| + // | Key Management Algorithm | |
| + // +--------------+-------------------------------------------------------+ |
| + // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] | |
| + // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding | |
| + // | | (OAEP) [RFC3447], with the default parameters | |
| + // | | specified by RFC3447 in Section A.2.1 | |
| + // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm | |
| + // | | [RFC3394] using 128 bit keys | |
| + // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys | |
| + // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using | |
| + // | | 128 bit keys | |
| + // | "A256GCM" | AES GCM using 256 bit keys | |
| + // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | |
| + // | | padding [NIST.800-38A] [not yet part of JOSE] | |
| + // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] | |
| + // | "A384CBC" | AES CBC using 384 bit keys [not yet part of JOSE] | |
| + // | "A512CBC" | AES CBC using 512 bit keys [not yet part of JOSE] | |
| + // +--------------+-------------------------------------------------------+ |
| + // |
| + // kty-specific parameters |
| + // The value of kty determines the type and content of the keying material |
| + // carried in the JWK to be imported. Currently only two possibilities are |
| + // supported: a raw key or an RSA public key. RSA private keys are not |
| + // supported because typical applications seldom need to import a private key, |
| + // and the large number of JWK parameters required to describe one. |
| + // - kty == "oct" (symmetric or other raw key) |
| + // +-------+--------------------------------------------------------------+ |
| + // | "k" | Contains the value of the symmetric (or other single-valued) | |
| + // | | key. It is represented as the base64url encoding of the | |
| + // | | octet sequence containing the key value. | |
| + // +-------+--------------------------------------------------------------+ |
| + // - kty == "RSA" (RSA public key) |
| + // +-------+--------------------------------------------------------------+ |
| + // | "n" | Contains the modulus value for the RSA public key. It is | |
| + // | | represented as the base64url encoding of the value's | |
| + // | | unsigned big endian representation as an octet sequence. | |
| + // +-------+--------------------------------------------------------------+ |
| + // | "e" | Contains the exponent value for the RSA public key. It is | |
| + // | | represented as the base64url encoding of the value's | |
| + // | | unsigned big endian representation as an octet sequence. | |
| + // +-------+--------------------------------------------------------------+ |
| + // |
| + // Conflict resolution |
| + // The type, algorithm, extractable, and usage_mask input parameters may be |
| + // different from similar values inside the JWK. Conflicts are resolved as |
| + // follows: |
| + // type: Deduce value from JWK contents only, ignore input value |
| + // algorithm: Use JWK value if present, otherwise use input value |
| + // extractable: If JWK value present, logical AND of the input and JWK values, |
| + // otherwise use input value |
| + // keyUsage: Use JWK value if present, otherwise use input value |
|
Ryan Sleevi
2013/10/04 23:19:11
These are all things that should be in the spec be
padolph
2013/10/05 02:57:42
The other parameters are easy, but can you please
|
| + |
| + std::string jsonStr(key_data, key_data + key_data_size); |
|
Ryan Sleevi
2013/10/04 23:19:11
json_str
However, you don't need to use std::stri
padolph
2013/10/05 02:57:42
Done.
|
| + scoped_ptr<base::Value> value(base::JSONReader::Read(jsonStr)); |
| + // Note, bare pointer dict_value is ok since it points into scoped value. |
| + base::DictionaryValue* dict_value = NULL; |
| + if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) |
| + return false; |
| + |
| + // JWK "kty". Exit early if this required JWK parameter is missing. |
| + std::string jwk_kty_value; |
| + if (!dict_value->GetString("kty", &jwk_kty_value)) |
| + return false; |
| + |
| + // JWK "extractable" --> extractable parameter |
| + bool jwk_extractable_value; |
| + if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) { |
| + *extractable &= jwk_extractable_value; |
| + } |
| + |
| + // JWK "alg" --> algorithm parameter |
| + std::string jwk_alg_value; |
| + if (dict_value->GetString("alg", &jwk_alg_value)) { |
| + const StringIntMap::iterator pos = jwk_algorithm_map_.find(jwk_alg_value); |
| + if (pos == jwk_algorithm_map_.end()) |
| + return false; |
| + const int jwk_algorithm_id = pos->second; |
| + const unsigned short key_length_bits = |
| + JwkAlgIdToKeyLengthBits(jwk_algorithm_id); |
| + const WebKit::WebCryptoAlgorithmId webcrypto_algorithm_id = |
| + JwkAlgIdToWebCryptoAlgId(jwk_algorithm_id); |
| + switch (webcrypto_algorithm_id) { |
| + case WebKit::WebCryptoAlgorithmIdHmac: |
| + *algorithm = CreateHmacAlgorithm(key_length_bits); |
| + break; |
| + case WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: |
| + *algorithm = CreateRsaSsaAlgorithm(key_length_bits); |
| + break; |
| + case WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: |
| + *algorithm = CreateAlgorithm(webcrypto_algorithm_id); |
| + break; |
| + case WebKit::WebCryptoAlgorithmIdRsaOaep: |
| + *algorithm = CreateRsaOaepAlgorithm(key_length_bits); |
| + break; |
| + case WebKit::WebCryptoAlgorithmIdAesGcm: |
| + *algorithm = CreateAesGcmAlgorithm(key_length_bits); |
| + break; |
| + case WebKit::WebCryptoAlgorithmIdAesCbc: |
| + *algorithm = CreateAesCbcAlgorithm(key_length_bits); |
| + break; |
| + default: |
| + return false; |
| + } |
| + } |
| + |
| + // JWK "use" --> usage_mask parameter |
| + std::string jwk_use_value; |
| + if (dict_value->GetString("use", &jwk_use_value)) { |
| + if (jwk_use_value == "enc") { |
| + *usage_mask = |
| + WebKit::WebCryptoKeyUsageEncrypt | WebKit::WebCryptoKeyUsageDecrypt; |
| + } else if (jwk_use_value == "sig") { |
| + *usage_mask = |
| + WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify; |
| + } else if (jwk_use_value == "wrap") { |
| + *usage_mask = |
| + WebKit::WebCryptoKeyUsageWrapKey | WebKit::WebCryptoKeyUsageUnwrapKey; |
| + } else { |
| + return false; |
| + } |
| + } |
| + |
| + // JWK keying material --> ImportKeyInternal() |
| + if (jwk_kty_value == "oct") { |
| + std::string jwk_k_value_url64; |
| + if (!dict_value->GetString("k", &jwk_k_value_url64)) |
| + return false; |
| + std::string jwk_k_value; |
| + if (!Base64DecodeUrlSafe(jwk_k_value_url64, &jwk_k_value)) |
| + return false; |
| + const std::vector<uint8> data(jwk_k_value.begin(), jwk_k_value.end()); |
| + if (!ImportKeyInternal(WebKit::WebCryptoKeyFormatRaw, |
| + &data[0], |
| + data.size(), |
| + *algorithm, |
| + *usage_mask, |
| + handle, |
| + type)) |
| + return false; |
| + } else if (jwk_kty_value == "RSA") { |
| + // TODO(padolph): RSA public key |
| + return false; |
| + } else { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| } // namespace content |