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