|
3 | 3 | #include "js-compute-builtins.h"
|
4 | 4 |
|
5 | 5 | namespace builtins {
|
| 6 | + |
| 7 | +namespace { |
| 8 | +void convertErrorToInvalidAccessError(JSContext *cx) { |
| 9 | + MOZ_ASSERT(JS_IsExceptionPending(cx)); |
| 10 | + JS::RootedValue exn(cx); |
| 11 | + if (!JS_GetPendingException(cx, &exn)) { |
| 12 | + return; |
| 13 | + } |
| 14 | + MOZ_ASSERT(exn.isObject()); |
| 15 | + JS::RootedObject error(cx, &exn.toObject()); |
| 16 | + JS::RootedValue name(cx, JS::StringValue(JS_NewStringCopyZ(cx, "InvalidAccessError"))); |
| 17 | + JS_SetProperty(cx, error, "name", name); |
| 18 | + JS::RootedValue code(cx, JS::NumberValue(15)); |
| 19 | + JS_SetProperty(cx, error, "code", code); |
| 20 | +} |
| 21 | +} // namespace |
6 | 22 | // digest(algorithm, data)
|
7 | 23 | // https://w3c.github.io/webcrypto/#SubtleCrypto-method-digest
|
8 | 24 | bool SubtleCrypto::digest(JSContext *cx, unsigned argc, JS::Value *vp) {
|
@@ -180,33 +196,27 @@ bool SubtleCrypto::sign(JSContext *cx, unsigned argc, JS::Value *vp) {
|
180 | 196 | // 1. Let algorithm and key be the algorithm and key parameters passed to the sign() method,
|
181 | 197 | // respectively.
|
182 | 198 | auto algorithm = args.get(0);
|
183 |
| - JS::RootedObject key(cx); |
184 |
| - { |
185 |
| - auto key_arg = args.get(1); |
186 |
| - if (!key_arg.isObject()) { |
187 |
| - JS_ReportErrorLatin1(cx, "parameter 2 is not of type 'CryptoKey'"); |
188 |
| - return ReturnPromiseRejectedWithPendingError(cx, args); |
189 |
| - } |
190 |
| - key.set(&key_arg.toObject()); |
191 |
| - if (!CryptoKey::is_instance(key)) { |
192 |
| - JS_ReportErrorLatin1(cx, "parameter 2 is not of type 'CryptoKey'"); |
193 |
| - return ReturnPromiseRejectedWithPendingError(cx, args); |
194 |
| - } |
| 199 | + auto key_arg = args.get(1); |
| 200 | + if (!key_arg.isObject()) { |
| 201 | + JS_ReportErrorLatin1(cx, "parameter 2 is not of type 'CryptoKey'"); |
| 202 | + return ReturnPromiseRejectedWithPendingError(cx, args); |
| 203 | + } |
| 204 | + JS::RootedObject key(cx, &key_arg.toObject()); |
| 205 | + if (!CryptoKey::is_instance(key)) { |
| 206 | + JS_ReportErrorLatin1(cx, "parameter 2 is not of type 'CryptoKey'"); |
| 207 | + return ReturnPromiseRejectedWithPendingError(cx, args); |
195 | 208 | }
|
196 | 209 |
|
197 | 210 | // 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to
|
198 | 211 | // the sign() method.
|
199 |
| - std::span<uint8_t> data; |
200 |
| - { |
201 |
| - std::optional<std::span<uint8_t>> dataOptional = |
202 |
| - value_to_buffer(cx, args.get(2), "SubtleCrypto.sign: data"); |
203 |
| - if (!dataOptional.has_value()) { |
204 |
| - // value_to_buffer would have already created a JS exception so we don't need to create one |
205 |
| - // ourselves. |
206 |
| - return ReturnPromiseRejectedWithPendingError(cx, args); |
207 |
| - } |
208 |
| - data = dataOptional.value(); |
| 212 | + std::optional<std::span<uint8_t>> dataOptional = |
| 213 | + value_to_buffer(cx, args.get(2), "SubtleCrypto.sign: data"); |
| 214 | + if (!dataOptional.has_value()) { |
| 215 | + // value_to_buffer would have already created a JS exception so we don't need to create one |
| 216 | + // ourselves. |
| 217 | + return ReturnPromiseRejectedWithPendingError(cx, args); |
209 | 218 | }
|
| 219 | + std::span<uint8_t> data = dataOptional.value(); |
210 | 220 |
|
211 | 221 | // 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm
|
212 | 222 | // and op set to "sign".
|
@@ -234,20 +244,21 @@ bool SubtleCrypto::sign(JSContext *cx, unsigned argc, JS::Value *vp) {
|
234 | 244 | auto match_result = CryptoKey::is_algorithm(cx, key, identifier);
|
235 | 245 | if (match_result.isErr()) {
|
236 | 246 | JS_ReportErrorUTF8(cx, "CryptoKey doesn't match AlgorithmIdentifier");
|
| 247 | + convertErrorToInvalidAccessError(cx); |
237 | 248 | return RejectPromiseWithPendingError(cx, promise);
|
238 | 249 | }
|
239 | 250 |
|
240 | 251 | if (match_result.unwrap() == false) {
|
241 |
| - // TODO: Change to an InvalidAccessError instance |
242 | 252 | JS_ReportErrorUTF8(cx, "CryptoKey doesn't match AlgorithmIdentifier");
|
| 253 | + convertErrorToInvalidAccessError(cx); |
243 | 254 | return RejectPromiseWithPendingError(cx, promise);
|
244 | 255 | }
|
245 | 256 |
|
246 | 257 | // 9. If the [[usages]] internal slot of key does not contain an entry that is "sign", then throw
|
247 | 258 | // an InvalidAccessError.
|
248 | 259 | if (!CryptoKey::canSign(key)) {
|
249 |
| - // TODO: Change to an InvalidAccessError instance |
250 | 260 | JS_ReportErrorLatin1(cx, "CryptoKey doesn't support signing");
|
| 261 | + convertErrorToInvalidAccessError(cx); |
251 | 262 | return RejectPromiseWithPendingError(cx, promise);
|
252 | 263 | }
|
253 | 264 |
|
@@ -284,20 +295,17 @@ bool SubtleCrypto::verify(JSContext *cx, unsigned argc, JS::Value *vp) {
|
284 | 295 | // 1. Let algorithm and key be the algorithm and key parameters passed to the verify() method,
|
285 | 296 | // respectively.
|
286 | 297 | auto algorithm = args.get(0);
|
287 |
| - JS::RootedObject key(cx); |
288 |
| - { |
289 |
| - auto key_arg = args.get(1); |
290 |
| - if (!key_arg.isObject()) { |
291 |
| - JS_ReportErrorLatin1(cx, "parameter 2 is not of type 'CryptoKey'"); |
292 |
| - return ReturnPromiseRejectedWithPendingError(cx, args); |
293 |
| - } |
294 |
| - key.set(&key_arg.toObject()); |
| 298 | + auto key_arg = args.get(1); |
| 299 | + if (!key_arg.isObject()) { |
| 300 | + JS_ReportErrorLatin1(cx, "parameter 2 is not of type 'CryptoKey'"); |
| 301 | + return ReturnPromiseRejectedWithPendingError(cx, args); |
| 302 | + } |
| 303 | + JS::RootedObject key(cx, &key_arg.toObject()); |
295 | 304 |
|
296 |
| - if (!CryptoKey::is_instance(key)) { |
297 |
| - JS_ReportErrorASCII( |
298 |
| - cx, "SubtleCrypto.verify: key (argument 2) does not implement interface CryptoKey"); |
299 |
| - return ReturnPromiseRejectedWithPendingError(cx, args); |
300 |
| - } |
| 305 | + if (!CryptoKey::is_instance(key)) { |
| 306 | + JS_ReportErrorASCII( |
| 307 | + cx, "SubtleCrypto.verify: key (argument 2) does not implement interface CryptoKey"); |
| 308 | + return ReturnPromiseRejectedWithPendingError(cx, args); |
301 | 309 | }
|
302 | 310 |
|
303 | 311 | // 2. Let signature be the result of getting a copy of the bytes held by the signature
|
@@ -341,15 +349,15 @@ bool SubtleCrypto::verify(JSContext *cx, unsigned argc, JS::Value *vp) {
|
341 | 349 | auto identifier = normalizedAlgorithm->identifier();
|
342 | 350 | auto match_result = CryptoKey::is_algorithm(cx, key, identifier);
|
343 | 351 | if (match_result.isErr() || match_result.unwrap() == false) {
|
344 |
| - // TODO: Change to an InvalidAccessError instance |
345 | 352 | JS_ReportErrorUTF8(cx, "CryptoKey doesn't match AlgorithmIdentifier");
|
| 353 | + convertErrorToInvalidAccessError(cx); |
346 | 354 | return RejectPromiseWithPendingError(cx, promise);
|
347 | 355 | }
|
348 | 356 | // 10. If the [[usages]] internal slot of key does not contain an entry that is "verify", then
|
349 | 357 | // throw an InvalidAccessError.
|
350 | 358 | if (!CryptoKey::canVerify(key)) {
|
351 |
| - // TODO: Change to an InvalidAccessError instance |
352 | 359 | JS_ReportErrorUTF8(cx, "CryptoKey doesn't support verification");
|
| 360 | + convertErrorToInvalidAccessError(cx); |
353 | 361 | return RejectPromiseWithPendingError(cx, promise);
|
354 | 362 | }
|
355 | 363 | // 11. Let result be the result of performing the verify operation specified by
|
|
0 commit comments