5553d82629bc08974cf27c3a72e7fd0cc39a553b
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 # include <gcrypt.h>
48 # if defined __APPLE__
49 /* Re enable deprecation warnings */
50 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
51 # endif
52 GCRY_THREAD_OPTION_PTHREAD_IMPL;
53 #endif
55 #include "collectd/network_buffer.h"
57 #define TYPE_HOST 0x0000
58 #define TYPE_TIME 0x0001
59 #define TYPE_TIME_HR 0x0008
60 #define TYPE_PLUGIN 0x0002
61 #define TYPE_PLUGIN_INSTANCE 0x0003
62 #define TYPE_TYPE 0x0004
63 #define TYPE_TYPE_INSTANCE 0x0005
64 #define TYPE_VALUES 0x0006
65 #define TYPE_INTERVAL 0x0007
66 #define TYPE_INTERVAL_HR 0x0009
68 /* Types to transmit notifications */
69 #define TYPE_MESSAGE 0x0100
70 #define TYPE_SEVERITY 0x0101
72 #define TYPE_SIGN_SHA256 0x0200
73 #define TYPE_ENCR_AES256 0x0210
75 #define PART_SIGNATURE_SHA256_SIZE 36
76 #define PART_ENCRYPTION_AES256_SIZE 42
78 #define ADD_GENERIC(nb,srcptr,size) do { \
79 assert ((size) <= (nb)->free); \
80 memcpy ((nb)->ptr, (srcptr), (size)); \
81 (nb)->ptr += (size); \
82 (nb)->free -= (size); \
83 } while (0)
85 #define ADD_STATIC(nb,var) \
86 ADD_GENERIC(nb,&(var),sizeof(var));
88 /*
89 * Data types
90 */
91 struct lcc_network_buffer_s
92 {
93 char *buffer;
94 size_t size;
96 lcc_value_list_t state;
97 char *ptr;
98 size_t free;
100 lcc_security_level_t seclevel;
101 char *username;
102 char *password;
104 gcry_cipher_hd_t encr_cypher;
105 size_t encr_header_len;
106 char encr_iv[16];
107 };
109 #define SSTRNCPY(dst,src,sz) do { \
110 strncpy ((dst), (src), (sz)); \
111 (dst)[(sz) - 1] = 0; \
112 } while (0)
114 /*
115 * Private functions
116 */
117 static _Bool have_gcrypt (void) /* {{{ */
118 {
119 static _Bool result = 0;
120 static _Bool need_init = 1;
122 if (!need_init)
123 return (result);
124 need_init = 0;
126 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
128 if (!gcry_check_version (GCRYPT_VERSION))
129 return (0);
131 gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
132 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
134 result = 1;
135 return (1);
136 } /* }}} _Bool have_gcrypt */
138 static uint64_t htonll (uint64_t val) /* {{{ */
139 {
140 static int config = 0;
142 uint32_t hi;
143 uint32_t lo;
145 if (config == 0)
146 {
147 uint16_t h = 0x1234;
148 uint16_t n = htons (h);
150 if (h == n)
151 config = 1;
152 else
153 config = 2;
154 }
156 if (config == 1)
157 return (val);
159 hi = (uint32_t) (val >> 32);
160 lo = (uint32_t) (val & 0x00000000FFFFFFFF);
162 hi = htonl (hi);
163 lo = htonl (lo);
165 return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
166 } /* }}} uint64_t htonll */
168 static double htond (double val) /* {{{ */
169 {
170 static int config = 0;
172 union { uint8_t byte[8]; double floating; } in;
173 union { uint8_t byte[8]; double floating; } out;
175 if (config == 0)
176 {
177 double d = 8.642135e130;
178 uint8_t c[8];
180 memcpy (c, &d, 8);
182 if ((c[0] == 0x2f) && (c[1] == 0x25)
183 && (c[2] == 0xc0) && (c[3] == 0xc7)
184 && (c[4] == 0x43) && (c[5] == 0x2b)
185 && (c[6] == 0x1f) && (c[7] == 0x5b))
186 config = 1; /* need nothing */
187 else if ((c[7] == 0x2f) && (c[6] == 0x25)
188 && (c[5] == 0xc0) && (c[4] == 0xc7)
189 && (c[3] == 0x43) && (c[2] == 0x2b)
190 && (c[1] == 0x1f) && (c[0] == 0x5b))
191 config = 2; /* endian flip */
192 else if ((c[4] == 0x2f) && (c[5] == 0x25)
193 && (c[6] == 0xc0) && (c[7] == 0xc7)
194 && (c[0] == 0x43) && (c[1] == 0x2b)
195 && (c[2] == 0x1f) && (c[3] == 0x5b))
196 config = 3; /* int swap */
197 else
198 config = 4;
199 }
201 if (isnan (val))
202 {
203 out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
204 out.byte[4] = out.byte[5] = 0x00;
205 out.byte[6] = 0xf8;
206 out.byte[7] = 0x7f;
207 return (out.floating);
208 }
209 else if (config == 1)
210 return (val);
211 else if (config == 2)
212 {
213 in.floating = val;
214 out.byte[0] = in.byte[7];
215 out.byte[1] = in.byte[6];
216 out.byte[2] = in.byte[5];
217 out.byte[3] = in.byte[4];
218 out.byte[4] = in.byte[3];
219 out.byte[5] = in.byte[2];
220 out.byte[6] = in.byte[1];
221 out.byte[7] = in.byte[0];
222 return (out.floating);
223 }
224 else if (config == 3)
225 {
226 in.floating = val;
227 out.byte[0] = in.byte[4];
228 out.byte[1] = in.byte[5];
229 out.byte[2] = in.byte[6];
230 out.byte[3] = in.byte[7];
231 out.byte[4] = in.byte[0];
232 out.byte[5] = in.byte[1];
233 out.byte[6] = in.byte[2];
234 out.byte[7] = in.byte[3];
235 return (out.floating);
236 }
237 else
238 {
239 /* If in doubt, just copy the value back to the caller. */
240 return (val);
241 }
242 } /* }}} double htond */
244 static int nb_add_values (char **ret_buffer, /* {{{ */
245 size_t *ret_buffer_len,
246 const lcc_value_list_t *vl)
247 {
248 char *packet_ptr;
249 size_t packet_len;
251 uint16_t pkg_type;
252 uint16_t pkg_length;
253 uint16_t pkg_num_values;
254 uint8_t pkg_values_types[vl->values_len];
255 value_t pkg_values[vl->values_len];
257 size_t offset;
258 size_t i;
260 packet_len = sizeof (pkg_type) + sizeof (pkg_length)
261 + sizeof (pkg_num_values)
262 + sizeof (pkg_values_types)
263 + sizeof (pkg_values);
265 if (*ret_buffer_len < packet_len)
266 return (ENOMEM);
268 pkg_type = htons (TYPE_VALUES);
269 pkg_length = htons ((uint16_t) packet_len);
270 pkg_num_values = htons ((uint16_t) vl->values_len);
272 for (i = 0; i < vl->values_len; i++)
273 {
274 pkg_values_types[i] = (uint8_t) vl->values_types[i];
275 switch (vl->values_types[i])
276 {
277 case LCC_TYPE_COUNTER:
278 pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
279 break;
281 case LCC_TYPE_GAUGE:
282 pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
283 break;
285 case LCC_TYPE_DERIVE:
286 pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
287 break;
289 case LCC_TYPE_ABSOLUTE:
290 pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
291 break;
293 default:
294 return (EINVAL);
295 } /* switch (vl->values_types[i]) */
296 } /* for (vl->values_len) */
298 /*
299 * Use `memcpy' to write everything to the buffer, because the pointer
300 * may be unaligned and some architectures, such as SPARC, can't handle
301 * that.
302 */
303 packet_ptr = *ret_buffer;
304 offset = 0;
305 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
306 offset += sizeof (pkg_type);
307 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
308 offset += sizeof (pkg_length);
309 memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
310 offset += sizeof (pkg_num_values);
311 memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
312 offset += sizeof (pkg_values_types);
313 memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
314 offset += sizeof (pkg_values);
316 assert (offset == packet_len);
318 *ret_buffer = packet_ptr + packet_len;
319 *ret_buffer_len -= packet_len;
320 return (0);
321 } /* }}} int nb_add_values */
323 static int nb_add_number (char **ret_buffer, /* {{{ */
324 size_t *ret_buffer_len,
325 uint16_t type, uint64_t value)
326 {
327 char *packet_ptr;
328 size_t packet_len;
330 uint16_t pkg_type;
331 uint16_t pkg_length;
332 uint64_t pkg_value;
334 size_t offset;
336 packet_len = sizeof (pkg_type)
337 + sizeof (pkg_length)
338 + sizeof (pkg_value);
340 if (*ret_buffer_len < packet_len)
341 return (ENOMEM);
343 pkg_type = htons (type);
344 pkg_length = htons ((uint16_t) packet_len);
345 pkg_value = htonll (value);
347 packet_ptr = *ret_buffer;
348 offset = 0;
349 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
350 offset += sizeof (pkg_type);
351 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
352 offset += sizeof (pkg_length);
353 memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
354 offset += sizeof (pkg_value);
356 assert (offset == packet_len);
358 *ret_buffer = packet_ptr + packet_len;
359 *ret_buffer_len -= packet_len;
360 return (0);
361 } /* }}} int nb_add_number */
363 static int nb_add_time (char **ret_buffer, /* {{{ */
364 size_t *ret_buffer_len,
365 uint16_t type, double value)
366 {
367 /* Convert to collectd's "cdtime" representation. */
368 uint64_t cdtime_value = (uint64_t) (value * 1073741824.0);
369 return (nb_add_number (ret_buffer, ret_buffer_len, type, cdtime_value));
370 } /* }}} int nb_add_time */
372 static int nb_add_string (char **ret_buffer, /* {{{ */
373 size_t *ret_buffer_len,
374 uint16_t type, const char *str, size_t str_len)
375 {
376 char *packet_ptr;
377 size_t packet_len;
379 uint16_t pkg_type;
380 uint16_t pkg_length;
382 size_t offset;
384 packet_len = sizeof (pkg_type)
385 + sizeof (pkg_length)
386 + str_len + 1;
387 if (*ret_buffer_len < packet_len)
388 return (ENOMEM);
390 pkg_type = htons (type);
391 pkg_length = htons ((uint16_t) packet_len);
393 packet_ptr = *ret_buffer;
394 offset = 0;
395 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
396 offset += sizeof (pkg_type);
397 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
398 offset += sizeof (pkg_length);
399 memcpy (packet_ptr + offset, str, str_len);
400 offset += str_len;
401 memset (packet_ptr + offset, 0, 1);
402 offset += 1;
404 assert (offset == packet_len);
406 *ret_buffer = packet_ptr + packet_len;
407 *ret_buffer_len -= packet_len;
408 return (0);
409 } /* }}} int nb_add_string */
411 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
412 const lcc_value_list_t *vl)
413 {
414 char *buffer = nb->ptr;
415 size_t buffer_size = nb->free;
417 const lcc_identifier_t *ident_src;
418 lcc_identifier_t *ident_dst;
420 ident_src = &vl->identifier;
421 ident_dst = &nb->state.identifier;
423 if (strcmp (ident_dst->host, ident_src->host) != 0)
424 {
425 if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
426 ident_src->host, strlen (ident_src->host)) != 0)
427 return (-1);
428 SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
429 }
431 if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
432 {
433 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
434 ident_src->plugin, strlen (ident_src->plugin)) != 0)
435 return (-1);
436 SSTRNCPY (ident_dst->plugin, ident_src->plugin,
437 sizeof (ident_dst->plugin));
438 }
440 if (strcmp (ident_dst->plugin_instance,
441 ident_src->plugin_instance) != 0)
442 {
443 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
444 ident_src->plugin_instance,
445 strlen (ident_src->plugin_instance)) != 0)
446 return (-1);
447 SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
448 sizeof (ident_dst->plugin_instance));
449 }
451 if (strcmp (ident_dst->type, ident_src->type) != 0)
452 {
453 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
454 ident_src->type, strlen (ident_src->type)) != 0)
455 return (-1);
456 SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
457 }
459 if (strcmp (ident_dst->type_instance,
460 ident_src->type_instance) != 0)
461 {
462 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
463 ident_src->type_instance,
464 strlen (ident_src->type_instance)) != 0)
465 return (-1);
466 SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
467 sizeof (ident_dst->type_instance));
468 }
470 if (nb->state.time != vl->time)
471 {
472 if (nb_add_time (&buffer, &buffer_size, TYPE_TIME_HR, vl->time))
473 return (-1);
474 nb->state.time = vl->time;
475 }
477 if (nb->state.interval != vl->interval)
478 {
479 if (nb_add_time (&buffer, &buffer_size, TYPE_INTERVAL_HR, vl->interval))
480 return (-1);
481 nb->state.interval = vl->interval;
482 }
484 if (nb_add_values (&buffer, &buffer_size, vl) != 0)
485 return (-1);
487 nb->ptr = buffer;
488 nb->free = buffer_size;
489 return (0);
490 } /* }}} int nb_add_value_list */
492 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
493 {
494 char *buffer;
495 size_t buffer_size;
497 gcry_md_hd_t hd;
498 gcry_error_t err;
499 unsigned char *hash;
500 const size_t hash_length = 32;
502 /* The type, length and username have already been filled in by
503 * "lcc_network_buffer_initialize". All we do here is calculate the hash over
504 * the username and the data and add the hash value to the buffer. */
506 buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
507 assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
508 buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
510 hd = NULL;
511 err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
512 if (err != 0)
513 return (-1);
515 assert (nb->password != NULL);
516 err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
517 if (err != 0)
518 {
519 gcry_md_close (hd);
520 return (-1);
521 }
523 gcry_md_write (hd, buffer, buffer_size);
524 hash = gcry_md_read (hd, GCRY_MD_SHA256);
525 if (hash == NULL)
526 {
527 gcry_md_close (hd);
528 return (-1);
529 }
531 assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
532 memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
534 gcry_md_close (hd);
535 return (0);
536 } /* }}} int nb_add_signature */
538 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
539 {
540 size_t package_length;
541 char *encr_ptr; /* pointer to data being encrypted */
542 size_t encr_size;
544 char *hash_ptr; /* pointer to data being hashed */
545 size_t hash_size;
546 char hash[20];
548 uint16_t pkg_length;
549 gcry_error_t err;
551 /* Fill in the package length */
552 package_length = nb->size - nb->free;
553 pkg_length = htons ((uint16_t) package_length);
554 memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
556 /* Calculate what to hash */
557 hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
558 hash_size = package_length - nb->encr_header_len;
560 /* Calculate what to encrypt */
561 encr_ptr = hash_ptr - sizeof (hash);
562 encr_size = hash_size + sizeof (hash);
564 /* Calculate the SHA-1 hash */
565 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
566 memcpy (encr_ptr, hash, sizeof (hash));
568 if (nb->encr_cypher == NULL)
569 {
570 unsigned char password_hash[32];
572 err = gcry_cipher_open (&nb->encr_cypher,
573 GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
574 if (err != 0)
575 return (-1);
577 /* Calculate our 256bit key used for AES */
578 gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
579 nb->password, strlen (nb->password));
581 err = gcry_cipher_setkey (nb->encr_cypher,
582 password_hash, sizeof (password_hash));
583 if (err != 0)
584 {
585 gcry_cipher_close (nb->encr_cypher);
586 nb->encr_cypher = NULL;
587 return (-1);
588 }
589 }
590 else /* if (nb->encr_cypher != NULL) */
591 {
592 gcry_cipher_reset (nb->encr_cypher);
593 }
595 /* Set the initialization vector */
596 err = gcry_cipher_setiv (nb->encr_cypher,
597 nb->encr_iv, sizeof (nb->encr_iv));
598 if (err != 0)
599 {
600 gcry_cipher_close (nb->encr_cypher);
601 nb->encr_cypher = NULL;
602 return (-1);
603 }
605 /* Encrypt the buffer in-place */
606 err = gcry_cipher_encrypt (nb->encr_cypher,
607 encr_ptr, encr_size,
608 /* in = */ NULL, /* in len = */ 0);
609 if (err != 0)
610 {
611 gcry_cipher_close (nb->encr_cypher);
612 nb->encr_cypher = NULL;
613 return (-1);
614 }
616 return (0);
617 } /* }}} int nb_add_encryption */
619 /*
620 * Public functions
621 */
622 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
623 {
624 lcc_network_buffer_t *nb;
626 if (size == 0)
627 size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
629 if (size < 128)
630 {
631 errno = EINVAL;
632 return (NULL);
633 }
635 nb = malloc (sizeof (*nb));
636 if (nb == NULL)
637 return (NULL);
638 memset (nb, 0, sizeof (*nb));
640 nb->size = size;
641 nb->buffer = malloc (nb->size);
642 if (nb->buffer == NULL)
643 {
644 free (nb);
645 return (NULL);
646 }
647 memset (nb->buffer, 0, nb->size);
649 nb->ptr = nb->buffer;
650 nb->free = nb->size;
652 nb->seclevel = NONE;
653 nb->username = NULL;
654 nb->password = NULL;
656 return (nb);
657 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
659 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
660 {
661 if (nb == NULL)
662 return;
664 free (nb->buffer);
665 free (nb);
666 } /* }}} void lcc_network_buffer_destroy */
668 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
669 lcc_security_level_t level,
670 const char *username, const char *password)
671 {
672 char *username_copy;
673 char *password_copy;
675 if (level == NONE)
676 {
677 free (nb->username);
678 free (nb->password);
679 nb->username = NULL;
680 nb->password = NULL;
681 nb->seclevel = NONE;
682 lcc_network_buffer_initialize (nb);
683 return (0);
684 }
686 if (!have_gcrypt ())
687 return (ENOTSUP);
689 username_copy = strdup (username);
690 password_copy = strdup (password);
691 if ((username_copy == NULL) || (password_copy == NULL))
692 {
693 free (username_copy);
694 free (password_copy);
695 return (ENOMEM);
696 }
698 free (nb->username);
699 free (nb->password);
700 nb->username = username_copy;
701 nb->password = password_copy;
702 nb->seclevel = level;
704 lcc_network_buffer_initialize (nb);
705 return (0);
706 } /* }}} int lcc_network_buffer_set_security_level */
708 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
709 {
710 if (nb == NULL)
711 return (EINVAL);
713 memset (nb->buffer, 0, nb->size);
714 memset (&nb->state, 0, sizeof (nb->state));
715 nb->ptr = nb->buffer;
716 nb->free = nb->size;
718 if (nb->seclevel == SIGN)
719 {
720 size_t username_len;
721 uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
722 uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
724 assert (nb->username != NULL);
725 username_len = strlen (nb->username);
726 pkg_length = htons (pkg_length + ((uint16_t) username_len));
728 /* Fill in everything but the hash value here. */
729 memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
730 memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
731 nb->ptr += PART_SIGNATURE_SHA256_SIZE;
732 nb->free -= PART_SIGNATURE_SHA256_SIZE;
734 memcpy (nb->ptr, nb->username, username_len);
735 nb->ptr += username_len;
736 nb->free -= username_len;
737 }
738 else if (nb->seclevel == ENCRYPT)
739 {
740 size_t username_length = strlen (nb->username);
741 uint16_t pkg_type = htons (TYPE_ENCR_AES256);
742 uint16_t pkg_length = 0; /* Filled in in finalize. */
743 uint16_t pkg_user_len = htons ((uint16_t) username_length);
744 char hash[20];
746 nb->encr_header_len = username_length;
747 nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
749 gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
750 GCRY_STRONG_RANDOM);
752 /* Filled in in finalize. */
753 memset (hash, 0, sizeof (hash));
755 ADD_STATIC (nb, pkg_type);
756 ADD_STATIC (nb, pkg_length);
757 ADD_STATIC (nb, pkg_user_len);
758 ADD_GENERIC (nb, nb->username, username_length);
759 ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
760 ADD_GENERIC (nb, hash, sizeof (hash));
761 assert ((nb->encr_header_len + nb->free) == nb->size);
762 }
764 return (0);
765 } /* }}} int lcc_network_buffer_initialize */
767 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
768 {
769 if (nb == NULL)
770 return (EINVAL);
772 if (nb->seclevel == SIGN)
773 nb_add_signature (nb);
774 else if (nb->seclevel == ENCRYPT)
775 nb_add_encryption (nb);
777 return (0);
778 } /* }}} int lcc_network_buffer_finalize */
780 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
781 const lcc_value_list_t *vl)
782 {
783 int status;
785 if ((nb == NULL) || (vl == NULL))
786 return (EINVAL);
788 status = nb_add_value_list (nb, vl);
789 return (status);
790 } /* }}} int lcc_network_buffer_add_value */
792 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
793 void *buffer, size_t *buffer_size)
794 {
795 size_t sz_required;
796 size_t sz_available;
798 if ((nb == NULL) || (buffer_size == NULL))
799 return (EINVAL);
801 assert (nb->size >= nb->free);
802 sz_required = nb->size - nb->free;
803 sz_available = *buffer_size;
805 *buffer_size = sz_required;
806 if (buffer != NULL)
807 memcpy (buffer, nb->buffer,
808 (sz_available < sz_required) ? sz_available : sz_required);
810 return (0);
811 } /* }}} int lcc_network_buffer_get */
813 /* vim: set sw=2 sts=2 et fdm=marker : */