blob: 0b6db79f4e5a117f8b9a4f9c89461ed0a9c161d6 [file] [log] [blame]
/*
* keymanagetest.c
*
* Expected SUCCESSes: 2 + 2 + 3 for all tests.
*
* Returns:
* Number of FAILUREs.
*
*
* FIX Or how about passing a usmUser name and looking up the entry as
* a means of getting key material? This means the userList is
* available from an application...
*
* ASSUMES No key management functions return non-zero success codes.
*
* Test of generate_Ku(). SUCCESSes: 2
* Test of generate_kul(). SUCCESSes: 2
* Test of {encode,decode}_keychange(). SUCCESSes: 3
*/
static char *rcsid = "$Id$"; /* */
#include <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;
#if !defined(__linux__)
extern int optreset;
#endif
/*
* Globals, &c...
*/
char *local_progname;
#define USAGE "Usage: %s [-h][-aklu][-E <engineID>][-N <newkey>][-O <oldkey>][-P <passphrase>]"
#define OPTIONLIST "aqE:hklN:O:P:u"
int doalltests = 0,
dogenKu = 0,
dogenkul = 0,
dokeychange = 0;
#define ALLOPTIONS (doalltests + dogenKu + dogenkul + dokeychange)
#define LOCAL_MAXBUF (1024 * 8)
#define NL "\n"
#define OUTPUTALWAYS(o) fprintf(stdout, "\n\n%s\n\n", o);
#define OUTPUT(o) if (!bequiet) { OUTPUTALWAYS(o); }
#define SUCCESS(s) \
{ \
if (!failcount && !bequiet) \
fprintf(stdout, "\nSUCCESS: %s\n", s); \
}
#define FAILED(e, f) \
{ \
if (e != SNMPERR_SUCCESS && !bequiet) { \
fprintf(stdout, "\nFAILED: %s\n", f); \
failcount += 1; \
} \
}
/*
* Test specific globals.
*/
#define ENGINEID_DEFAULT "1.2.3.4wild"
#define PASSPHRASE_DEFAULT "Clay's Conclusion: Creativity is great, " \
"but plagiarism is faster."
#define OLDKEY_DEFAULT "This is a very old key."
#define NEWKEY_DEFAULT "This key, on the other hand, is very new."
char *engineID = NULL;
char *passphrase = NULL;
char *oldkey = NULL;
char *newkey = NULL;
int bequiet = 0;
/*
* Prototypes.
*/
void usage(FILE *ofp);
int test_genkul(void);
int test_genKu(void);
int test_keychange(void);
int
main(int argc, char **argv)
{
int rval = SNMPERR_SUCCESS,
failcount = 0;
char ch;
local_progname = argv[0];
optarg = NULL;
/*
* Parse.
*/
while ( (ch = getopt(argc, argv, OPTIONLIST)) != EOF )
{
switch(ch) {
case 'a': doalltests = 1; break;
case 'E': engineID = optarg; break;
case 'k': dokeychange = 1; break;
case 'l': dogenkul = 1; break;
case 'N': newkey = optarg; break;
case 'O': oldkey = optarg; break;
case 'P': passphrase = optarg; break;
case 'u': dogenKu = 1; break;
case 'q': bequiet = 1; break;
case 'h':
rval = 0;
default:
usage(stdout);
exit(rval);
}
argc -= 1; argv += 1;
if (optarg) {
argc -= 1; argv += 1;
}
optind = 1;
optarg = NULL;
#if !defined(__linux__)
optreset = 1;
#endif
} /* 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 (dogenKu || doalltests) {
failcount += test_genKu();
}
if (dogenkul || doalltests) {
failcount += test_genkul();
}
if (dokeychange || doalltests) {
failcount += test_keychange();
}
/*
* 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
" -E [0x]<engineID> snmpEngineID string." NL
" -k Test {encode,decode}_keychange()." NL
" -l generate_kul()." NL
" -h Help." NL
" -N [0x]<newkey> New key (for testing KeyChange TC)." NL
" -O [0x]<oldkey> Old key (for testing KeyChange TC)." NL
" -P <passphrase> Source string for usmUser master key." NL
" -u generate_Ku()." NL
" -q be quiet." 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_genKu
*
* Returns:
* Number of failures.
*
*
* Test generation of usmUser master key from a passphrase.
*
* ASSUMES Passphrase is made of printable characters!
*/
int
test_genKu(void)
{
int rval = SNMPERR_SUCCESS,
failcount = 0,
properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5),
kulen;
char *hashname = "usmHMACMD5AuthProtocol.",
*s;
u_char Ku[LOCAL_MAXBUF];
oid *hashtype = usmHMACMD5AuthProtocol;
OUTPUT("Test of generate_Ku --");
/*
* Set passphrase.
*/
if (!passphrase) {
passphrase = PASSPHRASE_DEFAULT;
}
if (!bequiet)
fprintf(stdout, "Passphrase%s:\n\t%s\n\n",
(passphrase == PASSPHRASE_DEFAULT) ? " (default)" : "",
passphrase);
test_genKu_again:
memset(Ku, 0, LOCAL_MAXBUF);
kulen = LOCAL_MAXBUF;
rval = generate_Ku( hashtype, USM_LENGTH_OID_TRANSFORM,
passphrase, strlen(passphrase),
Ku, &kulen);
FAILED(rval, "generate_Ku().");
if (kulen != properlength) {
FAILED(SNMPERR_GENERR, "Ku length is wrong for this hashtype.");
}
binary_to_hex(Ku, kulen, &s);
if (!bequiet)
fprintf(stdout, "Ku (len=%d): %s\n", kulen, s);
free_zero(s, kulen);
SUCCESS(hashname);
if (!bequiet)
fprintf(stdout, "\n");
#ifdef HAVE_LIBKMT
if (hashtype == usmHMACMD5AuthProtocol) {
hashtype = usmHMACSHA1AuthProtocol;
hashname = "usmHMACSHA1AuthProtocol.";
properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
goto test_genKu_again;
}
#endif
return failcount;
} /* end test_genKu() */
/*******************************************************************-o-******
* test_genkul
*
* Returns:
* Number of failures.
*
*
* Test of generate_kul().
*
* A passphrase and engineID are hashed into a master key Ku using
* both known hash transforms. Localized keys, also using both hash
* transforms, are generated from each of these master keys.
*
* ASSUME generate_Ku is already tested.
* ASSUME engineID is initially a NULL terminated string.
*/
int
test_genkul(void)
{
int rval = SNMPERR_SUCCESS,
failcount = 0,
properlength,
kulen,
kul_len,
engineID_len,
isdefault = FALSE;
char *s = NULL,
*testname = "Using HMACMD5 to create master key.",
*hashname_Ku = "usmHMACMD5AuthProtocol",
*hashname_kul;
u_char Ku[LOCAL_MAXBUF],
kul[LOCAL_MAXBUF];
oid *hashtype_Ku = usmHMACMD5AuthProtocol,
*hashtype_kul;
OUTPUT("Test of generate_kul --");
/*
* Set passphrase and engineID.
*
* If engineID begins with 0x, assume it is written in (printable)
* hex and convert it to binary data.
*/
if (!passphrase) {
passphrase = PASSPHRASE_DEFAULT;
}
if (!bequiet)
fprintf(stdout, "Passphrase%s:\n\t%s\n\n",
(passphrase == PASSPHRASE_DEFAULT) ? " (default)" : "",
passphrase);
if (!engineID) {
engineID = ENGINEID_DEFAULT;
isdefault = TRUE;
}
engineID_len = strlen(engineID);
if (tolower(*(engineID+1)) == 'x') {
engineID_len = hex_to_binary2(engineID+2, engineID_len-2, &s);
if (engineID_len < 0) {
FAILED( (rval = SNMPERR_GENERR),
"Could not resolve hex engineID.");
}
engineID = s;
binary_to_hex(engineID, engineID_len, &s);
}
if (!bequiet)
fprintf(stdout, "engineID%s (len=%d): %s\n\n",
(isdefault) ? " (default)" : "",
engineID_len, (s) ? s : engineID);
if (s) {
SNMP_FREE(s);
}
/*
* Create a master key using both hash transforms; create localized
* keys using both hash transforms from each master key.
*/
test_genkul_again_master:
memset(Ku, 0, LOCAL_MAXBUF);
kulen = LOCAL_MAXBUF;
hashname_kul = "usmHMACMD5AuthProtocol";
hashtype_kul = usmHMACMD5AuthProtocol;
properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
rval = generate_Ku( hashtype_Ku, USM_LENGTH_OID_TRANSFORM,
passphrase, strlen(passphrase),
Ku, &kulen);
FAILED(rval, "generate_Ku().");
binary_to_hex(Ku, kulen, &s);
if (!bequiet)
fprintf(stdout,
"\n\nMaster Ku using \"%s\":\n\t%s\n\n", hashname_Ku, s);
free_zero(s, kulen);
test_genkul_again_local:
memset(kul, 0, LOCAL_MAXBUF);
kul_len = LOCAL_MAXBUF;
rval = generate_kul( hashtype_kul, USM_LENGTH_OID_TRANSFORM,
engineID, engineID_len,
Ku, kulen,
kul, &kul_len);
if ( (hashtype_Ku == usmHMACMD5AuthProtocol)
&& (hashtype_kul == usmHMACSHA1AuthProtocol) )
{
if (rval == SNMPERR_SUCCESS) {
FAILED( SNMPERR_GENERR,
"generate_kul SHOULD fail when Ku length is "
"less than hash transform length.");
}
} else {
FAILED(rval, "generate_kul().");
if (kul_len != properlength) {
FAILED( SNMPERR_GENERR,
"kul length is wrong for the given hashtype.");
}
binary_to_hex(kul, kul_len, &s);
fprintf(stdout, "kul (%s) (len=%d): %s\n",
((hashtype_Ku == usmHMACMD5AuthProtocol)?"MD5":"SHA"),
kul_len, s);
free_zero(s, kul_len);
}
/* Create localized key using the other hash transform, but from
* the same master key.
*/
#ifdef HAVE_LIBKMT
if (hashtype_kul == usmHMACMD5AuthProtocol) {
hashtype_kul = usmHMACSHA1AuthProtocol;
hashname_kul = "usmHMACSHA1AuthProtocol";
properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
goto test_genkul_again_local;
}
#endif
SUCCESS(testname);
/* Re-create the master key using the other hash transform.
*/
#ifdef HAVE_LIBKMT
if (hashtype_Ku == usmHMACMD5AuthProtocol) {
hashtype_Ku = usmHMACSHA1AuthProtocol;
hashname_Ku = "usmHMACSHA1AuthProtocol";
testname = "Using HMACSHA1 to create master key.";
goto test_genkul_again_master;
}
#endif
return failcount;
} /* end test_genkul() */
/*******************************************************************-o-******
* test_keychange
*
* Returns:
* Number of failures.
*
*
* Test of KeyChange TC implementation.
*
* ASSUME newkey and oldkey begin as NULL terminated strings.
*/
int
test_keychange(void)
{
int rval = SNMPERR_SUCCESS,
failcount = 0,
properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5),
oldkey_len,
newkey_len,
keychange_len,
temp_len,
isdefault_new = FALSE,
isdefault_old = FALSE;
char *hashname = "usmHMACMD5AuthProtocol.",
*s;
u_char oldkey_buf[LOCAL_MAXBUF],
newkey_buf[LOCAL_MAXBUF],
temp_buf[LOCAL_MAXBUF],
keychange_buf[LOCAL_MAXBUF];
oid *hashtype = usmHMACMD5AuthProtocol;
OUTPUT("Test of KeyChange TC --");
/*
* Set newkey and oldkey.
*/
if (!newkey) { /* newkey */
newkey = NEWKEY_DEFAULT;
isdefault_new = TRUE;
}
newkey_len = strlen(newkey);
if (tolower(*(newkey+1)) == 'x') {
newkey_len = hex_to_binary2(newkey+2, newkey_len-2, &s);
if (newkey_len < 0) {
FAILED( (rval = SNMPERR_GENERR),
"Could not resolve hex newkey.");
}
newkey = s;
binary_to_hex(newkey, newkey_len, &s);
}
if (!oldkey) { /* oldkey */
oldkey = OLDKEY_DEFAULT;
isdefault_old = TRUE;
}
oldkey_len = strlen(oldkey);
if (tolower(*(oldkey+1)) == 'x') {
oldkey_len = hex_to_binary2(oldkey+2, oldkey_len-2, &s);
if (oldkey_len < 0) {
FAILED( (rval = SNMPERR_GENERR),
"Could not resolve hex oldkey.");
}
oldkey = s;
binary_to_hex(oldkey, oldkey_len, &s);
}
test_keychange_again:
memset(oldkey_buf, 0, LOCAL_MAXBUF);
memset(newkey_buf, 0, LOCAL_MAXBUF);
memset(keychange_buf, 0, LOCAL_MAXBUF);
memset(temp_buf, 0, LOCAL_MAXBUF);
memcpy(oldkey_buf, oldkey, SNMP_MIN(oldkey_len, properlength));
memcpy(newkey_buf, newkey, SNMP_MIN(newkey_len, properlength));
keychange_len = LOCAL_MAXBUF;
binary_to_hex(oldkey_buf, properlength, &s);
fprintf(stdout, "\noldkey%s (len=%d): %s\n",
(isdefault_old) ? " (default)" : "", properlength, s);
SNMP_FREE(s);
binary_to_hex(newkey_buf, properlength, &s);
fprintf(stdout, "newkey%s (len=%d): %s\n\n",
(isdefault_new) ? " (default)" : "", properlength, s);
SNMP_FREE(s);
rval = encode_keychange(hashtype, USM_LENGTH_OID_TRANSFORM,
oldkey_buf, properlength,
newkey_buf, properlength,
keychange_buf, &keychange_len);
FAILED(rval, "encode_keychange().");
if (keychange_len != (properlength*2)) {
FAILED( SNMPERR_GENERR,
"KeyChange string (encoded) is not proper length "
"for this hash transform.");
}
binary_to_hex(keychange_buf, keychange_len, &s);
fprintf(stdout, "(%s) KeyChange string: %s\n\n",
((hashtype == usmHMACMD5AuthProtocol)?"MD5":"SHA"),s);
SNMP_FREE(s);
temp_len = properlength;
rval = decode_keychange(hashtype, USM_LENGTH_OID_TRANSFORM,
oldkey_buf, properlength,
keychange_buf, properlength*2,
temp_buf, &temp_len);
FAILED(rval, "decode_keychange().");
if (temp_len != properlength) {
FAILED( SNMPERR_GENERR,
"decoded newkey is not proper length for "
"this hash transform.");
}
binary_to_hex(temp_buf, temp_len, &s);
fprintf(stdout, "decoded newkey: %s\n\n", s);
SNMP_FREE(s);
if ( memcmp(newkey_buf, temp_buf, temp_len) ) {
FAILED( SNMPERR_GENERR, "newkey did not decode properly.");
}
SUCCESS(hashname);
fprintf(stdout, "\n");
/*
* Multiplex different test combinations.
*
* First clause is for Test #2, second clause is for (last) Test #3.
*/
#ifdef HAVE_LIBKMT
if (hashtype == usmHMACMD5AuthProtocol) {
hashtype = usmHMACSHA1AuthProtocol;
hashname = "usmHMACSHA1AuthProtocol (w/DES length kul's).";
properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES)
+ BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
goto test_keychange_again;
} else if ( properlength < BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1) ) {
hashtype = usmHMACSHA1AuthProtocol;
hashname = "usmHMACSHA1AuthProtocol.";
properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
goto test_keychange_again;
}
#endif
return failcount;
} /* end test_keychange() */