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 <pthread.h>
40 # if defined __APPLE__
41 /* default xcode compiler throws warnings even when deprecated functionality
42 * is not used. -Werror breaks the build because of erroneous warnings.
43 * http://stackoverflow.com/questions/10556299/compiler-warnings-with-libgcrypt-v1-5-0/12830209#12830209
44 */
45 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
46 # endif
47 /* FreeBSD's copy of libgcrypt extends the existing GCRYPT_NO_DEPRECATED
48 * to properly hide all deprecated functionality.
49 * http://svnweb.freebsd.org/ports/head/security/libgcrypt/files/patch-src__gcrypt.h.in
50 */
51 # define GCRYPT_NO_DEPRECATED
52 # include <gcrypt.h>
53 # if defined __APPLE__
54 /* Re enable deprecation warnings */
55 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
56 # endif
57 GCRY_THREAD_OPTION_PTHREAD_IMPL;
58 #endif
60 #include "collectd/network_buffer.h"
62 #define TYPE_HOST 0x0000
63 #define TYPE_TIME 0x0001
64 #define TYPE_TIME_HR 0x0008
65 #define TYPE_PLUGIN 0x0002
66 #define TYPE_PLUGIN_INSTANCE 0x0003
67 #define TYPE_TYPE 0x0004
68 #define TYPE_TYPE_INSTANCE 0x0005
69 #define TYPE_VALUES 0x0006
70 #define TYPE_INTERVAL 0x0007
71 #define TYPE_INTERVAL_HR 0x0009
73 /* Types to transmit notifications */
74 #define TYPE_MESSAGE 0x0100
75 #define TYPE_SEVERITY 0x0101
77 #define TYPE_SIGN_SHA256 0x0200
78 #define TYPE_ENCR_AES256 0x0210
80 #define PART_SIGNATURE_SHA256_SIZE 36
81 #define PART_ENCRYPTION_AES256_SIZE 42
83 #define ADD_GENERIC(nb,srcptr,size) do { \
84 assert ((size) <= (nb)->free); \
85 memcpy ((nb)->ptr, (srcptr), (size)); \
86 (nb)->ptr += (size); \
87 (nb)->free -= (size); \
88 } while (0)
90 #define ADD_STATIC(nb,var) \
91 ADD_GENERIC(nb,&(var),sizeof(var));
93 /*
94 * Data types
95 */
96 struct lcc_network_buffer_s
97 {
98 char *buffer;
99 size_t size;
101 lcc_value_list_t state;
102 char *ptr;
103 size_t free;
105 lcc_security_level_t seclevel;
106 char *username;
107 char *password;
109 gcry_cipher_hd_t encr_cypher;
110 size_t encr_header_len;
111 char encr_iv[16];
112 };
114 #define SSTRNCPY(dst,src,sz) do { \
115 strncpy ((dst), (src), (sz)); \
116 (dst)[(sz) - 1] = 0; \
117 } while (0)
119 /*
120 * Private functions
121 */
122 static _Bool have_gcrypt (void) /* {{{ */
123 {
124 static _Bool result = 0;
125 static _Bool need_init = 1;
127 if (!need_init)
128 return (result);
129 need_init = 0;
131 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
133 if (!gcry_check_version (GCRYPT_VERSION))
134 return (0);
136 gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
137 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
139 result = 1;
140 return (1);
141 } /* }}} _Bool have_gcrypt */
143 static uint64_t htonll (uint64_t val) /* {{{ */
144 {
145 static int config = 0;
147 uint32_t hi;
148 uint32_t lo;
150 if (config == 0)
151 {
152 uint16_t h = 0x1234;
153 uint16_t n = htons (h);
155 if (h == n)
156 config = 1;
157 else
158 config = 2;
159 }
161 if (config == 1)
162 return (val);
164 hi = (uint32_t) (val >> 32);
165 lo = (uint32_t) (val & 0x00000000FFFFFFFF);
167 hi = htonl (hi);
168 lo = htonl (lo);
170 return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
171 } /* }}} uint64_t htonll */
173 static double htond (double val) /* {{{ */
174 {
175 static int config = 0;
177 union { uint8_t byte[8]; double floating; } in;
178 union { uint8_t byte[8]; double floating; } out;
180 if (config == 0)
181 {
182 double d = 8.642135e130;
183 uint8_t c[8];
185 memcpy (c, &d, 8);
187 if ((c[0] == 0x2f) && (c[1] == 0x25)
188 && (c[2] == 0xc0) && (c[3] == 0xc7)
189 && (c[4] == 0x43) && (c[5] == 0x2b)
190 && (c[6] == 0x1f) && (c[7] == 0x5b))
191 config = 1; /* need nothing */
192 else if ((c[7] == 0x2f) && (c[6] == 0x25)
193 && (c[5] == 0xc0) && (c[4] == 0xc7)
194 && (c[3] == 0x43) && (c[2] == 0x2b)
195 && (c[1] == 0x1f) && (c[0] == 0x5b))
196 config = 2; /* endian flip */
197 else if ((c[4] == 0x2f) && (c[5] == 0x25)
198 && (c[6] == 0xc0) && (c[7] == 0xc7)
199 && (c[0] == 0x43) && (c[1] == 0x2b)
200 && (c[2] == 0x1f) && (c[3] == 0x5b))
201 config = 3; /* int swap */
202 else
203 config = 4;
204 }
206 if (isnan (val))
207 {
208 out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
209 out.byte[4] = out.byte[5] = 0x00;
210 out.byte[6] = 0xf8;
211 out.byte[7] = 0x7f;
212 return (out.floating);
213 }
214 else if (config == 1)
215 return (val);
216 else if (config == 2)
217 {
218 in.floating = val;
219 out.byte[0] = in.byte[7];
220 out.byte[1] = in.byte[6];
221 out.byte[2] = in.byte[5];
222 out.byte[3] = in.byte[4];
223 out.byte[4] = in.byte[3];
224 out.byte[5] = in.byte[2];
225 out.byte[6] = in.byte[1];
226 out.byte[7] = in.byte[0];
227 return (out.floating);
228 }
229 else if (config == 3)
230 {
231 in.floating = val;
232 out.byte[0] = in.byte[4];
233 out.byte[1] = in.byte[5];
234 out.byte[2] = in.byte[6];
235 out.byte[3] = in.byte[7];
236 out.byte[4] = in.byte[0];
237 out.byte[5] = in.byte[1];
238 out.byte[6] = in.byte[2];
239 out.byte[7] = in.byte[3];
240 return (out.floating);
241 }
242 else
243 {
244 /* If in doubt, just copy the value back to the caller. */
245 return (val);
246 }
247 } /* }}} double htond */
249 static int nb_add_values (char **ret_buffer, /* {{{ */
250 size_t *ret_buffer_len,
251 const lcc_value_list_t *vl)
252 {
253 char *packet_ptr;
254 size_t packet_len;
256 uint16_t pkg_type;
257 uint16_t pkg_length;
258 uint16_t pkg_num_values;
259 uint8_t pkg_values_types[vl->values_len];
260 value_t pkg_values[vl->values_len];
262 size_t offset;
263 size_t i;
265 packet_len = sizeof (pkg_type) + sizeof (pkg_length)
266 + sizeof (pkg_num_values)
267 + sizeof (pkg_values_types)
268 + sizeof (pkg_values);
270 if (*ret_buffer_len < packet_len)
271 return (ENOMEM);
273 pkg_type = htons (TYPE_VALUES);
274 pkg_length = htons ((uint16_t) packet_len);
275 pkg_num_values = htons ((uint16_t) vl->values_len);
277 for (i = 0; i < vl->values_len; i++)
278 {
279 pkg_values_types[i] = (uint8_t) vl->values_types[i];
280 switch (vl->values_types[i])
281 {
282 case LCC_TYPE_COUNTER:
283 pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
284 break;
286 case LCC_TYPE_GAUGE:
287 pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
288 break;
290 case LCC_TYPE_DERIVE:
291 pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
292 break;
294 case LCC_TYPE_ABSOLUTE:
295 pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
296 break;
298 default:
299 return (EINVAL);
300 } /* switch (vl->values_types[i]) */
301 } /* for (vl->values_len) */
303 /*
304 * Use `memcpy' to write everything to the buffer, because the pointer
305 * may be unaligned and some architectures, such as SPARC, can't handle
306 * that.
307 */
308 packet_ptr = *ret_buffer;
309 offset = 0;
310 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
311 offset += sizeof (pkg_type);
312 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
313 offset += sizeof (pkg_length);
314 memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
315 offset += sizeof (pkg_num_values);
316 memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
317 offset += sizeof (pkg_values_types);
318 memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
319 offset += sizeof (pkg_values);
321 assert (offset == packet_len);
323 *ret_buffer = packet_ptr + packet_len;
324 *ret_buffer_len -= packet_len;
325 return (0);
326 } /* }}} int nb_add_values */
328 static int nb_add_number (char **ret_buffer, /* {{{ */
329 size_t *ret_buffer_len,
330 uint16_t type, uint64_t value)
331 {
332 char *packet_ptr;
333 size_t packet_len;
335 uint16_t pkg_type;
336 uint16_t pkg_length;
337 uint64_t pkg_value;
339 size_t offset;
341 packet_len = sizeof (pkg_type)
342 + sizeof (pkg_length)
343 + sizeof (pkg_value);
345 if (*ret_buffer_len < packet_len)
346 return (ENOMEM);
348 pkg_type = htons (type);
349 pkg_length = htons ((uint16_t) packet_len);
350 pkg_value = htonll (value);
352 packet_ptr = *ret_buffer;
353 offset = 0;
354 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
355 offset += sizeof (pkg_type);
356 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
357 offset += sizeof (pkg_length);
358 memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
359 offset += sizeof (pkg_value);
361 assert (offset == packet_len);
363 *ret_buffer = packet_ptr + packet_len;
364 *ret_buffer_len -= packet_len;
365 return (0);
366 } /* }}} int nb_add_number */
368 static int nb_add_time (char **ret_buffer, /* {{{ */
369 size_t *ret_buffer_len,
370 uint16_t type, double value)
371 {
372 /* Convert to collectd's "cdtime" representation. */
373 uint64_t cdtime_value = (uint64_t) (value * 1073741824.0);
374 return (nb_add_number (ret_buffer, ret_buffer_len, type, cdtime_value));
375 } /* }}} int nb_add_time */
377 static int nb_add_string (char **ret_buffer, /* {{{ */
378 size_t *ret_buffer_len,
379 uint16_t type, const char *str, size_t str_len)
380 {
381 char *packet_ptr;
382 size_t packet_len;
384 uint16_t pkg_type;
385 uint16_t pkg_length;
387 size_t offset;
389 packet_len = sizeof (pkg_type)
390 + sizeof (pkg_length)
391 + str_len + 1;
392 if (*ret_buffer_len < packet_len)
393 return (ENOMEM);
395 pkg_type = htons (type);
396 pkg_length = htons ((uint16_t) packet_len);
398 packet_ptr = *ret_buffer;
399 offset = 0;
400 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
401 offset += sizeof (pkg_type);
402 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
403 offset += sizeof (pkg_length);
404 memcpy (packet_ptr + offset, str, str_len);
405 offset += str_len;
406 memset (packet_ptr + offset, 0, 1);
407 offset += 1;
409 assert (offset == packet_len);
411 *ret_buffer = packet_ptr + packet_len;
412 *ret_buffer_len -= packet_len;
413 return (0);
414 } /* }}} int nb_add_string */
416 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
417 const lcc_value_list_t *vl)
418 {
419 char *buffer = nb->ptr;
420 size_t buffer_size = nb->free;
422 const lcc_identifier_t *ident_src;
423 lcc_identifier_t *ident_dst;
425 ident_src = &vl->identifier;
426 ident_dst = &nb->state.identifier;
428 if (strcmp (ident_dst->host, ident_src->host) != 0)
429 {
430 if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
431 ident_src->host, strlen (ident_src->host)) != 0)
432 return (-1);
433 SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
434 }
436 if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
437 {
438 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
439 ident_src->plugin, strlen (ident_src->plugin)) != 0)
440 return (-1);
441 SSTRNCPY (ident_dst->plugin, ident_src->plugin,
442 sizeof (ident_dst->plugin));
443 }
445 if (strcmp (ident_dst->plugin_instance,
446 ident_src->plugin_instance) != 0)
447 {
448 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
449 ident_src->plugin_instance,
450 strlen (ident_src->plugin_instance)) != 0)
451 return (-1);
452 SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
453 sizeof (ident_dst->plugin_instance));
454 }
456 if (strcmp (ident_dst->type, ident_src->type) != 0)
457 {
458 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
459 ident_src->type, strlen (ident_src->type)) != 0)
460 return (-1);
461 SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
462 }
464 if (strcmp (ident_dst->type_instance,
465 ident_src->type_instance) != 0)
466 {
467 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
468 ident_src->type_instance,
469 strlen (ident_src->type_instance)) != 0)
470 return (-1);
471 SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
472 sizeof (ident_dst->type_instance));
473 }
475 if (nb->state.time != vl->time)
476 {
477 if (nb_add_time (&buffer, &buffer_size, TYPE_TIME_HR, vl->time))
478 return (-1);
479 nb->state.time = vl->time;
480 }
482 if (nb->state.interval != vl->interval)
483 {
484 if (nb_add_time (&buffer, &buffer_size, TYPE_INTERVAL_HR, vl->interval))
485 return (-1);
486 nb->state.interval = vl->interval;
487 }
489 if (nb_add_values (&buffer, &buffer_size, vl) != 0)
490 return (-1);
492 nb->ptr = buffer;
493 nb->free = buffer_size;
494 return (0);
495 } /* }}} int nb_add_value_list */
497 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
498 {
499 char *buffer;
500 size_t buffer_size;
502 gcry_md_hd_t hd;
503 gcry_error_t err;
504 unsigned char *hash;
505 const size_t hash_length = 32;
507 /* The type, length and username have already been filled in by
508 * "lcc_network_buffer_initialize". All we do here is calculate the hash over
509 * the username and the data and add the hash value to the buffer. */
511 buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
512 assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
513 buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
515 hd = NULL;
516 err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
517 if (err != 0)
518 return (-1);
520 assert (nb->password != NULL);
521 err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
522 if (err != 0)
523 {
524 gcry_md_close (hd);
525 return (-1);
526 }
528 gcry_md_write (hd, buffer, buffer_size);
529 hash = gcry_md_read (hd, GCRY_MD_SHA256);
530 if (hash == NULL)
531 {
532 gcry_md_close (hd);
533 return (-1);
534 }
536 assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
537 memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
539 gcry_md_close (hd);
540 return (0);
541 } /* }}} int nb_add_signature */
543 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
544 {
545 size_t package_length;
546 char *encr_ptr; /* pointer to data being encrypted */
547 size_t encr_size;
549 char *hash_ptr; /* pointer to data being hashed */
550 size_t hash_size;
551 char hash[20];
553 uint16_t pkg_length;
554 gcry_error_t err;
556 /* Fill in the package length */
557 package_length = nb->size - nb->free;
558 pkg_length = htons ((uint16_t) package_length);
559 memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
561 /* Calculate what to hash */
562 hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
563 hash_size = package_length - nb->encr_header_len;
565 /* Calculate what to encrypt */
566 encr_ptr = hash_ptr - sizeof (hash);
567 encr_size = hash_size + sizeof (hash);
569 /* Calculate the SHA-1 hash */
570 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
571 memcpy (encr_ptr, hash, sizeof (hash));
573 if (nb->encr_cypher == NULL)
574 {
575 unsigned char password_hash[32];
577 err = gcry_cipher_open (&nb->encr_cypher,
578 GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
579 if (err != 0)
580 return (-1);
582 /* Calculate our 256bit key used for AES */
583 gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
584 nb->password, strlen (nb->password));
586 err = gcry_cipher_setkey (nb->encr_cypher,
587 password_hash, sizeof (password_hash));
588 if (err != 0)
589 {
590 gcry_cipher_close (nb->encr_cypher);
591 nb->encr_cypher = NULL;
592 return (-1);
593 }
594 }
595 else /* if (nb->encr_cypher != NULL) */
596 {
597 gcry_cipher_reset (nb->encr_cypher);
598 }
600 /* Set the initialization vector */
601 err = gcry_cipher_setiv (nb->encr_cypher,
602 nb->encr_iv, sizeof (nb->encr_iv));
603 if (err != 0)
604 {
605 gcry_cipher_close (nb->encr_cypher);
606 nb->encr_cypher = NULL;
607 return (-1);
608 }
610 /* Encrypt the buffer in-place */
611 err = gcry_cipher_encrypt (nb->encr_cypher,
612 encr_ptr, encr_size,
613 /* in = */ NULL, /* in len = */ 0);
614 if (err != 0)
615 {
616 gcry_cipher_close (nb->encr_cypher);
617 nb->encr_cypher = NULL;
618 return (-1);
619 }
621 return (0);
622 } /* }}} int nb_add_encryption */
624 /*
625 * Public functions
626 */
627 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
628 {
629 lcc_network_buffer_t *nb;
631 if (size == 0)
632 size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
634 if (size < 128)
635 {
636 errno = EINVAL;
637 return (NULL);
638 }
640 nb = malloc (sizeof (*nb));
641 if (nb == NULL)
642 return (NULL);
643 memset (nb, 0, sizeof (*nb));
645 nb->size = size;
646 nb->buffer = malloc (nb->size);
647 if (nb->buffer == NULL)
648 {
649 free (nb);
650 return (NULL);
651 }
652 memset (nb->buffer, 0, nb->size);
654 nb->ptr = nb->buffer;
655 nb->free = nb->size;
657 nb->seclevel = NONE;
658 nb->username = NULL;
659 nb->password = NULL;
661 return (nb);
662 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
664 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
665 {
666 if (nb == NULL)
667 return;
669 free (nb->buffer);
670 free (nb);
671 } /* }}} void lcc_network_buffer_destroy */
673 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
674 lcc_security_level_t level,
675 const char *username, const char *password)
676 {
677 char *username_copy;
678 char *password_copy;
680 if (level == NONE)
681 {
682 free (nb->username);
683 free (nb->password);
684 nb->username = NULL;
685 nb->password = NULL;
686 nb->seclevel = NONE;
687 lcc_network_buffer_initialize (nb);
688 return (0);
689 }
691 if (!have_gcrypt ())
692 return (ENOTSUP);
694 username_copy = strdup (username);
695 password_copy = strdup (password);
696 if ((username_copy == NULL) || (password_copy == NULL))
697 {
698 free (username_copy);
699 free (password_copy);
700 return (ENOMEM);
701 }
703 free (nb->username);
704 free (nb->password);
705 nb->username = username_copy;
706 nb->password = password_copy;
707 nb->seclevel = level;
709 lcc_network_buffer_initialize (nb);
710 return (0);
711 } /* }}} int lcc_network_buffer_set_security_level */
713 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
714 {
715 if (nb == NULL)
716 return (EINVAL);
718 memset (nb->buffer, 0, nb->size);
719 memset (&nb->state, 0, sizeof (nb->state));
720 nb->ptr = nb->buffer;
721 nb->free = nb->size;
723 if (nb->seclevel == SIGN)
724 {
725 size_t username_len;
726 uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
727 uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
729 assert (nb->username != NULL);
730 username_len = strlen (nb->username);
731 pkg_length = htons (pkg_length + ((uint16_t) username_len));
733 /* Fill in everything but the hash value here. */
734 memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
735 memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
736 nb->ptr += PART_SIGNATURE_SHA256_SIZE;
737 nb->free -= PART_SIGNATURE_SHA256_SIZE;
739 memcpy (nb->ptr, nb->username, username_len);
740 nb->ptr += username_len;
741 nb->free -= username_len;
742 }
743 else if (nb->seclevel == ENCRYPT)
744 {
745 size_t username_length = strlen (nb->username);
746 uint16_t pkg_type = htons (TYPE_ENCR_AES256);
747 uint16_t pkg_length = 0; /* Filled in in finalize. */
748 uint16_t pkg_user_len = htons ((uint16_t) username_length);
749 char hash[20];
751 nb->encr_header_len = username_length;
752 nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
754 gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
755 GCRY_STRONG_RANDOM);
757 /* Filled in in finalize. */
758 memset (hash, 0, sizeof (hash));
760 ADD_STATIC (nb, pkg_type);
761 ADD_STATIC (nb, pkg_length);
762 ADD_STATIC (nb, pkg_user_len);
763 ADD_GENERIC (nb, nb->username, username_length);
764 ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
765 ADD_GENERIC (nb, hash, sizeof (hash));
766 assert ((nb->encr_header_len + nb->free) == nb->size);
767 }
769 return (0);
770 } /* }}} int lcc_network_buffer_initialize */
772 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
773 {
774 if (nb == NULL)
775 return (EINVAL);
777 if (nb->seclevel == SIGN)
778 nb_add_signature (nb);
779 else if (nb->seclevel == ENCRYPT)
780 nb_add_encryption (nb);
782 return (0);
783 } /* }}} int lcc_network_buffer_finalize */
785 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
786 const lcc_value_list_t *vl)
787 {
788 int status;
790 if ((nb == NULL) || (vl == NULL))
791 return (EINVAL);
793 status = nb_add_value_list (nb, vl);
794 return (status);
795 } /* }}} int lcc_network_buffer_add_value */
797 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
798 void *buffer, size_t *buffer_size)
799 {
800 size_t sz_required;
801 size_t sz_available;
803 if ((nb == NULL) || (buffer_size == NULL))
804 return (EINVAL);
806 assert (nb->size >= nb->free);
807 sz_required = nb->size - nb->free;
808 sz_available = *buffer_size;
810 *buffer_size = sz_required;
811 if (buffer != NULL)
812 memcpy (buffer, nb->buffer,
813 (sz_available < sz_required) ? sz_available : sz_required);
815 return (0);
816 } /* }}} int lcc_network_buffer_get */
818 /* vim: set sw=2 sts=2 et fdm=marker : */