cert.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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 version == cert.Version3 {
  37. pub, priv = appendPQSigningKey(pub, priv)
  38. }
  39. if before.IsZero() {
  40. before = testCertNow.Add(time.Second * -60)
  41. }
  42. if after.IsZero() {
  43. after = testCertNow.Add(time.Second * 60)
  44. }
  45. t := &cert.TBSCertificate{
  46. Curve: curve,
  47. Version: version,
  48. Name: "test ca",
  49. NotBefore: time.Unix(before.Unix(), 0),
  50. NotAfter: time.Unix(after.Unix(), 0),
  51. PublicKey: pub,
  52. Networks: networks,
  53. UnsafeNetworks: unsafeNetworks,
  54. Groups: groups,
  55. IsCA: true,
  56. }
  57. if version == cert.Version3 {
  58. t.PQSuite = cert.DefaultPQSuite
  59. }
  60. c, err := t.Sign(nil, curve, priv)
  61. if err != nil {
  62. panic(err)
  63. }
  64. pem, err := c.MarshalPEM()
  65. if err != nil {
  66. panic(err)
  67. }
  68. return c, pub, priv, pem
  69. }
  70. // NewTestCert will generate a signed certificate with the provided details.
  71. // Expiry times are defaulted if you do not pass them in
  72. 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) {
  73. if before.IsZero() {
  74. before = testCertNow.Add(time.Second * -60)
  75. }
  76. if after.IsZero() {
  77. after = testCertNow.Add(time.Second * 60)
  78. }
  79. var pub, priv []byte
  80. switch curve {
  81. case cert.Curve_CURVE25519:
  82. pub, priv = X25519Keypair()
  83. case cert.Curve_P256:
  84. pub, priv = P256Keypair()
  85. default:
  86. panic("unknown curve")
  87. }
  88. if v == cert.Version3 {
  89. pub, priv = appendPQKey(ca, pub, priv)
  90. }
  91. nc := &cert.TBSCertificate{
  92. Version: v,
  93. Curve: curve,
  94. Name: name,
  95. Networks: networks,
  96. UnsafeNetworks: unsafeNetworks,
  97. Groups: groups,
  98. NotBefore: time.Unix(before.Unix(), 0),
  99. NotAfter: time.Unix(after.Unix(), 0),
  100. PublicKey: pub,
  101. IsCA: false,
  102. PQSuite: cert.PQSuiteOf(ca),
  103. }
  104. c, err := nc.Sign(ca, ca.Curve(), key)
  105. if err != nil {
  106. panic(err)
  107. }
  108. pem, err := c.MarshalPEM()
  109. if err != nil {
  110. panic(err)
  111. }
  112. if v == cert.Version3 {
  113. return c, pub, cert.MarshalPQPrivateKeyToPEM(curve, cert.PQSuiteOf(ca), priv), pem
  114. }
  115. return c, pub, cert.MarshalPrivateKeyToPEM(curve, priv), pem
  116. }
  117. func NewTestCertDifferentVersion(c cert.Certificate, v cert.Version, ca cert.Certificate, key []byte) (cert.Certificate, []byte) {
  118. nc := &cert.TBSCertificate{
  119. Version: v,
  120. Curve: c.Curve(),
  121. Name: c.Name(),
  122. Networks: c.Networks(),
  123. UnsafeNetworks: c.UnsafeNetworks(),
  124. Groups: c.Groups(),
  125. NotBefore: time.Unix(c.NotBefore().Unix(), 0),
  126. NotAfter: time.Unix(c.NotAfter().Unix(), 0),
  127. PublicKey: c.PublicKey(),
  128. IsCA: false,
  129. PQSuite: cert.PQSuiteOf(ca),
  130. }
  131. c, err := nc.Sign(ca, ca.Curve(), key)
  132. if err != nil {
  133. panic(err)
  134. }
  135. pem, err := c.MarshalPEM()
  136. if err != nil {
  137. panic(err)
  138. }
  139. return c, pem
  140. }
  141. // appendPQSigningKey makes a classical CA keypair into a version 3 composite one with a fresh key of the default suite.
  142. func appendPQSigningKey(pub, priv []byte) ([]byte, []byte) {
  143. pqPub, pqPriv, err := cert.DefaultPQSuite.GenerateKey(true)
  144. if err != nil {
  145. panic(err)
  146. }
  147. return append(pub, pqPub...), append(priv, pqPriv...)
  148. }
  149. // appendPQKey makes a classical host keypair into a version 3 composite one with a fresh key of the CA's suite.
  150. func appendPQKey(ca cert.Certificate, pub, priv []byte) ([]byte, []byte) {
  151. pqPub, pqPriv, err := cert.PQSuiteOf(ca).GenerateKey(false)
  152. if err != nil {
  153. panic(err)
  154. }
  155. return append(pub, pqPub...), append(priv, pqPriv...)
  156. }
  157. func X25519Keypair() ([]byte, []byte) {
  158. privkey := make([]byte, 32)
  159. if _, err := io.ReadFull(rand.Reader, privkey); err != nil {
  160. panic(err)
  161. }
  162. pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint)
  163. if err != nil {
  164. panic(err)
  165. }
  166. return pubkey, privkey
  167. }
  168. func P256Keypair() ([]byte, []byte) {
  169. privkey, err := ecdh.P256().GenerateKey(rand.Reader)
  170. if err != nil {
  171. panic(err)
  172. }
  173. pubkey := privkey.PublicKey()
  174. return pubkey.Bytes(), privkey.Bytes()
  175. }
  176. // DummyCert is a minimal cert.Certificate implementation for testing error paths.
  177. type DummyCert struct {
  178. Version_ cert.Version
  179. Curve_ cert.Curve
  180. Groups_ []string
  181. IsCA_ bool
  182. Issuer_ string
  183. Name_ string
  184. Networks_ []netip.Prefix
  185. NotAfter_ time.Time
  186. NotBefore_ time.Time
  187. PublicKey_ []byte
  188. Signature_ []byte
  189. UnsafeNetworks_ []netip.Prefix
  190. }
  191. func (d *DummyCert) Version() cert.Version { return d.Version_ }
  192. func (d *DummyCert) Curve() cert.Curve { return d.Curve_ }
  193. func (d *DummyCert) Groups() []string { return d.Groups_ }
  194. func (d *DummyCert) IsCA() bool { return d.IsCA_ }
  195. func (d *DummyCert) Issuer() string { return d.Issuer_ }
  196. func (d *DummyCert) Name() string { return d.Name_ }
  197. func (d *DummyCert) Networks() []netip.Prefix { return d.Networks_ }
  198. func (d *DummyCert) NotAfter() time.Time { return d.NotAfter_ }
  199. func (d *DummyCert) NotBefore() time.Time { return d.NotBefore_ }
  200. func (d *DummyCert) PublicKey() []byte { return d.PublicKey_ }
  201. func (d *DummyCert) Signature() []byte { return d.Signature_ }
  202. func (d *DummyCert) UnsafeNetworks() []netip.Prefix { return d.UnsafeNetworks_ }
  203. func (d *DummyCert) Fingerprint() (string, error) { return "", nil }
  204. func (d *DummyCert) CheckSignature(key []byte) bool { return false }
  205. func (d *DummyCert) MarshalForHandshakes() ([]byte, error) { return nil, nil }
  206. func (d *DummyCert) MarshalPEM() ([]byte, error) { return nil, nil }
  207. func (d *DummyCert) MarshalJSON() ([]byte, error) { return nil, nil }
  208. func (d *DummyCert) Marshal() ([]byte, error) { return nil, nil }
  209. func (d *DummyCert) String() string { return "dummy" }
  210. func (d *DummyCert) Copy() cert.Certificate { return d }
  211. func (d *DummyCert) VerifyPrivateKey(c cert.Curve, k []byte) error { return nil }
  212. func (d *DummyCert) Expired(time.Time) bool { return false }
  213. func (d *DummyCert) MarshalPublicKeyPEM() []byte { return nil }
  214. func (d *DummyCert) PublicKeyPEM() []byte { return nil }
  215. // NewTestCAPool creates a CAPool from the given CA certificates, panicking on error.
  216. func NewTestCAPool(cas ...cert.Certificate) *cert.CAPool {
  217. pool := cert.NewCAPool()
  218. for _, ca := range cas {
  219. if err := pool.AddCA(ca); err != nil {
  220. panic(err)
  221. }
  222. }
  223. return pool
  224. }