123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- package cert
- import (
- "fmt"
- "net/netip"
- "time"
- )
- type Version uint8
- const (
- VersionPre1 Version = 0
- Version1 Version = 1
- Version2 Version = 2
- )
- type Certificate interface {
- // Version defines the underlying certificate structure and wire protocol version
- // Version1 certificates are ipv4 only and uses protobuf serialization
- // Version2 certificates are ipv4 or ipv6 and uses asn.1 serialization
- Version() Version
- // Name is the human-readable name that identifies this certificate.
- Name() string
- // Networks is a list of ip addresses and network sizes assigned to this certificate.
- // If IsCA is true then certificates signed by this CA can only have ip addresses and
- // networks that are contained by an entry in this list.
- Networks() []netip.Prefix
- // UnsafeNetworks is a list of networks that this host can act as an unsafe router for.
- // If IsCA is true then certificates signed by this CA can only have networks that are
- // contained by an entry in this list.
- UnsafeNetworks() []netip.Prefix
- // Groups is a list of identities that can be used to write more general firewall rule
- // definitions.
- // If IsCA is true then certificates signed by this CA can only use groups that are
- // in this list.
- Groups() []string
- // IsCA signifies if this is a certificate authority (true) or a host certificate (false).
- // It is invalid to use a CA certificate as a host certificate.
- IsCA() bool
- // NotBefore is the time at which this certificate becomes valid.
- // If IsCA is true then certificate signed by this CA can not have a time before this.
- NotBefore() time.Time
- // NotAfter is the time at which this certificate becomes invalid.
- // If IsCA is true then certificate signed by this CA can not have a time after this.
- NotAfter() time.Time
- // Issuer is the fingerprint of the CA that signed this certificate.
- // If IsCA is true then this will be empty.
- Issuer() string
- // PublicKey is the raw bytes to be used in asymmetric cryptographic operations.
- PublicKey() []byte
- // Curve identifies which curve was used for the PublicKey and Signature.
- Curve() Curve
- // Signature is the cryptographic seal for all the details of this certificate.
- // CheckSignature can be used to verify that the details of this certificate are valid.
- Signature() []byte
- // CheckSignature will check that the certificate Signature() matches the
- // computed signature. A true result means this certificate has not been tampered with.
- CheckSignature(signingPublicKey []byte) bool
- // Fingerprint returns the hex encoded sha256 sum of the certificate.
- // This acts as a unique fingerprint and can be used to blocklist certificates.
- Fingerprint() (string, error)
- // Expired tests if the certificate is valid for the provided time.
- Expired(t time.Time) bool
- // VerifyPrivateKey returns an error if the private key is not a pair with the certificates public key.
- VerifyPrivateKey(curve Curve, privateKey []byte) error
- // Marshal will return the byte representation of this certificate
- // This is primarily the format transmitted on the wire.
- Marshal() ([]byte, error)
- // MarshalForHandshakes prepares the bytes needed to use directly in a handshake
- MarshalForHandshakes() ([]byte, error)
- // MarshalPEM will return a PEM encoded representation of this certificate
- // This is primarily the format stored on disk
- MarshalPEM() ([]byte, error)
- // MarshalJSON will return the json representation of this certificate
- MarshalJSON() ([]byte, error)
- // String will return a human-readable representation of this certificate
- String() string
- // Copy creates a copy of the certificate
- Copy() Certificate
- }
- // CachedCertificate represents a verified certificate with some cached fields to improve
- // performance.
- type CachedCertificate struct {
- Certificate Certificate
- InvertedGroups map[string]struct{}
- Fingerprint string
- signerFingerprint string
- }
- func (cc *CachedCertificate) String() string {
- return cc.Certificate.String()
- }
- // Recombine will attempt to unmarshal a certificate received in a handshake.
- // Handshakes save space by placing the peers public key in a different part of the packet, we have to
- // reassemble the actual certificate structure with that in mind.
- func Recombine(v Version, rawCertBytes, publicKey []byte, curve Curve) (Certificate, error) {
- if publicKey == nil {
- return nil, ErrNoPeerStaticKey
- }
- if rawCertBytes == nil {
- return nil, ErrNoPayload
- }
- var c Certificate
- var err error
- switch v {
- // Implementations must ensure the result is a valid cert!
- case VersionPre1, Version1:
- c, err = unmarshalCertificateV1(rawCertBytes, publicKey)
- case Version2:
- c, err = unmarshalCertificateV2(rawCertBytes, publicKey, curve)
- default:
- //TODO: CERT-V2 make a static var
- return nil, fmt.Errorf("unknown certificate version %d", v)
- }
- if err != nil {
- return nil, err
- }
- if c.Curve() != curve {
- return nil, fmt.Errorf("certificate curve %s does not match expected %s", c.Curve().String(), curve.String())
- }
- return c, nil
- }
|