1
0
mirror of https://github.com/coalaura/up.git synced 2025-07-17 21:44:35 +00:00

prefetch cert

This commit is contained in:
Laura
2025-06-20 23:37:53 +02:00
parent 11c2deb097
commit 9e13dff54c
2 changed files with 52 additions and 14 deletions

View File

@ -135,6 +135,51 @@ func CertificateFingerprint(certificate *x509.Certificate) string {
return fmt.Sprintf("%s-%s", algo, hex.EncodeToString(sum[:])) return fmt.Sprintf("%s-%s", algo, hex.EncodeToString(sum[:]))
} }
func PreFetchServerCertificate(store *CertificateStore, addr string) error {
conn, err := tls.DialWithDialer(&net.Dialer{
Timeout: 5 * time.Second,
}, "tcp", addr, &tls.Config{
InsecureSkipVerify: true,
})
if err != nil {
return err
}
defer conn.Close()
state := conn.ConnectionState()
if len(state.PeerCertificates) == 0 {
return fmt.Errorf("no peer certificates")
}
certificate := state.PeerCertificates[0]
if certificate.Subject.CommonName != "up" {
return errors.New("invalid certificate subject")
}
name := state.ServerName
fingerprint := CertificateFingerprint(certificate)
if store.IsPinned(name, fingerprint) {
return nil
}
log.Printf("Server fingerprint for %s: %s\n", name, fingerprint)
log.Print("Accept? [y/N]: ")
var confirm string
fmt.Scanln(&confirm)
if strings.ToLower(strings.TrimSpace(confirm)) != "y" {
return errors.New("certificate rejected")
}
return store.Pin(name, fingerprint)
}
func NewPinnedClient(store *CertificateStore) *http.Client { func NewPinnedClient(store *CertificateStore) *http.Client {
config := &tls.Config{ config := &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
@ -154,22 +199,11 @@ func NewPinnedClient(store *CertificateStore) *http.Client {
name := cs.ServerName name := cs.ServerName
fingerprint := CertificateFingerprint(certificate) fingerprint := CertificateFingerprint(certificate)
if store.IsPinned(name, fingerprint) { if !store.IsPinned(name, fingerprint) {
return nil return errors.New("unknown certificate")
} }
log.Printf("Server fingerprint for %s: %s\n", name, fingerprint) return nil
log.Print("Accept? [y/N]: ")
var confirm string
fmt.Scanln(&confirm)
if strings.ToLower(strings.TrimSpace(confirm)) != "y" {
return errors.New("certificate rejected")
}
return store.Pin(name, fingerprint)
} }
return &http.Client{ return &http.Client{

View File

@ -141,6 +141,10 @@ func run(_ context.Context, cmd *cli.Command) error {
return fmt.Errorf("failed to load certificate store: %v", err) return fmt.Errorf("failed to load certificate store: %v", err)
} }
if err = PreFetchServerCertificate(store, hostname); err != nil {
return err
}
client := NewPinnedClient(store) client := NewPinnedClient(store)
log.Println("Requesting challenge...") log.Println("Requesting challenge...")