summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/platform_keys/platform_keys.h20
-rw-r--r--chrome/browser/chromeos/platform_keys/platform_keys_nss.cc30
-rw-r--r--chrome/browser/chromeos/platform_keys/platform_keys_service.cc11
-rw-r--r--chrome/browser/chromeos/platform_keys/platform_keys_service.h7
-rw-r--r--chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc14
-rw-r--r--chrome/common/extensions/api/enterprise_platform_keys_internal.idl6
-rw-r--r--chrome/renderer/extensions/enterprise_platform_keys_natives.cc9
-rw-r--r--chrome/renderer/extensions/enterprise_platform_keys_natives.h3
-rw-r--r--chrome/renderer/resources/extensions/enterprise_platform_keys/subtle_crypto.js30
9 files changed, 106 insertions, 24 deletions
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys.h b/chrome/browser/chromeos/platform_keys/platform_keys.h
index a1a4827..2a61275 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys.h
+++ b/chrome/browser/chromeos/platform_keys/platform_keys.h
@@ -26,6 +26,14 @@ namespace chromeos {
namespace platform_keys {
+// Supported hash algorithms.
+enum HashAlgorithm {
+ HASH_ALGORITHM_SHA1,
+ HASH_ALGORITHM_SHA256,
+ HASH_ALGORITHM_SHA384,
+ HASH_ALGORITHM_SHA512
+};
+
namespace subtle {
// Functions of this namespace shouldn't be called directly from the context of
// an extension. Instead use PlatformKeysService which enforces restrictions
@@ -46,14 +54,16 @@ void GenerateRSAKey(const std::string& token_id,
typedef base::Callback<void(const std::string& signature,
const std::string& error_message)> SignCallback;
-// Signs |data| with the private key matching |public_key|, if that key is
-// stored in the given token. |token_id| is currently ignored, instead the user
-// token associated with |browser_context| is always used. |public_key| must be
-// the DER encoding of a SubjectPublicKeyInfo. |callback| will be invoked with
-// the signature or an error message.
+// Digests |data| with |hash_algorithm| and afterwards signs the digest with the
+// private key matching |public_key|, if that key is stored in the given token.
+// |token_id| is currently ignored, instead the user token associated with
+// |browser_context| is always used. |public_key| must be the DER encoding of a
+// SubjectPublicKeyInfo. |callback| will be invoked with the signature or an
+// error message.
// Currently supports RSA keys only.
void Sign(const std::string& token_id,
const std::string& public_key,
+ HashAlgorithm hash_algorithm,
const std::string& data,
const SignCallback& callback,
content::BrowserContext* browser_context);
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
index 87dfde6..f3a0208 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
@@ -152,6 +152,7 @@ class GenerateRSAKeyState : public NSSOperationState {
class SignState : public NSSOperationState {
public:
SignState(const std::string& public_key,
+ HashAlgorithm hash_algorithm,
const std::string& data,
const subtle::SignCallback& callback);
virtual ~SignState() {}
@@ -169,6 +170,7 @@ class SignState : public NSSOperationState {
}
const std::string public_key_;
+ HashAlgorithm hash_algorithm_;
const std::string data_;
private:
@@ -259,9 +261,13 @@ GenerateRSAKeyState::GenerateRSAKeyState(
}
SignState::SignState(const std::string& public_key,
+ HashAlgorithm hash_algorithm,
const std::string& data,
const subtle::SignCallback& callback)
- : public_key_(public_key), data_(data), callback_(callback) {
+ : public_key_(public_key),
+ hash_algorithm_(hash_algorithm),
+ data_(data),
+ callback_(callback) {
}
GetCertificatesState::GetCertificatesState(
@@ -333,12 +339,28 @@ void RSASignOnWorkerThread(scoped_ptr<SignState> state) {
return;
}
+ SECOidTag sign_alg_tag = SEC_OID_UNKNOWN;
+ switch (state->hash_algorithm_) {
+ case HASH_ALGORITHM_SHA1:
+ sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+ break;
+ case HASH_ALGORITHM_SHA256:
+ sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
+ break;
+ case HASH_ALGORITHM_SHA384:
+ sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
+ break;
+ case HASH_ALGORITHM_SHA512:
+ sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
+ break;
+ }
+
SECItem sign_result = {siBuffer, NULL, 0};
if (SEC_SignData(&sign_result,
reinterpret_cast<const unsigned char*>(state->data_.data()),
state->data_.size(),
rsa_key->key(),
- SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION) != SECSuccess) {
+ sign_alg_tag) != SECSuccess) {
LOG(ERROR) << "Couldn't sign.";
state->OnError(FROM_HERE, kErrorInternal);
return;
@@ -495,11 +517,13 @@ void GenerateRSAKey(const std::string& token_id,
void Sign(const std::string& token_id,
const std::string& public_key,
+ HashAlgorithm hash_algorithm,
const std::string& data,
const SignCallback& callback,
BrowserContext* browser_context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- scoped_ptr<SignState> state(new SignState(public_key, data, callback));
+ scoped_ptr<SignState> state(
+ new SignState(public_key, hash_algorithm, data, callback));
// Get the pointer to |state| before base::Passed releases |state|.
NSSOperationState* state_ptr = state.get();
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
index 124cb7a..9b1d0b5 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
@@ -49,6 +49,7 @@ void WrapGenerateKeyCallback(
// |callback| with an error.
void CheckValidityAndSign(const std::string& token_id,
const std::string& public_key_spki_der,
+ platform_keys::HashAlgorithm hash_algorithm,
const std::string& data,
const PlatformKeysService::SignCallback& callback,
content::BrowserContext* browser_context,
@@ -58,8 +59,12 @@ void CheckValidityAndSign(const std::string& token_id,
kErrorKeyNotAllowedForSigning);
return;
}
- platform_keys::subtle::Sign(
- token_id, public_key_spki_der, data, callback, browser_context);
+ platform_keys::subtle::Sign(token_id,
+ public_key_spki_der,
+ hash_algorithm,
+ data,
+ callback,
+ browser_context);
}
} // namespace
@@ -94,6 +99,7 @@ void PlatformKeysService::GenerateRSAKey(const std::string& token_id,
void PlatformKeysService::Sign(const std::string& token_id,
const std::string& public_key_spki_der,
+ platform_keys::HashAlgorithm hash_algorithm,
const std::string& data,
const std::string& extension_id,
const SignCallback& callback) {
@@ -103,6 +109,7 @@ void PlatformKeysService::Sign(const std::string& token_id,
base::Bind(&CheckValidityAndSign,
token_id,
public_key_spki_der,
+ hash_algorithm,
data,
callback,
browser_context_));
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.h b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
index e5b1259..d6401a4 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.h
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/platform_keys/platform_keys.h"
#include "components/keyed_service/core/keyed_service.h"
namespace content {
@@ -66,8 +67,9 @@ class PlatformKeysService : public KeyedService {
typedef base::Callback<void(const std::string& signature,
const std::string& error_message)> SignCallback;
- // Signs |data| with the private key matching |public_key_spki_der|, if that
- // key is stored in the given token and wasn't used for signing before.
+ // Digests |data| with |hash_algorithm| and afterwards signs the digest with
+ // the private key matching |public_key_spki_der|, if that key is stored in
+ // the given token and wasn't used for signing before.
// Unregisters the key so that every future attempt to sign data with this key
// is rejected. |token_id| is currently ignored, instead the user token
// associated with |browser_context| is always used. |public_key_spki_der|
@@ -77,6 +79,7 @@ class PlatformKeysService : public KeyedService {
// Will only call back during the lifetime of this object.
void Sign(const std::string& token_id,
const std::string& public_key_spki_der,
+ platform_keys::HashAlgorithm hash_algorithm,
const std::string& data,
const std::string& extension_id,
const SignCallback& callback);
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
index 7ee7fb0..16a907f 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
@@ -25,6 +25,7 @@ namespace api_epki = api::enterprise_platform_keys_internal;
// extension. Keep this in sync with the custom binding in Javascript.
const char kErrorInvalidToken[] = "The token is not valid.";
+const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
const char kErrorInvalidX509Cert[] =
"Certificate is not a valid X.509 certificate.";
const char kTokenIdUser[] = "user";
@@ -89,6 +90,18 @@ EnterprisePlatformKeysInternalSignFunction::Run() {
if (!ValidateToken(params->token_id))
return RespondNow(Error(kErrorInvalidToken));
+ chromeos::platform_keys::HashAlgorithm hash_algorithm;
+ if (params->hash_algorithm_name == "SHA-1")
+ hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA1;
+ else if (params->hash_algorithm_name == "SHA-256")
+ hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA256;
+ else if (params->hash_algorithm_name == "SHA-384")
+ hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA384;
+ else if (params->hash_algorithm_name == "SHA-512")
+ hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA512;
+ else
+ return RespondNow(Error(kErrorAlgorithmNotSupported));
+
chromeos::PlatformKeysService* service =
chromeos::PlatformKeysServiceFactory::GetForBrowserContext(
browser_context());
@@ -97,6 +110,7 @@ EnterprisePlatformKeysInternalSignFunction::Run() {
service->Sign(
params->token_id,
params->public_key,
+ hash_algorithm,
params->data,
extension_id(),
base::Bind(&EnterprisePlatformKeysInternalSignFunction::OnSigned, this));
diff --git a/chrome/common/extensions/api/enterprise_platform_keys_internal.idl b/chrome/common/extensions/api/enterprise_platform_keys_internal.idl
index b6d8f06..347f1a9 100644
--- a/chrome/common/extensions/api/enterprise_platform_keys_internal.idl
+++ b/chrome/common/extensions/api/enterprise_platform_keys_internal.idl
@@ -38,12 +38,18 @@ namespace enterprise.platformKeysInternal {
// |tokenId| The id of a Token returned by |getTokens|.
// |publicKey| The Subject Public Key Info of a key previously generated by
// |generateKey| in DER encoding.
+ // |hashAlgorithmName| The recognized algorithm name as specified by
+ // WebCrypto of the hash algorithm that will be used to digest |data|
+ // before signing. Currently supported are: SHA-{1,256,384,512}.
+ // TODO(pneubeck): use an enum once supported:
+ // http://www.crbug.com/385539 .
// |data| The data to sign.
// |callback| Called back with the signature of |data|.
// TODO: Instead of ArrayBuffer should be (ArrayBuffer or ArrayBufferView),
// or at least (ArrayBuffer or Uint8Array).
static void sign(DOMString tokenId,
ArrayBuffer publicKey,
+ DOMString hashAlgorithmName,
ArrayBuffer data,
SignCallback callback);
};
diff --git a/chrome/renderer/extensions/enterprise_platform_keys_natives.cc b/chrome/renderer/extensions/enterprise_platform_keys_natives.cc
index 2e11b25..9bccc81 100644
--- a/chrome/renderer/extensions/enterprise_platform_keys_natives.cc
+++ b/chrome/renderer/extensions/enterprise_platform_keys_natives.cc
@@ -56,6 +56,15 @@ scoped_ptr<base::DictionaryValue> WebCryptoAlgorithmToBaseValue(
base::BinaryValue::CreateWithCopiedBuffer(
reinterpret_cast<const char*>(public_exponent.data()),
public_exponent.size()));
+
+ const blink::WebCryptoAlgorithm& hash = rsaHashedKeyGen->hash();
+ DCHECK(!hash.isNull());
+ const blink::WebCryptoAlgorithmInfo* hash_info =
+ blink::WebCryptoAlgorithm::lookupAlgorithmInfo(hash.id());
+
+ scoped_ptr<base::DictionaryValue> hash_dict(new base::DictionaryValue);
+ hash_dict->SetStringWithoutPathExpansion("name", hash_info->name);
+ dict->SetWithoutPathExpansion("hash", hash_dict.release());
}
// Otherwise, |algorithm| is missing support here or no parameters were
// required.
diff --git a/chrome/renderer/extensions/enterprise_platform_keys_natives.h b/chrome/renderer/extensions/enterprise_platform_keys_natives.h
index 6afd99fc..9649aee 100644
--- a/chrome/renderer/extensions/enterprise_platform_keys_natives.h
+++ b/chrome/renderer/extensions/enterprise_platform_keys_natives.h
@@ -23,7 +23,8 @@ class EnterprisePlatformKeysNatives : public ObjectBackedNativeHandler {
// |operation|: A string describing the operation. Supported operations are
// "GenerateKey", "Sign" and "Verify".
// Returns the normalized dictionary on success, or null if some required
- // parameters are missing or not supported.
+ // parameters are missing or not supported. Note that it returns untyped
+ // arrays instead of typed arrays (e.g. for RSA publicExponent).
void NormalizeAlgorithm(const v8::FunctionCallbackInfo<v8::Value>& call_info);
DISALLOW_COPY_AND_ASSIGN(EnterprisePlatformKeysNatives);
diff --git a/chrome/renderer/resources/extensions/enterprise_platform_keys/subtle_crypto.js b/chrome/renderer/resources/extensions/enterprise_platform_keys/subtle_crypto.js
index b3aece1..017a3e2 100644
--- a/chrome/renderer/resources/extensions/enterprise_platform_keys/subtle_crypto.js
+++ b/chrome/renderer/resources/extensions/enterprise_platform_keys/subtle_crypto.js
@@ -102,6 +102,11 @@ SubtleCryptoImpl.prototype.generateKey =
throw CreateSyntaxError();
}
+ // normalizeAlgorithm returns an array, but publicExponent should be a
+ // Uint8Array.
+ normalizedAlgorithmParameters.publicExponent =
+ new Uint8Array(normalizedAlgorithmParameters.publicExponent);
+
if (normalizedAlgorithmParameters.name !== 'RSASSA-PKCS1-v1_5' ||
!equalsStandardPublicExponent(
normalizedAlgorithmParameters.publicExponent)) {
@@ -118,7 +123,7 @@ SubtleCryptoImpl.prototype.generateKey =
reject(CreateOperationError());
return;
}
- resolve(new KeyPair(spki, algorithm, keyUsages));
+ resolve(new KeyPair(spki, normalizedAlgorithmParameters, keyUsages));
});
});
};
@@ -141,16 +146,19 @@ SubtleCryptoImpl.prototype.sign = function(algorithm, key, dataView) {
// might contain more data than dataView.
var data = dataView.buffer.slice(dataView.byteOffset,
dataView.byteOffset + dataView.byteLength);
- internalAPI.sign(
- subtleCrypto.tokenId, getSpki(key), data, function(signature) {
- if (catchInvalidTokenError(reject))
- return;
- if (chrome.runtime.lastError) {
- reject(CreateOperationError());
- return;
- }
- resolve(signature);
- });
+ internalAPI.sign(subtleCrypto.tokenId,
+ getSpki(key),
+ key.algorithm.hash.name,
+ data,
+ function(signature) {
+ if (catchInvalidTokenError(reject))
+ return;
+ if (chrome.runtime.lastError) {
+ reject(CreateOperationError());
+ return;
+ }
+ resolve(signature);
+ });
});
};