Skip to content

Commit

Permalink
Support OtherName SAN in Fulcio cert
Browse files Browse the repository at this point in the history
Add support for parsing and verifying a Fulcio certificate with a
username identity issued from an OIDC provider. See [1].

[1] https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md#1361415726417--othername-san

Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
  • Loading branch information
cmurphy committed Jul 12, 2024
1 parent ec91cbf commit b81bf6c
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 7 deletions.
9 changes: 7 additions & 2 deletions pkg/fulcio/certificate/summarize.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"errors"
"fmt"
"reflect"

"github.com/sigstore/sigstore/pkg/cryptoutils"
)

type Summary struct {
Expand Down Expand Up @@ -51,8 +53,11 @@ func SummarizeCertificate(cert *x509.Certificate) (Summary, error) {
san = cert.URIs[0].String()
case len(cert.EmailAddresses) > 0:
san = cert.EmailAddresses[0]
default:
// TODO: Support OtherName SANs i.e. https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md#1361415726417--othername-san
}
if san == "" {
san, _ = cryptoutils.UnmarshalOtherNameSAN(cert.Extensions)
}
if san == "" {
return Summary{}, errors.New("No Subject Alternative Name found")
}

Expand Down
24 changes: 24 additions & 0 deletions pkg/fulcio/certificate/summarize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,30 @@ func TestSummarizeCertificateWithOauthBundle(t *testing.T) {
assert.Equal(t, expected, cs)
}

func TestSummarizeCertificateWithOtherNameSAN(t *testing.T) {
entity := data.OthernameBundle(t)
vc, err := entity.VerificationContent()
if err != nil {
t.Fatalf("failed to get verification content: %v", err)
}

leaf := vc.GetCertificate()

if leaf == nil {
t.Fatalf("expected verification content to be a certificate chain")
}
cs, err := certificate.SummarizeCertificate(leaf)
assert.NoError(t, err)
expected := certificate.Summary{
CertificateIssuer: "O=Linux Foundation,POSTALCODE=57274,STREET=548 Market St,L=San Francisco,ST=California,C=USA",
SubjectAlternativeName: "foo!oidc.local",
Extensions: certificate.Extensions{
Issuer: "http://oidc.local:8080",
},
}
assert.Equal(t, expected, cs)
}

func TestCompareExtensions(t *testing.T) {
// Test that the extensions are equal
actualExt := certificate.Extensions{
Expand Down
16 changes: 16 additions & 0 deletions pkg/testing/data/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ var SigstoreBundleRaw []byte
//go:embed sigstore.js@2.0.0-provenanceBundle.json
var SigstoreJS200ProvenanceBundleRaw []byte

//go:embed othernameBundle.json
var OthernameBundleRaw []byte

func TestBundle(t *testing.T, raw []byte) *bundle.ProtobufBundle {
var b protobundle.Bundle
err := protojson.Unmarshal(raw, &b)
Expand All @@ -65,6 +68,10 @@ func SigstoreJS200ProvenanceBundle(t *testing.T) *bundle.ProtobufBundle {
return TestBundle(t, SigstoreJS200ProvenanceBundleRaw)
}

func OthernameBundle(t *testing.T) *bundle.ProtobufBundle {
return TestBundle(t, OthernameBundleRaw)
}

func PublicGoodTrustedMaterialRoot(t *testing.T) *root.TrustedRoot {
trustedrootJSON, _ := os.ReadFile("../../examples/trusted-root-public-good.json")
trustedRoot, _ := root.NewTrustedRootFromJSON(trustedrootJSON)
Expand All @@ -73,3 +80,12 @@ func PublicGoodTrustedMaterialRoot(t *testing.T) *root.TrustedRoot {

return trustedRoot
}

func ScaffoldingTrustedMaterialRoot(t *testing.T) *root.TrustedRoot {
trustedrootJSON, _ := os.ReadFile("../testing/data/trusted-root-scaffolding.json")
trustedRoot, _ := root.NewTrustedRootFromJSON(trustedrootJSON)

assert.NotNil(t, trustedRoot)

return trustedRoot
}
44 changes: 44 additions & 0 deletions pkg/testing/data/othernameBundle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json",
"verificationMaterial": {
"certificate": {
"rawBytes": "MIIEtTCCAp2gAwIBAgIUQo007zs0OhGOK8/Acik+axa7ve0wDQYJKoZIhvcNAQELBQAwfjEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRYwFAYDVQQJEw01NDggTWFya2V0IFN0MQ4wDAYDVQQREwU1NzI3NDEZMBcGA1UEChMQTGludXggRm91bmRhdGlvbjAeFw0yNDA3MTIxOTA2MjhaFw0yNDA3MTIxOTE2MjhaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ2fasaLzAQ6NW1DeN47ahLQ+4B/yykTNrlPN1L4/Fd2n7+Khk2Np0sCOzn1q1J3A9ctTaLwhmaWx98VXVax9uNo4IBcjCCAW4wDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBQav7zimj6IhRI/bEru7UNoUd2MMDAfBgNVHSMEGDAWgBSPD5vlHaXVMRD4Ul0X+y/OAJEl7TAsBgNVHREBAf8EIjAgoB4GCisGAQQBg78wAQegEAwOZm9vIW9pZGMubG9jYWwwJAYKKwYBBAGDvzABAQQWaHR0cDovL29pZGMubG9jYWw6ODA4MDAmBgorBgEEAYO/MAEIBBgMFmh0dHA6Ly9vaWRjLmxvY2FsOjgwODAwgYoGCisGAQQB1nkCBAIEfAR6AHgAdgDesHDYHzkyPSGM4zeGpsPji0+Fkuo5K601DwRJUWQDXAAAAZCoVvGxAAAEAwBHMEUCIF8KATnGR/A0M00weGYISnKlMHu+/PQPLXu7yO0G2itfAiEA2k2BG9Hzdp2AcgverhnsegnXxjKNO5FNtnwW/jnOIo4wDQYJKoZIhvcNAQELBQADggIBAGODe/vPPzDxaroHlIm/2uGoAl7a/aWJZvjobg7a9QqSM43nFhprRF3C518jATPxmzr0xzmDMOcI6+aT1ezK6pBRK5U/vY+mLzYHxBg9CcBDd6A8mOl89Qn1x6awSXoq+3D950Eww3vHfEJUS5gAFfD0SE91Y9L6fN1u9VzfcB27sTHfnfCk78iQf+sA0KWaTFgekCTkWetP9839efcQo5xY5JkxHzCWxKDsZrZqH3goGHCqdIL93g06QLJIHqOH3ztMvfkYbLmVuTV2RiysdYVhD6sJRlEKyiXtaXwthqdbsgbiKD8gRmQRJir961PoxTKkSvHhdafVmVUYtkWO6wQ98PwmOY0Poj+3zWoOAsnzqr0jwFn8QVNdeWKlDmzXqdXn5aBoXBphlQy/j2u1TWsl8Hc7JL+HhmV3GhqRbhD31WxVAQqi0poK7ig3ZB+q36TXvesmLEWenICplXscUy2Lr39C5sBeiLwLse3aaXse95YHqJkYgP44cS33/mmTmy2C1Fc4Pu01akUhLx69/sgLHS/3G2+UqgG8nslz2N7l7SUXat4Djqec1XQvoWG/f7kUbn3+dt0N8vv4YHVqVyaW7QkXcP6hyjnT8chmjsqCSCy8KWsgxr0pqpLCrrumlSke1BJGL4EZm0hSDvrh0dhqTgros8GZsYq8AJBAAmqj"
},
"tlogEntries": [
{
"logIndex": "3",
"logId": {
"keyId": "9vs1fkgdlblPyMuWiLRAQbEg0hmDHE6UwC92VxyLS8g="
},
"kindVersion": {
"kind": "hashedrekord",
"version": "0.0.1"
},
"integratedTime": "1720811189",
"inclusionPromise": {
"signedEntryTimestamp": "MEUCIQDlRe4vCqGTap9Bko4TN9scDU7E7ideUfC51cEwxJJVJwIgBhimuSEUEUTuJ8rISl9UyMZvZp2hi1m7SSDIZM/ZkAA="
},
"inclusionProof": {
"logIndex": "3",
"rootHash": "uZYUY33ENx3NVSOphL2yVZLM+fjGXvOvRoQ15T82jp8=",
"treeSize": "4",
"hashes": [
"7KJPHdqkyM0JutlXYl4X0P0KU4VrWQKzjU6khYDdypw=",
"t2F/5pUpEDAGCLrNbBywFrpk6eTM03yRmqxCkwO8nd0="
],
"checkpoint": {
"envelope": "rekor-00001-deployment-56bf7777c9-jds5x - 6364419738405537866\n4\nuZYUY33ENx3NVSOphL2yVZLM+fjGXvOvRoQ15T82jp8=\n\n— rekor-00001-deployment-56bf7777c9-jds5x 9vs1fjBFAiBU8kwsoJjjEntsK485B35Sa4xhVryfMnnsv+V3fjujFgIhAOe8Okg1uwIH0no5NG3YvR57Fq0rwdxTxLqrsj2Ox1aj\n"
}
},
"canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJiYzEwM2I0YTg0OTcxZWY2NDU5YjI5NGEyYjk4NTY4YTJiZmI3MmNkZWQwOWQ0YWNkMWUxNjM2NmE0MDFmOTViIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQ2pKYmY1ZXZRRzBjZUN1SHEvZ1VWeWI4dFU5OHBaaVFudTcxYkRuT2drbUFpRUF0bzZLeTJYQjhPeitab1NQRzRQSjg3cnNUejFkR1h0V3V5LzU4OXZXZlB3PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVVjBWRU5EUVhBeVowRjNTVUpCWjBsVlVXOHdNRGQ2Y3pCUGFFZFBTemd2UVdOcGF5dGhlR0UzZG1Vd2QwUlJXVXBMYjFwSmFIWmpUa0ZSUlV3S1FsRkJkMlpxUlUxTlFXOUhRVEZWUlVKb1RVUldWazVDVFZKTmQwVlJXVVJXVVZGSlJYZHdSRmxYZUhCYWJUbDVZbTFzYUUxU1dYZEdRVmxFVmxGUlNBcEZkekZVV1ZjMFoxSnVTbWhpYlU1d1l6Sk9kazFTV1hkR1FWbEVWbEZSU2tWM01ERk9SR2RuVkZkR2VXRXlWakJKUms0d1RWRTBkMFJCV1VSV1VWRlNDa1YzVlRGT2Vra3pUa1JGV2sxQ1kwZEJNVlZGUTJoTlVWUkhiSFZrV0dkblVtMDVNV0p0VW1oa1IyeDJZbXBCWlVaM01IbE9SRUV6VFZSSmVFOVVRVElLVFdwb1lVWjNNSGxPUkVFelRWUkplRTlVUlRKTmFtaGhUVUZCZDFkVVFWUkNaMk54YUd0cVQxQlJTVUpDWjJkeGFHdHFUMUJSVFVKQ2QwNURRVUZSTWdwbVlYTmhUSHBCVVRaT1Z6RkVaVTQwTjJGb1RGRXJORUl2ZVhsclZFNXliRkJPTVV3MEwwWmtNbTQzSzB0b2F6Sk9jREJ6UTA5NmJqRnhNVW96UVRsakNuUlVZVXgzYUcxaFYzZzVPRlpZVm1GNE9YVk9ielJKUW1OcVEwTkJWelIzUkdkWlJGWlNNRkJCVVVndlFrRlJSRUZuWlVGTlFrMUhRVEZWWkVwUlVVMEtUVUZ2UjBORGMwZEJVVlZHUW5kTlJFMUNNRWRCTVZWa1JHZFJWMEpDVVdGMk4zcHBiV28yU1doU1NTOWlSWEoxTjFWT2IxVmtNazFOUkVGbVFtZE9WZ3BJVTAxRlIwUkJWMmRDVTFCRU5YWnNTR0ZZVmsxU1JEUlZiREJZSzNrdlQwRktSV3czVkVGelFtZE9Wa2hTUlVKQlpqaEZTV3BCWjI5Q05FZERhWE5IQ2tGUlVVSm5OemgzUVZGbFowVkJkMDlhYlRsMlNWYzVjRnBIVFhWaVJ6bHFXVmQzZDBwQldVdExkMWxDUWtGSFJIWjZRVUpCVVZGWFlVaFNNR05FYjNZS1RESTVjRnBIVFhWaVJ6bHFXVmQzTms5RVFUUk5SRUZ0UW1kdmNrSm5SVVZCV1U4dlRVRkZTVUpDWjAxR2JXZ3daRWhCTmt4NU9YWmhWMUpxVEcxNGRncFpNa1p6VDJwbmQwOUVRWGRuV1c5SFEybHpSMEZSVVVJeGJtdERRa0ZKUldaQlVqWkJTR2RCWkdkRVpYTklSRmxJZW10NVVGTkhUVFI2WlVkd2MxQnFDbWt3SzBacmRXODFTell3TVVSM1VrcFZWMUZFV0VGQlFVRmFRMjlXZGtkNFFVRkJSVUYzUWtoTlJWVkRTVVk0UzBGVWJrZFNMMEV3VFRBd2QyVkhXVWtLVTI1TGJFMUlkU3N2VUZGUVRGaDFOM2xQTUVjeWFYUm1RV2xGUVRKck1rSkhPVWg2WkhBeVFXTm5kbVZ5YUc1elpXZHVXSGhxUzA1UE5VWk9kRzUzVndvdmFtNVBTVzgwZDBSUldVcExiMXBKYUhaalRrRlJSVXhDVVVGRVoyZEpRa0ZIVDBSbEwzWlFVSHBFZUdGeWIwaHNTVzB2TW5WSGIwRnNOMkV2WVZkS0NscDJhbTlpWnpkaE9WRnhVMDAwTTI1R2FIQnlVa1l6UXpVeE9HcEJWRkI0YlhweU1IaDZiVVJOVDJOSk5pdGhWREZsZWtzMmNFSlNTelZWTDNaWksyMEtUSHBaU0hoQ1p6bERZMEpFWkRaQk9HMVBiRGc1VVc0eGVEWmhkMU5ZYjNFck0wUTVOVEJGZDNjemRraG1SVXBWVXpWblFVWm1SREJUUlRreFdUbE1OZ3BtVGpGMU9WWjZabU5DTWpkelZFaG1ibVpEYXpjNGFWRm1LM05CTUV0WFlWUkdaMlZyUTFSclYyVjBVRGs0TXpsbFptTlJielY0V1RWS2EzaElla05YQ25oTFJITmFjbHB4U0RObmIwZElRM0ZrU1V3NU0yY3dObEZNU2tsSWNVOUlNM3AwVFhabWExbGlURzFXZFZSV01sSnBlWE5rV1Zab1JEWnpTbEpzUlVzS2VXbFlkR0ZZZDNSb2NXUmljMmRpYVV0RU9HZFNiVkZTU21seU9UWXhVRzk0VkV0clUzWklhR1JoWmxadFZsVlpkR3RYVHpaM1VUazRVSGR0VDFrd1VBcHZhaXN6ZWxkdlQwRnpibnB4Y2pCcWQwWnVPRkZXVG1SbFYwdHNSRzE2V0hGa1dHNDFZVUp2V0VKd2FHeFJlUzlxTW5VeFZGZHpiRGhJWXpkS1RDdElDbWh0VmpOSGFIRlNZbWhFTXpGWGVGWkJVWEZwTUhCdlN6ZHBaek5hUWl0eE16WlVXSFpsYzIxTVJWZGxia2xEY0d4WWMyTlZlVEpNY2pNNVF6VnpRbVVLYVV4M1RITmxNMkZoV0hObE9UVlpTSEZLYTFsblVEUTBZMU16TXk5dGJWUnRlVEpETVVaak5GQjFNREZoYTFWb1RIZzJPUzl6WjB4SVV5OHpSeklyVlFweFowYzRibk5zZWpKT04ydzNVMVZZWVhRMFJHcHhaV014V0ZGMmIxZEhMMlkzYTFWaWJqTXJaSFF3VGpoMmRqUlpTRlp4Vm5saFZ6ZFJhMWhqVURab0NubHFibFE0WTJodGFuTnhRMU5EZVRoTFYzTm5lSEl3Y0hGd1RFTnljblZ0YkZOclpURkNTa2RNTkVWYWJUQm9VMFIyY21nd1pHaHhWR2R5YjNNNFIxb0tjMWx4T0VGS1FrRkJiWEZxQ2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIn19fX0="
}
]
},
"messageSignature": {
"messageDigest": {
"algorithm": "SHA2_256",
"digest": "vBA7SoSXHvZFmylKK5hWiiv7cs3tCdSs0eFjZqQB+Vs="
},
"signature": "MEUCICjJbf5evQG0ceCuHq/gUVyb8tU98pZiQnu71bDnOgkmAiEAto6Ky2XB8Oz+ZoSPG4PJ87rsTz1dGXtWuy/589vWfPw="
}
}
53 changes: 53 additions & 0 deletions pkg/testing/data/trusted-root-scaffolding.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1",
"tlogs": [
{
"baseUrl": "http://rekor.rekor-system.172.18.255.1.sslip.io",
"hashAlgorithm": "SHA2_256",
"publicKey": {
"rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnPyeVMLRWPJQpCHcUdG41k+oJiQEjX4uGSX7ujPH7Iv5zQD3VYiHhyQ/oMJvc1vx+2Zk2DBcBhN9IT0eZjB2RQ==",
"keyDetails": "PKIX_ECDSA_P256_SHA_256",
"validFor": {
"start": "2024-07-12T18:35:53Z"
}
},
"logId": {
"keyId": "9vs1fkgdlblPyMuWiLRAQbEg0hmDHE6UwC92VxyLS8g="
}
}
],
"certificateAuthorities": [
{
"subject": {
"organization": "Linux Foundation"
},
"uri": "http://fulcio.fulcio-system.172.18.255.1.sslip.io",
"certChain": {
"certificates": [
{
"rawBytes": "MIIFwzCCA6ugAwIBAgIIGOK4JTIvAnQwDQYJKoZIhvcNAQELBQAwfjEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRYwFAYDVQQJEw01NDggTWFya2V0IFN0MQ4wDAYDVQQREwU1NzI3NDEZMBcGA1UEChMQTGludXggRm91bmRhdGlvbjAeFw0yNDA3MTEyMjI4NDFaFw0yNTA3MTEyMjI4NDFaMH4xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEWMBQGA1UECRMNNTQ4IE1hcmtldCBTdDEOMAwGA1UEERMFNTcyNzQxGTAXBgNVBAoTEExpbnV4IEZvdW5kYXRpb24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCrq2z5byNpomZGJsrEloYzae0zU6bZK2x+9C16DdocsLavJNX2MaxQ28imb5YYp4z6M52SDPW4NZKCtJRSOp4Z+jK6194z6r08SCbU4JdU6qhBWhzb5PqDN8JYImnWAsUAg2MHu8DWDHsNVfyivxkqeeyTf/c4aAJX0YqVv8WnvEnI6rstV6CO3/Q7VqZrK3vfUH4rFuiIBwCO1TLnVh9RHARM43oDdeKAQLKh2p4PD6VoOVPNEw8uxuokG8qyJZOUVgUETovR8E3puTVn3iopea2BvMADZQA1u6MT4MCjY/Hqv+RdQ6W4c2eyey/ZZSoiQUZmkO2YTqtYPH2B+ucDmIOJ07MtraFeB1CXfRlPa5sv02N6NzZN/iD66GQ/fV2PiuMyJVmhnYJp0Yf3onVmmpxIEOkUDnWudUtMJHZuLy0rhu/hAid6l0KEGjXlBvXu7txZHw1AMerQbvn5VJdPgm4PT/5xK5f1PpPGxVZwGkjmBMZmj9+hRt0OHH59aK31vqGqPbQtIXguAlF89O1UaZv4JGnpdaJl4K3huXnahcI16+8s+Vu9sJ4dfZT/NlFV26a4aU7q+E7yH3n8+zmsk3+l06BWxz7R6SSp6Fx4yPB/3SBs2c5SJ5k6a+/3SssqVHWwgSZD6cXDt1ByYDMjkHFExV0oLDr0Q057l/ainQIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUjw+b5R2l1TEQ+FJdF/svzgCRJe0wDQYJKoZIhvcNAQELBQADggIBAECAX4HbC+MWJS5+D6aZmu7P85ZDzHMpIk5LJiAJwLUIOZwF4K0z9AOHE/nqg5+PnZGWWI3a9UheuzsZauerz/jaP8thBWjVDJCROJZpMMvALAjJfgIFJw3YLNPUup0EL4UohZ7iWoD6e/vfY64DKzCpdfGDRfcBCnWqBIYeSSPNqH+i0L059oR9kXv3jwR4os0CWk8TUMBYGeDADeE27QuZ4qafLkmOaqp//yWXwOoe4MZBxettZz/Nib5RRhCxRQ88hbs/zH3T5bBgp+DZ0anjy2iVhOj2x02mdD6Zcb32JgEJLQHCTAdGamcdulQDXC+YS9N2U0ap8J3tZCrEPQkdkeRzJ2EzQx38NIiY16BPlAqnnRpOZiXqee4O7bni4qdyVAYpkArSRNvKQbTyLHYLiQ+TEMs0SboajbQtC38I4ztZXr2ozM2b1MU0d3rBLsozmAhqT99od8wiBValo0EEi2mSxArRHy0puIOMs1i4kIz2yTbyeEI5pnkq/2uaX+RPmS2UB83SmbZ7Ex9eNe6QjnMhCv5fU0wcjtwwPp0GMMRulErGvnZ39PRMjEH79C8Nfhx9nZZoEN5VCG9qrM1KMlDLwNc09W5RJTYRQ7d41sC2hdMgwmxVJ08Ai3XMn7xiJ9JwnaypClc14XsQERoy2afgBUME9CL00G20nVYb"
}
]
},
"validFor": {
"start": "2024-07-12T18:35:53Z"
}
}
],
"ctlogs": [
{
"baseUrl": "http://ctlog.ctlog-system.172.18.255.1.sslip.io",
"hashAlgorithm": "SHA2_256",
"publicKey": {
"rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ7v1OnMWwYi4O5oaycBsWKom3McZBDzNqXsIOq9AXc3z2HOeWVbaDd1V/9c91WRFyAv77Ao9hS9D9MEboT7lZg==",
"keyDetails": "PKIX_ECDSA_P256_SHA_256",
"validFor": {
"start": "2024-07-12T18:35:53Z"
}
},
"logId": {
"keyId": "3rBw2B85Mj0hjOM3hqbD44tPhZLqOSutNQ8ESVFkA1w="
}
}
]
}
22 changes: 17 additions & 5 deletions pkg/verify/signed_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package verify

import (
"encoding/asn1"
"errors"
"fmt"
"io"
Expand All @@ -23,6 +24,7 @@ import (
"github.com/in-toto/in-toto-golang/in_toto"
"github.com/sigstore/sigstore-go/pkg/fulcio/certificate"
"github.com/sigstore/sigstore-go/pkg/root"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)

const (
Expand Down Expand Up @@ -497,11 +499,26 @@ func (v *SignedEntityVerifier) Verify(entity SignedEntity, pb PolicyBuilder) (*V
if leafCert := verificationContent.GetCertificate(); leafCert != nil {
signedWithCertificate = true

certSummary, err = certificate.SummarizeCertificate(leafCert)
if err != nil {
return nil, fmt.Errorf("failed to summarize certificate: %w", err)
}

// From spec:
// > ## Certificate
// > …
// > The Verifier MUST perform certification path validation (RFC 5280 §6) of the certificate chain with the pre-distributed Fulcio root certificate(s) as a trust anchor, but with a fake “current time.” If a timestamp from the timestamping service is available, the Verifier MUST perform path validation using the timestamp from the Timestamping Service. If a timestamp from the Transparency Service is available, the Verifier MUST perform path validation using the timestamp from the Transparency Service. If both are available, the Verifier performs path validation twice. If either fails, verification fails.

if len(leafCert.UnhandledCriticalExtensions) > 0 {
var unhandledExts []asn1.ObjectIdentifier
for _, oid := range leafCert.UnhandledCriticalExtensions {
if !oid.Equal(cryptoutils.SANOID) {
unhandledExts = append(unhandledExts, oid)
}
}
leafCert.UnhandledCriticalExtensions = unhandledExts
}

for _, verifiedTs := range verifiedTimestamps {
// verify the leaf certificate against the root
err = VerifyLeafCertificate(verifiedTs.Timestamp, leafCert, v.trustedMaterial)
Expand All @@ -519,11 +536,6 @@ func (v *SignedEntityVerifier) Verify(entity SignedEntity, pb PolicyBuilder) (*V
return nil, fmt.Errorf("failed to verify signed certificate timestamp: %w", err)
}
}

certSummary, err = certificate.SummarizeCertificate(leafCert)
if err != nil {
return nil, fmt.Errorf("failed to summarize certificate: %w", err)
}
}

// From spec:
Expand Down
24 changes: 24 additions & 0 deletions pkg/verify/signed_entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,30 @@ func TestEntitySignedByPublicGoodWithHighObserverTimestampThresholdFails(t *test
}
}

func TestEntityWithOthernameSan(t *testing.T) {
tr := data.ScaffoldingTrustedMaterialRoot(t)
entity := data.OthernameBundle(t)

v, err := verify.NewSignedEntityVerifier(tr, verify.WithoutAnyObserverTimestampsUnsafe())
assert.NoError(t, err)

digest, err := hex.DecodeString("bc103b4a84971ef6459b294a2b98568a2bfb72cded09d4acd1e16366a401f95b")
assert.NoError(t, err)

certID, err := verify.NewShortCertificateIdentity("http://oidc.local:8080", "foo!oidc.local", "")
res, err := v.Verify(entity, verify.NewPolicy(verify.WithArtifactDigest("sha256", digest), verify.WithCertificateIdentity(certID)))
assert.NoError(t, err)
assert.NotNil(t, res)

assert.Equal(t, res.VerifiedIdentity.Issuer, "http://oidc.local:8080")
assert.Equal(t, res.VerifiedIdentity.SubjectAlternativeName.SubjectAlternativeName, "foo!oidc.local")

// an email address doesn't verify
certID, err = verify.NewShortCertificateIdentity("http://oidc.local:8080", "foo@oidc.local", "")
_, err = v.Verify(entity, verify.NewPolicy(verify.WithArtifactDigest("sha256", digest), verify.WithCertificateIdentity(certID)))
assert.Error(t, err)
}

// Now we test policy:

func TestVerifyPolicyOptionErors(t *testing.T) {
Expand Down

0 comments on commit b81bf6c

Please sign in to comment.