summaryrefslogtreecommitdiffstats
path: root/components/webcrypto
diff options
context:
space:
mode:
authoreroman <eroman@chromium.org>2015-09-15 17:31:52 -0700
committerCommit bot <commit-bot@chromium.org>2015-09-16 00:32:36 +0000
commitdceea88ee742f7b4e6599156d7bc77a8d1968d61 (patch)
tree3afda1e23ac9e202972fed869c36cb254416f38c /components/webcrypto
parenta7c3f51cf5a2808acd9390edbb664ef5692cc20f (diff)
downloadchromium_src-dceea88ee742f7b4e6599156d7bc77a8d1968d61.zip
chromium_src-dceea88ee742f7b4e6599156d7bc77a8d1968d61.tar.gz
chromium_src-dceea88ee742f7b4e6599156d7bc77a8d1968d61.tar.bz2
[refactor] Move algorithm-specific JWK code into algorithm-specific files.
This is a cleanup possible now that the NSS implementation is gone. BUG=519504 Review URL: https://codereview.chromium.org/1314033006 Cr-Commit-Position: refs/heads/master@{#349048}
Diffstat (limited to 'components/webcrypto')
-rw-r--r--components/webcrypto/jwk.cc181
-rw-r--r--components/webcrypto/jwk.h87
-rw-r--r--components/webcrypto/openssl/aes_algorithm_openssl.cc43
-rw-r--r--components/webcrypto/openssl/hmac_openssl.cc23
-rw-r--r--components/webcrypto/openssl/rsa_hashed_algorithm_openssl.cc115
5 files changed, 167 insertions, 282 deletions
diff --git a/components/webcrypto/jwk.cc b/components/webcrypto/jwk.cc
index 7ae5ca2..701b82f 100644
--- a/components/webcrypto/jwk.cc
+++ b/components/webcrypto/jwk.cc
@@ -16,9 +16,6 @@
#include "components/webcrypto/status.h"
#include "components/webcrypto/webcrypto_util.h"
-// TODO(eroman): The algorithm-specific logic in this file for AES and RSA
-// should be moved into the corresponding AlgorithmImplementation file.
-
// JSON Web Key Format (JWK) is defined by:
// http://tools.ietf.org/html/draft-ietf-jose-json-web-key
//
@@ -400,184 +397,6 @@ void WriteSecretKeyJwk(const CryptoData& raw_key_data,
writer.ToJson(jwk_key_data);
}
-Status ReadSecretKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data) {
- JwkReader jwk;
- Status status = ReadSecretKeyNoExpectedAlg(
- key_data, expected_extractable, expected_usages, raw_key_data, &jwk);
- if (status.IsError())
- return status;
- return jwk.VerifyAlg(expected_alg);
-}
-
-std::string MakeJwkAesAlgorithmName(const std::string& suffix,
- size_t keylen_bytes) {
- if (keylen_bytes == 16)
- return std::string("A128") + suffix;
- if (keylen_bytes == 24)
- return std::string("A192") + suffix;
- if (keylen_bytes == 32)
- return std::string("A256") + suffix;
- return std::string();
-}
-
-Status ReadAesSecretKeyJwk(const CryptoData& key_data,
- const std::string& algorithm_name_suffix,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data) {
- JwkReader jwk;
- Status status = ReadSecretKeyNoExpectedAlg(
- key_data, expected_extractable, expected_usages, raw_key_data, &jwk);
- if (status.IsError())
- return status;
-
- bool has_jwk_alg;
- std::string jwk_alg;
- status = jwk.GetAlg(&jwk_alg, &has_jwk_alg);
- if (status.IsError())
- return status;
-
- if (has_jwk_alg) {
- std::string expected_algorithm_name =
- MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size());
-
- if (jwk_alg != expected_algorithm_name) {
- // Give a different error message if the key length was wrong.
- if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) ||
- jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) ||
- jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) {
- return Status::ErrorJwkIncorrectKeyLength();
- }
- return Status::ErrorJwkAlgorithmInconsistent();
- }
- }
-
- return Status::Success();
-}
-
-// Writes an RSA public key to a JWK dictionary
-void WriteRsaPublicKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data) {
- JwkWriter writer(algorithm, extractable, usages, "RSA");
- writer.SetBytes("n", n);
- writer.SetBytes("e", e);
- writer.ToJson(jwk_key_data);
-}
-
-// Writes an RSA private key to a JWK dictionary
-void WriteRsaPrivateKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const CryptoData& d,
- const CryptoData& p,
- const CryptoData& q,
- const CryptoData& dp,
- const CryptoData& dq,
- const CryptoData& qi,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data) {
- JwkWriter writer(algorithm, extractable, usages, "RSA");
-
- writer.SetBytes("n", n);
- writer.SetBytes("e", e);
- writer.SetBytes("d", d);
- // Although these are "optional" in the JWA, WebCrypto spec requires them to
- // be emitted.
- writer.SetBytes("p", p);
- writer.SetBytes("q", q);
- writer.SetBytes("dp", dp);
- writer.SetBytes("dq", dq);
- writer.SetBytes("qi", qi);
- writer.ToJson(jwk_key_data);
-}
-
-JwkRsaInfo::JwkRsaInfo() : is_private_key(false) {
-}
-
-JwkRsaInfo::~JwkRsaInfo() {
-}
-
-Status ReadRsaKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- JwkRsaInfo* result) {
- JwkReader jwk;
- Status status = jwk.Init(key_data, expected_extractable, expected_usages,
- "RSA", expected_alg);
- if (status.IsError())
- return status;
-
- // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
- // in the JWK, while an RSA private key must have those, plus at least a "d"
- // (private exponent) entry.
- // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
- // section 6.3.
- status = jwk.GetBigInteger("n", &result->n);
- if (status.IsError())
- return status;
- status = jwk.GetBigInteger("e", &result->e);
- if (status.IsError())
- return status;
-
- result->is_private_key = jwk.HasMember("d");
- if (!result->is_private_key)
- return Status::Success();
-
- status = jwk.GetBigInteger("d", &result->d);
- if (status.IsError())
- return status;
-
- // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
- // spec. However they are required by Chromium's WebCrypto implementation.
-
- status = jwk.GetBigInteger("p", &result->p);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("q", &result->q);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("dp", &result->dp);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("dq", &result->dq);
- if (status.IsError())
- return status;
-
- status = jwk.GetBigInteger("qi", &result->qi);
- if (status.IsError())
- return status;
-
- return Status::Success();
-}
-
-const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
- switch (hash) {
- case blink::WebCryptoAlgorithmIdSha1:
- return "HS1";
- case blink::WebCryptoAlgorithmIdSha256:
- return "HS256";
- case blink::WebCryptoAlgorithmIdSha384:
- return "HS384";
- case blink::WebCryptoAlgorithmIdSha512:
- return "HS512";
- default:
- return NULL;
- }
-}
-
bool Base64DecodeUrlSafe(const std::string& input, std::string* output) {
// The JSON web signature spec specifically says that padding is omitted.
if (input.find_first_of("+/=") != std::string::npos)
diff --git a/components/webcrypto/jwk.h b/components/webcrypto/jwk.h
index 5ab62fe..2c55582 100644
--- a/components/webcrypto/jwk.h
+++ b/components/webcrypto/jwk.h
@@ -140,91 +140,14 @@ void WriteSecretKeyJwk(const CryptoData& raw_key_data,
// Parses a UTF-8 encoded JWK (key_data), and extracts the key material to
// |*raw_key_data|. Returns Status::Success() on success, otherwise an error.
// In order for this to succeed:
-// * expected_alg must match the JWK's "alg", if present.
// * expected_extractable must be consistent with the JWK's "ext", if
// present.
// * expected_usages must be a subset of the JWK's "key_ops" if present.
-Status ReadSecretKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data);
-
-// Creates an AES algorithm name for the given key size (in bytes). For
-// instance "A128CBC" is the result of suffix="CBC", keylen_bytes=16.
-std::string MakeJwkAesAlgorithmName(const std::string& suffix,
- size_t keylen_bytes);
-
-// This is very similar to ReadSecretKeyJwk(), except instead of specifying an
-// absolute "expected_alg", the suffix for an AES algorithm name is given
-// (See MakeJwkAesAlgorithmName() for an explanation of what the suffix is).
-//
-// This is because the algorithm name for AES keys is dependent on the length
-// of the key. This function expects key lengths to be either 128, 192, or 256
-// bits.
-Status ReadAesSecretKeyJwk(const CryptoData& key_data,
- const std::string& algorithm_name_suffix,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- std::vector<uint8_t>* raw_key_data);
-
-// Writes a JWK-formated RSA public key and saves the result to
-// |*jwk_key_data|.
-void WriteRsaPublicKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data);
-
-// Writes a JWK-formated RSA private key and saves the result to
-// |*jwk_key_data|.
-void WriteRsaPrivateKeyJwk(const CryptoData& n,
- const CryptoData& e,
- const CryptoData& d,
- const CryptoData& p,
- const CryptoData& q,
- const CryptoData& dp,
- const CryptoData& dq,
- const CryptoData& qi,
- const std::string& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- std::vector<uint8_t>* jwk_key_data);
-
-// Describes the RSA components for a parsed key. The names of the properties
-// correspond with those from the JWK spec. Note that Chromium's WebCrypto
-// implementation does not support multi-primes, so there is no parsed field
-// for othinfo.
-struct JwkRsaInfo {
- JwkRsaInfo();
- ~JwkRsaInfo();
-
- bool is_private_key;
- std::string n;
- std::string e;
- std::string d;
- std::string p;
- std::string q;
- std::string dp;
- std::string dq;
- std::string qi;
-};
-
-// Parses a UTF-8 encoded JWK (key_data), and extracts the RSA components to
-// |*result|. Returns Status::Success() on success, otherwise an error.
-// In order for this to succeed:
-// * expected_alg must match the JWK's "alg", if present.
-// * expected_extractable must be consistent with the JWK's "ext", if
-// present.
-// * expected_usages must be a subset of the JWK's "key_ops" if present.
-Status ReadRsaKeyJwk(const CryptoData& key_data,
- const std::string& expected_alg,
- bool expected_extractable,
- blink::WebCryptoKeyUsageMask expected_usages,
- JwkRsaInfo* result);
-
-const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash);
+Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data,
+ bool expected_extractable,
+ blink::WebCryptoKeyUsageMask expected_usages,
+ std::vector<uint8_t>* raw_key_data,
+ JwkReader* jwk);
// This decodes JWK's flavor of base64 encoding, as described by:
// https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-36#section-2
diff --git a/components/webcrypto/openssl/aes_algorithm_openssl.cc b/components/webcrypto/openssl/aes_algorithm_openssl.cc
index 05e30c5..0a47286 100644
--- a/components/webcrypto/openssl/aes_algorithm_openssl.cc
+++ b/components/webcrypto/openssl/aes_algorithm_openssl.cc
@@ -15,6 +15,23 @@
namespace webcrypto {
+namespace {
+
+// Creates an AES algorithm name for the given key size (in bytes). For
+// instance "A128CBC" is the result of suffix="CBC", keylen_bytes=16.
+std::string MakeJwkAesAlgorithmName(const std::string& suffix,
+ size_t keylen_bytes) {
+ if (keylen_bytes == 16)
+ return std::string("A128") + suffix;
+ if (keylen_bytes == 24)
+ return std::string("A192") + suffix;
+ if (keylen_bytes == 32)
+ return std::string("A256") + suffix;
+ return std::string();
+}
+
+} // namespace
+
AesAlgorithm::AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,
const std::string& jwk_suffix)
: all_key_usages_(all_key_usages), jwk_suffix_(jwk_suffix) {
@@ -83,11 +100,33 @@ Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
std::vector<uint8_t> raw_data;
- Status status = ReadAesSecretKeyJwk(key_data, jwk_suffix_, extractable,
- usages, &raw_data);
+ JwkReader jwk;
+ Status status = ReadSecretKeyNoExpectedAlg(key_data, extractable, usages,
+ &raw_data, &jwk);
+ if (status.IsError())
+ return status;
+
+ bool has_jwk_alg;
+ std::string jwk_alg;
+ status = jwk.GetAlg(&jwk_alg, &has_jwk_alg);
if (status.IsError())
return status;
+ if (has_jwk_alg) {
+ std::string expected_algorithm_name =
+ MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size());
+
+ if (jwk_alg != expected_algorithm_name) {
+ // Give a different error message if the key length was wrong.
+ if (jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 16) ||
+ jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 24) ||
+ jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 32)) {
+ return Status::ErrorJwkIncorrectKeyLength();
+ }
+ return Status::ErrorJwkAlgorithmInconsistent();
+ }
+ }
+
return ImportKeyRaw(CryptoData(raw_data), algorithm, extractable, usages,
key);
}
diff --git a/components/webcrypto/openssl/hmac_openssl.cc b/components/webcrypto/openssl/hmac_openssl.cc
index 9962bfd..d436d46 100644
--- a/components/webcrypto/openssl/hmac_openssl.cc
+++ b/components/webcrypto/openssl/hmac_openssl.cc
@@ -22,6 +22,21 @@ namespace webcrypto {
namespace {
+const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
+ switch (hash) {
+ case blink::WebCryptoAlgorithmIdSha1:
+ return "HS1";
+ case blink::WebCryptoAlgorithmIdSha256:
+ return "HS256";
+ case blink::WebCryptoAlgorithmIdSha384:
+ return "HS384";
+ case blink::WebCryptoAlgorithmIdSha512:
+ return "HS512";
+ default:
+ return NULL;
+ }
+}
+
const blink::WebCryptoKeyUsageMask kAllKeyUsages =
blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
@@ -130,8 +145,12 @@ class HmacImplementation : public AlgorithmImplementation {
return Status::ErrorUnexpected();
std::vector<uint8_t> raw_data;
- Status status = ReadSecretKeyJwk(key_data, algorithm_name, extractable,
- usages, &raw_data);
+ JwkReader jwk;
+ Status status = ReadSecretKeyNoExpectedAlg(key_data, extractable, usages,
+ &raw_data, &jwk);
+ if (status.IsError())
+ return status;
+ status = jwk.VerifyAlg(algorithm_name);
if (status.IsError())
return status;
diff --git a/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.cc b/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.cc
index e672e13..1082639 100644
--- a/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.cc
+++ b/components/webcrypto/openssl/rsa_hashed_algorithm_openssl.cc
@@ -24,6 +24,86 @@ namespace webcrypto {
namespace {
+// Describes the RSA components for a parsed key. The names of the properties
+// correspond with those from the JWK spec. Note that Chromium's WebCrypto
+// implementation does not support multi-primes, so there is no parsed field
+// for "oth".
+struct JwkRsaInfo {
+ bool is_private_key = false;
+ std::string n;
+ std::string e;
+ std::string d;
+ std::string p;
+ std::string q;
+ std::string dp;
+ std::string dq;
+ std::string qi;
+};
+
+// Parses a UTF-8 encoded JWK (key_data), and extracts the RSA components to
+// |*result|. Returns Status::Success() on success, otherwise an error.
+// In order for this to succeed:
+// * expected_alg must match the JWK's "alg", if present.
+// * expected_extractable must be consistent with the JWK's "ext", if
+// present.
+// * expected_usages must be a subset of the JWK's "key_ops" if present.
+Status ReadRsaKeyJwk(const CryptoData& key_data,
+ const std::string& expected_alg,
+ bool expected_extractable,
+ blink::WebCryptoKeyUsageMask expected_usages,
+ JwkRsaInfo* result) {
+ JwkReader jwk;
+ Status status = jwk.Init(key_data, expected_extractable, expected_usages,
+ "RSA", expected_alg);
+ if (status.IsError())
+ return status;
+
+ // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
+ // in the JWK, while an RSA private key must have those, plus at least a "d"
+ // (private exponent) entry.
+ // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
+ // section 6.3.
+ status = jwk.GetBigInteger("n", &result->n);
+ if (status.IsError())
+ return status;
+ status = jwk.GetBigInteger("e", &result->e);
+ if (status.IsError())
+ return status;
+
+ result->is_private_key = jwk.HasMember("d");
+ if (!result->is_private_key)
+ return Status::Success();
+
+ status = jwk.GetBigInteger("d", &result->d);
+ if (status.IsError())
+ return status;
+
+ // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
+ // spec. However they are required by Chromium's WebCrypto implementation.
+
+ status = jwk.GetBigInteger("p", &result->p);
+ if (status.IsError())
+ return status;
+
+ status = jwk.GetBigInteger("q", &result->q);
+ if (status.IsError())
+ return status;
+
+ status = jwk.GetBigInteger("dp", &result->dp);
+ if (status.IsError())
+ return status;
+
+ status = jwk.GetBigInteger("dq", &result->dq);
+ if (status.IsError())
+ return status;
+
+ status = jwk.GetBigInteger("qi", &result->qi);
+ if (status.IsError())
+ return status;
+
+ return Status::Success();
+}
+
// Creates a blink::WebCryptoAlgorithm having the modulus length and public
// exponent of |key|.
Status CreateRsaHashedKeyAlgorithm(
@@ -343,23 +423,28 @@ Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
return Status::ErrorUnexpected();
switch (key.type()) {
- case blink::WebCryptoKeyTypePublic:
- WriteRsaPublicKeyJwk(CryptoData(BIGNUMToVector(rsa->n)),
- CryptoData(BIGNUMToVector(rsa->e)), jwk_algorithm,
- key.extractable(), key.usages(), buffer);
+ case blink::WebCryptoKeyTypePublic: {
+ JwkWriter writer(jwk_algorithm, key.extractable(), key.usages(), "RSA");
+ writer.SetBytes("n", CryptoData(BIGNUMToVector(rsa->n)));
+ writer.SetBytes("e", CryptoData(BIGNUMToVector(rsa->e)));
+ writer.ToJson(buffer);
return Status::Success();
- case blink::WebCryptoKeyTypePrivate:
- WriteRsaPrivateKeyJwk(CryptoData(BIGNUMToVector(rsa->n)),
- CryptoData(BIGNUMToVector(rsa->e)),
- CryptoData(BIGNUMToVector(rsa->d)),
- CryptoData(BIGNUMToVector(rsa->p)),
- CryptoData(BIGNUMToVector(rsa->q)),
- CryptoData(BIGNUMToVector(rsa->dmp1)),
- CryptoData(BIGNUMToVector(rsa->dmq1)),
- CryptoData(BIGNUMToVector(rsa->iqmp)),
- jwk_algorithm, key.extractable(), key.usages(),
- buffer);
+ }
+ case blink::WebCryptoKeyTypePrivate: {
+ JwkWriter writer(jwk_algorithm, key.extractable(), key.usages(), "RSA");
+ writer.SetBytes("n", CryptoData(BIGNUMToVector(rsa->n)));
+ writer.SetBytes("e", CryptoData(BIGNUMToVector(rsa->e)));
+ writer.SetBytes("d", CryptoData(BIGNUMToVector(rsa->d)));
+ // Although these are "optional" in the JWA, WebCrypto spec requires them
+ // to be emitted.
+ writer.SetBytes("p", CryptoData(BIGNUMToVector(rsa->p)));
+ writer.SetBytes("q", CryptoData(BIGNUMToVector(rsa->q)));
+ writer.SetBytes("dp", CryptoData(BIGNUMToVector(rsa->dmp1)));
+ writer.SetBytes("dq", CryptoData(BIGNUMToVector(rsa->dmq1)));
+ writer.SetBytes("qi", CryptoData(BIGNUMToVector(rsa->iqmp)));
+ writer.ToJson(buffer);
return Status::Success();
+ }
default:
return Status::ErrorUnexpected();