1 /* tlspool/starttls.c -- Setup and validation handler for TLS session */
20 #include <sys/types.h>
21 #include <sys/socket.h>
23 #include <arpa/inet.h>
24 #include <netinet/in.h>
26 #include <gnutls/gnutls.h>
27 #include <gnutls/pkcs11.h>
28 #include <gnutls/abstract.h>
29 #include <gnutls/dane.h>
31 #include <p11-kit/pkcs11.h>
33 #include <tlspool/commands.h>
34 #include <tlspool/internal.h>
39 /* Plus, from k5-int.h: */
40 krb5_error_code KRB5_CALLCONV krb5_decrypt_tkt_part(krb5_context,
41 const krb5_keyblock *,
45 #include <quick-der/api.h>
46 #include <quick-der/rfc4120.h>
47 typedef DER_OVLY_rfc4120_Ticket ticket_t;
48 typedef DER_OVLY_rfc4120_Authenticator authenticator_t;
49 typedef DER_OVLY_rfc4120_EncryptedData encrypted_data_t;
51 #include <tlspool/internal.h>
57 #include <sys/types.h>
58 #include <sys/socket.h>
61 #include <arpa/inet.h>
68 #define SHUT_RD SD_RECEIVE
69 #define SHUT_WR SD_SEND
70 #else /* WINDOWS_PORT */
71 #define RECV_FLAGS MSG_DONTWAIT | MSG_NOSIGNAL
72 #endif /* WINDOWS_PORT */
79 #if EXPECTED_LID_TYPE_COUNT != LID_TYPE_CNT
80 #error "Set EXPECTED_LID_TYPE_COUNT in <tlspool/internal.h> to match LID_TYPE_CNT"
84 /* This module hosts TLS handlers which treat an individual connection.
86 * Initially, the TLS setup is processed, which means validating the
87 * connection. If and when this succeeds, a continued process is needed
88 * to encrypt and decrypt traffic while it is in transit.
90 * Every TLS connection (including the attempt to set it up) is hosted in
91 * its own thread. This means that it can abide time to wait for PINENTRY,
92 * LOCALID or LIDENTRY responses. It also means a very clear flow when the
93 * time comes to destroy a connection.
95 * While encrypting and decrypting traffic passing through, the thread
96 * will use its own poll() call, and thus offload the potentially large
97 * one of the main thread, which is supposed to be a low-traffic task.
98 * The set of file descriptors used by the session-handler threads are
99 * in contrast very small and can easily be started for every single
100 * packet passing through.
102 * Might the user terminate a process while this one is waiting for a
103 * callback command request, then the main TLS pool thread will take
104 * care of taking down this thread. To that end, it sets the followup
105 * pointer that normally holds a callback response to NULL, and then
106 * permits this thread to run again. This will lead to a shutdown of
107 * this process, and proper closing of all connections. The remote peer
108 * will therefore see the result of a local kill as a connection reset.
110 * In case one of the end points of the connection is terminated, a
111 * similar thing will happen; the thread will terminate itself after
112 * a cleanup of any outstanding resources. This, once again, leads
113 * to passing on the reset of a connection between the encrypted and
114 * side of the connection.
120 * GnuTLS infrastructure setup.
121 * Session-shared DH-keys, credentials structures, and so on.
123 static gnutls_dh_params_t dh_params;
126 gnutls_credentials_type_t credtp;
130 #define EXPECTED_SRV_CREDCOUNT 3
131 #define EXPECTED_CLI_CREDCOUNT 3
132 static struct credinfo srv_creds [EXPECTED_SRV_CREDCOUNT];
133 static struct credinfo cli_creds [EXPECTED_CLI_CREDCOUNT];
134 static int srv_credcount = 0;
135 static int cli_credcount = 0;
136 static const char const *onthefly_p11uri = "pkcs11:manufacturer=ARPA2.net;token=TLS+Pool+internal;object=on-the-fly+signer;type=private;serial=1";
137 static unsigned long long onthefly_serial; //TODO: Fill with now * 1000
138 static gnutls_x509_crt_t onthefly_issuercrt = NULL;
139 static gnutls_privkey_t onthefly_issuerkey = NULL;
140 static gnutls_x509_privkey_t onthefly_subjectkey = NULL;
141 static pthread_mutex_t onthefly_signer_lock = PTHREAD_MUTEX_INITIALIZER;
144 static krb5_context krbctx_cli, krbctx_srv;
145 static krb5_keytab krb_kt_cli, krb_kt_srv;
146 static bool got_cc_cli, got_cc_srv;
147 static int have_key_tgt_cc (
148 struct command *cmd, // in, session context
149 krb5_context ctx, // in, kerberos context
150 bool use_cc, // in, whether to use cc
151 krb5_kvno kvno, // in, kvno (0 for highest)
152 krb5_enctype enctype,// in, enctype (0 for any)
153 char *p11uri, // in/opt, PKCS #11 pwd URI
154 krb5_keytab kt, // in/opt, keytab
155 krb5_keyblock *key, // opt/opt session key
156 krb5_creds **tgt, // out/opt, tkt granting tkt
157 krb5_ccache *cc); // out/opt, cred cache
158 static int have_service_ticket (
159 struct command *cmd, // in, session context
160 krb5_context ctx, // in, kerberos context
161 krb5_ccache cc_opt, // in/opt, credcache
162 krb5_principal cli, // in, client principal
163 krb5_creds *ticket); // out/opt, tkt granting tkt
167 /* The local variation on the ctlkeynode structure, with TLS-specific fields
169 struct ctlkeynode_tls {
170 struct ctlkeynode regent; // Structure for ctlkey_register()
171 gnutls_session_t session; // Additional data specifically for TLS
172 pthread_t owner; // For interruption of copycat()
173 int plainfd; // Plain-side connection
174 int cryptfd; // Crypt-side connection
177 /* A local structure used for iterating over PKCS #11 entries. This is used
178 * to iterate over password attempts, no more than MAX_P11ITER_ATTEMPTS though.
180 * When a password is requested but none is available, the password request
181 * will be passed to the user using the PIN callback mechanism. When this
182 * is done, a warning may be given that the TLS Pool overtakes control over
183 * the account (when thusly configured). In support of that option, the
184 * $attempt is counted and the respective $p11pwd is CK_INVALID_HANDLE.
185 * TODO: Perhaps interact for saving, such as entering an certain string?
187 * When a number of attempts needs to be made before success, then any
188 * objects that precede a succeeded $attempt can be removed. The same may
189 * be true for any objects after it.
191 * This mechanism is useful during password changes. When a new password is
192 * desired by the KDC, then a random object is created and returned twice.
193 * To support repeated delivery, the password is stored in $newpwd;
194 * In this case, the safest choice is still to leave the last $p11pwd.
196 * The caller may decide to invoke the password changing procedure, namely
197 * after manual entry as evidenced by the condition
199 * (attempts < MAX_P11_ITER_ATTEMPTS) &&
200 * (p11pwd [attempt] == CK_INVALID_HANDLE)
202 * TODO: This is a designed data structure, but not yet installed.
204 * TODO: It is more useful to abolish passwords, and truly use PKCS #11.
206 #define MAX_P11ITER_ATTEMPTS 3
208 struct command *cmd; // The session command structure
209 CK_SESSION_HANDLE p11ses; // The PKCS #11 session in motion
210 int attempt; // Starts at -1, incremented by pwd entry
211 CK_OBJECT_HANDLE p11pwd [MAX_P11ITER_ATTEMPTS];
212 // Sequence of $attempt objects returned
213 CK_OBJECT_HANDLE newpwd; // Set when a new password was offered
216 /* The list of accepted Exporter Label Prefixes for starttls_prng()
218 char *tlsprng_label_prefixes [] = {
219 // Forbidden by RFC 5705: "client finished",
220 // Forbidden by RFC 5705: "server finished",
221 // Forbidden by RFC 5705: "master secret",
222 // Forbidden by RFC 5705: "key expansion",
223 "client EAP encryption", // not suited for DTLS
224 "ttls keying material", // not suited for DTLS
225 "ttls challenge", // not suited for DTLS
226 "EXTRACTOR-dtls_srtp",
227 "EXPORTER_DTLS_OVER_SCTP",
228 "EXPORTER-ETSI-TC-M2M-Bootstrap",
229 "EXPORTER-ETSI-TC-M2M-Connection",
231 "EXPORTER_GBA_Digest",
232 "EXPORTER: teap session key seed", // not suited for DTLS
233 "EXPORTER-oneM2M-Bootstrap",
234 "EXPORTER-oneM2M-Connection",
238 /* The registry with the service names that are deemed safe for an
239 * anonymous precursor phase; that is, the service names that may offer
240 * ANON-DH initially, and immediately renegotiate an authenticated
241 * connection. See doc/anonymising-precursor.* for more information.
243 * The registry is ordered by case-independent service name, so it can
244 * be searched in 2log time. Service names are as defined by IANA in the
245 * "Service Name and Transport Protocol Port Number Registry".
247 * The entries in the registry depend on the role played; either as a
248 * client or as a server. This refers to the local node, and depends on
249 * uncertainty of the remote party's TLS implementation and whether or
250 * not the protocol could lead to the remote sending information that
251 * requires authentication before the secure renogiation into an
252 * authenticated connection has been completed by this side. This is
253 * a protocol-dependent matter and the registry provided here serves to
254 * encapsulate this knowledge inside the TLS Pool instead of bothering
255 * application designers with it. Entries that are not found in the
256 * registry are interpreted as not allowing an anonymising precursor.
258 * Note that ANONPRE_EXTEND_MASTER_SECRET cannot be verified before
259 * GnuTLS version 3.4.0; see "imap" below for the resulting impact. This
260 * also impacts dynamic linking, because 3.4.0 introduces the new function
261 * gnutls_ext_get_data() that is used for this requirement.
263 #define ANONPRE_FORBID 0x00
264 #define ANONPRE_CLIENT 0x01
265 #define ANONPRE_SERVER 0x02
266 #define ANONPRE_EITHER (ANONPRE_CLIENT | ANONPRE_SERVER)
267 #define ANONPRE_EXTEND_MASTER_SECRET 0x10
268 struct anonpre_regentry {
272 struct anonpre_regentry anonpre_registry [] = {
273 /* This registry is commented out for now, although the code to use it seems
274 * to work fine. GnuTLS however, does not seem to support making the switch
275 * from ANON-ECDH to an authenticated handshake. Details:
276 * http://lists.gnutls.org/pipermail/gnutls-help/2015-November/003998.html
278 { "generic_anonpre", ANONPRE_EITHER }, // Name invalid as per RFC 6335
279 { "http", ANONPRE_CLIENT }, // Server also if it ignores client ID
280 #if GNUTLS_VERSION_NUMBER < 0x030400
281 { "imap", ANONPRE_SERVER },
283 { "imap", ANONPRE_EITHER | ANONPRE_EXTEND_MASTER_SECRET },
285 { "pop3", ANONPRE_EITHER },
286 { "smtp", ANONPRE_EITHER },
288 * End of commenting out the registry
291 const int anonpre_registry_size = sizeof (anonpre_registry) / sizeof (struct anonpre_regentry);
294 /* The registry of Key Usage and Extended Key Usage for any given service name.
296 static const char *http_noncrit [] = { GNUTLS_KP_TLS_WWW_SERVER, GNUTLS_KP_TLS_WWW_CLIENT, NULL };
297 struct svcusage_regentry {
300 const char **oids_non_critical;
301 const char **oids_critical;
303 struct svcusage_regentry svcusage_registry [] = {
305 GNUTLS_KEY_KEY_ENCIPHERMENT |
306 GNUTLS_KEY_KEY_AGREEMENT,
311 GNUTLS_KEY_DIGITAL_SIGNATURE |
312 GNUTLS_KEY_KEY_ENCIPHERMENT |
313 GNUTLS_KEY_KEY_AGREEMENT,
318 const int svcusage_registry_size = sizeof (svcusage_registry) / sizeof (struct svcusage_regentry);
321 /* The maximum number of bytes that can be passed over a TLS connection before
322 * the authentication is complete in case of a anonymous precursor within a
323 * protocol that ensures that this cannot be a problem.
327 /* The priorities cache for "NORMAL" -- used to preconfigure the server,
328 * actually to overcome its unwillingness to perform the handshake, and
329 * leave it to srv_clienthello() to setup the priority string.
331 gnutls_priority_t priority_normal;
334 /* Map a GnuTLS call (usually a function call) to a POSIX errno,
335 * optionally reporting an errstr to avoid loosing information.
336 * Retain errno if it already exists.
337 * Continue if errno differs from 0, GnuTLS may "damage" it even when OK. */
338 #define E_g2e(errstr,gtlscall) { \
339 if (gtls_errno == GNUTLS_E_SUCCESS) { \
340 gtls_errno = (gtlscall); \
341 if (gtls_errno != GNUTLS_E_SUCCESS) { \
342 error_gnutls2posix (gtls_errno, errstr); \
347 /* Cleanup when GnuTLS leaves errno damaged but returns no gtls_errno */
348 #define E_gnutls_clear_errno() { \
349 if (gtls_errno == GNUTLS_E_SUCCESS) { \
354 /* Error number translation, including error string setup. See E_g2e(). */
355 void error_gnutls2posix (int gtls_errno, char *new_errstr) {
357 register int newerrno;
360 if (gtls_errno == GNUTLS_E_SUCCESS) {
363 errstr = error_getstring ();
364 if (errstr != NULL) {
368 // Report the textual error
369 if (new_errstr == NULL) {
370 new_errstr = "GnuTLS error";
372 tlog (TLOG_TLS, LOG_ERR, "%s: %s",
374 gnutls_strerror (gtls_errno));
375 error_setstring (new_errstr);
377 // Translate error to a POSIX errno value
378 switch (gtls_errno) {
379 case GNUTLS_E_SUCCESS:
381 case GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM:
382 case GNUTLS_E_UNKNOWN_CIPHER_TYPE:
383 case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
384 case GNUTLS_E_UNWANTED_ALGORITHM:
385 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
386 case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
387 case GNUTLS_E_X509_UNKNOWN_SAN:
388 case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
389 case GNUTLS_E_UNKNOWN_PK_ALGORITHM:
390 case GNUTLS_E_NO_TEMPORARY_RSA_PARAMS:
391 case GNUTLS_E_NO_COMPRESSION_ALGORITHMS:
392 case GNUTLS_E_NO_CIPHER_SUITES:
393 case GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED:
394 case GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE:
395 case GNUTLS_E_UNKNOWN_HASH_ALGORITHM:
396 case GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE:
397 case GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE:
398 case GNUTLS_E_NO_TEMPORARY_DH_PARAMS:
399 case GNUTLS_E_UNKNOWN_ALGORITHM:
400 case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
401 case GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED:
402 case GNUTLS_E_X509_UNSUPPORTED_OID:
403 case GNUTLS_E_CHANNEL_BINDING_NOT_AVAILABLE:
404 case GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL:
405 case GNUTLS_E_ECC_NO_SUPPORTED_CURVES:
406 case GNUTLS_E_ECC_UNSUPPORTED_CURVE:
407 case GNUTLS_E_X509_UNSUPPORTED_EXTENSION:
408 case GNUTLS_E_NO_CERTIFICATE_STATUS:
409 case GNUTLS_E_NO_APPLICATION_PROTOCOL:
410 #ifdef GNUTLS_E_NO_SELF_TEST
411 case GNUTLS_E_NO_SELF_TEST:
413 newerrno = EOPNOTSUPP;
415 case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
416 case GNUTLS_E_INVALID_REQUEST:
419 case GNUTLS_E_INVALID_SESSION:
420 case GNUTLS_E_REHANDSHAKE:
421 case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
424 case GNUTLS_E_PUSH_ERROR:
425 case GNUTLS_E_PULL_ERROR:
426 case GNUTLS_E_PREMATURE_TERMINATION:
427 case GNUTLS_E_SESSION_EOF:
428 newerrno = ECONNRESET;
430 case GNUTLS_E_UNEXPECTED_PACKET:
431 case GNUTLS_E_WARNING_ALERT_RECEIVED:
432 case GNUTLS_E_FATAL_ALERT_RECEIVED:
433 case GNUTLS_E_LARGE_PACKET:
434 case GNUTLS_E_ERROR_IN_FINISHED_PACKET:
435 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
436 case GNUTLS_E_MPI_SCAN_FAILED:
437 case GNUTLS_E_DECRYPTION_FAILED:
438 case GNUTLS_E_DECOMPRESSION_FAILED:
439 case GNUTLS_E_COMPRESSION_FAILED:
440 case GNUTLS_E_BASE64_DECODING_ERROR:
441 case GNUTLS_E_MPI_PRINT_FAILED:
442 case GNUTLS_E_GOT_APPLICATION_DATA:
443 case GNUTLS_E_RECORD_LIMIT_REACHED:
444 case GNUTLS_E_ENCRYPTION_FAILED:
445 case GNUTLS_E_PK_ENCRYPTION_FAILED:
446 case GNUTLS_E_PK_DECRYPTION_FAILED:
447 case GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER:
448 case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
449 case GNUTLS_E_PKCS1_WRONG_PAD:
450 case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
451 case GNUTLS_E_FILE_ERROR:
452 case GNUTLS_E_ASN1_ELEMENT_NOT_FOUND:
453 case GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND:
454 case GNUTLS_E_ASN1_DER_ERROR:
455 case GNUTLS_E_ASN1_VALUE_NOT_FOUND:
456 case GNUTLS_E_ASN1_GENERIC_ERROR:
457 case GNUTLS_E_ASN1_VALUE_NOT_VALID:
458 case GNUTLS_E_ASN1_TAG_ERROR:
459 case GNUTLS_E_ASN1_TAG_IMPLICIT:
460 case GNUTLS_E_ASN1_TYPE_ANY_ERROR:
461 case GNUTLS_E_ASN1_SYNTAX_ERROR:
462 case GNUTLS_E_ASN1_DER_OVERFLOW:
463 case GNUTLS_E_TOO_MANY_EMPTY_PACKETS:
464 case GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS:
465 case GNUTLS_E_SRP_PWD_PARSING_ERROR:
466 case GNUTLS_E_BASE64_ENCODING_ERROR:
467 case GNUTLS_E_OPENPGP_KEYRING_ERROR:
468 case GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR:
469 case GNUTLS_E_OPENPGP_SUBKEY_ERROR:
470 case GNUTLS_E_CRYPTO_ALREADY_REGISTERED:
471 case GNUTLS_E_HANDSHAKE_TOO_LARGE:
472 case GNUTLS_E_BAD_COOKIE:
473 case GNUTLS_E_PARSING_ERROR:
474 case GNUTLS_E_CERTIFICATE_LIST_UNSORTED:
475 case GNUTLS_E_NO_PRIORITIES_WERE_SET:
476 #ifdef GNUTLS_E_PK_GENERATION_ERROR
477 case GNUTLS_E_PK_GENERATION_ERROR:
479 #ifdef GNUTLS_E_SELF_TEST_ERROR
480 case GNUTLS_E_SELF_TEST_ERROR:
482 #ifdef GNUTLS_E_SOCKETS_INIT_ERROR
483 case GNUTLS_E_SOCKETS_INIT_ERROR:
487 case GNUTLS_E_MEMORY_ERROR:
488 case GNUTLS_E_SHORT_MEMORY_BUFFER:
494 case GNUTLS_E_EXPIRED:
495 case GNUTLS_E_TIMEDOUT:
496 newerrno = ETIMEDOUT;
498 case GNUTLS_E_DB_ERROR:
505 case GNUTLS_E_SRP_PWD_ERROR:
506 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
507 case GNUTLS_E_HASH_FAILED:
508 case GNUTLS_E_PK_SIGN_FAILED:
509 case GNUTLS_E_CERTIFICATE_ERROR:
510 case GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION:
511 case GNUTLS_E_KEY_USAGE_VIOLATION:
512 case GNUTLS_E_NO_CERTIFICATE_FOUND:
513 case GNUTLS_E_OPENPGP_UID_REVOKED:
514 case GNUTLS_E_OPENPGP_GETKEY_FAILED:
515 case GNUTLS_E_PK_SIG_VERIFY_FAILED:
516 case GNUTLS_E_ILLEGAL_SRP_USERNAME:
517 case GNUTLS_E_INVALID_PASSWORD:
518 case GNUTLS_E_MAC_VERIFY_FAILED:
519 case GNUTLS_E_IA_VERIFY_FAILED:
520 case GNUTLS_E_UNKNOWN_SRP_USERNAME:
521 case GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR:
522 case GNUTLS_E_USER_ERROR:
523 case GNUTLS_E_AUTH_ERROR:
526 case GNUTLS_E_INTERRUPTED:
529 case GNUTLS_E_INTERNAL_ERROR:
530 case GNUTLS_E_CONSTRAINT_ERROR:
531 case GNUTLS_E_ILLEGAL_PARAMETER:
534 case GNUTLS_E_SAFE_RENEGOTIATION_FAILED:
535 newerrno = ECONNREFUSED;
537 case GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY:
538 case GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY:
539 #ifdef GNUTLS_E_LIB_IN_ERROR_STATE
540 case GNUTLS_E_LIB_IN_ERROR_STATE:
544 case GNUTLS_E_RANDOM_FAILED:
547 case GNUTLS_E_CRYPTODEV_IOCTL_ERROR:
548 case GNUTLS_E_CRYPTODEV_DEVICE_ERROR:
549 case GNUTLS_E_HEARTBEAT_PONG_RECEIVED:
550 case GNUTLS_E_HEARTBEAT_PING_RECEIVED:
551 case GNUTLS_E_PKCS11_ERROR:
552 case GNUTLS_E_PKCS11_LOAD_ERROR:
553 case GNUTLS_E_PKCS11_PIN_ERROR:
554 case GNUTLS_E_PKCS11_SLOT_ERROR:
555 case GNUTLS_E_LOCKING_ERROR:
556 case GNUTLS_E_PKCS11_ATTRIBUTE_ERROR:
557 case GNUTLS_E_PKCS11_DEVICE_ERROR:
558 case GNUTLS_E_PKCS11_DATA_ERROR:
559 case GNUTLS_E_PKCS11_UNSUPPORTED_FEATURE_ERROR:
560 case GNUTLS_E_PKCS11_KEY_ERROR:
561 case GNUTLS_E_PKCS11_PIN_EXPIRED:
562 case GNUTLS_E_PKCS11_PIN_LOCKED:
563 case GNUTLS_E_PKCS11_SESSION_ERROR:
564 case GNUTLS_E_PKCS11_SIGNATURE_ERROR:
565 case GNUTLS_E_PKCS11_TOKEN_ERROR:
566 case GNUTLS_E_PKCS11_USER_ERROR:
567 case GNUTLS_E_CRYPTO_INIT_FAILED:
568 case GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE:
569 case GNUTLS_E_TPM_ERROR:
570 case GNUTLS_E_TPM_KEY_PASSWORD_ERROR:
571 case GNUTLS_E_TPM_SRK_PASSWORD_ERROR:
572 case GNUTLS_E_TPM_SESSION_ERROR:
573 case GNUTLS_E_TPM_KEY_NOT_FOUND:
574 case GNUTLS_E_TPM_UNINITIALIZED:
575 case GNUTLS_E_OCSP_RESPONSE_ERROR:
576 case GNUTLS_E_RANDOM_DEVICE_ERROR:
578 newerrno = EREMOTEIO;
591 /* Generate Diffie-Hellman parameters - for use with DHE
592 * kx algorithms. TODO: These should be discarded and regenerated
593 * once a day, once a week or once a month. Depending on the
594 * security requirements.
596 static gtls_error generate_dh_params (void) {
598 int gtls_errno = GNUTLS_E_SUCCESS;
599 bits = gnutls_sec_param_to_pk_bits (
601 GNUTLS_SEC_PARAM_LEGACY);
602 //TODO// Acquire DH-params lock
603 E_g2e ("Failed to initialise DH params",
604 gnutls_dh_params_init (
606 E_g2e ("Failed to generate DH params",
607 gnutls_dh_params_generate2 (
610 //TODO// Release DH-params lock
614 /* Load Diffie-Hellman parameters from file - or generate them when load fails.
616 static gtls_error load_dh_params (void) {
617 gnutls_dh_params_t dhp;
618 gnutls_datum_t pkcs3;
619 char *filename = cfg_tls_dhparamfile ();
620 int gtls_errno = GNUTLS_E_SUCCESS;
621 memset (&pkcs3, 0, sizeof (pkcs3));
623 E_g2e ("No PKCS #3 PEM file with DH params",
627 E_gnutls_clear_errno ();
628 E_g2e ("Failed to initialise DH params",
629 gnutls_dh_params_init (
631 E_g2e ("Failed to import DH params from PKCS #3 PEM",
632 gnutls_dh_params_import_pkcs3 (
635 GNUTLS_X509_FMT_PEM));
636 E_gnutls_clear_errno ();
638 if (pkcs3.data != NULL) {
641 if (gtls_errno != GNUTLS_E_SUCCESS) {
643 // File failed to load, so try to generate fresh DH params
644 int gtls_errno_stack0;
645 gtls_errno = GNUTLS_E_SUCCESS;
646 tlog (TLOG_CRYPTO, LOG_DEBUG, "Failed to load DH params from %s; generating fresh parameters", filename);
647 E_g2e ("Failed to generate DH params",
648 generate_dh_params ());
649 gtls_errno_stack0 = gtls_errno;
650 //TODO// Acquire DH-params lock
651 E_g2e ("Failed to format DH params as PKCS #3 PEM",
652 gnutls_dh_params_export2_pkcs3 (
656 //TODO// Release DH-params lock
657 if ((gtls_errno == GNUTLS_E_SUCCESS) && (filename != NULL)) {
660 // Best effor file save -- readback will parse
661 pemf = fopen (filename, "w");
663 fwrite (pkcs3.data, 1, pkcs3.size, pemf);
665 tlog (TLOG_FILES, LOG_DEBUG, "Saved DH params to %s (best-effort)", filename);
667 E_gnutls_clear_errno ();
669 gtls_errno = gtls_errno_stack0;
671 gnutls_dh_params_t old_dh;
672 //TODO// Acquire DH-params lock
675 //TODO// Release DH-params lock
677 gnutls_dh_params_deinit (old_dh);
683 /* Remove DH parameters, to be used during program cleanup. */
684 static void remove_dh_params (void) {
686 gnutls_dh_params_deinit (dh_params);
692 /* A log printing function
694 void log_gnutls (int level, const char *msg) {
695 tlog (TLOG_TLS, level, "GnuTLS: %s", msg);
699 /* Implement the GnuTLS function for token insertion callback. This function
700 * refers back to the generic callback for token insertion.
702 int gnutls_token_callback (void *const userdata,
703 const char *const label,
705 if (token_callback (label, retry)) {
706 return GNUTLS_E_SUCCESS;
708 return GNUTLS_E_PKCS11_TOKEN_ERROR;
714 * Implement the GnuTLS function for PIN callback. This function calls
715 * the generic PIN callback operation.
717 int gnutls_pin_callback (void *userdata,
719 const char *token_url,
720 const char *token_label,
724 if (flags & GNUTLS_PIN_SO) {
725 return GNUTLS_E_USER_ERROR;
727 if (pin_callback (attempt, token_url, NULL, pin, pin_max)) {
730 return GNUTLS_E_PKCS11_PIN_ERROR;
735 /* Register a PKCS #11 provider with the GnuTLS environment. */
736 void starttls_pkcs11_provider (char *p11path) {
737 unsigned int token_seq = 0;
739 if (gnutls_pkcs11_add_provider (p11path, NULL) != 0) {
740 fprintf (stderr, "Failed to register PKCS #11 library %s with GnuTLS\n", p11path);
743 while (gnutls_pkcs11_token_get_url (token_seq, 0, &p11uri) == 0) {
745 fprintf (stderr, "DEBUG: Found token URI %s\n", p11uri);
747 //TODO// if (gnutls_pkcs11_token_get_info (p11uri, GNUTLS_PKCS11_TOKEN_LABEL-of-SERIAL-of-MANUFACTURER-of-MODEL, output, utput_size) == 0) { ... }
748 gnutls_free (p11uri);
751 //TODO// Select token by name (value)
752 //TODO// if PIN available then set it up
753 //TODO:WHY?// free_p11pin ();
756 static void cleanup_starttls_credentials (void);/* Defined below */
757 static void cleanup_starttls_validation (void); /* Defined below */
759 static void cleanup_starttls_kerberos (void); /* Defined below */
760 static int setup_starttls_kerberos (void); /* Defined below */
762 static int setup_starttls_credentials (void); /* Defined below */
764 /* The global and static setup function for the starttls functions.
766 void setup_starttls (void) {
768 int gtls_errno = GNUTLS_E_SUCCESS;
769 char *otfsigcrt, *otfsigkey;
771 // Setup configuration variables
772 maxpreauth = cfg_tls_maxpreauth ();
774 // Basic library actions
775 tlog (TLOG_TLS, LOG_DEBUG, "Compiled against GnuTLS version %s", GNUTLS_VERSION);
776 curver = gnutls_check_version (GNUTLS_VERSION);
777 tlog (TLOG_TLS, LOG_DEBUG, "Running against %s GnuTLS version %s", curver? "acceptable": "OLDER", curver? curver: gnutls_check_version (NULL));
778 E_g2e ("GnuTLS global initialisation failed",
779 gnutls_global_init ());
780 E_gnutls_clear_errno ();
781 E_g2e ("GnuTLS PKCS #11 initialisation failed",
783 GNUTLS_PKCS11_FLAG_MANUAL, NULL));
785 // Setup logging / debugging
786 if (cfg_log_level () == LOG_DEBUG) {
787 gnutls_global_set_log_function (log_gnutls);
788 gnutls_global_set_log_level (9);
793 E_g2e ("Kerberos initialisation failed",
794 setup_starttls_kerberos ());
797 // Setup callbacks for user communication
798 gnutls_pkcs11_set_token_function (gnutls_token_callback, NULL);
799 gnutls_pkcs11_set_pin_function (gnutls_pin_callback, NULL);
801 // Setup DH parameters
802 E_g2e ("Loading DH params failed",
805 // Setup shared credentials for all client server processes
806 E_g2e ("Failed to setup GnuTLS callback credentials",
807 setup_starttls_credentials ());
809 // Parse the default priority string
811 E_g2e ("Failed to setup NORMAL priority cache",
812 gnutls_priority_init (&priority_normal,
815 "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
817 "+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
819 "+ECDHE-KRB:" // +ECDHE-KRB-RSA:+ECDHE-KRB-ECDSA:"
820 "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:"
821 "+CTYPE-SRV-KRB:+CTYPE-SRV-X.509:+CTYPE-SRV-OPENPGP:"
822 "+CTYPE-CLI-KRB:+CTYPE-CLI-X.509:+CTYPE-CLI-OPENPGP:"
823 "+SRP:+SRP-RSA:+SRP-DSS",
826 E_g2e ("Failed to setup NORMAL priority cache",
827 gnutls_priority_init (&priority_normal,
829 "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
830 "+COMP-NULL:+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
832 "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:"
833 "+CTYPE-X.509:+CTYPE-OPENPGP:"
834 "+SRP:+SRP-RSA:+SRP-DSS",
838 // Try to setup on-the-fly signing key / certificate and gen a certkey
839 otfsigcrt = cfg_tls_onthefly_signcert ();
840 otfsigkey = cfg_tls_onthefly_signkey ();
841 fprintf (stderr, "DEBUG: gtls_errno = %d, otfsigcrt == %s, otfsigkey == %s\n", gtls_errno, otfsigcrt? otfsigcrt: "NULL", otfsigkey? otfsigkey: "NULL");
842 if ((gtls_errno == GNUTLS_E_SUCCESS) && (otfsigcrt != NULL)) {
843 FILE *crtfile = NULL;
844 fprintf (stderr, "DEBUG: gtls_errno==%d when initialising onthefly_issuercrt\n", gtls_errno);
845 E_g2e ("Failed to initialise on-the-fly issuer certificate structure",
846 gnutls_x509_crt_init (&onthefly_issuercrt));
847 if (strncmp (otfsigcrt, "file:", 5) == 0) {
848 // Provisionary support for the "file:" prefix
851 crtfile = fopen (otfsigcrt, "r");
852 if (crtfile == NULL) {
853 E_g2e ("Failed to open on-the-fly issuer certificate file",
854 GNUTLS_E_FILE_ERROR);
855 fprintf (stderr, "DEBUG: gtls_errno==%d after failing to open file for onthefly_issuercrt\n", gtls_errno);
858 size_t len = fread (crt, 1, sizeof (crt), crtfile);
859 if (ferror (crtfile)) {
860 E_g2e ("Failed to read on-the-fly issuer certificate from file",
861 GNUTLS_E_FILE_ERROR);
862 } else if ((len >= sizeof (crt)) || !feof (crtfile)) {
863 E_g2e ("Unexpectedly long on-the-fly issuer certificate file",
864 GNUTLS_E_FILE_ERROR);
866 gnutls_datum_t cd = {
870 fprintf (stderr, "DEBUG: gtls_errno==%d before importing onthefly_issuercrt\n", gtls_errno);
871 E_g2e ("Failed to import on-the-fly certificate from file",
872 gnutls_x509_crt_import (onthefly_issuercrt, &cd, GNUTLS_X509_FMT_DER));
873 fprintf (stderr, "DEBUG: gtls_errno==%d after importing onthefly_issuercrt\n", gtls_errno);
878 if ((gtls_errno == GNUTLS_E_SUCCESS) && (otfsigkey != NULL)) {
879 E_g2e ("Failed to initialise on-the-fly issuer private key structure",
880 gnutls_privkey_init (&onthefly_issuerkey));
881 fprintf (stderr, "DEBUG: before onthefly p11 import, gtlserrno = %d\n", gtls_errno);
882 E_g2e ("Failed to import pkcs11: URI into on-the-fly issuer private key",
883 gnutls_privkey_import_pkcs11_url (onthefly_issuerkey, otfsigkey));
884 fprintf (stderr, "DEBUG: after onthefly p11 import, gtlserrno = %d\n", gtls_errno);
886 fprintf (stderr, "DEBUG: When it matters, gtls_errno = %d, onthefly_issuercrt %s NULL, onthefly_issuerkey %s NULL\n", gtls_errno, onthefly_issuercrt?"!=":"==", onthefly_issuerkey?"!=":"==");
887 if ((gtls_errno == GNUTLS_E_SUCCESS) && (onthefly_issuercrt != NULL) && (onthefly_issuerkey != NULL)) {
888 E_g2e ("Failed to initialise on-the-fly certificate session key",
889 gnutls_x509_privkey_init (&onthefly_subjectkey));
890 E_g2e ("Failed to generate on-the-fly certificate session key",
891 gnutls_x509_privkey_generate (onthefly_subjectkey, GNUTLS_PK_RSA, 2048 /*TODO:FIXED*/, 0));
892 if (gtls_errno == GNUTLS_E_SUCCESS) {
893 tlog (TLOG_TLS, LOG_INFO, "Setup for on-the-fly signing with the TLS Pool");
895 tlog (TLOG_TLS, LOG_ERR, "Failed to setup on-the-fly signing (shall continue without it)");
896 gnutls_x509_privkey_deinit (onthefly_subjectkey);
897 onthefly_subjectkey = NULL;
900 gtls_errno = GNUTLS_E_SUCCESS;
901 E_gnutls_clear_errno ();
903 if (onthefly_subjectkey == NULL) {
904 if (onthefly_issuercrt != NULL) {
905 gnutls_x509_crt_deinit (onthefly_issuercrt);
906 onthefly_issuercrt = NULL;
908 if (onthefly_issuerkey != NULL) {
909 gnutls_privkey_deinit (onthefly_issuerkey);
910 onthefly_issuerkey = NULL;
914 // Finally, check whether there was any error setting up GnuTLS
915 if (gtls_errno != GNUTLS_E_SUCCESS) {
916 tlog (TLOG_TLS, LOG_CRIT, "FATAL: GnuTLS setup failed: %s", gnutls_strerror (gtls_errno));
920 //MOVED// // Setup the management databases
921 //MOVED// tlog (TLOG_DB, LOG_DEBUG, "Setting up management databases");
922 //MOVED// E_e2e ("Failed to setup management databases",
923 //MOVED// setup_management ());
924 //MOVED// if (errno != 0) {
925 //MOVED// tlog (TLOG_DB, LOG_CRIT, "FATAL: Management databases setup failed: %s", strerror (errno));
930 /* Cleanup the structures and resources that were setup for handling TLS.
932 void cleanup_starttls (void) {
933 //MOVED// cleanup_management ();
934 if (onthefly_subjectkey != NULL) {
935 gnutls_x509_privkey_deinit (onthefly_subjectkey);
936 onthefly_subjectkey = NULL;
938 if (onthefly_issuercrt != NULL) {
939 gnutls_x509_crt_deinit (onthefly_issuercrt);
940 onthefly_issuercrt = NULL;
942 if (onthefly_issuerkey != NULL) {
943 gnutls_privkey_deinit (onthefly_issuerkey);
944 onthefly_issuerkey = NULL;
947 cleanup_starttls_credentials ();
949 cleanup_starttls_kerberos ();
952 gnutls_pkcs11_set_pin_function (NULL, NULL);
953 gnutls_pkcs11_set_token_function (NULL, NULL);
954 gnutls_pkcs11_deinit ();
955 gnutls_priority_deinit (priority_normal);
956 gnutls_global_deinit ();
961 * The copycat function is a bidirectional transport between the given
962 * remote and local sockets, but it will encrypt traffic from local to
963 * remote, and decrypt traffic from remote to local. It will do this
964 * until one of the end points is shut down, at which time it will
965 * return and assume the context will close down both pre-existing
968 * This copycat actually has a few sharp claws to watch for -- shutdown
969 * of sockets may drop the last bit of information sent. First, the
970 * signal POLLHUP is best ignored because it travels asynchronously.
971 * Second, reading 0 is a good indicator of end-of-file and may be
972 * followed by an shutdown of reading from that stream. But, more
973 * importantly, the other side must have this information forwarded
974 * so it can shutdown. This means that a shutdown for writing to that
975 * stream is to be sent. Even when *both* sides have agreed to not send
976 * anything, they may still not have received all they were offered for
977 * reading, so we should SO_LINGER on the sockets so they can acknowledge,
978 * and after a timeout we can establish that shutdown failed and log and
979 * return an error for it.
980 * Will you believe that I had looked up if close() would suffice? The man
981 * page clearly stated yes. However, these articles offer much more detail:
982 * http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable
983 * http://www.greenend.org.uk/rjk/tech/poll.html
985 * This function blocks during its call to poll(), in a state that can easily
986 * be restarted. This is when thread cancellation is temporarily enabled.
987 * Other threads may use this to cancel the thread and have it joined with that
988 * thread which will subsume its tasks and restart the handshake. We might
989 * later make this more advanced, by using a cancel stack push/pull mechanisms
990 * to ensure that recv() always results in send() in spite of cancellation.
992 * The return value of copycat is a GNUTLS_E_ code, usually GNUTLS_E_SUCCESS.
993 * For the moment, only one special value is of concern, namely
994 * GNUTLS_E_REHANDSHAKE which client or server side may receive when an
995 * attempt is made to renegotiate the security of the connection.
997 static int copycat (int local, int remote, gnutls_session_t wrapped, pool_handle_t client) {
999 struct pollfd inout [3];
1001 struct linger linger = { 1, 10 };
1003 int retval = GNUTLS_E_SUCCESS;
1005 client = INVALID_POOL_HANDLE;
1006 inout [0].fd = local;
1007 inout [1].fd = remote;
1011 inout [2].fd = client;
1012 have_client = inout [2].fd != INVALID_POOL_HANDLE;
1015 inout [2].revents = 0; // Will not be written by poll
1016 //FORK!=DETACH// inout [2].fd = ctlkey_signalling_fd;
1018 inout [0].events = POLLIN;
1019 inout [1].events = POLLIN;
1020 inout [2].events = 0; // error events only
1021 tlog (TLOG_COPYCAT, LOG_DEBUG, "Starting copycat cycle for local=%d, remote=%d, control=%d", local, remote, client);
1022 while (((inout [0].events | inout [1].events) & POLLIN) != 0) {
1024 assert (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) == 0);
1025 pthread_testcancel (); // Efficiency & Certainty
1026 polled = poll (inout, have_client? 3: 2, -1);
1027 assert (pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL) == 0);
1029 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat polling returned an error");
1030 break; // Polling sees an error
1032 if (inout [0].revents & POLLIN) {
1033 // Read local and encrypt to remote
1034 sz = recv (local, buf, sizeof (buf), RECV_FLAGS);
1035 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat received %d local bytes (or error<0) from %d", (int) sz, local);
1037 tlog (TLOG_COPYCAT, LOG_ERR, "Error while receiving: %s", strerror (errno));
1038 break; // stream error
1039 } else if (sz == 0) {
1040 inout [0].events &= ~POLLIN;
1041 shutdown (local, SHUT_RD);
1043 setsockopt (remote, SOL_SOCKET, SO_LINGER, (const char *) &linger, sizeof (linger));
1044 #else /* WINDOWS_PORT */
1045 setsockopt (remote, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
1046 #endif /* WINDOWS_PORT */
1047 gnutls_bye (wrapped, GNUTLS_SHUT_WR);
1048 } else if (gnutls_record_send (wrapped, buf, sz) != sz) {
1049 tlog (TLOG_COPYCAT, LOG_ERR, "gnutls_record_send() failed to pass on the requested bytes");
1050 break; // communication error
1052 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat sent %d bytes to remote %d", (int) sz, remote);
1055 if (inout [1].revents & POLLIN) {
1056 // Read remote and decrypt to local
1057 sz = gnutls_record_recv (wrapped, buf, sizeof (buf));
1058 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat received %d remote bytes from %d (or error if <0)", (int) sz, remote);
1060 //TODO// Process GNUTLS_E_REHANDSHAKE
1061 if (sz == GNUTLS_E_REHANDSHAKE) {
1062 tlog (TLOG_TLS, LOG_INFO, "Received renegotiation request over TLS handle %d", remote);
1063 retval = GNUTLS_E_REHANDSHAKE;
1065 } else if (gnutls_error_is_fatal (sz)) {
1066 tlog (TLOG_TLS, LOG_ERR, "GnuTLS fatal error: %s", gnutls_strerror (sz));
1067 break; // stream error
1069 tlog (TLOG_TLS, LOG_INFO, "GnuTLS recoverable error: %s", gnutls_strerror (sz));
1071 } else if (sz == 0) {
1072 inout [1].events &= ~POLLIN;
1073 shutdown (remote, SHUT_RD);
1075 setsockopt (local, SOL_SOCKET, SO_LINGER, (const char *) &linger, sizeof (linger));
1076 #else /* WINDOWS_PORT */
1077 setsockopt (local, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
1078 #endif /* WINDOWS_PORT */
1079 shutdown (local, SHUT_WR);
1080 } else if (send (local, buf, sz, RECV_FLAGS) != sz) {
1081 break; // communication error
1083 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat sent %d bytes to local %d", (int) sz, local);
1086 inout [0].revents &= ~(POLLIN | POLLHUP); // Thy copying cat?
1087 inout [1].revents &= ~(POLLIN | POLLHUP); // Retract thee claws!
1088 if ((inout [0].revents | inout [1].revents) & ~POLLIN) {
1089 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat data connection polling returned a special condition");
1090 break; // Apparently, one of POLLERR, POLLHUP, POLLNVAL
1092 #ifndef WINDOWS_PORT
1093 if (inout [2].revents & ~POLLIN) {
1095 // This case is currently not ever triggered
1096 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat control connection polling returned a special condition");
1097 break; // Apparently, one of POLLERR, POLLHUP, POLLNVAL
1099 inout [2].fd = client;
1100 have_client = inout [2].fd >= 0;
1102 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat signalling_fd polling raised a signal to set control fd to %d", inout [2].fd);
1104 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat signalling_fd polling raised a signal that could be ignored");
1109 #endif /* !WINDOWS_PORT */
1111 tlog (TLOG_COPYCAT, LOG_DEBUG, "Ending copycat cycle for local=%d, remote=%d", local, remote);
1116 /* The callback function that retrieves certification information from either
1117 * the client or the server in the course of the handshake procedure.
1119 gtls_error clisrv_cert_retrieve (gnutls_session_t session,
1120 const gnutls_datum_t* req_ca_dn,
1122 const gnutls_pk_algorithm_t* pk_algos,
1123 int pk_algos_length,
1124 gnutls_pcert_st** pcert,
1125 unsigned int *pcert_length,
1126 gnutls_privkey_t *pkey) {
1127 gnutls_certificate_type_t certtp;
1128 gnutls_pcert_st *pc = NULL;
1129 struct command *cmd;
1131 gnutls_datum_t privdatum = { NULL, 0 };
1132 gnutls_datum_t certdatum = { NULL, 0 };
1133 gnutls_openpgp_crt_t pgpcert = NULL;
1134 gnutls_openpgp_privkey_t pgppriv = NULL;
1135 int gtls_errno = GNUTLS_E_SUCCESS;
1139 char sni [sizeof (cmd->cmd.pio_data.pioc_starttls.localid)];
1140 size_t snilen = sizeof (sni);
1147 gtls_error fetch_local_credentials (struct command *cmd);
1148 gnutls_pcert_st *load_certificate_chain (uint32_t flags, unsigned int *chainlen, gnutls_datum_t *certdatum);
1151 // Setup a number of common references and structures
1154 cmd = (struct command *) gnutls_session_get_ptr (session);
1156 E_g2e ("No data pointer with session",
1157 GNUTLS_E_INVALID_SESSION);
1160 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
1161 lidrole = LID_ROLE_CLIENT;
1163 } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
1164 lidrole = LID_ROLE_SERVER;
1167 E_g2e ("TLS Pool command supports neither local client nor local server role",
1168 GNUTLS_E_INVALID_SESSION);
1171 lid = cmd->cmd.pio_data.pioc_starttls.localid;
1172 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
1175 // On a server, lookup the server name and match it against lid.
1176 // TODO: For now assume a single server name in SNI (as that is normal).
1177 if (lidrole == LID_ROLE_SERVER) {
1178 if (gnutls_server_name_get (session, sni, &snilen, &snitype, 0) || (snitype != GNUTLS_NAME_DNS)) {
1179 E_g2e ("Requested SNI error or not a DNS name",
1180 GNUTLS_E_NO_CERTIFICATE_FOUND);
1185 for (atidx=128; atidx > 0; atidx--) {
1186 if (lid [atidx-1] == '@') {
1190 if (strncmp (sni, lid + atidx, sizeof (sni)-atidx) != 0) {
1191 tlog (TLOG_TLS, LOG_ERR, "SNI %s does not match preset local identity %s", sni, lid);
1192 E_g2e ("Requested SNI does not match local identity",
1193 GNUTLS_E_NO_CERTIFICATE_FOUND);
1197 // TODO: Should ask for permission before accepting SNI
1198 memcpy (lid, sni, sizeof (sni));
1203 // Setup the lidtype parameter for responding
1205 certtp = gnutls_certificate_type_get_ours (session);
1207 certtp = gnutls_certificate_type_get (session);
1209 if (certtp == GNUTLS_CRT_OPENPGP) {
1210 tlog (TLOG_TLS, LOG_INFO, "Serving OpenPGP certificate request as a %s", rolestr);
1211 lidtype = LID_TYPE_PGP;
1212 } else if (certtp == GNUTLS_CRT_X509) {
1213 tlog (TLOG_TLS, LOG_INFO, "Serving X.509 certificate request as a %s", rolestr);
1214 lidtype = LID_TYPE_X509;
1216 } else if (certtp == GNUTLS_CRT_KRB) {
1217 tlog (TLOG_TLS, LOG_INFO, "Serving Kerberos Ticket request as a %s", rolestr);
1218 lidtype = LID_TYPE_KRB5;
1221 // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
1222 tlog (TLOG_TLS, LOG_ERR, "Funny sort of certificate %d retrieval attempted as a %s", certtp, rolestr);
1223 E_g2e ("Requested certtype is neither X.509 nor OpenPGP",
1224 GNUTLS_E_CERTIFICATE_ERROR);
1229 // Find the prefetched local identity to use towards this remote
1230 // Send a callback to the user if none is available and accessible
1231 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALID_CHECK) {
1232 uint32_t oldcmd = cmd->cmd.pio_cmd;
1233 struct command *resp;
1234 cmd->cmd.pio_cmd = PIOC_STARTTLS_LOCALID_V2;
1235 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Calling send_callback_and_await_response with PIOC_STARTTLS_LOCALID_V2");
1236 resp = send_callback_and_await_response (cmd, 0);
1237 assert (resp != NULL); // No timeout, should be non-NULL
1238 if (resp->cmd.pio_cmd != PIOC_STARTTLS_LOCALID_V2) {
1239 tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has unexpected command code");
1240 cmd->cmd.pio_cmd = oldcmd;
1241 return GNUTLS_E_CERTIFICATE_ERROR;
1243 assert (resp == cmd); // No ERROR, so should be the same
1244 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Processing callback response that sets plainfd:=%d and lid:=\"%s\" for rid==\"%s\"", cmd->passfd, lid, rid);
1245 cmd->cmd.pio_cmd = oldcmd;
1247 // Check that new rid is a generalisation of original rid
1248 // Note: This is only of interest for client operation
1249 if (lidrole == LID_ROLE_CLIENT) {
1250 selector_t newrid = donai_from_stable_string (rid, strlen (rid));
1251 donai_t oldrid = donai_from_stable_string (cmd->orig_starttls->remoteid, strlen (cmd->orig_starttls->remoteid));
1252 if (!donai_matches_selector (&oldrid, &newrid)) {
1253 return GNUTLS_E_NO_CERTIFICATE_FOUND;
1257 // Now reiterate to lookup lid credentials in db_localid
1258 E_g2e ("Missing local credentials",
1259 fetch_local_credentials (cmd));
1261 if (cmd->lids [lidtype - LID_TYPE_MIN].data == NULL) {
1262 fprintf (stderr, "DEBUG: Missing certificate for local ID %s and remote ID %s\n", lid, rid);
1263 E_g2e ("Missing certificate for local ID",
1264 GNUTLS_E_NO_CERTIFICATE_FOUND);
1269 // Split the credential into its various aspects
1270 ok = dbcred_interpret (
1271 &cmd->lids [lidtype - LID_TYPE_MIN],
1276 tlog (TLOG_DB, LOG_DEBUG, "BDB entry has flags=0x%08x, p11priv=\"%s\", cert.size=%d", flags, p11priv, certdatum.size);
1277 //TODO// ok = ok && verify_cert_... (...); -- keyidlookup
1279 gtls_errno = GNUTLS_E_CERTIFICATE_ERROR;
1283 // Allocate response structures
1285 *pcert = load_certificate_chain (flags, pcert_length, &certdatum);
1286 if (*pcert == NULL) {
1287 E_g2e ("Failed to load certificate chain",
1288 GNUTLS_E_CERTIFICATE_ERROR);
1291 cmd->session_certificate = (intptr_t) (void *) *pcert; //TODO// Used for session cleanup
1294 // Setup private key
1295 E_g2e ("Failed to initialise private key",
1296 gnutls_privkey_init (
1298 if ((onthefly_subjectkey != NULL) && (strcmp (p11priv, onthefly_p11uri) == 0)) {
1299 // Setup the on-the-fly certification key as private key
1300 E_g2e ("Failed to import on-the-fly subject private key",
1301 gnutls_privkey_import_x509 (
1303 onthefly_subjectkey,
1304 GNUTLS_PRIVKEY_IMPORT_COPY));
1306 } else if (lidtype == LID_TYPE_KRB5) {
1307 // Fake a private key for Kerberos (we sign it out here, not GnuTLS)
1308 E_g2e ("Failed to generate a private-key placeholder for Kerberos",
1309 gnutls_privkey_generate_krb (
1314 // Import the PKCS #11 key as the private key for use by GnuTLS
1315 if (gtls_errno == GNUTLS_E_SUCCESS) {
1316 cmd->session_privatekey = (intptr_t) (void *) *pkey; //TODO// Used for session cleanup
1318 E_g2e ("Failed to import PKCS #11 private key URI",
1319 gnutls_privkey_import_pkcs11_url (
1323 E_gnutls_clear_errno ();
1325 //TODO// Moved out (start)
1328 // Setup public key certificate
1331 E_g2e ("MOVED: Failed to import X.509 certificate into chain",
1332 gnutls_pcert_import_x509_raw (
1335 GNUTLS_X509_FMT_DER,
1339 E_g2e ("MOVED: Failed to import OpenPGP public key",
1340 gnutls_pcert_import_openpgp_raw (
1343 GNUTLS_OPENPGP_FMT_RAW,
1344 NULL, /* use master key */
1349 if (lidrole == LID_ROLE_CLIENT) {
1351 // KDH-Only or KDH-Enhanced; fetch ticket for localid
1352 // and a TGT based on it for service/remoteid@REALM
1354 // First, try to obtain a TGT and key, in various ways
1356 krb5_creds *tgt = NULL;
1358 krb5_ccache cc = NULL;
1360 memset (&ticket, 0, sizeof (ticket));
1361 memset (&key, 0, sizeof (key ));
1362 status = have_key_tgt_cc (
1369 // We never use this key ourselves
1370 krb5_free_keyblock_contents (krbctx_cli, &key);
1372 // #ifndef TOM_IS_WEG_EN_NU_GAAN_WE_ERVOOR
1374 // Stop processing when no tgt was found
1375 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1379 // Store client identity in session object
1380 if (0 != krb5_copy_principal (
1384 krb5_free_creds (krbctx_cli, tgt);
1387 krb5_cc_close (krbctx_cli, cc);
1390 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1394 // Now find a service ticket to talk to
1395 //TODO// Pass credcache instead?
1396 status = have_service_ticket (
1402 // We don't need cc anymore below
1403 krb5_cc_close (krbctx_cli, cc);
1406 // Stop processing when no ticket was found
1407 krb5_free_creds (krbctx_cli, tgt);
1409 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1413 // Only for KDH-Only mode can the client rely on a
1414 // server principal taken from the ticket;
1415 // So only store krbid_srv for KDH-Only mode.
1416 if ((gnutls_certificate_type_get_peers (cmd->session)
1417 == GNUTLS_CRT_KRB) &&
1418 (0 != krb5_copy_principal (
1421 &cmd->krbid_srv))) {
1422 krb5_free_cred_contents (krbctx_cli, &ticket);
1423 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1426 krb5_free_creds (krbctx_cli, tgt);
1428 certdatum.data = ticket.ticket.data;
1429 certdatum.size = ticket.ticket.length;
1431 // certdatum.data = "NEPPERD";
1432 // certdatum.size = 7;
1434 E_g2e ("MOVED: Failed to import Kerberos ticket",
1435 gnutls_pcert_import_krb_raw (
1439 // #ifdef TOM_IS_WEG
1440 krb5_free_cred_contents (krbctx_cli, &ticket);
1444 // For KDH-Only, the server supplies one of:
1445 // - an empty ticket (0 bytes long)
1446 // - a TGT for user-to-user mode (where considered useful)
1447 //TODO// E_g2e ("MOVED: Failed to import Kerberos ticket",
1448 //TODO// gnutls_pcert_import_krb_raw (
1450 //TODO// &certdatum, //TODO:WHATSFOUND//
1454 krb5_creds *tgt = NULL;
1456 // Determine whether we want to run in user-to-user mode
1457 // for which we should supply a TGT to the TLS client
1458 u2u = u2u || ((PIOF_STARTTLS_BOTHROLES_PEER & ~cmd->cmd.pio_data.pioc_starttls.flags) == 0);
1459 u2u = u2u || (strchr (rid, '@') != NULL);
1460 // u2u = u2u || "shaken hands on TLS symmetry extension"
1461 u2u = u2u && got_cc_srv; // We may simply not be able!
1463 // When not in user-to-user mode, deliver 0 bytes
1465 certdatum.data = "";
1467 E_g2e ("Failed to withhold Kerberos server ticket",
1468 gnutls_pcert_import_krb_raw (
1475 // Continue specifically for user-to-user mode.
1476 //TODO// Setup server principal identity
1478 // Fetch the service's key
1479 status = have_key_tgt_cc (
1481 1, 0, 0, // Hmm... later we know kvno/etype
1484 &cmd->krb_key, &tgt, NULL);
1486 // There's no use in having just the key
1487 krb5_free_keyblock_contents (krbctx_srv, &cmd->krb_key);
1488 memset (&cmd->krb_key, 0, sizeof (cmd->krb_key));
1491 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1492 } else if (0 != krb5_copy_principal (
1496 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1498 certdatum.data = tgt->ticket.data;
1499 certdatum.size = tgt->ticket.length;
1500 E_g2e ("Failed to withhold Kerberos server ticket",
1501 gnutls_pcert_import_krb_raw (
1505 krb5_free_creds (krbctx_cli, tgt);
1511 /* Should not happen */
1515 //TODO// Moved out (end)
1517 #ifdef ANCIENT_CODE_WHEN_DBERRNO_RAN_IN_PARALLEL
1519 // Lap up any overseen POSIX error codes in errno
1521 tlog (TLOG_TLS, LOG_DEBUG, "Failing TLS on errno=%d / %s", errno, strerror (errno));
1522 cmd->session_errno = errno;
1523 gtls_errno = GNUTLS_E_NO_CIPHER_SUITES; /* Vaguely matching */
1528 // Return the overral error code, hopefully GNUTLS_E_SUCCESS
1529 tlog (TLOG_TLS, LOG_DEBUG, "Returning %d / %s from clisrv_cert_retrieve()", gtls_errno, gnutls_strerror (gtls_errno));
1530 fprintf (stderr, "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);
1534 /* Load a single certificate in the given gnutls_pcert_st from the given
1535 * gnutls_datum_t. Use the lidtype to determine how to do this.
1537 gtls_error load_certificate (int lidtype, gnutls_pcert_st *pcert, gnutls_datum_t *certdatum) {
1538 int gtls_errno = GNUTLS_E_SUCCESS;
1540 // Setup public key certificate
1543 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]);
1544 E_g2e ("Failed to import X.509 certificate into chain",
1545 gnutls_pcert_import_x509_raw (
1548 GNUTLS_X509_FMT_DER,
1552 E_g2e ("Failed to import OpenPGP certificate",
1553 gnutls_pcert_import_openpgp_raw (
1556 GNUTLS_OPENPGP_FMT_RAW,
1557 NULL, /* use master key */
1561 /* Binary information is currently moot, so do not load it */
1564 /* Should not happen */
1571 /* Load a certificate chain. This returns a value for a retrieval function's
1572 * pcert, and also modifies the chainlen. The latter starts at 0, and is
1573 * incremented in a nested procedure that unrolls until all certificates are
1576 gnutls_pcert_st *load_certificate_chain (uint32_t flags, unsigned int *chainlen, gnutls_datum_t *certdatum) {
1577 gnutls_pcert_st *chain;
1578 unsigned int mypos = *chainlen;
1579 int gtls_errno = GNUTLS_E_SUCCESS;
1582 // Quick and easy: No chaining required, just add the literal data.
1583 // Note however, this may be the end of a chain, so allocate all
1584 // structures and load the single one at the end.
1585 if ((flags & (LID_CHAINED | LID_NEEDS_CHAIN)) == 0) {
1587 chain = (gnutls_pcert_st *) calloc (*chainlen, sizeof (gnutls_pcert_st));
1588 if (chain != NULL) {
1591 (*chainlen) * sizeof (gnutls_pcert_st));
1593 gtls_errno = GNUTLS_E_MEMORY_ERROR;
1595 E_g2e ("Failed to load certificate into chain",
1597 flags & LID_TYPE_MASK,
1600 if (gtls_errno != GNUTLS_E_SUCCESS) {
1611 // First extended case. Chain certs in response to LID_CHAINED.
1612 // Recursive calls are depth-first, so we only add our first cert
1613 // after a recursive call succeeds. Any LID_NEEDS_CHAIN work is
1614 // added after LID_CHAINED, so is higher up in the hierarchy, but
1615 // it is loaded as part of the recursion. To support that, a
1616 // recursive call with certdatum.size==0 is possible when the
1617 // LID_NEEDS_CHAIN flag is set, and this section then skips.
1618 // Note that this code is also used to load the certificate chain
1619 // provided by LID_NEEDS_CHAIN, but by then the flag in a recursive
1620 // call is replaced with LID_CHAINED and no more LID_NEEDS_CHAIN.
1621 if (((flags & LID_CHAINED) != 0) && (certdatum->size > 0)) {
1624 gnutls_datum_t nextdatum;
1626 // Note: Accept BER because the outside SEQUENCE is not signed
1627 certlen = asn1_get_length_ber (
1628 ((char *) certdatum->data) + 1,
1631 certlen += 1 + lenlen;
1632 tlog (TLOG_CERT, LOG_DEBUG, "Found LID_CHAINED certificate size %d", certlen);
1633 if (certlen > certdatum->size) {
1634 tlog (TLOG_CERT, LOG_ERR, "Refusing LID_CHAINED certificate beyond data size %d", certdatum->size);
1637 } else if (certlen <= 0) {
1638 tlog (TLOG_CERT, LOG_ERR, "Refusing LID_CHAINED certificate of too-modest data size %d", certlen);
1642 nextdatum.data = ((char *) certdatum->data) + certlen;
1643 nextdatum.size = certdatum->size - certlen;
1644 certdatum->size = certlen;
1645 nextlen = asn1_get_length_ber (
1646 ((char *) nextdatum.data) + 1,
1649 nextlen += 1 + lenlen;
1650 if (nextlen == nextdatum.size) {
1651 // The last cert is loaded thinking it is not CHAINED,
1652 // but NEEDS_CHAIN can still be present for expansion.
1653 flags &= ~LID_CHAINED;
1656 chain = load_certificate_chain (flags, chainlen, &nextdatum);
1657 if (chain != NULL) {
1658 E_g2e ("Failed to add chained certificate",
1660 flags & LID_TYPE_MASK,
1663 if (gtls_errno != GNUTLS_E_SUCCESS) {
1673 // Second extended case. Chain certs in response to LID_NEEDS_CHAIN.
1674 // These are the highest-up in the hierarchy, above any LID_CHAINED
1675 // certificates. The procedure for adding them is looking them up
1676 // in a central database by their authority key identifier. What is
1677 // found is assumed to be a chain, and will be unrolled by replacing
1678 // the LID_NEEDS_CHAIN flag with LID_CHAINED and calling recursively.
1679 if (((flags & LID_NEEDS_CHAIN) != 0) && (certdatum->size == 0)) {
1680 //TODO//CODE// lookup new certdatum
1681 flags &= ~LID_NEEDS_CHAIN;
1682 flags |= LID_CHAINED;
1683 //TODO//CODE// recursive call
1684 //TODO//CODE// no structures to fill here
1685 //TODO//CODE// cleanup new certdatum
1689 // Final judgement. Nothing worked. Return failure.
1696 /********** KERBEROS SUPPORT FUNCTIONS FOR TLS-KDH **********/
1700 /* Prepare the Kerberos resources for use by clients and/or servers.
1703 static int setup_starttls_kerberos (void) {
1706 int retval = GNUTLS_E_SUCCESS;
1707 krb5_ccache krb_cc_tmp;
1708 const char *cctype_cli = NULL;
1709 const char *cctype_srv = NULL;
1712 krbctx_cli = krbctx_srv = NULL;
1713 krb_kt_cli = krb_kt_srv = NULL;
1714 got_cc_cli = got_cc_srv = 0;
1716 // Construct credentials caching for Kerberos
1718 k5err = krb5_init_context (&krbctx_cli);
1721 k5err = krb5_init_context (&krbctx_srv);
1724 // Load the various configuration variables
1725 cfg = cfg_krb_client_keytab ();
1726 if ((k5err == 0) && (cfg != NULL)) {
1727 k5err = krb5_kt_resolve (krbctx_cli, cfg, &krb_kt_cli);
1729 cfg = cfg_krb_server_keytab ();
1730 if ((k5err == 0) && (cfg != NULL)) {
1731 k5err = krb5_kt_resolve (krbctx_srv, cfg, &krb_kt_srv);
1733 cfg = cfg_krb_client_credcache ();
1734 #if 0 /* Temporary bypass of cctype checks */
1735 if ((k5err == 0) && (cfg != NULL)) {
1736 k5err = krb5_cc_set_default_name (krbctx_cli, cfg);
1738 k5err = krb5_cc_default (krbctx_cli, &krb_cc_tmp);
1742 cctype_cli = krb5_cc_get_type (krbctx_cli, krb_cc_tmp);
1743 krb5_cc_close (krbctx_cli, krb_cc_tmp);
1747 cfg = cfg_krb_server_credcache ();
1748 #if 0 /* Temporary bypass of cctype checks */
1749 if ((k5err == 0) && (cfg != NULL)) {
1750 k5err = krb5_cc_set_default_name (krbctx_srv, cfg);
1752 k5err = krb5_cc_default (krbctx_srv, &krb_cc_tmp);
1756 cctype_srv = krb5_cc_get_type (krbctx_cli, krb_cc_tmp);
1757 krb5_cc_close (krbctx_srv, krb_cc_tmp);
1762 // Check for consistency and log helpful messages for the sysop
1764 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "Error during STARTTLS setup: %s (acting on %s)",
1765 krb5_get_error_message (krbctx_cli, k5err),
1767 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1769 if (krb_kt_cli != NULL) {
1770 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_WARNING, "Ignoring the configured kerberos_client_keytab -- it is not implemented yet");
1772 if (krb_kt_srv == NULL) {
1773 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "No kerberos_server_keytab configured, so Kerberos cannot work at all");
1774 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1775 /* TODO: Only for MIT krb5 1.11 and up
1776 } else if (0 == krb5_kt_have_content (krb_ctx, krb_kt_srv)) {
1777 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "Keytab in kerberos_server_keytab is absent or empty");
1778 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1781 if (krbctx_cli == NULL) {
1782 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "No kerberos_client_credcache configured, so Kerberos cannot work at all");
1783 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1784 #if 0 /* Temporary bypass of cctype checks */
1785 } else if (!krb5_cc_support_switch (
1786 krbctx_cli, cctype_cli)) {
1787 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "Your kerberos_client_credcache does not support multilpe identities");
1788 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1791 if (krbctx_srv == NULL) {
1792 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_WARNING, "No kerberos_server_credcache configured, so user-to-user Kerberos will not work");
1793 #if 0 /* Temporary bypass of cctype checks */
1794 } else if (!krb5_cc_support_switch (
1795 krbctx_srv, cctype_srv)) {
1796 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "Your kerberos_server_credcache does not support multilpe identities");
1797 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1800 if (retval != GNUTLS_E_SUCCESS) {
1801 cleanup_starttls_kerberos ();
1808 /* Cleanup Kerberos resources. This must be an idempotent function, because
1809 * it is called when Kerberos panics as well as when
1812 static void cleanup_starttls_kerberos (void) {
1813 if (krb_kt_srv != NULL) {
1814 krb5_kt_close (krbctx_srv, krb_kt_srv);
1817 if (krb_kt_cli != NULL) {
1818 krb5_kt_close (krbctx_cli, krb_kt_cli);
1821 if (krbctx_srv != NULL) {
1822 krb5_free_context (krbctx_srv);
1825 if (krbctx_cli != NULL) {
1826 krb5_free_context (krbctx_cli);
1833 /* Prompter callback function for PKCS #11.
1835 * TODO: Use "struct pkcs11iter" as data, possibly interact with the user,
1836 * and keep a score on where we stand with password entry and changes.
1837 * Create clisrv_p11krb_setup() and clisrv_p11krb_cleanup() functions.
1839 * In the current release for Kerberos, we have a very minimal mode for
1840 * doing this. We may embellish it later or, preferrably, turn to a more
1841 * PKCS #11 styled approach, perhaps PKINIT or FAST.
1844 static krb5_error_code clisrv_p11krb_callback (krb5_context ctx,
1849 krb5_prompt prompts []) {
1850 struct command *cmd = (struct command *) vcmd;
1852 krb5_prompt_type *codes = krb5_get_prompt_types (ctx);
1854 static const char *token_url = "pkcs11:manufacturer=Kerberos+infrastructure;model=TLS+Pool;serial=%28none%29";
1855 static const char *token_label = "Kerberos infrastructure";
1856 for (i=0; i<num_prompts; i++) {
1858 // Visit each prompt in turn, setting responses or return failure
1859 switch (codes [i]) {
1860 case KRB5_PROMPT_TYPE_PASSWORD:
1861 //TODO// Read a password from PKCS #11
1862 //TODO// Do we need to cycle passwords to cover retry?
1863 //TODO// Delete any failed passwords?
1865 if (attempt >= MAX_P11ITER_ATTEMPTS) {
1866 return KRB5_LIBOS_CANTREADPWD;
1868 // Nothing in PKCS #11 --> so fallback on manual entry
1869 if (!pin_callback (attempt,
1870 token_url, "Enter Kerberos password:",
1871 prompts [i].reply->data,
1872 prompts [i].reply->length)) {
1873 memset (prompts [i].reply->data, 0, prompts [i].reply->length);
1874 return KRB5_LIBOS_CANTREADPWD;
1876 //TODO// Manage data structure
1877 prompts [i].reply->length = strlen (prompts [i].reply->data);
1879 case KRB5_PROMPT_TYPE_NEW_PASSWORD:
1880 case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
1881 //TODO// Setup new password in PKCS #11
1882 case KRB5_PROMPT_TYPE_PREAUTH:
1883 //TODO// Use FAST, PKINIT, and so on...
1885 // Unrecognised and unimplemented prompt types end here
1886 return KRB5_LIBOS_CANTREADPWD;
1894 /* Find a Kerberos keyblock and ticket to use for the localid. Do not look
1895 * into services yet in this function. This function implements a simple
1896 * procedure, based on optional arguments p11uri, keytab, credcache. It
1897 * produces <key,tgt> or <key,NULL> or (for errors) <NULL,NULL>.
1899 * The procedure followed, fully written out, is outlined below:
1901 * IF have(credcache) AND acceptable (renewable) time
1902 * THEN RETURN <key,tgt>
1903 * ELSE IF have (keytab) AND found a suitable key
1904 * THEN IF have(credcache) and it works
1905 * THEN fetch cred tgt and key (auth with key in keytab)
1908 * ELSE RETURN <key,NULL>
1909 * ELSE IF have(p11uri) AND it works
1910 * THEN fetch cred tgt and key (auth with pwd in p11uri)
1913 * ELSE RETURN <NULL,NULL>
1915 * The function returns a status value counting the number of values returned,
1916 * so 0 means error, 1 means key only and 2 means key and tgt.
1919 static int have_key_tgt_cc (struct command *cmd, // in, session context
1920 krb5_context ctx, // in, kerberos context
1921 bool use_cc, // in, whether to use cc
1922 krb5_kvno kvno, // in, kvno (0 for highest)
1923 krb5_enctype enctype,// in, enctype (0 for any)
1924 char *p11uri, // in/opt, PKCS #11 pwd URI
1925 krb5_keytab kt, // in/opt, keytab
1926 krb5_keyblock *key, // opt/opt session key
1927 krb5_creds **tgt, // out/opt, tkt granting tkt
1928 krb5_ccache *cc) { // out/opt, cred cache
1930 krb5_ccache newcc = NULL;
1931 krb5_principal sought = NULL;
1932 krb5_principal sought1 = NULL;
1933 krb5_principal tgtname = NULL;
1934 krb5_keytab_entry ktentry;
1935 const char *svc = cmd->cmd.pio_data.pioc_starttls.service;
1936 const char *lid = cmd->cmd.pio_data.pioc_starttls.localid;
1941 uint32_t nametype, nametype_alt;
1944 // Assertions, and initialise variables
1945 assert ( cmd != NULL);
1946 assert ( ctx != NULL);
1947 assert ( key != NULL);
1948 assert (*tgt == NULL);
1949 krb5_free_keyblock_contents (ctx, key);
1954 // Construct the realm name
1955 liddom = strrchr (lid, '@');
1956 if (liddom != NULL) {
1957 lid1len = ((intptr_t) liddom) - ((intptr_t) lid);
1958 liddom++; // Skip '@'
1960 liddom = lid; // localid is a host
1961 lid1len = strnlen (lid, 128);
1963 k5err = krb5_get_host_realm (ctx, liddom, &realms);
1964 if ((k5err == 0) && (realms [0] != NULL) && (*realms [0] != '\0')) {
1965 strncpy (realm, realms [0], sizeof (realm));
1966 realm [sizeof (realm)-1] = '\0';
1971 realm [i] = toupper (liddom [i]);
1973 } while (liddom [i-1] != '\0');
1975 strcpy (realm, "ARPA2.NET");
1979 krb5_free_host_realm (ctx, realms);
1984 // Construct a sought principal name in a given naming style,
1985 // and try to locate it in the existing cache.
1986 // With @, try liduser@liddom@REALM or else liduser@REALM
1987 // Without @, try svc/liddom@REALM
1988 nametype = (lid == liddom) ? KRB5_NT_SRV_HST : KRB5_NT_ENTERPRISE_PRINCIPAL;
1990 nametype_alt = nametype;
1992 case KRB5_NT_ENTERPRISE_PRINCIPAL:
1993 nametype_alt = KRB5_NT_PRINCIPAL;
1994 k5err = krb5_build_principal_ext (ctx, &sought,
1995 strlen (realm), realm,
1996 strnlen (lid, 128), lid,
1999 case KRB5_NT_SRV_HST:
2000 if (strcmp (svc, "http") == 0) {
2003 k5err = krb5_build_principal_ext (ctx, &sought,
2004 strlen (realm), realm,
2009 case KRB5_NT_PRINCIPAL:
2010 k5err = krb5_build_principal_ext (ctx, &sought,
2011 strlen (realm), realm,
2017 sought->type = nametype;
2021 k5err = krb5_cc_cache_match (ctx, sought, &newcc);
2023 if ((nametype_alt != nametype) && (sought1 == NULL)) {
2024 nametype = nametype_alt;
2030 // We failed to find an *existing* credentials cache
2031 // for the local identity.
2033 // Our new hope is to create a fresh credential, and add
2034 // it to the current credcache. To that end, we now try
2035 // to overrule k5err by getting hold of our default cc.
2039 // Construct the TGT name
2040 k5err = krb5_build_principal_ext (ctx, &tgtname,
2041 strlen (realm), realm,
2043 strlen (realm), realm,
2049 tgtname->type = KRB5_NT_SRV_INST;
2051 // Try to get the service ticket for the TGT name from the cache
2053 memset (&credreq, 0, sizeof (credreq));
2054 credreq.client = sought;
2055 credreq.server = tgtname;
2056 k5err = krb5_get_credentials (ctx,
2057 /* KRB5_GC_USER_USER ?|? */
2058 ( use_cc ? 0 : KRB5_GC_CACHED ),
2063 && (now + 300 > (*tgt)->times.endtime)
2064 && (now + 300 < (*tgt)->times.renew_till)) {
2065 //TODO:NOTHERE// krb5_free_creds (ctx, *tgt);
2066 //TODO:NOTHERE// *tgt = NULL;
2067 // Try to renew the ticket
2068 k5err = krb5_get_renewed_creds (ctx,
2072 NULL); /* krbtgt/REALM@REALM */
2075 && (now + 300 > (*tgt)->times.endtime)) {
2076 // Thanks, but no thanks!
2077 krb5_free_creds (ctx, *tgt);
2082 // First case worked -- return <key,tgt> from credout
2083 k5err = krb5_copy_keyblock_contents (ctx,
2086 // On failure, key shows failure
2095 // Prior attempts failed. Instead, look for keytab or p11uri presence.
2096 // This is skipped when the use_cc option below welcomes krb5_creds.
2097 if ((key->contents == NULL) && (p11uri == NULL) && (kt == NULL)) {
2098 // We cannot obtain a new krbtgt
2099 // We simply return what we've got (which may be nothing)
2102 if ((kt == NULL) && (!use_cc)) {
2103 // We have nowhere to store a new krbtgt if we got it
2104 // We simply return what we've got (which is at least a key)
2108 // Either we have a keytab key, or we have a p11uri,
2109 // so we can attempt to create a new credcache with a new krbtgt
2111 if (newcc == NULL) {
2112 k5err = krb5_cc_default (ctx, &newcc);
2114 // Utter failure to do even the simplest thing
2118 *tgt = malloc (sizeof (**tgt));
2123 memset (*tgt, 0, sizeof (**tgt));
2124 if ((sought != NULL) && (sought1 == NULL)) {
2125 // We only tried one name
2130 if (sought1 == NULL) {
2133 if (p11uri == NULL) {
2134 k5err = krb5_get_init_creds_keytab (
2139 0, /* start now please */
2140 NULL, /* get a TGT please */
2141 NULL); //TODO// opts needed?
2143 //TODO// Prepare PKCS #11 access
2144 k5err = krb5_get_init_creds_password (
2149 NULL, // Use callbacks for password
2150 clisrv_p11krb_callback,
2155 cmd, /* callback data pointer */
2156 0, /* start now please */
2157 NULL, /* get a TGT please */
2158 NULL); //TODO// opts needed?
2159 //TODO// End PKCS #11 access
2162 krb5_free_principal (ctx, sought1);
2166 } while (k5err != 0);
2168 // Failed to initiate new credentials
2169 krb5_free_creds (ctx, *tgt);
2173 #ifdef TOM_IS_WEG_EN_IK_SNAP_WAAROM_KRB5_FCC_NOFILE
2175 if (sought1 != NULL) {
2176 k5err = krb5_cc_initialize (ctx, newcc, sought1);
2178 k5err = krb5_cc_store_cred (ctx, newcc, *tgt);
2182 // Copy the keyblock; any failure will show up in key
2183 krb5_copy_keyblock_contents (ctx,
2187 // We succeeded in setting up a new Ticket Granting Ticket!
2195 // As a last resort, dig up a key directly from the keytab;
2196 // this is the only place where kvno and enctype are used
2198 //NOTE// Might be more direct as krb5_kt_read_service_key()
2199 k5err = krb5_kt_get_entry (
2205 k5err = krb5_copy_keyblock_contents (ctx,
2208 krb5_free_keytab_entry_contents (ctx, &ktentry);
2209 // On failure, key shows failure.
2218 // Nothing more to try, so we continue into cleanup
2221 // Cleanup and return the <key,tgt> values as they were delivered
2222 if (sought1 != NULL) {
2223 krb5_free_principal (ctx, sought1);
2226 if (sought != NULL) {
2227 krb5_free_principal (ctx, sought);
2230 if (tgtname != NULL) {
2231 krb5_free_principal (ctx, tgtname);
2234 if (newcc != NULL) {
2235 krb5_cc_close (ctx, newcc);
2238 if (key->contents == NULL) {
2240 const char *errmsg = krb5_get_error_message (ctx, k5err);
2241 tlog (TLOG_DAEMON, LOG_ERR, "Kerberos error: %s", errmsg);
2242 krb5_free_error_message (ctx, errmsg);
2245 krb5_free_creds (ctx, *tgt);
2248 if ((cc != NULL) && (*cc != NULL)) {
2249 krb5_cc_close (ctx, *cc);
2253 } else if (tgt == NULL) {
2254 if ((cc != NULL) && (*cc != NULL)) {
2255 krb5_cc_close (ctx, *cc);
2259 } else if ((cc == NULL) || (*cc == NULL)) {
2268 /* Have a ticket for the remote service. Do this as a client. The client
2269 * principal and realm are provided, and the ticket to be returned will
2270 * also provide the accompanying key.
2272 * This function will incorporate the peer TGT, when it is provided. This
2273 * is the case in KDH-Only exchanges with a non-empty Server Certificate.
2275 * TODO: We are not currently serving backend tickets, but these could be
2276 * passed in as authorization data along with the credential request.
2277 * Note however, that authorization data is copied by default from the TGT,
2278 * but not necessarily from the request. Not without KDC modifications.
2279 * But then again, the KDC should have responded with an error that it was
2280 * missing backend services; this is not something the client should decide
2281 * on, and certainly not after being requested by the service. The error
2282 * and recovery could be implemented here (if we can get the error info out
2283 * of the libkrb5 API). Alternatively, we might consider passing the
2284 * authorization data in the authenticator since we get to control it.
2285 * What will the specification say?
2287 * The return value indicates how many of the requested output values have
2288 * been provided, counting from the first. So, 0 means a total failure and
2289 * anything higher is a (partial) success.
2292 static int have_service_ticket (
2293 struct command *cmd, // in, session context
2294 krb5_context ctx, // in, kerberos context
2295 krb5_ccache cc_opt, // in/opt, credcache
2296 krb5_principal cli, // in, client principal
2297 krb5_creds *ticket) { // out, tkt granting tkt
2299 krb5_ccache cc = cc_opt;
2301 krb5_principal srv = NULL;
2305 // Sanity checks and initialisation
2306 memset (&tkt_srv, 0, sizeof (tkt_srv));
2307 memset (&credreq, 0, sizeof (credreq));
2309 // Determine the optional cc parameter if it was not provided
2310 //TODO// This can go if we always get it passed from have_key_tgt_cc()
2312 k5err = krb5_cc_cache_match (ctx, cli, &cc);
2318 // Build the server's principal name
2319 const char *svc = cmd->cmd.pio_data.pioc_starttls.service;
2320 const char *rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
2324 riddom = strrchr (rid, '@');
2325 if (riddom != NULL) {
2326 riddom++; // Skip '@'
2328 riddom = rid; // localid is a host
2330 k5err = krb5_get_host_realm (ctx, riddom, &realms);
2331 if ((k5err == 0) && (realms [0] != NULL) && (*realms [0] != '\0')) {
2332 strncpy (realm, realms [0], sizeof (realm));
2333 realm [sizeof (realm)-1] = '\0';
2338 realm [i] = toupper (riddom [i]);
2340 } while (riddom [i-1] != '\0');
2342 strcpy (realm, "ARPA2.NET");
2346 krb5_free_host_realm (ctx, realms);
2350 if (strcmp (svc, "http") == 0) {
2353 k5err = krb5_build_principal_ext (ctx, &srv,
2354 strlen (realm), realm,
2361 srv->type = KRB5_NT_SRV_HST;
2363 // Construct credential request
2364 credreq.client = cli;
2365 credreq.server = srv;
2366 //TODO// credreq.authdata may be used for backend service tickets
2368 // See if our peer provided us with a TGT
2369 // - we are sure of GNUTLS_CRD_CERTIFICATE because we implement it now
2370 // - we must ensure that this is KDH-Only (remote GNUTLS_CRT_KRB)
2371 // - we must ensure that the remote provided a non-empty ticket
2372 if (gnutls_certificate_type_get_peers (cmd->session) == GNUTLS_CRT_KRB) {
2373 // This is KDH-Only -- and the server may present a TGT
2374 const gnutls_datum_t *opt_srv_tkt;
2375 unsigned int srv_tkt_count;
2376 opt_srv_tkt = gnutls_certificate_get_peers (cmd->session, &srv_tkt_count);
2377 if ((opt_srv_tkt != NULL) && (srv_tkt_count >= 1) && (opt_srv_tkt [0].size > 5)) {
2378 // Looks good, we'll use only the first (normally only) one
2379 credreq.second_ticket.data = opt_srv_tkt [0].data;
2380 credreq.second_ticket.length = opt_srv_tkt [0].size;
2381 u2u = KRB5_GC_USER_USER;
2385 // Fetch the ticket for the service
2387 k5err = krb5_get_credentials (ctx, u2u, cc, &credreq, &ticket);
2389 krb5_tkt_creds_context credsctx = NULL;
2390 k5err = krb5_tkt_creds_init (ctx, cc, &credreq, u2u, &credsctx);
2392 k5err = krb5_tkt_creds_get (ctx, credsctx);
2394 ticket = malloc (sizeof (*ticket));
2395 if (ticket != NULL) {
2396 k5err = krb5_tkt_creds_get_creds (ctx, credsctx, ticket);
2398 krb5_free_creds (ctx, ticket);
2403 krb5_tkt_creds_free (ctx, credsctx);
2407 // Cleanup and return; the return value depends on k5err
2409 if ((cc != NULL) && (cc_opt == NULL)) {
2410 //TODO// This can go if we always get it passed from have_key_tgt_cc()
2411 krb5_cc_close (ctx, cc);
2415 krb5_free_principal (ctx, srv);
2417 return (k5err == 0) ? 1 : 0;
2422 /* DER utility: This should probably appear in Quick DER sometime soon.
2424 * Pack an Int32 or UInt32 and return the number of bytes. Do not pack a header
2425 * around it. The function returns the number of bytes taken, even 0 is valid.
2427 typedef uint8_t QDERBUF_INT32_T [4];
2428 dercursor qder2b_pack_int32 (uint8_t *target_4b, int32_t value) {
2431 retval.derptr = target_4b;
2433 while (shift >= 0) {
2434 if ((retval.derlen == 0) && (shift > 0)) {
2435 // Skip sign-extending initial bytes
2436 uint32_t neutro = (value >> (shift - 1) ) & 0x000001ff;
2437 if ((neutro == 0x000001ff) || (neutro == 0x00000000)) {
2442 target_4b [retval.derlen] = (value >> shift) & 0xff;
2448 typedef uint8_t QDERBUF_UINT32_T [5];
2449 dercursor qder2b_pack_uint32 (uint8_t *target_5b, uint32_t value) {
2452 if (value & 0x80000000) {
2456 retval = qder2b_pack_int32 (target_5b + ofs, (int32_t) value);
2457 retval.derptr -= ofs;
2458 retval.derlen += ofs;
2463 /* DER utility: This should probably appear in Quick DER sometime soon.
2465 * Unpack an Int32 or UInt32 from a given number of bytes. Do not assume a header
2466 * around it. The function returns the value found.
2468 * Out of range values are returned as 0. This value only indicates invalid
2469 * return when len > 1, so check for that.
2471 int32_t qder2b_unpack_int32 (dercursor data4) {
2474 if (data4.derlen > 4) {
2477 if ((data4.derlen > 0) && (0x80 & *data4.derptr)) {
2480 for (idx=0; idx<data4.derlen; idx++) {
2482 retval += data4.derptr [idx];
2487 uint32_t qder2b_unpack_uint32 (dercursor data5) {
2488 uint32_t retval = 0;
2490 if (data5.derlen > 5) {
2493 if (data5.derlen == 5) {
2494 if (*data5.derptr != 0x00) {
2497 // Modify the local copy on our stack
2501 retval = (uint32_t) qder2b_unpack_int32 (data5);
2507 /* The callback function that retrieves a TLS-KDH "signature", which is kept
2508 * outside of GnuTLS. The callback computes an authenticator encrypted to
2509 * the session's Kerberos key.
2512 static gtls_error cli_kdhsig_encode (gnutls_session_t session,
2513 gnutls_datum_t *enc_authenticator,
2514 gnutls_datum_t *dec_authenticator,
2515 const gnutls_datum_t *hash,
2516 int32_t checksum_type) {
2518 // Variables, sanity checking, initialisation
2519 struct command *cmd;
2521 authenticator_t auth;
2522 QDERBUF_INT32_T derv5;
2523 QDERBUF_INT32_T dernametype;
2524 QDERBUF_INT32_T dercksumtype;
2525 krb5_keyblock subkey;
2526 gnutls_certificate_type_t peercert;
2527 QDERBUF_INT32_T dersubkey;
2528 krb5_timestamp now_s;
2529 char derctime [100];
2531 QDERBUF_INT32_T dercusec;
2533 enc_authenticator->data = strdup ("HushHushTralalaToereloere");
2534 enc_authenticator->size = 25;
2535 dec_authenticator->data = strdup ("PushPushTralalaToereloere");
2536 dec_authenticator->size = 25;
2539 cmd = (struct command *) gnutls_session_get_ptr (session);
2540 memset (&auth, 0, sizeof (auth));
2541 memset (&subkey, 0, sizeof (subkey));
2542 assert (cmd->krbid_cli != NULL);
2543 assert (cmd->krb_key.contents != NULL);
2544 static const uint8_t auth_packer [] = { DER_PACK_rfc4120_Authenticator };
2545 static const uint8_t encdata_packer [] = { DER_PACK_rfc4120_EncryptedData };
2547 // Setup secure hash in authenticator (never optional for TLS-KDH)
2548 auth.cksum.cksumtype = qder2b_pack_int32 (dercksumtype, checksum_type);
2550 // Optionally include a subkey (namely, for KDH-Only)
2551 peercert = gnutls_certificate_type_get_peers (session);
2552 if (peercert == GNUTLS_CRT_KRB) {
2553 // This is KDH-Only, for which we MUST create a random subkey
2554 k5err = krb5_c_make_random_key (
2556 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
2559 return GNUTLS_E_ENCRYPTION_FAILED;
2561 auth.subkey.keytype = qder2b_pack_int32 (dersubkey, subkey.enctype);
2562 auth.subkey.keyvalue.derptr = subkey.contents;
2563 auth.subkey.keyvalue.derlen = subkey.length;
2566 // Setup the client realm and principal name
2567 auth.crealm.derptr = cmd->krbid_cli->realm.data;
2568 auth.crealm.derlen = cmd->krbid_cli->realm.length;
2569 auth.cname.name_type = qder2b_pack_int32 (dernametype, cmd->krbid_cli->type);
2570 // The SEQUENCE OF with just one component is trivial to prepack
2571 auth.cname.name_string.derptr = cmd->krbid_cli->data [0].data;
2572 auth.cname.name_string.derlen = cmd->krbid_cli->data [0].length;
2574 // Setup the Kerberos version number (5)
2575 auth.authenticator_vno = qder2b_pack_int32 (derv5, 5);
2577 // Setup the obliged microsecond timer values (ignore error returns)
2578 krb5_us_timeofday (krbctx_cli, &now_s, &now_us);
2579 krb5_timestamp_to_string (now_s, derctime, sizeof (derctime));
2580 derctime [sizeof (derctime)-1] = '\0';
2581 auth.ctime.derptr = derctime;
2582 auth.ctime.derlen = strlen (derctime);
2583 auth.cusec = qder2b_pack_int32 (dercusec, now_us);
2585 // Pack the decoded result into dec_authenticator
2586 size_t declen = der_pack ( auth_packer,
2587 (const dercursor *) &auth,
2588 NULL // Measure length, no output yet
2590 uint8_t *decptr = malloc (declen);
2591 if (decptr == NULL) {
2592 return GNUTLS_E_MEMORY_ERROR;
2594 der_pack ( auth_packer,
2595 (const dercursor *) &auth,
2598 if (0 != krb5_c_encrypt_length (krbctx_cli,
2599 cmd->krb_key.enctype,
2603 return GNUTLS_E_ENCRYPTION_FAILED;
2605 uint8_t *rawptr = malloc (rawlen);
2606 if (rawptr == NULL) {
2608 return GNUTLS_E_MEMORY_ERROR;
2611 krb5_enc_data rawdata;
2612 memset (&decdata, 0, sizeof (decdata));
2613 memset (&rawdata, 0, sizeof (rawdata));
2614 decdata.data = decptr;
2615 decdata.length = declen;
2616 rawdata.ciphertext.data = rawptr;
2617 rawdata.ciphertext.length = rawlen;
2618 if (0 != krb5_c_encrypt ( krbctx_cli,
2620 11 /* stealing key usage from AP-REQ */,
2626 return GNUTLS_E_ENCRYPTION_FAILED;
2629 // Prepare the header information
2630 QDERBUF_INT32_T deretype;
2631 QDERBUF_UINT32_T derkvno;
2632 encrypted_data_t encdata;
2633 encdata.etype = qder2b_pack_int32 (deretype, cmd->krb_key.enctype);
2634 //NOT// encdata.kvno = qder2b_pack_int32 (derkvno, cmd->krb_key.kvno);
2635 encdata.cipher.derptr = rawdata.ciphertext.data;
2636 encdata.cipher.derlen = rawdata.ciphertext.length;
2638 // Prepare for packing the header and rawdata as EncryptedData
2639 size_t enclen = der_pack ( encdata_packer,
2640 (const dercursor *) &encdata,
2641 NULL // Measure length, no output yet
2643 uint8_t *encptr = malloc (enclen);
2644 if (encptr == NULL) {
2647 return GNUTLS_E_MEMORY_ERROR;
2649 der_pack ( encdata_packer,
2650 (const dercursor *) &encdata,
2654 // Return our final verdict on the generation of the Authenticator
2655 dec_authenticator->data = decptr;
2656 dec_authenticator->size = declen;
2657 enc_authenticator->data = encptr;
2658 enc_authenticator->size = enclen;
2664 /* The callback function that verifies a TLS-KDH "signature", which is kept
2665 * outside of GnuTLS. The callback verifies the authenticator against the
2666 * provided session hash and returns the decrypted authenticator.
2669 static int srv_kdhsig_decode (gnutls_session_t session,
2670 const gnutls_datum_t *enc_authenticator,
2671 gnutls_datum_t *dec_authenticator,
2672 gnutls_datum_t *hash,
2673 int32_t *checksum_type) {
2675 // Variables, sanity checks and initialisation
2676 struct command *cmd;
2677 static const uint8_t encdata_packer [] = { DER_PACK_rfc4120_EncryptedData };
2678 static const uint8_t auth_packer [] = { DER_PACK_rfc4120_Authenticator };
2679 encrypted_data_t encdata;
2680 cmd = (struct command *) gnutls_session_get_ptr (session);
2682 // Retrieve the session key and store it in cmd->krb_key.
2684 // Prior setting of cmd->krb_key would be due to user-to-user mode
2685 // having been setup with this as the server-supplied TGT key, in
2686 // which case cmd->krb_key would need to be overwritten by the
2689 // When no prior cmd->krb_key is available, use the keytab to
2690 // decode the client's ticket.
2691 assert (gnutls_certificate_type_get_peers (session) == GNUTLS_CRT_KRB);
2692 const gnutls_datum_t *certs;
2693 unsigned int num_certs;
2694 certs = gnutls_certificate_get_peers (cmd->session, &num_certs);
2695 if (num_certs != 1) {
2696 return GNUTLS_E_NO_CERTIFICATE_FOUND;
2700 krbcert.data = certs [0].data;
2701 krbcert.length = certs [0].size;
2702 if (0 != krb5_decode_ticket (&krbcert, &tkt)) {
2703 return GNUTLS_E_NO_CERTIFICATE_FOUND;
2706 if (cmd->krb_key.contents != NULL) {
2707 // user-to-user mode
2708 if (0 != krb5_decrypt_tkt_part (
2709 krbctx_srv, &cmd->krb_key, tkt)) {
2712 krb5_free_keyblock_contents (krbctx_srv, &cmd->krb_key);
2714 // client-to-server mode
2715 if (0 != krb5_server_decrypt_ticket_keytab (
2716 krbctx_srv, krb_kt_srv, tkt)) {
2720 if (0 != krb5_copy_keyblock_contents (
2722 tkt->enc_part2->session,
2726 if (0 != krb5_copy_principal ( krbctx_srv,
2727 tkt->enc_part2->client,
2731 if (cmd->krbid_srv->data != NULL) {
2732 if (!krb5_principal_compare ( krbctx_srv,
2735 // Server name changed since u2u setup -- not permitted
2739 if (0 != krb5_copy_principal ( krbctx_srv,
2745 krb5_free_ticket (krbctx_srv, tkt);
2747 return GNUTLS_E_NO_CERTIFICATE_FOUND;
2750 // Harvest the EncryptedData fields from the enc_authenticator
2751 dercursor enctransport;
2752 enctransport.derptr = enc_authenticator->data;
2753 enctransport.derlen = enc_authenticator->size;
2754 if (0 != der_unpack ( &enctransport,
2756 (dercursor *) &encdata,
2758 return GNUTLS_E_DECRYPTION_FAILED;
2760 if (encdata.kvno.derptr != NULL) {
2761 return GNUTLS_E_DECRYPTION_FAILED;
2763 int32_t etype = qder2b_unpack_int32 (encdata.etype);
2765 // Decrypt the EncryptedData fields into the dec_authenticator
2766 krb5_enc_data rawdata;
2768 memset (&rawdata, 0, sizeof (rawdata));
2769 memset (&decdata, 0, sizeof (decdata));
2770 rawdata.enctype = etype;
2771 rawdata.ciphertext.data = encdata.cipher.derptr;
2772 rawdata.ciphertext.length = encdata.cipher.derlen;
2773 decdata.data = dec_authenticator->data;
2774 decdata.length = dec_authenticator->size;
2775 if (0 != krb5_c_decrypt ( krbctx_srv,
2777 11 /* stealing key usage from AP-REQ */,
2781 return GNUTLS_E_DECRYPTION_FAILED;
2783 dec_authenticator->size = decdata.length;
2785 // Unpack the decrypted Authenticator
2786 dercursor decsyntax;
2787 decsyntax.derptr = decdata.data;
2788 decsyntax.derlen = decdata.length;
2789 authenticator_t auth;
2790 if (0 != der_unpack ( &decsyntax,
2792 (dercursor *) &auth,
2794 return GNUTLS_E_DECRYPTION_FAILED;
2797 // Validate the contents of the Authenticator
2798 if (qder2b_unpack_int32 (auth.authenticator_vno) != 5) {
2799 return GNUTLS_E_DECRYPTION_FAILED;
2801 if (auth.cksum.checksum.derptr == NULL) {
2802 return GNUTLS_E_DECRYPTION_FAILED;
2804 if (auth.cksum.checksum.derlen < 16) {
2805 return GNUTLS_E_DECRYPTION_FAILED;
2807 //TODO// Optionally, for KDH-Only, ensure presence and size of a subkey
2809 // Produce the requested content from the Authenticator and return
2810 *checksum_type = qder2b_unpack_int32 (auth.cksum.cksumtype);
2811 hash->data = auth.cksum.checksum.derptr;
2812 hash->size = auth.cksum.checksum.derlen;
2819 /********** VALIDATION EXPRESSION LINKUP TO GNUTLS **********/
2824 * The following functions implement the various validation expression
2825 * components in terms of the GnuTLS sessions of this code file.
2826 * Some work is repeated in various expression variables, notably the
2827 * lookup of a session's peer credentials, and possibly importing them
2828 * into X.509 structures. We may at some point decide to instead do
2829 * this ahead of time, ath the expense of some compleity and possibly
2830 * slow-down of the start of the computations.
2835 /* valexp_store_final -- store the valexp outcome in cmd->valexp_result.
2837 static void valexp_store_final (void *vcmd, struct valexp *ve, bool result) {
2838 ((struct command *) vcmd)->valexp_result = result;
2841 /* valexp_valflag_set -- set a validation flag bit for an uppercase predicate.
2843 static void valexp_valflag_set (struct command *cmd, char pred) {
2844 int len = strlen (cmd->valflags);
2845 cmd->valflags [len++] = pred;
2846 cmd->valflags [len ] = '\0';
2849 /* valexp_valflag_start -- get a prior set bit with validation information.
2850 * Where cmd->valflags is a string of uppercase letters that were ensured.
2852 static void valexp_valflag_start (void *vcmd, struct valexp *ve, char pred) {
2853 struct command *cmd = (struct command *) vcmd;
2854 pred &= 0xdf; // lowercase->uppercase
2855 valexp_setpredicate (ve, pred, NULL != strchr (cmd->valflags, pred));
2858 /* valexp_0_start -- validation function for the GnuTLS backend.
2859 * This function immediately sends failure on something impossible.
2861 static void valexp_0_start (void *vcmd, struct valexp *ve, char pred) {
2862 valexp_setpredicate (ve, pred, 0);
2865 /* valexp_1_start -- validation function for the GnuTLS backend.
2866 * This function immediately sends success on something trivial.
2868 static void valexp_1_start (void *vcmd, struct valexp *ve, char pred) {
2869 valexp_setpredicate (ve, pred, 1);
2872 //TODO// valexp_L_start, valexp_l_start
2874 /* valexp_I_start -- validation function for the GnuTLS backend.
2875 * This function ensures that the remote peer provides an identity.
2876 * TODO: We should compare the hostname as well, or compare if in remoteid
2877 * TODO: We may need to support more than just X509/PGP certificates
2879 static void valexp_I_start (void *vcmd, struct valexp *ve, char pred) {
2880 struct command *cmd = (struct command *) vcmd;
2882 ok = ok && (cmd->remote_auth_type == GNUTLS_CRD_CERTIFICATE);
2883 ok = ok && (cmd->remote_cert_count > 0);
2884 // Accept most certificates, but not for example GNUTLS_CRT_RAW
2886 #ifdef GNUTLS_CRT_KRB
2887 (cmd->remote_cert_type == GNUTLS_CRT_KRB) ||
2889 (cmd->remote_cert_type == GNUTLS_CRT_X509) ||
2890 (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) );
2891 // peer-returned "certs" points into GnuTLS' internal data structures
2892 valexp_setpredicate (ve, pred, ok);
2895 /* valexp_i_start -- is opportunistic and will always succeed
2897 #define valexp_i_start valexp_1_start
2899 /* valexp_Ff_start -- validation function for the GnuTLS backend.
2900 * This functin ensures that forward secrecy is applied.
2901 * While _F_ only accepts DHE, _f_ will also accept DH.
2902 * Note: GnuTLS does not seem to show DH that is not also DHE.
2904 static void valexp_Ff_start (void *vcmd, struct valexp *ve, char pred) {
2905 struct command *cmd = (struct command *) vcmd;
2906 gnutls_kx_algorithm_t kx = gnutls_kx_get (cmd->session);
2908 case GNUTLS_KX_UNKNOWN:
2910 case GNUTLS_KX_RSA_EXPORT:
2913 valexp_setpredicate (ve, pred, 0);
2915 case GNUTLS_KX_DHE_DSS:
2916 case GNUTLS_KX_DHE_RSA:
2918 case GNUTLS_KX_SRP_RSA:
2919 case GNUTLS_KX_SRP_DSS:
2920 case GNUTLS_KX_DHE_PSK:
2921 case GNUTLS_KX_ECDHE_RSA:
2922 case GNUTLS_KX_ECDHE_ECDSA:
2923 case GNUTLS_KX_ECDHE_PSK:
2924 case GNUTLS_KX_ANON_ECDH: // Assume DHE is in fact implemented
2925 case GNUTLS_KX_ANON_DH: // Assume DHE is in fact implemented
2926 valexp_setpredicate (ve, pred, 1);
2928 // case GNUTLS_KX_xxx_DH:
2929 // valexp_setpredicate (ve, pred, pred != 'F');
2934 /* valexp_A_start -- validation function for the GnuTLS backend.
2935 * This function ensures that an anonymising precursor is used.
2937 #define valexp_A_start valexp_valflag_start
2939 /* valexp_a_start -- is opportunistic and will always succeed */
2940 #define valexp_a_start valexp_1_start
2942 /* valexp_Tt_start -- validation function for the GnuTLS backend.
2943 * This function ensures trust based on a trusted certificate/key list.
2944 * In the _t_ case, self-signed certificates are also accepted.
2946 static void valexp_Tt_start (void *vcmd, struct valexp *ve, char pred) {
2947 struct command *cmd = (struct command *) vcmd;
2949 unsigned int vfyresult;
2952 if (cmd->vfystatus != 0) {
2955 if (cmd->remote_auth_type != GNUTLS_CRD_CERTIFICATE) {
2959 // Handle self-signed peer certificates in a special way
2960 if (cmd->remote_cert_count == 1) {
2962 bad = bad || (pred == 'T'); // Reject self-signed
2963 if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
2965 bad = bad || gnutls_x509_crt_verify (
2966 (gnutls_x509_crt_t ) cmd->remote_cert [0],
2967 (gnutls_x509_crt_t *) &cmd->remote_cert [0], 1,
2968 GNUTLS_VERIFY_DISABLE_CA_SIGN,
2970 // Apply the most stringent test. This includes all of
2971 // GNUTLS_CERT_INVALID (always set, often with others)
2972 // GNUTLS_CERT_NOT_ACTIVATED
2973 // GNUTLS_CERT_EXPIRED
2974 // GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
2975 // GNUTLS_CERT_SIGNER_NOT_FOUND
2976 // GNUTLS_CERT_SIGNER_NOT_CA => oops...
2977 // stopped with GNUTLS_VERIFY_DISABLE_CA_SIGN
2978 // GNUTLS_CERT_SIGNATURE_FAILURE
2979 // GNUTLS_CERT_INSECURE_ALGORITHM
2980 bad = bad || (vfyresult != 0);
2985 } else if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
2986 //TODO// Prefer to actually check PGP self-signature
2987 //TODO// But only value is check private-key ownership
2990 #ifdef GNUTLS_CRT_KRB
2991 } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
2992 // Kerberos has authenticated the ticket for us
2993 //TODO// Should we try reading from the ticket/auth?
3002 if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3003 // Now check the certificate chain, taking CA bits into account
3004 for (i=1; i<cmd->remote_cert_count; i++) {
3006 bad = bad || gnutls_x509_crt_verify (
3007 (gnutls_x509_crt_t ) cmd->remote_cert [i-1],
3008 (gnutls_x509_crt_t *) &cmd->remote_cert [i], 1,
3011 // Apply the most stringent test. This includes all of
3012 // GNUTLS_CERT_INVALID (always set, often with others)
3013 // GNUTLS_CERT_NOT_ACTIVATED
3014 // GNUTLS_CERT_EXPIRED
3015 // GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
3016 // GNUTLS_CERT_SIGNER_NOT_FOUND
3017 // GNUTLS_CERT_SIGNER_NOT_CA => oops...
3018 // stopped with GNUTLS_VERIFY_DISABLE_CA_SIGN
3019 // GNUTLS_CERT_SIGNATURE_FAILURE
3020 // GNUTLS_CERT_INSECURE_ALGORITHM
3021 bad = bad || (vfyresult != 0);
3023 } else if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3024 ; //TODO// Check PGP direct signature (and also use in self-sig)
3025 #ifdef GNUTLS_CRT_KRB
3026 } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3027 ; // Trust has already been validated through Kerberos
3031 valexp_setpredicate (ve, pred, flagval);
3034 /* valexp_Dd_start -- validation function for the GnuTLS backend.
3035 * This function validates through DNSSEC.
3036 * While _D_ enforces DNSSEC, _d_ also accepts opted-out security.
3038 static void valexp_Dd_start (void *vcmd, struct valexp *ve, char pred) {
3039 struct command *cmd = (struct command *) vcmd;
3042 unsigned int vfystat;
3046 struct sockaddr peername;
3047 socklen_t peernamesz = sizeof (peername);
3049 host = strchr (cmd->cmd.pio_data.pioc_starttls.remoteid, '@');
3051 host = cmd->cmd.pio_data.pioc_starttls.remoteid;
3053 switch (cmd->cmd.pio_data.pioc_starttls.ipproto) {
3066 sox = gnutls_transport_get_int (cmd->session);
3070 if (getpeername (sox, &peername, &peernamesz) != 0) {
3073 if ((peername.sa_family == AF_INET) &&
3074 (peernamesz == sizeof (struct sockaddr_in))) {
3075 port = ntohs (((struct sockaddr_in *) &peername)->sin_port);
3076 } else if ((peername.sa_family == AF_INET6) &&
3077 (peernamesz == sizeof (struct sockaddr_in6))) {
3079 port = ntohs (((struct sockaddr_in6 *) &peername)->sin6_port);
3082 //TODO// We might use online.c code instead?
3083 if (dane_state_init (&stat, /*TODO:*/ 0) != GNUTLS_E_SUCCESS) {
3086 if (dane_verify_session_crt (stat,
3092 DANE_VFLAG_FAIL_IF_NOT_CHECKED,
3093 &vfystat) == DANE_E_SUCCESS) {
3094 if ((pred == 'D') && (vfystat & DANE_VERIFY_UNKNOWN_DANE_INFO)) {
3095 dane_state_deinit (stat);
3098 flagval = ((vfystat & ~DANE_VERIFY_UNKNOWN_DANE_INFO) == 0);
3100 dane_state_deinit (stat);
3102 valexp_setpredicate (ve, pred, flagval);
3105 /* valexp_Rr_start -- validation function for the GnuTLS backend.
3106 * This function validates through a CRL.
3107 * While _R_ requires the CRL to be present, _r_ accepts confirmed absense.
3108 * TODO: This is not implemented yet.
3110 static void valexp_Rr_start (void *vcmd, struct valexp *ve, char pred) {
3112 valexp_setpredicate (ve, pred, 0);
3115 /* valexp_Ee_start -- validation function for the GnuTLS backend.
3116 * This function validates certificate extensions for the named service.
3117 * While _E_ required OIDs to be marked critical, _e_ also accepts non-crit.
3119 static void valexp_Ee_start (void *vcmd, struct valexp *ve, char pred) {
3121 valexp_setpredicate (ve, pred, 0);
3124 /* valexp_Oo_start -- validation function for the GnuTLS backend.
3125 * This function validates with online/live information.
3126 * While _O_ required positive confirmation, _o_ also accepts unknown.
3127 * -> For X.509, look in OCSP or CRL or Global Directory
3128 * -> For OpenPGP, redirect O->G, o->g
3129 * -> For Kerberos, accept anything as sufficiently live / online
3131 static void valexp_Oo_start (void *vcmd, struct valexp *ve, char pred) {
3132 struct command *cmd = (struct command *) vcmd;
3134 online2success_t o2vf;
3136 gnutls_datum_t *raw;
3137 if (cmd->remote_auth_type != GNUTLS_CRD_CERTIFICATE) {
3138 // No authentication types other than certificates yet
3141 if ((pred >= 'a') && (pred <= 'z')) {
3142 o2vf = online2success_optional;
3144 o2vf = online2success_enforced;
3146 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
3147 raw = (gnutls_datum_t *) cmd->remote_cert_raw;
3148 if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3149 valflag = o2vf (online_globaldir_pgp (
3151 raw->data, raw->size));
3152 } else if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3153 // OCSP inquiry or globaldir
3154 valflag = o2vf (online_globaldir_x509 (
3156 raw->data, raw->size));
3158 } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3159 // Kerberos is sufficiently "live" to be pass O
3164 // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
3169 valexp_setpredicate (ve, pred, valflag);
3172 /* valexp_Gg_start -- validation function for the GnuTLS backend.
3173 * This function validates through the LDAP global directory.
3174 * While _G_ requires information to be present, _g_ also accepts absense.
3175 * -> For X.509, lookup userCertificate
3176 * -> For OpenPGP, lookup pgpKey
3177 * -> For KDH, lookup krbPrincipalName
3178 * -> For SRP, nothing is defined
3179 * -> For OpenSSH, no TLS support
3181 static void valexp_Gg_start (void *vcmd, struct valexp *ve, char pred) {
3182 struct command *cmd = (struct command *) vcmd;
3184 online2success_t o2vf;
3186 gnutls_datum_t *raw;
3187 if (cmd->remote_auth_type != GNUTLS_CRD_CERTIFICATE) {
3188 // No authentication types other than certificates yet
3191 if ((pred >= 'a') && (pred <= 'z')) {
3192 o2vf = online2success_optional;
3194 o2vf = online2success_enforced;
3196 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
3197 raw = (gnutls_datum_t *) cmd->remote_cert_raw;
3198 if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3199 valflag = o2vf (online_globaldir_pgp (
3201 raw->data, raw->size));
3202 } else if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3203 //TODO// OCSP inquiry or globaldir
3204 valflag = o2vf (online_globaldir_x509 (
3206 raw->data, raw->size));
3207 #ifdef GNUTLS_CRT_KRB
3208 } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3210 //TODO// valflag = o2vf (online_globaldir_kerberos (
3212 //TODO// raw->data, raw->size));
3215 // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
3220 valexp_setpredicate (ve, pred, valflag);
3223 /* valexp_Pp_start -- validation function for the GnuTLS backend.
3224 * This function validates through pinning information.
3225 * While _P_ requires pinning to be present, _p_ will Trust On First Use.
3227 static void valexp_Pp_start (void *vcmd, struct valexp *ve, char pred) {
3229 valexp_setpredicate (ve, pred, 0);
3232 /* valexp_U_start -- validation function for the GnuTLS backend.
3233 * This function validates a matching username.
3235 static void valexp_U_start (void *vcmd, struct valexp *ve, char pred) {
3237 valexp_setpredicate (ve, pred, 0);
3240 /* valexp_Ss_start -- validation function for the GnuTLS backend.
3241 * This function ensures that the local end is a server.
3242 * While _S_ denies credentials also usable for clients, _s_ permits them.
3244 static void valexp_Ss_start (void *vcmd, struct valexp *ve, char pred) {
3245 struct command *cmd = (struct command *) vcmd;
3247 if ((pred == 'S') && (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)) {
3250 flagval = (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) != 0;
3252 valexp_setpredicate (ve, pred, flagval);
3255 /* valexp_Cc_start -- validation function for the GnuTLS backend.
3256 * This function ensures that the local end is a client.
3257 * While _C_ denies credentials also usable for servers, _c_ permits them.
3259 static void valexp_Cc_start (void *vcmd, struct valexp *ve, char pred) {
3260 struct command *cmd = (struct command *) vcmd;
3262 if ((pred == 'C') && (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER)) {
3265 flagval = (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) != 0;
3267 valexp_setpredicate (ve, pred, flagval);
3271 static void valexp_error_start (void *handler_data, struct valexp *ve, char pred) {
3274 static void valexp_ignore_stop (void *handler_data, struct valexp *ve, char pred) {
3277 static void valexp_ignore_final (void *handler_data, struct valexp *ve, bool value) {
3282 /* Given a predicate, invoke its start routine.
3284 static void valexp_switch_start (void *handler_data, struct valexp *ve, char pred) {
3287 valexp_I_start (handler_data, ve, pred);
3290 valexp_i_start (handler_data, ve, pred);
3294 valexp_Ff_start (handler_data, ve, pred);
3297 valexp_A_start (handler_data, ve, pred);
3300 valexp_a_start (handler_data, ve, pred);
3304 valexp_Tt_start (handler_data, ve, pred);
3308 valexp_Dd_start (handler_data, ve, pred);
3312 valexp_Rr_start (handler_data, ve, pred);
3316 valexp_Ee_start (handler_data, ve, pred);
3320 valexp_Oo_start (handler_data, ve, pred);
3324 valexp_Gg_start (handler_data, ve, pred);
3328 valexp_Pp_start (handler_data, ve, pred);
3331 valexp_U_start (handler_data, ve, pred);
3335 valexp_Ss_start (handler_data, ve, pred);
3339 valexp_Cc_start (handler_data, ve, pred);
3342 // Called on an unregistered symbol, that spells failure
3343 valexp_setpredicate (ve, pred, 0);
3348 /* Return a shared constant structure for valexp_handling with GnuTLS.
3349 * This function does not fail; it always returns a non-NULL value.
3351 static const struct valexp_handling *have_starttls_validation (void) {
3352 static const struct valexp_handling starttls_valexp_handling = {
3353 .handler_start = valexp_switch_start,
3354 .handler_stop = valexp_ignore_stop,
3355 .handler_final = valexp_store_final,
3357 return &starttls_valexp_handling;
3362 /* If any remote credentials are noted, cleanup on them. This removes
3363 * any remote_cert[...] entries, counting up to remote_cert_count which
3364 * is naturally set to 0 initially, as well as after this has run.
3366 static void cleanup_any_remote_credentials (struct command *cmd) {
3367 while (cmd->remote_cert_count > 0) {
3368 gnutls_x509_crt_deinit (
3369 cmd->remote_cert [--cmd->remote_cert_count]);
3371 memset (cmd->remote_cert, 0, sizeof (cmd->remote_cert));
3374 /* Fetch remote credentials. This can be done after TLS handshaking has
3375 * completed, to find the certificates or other credentials provided by
3376 * the peer to establish its identity. The validation expression routines
3377 * can then refer to this resource, and won't have to request the same
3378 * information over and over again. To this end, the information is stored
3379 * in the session object. The arrays in which this information is stored
3380 * are size-constrained, but that is also a good security precaution.
3382 * The information ends up in the following variables:
3383 * - remote_auth_type
3384 * - remote_cert_type (if remote_auth_type == GNUTLS_CRD_CERTIFICATE)
3385 * - remote_cert[...] (if remote_cert_type == GNUTLS_CRD_CERTIFICATE)
3386 * - remote_cert_count is the number of entries in remote_cert (up to root)
3388 * When certificates are used, the root certificate is looked up, for
3391 * After running successfully, a call to cleanup_any_remote_credentials()
3392 * must be called to clean up any data in the cmd structure. This may be
3393 * done on cmd at any time after initialisation, even multiple times and
3394 * even when this call fails. This call actually cleans up anything it
3395 * setup in the past, before setting up the data anew.
3397 static gtls_error fetch_remote_credentials (struct command *cmd) {
3398 gtls_error gtls_errno = GNUTLS_E_SUCCESS;
3399 const gnutls_datum_t *certs;
3400 unsigned int num_certs;
3401 gnutls_x509_crt_t x509peers [11]; // Peers + Root for GNUTLS_CRT_X509
3406 // Did we run this before? Then cleanup.
3407 cleanup_any_remote_credentials (cmd);
3408 //INVOLVES// memset (cmd->remote_cert, 0, sizeof (cmd->remote_cert));
3409 //INVOLVES// cmd->remote_cert_count = 0;
3410 // Prepare as-yet-unset default return values
3411 cmd->remote_auth_type = -1;
3412 cmd->remote_cert_raw = NULL;
3414 // Obtain the authentication type for the peer
3415 cmd->remote_auth_type = gnutls_auth_get_type (cmd->session);
3416 switch (cmd->remote_auth_type) {
3417 case GNUTLS_CRD_CERTIFICATE:
3418 // Continue loading certificates in the GnuTLS format
3420 case GNUTLS_CRD_ANON:
3421 // No basis for any identity claim
3422 cmd->cmd.pio_data.pioc_starttls.remoteid [0] = '\0';
3423 return GNUTLS_E_SUCCESS;
3424 case GNUTLS_CRD_SRP:
3425 return GNUTLS_E_SUCCESS;
3426 case GNUTLS_CRD_PSK:
3427 return GNUTLS_E_SUCCESS;
3429 return GNUTLS_E_AUTH_ERROR;
3432 // Continue loading the certificate information: X.509, PGP, ...
3434 cmd->remote_cert_type = gnutls_certificate_type_get_peers (cmd->session);
3435 certs = gnutls_certificate_get_peers (cmd->session, &num_certs);
3437 cmd->remote_cert_type = gnutls_certificate_type_get (cmd->session);
3438 certs = gnutls_certificate_get (cmd->session, &num_certs);
3440 if (certs == NULL) {
3443 // "certs" points into GnuTLS' internal data structures
3444 if ((num_certs < 1) || (num_certs > CERTS_MAX_DEPTH)) {
3445 return GNUTLS_E_AUTH_ERROR;
3447 cmd->remote_cert_raw = (void *) &certs [0];
3449 // Turn certificate data into GnuTLS' data structures (to be cleaned)
3450 if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3451 peer_tad = TAD_TYPE_X509;
3452 for (i=0; i < num_certs; i++) {
3453 E_g2e ("Failed to initialise peer X.509 certificate",
3454 gnutls_x509_crt_init (
3455 (gnutls_x509_crt_t *) &cmd->remote_cert [i]));
3456 if (gtls_errno == GNUTLS_E_SUCCESS) {
3457 cmd->remote_cert_count++;
3459 E_g2e ("Failed to import peer X.509 certificate",
3460 gnutls_x509_crt_import (
3461 cmd->remote_cert [i],
3462 &certs [i], GNUTLS_X509_FMT_DER));
3464 if (gtls_errno != GNUTLS_E_SUCCESS) {
3467 } else if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3468 peer_tad = TAD_TYPE_PGP;
3469 E_g2e ("Failed to initialise peer PGP key",
3470 gnutls_x509_crt_init (
3471 (gnutls_x509_crt_t *) &cmd->remote_cert [0]));
3472 if (gtls_errno == GNUTLS_E_SUCCESS) {
3473 cmd->remote_cert_count = 1;
3475 E_g2e ("Failed to import peer PGP key",
3476 gnutls_openpgp_crt_import (
3477 cmd->remote_cert [0],
3478 &certs [0], GNUTLS_OPENPGP_FMT_RAW));
3479 if (gtls_errno != GNUTLS_E_SUCCESS) {
3485 // Lookup the trusted party that the peers certificates is promoting.
3486 // Note that even if the peer ends in a CA cert (which it may not
3487 // always send along) then we can still add it ourselves again :-)
3488 // Only worry might be that CA certs require no AuthorityKeyIdentifier.
3489 if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3490 // Retrieve the AuthorityKeyIdentifier from last (or semi-last)
3495 DBC *crs_trust = NULL;
3497 gnutls_datum_t anchor_gnutls;
3498 gnutls_x509_crt_t dbroot;
3499 dbt_init_empty (&rootca);
3500 dbt_init_empty (&anchor);
3502 gtls_errno = gnutls_x509_crt_get_authority_key_id (
3503 cmd->remote_cert [cmd->remote_cert_count-1],
3506 if (gtls_errno == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
3507 // Only retry if the last is a signer, possibly CA
3508 if (cmd->remote_cert_count == 1) {
3509 // Permit self-signed certificate evaluation
3510 gtls_errno = GNUTLS_E_SUCCESS;
3511 } else if (cmd->remote_cert_count > 1) {
3512 // Assume the last is a root cert, as it lacks authid
3513 gnutls_x509_crt_deinit (
3514 cmd->remote_cert [--cmd->remote_cert_count]);
3515 cmd->remote_cert [cmd->remote_cert_count] = NULL;
3517 gtls_errno = gnutls_x509_crt_get_authority_key_id (
3518 cmd->remote_cert [cmd->remote_cert_count-1],
3523 if (gtls_errno != GNUTLS_E_SUCCESS) {
3526 // Get root cert from trustdb into remote_cert [_count++]
3527 dbt_init_fixbuf (&rootca, id, idsz);
3528 dbt_init_malloc (&anchor);
3529 E_d2e ("Failed to create db_disclose cursor",
3535 E_d2e ("X.509 authority key identifier not found in trust database",
3537 crs_trust, &rootca, &anchor));
3538 while (db_errno == 0) {
3539 // Process "anchor" entry (inasfar as meaningful)
3540 uint32_t anchorflags;
3543 char *valexp; //TODO// Initiate this before cleanup
3544 int tstatus = trust_interpret (&anchor, &anchorflags, &valexp, &trustdata, &trustdatalen);
3546 if (tstatus != TAD_STATUS_SUCCESS) {
3547 // Signal any DB error to bail out of this loop
3548 db_errno = DB_KEYEMPTY;
3549 } else if ((anchorflags & TAD_TYPE_MASK) != peer_tad) {
3550 ; // Skip unsought trust database entry
3551 } else if ((anchorflags & TAD_TYPE_MASK) == TAD_TYPE_X509) {
3552 E_g2e ("Certificate chain too long",
3553 (cmd->remote_cert_count >= CERTS_MAX_DEPTH)
3554 ? GNUTLS_E_AUTH_ERROR
3555 : GNUTLS_E_SUCCESS);
3556 // Turn the anchor into an X.509 certificate
3557 E_g2e ("Failet to initialise X.509 peer trust anchor",
3558 gnutls_x509_crt_init ((gnutls_x509_crt_t *) &cmd->remote_cert [cmd->remote_cert_count]));
3559 if (gtls_errno == GNUTLS_E_SUCCESS) {
3560 cmd->remote_cert_count++;
3561 anchor_gnutls.data = anchor.data;
3562 anchor_gnutls.size = anchor.size;
3563 E_g2e ("Failed to import X.509 peer trust anchor",
3564 gnutls_x509_crt_import (cmd->remote_cert [cmd->remote_cert_count-1], &anchor_gnutls, GNUTLS_X509_FMT_DER));
3566 if (gtls_errno == GNUTLS_E_SUCCESS) {
3567 // Everything worked, we have a chain
3569 if (cmd->trust_valexp) {
3570 free (cmd->trust_valexp);
3572 cmd->trust_valexp = strdup (valexp);
3574 // Signal arbitrary DB error
3575 db_errno = DB_KEYEMPTY;
3577 } else if ((anchorflags & TAD_TYPE_MASK) == TAD_TYPE_REVOKE_X509) {
3578 //TODO// Possibly verify end cert revocation
3580 /* Ignore entry, continue with the next */;
3582 db_errno = dba_trust_iterate (crs_trust, &rootca, &anchor);
3584 if (crs_trust != NULL) {
3585 crs_trust->close (crs_trust);
3589 // No dbt_free (&rootca) because it is set to a fixed buffer
3590 if (db_errno != DB_NOTFOUND) {
3593 } else if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3594 ; //TODO// Attempt to load PGP direct signer(s)
3595 ; //OPTION// May use the _count for alternative signers!
3596 ; //OPTION// May setup/reload a keyring based on trust.db
3597 #ifdef GNUTLS_CRT_KRB
3598 } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3599 ; //TODO// Process as appropriate for Kerberos (store Ticket?)
3603 // Cleanup (when returning an error code) and return
3605 if (gtls_errno != GNUTLS_E_SUCCESS) {
3606 cleanup_any_remote_credentials (cmd);
3608 while ((!got_chain) && (cmd->remote_cert_count > 1)) {
3609 --cmd->remote_cert_count;
3610 gnutls_x509_crt_deinit (
3611 cmd->remote_cert [cmd->remote_cert_count]);
3612 cmd->remote_cert [cmd->remote_cert_count] = NULL;
3618 /* Fetch local credentials. This can be done before TLS is started, to find
3619 * the possible authentication forms that can be offered. The function
3620 * can additionally be used after interaction with the client to establish
3621 * a local identity that was not initially provided, or that was not
3622 * considered public at the time.
3624 gtls_error fetch_local_credentials (struct command *cmd) {
3627 DBC *crs_disclose = NULL;
3628 DBC *crs_localid = NULL;
3632 selector_t remote_selector;
3636 gtls_error certificate_onthefly (struct command *cmd);
3639 // When applicable, try to create an on-the-fly certificate
3640 if (((cmd->cmd.pio_cmd == PIOC_STARTTLS_V2) &&
3641 (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALID_ONTHEFLY))
3642 || ((cmd->cmd.pio_cmd == PIOC_LIDENTRY_CALLBACK_V2) &&
3643 (cmd->cmd.pio_data.pioc_lidentry.flags & PIOF_LIDENTRY_ONTHEFLY))) {
3644 gtls_errno = certificate_onthefly (cmd);
3645 if (gtls_errno != GNUTLS_E_AGAIN) {
3646 // This includes GNUTLS_E_SUCCESS
3647 fprintf (stderr, "DEBUG: otfcert retrieval returned %d\n", gtls_errno);
3650 fprintf (stderr, "DEBUG: otfcert retrieval returned GNUTLS_E_AGAIN, so skip it\n", gtls_errno);
3651 gtls_errno = GNUTLS_E_SUCCESS; // Attempt failed, ignore
3656 // Setup a number of common references and structures
3657 // Note: Current GnuTLS cannot support being a peer
3658 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
3659 lidrole = LID_ROLE_CLIENT;
3660 } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
3661 lidrole = LID_ROLE_SERVER;
3663 E_g2e ("TLS Pool command supports neither local client nor local server role",
3664 GNUTLS_E_INVALID_SESSION);
3667 lid = cmd->cmd.pio_data.pioc_starttls.localid;
3668 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
3671 // Refuse to disclose client credentials when the server name is unset;
3672 // note that server-claimed identities are unproven during handshake.
3673 if ((lidrole == LID_ROLE_CLIENT) && (*rid == '\0')) {
3674 tlog (TLOG_USER, LOG_ERR, "No remote identity (server name) set, so no client credential disclosure");
3675 E_g2e ("Missing remote ID",
3676 GNUTLS_E_NO_CERTIFICATE_FOUND);
3680 // Setup database iterators to map identities to credentials
3681 if (lidrole == LID_ROLE_CLIENT) {
3682 E_d2e ("Failed to create db_disclose cursor",
3683 dbh_disclose->cursor (
3689 E_d2e ("Failed to create db_localid cursor",
3690 dbh_localid->cursor (
3696 // Prepare for iteration over possible local identities / credentials
3699 if (gtls_errno != 0) {
3701 } else if (lidrole == LID_ROLE_CLIENT) {
3702 memcpy (cid, rid, sizeof (cid));
3703 dbt_init_fixbuf (&discpatn, cid, strlen (cid));
3704 dbt_init_fixbuf (&keydata, mid, sizeof (mid)-1);
3705 dbt_init_malloc (&creddata);
3707 donai_t remote_donai = donai_from_stable_string (rid, strlen (rid));
3708 if (!selector_iterate_init (&remote_selector, &remote_donai)) {
3709 E_g2e ("Syntax of remote ID unsuitable for selector",
3710 GNUTLS_E_INVALID_REQUEST);
3712 E_d2e ("Failed to start iterator on remote ID selector",
3713 dbcred_iterate_from_remoteid_selector (
3722 dbt_init_fixbuf (&discpatn, "", 0); // Unused but good style
3723 dbt_init_fixbuf (&keydata, lid, strlen (lid));
3724 dbt_init_malloc (&creddata);
3725 E_d2e ("Failed to start iterator on local ID",
3726 dbcred_iterate_from_localid (
3731 if (db_errno != 0) {
3732 gtls_errno = GNUTLS_E_DB_ERROR;
3736 // Now store the local identities inasfar as they are usable
3738 while ((gtls_errno == GNUTLS_E_SUCCESS) && (db_errno == 0)) {
3743 tlog (TLOG_DB, LOG_DEBUG, "Found BDB entry %s disclosed to %s", creddata.data + 4, (lidrole == LID_ROLE_CLIENT)? rid: "all clients");
3747 lidtype = flags & LID_TYPE_MASK;
3748 ok = ok && ((flags & lidrole) != 0);
3749 ok = ok && ((flags & LID_NO_PKCS11) == 0);
3750 ok = ok && (lidtype >= LID_TYPE_MIN);
3751 ok = ok && (lidtype <= LID_TYPE_MAX);
3753 // For current/simple Kerberos, refuse data after PKCS #11 URI
3754 ok = ok && ((lidtype != LID_TYPE_KRB5) || (NULL == memchr (creddata.data + 4, '\0', creddata.size - 4 - 1)));
3756 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 ");
3758 // Move the credential into the command structure
3759 dbt_store (&creddata,
3760 &cmd->lids [lidtype - LID_TYPE_MIN]);
3763 // Skip the credential by freeing its data structure
3764 dbt_free (&creddata);
3766 db_errno = dbcred_iterate_next (crs_disclose, crs_localid, &discpatn, &keydata, &creddata);
3769 if (db_errno == DB_NOTFOUND) {
3771 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
3774 if (crs_localid != NULL) {
3775 crs_localid->close (crs_localid);
3778 if (crs_disclose != NULL) {
3779 crs_disclose->close (crs_disclose);
3780 crs_disclose = NULL;
3787 * Check if a given cmd has the given LID_TYPE setup.
3788 * Return 1 for yes or 0 for no; this is used in priority strings.
3790 static inline int lidtpsup (struct command *cmd, int lidtp) {
3791 return cmd->lids [lidtp - LID_TYPE_MIN].data != NULL;
3794 /* Configure the GnuTLS session with suitable credentials and priority string.
3795 * The anonpre_ok flag should be non-zero to permit Anonymous Precursor.
3797 * The credential setup is optional; when creds is NULL, no changes will
3800 static int configure_session (struct command *cmd,
3801 gnutls_session_t session,
3802 struct credinfo *creds,
3806 int gtls_errno = GNUTLS_E_SUCCESS;
3808 // Install the shared credentials for the client or server role
3809 if (creds != NULL) {
3810 gnutls_credentials_clear (session);
3811 for (i=0; i<credcount; i++) {
3812 E_g2e ("Failed to install credentials into TLS session",
3813 gnutls_credentials_set (
3820 // Setup the priority string for this session; this avoids future
3821 // credential callbacks that ask for something impossible or
3824 // Variation factors:
3825 // - starting configuration (can it be empty?)
3826 // - Configured security parameters (database? variable?)
3827 // - CTYPEs, SRP, ANON-or-not --> fill in as + or - characters
3828 if (gtls_errno == GNUTLS_E_SUCCESS) {
3831 snprintf (priostr, sizeof (priostr)-1,
3832 // "NORMAL:-RSA:" -- also ECDH-RSA, ECDHE-RSA, ...DSA...
3834 "%%ASYM_CERT_TYPES:"
3835 "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
3837 "+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
3839 "+ECDHE-KRB:" // +ECDHE-KRB-RSA:+ECDHE-KRB-ECDHE:" // opt?
3840 "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:" //TODO//
3841 "+CTYPE-SRV-KRB:+CTYPE-SRV-X.509:+CTYPE-SRV-OPENPGP:"
3843 "%cCTYPE-CLI-X.509:"
3844 "%cCTYPE-CLI-OPENPGP:"
3845 "%cSRP:%cSRP-RSA:%cSRP-DSS",
3846 anonpre_ok ?'+':'-',
3847 1 /* lidtpsup (cmd, LID_TYPE_KRB5)*/ ?'+':'-',
3848 1 /*lidtpsup (cmd, LID_TYPE_X509)*/ ?'+':'-',
3849 1 /*lidtpsup (cmd, LID_TYPE_PGP)*/ ?'+':'-',
3850 //TODO// Temporarily patched out SRP
3851 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
3852 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
3853 lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-');
3855 // It's not possible to make good decisions on certificate type
3856 // for both sides based on knowledge of local authentication
3857 // abilities. So we permit all (but would like to be subtler).
3858 snprintf (priostr, sizeof (priostr)-1,
3859 // "NORMAL:-RSA:" -- also ECDH-RSA, ECDHE-RSA, ...DSA...
3861 "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
3863 "+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
3865 "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:" //TODO//
3868 "%cSRP:%cSRP-RSA:%cSRP-DSS",
3869 anonpre_ok ?'+':'-',
3872 //TODO// Temporarily patched out SRP
3877 tlog (TLOG_TLS, LOG_DEBUG, "Constructed priority string %s for local ID %s",
3878 priostr, cmd->cmd.pio_data.pioc_starttls.localid);
3879 E_g2e ("Failed to set GnuTLS priority string",
3880 gnutls_priority_set_direct (
3886 // Return the application GNUTLS_E_ code including _SUCCESS
3890 /* The callback functions retrieve various bits of information for the client
3891 * or server in the course of the handshake procedure.
3893 * The logic here is based on client-sent information, such as:
3894 * - TLS hints -- X.509 or alternatives like OpenPGP, SRP, PSK
3895 * - TLS hints -- Server Name Indication
3896 * - User hints -- local and remote identities provided
3898 static int srv_clienthello (gnutls_session_t session, unsigned int htype, unsigned int post, unsigned int incoming, const gnutls_datum_t *msg) {
3899 struct command *cmd;
3900 int gtls_errno = GNUTLS_E_SUCCESS;
3901 char sni [sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid)]; // static
3902 size_t snilen = sizeof (sni);
3906 tlog (LOG_DAEMON, LOG_INFO, "Invoked %sprocessor for Client Hello, htype=%d, incoming=%d\n",
3907 post ? "post" : "pre",
3911 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3913 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3917 // Setup a number of common references
3918 cmd = (struct command *) gnutls_session_get_ptr (session);
3920 return GNUTLS_E_INVALID_SESSION;
3924 // Setup server-specific credentials and priority string
3925 //TODO// get anonpre value here
3926 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
3927 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3928 E_g2e ("Failed to reconfigure GnuTLS as a server",
3929 configure_session (cmd,
3931 srv_creds, srv_credcount,
3932 cmd->anonpre & ANONPRE_SERVER));
3933 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
3938 // Setup a number of common references
3939 cmd = (struct command *) gnutls_session_get_ptr (session);
3941 return GNUTLS_E_INVALID_SESSION;
3943 lid = cmd->cmd.pio_data.pioc_starttls.localid;
3946 // Setup to ignore/request/require remote identity (from client)
3947 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3948 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_IGNORE_REMOTEID) {
3949 // Neither Request nor Require remoteid; ignore it
3951 } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REQUEST_REMOTEID) {
3952 // Use Request instead of Require for remoteid
3953 ( //RETURNS_VOID// E_g2e ("Failed to request remote identity",
3954 gnutls_certificate_server_set_request (
3956 GNUTLS_CERT_REQUEST));
3957 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
3959 // Require a remoteid from the client (default)
3960 ( //RETURNS_VOID// E_g2e ("Failed to require remote identity (the default)",
3961 gnutls_certificate_server_set_request (
3963 GNUTLS_CERT_REQUIRE));
3964 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
3968 // Find the client-helloed ServerNameIndication, or the service name
3969 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3971 if (gnutls_server_name_get (session, sni, &snilen, &snitype, 0) == 0) {
3972 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3974 case GNUTLS_NAME_DNS:
3976 // Note: In theory, other name types could be sent, and it would
3977 // be useful to access indexes beyond 0. In practice, nobody
3978 // uses other name types than exactly one GNUTLS_NAME_DNS.
3981 tlog (TLOG_TLS, LOG_ERR, "Received an unexpected SNI type; that is possible but uncommon; skipping SNI");
3982 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3986 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3987 if (sni [0] != '\0') {
3990 for (atidx=128; atidx > 0; atidx--) {
3991 if (lid [atidx-1] == '@') {
3995 if (strncmp (sni, lid + atidx, sizeof (sni)-atidx) != 0) {
3996 tlog (TLOG_USER | TLOG_TLS, LOG_ERR, "Mismatch between client-sent SNI %s and local identity %s", sni, lid);
3997 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3998 return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
4001 memcpy (lid, sni, sizeof (sni));
4002 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
4005 memcpy (sni, lid, sizeof (sni)-1);
4006 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
4007 sni [sizeof (sni) - 1] = '\0';
4009 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
4013 // Lap up any unnoticed POSIX error messages
4015 cmd->session_errno = errno;
4016 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
4017 gtls_errno = GNUTLS_E_NO_CIPHER_SUITES; /* Vaguely matching */
4018 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
4022 // Round off with an overal judgement
4023 fprintf (stderr, "DEBUG: Returning gtls_errno = %d or \"%s\" from srv_clihello()\n", gtls_errno, gnutls_strerror (gtls_errno));
4028 int cli_srpcreds_retrieve (gnutls_session_t session,
4032 tlog (TLOG_CRYPTO, LOG_DEBUG, "Picking up SRP credentials");
4033 *username = strdup ("tester");
4034 *password = strdup ("test");
4035 return GNUTLS_E_SUCCESS;
4039 /* Setup credentials to be shared by all clients and servers.
4040 * Credentials are generally implemented through callback functions.
4041 * This should be called after setting up DH parameters.
4043 static int setup_starttls_credentials (void) {
4044 gnutls_anon_server_credentials_t srv_anoncred = NULL;
4045 gnutls_anon_client_credentials_t cli_anoncred = NULL;
4046 gnutls_certificate_credentials_t clisrv_certcred = NULL;
4047 //TODO:NOTHERE// int srpbits;
4048 gnutls_srp_server_credentials_t srv_srpcred = NULL;
4049 gnutls_srp_client_credentials_t cli_srpcred = NULL;
4050 //TODO// gnutls_kdh_server_credentials_t srv_kdhcred = NULL;
4051 //TODO// gnutls_kdh_server_credentials_t cli_kdhcred = NULL;
4052 int gtls_errno = GNUTLS_E_SUCCESS;
4053 int gtls_errno_stack0 = GNUTLS_E_SUCCESS;
4056 // Construct anonymous server credentials
4057 E_g2e ("Failed to allocate ANON-DH server credentials",
4058 gnutls_anon_allocate_server_credentials (
4060 if (!have_error_codes ()) /* E_g2e (...) */ gnutls_anon_set_server_dh_params (
4063 if (gtls_errno == GNUTLS_E_SUCCESS) {
4064 tlog (TLOG_CRYPTO, LOG_INFO, "Setting server anonymous credentials");
4065 srv_creds [srv_credcount].credtp = GNUTLS_CRD_ANON;
4066 srv_creds [srv_credcount].cred = (void *) srv_anoncred;
4068 } else if (srv_anoncred != NULL) {
4069 gnutls_anon_free_server_credentials (srv_anoncred);
4070 srv_anoncred = NULL;
4074 // Construct anonymous client credentials
4075 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4076 E_g2e ("Failed to allocate ANON-DH client credentials",
4077 gnutls_anon_allocate_client_credentials (
4079 #ifdef MIRROR_IMAGE_OF_SERVER_ANONYMOUS_CREDENTIALS
4080 // NOTE: This is not done under TLS; server always provides DH params
4081 if (!have_error_codes ()) gnutls_anon_set_client_dh_params (
4085 if (gtls_errno == GNUTLS_E_SUCCESS) {
4086 tlog (TLOG_CRYPTO, LOG_INFO, "Setting client anonymous credentials");
4087 cli_creds [cli_credcount].credtp = GNUTLS_CRD_ANON;
4088 cli_creds [cli_credcount].cred = (void *) cli_anoncred;
4090 } else if (cli_anoncred != NULL) {
4091 gnutls_anon_free_client_credentials (cli_anoncred);
4092 cli_anoncred = NULL;
4096 // Construct certificate credentials for X.509 and OpenPGP cli/srv
4097 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4098 E_g2e ("Failed to allocate certificate credentials",
4099 gnutls_certificate_allocate_credentials (
4101 //TODO// What to do here when we add locking on DH params?
4102 gnutls_certificate_set_dh_params (
4105 gtls_errno_stack0 = gtls_errno;
4106 /* TODO: Bad code. GnuTLS 3.2.1 ignores retrieve_function2 when
4107 * checking if it can handle the OpenPGP certificate type in
4108 * _gnutls_session_cert_type_supported (gnutls_status.c:175) but
4109 * it does see the "1" version field. It does not callback the
4110 * "1" version if "2" is present though.
4112 if (!have_error_codes ()) /* TODO:GnuTLSversions E_g2e (...) */ gnutls_certificate_set_retrieve_function (
4115 if (!have_error_codes ()) /* TODO:GnuTLSversions E_g2e (...) */ gnutls_certificate_set_retrieve_function2 (
4117 clisrv_cert_retrieve);
4119 E_g2e ("Failed to set encoding callback for Kerberos Authenticators",
4120 gnutls_authenticator_set_encode_function (
4122 cli_kdhsig_encode));
4123 E_g2e ("Failed to set decoding callback for Kerberos Authenticators",
4124 gnutls_authenticator_set_decode_function (
4126 srv_kdhsig_decode));
4128 if (gtls_errno == GNUTLS_E_SUCCESS) {
4129 // Setup for certificates
4130 tlog (TLOG_CERT, LOG_INFO, "Setting client and server certificate credentials");
4131 cli_creds [cli_credcount].credtp = GNUTLS_CRD_CERTIFICATE;
4132 cli_creds [cli_credcount].cred = (void *) clisrv_certcred;
4134 srv_creds [srv_credcount].credtp = GNUTLS_CRD_CERTIFICATE;
4135 srv_creds [srv_credcount].cred = (void *) clisrv_certcred;
4137 } else if (clisrv_certcred != NULL) {
4138 gnutls_certificate_free_credentials (clisrv_certcred);
4139 clisrv_certcred = NULL;
4143 // Construct server credentials for SRP authentication
4144 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4145 E_g2e ("Failed to allocate SRP server credentials",
4146 gnutls_srp_allocate_server_credentials (
4148 E_g2e ("Failed to set SRP server credentials",
4149 gnutls_srp_set_server_credentials_file (
4151 "../testdata/tlspool-test-srp.passwd",
4152 "../testdata/tlspool-test-srp.conf"));
4153 if (gtls_errno == GNUTLS_E_SUCCESS) {
4154 tlog (TLOG_CRYPTO, LOG_INFO, "Setting server SRP credentials");
4155 srv_creds [srv_credcount].credtp = GNUTLS_CRD_SRP;
4156 srv_creds [srv_credcount].cred = (void *) srv_srpcred;
4158 } else if (srv_srpcred != NULL) {
4159 gnutls_srp_free_server_credentials (srv_srpcred);
4164 // Construct client credentials for SRP authentication
4165 gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4166 E_g2e ("Failed to allocate SRP client credentials",
4167 gnutls_srp_allocate_client_credentials (
4169 if (!have_error_codes ()) gnutls_srp_set_client_credentials_function (
4171 cli_srpcreds_retrieve);
4172 if (gtls_errno == GNUTLS_E_SUCCESS) {
4173 tlog (TLOG_CRYPTO, LOG_INFO, "Setting client SRP credentials");
4174 cli_creds [cli_credcount].credtp = GNUTLS_CRD_SRP;
4175 cli_creds [cli_credcount].cred = (void *) cli_srpcred;
4177 } else if (cli_srpcred != NULL) {
4178 gnutls_srp_free_client_credentials (cli_srpcred);
4183 // Construct server credentials for KDH authentication
4184 //TODO// gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4185 //TODO// E_g2e ("Failed to allocate KDH server credentials",
4186 //TODO// gnutls_kdh_allocate_server_credentials (
4187 //TODO// &srv_kdhcred));
4188 //TODO// E_g2e ("Failed to set KDH server DH params",
4189 //TODO// gnutls_kdh_set_server_dh_params (
4190 //TODO// srv_kdhcred,
4191 //TODO// dh_params));
4192 //TODO// if (gtls_errno == GNUTLS_E_SUCCESS) {
4193 //TODO// tlog (TLOG_CRYPTO, LOG_INFO, "Setting server KDH credentials");
4194 //TODO// srv_creds [srv_credcount].credtp = GNUTLS_CRD_KDH;
4195 //TODO// srv_creds [srv_credcount].cred = (void *) srv_kdhcred;
4196 //TODO// srv_credcount++;
4197 //TODO// } else if (srv_kdhcred != NULL) {
4198 //TODO// gnutls_kdh_free_server_credentials (srv_kdhcred);
4199 //TODO// srv_kdhcred = NULL;
4203 // Construct client credentials for KDH
4204 //TODO// gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4205 //TODO// E_g2e ("Failed to allocate KDH client credentials",
4206 //TODO// gnutls_kdh_allocate_client_credentials (
4207 //TODO// &cli_kdhcred));
4208 //TODO// E_g2e ("Failed to set KDH client credentials",
4209 //TODO// gnutls_kdh_set_client_credentials_function (
4210 //TODO// cli_kdhcred,
4211 //TODO// cli_kdh_retrieve));
4212 //TODO// if (gtls_errno == GNUTLS_E_SUCCESS) {
4213 //TODO// tlog (TLOG_CRYPTO, LOG_INFO, "Setting client KDH credentials");
4214 //TODO// cli_creds [cli_credcount].credtp = GNUTLS_CRD_KDH;
4215 //TODO// cli_creds [cli_credcount].cred = (void *) cli_kdhcred;
4216 //TODO// cli_credcount++;
4217 //TODO// } else if (cli_kdhcred != NULL) {
4218 //TODO// gnutls_kdh_free_client_credentials (cli_kdhcred);
4219 //TODO// cli_kdhcred = NULL;
4223 // Ensure that at least one credential has been set
4224 // TODO: Look at the counters; but at boot, we can require all okay
4225 if ((gtls_errno == GNUTLS_E_SUCCESS) &&
4226 ( (cli_credcount != EXPECTED_CLI_CREDCOUNT) ||
4227 (srv_credcount != EXPECTED_SRV_CREDCOUNT) ) ) {
4228 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);
4229 E_g2e ("Not all credentials could be setup",
4230 GNUTLS_E_INSUFFICIENT_CREDENTIALS);
4234 // Report overall error or success
4239 /* Cleanup all credentials created, just before exiting the daemon.
4241 static void cleanup_starttls_credentials (void) {
4242 while (srv_credcount-- > 0) {
4243 struct credinfo *crd = &srv_creds [srv_credcount];
4244 switch (crd->credtp) {
4245 case GNUTLS_CRD_CERTIFICATE:
4246 // Shared with client; skipped in server and removed in client
4247 // gnutls_certificate_free_credentials (crd->cred);
4249 case GNUTLS_CRD_ANON:
4250 gnutls_anon_free_server_credentials (crd->cred);
4252 case GNUTLS_CRD_SRP:
4253 gnutls_srp_free_server_credentials (crd->cred);
4255 //TODO// case GNUTLS_CRD_KDH:
4256 //TODO// gnutls_kdh_free_server_credentials (crd->cred);
4260 while (cli_credcount-- > 0) {
4261 struct credinfo *crd = &cli_creds [cli_credcount];
4262 switch (crd->credtp) {
4263 case GNUTLS_CRD_CERTIFICATE:
4264 // Shared with client; skipped in server and removed in client
4265 gnutls_certificate_free_credentials (crd->cred);
4267 case GNUTLS_CRD_ANON:
4268 gnutls_anon_free_client_credentials (crd->cred);
4270 case GNUTLS_CRD_SRP:
4271 gnutls_srp_free_client_credentials (crd->cred);
4273 //TODO// case GNUTLS_CRD_KDH:
4274 //TODO// gnutls_kdh_free_client_credentials (crd->cred);
4282 * The starttls_thread is a main program for the setup of a TLS connection,
4283 * either in client mode or server mode. Note that the distinction between
4284 * client and server mode is only a TLS concern, but not of interest to the
4285 * application or the records exchanged.
4287 * If the STARTTLS operation succeeds, this will be reported back to the
4288 * application, but the TLS pool will continue to be active in a copycat
4289 * procedure: encrypting outgoing traffic and decrypting incoming traffic.
4291 * A new handshake may be initiated with a STARTTLS command with the special
4292 * flag PIOF_STARTTLS_RENEGOTIATE and the ctlkey set to a previously setup
4293 * TLS connection. This command runs in a new thread, that cancels the old
4294 * one (which it can only do while it is waiting in copycat) and then join
4295 * that thread (and its data) with the current one. This is based on the
4296 * ctlkey, which serves to lookup the old thread's data. When the
4297 * connection ends for other reasons than a permitted cancel by another
4298 * thread, will the thread cleanup its own resources. In these situations,
4299 * the new command determines the negotiation parameters, and returns identity
4302 * In addition, the remote side may initiate renegotiation. This is accepted
4303 * without further ado (although future versions of the TLS Pool may add a
4304 * callback mechanism to get it approved). The renegotiation now runs under
4305 * the originally supplied negotiation parameters. In case it needs a new
4306 * local identity, it may also perform callbacks. Possibly repeating what
4307 * happened before -- but most often, a server will start processing a
4308 * protocol and determine that it requires more for the requested level of
4309 * service, and then renegotiate. This is common, for example, with HTTPS
4310 * connections that decide they need a client certificate for certain URLs.
4311 * The implementation of this facility is currently as unstructured as the
4312 * facility itself, namely through a goto. We may come to the conclusion
4313 * that a loop is in fact a warranted alternative, but we're not yet
4314 * convinced that this would match with other "structures" in TLS.
4316 * In conclusion, there are three possible ways of running this code:
4317 * 1. For a new connection. Many variables are not known and build up
4318 * in the course of running the function.
4319 * 2. After a command requesting renegotiation. This overtakes the prior
4320 * connection's thread, and copies its data from the ctlkeynode_tls.
4321 * The resulting code has a number of variables filled in already at
4323 * 3. After a remote request for renegotiation. This loops back to an
4324 * earlier phase, but after the thread takeover and ctlkeynode_tls copy
4325 * of the explicit command for renegotation. Its behaviour is subtly
4326 * different in that it has no command to act on, and so it cannot
4327 * send responses or error codes. It will however log and shutdown
4328 * as the command-driven options would. It will not perform callbacks
4329 * for PIOC_STARTTLS_LOCALID_V2 or PIOC_PLAINTEXT_CONNECT_V2. It will
4330 * however trigger the PIOC_LIDENTRY_CALLBACK_V2 through the separate
4331 * callback command, if one is registered.
4332 * Yeah, it's great fun, coding TLS and keeping it both flexible and secure.
4334 static void *starttls_thread (void *cmd_void) {
4335 struct command *cmd, *replycmd;
4336 struct command cmd_copy; // for relooping during renegotiation
4337 struct pioc_starttls orig_starttls;
4338 uint32_t orig_cmdcode;
4341 gnutls_session_t session;
4342 int got_session = 0;
4343 int gtls_errno = GNUTLS_E_SUCCESS;
4345 struct ctlkeynode_tls *ckn = NULL;
4348 int want_remoteid = 1;
4349 int got_remoteid = 0;
4350 int renegotiating = 0;
4351 char *preauth = NULL;
4352 unsigned int preauthlen = 0;
4353 int taking_over = 0;
4354 int my_maxpreauth = 0;
4358 // Block thread cancellation -- and re-enable it in copycat()
4359 assert (pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL) == 0);
4362 // General thread setup
4363 replycmd = cmd = (struct command *) cmd_void;
4365 send_error (replycmd, EINVAL, "Command structure not received");
4366 assert (pthread_detach (pthread_self ()) == 0);
4369 *cmd->valflags = '\0';
4370 cmd->session_errno = 0;
4372 orig_cmdcode = cmd->cmd.pio_cmd;
4373 memcpy (&orig_starttls, &cmd->cmd.pio_data.pioc_starttls, sizeof (orig_starttls));
4374 cmd->orig_starttls = &orig_starttls;
4375 cryptfd = cmd->passfd;
4377 //TODO:TEST Removed here because it is tested below
4380 tlog (TLOG_UNIXSOCK, LOG_ERR, "No ciphertext file descriptor supplied to TLS Pool");
4381 send_error (replycmd, EINVAL, "No ciphertext file descriptor supplied to TLS Pool");
4382 assert (pthread_detach (pthread_self ()) == 0);
4386 cmd->session_certificate = (intptr_t) (void *) NULL;
4387 cmd->session_privatekey = (intptr_t) (void *) NULL;
4390 // In case of renegotiation, lookup the previous ctlkeynode by its
4391 // ctlkey. The fact that we have ckn != NULL indicates that we are
4392 // renegotiating in the code below; it will supply information as
4393 // we continue to run the TLS process.
4394 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_RENEGOTIATE) {
4395 fprintf (stderr, "DEBUG: Got a request to renegotiate existing TLS connection\n");
4397 // Check that no FD was passed (and ended up in cryptfd)
4399 tlog (TLOG_UNIXSOCK, LOG_ERR, "Renegotiation started with extraneous file descriptor");
4400 send_error (replycmd, EPROTO, "File handle supplied for renegotiation");
4402 assert (pthread_detach (pthread_self ()) == 0);
4406 // First find the ctlkeynode_tls
4407 ckn = (struct ctlkeynode_tls *) ctlkey_find (cmd->cmd.pio_data.pioc_starttls.ctlkey, security_tls, cmd->clientfd);
4408 fprintf (stderr, "DEBUG: Got ckn == 0x%0x\n", (intptr_t) ckn);
4410 tlog (TLOG_UNIXSOCK, LOG_ERR, "Failed to find TLS connection for renegotiation by its ctlkey");
4411 send_error (replycmd, ESRCH, "Cannot find TLS connection for renegotiation");
4412 assert (pthread_detach (pthread_self ()) == 0);
4416 // Now cancel the pthread for this process
4417 errno = pthread_cancel (ckn->owner);
4418 fprintf (stderr, "DEBUG: pthread_cancel returned %d\n", errno);
4421 errno = pthread_join (ckn->owner, &retval);
4422 fprintf (stderr, "DEBUG: pthread_join returned %d\n", errno);
4425 // We have now synchronised with the cancelled thread
4426 // Cleanup any _remote data in ckn->session->cmd
4427 cleanup_any_remote_credentials (
4428 (struct command *) gnutls_session_get_ptr (
4432 tlog (TLOG_UNIXSOCK, LOG_ERR, "Failed to interrupt TLS connection for renegotiation");
4433 send_error (replycmd, errno, "Cannot interrupt TLS connection for renegotiation");
4434 ctlkey_unfind (&ckn->regent);
4435 assert (pthread_detach (pthread_self ()) == 0);
4436 // Do not free the ckn, as the other thread still runs
4440 // We are in control! Assimilate the TLS connection data.
4442 plainfd = ckn->plainfd;
4443 cryptfd = ckn->cryptfd;
4444 session = ckn->session;
4447 ctlkey_unfind (&ckn->regent);
4450 // Then follows the unstructured entry point for the unstructured
4451 // request to a TLS connection to renegotiate its security parameters.
4452 // Doing this in any other way than with goto would add a lot of
4453 // make-belief structure that only existed to make this looping
4454 // possible. We'd rather be honest and admit the lack of structure
4455 // that TLS has in this respect. Maybe we'll capture it one giant loop
4456 // at some point, but for now that does not seem to add any relief.
4458 fprintf (stderr, "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);
4461 // If this is server renegotiating, send a request to that end
4462 //TODO// Only invoke gnutls_rehandshake() on the server
4463 if (renegotiating && (taking_over || anonpost) && (gtls_errno == GNUTLS_E_SUCCESS)) {
4464 fprintf (stderr, "DEBUG: Invoking gnutls_rehandshake in renegotiation loop\n");
4465 gtls_errno = gnutls_rehandshake (session);
4466 if (gtls_errno == GNUTLS_E_INVALID_REQUEST) {
4467 // Clients should not do this; be forgiving
4468 gtls_errno = GNUTLS_E_SUCCESS;
4469 fprintf (stderr, "DEBUG: Client-side invocation flagged as wrong; compensated error\n");
4474 // When renegotiating TLS security, ensure that it is done securely
4475 if (renegotiating && (gnutls_safe_renegotiation_status (session) == 0)) {
4476 send_error (replycmd, EPROTO, "Renegotiation requested while secure renegotiation is unavailable on remote");
4486 if (ctlkey_unregister (ckn->regent.ctlkey)) {
4491 assert (pthread_detach (pthread_self ()) == 0);
4496 // Potentially decouple the controlling fd (ctlkey is in orig_starttls)
4497 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_FORK) {
4498 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_FORK;
4503 // Setup BDB transactions and reset credential datum fields
4505 memset (&cmd->lids, 0, sizeof (cmd->lids));
4506 manage_txn_begin (&cmd->txn);
4510 // Permit cancellation of this thread -- TODO: Cleanup?
4511 //TODO:TEST// Defer setcancelstate until copycat() activity
4513 errno = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
4515 send_error (replycmd, ESRCH, "STARTTLS handler thread cancellability refused");
4525 if (ctlkey_unregister (ckn->regent.ctlkey)) {
4530 manage_txn_rollback (&cmd->txn);
4531 assert (pthread_detach (pthread_self ()) == 0);
4536 // Check and setup the plaintext file handle
4538 send_error (replycmd, EPROTO, "You must supply a TLS-protected socket");
4543 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
4544 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
4545 if (ctlkey_unregister (ckn->regent.ctlkey)) {
4550 manage_txn_rollback (&cmd->txn);
4551 assert (pthread_detach (pthread_self ()) == 0);
4556 // Decide on support for the Anonymous Precursor, based on the
4557 // service name and its appearance in the anonpre_registry.
4558 // If the remoteid is not interesting to the client then also
4559 // support an Anonymous Precursor; we have nothing to loose.
4560 cmd->anonpre &= ~ANONPRE_EITHER;
4561 if (renegotiating) {
4562 ; // Indeed, during renegotiation we always disable ANON-DH
4563 } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_IGNORE_REMOTEID) {
4564 cmd->anonpre = ANONPRE_EITHER;
4567 int anonpre_regidx = anonpre_registry_size >> 1;
4568 int anonpre_regjmp = (anonpre_registry_size + 1) >> 1;
4570 while (anonpre_regjmp > 0) {
4571 anonpre_regjmp = anonpre_regjmp >> 1;
4572 cmp = strncasecmp (anonpre_registry [anonpre_regidx].service,
4573 cmd->cmd.pio_data.pioc_starttls.service,
4574 TLSPOOL_SERVICELEN);
4575 fprintf (stderr, "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);
4577 // anonpre_regent matches
4578 cmd->anonpre = anonpre_registry [anonpre_regidx].flags;
4580 } else if (cmp > 0) {
4581 // anonpre_regent too high
4582 anonpre_regidx -= 1 + anonpre_regjmp;
4583 if (anonpre_regidx < 0) {
4587 // anonpre_regent too low
4588 anonpre_regidx += 1 + anonpre_regjmp;
4589 if (anonpre_regidx >= anonpre_registry_size) {
4590 anonpre_regidx = anonpre_registry_size - 1;
4597 // Setup flags for client and/or server roles (make sure there is one)
4598 if ((!renegotiating) && ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REMOTEROLE_CLIENT) == 0)) {
4599 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_LOCALROLE_SERVER;
4601 if ((!renegotiating) && ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REMOTEROLE_SERVER) == 0)) {
4602 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_LOCALROLE_CLIENT;
4604 if ((cmd->cmd.pio_data.pioc_starttls.flags & (PIOF_STARTTLS_LOCALROLE_CLIENT | PIOF_STARTTLS_LOCALROLE_SERVER)) == 0) {
4606 // Neither a TLS client nor a TLS server
4608 send_error (replycmd, ENOTSUP, "Command not supported");
4614 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
4615 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
4616 if (ctlkey_unregister (ckn->regent.ctlkey)) {
4621 manage_txn_rollback (&cmd->txn);
4622 assert (pthread_detach (pthread_self ()) == 0);
4627 // Setup the TLS session. Also see doc/p2p-tls.*
4629 // TODO: GnuTLS cannot yet setup p2p connections
4631 gnutls_session_set_ptr (
4634 //TODO:DONE?// Clear various settings... creds, flags, modes? CLI/SRV?
4636 E_g2e ("Failed to initialise GnuTLS peer session",
4639 (((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)? GNUTLS_CLIENT: 0) |
4640 ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER)? GNUTLS_SERVER: 0))
4642 if (gtls_errno == GNUTLS_E_SUCCESS) {
4644 gnutls_session_set_ptr (
4649 cmd->session = session;
4651 // Setup client-specific behaviour if needed
4652 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
4653 if (!renegotiating) { //TODO:TEST//
4655 // Setup as a TLS client
4659 // Require a minimum security level for SRP
4661 //TODO:CRASH// if (gtls_errno == GNUTLS_E_SUCCESS) gnutls_srp_set_prime_bits (
4662 //TODO:CRASH// session,
4663 //TODO:CRASH// srpbits);
4665 // Setup as a TLS client
4667 // Setup for potential sending of SNI
4668 if ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_WITHOUT_SNI) == 0) {
4669 char *str = cmd->cmd.pio_data.pioc_starttls.remoteid;
4672 while (str [len] && (len < 128)) {
4673 if (str [len] == '@') {
4678 // If no usable remoteid was setup, ignore it
4679 if ((len + ofs > 0) && (len < 128)) {
4680 cmd->cmd.pio_data.pioc_starttls.remoteid [sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid)-1] = '\0';
4681 E_g2e ("Client failed to setup SNI",
4682 gnutls_server_name_set (
4691 // Setup for client credential installation in this session
4693 // Setup client-specific credentials and priority string
4694 fprintf (stderr, "DEBUG: Configuring client credentials\n");
4695 E_g2e ("Failed to configure GnuTLS as a client",
4696 configure_session (cmd,
4698 anonpost? NULL: cli_creds,
4699 anonpost? 0: cli_credcount,
4700 cmd->anonpre & ANONPRE_CLIENT));
4703 // Setup callback to server-specific behaviour if needed
4704 if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
4705 fprintf (stderr, "DEBUG: Configuring for server credentials callback if %d==0\n", gtls_errno);
4706 if (!renegotiating) { //TODO:TEST//
4707 if (gtls_errno == GNUTLS_E_SUCCESS) {
4708 gnutls_handshake_set_hook_function (
4710 GNUTLS_HANDSHAKE_CLIENT_HELLO,
4715 //TODO:TEST// configure_session _if_ not setup as a client (too)
4717 // Setup for server credential installation in this session
4719 // Setup server-specific credentials and priority string
4721 if (! (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)) {
4722 fprintf (stderr, "DEBUG: Configuring server credentials (because it is not a client)\n");
4723 E_g2e ("Failed to configure GnuTLS as a server",
4724 configure_session (cmd,
4726 anonpost? NULL: srv_creds,
4727 anonpost? 0: srv_credcount,
4728 cmd->anonpre & ANONPRE_SERVER));
4734 // Prefetch local identities that might be used in this session
4736 E_g2e ("Failed to fetch local credentials",
4737 fetch_local_credentials (cmd));
4741 // Setup a temporary priority string so handshaking can start
4742 if ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) == 0) {
4743 E_g2e ("Failed to preconfigure server token priority string",
4744 gnutls_priority_set (
4750 // Check if past code stored an error code through POSIX
4751 if (cmd->session_errno) {
4752 gtls_errno = GNUTLS_E_USER_ERROR;
4756 // Setup a timeout value as specified in the command, where TLS Pool
4757 // defines 0 as default and ~0 as infinite (GnuTLS has 0 as infinite).
4758 tout = cmd->cmd.pio_data.pioc_starttls.timeout;
4759 if (renegotiating) {
4760 ; // Do not set timeout
4762 if (tout == TLSPOOL_TIMEOUT_DEFAULT) {
4763 gnutls_handshake_set_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
4764 } else if (tout == TLSPOOL_TIMEOUT_INFINITE) {
4765 gnutls_handshake_set_timeout (session, 0);
4767 gnutls_handshake_set_timeout (session, tout);
4771 // Now setup for the GnuTLS handshake
4773 if (renegotiating) {
4774 ; // Do not setup cryptfd
4776 if (gtls_errno == GNUTLS_E_SUCCESS) {
4777 gnutls_transport_set_int (session, cryptfd);
4779 if (gtls_errno != GNUTLS_E_SUCCESS) {
4780 tlog (TLOG_TLS, LOG_ERR, "Failed to prepare for TLS: %s", gnutls_strerror (gtls_errno));
4781 if (cmd->session_errno) {
4782 send_error (replycmd, cmd->session_errno, error_getstring ());
4784 send_error (replycmd, EIO, "Failed to prepare for TLS");
4787 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
4788 gnutls_deinit (session);
4796 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
4797 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
4798 if (ctlkey_unregister (ckn->regent.ctlkey)) {
4803 manage_txn_rollback (&cmd->txn);
4804 assert (pthread_detach (pthread_self ()) == 0);
4807 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_DEBUG, "TLS handshake started over %d", cryptfd);
4810 // Take a rehandshaking step forward.
4812 gtls_errno = gnutls_handshake (session);
4814 // When data is sent before completing
4815 // the rehandshake, then it's something
4816 // harmless, given the criteria for the
4817 // anonpre_registry. We pass it on and
4818 // don't worry about it. We do report
4821 // Note: Applications should be willing
4822 // to buffer or process such early data
4823 // before the handshake is over or else
4824 // the handshake will bail out in error.
4826 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
4827 if (my_maxpreauth <= 0) {
4828 tlog (TLOG_COPYCAT, LOG_ERR, "Received unwanted early data before authentication is complete");
4829 break; // Terminate the handshake
4830 } else if (preauth == NULL) {
4831 preauth = malloc (my_maxpreauth);
4832 if (preauth == NULL) {
4833 gtls_errno = GNUTLS_E_MEMORY_ERROR;
4834 break; // Terminate the handshake
4838 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
4839 if (preauthlen >= my_maxpreauth) {
4840 tlog (TLOG_COPYCAT, LOG_ERR, "Received more early data than willing to receive (%d bytes)", my_maxpreauth);
4841 break; // Terminate the handshake
4844 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
4846 sz = gnutls_record_recv (session, preauth + preauthlen, my_maxpreauth - preauthlen);
4847 tlog (TLOG_COPYCAT, LOG_DEBUG, "Received %d remote bytes (or error if <0) from %d during anonymous precursor\n", (int) sz, cryptfd);
4850 gtls_errno = GNUTLS_E_SUCCESS;
4852 gtls_errno = sz; // It's actually an error code
4855 } while ((gtls_errno < 0) &&
4856 //DROPPED// (gtls_errno != GNUTLS_E_GOT_APPLICATION_DATA) &&
4857 //DROPPED// (gtls_errno != GNUTLS_E_WARNING_ALERT_RECEIVED) &&
4858 (gnutls_error_is_fatal (gtls_errno) == 0));
4860 // Handshake done -- initialise remote_xxx, vfystatus, got_remoteid
4861 E_g2e ("Failed to retrieve peer credentials",
4862 fetch_remote_credentials (cmd));
4863 if (gtls_errno == 0) {
4864 const gnutls_datum_t *certs;
4865 unsigned int num_certs;
4867 switch (cmd->remote_auth_type) { // Peer's cred type
4868 case GNUTLS_CRD_CERTIFICATE:
4869 if (cmd->remote_cert_count >= 1) {
4872 #ifdef PHASED_OUT_DIRECT_VALIDATION
4873 E_g2e ("Failed to validate peer",
4874 gnutls_certificate_verify_peers2 (
4880 case GNUTLS_CRD_PSK:
4881 // Difficult... what did the history say about this?
4883 cmd->vfystatus = GNUTLS_CERT_SIGNER_NOT_FOUND;
4885 case GNUTLS_CRD_SRP:
4886 // Got a credential, validation follows later on
4887 //TODO// SRP does not really auth the server
4889 cmd->vfystatus = GNUTLS_CERT_SIGNER_NOT_FOUND;
4891 case GNUTLS_CRD_ANON:
4892 // Did not get a credential, perhaps due to anonpre
4894 cmd->vfystatus = GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNATURE_FAILURE;
4897 // Inner Application extension is no true credential
4898 // Should we compare the client-requested service?
4899 // Should we renegotiate into the ALPN protocol?
4901 cmd->vfystatus = GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNATURE_FAILURE;
4904 // Unknown creds cautiously considered unauthentitcated
4906 cmd->vfystatus = ~ (unsigned short) 0; // It's all bad
4910 // Now recognise and handle the Anonymous Precursor
4911 if (((cmd->anonpre & ANONPRE_EITHER) != 0)
4912 && want_remoteid && !got_remoteid) {
4913 assert (anonpost == 0);
4914 valexp_valflag_set (cmd, 'A');
4915 // Disable ANON-protocols but keep creds from before
4916 //TODO:ELSEWHERE// tlog (TLOG_TLS, LOG_DEBUG, "Reconfiguring TLS over %d without Anonymous Precursor\n", cryptfd);
4917 //TODO:ELSEWHERE// E_g2e ("Failed to reconfigure GnuTLS without anonymous precursor",
4918 //TODO:ELSEWHERE// configure_session (cmd,
4919 //TODO:ELSEWHERE// session,
4920 //TODO:ELSEWHERE// NULL, 0,
4921 //TODO:ELSEWHERE// 0));
4922 // We do not want to use ANON-DH if the flag
4923 // ANONPRE_EXTEND_MASTER_SECRET is set for the protocol
4924 // but the remote peer does not support it. Only if
4925 // this problem cannot possibly occur, permit
4926 // my_maxpreauth > 0 for early data acceptance.
4928 if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
4929 #if GNUTLS_VERSION_NUMBER >= 0x030400
4930 gnutls_ext_priv_data_t ext;
4931 if (!gnutls_ext_get_data (session, 23, &ext)) {
4932 my_maxpreauth = maxpreauth;
4936 my_maxpreauth = maxpreauth;
4938 if (gtls_errno == 0) {
4939 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_DEBUG, "TLS handshake continued over %d after anonymous precursor", cryptfd);
4940 renegotiating = 1; // (de)selects steps
4941 anonpost = 1; // (de)selects steps
4946 if ((gtls_errno == GNUTLS_E_SUCCESS) && cmd->session_errno) {
4947 gtls_errno = GNUTLS_E_USER_ERROR;
4952 // Run the validation expression logic, using expressions we ran into
4953 fprintf (stderr, "DEBUG: Prior to valexp, gtls_errno = %d\n", gtls_errno);
4954 if (gtls_errno == GNUTLS_E_SUCCESS) {
4955 struct valexp *verun = NULL;
4956 char *valexp_conj [3];
4957 int valexp_conj_count = 0;
4958 // Setup for validation expression runthrough
4959 cmd->valexp_result = -1;
4960 if ((cmd->trust_valexp != NULL) && (0 != strcmp (cmd->trust_valexp, "1"))) {
4961 fprintf (stderr, "DEBUG: Trust valexp \"%s\" @ 0x%016x\n", cmd->trust_valexp, (uint64_t) cmd->trust_valexp);
4962 valexp_conj [valexp_conj_count++] = cmd->trust_valexp;
4964 if (cmd->lids [LID_TYPE_VALEXP - LID_TYPE_MIN].data != NULL) {
4965 // Interpret the entry, abuse p11uri as valexp
4969 gnutls_datum_t ignored;
4970 ok = dbcred_interpret (
4971 &cmd->lids [LID_TYPE_VALEXP - LID_TYPE_MIN],
4976 fprintf (stderr, "DEBUG: LocalID valexp \"%s\" @ 0x%016x (ok=%d)\n", lid_valexp, (uint64_t) lid_valexp, ok);
4977 if (ok && (lid_valexp != NULL)) {
4978 valexp_conj [valexp_conj_count++] = lid_valexp;
4980 gtls_errno = GNUTLS_E_AUTH_ERROR;
4983 fprintf (stderr, "DEBUG: Number of valexp is %d, gtls_errno=%d\n", valexp_conj_count, gtls_errno);
4984 // Optionally start computing the validation expression
4985 if ((gtls_errno == GNUTLS_E_SUCCESS) && (valexp_conj_count > 0)) {
4986 valexp_conj [valexp_conj_count] = NULL;
4987 verun = valexp_register (
4989 have_starttls_validation (),
4991 fprintf (stderr, "DEBUG: Registered to verun = 0x%016x\n", (uint64_t) verun);
4992 if (verun == NULL) {
4993 gtls_errno = GNUTLS_E_AUTH_ERROR;
4996 // When setup, run the validation expressions to completion
4997 if (verun != NULL) {
4998 while (cmd->valexp_result == -1) {
4999 ; //TODO: Tickle async predicate run completion
5001 fprintf (stderr, "DEBUG: Finishing tickling \"async\" predicates for valexp\n");
5002 if (cmd->valexp_result != 1) {
5003 tlog (TLOG_TLS, LOG_INFO, "TLS validation expression result is %d", cmd->valexp_result);
5004 gtls_errno = GNUTLS_E_AUTH_ERROR;
5005 fprintf (stderr, "DEBUG: valexp returns NEGATIVE result\n");
5007 else fprintf (stderr, "DEBUG: valexp returns POSITIVE result\n");
5008 valexp_unregister (verun);
5009 fprintf (stderr, "DEBUG: Unregistered verun 0x%016x\n", (uint64_t) verun);
5014 // Cleanup any prefetched identities
5015 for (i=LID_TYPE_MIN; i<=LID_TYPE_MAX; i++) {
5016 if (cmd->lids [i - LID_TYPE_MIN].data != NULL) {
5017 free (cmd->lids [i - LID_TYPE_MIN].data);
5020 memset (cmd->lids, 0, sizeof (cmd->lids));
5022 // Cleanup any trust_valexp duplicate string
5023 if (cmd->trust_valexp != NULL) {
5024 free (cmd->trust_valexp);
5025 cmd->trust_valexp = NULL;
5028 // Cleanup any Kerberos session key -- it served its purpose
5029 if (cmd->krb_key.contents != NULL) {
5030 // RATHER BLUNT: It shouldn't matter which krbctx_ is used...
5031 krb5_free_keyblock_contents (krbctx_srv, &cmd->krb_key);
5032 memset (&cmd->krb_key, 0, sizeof (cmd->krb_key));
5034 if (cmd->krbid_srv != NULL) {
5035 // RATHER BLUNT: It shouldn't matter which krbctx_ is used...
5036 krb5_free_principal (krbctx_srv, cmd->krbid_srv);
5037 cmd->krbid_srv = NULL;
5039 if (cmd->krbid_cli != NULL) {
5040 // RATHER BLUNT: It shouldn't matter which krbctx_ is used...
5041 krb5_free_principal (krbctx_srv, cmd->krbid_cli);
5042 cmd->krbid_cli = NULL;
5046 /* This is not proper. gnutls_certificate_set_key() suggests that these are
5047 * automatically cleaned up, and although this is not repeated in
5048 * gnutls_certificate_set_retrieve_function2() it is likely to be related.
5049 * Plus, renegotiation with this code in place bogged down on failed pcerts;
5050 * they were detected in _gnutls_selected_cert_supported_kx() but their
5051 * key exchange algorithm was never found.
5053 if (NULL != (void *) cmd->session_privatekey) {
5054 gnutls_privkey_deinit ((void *) cmd->session_privatekey);
5055 cmd->session_privatekey = (intptr_t) (void *) NULL;
5057 if (NULL != (void *) cmd->session_certificate) {
5058 gnutls_pcert_deinit ((void *) cmd->session_certificate);
5059 free ((void *) cmd->session_certificate);
5060 cmd->session_certificate = (intptr_t) (void *) NULL;
5065 // From here, assume nothing about the cmd->cmd structure; as part of
5066 // the handshake, it may have passed through the client's control, as
5067 // part of a callback. So, reinitialise the entire return structure.
5068 //TODO// Or backup the (struct pioc_starttls) before handshaking
5069 cmd->cmd.pio_cmd = orig_cmdcode;
5070 cmd->cmd.pio_data.pioc_starttls.localid [0] =
5071 cmd->cmd.pio_data.pioc_starttls.remoteid [0] = '\0';
5074 // Respond to positive or negative outcome of the handshake
5075 if (gtls_errno != GNUTLS_E_SUCCESS) {
5076 tlog (TLOG_TLS, LOG_ERR, "TLS handshake failed: %s", gnutls_strerror (gtls_errno));
5077 if (cmd->session_errno) {
5079 tlog (TLOG_TLS, LOG_ERR, "Underlying cause may be: %s", strerror (cmd->session_errno));
5080 errstr = error_getstring ();
5081 if (errstr == NULL) {
5082 errstr = "TLS handshake failed";
5084 send_error (replycmd, cmd->session_errno, errstr);
5086 send_error (replycmd, EPERM, "TLS handshake failed");
5092 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
5093 gnutls_deinit (session);
5101 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
5102 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
5103 if (ctlkey_unregister (ckn->regent.ctlkey)) {
5108 manage_txn_rollback (&cmd->txn);
5109 assert (pthread_detach (pthread_self ()) == 0);
5112 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_INFO, "TLS handshake succeeded over %d", cryptfd);
5113 //TODO// extract_authenticated_remote_identity (cmd);
5117 // Request the plaintext file descriptor with a callback
5119 uint32_t oldcmd = cmd->cmd.pio_cmd;
5120 struct command *resp;
5121 cmd->cmd.pio_cmd = PIOC_PLAINTEXT_CONNECT_V2;
5122 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Calling send_callback_and_await_response with PIOC_PLAINTEXT_CONNECT_V2");
5123 resp = send_callback_and_await_response (replycmd, 0);
5124 assert (resp != NULL); // No timeout, should be non-NULL
5125 if (resp->cmd.pio_cmd != PIOC_PLAINTEXT_CONNECT_V2) {
5126 tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has unexpected command code");
5127 send_error (replycmd, EINVAL, "Callback response has bad command code");
5132 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
5133 gnutls_deinit (session);
5137 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
5138 if (ckn) { /* TODO: CHECK NEEDED? PRACTICE=>YES */
5139 if (ctlkey_unregister (ckn->regent.ctlkey)) {
5144 manage_txn_rollback (&cmd->txn);
5145 assert (pthread_detach (pthread_self ()) == 0);
5148 cmd->cmd.pio_cmd = oldcmd;
5149 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);
5150 plainfd = resp->passfd;
5154 tlog (TLOG_UNIXSOCK, LOG_ERR, "No plaintext file descriptor supplied to TLS Pool");
5155 send_error (replycmd, EINVAL, "No plaintext file descriptor supplied to TLS Pool");
5160 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
5161 gnutls_deinit (session);
5165 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
5166 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
5167 if (ctlkey_unregister (ckn->regent.ctlkey)) {
5172 manage_txn_rollback (&cmd->txn);
5173 assert (pthread_detach (pthread_self ()) == 0);
5176 //DEFERRED// send_command (replycmd, -1); // app sent plainfd to us
5179 // Copy TLS records until the connection is closed
5180 manage_txn_commit (&cmd->txn);
5181 if (!renegotiating) {
5182 ckn = (struct ctlkeynode_tls *) malloc (sizeof (struct ctlkeynode_tls));
5185 send_error (replycmd, ENOMEM, "Out of memory allocating control key structure");
5187 int detach = (orig_starttls.flags & PIOF_STARTTLS_DETACH) != 0;
5188 ckn->session = session;
5189 ckn->owner = pthread_self ();
5190 ckn->cryptfd = cryptfd;
5191 ckn->plainfd = plainfd;
5192 //DEBUG// fprintf (stderr, "Registering control key\n");
5193 if (renegotiating || (ctlkey_register (orig_starttls.ctlkey, &ckn->regent, security_tls, detach ? INVALID_POOL_HANDLE : cmd->clientfd, forked) == 0)) {
5194 int copied = GNUTLS_E_SUCCESS;
5195 send_command (replycmd, -1); // app sent plainfd to us
5199 // Check on extended master secret if desired
5200 if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
5201 #if GNUTLS_VERSION_NUMBER >= 0x030400
5202 gnutls_ext_priv_data_t ext;
5203 if (!gnutls_ext_get_data (session, 23, &ext)) {
5204 cmd->anonpre &= ~ANONPRE_EXTEND_MASTER_SECRET;
5208 if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
5209 tlog (TLOG_COPYCAT, LOG_ERR, "Received %d remote bytes from anonymous precursor but lacking %s-required authentication through extended master secret", orig_starttls.service);
5210 gtls_errno = GNUTLS_E_LARGE_PACKET;
5213 } else if (write (plainfd, preauth, preauthlen) == preauthlen) {
5214 tlog (TLOG_COPYCAT, LOG_DEBUG, "Passed on %d remote bytes from anonymous precursor to %d\n", preauthlen, plainfd);
5217 copied = copycat (plainfd, cryptfd, session, detach ? INVALID_POOL_HANDLE : cmd->clientfd);
5219 tlog (TLOG_COPYCAT, LOG_DEBUG, "Failed to pass on %d remote bytes from anonymous precursor to %d\n", preauthlen, plainfd);
5222 copied = copycat (plainfd, cryptfd, session, detach ? INVALID_POOL_HANDLE : cmd->clientfd);
5224 // Renegotiate if copycat asked us to
5225 if (copied == GNUTLS_E_REHANDSHAKE) {
5226 // Yes, goto is a dirty technique. On the
5227 // other hand, so is forcing unstructured
5228 // code flows into a make-belief structure
5229 // that needs changing over and over again.
5230 // I fear goto is the most reasonable way
5231 // of handling this rather obtuse structure
5232 // of renegotiation of security in TLS :(
5233 //TODO// Ensure secure renegotiation!!!
5235 replycmd = NULL; // Bypass all send_XXX()
5236 memcpy (&cmd_copy, cmd, sizeof (cmd_copy));
5238 memcpy (cmd->cmd.pio_data.pioc_starttls.localid, orig_starttls.localid, sizeof (cmd->cmd.pio_data.pioc_starttls.localid));
5239 memcpy (cmd->cmd.pio_data.pioc_starttls.remoteid, orig_starttls.remoteid, sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid));
5240 cmd->cmd.pio_data.pioc_starttls.flags = orig_starttls.flags & ~PIOF_STARTTLS_LOCALID_CHECK;
5241 // Disabling the flag causing LOCALID_CHECK
5242 // ...and plainfd >= 0 so no PLAINTEXT_CONNECT
5243 // ...so there will be no callbacks to cmd
5244 fprintf (stderr, "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);
5247 //DEBUG// fprintf (stderr, "Unregistering control key\n");
5248 // Unregister by ctlkey, which should always succeed
5249 // if the TLS connection hadn't been closed down yet;
5250 // and if it does, the memory can be freed. Note that
5251 // the ctlkey is not taken from the ckn, which may
5252 // already have been freed if the ctlfd was closed
5253 // and the connection could not continue detached
5254 // (such as after forking it).
5255 fprintf (stderr, "ctlkey_unregister under ckn=0x%x at %d\n", ckn, __LINE__);
5256 if (ctlkey_unregister (orig_starttls.ctlkey)) {
5260 //DEBUG// fprintf (stderr, "Unregistered control key\n");
5262 send_error (replycmd, ENOENT, "Failed to register control key for TLS connection");
5271 cleanup_any_remote_credentials (cmd);
5273 fprintf (stderr, "gnutls_deinit (0x%x) at %d\n", session, __LINE__);
5274 gnutls_deinit (session);
5277 assert (pthread_detach (pthread_self ()) == 0);
5283 * The starttls function responds to an application's request to
5284 * setup TLS for a given file descriptor, and return a file descriptor
5285 * with the unencrypted view when done. The main thing done here is to
5286 * spark off a new thread that handles the operations.
5288 void starttls (struct command *cmd) {
5289 /* Create a thread and, if successful, wait for it to unlock cmd */
5290 errno = pthread_create (&cmd->handler, NULL, starttls_thread, (void *) cmd);
5292 send_error (cmd, ESRCH, "STARTTLS thread refused");
5295 //TODO:TEST// Thread detaches itself before terminating w/o followup
5297 errno = pthread_detach (cmd->handler);
5299 pthread_cancel (cmd->handler);
5300 send_error (cmd, ESRCH, "STARTTLS thread detachment refused");
5308 * Run the PRNG for a TLS connection, identified by its control key. If the connection
5309 * is not a TLS connection, or if the control key is not found, reply with ERROR;
5310 * otherwise, the session should help to create pseudo-random bytes.
5312 void starttls_prng (struct command *cmd) {
5313 uint8_t in1 [TLSPOOL_PRNGBUFLEN];
5314 uint8_t in2 [TLSPOOL_PRNGBUFLEN];
5315 int16_t in1len, in2len, prnglen;
5316 struct ctlkeynode_tls *ckn = NULL;
5319 int gtls_errno = GNUTLS_E_SUCCESS;
5320 struct pioc_prng *prng = &cmd->cmd.pio_data.pioc_prng;
5322 // Find arguments and validate them
5323 in1len = prng->in1_len;
5324 in2len = prng->in2_len;
5325 prnglen = prng->prng_len;
5326 err = err || (in1len <= 0);
5327 err = err || (prnglen > TLSPOOL_PRNGBUFLEN);
5328 err = err || ((TLSPOOL_CTLKEYLEN + in1len + (in2len >= 0? in2len: 0))
5329 > TLSPOOL_PRNGBUFLEN);
5331 memcpy (in1, prng->buffer + TLSPOOL_CTLKEYLEN , in1len);
5333 memcpy (in2, prng->buffer + TLSPOOL_CTLKEYLEN + in1len, in2len);
5336 // - check the label string
5337 prefixes = tlsprng_label_prefixes;
5338 while ((!err) && (*prefixes)) {
5339 char *pf = *prefixes++;
5340 if (strlen (pf) != in1len) {
5343 if (strcmp (pf, in1) != 0) {
5347 if (*prefixes == NULL) {
5348 // RFC 5705 defines a private-use prefix "EXPERIMENTAL"
5349 if ((in1len <= 12) || (strncmp (in1, "EXPERIMENTAL", 12) != 0)) {
5353 // - check the ctlkey (and ensure it is for TLS)
5355 //DEBUG// fprintf (stderr, "Hoping to find control key\n");
5356 ckn = (struct ctlkeynode_tls *) ctlkey_find (prng->buffer, security_tls, cmd->clientfd);
5359 // Now wipe the PRNG buffer to get rid of any sensitive bytes
5360 memset (prng->buffer, 0, TLSPOOL_PRNGBUFLEN);
5362 // If an error occurrend with the command, report it now
5364 send_error (cmd, EINVAL, "TLS PRNG request invalid");
5365 // ckn is NULL if err != 0, so no need for ctlkey_unfind()
5369 send_error (cmd, ENOENT, "Invalid control key");
5373 // Now actually invoke the PRNG command in the GnuTLS backend
5375 E_g2e ("GnuTLS PRNG based on session master key failed",
5376 gnutls_prf_rfc5705 (ckn->session,
5378 (in2len >= 0)? in2len: 0, (in2len >= 0) ? in2: NULL,
5379 prnglen, prng->buffer));
5380 err = err || (errno != 0);
5382 // Wipe temporary data / buffers for security reasons
5383 memset (in1, 0, sizeof (in1));
5384 memset (in2, 0, sizeof (in2));
5385 ctlkey_unfind ((struct ctlkeynode *) ckn);
5387 // Return the outcome to the user
5389 send_error (cmd, errno? errno: EIO, "PRNG in TLS backend failed");
5391 send_command (cmd, -1);
5396 /* Flying signer functionality. Create an on-the-fly certificate because
5397 * the lidentry daemon and/or application asks for this to represent the
5398 * local identity. Note that this will only work if the remote party
5399 * accepts the root identity under which on-the-signing is done.
5401 * When no root credentials have been configured, this function will
5402 * fail with GNUTLS_E_AGAIN; it may be used as a hint to try through
5403 * other (more conventional) means to obtain a client certificate.
5405 * The API of this function matches that of fetch_local_credentials()
5406 * and that is not a coincidence; this is a drop-in replacement in some
5409 * Limitations: The current implementation only supports X.509 certificates
5410 * to be generated on the fly. So, this will set LID_TYPE_X509, if anything.
5412 gtls_error certificate_onthefly (struct command *cmd) {
5413 gtls_error gtls_errno = GNUTLS_E_SUCCESS;
5414 gnutls_x509_crt_t otfcert;
5416 gnutls_x509_subject_alt_name_t altnmtp;
5421 if ((onthefly_issuercrt == NULL) || (onthefly_issuerkey == NULL) || (onthefly_subjectkey == NULL)) {
5422 // Not able to supply on-the-fly certificates; try someway else
5423 return GNUTLS_E_AGAIN;
5425 if (cmd->cmd.pio_data.pioc_starttls.localid [0] == '\0') {
5426 return GNUTLS_E_NO_CERTIFICATE_FOUND;
5428 if (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data != NULL) {
5429 free (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data);
5430 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data = NULL;
5431 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
5435 // Create an empty certificate
5436 E_g2e ("Failed to initialise on-the-fly certificate",
5437 gnutls_x509_crt_init (&otfcert));
5438 if (gtls_errno != GNUTLS_E_SUCCESS) {
5443 // Fill the certificate with the usual field
5444 E_g2e ("Failed to set on-the-fly certificate to non-CA mode",
5445 gnutls_x509_crt_set_ca_status (otfcert, 0));
5446 E_g2e ("Failed to set on-the-fly certificate version",
5447 gnutls_x509_crt_set_version (otfcert, 3));
5448 onthefly_serial++; //TODO// Consider a random byte string
5449 E_g2e ("Failed to set on-the-fly serial number",
5450 gnutls_x509_crt_set_serial (otfcert, &onthefly_serial, sizeof (onthefly_serial)));
5451 // Skip gnutls_x509_crt_set_issuer_by_dn_by_oid(), added when signing
5453 E_g2e ("Failed to set on-the-fly activation time to now - 2 min",
5454 gnutls_x509_crt_set_activation_time (otfcert, now - 120));
5455 E_g2e ("Failed to set on-the-fly expiration time to now + 3 min",
5456 gnutls_x509_crt_set_expiration_time (otfcert, now + 180));
5457 E_g2e ("Setup certificate CN with local identity",
5458 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? */
5459 E_g2e ("Setup certificate OU with TLS Pool on-the-fly",
5460 gnutls_x509_crt_set_dn_by_oid (otfcert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, "TLS Pool on-the-fly", 19));
5461 if (strchr (cmd->cmd.pio_data.pioc_starttls.localid, '@')) {
5462 // localid has the format of an emailAddress
5463 altnmtp = GNUTLS_SAN_RFC822NAME;
5465 // localid has the format of a dnsName
5466 altnmtp = GNUTLS_SAN_DNSNAME;
5468 E_g2e ("Failed to set subjectAltName to localid",
5469 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));
5470 //TODO:SKIP, hoping that signing adds: gnutls_x509_crt_set_authority_key_id()
5471 //TODO:SKIP, hoping that a cert without also works: gnutls_x509_crt_set_subjectkey_id()
5472 //TODO:SKIP? gnutls_x509_crt_set_extension_by_oid
5473 //TODO: gnutls_x509_crt_set_key_usage
5474 //TODO:SKIP? gnutls_x509_crt_set_ca_status
5475 for (i=0; i < svcusage_registry_size; i++) {
5476 if (strcmp (svcusage_registry [i].service, cmd->cmd.pio_data.pioc_starttls.service) == 0) {
5477 const char **walker;
5478 E_g2e ("Failed to setup basic key usage during on-the-fly certificate creation",
5479 gnutls_x509_crt_set_key_usage (otfcert, svcusage_registry [i].usage));
5480 walker = svcusage_registry [i].oids_non_critical;
5483 E_g2e ("Failed to append non-critical extended key purpose during on-the-fly certificate creation",
5484 gnutls_x509_crt_set_key_purpose_oid (otfcert, *walker, 0));
5488 walker = svcusage_registry [i].oids_critical;
5491 E_g2e ("Failed to append critical extended key purpose during on-the-fly certificate creation",
5492 gnutls_x509_crt_set_key_purpose_oid (otfcert, *walker, 1));
5499 E_g2e ("Failed to et the on-the-fly subject key",
5500 gnutls_x509_crt_set_key (otfcert, onthefly_subjectkey));
5501 /* TODO: The lock below should not be necessary; it is handled by p11-kit
5502 * or at least it ought to be. What I found however, was that
5503 * a client and server would try to use the onthefly_issuerkey
5504 * at virtually the same time, and then the second call to
5505 * C_SignInit returns CKR_OPERATION_ACTIVE. The lock solved this.
5506 * This makes me frown about server keys stored in PKCS #11...
5508 {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"); } }
5509 assert (pthread_mutex_lock (&onthefly_signer_lock) == 0);
5510 E_g2e ("Failed to sign on-the-fly certificate",
5511 gnutls_x509_crt_privkey_sign (otfcert, onthefly_issuercrt, onthefly_issuerkey, GNUTLS_DIG_SHA256, 0));
5512 pthread_mutex_unlock (&onthefly_signer_lock);
5515 // Construct cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data+size for this certificate
5516 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
5517 if (gtls_errno == GNUTLS_E_SUCCESS) {
5518 gtls_errno = gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_DER, NULL, &cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size);
5519 if (gtls_errno == GNUTLS_E_SHORT_MEMORY_BUFFER) {
5520 // This is as expected, now .size will have been set
5521 gtls_errno = GNUTLS_E_SUCCESS;
5523 if (gtls_errno = GNUTLS_E_SUCCESS) {
5524 // Something must be wrong if we receive OK
5525 gtls_errno = GNUTLS_E_INVALID_REQUEST;
5528 E_g2e ("Error while measuring on-the-fly certificate size",
5531 uint8_t *ptr = NULL;
5532 if (gtls_errno == GNUTLS_E_SUCCESS) {
5533 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size += 4 + strlen (onthefly_p11uri) + 1;
5534 ptr = malloc (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size);
5536 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
5537 gnutls_x509_crt_deinit (otfcert);
5538 return GNUTLS_E_MEMORY_ERROR;
5543 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data = ptr;
5544 * (uint32_t *) ptr = htonl (LID_TYPE_X509 | LID_ROLE_BOTH);
5546 strcpy (ptr, onthefly_p11uri);
5547 ptr += strlen (onthefly_p11uri) + 1;
5548 restsz = cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size - 4 - strlen (onthefly_p11uri) - 1;
5549 E_g2e ("Failed to export on-the-fly certificate as a credential",
5550 gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_DER, ptr, &restsz));
5551 char *pembuf [10000];
5552 size_t pemlen = sizeof (pembuf) - 1;
5553 int exporterror = gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_PEM, pembuf, &pemlen);
5554 if (exporterror == 0) {
5555 pembuf [pemlen] = '\0';
5556 fprintf (stderr, "DEBUG: otfcert ::=\n%s\n", pembuf);
5558 fprintf (stderr, "DEBUG: otfcert export to PEM failed with %d, gtls_errno already was %d\n", exporterror, gtls_errno);
5563 // Cleanup the allocated and built structures
5564 gnutls_x509_crt_deinit (otfcert);
5567 // Return the overall result that might have stopped otf halfway