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 761 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 854 return false; | 872 return false; | 
| 855 } | 873 } | 
| 856 } | 874 } | 
| 857 | 875 | 
| 858 bool WebCryptoImpl::SignInternal( | 876 bool WebCryptoImpl::SignInternal( | 
| 859 const blink::WebCryptoAlgorithm& algorithm, | 877 const blink::WebCryptoAlgorithm& algorithm, | 
| 860 const blink::WebCryptoKey& key, | 878 const blink::WebCryptoKey& key, | 
| 861 const unsigned char* data, | 879 const unsigned char* data, | 
| 862 unsigned data_size, | 880 unsigned data_size, | 
| 863 blink::WebArrayBuffer* buffer) { | 881 blink::WebArrayBuffer* buffer) { | 
| 882 | |
| 883 // Note: It is not an error to sign empty data. | |
| 884 | |
| 885 DCHECK(buffer); | |
| 886 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | |
| 887 | |
| 864 blink::WebArrayBuffer result; | 888 blink::WebArrayBuffer result; | 
| 865 | 889 | 
| 866 switch (algorithm.id()) { | 890 switch (algorithm.id()) { | 
| 867 case blink::WebCryptoAlgorithmIdHmac: { | 891 case blink::WebCryptoAlgorithmIdHmac: { | 
| 868 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | 892 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | 
| 869 if (!params) { | 893 if (!params) { | 
| 870 return false; | 894 return false; | 
| 871 } | 895 } | 
| 872 | 896 | 
| 873 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 897 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 
| 874 | 898 | 
| 875 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | 899 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | 
| 876 WebCryptoAlgorithmToHMACMechanism(params->hash())); | 900 WebCryptoAlgorithmToHMACMechanism(params->hash())); | 
| 877 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | |
| 878 | 901 | 
| 879 SECItem param_item = { siBuffer, NULL, 0 }; | 902 SECItem param_item = { siBuffer, NULL, 0 }; | 
| 880 SECItem data_item = { | 903 SECItem data_item = { | 
| 881 siBuffer, | 904 siBuffer, | 
| 882 const_cast<unsigned char*>(data), | 905 const_cast<unsigned char*>(data), | 
| 883 data_size | 906 data_size | 
| 884 }; | 907 }; | 
| 885 // First call is to figure out the length. | 908 // First call is to figure out the length. | 
| 886 SECItem signature_item = { siBuffer, NULL, 0 }; | 909 SECItem signature_item = { siBuffer, NULL, 0 }; | 
| 887 | 910 | 
| (...skipping 17 matching lines...) Expand all Loading... | |
| 905 &signature_item, | 928 &signature_item, | 
| 906 &data_item) != SECSuccess) { | 929 &data_item) != SECSuccess) { | 
| 907 NOTREACHED(); | 930 NOTREACHED(); | 
| 908 return false; | 931 return false; | 
| 909 } | 932 } | 
| 910 | 933 | 
| 911 DCHECK_EQ(result.byteLength(), signature_item.len); | 934 DCHECK_EQ(result.byteLength(), signature_item.len); | 
| 912 | 935 | 
| 913 break; | 936 break; | 
| 914 } | 937 } | 
| 938 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { | |
| 939 // Only private key signing is supported. | |
| 940 if (key.type() != blink::WebCryptoKeyTypePrivate) | |
| 941 return false; | |
| 942 | |
| 943 PrivateKeyHandle* const private_key = | |
| 944 reinterpret_cast<PrivateKeyHandle*>(key.handle()); | |
| 945 DCHECK(private_key); | |
| 946 DCHECK(private_key->key()); | |
| 947 | |
| 948 // Get the inner hash algorithm and convert to an NSS SECOidTag | |
| 949 const blink::WebCryptoAlgorithm hash_algorithm = | |
| 950 webcrypto::GetInnerHashAlgorithm(algorithm); | |
| 951 if (hash_algorithm.isNull()) // TODO(padolph): DCHECK instead? | |
| 952 return false; | |
| 953 const SECOidTag hash_alg_tag = | |
| 954 WebCryptoAlgorithmToNssSecOidShaTag(hash_algorithm); | |
| 955 if (hash_alg_tag == SEC_OID_UNKNOWN) | |
| 956 return false; | |
| 957 | |
| 958 // Get the NSS signature algorithm SECOidTag corresponding to the key type | |
| 959 // and inner hash algorithm SECOidTag. | |
| 960 const SECOidTag sign_alg_tag = SEC_GetSignatureAlgorithmOidTag( | |
| 961 private_key->key()->keyType, | |
| 962 hash_alg_tag); | |
| 963 if (sign_alg_tag == SEC_OID_UNKNOWN) | |
| 964 return false; | |
| 965 | |
| 966 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); | |
| 967 if (SEC_SignData(signature_item.get(), | |
| 968 data, | |
| 969 data_size, | |
| 970 private_key->key(), | |
| 971 sign_alg_tag) != SECSuccess) { | |
| 972 return false; | |
| 973 } | |
| 974 | |
| 975 result = webcrypto::CreateArrayBuffer(signature_item->data, | |
| 976 signature_item->len); | |
| 977 | |
| 978 break; | |
| 979 } | |
| 915 default: | 980 default: | 
| 916 return false; | 981 return false; | 
| 917 } | 982 } | 
| 918 | 983 | 
| 919 *buffer = result; | 984 *buffer = result; | 
| 920 return true; | 985 return true; | 
| 921 } | 986 } | 
| 922 | 987 | 
| 923 bool WebCryptoImpl::VerifySignatureInternal( | 988 bool WebCryptoImpl::VerifySignatureInternal( | 
| 924 const blink::WebCryptoAlgorithm& algorithm, | 989 const blink::WebCryptoAlgorithm& algorithm, | 
| 925 const blink::WebCryptoKey& key, | 990 const blink::WebCryptoKey& key, | 
| 926 const unsigned char* signature, | 991 const unsigned char* signature, | 
| 927 unsigned signature_size, | 992 unsigned signature_size, | 
| 928 const unsigned char* data, | 993 const unsigned char* data, | 
| 929 unsigned data_size, | 994 unsigned data_size, | 
| 930 bool* signature_match) { | 995 bool* signature_match) { | 
| 996 | |
| 997 if (!signature_size) | |
| 998 return false; | |
| 999 DCHECK(signature); | |
| 1000 | |
| 931 switch (algorithm.id()) { | 1001 switch (algorithm.id()) { | 
| 932 case blink::WebCryptoAlgorithmIdHmac: { | 1002 case blink::WebCryptoAlgorithmIdHmac: { | 
| 933 blink::WebArrayBuffer result; | 1003 blink::WebArrayBuffer result; | 
| 934 if (!SignInternal(algorithm, key, data, data_size, &result)) { | 1004 if (!SignInternal(algorithm, key, data, data_size, &result)) { | 
| 935 return false; | 1005 return false; | 
| 936 } | 1006 } | 
| 937 | 1007 | 
| 938 // Handling of truncated signatures is underspecified in the WebCrypto | 1008 // Handling of truncated signatures is underspecified in the WebCrypto | 
| 939 // spec, so here we fail verification if a truncated signature is being | 1009 // spec, so here we fail verification if a truncated signature is being | 
| 940 // verified. | 1010 // verified. | 
| 941 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | 1011 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | 
| 942 *signature_match = | 1012 *signature_match = | 
| 943 result.byteLength() == signature_size && | 1013 result.byteLength() == signature_size && | 
| 944 crypto::SecureMemEqual(result.data(), signature, signature_size); | 1014 crypto::SecureMemEqual(result.data(), signature, signature_size); | 
| 945 | 1015 | 
| 946 break; | 1016 break; | 
| 947 } | 1017 } | 
| 1018 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { | |
| 1019 | |
| 1020 // Only public key signature verification is supported. | |
| 1021 if (key.type() != blink::WebCryptoKeyTypePublic) | |
| 1022 return false; | |
| 1023 | |
| 1024 PublicKeyHandle* const public_key = | |
| 1025 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
| 1026 DCHECK(public_key); | |
| 1027 DCHECK(public_key->key()); | |
| 1028 | |
| 1029 const SECItem signature_item = { | |
| 1030 siBuffer, | |
| 1031 const_cast<unsigned char*>(signature), | |
| 1032 signature_size | |
| 1033 }; | |
| 1034 | |
| 1035 const SECOidTag hash_alg_tag = WebCryptoAlgorithmToNssSecOidShaTag( | |
| 
 
eroman
2013/12/19 22:56:38
Please check for SEC_OID_UNKNOWN and fail.
Passin
 
padolph
2013/12/20 00:03:39
Done.
 
 | |
| 1036 webcrypto::GetInnerHashAlgorithm(algorithm)); | |
| 1037 | |
| 1038 *signature_match = | |
| 1039 VFY_VerifyDataDirect( | |
| 1040 data, | |
| 1041 data_size, | |
| 1042 public_key->key(), | |
| 1043 &signature_item, | |
| 1044 SEC_OID_PKCS1_RSA_ENCRYPTION, | |
| 1045 hash_alg_tag, | |
| 1046 NULL, | |
| 1047 NULL) == SECSuccess; | |
| 1048 | |
| 1049 break; | |
| 1050 } | |
| 948 default: | 1051 default: | 
| 949 return false; | 1052 return false; | 
| 950 } | 1053 } | 
| 951 | 1054 | 
| 952 return true; | 1055 return true; | 
| 953 } | 1056 } | 
| 954 | 1057 | 
| 955 bool WebCryptoImpl::ImportRsaPublicKeyInternal( | 1058 bool WebCryptoImpl::ImportRsaPublicKeyInternal( | 
| 956 const unsigned char* modulus_data, | 1059 const unsigned char* modulus_data, | 
| 957 unsigned modulus_size, | 1060 unsigned modulus_size, | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1004 | 1107 | 
| 1005 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1108 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 
| 1006 blink::WebCryptoKeyTypePublic, | 1109 blink::WebCryptoKeyTypePublic, | 
| 1007 extractable, | 1110 extractable, | 
| 1008 algorithm, | 1111 algorithm, | 
| 1009 usage_mask); | 1112 usage_mask); | 
| 1010 return true; | 1113 return true; | 
| 1011 } | 1114 } | 
| 1012 | 1115 | 
| 1013 } // namespace content | 1116 } // namespace content | 
| OLD | NEW |