]> Cypherpunks.ru repositories - ucspi.git/blob - cmd/tlss/main.go
Unify copyright comment format
[ucspi.git] / cmd / tlss / main.go
1 // ucspi/cmd/tlss -- UCSPI TCP proxy server
2 // Copyright (C) 2021-2024 Sergey Matveev <stargrave@stargrave.org>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 package main
17
18 import (
19         "crypto/tls"
20         "crypto/x509"
21         "flag"
22         "fmt"
23         "io"
24         "log"
25         "os"
26         "os/exec"
27
28         "go.cypherpunks.ru/ucspi"
29 )
30
31 func main() {
32         crtPath := flag.String("cert", "cert.pem", "Path to server X.509 certificate")
33         prvPath := flag.String("key", "prv.pem", "Path to server PKCS#8 private key")
34         casPath := flag.String("client-ca", "", "Require client authentication, path to CA certificates file")
35         flag.Usage = func() {
36                 fmt.Fprintf(os.Stderr, `Usage: tcpserver host port tlss [-client-ca CAs.pem]
37         -cert cert.pem -key prv.pem program [args...]
38
39 `)
40                 flag.PrintDefaults()
41         }
42         flag.Parse()
43         log.SetFlags(log.Lshortfile)
44
45         crtRaw, _, err := ucspi.CertificateFromFile(*crtPath)
46         if err != nil {
47                 log.Fatalln(err)
48         }
49         prv, err := ucspi.PrivateKeyFromFile(*prvPath)
50         if err != nil {
51                 log.Fatalln(err)
52         }
53         var cas *x509.CertPool
54         if *casPath != "" {
55                 _, cas, err = ucspi.CertPoolFromFile(*casPath)
56                 if err != nil {
57                         log.Fatalln(err)
58                 }
59         }
60
61         cfg := &tls.Config{
62                 Certificates: []tls.Certificate{{
63                         Certificate: [][]byte{crtRaw},
64                         PrivateKey:  prv,
65                 }},
66                 ClientCAs: cas,
67         }
68         if *casPath != "" {
69                 cfg.ClientAuth = tls.RequireAndVerifyClientCert
70         }
71
72         conn, _ := ucspi.NewConn(os.Stdin, os.Stdout)
73         tlsConn := tls.Server(conn, cfg)
74         if err = tlsConn.Handshake(); err != nil {
75                 log.Fatalln(err)
76         }
77         var dn string
78         if *casPath != "" {
79                 dn = tlsConn.ConnectionState().PeerCertificates[0].Subject.String()
80         }
81
82         rr, rw, err := os.Pipe()
83         if err != nil {
84                 log.Fatalln(err)
85         }
86         wr, ww, err := os.Pipe()
87         if err != nil {
88                 log.Fatalln(err)
89         }
90         args := flag.Args()
91         cmd := exec.Command(args[0], args[1:]...)
92         cmd.Stdin = rr
93         cmd.Stdout = ww
94         cmd.Stderr = os.Stderr
95         cmd.Env = append(os.Environ(), "PROTO=TLS")
96         if dn != "" {
97                 cmd.Env = append(cmd.Env, "TLSREMOTEDN="+dn)
98         }
99
100         if err = cmd.Start(); err != nil {
101                 log.Fatalln(err)
102         }
103         worker := make(chan struct{})
104         go func() {
105                 io.Copy(rw, tlsConn)
106                 rw.Close()
107         }()
108         go func() {
109                 io.Copy(tlsConn, wr)
110                 tlsConn.Close()
111                 close(worker)
112         }()
113         err = cmd.Wait()
114         ww.Close()
115         <-worker
116         if err != nil {
117                 log.Fatalln(err)
118         }
119 }