Skip to content

Commit

Permalink
add TestSignVerifyCertBundle
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitris committed Jun 20, 2024
1 parent cbf480e commit 92bbac8
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 16 deletions.
56 changes: 56 additions & 0 deletions test/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,62 @@ func TestSignVerify(t *testing.T) {
mustErr(verify(pubKeyPath, imgName, true, map[string]interface{}{"foo": "bar", "baz": "bat"}, "", false), t)
}

func TestSignVerifyCertBundle(t *testing.T) {
td := t.TempDir()
err := downloadAndSetEnv(t, rekorURL+"/api/v1/log/publicKey", env.VariableSigstoreRekorPublicKey.String(), td)
if err != nil {
t.Fatal(err)
}

repo, stop := reg(t)
defer stop()

imgName := path.Join(repo, "cosign-e2e")

_, _, cleanup := mkimage(t, imgName)
defer cleanup()

caCertFile, _ /* caPrivKeyFile */, caIntermediateCertFile, _ /* caIntermediatePrivKeyFile */, certFile, privKeyFile, pubkeyFile, err := generateCertificateBundleFiles(td, true, "foobar")

ctx := context.Background()
// Verify should fail at first
must(verifyCertBundle(pubkeyFile, caCertFile, caIntermediateCertFile, certFile, imgName, true, nil, "", false), t)
// So should download
mustErr(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t)

// Now sign the image
ko := options.KeyOpts{
KeyRef: privKeyFile,
PassFunc: passFunc,
RekorURL: rekorURL,
SkipConfirmation: true,
}
so := options.SignOptions{
Upload: true,
TlogUpload: true,
}
must(sign.SignCmd(ro, ko, so, []string{imgName}), t)

// Now verify and download should work!
must(verifyCertBundle(pubkeyFile, caCertFile, caIntermediateCertFile, certFile, imgName, true, nil, "", false), t)
must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t)

// Look for a specific annotation
mustErr(verifyCertBundle(pubkeyFile, caCertFile, caIntermediateCertFile, certFile, imgName, true, map[string]interface{}{"foo": "bar"}, "", false), t)

so.AnnotationOptions = options.AnnotationOptions{
Annotations: []string{"foo=bar"},
}
// Sign the image with an annotation
must(sign.SignCmd(ro, ko, so, []string{imgName}), t)

// It should match this time.
must(verifyCertBundle(pubkeyFile, caCertFile, caIntermediateCertFile, certFile, imgName, true, map[string]interface{}{"foo": "bar"}, "", false), t)

// But two doesn't work
mustErr(verifyCertBundle(pubkeyFile, caCertFile, caIntermediateCertFile, certFile, imgName, true, map[string]interface{}{"foo": "bar", "baz": "bat"}, "", false), t)
}

func TestSignVerifyClean(t *testing.T) {
td := t.TempDir()
err := downloadAndSetEnv(t, rekorURL+"/api/v1/log/publicKey", env.VariableSigstoreRekorPublicKey.String(), td)
Expand Down
117 changes: 104 additions & 13 deletions test/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,28 @@ var verify = func(keyRef, imageRef string, checkClaims bool, annotations map[str
return cmd.Exec(context.Background(), args)
}

var verifyCertBundle = func(keyRef, caCertFile, caIntermediates, certFile, imageRef string, checkClaims bool, annotations map[string]interface{}, attachment string, skipTlogVerify bool) error {
cmd := cliverify.VerifyCommand{
KeyRef: keyRef,
RekorURL: rekorURL,
CheckClaims: checkClaims,
Annotations: sigs.AnnotationsMap{Annotations: annotations},
Attachment: attachment,
HashAlgorithm: crypto.SHA256,
MaxWorkers: 10,
IgnoreTlog: skipTlogVerify,
CertVerifyOptions: options.CertVerifyOptions{
Cert: certFile,
CAIntermediates: caIntermediates,
CARoots: caCertFile,
},
}

args := []string{imageRef}

return cmd.Exec(context.Background(), args)
}

var verifyTSA = func(keyRef, imageRef string, checkClaims bool, annotations map[string]interface{}, attachment, tsaCertChain string, skipTlogVerify bool) error {
cmd := cliverify.VerifyCommand{
KeyRef: keyRef,
Expand Down Expand Up @@ -453,13 +475,77 @@ func downloadAndSetEnv(t *testing.T, url, envVar, dir string) error {
t.Setenv(envVar, f.Name())
return nil
}
func GenerateCertificateBundle(td string, genIntermediate bool, outputSuffix string) (

func generateCertificateBundleFiles(td string, genIntermediate bool, outputSuffix string) (
caCertFile string,
caPrivKeyFile string,
caIntermediateCertFile string,
caIntermediatePrivKeyFile string,
certFile string,
keyFile string,
pubKeyFile string,
err error,
) {
caCertBuf, caPrivKeyBuf, caIntermediateCertBuf, caIntermediatePrivKeyBuf, certBuf, keyBuf, pubkey, err := generateCertificateBundle(genIntermediate)
if err != nil {
err = fmt.Errorf("error generating certificate bundle: %w", err)
return
}
err = os.WriteFile(filepath.Join(td, fmt.Sprintf("caCert%s.pem", outputSuffix)), caCertBuf.Bytes(), 0600)
if err != nil {
err = fmt.Errorf("error writing caCert to file: %w", err)
return
}
err = os.WriteFile(filepath.Join(td, fmt.Sprintf("caPrivKey%s.pem", outputSuffix)), caPrivKeyBuf.Bytes(), 0600)
if err != nil {
err = fmt.Errorf("error writing caPrivKey to file: %w", err)
return
}
if genIntermediate {
err = os.WriteFile(filepath.Join(td, fmt.Sprintf("caIntermediateCert%s.pem", outputSuffix)), caIntermediateCertBuf.Bytes(), 0600)
if err != nil {
err = fmt.Errorf("error writing caIntermediateCert to file: %w", err)
return
}
err = os.WriteFile(filepath.Join(td, fmt.Sprintf("caIntermediatePrivKey%s.pem", outputSuffix)), caIntermediatePrivKeyBuf.Bytes(), 0600)
if err != nil {
err = fmt.Errorf("error writing caIntermediatePrivKey to file: %w", err)
return
}
}
err = os.WriteFile(filepath.Join(td, fmt.Sprintf("cert%s.pem", outputSuffix)), certBuf.Bytes(), 0600)
if err != nil {
err = fmt.Errorf("error writing cert to file: %w", err)
return
}
err = os.WriteFile(filepath.Join(td, fmt.Sprintf("key%s.pem", outputSuffix)), keyBuf.Bytes(), 0600)
if err != nil {
err = fmt.Errorf("error writing key to file: %w", err)
return
}
// write the public key to a file
pubKeyFile = filepath.Join(td, fmt.Sprintf("pubkey%s.pem", outputSuffix))
pubKeyBuf := &bytes.Buffer{}
pubKeyBytes, err := x509.MarshalPKIXPublicKey(pubkey)
if err != nil {
err = fmt.Errorf("error marshalling public key: %w", err)
return
}
err = pem.Encode(pubKeyBuf, &pem.Block{
Type: "PUBLIC KEY",
Bytes: pubKeyBytes,
})
return
}

func generateCertificateBundle(genIntermediate bool) (
caCertBuf *bytes.Buffer,
caPrivKeyBuf *bytes.Buffer,
caIntermediateCertBuf *bytes.Buffer,
caIntermediatePrivKeyBuf *bytes.Buffer,
certBuf *bytes.Buffer,
keyBuf *bytes.Buffer,
pubkeyBuf *bytes.Buffer,
err error,
) {
// set up our CA certificate
Expand Down Expand Up @@ -488,7 +574,7 @@ func GenerateCertificateBundle(td string, genIntermediate bool, outputSuffix str
if err != nil {
log.Fatal(err)
}

pubkey := &caPrivKey.PublicKey
// create the CA
caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey)
if err != nil {
Expand All @@ -510,7 +596,20 @@ func GenerateCertificateBundle(td string, genIntermediate bool, outputSuffix str
Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey),
})
if err != nil {
log.Fatalf("unable to create encode to buffer: %v", err) //nolint:gocritic
log.Fatalf("unable to PEM encode private key to buffer: %v", err) //nolint:gocritic
}
pubkeyBuf = &bytes.Buffer{}
// PEM encode to pubkeyBuf the public key of caPrivKey
pubkeyBytes, err := x509.MarshalPKIXPublicKey(pubkey)
if err != nil {
log.Fatalf("failed to marshal public key: %v", err)
}
err = pem.Encode(pubkeyBuf, &pem.Block{
Type: "PUBLIC KEY",
Bytes: pubkeyBytes,
})
if err != nil {
log.Fatalf("failed to PME-encode public key to buffer: %v", err)
}

// generate intermediate CA if requested
Expand Down Expand Up @@ -562,7 +661,7 @@ func GenerateCertificateBundle(td string, genIntermediate bool, outputSuffix str
Bytes: x509.MarshalPKCS1PrivateKey(caIntermediatePrivKey),
})
if err != nil {
log.Fatalf("unable to create caIntermediatePrivKey %s: %v", td, err) //nolint:gocritic
log.Fatalf("unable to PEM encode caIntermediatePrivKey: %v", err)
}
}
// set up our server certificate
Expand Down Expand Up @@ -611,13 +710,5 @@ func GenerateCertificateBundle(td string, genIntermediate bool, outputSuffix str
log.Fatalf("failed to encode cert: %v", err)
}

keyBuf = &bytes.Buffer{}
err = pem.Encode(keyBuf, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(certPrivKey),
})
if err != nil {
log.Fatalf("failed to encode private key to buffer: %v", err)
}
return caCertBuf, caPrivKeyBuf, caIntermediateCertBuf, caIntermediatePrivKeyBuf, certBuf, keyBuf, nil
return caCertBuf, caPrivKeyBuf, caIntermediateCertBuf, caIntermediatePrivKeyBuf, certBuf, keyBuf, pubkeyBuf, nil
}
22 changes: 19 additions & 3 deletions test/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,24 @@ package test
import "testing"

func TestGenerateCertificateBundle(t *testing.T) {
_, _, _, _, _, _, err := GenerateCertificateBundle("functest", true, "foobar")
if err != nil {
t.Fatalf("Error generating certificate bundle: %v", err)
for _, test := range []struct {
name string
genIntermediate bool
}{
{
name: "without intermediate",
genIntermediate: false,
},
{
name: "with intermediate",
genIntermediate: true,
},
} {
t.Run(test.name, func(t *testing.T) {
_, _, _, _, _, _, _, err := generateCertificateBundle(true)
if err != nil {
t.Fatalf("Error generating certificate bundle: %v", err)
}
})
}
}

0 comments on commit 92bbac8

Please sign in to comment.