/* * keymanagetest.c * * HEADER Testing key management API functionality * * 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 */ #include #include #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #include #include #include #include #include #include #include #include #include #include extern char *optarg; extern int optind, optopt, opterr; int testcount = 0; /* * Globals, &c... */ char *local_progname; #define USAGE "Usage: %s [-h][-aklu][-E ][-N ][-O ][-P ]" #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, "# %s\n", o); #define OUTPUT(o) if (!bequiet) { OUTPUTALWAYS(o); } #define SUCCESS(s) \ { \ fprintf(stdout, "# Done with %s\n", s); \ } #define FAILED(e, f) \ { \ if ((e) != SNMPERR_SUCCESS) { \ fprintf(stdout, "not ok: %d - %s\n", ++testcount, f); \ failcount += 1; \ } else { \ fprintf(stdout, "ok: %d - %s\n", ++testcount, f); \ } \ fflush(stdout); \ } #define DETAILINT(s, i) \ fprintf(stdout, "# %s: %d\n", s, i); /* * 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." u_char *engineID = NULL; char *passphrase = NULL; const u_char *oldkey = NULL; const u_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 = (u_char *) optarg; break; case 'k': dokeychange = 1; break; case 'l': dogenkul = 1; break; case 'N': newkey = (u_char *) optarg; break; case 'O': oldkey = (u_char *) 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; } /* endwhile getopt */ if ((argc > 1)) { usage(stdout); exit(1000); } else if (ALLOPTIONS != 1) { doalltests = 1; } /* * 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(); } fprintf(stdout, "1..%d\n", testcount); return failcount; } /* end main() */ void usage(FILE * ofp) { fprintf(ofp, USAGE "" NL " -a All tests." NL " -E [0x] snmpEngineID string." NL " -k Test {encode,decode}_keychange()." NL " -l generate_kul()." NL " -h Help." NL " -N [0x] New key (for testing KeyChange TC)." NL " -O [0x] Old key (for testing KeyChange TC)." NL " -P 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); size_t kulen; const char *hashname = "usmHMACMD5AuthProtocol."; char *s; u_char Ku[LOCAL_MAXBUF]; oid *hashtype = usmHMACMD5AuthProtocol; OUTPUT("Test of generate_Ku --"); /* * Set passphrase. */ if (!passphrase) { passphrase = strdup(PASSPHRASE_DEFAULT); } if (!bequiet) fprintf(stdout, "Passphrase%s: %s\n", (strcmp(passphrase, PASSPHRASE_DEFAULT) == 0) ? " (default)" : "", passphrase); test_genKu_again: memset(Ku, 0, LOCAL_MAXBUF); kulen = LOCAL_MAXBUF; rval = generate_Ku(hashtype, USM_LENGTH_OID_TRANSFORM, (const u_char *) passphrase, strlen(passphrase), Ku, &kulen); FAILED(rval, "generate_Ku()."); FAILED((kulen != properlength), "Ku length is the right length for this hashtype."); binary_to_hex(Ku, kulen, &s); if (!bequiet) fprintf(stdout, "# Ku (len=%" NETSNMP_PRIz "u): %s\n", kulen, s); free_zero(s, kulen); OUTPUT(hashname); if (hashtype == usmHMACMD5AuthProtocol) { hashtype = usmHMACSHA1AuthProtocol; hashname = "usmHMACSHA1AuthProtocol."; properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1); goto test_genKu_again; } 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, engineID_len, isdefault = FALSE; size_t kulen, kul_len; char *s = NULL; const char *testname = "Using HMACMD5 to create master key."; const char *hashname_Ku = "usmHMACMD5AuthProtocol"; 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 = strdup(PASSPHRASE_DEFAULT); } if (!bequiet) fprintf(stdout, "# Passphrase%s: %s\n", (strcmp(passphrase, PASSPHRASE_DEFAULT) == 0) ? " (default)" : "", passphrase); if (!engineID) { engineID = (u_char *) strdup(ENGINEID_DEFAULT); isdefault = TRUE; } engineID_len = strlen((char *) engineID); if (tolower(*(engineID + 1)) == 'x') { engineID_len = hex_to_binary2(engineID + 2, engineID_len - 2, &s); FAILED((engineID_len < 0), "Could not resolve hex engineID."); engineID = (u_char *) s; binary_to_hex(engineID, engineID_len, &s); } if (!bequiet) fprintf(stdout, "# engineID%s (len=%d): %s\n", (isdefault) ? " (default)" : "", engineID_len, ((s != 0) ? ((u_char *) s) : engineID)); 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; hashtype_kul = usmHMACMD5AuthProtocol; properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5); rval = generate_Ku(hashtype_Ku, USM_LENGTH_OID_TRANSFORM, (u_char *) passphrase, strlen(passphrase), Ku, &kulen); FAILED(rval, "generate_Ku()."); binary_to_hex(Ku, kulen, &s); if (!bequiet) fprintf(stdout, "# Master Ku using \"%s\": \t%s\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)) { FAILED((rval == SNMPERR_SUCCESS), "generate_kul SHOULD fail when Ku length is " "less than hash transform length."); } else { FAILED(rval, "generate_kul()."); FAILED(kul_len != properlength, "checking if kul length is right for the given hashtype."); binary_to_hex(kul, kul_len, &s); fprintf(stdout, "# kul (%s) (len=%" NETSNMP_PRIz "u): %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. */ if (hashtype_kul == usmHMACMD5AuthProtocol) { hashtype_kul = usmHMACSHA1AuthProtocol; properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1); goto test_genkul_again_local; } SUCCESS(testname); /* * Re-create the master key using the other hash transform. */ if (hashtype_Ku == usmHMACMD5AuthProtocol) { hashtype_Ku = usmHMACSHA1AuthProtocol; hashname_Ku = "usmHMACSHA1AuthProtocol"; testname = "Using HMACSHA1 to create master key."; goto test_genkul_again_master; } 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, isdefault_new = FALSE, isdefault_old = FALSE; size_t keychange_len, temp_len; const char *hashname = "usmHMACMD5AuthProtocol."; char *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 = (const u_char *) NEWKEY_DEFAULT; isdefault_new = TRUE; } newkey_len = strlen((const char *) newkey); if (tolower(*(newkey + 1)) == 'x') { newkey_len = hex_to_binary2((const u_char *) newkey + 2, newkey_len - 2, &s); FAILED(newkey_len < 0, "Could not resolve hex newkey."); newkey = (const u_char *) s; binary_to_hex((const u_char *) newkey, newkey_len, &s); } if (!oldkey) { /* oldkey */ oldkey = (const u_char *) OLDKEY_DEFAULT; isdefault_old = TRUE; } oldkey_len = strlen((const char *) oldkey); if (tolower(*(oldkey + 1)) == 'x') { oldkey_len = hex_to_binary2((const u_char *) oldkey + 2, oldkey_len - 2, &s); FAILED(oldkey_len < 0, "Could not resolve hex oldkey."); oldkey = (const u_char *) 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, "# oldkey%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", (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()."); FAILED(keychange_len != (properlength * 2), "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", ((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()."); FAILED(temp_len != properlength, "decoded newkey is not proper length for " "this hash transform."); binary_to_hex(temp_buf, temp_len, &s); fprintf(stdout, "# decoded newkey: %s\n", s); SNMP_FREE(s); FAILED(memcmp(newkey_buf, temp_buf, temp_len), "newkey did not decode properly."); SUCCESS(hashname); /* * Multiplex different test combinations. * * First clause is for Test #2, second clause is for (last) Test #3. */ 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; } return failcount; } /* end test_keychange() */