| /* |
| * 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 <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; |
| |
| |
| |
| /* |
| * 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; |
| } /* 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"); |
| |
| 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, 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. |
| */ |
| if (hashtype_kul == usmHMACMD5AuthProtocol) { |
| hashtype_kul = usmHMACSHA1AuthProtocol; |
| hashname_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, |
| 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. |
| */ |
| 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() */ |