mirror of
https://github.com/coalaura/up.git
synced 2025-07-17 21:44:35 +00:00
prefetch cert
This commit is contained in:
@ -135,6 +135,51 @@ func CertificateFingerprint(certificate *x509.Certificate) string {
|
||||
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 {
|
||||
config := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
@ -154,22 +199,11 @@ func NewPinnedClient(store *CertificateStore) *http.Client {
|
||||
name := cs.ServerName
|
||||
fingerprint := CertificateFingerprint(certificate)
|
||||
|
||||
if store.IsPinned(name, fingerprint) {
|
||||
return nil
|
||||
if !store.IsPinned(name, fingerprint) {
|
||||
return errors.New("unknown certificate")
|
||||
}
|
||||
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
|
||||
return &http.Client{
|
||||
|
@ -141,6 +141,10 @@ func run(_ context.Context, cmd *cli.Command) error {
|
||||
return fmt.Errorf("failed to load certificate store: %v", err)
|
||||
}
|
||||
|
||||
if err = PreFetchServerCertificate(store, hostname); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := NewPinnedClient(store)
|
||||
|
||||
log.Println("Requesting challenge...")
|
||||
|
Reference in New Issue
Block a user