net-snmp
5.4.1
|
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 */