mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-26 22:48:07 +02:00
add mTLS UserPrincipalName SAN match (#5177)
Add a new 'user_principal_name' type to the downstream mTLS match_subject_alt_names option. This corresponds to the 'OtherName' type with type-id 1.3.6.1.4.1.311.20.2.3 and a UTF8String value. Add support for UserPrincipalName SAN matching to the policy evaluator.
This commit is contained in:
parent
b0606d9283
commit
dbedfc586f
9 changed files with 416 additions and 84 deletions
|
@ -3,14 +3,18 @@ package evaluator
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/asn1"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru/v2"
|
lru "github.com/hashicorp/golang-lru/v2"
|
||||||
|
"golang.org/x/crypto/cryptobyte"
|
||||||
|
cb_asn1 "golang.org/x/crypto/cryptobyte/asn1"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
|
@ -135,6 +139,16 @@ func verifyClientCertificate(
|
||||||
crls map[string]*x509.RevocationList,
|
crls map[string]*x509.RevocationList,
|
||||||
constraints ClientCertConstraints,
|
constraints ClientCertConstraints,
|
||||||
) error {
|
) error {
|
||||||
|
// If a SubjectAltName extension is:
|
||||||
|
// - marked as critical, and
|
||||||
|
// - contains only name types that are not recognized by the Go standard
|
||||||
|
// library (i.e. no DNS, email address, IP address, or URI names)
|
||||||
|
// then the Go parsing code will add it to the UnhandleCriticalExtensions
|
||||||
|
// field of the Certificate struct. This will fail the Verify() call below.
|
||||||
|
// Because we support other SAN matching checks, let's avoid this behavior.
|
||||||
|
cert.UnhandledCriticalExtensions = slices.DeleteFunc(cert.UnhandledCriticalExtensions,
|
||||||
|
func(oid asn1.ObjectIdentifier) bool { return oid.Equal(oidSubjectAltName) })
|
||||||
|
|
||||||
chains, err := cert.Verify(x509.VerifyOptions{
|
chains, err := cert.Verify(x509.VerifyOptions{
|
||||||
Roots: roots,
|
Roots: roots,
|
||||||
Intermediates: intermediates,
|
Intermediates: intermediates,
|
||||||
|
@ -242,6 +256,17 @@ func validateClientCertificateSANs(chain []*x509.Certificate, matchers SANMatche
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if r := matchers[config.SANTypeUserPrincipalName]; r != nil {
|
||||||
|
names, err := getUserPrincipalNamesFromCert(cert)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, name := range names {
|
||||||
|
if r.MatchString(name) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return errNoSANMatch
|
return errNoSANMatch
|
||||||
}
|
}
|
||||||
|
@ -256,3 +281,56 @@ func parseCertificate(pemStr string) (*x509.Certificate, error) {
|
||||||
}
|
}
|
||||||
return x509.ParseCertificate(block.Bytes)
|
return x509.ParseCertificate(block.Bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
oidSubjectAltName = asn1.ObjectIdentifier{2, 5, 29, 17}
|
||||||
|
oidUserPrincipalName = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 20, 2, 3}
|
||||||
|
otherNameTag = cb_asn1.Tag(0).Constructed().ContextSpecific()
|
||||||
|
otherNameValueTag = cb_asn1.Tag(0).Constructed().ContextSpecific()
|
||||||
|
)
|
||||||
|
|
||||||
|
func getUserPrincipalNamesFromSAN(raw []byte) ([]string, error) {
|
||||||
|
san := cryptobyte.String(raw)
|
||||||
|
var generalNames cryptobyte.String
|
||||||
|
if !san.ReadASN1(&generalNames, cb_asn1.SEQUENCE) {
|
||||||
|
return nil, errors.New("error reading GeneralNames sequence")
|
||||||
|
}
|
||||||
|
var upns []string
|
||||||
|
for !generalNames.Empty() {
|
||||||
|
var name cryptobyte.String
|
||||||
|
var tag cb_asn1.Tag
|
||||||
|
if !generalNames.ReadAnyASN1(&name, &tag) {
|
||||||
|
return nil, errors.New("error reading GeneralName")
|
||||||
|
} else if tag != otherNameTag {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var oid asn1.ObjectIdentifier
|
||||||
|
if !name.ReadASN1ObjectIdentifier(&oid) {
|
||||||
|
return nil, errors.New("error reading OtherName type ID")
|
||||||
|
} else if !oid.Equal(oidUserPrincipalName) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var value cryptobyte.String
|
||||||
|
if !name.ReadASN1(&value, otherNameValueTag) {
|
||||||
|
return nil, errors.New("error reading UserPrincipalName value")
|
||||||
|
}
|
||||||
|
|
||||||
|
var utf8string cryptobyte.String
|
||||||
|
if !value.ReadASN1(&utf8string, cb_asn1.UTF8String) {
|
||||||
|
return nil, errors.New("error reading UserPrincipalName: expected UTF8String")
|
||||||
|
}
|
||||||
|
upns = append(upns, string(utf8string))
|
||||||
|
}
|
||||||
|
return upns, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserPrincipalNamesFromCert(cert *x509.Certificate) ([]string, error) {
|
||||||
|
for _, ext := range cert.Extensions {
|
||||||
|
if ext.Id.Equal(oidSubjectAltName) {
|
||||||
|
return getUserPrincipalNamesFromSAN(ext.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package evaluator
|
package evaluator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/asn1"
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -19,133 +20,146 @@ const (
|
||||||
testCA = `
|
testCA = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBaDCCAQ6gAwIBAgICEAAwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
MIIBaDCCAQ6gAwIBAgICEAAwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAaMRgw
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAaMRgw
|
||||||
FgYDVQQDEw9UcnVzdGVkIFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
|
FgYDVQQDEw9UcnVzdGVkIFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
|
||||||
AAR2/RkzmSK6paoeTKFx1Bd52ZCg29ulJlMxFdSZT8FlmmaK9mN6KWwO+NHYObiW
|
AAS+oiuwekZ86TUjhJQV12ZjAlt+3Zy/VkRuj7tA7wtFwEs8w77iQryIQO/DEccY
|
||||||
y3AQuoSTrZXlrlRW5ANvMI+io0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
|
9coUjLfWFc/V5LTsNlYTh4B8o0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
|
||||||
BAUwAwEB/zAdBgNVHQ4EFgQUJGFVU2UOvOVgaY9YcCUiunGpiCQwCgYIKoZIzj0E
|
BAUwAwEB/zAdBgNVHQ4EFgQU4hTNmxqsRHUZ8Nk/m03RHo6HGyAwCgYIKoZIzj0E
|
||||||
AwIDSAAwRQIhAMU5/NjpitOSbUobtjeOriPH8JRo9qy1iFyeVNAcdVvgAiAewq2A
|
AwIDSAAwRQIhAMH+UKlJxWDdtKH7YRnhSefk/AxfjdjrDJhQKm4EUrVjAiAxxvdP
|
||||||
PhgzWTw5F9PJg++9i+xGQTqHs3ZirG27cCjvhQ==
|
yoEpPAq1NW/Ny9yuKE8mfRTWgu+09L3jOwDqTg==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testValidCert = `
|
testValidCert = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBYjCCAQigAwIBAgICEAEwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
MIIBYTCCAQigAwIBAgICEAEwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAeMRww
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAeMRww
|
||||||
GgYDVQQDExN0cnVzdGVkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
GgYDVQQDExN0cnVzdGVkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||||
AQcDQgAEcWa1Bz6mpsLnM1VD8gtzELjzjEp9Dopp/xWScFO9qtay5SBOeX+Ftr0O
|
AQcDQgAED3L4Hf7kBaa6E76kRaideTYPS+deD+T1+qwfD5amUF4h3dblJCQgDuWl
|
||||||
8+/RkoKHzGgZ80gr6xQyUJL3MCwVZKM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
|
p9WA7PzJioroP4HeUUVll8GF4Ngx/aM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
|
||||||
HwYDVR0jBBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwCgYIKoZIzj0EAwIDSAAw
|
HwYDVR0jBBgwFoAU4hTNmxqsRHUZ8Nk/m03RHo6HGyAwCgYIKoZIzj0EAwIDRwAw
|
||||||
RQIgXM1ogmy0vcz4lYzji5X3In1n2GLOFNTgucFPkM0GtqgCIQCsXPs/0OjSFyDR
|
RAIgeS3o3PnBZTGSM5yFuxl+xZQwItUGOvk4TUIHbLKIh+QCIGYABXVpXyaHT1/7
|
||||||
FBqAm1NqDJcxq685fS9t3VfHwapcVA==
|
xAdvB6E8eNv4/LIbPo3OKVwzLWka
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testUntrustedCert = `
|
testUntrustedCert = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBZjCCAQygAwIBAgICEAEwCgYIKoZIzj0EAwIwHDEaMBgGA1UEAxMRVW50cnVz
|
MIIBZzCCAQygAwIBAgICEAEwCgYIKoZIzj0EAwIwHDEaMBgGA1UEAxMRVW50cnVz
|
||||||
dGVkIFJvb3QgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zMzA4MDcxODAzMjFaMCAx
|
dGVkIFJvb3QgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zNDA3MjMxODA3NDlaMCAx
|
||||||
HjAcBgNVBAMTFXVudHJ1c3RlZCBjbGllbnQgY2VydDBZMBMGByqGSM49AgEGCCqG
|
HjAcBgNVBAMTFXVudHJ1c3RlZCBjbGllbnQgY2VydDBZMBMGByqGSM49AgEGCCqG
|
||||||
SM49AwEHA0IABJxEIKqLhhMEm5XZXkT+p+hlC2TFyaW0HIZqoE9navJrAcUB8L2M
|
SM49AwEHA0IABD7wlyIZI0dk81W93CPi0C9EK5oWnP9jyf6ukNSfuN2/AifVyskZ
|
||||||
mVQ+/wLaCznJHLeSLn46uGH5p1hoGFqOrdajODA2MBMGA1UdJQQMMAoGCCsGAQUF
|
ZaJsC1y0x11eHQn0AKDvFZvrM5ntgtEKvTujODA2MBMGA1UdJQQMMAoGCCsGAQUF
|
||||||
BwMCMB8GA1UdIwQYMBaAFIp2rlIiSnr33ea3cGyLsX4LEYwWMAoGCCqGSM49BAMC
|
BwMCMB8GA1UdIwQYMBaAFCWSSHqA46gKGwIZH3RAYyds6hJ0MAoGCCqGSM49BAMC
|
||||||
A0gAMEUCIDtJIZJDcqIYaDXhZFs0nd0nHER8IGP9n4BBFMWewAb2AiEAlQyavOxw
|
A0kAMEYCIQDeg+lSgmzg5W85HpMjnfcbDxOwTFAuG2dBZIFm4MeZRAIhAOhReIDb
|
||||||
iTQQxt0rXB4Ox5zWpU9q68+F9BGBkQKTsBs=
|
B0ktSaPCNQOn1m0PMi4OxnSrClWV0pQzZwiM
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testRevokedCert = `
|
testRevokedCert = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBYjCCAQigAwIBAgICEAIwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
MIIBYzCCAQigAwIBAgICEAIwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAeMRww
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAeMRww
|
||||||
GgYDVQQDExNyZXZva2VkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
GgYDVQQDExNyZXZva2VkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||||
AQcDQgAEcnoO4EM72C7xL31RE9e6m9YJYyF6E4JloASECd8mdiXPlMXIjq8MZHB5
|
AQcDQgAE5sRZhAupCq3X0KWDNRfJh0H0jOGNOQawaKFejCQQ0t2kXCvfkvcTlGWo
|
||||||
28mFAVQNE7erAtBftID1SbuY4IpXxqM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
|
Cjlgtc885wLI5n0KPG5ugN1Zk7nrlqM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
|
||||||
HwYDVR0jBBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwCgYIKoZIzj0EAwIDSAAw
|
HwYDVR0jBBgwFoAU4hTNmxqsRHUZ8Nk/m03RHo6HGyAwCgYIKoZIzj0EAwIDSQAw
|
||||||
RQIgUUETSO064YIu+VKnyRb0yBnNTjXLy3TvGuYgZI8VX0YCIQDd0gyNEC5YLvRN
|
RgIhAIzYBLOWFTLdWvf//svgjUAtjW51/qvuR+oUQSpyJEs7AiEAlmGwYPnUpVah
|
||||||
njxfnLoimp+TzTVzvsCokUbNSNRKJA==
|
1ri42dcuvYe6u+E7yWQOvF9MRVBQFrI=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testCRL = `
|
testCRL = `
|
||||||
-----BEGIN X509 CRL-----
|
-----BEGIN X509 CRL-----
|
||||||
MIHeMIGFAgEBMAoGCCqGSM49BAMCMBoxGDAWBgNVBAMTD1RydXN0ZWQgUm9vdCBD
|
MIHeMIGFAgEBMAoGCCqGSM49BAMCMBoxGDAWBgNVBAMTD1RydXN0ZWQgUm9vdCBD
|
||||||
QRgPMDAwMTAxMDEwMDAwMDBaMBUwEwICEAIXDTIzMDgxMDE4MDMyMVqgMDAuMB8G
|
QRgPMDAwMTAxMDEwMDAwMDBaMBUwEwICEAIXDTI0MDcyNTE4MDc0OVqgMDAuMB8G
|
||||||
A1UdIwQYMBaAFCRhVVNlDrzlYGmPWHAlIrpxqYgkMAsGA1UdFAQEAgIgADAKBggq
|
A1UdIwQYMBaAFOIUzZsarER1GfDZP5tN0R6OhxsgMAsGA1UdFAQEAgIgADAKBggq
|
||||||
hkjOPQQDAgNIADBFAiEAumtTtjiQt1VsbsEnyr+xbpK0KmzKvkpxIVgE1M9CND0C
|
hkjOPQQDAgNIADBFAiAMtFj+hNOleIXozxi6QJJrRtS/7LyYrDuRju/CKvbxhwIh
|
||||||
IA8zx5clcaGIT5xRnBLZW7RwA37IOmB+7zjAuJQpmKKp
|
AKXWklJEPCyzzhIt4ETiesXhMu8UUngRhuWwGLFQoyJH
|
||||||
-----END X509 CRL-----
|
-----END X509 CRL-----
|
||||||
`
|
`
|
||||||
testIntermediateCA = `
|
testIntermediateCA = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBkTCCATegAwIBAgICEAMwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
MIIBkTCCATegAwIBAgICEAMwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAiMSAw
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAiMSAw
|
||||||
HgYDVQQDExdUcnVzdGVkIEludGVybWVkaWF0ZSBDQTBZMBMGByqGSM49AgEGCCqG
|
HgYDVQQDExdUcnVzdGVkIEludGVybWVkaWF0ZSBDQTBZMBMGByqGSM49AgEGCCqG
|
||||||
SM49AwEHA0IABMY+zxL/2dNORuha3uVVOXZYIkTpa9V8N9UVrM15HOHkrdLlz1qk
|
SM49AwEHA0IABCSif6O54Y74VpVNMHl37iECM1RKCjzJgu7a3CE2O8W7IdO3vQVT
|
||||||
4wbePkkoGtNRzoayb0iZqeA4YjOxqyPG8emjYzBhMA4GA1UdDwEB/wQEAwIBBjAP
|
X4FTcGjzR+WaQNdssuAJ8ch5lxDbOQDPT4WjYzBhMA4GA1UdDwEB/wQEAwIBBjAP
|
||||||
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQpGNmcLLM3vHiOADYGPDQL8AhkyDAf
|
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTlu+78yKKKOakqZzrIgHoWLRMc/TAf
|
||||||
BgNVHSMEGDAWgBQkYVVTZQ685WBpj1hwJSK6camIJDAKBggqhkjOPQQDAgNIADBF
|
BgNVHSMEGDAWgBTiFM2bGqxEdRnw2T+bTdEejocbIDAKBggqhkjOPQQDAgNIADBF
|
||||||
AiEAnR6xrk7OCk91ymtzU+duZXDqDq35w0oO+MM8nqpac4YCIED+6c9dJKvRCc/C
|
AiB7bkMezoRqrjFzmQNzZ2smcrmKJ2ePrfNe3xFyWgQyWwIhAIIMAN2jg39P27mn
|
||||||
nP8PMxRaUsbQet1woE7Fckn5tK4N
|
r0/T4PhfiLBY8naJw7t3bW6siCaU
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testValidIntermediateCert = `
|
testValidIntermediateCert = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBdTCCARqgAwIBAgICEAAwCgYIKoZIzj0EAwIwIjEgMB4GA1UEAxMXVHJ1c3Rl
|
MIIBdTCCARqgAwIBAgICEAAwCgYIKoZIzj0EAwIwIjEgMB4GA1UEAxMXVHJ1c3Rl
|
||||||
ZCBJbnRlcm1lZGlhdGUgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zMzA4MDcxODAz
|
ZCBJbnRlcm1lZGlhdGUgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zNDA3MjMxODA3
|
||||||
MjFaMCgxJjAkBgNVBAMTHWNsaWVudCBjZXJ0IGZyb20gaW50ZXJtZWRpYXRlMFkw
|
NDlaMCgxJjAkBgNVBAMTHWNsaWVudCBjZXJ0IGZyb20gaW50ZXJtZWRpYXRlMFkw
|
||||||
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5SVyYjNRuuFXGjEmCcuVtMq7e2bmndPK
|
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErSXc3EmG1iX8r1zra1v+wOFlX3nBTj3N
|
||||||
bRJ7lJ5cc0kZSoNJes5wXOtGRFbx3+admRHq+w1XEBXOe+yRUB8kdKM4MDYwEwYD
|
g03l5a5BvAclZ4jRLyU25RAT+LoPZwCag526xCsXQ2rctamWYuftvqM4MDYwEwYD
|
||||||
VR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0jBBgwFoAUKRjZnCyzN7x4jgA2Bjw0C/AI
|
VR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0jBBgwFoAU5bvu/MiiijmpKmc6yIB6Fi0T
|
||||||
ZMgwCgYIKoZIzj0EAwIDSQAwRgIhAMj0O2wDRLoxGIPUDOmUfYxmxglOecQhSkWO
|
HP0wCgYIKoZIzj0EAwIDSQAwRgIhAOmeRu2zAnCYHUhdBlH1/+K6pHysCJJHboSO
|
||||||
NBtItSxmAiEAy0XCzvpL6XOZU3zxyCjTdJQa2RiC6YnypMaCaETzCaU=
|
781NdfTkAiEA/ABjaj2sNNUFDCl/Ayqu7ufv+o5/F6mx3tMdnWZ0rlQ=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testValidCertWithDNSSANs = `
|
testValidCertWithDNSSANs = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBlTCCATugAwIBAgICEAQwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
MIIBljCCATugAwIBAgICEAQwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAYMRYw
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAYMRYw
|
||||||
FAYDVQQDEw1jbGllbnQgY2VydCAzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
FAYDVQQDEw1jbGllbnQgY2VydCAzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
||||||
LFai39b7TYauNjg4M58f0qY6jTC7xEOhE84wTTcevZvH/t2Y7U0BBNGkvpb14yxh
|
n3orlbZpOzCKyYbyFwUWO/hYcI+uldw2Fczdas+9g02E5mtnZpprxFnnzMipF6X9
|
||||||
60vrRKZA9t9G6ZvWKcY/BKNxMG8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
PIOVTWEPJ7LRNIN2Bt8zLKNxMG8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
||||||
BBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwNwYDVR0RBDAwLoIVYS5jbGllbnQz
|
BBgwFoAU4hTNmxqsRHUZ8Nk/m03RHo6HGyAwNwYDVR0RBDAwLoIVYS5jbGllbnQz
|
||||||
LmV4YW1wbGUuY29tghViLmNsaWVudDMuZXhhbXBsZS5jb20wCgYIKoZIzj0EAwID
|
LmV4YW1wbGUuY29tghViLmNsaWVudDMuZXhhbXBsZS5jb20wCgYIKoZIzj0EAwID
|
||||||
SAAwRQIgBSw8MsKWPPcpGtuVpNJonTEthIOjIGXswxiYG49y2BECIQC5D1DCX/lY
|
SQAwRgIhAI36+egFjZ3NtLlT6xcSpTJtd6dOw/uBXxXnIiYfgoV6AiEA8Eazupyl
|
||||||
KSwF4aapPx4906VujTL+Ehj8L5ImUYcPbA==
|
xiUuFh7lEsr293NN0G7IW6tJW36bWTxYOf8=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testValidCertWithEmailSAN = `
|
testValidCertWithEmailSAN = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBezCCASKgAwIBAgICEAUwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
MIIBfDCCASKgAwIBAgICEAUwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAYMRYw
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAYMRYw
|
||||||
FAYDVQQDEw1jbGllbnQgY2VydCA0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
FAYDVQQDEw1jbGllbnQgY2VydCA0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
||||||
WvX8BnCrzUSpLrYka8ed+bz6/HoXUvq5nRqysKe0nGYSsXKRjxLdCG8AKsoGIQIv
|
IIdyrCKf7142FXGd1ZU+eKkUu73heahK7iWOpCC3gMks12KKnpkcrt5ezQ1LM51P
|
||||||
KOQScf/4TJUNIUY4XOsFI6NYMFYwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
CI/yWYdmLPHgmzychJIiF6NYMFYwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
||||||
BBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwHgYDVR0RBBcwFYETY2xpZW50NEBl
|
BBgwFoAU4hTNmxqsRHUZ8Nk/m03RHo6HGyAwHgYDVR0RBBcwFYETY2xpZW50NEBl
|
||||||
eGFtcGxlLmNvbTAKBggqhkjOPQQDAgNHADBEAiAMYGTjUBqgnai8UL3B/iQkCkMb
|
eGFtcGxlLmNvbTAKBggqhkjOPQQDAgNIADBFAiBeMogtQTVB9vi+snua/DfcKu18
|
||||||
xgCC1ZYdZaJ1RBwFfgIgIhjQZ2s6dTaah/LzYJ9ZwMvSA86XQvzTVSuT6s+RJw0=
|
puJx/UGqXfwpYMObiwIhANwPL6FgGC208+LVca6r09BCh7QsoJCwCdAMTd5V7Pup
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testValidCertWithIPSAN = `
|
testValidCertWithIPSAN = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBbTCCAROgAwIBAgICEAYwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
MIIBbTCCAROgAwIBAgICEAYwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAYMRYw
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAYMRYw
|
||||||
FAYDVQQDEw1jbGllbnQgY2VydCA1MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
FAYDVQQDEw1jbGllbnQgY2VydCA1MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
||||||
6+9BE+aomrR2Mdnx4iFY63t0hsVD6rYaHBW1b9roFQX6Cor4YeUfkEEF4LrGeAyb
|
9JayRtfR5I0U6pk/FMf+LwdAY1+toL0CBwgj6UOgRPQKj2osSwJvGSQg3OBMyoMW
|
||||||
wcqb6G1ExgNyjEh10Ai1M6NJMEcwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
48UoykPMuEx9RgJAdG2rLaNJMEcwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
||||||
BBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwDwYDVR0RBAgwBocEwKgKCjAKBggq
|
BBgwFoAU4hTNmxqsRHUZ8Nk/m03RHo6HGyAwDwYDVR0RBAgwBocEwKgKCjAKBggq
|
||||||
hkjOPQQDAgNIADBFAiEA/mq32YZZAacOH/P/wjvfD1n74DD/GkhW4kfS72Z0oGQC
|
hkjOPQQDAgNIADBFAiBxtRMWbiwa0kSftQ7KWymaEQzTNwa4DlanaJFitHX7wwIh
|
||||||
IAQ+L8E78JOLaPWXiL7WFpVrb0hOHkV2m9Qw4GB41mUN
|
ALbkwkvT/egNexdQIL8SpP0owUiXvuB/OkmY49XQigub
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
testValidCertWithURISAN = `
|
testValidCertWithURISAN = `
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBhTCCASugAwIBAgICEAcwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
MIIBhTCCASugAwIBAgICEAcwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAYMRYw
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAYMRYw
|
||||||
FAYDVQQDEw1jbGllbnQgY2VydCA2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
FAYDVQQDEw1jbGllbnQgY2VydCA2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
||||||
7mHladapSY5PlVYToL1dHr0tJPGe5XVP8DSZJz+WWyS9tWsuEsK6P5yeZrbWASOX
|
vpHXNca1VPMtp5x3cAgAUjfGEkrJ3oaQmRvbPnbOuxP91GSh1qFDOcnQlLQSI9WV
|
||||||
foH7iVIdx3DMyukGsvMX+KNhMF8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
HbaWsCYEQ/cEvCL45/PDqqNhMF8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
||||||
BBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwJwYDVR0RBCAwHoYcc3BpZmZlOi8v
|
BBgwFoAU4hTNmxqsRHUZ8Nk/m03RHo6HGyAwJwYDVR0RBCAwHoYcc3BpZmZlOi8v
|
||||||
ZXhhbXBsZS5jb20vZm9vL2JhcjAKBggqhkjOPQQDAgNIADBFAiAhzElKeGJzp2zP
|
ZXhhbXBsZS5jb20vZm9vL2JhcjAKBggqhkjOPQQDAgNIADBFAiEA0uz8g6/A+9p9
|
||||||
GOTUEy0f6b2tvMYGDLQxCcp4bc4QuQIhAPwX4Y3Cr7uazQlbwL6D51y9NCcDyj3D
|
AnNH20Sk6UiXwuKvy1pxk7TeMd02o6ACIBMsLVs+WIWZLht52+FEUJbpNXSF+IY+
|
||||||
Z18vZNxm9ZR1
|
e4rx7Ac0KxRL
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
`
|
||||||
|
testValidCertWithUPNSAN = `
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBiDCCAS2gAwIBAgICEAcwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
|
||||||
|
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzQwNzIzMTgwNzQ5WjAYMRYw
|
||||||
|
FAYDVQQDEw1jbGllbnQgY2VydCA3MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
||||||
|
QfxgDFsW27yUCmT990CwIVQexBdQ+dYRWuOHCnC+dGYESUcU6913hIEZEOwuqvwm
|
||||||
|
eKCX+NOZ+kXiGSxqD+F7C6NjMGEwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
|
||||||
|
BBgwFoAU4hTNmxqsRHUZ8Nk/m03RHo6HGyAwKQYDVR0RAQH/BB8wHaAbBgorBgEE
|
||||||
|
AYI3FAIDoA0MC3Rlc3RfZGV2aWNlMAoGCCqGSM49BAMCA0kAMEYCIQDw8sM7Eu5F
|
||||||
|
hTgx7XMlMsIlUTs0/n1WrMlr5RcdPlG9tgIhAK9o4Dtlr2bqW7w9RSidNLT6loCJ
|
||||||
|
dgwikvJkMOfcuexx
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
@ -366,6 +380,25 @@ func Test_isValidClientCertificate(t *testing.T) {
|
||||||
assert.NoError(t, err, "should not return an error")
|
assert.NoError(t, err, "should not return an error")
|
||||||
assert.False(t, valid, "should return false")
|
assert.False(t, valid, "should return false")
|
||||||
})
|
})
|
||||||
|
t.Run("UserPrincipalName SAN", func(t *testing.T) {
|
||||||
|
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
|
||||||
|
Presented: true,
|
||||||
|
Leaf: testValidCertWithUPNSAN,
|
||||||
|
}, ClientCertConstraints{SANMatchers: SANMatchers{
|
||||||
|
config.SANTypeUserPrincipalName: regexp.MustCompile(`^test_device$`),
|
||||||
|
}})
|
||||||
|
assert.NoError(t, err, "should not return an error")
|
||||||
|
assert.True(t, valid, "should return true")
|
||||||
|
|
||||||
|
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
|
||||||
|
Presented: true,
|
||||||
|
Leaf: testValidCertWithURISAN,
|
||||||
|
}, ClientCertConstraints{SANMatchers: SANMatchers{
|
||||||
|
config.SANTypeDNS: regexp.MustCompile(`^test-device$`), // mismatched type
|
||||||
|
}})
|
||||||
|
assert.NoError(t, err, "should not return an error")
|
||||||
|
assert.False(t, valid, "should return false")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClientCertConstraintsFromConfig(t *testing.T) {
|
func TestClientCertConstraintsFromConfig(t *testing.T) {
|
||||||
|
@ -452,3 +485,147 @@ func TestClientCertConstraintsFromConfig(t *testing.T) {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetUserPrincipalNamesFromSAN(t *testing.T) {
|
||||||
|
type OtherName[T any] struct {
|
||||||
|
TypeID asn1.ObjectIdentifier
|
||||||
|
Value T `asn1:"tag:0"`
|
||||||
|
}
|
||||||
|
type PrintableString struct {
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
type IA5String struct {
|
||||||
|
Value string `asn1:"ia5"`
|
||||||
|
}
|
||||||
|
type UTF8String struct {
|
||||||
|
Value string `asn1:"utf8"`
|
||||||
|
}
|
||||||
|
upn := func(name string) OtherName[UTF8String] {
|
||||||
|
return OtherName[UTF8String]{
|
||||||
|
TypeID: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 20, 2, 3},
|
||||||
|
Value: UTF8String{name},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("OneUserPrincipalName", func(t *testing.T) {
|
||||||
|
type SAN struct {
|
||||||
|
UPN OtherName[UTF8String] `asn1:"tag:0"`
|
||||||
|
}
|
||||||
|
san, err := asn1.Marshal(SAN{upn("hello")})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(san)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []string{"hello"}, names)
|
||||||
|
})
|
||||||
|
t.Run("MultipleUserPrincipalNames", func(t *testing.T) {
|
||||||
|
type SAN struct {
|
||||||
|
UPN1 OtherName[UTF8String] `asn1:"tag:0"`
|
||||||
|
UPN2 OtherName[UTF8String] `asn1:"tag:0"`
|
||||||
|
UPN3 OtherName[UTF8String] `asn1:"tag:0"`
|
||||||
|
}
|
||||||
|
san, err := asn1.Marshal(SAN{upn("foo"), upn("bar"), upn("baz")})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(san)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []string{"foo", "bar", "baz"}, names)
|
||||||
|
})
|
||||||
|
t.Run("NoUserPrincipalName", func(t *testing.T) {
|
||||||
|
type SAN struct {
|
||||||
|
DNS string `asn1:"tag:2,ia5"`
|
||||||
|
IP []byte `asn1:"tag:7"`
|
||||||
|
Email string `asn1:"tag:1,ia5"`
|
||||||
|
}
|
||||||
|
san, err := asn1.Marshal(SAN{
|
||||||
|
"localhost",
|
||||||
|
[]byte{127, 0, 0, 1},
|
||||||
|
"me@example.com",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(san)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, names)
|
||||||
|
})
|
||||||
|
t.Run("MultipleNameTypes", func(t *testing.T) {
|
||||||
|
type SAN struct {
|
||||||
|
DNS1 string `asn1:"tag:2,ia5"`
|
||||||
|
DNS2 string `asn1:"tag:2,ia5"`
|
||||||
|
Other1 OtherName[IA5String] `asn1:"tag:0"`
|
||||||
|
Other2 OtherName[UTF8String] `asn1:"tag:0"`
|
||||||
|
Other3 OtherName[PrintableString] `asn1:"tag:0"`
|
||||||
|
}
|
||||||
|
san, err := asn1.Marshal(SAN{
|
||||||
|
"example.com",
|
||||||
|
"example.org",
|
||||||
|
OtherName[IA5String]{
|
||||||
|
TypeID: asn1.ObjectIdentifier{1, 1, 1, 1},
|
||||||
|
Value: IA5String{"IA5String"},
|
||||||
|
},
|
||||||
|
upn("UserPrincipalName"),
|
||||||
|
OtherName[PrintableString]{
|
||||||
|
TypeID: asn1.ObjectIdentifier{1, 1, 1, 2},
|
||||||
|
Value: PrintableString{"PrintableString"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(san)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []string{"UserPrincipalName"}, names)
|
||||||
|
})
|
||||||
|
t.Run("UserPrincipalNameWrongValueType", func(t *testing.T) {
|
||||||
|
type SAN struct {
|
||||||
|
UPN OtherName[PrintableString] `asn1:"tag:0"`
|
||||||
|
}
|
||||||
|
san, err := asn1.Marshal(SAN{
|
||||||
|
OtherName[PrintableString]{
|
||||||
|
TypeID: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 20, 2, 3},
|
||||||
|
Value: PrintableString{"PrintableString"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(san)
|
||||||
|
assert.ErrorContains(t, err, "expected UTF8String")
|
||||||
|
assert.Empty(t, names)
|
||||||
|
})
|
||||||
|
t.Run("EmptySAN", func(t *testing.T) {
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(nil)
|
||||||
|
assert.ErrorContains(t, err, "error reading GeneralNames sequence")
|
||||||
|
assert.Empty(t, names)
|
||||||
|
})
|
||||||
|
t.Run("TruncatedGeneralName", func(t *testing.T) {
|
||||||
|
san := []byte{0x30, 0x02, 0x82, 0x05 /* 5 more bytes expected */}
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(san)
|
||||||
|
assert.ErrorContains(t, err, "error reading GeneralName")
|
||||||
|
assert.Empty(t, names)
|
||||||
|
})
|
||||||
|
t.Run("OtherNameWrongTypeIDType", func(t *testing.T) {
|
||||||
|
san := []byte{0x30, 0x06, 0xa0, 0x04, 0x02 /* type Integer, not OID */, 0x02, 0x46, 0x01}
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(san)
|
||||||
|
assert.ErrorContains(t, err, "error reading OtherName type ID")
|
||||||
|
assert.Empty(t, names)
|
||||||
|
})
|
||||||
|
t.Run("UserPrincipalNameWrongValueTag", func(t *testing.T) {
|
||||||
|
type BadOtherName struct {
|
||||||
|
TypeID asn1.ObjectIdentifier
|
||||||
|
Value UTF8String `asn1:"tag:1"` // instead of tag 0
|
||||||
|
}
|
||||||
|
type SAN struct {
|
||||||
|
UPN BadOtherName `asn1:"tag:0"`
|
||||||
|
}
|
||||||
|
san, err := asn1.Marshal(SAN{
|
||||||
|
UPN: BadOtherName{
|
||||||
|
TypeID: oidUserPrincipalName,
|
||||||
|
Value: UTF8String{"hello"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
names, err := getUserPrincipalNamesFromSAN(san)
|
||||||
|
assert.ErrorContains(t, err, "error reading UserPrincipalName value")
|
||||||
|
assert.Empty(t, names)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
@ -68,6 +69,33 @@ func newCRL(
|
||||||
return string(pem.EncodeToMemory(&pem.Block{Type: "X509 CRL", Bytes: der}))
|
return string(pem.EncodeToMemory(&pem.Block{Type: "X509 CRL", Bytes: der}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a raw SubjectAltName extension with a single UserPrincipalName.
|
||||||
|
func newSANUserPrincipalName(upnValue string) []byte {
|
||||||
|
type UPN struct {
|
||||||
|
UTF8String string `asn1:"utf8"`
|
||||||
|
}
|
||||||
|
type OtherName struct {
|
||||||
|
OID asn1.ObjectIdentifier
|
||||||
|
Value UPN `asn1:"tag:0"`
|
||||||
|
}
|
||||||
|
type GeneralNames struct {
|
||||||
|
OtherName OtherName `asn1:"tag:0"`
|
||||||
|
}
|
||||||
|
san, err := asn1.Marshal(GeneralNames{
|
||||||
|
OtherName: OtherName{
|
||||||
|
OID: asn1.ObjectIdentifier{
|
||||||
|
1, 3, 6, 1, 4, 1, 311, 20, 2, 3},
|
||||||
|
Value: UPN{
|
||||||
|
UTF8String: upnValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
return san
|
||||||
|
}
|
||||||
|
|
||||||
// Generates new test certificates and CRLs.
|
// Generates new test certificates and CRLs.
|
||||||
func main() {
|
func main() {
|
||||||
notAfter := time.Now().Add(3650 * 24 * time.Hour)
|
notAfter := time.Now().Add(3650 * 24 * time.Hour)
|
||||||
|
@ -190,6 +218,20 @@ func main() {
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||||
}, rootCA, rootKey)
|
}, rootCA, rootKey)
|
||||||
|
|
||||||
|
trustedClientCert7PEM, _, _ := newCertificate(&x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(0x1007),
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: "client cert 7",
|
||||||
|
},
|
||||||
|
NotAfter: notAfter,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||||
|
ExtraExtensions: []pkix.Extension{{
|
||||||
|
Id: asn1.ObjectIdentifier{2, 5, 29, 17},
|
||||||
|
Critical: true, // requires special handling during verification
|
||||||
|
Value: newSANUserPrincipalName("test_device"),
|
||||||
|
}},
|
||||||
|
}, rootCA, rootKey)
|
||||||
|
|
||||||
fmt.Println(`
|
fmt.Println(`
|
||||||
const (
|
const (
|
||||||
testCA = ` + "`\n" + rootPEM + "`" + `
|
testCA = ` + "`\n" + rootPEM + "`" + `
|
||||||
|
@ -203,6 +245,7 @@ const (
|
||||||
testValidCertWithEmailSAN = ` + "`\n" + trustedClientCert4PEM + "`" + `
|
testValidCertWithEmailSAN = ` + "`\n" + trustedClientCert4PEM + "`" + `
|
||||||
testValidCertWithIPSAN = ` + "`\n" + trustedClientCert5PEM + "`" + `
|
testValidCertWithIPSAN = ` + "`\n" + trustedClientCert5PEM + "`" + `
|
||||||
testValidCertWithURISAN = ` + "`\n" + trustedClientCert6PEM + "`" + `
|
testValidCertWithURISAN = ` + "`\n" + trustedClientCert6PEM + "`" + `
|
||||||
|
testValidCertWithUPNSAN = ` + "`\n" + trustedClientCert7PEM + "`" + `
|
||||||
)
|
)
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,7 @@ func TestHeadersEvaluator(t *testing.T) {
|
||||||
assert.Equal(t, "CUSTOM_VALUE", output.Headers.Get("X-Custom-Header"))
|
assert.Equal(t, "CUSTOM_VALUE", output.Headers.Get("X-Custom-Header"))
|
||||||
assert.Equal(t, "ID_TOKEN", output.Headers.Get("X-ID-Token"))
|
assert.Equal(t, "ID_TOKEN", output.Headers.Get("X-ID-Token"))
|
||||||
assert.Equal(t, "ACCESS_TOKEN", output.Headers.Get("X-Access-Token"))
|
assert.Equal(t, "ACCESS_TOKEN", output.Headers.Get("X-Access-Token"))
|
||||||
assert.Equal(t, "ebf421e323e31c3900a7985a16e72c59f45f5a2c15283297567e226b3b17d1a1",
|
assert.Equal(t, "3febe6467787e93f0a01030e0803072feaa710f724a9dc74de05cfba3d4a6d23",
|
||||||
output.Headers.Get("Client-Cert-Fingerprint"))
|
output.Headers.Get("Client-Cert-Fingerprint"))
|
||||||
assert.Equal(t, "escaped $dollar sign", output.Headers.Get("Foo"))
|
assert.Equal(t, "escaped $dollar sign", output.Headers.Get("Foo"))
|
||||||
})
|
})
|
||||||
|
|
|
@ -278,6 +278,7 @@ func Test_buildDownstreamTLSContext(t *testing.T) {
|
||||||
{Type: config.SANTypeEmail, Pattern: `.*@example\.com`},
|
{Type: config.SANTypeEmail, Pattern: `.*@example\.com`},
|
||||||
{Type: config.SANTypeIPAddress, Pattern: `10\.10\.42\..*`},
|
{Type: config.SANTypeIPAddress, Pattern: `10\.10\.42\..*`},
|
||||||
{Type: config.SANTypeURI, Pattern: `spiffe://example\.com/.*`},
|
{Type: config.SANTypeURI, Pattern: `spiffe://example\.com/.*`},
|
||||||
|
{Type: config.SANTypeUserPrincipalName, Pattern: `^device-id$`},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
@ -321,6 +322,16 @@ func Test_buildDownstreamTLSContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sanType": "URI"
|
"sanType": "URI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"safeRegex": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": "^device-id$"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sanType": "OTHER_NAME",
|
||||||
|
"oid": "1.3.6.1.4.1.311.20.2.3"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"onlyVerifyLeafCertCrl": true,
|
"onlyVerifyLeafCertCrl": true,
|
||||||
|
|
|
@ -51,6 +51,10 @@ const (
|
||||||
|
|
||||||
// SANTypeURI represents a URI.
|
// SANTypeURI represents a URI.
|
||||||
SANTypeURI SANType = "uri"
|
SANTypeURI SANType = "uri"
|
||||||
|
|
||||||
|
// SANTypeUserPrincipalName represents a UserPrincipalName (otherName with
|
||||||
|
// type ID 1.3.6.1.4.1.311.20.2.3).
|
||||||
|
SANTypeUserPrincipalName = "user_principal_name"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DownstreamMTLSSettings specify the downstream client certificate requirements.
|
// DownstreamMTLSSettings specify the downstream client certificate requirements.
|
||||||
|
@ -259,6 +263,7 @@ func (s *SANMatcher) ToEnvoyProto() *envoy_tls.SubjectAltNameMatcher {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Oid: s.oid(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +277,18 @@ func (s *SANMatcher) envoyType() envoy_tls.SubjectAltNameMatcher_SanType {
|
||||||
return envoy_tls.SubjectAltNameMatcher_IP_ADDRESS
|
return envoy_tls.SubjectAltNameMatcher_IP_ADDRESS
|
||||||
case SANTypeURI:
|
case SANTypeURI:
|
||||||
return envoy_tls.SubjectAltNameMatcher_URI
|
return envoy_tls.SubjectAltNameMatcher_URI
|
||||||
|
case SANTypeUserPrincipalName:
|
||||||
|
return envoy_tls.SubjectAltNameMatcher_OTHER_NAME
|
||||||
default:
|
default:
|
||||||
return envoy_tls.SubjectAltNameMatcher_SAN_TYPE_UNSPECIFIED
|
return envoy_tls.SubjectAltNameMatcher_SAN_TYPE_UNSPECIFIED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SANMatcher) oid() string {
|
||||||
|
switch s.Type {
|
||||||
|
case SANTypeUserPrincipalName:
|
||||||
|
return "1.3.6.1.4.1.311.20.2.3"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -178,6 +178,7 @@ func TestDownstreamMTLSSettingsValidate(t *testing.T) {
|
||||||
{Type: "email", Pattern: `.*@\.example\.com`},
|
{Type: "email", Pattern: `.*@\.example\.com`},
|
||||||
{Type: "ip_address", Pattern: `192\.168\.0\..*`},
|
{Type: "ip_address", Pattern: `192\.168\.0\..*`},
|
||||||
{Type: "uri", Pattern: `spiffe://example.com/department/.*`},
|
{Type: "uri", Pattern: `spiffe://example.com/department/.*`},
|
||||||
|
{Type: "user_principal_name", Pattern: `username@realm`},
|
||||||
},
|
},
|
||||||
}, ""},
|
}, ""},
|
||||||
}
|
}
|
||||||
|
|
8
go.mod
8
go.mod
|
@ -20,7 +20,7 @@ require (
|
||||||
github.com/cloudflare/circl v1.3.9
|
github.com/cloudflare/circl v1.3.9
|
||||||
github.com/coreos/go-oidc/v3 v3.10.0
|
github.com/coreos/go-oidc/v3 v3.10.0
|
||||||
github.com/docker/docker v27.0.3+incompatible
|
github.com/docker/docker v27.0.3+incompatible
|
||||||
github.com/envoyproxy/go-control-plane v0.12.0
|
github.com/envoyproxy/go-control-plane v0.12.1-0.20240717153332-b7af5b7dab54
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.4
|
github.com/envoyproxy/protoc-gen-validate v1.0.4
|
||||||
github.com/go-chi/chi/v5 v5.1.0
|
github.com/go-chi/chi/v5 v5.1.0
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3
|
github.com/go-jose/go-jose/v3 v3.0.3
|
||||||
|
@ -85,7 +85,7 @@ require (
|
||||||
golang.org/x/time v0.5.0
|
golang.org/x/time v0.5.0
|
||||||
google.golang.org/api v0.183.0
|
google.golang.org/api v0.183.0
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157
|
||||||
google.golang.org/grpc v1.64.1
|
google.golang.org/grpc v1.65.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
namespacelabs.dev/go-filenotify v0.0.0-20220511192020-53ea11be7eaa
|
namespacelabs.dev/go-filenotify v0.0.0-20220511192020-53ea11be7eaa
|
||||||
|
@ -93,6 +93,7 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
cel.dev/expr v0.15.0 // indirect
|
||||||
cloud.google.com/go v0.114.0 // indirect
|
cloud.google.com/go v0.114.0 // indirect
|
||||||
cloud.google.com/go/auth v0.5.1 // indirect
|
cloud.google.com/go/auth v0.5.1 // indirect
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
|
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
|
||||||
|
@ -125,7 +126,7 @@ require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||||
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 // indirect
|
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b // indirect
|
||||||
github.com/containerd/continuity v0.4.2 // indirect
|
github.com/containerd/continuity v0.4.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/distribution/reference v0.5.0 // indirect
|
github.com/distribution/reference v0.5.0 // indirect
|
||||||
|
@ -182,6 +183,7 @@ require (
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/philhofer/fwd v1.0.0 // indirect
|
github.com/philhofer/fwd v1.0.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||||
github.com/prometheus/statsd_exporter v0.22.7 // indirect
|
github.com/prometheus/statsd_exporter v0.22.7 // indirect
|
||||||
|
|
20
go.sum
20
go.sum
|
@ -1,3 +1,5 @@
|
||||||
|
cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w=
|
||||||
|
cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
@ -158,8 +160,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
|
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
|
||||||
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 h1:DBmgJDC9dTfkVyGgipamEh2BpGYxScCH1TOF1LL1cXc=
|
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
|
||||||
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
|
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
@ -198,8 +200,8 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
|
github.com/envoyproxy/go-control-plane v0.12.1-0.20240717153332-b7af5b7dab54 h1:ekmHq5UzNblkBSc6SUen5FKxnq1h30JbZWbQFNzWLPI=
|
||||||
github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
|
github.com/envoyproxy/go-control-plane v0.12.1-0.20240717153332-b7af5b7dab54/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
|
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
||||||
|
@ -262,8 +264,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
|
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
|
||||||
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
@ -509,6 +511,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -1025,8 +1029,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
|
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||||
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
|
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue