75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
package crypto
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"shamilnunhuck/saml-oidc-bridge/internal/config"
|
|
)
|
|
|
|
type KeyStore struct {
|
|
activeID string
|
|
signers map[string]tls.Certificate
|
|
certsDER map[string][]byte
|
|
}
|
|
|
|
func NewKeyStore(c config.Crypto) (*KeyStore, error) {
|
|
ks := &KeyStore{
|
|
activeID: c.ActiveKey,
|
|
signers: map[string]tls.Certificate{},
|
|
certsDER: map[string][]byte{},
|
|
}
|
|
for _, k := range c.Keys {
|
|
cert, priv, err := parseKeypair(k.CertPEM, k.KeyPEM)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("key %s: %w", k.ID, err)
|
|
}
|
|
ks.certsDER[k.ID] = cert.Raw
|
|
if priv != nil {
|
|
ks.signers[k.ID] = tls.Certificate{Certificate: [][]byte{cert.Raw}, PrivateKey: priv}
|
|
}
|
|
}
|
|
if _, ok := ks.signers[ks.activeID]; !ok {
|
|
return nil, errors.New("active signing key not available (missing or no private key)")
|
|
}
|
|
return ks, nil
|
|
}
|
|
|
|
func (ks *KeyStore) Active() tls.Certificate { return ks.signers[ks.activeID] }
|
|
func (ks *KeyStore) AllCertsDER() [][]byte {
|
|
out := make([][]byte, 0, len(ks.certsDER))
|
|
for _, der := range ks.certsDER {
|
|
out = append(out, der)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func parseKeypair(certPEM, keyPEM string) (*x509.Certificate, interface{}, error) {
|
|
cb, _ := pem.Decode([]byte(certPEM))
|
|
if cb == nil {
|
|
return nil, nil, errors.New("invalid cert pem")
|
|
}
|
|
cert, err := x509.ParseCertificate(cb.Bytes)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
var priv interface{}
|
|
if keyPEM != "" {
|
|
kb, _ := pem.Decode([]byte(keyPEM))
|
|
if kb == nil {
|
|
return nil, nil, errors.New("invalid key pem")
|
|
}
|
|
priv, err = x509.ParsePKCS8PrivateKey(kb.Bytes)
|
|
if err != nil {
|
|
priv, err = x509.ParsePKCS1PrivateKey(kb.Bytes)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
}
|
|
return cert, priv, nil
|
|
}
|