added files
[bcm963xx.git] / userapps / opensource / net-snmp / testing / keymanagetest.c
1 /*
2  * keymanagetest.c
3  *
4  * Expected SUCCESSes:  2 + 2 + 3 for all tests.
5  *
6  * Returns:
7  *      Number of FAILUREs.
8  * 
9  *
10  * FIX  Or how about passing a usmUser name and looking up the entry as
11  *      a means of getting key material?  This means the userList is
12  *      available from an application...
13  *
14  * ASSUMES  No key management functions return non-zero success codes.
15  *
16  * Test of generate_Ku().                       SUCCESSes: 2
17  * Test of generate_kul().                      SUCCESSes: 2
18  * Test of {encode,decode}_keychange().         SUCCESSes: 3
19  */
20
21 static char    *rcsid = "$Id: keymanagetest.c,v 5.0 2002/04/20 07:30:22 hardaker Exp $";        /* */
22
23 #include <net-snmp/net-snmp-config.h>
24
25 #include <stdio.h>
26 #ifdef HAVE_NETINET_IN_H
27 #include <netinet/in.h>
28 #endif
29
30 #include "asn1.h"
31 #include "snmp_api.h"
32 #include "keytools.h"
33 #include "tools.h"
34 #include "scapi.h"
35 #include "transform_oids.h"
36 #include "callback.h"
37
38 #include <stdlib.h>
39
40 extern char    *optarg;
41 extern int      optind, optopt, opterr;
42
43
44
45 /*
46  * Globals, &c...
47  */
48 char           *local_progname;
49
50 #define USAGE   "Usage: %s [-h][-aklu][-E <engineID>][-N <newkey>][-O <oldkey>][-P <passphrase>]"
51 #define OPTIONLIST      "aqE:hklN:O:P:u"
52
53 int             doalltests = 0, dogenKu = 0, dogenkul = 0, dokeychange = 0;
54
55 #define ALLOPTIONS      (doalltests + dogenKu + dogenkul + dokeychange)
56
57
58 #define LOCAL_MAXBUF    (1024 * 8)
59 #define NL              "\n"
60
61 #define OUTPUTALWAYS(o) fprintf(stdout, "\n\n%s\n\n", o);
62 #define OUTPUT(o)       if (!bequiet) { OUTPUTALWAYS(o); }
63
64 #define SUCCESS(s)                                      \
65 {                                                       \
66         if (!failcount && !bequiet)                                     \
67                 fprintf(stdout, "\nSUCCESS: %s\n", s);  \
68 }
69
70 #define FAILED(e, f)                                    \
71 {                                                       \
72         if (e != SNMPERR_SUCCESS && !bequiet) {                 \
73                 fprintf(stdout, "\nFAILED: %s\n", f);   \
74                 failcount += 1;                         \
75         }                                               \
76 }
77
78
79
80 /*
81  * Test specific globals.
82  */
83 #define ENGINEID_DEFAULT        "1.2.3.4wild"
84 #define PASSPHRASE_DEFAULT      "Clay's Conclusion: Creativity is great, " \
85                                         "but plagiarism is faster."
86 #define OLDKEY_DEFAULT          "This is a very old key."
87 #define NEWKEY_DEFAULT          "This key, on the other hand, is very new."
88
89 char           *engineID = NULL;
90 char           *passphrase = NULL;
91 char           *oldkey = NULL;
92 char           *newkey = NULL;
93 int             bequiet = 0;
94
95
96 /*
97  * Prototypes.
98  */
99 void            usage(FILE * ofp);
100
101 int             test_genkul(void);
102 int             test_genKu(void);
103 int             test_keychange(void);
104
105
106
107
108 int
109 main(int argc, char **argv)
110 {
111     int             rval = SNMPERR_SUCCESS, failcount = 0;
112     char            ch;
113
114     local_progname = argv[0];
115     optarg = NULL;
116
117     /*
118      * Parse.
119      */
120     while ((ch = getopt(argc, argv, OPTIONLIST)) != EOF) {
121         switch (ch) {
122         case 'a':
123             doalltests = 1;
124             break;
125         case 'E':
126             engineID = optarg;
127             break;
128         case 'k':
129             dokeychange = 1;
130             break;
131         case 'l':
132             dogenkul = 1;
133             break;
134         case 'N':
135             newkey = optarg;
136             break;
137         case 'O':
138             oldkey = optarg;
139             break;
140         case 'P':
141             passphrase = optarg;
142             break;
143         case 'u':
144             dogenKu = 1;
145             break;
146         case 'q':
147             bequiet = 1;
148             break;
149         case 'h':
150             rval = 0;
151         default:
152             usage(stdout);
153             exit(rval);
154         }
155
156         argc -= 1;
157         argv += 1;
158         if (optarg) {
159             argc -= 1;
160             argv += 1;
161         }
162
163         optind = 1;
164         optarg = NULL;
165     }                           /* endwhile getopt */
166
167     if ((argc > 1)) {
168         usage(stdout);
169         exit(1000);
170
171     } else if (ALLOPTIONS != 1) {
172         usage(stdout);
173         exit(1000);
174     }
175
176
177     /*
178      * Test stuff.
179      */
180     rval = sc_init();
181     FAILED(rval, "sc_init().");
182
183     if (dogenKu || doalltests) {
184         failcount += test_genKu();
185     }
186     if (dogenkul || doalltests) {
187         failcount += test_genkul();
188     }
189     if (dokeychange || doalltests) {
190         failcount += test_keychange();
191     }
192
193
194     /*
195      * Cleanup.
196      */
197     rval = sc_shutdown(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
198                        NULL, NULL);
199     FAILED(rval, "sc_shutdown().");
200
201     return failcount;
202
203 }                               /* end main() */
204
205
206
207
208
209 void
210 usage(FILE * ofp)
211 {
212     fprintf(ofp,
213             USAGE
214             "" NL
215             "    -a                     All tests." NL
216             "    -E [0x]<engineID>      snmpEngineID string."
217             NL
218             "    -k                     Test {encode,decode}_keychange()."
219             NL
220             "    -l                     generate_kul()."
221             NL
222             "    -h                     Help."
223             NL
224             "    -N [0x]<newkey>        New key (for testing KeyChange TC)."
225             NL
226             "    -O [0x]<oldkey>        Old key (for testing KeyChange TC)."
227             NL
228             "    -P <passphrase>        Source string for usmUser master key."
229             NL
230             "    -u                     generate_Ku()."
231             NL
232             "    -q                     be quiet."
233             NL "" NL, local_progname);
234
235 }                               /* end usage() */
236
237
238
239
240 #ifdef EXAMPLE
241 /*******************************************************************-o-******
242  * test_dosomething
243  *
244  * Test template.
245  *
246  * Returns:
247  *      Number of failures.
248  */
249 int
250 test_dosomething(void)
251 {
252     int             rval = SNMPERR_SUCCESS, failcount = 0;
253
254     EM0(1, "UNIMPLEMENTED");    /* EM(1); /* */
255
256   test_dosomething_quit:
257     return failcount;
258
259 }                               /* end test_dosomething() */
260 #endif                          /* EXAMPLE */
261
262
263
264 /*******************************************************************-o-******
265  * test_genKu
266  *
267  * Returns:
268  *      Number of failures.
269  *
270  *
271  * Test generation of usmUser master key from a passphrase.
272  *
273  * ASSUMES  Passphrase is made of printable characters!
274  */
275 int
276 test_genKu(void)
277 {
278     int             rval = SNMPERR_SUCCESS,
279         failcount = 0,
280         properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5), kulen;
281     char           *hashname = "usmHMACMD5AuthProtocol.", *s;
282     u_char          Ku[LOCAL_MAXBUF];
283     oid            *hashtype = usmHMACMD5AuthProtocol;
284
285     OUTPUT("Test of generate_Ku --");
286
287     /*
288      * Set passphrase.
289      */
290     if (!passphrase) {
291         passphrase = PASSPHRASE_DEFAULT;
292     }
293     if (!bequiet)
294         fprintf(stdout, "Passphrase%s:\n\t%s\n\n",
295                 (passphrase == PASSPHRASE_DEFAULT) ? " (default)" : "",
296                 passphrase);
297
298
299   test_genKu_again:
300     memset(Ku, 0, LOCAL_MAXBUF);
301     kulen = LOCAL_MAXBUF;
302
303     rval = generate_Ku(hashtype, USM_LENGTH_OID_TRANSFORM,
304                        passphrase, strlen(passphrase), Ku, &kulen);
305     FAILED(rval, "generate_Ku().");
306
307     if (kulen != properlength) {
308         FAILED(SNMPERR_GENERR, "Ku length is wrong for this hashtype.");
309     }
310
311     binary_to_hex(Ku, kulen, &s);
312     if (!bequiet)
313         fprintf(stdout, "Ku (len=%d):  %s\n", kulen, s);
314     free_zero(s, kulen);
315
316     SUCCESS(hashname);
317     if (!bequiet)
318         fprintf(stdout, "\n");
319
320     if (hashtype == usmHMACMD5AuthProtocol) {
321         hashtype = usmHMACSHA1AuthProtocol;
322         hashname = "usmHMACSHA1AuthProtocol.";
323         properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
324         goto test_genKu_again;
325     }
326
327     return failcount;
328
329 }                               /* end test_genKu() */
330
331
332
333
334 /*******************************************************************-o-******
335  * test_genkul
336  *
337  * Returns:
338  *      Number of failures.
339  *
340  *
341  * Test of generate_kul().
342  *
343  * A passphrase and engineID are hashed into a master key Ku using
344  * both known hash transforms.  Localized keys, also using both hash
345  * transforms, are generated from each of these master keys.
346  *
347  * ASSUME  generate_Ku is already tested.
348  * ASSUME  engineID is initially a NULL terminated string.
349  */
350 int
351 test_genkul(void)
352 {
353     int             rval = SNMPERR_SUCCESS,
354         failcount = 0,
355         properlength, kulen, kul_len, engineID_len, isdefault = FALSE;
356
357     char           *s = NULL,
358         *testname = "Using HMACMD5 to create master key.",
359         *hashname_Ku = "usmHMACMD5AuthProtocol", *hashname_kul;
360
361     u_char          Ku[LOCAL_MAXBUF], kul[LOCAL_MAXBUF];
362
363     oid            *hashtype_Ku = usmHMACMD5AuthProtocol, *hashtype_kul;
364
365     OUTPUT("Test of generate_kul --");
366
367
368     /*
369      * Set passphrase and engineID.
370      *
371      * If engineID begins with 0x, assume it is written in (printable)
372      * hex and convert it to binary data.
373      */
374     if (!passphrase) {
375         passphrase = PASSPHRASE_DEFAULT;
376     }
377     if (!bequiet)
378         fprintf(stdout, "Passphrase%s:\n\t%s\n\n",
379                 (passphrase == PASSPHRASE_DEFAULT) ? " (default)" : "",
380                 passphrase);
381
382     if (!engineID) {
383         engineID = ENGINEID_DEFAULT;
384         isdefault = TRUE;
385     }
386
387     engineID_len = strlen(engineID);
388
389     if (tolower(*(engineID + 1)) == 'x') {
390         engineID_len = hex_to_binary2(engineID + 2, engineID_len - 2, &s);
391         if (engineID_len < 0) {
392             FAILED((rval = SNMPERR_GENERR),
393                    "Could not resolve hex engineID.");
394         }
395         engineID = s;
396         binary_to_hex(engineID, engineID_len, &s);
397     }
398
399     if (!bequiet)
400         fprintf(stdout, "engineID%s (len=%d):  %s\n\n",
401                 (isdefault) ? " (default)" : "",
402                 engineID_len, (s) ? s : engineID);
403     if (s) {
404         SNMP_FREE(s);
405     }
406
407
408
409     /*
410      * Create a master key using both hash transforms; create localized
411      * keys using both hash transforms from each master key.
412      */
413   test_genkul_again_master:
414     memset(Ku, 0, LOCAL_MAXBUF);
415     kulen = LOCAL_MAXBUF;
416     hashname_kul = "usmHMACMD5AuthProtocol";
417     hashtype_kul = usmHMACMD5AuthProtocol;
418     properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
419
420
421     rval = generate_Ku(hashtype_Ku, USM_LENGTH_OID_TRANSFORM,
422                        passphrase, strlen(passphrase), Ku, &kulen);
423     FAILED(rval, "generate_Ku().");
424
425     binary_to_hex(Ku, kulen, &s);
426     if (!bequiet)
427         fprintf(stdout,
428                 "\n\nMaster Ku using \"%s\":\n\t%s\n\n", hashname_Ku, s);
429     free_zero(s, kulen);
430
431
432   test_genkul_again_local:
433     memset(kul, 0, LOCAL_MAXBUF);
434     kul_len = LOCAL_MAXBUF;
435
436     rval = generate_kul(hashtype_kul, USM_LENGTH_OID_TRANSFORM,
437                         engineID, engineID_len, Ku, kulen, kul, &kul_len);
438
439     if ((hashtype_Ku == usmHMACMD5AuthProtocol)
440         && (hashtype_kul == usmHMACSHA1AuthProtocol)) {
441         if (rval == SNMPERR_SUCCESS) {
442             FAILED(SNMPERR_GENERR,
443                    "generate_kul SHOULD fail when Ku length is "
444                    "less than hash transform length.");
445         }
446
447     } else {
448         FAILED(rval, "generate_kul().");
449
450         if (kul_len != properlength) {
451             FAILED(SNMPERR_GENERR,
452                    "kul length is wrong for the given hashtype.");
453         }
454
455         binary_to_hex(kul, kul_len, &s);
456         fprintf(stdout, "kul (%s) (len=%d):  %s\n",
457                 ((hashtype_Ku == usmHMACMD5AuthProtocol) ? "MD5" : "SHA"),
458                 kul_len, s);
459         free_zero(s, kul_len);
460     }
461
462
463     /*
464      * Create localized key using the other hash transform, but from
465      * * the same master key.
466      */
467     if (hashtype_kul == usmHMACMD5AuthProtocol) {
468         hashtype_kul = usmHMACSHA1AuthProtocol;
469         hashname_kul = "usmHMACSHA1AuthProtocol";
470         properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
471         goto test_genkul_again_local;
472     }
473
474     SUCCESS(testname);
475
476
477     /*
478      * Re-create the master key using the other hash transform.
479      */
480     if (hashtype_Ku == usmHMACMD5AuthProtocol) {
481         hashtype_Ku = usmHMACSHA1AuthProtocol;
482         hashname_Ku = "usmHMACSHA1AuthProtocol";
483         testname = "Using HMACSHA1 to create master key.";
484         goto test_genkul_again_master;
485     }
486
487     return failcount;
488
489 }                               /* end test_genkul() */
490
491
492
493
494 /*******************************************************************-o-******
495  * test_keychange
496  *
497  * Returns:
498  *      Number of failures.
499  *
500  *
501  * Test of KeyChange TC implementation.
502  *
503  * ASSUME newkey and oldkey begin as NULL terminated strings.
504  */
505 int
506 test_keychange(void)
507 {
508     int             rval = SNMPERR_SUCCESS,
509         failcount = 0,
510         properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5),
511         oldkey_len,
512         newkey_len,
513         keychange_len,
514         temp_len, isdefault_new = FALSE, isdefault_old = FALSE;
515
516     char           *hashname = "usmHMACMD5AuthProtocol.", *s;
517
518     u_char          oldkey_buf[LOCAL_MAXBUF],
519         newkey_buf[LOCAL_MAXBUF],
520         temp_buf[LOCAL_MAXBUF], keychange_buf[LOCAL_MAXBUF];
521
522     oid            *hashtype = usmHMACMD5AuthProtocol;
523
524     OUTPUT("Test of KeyChange TC --");
525
526
527     /*
528      * Set newkey and oldkey.
529      */
530     if (!newkey) {              /* newkey */
531         newkey = NEWKEY_DEFAULT;
532         isdefault_new = TRUE;
533     }
534     newkey_len = strlen(newkey);
535
536     if (tolower(*(newkey + 1)) == 'x') {
537         newkey_len = hex_to_binary2(newkey + 2, newkey_len - 2, &s);
538         if (newkey_len < 0) {
539             FAILED((rval = SNMPERR_GENERR),
540                    "Could not resolve hex newkey.");
541         }
542         newkey = s;
543         binary_to_hex(newkey, newkey_len, &s);
544     }
545
546     if (!oldkey) {              /* oldkey */
547         oldkey = OLDKEY_DEFAULT;
548         isdefault_old = TRUE;
549     }
550     oldkey_len = strlen(oldkey);
551
552     if (tolower(*(oldkey + 1)) == 'x') {
553         oldkey_len = hex_to_binary2(oldkey + 2, oldkey_len - 2, &s);
554         if (oldkey_len < 0) {
555             FAILED((rval = SNMPERR_GENERR),
556                    "Could not resolve hex oldkey.");
557         }
558         oldkey = s;
559         binary_to_hex(oldkey, oldkey_len, &s);
560     }
561
562
563
564   test_keychange_again:
565     memset(oldkey_buf, 0, LOCAL_MAXBUF);
566     memset(newkey_buf, 0, LOCAL_MAXBUF);
567     memset(keychange_buf, 0, LOCAL_MAXBUF);
568     memset(temp_buf, 0, LOCAL_MAXBUF);
569
570     memcpy(oldkey_buf, oldkey, SNMP_MIN(oldkey_len, properlength));
571     memcpy(newkey_buf, newkey, SNMP_MIN(newkey_len, properlength));
572     keychange_len = LOCAL_MAXBUF;
573
574
575     binary_to_hex(oldkey_buf, properlength, &s);
576     fprintf(stdout, "\noldkey%s (len=%d):  %s\n",
577             (isdefault_old) ? " (default)" : "", properlength, s);
578     SNMP_FREE(s);
579
580     binary_to_hex(newkey_buf, properlength, &s);
581     fprintf(stdout, "newkey%s (len=%d):  %s\n\n",
582             (isdefault_new) ? " (default)" : "", properlength, s);
583     SNMP_FREE(s);
584
585
586     rval = encode_keychange(hashtype, USM_LENGTH_OID_TRANSFORM,
587                             oldkey_buf, properlength,
588                             newkey_buf, properlength,
589                             keychange_buf, &keychange_len);
590     FAILED(rval, "encode_keychange().");
591
592     if (keychange_len != (properlength * 2)) {
593         FAILED(SNMPERR_GENERR,
594                "KeyChange string (encoded) is not proper length "
595                "for this hash transform.");
596     }
597
598     binary_to_hex(keychange_buf, keychange_len, &s);
599     fprintf(stdout, "(%s) KeyChange string:  %s\n\n",
600             ((hashtype == usmHMACMD5AuthProtocol) ? "MD5" : "SHA"), s);
601     SNMP_FREE(s);
602
603     temp_len = properlength;
604     rval = decode_keychange(hashtype, USM_LENGTH_OID_TRANSFORM,
605                             oldkey_buf, properlength,
606                             keychange_buf, properlength * 2,
607                             temp_buf, &temp_len);
608     FAILED(rval, "decode_keychange().");
609
610     if (temp_len != properlength) {
611         FAILED(SNMPERR_GENERR,
612                "decoded newkey is not proper length for "
613                "this hash transform.");
614     }
615
616     binary_to_hex(temp_buf, temp_len, &s);
617     fprintf(stdout, "decoded newkey:  %s\n\n", s);
618     SNMP_FREE(s);
619
620
621     if (memcmp(newkey_buf, temp_buf, temp_len)) {
622         FAILED(SNMPERR_GENERR, "newkey did not decode properly.");
623     }
624
625
626     SUCCESS(hashname);
627     fprintf(stdout, "\n");
628
629
630     /*
631      * Multiplex different test combinations.
632      *
633      * First clause is for Test #2, second clause is for (last) Test #3.
634      */
635     if (hashtype == usmHMACMD5AuthProtocol) {
636         hashtype = usmHMACSHA1AuthProtocol;
637         hashname = "usmHMACSHA1AuthProtocol (w/DES length kul's).";
638         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES)
639             + BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
640         goto test_keychange_again;
641
642     } else if (properlength < BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1)) {
643         hashtype = usmHMACSHA1AuthProtocol;
644         hashname = "usmHMACSHA1AuthProtocol.";
645         properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
646         goto test_keychange_again;
647     }
648
649     return failcount;
650
651 }                               /* end test_keychange() */