print_test.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. package main
  2. import (
  3. "bytes"
  4. "crypto/ed25519"
  5. "crypto/rand"
  6. "encoding/hex"
  7. "net/netip"
  8. "os"
  9. "testing"
  10. "time"
  11. "github.com/slackhq/nebula/cert"
  12. "github.com/stretchr/testify/assert"
  13. )
  14. func Test_printSummary(t *testing.T) {
  15. assert.Equal(t, "print <flags>: prints details about a certificate", printSummary())
  16. }
  17. func Test_printHelp(t *testing.T) {
  18. ob := &bytes.Buffer{}
  19. printHelp(ob)
  20. assert.Equal(
  21. t,
  22. "Usage of "+os.Args[0]+" print <flags>: prints details about a certificate\n"+
  23. " -json\n"+
  24. " \tOptional: outputs certificates in json format\n"+
  25. " -out-qr string\n"+
  26. " \tOptional: output a qr code image (png) of the certificate\n"+
  27. " -path string\n"+
  28. " \tRequired: path to the certificate\n",
  29. ob.String(),
  30. )
  31. }
  32. func Test_printCert(t *testing.T) {
  33. // Orient our local time and avoid headaches
  34. time.Local = time.UTC
  35. ob := &bytes.Buffer{}
  36. eb := &bytes.Buffer{}
  37. // no path
  38. err := printCert([]string{}, ob, eb)
  39. assert.Equal(t, "", ob.String())
  40. assert.Equal(t, "", eb.String())
  41. assertHelpError(t, err, "-path is required")
  42. // no cert at path
  43. ob.Reset()
  44. eb.Reset()
  45. err = printCert([]string{"-path", "does_not_exist"}, ob, eb)
  46. assert.Equal(t, "", ob.String())
  47. assert.Equal(t, "", eb.String())
  48. assert.EqualError(t, err, "unable to read cert; open does_not_exist: "+NoSuchFileError)
  49. // invalid cert at path
  50. ob.Reset()
  51. eb.Reset()
  52. tf, err := os.CreateTemp("", "print-cert")
  53. assert.Nil(t, err)
  54. defer os.Remove(tf.Name())
  55. tf.WriteString("-----BEGIN NOPE-----")
  56. err = printCert([]string{"-path", tf.Name()}, ob, eb)
  57. assert.Equal(t, "", ob.String())
  58. assert.Equal(t, "", eb.String())
  59. assert.EqualError(t, err, "error while unmarshaling cert: input did not contain a valid PEM encoded block")
  60. // test multiple certs
  61. ob.Reset()
  62. eb.Reset()
  63. tf.Truncate(0)
  64. tf.Seek(0, 0)
  65. ca, caKey := NewTestCaCert("test ca", nil, nil, time.Time{}, time.Time{}, nil, nil, nil)
  66. c, _ := NewTestCert(ca, caKey, "test", time.Time{}, time.Time{}, []netip.Prefix{netip.MustParsePrefix("10.0.0.123/8")}, nil, []string{"hi"})
  67. p, _ := c.MarshalPEM()
  68. tf.Write(p)
  69. tf.Write(p)
  70. tf.Write(p)
  71. err = printCert([]string{"-path", tf.Name()}, ob, eb)
  72. fp, _ := c.Fingerprint()
  73. pk := hex.EncodeToString(c.PublicKey())
  74. sig := hex.EncodeToString(c.Signature())
  75. assert.Nil(t, err)
  76. assert.Equal(
  77. t,
  78. //"NebulaCertificate {\n\tDetails {\n\t\tName: test\n\t\tIps: []\n\t\tSubnets: []\n\t\tGroups: [\n\t\t\t\"hi\"\n\t\t]\n\t\tNot before: 0001-01-01 00:00:00 +0000 UTC\n\t\tNot After: 0001-01-01 00:00:00 +0000 UTC\n\t\tIs CA: false\n\t\tIssuer: "+c.Issuer()+"\n\t\tPublic key: "+pk+"\n\t\tCurve: CURVE25519\n\t}\n\tFingerprint: "+fp+"\n\tSignature: "+sig+"\n}\nNebulaCertificate {\n\tDetails {\n\t\tName: test\n\t\tIps: []\n\t\tSubnets: []\n\t\tGroups: [\n\t\t\t\"hi\"\n\t\t]\n\t\tNot before: 0001-01-01 00:00:00 +0000 UTC\n\t\tNot After: 0001-01-01 00:00:00 +0000 UTC\n\t\tIs CA: false\n\t\tIssuer: "+c.Issuer()+"\n\t\tPublic key: "+pk+"\n\t\tCurve: CURVE25519\n\t}\n\tFingerprint: "+fp+"\n\tSignature: "+sig+"\n}\nNebulaCertificate {\n\tDetails {\n\t\tName: test\n\t\tIps: []\n\t\tSubnets: []\n\t\tGroups: [\n\t\t\t\"hi\"\n\t\t]\n\t\tNot before: 0001-01-01 00:00:00 +0000 UTC\n\t\tNot After: 0001-01-01 00:00:00 +0000 UTC\n\t\tIs CA: false\n\t\tIssuer: "+c.Issuer()+"\n\t\tPublic key: "+pk+"\n\t\tCurve: CURVE25519\n\t}\n\tFingerprint: "+fp+"\n\tSignature: "+sig+"\n}\n",
  79. `{
  80. "details": {
  81. "curve": "CURVE25519",
  82. "groups": [
  83. "hi"
  84. ],
  85. "isCa": false,
  86. "issuer": "`+c.Issuer()+`",
  87. "name": "test",
  88. "networks": [
  89. "10.0.0.123/8"
  90. ],
  91. "notAfter": "0001-01-01T00:00:00Z",
  92. "notBefore": "0001-01-01T00:00:00Z",
  93. "publicKey": "`+pk+`",
  94. "unsafeNetworks": []
  95. },
  96. "fingerprint": "`+fp+`",
  97. "signature": "`+sig+`",
  98. "version": 1
  99. }
  100. {
  101. "details": {
  102. "curve": "CURVE25519",
  103. "groups": [
  104. "hi"
  105. ],
  106. "isCa": false,
  107. "issuer": "`+c.Issuer()+`",
  108. "name": "test",
  109. "networks": [
  110. "10.0.0.123/8"
  111. ],
  112. "notAfter": "0001-01-01T00:00:00Z",
  113. "notBefore": "0001-01-01T00:00:00Z",
  114. "publicKey": "`+pk+`",
  115. "unsafeNetworks": []
  116. },
  117. "fingerprint": "`+fp+`",
  118. "signature": "`+sig+`",
  119. "version": 1
  120. }
  121. {
  122. "details": {
  123. "curve": "CURVE25519",
  124. "groups": [
  125. "hi"
  126. ],
  127. "isCa": false,
  128. "issuer": "`+c.Issuer()+`",
  129. "name": "test",
  130. "networks": [
  131. "10.0.0.123/8"
  132. ],
  133. "notAfter": "0001-01-01T00:00:00Z",
  134. "notBefore": "0001-01-01T00:00:00Z",
  135. "publicKey": "`+pk+`",
  136. "unsafeNetworks": []
  137. },
  138. "fingerprint": "`+fp+`",
  139. "signature": "`+sig+`",
  140. "version": 1
  141. }
  142. `,
  143. ob.String(),
  144. )
  145. assert.Equal(t, "", eb.String())
  146. // test json
  147. ob.Reset()
  148. eb.Reset()
  149. tf.Truncate(0)
  150. tf.Seek(0, 0)
  151. tf.Write(p)
  152. tf.Write(p)
  153. tf.Write(p)
  154. err = printCert([]string{"-json", "-path", tf.Name()}, ob, eb)
  155. fp, _ = c.Fingerprint()
  156. pk = hex.EncodeToString(c.PublicKey())
  157. sig = hex.EncodeToString(c.Signature())
  158. assert.Nil(t, err)
  159. assert.Equal(
  160. t,
  161. `[{"details":{"curve":"CURVE25519","groups":["hi"],"isCa":false,"issuer":"`+c.Issuer()+`","name":"test","networks":["10.0.0.123/8"],"notAfter":"0001-01-01T00:00:00Z","notBefore":"0001-01-01T00:00:00Z","publicKey":"`+pk+`","unsafeNetworks":[]},"fingerprint":"`+fp+`","signature":"`+sig+`","version":1},{"details":{"curve":"CURVE25519","groups":["hi"],"isCa":false,"issuer":"`+c.Issuer()+`","name":"test","networks":["10.0.0.123/8"],"notAfter":"0001-01-01T00:00:00Z","notBefore":"0001-01-01T00:00:00Z","publicKey":"`+pk+`","unsafeNetworks":[]},"fingerprint":"`+fp+`","signature":"`+sig+`","version":1},{"details":{"curve":"CURVE25519","groups":["hi"],"isCa":false,"issuer":"`+c.Issuer()+`","name":"test","networks":["10.0.0.123/8"],"notAfter":"0001-01-01T00:00:00Z","notBefore":"0001-01-01T00:00:00Z","publicKey":"`+pk+`","unsafeNetworks":[]},"fingerprint":"`+fp+`","signature":"`+sig+`","version":1}]
  162. `,
  163. ob.String(),
  164. )
  165. assert.Equal(t, "", eb.String())
  166. }
  167. // NewTestCaCert will generate a CA cert
  168. func NewTestCaCert(name string, pubKey, privKey []byte, before, after time.Time, networks, unsafeNetworks []netip.Prefix, groups []string) (cert.Certificate, []byte) {
  169. var err error
  170. if pubKey == nil || privKey == nil {
  171. pubKey, privKey, err = ed25519.GenerateKey(rand.Reader)
  172. if err != nil {
  173. panic(err)
  174. }
  175. }
  176. t := &cert.TBSCertificate{
  177. Version: cert.Version1,
  178. Name: name,
  179. NotBefore: time.Unix(before.Unix(), 0),
  180. NotAfter: time.Unix(after.Unix(), 0),
  181. PublicKey: pubKey,
  182. Networks: networks,
  183. UnsafeNetworks: unsafeNetworks,
  184. Groups: groups,
  185. IsCA: true,
  186. }
  187. c, err := t.Sign(nil, cert.Curve_CURVE25519, privKey)
  188. if err != nil {
  189. panic(err)
  190. }
  191. return c, privKey
  192. }
  193. func NewTestCert(ca cert.Certificate, signerKey []byte, name string, before, after time.Time, networks, unsafeNetworks []netip.Prefix, groups []string) (cert.Certificate, []byte) {
  194. if before.IsZero() {
  195. before = ca.NotBefore()
  196. }
  197. if after.IsZero() {
  198. after = ca.NotAfter()
  199. }
  200. if len(networks) == 0 {
  201. networks = []netip.Prefix{netip.MustParsePrefix("10.0.0.123/8")}
  202. }
  203. pub, rawPriv := x25519Keypair()
  204. nc := &cert.TBSCertificate{
  205. Version: cert.Version1,
  206. Name: name,
  207. Networks: networks,
  208. UnsafeNetworks: unsafeNetworks,
  209. Groups: groups,
  210. NotBefore: time.Unix(before.Unix(), 0),
  211. NotAfter: time.Unix(after.Unix(), 0),
  212. PublicKey: pub,
  213. IsCA: false,
  214. }
  215. c, err := nc.Sign(ca, ca.Curve(), signerKey)
  216. if err != nil {
  217. panic(err)
  218. }
  219. return c, rawPriv
  220. }