Skip to content

Commit

Permalink
topdown/crypto: Add URIStrings field to JSON certs
Browse files Browse the repository at this point in the history
This is being added to make it easier to write policy on the contents of
certificate URI SANs. This is where information like SPIFFE IDs etc are
contained and it's helpful to Rego authors to have access to these
values without rebuilding the URI from the parsed data under URIs.

Fixes: #6416

Signed-off-by: Charlie Egan <[email protected]>
  • Loading branch information
charlieegan3 authored Nov 29, 2023
1 parent 8194a22 commit 7a32e8f
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
cases:
- data:
modules:
- |
package test
import future.keywords
certs := `-----BEGIN CERTIFICATE-----
MIIBoDCCAUagAwIBAgIRAJXcMYZALXooNq/VV/grXhMwCgYIKoZIzj0EAwIwLjER
MA8GA1UEChMIT1BBIFRlc3QxGTAXBgNVBAMTEE9QQSBUZXN0IFJvb3QgQ0EwHhcN
MjEwNzAxMTc0MTUzWhcNMzEwNjI5MTc0MTUzWjAuMREwDwYDVQQKEwhPUEEgVGVz
dDEZMBcGA1UEAxMQT1BBIFRlc3QgUm9vdCBDQTBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABFqhdZA5LjsJgzsBvhgzfayZFOk+C7PmGCi7xz6zOC3xWORJZSNOyZeJ
YzSKFmoMZkcFMfslTW1jp9fwe1xl3HWjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNV
HRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTch60qxQvLl+AfDfcaXmjvT8GvpzAK
BggqhkjOPQQDAgNIADBFAiBqraIP0l2U0oNuH0+rf36hDks94wSB5EGlGH3lYNMR
ugIhANkbukX5hOP8pJDRWP/pYuv6MBnRY4BS8gpp9Vu31qOb
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIByDCCAW6gAwIBAgIQC0k4DPGrh9me73EJX5zntTAKBggqhkjOPQQDAjAuMREw
DwYDVQQKEwhPUEEgVGVzdDEZMBcGA1UEAxMQT1BBIFRlc3QgUm9vdCBDQTAeFw0y
MTA3MDExNzQxNTNaFw0zMTA2MjkxNzQxNTNaMDYxETAPBgNVBAoTCE9QQSBUZXN0
MSEwHwYDVQQDExhPUEEgVGVzdCBJbnRlcm1lZGlhdGUgQ0EwWTATBgcqhkjOPQIB
BggqhkjOPQMBBwNCAARvXQa7fy476gDI81nqLYb2SnD459WxBmU0hk2bA3ZuNtI+
H20KXz6ISmxH3MZ2WBm6rOy7y4Gn+WMCJuxzcl5jo2YwZDAOBgNVHQ8BAf8EBAMC
AQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuslZNjJl0V8I1Gj17IID
ALy/9WEwHwYDVR0jBBgwFoAU3IetKsULy5fgHw33Gl5o70/Br6cwCgYIKoZIzj0E
AwIDSAAwRQIgUwsYApW9Tsm6AstWswaKGie0srB4FUkUbfKwWmUI2JgCIQCBTySN
MF+EiQAMKyz/N9KUuXEckC356WvKcyJaYYcV0w==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8zCCAZqgAwIBAgIRAID4gPKg7DDiuOfzUYFSXLAwCgYIKoZIzj0EAwIwNjER
MA8GA1UEChMIT1BBIFRlc3QxITAfBgNVBAMTGE9QQSBUZXN0IEludGVybWVkaWF0
ZSBDQTAeFw0yMTA3MDUxNzQ5NTBaFw0zNjA3MDExNzQ5NDdaMCUxIzAhBgNVBAMT
Gm5vdGFyZWFsc2l0ZS5vcGEubG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAE1YSXZXeaGGL+XeYyoPi/QdA39Ds4fgxSHJTMh+js393kByPm2PNtFkem
tUii3KCRJw3SEh3z0JWr/9y4+ua2L6OBmTCBljAOBgNVHQ8BAf8EBAMCB4AwHQYD
VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBRL0P0g17viZHo9
CnXe3ZQJm48LXTAfBgNVHSMEGDAWgBS6yVk2MmXRXwjUaPXsggMAvL/1YTAlBgNV
HREEHjAcghpub3RhcmVhbHNpdGUub3BhLmxvY2FsaG9zdDAKBggqhkjOPQQDAgNH
ADBEAiAtmZewL94ijN0YwUGaJM9BXCaoTQPwkzugqjCj+K912QIgKKFvbPu4asrE
nwy7dzejHmQUcZ/aUNbc4VTbiv15ESk=
-----END CERTIFICATE-----
`
value := crypto.x509.parse_and_verify_certificates(certs)
result := {
"valid": value[0],
"certs": [c|
some cert in value[1]
c := {
"CN": cert.Subject.CommonName,
"DNS": cert.DNSNames,
"URI": cert.URIStrings,
}
],
}
note: cryptox509parseandverifycertificates/base_case
query: data.test.result = x
want_result:
- x:
certs:
- CN: notarealsite.opa.localhost
DNS:
- notarealsite.opa.localhost
URI:
- CN: OPA Test Intermediate CA
DNS:
URI:
- CN: OPA Test Root CA
DNS:
URI:
valid: true
- data:
modules:
- |
package test
import future.keywords
certs := `-----BEGIN CERTIFICATE-----
MIIB1TCCAXugAwIBAgIIKIoxsnMwJJ4wCgYIKoZIzj0EAwIwPTELMAkGA1UEBhMC
R0IxEDAOBgNVBAoTB0V4YW1wbGUxHDAaBgNVBAUTEzI5MjEyMDE5NTA4MDk2NjI2
MjIwIBcNMjMxMTI5MTc1NTQ2WhgPMjEyMzExMDUxNzU1NDZaMD0xCzAJBgNVBAYT
AkdCMRAwDgYDVQQKEwdFeGFtcGxlMRwwGgYDVQQFExMyOTIxMjAxOTUwODA5NjYy
NjIyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkvI9ddM0SuP9LvBWS1y64fuK
ELCjVF5W3FSKm3azKEkDi8Eq1I1UM80MgCjC5ChNNyM4+cmVUDrCkTl3SqRxa6Nj
MGEwDgYDVR0PAQH/BAQDAgIEMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF7H
A8n3mXXnwUP0ypMJ9JwY5wasMB8GA1UdEQQYMBaGFHNwaWZmZTovL2V4YW1wbGUu
Y29tMAoGCCqGSM49BAMCA0gAMEUCIByB2l5RIWmaU8qcRv13qigbB9BV/F2raEk+
pRQnsUcgAiEA9OvBpPKC/FBkI5vVvR7WgK5sGPna4+a0RkXxRQgN2jM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB1jCCAXygAwIBAgIIV9914tIKKkMwCgYIKoZIzj0EAwIwPTELMAkGA1UEBhMC
R0IxEDAOBgNVBAoTB0V4YW1wbGUxHDAaBgNVBAUTEzI5MjEyMDE5NTA4MDk2NjI2
MjIwIBcNMjMxMTI5MTc1NTQ2WhgPMjEyMjExMDUxNzU1NDZaMD0xCzAJBgNVBAYT
AkdCMRAwDgYDVQQKEwdFeGFtcGxlMRwwGgYDVQQFExM2MzMxOTA5MjE4MTUzMTQ2
OTQ3MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMoy2UqvC8zL3sPfLNvG1nX5p
6hhEyDjFtokORB4VkKiPXFryIFn8XHG0ipz6aKSwVMoDT2T/YXP/wWpVwPJCi6Nk
MGIwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATAMBgNVHRMBAf8EAjAAMCMGA1UdEQQcMBqGGHNwaWZmZTovL2V4YW1wbGUuY29t
L29wYTAKBggqhkjOPQQDAgNIADBFAiBEmdSKGj2+9J5SQPIAmwdxpVTOxqmVQv2x
Vvita/AmowIhAOyX/alNJxL4iCfKUNwlC2lYxGhuWopWgB1Q32bQhTEh
-----END CERTIFICATE-----
`
value := crypto.x509.parse_and_verify_certificates(certs)
result := {
"valid": value[0],
"certs": [c|
some cert in value[1]
c := {
"CN": cert.Subject.CommonName,
"DNS": cert.DNSNames,
"URI": cert.URIStrings,
}
],
}
note: cryptox509parseandverifycertificates/uri_strings
query: data.test.result = x
want_result:
- x:
certs:
- CN: ''
DNS: null
URI:
- spiffe://example.com/opa
- CN: ''
DNS: null
URI:
- spiffe://example.com
valid: true

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cases:
- data:
modules:
- |
package generated
certs = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUIxekNDQVh5Z0F3SUJBZ0lJZGxpT1dVY1NXM3N3Q2dZSUtvWkl6ajBFQXdJd1BURUxNQWtHQTFVRUJoTUMKUjBJeEVEQU9CZ05WQkFvVEIwVjRZVzF3YkdVeEhEQWFCZ05WQkFVVEV6RTFPREV4TnpnNU56UTJPRFkxTmpneQpOalF3SUJjTk1qTXhNVEl3TVRZMU5USTRXaGdQTWpFeU1qRXdNamN4TmpVMU1qaGFNRDB4Q3pBSkJnTlZCQVlUCkFrZENNUkF3RGdZRFZRUUtFd2RGZUdGdGNHeGxNUnd3R2dZRFZRUUZFeE00TlRJM056SXlOREE0TlRJeE5qVXoKTVRFMU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXp0UDNrQnNpQXY4UUF5eWxUalJZSFlWegpjWTB5YmpBdC9VbWpZb3Fxb0o4SEtIdXF1ckRaUmVwa05qUXdwV3pmZndZZ0xaNk42SisyVUlPdlZ0TDZEcU5rCk1HSXdEZ1lEVlIwUEFRSC9CQVFEQWdlQU1CMEdBMVVkSlFRV01CUUdDQ3NHQVFVRkJ3TUNCZ2dyQmdFRkJRY0QKQVRBTUJnTlZIUk1CQWY4RUFqQUFNQ01HQTFVZEVRUWNNQnFHR0hOd2FXWm1aVG92TDJWNFlXMXdiR1V1WTI5dApMMjl3WVRBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQXlRNDhPd25lTHkzMjZqYitEUjd5RjJhcS94Wnl1cW9qCitUU3ZLVVB5NEU0Q0lRQ0VMUlp3K0dWTjhJR0drVGV4MGxxTDNxY21mWldJbm15VitrbnQ0d3p3L3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
uri_strings = crypto.x509.parse_certificates(certs)[0].URIStrings
note: cryptox509parsecertificates/uri_strings
query: data.generated.uri_strings = x
want_result:
- x:
- spiffe://example.com/opa
- data:
modules:
- |
package generated
certs = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNTakNDQWJPZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRMEZBREJDTVFzd0NRWURWUVFHRXdKMWN6RUwKTUFrR0ExVUVDQXdDUTBFeEVEQU9CZ05WQkFvTUIwVjRZVzF3YkdVeEZEQVNCZ05WQkFNTUMyVjRZVzF3YkdVdQpZMjl0TUI0WERUSXpNVEV5T1RFMk5ESXdPRm9YRFRJME1URXlPREUyTkRJd09Gb3dRakVMTUFrR0ExVUVCaE1DCmRYTXhDekFKQmdOVkJBZ01Ba05CTVJBd0RnWURWUVFLREFkRmVHRnRjR3hsTVJRd0VnWURWUVFEREF0bGVHRnQKY0d4bExtTnZiVENCbnpBTkJna3Foa2lHOXcwQkFRRUZBQU9CalFBd2dZa0NnWUVBempOT1puY05DL25MdEZQYwpUNnNlSzZ0ditTbU9GaGk3NVBKRm9sQ0dFZUFiTHJHTzhaUmR2cXY2OStTTk41MUhrNFBJUDUrejk4aHZIdWJQClVtcGdOMVdVM3FKK2tOVTJXL3poR3pLMTdIL2c3YjVJTjRHZmx3bXJlRWZscnRicnZKSGRlRkVhVGtmYnVld0YKVmZvLzRiaG0yYUthczNHcUo3RnlBNDVxeVUwQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZOUStDMUVOK0dSYwpGS1dyTll6ZWdnbFc3TE9lTUI4R0ExVWRJd1FZTUJhQUZOUStDMUVOK0dSY0ZLV3JOWXplZ2dsVzdMT2VNQXdHCkExVWRFd1FGTUFNQkFmOHdEUVlKS29aSWh2Y05BUUVOQlFBRGdZRUF1cXdVVWVXbTFJaURRbmphK1hqd1VCaXUKQXBYWEx5NlFZRG9jUkhoRHlJS3BKSWRJOXltNi9RcVhkOFQ2WGlYUTJDbFNJbGxBSTByQWJYNUZvYzNxaWRkUAp0d2huT1pxd3NZdFhUNy9XOHFLSm5FVnhZckJuRmZSdk9SU3ZlOEtwSDErVHQ2elZEYlJ5bENacTR1TTNrZXN2CmJabXlVdlM1bldBVm44ZmhFdUU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0="
uri_strings = crypto.x509.parse_certificates(certs)[0].URIStrings
note: cryptox509parsecertificates/uri_strings_no_uris
query: data.generated.uri_strings = x
want_result:
- x: null
26 changes: 24 additions & 2 deletions topdown/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,36 @@ func builtinCryptoX509ParseCertificates(_ BuiltinContext, operands []*ast.Term,
return err
}

v, err := ast.InterfaceToValue(certs)
v, err := ast.InterfaceToValue(extendCertificates(certs))
if err != nil {
return err
}

return iter(ast.NewTerm(v))
}

// extendedCert is a wrapper around x509.Certificate that adds additional fields for JSON serialization.
type extendedCert struct {
x509.Certificate
URIStrings []string
}

func extendCertificates(certs []*x509.Certificate) []extendedCert {
// add a field to certs containing the URIs as strings
processedCerts := make([]extendedCert, len(certs))

for i, cert := range certs {
processedCerts[i].Certificate = *cert
if cert.URIs != nil {
processedCerts[i].URIStrings = make([]string, len(cert.URIs))
for j, uri := range cert.URIs {
processedCerts[i].URIStrings[j] = uri.String()
}
}
}
return processedCerts
}

func builtinCryptoX509ParseAndVerifyCertificates(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {

a := operands[0].Value
Expand All @@ -87,7 +109,7 @@ func builtinCryptoX509ParseAndVerifyCertificates(_ BuiltinContext, operands []*a
return iter(invalid)
}

value, err := ast.InterfaceToValue(verified)
value, err := ast.InterfaceToValue(extendCertificates(verified))
if err != nil {
return err
}
Expand Down

0 comments on commit 7a32e8f

Please sign in to comment.