diff options
-rwxr-xr-x | regress/unittests/sshkey/mktestdata.sh | 4 | ||||
-rw-r--r-- | regress/unittests/sshkey/test_sshkey.c | 175 |
2 files changed, 167 insertions, 12 deletions
diff --git a/regress/unittests/sshkey/mktestdata.sh b/regress/unittests/sshkey/mktestdata.sh index ee1fe3962..09165af02 100755 --- a/regress/unittests/sshkey/mktestdata.sh +++ b/regress/unittests/sshkey/mktestdata.sh | |||
@@ -1,5 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # $OpenBSD: mktestdata.sh,v 1.3 2014/07/22 23:57:40 dtucker Exp $ | 2 | # $OpenBSD: mktestdata.sh,v 1.4 2015/01/18 19:54:46 djm Exp $ |
3 | 3 | ||
4 | PW=mekmitasdigoat | 4 | PW=mekmitasdigoat |
5 | 5 | ||
@@ -187,4 +187,6 @@ ssh-keygen -Bf dsa_2 | awk '{print $2}' > dsa_2.fp.bb | |||
187 | ssh-keygen -Bf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp.bb | 187 | ssh-keygen -Bf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp.bb |
188 | ssh-keygen -Bf ed25519_2 | awk '{print $2}' > ed25519_2.fp.bb | 188 | ssh-keygen -Bf ed25519_2 | awk '{print $2}' > ed25519_2.fp.bb |
189 | 189 | ||
190 | # XXX Extend ssh-keygen to do detached signatures (better to test/fuzz against) | ||
191 | |||
190 | echo "$PW" > pw | 192 | echo "$PW" > pw |
diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c index ef0c67956..247d42019 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: test_sshkey.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */ | 1 | /* $OpenBSD: test_sshkey.c,v 1.2 2015/01/18 19:54:46 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Regress test for sshkey.h key management API | 3 | * Regress test for sshkey.h key management API |
4 | * | 4 | * |
@@ -37,6 +37,20 @@ | |||
37 | void sshkey_tests(void); | 37 | void sshkey_tests(void); |
38 | 38 | ||
39 | static void | 39 | static void |
40 | put_opt(struct sshbuf *b, const char *name, const char *value) | ||
41 | { | ||
42 | struct sshbuf *sect; | ||
43 | |||
44 | sect = sshbuf_new(); | ||
45 | ASSERT_PTR_NE(sect, NULL); | ||
46 | ASSERT_INT_EQ(sshbuf_put_cstring(b, name), 0); | ||
47 | if (value != NULL) | ||
48 | ASSERT_INT_EQ(sshbuf_put_cstring(sect, value), 0); | ||
49 | ASSERT_INT_EQ(sshbuf_put_stringb(b, sect), 0); | ||
50 | sshbuf_free(sect); | ||
51 | } | ||
52 | |||
53 | static void | ||
40 | build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, | 54 | build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, |
41 | const struct sshkey *sign_key, const struct sshkey *ca_key) | 55 | const struct sshkey *sign_key, const struct sshkey *ca_key) |
42 | { | 56 | { |
@@ -45,6 +59,7 @@ build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, | |||
45 | size_t siglen; | 59 | size_t siglen; |
46 | 60 | ||
47 | ca_buf = sshbuf_new(); | 61 | ca_buf = sshbuf_new(); |
62 | ASSERT_PTR_NE(ca_buf, NULL); | ||
48 | ASSERT_INT_EQ(sshkey_to_blob_buf(ca_key, ca_buf), 0); | 63 | ASSERT_INT_EQ(sshkey_to_blob_buf(ca_key, ca_buf), 0); |
49 | 64 | ||
50 | /* | 65 | /* |
@@ -52,18 +67,23 @@ build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, | |||
52 | * the type string. This is a bit of a hack :/ | 67 | * the type string. This is a bit of a hack :/ |
53 | */ | 68 | */ |
54 | pk = sshbuf_new(); | 69 | pk = sshbuf_new(); |
70 | ASSERT_PTR_NE(pk, NULL); | ||
55 | ASSERT_INT_EQ(sshkey_plain_to_blob_buf(k, pk), 0); | 71 | ASSERT_INT_EQ(sshkey_plain_to_blob_buf(k, pk), 0); |
56 | ASSERT_INT_EQ(sshbuf_skip_string(pk), 0); | 72 | ASSERT_INT_EQ(sshbuf_skip_string(pk), 0); |
57 | 73 | ||
58 | principals = sshbuf_new(); | 74 | principals = sshbuf_new(); |
75 | ASSERT_PTR_NE(principals, NULL); | ||
59 | ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0); | 76 | ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0); |
60 | ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0); | 77 | ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0); |
61 | 78 | ||
62 | critopts = sshbuf_new(); | 79 | critopts = sshbuf_new(); |
63 | /* XXX fill this in */ | 80 | ASSERT_PTR_NE(critopts, NULL); |
81 | put_opt(critopts, "force-command", "/usr/local/bin/nethack"); | ||
82 | put_opt(critopts, "source-address", "192.168.0.0/24,127.0.0.1,::1"); | ||
64 | 83 | ||
65 | exts = sshbuf_new(); | 84 | exts = sshbuf_new(); |
66 | /* XXX fill this in */ | 85 | ASSERT_PTR_NE(exts, NULL); |
86 | put_opt(critopts, "permit-X11-forwarding", NULL); | ||
67 | 87 | ||
68 | ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0); | 88 | ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0); |
69 | ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */ | 89 | ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */ |
@@ -90,6 +110,67 @@ build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, | |||
90 | sshbuf_free(pk); | 110 | sshbuf_free(pk); |
91 | } | 111 | } |
92 | 112 | ||
113 | static void | ||
114 | signature_test(struct sshkey *k, struct sshkey *bad, const u_char *d, size_t l) | ||
115 | { | ||
116 | size_t len; | ||
117 | u_char *sig; | ||
118 | |||
119 | ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, 0), 0); | ||
120 | ASSERT_SIZE_T_GT(len, 8); | ||
121 | ASSERT_PTR_NE(sig, NULL); | ||
122 | ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, 0), 0); | ||
123 | ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, 0), 0); | ||
124 | /* Fuzz test is more comprehensive, this is just a smoke test */ | ||
125 | sig[len - 5] ^= 0x10; | ||
126 | ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, 0), 0); | ||
127 | free(sig); | ||
128 | } | ||
129 | |||
130 | static void | ||
131 | banana(u_char *s, size_t l) | ||
132 | { | ||
133 | size_t o; | ||
134 | const u_char the_banana[] = { 'b', 'a', 'n', 'a', 'n', 'a' }; | ||
135 | |||
136 | for (o = 0; o < l; o += sizeof(the_banana)) { | ||
137 | if (l - o < sizeof(the_banana)) { | ||
138 | memcpy(s + o, "nanananana", l - o); | ||
139 | break; | ||
140 | } | ||
141 | memcpy(s + o, banana, sizeof(the_banana)); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void | ||
146 | signature_tests(struct sshkey *k, struct sshkey *bad) | ||
147 | { | ||
148 | u_char i, buf[2049]; | ||
149 | size_t lens[] = { | ||
150 | 1, 2, 7, 8, 9, 15, 16, 17, 31, 32, 33, 127, 128, 129, | ||
151 | 255, 256, 257, 1023, 1024, 1025, 2047, 2048, 2049 | ||
152 | }; | ||
153 | |||
154 | for (i = 0; i < (sizeof(lens)/sizeof(lens[0])); i++) { | ||
155 | test_subtest_info("%s key, banana length %zu", | ||
156 | sshkey_type(k), lens[i]); | ||
157 | banana(buf, lens[i]); | ||
158 | signature_test(k, bad, buf, lens[i]); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | static struct sshkey * | ||
163 | get_private(const char *n) | ||
164 | { | ||
165 | struct sshbuf *b; | ||
166 | struct sshkey *ret; | ||
167 | |||
168 | b = load_file(n); | ||
169 | ASSERT_INT_EQ(sshkey_parse_private_fileblob(b, "", n, &ret, NULL), 0); | ||
170 | sshbuf_free(b); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
93 | void | 174 | void |
94 | sshkey_tests(void) | 175 | sshkey_tests(void) |
95 | { | 176 | { |
@@ -332,26 +413,98 @@ sshkey_tests(void) | |||
332 | #endif | 413 | #endif |
333 | sshkey_free(kf); | 414 | sshkey_free(kf); |
334 | 415 | ||
335 | /* XXX certify test */ | 416 | TEST_START("certify key"); |
336 | /* XXX sign test */ | 417 | ASSERT_INT_EQ(sshkey_load_public(test_data_file("ed25519_1.pub"), |
337 | /* XXX verify test */ | 418 | &k1, NULL), 0); |
419 | k2 = get_private("ed25519_2"); | ||
420 | ASSERT_INT_EQ(sshkey_to_certified(k1, 0), 0); | ||
421 | ASSERT_PTR_NE(k1->cert, NULL); | ||
422 | k1->cert->type = SSH2_CERT_TYPE_USER; | ||
423 | k1->cert->serial = 1234; | ||
424 | k1->cert->key_id = strdup("estragon"); | ||
425 | ASSERT_PTR_NE(k1->cert->key_id, NULL); | ||
426 | k1->cert->principals = calloc(4, sizeof(*k1->cert->principals)); | ||
427 | ASSERT_PTR_NE(k1->cert->principals, NULL); | ||
428 | k1->cert->principals[0] = strdup("estragon"); | ||
429 | k1->cert->principals[1] = strdup("vladimir"); | ||
430 | k1->cert->principals[2] = strdup("pozzo"); | ||
431 | k1->cert->principals[3] = strdup("lucky"); | ||
432 | ASSERT_PTR_NE(k1->cert->principals[0], NULL); | ||
433 | ASSERT_PTR_NE(k1->cert->principals[1], NULL); | ||
434 | ASSERT_PTR_NE(k1->cert->principals[2], NULL); | ||
435 | ASSERT_PTR_NE(k1->cert->principals[3], NULL); | ||
436 | k1->cert->valid_after = 0; | ||
437 | k1->cert->valid_before = (u_int64_t)-1; | ||
438 | k1->cert->critical = sshbuf_new(); | ||
439 | ASSERT_PTR_NE(k1->cert->critical, NULL); | ||
440 | k1->cert->extensions = sshbuf_new(); | ||
441 | ASSERT_PTR_NE(k1->cert->extensions, NULL); | ||
442 | put_opt(k1->cert->critical, "force-command", "/usr/bin/true"); | ||
443 | put_opt(k1->cert->critical, "source-address", "127.0.0.1"); | ||
444 | put_opt(k1->cert->extensions, "permit-X11-forwarding", NULL); | ||
445 | put_opt(k1->cert->extensions, "permit-agent-forwarding", NULL); | ||
446 | ASSERT_INT_EQ(sshkey_from_private(k2, &k1->cert->signature_key), 0); | ||
447 | ASSERT_INT_EQ(sshkey_certify(k1, k2), 0); | ||
448 | b = sshbuf_new(); | ||
449 | ASSERT_PTR_NE(b, NULL); | ||
450 | ASSERT_INT_EQ(sshkey_to_blob_buf(k1, b), 0); | ||
451 | ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k3), 0); | ||
452 | |||
453 | sshkey_free(k1); | ||
454 | sshkey_free(k2); | ||
455 | sshkey_free(k3); | ||
456 | sshbuf_reset(b); | ||
457 | TEST_DONE(); | ||
458 | |||
459 | TEST_START("sign and verify RSA"); | ||
460 | k1 = get_private("rsa_1"); | ||
461 | ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_2.pub"), &k2, | ||
462 | NULL), 0); | ||
463 | signature_tests(k1, k2); | ||
464 | sshkey_free(k1); | ||
465 | sshkey_free(k2); | ||
466 | TEST_DONE(); | ||
467 | |||
468 | TEST_START("sign and verify DSA"); | ||
469 | k1 = get_private("dsa_1"); | ||
470 | ASSERT_INT_EQ(sshkey_load_public(test_data_file("dsa_2.pub"), &k2, | ||
471 | NULL), 0); | ||
472 | signature_tests(k1, k2); | ||
473 | sshkey_free(k1); | ||
474 | sshkey_free(k2); | ||
475 | TEST_DONE(); | ||
476 | |||
477 | TEST_START("sign and verify ECDSA"); | ||
478 | k1 = get_private("ecdsa_1"); | ||
479 | ASSERT_INT_EQ(sshkey_load_public(test_data_file("ecdsa_2.pub"), &k2, | ||
480 | NULL), 0); | ||
481 | signature_tests(k1, k2); | ||
482 | sshkey_free(k1); | ||
483 | sshkey_free(k2); | ||
484 | TEST_DONE(); | ||
485 | |||
486 | TEST_START("sign and verify ED25519"); | ||
487 | k1 = get_private("ed25519_1"); | ||
488 | ASSERT_INT_EQ(sshkey_load_public(test_data_file("ed25519_2.pub"), &k2, | ||
489 | NULL), 0); | ||
490 | signature_tests(k1, k2); | ||
491 | sshkey_free(k1); | ||
492 | sshkey_free(k2); | ||
493 | TEST_DONE(); | ||
338 | 494 | ||
339 | TEST_START("nested certificate"); | 495 | TEST_START("nested certificate"); |
340 | ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0); | 496 | ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0); |
341 | ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, | 497 | ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, |
342 | NULL), 0); | 498 | NULL), 0); |
343 | b = load_file("rsa_2"); | 499 | k3 = get_private("ed25519_2"); |
344 | ASSERT_INT_EQ(sshkey_parse_private_fileblob(b, "", "rsa_1", | ||
345 | &k3, NULL), 0); | ||
346 | sshbuf_reset(b); | ||
347 | build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1); | 500 | build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1); |
348 | ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4), | 501 | ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4), |
349 | SSH_ERR_KEY_CERT_INVALID_SIGN_KEY); | 502 | SSH_ERR_KEY_CERT_INVALID_SIGN_KEY); |
350 | ASSERT_PTR_EQ(k4, NULL); | 503 | ASSERT_PTR_EQ(k4, NULL); |
351 | sshbuf_free(b); | ||
352 | sshkey_free(k1); | 504 | sshkey_free(k1); |
353 | sshkey_free(k2); | 505 | sshkey_free(k2); |
354 | sshkey_free(k3); | 506 | sshkey_free(k3); |
507 | sshbuf_free(b); | ||
355 | TEST_DONE(); | 508 | TEST_DONE(); |
356 | 509 | ||
357 | } | 510 | } |