Skip to content

Commit 285de31

Browse files
committed
feat(tls): add simple tls support
1 parent 8b59a3e commit 285de31

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type Config struct {
3737
DisplayMaxBrightness int `json:"display_max_brightness"`
3838
DisplayDimAfterSec int `json:"display_dim_after_sec"`
3939
DisplayOffAfterSec int `json:"display_off_after_sec"`
40+
TLSMode string `json:"tls_mode"`
4041
UsbConfig *UsbConfig `json:"usb_config"`
4142
}
4243

@@ -50,6 +51,7 @@ var defaultConfig = &Config{
5051
DisplayMaxBrightness: 64,
5152
DisplayDimAfterSec: 120, // 2 minutes
5253
DisplayOffAfterSec: 1800, // 30 minutes
54+
TLSMode: "",
5355
UsbConfig: &UsbConfig{
5456
VendorId: "0x1d6b", //The Linux Foundation
5557
ProductId: "0x0104", //Multifunction Composite Gadget

main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ func Main() {
6868
}()
6969
//go RunFuseServer()
7070
go RunWebServer()
71+
if config.TLSMode != "" {
72+
go RunWebSecureServer()
73+
}
7174
// If the cloud token isn't set, the client won't be started by default.
7275
// However, if the user adopts the device via the web interface, handleCloudRegister will start the client.
7376
if config.CloudToken != "" {

web_tls.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package kvm
2+
3+
import (
4+
"crypto/ecdsa"
5+
"crypto/elliptic"
6+
"crypto/rand"
7+
"crypto/tls"
8+
"crypto/x509"
9+
"crypto/x509/pkix"
10+
"encoding/pem"
11+
"log"
12+
"math/big"
13+
"net"
14+
"net/http"
15+
"strings"
16+
"sync"
17+
"time"
18+
)
19+
20+
const (
21+
WebSecureListen = ":443"
22+
WebSecureSelfSignedDefaultDomain = "jetkvm.local"
23+
WebSecureSelfSignedDuration = 365 * 24 * time.Hour
24+
)
25+
26+
var (
27+
tlsCerts = make(map[string]*tls.Certificate)
28+
tlsCertLock = &sync.Mutex{}
29+
)
30+
31+
// RunWebSecureServer runs a web server with TLS.
32+
func RunWebSecureServer() {
33+
r := setupRouter()
34+
35+
server := &http.Server{
36+
Addr: WebSecureListen,
37+
Handler: r,
38+
TLSConfig: &tls.Config{
39+
// TODO: cache certificate in persistent storage
40+
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
41+
hostname := WebSecureSelfSignedDefaultDomain
42+
if info.ServerName != "" {
43+
hostname = info.ServerName
44+
} else {
45+
hostname = strings.Split(info.Conn.LocalAddr().String(), ":")[0]
46+
}
47+
48+
logger.Infof("TLS handshake for %s, SupportedProtos: %v", hostname, info.SupportedProtos)
49+
50+
cert := createSelfSignedCert(hostname)
51+
52+
return cert, nil
53+
},
54+
},
55+
}
56+
logger.Infof("Starting websecure server on %s", RunWebSecureServer)
57+
err := server.ListenAndServeTLS("", "")
58+
if err != nil {
59+
panic(err)
60+
}
61+
return
62+
}
63+
64+
func createSelfSignedCert(hostname string) *tls.Certificate {
65+
if tlsCert := tlsCerts[hostname]; tlsCert != nil {
66+
return tlsCert
67+
}
68+
tlsCertLock.Lock()
69+
defer tlsCertLock.Unlock()
70+
71+
logger.Infof("Creating self-signed certificate for %s", hostname)
72+
73+
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
74+
if err != nil {
75+
log.Fatalf("Failed to generate private key: %v", err)
76+
}
77+
keyUsage := x509.KeyUsageDigitalSignature
78+
79+
notBefore := time.Now()
80+
notAfter := notBefore.AddDate(1, 0, 0)
81+
82+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
83+
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
84+
if err != nil {
85+
logger.Errorf("Failed to generate serial number: %v", err)
86+
}
87+
88+
dnsName := hostname
89+
ip := net.ParseIP(hostname)
90+
if ip != nil {
91+
dnsName = WebSecureSelfSignedDefaultDomain
92+
}
93+
94+
template := x509.Certificate{
95+
SerialNumber: serialNumber,
96+
Subject: pkix.Name{
97+
CommonName: hostname,
98+
Organization: []string{"JetKVM"},
99+
},
100+
NotBefore: notBefore,
101+
NotAfter: notAfter,
102+
103+
KeyUsage: keyUsage,
104+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
105+
BasicConstraintsValid: true,
106+
107+
DNSNames: []string{dnsName},
108+
IPAddresses: []net.IP{},
109+
}
110+
111+
if ip != nil {
112+
template.IPAddresses = append(template.IPAddresses, ip)
113+
}
114+
115+
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
116+
if err != nil {
117+
logger.Errorf("Failed to create certificate: %v", err)
118+
}
119+
120+
cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
121+
if cert == nil {
122+
logger.Errorf("Failed to encode certificate")
123+
}
124+
125+
tlsCert := &tls.Certificate{
126+
Certificate: [][]byte{derBytes},
127+
PrivateKey: priv,
128+
}
129+
tlsCerts[hostname] = tlsCert
130+
131+
return tlsCert
132+
}

0 commit comments

Comments
 (0)