@@ -248,57 +248,61 @@ for (const test of TEST_CASES) { |
248 | 248 | // Test that create(De|C)ipheriv throws if the mode is CCM and an invalid |
249 | 249 | // authentication tag length has been specified. |
250 | 250 | { |
251 | | - for (const authTagLength of [-1, true, false, NaN, 5.5]) { |
252 | | - assert.throws(() => { |
253 | | - crypto.createCipheriv('aes-256-ccm', |
254 | | - 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
255 | | - 'qkuZpJWCewa6S', |
256 | | - { |
257 | | - authTagLength |
258 | | - }); |
259 | | - }, { |
260 | | - name: 'TypeError', |
261 | | - code: 'ERR_INVALID_ARG_VALUE', |
262 | | - message: "The property 'options.authTagLength' is invalid. " + |
263 | | - `Received ${inspect(authTagLength)}` |
264 | | - }); |
265 | | - |
266 | | - assert.throws(() => { |
267 | | - crypto.createDecipheriv('aes-256-ccm', |
| 251 | + if (!ciphers.includes('aes-256-ccm')) { |
| 252 | + common.printSkipMessage(`unsupported aes-256-ccm test`); |
| 253 | + } else { |
| 254 | + for (const authTagLength of [-1, true, false, NaN, 5.5]) { |
| 255 | + assert.throws(() => { |
| 256 | + crypto.createCipheriv('aes-256-ccm', |
268 | 257 | 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
269 | 258 | 'qkuZpJWCewa6S', |
270 | 259 | { |
271 | 260 | authTagLength |
272 | 261 | }); |
273 | | - }, { |
274 | | - name: 'TypeError', |
275 | | - code: 'ERR_INVALID_ARG_VALUE', |
276 | | - message: "The property 'options.authTagLength' is invalid. " + |
277 | | - `Received ${inspect(authTagLength)}` |
278 | | - }); |
279 | | - } |
280 | | - |
281 | | - // The following values will not be caught by the JS layer and thus will not |
282 | | - // use the default error codes. |
283 | | - for (const authTagLength of [0, 1, 2, 3, 5, 7, 9, 11, 13, 15, 17, 18]) { |
284 | | - assert.throws(() => { |
285 | | - crypto.createCipheriv('aes-256-ccm', |
286 | | - 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
287 | | - 'qkuZpJWCewa6S', |
288 | | - { |
289 | | - authTagLength |
290 | | - }); |
291 | | - }, errMessages.authTagLength); |
| 262 | + }, { |
| 263 | + name: 'TypeError', |
| 264 | + code: 'ERR_INVALID_ARG_VALUE', |
| 265 | + message: "The property 'options.authTagLength' is invalid. " + |
| 266 | + `Received ${inspect(authTagLength)}` |
| 267 | + }); |
292 | 268 |
|
293 | | - if (!isFipsEnabled) { |
294 | 269 | assert.throws(() => { |
295 | 270 | crypto.createDecipheriv('aes-256-ccm', |
296 | 271 | 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
297 | 272 | 'qkuZpJWCewa6S', |
298 | 273 | { |
299 | 274 | authTagLength |
300 | 275 | }); |
| 276 | + }, { |
| 277 | + name: 'TypeError', |
| 278 | + code: 'ERR_INVALID_ARG_VALUE', |
| 279 | + message: "The property 'options.authTagLength' is invalid. " + |
| 280 | + `Received ${inspect(authTagLength)}` |
| 281 | + }); |
| 282 | + } |
| 283 | + |
| 284 | + // The following values will not be caught by the JS layer and thus will not |
| 285 | + // use the default error codes. |
| 286 | + for (const authTagLength of [0, 1, 2, 3, 5, 7, 9, 11, 13, 15, 17, 18]) { |
| 287 | + assert.throws(() => { |
| 288 | + crypto.createCipheriv('aes-256-ccm', |
| 289 | + 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
| 290 | + 'qkuZpJWCewa6S', |
| 291 | + { |
| 292 | + authTagLength |
| 293 | + }); |
301 | 294 | }, errMessages.authTagLength); |
| 295 | + |
| 296 | + if (!isFipsEnabled) { |
| 297 | + assert.throws(() => { |
| 298 | + crypto.createDecipheriv('aes-256-ccm', |
| 299 | + 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
| 300 | + 'qkuZpJWCewa6S', |
| 301 | + { |
| 302 | + authTagLength |
| 303 | + }); |
| 304 | + }, errMessages.authTagLength); |
| 305 | + } |
302 | 306 | } |
303 | 307 | } |
304 | 308 | } |
@@ -307,6 +311,11 @@ for (const test of TEST_CASES) { |
307 | 311 | // authentication tag length has been specified. |
308 | 312 | { |
309 | 313 | for (const mode of ['ccm', 'ocb']) { |
| 314 | + if (!ciphers.includes(`aes-256-${mode}`)) { |
| 315 | + common.printSkipMessage(`unsupported aes-256-${mode} test`); |
| 316 | + continue; |
| 317 | + } |
| 318 | + |
310 | 319 | assert.throws(() => { |
311 | 320 | crypto.createCipheriv(`aes-256-${mode}`, |
312 | 321 | 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
@@ -330,84 +339,96 @@ for (const test of TEST_CASES) { |
330 | 339 |
|
331 | 340 | // Test that setAAD throws if an invalid plaintext length has been specified. |
332 | 341 | { |
333 | | - const cipher = crypto.createCipheriv('aes-256-ccm', |
334 | | - 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
335 | | - 'qkuZpJWCewa6S', |
336 | | - { |
337 | | - authTagLength: 10 |
338 | | - }); |
339 | | - |
340 | | - for (const plaintextLength of [-1, true, false, NaN, 5.5]) { |
341 | | - assert.throws(() => { |
342 | | - cipher.setAAD(Buffer.from('0123456789', 'hex'), { plaintextLength }); |
343 | | - }, { |
344 | | - name: 'TypeError', |
345 | | - code: 'ERR_INVALID_ARG_VALUE', |
346 | | - message: "The property 'options.plaintextLength' is invalid. " + |
347 | | - `Received ${inspect(plaintextLength)}` |
348 | | - }); |
| 342 | + if (!ciphers.includes('aes-256-ccm')) { |
| 343 | + common.printSkipMessage(`unsupported aes-256-ccm test`); |
| 344 | + } else { |
| 345 | + const cipher = crypto.createCipheriv('aes-256-ccm', |
| 346 | + 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
| 347 | + 'qkuZpJWCewa6S', |
| 348 | + { |
| 349 | + authTagLength: 10 |
| 350 | + }); |
| 351 | + |
| 352 | + for (const plaintextLength of [-1, true, false, NaN, 5.5]) { |
| 353 | + assert.throws(() => { |
| 354 | + cipher.setAAD(Buffer.from('0123456789', 'hex'), { plaintextLength }); |
| 355 | + }, { |
| 356 | + name: 'TypeError', |
| 357 | + code: 'ERR_INVALID_ARG_VALUE', |
| 358 | + message: "The property 'options.plaintextLength' is invalid. " + |
| 359 | + `Received ${inspect(plaintextLength)}` |
| 360 | + }); |
| 361 | + } |
349 | 362 | } |
350 | 363 | } |
351 | 364 |
|
352 | 365 | // Test that setAAD and update throw if the plaintext is too long. |
353 | 366 | { |
354 | | - for (const ivLength of [13, 12]) { |
355 | | - const maxMessageSize = (1 << (8 * (15 - ivLength))) - 1; |
356 | | - const key = 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8'; |
357 | | - const cipher = () => crypto.createCipheriv('aes-256-ccm', key, |
358 | | - '0'.repeat(ivLength), |
359 | | - { |
360 | | - authTagLength: 10 |
361 | | - }); |
| 367 | + if (!ciphers.includes('aes-256-ccm')) { |
| 368 | + common.printSkipMessage(`unsupported aes-256-ccm test`); |
| 369 | + } else { |
| 370 | + for (const ivLength of [13, 12]) { |
| 371 | + const maxMessageSize = (1 << (8 * (15 - ivLength))) - 1; |
| 372 | + const key = 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8'; |
| 373 | + const cipher = () => crypto.createCipheriv('aes-256-ccm', key, |
| 374 | + '0'.repeat(ivLength), |
| 375 | + { |
| 376 | + authTagLength: 10 |
| 377 | + }); |
362 | 378 |
|
363 | | - assert.throws(() => { |
364 | | - cipher().setAAD(Buffer.alloc(0), { |
365 | | - plaintextLength: maxMessageSize + 1 |
366 | | - }); |
367 | | - }, /Invalid message length$/); |
| 379 | + assert.throws(() => { |
| 380 | + cipher().setAAD(Buffer.alloc(0), { |
| 381 | + plaintextLength: maxMessageSize + 1 |
| 382 | + }); |
| 383 | + }, /Invalid message length$/); |
368 | 384 |
|
369 | | - const msg = Buffer.alloc(maxMessageSize + 1); |
370 | | - assert.throws(() => { |
371 | | - cipher().update(msg); |
372 | | - }, /Invalid message length/); |
| 385 | + const msg = Buffer.alloc(maxMessageSize + 1); |
| 386 | + assert.throws(() => { |
| 387 | + cipher().update(msg); |
| 388 | + }, /Invalid message length/); |
373 | 389 |
|
374 | | - const c = cipher(); |
375 | | - c.setAAD(Buffer.alloc(0), { |
376 | | - plaintextLength: maxMessageSize |
377 | | - }); |
378 | | - c.update(msg.slice(1)); |
| 390 | + const c = cipher(); |
| 391 | + c.setAAD(Buffer.alloc(0), { |
| 392 | + plaintextLength: maxMessageSize |
| 393 | + }); |
| 394 | + c.update(msg.slice(1)); |
| 395 | + } |
379 | 396 | } |
380 | 397 | } |
381 | 398 |
|
382 | 399 | // Test that setAAD throws if the mode is CCM and the plaintext length has not |
383 | 400 | // been specified. |
384 | 401 | { |
385 | | - assert.throws(() => { |
386 | | - const cipher = crypto.createCipheriv('aes-256-ccm', |
387 | | - 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
388 | | - 'qkuZpJWCewa6S', |
389 | | - { |
390 | | - authTagLength: 10 |
391 | | - }); |
392 | | - cipher.setAAD(Buffer.from('0123456789', 'hex')); |
393 | | - }, /options\.plaintextLength required for CCM mode with AAD/); |
394 | | - |
395 | | - if (!isFipsEnabled) { |
| 402 | + if (!ciphers.includes('aes-256-ccm')) { |
| 403 | + common.printSkipMessage(`unsupported aes-256-ccm test`); |
| 404 | + } else { |
396 | 405 | assert.throws(() => { |
397 | | - const cipher = crypto.createDecipheriv('aes-256-ccm', |
398 | | - 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
399 | | - 'qkuZpJWCewa6S', |
400 | | - { |
401 | | - authTagLength: 10 |
402 | | - }); |
| 406 | + const cipher = crypto.createCipheriv('aes-256-ccm', |
| 407 | + 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
| 408 | + 'qkuZpJWCewa6S', |
| 409 | + { |
| 410 | + authTagLength: 10 |
| 411 | + }); |
403 | 412 | cipher.setAAD(Buffer.from('0123456789', 'hex')); |
404 | 413 | }, /options\.plaintextLength required for CCM mode with AAD/); |
| 414 | + |
| 415 | + if (!isFipsEnabled) { |
| 416 | + assert.throws(() => { |
| 417 | + const cipher = crypto.createDecipheriv('aes-256-ccm', |
| 418 | + 'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8', |
| 419 | + 'qkuZpJWCewa6S', |
| 420 | + { |
| 421 | + authTagLength: 10 |
| 422 | + }); |
| 423 | + cipher.setAAD(Buffer.from('0123456789', 'hex')); |
| 424 | + }, /options\.plaintextLength required for CCM mode with AAD/); |
| 425 | + } |
405 | 426 | } |
406 | 427 | } |
407 | 428 |
|
408 | 429 | // Test that final() throws in CCM mode when no authentication tag is provided. |
409 | 430 | { |
410 | | - if (!isFipsEnabled) { |
| 431 | + if (!isFipsEnabled && ciphers.includes('aes-128-ccm')) { |
411 | 432 | const key = Buffer.from('1ed2233fa2223ef5d7df08546049406c', 'hex'); |
412 | 433 | const iv = Buffer.from('7305220bca40d4c90e1791e9', 'hex'); |
413 | 434 | const ct = Buffer.from('8beba09d4d4d861f957d51c0794f4abf8030848e', 'hex'); |
@@ -439,12 +460,16 @@ for (const test of TEST_CASES) { |
439 | 460 |
|
440 | 461 | // Test that an IV length of 11 does not overflow max_message_size_. |
441 | 462 | { |
442 | | - const key = 'x'.repeat(16); |
443 | | - const iv = Buffer.from('112233445566778899aabb', 'hex'); |
444 | | - const options = { authTagLength: 8 }; |
445 | | - const encrypt = crypto.createCipheriv('aes-128-ccm', key, iv, options); |
446 | | - encrypt.update('boom'); // Should not throw 'Message exceeds maximum size'. |
447 | | - encrypt.final(); |
| 463 | + if (!ciphers.includes('aes-128-ccm')) { |
| 464 | + common.printSkipMessage(`unsupported aes-128-ccm test`); |
| 465 | + } else { |
| 466 | + const key = 'x'.repeat(16); |
| 467 | + const iv = Buffer.from('112233445566778899aabb', 'hex'); |
| 468 | + const options = { authTagLength: 8 }; |
| 469 | + const encrypt = crypto.createCipheriv('aes-128-ccm', key, iv, options); |
| 470 | + encrypt.update('boom'); // Should not throw 'Message exceeds maximum size'. |
| 471 | + encrypt.final(); |
| 472 | + } |
448 | 473 | } |
449 | 474 |
|
450 | 475 | // Test that the authentication tag can be set at any point before calling |
@@ -499,6 +524,11 @@ for (const test of TEST_CASES) { |
499 | 524 | } |
500 | 525 |
|
501 | 526 | for (const alg of ['aes-256-gcm', 'aes-256-ocb', 'chacha20-poly1305']) { |
| 527 | + if (!ciphers.includes(alg)) { |
| 528 | + common.printSkipMessage(`unsupported ${alg} test`); |
| 529 | + continue; |
| 530 | + } |
| 531 | + |
502 | 532 | for (const authTagLength of alg === 'aes-256-gcm' ? [undefined, 8] : [8]) { |
503 | 533 | for (const [useAAD, useMessage] of [ |
504 | 534 | [false, false], // No AAD, no update. |
@@ -520,6 +550,11 @@ for (const test of TEST_CASES) { |
520 | 550 | const opts = { authTagLength: 8 }; |
521 | 551 |
|
522 | 552 | for (const mode of ['gcm', 'ccm', 'ocb']) { |
| 553 | + if (!ciphers.includes(`aes-128-${mode}`)) { |
| 554 | + common.printSkipMessage(`unsupported aes-128-${mode} test`); |
| 555 | + continue; |
| 556 | + } |
| 557 | + |
523 | 558 | const cipher = crypto.createCipheriv(`aes-128-${mode}`, key, iv, opts); |
524 | 559 | const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]); |
525 | 560 | const tag = cipher.getAuthTag(); |
@@ -563,25 +598,29 @@ for (const test of TEST_CASES) { |
563 | 598 | tampered: false, |
564 | 599 | }; |
565 | 600 |
|
566 | | - // Invalid IV lengths should be detected: |
567 | | - // - 12 and below are valid. |
568 | | - // - 13-16 are not detected as invalid by some OpenSSL versions. |
569 | | - check(13); |
570 | | - check(14); |
571 | | - check(15); |
572 | | - check(16); |
573 | | - // - 17 and above were always detected as invalid by OpenSSL. |
574 | | - check(17); |
575 | | - |
576 | | - function check(ivLength) { |
577 | | - const prefix = ivLength - valid.iv.length / 2; |
578 | | - assert.throws(() => crypto.createCipheriv( |
579 | | - valid.algo, |
580 | | - Buffer.from(valid.key, 'hex'), |
581 | | - Buffer.from(H(prefix) + valid.iv, 'hex') |
582 | | - ), errMessages.length, `iv length ${ivLength} was not rejected`); |
583 | | - |
584 | | - function H(length) { return '00'.repeat(length); } |
| 601 | + if (!ciphers.includes(valid.algo)) { |
| 602 | + common.printSkipMessage(`unsupported ${valid.algo} test`); |
| 603 | + } else { |
| 604 | + // Invalid IV lengths should be detected: |
| 605 | + // - 12 and below are valid. |
| 606 | + // - 13-16 are not detected as invalid by some OpenSSL versions. |
| 607 | + check(13); |
| 608 | + check(14); |
| 609 | + check(15); |
| 610 | + check(16); |
| 611 | + // - 17 and above were always detected as invalid by OpenSSL. |
| 612 | + check(17); |
| 613 | + |
| 614 | + function check(ivLength) { |
| 615 | + const prefix = ivLength - valid.iv.length / 2; |
| 616 | + assert.throws(() => crypto.createCipheriv( |
| 617 | + valid.algo, |
| 618 | + Buffer.from(valid.key, 'hex'), |
| 619 | + Buffer.from(H(prefix) + valid.iv, 'hex') |
| 620 | + ), errMessages.length, `iv length ${ivLength} was not rejected`); |
| 621 | + |
| 622 | + function H(length) { return '00'.repeat(length); } |
| 623 | + } |
585 | 624 | } |
586 | 625 | } |
587 | 626 |
|
|