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 HAVE_STRUCT_DES_KS_STRUCT_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 unsigned int 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 (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 unsigned int tmp_len; 00408 #endif 00409 int ret; 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, &tmp_len); 00483 *MAC_len = tmp_len; 00484 } else 00485 #endif 00486 if (ISTRANSFORM(hashtype, HMACSHA1Auth)) { 00487 rval = pkcs_digest(CKM_SHA_1, buf, buf_len, MAC, &tmp_len); 00488 *MAC_len = tmp_len; 00489 } else { 00490 return (SNMPERR_GENERR); 00491 } 00492 00493 return (rval); 00494 00495 #else /* NETSNMP_USE_INTERNAL_MD5 */ 00496 00497 if (MDchecksum(buf, buf_len, MAC, *MAC_len)) { 00498 return SNMPERR_GENERR; 00499 } 00500 if (*MAC_len > 16) 00501 *MAC_len = 16; 00502 return SNMPERR_SUCCESS; 00503 00504 #endif /* NETSNMP_USE_OPENSSL */ 00505 } 00506 #else /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */ 00507 _SCAPI_NOT_CONFIGURED 00508 #endif /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */ 00509 /*******************************************************************-o-****** 00510 * sc_check_keyed_hash 00511 * 00512 * Parameters: 00513 * authtype Transform type of authentication hash. 00514 * *key Key bits in a string of bytes. 00515 * keylen Length of key in bytes. 00516 * *message Message for which to check the hash. 00517 * msglen Length of message. 00518 * *MAC Given hash. 00519 * maclen Length of given hash; indicates truncation if it is 00520 * shorter than the normal size of output for 00521 * given hash transform. 00522 * Returns: 00523 * SNMPERR_SUCCESS Success. 00524 * SNMP_SC_GENERAL_FAILURE Any error 00525 * 00526 * 00527 * Check the hash given in MAC against the hash of message. If the length 00528 * of MAC is less than the length of the transform hash output, only maclen 00529 * bytes are compared. The length of MAC cannot be greater than the 00530 * length of the hash transform output. 00531 */ 00532 int 00533 sc_check_keyed_hash(const oid * authtype, size_t authtypelen, 00534 u_char * key, u_int keylen, 00535 u_char * message, u_int msglen, 00536 u_char * MAC, u_int maclen) 00537 #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) 00538 { 00539 int rval = SNMPERR_SUCCESS; 00540 size_t buf_len = SNMP_MAXBUF_SMALL; 00541 00542 u_char buf[SNMP_MAXBUF_SMALL]; 00543 00544 DEBUGTRACE; 00545 00546 #ifdef NETSNMP_ENABLE_TESTING_CODE 00547 { 00548 int i; 00549 DEBUGMSG(("scapi", "sc_check_keyed_hash(): key=0x")); 00550 for (i = 0; i < keylen; i++) 00551 DEBUGMSG(("scapi", "%02x", key[i] & 0xff)); 00552 DEBUGMSG(("scapi", " (%d)\n", keylen)); 00553 } 00554 #endif /* NETSNMP_ENABLE_TESTING_CODE */ 00555 00556 /* 00557 * Sanity check. 00558 */ 00559 if (!authtype || !key || !message || !MAC 00560 || (keylen <= 0) || (msglen <= 0) || (maclen <= 0) 00561 || (authtypelen != USM_LENGTH_OID_TRANSFORM)) { 00562 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit); 00563 } 00564 00565 00566 if (maclen != USM_MD5_AND_SHA_AUTH_LEN) { 00567 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit); 00568 } 00569 00570 /* 00571 * Generate a full hash of the message, then compare 00572 * the result with the given MAC which may shorter than 00573 * the full hash length. 00574 */ 00575 rval = sc_generate_keyed_hash(authtype, authtypelen, 00576 key, keylen, 00577 message, msglen, buf, &buf_len); 00578 QUITFUN(rval, sc_check_keyed_hash_quit); 00579 00580 if (maclen > msglen) { 00581 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit); 00582 00583 } else if (memcmp(buf, MAC, maclen) != 0) { 00584 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit); 00585 } 00586 00587 00588 sc_check_keyed_hash_quit: 00589 SNMP_ZERO(buf, SNMP_MAXBUF_SMALL); 00590 00591 return rval; 00592 00593 } /* end sc_check_keyed_hash() */ 00594 00595 #else 00596 _SCAPI_NOT_CONFIGURED 00597 #endif /* NETSNMP_USE_INTERNAL_MD5 */ 00598 /*******************************************************************-o-****** 00599 * sc_encrypt 00600 * 00601 * Parameters: 00602 * privtype Type of privacy cryptographic transform. 00603 * *key Key bits for crypting. 00604 * keylen Length of key (buffer) in bytes. 00605 * *iv IV bits for crypting. 00606 * ivlen Length of iv (buffer) in bytes. 00607 * *plaintext Plaintext to crypt. 00608 * ptlen Length of plaintext. 00609 * *ciphertext Ciphertext to crypt. 00610 * *ctlen Length of ciphertext. 00611 * 00612 * Returns: 00613 * SNMPERR_SUCCESS Success. 00614 * SNMPERR_SC_NOT_CONFIGURED Encryption is not supported. 00615 * SNMPERR_SC_GENERAL_FAILURE Any other error 00616 * 00617 * 00618 * Encrypt plaintext into ciphertext using key and iv. 00619 * 00620 * ctlen contains actual number of crypted bytes in ciphertext upon 00621 * successful return. 00622 */ 00623 int 00624 sc_encrypt(const oid * privtype, size_t privtypelen, 00625 u_char * key, u_int keylen, 00626 u_char * iv, u_int ivlen, 00627 u_char * plaintext, u_int ptlen, 00628 u_char * ciphertext, size_t * ctlen) 00629 #if defined(NETSNMP_USE_OPENSSL) 00630 { 00631 int rval = SNMPERR_SUCCESS; 00632 u_int properlength = 0, properlength_iv = 0; 00633 u_char pad_block[128]; /* bigger than anything I need */ 00634 u_char my_iv[128]; /* ditto */ 00635 int pad, plast, pad_size = 0; 00636 int have_trans; 00637 #ifndef NETSNMP_DISABLE_DES 00638 #ifdef OLD_DES 00639 DES_key_schedule key_sch; 00640 #else 00641 DES_key_schedule key_sched_store; 00642 DES_key_schedule *key_sch = &key_sched_store; 00643 #endif 00644 DES_cblock key_struct; 00645 #endif 00646 #ifdef HAVE_AES 00647 AES_KEY aes_key; 00648 int new_ivlen = 0; 00649 #endif 00650 00651 DEBUGTRACE; 00652 00653 /* 00654 * Sanity check. 00655 */ 00656 #if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV) 00657 snmp_log(LOG_ERR, "Encryption support not enabled.\n"); 00658 return SNMPERR_SC_NOT_CONFIGURED; 00659 #endif 00660 00661 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen 00662 || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0) 00663 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) { 00664 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); 00665 } else if (ptlen > *ctlen) { 00666 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); 00667 } 00668 #ifdef NETSNMP_ENABLE_TESTING_CODE 00669 { 00670 size_t buf_len = 128, out_len = 0; 00671 u_char *buf = (u_char *) malloc(buf_len); 00672 00673 if (buf != NULL) { 00674 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1, 00675 iv, ivlen)) { 00676 DEBUGMSGTL(("scapi", "encrypt: IV: %s/", buf)); 00677 } else { 00678 DEBUGMSGTL(("scapi", "encrypt: IV: %s [TRUNCATED]/", buf)); 00679 } 00680 out_len = 0; 00681 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1, 00682 key, keylen)) { 00683 DEBUGMSG(("scapi", "%s\n", buf)); 00684 } else { 00685 DEBUGMSG(("scapi", "%s [TRUNCATED]\n", buf)); 00686 } 00687 out_len = 0; 00688 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1, 00689 plaintext, 16)) { 00690 DEBUGMSGTL(("scapi", "encrypt: string: %s\n", buf)); 00691 } else { 00692 DEBUGMSGTL(("scapi", "encrypt: string: %s [TRUNCATED]\n", 00693 buf)); 00694 } 00695 free(buf); 00696 } else { 00697 DEBUGMSGTL(("scapi", 00698 "encrypt: malloc fail for debug output\n")); 00699 } 00700 } 00701 #endif /* NETSNMP_ENABLE_TESTING_CODE */ 00702 00703 00704 /* 00705 * Determine privacy transform. 00706 */ 00707 have_trans = 0; 00708 #ifndef NETSNMP_DISABLE_DES 00709 if (ISTRANSFORM(privtype, DESPriv)) { 00710 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES); 00711 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV); 00712 pad_size = properlength; 00713 have_trans = 1; 00714 } 00715 #endif 00716 #ifdef HAVE_AES 00717 if (ISTRANSFORM(privtype, AESPriv)) { 00718 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES); 00719 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV); 00720 have_trans = 1; 00721 } 00722 #endif 00723 if (!have_trans) { 00724 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); 00725 } 00726 00727 if ((keylen < properlength) || (ivlen < properlength_iv)) { 00728 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); 00729 } 00730 00731 memset(my_iv, 0, sizeof(my_iv)); 00732 00733 #ifndef NETSNMP_DISABLE_DES 00734 if (ISTRANSFORM(privtype, DESPriv)) { 00735 00736 /* 00737 * now calculate the padding needed 00738 */ 00739 pad = pad_size - (ptlen % pad_size); 00740 plast = (int) ptlen - (pad_size - pad); 00741 if (pad == pad_size) 00742 pad = 0; 00743 if (ptlen + pad > *ctlen) { 00744 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); /* not enough space */ 00745 } 00746 if (pad > 0) { /* copy data into pad block if needed */ 00747 memcpy(pad_block, plaintext + plast, pad_size - pad); 00748 memset(&pad_block[pad_size - pad], pad, pad); /* filling in padblock */ 00749 } 00750 00751 memcpy(key_struct, key, sizeof(key_struct)); 00752 (void) DES_key_sched(&key_struct, key_sch); 00753 00754 memcpy(my_iv, iv, ivlen); 00755 /* 00756 * encrypt the data 00757 */ 00758 DES_ncbc_encrypt(plaintext, ciphertext, plast, key_sch, 00759 (DES_cblock *) my_iv, DES_ENCRYPT); 00760 if (pad > 0) { 00761 /* 00762 * then encrypt the pad block 00763 */ 00764 DES_ncbc_encrypt(pad_block, ciphertext + plast, pad_size, 00765 key_sch, (DES_cblock *) my_iv, DES_ENCRYPT); 00766 *ctlen = plast + pad_size; 00767 } else { 00768 *ctlen = plast; 00769 } 00770 } 00771 #endif 00772 #ifdef HAVE_AES 00773 if (ISTRANSFORM(privtype, AESPriv)) { 00774 (void) AES_set_encrypt_key(key, properlength*8, &aes_key); 00775 00776 memcpy(my_iv, iv, ivlen); 00777 /* 00778 * encrypt the data 00779 */ 00780 AES_cfb128_encrypt(plaintext, ciphertext, ptlen, 00781 &aes_key, my_iv, &new_ivlen, AES_ENCRYPT); 00782 *ctlen = ptlen; 00783 } 00784 #endif 00785 sc_encrypt_quit: 00786 /* 00787 * clear memory just in case 00788 */ 00789 memset(my_iv, 0, sizeof(my_iv)); 00790 memset(pad_block, 0, sizeof(pad_block)); 00791 #ifndef NETSNMP_DISABLE_DES 00792 memset(key_struct, 0, sizeof(key_struct)); 00793 #ifdef OLD_DES 00794 memset(&key_sch, 0, sizeof(key_sch)); 00795 #else 00796 memset(&key_sched_store, 0, sizeof(key_sched_store)); 00797 #endif 00798 #endif 00799 #ifdef HAVE_AES 00800 memset(&aes_key,0,sizeof(aes_key)); 00801 #endif 00802 return rval; 00803 00804 } /* end sc_encrypt() */ 00805 #elif defined(NETSNMP_USE_PKCS11) 00806 { 00807 int rval = SNMPERR_SUCCESS; 00808 u_int properlength, properlength_iv; 00809 u_char pkcs_des_key[8]; 00810 00811 DEBUGTRACE; 00812 00813 /* 00814 * Sanity check. 00815 */ 00816 #if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV) 00817 snmp_log(LOG_ERR, "Encryption support not enabled.\n"); 00818 return SNMPERR_SC_NOT_CONFIGURED; 00819 #endif 00820 00821 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen 00822 || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0) 00823 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) { 00824 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); 00825 } else if (ptlen > *ctlen) { 00826 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); 00827 } 00828 00829 /* 00830 * Determine privacy transform. 00831 */ 00832 if (ISTRANSFORM(privtype, DESPriv)) { 00833 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES); 00834 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV); 00835 } else { 00836 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); 00837 } 00838 00839 if ((keylen < properlength) || (ivlen < properlength_iv)) { 00840 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); 00841 } 00842 00843 if (ISTRANSFORM(privtype, DESPriv)) { 00844 memset(pkcs_des_key, 0, sizeof(pkcs_des_key)); 00845 memcpy(pkcs_des_key, key, sizeof(pkcs_des_key)); 00846 rval = pkcs_encrpyt(CKM_DES_CBC, pkcs_des_key, 00847 sizeof(pkcs_des_key), iv, ivlen, plaintext, ptlen, 00848 ciphertext, ctlen); 00849 } 00850 00851 sc_encrypt_quit: 00852 return rval; 00853 } 00854 #else 00855 { 00856 # if NETSNMP_USE_INTERNAL_MD5 00857 { 00858 snmp_log(LOG_ERR, "Encryption support not enabled.\n"); 00859 DEBUGMSGTL(("scapi", "Encrypt function not defined.\n")); 00860 return SNMPERR_SC_GENERAL_FAILURE; 00861 } 00862 00863 # else 00864 _SCAPI_NOT_CONFIGURED 00865 # endif /* NETSNMP_USE_INTERNAL_MD5 */ 00866 } 00867 #endif /* */ 00868 00869 00870 00871 /*******************************************************************-o-****** 00872 * sc_decrypt 00873 * 00874 * Parameters: 00875 * privtype 00876 * *key 00877 * keylen 00878 * *iv 00879 * ivlen 00880 * *ciphertext 00881 * ctlen 00882 * *plaintext 00883 * *ptlen 00884 * 00885 * Returns: 00886 * SNMPERR_SUCCESS Success. 00887 * SNMPERR_SC_NOT_CONFIGURED Encryption is not supported. 00888 * SNMPERR_SC_GENERAL_FAILURE Any other error 00889 * 00890 * 00891 * Decrypt ciphertext into plaintext using key and iv. 00892 * 00893 * ptlen contains actual number of plaintext bytes in plaintext upon 00894 * successful return. 00895 */ 00896 int 00897 sc_decrypt(const oid * privtype, size_t privtypelen, 00898 u_char * key, u_int keylen, 00899 u_char * iv, u_int ivlen, 00900 u_char * ciphertext, u_int ctlen, 00901 u_char * plaintext, size_t * ptlen) 00902 #ifdef NETSNMP_USE_OPENSSL 00903 { 00904 00905 int rval = SNMPERR_SUCCESS; 00906 u_char my_iv[128]; 00907 #ifndef NETSNMP_DISABLE_DES 00908 #ifdef OLD_DES 00909 DES_key_schedule key_sch; 00910 #else 00911 DES_key_schedule key_sched_store; 00912 DES_key_schedule *key_sch = &key_sched_store; 00913 #endif 00914 DES_cblock key_struct; 00915 #endif 00916 u_int properlength = 0, properlength_iv = 0; 00917 int have_transform; 00918 #ifdef HAVE_AES 00919 int new_ivlen = 0; 00920 AES_KEY aes_key; 00921 #endif 00922 00923 DEBUGTRACE; 00924 00925 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen 00926 || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen) 00927 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) { 00928 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit); 00929 } 00930 #ifdef NETSNMP_ENABLE_TESTING_CODE 00931 { 00932 size_t buf_len = 128, out_len = 0; 00933 u_char *buf = (u_char *) malloc(buf_len); 00934 00935 if (buf != NULL) { 00936 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1, 00937 iv, ivlen)) { 00938 DEBUGMSGTL(("scapi", "decrypt: IV: %s/", buf)); 00939 } else { 00940 DEBUGMSGTL(("scapi", "decrypt: IV: %s [TRUNCATED]/", buf)); 00941 } 00942 out_len = 0; 00943 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1, 00944 key, keylen)) { 00945 DEBUGMSG(("scapi", "%s\n", buf)); 00946 } else { 00947 DEBUGMSG(("scapi", "%s\n", buf)); 00948 } 00949 free(buf); 00950 } else { 00951 DEBUGMSGTL(("scapi", 00952 "decrypt: malloc fail for debug output\n")); 00953 } 00954 } 00955 #endif /* NETSNMP_ENABLE_TESTING_CODE */ 00956 00957 /* 00958 * Determine privacy transform. 00959 */ 00960 have_transform = 0; 00961 #ifndef NETSNMP_DISABLE_DES 00962 if (ISTRANSFORM(privtype, DESPriv)) { 00963 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES); 00964 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV); 00965 have_transform = 1; 00966 } 00967 #endif 00968 #ifdef HAVE_AES 00969 if (ISTRANSFORM(privtype, AESPriv)) { 00970 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES); 00971 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV); 00972 have_transform = 1; 00973 } 00974 #endif 00975 if (!have_transform) { 00976 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit); 00977 } 00978 00979 if ((keylen < properlength) || (ivlen < properlength_iv)) { 00980 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit); 00981 } 00982 00983 memset(my_iv, 0, sizeof(my_iv)); 00984 #ifndef NETSNMP_DISABLE_DES 00985 if (ISTRANSFORM(privtype, DESPriv)) { 00986 memcpy(key_struct, key, sizeof(key_struct)); 00987 (void) DES_key_sched(&key_struct, key_sch); 00988 00989 memcpy(my_iv, iv, ivlen); 00990 DES_cbc_encrypt(ciphertext, plaintext, ctlen, key_sch, 00991 (DES_cblock *) my_iv, DES_DECRYPT); 00992 *ptlen = ctlen; 00993 } 00994 #endif 00995 #ifdef HAVE_AES 00996 if (ISTRANSFORM(privtype, AESPriv)) { 00997 (void) AES_set_encrypt_key(key, properlength*8, &aes_key); 00998 00999 memcpy(my_iv, iv, ivlen); 01000 /* 01001 * encrypt the data 01002 */ 01003 AES_cfb128_encrypt(ciphertext, plaintext, ctlen, 01004 &aes_key, my_iv, &new_ivlen, AES_DECRYPT); 01005 *ptlen = ctlen; 01006 } 01007 #endif 01008 01009 /* 01010 * exit cond 01011 */ 01012 sc_decrypt_quit: 01013 #ifndef NETSNMP_DISABLE_DES 01014 #ifdef OLD_DES 01015 memset(&key_sch, 0, sizeof(key_sch)); 01016 #else 01017 memset(&key_sched_store, 0, sizeof(key_sched_store)); 01018 #endif 01019 memset(key_struct, 0, sizeof(key_struct)); 01020 #endif 01021 memset(my_iv, 0, sizeof(my_iv)); 01022 return rval; 01023 } /* USE OPEN_SSL */ 01024 #elif NETSNMP_USE_PKCS11 /* USE PKCS */ 01025 { 01026 int rval = SNMPERR_SUCCESS; 01027 u_int properlength, properlength_iv; 01028 u_char pkcs_des_key[8]; 01029 01030 DEBUGTRACE; 01031 01032 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen 01033 || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen) 01034 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) { 01035 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit); 01036 } 01037 01038 /* 01039 * Determine privacy transform. 01040 */ 01041 if (ISTRANSFORM(privtype, DESPriv)) { 01042 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES); 01043 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV); 01044 } else { 01045 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit); 01046 } 01047 01048 if ((keylen < properlength) || (ivlen < properlength_iv)) { 01049 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit); 01050 } 01051 01052 if (ISTRANSFORM(privtype, DESPriv)) { 01053 memset(pkcs_des_key, 0, sizeof(pkcs_des_key)); 01054 memcpy(pkcs_des_key, key, sizeof(pkcs_des_key)); 01055 rval = pkcs_decrpyt(CKM_DES_CBC, pkcs_des_key, 01056 sizeof(pkcs_des_key), iv, ivlen, ciphertext, 01057 ctlen, plaintext, ptlen); 01058 *ptlen = ctlen; 01059 } 01060 01061 sc_decrypt_quit: 01062 return rval; 01063 } /* USE PKCS */ 01064 #else 01065 { 01066 #if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV) 01067 snmp_log(LOG_ERR, "Encryption support not enabled.\n"); 01068 return SNMPERR_SC_NOT_CONFIGURED; 01069 #else 01070 # if NETSNMP_USE_INTERNAL_MD5 01071 { 01072 DEBUGMSGTL(("scapi", "Decryption function not defined.\n")); 01073 return SNMPERR_SC_GENERAL_FAILURE; 01074 } 01075 01076 # else 01077 _SCAPI_NOT_CONFIGURED 01078 # endif /* NETSNMP_USE_INTERNAL_MD5 */ 01079 #endif /* */ 01080 } 01081 #endif /* NETSNMP_USE_OPENSSL */
1.5.7.1
Last modified: Tuesday, 23-Dec-2025 17:22:04 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.