ca.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package cert
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. )
  7. type NebulaCAPool struct {
  8. CAs map[string]*NebulaCertificate
  9. certBlacklist map[string]struct{}
  10. }
  11. // NewCAPool creates a CAPool
  12. func NewCAPool() *NebulaCAPool {
  13. ca := NebulaCAPool{
  14. CAs: make(map[string]*NebulaCertificate),
  15. certBlacklist: make(map[string]struct{}),
  16. }
  17. return &ca
  18. }
  19. func NewCAPoolFromBytes(caPEMs []byte) (*NebulaCAPool, error) {
  20. pool := NewCAPool()
  21. var err error
  22. for {
  23. caPEMs, err = pool.AddCACertificate(caPEMs)
  24. if err != nil {
  25. return nil, err
  26. }
  27. if caPEMs == nil || len(caPEMs) == 0 || strings.TrimSpace(string(caPEMs)) == "" {
  28. break
  29. }
  30. }
  31. return pool, nil
  32. }
  33. // AddCACertificate verifies a Nebula CA certificate and adds it to the pool
  34. // Only the first pem encoded object will be consumed, any remaining bytes are returned.
  35. // Parsed certificates will be verified and must be a CA
  36. func (ncp *NebulaCAPool) AddCACertificate(pemBytes []byte) ([]byte, error) {
  37. c, pemBytes, err := UnmarshalNebulaCertificateFromPEM(pemBytes)
  38. if err != nil {
  39. return pemBytes, err
  40. }
  41. if !c.Details.IsCA {
  42. return pemBytes, fmt.Errorf("provided certificate was not a CA; %s", c.Details.Name)
  43. }
  44. if !c.CheckSignature(c.Details.PublicKey) {
  45. return pemBytes, fmt.Errorf("provided certificate was not self signed; %s", c.Details.Name)
  46. }
  47. if c.Expired(time.Now()) {
  48. return pemBytes, fmt.Errorf("provided CA certificate is expired; %s", c.Details.Name)
  49. }
  50. sum, err := c.Sha256Sum()
  51. if err != nil {
  52. return pemBytes, fmt.Errorf("could not calculate shasum for provided CA; error: %s; %s", err, c.Details.Name)
  53. }
  54. ncp.CAs[sum] = c
  55. return pemBytes, nil
  56. }
  57. // BlacklistFingerprint adds a cert fingerprint to the blacklist
  58. func (ncp *NebulaCAPool) BlacklistFingerprint(f string) {
  59. ncp.certBlacklist[f] = struct{}{}
  60. }
  61. // ResetCertBlacklist removes all previously blacklisted cert fingerprints
  62. func (ncp *NebulaCAPool) ResetCertBlacklist() {
  63. ncp.certBlacklist = make(map[string]struct{})
  64. }
  65. // IsBlacklisted returns true if the fingerprint fails to generate or has been explicitly blacklisted
  66. func (ncp *NebulaCAPool) IsBlacklisted(c *NebulaCertificate) bool {
  67. h, err := c.Sha256Sum()
  68. if err != nil {
  69. return true
  70. }
  71. if _, ok := ncp.certBlacklist[h]; ok {
  72. return true
  73. }
  74. return false
  75. }
  76. // GetCAForCert attempts to return the signing certificate for the provided certificate.
  77. // No signature validation is performed
  78. func (ncp *NebulaCAPool) GetCAForCert(c *NebulaCertificate) (*NebulaCertificate, error) {
  79. if c.Details.Issuer == "" {
  80. return nil, fmt.Errorf("no issuer in certificate")
  81. }
  82. signer, ok := ncp.CAs[c.Details.Issuer]
  83. if ok {
  84. return signer, nil
  85. }
  86. return nil, fmt.Errorf("could not find ca for the certificate")
  87. }
  88. // GetFingerprints returns an array of trusted CA fingerprints
  89. func (ncp *NebulaCAPool) GetFingerprints() []string {
  90. fp := make([]string, len(ncp.CAs))
  91. i := 0
  92. for k := range ncp.CAs {
  93. fp[i] = k
  94. i++
  95. }
  96. return fp
  97. }