keytools.c
上传用户:cxs890
上传日期:2021-05-22
资源大小:347k
文件大小:17k
源码类别:

SNMP编程

开发平台:

C/C++

  1. /*
  2.  * keytools.c
  3.  */
  4. #include <config.h>
  5. #include <stdio.h>
  6. #include <sys/types.h>
  7. #if HAVE_WINSOCK_H
  8. #include <ip/socket.h>
  9. #endif
  10. #ifdef HAVE_NETINET_IN_H
  11. #include <netinet/in.h>
  12. #endif
  13. #ifdef HAVE_STDLIB_H
  14. #include <stdlib.h>
  15. #endif
  16. #if HAVE_STRING_H
  17. #include <string.h>
  18. #else
  19. #include <strings.h>
  20. #endif
  21. #if HAVE_DMALLOC_H
  22. #include <dmalloc.h>
  23. #endif
  24. #include "asn1.h"
  25. #include "snmp_api.h"
  26. #ifdef USE_OPENSSL
  27. # include <openssl/hmac.h>
  28. #else 
  29. #ifdef USE_INTERNAL_MD5
  30. /*#include "md5.h"*/
  31. #include <libsys/md5.h>
  32. #ifdef SWITCH
  33. #include <libsys/sha.h>
  34. #endif
  35. #endif
  36. #endif
  37. #include "scapi.h"
  38. #include "keytools.h"
  39. #include "tools.h"
  40. #include "snmp_debug.h"
  41. #include "snmp_logging.h"
  42. #include "transform_oids.h"
  43. typedef (*HASH_INIT_FUNC)(void *ctx);
  44. typedef (*HASH_UPDATE_FUNC)(void *ctx, unsigned char *dataIn, int len);
  45. typedef (*HASH_FINAL_FUNC)(unsigned char *hashout, void *ctx);
  46. /*******************************************************************-o-******
  47.  * generate_Ku
  48.  *
  49.  * Parameters:
  50.  * *hashtype MIB OID for the transform type for hashing.
  51.  *  hashtype_len Length of OID value.
  52.  * *P Pre-allocated bytes of passpharase.
  53.  *  pplen Length of passphrase.
  54.  * *Ku Buffer to contain Ku.
  55.  * *kulen Length of Ku buffer.
  56.  *      
  57.  * Returns:
  58.  * SNMPERR_SUCCESS Success.
  59.  * SNMPERR_GENERR All errors.
  60.  *
  61.  *
  62.  * Convert a passphrase into a master user key, Ku, according to the
  63.  * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM)
  64.  * as follows:
  65.  *
  66.  * Expand the passphrase to fill the passphrase buffer space, if necessary,
  67.  * concatenation as many duplicates as possible of P to itself.  If P is
  68.  * larger than the buffer space, truncate it to fit.
  69.  *
  70.  * Then hash the result with the given hashtype transform.  Return
  71.  * the result as Ku.
  72.  *
  73.  * If successful, kulen contains the size of the hash written to Ku.
  74.  *
  75.  * NOTE  Passphrases less than USM_LENGTH_P_MIN characters in length
  76.  *  cause an error to be returned.
  77.  *  (Punt this check to the cmdline apps?  XXX)
  78.  */
  79. int
  80. generate_Ku( oid *hashtype, u_int  hashtype_len,
  81. u_char *P, size_t  pplen,
  82. u_char *Ku, size_t *kulen)
  83. #ifdef INCLUDE_SNMPV3
  84. {
  85. int  rval   = SNMPERR_SUCCESS,
  86.  nbytes = USM_LENGTH_EXPANDED_PASSPHRASE;
  87.         u_int            i, pindex = 0;
  88. u_char  buf[USM_LENGTH_KU_HASHBLOCK],
  89. *bufp;
  90.     HASH_INIT_FUNC hash_init_func;
  91.     HASH_UPDATE_FUNC hash_update_func;
  92.     HASH_FINAL_FUNC hash_final_func;
  93. #ifdef USE_OPENSSL
  94. EVP_MD_CTX      *ctx = malloc(sizeof(EVP_MD_CTX));
  95. #else
  96.     MD5_CTX MD;
  97.     SHA_CTX SHA;
  98.     void *ctx;
  99. #endif
  100. /*
  101.  * Sanity check.
  102.  */
  103. if ( !hashtype || !P || !Ku || !kulen
  104. || (*kulen<=0)
  105. || (hashtype_len != USM_LENGTH_OID_TRANSFORM) )
  106. {
  107. QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
  108. }
  109.         if (pplen < USM_LENGTH_P_MIN) {
  110. #ifdef SNMP_TESTING_CODE
  111.           snmp_log(LOG_WARNING, "Warning: passphrase chosen is below the length requiremnts of the USM.n");
  112. #else
  113.           snmp_set_detail("Password length too short.");
  114.           QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
  115. #endif
  116.         }
  117. /*
  118.  * Setup for the transform type.
  119.  */
  120. if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
  121.         hash_init_func = (HASH_INIT_FUNC)MD5Init;
  122.         hash_update_func = (HASH_UPDATE_FUNC)MD5Update;
  123.         hash_final_func = (HASH_FINAL_FUNC)MD5Final;
  124.         ctx = (void*)&MD;
  125. }
  126. else if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
  127.         hash_init_func = (HASH_INIT_FUNC)SHAInit;
  128.         hash_update_func = (HASH_UPDATE_FUNC)SHAUpdate;
  129.         hash_final_func = (HASH_FINAL_FUNC)SHAFinal;
  130.         ctx = (void*)&SHA;
  131.     }
  132. else  {
  133.   return (SNMPERR_GENERR);
  134. }
  135. #ifdef USE_OPENSSL
  136. if (ISTRANSFORM(hashtype, HMACMD5Auth))
  137.   EVP_DigestInit(ctx, EVP_md5());
  138. else if (ISTRANSFORM(hashtype, HMACSHA1Auth))
  139.   EVP_DigestInit(ctx, EVP_sha1());
  140. else  {
  141.   free(ctx);
  142.   return (SNMPERR_GENERR);
  143. }
  144. #else 
  145.         hash_init_func(ctx);
  146. #endif /* USE_OPENSSL */
  147.         while (nbytes > 0) {
  148.                 bufp = buf;
  149.                 for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) {
  150.                         *bufp++ = P[pindex++ % pplen];
  151.                 }
  152. #ifdef USE_OPENSSL
  153. EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK);
  154. #else
  155. /*                MD5Update(&MD, buf, USM_LENGTH_KU_HASHBLOCK);*/
  156.                 hash_update_func(ctx, buf, USM_LENGTH_KU_HASHBLOCK);
  157. #endif /* USE_OPENSSL */
  158.                 nbytes -= USM_LENGTH_KU_HASHBLOCK;
  159.         }
  160. #ifdef USE_OPENSSL
  161. EVP_DigestFinal(ctx, (unsigned char *) Ku, (unsigned int *) kulen);
  162. /* what about free() */
  163. #else
  164. /*        MD5Final(Ku, &MD);*/
  165.         hash_final_func(Ku, ctx);
  166.         *kulen = sc_get_properlength(hashtype, hashtype_len);
  167. /* md5_fin:
  168.         memset(&MD, 0, sizeof(MD)); */
  169. #endif /* USE_OPENSSL */
  170. #ifdef SNMP_TESTING_CODE
  171.         DEBUGMSGTL(("generate_Ku", "generating Ku (from %s): ", P));
  172.         for(i=0; i < *kulen; i++)
  173.           DEBUGMSG(("generate_Ku", "%02x",Ku[i]));
  174.         DEBUGMSG(("generate_Ku","n"));
  175. #endif /* SNMP_TESTING_CODE */
  176. generate_Ku_quit:
  177. memset(buf, 0, sizeof(buf));
  178. #ifdef USE_OPENSSL
  179. free(ctx);
  180. #endif
  181. return rval;
  182. }  /* end generate_Ku() */
  183. #else
  184. {
  185. return -1;
  186. }
  187. #endif /* internal or openssl */
  188. /*******************************************************************-o-******
  189.  * generate_kul
  190.  *
  191.  * Parameters:
  192.  * *hashtype
  193.  *  hashtype_len
  194.  * *engineID
  195.  *  engineID_len
  196.  * *Ku Master key for a given user.
  197.  *  ku_len Length of Ku in bytes.
  198.  * *Kul Localized key for a given user at engineID.
  199.  * *kul_len Length of Kul buffer (IN); Length of Kul key (OUT).
  200.  *      
  201.  * Returns:
  202.  * SNMPERR_SUCCESS Success.
  203.  * SNMPERR_GENERR All errors.
  204.  *
  205.  *
  206.  * Ku MUST be the proper length (currently fixed) for the given hashtype.
  207.  *
  208.  * Upon successful return, Kul contains the localized form of Ku at
  209.  * engineID, and the length of the key is stored in kul_len.
  210.  *
  211.  * The localized key method is defined in RFC2274, Sections 2.6 and A.2, and
  212.  * originally documented in:
  213.  *   U. Blumenthal, N. C. Hien, B. Wijnen,
  214.  *      "Key Derivation for Network Management Applications",
  215.  * IEEE Network Magazine, April/May issue, 1997.
  216.  *
  217.  *
  218.  * ASSUMES  SNMP_MAXBUF >= sizeof(Ku + engineID + Ku).
  219.  *
  220.  * NOTE  Localized keys for privacy transforms are generated via
  221.  *  the authentication transform held by the same usmUser.
  222.  *
  223.  * XXX An engineID of any length is accepted, even if larger than
  224.  * what is spec'ed for the textual convention.
  225.  */
  226. int
  227. generate_kul( oid *hashtype, u_int  hashtype_len,
  228. u_char *engineID, size_t  engineID_len,
  229. u_char *Ku, size_t  ku_len,
  230. u_char *Kul, size_t *kul_len)
  231. #ifdef INCLUDE_SNMPV3
  232. {
  233. int  rval    = SNMPERR_SUCCESS;
  234. u_int  nbytes  = 0;
  235.         size_t           properlength;
  236. u_char  buf[SNMP_MAXBUF];
  237. void *context = NULL;
  238. #ifdef SNMP_TESTING_CODE
  239.         int  i;
  240. #endif
  241.     MD5_CTX MD;
  242.     SHA_CTX SHA;
  243. /*
  244.  * Sanity check.
  245.  */
  246. if ( !hashtype || !engineID || !Ku || !Kul || !kul_len
  247. || (engineID_len<=0) || (ku_len<=0) || (*kul_len<=0)
  248. || (hashtype_len != USM_LENGTH_OID_TRANSFORM) )
  249. {
  250. QUITFUN(SNMPERR_GENERR, generate_kul_quit);
  251. }
  252.         properlength = sc_get_properlength(hashtype, hashtype_len);
  253.         if (properlength == (size_t)SNMPERR_GENERR)
  254.           QUITFUN(SNMPERR_GENERR, generate_kul_quit);
  255.        
  256. if (((int)*kul_len < properlength) || ((int)ku_len < properlength) ) {
  257. QUITFUN(SNMPERR_GENERR, generate_kul_quit);
  258. }
  259. /*
  260.  * Concatenate Ku and engineID properly, then hash the result.
  261.  * Store it in Kul.
  262.  */
  263. nbytes = 0;
  264. memcpy(buf,    Ku, properlength); nbytes += properlength;
  265. memcpy(buf+nbytes, engineID, engineID_len); nbytes += engineID_len;
  266. memcpy(buf+nbytes, Ku, properlength); nbytes += properlength;
  267. if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
  268.         MD5Init(&MD);
  269.         MD5Update(&MD, buf, 32+engineID_len);
  270.         MD5Final(Kul, &MD);
  271.         *kul_len = properlength;
  272. }
  273. else if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
  274.         SHAInit(&SHA);
  275.         SHAUpdate(&SHA, buf, 40+engineID_len);
  276.         SHAFinal(Kul, &SHA);
  277.         *kul_len = properlength;
  278. }
  279. else  {
  280.   return (SNMPERR_GENERR);
  281. }
  282. #ifdef SNMP_TESTING_CODE
  283.         DEBUGMSGTL(("generate_kul", "generating Kul (from Ku): "));
  284.         for(i=0; i < *kul_len; i++)
  285.           DEBUGMSG(("generate_kul", "%02x",Kul[i]));
  286.         DEBUGMSG(("generate_kul", "keytoolsn"));
  287. #endif /* SNMP_TESTING_CODE */
  288. QUITFUN(rval, generate_kul_quit);
  289. generate_kul_quit:
  290. SNMP_FREE(context);
  291. return rval;
  292. }  /* end generate_kul() */
  293. #else
  294. {
  295. return -1;
  296. }
  297. #endif /* internal or openssl */
  298. /*******************************************************************-o-******
  299.  * encode_keychange
  300.  *
  301.  * Parameters:
  302.  * *hashtype MIB OID for the hash transform type.
  303.  *  hashtype_len Length of the MIB OID hash transform type.
  304.  * *oldkey Old key that is used to encodes the new key.
  305.  *  oldkey_len Length of oldkey in bytes.
  306.  * *newkey New key that is encoded using the old key.
  307.  *  newkey_len Length of new key in bytes.
  308.  * *kcstring Buffer to contain the KeyChange TC string.
  309.  * *kcstring_len Length of kcstring buffer.
  310.  *      
  311.  * Returns:
  312.  * SNMPERR_SUCCESS Success.
  313.  * SNMPERR_GENERR All errors.
  314.  *
  315.  *
  316.  * Uses oldkey and acquired random bytes to encode newkey into kcstring
  317.  * according to the rules of the KeyChange TC described in RFC 2274, Section 5.
  318.  *
  319.  * Upon successful return, *kcstring_len contains the length of the
  320.  * encoded string.
  321.  *
  322.  * ASSUMES Old and new key are always equal to each other, although
  323.  * this may be less than the transform type hash output
  324.  *  output length (eg, using KeyChange for a DESPriv key when
  325.  * the user also uses SHA1Auth).  This also implies that the
  326.  * hash placed in the second 1/2 of the key change string
  327.  * will be truncated before the XOR'ing when the hash output is 
  328.  * larger than that 1/2 of the key change string.
  329.  *
  330.  * *kcstring_len will be returned as exactly twice that same
  331.  * length though the input buffer may be larger.
  332.  *
  333.  * XXX FIX:     Does not handle varibable length keys.
  334.  * XXX FIX:     Does not handle keys larger than the hash algorithm used.
  335.  */
  336. int
  337. encode_keychange( oid *hashtype, u_int  hashtype_len,
  338. u_char *oldkey, size_t  oldkey_len,
  339. u_char *newkey, size_t  newkey_len,
  340. u_char *kcstring, size_t *kcstring_len)
  341. #ifdef INCLUDE_SNMPV3 
  342. {
  343. int  rval    = SNMPERR_SUCCESS;
  344. size_t  properlength;
  345.         size_t            nbytes  = 0;
  346.         u_char          *tmpbuf = NULL;
  347. void *context = NULL;
  348. /*
  349.  * Sanity check.
  350.  */
  351. if ( !hashtype || !oldkey || !newkey || !kcstring || !kcstring_len
  352. || (oldkey_len<=0) || (newkey_len<=0) || (*kcstring_len<=0)
  353. || (hashtype_len != USM_LENGTH_OID_TRANSFORM) )
  354. {
  355. QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
  356. }
  357. /*
  358.  * Setup for the transform type.
  359.  */
  360.         properlength = sc_get_properlength(hashtype, hashtype_len);
  361.         if (properlength == (size_t)SNMPERR_GENERR)
  362.           QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
  363. if ( (oldkey_len != newkey_len) || (*kcstring_len < (2*oldkey_len)) )
  364. {
  365. QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
  366. }
  367. properlength = SNMP_MIN((int)oldkey_len, properlength);
  368. /*
  369.  * Use the old key and some random bytes to encode the new key
  370.  * in the KeyChange TC format:
  371.  * . Get random bytes (store in first half of kcstring),
  372.  * . Hash (oldkey | random_bytes) (into second half of kcstring),
  373.  * . XOR hash and newkey (into second half of kcstring).
  374.  *
  375.  * Getting the wrong number of random bytes is considered an error.
  376.  */
  377. nbytes = properlength;
  378. #if defined(SNMP_TESTING_CODE) && defined(RANDOMZEROS)
  379. memset(kcstring, 0, nbytes);
  380. DEBUGMSG(("encode_keychange",
  381.                           "** Using all zero bits for "random" delta of )"
  382.                           "the keychange string! **n"));
  383. #else /* !SNMP_TESTING_CODE */
  384. rval = sc_random(kcstring, &nbytes);
  385. QUITFUN(rval, encode_keychange_quit);
  386. if ((int)nbytes != properlength) {
  387. QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
  388. }
  389. #endif /* !SNMP_TESTING_CODE */
  390.         tmpbuf = (u_char *)malloc(properlength*2);
  391.         if (tmpbuf) {
  392.             memcpy(tmpbuf, oldkey, properlength);
  393.             memcpy(tmpbuf+properlength, kcstring, properlength);
  394.     
  395.             *kcstring_len -= properlength;
  396.             rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength*2,
  397.                            kcstring+properlength, kcstring_len);
  398.             
  399.             QUITFUN(rval, encode_keychange_quit);
  400.     
  401.             *kcstring_len = (properlength*2);
  402.     
  403.             kcstring += properlength;
  404.             nbytes    = 0;
  405.             while ((int)(nbytes++) < properlength) {
  406.              *kcstring++ = *kcstring ^ *newkey++;
  407.             }
  408.         }
  409. encode_keychange_quit:
  410. if (rval != SNMPERR_SUCCESS) memset(kcstring, 0, *kcstring_len);
  411.         SNMP_FREE(tmpbuf);
  412. SNMP_FREE(context);
  413. return rval;
  414. }  /* end encode_keychange() */
  415. #else
  416. {
  417. return -1;
  418. }
  419. #endif /* internal or openssl */
  420. /*******************************************************************-o-******
  421.  * decode_keychange
  422.  *
  423.  * Parameters:
  424.  * *hashtype MIB OID of the hash transform to use.
  425.  *  hashtype_len Length of the hash transform MIB OID.
  426.  * *oldkey Old key that is used to encode the new key.
  427.  *  oldkey_len Length of oldkey in bytes.
  428.  * *kcstring Encoded KeyString buffer containing the new key.
  429.  *  kcstring_len Length of kcstring in bytes.
  430.  * *newkey Buffer to hold the extracted new key.
  431.  * *newkey_len Length of newkey in bytes.
  432.  *      
  433.  * Returns:
  434.  * SNMPERR_SUCCESS Success.
  435.  * SNMPERR_GENERR All errors.
  436.  *
  437.  *
  438.  * Decodes a string of bits encoded according to the KeyChange TC described
  439.  * in RFC 2274, Section 5.  The new key is extracted from *kcstring with
  440.  * the aid of the old key.
  441.  *
  442.  * Upon successful return, *newkey_len contains the length of the new key.
  443.  *
  444.  *
  445.  * ASSUMES Old key is exactly 1/2 the length of the KeyChange buffer,
  446.  * although this length may be less than the hash transform
  447.  * output.  Thus the new key length will be equal to the old
  448.  * key length.
  449.  */
  450. /* XXX:  if the newkey is not long enough, it should be freed and remalloced */
  451. int
  452. decode_keychange( oid *hashtype, u_int  hashtype_len,
  453. u_char *oldkey, size_t  oldkey_len,
  454. u_char *kcstring, size_t  kcstring_len,
  455. u_char *newkey, size_t *newkey_len)
  456. #ifdef INCLUDEV3
  457. {
  458. int  rval    = SNMPERR_SUCCESS;
  459. size_t  properlength = 0;
  460. u_int  nbytes  = 0;
  461. u_char *bufp,
  462.  tmp_buf[SNMP_MAXBUF];
  463.         size_t           tmp_buf_len = SNMP_MAXBUF;
  464. void *context = NULL;
  465.         u_char          *tmpbuf = NULL;
  466. /*
  467.  * Sanity check.
  468.  */
  469. if ( !hashtype || !oldkey || !kcstring || !newkey || !newkey_len
  470. || (oldkey_len<=0) || (kcstring_len<=0) || (*newkey_len<=0)
  471. || (hashtype_len != USM_LENGTH_OID_TRANSFORM) )
  472. {
  473. QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
  474. }
  475. /*
  476.  * Setup for the transform type.
  477.  */
  478.         properlength = sc_get_properlength(hashtype, hashtype_len);
  479.         if (properlength == (size_t)SNMPERR_GENERR)
  480.           QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
  481. if ( ((oldkey_len*2) != kcstring_len) || (*newkey_len < oldkey_len) )
  482. {
  483. QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
  484. }
  485. properlength = oldkey_len;
  486.         *newkey_len = properlength;
  487. /*
  488.  * Use the old key and the given KeyChange TC string to recover
  489.  * the new key:
  490.  * . Hash (oldkey | random_bytes) (into newkey),
  491.  * . XOR hash and encoded (second) half of kcstring (into newkey).
  492.  */
  493.         tmpbuf = (u_char *)malloc(properlength*2);
  494.         if (tmpbuf) {
  495.             memcpy(tmpbuf, oldkey, properlength);
  496.             memcpy(tmpbuf+properlength, kcstring, properlength);
  497.     
  498.             rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength*2,
  499.                            tmp_buf, &tmp_buf_len);
  500.             QUITFUN(rval, decode_keychange_quit);
  501.     
  502.             memcpy(newkey, tmp_buf, properlength);
  503.             bufp   = kcstring+properlength;
  504.             nbytes = 0;
  505.             while ((int)(nbytes++) < properlength) {
  506.                     *newkey++ = *newkey ^ *bufp++;
  507.             }
  508.         }
  509. decode_keychange_quit:
  510. if (rval != SNMPERR_SUCCESS) {
  511. memset(newkey, 0, properlength);
  512. }
  513. memset(tmp_buf, 0, SNMP_MAXBUF);
  514. SNMP_FREE(context);
  515.         if (tmpbuf != NULL) SNMP_FREE(tmpbuf);
  516. return rval;
  517. }  /* end decode_keychange() */
  518. #else
  519. {
  520. return -1;
  521. }
  522. #endif /* internal or openssl */