Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
| 6 | 6 |
| 7 #include <cryptohi.h> | 7 #include <cryptohi.h> |
| 8 #include <pk11pub.h> | 8 #include <pk11pub.h> |
| 9 #include <sechash.h> | 9 #include <sechash.h> |
| 10 | 10 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 case blink::WebCryptoAlgorithmIdSha384: | 73 case blink::WebCryptoAlgorithmIdSha384: |
| 74 return HASH_AlgSHA384; | 74 return HASH_AlgSHA384; |
| 75 case blink::WebCryptoAlgorithmIdSha512: | 75 case blink::WebCryptoAlgorithmIdSha512: |
| 76 return HASH_AlgSHA512; | 76 return HASH_AlgSHA512; |
| 77 default: | 77 default: |
| 78 // Not a digest algorithm. | 78 // Not a digest algorithm. |
| 79 return HASH_AlgNULL; | 79 return HASH_AlgNULL; |
| 80 } | 80 } |
| 81 } | 81 } |
| 82 | 82 |
| 83 SECOidTag WebCryptoAlgorithmToNssSecOidShaTag( | |
| 84 const blink::WebCryptoAlgorithm& algorithm) { | |
| 85 switch (algorithm.id()) { | |
| 86 case blink::WebCryptoAlgorithmIdSha1: | |
| 87 return SEC_OID_SHA1; | |
| 88 case blink::WebCryptoAlgorithmIdSha224: | |
| 89 return SEC_OID_SHA224; | |
| 90 case blink::WebCryptoAlgorithmIdSha256: | |
| 91 return SEC_OID_SHA256; | |
| 92 case blink::WebCryptoAlgorithmIdSha384: | |
| 93 return SEC_OID_SHA384; | |
| 94 case blink::WebCryptoAlgorithmIdSha512: | |
| 95 return SEC_OID_SHA512; | |
| 96 default: | |
| 97 return SEC_OID_UNKNOWN; | |
| 98 } | |
| 99 } | |
| 100 | |
| 83 CK_MECHANISM_TYPE WebCryptoAlgorithmToHMACMechanism( | 101 CK_MECHANISM_TYPE WebCryptoAlgorithmToHMACMechanism( |
| 84 const blink::WebCryptoAlgorithm& algorithm) { | 102 const blink::WebCryptoAlgorithm& algorithm) { |
| 85 switch (algorithm.id()) { | 103 switch (algorithm.id()) { |
| 86 case blink::WebCryptoAlgorithmIdSha1: | 104 case blink::WebCryptoAlgorithmIdSha1: |
| 87 return CKM_SHA_1_HMAC; | 105 return CKM_SHA_1_HMAC; |
| 88 case blink::WebCryptoAlgorithmIdSha256: | 106 case blink::WebCryptoAlgorithmIdSha256: |
| 89 return CKM_SHA256_HMAC; | 107 return CKM_SHA256_HMAC; |
| 90 default: | 108 default: |
| 91 // Not a supported algorithm. | 109 // Not a supported algorithm. |
| 92 return CKM_INVALID_MECHANISM; | 110 return CKM_INVALID_MECHANISM; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 232 size_t reverse_i = data_size - i - 1; | 250 size_t reverse_i = data_size - i - 1; |
| 233 | 251 |
| 234 if (reverse_i >= sizeof(unsigned long) && data[i]) | 252 if (reverse_i >= sizeof(unsigned long) && data[i]) |
| 235 return false; // Too large for a long. | 253 return false; // Too large for a long. |
| 236 | 254 |
| 237 *result |= data[i] << 8 * reverse_i; | 255 *result |= data[i] << 8 * reverse_i; |
| 238 } | 256 } |
| 239 return true; | 257 return true; |
| 240 } | 258 } |
| 241 | 259 |
| 260 // 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.
| |
| 261 blink::WebCryptoAlgorithm GetInnerHashAlgorithm( | |
| 262 const blink::WebCryptoAlgorithm& algorithm) { | |
| 263 DCHECK(!algorithm.isNull()); | |
| 264 switch (algorithm.id()) { | |
| 265 case blink::WebCryptoAlgorithmIdHmac: | |
| 266 if (algorithm.hmacParams()) | |
| 267 return algorithm.hmacParams()->hash(); | |
| 268 else if (algorithm.hmacKeyParams()) | |
| 269 return algorithm.hmacKeyParams()->hash(); | |
| 270 break; | |
| 271 case blink::WebCryptoAlgorithmIdRsaOaep: | |
| 272 if (algorithm.rsaOaepParams()) | |
| 273 return algorithm.rsaOaepParams()->hash(); | |
| 274 break; | |
| 275 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
| 276 if (algorithm.rsaSsaParams()) | |
| 277 return algorithm.rsaSsaParams()->hash(); | |
| 278 break; | |
| 279 default: | |
| 280 break; | |
| 281 } | |
| 282 return blink::WebCryptoAlgorithm::createNull(); | |
| 283 } | |
| 284 | |
| 242 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { | 285 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { |
| 243 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 286 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
| 244 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || | 287 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || |
| 245 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; | 288 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; |
| 246 } | 289 } |
| 247 | 290 |
| 248 bool ImportKeyInternalRaw( | 291 bool ImportKeyInternalRaw( |
| 249 const unsigned char* key_data, | 292 const unsigned char* key_data, |
| 250 unsigned key_data_size, | 293 unsigned key_data_size, |
| 251 const blink::WebCryptoAlgorithm& algorithm, | 294 const blink::WebCryptoAlgorithm& algorithm, |
| (...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 838 return false; | 881 return false; |
| 839 } | 882 } |
| 840 } | 883 } |
| 841 | 884 |
| 842 bool WebCryptoImpl::SignInternal( | 885 bool WebCryptoImpl::SignInternal( |
| 843 const blink::WebCryptoAlgorithm& algorithm, | 886 const blink::WebCryptoAlgorithm& algorithm, |
| 844 const blink::WebCryptoKey& key, | 887 const blink::WebCryptoKey& key, |
| 845 const unsigned char* data, | 888 const unsigned char* data, |
| 846 unsigned data_size, | 889 unsigned data_size, |
| 847 blink::WebArrayBuffer* buffer) { | 890 blink::WebArrayBuffer* buffer) { |
| 891 | |
| 892 // Note: It is not an error to sign empty data. | |
| 893 | |
| 894 DCHECK(buffer); | |
| 895 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | |
| 896 | |
| 848 blink::WebArrayBuffer result; | 897 blink::WebArrayBuffer result; |
| 849 | 898 |
| 850 switch (algorithm.id()) { | 899 switch (algorithm.id()) { |
| 851 case blink::WebCryptoAlgorithmIdHmac: { | 900 case blink::WebCryptoAlgorithmIdHmac: { |
| 852 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | 901 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); |
| 853 if (!params) { | 902 if (!params) { |
| 854 return false; | 903 return false; |
| 855 } | 904 } |
| 856 | 905 |
| 857 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 906 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); |
| 858 | 907 |
| 859 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | 908 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), |
| 860 WebCryptoAlgorithmToHMACMechanism(params->hash())); | 909 WebCryptoAlgorithmToHMACMechanism(params->hash())); |
| 861 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | |
| 862 | 910 |
| 863 SECItem param_item = { siBuffer, NULL, 0 }; | 911 SECItem param_item = { siBuffer, NULL, 0 }; |
| 864 SECItem data_item = { | 912 SECItem data_item = { |
| 865 siBuffer, | 913 siBuffer, |
| 866 const_cast<unsigned char*>(data), | 914 const_cast<unsigned char*>(data), |
| 867 data_size | 915 data_size |
| 868 }; | 916 }; |
| 869 // First call is to figure out the length. | 917 // First call is to figure out the length. |
| 870 SECItem signature_item = { siBuffer, NULL, 0 }; | 918 SECItem signature_item = { siBuffer, NULL, 0 }; |
| 871 | 919 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 889 &signature_item, | 937 &signature_item, |
| 890 &data_item) != SECSuccess) { | 938 &data_item) != SECSuccess) { |
| 891 NOTREACHED(); | 939 NOTREACHED(); |
| 892 return false; | 940 return false; |
| 893 } | 941 } |
| 894 | 942 |
| 895 DCHECK_EQ(result.byteLength(), signature_item.len); | 943 DCHECK_EQ(result.byteLength(), signature_item.len); |
| 896 | 944 |
| 897 break; | 945 break; |
| 898 } | 946 } |
| 947 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { | |
| 948 // Only private key signing is supported. | |
| 949 if (key.type() != blink::WebCryptoKeyTypePrivate) | |
| 950 return false; | |
| 951 | |
| 952 PrivateKeyHandle* const private_key = | |
| 953 reinterpret_cast<PrivateKeyHandle*>(key.handle()); | |
| 954 DCHECK(private_key); | |
| 955 DCHECK(private_key->key()); | |
| 956 | |
| 957 // Get the inner hash algorithm and convert to an NSS SECOidTag | |
| 958 const blink::WebCryptoAlgorithm hash_algorithm = | |
| 959 GetInnerHashAlgorithm(algorithm); | |
| 960 if (hash_algorithm.isNull()) // TODO(padolph): DCHECK instead? | |
| 961 return false; | |
| 962 const SECOidTag hash_alg_tag = | |
| 963 WebCryptoAlgorithmToNssSecOidShaTag(hash_algorithm); | |
| 964 if (hash_alg_tag == SEC_OID_UNKNOWN) | |
| 965 return false; | |
| 966 | |
| 967 // Get the NSS signature algorithm SECOidTag corresponding to the key type | |
| 968 // and inner hash algorithm SECOidTag. | |
| 969 const SECOidTag sign_alg_tag = SEC_GetSignatureAlgorithmOidTag( | |
| 970 private_key->key()->keyType, | |
| 971 hash_alg_tag); | |
| 972 if (sign_alg_tag == SEC_OID_UNKNOWN) | |
| 973 return false; | |
| 974 | |
| 975 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); | |
| 976 if (SEC_SignData(signature_item.get(), | |
| 977 data, | |
| 978 data_size, | |
| 979 private_key->key(), | |
| 980 sign_alg_tag) != SECSuccess) { | |
| 981 return false; | |
| 982 } | |
| 983 | |
| 984 result = blink::WebArrayBuffer::create(signature_item->len, 1); | |
| 985 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.
| |
| 986 | |
| 987 break; | |
| 988 } | |
| 899 default: | 989 default: |
| 900 return false; | 990 return false; |
| 901 } | 991 } |
| 902 | 992 |
| 903 *buffer = result; | 993 *buffer = result; |
| 904 return true; | 994 return true; |
| 905 } | 995 } |
| 906 | 996 |
| 907 bool WebCryptoImpl::VerifySignatureInternal( | 997 bool WebCryptoImpl::VerifySignatureInternal( |
| 908 const blink::WebCryptoAlgorithm& algorithm, | 998 const blink::WebCryptoAlgorithm& algorithm, |
| 909 const blink::WebCryptoKey& key, | 999 const blink::WebCryptoKey& key, |
| 910 const unsigned char* signature, | 1000 const unsigned char* signature, |
| 911 unsigned signature_size, | 1001 unsigned signature_size, |
| 912 const unsigned char* data, | 1002 const unsigned char* data, |
| 913 unsigned data_size, | 1003 unsigned data_size, |
| 914 bool* signature_match) { | 1004 bool* signature_match) { |
| 1005 | |
| 1006 if (!signature_size) | |
| 1007 return false; | |
| 1008 DCHECK(signature); | |
| 1009 | |
| 915 switch (algorithm.id()) { | 1010 switch (algorithm.id()) { |
| 916 case blink::WebCryptoAlgorithmIdHmac: { | 1011 case blink::WebCryptoAlgorithmIdHmac: { |
| 917 blink::WebArrayBuffer result; | 1012 blink::WebArrayBuffer result; |
| 918 if (!SignInternal(algorithm, key, data, data_size, &result)) { | 1013 if (!SignInternal(algorithm, key, data, data_size, &result)) { |
| 919 return false; | 1014 return false; |
| 920 } | 1015 } |
| 921 | 1016 |
| 922 // Handling of truncated signatures is underspecified in the WebCrypto | 1017 // Handling of truncated signatures is underspecified in the WebCrypto |
| 923 // spec, so here we fail verification if a truncated signature is being | 1018 // spec, so here we fail verification if a truncated signature is being |
| 924 // verified. | 1019 // verified. |
| 925 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | 1020 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 |
| 926 *signature_match = | 1021 *signature_match = |
| 927 result.byteLength() == signature_size && | 1022 result.byteLength() == signature_size && |
| 928 crypto::SecureMemEqual(result.data(), signature, signature_size); | 1023 crypto::SecureMemEqual(result.data(), signature, signature_size); |
| 929 | 1024 |
| 930 break; | 1025 break; |
| 931 } | 1026 } |
| 1027 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { | |
| 1028 | |
| 1029 // Only public key signature verification is supported. | |
| 1030 if (key.type() != blink::WebCryptoKeyTypePublic) | |
| 1031 return false; | |
| 1032 | |
| 1033 PublicKeyHandle* const public_key = | |
| 1034 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
| 1035 DCHECK(public_key); | |
| 1036 DCHECK(public_key->key()); | |
| 1037 | |
| 1038 const SECItem signature_item = { | |
| 1039 siBuffer, | |
| 1040 const_cast<unsigned char*>(signature), | |
| 1041 signature_size | |
| 1042 }; | |
| 1043 | |
| 1044 *signature_match = | |
| 1045 VFY_VerifyDataDirect( | |
| 1046 data, | |
| 1047 data_size, | |
| 1048 public_key->key(), | |
| 1049 &signature_item, | |
| 1050 SEC_OID_PKCS1_RSA_ENCRYPTION, | |
| 1051 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
| |
| 1052 NULL, | |
| 1053 NULL) == SECSuccess; | |
| 1054 | |
| 1055 break; | |
| 1056 } | |
| 932 default: | 1057 default: |
| 933 return false; | 1058 return false; |
| 934 } | 1059 } |
| 935 | 1060 |
| 936 return true; | 1061 return true; |
| 937 } | 1062 } |
| 938 | 1063 |
| 939 bool WebCryptoImpl::ImportRsaPublicKeyInternal( | 1064 bool WebCryptoImpl::ImportRsaPublicKeyInternal( |
| 940 const unsigned char* modulus_data, | 1065 const unsigned char* modulus_data, |
| 941 unsigned modulus_size, | 1066 unsigned modulus_size, |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 988 | 1113 |
| 989 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1114 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), |
| 990 blink::WebCryptoKeyTypePublic, | 1115 blink::WebCryptoKeyTypePublic, |
| 991 extractable, | 1116 extractable, |
| 992 algorithm, | 1117 algorithm, |
| 993 usage_mask); | 1118 usage_mask); |
| 994 return true; | 1119 return true; |
| 995 } | 1120 } |
| 996 | 1121 |
| 997 } // namespace content | 1122 } // namespace content |
| OLD | NEW |