verify_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package main
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "os"
  6. "testing"
  7. "time"
  8. "github.com/slackhq/nebula/cert"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. "golang.org/x/crypto/ed25519"
  12. )
  13. func Test_verifySummary(t *testing.T) {
  14. assert.Equal(t, "verify <flags>: verifies a certificate isn't expired and was signed by a trusted authority.", verifySummary())
  15. }
  16. func Test_verifyHelp(t *testing.T) {
  17. ob := &bytes.Buffer{}
  18. verifyHelp(ob)
  19. assert.Equal(
  20. t,
  21. "Usage of "+os.Args[0]+" verify <flags>: verifies a certificate isn't expired and was signed by a trusted authority.\n"+
  22. " Pass \"-\" to any path flag to read from stdin or write to stdout.\n"+
  23. " -ca string\n"+
  24. " \tRequired: path to a file containing one or more ca certificates\n"+
  25. " -crt string\n"+
  26. " \tRequired: path to a file containing a single certificate\n",
  27. ob.String(),
  28. )
  29. }
  30. func Test_verify(t *testing.T) {
  31. time.Local = time.UTC
  32. ob := &bytes.Buffer{}
  33. eb := &bytes.Buffer{}
  34. // required args
  35. assertHelpError(t, verify([]string{"-ca", "derp"}, ob, eb), "-crt is required")
  36. assert.Empty(t, ob.String())
  37. assert.Empty(t, eb.String())
  38. assertHelpError(t, verify([]string{"-crt", "derp"}, ob, eb), "-ca is required")
  39. assert.Empty(t, ob.String())
  40. assert.Empty(t, eb.String())
  41. // no ca at path
  42. ob.Reset()
  43. eb.Reset()
  44. err := verify([]string{"-ca", "does_not_exist", "-crt", "does_not_exist"}, ob, eb)
  45. assert.Empty(t, ob.String())
  46. assert.Empty(t, eb.String())
  47. require.EqualError(t, err, "error while reading ca: open does_not_exist: "+NoSuchFileError)
  48. // invalid ca at path
  49. ob.Reset()
  50. eb.Reset()
  51. caFile, err := os.CreateTemp("", "verify-ca")
  52. require.NoError(t, err)
  53. defer os.Remove(caFile.Name())
  54. caFile.WriteString("-----BEGIN NOPE-----")
  55. err = verify([]string{"-ca", caFile.Name(), "-crt", "does_not_exist"}, ob, eb)
  56. assert.Empty(t, ob.String())
  57. assert.Empty(t, eb.String())
  58. require.ErrorIs(t, err, cert.ErrInvalidPEMBlock)
  59. // make a ca for later
  60. caPub, caPriv, _ := ed25519.GenerateKey(rand.Reader)
  61. ca, _ := NewTestCaCert("test-ca", caPub, caPriv, time.Now().Add(time.Hour*-1), time.Now().Add(time.Hour*2), nil, nil, nil)
  62. b, _ := ca.MarshalPEM()
  63. caFile.Truncate(0)
  64. caFile.Seek(0, 0)
  65. caFile.Write(b)
  66. // no crt at path
  67. err = verify([]string{"-ca", caFile.Name(), "-crt", "does_not_exist"}, ob, eb)
  68. assert.Empty(t, ob.String())
  69. assert.Empty(t, eb.String())
  70. require.EqualError(t, err, "unable to read crt: open does_not_exist: "+NoSuchFileError)
  71. // invalid crt at path
  72. ob.Reset()
  73. eb.Reset()
  74. certFile, err := os.CreateTemp("", "verify-cert")
  75. require.NoError(t, err)
  76. defer os.Remove(certFile.Name())
  77. certFile.WriteString("-----BEGIN NOPE-----")
  78. err = verify([]string{"-ca", caFile.Name(), "-crt", certFile.Name()}, ob, eb)
  79. assert.Empty(t, ob.String())
  80. assert.Empty(t, eb.String())
  81. require.EqualError(t, err, "error while parsing crt: input did not contain a valid PEM encoded block")
  82. // unverifiable cert at path
  83. crt, _ := NewTestCert(ca, caPriv, "test-cert", time.Now().Add(time.Hour*-1), time.Now().Add(time.Hour), nil, nil, nil)
  84. // Slightly evil hack to modify the certificate after it was sealed to generate an invalid signature
  85. pub := crt.PublicKey()
  86. for i, _ := range pub {
  87. pub[i] = 0
  88. }
  89. b, _ = crt.MarshalPEM()
  90. certFile.Truncate(0)
  91. certFile.Seek(0, 0)
  92. certFile.Write(b)
  93. err = verify([]string{"-ca", caFile.Name(), "-crt", certFile.Name()}, ob, eb)
  94. assert.Empty(t, ob.String())
  95. assert.Empty(t, eb.String())
  96. require.ErrorIs(t, err, cert.ErrSignatureMismatch)
  97. // verified cert at path
  98. crt, _ = NewTestCert(ca, caPriv, "test-cert", time.Now().Add(time.Hour*-1), time.Now().Add(time.Hour), nil, nil, nil)
  99. b, _ = crt.MarshalPEM()
  100. certFile.Truncate(0)
  101. certFile.Seek(0, 0)
  102. certFile.Write(b)
  103. err = verify([]string{"-ca", caFile.Name(), "-crt", certFile.Name()}, ob, eb)
  104. assert.Empty(t, ob.String())
  105. assert.Empty(t, eb.String())
  106. require.NoError(t, err)
  107. }
  108. func Test_verify_stdio(t *testing.T) {
  109. ob := &bytes.Buffer{}
  110. eb := &bytes.Buffer{}
  111. caPub, caPriv, _ := ed25519.GenerateKey(rand.Reader)
  112. ca, _ := NewTestCaCert("test-ca", caPub, caPriv, time.Now().Add(time.Hour*-1), time.Now().Add(time.Hour*2), nil, nil, nil)
  113. caPEM, _ := ca.MarshalPEM()
  114. crt, _ := NewTestCert(ca, caPriv, "test-cert", time.Now().Add(time.Hour*-1), time.Now().Add(time.Hour), nil, nil, nil)
  115. crtPEM, _ := crt.MarshalPEM()
  116. caFile, err := os.CreateTemp("", "verify-ca")
  117. require.NoError(t, err)
  118. defer os.Remove(caFile.Name())
  119. caFile.Write(caPEM)
  120. // crt on stdin, ca on disk
  121. withStdin(t, bytes.NewReader(crtPEM))
  122. require.NoError(t, verify([]string{"-ca", caFile.Name(), "-crt", "-"}, ob, eb))
  123. assert.Empty(t, ob.String())
  124. assert.Empty(t, eb.String())
  125. // ca on stdin, crt on disk
  126. certFile, err := os.CreateTemp("", "verify-cert")
  127. require.NoError(t, err)
  128. defer os.Remove(certFile.Name())
  129. certFile.Write(crtPEM)
  130. withStdin(t, bytes.NewReader(caPEM))
  131. ob.Reset()
  132. eb.Reset()
  133. require.NoError(t, verify([]string{"-ca", "-", "-crt", certFile.Name()}, ob, eb))
  134. assert.Empty(t, ob.String())
  135. assert.Empty(t, eb.String())
  136. // both flags on stdin should error
  137. withStdin(t, bytes.NewReader(caPEM))
  138. ob.Reset()
  139. eb.Reset()
  140. require.EqualError(t, verify([]string{"-ca", "-", "-crt", "-"}, ob, eb),
  141. `-ca and -crt both set to "-", only one input may read from stdin`)
  142. }