Source file 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_test
     6  
     7  import (
     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  
    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.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: " + 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  		{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  
   239  func 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  
   261  func 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  
   269  func 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  
   277  func fromHex(hexStr string) []byte {
   278  	s, err := hex.DecodeString(hexStr)
   279  	if err != nil {
   280  		panic(err)
   281  	}
   282  	return s
   283  }
   284  
   285  func 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  

View as plain text