]> Cypherpunks.ru repositories - gostls13.git/blob - src/crypto/rsa/pss_test.go
[dev.boringcrypto] misc/boring: add new releases to RELEASES file
[gostls13.git] / src / crypto / rsa / pss_test.go
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         }
212
213         hash := crypto.SHA1
214         h := hash.New()
215         h.Write([]byte("testing"))
216         hashed := h.Sum(nil)
217         var opts PSSOptions
218
219         for i, test := range saltLengthCombinations {
220                 opts.SaltLength = test.signSaltLength
221                 sig, err := SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, &opts)
222                 if err != nil {
223                         t.Errorf("#%d: error while signing: %s", i, err)
224                         continue
225                 }
226
227                 opts.SaltLength = test.verifySaltLength
228                 err = VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, &opts)
229                 if (err == nil) != test.good {
230                         t.Errorf("#%d: bad result, wanted: %t, got: %s", i, test.good, err)
231                 }
232         }
233 }
234
235 func bigFromHex(hex string) *big.Int {
236         n, ok := new(big.Int).SetString(hex, 16)
237         if !ok {
238                 panic("bad hex: " + hex)
239         }
240         return n
241 }
242
243 func intFromHex(hex string) int {
244         i, err := strconv.ParseInt(hex, 16, 32)
245         if err != nil {
246                 panic(err)
247         }
248         return int(i)
249 }
250
251 func fromHex(hexStr string) []byte {
252         s, err := hex.DecodeString(hexStr)
253         if err != nil {
254                 panic(err)
255         }
256         return s
257 }