Commit a36c84a6 authored by eroman@chromium.org's avatar eroman@chromium.org

Revert 284192 due to a failing test.

Review URL: https://codereview.chromium.org/401983002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284215 0039d316-1c4b-4281-b951-d872f2087c98
parent 8b5c11a0
...@@ -933,6 +933,7 @@ void BlinkPlatformImpl::didStopWorkerThread(blink::WebThread* thread) { ...@@ -933,6 +933,7 @@ void BlinkPlatformImpl::didStopWorkerThread(blink::WebThread* thread) {
} }
blink::WebCrypto* BlinkPlatformImpl::crypto() { blink::WebCrypto* BlinkPlatformImpl::crypto() {
WebCryptoImpl::EnsureInit();
return &web_crypto_; return &web_crypto_;
} }
......
This diff is collapsed.
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/algorithm_implementation.h"
#include "content/child/webcrypto/status.h"
namespace content {
namespace webcrypto {
AlgorithmImplementation::~AlgorithmImplementation() {
}
Status AlgorithmImplementation::Encrypt(
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const {
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::Decrypt(
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const {
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const {
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::Verify(
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) const {
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::Digest(
const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8>* buffer) const {
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const {
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::VerifyKeyUsagesBeforeGenerateKeyPair(
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKeyUsageMask* public_usage_mask,
blink::WebCryptoKeyUsageMask* private_usage_mask) const {
*public_usage_mask = *private_usage_mask = 0;
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::GenerateSecretKey(
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::GenerateKeyPair(
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask public_usage_mask,
blink::WebCryptoKeyUsageMask private_usage_mask,
blink::WebCryptoKey* public_key,
blink::WebCryptoKey* private_key) const {
return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const {
return Status::ErrorUnsupportedImportKeyFormat();
}
Status AlgorithmImplementation::ImportKeyRaw(
const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
return Status::ErrorUnsupportedImportKeyFormat();
}
Status AlgorithmImplementation::ImportKeyPkcs8(
const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
return Status::ErrorUnsupportedImportKeyFormat();
}
Status AlgorithmImplementation::ImportKeySpki(
const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
return Status::ErrorUnsupportedImportKeyFormat();
}
Status AlgorithmImplementation::ImportKeyJwk(
const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
return Status::ErrorUnsupportedImportKeyFormat();
}
Status AlgorithmImplementation::ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const {
return Status::ErrorUnsupportedExportKeyFormat();
}
Status AlgorithmImplementation::ExportKeyPkcs8(
const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const {
return Status::ErrorUnsupportedExportKeyFormat();
}
Status AlgorithmImplementation::ExportKeySpki(
const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const {
return Status::ErrorUnsupportedExportKeyFormat();
}
Status AlgorithmImplementation::ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const {
return Status::ErrorUnsupportedExportKeyFormat();
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_CRYPTO_ALGORITHM_IMPLEMENTATION_H_
#define CONTENT_CHILD_WEBCRYPTO_CRYPTO_ALGORITHM_IMPLEMENTATION_H_
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "third_party/WebKit/public/platform/WebCrypto.h"
namespace content {
namespace webcrypto {
class CryptoData;
class Status;
// AlgorithmImplementation is a base class for *executing* the operations of an
// algorithm (generating keys, encrypting, signing, etc.).
//
// This is in contrast to blink::WebCryptoAlgorithm which instead *describes*
// the operation and its parameters.
//
// AlgorithmImplementation has reasonable default implementations for all
// methods which behave as if the operation is it is unsupported, so
// implementations need only override the applicable methods.
//
// Unless stated otherwise methods of AlgorithmImplementation are responsible
// for sanitizing their inputs. The following can be assumed:
//
// * |algorithm.id()| and |key.algorithm.id()| matches the algorithm under
// which the implementation was registerd.
// * |algorithm| has the correct parameters type for the operation.
// * The key usages have already been verified. In fact in the case of calls
// to Encrypt()/Decrypt() the corresponding key usages may not be present
// (when wrapping/unwrapping).
class AlgorithmImplementation {
public:
virtual ~AlgorithmImplementation();
// This method corresponds to Web Crypto's crypto.subtle.encrypt().
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const;
// This method corresponds to Web Crypto's crypto.subtle.decrypt().
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const;
// This method corresponds to Web Crypto's crypto.subtle.sign().
virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const;
// This method corresponds to Web Crypto's crypto.subtle.verify().
virtual Status Verify(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) const;
// This method corresponds to Web Crypto's crypto.subtle.digest().
virtual Status Digest(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8>* buffer) const;
// VerifyKeyUsagesBeforeGenerateKey() must be called prior to
// GenerateSecretKey() to validate the requested key usages.
virtual Status VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const;
// This method corresponds to Web Crypto's crypto.subtle.generateKey().
virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const;
// VerifyKeyUsagesBeforeGenerateKeyPair() must be called prior to
// GenerateKeyPair() to validate the requested key usages.
virtual Status VerifyKeyUsagesBeforeGenerateKeyPair(
blink::WebCryptoKeyUsageMask combined_usage_mask,
blink::WebCryptoKeyUsageMask* public_usage_mask,
blink::WebCryptoKeyUsageMask* private_usage_mask) const;
// This method corresponds to Web Crypto's crypto.subtle.generateKey().
virtual Status GenerateKeyPair(
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask public_usage_mask,
blink::WebCryptoKeyUsageMask private_usage_mask,
blink::WebCryptoKey* public_key,
blink::WebCryptoKey* private_key) const;
// -----------------------------------------------
// Key import
// -----------------------------------------------
// VerifyKeyUsagesBeforeImportKey() must be called before either
// importing a key, or unwrapping a key.
//
// Implementations should return an error if the requested usages are invalid
// when importing for the specified format.
//
// For instance, importing an RSA-SSA key with 'spki' format and Sign usage
// is invalid. The 'spki' format implies it will be a public key, and public
// keys do not support signing.
//
// When called with format=JWK the key type may be unknown. The
// ImportKeyJwk() must do the final usage check.
virtual Status VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const;
// This method corresponds to Web Crypto's
// crypto.subtle.importKey(format='raw').
virtual Status ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const;
// This method corresponds to Web Crypto's
// crypto.subtle.importKey(format='pkcs8').
virtual Status ImportKeyPkcs8(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const;
// This method corresponds to Web Crypto's
// crypto.subtle.importKey(format='spki').
virtual Status ImportKeySpki(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const;
// This method corresponds to Web Crypto's
// crypto.subtle.importKey(format='jwk').
virtual Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const;
// -----------------------------------------------
// Key export
// -----------------------------------------------
virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const;
virtual Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const;
virtual Status ExportKeySpki(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const;
virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const;
};
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_CRYPTO_ALGORITHM_IMPLEMENTATION_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/algorithm_registry.h"
#include "base/lazy_instance.h"
#include "content/child/webcrypto/algorithm_implementation.h"
#include "content/child/webcrypto/platform_crypto.h"
#include "content/child/webcrypto/status.h"
namespace content {
namespace webcrypto {
namespace {
class AlgorithmRegistry {
public:
AlgorithmRegistry()
: sha_(CreatePlatformShaImplementation()),
aes_gcm_(CreatePlatformAesGcmImplementation()),
aes_cbc_(CreatePlatformAesCbcImplementation()),
aes_kw_(CreatePlatformAesKwImplementation()),
hmac_(CreatePlatformHmacImplementation()),
rsa_ssa_(CreatePlatformRsaSsaImplementation()),
rsa_oaep_(CreatePlatformRsaOaepImplementation()) {
PlatformInit();
}
const AlgorithmImplementation* GetAlgorithm(
blink::WebCryptoAlgorithmId id) const {
switch (id) {
case blink::WebCryptoAlgorithmIdSha1:
case blink::WebCryptoAlgorithmIdSha256:
case blink::WebCryptoAlgorithmIdSha384:
case blink::WebCryptoAlgorithmIdSha512:
return sha_.get();
case blink::WebCryptoAlgorithmIdAesGcm:
return aes_gcm_.get();
case blink::WebCryptoAlgorithmIdAesCbc:
return aes_cbc_.get();
case blink::WebCryptoAlgorithmIdAesKw:
return aes_kw_.get();
case blink::WebCryptoAlgorithmIdHmac:
return hmac_.get();
case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
return rsa_ssa_.get();
case blink::WebCryptoAlgorithmIdRsaOaep:
return rsa_oaep_.get();
default:
return NULL;
}
}
private:
scoped_ptr<AlgorithmImplementation> sha_;
scoped_ptr<AlgorithmImplementation> aes_gcm_;
scoped_ptr<AlgorithmImplementation> aes_cbc_;
scoped_ptr<AlgorithmImplementation> aes_kw_;
scoped_ptr<AlgorithmImplementation> hmac_;
scoped_ptr<AlgorithmImplementation> rsa_ssa_;
scoped_ptr<AlgorithmImplementation> rsa_oaep_;
};
} // namespace
base::LazyInstance<AlgorithmRegistry>::Leaky g_algorithm_registry =
LAZY_INSTANCE_INITIALIZER;
Status GetAlgorithmImplementation(blink::WebCryptoAlgorithmId id,
const AlgorithmImplementation** impl) {
*impl = g_algorithm_registry.Get().GetAlgorithm(id);
if (*impl)
return Status::Success();
return Status::ErrorUnsupported();
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_ALGORITHM_REGISTRY_H_
#define CONTENT_CHILD_WEBCRYPTO_ALGORITHM_REGISTRY_H_
#include "third_party/WebKit/public/platform/WebCrypto.h"
namespace content {
namespace webcrypto {
class AlgorithmImplementation;
class Status;
// Retrieves the AlgorithmImplementation applicable for |id|.
//
// If there is no available implementation, then an error is returned, and
// *impl is set to NULL.
//
// Otherwise Success is returned and *impl is set to a non-NULL value. The
// AlgorithmImplementation pointer will remain valid until the program's
// termination.
Status GetAlgorithmImplementation(blink::WebCryptoAlgorithmId id,
const AlgorithmImplementation** impl);
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_ALGORITHM_REGISTRY_H_
This diff is collapsed.
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <vector> #include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/values.h"
#include "third_party/WebKit/public/platform/WebArrayBuffer.h" #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
#include "third_party/WebKit/public/platform/WebCrypto.h" #include "third_party/WebKit/public/platform/WebCrypto.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
...@@ -20,105 +19,13 @@ namespace webcrypto { ...@@ -20,105 +19,13 @@ namespace webcrypto {
class CryptoData; class CryptoData;
class Status; class Status;
// Writes a JWK-formatted symmetric key to |jwk_key_data|. Status ImportKeyJwk(const CryptoData& key_data,
// * raw_key_data: The actual key data const blink::WebCryptoAlgorithm& algorithm,
// * algorithm: The JWK algorithm name (i.e. "alg") bool extractable,
// * extractable: The JWK extractability (i.e. "ext") blink::WebCryptoKeyUsageMask usage_mask,
// * usage_mask: The JWK usages (i.e. "key_ops") blink::WebCryptoKey* key);
void WriteSecretKeyJwk(const CryptoData& raw_key_data,
const std::string& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
std::vector<uint8>* jwk_key_data);
// Parses a UTF-8 encoded JWK (key_data), and extracts the key material to Status ExportKeyJwk(const blink::WebCryptoKey& key, std::vector<uint8>* buffer);
// |*raw_key_data|. Returns Status::Success() on success, otherwise an error.
// In order for this to succeed:
// * expected_algorithm must match the JWK's "alg", if present.
// * expected_extractable must be consistent with the JWK's "ext", if
// present.
// * expected_usage_mask must be a subset of the JWK's "key_ops" if present.
Status ReadSecretKeyJwk(const CryptoData& key_data,
const std::string& expected_algorithm,
bool expected_extractable,
blink::WebCryptoKeyUsageMask expected_usage_mask,
std::vector<uint8>* 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,
unsigned int keylen_bytes);
// This is very similar to ReadSecretKeyJwk(), except instead of specifying an
// absolut "expected_algorithm", 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_usage_mask,
std::vector<uint8>* 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 usage_mask,
std::vector<uint8>* 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 usage_mask,
std::vector<uint8>* 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_algorithm must match the JWK's "alg", if present.
// * expected_extractable must be consistent with the JWK's "ext", if
// present.
// * expected_usage_mask must be a subset of the JWK's "key_ops" if present.
Status ReadRsaKeyJwk(const CryptoData& key_data,
const std::string& expected_algorithm,
bool expected_extractable,
blink::WebCryptoKeyUsageMask expected_usage_mask,
JwkRsaInfo* result);
const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash);
} // namespace webcrypto } // namespace webcrypto
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cryptohi.h>
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/nss/aes_key_nss.h"
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/nss/util_nss.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/scoped_nss_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
namespace content {
namespace webcrypto {
namespace {
Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode,
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) {
const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
if (!params)
return Status::ErrorUnexpected();
CryptoData iv(params->iv().data(), params->iv().size());
if (iv.byte_length() != 16)
return Status::ErrorIncorrectSizeAesCbcIv();
PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT;
SECItem iv_item = MakeSECItemForBuffer(iv);
crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
if (!param)
return Status::OperationError();
crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
CKM_AES_CBC_PAD, operation, sym_key, param.get()));
if (!context.get())
return Status::OperationError();
// Oddly PK11_CipherOp takes input and output lengths as "int" rather than
// "unsigned int". Do some checks now to avoid integer overflowing.
if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) {
// TODO(eroman): Handle this by chunking the input fed into NSS. Right now
// it doesn't make much difference since the one-shot API would end up
// blowing out the memory and crashing anyway.
return Status::ErrorDataTooLarge();
}
// PK11_CipherOp does an invalid memory access when given empty decryption
// input, or input which is not a multiple of the block size. See also
// https://bugzilla.mozilla.com/show_bug.cgi?id=921687.
if (operation == CKA_DECRYPT &&
(data.byte_length() == 0 || (data.byte_length() % AES_BLOCK_SIZE != 0))) {
return Status::OperationError();
}
// TODO(eroman): Refine the output buffer size. It can be computed exactly for
// encryption, and can be smaller for decryption.
unsigned int output_max_len = data.byte_length() + AES_BLOCK_SIZE;
CHECK_GT(output_max_len, data.byte_length());
buffer->resize(output_max_len);
unsigned char* buffer_data = Uint8VectorStart(buffer);
int output_len;
if (SECSuccess != PK11_CipherOp(context.get(),
buffer_data,
&output_len,
buffer->size(),
data.bytes(),
data.byte_length())) {
return Status::OperationError();
}
unsigned int final_output_chunk_len;
if (SECSuccess != PK11_DigestFinal(context.get(),
buffer_data + output_len,
&final_output_chunk_len,
output_max_len - output_len)) {
return Status::OperationError();
}
buffer->resize(final_output_chunk_len + output_len);
return Status::Success();
}
class AesCbcImplementation : public AesAlgorithm {
public:
AesCbcImplementation() : AesAlgorithm(CKM_AES_CBC, "CBC") {}
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
return AesCbcEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
}
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
return AesCbcEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
}
};
} // namespace
AlgorithmImplementation* CreatePlatformAesCbcImplementation() {
return new AesCbcImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/nss/aes_key_nss.h"
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/nss/util_nss.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
// At the time of this writing:
// * Windows and Mac builds ship with their own copy of NSS (3.15+)
// * Linux builds use the system's libnss, which is 3.14 on Debian (but 3.15+
// on other distros).
//
// Since NSS provides AES-GCM support starting in version 3.15, it may be
// unavailable for Linux Chrome users.
//
// * !defined(CKM_AES_GCM)
//
// This means that at build time, the NSS header pkcs11t.h is older than
// 3.15. However at runtime support may be present.
//
// TODO(eroman): Simplify this once 3.15+ is required by Linux builds.
#if !defined(CKM_AES_GCM)
#define CKM_AES_GCM 0x00001087
struct CK_GCM_PARAMS {
CK_BYTE_PTR pIv;
CK_ULONG ulIvLen;
CK_BYTE_PTR pAAD;
CK_ULONG ulAADLen;
CK_ULONG ulTagBits;
};
#endif // !defined(CKM_AES_GCM)
namespace content {
namespace webcrypto {
namespace {
Status NssSupportsAesGcm() {
if (NssRuntimeSupport::Get()->IsAesGcmSupported())
return Status::Success();
return Status::ErrorUnsupported(
"NSS version doesn't support AES-GCM. Try using version 3.15 or later");
}
// Helper to either encrypt or decrypt for AES-GCM. The result of encryption is
// the concatenation of the ciphertext and the authentication tag. Similarly,
// this is the expectation for the input to decryption.
Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) {
Status status = NssSupportsAesGcm();
if (status.IsError())
return status;
PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
if (!params)
return Status::ErrorUnexpected();
unsigned int tag_length_bits;
status = GetAesGcmTagLengthInBits(params, &tag_length_bits);
if (status.IsError())
return status;
unsigned int tag_length_bytes = tag_length_bits / 8;
CryptoData iv(params->iv());
CryptoData additional_data(params->optionalAdditionalData());
CK_GCM_PARAMS gcm_params = {0};
gcm_params.pIv = const_cast<unsigned char*>(iv.bytes());
gcm_params.ulIvLen = iv.byte_length();
gcm_params.pAAD = const_cast<unsigned char*>(additional_data.bytes());
gcm_params.ulAADLen = additional_data.byte_length();
gcm_params.ulTagBits = tag_length_bits;
SECItem param;
param.type = siBuffer;
param.data = reinterpret_cast<unsigned char*>(&gcm_params);
param.len = sizeof(gcm_params);
unsigned int buffer_size = 0;
// Calculate the output buffer size.
if (mode == ENCRYPT) {
// TODO(eroman): This is ugly, abstract away the safe integer arithmetic.
if (data.byte_length() > (UINT_MAX - tag_length_bytes))
return Status::ErrorDataTooLarge();
buffer_size = data.byte_length() + tag_length_bytes;
} else {
// TODO(eroman): In theory the buffer allocated for the plain text should be
// sized as |data.byte_length() - tag_length_bytes|.
//
// However NSS has a bug whereby it will fail if the output buffer size is
// not at least as large as the ciphertext:
//
// https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674
//
// From the analysis of that bug it looks like it might be safe to pass a
// correctly sized buffer but lie about its size. Since resizing the
// WebCryptoArrayBuffer is expensive that hack may be worth looking into.
buffer_size = data.byte_length();
}
buffer->resize(buffer_size);
unsigned char* buffer_data = Uint8VectorStart(buffer);
PK11_EncryptDecryptFunction encrypt_or_decrypt_func =
(mode == ENCRYPT) ? NssRuntimeSupport::Get()->pk11_encrypt_func()
: NssRuntimeSupport::Get()->pk11_decrypt_func();
unsigned int output_len = 0;
SECStatus result = encrypt_or_decrypt_func(sym_key,
CKM_AES_GCM,
&param,
buffer_data,
&output_len,
buffer->size(),
data.bytes(),
data.byte_length());
if (result != SECSuccess)
return Status::OperationError();
// Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug
// above).
buffer->resize(output_len);
return Status::Success();
}
class AesGcmImplementation : public AesAlgorithm {
public:
AesGcmImplementation() : AesAlgorithm(CKM_AES_GCM, "GCM") {}
virtual Status VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
// Prevent importing AES-GCM keys if it is unavailable.
Status status = NssSupportsAesGcm();
if (status.IsError())
return status;
return AesAlgorithm::VerifyKeyUsagesBeforeImportKey(format, usage_mask);
}
virtual Status VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
// Prevent generating AES-GCM keys if it is unavailable.
Status status = NssSupportsAesGcm();
if (status.IsError())
return status;
return AesAlgorithm::VerifyKeyUsagesBeforeGenerateKey(usage_mask);
}
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
return AesGcmEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
}
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
return AesGcmEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
}
};
} // namespace
AlgorithmImplementation* CreatePlatformAesGcmImplementation() {
return new AesGcmImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/nss/aes_key_nss.h"
#include "base/logging.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/jwk.h"
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/nss/sym_key_nss.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace content {
namespace webcrypto {
AesAlgorithm::AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
CK_FLAGS import_flags,
blink::WebCryptoKeyUsageMask all_key_usages,
const std::string& jwk_suffix)
: import_mechanism_(import_mechanism),
import_flags_(import_flags),
all_key_usages_(all_key_usages),
jwk_suffix_(jwk_suffix) {
}
AesAlgorithm::AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
const std::string& jwk_suffix)
: import_mechanism_(import_mechanism),
import_flags_(CKF_ENCRYPT | CKF_DECRYPT),
all_key_usages_(blink::WebCryptoKeyUsageEncrypt |
blink::WebCryptoKeyUsageDecrypt |
blink::WebCryptoKeyUsageWrapKey |
blink::WebCryptoKeyUsageUnwrapKey),
jwk_suffix_(jwk_suffix) {
}
Status AesAlgorithm::VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const {
return CheckKeyCreationUsages(all_key_usages_, usage_mask);
}
Status AesAlgorithm::GenerateSecretKey(
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
unsigned int keylen_bits;
Status status =
GetAesKeyGenLengthInBits(algorithm.aesKeyGenParams(), &keylen_bits);
if (status.IsError())
return status;
return GenerateSecretKeyNss(
blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
extractable,
usage_mask,
keylen_bits / 8,
CKM_AES_KEY_GEN,
key);
}
Status AesAlgorithm::VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
case blink::WebCryptoKeyFormatJwk:
return CheckKeyCreationUsages(all_key_usages_, usage_mask);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
}
Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
const unsigned int keylen_bytes = key_data.byte_length();
Status status = VerifyAesKeyLengthForImport(keylen_bytes);
if (status.IsError())
return status;
// No possibility of overflow.
unsigned int keylen_bits = keylen_bytes * 8;
return ImportKeyRawNss(
key_data,
blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
extractable,
usage_mask,
import_mechanism_,
import_flags_,
key);
}
Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
std::vector<uint8> raw_data;
Status status = ReadAesSecretKeyJwk(
key_data, jwk_suffix_, extractable, usage_mask, &raw_data);
if (status.IsError())
return status;
return ImportKeyRaw(
CryptoData(raw_data), algorithm, extractable, usage_mask, key);
}
Status AesAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const {
*buffer = SymKeyNss::Cast(key)->raw_key_data();
return Status::Success();
}
Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const {
SymKeyNss* sym_key = SymKeyNss::Cast(key);
const std::vector<uint8>& raw_data = sym_key->raw_key_data();
WriteSecretKeyJwk(CryptoData(raw_data),
MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size()),
key.extractable(),
key.usages(),
buffer);
return Status::Success();
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_NSS_AES_NSS_H_
#define CONTENT_CHILD_WEBCRYPTO_NSS_AES_NSS_H_
#include <pkcs11t.h>
#include "content/child/webcrypto/algorithm_implementation.h"
namespace content {
namespace webcrypto {
// Base class for AES algorithms that provides the implementation for key
// creation and export.
class AesAlgorithm : public AlgorithmImplementation {
public:
// Constructs an AES algorithm whose keys will be imported using the NSS
// mechanism |import_mechanism| and NSS flags |import_flags|.
// |all_key_usages| is the set of all WebCrypto key usages that are
// allowed for imported or generated keys. |jwk_suffix| is the suffix
// used when constructing JWK names for the algorithm. For instance A128CBC
// is the JWK name for 128-bit AES-CBC. The |jwk_suffix| in this case would
// be "CBC".
AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
CK_FLAGS import_flags,
blink::WebCryptoKeyUsageMask all_key_usages,
const std::string& jwk_suffix);
// This is the same as the other AesAlgorithm constructor, however
// |import_flags| and |all_key_usages| are pre-filled to values for
// encryption/decryption algorithms (supports usages for: encrypt, decrypt,
// wrap, unwrap).
AesAlgorithm(CK_MECHANISM_TYPE import_mechanism,
const std::string& jwk_suffix);
virtual Status VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE;
virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE;
virtual Status ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE;
virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE;
private:
const CK_MECHANISM_TYPE import_mechanism_;
const CK_FLAGS import_flags_;
const blink::WebCryptoKeyUsageMask all_key_usages_;
const std::string jwk_suffix_;
};
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_NSS_AES_NSS_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <secerr.h>
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/nss/aes_key_nss.h"
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/nss/sym_key_nss.h"
#include "content/child/webcrypto/nss/util_nss.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/scoped_nss_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace content {
namespace webcrypto {
namespace {
// The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt
// Section 2.2.3.1.
const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
// The result of unwrapping is a SymKey rather than a buffer. This is a
// consequence of how NSS exposes AES-KW. Subsequent code can extract the value
// of the sym key to interpret it as key bytes in another format.
Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
PK11SymKey* wrapping_key,
CK_MECHANISM_TYPE mechanism,
CK_FLAGS flags,
crypto::ScopedPK11SymKey* unwrapped_key) {
DCHECK_GE(wrapped_key_data.byte_length(), 24u);
DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u);
SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
crypto::ScopedSECItem param_item(
PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
if (!param_item)
return Status::ErrorUnexpected();
SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
// The plaintext length is always 64 bits less than the data size.
const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
#if defined(USE_NSS)
// Part of workaround for
// https://bugzilla.mozilla.org/show_bug.cgi?id=981170. See the explanation
// later in this function.
PORT_SetError(0);
#endif
crypto::ScopedPK11SymKey new_key(
PK11_UnwrapSymKeyWithFlags(wrapping_key,
CKM_NSS_AES_KEY_WRAP,
param_item.get(),
&cipher_text,
mechanism,
CKA_FLAGS_ONLY,
plaintext_length,
flags));
// TODO(padolph): Use NSS PORT_GetError() and friends to report a more
// accurate error, providing if doesn't leak any information to web pages
// about other web crypto users, key details, etc.
if (!new_key)
return Status::OperationError();
#if defined(USE_NSS)
// Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=981170
// which was fixed in NSS 3.16.0.
// If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey,
// with a reasonable length but with key data pointing to uninitialized
// memory.
// To understand this workaround see the fix for 981170:
// https://hg.mozilla.org/projects/nss/rev/753bb69e543c
if (!NSS_VersionCheck("3.16") && PORT_GetError() == SEC_ERROR_BAD_DATA)
return Status::OperationError();
#endif
*unwrapped_key = new_key.Pass();
return Status::Success();
}
Status WrapSymKeyAesKw(PK11SymKey* key,
PK11SymKey* wrapping_key,
std::vector<uint8>* buffer) {
// The data size must be at least 16 bytes and a multiple of 8 bytes.
// RFC 3394 does not specify a maximum allowed data length, but since only
// keys are being wrapped in this application (which are small), a reasonable
// max limit is whatever will fit into an unsigned. For the max size test,
// note that AES Key Wrap always adds 8 bytes to the input data size.
const unsigned int input_length = PK11_GetKeyLength(key);
DCHECK_GE(input_length, 16u);
DCHECK((input_length % 8) == 0);
if (input_length > UINT_MAX - 8)
return Status::ErrorDataTooLarge();
SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
crypto::ScopedSECItem param_item(
PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
if (!param_item)
return Status::ErrorUnexpected();
const unsigned int output_length = input_length + 8;
buffer->resize(output_length);
SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer));
if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
param_item.get(),
wrapping_key,
key,
&wrapped_key_item)) {
return Status::OperationError();
}
if (output_length != wrapped_key_item.len)
return Status::ErrorUnexpected();
return Status::Success();
}
class AesKwCryptoAlgorithmNss : public AesAlgorithm {
public:
AesKwCryptoAlgorithmNss()
: AesAlgorithm(
CKM_NSS_AES_KEY_WRAP,
CKF_WRAP | CKF_WRAP,
blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
"KW") {}
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& wrapping_key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
if (data.byte_length() < 16)
return Status::ErrorDataTooSmall();
if (data.byte_length() % 8)
return Status::ErrorInvalidAesKwDataLength();
// Due to limitations in the NSS API for the AES-KW algorithm, |data| must
// be temporarily viewed as a symmetric key to be wrapped (encrypted).
SECItem data_item = MakeSECItemForBuffer(data);
crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
crypto::ScopedPK11SymKey data_as_sym_key(
PK11_ImportSymKey(slot.get(),
CKK_GENERIC_SECRET,
PK11_OriginUnwrap,
CKA_SIGN,
&data_item,
NULL));
if (!data_as_sym_key)
return Status::OperationError();
return WrapSymKeyAesKw(
data_as_sym_key.get(), SymKeyNss::Cast(wrapping_key)->key(), buffer);
}
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& wrapping_key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
if (data.byte_length() < 24)
return Status::ErrorDataTooSmall();
if (data.byte_length() % 8)
return Status::ErrorInvalidAesKwDataLength();
// Due to limitations in the NSS API for the AES-KW algorithm, |data| must
// be temporarily viewed as a symmetric key to be unwrapped (decrypted).
crypto::ScopedPK11SymKey decrypted;
Status status = DoUnwrapSymKeyAesKw(data,
SymKeyNss::Cast(wrapping_key)->key(),
CKK_GENERIC_SECRET,
0,
&decrypted);
if (status.IsError())
return status;
// Once the decrypt is complete, extract the resultant raw bytes from NSS
// and return them to the caller.
if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess)
return Status::OperationError();
const SECItem* const key_data = PK11_GetKeyData(decrypted.get());
if (!key_data)
return Status::OperationError();
buffer->assign(key_data->data, key_data->data + key_data->len);
return Status::Success();
}
};
} // namespace
AlgorithmImplementation* CreatePlatformAesKwImplementation() {
return new AesKwCryptoAlgorithmNss;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cryptohi.h>
#include <pk11pub.h>
#include <secerr.h>
#include <sechash.h>
#include "base/logging.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/jwk.h"
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/nss/sym_key_nss.h"
#include "content/child/webcrypto/nss/util_nss.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/secure_util.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace content {
namespace webcrypto {
namespace {
const blink::WebCryptoKeyUsageMask kAllKeyUsages =
blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
bool WebCryptoHashToHMACMechanism(const blink::WebCryptoAlgorithm& algorithm,
CK_MECHANISM_TYPE* mechanism) {
switch (algorithm.id()) {
case blink::WebCryptoAlgorithmIdSha1:
*mechanism = CKM_SHA_1_HMAC;
return true;
case blink::WebCryptoAlgorithmIdSha256:
*mechanism = CKM_SHA256_HMAC;
return true;
case blink::WebCryptoAlgorithmIdSha384:
*mechanism = CKM_SHA384_HMAC;
return true;
case blink::WebCryptoAlgorithmIdSha512:
*mechanism = CKM_SHA512_HMAC;
return true;
default:
return false;
}
}
class HmacImplementation : public AlgorithmImplementation {
public:
HmacImplementation() {}
virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE {
const blink::WebCryptoHmacKeyGenParams* params =
algorithm.hmacKeyGenParams();
const blink::WebCryptoAlgorithm& hash = params->hash();
CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
return Status::ErrorUnsupported();
unsigned int keylen_bits = 0;
Status status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
if (status.IsError())
return status;
return GenerateSecretKeyNss(
blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
extractable,
usage_mask,
keylen_bits / 8,
mechanism,
key);
}
virtual Status VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
case blink::WebCryptoKeyFormatJwk:
return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
}
virtual Status VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
}
virtual Status ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE {
const blink::WebCryptoAlgorithm& hash =
algorithm.hmacImportParams()->hash();
CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
return Status::ErrorUnsupported();
// TODO(eroman): check for overflow.
unsigned int keylen_bits = key_data.byte_length() * 8;
return ImportKeyRawNss(
key_data,
blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
extractable,
usage_mask,
mechanism,
CKF_SIGN | CKF_VERIFY,
key);
}
virtual Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE {
const char* algorithm_name =
GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
if (!algorithm_name)
return Status::ErrorUnexpected();
std::vector<uint8> raw_data;
Status status = ReadSecretKeyJwk(
key_data, algorithm_name, extractable, usage_mask, &raw_data);
if (status.IsError())
return status;
return ImportKeyRaw(
CryptoData(raw_data), algorithm, extractable, usage_mask, key);
}
virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE {
*buffer = SymKeyNss::Cast(key)->raw_key_data();
return Status::Success();
}
virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE {
SymKeyNss* sym_key = SymKeyNss::Cast(key);
const std::vector<uint8>& raw_data = sym_key->raw_key_data();
const char* algorithm_name =
GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
if (!algorithm_name)
return Status::ErrorUnexpected();
WriteSecretKeyJwk(CryptoData(raw_data),
algorithm_name,
key.extractable(),
key.usages(),
buffer);
return Status::Success();
}
virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
const blink::WebCryptoAlgorithm& hash =
key.algorithm().hmacParams()->hash();
PK11SymKey* sym_key = SymKeyNss::Cast(key)->key();
CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
if (!WebCryptoHashToHMACMechanism(hash, &mechanism))
return Status::ErrorUnexpected();
SECItem param_item = {siBuffer, NULL, 0};
SECItem data_item = MakeSECItemForBuffer(data);
// First call is to figure out the length.
SECItem signature_item = {siBuffer, NULL, 0};
if (PK11_SignWithSymKey(
sym_key, mechanism, &param_item, &signature_item, &data_item) !=
SECSuccess) {
return Status::OperationError();
}
DCHECK_NE(0u, signature_item.len);
buffer->resize(signature_item.len);
signature_item.data = Uint8VectorStart(buffer);
if (PK11_SignWithSymKey(
sym_key, mechanism, &param_item, &signature_item, &data_item) !=
SECSuccess) {
return Status::OperationError();
}
CHECK_EQ(buffer->size(), signature_item.len);
return Status::Success();
}
virtual Status Verify(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) const OVERRIDE {
std::vector<uint8> result;
Status status = Sign(algorithm, key, data, &result);
if (status.IsError())
return status;
// Do not allow verification of truncated MACs.
*signature_match = result.size() == signature.byte_length() &&
crypto::SecureMemEqual(Uint8VectorStart(result),
signature.bytes(),
signature.byte_length());
return Status::Success();
}
};
} // namespace
AlgorithmImplementation* CreatePlatformHmacImplementation() {
return new HmacImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
namespace content {
namespace webcrypto {
KeyNss::KeyNss(const CryptoData& serialized_key_data)
: serialized_key_data_(
serialized_key_data.bytes(),
serialized_key_data.bytes() + serialized_key_data.byte_length()) {
}
KeyNss::~KeyNss() {
}
SymKeyNss* KeyNss::AsSymKey() {
return NULL;
}
PublicKeyNss* KeyNss::AsPublicKey() {
return NULL;
}
PrivateKeyNss* KeyNss::AsPrivateKey() {
return NULL;
}
SymKeyNss::~SymKeyNss() {
}
SymKeyNss* SymKeyNss::Cast(const blink::WebCryptoKey& key) {
KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
return platform_key->AsSymKey();
}
SymKeyNss* SymKeyNss::AsSymKey() {
return this;
}
SymKeyNss::SymKeyNss(crypto::ScopedPK11SymKey key,
const CryptoData& raw_key_data)
: KeyNss(raw_key_data), key_(key.Pass()) {
}
PublicKeyNss::~PublicKeyNss() {
}
PublicKeyNss* PublicKeyNss::Cast(const blink::WebCryptoKey& key) {
KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
return platform_key->AsPublicKey();
}
PublicKeyNss* PublicKeyNss::AsPublicKey() {
return this;
}
PublicKeyNss::PublicKeyNss(crypto::ScopedSECKEYPublicKey key,
const CryptoData& spki_data)
: KeyNss(spki_data), key_(key.Pass()) {
}
PrivateKeyNss::~PrivateKeyNss() {
}
PrivateKeyNss* PrivateKeyNss::Cast(const blink::WebCryptoKey& key) {
KeyNss* platform_key = reinterpret_cast<KeyNss*>(key.handle());
return platform_key->AsPrivateKey();
}
PrivateKeyNss* PrivateKeyNss::AsPrivateKey() {
return this;
}
PrivateKeyNss::PrivateKeyNss(crypto::ScopedSECKEYPrivateKey key,
const CryptoData& pkcs8_data)
: KeyNss(pkcs8_data), key_(key.Pass()) {
}
bool PlatformSerializeKeyForClone(const blink::WebCryptoKey& key,
blink::WebVector<uint8>* key_data) {
const KeyNss* nss_key = static_cast<KeyNss*>(key.handle());
*key_data = nss_key->serialized_key_data();
return true;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_NSS_KEY_NSS_H_
#define CONTENT_CHILD_WEBCRYPTO_NSS_KEY_NSS_H_
#include "content/child/webcrypto/algorithm_implementation.h"
#include "crypto/scoped_nss_types.h"
namespace content {
namespace webcrypto {
class PrivateKeyNss;
class PublicKeyNss;
class SymKeyNss;
// Base key class for all NSS keys, used to safely cast between types. Each key
// maintains a copy of its serialized form in either 'raw', 'pkcs8', or 'spki'
// format. This is to allow structured cloning of keys synchronously from the
// target Blink thread without having to lock access to the key.
class KeyNss : public blink::WebCryptoKeyHandle {
public:
explicit KeyNss(const CryptoData& serialized_key_data);
virtual ~KeyNss();
virtual SymKeyNss* AsSymKey();
virtual PublicKeyNss* AsPublicKey();
virtual PrivateKeyNss* AsPrivateKey();
const std::vector<uint8>& serialized_key_data() const {
return serialized_key_data_;
}
private:
const std::vector<uint8> serialized_key_data_;
};
class SymKeyNss : public KeyNss {
public:
virtual ~SymKeyNss();
SymKeyNss(crypto::ScopedPK11SymKey key, const CryptoData& raw_key_data);
static SymKeyNss* Cast(const blink::WebCryptoKey& key);
PK11SymKey* key() { return key_.get(); }
virtual SymKeyNss* AsSymKey() OVERRIDE;
const std::vector<uint8>& raw_key_data() const {
return serialized_key_data();
}
private:
crypto::ScopedPK11SymKey key_;
DISALLOW_COPY_AND_ASSIGN(SymKeyNss);
};
class PublicKeyNss : public KeyNss {
public:
virtual ~PublicKeyNss();
PublicKeyNss(crypto::ScopedSECKEYPublicKey key, const CryptoData& spki_data);
static PublicKeyNss* Cast(const blink::WebCryptoKey& key);
SECKEYPublicKey* key() { return key_.get(); }
virtual PublicKeyNss* AsPublicKey() OVERRIDE;
const std::vector<uint8>& spki_data() const { return serialized_key_data(); }
private:
crypto::ScopedSECKEYPublicKey key_;
DISALLOW_COPY_AND_ASSIGN(PublicKeyNss);
};
class PrivateKeyNss : public KeyNss {
public:
virtual ~PrivateKeyNss();
PrivateKeyNss(crypto::ScopedSECKEYPrivateKey key,
const CryptoData& pkcs8_data);
static PrivateKeyNss* Cast(const blink::WebCryptoKey& key);
SECKEYPrivateKey* key() { return key_.get(); }
virtual PrivateKeyNss* AsPrivateKey() OVERRIDE;
const std::vector<uint8>& pkcs8_data() const { return serialized_key_data(); }
private:
crypto::ScopedSECKEYPrivateKey key_;
DISALLOW_COPY_AND_ASSIGN(PrivateKeyNss);
};
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_NSS_KEY_NSS_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_NSS_RSA_KEY_NSS_H_
#define CONTENT_CHILD_WEBCRYPTO_NSS_RSA_KEY_NSS_H_
#include <pkcs11t.h>
#include "content/child/webcrypto/algorithm_implementation.h"
namespace content {
namespace webcrypto {
class PublicKeyNss;
class PrivateKeyNss;
// Base class for an RSA algorithm whose keys additionaly have a hash parameter
// bound to them. Provides functionality for generating, importing, and
// exporting keys.
class RsaHashedAlgorithm : public AlgorithmImplementation {
public:
// Constructs an RSA algorithm which will use the NSS flags |generate_flags|
// when generating keys. |all_public_key_usages| and |all_private_key_usages|
// are the set of WebCrypto key usages that are valid for created keys
// (public and private respectively).
//
// For instance if public keys support encryption and wrapping, and private
// keys support decryption and unwrapping callers should set:
// all_public_key_usages = UsageEncrypt | UsageWrap
// all_private_key_usages = UsageDecrypt | UsageUnwrap
// This information is used when importing or generating keys, to enforce
// that valid key usages are allowed.
RsaHashedAlgorithm(CK_FLAGS generate_flags,
blink::WebCryptoKeyUsageMask all_public_key_usages,
blink::WebCryptoKeyUsageMask all_private_key_usages)
: generate_flags_(generate_flags),
all_public_key_usages_(all_public_key_usages),
all_private_key_usages_(all_private_key_usages) {}
// For instance "RSA-OAEP-256".
virtual const char* GetJwkAlgorithm(
const blink::WebCryptoAlgorithmId hash) const = 0;
virtual Status VerifyKeyUsagesBeforeGenerateKeyPair(
blink::WebCryptoKeyUsageMask combined_usage_mask,
blink::WebCryptoKeyUsageMask* public_usage_mask,
blink::WebCryptoKeyUsageMask* private_usage_mask) const OVERRIDE;
virtual Status GenerateKeyPair(
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask public_usage_mask,
blink::WebCryptoKeyUsageMask private_usage_mask,
blink::WebCryptoKey* public_key,
blink::WebCryptoKey* private_key) const OVERRIDE;
virtual Status VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE;
virtual Status ImportKeyPkcs8(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status ImportKeySpki(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE;
virtual Status ExportKeySpki(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE;
virtual Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE;
private:
CK_FLAGS generate_flags_;
blink::WebCryptoKeyUsageMask all_public_key_usages_;
blink::WebCryptoKeyUsageMask all_private_key_usages_;
};
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_NSS_RSA_KEY_NSS_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cryptohi.h>
#include <keyhi.h>
#include <pk11pub.h>
#include <secerr.h>
#include <sechash.h>
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/nss/rsa_key_nss.h"
#include "content/child/webcrypto/nss/util_nss.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace content {
namespace webcrypto {
namespace {
Status NssSupportsRsaOaep() {
if (NssRuntimeSupport::Get()->IsRsaOaepSupported())
return Status::Success();
return Status::ErrorUnsupported(
"NSS version doesn't support RSA-OAEP. Try using version 3.16.2 or "
"later");
}
CK_MECHANISM_TYPE WebCryptoHashToMGFMechanism(
const blink::WebCryptoAlgorithm& algorithm) {
switch (algorithm.id()) {
case blink::WebCryptoAlgorithmIdSha1:
return CKG_MGF1_SHA1;
case blink::WebCryptoAlgorithmIdSha256:
return CKG_MGF1_SHA256;
case blink::WebCryptoAlgorithmIdSha384:
return CKG_MGF1_SHA384;
case blink::WebCryptoAlgorithmIdSha512:
return CKG_MGF1_SHA512;
default:
return CKM_INVALID_MECHANISM;
}
}
CK_MECHANISM_TYPE WebCryptoHashToDigestMechanism(
const blink::WebCryptoAlgorithm& algorithm) {
switch (algorithm.id()) {
case blink::WebCryptoAlgorithmIdSha1:
return CKM_SHA_1;
case blink::WebCryptoAlgorithmIdSha256:
return CKM_SHA256;
case blink::WebCryptoAlgorithmIdSha384:
return CKM_SHA384;
case blink::WebCryptoAlgorithmIdSha512:
return CKM_SHA512;
default:
// Not a supported algorithm.
return CKM_INVALID_MECHANISM;
}
}
bool InitializeRsaOaepParams(const blink::WebCryptoAlgorithm& hash,
const CryptoData& label,
CK_RSA_PKCS_OAEP_PARAMS* oaep_params) {
oaep_params->source = CKZ_DATA_SPECIFIED;
oaep_params->pSourceData = const_cast<unsigned char*>(label.bytes());
oaep_params->ulSourceDataLen = label.byte_length();
oaep_params->mgf = WebCryptoHashToMGFMechanism(hash);
oaep_params->hashAlg = WebCryptoHashToDigestMechanism(hash);
if (oaep_params->mgf == CKM_INVALID_MECHANISM ||
oaep_params->hashAlg == CKM_INVALID_MECHANISM) {
return false;
}
return true;
}
Status EncryptRsaOaep(SECKEYPublicKey* key,
const blink::WebCryptoAlgorithm& hash,
const CryptoData& label,
const CryptoData& data,
std::vector<uint8>* buffer) {
CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
if (!InitializeRsaOaepParams(hash, label, &oaep_params))
return Status::ErrorUnsupported();
SECItem param;
param.type = siBuffer;
param.data = reinterpret_cast<unsigned char*>(&oaep_params);
param.len = sizeof(oaep_params);
buffer->resize(SECKEY_PublicKeyStrength(key));
unsigned char* buffer_data = Uint8VectorStart(buffer);
unsigned int output_len;
if (NssRuntimeSupport::Get()->pk11_pub_encrypt_func()(key,
CKM_RSA_PKCS_OAEP,
&param,
buffer_data,
&output_len,
buffer->size(),
data.bytes(),
data.byte_length(),
NULL) != SECSuccess) {
return Status::OperationError();
}
CHECK_LE(output_len, buffer->size());
buffer->resize(output_len);
return Status::Success();
}
Status DecryptRsaOaep(SECKEYPrivateKey* key,
const blink::WebCryptoAlgorithm& hash,
const CryptoData& label,
const CryptoData& data,
std::vector<uint8>* buffer) {
Status status = NssSupportsRsaOaep();
if (status.IsError())
return status;
CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
if (!InitializeRsaOaepParams(hash, label, &oaep_params))
return Status::ErrorUnsupported();
SECItem param;
param.type = siBuffer;
param.data = reinterpret_cast<unsigned char*>(&oaep_params);
param.len = sizeof(oaep_params);
const int modulus_length_bytes = PK11_GetPrivateModulusLen(key);
if (modulus_length_bytes <= 0)
return Status::ErrorUnexpected();
buffer->resize(modulus_length_bytes);
unsigned char* buffer_data = Uint8VectorStart(buffer);
unsigned int output_len;
if (NssRuntimeSupport::Get()->pk11_priv_decrypt_func()(key,
CKM_RSA_PKCS_OAEP,
&param,
buffer_data,
&output_len,
buffer->size(),
data.bytes(),
data.byte_length()) !=
SECSuccess) {
return Status::OperationError();
}
CHECK_LE(output_len, buffer->size());
buffer->resize(output_len);
return Status::Success();
}
class RsaOaepImplementation : public RsaHashedAlgorithm {
public:
RsaOaepImplementation()
: RsaHashedAlgorithm(
CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP,
blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
blink::WebCryptoKeyUsageDecrypt |
blink::WebCryptoKeyUsageUnwrapKey) {}
virtual Status VerifyKeyUsagesBeforeGenerateKeyPair(
blink::WebCryptoKeyUsageMask combined_usage_mask,
blink::WebCryptoKeyUsageMask* public_usage_mask,
blink::WebCryptoKeyUsageMask* private_usage_mask) const OVERRIDE {
Status status = NssSupportsRsaOaep();
if (status.IsError())
return status;
return RsaHashedAlgorithm::VerifyKeyUsagesBeforeGenerateKeyPair(
combined_usage_mask, public_usage_mask, private_usage_mask);
}
virtual Status VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
Status status = NssSupportsRsaOaep();
if (status.IsError())
return status;
return RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(format,
usage_mask);
}
virtual const char* GetJwkAlgorithm(
const blink::WebCryptoAlgorithmId hash) const OVERRIDE {
switch (hash) {
case blink::WebCryptoAlgorithmIdSha1:
return "RSA-OAEP";
case blink::WebCryptoAlgorithmIdSha256:
return "RSA-OAEP-256";
case blink::WebCryptoAlgorithmIdSha384:
return "RSA-OAEP-384";
case blink::WebCryptoAlgorithmIdSha512:
return "RSA-OAEP-512";
default:
return NULL;
}
}
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
if (key.type() != blink::WebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
return EncryptRsaOaep(
PublicKeyNss::Cast(key)->key(),
key.algorithm().rsaHashedParams()->hash(),
CryptoData(algorithm.rsaOaepParams()->optionalLabel()),
data,
buffer);
}
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
if (key.type() != blink::WebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
return DecryptRsaOaep(
PrivateKeyNss::Cast(key)->key(),
key.algorithm().rsaHashedParams()->hash(),
CryptoData(algorithm.rsaOaepParams()->optionalLabel()),
data,
buffer);
}
};
} // namespace
AlgorithmImplementation* CreatePlatformRsaOaepImplementation() {
return new RsaOaepImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cryptohi.h>
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/nss/rsa_key_nss.h"
#include "content/child/webcrypto/nss/util_nss.h"
#include "content/child/webcrypto/status.h"
#include "crypto/scoped_nss_types.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace content {
namespace webcrypto {
namespace {
class RsaSsaImplementation : public RsaHashedAlgorithm {
public:
RsaSsaImplementation()
: RsaHashedAlgorithm(CKF_SIGN | CKF_VERIFY,
blink::WebCryptoKeyUsageVerify,
blink::WebCryptoKeyUsageSign) {}
virtual const char* GetJwkAlgorithm(
const blink::WebCryptoAlgorithmId hash) const OVERRIDE {
switch (hash) {
case blink::WebCryptoAlgorithmIdSha1:
return "RS1";
case blink::WebCryptoAlgorithmIdSha256:
return "RS256";
case blink::WebCryptoAlgorithmIdSha384:
return "RS384";
case blink::WebCryptoAlgorithmIdSha512:
return "RS512";
default:
return NULL;
}
}
virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
if (key.type() != blink::WebCryptoKeyTypePrivate)
return Status::ErrorUnexpectedKeyType();
SECKEYPrivateKey* private_key = PrivateKeyNss::Cast(key)->key();
const blink::WebCryptoAlgorithm& hash =
key.algorithm().rsaHashedParams()->hash();
// Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the
// inner hash of the input Web Crypto algorithm.
SECOidTag sign_alg_tag;
switch (hash.id()) {
case blink::WebCryptoAlgorithmIdSha1:
sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
break;
case blink::WebCryptoAlgorithmIdSha256:
sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
break;
case blink::WebCryptoAlgorithmIdSha384:
sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
break;
case blink::WebCryptoAlgorithmIdSha512:
sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
break;
default:
return Status::ErrorUnsupported();
}
crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0));
if (SEC_SignData(signature_item.get(),
data.bytes(),
data.byte_length(),
private_key,
sign_alg_tag) != SECSuccess) {
return Status::OperationError();
}
buffer->assign(signature_item->data,
signature_item->data + signature_item->len);
return Status::Success();
}
virtual Status Verify(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) const OVERRIDE {
if (key.type() != blink::WebCryptoKeyTypePublic)
return Status::ErrorUnexpectedKeyType();
SECKEYPublicKey* public_key = PublicKeyNss::Cast(key)->key();
const blink::WebCryptoAlgorithm& hash =
key.algorithm().rsaHashedParams()->hash();
const SECItem signature_item = MakeSECItemForBuffer(signature);
SECOidTag hash_alg_tag;
switch (hash.id()) {
case blink::WebCryptoAlgorithmIdSha1:
hash_alg_tag = SEC_OID_SHA1;
break;
case blink::WebCryptoAlgorithmIdSha256:
hash_alg_tag = SEC_OID_SHA256;
break;
case blink::WebCryptoAlgorithmIdSha384:
hash_alg_tag = SEC_OID_SHA384;
break;
case blink::WebCryptoAlgorithmIdSha512:
hash_alg_tag = SEC_OID_SHA512;
break;
default:
return Status::ErrorUnsupported();
}
*signature_match =
SECSuccess == VFY_VerifyDataDirect(data.bytes(),
data.byte_length(),
public_key,
&signature_item,
SEC_OID_PKCS1_RSA_ENCRYPTION,
hash_alg_tag,
NULL,
NULL);
return Status::Success();
}
};
} // namespace
AlgorithmImplementation* CreatePlatformRsaSsaImplementation() {
return new RsaSsaImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <sechash.h>
#include <vector>
#include "content/child/webcrypto/algorithm_implementation.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/nss/util_nss.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/nss_util.h"
#include "crypto/scoped_nss_types.h"
namespace content {
namespace webcrypto {
namespace {
HASH_HashType WebCryptoAlgorithmToNSSHashType(
blink::WebCryptoAlgorithmId algorithm) {
switch (algorithm) {
case blink::WebCryptoAlgorithmIdSha1:
return HASH_AlgSHA1;
case blink::WebCryptoAlgorithmIdSha256:
return HASH_AlgSHA256;
case blink::WebCryptoAlgorithmIdSha384:
return HASH_AlgSHA384;
case blink::WebCryptoAlgorithmIdSha512:
return HASH_AlgSHA512;
default:
// Not a digest algorithm.
return HASH_AlgNULL;
}
}
// Implementation of blink::WebCryptoDigester, an internal Blink detail not
// part of WebCrypto, that allows chunks of data to be streamed in before
// computing a SHA-* digest (as opposed to ShaImplementation, which computes
// digests over complete messages)
class DigestorNSS : public blink::WebCryptoDigestor {
public:
explicit DigestorNSS(blink::WebCryptoAlgorithmId algorithm_id)
: hash_context_(NULL), algorithm_id_(algorithm_id) {}
virtual ~DigestorNSS() {
if (!hash_context_)
return;
HASH_Destroy(hash_context_);
hash_context_ = NULL;
}
virtual bool consume(const unsigned char* data, unsigned int size) {
return ConsumeWithStatus(data, size).IsSuccess();
}
Status ConsumeWithStatus(const unsigned char* data, unsigned int size) {
// Initialize everything if the object hasn't been initialized yet.
if (!hash_context_) {
Status error = Init();
if (!error.IsSuccess())
return error;
}
HASH_Update(hash_context_, data, size);
return Status::Success();
}
virtual bool finish(unsigned char*& result_data,
unsigned int& result_data_size) {
Status error = FinishInternal(result_, &result_data_size);
if (!error.IsSuccess())
return false;
result_data = result_;
return true;
}
Status FinishWithVectorAndStatus(std::vector<uint8>* result) {
if (!hash_context_)
return Status::ErrorUnexpected();
unsigned int result_length = HASH_ResultLenContext(hash_context_);
result->resize(result_length);
unsigned char* digest = Uint8VectorStart(result);
unsigned int digest_size; // ignored
return FinishInternal(digest, &digest_size);
}
private:
Status Init() {
HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm_id_);
if (hash_type == HASH_AlgNULL)
return Status::ErrorUnsupported();
hash_context_ = HASH_Create(hash_type);
if (!hash_context_)
return Status::OperationError();
HASH_Begin(hash_context_);
return Status::Success();
}
Status FinishInternal(unsigned char* result, unsigned int* result_size) {
if (!hash_context_) {
Status error = Init();
if (!error.IsSuccess())
return error;
}
unsigned int hash_result_length = HASH_ResultLenContext(hash_context_);
DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX));
HASH_End(hash_context_, result, result_size, hash_result_length);
if (*result_size != hash_result_length)
return Status::ErrorUnexpected();
return Status::Success();
}
HASHContext* hash_context_;
blink::WebCryptoAlgorithmId algorithm_id_;
unsigned char result_[HASH_LENGTH_MAX];
};
class ShaImplementation : public AlgorithmImplementation {
public:
virtual Status Digest(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
DigestorNSS digestor(algorithm.id());
Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
// http://crbug.com/366427: the spec does not define any other failures for
// digest, so none of the subsequent errors are spec compliant.
if (!error.IsSuccess())
return error;
return digestor.FinishWithVectorAndStatus(buffer);
}
};
} // namespace
AlgorithmImplementation* CreatePlatformShaImplementation() {
return new ShaImplementation();
}
scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
blink::WebCryptoAlgorithmId algorithm) {
return scoped_ptr<blink::WebCryptoDigestor>(new DigestorNSS(algorithm));
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/nss/sym_key_nss.h"
#include "base/logging.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/nss/key_nss.h"
#include "content/child/webcrypto/nss/util_nss.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/scoped_nss_types.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace content {
namespace webcrypto {
Status GenerateSecretKeyNss(const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
unsigned keylen_bytes,
CK_MECHANISM_TYPE mechanism,
blink::WebCryptoKey* key) {
DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
if (!slot)
return Status::OperationError();
crypto::ScopedPK11SymKey pk11_key(
PK11_KeyGen(slot.get(), mechanism, NULL, keylen_bytes, NULL));
if (!pk11_key)
return Status::OperationError();
if (PK11_ExtractKeyValue(pk11_key.get()) != SECSuccess)
return Status::OperationError();
const SECItem* key_data = PK11_GetKeyData(pk11_key.get());
if (!key_data)
return Status::OperationError();
scoped_ptr<SymKeyNss> handle(new SymKeyNss(
pk11_key.Pass(), CryptoData(key_data->data, key_data->len)));
*key = blink::WebCryptoKey::create(handle.release(),
blink::WebCryptoKeyTypeSecret,
extractable,
algorithm,
usage_mask);
return Status::Success();
}
Status ImportKeyRawNss(const CryptoData& key_data,
const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
CK_MECHANISM_TYPE mechanism,
CK_FLAGS flags,
blink::WebCryptoKey* key) {
DCHECK(!algorithm.isNull());
SECItem key_item = MakeSECItemForBuffer(key_data);
crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
crypto::ScopedPK11SymKey pk11_sym_key(
PK11_ImportSymKeyWithFlags(slot.get(),
mechanism,
PK11_OriginUnwrap,
CKA_FLAGS_ONLY,
&key_item,
flags,
false,
NULL));
if (!pk11_sym_key.get())
return Status::OperationError();
scoped_ptr<SymKeyNss> handle(new SymKeyNss(pk11_sym_key.Pass(), key_data));
*key = blink::WebCryptoKey::create(handle.release(),
blink::WebCryptoKeyTypeSecret,
extractable,
algorithm,
usage_mask);
return Status::Success();
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
#define CONTENT_CHILD_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
#include <pkcs11t.h>
#include "third_party/WebKit/public/platform/WebCrypto.h"
namespace content {
namespace webcrypto {
class CryptoData;
class Status;
Status GenerateSecretKeyNss(const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
unsigned keylen_bytes,
CK_MECHANISM_TYPE mechanism,
blink::WebCryptoKey* key);
Status ImportKeyRawNss(const CryptoData& key_data,
const blink::WebCryptoKeyAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
CK_MECHANISM_TYPE mechanism,
CK_FLAGS flags,
blink::WebCryptoKey* key);
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_NSS_SYM_KEY_NSS_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/nss/util_nss.h"
#include "base/lazy_instance.h"
#include "content/child/webcrypto/crypto_data.h"
#include "crypto/nss_util.h"
#include "crypto/scoped_nss_types.h"
#if defined(USE_NSS)
#include <dlfcn.h>
#include <secoid.h>
#endif
namespace content {
namespace webcrypto {
namespace {
base::LazyInstance<NssRuntimeSupport>::Leaky g_nss_runtime_support =
LAZY_INSTANCE_INITIALIZER;
} // namespace
// Creates a SECItem for the data in |buffer|. This does NOT make a copy, so
// |buffer| should outlive the SECItem.
SECItem MakeSECItemForBuffer(const CryptoData& buffer) {
SECItem item = {
siBuffer,
// NSS requires non-const data even though it is just for input.
const_cast<unsigned char*>(buffer.bytes()), buffer.byte_length()};
return item;
}
CryptoData SECItemToCryptoData(const SECItem& item) {
return CryptoData(item.data, item.len);
}
NssRuntimeSupport* NssRuntimeSupport::Get() {
return &g_nss_runtime_support.Get();
}
NssRuntimeSupport::NssRuntimeSupport() : internal_slot_does_oaep_(false) {
#if !defined(USE_NSS)
// Using a bundled version of NSS that is guaranteed to have this symbol.
pk11_encrypt_func_ = PK11_Encrypt;
pk11_decrypt_func_ = PK11_Decrypt;
pk11_pub_encrypt_func_ = PK11_PubEncrypt;
pk11_priv_decrypt_func_ = PK11_PrivDecrypt;
internal_slot_does_oaep_ = true;
#else
// Using system NSS libraries and PCKS #11 modules, which may not have the
// necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM).
// If PK11_Encrypt() was successfully resolved, then NSS will support
// AES-GCM directly. This was introduced in NSS 3.15.
pk11_encrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
dlsym(RTLD_DEFAULT, "PK11_Encrypt"));
pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
dlsym(RTLD_DEFAULT, "PK11_Decrypt"));
// Even though NSS's pk11wrap layer may support
// PK11_PubEncrypt/PK11_PubDecrypt (introduced in NSS 3.16.2), it may have
// loaded a softoken that does not include OAEP support.
pk11_pub_encrypt_func_ = reinterpret_cast<PK11_PubEncryptFunction>(
dlsym(RTLD_DEFAULT, "PK11_PubEncrypt"));
pk11_priv_decrypt_func_ = reinterpret_cast<PK11_PrivDecryptFunction>(
dlsym(RTLD_DEFAULT, "PK11_PrivDecrypt"));
if (pk11_priv_decrypt_func_ && pk11_pub_encrypt_func_) {
crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
internal_slot_does_oaep_ =
!!PK11_DoesMechanism(slot.get(), CKM_RSA_PKCS_OAEP);
}
#endif
}
void PlatformInit() {
crypto::EnsureNSSInit();
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_NSS_UTIL_NSS_H_
#define CONTENT_CHILD_WEBCRYPTO_NSS_UTIL_NSS_H_
#include <keythi.h>
#include <pkcs11t.h>
#include <seccomon.h>
#include <secmodt.h>
#include "base/lazy_instance.h"
namespace content {
namespace webcrypto {
class CryptoData;
SECItem MakeSECItemForBuffer(const CryptoData& buffer);
enum EncryptOrDecrypt { ENCRYPT, DECRYPT };
CryptoData SECItemToCryptoData(const SECItem& item);
// Signature for PK11_Encrypt and PK11_Decrypt.
typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*,
CK_MECHANISM_TYPE,
SECItem*,
unsigned char*,
unsigned int*,
unsigned int,
const unsigned char*,
unsigned int);
// Signature for PK11_PubEncrypt
typedef SECStatus (*PK11_PubEncryptFunction)(SECKEYPublicKey*,
CK_MECHANISM_TYPE,
SECItem*,
unsigned char*,
unsigned int*,
unsigned int,
const unsigned char*,
unsigned int,
void*);
// Signature for PK11_PrivDecrypt
typedef SECStatus (*PK11_PrivDecryptFunction)(SECKEYPrivateKey*,
CK_MECHANISM_TYPE,
SECItem*,
unsigned char*,
unsigned int*,
unsigned int,
const unsigned char*,
unsigned int);
// Singleton that detects whether or not AES-GCM and
// RSA-OAEP are supported by the version of NSS being used.
// On non-Linux platforms, Chromium embedders ship with a
// fixed version of NSS, and these are always available.
// However, on Linux (and ChromeOS), NSS is provided by the
// system, and thus not all algorithms may be available
// or be safe to use.
class NssRuntimeSupport {
public:
bool IsAesGcmSupported() const {
return pk11_encrypt_func_ && pk11_decrypt_func_;
}
bool IsRsaOaepSupported() const {
return pk11_pub_encrypt_func_ && pk11_priv_decrypt_func_ &&
internal_slot_does_oaep_;
}
// Returns NULL if unsupported.
PK11_EncryptDecryptFunction pk11_encrypt_func() const {
return pk11_encrypt_func_;
}
// Returns NULL if unsupported.
PK11_EncryptDecryptFunction pk11_decrypt_func() const {
return pk11_decrypt_func_;
}
// Returns NULL if unsupported.
PK11_PubEncryptFunction pk11_pub_encrypt_func() const {
return pk11_pub_encrypt_func_;
}
// Returns NULL if unsupported.
PK11_PrivDecryptFunction pk11_priv_decrypt_func() const {
return pk11_priv_decrypt_func_;
}
static NssRuntimeSupport* Get();
private:
friend struct base::DefaultLazyInstanceTraits<NssRuntimeSupport>;
NssRuntimeSupport();
PK11_EncryptDecryptFunction pk11_encrypt_func_;
PK11_EncryptDecryptFunction pk11_decrypt_func_;
PK11_PubEncryptFunction pk11_pub_encrypt_func_;
PK11_PrivDecryptFunction pk11_priv_decrypt_func_;
bool internal_slot_does_oaep_;
};
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_NSS_UTIL_NSS_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <openssl/aes.h>
#include <openssl/evp.h>
#include "base/logging.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/openssl/aes_key_openssl.h"
#include "content/child/webcrypto/openssl/key_openssl.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
namespace content {
namespace webcrypto {
namespace {
const EVP_CIPHER* GetAESCipherByKeyLength(unsigned int key_length_bytes) {
// BoringSSL does not support 192-bit AES keys.
switch (key_length_bytes) {
case 16:
return EVP_aes_128_cbc();
case 32:
return EVP_aes_256_cbc();
default:
return NULL;
}
}
// OpenSSL constants for EVP_CipherInit_ex(), do not change
enum CipherOperation { kDoDecrypt = 0, kDoEncrypt = 1 };
Status AesCbcEncryptDecrypt(CipherOperation cipher_operation,
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) {
const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
const std::vector<uint8>& raw_key = SymKeyOpenSsl::Cast(key)->raw_key_data();
if (params->iv().size() != 16)
return Status::ErrorIncorrectSizeAesCbcIv();
if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) {
// TODO(padolph): Handle this by chunking the input fed into OpenSSL. Right
// now it doesn't make much difference since the one-shot API would end up
// blowing out the memory and crashing anyway.
return Status::ErrorDataTooLarge();
}
// Note: PKCS padding is enabled by default
crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>::Type context(
EVP_CIPHER_CTX_new());
if (!context.get())
return Status::OperationError();
const EVP_CIPHER* const cipher = GetAESCipherByKeyLength(raw_key.size());
DCHECK(cipher);
if (!EVP_CipherInit_ex(context.get(),
cipher,
NULL,
&raw_key[0],
params->iv().data(),
cipher_operation)) {
return Status::OperationError();
}
// According to the openssl docs, the amount of data written may be as large
// as (data_size + cipher_block_size - 1), constrained to a multiple of
// cipher_block_size.
unsigned int output_max_len = data.byte_length() + AES_BLOCK_SIZE - 1;
const unsigned remainder = output_max_len % AES_BLOCK_SIZE;
if (remainder != 0)
output_max_len += AES_BLOCK_SIZE - remainder;
DCHECK_GT(output_max_len, data.byte_length());
buffer->resize(output_max_len);
unsigned char* const buffer_data = Uint8VectorStart(buffer);
int output_len = 0;
if (!EVP_CipherUpdate(context.get(),
buffer_data,
&output_len,
data.bytes(),
data.byte_length()))
return Status::OperationError();
int final_output_chunk_len = 0;
if (!EVP_CipherFinal_ex(
context.get(), buffer_data + output_len, &final_output_chunk_len)) {
return Status::OperationError();
}
const unsigned int final_output_len =
static_cast<unsigned int>(output_len) +
static_cast<unsigned int>(final_output_chunk_len);
DCHECK_LE(final_output_len, output_max_len);
buffer->resize(final_output_len);
return Status::Success();
}
class AesCbcImplementation : public AesAlgorithm {
public:
AesCbcImplementation() : AesAlgorithm("CBC") {}
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
return AesCbcEncryptDecrypt(kDoEncrypt, algorithm, key, data, buffer);
}
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
return AesCbcEncryptDecrypt(kDoDecrypt, algorithm, key, data, buffer);
}
};
} // namespace
AlgorithmImplementation* CreatePlatformAesCbcImplementation() {
return new AesCbcImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include <openssl/evp.h>
#include "base/logging.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/openssl/aes_key_openssl.h"
#include "content/child/webcrypto/openssl/key_openssl.h"
#include "content/child/webcrypto/openssl/util_openssl.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
namespace content {
namespace webcrypto {
namespace {
const EVP_AEAD* GetAesGcmAlgorithmFromKeySize(unsigned int key_size_bytes) {
switch (key_size_bytes) {
case 16:
return EVP_aead_aes_128_gcm();
// TODO(eroman): Hook up 256-bit support when it is available.
default:
return NULL;
}
}
Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) {
const std::vector<uint8>& raw_key = SymKeyOpenSsl::Cast(key)->raw_key_data();
const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
unsigned int tag_length_bits;
Status status = GetAesGcmTagLengthInBits(params, &tag_length_bits);
if (status.IsError())
return status;
unsigned int tag_length_bytes = tag_length_bits / 8;
CryptoData iv(params->iv());
CryptoData additional_data(params->optionalAdditionalData());
EVP_AEAD_CTX ctx;
const EVP_AEAD* const aead_alg =
GetAesGcmAlgorithmFromKeySize(raw_key.size());
if (!aead_alg)
return Status::ErrorUnexpected();
if (!EVP_AEAD_CTX_init(&ctx,
aead_alg,
Uint8VectorStart(raw_key),
raw_key.size(),
tag_length_bytes,
NULL)) {
return Status::OperationError();
}
crypto::ScopedOpenSSL<EVP_AEAD_CTX, EVP_AEAD_CTX_cleanup>::Type ctx_cleanup(
&ctx);
size_t len;
int ok;
if (mode == DECRYPT) {
if (data.byte_length() < tag_length_bytes)
return Status::ErrorDataTooSmall();
buffer->resize(data.byte_length() - tag_length_bytes);
ok = EVP_AEAD_CTX_open(&ctx,
Uint8VectorStart(buffer),
&len,
buffer->size(),
iv.bytes(),
iv.byte_length(),
data.bytes(),
data.byte_length(),
additional_data.bytes(),
additional_data.byte_length());
} else {
// No need to check for unsigned integer overflow here (seal fails if
// the output buffer is too small).
buffer->resize(data.byte_length() + tag_length_bytes);
ok = EVP_AEAD_CTX_seal(&ctx,
Uint8VectorStart(buffer),
&len,
buffer->size(),
iv.bytes(),
iv.byte_length(),
data.bytes(),
data.byte_length(),
additional_data.bytes(),
additional_data.byte_length());
}
if (!ok)
return Status::OperationError();
buffer->resize(len);
return Status::Success();
}
class AesGcmImplementation : public AesAlgorithm {
public:
AesGcmImplementation() : AesAlgorithm("GCM") {}
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
return AesGcmEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer);
}
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
return AesGcmEncryptDecrypt(DECRYPT, algorithm, key, data, buffer);
}
};
} // namespace
AlgorithmImplementation* CreatePlatformAesGcmImplementation() {
return new AesGcmImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/openssl/aes_key_openssl.h"
#include "base/logging.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/jwk.h"
#include "content/child/webcrypto/openssl/key_openssl.h"
#include "content/child/webcrypto/openssl/sym_key_openssl.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace content {
namespace webcrypto {
AesAlgorithm::AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,
const std::string& jwk_suffix)
: all_key_usages_(all_key_usages), jwk_suffix_(jwk_suffix) {
}
AesAlgorithm::AesAlgorithm(const std::string& jwk_suffix)
: all_key_usages_(blink::WebCryptoKeyUsageEncrypt |
blink::WebCryptoKeyUsageDecrypt |
blink::WebCryptoKeyUsageWrapKey |
blink::WebCryptoKeyUsageUnwrapKey),
jwk_suffix_(jwk_suffix) {
}
Status AesAlgorithm::VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const {
return CheckKeyCreationUsages(all_key_usages_, usage_mask);
}
Status AesAlgorithm::GenerateSecretKey(
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
unsigned int keylen_bits;
Status status =
GetAesKeyGenLengthInBits(algorithm.aesKeyGenParams(), &keylen_bits);
if (status.IsError())
return status;
return GenerateSecretKeyOpenSsl(
blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
extractable,
usage_mask,
keylen_bits / 8,
key);
}
Status AesAlgorithm::VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
case blink::WebCryptoKeyFormatJwk:
return CheckKeyCreationUsages(all_key_usages_, usage_mask);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
}
Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
const unsigned int keylen_bytes = key_data.byte_length();
Status status = VerifyAesKeyLengthForImport(keylen_bytes);
if (status.IsError())
return status;
// No possibility of overflow.
unsigned int keylen_bits = keylen_bytes * 8;
return ImportKeyRawOpenSsl(
key_data,
blink::WebCryptoKeyAlgorithm::createAes(algorithm.id(), keylen_bits),
extractable,
usage_mask,
key);
}
Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const {
std::vector<uint8> raw_data;
Status status = ReadAesSecretKeyJwk(
key_data, jwk_suffix_, extractable, usage_mask, &raw_data);
if (status.IsError())
return status;
return ImportKeyRaw(
CryptoData(raw_data), algorithm, extractable, usage_mask, key);
}
Status AesAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const {
*buffer = SymKeyOpenSsl::Cast(key)->raw_key_data();
return Status::Success();
}
Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const {
const std::vector<uint8>& raw_data = SymKeyOpenSsl::Cast(key)->raw_key_data();
WriteSecretKeyJwk(CryptoData(raw_data),
MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size()),
key.extractable(),
key.usages(),
buffer);
return Status::Success();
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_OPENSSL_AES_OPENSSL_H_
#define CONTENT_CHILD_WEBCRYPTO_OPENSSL_AES_OPENSSL_H_
#include "content/child/webcrypto/algorithm_implementation.h"
namespace content {
namespace webcrypto {
// Base class for AES algorithms that provides the implementation for key
// creation and export.
class AesAlgorithm : public AlgorithmImplementation {
public:
// |all_key_usages| is the set of all WebCrypto key usages that are
// allowed for imported or generated keys. |jwk_suffix| is the suffix
// used when constructing JWK names for the algorithm. For instance A128CBC
// is the JWK name for 128-bit AES-CBC. The |jwk_suffix| in this case would
// be "CBC".
AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,
const std::string& jwk_suffix);
// This is the same as the other AesAlgorithm constructor where
// |all_key_usages| is pre-filled to values for encryption/decryption
// algorithms (supports usages for: encrypt, decrypt, wrap, unwrap).
explicit AesAlgorithm(const std::string& jwk_suffix);
virtual Status VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE;
virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE;
virtual Status ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE;
virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE;
virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE;
private:
const blink::WebCryptoKeyUsageMask all_key_usages_;
const std::string jwk_suffix_;
};
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_OPENSSL_AES_OPENSSL_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/logging.h"
#include "content/child/webcrypto/openssl/aes_key_openssl.h"
#include "content/child/webcrypto/status.h"
namespace content {
namespace webcrypto {
namespace {
class AesKwImplementation : public AesAlgorithm {
public:
AesKwImplementation() : AesAlgorithm("KW") {}
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
// TODO(eroman):
return Status::ErrorUnsupported();
}
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
// TODO(eroman):
return Status::ErrorUnsupported();
}
};
} // namespace
AlgorithmImplementation* CreatePlatformAesKwImplementation() {
return new AesKwImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <openssl/hmac.h>
#include "base/logging.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/jwk.h"
#include "content/child/webcrypto/openssl/key_openssl.h"
#include "content/child/webcrypto/openssl/sym_key_openssl.h"
#include "content/child/webcrypto/openssl/util_openssl.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/secure_util.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace content {
namespace webcrypto {
namespace {
const blink::WebCryptoKeyUsageMask kAllKeyUsages =
blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
Status SignHmac(const std::vector<uint8>& raw_key,
const blink::WebCryptoAlgorithm& hash,
const CryptoData& data,
std::vector<uint8>* buffer) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
const EVP_MD* digest_algorithm = GetDigest(hash.id());
if (!digest_algorithm)
return Status::ErrorUnsupported();
unsigned int hmac_expected_length = EVP_MD_size(digest_algorithm);
// OpenSSL wierdness here.
// First, HMAC() needs a void* for the key data, so make one up front as a
// cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key,
// which will result if the raw_key vector is empty; an entirely valid
// case. Handle this specific case by pointing to an empty array.
const unsigned char null_key[] = {};
const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key;
buffer->resize(hmac_expected_length);
crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result(
Uint8VectorStart(buffer), hmac_expected_length);
unsigned int hmac_actual_length;
unsigned char* const success = HMAC(digest_algorithm,
raw_key_voidp,
raw_key.size(),
data.bytes(),
data.byte_length(),
hmac_result.safe_buffer(),
&hmac_actual_length);
if (!success || hmac_actual_length != hmac_expected_length)
return Status::OperationError();
return Status::Success();
}
class HmacImplementation : public AlgorithmImplementation {
public:
HmacImplementation() {}
virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE {
const blink::WebCryptoHmacKeyGenParams* params =
algorithm.hmacKeyGenParams();
unsigned int keylen_bits = 0;
Status status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
if (status.IsError())
return status;
return GenerateSecretKeyOpenSsl(blink::WebCryptoKeyAlgorithm::createHmac(
params->hash().id(), keylen_bits),
extractable,
usage_mask,
keylen_bits / 8,
key);
}
virtual Status VerifyKeyUsagesBeforeImportKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
case blink::WebCryptoKeyFormatJwk:
return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
}
virtual Status VerifyKeyUsagesBeforeGenerateKey(
blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
}
virtual Status ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE {
const blink::WebCryptoAlgorithm& hash =
algorithm.hmacImportParams()->hash();
// TODO(eroman): check for overflow.
unsigned int keylen_bits = key_data.byte_length() * 8;
return ImportKeyRawOpenSsl(
key_data,
blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bits),
extractable,
usage_mask,
key);
}
virtual Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) const OVERRIDE {
const char* algorithm_name =
GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
if (!algorithm_name)
return Status::ErrorUnexpected();
std::vector<uint8> raw_data;
Status status = ReadSecretKeyJwk(
key_data, algorithm_name, extractable, usage_mask, &raw_data);
if (status.IsError())
return status;
return ImportKeyRaw(
CryptoData(raw_data), algorithm, extractable, usage_mask, key);
}
virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE {
*buffer = SymKeyOpenSsl::Cast(key)->raw_key_data();
return Status::Success();
}
virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
std::vector<uint8>* buffer) const OVERRIDE {
SymKeyOpenSsl* sym_key = SymKeyOpenSsl::Cast(key);
const std::vector<uint8>& raw_data = sym_key->raw_key_data();
const char* algorithm_name =
GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
if (!algorithm_name)
return Status::ErrorUnexpected();
WriteSecretKeyJwk(CryptoData(raw_data),
algorithm_name,
key.extractable(),
key.usages(),
buffer);
return Status::Success();
}
virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
const blink::WebCryptoAlgorithm& hash =
key.algorithm().hmacParams()->hash();
return SignHmac(
SymKeyOpenSsl::Cast(key)->raw_key_data(), hash, data, buffer);
}
virtual Status Verify(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) const OVERRIDE {
std::vector<uint8> result;
Status status = Sign(algorithm, key, data, &result);
if (status.IsError())
return status;
// Do not allow verification of truncated MACs.
*signature_match = result.size() == signature.byte_length() &&
crypto::SecureMemEqual(Uint8VectorStart(result),
signature.bytes(),
signature.byte_length());
return Status::Success();
}
};
} // namespace
AlgorithmImplementation* CreatePlatformHmacImplementation() {
return new HmacImplementation;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/child/webcrypto/openssl/key_openssl.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
namespace content {
namespace webcrypto {
KeyOpenSsl::KeyOpenSsl(const CryptoData& serialized_key_data)
: serialized_key_data_(
serialized_key_data.bytes(),
serialized_key_data.bytes() + serialized_key_data.byte_length()) {
}
KeyOpenSsl::~KeyOpenSsl() {
}
SymKeyOpenSsl* KeyOpenSsl::AsSymKey() {
return NULL;
}
SymKeyOpenSsl::~SymKeyOpenSsl() {
}
SymKeyOpenSsl* SymKeyOpenSsl::Cast(const blink::WebCryptoKey& key) {
KeyOpenSsl* platform_key = reinterpret_cast<KeyOpenSsl*>(key.handle());
return platform_key->AsSymKey();
}
SymKeyOpenSsl* SymKeyOpenSsl::AsSymKey() {
return this;
}
SymKeyOpenSsl::SymKeyOpenSsl(const CryptoData& raw_key_data)
: KeyOpenSsl(raw_key_data) {
}
bool PlatformSerializeKeyForClone(const blink::WebCryptoKey& key,
blink::WebVector<uint8>* key_data) {
const KeyOpenSsl* openssl_key = static_cast<KeyOpenSsl*>(key.handle());
*key_data = openssl_key->serialized_key_data();
return true;
}
} // namespace webcrypto
} // namespace content
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_CHILD_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
#define CONTENT_CHILD_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
#include "content/child/webcrypto/algorithm_implementation.h"
namespace content {
namespace webcrypto {
class SymKeyOpenSsl;
// Base key class for all OpenSSL keys, used to safely cast between types. Each
// key maintains a copy of its serialized form in either 'raw', 'pkcs8', or
// 'spki' format. This is to allow structured cloning of keys synchronously from
// the target Blink thread without having to lock access to the key.
class KeyOpenSsl : public blink::WebCryptoKeyHandle {
public:
explicit KeyOpenSsl(const CryptoData& serialized_key_data);
virtual ~KeyOpenSsl();
virtual SymKeyOpenSsl* AsSymKey();
const std::vector<uint8>& serialized_key_data() const {
return serialized_key_data_;
}
private:
const std::vector<uint8> serialized_key_data_;
};
class SymKeyOpenSsl : public KeyOpenSsl {
public:
virtual ~SymKeyOpenSsl();
explicit SymKeyOpenSsl(const CryptoData& raw_key_data);
static SymKeyOpenSsl* Cast(const blink::WebCryptoKey& key);
virtual SymKeyOpenSsl* AsSymKey() OVERRIDE;
const std::vector<uint8>& raw_key_data() const {
return serialized_key_data();
}
private:
DISALLOW_COPY_AND_ASSIGN(SymKeyOpenSsl);
};
} // namespace webcrypto
} // namespace content
#endif // CONTENT_CHILD_WEBCRYPTO_OPENSSL_KEY_OPENSSL_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include "base/logging.h"
#include "content/child/webcrypto/algorithm_implementation.h"
#include "content/child/webcrypto/crypto_data.h"
#include "content/child/webcrypto/openssl/util_openssl.h"
#include "content/child/webcrypto/status.h"
#include "content/child/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
namespace content {
namespace webcrypto {
namespace {
// Implementation of blink::WebCryptoDigester, an internal Blink detail not
// part of WebCrypto, that allows chunks of data to be streamed in before
// computing a SHA-* digest (as opposed to ShaImplementation, which computes
// digests over complete messages)
class DigestorOpenSsl : public blink::WebCryptoDigestor {
public:
explicit DigestorOpenSsl(blink::WebCryptoAlgorithmId algorithm_id)
: initialized_(false),
digest_context_(EVP_MD_CTX_create()),
algorithm_id_(algorithm_id) {}
virtual bool consume(const unsigned char* data, unsigned int size) {
return ConsumeWithStatus(data, size).IsSuccess();
}
Status ConsumeWithStatus(const unsigned char* data, unsigned int size) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
Status error = Init();
if (!error.IsSuccess())
return error;
if (!EVP_DigestUpdate(digest_context_.get(), data, size))
return Status::OperationError();
return Status::Success();
}
virtual bool finish(unsigned char*& result_data,
unsigned int& result_data_size) {
Status error = FinishInternal(result_, &result_data_size);
if (!error.IsSuccess())
return false;
result_data = result_;
return true;
}
Status FinishWithVectorAndStatus(std::vector<uint8>* result) {
const int hash_expected_size = EVP_MD_CTX_size(digest_context_.get());
result->resize(hash_expected_size);
unsigned char* const hash_buffer = Uint8VectorStart(result);
unsigned int hash_buffer_size; // ignored
return FinishInternal(hash_buffer, &hash_buffer_size);
}
private:
Status Init() {
if (initialized_)
return Status::Success();
const EVP_MD* digest_algorithm = GetDigest(algorithm_id_);
if (!digest_algorithm)
return Status::ErrorUnexpected();
if (!digest_context_.get())
return Status::OperationError();
if (!EVP_DigestInit_ex(digest_context_.get(), digest_algorithm, NULL))
return Status::OperationError();
initialized_ = true;
return Status::Success();
}
Status FinishInternal(unsigned char* result, unsigned int* result_size) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
Status error = Init();
if (!error.IsSuccess())
return error;
const int hash_expected_size = EVP_MD_CTX_size(digest_context_.get());
if (hash_expected_size <= 0)
return Status::ErrorUnexpected();
DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE);
if (!EVP_DigestFinal_ex(digest_context_.get(), result, result_size) ||
static_cast<int>(*result_size) != hash_expected_size)
return Status::OperationError();
return Status::Success();
}
bool initialized_;
crypto::ScopedEVP_MD_CTX digest_context_;
blink::WebCryptoAlgorithmId algorithm_id_;
unsigned char result_[EVP_MAX_MD_SIZE];
};
class ShaImplementation : public AlgorithmImplementation {
public:
virtual Status Digest(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8>* buffer) const OVERRIDE {
DigestorOpenSsl digestor(algorithm.id());
Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
// http://crbug.com/366427: the spec does not define any other failures for
// digest, so none of the subsequent errors are spec compliant.
if (!error.IsSuccess())
return error;
return digestor.FinishWithVectorAndStatus(buffer);
}
};
} // namespace
AlgorithmImplementation* CreatePlatformShaImplementation() {
return new ShaImplementation();
}
scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
blink::WebCryptoAlgorithmId algorithm) {
return scoped_ptr<blink::WebCryptoDigestor>(new DigestorOpenSsl(algorithm));
}
} // namespace webcrypto
} // namespace content
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -25,6 +25,8 @@ class WebCryptoImpl : public blink::WebCrypto { ...@@ -25,6 +25,8 @@ class WebCryptoImpl : public blink::WebCrypto {
virtual ~WebCryptoImpl(); virtual ~WebCryptoImpl();
static void EnsureInit();
virtual void encrypt(const blink::WebCryptoAlgorithm& algorithm, virtual void encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key, const blink::WebCryptoKey& key,
const unsigned char* data, const unsigned char* data,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment