@@ -290,6 +290,36 @@ if (hasOpenSSL(3, 2)) {
290290 } ) ) ;
291291}
292292
293+ // --- Async (callback) error handling ---
294+ {
295+ // Non-signing key type error is delivered via callback
296+ const x25519Priv = fixtures . readKey ( 'x25519_private.pem' , 'ascii' ) ;
297+ crypto . signDigest ( 'sha256' , Buffer . alloc ( 32 ) , x25519Priv , common . mustCall ( ( err ) => {
298+ assert ( err ) ;
299+ assert . match ( err . message , / o p e r a t i o n n o t s u p p o r t e d f o r t h i s k e y t y p e / ) ;
300+ } ) ) ;
301+ }
302+
303+ if ( hasOpenSSL ( 3 , 2 ) ) {
304+ // Wrong digest length error is delivered via callback
305+ const edPrivKey = fixtures . readKey ( 'ed25519_private.pem' , 'ascii' ) ;
306+ crypto . signDigest ( null , Buffer . alloc ( 32 ) , edPrivKey , common . mustCall ( ( err ) => {
307+ assert ( err ) ;
308+ assert . match ( err . message , / i n v a l i d d i g e s t l e n g t h / ) ;
309+ } ) ) ;
310+ }
311+
312+ if ( hasOpenSSL ( 3 , 5 ) ) {
313+ // PrehashUnsupported error is delivered via callback
314+ const mldsaPrivKey = fixtures . readKey ( 'ml_dsa_44_private.pem' , 'ascii' ) ;
315+ crypto . signDigest ( null , Buffer . alloc ( 32 ) , mldsaPrivKey , common . mustCall ( ( err ) => {
316+ assert ( err ) ;
317+ // TODO(@panva): revisit how to make CryptoJob async failures retain
318+ // and decorate OpenSSL errors.
319+ assert . match ( err . message , / D e r i v i n g b i t s f a i l e d / ) ;
320+ } ) ) ;
321+ }
322+
293323// --- Error: unsupported key type for prehashed signing ---
294324{
295325 // ML-DSA keys are one-shot-only and don't support prehashed signing.
@@ -350,6 +380,60 @@ if (hasOpenSSL(3, 2)) {
350380 } , { code : 'ERR_CRYPTO_INVALID_DIGEST' } ) ;
351381}
352382
383+ // --- Error: string inputs are rejected (digest must be binary) ---
384+ {
385+ const privKey = fixtures . readKey ( 'rsa_private_2048.pem' , 'ascii' ) ;
386+ const pubKey = fixtures . readKey ( 'rsa_public_2048.pem' , 'ascii' ) ;
387+
388+ // 64-byte string (same length as a SHA-512 digest)
389+ const strDigest64 = 'a' . repeat ( 64 ) ;
390+ assert . throws ( ( ) => {
391+ crypto . signDigest ( 'sha256' , strDigest64 , privKey ) ;
392+ } , { code : 'ERR_INVALID_ARG_TYPE' } ) ;
393+
394+ assert . throws ( ( ) => {
395+ crypto . verifyDigest ( 'sha256' , strDigest64 , pubKey , Buffer . alloc ( 256 ) ) ;
396+ } , { code : 'ERR_INVALID_ARG_TYPE' } ) ;
397+
398+ // 128-byte string
399+ const strDigest128 = 'b' . repeat ( 128 ) ;
400+ assert . throws ( ( ) => {
401+ crypto . signDigest ( 'sha256' , strDigest128 , privKey ) ;
402+ } , { code : 'ERR_INVALID_ARG_TYPE' } ) ;
403+
404+ assert . throws ( ( ) => {
405+ crypto . verifyDigest ( 'sha256' , strDigest128 , pubKey , Buffer . alloc ( 256 ) ) ;
406+ } , { code : 'ERR_INVALID_ARG_TYPE' } ) ;
407+ }
408+
409+ // --- ECDSA: hash larger than curve order (cross-verify) ---
410+ // Using SHA-512 (64 bytes) with P-256 (32-byte order) and P-384 (48-byte order).
411+ // The digest is larger than the curve's order; ECDSA truncates it internally.
412+ {
413+ const curves = [
414+ { priv : 'ec_p256_private.pem' , pub : 'ec_p256_public.pem' } ,
415+ { priv : 'ec_p384_private.pem' , pub : 'ec_p384_public.pem' } ,
416+ ] ;
417+
418+ for ( const { priv, pub } of curves ) {
419+ const privKey = fixtures . readKey ( priv , 'ascii' ) ;
420+ const pubKey = fixtures . readKey ( pub , 'ascii' ) ;
421+
422+ const digest = crypto . createHash ( 'sha512' ) . update ( data ) . digest ( ) ;
423+
424+ // signDigest + verifyDigest
425+ const sig = crypto . signDigest ( 'sha512' , digest , privKey ) ;
426+ assert . strictEqual ( crypto . verifyDigest ( 'sha512' , digest , pubKey , sig ) , true ) ;
427+
428+ // Cross-verify: sign with crypto.signDigest, verify with crypto.verify
429+ assert . strictEqual ( crypto . verify ( 'sha512' , data , pubKey , sig ) , true ) ;
430+
431+ // Cross-verify: sign with crypto.sign, verify with crypto.verifyDigest
432+ const sig2 = crypto . sign ( 'sha512' , data , privKey ) ;
433+ assert . strictEqual ( crypto . verifyDigest ( 'sha512' , digest , pubKey , sig2 ) , true ) ;
434+ }
435+ }
436+
353437// --- Error: wrong digest length for Ed25519ph/Ed448ph ---
354438if ( hasOpenSSL ( 3 , 2 ) ) {
355439 // Ed25519ph requires exactly 64-byte SHA-512 digest
@@ -367,4 +451,15 @@ if (hasOpenSSL(3, 2)) {
367451 crypto . signDigest ( null , Buffer . alloc ( 32 ) , privKey ) ;
368452 } , { code : 'ERR_OSSL_INVALID_DIGEST_LENGTH' } ) ;
369453 }
454+
455+ // Ed448ph rejects a valid 128-byte SHAKE256 digest (must be exactly 64 bytes)
456+ {
457+ const privKey = fixtures . readKey ( 'ed448_private.pem' , 'ascii' ) ;
458+ const shake256_128 = crypto . createHash ( 'shake256' , { outputLength : 128 } ) . update ( data ) . digest ( ) ;
459+ assert . strictEqual ( shake256_128 . length , 128 ) ;
460+
461+ assert . throws ( ( ) => {
462+ crypto . signDigest ( null , shake256_128 , privKey ) ;
463+ } , { code : 'ERR_OSSL_INVALID_DIGEST_LENGTH' } ) ;
464+ }
370465}
0 commit comments