diff --git a/pkg/signature/keys.go b/pkg/signature/keys.go index d5ee85d6fbfe..3fa1310354e5 100644 --- a/pkg/signature/keys.go +++ b/pkg/signature/keys.go @@ -43,6 +43,25 @@ import ( _ "github.com/sigstore/sigstore/pkg/signature/kms/hashivault" ) +var ( + // Fulcio cert-extensions, documented here: https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md + CertExtensionOIDCIssuer = "1.3.6.1.4.1.57264.1.1" + CertExtensionGithubWorkflowTrigger = "1.3.6.1.4.1.57264.1.2" + CertExtensionGithubWorkflowSha = "1.3.6.1.4.1.57264.1.3" + CertExtensionGithubWorkflowName = "1.3.6.1.4.1.57264.1.4" + CertExtensionGithubWorkflowRepository = "1.3.6.1.4.1.57264.1.5" + CertExtensionGithubWorkflowRef = "1.3.6.1.4.1.57264.1.6" + + CertExtensionMap = map[string]string{ + CertExtensionOIDCIssuer: "oidcIssuer", + CertExtensionGithubWorkflowTrigger: "githubWorkflowTrigger", + CertExtensionGithubWorkflowSha: "githubWorkflowSha", + CertExtensionGithubWorkflowName: "githubWorkflowName", + CertExtensionGithubWorkflowRepository: "githubWorkflowRepository", + CertExtensionGithubWorkflowRef: "githubWorkflowRef", + } +) + // LoadPublicKey is a wrapper for VerifierForKeyRef, hardcoding SHA256 as the hash algorithm func LoadPublicKey(ctx context.Context, keyRef string) (verifier signature.Verifier, err error) { return VerifierForKeyRef(ctx, keyRef, crypto.SHA256) @@ -243,9 +262,22 @@ func CertSubject(c *x509.Certificate) string { func CertIssuerExtension(cert *x509.Certificate) string { for _, ext := range cert.Extensions { - if ext.Id.String() == "1.3.6.1.4.1.57264.1.1" { + if ext.Id.String() == CertExtensionOIDCIssuer { return string(ext.Value) } } return "" } + +func CertExtensions(cert *x509.Certificate) map[string]string { + extensions := map[string]string{} + for _, ext := range cert.Extensions { + readableName, ok := CertExtensionMap[ext.Id.String()] + if ok { + extensions[readableName] = string(ext.Value) + } else { + extensions[ext.Id.String()] = string(ext.Value) + } + } + return extensions +} diff --git a/pkg/signature/keys_test.go b/pkg/signature/keys_test.go index ddebb471d5b8..e95d335639e1 100644 --- a/pkg/signature/keys_test.go +++ b/pkg/signature/keys_test.go @@ -16,6 +16,9 @@ package signature import ( "context" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" "os" "testing" @@ -110,3 +113,41 @@ func pass(s string) cosign.PassFunc { return []byte(s), nil } } + +func createCert(t *testing.T) *x509.Certificate { + t.Helper() + return &x509.Certificate{ + Extensions: []pkix.Extension{ + {Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, Value: []byte("myIssuer")}, + {Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 4}, Value: []byte("myWorkflowName")}, + {Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 6}, Value: []byte("myWorkflowRef")}, + {Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 42}, Value: []byte("myCustomExtension")}, + }, + } +} + +func TestCertExtensions(t *testing.T) { + t.Parallel() + cert := createCert(t) + exts := CertExtensions(cert) + + if len(exts) != 4 { + t.Fatalf("Unexpected extension-count: %v", len(exts)) + } + + if val, ok := exts["oidcIssuer"]; !ok || val != "myIssuer" { + t.Fatal("CertExtension does not extract field 'oidcIssuer' correctly") + } + + if val, ok := exts["githubWorkflowName"]; !ok || val != "myWorkflowName" { + t.Fatal("CertExtension does not extract field 'githubWorkflowName' correctly") + } + + if val, ok := exts["githubWorkflowRef"]; !ok || val != "myWorkflowRef" { + t.Fatal("CertExtension does not extract field 'githubWorkflowRef' correctly") + } + + if val, ok := exts["1.3.6.1.4.1.57264.1.42"]; !ok || val != "myCustomExtension" { + t.Fatal("CertExtension does not extract field '1.3.6.1.4.1.57264.1.42' correctly") + } +}