5
5
//! - PKCS#11: https://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html
6
6
7
7
use anyhow:: Context ;
8
+ use asn1_rs:: BigInt ;
8
9
use asn1_rs:: FromDer as _;
10
+ use asn1_rs:: Integer ;
11
+ use asn1_rs:: SequenceOf ;
9
12
use asn1_rs:: ToDer ;
10
13
use camino:: Utf8PathBuf ;
11
14
use cryptoki:: context:: CInitializeArgs ;
@@ -397,19 +400,32 @@ impl Signer for PkcsSigner {
397
400
}
398
401
}
399
402
400
- fn format_asn1_ecdsa_signature ( r_bytes : & [ u8 ] , s_bytes : & [ u8 ] ) -> Result < Vec < u8 > , anyhow:: Error > {
401
- let mut writer = Vec :: new ( ) ;
402
-
403
- write_asn1_integer ( & mut writer, r_bytes) ;
404
-
405
- write_asn1_integer ( & mut writer, s_bytes) ;
406
-
407
- let seq = asn1_rs:: Sequence :: new ( writer. into ( ) ) ;
408
- let b = seq. to_der_vec ( ) . unwrap ( ) ;
409
- Ok ( b)
403
+ /// Formats the output of PKCS11 EC signature as an ASN.1 Ecdsa-Sig-Value.
404
+ ///
405
+ /// This function takes the raw `r` and `s` byte slices and encodes them as ASN.1 INTEGERs,
406
+ /// then wraps them in an ASN.1 SEQUENCE, and finally serializes the structure to DER.
407
+ ///
408
+ /// PKCS#11 EC signature operations typically return a raw concatenation of the `r` and `s` values,
409
+ /// each representing a big-endian positive integer of fixed length (depending on the curve).
410
+ /// However, most cryptographic protocols (including TLS and X.509) expect ECDSA signatures to be
411
+ /// encoded as an ASN.1 DER SEQUENCE of two INTEGERs, as described in RFC 3279 section 2.2.3.
412
+ ///
413
+ /// - https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.0/os/pkcs11-curr-v3.0-os.html#_Toc30061178
414
+ /// - https://www.ietf.org/rfc/rfc3279#section-2.2.3
415
+ fn format_asn1_ecdsa_signature ( r_bytes : & [ u8 ] , s_bytes : & [ u8 ] ) -> anyhow:: Result < Vec < u8 > > {
416
+ let r = format_asn1_integer ( r_bytes) . to_signed_bytes_be ( ) ;
417
+ let r = Integer :: new ( & r) ;
418
+ let s = format_asn1_integer ( s_bytes) . to_signed_bytes_be ( ) ;
419
+ let s = Integer :: new ( & s) ;
420
+
421
+ let seq = SequenceOf :: < Integer > :: from_iter ( [ r, s] ) ;
422
+ let seq_der = seq
423
+ . to_der_vec ( )
424
+ . context ( "Unexpected ASN.1 error when serializing Ecdsa-Sig-Value" ) ?;
425
+ Ok ( seq_der)
410
426
}
411
427
412
- fn write_asn1_integer ( writer : & mut dyn std :: io :: Write , b : & [ u8 ] ) {
428
+ fn format_asn1_integer ( b : & [ u8 ] ) -> BigInt {
413
429
let mut i = asn1_rs:: BigInt :: from_signed_bytes_be ( b) ;
414
430
if i. sign ( ) == asn1_rs:: Sign :: Minus {
415
431
// Prepend a most significant zero byte if value < 0
@@ -418,9 +434,7 @@ fn write_asn1_integer(writer: &mut dyn std::io::Write, b: &[u8]) {
418
434
419
435
i = asn1_rs:: BigInt :: from_signed_bytes_be ( & positive) ;
420
436
}
421
- let i = i. to_signed_bytes_be ( ) ;
422
- let i = asn1_rs:: Integer :: new ( & i) ;
423
- let _ = i. write_der ( writer) ;
437
+ i
424
438
}
425
439
426
440
fn get_ec_mechanism ( session : & Session , key : ObjectHandle ) -> anyhow:: Result < SigScheme > {
@@ -450,3 +464,34 @@ fn get_ec_mechanism(session: &Session, key: ObjectHandle) -> anyhow::Result<SigS
450
464
_ => anyhow:: bail!( "Parsed oID({oid}) doesn't match any supported EC curve" ) ,
451
465
}
452
466
}
467
+
468
+ #[ cfg( test) ]
469
+ mod tests {
470
+ use super :: * ;
471
+ use asn1_rs:: Any ;
472
+ use asn1_rs:: Integer ;
473
+ use asn1_rs:: SequenceOf ;
474
+
475
+ #[ test]
476
+ fn test_format_asn1_ecdsa_signature_invalid_asn1 ( ) {
477
+ // Use 32-byte r and s (as for P-256)
478
+ let r = [ 0x01u8 ; 32 ] ;
479
+ let s = [ 0xffu8 ; 32 ] ;
480
+
481
+ let der = format_asn1_ecdsa_signature ( & r, & s) . expect ( "Should encode" ) ;
482
+
483
+ // Try to parse as ASN.1 SEQUENCE of two INTEGERs
484
+ let parsed = Any :: from_der ( & der) ;
485
+ assert ! ( parsed. is_ok( ) , "Should parse as ASN.1" ) ;
486
+
487
+ // Now check that the sequence contains exactly two INTEGERs
488
+ let seq: SequenceOf < Integer > = SequenceOf :: from_der ( & der)
489
+ . expect ( "Should parse as sequence" )
490
+ . 1 ;
491
+ assert_eq ! ( seq. len( ) , 2 , "ASN.1 sequence should have two items" ) ;
492
+
493
+ // make sure input is not misinterpreted as negative numbers
494
+ assert_eq ! ( seq[ 0 ] . as_bigint( ) . to_bytes_be( ) . 1 , r) ;
495
+ assert_eq ! ( seq[ 1 ] . as_bigint( ) . to_bytes_be( ) . 1 , s) ;
496
+ }
497
+ }
0 commit comments