print_test.go 7.4 KB

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