2024-01-01 13:19:19 +00:00
|
|
|
package certificates
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rsa"
|
|
|
|
"crypto/tls"
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/pem"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"bytes"
|
|
|
|
"crypto/rand"
|
|
|
|
"crypto/x509"
|
|
|
|
"crypto/x509/pkix"
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/go-acme/lego/v4/certcrypto"
|
|
|
|
"github.com/go-acme/lego/v4/certificate"
|
|
|
|
"github.com/go-acme/lego/v4/lego"
|
|
|
|
)
|
|
|
|
|
2024-01-01 13:47:13 +00:00
|
|
|
func RenewCertificate(old *CertificateWrapper, acmeClient *lego.Client) (CertificateWrapper, error) {
|
|
|
|
pk, _ := base64.StdEncoding.DecodeString(old.PrivateKeyEncoded)
|
|
|
|
res := certificate.Resource{
|
|
|
|
PrivateKey: pk,
|
|
|
|
Certificate: old.Certificate,
|
|
|
|
CSR: old.CSR,
|
|
|
|
}
|
|
|
|
|
|
|
|
new, err := acmeClient.Certificate.Renew(res, true, false, "")
|
|
|
|
if err != nil {
|
|
|
|
return CertificateWrapper{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the new certificate into a wrapper struct
|
|
|
|
tlsCert, err := tls.X509KeyPair(new.Certificate, new.PrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return CertificateWrapper{}, err
|
|
|
|
}
|
|
|
|
wrapper := CertificateWrapper{
|
|
|
|
TlsCertificate: &tlsCert,
|
2024-01-02 17:23:46 +00:00
|
|
|
DomainKey: old.DomainKey,
|
2024-01-01 13:47:13 +00:00
|
|
|
NotAfter: time.Now().Add(time.Hour * 24 * 60),
|
|
|
|
PrivateKeyEncoded: base64.StdEncoding.EncodeToString(new.PrivateKey),
|
|
|
|
Certificate: new.Certificate,
|
|
|
|
CSR: new.CSR,
|
|
|
|
}
|
|
|
|
return wrapper, nil
|
|
|
|
}
|
|
|
|
|
2024-01-02 17:23:46 +00:00
|
|
|
func ObtainNewCertificate(domains []string, domainKey string, acmeClient *lego.Client) (CertificateWrapper, error) {
|
2024-01-01 13:19:19 +00:00
|
|
|
req := certificate.ObtainRequest{
|
|
|
|
Domains: domains,
|
|
|
|
Bundle: true,
|
|
|
|
}
|
|
|
|
cert, err := acmeClient.Certificate.Obtain(req)
|
|
|
|
if err != nil {
|
|
|
|
return CertificateWrapper{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
tlsCert, err := tls.X509KeyPair(cert.Certificate, cert.PrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return CertificateWrapper{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
wrapper := CertificateWrapper{
|
|
|
|
TlsCertificate: &tlsCert,
|
2024-01-02 17:23:46 +00:00
|
|
|
DomainKey: domainKey,
|
2024-01-01 13:47:13 +00:00
|
|
|
//NotAfter: tlsCert.Leaf.NotAfter,
|
2024-01-01 13:19:19 +00:00
|
|
|
NotAfter: time.Now().Add(time.Hour * 24 * 60),
|
|
|
|
PrivateKeyEncoded: base64.StdEncoding.EncodeToString(cert.PrivateKey),
|
|
|
|
Certificate: cert.Certificate,
|
2024-01-01 13:47:13 +00:00
|
|
|
CSR: cert.CSR,
|
2024-01-01 13:19:19 +00:00
|
|
|
}
|
|
|
|
return wrapper, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a fallback certificate for the domain.
|
|
|
|
func MakeFallbackCertificate(pagesDomain string) (*CertificateWrapper, error) {
|
|
|
|
key, err := certcrypto.GeneratePrivateKey(certcrypto.RSA2048)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
notAfter := time.Now().Add(time.Hour * 24 * 7)
|
|
|
|
cert := x509.Certificate{
|
|
|
|
SerialNumber: big.NewInt(1),
|
|
|
|
Subject: pkix.Name{
|
|
|
|
CommonName: pagesDomain,
|
|
|
|
Organization: []string{"Pages Server"},
|
|
|
|
},
|
|
|
|
NotAfter: notAfter,
|
|
|
|
NotBefore: time.Now(),
|
|
|
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
|
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
|
|
BasicConstraintsValid: true,
|
|
|
|
}
|
|
|
|
certBytes, err := x509.CreateCertificate(
|
|
|
|
rand.Reader,
|
|
|
|
&cert,
|
|
|
|
&cert,
|
|
|
|
&key.(*rsa.PrivateKey).PublicKey,
|
|
|
|
key,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out := &bytes.Buffer{}
|
|
|
|
err = pem.Encode(out, &pem.Block{
|
|
|
|
Bytes: certBytes,
|
|
|
|
Type: "CERTIFICATE",
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
outBytes := out.Bytes()
|
|
|
|
res := &certificate.Resource{
|
|
|
|
PrivateKey: certcrypto.PEMEncode(key),
|
|
|
|
Certificate: outBytes,
|
|
|
|
IssuerCertificate: outBytes,
|
|
|
|
Domain: pagesDomain,
|
|
|
|
}
|
|
|
|
tlsCertificate, err := tls.X509KeyPair(res.Certificate, res.PrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &CertificateWrapper{
|
|
|
|
TlsCertificate: &tlsCertificate,
|
2024-01-02 17:23:46 +00:00
|
|
|
DomainKey: "*." + pagesDomain,
|
2024-01-01 13:19:19 +00:00
|
|
|
NotAfter: notAfter,
|
|
|
|
PrivateKeyEncoded: base64.StdEncoding.EncodeToString(certcrypto.PEMEncode(key)),
|
|
|
|
Certificate: outBytes,
|
2024-01-01 13:47:13 +00:00
|
|
|
CSR: []byte{},
|
2024-01-01 13:19:19 +00:00
|
|
|
}, nil
|
|
|
|
}
|