]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/snmp/lib/v2_0/src/keytools.c
Initial revision
[karo-tx-redboot.git] / packages / net / snmp / lib / v2_0 / src / keytools.c
1 //==========================================================================
2 //
3 //      ./lib/current/src/keytools.c
4 //
5 //
6 //==========================================================================
7 //####ECOSGPLCOPYRIGHTBEGIN####
8 // -------------------------------------------
9 // This file is part of eCos, the Embedded Configurable Operating System.
10 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
11 //
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
15 //
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 // for more details.
20 //
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 //
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
31 //
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
34 //
35 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36 // at http://sources.redhat.com/ecos/ecos-license/
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //####UCDSNMPCOPYRIGHTBEGIN####
40 //
41 // -------------------------------------------
42 //
43 // Portions of this software may have been derived from the UCD-SNMP
44 // project,  <http://ucd-snmp.ucdavis.edu/>  from the University of
45 // California at Davis, which was originally based on the Carnegie Mellon
46 // University SNMP implementation.  Portions of this software are therefore
47 // covered by the appropriate copyright disclaimers included herein.
48 //
49 // The release used was version 4.1.2 of May 2000.  "ucd-snmp-4.1.2"
50 // -------------------------------------------
51 //
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
55 //
56 // Author(s):    hmt
57 // Contributors: hmt
58 // Date:         2000-05-30
59 // Purpose:      Port of UCD-SNMP distribution to eCos.
60 // Description:  
61 //              
62 //
63 //####DESCRIPTIONEND####
64 //
65 //==========================================================================
66 /********************************************************************
67        Copyright 1989, 1991, 1992 by Carnegie Mellon University
68
69                           Derivative Work -
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
71
72                          All Rights Reserved
73
74 Permission to use, copy, modify and distribute this software and its
75 documentation for any purpose and without fee is hereby granted,
76 provided that the above copyright notice appears in all copies and
77 that both that copyright notice and this permission notice appear in
78 supporting documentation, and that the name of CMU and The Regents of
79 the University of California not be used in advertising or publicity
80 pertaining to distribution of the software without specific written
81 permission.
82
83 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85 WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL CMU OR
86 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91 *********************************************************************/
92 /*
93  * keytools.c
94  */
95
96 #include <config.h>
97
98 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
99 #include <stdio.h>
100 #include <sys/types.h>
101 #if HAVE_WINSOCK_H
102 #include <winsock.h>
103 #endif
104 #ifdef HAVE_NETINET_IN_H
105 #include <netinet/in.h>
106 #endif
107 #ifdef HAVE_STDLIB_H
108 #include <stdlib.h>
109 #endif
110 #if HAVE_STRING_H
111 #include <string.h>
112 #else
113 #include <strings.h>
114 #endif
115
116 #if HAVE_DMALLOC_H
117 #include <dmalloc.h>
118 #endif
119
120 #include "asn1.h"
121 #include "snmp_api.h"
122 #ifdef USE_OPENSSL
123 #       include <openssl/hmac.h>
124 #else 
125 #ifdef USE_INTERNAL_MD5
126 #include "md5.h"
127 #endif
128 #endif
129
130 #include "scapi.h"
131 #include "keytools.h"
132 #include "tools.h"
133 #include "snmp_debug.h"
134 #include "snmp_logging.h"
135
136 #include "transform_oids.h"
137
138 /*******************************************************************-o-******
139  * generate_Ku
140  *
141  * Parameters:
142  *      *hashtype       MIB OID for the transform type for hashing.
143  *       hashtype_len   Length of OID value.
144  *      *P              Pre-allocated bytes of passpharase.
145  *       pplen          Length of passphrase.
146  *      *Ku             Buffer to contain Ku.
147  *      *kulen          Length of Ku buffer.
148  *      
149  * Returns:
150  *      SNMPERR_SUCCESS                 Success.
151  *      SNMPERR_GENERR                  All errors.
152  *
153  *
154  * Convert a passphrase into a master user key, Ku, according to the
155  * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM)
156  * as follows:
157  *
158  * Expand the passphrase to fill the passphrase buffer space, if necessary,
159  * concatenation as many duplicates as possible of P to itself.  If P is
160  * larger than the buffer space, truncate it to fit.
161  *
162  * Then hash the result with the given hashtype transform.  Return
163  * the result as Ku.
164  *
165  * If successful, kulen contains the size of the hash written to Ku.
166  *
167  * NOTE  Passphrases less than USM_LENGTH_P_MIN characters in length
168  *       cause an error to be returned.
169  *       (Punt this check to the cmdline apps?  XXX)
170  */
171 int
172 generate_Ku(    oid     *hashtype,      u_int  hashtype_len,
173                 u_char  *P,             size_t  pplen,
174                 u_char  *Ku,            size_t *kulen)
175 #if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL)
176 {
177         int              rval   = SNMPERR_SUCCESS,
178                          nbytes = USM_LENGTH_EXPANDED_PASSPHRASE;
179
180         u_int            i, pindex = 0;
181
182         u_char           buf[USM_LENGTH_KU_HASHBLOCK],
183                         *bufp;
184
185 #ifdef USE_OPENSSL
186         EVP_MD_CTX      *ctx = malloc(sizeof(EVP_MD_CTX));
187 #else
188         MDstruct         MD;
189 #endif
190         /*
191          * Sanity check.
192          */
193         if ( !hashtype || !P || !Ku || !kulen
194                 || (*kulen<=0)
195                 || (hashtype_len != USM_LENGTH_OID_TRANSFORM) )
196         {
197                 QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
198         }
199
200         if (pplen < USM_LENGTH_P_MIN) {
201 #ifdef SNMP_TESTING_CODE
202           snmp_log(LOG_WARNING, "Warning: passphrase chosen is below the length requiremnts of the USM.\n");
203 #else
204           snmp_set_detail("Password length too short.");
205           QUITFUN(SNMPERR_GENERR, generate_Ku_quit);
206 #endif
207         }
208
209
210         /*
211          * Setup for the transform type.
212          */
213 #ifdef USE_OPENSSL
214         
215         if (ISTRANSFORM(hashtype, HMACMD5Auth))
216           EVP_DigestInit(ctx, EVP_md5());
217         else if (ISTRANSFORM(hashtype, HMACSHA1Auth))
218           EVP_DigestInit(ctx, EVP_sha1());
219         else  {
220           free(ctx);
221           return (SNMPERR_GENERR);
222         }
223 #else 
224         MDbegin(&MD);
225 #endif /* USE_OPENSSL */
226
227         while (nbytes > 0) {
228                 bufp = buf;
229                 for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) {
230                         *bufp++ = P[pindex++ % pplen];
231                 }
232 #ifdef USE_OPENSSL
233                 EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK);
234 #else
235                 if (MDupdate(&MD, buf, USM_LENGTH_KU_HASHBLOCK*8)) {
236                     rval = SNMPERR_USM_ENCRYPTIONERROR;
237                     goto md5_fin;
238                 }
239 #endif /* USE_OPENSSL */
240
241                 nbytes -= USM_LENGTH_KU_HASHBLOCK;
242         }
243
244 #ifdef USE_OPENSSL
245         EVP_DigestFinal(ctx, (unsigned char *) Ku, (unsigned int *) kulen);
246         /* what about free() */
247 #else
248         if (MDupdate(&MD, buf, 0)) {
249             rval = SNMPERR_USM_ENCRYPTIONERROR;
250             goto md5_fin;
251         }
252         *kulen = sc_get_properlength(hashtype, hashtype_len);
253         MDget(&MD, Ku, *kulen);
254 md5_fin:
255         memset(&MD, 0, sizeof(MD));
256 #endif /* USE_OPENSSL */
257
258
259 #ifdef SNMP_TESTING_CODE
260         DEBUGMSGTL(("generate_Ku", "generating Ku (from %s): ", P));
261         for(i=0; i < *kulen; i++)
262           DEBUGMSG(("generate_Ku", "%02x",Ku[i]));
263         DEBUGMSG(("generate_Ku","\n"));
264 #endif /* SNMP_TESTING_CODE */
265
266
267 generate_Ku_quit:
268         memset(buf, 0, sizeof(buf));
269 #ifdef USE_OPENSSL
270         free(ctx);
271 #endif
272         return rval;
273
274 }  /* end generate_Ku() */
275
276 #else
277 _KEYTOOLS_NOT_AVAILABLE
278 #endif                                          /* internal or openssl */
279
280
281
282
283 /*******************************************************************-o-******
284  * generate_kul
285  *
286  * Parameters:
287  *      *hashtype
288  *       hashtype_len
289  *      *engineID
290  *       engineID_len
291  *      *Ku             Master key for a given user.
292  *       ku_len         Length of Ku in bytes.
293  *      *Kul            Localized key for a given user at engineID.
294  *      *kul_len        Length of Kul buffer (IN); Length of Kul key (OUT).
295  *      
296  * Returns:
297  *      SNMPERR_SUCCESS                 Success.
298  *      SNMPERR_GENERR                  All errors.
299  *
300  *
301  * Ku MUST be the proper length (currently fixed) for the given hashtype.
302  *
303  * Upon successful return, Kul contains the localized form of Ku at
304  * engineID, and the length of the key is stored in kul_len.
305  *
306  * The localized key method is defined in RFC2274, Sections 2.6 and A.2, and
307  * originally documented in:
308  *      U. Blumenthal, N. C. Hien, B. Wijnen,
309  *      "Key Derivation for Network Management Applications",
310  *      IEEE Network Magazine, April/May issue, 1997.
311  *
312  *
313  * ASSUMES  SNMP_MAXBUF >= sizeof(Ku + engineID + Ku).
314  *
315  * NOTE  Localized keys for privacy transforms are generated via
316  *       the authentication transform held by the same usmUser.
317  *
318  * XXX  An engineID of any length is accepted, even if larger than
319  *      what is spec'ed for the textual convention.
320  */
321 int
322 generate_kul(   oid     *hashtype,      u_int  hashtype_len,
323                 u_char  *engineID,      size_t  engineID_len,
324                 u_char  *Ku,            size_t  ku_len,
325                 u_char  *Kul,           size_t *kul_len)
326 #if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5)
327 {
328         int              rval    = SNMPERR_SUCCESS;
329         u_int            nbytes  = 0;
330         size_t           properlength;
331
332         u_char           buf[SNMP_MAXBUF];
333         void            *context = NULL;
334 #ifdef SNMP_TESTING_CODE
335         int              i;
336 #endif
337
338
339         /*
340          * Sanity check.
341          */
342         if ( !hashtype || !engineID || !Ku || !Kul || !kul_len
343                 || (engineID_len<=0) || (ku_len<=0) || (*kul_len<=0)
344                 || (hashtype_len != USM_LENGTH_OID_TRANSFORM) )
345         {
346                 QUITFUN(SNMPERR_GENERR, generate_kul_quit);
347         }
348
349
350         properlength = sc_get_properlength(hashtype, hashtype_len);
351         if (properlength == SNMPERR_GENERR)
352           QUITFUN(SNMPERR_GENERR, generate_kul_quit);
353        
354
355         if (((int)*kul_len < properlength) || ((int)ku_len < properlength) ) {
356                 QUITFUN(SNMPERR_GENERR, generate_kul_quit);
357         }
358
359         /*
360          * Concatenate Ku and engineID properly, then hash the result.
361          * Store it in Kul.
362          */
363         nbytes = 0;
364         memcpy(buf,        Ku,          properlength); nbytes += properlength;
365         memcpy(buf+nbytes, engineID,    engineID_len); nbytes += engineID_len;
366         memcpy(buf+nbytes, Ku,          properlength); nbytes += properlength;
367
368         rval = sc_hash(hashtype, hashtype_len, buf, nbytes, Kul, kul_len);
369
370 #ifdef SNMP_TESTING_CODE
371         DEBUGMSGTL(("generate_kul", "generating Kul (from Ku): "));
372         for(i=0; i < *kul_len; i++)
373           DEBUGMSG(("generate_kul", "%02x",Kul[i]));
374         DEBUGMSG(("generate_kul", "keytools\n"));
375 #endif /* SNMP_TESTING_CODE */
376
377         QUITFUN(rval, generate_kul_quit);
378                 
379
380 generate_kul_quit:
381         SNMP_FREE(context);
382         return rval;
383
384 }  /* end generate_kul() */
385
386 #else
387 _KEYTOOLS_NOT_AVAILABLE
388 #endif                                          /* internal or openssl */
389
390
391
392
393 /*******************************************************************-o-******
394  * encode_keychange
395  *
396  * Parameters:
397  *      *hashtype       MIB OID for the hash transform type.
398  *       hashtype_len   Length of the MIB OID hash transform type.
399  *      *oldkey         Old key that is used to encodes the new key.
400  *       oldkey_len     Length of oldkey in bytes.
401  *      *newkey         New key that is encoded using the old key.
402  *       newkey_len     Length of new key in bytes.
403  *      *kcstring       Buffer to contain the KeyChange TC string.
404  *      *kcstring_len   Length of kcstring buffer.
405  *      
406  * Returns:
407  *      SNMPERR_SUCCESS                 Success.
408  *      SNMPERR_GENERR                  All errors.
409  *
410  *
411  * Uses oldkey and acquired random bytes to encode newkey into kcstring
412  * according to the rules of the KeyChange TC described in RFC 2274, Section 5.
413  *
414  * Upon successful return, *kcstring_len contains the length of the
415  * encoded string.
416  *
417  * ASSUMES      Old and new key are always equal to each other, although
418  *              this may be less than the transform type hash output
419  *              output length (eg, using KeyChange for a DESPriv key when
420  *              the user also uses SHA1Auth).  This also implies that the
421  *              hash placed in the second 1/2 of the key change string
422  *              will be truncated before the XOR'ing when the hash output is 
423  *              larger than that 1/2 of the key change string.
424  *
425  *              *kcstring_len will be returned as exactly twice that same
426  *              length though the input buffer may be larger.
427  *
428  * XXX FIX:     Does not handle varibable length keys.
429  * XXX FIX:     Does not handle keys larger than the hash algorithm used.
430  */
431 int
432 encode_keychange(       oid     *hashtype,      u_int  hashtype_len,
433                         u_char  *oldkey,        size_t  oldkey_len,
434                         u_char  *newkey,        size_t  newkey_len,
435                         u_char  *kcstring,      size_t *kcstring_len)
436 #if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5)
437 {
438         int              rval    = SNMPERR_SUCCESS;
439         size_t           properlength;
440         size_t            nbytes  = 0;
441
442         u_char          *tmpbuf = NULL;
443         void            *context = NULL;
444
445
446         /*
447          * Sanity check.
448          */
449         if ( !hashtype || !oldkey || !newkey || !kcstring || !kcstring_len
450                 || (oldkey_len<=0) || (newkey_len<=0) || (*kcstring_len<=0)
451                 || (hashtype_len != USM_LENGTH_OID_TRANSFORM) )
452         {
453                 QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
454         }
455
456         /*
457          * Setup for the transform type.
458          */
459         properlength = sc_get_properlength(hashtype, hashtype_len);
460         if (properlength == SNMPERR_GENERR)
461           QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
462
463         if ( (oldkey_len != newkey_len) || (*kcstring_len < (2*oldkey_len)) )
464         {
465                 QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
466         }
467
468         properlength = SNMP_MIN((int)oldkey_len, properlength);
469
470         /*
471          * Use the old key and some random bytes to encode the new key
472          * in the KeyChange TC format:
473          *      . Get random bytes (store in first half of kcstring),
474          *      . Hash (oldkey | random_bytes) (into second half of kcstring),
475          *      . XOR hash and newkey (into second half of kcstring).
476          *
477          * Getting the wrong number of random bytes is considered an error.
478          */
479         nbytes = properlength;
480
481 #if defined(SNMP_TESTING_CODE) && defined(RANDOMZEROS)
482                 memset(kcstring, 0, nbytes);
483                 DEBUGMSG(("encode_keychange",
484                           "** Using all zero bits for \"random\" delta of )"
485                           "the keychange string! **\n"));
486 #else /* !SNMP_TESTING_CODE */
487                 rval = sc_random(kcstring, &nbytes);
488                 QUITFUN(rval, encode_keychange_quit);
489                 if ((int)nbytes != properlength) {
490                         QUITFUN(SNMPERR_GENERR, encode_keychange_quit);
491                 }
492 #endif /* !SNMP_TESTING_CODE */
493
494         tmpbuf = (u_char *)malloc(properlength*2);
495         if (tmpbuf) {
496             memcpy(tmpbuf, oldkey, properlength);
497             memcpy(tmpbuf+properlength, kcstring, properlength);
498     
499             *kcstring_len -= properlength;
500             rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength*2,
501                            kcstring+properlength, kcstring_len);
502             
503             QUITFUN(rval, encode_keychange_quit);
504     
505             *kcstring_len = (properlength*2);
506     
507             kcstring += properlength;
508             nbytes    = 0;
509             while ((int)(nbytes++) < properlength) {
510                 u_char kcs = *kcstring;
511                 *kcstring++ = kcs ^ *newkey++;
512             }
513         }
514
515 encode_keychange_quit:
516         if (rval != SNMPERR_SUCCESS) memset(kcstring, 0, *kcstring_len);
517         SNMP_FREE(tmpbuf);
518         SNMP_FREE(context);
519
520         return rval;
521
522 }  /* end encode_keychange() */
523
524 #else
525 _KEYTOOLS_NOT_AVAILABLE
526 #endif                                          /* internal or openssl */
527
528
529
530
531 /*******************************************************************-o-******
532  * decode_keychange
533  *
534  * Parameters:
535  *      *hashtype       MIB OID of the hash transform to use.
536  *       hashtype_len   Length of the hash transform MIB OID.
537  *      *oldkey         Old key that is used to encode the new key.
538  *       oldkey_len     Length of oldkey in bytes.
539  *      *kcstring       Encoded KeyString buffer containing the new key.
540  *       kcstring_len   Length of kcstring in bytes.
541  *      *newkey         Buffer to hold the extracted new key.
542  *      *newkey_len     Length of newkey in bytes.
543  *      
544  * Returns:
545  *      SNMPERR_SUCCESS                 Success.
546  *      SNMPERR_GENERR                  All errors.
547  *
548  *
549  * Decodes a string of bits encoded according to the KeyChange TC described
550  * in RFC 2274, Section 5.  The new key is extracted from *kcstring with
551  * the aid of the old key.
552  *
553  * Upon successful return, *newkey_len contains the length of the new key.
554  *
555  *
556  * ASSUMES      Old key is exactly 1/2 the length of the KeyChange buffer,
557  *              although this length may be less than the hash transform
558  *              output.  Thus the new key length will be equal to the old
559  *              key length.
560  */
561
562 /* XXX:  if the newkey is not long enough, it should be freed and remalloced */
563 int
564 decode_keychange(       oid     *hashtype,      u_int  hashtype_len,
565                         u_char  *oldkey,        size_t  oldkey_len,
566                         u_char  *kcstring,      size_t  kcstring_len,
567                         u_char  *newkey,        size_t *newkey_len)
568 #if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5)
569 {
570         int              rval    = SNMPERR_SUCCESS;
571         size_t           properlength = 0;
572         u_int            nbytes  = 0;
573
574         u_char          *bufp,
575                          tmp_buf[SNMP_MAXBUF];
576         size_t           tmp_buf_len = SNMP_MAXBUF;
577         void            *context = NULL;
578         u_char          *tmpbuf = NULL;
579
580
581
582         /*
583          * Sanity check.
584          */
585         if ( !hashtype || !oldkey || !kcstring || !newkey || !newkey_len
586                 || (oldkey_len<=0) || (kcstring_len<=0) || (*newkey_len<=0)
587                 || (hashtype_len != USM_LENGTH_OID_TRANSFORM) )
588         {
589                 QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
590         }
591
592
593         /*
594          * Setup for the transform type.
595          */
596         properlength = sc_get_properlength(hashtype, hashtype_len);
597         if (properlength == SNMPERR_GENERR)
598           QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
599
600
601         if ( ((oldkey_len*2) != kcstring_len) || (*newkey_len < oldkey_len) )
602         {
603                 QUITFUN(SNMPERR_GENERR, decode_keychange_quit);
604         }
605
606         properlength = oldkey_len;
607         *newkey_len = properlength;
608
609         /*
610          * Use the old key and the given KeyChange TC string to recover
611          * the new key:
612          *      . Hash (oldkey | random_bytes) (into newkey),
613          *      . XOR hash and encoded (second) half of kcstring (into newkey).
614          */
615         tmpbuf = (u_char *)malloc(properlength*2);
616         if (tmpbuf) {
617             memcpy(tmpbuf, oldkey, properlength);
618             memcpy(tmpbuf+properlength, kcstring, properlength);
619     
620             rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength*2,
621                            tmp_buf, &tmp_buf_len);
622             QUITFUN(rval, decode_keychange_quit);
623     
624             memcpy(newkey, tmp_buf, properlength);
625             bufp   = kcstring+properlength;
626             nbytes = 0;
627             while ((int)(nbytes++) < properlength) {
628                     u_char nk = *newkey;
629                     *newkey++ = nk ^ *bufp++;
630             }
631         }
632
633 decode_keychange_quit:
634         if (rval != SNMPERR_SUCCESS) {
635                 memset(newkey, 0, properlength);
636         }
637         memset(tmp_buf, 0, SNMP_MAXBUF);
638         SNMP_FREE(context);
639         if (tmpbuf != NULL) SNMP_FREE(tmpbuf);
640
641         return rval;
642
643 }  /* end decode_keychange() */
644
645 #else
646 _KEYTOOLS_NOT_AVAILABLE
647 #endif                                          /* internal or openssl */
648
649 #endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */