121 lines
2.7 KiB
Go
121 lines
2.7 KiB
Go
package pktls
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
type Config struct {
|
|
PrivateKey PrivateKey
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
Config
|
|
Allowed []PublicKey
|
|
}
|
|
|
|
type ClientConfig struct {
|
|
Config
|
|
Server PublicKey
|
|
}
|
|
|
|
func ServerFromString(privkey string, allowed []string) (*ServerConfig, error) {
|
|
if len(allowed) == 0 {
|
|
return nil, fmt.Errorf("no allowed keys set, server will accept no clients")
|
|
}
|
|
priv, err := PrivateFromString(privkey)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("server private key: %w", err)
|
|
}
|
|
|
|
allowedKeys := make([]PublicKey, len(allowed))
|
|
for i, pk := range allowed {
|
|
public, err := PublicFromString(pk)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("allowed key %d: %w", i, err)
|
|
}
|
|
allowedKeys[i] = public
|
|
}
|
|
cfg := &ServerConfig{
|
|
Config: Config{
|
|
PrivateKey: priv,
|
|
},
|
|
Allowed: allowedKeys,
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func ClientFromString(privkey string, server string) (*ClientConfig, error) {
|
|
priv, err := PrivateFromString(privkey)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("client private key: %w", err)
|
|
}
|
|
serverKey, err := PublicFromString(server)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("server public key: %w", err)
|
|
}
|
|
cfg := &ClientConfig{
|
|
Config: Config{
|
|
PrivateKey: priv,
|
|
},
|
|
Server: serverKey,
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
func (s *ServerConfig) Configure(config *tls.Config) error {
|
|
tlsCert, err := s.PrivateKey.GenerateTLS(TLSServer)
|
|
if err != nil {
|
|
return fmt.Errorf("generating TLS certificate/keypair failed: %w", err)
|
|
}
|
|
config.Certificates = []tls.Certificate{*tlsCert}
|
|
config.ClientAuth = tls.RequireAnyClientCert
|
|
config.VerifyPeerCertificate = s.VerifyPeerCertificate
|
|
return nil
|
|
}
|
|
|
|
func (s *ServerConfig) VerifyPeerCertificate(rawCerts [][]byte, _ [][]*x509.Certificate) error {
|
|
if len(rawCerts) != 1 {
|
|
return fmt.Errorf("need exacty one client certificate")
|
|
}
|
|
cert := rawCerts[0]
|
|
|
|
lastErr := ErrWrongIdentity
|
|
for _, allowed := range s.Allowed {
|
|
err := allowed.Verify(TLSServer, cert)
|
|
switch {
|
|
case err == nil:
|
|
return nil
|
|
case errors.Is(err, ErrWrongIdentity):
|
|
lastErr = err
|
|
continue
|
|
default:
|
|
return err
|
|
}
|
|
}
|
|
|
|
return lastErr
|
|
}
|
|
|
|
func (c *ClientConfig) Configure(config *tls.Config) error {
|
|
tlsCert, err := c.PrivateKey.GenerateTLS(TLSClient)
|
|
if err != nil {
|
|
return fmt.Errorf("generating TLS certificate/keypair failed: %w", err)
|
|
}
|
|
config.Certificates = []tls.Certificate{*tlsCert}
|
|
config.InsecureSkipVerify = true
|
|
config.VerifyPeerCertificate = c.VerifyPeerCertificate
|
|
return nil
|
|
}
|
|
|
|
func (c *ClientConfig) VerifyPeerCertificate(rawCerts [][]byte, _ [][]*x509.Certificate) error {
|
|
if len(rawCerts) != 1 {
|
|
return fmt.Errorf("need exacty one server certificate")
|
|
}
|
|
cert := rawCerts[0]
|
|
return c.Server.Verify(TLSClient, cert)
|
|
}
|