Skip to content

Commit

Permalink
move verify logic to pkg
Browse files Browse the repository at this point in the history
Signed-off-by: Hector Fernandez <[email protected]>
  • Loading branch information
hectorj2f committed Nov 6, 2022
1 parent 5b514aa commit 9c61a11
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 67 deletions.
70 changes: 6 additions & 64 deletions cmd/timestamp-cli/app/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,14 @@
package app

import (
"bytes"
"crypto/x509"
"errors"
"fmt"
"hash"
"io"
"os"
"path/filepath"

"github.com/digitorus/pkcs7"
"github.com/digitorus/timestamp"
"github.com/sigstore/timestamp-authority/cmd/timestamp-cli/app/format"
"github.com/sigstore/timestamp-authority/pkg/log"
"github.com/sigstore/timestamp-authority/pkg/verify"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
Expand Down Expand Up @@ -72,80 +67,27 @@ func runVerify() (interface{}, error) {
return nil, fmt.Errorf("Error reading request from file: %w", err)
}

ts, err := timestamp.ParseResponse(tsrBytes)
if err != nil {
pe := timestamp.ParseError("")
if errors.As(err, &pe) {
return nil, fmt.Errorf("Given timestamp response is not valid: %w", err)
}
return nil, fmt.Errorf("Error parsing response into Timestamp: %w", err)
}

// verify the timestamp response against the certificate chain PEM file
err = verifyTSRWithPEM(ts)
if err != nil {
return nil, err
}

// verify the timestamp response signature against the local arficat hash
err = verifyArtifactWithTSR(ts)
if err != nil {
return nil, err
}

return &verifyCmdOutput{TimestampPath: tsrPath}, nil
}

func verifyTSRWithPEM(ts *timestamp.Timestamp) error {
p7Message, err := pkcs7.Parse(ts.RawToken)
if err != nil {
return fmt.Errorf("Error parsing hashed message: %w", err)
}

certChainPEM := viper.GetString("cert-chain")
pemBytes, err := os.ReadFile(filepath.Clean(certChainPEM))
if err != nil {
return fmt.Errorf("Error reading request from file: %w", err)
return nil, fmt.Errorf("Error reading request from file: %w", err)
}

certPool := x509.NewCertPool()
ok := certPool.AppendCertsFromPEM(pemBytes)
if !ok {
return fmt.Errorf("Error while appending certs from PEM")
}

err = p7Message.VerifyWithChain(certPool)
if err != nil {
return fmt.Errorf("Error while verifying with chain: %w", err)
return nil, fmt.Errorf("Error parsing response into Timestamp while appending certs from PEM")
}

log.CliLogger.Info("Verified with chain")

return nil
}

func verifyArtifactWithTSR(ts *timestamp.Timestamp) error {
artifactPath := viper.GetString("artifact")
artifact, err := os.Open(filepath.Clean(artifactPath))
if err != nil {
return err
}

return verifyHashedMessages(ts.HashAlgorithm.New(), ts.HashedMessage, artifact)
}

func verifyHashedMessages(hashAlg hash.Hash, hashedMessage []byte, artifactReader io.Reader) error {
h := hashAlg
if _, err := io.Copy(h, artifactReader); err != nil {
return fmt.Errorf("failed to create hash %w", err)
return nil, err
}
localHashedMsg := h.Sum(nil)

if !bytes.Equal(localHashedMsg, hashedMessage) {
return fmt.Errorf("Hashed messages don't match")
}
err = verify.TimestampResponse(tsrBytes, artifact, certPool)

return nil
return &verifyCmdOutput{TimestampPath: tsrPath}, err
}

func init() {
Expand Down
4 changes: 2 additions & 2 deletions pkg/tests/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestVerify_InvalidTSR(t *testing.T) {

// It should return a message that the PEM is not valid
out := runCliErr(t, "--timestamp_server", restapiURL, "verify", "--timestamp", invalidTSR, "--artifact", artifactPath, "--cert-chain", pemPath)
outputContains(t, out, "Error parsing response into Timestamp")
outputContains(t, out, "Error parsing response into Timestamp while appending certs from PEM")
}

func TestVerify_InvalidPEM(t *testing.T) {
Expand All @@ -127,7 +127,7 @@ func TestVerify_InvalidPEM(t *testing.T) {

// It should return a message that the PEM is not valid
out := runCliErr(t, "--timestamp_server", restapiURL, "verify", "--timestamp", tsrPath, "--artifact", artifactPath, "--cert-chain", invalidPEMPath)
outputContains(t, out, "Error while appending certs from PEM")
outputContains(t, out, "Error parsing response into Timestamp while appending certs from PEM")
}

func runCliErr(t *testing.T, arg ...string) string {
Expand Down
77 changes: 77 additions & 0 deletions pkg/verify/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// 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 verify

import (
"bytes"
"crypto/x509"
"errors"
"fmt"
"hash"
"io"

"github.com/digitorus/pkcs7"
"github.com/digitorus/timestamp"
)

// VerifyTimestampResponse the timestamp response using a timestamp certificate chain.
func TimestampResponse(tsrBytes []byte, artifact io.Reader, certPool *x509.CertPool) error {
ts, err := timestamp.ParseResponse(tsrBytes)
if err != nil {
pe := timestamp.ParseError("")
if errors.As(err, &pe) {
return fmt.Errorf("Given timestamp response is not valid: %w", err)
}
return fmt.Errorf("Error parsing response into Timestamp: %w", err)
}

// verify the timestamp response against the certificate chain PEM file
err = verifyTSRWithPEM(ts, certPool)
if err != nil {
return err
}

// verify the timestamp response signature against the local arficat hash
return verifyHashedMessages(ts.HashAlgorithm.New(), ts.HashedMessage, artifact)
}

func verifyTSRWithPEM(ts *timestamp.Timestamp, certPool *x509.CertPool) error {
p7Message, err := pkcs7.Parse(ts.RawToken)
if err != nil {
return fmt.Errorf("Error parsing hashed message: %w", err)
}

err = p7Message.VerifyWithChain(certPool)
if err != nil {
return fmt.Errorf("Error while verifying with chain: %w", err)
}

return nil
}

func verifyHashedMessages(hashAlg hash.Hash, hashedMessage []byte, artifactReader io.Reader) error {
h := hashAlg
if _, err := io.Copy(h, artifactReader); err != nil {
return fmt.Errorf("failed to create hash %w", err)
}
localHashedMsg := h.Sum(nil)

if !bytes.Equal(localHashedMsg, hashedMessage) {
return fmt.Errorf("Hashed messages don't match")
}

return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package app
package verify

import (
"bytes"
Expand Down

0 comments on commit 9c61a11

Please sign in to comment.