pomerium/authorize/evaluator/opa/functions.go
Caleb Doxsey e4832cb4ed
authorize: add client mTLS support (#751)
* authorize: add client mtls support

* authorize: better error messages for envoy

* switch from function to input

* add TrustedCa to envoy config so that users are prompted for the correct client certificate

* update documentation

* fix invalid ClientCAFile

* regenerate cache protobuf

* avoid recursion, add test

* move comment line

* use http.StatusOK

* various fixes
2020-05-21 16:01:07 -06:00

58 lines
1.2 KiB
Go

package opa
import (
"crypto/x509"
"encoding/pem"
"fmt"
lru "github.com/hashicorp/golang-lru"
)
var isValidClientCertificateCache, _ = lru.New2Q(100)
func isValidClientCertificate(ca, cert string) (bool, error) {
// when ca is the empty string, client certificates are always accepted
if ca == "" {
return true, nil
}
// when cert is the empty string, no client certificate was supplied
if cert == "" {
return false, nil
}
cacheKey := [2]string{ca, cert}
value, ok := isValidClientCertificateCache.Get(cacheKey)
if ok {
return value.(bool), nil
}
roots := x509.NewCertPool()
roots.AppendCertsFromPEM([]byte(ca))
xcert, err := parseCertificate(cert)
if err != nil {
return false, err
}
_, verifyErr := xcert.Verify(x509.VerifyOptions{
Roots: roots,
})
valid := verifyErr == nil
isValidClientCertificateCache.Add(cacheKey, valid)
return valid, nil
}
func parseCertificate(pemStr string) (*x509.Certificate, error) {
block, _ := pem.Decode([]byte(pemStr))
if block == nil {
return nil, fmt.Errorf("invalid certificate")
}
if block.Type != "CERTIFICATE" {
return nil, fmt.Errorf("unknown PEM type: %s", block.Type)
}
return x509.ParseCertificate(block.Bytes)
}