net-snmp  5.4.1
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 
00019 #include <sys/types.h>
00020 #if HAVE_WINSOCK_H
00021 #include <winsock.h>
00022 #endif
00023 #ifdef HAVE_STDLIB_H
00024 #include <stdlib.h>
00025 #endif
00026 #if HAVE_STRING_H
00027 #include <string.h>
00028 #else
00029 #include <strings.h>
00030 #endif
00031 #if TIME_WITH_SYS_TIME
00032 # ifdef WIN32
00033 #  include <sys/timeb.h>
00034 # else
00035 #  include <sys/time.h>
00036 # endif
00037 # include <time.h>
00038 #else
00039 # if HAVE_SYS_TIME_H
00040 #  include <sys/time.h>
00041 # else
00042 #  include <time.h>
00043 # endif
00044 #endif
00045 #ifdef HAVE_NETINET_IN_H
00046 #include <netinet/in.h>
00047 #endif
00048 
00049 #if HAVE_DMALLOC_H
00050 #include <dmalloc.h>
00051 #endif
00052 
00053 #include <net-snmp/types.h>
00054 #include <net-snmp/output_api.h>
00055 #include <net-snmp/utilities.h>
00056 
00057 #ifdef NETSNMP_USE_INTERNAL_MD5
00058 #include <net-snmp/library/md5.h>
00059 #endif
00060 #include <net-snmp/library/snmp_api.h>
00061 #include <net-snmp/library/callback.h>
00062 #include <net-snmp/library/snmp_secmod.h>
00063 #include <net-snmp/library/snmpusm.h>
00064 #include <net-snmp/library/keytools.h>
00065 #include <net-snmp/library/scapi.h>
00066 #include <net-snmp/library/mib.h>
00067 #include <net-snmp/library/transform_oids.h>
00068 
00069 #ifdef NETSNMP_USE_OPENSSL
00070 #include <openssl/hmac.h>
00071 #include <openssl/evp.h>
00072 #include <openssl/rand.h>
00073 #include <openssl/des.h>
00074 #ifdef HAVE_AES
00075 #include <openssl/aes.h>
00076 #endif
00077 
00078 #ifndef NETSNMP_DISABLE_DES
00079 #ifdef STRUCT_DES_KS_STRUCT_HAS_WEAK_KEY
00080 /* these are older names for newer structures that exist in openssl .9.7 */
00081 #define DES_key_schedule    des_key_schedule 
00082 #define DES_cblock          des_cblock 
00083 #define DES_key_sched       des_key_sched 
00084 #define DES_ncbc_encrypt    des_ncbc_encrypt
00085 #define DES_cbc_encrypt    des_cbc_encrypt
00086 #define OLD_DES
00087 #endif
00088 #endif
00089 
00090 #endif /* HAVE_OPENSSL */
00091 
00092 #ifdef NETSNMP_USE_PKCS11
00093 #include <security/cryptoki.h>
00094 #endif
00095 
00096 #ifdef QUITFUN
00097 #undef QUITFUN
00098 #define QUITFUN(e, l)                                   \
00099         if (e != SNMPERR_SUCCESS) {                     \
00100                 rval = SNMPERR_SC_GENERAL_FAILURE;      \
00101                 goto l ;                                \
00102         }
00103 #endif
00104 
00105 
00106 /*
00107  * sc_get_properlength(oid *hashtype, u_int hashtype_len):
00108  * 
00109  * Given a hashing type ("hashtype" and its length hashtype_len), return
00110  * the length of the hash result.
00111  * 
00112  * Returns either the length or SNMPERR_GENERR for an unknown hashing type.
00113  */
00114 int
00115 sc_get_properlength(const oid * hashtype, u_int hashtype_len)
00116 {
00117     DEBUGTRACE;
00118     /*
00119      * Determine transform type hash length.
00120      */
00121 #ifndef NETSNMP_DISABLE_MD5
00122     if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
00123         return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
00124     } else
00125 #endif
00126         if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
00127         return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
00128     }
00129     return SNMPERR_GENERR;
00130 }
00131 
00132 int
00133 sc_get_proper_priv_length(const oid * privtype, u_int privtype_len)
00134 {
00135     int properlength = 0;
00136 #ifndef NETSNMP_DISABLE_DES
00137     if (ISTRANSFORM(privtype, DESPriv)) {
00138         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
00139     }
00140 #endif
00141 #ifdef HAVE_AES
00142     if (ISTRANSFORM(privtype, AESPriv)) {
00143         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
00144     }
00145 #endif
00146     return properlength;
00147 }
00148 
00149 
00150 /*******************************************************************-o-******
00151  * sc_init
00152  *
00153  * Returns:
00154  *      SNMPERR_SUCCESS                 Success.
00155  */
00156 int
00157 sc_init(void)
00158 {
00159     int             rval = SNMPERR_SUCCESS;
00160 
00161 #ifndef NETSNMP_USE_OPENSSL
00162 #ifdef NETSNMP_USE_INTERNAL_MD5
00163     struct timeval  tv;
00164 
00165     DEBUGTRACE;
00166 
00167     gettimeofday(&tv, (struct timezone *) 0);
00168 
00169     srandom(tv.tv_sec ^ tv.tv_usec);
00170 #elif NETSNMP_USE_PKCS11
00171     DEBUGTRACE;
00172     rval = pkcs_init();
00173 #else
00174     rval = SNMPERR_SC_NOT_CONFIGURED;
00175 #endif                           /* NETSNMP_USE_INTERNAL_MD5 */
00176     /*
00177      * XXX ogud: The only reason to do anything here with openssl is to 
00178      * * XXX ogud: seed random number generator 
00179      */
00180 #endif                          /* ifndef NETSNMP_USE_OPENSSL */
00181     return rval;
00182 }                               /* end sc_init() */
00183 
00184 /*******************************************************************-o-******
00185  * sc_random
00186  *
00187  * Parameters:
00188  *      *buf            Pre-allocated buffer.
00189  *      *buflen         Size of buffer.
00190  *      
00191  * Returns:
00192  *      SNMPERR_SUCCESS                 Success.
00193  */
00194 int
00195 sc_random(u_char * buf, size_t * buflen)
00196 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
00197 {
00198     int             rval = SNMPERR_SUCCESS;
00199 #ifdef NETSNMP_USE_INTERNAL_MD5
00200     int             i;
00201     int             rndval;
00202     u_char         *ucp = buf;
00203 #endif
00204 
00205     DEBUGTRACE;
00206 
00207 #ifdef NETSNMP_USE_OPENSSL
00208     RAND_bytes(buf, *buflen);   /* will never fail */
00209 #elif NETSNMP_USE_PKCS11                        /* NETSNMP_USE_PKCS11 */
00210     pkcs_random(buf, *buflen);
00211 #else                           /* NETSNMP_USE_INTERNAL_MD5 */
00212     /*
00213      * fill the buffer with random integers.  Note that random()
00214      * is defined in config.h and may not be truly the random()
00215      * system call if something better existed 
00216      */
00217     rval = *buflen - *buflen % sizeof(rndval);
00218     for (i = 0; i < rval; i += sizeof(rndval)) {
00219         rndval = random();
00220         memcpy(ucp, &rndval, sizeof(rndval));
00221         ucp += sizeof(rndval);
00222     }
00223 
00224     rndval = random();
00225     memcpy(ucp, &rndval, *buflen % sizeof(rndval));
00226 
00227     rval = SNMPERR_SUCCESS;
00228 #endif                          /* NETSNMP_USE_OPENSSL */
00229     return rval;
00230 
00231 }                               /* end sc_random() */
00232 
00233 #else
00234 _SCAPI_NOT_CONFIGURED
00235 #endif                          /*  */
00236 /*******************************************************************-o-******
00237  * sc_generate_keyed_hash
00238  *
00239  * Parameters:
00240  *       authtype       Type of authentication transform.
00241  *       authtypelen
00242  *      *key            Pointer to key (Kul) to use in keyed hash.
00243  *       keylen         Length of key in bytes.
00244  *      *message        Pointer to the message to hash.
00245  *       msglen         Length of the message.
00246  *      *MAC            Will be returned with allocated bytes containg hash.
00247  *      *maclen         Length of the hash buffer in bytes; also indicates
00248  *                              whether the MAC should be truncated.
00249  *      
00250  * Returns:
00251  *      SNMPERR_SUCCESS                 Success.
00252  *      SNMPERR_GENERR                  All errs
00253  *
00254  *
00255  * A hash of the first msglen bytes of message using a keyed hash defined
00256  * by authtype is created and stored in MAC.  MAC is ASSUMED to be a buffer
00257  * of at least maclen bytes.  If the length of the hash is greater than
00258  * maclen, it is truncated to fit the buffer.  If the length of the hash is
00259  * less than maclen, maclen set to the number of hash bytes generated.
00260  *
00261  * ASSUMED that the number of hash bits is a multiple of 8.
00262  */
00263 int
00264 sc_generate_keyed_hash(const oid * authtype, size_t authtypelen,
00265                        u_char * key, u_int keylen,
00266                        u_char * message, u_int msglen,
00267                        u_char * MAC, size_t * maclen)
00268 #if  defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
00269 {
00270     int             rval = SNMPERR_SUCCESS;
00271     int             properlength;
00272 
00273     u_char          buf[SNMP_MAXBUF_SMALL];
00274 #if  defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
00275     size_t             buf_len = sizeof(buf);
00276 #endif
00277 
00278     DEBUGTRACE;
00279 
00280 #ifdef NETSNMP_ENABLE_TESTING_CODE
00281     {
00282         int             i;
00283         DEBUGMSG(("sc_generate_keyed_hash",
00284                   "sc_generate_keyed_hash(): key=0x"));
00285         for (i = 0; i < keylen; i++)
00286             DEBUGMSG(("sc_generate_keyed_hash", "%02x", key[i] & 0xff));
00287         DEBUGMSG(("sc_generate_keyed_hash", " (%d)\n", keylen));
00288     }
00289 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00290 
00291     /*
00292      * Sanity check.
00293      */
00294     if (!authtype || !key || !message || !MAC || !maclen
00295         || (keylen <= 0) || (msglen <= 0) || (*maclen <= 0)
00296         || (authtypelen != USM_LENGTH_OID_TRANSFORM)) {
00297         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00298     }
00299 
00300     properlength = sc_get_properlength(authtype, authtypelen);
00301     if (properlength == SNMPERR_GENERR)
00302         return properlength;
00303 
00304     if (((int) keylen < properlength)) {
00305         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00306     }
00307 #ifdef NETSNMP_USE_OPENSSL
00308     /*
00309      * Determine transform type.
00310      */
00311 #ifndef NETSNMP_DISABLE_MD5
00312     if (ISTRANSFORM(authtype, HMACMD5Auth))
00313         HMAC(EVP_md5(), key, keylen, message, msglen, buf, &buf_len);
00314     else
00315 #endif
00316         if (ISTRANSFORM(authtype, HMACSHA1Auth))
00317         HMAC(EVP_sha1(), key, keylen, message, msglen, buf, &buf_len);
00318     else {
00319         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00320     }
00321     if ((int)buf_len != properlength) {
00322         QUITFUN(rval, sc_generate_keyed_hash_quit);
00323     }
00324     if ((int)*maclen > buf_len)
00325         *maclen = buf_len;
00326     memcpy(MAC, buf, *maclen);
00327 
00328 #elif NETSNMP_USE_PKCS11                    /* NETSNMP_USE_PKCS11 */
00329 
00330 #ifndef NETSNMP_DISABLE_MD5
00331     if (ISTRANSFORM(authtype, HMACMD5Auth)) {
00332         if (pkcs_sign(CKM_MD5_HMAC,key, keylen, message,
00333                         msglen, buf, &buf_len) != SNMPERR_SUCCESS) {
00334             QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00335         }
00336     } else
00337 #endif
00338         if (ISTRANSFORM(authtype, HMACSHA1Auth)) {
00339         if (pkcs_sign(CKM_SHA_1_HMAC,key, keylen, message,
00340                         msglen, buf, &buf_len) != SNMPERR_SUCCESS) {
00341             QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00342         }
00343     } else {
00344         QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
00345     }
00346 
00347     if (buf_len != properlength) {
00348         QUITFUN(rval, sc_generate_keyed_hash_quit);
00349     }
00350     if (*maclen > buf_len)
00351         *maclen = buf_len;
00352     memcpy(MAC, buf, *maclen);
00353 
00354 #else                            /* NETSNMP_USE_INTERNAL_MD5 */
00355     if ((int) *maclen > properlength)
00356         *maclen = properlength;
00357     if (MDsign(message, msglen, MAC, *maclen, key, keylen)) {
00358         rval = SNMPERR_GENERR;
00359         goto sc_generate_keyed_hash_quit;
00360     }
00361 #endif                          /* NETSNMP_USE_OPENSSL */
00362 
00363 #ifdef NETSNMP_ENABLE_TESTING_CODE
00364     {
00365         char           *s;
00366         int             len = binary_to_hex(MAC, *maclen, &s);
00367 
00368         DEBUGMSGTL(("scapi", "Full v3 message hash: %s\n", s));
00369         SNMP_ZERO(s, len);
00370         SNMP_FREE(s);
00371     }
00372 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00373 
00374   sc_generate_keyed_hash_quit:
00375     SNMP_ZERO(buf, SNMP_MAXBUF_SMALL);
00376     return rval;
00377 }                               /* end sc_generate_keyed_hash() */
00378 
00379 #else
00380                 _SCAPI_NOT_CONFIGURED
00381 #endif                          /* */
00382 /*
00383  * sc_hash(): a generic wrapper around whatever hashing package we are using.
00384  * 
00385  * IN:
00386  * hashtype    - oid pointer to a hash type
00387  * hashtypelen - length of oid pointer
00388  * buf         - u_char buffer to be hashed
00389  * buf_len     - integer length of buf data
00390  * MAC_len     - length of the passed MAC buffer size.
00391  * 
00392  * OUT:    
00393  * MAC         - pre-malloced space to store hash output.
00394  * MAC_len     - length of MAC output to the MAC buffer.
00395  * 
00396  * Returns:
00397  * SNMPERR_SUCCESS              Success.
00398  * SNMP_SC_GENERAL_FAILURE      Any error.
00399  */
00400 int
00401 sc_hash(const oid * hashtype, size_t hashtypelen, u_char * buf,
00402         size_t buf_len, u_char * MAC, size_t * MAC_len)
00403 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
00404 {
00405 #if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
00406     int            rval = SNMPERR_SUCCESS;
00407 #endif
00408     int            ret;
00409     unsigned int   tmp_len;
00410 
00411 #ifdef NETSNMP_USE_OPENSSL
00412     const EVP_MD   *hashfn;
00413     EVP_MD_CTX     ctx, *cptr;
00414 #endif
00415 
00416     DEBUGTRACE;
00417 
00418     if (hashtype == NULL || hashtypelen < 0 || buf == NULL ||
00419         buf_len <= 0 || MAC == NULL || MAC_len == NULL )
00420         return (SNMPERR_GENERR);
00421     ret = sc_get_properlength(hashtype, hashtypelen);
00422     if (( ret < 0 ) || (*MAC_len < ret ))
00423         return (SNMPERR_GENERR);
00424 
00425 #ifdef NETSNMP_USE_OPENSSL
00426     /*
00427      * Determine transform type.
00428      */
00429 #ifndef NETSNMP_DISABLE_MD5
00430     if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
00431         hashfn = (const EVP_MD *) EVP_md5();
00432     } else
00433 #endif
00434         if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
00435         hashfn = (const EVP_MD *) EVP_sha1();
00436     } else {
00437         return (SNMPERR_GENERR);
00438     }
00439 
00441     memset(&ctx, 0, sizeof(ctx));
00442     cptr = &ctx;
00443 #if defined(OLD_DES)
00444     EVP_DigestInit(cptr, hashfn);
00445 #else /* !OLD_DES */
00446     /* this is needed if the runtime library is different than the compiled
00447        library since the openssl versions are very different. */
00448     if (SSLeay() < 0x907000) {
00449         /* the old version of the struct was bigger and thus more
00450            memory is needed. should be 152, but we use 256 for safety. */
00451         cptr = (EVP_MD_CTX *)malloc(256);
00452         EVP_DigestInit(cptr, hashfn);
00453     } else {
00454         EVP_MD_CTX_init(cptr);
00455         EVP_DigestInit(cptr, hashfn);
00456     }
00457 #endif
00458 
00460     EVP_DigestUpdate(cptr, buf, buf_len);
00461 
00463 #if defined(OLD_DES)
00464     EVP_DigestFinal(cptr, MAC, &tmp_len);
00465     *MAC_len = tmp_len;
00466 #else /* !OLD_DES */
00467     if (SSLeay() < 0x907000) {
00468         EVP_DigestFinal(cptr, MAC, &tmp_len);
00469         *MAC_len = tmp_len;
00470         free(cptr);
00471     } else {
00472         EVP_DigestFinal_ex(cptr, MAC, &tmp_len);
00473         *MAC_len = tmp_len;
00474         EVP_MD_CTX_cleanup(cptr);
00475     }
00476 #endif                          /* OLD_DES */
00477     return (rval);
00478 #elif NETSNMP_USE_PKCS11                  /* NETSNMP_USE_PKCS11 */
00479 
00480 #ifndef NETSNMP_DISABLE_MD5
00481     if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
00482         rval = pkcs_digest(CKM_MD5, buf, buf_len, MAC, MAC_len);
00483     } else
00484 #endif
00485         if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
00486         rval = pkcs_digest(CKM_SHA_1, buf, buf_len, MAC, MAC_len);
00487     } else {
00488         return (SNMPERR_GENERR);
00489     }
00490 
00491      return (rval);
00492 
00493 #else                           /* NETSNMP_USE_INTERNAL_MD5 */
00494 
00495     if (MDchecksum(buf, buf_len, MAC, *MAC_len)) {
00496         return SNMPERR_GENERR;
00497     }
00498     if (*MAC_len > 16)
00499         *MAC_len = 16;
00500     return SNMPERR_SUCCESS;
00501 
00502 #endif                          /* NETSNMP_USE_OPENSSL */
00503 }
00504 #else                           /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */
00505 _SCAPI_NOT_CONFIGURED
00506 #endif                          /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */
00507 /*******************************************************************-o-******
00508  * sc_check_keyed_hash
00509  *
00510  * Parameters:
00511  *       authtype       Transform type of authentication hash.
00512  *      *key            Key bits in a string of bytes.
00513  *       keylen         Length of key in bytes.
00514  *      *message        Message for which to check the hash.
00515  *       msglen         Length of message.
00516  *      *MAC            Given hash.
00517  *       maclen         Length of given hash; indicates truncation if it is
00518  *                              shorter than the normal size of output for
00519  *                              given hash transform.
00520  * Returns:
00521  *      SNMPERR_SUCCESS         Success.
00522  *      SNMP_SC_GENERAL_FAILURE Any error
00523  *
00524  *
00525  * Check the hash given in MAC against the hash of message.  If the length
00526  * of MAC is less than the length of the transform hash output, only maclen
00527  * bytes are compared.  The length of MAC cannot be greater than the
00528  * length of the hash transform output.
00529  */
00530 int
00531 sc_check_keyed_hash(const oid * authtype, size_t authtypelen,
00532                     u_char * key, u_int keylen,
00533                     u_char * message, u_int msglen,
00534                     u_char * MAC, u_int maclen)
00535 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
00536 {
00537     int             rval = SNMPERR_SUCCESS;
00538     size_t          buf_len = SNMP_MAXBUF_SMALL;
00539 
00540     u_char          buf[SNMP_MAXBUF_SMALL];
00541 
00542     DEBUGTRACE;
00543 
00544 #ifdef NETSNMP_ENABLE_TESTING_CODE
00545     {
00546         int             i;
00547         DEBUGMSG(("scapi", "sc_check_keyed_hash():    key=0x"));
00548         for (i = 0; i < keylen; i++)
00549             DEBUGMSG(("scapi", "%02x", key[i] & 0xff));
00550         DEBUGMSG(("scapi", " (%d)\n", keylen));
00551     }
00552 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00553 
00554     /*
00555      * Sanity check.
00556      */
00557     if (!authtype || !key || !message || !MAC
00558         || (keylen <= 0) || (msglen <= 0) || (maclen <= 0)
00559         || (authtypelen != USM_LENGTH_OID_TRANSFORM)) {
00560         QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
00561     }
00562 
00563 
00564     /*
00565      * Generate a full hash of the message, then compare
00566      * the result with the given MAC which may shorter than
00567      * the full hash length.
00568      */
00569     rval = sc_generate_keyed_hash(authtype, authtypelen,
00570                                   key, keylen,
00571                                   message, msglen, buf, &buf_len);
00572     QUITFUN(rval, sc_check_keyed_hash_quit);
00573 
00574     if (maclen > msglen) {
00575         QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
00576 
00577     } else if (memcmp(buf, MAC, maclen) != 0) {
00578         QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
00579     }
00580 
00581 
00582   sc_check_keyed_hash_quit:
00583     SNMP_ZERO(buf, SNMP_MAXBUF_SMALL);
00584 
00585     return rval;
00586 
00587 }                               /* end sc_check_keyed_hash() */
00588 
00589 #else
00590 _SCAPI_NOT_CONFIGURED
00591 #endif                          /* NETSNMP_USE_INTERNAL_MD5 */
00592 /*******************************************************************-o-******
00593  * sc_encrypt
00594  *
00595  * Parameters:
00596  *       privtype       Type of privacy cryptographic transform.
00597  *      *key            Key bits for crypting.
00598  *       keylen         Length of key (buffer) in bytes.
00599  *      *iv             IV bits for crypting.
00600  *       ivlen          Length of iv (buffer) in bytes.
00601  *      *plaintext      Plaintext to crypt.
00602  *       ptlen          Length of plaintext.
00603  *      *ciphertext     Ciphertext to crypt.
00604  *      *ctlen          Length of ciphertext.
00605  *      
00606  * Returns:
00607  *      SNMPERR_SUCCESS                 Success.
00608  *      SNMPERR_SC_NOT_CONFIGURED       Encryption is not supported.
00609  *      SNMPERR_SC_GENERAL_FAILURE      Any other error
00610  *
00611  *
00612  * Encrypt plaintext into ciphertext using key and iv.
00613  *
00614  * ctlen contains actual number of crypted bytes in ciphertext upon
00615  * successful return.
00616  */
00617 int
00618 sc_encrypt(const oid * privtype, size_t privtypelen,
00619            u_char * key, u_int keylen,
00620            u_char * iv, u_int ivlen,
00621            u_char * plaintext, u_int ptlen,
00622            u_char * ciphertext, size_t * ctlen)
00623 #if defined(NETSNMP_USE_OPENSSL)
00624 {
00625     int             rval = SNMPERR_SUCCESS;
00626     u_int           properlength = 0, properlength_iv = 0;
00627     u_char          pad_block[128];      /* bigger than anything I need */
00628     u_char          my_iv[128];  /* ditto */
00629     int             pad, plast, pad_size = 0;
00630     int             have_trans;
00631 #ifndef NETSNMP_DISABLE_DES
00632 #ifdef OLD_DES
00633     DES_key_schedule key_sch;
00634 #else
00635     DES_key_schedule key_sched_store;
00636     DES_key_schedule *key_sch = &key_sched_store;
00637 #endif
00638     DES_cblock       key_struct;
00639 #endif
00640 #ifdef HAVE_AES
00641     AES_KEY aes_key;
00642     int new_ivlen = 0;
00643 #endif
00644 
00645     DEBUGTRACE;
00646 
00647     /*
00648      * Sanity check.
00649      */
00650 #if     !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
00651     snmp_log(LOG_ERR, "Encryption support not enabled.\n");
00652     return SNMPERR_SC_NOT_CONFIGURED;
00653 #endif
00654 
00655     if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
00656         || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0)
00657         || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
00658         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00659     } else if (ptlen > *ctlen) {
00660         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00661     }
00662 #ifdef NETSNMP_ENABLE_TESTING_CODE
00663     {
00664         size_t          buf_len = 128, out_len = 0;
00665         u_char         *buf = (u_char *) malloc(buf_len);
00666 
00667         if (buf != NULL) {
00668             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
00669                                          iv, ivlen)) {
00670                 DEBUGMSGTL(("scapi", "encrypt: IV: %s/", buf));
00671             } else {
00672                 DEBUGMSGTL(("scapi", "encrypt: IV: %s [TRUNCATED]/", buf));
00673             }
00674             out_len = 0;
00675             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
00676                                          key, keylen)) {
00677                 DEBUGMSG(("scapi", "%s\n", buf));
00678             } else {
00679                 DEBUGMSG(("scapi", "%s [TRUNCATED]\n", buf));
00680             }
00681             out_len = 0;
00682             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
00683                                          plaintext, 16)) {
00684                 DEBUGMSGTL(("scapi", "encrypt: string: %s\n", buf));
00685             } else {
00686                 DEBUGMSGTL(("scapi", "encrypt: string: %s [TRUNCATED]\n",
00687                             buf));
00688             }
00689             free(buf);
00690         } else {
00691             DEBUGMSGTL(("scapi",
00692                         "encrypt: malloc fail for debug output\n"));
00693         }
00694     }
00695 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00696 
00697 
00698     /*
00699      * Determine privacy transform.
00700      */
00701     have_trans = 0;
00702 #ifndef NETSNMP_DISABLE_DES
00703     if (ISTRANSFORM(privtype, DESPriv)) {
00704         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
00705         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
00706         pad_size = properlength;
00707         have_trans = 1;
00708     }
00709 #endif
00710 #ifdef HAVE_AES
00711     if (ISTRANSFORM(privtype, AESPriv)) {
00712         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
00713         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV);
00714         have_trans = 1;
00715     }
00716 #endif
00717     if (!have_trans) {
00718         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00719     }
00720 
00721     if ((keylen < properlength) || (ivlen < properlength_iv)) {
00722         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00723     }
00724 
00725     memset(my_iv, 0, sizeof(my_iv));
00726 
00727 #ifndef NETSNMP_DISABLE_DES
00728     if (ISTRANSFORM(privtype, DESPriv)) {
00729 
00730         /*
00731          * now calculate the padding needed 
00732          */
00733         pad = pad_size - (ptlen % pad_size);
00734         plast = (int) ptlen - (pad_size - pad);
00735         if (pad == pad_size)
00736             pad = 0;
00737         if (ptlen + pad > *ctlen) {
00738             QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);    /* not enough space */
00739         }
00740         if (pad > 0) {              /* copy data into pad block if needed */
00741             memcpy(pad_block, plaintext + plast, pad_size - pad);
00742             memset(&pad_block[pad_size - pad], pad, pad);   /* filling in padblock */
00743         }
00744 
00745         memcpy(key_struct, key, sizeof(key_struct));
00746         (void) DES_key_sched(&key_struct, key_sch);
00747 
00748         memcpy(my_iv, iv, ivlen);
00749         /*
00750          * encrypt the data 
00751          */
00752         DES_ncbc_encrypt(plaintext, ciphertext, plast, key_sch,
00753                          (DES_cblock *) my_iv, DES_ENCRYPT);
00754         if (pad > 0) {
00755             /*
00756              * then encrypt the pad block 
00757              */
00758             DES_ncbc_encrypt(pad_block, ciphertext + plast, pad_size,
00759                              key_sch, (DES_cblock *) my_iv, DES_ENCRYPT);
00760             *ctlen = plast + pad_size;
00761         } else {
00762             *ctlen = plast;
00763         }
00764     }
00765 #endif
00766 #ifdef HAVE_AES
00767     if (ISTRANSFORM(privtype, AESPriv)) {
00768         (void) AES_set_encrypt_key(key, properlength*8, &aes_key);
00769 
00770         memcpy(my_iv, iv, ivlen);
00771         /*
00772          * encrypt the data 
00773          */
00774         AES_cfb128_encrypt(plaintext, ciphertext, ptlen,
00775                            &aes_key, my_iv, &new_ivlen, AES_ENCRYPT);
00776         *ctlen = ptlen;
00777     }
00778 #endif
00779   sc_encrypt_quit:
00780     /*
00781      * clear memory just in case 
00782      */
00783     memset(my_iv, 0, sizeof(my_iv));
00784     memset(pad_block, 0, sizeof(pad_block));
00785 #ifndef NETSNMP_DISABLE_DES
00786     memset(key_struct, 0, sizeof(key_struct));
00787 #ifdef OLD_DES
00788     memset(&key_sch, 0, sizeof(key_sch));
00789 #else
00790     memset(&key_sched_store, 0, sizeof(key_sched_store));
00791 #endif
00792 #endif
00793 #ifdef HAVE_AES
00794     memset(&aes_key,0,sizeof(aes_key));
00795 #endif
00796     return rval;
00797 
00798 }                               /* end sc_encrypt() */
00799 #elif defined(NETSNMP_USE_PKCS11)
00800 {
00801     int             rval = SNMPERR_SUCCESS;
00802     u_int           properlength, properlength_iv;
00803     u_char          pkcs_des_key[8];
00804 
00805     DEBUGTRACE;
00806 
00807     /*
00808      * Sanity check.
00809      */
00810 #if     !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
00811     snmp_log(LOG_ERR, "Encryption support not enabled.\n");
00812     return SNMPERR_SC_NOT_CONFIGURED;
00813 #endif
00814 
00815     if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
00816         || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0)
00817         || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
00818         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00819     } else if (ptlen > *ctlen) {
00820         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00821     }
00822 
00823     /*
00824      * Determine privacy transform.
00825      */
00826     if (ISTRANSFORM(privtype, DESPriv)) {
00827         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
00828         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
00829     } else {
00830         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00831     }
00832 
00833     if ((keylen < properlength) || (ivlen < properlength_iv)) {
00834         QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
00835     }
00836 
00837     if (ISTRANSFORM(privtype, DESPriv)) {
00838         memset(pkcs_des_key, 0, sizeof(pkcs_des_key));
00839         memcpy(pkcs_des_key, key, sizeof(pkcs_des_key));
00840         rval = pkcs_encrpyt(CKM_DES_CBC, pkcs_des_key,
00841                 sizeof(pkcs_des_key), iv, ivlen, plaintext, ptlen,
00842                 ciphertext, ctlen);
00843     }
00844 
00845   sc_encrypt_quit:
00846     return rval;
00847 }
00848 #else
00849 {
00850 #       if NETSNMP_USE_INTERNAL_MD5
00851     {
00852         snmp_log(LOG_ERR, "Encryption support not enabled.\n");
00853         DEBUGMSGTL(("scapi", "Encrypt function not defined.\n"));
00854         return SNMPERR_SC_GENERAL_FAILURE;
00855     }
00856 
00857 #       else
00858     _SCAPI_NOT_CONFIGURED
00859 #       endif                   /* NETSNMP_USE_INTERNAL_MD5 */
00860 }
00861 #endif                          /* */
00862 
00863 
00864 
00865 /*******************************************************************-o-******
00866  * sc_decrypt
00867  *
00868  * Parameters:
00869  *       privtype
00870  *      *key
00871  *       keylen
00872  *      *iv
00873  *       ivlen
00874  *      *ciphertext
00875  *       ctlen
00876  *      *plaintext
00877  *      *ptlen
00878  *      
00879  * Returns:
00880  *      SNMPERR_SUCCESS                 Success.
00881  *      SNMPERR_SC_NOT_CONFIGURED       Encryption is not supported.
00882  *      SNMPERR_SC_GENERAL_FAILURE      Any other error
00883  *
00884  *
00885  * Decrypt ciphertext into plaintext using key and iv.
00886  *
00887  * ptlen contains actual number of plaintext bytes in plaintext upon
00888  * successful return.
00889  */
00890 int
00891 sc_decrypt(const oid * privtype, size_t privtypelen,
00892            u_char * key, u_int keylen,
00893            u_char * iv, u_int ivlen,
00894            u_char * ciphertext, u_int ctlen,
00895            u_char * plaintext, size_t * ptlen)
00896 #ifdef NETSNMP_USE_OPENSSL
00897 {
00898 
00899     int             rval = SNMPERR_SUCCESS;
00900     u_char          my_iv[128];
00901 #ifndef NETSNMP_DISABLE_DES
00902 #ifdef OLD_DES
00903     DES_key_schedule key_sch;
00904 #else
00905     DES_key_schedule key_sched_store;
00906     DES_key_schedule *key_sch = &key_sched_store;
00907 #endif
00908     DES_cblock      key_struct;
00909 #endif
00910     u_int           properlength = 0, properlength_iv = 0;
00911     int             have_transform;
00912 #ifdef HAVE_AES
00913     int new_ivlen = 0;
00914     AES_KEY aes_key;
00915 #endif
00916 
00917     DEBUGTRACE;
00918 
00919     if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
00920         || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)
00921         || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
00922         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
00923     }
00924 #ifdef NETSNMP_ENABLE_TESTING_CODE
00925     {
00926         size_t          buf_len = 128, out_len = 0;
00927         u_char         *buf = (u_char *) malloc(buf_len);
00928 
00929         if (buf != NULL) {
00930             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
00931                                          iv, ivlen)) {
00932                 DEBUGMSGTL(("scapi", "decrypt: IV: %s/", buf));
00933             } else {
00934                 DEBUGMSGTL(("scapi", "decrypt: IV: %s [TRUNCATED]/", buf));
00935             }
00936             out_len = 0;
00937             if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
00938                                          key, keylen)) {
00939                 DEBUGMSG(("scapi", "%s\n", buf));
00940             } else {
00941                 DEBUGMSG(("scapi", "%s\n", buf));
00942             }
00943             free(buf);
00944         } else {
00945             DEBUGMSGTL(("scapi",
00946                         "decrypt: malloc fail for debug output\n"));
00947         }
00948     }
00949 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00950 
00951     /*
00952      * Determine privacy transform.
00953      */
00954     have_transform = 0;
00955 #ifndef NETSNMP_DISABLE_DES
00956     if (ISTRANSFORM(privtype, DESPriv)) {
00957         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
00958         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
00959         have_transform = 1;
00960     }
00961 #endif
00962 #ifdef HAVE_AES
00963     if (ISTRANSFORM(privtype, AESPriv)) {
00964         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
00965         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV);
00966         have_transform = 1;
00967     }
00968 #endif
00969     if (!have_transform) {
00970         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
00971     }
00972 
00973     if ((keylen < properlength) || (ivlen < properlength_iv)) {
00974         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
00975     }
00976 
00977     memset(my_iv, 0, sizeof(my_iv));
00978 #ifndef NETSNMP_DISABLE_DES
00979     if (ISTRANSFORM(privtype, DESPriv)) {
00980         memcpy(key_struct, key, sizeof(key_struct));
00981         (void) DES_key_sched(&key_struct, key_sch);
00982 
00983         memcpy(my_iv, iv, ivlen);
00984         DES_cbc_encrypt(ciphertext, plaintext, ctlen, key_sch,
00985                         (DES_cblock *) my_iv, DES_DECRYPT);
00986         *ptlen = ctlen;
00987     }
00988 #endif
00989 #ifdef HAVE_AES
00990     if (ISTRANSFORM(privtype, AESPriv)) {
00991         (void) AES_set_encrypt_key(key, properlength*8, &aes_key);
00992 
00993         memcpy(my_iv, iv, ivlen);
00994         /*
00995          * encrypt the data 
00996          */
00997         AES_cfb128_encrypt(ciphertext, plaintext, ctlen,
00998                            &aes_key, my_iv, &new_ivlen, AES_DECRYPT);
00999         *ptlen = ctlen;
01000     }
01001 #endif
01002 
01003     /*
01004      * exit cond 
01005      */
01006   sc_decrypt_quit:
01007 #ifndef NETSNMP_DISABLE_DES
01008 #ifdef OLD_DES
01009     memset(&key_sch, 0, sizeof(key_sch));
01010 #else
01011     memset(&key_sched_store, 0, sizeof(key_sched_store));
01012 #endif
01013     memset(key_struct, 0, sizeof(key_struct));
01014 #endif
01015     memset(my_iv, 0, sizeof(my_iv));
01016     return rval;
01017 }                               /* USE OPEN_SSL */
01018 #elif NETSNMP_USE_PKCS11                  /* USE PKCS */
01019 {
01020     int             rval = SNMPERR_SUCCESS;
01021     u_int           properlength, properlength_iv;
01022     u_char          pkcs_des_key[8];
01023 
01024     DEBUGTRACE;
01025 
01026     if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
01027         || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)
01028         || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
01029         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01030     }
01031 
01032     /*
01033      * Determine privacy transform.
01034      */
01035     if (ISTRANSFORM(privtype, DESPriv)) {
01036         properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
01037         properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
01038     } else {
01039         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01040     }
01041 
01042     if ((keylen < properlength) || (ivlen < properlength_iv)) {
01043         QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
01044     }
01045 
01046     if (ISTRANSFORM(privtype, DESPriv)) {
01047         memset(pkcs_des_key, 0, sizeof(pkcs_des_key));
01048         memcpy(pkcs_des_key, key, sizeof(pkcs_des_key));
01049         rval = pkcs_decrpyt(CKM_DES_CBC, pkcs_des_key, 
01050                 sizeof(pkcs_des_key), iv, ivlen, ciphertext,
01051                 ctlen, plaintext, ptlen);
01052         *ptlen = ctlen;
01053     }
01054 
01055   sc_decrypt_quit:
01056     return rval;
01057 }                               /* USE PKCS */
01058 #else
01059 {
01060 #if     !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
01061     snmp_log(LOG_ERR, "Encryption support not enabled.\n");
01062     return SNMPERR_SC_NOT_CONFIGURED;
01063 #else
01064 #       if NETSNMP_USE_INTERNAL_MD5
01065     {
01066         DEBUGMSGTL(("scapi", "Decryption function not defined.\n"));
01067         return SNMPERR_SC_GENERAL_FAILURE;
01068     }
01069 
01070 #       else
01071     _SCAPI_NOT_CONFIGURED
01072 #       endif                   /* NETSNMP_USE_INTERNAL_MD5 */
01073 #endif                          /*  */
01074 }
01075 #endif                          /* NETSNMP_USE_OPENSSL */