1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-11-12 19:55:59 +01:00
galene/webserver/certificate.go
Juliusz Chroboczek b1babf5b77 Update TLS certificates, generate certificate if not found.
We now notice that a TLS certificate on disk has changed, and we
generate a self-signed certificate if none is found.
2021-02-24 20:29:03 +01:00

98 lines
2.2 KiB
Go

package webserver
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"log"
"math/big"
"os"
"path/filepath"
"sync/atomic"
"time"
)
type certInfo struct {
certificate *tls.Certificate
keyTime time.Time
certTime time.Time
}
var certificate atomic.Value
func generateCertificate(dataDir string) (tls.Certificate, error) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return tls.Certificate{}, err
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
now := time.Now()
template := x509.Certificate{
SerialNumber: serialNumber,
NotBefore: now,
NotAfter: now.Add(365 * 24 * time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
bytes, err := x509.CreateCertificate(
rand.Reader, &template, &template, &priv.PublicKey, priv,
)
if err != nil {
return tls.Certificate{}, err
}
return tls.Certificate{
Certificate: [][]byte{bytes},
PrivateKey: priv,
}, nil
}
func fileTime(filename string) time.Time {
fi, err := os.Stat(filename)
if err != nil {
if !os.IsNotExist(err) {
log.Printf("%v: %v", filename, err)
}
return time.Time{}
}
return fi.ModTime()
}
func getCertificate(dataDir string) (*tls.Certificate, error) {
info, ok := certificate.Load().(*certInfo)
certFile := filepath.Join(dataDir, "cert.pem")
keyFile := filepath.Join(dataDir, "key.pem")
certTime := fileTime(certFile)
keyTime := fileTime(keyFile)
if !ok || !info.certTime.Equal(certTime) || !info.keyTime.Equal(keyTime) {
var cert tls.Certificate
if certTime.Equal(time.Time{}) || keyTime.Equal(time.Time{}) {
log.Printf("Generating self-signed certificate")
var err error
cert, err = generateCertificate(dataDir)
if err != nil {
return nil, err
}
} else {
var err error
cert, err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}
}
info = &certInfo{
certificate: &cert,
certTime: certTime,
keyTime: keyTime,
}
certificate.Store(info)
}
return info.certificate, nil
}