Coverage Report

Created: 2026-10-17 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/keytools.c
Line
Count
Source
1
/* Portions of this file are subject to the following copyright(s).  See
2
 * the Net-SNMP's COPYING file for more details and other copyrights
3
 * that may apply:
4
 */
5
/*
6
 * Portions of this file are copyrighted by:
7
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
8
 * Use is subject to license terms specified in the COPYING file
9
 * distributed with the Net-SNMP package.
10
 *
11
 * Portions of this file are copyrighted by:
12
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
13
 * Use is subject to license terms specified in the COPYING file
14
 * distributed with the Net-SNMP package.
15
 */
16
17
/*
18
 * keytools.c
19
 */
20
21
#include <net-snmp/net-snmp-config.h>
22
#include <net-snmp/net-snmp-features.h>
23
24
#include <stdio.h>
25
#include <sys/types.h>
26
#ifdef HAVE_NETINET_IN_H
27
#include <netinet/in.h>
28
#endif
29
#ifdef HAVE_STDLIB_H
30
#include <stdlib.h>
31
#endif
32
#ifdef HAVE_STRING_H
33
#include <string.h>
34
#else
35
#include <strings.h>
36
#endif
37
38
#ifdef HAVE_UNISTD_H
39
#include <unistd.h>
40
#endif
41
42
#include <math.h>
43
44
#include <net-snmp/types.h>
45
#include <net-snmp/output_api.h>
46
#include <net-snmp/utilities.h>
47
48
#include <net-snmp/library/snmp_api.h>
49
#ifdef NETSNMP_USE_OPENSSL
50
# include <openssl/hmac.h>
51
#else
52
#ifdef NETSNMP_USE_INTERNAL_MD5
53
#include <net-snmp/library/md5.h>
54
#endif
55
#endif
56
#ifdef NETSNMP_USE_INTERNAL_CRYPTO
57
#include <net-snmp/library/openssl_md5.h>
58
#include <net-snmp/library/openssl_sha.h>
59
#endif
60
61
#ifdef NETSNMP_USE_PKCS11
62
#include <security/cryptoki.h>
63
#endif
64
65
#include <net-snmp/library/scapi.h>
66
#include <net-snmp/library/keytools.h>
67
68
#include <net-snmp/library/transform_oids.h>
69
70
#include <net-snmp/library/snmp_secmod.h>
71
#include <net-snmp/library/snmpusm.h>
72
73
netsnmp_feature_child_of(usm_support, libnetsnmp);
74
netsnmp_feature_child_of(usm_keytools, usm_support);
75
76
#ifndef NETSNMP_FEATURE_REMOVE_USM_KEYTOOLS
77
78
/*******************************************************************-o-******
79
 * generate_Ku
80
 *
81
 * Parameters:
82
 *  *hashtype MIB OID for the transform type for hashing.
83
 *   hashtype_len Length of OID value.
84
 *  *P    Pre-allocated bytes of passphrase.
85
 *   pplen    Length of passphrase.
86
 *  *Ku   Buffer to contain Ku.
87
 *  *kulen    Length of Ku buffer.
88
 *      
89
 * Returns:
90
 *  SNMPERR_SUCCESS     Success.
91
 *  SNMPERR_GENERR      All errors.
92
 *
93
 *
94
 * Convert a passphrase into a master user key, Ku, according to the
95
 * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM)
96
 * as follows:
97
 *
98
 * Expand the passphrase to fill the passphrase buffer space, if necessary,
99
 * concatenation as many duplicates as possible of P to itself.  If P is
100
 * larger than the buffer space, truncate it to fit.
101
 *
102
 * Then hash the result with the given hashtype transform.  Return
103
 * the result as Ku.
104
 *
105
 * If successful, kulen contains the size of the hash written to Ku.
106
 *
107
 * NOTE  Passphrases less than USM_LENGTH_P_MIN characters in length
108
 *   cause an error to be returned.
109
 *   (Punt this check to the cmdline apps?  XXX)
110
 */
111
int
112
generate_Ku(const oid * hashtype, u_int hashtype_len,
113
            const u_char * P, size_t pplen, u_char * Ku, size_t * kulen)
114
#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
115
0
{
116
0
    int             rval = SNMPERR_SUCCESS,
117
0
        nbytes = USM_LENGTH_EXPANDED_PASSPHRASE, auth_type;
118
#if !defined(NETSNMP_USE_OPENSSL) && \
119
    defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
120
    int             ret;
121
#endif
122
123
0
    u_int           i, pindex = 0;
124
125
0
    u_char          buf[USM_LENGTH_KU_HASHBLOCK], *bufp;
126
127
0
#ifdef NETSNMP_USE_OPENSSL
128
0
    EVP_MD_CTX     *ctx = NULL;
129
0
    const EVP_MD   *hashfn = NULL;
130
#elif defined(NETSNMP_USE_INTERNAL_CRYPTO)
131
    SHA_CTX csha1;
132
    MD5_CTX cmd5;
133
    char    cryptotype = 0;
134
#define TYPE_MD5  1
135
#define TYPE_SHA1 2
136
#else
137
    MDstruct        MD;
138
#endif
139
    /*
140
     * Sanity check.
141
     */
142
0
    if (!hashtype || !P || !Ku || !kulen || (*kulen <= 0)) {
143
0
        QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
144
0
    }
145
146
0
    if (pplen < USM_LENGTH_P_MIN) {
147
0
        snmp_log(LOG_ERR, "Error: passphrase chosen is below the length "
148
0
                 "requirements of the USM (min=%d).\n",USM_LENGTH_P_MIN);
149
0
        snmp_set_detail("The supplied password length is too short.");
150
0
        QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
151
0
    }
152
153
0
    auth_type = sc_get_authtype(hashtype, hashtype_len);
154
0
    if (SNMPERR_GENERR == auth_type) {
155
0
        snmp_log(LOG_ERR, "Error: unknown authtype");
156
0
        snmp_set_detail("unknown authtype");
157
0
        QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
158
0
    }
159
160
    /*
161
     * Setup for the transform type.
162
     */
163
0
#ifdef NETSNMP_USE_OPENSSL
164
165
0
    if (*kulen < EVP_MAX_MD_SIZE) {
166
0
        snmp_log(LOG_ERR, "Internal Error: ku buffer too small (min=%d).\n",
167
0
                 EVP_MAX_MD_SIZE);
168
0
        snmp_set_detail("Internal Error: ku buffer too small.");
169
0
        QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
170
0
    }
171
172
    /** get hash function */
173
0
    hashfn = sc_get_openssl_hashfn(auth_type);
174
0
    if (NULL == hashfn) {
175
0
        snmp_log(LOG_ERR, "Error: no hashfn for authtype");
176
0
        snmp_set_detail("no hashfn for authtype");
177
0
        QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
178
0
    }
179
180
0
#if defined(HAVE_EVP_MD_CTX_NEW)
181
0
    ctx = EVP_MD_CTX_new();
182
#elif defined(HAVE_EVP_MD_CTX_CREATE)
183
    ctx = EVP_MD_CTX_create();
184
#elif defined(HAVE_VOID_EVP_MD_CTX_INIT)
185
    ctx = malloc(sizeof(*ctx));
186
    if (ctx)
187
        EVP_MD_CTX_init(ctx);
188
#else
189
    ctx = malloc(sizeof(*ctx));
190
    if (!ctx || !EVP_MD_CTX_init(ctx)) {
191
        rval = SNMPERR_GENERR;
192
        goto generate_Ku_quit;
193
    }
194
#endif
195
0
    if (!ctx || !EVP_DigestInit(ctx, hashfn)) {
196
0
        rval = SNMPERR_GENERR;
197
0
        goto generate_Ku_quit;
198
0
    }
199
200
#elif defined(NETSNMP_USE_INTERNAL_CRYPTO)
201
#ifndef NETSNMP_DISABLE_MD5
202
    if (NETSNMP_USMAUTH_HMACMD5 == auth_type) {
203
        if (!MD5_Init(&cmd5))
204
            return SNMPERR_GENERR;
205
        cryptotype = TYPE_MD5;
206
    } else
207
#endif
208
           if (NETSNMP_USMAUTH_HMACSHA1 == auth_type) {
209
        if (!SHA1_Init(&csha1))
210
            return SNMPERR_GENERR;
211
        cryptotype = TYPE_SHA1;
212
    } else {
213
        return (SNMPERR_GENERR);
214
    }
215
#else
216
    MDbegin(&MD);
217
#endif                          /* NETSNMP_USE_OPENSSL */
218
219
0
    while (nbytes > 0) {
220
0
        bufp = buf;
221
0
        for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) {
222
0
            *bufp++ = P[pindex++ % pplen];
223
0
        }
224
0
#ifdef NETSNMP_USE_OPENSSL
225
0
        if (!EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK)) {
226
0
            rval = SNMPERR_USM_ENCRYPTIONERROR;
227
0
            goto generate_Ku_quit;
228
0
        }
229
#elif defined(NETSNMP_USE_INTERNAL_CRYPTO)
230
        if (TYPE_SHA1 == cryptotype) {
231
            rval = !SHA1_Update(&csha1, buf, USM_LENGTH_KU_HASHBLOCK);
232
        } else {
233
            rval = !MD5_Update(&cmd5, buf, USM_LENGTH_KU_HASHBLOCK);
234
        }
235
        if (rval != 0) {
236
            return SNMPERR_USM_ENCRYPTIONERROR;
237
        }
238
#elif defined(NETSNMP_USE_INTERNAL_MD5)
239
        if (MDupdate(&MD, buf, USM_LENGTH_KU_HASHBLOCK * 8)) {
240
            rval = SNMPERR_USM_ENCRYPTIONERROR;
241
            goto md5_fin;
242
        }
243
#endif                          /* NETSNMP_USE_OPENSSL */
244
0
        nbytes -= USM_LENGTH_KU_HASHBLOCK;
245
0
    }
246
247
0
#ifdef NETSNMP_USE_OPENSSL
248
0
    {
249
0
    unsigned int    tmp_len;
250
251
0
    tmp_len = *kulen;
252
0
    if (!EVP_DigestFinal(ctx, (unsigned char *) Ku, &tmp_len)) {
253
0
        rval = SNMPERR_USM_ENCRYPTIONERROR;
254
0
        goto generate_Ku_quit;
255
0
    }
256
0
    *kulen = tmp_len;
257
    /*
258
     * what about free() 
259
     */
260
0
    }
261
#elif defined(NETSNMP_USE_INTERNAL_CRYPTO)
262
    if (TYPE_SHA1 == cryptotype) {
263
        SHA1_Final(Ku, &csha1);
264
    } else {
265
        MD5_Final(Ku, &cmd5);
266
    }
267
    ret = sc_get_properlength(hashtype, hashtype_len);
268
    if (ret == SNMPERR_GENERR)
269
        return SNMPERR_GENERR;
270
    *kulen = ret;
271
#elif defined(NETSNMP_USE_INTERNAL_MD5)
272
    if (MDupdate(&MD, buf, 0)) {
273
        rval = SNMPERR_USM_ENCRYPTIONERROR;
274
        goto md5_fin;
275
    }
276
    ret = sc_get_properlength(hashtype, hashtype_len);
277
    if (ret == SNMPERR_GENERR)
278
        return SNMPERR_GENERR;
279
    *kulen = ret;
280
    MDget(&MD, Ku, *kulen);
281
  md5_fin:
282
    memset(&MD, 0, sizeof(MD));
283
#endif                          /* NETSNMP_USE_INTERNAL_MD5 */
284
285
286
#ifdef NETSNMP_ENABLE_TESTING_CODE
287
    DEBUGMSGTL(("generate_Ku", "generating Ku (%s from %s): ",
288
                usm_lookup_auth_str(auth_type), P));
289
    for (i = 0; i < *kulen; i++)
290
        DEBUGMSG(("generate_Ku", "%02x", Ku[i]));
291
    DEBUGMSG(("generate_Ku", "\n"));
292
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
293
294
295
0
  generate_Ku_quit:
296
0
    memset(buf, 0, sizeof(buf));
297
0
#ifdef NETSNMP_USE_OPENSSL
298
0
    if (ctx) {
299
0
#if defined(HAVE_EVP_MD_CTX_FREE)
300
0
        EVP_MD_CTX_free(ctx);
301
#elif defined(HAVE_EVP_MD_CTX_DESTROY)
302
        EVP_MD_CTX_destroy(ctx);
303
#else
304
        EVP_MD_CTX_cleanup(ctx);
305
        free(ctx);
306
#endif
307
0
    }
308
0
#endif
309
0
    return rval;
310
311
0
}                               /* end generate_Ku() */
312
#elif defined(NETSNMP_USE_PKCS11)
313
{
314
    int             rval = SNMPERR_SUCCESS, auth_type;;
315
316
    /*
317
     * Sanity check.
318
     */
319
    if (!hashtype || !P || !Ku || !kulen || (*kulen <= 0)) {
320
        QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
321
    }
322
323
    if (pplen < USM_LENGTH_P_MIN) {
324
        snmp_log(LOG_ERR, "Error: passphrase chosen is below the length "
325
                 "requirements of the USM (min=%d).\n",USM_LENGTH_P_MIN);
326
        snmp_set_detail("The supplied password length is too short.");
327
        QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
328
    }
329
330
    auth_type = sc_get_authtype(hashtype, hashtype_len);
331
    if (SNMPERR_GENERR == auth_type) {
332
        snmp_log(LOG_ERR, "Error: unknown authtype");
333
        snmp_set_detail("unknown authtype");
334
        QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
335
    }
336
337
338
    /*
339
     * Setup for the transform type.
340
     */
341
342
#ifndef NETSNMP_DISABLE_MD5
343
    if (NETSNMP_USMAUTH_HMACMD5 == auth_type)
344
        return pkcs_generate_Ku(CKM_MD5, P, pplen, Ku, kulen);
345
    else
346
#endif
347
        if (NETSNMP_USMAUTH_HMACSHA1 == auth_type)
348
        return pkcs_generate_Ku(CKM_SHA_1, P, pplen, Ku, kulen);
349
    else {
350
        return (SNMPERR_GENERR);
351
    }
352
353
  generate_Ku_quit:
354
355
    return rval;
356
}                               /* end generate_Ku() */
357
#else
358
_KEYTOOLS_NOT_AVAILABLE
359
#endif                          /* internal or openssl */
360
/*******************************************************************-o-******
361
 * generate_kul
362
 *
363
 * Parameters:
364
 *  *hashtype
365
 *   hashtype_len
366
 *  *engineID
367
 *   engineID_len
368
 *  *Ku   Master key for a given user.
369
 *   ku_len   Length of Ku in bytes.
370
 *  *Kul    Localized key for a given user at engineID.
371
 *  *kul_len  Length of Kul buffer (IN); Length of Kul key (OUT).
372
 *      
373
 * Returns:
374
 *  SNMPERR_SUCCESS     Success.
375
 *  SNMPERR_GENERR      All errors.
376
 *
377
 *
378
 * Ku MUST be the proper length (currently fixed) for the given hashtype.
379
 *
380
 * Upon successful return, Kul contains the localized form of Ku at
381
 * engineID, and the length of the key is stored in kul_len.
382
 *
383
 * The localized key method is defined in RFC2274, Sections 2.6 and A.2, and
384
 * originally documented in:
385
 *    U. Blumenthal, N. C. Hien, B. Wijnen,
386
 *      "Key Derivation for Network Management Applications",
387
 *  IEEE Network Magazine, April/May issue, 1997.
388
 *
389
 *
390
 * ASSUMES  SNMP_MAXBUF >= sizeof(Ku + engineID + Ku).
391
 *
392
 * NOTE  Localized keys for privacy transforms are generated via
393
 *   the authentication transform held by the same usmUser.
394
 *
395
 * XXX  An engineID of any length is accepted, even if larger than
396
 *  what is spec'ed for the textual convention.
397
 */
398
int
399
generate_kul(const oid * hashtype, u_int hashtype_len,
400
             const u_char * engineID, size_t engineID_len,
401
             const u_char * Ku, size_t ku_len,
402
             u_char * Kul, size_t * kul_len)
403
#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
404
0
{
405
0
    int             rval = SNMPERR_SUCCESS, auth_type;
406
0
    u_int           nbytes = 0;
407
0
    size_t          properlength;
408
0
    int             iproperlength;
409
410
0
    u_char          buf[SNMP_MAXBUF];
411
#ifdef NETSNMP_ENABLE_TESTING_CODE
412
    int             i;
413
#endif
414
415
416
    /*
417
     * Sanity check.
418
     */
419
0
    if (!hashtype || !engineID || !Ku || !Kul || !kul_len
420
0
        || (engineID_len <= 0) || (ku_len <= 0) || (*kul_len <= 0)) {
421
0
        QUITFUN(SNMPERR_GENERR, generate_kul_quit);
422
0
    }
423
424
0
    auth_type = sc_get_authtype(hashtype, hashtype_len);
425
0
    if (SNMPERR_GENERR == auth_type)
426
0
        QUITFUN(SNMPERR_GENERR, generate_kul_quit);
427
428
0
    iproperlength = sc_get_proper_auth_length_bytype(auth_type);
429
0
    if (iproperlength == SNMPERR_GENERR)
430
0
        QUITFUN(SNMPERR_GENERR, generate_kul_quit);
431
432
0
    properlength = (size_t) iproperlength;
433
434
0
    if ((*kul_len < properlength) || (ku_len < properlength) ||
435
0
        (engineID_len > sizeof(buf)) ||
436
0
        (2 * properlength > sizeof(buf) - engineID_len)) {
437
0
        QUITFUN(SNMPERR_GENERR, generate_kul_quit);
438
0
    }
439
440
    /*
441
     * Concatenate Ku and engineID properly, then hash the result.
442
     * Store it in Kul.
443
     */
444
0
    nbytes = 0;
445
0
    memcpy(buf, Ku, properlength);
446
0
    nbytes += properlength;
447
0
    memcpy(buf + nbytes, engineID, engineID_len);
448
0
    nbytes += engineID_len;
449
0
    memcpy(buf + nbytes, Ku, properlength);
450
0
    nbytes += properlength;
451
452
0
    rval = sc_hash(hashtype, hashtype_len, buf, nbytes, Kul, kul_len);
453
454
#ifdef NETSNMP_ENABLE_TESTING_CODE
455
    DEBUGMSGTL(("generate_kul", "generating Kul (%s from Ku): ",
456
                usm_lookup_auth_str(auth_type) ));
457
    for (i = 0; i < *kul_len; i++)
458
        DEBUGMSG(("generate_kul", "%02x", Kul[i]));
459
    DEBUGMSG(("generate_kul", "keytools\n"));
460
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
461
462
0
    QUITFUN(rval, generate_kul_quit);
463
464
465
0
  generate_kul_quit:
466
0
    return rval;
467
468
0
}                               /* end generate_kul() */
469
470
#else
471
_KEYTOOLS_NOT_AVAILABLE
472
#endif                          /* internal or openssl */
473
474
/*******************************************************************-o-******
475
 * _kul_extend_blumenthal
476
 *
477
 * Parameters:
478
 *     *hashoid        MIB OID for the hash transform type.
479
 *      hashoid_len    Length of the MIB OID hash transform type.
480
 *     *origKul        original kul (localized; IN/OUT)
481
 *     *origKulLen     Length of original kul in bytes (IN/OUT)
482
 *      origKulSize    Size of original kul buffer
483
 *      needKeyLen     Size needed for key
484
 *
485
 * Returns:
486
 *      SNMPERR_SUCCESS      Success.
487
 *      SNMPERR_GENERR       All errors.
488
 */
489
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
490
static int
491
_kul_extend_blumenthal(int needKeyLen, oid *hashoid, u_int hashoid_len,
492
                       u_char *origKul, size_t *origKulLen, int origKulSize)
493
0
{
494
0
    u_char newKul[USM_LENGTH_KU_HASHBLOCK];
495
0
    size_t newKulLen;
496
0
    int count, hashBits, hashBytes, authtype, i, saveLen;
497
498
0
    DEBUGMSGTL(("usm:extend_kul", " blumenthal called\n"));
499
500
0
    if (NULL == hashoid || NULL == origKul || NULL == origKulLen ||
501
0
        needKeyLen > origKulSize) {
502
0
        DEBUGMSGTL(("usm:extend_kul", "bad parameters\n"));
503
0
        return SNMPERR_GENERR;
504
0
   }
505
506
0
    authtype = sc_get_authtype(hashoid, hashoid_len);
507
0
    if (authtype < 0 ) {
508
0
        DEBUGMSGTL(("usm:extend_kul", "unknown authtype\n"));
509
0
        return SNMPERR_GENERR;
510
0
    }
511
512
0
    saveLen = *origKulLen;
513
0
    needKeyLen -= *origKulLen; /* subtract bytes we already have */
514
515
    /*
516
     * 3.1.2.1:
517
     *   1)Let Hnnn() the hash function of the authentication protocol for
518
     *      the user U on the SNMP authoritative engine E. nnn being the size
519
     *      of the output of the hash function (e.g. nnn=128 bits for MD5, or
520
     *      nnn=160 bits for SHA1).
521
     */
522
0
    hashBytes = sc_get_proper_auth_length_bytype(authtype);
523
0
    hashBits = 8 * hashBytes;
524
525
    /* 3.1.2.1:
526
     *   2)Set c = ceil ( 256 / nnn )
527
     */
528
0
    count = ceil( (double)256 / (double)hashBits );
529
0
    DEBUGMSGTL(("9:usm:extend_kul:blumenthal", "count ceiling %d\n", count));
530
531
    /* 3.1.2.1:
532
     *   3)For i = 1, 2, ..., c
533
     *        a.Set Kul = Kul || Hnnn(Kul);     Where Hnnn() is the hash
534
     *          function of the authentication protocol defined for that user
535
     */
536
0
    for(i = 0; i < count; ++i) {
537
0
        int copyLen, rc;
538
539
0
        newKulLen = sizeof(newKul);
540
0
        rc = sc_hash_type( authtype, origKul, *origKulLen, newKul, &newKulLen);
541
0
        if (SNMPERR_SUCCESS != rc) {
542
0
            DEBUGMSGTL(("usm:extend_kul", "error from sc_hash_type\n"));
543
0
            return SNMPERR_GENERR;
544
0
        }
545
546
0
        copyLen = SNMP_MIN(needKeyLen, newKulLen);
547
0
        memcpy(origKul + *origKulLen, newKul, copyLen);
548
0
        needKeyLen -= copyLen;
549
0
        *origKulLen += copyLen;
550
551
        /** not part of the draft, but stop if we already have enough bits */
552
0
        if (needKeyLen <= 0)
553
0
            break;
554
0
    }
555
556
0
    DEBUGMSGTL(("usm:extend_kul:blumenthal",
557
0
                "orig len %d, new len %" NETSNMP_PRIz "d\n",
558
0
                saveLen, *origKulLen));
559
560
0
    return SNMPERR_SUCCESS;
561
0
}
562
#endif /* NETSNMP_DRAFT_BLUMENTHAL_AES_04 */
563
564
/*******************************************************************-o-******
565
 * _kul_extend_reeder
566
 *
567
 * Parameters:
568
 *     *hashoid        MIB OID for the hash transform type.
569
 *      hashoid_len    Length of the MIB OID hash transform type.
570
 *     *engineID       engineID
571
 *      engineIDLen    Length of engineID
572
 *     *origKul        original kul (localized; IN/OUT)
573
 *     *origKulLen     Length of original kul in bytes (IN/OUT)
574
 *      origKulSize    Size of original kul buffer
575
 *
576
 * Returns:
577
 *      SNMPERR_SUCCESS      Success.
578
 *      SNMPERR_GENERR       All errors.
579
 */
580
#if defined(NETSNMP_DRAFT_REEDER_3DES) || defined(NETSNMP_DRAFT_BLUMENTHAL_AES_04)
581
static int
582
_kul_extend_reeder(int needKeyLen, oid *hashoid, u_int hashoid_len,
583
                   u_char *engineID, int engineIDLen,
584
                   u_char *origKul, size_t *origKulLen, int origKulSize)
585
0
{
586
0
    u_char newKu[USM_LENGTH_KU_HASHBLOCK], newKul[USM_LENGTH_KU_HASHBLOCK];
587
0
    size_t newKuLen, newKulLen, saveLen;
588
0
    int authType, copylen;
589
590
0
    DEBUGMSGTL(("usm:extend_kul", " reeder called\n"));
591
592
0
    if (NULL == hashoid || NULL == engineID || NULL == origKul ||
593
0
        NULL == origKulLen || needKeyLen > origKulSize)
594
0
        return SNMPERR_GENERR;
595
596
0
    authType = sc_get_authtype(hashoid, hashoid_len);
597
0
    if (SNMPERR_GENERR == authType)
598
0
        return SNMPERR_GENERR;
599
0
    newKulLen = sc_get_proper_auth_length_bytype(authType);
600
0
    saveLen = *origKulLen;
601
0
    needKeyLen -= *origKulLen; /* subtract bytes we already have */
602
0
    while (needKeyLen > 0) {
603
604
0
        newKuLen = sizeof(newKu);
605
        /*
606
         * hash the existing key using the passphrase to Ku algorithm.
607
         * [ Ku' = Ku(kul) ]
608
         */
609
0
        if (generate_Ku(hashoid, hashoid_len, origKul, *origKulLen,
610
0
                        newKu, &newKuLen) != SNMPERR_SUCCESS)
611
0
            return SNMPERR_GENERR;
612
613
        /*
614
         * localize the new key generated from current localized key
615
         * and append it to the current localized key.
616
         * [ kul' = kul || kul(Ku') ]
617
         */
618
0
        newKulLen = sizeof(newKul);
619
0
        if(generate_kul(hashoid, hashoid_len, engineID, engineIDLen,
620
0
                        newKu, newKuLen, newKul,
621
0
                        &newKulLen) != SNMPERR_SUCCESS)
622
0
            return SNMPERR_GENERR;
623
624
0
        copylen = SNMP_MIN(needKeyLen, newKulLen);
625
0
        memcpy(origKul + *origKulLen, newKul, copylen);
626
0
        needKeyLen -= copylen;
627
0
        *origKulLen += copylen;
628
0
    }
629
630
0
    DEBUGMSGTL(("usm:extend_kul:reeder",
631
0
                "orig len %" NETSNMP_PRIz "d, new len %" NETSNMP_PRIz "d\n",
632
0
                saveLen, *origKulLen));
633
0
    return SNMPERR_SUCCESS;
634
0
}
635
#endif /* NETSNMP_DRAFT_REEDER_3DES || NETSNMP_DRAFT_BLUMENTHAL_AES_04 */
636
637
/*******************************************************************-o-******
638
 * netsnmp_extend_key
639
 *
640
 * Extend a kul buffer to the needed key size. if the passed kulBuf
641
 * is not large enough, a new one will be allocated and the old one
642
 * will be freed.
643
 *
644
 * Parameters:
645
 *       neededKeyLen   The neede key length
646
 *      *hashoid        MIB OID for the hash transform type.
647
 *       hashoid_len    Length of the MIB OID hash transform type.
648
 *       privType       Privacy algorithm type
649
 *       engineID       engineID
650
 *       engineIDLen    Length of engineID
651
 *     **kulBuf         Pointer to a buffer pointer
652
 *      *kulBufLen      Length of current kul buffer
653
 *       kulBufSize     Allocated size of current kul buffer
654
 *
655
 * OUT:
656
 *     **kulBuf         New kulBuf pointer (if it needed to be expanded)
657
 *      *kulBufLen      Length of new kul buffer
658
 *
659
 * Returns:
660
 *     SNMPERR_SUCCESS  Success.
661
 *     SNMPERR_GENERR   All errors.
662
 */
663
int
664
netsnmp_extend_kul(u_int needKeyLen, oid *hashoid, u_int hashoid_len,
665
                   int privType, u_char *engineID, u_int engineIDLen,
666
                   u_char **kulBuf, size_t *kulBufLen, u_int kulBufSize)
667
0
{
668
0
    int ret;
669
0
    u_char *newKul;
670
0
    size_t newKulLen;
671
672
0
    DEBUGMSGTL(("9:usm:extend_kul", " called\n"));
673
674
0
    if (*kulBufLen >= needKeyLen) {
675
0
        DEBUGMSGTL(("usm:extend_kul", " key already big enough\n"));
676
0
        return SNMPERR_SUCCESS; /* already have enough key material */
677
0
    }
678
679
0
    switch (privType & (USM_PRIV_MASK_ALG | USM_PRIV_MASK_VARIANT)) {
680
0
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
681
0
        case USM_CREATE_USER_PRIV_AES192:
682
0
        case USM_CREATE_USER_PRIV_AES256:
683
0
            break;
684
0
#endif
685
0
#if defined(NETSNMP_DRAFT_REEDER_3DES) || defined(NETSNMP_DRAFT_BLUMENTHAL_AES_04)
686
0
        case USM_CREATE_USER_PRIV_3DES:
687
0
            break;
688
0
#endif
689
0
         default:
690
0
            DEBUGMSGTL(("usm:extend_kul",
691
0
                        "no extension method defined for priv type 0x%x\n",
692
0
                        privType));
693
0
            return SNMPERR_SUCCESS;
694
0
    }
695
696
0
    DEBUGMSGTL(("usm:extend_kul", " have %" NETSNMP_PRIz "d bytes; need %d\n",
697
0
                *kulBufLen, needKeyLen));
698
699
0
    if (kulBufSize < needKeyLen) {
700
0
        newKul = calloc(1, needKeyLen);
701
0
        if (NULL == newKul)
702
0
            return SNMPERR_GENERR;
703
0
        memcpy(newKul, *kulBuf, *kulBufLen);
704
0
        newKulLen = *kulBufLen;
705
0
        kulBufSize = needKeyLen;
706
0
    }
707
0
    else {
708
0
        newKul = *kulBuf;
709
0
        newKulLen = *kulBufLen;
710
0
    }
711
712
#ifdef NETSNMP_ENABLE_TESTING_CODE
713
    DEBUGIF("9:usm:extend_kul") {
714
        int             i;
715
        DEBUGMSG(("9:usm:extend_kul",
716
                  "key: key=0x"));
717
        for (i = 0; i < newKulLen; i++)
718
            DEBUGMSG(("9:usm:extend_kul", "%02x", newKul[i] & 0xff));
719
        DEBUGMSG(("9:usm:extend_kul", " (%ld)\n", newKulLen));
720
    }
721
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
722
0
    ret = SNMPERR_SUCCESS; /* most privTypes don't need extended kul */
723
0
    switch (privType & (USM_PRIV_MASK_ALG | USM_PRIV_MASK_VARIANT)) {
724
0
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
725
0
        case USM_CREATE_USER_PRIV_AES192:
726
0
        case USM_CREATE_USER_PRIV_AES256:
727
0
        {
728
0
            int reeder = privType & USM_AES_REEDER_FLAG;
729
0
            if (reeder)
730
0
                ret = _kul_extend_reeder(needKeyLen, hashoid, hashoid_len,
731
0
                                         engineID, engineIDLen,
732
0
                                         newKul, &newKulLen, kulBufSize);
733
0
            else
734
0
                ret = _kul_extend_blumenthal(needKeyLen, hashoid, hashoid_len,
735
0
                                             newKul, &newKulLen, kulBufSize);
736
0
        }
737
0
        break;
738
0
#endif
739
#if defined(NETSNMP_DRAFT_REEDER_3DES)
740
        case USM_CREATE_USER_PRIV_3DES:
741
            ret = _kul_extend_reeder(needKeyLen, hashoid, hashoid_len,
742
                                     engineID, engineIDLen,
743
                                     newKul, &newKulLen, kulBufSize);
744
            break;
745
#endif
746
0
        default:
747
0
            DEBUGMSGTL(("usm:extend_kul",
748
0
                        "unknown priv type 0x%x\n", privType));
749
0
            ret = SNMPERR_GENERR;
750
0
    }
751
752
0
    if (SNMPERR_SUCCESS == ret) {
753
0
        *kulBufLen = newKulLen;
754
0
        if (newKul != *kulBuf) {
755
0
            free(*kulBuf);
756
0
            *kulBuf = newKul;
757
0
        }
758
0
    }
759
0
    else {
760
0
        if (newKul != *kulBuf)
761
0
            free(newKul);
762
0
    }
763
#ifdef NETSNMP_ENABLE_TESTING_CODE
764
    DEBUGIF("9:usm:extend_kul") {
765
        int             i;
766
        DEBUGMSG(("usm:extend_kul",
767
                  "key: key=0x"));
768
        for (i = 0; i < newKulLen; i++)
769
            DEBUGMSG(("usm:extend_kul", "%02x", newKul[i] & 0xff));
770
        DEBUGMSG(("usm:extend_kul", " (%ld)\n", newKulLen));
771
    }
772
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
773
774
0
    return ret;
775
0
}
776
777
/*******************************************************************-o-******
778
 * encode_keychange
779
 *
780
 * Parameters:
781
 *  *hashtype MIB OID for the hash transform type.
782
 *   hashtype_len Length of the MIB OID hash transform type.
783
 *  *oldkey   Old key that is used to encodes the new key.
784
 *   oldkey_len Length of oldkey in bytes.
785
 *  *newkey   New key that is encoded using the old key.
786
 *   newkey_len Length of new key in bytes.
787
 *  *kcstring Buffer to contain the KeyChange TC string.
788
 *  *kcstring_len Length of kcstring buffer.
789
 *      
790
 * Returns:
791
 *  SNMPERR_SUCCESS     Success.
792
 *  SNMPERR_GENERR      All errors.
793
 *
794
 *
795
 * Uses oldkey and acquired random bytes to encode newkey into kcstring
796
 * according to the rules of the KeyChange TC described in RFC 2274, Section 5.
797
 *
798
 * Upon successful return, *kcstring_len contains the length of the
799
 * encoded string.
800
 *
801
 * ASSUMES  Old and new key are always equal to each other, although
802
 *    this may be less than the transform type hash output
803
 *    output length (eg, using KeyChange for a DESPriv key when
804
 *    the user also uses SHA1Auth).  This also implies that the
805
 *    hash placed in the second 1/2 of the key change string
806
 *    will be truncated before the XOR'ing when the hash output is 
807
 *    larger than that 1/2 of the key change string.
808
 *
809
 *    *kcstring_len will be returned as exactly twice that same
810
 *    length though the input buffer may be larger.
811
 *
812
 * XXX FIX:     Does not handle variable length keys.
813
 * XXX FIX:     Does not handle keys larger than the hash algorithm used.
814
 *
815
KeyChange ::=     TEXTUAL-CONVENTION
816
   STATUS         current
817
   DESCRIPTION
818
         "Every definition of an object with this syntax must identify
819
          a protocol P, a secret key K, and a hash algorithm H
820
          that produces output of L octets.
821
822
          The object's value is a manager-generated, partially-random
823
          value which, when modified, causes the value of the secret
824
          key K, to be modified via a one-way function.
825
826
          The value of an instance of this object is the concatenation
827
          of two components: first a 'random' component and then a
828
          'delta' component.
829
830
          The lengths of the random and delta components
831
          are given by the corresponding value of the protocol P;
832
          if P requires K to be a fixed length, the length of both the
833
          random and delta components is that fixed length; if P
834
          allows the length of K to be variable up to a particular
835
          maximum length, the length of the random component is that
836
          maximum length and the length of the delta component is any
837
          length less than or equal to that maximum length.
838
          For example, usmHMACMD5AuthProtocol requires K to be a fixed
839
          length of 16 octets and L - of 16 octets.
840
          usmHMACSHAAuthProtocol requires K to be a fixed length of
841
          20 octets and L - of 20 octets. Other protocols may define
842
          other sizes, as deemed appropriate.
843
844
          When a requester wants to change the old key K to a new
845
          key keyNew on a remote entity, the 'random' component is
846
          obtained from either a true random generator, or from a
847
          pseudorandom generator, and the 'delta' component is
848
          computed as follows:
849
850
           - a temporary variable is initialized to the existing value
851
             of K;
852
           - if the length of the keyNew is greater than L octets,
853
             then:
854
              - the random component is appended to the value of the
855
                temporary variable, and the result is input to the
856
                the hash algorithm H to produce a digest value, and
857
                the temporary variable is set to this digest value;
858
              - the value of the temporary variable is XOR-ed with
859
                the first (next) L-octets (16 octets in case of MD5)
860
                of the keyNew to produce the first (next) L-octets
861
                (16 octets in case of MD5) of the 'delta' component.
862
              - the above two steps are repeated until the unused
863
                portion of the keyNew component is L octets or less,
864
           - the random component is appended to the value of the
865
             temporary variable, and the result is input to the
866
             hash algorithm H to produce a digest value;
867
           - this digest value, truncated if necessary to be the same
868
             length as the unused portion of the keyNew, is XOR-ed
869
             with the unused portion of the keyNew to produce the
870
             (final portion of the) 'delta' component.
871
872
           For example, using MD5 as the hash algorithm H:
873
874
              iterations = (lenOfDelta - 1)/16; -- integer division
875
              temp = keyOld;
876
              for (i = 0; i < iterations; i++) {
877
                  temp = MD5 (temp || random);
878
                  delta[i*16 .. (i*16)+15] =
879
                         temp XOR keyNew[i*16 .. (i*16)+15];
880
              }
881
              temp = MD5 (temp || random);
882
              delta[i*16 .. lenOfDelta-1] =
883
                     temp XOR keyNew[i*16 .. lenOfDelta-1];
884
885
          The 'random' and 'delta' components are then concatenated as
886
          described above, and the resulting octet string is sent to
887
          the recipient as the new value of an instance of this object.
888
889
          At the receiver side, when an instance of this object is set
890
          to a new value, then a new value of K is computed as follows:
891
892
           - a temporary variable is initialized to the existing value
893
             of K;
894
           - if the length of the delta component is greater than L
895
             octets, then:
896
              - the random component is appended to the value of the
897
                temporary variable, and the result is input to the
898
                hash algorithm H to produce a digest value, and the
899
                temporary variable is set to this digest value;
900
              - the value of the temporary variable is XOR-ed with
901
                the first (next) L-octets (16 octets in case of MD5)
902
                of the delta component to produce the first (next)
903
                L-octets (16 octets in case of MD5) of the new value
904
                of K.
905
              - the above two steps are repeated until the unused
906
                portion of the delta component is L octets or less,
907
           - the random component is appended to the value of the
908
             temporary variable, and the result is input to the
909
             hash algorithm H to produce a digest value;
910
           - this digest value, truncated if necessary to be the same
911
             length as the unused portion of the delta component, is
912
             XOR-ed with the unused portion of the delta component to
913
             produce the (final portion of the) new value of K.
914
915
           For example, using MD5 as the hash algorithm H:
916
917
              iterations = (lenOfDelta - 1)/16; -- integer division
918
              temp = keyOld;
919
              for (i = 0; i < iterations; i++) {
920
                  temp = MD5 (temp || random);
921
                  keyNew[i*16 .. (i*16)+15] =
922
                         temp XOR delta[i*16 .. (i*16)+15];
923
              }
924
              temp = MD5 (temp || random);
925
              keyNew[i*16 .. lenOfDelta-1] =
926
                     temp XOR delta[i*16 .. lenOfDelta-1];
927
928
          The value of an object with this syntax, whenever it is
929
          retrieved by the management protocol, is always the zero
930
          length string.
931
932
          Note that the keyOld and keyNew are the localized keys.
933
934
          Note that it is probably wise that when an SNMP entity sends
935
          a SetRequest to change a key, that it keeps a copy of the old
936
          key until it has confirmed that the key change actually
937
          succeeded.
938
         "
939
    SYNTAX       OCTET STRING
940
 *
941
 */
942
int
943
encode_keychange(const oid * hashtype, u_int hashtype_len,
944
                 u_char * oldkey, size_t oldkey_len,
945
                 u_char * newkey, size_t newkey_len,
946
                 u_char * kcstring, size_t * kcstring_len)
947
#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
948
0
{
949
0
    u_char          tmpbuf[SNMP_MAXBUF_SMALL], digest[SNMP_MAXBUF_SMALL];
950
0
    u_char          delta[SNMP_MAXBUF_SMALL];
951
0
    u_char         *tmpp = tmpbuf, *randp;
952
0
    int             rval = SNMPERR_SUCCESS, auth_type;
953
0
    int             iauth_length, tmp_len;
954
0
    size_t          auth_length, rand_len, digest_len, delta_len = 0;
955
956
    /*
957
     * Sanity check.
958
     */
959
0
    if (!hashtype || !oldkey || !newkey || !kcstring
960
0
        || (oldkey_len != newkey_len ) || (newkey_len == 0)
961
0
        || (*kcstring_len < (2 * newkey_len))) {
962
0
        QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
963
0
    }
964
965
    /*
966
     * Setup for the transform type.
967
     */
968
0
    auth_type = sc_get_authtype(hashtype, hashtype_len);
969
0
    iauth_length = sc_get_proper_auth_length_bytype(auth_type);
970
0
    if (iauth_length <= 0)
971
0
        QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
972
973
0
    if (oldkey_len > sizeof(tmpbuf) / 2 ||
974
0
        oldkey_len > sizeof(tmpbuf) - (size_t)iauth_length ||
975
0
        newkey_len > sizeof(delta)) {
976
0
        QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
977
0
    }
978
979
0
    auth_length = SNMP_MIN(oldkey_len, (size_t)iauth_length);
980
981
0
    DEBUGMSGTL(("encode_keychange",
982
0
                "oldkey_len %" NETSNMP_PRIz "d, newkey_len %" NETSNMP_PRIz "d, auth_length %" NETSNMP_PRIz "d\n",
983
0
                oldkey_len, newkey_len, auth_length));
984
985
    /*
986
     * Use the old key and some random bytes to encode the new key
987
     * in the KeyChange TC format:
988
     *      . Get random bytes (store in first half of kcstring),
989
     *      . Hash (oldkey | random_bytes) (into second half of kcstring),
990
     *      . XOR hash and newkey (into second half of kcstring).
991
     *
992
     * Getting the wrong number of random bytes is considered an error.
993
     */
994
0
    randp = kcstring;
995
0
    rand_len = oldkey_len;
996
997
0
    memset(randp, 0x0, rand_len);
998
    /*
999
     * KeyChange ::=     TEXTUAL-CONVENTION
1000
     *    STATUS         current
1001
     *    DESCRIPTION
1002
     *    [...]
1003
     *    When a requester wants to change the old key K to a new
1004
     *    key keyNew on a remote entity, the 'random' component is
1005
     *    obtained from either a true random generator, or from a
1006
     *    pseudorandom generator, ...
1007
     */
1008
#if defined(NETSNMP_ENABLE_TESTING_CODE) && defined(RANDOMZEROS)
1009
    memset(randp, 0, rand_len);
1010
    DEBUGMSG(("encode_keychange",
1011
              "** Using all zero bits for \"random\" delta of )"
1012
              "the keychange string! **\n"));
1013
#else                           /* !NETSNMP_ENABLE_TESTING_CODE */
1014
0
    rval = sc_random(randp, &rand_len);
1015
0
    QUITFUN(rval, encode_keychange_quit);
1016
0
    if (rand_len != oldkey_len) {
1017
0
        QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
1018
0
    }
1019
0
#endif                          /* !NETSNMP_ENABLE_TESTING_CODE */
1020
#ifdef NETSNMP_ENABLE_TESTING_CODE
1021
    DEBUGIF("encode_keychange") {
1022
        int             i;
1023
        DEBUGMSG(("encode_keychange",
1024
                  "rand: key=0x"));
1025
        for (i = 0; i < rand_len; i++)
1026
            DEBUGMSG(("encode_keychange", "%02x", randp[i] & 0xff));
1027
        DEBUGMSG(("encode_keychange", " (%ld)\n", rand_len));
1028
    }
1029
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
1030
1031
    /*
1032
     *                        ... and the 'delta' component is
1033
     *    computed as follows:
1034
     *
1035
     *     - a temporary variable is initialized to the existing value
1036
     *       of K;
1037
     */
1038
0
    memcpy(tmpbuf, oldkey, oldkey_len);
1039
0
    tmp_len = oldkey_len;
1040
0
    tmpp  = tmpbuf + tmp_len;
1041
1042
0
    delta_len = 0;
1043
0
    while (delta_len < newkey_len) {
1044
0
        DEBUGMSGTL(("encode_keychange", "%" NETSNMP_PRIz "d < %" NETSNMP_PRIz "d\n", delta_len,
1045
0
                    newkey_len));
1046
1047
        /*
1048
         *  - the random component is appended to the value of the
1049
         *    temporary variable,
1050
         */
1051
0
        memcpy(tmpp, randp, rand_len);
1052
0
        tmp_len += rand_len;
1053
1054
        /*
1055
         *                        and the result is input to the
1056
         *    the hash algorithm H to produce a digest value, and
1057
         *    the temporary variable is set to this digest value;
1058
         */
1059
0
        digest_len = sizeof(digest);
1060
0
        rval = sc_hash(hashtype, hashtype_len, tmpbuf, tmp_len,
1061
0
                       digest, &digest_len);
1062
0
        QUITFUN(rval, encode_keychange_quit);
1063
0
        DEBUGMSGTL(("encode_keychange", "digest_len %" NETSNMP_PRIz "d\n", digest_len));
1064
1065
0
        memcpy(tmpbuf, digest, digest_len);
1066
0
        tmp_len = digest_len;
1067
0
        tmpp = tmpbuf;
1068
        /*
1069
         *  - the value of the temporary variable is XOR-ed with
1070
         *    the first (next) L-octets (16 octets in case of MD5)
1071
         *    of the keyNew to produce the first (next) L-octets
1072
         *    (16 octets in case of MD5) of the 'delta' component.
1073
         *  - the above two steps are repeated until the unused
1074
         *    portion of the keyNew component is L octets or less,
1075
         */
1076
0
        while ((delta_len < newkey_len) && (digest_len-- > 0)) {
1077
0
            delta[delta_len] = *tmpp ^ newkey[delta_len];
1078
0
            DEBUGMSGTL(("encode_keychange",
1079
0
                        "d[%" NETSNMP_PRIz "d] 0x%0x = 0x%0x ^ 0x%0x\n",
1080
0
                        delta_len, delta[delta_len], *tmpp, newkey[delta_len]));
1081
0
            ++tmpp;
1082
0
            ++delta_len;
1083
0
        }
1084
0
        DEBUGMSGTL(("encode_keychange", "delta_len %" NETSNMP_PRIz "d\n", delta_len));
1085
0
    }
1086
1087
    /** copy results */
1088
0
    memcpy(kcstring + rand_len, delta, delta_len);
1089
0
    *kcstring_len = rand_len + delta_len;
1090
1091
#ifdef NETSNMP_ENABLE_TESTING_CODE
1092
    DEBUGIF("encode_keychange") {
1093
        int             i;
1094
        DEBUGMSG(("encode_keychange",
1095
                  "oldkey: key=0x"));
1096
        for (i = 0; i < oldkey_len; i++)
1097
            DEBUGMSG(("encode_keychange", "%02x", oldkey[i] & 0xff));
1098
        DEBUGMSG(("encode_keychange", " (%ld)\n", oldkey_len));
1099
1100
        DEBUGMSG(("encode_keychange",
1101
                  "newkey: key=0x"));
1102
        for (i = 0; i < newkey_len; i++)
1103
            DEBUGMSG(("encode_keychange", "%02x", newkey[i] & 0xff));
1104
        DEBUGMSG(("encode_keychange", " (%ld)\n", newkey_len));
1105
1106
        DEBUGMSG(("encode_keychange",
1107
                  "kcstring: key=0x"));
1108
        for (i = 0; i < *kcstring_len; i++)
1109
            DEBUGMSG(("encode_keychange", "%02x", kcstring[i] & 0xff));
1110
        DEBUGMSG(("encode_keychange", " (%ld)\n", *kcstring_len));
1111
    }
1112
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
1113
0
  encode_keychange_quit:
1114
0
    if (kcstring && rval != SNMPERR_SUCCESS)
1115
0
        memset(kcstring, 0, *kcstring_len);
1116
0
    memset(tmpbuf, 0, sizeof(tmpbuf));
1117
0
    memset(digest, 0, sizeof(digest));
1118
0
    memset(delta, 0, sizeof(delta));
1119
1120
0
    return rval;
1121
1122
0
}                               /* end encode_keychange() */
1123
1124
#else
1125
_KEYTOOLS_NOT_AVAILABLE
1126
#endif                          /* internal or openssl */
1127
/*******************************************************************-o-******
1128
 * decode_keychange
1129
 *
1130
 * Parameters:
1131
 *  *hashtype MIB OID of the hash transform to use.
1132
 *   hashtype_len Length of the hash transform MIB OID.
1133
 *  *oldkey   Old key that is used to encode the new key.
1134
 *   oldkey_len Length of oldkey in bytes.
1135
 *  *kcstring Encoded KeyString buffer containing the new key.
1136
 *   kcstring_len Length of kcstring in bytes.
1137
 *  *newkey   Buffer to hold the extracted new key.
1138
 *  *newkey_len Length of newkey in bytes.
1139
 *      
1140
 * Returns:
1141
 *  SNMPERR_SUCCESS     Success.
1142
 *  SNMPERR_GENERR      All errors.
1143
 *
1144
 *
1145
 * Decodes a string of bits encoded according to the KeyChange TC described
1146
 * in RFC 2274, Section 5.  The new key is extracted from *kcstring with
1147
 * the aid of the old key.
1148
 *
1149
 * Upon successful return, *newkey_len contains the length of the new key.
1150
 *
1151
 *
1152
 * ASSUMES  Old key is exactly 1/2 the length of the KeyChange buffer,
1153
 *    although this length may not be equal to the hash transform
1154
 *    output.  Thus the new key length will be equal to the old
1155
 *    key length.
1156
 *
1157
KeyChange ::=     TEXTUAL-CONVENTION
1158
   STATUS         current
1159
   DESCRIPTION
1160
         "Every definition of an object with this syntax must identify
1161
          a protocol P, a secret key K, and a hash algorithm H
1162
          that produces output of L octets.
1163
1164
          The object's value is a manager-generated, partially-random
1165
          value which, when modified, causes the value of the secret
1166
          key K, to be modified via a one-way function.
1167
1168
          The value of an instance of this object is the concatenation
1169
          of two components: first a 'random' component and then a
1170
          'delta' component.
1171
1172
          The lengths of the random and delta components
1173
          are given by the corresponding value of the protocol P;
1174
          if P requires K to be a fixed length, the length of both the
1175
          random and delta components is that fixed length; if P
1176
          allows the length of K to be variable up to a particular
1177
          maximum length, the length of the random component is that
1178
          maximum length and the length of the delta component is any
1179
          length less than or equal to that maximum length.
1180
          For example, usmHMACMD5AuthProtocol requires K to be a fixed
1181
          length of 16 octets and L - of 16 octets.
1182
          usmHMACSHAAuthProtocol requires K to be a fixed length of
1183
          20 octets and L - of 20 octets. Other protocols may define
1184
          other sizes, as deemed appropriate.
1185
1186
          When a requester wants to change the old key K to a new
1187
          [... see encode_keychange above ...]
1188
1189
          At the receiver side, when an instance of this object is set
1190
          to a new value, then a new value of K is computed as follows:
1191
1192
           - a temporary variable is initialized to the existing value
1193
             of K;
1194
           - if the length of the delta component is greater than L
1195
             octets, then:
1196
              - the random component is appended to the value of the
1197
                temporary variable, and the result is input to the
1198
                hash algorithm H to produce a digest value, and the
1199
                temporary variable is set to this digest value;
1200
              - the value of the temporary variable is XOR-ed with
1201
                the first (next) L-octets (16 octets in case of MD5)
1202
                of the delta component to produce the first (next)
1203
                L-octets (16 octets in case of MD5) of the new value
1204
                of K.
1205
              - the above two steps are repeated until the unused
1206
                portion of the delta component is L octets or less,
1207
           - the random component is appended to the value of the
1208
             temporary variable, and the result is input to the
1209
             hash algorithm H to produce a digest value;
1210
           - this digest value, truncated if necessary to be the same
1211
             length as the unused portion of the delta component, is
1212
             XOR-ed with the unused portion of the delta component to
1213
             produce the (final portion of the) new value of K.
1214
1215
           For example, using MD5 as the hash algorithm H:
1216
1217
              iterations = (lenOfDelta - 1)/16; -- integer division
1218
              temp = keyOld;
1219
              for (i = 0; i < iterations; i++) {
1220
                  temp = MD5 (temp || random);
1221
                  keyNew[i*16 .. (i*16)+15] =
1222
                         temp XOR delta[i*16 .. (i*16)+15];
1223
              }
1224
              temp = MD5 (temp || random);
1225
              keyNew[i*16 .. lenOfDelta-1] =
1226
                     temp XOR delta[i*16 .. lenOfDelta-1];
1227
1228
          The value of an object with this syntax, whenever it is
1229
          retrieved by the management protocol, is always the zero
1230
          length string.
1231
1232
          Note that the keyOld and keyNew are the localized keys.
1233
1234
          Note that it is probably wise that when an SNMP entity sends
1235
          a SetRequest to change a key, that it keeps a copy of the old
1236
          key until it has confirmed that the key change actually
1237
          succeeded.
1238
         "
1239
    SYNTAX       OCTET STRING
1240
 */
1241
/*
1242
 * XXX:  if the newkey is not long enough, it should be freed and remalloced 
1243
 */
1244
int
1245
decode_keychange(const oid *hashtype, u_int hashtype_len,
1246
                 const u_char *oldkey, size_t oldkey_len,
1247
                 const u_char *kcstring, size_t kcstring_len,
1248
                 u_char *newkey, size_t *newkey_len)
1249
#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
1250
0
{
1251
0
    int             rval = SNMPERR_SUCCESS, auth_type;
1252
0
    size_t          hash_len = 0, key_len = 0;
1253
0
    int             ihash_len = 0;
1254
0
    u_int           nbytes = 0;
1255
1256
0
    const u_char   *deltap;
1257
0
    u_char          hash[SNMP_MAXBUF];
1258
0
    size_t          delta_len, tmpbuf_len;
1259
0
    u_char         *tmpbuf = NULL;
1260
#ifdef NETSNMP_ENABLE_TESTING_CODE
1261
    u_char         *newkey_save = newkey;
1262
#endif
1263
1264
    /*
1265
     * Sanity check.
1266
     */
1267
0
    if (!hashtype || !oldkey || !kcstring || !newkey || !newkey_len
1268
0
        || (oldkey_len == 0) || (kcstring_len == 0) || (*newkey_len == 0)) {
1269
0
        DEBUGMSGTL(("decode_keychange", "bad args\n"));
1270
0
        QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
1271
0
    }
1272
1273
    /*
1274
     * Setup for the transform type.
1275
     */
1276
0
    auth_type = sc_get_authtype(hashtype, hashtype_len);
1277
0
    ihash_len = sc_get_proper_auth_length_bytype(auth_type);
1278
0
    if (ihash_len == SNMPERR_GENERR) {
1279
0
        DEBUGMSGTL(("decode_keychange", "proper length err\n"));
1280
0
        QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
1281
0
    }
1282
0
    hash_len = (size_t) ihash_len;
1283
0
    DEBUGMSGTL(("decode_keychange",
1284
0
                "oldkey_len %" NETSNMP_PRIz "d, newkey_len %" NETSNMP_PRIz "d, kcstring_len %" NETSNMP_PRIz "d, hash_len %" NETSNMP_PRIz "d\n",
1285
0
                oldkey_len, *newkey_len, kcstring_len, hash_len));
1286
1287
0
    if (((oldkey_len * 2) != kcstring_len) || (*newkey_len < oldkey_len)) {
1288
0
        DEBUGMSGTL(("decode_keychange", "keylen error\n"));
1289
0
        QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
1290
0
    }
1291
1292
    /*********** handle hash len > keylen ******************/
1293
1294
0
    key_len = oldkey_len;
1295
0
    *newkey_len = oldkey_len;
1296
1297
#ifdef NETSNMP_ENABLE_TESTING_CODE
1298
    DEBUGIF("decode_keychange") {
1299
        int             i;
1300
        DEBUGMSG(("decode_keychange",
1301
                  "oldkey: key=0x"));
1302
        for (i = 0; i < oldkey_len; i++)
1303
            DEBUGMSG(("decode_keychange", "%02x", oldkey[i] & 0xff));
1304
        DEBUGMSG(("decode_keychange", " (%ld)\n", oldkey_len));
1305
1306
        DEBUGMSG(("decode_keychange",
1307
                  "kcstring: key=0x"));
1308
        for (i = 0; i < kcstring_len; i++)
1309
            DEBUGMSG(("decode_keychange", "%02x", kcstring[i] & 0xff));
1310
        DEBUGMSG(("decode_keychange", " (%ld)\n", kcstring_len));
1311
    }
1312
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
1313
1314
    /*
1315
     * KeyChange ::=     TEXTUAL-CONVENTION
1316
     *    STATUS         current
1317
     *    DESCRIPTION
1318
     *    [...]
1319
     *    At the receiver side, when an instance of this object is set
1320
     *    to a new value, then a new value of K is computed as follows:
1321
     *
1322
     *     - a temporary variable is initialized to the existing value
1323
     *       of K;
1324
     */
1325
0
    tmpbuf = (u_char *) malloc(key_len * 2);
1326
0
    if (NULL == tmpbuf) {
1327
0
        DEBUGMSGTL(("decode_keychange", "malloc failed\n"));
1328
0
        QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
1329
0
    }
1330
0
    memcpy(tmpbuf, oldkey, key_len);
1331
0
    tmpbuf_len = key_len;
1332
1333
    /*
1334
     * key=0xe27c077c47d4cb4e4473aeac969ba9fa622486e0|d7440406892e0941175cb5ee
1335
     * key=0xe27c077c47d4cb4e4473aeac969ba9fa622486e0|4fa8e081a6cb2f089f40949c
1336
     */
1337
0
    delta_len = 0;
1338
0
    deltap = kcstring + key_len;
1339
0
    while (delta_len < key_len) {
1340
1341
        /*
1342
         * - if the length of the delta component is greater than L
1343
         *   octets, then:
1344
         *    - the random component is appended to the value of the
1345
         *      temporary variable, ...
1346
         */
1347
0
        DEBUGMSGTL(("decode_keychange",
1348
0
                    "append random tmpbuf_len %" NETSNMP_PRIz "d key_len %" NETSNMP_PRIz "d\n",
1349
0
                    tmpbuf_len, key_len));
1350
0
        memcpy(tmpbuf + tmpbuf_len, kcstring, key_len);
1351
0
        tmpbuf_len += key_len;
1352
1353
        /*
1354
         *                      ... and the result is input to the
1355
         *      hash algorithm H to produce a digest value, ...
1356
         */
1357
0
        hash_len = sizeof(hash);
1358
0
        DEBUGMSGTL(("decode_keychange", "get hash\n"));
1359
0
        rval = sc_hash(hashtype, hashtype_len, tmpbuf, tmpbuf_len,
1360
0
                       hash, &hash_len);
1361
0
        QUITFUN(rval, decode_keychange_quit);
1362
0
        if (hash_len > key_len) {
1363
0
            DEBUGMSGTL(("decode_keychange",
1364
0
                        "truncating hash to key_len\n"));
1365
0
            hash_len = key_len;
1366
0
        }
1367
1368
        /*
1369
         *                                              ... and the
1370
         *      temporary variable is set to this digest value;
1371
         */
1372
0
        DEBUGMSGTL(("decode_keychange", "copy %" NETSNMP_PRIz "d hash bytes to tmp\n",
1373
0
                       hash_len));
1374
0
        memcpy(tmpbuf, hash, hash_len);
1375
0
        tmpbuf_len = hash_len;
1376
1377
        /*
1378
         *    - the value of the temporary variable is XOR-ed with
1379
         *      the first (next) L-octets (16 octets in case of MD5)
1380
         *      of the delta component to produce the first (next)
1381
         *      L-octets (16 octets in case of MD5) of the new value
1382
         *      of K.
1383
         */
1384
0
        DEBUGMSGTL(("decode_keychange",
1385
0
                    "xor to get new key; hash_len %" NETSNMP_PRIz "d delta_len %" NETSNMP_PRIz "d\n",
1386
0
                    hash_len, delta_len));
1387
0
        nbytes = 0;
1388
0
        while ((nbytes < hash_len) && (delta_len < key_len)) {
1389
0
            newkey[delta_len] = tmpbuf[nbytes++] ^ deltap[delta_len];
1390
0
            ++delta_len;
1391
0
        }
1392
0
    }
1393
1394
#ifdef NETSNMP_ENABLE_TESTING_CODE
1395
    DEBUGIF("decode_keychange") {
1396
        int             i;
1397
        DEBUGMSG(("decode_keychange",
1398
                  "newkey: key=0x"));
1399
        for (i = 0; i < *newkey_len; i++)
1400
            DEBUGMSG(("decode_keychange", "%02x", newkey_save[i] & 0xff));
1401
        DEBUGMSG(("decode_keychange", " (%ld)\n", *newkey_len));
1402
    }
1403
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
1404
1405
0
  decode_keychange_quit:
1406
0
    if (rval != SNMPERR_SUCCESS) {
1407
0
        DEBUGMSGTL(("decode_keychange", "error %d\n", rval));
1408
0
        if (newkey)
1409
0
            memset(newkey, 0, key_len);
1410
0
    }
1411
0
    memset(hash, 0, SNMP_MAXBUF);
1412
0
    SNMP_FREE(tmpbuf);
1413
1414
0
    return rval;
1415
1416
0
}                               /* end decode_keychange() */
1417
1418
#else
1419
_KEYTOOLS_NOT_AVAILABLE
1420
#endif                          /* internal or openssl */
1421
#endif /* NETSNMP_FEATURE_REMOVE_USM_KEYTOOLS */