1 /**
2 * collectd - src/libcollectdclient/network_buffer.c
3 * Copyright (C) 2010-2015 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 <arpa/inet.h> /* htons */
30 #include <assert.h>
31 #include <errno.h>
32 #include <math.h>
33 #include <stdlib.h>
34 #include <string.h>
36 #include <pthread.h>
38 #if HAVE_GCRYPT_H
39 #if defined __APPLE__
40 /* default xcode compiler throws warnings even when deprecated functionality
41 * is not used. -Werror breaks the build because of erroneous warnings.
42 * http://stackoverflow.com/questions/10556299/compiler-warnings-with-libgcrypt-v1-5-0/12830209#12830209
43 */
44 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
45 #endif
46 /* FreeBSD's copy of libgcrypt extends the existing GCRYPT_NO_DEPRECATED
47 * to properly hide all deprecated functionality.
48 * http://svnweb.freebsd.org/ports/head/security/libgcrypt/files/patch-src__gcrypt.h.in
49 */
50 #define GCRYPT_NO_DEPRECATED
51 #include <gcrypt.h>
52 #if defined __APPLE__
53 /* Re enable deprecation warnings */
54 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
55 #endif
56 #if GCRYPT_VERSION_NUMBER < 0x010600
57 GCRY_THREAD_OPTION_PTHREAD_IMPL;
58 #endif
59 #endif
61 #include "collectd/network_buffer.h"
63 #define TYPE_HOST 0x0000
64 #define TYPE_TIME 0x0001
65 #define TYPE_TIME_HR 0x0008
66 #define TYPE_PLUGIN 0x0002
67 #define TYPE_PLUGIN_INSTANCE 0x0003
68 #define TYPE_TYPE 0x0004
69 #define TYPE_TYPE_INSTANCE 0x0005
70 #define TYPE_VALUES 0x0006
71 #define TYPE_INTERVAL 0x0007
72 #define TYPE_INTERVAL_HR 0x0009
74 /* Types to transmit notifications */
75 #define TYPE_MESSAGE 0x0100
76 #define TYPE_SEVERITY 0x0101
78 #define TYPE_SIGN_SHA256 0x0200
79 #define TYPE_ENCR_AES256 0x0210
81 #define PART_SIGNATURE_SHA256_SIZE 36
82 #define PART_ENCRYPTION_AES256_SIZE 42
84 #define ADD_GENERIC(nb, srcptr, size) \
85 do { \
86 assert((size) <= (nb)->free); \
87 memcpy((nb)->ptr, (srcptr), (size)); \
88 (nb)->ptr += (size); \
89 (nb)->free -= (size); \
90 } while (0)
92 #define ADD_STATIC(nb, var) ADD_GENERIC(nb, &(var), sizeof(var));
94 /*
95 * Data types
96 */
97 struct lcc_network_buffer_s {
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 #if HAVE_GCRYPT_H
110 gcry_cipher_hd_t encr_cypher;
111 size_t encr_header_len;
112 char encr_iv[16];
113 #endif
114 };
116 #define SSTRNCPY(dst, src, sz) \
117 do { \
118 strncpy((dst), (src), (sz)); \
119 (dst)[(sz)-1] = 0; \
120 } while (0)
122 /*
123 * Private functions
124 */
125 static _Bool have_gcrypt(void) /* {{{ */
126 {
127 static _Bool result = 0;
128 static _Bool need_init = 1;
130 if (!need_init)
131 return (result);
132 need_init = 0;
134 #if HAVE_GCRYPT_H
135 #if GCRYPT_VERSION_NUMBER < 0x010600
136 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
137 return (0);
138 #endif
140 if (!gcry_check_version(GCRYPT_VERSION))
141 return (0);
143 if (!gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0))
144 return (0);
146 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
148 result = 1;
149 return (1);
150 #else
151 return (0);
152 #endif
153 } /* }}} _Bool have_gcrypt */
155 #ifndef HAVE_HTONLL
156 static uint64_t htonll(uint64_t val) /* {{{ */
157 {
158 static int config = 0;
160 uint32_t hi;
161 uint32_t lo;
163 if (config == 0) {
164 uint16_t h = 0x1234;
165 uint16_t n = htons(h);
167 if (h == n)
168 config = 1;
169 else
170 config = 2;
171 }
173 if (config == 1)
174 return (val);
176 hi = (uint32_t)(val >> 32);
177 lo = (uint32_t)(val & 0x00000000FFFFFFFF);
179 hi = htonl(hi);
180 lo = htonl(lo);
182 return ((((uint64_t)lo) << 32) | ((uint64_t)hi));
183 } /* }}} uint64_t htonll */
184 #endif
186 static double htond(double val) /* {{{ */
187 {
188 static int config = 0;
190 union {
191 uint8_t byte[8];
192 double floating;
193 } in;
194 union {
195 uint8_t byte[8];
196 double floating;
197 } out;
199 if (config == 0) {
200 double d = 8.642135e130;
201 uint8_t c[8];
203 memcpy(c, &d, 8);
205 if ((c[0] == 0x2f) && (c[1] == 0x25) && (c[2] == 0xc0) && (c[3] == 0xc7) &&
206 (c[4] == 0x43) && (c[5] == 0x2b) && (c[6] == 0x1f) && (c[7] == 0x5b))
207 config = 1; /* need nothing */
208 else if ((c[7] == 0x2f) && (c[6] == 0x25) && (c[5] == 0xc0) &&
209 (c[4] == 0xc7) && (c[3] == 0x43) && (c[2] == 0x2b) &&
210 (c[1] == 0x1f) && (c[0] == 0x5b))
211 config = 2; /* endian flip */
212 else if ((c[4] == 0x2f) && (c[5] == 0x25) && (c[6] == 0xc0) &&
213 (c[7] == 0xc7) && (c[0] == 0x43) && (c[1] == 0x2b) &&
214 (c[2] == 0x1f) && (c[3] == 0x5b))
215 config = 3; /* int swap */
216 else
217 config = 4;
218 }
220 if (isnan(val)) {
221 out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
222 out.byte[4] = out.byte[5] = 0x00;
223 out.byte[6] = 0xf8;
224 out.byte[7] = 0x7f;
225 return (out.floating);
226 } else if (config == 1)
227 return (val);
228 else if (config == 2) {
229 in.floating = val;
230 out.byte[0] = in.byte[7];
231 out.byte[1] = in.byte[6];
232 out.byte[2] = in.byte[5];
233 out.byte[3] = in.byte[4];
234 out.byte[4] = in.byte[3];
235 out.byte[5] = in.byte[2];
236 out.byte[6] = in.byte[1];
237 out.byte[7] = in.byte[0];
238 return (out.floating);
239 } else if (config == 3) {
240 in.floating = val;
241 out.byte[0] = in.byte[4];
242 out.byte[1] = in.byte[5];
243 out.byte[2] = in.byte[6];
244 out.byte[3] = in.byte[7];
245 out.byte[4] = in.byte[0];
246 out.byte[5] = in.byte[1];
247 out.byte[6] = in.byte[2];
248 out.byte[7] = in.byte[3];
249 return (out.floating);
250 } else {
251 /* If in doubt, just copy the value back to the caller. */
252 return (val);
253 }
254 } /* }}} double htond */
256 static int nb_add_values(char **ret_buffer, /* {{{ */
257 size_t *ret_buffer_len, const lcc_value_list_t *vl) {
258 char *packet_ptr;
259 size_t packet_len;
261 uint16_t pkg_type;
262 uint16_t pkg_length;
263 uint16_t pkg_num_values;
264 uint8_t pkg_values_types[vl->values_len];
265 value_t pkg_values[vl->values_len];
267 size_t offset;
269 packet_len = sizeof(pkg_type) + sizeof(pkg_length) + sizeof(pkg_num_values) +
270 sizeof(pkg_values_types) + sizeof(pkg_values);
272 if (*ret_buffer_len < packet_len)
273 return (ENOMEM);
275 pkg_type = htons(TYPE_VALUES);
276 pkg_length = htons((uint16_t)packet_len);
277 pkg_num_values = htons((uint16_t)vl->values_len);
279 for (size_t i = 0; i < vl->values_len; i++) {
280 pkg_values_types[i] = (uint8_t)vl->values_types[i];
281 switch (vl->values_types[i]) {
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, uint16_t type,
330 uint64_t value) {
331 char *packet_ptr;
332 size_t packet_len;
334 uint16_t pkg_type;
335 uint16_t pkg_length;
336 uint64_t pkg_value;
338 size_t offset;
340 packet_len = sizeof(pkg_type) + sizeof(pkg_length) + sizeof(pkg_value);
342 if (*ret_buffer_len < packet_len)
343 return (ENOMEM);
345 pkg_type = htons(type);
346 pkg_length = htons((uint16_t)packet_len);
347 pkg_value = htonll(value);
349 packet_ptr = *ret_buffer;
350 offset = 0;
351 memcpy(packet_ptr + offset, &pkg_type, sizeof(pkg_type));
352 offset += sizeof(pkg_type);
353 memcpy(packet_ptr + offset, &pkg_length, sizeof(pkg_length));
354 offset += sizeof(pkg_length);
355 memcpy(packet_ptr + offset, &pkg_value, sizeof(pkg_value));
356 offset += sizeof(pkg_value);
358 assert(offset == packet_len);
360 *ret_buffer = packet_ptr + packet_len;
361 *ret_buffer_len -= packet_len;
362 return (0);
363 } /* }}} int nb_add_number */
365 static int nb_add_time(char **ret_buffer, /* {{{ */
366 size_t *ret_buffer_len, uint16_t type, double value) {
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, uint16_t type, const char *str,
374 size_t str_len) {
375 char *packet_ptr;
376 size_t packet_len;
378 uint16_t pkg_type;
379 uint16_t pkg_length;
381 size_t offset;
383 packet_len = sizeof(pkg_type) + sizeof(pkg_length) + str_len + 1;
384 if (*ret_buffer_len < packet_len)
385 return (ENOMEM);
387 pkg_type = htons(type);
388 pkg_length = htons((uint16_t)packet_len);
390 packet_ptr = *ret_buffer;
391 offset = 0;
392 memcpy(packet_ptr + offset, &pkg_type, sizeof(pkg_type));
393 offset += sizeof(pkg_type);
394 memcpy(packet_ptr + offset, &pkg_length, sizeof(pkg_length));
395 offset += sizeof(pkg_length);
396 memcpy(packet_ptr + offset, str, str_len);
397 offset += str_len;
398 memset(packet_ptr + offset, 0, 1);
399 offset += 1;
401 assert(offset == packet_len);
403 *ret_buffer = packet_ptr + packet_len;
404 *ret_buffer_len -= packet_len;
405 return (0);
406 } /* }}} int nb_add_string */
408 static int nb_add_value_list(lcc_network_buffer_t *nb, /* {{{ */
409 const lcc_value_list_t *vl) {
410 char *buffer = nb->ptr;
411 size_t buffer_size = nb->free;
413 const lcc_identifier_t *ident_src;
414 lcc_identifier_t *ident_dst;
416 ident_src = &vl->identifier;
417 ident_dst = &nb->state.identifier;
419 if (strcmp(ident_dst->host, ident_src->host) != 0) {
420 if (nb_add_string(&buffer, &buffer_size, TYPE_HOST, ident_src->host,
421 strlen(ident_src->host)) != 0)
422 return (-1);
423 SSTRNCPY(ident_dst->host, ident_src->host, sizeof(ident_dst->host));
424 }
426 if (strcmp(ident_dst->plugin, ident_src->plugin) != 0) {
427 if (nb_add_string(&buffer, &buffer_size, TYPE_PLUGIN, ident_src->plugin,
428 strlen(ident_src->plugin)) != 0)
429 return (-1);
430 SSTRNCPY(ident_dst->plugin, ident_src->plugin, sizeof(ident_dst->plugin));
431 }
433 if (strcmp(ident_dst->plugin_instance, ident_src->plugin_instance) != 0) {
434 if (nb_add_string(&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
435 ident_src->plugin_instance,
436 strlen(ident_src->plugin_instance)) != 0)
437 return (-1);
438 SSTRNCPY(ident_dst->plugin_instance, ident_src->plugin_instance,
439 sizeof(ident_dst->plugin_instance));
440 }
442 if (strcmp(ident_dst->type, ident_src->type) != 0) {
443 if (nb_add_string(&buffer, &buffer_size, TYPE_TYPE, ident_src->type,
444 strlen(ident_src->type)) != 0)
445 return (-1);
446 SSTRNCPY(ident_dst->type, ident_src->type, sizeof(ident_dst->type));
447 }
449 if (strcmp(ident_dst->type_instance, ident_src->type_instance) != 0) {
450 if (nb_add_string(&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
451 ident_src->type_instance,
452 strlen(ident_src->type_instance)) != 0)
453 return (-1);
454 SSTRNCPY(ident_dst->type_instance, ident_src->type_instance,
455 sizeof(ident_dst->type_instance));
456 }
458 if (nb->state.time != vl->time) {
459 if (nb_add_time(&buffer, &buffer_size, TYPE_TIME_HR, vl->time))
460 return (-1);
461 nb->state.time = vl->time;
462 }
464 if (nb->state.interval != vl->interval) {
465 if (nb_add_time(&buffer, &buffer_size, TYPE_INTERVAL_HR, vl->interval))
466 return (-1);
467 nb->state.interval = vl->interval;
468 }
470 if (nb_add_values(&buffer, &buffer_size, vl) != 0)
471 return (-1);
473 nb->ptr = buffer;
474 nb->free = buffer_size;
475 return (0);
476 } /* }}} int nb_add_value_list */
478 #if HAVE_GCRYPT_H
479 static int nb_add_signature(lcc_network_buffer_t *nb) /* {{{ */
480 {
481 char *buffer;
482 size_t buffer_size;
484 gcry_md_hd_t hd;
485 gcry_error_t err;
486 unsigned char *hash;
487 const size_t hash_length = 32;
489 /* The type, length and username have already been filled in by
490 * "lcc_network_buffer_initialize". All we do here is calculate the hash over
491 * the username and the data and add the hash value to the buffer. */
493 buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
494 assert(nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
495 buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
497 hd = NULL;
498 err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
499 if (err != 0)
500 return (-1);
502 assert(nb->password != NULL);
503 err = gcry_md_setkey(hd, nb->password, strlen(nb->password));
504 if (err != 0) {
505 gcry_md_close(hd);
506 return (-1);
507 }
509 gcry_md_write(hd, buffer, buffer_size);
510 hash = gcry_md_read(hd, GCRY_MD_SHA256);
511 if (hash == NULL) {
512 gcry_md_close(hd);
513 return (-1);
514 }
516 assert(((2 * sizeof(uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
517 memcpy(nb->buffer + (2 * sizeof(uint16_t)), hash, hash_length);
519 gcry_md_close(hd);
520 return (0);
521 } /* }}} int nb_add_signature */
523 static int nb_add_encryption(lcc_network_buffer_t *nb) /* {{{ */
524 {
525 size_t package_length;
526 char *encr_ptr; /* pointer to data being encrypted */
527 size_t encr_size;
529 char *hash_ptr; /* pointer to data being hashed */
530 size_t hash_size;
531 char hash[20];
533 uint16_t pkg_length;
534 gcry_error_t err;
536 /* Fill in the package length */
537 package_length = nb->size - nb->free;
538 pkg_length = htons((uint16_t)package_length);
539 memcpy(nb->buffer + 2, &pkg_length, sizeof(pkg_length));
541 /* Calculate what to hash */
542 hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
543 hash_size = package_length - nb->encr_header_len;
545 /* Calculate what to encrypt */
546 encr_ptr = hash_ptr - sizeof(hash);
547 encr_size = hash_size + sizeof(hash);
549 /* Calculate the SHA-1 hash */
550 gcry_md_hash_buffer(GCRY_MD_SHA1, hash, hash_ptr, hash_size);
551 memcpy(encr_ptr, hash, sizeof(hash));
553 if (nb->encr_cypher == NULL) {
554 unsigned char password_hash[32];
556 err = gcry_cipher_open(&nb->encr_cypher, GCRY_CIPHER_AES256,
557 GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
558 if (err != 0)
559 return (-1);
561 /* Calculate our 256bit key used for AES */
562 gcry_md_hash_buffer(GCRY_MD_SHA256, password_hash, nb->password,
563 strlen(nb->password));
565 err = gcry_cipher_setkey(nb->encr_cypher, password_hash,
566 sizeof(password_hash));
567 if (err != 0) {
568 gcry_cipher_close(nb->encr_cypher);
569 nb->encr_cypher = NULL;
570 return (-1);
571 }
572 } else /* if (nb->encr_cypher != NULL) */
573 {
574 gcry_cipher_reset(nb->encr_cypher);
575 }
577 /* Set the initialization vector */
578 err = gcry_cipher_setiv(nb->encr_cypher, nb->encr_iv, sizeof(nb->encr_iv));
579 if (err != 0) {
580 gcry_cipher_close(nb->encr_cypher);
581 nb->encr_cypher = NULL;
582 return (-1);
583 }
585 /* Encrypt the buffer in-place */
586 err = gcry_cipher_encrypt(nb->encr_cypher, encr_ptr, encr_size,
587 /* in = */ NULL, /* in len = */ 0);
588 if (err != 0) {
589 gcry_cipher_close(nb->encr_cypher);
590 nb->encr_cypher = NULL;
591 return (-1);
592 }
594 return (0);
595 } /* }}} int nb_add_encryption */
596 #endif
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 errno = EINVAL;
610 return (NULL);
611 }
613 nb = calloc(1, sizeof(*nb));
614 if (nb == NULL)
615 return (NULL);
617 nb->size = size;
618 nb->buffer = calloc(1, nb->size);
619 if (nb->buffer == NULL) {
620 free(nb);
621 return (NULL);
622 }
624 nb->ptr = nb->buffer;
625 nb->free = nb->size;
627 nb->seclevel = NONE;
628 nb->username = NULL;
629 nb->password = NULL;
631 return (nb);
632 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
634 void lcc_network_buffer_destroy(lcc_network_buffer_t *nb) /* {{{ */
635 {
636 if (nb == NULL)
637 return;
639 free(nb->buffer);
640 free(nb);
641 } /* }}} void lcc_network_buffer_destroy */
643 int lcc_network_buffer_set_security_level(lcc_network_buffer_t *nb, /* {{{ */
644 lcc_security_level_t level,
645 const char *username,
646 const char *password) {
647 char *username_copy;
648 char *password_copy;
650 if (level == NONE) {
651 free(nb->username);
652 free(nb->password);
653 nb->username = NULL;
654 nb->password = NULL;
655 nb->seclevel = NONE;
656 lcc_network_buffer_initialize(nb);
657 return (0);
658 }
660 if (!have_gcrypt())
661 return (ENOTSUP);
663 username_copy = strdup(username);
664 password_copy = strdup(password);
665 if ((username_copy == NULL) || (password_copy == NULL)) {
666 free(username_copy);
667 free(password_copy);
668 return (ENOMEM);
669 }
671 free(nb->username);
672 free(nb->password);
673 nb->username = username_copy;
674 nb->password = password_copy;
675 nb->seclevel = level;
677 lcc_network_buffer_initialize(nb);
678 return (0);
679 } /* }}} int lcc_network_buffer_set_security_level */
681 int lcc_network_buffer_initialize(lcc_network_buffer_t *nb) /* {{{ */
682 {
683 if (nb == NULL)
684 return (EINVAL);
686 memset(nb->buffer, 0, nb->size);
687 memset(&nb->state, 0, sizeof(nb->state));
688 nb->ptr = nb->buffer;
689 nb->free = nb->size;
691 #if HAVE_GCRYPT_H
692 if (nb->seclevel == SIGN) {
693 size_t username_len;
694 uint16_t pkg_type = htons(TYPE_SIGN_SHA256);
695 uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
697 assert(nb->username != NULL);
698 username_len = strlen(nb->username);
699 pkg_length = htons(pkg_length + ((uint16_t)username_len));
701 /* Fill in everything but the hash value here. */
702 memcpy(nb->ptr, &pkg_type, sizeof(pkg_type));
703 memcpy(nb->ptr + sizeof(pkg_type), &pkg_length, sizeof(pkg_length));
704 nb->ptr += PART_SIGNATURE_SHA256_SIZE;
705 nb->free -= PART_SIGNATURE_SHA256_SIZE;
707 memcpy(nb->ptr, nb->username, username_len);
708 nb->ptr += username_len;
709 nb->free -= username_len;
710 } else if (nb->seclevel == ENCRYPT) {
711 size_t username_length = strlen(nb->username);
712 uint16_t pkg_type = htons(TYPE_ENCR_AES256);
713 uint16_t pkg_length = 0; /* Filled in in finalize. */
714 uint16_t pkg_user_len = htons((uint16_t)username_length);
715 /* Filled in in finalize. */
716 char hash[20] = {0};
718 nb->encr_header_len = username_length;
719 nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
721 gcry_randomize((void *)&nb->encr_iv, sizeof(nb->encr_iv),
722 GCRY_STRONG_RANDOM);
724 ADD_STATIC(nb, pkg_type);
725 ADD_STATIC(nb, pkg_length);
726 ADD_STATIC(nb, pkg_user_len);
727 ADD_GENERIC(nb, nb->username, username_length);
728 ADD_GENERIC(nb, nb->encr_iv, sizeof(nb->encr_iv));
729 ADD_GENERIC(nb, hash, sizeof(hash));
730 assert((nb->encr_header_len + nb->free) == nb->size);
731 }
732 #endif
734 return (0);
735 } /* }}} int lcc_network_buffer_initialize */
737 int lcc_network_buffer_finalize(lcc_network_buffer_t *nb) /* {{{ */
738 {
739 if (nb == NULL)
740 return (EINVAL);
742 #if HAVE_GCRYPT_H
743 if (nb->seclevel == SIGN)
744 return nb_add_signature(nb);
745 else if (nb->seclevel == ENCRYPT)
746 return nb_add_encryption(nb);
747 #endif
749 return (0);
750 } /* }}} int lcc_network_buffer_finalize */
752 int lcc_network_buffer_add_value(lcc_network_buffer_t *nb, /* {{{ */
753 const lcc_value_list_t *vl) {
754 int status;
756 if ((nb == NULL) || (vl == NULL))
757 return (EINVAL);
759 status = nb_add_value_list(nb, vl);
760 return (status);
761 } /* }}} int lcc_network_buffer_add_value */
763 int lcc_network_buffer_get(lcc_network_buffer_t *nb, /* {{{ */
764 void *buffer, size_t *buffer_size) {
765 size_t sz_required;
766 size_t sz_available;
768 if ((nb == NULL) || (buffer_size == NULL))
769 return (EINVAL);
771 assert(nb->size >= nb->free);
772 sz_required = nb->size - nb->free;
773 sz_available = *buffer_size;
775 *buffer_size = sz_required;
776 if (buffer != NULL)
777 memcpy(buffer, nb->buffer,
778 (sz_available < sz_required) ? sz_available : sz_required);
780 return (0);
781 } /* }}} int lcc_network_buffer_get */