1 /**
2 * collectd - src/libcollectdclient/network_buffer.c
3 * Copyright (C) 2010-2012 Florian octo Forster
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Florian octo Forster <octo at collectd.org>
25 **/
27 #include "config.h"
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 #include <assert.h>
33 #include <errno.h>
34 #include <arpa/inet.h> /* htons */
36 #include <pthread.h>
38 #if HAVE_LIBGCRYPT
39 #include <gcrypt.h>
40 GCRY_THREAD_OPTION_PTHREAD_IMPL;
41 #endif
43 #include "collectd/network_buffer.h"
45 #define TYPE_HOST 0x0000
46 #define TYPE_TIME 0x0001
47 #define TYPE_PLUGIN 0x0002
48 #define TYPE_PLUGIN_INSTANCE 0x0003
49 #define TYPE_TYPE 0x0004
50 #define TYPE_TYPE_INSTANCE 0x0005
51 #define TYPE_VALUES 0x0006
52 #define TYPE_INTERVAL 0x0007
54 /* Types to transmit notifications */
55 #define TYPE_MESSAGE 0x0100
56 #define TYPE_SEVERITY 0x0101
58 #define TYPE_SIGN_SHA256 0x0200
59 #define TYPE_ENCR_AES256 0x0210
61 #define PART_SIGNATURE_SHA256_SIZE 36
62 #define PART_ENCRYPTION_AES256_SIZE 42
64 #define ADD_GENERIC(nb,srcptr,size) do { \
65 assert ((size) <= (nb)->free); \
66 memcpy ((nb)->ptr, (srcptr), (size)); \
67 (nb)->ptr += (size); \
68 (nb)->free -= (size); \
69 } while (0)
71 #define ADD_STATIC(nb,var) \
72 ADD_GENERIC(nb,&(var),sizeof(var));
74 /*
75 * Data types
76 */
77 struct lcc_network_buffer_s
78 {
79 char *buffer;
80 size_t size;
82 lcc_value_list_t state;
83 char *ptr;
84 size_t free;
86 lcc_security_level_t seclevel;
87 char *username;
88 char *password;
90 gcry_cipher_hd_t encr_cypher;
91 size_t encr_header_len;
92 char encr_iv[16];
93 };
95 #define SSTRNCPY(dst,src,sz) do { \
96 strncpy ((dst), (src), (sz)); \
97 (dst)[(sz) - 1] = 0; \
98 } while (0)
100 /*
101 * Private functions
102 */
103 static _Bool have_gcrypt (void) /* {{{ */
104 {
105 static _Bool result = 0;
106 static _Bool need_init = 1;
108 if (!need_init)
109 return (result);
110 need_init = 0;
112 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
114 if (!gcry_check_version (GCRYPT_VERSION))
115 return (0);
117 gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
118 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
120 result = 1;
121 return (1);
122 } /* }}} _Bool have_gcrypt */
124 static uint64_t htonll (uint64_t val) /* {{{ */
125 {
126 static int config = 0;
128 uint32_t hi;
129 uint32_t lo;
131 if (config == 0)
132 {
133 uint16_t h = 0x1234;
134 uint16_t n = htons (h);
136 if (h == n)
137 config = 1;
138 else
139 config = 2;
140 }
142 if (config == 1)
143 return (val);
145 hi = (uint32_t) (val >> 32);
146 lo = (uint32_t) (val & 0x00000000FFFFFFFF);
148 hi = htonl (hi);
149 lo = htonl (lo);
151 return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
152 } /* }}} uint64_t htonll */
154 static double htond (double val) /* {{{ */
155 {
156 static int config = 0;
158 union { uint8_t byte[8]; double floating; } in;
159 union { uint8_t byte[8]; double floating; } out;
161 if (config == 0)
162 {
163 double d = 8.642135e130;
164 uint8_t c[8];
166 memcpy (c, &d, 8);
168 if ((c[0] == 0x2f) && (c[1] == 0x25)
169 && (c[2] == 0xc0) && (c[3] == 0xc7)
170 && (c[4] == 0x43) && (c[5] == 0x2b)
171 && (c[6] == 0x1f) && (c[7] == 0x5b))
172 config = 1; /* need nothing */
173 else if ((c[7] == 0x2f) && (c[6] == 0x25)
174 && (c[5] == 0xc0) && (c[4] == 0xc7)
175 && (c[3] == 0x43) && (c[2] == 0x2b)
176 && (c[1] == 0x1f) && (c[0] == 0x5b))
177 config = 2; /* endian flip */
178 else if ((c[4] == 0x2f) && (c[5] == 0x25)
179 && (c[6] == 0xc0) && (c[7] == 0xc7)
180 && (c[0] == 0x43) && (c[1] == 0x2b)
181 && (c[2] == 0x1f) && (c[3] == 0x5b))
182 config = 3; /* int swap */
183 else
184 config = 4;
185 }
187 if (isnan (val))
188 {
189 out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
190 out.byte[4] = out.byte[5] = 0x00;
191 out.byte[6] = 0xf8;
192 out.byte[7] = 0x7f;
193 return (out.floating);
194 }
195 else if (config == 1)
196 return (val);
197 else if (config == 2)
198 {
199 in.floating = val;
200 out.byte[0] = in.byte[7];
201 out.byte[1] = in.byte[6];
202 out.byte[2] = in.byte[5];
203 out.byte[3] = in.byte[4];
204 out.byte[4] = in.byte[3];
205 out.byte[5] = in.byte[2];
206 out.byte[6] = in.byte[1];
207 out.byte[7] = in.byte[0];
208 return (out.floating);
209 }
210 else if (config == 3)
211 {
212 in.floating = val;
213 out.byte[0] = in.byte[4];
214 out.byte[1] = in.byte[5];
215 out.byte[2] = in.byte[6];
216 out.byte[3] = in.byte[7];
217 out.byte[4] = in.byte[0];
218 out.byte[5] = in.byte[1];
219 out.byte[6] = in.byte[2];
220 out.byte[7] = in.byte[3];
221 return (out.floating);
222 }
223 else
224 {
225 /* If in doubt, just copy the value back to the caller. */
226 return (val);
227 }
228 } /* }}} double htond */
230 static int nb_add_values (char **ret_buffer, /* {{{ */
231 size_t *ret_buffer_len,
232 const lcc_value_list_t *vl)
233 {
234 char *packet_ptr;
235 size_t packet_len;
237 uint16_t pkg_type;
238 uint16_t pkg_length;
239 uint16_t pkg_num_values;
240 uint8_t pkg_values_types[vl->values_len];
241 value_t pkg_values[vl->values_len];
243 size_t offset;
244 size_t i;
246 packet_len = sizeof (pkg_type) + sizeof (pkg_length)
247 + sizeof (pkg_num_values)
248 + sizeof (pkg_values_types)
249 + sizeof (pkg_values);
251 if (*ret_buffer_len < packet_len)
252 return (ENOMEM);
254 pkg_type = htons (TYPE_VALUES);
255 pkg_length = htons ((uint16_t) packet_len);
256 pkg_num_values = htons ((uint16_t) vl->values_len);
258 for (i = 0; i < vl->values_len; i++)
259 {
260 pkg_values_types[i] = (uint8_t) vl->values_types[i];
261 switch (vl->values_types[i])
262 {
263 case LCC_TYPE_COUNTER:
264 pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
265 break;
267 case LCC_TYPE_GAUGE:
268 pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
269 break;
271 case LCC_TYPE_DERIVE:
272 pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
273 break;
275 case LCC_TYPE_ABSOLUTE:
276 pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
277 break;
279 default:
280 return (EINVAL);
281 } /* switch (vl->values_types[i]) */
282 } /* for (vl->values_len) */
284 /*
285 * Use `memcpy' to write everything to the buffer, because the pointer
286 * may be unaligned and some architectures, such as SPARC, can't handle
287 * that.
288 */
289 packet_ptr = *ret_buffer;
290 offset = 0;
291 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
292 offset += sizeof (pkg_type);
293 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
294 offset += sizeof (pkg_length);
295 memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
296 offset += sizeof (pkg_num_values);
297 memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
298 offset += sizeof (pkg_values_types);
299 memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
300 offset += sizeof (pkg_values);
302 assert (offset == packet_len);
304 *ret_buffer = packet_ptr + packet_len;
305 *ret_buffer_len -= packet_len;
306 return (0);
307 } /* }}} int nb_add_values */
309 static int nb_add_number (char **ret_buffer, /* {{{ */
310 size_t *ret_buffer_len,
311 uint16_t type, uint64_t value)
312 {
313 char *packet_ptr;
314 size_t packet_len;
316 uint16_t pkg_type;
317 uint16_t pkg_length;
318 uint64_t pkg_value;
320 size_t offset;
322 packet_len = sizeof (pkg_type)
323 + sizeof (pkg_length)
324 + sizeof (pkg_value);
326 if (*ret_buffer_len < packet_len)
327 return (ENOMEM);
329 pkg_type = htons (type);
330 pkg_length = htons ((uint16_t) packet_len);
331 pkg_value = htonll (value);
333 packet_ptr = *ret_buffer;
334 offset = 0;
335 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
336 offset += sizeof (pkg_type);
337 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
338 offset += sizeof (pkg_length);
339 memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
340 offset += sizeof (pkg_value);
342 assert (offset == packet_len);
344 *ret_buffer = packet_ptr + packet_len;
345 *ret_buffer_len -= packet_len;
346 return (0);
347 } /* }}} int nb_add_number */
349 static int nb_add_string (char **ret_buffer, /* {{{ */
350 size_t *ret_buffer_len,
351 uint16_t type, const char *str, size_t str_len)
352 {
353 char *packet_ptr;
354 size_t packet_len;
356 uint16_t pkg_type;
357 uint16_t pkg_length;
359 size_t offset;
361 packet_len = sizeof (pkg_type)
362 + sizeof (pkg_length)
363 + str_len + 1;
364 if (*ret_buffer_len < packet_len)
365 return (ENOMEM);
367 pkg_type = htons (type);
368 pkg_length = htons ((uint16_t) packet_len);
370 packet_ptr = *ret_buffer;
371 offset = 0;
372 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
373 offset += sizeof (pkg_type);
374 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
375 offset += sizeof (pkg_length);
376 memcpy (packet_ptr + offset, str, str_len);
377 offset += str_len;
378 memset (packet_ptr + offset, 0, 1);
379 offset += 1;
381 assert (offset == packet_len);
383 *ret_buffer = packet_ptr + packet_len;
384 *ret_buffer_len -= packet_len;
385 return (0);
386 } /* }}} int nb_add_string */
388 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
389 const lcc_value_list_t *vl)
390 {
391 char *buffer = nb->ptr;
392 size_t buffer_size = nb->free;
394 const lcc_identifier_t *ident_src;
395 lcc_identifier_t *ident_dst;
397 ident_src = &vl->identifier;
398 ident_dst = &nb->state.identifier;
400 if (strcmp (ident_dst->host, ident_src->host) != 0)
401 {
402 if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
403 ident_src->host, strlen (ident_src->host)) != 0)
404 return (-1);
405 SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
406 }
408 if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
409 {
410 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
411 ident_src->plugin, strlen (ident_src->plugin)) != 0)
412 return (-1);
413 SSTRNCPY (ident_dst->plugin, ident_src->plugin,
414 sizeof (ident_dst->plugin));
415 }
417 if (strcmp (ident_dst->plugin_instance,
418 ident_src->plugin_instance) != 0)
419 {
420 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
421 ident_src->plugin_instance,
422 strlen (ident_src->plugin_instance)) != 0)
423 return (-1);
424 SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
425 sizeof (ident_dst->plugin_instance));
426 }
428 if (strcmp (ident_dst->type, ident_src->type) != 0)
429 {
430 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
431 ident_src->type, strlen (ident_src->type)) != 0)
432 return (-1);
433 SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
434 }
436 if (strcmp (ident_dst->type_instance,
437 ident_src->type_instance) != 0)
438 {
439 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
440 ident_src->type_instance,
441 strlen (ident_src->type_instance)) != 0)
442 return (-1);
443 SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
444 sizeof (ident_dst->type_instance));
445 }
447 if (nb->state.time != vl->time)
448 {
449 if (nb_add_number (&buffer, &buffer_size, TYPE_TIME,
450 (uint64_t) vl->time))
451 return (-1);
452 nb->state.time = vl->time;
453 }
455 if (nb->state.interval != vl->interval)
456 {
457 if (nb_add_number (&buffer, &buffer_size, TYPE_INTERVAL,
458 (uint64_t) vl->interval))
459 return (-1);
460 nb->state.interval = vl->interval;
461 }
463 if (nb_add_values (&buffer, &buffer_size, vl) != 0)
464 return (-1);
466 nb->ptr = buffer;
467 nb->free = buffer_size;
468 return (0);
469 } /* }}} int nb_add_value_list */
471 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
472 {
473 char *buffer;
474 size_t buffer_size;
476 gcry_md_hd_t hd;
477 gcry_error_t err;
478 unsigned char *hash;
479 const size_t hash_length = 32;
481 /* The type, length and username have already been filled in by
482 * "lcc_network_buffer_initialize". All we do here is calculate the hash over
483 * the username and the data and add the hash value to the buffer. */
485 buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
486 assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
487 buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
489 hd = NULL;
490 err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
491 if (err != 0)
492 return (-1);
494 assert (nb->password != NULL);
495 err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
496 if (err != 0)
497 {
498 gcry_md_close (hd);
499 return (-1);
500 }
502 gcry_md_write (hd, buffer, buffer_size);
503 hash = gcry_md_read (hd, GCRY_MD_SHA256);
504 if (hash == NULL)
505 {
506 gcry_md_close (hd);
507 return (-1);
508 }
510 assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
511 memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
513 gcry_md_close (hd);
514 return (0);
515 } /* }}} int nb_add_signature */
517 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
518 {
519 size_t package_length;
520 char *encr_ptr; /* pointer to data being encrypted */
521 size_t encr_size;
523 char *hash_ptr; /* pointer to data being hashed */
524 size_t hash_size;
525 char hash[20];
527 uint16_t pkg_length;
528 gcry_error_t err;
530 /* Fill in the package length */
531 package_length = nb->size - nb->free;
532 pkg_length = htons ((uint16_t) package_length);
533 memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
535 /* Calculate what to hash */
536 hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
537 hash_size = package_length - nb->encr_header_len;
539 /* Calculate what to encrypt */
540 encr_ptr = hash_ptr - sizeof (hash);
541 encr_size = hash_size + sizeof (hash);
543 /* Calculate the SHA-1 hash */
544 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
545 memcpy (encr_ptr, hash, sizeof (hash));
547 if (nb->encr_cypher == NULL)
548 {
549 unsigned char password_hash[32];
551 err = gcry_cipher_open (&nb->encr_cypher,
552 GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
553 if (err != 0)
554 return (-1);
556 /* Calculate our 256bit key used for AES */
557 gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
558 nb->password, strlen (nb->password));
560 err = gcry_cipher_setkey (nb->encr_cypher,
561 password_hash, sizeof (password_hash));
562 if (err != 0)
563 {
564 gcry_cipher_close (nb->encr_cypher);
565 nb->encr_cypher = NULL;
566 return (-1);
567 }
568 }
569 else /* if (nb->encr_cypher != NULL) */
570 {
571 gcry_cipher_reset (nb->encr_cypher);
572 }
574 /* Set the initialization vector */
575 err = gcry_cipher_setiv (nb->encr_cypher,
576 nb->encr_iv, sizeof (nb->encr_iv));
577 if (err != 0)
578 {
579 gcry_cipher_close (nb->encr_cypher);
580 nb->encr_cypher = NULL;
581 return (-1);
582 }
584 /* Encrypt the buffer in-place */
585 err = gcry_cipher_encrypt (nb->encr_cypher,
586 encr_ptr, encr_size,
587 /* in = */ NULL, /* in len = */ 0);
588 if (err != 0)
589 {
590 gcry_cipher_close (nb->encr_cypher);
591 nb->encr_cypher = NULL;
592 return (-1);
593 }
595 return (0);
596 } /* }}} int nb_add_encryption */
598 /*
599 * Public functions
600 */
601 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
602 {
603 lcc_network_buffer_t *nb;
605 if (size == 0)
606 size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
608 if (size < 128)
609 {
610 errno = EINVAL;
611 return (NULL);
612 }
614 nb = malloc (sizeof (*nb));
615 if (nb == NULL)
616 return (NULL);
617 memset (nb, 0, sizeof (*nb));
619 nb->size = size;
620 nb->buffer = malloc (nb->size);
621 if (nb->buffer == NULL)
622 {
623 free (nb);
624 return (NULL);
625 }
626 memset (nb->buffer, 0, nb->size);
628 nb->ptr = nb->buffer;
629 nb->free = nb->size;
631 nb->seclevel = NONE;
632 nb->username = NULL;
633 nb->password = NULL;
635 return (nb);
636 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
638 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
639 {
640 if (nb == NULL)
641 return;
643 free (nb->buffer);
644 free (nb);
645 } /* }}} void lcc_network_buffer_destroy */
647 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
648 lcc_security_level_t level,
649 const char *username, const char *password)
650 {
651 char *username_copy;
652 char *password_copy;
654 if (level == NONE)
655 {
656 free (nb->username);
657 free (nb->password);
658 nb->username = NULL;
659 nb->password = NULL;
660 nb->seclevel = NONE;
661 lcc_network_buffer_initialize (nb);
662 return (0);
663 }
665 if (!have_gcrypt ())
666 return (ENOTSUP);
668 username_copy = strdup (username);
669 password_copy = strdup (password);
670 if ((username_copy == NULL) || (password_copy == NULL))
671 {
672 free (username_copy);
673 free (password_copy);
674 return (ENOMEM);
675 }
677 free (nb->username);
678 free (nb->password);
679 nb->username = username_copy;
680 nb->password = password_copy;
681 nb->seclevel = level;
683 lcc_network_buffer_initialize (nb);
684 return (0);
685 } /* }}} int lcc_network_buffer_set_security_level */
687 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
688 {
689 if (nb == NULL)
690 return (EINVAL);
692 memset (nb->buffer, 0, nb->size);
693 memset (&nb->state, 0, sizeof (nb->state));
694 nb->ptr = nb->buffer;
695 nb->free = nb->size;
697 if (nb->seclevel == SIGN)
698 {
699 size_t username_len;
700 uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
701 uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
703 assert (nb->username != NULL);
704 username_len = strlen (nb->username);
705 pkg_length = htons (pkg_length + ((uint16_t) username_len));
707 /* Fill in everything but the hash value here. */
708 memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
709 memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
710 nb->ptr += PART_SIGNATURE_SHA256_SIZE;
711 nb->free -= PART_SIGNATURE_SHA256_SIZE;
713 memcpy (nb->ptr, nb->username, username_len);
714 nb->ptr += username_len;
715 nb->free -= username_len;
716 }
717 else if (nb->seclevel == ENCRYPT)
718 {
719 size_t username_length = strlen (nb->username);
720 uint16_t pkg_type = htons (TYPE_ENCR_AES256);
721 uint16_t pkg_length = 0; /* Filled in in finalize. */
722 uint16_t pkg_user_len = htons ((uint16_t) username_length);
723 char hash[20];
725 nb->encr_header_len = username_length;
726 nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
728 gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
729 GCRY_STRONG_RANDOM);
731 /* Filled in in finalize. */
732 memset (hash, 0, sizeof (hash));
734 ADD_STATIC (nb, pkg_type);
735 ADD_STATIC (nb, pkg_length);
736 ADD_STATIC (nb, pkg_user_len);
737 ADD_GENERIC (nb, nb->username, username_length);
738 ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
739 ADD_GENERIC (nb, hash, sizeof (hash));
740 assert ((nb->encr_header_len + nb->free) == nb->size);
741 }
743 return (0);
744 } /* }}} int lcc_network_buffer_initialize */
746 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
747 {
748 if (nb == NULL)
749 return (EINVAL);
751 if (nb->seclevel == SIGN)
752 nb_add_signature (nb);
753 else if (nb->seclevel == ENCRYPT)
754 nb_add_encryption (nb);
756 return (0);
757 } /* }}} int lcc_network_buffer_finalize */
759 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
760 const lcc_value_list_t *vl)
761 {
762 int status;
764 if ((nb == NULL) || (vl == NULL))
765 return (EINVAL);
767 status = nb_add_value_list (nb, vl);
768 return (status);
769 } /* }}} int lcc_network_buffer_add_value */
771 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
772 void *buffer, size_t *buffer_size)
773 {
774 size_t sz_required;
775 size_t sz_available;
777 if ((nb == NULL) || (buffer_size == NULL))
778 return (EINVAL);
780 assert (nb->size >= nb->free);
781 sz_required = nb->size - nb->free;
782 sz_available = *buffer_size;
784 *buffer_size = sz_required;
785 if (buffer != NULL)
786 memcpy (buffer, nb->buffer,
787 (sz_available < sz_required) ? sz_available : sz_required);
789 return (0);
790 } /* }}} int lcc_network_buffer_get */
792 /* vim: set sw=2 sts=2 et fdm=marker : */