Index: content/renderer/webcrypto/webcrypto_impl_openssl.cc |
diff --git a/content/renderer/webcrypto/webcrypto_impl_openssl.cc b/content/renderer/webcrypto/webcrypto_impl_openssl.cc |
index 040c174a62b0c85c6598158d9d8a61761e6eaf28..767d840dc00a42803046e4e918ce157c4c7b0a70 100644 |
--- a/content/renderer/webcrypto/webcrypto_impl_openssl.cc |
+++ b/content/renderer/webcrypto/webcrypto_impl_openssl.cc |
@@ -4,10 +4,37 @@ |
#include "content/renderer/webcrypto/webcrypto_impl.h" |
+#include <vector> |
+#include <openssl/hmac.h> |
+#include <openssl/sha.h> |
+ |
+#include "base/logging.h" |
+#include "crypto/openssl_util.h" |
+#include "crypto/secure_util.h" |
+#include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
+ |
namespace content { |
-void WebCryptoImpl::Init() { |
-} |
+namespace { |
+ |
+class SymKeyHandle : public WebKit::WebCryptoKeyHandle { |
+ public: |
+ SymKeyHandle(const unsigned char* key_data, unsigned key_data_size) |
+ : key_(key_data, key_data + key_data_size) {} |
+ |
+ const std::vector<unsigned char>& key() const { return key_; } |
+ |
+ private: |
+ const std::vector<unsigned char> key_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); |
+}; |
+ |
+} // anonymous namespace |
+ |
+void WebCryptoImpl::Init() { crypto::EnsureOpenSSLInit(); } |
bool WebCryptoImpl::EncryptInternal( |
const WebKit::WebCryptoAlgorithm& algorithm, |
@@ -15,6 +42,8 @@ bool WebCryptoImpl::EncryptInternal( |
const unsigned char* data, |
unsigned data_size, |
WebKit::WebArrayBuffer* buffer) { |
+ // TODO(padolph): Placeholder for OpenSSL implementation. |
+ // Issue http://crbug.com/267888. |
return false; |
} |
@@ -32,7 +61,7 @@ bool WebCryptoImpl::DigestInternal( |
const unsigned char* data, |
unsigned data_size, |
WebKit::WebArrayBuffer* buffer) { |
- // TODO(bryaneyler): Placeholder for OpenSSL implementation. |
+ // TODO(padolph): Placeholder for OpenSSL implementation. |
// Issue http://crbug.com/267888. |
return false; |
} |
@@ -42,12 +71,45 @@ bool WebCryptoImpl::ImportKeyInternal( |
const unsigned char* key_data, |
unsigned key_data_size, |
const WebKit::WebCryptoAlgorithm& algorithm, |
- WebKit::WebCryptoKeyUsageMask usage_mask, |
+ WebKit::WebCryptoKeyUsageMask /*usage_mask*/, |
scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, |
WebKit::WebCryptoKeyType* type) { |
- // TODO(bryaneyler): Placeholder for OpenSSL implementation. |
- // Issue http://crbug.com/267888. |
- return false; |
+ |
+ // TODO(padolph): Support all relevant alg types and then remove this gate. |
+ if (algorithm.id() != WebKit::WebCryptoAlgorithmIdHmac && |
+ algorithm.id() != WebKit::WebCryptoAlgorithmIdAesCbc) { |
+ return false; |
+ } |
+ |
+ // TODO(padolph): Need to split handling for symmetric (raw or jwk format) and |
+ // asymmetric (jwk, spki, or pkcs8 format) keys. |
+ // Currently only supporting symmetric. |
+ |
+ // TODO(padolph): jwk handling. Define precedence between jwk contents and |
+ // this method's parameters, e.g. 'alg' in jwk vs algorithm.id(). Who wins if |
+ // they differ? (jwk, probably) |
+ |
+ // Symmetric keys are always type secret |
+ *type = WebKit::WebCryptoKeyTypeSecret; |
+ |
+ const unsigned char* raw_key_data; |
+ unsigned raw_key_data_size; |
+ switch (format) { |
+ case WebKit::WebCryptoKeyFormatRaw: |
+ raw_key_data = key_data; |
+ raw_key_data_size = key_data_size; |
+ break; |
+ case WebKit::WebCryptoKeyFormatJwk: |
+ // TODO(padolph): Handle jwk format; need simple JSON parser. |
+ // break; |
+ return false; |
+ default: |
+ return false; |
+ } |
+ |
+ handle->reset(new SymKeyHandle(raw_key_data, raw_key_data_size)); |
+ |
+ return true; |
} |
bool WebCryptoImpl::SignInternal( |
@@ -56,9 +118,86 @@ bool WebCryptoImpl::SignInternal( |
const unsigned char* data, |
unsigned data_size, |
WebKit::WebArrayBuffer* buffer) { |
- // TODO(bryaneyler): Placeholder for OpenSSL implementation. |
- // Issue http://crbug.com/267888. |
- return false; |
+ |
+ WebKit::WebArrayBuffer result; |
+ |
+ switch (algorithm.id()) { |
+ case WebKit::WebCryptoAlgorithmIdHmac: { |
+ |
+ DCHECK_EQ(key.algorithm().id(), WebKit::WebCryptoAlgorithmIdHmac); |
+ DCHECK_NE(0, key.usages() & WebKit::WebCryptoKeyUsageSign); |
+ |
+ const WebKit::WebCryptoHmacParams* const params = algorithm.hmacParams(); |
+ if (!params) |
+ return false; |
+ |
+ const EVP_MD* evp_sha = 0; |
+ unsigned int hmac_expected_length = 0; |
+ // Note that HMAC length is determined by the hash used. |
+ switch (params->hash().id()) { |
+ case WebKit::WebCryptoAlgorithmIdSha1: |
+ evp_sha = EVP_sha1(); |
+ hmac_expected_length = SHA_DIGEST_LENGTH; |
+ break; |
+ case WebKit::WebCryptoAlgorithmIdSha224: |
+ evp_sha = EVP_sha224(); |
+ hmac_expected_length = SHA224_DIGEST_LENGTH; |
+ break; |
+ case WebKit::WebCryptoAlgorithmIdSha256: |
+ evp_sha = EVP_sha256(); |
+ hmac_expected_length = SHA256_DIGEST_LENGTH; |
+ break; |
+ case WebKit::WebCryptoAlgorithmIdSha384: |
+ evp_sha = EVP_sha384(); |
+ hmac_expected_length = SHA384_DIGEST_LENGTH; |
+ break; |
+ case WebKit::WebCryptoAlgorithmIdSha512: |
+ evp_sha = EVP_sha512(); |
+ hmac_expected_length = SHA512_DIGEST_LENGTH; |
+ break; |
+ default: |
+ // Not a digest algorithm. |
+ return false; |
+ } |
+ |
+ SymKeyHandle* const sym_key = |
+ reinterpret_cast<SymKeyHandle*>(key.handle()); |
+ const std::vector<unsigned char>& raw_key = sym_key->key(); |
+ |
+ // 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; |
+ |
+ result = WebKit::WebArrayBuffer::create(hmac_expected_length, 1); |
+ crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( |
+ reinterpret_cast<unsigned char*>(result.data()), |
+ hmac_expected_length); |
+ |
+ crypto::OpenSSLErrStackTracer(FROM_HERE); |
+ |
+ unsigned int hmac_actual_length; |
+ unsigned char* const success = HMAC(evp_sha, |
+ raw_key_voidp, |
+ raw_key.size(), |
+ data, |
+ data_size, |
+ hmac_result.safe_buffer(), |
+ &hmac_actual_length); |
+ if (!success || hmac_actual_length != hmac_expected_length) |
+ return false; |
+ |
+ break; |
+ } |
+ default: |
+ return false; |
+ } |
+ |
+ *buffer = result; |
+ return true; |
} |
bool WebCryptoImpl::VerifySignatureInternal( |
@@ -69,9 +208,27 @@ bool WebCryptoImpl::VerifySignatureInternal( |
const unsigned char* data, |
unsigned data_size, |
bool* signature_match) { |
- // TODO(bryaneyler): Placeholder for OpenSSL implementation. |
- // Issue http://crbug.com/267888. |
- return false; |
+ switch (algorithm.id()) { |
+ case WebKit::WebCryptoAlgorithmIdHmac: { |
+ WebKit::WebArrayBuffer result; |
+ if (!SignInternal(algorithm, key, data, data_size, &result)) { |
+ return false; |
+ } |
+ |
+ // Handling of truncated signatures is underspecified in the WebCrypto |
+ // spec, so here we fail verification if a truncated signature is being |
+ // verified. |
+ // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 |
+ *signature_match = |
+ result.byteLength() == signature_size && |
+ crypto::SecureMemEqual(result.data(), signature, signature_size); |
+ |
+ break; |
+ } |
+ default: |
+ return false; |
+ } |
+ return true; |
} |
} // namespace content |