Documentation
¶
Overview ¶
Package certutil provides utilities to work with certificates.
A Bundler builds and verifies certificate chains. It trusts only the roots it is given, plus the platform trust store when WithSystemRoots(true) is set; without trust roots it defaults to Force, which checks signatures only. AIA downloads (WithAIA) are bounded by the WithHTTPClient timeout and the context given to BundleContext. One Bundler can be shared by goroutines; intermediates it learns over AIA are reused by later calls:
b, err := certutil.NewBundler(nil, intermediates,
certutil.WithSystemRoots(true),
certutil.WithAIA(true),
)
if err != nil {
return err
}
chain, err := b.BundleContext(ctx, []*x509.Certificate{leaf}, nil)
Index ¶
- Constants
- Variables
- func BuildBundle(c *Chain) (bundle *Bundle, status *BundleStatus, err error)
- func CreateOCSPRequest(crt, issuer *x509.Certificate, hash crypto.Hash) ([]byte, error)
- func CreatePoolFromPEM(pemBytes []byte) (*x509.CertPool, error)
- func Digest(hash crypto.Hash, data []byte) []byte
- func EncodePrivateKeyToPEM(priv crypto.PrivateKey) (key []byte, err error)
- func EncodePublicKeyToPEM(pubKey crypto.PublicKey) ([]byte, error)
- func EncodeToPEM(out io.Writer, withComments bool, certs ...*x509.Certificate) error
- func EncodeToPEMString(withComments bool, certs ...*x509.Certificate) (string, error)
- func ExpiryTime(chain []*x509.Certificate) (notAfter time.Time)
- func FindExtension(list []pkix.Extension, oid asn1.ObjectIdentifier) *pkix.Extension
- func FindExtensionValue(list []pkix.Extension, oid asn1.ObjectIdentifier) []byte
- func FindIssuer(crt *x509.Certificate, chain []*x509.Certificate, root *x509.Certificate) *x509.Certificate
- func GetAuthorityKeyID(c *x509.Certificate) string
- func GetIssuerID(c *x509.Certificate) string
- func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error)
- func GetSubjectID(c *x509.Certificate) string
- func GetSubjectKeyID(c *x509.Certificate) string
- func GetThumbprintStr(c *x509.Certificate) string
- func HasOCSPNoCheck(crt *x509.Certificate) bool
- func HashAlgoToStr(hash crypto.Hash) string
- func HashToBase64URL(hash crypto.Hash, data []byte) string
- func HashToHex(hash crypto.Hash, data []byte) string
- func IsOCSPSigner(crt *x509.Certificate) bool
- func JoinPEM(p1, p2 []byte) []byte
- func LoadAndVerifyBundleFromPEM(certFile, intCAFile, rootFile string, opt ...Option) (*Bundle, *BundleStatus, error)
- func LoadChainFromPEM(certFile string) ([]*x509.Certificate, error)
- func LoadFromPEM(certFile string) (*x509.Certificate, error)
- func LoadPEMFiles(files ...string) ([]byte, error)
- func NameToString(name *pkix.Name) string
- func NewHash(algo string) (hash.Hash, error)
- func ParseChainFromPEM(certificateChainPem []byte) ([]*x509.Certificate, error)
- func ParseFromPEM(bytes []byte) (*x509.Certificate, error)
- func ParseHexDigestWithPrefix(digest string) (hash.Hash, []byte, error)
- func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error)
- func ParsePrivateKeyPEM(keyPEM []byte) (key crypto.Signer, err error)
- func ParsePrivateKeyPEMWithPassword(keyPEM []byte, password []byte) (key crypto.Signer, err error)
- func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)
- func Random(byteLength int) []byte
- func RandomString(length int) string
- func SHA1(data []byte) []byte
- func SHA1Base64(data []byte) string
- func SHA1Hex(data []byte) string
- func SHA256(data []byte) []byte
- func SHA256Base64(data []byte) string
- func SHA256Hex(data []byte) string
- func StrToHashAlgo(algo string) crypto.Hash
- func VerifyBundleFromPEM(certPEM, intCAPEM, rootPEM []byte, opt ...Option) (bundle *Bundle, status *BundleStatus, err error)
- type Bundle
- type BundleFlavor
- type BundleStatus
- type Bundler
- func (b *Bundler) Bundle(certs []*x509.Certificate, key crypto.Signer) (*Chain, error)
- func (b *Bundler) BundleContext(ctx context.Context, certs []*x509.Certificate, key crypto.Signer) (*Chain, error)
- func (b *Bundler) ChainFromFile(bundleFile, keyFile string, password string) (*Chain, error)
- func (b *Bundler) ChainFromPEM(certsRaw, keyPEM []byte, password string) (*Chain, error)
- func (b *Bundler) ChainFromPEMContext(ctx context.Context, certsRaw, keyPEM []byte, password string) (*Chain, error)
- func (b *Bundler) VerifyOptions() x509.VerifyOptions
- type Chain
- type KeyInfo
- type Option
Constants ¶
const ( BundleExpiringBit int = 1 << iota // 0x01 BundleNotUbiquitousBit // 0x02 )
Warning code for a success
Variables ¶
var ErrNoCertificates = errors.New("no certificates")
ErrNoCertificates is returned, wrapped, when a Bundler or BuildBundle is given no certificate to bundle.
var HTTPClient = http.DefaultClient
HTTPClient is not read by this package.
Deprecated: AIA downloads use the client passed to WithHTTPClient, or a client with a 3s timeout when none is given; setting this variable has no effect (XPKI-044).
var IntermediateStash string
IntermediateStash contains the path to the directory where downloaded intermediates should be saved. When unspecified, downloaded intermediates are not saved.
var RandReader randSource = rand.Reader
RandReader is used so that it can be replaced in tests that require deterministic output
Functions ¶
func BuildBundle ¶ added in v0.3.0
func BuildBundle(c *Chain) (bundle *Bundle, status *BundleStatus, err error)
BuildBundle returns the Bundle and BundleStatus of a Chain built by a Bundler. A nil c or c.Cert returns an error; a nil c.Status is treated as an empty status, and a nil c.Root (a Force chain) leaves RootCert and RootCertPEM empty (XPKI-042).
func CreateOCSPRequest ¶ added in v0.3.0
CreateOCSPRequest returns the DER encoded OCSP request for crt issued by issuer, hashing the issuer key with hash. A nil crt or issuer or an unavailable hash returns an error before any work (XPKI-103), and so does an issuer whose subject is not crt's issuer name or whose key did not sign crt (XPKI-121). The signature check accepts SHA-1 and applies no CA policy.
func CreatePoolFromPEM ¶
CreatePoolFromPEM returns CertPool from PEM encoded certs
func EncodePrivateKeyToPEM ¶
func EncodePrivateKeyToPEM(priv crypto.PrivateKey) (key []byte, err error)
EncodePrivateKeyToPEM returns PEM encoded private key
func EncodePublicKeyToPEM ¶
EncodePublicKeyToPEM returns PEM encoded public key
func EncodeToPEM ¶
EncodeToPEM converts certificates to PEM format, with optional comments
func EncodeToPEMString ¶
func EncodeToPEMString(withComments bool, certs ...*x509.Certificate) (string, error)
EncodeToPEMString converts certificates to PEM format, with optional comments
func ExpiryTime ¶ added in v0.2.0
func ExpiryTime(chain []*x509.Certificate) (notAfter time.Time)
ExpiryTime returns the time when the certificate chain is expired.
func FindExtension ¶ added in v0.2.0
FindExtension returns extension, or nil
func FindExtensionValue ¶ added in v0.2.0
func FindExtensionValue(list []pkix.Extension, oid asn1.ObjectIdentifier) []byte
FindExtensionValue returns extension value, or nil
func FindIssuer ¶
func FindIssuer(crt *x509.Certificate, chain []*x509.Certificate, root *x509.Certificate) *x509.Certificate
FindIssuer returns an issuer cert
func GetAuthorityKeyID ¶
func GetAuthorityKeyID(c *x509.Certificate) string
GetAuthorityKeyID returns Authority Key Identifier
func GetIssuerID ¶
func GetIssuerID(c *x509.Certificate) string
GetIssuerID returns ID of the issuer. If present, it uses Authority Key Identifier, otherwise SHA1 of the Issuer name
func GetKeyDERFromPEM ¶ added in v0.2.0
GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes, decrypting it with password when it is encrypted. Encrypted PKCS#8 keys are supported only with PBES2, PBKDF2 (HMAC-SHA1, -SHA224, -SHA256, -SHA384 or -SHA512, at most 10,000,000 iterations) and AES-128/192/256-CBC, which OpenSSL 3 writes by default. Other PKCS#8 schemes (PBES1, PKCS#12 PBE, scrypt, DES) return an "unsupported PKCS#8 encryption" error (XPKI-043). The decrypted bytes are returned only when they are a PKCS#8 PrivateKeyInfo; otherwise, as for bad padding, the error matches x509.IncorrectPasswordError (XPKI-115).
func GetSubjectID ¶
func GetSubjectID(c *x509.Certificate) string
GetSubjectID returns ID of the cert. If present, it uses Subject Key Identifier, otherwise SHA1 of the Subject name
func GetSubjectKeyID ¶
func GetSubjectKeyID(c *x509.Certificate) string
GetSubjectKeyID returns Subject Key Identifier
func GetThumbprintStr ¶
func GetThumbprintStr(c *x509.Certificate) string
GetThumbprintStr returns hex-encoded SHA1 of the certificate
func HasOCSPNoCheck ¶ added in v0.3.0
func HasOCSPNoCheck(crt *x509.Certificate) bool
HasOCSPNoCheck returns true if certificate has ocsp-no-check. Both Extensions (populated on a parsed certificate) and ExtraExtensions (populated on a template before signing) are inspected.
func HashAlgoToStr ¶
HashAlgoToStr converts hash algorithm to string
func HashToBase64URL ¶
HashToBase64URL returns Base64URL encoded digest
func IsOCSPSigner ¶ added in v0.3.0
func IsOCSPSigner(crt *x509.Certificate) bool
IsOCSPSigner returns true for OCSP key usage
func LoadAndVerifyBundleFromPEM ¶
func LoadAndVerifyBundleFromPEM(certFile, intCAFile, rootFile string, opt ...Option) (*Bundle, *BundleStatus, error)
LoadAndVerifyBundleFromPEM constructs and verifies the cert chain
func LoadChainFromPEM ¶
func LoadChainFromPEM(certFile string) ([]*x509.Certificate, error)
LoadChainFromPEM returns Certificates loaded from the file
func LoadFromPEM ¶
func LoadFromPEM(certFile string) (*x509.Certificate, error)
LoadFromPEM returns Certificate loaded from the file
func LoadPEMFiles ¶
LoadPEMFiles loads and concatenates PEM files into one slice
func NameToString ¶
NameToString converts Name to string, compatible with openssl output
func ParseChainFromPEM ¶
func ParseChainFromPEM(certificateChainPem []byte) ([]*x509.Certificate, error)
ParseChainFromPEM returns Certificates parsed from PEM
func ParseFromPEM ¶
func ParseFromPEM(bytes []byte) (*x509.Certificate, error)
ParseFromPEM returns Certificate parsed from PEM
func ParseHexDigestWithPrefix ¶
ParseHexDigestWithPrefix parses encoded digest in {alg}:{hex} format
func ParsePrivateKeyDER ¶ added in v0.2.0
ParsePrivateKeyDER parses a PKCS #1, PKCS #8, ECDSA, or Ed25519 DER-encoded private key. The key must not be in PEM format.
func ParsePrivateKeyPEM ¶ added in v0.2.0
ParsePrivateKeyPEM parses and returns a PEM-encoded private key. The private key may be either an unencrypted PKCS#8, PKCS#1, or elliptic private key.
func ParsePrivateKeyPEMWithPassword ¶ added in v0.2.0
ParsePrivateKeyPEMWithPassword parses and returns a PEM-encoded private key. The private key may be an unencrypted PKCS#8, PKCS#1, or SEC1 key, a legacy PEM block encrypted per RFC 1423 (Proc-Type: 4,ENCRYPTED), or an encrypted PKCS#8 key (ENCRYPTED PRIVATE KEY) as described by GetKeyDERFromPEM. The key may be RSA, ECDSA, or Ed25519 (PKCS#8 only). A nil password fails for an encrypted key; a wrong password returns an error that matches x509.IncorrectPasswordError.
func ParseRSAPublicKeyFromPEM ¶
ParseRSAPublicKeyFromPEM parses PEM encoded RSA public key
func RandomString ¶
RandomString returns a random string of the given length over [0-9A-Za-z]. It panics if the random source fails.
func SHA256Base64 ¶
SHA256Base64 returns Base64URL encoded SHA256
func StrToHashAlgo ¶
StrToHashAlgo converts string to hash algorithm
func VerifyBundleFromPEM ¶
func VerifyBundleFromPEM(certPEM, intCAPEM, rootPEM []byte, opt ...Option) (bundle *Bundle, status *BundleStatus, err error)
VerifyBundleFromPEM constructs and verifies the cert chain
Types ¶
type Bundle ¶
type Bundle struct {
// Chain does not include the root anchor
Chain []*x509.Certificate
Cert *x509.Certificate
IssuerCert *x509.Certificate
RootCert *x509.Certificate
Issuer *pkix.Name
Subject *pkix.Name
IssuerID string
SubjectID string
Expires time.Time
Hostnames []string
CertPEM string
CACertsPEM string
RootCertPEM string
}
A Bundle contains a certificate and its trust chain. It is intended to store the most widely applicable chain, with shortness an explicit goal.
func SortBundlesByExpiration ¶
SortBundlesByExpiration returns a new slice of bundles sorted by Expires in descending order. The sort is stable, so bundles with the same Expires keep their input order, and nil bundles go last. The caller's slice is not reordered; the bundles themselves are shared (XPKI-038).
func (*Bundle) ExpiresInHours ¶
ExpiresInHours returns the time until Expires truncated toward zero to whole hours: 90 minutes is 1h, and an expiry 90 minutes ago is -1h (XPKI-045).
type BundleFlavor ¶ added in v0.2.0
type BundleFlavor string
BundleFlavor is named optimization strategy on certificate chain selection when bundling.
const ( // Optimal means the shortest chain with newest intermediates and // the most advanced crypto. Optimal BundleFlavor = "optimal" // Force means the bundler only verifies the input as a valid bundle, not optimization is done. Force BundleFlavor = "force" )
type BundleStatus ¶
type BundleStatus struct {
// A list of SKIs of expiring certificates
ExpiringSKIs []string `json:"expiring_SKIs"`
// A list of untrusted root store names
Untrusted []string `json:"untrusted_root_stores"`
// A list of human readable warning messages based on the bundle status.
Messages []string `json:"messages"`
Code int `json:"code"`
}
BundleStatus is designated for various status reporting.
func (*BundleStatus) IsExpiring ¶
func (b *BundleStatus) IsExpiring() bool
IsExpiring returns true if bundle is expiring in less than 30 days
func (*BundleStatus) IsUntrusted ¶
func (b *BundleStatus) IsUntrusted() bool
IsUntrusted returns true if the cert's issuers are not trusted
type Bundler ¶ added in v0.2.0
type Bundler struct {
RootPool *x509.CertPool
IntermediatePool *x509.CertPool
KnownIssuers map[string]bool
// contains filtered or unexported fields
}
A Bundler contains the certificate pools for producing certificate bundles. It contains any intermediates and root certificates that should be used.
A Bundler is safe for concurrent use. Intermediates learned over AIA are shared by later calls: they are published by replacing IntermediatePool and KnownIssuers with updated copies, so a pool or map once read is never modified (XPKI-035).
The exported fields are set-up state. Set or replace them only before the first Bundle, ChainFromPEM or VerifyOptions call, and do not modify the pools or the map in place. After that, read the pools through VerifyOptions; reading the fields directly races with learning.
func LoadBundler ¶ added in v0.3.0
LoadBundler creates a new Bundler from the files passed in; these files should contain a list of valid root certificates and a list of valid intermediate certificates, respectively.
func NewBundler ¶ added in v0.2.0
func NewBundler(roots, intermediates []*x509.Certificate, opt ...Option) (*Bundler, error)
NewBundler returns a Bundler that trusts roots, plus the system roots with WithSystemRoots, and uses intermediates to build chains. The flavor defaults to Optimal with trust roots and to Force without them; Optimal without trust roots is an error, so a Bundler never trusts system roots implicitly. RootPool is nil only when there are no trust roots.
func NewBundlerFromPEM ¶ added in v0.2.0
NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and intermediate certificates. Without root certificates the default flavor is Force; see NewBundler.
func (*Bundler) Bundle ¶ added in v0.2.0
Bundle takes an X509 certificate (already in the Certificate structure), a private key as crypto.Signer in one of the appropriate formats (i.e. *rsa.PrivateKey or *ecdsa.PrivateKey, or even a opaque key), using them to build a certificate bundle. certs[0] is the leaf (a reversed chain is detected). A nil or empty certs returns an error matching ErrNoCertificates, and a nil entry returns an error (XPKI-036).
func (*Bundler) BundleContext ¶ added in v0.29.306
func (b *Bundler) BundleContext(ctx context.Context, certs []*x509.Certificate, key crypto.Signer) (*Chain, error)
BundleContext is Bundle with a context that bounds and cancels AIA downloads. When ctx is done during an AIA download, the returned error matches ctx.Err() with errors.Is. An Optimal Bundler whose RootPool is nil fails instead of verifying against the system roots.
func (*Bundler) ChainFromFile ¶ added in v0.3.0
ChainFromFile takes a set of files containing the PEM-encoded leaf certificate (optionally along with some intermediate certs), the PEM-encoded private key and returns the bundle built from that key and the certificate(s).
func (*Bundler) ChainFromPEM ¶ added in v0.3.0
ChainFromPEM builds a certificate chain from the set of byte slices containing the PEM or DER-encoded certificate(s), private key.
func (*Bundler) ChainFromPEMContext ¶ added in v0.29.306
func (b *Bundler) ChainFromPEMContext(ctx context.Context, certsRaw, keyPEM []byte, password string) (*Chain, error)
ChainFromPEMContext is ChainFromPEM with a context that bounds and cancels AIA downloads; see BundleContext.
func (*Bundler) VerifyOptions ¶ added in v0.2.0
func (b *Bundler) VerifyOptions() x509.VerifyOptions
VerifyOptions returns the x509.VerifyOptions used by Optimal bundling. Roots is never nil: without a RootPool it is an empty pool, so the options never fall back to the system roots. It is a snapshot: intermediates learned later are not added to it.
type Chain ¶ added in v0.2.0
type Chain struct {
Chain []*x509.Certificate
Cert *x509.Certificate
Root *x509.Certificate
Key any
Issuer *pkix.Name
Subject *pkix.Name
Expires time.Time
LeafExpires time.Time
Hostnames []string
Status *BundleStatus
}
Chain contains a certificate and its trust chain. It is intended to store the most widely applicable chain, with shortness an explicit goal.
type Option ¶ added in v0.2.0
type Option func(*options)
An Option sets options such as allowed key usages, etc.
func WithBundleFlavor ¶ added in v0.3.0
func WithBundleFlavor(flavor BundleFlavor) Option
WithBundleFlavor selects Optimal or Force chain building. Without this option the flavor is Optimal when the Bundler has trust roots (explicit roots or WithSystemRoots) and Force otherwise. NewBundler rejects Optimal without trust roots and any other flavor value; the last option wins.
func WithHTTPClient ¶ added in v0.3.0
WithHTTPClient sets the client for AIA downloads. Each request is bounded by the client's Timeout, or 3s when it is zero, and by the context given to BundleContext. Only a 200 response of at most 1 MiB is parsed. Without this option a client with a 3s timeout is used.
func WithKeyUsages ¶ added in v0.2.0
func WithKeyUsages(usages ...x509.ExtKeyUsage) Option
WithKeyUsages lets you set which Extended Key Usage values are acceptable. By default x509.ExtKeyUsageAny will be used.
func WithSystemRoots ¶ added in v0.29.306
WithSystemRoots adds the platform trust store (x509.SystemCertPool) to the explicit roots. It is the only way a Bundler trusts system roots: without it, Optimal verification uses the explicit roots alone (XPKI-041).