2 tofuproxy -- HTTP proxy with TLS certificates management
3 Copyright (C) 2021 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 "go.cypherpunks.ru/ucspi"
34 "go.stargrave.org/tofuproxy/caches"
35 "go.stargrave.org/tofuproxy/fifos"
40 type ClientCertificateGetter struct {
45 func (g *ClientCertificateGetter) get(
46 cri *tls.CertificateRequestInfo,
47 ) (*tls.Certificate, error) {
48 caches.TLSAuthCacheM.RLock()
49 tlsCert := caches.TLSAuthCache[g.host]
50 caches.TLSAuthCacheM.RUnlock()
54 sigSchemes := make([]string, 0, len(cri.SignatureSchemes))
55 for _, ss := range cri.SignatureSchemes {
56 sigSchemes = append(sigSchemes, ss.String())
59 b.WriteString(fmt.Sprintf(`
61 wm title . "TLS client authentication: %s"
73 button .login -text "Use" -command login
76 bind . <KeyPress> {switch -exact %%K {
77 q {exit 0} ; # reject once
81 label .lTLSVersion -text "TLS version: %s"
85 foreach sigScheme {%s} {
86 label .lSignatureScheme$sigSchemeRow -text "Signature scheme: $sigScheme"
87 grid .lSignatureScheme$sigSchemeRow
93 ucspi.TLSVersion(cri.Version),
94 strings.Join(sigSchemes, " "),
97 ents, err := os.ReadDir(CCerts)
101 certs := make([]*x509.Certificate, 0, len(ents))
102 tlsCerts := make([]*tls.Certificate, 0, len(ents))
103 for i, ent := range ents {
104 p := filepath.Join(CCerts, ent.Name())
105 _, cert, err := ucspi.CertificateFromFile(p)
109 prv, err := ucspi.PrivateKeyFromFile(p)
113 certs = append(certs, cert)
114 tlsCerts = append(tlsCerts, &tls.Certificate{
115 Certificate: [][]byte{cert.Raw},
118 b.WriteString(fmt.Sprintf(".lb insert end \"%d: %s\"\n", i, cert.Subject))
120 // ioutil.WriteFile("/tmp/tls-auth-dialog.tcl", b.Bytes(), 0666)
121 cmd := exec.Command(CmdWish)
123 out, err := cmd.Output()
127 lines := strings.Split(string(out), "\n")
129 return nil, errors.New("invalid output from authentication form")
131 t := strings.Split(lines[0], ":")[0]
132 i, err := strconv.Atoi(t)
134 return &tls.Certificate{}, nil
136 fifos.LogTLSAuth <- fmt.Sprintf("%s\t%s", g.host, certs[i].Subject)
137 caches.TLSAuthCacheM.Lock()
138 caches.TLSAuthCache[g.host] = tlsCerts[i]
139 caches.TLSAuthCacheM.Unlock()
141 return tlsCerts[i], nil