]> Sergey Matveev's repositories - tofuproxy.git/commitdiff
Missing source
authorSergey Matveev <stargrave@stargrave.org>
Wed, 8 Sep 2021 17:47:54 +0000 (20:47 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Wed, 8 Sep 2021 17:47:54 +0000 (20:47 +0300)
tlsauth.go [new file with mode: 0644]

diff --git a/tlsauth.go b/tlsauth.go
new file mode 100644 (file)
index 0000000..531245d
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+tofuproxy -- HTTP proxy with TLS certificates management
+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/>.
+*/
+
+package tofuproxy
+
+import (
+       "bytes"
+       "crypto/tls"
+       "crypto/x509"
+       "errors"
+       "fmt"
+       "log"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "strconv"
+       "strings"
+
+       "go.cypherpunks.ru/ucspi"
+       "go.stargrave.org/tofuproxy/fifos"
+)
+
+var CCerts string
+
+type ClientCertificateGetter struct {
+       host string
+}
+
+func (g *ClientCertificateGetter) get(
+       cri *tls.CertificateRequestInfo,
+) (*tls.Certificate, error) {
+       var b bytes.Buffer
+       b.WriteString(fmt.Sprintf(`
+wm title . "TLS client authentication: %s"
+
+label .lVersion -text "Version: %s"
+grib .lVersion
+
+set lb [listbox .lb]
+.lb insert end ""
+`,
+               g.host,
+               ucspi.TLSVersion(cri.Version),
+       ))
+
+       ents, err := os.ReadDir(CCerts)
+       if err != nil {
+               log.Fatalln(err)
+       }
+       certs := make([]*x509.Certificate, 0, len(ents))
+       tlsCerts := make([]*tls.Certificate, 0, len(ents))
+       for i, ent := range ents {
+               p := filepath.Join(CCerts, ent.Name())
+               _, cert, err := ucspi.CertificateFromFile(p)
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               prv, err := ucspi.PrivateKeyFromFile(p)
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               certs = append(certs, cert)
+               tlsCerts = append(tlsCerts, &tls.Certificate{
+                       Certificate: [][]byte{cert.Raw},
+                       PrivateKey:  prv,
+               })
+               b.WriteString(fmt.Sprintf(".lb insert end \"%d: %s\"\n", i, cert.Subject))
+       }
+       b.WriteString(`
+grid .lb
+
+proc submit {} {
+    global lb
+    puts [$lb get active]
+    exit
+}
+
+button .submit -text "Use" -command submit
+grid .submit
+`)
+       cmd := exec.Command(CmdWish)
+       cmd.Stdin = &b
+       out, err := cmd.Output()
+       if err != nil {
+               return nil, err
+       }
+       lines := strings.Split(string(out), "\n")
+       if len(lines) < 1 {
+               return nil, errors.New("invalid output from authentication form")
+       }
+       t := strings.Split(lines[0], ":")[0]
+       i, err := strconv.Atoi(t)
+       if err != nil {
+               return &tls.Certificate{}, nil
+       }
+       fifos.SinkCert <- fmt.Sprintf("ClientAuth\t%s\t%s", g.host, certs[i].Subject)
+       return tlsCerts[i], nil
+}