mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
583 lines
17 KiB
Go
583 lines
17 KiB
Go
|
package utils
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto/ecdsa"
|
||
|
"crypto/ed25519"
|
||
|
"crypto/elliptic"
|
||
|
"crypto/rand"
|
||
|
"crypto/rsa"
|
||
|
"crypto/tls"
|
||
|
"crypto/x509"
|
||
|
"crypto/x509/pkix"
|
||
|
"encoding/pem"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"math/big"
|
||
|
"net"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||
|
"github.com/authelia/authelia/v4/internal/logging"
|
||
|
)
|
||
|
|
||
|
// PEMBlockType represent an enum of the existing PEM block types.
|
||
|
type PEMBlockType int
|
||
|
|
||
|
const (
|
||
|
// Certificate block type.
|
||
|
Certificate PEMBlockType = iota
|
||
|
// PrivateKey block type.
|
||
|
PrivateKey
|
||
|
)
|
||
|
|
||
|
// GenerateCertificate generate a certificate given a private key. RSA, Ed25519 and ECDSA are officially supported.
|
||
|
func GenerateCertificate(privateKeyBuilder PrivateKeyBuilder, hosts []string, validFrom time.Time, validFor time.Duration, isCA bool) ([]byte, []byte, error) {
|
||
|
privateKey, err := privateKeyBuilder.Build()
|
||
|
if err != nil {
|
||
|
return nil, nil, fmt.Errorf("unable to build private key: %w", err)
|
||
|
}
|
||
|
|
||
|
notBefore := validFrom
|
||
|
notAfter := validFrom.Add(validFor)
|
||
|
|
||
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||
|
|
||
|
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||
|
if err != nil {
|
||
|
return nil, nil, fmt.Errorf("failed to generate serial number: %v", err)
|
||
|
}
|
||
|
|
||
|
template := x509.Certificate{
|
||
|
SerialNumber: serialNumber,
|
||
|
Subject: pkix.Name{
|
||
|
Organization: []string{"Acme Co"},
|
||
|
},
|
||
|
NotBefore: notBefore,
|
||
|
NotAfter: notAfter,
|
||
|
|
||
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||
|
BasicConstraintsValid: true,
|
||
|
}
|
||
|
|
||
|
for _, h := range hosts {
|
||
|
if ip := net.ParseIP(h); ip != nil {
|
||
|
template.IPAddresses = append(template.IPAddresses, ip)
|
||
|
} else {
|
||
|
template.DNSNames = append(template.DNSNames, h)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if isCA {
|
||
|
template.IsCA = true
|
||
|
template.KeyUsage |= x509.KeyUsageCertSign
|
||
|
}
|
||
|
|
||
|
certDERBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey)
|
||
|
if err != nil {
|
||
|
return nil, nil, fmt.Errorf("failed to create certificate: %v", err)
|
||
|
}
|
||
|
|
||
|
certPEMBytes, err := ConvertDERToPEM(certDERBytes, Certificate)
|
||
|
if err != nil {
|
||
|
return nil, nil, fmt.Errorf("failed to convert certificate in DER format into PEM: %v", err)
|
||
|
}
|
||
|
|
||
|
keyDERBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||
|
if err != nil {
|
||
|
return nil, nil, fmt.Errorf("failed to marshal private key: %v", err)
|
||
|
}
|
||
|
|
||
|
keyPEMBytes, err := ConvertDERToPEM(keyDERBytes, PrivateKey)
|
||
|
if err != nil {
|
||
|
return nil, nil, fmt.Errorf("faile to convert certificate in DER format into PEM: %v", err)
|
||
|
}
|
||
|
|
||
|
return certPEMBytes, keyPEMBytes, nil
|
||
|
}
|
||
|
|
||
|
// ConvertDERToPEM convert certificate in DER format into PEM format.
|
||
|
func ConvertDERToPEM(der []byte, blockType PEMBlockType) ([]byte, error) {
|
||
|
var buf bytes.Buffer
|
||
|
|
||
|
var blockTypeStr string
|
||
|
|
||
|
switch blockType {
|
||
|
case Certificate:
|
||
|
blockTypeStr = "CERTIFICATE"
|
||
|
case PrivateKey:
|
||
|
blockTypeStr = "PRIVATE KEY"
|
||
|
default:
|
||
|
return nil, fmt.Errorf("unknown PEM block type %d", blockType)
|
||
|
}
|
||
|
|
||
|
if err := pem.Encode(&buf, &pem.Block{Type: blockTypeStr, Bytes: der}); err != nil {
|
||
|
return nil, fmt.Errorf("failed to encode DER data into PEM: %v", err)
|
||
|
}
|
||
|
|
||
|
return buf.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
func publicKey(privateKey interface{}) interface{} {
|
||
|
switch k := privateKey.(type) {
|
||
|
case *rsa.PrivateKey:
|
||
|
return &k.PublicKey
|
||
|
case *ecdsa.PrivateKey:
|
||
|
return &k.PublicKey
|
||
|
case ed25519.PrivateKey:
|
||
|
return k.Public().(ed25519.PublicKey)
|
||
|
default:
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// PrivateKeyBuilder interface for a private key builder.
|
||
|
type PrivateKeyBuilder interface {
|
||
|
Build() (interface{}, error)
|
||
|
}
|
||
|
|
||
|
// RSAKeyBuilder builder of RSA private key.
|
||
|
type RSAKeyBuilder struct {
|
||
|
keySizeInBits int
|
||
|
}
|
||
|
|
||
|
// WithKeySize configure the key size to use with RSA.
|
||
|
func (rkb RSAKeyBuilder) WithKeySize(bits int) RSAKeyBuilder {
|
||
|
rkb.keySizeInBits = bits
|
||
|
return rkb
|
||
|
}
|
||
|
|
||
|
// Build a RSA private key.
|
||
|
func (rkb RSAKeyBuilder) Build() (interface{}, error) {
|
||
|
return rsa.GenerateKey(rand.Reader, rkb.keySizeInBits)
|
||
|
}
|
||
|
|
||
|
// Ed25519KeyBuilder builder of Ed25519 private key.
|
||
|
type Ed25519KeyBuilder struct{}
|
||
|
|
||
|
// Build an Ed25519 private key.
|
||
|
func (ekb Ed25519KeyBuilder) Build() (interface{}, error) {
|
||
|
_, priv, err := ed25519.GenerateKey(rand.Reader)
|
||
|
return priv, err
|
||
|
}
|
||
|
|
||
|
// ECDSAKeyBuilder builder of ECDSA private key.
|
||
|
type ECDSAKeyBuilder struct {
|
||
|
curve elliptic.Curve
|
||
|
}
|
||
|
|
||
|
// WithCurve configure the curve to use for the ECDSA private key.
|
||
|
func (ekb ECDSAKeyBuilder) WithCurve(curve elliptic.Curve) ECDSAKeyBuilder {
|
||
|
ekb.curve = curve
|
||
|
return ekb
|
||
|
}
|
||
|
|
||
|
// Build an ECDSA private key.
|
||
|
func (ekb ECDSAKeyBuilder) Build() (interface{}, error) {
|
||
|
return ecdsa.GenerateKey(ekb.curve, rand.Reader)
|
||
|
}
|
||
|
|
||
|
// ParseX509FromPEM parses PEM bytes and returns a PKCS key.
|
||
|
func ParseX509FromPEM(data []byte) (key interface{}, err error) {
|
||
|
block, _ := pem.Decode(data)
|
||
|
if block == nil {
|
||
|
return nil, errors.New("failed to parse PEM block containing the key")
|
||
|
}
|
||
|
|
||
|
switch block.Type {
|
||
|
case BlockTypeRSAPrivateKey:
|
||
|
key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
||
|
case BlockTypeECDSAPrivateKey:
|
||
|
key, err = x509.ParseECPrivateKey(block.Bytes)
|
||
|
case BlockTypePKCS8PrivateKey:
|
||
|
key, err = x509.ParsePKCS8PrivateKey(block.Bytes)
|
||
|
case BlockTypeRSAPublicKey:
|
||
|
key, err = x509.ParsePKCS1PublicKey(block.Bytes)
|
||
|
case BlockTypePKIXPublicKey:
|
||
|
key, err = x509.ParsePKIXPublicKey(block.Bytes)
|
||
|
case BlockTypeCertificate:
|
||
|
key, err = x509.ParseCertificate(block.Bytes)
|
||
|
default:
|
||
|
return nil, fmt.Errorf("unknown block type: %s", block.Type)
|
||
|
}
|
||
|
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return key, nil
|
||
|
}
|
||
|
|
||
|
// CastX509AsCertificate converts an interface to an *x509.Certificate.
|
||
|
func CastX509AsCertificate(c interface{}) (certificate *x509.Certificate, ok bool) {
|
||
|
switch t := c.(type) {
|
||
|
case x509.Certificate:
|
||
|
return &t, true
|
||
|
case *x509.Certificate:
|
||
|
return t, true
|
||
|
default:
|
||
|
return nil, false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// IsX509PrivateKey returns true if the provided interface is an rsa.PrivateKey, ecdsa.PrivateKey, or ed25519.PrivateKey.
|
||
|
func IsX509PrivateKey(i interface{}) bool {
|
||
|
switch i.(type) {
|
||
|
case rsa.PrivateKey, *rsa.PrivateKey, ecdsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, *ed25519.PrivateKey:
|
||
|
return true
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NewTLSConfig generates a tls.Config from a schema.TLSConfig and a x509.CertPool.
|
||
|
func NewTLSConfig(config *schema.TLSConfig, defaultMinVersion uint16, certPool *x509.CertPool) (tlsConfig *tls.Config) {
|
||
|
minVersion, err := TLSStringToTLSConfigVersion(config.MinimumVersion)
|
||
|
if err != nil {
|
||
|
minVersion = defaultMinVersion
|
||
|
}
|
||
|
|
||
|
return &tls.Config{
|
||
|
ServerName: config.ServerName,
|
||
|
InsecureSkipVerify: config.SkipVerify, //nolint:gosec // Informed choice by user. Off by default.
|
||
|
MinVersion: minVersion,
|
||
|
RootCAs: certPool,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NewX509CertPool generates a x509.CertPool from the system PKI and the directory specified.
|
||
|
func NewX509CertPool(directory string) (certPool *x509.CertPool, warnings []error, errors []error) {
|
||
|
certPool, err := x509.SystemCertPool()
|
||
|
if err != nil {
|
||
|
warnings = append(warnings, fmt.Errorf("could not load system certificate pool which may result in untrusted certificate issues: %v", err))
|
||
|
certPool = x509.NewCertPool()
|
||
|
}
|
||
|
|
||
|
logger := logging.Logger()
|
||
|
|
||
|
logger.Tracef("Starting scan of directory %s for certificates", directory)
|
||
|
|
||
|
if directory != "" {
|
||
|
certsFileInfo, err := os.ReadDir(directory)
|
||
|
if err != nil {
|
||
|
errors = append(errors, fmt.Errorf("could not read certificates from directory %v", err))
|
||
|
} else {
|
||
|
for _, certFileInfo := range certsFileInfo {
|
||
|
nameLower := strings.ToLower(certFileInfo.Name())
|
||
|
|
||
|
if !certFileInfo.IsDir() && (strings.HasSuffix(nameLower, ".cer") || strings.HasSuffix(nameLower, ".crt") || strings.HasSuffix(nameLower, ".pem")) {
|
||
|
certPath := filepath.Join(directory, certFileInfo.Name())
|
||
|
|
||
|
logger.Tracef("Found possible cert %s, attempting to add it to the pool", certPath)
|
||
|
|
||
|
certBytes, err := os.ReadFile(certPath)
|
||
|
if err != nil {
|
||
|
errors = append(errors, fmt.Errorf("could not read certificate %v", err))
|
||
|
} else if ok := certPool.AppendCertsFromPEM(certBytes); !ok {
|
||
|
errors = append(errors, fmt.Errorf("could not import certificate %s", certFileInfo.Name()))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
logger.Tracef("Finished scan of directory %s for certificates", directory)
|
||
|
|
||
|
return certPool, warnings, errors
|
||
|
}
|
||
|
|
||
|
// TLSStringToTLSConfigVersion returns a go crypto/tls version for a tls.Config based on string input.
|
||
|
func TLSStringToTLSConfigVersion(input string) (version uint16, err error) {
|
||
|
switch strings.ToUpper(input) {
|
||
|
case "TLS1.3", TLS13:
|
||
|
return tls.VersionTLS13, nil
|
||
|
case "TLS1.2", TLS12:
|
||
|
return tls.VersionTLS12, nil
|
||
|
case "TLS1.1", TLS11:
|
||
|
return tls.VersionTLS11, nil
|
||
|
case "TLS1.0", TLS10:
|
||
|
return tls.VersionTLS10, nil
|
||
|
}
|
||
|
|
||
|
return 0, ErrTLSVersionNotSupported
|
||
|
}
|
||
|
|
||
|
// WriteCertificateBytesToPEM writes a certificate/csr to a file in the PEM format.
|
||
|
func WriteCertificateBytesToPEM(cert []byte, path string, csr bool) (err error) {
|
||
|
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to open %s for writing: %w", path, err)
|
||
|
}
|
||
|
|
||
|
blockType := BlockTypeCertificate
|
||
|
if csr {
|
||
|
blockType = BlockTypeCertificateRequest
|
||
|
}
|
||
|
|
||
|
if err = pem.Encode(out, &pem.Block{Bytes: cert, Type: blockType}); err != nil {
|
||
|
_ = out.Close()
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return out.Close()
|
||
|
}
|
||
|
|
||
|
// WriteKeyToPEM writes a key that can be encoded as a PEM to a file in the PEM format.
|
||
|
func WriteKeyToPEM(key interface{}, path string, pkcs8 bool) (err error) {
|
||
|
pemBlock, err := PEMBlockFromX509Key(key, pkcs8)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to open %s for writing: %w", path, err)
|
||
|
}
|
||
|
|
||
|
if err = pem.Encode(out, pemBlock); err != nil {
|
||
|
_ = out.Close()
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return out.Close()
|
||
|
}
|
||
|
|
||
|
// PEMBlockFromX509Key turns a PublicKey or PrivateKey into a pem.Block.
|
||
|
func PEMBlockFromX509Key(key interface{}, pkcs8 bool) (pemBlock *pem.Block, err error) {
|
||
|
var (
|
||
|
data []byte
|
||
|
blockType string
|
||
|
)
|
||
|
|
||
|
switch k := key.(type) {
|
||
|
case *rsa.PrivateKey:
|
||
|
if pkcs8 {
|
||
|
blockType = BlockTypePKCS8PrivateKey
|
||
|
data, err = x509.MarshalPKCS8PrivateKey(key)
|
||
|
|
||
|
break
|
||
|
}
|
||
|
|
||
|
blockType = BlockTypeRSAPrivateKey
|
||
|
data = x509.MarshalPKCS1PrivateKey(k)
|
||
|
case *ecdsa.PrivateKey:
|
||
|
if pkcs8 {
|
||
|
blockType = BlockTypePKCS8PrivateKey
|
||
|
data, err = x509.MarshalPKCS8PrivateKey(key)
|
||
|
|
||
|
break
|
||
|
}
|
||
|
|
||
|
blockType = BlockTypeECDSAPrivateKey
|
||
|
data, err = x509.MarshalECPrivateKey(k)
|
||
|
case ed25519.PrivateKey:
|
||
|
blockType = BlockTypePKCS8PrivateKey
|
||
|
data, err = x509.MarshalPKCS8PrivateKey(k)
|
||
|
case *rsa.PublicKey:
|
||
|
if pkcs8 {
|
||
|
blockType = BlockTypePKIXPublicKey
|
||
|
data, err = x509.MarshalPKIXPublicKey(key)
|
||
|
|
||
|
break
|
||
|
}
|
||
|
|
||
|
blockType = BlockTypeRSAPublicKey
|
||
|
data = x509.MarshalPKCS1PublicKey(k)
|
||
|
case *ecdsa.PublicKey, ed25519.PublicKey:
|
||
|
blockType = BlockTypePKIXPublicKey
|
||
|
data, err = x509.MarshalPKIXPublicKey(k)
|
||
|
default:
|
||
|
err = fmt.Errorf("failed to match key type: %T", k)
|
||
|
}
|
||
|
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("failed to marshal key: %w", err)
|
||
|
}
|
||
|
|
||
|
return &pem.Block{
|
||
|
Type: blockType,
|
||
|
Bytes: data,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// KeySigAlgorithmFromString returns a x509.PublicKeyAlgorithm and x509.SignatureAlgorithm given a keyAlgorithm and signatureAlgorithm string.
|
||
|
func KeySigAlgorithmFromString(keyAlgorithm, signatureAlgorithm string) (keyAlg x509.PublicKeyAlgorithm, sigAlg x509.SignatureAlgorithm) {
|
||
|
keyAlg = PublicKeyAlgorithmFromString(keyAlgorithm)
|
||
|
|
||
|
if keyAlg == x509.UnknownPublicKeyAlgorithm {
|
||
|
return x509.UnknownPublicKeyAlgorithm, x509.UnknownSignatureAlgorithm
|
||
|
}
|
||
|
|
||
|
switch keyAlg {
|
||
|
case x509.RSA:
|
||
|
return keyAlg, RSASignatureAlgorithmFromString(signatureAlgorithm)
|
||
|
case x509.ECDSA:
|
||
|
return keyAlg, ECDSASignatureAlgorithmFromString(signatureAlgorithm)
|
||
|
case x509.Ed25519:
|
||
|
return keyAlg, x509.PureEd25519
|
||
|
default:
|
||
|
return keyAlg, x509.UnknownSignatureAlgorithm
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// PublicKeyAlgorithmFromString returns a x509.PublicKeyAlgorithm given an appropriate string.
|
||
|
func PublicKeyAlgorithmFromString(algorithm string) (alg x509.PublicKeyAlgorithm) {
|
||
|
switch strings.ToUpper(algorithm) {
|
||
|
case KeyAlgorithmRSA:
|
||
|
return x509.RSA
|
||
|
case KeyAlgorithmECDSA:
|
||
|
return x509.ECDSA
|
||
|
case KeyAlgorithmEd25519:
|
||
|
return x509.Ed25519
|
||
|
default:
|
||
|
return x509.UnknownPublicKeyAlgorithm
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RSASignatureAlgorithmFromString returns a x509.SignatureAlgorithm for the RSA x509.PublicKeyAlgorithm given an
|
||
|
// algorithm string.
|
||
|
func RSASignatureAlgorithmFromString(algorithm string) (alg x509.SignatureAlgorithm) {
|
||
|
switch strings.ToUpper(algorithm) {
|
||
|
case HashAlgorithmSHA1:
|
||
|
return x509.SHA1WithRSA
|
||
|
case HashAlgorithmSHA256:
|
||
|
return x509.SHA256WithRSA
|
||
|
case HashAlgorithmSHA384:
|
||
|
return x509.SHA384WithRSA
|
||
|
case HashAlgorithmSHA512:
|
||
|
return x509.SHA512WithRSA
|
||
|
default:
|
||
|
return x509.UnknownSignatureAlgorithm
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ECDSASignatureAlgorithmFromString returns a x509.SignatureAlgorithm for the ECDSA x509.PublicKeyAlgorithm given an
|
||
|
// algorithm string.
|
||
|
func ECDSASignatureAlgorithmFromString(algorithm string) (alg x509.SignatureAlgorithm) {
|
||
|
switch strings.ToUpper(algorithm) {
|
||
|
case HashAlgorithmSHA1:
|
||
|
return x509.ECDSAWithSHA1
|
||
|
case HashAlgorithmSHA256:
|
||
|
return x509.ECDSAWithSHA256
|
||
|
case HashAlgorithmSHA384:
|
||
|
return x509.ECDSAWithSHA384
|
||
|
case HashAlgorithmSHA512:
|
||
|
return x509.ECDSAWithSHA512
|
||
|
default:
|
||
|
return x509.UnknownSignatureAlgorithm
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EllipticCurveFromString turns a string into an elliptic.Curve.
|
||
|
func EllipticCurveFromString(curveString string) (curve elliptic.Curve) {
|
||
|
switch strings.ToUpper(curveString) {
|
||
|
case EllipticCurveAltP224, EllipticCurveP224:
|
||
|
return elliptic.P224()
|
||
|
case EllipticCurveAltP256, EllipticCurveP256:
|
||
|
return elliptic.P256()
|
||
|
case EllipticCurveAltP384, EllipticCurveP384:
|
||
|
return elliptic.P384()
|
||
|
case EllipticCurveAltP521, EllipticCurveP521:
|
||
|
return elliptic.P521()
|
||
|
default:
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// PublicKeyFromPrivateKey returns a PublicKey when provided with a PrivateKey.
|
||
|
func PublicKeyFromPrivateKey(privateKey interface{}) (publicKey interface{}) {
|
||
|
switch k := privateKey.(type) {
|
||
|
case *rsa.PrivateKey:
|
||
|
return &k.PublicKey
|
||
|
case *ecdsa.PrivateKey:
|
||
|
return &k.PublicKey
|
||
|
case ed25519.PrivateKey:
|
||
|
return k.Public().(ed25519.PublicKey)
|
||
|
default:
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// X509ParseKeyUsage parses a list of key usages. If provided with an empty list returns a default of Key Encipherment
|
||
|
// and Digital Signature unless ca is true in which case it returns Cert Sign.
|
||
|
func X509ParseKeyUsage(keyUsages []string, ca bool) (keyUsage x509.KeyUsage) {
|
||
|
if len(keyUsages) == 0 {
|
||
|
keyUsage = x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
|
||
|
if ca {
|
||
|
keyUsage |= x509.KeyUsageCertSign
|
||
|
}
|
||
|
|
||
|
return keyUsage
|
||
|
}
|
||
|
|
||
|
for _, keyUsageString := range keyUsages {
|
||
|
switch strings.ToLower(keyUsageString) {
|
||
|
case "digitalsignature", "digital_signature":
|
||
|
keyUsage |= x509.KeyUsageDigitalSignature
|
||
|
case "keyencipherment", "key_encipherment":
|
||
|
keyUsage |= x509.KeyUsageKeyEncipherment
|
||
|
case "dataencipherment", "data_encipherment":
|
||
|
keyUsage |= x509.KeyUsageDataEncipherment
|
||
|
case "keyagreement", "key_agreement":
|
||
|
keyUsage |= x509.KeyUsageKeyAgreement
|
||
|
case "certsign", "cert_sign", "certificatesign", "certificate_sign":
|
||
|
keyUsage |= x509.KeyUsageCertSign
|
||
|
case "crlsign", "crl_sign":
|
||
|
keyUsage |= x509.KeyUsageCRLSign
|
||
|
case "encipheronly", "encipher_only":
|
||
|
keyUsage |= x509.KeyUsageEncipherOnly
|
||
|
case "decipheronly", "decipher_only":
|
||
|
keyUsage |= x509.KeyUsageDecipherOnly
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return keyUsage
|
||
|
}
|
||
|
|
||
|
// X509ParseExtendedKeyUsage parses a list of extended key usages. If provided with an empty list returns a default of
|
||
|
// Server Auth unless ca is true in which case it returns a default of Any.
|
||
|
func X509ParseExtendedKeyUsage(extKeyUsages []string, ca bool) (extKeyUsage []x509.ExtKeyUsage) {
|
||
|
if len(extKeyUsages) == 0 {
|
||
|
if ca {
|
||
|
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
|
||
|
} else {
|
||
|
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
|
||
|
}
|
||
|
|
||
|
return extKeyUsage
|
||
|
}
|
||
|
|
||
|
loop:
|
||
|
for _, extKeyUsageString := range extKeyUsages {
|
||
|
switch strings.ToLower(extKeyUsageString) {
|
||
|
case "any":
|
||
|
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
|
||
|
break loop
|
||
|
case "serverauth", "server_auth":
|
||
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageServerAuth)
|
||
|
case "clientauth", "client_auth":
|
||
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageClientAuth)
|
||
|
case "codesigning", "code_signing":
|
||
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageCodeSigning)
|
||
|
case "emailprotection", "email_protection":
|
||
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageEmailProtection)
|
||
|
case "ipsecendsystem", "ipsec_endsystem", "ipsec_end_system":
|
||
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageIPSECEndSystem)
|
||
|
case "ipsectunnel", "ipsec_tunnel":
|
||
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageIPSECTunnel)
|
||
|
case "ipsecuser", "ipsec_user":
|
||
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageIPSECUser)
|
||
|
case "ocspsigning", "ocsp_signing":
|
||
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageOCSPSigning)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return extKeyUsage
|
||
|
}
|