+++ /dev/null
-/*
-tofuproxy -- flexible HTTP/WARC 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/caches"
- "go.stargrave.org/tofuproxy/fifos"
-)
-
-var CCerts string
-
-type ClientCertificateGetter struct {
- host string
- auth bool
-}
-
-func (g *ClientCertificateGetter) get(
- cri *tls.CertificateRequestInfo,
-) (*tls.Certificate, error) {
- caches.TLSAuthCacheM.RLock()
- tlsCert := caches.TLSAuthCache[g.host]
- caches.TLSAuthCacheM.RUnlock()
- if tlsCert != nil {
- return tlsCert, nil
- }
- sigSchemes := make([]string, 0, len(cri.SignatureSchemes))
- for _, ss := range cri.SignatureSchemes {
- sigSchemes = append(sigSchemes, ss.String())
- }
- var b bytes.Buffer
- b.WriteString(fmt.Sprintf(`
-tk_setPalette grey
-wm title . "TLS client authentication: %s"
-
-set lb [listbox .lb]
-.lb insert end ""
-grid .lb
-
-proc login {} {
- global lb
- puts [$lb get active]
- exit
-}
-
-button .login -text "Use" -command login
-grid .login
-
-bind . <KeyPress> {switch -exact %%K {
- q {exit 0} ; # reject once
- l login
-}}
-
-label .lTLSVersion -text "TLS version: %s"
-grid .lTLSVersion
-
-set sigSchemeRow 0
-foreach sigScheme {%s} {
- label .lSignatureScheme$sigSchemeRow -text "Signature scheme: $sigScheme"
- grid .lSignatureScheme$sigSchemeRow
- incr sigSchemeRow
-}
-
-`,
- g.host,
- ucspi.TLSVersion(cri.Version),
- strings.Join(sigSchemes, " "),
- ))
-
- 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))
- }
- // ioutil.WriteFile("/tmp/tls-auth-dialog.tcl", b.Bytes(), 0666)
- 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.LogTLSAuth <- fmt.Sprintf("%s\t%s", g.host, certs[i].Subject)
- caches.TLSAuthCacheM.Lock()
- caches.TLSAuthCache[g.host] = tlsCerts[i]
- caches.TLSAuthCacheM.Unlock()
- g.auth = true
- return tlsCerts[i], nil
-}