summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2015-05-28 11:04:33 -0400
committerNick Mathewson <nickm@torproject.org>2015-05-28 11:04:33 -0400
commit1b52e95028e0d84b7a112e4b8f2e393261dbb19c (patch)
tree3dba31b96e31d4c9816a2f124afc5ff2152af2c8 /src/test
parent0989ba33834c17b2eac3bb87596fca115965ce3c (diff)
parent5eb584e2e91bd5d6d204b9bb62a95c0edf43ff71 (diff)
downloadtor-1b52e95028e0d84b7a112e4b8f2e393261dbb19c.tar.gz
tor-1b52e95028e0d84b7a112e4b8f2e393261dbb19c.zip
Merge branch '12498_ed25519_keys_v6'
Fixed numerous conflicts, and ported code to use new base64 api.
Diffstat (limited to 'src/test')
-rw-r--r--src/test/example_extrainfo.inc233
-rw-r--r--src/test/failing_routerdescs.inc901
-rw-r--r--src/test/include.am6
-rw-r--r--src/test/test.c4
-rw-r--r--src/test/test_containers.c38
-rw-r--r--src/test/test_crypto.c20
-rw-r--r--src/test/test_dir.c133
-rw-r--r--src/test/test_keypin.c255
-rw-r--r--src/test/test_link_handshake.c914
-rw-r--r--src/test/test_microdesc.c93
-rw-r--r--src/test/test_routerkeys.c540
11 files changed, 3122 insertions, 15 deletions
diff --git a/src/test/example_extrainfo.inc b/src/test/example_extrainfo.inc
index 606279a765..e096afd6c4 100644
--- a/src/test/example_extrainfo.inc
+++ b/src/test/example_extrainfo.inc
@@ -190,3 +190,236 @@ static const char EX_EI_BAD_PUBLISHED_KEY[] =
"BvG6303md3INygg+KP49RvWEJR/cU4RZ9QfHpORxH2OocMyRedw2rLex2E7jNNSi\n"
"52yd1sHFYI8ZQ4aff+ZHUjJUGKRyqpbc8okVbq/Rl7vug0dd12eHAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n";
+
+static const char EX_EI_GOOD_ED_EI[] =
+ "extra-info emma A692FE045C32B5E3A54B52882EF678A9DAC46A73\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AYgHn/OKR8GHBlscN5VkO73wA9jSci8QgTM30615ZT44AQAgBAC08woT\n"
+ "MBZpKzRcaoEJhEG7+RmuYtnB2+nODk9IRIs8ZoyYPTZ6dLzI+MLMmtzUuo/Wmvw0\n"
+ "PflTyCb2RlWitOEhAErWH3Z9UmYGnzM/COId0Fe3ScSriyvRoFnJY1+GVAQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 a7K8nwfg+HrdlSGQwr9rnLBq0qozkyZZs6d6aiLEiXGdhV1r9KJncmlQ5SNoY/zMQlyQm8EV5rCyBiVliKQ1Bw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "GvmCmIGgbC1DeawRyRuChy62VmBOG0EviryG/a2qSZiFy0iPPwqSp5ZyZDQEIEId\n"
+ "kkk1zPzK1+S3fmgOAXyXGH0r4YFkoLGnhMk07BoEwi6HEXzjJsabmcNkOHfaOWgs\n"
+ "/5nvnLfcmxL4c6FstZ7t9VQpE06y3GU0zwBeIy1qjp0=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ ;
+const char EX_EI_GOOD_ED_EI_FP[] = "A692FE045C32B5E3A54B52882EF678A9DAC46A73";
+static const char EX_EI_GOOD_ED_EI_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM3jdYwjwGxDWYj/vyFkQT7RgeCNIn89Ei6D2+L/fdtFnqrMXOreFFHL\n"
+ "C7CK2v2uN3v+uXxfb5lADz3NcalxJrCfGTGtaBk7PwMZraTSh2luFKOvSRBQCmB1\n"
+ "yD5N0QqnIhBJoGr6NITpbWyiTKWvYLjl9PZd9af8e8jQCAa5P1j1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+
+static const char EX_EI_ED_MISSING_SIG[] =
+ "extra-info rachel 2A7521497B91A8437021515308A47491164EDBA1\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AT2/T71LFYHiI1ppwNiuaewIu2Hq+GWWQ85O8gpWcUxeAQAgBAC2dgYu\n"
+ "moxhtuip7GVlthT9iomZKba1IllVa7uE1u2uO9BUYZQWXciFt7OnNzMH5mlffwxB\n"
+ "1dWCl+G5nbOsV5jYLbfhrF5afZotf+EQTfob4cCH79AV223LPcySbTHTtQ4=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "oypRD2IZQ5EttOE8dvofrW80nnBfijSkvYzBrM6H4KVeayRYvWfmi96dYO6ybMqm\n"
+ "Yp7Gs3ngqeeNdfHtkRPuQVUXUGYZgBTvYItuagnFlFgRqaHy0knwUIVOL35eqWYx\n"
+ "xSbQKA7fglxEDMFs/RK7FRP4dWc731ZMt5wzzfJHZ8E=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ ;
+const char EX_EI_ED_MISSING_SIG_FP[] = "2A7521497B91A8437021515308A47491164EDBA1";
+static const char EX_EI_ED_MISSING_SIG_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOOB8ccxbtk2dB5FuKFhGndDcO6STNjB6KiG0b9X2QwKrOZMfmXSigto\n"
+ "mtC1JfPTxECayRjLSiP/9UD8iTVvlcnc8mMWBGM12Pa/KoCZRn7McHI3JJ7n9lfn\n"
+ "qw9+iZ9b/rBimzOb3W6k3uxzg9r8secdq4jJwTnwSjTObgxZtC8/AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+
+static const char EX_EI_ED_MISSING_CERT[] =
+ "extra-info lynne E88E43E86015345A323D93D825C33E4AD1028F65\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 H4gKIKm5K9Pfkriy7SlMUD6BdYVp6B5mXKzR/rTyYlpH0tEZ4Fx2hlHNfNNdWXJieXzKZQZo8e7SOVzvrAC3CQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "dIrbQjK5T9t5KM8CpsMF85hh2i060oPIxzYQMgE1q4j99dtb/n7SE8nhj1Sjij4D\n"
+ "7JvTjGdLHi3bFSxXaSmla0wxD9PUYFN7VsBQmwSaDrqrzJFb1SGwZuzW1IEZ7BBi\n"
+ "H0czsxEteg5hcNRwISj5WVthuWmau9v13MijtZGSK40=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+const char EX_EI_ED_MISSING_CERT_FP[] = "E88E43E86015345A323D93D825C33E4AD1028F65";
+static const char EX_EI_ED_MISSING_CERT_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALjA/geb0TR9rp/UPvLhABQpB0XUDYuZAnLkrv+i7AAV7FemTDveEGnc\n"
+ "XdXNSusO1mHOquvr0YYKPhwauInxD56S8QOzLYiWWajGq8XHARQ33b4/9K2TUrAx\n"
+ "W9HTHV1U1zrPlCJtrkbjxsYoHpUg5ljzM7FGYGY5xuvyHu18SQvzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_BAD_CERT1[] =
+ "extra-info marcie F78D8A655607D32281D02144817A4F1D26AE520F\n"
+ "identity-ed25519\n"
+ "-----BEGIN PLAGICAL SPELL-----\n"
+ "aaaa\n"
+ "-----END PLAGICAL SPELL\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 KQJ+2AH7EkkjrD0RtDtUAIr+Vc7wndwILYnoUxFLSJiTP+5fMi54eFF/f1OgkG8gYyTh8phMij9WOxK/dsOpBg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "XWD+P25AH6moi79j20Si3hqKGcJDws+FORL1MTu+GeJLV1mp5CR9N83UH4ffulcL\n"
+ "CpSSBDL/j74HqapzW7QvBx3FilaNT55GvcobZDFK4TKkCEyEmcuWKpEceBS7JTTV\n"
+ "SvwZeOObTjWPafELbsc/gI9Rh5Idwu7mZt3ZVntCGaQ=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_BAD_CERT1_FP[] = "F78D8A655607D32281D02144817A4F1D26AE520F";
+static const char EX_EI_ED_BAD_CERT1_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMlR46JhxsCmWYtmIB/JjTV2TUYIhJLmHy+X7FfkK3ZVQvvl9/3GSXFL\n"
+ "3USfyf3j34XLh8An7pJBi9LAHkIXgnRbglCud7dXoexabmC+c2mSbw5RnuxDGEwz\n"
+ "krXUph/r2b+2UY1CgEt28nFigaHrIQbCmF4szFX/2GPYCLi5SrRNAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_BAD_CERT2[] =
+ "extra-info jaeger 7C2B42E783C4E0EB0CC3BDB37385D16737BACFBD\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55Acpw27GZBdwGCgawCj2F/DPadt8F/9DnEWywEew1Yi3qAOtLpCB8KXL7\n"
+ "4w5deFW2RBg8qTondNSUvAmwYLbLjNXMmgA3+nkoJOP3fcmQMHz1jm5xzgs2lCVP\n"
+ "t5txApaBIA4=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 DRQ4MLOGosBbW8M+17klNu8uWVkPxErmmEYoSo6OuH2Tzrcs6sUY+8Xi2qLoV1SbOugJ214Htl0I+6ceag+vBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "DfdA+DbuN9nVJNujuSY5wNCDLk7Hfzkrde/sK0hVmZRvivtpF/Fy/dVQHHGNFY5i\n"
+ "L1cESAgq9HLdbHU+hcc08XXxTIaGwvoklcJClcG3ENVBWkTXbJNT+ifr7chEagIi\n"
+ "cVrtU6RVmzldSbyir8V/Z4S/Cm67gYAgjM5gfoFUqDs=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+const char EX_EI_ED_BAD_CERT2_FP[] = "7C2B42E783C4E0EB0CC3BDB37385D16737BACFBD";
+static const char EX_EI_ED_BAD_CERT2_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALAM1F/0XJEsbxIQqb3+ObX/yGVnq9of8Q9sLsmxffD6hwVpCqnV3lTg\n"
+ "iC6+xZ/bSlTGLPi0k8QLCaTmYxgKwmlMPpbQZ4kpZUrsb9flKdChMN7w8hd48pY9\n"
+ "lu8QiAEgErsl5rCCJIHHjrxxM/Cnd0TnedRnj/Z2YqpNx/ggsmsRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_BAD_SIG1[] =
+ "extra-info vary 5AC3A538FEEFC6F9FCC5FA0CE64704396C30D62A\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AbPp++GrRb6WphSu+PkMaYsqY/beiLBmtiV3YP5i2JkKAQAgBABKXjg1\n"
+ "aiz2JfQpNOG308i2EojnUAZEk0C0x9g2BAAXGL63sv3eO/qrlytsG1x2hkcamxFn\n"
+ "LmfZBb/prqe1Vy4wABuhqWHAUtM29vXR6lpiCJeddt9Pa8XVy/tgWLX6TAw=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 a7K8nwfg+HrdlSGQwr9rnLBq0qozkyZZs6d6aiLEiXGdhV1r9KJncmlQ5SNoY/zMQlyQm8EV5rCyBiVliKQ1Bw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "xhZX8Qmgft51NJ7eMd4vrESzf/VdxDrBz7hgn8K+5bLtZUksG0s6s7IyGRYWQtp4\n"
+ "/7oc9sYe3lcQiUN2K7DkeBDlL8Pcsl8aIlKuujWomCE3j0TIu+8XK6oJeo7eYic+\n"
+ "IA7EwVbdZsKsW5/eJVzbX2eO0a5zyJ5RIYotFNYNCSE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_BAD_SIG1_FP[] = "5AC3A538FEEFC6F9FCC5FA0CE64704396C30D62A";
+static const char EX_EI_ED_BAD_SIG1_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMvb6SuoIkPfBkJgQuo5aQDepAs1kEETZ9VXotMlhB0JJikrqBrAAz+7\n"
+ "rjIJ4JsBaeQuN0Z5ksXk2ebxtef7oMIUs37NfekLQHbNR0VsXkFXPEGmOAqpZjW0\n"
+ "P524eHqybWYZTckvZtUvKI3xYGD6kEEkz4qmV6dcExU1OiAYO9jrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_BAD_SIG2[] =
+ "extra-info coward 7F1D4DD477E340C6D6B389FAC26EDC746113082F\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf56AZkSDiFZ1QaiLJhcKdFDE5Kei/sPaPEIEoPMGP4BvOVXAQAgBAAlRLzx\n"
+ "U029tgIL9BRe47MVgcPJGy48db6ntzhjil7iOnWKT70z2LorUD5CZoLJs72TjB6r\n"
+ "8+HYNyFLEM6dvytWZf9NA5gLdhogbFcUk/R3gbNepmCF7XoZjbhPIp8zOwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 yfV+GySMIP1fw1oVa1C1de4XOWBqT4pUtEmSHq1h+WrLBNCh3/HZWvNC/denf2YVntuQrMLCJEv5ZaFKU+AIDQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "g+BWq69i9CP19va2cYMAXCQ6jK3IG0VmNYspjjUFgmFpJKGG6bHeOkuy1GXp47fG\n"
+ "LzZ3OPfJLptxU5AOQDUUYf25hu9uSl6gyknCzsszFs5n6ticuNejvcpzw6UfO1LP\n"
+ "5u+mGJlgpcMtmSraImDZrRipmZ3oRWvEULltlvzGQcQ=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_BAD_SIG2_FP[] = "7F1D4DD477E340C6D6B389FAC26EDC746113082F";
+static const char EX_EI_ED_BAD_SIG2_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALzOyfCEUZnvCyhlyMctPkdXg/XRE3Cr6QgyzdKf5kQbUiu2n0FgSHOX\n"
+ "iP5gfq8sO9eVeTPZtjE7/+KiR8aQJECy+eoye+lpsfm3tXpLxnpOIgL4DlURxlo/\n"
+ "rfCyv30SYBN9j62qgU9m6U2ydI0tH7/9Ep8yIY/QL8me8VAjLbf/AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+
+static const char EX_EI_ED_MISPLACED_CERT[] =
+ "extra-info msselene 3B788BD0CE348BC5CED48313307C78175EB6D0F3\n"
+ "published 2014-10-05 20:07:00\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AWBcqjzLESDuLNGsqQ/tHn32XueXwj2fDlgEy/kQNVf/AQAgBAAFOegg\n"
+ "XY1LR82xE9ohAYJxYpwJJw0YfXsBhGHqfakEoBtSgFJ3cQAUXZQX4lX6G8IxAlQB\n"
+ "7Rj7dPQuQRUmqD1yyKb/ScBgCa8esxlhNlATz47kRNR38A3TcoJ4c1Zv6AE=\n"
+ "-----END ED25519 CERT-----\n"
+ "router-sig-ed25519 Q52JKH9/iMsr1jIPlWHHxakSBvyqjT1gzL944vad4OhzCZuNuAYGWyWSGzTb1DVmBqqbAUq73TiZKAz77YLNCQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "YplvAIwExGf5/L8AoroVQXtGm+26EffrxKBArMKn0zS1NOOie1p0oF/+qJg+rNWU\n"
+ "6cv3Anf188EXGlkUOddavgVH8CQbvve2nHSfIAPxjgEX9QNXbM5CiaMwgpCewXnF\n"
+ "UoNBVo5tydeLHVns15MBg/JNIxUQMd6svMoPp2WqmaE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_MISPLACED_CERT_FP[] = "3B788BD0CE348BC5CED48313307C78175EB6D0F3";
+static const char EX_EI_ED_MISPLACED_CERT_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALTwNqhTprg1oC6bEbDqwIYBoER6prqUXQFbwbFDn+ekXhZj8vltgGwp\n"
+ "aDGl9ceZWDKfi+reR6rZXjAJGctmv0VHkfe7maUX4FC/d2T8N8DvS+3IvJzFMpbT\n"
+ "O0fFrDTrCSnPikqFfQWnlP8yoF5vO7wo0jRRY432fLRXg9WqVzdrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_MISPLACED_SIG[] =
+ "extra-info grazie 384E40A5DEED4AB1D8A74F1FCBDB18B7C24A8284\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AcGuIBoa6TBqD8Gg5atcwp/+r9ThxIBkULmPv9OSGhv+AQAgBACXH13y\n"
+ "mUvdpcN6oRN1nX6mnH40LyfYR5um8xogJZk3oINse5cRNrfMgVWiBpDlJZAwlDDa\n"
+ "lx99hzuZBong+CiOcnEvLMsBaVJmNTm5mpdetYclZpl0g8QEXznXXeRBMgM=\n"
+ "-----END ED25519 CERT-----\n"
+ "router-sig-ed25519 TxuO86dQ3pUaIY2raQ3hoDBmh4TTPC0OVgY98T5cf6Y+sHyiELCkkKQ3lqqXCjqnbTLr1/4riH980JoWPpR+Dw\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "kV2CtArl1VF1nUSyHL00mO3nEdNxlQU5N7/hZNTd+45lej5Veb+6vb4ujelsFERJ\n"
+ "YoxwIs6SuKAR4orQytCL0e+GgZsrg8zGTveEtMX/+u//OcCwQBYEevR5duBZjVw/\n"
+ "yzpEHwdIdB2PPyDBLkf1VKnP7uDj059tXiQRWl7LXgE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_MISPLACED_SIG_FP[] = "384E40A5DEED4AB1D8A74F1FCBDB18B7C24A8284";
+static const char EX_EI_ED_MISPLACED_SIG_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAK0HgOCG/6433VCrwz/vhk3cKmyOfenCp0GZ4DIUwPWt4DeyP4nTbN6T\n"
+ "1HJ1H8+hXC9bMuI4m43IWrzgLycQ9UaskUn372ZjHP9InPqHMJU6GQ7vZUe9Tgza\n"
+ "qnBdRPoxnrZzUOzlvatGrePt0hDiOZaMtDAkeEojFp9Wp2ZN7+tZAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+
diff --git a/src/test/failing_routerdescs.inc b/src/test/failing_routerdescs.inc
index b49d59fd8a..e2b72c58a0 100644
--- a/src/test/failing_routerdescs.inc
+++ b/src/test/failing_routerdescs.inc
@@ -666,3 +666,904 @@ static const char EX_RI_ZERO_ORPORT[] =
"wgFKhHI/49NHyWHX5IMQpeicg0T7Qa6qwnUvspH62p8=\n"
"-----END SIGNATURE-----\n"
;
+
+static const char EX_RI_MINIMAL_ED[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf5iAa+2yD5ryD5kXaWbpmzaTyuTjRfjMTFleDuFGkHe26wrAQAgBABFTAHm\n"
+ "hdZriC+6BRCCMYu48cYc9tUN1adfEROqSHZN3HHP4k/fYgncoxrS3OYDX1x8Ysm/\n"
+ "sqxAXBY4NhCMswWvuDYgtQpro9YaFohiorJkHjyLQXjUeZikCfDrlxyR8AM=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOsjlHgM/lPQgjJyfrq0y+cR+iipcAeS2HAU8CK9SATETOTZYrxoL5vH\n"
+ "1BNteT+JxAxpjva+j7r7XZV41xPDx7alVr8G3zQsjqkAt5NnleTfUREUbg0+OSMV\n"
+ "10gU+DgcZJTMehfGYJnuJsF4eQHio/ZTdJLaZML7qwq0iWg3sZfBAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAK9NjRY7GtAZnlxrAZlImChXmGzml0uk2KlCugvju+eIsjSA/zW3LuqW\n"
+ "wqp7Kh488Ak5nUFSlCaV9GjAexT134pynst8P0m/ofrejwlzl5DHd6sFbR33Fkzl\n"
+ "H48zic0QDY+8tKXI732dA4GveEwZDlxxy8sPcvUDaVyTsuZLHR4zAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key 71DgscFrk4i58O5GuTerI9g3JL0kz+6QaCstAllz9xw=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf5iAUVMAeaF1muIL7oFEIIxi7jxxhz21Q3Vp18RE6pIdk3cAH5ijeKqa+LM\n"
+ "T5Nb0I42Io4Z7BVjXG7sYVSxrospCOI4dqkl2ln3BKNuEFFT42xJwt+XGz3aMyK2\n"
+ "Cpp8w8I8nwU=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "lAZwD6YVic61NvJ0Iy62cSPuzJl5hJOFYNh9iSG/vn4/lVfnnCik+Gqi2v9pwItC\n"
+ "acwmutCSrMprmmFAW1dgzoU7GzUtdbxaGaOJdg8WwtO4JjFSzScTDB8R6sp0SCAI\n"
+ "PdbzAzJyiMqYcynyyCTiL77iwhUOBPzs2fXlivMtW2E=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 Oyo/eES+/wsgse1f+YSiJDGatBDaiB4fASf7vJ7GxFeD4OfLbB7OYa4hYNEo5NBssNt/PA55AQVSL8hvzBE3Cg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "wdk26ZtS1H81IxcUThyirANLoszrnYYhOMP57YRAUDEzUr88X6yNDZ5S0tLl+FoT\n"
+ "9XlEVrpN7Z3k4N9WloWb0o/zVVidPMRVwt8YQakSgR8axzMQg6QhQ6zXTiYhiXa4\n"
+ "mawlwYFXsaVDSIIqYA2CudIyF3UBRZuTbw0CFZElMWc=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+
+static const char EX_RI_ED_MISSING_CROSSCERT[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AfsyyHhGluzfESzL4LP8AhFEm83+GkFoHbe1KnssVngHAQAgBABNzJRw\n"
+ "BLXT3QMlic0QZ4eG612wkfSRS4yzONIbATKLHIgyzgGiGl4gaSX0JTeHeGfIlu7P\n"
+ "5SKocZVNxm1mp55PG+tgBqHObDRJRSgbOyUbUgfOtcbQGUeVgUlFKWZ9FAY=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMqT7K8cEzWIaPNXbNgvoZ5ejavoszI2OjW9XXetPD/S2f+N7TfQXHBW\n"
+ "bnjpgj87gmk59w0OXTMCv+XofZ0xOy2YR/jG5l1VJIvqgJhhFJ8oSEGVzy+97Ekn\n"
+ "Lb1FEYuVfVxSxnU2jhHW6KPtee/gvuyRI/TvZuwmYWxLRpikVn4pAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM4nITNe8UykgsIuo5czSSSl3Okr1K+UVWTzDGLznDg77MkLy7mydmk9\n"
+ "vf51OB+ogQhozYKIh9uHvecOzY4EhSIuKhui4hNyQklD9juGoW7RVTSpGdYT1ymp\n"
+ "dDYS30JBPwCZ7KjdMtXiU8ch2WgbzYBuI+JfjwOhfcsuNC9QPfbfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key lx8o212IYw5Ly2KbH2ua1+fr4YvDq5nKd7LHMdPzTGo=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
+ "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
+ "mjQFK4AtRwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "cv1yL8HhQzQfjzkSosziu2kMecNUQGle4d103h6tVMoZS1ua1xiDpVKeuWPl9Z0+\n"
+ "wpFwRkOmK0HpNeOXCNHJwfJaWBGQXunB3WQ6Oi1BLilwLtWQixGTYG0hZ6xYLTnX\n"
+ "PdSQIbsohSgCzo9HLTAgTnkyBgklIO1PHJBJsaNOwfI=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+
+static const char EX_RI_ED_MISSING_CROSSCERT2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AXXgm0CUWQr+rxvgdIslqaFdBiwosT+9PaC8zOxYGIsZAQAgBAA6yeH7\n"
+ "3AfGIGuDpVihVUUo0QwguWDPwk2dBJan7B0qgPWF5Y4YL5XDh2nMatskUrtUGCr1\n"
+ "abLYlJPozmYd6QBSv6eyBfITS/oNOMyZpjDiIjcLQD08tVQ2Jho+WmN64wc=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMdyTK/VPZloLUaLsvj1+NOFs33/E9HmA0VgvZ1nNUrR+PxSR71QF7Tw\n"
+ "DKz+/p2rJE+MPfQ/Na3dH0vH4CDZ+FH2m4A8SB9emF8aKxdc/7KCjQNDQCNlEQYn\n"
+ "O9WvZJhbNPHUmX0z4OotI+Sk3qBzVHu0BGDsPYC9gwszIumDUILxAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL8o6CJiLfW4vdRFvJ2nFt/H/ei0ov83rilOuwSmNORmL9lvnHY++HrD\n"
+ "dmEEvBv74xqWJxGbJ6OQ3VOwRpf2X/cb4gAvsQDqDmNwpJsrPYRQVXp/KY/8z7bJ\n"
+ "dM4CjcsuJHHmj3yc3iCzgqt/Xr6vR24X4bee12/bP7R8IETvWoiHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key qpNEGrLMVn28Odonk/nDtZq1ljy0fBshwgoAm4X1yzQ=\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "i4RKGIeaUrO6nzfdtb6j+ijYJh1Vgc9bsHMpW9cVCOjoJKFW9xljgl9xp6LytviN\n"
+ "ppKYCt9/JflbZUZjny34ESltPGrdquvHe8TtdQazjiZBWQok/kKnx2i+PioRF/xI\n"
+ "P8D0512kbJjXSuuq9tGl94RKPM/ySGjkTJPevN4TaJE=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 pMAOpepn5Q9MxcV9+Yiftu50oBzBsItQcBV9qdZCIt3lvSFqFY9+wJjaShvW3N9ICHkunrC0h/w5VEfx4SQdDA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Du5fJYDzvEeGqKTJwgaQsJJgz39K/J4qEM2TZ3Mh0XuDM1ZWDtjyzP03PaPQqbJ1\n"
+ "FsN5IStjOqN3O1IWuLzGaZGpGVuqcyYOxjs7REkGQn2LfqCjpzjaAdcsL0fI4ain\n"
+ "o/in8GQ6S/qhsx8enKlN0tffTmWmH9bmmVz0+yYmBSo=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_MISSING_CROSSCERT_SIGN[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AfoVFYuJnDNBWbjbTqfXACUtXWPipmqEYC++Ok/+4VoFAQAgBADH7JzI\n"
+ "fjSMV158AMiftgNY+KyHYIECuL9SnV3CSO+8+I7+r9n+A3DQQmGLULo/uZnkbteJ\n"
+ "+uy6uRG4kW0fnuBlKhseJQm9hjNGWzC8hmebp1M+bxwG41EGI7BZvnTrRgM=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALEqlijoFIDX1y1i5zfei8DuDIsFtSw56PGgnMRGcybwD1PRQCheCUZM\n"
+ "erQgFCWjgLgvGJERBK/oILW1dFXp4MAR5RgnrPGTfWTinCj32obMLN1gIczpq6a9\n"
+ "P9uv6Cz0ApSxpA/AuvjyAZwQKbUXuMvIY4aTprAKSqqVohk6E+E1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMZbbBjGV7xPri4XNmejq4add93p+XsWlsfbM930bcC2JZiwg4g4cq6W\n"
+ "idl8VDmCXeaWg5y3kb82Ch/Q9vPG0QYQbXxUA3JxQKKbcEK3QsEvqQh8Nb7krILK\n"
+ "YnSGAnLG2Nc3PnKb7Wpb8M3rAysC5O99Gq1mSfm8ntj3zlIM7NSHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key CYcpfIF4T9PJcfROfVJTUYl0zNd4Ia5u0L9eng/EBSo=\n"
+ "ntor-onion-key-crosscert\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AcfsnMh+NIxXXnwAyJ+2A1j4rIdggQK4v1KdXcJI77z4AMRc2LxiKbyr\n"
+ "fqRVynHuB031C4TN/HAlNPBjVoRvQRgzpiyyoyCqMDxLZdM8KtzdLLeqZJOXtWod\n"
+ "UXbYG3L70go=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "BRwRAK2lWxWGS49k8gXFHLEQ/h4k8gOQxM0WgCaN4LjAOilLHFjsjXkmKgttVpHl\n"
+ "f0V9ebSf+HgkpQnDSD8ittnr/0QaohUbD4lzslW4e/tQYEiM46soSoFft85J6U3G\n"
+ "D3D63+GmaOfIaa4nv7CD0Rw/Jz0zTuyEuARsdJIr1IY=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 7XfV5r7FXbXPEvrxlecWmAJxat/6VT+/4tE5cHrQnvLM4zslysstWH6/AfIfcmUuDlQ0watmfg1MvVnjavcfDA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "eigLL3S/oMGL2tJULt9bl3S0iY+YIxdKeGFCcKZci59zD786m+n+BpGM3yPpvrXr\n"
+ "bGvl4IBqCa1I+TqPP1rM9lIEcUWaBT7Zo5uMcL1o+zZl1ZWPWVVKP5hC5ehDueu8\n"
+ "/blzNhTEFAp23ftDK9PnFf+bXxqbgKkEoZsxnd3e9Ns=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+
+static const char EX_RI_ED_BAD_SIG1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AR8QC+SNBpPOTVY198IQBANNwZjy+SBqQNxfzjEmo204AQAgBABjz4FP\n"
+ "zW/G+fu7YirvANvvqJeb7S1YYJnf6IrPaPsPRzDqJcO3/sTzFC5OSb9iJmzQAWnn\n"
+ "ADPOl+nOJC58XJnJ7CUJdPtyoVdMvUiUT/Jtg4RuCN1iDaDYaTh2VavImAY=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKuLC0kzCBTV6+WPZcAOQPKjqbjvMIyaehIQS1o90dYM+Tosrhtk3bw8\n"
+ "QBLMaiWL3kfIWPZuWi2ai40dmqAXMrXH3yBgKRNZ6zZSbUUuJ1IknqmrQ2PKjC/p\n"
+ "sIW2awC6Tq+zrZ7vntDb02zY857vP59j8eolTDg1Vvn6l2ieL+WhAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMnBQPOJBQLZ3NAa70n6lGZGvS3DYZFNOZ2QnHVeVvOSFIFsuvHtnUdX\n"
+ "svDafznYAuRFRVqJS2xtKKGu0cmy6ulEbBF+4uAEMwQY7dGRPMgVF1Z33U0CSd08\n"
+ "ChCJGPTE7tGGuoeSIGN3mfC4z2v9SP3McBdAiLHisPzaUjfRTcwRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key W8fUvBpKBoePmqb70rdJUcRT0NhELDWH7/BSXJtkXS0=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AWPPgU/Nb8b5+7tiKu8A2++ol5vtLVhgmd/ois9o+w9HAAPwWqmL0HXa\n"
+ "bYKrKPWQYnpQHQ3Ty0MmCgj3ABF940JURnV161RlN8CRAOJaeQ0Z8wBRLFC1NqLT\n"
+ "+GVdtewGeQA=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "x0vT5Wv7Guc0/Vu2BqomWwenh8oda9+8K/7ILi5GQL/WC29Tj51i0EE7PVSnSMJ7\n"
+ "33I/V+N5neauqWnbg7TxYaLsPfr6SpPTpBL1Xt0OiwT1//PvPYZ1gCcF3ig3KcfI\n"
+ "mreQd5C5Vri6ukWkMtz/zNDaDpDanzaNXTdaUXmFHF4=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Hci/Br1+NNymDZBmQy1QWMlCeLe8Z1vtZ2ZTj42jDhWg1OC/v72ptI072x4x5cmi\n"
+ "X3EONy8wQUvTNowkfG6/V/B768C7FYJYBId1GAFZZymXnON9zUYnE3z1J20eu6l6\n"
+ "QepmmdvRmteIHMQ7HLSrBuDuXZUDJD0yXm6g8bMT+Ek=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_SIG2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AW8fyx54c7vQQA/AmShAitFP7XI1CLdifEVPSrFKwYq6AQAgBAChqjVA\n"
+ "/wKKJZ30BIQoXe5+QMiPR6meNxF1lBttQ2t5AhauZbH5XzRhZkdGo114wuyPNEM9\n"
+ "PrBwp5akTtari9doVy6gs3McqdoIbRdWevpaGj5g5oOEOtA9b5UNWQSwUAs=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALp0Croi9zhpGxi9sUj54jr/flZdzxVVS+8VNldJG2c1soSx8kwlwotu\n"
+ "7mGGudJDAzDHGo5F5CCPEfQov2OmDehpefYUz/AaMLly6PrLRJlcUcpLogGf1+KU\n"
+ "1lLwE8kanXUkgvDhVQiFvNjy2Dxxuv3AHH4WdZZfbMbm8FJRGoHzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMoI9vQT4g2sV2dViGOWOzxckk367T9sMjVwcYfJCmnixGxjWeKScQFB\n"
+ "K9v1uK73cfZR8AxiUGK4/iOX/9en14mJOGF7fftAqypFLAt1TBvb07IgXljOBoHc\n"
+ "Paw4oZoJQzEoazt0Oa181LyNnNIoaZpHVZd1+a1Gs1gKoM4xDBv1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key KjyvXYkMcpke5ZsUYf2gZAUNeEoz8NAwYoQvvbcDGiw=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AaGqNUD/AoolnfQEhChd7n5AyI9HqZ43EXWUG21Da3kCAI6MRHm7GpCF\n"
+ "/3zDGR/6jKe625uFZX9HpLt6FgAdGSJeMQ9W4Np9VkrFXAB3gvh7xxRzSgZ1rXgR\n"
+ "lUomgi7N1gc=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "xJXvCCpP4ExBuT3OTsdn2HJB0HidupmQq5zBh8fx/ox6+047ZBOM7+hVxxWapcMg\n"
+ "PMXbcLD4L/FCBpA/rjnFUE/9kztdq7FH/rOdi0nB6FZWhwDcsZuyfvbnDTxz5iHJ\n"
+ "87gd5nXA5PE649SRCxW5LX0OtSiPFPazu4KyyBgnTIM=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "tk4kBNYqB8utOmX30HrV8YfnwBXYODIiL3M/juRS6nPn0uvbW7pjoZ3ck/ahgW+6\n"
+ "FNQsgTJnEADCWS1r6v7PcvzQjtrOUUpNxGJxYw1r8yZkvmIxSQD6GMzuTxq7o1VA\n"
+ "/wZYDLonLhCWRdPjxnrl12+z92NdyISJCHMLRVqs2QY=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_SIG3[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AYYiKZrFWZ/Cj5mZbfK11MZHYbwchllsUl4qPqY9gfi6AQAgBAB4irxT\n"
+ "86FYA0NbZssSTmfyG6Edcf0ge61OwB4QD35kHCrvuZk2HnmL+63Tj4QoFqIVnwVC\n"
+ "3wRGJGcmS7y+vS64GUXbuyTgqgpl/KuoHo5Aqe6IxJlVWYtU6W0M6FV9tAM=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMUEvXTVTl5xkQ2MTEsB4sXQ3MQkz8sQrU63rlqglpi1yUv24fotjzvE\n"
+ "oJpeKJBwwg5WBW/fW0bUDJF2cOHRHkj/R4Is3m+2PR1Kn3UbYfxNkFkTE11l099V\n"
+ "H6xlsi0TJOJKlgrcbSuB7se2QctZVhwsdsJvFRptC9Qd+klAPb7tAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMooTeSUX7GPoyklSd1/6cF1u8e2LbjOLIpZrMon0Xt7c/aNwlrG9rVo\n"
+ "TSokHs3AQ2H2XIceySVRRWR4AdX9KApO4CX0gGTuVUmq6hFJWMnHdAs2mKL0kt1w\n"
+ "I+YWzjUqn4jIVa2nMbyHVQWzIysWwWiO4yduIjAYpBbWd9Biew4BAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key BN0I+pLmFkDQD5iRsdkcped4eZwGIuXnLiX2K0Zoi2I=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AXiKvFPzoVgDQ1tmyxJOZ/IboR1x/SB7rU7AHhAPfmQcAOrIvaG/xJqe\n"
+ "adM6mai+FlV8Dbt6QrXTcNHJU1m+CUDthA9TPTAYz9D8W0mTEQ6KEAKGfQrNLy2r\n"
+ "G1B+9wWSpA4=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
+ "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
+ "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 abcdvEzGFYMcJ/Ea7sbessW1qRJmnNNo2Khkkl0rEEgtLX0b4L4MMhK/ktS52Y6jX3PRQWK5PZc6gjV7Jaldh+g0Aw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Vyj7g3eQ3K4+tm49fJkAtsAYnYHcEiMnlucYCEPeKojzYStNfZwQO2SG5gsoBIif\n"
+ "urgQZ/heaF4uiGFg64UFw08doXqQkd5SHO3B4astslITvmq0jyaqzSXhdB5uUzvp\n"
+ "QCR0fqGLVS1acUiqGbRr4PiZ9G7OJkm230N3rGdet+0=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_SIG4[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AaEnncX/t0cbLm1xrtlUpkXghaA8fVuV7g1VF3YNfCaIAQAgBAC7Ki3S\n"
+ "zzH9Aezz5X4fbwHeF+BQEDfVasfyTxTI4fhRi7t3RxHzBJd60uEMXy2FchD8VO5d\n"
+ "j4Dl7R4btrohPVSVBQZuemBQSW6g3ufNl0txpFWu0R7vBPTFH6oyXYfY9gQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALGKwzhOui2/jJPjU1ngW5IZRPcoDk7RAfGDO4xaef4VfAFHCV9CQO1c\n"
+ "/wQ09CcRdggTvUcv9hJTGJhSObUUooCkxw4/35f/A6/NoW1Gi0JqF9EsQWHpuAfr\n"
+ "n/ATlJQ9oGdTCNDq/BXSPWXhoI6UhUe0wiD4P4x4QwaYHcZh+lE5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOKrizVm2h5/jE/HqqLCBLWJZVVoGspasCtDDqHhSqsPzyjpqa52iMKi\n"
+ "q/deJ92le3J2NJRGKxPmPQqWxwhIjnMS5kUMoW182iLpO/G9qyPZ0dh6jXB0NBLF\n"
+ "ySfW6V2s3h4G4D2P+fqnsnzQnAX7YufkvgDau/qTWi2CqD0CjavDAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key A9h8jY9dPbhHTDbIc/NYWXmRP65wwSMrkY1MN8dV3BM=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AbsqLdLPMf0B7PPlfh9vAd4X4FAQN9Vqx/JPFMjh+FGLAN8xr/w3KFVi\n"
+ "yXoP/az6hIbJh0HYCwH8D1rPoQLcdpe8XVwFSrHGarZesdslIwc9dZa/D1dx3OGO\n"
+ "UhJOrdv51QY=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "bLmdO7ME5vq+c9y/Hd8EyBviMBTeo85sHZF/z6Pehc3Wg3i1BJ8DHSd1cK24Pg48\n"
+ "4WUrGTfonewuzJBDd3MLkKe6epXmvUgvuQN5wQszq1+u9ap/mRf6b3nEG0MHxMlO\n"
+ "FLx5MBsScuo+Q+pwXZa8vPuKTtEjqbVZivdKExJuIX0=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ " router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "LqNGEa10zwSPeomBXTfgvBnnWAdWyiR7KYZq9T++jK4ctR6hUaWngH8qSteUrkMx\n"
+ "gyWb6UMmlxdfOG0sdcU463HsqV7zObaKya8/WwQ9elj3FfsToswUCeOaLR/Rg7wC\n"
+ "zcUjI5VsneQoXT2WVZbZBLsLB3+7QfezVHRMB377GAY=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_RI_ED_BAD_CROSSCERT1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AV1AfOvQWKlWsbzoBdJc5m72ShIJuA8eNV15basjhXYdAQAgBABy+KQK\n"
+ "3oLDGtqL5kwRmjAsls/+C6SAoAALll7U7wNSH7en5RVBal4RUzCf57ea/KG0c9V8\n"
+ "2DmZ3PdOt2aY/M2bWGmmH/tyyapOoV98dhDwFU7zcx/pMfRnJTDRSDwl8QE=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMP6xbqbj+x1mq5XImjeT0rUzqKZTgBd5zvK4Xcy9IifJuFC9+mMzrY4\n"
+ "WhYbdClxKUkDMkit9MVhek+P/w5TSHKl6AuqGaO09ID+hZpoUSdoBUYktynxfGsx\n"
+ "kIDu0XvgtAeSyJaVvoV1SKVChY0IBbzUqbHt4O2Q1BhzFCKEJTEzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANwWlBh7e/eSLlhto5YUdj1iGYOq+yAmlosDItVfYrSPJuUfM2ocMBAn\n"
+ "udbRbWiADoqsbKn/gwwHCC/f1HX2FkRXxxnOlJKLo+NEi8tGmOlcQXSQol1pCpvK\n"
+ "sA9TxtYr+Ft4LRpxNrexF+pIBxqzwetqQrZbKYr0CFJi8q1qlMynAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key cs1AP+xF5cXTLuKeOeItdoDAzfALTJkwk9lB4mtC4QI=\n"
+ "ntor-onion-key-crosscert 3\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AXL4pAregsMa2ovmTBGaMCyWz/4LpICgAAuWXtTvA1IfAKo6ANUq+hi+\n"
+ "xb3J4aYafnszlj87oi/DR+SDf29wzwNw8gmaqGzJ5GbfISfABuTUCzlilZyVnLxi\n"
+ "BHcCH6PWiAQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "qC9Kph/kGtONR2DxZDoIFFgnDFC+/7H07EgCiYQdIFIROc+gGK9qBOgeFEptrkXF\n"
+ "XdE35xxox5xSASQvp7hjFwxUtJRGOtf2O98regqeeaz6O9VPXHkLf51uqX3bVgq8\n"
+ "KvFAsFFS66GxhtbrVjpyRgIwHAYvse1WVESfLuZZTn0=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 3uW8Q1aetIQLOsqSco128ZUaHlhqdYiBvrxV7x75BGNS5RzIMTEwYDNtEX1LNPFJ5N0YOV0HEEOLhrJUV9QCBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "WuD7S/saTYBxKvItITbHRi8n+e6g/oVbosicfbRbafYPzPp4Prb+RK03UTafzXrV\n"
+ "QEQIzDNhfePcIMH8qX+qrogLMXFqiXx6TVQ0GqNvqirokk8ar3AgtRtewhChAuAj\n"
+ "8pmQTj2JpZn/iB3PCE2l/93O9LHZfp44hc8QOWKs6BE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT4[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AW5TTGF9jCMl7aALZzqypD9Bj8WYnAPIrKCoIJdgMbY0AQAgBAB7eCn8\n"
+ "rukx7t/egZUdqU7+FYqsnO4wdmOkLZkp0+gpF3jjk6N1Q0037NNVNZBjONB0Nm2F\n"
+ "CpB3nWSJliSSKr5tOYsuBPFy5VVGYeKPakpOoxanQ1UcqevMBAQy0zf9hwA=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALeS5YbeDuKQ5iiuUvh3REoyJ47/YU9lslWmTrVBf9b66pMnYJv/awPu\n"
+ "m2HredUAJ3VzwQ38VJA39w3fQXUhQDnQ0OPpKzeAmIiuG+6WdW/mBSK7uKcezC23\n"
+ "LA1d6Afyl79LjZz/n+ENXqNMlJk4QPcPHuRnAvwBl3t8YVRPJmxhAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPprokY7utWuO/0252dBB5MCxmVD/dROaIBDyFtpdH+YVv04rkOlDzYD\n"
+ "W4mgHVBMxEm/cspTgQmJ4exRHJPpcSe1RYHt1ONZdLYr6D7OOWf0y1IUrVSzF6K4\n"
+ "lqlmNuH1H4+TKGbkvixYc5GU/2ZmAy6gFEuphYnBbsN2Ywc38mnfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key Cgo6xniGfEiuYoLSPUdE4Vb2D4zj2NQzC1lRjysRRXs=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
+ "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
+ "mjQFK4AtRwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "bi4M/AJLZF7/vSNmOj4uhrgKBQA/KfcZy5e58mhGL4owxd9vaWfl3aelvb9jf9zN\n"
+ "Q7FMv8f9aXzeVIoXIpRJxSKIJgBtG2wnMumIc80pqBvTyGInharszb6njfm0bg1u\n"
+ "PfJkbQYyf/dA5l5UwCrjFs06ImDmjFTAdsSWf6DfZ/k=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "io16v+e0pK3sbFzPGnkQrAjrRgIOJHrVZ1RXcxZ1+UNXagWM/MOLhQpkU/cw49Wd\n"
+ "4rQeZD3JQh16330eXbxc97AyDgp0b30He846SI0MfW/DnmGI8ZNeYfLbMv2bmbs9\n"
+ "QULzyIH8C+5mnMI1arcuiAua+Dpa34F79vgqPuvw5fU=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT3[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AVB+j+B2yPgGywvp7nvejyhMh9ejKmw7LCwufV83Zl9eAQAgBAConA3B\n"
+ "jJ3X2tES40jd94rRUFS2/s/Yv7E4LEQ9z0+jz8horNivzK3O/t7IGxJggi+b41/9\n"
+ "Uaqt+wqtVuKj0xJ9jwBlCXFt28G2P9s4ZyXYgGZqo7MlJlboybnOMvmoTQA=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPWuEWckT4aYAVNrZzLA8xVwfXp0wzfXeTWBztLS8VzssN6w/+cwXdeY\n"
+ "N1YNc2DiD3u8f+7kmuZIqL1EFQUwTvRwEzQXm2dqGM7qkm5ZGNMb5FKu+QwO2ImI\n"
+ "FLNiO5zO/LqP3cf/2L8/DuvruLenUrhRtecGFaHmhDYl+2brHIiPAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMtHTfk0gDvp9+PtIG8Ks7rgCiJZ2aihSvr6WaKHYuIprgspFuga98cg\n"
+ "D//J80CrgH5Dw68YnkG+gU40IxP7YzhQ4glFlJGu3s2y7Qazcv5ww1XtHur+GDoA\n"
+ "cY0zCLhltNQFxIsoVUepY97XA6Y2ejYJjyqNXQcAmoPNoVhnTdkhAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key ibZf57LptdOK3WpVFXkYMatEEqPhuVWxsnkwF6638V4=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AaicDcGMndfa0RLjSN33itFQVLb+z9i/sTgsRD3PT6PPAEbkxCdI/bH/\n"
+ "B06DAjRuoDiv1HKsGuW+UN1iGEiWu2ieFzf3m0Z7BL9p2u2zIbHYkP50b3T3sebD\n"
+ "1AksemmMdA0=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
+ "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
+ "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 XS4zVi46Xl3xKhuozPCDlW0QRFD4qUhJmkefonQNsRlMVsrPkALnP2tfnfdfTc69hbNa22pOjJNf6Gm505EnAw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Q+R3OpO8VhfvFbXuE5qolhVbgosBHy2A5QS91TMzCbsxa8pBA6Li4QdPR37wvdLq\n"
+ "KayfmmNCMKU5qiZMyXqJZm4fdpxiSi50Z0tYlXM3b2OVfza3+pSOEBl89fN6G4Qc\n"
+ "pAmM14eEo1UzXrqZw76tMS2CwOYF5vR2xFGCYC0b5hM=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT5[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AaCfOaispi7dJhK0c8HXJHIwoBkMgRpmmHu+3Zce/soMAQAgBAB5bAIo\n"
+ "5i4TSY/bV2KQAyziRwvgJm+nEiECClflPbP9Um+zOzOgxtDmNnR5UFQj+VWNG4uf\n"
+ "5lnaryN+PfUXZMTcs8AARof3fFz9tVPINHDrsGvKt8gpzgZEHkVioAXOFwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL3Fr/ovZ9SMGYrAM24taKBm/NpemZaXdD/JeBXFYm5Zs3szLwJC4Etm\n"
+ "zjNL6tVy+I21O1g3cs16TkflcidsjPXNx//PHAn7bqWMekjrt3SQdkHW2gDPgT2c\n"
+ "zYJ/hBR96JYG796jP3pkfJz6Iz5uT/ci3A/cdaVbzM1uZbMUgYGzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMHB+1dWa8BBrKE94vTqfbkSEuysG5LyyZF/WrqHq/3W+ocDLz795k8O\n"
+ "2Zvgr9im/Ib4hD7IyrtRexcuBdwujdG7cBALdCcWiUTGAMkl96HNETSX+lUVIpJ9\n"
+ "pMsc9O7+yz+/0Cl2RpILZCdE/7I96qHpZl3tzlRKSu15WeIm5U77AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key GXi0a2VLcRHQMMYys85zu3IPqOn5ZTsOixYyQvTGnQs=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN BUTTERED CRUMPET-----\n"
+ "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
+ "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
+ "mjQFK4AtRwg=\n"
+ "-----END BUTTERED CRUMPET-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "T9NHMBhuJo+TlfU3TztNgCc9fK1naNRwPOyoqr5R6lJvJ40jkHnIVOFuvuzvZ35O\n"
+ "QgPbyFcMjv6leV5xcW+/I9tWaBUFXiRGI27qjCFth4Gxq2B6B2dIcQliLXSvW9b+\n"
+ "CMTgDwVa4h2R2PMh18TRx1596ywE09YhCgBF3CwYsiM=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 sRpiP9kyW/DGOphp4V2VCtcKNA8i7zGuv2tnljNIPTB7r7KsTvdUk/Ha9ArRQEivO4nC2HHENtknDl3GtWIPCA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "DtORw3+gO/yUUIp70xDaWSOgQZrJAAoZTNCB7q5WCoZOngeaCiC1Gtc+Fmdn7tER\n"
+ "uPqQC5H/Kh3Mi82PCj0JxvNivnNTNY1AZVaIX5YoioXVOkWF0B2pqMvFuDSdm2oJ\n"
+ "29PqSVcklquu19EjJRTopIHvYn3sFhQL4LarMsYY11c=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT6[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55ARMMCtQ8pObC5bq02AUE9Lx2bqsZBBkeOsDZVaEq6JavAQAgBABtV0xF\n"
+ "CsWXL/uFIBnoEsnXBeU1MvYRFrj1vR7QHdWXnxywXvBYUAC8lu/uyc8qqLp+aQSJ\n"
+ "5JzpDYlg3hp1fl5k97iv5F9WrR6s554YpmgYy9agFaxZ4LmRgz7n0UJ8mwM=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAO5qd1TndKD2pEs1ZLWsHlvfO/E7cA0H7NKGLSioGpBf4P0rtkueX4ci\n"
+ "kJNa/4Fn/QsLECqEF2lUjkIc8YL+HMS6qteKvN8+nn16DfvnIhPDNZWTJjLl1bOI\n"
+ "sWSSiduhanoWQnhRtl3Rxg3opdNd9ApO0DLUNy4Qy18Ai6SgksfHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAJkMYNpK7eJJyGwD/xG/iNg6gzzbIwrOSvmtoP7Rot42qtBiQ9A9kdsy\n"
+ "sazwkWkM93U1+1OaAADPYxeHoyHnuia95Cnc5y2lFSH3I7gnGGSPKSTwXtdyvDWZ\n"
+ "P1LbmQ4Bnh5leTCNZ/eFC4/GjNVzqHxjbb8a11dQhA8dOk8PrUq9AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key HdSQOqvLr4YnJE1XzzVIddgKgnjaHKJqnq0GqF4wXDg=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AW1XTEUKxZcv+4UgGegSydcF5TUy9hEWuPW9HtAd1ZefACVwif1deQry\n"
+ "K5GeemRa32sGzujVDDe75WRiPKFT3l/EtjTq3oeVq2xwbVJklnG3ASejKTr3YcHt\n"
+ "ov0jOl0jywc=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN NAUGHTY MARMOSET-----\n"
+ "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
+ "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
+ "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
+ "-----END NAUGHTY MARMOSET-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 lNY8TRX/FZdH5eFbsBkFHuRi8bPDsE5P+v7zExyD/IXnKS/ffYlP8qw1XIPdEDOIzGQ14+kyPX0SotaAqHRtBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "BHamS+epF77iozo5cBt+tbs22m9GhwY55DRXpEWAtvn67jsMnmn7qCOLONigK1RT\n"
+ "adZNezIydcCxXltgHTdKaZw4lcqv3s0KL8kI8frbBmm7PjXtWnrdXBYY+YK54MN/\n"
+ "t4N3162o9hzzKSwye0gPjgzpQ1xtEIkzWhBcmE9Vw5s=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT7[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AfVmH2ReTyatl4VnS5YREtCM2dwikWuAPffq6M5bysZxAQAgBAAXoqE7\n"
+ "taqwLDXLZrZukpF1eBkCwYQK9uzctHTuMdqOHChguvkfX7V4H3O76Ayqvz+Z1ut1\n"
+ "KYRdgiArn3viRaBv3ZKT4Z75suMI3bjqGOSGLAKfOa0uLkOmKblHHhSUkwQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOLNugzUezzzw+N1SuQWzILJYkUJyQDoVXSZjT0dzBplHCjlrv0WZCUP\n"
+ "/pbonE7SlCChIovHcdiASaLj7MVaGgYDq3M1Vtgt5vhgGl10/+evBAD1QEt8AVfr\n"
+ "5+PH/sbZvOWucAhNUhOlqFKAn4vdRY39VEEXC5/Jz5fsk1E/DBu5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKxzg1hsYMS+0zAIrgYxSGO0GbKRrL/VhdlMEGu7ACaoqlGnmGQS3B4B\n"
+ "gLk8xDdx9N//8+YTx0hUIxP38w08lubPl1WXMq8s7wAiFd06Nklf65mHs0sXVtS1\n"
+ "EG3f97PQqmBpEJOwYBATNcA9e6F62P8SXNkpSjOzNaE0h9wHNKk7AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key msdr3O4W4bm/xdmZLzj35363ZSFex8yQxLWsV3wRCAQ=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "VQoABx54AU3MlHAEtgPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
+ "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
+ "mjQFK4AtRwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "RJJRiU0vjVtRi3bVZru3aTvV5l56X/WOOp/ii316yPAS3aAMpOm1+piFVR5MNqcB\n"
+ "ZGyrA2Kx0hawdL2buU47iZ12GOCi4f1Es4V4N0TQgJICsKX38DsRdct9c1qMcqpp\n"
+ "1aENSRuaw0szTIr9OgR7/8stqR5c3iF1H5fOhmTi6xM=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "F3ZqvsyL6RRhPEnNFFIZY4WJM7LK082rseWzRkGNXjwoEwOWUK8enQ4Wjit+wozW\n"
+ "4HVIY1F+vP7gm6IiOEAFgEpB4C8FGuyoFw2q0ONA2tqTcvBJDDnqbx08FO7v2Dij\n"
+ "d3ucfc5gf7YNaoFCMMuyAzC56eyNk4U+6cSKy6wnJds=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_RI_ED_MISPLACED1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKT6OIN6TsDB+xcp1uLeE0K3aiHGqa7hdxMBGpvcD0UFSyzpVv1A/fJa\n"
+ "tClDCwTpfTGbyK2L7AO75Ci0c7jf6Pq+V7L6R7o12g6WBTMrgsceC4YqXSKpXNhi\n"
+ "oudJyPfVzBfKcJUSynv89FUQOyul/WRRqWTfv0xUsJ3yjuOESfCNAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AbBV9NVz0Hdl0Uiv87LiXaTAoeSXE+bheNG4Dju1GzQHAQAgBAD16h+T\n"
+ "ygzSgPN4Qat5ITthvm+lvMwMVGbVNWMxNy9i33NGhgp8kqMp2iPAY+LhX8It2b+X\n"
+ "8H9cBmYLO5G7AlMPj7GsuWdCdP/M/ldMvFfznlqeE3pCpRas6W48CFJ+9Ao=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANMO/MepK3uCkKTLRCwIWc/8URVza2gEmDx6mDTJIB/Mw8U8VRDuu4iJ\n"
+ "v+LL3D8/HGLvT9a8OXbl5525Zszt8XueF3uePBF0Qp0fjGBL8GFqmrmFe6plurPJ\n"
+ "TfrS/m3q+KhXAUowmghciVGDY0kMiDG9X/t/zKLMKWVDYRZk+fupAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key I8yDO62Flx5O/QsFvgb2ArIRqwJLWetHMeZdxngRl2A=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AfXqH5PKDNKA83hBq3khO2G+b6W8zAxUZtU1YzE3L2LfAGC1uXxN2KwW\n"
+ "w4PqRidM1UPZ5jVOHceZYNQcTzzzArfBpr9OraOO2up4TGte8GVqjJNxrZc1gfjn\n"
+ "CwPW5WxpFg0=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "jLg3D3VO4i0sN8p2qtB6+5C3tai/K4M89mP7z2abQnUTbynOacPoNXIk4o64DjBJ\n"
+ "kaR42yfA7yQZ8Rj8abwgz0Zz6zbd+JjE+s/EklrEEtOl+jZAl3i+92FaHROJojXq\n"
+ "hw+ZEPOb9zgb1UQ7S1Fo+GoqA5bdGm/Wg1kSQielkNE=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 TRKvIl/wIIRD4Xcmd6HYmy7tD0KhVGgoStpWPtX0zmXGZ7+jugItrY0frDu9n82syiruuA45ZOs1Rfi4CbOSCg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "NYpRfurB1YhFmDAdRc2Sd77S7By2V/0kgEHpJhtySb7efiQsyOA4ZBr1zEFPAXdp\n"
+ "TviKzyS9kN2fnz3hORoqFul33BDZbiLMNLtt5tzp62TYtmIg9IZdjjczbJUgbVLt\n"
+ "KCJL0vM7fdbXkZX61GIBbMYwzwIiHvVxG7F/AS5RbtE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_MISPLACED2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AfJo9FIePrxeDNnWT6SWkoz0/L27018XjUNWEHfaR06MAQAgBAAMgolK\n"
+ "nLg3ZnVv0skzHCfmX+ZR9Ttwj7FNXfhXCsyr860S79OW5LD0/m1GcS9JflWhP+FO\n"
+ "ng5cRb+aqNc8Ul+/4sQudZRx8w4U3d5rOuMGCqhQXnktH9AFzQHFq0jpAAU=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPeK/znKLRvSUmCIUiZOgfhiRFt7XGN//C2GFuey4xkKiIr9LWMuVe9m\n"
+ "Wx39Ea2UGEtNGCEVvZdJMDVRl7heFTfJTN4L1YeyWx6iNRWlpAmgQOKII7slHwlq\n"
+ "seEULOLOXc9AsU/v9ba9G54DFbHfe2k44ZOwEmaQZW5VF/I0YMMdAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKFRzlrqPPxEW0nboAJ1qzKFb/vFtvRW0xNVb8RtbOY/NY5FV1hS8yfH\n"
+ "igtugkrOBmWah7cmJhiON2j+TKeBxEoXwJMZeyV+HLbr7nY/mFhad4BQ3Frkl8d6\n"
+ "1kQMhOJswMdwnnVHPNGUob4YAX0SpFA6MpBVj92zmMBeaihqUS9VAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key br8svioLcJCAQxoo3KvlT288p8rb4lQIZNLlplkIKkw=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AQyCiUqcuDdmdW/SyTMcJ+Zf5lH1O3CPsU1d+FcKzKvzAG9XqwmRm0uJ\n"
+ "E49NoHcWr9IzdIwSGo+PJSkVpk95a5p2s065BetCWxEEBJQniajQf2hZ36zmV9rq\n"
+ "a6puqkEAKAM=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "d6QGIVAJL5JjHUyV+aicLIdBYyxHwviKpPcp7uldRF8vfDGFpu0qFgJ5KT+3t36w\n"
+ "QY1r75bvUMG/ZzGKDg95dcK0X2AK6GFlcrYyCoQEVOsuPc1QEUeK9P2s7viNQE4V\n"
+ "tRwG/CvJhPfcnxErzVGfXIeYRL1r/hPNFDZSeSxPPM0=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "router-sig-ed25519 ts9pFk8PnDWtXgQad09XC/ZCbruSx1U1pNOMWF9fyoNG0CodxdDH9Vglg+BOS7Nd9fmsINfPWKCVdVuSSM7zCA\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "YMl6mpQm7UCsPQhZKMm0aZ7fzGevWzRbQO+de20HTn7fVqMWQf2hBDJe9QTN/uDK\n"
+ "/VKYT8SnIBexbrSMy1N5q8kNFKxxUtwA9GRtz620Vvc4m+lz/tnT9qucIKCDL5iJ\n"
+ "eRpnls0JoAMIHKl99zdUioYubmOZuqUaRAdT8ulWy+Y=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CERT1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
+ "Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
+ "dZToQTFSzAQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM4o2DrTwn3wrvUMm41S/hFL5ZtRHGRDh26o8htn14AKMC65vpygKFY7\n"
+ "fUQVClAiJthAs5fD/8sE5XDtQrLnFv5OegQx8kSPuwyS/+5pI1bdxRJvKMOUl2Tc\n"
+ "fAUhzeNBmPvW3lMi9Fksw5sCSAKQ5VH/+DlYvBGZIO49pTnOAty1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMzIsJeEWWjN3Lp6qrzaJGn8uhJPJyjy2Wt3sp7z7iD/yBWW6Q7Jku3e\n"
+ "C5QfKmSmNi2pNjS0SqPjqZZNsbcxpq/bEOcZdysZG1lqi/QgxUevk57RWjh3EFsG\n"
+ "TwK3ougKWB5Q6/3m32dNsnnnDqzVapgZo7Zd3V/aCo0BVtL5VXZbAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key W28nwT/5FJ818M78y/5sNOkxhQ7ENBhjVhGG2j6KvFY=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
+ "Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
+ "dZToQTFSzAQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "FWnEjvFob0ObgqohMT7miwGsAuioCT7Urz6tyWaGWph/TP9hbFWj4MPK5mt998mn\n"
+ "xA8zHSF5n/edu7wVX+rtnPrYPBmg+qN8+Pq6XMg64CwtWu+sqigsi6vtz/TfAIDL\n"
+ "mypENmSY32sWPvy/CA8dAZ2ASh57EH9a+WcFModpXkM=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 88YqJdGJS4O6XiUCNrc9xbOHxujvcN/TkCoRuQQeKfZGHM+4IhI6AcXFlPIfDYq0SAavMhVmzsDDw0ROl7vyCQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "cU4WDO3w9ZfVRbNUgxOQMbwS2xWXvaL+cZmIV6AAjAZVWkLEpif4g6uYu+jJUZOS\n"
+ "NUT7lNOMwTu4tE4b1YJpnD9T8iW0DlOXxlvRBMQYmKwhQuYk898BDGTSk+0AY0HJ\n"
+ "vv8wRVewDajNhW7tFY907IdHvPXG0u83GANxkYrRyUg=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CERT2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN WOBBLY RUTABAGA-----\n"
+ "helo\n"
+ "-----END WOBBLY RUTABAGA-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANZvqyqFeiekh8ApqIGK4ZtOqjaX87EzDestvAWwamVOXiPoUrzXgM3O\n"
+ "l8uuTnMA4TfnjLyyA2TnaMzJylOI1OMHuW/D9B/liWDstSxWNNIlKgLQ/Dh9xBS7\n"
+ "uQb2PYlI+iMkPKPyJQSTDdGHE7cdFPewUfhRtJU3F5ztm/3FLBFvAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANZl8U/Z8KCPS7EBDzt8i9kNETXS7vnp9gnw3BQNXfjiDtDg9eO7ChxY\n"
+ "NBwuOTXmRxfX3W9kvZ0op9Hno6hixIhHzDql+vZ+hN7yPanVVDglSUXcr31yBm5K\n"
+ "kA+ZnRvH3oVQ97E4rRzpi09dtI13Pzu7JS5jRMtH+JF1kQBoNC0dAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key lUrEL+TVXpjjHQ2BIKk34vblyDmoyMro1a6/9hJ4VRc=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55Abm5E7FBdd3F8N1xuz/vdv03zh2lABrmGjzPQ3AFJtntALNeQTgjv0JL\n"
+ "jON4+SPNi0B2Bva3yKaSsdxiHQ1rIwQqIUVkzXmmX4jmsvJK/9gERAdD7GafTKZQ\n"
+ "BaZbNXBvmQw=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "OxkqFsw1vHUQ9iPYcKC/MHUBtbLPK6JY2i81ccAai2eW118UXcTbeCRccrXyqSkl\n"
+ "RLcooZyli1D6wg9x7O8+2+HXIbUa6WcTOD1Qi7Z9wKZfk4sDUy7QHKENMRfAXwX3\n"
+ "U/gqd4BflMPp4+XrYfPzz+6yQPWp0t9wXbFv5hZ9F3k=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 fW6Bt4R3xVk5KMDyOcYg8n5ANP0OrQq2PQFK2cW0lTAdi+eX+oT/BeWnkrn0uSWOC/t4omCmH4Rdl8M9xtpfBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "DHxiQXuLxZR0ylqwUGGePgN4KF4ItlOV/DuGmmszCO/Ut0p+5s4FP2v6Mm9M92Wj\n"
+ "75rS9xF/Ts0Kf49dvgc+c5VTvhX5I5SwGQkRk0RNJtNoP0t+qXBHaFV8BlAeaWF6\n"
+ "Lg3O+GUK325fQv9uDPCe37mFQV9jafAzsZUrO/ggb1U=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CERT3[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "BVVVnf55AW5TTGF9jCMl7aALZzqypD9Bj8WYnAPIrKCoIJdgMbY0AQAgBAB7eCn8\n"
+ "rukx7t/egZUdqU7+FYqsnO4wdmOkLZkp0+gpF3jjk6N1Q0037NNVNZBjONB0Nm2F\n"
+ "CpB3nWSJliSSKr5tOYsuBPFy5VVGYeKPakpOoxanQ1UcqevMBAQy0zf9hwA=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPgeQNbKwpnTU+qW/2djh66hptS9rcy1B4vdyWkDTdREao2ECuCv691Y\n"
+ "oIw3MpTWvpC1qHIKorunusR0FKgwXw3xQTikXbDq/1ptsekzoIA1R/hltQV3UuGH\n"
+ "zdzHuQXAMX7Fdll2gyya03c3Yq5s+xSDvGdkEeaIoctKjwxp4SdNAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOzWuH4cPW9rIrfi8MrruMUg4IUVHz4BxfY4/szMIUvzeEAdHn4FYkWy\n"
+ "Vt7MDtUELZsmZeFNmkn72kLxnrdZ5XhxZBriq1Fzq11cSWRBF+SyE1MdcouY4GyG\n"
+ "drw6T8xb8ty19q0eO6C/gw27iqXPAp1clvkroLg6Nv9lGZvsedVDAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key /vYZ+9yLqG7yUnutoI57s96JBl36GTz0IDWE244rbzE=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AZ4zVBWP/fIYEgWmyj0WpO6CkXRJjtrWXtiT02k3IddiAMpYgMemGIpN\n"
+ "xj7TQRULsHHYvo4fLcKrSgndQbUUhfLTUuVhIzbnE2TBLMVOEkpxKU6mTuvTT/3h\n"
+ "MJugrwTWVg4=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "c/Vqu3wtsTsYMdnhTS9Tn1Pq6jDmH4uRD5WmbaCKKrkin2DjuYSMVpypndkdlZDE\n"
+ "He7uF7SUO3QG/UcRIXYOsg9MSLUmvn2kIwef8ykyqlRh95Csjo5DyattUhL2w4QF\n"
+ "tJkJBQAnXWaAVW1O8XimGCAvJ84cxbmZEcpN6WKjrXI=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 Ue7bkPpOoc8ca7cyQj/Vq3BP5X4vwLA5QmpLGw/WfRNVRPojJRxU3RVqWMi3JbsJFRTe6pH6ZHyXER33G5aAAA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "ifKUtbxmqHVs8A0oT5n7Te0c6D/XqWQTc0RxX9OKGspzh6wNX26h0Xa2vpK1Q9Zu\n"
+ "sj61I7vbHuZN6rxiWs9IzJgb//XaNJasX1pd9tbGSXW+yYzc9G9kaa7vp3HcnhIP\n"
+ "XVWzzS8WmOiVNGcF65j6f7yGloTgN7cHMptgJG7pWes=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_BAD_EI_DIGEST2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55ATrK8IVBWLO2yXKCqXLXJOTu89W2b+hREPO+tCrxjVqWAQAgBACG/vVx\n"
+ "NK8wKVZvf34d75ZObSR0ge1N2RrAIKNslNXBq/tcllIrNE4S0ZNcMpA+hxXoVFeo\n"
+ "jbxifYX7nTs5N3GrGPmkiuo82v2X6ZwoIXJGFnvWMxCjsYsUVDDxoT6h/w8=\n"
+ "-----END ED25519 CERT-----\n"
+ "extra-info-digest E5FAC29E766D63F96AD175069640E803F2723765 99oo\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAK9wHSdRalxkuAybrSCA3dlEC1ZGc7oHOzXRGLg+z6batuiCdQtus1Rk\n"
+ "LP821eZJtEMAE56aewCIHDcTiCxVa6DMqmxRjm5pfW4G5H5QCPYT6Fu0RoYck3Ef\n"
+ "vkgits5/fNYGPPVC7k8AdGax5dKj5oFVGq+JWolYFRv6tyR9AThvAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKxjxTQ/T/MHpFbk7/zwA7l5b3IW3yVcyVe6eIGFoYun8FI0fbYRmR4M\n"
+ "G5Asu07gP9Bbgt3AFPuEqrjg4u+lIkgqTcCgKWJbAgm7fslwaDTXQ36A7I1M95PD\n"
+ "GJ10Dk5v4dVbrqwoF7MSrQPFtMO91RP11nGPSvDqXZJ4XpwqwdxpAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key LuVmHxpj4F5mPXGNi4MtxbIbLMav6frJRBsRgAvpdzo=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AYb+9XE0rzApVm9/fh3vlk5tJHSB7U3ZGsAgo2yU1cGrAKBcSzwi4lY/\n"
+ "salCELOLdeZzOjDNnBd6cKp2WJg7Yz5zFlbVbyNk0iwfGmucHk8vQZe5BS0Oq/Pz\n"
+ "B1u/BcJv8gk=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "QsAQVdDVHtasDbhrZG4ZxImdTTMY7fz3vouAiGyZx6/jCCB5v0gHwTn4xo6pgLEW\n"
+ "LQfMhQZIr76Ky67c0hAN2hihuDlfvhfVe9c2c5UOH1BOhq3llE3Hc3xGyEy3rw7r\n"
+ "5y38YGi759CvsP2/L8JfXMuBg89OcgJYFa27Q6e6MdQ=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 5zoQ0dufeeOJ/tE/BgcWgM8JpfW1ELSXLz4dI+K8YRH/gUtaPmYJgU2QfeUHD0oy1iwv4Qvl8Ferga7aBk1+DA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "D6KRMwkb6JmVEnpZ825SD3LMB84UmVy0i94xk44OwhoWNKLXhaSTWJgf6AqnPG5o\n"
+ "QrCypSb44bYLn+VaDN5LVUl36jeZqCT4xd+4ZwIRdPOUj7vcVmyUDg3lXcAIk97Q\n"
+ "E5PrQY1mQuLSIjjKInAR2NRBumNJtRw31Y/DTB7tODU=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
diff --git a/src/test/include.am b/src/test/include.am
index c672b3fedc..0ef556a9bf 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -35,6 +35,8 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
-DLOCALSTATEDIR="\"$(localstatedir)\"" \
-DBINDIR="\"$(bindir)\"" \
-I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" \
+ -I"$(top_srcdir)/src/trunnel" \
+ -I"$(top_srcdir)/src/ext/trunnel" \
-DTOR_UNIT_TESTS
# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
@@ -67,6 +69,8 @@ src_test_test_SOURCES = \
src/test/test_extorport.c \
src/test/test_hs.c \
src/test/test_introduce.c \
+ src/test/test_keypin.c \
+ src/test/test_link_handshake.c \
src/test/test_logging.c \
src/test/test_microdesc.c \
src/test/test_nodelist.c \
@@ -135,7 +139,7 @@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
src/common/libor-crypto.a $(LIBDONNA) \
- src/common/libor-event.a \
+ src/common/libor-event.a src/trunnel/libor-trunnel.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@
diff --git a/src/test/test.c b/src/test/test.c
index f30b8ae1af..7ad849f49e 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1137,6 +1137,8 @@ extern struct testcase_t guardfraction_tests[];
extern struct testcase_t extorport_tests[];
extern struct testcase_t hs_tests[];
extern struct testcase_t introduce_tests[];
+extern struct testcase_t keypin_tests[];
+extern struct testcase_t link_handshake_tests[];
extern struct testcase_t logging_tests[];
extern struct testcase_t microdesc_tests[];
extern struct testcase_t nodelist_tests[];
@@ -1183,6 +1185,8 @@ struct testgroup_t testgroups[] = {
{ "extorport/", extorport_tests },
{ "hs/", hs_tests },
{ "introduce/", introduce_tests },
+ { "keypin/", keypin_tests },
+ { "link-handshake/", link_handshake_tests },
{ "nodelist/", nodelist_tests },
{ "oom/", oom_tests },
{ "options/", options_tests },
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 79085a748e..3d150f5abf 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -496,6 +496,43 @@ test_container_smartlist_join(void *arg)
}
static void
+test_container_smartlist_pos(void *arg)
+{
+ (void) arg;
+ smartlist_t *sl = smartlist_new();
+
+ smartlist_add(sl, tor_strdup("This"));
+ smartlist_add(sl, tor_strdup("is"));
+ smartlist_add(sl, tor_strdup("a"));
+ smartlist_add(sl, tor_strdup("test"));
+ smartlist_add(sl, tor_strdup("for"));
+ smartlist_add(sl, tor_strdup("a"));
+ smartlist_add(sl, tor_strdup("function"));
+
+ /* Test string_pos */
+ tt_int_op(smartlist_string_pos(NULL, "Fred"), ==, -1);
+ tt_int_op(smartlist_string_pos(sl, "Fred"), ==, -1);
+ tt_int_op(smartlist_string_pos(sl, "This"), ==, 0);
+ tt_int_op(smartlist_string_pos(sl, "a"), ==, 2);
+ tt_int_op(smartlist_string_pos(sl, "function"), ==, 6);
+
+ /* Test pos */
+ tt_int_op(smartlist_pos(NULL, "Fred"), ==, -1);
+ tt_int_op(smartlist_pos(sl, "Fred"), ==, -1);
+ tt_int_op(smartlist_pos(sl, "This"), ==, -1);
+ tt_int_op(smartlist_pos(sl, "a"), ==, -1);
+ tt_int_op(smartlist_pos(sl, "function"), ==, -1);
+ tt_int_op(smartlist_pos(sl, smartlist_get(sl,0)), ==, 0);
+ tt_int_op(smartlist_pos(sl, smartlist_get(sl,2)), ==, 2);
+ tt_int_op(smartlist_pos(sl, smartlist_get(sl,5)), ==, 5);
+ tt_int_op(smartlist_pos(sl, smartlist_get(sl,6)), ==, 6);
+
+ done:
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+}
+
+static void
test_container_smartlist_ints_eq(void *arg)
{
smartlist_t *sl1 = NULL, *sl2 = NULL;
@@ -1053,6 +1090,7 @@ struct testcase_t container_tests[] = {
CONTAINER_LEGACY(smartlist_overlap),
CONTAINER_LEGACY(smartlist_digests),
CONTAINER_LEGACY(smartlist_join),
+ CONTAINER_LEGACY(smartlist_pos),
CONTAINER(smartlist_ints_eq, 0),
CONTAINER_LEGACY(bitarray),
CONTAINER_LEGACY(digestset),
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 7944864bd7..6cba850f30 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -698,9 +698,18 @@ test_crypto_formats(void *arg)
for (idx = 0; idx < 10; ++idx) {
i = base64_encode(data2, 1024, data1, idx, 0);
tt_int_op(i, OP_GE, 0);
+ tt_int_op(i, OP_EQ, strlen(data2));
j = base64_decode(data3, 1024, data2, i);
tt_int_op(j,OP_EQ, idx);
tt_mem_op(data3,OP_EQ, data1, idx);
+
+ i = base64_encode_nopad(data2, 1024, (uint8_t*)data1, idx);
+ tt_int_op(i, OP_GE, 0);
+ tt_int_op(i, OP_EQ, strlen(data2));
+ tt_assert(! strchr(data2, '='));
+ j = base64_decode_nopad((uint8_t*)data3, 1024, data2, i);
+ tt_int_op(j, OP_EQ, idx);
+ tt_mem_op(data3,OP_EQ, data1, idx);
}
strlcpy(data1, "Test string that contains 35 chars.", 1024);
@@ -1264,6 +1273,8 @@ test_crypto_ed25519_simple(void *arg)
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec1));
tt_mem_op(pub1.pubkey, OP_EQ, pub2.pubkey, sizeof(pub1.pubkey));
+ tt_assert(ed25519_pubkey_eq(&pub1, &pub2));
+ tt_assert(ed25519_pubkey_eq(&pub1, &pub1));
memcpy(&kp1.pubkey, &pub1, sizeof(pub1));
memcpy(&kp1.seckey, &sec1, sizeof(sec1));
@@ -1283,6 +1294,7 @@ test_crypto_ed25519_simple(void *arg)
/* Wrong public key doesn't work. */
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec2));
tt_int_op(-1, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub2));
+ tt_assert(! ed25519_pubkey_eq(&pub1, &pub2));
/* Wrong message doesn't work. */
tt_int_op(0, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub1));
@@ -1421,9 +1433,10 @@ test_crypto_ed25519_test_vectors(void *arg)
static void
test_crypto_ed25519_encode(void *arg)
{
- char buf[ED25519_BASE64_LEN+1];
+ char buf[ED25519_SIG_BASE64_LEN+1];
ed25519_keypair_t kp;
ed25519_public_key_t pk;
+ ed25519_signature_t sig1, sig2;
char *mem_op_hex_tmp = NULL;
(void) arg;
@@ -1434,6 +1447,11 @@ test_crypto_ed25519_encode(void *arg)
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk, buf));
tt_mem_op(kp.pubkey.pubkey, OP_EQ, pk.pubkey, ED25519_PUBKEY_LEN);
+ tt_int_op(0, OP_EQ, ed25519_sign(&sig1, (const uint8_t*)"ABC", 3, &kp));
+ tt_int_op(0, OP_EQ, ed25519_signature_to_base64(buf, &sig1));
+ tt_int_op(0, OP_EQ, ed25519_signature_from_base64(&sig2, buf));
+ tt_mem_op(sig1.sig, OP_EQ, sig2.sig, ED25519_SIG_LEN);
+
/* Test known value. */
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk,
"lVIuIctLjbGZGU5wKMNXxXlSE3cW4kaqkqm04u6pxvM"));
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index a949f5de73..3e9e955b2b 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -14,15 +14,18 @@
#define NETWORKSTATUS_PRIVATE
#include "or.h"
#include "config.h"
+#include "crypto_ed25519.h"
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
#include "hibernate.h"
#include "networkstatus.h"
#include "router.h"
+#include "routerkeys.h"
#include "routerlist.h"
#include "routerparse.h"
#include "test.h"
+#include "torcert.h"
static void
test_dir_nicknames(void *arg)
@@ -87,8 +90,11 @@ test_dir_formats(void *arg)
routerinfo_t *rp1 = NULL, *rp2 = NULL;
addr_policy_t *ex1, *ex2;
routerlist_t *dir1 = NULL, *dir2 = NULL;
+ uint8_t *rsa_cc = NULL;
+ tor_cert_t *ntor_cc = NULL;
or_options_t *options = get_options_mutable();
const addr_policy_t *p;
+ time_t now = time(NULL);
(void)arg;
pk1 = pk_generate(0);
@@ -127,14 +133,33 @@ test_dir_formats(void *arg)
ex2->prt_min = ex2->prt_max = 24;
r2 = tor_malloc_zero(sizeof(routerinfo_t));
r2->addr = 0x0a030201u; /* 10.3.2.1 */
+ ed25519_keypair_t kp1, kp2;
+ ed25519_secret_key_from_seed(&kp1.seckey,
+ (const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
+ ed25519_public_key_generate(&kp1.pubkey, &kp1.seckey);
+ ed25519_secret_key_from_seed(&kp2.seckey,
+ (const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
+ r2->signing_key_cert = tor_cert_create(&kp1,
+ CERT_TYPE_ID_SIGNING,
+ &kp2.pubkey,
+ now, 86400,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ char cert_buf[256];
+ base64_encode(cert_buf, sizeof(cert_buf),
+ (const char*)r2->signing_key_cert->encoded,
+ r2->signing_key_cert->encoded_len,
+ BASE64_ENCODE_MULTILINE);
r2->platform = tor_strdup(platform);
r2->cache_info.published_on = 5;
r2->or_port = 9005;
r2->dir_port = 0;
r2->onion_pkey = crypto_pk_dup_key(pk2);
r2->onion_curve25519_pkey = tor_malloc_zero(sizeof(curve25519_public_key_t));
- curve25519_public_from_base64(r2->onion_curve25519_pkey,
- "skyinAnvardNostarsNomoonNowindormistsorsnow");
+ curve25519_keypair_t r2_onion_keypair;
+ curve25519_keypair_generate(&r2_onion_keypair, 0);
+ r2->onion_curve25519_pkey = tor_memdup(&r2_onion_keypair.pubkey,
+ sizeof(curve25519_public_key_t));
r2->identity_pkey = crypto_pk_dup_key(pk1);
r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000;
r2->exit_policy = smartlist_new();
@@ -150,7 +175,7 @@ test_dir_formats(void *arg)
/* XXXX025 router_dump_to_string should really take this from ri.*/
options->ContactInfo = tor_strdup("Magri White "
"<magri@elsewhere.example.com>");
- buf = router_dump_router_to_string(r1, pk2);
+ buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL);
tor_free(options->ContactInfo);
tt_assert(buf);
@@ -183,7 +208,7 @@ test_dir_formats(void *arg)
tt_str_op(buf,OP_EQ, buf2);
tor_free(buf);
- buf = router_dump_router_to_string(r1, pk2);
+ buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL);
tt_assert(buf);
cp = buf;
rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
@@ -201,6 +226,10 @@ test_dir_formats(void *arg)
strlcpy(buf2,
"router Fred 10.3.2.1 9005 0 0\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n", sizeof(buf2));
+ strlcat(buf2, cert_buf, sizeof(buf2));
+ strlcat(buf2, "-----END ED25519 CERT-----\n"
"platform Tor "VERSION" on ", sizeof(buf2));
strlcat(buf2, get_uname(), sizeof(buf2));
strlcat(buf2, "\n"
@@ -215,19 +244,52 @@ test_dir_formats(void *arg)
strlcat(buf2, pk2_str, sizeof(buf2));
strlcat(buf2, "signing-key\n", sizeof(buf2));
strlcat(buf2, pk1_str, sizeof(buf2));
+ int rsa_cc_len;
+ rsa_cc = make_tap_onion_key_crosscert(pk2,
+ &kp1.pubkey,
+ pk1,
+ &rsa_cc_len);
+ tt_assert(rsa_cc);
+ base64_encode(cert_buf, sizeof(cert_buf), (char*)rsa_cc, rsa_cc_len,
+ BASE64_ENCODE_MULTILINE);
+ strlcat(buf2, "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n", sizeof(buf2));
+ strlcat(buf2, cert_buf, sizeof(buf2));
+ strlcat(buf2, "-----END CROSSCERT-----\n", sizeof(buf2));
+ int ntor_cc_sign;
+ ntor_cc = make_ntor_onion_key_crosscert(&r2_onion_keypair,
+ &kp1.pubkey,
+ r2->cache_info.published_on,
+ MIN_ONION_KEY_LIFETIME,
+ &ntor_cc_sign);
+ tt_assert(ntor_cc);
+ base64_encode(cert_buf, sizeof(cert_buf),
+ (char*)ntor_cc->encoded, ntor_cc->encoded_len,
+ BASE64_ENCODE_MULTILINE);
+ tor_snprintf(buf2+strlen(buf2), sizeof(buf2)-strlen(buf2),
+ "ntor-onion-key-crosscert %d\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "%s"
+ "-----END ED25519 CERT-----\n", ntor_cc_sign, cert_buf);
+
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
- strlcat(buf2, "ntor-onion-key "
- "skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2));
+ strlcat(buf2, "ntor-onion-key ", sizeof(buf2));
+ base64_encode(cert_buf, sizeof(cert_buf),
+ (const char*)r2_onion_keypair.pubkey.public_key, 32,
+ BASE64_ENCODE_MULTILINE);
+ strlcat(buf2, cert_buf, sizeof(buf2));
strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
- strlcat(buf2, "router-signature\n", sizeof(buf2));
+ strlcat(buf2, "router-sig-ed25519 ", sizeof(buf2));
- buf = router_dump_router_to_string(r2, pk1);
+ buf = router_dump_router_to_string(r2, pk1, pk2, &r2_onion_keypair, &kp2);
+ tt_assert(buf);
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
* twice */
- tt_str_op(buf,OP_EQ, buf2);
+
+ tt_str_op(buf, OP_EQ, buf2);
tor_free(buf);
- buf = router_dump_router_to_string(r2, pk1);
+ buf = router_dump_router_to_string(r2, pk1, NULL, NULL, NULL);
cp = buf;
rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
tt_assert(rp2);
@@ -280,6 +342,7 @@ test_dir_formats(void *arg)
if (rp2)
routerinfo_free(rp2);
+ tor_free(rsa_cc);
tor_free(buf);
tor_free(pk1_str);
tor_free(pk2_str);
@@ -293,7 +356,7 @@ test_dir_formats(void *arg)
#include "failing_routerdescs.inc"
static void
-test_dir_routerparse_bad(void *arg)
+test_dir_routerinfo_parsing(void *arg)
{
(void) arg;
@@ -318,6 +381,8 @@ test_dir_routerparse_bad(void *arg)
CHECK_OK(EX_RI_MINIMAL);
CHECK_OK(EX_RI_MAXIMAL);
+ CHECK_OK(EX_RI_MINIMAL_ED);
+
/* good annotations prepended */
routerinfo_free(ri);
ri = router_parse_entry_from_string(EX_RI_MINIMAL, NULL, 0, 0,
@@ -376,8 +441,28 @@ test_dir_routerparse_bad(void *arg)
CHECK_FAIL(EX_RI_BAD_FAMILY, 0);
CHECK_FAIL(EX_RI_ZERO_ORPORT, 0);
+ CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT, 0);
+ CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT2, 0);
+ CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT_SIGN, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_SIG1, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_SIG2, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_SIG3, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_SIG4, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT1, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT3, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT4, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT5, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT6, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT7, 0);
+ CHECK_FAIL(EX_RI_ED_MISPLACED1, 0);
+ CHECK_FAIL(EX_RI_ED_MISPLACED2, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CERT1, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CERT2, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CERT3, 0);
+
/* This is allowed; we just ignore it. */
CHECK_OK(EX_RI_BAD_EI_DIGEST);
+ CHECK_OK(EX_RI_BAD_EI_DIGEST2);
#undef CHECK_FAIL
#undef CHECK_OK
@@ -433,20 +518,34 @@ test_dir_extrainfo_parsing(void *arg)
tt_assert(ei->pending_sig);
CHECK_OK(EX_EI_MAXIMAL);
tt_assert(ei->pending_sig);
+ CHECK_OK(EX_EI_GOOD_ED_EI);
+ tt_assert(ei->pending_sig);
map = (struct digest_ri_map_t *)digestmap_new();
ADD(EX_EI_MINIMAL);
ADD(EX_EI_MAXIMAL);
+ ADD(EX_EI_GOOD_ED_EI);
ADD(EX_EI_BAD_FP);
ADD(EX_EI_BAD_NICKNAME);
ADD(EX_EI_BAD_TOKENS);
ADD(EX_EI_BAD_START);
ADD(EX_EI_BAD_PUBLISHED);
+ ADD(EX_EI_ED_MISSING_SIG);
+ ADD(EX_EI_ED_MISSING_CERT);
+ ADD(EX_EI_ED_BAD_CERT1);
+ ADD(EX_EI_ED_BAD_CERT2);
+ ADD(EX_EI_ED_BAD_SIG1);
+ ADD(EX_EI_ED_BAD_SIG2);
+ ADD(EX_EI_ED_MISPLACED_CERT);
+ ADD(EX_EI_ED_MISPLACED_SIG);
+
CHECK_OK(EX_EI_MINIMAL);
tt_assert(!ei->pending_sig);
CHECK_OK(EX_EI_MAXIMAL);
tt_assert(!ei->pending_sig);
+ CHECK_OK(EX_EI_GOOD_ED_EI);
+ tt_assert(!ei->pending_sig);
CHECK_FAIL(EX_EI_BAD_SIG1,1);
CHECK_FAIL(EX_EI_BAD_SIG2,1);
@@ -457,6 +556,15 @@ test_dir_extrainfo_parsing(void *arg)
CHECK_FAIL(EX_EI_BAD_START,0);
CHECK_FAIL(EX_EI_BAD_PUBLISHED,0);
+ CHECK_FAIL(EX_EI_ED_MISSING_SIG,0);
+ CHECK_FAIL(EX_EI_ED_MISSING_CERT,0);
+ CHECK_FAIL(EX_EI_ED_BAD_CERT1,0);
+ CHECK_FAIL(EX_EI_ED_BAD_CERT2,0);
+ CHECK_FAIL(EX_EI_ED_BAD_SIG1,0);
+ CHECK_FAIL(EX_EI_ED_BAD_SIG2,0);
+ CHECK_FAIL(EX_EI_ED_MISPLACED_CERT,0);
+ CHECK_FAIL(EX_EI_ED_MISPLACED_SIG,0);
+
#undef CHECK_OK
#undef CHECK_FAIL
@@ -1394,6 +1502,7 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs)
static time_t published = 0;
r = tor_malloc_zero(sizeof(routerinfo_t));
+ r->cert_expiration_time = TIME_MAX;
memcpy(r->cache_info.identity_digest, rs->identity_digest, DIGEST_LEN);
memcpy(r->cache_info.signed_descriptor_digest, rs->descriptor_digest,
DIGEST_LEN);
@@ -3108,7 +3217,7 @@ test_dir_packages(void *arg)
struct testcase_t dir_tests[] = {
DIR_LEGACY(nicknames),
DIR_LEGACY(formats),
- DIR(routerparse_bad, 0),
+ DIR(routerinfo_parsing, 0),
DIR(extrainfo_parsing, 0),
DIR(parse_router_list, TT_FORK),
DIR(load_routers, TT_FORK),
diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c
new file mode 100644
index 0000000000..afd4ca201d
--- /dev/null
+++ b/src/test/test_keypin.c
@@ -0,0 +1,255 @@
+/* Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#define KEYPIN_PRIVATE
+#include "or.h"
+#include "keypin.h"
+#include "util.h"
+
+#include "test.h"
+
+static void
+test_keypin_parse_line(void *arg)
+{
+ (void)arg;
+ keypin_ent_t *ent = NULL;
+
+ /* Good line */
+ ent = keypin_parse_journal_line(
+ "aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
+ "VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
+ tt_assert(ent);
+ tt_mem_op(ent->rsa_id, ==, "here is a good sha1!", 20);
+ tt_mem_op(ent->ed25519_key, ==, "This ed25519 scoffs at the sha1.", 32);
+ tor_free(ent); ent = NULL;
+
+ /* Good line with extra stuff we will ignore. */
+ ent = keypin_parse_journal_line(
+ "aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
+ "VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4helloworld");
+ tt_assert(ent);
+ tt_mem_op(ent->rsa_id, ==, "here is a good sha1!", 20);
+ tt_mem_op(ent->ed25519_key, ==, "This ed25519 scoffs at the sha1.", 32);
+ tor_free(ent); ent = NULL;
+
+ /* Bad line: no space in the middle. */
+ ent = keypin_parse_journal_line(
+ "aGVyZSBpcyBhIGdvb2Qgc2hhMSE?"
+ "VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
+ tt_assert(! ent);
+
+ /* Bad line: bad base64 in RSA ID */
+ ent = keypin_parse_journal_line(
+ "aGVyZSBpcyBhIGdv!2Qgc2hhMSE "
+ "VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
+ tt_assert(! ent);
+
+ /* Bad line: bad base64 in Ed25519 */
+ ent = keypin_parse_journal_line(
+ "aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
+ "VGhpcyBlZDI1NTE5IHNjb2ZmcyB!dCB0aGUgc2hhMS4");
+ tt_assert(! ent);
+
+ done:
+ tor_free(ent);
+}
+
+static smartlist_t *mock_addent_got = NULL;
+static void
+mock_addent(keypin_ent_t *ent)
+{
+ smartlist_add(mock_addent_got, ent);
+ keypin_add_entry_to_map__real(ent);
+}
+
+static void
+test_keypin_parse_file(void *arg)
+{
+ (void)arg;
+
+ mock_addent_got = smartlist_new();
+ MOCK(keypin_add_entry_to_map, mock_addent);
+
+ /* Simple, minimal, correct example. */
+ const char data1[] =
+"PT09PT09PT09PT09PT09PT09PT0 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0\n"
+"TG9yYXggaXBzdW0gZ3J1dnZ1bHU cyB0aG5lZWQgYW1ldCwgc25lcmdlbGx5IG9uY2UtbGU\n"
+"ciBsZXJraW0sIHNlZCBkbyBiYXI YmFsb290IHRlbXBvciBnbHVwcGl0dXMgdXQgbGFib3I\n"
+"ZSBldCB0cnVmZnVsYSBtYWduYSA YWxpcXVhLiBVdCBlbmltIGFkIGdyaWNrbGUtZ3Jhc3M\n"
+"dmVuaWFtLCBxdWlzIG1pZmYtbXU ZmZlcmVkIGdhLXp1bXBjbyBsYWJvcmlzIG5pc2kgdXQ\n"
+"Y3J1ZmZ1bHVzIGV4IGVhIHNjaGw b3BwaXR5IGNvbnNlcXVhdC4gRHVpcyBhdXRlIHNuYXI\n"
+"Z2dsZSBpbiBzd29tZWVzd2FucyA aW4gdm9sdXB0YXRlIGF4ZS1oYWNrZXIgZXNzZSByaXA\n"
+"cHVsdXMgY3J1bW1paSBldSBtb28 ZiBudWxsYSBzbnV2di5QTFVHSFBMT1ZFUlhZWlpZLi4\n";
+
+ tt_int_op(0, ==, keypin_load_journal_impl(data1, strlen(data1)));
+ tt_int_op(8, ==, smartlist_len(mock_addent_got));
+ keypin_ent_t *ent = smartlist_get(mock_addent_got, 2);
+ tt_mem_op(ent->rsa_id, ==, "r lerkim, sed do bar", 20);
+ tt_mem_op(ent->ed25519_key, ==, "baloot tempor gluppitus ut labor", 32);
+
+ /* More complex example: weird lines, bogus lines,
+ duplicate/conflicting lines */
+ const char data2[] =
+ "PT09PT09PT09PT09PT09PT09PT0 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0\n"
+ "# This is a comment.\n"
+ " \n"
+ "QXQgdGhlIGVuZCBvZiB0aGUgeWU YXIgS3VycmVta2FybWVycnVrIHNhaWQgdG8gaGltLCA\n"
+ "IllvdSBoYXZlIG1hZGUgYSBnb28 ZCBiZWdpbm5pbmcuIiBCdXQgbm8gbW9yZS4gV2l6YXI\n"
+ "\n"
+ "ZHMgc3BlYWsgdHJ1dGgsIGFuZCA aXQgd2FzIHRydWUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n"
+ "@reserved for a future extension \n"
+ "eSBvZiBOYW1lcyB0aGF0IEdlZCA aGFkIHRvaWxlZCbyB3aW4gdGhhdCB5ZWFyIHdhcyA\n"
+ "eSBvZiBOYW1lcyB0aGF0IEdlZCA aGFkIHRvaWxlZCbyB3aW4gdGhhdCB5ZWFyIHdhcy"
+ "A line too long\n"
+ "dGhlIG1lcmUgc3RhcnQgb2Ygd2g YXQgaGUgbXVzdCBnbyBvb!BsZWFybmluZy4uLi4uLi4\n"
+ "ZHMgc3BlYWsgdaJ1dGgsIGFuZCA aXQgd2FzIHRydWUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n"
+ "ZHMgc3BlYWsgdHJ1dGgsIGFuZCA aXQgd2FzIHRydaUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n"
+ ;
+
+ tt_int_op(0, ==, keypin_load_journal_impl(data2, strlen(data2)));
+ tt_int_op(11, ==, smartlist_len(mock_addent_got));
+ ent = smartlist_get(mock_addent_got, 9);
+ tt_mem_op(ent->rsa_id, ==, "\"You have made a goo", 20);
+ tt_mem_op(ent->ed25519_key, ==, "d beginning.\" But no more. Wizar", 32);
+
+ ent = smartlist_get(mock_addent_got, 10);
+ tt_mem_op(ent->rsa_id, ==, "ds speak truth, and ", 20);
+ tt_mem_op(ent->ed25519_key, ==, "it was true that all the master\n", 32);
+
+ /* File truncated before NL */
+ const char data3[] =
+ "Tm8gZHJhZ29uIGNhbiByZXNpc3Q IHRoZSBmYXNjaW5hdGlvbiBvZiByaWRkbGluZyB0YWw";
+ tt_int_op(0, ==, keypin_load_journal_impl(data3, strlen(data3)));
+ tt_int_op(12, ==, smartlist_len(mock_addent_got));
+ ent = smartlist_get(mock_addent_got, 11);
+ tt_mem_op(ent->rsa_id, ==, "No dragon can resist", 20);
+ tt_mem_op(ent->ed25519_key, ==, " the fascination of riddling tal", 32);
+
+ done:
+ keypin_clear();
+ smartlist_free(mock_addent_got);
+}
+
+#define ADD(a,b) keypin_check_and_add((const uint8_t*)(a),(const uint8_t*)(b))
+#define LONE_RSA(a) keypin_check_lone_rsa((const uint8_t*)(a))
+
+static void
+test_keypin_add_entry(void *arg)
+{
+ (void)arg;
+ keypin_clear();
+
+ tt_int_op(KEYPIN_ADDED, ==, ADD("ambassadors-at-large",
+ "bread-and-butter thing-in-itself"));
+ tt_int_op(KEYPIN_ADDED, ==, ADD("gentleman-adventurer",
+ "cloak-and-dagger what's-his-face"));
+
+ tt_int_op(KEYPIN_FOUND, ==, ADD("ambassadors-at-large",
+ "bread-and-butter thing-in-itself"));
+ tt_int_op(KEYPIN_FOUND, ==, ADD("ambassadors-at-large",
+ "bread-and-butter thing-in-itself"));
+ tt_int_op(KEYPIN_FOUND, ==, ADD("gentleman-adventurer",
+ "cloak-and-dagger what's-his-face"));
+
+ tt_int_op(KEYPIN_ADDED, ==, ADD("Johnnies-come-lately",
+ "run-of-the-mill root-mean-square"));
+
+ tt_int_op(KEYPIN_MISMATCH, ==, ADD("gentleman-adventurer",
+ "hypersentimental closefistedness"));
+
+ tt_int_op(KEYPIN_MISMATCH, ==, ADD("disestablismentarian",
+ "cloak-and-dagger what's-his-face"));
+
+ tt_int_op(KEYPIN_FOUND, ==, ADD("gentleman-adventurer",
+ "cloak-and-dagger what's-his-face"));
+
+ tt_int_op(KEYPIN_NOT_FOUND, ==, LONE_RSA("Llanfairpwllgwyngyll"));
+ tt_int_op(KEYPIN_MISMATCH, ==, LONE_RSA("Johnnies-come-lately"));
+
+ done:
+ keypin_clear();
+}
+
+static void
+test_keypin_journal(void *arg)
+{
+ (void)arg;
+ char *contents = NULL;
+ const char *fname = get_fname("keypin-journal");
+
+ tt_int_op(0, ==, keypin_load_journal(fname)); /* ENOENT is okay */
+ update_approx_time(1217709000);
+ tt_int_op(0, ==, keypin_open_journal(fname));
+
+ tt_int_op(KEYPIN_ADDED, ==, ADD("king-of-the-herrings",
+ "good-for-nothing attorney-at-law"));
+ tt_int_op(KEYPIN_ADDED, ==, ADD("yellowish-red-yellow",
+ "salt-and-pepper high-muck-a-muck"));
+ tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
+ "salt-and-pepper high-muck-a-muck"));
+ keypin_close_journal();
+ keypin_clear();
+
+ tt_int_op(0, ==, keypin_load_journal(fname));
+ update_approx_time(1231041600);
+ tt_int_op(0, ==, keypin_open_journal(fname));
+ tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
+ "salt-and-pepper high-muck-a-muck"));
+ tt_int_op(KEYPIN_ADDED, ==, ADD("theatre-in-the-round",
+ "holier-than-thou jack-in-the-box"));
+ tt_int_op(KEYPIN_ADDED, ==, ADD("no-deposit-no-return",
+ "across-the-board will-o-the-wisp"));
+ tt_int_op(KEYPIN_MISMATCH, ==, ADD("intellectualizations",
+ "salt-and-pepper high-muck-a-muck"));
+ keypin_close_journal();
+ keypin_clear();
+
+ tt_int_op(0, ==, keypin_load_journal(fname));
+ update_approx_time(1412278354);
+ tt_int_op(0, ==, keypin_open_journal(fname));
+ tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
+ "salt-and-pepper high-muck-a-muck"));
+ tt_int_op(KEYPIN_MISMATCH, ==, ADD("intellectualizations",
+ "salt-and-pepper high-muck-a-muck"));
+ tt_int_op(KEYPIN_FOUND, ==, ADD("theatre-in-the-round",
+ "holier-than-thou jack-in-the-box"));
+ tt_int_op(KEYPIN_MISMATCH, ==, ADD("counterrevolutionary",
+ "holier-than-thou jack-in-the-box"));
+ tt_int_op(KEYPIN_MISMATCH, ==, ADD("no-deposit-no-return",
+ "floccinaucinihilipilificationism"));
+ keypin_close_journal();
+
+ contents = read_file_to_str(fname, RFTS_BIN, NULL);
+ tt_assert(contents);
+ tt_str_op(contents,==,
+ "\n"
+ "@opened-at 2008-08-02 20:30:00\n"
+ "a2luZy1vZi10aGUtaGVycmluZ3M Z29vZC1mb3Itbm90aGluZyBhdHRvcm5leS1hdC1sYXc\n"
+ "eWVsbG93aXNoLXJlZC15ZWxsb3c c2FsdC1hbmQtcGVwcGVyIGhpZ2gtbXVjay1hLW11Y2s\n"
+ "\n"
+ "@opened-at 2009-01-04 04:00:00\n"
+ "dGhlYXRyZS1pbi10aGUtcm91bmQ aG9saWVyLXRoYW4tdGhvdSBqYWNrLWluLXRoZS1ib3g\n"
+ "bm8tZGVwb3NpdC1uby1yZXR1cm4 YWNyb3NzLXRoZS1ib2FyZCB3aWxsLW8tdGhlLXdpc3A\n"
+ "\n"
+ "@opened-at 2014-10-02 19:32:34\n");
+
+ done:
+ tor_free(contents);
+ keypin_clear();
+}
+
+#undef ADD
+#undef LONE_RSA
+
+#define TEST(name, flags) \
+ { #name , test_keypin_ ## name, (flags), NULL, NULL }
+
+struct testcase_t keypin_tests[] = {
+ TEST( parse_line, 0 ),
+ TEST( parse_file, TT_FORK ),
+ TEST( add_entry, TT_FORK ),
+ TEST( journal, TT_FORK ),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
new file mode 100644
index 0000000000..bfdd6f3d1a
--- /dev/null
+++ b/src/test/test_link_handshake.c
@@ -0,0 +1,914 @@
+/* Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define CHANNELTLS_PRIVATE
+#define CONNECTION_PRIVATE
+#define TOR_CHANNEL_INTERNAL_
+#include "or.h"
+#include "config.h"
+#include "connection.h"
+#include "connection_or.h"
+#include "channeltls.h"
+#include "link_handshake.h"
+#include "scheduler.h"
+
+#include "test.h"
+
+var_cell_t *mock_got_var_cell = NULL;
+
+static void
+mock_write_var_cell(const var_cell_t *vc, or_connection_t *conn)
+{
+ (void)conn;
+
+ var_cell_t *newcell = var_cell_new(vc->payload_len);
+ memcpy(newcell, vc, sizeof(var_cell_t));
+ memcpy(newcell->payload, vc->payload, vc->payload_len);
+
+ mock_got_var_cell = newcell;
+}
+static int
+mock_tls_cert_matches_key(const tor_tls_t *tls, const tor_x509_cert_t *cert)
+{
+ (void) tls;
+ (void) cert; // XXXX look at this.
+ return 1;
+}
+
+static int mock_send_netinfo_called = 0;
+static int
+mock_send_netinfo(or_connection_t *conn)
+{
+ (void) conn;
+ ++mock_send_netinfo_called;// XXX check_this
+ return 0;
+}
+
+static int mock_close_called = 0;
+static void
+mock_close_for_err(or_connection_t *orconn, int flush)
+{
+ (void)orconn;
+ (void)flush;
+ ++mock_close_called;
+}
+
+static int mock_send_authenticate_called = 0;
+static int
+mock_send_authenticate(or_connection_t *conn, int type)
+{
+ (void) conn;
+ (void) type;
+ ++mock_send_authenticate_called;// XXX check_this
+ return 0;
+}
+
+/* Test good certs cells */
+static void
+test_link_handshake_certs_ok(void *arg)
+{
+ (void) arg;
+
+ or_connection_t *c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
+ or_connection_t *c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
+ var_cell_t *cell1 = NULL, *cell2 = NULL;
+ certs_cell_t *cc1 = NULL, *cc2 = NULL;
+ channel_tls_t *chan1 = NULL, *chan2 = NULL;
+ crypto_pk_t *key1 = NULL, *key2 = NULL;
+
+ scheduler_init();
+
+ MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
+ MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
+ MOCK(connection_or_send_netinfo, mock_send_netinfo);
+
+ key1 = pk_generate(2);
+ key2 = pk_generate(3);
+
+ /* We need to make sure that our TLS certificates are set up before we can
+ * actually generate a CERTS cell.
+ */
+ tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
+ key1, key2, 86400), ==, 0);
+
+ c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ c1->link_proto = 3;
+ tt_int_op(connection_init_or_handshake_state(c1, 1), ==, 0);
+
+ c2->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ c2->link_proto = 3;
+ tt_int_op(connection_init_or_handshake_state(c2, 0), ==, 0);
+
+ tt_int_op(0, ==, connection_or_send_certs_cell(c1));
+ tt_assert(mock_got_var_cell);
+ cell1 = mock_got_var_cell;
+
+ tt_int_op(0, ==, connection_or_send_certs_cell(c2));
+ tt_assert(mock_got_var_cell);
+ cell2 = mock_got_var_cell;
+
+ tt_int_op(cell1->command, ==, CELL_CERTS);
+ tt_int_op(cell1->payload_len, >, 1);
+
+ tt_int_op(cell2->command, ==, CELL_CERTS);
+ tt_int_op(cell2->payload_len, >, 1);
+
+ tt_int_op(cell1->payload_len, ==,
+ certs_cell_parse(&cc1, cell1->payload, cell1->payload_len));
+ tt_int_op(cell2->payload_len, ==,
+ certs_cell_parse(&cc2, cell2->payload, cell2->payload_len));
+
+ tt_int_op(2, ==, cc1->n_certs);
+ tt_int_op(2, ==, cc2->n_certs);
+
+ tt_int_op(certs_cell_get_certs(cc1, 0)->cert_type, ==,
+ CERTTYPE_RSA1024_ID_AUTH);
+ tt_int_op(certs_cell_get_certs(cc1, 1)->cert_type, ==,
+ CERTTYPE_RSA1024_ID_ID);
+
+ tt_int_op(certs_cell_get_certs(cc2, 0)->cert_type, ==,
+ CERTTYPE_RSA1024_ID_LINK);
+ tt_int_op(certs_cell_get_certs(cc2, 1)->cert_type, ==,
+ CERTTYPE_RSA1024_ID_ID);
+
+ chan1 = tor_malloc_zero(sizeof(*chan1));
+ channel_tls_common_init(chan1);
+ c1->chan = chan1;
+ chan1->conn = c1;
+ c1->base_.address = tor_strdup("C1");
+ c1->tls = tor_tls_new(-1, 0);
+ c1->link_proto = 4;
+ c1->base_.conn_array_index = -1;
+ crypto_pk_get_digest(key2, c1->identity_digest);
+
+ channel_tls_process_certs_cell(cell2, chan1);
+
+ tt_assert(c1->handshake_state->received_certs_cell);
+ tt_assert(c1->handshake_state->auth_cert == NULL);
+ tt_assert(c1->handshake_state->id_cert);
+ tt_assert(! tor_mem_is_zero(
+ (char*)c1->handshake_state->authenticated_peer_id, 20));
+
+ chan2 = tor_malloc_zero(sizeof(*chan2));
+ channel_tls_common_init(chan2);
+ c2->chan = chan2;
+ chan2->conn = c2;
+ c2->base_.address = tor_strdup("C2");
+ c2->tls = tor_tls_new(-1, 1);
+ c2->link_proto = 4;
+ c2->base_.conn_array_index = -1;
+ crypto_pk_get_digest(key1, c2->identity_digest);
+
+ channel_tls_process_certs_cell(cell1, chan2);
+
+ tt_assert(c2->handshake_state->received_certs_cell);
+ tt_assert(c2->handshake_state->auth_cert);
+ tt_assert(c2->handshake_state->id_cert);
+ tt_assert(tor_mem_is_zero(
+ (char*)c2->handshake_state->authenticated_peer_id, 20));
+
+ done:
+ UNMOCK(tor_tls_cert_matches_key);
+ UNMOCK(connection_or_write_var_cell_to_buf);
+ UNMOCK(connection_or_send_netinfo);
+ connection_free_(TO_CONN(c1));
+ connection_free_(TO_CONN(c2));
+ tor_free(cell1);
+ tor_free(cell2);
+ certs_cell_free(cc1);
+ certs_cell_free(cc2);
+ circuitmux_free(chan1->base_.cmux);
+ tor_free(chan1);
+ circuitmux_free(chan2->base_.cmux);
+ tor_free(chan2);
+ crypto_pk_free(key1);
+ crypto_pk_free(key2);
+}
+
+typedef struct certs_data_s {
+ or_connection_t *c;
+ channel_tls_t *chan;
+ certs_cell_t *ccell;
+ var_cell_t *cell;
+ crypto_pk_t *key1, *key2;
+} certs_data_t;
+
+
+static int
+recv_certs_cleanup(const struct testcase_t *test, void *obj)
+{
+ (void)test;
+ certs_data_t *d = obj;
+ UNMOCK(tor_tls_cert_matches_key);
+ UNMOCK(connection_or_send_netinfo);
+ UNMOCK(connection_or_close_for_error);
+
+ if (d) {
+ tor_free(d->cell);
+ certs_cell_free(d->ccell);
+ connection_free_(TO_CONN(d->c));
+ circuitmux_free(d->chan->base_.cmux);
+ tor_free(d->chan);
+ crypto_pk_free(d->key1);
+ crypto_pk_free(d->key2);
+ tor_free(d);
+ }
+ return 1;
+}
+
+static void *
+recv_certs_setup(const struct testcase_t *test)
+{
+ (void)test;
+ certs_data_t *d = tor_malloc_zero(sizeof(*d));
+ certs_cell_cert_t *ccc1 = NULL;
+ certs_cell_cert_t *ccc2 = NULL;
+ ssize_t n;
+
+ d->c = or_connection_new(CONN_TYPE_OR, AF_INET);
+ d->chan = tor_malloc_zero(sizeof(*d->chan));
+ d->c->chan = d->chan;
+ d->c->base_.address = tor_strdup("HaveAnAddress");
+ d->c->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ d->chan->conn = d->c;
+ tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0);
+ d->c->link_proto = 4;
+
+ d->key1 = pk_generate(2);
+ d->key2 = pk_generate(3);
+
+ tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
+ d->key1, d->key2, 86400), ==, 0);
+ d->ccell = certs_cell_new();
+ ccc1 = certs_cell_cert_new();
+ certs_cell_add_certs(d->ccell, ccc1);
+ ccc2 = certs_cell_cert_new();
+ certs_cell_add_certs(d->ccell, ccc2);
+ d->ccell->n_certs = 2;
+ ccc1->cert_type = 1;
+ ccc2->cert_type = 2;
+
+ const tor_x509_cert_t *a,*b;
+ const uint8_t *enca, *encb;
+ size_t lena, lenb;
+ tor_tls_get_my_certs(1, &a, &b);
+ tor_x509_cert_get_der(a, &enca, &lena);
+ tor_x509_cert_get_der(b, &encb, &lenb);
+ certs_cell_cert_setlen_body(ccc1, lena);
+ ccc1->cert_len = lena;
+ certs_cell_cert_setlen_body(ccc2, lenb);
+ ccc2->cert_len = lenb;
+
+ memcpy(certs_cell_cert_getarray_body(ccc1), enca, lena);
+ memcpy(certs_cell_cert_getarray_body(ccc2), encb, lenb);
+
+ d->cell = var_cell_new(4096);
+ d->cell->command = CELL_CERTS;
+
+ n = certs_cell_encode(d->cell->payload, 4096, d->ccell);
+ tt_int_op(n, >, 0);
+ d->cell->payload_len = n;
+
+ MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
+ MOCK(connection_or_send_netinfo, mock_send_netinfo);
+ MOCK(connection_or_close_for_error, mock_close_for_err);
+
+ tt_int_op(0, ==, d->c->handshake_state->received_certs_cell);
+ tt_int_op(0, ==, mock_send_authenticate_called);
+ tt_int_op(0, ==, mock_send_netinfo_called);
+
+ return d;
+ done:
+ recv_certs_cleanup(test, d);
+ return NULL;
+}
+
+static struct testcase_setup_t setup_recv_certs = {
+ .setup_fn = recv_certs_setup,
+ .cleanup_fn = recv_certs_cleanup
+};
+
+static void
+test_link_handshake_recv_certs_ok(void *arg)
+{
+ certs_data_t *d = arg;
+ channel_tls_process_certs_cell(d->cell, d->chan);
+ tt_int_op(0, ==, mock_close_called);
+ tt_int_op(d->c->handshake_state->authenticated, ==, 1);
+ tt_int_op(d->c->handshake_state->received_certs_cell, ==, 1);
+ tt_assert(d->c->handshake_state->id_cert != NULL);
+ tt_assert(d->c->handshake_state->auth_cert == NULL);
+
+ done:
+ ;
+}
+
+static void
+test_link_handshake_recv_certs_ok_server(void *arg)
+{
+ certs_data_t *d = arg;
+ d->c->handshake_state->started_here = 0;
+ certs_cell_get_certs(d->ccell, 0)->cert_type = 3;
+ certs_cell_get_certs(d->ccell, 1)->cert_type = 2;
+ ssize_t n = certs_cell_encode(d->cell->payload, 2048, d->ccell);
+ tt_int_op(n, >, 0);
+ d->cell->payload_len = n;
+ channel_tls_process_certs_cell(d->cell, d->chan);
+ tt_int_op(0, ==, mock_close_called);
+ tt_int_op(d->c->handshake_state->authenticated, ==, 0);
+ tt_int_op(d->c->handshake_state->received_certs_cell, ==, 1);
+ tt_assert(d->c->handshake_state->id_cert != NULL);
+ tt_assert(d->c->handshake_state->auth_cert != NULL);
+
+ done:
+ ;
+}
+
+#define CERTS_FAIL(name, code) \
+ static void \
+ test_link_handshake_recv_certs_ ## name (void *arg) \
+ { \
+ certs_data_t *d = arg; \
+ { code ; } \
+ channel_tls_process_certs_cell(d->cell, d->chan); \
+ tt_int_op(1, ==, mock_close_called); \
+ tt_int_op(0, ==, mock_send_authenticate_called); \
+ tt_int_op(0, ==, mock_send_netinfo_called); \
+ done: \
+ ; \
+ }
+
+CERTS_FAIL(badstate, d->c->base_.state = OR_CONN_STATE_CONNECTING)
+CERTS_FAIL(badproto, d->c->link_proto = 2)
+CERTS_FAIL(duplicate, d->c->handshake_state->received_certs_cell = 1)
+CERTS_FAIL(already_authenticated,
+ d->c->handshake_state->authenticated = 1)
+CERTS_FAIL(empty, d->cell->payload_len = 0)
+CERTS_FAIL(bad_circid, d->cell->circ_id = 1)
+CERTS_FAIL(truncated_1, d->cell->payload[0] = 5)
+CERTS_FAIL(truncated_2, {
+ d->cell->payload_len = 4;
+ memcpy(d->cell->payload, "\x01\x01\x00\x05", 4);})
+CERTS_FAIL(truncated_3, {
+ d->cell->payload_len = 7;
+ memcpy(d->cell->payload, "\x01\x01\x00\x05""abc", 7);})
+#define REENCODE() do { \
+ ssize_t n = certs_cell_encode(d->cell->payload, 4096, d->ccell); \
+ tt_int_op(n, >, 0); \
+ d->cell->payload_len = n; \
+ } while (0)
+
+CERTS_FAIL(not_x509, {
+ certs_cell_cert_setlen_body(certs_cell_get_certs(d->ccell, 0), 3);
+ certs_cell_get_certs(d->ccell, 0)->cert_len = 3;
+ REENCODE();
+ })
+CERTS_FAIL(both_link, {
+ certs_cell_get_certs(d->ccell, 0)->cert_type = 1;
+ certs_cell_get_certs(d->ccell, 1)->cert_type = 1;
+ REENCODE();
+ })
+CERTS_FAIL(both_id_rsa, {
+ certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
+ certs_cell_get_certs(d->ccell, 1)->cert_type = 2;
+ REENCODE();
+ })
+CERTS_FAIL(both_auth, {
+ certs_cell_get_certs(d->ccell, 0)->cert_type = 3;
+ certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
+ REENCODE();
+ })
+CERTS_FAIL(wrong_labels_1, {
+ certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
+ certs_cell_get_certs(d->ccell, 1)->cert_type = 1;
+ REENCODE();
+ })
+CERTS_FAIL(wrong_labels_2, {
+ const tor_x509_cert_t *a;
+ const tor_x509_cert_t *b;
+ const uint8_t *enca;
+ size_t lena;
+ tor_tls_get_my_certs(1, &a, &b);
+ tor_x509_cert_get_der(a, &enca, &lena);
+ certs_cell_cert_setlen_body(certs_cell_get_certs(d->ccell, 1), lena);
+ memcpy(certs_cell_cert_getarray_body(certs_cell_get_certs(d->ccell, 1)),
+ enca, lena);
+ certs_cell_get_certs(d->ccell, 1)->cert_len = lena;
+ REENCODE();
+ })
+CERTS_FAIL(wrong_labels_3, {
+ certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
+ certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
+ REENCODE();
+ })
+CERTS_FAIL(server_missing_certs, {
+ d->c->handshake_state->started_here = 0;
+ })
+CERTS_FAIL(server_wrong_labels_1, {
+ d->c->handshake_state->started_here = 0;
+ certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
+ certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
+ REENCODE();
+ })
+
+static void
+test_link_handshake_send_authchallenge(void *arg)
+{
+ (void)arg;
+
+ or_connection_t *c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
+ var_cell_t *cell1=NULL, *cell2=NULL;
+
+ MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
+
+ tt_int_op(connection_init_or_handshake_state(c1, 0), ==, 0);
+ c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ tt_assert(! mock_got_var_cell);
+ tt_int_op(0, ==, connection_or_send_auth_challenge_cell(c1));
+ cell1 = mock_got_var_cell;
+ tt_int_op(0, ==, connection_or_send_auth_challenge_cell(c1));
+ cell2 = mock_got_var_cell;
+ tt_int_op(36, ==, cell1->payload_len);
+ tt_int_op(36, ==, cell2->payload_len);
+ tt_int_op(0, ==, cell1->circ_id);
+ tt_int_op(0, ==, cell2->circ_id);
+ tt_int_op(CELL_AUTH_CHALLENGE, ==, cell1->command);
+ tt_int_op(CELL_AUTH_CHALLENGE, ==, cell2->command);
+
+ tt_mem_op("\x00\x01\x00\x01", ==, cell1->payload + 32, 4);
+ tt_mem_op("\x00\x01\x00\x01", ==, cell2->payload + 32, 4);
+ tt_mem_op(cell1->payload, !=, cell2->payload, 32);
+
+ done:
+ UNMOCK(connection_or_write_var_cell_to_buf);
+ connection_free_(TO_CONN(c1));
+ tor_free(cell1);
+ tor_free(cell2);
+}
+
+typedef struct authchallenge_data_s {
+ or_connection_t *c;
+ channel_tls_t *chan;
+ var_cell_t *cell;
+} authchallenge_data_t;
+
+static int
+recv_authchallenge_cleanup(const struct testcase_t *test, void *obj)
+{
+ (void)test;
+ authchallenge_data_t *d = obj;
+
+ UNMOCK(connection_or_send_netinfo);
+ UNMOCK(connection_or_close_for_error);
+ UNMOCK(connection_or_send_authenticate_cell);
+
+ if (d) {
+ tor_free(d->cell);
+ connection_free_(TO_CONN(d->c));
+ circuitmux_free(d->chan->base_.cmux);
+ tor_free(d->chan);
+ tor_free(d);
+ }
+ return 1;
+}
+
+static void *
+recv_authchallenge_setup(const struct testcase_t *test)
+{
+ (void)test;
+ authchallenge_data_t *d = tor_malloc_zero(sizeof(*d));
+ d->c = or_connection_new(CONN_TYPE_OR, AF_INET);
+ d->chan = tor_malloc_zero(sizeof(*d->chan));
+ d->c->chan = d->chan;
+ d->c->base_.address = tor_strdup("HaveAnAddress");
+ d->c->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ d->chan->conn = d->c;
+ tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0);
+ d->c->link_proto = 4;
+ d->c->handshake_state->received_certs_cell = 1;
+ d->cell = var_cell_new(128);
+ d->cell->payload_len = 38;
+ d->cell->payload[33] = 2;
+ d->cell->payload[35] = 7;
+ d->cell->payload[37] = 1;
+ d->cell->command = CELL_AUTH_CHALLENGE;
+
+ get_options_mutable()->ORPort_set = 1;
+
+ MOCK(connection_or_close_for_error, mock_close_for_err);
+ MOCK(connection_or_send_netinfo, mock_send_netinfo);
+ MOCK(connection_or_send_authenticate_cell, mock_send_authenticate);
+
+ tt_int_op(0, ==, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(0, ==, mock_send_authenticate_called);
+ tt_int_op(0, ==, mock_send_netinfo_called);
+
+ return d;
+ done:
+ recv_authchallenge_cleanup(test, d);
+ return NULL;
+}
+
+static struct testcase_setup_t setup_recv_authchallenge = {
+ .setup_fn = recv_authchallenge_setup,
+ .cleanup_fn = recv_authchallenge_cleanup
+};
+
+static void
+test_link_handshake_recv_authchallenge_ok(void *arg)
+{
+ authchallenge_data_t *d = arg;
+
+ channel_tls_process_auth_challenge_cell(d->cell, d->chan);
+ tt_int_op(0, ==, mock_close_called);
+ tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(1, ==, mock_send_authenticate_called);
+ tt_int_op(1, ==, mock_send_netinfo_called);
+ done:
+ ;
+}
+
+static void
+test_link_handshake_recv_authchallenge_ok_noserver(void *arg)
+{
+ authchallenge_data_t *d = arg;
+ get_options_mutable()->ORPort_set = 0;
+
+ channel_tls_process_auth_challenge_cell(d->cell, d->chan);
+ tt_int_op(0, ==, mock_close_called);
+ tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(0, ==, mock_send_authenticate_called);
+ tt_int_op(0, ==, mock_send_netinfo_called);
+ done:
+ ;
+}
+
+static void
+test_link_handshake_recv_authchallenge_ok_unrecognized(void *arg)
+{
+ authchallenge_data_t *d = arg;
+ d->cell->payload[37] = 99;
+
+ channel_tls_process_auth_challenge_cell(d->cell, d->chan);
+ tt_int_op(0, ==, mock_close_called);
+ tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(0, ==, mock_send_authenticate_called);
+ tt_int_op(1, ==, mock_send_netinfo_called);
+ done:
+ ;
+}
+
+#define AUTHCHALLENGE_FAIL(name, code) \
+ static void \
+ test_link_handshake_recv_authchallenge_ ## name (void *arg) \
+ { \
+ authchallenge_data_t *d = arg; \
+ { code ; } \
+ channel_tls_process_auth_challenge_cell(d->cell, d->chan); \
+ tt_int_op(1, ==, mock_close_called); \
+ tt_int_op(0, ==, mock_send_authenticate_called); \
+ tt_int_op(0, ==, mock_send_netinfo_called); \
+ done: \
+ ; \
+ }
+
+AUTHCHALLENGE_FAIL(badstate,
+ d->c->base_.state = OR_CONN_STATE_CONNECTING)
+AUTHCHALLENGE_FAIL(badproto,
+ d->c->link_proto = 2)
+AUTHCHALLENGE_FAIL(as_server,
+ d->c->handshake_state->started_here = 0;)
+AUTHCHALLENGE_FAIL(duplicate,
+ d->c->handshake_state->received_auth_challenge = 1)
+AUTHCHALLENGE_FAIL(nocerts,
+ d->c->handshake_state->received_certs_cell = 0)
+AUTHCHALLENGE_FAIL(tooshort,
+ d->cell->payload_len = 33)
+AUTHCHALLENGE_FAIL(truncated,
+ d->cell->payload_len = 34)
+AUTHCHALLENGE_FAIL(nonzero_circid,
+ d->cell->circ_id = 1337)
+
+
+static tor_x509_cert_t *mock_peer_cert = NULL;
+static tor_x509_cert_t *
+mock_get_peer_cert(tor_tls_t *tls)
+{
+ (void)tls;
+ return mock_peer_cert;
+}
+
+static int
+mock_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
+{
+ (void)tls;
+ memcpy(secrets_out, "int getRandomNumber(){return 4;}", 32);
+ return 0;
+}
+
+static void
+mock_set_circid_type(channel_t *chan,
+ crypto_pk_t *identity_rcvd,
+ int consider_identity)
+{
+ (void) chan;
+ (void) identity_rcvd;
+ (void) consider_identity;
+}
+
+typedef struct authenticate_data_s {
+ or_connection_t *c1, *c2;
+ channel_tls_t *chan2;
+ var_cell_t *cell;
+ crypto_pk_t *key1, *key2;
+} authenticate_data_t;
+
+static int
+authenticate_data_cleanup(const struct testcase_t *test, void *arg)
+{
+ (void) test;
+ UNMOCK(connection_or_write_var_cell_to_buf);
+ UNMOCK(tor_tls_get_peer_cert);
+ UNMOCK(tor_tls_get_tlssecrets);
+ UNMOCK(connection_or_close_for_error);
+ UNMOCK(channel_set_circid_type);
+ authenticate_data_t *d = arg;
+ if (d) {
+ tor_free(d->cell);
+ connection_free_(TO_CONN(d->c1));
+ connection_free_(TO_CONN(d->c2));
+ circuitmux_free(d->chan2->base_.cmux);
+ tor_free(d->chan2);
+ crypto_pk_free(d->key1);
+ crypto_pk_free(d->key2);
+ tor_free(d);
+ }
+ mock_peer_cert = NULL;
+
+ return 1;
+}
+
+static void *
+authenticate_data_setup(const struct testcase_t *test)
+{
+ authenticate_data_t *d = tor_malloc_zero(sizeof(*d));
+
+ scheduler_init();
+
+ MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
+ MOCK(tor_tls_get_peer_cert, mock_get_peer_cert);
+ MOCK(tor_tls_get_tlssecrets, mock_get_tlssecrets);
+ MOCK(connection_or_close_for_error, mock_close_for_err);
+ MOCK(channel_set_circid_type, mock_set_circid_type);
+ d->c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
+ d->c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
+
+ d->key1 = pk_generate(2);
+ d->key2 = pk_generate(3);
+ tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
+ d->key1, d->key2, 86400), ==, 0);
+
+ d->c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ d->c1->link_proto = 3;
+ tt_int_op(connection_init_or_handshake_state(d->c1, 1), ==, 0);
+
+ d->c2->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ d->c2->link_proto = 3;
+ tt_int_op(connection_init_or_handshake_state(d->c2, 0), ==, 0);
+ var_cell_t *cell = var_cell_new(16);
+ cell->command = CELL_CERTS;
+ or_handshake_state_record_var_cell(d->c1, d->c1->handshake_state, cell, 1);
+ or_handshake_state_record_var_cell(d->c2, d->c2->handshake_state, cell, 0);
+ memset(cell->payload, 0xf0, 16);
+ or_handshake_state_record_var_cell(d->c1, d->c1->handshake_state, cell, 0);
+ or_handshake_state_record_var_cell(d->c2, d->c2->handshake_state, cell, 1);
+ tor_free(cell);
+
+ d->chan2 = tor_malloc_zero(sizeof(*d->chan2));
+ channel_tls_common_init(d->chan2);
+ d->c2->chan = d->chan2;
+ d->chan2->conn = d->c2;
+ d->c2->base_.address = tor_strdup("C2");
+ d->c2->tls = tor_tls_new(-1, 1);
+ d->c2->handshake_state->received_certs_cell = 1;
+
+ const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL, *auth_cert=NULL;
+ tt_assert(! tor_tls_get_my_certs(1, &link_cert, &id_cert));
+
+ const uint8_t *der;
+ size_t sz;
+ tor_x509_cert_get_der(id_cert, &der, &sz);
+ d->c1->handshake_state->id_cert = tor_x509_cert_decode(der, sz);
+ d->c2->handshake_state->id_cert = tor_x509_cert_decode(der, sz);
+
+ tor_x509_cert_get_der(link_cert, &der, &sz);
+ mock_peer_cert = tor_x509_cert_decode(der, sz);
+ tt_assert(mock_peer_cert);
+ tt_assert(! tor_tls_get_my_certs(0, &auth_cert, &id_cert));
+ tor_x509_cert_get_der(auth_cert, &der, &sz);
+ d->c2->handshake_state->auth_cert = tor_x509_cert_decode(der, sz);
+
+ /* Make an authenticate cell ... */
+ tt_int_op(0, ==, connection_or_send_authenticate_cell(d->c1,
+ AUTHTYPE_RSA_SHA256_TLSSECRET));
+ tt_assert(mock_got_var_cell);
+ d->cell = mock_got_var_cell;
+ mock_got_var_cell = NULL;
+
+ return d;
+ done:
+ authenticate_data_cleanup(test, d);
+ return NULL;
+}
+
+static struct testcase_setup_t setup_authenticate = {
+ .setup_fn = authenticate_data_setup,
+ .cleanup_fn = authenticate_data_cleanup
+};
+
+static void
+test_link_handshake_auth_cell(void *arg)
+{
+ authenticate_data_t *d = arg;
+ auth1_t *auth1 = NULL;
+ crypto_pk_t *auth_pubkey = NULL;
+
+ /* Is the cell well-formed on the outer layer? */
+ tt_int_op(d->cell->command, ==, CELL_AUTHENTICATE);
+ tt_int_op(d->cell->payload[0], ==, 0);
+ tt_int_op(d->cell->payload[1], ==, 1);
+ tt_int_op(ntohs(get_uint16(d->cell->payload + 2)), ==,
+ d->cell->payload_len - 4);
+
+ /* Check it out for plausibility... */
+ auth_ctx_t ctx;
+ ctx.is_ed = 0;
+ tt_int_op(d->cell->payload_len-4, ==, auth1_parse(&auth1,
+ d->cell->payload+4,
+ d->cell->payload_len - 4, &ctx));
+ tt_assert(auth1);
+
+ tt_mem_op(auth1->type, ==, "AUTH0001", 8);
+ tt_mem_op(auth1->tlssecrets, ==, "int getRandomNumber(){return 4;}", 32);
+ tt_int_op(auth1_getlen_sig(auth1), >, 120);
+
+ /* Is the signature okay? */
+ uint8_t sig[128];
+ uint8_t digest[32];
+
+ auth_pubkey = tor_tls_cert_get_key(d->c2->handshake_state->auth_cert);
+ int n = crypto_pk_public_checksig(
+ auth_pubkey,
+ (char*)sig, sizeof(sig), (char*)auth1_getarray_sig(auth1),
+ auth1_getlen_sig(auth1));
+ tt_int_op(n, ==, 32);
+ const uint8_t *start = d->cell->payload+4, *end = auth1->end_of_signed;
+ crypto_digest256((char*)digest,
+ (const char*)start, end-start, DIGEST_SHA256);
+ tt_mem_op(sig, ==, digest, 32);
+
+ /* Then feed it to c2. */
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 0);
+ channel_tls_process_authenticate_cell(d->cell, d->chan2);
+ tt_int_op(mock_close_called, ==, 0);
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 1);
+
+ done:
+ auth1_free(auth1);
+ crypto_pk_free(auth_pubkey);
+}
+
+#define AUTHENTICATE_FAIL(name, code) \
+ static void \
+ test_link_handshake_auth_ ## name (void *arg) \
+ { \
+ authenticate_data_t *d = arg; \
+ { code ; } \
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \
+ channel_tls_process_authenticate_cell(d->cell, d->chan2); \
+ tt_int_op(mock_close_called, ==, 1); \
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \
+ done: \
+ ; \
+ }
+
+AUTHENTICATE_FAIL(badstate,
+ d->c2->base_.state = OR_CONN_STATE_CONNECTING)
+AUTHENTICATE_FAIL(badproto,
+ d->c2->link_proto = 2)
+AUTHENTICATE_FAIL(atclient,
+ d->c2->handshake_state->started_here = 1)
+AUTHENTICATE_FAIL(duplicate,
+ d->c2->handshake_state->received_authenticate = 1)
+static void
+test_link_handshake_auth_already_authenticated(void *arg)
+{
+ authenticate_data_t *d = arg;
+ d->c2->handshake_state->authenticated = 1;
+ channel_tls_process_authenticate_cell(d->cell, d->chan2);
+ tt_int_op(mock_close_called, ==, 1);
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 1);
+ done:
+ ;
+}
+AUTHENTICATE_FAIL(nocerts,
+ d->c2->handshake_state->received_certs_cell = 0)
+AUTHENTICATE_FAIL(noidcert,
+ tor_x509_cert_free(d->c2->handshake_state->id_cert);
+ d->c2->handshake_state->id_cert = NULL)
+AUTHENTICATE_FAIL(noauthcert,
+ tor_x509_cert_free(d->c2->handshake_state->auth_cert);
+ d->c2->handshake_state->auth_cert = NULL)
+AUTHENTICATE_FAIL(tooshort,
+ d->cell->payload_len = 3)
+AUTHENTICATE_FAIL(badtype,
+ d->cell->payload[0] = 0xff)
+AUTHENTICATE_FAIL(truncated_1,
+ d->cell->payload[2]++)
+AUTHENTICATE_FAIL(truncated_2,
+ d->cell->payload[3]++)
+AUTHENTICATE_FAIL(tooshort_1,
+ tt_int_op(d->cell->payload_len, >=, 260);
+ d->cell->payload[2] -= 1;
+ d->cell->payload_len -= 256;)
+AUTHENTICATE_FAIL(badcontent,
+ d->cell->payload[10] ^= 0xff)
+AUTHENTICATE_FAIL(badsig_1,
+ d->cell->payload[d->cell->payload_len - 5] ^= 0xff)
+
+#define TEST(name, flags) \
+ { #name , test_link_handshake_ ## name, (flags), NULL, NULL }
+
+#define TEST_RCV_AUTHCHALLENGE(name) \
+ { "recv_authchallenge/" #name , \
+ test_link_handshake_recv_authchallenge_ ## name, TT_FORK, \
+ &setup_recv_authchallenge, NULL }
+
+#define TEST_RCV_CERTS(name) \
+ { "recv_certs/" #name , \
+ test_link_handshake_recv_certs_ ## name, TT_FORK, \
+ &setup_recv_certs, NULL }
+
+#define TEST_AUTHENTICATE(name) \
+ { "authenticate/" #name , test_link_handshake_auth_ ## name, TT_FORK, \
+ &setup_authenticate, NULL }
+
+struct testcase_t link_handshake_tests[] = {
+ TEST(certs_ok, TT_FORK),
+ //TEST(certs_bad, TT_FORK),
+ TEST_RCV_CERTS(ok),
+ TEST_RCV_CERTS(ok_server),
+ TEST_RCV_CERTS(badstate),
+ TEST_RCV_CERTS(badproto),
+ TEST_RCV_CERTS(duplicate),
+ TEST_RCV_CERTS(already_authenticated),
+ TEST_RCV_CERTS(empty),
+ TEST_RCV_CERTS(bad_circid),
+ TEST_RCV_CERTS(truncated_1),
+ TEST_RCV_CERTS(truncated_2),
+ TEST_RCV_CERTS(truncated_3),
+ TEST_RCV_CERTS(not_x509),
+ TEST_RCV_CERTS(both_link),
+ TEST_RCV_CERTS(both_id_rsa),
+ TEST_RCV_CERTS(both_auth),
+ TEST_RCV_CERTS(wrong_labels_1),
+ TEST_RCV_CERTS(wrong_labels_2),
+ TEST_RCV_CERTS(wrong_labels_3),
+ TEST_RCV_CERTS(server_missing_certs),
+ TEST_RCV_CERTS(server_wrong_labels_1),
+
+ TEST(send_authchallenge, TT_FORK),
+ TEST_RCV_AUTHCHALLENGE(ok),
+ TEST_RCV_AUTHCHALLENGE(ok_noserver),
+ TEST_RCV_AUTHCHALLENGE(ok_unrecognized),
+ TEST_RCV_AUTHCHALLENGE(badstate),
+ TEST_RCV_AUTHCHALLENGE(badproto),
+ TEST_RCV_AUTHCHALLENGE(as_server),
+ TEST_RCV_AUTHCHALLENGE(duplicate),
+ TEST_RCV_AUTHCHALLENGE(nocerts),
+ TEST_RCV_AUTHCHALLENGE(tooshort),
+ TEST_RCV_AUTHCHALLENGE(truncated),
+ TEST_RCV_AUTHCHALLENGE(nonzero_circid),
+
+ TEST_AUTHENTICATE(cell),
+ TEST_AUTHENTICATE(badstate),
+ TEST_AUTHENTICATE(badproto),
+ TEST_AUTHENTICATE(atclient),
+ TEST_AUTHENTICATE(duplicate),
+ TEST_AUTHENTICATE(already_authenticated),
+ TEST_AUTHENTICATE(nocerts),
+ TEST_AUTHENTICATE(noidcert),
+ TEST_AUTHENTICATE(noauthcert),
+ TEST_AUTHENTICATE(tooshort),
+ TEST_AUTHENTICATE(badtype),
+ TEST_AUTHENTICATE(truncated_1),
+ TEST_AUTHENTICATE(truncated_2),
+ TEST_AUTHENTICATE(tooshort_1),
+ TEST_AUTHENTICATE(badcontent),
+ TEST_AUTHENTICATE(badsig_1),
+ //TEST_AUTHENTICATE(),
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index fb3df77edc..3c22e1809a 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -10,6 +10,7 @@
#include "networkstatus.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "torcert.h"
#include "test.h"
@@ -335,6 +336,59 @@ static const char test_ri[] =
"t0xkIE39ss/EwmQr7iIgkdVH4oRIMsjYnFFJBG26nYY=\n"
"-----END SIGNATURE-----\n";
+static const char test_ri2[] =
+ "router test001a 127.0.0.1 5001 0 7001\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf/FAf5iDuKCZP2VxnAaQWdklilAh6kaEeFX4z8261Yx2T1/AQAgBADCp8vO\n"
+ "B8K1F9g2DzwuwvVCnPFLSK1qknVqPpNucHLH9DY7fuIYogBAdz4zHv1qC7RKaMNG\n"
+ "Jux/tMO2tzPcm62Ky5PjClMQplKUOnZNQ+RIpA3wYCIfUDy/cQnY7XWgNQ0=\n"
+ "-----END ED25519 CERT-----\n"
+ "platform Tor 0.2.6.0-alpha-dev on Darwin\n"
+ "protocols Link 1 2 Circuit 1\n"
+ "published 2014-10-08 12:58:04\n"
+ "fingerprint B7E2 7F10 4213 C36F 13E7 E982 9182 845E 4959 97A0\n"
+ "uptime 0\n"
+ "bandwidth 1073741824 1073741824 0\n"
+ "extra-info-digest 568F27331B6D8C73E7024F1EF5D097B90DFC7CDB\n"
+ "caches-extra-info\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n"
+ "+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n"
+ "l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAN8+78KUVlgHXdMMkYJxcwh1Zv2y+Gb5eWUyltUaQRajhrT9ij2T5JZs\n"
+ "M0g85xTcuM3jNVVpV79+33hiTohdC6UZ+Bk4USQ7WBFzRbVFSXoVKLBJFkCOIexg\n"
+ "SMGNd5WEDtHWrXl58mizmPFu1eG6ZxHzt7RuLSol5cwBvawXPNkFAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "ETFDzU49bvNfoZnKK1j6JeBP2gDirgj6bBCgWpUYs663OO9ypbZRO0JwWANssKl6\n"
+ "oaq9vKTsKGRsaNnqnz/JGMhehymakjjNtqg7crWwsahe8+7Pw9GKmW+YjFtcOkUf\n"
+ "KfOn2bmKBa1FoJb4yW3oXzHcdlLSRuCciKqPn+Hky5o=\n"
+ "-----END CROSSCERT-----\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf2dAcKny84HwrUX2DYPPC7C9UKc8UtIrWqSdWo+k25wcsf0AFohutG+xI06\n"
+ "Ef21c5Zl1j8Hw6DzHDjYyJevXLFuOneaL3zcH2Ldn4sjrG3kc5UuVvRfTvV120UO\n"
+ "xk4f5s5LGwY=\n"
+ "-----END ED25519 CERT-----\n"
+ "hidden-service-dir\n"
+ "contact auth1@test.test\n"
+ "ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n"
+ "reject *:*\n"
+ "router-sig-ed25519 5aQXyTif7PExIuL2di37UvktmJECKnils2OWz2vDi"
+ "hFxi+5TTAAPxYkS5clhc/Pjvw34itfjGmTKFic/8httAQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "BaUB+aFPQbb3BwtdzKsKqV3+6cRlSqJF5bI3UTmwRoJk+Z5Pz+W5NWokNI0xArHM\n"
+ "T4T5FZCCP9350jXsUCIvzyIyktU6aVRCGFt76rFlo1OETpN8GWkMnQU0w18cxvgS\n"
+ "cf34GXHv61XReJF3AlzNHFpbrPOYmowmhrTULKyMqow=\n"
+ "-----END SIGNATURE-----\n";
+
static const char test_md_8[] =
"onion-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
@@ -365,6 +419,26 @@ static const char test_md_18[] =
"p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
"id rsa1024 Cd47okjCHD83YGzThGBDptXs9Z4\n";
+static const char test_md2_18[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n"
+ "+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n"
+ "l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n"
+ "id rsa1024 t+J/EEITw28T5+mCkYKEXklZl6A\n";
+
+static const char test_md2_21[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n"
+ "+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n"
+ "l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n"
+ "id ed25519 wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n";
+
static void
test_md_generate(void *arg)
{
@@ -391,6 +465,25 @@ test_md_generate(void *arg)
md = dirvote_create_microdescriptor(ri, 18);
tt_str_op(md->body, OP_EQ, test_md_18);
+ microdesc_free(md);
+ md = NULL;
+ md = dirvote_create_microdescriptor(ri, 21);
+ tt_str_op(md->body, ==, test_md_18);
+
+ ri = router_parse_entry_from_string(test_ri2, NULL, 0, 0, NULL, NULL);
+
+ microdesc_free(md);
+ md = NULL;
+ md = dirvote_create_microdescriptor(ri, 18);
+ tt_str_op(md->body, ==, test_md2_18);
+
+ microdesc_free(md);
+ md = NULL;
+ md = dirvote_create_microdescriptor(ri, 21);
+ tt_str_op(md->body, ==, test_md2_21);
+ tt_assert(ed25519_pubkey_eq(md->ed25519_identity_pkey,
+ &ri->signing_key_cert->signing_key));
+
done:
microdesc_free(md);
routerinfo_free(ri);
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index 60b6bb5a72..26f9701f49 100644
--- a/src/test/test_routerkeys.c
+++ b/src/test/test_routerkeys.c
@@ -8,11 +8,17 @@
#include "or.h"
#include "config.h"
#include "router.h"
+#include "routerkeys.h"
#include "util.h"
#include "crypto.h"
-
+#include "torcert.h"
#include "test.h"
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#endif
+
static void
test_routerkeys_write_fingerprint(void *arg)
{
@@ -75,11 +81,543 @@ test_routerkeys_write_fingerprint(void *arg)
tor_free(cp2);
}
+static void
+test_routerkeys_ed_certs(void *args)
+{
+ (void)args;
+ ed25519_keypair_t kp1, kp2;
+ tor_cert_t *cert[2] = {NULL, NULL};
+ tor_cert_t *parsed_cert[2] = {NULL, NULL};
+ time_t now = 1412094534;
+ uint8_t *junk = NULL;
+ char *base64 = NULL;
+
+ tt_int_op(0,==,ed25519_keypair_generate(&kp1, 0));
+ tt_int_op(0,==,ed25519_keypair_generate(&kp2, 0));
+
+ for (int i = 0; i <= 1; ++i) {
+ uint32_t flags = i ? CERT_FLAG_INCLUDE_SIGNING_KEY : 0;
+
+ cert[i] = tor_cert_create(&kp1, 5, &kp2.pubkey, now, 10000, flags);
+ tt_assert(cert[i]);
+
+ tt_assert(cert[i]->sig_bad == 0);
+ tt_assert(cert[i]->sig_ok == 1);
+ tt_assert(cert[i]->cert_expired == 0);
+ tt_assert(cert[i]->cert_valid == 1);
+ tt_int_op(cert[i]->cert_type, ==, 5);
+ tt_mem_op(cert[i]->signed_key.pubkey, ==, &kp2.pubkey.pubkey, 32);
+ tt_mem_op(cert[i]->signing_key.pubkey, ==, &kp1.pubkey.pubkey, 32);
+ tt_int_op(cert[i]->signing_key_included, ==, i);
+
+ tt_assert(cert[i]->encoded);
+ tt_int_op(cert[i]->encoded_len, ==, 104 + 36 * i);
+ tt_int_op(cert[i]->encoded[0], ==, 1);
+ tt_int_op(cert[i]->encoded[1], ==, 5);
+
+ parsed_cert[i] = tor_cert_parse(cert[i]->encoded, cert[i]->encoded_len);
+ tt_assert(parsed_cert[i]);
+ tt_int_op(cert[i]->encoded_len, ==, parsed_cert[i]->encoded_len);
+ tt_mem_op(cert[i]->encoded, ==, parsed_cert[i]->encoded,
+ cert[i]->encoded_len);
+ tt_assert(parsed_cert[i]->sig_bad == 0);
+ tt_assert(parsed_cert[i]->sig_ok == 0);
+ tt_assert(parsed_cert[i]->cert_expired == 0);
+ tt_assert(parsed_cert[i]->cert_valid == 0);
+
+ /* Expired */
+ tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now + 30000),
+ <, 0);
+ tt_assert(parsed_cert[i]->cert_expired == 1);
+ parsed_cert[i]->cert_expired = 0;
+
+ /* Wrong key */
+ tt_int_op(tor_cert_checksig(parsed_cert[i], &kp2.pubkey, now), <, 0);
+ tt_assert(parsed_cert[i]->sig_bad== 1);
+ parsed_cert[i]->sig_bad = 0;
+
+ /* Missing key */
+ int ok = tor_cert_checksig(parsed_cert[i], NULL, now);
+ tt_int_op(ok < 0, ==, i == 0);
+ tt_assert(parsed_cert[i]->sig_bad == 0);
+ tt_assert(parsed_cert[i]->sig_ok == (i != 0));
+ tt_assert(parsed_cert[i]->cert_valid == (i != 0));
+ parsed_cert[i]->sig_bad = 0;
+ parsed_cert[i]->sig_ok = 0;
+ parsed_cert[i]->cert_valid = 0;
+
+ /* Right key */
+ tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now), ==, 0);
+ tt_assert(parsed_cert[i]->sig_bad == 0);
+ tt_assert(parsed_cert[i]->sig_ok == 1);
+ tt_assert(parsed_cert[i]->cert_expired == 0);
+ tt_assert(parsed_cert[i]->cert_valid == 1);
+ }
+
+ /* Now try some junky certs. */
+ /* - Truncated */
+ tt_ptr_op(NULL, ==,tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len-1));
+
+ /* - First byte modified */
+ cert[0]->encoded[0] = 99;
+ tt_ptr_op(NULL, ==,tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len));
+ cert[0]->encoded[0] = 1;
+
+ /* - Extra byte at the end*/
+ junk = tor_malloc_zero(cert[0]->encoded_len + 1);
+ memcpy(junk, cert[0]->encoded, cert[0]->encoded_len);
+ tt_ptr_op(NULL, ==, tor_cert_parse(junk, cert[0]->encoded_len+1));
+
+ /* - Multiple signing key instances */
+ tor_free(junk);
+ junk = tor_malloc_zero(104 + 36 * 2);
+ junk[0] = 1; /* version */
+ junk[1] = 5; /* cert type */
+ junk[6] = 1; /* key type */
+ junk[39] = 2; /* n_extensions */
+ junk[41] = 32; /* extlen */
+ junk[42] = 4; /* exttype */
+ junk[77] = 32; /* extlen */
+ junk[78] = 4; /* exttype */
+ tt_ptr_op(NULL, ==, tor_cert_parse(junk, 104 + 36 * 2));
+
+ done:
+ tor_cert_free(cert[0]);
+ tor_cert_free(cert[1]);
+ tor_cert_free(parsed_cert[0]);
+ tor_cert_free(parsed_cert[1]);
+ tor_free(junk);
+ tor_free(base64);
+}
+
+static void
+test_routerkeys_ed_key_create(void *arg)
+{
+ (void)arg;
+ tor_cert_t *cert = NULL;
+ ed25519_keypair_t *kp1 = NULL, *kp2 = NULL;
+ time_t now = time(NULL);
+
+ /* This is a simple alias for 'make a new keypair' */
+ kp1 = ed_key_new(NULL, 0, 0, 0, 0, &cert);
+ tt_assert(kp1);
+
+ /* Create a new certificate signed by kp1. */
+ kp2 = ed_key_new(kp1, INIT_ED_KEY_NEEDCERT, now, 3600, 4, &cert);
+ tt_assert(kp2);
+ tt_assert(cert);
+ tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, sizeof(ed25519_public_key_t));
+ tt_assert(! cert->signing_key_included);
+
+ tt_int_op(cert->valid_until, >=, now);
+ tt_int_op(cert->valid_until, <=, now+7200);
+
+ /* Create a new key-including certificate signed by kp1 */
+ ed25519_keypair_free(kp2);
+ tor_cert_free(cert);
+ cert = NULL; kp2 = NULL;
+ kp2 = ed_key_new(kp1, (INIT_ED_KEY_NEEDCERT|
+ INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT),
+ now, 3600, 4, &cert);
+ tt_assert(kp2);
+ tt_assert(cert);
+ tt_assert(cert->signing_key_included);
+ tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, sizeof(ed25519_public_key_t));
+ tt_mem_op(&cert->signing_key, ==, &kp1->pubkey,sizeof(ed25519_public_key_t));
+
+ done:
+ ed25519_keypair_free(kp1);
+ ed25519_keypair_free(kp2);
+ tor_cert_free(cert);
+}
+
+static void
+test_routerkeys_ed_key_init_basic(void *arg)
+{
+ (void) arg;
+
+ tor_cert_t *cert = NULL, *cert2 = NULL;
+ ed25519_keypair_t *kp1 = NULL, *kp2 = NULL, *kp3 = NULL;
+ time_t now = time(NULL);
+ char *fname1 = tor_strdup(get_fname("test_ed_key_1"));
+ char *fname2 = tor_strdup(get_fname("test_ed_key_2"));
+ struct stat st;
+
+ unlink(fname1);
+ unlink(fname2);
+
+ /* Fail to load a key that isn't there. */
+ kp1 = ed_key_init_from_file(fname1, 0, LOG_INFO, NULL, now, 0, 7, &cert);
+ tt_assert(kp1 == NULL);
+ tt_assert(cert == NULL);
+
+ /* Create the key if requested to do so. */
+ kp1 = ed_key_init_from_file(fname1, INIT_ED_KEY_CREATE, LOG_INFO,
+ NULL, now, 0, 7, &cert);
+ tt_assert(kp1 != NULL);
+ tt_assert(cert == NULL);
+ tt_int_op(stat(get_fname("test_ed_key_1_cert"), &st), <, 0);
+ tt_int_op(stat(get_fname("test_ed_key_1_secret_key"), &st), ==, 0);
+
+ /* Fail to load if we say we need a cert */
+ kp2 = ed_key_init_from_file(fname1, INIT_ED_KEY_NEEDCERT, LOG_INFO,
+ NULL, now, 0, 7, &cert);
+ tt_assert(kp2 == NULL);
+
+ /* Fail to load if we say the wrong key type */
+ kp2 = ed_key_init_from_file(fname1, 0, LOG_INFO,
+ NULL, now, 0, 6, &cert);
+ tt_assert(kp2 == NULL);
+
+ /* Load successfully if we're not picky, whether we say "create" or not. */
+ kp2 = ed_key_init_from_file(fname1, INIT_ED_KEY_CREATE, LOG_INFO,
+ NULL, now, 0, 7, &cert);
+ tt_assert(kp2 != NULL);
+ tt_assert(cert == NULL);
+ tt_mem_op(kp1, ==, kp2, sizeof(*kp1));
+ ed25519_keypair_free(kp2); kp2 = NULL;
+
+ kp2 = ed_key_init_from_file(fname1, 0, LOG_INFO,
+ NULL, now, 0, 7, &cert);
+ tt_assert(kp2 != NULL);
+ tt_assert(cert == NULL);
+ tt_mem_op(kp1, ==, kp2, sizeof(*kp1));
+ ed25519_keypair_free(kp2); kp2 = NULL;
+
+ /* Now create a key with a cert. */
+ kp2 = ed_key_init_from_file(fname2, (INIT_ED_KEY_CREATE|
+ INIT_ED_KEY_NEEDCERT),
+ LOG_INFO, kp1, now, 7200, 7, &cert);
+ tt_assert(kp2 != NULL);
+ tt_assert(cert != NULL);
+ tt_mem_op(kp1, !=, kp2, sizeof(*kp1));
+ tt_int_op(stat(get_fname("test_ed_key_2_cert"), &st), ==, 0);
+ tt_int_op(stat(get_fname("test_ed_key_2_secret_key"), &st), ==, 0);
+
+ tt_assert(cert->cert_valid == 1);
+ tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, 32);
+
+ /* Now verify we can load the cert... */
+ kp3 = ed_key_init_from_file(fname2, (INIT_ED_KEY_CREATE|
+ INIT_ED_KEY_NEEDCERT),
+ LOG_INFO, kp1, now, 7200, 7, &cert2);
+ tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
+ tt_mem_op(cert2->encoded, ==, cert->encoded, cert->encoded_len);
+ ed25519_keypair_free(kp3); kp3 = NULL;
+ tor_cert_free(cert2); cert2 = NULL;
+
+ /* ... even without create... */
+ kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
+ LOG_INFO, kp1, now, 7200, 7, &cert2);
+ tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
+ tt_mem_op(cert2->encoded, ==, cert->encoded, cert->encoded_len);
+ ed25519_keypair_free(kp3); kp3 = NULL;
+ tor_cert_free(cert2); cert2 = NULL;
+
+ /* ... but that we don't crash or anything if we say we don't want it. */
+ kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
+ LOG_INFO, kp1, now, 7200, 7, NULL);
+ tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
+ ed25519_keypair_free(kp3); kp3 = NULL;
+
+ /* Fail if we're told the wrong signing key */
+ kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
+ LOG_INFO, kp2, now, 7200, 7, &cert2);
+ tt_assert(kp3 == NULL);
+ tt_assert(cert2 == NULL);
+
+ done:
+ ed25519_keypair_free(kp1);
+ ed25519_keypair_free(kp2);
+ ed25519_keypair_free(kp3);
+ tor_cert_free(cert);
+ tor_cert_free(cert2);
+ tor_free(fname1);
+ tor_free(fname2);
+}
+
+static void
+test_routerkeys_ed_key_init_split(void *arg)
+{
+ (void) arg;
+
+ tor_cert_t *cert = NULL;
+ ed25519_keypair_t *kp1 = NULL, *kp2 = NULL;
+ time_t now = time(NULL);
+ char *fname1 = tor_strdup(get_fname("test_ed_key_3"));
+ char *fname2 = tor_strdup(get_fname("test_ed_key_4"));
+ struct stat st;
+ const uint32_t flags = INIT_ED_KEY_SPLIT|INIT_ED_KEY_MISSING_SECRET_OK;
+
+ unlink(fname1);
+ unlink(fname2);
+
+ /* Can't load key that isn't there. */
+ kp1 = ed_key_init_from_file(fname1, flags, LOG_INFO, NULL, now, 0, 7, &cert);
+ tt_assert(kp1 == NULL);
+ tt_assert(cert == NULL);
+
+ /* Create a split key */
+ kp1 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
+ LOG_INFO, NULL, now, 0, 7, &cert);
+ tt_assert(kp1 != NULL);
+ tt_assert(cert == NULL);
+ tt_int_op(stat(get_fname("test_ed_key_3_cert"), &st), <, 0);
+ tt_int_op(stat(get_fname("test_ed_key_3_secret_key"), &st), ==, 0);
+ tt_int_op(stat(get_fname("test_ed_key_3_public_key"), &st), ==, 0);
+
+ /* Load it. */
+ kp2 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
+ LOG_INFO, NULL, now, 0, 7, &cert);
+ tt_assert(kp2 != NULL);
+ tt_assert(cert == NULL);
+ tt_mem_op(kp1, ==, kp2, sizeof(*kp2));
+ ed25519_keypair_free(kp2); kp2 = NULL;
+
+ /* Okay, try killing the secret key and loading it. */
+ unlink(get_fname("test_ed_key_3_secret_key"));
+ kp2 = ed_key_init_from_file(fname1, flags,
+ LOG_INFO, NULL, now, 0, 7, &cert);
+ tt_assert(kp2 != NULL);
+ tt_assert(cert == NULL);
+ tt_mem_op(&kp1->pubkey, ==, &kp2->pubkey, sizeof(kp2->pubkey));
+ tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
+ sizeof(kp2->seckey.seckey)));
+ ed25519_keypair_free(kp2); kp2 = NULL;
+
+ /* Even when we're told to "create", don't create if there's a public key */
+ kp2 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
+ LOG_INFO, NULL, now, 0, 7, &cert);
+ tt_assert(kp2 != NULL);
+ tt_assert(cert == NULL);
+ tt_mem_op(&kp1->pubkey, ==, &kp2->pubkey, sizeof(kp2->pubkey));
+ tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
+ sizeof(kp2->seckey.seckey)));
+ ed25519_keypair_free(kp2); kp2 = NULL;
+
+ /* Make sure we fail on a tag mismatch, though */
+ kp2 = ed_key_init_from_file(fname1, flags,
+ LOG_INFO, NULL, now, 0, 99, &cert);
+ tt_assert(kp2 == NULL);
+
+ done:
+ ed25519_keypair_free(kp1);
+ ed25519_keypair_free(kp2);
+ tor_cert_free(cert);
+ tor_free(fname1);
+ tor_free(fname2);
+}
+
+static void
+test_routerkeys_ed_keys_init_all(void *arg)
+{
+ (void)arg;
+ char *dir = tor_strdup(get_fname("test_ed_keys_init_all"));
+ or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
+ time_t now = time(NULL);
+ ed25519_public_key_t id;
+ ed25519_keypair_t sign, auth;
+ tor_cert_t *link_cert = NULL;
+
+ get_options_mutable()->ORPort_set = 1;
+
+ crypto_pk_t *rsa = pk_generate(0);
+
+ set_server_identity_key(rsa);
+ set_client_identity_key(rsa);
+
+ router_initialize_tls_context();
+
+ options->SigningKeyLifetime = 30*86400;
+ options->TestingAuthKeyLifetime = 2*86400;
+ options->TestingLinkCertLifetime = 2*86400;
+ options->TestingSigningKeySlop = 2*86400;
+ options->TestingAuthKeySlop = 2*3600;
+ options->TestingLinkKeySlop = 2*3600;
+
+#ifdef _WIN32
+ mkdir(dir);
+ mkdir(get_fname("test_ed_keys_init_all/keys"));
+#else
+ mkdir(dir, 0700);
+ mkdir(get_fname("test_ed_keys_init_all/keys"), 0700);
+#endif
+
+ options->DataDirectory = dir;
+
+ tt_int_op(0, ==, load_ed_keys(options, now));
+ tt_int_op(0, ==, generate_ed_link_cert(options, now));
+ tt_assert(get_master_identity_key());
+ tt_assert(get_master_identity_key());
+ tt_assert(get_master_signing_keypair());
+ tt_assert(get_current_auth_keypair());
+ tt_assert(get_master_signing_key_cert());
+ tt_assert(get_current_link_cert_cert());
+ tt_assert(get_current_auth_key_cert());
+ memcpy(&id, get_master_identity_key(), sizeof(id));
+ memcpy(&sign, get_master_signing_keypair(), sizeof(sign));
+ memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
+ link_cert = tor_cert_dup(get_current_link_cert_cert());
+
+ /* Call load_ed_keys again, but nothing has changed. */
+ tt_int_op(0, ==, load_ed_keys(options, now));
+ tt_int_op(0, ==, generate_ed_link_cert(options, now));
+ tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
+ tt_mem_op(&auth, ==, get_current_auth_keypair(), sizeof(auth));
+ tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));
+
+ /* Force a reload: we make new link/auth keys. */
+ routerkeys_free_all();
+ tt_int_op(0, ==, load_ed_keys(options, now));
+ tt_int_op(0, ==, generate_ed_link_cert(options, now));
+ tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
+ tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));
+ tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
+ tt_assert(get_master_signing_key_cert());
+ tt_assert(get_current_link_cert_cert());
+ tt_assert(get_current_auth_key_cert());
+ tor_cert_free(link_cert);
+ link_cert = tor_cert_dup(get_current_link_cert_cert());
+ memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
+
+ /* Force a link/auth-key regeneration by advancing time. */
+ tt_int_op(0, ==, load_ed_keys(options, now+3*86400));
+ tt_int_op(0, ==, generate_ed_link_cert(options, now+3*86400));
+ tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
+ tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
+ tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
+ tt_assert(get_master_signing_key_cert());
+ tt_assert(get_current_link_cert_cert());
+ tt_assert(get_current_auth_key_cert());
+ tor_cert_free(link_cert);
+ link_cert = tor_cert_dup(get_current_link_cert_cert());
+ memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
+
+ /* Force a signing-key regeneration by advancing time. */
+ tt_int_op(0, ==, load_ed_keys(options, now+100*86400));
+ tt_int_op(0, ==, generate_ed_link_cert(options, now+100*86400));
+ tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, !=, get_master_signing_keypair(), sizeof(sign));
+ tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
+ tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
+ tt_assert(get_master_signing_key_cert());
+ tt_assert(get_current_link_cert_cert());
+ tt_assert(get_current_auth_key_cert());
+ memcpy(&sign, get_master_signing_keypair(), sizeof(sign));
+ tor_cert_free(link_cert);
+ link_cert = tor_cert_dup(get_current_link_cert_cert());
+ memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
+
+ /* Demonstrate that we can start up with no secret identity key */
+ routerkeys_free_all();
+ unlink(get_fname("test_ed_keys_init_all/keys/"
+ "ed25519_master_id_secret_key"));
+ tt_int_op(0, ==, load_ed_keys(options, now));
+ tt_int_op(0, ==, generate_ed_link_cert(options, now));
+ tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
+ tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
+ tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
+ tt_assert(get_master_signing_key_cert());
+ tt_assert(get_current_link_cert_cert());
+ tt_assert(get_current_auth_key_cert());
+
+ /* But we're in trouble if we have no id key and our signing key has
+ expired. */
+ log_global_min_severity_ = LOG_ERR; /* Suppress warnings.
+ * XXX (better way to do this)? */
+ routerkeys_free_all();
+ tt_int_op(-1, ==, load_ed_keys(options, now+200*86400));
+
+ done:
+ tor_free(dir);
+ tor_free(options);
+ routerkeys_free_all();
+}
+
+static void
+test_routerkeys_cross_certify_ntor(void *args)
+{
+ (void) args;
+
+ tor_cert_t *cert = NULL;
+ curve25519_keypair_t onion_keys;
+ ed25519_public_key_t master_key;
+ ed25519_public_key_t onion_check_key;
+ time_t now = time(NULL);
+ int sign;
+
+ tt_int_op(0, ==, ed25519_public_from_base64(&master_key,
+ "IamwritingthesetestsOnARainyAfternoonin2014"));
+ tt_int_op(0, ==, curve25519_keypair_generate(&onion_keys, 0));
+ cert = make_ntor_onion_key_crosscert(&onion_keys,
+ &master_key,
+ now, 10000,
+ &sign);
+ tt_assert(cert);
+ tt_assert(sign == 0 || sign == 1);
+ tt_int_op(cert->cert_type, ==, CERT_TYPE_ONION_ID);
+ tt_int_op(1, ==, ed25519_pubkey_eq(&cert->signed_key, &master_key));
+ tt_int_op(0, ==, ed25519_public_key_from_curve25519_public_key(
+ &onion_check_key, &onion_keys.pubkey, sign));
+ tt_int_op(0, ==, tor_cert_checksig(cert, &onion_check_key, now));
+
+ done:
+ tor_cert_free(cert);
+}
+
+static void
+test_routerkeys_cross_certify_tap(void *args)
+{
+ (void)args;
+ uint8_t *cc = NULL;
+ int cc_len;
+ ed25519_public_key_t master_key;
+ crypto_pk_t *onion_key = pk_generate(2), *id_key = pk_generate(1);
+ char digest[20];
+ char buf[128];
+ int n;
+
+ tt_int_op(0, ==, ed25519_public_from_base64(&master_key,
+ "IAlreadyWroteTestsForRouterdescsUsingTheseX"));
+
+ cc = make_tap_onion_key_crosscert(onion_key,
+ &master_key,
+ id_key, &cc_len);
+ tt_assert(cc);
+ tt_assert(cc_len);
+
+ n = crypto_pk_public_checksig(onion_key, buf, sizeof(buf),
+ (char*)cc, cc_len);
+ tt_int_op(n,>,0);
+ tt_int_op(n,==,52);
+
+ crypto_pk_get_digest(id_key, digest);
+ tt_mem_op(buf,==,digest,20);
+ tt_mem_op(buf+20,==,master_key.pubkey,32);
+
+ tt_int_op(0, ==, check_tap_onion_key_crosscert(cc, cc_len,
+ onion_key, &master_key, (uint8_t*)digest));
+
+ done:
+ tor_free(cc);
+}
+
#define TEST(name, flags) \
{ #name , test_routerkeys_ ## name, (flags), NULL, NULL }
struct testcase_t routerkeys_tests[] = {
TEST(write_fingerprint, TT_FORK),
+ TEST(ed_certs, TT_FORK),
+ TEST(ed_key_create, TT_FORK),
+ TEST(ed_key_init_basic, TT_FORK),
+ TEST(ed_key_init_split, TT_FORK),
+ TEST(ed_keys_init_all, TT_FORK),
+ TEST(cross_certify_ntor, 0),
+ TEST(cross_certify_tap, 0),
END_OF_TESTCASES
};