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 }