From c82444eda205c788bce6da7a2dbffbaec3740cc0 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 29 Jun 2025 19:36:09 +0800 Subject: [PATCH] feat: add go ca --- go-ca/go.mod | 3 +++ go-ca/main.go | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 go-ca/go.mod create mode 100644 go-ca/main.go diff --git a/go-ca/go.mod b/go-ca/go.mod new file mode 100644 index 0000000..2d14df8 --- /dev/null +++ b/go-ca/go.mod @@ -0,0 +1,3 @@ +module git.hatter.ink/golang-tests/go-ca + +go 1.24.3 diff --git a/go-ca/main.go b/go-ca/main.go new file mode 100644 index 0000000..bbd5090 --- /dev/null +++ b/go-ca/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha1" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math" + "math/big" + "time" +) + +func main() { + err := innerMain() + if err == nil { + println("Success") + } else { + println("Error: ", err.Error()) + } +} + +func innerMain() error { + rootKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + if err != nil { + return err + } + rootCert, err := issueRootCertificate(&rootKey.PublicKey, rootKey) + if err != nil { + return err + } + println(string(pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: rootCert, + }))) + return nil +} + +func issueRootCertificate(pubKey, parentPrivKey any) ([]byte, error) { + now := time.Now() + template := x509.Certificate{ + SerialNumber: generateSerialNumber(), + Subject: pkix.Name{ + CommonName: "Root CA", + }, + NotBefore: now.UTC(), + NotAfter: now.AddDate(100, 0, 0).UTC(), + BasicConstraintsValid: true, + IsCA: true, + MaxPathLen: 10, + // MaxPathLenZero: true, + SubjectKeyId: getKeyId(pubKey), + KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, + } + parentCert := &template + return x509.CreateCertificate(rand.Reader, &template, parentCert, pubKey, parentPrivKey) +} + +func getKeyId(pubKey any) []byte { + pubKeyBytes, err := x509.MarshalPKIXPublicKey(pubKey) + if err != nil { + panic("Should not happen") + } + return sha1.New().Sum(pubKeyBytes) +} + +func generateSerialNumber() *big.Int { + randInt, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)) + if err != nil { + panic("Should not happen") + } + return randInt +}