mirror of
https://github.com/syntrex-lab/gomcp.git
synced 2026-04-26 21:06:21 +02:00
82 lines
2.7 KiB
Go
82 lines
2.7 KiB
Go
package transport
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"math/big"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
// TLSConfig configures mutual TLS for P2P connections (v3.6).
|
|
type TLSConfig struct {
|
|
CertFile string `json:"cert_file,omitempty"` // Path to cert PEM (auto-generated if empty)
|
|
KeyFile string `json:"key_file,omitempty"` // Path to key PEM (auto-generated if empty)
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
// GenerateSelfSignedCert creates a self-signed TLS certificate for P2P mutual auth.
|
|
// The cert includes the peer ID as the common name for identity verification.
|
|
func GenerateSelfSignedCert(peerID string) (tls.Certificate, error) {
|
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
return tls.Certificate{}, fmt.Errorf("generate key: %w", err)
|
|
}
|
|
|
|
serial, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
|
|
|
template := &x509.Certificate{
|
|
SerialNumber: serial,
|
|
Subject: pkix.Name{
|
|
CommonName: peerID,
|
|
Organization: []string{"GoMCP P2P"},
|
|
},
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().Add(365 * 24 * time.Hour),
|
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
|
BasicConstraintsValid: true,
|
|
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
|
|
DNSNames: []string{"localhost"},
|
|
}
|
|
|
|
certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
|
if err != nil {
|
|
return tls.Certificate{}, fmt.Errorf("create cert: %w", err)
|
|
}
|
|
|
|
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
|
keyDER, err := x509.MarshalECPrivateKey(key)
|
|
if err != nil {
|
|
return tls.Certificate{}, fmt.Errorf("marshal key: %w", err)
|
|
}
|
|
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER})
|
|
|
|
return tls.X509KeyPair(certPEM, keyPEM)
|
|
}
|
|
|
|
// NewMutualTLSConfig creates a TLS config for mutual authentication.
|
|
// Both server and client verify each other's certificates.
|
|
func NewMutualTLSConfig(cert tls.Certificate) *tls.Config {
|
|
return &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
ClientAuth: tls.RequireAnyClientCert,
|
|
InsecureSkipVerify: true, // Self-signed certs — verify via genome hash instead.
|
|
MinVersion: tls.VersionTLS13,
|
|
}
|
|
}
|
|
|
|
// ExtractPeerIDFromCert extracts the peer ID (CommonName) from a TLS connection.
|
|
func ExtractPeerIDFromCert(conn *tls.Conn) (string, error) {
|
|
state := conn.ConnectionState()
|
|
if len(state.PeerCertificates) == 0 {
|
|
return "", fmt.Errorf("no peer certificate")
|
|
}
|
|
return state.PeerCertificates[0].Subject.CommonName, nil
|
|
}
|