@@ -3,11 +3,13 @@ package httpsign
33import (
44 "bufio"
55 "bytes"
6+ "crypto"
67 "crypto/ecdsa"
78 "crypto/ed25519"
89 "crypto/elliptic"
910 "crypto/rand"
1011 "crypto/rsa"
12+ "crypto/sha512"
1113 "crypto/x509"
1214 "crypto/x509/pkix"
1315 "encoding/asn1"
@@ -1036,6 +1038,85 @@ func TestMessageSignAndVerifyRSAPSS(t *testing.T) {
10361038 }
10371039}
10381040
1041+ // TestRSAPSSSaltLength verifies that RSA-PSS signatures use the correct salt length
1042+ // (64 bytes for SHA-512) as required by RFC 9421 Section 3.3.1
1043+ func TestRSAPSSSaltLength (t * testing.T ) {
1044+ prvKey , err := loadRSAPSSPrivateKey (rsaPSSPrvKey )
1045+ if err != nil {
1046+ t .Fatalf ("cannot read private key: %v" , err )
1047+ }
1048+ pubKey , err := parseRsaPublicKeyFromPemStr (rsaPSSPubKey )
1049+ if err != nil {
1050+ t .Fatalf ("cannot read public key: %v" , err )
1051+ }
1052+
1053+ config := NewSignConfig ().SetKeyID ("test-key-rsa-pss" )
1054+ fields := Headers ("@authority" , "date" )
1055+ signer , err := NewRSAPSSSigner (* prvKey , config , fields )
1056+ assert .NoError (t , err , "failed to create signer" )
1057+
1058+ // Use the internal sign method directly on test data
1059+ testData := []byte ("test signature base for salt length verification" )
1060+ sigBytes , err := signer .sign (testData )
1061+ assert .NoError (t , err , "signing failed" )
1062+
1063+ // Hash the test data
1064+ hashed := sha512 .Sum512 (testData )
1065+
1066+ // Verify with explicit PSSSaltLengthEqualsHash (64 bytes for SHA-512)
1067+ // If this succeeds, it proves our signer uses the correct salt length per RFC 9421
1068+ opts := & rsa.PSSOptions {SaltLength : rsa .PSSSaltLengthEqualsHash }
1069+ err = rsa .VerifyPSS (pubKey , crypto .SHA512 , hashed [:], sigBytes , opts )
1070+ assert .NoError (t , err , "signature should verify with 64-byte salt (PSSSaltLengthEqualsHash)" )
1071+
1072+ // Also verify that it would fail with wrong salt length expectation (e.g., 32 bytes)
1073+ optsWrong := & rsa.PSSOptions {SaltLength : 32 }
1074+ err = rsa .VerifyPSS (pubKey , crypto .SHA512 , hashed [:], sigBytes , optsWrong )
1075+ assert .Error (t , err , "signature should NOT verify with wrong salt length (32 bytes)" )
1076+
1077+ // Verify with PSSSaltLengthAuto should also work (it auto-detects)
1078+ err = rsa .VerifyPSS (pubKey , crypto .SHA512 , hashed [:], sigBytes , nil )
1079+ assert .NoError (t , err , "signature should verify with auto-detect (nil options)" )
1080+ }
1081+
1082+ // TestRSAPSSBackwardsCompatibility verifies that old signatures (created with PSSSaltLengthAuto,
1083+ // ~190 bytes of salt) can still be verified by the current verifier
1084+ func TestRSAPSSBackwardsCompatibility (t * testing.T ) {
1085+ prvKey , err := loadRSAPSSPrivateKey (rsaPSSPrvKey )
1086+ if err != nil {
1087+ t .Fatalf ("cannot read private key: %v" , err )
1088+ }
1089+ pubKey , err := parseRsaPublicKeyFromPemStr (rsaPSSPubKey )
1090+ if err != nil {
1091+ t .Fatalf ("cannot read public key: %v" , err )
1092+ }
1093+
1094+ // Simulate an "old" signature created with PSSSaltLengthAuto (maximum salt, ~190 bytes)
1095+ testData := []byte ("test signature base for backwards compatibility" )
1096+ hashed := sha512 .Sum512 (testData )
1097+
1098+ // Create a signature with PSSSaltLengthAuto (old behavior)
1099+ optsOld := & rsa.PSSOptions {SaltLength : rsa .PSSSaltLengthAuto }
1100+ oldSig , err := rsa .SignPSS (rand .Reader , prvKey , crypto .SHA512 , hashed [:], optsOld )
1101+ assert .NoError (t , err , "old-style signing should work" )
1102+
1103+ // Create a verifier using the current implementation
1104+ config := NewVerifyConfig ().SetKeyID ("test-key-rsa-pss" )
1105+ fields := Headers ("@authority" , "date" )
1106+ verifier , err := NewRSAPSSVerifier (* pubKey , config , fields )
1107+ assert .NoError (t , err , "failed to create verifier" )
1108+
1109+ // Verify the old signature using the verifier's internal method
1110+ // The verifier should accept it because it uses nil options (auto-detect)
1111+ success , err := verifier .verify (testData , oldSig )
1112+ assert .NoError (t , err , "old signature (with max salt ~190 bytes) should still verify" )
1113+ assert .True (t , success , "verification should succeed" )
1114+
1115+ // Also test with direct VerifyPSS using nil (auto-detect) - this is what the verifier uses
1116+ err = rsa .VerifyPSS (pubKey , crypto .SHA512 , hashed [:], oldSig , nil )
1117+ assert .NoError (t , err , "old signature should verify with auto-detect (nil options)" )
1118+ }
1119+
10391120func TestSignAndVerifyRSA (t * testing.T ) {
10401121 config := NewSignConfig ().SignAlg (false ).setFakeCreated (1618884475 ).SetKeyID ("test-key-rsa" )
10411122 fields := Headers ("@authority" , "date" , "content-type" )
0 commit comments