net-snmp 5.7
scapi.c
00001 /* Portions of this file are subject to the following copyright(s).  See
00002  * the Net-SNMP's COPYING file for more details and other copyrights
00003  * that may apply:
00004  */
00005 /*
00006  * Portions of this file are copyrighted by:
00007  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00008  * Use is subject to license terms specified in the COPYING file
00009  * distributed with the Net-SNMP package.
00010  */
00011 
00012 /*
00013  * scapi.c
00014  *
00015  */
00016 
00017 #include <net-snmp/net-snmp-config.h>
00018 #include <net-snmp/net-snmp-features.h>
00019 
00020 #include <sys/types.h>
00021 #ifdef HAVE_STDLIB_H
00022 #include <stdlib.h>
00023 #endif
00024 #if HAVE_STRING_H
00025 #include <string.h>
00026 #else
00027 #include <strings.h>
00028 #endif
00029 #if TIME_WITH_SYS_TIME
00030 # include <sys/time.h>
00031 # include <time.h>
00032 #else
00033 # if HAVE_SYS_TIME_H
00034 #  include <sys/time.h>
00035 # else
00036 #  include <time.h>
00037 # endif
00038 #endif
00039 #ifdef HAVE_NETINET_IN_H
00040 #include <netinet/in.h>
00041 #endif
00042 
00043 #if HAVE_UNISTD_H
00044 #include <unistd.h>
00045 #endif
00046 #if HAVE_DMALLOC_H
00047 #include <dmalloc.h>
00048 #endif
00049 
00050 #include <net-snmp/types.h>
00051 #include <net-snmp/output_api.h>
00052 #include <net-snmp/utilities.h>
00053 
00054 netsnmp_feature_child_of(usm_support, libnetsnmp)
00055 netsnmp_feature_child_of(usm_scapi, usm_support)
00056 
00057 #ifndef NETSNMP_FEATURE_REMOVE_USM_SCAPI
00058 
00059 #ifdef NETSNMP_USE_INTERNAL_MD5
00060 #include <net-snmp/library/md5.h>
00061 #endif
00062 #include <net-snmp/library/snmp_api.h>
00063 #include <net-snmp/library/callback.h>
00064 #include <net-snmp/library/snmp_secmod.h>
00065 #include <net-snmp/library/snmpusm.h>
00066 #include <net-snmp/library/keytools.h>
00067 #include <net-snmp/library/scapi.h>
00068 #include <net-snmp/library/mib.h>
00069 #include <net-snmp/library/transform_oids.h>
00070 
00071 #ifdef NETSNMP_USE_INTERNAL_CRYPTO
00072 #include <net-snmp/library/openssl_md5.h>
00073 #include <net-snmp/library/openssl_sha.h>
00074 #include <net-snmp/library/openssl_des.h>
00075 #include <net-snmp/library/openssl_aes.h>
00076 #endif
00077 
00078 #ifdef NETSNMP_USE_OPENSSL
00079 #include <openssl/hmac.h>
00080 #include <openssl/evp.h>
00081 #include <openssl/rand.h>
00082 #include <openssl/des.h>
00083 #ifdef HAVE_AES
00084 #include <openssl/aes.h>
00085 #endif
00086 
00087 #ifndef NETSNMP_DISABLE_DES
00088 #ifdef HAVE_STRUCT_DES_KS_STRUCT_WEAK_KEY
00089 /* these are older names for newer structures that exist in openssl .9.7 */
00090 #define DES_key_schedule    des_key_schedule 
00091 #define DES_cblock          des_cblock 
00092 #define DES_key_sched       des_key_sched 
00093 #define DES_ncbc_encrypt    des_ncbc_encrypt
00094 #define DES_cbc_encrypt    des_cbc_encrypt
00095 #define OLD_DES
00096 #endif
00097 #endif
00098 
00099 #endif /* HAVE_OPENSSL */
00100 
00101 #ifdef NETSNMP_USE_INTERNAL_CRYPTO
00102 #endif
00103 
00104 #ifdef NETSNMP_USE_PKCS11
00105 #include <security/cryptoki.h>
00106 #endif
00107 
00108 #ifdef QUITFUN
00109 #undef QUITFUN
00110 #define QUITFUN(e, l)                                   \
00111         if (e != SNMPERR_SUCCESS) {                     \
00112                 rval = SNMPERR_SC_GENERAL_FAILURE;      \
00113                 goto l ;                                \
00114         }
00115 #endif
00116 
00117 #ifdef NETSNMP_USE_INTERNAL_CRYPTO
00118 static
00119 int SHA1_hmac(u_char * data, size_t len, u_char * mac, size_t maclen,
00120               u_char * secret, size_t secretlen);
00121 
00122 static
00123 int MD5_hmac(u_char * data, size_t len, u_char * mac, size_t maclen,
00124              u_char * secret, size_t secretlen);
00125 #endif
00126 
00127 /*
00128  * sc_get_properlength(oid *hashtype, u_int hashtype_len):
00129  * 
00130  * Given a hashing type ("hashtype" and its length hashtype_len), return
00131  * the length of the hash result.
00132  * 
00133  * Returns either the length or SNMPERR_GENERR for an unknown hashing type.
00134  */
00135 int
00136 sc_get_properlength(const oid * hashtype, u_int hashtype_len)
00137 {
00138     DEBUGTRACE;
00139     /*
00140      * Determine transform type hash length.
00141      */
00142 #ifndef NETSNMP_DISABLE_MD5
00143     if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
00144         return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
00145     } else
00146 #endif
00147         if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
00148         return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
00149     }
00150     return SNMPERR_GENERR;
00151 }
00152 
00153 netsnmp_feature_child_of(scapi_get_proper_priv_length, netsnmp_unused)
00154 #ifndef NETSNMP_FEATURE_REMOVE_SCAPI_GET_PROPER_PRIV_LENGTH
00155 int
00156 sc_get_proper_priv_length(const oid * privtype, u_int privtype_len)
00157 {
00158     int properlength = 0;
00159 #ifndef NETSNMP_DISABLE_DES
00160     if (ISTRANSFORM(privtype, DESPriv)) {
00161         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
00162     }
00163 #endif
00164 #ifdef HAVE_AES
00165     if (ISTRANSFORM(privtype, AESPriv)) {
00166         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
00167     }
00168 #endif
00169     return properlength;
00170 }
00171 #endif /* NETSNMP_FEATURE_REMOVE_SCAPI_GET_PROPER_PRIV_LENGTH */
00172 
00173 
00174 /*******************************************************************-o-******
00175  * sc_init
00176  *
00177  * Returns:
00178  *      SNMPERR_SUCCESS                 Success.
00179  */
00180 int
00181 sc_init(void)
00182 {
00183     int             rval = SNMPERR_SUCCESS;
00184 
00185 #if !defined(NETSNMP_USE_OPENSSL)
00186 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00187     struct timeval  tv;
00188 
00189     DEBUGTRACE;
00190 
00191     gettimeofday(&tv, (struct timezone *) 0);
00192 
00193     srandom((unsigned)(tv.tv_sec ^ tv.tv_usec));
00194 #elif NETSNMP_USE_PKCS11
00195     DEBUGTRACE;
00196     rval = pkcs_init();
00197 #else
00198     rval = SNMPERR_SC_NOT_CONFIGURED;
00199 #endif                           /* NETSNMP_USE_INTERNAL_MD5 */
00200     /*
00201      * XXX ogud: The only reason to do anything here with openssl is to 
00202      * * XXX ogud: seed random number generator 
00203      */
00204 #endif                          /* ifndef NETSNMP_USE_OPENSSL */
00205     return rval;
00206 }                               /* end sc_init() */
00207 
00208 /*******************************************************************-o-******
00209  * sc_random
00210  *
00211  * Parameters:
00212  *      *buf            Pre-allocated buffer.
00213  *      *buflen         Size of buffer.
00214  *      
00215  * Returns:
00216  *      SNMPERR_SUCCESS                 Success.
00217  */
00218 int
00219 sc_random(u_char * buf, size_t * buflen)
00220 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00221 {
00222     int             rval = SNMPERR_SUCCESS;
00223 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00224     int             i;
00225     int             rndval;
00226     u_char         *ucp = buf;
00227 #endif
00228 
00229     DEBUGTRACE;
00230 
00231 #ifdef NETSNMP_USE_OPENSSL
00232     RAND_bytes(buf, *buflen);   /* will never fail */
00233 #elif NETSNMP_USE_PKCS11                        /* NETSNMP_USE_PKCS11 */
00234     pkcs_random(buf, *buflen);
00235 #else                           /* NETSNMP_USE_INTERNAL_MD5 */
00236     /*
00237      * fill the buffer with random integers.  Note that random()
00238      * is defined in config.h and may not be truly the random()
00239      * system call if something better existed 
00240      */
00241     rval = *buflen - *buflen % sizeof(rndval);
00242     for (i = 0; i < rval; i += sizeof(rndval)) {
00243         rndval = random();
00244         memcpy(ucp, &rndval, sizeof(rndval));
00245         ucp += sizeof(rndval);
00246     }
00247 
00248     rndval = random();
00249     memcpy(ucp, &rndval, *buflen % sizeof(rndval));
00250 
00251     rval = SNMPERR_SUCCESS;
00252 #endif                          /* NETSNMP_USE_OPENSSL */
00253     return rval;
00254 
00255 }                               /* end sc_random() */
00256 
00257 #else
00258 _SCAPI_NOT_CONFIGURED
00259 #endif                          /*  */
00260 /*******************************************************************-o-******
00261  * sc_generate_keyed_hash
00262  *
00263  * Parameters:
00264  *       authtype       Type of authentication transform.
00265  *       authtypelen
00266  *      *key            Pointer to key (Kul) to use in keyed hash.
00267  *       keylen         Length of key in bytes.
00268  *      *message        Pointer to the message to hash.
00269  *       msglen         Length of the message.
00270  *      *MAC            Will be returned with allocated bytes containg hash.
00271  *      *maclen         Length of the hash buffer in bytes; also indicates
00272  *                              whether the MAC should be truncated.
00273  *      
00274  * Returns:
00275  *      SNMPERR_SUCCESS                 Success.
00276  *      SNMPERR_GENERR                  All errs
00277  *
00278  *
00279  * A hash of the first msglen bytes of message using a keyed hash defined
00280  * by authtype is created and stored in MAC.  MAC is ASSUMED to be a buffer
00281  * of at least maclen bytes.  If the length of the hash is greater than
00282  * maclen, it is truncated to fit the buffer.  If the length of the hash is
00283  * less than maclen, maclen set to the number of hash bytes generated.
00284  *
00285  * ASSUMED that the number of hash bits is a multiple of 8.
00286  */
00287 int
00288 sc_generate_keyed_hash(const oid * authtype, size_t authtypelen,
00289                        const u_char * key, u_int keylen,
00290                        const u_char * message, u_int msglen,
00291                        u_char * MAC, size_t * maclen)
00292 #if  defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00293 {
00294     int             rval = SNMPERR_SUCCESS;
00295     int             iproperlength;
00296     size_t          properlength;
00297 
00298     u_char          buf[SNMP_MAXBUF_SMALL];
00299 #if  defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
00300     unsigned int    buf_len = sizeof(buf);
00301 #endif
00302 
00303     DEBUGTRACE;
00304 
00305 #ifdef NETSNMP_ENABLE_TESTING_CODE
00306     {
00307         int             i;
00308         DEBUGMSG(("sc_generate_keyed_hash",
00309                   "sc_generate_keyed_hash(): key=0x"));
00310         for (i = 0; i < keylen; i++)
00311             DEBUGMSG(("sc_generate_keyed_hash", "%02x", key[i] & 0xff));
00312         DEBUGMSG(("sc_generate_keyed_hash", " (%d)\n", keylen));
00313     }
00314 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00315 
00316     /*
00317      * Sanity check.
00318      */
00319     if (!authtype || !key || !message || !MAC || !maclen
00320         || (keylen <= 0) || (msglen <= 0) || (*maclen <= 0)
00321         || (authtypelen != USM_LENGTH_OID_TRANSFORM)) {
00322         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00323     }
00324 
00325     iproperlength = sc_get_properlength(authtype, authtypelen);
00326     if (iproperlength == SNMPERR_GENERR)
00327         return SNMPERR_GENERR;
00328     properlength = (size_t)iproperlength;
00329     if (keylen < properlength) {
00330         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00331     }
00332 #ifdef NETSNMP_USE_OPENSSL
00333     /*
00334      * Determine transform type.
00335      */
00336 #ifndef NETSNMP_DISABLE_MD5
00337     if (ISTRANSFORM(authtype, HMACMD5Auth))
00338         HMAC(EVP_md5(), key, keylen, message, msglen, buf, &buf_len);
00339     else
00340 #endif
00341         if (ISTRANSFORM(authtype, HMACSHA1Auth))
00342         HMAC(EVP_sha1(), key, keylen, message, msglen, buf, &buf_len);
00343     else {
00344         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00345     }
00346     if (buf_len != properlength) {
00347         QUITFUN(rval, sc_generate_keyed_hash_quit);
00348     }
00349     if (*maclen > buf_len)
00350         *maclen = buf_len;
00351     memcpy(MAC, buf, *maclen);
00352 
00353 #elif NETSNMP_USE_PKCS11                    /* NETSNMP_USE_PKCS11 */
00354 
00355 #ifndef NETSNMP_DISABLE_MD5
00356     if (ISTRANSFORM(authtype, HMACMD5Auth)) {
00357         if (pkcs_sign(CKM_MD5_HMAC,key, keylen, message,
00358                         msglen, buf, &buf_len) != SNMPERR_SUCCESS) {
00359             QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00360         }
00361     } else
00362 #endif
00363         if (ISTRANSFORM(authtype, HMACSHA1Auth)) {
00364         if (pkcs_sign(CKM_SHA_1_HMAC,key, keylen, message,
00365                         msglen, buf, &buf_len) != SNMPERR_SUCCESS) {
00366             QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00367         }
00368     } else {
00369         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00370     }
00371 
00372     if (buf_len != properlength) {
00373         QUITFUN(rval, sc_generate_keyed_hash_quit);
00374     }
00375     if (*maclen > buf_len)
00376         *maclen = buf_len;
00377     memcpy(MAC, buf, *maclen);
00378 
00379 #elif NETSNMP_USE_INTERNAL_CRYPTO
00380     if (*maclen > properlength)
00381         *maclen = properlength;
00382 #ifndef NETSNMP_DISABLE_MD5
00383     if (ISTRANSFORM(authtype, HMACMD5Auth))
00384         rval = MD5_hmac(message, msglen, MAC, *maclen, key, keylen);
00385     else
00386 #endif
00387          if (ISTRANSFORM(authtype, HMACSHA1Auth))
00388         rval = SHA1_hmac(message, msglen, MAC, *maclen, key, keylen);
00389     else {
00390         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00391     }
00392     if (rval != 0) {
00393         rval = SNMPERR_GENERR;
00394         goto sc_generate_keyed_hash_quit;
00395     }    
00396 #else                            /* NETSNMP_USE_INTERNAL_MD5 */
00397     if (*maclen > properlength)
00398         *maclen = properlength;
00399     if (MDsign(message, msglen, MAC, *maclen, key, keylen)) {
00400         rval = SNMPERR_GENERR;
00401         goto sc_generate_keyed_hash_quit;
00402     }
00403 #endif                          /* NETSNMP_USE_OPENSSL */
00404 
00405 #ifdef NETSNMP_ENABLE_TESTING_CODE
00406     {
00407         char           *s;
00408         int             len = binary_to_hex(MAC, *maclen, &s);
00409 
00410         DEBUGMSGTL(("scapi", "Full v3 message hash: %s\n", s));
00411         SNMP_ZERO(s, len);
00412         SNMP_FREE(s);
00413     }
00414 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00415 
00416   sc_generate_keyed_hash_quit:
00417     memset(buf, 0, SNMP_MAXBUF_SMALL);
00418     return rval;
00419 }                               /* end sc_generate_keyed_hash() */
00420 
00421 #else
00422                 _SCAPI_NOT_CONFIGURED
00423 #endif                          /* */
00424 /*
00425  * sc_hash(): a generic wrapper around whatever hashing package we are using.
00426  * 
00427  * IN:
00428  * hashtype    - oid pointer to a hash type
00429  * hashtypelen - length of oid pointer
00430  * buf         - u_char buffer to be hashed
00431  * buf_len     - integer length of buf data
00432  * MAC_len     - length of the passed MAC buffer size.
00433  * 
00434  * OUT:    
00435  * MAC         - pre-malloced space to store hash output.
00436  * MAC_len     - length of MAC output to the MAC buffer.
00437  * 
00438  * Returns:
00439  * SNMPERR_SUCCESS              Success.
00440  * SNMP_SC_GENERAL_FAILURE      Any error.
00441  */
00442 int
00443 sc_hash(const oid * hashtype, size_t hashtypelen, const u_char * buf,
00444         size_t buf_len, u_char * MAC, size_t * MAC_len)
00445 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00446 {
00447 #if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00448     int            rval = SNMPERR_SUCCESS;
00449 #endif
00450 #if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
00451     unsigned int   tmp_len;
00452 #endif
00453     int            ret;
00454 
00455 #ifdef NETSNMP_USE_OPENSSL
00456     const EVP_MD   *hashfn;
00457     EVP_MD_CTX     ctx, *cptr;
00458 #endif
00459 #ifdef NETSNMP_USE_INTERNAL_CRYPTO
00460     MD5_CTX        cmd5;
00461     SHA_CTX        csha1;
00462 #endif
00463     DEBUGTRACE;
00464 
00465     if (hashtype == NULL || buf == NULL || buf_len <= 0 ||
00466         MAC == NULL || MAC_len == NULL )
00467         return (SNMPERR_GENERR);
00468     ret = sc_get_properlength(hashtype, hashtypelen);
00469     if (( ret < 0 ) || (*MAC_len < (size_t)ret ))
00470         return (SNMPERR_GENERR);
00471 
00472 #ifdef NETSNMP_USE_OPENSSL
00473     /*
00474      * Determine transform type.
00475      */
00476 #ifndef NETSNMP_DISABLE_MD5
00477     if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
00478         hashfn = (const EVP_MD *) EVP_md5();
00479     } else
00480 #endif
00481         if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
00482         hashfn = (const EVP_MD *) EVP_sha1();
00483     } else {
00484         return (SNMPERR_GENERR);
00485     }
00486 
00488     memset(&ctx, 0, sizeof(ctx));
00489     cptr = &ctx;
00490 #if defined(OLD_DES)
00491     EVP_DigestInit(cptr, hashfn);
00492 #else /* !OLD_DES */
00493     /* this is needed if the runtime library is different than the compiled
00494        library since the openssl versions are very different. */
00495     if (SSLeay() < 0x907000) {
00496         /* the old version of the struct was bigger and thus more
00497            memory is needed. should be 152, but we use 256 for safety. */
00498         cptr = (EVP_MD_CTX *)malloc(256);
00499         EVP_DigestInit(cptr, hashfn);
00500     } else {
00501         EVP_MD_CTX_init(cptr);
00502         EVP_DigestInit(cptr, hashfn);
00503     }
00504 #endif
00505 
00507     EVP_DigestUpdate(cptr, buf, buf_len);
00508 
00510 #if defined(OLD_DES)
00511     EVP_DigestFinal(cptr, MAC, &tmp_len);
00512     *MAC_len = tmp_len;
00513 #else /* !OLD_DES */
00514     if (SSLeay() < 0x907000) {
00515         EVP_DigestFinal(cptr, MAC, &tmp_len);
00516         *MAC_len = tmp_len;
00517         free(cptr);
00518     } else {
00519         EVP_DigestFinal_ex(cptr, MAC, &tmp_len);
00520         *MAC_len = tmp_len;
00521         EVP_MD_CTX_cleanup(cptr);
00522     }
00523 #endif                          /* OLD_DES */
00524     return (rval);
00525 
00526 #elif NETSNMP_USE_INTERNAL_CRYPTO
00527 #ifndef NETSNMP_DISABLE_MD5
00528     if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
00529         if (*MAC_len < MD5_DIGEST_LENGTH)
00530             return (SNMPERR_GENERR);      /* the buffer isn't big enough */
00531         MD5_Init(&cmd5);
00532         MD5_Update(&cmd5, buf, buf_len);
00533         MD5_Final(MAC, &cmd5);
00534         *MAC_len = MD5_DIGEST_LENGTH;
00535     } else 
00536 #endif
00537     if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
00538         if (*MAC_len < SHA_DIGEST_LENGTH)
00539             return (SNMPERR_GENERR);      /* the buffer isn't big enough */
00540         SHA1_Init(&csha1);
00541         SHA1_Update(&csha1, buf, buf_len);
00542         SHA1_Final(MAC, &csha1);
00543         *MAC_len = SHA_DIGEST_LENGTH;
00544             
00545     } else {
00546         return (SNMPERR_GENERR);
00547     }
00548     return (rval);
00549 #elif NETSNMP_USE_PKCS11                  /* NETSNMP_USE_PKCS11 */
00550 
00551 #ifndef NETSNMP_DISABLE_MD5
00552     if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
00553         rval = pkcs_digest(CKM_MD5, buf, buf_len, MAC, &tmp_len);
00554         *MAC_len = tmp_len;
00555     } else
00556 #endif
00557         if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
00558         rval = pkcs_digest(CKM_SHA_1, buf, buf_len, MAC, &tmp_len);
00559         *MAC_len = tmp_len;
00560     } else {
00561         return (SNMPERR_GENERR);
00562     }
00563 
00564      return (rval);
00565 
00566 #else                           /* NETSNMP_USE_INTERNAL_MD5 */
00567 
00568     if (MDchecksum(buf, buf_len, MAC, *MAC_len)) {
00569         return SNMPERR_GENERR;
00570     }
00571     if (*MAC_len > 16)
00572         *MAC_len = 16;
00573     return SNMPERR_SUCCESS;
00574 
00575 #endif                          /* NETSNMP_USE_OPENSSL */
00576 }
00577 #else                           /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */
00578 _SCAPI_NOT_CONFIGURED
00579 #endif                          /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */
00580 /*******************************************************************-o-******
00581  * sc_check_keyed_hash
00582  *
00583  * Parameters:
00584  *       authtype       Transform type of authentication hash.
00585  *      *key            Key bits in a string of bytes.
00586  *       keylen         Length of key in bytes.
00587  *      *message        Message for which to check the hash.
00588  *       msglen         Length of message.
00589  *      *MAC            Given hash.
00590  *       maclen         Length of given hash; indicates truncation if it is
00591  *                              shorter than the normal size of output for
00592  *                              given hash transform.
00593  * Returns:
00594  *      SNMPERR_SUCCESS         Success.
00595  *      SNMP_SC_GENERAL_FAILURE Any error
00596  *
00597  *
00598  * Check the hash given in MAC against the hash of message.  If the length
00599  * of MAC is less than the length of the transform hash output, only maclen
00600  * bytes are compared.  The length of MAC cannot be greater than the
00601  * length of the hash transform output.
00602  */
00603 int
00604 sc_check_keyed_hash(const oid * authtype, size_t authtypelen,
00605                     const u_char * key, u_int keylen,
00606                     const u_char * message, u_int msglen,
00607                     const u_char * MAC, u_int maclen)
00608 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00609 {
00610     int             rval = SNMPERR_SUCCESS;
00611     size_t          buf_len = SNMP_MAXBUF_SMALL;
00612 
00613     u_char          buf[SNMP_MAXBUF_SMALL];
00614 
00615     DEBUGTRACE;
00616 
00617 #ifdef NETSNMP_ENABLE_TESTING_CODE
00618     {
00619         int             i;
00620         DEBUGMSG(("scapi", "sc_check_keyed_hash():    key=0x"));
00621         for (i = 0; i < keylen; i++)
00622             DEBUGMSG(("scapi", "%02x", key[i] & 0xff));
00623         DEBUGMSG(("scapi", " (%d)\n", keylen));
00624     }
00625 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00626 
00627     /*
00628      * Sanity check.
00629      */
00630     if (!authtype || !key || !message || !MAC
00631         || (keylen <= 0) || (msglen <= 0) || (maclen <= 0)
00632         || (authtypelen != USM_LENGTH_OID_TRANSFORM)) {
00633         QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
00634     }
00635 
00636 
00637     if (maclen != USM_MD5_AND_SHA_AUTH_LEN) {
00638         QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
00639     }
00640     
00641     /*
00642      * Generate a full hash of the message, then compare
00643      * the result with the given MAC which may shorter than
00644      * the full hash length.
00645      */
00646     rval = sc_generate_keyed_hash(authtype, authtypelen,
00647                                   key, keylen,
00648                                   message, msglen, buf, &buf_len);
00649     QUITFUN(rval, sc_check_keyed_hash_quit);
00650 
00651     if (maclen > msglen) {
00652         QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
00653 
00654     } else if (memcmp(buf, MAC, maclen) != 0) {
00655         QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
00656     }
00657 
00658 
00659   sc_check_keyed_hash_quit:
00660     memset(buf, 0, SNMP_MAXBUF_SMALL);
00661 
00662     return rval;
00663 
00664 }                               /* end sc_check_keyed_hash() */
00665 
00666 #else
00667 _SCAPI_NOT_CONFIGURED
00668 #endif                          /* NETSNMP_USE_INTERNAL_MD5 */
00669 /*******************************************************************-o-******
00670  * sc_encrypt
00671  *
00672  * Parameters:
00673  *       privtype       Type of privacy cryptographic transform.
00674  *      *key            Key bits for crypting.
00675  *       keylen         Length of key (buffer) in bytes.
00676  *      *iv             IV bits for crypting.
00677  *       ivlen          Length of iv (buffer) in bytes.
00678  *      *plaintext      Plaintext to crypt.
00679  *       ptlen          Length of plaintext.
00680  *      *ciphertext     Ciphertext to crypt.
00681  *      *ctlen          Length of ciphertext.
00682  *      
00683  * Returns:
00684  *      SNMPERR_SUCCESS                 Success.
00685  *      SNMPERR_SC_NOT_CONFIGURED       Encryption is not supported.
00686  *      SNMPERR_SC_GENERAL_FAILURE      Any other error
00687  *
00688  *
00689  * Encrypt plaintext into ciphertext using key and iv.
00690  *
00691  * ctlen contains actual number of crypted bytes in ciphertext upon
00692  * successful return.
00693  */
00694 int
00695 sc_encrypt(const oid * privtype, size_t privtypelen,
00696            u_char * key, u_int keylen,
00697            u_char * iv, u_int ivlen,
00698            const u_char * plaintext, u_int ptlen,
00699            u_char * ciphertext, size_t * ctlen)
00700 #if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00701 {
00702     int             rval = SNMPERR_SUCCESS;
00703     u_int           properlength = 0, properlength_iv = 0;
00704     u_char          pad_block[128];      /* bigger than anything I need */
00705     u_char          my_iv[128];  /* ditto */
00706     int             pad, plast, pad_size = 0;
00707     int             have_trans;
00708 #ifndef NETSNMP_DISABLE_DES
00709 #ifdef OLD_DES
00710     DES_key_schedule key_sch;
00711 #else
00712     DES_key_schedule key_sched_store;
00713     DES_key_schedule *key_sch = &key_sched_store;
00714 #endif
00715     DES_cblock       key_struct;
00716 #endif
00717 #ifdef HAVE_AES
00718     AES_KEY aes_key;
00719     int new_ivlen = 0;
00720 #endif
00721 
00722     DEBUGTRACE;
00723 
00724     /*
00725      * Sanity check.
00726      */
00727 #if     !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
00728     snmp_log(LOG_ERR, "Encryption support not enabled.\n");
00729     return SNMPERR_SC_NOT_CONFIGURED;
00730 #endif
00731 
00732     if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
00733         || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0)
00734         || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
00735         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00736     } else if (ptlen > *ctlen) {
00737         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00738     }
00739 #ifdef NETSNMP_ENABLE_TESTING_CODE
00740     {
00741         size_t          buf_len = 128, out_len = 0;
00742         u_char         *buf = (u_char *) malloc(buf_len);
00743 
00744         if (buf != NULL) {
00745             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
00746                                          iv, ivlen)) {
00747                 DEBUGMSGTL(("scapi", "encrypt: IV: %s/", buf));
00748             } else {
00749                 DEBUGMSGTL(("scapi", "encrypt: IV: %s [TRUNCATED]/", buf));
00750             }
00751             out_len = 0;
00752             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
00753                                          key, keylen)) {
00754                 DEBUGMSG(("scapi", "%s\n", buf));
00755             } else {
00756                 DEBUGMSG(("scapi", "%s [TRUNCATED]\n", buf));
00757             }
00758             out_len = 0;
00759             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
00760                                          plaintext, 16)) {
00761                 DEBUGMSGTL(("scapi", "encrypt: string: %s\n", buf));
00762             } else {
00763                 DEBUGMSGTL(("scapi", "encrypt: string: %s [TRUNCATED]\n",
00764                             buf));
00765             }
00766             free(buf);
00767         } else {
00768             DEBUGMSGTL(("scapi",
00769                         "encrypt: malloc fail for debug output\n"));
00770         }
00771     }
00772 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00773 
00774 
00775     /*
00776      * Determine privacy transform.
00777      */
00778     have_trans = 0;
00779 #ifndef NETSNMP_DISABLE_DES
00780     if (ISTRANSFORM(privtype, DESPriv)) {
00781         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
00782         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
00783         pad_size = properlength;
00784         have_trans = 1;
00785     }
00786 #endif
00787 #ifdef HAVE_AES
00788     if (ISTRANSFORM(privtype, AESPriv)) {
00789         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
00790         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV);
00791         have_trans = 1;
00792     }
00793 #endif
00794     if (!have_trans) {
00795         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00796     }
00797 
00798     if ((keylen < properlength) || (ivlen < properlength_iv)) {
00799         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00800     }
00801 
00802     memset(my_iv, 0, sizeof(my_iv));
00803 
00804 #ifndef NETSNMP_DISABLE_DES
00805     if (ISTRANSFORM(privtype, DESPriv)) {
00806 
00807         /*
00808          * now calculate the padding needed 
00809          */
00810         pad = pad_size - (ptlen % pad_size);
00811         plast = (int) ptlen - (pad_size - pad);
00812         if (pad == pad_size)
00813             pad = 0;
00814         if (ptlen + pad > *ctlen) {
00815             QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);    /* not enough space */
00816         }
00817         if (pad > 0) {              /* copy data into pad block if needed */
00818             memcpy(pad_block, plaintext + plast, pad_size - pad);
00819             memset(&pad_block[pad_size - pad], pad, pad);   /* filling in padblock */
00820         }
00821 
00822         memcpy(key_struct, key, sizeof(key_struct));
00823         (void) DES_key_sched(&key_struct, key_sch);
00824 
00825         memcpy(my_iv, iv, ivlen);
00826         /*
00827          * encrypt the data 
00828          */
00829         DES_ncbc_encrypt(plaintext, ciphertext, plast, key_sch,
00830                          (DES_cblock *) my_iv, DES_ENCRYPT);
00831         if (pad > 0) {
00832             /*
00833              * then encrypt the pad block 
00834              */
00835             DES_ncbc_encrypt(pad_block, ciphertext + plast, pad_size,
00836                              key_sch, (DES_cblock *) my_iv, DES_ENCRYPT);
00837             *ctlen = plast + pad_size;
00838         } else {
00839             *ctlen = plast;
00840         }
00841     }
00842 #endif
00843 #ifdef HAVE_AES
00844     if (ISTRANSFORM(privtype, AESPriv)) {
00845         (void) AES_set_encrypt_key(key, properlength*8, &aes_key);
00846 
00847         memcpy(my_iv, iv, ivlen);
00848         /*
00849          * encrypt the data 
00850          */
00851         AES_cfb128_encrypt(plaintext, ciphertext, ptlen,
00852                            &aes_key, my_iv, &new_ivlen, AES_ENCRYPT);
00853         *ctlen = ptlen;
00854     }
00855 #endif
00856   sc_encrypt_quit:
00857     /*
00858      * clear memory just in case 
00859      */
00860     memset(my_iv, 0, sizeof(my_iv));
00861     memset(pad_block, 0, sizeof(pad_block));
00862 #ifndef NETSNMP_DISABLE_DES
00863     memset(key_struct, 0, sizeof(key_struct));
00864 #ifdef OLD_DES
00865     memset(&key_sch, 0, sizeof(key_sch));
00866 #else
00867     memset(&key_sched_store, 0, sizeof(key_sched_store));
00868 #endif
00869 #endif
00870 #ifdef HAVE_AES
00871     memset(&aes_key,0,sizeof(aes_key));
00872 #endif
00873     return rval;
00874 
00875 }                               /* end sc_encrypt() */
00876 #elif defined(NETSNMP_USE_PKCS11)
00877 {
00878     int             rval = SNMPERR_SUCCESS;
00879     u_int           properlength, properlength_iv;
00880     u_char          pkcs_des_key[8];
00881 
00882     DEBUGTRACE;
00883 
00884     /*
00885      * Sanity check.
00886      */
00887 #if     !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
00888     snmp_log(LOG_ERR, "Encryption support not enabled.\n");
00889     return SNMPERR_SC_NOT_CONFIGURED;
00890 #endif
00891 
00892     if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
00893         || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0)
00894         || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
00895         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00896     } else if (ptlen > *ctlen) {
00897         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00898     }
00899 
00900     /*
00901      * Determine privacy transform.
00902      */
00903     if (ISTRANSFORM(privtype, DESPriv)) {
00904         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
00905         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
00906     } else {
00907         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00908     }
00909 
00910     if ((keylen < properlength) || (ivlen < properlength_iv)) {
00911         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00912     }
00913 
00914     if (ISTRANSFORM(privtype, DESPriv)) {
00915         memset(pkcs_des_key, 0, sizeof(pkcs_des_key));
00916         memcpy(pkcs_des_key, key, sizeof(pkcs_des_key));
00917         rval = pkcs_encrpyt(CKM_DES_CBC, pkcs_des_key,
00918                 sizeof(pkcs_des_key), iv, ivlen, plaintext, ptlen,
00919                 ciphertext, ctlen);
00920     }
00921 
00922   sc_encrypt_quit:
00923     return rval;
00924 }
00925 #else
00926 {
00927 #       if NETSNMP_USE_INTERNAL_MD5
00928     {
00929         snmp_log(LOG_ERR, "Encryption support not enabled.\n");
00930         DEBUGMSGTL(("scapi", "Encrypt function not defined.\n"));
00931         return SNMPERR_SC_GENERAL_FAILURE;
00932     }
00933 
00934 #       else
00935     _SCAPI_NOT_CONFIGURED
00936 #       endif                   /* NETSNMP_USE_INTERNAL_MD5 */
00937 }
00938 #endif                          /* */
00939 
00940 
00941 
00942 /*******************************************************************-o-******
00943  * sc_decrypt
00944  *
00945  * Parameters:
00946  *       privtype
00947  *      *key
00948  *       keylen
00949  *      *iv
00950  *       ivlen
00951  *      *ciphertext
00952  *       ctlen
00953  *      *plaintext
00954  *      *ptlen
00955  *      
00956  * Returns:
00957  *      SNMPERR_SUCCESS                 Success.
00958  *      SNMPERR_SC_NOT_CONFIGURED       Encryption is not supported.
00959  *      SNMPERR_SC_GENERAL_FAILURE      Any other error
00960  *
00961  *
00962  * Decrypt ciphertext into plaintext using key and iv.
00963  *
00964  * ptlen contains actual number of plaintext bytes in plaintext upon
00965  * successful return.
00966  */
00967 int
00968 sc_decrypt(const oid * privtype, size_t privtypelen,
00969            u_char * key, u_int keylen,
00970            u_char * iv, u_int ivlen,
00971            u_char * ciphertext, u_int ctlen,
00972            u_char * plaintext, size_t * ptlen)
00973 #if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
00974 {
00975 
00976     int             rval = SNMPERR_SUCCESS;
00977     u_char          my_iv[128];
00978 #ifndef NETSNMP_DISABLE_DES
00979 #ifdef OLD_DES
00980     DES_key_schedule key_sch;
00981 #else
00982     DES_key_schedule key_sched_store;
00983     DES_key_schedule *key_sch = &key_sched_store;
00984 #endif
00985     DES_cblock      key_struct;
00986 #endif
00987     u_int           properlength = 0, properlength_iv = 0;
00988     int             have_transform;
00989 #ifdef HAVE_AES
00990     int new_ivlen = 0;
00991     AES_KEY aes_key;
00992 #endif
00993 
00994     DEBUGTRACE;
00995 
00996     if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
00997         || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)
00998         || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
00999         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01000     }
01001 #ifdef NETSNMP_ENABLE_TESTING_CODE
01002     {
01003         size_t          buf_len = 128, out_len = 0;
01004         u_char         *buf = (u_char *) malloc(buf_len);
01005 
01006         if (buf != NULL) {
01007             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
01008                                          iv, ivlen)) {
01009                 DEBUGMSGTL(("scapi", "decrypt: IV: %s/", buf));
01010             } else {
01011                 DEBUGMSGTL(("scapi", "decrypt: IV: %s [TRUNCATED]/", buf));
01012             }
01013             out_len = 0;
01014             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
01015                                          key, keylen)) {
01016                 DEBUGMSG(("scapi", "%s\n", buf));
01017             } else {
01018                 DEBUGMSG(("scapi", "%s\n", buf));
01019             }
01020             free(buf);
01021         } else {
01022             DEBUGMSGTL(("scapi",
01023                         "decrypt: malloc fail for debug output\n"));
01024         }
01025     }
01026 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
01027 
01028     /*
01029      * Determine privacy transform.
01030      */
01031     have_transform = 0;
01032 #ifndef NETSNMP_DISABLE_DES
01033     if (ISTRANSFORM(privtype, DESPriv)) {
01034         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
01035         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
01036         have_transform = 1;
01037     }
01038 #endif
01039 #ifdef HAVE_AES
01040     if (ISTRANSFORM(privtype, AESPriv)) {
01041         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
01042         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV);
01043         have_transform = 1;
01044     }
01045 #endif
01046     if (!have_transform) {
01047         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01048     }
01049 
01050     if ((keylen < properlength) || (ivlen < properlength_iv)) {
01051         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01052     }
01053 
01054     memset(my_iv, 0, sizeof(my_iv));
01055 #ifndef NETSNMP_DISABLE_DES
01056     if (ISTRANSFORM(privtype, DESPriv)) {
01057         memcpy(key_struct, key, sizeof(key_struct));
01058         (void) DES_key_sched(&key_struct, key_sch);
01059 
01060         memcpy(my_iv, iv, ivlen);
01061         DES_cbc_encrypt(ciphertext, plaintext, ctlen, key_sch,
01062                         (DES_cblock *) my_iv, DES_DECRYPT);
01063         *ptlen = ctlen;
01064     }
01065 #endif
01066 #ifdef HAVE_AES
01067     if (ISTRANSFORM(privtype, AESPriv)) {
01068         (void) AES_set_encrypt_key(key, properlength*8, &aes_key);
01069 
01070         memcpy(my_iv, iv, ivlen);
01071         /*
01072          * encrypt the data 
01073          */
01074         AES_cfb128_encrypt(ciphertext, plaintext, ctlen,
01075                            &aes_key, my_iv, &new_ivlen, AES_DECRYPT);
01076         *ptlen = ctlen;
01077     }
01078 #endif
01079 
01080     /*
01081      * exit cond 
01082      */
01083   sc_decrypt_quit:
01084 #ifndef NETSNMP_DISABLE_DES
01085 #ifdef OLD_DES
01086     memset(&key_sch, 0, sizeof(key_sch));
01087 #else
01088     memset(&key_sched_store, 0, sizeof(key_sched_store));
01089 #endif
01090     memset(key_struct, 0, sizeof(key_struct));
01091 #endif
01092     memset(my_iv, 0, sizeof(my_iv));
01093     return rval;
01094 }                               /* USE OPEN_SSL */
01095 #elif NETSNMP_USE_PKCS11                  /* USE PKCS */
01096 {
01097     int             rval = SNMPERR_SUCCESS;
01098     u_int           properlength, properlength_iv;
01099     u_char          pkcs_des_key[8];
01100 
01101     DEBUGTRACE;
01102 
01103     if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
01104         || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)
01105         || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
01106         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01107     }
01108 
01109     /*
01110      * Determine privacy transform.
01111      */
01112     if (ISTRANSFORM(privtype, DESPriv)) {
01113         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
01114         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
01115     } else {
01116         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01117     }
01118 
01119     if ((keylen < properlength) || (ivlen < properlength_iv)) {
01120         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01121     }
01122 
01123     if (ISTRANSFORM(privtype, DESPriv)) {
01124         memset(pkcs_des_key, 0, sizeof(pkcs_des_key));
01125         memcpy(pkcs_des_key, key, sizeof(pkcs_des_key));
01126         rval = pkcs_decrpyt(CKM_DES_CBC, pkcs_des_key, 
01127                 sizeof(pkcs_des_key), iv, ivlen, ciphertext,
01128                 ctlen, plaintext, ptlen);
01129         *ptlen = ctlen;
01130     }
01131 
01132   sc_decrypt_quit:
01133     return rval;
01134 }                               /* USE PKCS */
01135 #else
01136 {
01137 #if     !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
01138     snmp_log(LOG_ERR, "Encryption support not enabled.\n");
01139     return SNMPERR_SC_NOT_CONFIGURED;
01140 #else
01141 #       if NETSNMP_USE_INTERNAL_MD5
01142     {
01143         DEBUGMSGTL(("scapi", "Decryption function not defined.\n"));
01144         return SNMPERR_SC_GENERAL_FAILURE;
01145     }
01146 
01147 #       else
01148     _SCAPI_NOT_CONFIGURED
01149 #       endif                   /* NETSNMP_USE_INTERNAL_MD5 */
01150 #endif                          /*  */
01151 }
01152 #endif                          /* NETSNMP_USE_OPENSSL */
01153 
01154 #ifdef NETSNMP_USE_INTERNAL_CRYPTO
01155 
01156 /* These functions are basically copies of the MDSign() routine in
01157    md5.c modified to be used with the OpenSSL hashing functions.  The
01158    copyright below is from the md5.c file that these functions were
01159    taken from: */
01160 
01161 /*
01162  * ** **************************************************************************
01163  * ** md5.c -- Implementation of MD5 Message Digest Algorithm                 **
01164  * ** Updated: 2/16/90 by Ronald L. Rivest                                    **
01165  * ** (C) 1990 RSA Data Security, Inc.                                        **
01166  * ** **************************************************************************
01167  */
01168 
01169 /*
01170  * MD5_hmac(data, len, MD5): do a checksum on an arbirtrary amount
01171  * of data, and prepended with a secret in the standard fashion 
01172  */
01173 static int
01174 MD5_hmac(u_char * data, size_t len, u_char * mac, size_t maclen,
01175          u_char * secret, size_t secretlen)
01176 {
01177 #define MD5_HASHKEYLEN 64
01178 #define MD5_SECRETKEYLEN 16
01179 
01180     MD5_CTX         cmd5;
01181     u_char          K1[MD5_HASHKEYLEN];
01182     u_char          K2[MD5_HASHKEYLEN];
01183     u_char          extendedAuthKey[MD5_HASHKEYLEN];
01184     u_char          buf[MD5_HASHKEYLEN];
01185     size_t          i;
01186     u_char         *cp, *newdata = NULL;
01187     int             rc = 0;
01188 
01189     /*
01190      * memset(K1,0,MD5_HASHKEYLEN);
01191      * memset(K2,0,MD5_HASHKEYLEN);
01192      * memset(buf,0,MD5_HASHKEYLEN);
01193      * memset(extendedAuthKey,0,MD5_HASHKEYLEN);
01194      */
01195 
01196     if (secretlen != MD5_SECRETKEYLEN || secret == NULL ||
01197         mac == NULL || data == NULL ||
01198         len <= 0 || maclen <= 0) {
01199         /*
01200          * DEBUGMSGTL(("md5","MD5 signing not properly initialized")); 
01201          */
01202         return -1;
01203     }
01204 
01205     memset(extendedAuthKey, 0, MD5_HASHKEYLEN);
01206     memcpy(extendedAuthKey, secret, secretlen);
01207     for (i = 0; i < MD5_HASHKEYLEN; i++) {
01208         K1[i] = extendedAuthKey[i] ^ 0x36;
01209         K2[i] = extendedAuthKey[i] ^ 0x5c;
01210     }
01211 
01212     MD5_Init(&cmd5);
01213     rc = !MD5_Update(&cmd5, K1, MD5_HASHKEYLEN);
01214     if (rc)
01215         goto update_end;
01216 
01217     i = len;
01218     if (((uintptr_t) data) % sizeof(long) != 0) {
01219         /*
01220          * this relies on the ability to use integer math and thus we
01221          * must rely on data that aligns on 32-bit-word-boundries 
01222          */
01223         memdup(&newdata, data, len);
01224         cp = newdata;
01225     } else {
01226         cp = data;
01227     }
01228 
01229     while (i >= 64) {
01230         rc = !MD5_Update(&cmd5, cp, 64);
01231         if (rc)
01232             goto update_end;
01233         cp += 64;
01234         i -= 64;
01235     }
01236 
01237     rc = !MD5_Update(&cmd5, cp, i);
01238     if (rc)
01239         goto update_end;
01240 
01241     memset(buf, 0, MD5_HASHKEYLEN);
01242     MD5_Final(buf, &cmd5);
01243 
01244     MD5_Init(&cmd5);
01245     rc = !MD5_Update(&cmd5, K2, MD5_HASHKEYLEN);
01246     if (rc)
01247         goto update_end;
01248     rc = !MD5_Update(&cmd5, buf, MD5_SECRETKEYLEN);
01249     if (rc)
01250         goto update_end;
01251 
01252     /*
01253      * copy the sign checksum to the outgoing pointer 
01254      */
01255     MD5_Final(buf, &cmd5);
01256     memcpy(mac, buf, maclen);
01257 
01258   update_end:
01259     memset(buf, 0, MD5_HASHKEYLEN);
01260     memset(K1, 0, MD5_HASHKEYLEN);
01261     memset(K2, 0, MD5_HASHKEYLEN);
01262     memset(extendedAuthKey, 0, MD5_HASHKEYLEN);
01263     memset(&cmd5, 0, sizeof(cmd5));
01264 
01265     if (newdata)
01266         free(newdata);
01267     return rc;
01268 }
01269 
01270 static int
01271 SHA1_hmac(u_char * data, size_t len, u_char * mac, size_t maclen,
01272          u_char * secret, size_t secretlen)
01273 {
01274 #define SHA1_HASHKEYLEN   64
01275 #define SHA1_SECRETKEYLEN 20
01276 
01277     SHA_CTX         csha1;
01278     u_char          K1[SHA1_HASHKEYLEN];
01279     u_char          K2[SHA1_HASHKEYLEN];
01280     u_char          extendedAuthKey[SHA1_HASHKEYLEN];
01281     u_char          buf[SHA1_HASHKEYLEN];
01282     size_t          i;
01283     u_char         *cp, *newdata = NULL;
01284     int             rc = 0;
01285 
01286     /*
01287      * memset(K1,0,SHA1_HASHKEYLEN);
01288      * memset(K2,0,SHA1_HASHKEYLEN);
01289      * memset(buf,0,SHA1_HASHKEYLEN);
01290      * memset(extendedAuthKey,0,SHA1_HASHKEYLEN);
01291      */
01292 
01293     if (secretlen != SHA1_SECRETKEYLEN || secret == NULL ||
01294         mac == NULL || data == NULL ||
01295         len <= 0 || maclen <= 0) {
01296         /*
01297          * DEBUGMSGTL(("sha1","SHA1 signing not properly initialized")); 
01298          */
01299         return -1;
01300     }
01301 
01302     memset(extendedAuthKey, 0, SHA1_HASHKEYLEN);
01303     memcpy(extendedAuthKey, secret, secretlen);
01304     for (i = 0; i < SHA1_HASHKEYLEN; i++) {
01305         K1[i] = extendedAuthKey[i] ^ 0x36;
01306         K2[i] = extendedAuthKey[i] ^ 0x5c;
01307     }
01308 
01309     SHA1_Init(&csha1);
01310     rc = !SHA1_Update(&csha1, K1, SHA1_HASHKEYLEN);
01311     if (rc)
01312         goto update_end;
01313 
01314     i = len;
01315     if (((uintptr_t) data) % sizeof(long) != 0) {
01316         /*
01317          * this relies on the ability to use integer math and thus we
01318          * must rely on data that aligns on 32-bit-word-boundries 
01319          */
01320         memdup(&newdata, data, len);
01321         cp = newdata;
01322     } else {
01323         cp = data;
01324     }
01325 
01326     while (i >= 64) {
01327         rc = !SHA1_Update(&csha1, cp, 64);
01328         if (rc)
01329             goto update_end;
01330         cp += 64;
01331         i -= 64;
01332     }
01333 
01334     rc = !SHA1_Update(&csha1, cp, i);
01335     if (rc)
01336         goto update_end;
01337 
01338     memset(buf, 0, SHA1_HASHKEYLEN);
01339     SHA1_Final(buf, &csha1);
01340 
01341     SHA1_Init(&csha1);
01342     rc = !SHA1_Update(&csha1, K2, SHA1_HASHKEYLEN);
01343     if (rc)
01344         goto update_end;
01345     rc = !SHA1_Update(&csha1, buf, SHA1_SECRETKEYLEN);
01346     if (rc)
01347         goto update_end;
01348 
01349     /*
01350      * copy the sign checksum to the outgoing pointer 
01351      */
01352     SHA1_Final(buf, &csha1);
01353     memcpy(mac, buf, maclen);
01354 
01355   update_end:
01356     memset(buf, 0, SHA1_HASHKEYLEN);
01357     memset(K1, 0, SHA1_HASHKEYLEN);
01358     memset(K2, 0, SHA1_HASHKEYLEN);
01359     memset(extendedAuthKey, 0, SHA1_HASHKEYLEN);
01360     memset(&csha1, 0, sizeof(csha1));
01361 
01362     if (newdata)
01363         free(newdata);
01364     return rc;
01365 }
01366 #endif /* NETSNMP_USE_INTERNAL_CRYPTO */
01367 #endif /*  NETSNMP_FEATURE_REMOVE_USM_SCAPI  */