From 8a157abeb24ede579c0e9f65520e064f53f6a682 Mon Sep 17 00:00:00 2001 From: Cody Soyland Date: Wed, 16 Oct 2024 08:28:01 -0500 Subject: [PATCH] Allow parsing of certificates from Fulcio if ctlog is disabled (#288) * Allow parsing of certificates from Fulcio if ctlog is disabled Signed-off-by: Cody Soyland * Change if/else to switch Signed-off-by: Cody Soyland * Add test for detached sct Signed-off-by: Cody Soyland --------- Signed-off-by: Cody Soyland --- pkg/sign/certificate.go | 18 +++++++++++---- pkg/sign/certificate_test.go | 43 +++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/pkg/sign/certificate.go b/pkg/sign/certificate.go index af002bc4..ddf32fb0 100644 --- a/pkg/sign/certificate.go +++ b/pkg/sign/certificate.go @@ -72,13 +72,18 @@ type publicKey struct { } type fulcioResponse struct { - SctCertWithChain signedCertificateEmbeddedSct `json:"signedCertificateEmbeddedSct"` + SignedCertificateEmbeddedSct signedCertificateEmbeddedSct `json:"signedCertificateEmbeddedSct"` + SignedCertificateDetachedSct signedCertificateDetachedSct `json:"signedCertificateDetachedSct"` } type signedCertificateEmbeddedSct struct { Chain chain `json:"chain"` } +type signedCertificateDetachedSct struct { + Chain chain `json:"chain"` +} + type chain struct { Certificates []string `json:"certificates"` } @@ -204,12 +209,17 @@ func (f *Fulcio) GetCertificate(ctx context.Context, keypair Keypair, opts *Cert return nil, err } - certs := fulcioResp.SctCertWithChain.Chain.Certificates - if len(certs) == 0 { + var cert []byte + switch { + case len(fulcioResp.SignedCertificateEmbeddedSct.Chain.Certificates) > 0: + cert = []byte(fulcioResp.SignedCertificateEmbeddedSct.Chain.Certificates[0]) + case len(fulcioResp.SignedCertificateDetachedSct.Chain.Certificates) > 0: + cert = []byte(fulcioResp.SignedCertificateDetachedSct.Chain.Certificates[0]) + default: return nil, errors.New("Fulcio returned no certificates") } - certBlock, _ := pem.Decode([]byte(certs[0])) + certBlock, _ := pem.Decode(cert) if certBlock == nil { return nil, errors.New("unable to parse Fulcio certificate") } diff --git a/pkg/sign/certificate_test.go b/pkg/sign/certificate_test.go index df1e7fb8..e6e69bea 100644 --- a/pkg/sign/certificate_test.go +++ b/pkg/sign/certificate_test.go @@ -39,7 +39,7 @@ func setupVirtualSigstore() { } } -func getFulcioResponse() (*http.Response, error) { +func getFulcioResponse(detachedSct bool) (*http.Response, error) { virtualSigstoreOnce.Do(setupVirtualSigstore) if virtualSigstoreErr != nil { return nil, virtualSigstoreErr @@ -55,14 +55,24 @@ func getFulcioResponse() (*http.Response, error) { Bytes: leafCert.Raw, })) - responseStruct := fulcioResponse{ - SctCertWithChain: signedCertificateEmbeddedSct{ - Chain: chain{ - Certificates: []string{certPEM}, + var responseStruct fulcioResponse + if detachedSct { + responseStruct = fulcioResponse{ + SignedCertificateDetachedSct: signedCertificateDetachedSct{ + Chain: chain{ + Certificates: []string{certPEM}, + }, }, - }, + } + } else { + responseStruct = fulcioResponse{ + SignedCertificateEmbeddedSct: signedCertificateEmbeddedSct{ + Chain: chain{ + Certificates: []string{certPEM}, + }, + }, + } } - fulcioJSON, err := json.Marshal(responseStruct) if err != nil { return nil, err @@ -76,14 +86,17 @@ func getFulcioResponse() (*http.Response, error) { return response, nil } -type mockFulcio struct{} +type mockFulcio struct { + detachedSct bool +} func (m *mockFulcio) RoundTrip(_ *http.Request) (*http.Response, error) { - return getFulcioResponse() + return getFulcioResponse(m.detachedSct) } type failFirstFulcio struct { - Count int + Count int + detachedSct bool } func (f *failFirstFulcio) RoundTrip(_ *http.Request) (*http.Response, error) { @@ -96,7 +109,7 @@ func (f *failFirstFulcio) RoundTrip(_ *http.Request) (*http.Response, error) { return response, nil } - return getFulcioResponse() + return getFulcioResponse(f.detachedSct) } func Test_GetCertificate(t *testing.T) { @@ -135,4 +148,12 @@ func Test_GetCertificate(t *testing.T) { cert, err = retryFulcio.GetCertificate(ctx, keypair, certOpts) assert.Nil(t, cert) assert.NotNil(t, err) + + // Test detached SCT + detachedOpts := &FulcioOptions{Retries: 1, Transport: &mockFulcio{detachedSct: true}} + detachedFulcio := NewFulcio(detachedOpts) + + cert, err = detachedFulcio.GetCertificate(ctx, keypair, certOpts) + assert.NotNil(t, cert) + assert.NoError(t, err) }