certs

package
v0.0.0-...-0569425 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2025 License: Apache-2.0 Imports: 32 Imported by: 4

Documentation

Overview

Package certs provides helpers around certificates.

Index

Constants

View Source
const (
	BlockTypeECPrivateKey    = "EC PRIVATE KEY"
	BlockTypeRSAPrivateKey   = "RSA PRIVATE KEY" // PKCS#1 private key
	BlockTypePKCS8PrivateKey = "PRIVATE KEY"     // PKCS#8 plain private key
	BlockTypeCertificate     = "CERTIFICATE"
)

Variables

View Source
var (
	MESH_NETWORK = []byte{0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0x00}
)

Functions

func GenerateKey

func GenerateKey(kty string) crypto.PrivateKey

func GetSAN

func GetSAN(c *x509.Certificate) ([]string, error)

func GetSANRequest

func GetSANRequest(req *http.Request) ([]string, error)

func IDFromCert

func IDFromCert(c []*x509.Certificate) string

func IDFromPublicKeyBytes

func IDFromPublicKeyBytes(m []byte) string

func MarshalPrivateKeyPEM

func MarshalPrivateKeyPEM(priv crypto.PrivateKey) []byte

MarshalPrivateKeyPEM returns the PEM encoding of the key

func MarshalPublicKey

func MarshalPublicKey(key crypto.PublicKey) []byte

Convert a PublicKey to a marshalled format - in the raw format. - 32 byte ED25519 - 65 bytes EC256 ( 0x04 prefix ) - DER RSA key (PKCS1)

Normally the key is available from request or response TLS.PeerCertificate[0]

func Pub2ID

func Pub2ID(pub []byte) uint64

Generate a 8-byte identifier from a public key

func Pub2VIP

func Pub2VIP(pub []byte) net.IP

Convert a public key to a VIP. This is the primary WorkloadID of the nodes. Primary format is the 64-byte EC256 public key.

For RSA, the ASN.1 format of the byte[] is used. For ED, the 32-byte raw encoding.

func PublicKey

func PublicKey(key crypto.PrivateKey) crypto.PublicKey

func PublicKeyBase32SHA

func PublicKeyBase32SHA(key crypto.PublicKey) string

PublicKeyBase32SHA returns a node WorkloadID based on the public key of the node - 52 bytes base32 for EC256 keys

func RawToCertChain

func RawToCertChain(rawCerts [][]byte) ([]*x509.Certificate, error)

func SPKIFingerprint

func SPKIFingerprint(key crypto.PublicKey) string

Return the SPKI fingerprint of the key https://www.rfc-editor.org/rfc/rfc7469#section-2.4

"An SPKI Fingerprint is defined as the output of a known cryptographic

hash algorithm whose input is the DER-encoded ASN.1 representation of
the Subject Public Key Info (SPKI) of an X.509 certificate"

"The SPKI Fingerprint is encoded in base 64 for use in an HTTP header

[RFC4648]"

Can be used with "ignore-certificate-errors-spki-list" in chrome, for cert pinning.

User-installed roots can bypass the pins.

openssl x509 -pubkey -noout -in <path to PEM cert> | openssl pkey -pubin -outform der \
  | openssl dgst -sha256 -binary | openssl base32Enc -base64

sha256/BASE64

func SignCertDER

func SignCertDER(template *x509.Certificate, pub crypto.PublicKey, caPrivate crypto.PrivateKey, parent *x509.Certificate) ([]byte, error)

SignCertDER uses caPrivate to sign a tlsCrt, returns the DER format. Used primarily for tests with self-signed tlsCrt.

func TLSA

func TLSA(key crypto.PublicKey) string

TLSA records have many types - this is for the Selector=1 (SubjectPublicKeyInfo == public key DER) matching=1 (SHA256 - same as in SPKI). CertUsage can be 0/2 (root certificate - must be in the chain, doesn't need basicConstraints), or 1/3 (Leaf/end certificate). Note that 0,1 require a trustChain root, while 2,3 don't.

Example: _443._tcp.www.example.com. IN TLSA (

2 1 1 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971)

DNS canonical representation is hex, but the record is binary.

func VerifyChain

func VerifyChain(chain []*x509.Certificate) (crypto.PublicKey, error)

VerifySelfSigned verifies the certificate chain and extract the remote's public key. The last element in the chain is expected to be the root - which should be checked against DANE or static config.

Types

type Cert

type Cert struct {
	// Cert is the loaded certificate.
	*tls.Certificate `json:"-"`

	// Org will be set in the CN field - should be the TrustDomain for mesh.
	Org string

	Name   string
	Domain string

	DNSSANs []string
	SPIFFE  string

	CA bool

	// If Base is set, cert will be loaded, and error generated if missing.
	// If not set and no other initialization is performed, a
	// self-signed certificate is generated.
	Base string `json:"base,omitempty"`

	// Certificates signing the private key.
	// First is the cert signing the public key, followed by any
	// certs signing previous certs. It is not required to include to
	// 'top level' root that signed the entire chain (which should be
	// in the trust roots).
	ChainPEM []byte `json:"chainPEM,omitempty"`
	KeyPEM   []byte `json:"keyPEM,omitempty"`
}

A Cert is a private key and an associated certificate chain.

The certificate chain includes X509 signatures on the public key and associated data, and is equivalent with a signed token.

A Cert can issue and verify tokens.

func NewCert

func NewCert() *Cert

func (*Cert) CertTemplate

func (ca *Cert) CertTemplate(org string, urlSAN string, sans ...string) *x509.Certificate

func (*Cert) GenerateTLSConfigServer

func (cert *Cert) GenerateTLSConfigServer(trust *MeshTrust) *tls.Config

GenerateTLSConfigServer is used to provide the server tls.Config for handshakes.

Will use the workload identity and do basic checks on client certs. It does not require client certs - but asks for them, and if found verifies.

If allowMeshExternal is set, will skip verification for certs with different trust domain.

The GetCertificate method can be replaced with one that handles multiple domains.

func (*Cert) InitSelfSignedKey

func (cert *Cert) InitSelfSignedKey(privk crypto.PrivateKey)

func (*Cert) InitSelfSignedPEMKey

func (cert *Cert) InitSelfSignedPEMKey(keyPEM string)

func (*Cert) Leaf

func (cert *Cert) Leaf() *x509.Certificate

Leaf returns the leaf certificate from the loaded cert, or a new template based on the Cert fields.

func (*Cert) PrivateKeyPEM

func (cert *Cert) PrivateKeyPEM() string

func (*Cert) Provision

func (cert *Cert) Provision(ctx context.Context) error

func (*Cert) PubB32

func (cert *Cert) PubB32() string

func (*Cert) PublicKey

func (cert *Cert) PublicKey() []byte

func (*Cert) PublicKeyPEM

func (cert *Cert) PublicKeyPEM() string

func (*Cert) Save

func (cert *Cert) Save(ctx context.Context, dir string) error

func (*Cert) SetCertPEM

func (cert *Cert) SetCertPEM(privatePEM string, chainPEMCat string) error

func (*Cert) SignCert

func (cert *Cert) SignCert(priv crypto.PrivateKey, ca crypto.PrivateKey, sans ...string) (tls.Certificate, []byte, []byte)

SignCert will create a tls.Certificate and the PEM encoding of the certificate, using the fields in Cert.

func (*Cert) SignCertDER

func (cert *Cert) SignCertDER(pub crypto.PublicKey, caPrivate crypto.PrivateKey, sans ...string) []byte

func (*Cert) Spiffee

func (cert *Cert) Spiffee() (*url.URL, string, string, string)

Extract the trustDomain, namespace and Name from a spiffee certificate

func (*Cert) TLSClient

func (cert *Cert) TLSClient(ctx context.Context, nc net.Conn,
	dest *Trust, mt *MeshTrust,
	remotePub32 string) (*tls.Conn, error)

GenerateTLSConfigDest returns a custom tls config for a Dest and a context holder. This should be used with a single

func (*Cert) TLSClientConf

func (cert *Cert) TLSClientConf(dest *Trust, sni string,
	remotePub32 string, rootT *MeshTrust) *tls.Config

TLSClientConf returns a TLS config using this certificate as client cert

sni can override the cluster sni remotePub32 is the cert-baseed identity of a specific endpoint.

On the returned config, you can override "NextProtos" (defaults

to h2), and ServerName (defaults to the dest FQDN)

type Certs

type Certs struct {
	// Local dir. If set, private key and certificates are saved there.
	// If not set, they will be loaded from SecretFS (keys), or auto-generated
	// ephemeral key are used.
	BaseDir string `json:"base,omitempty"`

	// Private key for the workload, used for signing.
	// The associated public key should be used to configure trust in this
	// workload and any identities it may use (impersonate) or delegate.
	Private crypto.PrivateKey `json:"-"`

	// CACert is a certificate associated with the private key, with the
	// CA bit set. Used to generate certificates signed by this workload.
	CACert *x509.Certificate `json:"-"`

	// FQDN is the FQDN of the workload.
	//
	// In Istio, the constant 'cluster.local' is
	// used for the mesh CA, which indicates a custom location is
	// used for the root key and use of SPIFFE certificates.
	//
	// Default to 'hostname' or env HOST and DOMAIN
	// The second component is treated as 'namespace'.
	FQDN string `json:"trustDomain,omitempty"`

	// The CA Certificate may be signed by multiple intermediaries
	// They need to be included in chains.
	// May include the top-level root - but this is not required.
	IntermediatesPEM []byte `json:"chainPEM,omitempty"`

	// For self-signed cert ('root'), this is the cert corresponding to
	// the private key. This needs to be added to the trust store.
	// This is NOT included in Intermediates - which are signatures by
	// other CAs that MUST be included in generated chains, so clients
	// can find a path to the other CAs.
	//
	// This is used if this CA is the top-level CA, signing other CAs - and
	// MUST be added to the trust store of each client.
	//
	// Since it is self-signed, the CA can re-generated this file.
	// For the chain, the signing CA (provider) must issue them again.
	CACertPEM []byte `json:"selfPEM,omitempty"`

	LoadTime time.Time `json:"-"`

	// Trust configures private CA roots as 'trusted'.
	// If no CA root is found, default is to trust the internal CA and
	// public roots.
	//
	// Each peer must have a valid certificate. If Trust is defined, the
	// cert must have a signature from one of the defined public keys.
	// This field includes CA-style keys, valid for all identities.
	Trust *MeshTrust `json:"trust"`

	// A filesystem interface for loading private keys. May also include
	// configs and certificates.
	SecretsFS fs.FS

	// A filesystem holding server certificates and configs. Loaded on-demand.
	// If a cert is not found - the internal CA will generate one.
	ConfigFS fs.FS

	// Cert is the workload certificate - should encode the primary FQDN of
	// the node.
	*Cert

	// Private key as a string (base64). EC256 is 33 bytes, ED25519 16 bytes,
	// and RSA encoded as PEM.
	PrivateString string `json:"key"`
}

Certs handles certificate and trust management, and is built around a primary private key.

It incorporates as private CA that can sign additional certs for subdomains, a filesystem for loading secrets, a filesystem for loading configs for client connections and an optional directory for local files and cache.

func NewCerts

func NewCerts() *Certs

func (*Certs) DialTLS

func (certs *Certs) DialTLS(nc net.Conn, addr string) (*tls.Conn, error)

WIP

func (*Certs) FromEnv

func (certs *Certs) FromEnv() error

func (*Certs) GetCertificate

func (certs *Certs) GetCertificate(ctx context.Context, sni string) (*tls.Certificate, error)

GetCertificate is typically called during handshake, both server and client. "sni" will be empty for client certificates, and set for server certificates - if not set, workload id is returned.

ctx is the handshake context - may include additional metadata about the operation.

func (*Certs) GetCerts

func (certs *Certs) GetCerts() map[string]*tls.Certificate

Get all known certificates from local files. This is used to support lego certificates and istio.

"istio" is a special name, set if istio certs are found

func (*Certs) Init

func (ca *Certs) Init(dir string) error

func (*Certs) InitSelfSigned

func (certs *Certs) InitSelfSigned(kty string, fqdn string) *Cert

func (*Certs) InitSelfSignedFromPEMKey

func (certs *Certs) InitSelfSignedFromPEMKey(keyPEM string, fqdn string) *Cert

InitSelfSignedFromPEMKey will use the private key (EC PEM) and generate a self signed certificate, using the config (name.domain)

func (*Certs) InitSelfSignedKeyRaw

func (certs *Certs) InitSelfSignedKeyRaw(privk crypto.PrivateKey, fqdn string) *Cert

func (*Certs) NewID

func (ca *Certs) NewID(ns, sa string, dns []string) *Cert

func (*Certs) NewIntermediaryCA

func (ca *Certs) NewIntermediaryCA(trust, cluster string) *Certs

NewIntermediaryCA creates a cert for an intermediary CA.

func (*Certs) NewTLSCert

func (ca *Certs) NewTLSCert(ns, sa string, dns []string) (*tls.Certificate, []byte, []byte)

NewTLSCert creates a new cert from this CA.

func (*Certs) Provision

func (certs *Certs) Provision(ctx context.Context) error

func (*Certs) Save

func (ca *Certs) Save(ctx context.Context, dir string) error

Save will save: - private key as tls.key (PEM) - CA certificate as ca.pem - certificate chain

func (*Certs) SetCert

func (ca *Certs) SetCert(privPEM, certPEM []byte) error

SetCert will init CA from PEM bytes. For example loading it from a K8S Secret or files.

func (*Certs) SignCertificate

func (c *Certs) SignCertificate(template *x509.Certificate, pub crypto.PublicKey) string

Signs and return a PEM-encoded certificate. The result includes the root CACertPEM files (intermediaries), but does not include the CA root or other trusted CAs.

type MeshTrust

type MeshTrust struct {

	// Used by mesh clients, for tickets.
	ClientSessionCache tls.ClientSessionCache `json:"-"`

	RootsPEM string `json:"roots,omitempty"`

	// This is the 'trust domain' for Istio-style certs, also
	// can be used with SERVICE.NAMESPACE.svc.DOMAIN or POD.NAMESPACE.DOMAIN
	//
	// If not set, '.local' and '.internal' are used.
	Domain []string `json:"domain"`

	// If set, limits the namespaces that are allowed to connect.
	// Same namespace and 'istio-system' are allowed by default.
	//
	// If set, no external certificates are allowed for clients.
	// Public certs for servers continue to be allowed (block internet
	// egress using network rules, not cert rules).
	AllowedNamespaces []string

	// AllowMeshExternal indicates that client certificates not signed by
	// a certPool certificare - but valid - will be allowed. The server
	// can inspect the cert chain in the connection and make
	// decisions based on the signers.
	AllowMeshExternal bool `json:"-"`
	// contains filtered or unexported fields
}

MeshTrust configures mesh-style trust, where all identities signed by a set of CAs are trusted.

Trust allow per-identity configuration, and is loaded on-demand from the config store (or DNS)

func NewMeshTrust

func NewMeshTrust() *MeshTrust

func (*MeshTrust) AddRootDER

func (mesh *MeshTrust) AddRootDER(root []byte) error

Add a list of certificates in DER format to the root. The top signer of the workload certificate is added by default.

func (*MeshTrust) AddRoots

func (mesh *MeshTrust) AddRoots(rootCertPEM []byte) error

AddRoots will process a PEM file containing multiple concatenated certificates.

func (*MeshTrust) Provision

func (t *MeshTrust) Provision(ctx context.Context) error

func (*MeshTrust) VerifyClientCert

func (mesh *MeshTrust) VerifyClientCert(allowMeshExternal bool, rawCerts [][]byte, _ [][]*x509.Certificate) error

VerifyClientCert is specific to servers accepting connections. Only used if 'request certificat' is set in the tls.Config, and if a certificate is provided by client.

type Trust

type Trust struct {
	Domain    string
	Namespace string

	RootsPEM string `json:"roots,omitempty"`

	// List of base32(public_key) to be trusted.
	RootPub32 []string

	AllowedNamespaces []string

	// If set to true, allow connections from clients not signed by the
	// trusted roots, and allow connections to servers not signed by trusted
	// roots or root CAs.
	//
	// The certificate public key will be verified out-of-band, using TOFU or
	// DNS or other mechanisms.
	AllowMeshExternal bool

	// If empty, the cluster is using system certs or SPIFFE CAs - as configured in
	// Mesh.
	//
	// Otherwise, it's the configured root certs list, in PEM format.
	// May include multiple concatenated roots.
	//
	// TODO: allow root SHA only.
	// TODO: move to trust config
	CACertPEM string `json:"ca_cert,omitempty"`

	// Expected SANs - if not set, the DNS host in the address is used.
	// For mesh FQDNs, the namespace will be checked ( second part of the FQDN )
	DNSSANs []string `json:"dns_san,omitempty"`
	//IPSANs  []string `json:"ip_san,omitempty"`
	URLSANs []string `json:"url_san,omitempty"`
	// SNI to use when making the request. Defaults to hostname in Addr
	SNI string `json:"sni,omitempty"`

	ALPN []string `json:"alpn,omitempty"`

	// Associated with a trust, used by clients.
	ClientSessionCache tls.ClientSessionCache `json:"-"`
	// contains filtered or unexported fields
}

Trust configures the verification (authentication) of the peers.

This can be used for mesh (using namespaces and 'trust domain') or for client overrides (custom SNI, ALPN - and trust servers with specific SANs or hash of public keys).

It does include small elements of authorization: - deny if the peer is not part of the mesh - allow only specific namespaces or domains (for Spiffe or DNS)

It can represent the 'default mesh' root of trust or per-domain verification.

This is similar to JWT verification: a set of signing keys and restrictions on what claims can be set.

func NewTrust

func NewTrust() *Trust

func (*Trust) CertPool

func (d *Trust) CertPool() *x509.CertPool

CertPool returns the list of roots to be trusted for this dest. Also implements caddy CA interface for trust anchors.

TODO: move this to certs package and use a reference, also handle DNS

func (*Trust) Provision

func (t *Trust) Provision(ctx context.Context) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL