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  	"compress/bzip2"
    10  	"crypto"
    11  	"crypto/internal/fips140"
    12  	"crypto/rand"
    13  	. "crypto/rsa"
    14  	"crypto/sha256"
    15  	"crypto/sha512"
    16  	"encoding/hex"
    17  	"math/big"
    18  	"os"
    19  	"strconv"
    20  	"strings"
    21  	"testing"
    22  )
    23  
    24  // TestPSSGolden tests all the test vectors in pss-vect.txt from
    25  // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
    26  func TestPSSGolden(t *testing.T) {
    27  	inFile, err := os.Open("testdata/pss-vect.txt.bz2")
    28  	if err != nil {
    29  		t.Fatalf("Failed to open input file: %s", err)
    30  	}
    31  	defer inFile.Close()
    32  
    33  	// The pss-vect.txt file contains RSA keys and then a series of
    34  	// signatures. A goroutine is used to preprocess the input by merging
    35  	// lines, removing spaces in hex values and identifying the start of
    36  	// new keys and signature blocks.
    37  	const newKeyMarker = "START NEW KEY"
    38  	const newSignatureMarker = "START NEW SIGNATURE"
    39  
    40  	values := make(chan string)
    41  
    42  	go func() {
    43  		defer close(values)
    44  		scanner := bufio.NewScanner(bzip2.NewReader(inFile))
    45  		var partialValue string
    46  		lastWasValue := true
    47  
    48  		for scanner.Scan() {
    49  			line := scanner.Text()
    50  			switch {
    51  			case len(line) == 0:
    52  				if len(partialValue) > 0 {
    53  					values <- strings.ReplaceAll(partialValue, " ", "")
    54  					partialValue = ""
    55  					lastWasValue = true
    56  				}
    57  				continue
    58  			case strings.HasPrefix(line, "# ======") && lastWasValue:
    59  				values <- newKeyMarker
    60  				lastWasValue = false
    61  			case strings.HasPrefix(line, "# ------") && lastWasValue:
    62  				values <- newSignatureMarker
    63  				lastWasValue = false
    64  			case strings.HasPrefix(line, "#"):
    65  				continue
    66  			default:
    67  				partialValue += line
    68  			}
    69  		}
    70  		if err := scanner.Err(); err != nil {
    71  			panic(err)
    72  		}
    73  	}()
    74  
    75  	var key *PublicKey
    76  	var hashed []byte
    77  	hash := crypto.SHA1
    78  	h := hash.New()
    79  	opts := &PSSOptions{
    80  		SaltLength: PSSSaltLengthEqualsHash,
    81  	}
    82  
    83  	for marker := range values {
    84  		switch marker {
    85  		case newKeyMarker:
    86  			key = new(PublicKey)
    87  			nHex, ok := <-values
    88  			if !ok {
    89  				continue
    90  			}
    91  			key.N = bigFromHex(nHex)
    92  			key.E = intFromHex(<-values)
    93  			// We don't care for d, p, q, dP, dQ or qInv.
    94  			for i := 0; i < 6; i++ {
    95  				<-values
    96  			}
    97  		case newSignatureMarker:
    98  			msg := fromHex(<-values)
    99  			<-values // skip salt
   100  			sig := fromHex(<-values)
   101  
   102  			h.Reset()
   103  			h.Write(msg)
   104  			hashed = h.Sum(hashed[:0])
   105  
   106  			if err := VerifyPSS(key, hash, hashed, sig, opts); err != nil {
   107  				t.Error(err)
   108  			}
   109  		default:
   110  			t.Fatalf("unknown marker: %s", marker)
   111  		}
   112  	}
   113  }
   114  
   115  // TestPSSOpenSSL ensures that we can verify a PSS signature from OpenSSL with
   116  // the default options. OpenSSL sets the salt length to be maximal.
   117  func TestPSSOpenSSL(t *testing.T) {
   118  	t.Setenv("GODEBUG", "rsa1024min=0")
   119  
   120  	hash := crypto.SHA256
   121  	h := hash.New()
   122  	h.Write([]byte("testing"))
   123  	hashed := h.Sum(nil)
   124  
   125  	// Generated with `echo -n testing | openssl dgst -sign key.pem -sigopt rsa_padding_mode:pss -sha256 > sig`
   126  	sig := []byte{
   127  		0x95, 0x59, 0x6f, 0xd3, 0x10, 0xa2, 0xe7, 0xa2, 0x92, 0x9d,
   128  		0x4a, 0x07, 0x2e, 0x2b, 0x27, 0xcc, 0x06, 0xc2, 0x87, 0x2c,
   129  		0x52, 0xf0, 0x4a, 0xcc, 0x05, 0x94, 0xf2, 0xc3, 0x2e, 0x20,
   130  		0xd7, 0x3e, 0x66, 0x62, 0xb5, 0x95, 0x2b, 0xa3, 0x93, 0x9a,
   131  		0x66, 0x64, 0x25, 0xe0, 0x74, 0x66, 0x8c, 0x3e, 0x92, 0xeb,
   132  		0xc6, 0xe6, 0xc0, 0x44, 0xf3, 0xb4, 0xb4, 0x2e, 0x8c, 0x66,
   133  		0x0a, 0x37, 0x9c, 0x69,
   134  	}
   135  
   136  	if err := VerifyPSS(&test512Key.PublicKey, hash, hashed, sig, nil); err != nil {
   137  		t.Error(err)
   138  	}
   139  }
   140  
   141  func TestPSSNilOpts(t *testing.T) {
   142  	hash := crypto.SHA256
   143  	h := hash.New()
   144  	h.Write([]byte("testing"))
   145  	hashed := h.Sum(nil)
   146  
   147  	SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, nil)
   148  }
   149  
   150  func TestPSSSigning(t *testing.T) {
   151  	var saltLengthCombinations = []struct {
   152  		signSaltLength, verifySaltLength int
   153  		good, fipsGood                   bool
   154  	}{
   155  		{PSSSaltLengthAuto, PSSSaltLengthAuto, true, true},
   156  		{PSSSaltLengthEqualsHash, PSSSaltLengthAuto, true, true},
   157  		{PSSSaltLengthEqualsHash, PSSSaltLengthEqualsHash, true, true},
   158  		{PSSSaltLengthEqualsHash, 8, false, false},
   159  		{8, 8, true, true},
   160  		{8, PSSSaltLengthAuto, true, true},
   161  		{42, PSSSaltLengthAuto, true, true},
   162  		// In FIPS mode, PSSSaltLengthAuto is capped at PSSSaltLengthEqualsHash.
   163  		{PSSSaltLengthAuto, PSSSaltLengthEqualsHash, false, true},
   164  		{PSSSaltLengthAuto, 106, true, false},
   165  		{PSSSaltLengthAuto, 20, false, true},
   166  		{PSSSaltLengthAuto, -2, false, false},
   167  	}
   168  
   169  	hash := crypto.SHA1
   170  	h := hash.New()
   171  	h.Write([]byte("testing"))
   172  	hashed := h.Sum(nil)
   173  	var opts PSSOptions
   174  
   175  	for i, test := range saltLengthCombinations {
   176  		opts.SaltLength = test.signSaltLength
   177  		sig, err := SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, &opts)
   178  		if err != nil {
   179  			t.Errorf("#%d: error while signing: %s", i, err)
   180  			continue
   181  		}
   182  
   183  		opts.SaltLength = test.verifySaltLength
   184  		err = VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, &opts)
   185  		good := test.good
   186  		if fips140.Enabled {
   187  			good = test.fipsGood
   188  		}
   189  		if (err == nil) != good {
   190  			t.Errorf("#%d: bad result, wanted: %t, got: %s", i, test.good, err)
   191  		}
   192  	}
   193  }
   194  
   195  func TestPSS513(t *testing.T) {
   196  	// See Issue 42741, and separately, RFC 8017: "Note that the octet length of
   197  	// EM will be one less than k if modBits - 1 is divisible by 8 and equal to
   198  	// k otherwise, where k is the length in octets of the RSA modulus n."
   199  	t.Setenv("GODEBUG", "rsa1024min=0")
   200  	key, err := GenerateKey(rand.Reader, 513)
   201  	if err != nil {
   202  		t.Fatal(err)
   203  	}
   204  	digest := sha256.Sum256([]byte("message"))
   205  	signature, err := key.Sign(rand.Reader, digest[:], &PSSOptions{
   206  		SaltLength: PSSSaltLengthAuto,
   207  		Hash:       crypto.SHA256,
   208  	})
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  	err = VerifyPSS(&key.PublicKey, crypto.SHA256, digest[:], signature, nil)
   213  	if err != nil {
   214  		t.Error(err)
   215  	}
   216  }
   217  
   218  func bigFromHex(hex string) *big.Int {
   219  	n, ok := new(big.Int).SetString(hex, 16)
   220  	if !ok {
   221  		panic("bad hex: " + hex)
   222  	}
   223  	return n
   224  }
   225  
   226  func intFromHex(hex string) int {
   227  	i, err := strconv.ParseInt(hex, 16, 32)
   228  	if err != nil {
   229  		panic(err)
   230  	}
   231  	return int(i)
   232  }
   233  
   234  func fromHex(hexStr string) []byte {
   235  	s, err := hex.DecodeString(hexStr)
   236  	if err != nil {
   237  		panic(err)
   238  	}
   239  	return s
   240  }
   241  
   242  func TestInvalidPSSSaltLength(t *testing.T) {
   243  	t.Setenv("GODEBUG", "rsa1024min=0")
   244  	key, err := GenerateKey(rand.Reader, 245)
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	digest := sha256.Sum256([]byte("message"))
   250  	if _, err := SignPSS(rand.Reader, key, crypto.SHA256, digest[:], &PSSOptions{
   251  		SaltLength: -2,
   252  		Hash:       crypto.SHA256,
   253  	}); err.Error() != "crypto/rsa: invalid PSS salt length" {
   254  		t.Fatalf("SignPSS unexpected error: got %v, want %v", err, "crypto/rsa: invalid PSS salt length")
   255  	}
   256  
   257  	// We don't check the specific error here, because crypto/rsa and crypto/internal/boring
   258  	// return different errors, so we just check that _an error_ was returned.
   259  	if err := VerifyPSS(&key.PublicKey, crypto.SHA256, []byte{1, 2, 3}, make([]byte, 31), &PSSOptions{
   260  		SaltLength: -2,
   261  	}); err == nil {
   262  		t.Fatal("VerifyPSS unexpected success")
   263  	}
   264  }
   265  
   266  func TestHashOverride(t *testing.T) {
   267  	digest := sha512.Sum512([]byte("message"))
   268  	// opts.Hash overrides the passed hash argument.
   269  	sig, err := SignPSS(rand.Reader, test2048Key, crypto.SHA256, digest[:], &PSSOptions{Hash: crypto.SHA512})
   270  	if err != nil {
   271  		t.Fatalf("SignPSS unexpected error: got %v, want nil", err)
   272  	}
   273  
   274  	// VerifyPSS has the inverse behavior, opts.Hash is always ignored, check this is true.
   275  	if err := VerifyPSS(&test2048Key.PublicKey, crypto.SHA512, digest[:], sig, &PSSOptions{Hash: crypto.SHA256}); err != nil {
   276  		t.Fatalf("VerifyPSS unexpected error: got %v, want nil", err)
   277  	}
   278  }
   279  

View as plain text