aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradnano <[email protected]>2020-09-27 23:49:41 -0400
committeradnano <[email protected]>2020-09-27 23:49:41 -0400
commitae4b458964700692dd2bc03ba3f269ea88269fda (patch)
tree55eb3422c9b0d68d27d1a0794c5f5f0651fa5c72
parentRemove tilde from comment (diff)
downloadgo-gemini-ae4b458964700692dd2bc03ba3f269ea88269fda.tar.xz
go-gemini-ae4b458964700692dd2bc03ba3f269ea88269fda.zip
Generate certificates on demand
-rw-r--r--cert.go32
-rw-r--r--client.go12
-rw-r--r--examples/cert/cert.go8
-rw-r--r--examples/client/client.go24
4 files changed, 46 insertions, 30 deletions
diff --git a/cert.go b/cert.go
index 8c82aa4..90bb514 100644
--- a/cert.go
+++ b/cert.go
@@ -4,6 +4,7 @@ import (
"bytes"
"crypto/ed25519"
"crypto/rand"
+ "crypto/tls"
"crypto/x509"
"encoding/pem"
"math/big"
@@ -14,27 +15,25 @@ import (
)
// CertificateStore maps hostnames to certificates.
-type CertificateStore struct {
- store map[string]*x509.Certificate // map of hostnames to certificates
-}
-
-func NewCertificateStore() *CertificateStore {
- return &CertificateStore{
- store: map[string]*x509.Certificate{},
- }
-}
+type CertificateStore map[string]*tls.Certificate
-func (c *CertificateStore) Put(hostname string, cert *x509.Certificate) {
- c.store[hostname] = cert
+// NewCertificateStore creates and returns a new certificate store.
+func NewCertificateStore() CertificateStore {
+ return map[string]*tls.Certificate{}
}
-func (c *CertificateStore) Get(hostname string) *x509.Certificate {
- return c.store[hostname]
+// NewCertificate creates and returns a new parsed certificate.
+func NewCertificate(host string, duration time.Duration) (tls.Certificate, error) {
+ crt, key, err := NewRawCertificate(host, duration)
+ if err != nil {
+ return tls.Certificate{}, err
+ }
+ return tls.X509KeyPair(crt, key)
}
-// NewCertificate creates and returns a raw certificate for the given host.
+// NewRawCertificate creates and returns a raw certificate for the given host.
// It generates a self-signed TLS certificate and a ED25519 private key.
-func NewCertificate(host string) (crt, key []byte, err error) {
+func NewRawCertificate(host string, duration time.Duration) (crt, key []byte, err error) {
// Generate a ED25519 private key
_, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
@@ -47,8 +46,7 @@ func NewCertificate(host string) (crt, key []byte, err error) {
keyUsage := x509.KeyUsageDigitalSignature
notBefore := time.Now()
- validFor := 365 * 24 * time.Hour
- notAfter := notBefore.Add(validFor)
+ notAfter := notBefore.Add(duration)
// Generate the serial number
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
diff --git a/client.go b/client.go
index 504fd18..37b1b6d 100644
--- a/client.go
+++ b/client.go
@@ -185,11 +185,11 @@ type Client struct {
KnownHosts KnownHosts
// CertificateStore contains all the certificates that the client has stored.
- CertificateStore *CertificateStore
+ CertificateStore CertificateStore
// GetCertificate, if not nil, will be called to determine which certificate
// (if any) should be used for a request.
- GetCertificate func(req *Request, store *CertificateStore) *tls.Certificate
+ GetCertificate func(hostname string, store CertificateStore) *tls.Certificate
// TrustCertificate, if not nil, will be called to determine whether the
// client should trust the given certificate.
@@ -205,14 +205,14 @@ func (c *Client) Send(req *Request) (*Response, error) {
MinVersion: tls.VersionTLS12,
GetClientCertificate: func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
if c.GetCertificate != nil {
- if cert := c.GetCertificate(req, c.CertificateStore); cert != nil {
+ if cert := c.GetCertificate(req.Hostname(), c.CertificateStore); cert != nil {
return cert, nil
}
}
- if req.Certificate == nil {
- return &tls.Certificate{}, nil
+ if req.Certificate != nil {
+ return req.Certificate, nil
}
- return req.Certificate, nil
+ return &tls.Certificate{}, nil
},
VerifyPeerCertificate: func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
// Parse the certificate
diff --git a/examples/cert/cert.go b/examples/cert/cert.go
index 23975c0..b9a284f 100644
--- a/examples/cert/cert.go
+++ b/examples/cert/cert.go
@@ -4,19 +4,21 @@ package main
import (
"log"
+ "time"
- "git.sr.ht/~adnano/go-gemini"
+ gmi "git.sr.ht/~adnano/go-gemini"
)
func main() {
host := "localhost"
- crt, key, err := gemini.NewCertificate(host)
+ duration := 365 * 24 * time.Hour
+ crt, key, err := gmi.NewRawCertificate(host, duration)
if err != nil {
log.Fatal(err)
}
- if err := gemini.WriteCertificate(host, crt, key); err != nil {
+ if err := gmi.WriteCertificate(host, crt, key); err != nil {
log.Fatal(err)
}
}
diff --git a/examples/client/client.go b/examples/client/client.go
index 22c96de..a64365f 100644
--- a/examples/client/client.go
+++ b/examples/client/client.go
@@ -4,21 +4,22 @@ package main
import (
"bufio"
+ "crypto/tls"
"crypto/x509"
"fmt"
"os"
+ "time"
- "git.sr.ht/~adnano/go-gemini"
+ gmi "git.sr.ht/~adnano/go-gemini"
)
var (
scanner = bufio.NewScanner(os.Stdin)
- client *gmi.Client
+ client = &gmi.Client{}
)
func init() {
// Initialize the client
- client = &gmi.Client{}
client.KnownHosts.Load() // Load known hosts
client.TrustCertificate = func(hostname string, cert *x509.Certificate, knownHosts *gmi.KnownHosts) error {
err := knownHosts.Lookup(hostname, cert)
@@ -45,6 +46,21 @@ func init() {
}
return err
}
+
+ client.CertificateStore = gmi.NewCertificateStore()
+ client.GetCertificate = func(hostname string, store gmi.CertificateStore) *tls.Certificate {
+ if cert, ok := store[hostname]; ok {
+ return cert
+ }
+ // Generate a certificate
+ duration := time.Hour
+ cert, err := gmi.NewCertificate(hostname, duration)
+ if err != nil {
+ return nil
+ }
+ store[hostname] = &cert
+ return &cert
+ }
}
// sendRequest sends a request to the given URL.
@@ -67,7 +83,7 @@ func sendRequest(req *gmi.Request) error {
case gmi.StatusClassRedirect:
fmt.Println("Redirecting to", resp.Meta)
// Make the request to the same host
- red, err := gmi.NewRequestTo(req.Host, resp.Meta)
+ red, err := gmi.NewRequestTo(resp.Meta, req.Host)
if err != nil {
return err
}