package ssl import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "io" "os" ) func GetCertificate(key *rsa.PrivateKey, root *x509.Certificate) (*x509.Certificate, []byte, error) { if cert, certPEM, err := pullCertificateFromFS(); err == nil { return cert, certPEM, nil } cert, certPEM, err := generateNewCertificate(root, key) if err != nil { Clear() return nil, nil, err } if err = saveCertificateToFS(certPEM); err != nil { Clear() return nil, nil, err } return cert, certPEM, nil } func generateNewCertificate(root *x509.Certificate, key *rsa.PrivateKey) (*x509.Certificate, []byte, error) { certDER, err := x509.CreateCertificate(rand.Reader, root, root, &key.PublicKey, key) if err != nil { return nil, nil, err } cert, err := x509.ParseCertificate(certDER) if err != nil { return nil, nil, err } return cert, pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: certDER, }), nil } func pullCertificateFromFS() (*x509.Certificate, []byte, error) { file, err := os.OpenFile(certPEMPath(), os.O_RDONLY, os.ModePerm) if err != nil { return nil, nil, err } defer file.Close() certPEM, err := io.ReadAll(file) if err != nil { return nil, nil, err } block, _ := pem.Decode(certPEM) cert, err := x509.ParseCertificate(block.Bytes) if err != nil { return nil, nil, err } return cert, certPEM, nil } func saveCertificateToFS(certPEM []byte) error { file, err := os.OpenFile(certPEMPath(), os.O_WRONLY|os.O_CREATE, 0600) if err != nil { return err } _, err = file.Write(certPEM) file.Close() return err } func clearCert() { os.Remove(certPEMPath()) }