cmd_sign_verify.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #!/usr/bin/env python3
  2. """Test sign/verify commands."""
  3. import os
  4. import tempfile
  5. from testlib import util, cmd, check
  6. from testlib.proc import Tinc
  7. from testlib.test import Test
  8. PRIV_KEY = """
  9. -----BEGIN ED25519 PRIVATE KEY-----
  10. 4Q8bJqfN60s0tOiZdAhAWLgB9+o947cta2WMXmQIz8mCdBdcphzhp23Wt2vUzfQ6
  11. XHt9+5IqidIw/lLXG61Nbc6IZ+4Fy1XOO1uJ6j4hqIKjdSytD2Vb7MPlNJfPdCDu
  12. -----END ED25519 PRIVATE KEY-----
  13. """
  14. HOST = """
  15. Ed25519PublicKey = nOSmPehc9ljTtbi+IeoKiyYnkc7gd12OzTZTy3TnwgL
  16. Port = 17879
  17. """
  18. # Do not replace \n or this will break on Windows if cloned with native line endings
  19. SIGNED_BYTES = """Signature = foo 1653397516 \
  20. T8Bjg7dc7IjsCrZQC/20qLRsWPlrbthnjyDHQM0BMLoTeAHbLt0fxP5CbTy7Cifgg7P0K179GeahBFsnaIr4MA\n\
  21. fake testing data\n\
  22. hello there\n\
  23. """.encode(
  24. "utf-8"
  25. )
  26. RAW_DATA = tempfile.mktemp()
  27. with open(RAW_DATA, "wb") as raw_file:
  28. raw_file.write(util.random_string(64).encode("utf-8"))
  29. def init(ctx: Test) -> Tinc:
  30. """Initialize a node."""
  31. foo = ctx.node()
  32. stdin = f"init {foo}"
  33. foo.cmd(stdin=stdin)
  34. return foo
  35. def test_sign_errors(foo: Tinc) -> None:
  36. """Test `sign` error conditions."""
  37. _, err = foo.cmd("sign", "foo", "bar", code=1)
  38. check.is_in("Too many arguments", err)
  39. _, err = foo.cmd("sign", "/nonexistent", code=1)
  40. check.is_in("Could not open", err)
  41. os.truncate(foo.sub("ed25519_key.priv"), 0)
  42. _, err = foo.cmd("sign", RAW_DATA, code=1)
  43. check.is_in("Could not read private key from", err)
  44. os.remove(foo.sub("ed25519_key.priv"))
  45. _, err = foo.cmd("sign", RAW_DATA, code=1)
  46. check.is_in("Could not open", err)
  47. def test_verify(foo: Tinc) -> None:
  48. """Test `verify` of data known to work."""
  49. signed_file = tempfile.mktemp()
  50. with open(signed_file, "wb") as f:
  51. f.write(SIGNED_BYTES)
  52. foo.name = "foo"
  53. util.write_text(foo.sub("tinc.conf"), f"Name = {foo}")
  54. util.write_text(foo.sub(f"hosts/{foo}"), HOST)
  55. util.write_text(foo.sub("ed25519_key.priv"), PRIV_KEY)
  56. for name in ".", foo.name:
  57. foo.cmd("verify", name, stdin=SIGNED_BYTES)
  58. foo.cmd("verify", name, signed_file)
  59. if os.name != "nt":
  60. foo.cmd("verify", "*", stdin=SIGNED_BYTES)
  61. foo.cmd("verify", "*", signed_file)
  62. os.remove(signed_file)
  63. def test_verify_errors(foo: Tinc) -> None:
  64. """Test `verify` error conditions."""
  65. _, err = foo.cmd("verify", code=1)
  66. check.is_in("Not enough arguments", err)
  67. _, err = foo.cmd("verify", foo.name, "bar", "baz", code=1)
  68. check.is_in("Too many arguments", err)
  69. _, err = foo.cmd("verify", "foo@", code=1)
  70. check.is_in("Invalid node name", err)
  71. _, err = foo.cmd("verify", foo.name, "/nonexistent", code=1)
  72. check.is_in("Could not open", err)
  73. _, err = foo.cmd("verify", foo.name, stdin="", code=1)
  74. check.is_in("Invalid input", err)
  75. _, err = foo.cmd("verify", foo.name, stdin="Signature = foo bar baz", code=1)
  76. check.is_in("Invalid input", err)
  77. sig = (
  78. "Signature = dog "
  79. "1653395565 "
  80. "D25ACFD89jaV9+6g9TNMDTDxH8JGd3wLMv/YNMwXbrj9Bos9q6IW/tuFPxGxYNQ6qAc93XFzkH5u7Gw+Z86GDA\n"
  81. )
  82. _, err = foo.cmd("verify", foo.name, stdin=sig, code=1)
  83. check.is_in(f"Signature is not made by {foo}", err)
  84. sig = (
  85. f"Signature = {foo} "
  86. "1653395565 "
  87. "D25ACFD89jaV9+6g9TNMDTDxH8JGd3wLMv/YNMwXbrj9Bos9q6IW/tuFPxGxYNQ6qAc93XFzkH5u7Gw+Z86GDA\n"
  88. )
  89. _, err = foo.cmd("verify", foo.name, stdin=sig, code=1)
  90. check.is_in("Invalid signature", err)
  91. util.write_text(foo.sub(f"hosts/{foo}"), "foobar")
  92. _, err = foo.cmd("verify", foo.name, stdin=sig, code=1)
  93. check.is_in("Could not read public key from", err)
  94. def test_sign_verify(foo: Tinc, bar: Tinc) -> None:
  95. """Test `sign` and pass its result to `verify`."""
  96. signed, _ = foo.cmd("sign", RAW_DATA, stdin=b"")
  97. assert isinstance(signed, bytes)
  98. signed_file = tempfile.mktemp()
  99. with open(signed_file, "wb") as f:
  100. f.write(signed)
  101. for name in ".", foo.name:
  102. foo.cmd("verify", name, signed_file)
  103. foo.cmd("verify", name, stdin=signed)
  104. if os.name != "nt":
  105. foo.cmd("verify", "*", signed_file)
  106. foo.cmd("verify", "*", stdin=signed)
  107. os.remove(signed_file)
  108. cmd.exchange(foo, bar)
  109. if os.name != "nt":
  110. signed, _ = foo.cmd("sign", RAW_DATA)
  111. bar.cmd("verify", "*", stdin=signed)
  112. signed, _ = bar.cmd("sign", RAW_DATA)
  113. foo.cmd("verify", bar.name, stdin=signed)
  114. with Test("test errors in `sign`") as context:
  115. test_sign_errors(init(context))
  116. with Test("test errors in `verify`") as context:
  117. test_verify_errors(init(context))
  118. with Test("test successful `verify`") as context:
  119. test_verify(init(context))
  120. with Test("test `sign` and `verify`") as context:
  121. test_sign_verify(init(context), init(context))