github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/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/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 TestPSSSigning(t *testing.T) { 193 var saltLengthCombinations = []struct { 194 signSaltLength, verifySaltLength int 195 good bool 196 }{ 197 {PSSSaltLengthAuto, PSSSaltLengthAuto, true}, 198 {PSSSaltLengthEqualsHash, PSSSaltLengthAuto, true}, 199 {PSSSaltLengthEqualsHash, PSSSaltLengthEqualsHash, true}, 200 {PSSSaltLengthEqualsHash, 8, false}, 201 {PSSSaltLengthAuto, PSSSaltLengthEqualsHash, false}, 202 {8, 8, true}, 203 } 204 205 hash := crypto.MD5 206 h := hash.New() 207 h.Write([]byte("testing")) 208 hashed := h.Sum(nil) 209 var opts PSSOptions 210 211 for i, test := range saltLengthCombinations { 212 opts.SaltLength = test.signSaltLength 213 sig, err := SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, &opts) 214 if err != nil { 215 t.Errorf("#%d: error while signing: %s", i, err) 216 continue 217 } 218 219 opts.SaltLength = test.verifySaltLength 220 err = VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, &opts) 221 if (err == nil) != test.good { 222 t.Errorf("#%d: bad result, wanted: %t, got: %s", i, test.good, err) 223 } 224 } 225 } 226 227 func bigFromHex(hex string) *big.Int { 228 n, ok := new(big.Int).SetString(hex, 16) 229 if !ok { 230 panic("bad hex: " + hex) 231 } 232 return n 233 } 234 235 func intFromHex(hex string) int { 236 i, err := strconv.ParseInt(hex, 16, 32) 237 if err != nil { 238 panic(err) 239 } 240 return int(i) 241 } 242 243 func fromHex(hexStr string) []byte { 244 s, err := hex.DecodeString(hexStr) 245 if err != nil { 246 panic(err) 247 } 248 return s 249 }