diff --git a/cmd/timestamp-cli/app/verify.go b/cmd/timestamp-cli/app/verify.go index a920d53c..6a71b64d 100644 --- a/cmd/timestamp-cli/app/verify.go +++ b/cmd/timestamp-cli/app/verify.go @@ -20,6 +20,7 @@ import ( "crypto/x509" "errors" "fmt" + "hash" "os" "path/filepath" @@ -129,14 +130,18 @@ func verifyArtifactWithTSR(ts *timestamp.Timestamp) error { return err } - h := ts.HashAlgorithm.New() - _, err = h.Write(artifactBytes) + return verifyHashedMessages(ts.HashAlgorithm.New(), ts.HashedMessage, artifactBytes) +} + +func verifyHashedMessages(hashAlg hash.Hash, hashedMessage []byte, artifactBytes []byte) error { + h := hashAlg + _, err := h.Write(artifactBytes) if err != nil { return fmt.Errorf("Failed to create local message hash") } localHashedMsg := h.Sum(nil) - if !bytes.Equal(localHashedMsg, ts.HashedMessage) { + if !bytes.Equal(localHashedMsg, hashedMessage) { return fmt.Errorf("Hashed messages don't match") } diff --git a/cmd/timestamp-cli/app/verify_test.go b/cmd/timestamp-cli/app/verify_test.go new file mode 100644 index 00000000..e834a740 --- /dev/null +++ b/cmd/timestamp-cli/app/verify_test.go @@ -0,0 +1,86 @@ +// +// Copyright 2022 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package app + +import ( + "bytes" + "crypto" + "io" + "log" + "net/http" + "strings" + "testing" + + "github.com/digitorus/timestamp" +) + +func TestVerifyArtifactHashedMessages(t *testing.T) { + type test struct { + message string + } + + tests := []test{ + { + message: "valid local artifact", + }, + { + message: "nonexistant local artifact", + }, + { + message: "valid local artifact with hash algorithm", + }, + { + message: "valid oid", + }, + { + message: "MIIEbjADAgEAMIIEZQYJKoZIhvcNAQcCoIIEVjCCBFICAQExDTALBglghkgBZQMEAgEwgdQGCyqGSIb3DQEJEAEEoIHEBIHBMIG+AgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgN94hMnpq0onyUi7r1zJHNiLT1/spX8MU2GBN9AdMe6wCFQDS6RL1iVlmlkwJzmpS2EH0cuX8sxgTMjAyMjExMDMxNzQyNDIrMDEwMDADAgEBAhRKnQszZjzcgJkpE8LCbmbF0s1jPaA0pDIwMDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIFRpbWVzdGFtcGluZ6CCAckwggHFMIIBaqADAgECAhRHCu9dHKS97mFo1cH5neJubRibujAKBggqhkjOPQQDAjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQGA1UEAxMNVGVzdCBUU0EgUm9vdDAeFw0yMjExMDMxMTUzMThaFw0zMTExMDMxMTU2MThaMDAxDjAMBgNVBAoTBWxvY2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATo3W6NQrpx5D8z5IvgD2DlAgoJMF4KPY9Pj4UfFhfOq029ryszXp3460Z7N+x86bDvyjVrHaeiPnl1HO9Q52zso2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFHSIhDdTGIsodML/iUOhx7hgo/K7MB8GA1UdIwQYMBaAFBoZYijuouZCvKDtBd0eCyaU2HWoMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMCA0kAMEYCIQCmPVr5kwYe4Jg9PGO6apgfzSrKAtESgNHpAbE3iIvJhQIhAJIGNxshJcC8LXHRrVWM77no3d3GguSvR01OAPZwE2pqMYIBmDCCAZQCAQEwQDAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQGA1UEAxMNVGVzdCBUU0EgUm9vdAIURwrvXRykve5haNXB+Z3ibm0Ym7owCwYJYIZIAWUDBAIBoIHqMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjIxMTAzMTY0MjQyWjAvBgkqhkiG9w0BCQQxIgQgrKbkOizzGoAudPhAnW5Qny788Kcd++VQwPrCMhg4MTEwfQYLKoZIhvcNAQkQAi8xbjBsMGowaAQgXqxJD0nAgg6en9P1bRrU7+6tzxOMn3YThreg7uR6T7EwRDAspCowKDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QCFEcK710cpL3uYWjVwfmd4m5tGJu6MAoGCCqGSM49BAMCBEcwRQIgQkc2BxMjnUMzqBDYzUiw10LoCIZ9Zmp1E0Hl6E+9mzwCIQDp2lD826Du5Ss4pNG/TksDknTUJfKvrLc2ex+x+W3VHg==", + }, + } + + for _, tc := range tests { + tsq, err := timestamp.CreateRequest(strings.NewReader(tc.message), ×tamp.RequestOptions{ + Hash: crypto.SHA256, + Certificates: true, + }) + if err != nil { + log.Fatal(err) + } + + tsr, err := http.Post("https://freetsa.org/tsr", "application/timestamp-query", bytes.NewReader(tsq)) + if err != nil { + log.Fatal(err) + } + + if tsr.StatusCode > 200 { + log.Fatal(tsr.Status) + } + + resp, err := io.ReadAll(tsr.Body) + if err != nil { + log.Fatal(err) + } + + tsResp, err := timestamp.ParseResponse(resp) + if err != nil { + log.Fatal(err) + } + + if err := verifyHashedMessages(tsResp.HashAlgorithm.New(), tsResp.HashedMessage, []byte(tc.message)); err != nil { + t.Errorf("verifyHashedMessages failed comparing hashes: %v", err) + } + + } +}