cert.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. package cert_test
  2. import (
  3. "crypto/ecdh"
  4. "crypto/ecdsa"
  5. "crypto/elliptic"
  6. "crypto/rand"
  7. "io"
  8. "net/netip"
  9. "time"
  10. "github.com/slackhq/nebula/cert"
  11. "golang.org/x/crypto/curve25519"
  12. "golang.org/x/crypto/ed25519"
  13. )
  14. // NewTestCaCert will create a new ca certificate
  15. func NewTestCaCert(version cert.Version, curve cert.Curve, before, after time.Time, networks, unsafeNetworks []netip.Prefix, groups []string) (cert.Certificate, []byte, []byte, []byte) {
  16. var err error
  17. var pub, priv []byte
  18. switch curve {
  19. case cert.Curve_CURVE25519:
  20. pub, priv, err = ed25519.GenerateKey(rand.Reader)
  21. case cert.Curve_P256:
  22. privk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  23. if err != nil {
  24. panic(err)
  25. }
  26. pub = elliptic.Marshal(elliptic.P256(), privk.PublicKey.X, privk.PublicKey.Y)
  27. priv = privk.D.FillBytes(make([]byte, 32))
  28. default:
  29. // There is no default to allow the underlying lib to respond with an error
  30. }
  31. if before.IsZero() {
  32. before = time.Now().Add(time.Second * -60).Round(time.Second)
  33. }
  34. if after.IsZero() {
  35. after = time.Now().Add(time.Second * 60).Round(time.Second)
  36. }
  37. t := &cert.TBSCertificate{
  38. Curve: curve,
  39. Version: version,
  40. Name: "test ca",
  41. NotBefore: time.Unix(before.Unix(), 0),
  42. NotAfter: time.Unix(after.Unix(), 0),
  43. PublicKey: pub,
  44. Networks: networks,
  45. UnsafeNetworks: unsafeNetworks,
  46. Groups: groups,
  47. IsCA: true,
  48. }
  49. c, err := t.Sign(nil, curve, priv)
  50. if err != nil {
  51. panic(err)
  52. }
  53. pem, err := c.MarshalPEM()
  54. if err != nil {
  55. panic(err)
  56. }
  57. return c, pub, priv, pem
  58. }
  59. // NewTestCert will generate a signed certificate with the provided details.
  60. // Expiry times are defaulted if you do not pass them in
  61. func NewTestCert(v cert.Version, curve cert.Curve, ca cert.Certificate, key []byte, name string, before, after time.Time, networks, unsafeNetworks []netip.Prefix, groups []string) (cert.Certificate, []byte, []byte, []byte) {
  62. if before.IsZero() {
  63. before = time.Now().Add(time.Second * -60).Round(time.Second)
  64. }
  65. if after.IsZero() {
  66. after = time.Now().Add(time.Second * 60).Round(time.Second)
  67. }
  68. var pub, priv []byte
  69. switch curve {
  70. case cert.Curve_CURVE25519:
  71. pub, priv = X25519Keypair()
  72. case cert.Curve_P256:
  73. pub, priv = P256Keypair()
  74. default:
  75. panic("unknown curve")
  76. }
  77. nc := &cert.TBSCertificate{
  78. Version: v,
  79. Curve: curve,
  80. Name: name,
  81. Networks: networks,
  82. UnsafeNetworks: unsafeNetworks,
  83. Groups: groups,
  84. NotBefore: time.Unix(before.Unix(), 0),
  85. NotAfter: time.Unix(after.Unix(), 0),
  86. PublicKey: pub,
  87. IsCA: false,
  88. }
  89. c, err := nc.Sign(ca, ca.Curve(), key)
  90. if err != nil {
  91. panic(err)
  92. }
  93. pem, err := c.MarshalPEM()
  94. if err != nil {
  95. panic(err)
  96. }
  97. return c, pub, cert.MarshalPrivateKeyToPEM(curve, priv), pem
  98. }
  99. func NewTestCertDifferentVersion(c cert.Certificate, v cert.Version, ca cert.Certificate, key []byte) (cert.Certificate, []byte) {
  100. nc := &cert.TBSCertificate{
  101. Version: v,
  102. Curve: c.Curve(),
  103. Name: c.Name(),
  104. Networks: c.Networks(),
  105. UnsafeNetworks: c.UnsafeNetworks(),
  106. Groups: c.Groups(),
  107. NotBefore: time.Unix(c.NotBefore().Unix(), 0),
  108. NotAfter: time.Unix(c.NotAfter().Unix(), 0),
  109. PublicKey: c.PublicKey(),
  110. IsCA: false,
  111. }
  112. c, err := nc.Sign(ca, ca.Curve(), key)
  113. if err != nil {
  114. panic(err)
  115. }
  116. pem, err := c.MarshalPEM()
  117. if err != nil {
  118. panic(err)
  119. }
  120. return c, pem
  121. }
  122. func X25519Keypair() ([]byte, []byte) {
  123. privkey := make([]byte, 32)
  124. if _, err := io.ReadFull(rand.Reader, privkey); err != nil {
  125. panic(err)
  126. }
  127. pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint)
  128. if err != nil {
  129. panic(err)
  130. }
  131. return pubkey, privkey
  132. }
  133. func P256Keypair() ([]byte, []byte) {
  134. privkey, err := ecdh.P256().GenerateKey(rand.Reader)
  135. if err != nil {
  136. panic(err)
  137. }
  138. pubkey := privkey.PublicKey()
  139. return pubkey.Bytes(), privkey.Bytes()
  140. }
  141. // DummyCert is a minimal cert.Certificate implementation for testing error paths.
  142. type DummyCert struct {
  143. Version_ cert.Version
  144. Curve_ cert.Curve
  145. Groups_ []string
  146. IsCA_ bool
  147. Issuer_ string
  148. Name_ string
  149. Networks_ []netip.Prefix
  150. NotAfter_ time.Time
  151. NotBefore_ time.Time
  152. PublicKey_ []byte
  153. Signature_ []byte
  154. UnsafeNetworks_ []netip.Prefix
  155. }
  156. func (d *DummyCert) Version() cert.Version { return d.Version_ }
  157. func (d *DummyCert) Curve() cert.Curve { return d.Curve_ }
  158. func (d *DummyCert) Groups() []string { return d.Groups_ }
  159. func (d *DummyCert) IsCA() bool { return d.IsCA_ }
  160. func (d *DummyCert) Issuer() string { return d.Issuer_ }
  161. func (d *DummyCert) Name() string { return d.Name_ }
  162. func (d *DummyCert) Networks() []netip.Prefix { return d.Networks_ }
  163. func (d *DummyCert) NotAfter() time.Time { return d.NotAfter_ }
  164. func (d *DummyCert) NotBefore() time.Time { return d.NotBefore_ }
  165. func (d *DummyCert) PublicKey() []byte { return d.PublicKey_ }
  166. func (d *DummyCert) Signature() []byte { return d.Signature_ }
  167. func (d *DummyCert) UnsafeNetworks() []netip.Prefix { return d.UnsafeNetworks_ }
  168. func (d *DummyCert) Fingerprint() (string, error) { return "", nil }
  169. func (d *DummyCert) CheckSignature(key []byte) bool { return false }
  170. func (d *DummyCert) MarshalForHandshakes() ([]byte, error) { return nil, nil }
  171. func (d *DummyCert) MarshalPEM() ([]byte, error) { return nil, nil }
  172. func (d *DummyCert) MarshalJSON() ([]byte, error) { return nil, nil }
  173. func (d *DummyCert) Marshal() ([]byte, error) { return nil, nil }
  174. func (d *DummyCert) String() string { return "dummy" }
  175. func (d *DummyCert) Copy() cert.Certificate { return d }
  176. func (d *DummyCert) VerifyPrivateKey(c cert.Curve, k []byte) error { return nil }
  177. func (d *DummyCert) Expired(time.Time) bool { return false }
  178. func (d *DummyCert) MarshalPublicKeyPEM() []byte { return nil }
  179. func (d *DummyCert) PublicKeyPEM() []byte { return nil }
  180. // NewTestCAPool creates a CAPool from the given CA certificates, panicking on error.
  181. func NewTestCAPool(cas ...cert.Certificate) *cert.CAPool {
  182. pool := cert.NewCAPool()
  183. for _, ca := range cas {
  184. if err := pool.AddCA(ca); err != nil {
  185. panic(err)
  186. }
  187. }
  188. return pool
  189. }