1 /* tlspool/starttls.c -- Setup and validation handler for TLS session */
17 #include <sys/types.h>
18 #include <sys/socket.h>
20 #include <gnutls/gnutls.h>
21 #include <gnutls/pkcs11.h>
22 #include <gnutls/abstract.h>
24 #include <tlspool/internal.h>
31 #if EXPECTED_LID_TYPE_COUNT != LID_TYPE_CNT
32 #error "Set EXPECTED_LID_TYPE_COUNT in <tlspool/internal.h> to match LID_TYPE_CNT"
36 /* This module hosts TLS handlers which treat an individual connection.
38 * Initially, the TLS setup is processed, which means validating the
39 * connection. If and when this succeeds, a continued process is needed
40 * to encrypt and decrypt traffic while it is in transit.
42 * Every TLS connection (including the attempt to set it up) is hosted in
43 * its own thread. This means that it can abide time to wait for PINENTRY
44 * or LOCALID responses. It also means a very clear flow when the time
45 * comes to destroy a connection.
47 * While encrypting and decrypting traffic passing through, the thread
48 * will use its own poll() call, and thus offload the potentially large
49 * one of the main thread, which is supposed to be a low-traffic task.
50 * The set of file descriptors used by the session-handler threads are
51 * in contrast very small and can easily be started for every single
52 * packet passing through.
54 * Might the user terminate a process while this one is waiting for a
55 * callback command request, then the main TLS pool thread will take
56 * care of taking down this thread. To that end, it sets the followup
57 * pointer that normally holds a callback response to NULL, and then
58 * permits this thread to run again. This will lead to a shutdown of
59 * this process, and proper closing of all connections. The remote peer
60 * will therefore see the result of a local kill as a connection reset.
62 * In case one of the end points of the connection is terminated, a
63 * similar thing will happen; the thread will terminate itself after
64 * a cleanup of any outstanding resources. This, once again, leads
65 * to passing on the reset of a connection between the encrypted and
66 * side of the connection.
72 * GnuTLS infrastructure setup.
73 * Session-shared DH-keys, credentials structures, and so on.
75 static gnutls_dh_params_t dh_params;
78 gnutls_credentials_type_t credtp;
82 #define EXPECTED_SRV_CREDCOUNT 3
83 #define EXPECTED_CLI_CREDCOUNT 2
84 static struct credinfo srv_creds [EXPECTED_SRV_CREDCOUNT];
85 static struct credinfo cli_creds [EXPECTED_CLI_CREDCOUNT];
86 static int srv_credcount = 0;
87 static int cli_credcount = 0;
90 /* Map a GnuTLS call (usually a function call) to a POSIX errno,
91 * optionally reporting an errstr to avoid loosing information.
92 * Retain errno if it already exists.
93 * Continue if errno differs from 0, GnuTLS may "damage" it even when OK. */
94 #define E_g2e(errstr,gtlscall) { \
95 if (gtls_errno == GNUTLS_E_SUCCESS) { \
96 int gtls_errno = (gtlscall); \
97 if (gtls_errno != GNUTLS_E_SUCCESS) { \
98 error_gnutls2posix (gtls_errno, errstr); \
103 /* Cleanup when GnuTLS leaves errno damaged but returns no gtls_errno */
104 #define E_gnutls_clear_errno() { \
105 if (gtls_errno == GNUTLS_E_SUCCESS) { \
110 /* Error number translation, including error string setup. See E_g2e(). */
111 void error_gnutls2posix (int gtls_errno, char *new_errstr) {
113 register int newerrno;
116 if (gtls_errno == GNUTLS_E_SUCCESS) {
119 errstr = error_getstring ();
120 if (errstr != NULL) {
124 // Report the textual error
125 if (new_errstr == NULL) {
126 new_errstr = "GnuTLS error";
128 tlog (TLOG_TLS, LOG_ERR, "%s: %s",
130 gnutls_strerror (gtls_errno));
131 error_setstring (new_errstr);
133 // Translate error to a POSIX errno value
134 switch (gtls_errno) {
135 case GNUTLS_E_SUCCESS:
137 case GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM:
138 case GNUTLS_E_UNKNOWN_CIPHER_TYPE:
139 case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
140 case GNUTLS_E_UNWANTED_ALGORITHM:
141 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
142 case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
143 case GNUTLS_E_X509_UNKNOWN_SAN:
144 case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
145 case GNUTLS_E_UNKNOWN_PK_ALGORITHM:
146 case GNUTLS_E_NO_TEMPORARY_RSA_PARAMS:
147 case GNUTLS_E_NO_COMPRESSION_ALGORITHMS:
148 case GNUTLS_E_NO_CIPHER_SUITES:
149 case GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED:
150 case GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE:
151 case GNUTLS_E_UNKNOWN_HASH_ALGORITHM:
152 case GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE:
153 case GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE:
154 case GNUTLS_E_NO_TEMPORARY_DH_PARAMS:
155 case GNUTLS_E_UNKNOWN_ALGORITHM:
156 case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
157 case GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED:
158 case GNUTLS_E_X509_UNSUPPORTED_OID:
159 case GNUTLS_E_CHANNEL_BINDING_NOT_AVAILABLE:
160 case GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL:
161 case GNUTLS_E_ECC_NO_SUPPORTED_CURVES:
162 case GNUTLS_E_ECC_UNSUPPORTED_CURVE:
163 case GNUTLS_E_X509_UNSUPPORTED_EXTENSION:
164 case GNUTLS_E_NO_CERTIFICATE_STATUS:
165 case GNUTLS_E_NO_APPLICATION_PROTOCOL:
166 #ifdef GNUTLS_E_NO_SELF_TEST
167 case GNUTLS_E_NO_SELF_TEST:
169 newerrno = EOPNOTSUPP;
171 case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
172 case GNUTLS_E_INVALID_REQUEST:
175 case GNUTLS_E_INVALID_SESSION:
176 case GNUTLS_E_REHANDSHAKE:
177 case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
180 case GNUTLS_E_PUSH_ERROR:
181 case GNUTLS_E_PULL_ERROR:
182 case GNUTLS_E_PREMATURE_TERMINATION:
183 case GNUTLS_E_SESSION_EOF:
184 newerrno = ECONNRESET;
186 case GNUTLS_E_UNEXPECTED_PACKET:
187 case GNUTLS_E_WARNING_ALERT_RECEIVED:
188 case GNUTLS_E_FATAL_ALERT_RECEIVED:
189 case GNUTLS_E_LARGE_PACKET:
190 case GNUTLS_E_ERROR_IN_FINISHED_PACKET:
191 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
192 case GNUTLS_E_MPI_SCAN_FAILED:
193 case GNUTLS_E_DECRYPTION_FAILED:
194 case GNUTLS_E_DECOMPRESSION_FAILED:
195 case GNUTLS_E_COMPRESSION_FAILED:
196 case GNUTLS_E_BASE64_DECODING_ERROR:
197 case GNUTLS_E_MPI_PRINT_FAILED:
198 case GNUTLS_E_GOT_APPLICATION_DATA:
199 case GNUTLS_E_RECORD_LIMIT_REACHED:
200 case GNUTLS_E_ENCRYPTION_FAILED:
201 case GNUTLS_E_PK_ENCRYPTION_FAILED:
202 case GNUTLS_E_PK_DECRYPTION_FAILED:
203 case GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER:
204 case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
205 case GNUTLS_E_PKCS1_WRONG_PAD:
206 case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
207 case GNUTLS_E_FILE_ERROR:
208 case GNUTLS_E_ASN1_ELEMENT_NOT_FOUND:
209 case GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND:
210 case GNUTLS_E_ASN1_DER_ERROR:
211 case GNUTLS_E_ASN1_VALUE_NOT_FOUND:
212 case GNUTLS_E_ASN1_GENERIC_ERROR:
213 case GNUTLS_E_ASN1_VALUE_NOT_VALID:
214 case GNUTLS_E_ASN1_TAG_ERROR:
215 case GNUTLS_E_ASN1_TAG_IMPLICIT:
216 case GNUTLS_E_ASN1_TYPE_ANY_ERROR:
217 case GNUTLS_E_ASN1_SYNTAX_ERROR:
218 case GNUTLS_E_ASN1_DER_OVERFLOW:
219 case GNUTLS_E_TOO_MANY_EMPTY_PACKETS:
220 case GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS:
221 case GNUTLS_E_SRP_PWD_PARSING_ERROR:
222 case GNUTLS_E_BASE64_ENCODING_ERROR:
223 case GNUTLS_E_OPENPGP_KEYRING_ERROR:
224 case GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR:
225 case GNUTLS_E_OPENPGP_SUBKEY_ERROR:
226 case GNUTLS_E_CRYPTO_ALREADY_REGISTERED:
227 case GNUTLS_E_HANDSHAKE_TOO_LARGE:
228 case GNUTLS_E_BAD_COOKIE:
229 case GNUTLS_E_PARSING_ERROR:
230 case GNUTLS_E_CERTIFICATE_LIST_UNSORTED:
231 case GNUTLS_E_NO_PRIORITIES_WERE_SET:
232 #ifdef GNUTLS_E_PK_GENERATION_ERROR
233 case GNUTLS_E_PK_GENERATION_ERROR:
235 #ifdef GNUTLS_E_SELF_TEST_ERROR
236 case GNUTLS_E_SELF_TEST_ERROR:
238 #ifdef GNUTLS_E_SOCKETS_INIT_ERROR
239 case GNUTLS_E_SOCKETS_INIT_ERROR:
243 case GNUTLS_E_MEMORY_ERROR:
244 case GNUTLS_E_SHORT_MEMORY_BUFFER:
250 case GNUTLS_E_EXPIRED:
251 case GNUTLS_E_TIMEDOUT:
252 newerrno = ETIMEDOUT;
254 case GNUTLS_E_DB_ERROR:
261 case GNUTLS_E_SRP_PWD_ERROR:
262 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
263 case GNUTLS_E_HASH_FAILED:
264 case GNUTLS_E_PK_SIGN_FAILED:
265 case GNUTLS_E_CERTIFICATE_ERROR:
266 case GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION:
267 case GNUTLS_E_KEY_USAGE_VIOLATION:
268 case GNUTLS_E_NO_CERTIFICATE_FOUND:
269 case GNUTLS_E_OPENPGP_UID_REVOKED:
270 case GNUTLS_E_OPENPGP_GETKEY_FAILED:
271 case GNUTLS_E_PK_SIG_VERIFY_FAILED:
272 case GNUTLS_E_ILLEGAL_SRP_USERNAME:
273 case GNUTLS_E_INVALID_PASSWORD:
274 case GNUTLS_E_MAC_VERIFY_FAILED:
275 case GNUTLS_E_IA_VERIFY_FAILED:
276 case GNUTLS_E_UNKNOWN_SRP_USERNAME:
277 case GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR:
278 case GNUTLS_E_USER_ERROR:
279 case GNUTLS_E_AUTH_ERROR:
282 case GNUTLS_E_INTERRUPTED:
285 case GNUTLS_E_INTERNAL_ERROR:
286 case GNUTLS_E_CONSTRAINT_ERROR:
287 case GNUTLS_E_ILLEGAL_PARAMETER:
290 case GNUTLS_E_SAFE_RENEGOTIATION_FAILED:
291 newerrno = ECONNREFUSED;
293 case GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY:
294 case GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY:
295 #ifdef GNUTLS_E_LIB_IN_ERROR_STATE
296 case GNUTLS_E_LIB_IN_ERROR_STATE:
300 case GNUTLS_E_RANDOM_FAILED:
303 case GNUTLS_E_CRYPTODEV_IOCTL_ERROR:
304 case GNUTLS_E_CRYPTODEV_DEVICE_ERROR:
305 case GNUTLS_E_HEARTBEAT_PONG_RECEIVED:
306 case GNUTLS_E_HEARTBEAT_PING_RECEIVED:
307 case GNUTLS_E_PKCS11_ERROR:
308 case GNUTLS_E_PKCS11_LOAD_ERROR:
309 case GNUTLS_E_PKCS11_PIN_ERROR:
310 case GNUTLS_E_PKCS11_SLOT_ERROR:
311 case GNUTLS_E_LOCKING_ERROR:
312 case GNUTLS_E_PKCS11_ATTRIBUTE_ERROR:
313 case GNUTLS_E_PKCS11_DEVICE_ERROR:
314 case GNUTLS_E_PKCS11_DATA_ERROR:
315 case GNUTLS_E_PKCS11_UNSUPPORTED_FEATURE_ERROR:
316 case GNUTLS_E_PKCS11_KEY_ERROR:
317 case GNUTLS_E_PKCS11_PIN_EXPIRED:
318 case GNUTLS_E_PKCS11_PIN_LOCKED:
319 case GNUTLS_E_PKCS11_SESSION_ERROR:
320 case GNUTLS_E_PKCS11_SIGNATURE_ERROR:
321 case GNUTLS_E_PKCS11_TOKEN_ERROR:
322 case GNUTLS_E_PKCS11_USER_ERROR:
323 case GNUTLS_E_CRYPTO_INIT_FAILED:
324 case GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE:
325 case GNUTLS_E_TPM_ERROR:
326 case GNUTLS_E_TPM_KEY_PASSWORD_ERROR:
327 case GNUTLS_E_TPM_SRK_PASSWORD_ERROR:
328 case GNUTLS_E_TPM_SESSION_ERROR:
329 case GNUTLS_E_TPM_KEY_NOT_FOUND:
330 case GNUTLS_E_TPM_UNINITIALIZED:
331 case GNUTLS_E_OCSP_RESPONSE_ERROR:
332 case GNUTLS_E_RANDOM_DEVICE_ERROR:
334 newerrno = EREMOTEIO;
347 /* Generate Diffie-Hellman parameters - for use with DHE
348 * kx algorithms. TODO: These should be discarded and regenerated
349 * once a day, once a week or once a month. Depending on the
350 * security requirements.
352 static gtls_error generate_dh_params (void) {
354 int gtls_errno = GNUTLS_E_SUCCESS;
355 bits = gnutls_sec_param_to_pk_bits (
357 GNUTLS_SEC_PARAM_LEGACY);
358 //TODO// Acquire DH-params lock
359 E_g2e ("Failed to initialise DH params",
360 gnutls_dh_params_init (
362 E_g2e ("Failed to generate DH params",
363 gnutls_dh_params_generate2 (
366 //TODO// Release DH-params lock
370 /* Load Diffie-Hellman parameters from file - or generate them when load fails.
372 static gtls_error load_dh_params (void) {
373 gnutls_dh_params_t dhp;
374 gnutls_datum_t pkcs3;
375 char *filename = cfg_tls_dhparamfile ();
376 int gtls_errno = GNUTLS_E_SUCCESS;
377 bzero (&pkcs3, sizeof (pkcs3));
379 E_g2e ("No PKCS #3 PEM file with DH params",
383 E_gnutls_clear_errno ();
384 E_g2e ("Failed to initialise DH params",
385 gnutls_dh_params_init (
387 E_g2e ("Failed to import DH params from PKCS #3 PEM",
388 gnutls_dh_params_import_pkcs3 (
391 GNUTLS_X509_FMT_PEM));
392 E_gnutls_clear_errno ();
394 if (pkcs3.data != NULL) {
397 if (gtls_errno != GNUTLS_E_SUCCESS) {
399 // File failed to load, so try to generate fresh DH params
400 int gtls_errno_stack0;
401 gtls_errno = GNUTLS_E_SUCCESS;
402 tlog (TLOG_CRYPTO, LOG_DEBUG, "Failed to load DH params from %s; generating fresh parameters", filename);
403 E_g2e ("Failed to generate DH params",
404 generate_dh_params ());
405 gtls_errno_stack0 = gtls_errno;
406 //TODO// Acquire DH-params lock
407 E_g2e ("Failed to format DH params as PKCS #3 PEM",
408 gnutls_dh_params_export2_pkcs3 (
412 //TODO// Release DH-params lock
413 if ((gtls_errno == GNUTLS_E_SUCCESS) && (filename != NULL)) {
416 // Best effor file save -- readback will parse
417 pemf = fopen (filename, "w");
419 fwrite (pkcs3.data, 1, pkcs3.size, pemf);
421 tlog (TLOG_FILES, LOG_DEBUG, "Saved DH params to %s (best-effort)", filename);
423 E_gnutls_clear_errno ();
425 gtls_errno = gtls_errno_stack0;
427 gnutls_dh_params_t old_dh;
428 //TODO// Acquire DH-params lock
431 //TODO// Release DH-params lock
433 gnutls_dh_params_deinit (old_dh);
439 /* Remove DH parameters, to be used during program cleanup. */
440 static void remove_dh_params (void) {
442 gnutls_dh_params_deinit (dh_params);
448 /* A log printing function
450 void log_gnutls (int level, const char *msg) {
451 tlog (TLOG_TLS, level, "GnuTLS: %s", msg);
455 /* Implement the GnuTLS function for token insertion callback. This function
456 * refers back to the generic callback for token insertion.
458 int gnutls_token_callback (void *const userdata,
459 const char *const label,
461 if (token_callback (label, retry)) {
462 return GNUTLS_E_SUCCESS;
464 return GNUTLS_E_PKCS11_TOKEN_ERROR;
470 * Implement the GnuTLS function for PIN callback. This function calls
471 * the generic PIN callback operation.
473 int gnutls_pin_callback (void *userdata,
475 const char *token_url,
476 const char *token_label,
480 if (flags & GNUTLS_PIN_SO) {
481 return GNUTLS_E_USER_ERROR;
483 if (pin_callback (attempt, token_url, token_label, pin, pin_max)) {
486 return GNUTLS_E_PKCS11_PIN_ERROR;
491 /* Register a PKCS #11 provider with the GnuTLS environment. */
492 void starttls_pkcs11_provider (char *p11path) {
493 unsigned int token_seq = 0;
495 if (gnutls_pkcs11_add_provider (p11path, NULL) != 0) {
496 fprintf (stderr, "Failed to register PKCS #11 library %s with GnuTLS\n", p11path);
499 while (gnutls_pkcs11_token_get_url (token_seq, 0, &p11uri) == 0) {
501 printf ("DEBUG: Found token URI %s\n", p11uri);
503 //TODO// if (gnutls_pkcs11_token_get_info (p11uri, GNUTLS_PKCS11_TOKEN_LABEL-of-SERIAL-of-MANUFACTURER-of-MODEL, output, utput_size) == 0) { ... }
504 gnutls_free (p11uri);
507 //TODO// Select token by name (value)
508 //TODO// if PIN available then set it up
509 //TODO:WHY?// free_p11pin ();
513 /* The global and static setup function for the starttls functions.
515 void setup_starttls (void) {
516 int setup_starttls_credentials (void); /* Defined below */
518 int gtls_errno = GNUTLS_E_SUCCESS;
520 // Basic library actions
521 tlog (TLOG_TLS, LOG_DEBUG, "Compiled against GnuTLS version %s", GNUTLS_VERSION);
522 curver = gnutls_check_version (GNUTLS_VERSION);
523 tlog (TLOG_TLS, LOG_DEBUG, "Running against %s GnuTLS version %s", curver? "acceptable": "OLDER", curver? curver: gnutls_check_version (NULL));
524 E_g2e ("GnuTLS global initialisation failed",
525 gnutls_global_init ());
526 E_gnutls_clear_errno ();
527 E_g2e ("GnuTLS PKCS #11 initialisation failed",
529 GNUTLS_PKCS11_FLAG_MANUAL, NULL));
531 // Setup logging / debugging
532 if (cfg_log_level () == LOG_DEBUG) {
533 gnutls_global_set_log_function (log_gnutls);
534 gnutls_global_set_log_level (2);
537 // Setup callbacks for user communication
538 gnutls_pkcs11_set_token_function (gnutls_token_callback, NULL);
539 gnutls_pkcs11_set_pin_function (gnutls_pin_callback, NULL);
541 // Setup DH parameters
542 E_g2e ("Loading DH params failed",
545 // Setup shared credentials for all client server processes
546 E_g2e ("Failed to setup GnuTLS callback credentials",
547 setup_starttls_credentials ());
548 if (gtls_errno != GNUTLS_E_SUCCESS) {
549 tlog (TLOG_TLS, LOG_CRIT, "FATAL: GnuTLS setup failed: %s", gnutls_strerror (gtls_errno));
553 //MOVED// // Setup the management databases
554 //MOVED// tlog (TLOG_DB, LOG_DEBUG, "Setting up management databases");
555 //MOVED// E_e2e ("Failed to setup management databases",
556 //MOVED// setup_management ());
557 //MOVED// if (errno != 0) {
558 //MOVED// tlog (TLOG_DB, LOG_CRIT, "FATAL: Management databases setup failed: %s", strerror (errno));
563 /* Cleanup the structures and resources that were setup for handling TLS.
565 void cleanup_starttls (void) {
566 void cleanup_starttls_credentials (void); /* Defined below */
567 //MOVED// cleanup_management ();
568 cleanup_starttls_credentials ();
570 gnutls_pkcs11_set_pin_function (NULL, NULL);
571 gnutls_pkcs11_set_token_function (NULL, NULL);
572 gnutls_pkcs11_deinit ();
573 gnutls_global_deinit ();
578 * The copycat function is a bidirectional transport between the given
579 * remote and local sockets, but it will encrypt traffic from local to
580 * remote, and decrypt traffic from remote to local. It will do this
581 * until one of the end points is shut down, at which time it will
582 * return and assume the context will close down both pre-existing
585 * This copycat actually has a few sharp claws to watch for -- shutdown
586 * of sockets may drop the last bit of information sent. First, the
587 * signal POLLHUP is best ignored because it travels asynchronously.
588 * Second, reading 0 is a good indicator of end-of-file and may be
589 * followed by an shutdown of reading from that stream. But, more
590 * importantly, the other side must have this information forwarded
591 * so it can shutdown. This means that a shutdown for writing to that
592 * stream is to be sent. Even when *both* sides have agreed to not send
593 * anything, they may still not have received all they were offered for
594 * reading, so we should SO_LINGER on the sockets so they can acknowledge,
595 * and after a timeout we can establish that shutdown failed and log and
596 * return an error for it.
597 * Will you believe that I had looked up if close() would suffice? The man
598 * page clearly stated yes. However, these articles offer much more detail:
599 * http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable
600 * http://www.greenend.org.uk/rjk/tech/poll.html
602 static void copycat (int local, int remote, gnutls_session_t wrapped, int master) {
604 struct pollfd inout [3];
606 struct linger linger = { 1, 10 };
608 inout [0].fd = local;
609 inout [1].fd = remote;
610 inout [2].fd = master;
611 inout [0].events = inout [1].events = POLLIN;
612 inout [2].events = 0; // error events only
613 tlog (TLOG_COPYCAT, LOG_DEBUG, "Starting copycat cycle for local=%d, remote=%d", local, remote);
614 while (((inout [0].events | inout [1].events) & POLLIN) != 0) {
615 if (poll (inout, 3, -1) == -1) {
616 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat polling returned an error");
617 break; // Polling sees an error
619 if (inout [0].revents & POLLIN) {
620 // Read local and encrypt to remote
621 sz = recv (local, buf, sizeof (buf), MSG_DONTWAIT);
622 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat received %d local bytes (or error<0) from %d", (int) sz, local);
624 tlog (TLOG_COPYCAT, LOG_ERR, "Error while receiving: %s", strerror (errno));
625 break; // stream error
626 } else if (sz == 0) {
627 inout [0].events &= ~POLLIN;
628 shutdown (local, SHUT_RD);
629 setsockopt (remote, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
630 gnutls_bye (wrapped, GNUTLS_SHUT_WR);
631 } else if (gnutls_record_send (wrapped, buf, sz) != sz) {
632 tlog (TLOG_COPYCAT, LOG_ERR, "gnutls_record_send() failed to pass on the requested bytes");
633 break; // communication error
635 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat sent %d bytes to remote %d", (int) sz, remote);
638 if (inout [1].revents & POLLIN) {
639 // Read remote and decrypt to local
640 sz = gnutls_record_recv (wrapped, buf, sizeof (buf));
641 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat received %d remote bytes from %d (or error if <0)", (int) sz, remote);
643 if (gnutls_error_is_fatal (sz)) {
644 tlog (TLOG_TLS, LOG_ERR, "GnuTLS fatal error: %s", gnutls_strerror (sz));
645 break; // stream error
647 tlog (TLOG_TLS, LOG_INFO, "GnuTLS recoverable error: %s", gnutls_strerror (sz));
649 } else if (sz == 0) {
650 inout [1].events &= ~POLLIN;
651 shutdown (remote, SHUT_RD);
652 setsockopt (local, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
653 shutdown (local, SHUT_WR);
654 } else if (send (local, buf, sz, MSG_DONTWAIT) != sz) {
655 break; // communication error
657 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat sent %d bytes to local %d", (int) sz, local);
660 inout [0].revents &= ~(POLLIN | POLLHUP); // Thy copying cat?
661 inout [1].revents &= ~(POLLIN | POLLHUP); // Retract thee claws!
662 if ((inout [0].revents | inout [1].revents | inout [2].revents) & ~POLLIN) {
663 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat polling returned a special condition");
664 break; // Apparently, one of POLLERR, POLLHUP, POLLNVAL
667 tlog (TLOG_COPYCAT, LOG_DEBUG, "Ending copycat cycle for local=%d, remote=%d", local, remote);
670 gnutls_deinit (wrapped);
674 /* The callback function that retrieves certification information from either
675 * the client or the server in the course of the handshake procedure.
677 gtls_error clisrv_cert_retrieve (gnutls_session_t session,
678 const gnutls_datum_t* req_ca_dn,
680 const gnutls_pk_algorithm_t* pk_algos,
682 gnutls_pcert_st** pcert,
683 unsigned int *pcert_length,
684 gnutls_privkey_t *pkey) {
685 gnutls_certificate_type_t certtp;
686 gnutls_pcert_st *pc = NULL;
689 gnutls_datum_t privdatum = { NULL, 0 };
690 gnutls_datum_t certdatum = { NULL, 0 };
691 gnutls_openpgp_crt_t pgpcert = NULL;
692 gnutls_openpgp_privkey_t pgppriv = NULL;
693 gnutls_x509_crt_t x509cert = NULL;
694 gnutls_x509_privkey_t x509priv = NULL;
695 int gtls_errno = GNUTLS_E_SUCCESS;
699 char sni [sizeof (cmd->cmd.pio_data.pioc_starttls.localid)];
700 size_t snilen = sizeof (sni);
707 gtls_error fetch_local_credentials (struct command *cmd);
708 gnutls_pcert_st *load_certificate_chain (uint32_t flags, unsigned int *chainlen, gnutls_datum_t *certdatum);
711 // Setup a number of common references and structures
713 cmd = (struct command *) gnutls_session_get_ptr (session);
715 E_g2e ("No data pointer with session",
716 GNUTLS_E_INVALID_SESSION);
719 if (cmd->cmd.pio_cmd == PIOC_STARTTLS_SERVER_V2) {
720 lidrole = LID_ROLE_SERVER;
722 } else if (cmd->cmd.pio_cmd == PIOC_STARTTLS_CLIENT_V2) {
723 lidrole = LID_ROLE_CLIENT;
726 E_g2e ("TLS Pool command is not _STARTTLS_",
727 GNUTLS_E_INVALID_SESSION);
730 lid = cmd->cmd.pio_data.pioc_starttls.localid;
731 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
734 // On a server, lookup the server name and match it against lid.
735 // TODO: For now assume a single server name in SNI (as that is normal).
736 if (lidrole == LID_ROLE_SERVER) {
737 if (gnutls_server_name_get (session, sni, &snilen, &snitype, 0) || (snitype != GNUTLS_NAME_DNS)) {
738 E_g2e ("Requested SNI error or not a DNS name",
739 GNUTLS_E_NO_CERTIFICATE_FOUND);
743 if (strncmp (sni, lid, snilen) != 0) {
744 tlog (TLOG_TLS, LOG_ERR, "SNI %s does not match preset local identity %s", sni, lid);
745 E_g2e ("Requested SNI does not match local identity",
746 GNUTLS_E_NO_CERTIFICATE_FOUND);
750 // TODO: Should ask for permission before accepting SNI
751 memcpy (lid, sni, sizeof (sni));
756 // Setup the lidtype parameter for responding
757 certtp = gnutls_certificate_type_get (session);
758 if (certtp == GNUTLS_CRT_OPENPGP) {
759 tlog (TLOG_TLS, LOG_INFO, "Serving OpenPGP certificate request as a %s", rolestr);
760 lidtype = LID_TYPE_PGP;
761 } else if (certtp == GNUTLS_CRT_X509) {
762 tlog (TLOG_TLS, LOG_INFO, "Serving X.509 certificate request as a %s", rolestr);
763 lidtype = LID_TYPE_X509;
765 // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
766 tlog (TLOG_TLS, LOG_ERR, "Funny sort of certificate retrieval attempted as a %s", rolestr);
767 E_g2e ("Requested certtype is neither X.509 nor OpenPGP",
768 GNUTLS_E_CERTIFICATE_ERROR);
773 // Find the prefetched local identity to use towards this remote
774 // Send a callback to the user if none is available and accessible
775 //TODO// This callback will be redirected to the identity watchdog
776 //TODO// Define a flag to enforce this callback (to set plainfd)
777 if (cmd->lids [lidtype - LID_TYPE_MIN].data == NULL) {
778 uint32_t oldcmd = cmd->cmd.pio_cmd;
779 cmd->cmd.pio_cmd = PIOC_STARTTLS_LOCALID_V1;
780 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Calling send_callback_and_await_response with PIOC_STARTTLS_LOCALID_V1");
781 cmd = send_callback_and_await_response (cmd);
782 if (cmd->cmd.pio_cmd != PIOC_STARTTLS_LOCALID_V1) {
783 tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has unexpected command code");
784 cmd->cmd.pio_cmd = oldcmd;
785 return GNUTLS_E_CERTIFICATE_ERROR;
787 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Processing callback response that sets plainfd:=%d and lid:=\"%s\" for rid==\"%s\"", cmd->passfd, lid, rid);
788 cmd->cmd.pio_cmd = oldcmd;
790 // Check that new rid is a generalisation of original rid
791 // Note: This is only of interest for client operation
792 if (oldcmd == PIOC_STARTTLS_CLIENT_V2) {
793 selector_t newrid = donai_from_stable_string (rid, strlen (rid));
794 donai_t oldrid = donai_from_stable_string (cmd->orig_piocdata->remoteid, strlen (cmd->orig_piocdata->remoteid));
795 if (!donai_matches_selector (&oldrid, &newrid)) {
796 return GNUTLS_E_NO_CERTIFICATE_FOUND;
800 // Add (rid,lid) to db_disclose for acceptance.
801 // Note that this is done within the STARTTLS transaction.
802 // Upon secure setup failure this change will roll back.
803 //TODO// Client => add (rid,lid) to db_disclose within cmd->txn
804 //TODO// Decide how to deal with lower-level overrides
806 // Now reiterate to lookup lid credentials in db_localid
807 E_g2e ("Missing local credentials",
808 fetch_local_credentials (cmd));
810 if (cmd->lids [lidtype - LID_TYPE_MIN].data == NULL) {
811 E_g2e ("Missing certificate for local ID",
812 GNUTLS_E_NO_CERTIFICATE_FOUND);
817 // Split the credential into its various aspects
818 ok = dbcred_interpret (
819 &cmd->lids [lidtype - LID_TYPE_MIN],
824 tlog (TLOG_DB, LOG_DEBUG, "BDB entry has flags=0x%08x, p11priv=\"%s\", cert.size=%d", flags, p11priv, certdatum.size);
825 //TODO// ok = ok && verify_cert_... (...); -- keyidlookup
827 gtls_errno = GNUTLS_E_CERTIFICATE_ERROR;
831 // Allocate response structures
833 *pcert = load_certificate_chain (flags, pcert_length, &certdatum);
834 if (*pcert == NULL) {
835 E_g2e ("Failed to load certificate chain",
836 GNUTLS_E_CERTIFICATE_ERROR);
839 cmd->session_certificate = (intptr_t) (void *) *pcert; //TODO// Used for session cleanup
843 E_g2e ("Failed to initialise private key",
844 gnutls_privkey_init (
846 if (gtls_errno == GNUTLS_E_SUCCESS) {
847 cmd->session_privatekey = (intptr_t) (void *) *pkey; //TODO// Used for session cleanup
849 E_g2e ("Failed to import PKCS #11 private key URL",
850 gnutls_privkey_import_pkcs11_url (
853 E_gnutls_clear_errno ();
855 //TODO// Moved out (start)
858 // Setup public key certificate
861 E_g2e ("Failed to import X.509 certificate into chain",
862 gnutls_pcert_import_x509_raw (
869 E_g2e ("Failed to import OpenPGP certificate",
870 gnutls_pcert_import_openpgp_raw (
873 GNUTLS_OPENPGP_FMT_RAW,
874 NULL, /* use master key */
878 /* Should not happen */
882 //TODO// Moved out (end)
885 // Lap up any overseen POSIX error codes in errno
887 tlog (TLOG_TLS, LOG_DEBUG, "Failing TLS on errno=%d / %s", errno, strerror (errno));
888 cmd->session_errno = errno;
889 gtls_errno = GNUTLS_E_NO_CIPHER_SUITES; /* Vaguely matching */
893 // Return the overral error code, hopefully GNUTLS_E_SUCCESS
894 tlog (TLOG_TLS, LOG_DEBUG, "Returning %d / %s from clisrv_cert_retrieve()", gtls_errno, gnutls_strerror (gtls_errno));
898 /* Load a single certificate in the given gnutls_pcert_st from the given
899 * gnutls_datum_t. Use the lidtype to determine how to do this.
901 gtls_error load_certificate (int lidtype, gnutls_pcert_st *pcert, gnutls_datum_t *certdatum) {
902 int gtls_errno = GNUTLS_E_SUCCESS;
904 // Setup public key certificate
907 E_g2e ("Failed to import X.509 certificate into chain",
908 gnutls_pcert_import_x509_raw (
915 E_g2e ("Failed to import OpenPGP certificate",
916 gnutls_pcert_import_openpgp_raw (
919 GNUTLS_OPENPGP_FMT_RAW,
920 NULL, /* use master key */
924 /* Should not happen */
931 /* Load a certificate chain. This returns a value for a retrieval function's
932 * pcert, and also modifies the chainlen. The latter starts at 0, and is
933 * incremented in a nested procedure that unrolls until all certificates are
936 gnutls_pcert_st *load_certificate_chain (uint32_t flags, unsigned int *chainlen, gnutls_datum_t *certdatum) {
937 gnutls_pcert_st *chain;
938 unsigned int mypos = *chainlen;
939 int gtls_errno = GNUTLS_E_SUCCESS;
942 // Quick and easy: No chaining required, just add the literal data.
943 // Note however, this may be the end of a chain, so allocate all
944 // structures and load the single one at the end.
945 if ((flags & (LID_CHAINED | LID_NEEDS_CHAIN)) == 0) {
947 chain = (gnutls_pcert_st *) calloc (*chainlen, sizeof (gnutls_pcert_st));
949 bzero (chain, (*chainlen) * sizeof (gnutls_pcert_st));
951 gtls_errno = GNUTLS_E_MEMORY_ERROR;
953 E_g2e ("Failed to load certificate into chain",
955 flags & LID_TYPE_MASK,
958 if (gtls_errno != GNUTLS_E_SUCCESS) {
969 // First extended case. Chain certs in response to LID_CHAINED.
970 // Recursive calls are depth-first, so we only add our first cert
971 // after a recursive call succeeds. Any LID_NEEDS_CHAIN work is
972 // added after LID_CHAINED, so is higher up in the hierarchy, but
973 // it is loaded as part of the recursion. To support that, a
974 // recursive call with certdatum.size==0 is possible when the
975 // LID_NEEDS_CHAIN flag is set, and this section then skips.
976 // Note that this code is also used to load the certificate chain
977 // provided by LID_NEEDS_CHAIN, but by then the flag in a recursive
978 // call is replaced with LID_CHAINED and no more LID_NEEDS_CHAIN.
979 if (((flags & LID_CHAINED) != 0) && (certdatum->size > 0)) {
982 gnutls_datum_t nextdatum;
984 // Note: Accept BER because the outside SEQUENCE is not signed
985 certlen = asn1_get_length_ber (
986 ((char *) certdatum->data) + 1,
989 certlen += 1 + lenlen;
990 tlog (TLOG_CERT, LOG_DEBUG, "Found LID_CHAINED certificate size %d", certlen);
991 if (certlen > certdatum->size) {
992 tlog (TLOG_CERT, LOG_ERR, "Refusing LID_CHAINED certificate beyond data size %d", certdatum->size);
995 } else if (certlen <= 0) {
996 tlog (TLOG_CERT, LOG_ERR, "Refusing LID_CHAINED certificate of too-modest data size %d", certlen);
1000 nextdatum.data = ((char *) certdatum->data) + certlen;
1001 nextdatum.size = certdatum->size - certlen;
1002 certdatum->size = certlen;
1003 nextlen = asn1_get_length_ber (
1004 ((char *) nextdatum.data) + 1,
1007 nextlen += 1 + lenlen;
1008 if (nextlen == nextdatum.size) {
1009 // The last cert is loaded thinking it is not CHAINED,
1010 // but NEEDS_CHAIN can still be present for expansion.
1011 flags &= ~LID_CHAINED;
1014 chain = load_certificate_chain (flags, chainlen, &nextdatum);
1015 if (chain != NULL) {
1016 E_g2e ("Failed to add chained certificate",
1018 flags & LID_TYPE_MASK,
1021 if (gtls_errno != GNUTLS_E_SUCCESS) {
1031 // Second extended case. Chain certs in response to LID_NEEDS_CHAIN.
1032 // These are the highest-up in the hierarchy, above any LID_CHAINED
1033 // certificates. The procedure for adding them is looking them up
1034 // in a central database by their authority key identifier. What is
1035 // found is assumed to be a chain, and will be unrolled by replacing
1036 // the LID_NEEDS_CHAIN flag with LID_CHAINED and calling recursively.
1037 if (((flags & LID_NEEDS_CHAIN) != 0) && (certdatum->size == 0)) {
1038 //TODO//CODE// lookup new certdatum
1039 flags &= ~LID_NEEDS_CHAIN;
1040 flags |= LID_CHAINED;
1041 //TODO//CODE// recursive call
1042 //TODO//CODE// no structures to fill here
1043 //TODO//CODE// cleanup new certdatum
1047 // Final judgement. Nothing worked. Return failure.
1053 /* Fetch local credentials. This can be done before TLS is started, to find
1054 * the possible authentication forms that can be offered. The function
1055 * can additionally be used after interaction with the client to establish
1056 * a local identity that was not initially provided, or that was not
1057 * considered public at the time.
1059 gtls_error fetch_local_credentials (struct command *cmd) {
1062 DBC *crs_disclose = NULL;
1063 DBC *crs_localid = NULL;
1067 selector_t remote_selector;
1073 // Setup a number of common references and structures
1074 if (cmd->cmd.pio_cmd == PIOC_STARTTLS_SERVER_V2) {
1075 lidrole = LID_ROLE_SERVER;
1076 } else if (cmd->cmd.pio_cmd == PIOC_STARTTLS_CLIENT_V2) {
1077 lidrole = LID_ROLE_CLIENT;
1079 E_g2e ("TLS Pool command is not _STARTTLS_",
1080 GNUTLS_E_INVALID_SESSION);
1083 lid = cmd->cmd.pio_data.pioc_starttls.localid;
1084 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
1087 // Refuse to disclose client credentials when the server name is unset;
1088 // note that server-claimed identities are unproven during handshake.
1089 if ((lidrole == LID_ROLE_CLIENT) && (*rid == '\0')) {
1090 tlog (TLOG_USER, LOG_ERR, "No remote identity (server name) set, so no client credential disclosure");
1091 E_g2e ("Missing remote ID",
1092 GNUTLS_E_NO_CERTIFICATE_FOUND);
1096 // Setup database iterators to map identities to credentials
1097 if (lidrole == LID_ROLE_CLIENT) {
1098 E_d2e ("Failed to create db_disclse cursor",
1099 dbh_disclose->cursor (
1105 E_d2e ("Failed to create db_localid cursor",
1106 dbh_localid->cursor (
1112 // Prepare for iteration over possible local identities / credentials
1115 if (gtls_errno != 0) {
1117 } else if (lidrole == LID_ROLE_CLIENT) {
1118 memcpy (cid, rid, sizeof (cid));
1119 dbt_init_fixbuf (&discpatn, cid, strlen (cid));
1120 dbt_init_fixbuf (&keydata, mid, sizeof (mid)-1);
1121 dbt_init_malloc (&creddata);
1123 donai_t remote_donai = donai_from_stable_string (rid, strlen (rid));
1124 if (!selector_iterate_init (&remote_selector, &remote_donai)) {
1125 E_g2e ("Syntax of remote ID unsuitable for selector",
1126 GNUTLS_E_INVALID_REQUEST);
1128 E_d2e ("Failed to start iterator on remote ID selector",
1129 dbcred_iterate_from_remoteid_selector (
1138 dbt_init_fixbuf (&discpatn, "", 0); // Unused but good style
1139 dbt_init_fixbuf (&keydata, lid, strlen (lid));
1140 dbt_init_malloc (&creddata);
1141 E_d2e ("Failed to start iterator on local ID",
1142 dbcred_iterate_from_localid (
1147 if (db_errno != 0) {
1148 gtls_errno = GNUTLS_E_DB_ERROR;
1152 // Now store the local identities inasfar as they are usable
1154 while ((gtls_errno == GNUTLS_E_SUCCESS) && (db_errno == 0)) {
1159 tlog (TLOG_DB, LOG_DEBUG, "Found BDB entry %s disclosed to %s", creddata.data + 4, (lidrole == LID_ROLE_CLIENT)? rid: "all clients");
1163 lidtype = flags & LID_TYPE_MASK;
1164 ok = ok && ((flags & lidrole) != 0);
1165 ok = ok && ((flags & LID_NO_PKCS11) == 0);
1166 ok = ok && (lidtype >= LID_TYPE_MIN);
1167 ok = ok && (lidtype <= LID_TYPE_MAX);
1168 tlog (TLOG_DB, LOG_DEBUG, "BDB entry has flags=0x%08x, so we (%04x/%04x) %s it", flags, lidrole, LID_ROLE_MASK, ok? "store": "skip ");
1170 // Move the credential into the command structure
1171 dbt_store (&creddata,
1172 &cmd->lids [lidtype - LID_TYPE_MIN]);
1175 // Skip the credential by freeing its data structure
1176 dbt_free (&creddata);
1178 db_errno = dbcred_iterate_next (crs_disclose, crs_localid, &discpatn, &keydata, &creddata);
1181 if (db_errno == DB_NOTFOUND) {
1183 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1186 if (crs_localid != NULL) {
1187 crs_localid->close (crs_localid);
1190 if (crs_disclose != NULL) {
1191 crs_disclose->close (crs_disclose);
1192 crs_disclose = NULL;
1198 /* The callback functions retrieve various bits of information for the client
1199 * or server in the course of the handshake procedure.
1201 * The logic here is based on client-sent information, such as:
1202 * - TLS hints -- X.509 or alternatives like OpenPGP, SRP, PSK
1203 * - TLS hints -- Server Name Indication
1204 * - User hints -- local and remote identities provided
1206 int srv_clienthello (gnutls_session_t session) {
1207 struct command *cmd;
1208 char sni [sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid)]; // static
1209 size_t snilen = sizeof (sni);
1211 int gtls_errno = GNUTLS_E_SUCCESS;
1215 // Setup a number of common references
1216 cmd = (struct command *) gnutls_session_get_ptr (session);
1218 return GNUTLS_E_INVALID_SESSION;
1220 lid = cmd->cmd.pio_data.pioc_starttls.localid;
1223 // Find the client-helloed ServerNameIndication, or the service name
1225 if (gnutls_server_name_get (session, sni, &snilen, &snitype, 0) == 0) {
1227 case GNUTLS_NAME_DNS:
1229 // Note: In theory, other name types could be sent, and it would
1230 // be useful to access indexes beyond 0. In practice, nobody
1231 // uses other name types than exactly one GNUTLS_NAME_DNS.
1234 tlog (TLOG_TLS, LOG_ERR, "Received an unexpected SNI type; that is possible but uncommon; skipping SNI");
1238 if (sni [0] != '\0') {
1240 if (strncmp (sni, lid, sizeof (sni)) != 0) {
1241 tlog (TLOG_USER | TLOG_TLS, LOG_ERR, "Mismatch between client-sent SNI %s and local identity %s", sni, lid);
1242 return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
1245 memcpy (lid, sni, sizeof (sni));
1248 memcpy (sni, lid, sizeof (sni)-1);
1249 sni [sizeof (sni) - 1] = '\0';
1253 // Lap up any unnoticed POSIX error messages
1255 cmd->session_errno = errno;
1256 gtls_errno = GNUTLS_E_NO_CIPHER_SUITES; /* Vaguely matching */
1260 // Round off with an overal judgement
1265 int cli_srpcreds_retrieve (gnutls_session_t session,
1269 tlog (TLOG_CRYPTO, LOG_DEBUG, "DEBUG: Picking up SRP credentials");
1270 *username = strdup ("tester");
1271 *password = strdup ("test");
1272 return GNUTLS_E_SUCCESS;
1276 /* Setup credentials to be shared by all clients and servers.
1277 * Credentials are generally implemented through callback functions.
1278 * This should be called after setting up DH parameters.
1280 int setup_starttls_credentials (void) {
1281 gnutls_anon_server_credentials_t srv_anoncred = NULL;
1282 gnutls_anon_client_credentials_t cli_anoncred = NULL;
1283 gnutls_certificate_credentials_t clisrv_certcred = NULL;
1284 //TODO:NOTHERE// int srpbits;
1285 gnutls_srp_server_credentials_t srv_srpcred = NULL;
1286 gnutls_srp_client_credentials_t cli_srpcred = NULL;
1287 //TODO// gnutls_kdh_server_credentials_t srv_kdhcred = NULL;
1288 //TODO// gnutls_kdh_server_credentials_t cli_kdhcred = NULL;
1289 int gtls_errno = GNUTLS_E_SUCCESS;
1290 int gtls_errno_stack0;
1293 // Construct certificate credentials for X.509 and OpenPGP cli/srv
1294 E_g2e ("Failed to allocate certificate credentials",
1295 gnutls_certificate_allocate_credentials (
1297 //TODO// What to do here when we add locking on DH params?
1298 gnutls_certificate_set_dh_params (
1301 gtls_errno_stack0 = gtls_errno;
1302 /* TODO: Bad code. GnuTLS 3.2.1 ignores retrieve_function2 when
1303 * checking if it can handle the OpenPGP certificate type in
1304 * _gnutls_session_cert_type_supported (gnutls_status.c:175) but
1305 * it does see the "1" version field. It does not callback the
1306 * "1" version if "2" is present though.
1308 if (!have_error_codes ()) /* TODO:GnuTLSversions E_g2e (...) */ gnutls_certificate_set_retrieve_function (
1311 if (!have_error_codes ()) /* TODO:GnuTLSversions E_g2e (...) */ gnutls_certificate_set_retrieve_function2 (
1313 clisrv_cert_retrieve);
1314 if (gtls_errno == GNUTLS_E_SUCCESS) {
1315 // Setup for certificates
1316 tlog (TLOG_CERT, LOG_INFO, "Setting client and server certificate credentials");
1317 cli_creds [cli_credcount].credtp = GNUTLS_CRD_CERTIFICATE;
1318 cli_creds [cli_credcount].cred = (void *) clisrv_certcred;
1320 srv_creds [srv_credcount].credtp = GNUTLS_CRD_CERTIFICATE;
1321 srv_creds [srv_credcount].cred = (void *) clisrv_certcred;
1323 } else if (clisrv_certcred != NULL) {
1324 gnutls_certificate_free_credentials (clisrv_certcred);
1325 clisrv_certcred = NULL;
1329 // Construct anonymous server credentials
1330 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
1331 E_g2e ("Failed to allocate ANON-DH server credentials",
1332 gnutls_anon_allocate_server_credentials (
1334 if (!have_error_codes ()) /* E_g2e (...) */ gnutls_anon_set_server_dh_params (
1337 if (gtls_errno == GNUTLS_E_SUCCESS) {
1338 tlog (TLOG_CRYPTO, LOG_INFO, "Setting server anonymous credentials");
1339 srv_creds [srv_credcount].credtp = GNUTLS_CRD_ANON;
1340 srv_creds [srv_credcount].cred = (void *) srv_anoncred;
1342 } else if (srv_anoncred != NULL) {
1343 gnutls_anon_free_server_credentials (srv_anoncred);
1344 srv_anoncred = NULL;
1347 #ifdef MIRROR_IMAGE_OF_SERVER_ANONYMOUS_CREDENTIALS
1349 // Construct anonymous client credentials
1350 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
1351 E_g2e ("Failed to allocate ANON-DH client credentials",
1352 gnutls_anon_allocate_client_credentials (
1354 if (!have_error_codes ()) gnutls_anon_set_client_dh_params (
1357 if (gtls_errno == GNUTLS_E_SUCCESS) {
1358 tlog (TLOG_CRYPTO, LOG_INFO, "Setting client anonymous credentials");
1359 cli_creds [cli_credcount].credtp = GNUTLS_CRD_ANON;
1360 cli_creds [cli_credcount].cred = (void *) cli_anoncred;
1362 } else if (cli_anoncred != NULL) {
1363 gnutls_anon_free_client_credentials (cli_anoncred);
1364 cli_anoncred = NULL;
1369 // Construct server credentials for SRP authentication
1370 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
1371 E_g2e ("Failed to allocate SRP server credentials",
1372 gnutls_srp_allocate_server_credentials (
1374 E_g2e ("Failed to set SRP server credentials",
1375 gnutls_srp_set_server_credentials_file (
1377 "../testdata/tlspool-test-srp.passwd",
1378 "../testdata/tlspool-test-srp.conf"));
1379 if (gtls_errno == GNUTLS_E_SUCCESS) {
1380 tlog (TLOG_CRYPTO, LOG_INFO, "Setting server SRP credentials");
1381 srv_creds [srv_credcount].credtp = GNUTLS_CRD_SRP;
1382 srv_creds [srv_credcount].cred = (void *) srv_srpcred;
1384 } else if (srv_srpcred != NULL) {
1385 gnutls_srp_free_server_credentials (srv_srpcred);
1390 // Construct client credentials for SRP authentication
1391 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
1392 E_g2e ("Failed to allocate SRP client credentials",
1393 gnutls_srp_allocate_client_credentials (
1395 if (!have_error_codes ()) gnutls_srp_set_client_credentials_function (
1397 cli_srpcreds_retrieve);
1398 if (gtls_errno == GNUTLS_E_SUCCESS) {
1399 tlog (TLOG_CRYPTO, LOG_INFO, "Setting client SRP credentials");
1400 cli_creds [cli_credcount].credtp = GNUTLS_CRD_SRP;
1401 cli_creds [cli_credcount].cred = (void *) cli_srpcred;
1403 } else if (cli_srpcred != NULL) {
1404 gnutls_srp_free_client_credentials (cli_srpcred);
1409 // Construct server credentials for KDH authentication
1410 //TODO// gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
1411 //TODO// E_g2e ("Failed to allocate KDH server credentials",
1412 //TODO// gnutls_kdh_allocate_server_credentials (
1413 //TODO// &srv_kdhcred));
1414 //TODO// E_g2e ("Failed to set KDH server DH params",
1415 //TODO// gnutls_kdh_set_server_dh_params (
1416 //TODO// srv_kdhcred,
1417 //TODO// dh_params));
1418 //TODO// if (gtls_errno == GNUTLS_E_SUCCESS) {
1419 //TODO// tlog (TLOG_CRYPTO, LOG_INFO, "Setting server KDH credentials");
1420 //TODO// srv_creds [srv_credcount].credtp = GNUTLS_CRD_KDH;
1421 //TODO// srv_creds [srv_credcount].cred = (void *) srv_kdhcred;
1422 //TODO// srv_credcount++;
1423 //TODO// } else if (srv_kdhcred != NULL) {
1424 //TODO// gnutls_kdh_free_server_credentials (srv_kdhcred);
1425 //TODO// srv_kdhcred = NULL;
1429 // Construct client credentials for KDH
1430 //TODO// gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
1431 //TODO// E_g2e ("Failed to allocate KDH client credentials",
1432 //TODO// gnutls_kdh_allocate_client_credentials (
1433 //TODO// &cli_kdhcred));
1434 //TODO// E_g2e ("Failed to set KDH client credentials",
1435 //TODO// gnutls_kdh_set_client_credentials_function (
1436 //TODO// cli_kdhcred,
1437 //TODO// cli_kdh_retrieve));
1438 //TODO// if (gtls_errno == GNUTLS_E_SUCCESS) {
1439 //TODO// tlog (TLOG_CRYPTO, LOG_INFO, "Setting client KDH credentials");
1440 //TODO// cli_creds [cli_credcount].credtp = GNUTLS_CRD_KDH;
1441 //TODO// cli_creds [cli_credcount].cred = (void *) cli_kdhcred;
1442 //TODO// cli_credcount++;
1443 //TODO// } else if (cli_kdhcred != NULL) {
1444 //TODO// gnutls_kdh_free_client_credentials (cli_kdhcred);
1445 //TODO// cli_kdhcred = NULL;
1449 // Ensure that at least one credential has been set
1450 // TODO: Look at the counters; but at boot, we can require all okay
1451 if ((gtls_errno == GNUTLS_E_SUCCESS) &&
1452 ( (cli_credcount != EXPECTED_CLI_CREDCOUNT) ||
1453 (srv_credcount != EXPECTED_SRV_CREDCOUNT) ) ) {
1454 tlog (TLOG_CRYPTO, LOG_ERR, "Not all credential types could be setup (cli %d/%d, srv %d/%d, gtls_errno %d)", cli_credcount, EXPECTED_CLI_CREDCOUNT, srv_credcount, EXPECTED_SRV_CREDCOUNT, gtls_errno);
1455 E_g2e ("Not all credentials could be setup",
1456 GNUTLS_E_INSUFFICIENT_CREDENTIALS);
1460 // Report overall error or success
1465 /* Cleanup all credentials created, just before exiting the daemon.
1467 void cleanup_starttls_credentials (void) {
1468 while (srv_credcount-- > 0) {
1469 struct credinfo *crd = &srv_creds [srv_credcount];
1470 switch (crd->credtp) {
1471 case GNUTLS_CRD_CERTIFICATE:
1472 // Shared with client; skipped in server and removed in client
1473 // gnutls_certificate_free_credentials (crd->cred);
1475 case GNUTLS_CRD_ANON:
1476 gnutls_anon_free_server_credentials (crd->cred);
1478 case GNUTLS_CRD_SRP:
1479 gnutls_srp_free_server_credentials (crd->cred);
1481 //TODO// case GNUTLS_CRD_KDH:
1482 //TODO// gnutls_kdh_free_server_credentials (crd->cred);
1486 while (cli_credcount-- > 0) {
1487 struct credinfo *crd = &cli_creds [cli_credcount];
1488 switch (crd->credtp) {
1489 case GNUTLS_CRD_CERTIFICATE:
1490 // Shared with client; skipped in server and removed in client
1491 gnutls_certificate_free_credentials (crd->cred);
1493 case GNUTLS_CRD_ANON:
1494 gnutls_anon_free_client_credentials (crd->cred);
1496 case GNUTLS_CRD_SRP:
1497 gnutls_srp_free_client_credentials (crd->cred);
1499 //TODO// case GNUTLS_CRD_KDH:
1500 //TODO// gnutls_kdh_free_client_credentials (crd->cred);
1508 * Check if a given cmd has the given LID_TYPE setup.
1509 * Return 1 for yes or 0 for no; this is used in priority strings.
1511 static inline int lidtpsup (struct command *cmd, int lidtp) {
1512 return cmd->lids [lidtp - LID_TYPE_MIN].data != NULL;
1516 * The starttls_thread is a main program for the setup of a TLS connection,
1517 * either in client mode or server mode. Note that the distinction between
1518 * client and server mode is only a TLS concern, but not of interest to the
1519 * application or the records exchanged.
1521 * If the STARTTLS operation succeeds, this will be reported back to the
1522 * application, but the TLS pool will continue to be active in a copycat
1523 * procedure: encrypting outgoing traffic and decrypting incoming traffic.
1524 * TODO: Are client and server routines different?
1526 static void *starttls_thread (void *cmd_void) {
1527 struct command *cmd;
1528 struct pioc_starttls orig_piocdata;
1533 gnutls_session_t session;
1534 int gtls_errno = GNUTLS_E_SUCCESS;
1536 struct credinfo *clisrv_creds;
1537 int clisrv_credcount;
1540 // General thread setup
1541 cmd = (struct command *) cmd_void;
1543 send_error (cmd, EINVAL, "Command structure not received");
1546 cmd->session_errno = 0;
1547 orig_cmd = cmd->cmd.pio_cmd;
1548 memcpy (&orig_piocdata, &cmd->cmd.pio_data.pioc_starttls, sizeof (orig_piocdata));
1549 cmd->orig_piocdata = &orig_piocdata;
1550 cryptfd = cmd->passfd;
1553 tlog (TLOG_UNIXSOCK, LOG_ERR, "No ciphertext file descriptor supplied to TLS Pool");
1554 send_error (cmd, EINVAL, "No ciphertext file descriptor supplied to TLS Pool");
1557 clientfd = cmd->clientfd;
1558 cmd->session_certificate = (intptr_t) (void *) NULL;
1559 cmd->session_privatekey = (intptr_t) (void *) NULL;
1562 // Setup BDB transactions and reset credential datum fields
1563 bzero (&cmd->lids, sizeof (cmd->lids)); //TODO: Probably double work?
1564 manage_txn_begin (&cmd->txn);
1567 // Permit cancellation of this thread -- TODO: Cleanup?
1568 errno = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
1570 send_error (cmd, ESRCH, "STARTTLS handler thread cancellability refused");
1574 // Check and setup the plaintext file handle
1575 if (cryptfd == -1) {
1576 send_error (cmd, EPROTO, "You must supply a TLS-protected socket");
1581 // Negotiate TLS; split client/server mode setup
1582 if (orig_cmd == PIOC_STARTTLS_SERVER_V2) {
1584 // Setup as a TLS server
1586 E_g2e ("Failed to initialise GnuTLS server session",
1590 if (gtls_errno == GNUTLS_E_SUCCESS) {
1591 gnutls_session_set_ptr (session, cmd);
1592 gnutls_handshake_set_post_client_hello_function (
1597 // Setup for server credential installation in this session
1598 clisrv_creds = srv_creds;
1599 clisrv_credcount = srv_credcount;
1601 } else if (orig_cmd == PIOC_STARTTLS_CLIENT_V2) {
1603 // Setup as a TLS client
1607 // Require a minimum security level for SRP
1609 //TODO:CRASH// if (gtls_errno == GNUTLS_E_SUCCESS) gnutls_srp_set_prime_bits (
1610 //TODO:CRASH// session,
1611 //TODO:CRASH// srpbits);
1613 // Setup as a TLS client
1614 E_g2e ("Failed to initialise GnuTLS client session",
1618 if (gtls_errno == GNUTLS_E_SUCCESS) {
1619 gnutls_session_set_ptr (
1624 // Setup for potential sending of SNI
1625 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_SEND_SNI) {
1626 char *str = cmd->cmd.pio_data.pioc_starttls.remoteid;
1628 while (str [len] && (len < 128)) {
1632 send_error (cmd, EINVAL, "Remote ID is not set");
1636 cmd->cmd.pio_data.pioc_starttls.remoteid [sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid)-1] = '\0';
1637 E_g2e ("Client failed to setup SNI",
1638 gnutls_server_name_set (
1645 // Setup for client credential installation in this session
1646 clisrv_creds = cli_creds;
1647 clisrv_credcount = cli_credcount;
1651 // Neither a TLS client nor a TLS server
1653 send_error (cmd, ENOTSUP, "Command not supported");
1659 // Install the shared credentials for the client or server role
1660 for (i=0; i<clisrv_credcount; i++) {
1661 E_g2e ("Failed to install credentials into TLS session",
1662 gnutls_credentials_set (
1664 clisrv_creds [i].credtp,
1665 clisrv_creds [i].cred ));
1669 // Prefetch local identities that might be used in this session
1670 E_g2e ("Failed to fetch local credentials",
1671 fetch_local_credentials (cmd));
1674 // Setup the priority string for this session; this avoids future
1675 // credential callbacks that ask for something impossible or
1678 // Variation factors:
1679 // - starting configuration (can it be empty?)
1680 // - Configured security parameters (database? variable?)
1681 // - CTYPEs, SRP, ANON-or-not --> fill in as + or - characters
1682 //TODO// Support for ANON-DH where appropriate
1683 if (gtls_errno == GNUTLS_E_SUCCESS) {
1685 snprintf (priostr, sizeof (priostr)-1,
1689 "%cSRP:%cSRP-RSA:%cSRP-DSS:"
1690 "%cANON-ECDH:%cANON-DH",
1691 lidtpsup (cmd, LID_TYPE_X509) ?'+':'-',
1692 lidtpsup (cmd, LID_TYPE_PGP) ?'+':'-',
1693 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
1694 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
1695 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
1696 0 /* TODO: ANON-DH */ ?'+':'-',
1697 0 /* TODO: ANON-DH */ ?'+':'-');
1698 tlog (TLOG_TLS, LOG_DEBUG, "Constructed priority string %s for local ID %s",
1699 priostr, cmd->cmd.pio_data.pioc_starttls.localid);
1700 E_g2e ("Failed to set GnuTLS priority string",
1701 gnutls_priority_set_direct (
1703 // "NORMAL:-KX-ALL:+SRP:+SRP-RSA:+SRP-DSS",
1704 // "NORMAL:+CTYPE-X.509:-CTYPE-OPENPGP:+CTYPE-X.509",
1705 // "NORMAL:-CTYPE-X.509:+CTYPE-OPENPGP:-CTYPE-X.509",
1706 // "NORMAL:+ANON-ECDH:+ANON-DH",
1712 // Check if past code stored an error code through POSIX
1713 if (cmd->session_errno) {
1714 gtls_errno = GNUTLS_E_USER_ERROR;
1718 // Now setup for the GnuTLS handshake
1720 if (gtls_errno == GNUTLS_E_SUCCESS) {
1721 gnutls_transport_set_int (session, cryptfd);
1722 gnutls_handshake_set_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1724 if (gtls_errno != GNUTLS_E_SUCCESS) {
1725 tlog (TLOG_TLS, LOG_ERR, "Failed to prepare for TLS: %s", gnutls_strerror (gtls_errno));
1726 if (cmd->session_errno) {
1727 send_error (cmd, cmd->session_errno, error_getstring ());
1729 send_error (cmd, EIO, "Failed to prepare for TLS");
1735 gtls_errno = gnutls_handshake (session);
1736 } while ((gtls_errno < 0) && (gnutls_error_is_fatal (gtls_errno) == 0));
1737 if ((gtls_errno == GNUTLS_E_SUCCESS) && cmd->session_errno) {
1738 gtls_errno = GNUTLS_E_USER_ERROR;
1742 // Cleanup any prefetched identities
1743 for (i=LID_TYPE_MIN; i<=LID_TYPE_MAX; i++) {
1744 if (cmd->lids [i - LID_TYPE_MIN].data != NULL) {
1745 free (cmd->lids [i - LID_TYPE_MIN].data);
1748 bzero (cmd->lids, sizeof (cmd->lids));
1749 if (NULL != (void *) cmd->session_privatekey) {
1750 gnutls_privkey_deinit ((void *) cmd->session_privatekey);
1751 cmd->session_privatekey = (intptr_t) (void *) NULL;
1753 if (NULL != (void *) cmd->session_certificate) {
1754 gnutls_pcert_deinit ((void *) cmd->session_certificate);
1755 free ((void *) cmd->session_certificate);
1756 cmd->session_certificate = (intptr_t) (void *) NULL;
1760 // From here, assume nothing about the cmd structure; as part of the
1761 // handshake, it may have passed through the client's control, as
1762 // part of a callback. So, reinitialise the entire return structure.
1763 //TODO// Or backup the (struct pioc_starttls) before handshaking
1764 cmd->cmd.pio_cmd = orig_cmd;
1765 cmd->cmd.pio_data.pioc_starttls.localid [0] =
1766 cmd->cmd.pio_data.pioc_starttls.remoteid [0] = 0;
1769 // Respond to positive or negative outcome of the handshake
1770 if (gtls_errno != GNUTLS_E_SUCCESS) {
1771 gnutls_deinit (session);
1772 tlog (TLOG_TLS, LOG_ERR, "TLS handshake failed: %s", gnutls_strerror (gtls_errno));
1773 if (cmd->session_errno) {
1774 tlog (TLOG_TLS, LOG_ERR, "Underlying cause may be: %s", strerror (cmd->session_errno));
1775 send_error (cmd, cmd->session_errno, error_getstring ());
1777 send_error (cmd, EPERM, "TLS handshake failed");
1779 manage_txn_rollback (&cmd->txn);
1783 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_INFO, "TLS handshake succeeded over %d", cryptfd);
1784 //TODO// extract_authenticated_remote_identity (cmd);
1788 // Request the plaintext file descriptor with a callback
1789 uint32_t oldcmd = cmd->cmd.pio_cmd;
1790 cmd->cmd.pio_cmd = PIOC_PLAINTEXT_CONNECT_V2;
1791 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Calling send_callback_and_await_response with PIOC_PLAINTEXT_CONNECT_V2");
1792 cmd = send_callback_and_await_response (cmd);
1793 if (cmd->cmd.pio_cmd != PIOC_PLAINTEXT_CONNECT_V2) {
1794 tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has unexpected command code");
1795 if (cmd->cmd.pio_cmd == PIOC_ERROR_V1) {
1796 send_command (cmd, -1); // Bounce error back
1798 send_error (cmd, EPROTO, "Unexpected response to plaintext connection callback");
1802 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Processing callback response that set plainfd:=%d for lid==\"%s\" and rid==\"%s\"", cmd->passfd, cmd->cmd.pio_data.pioc_starttls.localid, cmd->cmd.pio_data.pioc_starttls.remoteid);
1803 plainfd = cmd->passfd;
1806 tlog (TLOG_UNIXSOCK, LOG_ERR, "No plaintext file descriptor supplied to TLS Pool");
1807 send_error (cmd, EINVAL, "No plaintext file descriptor supplied to TLS Pool");
1808 manage_txn_rollback (&cmd->txn);
1812 if (cmd->cmd.pio_cmd != PIOC_PLAINTEXT_CONNECT_V2) {
1813 tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has bad command code");
1814 send_error (cmd, EINVAL, "Callback response has bad command code");
1815 manage_txn_rollback (&cmd->txn);
1820 cmd->cmd.pio_cmd = oldcmd;
1821 send_command (cmd, -1); // app sent plainfd to us
1824 // Copy TLS records until the connection is closed
1825 manage_txn_commit (&cmd->txn);
1826 copycat (plainfd, cryptfd, session, clientfd);
1831 * The starttls_client function responds to an application's request to
1832 * setup TLS for a given file descriptor, and return a file descriptor
1833 * with the unencrypted view when done. The main thing done here is to
1834 * spark off a new thread that handles the operations.
1835 * TODO: Are client and server routines different?
1837 void starttls_client (struct command *cmd) {
1838 /* Create a thread and, if successful, wait for it to unlock cmd */
1839 errno = pthread_create (&cmd->handler, NULL, starttls_thread, (void *) cmd);
1841 send_error (cmd, ESRCH, "STARTTLS_CLIENT thread refused");
1844 errno = pthread_detach (cmd->handler);
1846 pthread_cancel (cmd->handler);
1847 send_error (cmd, ESRCH, "STARTTLS_CLIENT thread detachment refused");
1853 * The starttls_server function responds to an application's request to
1854 * setup TLS for a given file descriptor, and return a file descriptor
1855 * with the unencrypted view when done. The main thing done here is to
1856 * spark off a new thread that handles the operations.
1858 void starttls_server (struct command *cmd) {
1859 /* Create a thread and, if successful, wait for it to unlock cmd */
1860 errno = pthread_create (&cmd->handler, NULL, starttls_thread, (void *) cmd);
1862 send_error (cmd, ESRCH, "STARTTLS_SERVER thread refused");
1865 errno = pthread_detach (cmd->handler);
1867 //TODO// Kill the thread... somehow
1868 send_error (cmd, ESRCH, "STARTTLS_CLIENT thread detachment refused");