erste module drin.
zwischenstand: Architektur aktualisiert, TOFU implementiert,
This commit is contained in:
1 parent
9d5789c5d7
commit
c8df9d7651
41 files changed
+6455
-36
No files matched your search
@@ -0,0 +1,139 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLoadOrCreateServerCert_Creates(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
sc, err := LoadOrCreateServerCert(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadOrCreateServerCert: %v", err)
|
||||
}
|
||||
for name, wantPerm := range map[string]os.FileMode{serverKeyFile: 0o600, serverCertFile: 0o644} {
|
||||
info, err := os.Stat(filepath.Join(dir, name))
|
||||
if err != nil {
|
||||
t.Fatalf("%s fehlt: %v", name, err)
|
||||
}
|
||||
if info.Mode().Perm() != wantPerm {
|
||||
t.Errorf("%s hat %o, erwartet %o", name, info.Mode().Perm(), wantPerm)
|
||||
}
|
||||
}
|
||||
|
||||
leaf := sc.Leaf()
|
||||
key, ok := leaf.PublicKey.(*ecdsa.PublicKey)
|
||||
if !ok || key.Curve != elliptic.P256() {
|
||||
t.Errorf("Schlüssel ist kein ECDSA P-256: %T", leaf.PublicKey)
|
||||
}
|
||||
// Selbstsigniert, aber bewusst keine CA (könnte sonst weitere
|
||||
// Zertifikate ausstellen) – daher nicht CheckSignatureFrom.
|
||||
if err := leaf.CheckSignature(leaf.SignatureAlgorithm, leaf.RawTBSCertificate, leaf.Signature); err != nil ||
|
||||
leaf.Issuer.String() != leaf.Subject.String() {
|
||||
t.Errorf("nicht selbstsigniert: %v", err)
|
||||
}
|
||||
if leaf.IsCA {
|
||||
t.Error("Server-Zertifikat darf keine CA sein")
|
||||
}
|
||||
if len(leaf.ExtKeyUsage) != 1 || leaf.ExtKeyUsage[0] != x509.ExtKeyUsageServerAuth {
|
||||
t.Errorf("ExtKeyUsage = %v, erwartet ServerAuth", leaf.ExtKeyUsage)
|
||||
}
|
||||
if leaf.NotAfter.Before(time.Now().AddDate(9, 0, 0)) {
|
||||
t.Errorf("gültig nur bis %v – ein Ablauf würde alle Pins brechen", leaf.NotAfter)
|
||||
}
|
||||
if sc.Fingerprint != FingerprintOf(leaf) {
|
||||
t.Error("Fingerprint passt nicht zum Zertifikat")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadOrCreateServerCert_StableAcrossRestarts(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
first, err := LoadOrCreateServerCert(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
second, err := LoadOrCreateServerCert(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("erneutes Laden: %v", err)
|
||||
}
|
||||
if first.Fingerprint != second.Fingerprint {
|
||||
t.Error("Fingerprint hat sich beim Neustart geändert – alle Agents würden die Verbindung verweigern")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadOrCreateServerCert_Errors(t *testing.T) {
|
||||
t.Run("nur Zertifikat vorhanden", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
LoadOrCreateServerCert(dir)
|
||||
os.Remove(filepath.Join(dir, serverKeyFile))
|
||||
if _, err := LoadOrCreateServerCert(dir); !errors.Is(err, ErrIncompleteCert) {
|
||||
t.Errorf("erwartet ErrIncompleteCert, bekommen %v", err)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(dir, serverKeyFile)); err == nil {
|
||||
t.Error("fehlender Schlüssel wurde stillschweigend neu erzeugt")
|
||||
}
|
||||
})
|
||||
t.Run("nur Schlüssel vorhanden", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
LoadOrCreateServerCert(dir)
|
||||
os.Remove(filepath.Join(dir, serverCertFile))
|
||||
if _, err := LoadOrCreateServerCert(dir); !errors.Is(err, ErrIncompleteCert) {
|
||||
t.Errorf("erwartet ErrIncompleteCert, bekommen %v", err)
|
||||
}
|
||||
})
|
||||
t.Run("Schlüssel zu offen", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
LoadOrCreateServerCert(dir)
|
||||
os.Chmod(filepath.Join(dir, serverKeyFile), 0o644)
|
||||
if _, err := LoadOrCreateServerCert(dir); !errors.Is(err, ErrInsecureKeyFile) {
|
||||
t.Errorf("erwartet ErrInsecureKeyFile, bekommen %v", err)
|
||||
}
|
||||
})
|
||||
t.Run("Schlüssel passt nicht zum Zertifikat", func(t *testing.T) {
|
||||
a, b := t.TempDir(), t.TempDir()
|
||||
LoadOrCreateServerCert(a)
|
||||
LoadOrCreateServerCert(b)
|
||||
data, _ := os.ReadFile(filepath.Join(b, serverCertFile))
|
||||
os.WriteFile(filepath.Join(a, serverCertFile), data, 0o644)
|
||||
if _, err := LoadOrCreateServerCert(a); err == nil {
|
||||
t.Error("erwartet Fehler bei fremdem Zertifikat")
|
||||
}
|
||||
})
|
||||
t.Run("Verzeichnis fehlt", func(t *testing.T) {
|
||||
if _, err := LoadOrCreateServerCert(filepath.Join(t.TempDir(), "fehlt")); err == nil {
|
||||
t.Error("erwartet Fehler")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServerTLSConfig_OnlyTLS13(t *testing.T) {
|
||||
sc, err := LoadOrCreateServerCert(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg := ServerTLSConfig(sc)
|
||||
if cfg.MinVersion != tls.VersionTLS13 {
|
||||
t.Errorf("MinVersion = %x, erwartet TLS 1.3", cfg.MinVersion)
|
||||
}
|
||||
|
||||
srv := httptest.NewUnstartedServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
|
||||
srv.TLS = cfg
|
||||
srv.StartTLS()
|
||||
defer srv.Close()
|
||||
|
||||
old := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true, MaxVersion: tls.VersionTLS12,
|
||||
}}}
|
||||
if _, err := old.Get(srv.URL); err == nil {
|
||||
t.Error("TLS-1.2-Client wurde akzeptiert")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user