1
0

cert.go 6.9 KB

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