net-snmp 5.7
|
00001 /* Portions of this file are subject to the following copyright(s). See 00002 * the Net-SNMP's COPYING file for more details and other copyrights 00003 * that may apply: 00004 */ 00005 /* 00006 * Portions of this file are copyrighted by: 00007 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00008 * Use is subject to license terms specified in the COPYING file 00009 * distributed with the Net-SNMP package. 00010 */ 00011 00012 /* 00013 * keytools.c 00014 */ 00015 00016 #include <net-snmp/net-snmp-config.h> 00017 #include <net-snmp/net-snmp-features.h> 00018 00019 #include <stdio.h> 00020 #include <sys/types.h> 00021 #ifdef HAVE_NETINET_IN_H 00022 #include <netinet/in.h> 00023 #endif 00024 #ifdef HAVE_STDLIB_H 00025 #include <stdlib.h> 00026 #endif 00027 #if HAVE_STRING_H 00028 #include <string.h> 00029 #else 00030 #include <strings.h> 00031 #endif 00032 00033 #if HAVE_UNISTD_H 00034 #include <unistd.h> 00035 #endif 00036 #if HAVE_DMALLOC_H 00037 #include <dmalloc.h> 00038 #endif 00039 00040 #include <net-snmp/types.h> 00041 #include <net-snmp/output_api.h> 00042 #include <net-snmp/utilities.h> 00043 00044 #include <net-snmp/library/snmp_api.h> 00045 #ifdef NETSNMP_USE_OPENSSL 00046 # include <openssl/hmac.h> 00047 #else 00048 #ifdef NETSNMP_USE_INTERNAL_MD5 00049 #include <net-snmp/library/md5.h> 00050 #endif 00051 #endif 00052 #ifdef NETSNMP_USE_INTERNAL_CRYPTO 00053 #include <net-snmp/library/openssl_md5.h> 00054 #include <net-snmp/library/openssl_sha.h> 00055 #endif 00056 00057 #ifdef NETSNMP_USE_PKCS11 00058 #include <security/cryptoki.h> 00059 #endif 00060 00061 #include <net-snmp/library/scapi.h> 00062 #include <net-snmp/library/keytools.h> 00063 00064 #include <net-snmp/library/transform_oids.h> 00065 00066 netsnmp_feature_child_of(usm_support, libnetsnmp) 00067 netsnmp_feature_child_of(usm_keytools, usm_support) 00068 00069 #ifndef NETSNMP_FEATURE_REMOVE_USM_KEYTOOLS 00070 00071 /*******************************************************************-o-****** 00072 * generate_Ku 00073 * 00074 * Parameters: 00075 * *hashtype MIB OID for the transform type for hashing. 00076 * hashtype_len Length of OID value. 00077 * *P Pre-allocated bytes of passpharase. 00078 * pplen Length of passphrase. 00079 * *Ku Buffer to contain Ku. 00080 * *kulen Length of Ku buffer. 00081 * 00082 * Returns: 00083 * SNMPERR_SUCCESS Success. 00084 * SNMPERR_GENERR All errors. 00085 * 00086 * 00087 * Convert a passphrase into a master user key, Ku, according to the 00088 * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM) 00089 * as follows: 00090 * 00091 * Expand the passphrase to fill the passphrase buffer space, if necessary, 00092 * concatenation as many duplicates as possible of P to itself. If P is 00093 * larger than the buffer space, truncate it to fit. 00094 * 00095 * Then hash the result with the given hashtype transform. Return 00096 * the result as Ku. 00097 * 00098 * If successful, kulen contains the size of the hash written to Ku. 00099 * 00100 * NOTE Passphrases less than USM_LENGTH_P_MIN characters in length 00101 * cause an error to be returned. 00102 * (Punt this check to the cmdline apps? XXX) 00103 */ 00104 int 00105 generate_Ku(const oid * hashtype, u_int hashtype_len, 00106 const u_char * P, size_t pplen, u_char * Ku, size_t * kulen) 00107 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_CRYPTO) 00108 { 00109 int rval = SNMPERR_SUCCESS, 00110 nbytes = USM_LENGTH_EXPANDED_PASSPHRASE; 00111 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_INTERNAL_CRYPTO) 00112 int ret; 00113 #endif 00114 00115 u_int i, pindex = 0; 00116 00117 u_char buf[USM_LENGTH_KU_HASHBLOCK], *bufp; 00118 00119 #ifdef NETSNMP_USE_OPENSSL 00120 EVP_MD_CTX *ctx = (EVP_MD_CTX *)malloc(sizeof(EVP_MD_CTX)); 00121 unsigned int tmp_len; 00122 #elif NETSNMP_USE_INTERNAL_CRYPTO 00123 SHA_CTX csha1; 00124 MD5_CTX cmd5; 00125 char cryptotype = 0; 00126 unsigned int tmp_len; 00127 #define TYPE_MD5 1 00128 #define TYPE_SHA1 2 00129 #else 00130 MDstruct MD; 00131 #endif 00132 /* 00133 * Sanity check. 00134 */ 00135 if (!hashtype || !P || !Ku || !kulen || (*kulen <= 0) 00136 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) { 00137 QUITFUN(SNMPERR_GENERR, generate_Ku_quit); 00138 } 00139 00140 if (pplen < USM_LENGTH_P_MIN) { 00141 snmp_log(LOG_ERR, "Error: passphrase chosen is below the length " 00142 "requirements of the USM (min=%d).\n",USM_LENGTH_P_MIN); 00143 snmp_set_detail("The supplied password length is too short."); 00144 QUITFUN(SNMPERR_GENERR, generate_Ku_quit); 00145 } 00146 00147 00148 /* 00149 * Setup for the transform type. 00150 */ 00151 #ifdef NETSNMP_USE_OPENSSL 00152 00153 #ifndef NETSNMP_DISABLE_MD5 00154 if (ISTRANSFORM(hashtype, HMACMD5Auth)) 00155 EVP_DigestInit(ctx, EVP_md5()); 00156 else 00157 #endif 00158 if (ISTRANSFORM(hashtype, HMACSHA1Auth)) 00159 EVP_DigestInit(ctx, EVP_sha1()); 00160 else { 00161 free(ctx); 00162 return (SNMPERR_GENERR); 00163 } 00164 #elif NETSNMP_USE_INTERNAL_CRYPTO 00165 #ifndef NETSNMP_DISABLE_MD5 00166 if (ISTRANSFORM(hashtype, HMACMD5Auth)) { 00167 MD5_Init(&cmd5); 00168 cryptotype = TYPE_MD5; 00169 } else 00170 #endif 00171 if (ISTRANSFORM(hashtype, HMACSHA1Auth)) { 00172 SHA1_Init(&csha1); 00173 cryptotype = TYPE_SHA1; 00174 } else { 00175 return (SNMPERR_GENERR); 00176 } 00177 #else 00178 MDbegin(&MD); 00179 #endif /* NETSNMP_USE_OPENSSL */ 00180 00181 while (nbytes > 0) { 00182 bufp = buf; 00183 for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) { 00184 *bufp++ = P[pindex++ % pplen]; 00185 } 00186 #ifdef NETSNMP_USE_OPENSSL 00187 EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK); 00188 #elif NETSNMP_USE_INTERNAL_CRYPTO 00189 if (TYPE_SHA1 == cryptotype) { 00190 rval = !SHA1_Update(&csha1, buf, USM_LENGTH_KU_HASHBLOCK); 00191 } else { 00192 rval = !MD5_Update(&cmd5, buf, USM_LENGTH_KU_HASHBLOCK); 00193 } 00194 if (rval != 0) { 00195 return SNMPERR_USM_ENCRYPTIONERROR; 00196 } 00197 #elif NETSNMP_USE_INTERNAL_MD5 00198 if (MDupdate(&MD, buf, USM_LENGTH_KU_HASHBLOCK * 8)) { 00199 rval = SNMPERR_USM_ENCRYPTIONERROR; 00200 goto md5_fin; 00201 } 00202 #endif /* NETSNMP_USE_OPENSSL */ 00203 nbytes -= USM_LENGTH_KU_HASHBLOCK; 00204 } 00205 00206 #ifdef NETSNMP_USE_OPENSSL 00207 tmp_len = *kulen; 00208 EVP_DigestFinal(ctx, (unsigned char *) Ku, &tmp_len); 00209 *kulen = tmp_len; 00210 /* 00211 * what about free() 00212 */ 00213 #elif NETSNMP_USE_INTERNAL_CRYPTO 00214 tmp_len = *kulen; 00215 if (TYPE_SHA1 == cryptotype) { 00216 SHA1_Final(Ku, &csha1); 00217 } else { 00218 MD5_Final(Ku, &cmd5); 00219 } 00220 ret = sc_get_properlength(hashtype, hashtype_len); 00221 if (ret == SNMPERR_GENERR) 00222 return SNMPERR_GENERR; 00223 *kulen = ret; 00224 #elif NETSNMP_USE_INTERNAL_MD5 00225 if (MDupdate(&MD, buf, 0)) { 00226 rval = SNMPERR_USM_ENCRYPTIONERROR; 00227 goto md5_fin; 00228 } 00229 ret = sc_get_properlength(hashtype, hashtype_len); 00230 if (ret == SNMPERR_GENERR) 00231 return SNMPERR_GENERR; 00232 *kulen = ret; 00233 MDget(&MD, Ku, *kulen); 00234 md5_fin: 00235 memset(&MD, 0, sizeof(MD)); 00236 #endif /* NETSNMP_USE_INTERNAL_MD5 */ 00237 00238 00239 #ifdef NETSNMP_ENABLE_TESTING_CODE 00240 DEBUGMSGTL(("generate_Ku", "generating Ku (from %s): ", P)); 00241 for (i = 0; i < *kulen; i++) 00242 DEBUGMSG(("generate_Ku", "%02x", Ku[i])); 00243 DEBUGMSG(("generate_Ku", "\n")); 00244 #endif /* NETSNMP_ENABLE_TESTING_CODE */ 00245 00246 00247 generate_Ku_quit: 00248 memset(buf, 0, sizeof(buf)); 00249 #ifdef NETSNMP_USE_OPENSSL 00250 free(ctx); 00251 #endif 00252 return rval; 00253 00254 } /* end generate_Ku() */ 00255 #elif NETSNMP_USE_PKCS11 00256 { 00257 int rval = SNMPERR_SUCCESS; 00258 00259 /* 00260 * Sanity check. 00261 */ 00262 if (!hashtype || !P || !Ku || !kulen || (*kulen <= 0) 00263 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) { 00264 QUITFUN(SNMPERR_GENERR, generate_Ku_quit); 00265 } 00266 00267 if (pplen < USM_LENGTH_P_MIN) { 00268 snmp_log(LOG_ERR, "Error: passphrase chosen is below the length " 00269 "requirements of the USM (min=%d).\n",USM_LENGTH_P_MIN); 00270 snmp_set_detail("The supplied password length is too short."); 00271 QUITFUN(SNMPERR_GENERR, generate_Ku_quit); 00272 } 00273 00274 /* 00275 * Setup for the transform type. 00276 */ 00277 00278 #ifndef NETSNMP_DISABLE_MD5 00279 if (ISTRANSFORM(hashtype, HMACMD5Auth)) 00280 return pkcs_generate_Ku(CKM_MD5, P, pplen, Ku, kulen); 00281 else 00282 #endif 00283 if (ISTRANSFORM(hashtype, HMACSHA1Auth)) 00284 return pkcs_generate_Ku(CKM_SHA_1, P, pplen, Ku, kulen); 00285 else { 00286 return (SNMPERR_GENERR); 00287 } 00288 00289 generate_Ku_quit: 00290 00291 return rval; 00292 } /* end generate_Ku() */ 00293 #else 00294 _KEYTOOLS_NOT_AVAILABLE 00295 #endif /* internal or openssl */ 00296 /*******************************************************************-o-****** 00297 * generate_kul 00298 * 00299 * Parameters: 00300 * *hashtype 00301 * hashtype_len 00302 * *engineID 00303 * engineID_len 00304 * *Ku Master key for a given user. 00305 * ku_len Length of Ku in bytes. 00306 * *Kul Localized key for a given user at engineID. 00307 * *kul_len Length of Kul buffer (IN); Length of Kul key (OUT). 00308 * 00309 * Returns: 00310 * SNMPERR_SUCCESS Success. 00311 * SNMPERR_GENERR All errors. 00312 * 00313 * 00314 * Ku MUST be the proper length (currently fixed) for the given hashtype. 00315 * 00316 * Upon successful return, Kul contains the localized form of Ku at 00317 * engineID, and the length of the key is stored in kul_len. 00318 * 00319 * The localized key method is defined in RFC2274, Sections 2.6 and A.2, and 00320 * originally documented in: 00321 * U. Blumenthal, N. C. Hien, B. Wijnen, 00322 * "Key Derivation for Network Management Applications", 00323 * IEEE Network Magazine, April/May issue, 1997. 00324 * 00325 * 00326 * ASSUMES SNMP_MAXBUF >= sizeof(Ku + engineID + Ku). 00327 * 00328 * NOTE Localized keys for privacy transforms are generated via 00329 * the authentication transform held by the same usmUser. 00330 * 00331 * XXX An engineID of any length is accepted, even if larger than 00332 * what is spec'ed for the textual convention. 00333 */ 00334 int 00335 generate_kul(const oid * hashtype, u_int hashtype_len, 00336 const u_char * engineID, size_t engineID_len, 00337 const u_char * Ku, size_t ku_len, 00338 u_char * Kul, size_t * kul_len) 00339 #if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO) 00340 { 00341 int rval = SNMPERR_SUCCESS; 00342 u_int nbytes = 0; 00343 size_t properlength; 00344 int iproperlength; 00345 00346 u_char buf[SNMP_MAXBUF]; 00347 #ifdef NETSNMP_ENABLE_TESTING_CODE 00348 int i; 00349 #endif 00350 00351 00352 /* 00353 * Sanity check. 00354 */ 00355 if (!hashtype || !engineID || !Ku || !Kul || !kul_len 00356 || (engineID_len <= 0) || (ku_len <= 0) || (*kul_len <= 0) 00357 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) { 00358 QUITFUN(SNMPERR_GENERR, generate_kul_quit); 00359 } 00360 00361 00362 iproperlength = sc_get_properlength(hashtype, hashtype_len); 00363 if (iproperlength == SNMPERR_GENERR) 00364 QUITFUN(SNMPERR_GENERR, generate_kul_quit); 00365 00366 properlength = (size_t) iproperlength; 00367 00368 if ((*kul_len < properlength) || (ku_len < properlength)) { 00369 QUITFUN(SNMPERR_GENERR, generate_kul_quit); 00370 } 00371 00372 /* 00373 * Concatenate Ku and engineID properly, then hash the result. 00374 * Store it in Kul. 00375 */ 00376 nbytes = 0; 00377 memcpy(buf, Ku, properlength); 00378 nbytes += properlength; 00379 memcpy(buf + nbytes, engineID, engineID_len); 00380 nbytes += engineID_len; 00381 memcpy(buf + nbytes, Ku, properlength); 00382 nbytes += properlength; 00383 00384 rval = sc_hash(hashtype, hashtype_len, buf, nbytes, Kul, kul_len); 00385 00386 #ifdef NETSNMP_ENABLE_TESTING_CODE 00387 DEBUGMSGTL(("generate_kul", "generating Kul (from Ku): ")); 00388 for (i = 0; i < *kul_len; i++) 00389 DEBUGMSG(("generate_kul", "%02x", Kul[i])); 00390 DEBUGMSG(("generate_kul", "keytools\n")); 00391 #endif /* NETSNMP_ENABLE_TESTING_CODE */ 00392 00393 QUITFUN(rval, generate_kul_quit); 00394 00395 00396 generate_kul_quit: 00397 return rval; 00398 00399 } /* end generate_kul() */ 00400 00401 #else 00402 _KEYTOOLS_NOT_AVAILABLE 00403 #endif /* internal or openssl */ 00404 /*******************************************************************-o-****** 00405 * encode_keychange 00406 * 00407 * Parameters: 00408 * *hashtype MIB OID for the hash transform type. 00409 * hashtype_len Length of the MIB OID hash transform type. 00410 * *oldkey Old key that is used to encodes the new key. 00411 * oldkey_len Length of oldkey in bytes. 00412 * *newkey New key that is encoded using the old key. 00413 * newkey_len Length of new key in bytes. 00414 * *kcstring Buffer to contain the KeyChange TC string. 00415 * *kcstring_len Length of kcstring buffer. 00416 * 00417 * Returns: 00418 * SNMPERR_SUCCESS Success. 00419 * SNMPERR_GENERR All errors. 00420 * 00421 * 00422 * Uses oldkey and acquired random bytes to encode newkey into kcstring 00423 * according to the rules of the KeyChange TC described in RFC 2274, Section 5. 00424 * 00425 * Upon successful return, *kcstring_len contains the length of the 00426 * encoded string. 00427 * 00428 * ASSUMES Old and new key are always equal to each other, although 00429 * this may be less than the transform type hash output 00430 * output length (eg, using KeyChange for a DESPriv key when 00431 * the user also uses SHA1Auth). This also implies that the 00432 * hash placed in the second 1/2 of the key change string 00433 * will be truncated before the XOR'ing when the hash output is 00434 * larger than that 1/2 of the key change string. 00435 * 00436 * *kcstring_len will be returned as exactly twice that same 00437 * length though the input buffer may be larger. 00438 * 00439 * XXX FIX: Does not handle varibable length keys. 00440 * XXX FIX: Does not handle keys larger than the hash algorithm used. 00441 */ 00442 int 00443 encode_keychange(const oid * hashtype, u_int hashtype_len, 00444 u_char * oldkey, size_t oldkey_len, 00445 u_char * newkey, size_t newkey_len, 00446 u_char * kcstring, size_t * kcstring_len) 00447 #if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO) 00448 { 00449 int rval = SNMPERR_SUCCESS; 00450 int iproperlength; 00451 size_t properlength; 00452 size_t nbytes = 0; 00453 00454 u_char *tmpbuf = NULL; 00455 00456 00457 /* 00458 * Sanity check. 00459 */ 00460 if (!kcstring || !kcstring_len) 00461 return SNMPERR_GENERR; 00462 00463 if (!hashtype || !oldkey || !newkey || !kcstring || !kcstring_len 00464 || (oldkey_len <= 0) || (newkey_len <= 0) || (*kcstring_len <= 0) 00465 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) { 00466 QUITFUN(SNMPERR_GENERR, encode_keychange_quit); 00467 } 00468 00469 /* 00470 * Setup for the transform type. 00471 */ 00472 iproperlength = sc_get_properlength(hashtype, hashtype_len); 00473 if (iproperlength == SNMPERR_GENERR) 00474 QUITFUN(SNMPERR_GENERR, encode_keychange_quit); 00475 00476 if ((oldkey_len != newkey_len) || (*kcstring_len < (2 * oldkey_len))) { 00477 QUITFUN(SNMPERR_GENERR, encode_keychange_quit); 00478 } 00479 00480 properlength = SNMP_MIN(oldkey_len, (size_t)iproperlength); 00481 00482 /* 00483 * Use the old key and some random bytes to encode the new key 00484 * in the KeyChange TC format: 00485 * . Get random bytes (store in first half of kcstring), 00486 * . Hash (oldkey | random_bytes) (into second half of kcstring), 00487 * . XOR hash and newkey (into second half of kcstring). 00488 * 00489 * Getting the wrong number of random bytes is considered an error. 00490 */ 00491 nbytes = properlength; 00492 00493 #if defined(NETSNMP_ENABLE_TESTING_CODE) && defined(RANDOMZEROS) 00494 memset(kcstring, 0, nbytes); 00495 DEBUGMSG(("encode_keychange", 00496 "** Using all zero bits for \"random\" delta of )" 00497 "the keychange string! **\n")); 00498 #else /* !NETSNMP_ENABLE_TESTING_CODE */ 00499 rval = sc_random(kcstring, &nbytes); 00500 QUITFUN(rval, encode_keychange_quit); 00501 if (nbytes != properlength) { 00502 QUITFUN(SNMPERR_GENERR, encode_keychange_quit); 00503 } 00504 #endif /* !NETSNMP_ENABLE_TESTING_CODE */ 00505 00506 tmpbuf = (u_char *) malloc(properlength * 2); 00507 if (tmpbuf) { 00508 memcpy(tmpbuf, oldkey, properlength); 00509 memcpy(tmpbuf + properlength, kcstring, properlength); 00510 00511 *kcstring_len -= properlength; 00512 rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength * 2, 00513 kcstring + properlength, kcstring_len); 00514 00515 QUITFUN(rval, encode_keychange_quit); 00516 00517 *kcstring_len = (properlength * 2); 00518 00519 kcstring += properlength; 00520 nbytes = 0; 00521 while ((nbytes++) < properlength) { 00522 *kcstring++ ^= *newkey++; 00523 } 00524 } 00525 00526 encode_keychange_quit: 00527 if (rval != SNMPERR_SUCCESS) 00528 memset(kcstring, 0, *kcstring_len); 00529 SNMP_FREE(tmpbuf); 00530 00531 return rval; 00532 00533 } /* end encode_keychange() */ 00534 00535 #else 00536 _KEYTOOLS_NOT_AVAILABLE 00537 #endif /* internal or openssl */ 00538 /*******************************************************************-o-****** 00539 * decode_keychange 00540 * 00541 * Parameters: 00542 * *hashtype MIB OID of the hash transform to use. 00543 * hashtype_len Length of the hash transform MIB OID. 00544 * *oldkey Old key that is used to encode the new key. 00545 * oldkey_len Length of oldkey in bytes. 00546 * *kcstring Encoded KeyString buffer containing the new key. 00547 * kcstring_len Length of kcstring in bytes. 00548 * *newkey Buffer to hold the extracted new key. 00549 * *newkey_len Length of newkey in bytes. 00550 * 00551 * Returns: 00552 * SNMPERR_SUCCESS Success. 00553 * SNMPERR_GENERR All errors. 00554 * 00555 * 00556 * Decodes a string of bits encoded according to the KeyChange TC described 00557 * in RFC 2274, Section 5. The new key is extracted from *kcstring with 00558 * the aid of the old key. 00559 * 00560 * Upon successful return, *newkey_len contains the length of the new key. 00561 * 00562 * 00563 * ASSUMES Old key is exactly 1/2 the length of the KeyChange buffer, 00564 * although this length may be less than the hash transform 00565 * output. Thus the new key length will be equal to the old 00566 * key length. 00567 */ 00568 /* 00569 * XXX: if the newkey is not long enough, it should be freed and remalloced 00570 */ 00571 int 00572 decode_keychange(const oid * hashtype, u_int hashtype_len, 00573 u_char * oldkey, size_t oldkey_len, 00574 u_char * kcstring, size_t kcstring_len, 00575 u_char * newkey, size_t * newkey_len) 00576 #if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO) 00577 { 00578 int rval = SNMPERR_SUCCESS; 00579 size_t properlength = 0; 00580 int iproperlength = 0; 00581 u_int nbytes = 0; 00582 00583 u_char *bufp, tmp_buf[SNMP_MAXBUF]; 00584 size_t tmp_buf_len = SNMP_MAXBUF; 00585 u_char *tmpbuf = NULL; 00586 00587 00588 00589 /* 00590 * Sanity check. 00591 */ 00592 if (!hashtype || !oldkey || !kcstring || !newkey || !newkey_len 00593 || (oldkey_len <= 0) || (kcstring_len <= 0) || (*newkey_len <= 0) 00594 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) { 00595 QUITFUN(SNMPERR_GENERR, decode_keychange_quit); 00596 } 00597 00598 00599 /* 00600 * Setup for the transform type. 00601 */ 00602 iproperlength = sc_get_properlength(hashtype, hashtype_len); 00603 if (iproperlength == SNMPERR_GENERR) 00604 QUITFUN(SNMPERR_GENERR, decode_keychange_quit); 00605 00606 properlength = (size_t) iproperlength; 00607 00608 if (((oldkey_len * 2) != kcstring_len) || (*newkey_len < oldkey_len)) { 00609 QUITFUN(SNMPERR_GENERR, decode_keychange_quit); 00610 } 00611 00612 properlength = oldkey_len; 00613 *newkey_len = properlength; 00614 00615 /* 00616 * Use the old key and the given KeyChange TC string to recover 00617 * the new key: 00618 * . Hash (oldkey | random_bytes) (into newkey), 00619 * . XOR hash and encoded (second) half of kcstring (into newkey). 00620 */ 00621 tmpbuf = (u_char *) malloc(properlength * 2); 00622 if (tmpbuf) { 00623 memcpy(tmpbuf, oldkey, properlength); 00624 memcpy(tmpbuf + properlength, kcstring, properlength); 00625 00626 rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength * 2, 00627 tmp_buf, &tmp_buf_len); 00628 QUITFUN(rval, decode_keychange_quit); 00629 00630 memcpy(newkey, tmp_buf, properlength); 00631 bufp = kcstring + properlength; 00632 nbytes = 0; 00633 while ((nbytes++) < properlength) { 00634 *newkey++ ^= *bufp++; 00635 } 00636 } 00637 00638 decode_keychange_quit: 00639 if (rval != SNMPERR_SUCCESS) { 00640 memset(newkey, 0, properlength); 00641 } 00642 memset(tmp_buf, 0, SNMP_MAXBUF); 00643 SNMP_FREE(tmpbuf); 00644 00645 return rval; 00646 00647 } /* end decode_keychange() */ 00648 00649 #else 00650 _KEYTOOLS_NOT_AVAILABLE 00651 #endif /* internal or openssl */ 00652 #endif /* NETSNMP_FEATURE_REMOVE_USM_KEYTOOLS */