1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/webcrypto/webcrypto_util.h"
7 #include "base/logging.h"
8 #include "components/webcrypto/status.h"
9 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
11 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
17 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
19 bool BigIntegerToUint(const uint8_t* data
,
21 unsigned int* result
) {
26 for (size_t i
= 0; i
< data_size
; ++i
) {
27 size_t reverse_i
= data_size
- i
- 1;
29 if (reverse_i
>= sizeof(*result
) && data
[i
])
30 return false; // Too large for a uint.
32 *result
|= data
[i
] << 8 * reverse_i
;
40 blink::WebCryptoAlgorithm
CreateAlgorithm(blink::WebCryptoAlgorithmId id
) {
41 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id
, NULL
);
44 blink::WebCryptoAlgorithm
CreateRsaHashedImportAlgorithm(
45 blink::WebCryptoAlgorithmId id
,
46 blink::WebCryptoAlgorithmId hash_id
) {
47 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id
));
48 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
49 id
, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id
)));
52 blink::WebCryptoAlgorithm
CreateEcImportAlgorithm(
53 blink::WebCryptoAlgorithmId id
,
54 blink::WebCryptoNamedCurve named_curve
) {
55 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
56 id
, new blink::WebCryptoEcKeyImportParams(named_curve
));
59 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a
,
60 blink::WebCryptoKeyUsageMask b
) {
65 Status
CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages
,
66 blink::WebCryptoKeyUsageMask actual_usages
,
67 bool allow_empty_usages
) {
68 if (!allow_empty_usages
&& actual_usages
== 0)
69 return Status::ErrorCreateKeyEmptyUsages();
71 if (!ContainsKeyUsages(all_possible_usages
, actual_usages
))
72 return Status::ErrorCreateKeyBadUsages();
73 return Status::Success();
76 Status
GetRsaKeyGenParameters(
77 const blink::WebCryptoRsaHashedKeyGenParams
* params
,
78 unsigned int* public_exponent
,
79 unsigned int* modulus_length_bits
) {
80 *modulus_length_bits
= params
->modulusLengthBits();
82 // Limit the RSA key sizes to:
83 // * Multiple of 8 bits
84 // * 256 bits to 16K bits
85 // This corresponds to the values that NSS would allow, which was relevant
86 // back when Chromium's WebCrypto supported both OpenSSL and NSS.
87 if (*modulus_length_bits
< 256 || *modulus_length_bits
> 16384 ||
88 (*modulus_length_bits
% 8) != 0) {
89 return Status::ErrorGenerateRsaUnsupportedModulus();
92 if (!BigIntegerToUint(params
->publicExponent().data(),
93 params
->publicExponent().size(), public_exponent
)) {
94 return Status::ErrorGenerateKeyPublicExponent();
97 // OpenSSL hangs when given bad public exponents. Use a whitelist to avoid
98 // feeding OpenSSL data that could hang.
99 if (*public_exponent
!= 3 && *public_exponent
!= 65537)
100 return Status::ErrorGenerateKeyPublicExponent();
102 return Status::Success();
105 Status
VerifyUsagesBeforeImportAsymmetricKey(
106 blink::WebCryptoKeyFormat format
,
107 blink::WebCryptoKeyUsageMask all_public_key_usages
,
108 blink::WebCryptoKeyUsageMask all_private_key_usages
,
109 blink::WebCryptoKeyUsageMask usages
) {
111 case blink::WebCryptoKeyFormatSpki
:
112 return CheckKeyCreationUsages(all_public_key_usages
, usages
, true);
113 case blink::WebCryptoKeyFormatPkcs8
:
114 return CheckKeyCreationUsages(all_private_key_usages
, usages
, false);
115 case blink::WebCryptoKeyFormatJwk
: {
116 // The JWK could represent either a public key or private key. The usages
117 // must make sense for one of the two. The usages will be checked again by
118 // ImportKeyJwk() once the key type has been determined.
119 if (CheckKeyCreationUsages(all_public_key_usages
, usages
, true)
121 CheckKeyCreationUsages(all_private_key_usages
, usages
, false)
123 return Status::ErrorCreateKeyBadUsages();
125 return Status::Success();
128 return Status::ErrorUnsupportedImportKeyFormat();
132 void TruncateToBitLength(size_t length_bits
, std::vector
<uint8_t>* bytes
) {
133 size_t length_bytes
= NumBitsToBytes(length_bits
);
135 if (bytes
->size() != length_bytes
) {
136 CHECK_LT(length_bytes
, bytes
->size());
137 bytes
->resize(length_bytes
);
140 size_t remainder_bits
= length_bits
% 8;
142 // Zero any "unused bits" in the final byte
144 (*bytes
)[bytes
->size() - 1] &= ~((0xFF) >> remainder_bits
);
148 Status
GetUsagesForGenerateAsymmetricKey(
149 blink::WebCryptoKeyUsageMask combined_usages
,
150 blink::WebCryptoKeyUsageMask all_public_usages
,
151 blink::WebCryptoKeyUsageMask all_private_usages
,
152 blink::WebCryptoKeyUsageMask
* public_usages
,
153 blink::WebCryptoKeyUsageMask
* private_usages
) {
154 Status status
= CheckKeyCreationUsages(all_public_usages
| all_private_usages
,
155 combined_usages
, true);
156 if (status
.IsError())
159 *public_usages
= combined_usages
& all_public_usages
;
160 *private_usages
= combined_usages
& all_private_usages
;
162 if (*private_usages
== 0)
163 return Status::ErrorCreateKeyEmptyUsages();
165 return Status::Success();
168 } // namespace webcrypto