From 154235aaedf1c92449e1e0101085aad3c31c5695 Mon Sep 17 00:00:00 2001
From: Dan Lorenc <dlorenc@google.com>
Date: Mon, 15 Mar 2021 21:51:53 -0500
Subject: [PATCH] Store the whole cert.

Signed-off-by: Dan Lorenc <dlorenc@google.com>
---
 pkg/pki/x509/x509.go | 51 ++++++++++++++++++++++++++++++++------------
 tests/e2e_test.go    | 15 +++++++++----
 2 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/pkg/pki/x509/x509.go b/pkg/pki/x509/x509.go
index 5813cd2..f6c58c1 100644
--- a/pkg/pki/x509/x509.go
+++ b/pkg/pki/x509/x509.go
@@ -69,7 +69,12 @@ func (s Signature) Verify(r io.Reader, k interface{}) error {
 		return fmt.Errorf("Invalid public key type for: %v", k)
 	}
 
-	switch pub := key.key.(type) {
+	p := key.key
+	if p == nil {
+		p = key.cert.c.PublicKey
+	}
+
+	switch pub := p.(type) {
 	case *rsa.PublicKey:
 		return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hash, s.signature)
 	case ed25519.PublicKey:
@@ -89,7 +94,13 @@ func (s Signature) Verify(r io.Reader, k interface{}) error {
 
 // PublicKey Public Key that follows the x509 standard
 type PublicKey struct {
-	key interface{}
+	key  interface{}
+	cert *cert
+}
+
+type cert struct {
+	c *x509.Certificate
+	b []byte
 }
 
 // NewPublicKey implements the pki.PublicKey interface
@@ -112,29 +123,41 @@ func NewPublicKey(r io.Reader) (*PublicKey, error) {
 		}
 		return &PublicKey{key: key}, nil
 	case "CERTIFICATE":
-		cert, err := x509.ParseCertificate(block.Bytes)
+		c, err := x509.ParseCertificate(block.Bytes)
 		if err != nil {
 			return nil, err
 		}
-		return &PublicKey{key: cert.PublicKey}, nil
+		return &PublicKey{
+			cert: &cert{
+				c: c,
+				b: block.Bytes,
+			}}, nil
 	}
 	return nil, fmt.Errorf("invalid public key: %s", string(rawPub))
 }
 
 // CanonicalValue implements the pki.PublicKey interface
 func (k PublicKey) CanonicalValue() ([]byte, error) {
-	if k.key == nil {
-		return nil, fmt.Errorf("x509 public key has not been initialized")
-	}
 
-	b, err := x509.MarshalPKIXPublicKey(k.key)
-	if err != nil {
-		return nil, err
-	}
+	var p pem.Block
+	switch {
+	case k.key != nil:
+		b, err := x509.MarshalPKIXPublicKey(k.key)
+		if err != nil {
+			return nil, err
+		}
 
-	p := pem.Block{
-		Type:  "PUBLIC KEY",
-		Bytes: b,
+		p = pem.Block{
+			Type:  "PUBLIC KEY",
+			Bytes: b,
+		}
+	case k.cert != nil:
+		p = pem.Block{
+			Type:  "CERTIFICATE",
+			Bytes: k.cert.b,
+		}
+	default:
+		return nil, fmt.Errorf("x509 public key has not been initialized")
 	}
 
 	var buf bytes.Buffer
diff --git a/tests/e2e_test.go b/tests/e2e_test.go
index 3d55f1f..fc1ed7e 100644
--- a/tests/e2e_test.go
+++ b/tests/e2e_test.go
@@ -242,14 +242,18 @@ func TestX509(t *testing.T) {
 		t.Fatal(err)
 	}
 
+	// If we do it twice, it should already exist
 	out := runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath,
 		"--public-key", certPath, "--pki-format", "x509")
 	outputContains(t, out, "Created entry at")
+	out = runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath,
+		"--public-key", certPath, "--pki-format", "x509")
+	outputContains(t, out, "Entry already exists")
 
-	// Now upload with the public key rather than the cert. They should be deduped.
+	// Now upload with the public key rather than the cert. They should NOT be deduped.
 	out = runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath,
 		"--public-key", pubKeyPath, "--pki-format", "x509")
-	outputContains(t, out, "Entry already exists")
+	outputContains(t, out, "Created entry at")
 
 	// Now let's go the other order to be sure. New artifact, key first then cert.
 	createdX509SignedArtifact(t, artifactPath, sigPath)
@@ -257,10 +261,13 @@ func TestX509(t *testing.T) {
 	out = runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath,
 		"--public-key", pubKeyPath, "--pki-format", "x509")
 	outputContains(t, out, "Created entry at")
-	// This should already exist
 	out = runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath,
-		"--public-key", certPath, "--pki-format", "x509")
+		"--public-key", pubKeyPath, "--pki-format", "x509")
 	outputContains(t, out, "Entry already exists")
+	// This should NOT already exist
+	out = runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath,
+		"--public-key", certPath, "--pki-format", "x509")
+	outputContains(t, out, "Created entry at")
 
 }
 
-- 
GitLab