text: /*
   * 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: keymanagetest.c,v 5.0 2002/04/20 07:30:22 hardaker Exp $";        /* */
  
  #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() */
  