blob: 82e9098ee7172d875739425051435eeb5f90c853 [file] [log] [blame]
/*
* scapitest.c
*
* Expected SUCCESSes: 2 + 10 + 1 for all tests.
*
* Returns:
* Number of FAILUREs.
*
*
* ASSUMES No key management functions return non-zero success codes.
*
* XXX Split into individual modules?
* XXX Error/fringe conditions should be tested.
*
*
* Test of sc_random. SUCCESSes: 2.
* REQUIRES a human to spot check for obvious non-randomness...
*
* Test of sc_generate_keyed_hash and sc_check_keyed_hash. SUCCESSes: 10.
*
* Test of sc_encrypt and sc_decrypt. SUCCESSes: 1.
*/
static char *rcsid = "$Id$"; /* */
#include <net-snmp/net-snmp-config.h>
#include <stdio.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "asn1.h"
#include "snmp_api.h"
#include "keytools.h"
#include "tools.h"
#include "scapi.h"
#include "transform_oids.h"
#include "callback.h"
#include <stdlib.h>
extern char *optarg;
extern int optind, optopt, opterr;
#define DEBUG /* */
/*
* Globals, &c...
*/
char *local_progname;
#define USAGE "Usage: %s [-h][-acHr]"
#define OPTIONLIST "achHr"
int doalltests = 0, docrypt = 0, dokeyedhash = 0, dorandom = 0;
#define ALLOPTIONS (doalltests + docrypt + dokeyedhash + dorandom)
#define LOCAL_MAXBUF (1024 * 8)
#define NL "\n"
#define OUTPUT(o) fprintf(stdout, "\n\n%s\n\n", o);
#define SUCCESS(s) \
{ \
if (!failcount) \
fprintf(stdout, "\nSUCCESS: %s\n", s); \
}
#define FAILED(e, f) \
{ \
if (e != SNMPERR_SUCCESS) { \
fprintf(stdout, "\nFAILED: %s\n", f); \
failcount += 1; \
} \
}
#define BIGSTRING \
" A port may be a pleasant retreat for any mind grown weary of" \
"the struggle for existence. The vast expanse of sky, the" \
"mobile architecture of the clouds, the chameleon coloration" \
"of the sea, the beacons flashing on the shore, together make" \
"a prism which is marvellously calculated to entertain but not" \
"fatigue the eye. The lofty ships with their complex webs of" \
"rigging, swayed to and fro by the swell in harmonious dance," \
"all help to maintain a taste for rhythm and beauty in the" \
"mind. And above all there is a mysterious, aristrocratic kind" \
"of pleasure to be had, for those who have lost all curiosity" \
"or ambition, as they strech on the belvedere or lean over the" \
"mole to watch the arrivals and departures of other men, those" \
"who still have sufficient strength of purpose in them, the" \
"urge to travel or enrich themselves." \
" -- Baudelaire" \
" From _The_Poems_in_Prose_, \"The Port\" (XLI)."
#define BIGSECRET "Shhhh... Don't tell *anyone* about this. Not a soul."
#define BKWDSECRET ".luos a toN .siht tuoba *enoyna* llet t'noD ...hhhhS"
#define MLCOUNT_MAX 6 /* MAC Length Count Maximum. */
/*
* Prototypes.
*/
void usage(FILE * ofp);
int test_docrypt(void);
int test_dokeyedhash(void);
int test_dorandom(void);
int
main(int argc, char **argv)
{
int rval = SNMPERR_SUCCESS, failcount = 0;
char ch;
local_progname = argv[0];
/*
* Parse.
*/
while ((ch = getopt(argc, argv, OPTIONLIST)) != EOF) {
switch (ch) {
case 'a':
doalltests = 1;
break;
case 'c':
docrypt = 1;
break;
case 'H':
dokeyedhash = 1;
break;
case 'r':
dorandom = 1;
break;
case 'h':
rval = 0;
default:
usage(stdout);
exit(rval);
}
argc -= 1;
argv += 1;
optind = 1;
} /* endwhile getopt */
if ((argc > 1)) {
usage(stdout);
exit(1000);
} else if (ALLOPTIONS != 1) {
usage(stdout);
exit(1000);
}
/*
* Test stuff.
*/
rval = sc_init();
FAILED(rval, "sc_init().");
if (docrypt || doalltests) {
failcount += test_docrypt();
}
if (dokeyedhash || doalltests) {
failcount += test_dokeyedhash();
}
if (dorandom || doalltests) {
failcount += test_dorandom();
}
/*
* Cleanup.
*/
rval = sc_shutdown(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
NULL, NULL);
FAILED(rval, "sc_shutdown().");
return failcount;
} /* end main() */
void
usage(FILE * ofp)
{
fprintf(ofp,
USAGE
"" NL
" -a All tests." NL
" -c Test of sc_encrypt()/sc_decrypt()."
NL
" -h Help."
NL
" -H Test sc_{generate,check}_keyed_hash()."
NL
" -r Test sc_random()."
NL "" NL, local_progname);
} /* end usage() */
#ifdef EXAMPLE
/*******************************************************************-o-******
* test_dosomething
*
* Test template.
*
* Returns:
* Number of failures.
*/
int
test_dosomething(void)
{
int rval = SNMPERR_SUCCESS, failcount = 0;
EM0(1, "UNIMPLEMENTED"); /* EM(1); /* */
test_dosomething_quit:
return failcount;
} /* end test_dosomething() */
#endif /* EXAMPLE */
/*******************************************************************-o-******
* test_dorandom
*
* One large request, one set of short requests.
*
* Returns:
* Number of failures.
*
* XXX probably should split up into individual options.
*/
int
test_dorandom(void)
{
int rval = SNMPERR_SUCCESS,
failcount = 0,
origrequest = (1024 * 2),
origrequest_short = 19, nbytes = origrequest, shortcount = 7, i;
char buf[LOCAL_MAXBUF];
OUTPUT("Random test -- large request:");
rval = sc_random(buf, &nbytes);
FAILED(rval, "sc_random().");
if (nbytes != origrequest) {
FAILED(SNMPERR_GENERR,
"sc_random() returned different than requested.");
}
dump_chunk("scapitest", NULL, buf, nbytes);
SUCCESS("Random test -- large request.");
OUTPUT("Random test -- short requests:");
origrequest_short = 16;
for (i = 0; i < shortcount; i++) {
nbytes = origrequest_short;
rval = sc_random(buf, &nbytes);
FAILED(rval, "sc_random().");
if (nbytes != origrequest_short) {
FAILED(SNMPERR_GENERR,
"sc_random() returned different " "than requested.");
}
dump_chunk("scapitest", NULL, buf, nbytes);
} /* endfor */
SUCCESS("Random test -- short requests.");
return failcount;
} /* end test_dorandom() */
/*******************************************************************-o-******
* test_dokeyedhash
*
* Returns:
* Number of failures.
*
*
* Test keyed hashes with a variety of MAC length requests.
*
*
* NOTE Both tests intentionally use the same secret
*
* FIX Get input or output from some other package which hashes...
* XXX Could cut this in half with a little indirection...
*/
int
test_dokeyedhash(void)
{
int rval = SNMPERR_SUCCESS, failcount = 0, bigstring_len = strlen(BIGSTRING), secret_len = strlen(BIGSECRET), properlength, mlcount = 0, /* MAC Length count. */
hblen; /* Hash Buffer length. */
u_int hashbuf_len[MLCOUNT_MAX] = {
LOCAL_MAXBUF,
BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1),
BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5),
BYTESIZE(SNMP_TRANS_AUTHLEN_HMAC96),
7,
0,
};
u_char hashbuf[LOCAL_MAXBUF];
char *s;
test_dokeyedhash_again:
OUTPUT("Keyed hash test using MD5 --");
memset(hashbuf, 0, LOCAL_MAXBUF);
hblen = hashbuf_len[mlcount];
properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
rval =
sc_generate_keyed_hash(usmHMACMD5AuthProtocol,
USM_LENGTH_OID_TRANSFORM, BIGSECRET,
secret_len, BIGSTRING, bigstring_len,
hashbuf, &hblen);
FAILED(rval, "sc_generate_keyed_hash().");
if (hashbuf_len[mlcount] > properlength) {
if (hblen != properlength) {
FAILED(SNMPERR_GENERR, "Wrong MD5 hash length returned. (1)");
}
} else if (hblen != hashbuf_len[mlcount]) {
FAILED(SNMPERR_GENERR, "Wrong MD5 hash length returned. (2)");
}
rval =
sc_check_keyed_hash(usmHMACMD5AuthProtocol,
USM_LENGTH_OID_TRANSFORM, BIGSECRET,
secret_len, BIGSTRING, bigstring_len, hashbuf,
hblen);
FAILED(rval, "sc_check_keyed_hash().");
binary_to_hex(hashbuf, hblen, &s);
fprintf(stdout, "hash buffer (len=%d, request=%d): %s\n",
hblen, hashbuf_len[mlcount], s);
SNMP_FREE(s);
SUCCESS("Keyed hash test using MD5.");
OUTPUT("Keyed hash test using SHA1 --");
memset(hashbuf, 0, LOCAL_MAXBUF);
hblen = hashbuf_len[mlcount];
properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
rval =
sc_generate_keyed_hash(usmHMACSHA1AuthProtocol,
USM_LENGTH_OID_TRANSFORM, BIGSECRET,
secret_len, BIGSTRING, bigstring_len,
hashbuf, &hblen);
FAILED(rval, "sc_generate_keyed_hash().");
if (hashbuf_len[mlcount] > properlength) {
if (hblen != properlength) {
FAILED(SNMPERR_GENERR,
"Wrong SHA1 hash length returned. (1)");
}
} else if (hblen != hashbuf_len[mlcount]) {
FAILED(SNMPERR_GENERR, "Wrong SHA1 hash length returned. (2)");
}
rval =
sc_check_keyed_hash(usmHMACSHA1AuthProtocol,
USM_LENGTH_OID_TRANSFORM, BIGSECRET,
secret_len, BIGSTRING, bigstring_len, hashbuf,
hblen);
FAILED(rval, "sc_check_keyed_hash().");
binary_to_hex(hashbuf, hblen, &s);
fprintf(stdout, "hash buffer (len=%d, request=%d): %s\n",
hblen, hashbuf_len[mlcount], s);
SNMP_FREE(s);
SUCCESS("Keyed hash test using SHA1.");
/*
* Run the basic hash tests but vary the size MAC requests.
*/
if (hashbuf_len[++mlcount] != 0) {
goto test_dokeyedhash_again;
}
return failcount;
} /* end test_dokeyedhash() */
/*******************************************************************-o-******
* test_docrypt
*
* Returns:
* Number of failures.
*/
int
test_docrypt(void)
{
int rval = SNMPERR_SUCCESS,
failcount = 0,
bigstring_len = strlen(BIGSTRING),
secret_len = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES),
iv_len = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
u_int buf_len = LOCAL_MAXBUF, cryptbuf_len = LOCAL_MAXBUF;
char buf[LOCAL_MAXBUF],
cryptbuf[LOCAL_MAXBUF], secret[LOCAL_MAXBUF], iv[LOCAL_MAXBUF];
OUTPUT("Test 1DES-CBC --");
memset(buf, 0, LOCAL_MAXBUF);
memcpy(secret, BIGSECRET, secret_len);
memcpy(iv, BKWDSECRET, iv_len);
rval = sc_encrypt(usmDESPrivProtocol, USM_LENGTH_OID_TRANSFORM,
secret, secret_len,
iv, iv_len,
BIGSTRING, bigstring_len, cryptbuf, &cryptbuf_len);
FAILED(rval, "sc_encrypt().");
rval = sc_decrypt(usmDESPrivProtocol, USM_LENGTH_OID_TRANSFORM,
secret, secret_len,
iv, iv_len, cryptbuf, cryptbuf_len, buf, &buf_len);
FAILED(rval, "sc_decrypt().");
if (buf_len != bigstring_len) {
FAILED(SNMPERR_GENERR, "Decrypted buffer is the wrong length.");
}
if (memcmp(buf, BIGSTRING, bigstring_len)) {
FAILED(SNMPERR_GENERR,
"Decrypted buffer is not equal to original plaintext.");
}
SUCCESS("Test 1DES-CBC --");
return failcount;
} /* end test_docrypt() */