test_keypin.c (9939B)
1 /* Copyright (c) 2014-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 #include "orconfig.h" 5 #define KEYPIN_PRIVATE 6 #include "core/or/or.h" 7 #include "feature/dirauth/keypin.h" 8 9 #include "test/test.h" 10 11 static void 12 test_keypin_parse_line(void *arg) 13 { 14 (void)arg; 15 keypin_ent_t *ent = NULL; 16 17 /* Good line */ 18 ent = keypin_parse_journal_line( 19 "aGVyZSBpcyBhIGdvb2Qgc2hhMSE " 20 "VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4"); 21 tt_assert(ent); 22 tt_mem_op(ent->rsa_id, OP_EQ, "here is a good sha1!", 20); 23 tt_mem_op(ent->ed25519_key, OP_EQ, "This ed25519 scoffs at the sha1.", 32); 24 tor_free(ent); ent = NULL; 25 26 /* Good line with extra stuff we will ignore. */ 27 ent = keypin_parse_journal_line( 28 "aGVyZSBpcyBhIGdvb2Qgc2hhMSE " 29 "VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4helloworld"); 30 tt_assert(ent); 31 tt_mem_op(ent->rsa_id, OP_EQ, "here is a good sha1!", 20); 32 tt_mem_op(ent->ed25519_key, OP_EQ, "This ed25519 scoffs at the sha1.", 32); 33 tor_free(ent); ent = NULL; 34 35 /* Bad line: no space in the middle. */ 36 ent = keypin_parse_journal_line( 37 "aGVyZSBpcyBhIGdvb2Qgc2hhMSE?" 38 "VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4"); 39 tt_ptr_op(ent, OP_EQ, NULL); 40 41 /* Bad line: bad base64 in RSA ID */ 42 ent = keypin_parse_journal_line( 43 "aGVyZSBpcyBhIGdv!2Qgc2hhMSE " 44 "VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4"); 45 tt_ptr_op(ent, OP_EQ, NULL); 46 47 /* Bad line: bad base64 in Ed25519 */ 48 ent = keypin_parse_journal_line( 49 "aGVyZSBpcyBhIGdvb2Qgc2hhMSE " 50 "VGhpcyBlZDI1NTE5IHNjb2ZmcyB!dCB0aGUgc2hhMS4"); 51 tt_ptr_op(ent, OP_EQ, NULL); 52 53 done: 54 tor_free(ent); 55 } 56 57 static smartlist_t *mock_addent_got = NULL; 58 static void 59 mock_addent(keypin_ent_t *ent) 60 { 61 smartlist_add(mock_addent_got, ent); 62 keypin_add_entry_to_map__real(ent); 63 } 64 65 static void 66 test_keypin_parse_file(void *arg) 67 { 68 (void)arg; 69 70 mock_addent_got = smartlist_new(); 71 MOCK(keypin_add_entry_to_map, mock_addent); 72 73 /* Simple, minimal, correct example. */ 74 const char data1[] = 75 "PT09PT09PT09PT09PT09PT09PT0 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0\n" 76 "TG9yYXggaXBzdW0gZ3J1dnZ1bHU cyB0aG5lZWQgYW1ldCwgc25lcmdlbGx5IG9uY2UtbGU\n" 77 "ciBsZXJraW0sIHNlZCBkbyBiYXI YmFsb290IHRlbXBvciBnbHVwcGl0dXMgdXQgbGFib3I\n" 78 "ZSBldCB0cnVmZnVsYSBtYWduYSA YWxpcXVhLiBVdCBlbmltIGFkIGdyaWNrbGUtZ3Jhc3M\n" 79 "dmVuaWFtLCBxdWlzIG1pZmYtbXU ZmZlcmVkIGdhLXp1bXBjbyBsYWJvcmlzIG5pc2kgdXQ\n" 80 "Y3J1ZmZ1bHVzIGV4IGVhIHNjaGw b3BwaXR5IGNvbnNlcXVhdC4gRHVpcyBhdXRlIHNuYXI\n" 81 "Z2dsZSBpbiBzd29tZWVzd2FucyA aW4gdm9sdXB0YXRlIGF4ZS1oYWNrZXIgZXNzZSByaXA\n" 82 "cHVsdXMgY3J1bW1paSBldSBtb28 ZiBudWxsYSBzbnV2di5QTFVHSFBMT1ZFUlhZWlpZLi4\n"; 83 84 tt_int_op(0, OP_EQ, keypin_load_journal_impl(data1, strlen(data1))); 85 tt_int_op(8, OP_EQ, smartlist_len(mock_addent_got)); 86 keypin_ent_t *ent = smartlist_get(mock_addent_got, 2); 87 tt_mem_op(ent->rsa_id, OP_EQ, "r lerkim, sed do bar", 20); 88 tt_mem_op(ent->ed25519_key, OP_EQ, "baloot tempor gluppitus ut labor", 32); 89 90 /* More complex example: weird lines, bogus lines, 91 duplicate/conflicting lines */ 92 const char data2[] = 93 "PT09PT09PT09PT09PT09PT09PT0 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0\n" 94 "# This is a comment.\n" 95 " \n" 96 "QXQgdGhlIGVuZCBvZiB0aGUgeWU YXIgS3VycmVta2FybWVycnVrIHNhaWQgdG8gaGltLCA\n" 97 "IllvdSBoYXZlIG1hZGUgYSBnb28 ZCBiZWdpbm5pbmcuIiBCdXQgbm8gbW9yZS4gV2l6YXI\n" 98 "\n" 99 "ZHMgc3BlYWsgdHJ1dGgsIGFuZCA aXQgd2FzIHRydWUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n" 100 "@reserved for a future extension \n" 101 "eSBvZiBOYW1lcyB0aGF0IEdlZCA aGFkIHRvaWxlZCbyB3aW4gdGhhdCB5ZWFyIHdhcyA\n" 102 "eSBvZiBOYW1lcyB0aGF0IEdlZCA aGFkIHRvaWxlZCbyB3aW4gdGhhdCB5ZWFyIHdhcy" 103 "A line too long\n" 104 "dGhlIG1lcmUgc3RhcnQgb2Ygd2g YXQgaGUgbXVzdCBnbyBvb!BsZWFybmluZy4uLi4uLi4\n" 105 "ZHMgc3BlYWsgdaJ1dGgsIGFuZCA aXQgd2FzIHRydWUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n" 106 "ZHMgc3BlYWsgdHJ1dGgsIGFuZCA aXQgd2FzIHRydaUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n" 107 ; 108 109 tt_int_op(0, OP_EQ, keypin_load_journal_impl(data2, strlen(data2))); 110 tt_int_op(13, OP_EQ, smartlist_len(mock_addent_got)); 111 ent = smartlist_get(mock_addent_got, 9); 112 tt_mem_op(ent->rsa_id, OP_EQ, "\"You have made a goo", 20); 113 tt_mem_op(ent->ed25519_key, OP_EQ, "d beginning.\" But no more. Wizar", 32); 114 115 ent = smartlist_get(mock_addent_got, 12); 116 tt_mem_op(ent->rsa_id, OP_EQ, "ds speak truth, and ", 20); 117 tt_mem_op(ent->ed25519_key, OP_EQ, 118 "it was tru\xa5 that all the master\n", 32); 119 120 /* File truncated before NL */ 121 const char data3[] = 122 "Tm8gZHJhZ29uIGNhbiByZXNpc3Q IHRoZSBmYXNjaW5hdGlvbiBvZiByaWRkbGluZyB0YWw"; 123 tt_int_op(0, OP_EQ, keypin_load_journal_impl(data3, strlen(data3))); 124 tt_int_op(14, OP_EQ, smartlist_len(mock_addent_got)); 125 ent = smartlist_get(mock_addent_got, 13); 126 tt_mem_op(ent->rsa_id, OP_EQ, "No dragon can resist", 20); 127 tt_mem_op(ent->ed25519_key, OP_EQ, " the fascination of riddling tal", 32); 128 129 done: 130 keypin_clear(); 131 smartlist_free(mock_addent_got); 132 } 133 134 #define ADD(a,b) keypin_check_and_add((const uint8_t*)(a),\ 135 (const uint8_t*)(b),0) 136 #define LONE_RSA(a) keypin_check_lone_rsa((const uint8_t*)(a)) 137 138 static void 139 test_keypin_add_entry(void *arg) 140 { 141 (void)arg; 142 keypin_clear(); 143 144 tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("ambassadors-at-large", 145 "bread-and-butter thing-in-itself")); 146 tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("gentleman-adventurer", 147 "cloak-and-dagger what's-his-face")); 148 149 tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("ambassadors-at-large", 150 "bread-and-butter thing-in-itself")); 151 tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("ambassadors-at-large", 152 "bread-and-butter thing-in-itself")); 153 tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("gentleman-adventurer", 154 "cloak-and-dagger what's-his-face")); 155 156 tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("Johnnies-come-lately", 157 "run-of-the-mill root-mean-square")); 158 159 tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("gentleman-adventurer", 160 "hypersentimental closefistedness")); 161 162 tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("disestablismentarian", 163 "cloak-and-dagger what's-his-face")); 164 165 tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("gentleman-adventurer", 166 "cloak-and-dagger what's-his-face")); 167 168 tt_int_op(KEYPIN_NOT_FOUND, OP_EQ, LONE_RSA("Llanfairpwllgwyngyll")); 169 tt_int_op(KEYPIN_MISMATCH, OP_EQ, LONE_RSA("Johnnies-come-lately")); 170 171 done: 172 keypin_clear(); 173 } 174 175 static void 176 test_keypin_journal(void *arg) 177 { 178 (void)arg; 179 char *contents = NULL; 180 const char *fname = get_fname("keypin-journal"); 181 182 tt_int_op(0, OP_EQ, keypin_load_journal(fname)); /* ENOENT is okay */ 183 update_approx_time(1217709000); 184 tt_int_op(0, OP_EQ, keypin_open_journal(fname)); 185 186 tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("king-of-the-herrings", 187 "good-for-nothing attorney-at-law")); 188 tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("yellowish-red-yellow", 189 "salt-and-pepper high-muck-a-muck")); 190 tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("yellowish-red-yellow", 191 "salt-and-pepper high-muck-a-muck")); 192 keypin_close_journal(); 193 keypin_clear(); 194 195 tt_int_op(0, OP_EQ, keypin_load_journal(fname)); 196 update_approx_time(1231041600); 197 tt_int_op(0, OP_EQ, keypin_open_journal(fname)); 198 tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("yellowish-red-yellow", 199 "salt-and-pepper high-muck-a-muck")); 200 tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("theatre-in-the-round", 201 "holier-than-thou jack-in-the-box")); 202 tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("no-deposit-no-return", 203 "across-the-board will-o-the-wisp")); 204 tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("intellectualizations", 205 "salt-and-pepper high-muck-a-muck")); 206 keypin_close_journal(); 207 keypin_clear(); 208 209 tt_int_op(0, OP_EQ, keypin_load_journal(fname)); 210 update_approx_time(1412278354); 211 tt_int_op(0, OP_EQ, keypin_open_journal(fname)); 212 tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("yellowish-red-yellow", 213 "salt-and-pepper high-muck-a-muck")); 214 tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("intellectualizations", 215 "salt-and-pepper high-muck-a-muck")); 216 tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("theatre-in-the-round", 217 "holier-than-thou jack-in-the-box")); 218 tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("counterrevolutionary", 219 "holier-than-thou jack-in-the-box")); 220 tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("no-deposit-no-return", 221 "floccinaucinihilipilificationism")); 222 keypin_close_journal(); 223 224 contents = read_file_to_str(fname, RFTS_BIN, NULL); 225 tt_assert(contents); 226 tt_str_op(contents,OP_EQ, 227 "\n" 228 "@opened-at 2008-08-02 20:30:00\n" 229 "a2luZy1vZi10aGUtaGVycmluZ3M Z29vZC1mb3Itbm90aGluZyBhdHRvcm5leS1hdC1sYXc\n" 230 "eWVsbG93aXNoLXJlZC15ZWxsb3c c2FsdC1hbmQtcGVwcGVyIGhpZ2gtbXVjay1hLW11Y2s\n" 231 "\n" 232 "@opened-at 2009-01-04 04:00:00\n" 233 "dGhlYXRyZS1pbi10aGUtcm91bmQ aG9saWVyLXRoYW4tdGhvdSBqYWNrLWluLXRoZS1ib3g\n" 234 "bm8tZGVwb3NpdC1uby1yZXR1cm4 YWNyb3NzLXRoZS1ib2FyZCB3aWxsLW8tdGhlLXdpc3A\n" 235 "\n" 236 "@opened-at 2014-10-02 19:32:34\n"); 237 238 done: 239 tor_free(contents); 240 keypin_clear(); 241 } 242 243 #undef ADD 244 #undef LONE_RSA 245 246 #define TEST(name, flags) \ 247 { #name , test_keypin_ ## name, (flags), NULL, NULL } 248 249 struct testcase_t keypin_tests[] = { 250 TEST( parse_line, 0 ), 251 TEST( parse_file, TT_FORK ), 252 TEST( add_entry, TT_FORK ), 253 TEST( journal, TT_FORK ), 254 END_OF_TESTCASES 255 };