github.com/himawarisunflower/go-update@v0.0.0-20210917073417-3bee296db6a2/apply_test.go (about)

     1  package update
     2  
     3  import (
     4  	"bytes"
     5  	"crypto"
     6  	"crypto/rand"
     7  	"crypto/sha256"
     8  	"crypto/x509"
     9  	"encoding/pem"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"testing"
    14  
    15  	"github.com/inconshreveable/go-update/internal/binarydist"
    16  )
    17  
    18  var (
    19  	oldFile         = []byte{0xDE, 0xAD, 0xBE, 0xEF}
    20  	newFile         = []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
    21  	newFileChecksum = sha256.Sum256(newFile)
    22  )
    23  
    24  func cleanup(path string) {
    25  	os.Remove(path)
    26  	os.Remove(fmt.Sprintf(".%s.new", path))
    27  }
    28  
    29  // we write with a separate name for each test so that we can run them in parallel
    30  func writeOldFile(path string, t *testing.T) {
    31  	if err := ioutil.WriteFile(path, oldFile, 0777); err != nil {
    32  		t.Fatalf("Failed to write file for testing preparation: %v", err)
    33  	}
    34  }
    35  
    36  func validateUpdate(path string, err error, t *testing.T) {
    37  	if err != nil {
    38  		t.Fatalf("Failed to update: %v", err)
    39  	}
    40  
    41  	buf, err := ioutil.ReadFile(path)
    42  	if err != nil {
    43  		t.Fatalf("Failed to read file post-update: %v", err)
    44  	}
    45  
    46  	if !bytes.Equal(buf, newFile) {
    47  		t.Fatalf("File was not updated! Bytes read: %v, Bytes expected: %v", buf, newFile)
    48  	}
    49  }
    50  
    51  func TestApplySimple(t *testing.T) {
    52  	fName := "TestApplySimple"
    53  	defer cleanup(fName)
    54  	writeOldFile(fName, t)
    55  
    56  	err := Apply(bytes.NewReader(newFile), Options{
    57  		TargetPath: fName,
    58  	})
    59  	validateUpdate(fName, err, t)
    60  }
    61  
    62  func TestApplyOldSavePath(t *testing.T) {
    63  	fName := "TestApplyOldSavePath"
    64  	defer cleanup(fName)
    65  	writeOldFile(fName, t)
    66  
    67  	oldfName := "OldSavePath"
    68  
    69  	err := Apply(bytes.NewReader(newFile), Options{
    70  		TargetPath:  fName,
    71  		OldSavePath: oldfName,
    72  	})
    73  	validateUpdate(fName, err, t)
    74  
    75  	if _, err := os.Stat(oldfName); os.IsNotExist(err) {
    76  		t.Fatalf("Failed to find the old file: %v", err)
    77  	}
    78  
    79  	cleanup(oldfName)
    80  }
    81  
    82  func TestVerifyChecksum(t *testing.T) {
    83  	fName := "TestVerifyChecksum"
    84  	defer cleanup(fName)
    85  	writeOldFile(fName, t)
    86  
    87  	err := Apply(bytes.NewReader(newFile), Options{
    88  		TargetPath: fName,
    89  		Checksum:   newFileChecksum[:],
    90  	})
    91  	validateUpdate(fName, err, t)
    92  }
    93  
    94  func TestVerifyChecksumNegative(t *testing.T) {
    95  	fName := "TestVerifyChecksumNegative"
    96  	defer cleanup(fName)
    97  	writeOldFile(fName, t)
    98  
    99  	badChecksum := []byte{0x0A, 0x0B, 0x0C, 0xFF}
   100  	err := Apply(bytes.NewReader(newFile), Options{
   101  		TargetPath: fName,
   102  		Checksum:   badChecksum,
   103  	})
   104  	if err == nil {
   105  		t.Fatalf("Failed to detect bad checksum!")
   106  	}
   107  }
   108  
   109  func TestApplyPatch(t *testing.T) {
   110  	fName := "TestApplyPatch"
   111  	defer cleanup(fName)
   112  	writeOldFile(fName, t)
   113  
   114  	patch := new(bytes.Buffer)
   115  	err := binarydist.Diff(bytes.NewReader(oldFile), bytes.NewReader(newFile), patch)
   116  	if err != nil {
   117  		t.Fatalf("Failed to create patch: %v", err)
   118  	}
   119  
   120  	err = Apply(patch, Options{
   121  		TargetPath: fName,
   122  		Patcher:    NewBSDiffPatcher(),
   123  	})
   124  	validateUpdate(fName, err, t)
   125  }
   126  
   127  func TestCorruptPatch(t *testing.T) {
   128  	fName := "TestCorruptPatch"
   129  	defer cleanup(fName)
   130  	writeOldFile(fName, t)
   131  
   132  	badPatch := []byte{0x44, 0x38, 0x86, 0x3c, 0x4f, 0x8d, 0x26, 0x54, 0xb, 0x11, 0xce, 0xfe, 0xc1, 0xc0, 0xf8, 0x31, 0x38, 0xa0, 0x12, 0x1a, 0xa2, 0x57, 0x2a, 0xe1, 0x3a, 0x48, 0x62, 0x40, 0x2b, 0x81, 0x12, 0xb1, 0x21, 0xa5, 0x16, 0xed, 0x73, 0xd6, 0x54, 0x84, 0x29, 0xa6, 0xd6, 0xb2, 0x1b, 0xfb, 0xe6, 0xbe, 0x7b, 0x70}
   133  	err := Apply(bytes.NewReader(badPatch), Options{
   134  		TargetPath: fName,
   135  		Patcher:    NewBSDiffPatcher(),
   136  	})
   137  	if err == nil {
   138  		t.Fatalf("Failed to detect corrupt patch!")
   139  	}
   140  }
   141  
   142  func TestVerifyChecksumPatchNegative(t *testing.T) {
   143  	fName := "TestVerifyChecksumPatchNegative"
   144  	defer cleanup(fName)
   145  	writeOldFile(fName, t)
   146  
   147  	patch := new(bytes.Buffer)
   148  	anotherFile := []byte{0x77, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
   149  	err := binarydist.Diff(bytes.NewReader(oldFile), bytes.NewReader(anotherFile), patch)
   150  	if err != nil {
   151  		t.Fatalf("Failed to create patch: %v", err)
   152  	}
   153  
   154  	err = Apply(patch, Options{
   155  		TargetPath: fName,
   156  		Checksum:   newFileChecksum[:],
   157  		Patcher:    NewBSDiffPatcher(),
   158  	})
   159  	if err == nil {
   160  		t.Fatalf("Failed to detect patch to wrong file!")
   161  	}
   162  }
   163  
   164  const ecdsaPublicKey = `
   165  -----BEGIN PUBLIC KEY-----
   166  MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEL8ThbSyEucsCxnd4dCZR2hIy5nea54ko
   167  O+jUUfIjkvwhCWzASm0lpCVdVpXKZXIe+NZ+44RQRv3+OqJkCCGzUgJkPNI3lxdG
   168  9zu8rbrnxISV06VQ8No7Ei9wiTpqmTBB
   169  -----END PUBLIC KEY-----
   170  `
   171  
   172  const ecdsaPrivateKey = `
   173  -----BEGIN EC PRIVATE KEY-----
   174  MIGkAgEBBDBttCB/1NOY4T+WrG4FSV49Ayn3gK1DNzfGaJ01JUXeiNFCWQM2pqpU
   175  om8ATPP/dkegBwYFK4EEACKhZANiAAQvxOFtLIS5ywLGd3h0JlHaEjLmd5rniSg7
   176  6NRR8iOS/CEJbMBKbSWkJV1Wlcplch741n7jhFBG/f46omQIIbNSAmQ80jeXF0b3
   177  O7ytuufEhJXTpVDw2jsSL3CJOmqZMEE=
   178  -----END EC PRIVATE KEY-----
   179  `
   180  
   181  const rsaPublicKey = `
   182  -----BEGIN PUBLIC KEY-----
   183  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxSWmu7trWKAwDFjiCN2D
   184  Tk2jj2sgcr/CMlI4cSSiIOHrXCFxP1I8i9PvQkd4hasXQrLbT5WXKrRGv1HKUKab
   185  b9ead+kD0kxk7i2bFYvKX43oq66IW0mOLTQBO7I9UyT4L7svcMD+HUQ2BqHoaQe4
   186  y20C59dPr9Dpcz8DZkdLsBV6YKF6Ieb3iGk8oRLMWNaUqPa8f1BGgxAkvPHcqDjT
   187  x4xRnjgTRRRlZvRtALHMUkIChgxDOhoEzKpGiqnX7HtMJfrhV6h0PAXNA4h9Kjv5
   188  5fhJ08Rz7mmZmtH5JxTK5XTquo59sihSajR4bSjZbbkQ1uLkeFlY3eli3xdQ7Nrf
   189  fQIDAQAB
   190  -----END PUBLIC KEY-----`
   191  
   192  const rsaPrivateKey = `
   193  -----BEGIN RSA PRIVATE KEY-----
   194  MIIEogIBAAKCAQEAxSWmu7trWKAwDFjiCN2DTk2jj2sgcr/CMlI4cSSiIOHrXCFx
   195  P1I8i9PvQkd4hasXQrLbT5WXKrRGv1HKUKabb9ead+kD0kxk7i2bFYvKX43oq66I
   196  W0mOLTQBO7I9UyT4L7svcMD+HUQ2BqHoaQe4y20C59dPr9Dpcz8DZkdLsBV6YKF6
   197  Ieb3iGk8oRLMWNaUqPa8f1BGgxAkvPHcqDjTx4xRnjgTRRRlZvRtALHMUkIChgxD
   198  OhoEzKpGiqnX7HtMJfrhV6h0PAXNA4h9Kjv55fhJ08Rz7mmZmtH5JxTK5XTquo59
   199  sihSajR4bSjZbbkQ1uLkeFlY3eli3xdQ7NrffQIDAQABAoIBAAkN+6RvrTR61voa
   200  Mvd5RQiZpEN4Bht/Fyo8gH8h0Zh1B9xJZOwlmMZLS5fdtHlfLEhR8qSrGDBL61vq
   201  I8KkhEsUufF78EL+YzxVN+Q7cWYGHIOWFokqza7hzpSxUQO6lPOMQ1eIZaNueJTB
   202  Zu07/47ISPPg/bXzgGVcpYlTCPTjUwKjtfyMqvX9AD7fIyYRm6zfE7EHj1J2sBFt
   203  Yz1OGELg6HfJwXfpnPfBvftD0hWGzJ78Bp71fPJe6n5gnqmSqRvrcXNWFnH/yqkN
   204  d6vPIxD6Z3LjvyZpkA7JillLva2L/zcIFhg4HZvQnWd8/PpDnUDonu36hcj4SC5j
   205  W4aVPLkCgYEA4XzNKWxqYcajzFGZeSxlRHupSAl2MT7Cc5085MmE7dd31wK2T8O4
   206  n7N4bkm/rjTbX85NsfWdKtWb6mpp8W3VlLP0rp4a/12OicVOkg4pv9LZDmY0sRlE
   207  YuDJk1FeCZ50UrwTZI3rZ9IhZHhkgVA6uWAs7tYndONkxNHG0pjqs4sCgYEA39MZ
   208  JwMqo3qsPntpgP940cCLflEsjS9hYNO3+Sv8Dq3P0HLVhBYajJnotf8VuU0fsQZG
   209  grmtVn1yThFbMq7X1oY4F0XBA+paSiU18c4YyUnwax2u4sw9U/Q9tmQUZad5+ueT
   210  qriMBwGv+ewO+nQxqvAsMUmemrVzrfwA5Oct+hcCgYAfiyXoNZJsOy2O15twqBVC
   211  j0oPGcO+/9iT89sg5lACNbI+EdMPNYIOVTzzsL1v0VUfAe08h++Enn1BPcG0VHkc
   212  ZFBGXTfJoXzfKQrkw7ZzbzuOGB4m6DH44xlP0oIlNlVvfX/5ASF9VJf3RiBJNsAA
   213  TsP6ZVr/rw/ZuL7nlxy+IQKBgDhL/HOXlE3yOQiuOec8WsNHTs7C1BXe6PtVxVxi
   214  988pYK/pclL6zEq5G5NLSceF4obAMVQIJ9UtUGbabrncyGUo9UrFPLsjYvprSZo8
   215  YHegpVwL50UcYgCP2kXZ/ldjPIcjYDz8lhvdDMor2cidGTEJn9P11HLNWP9V91Ob
   216  4jCZAoGAPNRSC5cC8iP/9j+s2/kdkfWJiNaolPYAUrmrkL6H39PYYZM5tnhaIYJV
   217  Oh9AgABamU0eb3p3vXTISClVgV7ifq1HyZ7BSUhMfaY2Jk/s3sUHCWFxPZe9sgEG
   218  KinIY/373KIkIV/5g4h2v1w330IWcfptxKcY/Er3DJr38f695GE=
   219  -----END RSA PRIVATE KEY-----`
   220  
   221  func signec(privatePEM string, source []byte, t *testing.T) []byte {
   222  	parseFn := func(p []byte) (crypto.Signer, error) { return x509.ParseECPrivateKey(p) }
   223  	return sign(parseFn, privatePEM, source, t)
   224  }
   225  
   226  func signrsa(privatePEM string, source []byte, t *testing.T) []byte {
   227  	parseFn := func(p []byte) (crypto.Signer, error) { return x509.ParsePKCS1PrivateKey(p) }
   228  	return sign(parseFn, privatePEM, source, t)
   229  }
   230  
   231  func sign(parsePrivKey func([]byte) (crypto.Signer, error), privatePEM string, source []byte, t *testing.T) []byte {
   232  	block, _ := pem.Decode([]byte(privatePEM))
   233  	if block == nil {
   234  		t.Fatalf("Failed to parse private key PEM")
   235  	}
   236  
   237  	priv, err := parsePrivKey(block.Bytes)
   238  	if err != nil {
   239  		t.Fatalf("Failed to parse private key DER: %v", err)
   240  	}
   241  
   242  	checksum := sha256.Sum256(source)
   243  	sig, err := priv.Sign(rand.Reader, checksum[:], crypto.SHA256)
   244  	if err != nil {
   245  		t.Fatalf("Failed to sign: %v", sig)
   246  	}
   247  
   248  	return sig
   249  }
   250  
   251  func TestVerifyECSignature(t *testing.T) {
   252  	fName := "TestVerifyECSignature"
   253  	defer cleanup(fName)
   254  	writeOldFile(fName, t)
   255  
   256  	opts := Options{TargetPath: fName}
   257  	err := opts.SetPublicKeyPEM([]byte(ecdsaPublicKey))
   258  	if err != nil {
   259  		t.Fatalf("Could not parse public key: %v", err)
   260  	}
   261  
   262  	opts.Signature = signec(ecdsaPrivateKey, newFile, t)
   263  	err = Apply(bytes.NewReader(newFile), opts)
   264  	validateUpdate(fName, err, t)
   265  }
   266  
   267  func TestVerifyRSASignature(t *testing.T) {
   268  	fName := "TestVerifyRSASignature"
   269  	defer cleanup(fName)
   270  	writeOldFile(fName, t)
   271  
   272  	opts := Options{
   273  		TargetPath: fName,
   274  		Verifier:   NewRSAVerifier(),
   275  	}
   276  	err := opts.SetPublicKeyPEM([]byte(rsaPublicKey))
   277  	if err != nil {
   278  		t.Fatalf("Could not parse public key: %v", err)
   279  	}
   280  
   281  	opts.Signature = signrsa(rsaPrivateKey, newFile, t)
   282  	err = Apply(bytes.NewReader(newFile), opts)
   283  	validateUpdate(fName, err, t)
   284  }
   285  
   286  func TestVerifyFailBadSignature(t *testing.T) {
   287  	fName := "TestVerifyFailBadSignature"
   288  	defer cleanup(fName)
   289  	writeOldFile(fName, t)
   290  
   291  	opts := Options{
   292  		TargetPath: fName,
   293  		Signature:  []byte{0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA},
   294  	}
   295  	err := opts.SetPublicKeyPEM([]byte(ecdsaPublicKey))
   296  	if err != nil {
   297  		t.Fatalf("Could not parse public key: %v", err)
   298  	}
   299  
   300  	err = Apply(bytes.NewReader(newFile), opts)
   301  	if err == nil {
   302  		t.Fatalf("Did not fail with bad signature")
   303  	}
   304  }
   305  
   306  func TestVerifyFailNoSignature(t *testing.T) {
   307  	fName := "TestVerifySignatureWithPEM"
   308  	defer cleanup(fName)
   309  	writeOldFile(fName, t)
   310  
   311  	opts := Options{TargetPath: fName}
   312  	err := opts.SetPublicKeyPEM([]byte(ecdsaPublicKey))
   313  	if err != nil {
   314  		t.Fatalf("Could not parse public key: %v", err)
   315  	}
   316  
   317  	err = Apply(bytes.NewReader(newFile), opts)
   318  	if err == nil {
   319  		t.Fatalf("Did not fail with empty signature")
   320  	}
   321  }
   322  
   323  const wrongKey = `
   324  -----BEGIN EC PRIVATE KEY-----
   325  MIGkAgEBBDBzqYp6N2s8YWYifBjS03/fFfmGeIPcxQEi+bbFeekIYt8NIKIkhD+r
   326  hpaIwSmot+qgBwYFK4EEACKhZANiAAR0EC8Usbkc4k30frfEB2ECmsIghu9DJSqE
   327  RbH7jfq2ULNv8tN/clRjxf2YXgp+iP3SQF1R1EYERKpWr8I57pgfIZtoZXjwpbQC
   328  VBbP/Ff+05HOqwPC7rJMy1VAJLKg7Cw=
   329  -----END EC PRIVATE KEY-----
   330  `
   331  
   332  func TestVerifyFailWrongSignature(t *testing.T) {
   333  	fName := "TestVerifyFailWrongSignature"
   334  	defer cleanup(fName)
   335  	writeOldFile(fName, t)
   336  
   337  	opts := Options{TargetPath: fName}
   338  	err := opts.SetPublicKeyPEM([]byte(ecdsaPublicKey))
   339  	if err != nil {
   340  		t.Fatalf("Could not parse public key: %v", err)
   341  	}
   342  
   343  	opts.Signature = signec(wrongKey, newFile, t)
   344  	err = Apply(bytes.NewReader(newFile), opts)
   345  	if err == nil {
   346  		t.Fatalf("Verified an update that was signed by an untrusted key!")
   347  	}
   348  }
   349  
   350  func TestSignatureButNoPublicKey(t *testing.T) {
   351  	fName := "TestSignatureButNoPublicKey"
   352  	defer cleanup(fName)
   353  	writeOldFile(fName, t)
   354  
   355  	err := Apply(bytes.NewReader(newFile), Options{
   356  		TargetPath: fName,
   357  		Signature:  signec(ecdsaPrivateKey, newFile, t),
   358  	})
   359  	if err == nil {
   360  		t.Fatalf("Allowed an update with a signautre verification when no public key was specified!")
   361  	}
   362  }
   363  
   364  func TestPublicKeyButNoSignature(t *testing.T) {
   365  	fName := "TestPublicKeyButNoSignature"
   366  	defer cleanup(fName)
   367  	writeOldFile(fName, t)
   368  
   369  	opts := Options{TargetPath: fName}
   370  	if err := opts.SetPublicKeyPEM([]byte(ecdsaPublicKey)); err != nil {
   371  		t.Fatalf("Could not parse public key: %v", err)
   372  	}
   373  	err := Apply(bytes.NewReader(newFile), opts)
   374  	if err == nil {
   375  		t.Fatalf("Allowed an update with no signautre when a public key was specified!")
   376  	}
   377  }
   378  
   379  func TestWriteError(t *testing.T) {
   380  	fName := "TestWriteError"
   381  	defer cleanup(fName)
   382  	writeOldFile(fName, t)
   383  
   384  	openFile = func(name string, flags int, perm os.FileMode) (*os.File, error) {
   385  		f, err := os.OpenFile(name, flags, perm)
   386  
   387  		// simulate Write() error by closing the file prematurely
   388  		f.Close()
   389  
   390  		return f, err
   391  	}
   392  	defer func() {
   393  		openFile = os.OpenFile
   394  	}()
   395  
   396  	err := Apply(bytes.NewReader(newFile), Options{TargetPath: fName})
   397  	if err == nil {
   398  		t.Fatalf("Allowed an update to an empty file")
   399  	}
   400  }