pki/src/pkiws/serverhandle.go
Paul Lecuq af826ff457
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
reworked cert issuing
2024-04-20 17:02:25 +02:00

113 lines
3.0 KiB
Go

package pkiws
import (
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"regexp"
"time"
"git.paulbsd.com/paulbsd/pki/src/cert"
"git.paulbsd.com/paulbsd/pki/src/config"
"git.paulbsd.com/paulbsd/pki/src/pki"
)
const timeformatstring string = "2006-01-02 15:04:05"
var domainRegex, err = regexp.Compile(`^[a-z0-9\*]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$`)
// GetCertificate get certificate from database if exists, of request it from ACME
func GetCertificate(cfg *config.Config, user *pki.User, domains *[]string) (result map[string]EntryResponse, err error) {
err = CheckDomains(domains)
if err != nil {
return result, err
}
result = make(map[string]EntryResponse)
firstdomain := (*domains)[0]
entry, err := user.GetEntry(cfg, &firstdomain)
if err != nil {
certs, err := user.RequestNewCert(cfg, domains)
if err != nil {
log.Printf("Error fetching new certificate %s\n", err)
return result, err
}
NotBefore, NotAfter, err := GetDates(certs.Certificate)
if err != nil {
log.Println("Error where parsing dates")
return result, err
}
entry := cert.Entry{Domain: certs.Domain,
Certificate: string(certs.Certificate),
PrivateKey: string(certs.PrivateKey),
ValidityBegin: NotBefore,
ValidityEnd: NotAfter,
AuthURL: cfg.ACME.AuthURL}
cfg.Db.Insert(&entry)
result[firstdomain] = convertEntryToResponse(entry)
return result, err
}
result[firstdomain] = convertEntryToResponse(entry)
return
}
// CheckDomains check if requested domains are valid
func CheckDomains(domains *[]string) (err error) {
for _, domain := range *domains {
err = CheckDomain(&domain)
if err != nil {
return
}
}
return
}
// CheckDomain check if requested domain are valid
func CheckDomain(domain *string) (err error) {
res := domainRegex.Match([]byte(*domain))
if !res {
return fmt.Errorf("Domain %s has not a valid syntax %s, please verify", *domain, err)
}
return
}
// GetDates decodes NotBefore and NotAfter date of cert
func GetDates(cert []byte) (NotBefore time.Time, NotAfter time.Time, err error) {
block, _ := pem.Decode(cert)
if block.Type == "CERTIFICATE" {
ce, err := x509.ParseCertificate(block.Bytes)
if err != nil {
log.Println("Error when parsing certificate")
}
NotBefore = ce.NotBefore
NotAfter = ce.NotAfter
}
return
}
// convertEntryToResponse converts database ACME entry to JSON ACME entry
func convertEntryToResponse(in cert.Entry) (out EntryResponse) {
out.Domains = append(out.Domains, in.Domain)
out.Certificate = in.Certificate
out.PrivateKey = in.PrivateKey
out.ValidityBegin = in.ValidityBegin.Format(timeformatstring)
out.ValidityEnd = in.ValidityEnd.Format(timeformatstring)
return
}
// EntryRequest
type EntryRequest struct {
Domains []string `json:"domains"`
}
// EntryResponse is the struct defining JSON response from webservice
type EntryResponse struct {
Domains []string `json:"domains"`
Certificate string `json:"certificate"`
PrivateKey string `json:"privatekey"`
ValidityBegin string `json:"validitybegin"`
ValidityEnd string `json:"validityend"`
}