print_test.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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{}, nil, 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. ob.String(),
  80. )
  81. assert.Equal(t, "", eb.String())
  82. // test json
  83. ob.Reset()
  84. eb.Reset()
  85. tf.Truncate(0)
  86. tf.Seek(0, 0)
  87. tf.Write(p)
  88. tf.Write(p)
  89. tf.Write(p)
  90. err = printCert([]string{"-json", "-path", tf.Name()}, ob, eb)
  91. fp, _ = c.Fingerprint()
  92. pk = hex.EncodeToString(c.PublicKey())
  93. sig = hex.EncodeToString(c.Signature())
  94. assert.Nil(t, err)
  95. assert.Equal(
  96. t,
  97. "{\"details\":{\"curve\":\"CURVE25519\",\"groups\":[\"hi\"],\"ips\":[],\"isCa\":false,\"issuer\":\""+c.Issuer()+"\",\"name\":\"test\",\"notAfter\":\"0001-01-01T00:00:00Z\",\"notBefore\":\"0001-01-01T00:00:00Z\",\"publicKey\":\""+pk+"\",\"subnets\":[]},\"fingerprint\":\""+fp+"\",\"signature\":\""+sig+"\"}\n{\"details\":{\"curve\":\"CURVE25519\",\"groups\":[\"hi\"],\"ips\":[],\"isCa\":false,\"issuer\":\""+c.Issuer()+"\",\"name\":\"test\",\"notAfter\":\"0001-01-01T00:00:00Z\",\"notBefore\":\"0001-01-01T00:00:00Z\",\"publicKey\":\""+pk+"\",\"subnets\":[]},\"fingerprint\":\""+fp+"\",\"signature\":\""+sig+"\"}\n{\"details\":{\"curve\":\"CURVE25519\",\"groups\":[\"hi\"],\"ips\":[],\"isCa\":false,\"issuer\":\""+c.Issuer()+"\",\"name\":\"test\",\"notAfter\":\"0001-01-01T00:00:00Z\",\"notBefore\":\"0001-01-01T00:00:00Z\",\"publicKey\":\""+pk+"\",\"subnets\":[]},\"fingerprint\":\""+fp+"\",\"signature\":\""+sig+"\"}\n",
  98. ob.String(),
  99. )
  100. assert.Equal(t, "", eb.String())
  101. }
  102. // NewTestCaCert will generate a CA cert
  103. func NewTestCaCert(name string, pubKey, privKey []byte, before, after time.Time, networks, unsafeNetworks []netip.Prefix, groups []string) (cert.Certificate, []byte) {
  104. var err error
  105. if pubKey == nil || privKey == nil {
  106. pubKey, privKey, err = ed25519.GenerateKey(rand.Reader)
  107. if err != nil {
  108. panic(err)
  109. }
  110. }
  111. t := &cert.TBSCertificate{
  112. Version: cert.Version1,
  113. Name: name,
  114. NotBefore: time.Unix(before.Unix(), 0),
  115. NotAfter: time.Unix(after.Unix(), 0),
  116. PublicKey: pubKey,
  117. Networks: networks,
  118. UnsafeNetworks: unsafeNetworks,
  119. Groups: groups,
  120. IsCA: true,
  121. }
  122. c, err := t.Sign(nil, cert.Curve_CURVE25519, privKey)
  123. if err != nil {
  124. panic(err)
  125. }
  126. return c, privKey
  127. }
  128. func NewTestCert(ca cert.Certificate, signerKey []byte, name string, before, after time.Time, networks, unsafeNetworks []netip.Prefix, groups []string) (cert.Certificate, []byte) {
  129. if before.IsZero() {
  130. before = ca.NotBefore()
  131. }
  132. if after.IsZero() {
  133. after = ca.NotAfter()
  134. }
  135. pub, rawPriv := x25519Keypair()
  136. nc := &cert.TBSCertificate{
  137. Version: cert.Version1,
  138. Name: name,
  139. Networks: networks,
  140. UnsafeNetworks: unsafeNetworks,
  141. Groups: groups,
  142. NotBefore: time.Unix(before.Unix(), 0),
  143. NotAfter: time.Unix(after.Unix(), 0),
  144. PublicKey: pub,
  145. IsCA: false,
  146. }
  147. c, err := nc.Sign(ca, ca.Curve(), signerKey)
  148. if err != nil {
  149. panic(err)
  150. }
  151. return c, rawPriv
  152. }