blob: cb2d2f3cb05d272718d634d3b76167614d840860 [file] [log] [blame]
Dave Shield00ef5692011-02-22 08:55:48 +00001/* Portions of this file are subject to the following copyright(s). See
2 * the Net-SNMP's COPYING file for more details and other copyrights
3 * that may apply:
4 */
5/*
6 * Portions of this file are copyrighted by:
7 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
8 * Use is subject to license terms specified in the COPYING file
9 * distributed with the Net-SNMP package.
10 */
11
12/*
13 * scapi.c
14 *
15 */
16
17#include <net-snmp/net-snmp-config.h>
18
19#include <sys/types.h>
20#if HAVE_WINSOCK_H
21#include <winsock.h>
22#endif
23#ifdef HAVE_STDLIB_H
24#include <stdlib.h>
25#endif
26#if HAVE_STRING_H
27#include <string.h>
28#else
29#include <strings.h>
30#endif
31#if TIME_WITH_SYS_TIME
32# ifdef WIN32
33# include <sys/timeb.h>
34# else
35# include <sys/time.h>
36# endif
37# include <time.h>
38#else
39# if HAVE_SYS_TIME_H
40# include <sys/time.h>
41# else
42# include <time.h>
43# endif
44#endif
45#ifdef HAVE_NETINET_IN_H
46#include <netinet/in.h>
47#endif
48
49#if HAVE_UNISTD_H
50#include <unistd.h>
51#endif
52#if HAVE_DMALLOC_H
53#include <dmalloc.h>
54#endif
55
56#include <net-snmp/types.h>
57#include <net-snmp/output_api.h>
58#include <net-snmp/utilities.h>
59
60#ifdef NETSNMP_USE_INTERNAL_MD5
61#include <net-snmp/library/md5.h>
62#endif
63#include <net-snmp/library/snmp_api.h>
64#include <net-snmp/library/callback.h>
65#include <net-snmp/library/snmp_secmod.h>
66#include <net-snmp/library/snmpusm.h>
67#include <net-snmp/library/keytools.h>
68#include <net-snmp/library/scapi.h>
69#include <net-snmp/library/mib.h>
70#include <net-snmp/library/transform_oids.h>
71
72#ifdef NETSNMP_USE_OPENSSL
73#include <openssl/hmac.h>
74#include <openssl/evp.h>
75#include <openssl/rand.h>
76#include <openssl/des.h>
77#ifdef HAVE_AES
78#include <openssl/aes.h>
79#endif
80
81#ifndef NETSNMP_DISABLE_DES
82#ifdef HAVE_STRUCT_DES_KS_STRUCT_WEAK_KEY
83/* these are older names for newer structures that exist in openssl .9.7 */
84#define DES_key_schedule des_key_schedule
85#define DES_cblock des_cblock
86#define DES_key_sched des_key_sched
87#define DES_ncbc_encrypt des_ncbc_encrypt
88#define DES_cbc_encrypt des_cbc_encrypt
89#define OLD_DES
90#endif
91#endif
92
93#endif /* HAVE_OPENSSL */
94
95#ifdef NETSNMP_USE_PKCS11
96#include <security/cryptoki.h>
97#endif
98
99#ifdef QUITFUN
100#undef QUITFUN
101#define QUITFUN(e, l) \
102 if (e != SNMPERR_SUCCESS) { \
103 rval = SNMPERR_SC_GENERAL_FAILURE; \
104 goto l ; \
105 }
106#endif
107
108
109/*
110 * sc_get_properlength(oid *hashtype, u_int hashtype_len):
111 *
112 * Given a hashing type ("hashtype" and its length hashtype_len), return
113 * the length of the hash result.
114 *
115 * Returns either the length or SNMPERR_GENERR for an unknown hashing type.
116 */
117int
118sc_get_properlength(const oid * hashtype, u_int hashtype_len)
119{
120 DEBUGTRACE;
121 /*
122 * Determine transform type hash length.
123 */
124#ifndef NETSNMP_DISABLE_MD5
125 if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
126 return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
127 } else
128#endif
129 if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
130 return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
131 }
132 return SNMPERR_GENERR;
133}
134
135int
136sc_get_proper_priv_length(const oid * privtype, u_int privtype_len)
137{
138 int properlength = 0;
139#ifndef NETSNMP_DISABLE_DES
140 if (ISTRANSFORM(privtype, DESPriv)) {
141 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
142 }
143#endif
144#ifdef HAVE_AES
145 if (ISTRANSFORM(privtype, AESPriv)) {
146 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
147 }
148#endif
149 return properlength;
150}
151
152
153/*******************************************************************-o-******
154 * sc_init
155 *
156 * Returns:
157 * SNMPERR_SUCCESS Success.
158 */
159int
160sc_init(void)
161{
162 int rval = SNMPERR_SUCCESS;
163
164#ifndef NETSNMP_USE_OPENSSL
165#ifdef NETSNMP_USE_INTERNAL_MD5
166 struct timeval tv;
167
168 DEBUGTRACE;
169
170 gettimeofday(&tv, (struct timezone *) 0);
171
172 srandom(tv.tv_sec ^ tv.tv_usec);
173#elif NETSNMP_USE_PKCS11
174 DEBUGTRACE;
175 rval = pkcs_init();
176#else
177 rval = SNMPERR_SC_NOT_CONFIGURED;
178#endif /* NETSNMP_USE_INTERNAL_MD5 */
179 /*
180 * XXX ogud: The only reason to do anything here with openssl is to
181 * * XXX ogud: seed random number generator
182 */
183#endif /* ifndef NETSNMP_USE_OPENSSL */
184 return rval;
185} /* end sc_init() */
186
187/*******************************************************************-o-******
188 * sc_random
189 *
190 * Parameters:
191 * *buf Pre-allocated buffer.
192 * *buflen Size of buffer.
193 *
194 * Returns:
195 * SNMPERR_SUCCESS Success.
196 */
197int
198sc_random(u_char * buf, size_t * buflen)
199#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
200{
201 int rval = SNMPERR_SUCCESS;
202#ifdef NETSNMP_USE_INTERNAL_MD5
203 int i;
204 int rndval;
205 u_char *ucp = buf;
206#endif
207
208 DEBUGTRACE;
209
210#ifdef NETSNMP_USE_OPENSSL
211 RAND_bytes(buf, *buflen); /* will never fail */
212#elif NETSNMP_USE_PKCS11 /* NETSNMP_USE_PKCS11 */
213 pkcs_random(buf, *buflen);
214#else /* NETSNMP_USE_INTERNAL_MD5 */
215 /*
216 * fill the buffer with random integers. Note that random()
217 * is defined in config.h and may not be truly the random()
218 * system call if something better existed
219 */
220 rval = *buflen - *buflen % sizeof(rndval);
221 for (i = 0; i < rval; i += sizeof(rndval)) {
222 rndval = random();
223 memcpy(ucp, &rndval, sizeof(rndval));
224 ucp += sizeof(rndval);
225 }
226
227 rndval = random();
228 memcpy(ucp, &rndval, *buflen % sizeof(rndval));
229
230 rval = SNMPERR_SUCCESS;
231#endif /* NETSNMP_USE_OPENSSL */
232 return rval;
233
234} /* end sc_random() */
235
236#else
237_SCAPI_NOT_CONFIGURED
238#endif /* */
239/*******************************************************************-o-******
240 * sc_generate_keyed_hash
241 *
242 * Parameters:
243 * authtype Type of authentication transform.
244 * authtypelen
245 * *key Pointer to key (Kul) to use in keyed hash.
246 * keylen Length of key in bytes.
247 * *message Pointer to the message to hash.
248 * msglen Length of the message.
249 * *MAC Will be returned with allocated bytes containg hash.
250 * *maclen Length of the hash buffer in bytes; also indicates
251 * whether the MAC should be truncated.
252 *
253 * Returns:
254 * SNMPERR_SUCCESS Success.
255 * SNMPERR_GENERR All errs
256 *
257 *
258 * A hash of the first msglen bytes of message using a keyed hash defined
259 * by authtype is created and stored in MAC. MAC is ASSUMED to be a buffer
260 * of at least maclen bytes. If the length of the hash is greater than
261 * maclen, it is truncated to fit the buffer. If the length of the hash is
262 * less than maclen, maclen set to the number of hash bytes generated.
263 *
264 * ASSUMED that the number of hash bits is a multiple of 8.
265 */
266int
267sc_generate_keyed_hash(const oid * authtype, size_t authtypelen,
268 u_char * key, u_int keylen,
269 u_char * message, u_int msglen,
270 u_char * MAC, size_t * maclen)
271#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
272{
273 int rval = SNMPERR_SUCCESS;
274 int properlength;
275
276 u_char buf[SNMP_MAXBUF_SMALL];
277#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
278 unsigned int buf_len = sizeof(buf);
279#endif
280
281 DEBUGTRACE;
282
283#ifdef NETSNMP_ENABLE_TESTING_CODE
284 {
285 int i;
286 DEBUGMSG(("sc_generate_keyed_hash",
287 "sc_generate_keyed_hash(): key=0x"));
288 for (i = 0; i < keylen; i++)
289 DEBUGMSG(("sc_generate_keyed_hash", "%02x", key[i] & 0xff));
290 DEBUGMSG(("sc_generate_keyed_hash", " (%d)\n", keylen));
291 }
292#endif /* NETSNMP_ENABLE_TESTING_CODE */
293
294 /*
295 * Sanity check.
296 */
297 if (!authtype || !key || !message || !MAC || !maclen
298 || (keylen <= 0) || (msglen <= 0) || (*maclen <= 0)
299 || (authtypelen != USM_LENGTH_OID_TRANSFORM)) {
300 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
301 }
302
303 properlength = sc_get_properlength(authtype, authtypelen);
304 if (properlength == SNMPERR_GENERR)
305 return properlength;
306
307 if (((int) keylen < properlength)) {
308 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
309 }
310#ifdef NETSNMP_USE_OPENSSL
311 /*
312 * Determine transform type.
313 */
314#ifndef NETSNMP_DISABLE_MD5
315 if (ISTRANSFORM(authtype, HMACMD5Auth))
316 HMAC(EVP_md5(), key, keylen, message, msglen, buf, &buf_len);
317 else
318#endif
319 if (ISTRANSFORM(authtype, HMACSHA1Auth))
320 HMAC(EVP_sha1(), key, keylen, message, msglen, buf, &buf_len);
321 else {
322 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
323 }
324 if (buf_len != properlength) {
325 QUITFUN(rval, sc_generate_keyed_hash_quit);
326 }
327 if ((int)*maclen > buf_len)
328 *maclen = buf_len;
329 memcpy(MAC, buf, *maclen);
330
331#elif NETSNMP_USE_PKCS11 /* NETSNMP_USE_PKCS11 */
332
333#ifndef NETSNMP_DISABLE_MD5
334 if (ISTRANSFORM(authtype, HMACMD5Auth)) {
335 if (pkcs_sign(CKM_MD5_HMAC,key, keylen, message,
336 msglen, buf, &buf_len) != SNMPERR_SUCCESS) {
337 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
338 }
339 } else
340#endif
341 if (ISTRANSFORM(authtype, HMACSHA1Auth)) {
342 if (pkcs_sign(CKM_SHA_1_HMAC,key, keylen, message,
343 msglen, buf, &buf_len) != SNMPERR_SUCCESS) {
344 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
345 }
346 } else {
347 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
348 }
349
350 if (buf_len != properlength) {
351 QUITFUN(rval, sc_generate_keyed_hash_quit);
352 }
353 if (*maclen > buf_len)
354 *maclen = buf_len;
355 memcpy(MAC, buf, *maclen);
356
357#else /* NETSNMP_USE_INTERNAL_MD5 */
358 if ((int) *maclen > properlength)
359 *maclen = properlength;
360 if (MDsign(message, msglen, MAC, *maclen, key, keylen)) {
361 rval = SNMPERR_GENERR;
362 goto sc_generate_keyed_hash_quit;
363 }
364#endif /* NETSNMP_USE_OPENSSL */
365
366#ifdef NETSNMP_ENABLE_TESTING_CODE
367 {
368 char *s;
369 int len = binary_to_hex(MAC, *maclen, &s);
370
371 DEBUGMSGTL(("scapi", "Full v3 message hash: %s\n", s));
372 SNMP_ZERO(s, len);
373 SNMP_FREE(s);
374 }
375#endif /* NETSNMP_ENABLE_TESTING_CODE */
376
377 sc_generate_keyed_hash_quit:
Magnus Fromreidea1986582009-10-14 23:12:05 +0000378 memset(buf, 0, SNMP_MAXBUF_SMALL);
Dave Shield00ef5692011-02-22 08:55:48 +0000379 return rval;
380} /* end sc_generate_keyed_hash() */
381
382#else
383 _SCAPI_NOT_CONFIGURED
384#endif /* */
385/*
386 * sc_hash(): a generic wrapper around whatever hashing package we are using.
387 *
388 * IN:
389 * hashtype - oid pointer to a hash type
390 * hashtypelen - length of oid pointer
391 * buf - u_char buffer to be hashed
392 * buf_len - integer length of buf data
393 * MAC_len - length of the passed MAC buffer size.
394 *
395 * OUT:
396 * MAC - pre-malloced space to store hash output.
397 * MAC_len - length of MAC output to the MAC buffer.
398 *
399 * Returns:
400 * SNMPERR_SUCCESS Success.
401 * SNMP_SC_GENERAL_FAILURE Any error.
Jan Safranekdd53ffb2012-11-12 15:46:43 +0100402 * SNMPERR_SC_NOT_CONFIGURED Hash type not supported.
Dave Shield00ef5692011-02-22 08:55:48 +0000403 */
404int
405sc_hash(const oid * hashtype, size_t hashtypelen, u_char * buf,
406 size_t buf_len, u_char * MAC, size_t * MAC_len)
407#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
408{
409#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
410 int rval = SNMPERR_SUCCESS;
411 unsigned int tmp_len;
412#endif
413 int ret;
414
415#ifdef NETSNMP_USE_OPENSSL
416 const EVP_MD *hashfn;
Bart Van Assche46eac022011-09-26 21:49:27 +0200417 EVP_MD_CTX *cptr;
Dave Shield00ef5692011-02-22 08:55:48 +0000418#endif
419
420 DEBUGTRACE;
421
422 if (hashtype == NULL || hashtypelen < 0 || buf == NULL ||
423 buf_len <= 0 || MAC == NULL || MAC_len == NULL )
424 return (SNMPERR_GENERR);
425 ret = sc_get_properlength(hashtype, hashtypelen);
426 if (( ret < 0 ) || (*MAC_len < ret ))
427 return (SNMPERR_GENERR);
428
429#ifdef NETSNMP_USE_OPENSSL
430 /*
431 * Determine transform type.
432 */
433#ifndef NETSNMP_DISABLE_MD5
434 if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
435 hashfn = (const EVP_MD *) EVP_md5();
436 } else
437#endif
438 if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
439 hashfn = (const EVP_MD *) EVP_sha1();
440 } else {
441 return (SNMPERR_GENERR);
442 }
443
444/** initialize the pointer */
Bart Van Assche46eac022011-09-26 21:49:27 +0200445#ifdef HAVE_EVP_MD_CTX_CREATE
446 cptr = EVP_MD_CTX_create();
447#else
448 cptr = malloc(sizeof(*cptr));
Dave Shield00ef5692011-02-22 08:55:48 +0000449#if defined(OLD_DES)
Bart Van Assche46eac022011-09-26 21:49:27 +0200450 memset(cptr, 0, sizeof(*cptr));
451#else
452 EVP_MD_CTX_init(cptr);
Dave Shield00ef5692011-02-22 08:55:48 +0000453#endif
Bart Van Assche46eac022011-09-26 21:49:27 +0200454#endif
Jan Safranekdd53ffb2012-11-12 15:46:43 +0100455 if (!EVP_DigestInit(cptr, hashfn)) {
456 /* requested hash function is not available */
457 return SNMPERR_SC_NOT_CONFIGURED;
458 }
Dave Shield00ef5692011-02-22 08:55:48 +0000459
460/** pass the data */
461 EVP_DigestUpdate(cptr, buf, buf_len);
462
463/** do the final pass */
Dave Shield00ef5692011-02-22 08:55:48 +0000464 EVP_DigestFinal(cptr, MAC, &tmp_len);
465 *MAC_len = tmp_len;
Bart Van Assche46eac022011-09-26 21:49:27 +0200466#ifdef HAVE_EVP_MD_CTX_DESTROY
467 EVP_MD_CTX_destroy(cptr);
468#else
469#if !defined(OLD_DES)
470 EVP_MD_CTX_cleanup(cptr);
471#endif
472 free(cptr);
473#endif
Dave Shield00ef5692011-02-22 08:55:48 +0000474 return (rval);
475#elif NETSNMP_USE_PKCS11 /* NETSNMP_USE_PKCS11 */
476
477#ifndef NETSNMP_DISABLE_MD5
478 if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
479 rval = pkcs_digest(CKM_MD5, buf, buf_len, MAC, &tmp_len);
480 *MAC_len = tmp_len;
481 } else
482#endif
483 if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
484 rval = pkcs_digest(CKM_SHA_1, buf, buf_len, MAC, &tmp_len);
485 *MAC_len = tmp_len;
486 } else {
487 return (SNMPERR_GENERR);
488 }
489
490 return (rval);
491
492#else /* NETSNMP_USE_INTERNAL_MD5 */
493
494 if (MDchecksum(buf, buf_len, MAC, *MAC_len)) {
495 return SNMPERR_GENERR;
496 }
497 if (*MAC_len > 16)
498 *MAC_len = 16;
499 return SNMPERR_SUCCESS;
500
501#endif /* NETSNMP_USE_OPENSSL */
502}
503#else /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */
504_SCAPI_NOT_CONFIGURED
505#endif /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */
506/*******************************************************************-o-******
507 * sc_check_keyed_hash
508 *
509 * Parameters:
510 * authtype Transform type of authentication hash.
511 * *key Key bits in a string of bytes.
512 * keylen Length of key in bytes.
513 * *message Message for which to check the hash.
514 * msglen Length of message.
515 * *MAC Given hash.
516 * maclen Length of given hash; indicates truncation if it is
517 * shorter than the normal size of output for
518 * given hash transform.
519 * Returns:
520 * SNMPERR_SUCCESS Success.
521 * SNMP_SC_GENERAL_FAILURE Any error
522 *
523 *
524 * Check the hash given in MAC against the hash of message. If the length
525 * of MAC is less than the length of the transform hash output, only maclen
526 * bytes are compared. The length of MAC cannot be greater than the
527 * length of the hash transform output.
528 */
529int
530sc_check_keyed_hash(const oid * authtype, size_t authtypelen,
531 u_char * key, u_int keylen,
532 u_char * message, u_int msglen,
533 u_char * MAC, u_int maclen)
534#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
535{
536 int rval = SNMPERR_SUCCESS;
537 size_t buf_len = SNMP_MAXBUF_SMALL;
538
539 u_char buf[SNMP_MAXBUF_SMALL];
540
541 DEBUGTRACE;
542
543#ifdef NETSNMP_ENABLE_TESTING_CODE
544 {
545 int i;
546 DEBUGMSG(("scapi", "sc_check_keyed_hash(): key=0x"));
547 for (i = 0; i < keylen; i++)
548 DEBUGMSG(("scapi", "%02x", key[i] & 0xff));
549 DEBUGMSG(("scapi", " (%d)\n", keylen));
550 }
551#endif /* NETSNMP_ENABLE_TESTING_CODE */
552
553 /*
554 * Sanity check.
555 */
556 if (!authtype || !key || !message || !MAC
557 || (keylen <= 0) || (msglen <= 0) || (maclen <= 0)
558 || (authtypelen != USM_LENGTH_OID_TRANSFORM)) {
559 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
560 }
561
562
563 if (maclen != USM_MD5_AND_SHA_AUTH_LEN) {
564 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
565 }
566
567 /*
568 * Generate a full hash of the message, then compare
569 * the result with the given MAC which may shorter than
570 * the full hash length.
571 */
572 rval = sc_generate_keyed_hash(authtype, authtypelen,
573 key, keylen,
574 message, msglen, buf, &buf_len);
575 QUITFUN(rval, sc_check_keyed_hash_quit);
576
577 if (maclen > msglen) {
578 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
579
580 } else if (memcmp(buf, MAC, maclen) != 0) {
581 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
582 }
583
584
585 sc_check_keyed_hash_quit:
Magnus Fromreidea1986582009-10-14 23:12:05 +0000586 memset(buf, 0, SNMP_MAXBUF_SMALL);
Dave Shield00ef5692011-02-22 08:55:48 +0000587
588 return rval;
589
590} /* end sc_check_keyed_hash() */
591
592#else
593_SCAPI_NOT_CONFIGURED
594#endif /* NETSNMP_USE_INTERNAL_MD5 */
595/*******************************************************************-o-******
596 * sc_encrypt
597 *
598 * Parameters:
599 * privtype Type of privacy cryptographic transform.
600 * *key Key bits for crypting.
601 * keylen Length of key (buffer) in bytes.
602 * *iv IV bits for crypting.
603 * ivlen Length of iv (buffer) in bytes.
604 * *plaintext Plaintext to crypt.
605 * ptlen Length of plaintext.
606 * *ciphertext Ciphertext to crypt.
607 * *ctlen Length of ciphertext.
608 *
609 * Returns:
610 * SNMPERR_SUCCESS Success.
611 * SNMPERR_SC_NOT_CONFIGURED Encryption is not supported.
612 * SNMPERR_SC_GENERAL_FAILURE Any other error
613 *
614 *
615 * Encrypt plaintext into ciphertext using key and iv.
616 *
617 * ctlen contains actual number of crypted bytes in ciphertext upon
618 * successful return.
619 */
620int
621sc_encrypt(const oid * privtype, size_t privtypelen,
622 u_char * key, u_int keylen,
623 u_char * iv, u_int ivlen,
624 u_char * plaintext, u_int ptlen,
625 u_char * ciphertext, size_t * ctlen)
626#if defined(NETSNMP_USE_OPENSSL)
627{
628 int rval = SNMPERR_SUCCESS;
629 u_int properlength = 0, properlength_iv = 0;
630 u_char pad_block[128]; /* bigger than anything I need */
631 u_char my_iv[128]; /* ditto */
632 int pad, plast, pad_size = 0;
633 int have_trans;
634#ifndef NETSNMP_DISABLE_DES
635#ifdef OLD_DES
636 DES_key_schedule key_sch;
637#else
638 DES_key_schedule key_sched_store;
639 DES_key_schedule *key_sch = &key_sched_store;
640#endif
641 DES_cblock key_struct;
642#endif
643#ifdef HAVE_AES
644 AES_KEY aes_key;
645 int new_ivlen = 0;
646#endif
647
648 DEBUGTRACE;
649
650 /*
651 * Sanity check.
652 */
653#if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
654 snmp_log(LOG_ERR, "Encryption support not enabled.\n");
655 return SNMPERR_SC_NOT_CONFIGURED;
656#endif
657
658 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
659 || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0)
660 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
661 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
662 } else if (ptlen > *ctlen) {
663 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
664 }
665#ifdef NETSNMP_ENABLE_TESTING_CODE
666 {
667 size_t buf_len = 128, out_len = 0;
668 u_char *buf = (u_char *) malloc(buf_len);
669
670 if (buf != NULL) {
671 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
672 iv, ivlen)) {
673 DEBUGMSGTL(("scapi", "encrypt: IV: %s/", buf));
674 } else {
675 DEBUGMSGTL(("scapi", "encrypt: IV: %s [TRUNCATED]/", buf));
676 }
677 out_len = 0;
678 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
679 key, keylen)) {
680 DEBUGMSG(("scapi", "%s\n", buf));
681 } else {
682 DEBUGMSG(("scapi", "%s [TRUNCATED]\n", buf));
683 }
684 out_len = 0;
685 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
686 plaintext, 16)) {
687 DEBUGMSGTL(("scapi", "encrypt: string: %s\n", buf));
688 } else {
689 DEBUGMSGTL(("scapi", "encrypt: string: %s [TRUNCATED]\n",
690 buf));
691 }
692 free(buf);
693 } else {
694 DEBUGMSGTL(("scapi",
695 "encrypt: malloc fail for debug output\n"));
696 }
697 }
698#endif /* NETSNMP_ENABLE_TESTING_CODE */
699
700
701 /*
702 * Determine privacy transform.
703 */
704 have_trans = 0;
705#ifndef NETSNMP_DISABLE_DES
706 if (ISTRANSFORM(privtype, DESPriv)) {
707 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
708 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
709 pad_size = properlength;
710 have_trans = 1;
711 }
712#endif
713#ifdef HAVE_AES
714 if (ISTRANSFORM(privtype, AESPriv)) {
715 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
716 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV);
717 have_trans = 1;
718 }
719#endif
720 if (!have_trans) {
721 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
722 }
723
724 if ((keylen < properlength) || (ivlen < properlength_iv)) {
725 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
726 }
727
728 memset(my_iv, 0, sizeof(my_iv));
729
730#ifndef NETSNMP_DISABLE_DES
731 if (ISTRANSFORM(privtype, DESPriv)) {
732
733 /*
734 * now calculate the padding needed
735 */
736 pad = pad_size - (ptlen % pad_size);
737 plast = (int) ptlen - (pad_size - pad);
738 if (pad == pad_size)
739 pad = 0;
740 if (ptlen + pad > *ctlen) {
741 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); /* not enough space */
742 }
743 if (pad > 0) { /* copy data into pad block if needed */
744 memcpy(pad_block, plaintext + plast, pad_size - pad);
745 memset(&pad_block[pad_size - pad], pad, pad); /* filling in padblock */
746 }
747
748 memcpy(key_struct, key, sizeof(key_struct));
749 (void) DES_key_sched(&key_struct, key_sch);
750
751 memcpy(my_iv, iv, ivlen);
752 /*
753 * encrypt the data
754 */
755 DES_ncbc_encrypt(plaintext, ciphertext, plast, key_sch,
756 (DES_cblock *) my_iv, DES_ENCRYPT);
757 if (pad > 0) {
758 /*
759 * then encrypt the pad block
760 */
761 DES_ncbc_encrypt(pad_block, ciphertext + plast, pad_size,
762 key_sch, (DES_cblock *) my_iv, DES_ENCRYPT);
763 *ctlen = plast + pad_size;
764 } else {
765 *ctlen = plast;
766 }
767 }
768#endif
769#ifdef HAVE_AES
770 if (ISTRANSFORM(privtype, AESPriv)) {
771 (void) AES_set_encrypt_key(key, properlength*8, &aes_key);
772
773 memcpy(my_iv, iv, ivlen);
774 /*
775 * encrypt the data
776 */
777 AES_cfb128_encrypt(plaintext, ciphertext, ptlen,
778 &aes_key, my_iv, &new_ivlen, AES_ENCRYPT);
779 *ctlen = ptlen;
780 }
781#endif
782 sc_encrypt_quit:
783 /*
784 * clear memory just in case
785 */
786 memset(my_iv, 0, sizeof(my_iv));
787 memset(pad_block, 0, sizeof(pad_block));
788#ifndef NETSNMP_DISABLE_DES
789 memset(key_struct, 0, sizeof(key_struct));
790#ifdef OLD_DES
791 memset(&key_sch, 0, sizeof(key_sch));
792#else
793 memset(&key_sched_store, 0, sizeof(key_sched_store));
794#endif
795#endif
796#ifdef HAVE_AES
797 memset(&aes_key,0,sizeof(aes_key));
798#endif
799 return rval;
800
801} /* end sc_encrypt() */
802#elif defined(NETSNMP_USE_PKCS11)
803{
804 int rval = SNMPERR_SUCCESS;
805 u_int properlength, properlength_iv;
806 u_char pkcs_des_key[8];
807
808 DEBUGTRACE;
809
810 /*
811 * Sanity check.
812 */
813#if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
814 snmp_log(LOG_ERR, "Encryption support not enabled.\n");
815 return SNMPERR_SC_NOT_CONFIGURED;
816#endif
817
818 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
819 || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0)
820 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
821 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
822 } else if (ptlen > *ctlen) {
823 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
824 }
825
826 /*
827 * Determine privacy transform.
828 */
829 if (ISTRANSFORM(privtype, DESPriv)) {
830 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
831 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
832 } else {
833 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
834 }
835
836 if ((keylen < properlength) || (ivlen < properlength_iv)) {
837 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
838 }
839
840 if (ISTRANSFORM(privtype, DESPriv)) {
841 memset(pkcs_des_key, 0, sizeof(pkcs_des_key));
842 memcpy(pkcs_des_key, key, sizeof(pkcs_des_key));
843 rval = pkcs_encrpyt(CKM_DES_CBC, pkcs_des_key,
844 sizeof(pkcs_des_key), iv, ivlen, plaintext, ptlen,
845 ciphertext, ctlen);
846 }
847
848 sc_encrypt_quit:
849 return rval;
850}
851#else
852{
853# if NETSNMP_USE_INTERNAL_MD5
854 {
855 snmp_log(LOG_ERR, "Encryption support not enabled.\n");
856 DEBUGMSGTL(("scapi", "Encrypt function not defined.\n"));
857 return SNMPERR_SC_GENERAL_FAILURE;
858 }
859
860# else
861 _SCAPI_NOT_CONFIGURED
862# endif /* NETSNMP_USE_INTERNAL_MD5 */
863}
864#endif /* */
865
866
867
868/*******************************************************************-o-******
869 * sc_decrypt
870 *
871 * Parameters:
872 * privtype
873 * *key
874 * keylen
875 * *iv
876 * ivlen
877 * *ciphertext
878 * ctlen
879 * *plaintext
880 * *ptlen
881 *
882 * Returns:
883 * SNMPERR_SUCCESS Success.
884 * SNMPERR_SC_NOT_CONFIGURED Encryption is not supported.
885 * SNMPERR_SC_GENERAL_FAILURE Any other error
886 *
887 *
888 * Decrypt ciphertext into plaintext using key and iv.
889 *
890 * ptlen contains actual number of plaintext bytes in plaintext upon
891 * successful return.
892 */
893int
894sc_decrypt(const oid * privtype, size_t privtypelen,
895 u_char * key, u_int keylen,
896 u_char * iv, u_int ivlen,
897 u_char * ciphertext, u_int ctlen,
898 u_char * plaintext, size_t * ptlen)
899#ifdef NETSNMP_USE_OPENSSL
900{
901
902 int rval = SNMPERR_SUCCESS;
903 u_char my_iv[128];
904#ifndef NETSNMP_DISABLE_DES
905#ifdef OLD_DES
906 DES_key_schedule key_sch;
907#else
908 DES_key_schedule key_sched_store;
909 DES_key_schedule *key_sch = &key_sched_store;
910#endif
911 DES_cblock key_struct;
912#endif
913 u_int properlength = 0, properlength_iv = 0;
914 int have_transform;
915#ifdef HAVE_AES
916 int new_ivlen = 0;
917 AES_KEY aes_key;
918#endif
919
920 DEBUGTRACE;
921
922 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
923 || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)
924 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
925 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
926 }
927#ifdef NETSNMP_ENABLE_TESTING_CODE
928 {
929 size_t buf_len = 128, out_len = 0;
930 u_char *buf = (u_char *) malloc(buf_len);
931
932 if (buf != NULL) {
933 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
934 iv, ivlen)) {
935 DEBUGMSGTL(("scapi", "decrypt: IV: %s/", buf));
936 } else {
937 DEBUGMSGTL(("scapi", "decrypt: IV: %s [TRUNCATED]/", buf));
938 }
939 out_len = 0;
940 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
941 key, keylen)) {
942 DEBUGMSG(("scapi", "%s\n", buf));
943 } else {
944 DEBUGMSG(("scapi", "%s\n", buf));
945 }
946 free(buf);
947 } else {
948 DEBUGMSGTL(("scapi",
949 "decrypt: malloc fail for debug output\n"));
950 }
951 }
952#endif /* NETSNMP_ENABLE_TESTING_CODE */
953
954 /*
955 * Determine privacy transform.
956 */
957 have_transform = 0;
958#ifndef NETSNMP_DISABLE_DES
959 if (ISTRANSFORM(privtype, DESPriv)) {
960 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
961 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
962 have_transform = 1;
963 }
964#endif
965#ifdef HAVE_AES
966 if (ISTRANSFORM(privtype, AESPriv)) {
967 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES);
968 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV);
969 have_transform = 1;
970 }
971#endif
972 if (!have_transform) {
973 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
974 }
975
976 if ((keylen < properlength) || (ivlen < properlength_iv)) {
977 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
978 }
979
980 memset(my_iv, 0, sizeof(my_iv));
981#ifndef NETSNMP_DISABLE_DES
982 if (ISTRANSFORM(privtype, DESPriv)) {
983 memcpy(key_struct, key, sizeof(key_struct));
984 (void) DES_key_sched(&key_struct, key_sch);
985
986 memcpy(my_iv, iv, ivlen);
987 DES_cbc_encrypt(ciphertext, plaintext, ctlen, key_sch,
988 (DES_cblock *) my_iv, DES_DECRYPT);
989 *ptlen = ctlen;
990 }
991#endif
992#ifdef HAVE_AES
993 if (ISTRANSFORM(privtype, AESPriv)) {
994 (void) AES_set_encrypt_key(key, properlength*8, &aes_key);
995
996 memcpy(my_iv, iv, ivlen);
997 /*
998 * encrypt the data
999 */
1000 AES_cfb128_encrypt(ciphertext, plaintext, ctlen,
1001 &aes_key, my_iv, &new_ivlen, AES_DECRYPT);
1002 *ptlen = ctlen;
1003 }
1004#endif
1005
1006 /*
1007 * exit cond
1008 */
1009 sc_decrypt_quit:
1010#ifndef NETSNMP_DISABLE_DES
1011#ifdef OLD_DES
1012 memset(&key_sch, 0, sizeof(key_sch));
1013#else
1014 memset(&key_sched_store, 0, sizeof(key_sched_store));
1015#endif
1016 memset(key_struct, 0, sizeof(key_struct));
1017#endif
1018 memset(my_iv, 0, sizeof(my_iv));
1019 return rval;
1020} /* USE OPEN_SSL */
1021#elif NETSNMP_USE_PKCS11 /* USE PKCS */
1022{
1023 int rval = SNMPERR_SUCCESS;
1024 u_int properlength, properlength_iv;
1025 u_char pkcs_des_key[8];
1026
1027 DEBUGTRACE;
1028
1029 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
1030 || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)
1031 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
1032 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
1033 }
1034
1035 /*
1036 * Determine privacy transform.
1037 */
1038 if (ISTRANSFORM(privtype, DESPriv)) {
1039 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
1040 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
1041 } else {
1042 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
1043 }
1044
1045 if ((keylen < properlength) || (ivlen < properlength_iv)) {
1046 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
1047 }
1048
1049 if (ISTRANSFORM(privtype, DESPriv)) {
1050 memset(pkcs_des_key, 0, sizeof(pkcs_des_key));
1051 memcpy(pkcs_des_key, key, sizeof(pkcs_des_key));
1052 rval = pkcs_decrpyt(CKM_DES_CBC, pkcs_des_key,
1053 sizeof(pkcs_des_key), iv, ivlen, ciphertext,
1054 ctlen, plaintext, ptlen);
1055 *ptlen = ctlen;
1056 }
1057
1058 sc_decrypt_quit:
1059 return rval;
1060} /* USE PKCS */
1061#else
1062{
1063#if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
1064 snmp_log(LOG_ERR, "Encryption support not enabled.\n");
1065 return SNMPERR_SC_NOT_CONFIGURED;
1066#else
1067# if NETSNMP_USE_INTERNAL_MD5
1068 {
1069 DEBUGMSGTL(("scapi", "Decryption function not defined.\n"));
1070 return SNMPERR_SC_GENERAL_FAILURE;
1071 }
1072
1073# else
1074 _SCAPI_NOT_CONFIGURED
1075# endif /* NETSNMP_USE_INTERNAL_MD5 */
1076#endif /* */
1077}
1078#endif /* NETSNMP_USE_OPENSSL */