summaryrefslogtreecommitdiff
path: root/tls.go
diff options
context:
space:
mode:
authortjp <tjp@ctrl-c.club>2024-01-08 11:10:24 -0700
committertjp <tjp@ctrl-c.club>2024-01-08 11:10:24 -0700
commita90327bcc0f46171e30a4a549fb5b44f8e91e303 (patch)
tree8595b256c8e9fa2232525199c51021e0efbebac4 /tls.go
parent230933ee0e4bce6ddf25e0816fff0bd30e3c8864 (diff)
identity management and use
Diffstat (limited to 'tls.go')
-rw-r--r--tls.go90
1 files changed, 86 insertions, 4 deletions
diff --git a/tls.go b/tls.go
index 22a248e..0ad56f4 100644
--- a/tls.go
+++ b/tls.go
@@ -1,24 +1,35 @@
package main
import (
+ "crypto/ed25519"
+ "crypto/rand"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
+ "crypto/x509/pkix"
"encoding/hex"
"errors"
+ "math/big"
+ "os"
+ "time"
)
-func tlsConfig() *tls.Config {
- return &tls.Config{
- InsecureSkipVerify: true,
- VerifyConnection: tofuVerify,
+func tlsConfig(state *BrowserState) *tls.Config {
+ if ident := state.Identities.Get(state.Url); ident != nil {
+ return ident
}
+ return anonymousTLS
}
var tofuStore map[string]string
var ErrTOFUViolation = errors.New("certificate for this domain has changed")
+var anonymousTLS = &tls.Config{
+ InsecureSkipVerify: true,
+ VerifyConnection: tofuVerify,
+}
+
func tofuVerify(connState tls.ConnectionState) error {
certhash, err := hashCert(connState.PeerCertificates[0])
if err != nil {
@@ -45,3 +56,74 @@ func hashCert(cert *x509.Certificate) (string, error) {
hash := sha256.Sum256(pubkeybytes)
return hex.EncodeToString(hash[:]), nil
}
+
+func createIdentity(state *BrowserState, name string) (*tls.Config, error) {
+ pubkey, privkey, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ return nil, err
+ }
+
+ rawprivkey, err := x509.MarshalPKCS8PrivateKey(privkey)
+ if err != nil {
+ return nil, err
+ }
+
+ commonName := name
+ state.Readline.SetPrompt("Common Name [" + name + "]: ")
+ if line, err := state.Readline.Readline(); err != nil {
+ return nil, err
+ } else if line != "" {
+ commonName = line
+ }
+
+ expiration := time.Date(9999, 12, 31, 0, 0, 0, 0, time.UTC)
+ state.Readline.SetPrompt("Expiration (yyyy-mm-dd) [9999-12-31]: ")
+ if line, err := state.Readline.Readline(); err != nil {
+ return nil, err
+ } else if line != "" {
+ expiration, err = time.ParseInLocation(time.DateOnly, line, time.UTC)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ snLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, snLimit)
+ if err != nil {
+ return nil, err
+ }
+
+ template := &x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{CommonName: commonName},
+ NotAfter: expiration,
+ KeyUsage: x509.KeyUsageDigitalSignature,
+ BasicConstraintsValid: true,
+ }
+
+ rawcert, err := x509.CreateCertificate(rand.Reader, template, template, pubkey, privkey)
+ if err != nil {
+ return nil, err
+ }
+
+ identFile, err := saveIdentity(name, rawprivkey, rawcert)
+ if err != nil {
+ return nil, err
+ }
+
+ cert, err := tls.LoadX509KeyPair(identFile, identFile)
+ if err != nil {
+ _ = os.Remove(identFile)
+ return nil, err
+ }
+
+ return identityForCert(cert), nil
+}
+
+func identityForCert(cert tls.Certificate) *tls.Config {
+ return &tls.Config{
+ Certificates: []tls.Certificate{cert},
+ InsecureSkipVerify: true,
+ VerifyConnection: tofuVerify,
+ }
+}