Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Side by Side Diff: content/renderer/webcrypto/webcrypto_impl_nss.cc

Issue 68303009: [webcrypto] Add RSASSA-PKCS1-v1_5 sign and verify for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698