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

View as plain text