1 /* tlspool/starttls.c -- Setup and validation handler for TLS session */
19 #include <sys/types.h>
20 #include <sys/socket.h>
22 #include <arpa/inet.h>
23 #include <netinet/in.h>
25 #include <gnutls/gnutls.h>
26 #include <gnutls/pkcs11.h>
27 #include <gnutls/abstract.h>
28 #include <gnutls/dane.h>
34 #include <tlspool/internal.h>
41 #if EXPECTED_LID_TYPE_COUNT != LID_TYPE_CNT
42 #error "Set EXPECTED_LID_TYPE_COUNT in <tlspool/internal.h> to match LID_TYPE_CNT"
46 /* This module hosts TLS handlers which treat an individual connection.
48 * Initially, the TLS setup is processed, which means validating the
49 * connection. If and when this succeeds, a continued process is needed
50 * to encrypt and decrypt traffic while it is in transit.
52 * Every TLS connection (including the attempt to set it up) is hosted in
53 * its own thread. This means that it can abide time to wait for PINENTRY,
54 * LOCALID or LIDENTRY responses. It also means a very clear flow when the
55 * time comes to destroy a connection.
57 * While encrypting and decrypting traffic passing through, the thread
58 * will use its own poll() call, and thus offload the potentially large
59 * one of the main thread, which is supposed to be a low-traffic task.
60 * The set of file descriptors used by the session-handler threads are
61 * in contrast very small and can easily be started for every single
62 * packet passing through.
64 * Might the user terminate a process while this one is waiting for a
65 * callback command request, then the main TLS pool thread will take
66 * care of taking down this thread. To that end, it sets the followup
67 * pointer that normally holds a callback response to NULL, and then
68 * permits this thread to run again. This will lead to a shutdown of
69 * this process, and proper closing of all connections. The remote peer
70 * will therefore see the result of a local kill as a connection reset.
72 * In case one of the end points of the connection is terminated, a
73 * similar thing will happen; the thread will terminate itself after
74 * a cleanup of any outstanding resources. This, once again, leads
75 * to passing on the reset of a connection between the encrypted and
76 * side of the connection.
82 * GnuTLS infrastructure setup.
83 * Session-shared DH-keys, credentials structures, and so on.
85 static gnutls_dh_params_t dh_params;
88 gnutls_credentials_type_t credtp;
92 #define EXPECTED_SRV_CREDCOUNT 3
93 #define EXPECTED_CLI_CREDCOUNT 3
94 static struct credinfo srv_creds [EXPECTED_SRV_CREDCOUNT];
95 static struct credinfo cli_creds [EXPECTED_CLI_CREDCOUNT];
96 static int srv_credcount = 0;
97 static int cli_credcount = 0;
98 static const char const *onthefly_p11uri = "pkcs11:manufacturer=ARPA2.net;token=TLS+Pool+internal;object=on-the-fly+signer;type=private;serial=1";
99 static unsigned long long onthefly_serial; //TODO: Fill with now * 1000
100 static gnutls_x509_crt_t onthefly_issuercrt = NULL;
101 static gnutls_privkey_t onthefly_issuerkey = NULL;
102 static gnutls_x509_privkey_t onthefly_subjectkey = NULL;
103 static pthread_mutex_t onthefly_signer_lock = PTHREAD_MUTEX_INITIALIZER;
105 static krb5_context kerberos_context;
106 static krb5_error_code have_credcache (krb5_principal sought, krb5_ccache *found);
108 /* The local variation on the ctlkeynode structure, with TLS-specific fields
110 struct ctlkeynode_tls {
111 struct ctlkeynode regent; // Structure for ctlkey_register()
112 gnutls_session_t session; // Additional data specifically for TLS
113 pthread_t owner; // For interruption of copycat()
114 int plainfd; // Plain-side connection
115 int cryptfd; // Crypt-side connection
118 /* The list of accepted Exporter Label Prefixes for starttls_prng()
120 char *tlsprng_label_prefixes [] = {
121 // Forbidden by RFC 5705: "client finished",
122 // Forbidden by RFC 5705: "server finished",
123 // Forbidden by RFC 5705: "master secret",
124 // Forbidden by RFC 5705: "key expansion",
125 "client EAP encryption", // not suited for DTLS
126 "ttls keying material", // not suited for DTLS
127 "ttls challenge", // not suited for DTLS
128 "EXTRACTOR-dtls_srtp",
129 "EXPORTER_DTLS_OVER_SCTP",
130 "EXPORTER-ETSI-TC-M2M-Bootstrap",
131 "EXPORTER-ETSI-TC-M2M-Connection",
133 "EXPORTER_GBA_Digest",
134 "EXPORTER: teap session key seed", // not suited for DTLS
135 "EXPORTER-oneM2M-Bootstrap",
136 "EXPORTER-oneM2M-Connection",
140 /* The registry with the service names that are deemed safe for an
141 * anonymous precursor phase; that is, the service names that may offer
142 * ANON-DH initially, and immediately renegotiate an authenticated
143 * connection. See doc/anonymising-precursor.* for more information.
145 * The registry is ordered by case-independent service name, so it can
146 * be searched in 2log time. Service names are as defined by IANA in the
147 * "Service Name and Transport Protocol Port Number Registry".
149 * The entries in the registry depend on the role played; either as a
150 * client or as a server. This refers to the local node, and depends on
151 * uncertainty of the remote party's TLS implementation and whether or
152 * not the protocol could lead to the remote sending information that
153 * requires authentication before the secure renogiation into an
154 * authenticated connection has been completed by this side. This is
155 * a protocol-dependent matter and the registry provided here serves to
156 * encapsulate this knowledge inside the TLS Pool instead of bothering
157 * application designers with it. Entries that are not found in the
158 * registry are interpreted as not allowing an anonymising precursor.
160 * Note that ANONPRE_EXTEND_MASTER_SECRET cannot be verified before
161 * GnuTLS version 3.4.0; see "imap" below for the resulting impact. This
162 * also impacts dynamic linking, because 3.4.0 introduces the new function
163 * gnutls_ext_get_data() that is used for this requirement.
165 #define ANONPRE_FORBID 0x00
166 #define ANONPRE_CLIENT 0x01
167 #define ANONPRE_SERVER 0x02
168 #define ANONPRE_EITHER (ANONPRE_CLIENT | ANONPRE_SERVER)
169 #define ANONPRE_EXTEND_MASTER_SECRET 0x10
170 struct anonpre_regentry {
174 struct anonpre_regentry anonpre_registry [] = {
175 /* This registry is commented out for now, although the code to use it seems
176 * to work fine. GnuTLS however, does not seem to support making the switch
177 * from ANON-ECDH to an authenticated handshake. Details:
178 * http://lists.gnutls.org/pipermail/gnutls-help/2015-November/003998.html
180 { "generic_anonpre", ANONPRE_EITHER }, // Name invalid as per RFC 6335
181 { "http", ANONPRE_CLIENT }, // Server also if it ignores client ID
182 #if GNUTLS_VERSION_NUMBER < 0x030400
183 { "imap", ANONPRE_SERVER },
185 { "imap", ANONPRE_EITHER | ANONPRE_EXTEND_MASTER_SECRET },
187 { "pop3", ANONPRE_EITHER },
188 { "smtp", ANONPRE_EITHER },
190 * End of commenting out the registry
193 const int anonpre_registry_size = sizeof (anonpre_registry) / sizeof (struct anonpre_regentry);
196 /* The registry of Key Usage and Extended Key Usage for any given service name.
198 static const char *http_noncrit [] = { GNUTLS_KP_TLS_WWW_SERVER, GNUTLS_KP_TLS_WWW_CLIENT, NULL };
199 struct svcusage_regentry {
202 const char **oids_non_critical;
203 const char **oids_critical;
205 struct svcusage_regentry svcusage_registry [] = {
207 GNUTLS_KEY_KEY_ENCIPHERMENT |
208 GNUTLS_KEY_KEY_AGREEMENT,
213 GNUTLS_KEY_DIGITAL_SIGNATURE |
214 GNUTLS_KEY_KEY_ENCIPHERMENT |
215 GNUTLS_KEY_KEY_AGREEMENT,
220 const int svcusage_registry_size = sizeof (svcusage_registry) / sizeof (struct svcusage_regentry);
223 /* The maximum number of bytes that can be passed over a TLS connection before
224 * the authentication is complete in case of a anonymous precursor within a
225 * protocol that ensures that this cannot be a problem.
229 /* The priorities cache for "NORMAL" -- used to preconfigure the server,
230 * actually to overcome its unwillingness to perform the handshake, and
231 * leave it to srv_clienthello() to setup the priority string.
233 gnutls_priority_t priority_normal;
236 /* Map a GnuTLS call (usually a function call) to a POSIX errno,
237 * optionally reporting an errstr to avoid loosing information.
238 * Retain errno if it already exists.
239 * Continue if errno differs from 0, GnuTLS may "damage" it even when OK. */
240 #define E_g2e(errstr,gtlscall) { \
241 if (gtls_errno == GNUTLS_E_SUCCESS) { \
242 gtls_errno = (gtlscall); \
243 if (gtls_errno != GNUTLS_E_SUCCESS) { \
244 error_gnutls2posix (gtls_errno, errstr); \
249 /* Cleanup when GnuTLS leaves errno damaged but returns no gtls_errno */
250 #define E_gnutls_clear_errno() { \
251 if (gtls_errno == GNUTLS_E_SUCCESS) { \
256 /* Error number translation, including error string setup. See E_g2e(). */
257 void error_gnutls2posix (int gtls_errno, char *new_errstr) {
259 register int newerrno;
262 if (gtls_errno == GNUTLS_E_SUCCESS) {
265 errstr = error_getstring ();
266 if (errstr != NULL) {
270 // Report the textual error
271 if (new_errstr == NULL) {
272 new_errstr = "GnuTLS error";
274 tlog (TLOG_TLS, LOG_ERR, "%s: %s",
276 gnutls_strerror (gtls_errno));
277 error_setstring (new_errstr);
279 // Translate error to a POSIX errno value
280 switch (gtls_errno) {
281 case GNUTLS_E_SUCCESS:
283 case GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM:
284 case GNUTLS_E_UNKNOWN_CIPHER_TYPE:
285 case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
286 case GNUTLS_E_UNWANTED_ALGORITHM:
287 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
288 case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
289 case GNUTLS_E_X509_UNKNOWN_SAN:
290 case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
291 case GNUTLS_E_UNKNOWN_PK_ALGORITHM:
292 case GNUTLS_E_NO_TEMPORARY_RSA_PARAMS:
293 case GNUTLS_E_NO_COMPRESSION_ALGORITHMS:
294 case GNUTLS_E_NO_CIPHER_SUITES:
295 case GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED:
296 case GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE:
297 case GNUTLS_E_UNKNOWN_HASH_ALGORITHM:
298 case GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE:
299 case GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE:
300 case GNUTLS_E_NO_TEMPORARY_DH_PARAMS:
301 case GNUTLS_E_UNKNOWN_ALGORITHM:
302 case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
303 case GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED:
304 case GNUTLS_E_X509_UNSUPPORTED_OID:
305 case GNUTLS_E_CHANNEL_BINDING_NOT_AVAILABLE:
306 case GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL:
307 case GNUTLS_E_ECC_NO_SUPPORTED_CURVES:
308 case GNUTLS_E_ECC_UNSUPPORTED_CURVE:
309 case GNUTLS_E_X509_UNSUPPORTED_EXTENSION:
310 case GNUTLS_E_NO_CERTIFICATE_STATUS:
311 case GNUTLS_E_NO_APPLICATION_PROTOCOL:
312 #ifdef GNUTLS_E_NO_SELF_TEST
313 case GNUTLS_E_NO_SELF_TEST:
315 newerrno = EOPNOTSUPP;
317 case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
318 case GNUTLS_E_INVALID_REQUEST:
321 case GNUTLS_E_INVALID_SESSION:
322 case GNUTLS_E_REHANDSHAKE:
323 case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
326 case GNUTLS_E_PUSH_ERROR:
327 case GNUTLS_E_PULL_ERROR:
328 case GNUTLS_E_PREMATURE_TERMINATION:
329 case GNUTLS_E_SESSION_EOF:
330 newerrno = ECONNRESET;
332 case GNUTLS_E_UNEXPECTED_PACKET:
333 case GNUTLS_E_WARNING_ALERT_RECEIVED:
334 case GNUTLS_E_FATAL_ALERT_RECEIVED:
335 case GNUTLS_E_LARGE_PACKET:
336 case GNUTLS_E_ERROR_IN_FINISHED_PACKET:
337 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
338 case GNUTLS_E_MPI_SCAN_FAILED:
339 case GNUTLS_E_DECRYPTION_FAILED:
340 case GNUTLS_E_DECOMPRESSION_FAILED:
341 case GNUTLS_E_COMPRESSION_FAILED:
342 case GNUTLS_E_BASE64_DECODING_ERROR:
343 case GNUTLS_E_MPI_PRINT_FAILED:
344 case GNUTLS_E_GOT_APPLICATION_DATA:
345 case GNUTLS_E_RECORD_LIMIT_REACHED:
346 case GNUTLS_E_ENCRYPTION_FAILED:
347 case GNUTLS_E_PK_ENCRYPTION_FAILED:
348 case GNUTLS_E_PK_DECRYPTION_FAILED:
349 case GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER:
350 case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
351 case GNUTLS_E_PKCS1_WRONG_PAD:
352 case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
353 case GNUTLS_E_FILE_ERROR:
354 case GNUTLS_E_ASN1_ELEMENT_NOT_FOUND:
355 case GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND:
356 case GNUTLS_E_ASN1_DER_ERROR:
357 case GNUTLS_E_ASN1_VALUE_NOT_FOUND:
358 case GNUTLS_E_ASN1_GENERIC_ERROR:
359 case GNUTLS_E_ASN1_VALUE_NOT_VALID:
360 case GNUTLS_E_ASN1_TAG_ERROR:
361 case GNUTLS_E_ASN1_TAG_IMPLICIT:
362 case GNUTLS_E_ASN1_TYPE_ANY_ERROR:
363 case GNUTLS_E_ASN1_SYNTAX_ERROR:
364 case GNUTLS_E_ASN1_DER_OVERFLOW:
365 case GNUTLS_E_TOO_MANY_EMPTY_PACKETS:
366 case GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS:
367 case GNUTLS_E_SRP_PWD_PARSING_ERROR:
368 case GNUTLS_E_BASE64_ENCODING_ERROR:
369 case GNUTLS_E_OPENPGP_KEYRING_ERROR:
370 case GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR:
371 case GNUTLS_E_OPENPGP_SUBKEY_ERROR:
372 case GNUTLS_E_CRYPTO_ALREADY_REGISTERED:
373 case GNUTLS_E_HANDSHAKE_TOO_LARGE:
374 case GNUTLS_E_BAD_COOKIE:
375 case GNUTLS_E_PARSING_ERROR:
376 case GNUTLS_E_CERTIFICATE_LIST_UNSORTED:
377 case GNUTLS_E_NO_PRIORITIES_WERE_SET:
378 #ifdef GNUTLS_E_PK_GENERATION_ERROR
379 case GNUTLS_E_PK_GENERATION_ERROR:
381 #ifdef GNUTLS_E_SELF_TEST_ERROR
382 case GNUTLS_E_SELF_TEST_ERROR:
384 #ifdef GNUTLS_E_SOCKETS_INIT_ERROR
385 case GNUTLS_E_SOCKETS_INIT_ERROR:
389 case GNUTLS_E_MEMORY_ERROR:
390 case GNUTLS_E_SHORT_MEMORY_BUFFER:
396 case GNUTLS_E_EXPIRED:
397 case GNUTLS_E_TIMEDOUT:
398 newerrno = ETIMEDOUT;
400 case GNUTLS_E_DB_ERROR:
407 case GNUTLS_E_SRP_PWD_ERROR:
408 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
409 case GNUTLS_E_HASH_FAILED:
410 case GNUTLS_E_PK_SIGN_FAILED:
411 case GNUTLS_E_CERTIFICATE_ERROR:
412 case GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION:
413 case GNUTLS_E_KEY_USAGE_VIOLATION:
414 case GNUTLS_E_NO_CERTIFICATE_FOUND:
415 case GNUTLS_E_OPENPGP_UID_REVOKED:
416 case GNUTLS_E_OPENPGP_GETKEY_FAILED:
417 case GNUTLS_E_PK_SIG_VERIFY_FAILED:
418 case GNUTLS_E_ILLEGAL_SRP_USERNAME:
419 case GNUTLS_E_INVALID_PASSWORD:
420 case GNUTLS_E_MAC_VERIFY_FAILED:
421 case GNUTLS_E_IA_VERIFY_FAILED:
422 case GNUTLS_E_UNKNOWN_SRP_USERNAME:
423 case GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR:
424 case GNUTLS_E_USER_ERROR:
425 case GNUTLS_E_AUTH_ERROR:
428 case GNUTLS_E_INTERRUPTED:
431 case GNUTLS_E_INTERNAL_ERROR:
432 case GNUTLS_E_CONSTRAINT_ERROR:
433 case GNUTLS_E_ILLEGAL_PARAMETER:
436 case GNUTLS_E_SAFE_RENEGOTIATION_FAILED:
437 newerrno = ECONNREFUSED;
439 case GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY:
440 case GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY:
441 #ifdef GNUTLS_E_LIB_IN_ERROR_STATE
442 case GNUTLS_E_LIB_IN_ERROR_STATE:
446 case GNUTLS_E_RANDOM_FAILED:
449 case GNUTLS_E_CRYPTODEV_IOCTL_ERROR:
450 case GNUTLS_E_CRYPTODEV_DEVICE_ERROR:
451 case GNUTLS_E_HEARTBEAT_PONG_RECEIVED:
452 case GNUTLS_E_HEARTBEAT_PING_RECEIVED:
453 case GNUTLS_E_PKCS11_ERROR:
454 case GNUTLS_E_PKCS11_LOAD_ERROR:
455 case GNUTLS_E_PKCS11_PIN_ERROR:
456 case GNUTLS_E_PKCS11_SLOT_ERROR:
457 case GNUTLS_E_LOCKING_ERROR:
458 case GNUTLS_E_PKCS11_ATTRIBUTE_ERROR:
459 case GNUTLS_E_PKCS11_DEVICE_ERROR:
460 case GNUTLS_E_PKCS11_DATA_ERROR:
461 case GNUTLS_E_PKCS11_UNSUPPORTED_FEATURE_ERROR:
462 case GNUTLS_E_PKCS11_KEY_ERROR:
463 case GNUTLS_E_PKCS11_PIN_EXPIRED:
464 case GNUTLS_E_PKCS11_PIN_LOCKED:
465 case GNUTLS_E_PKCS11_SESSION_ERROR:
466 case GNUTLS_E_PKCS11_SIGNATURE_ERROR:
467 case GNUTLS_E_PKCS11_TOKEN_ERROR:
468 case GNUTLS_E_PKCS11_USER_ERROR:
469 case GNUTLS_E_CRYPTO_INIT_FAILED:
470 case GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE:
471 case GNUTLS_E_TPM_ERROR:
472 case GNUTLS_E_TPM_KEY_PASSWORD_ERROR:
473 case GNUTLS_E_TPM_SRK_PASSWORD_ERROR:
474 case GNUTLS_E_TPM_SESSION_ERROR:
475 case GNUTLS_E_TPM_KEY_NOT_FOUND:
476 case GNUTLS_E_TPM_UNINITIALIZED:
477 case GNUTLS_E_OCSP_RESPONSE_ERROR:
478 case GNUTLS_E_RANDOM_DEVICE_ERROR:
480 newerrno = EREMOTEIO;
493 /* Generate Diffie-Hellman parameters - for use with DHE
494 * kx algorithms. TODO: These should be discarded and regenerated
495 * once a day, once a week or once a month. Depending on the
496 * security requirements.
498 static gtls_error generate_dh_params (void) {
500 int gtls_errno = GNUTLS_E_SUCCESS;
501 bits = gnutls_sec_param_to_pk_bits (
503 GNUTLS_SEC_PARAM_LEGACY);
504 //TODO// Acquire DH-params lock
505 E_g2e ("Failed to initialise DH params",
506 gnutls_dh_params_init (
508 E_g2e ("Failed to generate DH params",
509 gnutls_dh_params_generate2 (
512 //TODO// Release DH-params lock
516 /* Load Diffie-Hellman parameters from file - or generate them when load fails.
518 static gtls_error load_dh_params (void) {
519 gnutls_dh_params_t dhp;
520 gnutls_datum_t pkcs3;
521 char *filename = cfg_tls_dhparamfile ();
522 int gtls_errno = GNUTLS_E_SUCCESS;
523 bzero (&pkcs3, sizeof (pkcs3));
525 E_g2e ("No PKCS #3 PEM file with DH params",
529 E_gnutls_clear_errno ();
530 E_g2e ("Failed to initialise DH params",
531 gnutls_dh_params_init (
533 E_g2e ("Failed to import DH params from PKCS #3 PEM",
534 gnutls_dh_params_import_pkcs3 (
537 GNUTLS_X509_FMT_PEM));
538 E_gnutls_clear_errno ();
540 if (pkcs3.data != NULL) {
543 if (gtls_errno != GNUTLS_E_SUCCESS) {
545 // File failed to load, so try to generate fresh DH params
546 int gtls_errno_stack0;
547 gtls_errno = GNUTLS_E_SUCCESS;
548 tlog (TLOG_CRYPTO, LOG_DEBUG, "Failed to load DH params from %s; generating fresh parameters", filename);
549 E_g2e ("Failed to generate DH params",
550 generate_dh_params ());
551 gtls_errno_stack0 = gtls_errno;
552 //TODO// Acquire DH-params lock
553 E_g2e ("Failed to format DH params as PKCS #3 PEM",
554 gnutls_dh_params_export2_pkcs3 (
558 //TODO// Release DH-params lock
559 if ((gtls_errno == GNUTLS_E_SUCCESS) && (filename != NULL)) {
562 // Best effor file save -- readback will parse
563 pemf = fopen (filename, "w");
565 fwrite (pkcs3.data, 1, pkcs3.size, pemf);
567 tlog (TLOG_FILES, LOG_DEBUG, "Saved DH params to %s (best-effort)", filename);
569 E_gnutls_clear_errno ();
571 gtls_errno = gtls_errno_stack0;
573 gnutls_dh_params_t old_dh;
574 //TODO// Acquire DH-params lock
577 //TODO// Release DH-params lock
579 gnutls_dh_params_deinit (old_dh);
585 /* Remove DH parameters, to be used during program cleanup. */
586 static void remove_dh_params (void) {
588 gnutls_dh_params_deinit (dh_params);
594 /* A log printing function
596 void log_gnutls (int level, const char *msg) {
597 tlog (TLOG_TLS, level, "GnuTLS: %s", msg);
601 /* Implement the GnuTLS function for token insertion callback. This function
602 * refers back to the generic callback for token insertion.
604 int gnutls_token_callback (void *const userdata,
605 const char *const label,
607 if (token_callback (label, retry)) {
608 return GNUTLS_E_SUCCESS;
610 return GNUTLS_E_PKCS11_TOKEN_ERROR;
616 * Implement the GnuTLS function for PIN callback. This function calls
617 * the generic PIN callback operation.
619 int gnutls_pin_callback (void *userdata,
621 const char *token_url,
622 const char *token_label,
626 if (flags & GNUTLS_PIN_SO) {
627 return GNUTLS_E_USER_ERROR;
629 if (pin_callback (attempt, token_url, token_label, pin, pin_max)) {
632 return GNUTLS_E_PKCS11_PIN_ERROR;
637 /* Register a PKCS #11 provider with the GnuTLS environment. */
638 void starttls_pkcs11_provider (char *p11path) {
639 unsigned int token_seq = 0;
641 if (gnutls_pkcs11_add_provider (p11path, NULL) != 0) {
642 fprintf (stderr, "Failed to register PKCS #11 library %s with GnuTLS\n", p11path);
645 while (gnutls_pkcs11_token_get_url (token_seq, 0, &p11uri) == 0) {
647 fprintf (stderr, "DEBUG: Found token URI %s\n", p11uri);
649 //TODO// if (gnutls_pkcs11_token_get_info (p11uri, GNUTLS_PKCS11_TOKEN_LABEL-of-SERIAL-of-MANUFACTURER-of-MODEL, output, utput_size) == 0) { ... }
650 gnutls_free (p11uri);
653 //TODO// Select token by name (value)
654 //TODO// if PIN available then set it up
655 //TODO:WHY?// free_p11pin ();
659 /* The global and static setup function for the starttls functions.
661 void setup_starttls (void) {
662 int setup_starttls_credentials (void); /* Defined below */
664 int gtls_errno = GNUTLS_E_SUCCESS;
665 char *otfsigcrt, *otfsigkey;
667 // Setup configuration variables
668 maxpreauth = cfg_tls_maxpreauth ();
670 // Basic library actions
671 tlog (TLOG_TLS, LOG_DEBUG, "Compiled against GnuTLS version %s", GNUTLS_VERSION);
672 curver = gnutls_check_version (GNUTLS_VERSION);
673 tlog (TLOG_TLS, LOG_DEBUG, "Running against %s GnuTLS version %s", curver? "acceptable": "OLDER", curver? curver: gnutls_check_version (NULL));
674 E_g2e ("GnuTLS global initialisation failed",
675 gnutls_global_init ());
676 E_gnutls_clear_errno ();
677 E_g2e ("GnuTLS PKCS #11 initialisation failed",
679 GNUTLS_PKCS11_FLAG_MANUAL, NULL));
681 // Setup logging / debugging
682 if (cfg_log_level () == LOG_DEBUG) {
683 gnutls_global_set_log_function (log_gnutls);
684 gnutls_global_set_log_level (9);
687 // Setup callbacks for user communication
688 gnutls_pkcs11_set_token_function (gnutls_token_callback, NULL);
689 gnutls_pkcs11_set_pin_function (gnutls_pin_callback, NULL);
691 // Setup DH parameters
692 E_g2e ("Loading DH params failed",
695 // Setup shared credentials for all client server processes
696 E_g2e ("Failed to setup GnuTLS callback credentials",
697 setup_starttls_credentials ());
699 // Parse the default priority string
700 E_g2e ("Failed to setup NORMAL priority cache",
701 gnutls_priority_init (&priority_normal, "NONE:+VERS-TLS-ALL:+VERS-DTLS-ALL:+COMP-NULL:"
703 "%GNUTLS_ASYM_CERT_TYPES:"
705 "+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:+ANON-ECDH:+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:+CTYPE-X.509:+CTYPE-OPENPGP:+SRP:+SRP-RSA:+SRP-DSS", NULL));
706 // gnutls_priority_init (&priority_normal, "NORMAL:-RSA:+ANON-ECDH:+RSA:+CTYPE-X.509:+CTYPE-OPENPGP:+SRP:+SRP-RSA:+SRP-DSS", NULL));
708 // Try to setup on-the-fly signing key / certificate and gen a certkey
709 otfsigcrt = cfg_tls_onthefly_signcert ();
710 otfsigkey = cfg_tls_onthefly_signkey ();
711 fprintf (stderr, "DEBUG: gtls_errno = %d, otfsigcrt == %s, otfsigkey == %s\n", gtls_errno, otfsigcrt? otfsigcrt: "NULL", otfsigkey? otfsigkey: "NULL");
712 if ((gtls_errno == GNUTLS_E_SUCCESS) && (otfsigcrt != NULL)) {
713 FILE *crtfile = NULL;
714 fprintf (stderr, "DEBUG: gtls_errno==%d when initialising onthefly_issuercrt\n", gtls_errno);
715 E_g2e ("Failed to initialise on-the-fly issuer certificate structure",
716 gnutls_x509_crt_init (&onthefly_issuercrt));
717 if (strncmp (otfsigcrt, "file:", 5) == 0) {
718 // Provisionary support for the "file:" prefix
721 crtfile = fopen (otfsigcrt, "r");
722 if (crtfile == NULL) {
723 E_g2e ("Failed to open on-the-fly issuer certificate file",
724 GNUTLS_E_FILE_ERROR);
725 fprintf (stderr, "DEBUG: gtls_errno==%d after failing to open file for onthefly_issuercrt\n", gtls_errno);
728 size_t len = fread (crt, 1, sizeof (crt), crtfile);
729 if (ferror (crtfile)) {
730 E_g2e ("Failed to read on-the-fly issuer certificate from file",
731 GNUTLS_E_FILE_ERROR);
732 } else if ((len >= sizeof (crt)) || !feof (crtfile)) {
733 E_g2e ("Unexpectedly long on-the-fly issuer certificate file",
734 GNUTLS_E_FILE_ERROR);
736 gnutls_datum_t cd = {
740 fprintf (stderr, "DEBUG: gtls_errno==%d before importing onthefly_issuercrt\n", gtls_errno);
741 E_g2e ("Failed to import on-the-fly certificate from file",
742 gnutls_x509_crt_import (onthefly_issuercrt, &cd, GNUTLS_X509_FMT_DER));
743 fprintf (stderr, "DEBUG: gtls_errno==%d after importing onthefly_issuercrt\n", gtls_errno);
748 if ((gtls_errno == GNUTLS_E_SUCCESS) && (otfsigkey != NULL)) {
749 E_g2e ("Failed to initialise on-the-fly issuer private key structure",
750 gnutls_privkey_init (&onthefly_issuerkey));
751 fprintf (stderr, "DEBUG: before onthefly p11 import, gtlserrno = %d\n", gtls_errno);
752 E_g2e ("Failed to import pkcs11: URI into on-the-fly issuer private key",
753 gnutls_privkey_import_pkcs11_url (onthefly_issuerkey, otfsigkey));
754 fprintf (stderr, "DEBUG: after onthefly p11 import, gtlserrno = %d\n", gtls_errno);
756 fprintf (stderr, "DEBUG: When it matters, gtls_errno = %d, onthefly_issuercrt %s NULL, onthefly_issuerkey %s NULL\n", gtls_errno, onthefly_issuercrt?"!=":"==", onthefly_issuerkey?"!=":"==");
757 if ((gtls_errno == GNUTLS_E_SUCCESS) && (onthefly_issuercrt != NULL) && (onthefly_issuerkey != NULL)) {
758 E_g2e ("Failed to initialise on-the-fly certificate session key",
759 gnutls_x509_privkey_init (&onthefly_subjectkey));
760 E_g2e ("Failed to generate on-the-fly certificate session key",
761 gnutls_x509_privkey_generate (onthefly_subjectkey, GNUTLS_PK_RSA, 2048 /*TODO:FIXED*/, 0));
762 if (gtls_errno == GNUTLS_E_SUCCESS) {
763 tlog (TLOG_TLS, LOG_INFO, "Setup for on-the-fly signing with the TLS Pool");
765 tlog (TLOG_TLS, LOG_ERR, "Failed to setup on-the-fly signing (shall continue without it)");
766 gnutls_x509_privkey_deinit (onthefly_subjectkey);
767 onthefly_subjectkey = NULL;
770 gtls_errno = GNUTLS_E_SUCCESS;
771 E_gnutls_clear_errno ();
773 if (onthefly_subjectkey == NULL) {
774 if (onthefly_issuercrt != NULL) {
775 gnutls_x509_crt_deinit (onthefly_issuercrt);
776 onthefly_issuercrt = NULL;
778 if (onthefly_issuerkey != NULL) {
779 gnutls_privkey_deinit (onthefly_issuerkey);
780 onthefly_issuerkey = NULL;
784 // Finally, check whether there was any error setting up GnuTLS
785 if (gtls_errno != GNUTLS_E_SUCCESS) {
786 tlog (TLOG_TLS, LOG_CRIT, "FATAL: GnuTLS setup failed: %s", gnutls_strerror (gtls_errno));
790 //MOVED// // Setup the management databases
791 //MOVED// tlog (TLOG_DB, LOG_DEBUG, "Setting up management databases");
792 //MOVED// E_e2e ("Failed to setup management databases",
793 //MOVED// setup_management ());
794 //MOVED// if (errno != 0) {
795 //MOVED// tlog (TLOG_DB, LOG_CRIT, "FATAL: Management databases setup failed: %s", strerror (errno));
800 /* Cleanup the structures and resources that were setup for handling TLS.
802 void cleanup_starttls (void) {
803 void cleanup_starttls_credentials (void); /* Defined below */
804 //MOVED// cleanup_management ();
805 if (onthefly_subjectkey != NULL) {
806 gnutls_x509_privkey_deinit (onthefly_subjectkey);
807 onthefly_subjectkey = NULL;
809 if (onthefly_issuercrt != NULL) {
810 gnutls_x509_crt_deinit (onthefly_issuercrt);
811 onthefly_issuercrt = NULL;
813 if (onthefly_issuerkey != NULL) {
814 gnutls_privkey_deinit (onthefly_issuerkey);
815 onthefly_issuerkey = NULL;
817 if (kerberos_context != NULL) {
818 krb5_free_context (kerberos_context);
819 kerberos_context = NULL;
821 cleanup_starttls_credentials ();
823 gnutls_pkcs11_set_pin_function (NULL, NULL);
824 gnutls_pkcs11_set_token_function (NULL, NULL);
825 gnutls_pkcs11_deinit ();
826 gnutls_priority_deinit (priority_normal);
827 gnutls_global_deinit ();
832 * The copycat function is a bidirectional transport between the given
833 * remote and local sockets, but it will encrypt traffic from local to
834 * remote, and decrypt traffic from remote to local. It will do this
835 * until one of the end points is shut down, at which time it will
836 * return and assume the context will close down both pre-existing
839 * This copycat actually has a few sharp claws to watch for -- shutdown
840 * of sockets may drop the last bit of information sent. First, the
841 * signal POLLHUP is best ignored because it travels asynchronously.
842 * Second, reading 0 is a good indicator of end-of-file and may be
843 * followed by an shutdown of reading from that stream. But, more
844 * importantly, the other side must have this information forwarded
845 * so it can shutdown. This means that a shutdown for writing to that
846 * stream is to be sent. Even when *both* sides have agreed to not send
847 * anything, they may still not have received all they were offered for
848 * reading, so we should SO_LINGER on the sockets so they can acknowledge,
849 * and after a timeout we can establish that shutdown failed and log and
850 * return an error for it.
851 * Will you believe that I had looked up if close() would suffice? The man
852 * page clearly stated yes. However, these articles offer much more detail:
853 * http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable
854 * http://www.greenend.org.uk/rjk/tech/poll.html
856 * This function blocks during its call to poll(), in a state that can easily
857 * be restarted. This is when thread cancellation is temporarily enabled.
858 * Other threads may use this to cancel the thread and have it joined with that
859 * thread which will subsume its tasks and restart the handshake. We might
860 * later make this more advanced, by using a cancel stack push/pull mechanisms
861 * to ensure that recv() always results in send() in spite of cancellation.
863 * The return value of copycat is a GNUTLS_E_ code, usually GNUTLS_E_SUCCESS.
864 * For the moment, only one special value is of concern, namely
865 * GNUTLS_E_REHANDSHAKE which client or server side may receive when an
866 * attempt is made to renegotiate the security of the connection.
868 static int copycat (int local, int remote, gnutls_session_t wrapped, int client) {
870 struct pollfd inout [3];
872 struct linger linger = { 1, 10 };
874 int retval = GNUTLS_E_SUCCESS;
876 inout [0].fd = local;
877 inout [1].fd = remote;
878 inout [2].fd = client;
879 have_client = inout [2].fd >= 0;
881 inout [2].revents = 0; // Will not be written by poll
882 //FORK!=DETACH// inout [2].fd = ctlkey_signalling_fd;
884 inout [0].events = POLLIN;
885 inout [1].events = POLLIN;
886 inout [2].events = 0; // error events only
887 tlog (TLOG_COPYCAT, LOG_DEBUG, "Starting copycat cycle for local=%d, remote=%d, control=%d", local, remote, client);
888 while (((inout [0].events | inout [1].events) & POLLIN) != 0) {
890 assert (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) == 0);
891 pthread_testcancel (); // Efficiency & Certainty
892 polled = poll (inout, have_client? 3: 2, -1);
893 assert (pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL) == 0);
895 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat polling returned an error");
896 break; // Polling sees an error
898 if (inout [0].revents & POLLIN) {
899 // Read local and encrypt to remote
900 sz = recv (local, buf, sizeof (buf), MSG_DONTWAIT | MSG_NOSIGNAL);
901 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat received %d local bytes (or error<0) from %d", (int) sz, local);
903 tlog (TLOG_COPYCAT, LOG_ERR, "Error while receiving: %s", strerror (errno));
904 break; // stream error
905 } else if (sz == 0) {
906 inout [0].events &= ~POLLIN;
907 shutdown (local, SHUT_RD);
908 setsockopt (remote, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
909 gnutls_bye (wrapped, GNUTLS_SHUT_WR);
910 } else if (gnutls_record_send (wrapped, buf, sz) != sz) {
911 tlog (TLOG_COPYCAT, LOG_ERR, "gnutls_record_send() failed to pass on the requested bytes");
912 break; // communication error
914 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat sent %d bytes to remote %d", (int) sz, remote);
917 if (inout [1].revents & POLLIN) {
918 // Read remote and decrypt to local
919 sz = gnutls_record_recv (wrapped, buf, sizeof (buf));
920 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat received %d remote bytes from %d (or error if <0)", (int) sz, remote);
922 //TODO// Process GNUTLS_E_REHANDSHAKE
923 if (sz == GNUTLS_E_REHANDSHAKE) {
924 tlog (TLOG_TLS, LOG_INFO, "Received renegotiation request over TLS handle %d", remote);
925 retval = GNUTLS_E_REHANDSHAKE;
927 } else if (gnutls_error_is_fatal (sz)) {
928 tlog (TLOG_TLS, LOG_ERR, "GnuTLS fatal error: %s", gnutls_strerror (sz));
929 break; // stream error
931 tlog (TLOG_TLS, LOG_INFO, "GnuTLS recoverable error: %s", gnutls_strerror (sz));
933 } else if (sz == 0) {
934 inout [1].events &= ~POLLIN;
935 shutdown (remote, SHUT_RD);
936 setsockopt (local, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
937 shutdown (local, SHUT_WR);
938 } else if (send (local, buf, sz, MSG_DONTWAIT | MSG_NOSIGNAL) != sz) {
939 break; // communication error
941 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat sent %d bytes to local %d", (int) sz, local);
944 inout [0].revents &= ~(POLLIN | POLLHUP); // Thy copying cat?
945 inout [1].revents &= ~(POLLIN | POLLHUP); // Retract thee claws!
946 if ((inout [0].revents | inout [1].revents) & ~POLLIN) {
947 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat data connection polling returned a special condition");
948 break; // Apparently, one of POLLERR, POLLHUP, POLLNVAL
950 if (inout [2].revents & ~POLLIN) {
952 // This case is currently not ever triggered
953 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat control connection polling returned a special condition");
954 break; // Apparently, one of POLLERR, POLLHUP, POLLNVAL
956 inout [2].fd = client;
957 have_client = inout [2].fd >= 0;
959 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat signalling_fd polling raised a signal to set control fd to %d", inout [2].fd);
961 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat signalling_fd polling raised a signal that could be ignored");
967 tlog (TLOG_COPYCAT, LOG_DEBUG, "Ending copycat cycle for local=%d, remote=%d", local, remote);
972 /* The callback function that retrieves certification information from either
973 * the client or the server in the course of the handshake procedure.
975 gtls_error clisrv_cert_retrieve (gnutls_session_t session,
976 const gnutls_datum_t* req_ca_dn,
978 const gnutls_pk_algorithm_t* pk_algos,
980 gnutls_pcert_st** pcert,
981 unsigned int *pcert_length,
982 gnutls_privkey_t *pkey) {
983 gnutls_certificate_type_t certtp;
984 gnutls_pcert_st *pc = NULL;
987 gnutls_datum_t privdatum = { NULL, 0 };
988 gnutls_datum_t certdatum = { NULL, 0 };
989 gnutls_openpgp_crt_t pgpcert = NULL;
990 gnutls_openpgp_privkey_t pgppriv = NULL;
991 int gtls_errno = GNUTLS_E_SUCCESS;
995 char sni [sizeof (cmd->cmd.pio_data.pioc_starttls.localid)];
996 size_t snilen = sizeof (sni);
1003 gtls_error fetch_local_credentials (struct command *cmd);
1004 gnutls_pcert_st *load_certificate_chain (uint32_t flags, unsigned int *chainlen, gnutls_datum_t *certdatum);
1007 // Setup a number of common references and structures
1009 cmd = (struct command *) gnutls_session_get_ptr (session);
1011 E_g2e ("No data pointer with session",
1012 GNUTLS_E_INVALID_SESSION);
1015 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
1016 lidrole = LID_ROLE_CLIENT;
1018 } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
1019 lidrole = LID_ROLE_SERVER;
1022 E_g2e ("TLS Pool command supports neither local client nor local server role",
1023 GNUTLS_E_INVALID_SESSION);
1026 lid = cmd->cmd.pio_data.pioc_starttls.localid;
1027 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
1030 // On a server, lookup the server name and match it against lid.
1031 // TODO: For now assume a single server name in SNI (as that is normal).
1032 if (lidrole == LID_ROLE_SERVER) {
1033 if (gnutls_server_name_get (session, sni, &snilen, &snitype, 0) || (snitype != GNUTLS_NAME_DNS)) {
1034 E_g2e ("Requested SNI error or not a DNS name",
1035 GNUTLS_E_NO_CERTIFICATE_FOUND);
1040 for (atidx=128; atidx > 0; atidx--) {
1041 if (lid [atidx-1] == '@') {
1045 if (strncmp (sni, lid + atidx, sizeof (sni)-atidx) != 0) {
1046 tlog (TLOG_TLS, LOG_ERR, "SNI %s does not match preset local identity %s", sni, lid);
1047 E_g2e ("Requested SNI does not match local identity",
1048 GNUTLS_E_NO_CERTIFICATE_FOUND);
1052 // TODO: Should ask for permission before accepting SNI
1053 memcpy (lid, sni, sizeof (sni));
1058 // Setup the lidtype parameter for responding
1059 certtp = gnutls_certificate_type_get_peers (session);
1060 if (certtp == GNUTLS_CRT_OPENPGP) {
1061 tlog (TLOG_TLS, LOG_INFO, "Serving OpenPGP certificate request as a %s", rolestr);
1062 lidtype = LID_TYPE_PGP;
1063 } else if (certtp == GNUTLS_CRT_X509) {
1064 tlog (TLOG_TLS, LOG_INFO, "Serving X.509 certificate request as a %s", rolestr);
1065 lidtype = LID_TYPE_X509;
1067 } else if (certtp == GNUTLS_CRT_KRB) {
1068 tlog (TLOG_TLS, LOG_INFO, "Serving X.509 certificate request as a %s", rolestr);
1069 lidtype = LID_TYPE_KRB5;
1072 // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
1073 tlog (TLOG_TLS, LOG_ERR, "Funny sort of certificate retrieval attempted as a %s", rolestr);
1074 E_g2e ("Requested certtype is neither X.509 nor OpenPGP",
1075 GNUTLS_E_CERTIFICATE_ERROR);
1080 // Find the prefetched local identity to use towards this remote
1081 // Send a callback to the user if none is available and accessible
1082 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALID_CHECK) {
1083 uint32_t oldcmd = cmd->cmd.pio_cmd;
1084 struct command *resp;
1085 cmd->cmd.pio_cmd = PIOC_STARTTLS_LOCALID_V2;
1086 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Calling send_callback_and_await_response with PIOC_STARTTLS_LOCALID_V2");
1087 resp = send_callback_and_await_response (cmd, 0);
1088 assert (resp != NULL); // No timeout, should be non-NULL
1089 if (resp->cmd.pio_cmd != PIOC_STARTTLS_LOCALID_V2) {
1090 tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has unexpected command code");
1091 cmd->cmd.pio_cmd = oldcmd;
1092 return GNUTLS_E_CERTIFICATE_ERROR;
1094 assert (resp == cmd); // No ERROR, so should be the same
1095 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Processing callback response that sets plainfd:=%d and lid:=\"%s\" for rid==\"%s\"", cmd->passfd, lid, rid);
1096 cmd->cmd.pio_cmd = oldcmd;
1098 // Check that new rid is a generalisation of original rid
1099 // Note: This is only of interest for client operation
1100 if (lidrole == LID_ROLE_CLIENT) {
1101 selector_t newrid = donai_from_stable_string (rid, strlen (rid));
1102 donai_t oldrid = donai_from_stable_string (cmd->orig_starttls->remoteid, strlen (cmd->orig_starttls->remoteid));
1103 if (!donai_matches_selector (&oldrid, &newrid)) {
1104 return GNUTLS_E_NO_CERTIFICATE_FOUND;
1108 // Now reiterate to lookup lid credentials in db_localid
1109 E_g2e ("Missing local credentials",
1110 fetch_local_credentials (cmd));
1112 if (cmd->lids [lidtype - LID_TYPE_MIN].data == NULL) {
1113 fprintf (stderr, "DEBUG: Missing certificate for local ID %s and remote ID %s\n", lid, rid);
1114 E_g2e ("Missing certificate for local ID",
1115 GNUTLS_E_NO_CERTIFICATE_FOUND);
1120 // Split the credential into its various aspects
1121 ok = dbcred_interpret (
1122 &cmd->lids [lidtype - LID_TYPE_MIN],
1127 tlog (TLOG_DB, LOG_DEBUG, "BDB entry has flags=0x%08x, p11priv=\"%s\", cert.size=%d", flags, p11priv, certdatum.size);
1128 //TODO// ok = ok && verify_cert_... (...); -- keyidlookup
1130 gtls_errno = GNUTLS_E_CERTIFICATE_ERROR;
1134 // Allocate response structures
1136 *pcert = load_certificate_chain (flags, pcert_length, &certdatum);
1137 if (*pcert == NULL) {
1138 E_g2e ("Failed to load certificate chain",
1139 GNUTLS_E_CERTIFICATE_ERROR);
1142 cmd->session_certificate = (intptr_t) (void *) *pcert; //TODO// Used for session cleanup
1145 // Setup private key
1146 E_g2e ("Failed to initialise private key",
1147 gnutls_privkey_init (
1149 if ((onthefly_subjectkey != NULL) && (strcmp (p11priv, onthefly_p11uri) == 0)) {
1150 // Setup the on-the-fly certification key as private key
1151 E_g2e ("Failed to import on-the-fly subject private key",
1152 gnutls_privkey_import_x509 (
1154 onthefly_subjectkey,
1155 GNUTLS_PRIVKEY_IMPORT_COPY));
1157 } else if (lidtype == LID_TYPE_KRB5) {
1158 // Fake a private key for Kerberos (we sign it out here, not GnuTLS)
1159 E_g2e ("Failed to generate a private-key placeholder for Kerberos",
1160 gnutls_privkey_generate_krb (
1165 // Import the PKCS #11 key as the private key for use by GnuTLS
1166 if (gtls_errno == GNUTLS_E_SUCCESS) {
1167 cmd->session_privatekey = (intptr_t) (void *) *pkey; //TODO// Used for session cleanup
1169 E_g2e ("Failed to import PKCS #11 private key URI",
1170 gnutls_privkey_import_pkcs11_url (
1174 E_gnutls_clear_errno ();
1176 //TODO// Moved out (start)
1179 // Setup public key certificate
1182 E_g2e ("MOVED: Failed to import X.509 certificate into chain",
1183 gnutls_pcert_import_x509_raw (
1186 GNUTLS_X509_FMT_DER,
1190 E_g2e ("MOVED: Failed to import OpenPGP key",
1191 gnutls_pcert_import_openpgp_raw (
1194 GNUTLS_OPENPGP_FMT_RAW,
1195 NULL, /* use master key */
1200 if (lidrole == LID_ROLE_CLIENT) {
1201 // KDH-Only or KDH-Enhanced; fetch ticket for localid
1202 // and a TGT based on it for service/remoteid@REALM
1203 char *svc = cmd->cmd.pio_data.pioc_starttls.service;
1204 const gnutls_datum_t *server_tgt = NULL;
1205 // If the server provides a TGT, employ ENC-TKT-IN-SKEY
1206 if (gnutls_certificate_type_get_peers (cmd->session) == GNUTLS_CRT_KRB) {
1207 // Try to get the server's TGT; it returns NULL
1208 // if it wasn't found. We will not try this
1209 // unless we know what we'd find would be KRB.
1210 server_tgt = gnutls_certificate_get_peers (cmd->session, NULL);
1212 // The servicename may need mapping to another form
1213 if (strcmp (svc, "http")) {
1216 //TODO: Have a client ticket matching the found localid
1217 //TODO: From the client ticket, obtain a service ticket
1218 //TODO: Export the service ticket
1219 krb5_ccache mycache;
1220 krb5_creds prep_creds;
1221 krb5_creds *gotten_creds = NULL;
1222 char klid [128 + 1];
1223 char krid [128 + 1];
1224 krb5_data klidprincipal [1];
1225 krb5_data kridprincipal [2];
1229 // Fill the credentials request
1230 memset (&prep_creds, 0, sizeof (prep_creds));
1231 memcpy (klid, cmd->cmd.pio_data.pioc_starttls.localid, 128);
1232 memcpy (krid, cmd->cmd.pio_data.pioc_starttls.remoteid, 128);
1233 klid [128] = krid [128] = '\0';
1234 realmtmp = strrchr (klid, '@');
1235 if (realmtmp != NULL) {
1237 prep_creds.client->realm.data = realmtmp;
1238 prep_creds.client->realm.length = strlen (realmtmp);
1240 *realmtmp++ = toupper (*realmtmp);
1243 klidprincipal [0].data = klid;
1244 klidprincipal [0].length = strlen (klid);
1245 prep_creds.client->data = klidprincipal;
1246 prep_creds.client->length = 1;
1247 prep_creds.client->type = KRB5_NT_PRINCIPAL;
1248 realmtmp = strrchr (krid, '@');
1249 if (realmtmp != NULL) {
1251 prep_creds.server->realm.data = realmtmp;
1252 prep_creds.server->realm.length = strlen (realmtmp);
1254 *realmtmp++ = toupper (*realmtmp);
1257 kridprincipal [0].data = svc;
1258 kridprincipal [0].length = strnlen (svc, TLSPOOL_SERVICELEN);
1259 kridprincipal [1].data = krid;
1260 kridprincipal [1].length = strlen (krid);
1261 prep_creds.server->data = kridprincipal;
1262 prep_creds.server->length = 1;
1263 prep_creds.server->type = KRB5_NT_SRV_HST;
1264 // KDH-Only with server-side TGT
1265 //TODO// 1. setup flag KRB5_GC_USER_USER
1266 //TODO// 2. fill the .second_ticket value
1267 ok = ok && (0 == have_credcache (prep_creds.client, &mycache));
1268 ok = ok && (mycache != NULL);
1269 ok = ok && (0 == krb5_get_credentials (
1275 ok = ok && (gotten_creds != NULL);
1277 gtls_errno = GNUTLS_E_AUTH_ERROR;
1279 certdatum.data = gotten_creds->ticket.data;
1280 certdatum.size = gotten_creds->ticket.length;
1282 E_g2e ("MOVED: Failed to import Kerberos ticket",
1283 gnutls_pcert_import_krb_raw (
1287 if (gotten_creds != NULL) {
1288 krb5_free_creds (kerberos_context, gotten_creds);
1289 gotten_creds = NULL;
1292 // For KDH-Only, servers can send a TGT if they want to
1293 //TODO// E_g2e ("MOVED: Failed to import Kerberos ticket",
1294 //TODO// gnutls_pcert_import_krb_raw (
1296 //TODO// &certdatum, //TODO:WHATSFOUND//
1301 /* Should not happen */
1305 //TODO// Moved out (end)
1308 // Lap up any overseen POSIX error codes in errno
1310 tlog (TLOG_TLS, LOG_DEBUG, "Failing TLS on errno=%d / %s", errno, strerror (errno));
1311 cmd->session_errno = errno;
1312 gtls_errno = GNUTLS_E_NO_CIPHER_SUITES; /* Vaguely matching */
1316 // Return the overral error code, hopefully GNUTLS_E_SUCCESS
1317 tlog (TLOG_TLS, LOG_DEBUG, "Returning %d / %s from clisrv_cert_retrieve()", gtls_errno, gnutls_strerror (gtls_errno));
1318 printf ("DEBUG: clisrv_cert_retrieve() sets *pcert to 0x%xl (length %d)... {pubkey = 0x%lx, cert= {data = 0x%lx, size=%ld}, type=%ld}\n", (long) *pcert, *pcert_length, (long) (*pcert)->pubkey, (long) (*pcert)->cert.data, (long) (*pcert)->cert.size, (long) (*pcert)->type);
1322 /* Load a single certificate in the given gnutls_pcert_st from the given
1323 * gnutls_datum_t. Use the lidtype to determine how to do this.
1325 gtls_error load_certificate (int lidtype, gnutls_pcert_st *pcert, gnutls_datum_t *certdatum) {
1326 int gtls_errno = GNUTLS_E_SUCCESS;
1328 // Setup public key certificate
1331 fprintf (stderr, "DEBUG: About to import %d bytes worth of X.509 certificate into chain: %02x %02x %02x %02x...\n", certdatum->size, certdatum->data[0], certdatum->data[1], certdatum->data[2], certdatum->data[3]);
1332 E_g2e ("Failed to import X.509 certificate into chain",
1333 gnutls_pcert_import_x509_raw (
1336 GNUTLS_X509_FMT_DER,
1340 E_g2e ("Failed to import OpenPGP certificate",
1341 gnutls_pcert_import_openpgp_raw (
1344 GNUTLS_OPENPGP_FMT_RAW,
1345 NULL, /* use master key */
1349 /* Should not happen */
1356 /* Load a certificate chain. This returns a value for a retrieval function's
1357 * pcert, and also modifies the chainlen. The latter starts at 0, and is
1358 * incremented in a nested procedure that unrolls until all certificates are
1361 gnutls_pcert_st *load_certificate_chain (uint32_t flags, unsigned int *chainlen, gnutls_datum_t *certdatum) {
1362 gnutls_pcert_st *chain;
1363 unsigned int mypos = *chainlen;
1364 int gtls_errno = GNUTLS_E_SUCCESS;
1367 // Quick and easy: No chaining required, just add the literal data.
1368 // Note however, this may be the end of a chain, so allocate all
1369 // structures and load the single one at the end.
1370 if ((flags & (LID_CHAINED | LID_NEEDS_CHAIN)) == 0) {
1372 chain = (gnutls_pcert_st *) calloc (*chainlen, sizeof (gnutls_pcert_st));
1373 if (chain != NULL) {
1374 bzero (chain, (*chainlen) * sizeof (gnutls_pcert_st));
1376 gtls_errno = GNUTLS_E_MEMORY_ERROR;
1378 E_g2e ("Failed to load certificate into chain",
1380 flags & LID_TYPE_MASK,
1383 if (gtls_errno != GNUTLS_E_SUCCESS) {
1394 // First extended case. Chain certs in response to LID_CHAINED.
1395 // Recursive calls are depth-first, so we only add our first cert
1396 // after a recursive call succeeds. Any LID_NEEDS_CHAIN work is
1397 // added after LID_CHAINED, so is higher up in the hierarchy, but
1398 // it is loaded as part of the recursion. To support that, a
1399 // recursive call with certdatum.size==0 is possible when the
1400 // LID_NEEDS_CHAIN flag is set, and this section then skips.
1401 // Note that this code is also used to load the certificate chain
1402 // provided by LID_NEEDS_CHAIN, but by then the flag in a recursive
1403 // call is replaced with LID_CHAINED and no more LID_NEEDS_CHAIN.
1404 if (((flags & LID_CHAINED) != 0) && (certdatum->size > 0)) {
1407 gnutls_datum_t nextdatum;
1409 // Note: Accept BER because the outside SEQUENCE is not signed
1410 certlen = asn1_get_length_ber (
1411 ((char *) certdatum->data) + 1,
1414 certlen += 1 + lenlen;
1415 tlog (TLOG_CERT, LOG_DEBUG, "Found LID_CHAINED certificate size %d", certlen);
1416 if (certlen > certdatum->size) {
1417 tlog (TLOG_CERT, LOG_ERR, "Refusing LID_CHAINED certificate beyond data size %d", certdatum->size);
1420 } else if (certlen <= 0) {
1421 tlog (TLOG_CERT, LOG_ERR, "Refusing LID_CHAINED certificate of too-modest data size %d", certlen);
1425 nextdatum.data = ((char *) certdatum->data) + certlen;
1426 nextdatum.size = certdatum->size - certlen;
1427 certdatum->size = certlen;
1428 nextlen = asn1_get_length_ber (
1429 ((char *) nextdatum.data) + 1,
1432 nextlen += 1 + lenlen;
1433 if (nextlen == nextdatum.size) {
1434 // The last cert is loaded thinking it is not CHAINED,
1435 // but NEEDS_CHAIN can still be present for expansion.
1436 flags &= ~LID_CHAINED;
1439 chain = load_certificate_chain (flags, chainlen, &nextdatum);
1440 if (chain != NULL) {
1441 E_g2e ("Failed to add chained certificate",
1443 flags & LID_TYPE_MASK,
1446 if (gtls_errno != GNUTLS_E_SUCCESS) {
1456 // Second extended case. Chain certs in response to LID_NEEDS_CHAIN.
1457 // These are the highest-up in the hierarchy, above any LID_CHAINED
1458 // certificates. The procedure for adding them is looking them up
1459 // in a central database by their authority key identifier. What is
1460 // found is assumed to be a chain, and will be unrolled by replacing
1461 // the LID_NEEDS_CHAIN flag with LID_CHAINED and calling recursively.
1462 if (((flags & LID_NEEDS_CHAIN) != 0) && (certdatum->size == 0)) {
1463 //TODO//CODE// lookup new certdatum
1464 flags &= ~LID_NEEDS_CHAIN;
1465 flags |= LID_CHAINED;
1466 //TODO//CODE// recursive call
1467 //TODO//CODE// no structures to fill here
1468 //TODO//CODE// cleanup new certdatum
1472 // Final judgement. Nothing worked. Return failure.
1478 /* Iterate over a credential cache collection, looking for the one that
1479 * has the desired principal name and realm. If it does not exist yet,
1480 * create it. This works with collections such as DIR:/var/tlspool/creds
1481 * or, only on Linux, KEYRING:process:name to store creds in the kernel.
1482 * The function returns 0 when ok, or otherwise nonzero.
1485 static krb5_error_code have_credcache (krb5_principal sought, krb5_ccache *found) {
1486 krb5_cccol_cursor crs;
1488 krb5_principal princ;
1492 if (0 == krb5_cccol_cursor_new (kerberos_context, &crs)) {
1493 while (0 != krb5_cccol_cursor_next (kerberos_context, crs, &tmp)) {
1495 // No more ccache in directory
1498 if (0 != krb5_cc_get_principal (kerberos_context, tmp, &princ)) {
1501 hit = krb5_principal_compare (kerberos_context, princ, sought);
1502 krb5_free_principal (kerberos_context, princ);
1505 // Avoid cleaning up the context
1508 krb5_cc_close (kerberos_context, tmp);
1512 krb5_cccol_cursor_free (kerberos_context, &crs);
1515 // If need be, create a new credential cache
1516 if (NULL == *found) {
1517 //TODO// Param "type" set to "DIR" but that's pretty fixed.
1518 //TODO// Is "hint" really not interpreted?!?
1519 if (0 == krb5_cc_new_unique (kerberos_context, "DIR", NULL, &tmp)) {
1520 if (0 == krb5_cc_initialize (kerberos_context, tmp, sought)) {
1525 return (NULL != *found)? 0: KRB5_CC_NOTFOUND;
1530 /* valexp_valflag_set -- set a validation flag bit for an uppercase predicate.
1532 static void valexp_valflag_set (struct command *cmd, char pred) {
1533 int len = strlen (cmd->valflags);
1534 cmd->valflags [len++] = pred;
1535 cmd->valflags [len ] = '\0';
1538 /* valexp_valflag_start -- get a prior set bit with validation information.
1539 * Where cmd->valflags is a string of uppercase letters that were ensured.
1541 static void valexp_valflag_start (void *vcmd, struct valexp *ve, char pred) {
1542 struct command *cmd = (struct command *) vcmd;
1543 pred &= 0xdf; // lowercase->uppercase
1544 valexp_setpredicate (ve, pred, NULL != strchr (cmd->valflags, pred));
1547 /* valexp_0_start -- validation function for the GnuTLS backend.
1548 * This function immediately sends failure on something impossible.
1550 static void valexp_0_start (void *vcmd, struct valexp *ve, char pred) {
1551 valexp_setpredicate (ve, pred, 0);
1554 /* valexp_1_start -- validation function for the GnuTLS backend.
1555 * This function immediately sends success on something trivial.
1557 static void valexp_1_start (void *vcmd, struct valexp *ve, char pred) {
1558 valexp_setpredicate (ve, pred, 1);
1561 //TODO// valexp_L_start, valexp_l_start
1563 /* valexp_I_start -- validation function for the GnuTLS backend.
1564 * This function ensures that the remote peer provides an identity.
1565 * TODO: We should compare the hostname as well, or compare if in remoteid
1566 * TODO: We may need to support more than just X509/PGP certificates
1568 static void valexp_I_start (void *vcmd, struct valexp *ve, char pred) {
1569 struct command *cmd = (struct command *) vcmd;
1570 unsigned int num_certs = 0;
1571 // peer-returned "certs" points into GnuTLS' internal data structures
1572 valexp_setpredicate (ve, pred,
1573 (gnutls_certificate_get_peers (cmd->session, &num_certs) != NULL)
1574 && (num_certs > 0));
1577 /* valexp_i_start -- is opportunistic and will always succeed
1579 #define valexp_i_start valexp_1_start
1581 /* valexp_Ff_start -- validation function for the GnuTLS backend.
1582 * This functin ensures that forward secrecy is applied.
1583 * While _F_ only accepts DHE, _f_ will also accept DH.
1584 * Note: GnuTLS does not seem to show DH that is not also DHE.
1586 static void valexp_Ff_start (void *vcmd, struct valexp *ve, char pred) {
1587 struct command *cmd = (struct command *) vcmd;
1588 gnutls_kx_algorithm_t kx = gnutls_kx_get (cmd->session);
1590 case GNUTLS_KX_UNKNOWN:
1592 case GNUTLS_KX_RSA_EXPORT:
1595 valexp_setpredicate (ve, pred, 0);
1597 case GNUTLS_KX_DHE_DSS:
1598 case GNUTLS_KX_DHE_RSA:
1600 case GNUTLS_KX_SRP_RSA:
1601 case GNUTLS_KX_SRP_DSS:
1602 case GNUTLS_KX_DHE_PSK:
1603 case GNUTLS_KX_ECDHE_RSA:
1604 case GNUTLS_KX_ECDHE_ECDSA:
1605 case GNUTLS_KX_ECDHE_PSK:
1606 case GNUTLS_KX_ANON_ECDH: // Assume DHE is in fact implemented
1607 case GNUTLS_KX_ANON_DH: // Assume DHE is in fact implemented
1608 valexp_setpredicate (ve, pred, 1);
1610 // case GNUTLS_KX_xxx_DH:
1611 // valexp_setpredicate (ve, pred, pred != 'F');
1616 /* valexp_A_start -- validation function for the GnuTLS backend.
1617 * This function ensures that an anonymising precursor is used.
1619 #define valexp_A_start valexp_valflag_start
1621 /* valexp_a_start -- is opportunistic and will always succeed */
1622 #define valexp_a_start valexp_1_start
1624 /* valexp_Tt_start -- validation function for the GnuTLS backend.
1625 * This function ensures trust based on a trusted certificate/key list.
1626 * In the _t_ case, self-signed certificates are also accepted.
1628 static void valexp_Tt_start (void *vcmd, struct valexp *ve, char pred) {
1629 struct command *cmd = (struct command *) vcmd;
1631 gnutls_credentials_type_t authtp;
1632 const gnutls_datum_t *certs;
1633 unsigned int num_certs;
1634 if (cmd->vfystatus == 0) {
1637 authtp = gnutls_auth_get_type (cmd->session);
1638 if (authtp != GNUTLS_CRD_CERTIFICATE) {
1641 certs = gnutls_certificate_get_peers (cmd->session, &num_certs);
1642 // "certs" points into GnuTLS' internal data structures
1643 if (num_certs < 1) {
1646 if ((num_certs == 1) && (pred == 't')) {
1647 //TODO// if (self-signature-correct) {
1648 //TODO// flagval = 1;
1649 //TODO// goto setflagval;
1652 //TODO// Look in trust.db for H(cert[num_certs-1])
1653 //TODO// flagval = 1;
1655 valexp_setpredicate (ve, pred, flagval);
1658 /* valexp_Dd_start -- validation function for the GnuTLS backend.
1659 * This function validates through DNSSEC.
1660 * While _D_ enforces DNSSEC, _d_ also accepts opted-out security.
1662 static void valexp_Dd_start (void *vcmd, struct valexp *ve, char pred) {
1663 struct command *cmd = (struct command *) vcmd;
1666 unsigned int vfystat;
1670 struct sockaddr peername;
1671 socklen_t peernamesz = sizeof (peername);
1673 host = strchr (cmd->cmd.pio_data.pioc_starttls.remoteid, '@');
1675 host = cmd->cmd.pio_data.pioc_starttls.remoteid;
1677 switch (cmd->cmd.pio_data.pioc_starttls.ipproto) {
1690 sox = gnutls_transport_get_int (cmd->session);
1694 if (getpeername (sox, &peername, &peernamesz) != 0) {
1697 if ((peername.sa_family == AF_INET) &&
1698 (peernamesz == sizeof (struct sockaddr_in))) {
1699 port = ntohs (((struct sockaddr_in *) &peername)->sin_port);
1700 } else if ((peername.sa_family == AF_INET6) &&
1701 (peernamesz == sizeof (struct sockaddr_in6))) {
1703 port = ntohs (((struct sockaddr_in6 *) &peername)->sin6_port);
1706 if (dane_state_init (&stat, /*TODO:*/ 0) != GNUTLS_E_SUCCESS) {
1709 if (dane_verify_session_crt (stat,
1715 DANE_VFLAG_FAIL_IF_NOT_CHECKED,
1716 &vfystat) == DANE_E_SUCCESS) {
1717 if ((pred == 'D') && (vfystat & DANE_VERIFY_UNKNOWN_DANE_INFO)) {
1718 dane_state_deinit (stat);
1721 flagval = ((vfystat & ~DANE_VERIFY_UNKNOWN_DANE_INFO) == 0);
1723 dane_state_deinit (stat);
1725 valexp_setpredicate (ve, pred, flagval);
1728 /* valexp_Rr_start -- validation function for the GnuTLS backend.
1729 * This function validates through a CRL.
1730 * While _R_ requires the CRL to be present, _r_ accepts confirmed absense.
1731 * TODO: This is not implemented yet.
1733 static void valexp_Rr_start (void *vcmd, struct valexp *ve, char pred) {
1735 valexp_setpredicate (ve, pred, 0);
1738 /* valexp_Ee_start -- validation function for the GnuTLS backend.
1739 * This function validates certificate extensions for the named service.
1740 * While _E_ required OIDs to be marked critical, _e_ also accepts non-crit.
1742 static void valexp_Ee_start (void *vcmd, struct valexp *ve, char pred) {
1744 valexp_setpredicate (ve, pred, 0);
1747 /* valexp_Oo_start -- validation function for the GnuTLS backend.
1748 * This function validates with online/live information.
1749 * While _O_ required positive confirmation, _o_ also accepts unknown.
1750 * -> For X.509, look in OCSP
1751 * -> For OpenPGP, redirect O->G, o->g
1752 * -> For Kerberos, accept anything as sufficiently live / online
1754 static void valexp_Oo_start (void *vcmd, struct valexp *ve, char pred) {
1755 struct command *cmd = (struct command *) vcmd;
1759 gnutls_credentials_type_t authtp;
1760 gnutls_certificate_type_t certtp;
1761 online2success_t o2vf;
1763 const gnutls_datum_t *crt;
1764 unsigned int crtcount;
1765 authtp = gnutls_auth_get_type (cmd->session);
1766 if (authtp != GNUTLS_CRD_CERTIFICATE) {
1767 // No authentication types other than certificates yet
1770 if ((pred >= 'a') && (pred <= 'z')) {
1771 o2vf = online2success_optional;
1773 o2vf = online2success_enforced;
1775 certtp = gnutls_certificate_type_get (cmd->session);
1776 crt = gnutls_certificate_get_peers (cmd->session, &crtcount);
1777 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
1778 if (certtp == GNUTLS_CRT_OPENPGP) {
1779 valflag = o2vf (online_globaldir_pgp (
1780 rid, crt->data, crt->size));
1781 } else if (certtp == GNUTLS_CRT_X509) {
1782 //TODO// OCSP inquiry or globaldir
1783 valflag = o2vf (online_globaldir_x509 (
1784 rid, crt->data, crt->size));
1786 } else if (certtp == GNUTLS_CRT_KRB) {
1787 // Kerberos is sufficiently "live" to be pass O
1792 // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
1797 valexp_setpredicate (ve, pred, valflag);
1800 /* valexp_Gg_start -- validation function for the GnuTLS backend.
1801 * This function validates through the LDAP global directory.
1802 * While _G_ requires information to be present, _g_ also accepts absense.
1803 * -> For X.509, lookup userCertificate
1804 * -> For OpenPGP, lookup pgpKey
1805 * -> For KDH, lookup krbPrincipalName
1806 * -> For SRP, nothing is defined
1807 * -> For OpenSSH, no TLS support
1809 static void valexp_Gg_start (void *vcmd, struct valexp *ve, char pred) {
1810 struct command *cmd = (struct command *) vcmd;
1814 gnutls_credentials_type_t authtp;
1815 gnutls_certificate_type_t certtp;
1816 online2success_t o2vf;
1818 const gnutls_datum_t *crt;
1819 unsigned int crtcount;
1820 authtp = gnutls_auth_get_type (cmd->session);
1821 if (authtp != GNUTLS_CRD_CERTIFICATE) {
1822 // No authentication types other than certificates yet
1825 if ((pred >= 'a') && (pred <= 'z')) {
1826 o2vf = online2success_optional;
1828 o2vf = online2success_enforced;
1830 certtp = gnutls_certificate_type_get (cmd->session);
1831 crt = gnutls_certificate_get_peers (cmd->session, &crtcount);
1832 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
1833 if (certtp == GNUTLS_CRT_OPENPGP) {
1834 valflag = o2vf (online_globaldir_pgp (
1835 rid, crt->data, crt->size));
1836 } else if (certtp == GNUTLS_CRT_X509) {
1837 //TODO// OCSP inquiry or globaldir
1838 valflag = o2vf (online_globaldir_x509 (
1839 rid, crt->data, crt->size));
1841 } else if (certtp == GNUTLS_CRT_KRB) {
1843 //TODO// valflag = o2vf (online_globaldir_kerberos (
1844 //TODO// rid, crt->data, crt->size));
1847 // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
1852 valexp_setpredicate (ve, pred, valflag);
1855 /* valexp_Pp_start -- validation function for the GnuTLS backend.
1856 * This function validates through pinning information.
1857 * While _P_ requires pinning to be present, _p_ will Trust On First Use.
1859 static void valexp_Pp_start (void *vcmd, struct valexp *ve, char pred) {
1861 valexp_setpredicate (ve, pred, 0);
1864 /* valexp_U_start -- validation function for the GnuTLS backend.
1865 * This function validates a matching username.
1867 static void valexp_U_start (void *vcmd, struct valexp *ve, char pred) {
1869 valexp_setpredicate (ve, pred, 0);
1872 /* valexp_Ss_start -- validation function for the GnuTLS backend.
1873 * This function ensures that the local end is a server.
1874 * While _S_ denies credentials also usable for clients, _s_ permits them.
1876 static void valexp_Ss_start (void *vcmd, struct valexp *ve, char pred) {
1877 struct command *cmd = (struct command *) vcmd;
1879 if ((pred == 'S') && (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)) {
1882 flagval = (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) != 0;
1884 valexp_setpredicate (ve, pred, flagval);
1887 /* valexp_Cc_start -- validation function for the GnuTLS backend.
1888 * This function ensures that the local end is a client.
1889 * While _C_ denies credentials also usable for servers, _c_ permits them.
1891 static void valexp_Cc_start (void *vcmd, struct valexp *ve, char pred) {
1892 struct command *cmd = (struct command *) vcmd;
1894 if ((pred == 'C') && (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER)) {
1897 flagval = (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) != 0;
1899 valexp_setpredicate (ve, pred, flagval);
1904 /* Fetch local credentials. This can be done before TLS is started, to find
1905 * the possible authentication forms that can be offered. The function
1906 * can additionally be used after interaction with the client to establish
1907 * a local identity that was not initially provided, or that was not
1908 * considered public at the time.
1910 gtls_error fetch_local_credentials (struct command *cmd) {
1913 DBC *crs_disclose = NULL;
1914 DBC *crs_localid = NULL;
1918 selector_t remote_selector;
1922 gtls_error certificate_onthefly (struct command *cmd);
1925 // When applicable, try to create an on-the-fly certificate
1926 if (((cmd->cmd.pio_cmd == PIOC_STARTTLS_V2) &&
1927 (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALID_ONTHEFLY))
1928 || ((cmd->cmd.pio_cmd == PIOC_LIDENTRY_CALLBACK_V2) &&
1929 (cmd->cmd.pio_data.pioc_lidentry.flags & PIOF_LIDENTRY_ONTHEFLY))) {
1930 gtls_errno = certificate_onthefly (cmd);
1931 if (gtls_errno != GNUTLS_E_AGAIN) {
1932 // This includes GNUTLS_E_SUCCESS
1933 fprintf (stderr, "DEBUG: otfcert retrieval returned %d\n", gtls_errno);
1936 fprintf (stderr, "DEBUG: otfcert retrieval returned GNUTLS_E_AGAIN, so skip it\n", gtls_errno);
1937 gtls_errno = GNUTLS_E_SUCCESS; // Attempt failed, ignore
1942 // Setup a number of common references and structures
1943 // Note: Current GnuTLS cannot support being a peer
1944 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
1945 lidrole = LID_ROLE_CLIENT;
1946 } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
1947 lidrole = LID_ROLE_SERVER;
1949 E_g2e ("TLS Pool command supports neither local client nor local server role",
1950 GNUTLS_E_INVALID_SESSION);
1953 lid = cmd->cmd.pio_data.pioc_starttls.localid;
1954 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
1957 // Refuse to disclose client credentials when the server name is unset;
1958 // note that server-claimed identities are unproven during handshake.
1959 if ((lidrole == LID_ROLE_CLIENT) && (*rid == '\0')) {
1960 tlog (TLOG_USER, LOG_ERR, "No remote identity (server name) set, so no client credential disclosure");
1961 E_g2e ("Missing remote ID",
1962 GNUTLS_E_NO_CERTIFICATE_FOUND);
1966 // Setup database iterators to map identities to credentials
1967 if (lidrole == LID_ROLE_CLIENT) {
1968 E_d2e ("Failed to create db_disclose cursor",
1969 dbh_disclose->cursor (
1975 E_d2e ("Failed to create db_localid cursor",
1976 dbh_localid->cursor (
1982 // Prepare for iteration over possible local identities / credentials
1985 if (gtls_errno != 0) {
1987 } else if (lidrole == LID_ROLE_CLIENT) {
1988 memcpy (cid, rid, sizeof (cid));
1989 dbt_init_fixbuf (&discpatn, cid, strlen (cid));
1990 dbt_init_fixbuf (&keydata, mid, sizeof (mid)-1);
1991 dbt_init_malloc (&creddata);
1993 donai_t remote_donai = donai_from_stable_string (rid, strlen (rid));
1994 if (!selector_iterate_init (&remote_selector, &remote_donai)) {
1995 E_g2e ("Syntax of remote ID unsuitable for selector",
1996 GNUTLS_E_INVALID_REQUEST);
1998 E_d2e ("Failed to start iterator on remote ID selector",
1999 dbcred_iterate_from_remoteid_selector (
2008 dbt_init_fixbuf (&discpatn, "", 0); // Unused but good style
2009 dbt_init_fixbuf (&keydata, lid, strlen (lid));
2010 dbt_init_malloc (&creddata);
2011 E_d2e ("Failed to start iterator on local ID",
2012 dbcred_iterate_from_localid (
2017 if (db_errno != 0) {
2018 gtls_errno = GNUTLS_E_DB_ERROR;
2022 // Now store the local identities inasfar as they are usable
2024 while ((gtls_errno == GNUTLS_E_SUCCESS) && (db_errno == 0)) {
2029 tlog (TLOG_DB, LOG_DEBUG, "Found BDB entry %s disclosed to %s", creddata.data + 4, (lidrole == LID_ROLE_CLIENT)? rid: "all clients");
2033 lidtype = flags & LID_TYPE_MASK;
2034 ok = ok && ((flags & lidrole) != 0);
2035 ok = ok && ((flags & LID_NO_PKCS11) == 0);
2036 ok = ok && (lidtype >= LID_TYPE_MIN);
2037 ok = ok && (lidtype <= LID_TYPE_MAX);
2039 // For current/simple Kerberos, refuse data after PKCS #11 URI
2040 ok = ok && ((lidtype != LID_TYPE_KRB5) || (NULL == memchr (creddata.data + 4, '\0', creddata.size - 4 - 1)));
2042 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 ");
2044 // Move the credential into the command structure
2045 dbt_store (&creddata,
2046 &cmd->lids [lidtype - LID_TYPE_MIN]);
2049 // Skip the credential by freeing its data structure
2050 dbt_free (&creddata);
2052 db_errno = dbcred_iterate_next (crs_disclose, crs_localid, &discpatn, &keydata, &creddata);
2055 if (db_errno == DB_NOTFOUND) {
2057 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
2060 if (crs_localid != NULL) {
2061 crs_localid->close (crs_localid);
2064 if (crs_disclose != NULL) {
2065 crs_disclose->close (crs_disclose);
2066 crs_disclose = NULL;
2073 * Check if a given cmd has the given LID_TYPE setup.
2074 * Return 1 for yes or 0 for no; this is used in priority strings.
2076 static inline int lidtpsup (struct command *cmd, int lidtp) {
2077 return 1; //TODO// Can we decide if we needn't authenticate?
2078 return cmd->lids [lidtp - LID_TYPE_MIN].data != NULL;
2081 /* Configure the GnuTLS session with suitable credentials and priority string.
2082 * The anonpre_ok flag should be non-zero to permit Anonymous Precursor.
2084 * The credential setup is optional; when creds is NULL, no changes will
2087 static int configure_session (struct command *cmd,
2088 gnutls_session_t session,
2089 struct credinfo *creds,
2093 int gtls_errno = GNUTLS_E_SUCCESS;
2095 // Install the shared credentials for the client or server role
2096 if (creds != NULL) {
2097 gnutls_credentials_clear (session);
2098 for (i=0; i<credcount; i++) {
2099 E_g2e ("Failed to install credentials into TLS session",
2100 gnutls_credentials_set (
2107 // Setup the priority string for this session; this avoids future
2108 // credential callbacks that ask for something impossible or
2111 // Variation factors:
2112 // - starting configuration (can it be empty?)
2113 // - Configured security parameters (database? variable?)
2114 // - CTYPEs, SRP, ANON-or-not --> fill in as + or - characters
2115 if (gtls_errno == GNUTLS_E_SUCCESS) {
2117 snprintf (priostr, sizeof (priostr)-1,
2118 // "NORMAL:-RSA:" -- also ECDH-RSA, ECDHE-RSA, ...DSA...
2121 "%GNUTLS_ASYM_CERT_TYPES:"
2123 "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
2125 "+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
2127 "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:" //TODO//
2131 "%cCTYPE-CLI-KRB:%cCTYPE-SRV-X.509:",
2133 "%cSRP:%cSRP-RSA:%cSRP-DSS",
2134 anonpre_ok ?'+':'-',
2135 lidtpsup (cmd, LID_TYPE_X509) ?'+':'-',
2136 lidtpsup (cmd, LID_TYPE_PGP) ?'+':'-',
2138 lidtpsup (cmd, LID_TYPE_KRB5) ?'+':'-',
2139 lidtpsup (cmd, LID_TYPE_KRB5) ?'+':'-',
2141 //TODO// Temporarily patched out SRP
2142 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
2143 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
2144 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-');
2145 // strcpy (priostr, "NONE:+VERS-TLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL"); //TODO:TEST//
2146 // strcpy (priostr, "NONE:+VERS-TLS-ALL:+VERS-DTLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL"); //TODO:TEST//
2147 tlog (TLOG_TLS, LOG_DEBUG, "Constructed priority string %s for local ID %s",
2148 priostr, cmd->cmd.pio_data.pioc_starttls.localid);
2149 E_g2e ("Failed to set GnuTLS priority string",
2150 gnutls_priority_set_direct (
2156 // Return the application GNUTLS_E_ code including _SUCCESS
2160 /* The callback functions retrieve various bits of information for the client
2161 * or server in the course of the handshake procedure.
2163 * The logic here is based on client-sent information, such as:
2164 * - TLS hints -- X.509 or alternatives like OpenPGP, SRP, PSK
2165 * - TLS hints -- Server Name Indication
2166 * - User hints -- local and remote identities provided
2168 int srv_clienthello (gnutls_session_t session) {
2169 struct command *cmd;
2170 char sni [sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid)]; // static
2171 size_t snilen = sizeof (sni);
2173 int gtls_errno = GNUTLS_E_SUCCESS;
2176 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2178 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2180 // Setup a number of common references
2181 cmd = (struct command *) gnutls_session_get_ptr (session);
2183 return GNUTLS_E_INVALID_SESSION;
2185 lid = cmd->cmd.pio_data.pioc_starttls.localid;
2188 // Setup server-specific credentials and priority string
2189 //TODO// get anonpre value here
2190 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
2191 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2192 E_g2e ("Failed to reconfigure GnuTLS as a server",
2193 configure_session (cmd,
2195 srv_creds, srv_credcount,
2196 cmd->anonpre & ANONPRE_SERVER));
2197 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
2200 // Setup to ignore/request/require remote identity (from client)
2201 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2202 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_IGNORE_REMOTEID) {
2203 // Neither Request nor Require remoteid; ignore it
2205 } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REQUEST_REMOTEID) {
2206 // Use Request instead of Require for remoteid
2207 ( //RETURNS_VOID// E_g2e ("Failed to request remote identity",
2208 gnutls_certificate_server_set_request (
2210 GNUTLS_CERT_REQUEST));
2211 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
2213 // Require a remoteid from the client (default)
2214 ( //RETURNS_VOID// E_g2e ("Failed to require remote identity (the default)",
2215 gnutls_certificate_server_set_request (
2217 GNUTLS_CERT_REQUIRE));
2218 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
2222 // Find the client-helloed ServerNameIndication, or the service name
2223 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2225 if (gnutls_server_name_get (session, sni, &snilen, &snitype, 0) == 0) {
2226 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2228 case GNUTLS_NAME_DNS:
2230 // Note: In theory, other name types could be sent, and it would
2231 // be useful to access indexes beyond 0. In practice, nobody
2232 // uses other name types than exactly one GNUTLS_NAME_DNS.
2235 tlog (TLOG_TLS, LOG_ERR, "Received an unexpected SNI type; that is possible but uncommon; skipping SNI");
2236 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2240 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2241 if (sni [0] != '\0') {
2244 for (atidx=128; atidx > 0; atidx--) {
2245 if (lid [atidx-1] == '@') {
2249 if (strncmp (sni, lid + atidx, sizeof (sni)-atidx) != 0) {
2250 tlog (TLOG_USER | TLOG_TLS, LOG_ERR, "Mismatch between client-sent SNI %s and local identity %s", sni, lid);
2251 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2252 return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
2255 memcpy (lid, sni, sizeof (sni));
2256 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2259 memcpy (sni, lid, sizeof (sni)-1);
2260 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2261 sni [sizeof (sni) - 1] = '\0';
2263 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
2266 // Lap up any unnoticed POSIX error messages
2268 cmd->session_errno = errno;
2269 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
2270 gtls_errno = GNUTLS_E_NO_CIPHER_SUITES; /* Vaguely matching */
2271 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
2275 // Round off with an overal judgement
2276 fprintf (stderr, "DEBUG: Returning gtls_errno = %d or \"%s\" from srv_clihello()\n", gtls_errno, gnutls_strerror (gtls_errno));
2281 int cli_srpcreds_retrieve (gnutls_session_t session,
2285 tlog (TLOG_CRYPTO, LOG_DEBUG, "Picking up SRP credentials");
2286 *username = strdup ("tester");
2287 *password = strdup ("test");
2288 return GNUTLS_E_SUCCESS;
2292 /* Setup credentials to be shared by all clients and servers.
2293 * Credentials are generally implemented through callback functions.
2294 * This should be called after setting up DH parameters.
2296 int setup_starttls_credentials (void) {
2297 gnutls_anon_server_credentials_t srv_anoncred = NULL;
2298 gnutls_anon_client_credentials_t cli_anoncred = NULL;
2299 gnutls_certificate_credentials_t clisrv_certcred = NULL;
2300 //TODO:NOTHERE// int srpbits;
2301 gnutls_srp_server_credentials_t srv_srpcred = NULL;
2302 gnutls_srp_client_credentials_t cli_srpcred = NULL;
2303 //TODO// gnutls_kdh_server_credentials_t srv_kdhcred = NULL;
2304 //TODO// gnutls_kdh_server_credentials_t cli_kdhcred = NULL;
2305 int gtls_errno = GNUTLS_E_SUCCESS;
2306 int gtls_errno_stack0 = GNUTLS_E_SUCCESS;
2310 // Construct anonymous server credentials
2311 E_g2e ("Failed to allocate ANON-DH server credentials",
2312 gnutls_anon_allocate_server_credentials (
2314 if (!have_error_codes ()) /* E_g2e (...) */ gnutls_anon_set_server_dh_params (
2317 if (gtls_errno == GNUTLS_E_SUCCESS) {
2318 tlog (TLOG_CRYPTO, LOG_INFO, "Setting server anonymous credentials");
2319 srv_creds [srv_credcount].credtp = GNUTLS_CRD_ANON;
2320 srv_creds [srv_credcount].cred = (void *) srv_anoncred;
2322 } else if (srv_anoncred != NULL) {
2323 gnutls_anon_free_server_credentials (srv_anoncred);
2324 srv_anoncred = NULL;
2328 // Construct anonymous client credentials
2329 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
2330 E_g2e ("Failed to allocate ANON-DH client credentials",
2331 gnutls_anon_allocate_client_credentials (
2333 #ifdef MIRROR_IMAGE_OF_SERVER_ANONYMOUS_CREDENTIALS
2334 // NOTE: This is not done under TLS; server always provides DH params
2335 if (!have_error_codes ()) gnutls_anon_set_client_dh_params (
2339 if (gtls_errno == GNUTLS_E_SUCCESS) {
2340 tlog (TLOG_CRYPTO, LOG_INFO, "Setting client anonymous credentials");
2341 cli_creds [cli_credcount].credtp = GNUTLS_CRD_ANON;
2342 cli_creds [cli_credcount].cred = (void *) cli_anoncred;
2344 } else if (cli_anoncred != NULL) {
2345 gnutls_anon_free_client_credentials (cli_anoncred);
2346 cli_anoncred = NULL;
2350 // Construct certificate credentials for X.509 and OpenPGP cli/srv
2351 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
2352 E_g2e ("Failed to allocate certificate credentials",
2353 gnutls_certificate_allocate_credentials (
2355 //TODO// What to do here when we add locking on DH params?
2356 gnutls_certificate_set_dh_params (
2359 gtls_errno_stack0 = gtls_errno;
2360 /* TODO: Bad code. GnuTLS 3.2.1 ignores retrieve_function2 when
2361 * checking if it can handle the OpenPGP certificate type in
2362 * _gnutls_session_cert_type_supported (gnutls_status.c:175) but
2363 * it does see the "1" version field. It does not callback the
2364 * "1" version if "2" is present though.
2366 if (!have_error_codes ()) /* TODO:GnuTLSversions E_g2e (...) */ gnutls_certificate_set_retrieve_function (
2369 if (!have_error_codes ()) /* TODO:GnuTLSversions E_g2e (...) */ gnutls_certificate_set_retrieve_function2 (
2371 clisrv_cert_retrieve);
2372 if (gtls_errno == GNUTLS_E_SUCCESS) {
2373 // Setup for certificates
2374 tlog (TLOG_CERT, LOG_INFO, "Setting client and server certificate credentials");
2375 cli_creds [cli_credcount].credtp = GNUTLS_CRD_CERTIFICATE;
2376 cli_creds [cli_credcount].cred = (void *) clisrv_certcred;
2378 srv_creds [srv_credcount].credtp = GNUTLS_CRD_CERTIFICATE;
2379 srv_creds [srv_credcount].cred = (void *) clisrv_certcred;
2381 } else if (clisrv_certcred != NULL) {
2382 gnutls_certificate_free_credentials (clisrv_certcred);
2383 clisrv_certcred = NULL;
2387 // Construct server credentials for SRP authentication
2388 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
2389 E_g2e ("Failed to allocate SRP server credentials",
2390 gnutls_srp_allocate_server_credentials (
2392 E_g2e ("Failed to set SRP server credentials",
2393 gnutls_srp_set_server_credentials_file (
2395 "../testdata/tlspool-test-srp.passwd",
2396 "../testdata/tlspool-test-srp.conf"));
2397 if (gtls_errno == GNUTLS_E_SUCCESS) {
2398 tlog (TLOG_CRYPTO, LOG_INFO, "Setting server SRP credentials");
2399 srv_creds [srv_credcount].credtp = GNUTLS_CRD_SRP;
2400 srv_creds [srv_credcount].cred = (void *) srv_srpcred;
2402 } else if (srv_srpcred != NULL) {
2403 gnutls_srp_free_server_credentials (srv_srpcred);
2408 // Construct client credentials for SRP authentication
2409 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
2410 E_g2e ("Failed to allocate SRP client credentials",
2411 gnutls_srp_allocate_client_credentials (
2413 if (!have_error_codes ()) gnutls_srp_set_client_credentials_function (
2415 cli_srpcreds_retrieve);
2416 if (gtls_errno == GNUTLS_E_SUCCESS) {
2417 tlog (TLOG_CRYPTO, LOG_INFO, "Setting client SRP credentials");
2418 cli_creds [cli_credcount].credtp = GNUTLS_CRD_SRP;
2419 cli_creds [cli_credcount].cred = (void *) cli_srpcred;
2421 } else if (cli_srpcred != NULL) {
2422 gnutls_srp_free_client_credentials (cli_srpcred);
2427 // Construct credentials caching for Kerberos
2428 kerberos_context = NULL;
2429 //TODO:ALLOW_GLOBAL_CCACHE_LOOKUPS// kerberos_credcache = NULL;
2430 if (krb5_errno == 0) {
2431 krb5_errno = krb5_init_context (&kerberos_context);
2435 // Construct server credentials for KDH authentication
2436 //TODO// gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
2437 //TODO// E_g2e ("Failed to allocate KDH server credentials",
2438 //TODO// gnutls_kdh_allocate_server_credentials (
2439 //TODO// &srv_kdhcred));
2440 //TODO// E_g2e ("Failed to set KDH server DH params",
2441 //TODO// gnutls_kdh_set_server_dh_params (
2442 //TODO// srv_kdhcred,
2443 //TODO// dh_params));
2444 //TODO// if (gtls_errno == GNUTLS_E_SUCCESS) {
2445 //TODO// tlog (TLOG_CRYPTO, LOG_INFO, "Setting server KDH credentials");
2446 //TODO// srv_creds [srv_credcount].credtp = GNUTLS_CRD_KDH;
2447 //TODO// srv_creds [srv_credcount].cred = (void *) srv_kdhcred;
2448 //TODO// srv_credcount++;
2449 //TODO// } else if (srv_kdhcred != NULL) {
2450 //TODO// gnutls_kdh_free_server_credentials (srv_kdhcred);
2451 //TODO// srv_kdhcred = NULL;
2455 // Construct client credentials for KDH
2456 //TODO// gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
2457 //TODO// E_g2e ("Failed to allocate KDH client credentials",
2458 //TODO// gnutls_kdh_allocate_client_credentials (
2459 //TODO// &cli_kdhcred));
2460 //TODO// E_g2e ("Failed to set KDH client credentials",
2461 //TODO// gnutls_kdh_set_client_credentials_function (
2462 //TODO// cli_kdhcred,
2463 //TODO// cli_kdh_retrieve));
2464 //TODO// if (gtls_errno == GNUTLS_E_SUCCESS) {
2465 //TODO// tlog (TLOG_CRYPTO, LOG_INFO, "Setting client KDH credentials");
2466 //TODO// cli_creds [cli_credcount].credtp = GNUTLS_CRD_KDH;
2467 //TODO// cli_creds [cli_credcount].cred = (void *) cli_kdhcred;
2468 //TODO// cli_credcount++;
2469 //TODO// } else if (cli_kdhcred != NULL) {
2470 //TODO// gnutls_kdh_free_client_credentials (cli_kdhcred);
2471 //TODO// cli_kdhcred = NULL;
2475 // Ensure that at least one credential has been set
2476 // TODO: Look at the counters; but at boot, we can require all okay
2477 if ((gtls_errno == GNUTLS_E_SUCCESS) &&
2478 ( (cli_credcount != EXPECTED_CLI_CREDCOUNT) ||
2479 (srv_credcount != EXPECTED_SRV_CREDCOUNT) ) ) {
2480 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);
2481 E_g2e ("Not all credentials could be setup",
2482 GNUTLS_E_INSUFFICIENT_CREDENTIALS);
2486 // Report overall error or success
2491 /* Cleanup all credentials created, just before exiting the daemon.
2493 void cleanup_starttls_credentials (void) {
2494 while (srv_credcount-- > 0) {
2495 struct credinfo *crd = &srv_creds [srv_credcount];
2496 switch (crd->credtp) {
2497 case GNUTLS_CRD_CERTIFICATE:
2498 // Shared with client; skipped in server and removed in client
2499 // gnutls_certificate_free_credentials (crd->cred);
2501 case GNUTLS_CRD_ANON:
2502 gnutls_anon_free_server_credentials (crd->cred);
2504 case GNUTLS_CRD_SRP:
2505 gnutls_srp_free_server_credentials (crd->cred);
2507 //TODO// case GNUTLS_CRD_KDH:
2508 //TODO// gnutls_kdh_free_server_credentials (crd->cred);
2512 while (cli_credcount-- > 0) {
2513 struct credinfo *crd = &cli_creds [cli_credcount];
2514 switch (crd->credtp) {
2515 case GNUTLS_CRD_CERTIFICATE:
2516 // Shared with client; skipped in server and removed in client
2517 gnutls_certificate_free_credentials (crd->cred);
2519 case GNUTLS_CRD_ANON:
2520 gnutls_anon_free_client_credentials (crd->cred);
2522 case GNUTLS_CRD_SRP:
2523 gnutls_srp_free_client_credentials (crd->cred);
2525 //TODO// case GNUTLS_CRD_KDH:
2526 //TODO// gnutls_kdh_free_client_credentials (crd->cred);
2534 * The starttls_thread is a main program for the setup of a TLS connection,
2535 * either in client mode or server mode. Note that the distinction between
2536 * client and server mode is only a TLS concern, but not of interest to the
2537 * application or the records exchanged.
2539 * If the STARTTLS operation succeeds, this will be reported back to the
2540 * application, but the TLS pool will continue to be active in a copycat
2541 * procedure: encrypting outgoing traffic and decrypting incoming traffic.
2543 * A new handshake may be initiated with a STARTTLS command with the special
2544 * flag PIOF_STARTTLS_RENEGOTIATE and the ctlkey set to a previously setup
2545 * TLS connection. This command runs in a new thread, that cancels the old
2546 * one (which it can only do while it is waiting in copycat) and then join
2547 * that thread (and its data) with the current one. This is based on the
2548 * ctlkey, which serves to lookup the old thread's data. When the
2549 * connection ends for other reasons than a permitted cancel by another
2550 * thread, will the thread cleanup its own resources. In these situations,
2551 * the new command determines the negotiation parameters, and returns identity
2554 * In addition, the remote side may initiate renegotiation. This is accepted
2555 * without further ado (although future versions of the TLS Pool may add a
2556 * callback mechanism to get it approved). The renegotiation now runs under
2557 * the originally supplied negotiation parameters. In case it needs a new
2558 * local identity, it may also perform callbacks. Possibly repeating what
2559 * happened before -- but most often, a server will start processing a
2560 * protocol and determine that it requires more for the requested level of
2561 * service, and then renegotiate. This is common, for example, with HTTPS
2562 * connections that decide they need a client certificate for certain URLs.
2563 * The implementation of this facility is currently as unstructured as the
2564 * facility itself, namely through a goto. We may come to the conclusion
2565 * that a loop is in fact a warranted alternative, but we're not yet
2566 * convinced that this would match with other "structures" in TLS.
2568 * In conclusion, there are three possible ways of running this code:
2569 * 1. For a new connection. Many variables are not known and build up
2570 * in the course of running the function.
2571 * 2. After a command requesting renegotiation. This overtakes the prior
2572 * connection's thread, and copies its data from the ctlkeynode_tls.
2573 * The resulting code has a number of variables filled in already at
2575 * 3. After a remote request for renegotiation. This loops back to an
2576 * earlier phase, but after the thread takeover and ctlkeynode_tls copy
2577 * of the explicit command for renegotation. Its behaviour is subtly
2578 * different in that it has no command to act on, and so it cannot
2579 * send responses or error codes. It will however log and shutdown
2580 * as the command-driven options would. It will not perform callbacks
2581 * for PIOC_STARTTLS_LOCALID_V2 or PIOC_PLAINTEXT_CONNECT_V2. It will
2582 * however trigger the PIOC_LIDENTRY_CALLBACK_V2 through the separate
2583 * callback command, if one is registered.
2584 * Yeah, it's great fun, coding TLS and keeping it both flexible and secure.
2586 static void *starttls_thread (void *cmd_void) {
2587 struct command *cmd, *replycmd;
2588 struct command cmd_copy; // for relooping during renegotiation
2589 struct pioc_starttls orig_starttls;
2590 uint32_t orig_cmdcode;
2593 gnutls_session_t session;
2594 int got_session = 0;
2595 int gtls_errno = GNUTLS_E_SUCCESS;
2597 struct ctlkeynode_tls *ckn = NULL;
2600 int want_remoteid = 1;
2601 int got_remoteid = 0;
2602 int renegotiating = 0;
2603 char *preauth = NULL;
2604 unsigned int preauthlen = 0;
2605 int taking_over = 0;
2606 int my_maxpreauth = 0;
2610 // Block thread cancellation -- and re-enable it in copycat()
2611 assert (pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL) == 0);
2614 // General thread setup
2615 replycmd = cmd = (struct command *) cmd_void;
2617 send_error (replycmd, EINVAL, "Command structure not received");
2618 assert (pthread_detach (pthread_self ()) == 0);
2621 *cmd->valflags = '\0';
2622 cmd->session_errno = 0;
2624 orig_cmdcode = cmd->cmd.pio_cmd;
2625 memcpy (&orig_starttls, &cmd->cmd.pio_data.pioc_starttls, sizeof (orig_starttls));
2626 cmd->orig_starttls = &orig_starttls;
2627 cryptfd = cmd->passfd;
2629 //TODO:TEST Removed here because it is tested below
2632 tlog (TLOG_UNIXSOCK, LOG_ERR, "No ciphertext file descriptor supplied to TLS Pool");
2633 send_error (replycmd, EINVAL, "No ciphertext file descriptor supplied to TLS Pool");
2634 assert (pthread_detach (pthread_self ()) == 0);
2638 cmd->session_certificate = (intptr_t) (void *) NULL;
2639 cmd->session_privatekey = (intptr_t) (void *) NULL;
2642 // In case of renegotiation, lookup the previous ctlkeynode by its
2643 // ctlkey. The fact that we have ckn != NULL indicates that we are
2644 // renegotiating in the code below; it will supply information as
2645 // we continue to run the TLS process.
2646 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_RENEGOTIATE) {
2647 fprintf (stderr, "DEBUG: Got a request to renegotiate existing TLS connection\n");
2649 // Check that no FD was passed (and ended up in cryptfd)
2651 tlog (TLOG_UNIXSOCK, LOG_ERR, "Renegotiation started with extraneous file descriptor");
2652 send_error (replycmd, EPROTO, "File handle supplied for renegotiation");
2654 assert (pthread_detach (pthread_self ()) == 0);
2658 // First find the ctlkeynode_tls
2659 ckn = (struct ctlkeynode_tls *) ctlkey_find (cmd->cmd.pio_data.pioc_starttls.ctlkey, security_tls, cmd->clientfd);
2660 fprintf (stderr, "DEBUG: Got ckn == 0x%0x\n", (intptr_t) ckn);
2662 tlog (TLOG_UNIXSOCK, LOG_ERR, "Failed to find TLS connection for renegotiation by its ctlkey");
2663 send_error (replycmd, ESRCH, "Cannot find TLS connection for renegotiation");
2664 assert (pthread_detach (pthread_self ()) == 0);
2668 // Now cancel the pthread for this process
2669 errno = pthread_cancel (ckn->owner);
2670 fprintf (stderr, "DEBUG: pthread_cancel returned %d\n", errno);
2673 errno = pthread_join (ckn->owner, &retval);
2674 fprintf (stderr, "DEBUG: pthread_join returned %d\n", errno);
2677 tlog (TLOG_UNIXSOCK, LOG_ERR, "Failed to interrupt TLS connection for renegotiation");
2678 send_error (replycmd, errno, "Cannot interrupt TLS connection for renegotiation");
2679 ctlkey_unfind (&ckn->regent);
2680 assert (pthread_detach (pthread_self ()) == 0);
2681 // Do not free the ckn, as the other thread still runs
2685 // We are in control! Assimilate the TLS connection data.
2687 plainfd = ckn->plainfd;
2688 cryptfd = ckn->cryptfd;
2689 session = ckn->session;
2692 ctlkey_unfind (&ckn->regent);
2695 // Then follows the unstructured entry point for the unstructured
2696 // request to a TLS connection to renegotiate its security parameters.
2697 // Doing this in any other way than with goto would add a lot of
2698 // make-belief structure that only existed to make this looping
2699 // possible. We'd rather be honest and admit the lack of structure
2700 // that TLS has in this respect. Maybe we'll capture it one giant loop
2701 // at some point, but for now that does not seem to add any relief.
2703 printf ("DEBUG: Renegotiating = %d, anonpost = %d, plainfd = %d, cryptfd = %d, flags = 0x%x, session = 0x%x, got_session = %d, lid = \"%s\", rid = \"%s\"\n", renegotiating, anonpost, plainfd, cryptfd, cmd->cmd.pio_data.pioc_starttls.flags, session, got_session, cmd->cmd.pio_data.pioc_starttls.localid, cmd->cmd.pio_data.pioc_starttls.remoteid);
2706 // If this is server renegotiating, send a request to that end
2707 //TODO// Only invoke gnutls_rehandshake() on the server
2708 if (renegotiating && (taking_over || anonpost) && (gtls_errno == GNUTLS_E_SUCCESS)) {
2709 printf ("DEBUG: Invoking gnutls_rehandshake in renegotiation loop\n");
2710 gtls_errno = gnutls_rehandshake (session);
2711 if (gtls_errno == GNUTLS_E_INVALID_REQUEST) {
2712 // Clients should not do this; be forgiving
2713 gtls_errno = GNUTLS_E_SUCCESS;
2714 printf ("DEBUG: Client-side invocation flagged as wrong; compensated error\n");
2719 // When renegotiating TLS security, ensure that it is done securely
2720 if (renegotiating && (gnutls_safe_renegotiation_status (session) == 0)) {
2721 send_error (replycmd, EPROTO, "Renegotiation requested while secure renegotiation is unavailable on remote");
2731 if (ctlkey_unregister (ckn->regent.ctlkey)) {
2736 assert (pthread_detach (pthread_self ()) == 0);
2741 // Potentially decouple the controlling fd (ctlkey is in orig_starttls)
2742 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_FORK) {
2743 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_FORK;
2748 // Setup BDB transactions and reset credential datum fields
2750 bzero (&cmd->lids, sizeof (cmd->lids));
2751 manage_txn_begin (&cmd->txn);
2755 // Permit cancellation of this thread -- TODO: Cleanup?
2756 //TODO:TEST// Defer setcancelstate untill copycat() activity
2758 errno = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
2760 send_error (replycmd, ESRCH, "STARTTLS handler thread cancellability refused");
2770 if (ctlkey_unregister (ckn->regent.ctlkey)) {
2775 manage_txn_rollback (&cmd->txn);
2776 assert (pthread_detach (pthread_self ()) == 0);
2781 // Check and setup the plaintext file handle
2783 send_error (replycmd, EPROTO, "You must supply a TLS-protected socket");
2788 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
2789 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
2790 if (ctlkey_unregister (ckn->regent.ctlkey)) {
2795 manage_txn_rollback (&cmd->txn);
2796 assert (pthread_detach (pthread_self ()) == 0);
2801 // Decide on support for the Anonymous Precursor, based on the
2802 // service name and its appearance in the anonpre_registry.
2803 // If the remoteid is not interesting to the client then also
2804 // support an Anonymous Precursor; we have nothing to loose.
2805 cmd->anonpre &= ~ANONPRE_EITHER;
2806 if (renegotiating) {
2807 ; // Indeed, during renegotiation we always disable ANON-DH
2808 } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_IGNORE_REMOTEID) {
2809 cmd->anonpre = ANONPRE_EITHER;
2812 int anonpre_regidx = anonpre_registry_size >> 1;
2813 int anonpre_regjmp = (anonpre_registry_size + 1) >> 1;
2815 while (anonpre_regjmp > 0) {
2816 anonpre_regjmp = anonpre_regjmp >> 1;
2817 cmp = strncasecmp (anonpre_registry [anonpre_regidx].service,
2818 cmd->cmd.pio_data.pioc_starttls.service,
2819 TLSPOOL_SERVICELEN);
2820 printf ("DEBUG: anonpre_determination, comparing [%d] %s to %s, found cmp==%d\n", anonpre_regidx, anonpre_registry [anonpre_regidx].service, cmd->cmd.pio_data.pioc_starttls.service, cmp);
2822 // anonpre_regent matches
2823 cmd->anonpre = anonpre_registry [anonpre_regidx].flags;
2825 } else if (cmp > 0) {
2826 // anonpre_regent too high
2827 anonpre_regidx -= 1 + anonpre_regjmp;
2828 if (anonpre_regidx < 0) {
2832 // anonpre_regent too low
2833 anonpre_regidx += 1 + anonpre_regjmp;
2834 if (anonpre_regidx >= anonpre_registry_size) {
2835 anonpre_regidx = anonpre_registry_size - 1;
2842 // Setup flags for client and/or server roles (make sure there is one)
2843 if ((!renegotiating) && ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REMOTEROLE_CLIENT) == 0)) {
2844 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_LOCALROLE_SERVER;
2846 if ((!renegotiating) && ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REMOTEROLE_SERVER) == 0)) {
2847 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_LOCALROLE_CLIENT;
2849 if ((cmd->cmd.pio_data.pioc_starttls.flags & (PIOF_STARTTLS_LOCALROLE_CLIENT | PIOF_STARTTLS_LOCALROLE_SERVER)) == 0) {
2851 // Neither a TLS client nor a TLS server
2853 send_error (replycmd, ENOTSUP, "Command not supported");
2859 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
2860 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
2861 if (ctlkey_unregister (ckn->regent.ctlkey)) {
2866 manage_txn_rollback (&cmd->txn);
2867 assert (pthread_detach (pthread_self ()) == 0);
2872 // Setup the TLS session. Also see doc/p2p-tls.*
2874 // TODO: GnuTLS cannot yet setup p2p connections
2876 gnutls_session_set_ptr (
2879 //TODO:DONE?// Clear various settings... creds, flags, modes? CLI/SRV?
2881 E_g2e ("Failed to initialise GnuTLS peer session",
2884 (((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)? GNUTLS_CLIENT: 0) |
2885 ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER)? GNUTLS_SERVER: 0))
2887 if (gtls_errno == GNUTLS_E_SUCCESS) {
2889 gnutls_session_set_ptr (
2894 cmd->session = session;
2896 // Setup client-specific behaviour if needed
2897 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
2898 if (!renegotiating) { //TODO:TEST//
2900 // Setup as a TLS client
2904 // Require a minimum security level for SRP
2906 //TODO:CRASH// if (gtls_errno == GNUTLS_E_SUCCESS) gnutls_srp_set_prime_bits (
2907 //TODO:CRASH// session,
2908 //TODO:CRASH// srpbits);
2910 // Setup as a TLS client
2912 // Setup for potential sending of SNI
2913 if ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_WITHOUT_SNI) == 0) {
2914 char *str = cmd->cmd.pio_data.pioc_starttls.remoteid;
2917 while (str [len] && (len < 128)) {
2918 if (str [len] == '@') {
2923 // If no usable remoteid was setup, ignore it
2924 if ((len + ofs > 0) && (len < 128)) {
2925 cmd->cmd.pio_data.pioc_starttls.remoteid [sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid)-1] = '\0';
2926 E_g2e ("Client failed to setup SNI",
2927 gnutls_server_name_set (
2936 // Setup for client credential installation in this session
2938 // Setup client-specific credentials and priority string
2939 printf ("DEBUG: Configuring client credentials\n");
2940 E_g2e ("Failed to configure GnuTLS as a client",
2941 configure_session (cmd,
2943 anonpost? NULL: cli_creds,
2944 anonpost? 0: cli_credcount,
2945 cmd->anonpre & ANONPRE_CLIENT));
2948 // Setup callback to server-specific behaviour if needed
2949 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
2950 printf ("DEBUG: Configuring for server credentials callback if %d==0\n", gtls_errno);
2951 if (!renegotiating) { //TODO:TEST//
2952 if (gtls_errno == GNUTLS_E_SUCCESS) {
2953 gnutls_handshake_set_post_client_hello_function (
2958 //TODO:TEST// configure_session _if_ not setup as a client (too)
2960 // Setup for server credential installation in this session
2962 // Setup server-specific credentials and priority string
2964 if (! (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)) {
2965 printf ("DEBUG: Configuring server credentials (because it is not a client)\n");
2966 E_g2e ("Failed to configure GnuTLS as a server",
2967 configure_session (cmd,
2969 anonpost? NULL: srv_creds,
2970 anonpost? 0: srv_credcount,
2971 cmd->anonpre & ANONPRE_SERVER));
2977 // Prefetch local identities that might be used in this session
2979 E_g2e ("Failed to fetch local credentials",
2980 fetch_local_credentials (cmd));
2984 // Setup a temporary priority string so handshaking can start
2985 if ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) == 0) {
2986 E_g2e ("Failed to preconfigure server token priority string",
2987 gnutls_priority_set (
2993 // Check if past code stored an error code through POSIX
2994 if (cmd->session_errno) {
2995 gtls_errno = GNUTLS_E_USER_ERROR;
2999 // Setup a timeout value as specified in the command, where TLS Pool
3000 // defines 0 as default and ~0 as infinite (GnuTLS has 0 as infinite).
3001 tout = cmd->cmd.pio_data.pioc_starttls.timeout;
3002 if (renegotiating) {
3003 ; // Do not set timeout
3005 if (tout == TLSPOOL_TIMEOUT_DEFAULT) {
3006 gnutls_handshake_set_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
3007 } else if (tout == TLSPOOL_TIMEOUT_INFINITE) {
3008 gnutls_handshake_set_timeout (session, 0);
3010 gnutls_handshake_set_timeout (session, tout);
3014 // Now setup for the GnuTLS handshake
3016 if (renegotiating) {
3017 ; // Do not setup cryptfd
3019 if (gtls_errno == GNUTLS_E_SUCCESS) {
3020 gnutls_transport_set_int (session, cryptfd);
3022 if (gtls_errno != GNUTLS_E_SUCCESS) {
3023 tlog (TLOG_TLS, LOG_ERR, "Failed to prepare for TLS: %s", gnutls_strerror (gtls_errno));
3024 if (cmd->session_errno) {
3025 send_error (replycmd, cmd->session_errno, error_getstring ());
3027 send_error (replycmd, EIO, "Failed to prepare for TLS");
3030 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
3031 gnutls_deinit (session);
3039 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
3040 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
3041 if (ctlkey_unregister (ckn->regent.ctlkey)) {
3046 manage_txn_rollback (&cmd->txn);
3047 assert (pthread_detach (pthread_self ()) == 0);
3050 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_DEBUG, "TLS handshake started over %d", cryptfd);
3053 // Take a rehandshaking step forward.
3055 gtls_errno = gnutls_handshake (session);
3057 // When data is sent before completing
3058 // the rehandshake, then it's something
3059 // harmless, given the criteria for the
3060 // anonpre_registry. We pass it on and
3061 // don't worry about it. We do report
3064 // Note: Applications should be willing
3065 // to buffer or process such early data
3066 // before the handshake is over or else
3067 // the handshake will bail out in error.
3069 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
3070 if (my_maxpreauth <= 0) {
3071 tlog (TLOG_COPYCAT, LOG_ERR, "Received unwanted early data before authentication is complete");
3072 break; // Terminate the handshake
3073 } else if (preauth == NULL) {
3074 preauth = malloc (my_maxpreauth);
3075 if (preauth == NULL) {
3076 gtls_errno = GNUTLS_E_MEMORY_ERROR;
3077 break; // Terminate the handshake
3081 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
3082 if (preauthlen >= my_maxpreauth) {
3083 tlog (TLOG_COPYCAT, LOG_ERR, "Received more early data than willing to receive (%d bytes)", my_maxpreauth);
3084 break; // Terminate the handshake
3087 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
3089 sz = gnutls_record_recv (session, preauth + preauthlen, my_maxpreauth - preauthlen);
3090 tlog (TLOG_COPYCAT, LOG_DEBUG, "Received %d remote bytes (or error if <0) from %d during anonymous precursor\n", (int) sz, cryptfd);
3093 gtls_errno = GNUTLS_E_SUCCESS;
3095 gtls_errno = sz; // It's actually an error code
3098 } while ((gtls_errno < 0) &&
3099 //DROPPED// (gtls_errno != GNUTLS_E_GOT_APPLICATION_DATA) &&
3100 //DROPPED// (gtls_errno != GNUTLS_E_WARNING_ALERT_RECEIVED) &&
3101 (gnutls_error_is_fatal (gtls_errno) == 0));
3102 if (gtls_errno == 0) {
3103 const gnutls_datum_t *certs;
3104 unsigned int num_certs;
3106 switch (gnutls_auth_get_type (session)) { // Peer's cred type
3107 case GNUTLS_CRD_CERTIFICATE:
3108 certs = gnutls_certificate_get_peers (session, &num_certs);
3109 if ((certs != NULL) && (num_certs >= 1)) {
3112 // "certs" points into GnuTLS' internal data structures
3113 E_g2e ("Failed to validate peer",
3114 gnutls_certificate_verify_peers2 (
3118 case GNUTLS_CRD_PSK:
3119 // Difficult... what did the history say about this?
3121 cmd->vfystatus = GNUTLS_CERT_SIGNER_NOT_FOUND;
3123 case GNUTLS_CRD_SRP:
3124 // Got a credential, validation follows later on
3125 //TODO// SRP does not really auth the server
3127 cmd->vfystatus = GNUTLS_CERT_SIGNER_NOT_FOUND;
3129 case GNUTLS_CRD_ANON:
3130 // Did not get a credential, perhaps due to anonpre
3132 cmd->vfystatus = GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNATURE_FAILURE;
3135 // Inner Application extension is no true credential
3136 // Should we compare the client-requested service?
3137 // Should we renegotiate into the ALPN protocol?
3139 cmd->vfystatus = GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNATURE_FAILURE;
3142 // Unknown creds cautiously considered unauthentitcated
3144 cmd->vfystatus = ~ (unsigned short) 0; // It's all bad
3148 // Now recognise and handle the Anonymous Precursor
3149 if (((cmd->anonpre & ANONPRE_EITHER) != 0)
3150 && want_remoteid && !got_remoteid) {
3151 assert (anonpost == 0);
3152 valexp_valflag_set (cmd, 'A');
3153 // Disable ANON-protocols but keep creds from before
3154 //TODO:ELSEWHERE// tlog (TLOG_TLS, LOG_DEBUG, "Reconfiguring TLS over %d without Anonymous Precursor\n", cryptfd);
3155 //TODO:ELSEWHERE// E_g2e ("Failed to reconfigure GnuTLS without anonymous precursor",
3156 //TODO:ELSEWHERE// configure_session (cmd,
3157 //TODO:ELSEWHERE// session,
3158 //TODO:ELSEWHERE// NULL, 0,
3159 //TODO:ELSEWHERE// 0));
3160 // We do not want to use ANON-DH if the flag
3161 // ANONPRE_EXTEND_MASTER_SECRET is set for the protocol
3162 // but the remote peer does not support it. Only if
3163 // this problem cannot possibly occur, permit
3164 // my_maxpreauth > 0 for early data acceptance.
3166 if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
3167 #if GNUTLS_VERSION_NUMBER >= 0x030400
3168 gnutls_ext_priv_data_t ext;
3169 if (!gnutls_ext_get_data (session, 23, &ext)) {
3170 my_maxpreauth = maxpreauth;
3174 my_maxpreauth = maxpreauth;
3176 if (gtls_errno == 0) {
3177 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_DEBUG, "TLS handshake continued over %d after anonymous precursor", cryptfd);
3178 renegotiating = 1; // (de)selects steps
3179 anonpost = 1; // (de)selects steps
3184 if ((gtls_errno == GNUTLS_E_SUCCESS) && cmd->session_errno) {
3185 gtls_errno = GNUTLS_E_USER_ERROR;
3190 // Cleanup any prefetched identities
3191 for (i=LID_TYPE_MIN; i<=LID_TYPE_MAX; i++) {
3192 if (cmd->lids [i - LID_TYPE_MIN].data != NULL) {
3193 free (cmd->lids [i - LID_TYPE_MIN].data);
3196 bzero (cmd->lids, sizeof (cmd->lids));
3199 /* This is not proper. gnutls_certificate_set_key() suggests that these are
3200 * automatically cleaned up, and although this is not repeated in
3201 * gnutls_certificate_set_retrieve_function2() it is likely to be related.
3202 * Plus, renegotiation with this code in place bogged down on failed pcerts;
3203 * they were detected in _gnutls_selected_cert_supported_kx() but their
3204 * key exchange algorithm was never found.
3206 if (NULL != (void *) cmd->session_privatekey) {
3207 gnutls_privkey_deinit ((void *) cmd->session_privatekey);
3208 cmd->session_privatekey = (intptr_t) (void *) NULL;
3210 if (NULL != (void *) cmd->session_certificate) {
3211 gnutls_pcert_deinit ((void *) cmd->session_certificate);
3212 free ((void *) cmd->session_certificate);
3213 cmd->session_certificate = (intptr_t) (void *) NULL;
3218 // From here, assume nothing about the cmd->cmd structure; as part of
3219 // the handshake, it may have passed through the client's control, as
3220 // part of a callback. So, reinitialise the entire return structure.
3221 //TODO// Or backup the (struct pioc_starttls) before handshaking
3222 cmd->cmd.pio_cmd = orig_cmdcode;
3223 cmd->cmd.pio_data.pioc_starttls.localid [0] =
3224 cmd->cmd.pio_data.pioc_starttls.remoteid [0] = 0;
3227 // Respond to positive or negative outcome of the handshake
3228 if (gtls_errno != GNUTLS_E_SUCCESS) {
3229 tlog (TLOG_TLS, LOG_ERR, "TLS handshake failed: %s", gnutls_strerror (gtls_errno));
3230 if (cmd->session_errno) {
3232 tlog (TLOG_TLS, LOG_ERR, "Underlying cause may be: %s", strerror (cmd->session_errno));
3233 errstr = error_getstring ();
3234 if (errstr == NULL) {
3235 errstr = "TLS handshake failed";
3237 send_error (replycmd, cmd->session_errno, errstr);
3239 send_error (replycmd, EPERM, "TLS handshake failed");
3245 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
3246 gnutls_deinit (session);
3254 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
3255 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
3256 if (ctlkey_unregister (ckn->regent.ctlkey)) {
3261 manage_txn_rollback (&cmd->txn);
3262 assert (pthread_detach (pthread_self ()) == 0);
3265 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_INFO, "TLS handshake succeeded over %d", cryptfd);
3266 //TODO// extract_authenticated_remote_identity (cmd);
3270 // Request the plaintext file descriptor with a callback
3272 uint32_t oldcmd = cmd->cmd.pio_cmd;
3273 struct command *resp;
3274 cmd->cmd.pio_cmd = PIOC_PLAINTEXT_CONNECT_V2;
3275 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Calling send_callback_and_await_response with PIOC_PLAINTEXT_CONNECT_V2");
3276 resp = send_callback_and_await_response (replycmd, 0);
3277 assert (resp != NULL); // No timeout, should be non-NULL
3278 if (resp->cmd.pio_cmd != PIOC_PLAINTEXT_CONNECT_V2) {
3279 tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has unexpected command code");
3280 send_error (replycmd, EINVAL, "Callback response has bad command code");
3285 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
3286 gnutls_deinit (session);
3290 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
3291 if (ckn) { /* TODO: CHECK NEEDED? PRACTICE=>YES */
3292 if (ctlkey_unregister (ckn->regent.ctlkey)) {
3297 manage_txn_rollback (&cmd->txn);
3298 assert (pthread_detach (pthread_self ()) == 0);
3301 cmd->cmd.pio_cmd = oldcmd;
3302 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);
3303 plainfd = resp->passfd;
3307 tlog (TLOG_UNIXSOCK, LOG_ERR, "No plaintext file descriptor supplied to TLS Pool");
3308 send_error (replycmd, EINVAL, "No plaintext file descriptor supplied to TLS Pool");
3313 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
3314 gnutls_deinit (session);
3318 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
3319 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
3320 if (ctlkey_unregister (ckn->regent.ctlkey)) {
3325 manage_txn_rollback (&cmd->txn);
3326 assert (pthread_detach (pthread_self ()) == 0);
3329 //DEFERRED// send_command (replycmd, -1); // app sent plainfd to us
3332 // Copy TLS records until the connection is closed
3333 manage_txn_commit (&cmd->txn);
3334 if (!renegotiating) {
3335 ckn = (struct ctlkeynode_tls *) malloc (sizeof (struct ctlkeynode_tls));
3338 send_error (replycmd, ENOMEM, "Out of memory allocating control key structure");
3340 int detach = (orig_starttls.flags & PIOF_STARTTLS_DETACH) != 0;
3341 ckn->session = session;
3342 ckn->owner = pthread_self ();
3343 ckn->cryptfd = cryptfd;
3344 ckn->plainfd = plainfd;
3345 //DEBUG// fprintf (stderr, "Registering control key\n");
3346 if (renegotiating || (ctlkey_register (orig_starttls.ctlkey, &ckn->regent, security_tls, detach? -1: cmd->clientfd, forked) == 0)) {
3347 int copied = GNUTLS_E_SUCCESS;
3348 send_command (replycmd, -1); // app sent plainfd to us
3352 // Check on extended master secret if desired
3353 if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
3354 #if GNUTLS_VERSION_NUMBER >= 0x030400
3355 gnutls_ext_priv_data_t ext;
3356 if (!gnutls_ext_get_data (session, 23, &ext)) {
3357 cmd->anonpre &= ~ANONPRE_EXTEND_MASTER_SECRET;
3361 if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
3362 tlog (TLOG_COPYCAT, LOG_ERR, "Received %d remote bytes from anonymous precursor but lacking %s-required authentication through extended master secret", orig_starttls.service);
3363 gtls_errno = GNUTLS_E_LARGE_PACKET;
3366 } else if (write (plainfd, preauth, preauthlen) == preauthlen) {
3367 tlog (TLOG_COPYCAT, LOG_DEBUG, "Passed on %d remote bytes from anonymous precursor to %d\n", preauthlen, plainfd);
3370 copied = copycat (plainfd, cryptfd, session, detach? -1: cmd->clientfd);
3372 tlog (TLOG_COPYCAT, LOG_DEBUG, "Failed to pass on %d remote bytes from anonymous precursor to %d\n", preauthlen, plainfd);
3375 copied = copycat (plainfd, cryptfd, session, detach? -1: cmd->clientfd);
3377 // Renegotiate if copycat asked us to
3378 if (copied == GNUTLS_E_REHANDSHAKE) {
3379 // Yes, goto is a dirty technique. On the
3380 // other hand, so is forcing unstructured
3381 // code flows into a make-belief structure
3382 // that needs changing over and over again.
3383 // I fear goto is the most reasonable way
3384 // of handling this rather obtuse structure
3385 // of renegotiation of security in TLS :(
3386 //TODO// Ensure secure renegotiation!!!
3388 replycmd = NULL; // Bypass all send_XXX()
3389 memcpy (&cmd_copy, cmd, sizeof (cmd_copy));
3391 memcpy (cmd->cmd.pio_data.pioc_starttls.localid, orig_starttls.localid, sizeof (cmd->cmd.pio_data.pioc_starttls.localid));
3392 memcpy (cmd->cmd.pio_data.pioc_starttls.remoteid, orig_starttls.remoteid, sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid));
3393 cmd->cmd.pio_data.pioc_starttls.flags = orig_starttls.flags & ~PIOF_STARTTLS_LOCALID_CHECK;
3394 // Disabling the flag causing LOCALID_CHECK
3395 // ...and plainfd >= 0 so no PLAINTEXT_CONNECT
3396 // ...so there will be no callbacks to cmd
3397 printf ("DEBUG: Goto renegotiate with cmd.lid = \"%s\" and orig_cmd.lid = \"%s\" and cmd.rid = \"%s\" and orig_cmd.rid = \"%s\" and cmd.flags = 0x%x and orig_cmd.flags = 0x%x\n", cmd->cmd.pio_data.pioc_starttls.localid, orig_starttls.localid, cmd->cmd.pio_data.pioc_starttls.remoteid, orig_starttls.remoteid, cmd->cmd.pio_data.pioc_starttls.flags, orig_starttls.flags);
3400 //DEBUG// fprintf (stderr, "Unregistering control key\n");
3401 // Unregister by ctlkey, which should always succeed
3402 // if the TLS connection hadn't been closed down yet;
3403 // and if it does, the memory can be freed. Note that
3404 // the ctlkey is not taken from the ckn, which may
3405 // already have been freed if the ctlfd was closed
3406 // and the connection could not continue detached
3407 // (such as after forking it).
3408 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
3409 if (ctlkey_unregister (orig_starttls.ctlkey)) {
3413 //DEBUG// fprintf (stderr, "Unregistered control key\n");
3415 send_error (replycmd, ENOENT, "Failed to register control key for TLS connection");
3425 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
3426 gnutls_deinit (session);
3429 assert (pthread_detach (pthread_self ()) == 0);
3435 * The starttls function responds to an application's request to
3436 * setup TLS for a given file descriptor, and return a file descriptor
3437 * with the unencrypted view when done. The main thing done here is to
3438 * spark off a new thread that handles the operations.
3440 void starttls (struct command *cmd) {
3441 /* Create a thread and, if successful, wait for it to unlock cmd */
3442 errno = pthread_create (&cmd->handler, NULL, starttls_thread, (void *) cmd);
3444 send_error (cmd, ESRCH, "STARTTLS thread refused");
3447 //TODO:TEST// Thread detaches itself before terminating w/o followup
3449 errno = pthread_detach (cmd->handler);
3451 pthread_cancel (cmd->handler);
3452 send_error (cmd, ESRCH, "STARTTLS thread detachment refused");
3460 * Run the PRNG for a TLS connection, identified by its control key. If the connection
3461 * is not a TLS connection, or if the control key is not found, reply with ERROR;
3462 * otherwise, the session should help to create pseudo-random bytes.
3464 void starttls_prng (struct command *cmd) {
3465 uint8_t in1 [TLSPOOL_PRNGBUFLEN];
3466 uint8_t in2 [TLSPOOL_PRNGBUFLEN];
3467 int16_t in1len, in2len, prnglen;
3468 struct ctlkeynode_tls *ckn = NULL;
3471 int gtls_errno = GNUTLS_E_SUCCESS;
3472 struct pioc_prng *prng = &cmd->cmd.pio_data.pioc_prng;
3474 // Find arguments and validate them
3475 in1len = prng->in1_len;
3476 in2len = prng->in2_len;
3477 prnglen = prng->prng_len;
3478 err = err || (in1len <= 0);
3479 err = err || (prnglen > TLSPOOL_PRNGBUFLEN);
3480 err = err || ((TLSPOOL_CTLKEYLEN + in1len + (in2len >= 0? in2len: 0))
3481 > TLSPOOL_PRNGBUFLEN);
3483 memcpy (in1, prng->buffer + TLSPOOL_CTLKEYLEN , in1len);
3485 memcpy (in2, prng->buffer + TLSPOOL_CTLKEYLEN + in1len, in2len);
3488 // - check the label string
3489 prefixes = tlsprng_label_prefixes;
3490 while ((!err) && (*prefixes)) {
3491 char *pf = *prefixes++;
3492 if (strlen (pf) != in1len) {
3495 if (strcmp (pf, in1) != 0) {
3499 if (*prefixes == NULL) {
3500 // RFC 5705 defines a private-use prefix "EXPERIMENTAL"
3501 if ((in1len <= 12) || (strncmp (in1, "EXPERIMENTAL", 12) != 0)) {
3505 // - check the ctlkey (and ensure it is for TLS)
3507 //DEBUG// fprintf (stderr, "Hoping to find control key\n");
3508 ckn = (struct ctlkeynode_tls *) ctlkey_find (prng->buffer, security_tls, cmd->clientfd);
3511 // Now wipe the PRNG buffer to get rid of any sensitive bytes
3512 memset (prng->buffer, 0, TLSPOOL_PRNGBUFLEN);
3514 // If an error occurrend with the command, report it now
3516 send_error (cmd, EINVAL, "TLS PRNG request invalid");
3517 // ckn is NULL if err != 0, so no need for ctlkey_unfind()
3521 send_error (cmd, ENOENT, "Invalid control key");
3525 // Now actually invoke the PRNG command in the GnuTLS backend
3527 E_g2e ("GnuTLS PRNG based on session master key failed",
3528 gnutls_prf_rfc5705 (ckn->session,
3530 (in2len >= 0)? in2len: 0, (in2len >= 0) ? in2: NULL,
3531 prnglen, prng->buffer));
3532 err = err || (errno != 0);
3534 // Wipe temporary data / buffers for security reasons
3535 memset (in1, 0, sizeof (in1));
3536 memset (in2, 0, sizeof (in2));
3537 ctlkey_unfind ((struct ctlkeynode *) ckn);
3539 // Return the outcome to the user
3541 send_error (cmd, errno? errno: EIO, "PRNG in TLS backend failed");
3543 send_command (cmd, -1);
3548 /* Flying signer functionality. Create an on-the-fly certificate because
3549 * the lidentry daemon and/or application asks for this to represent the
3550 * local identity. Note that this will only work if the remote party
3551 * accepts the root identity under which on-the-signing is done.
3553 * When no root credentials have been configured, this function will
3554 * fail with GNUTLS_E_AGAIN; it may be used as a hint to try through
3555 * other (more conventional) means to obtain a client certificate.
3557 * The API of this function matches that of fetch_local_credentials()
3558 * and that is not a coincidence; this is a drop-in replacement in some
3561 * Limitations: The current implementation only supports X.509 certificates
3562 * to be generated on the fly. So, this will set LID_TYPE_X509, if anything.
3564 gtls_error certificate_onthefly (struct command *cmd) {
3565 gtls_error gtls_errno = GNUTLS_E_SUCCESS;
3566 gnutls_x509_crt_t otfcert;
3568 gnutls_x509_subject_alt_name_t altnmtp;
3573 if ((onthefly_issuercrt == NULL) || (onthefly_issuerkey == NULL) || (onthefly_subjectkey == NULL)) {
3574 // Not able to supply on-the-fly certificates; try someway else
3575 return GNUTLS_E_AGAIN;
3577 if (cmd->cmd.pio_data.pioc_starttls.localid [0] == '\0') {
3578 return GNUTLS_E_NO_CERTIFICATE_FOUND;
3580 if (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data != NULL) {
3581 free (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data);
3582 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data = NULL;
3583 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
3587 // Create an empty certificate
3588 E_g2e ("Failed to initialise on-the-fly certificate",
3589 gnutls_x509_crt_init (&otfcert));
3590 if (gtls_errno != GNUTLS_E_SUCCESS) {
3595 // Fill the certificate with the usual field
3596 E_g2e ("Failed to set on-the-fly certificate to non-CA mode",
3597 gnutls_x509_crt_set_ca_status (otfcert, 0));
3598 E_g2e ("Failed to set on-the-fly certificate version",
3599 gnutls_x509_crt_set_version (otfcert, 3));
3600 onthefly_serial++; //TODO// Consider a random byte string
3601 E_g2e ("Failed to set on-the-fly serial number",
3602 gnutls_x509_crt_set_serial (otfcert, &onthefly_serial, sizeof (onthefly_serial)));
3603 // Skip gnutls_x509_crt_set_issuer_by_dn_by_oid(), added when signing
3605 E_g2e ("Failed to set on-the-fly activation time to now - 2 min",
3606 gnutls_x509_crt_set_activation_time (otfcert, now - 120));
3607 E_g2e ("Failed to set on-the-fly expiration time to now + 3 min",
3608 gnutls_x509_crt_set_expiration_time (otfcert, now + 180));
3609 E_g2e ("Setup certificate CN with local identity",
3610 gnutls_x509_crt_set_dn_by_oid (otfcert, GNUTLS_OID_X520_COMMON_NAME, 0, cmd->cmd.pio_data.pioc_starttls.localid, strnlen (cmd->cmd.pio_data.pioc_starttls.localid, sizeof (cmd->cmd.pio_data.pioc_starttls.localid)-1))); /* TODO: Consider pioc_lidentry as well? */
3611 E_g2e ("Setup certificate OU with TLS Pool on-the-fly",
3612 gnutls_x509_crt_set_dn_by_oid (otfcert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, "TLS Pool on-the-fly", 19));
3613 if (strchr (cmd->cmd.pio_data.pioc_starttls.localid, '@')) {
3614 // localid has the format of an emailAddress
3615 altnmtp = GNUTLS_SAN_RFC822NAME;
3617 // localid has the format of a dnsName
3618 altnmtp = GNUTLS_SAN_DNSNAME;
3620 E_g2e ("Failed to set subjectAltName to localid",
3621 gnutls_x509_crt_set_subject_alt_name (otfcert, altnmtp, &cmd->cmd.pio_data.pioc_starttls.localid, strnlen (cmd->cmd.pio_data.pioc_starttls.localid, sizeof (cmd->cmd.pio_data.pioc_starttls.localid) - 1), GNUTLS_FSAN_APPEND));
3622 //TODO:SKIP, hoping that signing adds: gnutls_x509_crt_set_authority_key_id()
3623 //TODO:SKIP, hoping that a cert without also works: gnutls_x509_crt_set_subjectkey_id()
3624 //TODO:SKIP? gnutls_x509_crt_set_extension_by_oid
3625 //TODO: gnutls_x509_crt_set_key_usage
3626 //TODO:SKIP? gnutls_x509_crt_set_ca_status
3627 for (i=0; i < svcusage_registry_size; i++) {
3628 if (strcmp (svcusage_registry [i].service, cmd->cmd.pio_data.pioc_starttls.service) == 0) {
3629 const char **walker;
3630 E_g2e ("Failed to setup basic key usage during on-the-fly certificate creation",
3631 gnutls_x509_crt_set_key_usage (otfcert, svcusage_registry [i].usage));
3632 walker = svcusage_registry [i].oids_non_critical;
3635 E_g2e ("Failed to append non-critical extended key purpose during on-the-fly certificate creation",
3636 gnutls_x509_crt_set_key_purpose_oid (otfcert, *walker, 0));
3640 walker = svcusage_registry [i].oids_critical;
3643 E_g2e ("Failed to append critical extended key purpose during on-the-fly certificate creation",
3644 gnutls_x509_crt_set_key_purpose_oid (otfcert, *walker, 1));
3651 E_g2e ("Failed to et the on-the-fly subject key",
3652 gnutls_x509_crt_set_key (otfcert, onthefly_subjectkey));
3653 /* TODO: The lock below should not be necessary; it is handled by p11-kit
3654 * or at least it ought to be. What I found however, was that
3655 * a client and server would try to use the onthefly_issuerkey
3656 * at virtually the same time, and then the second call to
3657 * C_SignInit returns CKR_OPERATION_ACTIVE. The lock solved this.
3658 * This makes me frown about server keys stored in PKCS #11...
3660 {gnutls_datum_t data = { 0, 0}; if (gnutls_x509_crt_print (otfcert, GNUTLS_CRT_PRINT_UNSIGNED_FULL, &data) == 0) { fprintf (stderr, "DEBUG: PRESIGCERT: %s\n", data.data); gnutls_free (data.data); } else {fprintf (stderr, "DEBUG: PRESIGCERT failed to print\n"); } }
3661 assert (pthread_mutex_lock (&onthefly_signer_lock) == 0);
3662 E_g2e ("Failed to sign on-the-fly certificate",
3663 gnutls_x509_crt_privkey_sign (otfcert, onthefly_issuercrt, onthefly_issuerkey, GNUTLS_DIG_SHA256, 0));
3664 pthread_mutex_unlock (&onthefly_signer_lock);
3667 // Construct cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data+size for this certificate
3668 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
3669 if (gtls_errno == GNUTLS_E_SUCCESS) {
3670 gtls_errno = gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_DER, NULL, &cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size);
3671 if (gtls_errno == GNUTLS_E_SHORT_MEMORY_BUFFER) {
3672 // This is as expected, now .size will have been set
3673 gtls_errno = GNUTLS_E_SUCCESS;
3675 if (gtls_errno = GNUTLS_E_SUCCESS) {
3676 // Something must be wrong if we receive OK
3677 gtls_errno = GNUTLS_E_INVALID_REQUEST;
3680 E_g2e ("Error while measuring on-the-fly certificate size",
3683 uint8_t *ptr = NULL;
3684 if (gtls_errno == GNUTLS_E_SUCCESS) {
3685 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size += 4 + strlen (onthefly_p11uri) + 1;
3686 ptr = malloc (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size);
3688 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
3689 gnutls_x509_crt_deinit (otfcert);
3690 return GNUTLS_E_MEMORY_ERROR;
3695 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data = ptr;
3696 * (uint32_t *) ptr = htonl (LID_TYPE_X509 | LID_ROLE_BOTH);
3698 strcpy (ptr, onthefly_p11uri);
3699 ptr += strlen (onthefly_p11uri) + 1;
3700 restsz = cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size - 4 - strlen (onthefly_p11uri) - 1;
3701 E_g2e ("Failed to export on-the-fly certificate as a credential",
3702 gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_DER, ptr, &restsz));
3703 char *pembuf [10000];
3704 size_t pemlen = sizeof (pembuf) - 1;
3705 int exporterror = gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_PEM, pembuf, &pemlen);
3706 if (exporterror == 0) {
3707 pembuf [pemlen] = '\0';
3708 fprintf (stderr, "DEBUG: otfcert ::=\n%s\n", pembuf);
3710 fprintf (stderr, "DEBUG: otfcert export to PEM failed with %d, gtls_errno already was %d\n", exporterror, gtls_errno);
3715 // Cleanup the allocated and built structures
3716 gnutls_x509_crt_deinit (otfcert);
3719 // Return the overall result that might have stopped otf halfway