Update documentation

This commit is contained in:
adnano 2020-09-28 00:29:11 -04:00
parent 21022eb5ac
commit 622ea8e0f1
3 changed files with 40 additions and 4 deletions

View File

@ -82,5 +82,35 @@ certificate. See `examples/client` for an example.
Gemini takes advantage of client certificates for authentication. Gemini takes advantage of client certificates for authentication.
See `examples/auth` for an example server which authenticates its users with a If a server responds with `StatusCertificateRequired`, clients will generate a
certificate for the site and resend the request with the provided certificate.
In order for this to work, clients must specify the fields `CertificateStore`
and `GetCertificate`:
```go
// Initialize the certificate store.
client.CertificateStore = gmi.NewCertificateStore()
// GetCertificate is called when a server requests a certificate.
// The returned certificate, if not nil, will be used when resending the request.
client.GetCertificate = func(hostname string, store gmi.CertificateStore) *tls.Certificate {
// If the certificate is in the store, return it
if cert, ok := store[hostname]; ok {
return cert
}
// Otherwise, generate a certificate
duration := time.Hour
cert, err := gmi.NewCertificate(hostname, duration)
if err != nil {
return nil
}
// Store and return the certificate
store[hostname] = &cert
return &cert
}
```
Servers can then authenticate their clients with the fingerprint of their
certificates.
See `examples/auth` for an example server which authenticates its users with
username and password, and uses their client certificate to remember sessions. username and password, and uses their client certificate to remember sessions.

View File

@ -34,6 +34,7 @@ type Request struct {
Host string Host string
// Certificate specifies the TLS certificate to use for the request. // Certificate specifies the TLS certificate to use for the request.
// Request certificates take precedence over client certificates.
// This field is ignored by the server. // This field is ignored by the server.
Certificate *tls.Certificate Certificate *tls.Certificate
@ -188,8 +189,10 @@ type Client struct {
// CertificateStore contains all the certificates that the client has stored. // 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 // GetCertificate, if not nil, will be called when a server requests a certificate.
// to use when the server responds with CertificateRequired. // The returned certificate will be used when sending the request again.
// If the certificate is nil, the request will not be sent again and
// the response will be returned.
GetCertificate func(hostname string, store CertificateStore) *tls.Certificate GetCertificate func(hostname string, store CertificateStore) *tls.Certificate
// TrustCertificate, if not nil, will be called to determine whether the // TrustCertificate, if not nil, will be called to determine whether the
@ -205,6 +208,7 @@ func (c *Client) Send(req *Request) (*Response, error) {
InsecureSkipVerify: true, InsecureSkipVerify: true,
MinVersion: tls.VersionTLS12, MinVersion: tls.VersionTLS12,
GetClientCertificate: func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) { GetClientCertificate: func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
// Request certificates take precedence over client certificates
if req.Certificate != nil { if req.Certificate != nil {
return req.Certificate, nil return req.Certificate, nil
} }

View File

@ -49,15 +49,17 @@ func init() {
client.CertificateStore = gmi.NewCertificateStore() client.CertificateStore = gmi.NewCertificateStore()
client.GetCertificate = func(hostname string, store gmi.CertificateStore) *tls.Certificate { client.GetCertificate = func(hostname string, store gmi.CertificateStore) *tls.Certificate {
// If the certificate is in the store, return it
if cert, ok := store[hostname]; ok { if cert, ok := store[hostname]; ok {
return cert return cert
} }
// Generate a certificate // Otherwise, generate a certificate
duration := time.Hour duration := time.Hour
cert, err := gmi.NewCertificate(hostname, duration) cert, err := gmi.NewCertificate(hostname, duration)
if err != nil { if err != nil {
return nil return nil
} }
// Store and return the certificate
store[hostname] = &cert store[hostname] = &cert
return &cert return &cert
} }