diff --git a/dfssc/cmd/sign.go b/dfssc/cmd/sign.go index 9aa3c4827cccaa5032d8783bfb9e3ebfa97a37a3..71e04985dc6e11c89e94e0a58688586b621aff21 100644 --- a/dfssc/cmd/sign.go +++ b/dfssc/cmd/sign.go @@ -26,6 +26,13 @@ var signCmd = &cobra.Command{ os.Exit(1) } + var contractPath string + readStringParam("Local contract path (empty means no verification)", "", &contractPath) + if !checkContractHash(contractPath, contract.File.Hash) { + fmt.Fprintln(os.Stderr, "Invalid contract file! Aborting.") + os.Exit(1) + } + var passphrase string _ = readPassword(&passphrase, false) @@ -33,7 +40,7 @@ var signCmd = &cobra.Command{ manager, err := sign.NewSignatureManager(passphrase, contract) if err != nil { fmt.Fprintln(os.Stderr, err) - os.Exit(2) + os.Exit(1) } fmt.Println("Waiting for peers...") @@ -41,7 +48,7 @@ var signCmd = &cobra.Command{ err = manager.ConnectToPeers() if err != nil { fmt.Fprintln(os.Stderr, err) - os.Exit(3) + os.Exit(1) } // Confirmation @@ -49,7 +56,7 @@ var signCmd = &cobra.Command{ readStringParam("Do you REALLY want to sign "+contract.File.Name+"? Type 'yes' to confirm", "", &ready) if ready != "yes" { fmt.Println("Signature aborted!") - os.Exit(4) + os.Exit(1) } // Ignition @@ -57,7 +64,7 @@ var signCmd = &cobra.Command{ signatureUUID, err := manager.SendReadySign() if err != nil { fmt.Fprintln(os.Stderr, err) - os.Exit(5) + os.Exit(1) } // TODO Warning, integration tests are checking Stdout @@ -68,20 +75,33 @@ var signCmd = &cobra.Command{ err = manager.Sign() if err != nil { fmt.Fprintln(os.Stderr, err) - os.Exit(5) + os.Exit(1) } // Persist evidencies, if any err = manager.PersistSignaturesToFile() if err != nil { fmt.Fprintln(os.Stderr, err) - os.Exit(5) + os.Exit(1) } fmt.Println("Signature complete! See .proof file for evidences.") }, } +func checkContractHash(filename string, expectedHash string) bool { + if filename == "" { + return true + } + + ok, err := sign.CheckContractHash(filename, expectedHash) + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + + return ok +} + func signFeedbackFn(mail string, status sign.SignerStatus, data string) { if status == sign.StatusConnecting { fmt.Println("- Trying to connect with", mail, "/", data) diff --git a/dfssc/sign/check.go b/dfssc/sign/check.go new file mode 100644 index 0000000000000000000000000000000000000000..bd0757e867c1bec6f02b89133fbc8cd5c0e5c68a --- /dev/null +++ b/dfssc/sign/check.go @@ -0,0 +1,25 @@ +package sign + +import ( + "bytes" + "crypto/sha512" + "encoding/hex" + "io/ioutil" +) + +// CheckContractHash computes the hash of the provided file and compares it to the expected one. +func CheckContractHash(filename string, expectedHash string) (ok bool, err error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + return + } + + expected, err := hex.DecodeString(expectedHash) + if err != nil { + return + } + + hash := sha512.Sum512(data) + ok = bytes.Equal(expected, hash[:]) + return +} diff --git a/tests/sign_test.go b/tests/sign_test.go index 0e43e8ea2bc7377d4812faf83f19ef93a87ef04d..af3bf2e9888c14687d8fd2fcb92a59a76e331803 100644 --- a/tests/sign_test.go +++ b/tests/sign_test.go @@ -56,9 +56,10 @@ func TestSignContract(t *testing.T) { // Create contract client1 = newClient(client1) setLastArg(client1, "new", true) + contractFilePath := filepath.Join("testdata", "contract.txt") client1.Stdin = strings.NewReader( "password\n" + - filepath.Join("testdata", "contract.txt") + "\n" + + contractFilePath + "\n" + "\n" + "client1@example.com\n" + "client2@example.com\n" + @@ -76,6 +77,14 @@ func TestSignContract(t *testing.T) { err = ioutil.WriteFile(contractPath, contractData, os.ModePerm) assert.Equal(t, nil, err) + // Test with wrong file, should abort + wrongFileClient := newClient(client1) + setLastArg(wrongFileClient, "sign", true) + setLastArg(wrongFileClient, contractPath, false) + wrongFileClient.Stdin = strings.NewReader("wrongfile.txt\npassword\nyes\n") + _, err = wrongFileClient.Output() + assert.NotNil(t, err) + // Sign! clients[0] = newClient(client1) clients[1] = newClient(client2) @@ -87,7 +96,7 @@ func TestSignContract(t *testing.T) { setLastArg(clients[i], contractPath, false) go func(c *exec.Cmd, i int) { time.Sleep(time.Duration(i*2) * time.Second) - c.Stdin = strings.NewReader("password\nyes\n") + c.Stdin = strings.NewReader(contractFilePath + "\npassword\nyes\n") c.Stderr = os.Stderr output, err1 := c.Output() if err1 != nil {