cert.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. package cert
  2. import (
  3. "fmt"
  4. "net/netip"
  5. "time"
  6. )
  7. type Version uint8
  8. const (
  9. VersionPre1 Version = 0
  10. Version1 Version = 1
  11. Version2 Version = 2
  12. )
  13. type Certificate interface {
  14. // Version defines the underlying certificate structure and wire protocol version
  15. // Version1 certificates are ipv4 only and uses protobuf serialization
  16. // Version2 certificates are ipv4 or ipv6 and uses asn.1 serialization
  17. Version() Version
  18. // Name is the human-readable name that identifies this certificate.
  19. Name() string
  20. // Networks is a list of ip addresses and network sizes assigned to this certificate.
  21. // If IsCA is true then certificates signed by this CA can only have ip addresses and
  22. // networks that are contained by an entry in this list.
  23. Networks() []netip.Prefix
  24. // UnsafeNetworks is a list of networks that this host can act as an unsafe router for.
  25. // If IsCA is true then certificates signed by this CA can only have networks that are
  26. // contained by an entry in this list.
  27. UnsafeNetworks() []netip.Prefix
  28. // Groups is a list of identities that can be used to write more general firewall rule
  29. // definitions.
  30. // If IsCA is true then certificates signed by this CA can only use groups that are
  31. // in this list.
  32. Groups() []string
  33. // IsCA signifies if this is a certificate authority (true) or a host certificate (false).
  34. // It is invalid to use a CA certificate as a host certificate.
  35. IsCA() bool
  36. // NotBefore is the time at which this certificate becomes valid.
  37. // If IsCA is true then certificate signed by this CA can not have a time before this.
  38. NotBefore() time.Time
  39. // NotAfter is the time at which this certificate becomes invalid.
  40. // If IsCA is true then certificate signed by this CA can not have a time after this.
  41. NotAfter() time.Time
  42. // Issuer is the fingerprint of the CA that signed this certificate.
  43. // If IsCA is true then this will be empty.
  44. Issuer() string
  45. // PublicKey is the raw bytes to be used in asymmetric cryptographic operations.
  46. PublicKey() []byte
  47. // Curve identifies which curve was used for the PublicKey and Signature.
  48. Curve() Curve
  49. // Signature is the cryptographic seal for all the details of this certificate.
  50. // CheckSignature can be used to verify that the details of this certificate are valid.
  51. Signature() []byte
  52. // CheckSignature will check that the certificate Signature() matches the
  53. // computed signature. A true result means this certificate has not been tampered with.
  54. CheckSignature(signingPublicKey []byte) bool
  55. // Fingerprint returns the hex encoded sha256 sum of the certificate.
  56. // This acts as a unique fingerprint and can be used to blocklist certificates.
  57. Fingerprint() (string, error)
  58. // Expired tests if the certificate is valid for the provided time.
  59. Expired(t time.Time) bool
  60. // VerifyPrivateKey returns an error if the private key is not a pair with the certificates public key.
  61. VerifyPrivateKey(curve Curve, privateKey []byte) error
  62. // Marshal will return the byte representation of this certificate
  63. // This is primarily the format transmitted on the wire.
  64. Marshal() ([]byte, error)
  65. // MarshalForHandshakes prepares the bytes needed to use directly in a handshake
  66. MarshalForHandshakes() ([]byte, error)
  67. // MarshalPEM will return a PEM encoded representation of this certificate
  68. // This is primarily the format stored on disk
  69. MarshalPEM() ([]byte, error)
  70. // MarshalJSON will return the json representation of this certificate
  71. MarshalJSON() ([]byte, error)
  72. // String will return a human-readable representation of this certificate
  73. String() string
  74. // Copy creates a copy of the certificate
  75. Copy() Certificate
  76. }
  77. // CachedCertificate represents a verified certificate with some cached fields to improve
  78. // performance.
  79. type CachedCertificate struct {
  80. Certificate Certificate
  81. InvertedGroups map[string]struct{}
  82. Fingerprint string
  83. signerFingerprint string
  84. }
  85. func (cc *CachedCertificate) String() string {
  86. return cc.Certificate.String()
  87. }
  88. // RecombineAndValidate will attempt to unmarshal a certificate received in a handshake.
  89. // Handshakes save space by placing the peers public key in a different part of the packet, we have to
  90. // reassemble the actual certificate structure with that in mind.
  91. func RecombineAndValidate(v Version, rawCertBytes, publicKey []byte, curve Curve, caPool *CAPool) (*CachedCertificate, error) {
  92. if publicKey == nil {
  93. return nil, ErrNoPeerStaticKey
  94. }
  95. if rawCertBytes == nil {
  96. return nil, ErrNoPayload
  97. }
  98. c, err := unmarshalCertificateFromHandshake(v, rawCertBytes, publicKey, curve)
  99. if err != nil {
  100. return nil, fmt.Errorf("error unmarshaling cert: %w", err)
  101. }
  102. cc, err := caPool.VerifyCertificate(time.Now(), c)
  103. if err != nil {
  104. return nil, fmt.Errorf("certificate validation failed: %w", err)
  105. }
  106. return cc, nil
  107. }
  108. func unmarshalCertificateFromHandshake(v Version, b []byte, publicKey []byte, curve Curve) (Certificate, error) {
  109. var c Certificate
  110. var err error
  111. switch v {
  112. // Implementations must ensure the result is a valid cert!
  113. case VersionPre1, Version1:
  114. c, err = unmarshalCertificateV1(b, publicKey)
  115. case Version2:
  116. c, err = unmarshalCertificateV2(b, publicKey, curve)
  117. default:
  118. //TODO: CERT-V2 make a static var
  119. return nil, fmt.Errorf("unknown certificate version %d", v)
  120. }
  121. if err != nil {
  122. return nil, err
  123. }
  124. if c.Curve() != curve {
  125. return nil, fmt.Errorf("certificate curve %s does not match expected %s", c.Curve().String(), curve.String())
  126. }
  127. return c, nil
  128. }