github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/crypto/rsa/pss_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rsa 6 7 import ( 8 "bufio" 9 "bytes" 10 "compress/bzip2" 11 "crypto" 12 "crypto/rand" 13 "crypto/sha1" 14 "crypto/sha256" 15 "encoding/hex" 16 "math/big" 17 "os" 18 "strconv" 19 "strings" 20 "testing" 21 ) 22 23 func TestEMSAPSS(t *testing.T) { 24 // Test vector in file pss-int.txt from: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip 25 msg := []byte{ 26 0x85, 0x9e, 0xef, 0x2f, 0xd7, 0x8a, 0xca, 0x00, 0x30, 0x8b, 27 0xdc, 0x47, 0x11, 0x93, 0xbf, 0x55, 0xbf, 0x9d, 0x78, 0xdb, 28 0x8f, 0x8a, 0x67, 0x2b, 0x48, 0x46, 0x34, 0xf3, 0xc9, 0xc2, 29 0x6e, 0x64, 0x78, 0xae, 0x10, 0x26, 0x0f, 0xe0, 0xdd, 0x8c, 30 0x08, 0x2e, 0x53, 0xa5, 0x29, 0x3a, 0xf2, 0x17, 0x3c, 0xd5, 31 0x0c, 0x6d, 0x5d, 0x35, 0x4f, 0xeb, 0xf7, 0x8b, 0x26, 0x02, 32 0x1c, 0x25, 0xc0, 0x27, 0x12, 0xe7, 0x8c, 0xd4, 0x69, 0x4c, 33 0x9f, 0x46, 0x97, 0x77, 0xe4, 0x51, 0xe7, 0xf8, 0xe9, 0xe0, 34 0x4c, 0xd3, 0x73, 0x9c, 0x6b, 0xbf, 0xed, 0xae, 0x48, 0x7f, 35 0xb5, 0x56, 0x44, 0xe9, 0xca, 0x74, 0xff, 0x77, 0xa5, 0x3c, 36 0xb7, 0x29, 0x80, 0x2f, 0x6e, 0xd4, 0xa5, 0xff, 0xa8, 0xba, 37 0x15, 0x98, 0x90, 0xfc, 38 } 39 salt := []byte{ 40 0xe3, 0xb5, 0xd5, 0xd0, 0x02, 0xc1, 0xbc, 0xe5, 0x0c, 0x2b, 41 0x65, 0xef, 0x88, 0xa1, 0x88, 0xd8, 0x3b, 0xce, 0x7e, 0x61, 42 } 43 expected := []byte{ 44 0x66, 0xe4, 0x67, 0x2e, 0x83, 0x6a, 0xd1, 0x21, 0xba, 0x24, 45 0x4b, 0xed, 0x65, 0x76, 0xb8, 0x67, 0xd9, 0xa4, 0x47, 0xc2, 46 0x8a, 0x6e, 0x66, 0xa5, 0xb8, 0x7d, 0xee, 0x7f, 0xbc, 0x7e, 47 0x65, 0xaf, 0x50, 0x57, 0xf8, 0x6f, 0xae, 0x89, 0x84, 0xd9, 48 0xba, 0x7f, 0x96, 0x9a, 0xd6, 0xfe, 0x02, 0xa4, 0xd7, 0x5f, 49 0x74, 0x45, 0xfe, 0xfd, 0xd8, 0x5b, 0x6d, 0x3a, 0x47, 0x7c, 50 0x28, 0xd2, 0x4b, 0xa1, 0xe3, 0x75, 0x6f, 0x79, 0x2d, 0xd1, 51 0xdc, 0xe8, 0xca, 0x94, 0x44, 0x0e, 0xcb, 0x52, 0x79, 0xec, 52 0xd3, 0x18, 0x3a, 0x31, 0x1f, 0xc8, 0x96, 0xda, 0x1c, 0xb3, 53 0x93, 0x11, 0xaf, 0x37, 0xea, 0x4a, 0x75, 0xe2, 0x4b, 0xdb, 54 0xfd, 0x5c, 0x1d, 0xa0, 0xde, 0x7c, 0xec, 0xdf, 0x1a, 0x89, 55 0x6f, 0x9d, 0x8b, 0xc8, 0x16, 0xd9, 0x7c, 0xd7, 0xa2, 0xc4, 56 0x3b, 0xad, 0x54, 0x6f, 0xbe, 0x8c, 0xfe, 0xbc, 57 } 58 59 hash := sha1.New() 60 hash.Write(msg) 61 hashed := hash.Sum(nil) 62 63 encoded, err := emsaPSSEncode(hashed, 1023, salt, sha1.New()) 64 if err != nil { 65 t.Errorf("Error from emsaPSSEncode: %s\n", err) 66 } 67 if !bytes.Equal(encoded, expected) { 68 t.Errorf("Bad encoding. got %x, want %x", encoded, expected) 69 } 70 71 if err = emsaPSSVerify(hashed, encoded, 1023, len(salt), sha1.New()); err != nil { 72 t.Errorf("Bad verification: %s", err) 73 } 74 } 75 76 // TestPSSGolden tests all the test vectors in pss-vect.txt from 77 // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip 78 func TestPSSGolden(t *testing.T) { 79 inFile, err := os.Open("testdata/pss-vect.txt.bz2") 80 if err != nil { 81 t.Fatalf("Failed to open input file: %s", err) 82 } 83 defer inFile.Close() 84 85 // The pss-vect.txt file contains RSA keys and then a series of 86 // signatures. A goroutine is used to preprocess the input by merging 87 // lines, removing spaces in hex values and identifying the start of 88 // new keys and signature blocks. 89 const newKeyMarker = "START NEW KEY" 90 const newSignatureMarker = "START NEW SIGNATURE" 91 92 values := make(chan string) 93 94 go func() { 95 defer close(values) 96 scanner := bufio.NewScanner(bzip2.NewReader(inFile)) 97 var partialValue string 98 lastWasValue := true 99 100 for scanner.Scan() { 101 line := scanner.Text() 102 switch { 103 case len(line) == 0: 104 if len(partialValue) > 0 { 105 values <- strings.ReplaceAll(partialValue, " ", "") 106 partialValue = "" 107 lastWasValue = true 108 } 109 continue 110 case strings.HasPrefix(line, "# ======") && lastWasValue: 111 values <- newKeyMarker 112 lastWasValue = false 113 case strings.HasPrefix(line, "# ------") && lastWasValue: 114 values <- newSignatureMarker 115 lastWasValue = false 116 case strings.HasPrefix(line, "#"): 117 continue 118 default: 119 partialValue += line 120 } 121 } 122 if err := scanner.Err(); err != nil { 123 panic(err) 124 } 125 }() 126 127 var key *PublicKey 128 var hashed []byte 129 hash := crypto.SHA1 130 h := hash.New() 131 opts := &PSSOptions{ 132 SaltLength: PSSSaltLengthEqualsHash, 133 } 134 135 for marker := range values { 136 switch marker { 137 case newKeyMarker: 138 key = new(PublicKey) 139 nHex, ok := <-values 140 if !ok { 141 continue 142 } 143 key.N = bigFromHex(nHex) 144 key.E = intFromHex(<-values) 145 // We don't care for d, p, q, dP, dQ or qInv. 146 for i := 0; i < 6; i++ { 147 <-values 148 } 149 case newSignatureMarker: 150 msg := fromHex(<-values) 151 <-values // skip salt 152 sig := fromHex(<-values) 153 154 h.Reset() 155 h.Write(msg) 156 hashed = h.Sum(hashed[:0]) 157 158 if err := VerifyPSS(key, hash, hashed, sig, opts); err != nil { 159 t.Error(err) 160 } 161 default: 162 t.Fatalf("unknown marker: " + marker) 163 } 164 } 165 } 166 167 // TestPSSOpenSSL ensures that we can verify a PSS signature from OpenSSL with 168 // the default options. OpenSSL sets the salt length to be maximal. 169 func TestPSSOpenSSL(t *testing.T) { 170 hash := crypto.SHA256 171 h := hash.New() 172 h.Write([]byte("testing")) 173 hashed := h.Sum(nil) 174 175 // Generated with `echo -n testing | openssl dgst -sign key.pem -sigopt rsa_padding_mode:pss -sha256 > sig` 176 sig := []byte{ 177 0x95, 0x59, 0x6f, 0xd3, 0x10, 0xa2, 0xe7, 0xa2, 0x92, 0x9d, 178 0x4a, 0x07, 0x2e, 0x2b, 0x27, 0xcc, 0x06, 0xc2, 0x87, 0x2c, 179 0x52, 0xf0, 0x4a, 0xcc, 0x05, 0x94, 0xf2, 0xc3, 0x2e, 0x20, 180 0xd7, 0x3e, 0x66, 0x62, 0xb5, 0x95, 0x2b, 0xa3, 0x93, 0x9a, 181 0x66, 0x64, 0x25, 0xe0, 0x74, 0x66, 0x8c, 0x3e, 0x92, 0xeb, 182 0xc6, 0xe6, 0xc0, 0x44, 0xf3, 0xb4, 0xb4, 0x2e, 0x8c, 0x66, 183 0x0a, 0x37, 0x9c, 0x69, 184 } 185 186 if err := VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, nil); err != nil { 187 t.Error(err) 188 } 189 } 190 191 func TestPSSNilOpts(t *testing.T) { 192 hash := crypto.SHA256 193 h := hash.New() 194 h.Write([]byte("testing")) 195 hashed := h.Sum(nil) 196 197 SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, nil) 198 } 199 200 func TestPSSSigning(t *testing.T) { 201 var saltLengthCombinations = []struct { 202 signSaltLength, verifySaltLength int 203 good bool 204 }{ 205 {PSSSaltLengthAuto, PSSSaltLengthAuto, true}, 206 {PSSSaltLengthEqualsHash, PSSSaltLengthAuto, true}, 207 {PSSSaltLengthEqualsHash, PSSSaltLengthEqualsHash, true}, 208 {PSSSaltLengthEqualsHash, 8, false}, 209 {PSSSaltLengthAuto, PSSSaltLengthEqualsHash, false}, 210 {8, 8, true}, 211 {PSSSaltLengthAuto, 42, true}, 212 {PSSSaltLengthAuto, 20, false}, 213 {PSSSaltLengthAuto, -2, false}, 214 } 215 216 hash := crypto.SHA1 217 h := hash.New() 218 h.Write([]byte("testing")) 219 hashed := h.Sum(nil) 220 var opts PSSOptions 221 222 for i, test := range saltLengthCombinations { 223 opts.SaltLength = test.signSaltLength 224 sig, err := SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, &opts) 225 if err != nil { 226 t.Errorf("#%d: error while signing: %s", i, err) 227 continue 228 } 229 230 opts.SaltLength = test.verifySaltLength 231 err = VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, &opts) 232 if (err == nil) != test.good { 233 t.Errorf("#%d: bad result, wanted: %t, got: %s", i, test.good, err) 234 } 235 } 236 } 237 238 func TestSignWithPSSSaltLengthAuto(t *testing.T) { 239 key, err := GenerateKey(rand.Reader, 513) 240 if err != nil { 241 t.Fatal(err) 242 } 243 digest := sha256.Sum256([]byte("message")) 244 signature, err := key.Sign(rand.Reader, digest[:], &PSSOptions{ 245 SaltLength: PSSSaltLengthAuto, 246 Hash: crypto.SHA256, 247 }) 248 if err != nil { 249 t.Fatal(err) 250 } 251 if len(signature) == 0 { 252 t.Fatal("empty signature returned") 253 } 254 } 255 256 func bigFromHex(hex string) *big.Int { 257 n, ok := new(big.Int).SetString(hex, 16) 258 if !ok { 259 panic("bad hex: " + hex) 260 } 261 return n 262 } 263 264 func intFromHex(hex string) int { 265 i, err := strconv.ParseInt(hex, 16, 32) 266 if err != nil { 267 panic(err) 268 } 269 return int(i) 270 } 271 272 func fromHex(hexStr string) []byte { 273 s, err := hex.DecodeString(hexStr) 274 if err != nil { 275 panic(err) 276 } 277 return s 278 } 279 280 func TestInvalidPSSSaltLength(t *testing.T) { 281 key, err := GenerateKey(rand.Reader, 245) 282 if err != nil { 283 t.Fatal(err) 284 } 285 286 digest := sha256.Sum256([]byte("message")) 287 // We don't check the exact error matches, because crypto/rsa and crypto/internal/boring 288 // return two different error variables, which have the same content but are not equal. 289 if _, err := SignPSS(rand.Reader, key, crypto.SHA256, digest[:], &PSSOptions{ 290 SaltLength: -2, 291 Hash: crypto.SHA256, 292 }); err.Error() != invalidSaltLenErr.Error() { 293 t.Fatalf("SignPSS unexpected error: got %v, want %v", err, invalidSaltLenErr) 294 } 295 296 // We don't check the specific error here, because crypto/rsa and crypto/internal/boring 297 // return different errors, so we just check that _an error_ was returned. 298 if err := VerifyPSS(&key.PublicKey, crypto.SHA256, []byte{1, 2, 3}, make([]byte, 31), &PSSOptions{ 299 SaltLength: -2, 300 }); err == nil { 301 t.Fatal("VerifyPSS unexpected success") 302 } 303 }