go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/certutil/create_certificate_authority.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package certutil
     9  
    10  import (
    11  	"crypto/rand"
    12  	"crypto/sha1"
    13  	"crypto/x509"
    14  	"crypto/x509/pkix"
    15  	"encoding/asn1"
    16  	"fmt"
    17  
    18  	"go.charczuk.com/sdk/errutil"
    19  )
    20  
    21  // CreateCertificateAuthority creates a ca cert bundle from a given set of options.
    22  // The cert bundle can be used to generate client and server certificates.
    23  func CreateCertificateAuthority(options ...CertOption) (*CertBundle, error) {
    24  	createOptions := DefaultOptionsCertificateAuthority
    25  
    26  	if err := ResolveCertOptions(&createOptions, options...); err != nil {
    27  		return nil, err
    28  	}
    29  	if createOptions.PrivateKey == nil {
    30  		return nil, fmt.Errorf("create certificate authority; private key is unset")
    31  	}
    32  	var output CertBundle
    33  	output.PrivateKey = createOptions.PrivateKey
    34  	output.PublicKey = &createOptions.PrivateKey.PublicKey
    35  
    36  	var spki struct {
    37  		Algorithm        pkix.AlgorithmIdentifier
    38  		SubjectPublicKey asn1.BitString
    39  	}
    40  
    41  	spkiASN1, err := x509.MarshalPKIXPublicKey(output.PublicKey)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	_, err = asn1.Unmarshal(spkiASN1, &spki)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	skid := sha1.Sum(spki.SubjectPublicKey.Bytes)
    52  
    53  	createOptions.SubjectKeyId = skid[:]
    54  	createOptions.BasicConstraintsValid = true
    55  	createOptions.IsCA = true
    56  	createOptions.MaxPathLenZero = true
    57  
    58  	der, err := x509.CreateCertificate(rand.Reader, &createOptions.Certificate, &createOptions.Certificate, output.PublicKey, output.PrivateKey)
    59  	if err != nil {
    60  		return nil, errutil.New(err)
    61  	}
    62  	cert, err := x509.ParseCertificate(der)
    63  	if err != nil {
    64  		return nil, errutil.New(err)
    65  	}
    66  	output.CertificateDERs = [][]byte{der}
    67  	output.Certificates = []x509.Certificate{*cert}
    68  	return &output, nil
    69  }