1 #ifdef BRCM_SNMP_MIB_SUPPORT
6 #include <net-snmp/net-snmp-config.h>
13 #ifdef HAVE_NETINET_IN_H
14 #include <netinet/in.h>
29 #include <net-snmp/types.h>
30 #include <net-snmp/output_api.h>
31 #include <net-snmp/utilities.h>
33 #include <net-snmp/library/snmp_api.h>
35 # include <openssl/hmac.h>
37 #ifdef USE_INTERNAL_MD5
38 #include <net-snmp/library/md5.h>
42 #include <net-snmp/library/scapi.h>
43 #include <net-snmp/library/keytools.h>
45 #include <net-snmp/library/transform_oids.h>
47 /*******************************************************************-o-******
51 * *hashtype MIB OID for the transform type for hashing.
52 * hashtype_len Length of OID value.
53 * *P Pre-allocated bytes of passpharase.
54 * pplen Length of passphrase.
55 * *Ku Buffer to contain Ku.
56 * *kulen Length of Ku buffer.
59 * SNMPERR_SUCCESS Success.
60 * SNMPERR_GENERR All errors.
63 * Convert a passphrase into a master user key, Ku, according to the
64 * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM)
67 * Expand the passphrase to fill the passphrase buffer space, if necessary,
68 * concatenation as many duplicates as possible of P to itself. If P is
69 * larger than the buffer space, truncate it to fit.
71 * Then hash the result with the given hashtype transform. Return
74 * If successful, kulen contains the size of the hash written to Ku.
76 * NOTE Passphrases less than USM_LENGTH_P_MIN characters in length
77 * cause an error to be returned.
78 * (Punt this check to the cmdline apps? XXX)
81 generate_Ku(const oid * hashtype, u_int hashtype_len,
82 u_char * P, size_t pplen, u_char * Ku, size_t * kulen)
83 #if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL)
85 int rval = SNMPERR_SUCCESS,
86 nbytes = USM_LENGTH_EXPANDED_PASSPHRASE;
90 u_char buf[USM_LENGTH_KU_HASHBLOCK], *bufp;
93 EVP_MD_CTX *ctx = malloc(sizeof(EVP_MD_CTX));
100 if (!hashtype || !P || !Ku || !kulen || (*kulen <= 0)
101 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
102 QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
105 if (pplen < USM_LENGTH_P_MIN) {
106 snmp_log(LOG_ERR, "Error: passphrase chosen is below the length "
107 "requirements of the USM (min=%d).\n",USM_LENGTH_P_MIN);
108 snmp_set_detail("The supplied password length is too short.");
109 QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
114 * Setup for the transform type.
118 if (ISTRANSFORM(hashtype, HMACMD5Auth))
119 EVP_DigestInit(ctx, EVP_md5());
120 else if (ISTRANSFORM(hashtype, HMACSHA1Auth))
121 EVP_DigestInit(ctx, EVP_sha1());
124 return (SNMPERR_GENERR);
128 #endif /* USE_OPENSSL */
132 for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) {
133 *bufp++ = P[pindex++ % pplen];
136 EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK);
138 if (MDupdate(&MD, buf, USM_LENGTH_KU_HASHBLOCK * 8)) {
139 rval = SNMPERR_USM_ENCRYPTIONERROR;
142 #endif /* USE_OPENSSL */
144 nbytes -= USM_LENGTH_KU_HASHBLOCK;
148 EVP_DigestFinal(ctx, (unsigned char *) Ku, (unsigned int *) kulen);
153 if (MDupdate(&MD, buf, 0)) {
154 rval = SNMPERR_USM_ENCRYPTIONERROR;
157 *kulen = sc_get_properlength(hashtype, hashtype_len);
158 MDget(&MD, Ku, *kulen);
160 memset(&MD, 0, sizeof(MD));
161 #endif /* USE_OPENSSL */
164 #ifdef SNMP_TESTING_CODE
165 DEBUGMSGTL(("generate_Ku", "generating Ku (from %s): ", P));
166 for (i = 0; i < *kulen; i++)
167 DEBUGMSG(("generate_Ku", "%02x", Ku[i]));
168 DEBUGMSG(("generate_Ku", "\n"));
169 #endif /* SNMP_TESTING_CODE */
173 memset(buf, 0, sizeof(buf));
179 } /* end generate_Ku() */
182 _KEYTOOLS_NOT_AVAILABLE
183 #endif /* internal or openssl */
184 /*******************************************************************-o-******
192 * *Ku Master key for a given user.
193 * ku_len Length of Ku in bytes.
194 * *Kul Localized key for a given user at engineID.
195 * *kul_len Length of Kul buffer (IN); Length of Kul key (OUT).
198 * SNMPERR_SUCCESS Success.
199 * SNMPERR_GENERR All errors.
202 * Ku MUST be the proper length (currently fixed) for the given hashtype.
204 * Upon successful return, Kul contains the localized form of Ku at
205 * engineID, and the length of the key is stored in kul_len.
207 * The localized key method is defined in RFC2274, Sections 2.6 and A.2, and
208 * originally documented in:
209 * U. Blumenthal, N. C. Hien, B. Wijnen,
210 * "Key Derivation for Network Management Applications",
211 * IEEE Network Magazine, April/May issue, 1997.
214 * ASSUMES SNMP_MAXBUF >= sizeof(Ku + engineID + Ku).
216 * NOTE Localized keys for privacy transforms are generated via
217 * the authentication transform held by the same usmUser.
219 * XXX An engineID of any length is accepted, even if larger than
220 * what is spec'ed for the textual convention.
223 generate_kul(const oid * hashtype, u_int hashtype_len,
224 u_char * engineID, size_t engineID_len,
225 u_char * Ku, size_t ku_len,
226 u_char * Kul, size_t * kul_len)
227 #if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5)
229 int rval = SNMPERR_SUCCESS;
233 u_char buf[SNMP_MAXBUF];
234 #ifdef SNMP_TESTING_CODE
242 if (!hashtype || !engineID || !Ku || !Kul || !kul_len
243 || (engineID_len <= 0) || (ku_len <= 0) || (*kul_len <= 0)
244 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
245 QUITFUN(SNMPERR_GENERR, generate_kul_quit);
249 properlength = sc_get_properlength(hashtype, hashtype_len);
250 if (properlength == SNMPERR_GENERR)
251 QUITFUN(SNMPERR_GENERR, generate_kul_quit);
254 if (((int) *kul_len < properlength) || ((int) ku_len < properlength)) {
255 QUITFUN(SNMPERR_GENERR, generate_kul_quit);
259 * Concatenate Ku and engineID properly, then hash the result.
263 memcpy(buf, Ku, properlength);
264 nbytes += properlength;
265 memcpy(buf + nbytes, engineID, engineID_len);
266 nbytes += engineID_len;
267 memcpy(buf + nbytes, Ku, properlength);
268 nbytes += properlength;
270 rval = sc_hash(hashtype, hashtype_len, buf, nbytes, Kul, kul_len);
272 #ifdef SNMP_TESTING_CODE
273 DEBUGMSGTL(("generate_kul", "generating Kul (from Ku): "));
274 for (i = 0; i < *kul_len; i++)
275 DEBUGMSG(("generate_kul", "%02x", Kul[i]));
276 DEBUGMSG(("generate_kul", "keytools\n"));
277 #endif /* SNMP_TESTING_CODE */
279 QUITFUN(rval, generate_kul_quit);
285 } /* end generate_kul() */
288 _KEYTOOLS_NOT_AVAILABLE
289 #endif /* internal or openssl */
290 /*******************************************************************-o-******
294 * *hashtype MIB OID for the hash transform type.
295 * hashtype_len Length of the MIB OID hash transform type.
296 * *oldkey Old key that is used to encodes the new key.
297 * oldkey_len Length of oldkey in bytes.
298 * *newkey New key that is encoded using the old key.
299 * newkey_len Length of new key in bytes.
300 * *kcstring Buffer to contain the KeyChange TC string.
301 * *kcstring_len Length of kcstring buffer.
304 * SNMPERR_SUCCESS Success.
305 * SNMPERR_GENERR All errors.
308 * Uses oldkey and acquired random bytes to encode newkey into kcstring
309 * according to the rules of the KeyChange TC described in RFC 2274, Section 5.
311 * Upon successful return, *kcstring_len contains the length of the
314 * ASSUMES Old and new key are always equal to each other, although
315 * this may be less than the transform type hash output
316 * output length (eg, using KeyChange for a DESPriv key when
317 * the user also uses SHA1Auth). This also implies that the
318 * hash placed in the second 1/2 of the key change string
319 * will be truncated before the XOR'ing when the hash output is
320 * larger than that 1/2 of the key change string.
322 * *kcstring_len will be returned as exactly twice that same
323 * length though the input buffer may be larger.
325 * XXX FIX: Does not handle varibable length keys.
326 * XXX FIX: Does not handle keys larger than the hash algorithm used.
329 encode_keychange(const oid * hashtype, u_int hashtype_len,
330 u_char * oldkey, size_t oldkey_len,
331 u_char * newkey, size_t newkey_len,
332 u_char * kcstring, size_t * kcstring_len)
333 #if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5)
335 int rval = SNMPERR_SUCCESS;
339 u_char *tmpbuf = NULL;
345 if (!hashtype || !oldkey || !newkey || !kcstring || !kcstring_len
346 || (oldkey_len <= 0) || (newkey_len <= 0) || (*kcstring_len <= 0)
347 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
348 QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
352 * Setup for the transform type.
354 properlength = sc_get_properlength(hashtype, hashtype_len);
355 if (properlength == SNMPERR_GENERR)
356 QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
358 if ((oldkey_len != newkey_len) || (*kcstring_len < (2 * oldkey_len))) {
359 QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
362 properlength = SNMP_MIN((int) oldkey_len, properlength);
365 * Use the old key and some random bytes to encode the new key
366 * in the KeyChange TC format:
367 * . Get random bytes (store in first half of kcstring),
368 * . Hash (oldkey | random_bytes) (into second half of kcstring),
369 * . XOR hash and newkey (into second half of kcstring).
371 * Getting the wrong number of random bytes is considered an error.
373 nbytes = properlength;
375 #if defined(SNMP_TESTING_CODE) && defined(RANDOMZEROS)
376 memset(kcstring, 0, nbytes);
377 DEBUGMSG(("encode_keychange",
378 "** Using all zero bits for \"random\" delta of )"
379 "the keychange string! **\n"));
380 #else /* !SNMP_TESTING_CODE */
381 rval = sc_random(kcstring, &nbytes);
382 QUITFUN(rval, encode_keychange_quit);
383 if ((int) nbytes != properlength) {
384 QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
386 #endif /* !SNMP_TESTING_CODE */
388 tmpbuf = (u_char *) malloc(properlength * 2);
390 memcpy(tmpbuf, oldkey, properlength);
391 memcpy(tmpbuf + properlength, kcstring, properlength);
393 *kcstring_len -= properlength;
394 rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength * 2,
395 kcstring + properlength, kcstring_len);
397 QUITFUN(rval, encode_keychange_quit);
399 *kcstring_len = (properlength * 2);
401 kcstring += properlength;
403 while ((int) (nbytes++) < properlength) {
404 *kcstring++ ^= *newkey++;
408 encode_keychange_quit:
409 if (rval != SNMPERR_SUCCESS)
410 memset(kcstring, 0, *kcstring_len);
415 } /* end encode_keychange() */
418 _KEYTOOLS_NOT_AVAILABLE
419 #endif /* internal or openssl */
420 /*******************************************************************-o-******
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.
434 * SNMPERR_SUCCESS Success.
435 * SNMPERR_GENERR All errors.
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.
442 * Upon successful return, *newkey_len contains the length of the new key.
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
451 * XXX: if the newkey is not long enough, it should be freed and remalloced
454 decode_keychange(const oid * hashtype, u_int hashtype_len,
455 u_char * oldkey, size_t oldkey_len,
456 u_char * kcstring, size_t kcstring_len,
457 u_char * newkey, size_t * newkey_len)
458 #if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5)
460 int rval = SNMPERR_SUCCESS;
461 size_t properlength = 0;
464 u_char *bufp, tmp_buf[SNMP_MAXBUF];
465 size_t tmp_buf_len = SNMP_MAXBUF;
466 u_char *tmpbuf = NULL;
473 if (!hashtype || !oldkey || !kcstring || !newkey || !newkey_len
474 || (oldkey_len <= 0) || (kcstring_len <= 0) || (*newkey_len <= 0)
475 || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) {
476 QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
481 * Setup for the transform type.
483 properlength = sc_get_properlength(hashtype, hashtype_len);
484 if (properlength == SNMPERR_GENERR)
485 QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
488 if (((oldkey_len * 2) != kcstring_len) || (*newkey_len < oldkey_len)) {
489 QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
492 properlength = oldkey_len;
493 *newkey_len = properlength;
496 * Use the old key and the given KeyChange TC string to recover
498 * . Hash (oldkey | random_bytes) (into newkey),
499 * . XOR hash and encoded (second) half of kcstring (into newkey).
501 tmpbuf = (u_char *) malloc(properlength * 2);
503 memcpy(tmpbuf, oldkey, properlength);
504 memcpy(tmpbuf + properlength, kcstring, properlength);
506 rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength * 2,
507 tmp_buf, &tmp_buf_len);
508 QUITFUN(rval, decode_keychange_quit);
510 memcpy(newkey, tmp_buf, properlength);
511 bufp = kcstring + properlength;
513 while ((int) (nbytes++) < properlength) {
514 *newkey++ ^= *bufp++;
518 decode_keychange_quit:
519 if (rval != SNMPERR_SUCCESS) {
520 memset(newkey, 0, properlength);
522 memset(tmp_buf, 0, SNMP_MAXBUF);
528 } /* end decode_keychange() */
531 _KEYTOOLS_NOT_AVAILABLE
532 #endif /* internal or openssl */
534 #endif /* BRCM_SNMP_MIB_SUPPORT (snmpv3) */