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" ) 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, DomainKey: old.DomainKey, NotAfter: time.Now().Add(time.Hour * 24 * 60), PrivateKeyEncoded: base64.StdEncoding.EncodeToString(new.PrivateKey), Certificate: new.Certificate, CSR: new.CSR, } return wrapper, nil } func ObtainNewCertificate(domains []string, domainKey string, acmeClient *lego.Client) (CertificateWrapper, error) { 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, DomainKey: domainKey, //NotAfter: tlsCert.Leaf.NotAfter, NotAfter: time.Now().Add(time.Hour * 24 * 60), PrivateKeyEncoded: base64.StdEncoding.EncodeToString(cert.PrivateKey), Certificate: cert.Certificate, CSR: cert.CSR, } 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, DomainKey: "*." + pagesDomain, NotAfter: notAfter, PrivateKeyEncoded: base64.StdEncoding.EncodeToString(certcrypto.PEMEncode(key)), Certificate: outBytes, CSR: []byte{}, }, nil }