# BRCM_VERSION=3
[bcm963xx.git] / userapps / opensource / net-snmp / testing / scapitest.c
1 /*
2  * scapitest.c
3  *
4  * Expected SUCCESSes:  2 + 10 + 1 for all tests.
5  *
6  * Returns:
7  *      Number of FAILUREs.
8  *
9  *
10  * ASSUMES  No key management functions return non-zero success codes.
11  *
12  * XXX  Split into individual modules?
13  * XXX  Error/fringe conditions should be tested.
14  *
15  *
16  * Test of sc_random.                                           SUCCESSes: 2.
17  *      REQUIRES a human to spot check for obvious non-randomness...
18  *
19  * Test of sc_generate_keyed_hash and sc_check_keyed_hash.      SUCCESSes: 10.
20  *
21  * Test of sc_encrypt and sc_decrypt.                           SUCCESSes: 1.
22  */
23
24 static char    *rcsid = "$Id: scapitest.c,v 1.1.1.1 2005/04/29 01:45:23 echo Exp $";    /* */
25
26
27 #include <net-snmp/net-snmp-config.h>
28
29 #include <stdio.h>
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
32 #endif
33
34 #include "asn1.h"
35 #include "snmp_api.h"
36 #include "keytools.h"
37 #include "tools.h"
38 #include "scapi.h"
39 #include "transform_oids.h"
40 #include "callback.h"
41
42 #include <stdlib.h>
43
44 extern char    *optarg;
45 extern int      optind, optopt, opterr;
46
47 #define DEBUG                   /* */
48
49
50
51 /*
52  * Globals, &c...
53  */
54 char           *local_progname;
55
56 #define USAGE   "Usage: %s [-h][-acHr]"
57 #define OPTIONLIST      "achHr"
58
59 int             doalltests = 0, docrypt = 0, dokeyedhash = 0, dorandom = 0;
60
61 #define ALLOPTIONS      (doalltests + docrypt + dokeyedhash + dorandom)
62
63
64
65 #define LOCAL_MAXBUF    (1024 * 8)
66 #define NL              "\n"
67
68 #define OUTPUT(o)       fprintf(stdout, "\n\n%s\n\n", o);
69
70 #define SUCCESS(s)                                      \
71 {                                                       \
72         if (!failcount)                                 \
73                 fprintf(stdout, "\nSUCCESS: %s\n", s);  \
74 }
75
76 #define FAILED(e, f)                                    \
77 {                                                       \
78         if (e != SNMPERR_SUCCESS) {                     \
79                 fprintf(stdout, "\nFAILED: %s\n", f);   \
80                 failcount += 1;                         \
81         }                                               \
82 }
83
84
85 #define BIGSTRING                                                       \
86     "   A port may be a pleasant retreat for any mind grown weary of"   \
87     "the struggle for existence.  The vast expanse of sky, the"         \
88     "mobile architecture of the clouds, the chameleon coloration"       \
89     "of the sea, the beacons flashing on the shore, together make"      \
90     "a prism which is marvellously calculated to entertain but not"     \
91     "fatigue the eye.  The lofty ships with their complex webs of"      \
92     "rigging, swayed to and fro by the swell in harmonious dance,"      \
93     "all help to maintain a taste for rhythm and beauty in the"         \
94     "mind.  And above all there is a mysterious, aristrocratic kind"    \
95     "of pleasure to be had, for those who have lost all curiosity"      \
96     "or ambition, as they strech on the belvedere or lean over the"     \
97     "mole to watch the arrivals and departures of other men, those"     \
98     "who still have sufficient strength of purpose in them, the"        \
99     "urge to travel or enrich themselves."                              \
100     "   -- Baudelaire"                                                  \
101     "      From _The_Poems_in_Prose_, \"The Port\" (XLI)."
102
103 #define BIGSECRET       "Shhhh... Don't tell *anyone* about this.  Not a soul."
104 #define BKWDSECRET      ".luos a toN  .siht tuoba *enoyna* llet t'noD ...hhhhS"
105
106 #define MLCOUNT_MAX     6       /* MAC Length Count Maximum. */
107
108
109
110 /*
111  * Prototypes.
112  */
113 void            usage(FILE * ofp);
114
115 int             test_docrypt(void);
116 int             test_dokeyedhash(void);
117 int             test_dorandom(void);
118
119
120
121
122 int
123 main(int argc, char **argv)
124 {
125     int             rval = SNMPERR_SUCCESS, failcount = 0;
126     char            ch;
127
128     local_progname = argv[0];
129
130     /*
131      * Parse.
132      */
133     while ((ch = getopt(argc, argv, OPTIONLIST)) != EOF) {
134         switch (ch) {
135         case 'a':
136             doalltests = 1;
137             break;
138         case 'c':
139             docrypt = 1;
140             break;
141         case 'H':
142             dokeyedhash = 1;
143             break;
144         case 'r':
145             dorandom = 1;
146             break;
147         case 'h':
148             rval = 0;
149         default:
150             usage(stdout);
151             exit(rval);
152         }
153
154         argc -= 1;
155         argv += 1;
156         optind = 1;
157     }                           /* endwhile getopt */
158
159     if ((argc > 1)) {
160         usage(stdout);
161         exit(1000);
162
163     } else if (ALLOPTIONS != 1) {
164         usage(stdout);
165         exit(1000);
166     }
167
168
169     /*
170      * Test stuff.
171      */
172     rval = sc_init();
173     FAILED(rval, "sc_init().");
174
175
176     if (docrypt || doalltests) {
177         failcount += test_docrypt();
178     }
179     if (dokeyedhash || doalltests) {
180         failcount += test_dokeyedhash();
181     }
182     if (dorandom || doalltests) {
183         failcount += test_dorandom();
184     }
185
186
187     /*
188      * Cleanup.
189      */
190     rval = sc_shutdown(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
191                        NULL, NULL);
192     FAILED(rval, "sc_shutdown().");
193
194     return failcount;
195
196 }                               /* end main() */
197
198
199
200
201
202 void
203 usage(FILE * ofp)
204 {
205     fprintf(ofp,
206             USAGE
207             "" NL
208             "   -a              All tests." NL
209             "   -c              Test of sc_encrypt()/sc_decrypt()."
210             NL
211             "   -h              Help."
212             NL
213             "   -H              Test sc_{generate,check}_keyed_hash()."
214             NL
215             "   -r              Test sc_random()."
216             NL "" NL, local_progname);
217
218 }                               /* end usage() */
219
220
221
222
223 #ifdef EXAMPLE
224 /*******************************************************************-o-******
225  * test_dosomething
226  *
227  * Test template.
228  *
229  * Returns:
230  *      Number of failures.
231  */
232 int
233 test_dosomething(void)
234 {
235     int             rval = SNMPERR_SUCCESS, failcount = 0;
236
237     EM0(1, "UNIMPLEMENTED");    /* EM(1); /* */
238
239   test_dosomething_quit:
240     return failcount;
241
242 }                               /* end test_dosomething() */
243 #endif                          /* EXAMPLE */
244
245
246
247
248
249 /*******************************************************************-o-******
250  * test_dorandom
251  *
252  * One large request, one set of short requests.
253  *
254  * Returns:
255  *      Number of failures.
256  *
257  * XXX  probably should split up into individual options.
258  */
259 int
260 test_dorandom(void)
261 {
262     int             rval = SNMPERR_SUCCESS,
263         failcount = 0,
264         origrequest = (1024 * 2),
265         origrequest_short = 19, nbytes = origrequest, shortcount = 7, i;
266     char            buf[LOCAL_MAXBUF];
267
268     OUTPUT("Random test -- large request:");
269
270     rval = sc_random(buf, &nbytes);
271     FAILED(rval, "sc_random().");
272
273     if (nbytes != origrequest) {
274         FAILED(SNMPERR_GENERR,
275                "sc_random() returned different than requested.");
276     }
277
278     dump_chunk("scapitest", NULL, buf, nbytes);
279
280     SUCCESS("Random test -- large request.");
281
282
283     OUTPUT("Random test -- short requests:");
284     origrequest_short = 16;
285
286     for (i = 0; i < shortcount; i++) {
287         nbytes = origrequest_short;
288         rval = sc_random(buf, &nbytes);
289         FAILED(rval, "sc_random().");
290
291         if (nbytes != origrequest_short) {
292             FAILED(SNMPERR_GENERR,
293                    "sc_random() returned different " "than requested.");
294         }
295
296         dump_chunk("scapitest", NULL, buf, nbytes);
297     }                           /* endfor */
298
299     SUCCESS("Random test -- short requests.");
300
301
302     return failcount;
303
304 }                               /* end test_dorandom() */
305
306
307
308 /*******************************************************************-o-******
309  * test_dokeyedhash
310  *
311  * Returns:
312  *      Number of failures.
313  *
314  *
315  * Test keyed hashes with a variety of MAC length requests.
316  *
317  *
318  * NOTE Both tests intentionally use the same secret
319  *
320  * FIX  Get input or output from some other package which hashes...
321  * XXX  Could cut this in half with a little indirection...
322  */
323 int
324 test_dokeyedhash(void)
325 {
326     int             rval = SNMPERR_SUCCESS, failcount = 0, bigstring_len = strlen(BIGSTRING), secret_len = strlen(BIGSECRET), properlength, mlcount = 0,        /* MAC Length count.   */
327                     hblen;      /* Hash Buffer length. */
328
329     u_int           hashbuf_len[MLCOUNT_MAX] = {
330         LOCAL_MAXBUF,
331         BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1),
332         BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5),
333         BYTESIZE(SNMP_TRANS_AUTHLEN_HMAC96),
334         7,
335         0,
336     };
337
338     u_char          hashbuf[LOCAL_MAXBUF];
339     char           *s;
340
341   test_dokeyedhash_again:
342
343     OUTPUT("Keyed hash test using MD5 --");
344
345     memset(hashbuf, 0, LOCAL_MAXBUF);
346     hblen = hashbuf_len[mlcount];
347     properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
348
349     rval =
350         sc_generate_keyed_hash(usmHMACMD5AuthProtocol,
351                                USM_LENGTH_OID_TRANSFORM, BIGSECRET,
352                                secret_len, BIGSTRING, bigstring_len,
353                                hashbuf, &hblen);
354     FAILED(rval, "sc_generate_keyed_hash().");
355
356     if (hashbuf_len[mlcount] > properlength) {
357         if (hblen != properlength) {
358             FAILED(SNMPERR_GENERR, "Wrong MD5 hash length returned.  (1)");
359         }
360
361     } else if (hblen != hashbuf_len[mlcount]) {
362         FAILED(SNMPERR_GENERR, "Wrong MD5 hash length returned.  (2)");
363     }
364
365     rval =
366         sc_check_keyed_hash(usmHMACMD5AuthProtocol,
367                             USM_LENGTH_OID_TRANSFORM, BIGSECRET,
368                             secret_len, BIGSTRING, bigstring_len, hashbuf,
369                             hblen);
370     FAILED(rval, "sc_check_keyed_hash().");
371
372     binary_to_hex(hashbuf, hblen, &s);
373     fprintf(stdout, "hash buffer (len=%d, request=%d):   %s\n",
374             hblen, hashbuf_len[mlcount], s);
375     SNMP_FREE(s);
376
377     SUCCESS("Keyed hash test using MD5.");
378
379
380
381     OUTPUT("Keyed hash test using SHA1 --");
382
383     memset(hashbuf, 0, LOCAL_MAXBUF);
384     hblen = hashbuf_len[mlcount];
385     properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
386
387     rval =
388         sc_generate_keyed_hash(usmHMACSHA1AuthProtocol,
389                                USM_LENGTH_OID_TRANSFORM, BIGSECRET,
390                                secret_len, BIGSTRING, bigstring_len,
391                                hashbuf, &hblen);
392     FAILED(rval, "sc_generate_keyed_hash().");
393
394     if (hashbuf_len[mlcount] > properlength) {
395         if (hblen != properlength) {
396             FAILED(SNMPERR_GENERR,
397                    "Wrong SHA1 hash length returned.  (1)");
398         }
399
400     } else if (hblen != hashbuf_len[mlcount]) {
401         FAILED(SNMPERR_GENERR, "Wrong SHA1 hash length returned.  (2)");
402     }
403
404     rval =
405         sc_check_keyed_hash(usmHMACSHA1AuthProtocol,
406                             USM_LENGTH_OID_TRANSFORM, BIGSECRET,
407                             secret_len, BIGSTRING, bigstring_len, hashbuf,
408                             hblen);
409     FAILED(rval, "sc_check_keyed_hash().");
410
411     binary_to_hex(hashbuf, hblen, &s);
412     fprintf(stdout, "hash buffer (len=%d, request=%d):   %s\n",
413             hblen, hashbuf_len[mlcount], s);
414     SNMP_FREE(s);
415
416     SUCCESS("Keyed hash test using SHA1.");
417
418
419
420     /*
421      * Run the basic hash tests but vary the size MAC requests.
422      */
423     if (hashbuf_len[++mlcount] != 0) {
424         goto test_dokeyedhash_again;
425     }
426
427
428     return failcount;
429
430 }                               /* end test_dokeyedhash() */
431
432
433
434
435
436 /*******************************************************************-o-******
437  * test_docrypt
438  *
439  * Returns:
440  *      Number of failures.
441  */
442 int
443 test_docrypt(void)
444 {
445     int             rval = SNMPERR_SUCCESS,
446         failcount = 0,
447         bigstring_len = strlen(BIGSTRING),
448         secret_len = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES),
449         iv_len = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
450
451     u_int           buf_len = LOCAL_MAXBUF, cryptbuf_len = LOCAL_MAXBUF;
452
453     char            buf[LOCAL_MAXBUF],
454         cryptbuf[LOCAL_MAXBUF], secret[LOCAL_MAXBUF], iv[LOCAL_MAXBUF];
455
456     OUTPUT("Test 1DES-CBC --");
457
458
459     memset(buf, 0, LOCAL_MAXBUF);
460
461     memcpy(secret, BIGSECRET, secret_len);
462     memcpy(iv, BKWDSECRET, iv_len);
463
464
465     rval = sc_encrypt(usmDESPrivProtocol, USM_LENGTH_OID_TRANSFORM,
466                       secret, secret_len,
467                       iv, iv_len,
468                       BIGSTRING, bigstring_len, cryptbuf, &cryptbuf_len);
469     FAILED(rval, "sc_encrypt().");
470
471     rval = sc_decrypt(usmDESPrivProtocol, USM_LENGTH_OID_TRANSFORM,
472                       secret, secret_len,
473                       iv, iv_len, cryptbuf, cryptbuf_len, buf, &buf_len);
474     FAILED(rval, "sc_decrypt().");
475
476     if (buf_len != bigstring_len) {
477         FAILED(SNMPERR_GENERR, "Decrypted buffer is the wrong length.");
478     }
479     if (memcmp(buf, BIGSTRING, bigstring_len)) {
480         FAILED(SNMPERR_GENERR,
481                "Decrypted buffer is not equal to original plaintext.");
482     }
483
484
485     SUCCESS("Test 1DES-CBC --");
486
487     return failcount;
488
489 }                               /* end test_docrypt() */