Coverage Report

Created: 2024-07-27 06:05

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