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
6
7import (
8	"bufio"
9	"bytes"
10	"compress/bzip2"
11	"crypto"
12	_ "crypto/md5"
13	"crypto/rand"
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.Replace(partialValue, " ", "", -1)
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: " + 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	}
213
214	hash := crypto.MD5
215	h := hash.New()
216	h.Write([]byte("testing"))
217	hashed := h.Sum(nil)
218	var opts PSSOptions
219
220	for i, test := range saltLengthCombinations {
221		opts.SaltLength = test.signSaltLength
222		sig, err := SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, &opts)
223		if err != nil {
224			t.Errorf("#%d: error while signing: %s", i, err)
225			continue
226		}
227
228		opts.SaltLength = test.verifySaltLength
229		err = VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, &opts)
230		if (err == nil) != test.good {
231			t.Errorf("#%d: bad result, wanted: %t, got: %s", i, test.good, err)
232		}
233	}
234}
235
236func bigFromHex(hex string) *big.Int {
237	n, ok := new(big.Int).SetString(hex, 16)
238	if !ok {
239		panic("bad hex: " + hex)
240	}
241	return n
242}
243
244func intFromHex(hex string) int64 {
245	i, err := strconv.ParseInt(hex, 16, 64)
246	if err != nil {
247		panic(err)
248	}
249	return int64(i)
250}
251
252func fromHex(hexStr string) []byte {
253	s, err := hex.DecodeString(hexStr)
254	if err != nil {
255		panic(err)
256	}
257	return s
258}
259