cert.go 5.9 KB

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