113 lines
3.0 KiB
Go
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"`
|
|
}
|