diff options
Diffstat (limited to 'tls.go')
| -rw-r--r-- | tls.go | 90 |
1 files changed, 86 insertions, 4 deletions
@@ -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, + } +} |
