"crypto/x509"
"encoding/pem"
"fmt"
+ "io/ioutil"
"log"
"os"
"os/exec"
"go.cypherpunks.ru/ucspi"
)
+func certInfo(certRaw []byte) string {
+ cmd := exec.Command("certtool", "--certificate-info", "--inder")
+ cmd.Stdin = bytes.NewReader(certRaw)
+ out, err := cmd.Output()
+ if err != nil {
+ return err.Error()
+ }
+ lines := make([]string, 0, 128)
+ for i, line := range strings.Split(string(out), "\n") {
+ if strings.Contains(line, "ASCII:") {
+ continue
+ }
+ lines = append(lines, fmt.Sprintf(
+ "%03d %s", i, strings.ReplaceAll(line, `"`, `\"`),
+ ))
+ }
+ return strings.Join(lines, "\n")
+}
+
func verifyCert(
host string,
dialErr error,
}
return nil
}
- cmd := exec.Command(
- "xmessage",
- "-buttons",
- "Accept:10,Once:11,Reject:12",
- "-file", "-",
- )
var b bytes.Buffer
- b.WriteString("Host: " + host)
+ b.WriteString(fmt.Sprintf("wm title . \"%s\"\n", host))
+
if dialErr != nil {
- b.WriteString("\nError: " + dialErr.Error())
+ b.WriteString(fmt.Sprintf(`set tErr [text .tErr]
+$tErr insert end "%s"
+$tErr configure -wrap word -height 5
+`, dialErr.Error()))
+ b.WriteString("grid .tErr -columnspan 3\n")
}
+
if daneExists {
if daneMatched {
- b.WriteString("\nDANE matched")
+ b.WriteString("label .lDANE -bg green -text \"DANE matched\"\n")
} else {
- b.WriteString("\nDANE no match!")
+ b.WriteString("label .lDANE -bg red -text \"DANE not matched!\"\n")
}
+ b.WriteString("grid .lDANE\n")
}
+
+ var bCerts bytes.Buffer
for i, rawCert := range rawCerts {
- b.WriteString(fmt.Sprintf("\nTheir %d:\n", i))
- b.WriteString(certInfo(rawCert))
+ bCerts.WriteString(fmt.Sprintf("Their %d:\n", i))
+ bCerts.WriteString(certInfo(rawCert))
}
+ b.WriteString(fmt.Sprintf(`set tTheir [text .tTheir]
+$tTheir insert end "%s"
+set sbTheir [scrollbar .sbTheir -command [list $tTheir yview]]
+$tTheir configure -wrap word -yscrollcommand [list $sbTheir set]
+`, bCerts.String()))
+ b.WriteString("grid $tTheir $sbTheir -sticky nsew -columnspan 3\n")
+
if certsOur != nil {
- b.WriteString(strings.Repeat("-", 80))
+ bCerts.Reset()
for i, cert := range certsOur {
- b.WriteString(fmt.Sprintf("\nOur %d:\n", i))
- b.WriteString(certInfo(cert.Raw))
+ bCerts.WriteString(fmt.Sprintf("Our %d:\n", i))
+ bCerts.WriteString(certInfo(cert.Raw))
}
+ b.WriteString(fmt.Sprintf(`set tOur [text .tOur]
+$tOur insert end "%s"
+set sbOur [scrollbar .sbOur -command [list $tOur yview]]
+$tOur configure -wrap word -yscrollcommand [list $sbOur set]
+`, bCerts.String()))
+ b.WriteString("grid $tOur $sbOur -sticky nsew -columnspan 3\n")
}
+
+ b.WriteString(`
+proc doAccept {} { exit 10 }
+proc doOnce {} { exit 11 }
+proc doReject {} { exit 12 }
+button .bAccept -text "Accept" -bg green -command doAccept
+button .bOnce -text "Once" -command doOnce
+button .bReject -text "Reject" -bg red -command doReject
+grid .bAccept .bOnce .bReject
+grid rowconfigure . 0 -weight 1
+grid columnconfigure . 0 -weight 1
+`)
+
+ cmd := exec.Command("wish8.7")
+ ioutil.WriteFile("/tmp/w.tcl", b.Bytes(), 0666)
cmd.Stdin = &b
- switch cmd.Run().(*exec.ExitError).ExitCode() {
+ err = cmd.Run()
+ exitError, ok := err.(*exec.ExitError)
+ if !ok {
+ sinkCert <- fmt.Sprintf("DENY\t%s\t%s", host, certTheirHash)
+ return ErrRejected{host}
+ }
+ switch exitError.ExitCode() {
case 10:
sinkCert <- fmt.Sprintf("ADD\t%s\t%s", host, certTheirHash)
goto CertUpdate