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