Index: content/renderer/webcrypto/webcrypto_impl_nss.cc |
diff --git a/content/renderer/webcrypto/webcrypto_impl_nss.cc b/content/renderer/webcrypto/webcrypto_impl_nss.cc |
index 73319df1a78b837fa4c7a93a762d6307cd06e3f8..43f9c2527a94a1c9dd0e32668a8a94bdcd378314 100644 |
--- a/content/renderer/webcrypto/webcrypto_impl_nss.cc |
+++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc |
@@ -80,6 +80,24 @@ HASH_HashType WebCryptoAlgorithmToNSSHashType( |
} |
} |
+SECOidTag WebCryptoAlgorithmToNssSecOidShaTag( |
+ const blink::WebCryptoAlgorithm& algorithm) { |
+ switch (algorithm.id()) { |
+ case blink::WebCryptoAlgorithmIdSha1: |
+ return SEC_OID_SHA1; |
+ case blink::WebCryptoAlgorithmIdSha224: |
+ return SEC_OID_SHA224; |
+ case blink::WebCryptoAlgorithmIdSha256: |
+ return SEC_OID_SHA256; |
+ case blink::WebCryptoAlgorithmIdSha384: |
+ return SEC_OID_SHA384; |
+ case blink::WebCryptoAlgorithmIdSha512: |
+ return SEC_OID_SHA512; |
+ default: |
+ return SEC_OID_UNKNOWN; |
+ } |
+} |
+ |
CK_MECHANISM_TYPE WebCryptoAlgorithmToHMACMechanism( |
const blink::WebCryptoAlgorithm& algorithm) { |
switch (algorithm.id()) { |
@@ -239,6 +257,31 @@ bool BigIntegerToLong(const uint8* data, |
return true; |
} |
+// TODO(padolph): Move to webcrypto_util |
eroman
2013/12/06 02:20:42
This can be done as part of this changelist.
padolph
2013/12/06 18:52:52
Done.
|
+blink::WebCryptoAlgorithm GetInnerHashAlgorithm( |
+ const blink::WebCryptoAlgorithm& algorithm) { |
+ DCHECK(!algorithm.isNull()); |
+ switch (algorithm.id()) { |
+ case blink::WebCryptoAlgorithmIdHmac: |
+ if (algorithm.hmacParams()) |
+ return algorithm.hmacParams()->hash(); |
+ else if (algorithm.hmacKeyParams()) |
+ return algorithm.hmacKeyParams()->hash(); |
+ break; |
+ case blink::WebCryptoAlgorithmIdRsaOaep: |
+ if (algorithm.rsaOaepParams()) |
+ return algorithm.rsaOaepParams()->hash(); |
+ break; |
+ case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: |
+ if (algorithm.rsaSsaParams()) |
+ return algorithm.rsaSsaParams()->hash(); |
+ break; |
+ default: |
+ break; |
+ } |
+ return blink::WebCryptoAlgorithm::createNull(); |
+} |
+ |
bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { |
return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || |
@@ -845,6 +888,12 @@ bool WebCryptoImpl::SignInternal( |
const unsigned char* data, |
unsigned data_size, |
blink::WebArrayBuffer* buffer) { |
+ |
+ // Note: It is not an error to sign empty data. |
+ |
+ DCHECK(buffer); |
+ DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); |
+ |
blink::WebArrayBuffer result; |
switch (algorithm.id()) { |
@@ -858,7 +907,6 @@ bool WebCryptoImpl::SignInternal( |
DCHECK_EQ(PK11_GetMechanism(sym_key->key()), |
WebCryptoAlgorithmToHMACMechanism(params->hash())); |
- DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); |
SECItem param_item = { siBuffer, NULL, 0 }; |
SECItem data_item = { |
@@ -896,6 +944,48 @@ bool WebCryptoImpl::SignInternal( |
break; |
} |
+ case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { |
+ // Only private key signing is supported. |
+ if (key.type() != blink::WebCryptoKeyTypePrivate) |
+ return false; |
+ |
+ PrivateKeyHandle* const private_key = |
+ reinterpret_cast<PrivateKeyHandle*>(key.handle()); |
+ DCHECK(private_key); |
+ DCHECK(private_key->key()); |
+ |
+ // Get the inner hash algorithm and convert to an NSS SECOidTag |
+ const blink::WebCryptoAlgorithm hash_algorithm = |
+ GetInnerHashAlgorithm(algorithm); |
+ if (hash_algorithm.isNull()) // TODO(padolph): DCHECK instead? |
+ return false; |
+ const SECOidTag hash_alg_tag = |
+ WebCryptoAlgorithmToNssSecOidShaTag(hash_algorithm); |
+ if (hash_alg_tag == SEC_OID_UNKNOWN) |
+ return false; |
+ |
+ // Get the NSS signature algorithm SECOidTag corresponding to the key type |
+ // and inner hash algorithm SECOidTag. |
+ const SECOidTag sign_alg_tag = SEC_GetSignatureAlgorithmOidTag( |
+ private_key->key()->keyType, |
+ hash_alg_tag); |
+ if (sign_alg_tag == SEC_OID_UNKNOWN) |
+ return false; |
+ |
+ crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); |
+ if (SEC_SignData(signature_item.get(), |
+ data, |
+ data_size, |
+ private_key->key(), |
+ sign_alg_tag) != SECSuccess) { |
+ return false; |
+ } |
+ |
+ result = blink::WebArrayBuffer::create(signature_item->len, 1); |
+ memcpy(result.data(), signature_item->data, signature_item->len); |
eroman
2013/12/06 02:20:42
I believe there is now a helper for this checked i
padolph
2013/12/06 18:52:52
Done.
|
+ |
+ break; |
+ } |
default: |
return false; |
} |
@@ -912,6 +1002,11 @@ bool WebCryptoImpl::VerifySignatureInternal( |
const unsigned char* data, |
unsigned data_size, |
bool* signature_match) { |
+ |
+ if (!signature_size) |
+ return false; |
+ DCHECK(signature); |
+ |
switch (algorithm.id()) { |
case blink::WebCryptoAlgorithmIdHmac: { |
blink::WebArrayBuffer result; |
@@ -929,6 +1024,36 @@ bool WebCryptoImpl::VerifySignatureInternal( |
break; |
} |
+ case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { |
+ |
+ // Only public key signature verification is supported. |
+ if (key.type() != blink::WebCryptoKeyTypePublic) |
+ return false; |
+ |
+ PublicKeyHandle* const public_key = |
+ reinterpret_cast<PublicKeyHandle*>(key.handle()); |
+ DCHECK(public_key); |
+ DCHECK(public_key->key()); |
+ |
+ const SECItem signature_item = { |
+ siBuffer, |
+ const_cast<unsigned char*>(signature), |
+ signature_size |
+ }; |
+ |
+ *signature_match = |
+ VFY_VerifyDataDirect( |
+ data, |
+ data_size, |
+ public_key->key(), |
+ &signature_item, |
+ SEC_OID_PKCS1_RSA_ENCRYPTION, |
+ SEC_OID_UNKNOWN, |
eroman
2013/12/06 02:20:42
Forgive my crypto ignorance, but is this safe?
Th
padolph
2013/12/06 18:52:52
We know at this callsite that we have an RSA key,
padolph
2013/12/07 00:41:04
Added explicit setting of the hash algorithm, and
|
+ NULL, |
+ NULL) == SECSuccess; |
+ |
+ break; |
+ } |
default: |
return false; |
} |