crtman/internal/crt/issue.go
2025-10-12 20:01:19 +08:00

92 lines
2.6 KiB
Go

package crt
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"database/sql"
"fmt"
"log"
"math/big"
"time"
"github.com/jasinco/crtman/internal/cli"
"github.com/jasinco/crtman/internal/store"
)
func IssueRoot(config cli.CA_CFG) {
log.Printf("CA: Org: %s, FQDN: %s\n", config.Org, config.FQDN)
rootca := x509.Certificate{
IsCA: true,
Version: 1,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageOCSPSigning},
Subject: pkix.Name{
Country: []string{"Taiwan"},
Organization: []string{config.Org},
CommonName: config.FQDN,
},
NotBefore: time.Now(),
BasicConstraintsValid: true,
SerialNumber: big.NewInt(0),
}
privkey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatal(err)
}
crt, err := x509.CreateCertificate(rand.Reader, &rootca, &rootca, &privkey.PublicKey, privkey)
if err != nil {
log.Fatal("can't create x509 ca, ", err)
}
// privkey_bytes, err := x509.MarshalECPrivateKey(privkey)
// if err != nil {
// log.Fatal("can't create ecdsa key encoded, ", err)
// }
store.RootCA = crt
store.RootCAKey = privkey
}
// csr is a DER csr
func IssueCert(csr []byte) sql.Null[[]byte] {
req, err := x509.ParseCertificateRequest(csr)
if err != nil {
return sql.Null[[]byte]{Valid: false}
}
if req.CheckSignature() != nil {
return sql.Null[[]byte]{Valid: false}
}
store.SerialLock.Lock()
defer store.SerialLock.Unlock()
cert := x509.Certificate{
Subject: req.Subject,
PublicKey: req.PublicKey,
PublicKeyAlgorithm: req.PublicKeyAlgorithm,
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour * 24 * 720),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
IsCA: false,
BasicConstraintsValid: true,
DNSNames: req.DNSNames,
IPAddresses: req.IPAddresses,
SerialNumber: &store.Serial,
OCSPServer: []string{fmt.Sprintf("https://%s/api/ocsp", cli.Outbound)},
}
ca, err := x509.ParseCertificate(store.RootCA)
if err != nil {
log.Println(err)
return sql.Null[[]byte]{Valid: false}
}
signed, err := x509.CreateCertificate(rand.Reader, &cert, ca, req.PublicKey, store.RootCAKey)
if err != nil {
log.Println(err)
return sql.Null[[]byte]{Valid: false}
}
store.Serial.Add(&store.Serial, big.NewInt(1))
return sql.Null[[]byte]{Valid: true, V: signed}
}