Home | History | Annotate | Download | only in rsa
      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/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 
     24 func 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
     79 func 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.
    170 func 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 
    192 func 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 
    201 func 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 
    236 func 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 
    244 func intFromHex(hex string) int {
    245 	i, err := strconv.ParseInt(hex, 16, 32)
    246 	if err != nil {
    247 		panic(err)
    248 	}
    249 	return int(i)
    250 }
    251 
    252 func fromHex(hexStr string) []byte {
    253 	s, err := hex.DecodeString(hexStr)
    254 	if err != nil {
    255 		panic(err)
    256 	}
    257 	return s
    258 }
    259