1 /* tlspool/libtlspool.c -- Library function for starttls go-get-it */
15 #include <errortable.h>
21 #include <tlspool/starttls.h>
22 #include <tlspool/commands.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
29 #include <sys/select.h>
30 #include <sys/resource.h>
31 #include <netinet/in.h>
34 #if !defined(WINDOWS_PORT)
35 #define closesocket(s) close(s)
41 #define _tprintf printf
42 #endif /* WINDOWS_PORT */
44 /* Windows supports SCTP but fails to define this IANA-standardised symbol: */
46 #define IPPROTO_SCTP 132
50 #include "libtlspool_windows.c"
52 #include "libtlspool_posix.c"
55 /* The master thread will run the receiving side of the socket that connects
56 * to the TLS Pool. The have_master_lock is used with _trylock() and will
57 * succeed to lock once, thereby approving the creation of the master thread.
60 static pthread_mutex_t have_master_lock = PTHREAD_MUTEX_INITIALIZER;
62 static void *master_thread (void *path);
64 static int poolfd = -1; /* Blocked retrieval with tlspool_socket() */
66 static pthread_cond_t updated_poolfd = PTHREAD_COND_INITIALIZER;
68 static pthread_mutex_t prng_lock = PTHREAD_MUTEX_INITIALIZER;
71 /* Retrieve the process identity of the TLS Pool from the named file, or fall
72 * back on the default file if the name is set to NULL. Returns -1 on failure.
74 int tlspool_pid (char *opt_pidfile) {
79 if (opt_pidfile == NULL) {
80 opt_pidfile = tlspool_configvar (NULL, "daemon_pidfile");
82 if (opt_pidfile == NULL) {
83 opt_pidfile = TLSPOOL_DEFAULT_PIDFILE_PATH;
85 assert (opt_pidfile != NULL);
86 fd = open (opt_pidfile, O_RDONLY);
88 size_t len = read (fd, str_pid, sizeof (str_pid) -1);
90 if ((len > 0) && (len < sizeof (str_pid))) {
92 /* pid_t */ unsigned long pid = strtoul (str_pid, &endptr, 10);
93 while ((endptr != NULL) && (isspace (*endptr))) {
96 if ((pid <= INT_MAX) && (!*endptr)) {
104 /* The library function for starttls, which is normally called through one
105 * of the two inline variations below, which start client and server sides.
107 * As a side effect, this routine ensures that a master thread is running
108 * on the poolfd. This is the process that actually contacts the TLS Pool
109 * and sets up the poolfd socket.
111 int tlspool_open_poolhandle (char *path) {
112 int poolfdsample = poolfd;
113 if (poolfdsample < 0) {
114 pthread_mutex_t local_cond_wait = PTHREAD_MUTEX_INITIALIZER;
116 // Now that we have established a (first) poolfd, start up
117 // the master thread that will recv() from it, and distribute.
118 if (pthread_mutex_trylock (&have_master_lock) == 0) {
123 path = tlspool_configvar (NULL, "socket_name");
126 path = TLSPOOL_DEFAULT_SOCKET_PATH;
128 assert (path != NULL);
129 fprintf (stderr, "DEBUG: Opening TLS Pool on socket path %s\n", path);
131 if (strlen(path) + 1 > sizeof(((struct sockaddr_un *) NULL)->sun_path)) {
132 syslog(LOG_ERR, "TLS Pool path name too long for UNIX domain socket");
136 if (pthread_create(&thr, NULL, master_thread, (void *)path) != 0) {
137 syslog(LOG_NOTICE, "Failed to create TLS Pool client master thread");
138 pthread_mutex_unlock(&have_master_lock);
139 tlspool_close_poolhandle(poolfd);
143 pthread_detach (thr);
145 // We need enough randomness to avoid clashing ctlkeys
147 seed = ((unsigned int) time (NULL)) ^ (((unsigned int) me) << 16);
151 // Wait until the master thread signals that it updated the
152 // poolfd, as long as it is invalid.
154 // The cond_wait requires a mutex to wait on; the specs leave
155 // room for different mutexes for each waiter (otherwise it
156 // would not have been supplied with each pthread_cond_wait()
157 // call) and that helps to avoid threads to contend on a
158 // shared mutex -- which is why we use a local mutex per
159 // thread: we don't need to wait for unique access.
160 assert (pthread_mutex_lock (&local_cond_wait) == 0);
161 while (poolfdsample = poolfd, poolfdsample < 0) {
162 pthread_cond_wait (&updated_poolfd, &local_cond_wait);
164 pthread_mutex_unlock (&local_cond_wait);
169 /* The request registry is an array of pointers, filled by the starttls_xxx()
170 * functions for as long as they have requests standing out. The registry
171 * permits instant lookup of a mutex to signal, so the receiving end may
172 * pickup the message in its also-registered tlspool command buffer.
175 struct registry_entry {
176 pthread_mutex_t *sig; /* Wait for master thread's recvmsg() */
177 struct tlspool_command *buf; /* Buffer to hold received command */
178 int pfd; /* Client thread's assumed poolfd */
181 static struct registry_entry **registry;
183 static pthread_mutex_t registry_lock = PTHREAD_MUTEX_INITIALIZER;
186 /* Register a request handling structure under a request ID. Registers the
187 * registry entry at the given reqid; if reqid is -1, a new one, mappable to
188 * the uint16_t type for the field is allocated and set in *reqid. When the
189 * registry entry is NULL, it will be removed from the registry and the reqid
192 * The return value is 0 on success, or -1 on failure; the most probable
193 * cause for failure is
195 static int registry_update (int *reqid, struct registry_entry *entry) {
196 static int simu = -1;
197 static uint16_t pos = 0;
199 if (registry == NULL) {
200 simu = tlspool_simultaneous_starttls ();
201 registry = calloc (simu, sizeof (struct registry_entry *));
202 if (registry == NULL) {
203 syslog (LOG_NOTICE, "Failed to allocate TLS Pool request registry");
208 /* Set the entry in the given entry */
210 /* Allocate an entry in the registry */
211 assert (pthread_mutex_lock (®istry_lock) == 0);
214 if (registry [pos] == NULL) {
215 registry [pos] = entry;
224 pthread_mutex_unlock (®istry_lock);
230 if ((*reqid < 0) || (*reqid >= simu)) {
233 /* Remove the entry from the given entry */
234 assert (pthread_mutex_lock (®istry_lock) == 0);
235 registry [*reqid] = NULL; /* may not be atomic */
237 pthread_mutex_unlock (®istry_lock);
243 /* Flush registry entries with an older poolfd value; this is used after
244 * reconnecting to the TLS Pool, presumably having closed the old poolfd.
245 * Any outstanding registry entries will be sent an ERROR value at this
248 static void registry_flush (int poolfd) {
249 int regid = tlspool_simultaneous_starttls ();
250 assert (pthread_mutex_lock (®istry_lock) == 0);
251 while (regid-- > 0) {
252 struct registry_entry *entry = registry [regid];
253 if ((entry != NULL) && (entry->pfd != poolfd)) {
254 // Fill the cmd buffer with an error message
255 entry->buf->pio_cmd = PIOC_ERROR_V2;
256 entry->buf->pio_data.pioc_error.tlserrno = E_TLSPOOL_CLIENT_DISCONNECT;
257 strncpy (entry->buf->pio_data.pioc_error.message,
258 "TLS Pool connection closed",
259 sizeof (entry->buf->pio_data.pioc_error.message));
260 // Signal continuation to the recipient
261 pthread_mutex_unlock (entry->sig);
262 // Do not remove the entry; the recipient will do this
265 pthread_mutex_unlock (®istry_lock);
268 /* The master thread issues the recv() commands on the TLS Pool socket, and
269 * redistributes the result to the registry entries that are waiting for
270 * the data. The thread is started when the poolfd is first requested.
272 * Having a dedicated master thread is a great design simplification over
273 * temporary promotion of one of the application threads to a master status.
274 * The locking involved in the distinct state without a master, and the
275 * raceconditions while establishing the first on-demand master are dreadful.
277 * An additional advantage of a separate master thread is that it will
278 * instantly notice when the TLS Pool goes offline. At this time, it will
279 * lock the registry and cancel any requests in the registry that are
280 * waiting for the older connection. Subsequent attempts to receive are
281 * stopped immediately. The TLS Pool then tries to reconnect to the
282 * TLS Pool anew, using exponential back-off.
284 static void *master_thread (void *path) {
286 struct tlspool_command cmd;
287 //NOT-USED// char anc [CMSG_SPACE(sizeof (int))];
288 struct registry_entry *entry;
295 // If any old socket clients persist, tell them that the
296 // TLS Pool has been disconnected.
298 int poolfdcopy = poolfd;
299 // printf ("DEBUG: Removing old poolfd %d\n", poolfd);
302 tlspool_close_poolhandle (poolfdcopy);
305 // First, connect to the TLS Pool; upon failure, retry
306 // with 1s, 2s, 4s, 8s, 16s, 32s, 32s, 32s, ... intervals.
309 int newpoolfd = open_pool (path);
310 if (newpoolfd >= 0) {
314 // Signal a newly set poolfd value to all waiting.
315 // Note that we do not need to claim a mutex first;
316 // there is always one writer to poolfd (namely, this
317 // master_thread) and the rest simply reads it. This
318 // makes a silent assumption of atomic writes to the
319 // poolfd, which seems fair because the size of an
320 // fd table has been smaller than the size of the
321 // data bus since the times of ZX Spectrum and CP/M.
322 pthread_cond_broadcast (&updated_poolfd);
323 // printf ("DEBUG: Signalled slave threads with poolfd %d\n", poolfd);
325 // Wait before repeating, with exponential back-off
329 if (usec > 32000000) {
335 // We now have an established link to the TLS Pool, until
336 // further notice -- that is, until the TLS Pool terminates.
337 // At that time, a break ends the following loop and jumps
338 // back up to the re-connection logic.
340 int retval = os_recvmsg_command(poolfd, &cmd);
342 if ((retval == -1) && (errno = EINTR)) {
343 continue; // Badly masked user signal
349 #endif /* !WINDOWS_PORT */
351 // This includes EPIPE, or EOF, for detached
352 // TLS Pool; the treatment is to reconnect.
353 // printf ("DEBUG: recvmsg() returned -1 due to: %s\n", strerror (errno));
357 // Determine where to post the received message
358 entry = registry [cmd.pio_reqid];
360 // Protocol error! Client detached!
361 // printf ("DEBUG: Client detached! poolfd=%d, cmd=0x%08x, reqid=%d, cbid=%d\n", poolfd, cmd.pio_cmd, cmd.pio_reqid, cmd.pio_cbid);
362 if ((cmd.pio_cbid != 0) && (cmd.pio_cmd != PIOC_ERROR_V2)) {
363 // printf ("DEBUG: Will send PIOC_ERROR_V2 as callback to TLS Pool\n");
364 // TLS Pool is waiting for a callback;
365 // Send it an ERROR message instead.
366 cmd.pio_cmd = PIOC_ERROR_V2;
367 cmd.pio_data.pioc_error.tlserrno = E_TLSPOOL_CLIENT_REFUSES_CALLBACK;
368 strncpy (cmd.pio_data.pioc_error.message,
369 "TLS Pool client will not partake in callback",
370 sizeof (cmd.pio_data.pioc_error.message));
371 os_sendmsg_command (poolfd, &cmd, -1);
373 // printf ("DEBUG: Sent PIOC_ERROR_V2 as callback to TLS Pool\n");
375 // Do not attempt delivery
378 if (entry->pfd != poolfd) {
379 // printf ("DEBUG: Registry entry has older poolfd %d not %d, flushing registry\n", entry->pfd, poolfd);
380 registry_flush (poolfd);
382 memcpy (entry->buf, &cmd, sizeof (cmd));
383 //NOT-USED// deliver anc or passfd to recipient
384 pthread_mutex_unlock (entry->sig);
385 // printf ("DEBUG: Signalled slave with new message in place\n");
391 /* Consider handling the message reception interface, if no other thread is
392 * doing that yet. Then, wait until a message has been received.
394 static void registry_recvmsg (struct registry_entry *entry) {
395 static int lastpoolfd = -1;
397 // Detect poolfd socket change for potential dangling recipients
398 if (entry->pfd != lastpoolfd) {
399 lastpoolfd = tlspool_open_poolhandle (NULL);
400 if ((entry->pfd != lastpoolfd) && (lastpoolfd >= 0)) {
401 // Signal PIOC_ERROR to outdated recipients.
402 // (That will include the current recipient.)
403 registry_flush (lastpoolfd);
407 // Now wait for the registered command structure to be filled
408 // by the master thread. Note that the call to tlspool_open_poolhandle()
409 // above is made when this function is first called, and that
410 // routine ensures running of the master thread.
411 assert (pthread_mutex_lock (entry->sig) == 0);
415 /* The library function for ping, which is called to establish the API
416 * version and a list of facilities supported by the TLS Pool. The data
417 * supplied to the TLS Pool should represent the environment of the
418 * application, which is why no defaults are provided by this function
419 * but the application should supply all ping data.
421 * The pioc_ping structure will be copied into the command structure,
422 * and upon completion it will be copied back. Normally, the application
423 * would set YYYYMMDD_producer to TLSPOOL_IDENTITY_V2, and facilities
424 * to PIOF_FACILITY_ALL_CURRENT. The TLS Pool overwrites the former and
425 * resets unsupported bits in the latter. Note that facilities may be
426 * unsupported due to the compile-time environment of the TLS Pool or
427 * because it was configured without the requested support.
429 * This function returns zero on success, and -1 on failure. In case of
430 * failure, errno will be set.
432 int tlspool_ping (pingpool_t *pingdata) {
433 struct tlspool_command cmd;
434 pthread_mutex_t recvwait = PTHREAD_MUTEX_INITIALIZER;
435 struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
436 int entry_reqid = -1;
439 /* Prepare command structure */
440 poolfd = tlspool_open_poolhandle (NULL);
441 // printf ("DEBUG: poolfd = %d\n", poolfd);
446 /* Finish setting up the registry entry */
448 pthread_mutex_lock (&recvwait); // Will await unlock by master
449 /* Determine the request ID */
450 if (registry_update (&entry_reqid, ®ent) != 0) {
454 memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
455 cmd.pio_reqid = entry_reqid;
457 cmd.pio_cmd = PIOC_PING_V2;
458 memcpy (&cmd.pio_data.pioc_ping, pingdata, sizeof (struct pioc_ping));
459 if (os_sendmsg_command (poolfd, &cmd, -1) == -1) {
460 // Let SIGPIPE be reported as EPIPE
461 registry_update (&entry_reqid, NULL);
462 // errno inherited from sendmsg()
465 /* Await response and process it */
466 registry_recvmsg (®ent);
467 registry_update (&entry_reqid, NULL);
468 switch (cmd.pio_cmd) {
470 /* Bad luck, we failed */
471 syslog (LOG_INFO, "TLS Pool error to tlspool_ping(): %s", cmd.pio_data.pioc_error.message);
472 errno = cmd.pio_data.pioc_error.tlserrno;
475 /* Wheee!!! we're done */
476 memcpy (pingdata, &cmd.pio_data.pioc_ping, sizeof (pingpool_t));
479 /* V2 protocol error */
486 /* The library function for starttls, which is normally called through one
487 * of the two inline variations below, which start client and server sides.
489 * The cryptfd handle supplies the TLS connection that is assumed to have
490 * been setup. When the function ends, either in success or failure, this
491 * handle will no longer be available to the caller; the responsibility of
492 * closing it is passed on to the function and/or the TLS Pool.
494 * The tlsdata structure will be copied into the command structure,
495 * and upon completion it will be copied back. You can use it to
496 * communicate flags, protocols and other parameters, including the
497 * most important settings -- local and remote identifiers. See
498 * the socket protocol document for details.
500 * The privdata handle is used in conjunction with the namedconnect() call;
501 * it is passed on to connect the latter to the context from which it was
502 * called and is not further acted upon by this function.
504 * This function returns zero on success, and -1 on failure. In case of
505 * failure, errno will be set.
507 int tlspool_starttls (int cryptfd, starttls_t *tlsdata,
509 int (*namedconnect) (starttls_t *tlsdata,void *privdata)) {
510 struct tlspool_command cmd;
511 pthread_mutex_t recvwait = PTHREAD_MUTEX_INITIALIZER;
512 struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
513 int entry_reqid = -1;
518 int renegotiate = 0 != (tlsdata->flags & PIOF_STARTTLS_RENEGOTIATE);
519 int type = ipproto_to_sockettype (tlsdata->ipproto);
524 /* Prepare command structure */
525 poolfd = tlspool_open_poolhandle (NULL);
527 closesocket(cryptfd);
531 /* Finish setting up the registry entry */
533 pthread_mutex_lock (&recvwait); // Will await unlock by master
534 /* Determine the request ID */
535 if (registry_update (&entry_reqid, ®ent) != 0) {
536 closesocket(cryptfd);
540 memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
541 cmd.pio_reqid = entry_reqid;
543 cmd.pio_cmd = PIOC_STARTTLS_V2;
544 memcpy (&cmd.pio_data.pioc_starttls, tlsdata, sizeof (struct pioc_starttls));
546 #if TLSPOOL_CTLKEYLEN != 16
547 # error "Failure on assumption of 16 bytes per ctlkey"
551 assert (pthread_mutex_lock (&prng_lock) == 0);
552 #if RAND_MAX >= 0xffffffff
553 * (uint32_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 0] = random ();
554 * (uint32_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 4] = random ();
555 * (uint32_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 8] = random ();
556 * (uint32_t *) &cmd.pio_data.pioc_starttls.ctlkey [12] = random ();
557 #elif RAND_MAX >= 0xffff
558 * (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 0] = random ();
559 * (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 2] = random ();
560 * (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 4] = random ();
561 * (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 6] = random ();
562 * (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 8] = random ();
563 * (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [10] = random ();
564 * (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [12] = random ();
565 * (uint16_t *) &cmd.pio_data.pioc_starttls.ctlkey [14] = random ();
566 #elif RAND_MAX >= 0xff
567 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 0] = random ();
568 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 1] = random ();
569 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 2] = random ();
570 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 3] = random ();
571 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 4] = random ();
572 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 5] = random ();
573 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 6] = random ();
574 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 7] = random ();
575 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 8] = random ();
576 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [ 9] = random ();
577 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [10] = random ();
578 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [11] = random ();
579 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [12] = random ();
580 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [13] = random ();
581 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [14] = random ();
582 * (uint8_t *) &cmd.pio_data.pioc_starttls.ctlkey [15] = random ();
584 # error "Unsuitable random() function due to RAND_MAX value < 0xff"
586 pthread_mutex_unlock (&prng_lock);
588 // printf ("DEBUG: ctlkey =");
589 // {int i; for (i=0;i<16;i++) printf (" %02x", cmd.pio_data.pioc_starttls.ctlkey [i]);}
592 /* Send the request */
593 if (os_sendmsg_command(poolfd, &cmd, renegotiate ? -1 : cryptfd) == -1) {
594 // Let SIGPIPE be reported as EPIPE
596 registry_update (&entry_reqid, NULL);
597 // errno inherited from os_sendmsg_command()
600 sentfd = cryptfd; /* Close anytime after response and before fn end */
602 /* Handle responses until success or error */
605 //NOTUSED// mh.msg_control = anc;
606 //NOTUSED// mh.msg_controllen = sizeof (anc);
607 registry_recvmsg (®ent);
612 switch (cmd.pio_cmd) {
614 /* Bad luck, we failed */
615 syslog (LOG_INFO, "TLS Pool error to tlspool_starttls(): %s", cmd.pio_data.pioc_error.message);
616 registry_update (&entry_reqid, NULL);
617 errno = cmd.pio_data.pioc_error.tlserrno;
619 case PIOC_STARTTLS_LOCALID_V2:
620 case PIOC_PLAINTEXT_CONNECT_V2:
622 fprintf (stderr, "Callback to check local id or provide plaintext fd for localid=%s\n", cmd.pio_data.pioc_starttls.localid);
623 plainfd = (*namedconnect) (&cmd.pio_data.pioc_starttls, privdata);
625 /* default namedconnect() implementation */
626 plainfd = * (int *) privdata;
627 if ((plainfd < 0) && (cmd.pio_cmd == PIOC_PLAINTEXT_CONNECT_V2)) {
628 plainfd = tlspool_namedconnect_default (&cmd.pio_data.pioc_starttls, privdata);
632 cmd.pio_cmd = PIOC_ERROR_V2;
633 cmd.pio_data.pioc_error.tlserrno = errno;
635 /* We may now have a value to send in plainfd */
636 /* Now supply plainfd in the callback response */
638 if (os_sendmsg_command(poolfd, &cmd, plainfd) == -1) {
639 // Let SIGPIPE be reported as EPIPE
644 registry_update (&entry_reqid, NULL);
645 // errno inherited from np_send_command()
648 break; // Loop around and try again
649 case PIOC_STARTTLS_V2:
650 /* Wheee!!! we're done */
654 /* V2 protocol error */
655 registry_update (&entry_reqid, NULL);
661 /* Close the now-duplicated or now-erradicated plaintext fd */
663 memcpy (tlsdata, &cmd.pio_data.pioc_starttls, sizeof (struct pioc_starttls));
664 // printf ("DEBUG: Returning control key %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", tlsdata->ctlkey [0], tlsdata->ctlkey [1], tlsdata->ctlkey [2], tlsdata->ctlkey [3], tlsdata->ctlkey [4], tlsdata->ctlkey [5], tlsdata->ctlkey [6], tlsdata->ctlkey [7], tlsdata->ctlkey [8], tlsdata->ctlkey [9], tlsdata->ctlkey [10], tlsdata->ctlkey [11], tlsdata->ctlkey [12], tlsdata->ctlkey [13], tlsdata->ctlkey [14], tlsdata->ctlkey [15]);
665 registry_update (&entry_reqid, NULL);
670 /* The library function to send a control connection command, notably
671 * TLSPOOL_CONTROL_DETACH and TLSPOOL_CONTROL_REATTACH.
673 * This function returns zero on success, and -1 on failure. In case of
674 * failure, errno will be set.
676 int _tlspool_control_command (int cmdcode, uint8_t *ctlkey) {
677 struct tlspool_command cmd;
678 pthread_mutex_t recvwait = PTHREAD_MUTEX_INITIALIZER;
679 struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
680 int entry_reqid = -1;
683 /* Prepare command structure */
684 poolfd = tlspool_open_poolhandle (NULL);
689 /* Finish setting up the registry entry */
691 pthread_mutex_lock (&recvwait); // Will await unlock by master
692 /* Determine the request ID */
693 if (registry_update (&entry_reqid, ®ent) != 0) {
697 memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
698 cmd.pio_reqid = entry_reqid;
700 cmd.pio_cmd = cmdcode;
701 memcpy (&cmd.pio_data.pioc_control.ctlkey, ctlkey, TLSPOOL_CTLKEYLEN);
702 // printf ("DEBUG: Using control key %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", cmd.pio_data.pioc_control.ctlkey [0], cmd.pio_data.pioc_control.ctlkey [1], cmd.pio_data.pioc_control.ctlkey [2], cmd.pio_data.pioc_control.ctlkey [3], cmd.pio_data.pioc_control.ctlkey [4], cmd.pio_data.pioc_control.ctlkey [5], cmd.pio_data.pioc_control.ctlkey [6], cmd.pio_data.pioc_control.ctlkey [7], cmd.pio_data.pioc_control.ctlkey [8], cmd.pio_data.pioc_control.ctlkey [9], cmd.pio_data.pioc_control.ctlkey [10], cmd.pio_data.pioc_control.ctlkey [11], cmd.pio_data.pioc_control.ctlkey [12], cmd.pio_data.pioc_control.ctlkey [13], cmd.pio_data.pioc_control.ctlkey [14], cmd.pio_data.pioc_control.ctlkey [15]);
703 if (os_sendmsg_command (poolfd, &cmd, -1) == -1) {
704 // Let SIGPIPE be reported as EPIPE
705 registry_update (&entry_reqid, NULL);
706 // errno inherited from os_sendmsg_command()
709 /* Receive the response */
710 registry_recvmsg (®ent);
711 switch (cmd.pio_cmd) {
712 case PIOC_SUCCESS_V2:
717 errno = cmd.pio_data.pioc_error.tlserrno;
727 /* Generate a pseudo-random sequence based on session cryptographic keys.
729 * In the case of TLS, this adheres to RFC 5705; other protocols may or
730 * may not support a similar mechanism, in which case an error is returned.
732 * This leans on access privileges to an existing connection at a meta-level,
733 * for which we use the customary ctlkey verification mechanism introduced with
734 * tlspool_starttls (). Note that random material may be used for security
735 * purposes, such as finding the same session key for both sides deriving from
736 * prior key negotiation; the protection of a ctlkey for such applications is
739 * The inputs to this function must adhere to the following restrictions:
740 * - label must not be a NULL pointer, but opt_ctxvalue may be set to NULL
741 * to bypass the use of a context value. Note that passing an empty string
742 * in opt_ctxvalue is different from not providing the string at all by
743 * setting it to NULL.
744 * - label and opt_ctxvalue (if non-NULL) refer to ASCII strings with
745 * printable characters, terminated with a NUL character. The maximum
746 * string length of each is 254 bytes.
747 * - prng_len holds the requested number of pseudo-random bytes
748 * - prng_buf points is a non-NULL pointer to a buffer that can hold
751 * If the operation succeeds, then prng_buf holds prng_len bytes of random
752 * material, and zero is returned. If the operation fails, then prng_buf
753 * is filled with zero bytes (to make it stand out as a rather rare case of
754 * a random byte string) and -1 is returned.
756 * Note a few restrictions to the generality of this function, as a result of
757 * the underlying packet format for the communication with the TLS Pool; but
758 * the dimensions have been choosen such that these restrictions would not
759 * typically be a problem in practice:
760 * - it constrains the string lengths of label and opt_ctxvalue
761 * - it constrains prng_len to a maximum value of TLSPOOL_PRNGBUFLEN
763 * The TLS Pool may limit certain TLS PRNG labels, in adherence to the
764 * IANA-maintained TLS Exporter Label Registry. It additionally supports
765 * the EXPERIMENTAL label prefix specified in RFC 5705.
767 * Be advised that the maximum size of buffer may increase in future releases.
768 * So, be sure to use TLSPOOL_PRNGBUFLEN which holds the header-file defined
771 int tlspool_prng (char *label,
772 uint16_t ctxvalue_len, uint8_t *opt_ctxvalue,
773 uint16_t prng_len, uint8_t *prng_buf,
775 struct tlspool_command cmd;
776 pthread_mutex_t recvwait = PTHREAD_MUTEX_INITIALIZER;
777 struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
778 int entry_reqid = -1;
780 memset (prng_buf, 0, prng_len);
783 if ((prng_len > TLSPOOL_PRNGBUFLEN) ||
784 (label == NULL) || (strlen (label) > 254) ||
785 ((opt_ctxvalue != NULL) &&
786 ((ctxvalue_len > 254) ||
787 (strlen (label) + ctxvalue_len > TLSPOOL_PRNGBUFLEN - TLSPOOL_CTLKEYLEN)))) {
792 /* Prepare command structure */
793 poolfd = tlspool_open_poolhandle (NULL);
798 /* Finish setting up the registry entry */
800 pthread_mutex_lock (&recvwait); // Will await unlock by master
801 /* Determine the request ID */
802 if (registry_update (&entry_reqid, ®ent) != 0) {
806 memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
807 cmd.pio_reqid = entry_reqid;
809 cmd.pio_cmd = PIOC_PRNG_V2;
810 cmd.pio_data.pioc_prng.prng_len = prng_len;
811 memcpy (cmd.pio_data.pioc_prng.buffer, ctlkey, TLSPOOL_CTLKEYLEN);
812 cmd.pio_data.pioc_prng.in1_len = strlen (label);
813 memcpy (cmd.pio_data.pioc_prng.buffer + TLSPOOL_CTLKEYLEN, label, cmd.pio_data.pioc_prng.in1_len);
814 if (opt_ctxvalue != NULL) {
815 cmd.pio_data.pioc_prng.in2_len = ctxvalue_len;
816 memcpy (cmd.pio_data.pioc_prng.buffer + TLSPOOL_CTLKEYLEN + cmd.pio_data.pioc_prng.in1_len, opt_ctxvalue, cmd.pio_data.pioc_prng.in2_len);
818 cmd.pio_data.pioc_prng.in2_len = -1;
820 if (os_sendmsg_command (poolfd, &cmd, -1) == -1) {
821 // Let SIGPIPE be reported as EPIPE
822 registry_update (&entry_reqid, NULL);
823 // errno inherited from sendmsg()
826 /* Await response and process it */
827 registry_recvmsg (®ent);
828 registry_update (&entry_reqid, NULL);
829 switch (cmd.pio_cmd) {
831 /* Bad luck, we failed */
832 syslog (LOG_INFO, "TLS Pool error to tlspool_prng(): %s", cmd.pio_data.pioc_error.message);
833 errno = cmd.pio_data.pioc_error.tlserrno;
836 /* Wheee!!! we're done */
837 memcpy (prng_buf, cmd.pio_data.pioc_prng.buffer, prng_len);
840 /* V2 protocol error */
846 /* Check or retrieve information from the TLS Pool. Use kind_info to select
847 * the kind of information, with a PIOK_INFO_xxx tag from <tlspool/commands.h>.
849 * The amount of data will not exceed TLSPOOL_INFOBUFLEN, and you should
850 * provide a buffer that can hold at least that number of bytes. In addition,
851 * you should provide a pointer to a length. Initialise this length to ~0
852 * to perform a query. Any other length indicates a match, including the
853 * value 0 for a match with an empty string.
855 * You should provide the ctlkey from the tlspool_starttls() exchange to
856 * be able to reference the connection that you intend to query.
858 * This function returns zero on success, and -1 on failure. In case of
859 * failure, errno will be set. Specifically useful to know is that errno
860 * is set to E_TLSPOOL_INFOKIND_UNKNOWN when the TLS Pool has no code to
861 * provide the requested information (and so its current version will not
862 * provide it to any query) and to E_TLSPOOL_INFO_NOT_FOUND when the
863 * TLS Pool cannot answer the info query for other reasons, such as not
864 * having the information available in the current connection.
866 * The error ENOSYS is returned when the TLS Pool has no implementation
867 * for the query you made.
869 int tlspool_info (uint32_t info_kind,
870 uint8_t infobuf [TLSPOOL_INFOBUFLEN], uint16_t *infolenptr,
872 struct tlspool_command cmd;
873 pthread_mutex_t recvwait = PTHREAD_MUTEX_INITIALIZER;
874 struct registry_entry regent = { .sig = &recvwait, .buf = &cmd };
875 int entry_reqid = -1;
878 if ((*infolenptr > TLSPOOL_INFOBUFLEN) && (*infolenptr != 0xffff)) {
882 /* Prepare command structure */
883 poolfd = tlspool_open_poolhandle (NULL);
888 /* Finish setting up the registry entry */
890 pthread_mutex_lock (&recvwait); // Will await unlock by master
891 /* Determine the request ID */
892 if (registry_update (&entry_reqid, ®ent) != 0) {
896 /* Construct the command message */
897 memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
898 cmd.pio_reqid = entry_reqid;
900 cmd.pio_cmd = PIOC_INFO_V2;
901 cmd.pio_data.pioc_info.info_kind = info_kind;
902 cmd.pio_data.pioc_info.len = *infolenptr;
903 memcpy (cmd.pio_data.pioc_info.ctlkey, ctlkey, TLSPOOL_CTLKEYLEN);
904 if ((*infolenptr > 0) && (*infolenptr < TLSPOOL_INFOBUFLEN)) {
905 memcpy (cmd.pio_data.pioc_info.buffer, infobuf, *infolenptr);
907 /* Send the command message */
908 if (os_sendmsg_command (poolfd, &cmd, -1) == -1) {
909 // Let SIGPIPE be reported as EPIPE
910 registry_update (&entry_reqid, NULL);
911 // errno inherited from sendmsg()
914 /* Await response and process it */
915 registry_recvmsg (®ent);
916 registry_update (&entry_reqid, NULL);
917 switch (cmd.pio_cmd) {
919 /* Bad luck, we failed */
920 syslog (LOG_INFO, "TLS Pool error to tlspool_info(): %s", cmd.pio_data.pioc_error.message);
921 errno = cmd.pio_data.pioc_error.tlserrno;
924 /* Wheee!!! we're done */
925 *infolenptr = cmd.pio_data.pioc_info.len;
926 if ((*infolenptr > 0) && (*infolenptr < TLSPOOL_INFOBUFLEN)) {
927 memcpy (infobuf, cmd.pio_data.pioc_info.buffer, *infolenptr);
931 /* V2 protocol error */