-/*
-tofuproxy -- flexible HTTP/HTTPS proxy, TLS terminator, X.509 TOFU
- manager, WARC/geminispace browser
-Copyright (C) 2021 Sergey Matveev <stargrave@stargrave.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, version 3 of the License.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+// tofuproxy -- flexible HTTP/HTTPS proxy, TLS terminator, X.509 TOFU
+// manager, WARC/geminispace browser
+// Copyright (C) 2021-2024 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
package tofuproxy
"crypto/x509"
"encoding/hex"
"encoding/pem"
+ "errors"
"fmt"
+ "io/fs"
"log"
"os"
"os/exec"
if certTheirHash == certOurHash {
return ErrRejected{host}
}
- daneExists, daneMatched := dane(host, certTheir)
+ daneExists, daneMatched := DANE(host, certTheir)
if daneExists {
if daneMatched {
fifos.LogDANE <- fmt.Sprintf("%s\tACK", host)
fifos.LogDANE <- fmt.Sprintf("%s\tNAK", host)
}
}
+ if len(verifiedChains) > 0 {
+ caHashes := make(map[string]struct{})
+ for _, certs := range verifiedChains {
+ for _, cert := range certs {
+ caHashes[spkiHash(cert)] = struct{}{}
+ }
+ }
+ var restrictedHosts []string
+ caches.RestrictedM.RLock()
+ for h := range caHashes {
+ restrictedHosts = append(restrictedHosts, caches.Restricted[h]...)
+ }
+ caches.RestrictedM.RUnlock()
+ if len(restrictedHosts) > 0 {
+ for _, h := range restrictedHosts {
+ if host == h || strings.HasSuffix(host, "."+h) {
+ goto HostIsNotRestricted
+ }
+ }
+ fifos.LogCert <- fmt.Sprintf("Restricted\t%s", host)
+ return ErrRejected{host}
+ }
+ }
+HostIsNotRestricted:
fn := filepath.Join(Certs, host)
certsOur, _, err := ucspi.CertPoolFromFile(fn)
if err == nil || dialErr != nil || (daneExists && !daneMatched) {
caches.AcceptedM.Lock()
caches.Accepted[host] = certTheirHash
caches.AcceptedM.Unlock()
- if bytes.Compare(certsOur[0].Raw, rawCerts[0]) != 0 {
+ if !bytes.Equal(certsOur[0].Raw, rawCerts[0]) {
fifos.LogCert <- fmt.Sprintf("Refresh\t%s\t%s", host, certTheirHash)
goto CertUpdate
}
return nil
}
var b bytes.Buffer
- b.WriteString(fmt.Sprintf("set host \"%s\"\n", host))
+ fmt.Fprintf(&b, "set host \"%s\"\n", host)
if dialErr == nil {
- b.WriteString(fmt.Sprintf("set err \"\"\n"))
+ fmt.Fprintf(&b, "set err \"\"\n")
} else {
- b.WriteString(fmt.Sprintf("set err \"%s\"\n", dialErr.Error()))
+ fmt.Fprintf(&b, "set err \"%s\"\n", dialErr.Error())
}
var daneStatus string
if daneExists {
daneStatus = "bad"
}
}
- b.WriteString(fmt.Sprintf("set daneStatus \"%s\"\n", daneStatus))
+ fmt.Fprintf(&b, "set daneStatus \"%s\"\n", daneStatus)
hexCerts := make([]string, 0, len(rawCerts))
for _, rawCert := range rawCerts {
hexCerts = append(hexCerts, hex.EncodeToString([]byte(certInfo(rawCert))))
}
- b.WriteString(fmt.Sprintf(
- "set certsTheir \"%s\"\n", strings.Join(hexCerts, " "),
- ))
+ fmt.Fprintf(&b, "set certsTheir \"%s\"\n", strings.Join(hexCerts, " "))
hexCerts = make([]string, 0, len(certsOur))
for _, cert := range certsOur {
hexCerts = append(hexCerts, hex.EncodeToString([]byte(certInfo(cert.Raw))))
}
- b.WriteString(fmt.Sprintf(
- "set certsOur \"%s\"\n", strings.Join(hexCerts, " "),
- ))
+ fmt.Fprintf(&b, "set certsOur \"%s\"\n", strings.Join(hexCerts, " "))
b.WriteString(VerifyDialog)
cmd := exec.Command(CmdWish)
- // ioutil.WriteFile("/tmp/verify-dialog.tcl", b.Bytes(), 0666)
+ // os.WriteFile("/tmp/verify-dialog.tcl", b.Bytes(), 0666)
cmd.Stdin = &b
err = cmd.Run()
exitError, ok := err.(*exec.ExitError)
return ErrRejected{host}
}
} else {
- if !os.IsNotExist(err) {
+ if !errors.Is(err, fs.ErrNotExist) {
return err
}
fifos.LogCert <- fmt.Sprintf("TOFU\t%s\t%s", host, certTheirHash)