pomerium/authorize/evaluator/gen-test-certs.go
Kenneth Jenkins dbedfc586f
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.
2024-07-26 10:23:19 -07:00

251 lines
7.4 KiB
Go

//go:build ignore
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"fmt"
"log"
"math/big"
"net"
"net/url"
"time"
)
// Returns a new self-signed certificate, as both PEM data and an
// *x509.Certificate, along with the corresponding private key.
func newSelfSignedCertificate(template *x509.Certificate) (
string, *x509.Certificate, *ecdsa.PrivateKey,
) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatalln(err)
}
der, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
if err != nil {
log.Fatalln(err)
}
cert, err := x509.ParseCertificate(der)
if err != nil {
log.Fatalln(err)
}
return string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})), cert, key
}
// Returns a new certificate, as both PEM data and an *x509.Certificate, along
// with the new certificate's corresponding private key.
func newCertificate(template, issuer *x509.Certificate, issuerKey *ecdsa.PrivateKey) (
string, *x509.Certificate, *ecdsa.PrivateKey,
) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatalln(err)
}
der, err := x509.CreateCertificate(rand.Reader, template, issuer, key.Public(), issuerKey)
if err != nil {
log.Fatalln(err)
}
cert, err := x509.ParseCertificate(der)
if err != nil {
log.Fatalln(err)
}
return string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})), cert, key
}
// Returns a new CRL in PEM format.
func newCRL(
template *x509.RevocationList, issuer *x509.Certificate, issuerKey *ecdsa.PrivateKey,
) string {
der, err := x509.CreateRevocationList(rand.Reader, template, issuer, issuerKey)
if err != nil {
log.Fatalln(err)
}
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.
func main() {
notAfter := time.Now().Add(3650 * 24 * time.Hour)
rootPEM, rootCA, rootKey := newSelfSignedCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1000),
Subject: pkix.Name{
CommonName: "Trusted Root CA",
},
NotAfter: notAfter,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
BasicConstraintsValid: true,
IsCA: true,
})
trustedClientCertPEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1001),
Subject: pkix.Name{
CommonName: "trusted client cert",
},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
intermediatePEM, intermediateCA, intermediateKey := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1003),
Subject: pkix.Name{
CommonName: "Trusted Intermediate CA",
},
NotAfter: notAfter,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
BasicConstraintsValid: true,
IsCA: true,
}, rootCA, rootKey)
trustedClientCert2PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1000),
Subject: pkix.Name{
CommonName: "client cert from intermediate",
},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, intermediateCA, intermediateKey)
_, untrustedCA, untrustedCAKey := newSelfSignedCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1000),
Subject: pkix.Name{
CommonName: "Untrusted Root CA",
},
NotAfter: notAfter,
BasicConstraintsValid: true,
IsCA: true,
})
untrustedClientCertPEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1001),
Subject: pkix.Name{
CommonName: "untrusted client cert",
},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, untrustedCA, untrustedCAKey)
revokedClientCertPEM, revokedClientCert, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1002),
Subject: pkix.Name{
CommonName: "revoked client cert",
},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
crlPEM := newCRL(&x509.RevocationList{
Number: big.NewInt(0x2000),
RevokedCertificates: []pkix.RevokedCertificate{
{
SerialNumber: revokedClientCert.SerialNumber,
RevocationTime: time.Now(),
},
},
}, rootCA, rootKey)
trustedClientCert3PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1004),
Subject: pkix.Name{
CommonName: "client cert 3",
},
DNSNames: []string{"a.client3.example.com", "b.client3.example.com"},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
trustedClientCert4PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1005),
Subject: pkix.Name{
CommonName: "client cert 4",
},
EmailAddresses: []string{"client4@example.com"},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
trustedClientCert5PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1006),
Subject: pkix.Name{
CommonName: "client cert 5",
},
IPAddresses: []net.IP{net.ParseIP("192.168.10.10")},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
trustedClientCert6PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1007),
Subject: pkix.Name{
CommonName: "client cert 6",
},
URIs: []*url.URL{{Scheme: "spiffe", Host: "example.com", Path: "/foo/bar"}},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, 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(`
const (
testCA = ` + "`\n" + rootPEM + "`" + `
testValidCert = ` + "`\n" + trustedClientCertPEM + "`" + `
testUntrustedCert = ` + "`\n" + untrustedClientCertPEM + "`" + `
testRevokedCert = ` + "`\n" + revokedClientCertPEM + "`" + `
testCRL = ` + "`\n" + crlPEM + "`" + `
testIntermediateCA = ` + "`\n" + intermediatePEM + "`" + `
testValidIntermediateCert = ` + "`\n" + trustedClientCert2PEM + "`" + `
testValidCertWithDNSSANs = ` + "`\n" + trustedClientCert3PEM + "`" + `
testValidCertWithEmailSAN = ` + "`\n" + trustedClientCert4PEM + "`" + `
testValidCertWithIPSAN = ` + "`\n" + trustedClientCert5PEM + "`" + `
testValidCertWithURISAN = ` + "`\n" + trustedClientCert6PEM + "`" + `
testValidCertWithUPNSAN = ` + "`\n" + trustedClientCert7PEM + "`" + `
)
`)
}