Assignment clobbers value in if
[tlspool] / src / starttls.c
1 /* tlspool/starttls.c -- Setup and validation handler for TLS session */
2
3 #include "whoami.h"
4
5 #include <stdlib.h>
6 #include <stdint.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <memory.h>
10 #include <string.h>
11 #include <pthread.h>
12 #include <assert.h>
13
14 #include <ctype.h>
15
16 #include <unistd.h>
17 #include <syslog.h>
18 #include <errno.h>
19
20 #include <gnutls/gnutls.h>
21 #include <gnutls/pkcs11.h>
22 #include <gnutls/abstract.h>
23 #include <gnutls/dane.h>
24
25 #include <p11-kit/pkcs11.h>
26
27 #include <tlspool/commands.h>
28 #include <tlspool/internal.h>
29
30 #include <libtasn1.h>
31
32 #include <krb5.h>
33 /* Plus, from k5-int.h: */
34 krb5_error_code KRB5_CALLCONV krb5_decrypt_tkt_part(krb5_context,
35                                                     const krb5_keyblock *,
36                                                     krb5_ticket * );
37
38
39 #include <quick-der/api.h>
40 #include <quick-der/rfc4120.h>
41 typedef DER_OVLY_rfc4120_Ticket ticket_t;
42 typedef DER_OVLY_rfc4120_Authenticator authenticator_t;
43 typedef DER_OVLY_rfc4120_EncryptedData encrypted_data_t;
44
45 #include <tlspool/internal.h>
46
47 #ifdef WINDOWS_PORT
48 #include <winsock2.h>
49 #include <ws2tcpip.h>
50 #else
51 #include <poll.h>
52 #include <sys/types.h>
53 #include <sys/socket.h>
54
55 #include <krb5.h>
56
57 #ifndef __MINGW64__
58 #include <arpa/inet.h>
59 #endif
60 #include <netinet/in.h>
61 #endif
62
63 #ifdef WINDOWS_PORT
64 #include <windows.h>
65 #define RECV_FLAGS 0
66 #define SHUT_RD SD_RECEIVE
67 #define SHUT_WR SD_SEND
68 #else /* WINDOWS_PORT */
69 #define RECV_FLAGS MSG_DONTWAIT | MSG_NOSIGNAL
70 #endif /* WINDOWS_PORT */
71
72 #include "manage.h"
73 #include "donai.h"
74 #include "trust.h"
75
76
77 #if EXPECTED_LID_TYPE_COUNT != LID_TYPE_CNT
78 #error "Set EXPECTED_LID_TYPE_COUNT in <tlspool/internal.h> to match LID_TYPE_CNT"
79 #endif
80
81
82 /* This module hosts TLS handlers which treat an individual connection.
83  *
84  * Initially, the TLS setup is processed, which means validating the
85  * connection.  If and when this succeeds, a continued process is needed
86  * to encrypt and decrypt traffic while it is in transit.
87  *
88  * Every TLS connection (including the attempt to set it up) is hosted in
89  * its own thread.  This means that it can abide time to wait for PINENTRY,
90  * LOCALID or LIDENTRY responses.  It also means a very clear flow when the
91  * time comes to destroy a connection.
92  *
93  * While encrypting and decrypting traffic passing through, the thread
94  * will use its own poll() call, and thus offload the potentially large
95  * one of the main thread, which is supposed to be a low-traffic task.
96  * The set of file descriptors used by the session-handler threads are
97  * in contrast very small and can easily be started for every single
98  * packet passing through.
99  *
100  * Might the user terminate a process while this one is waiting for a
101  * callback command request, then the main TLS pool thread will take
102  * care of taking down this thread.  To that end, it sets the followup
103  * pointer that normally holds a callback response to NULL, and then
104  * permits this thread to run again.  This will lead to a shutdown of
105  * this process, and proper closing of all connections.  The remote peer
106  * will therefore see the result of a local kill as a connection reset.
107  *
108  * In case one of the end points of the connection is terminated, a
109  * similar thing will happen; the thread will terminate itself after
110  * a cleanup of any outstanding resources.  This, once again, leads
111  * to passing on the reset of a connection between the encrypted and
112  * side of the connection.
113  */
114
115
116
117 /*
118  * GnuTLS infrastructure setup.
119  * Session-shared DH-keys, credentials structures, and so on.
120  */
121 static gnutls_dh_params_t dh_params;
122
123 struct credinfo {
124         gnutls_credentials_type_t credtp;
125         void *cred;
126 };
127
128 #define EXPECTED_SRV_CREDCOUNT 3
129 #define EXPECTED_CLI_CREDCOUNT 3
130 static struct credinfo srv_creds [EXPECTED_SRV_CREDCOUNT];
131 static struct credinfo cli_creds [EXPECTED_CLI_CREDCOUNT];
132 static int srv_credcount = 0;
133 static int cli_credcount = 0;
134 static const char onthefly_p11uri[] = "pkcs11:manufacturer=ARPA2.net;token=TLS+Pool+internal;object=on-the-fly+signer;type=private;serial=1";
135 static unsigned long long onthefly_serial;  //TODO: Fill with now * 1000
136 static gnutls_x509_crt_t onthefly_issuercrt = NULL;
137 static gnutls_privkey_t onthefly_issuerkey = NULL;
138 static gnutls_x509_privkey_t onthefly_subjectkey = NULL;
139 static pthread_mutex_t onthefly_signer_lock = PTHREAD_MUTEX_INITIALIZER;
140
141 #ifdef HAVE_TLS_KDH
142 static krb5_context krbctx_cli, krbctx_srv;
143 static krb5_keytab  krb_kt_cli, krb_kt_srv;
144 static bool         got_cc_cli, got_cc_srv;
145 static int have_key_tgt_cc (
146                                 struct command *cmd, // in, session context
147                                 krb5_context ctx,    // in, kerberos context
148                                 bool use_cc,         // in, whether to use cc
149                                 krb5_kvno kvno,      // in, kvno (0 for highest)
150                                 krb5_enctype enctype,// in, enctype (0 for any)
151                                 char *p11uri,        // in/opt, PKCS #11 pwd URI
152                                 krb5_keytab kt,      // in/opt, keytab
153                                 krb5_keyblock *key,  // opt/opt session key
154                                 krb5_creds **tgt,    // out/opt, tkt granting tkt
155                                 krb5_ccache *cc);    // out/opt, cred cache
156 static int have_service_ticket (
157                                 struct command *cmd, // in, session context
158                                 krb5_context ctx,    // in, kerberos context
159                                 krb5_ccache cc_opt,  // in/opt, credcache
160                                 krb5_principal cli,  // in, client principal
161                                 krb5_creds **ticket);// out/opt, tkt granting tkt
162 #endif
163
164
165 /* The local variation on the ctlkeynode structure, with TLS-specific fields
166  */
167 struct ctlkeynode_tls {
168         struct ctlkeynode regent;       // Structure for ctlkey_register()
169         gnutls_session_t session;       // Additional data specifically for TLS
170         pthread_t owner;                // For interruption of copycat()
171         int plainfd;                    // Plain-side connection
172         int cryptfd;                    // Crypt-side connection
173 };
174
175 /* A local structure used for iterating over PKCS #11 entries.  This is used
176  * to iterate over password attempts, no more than MAX_P11ITER_ATTEMPTS though.
177  *
178  * When a password is requested but none is available, the password request
179  * will be passed to the user using the PIN callback mechanism.  When this
180  * is done, a warning may be given that the TLS Pool overtakes control over
181  * the account (when thusly configured).  In support of that option, the
182  * $attempt is counted and the respective $p11pwd is CK_INVALID_HANDLE.
183  * TODO: Perhaps interact for saving, such as entering an certain string?
184  *
185  * When a number of attempts needs to be made before success, then any
186  * objects that precede a succeeded $attempt can be removed.  The same may
187  * be true for any objects after it.
188  *
189  * This mechanism is useful during password changes.  When a new password is
190  * desired by the KDC, then a random object is created and returned twice.
191  * To support repeated delivery, the password is stored in $newpwd;
192  * In this case, the safest choice is still to leave the last $p11pwd.
193  *
194  * The caller may decide to invoke the password changing procedure, namely
195  * after manual entry as evidenced by the condition
196  *      (attempts >= 0) &&
197  *      (attempts < MAX_P11_ITER_ATTEMPTS) &&
198  *      (p11pwd [attempt] == CK_INVALID_HANDLE)
199  *
200  * TODO: This is a designed data structure, but not yet installed.
201  *
202  * TODO: It is more useful to abolish passwords, and truly use PKCS #11.
203  */
204 #define MAX_P11ITER_ATTEMPTS 3
205 struct pkcs11iter {
206         struct command *cmd;            // The session command structure
207         CK_SESSION_HANDLE p11ses;       // The PKCS #11 session in motion
208         int attempt;                    // Starts at -1, incremented by pwd entry
209         CK_OBJECT_HANDLE p11pwd [MAX_P11ITER_ATTEMPTS];
210                                         // Sequence of $attempt objects returned
211         CK_OBJECT_HANDLE newpwd;        // Set when a new password was offered
212 };
213
214 /* The list of accepted Exporter Label Prefixes for starttls_prng()
215  */
216 char *tlsprng_label_prefixes [] = {
217         // Forbidden by RFC 5705: "client finished",
218         // Forbidden by RFC 5705: "server finished",
219         // Forbidden by RFC 5705: "master secret",
220         // Forbidden by RFC 5705: "key expansion",
221         "client EAP encryption",                // not suited for DTLS
222         "ttls keying material",                 // not suited for DTLS
223         "ttls challenge",                       // not suited for DTLS
224         "EXTRACTOR-dtls_srtp",
225         "EXPORTER_DTLS_OVER_SCTP",
226         "EXPORTER-ETSI-TC-M2M-Bootstrap",
227         "EXPORTER-ETSI-TC-M2M-Connection",
228         "TLS_MK_Extr",
229         "EXPORTER_GBA_Digest",
230         "EXPORTER: teap session key seed",      // not suited for DTLS
231         "EXPORTER-oneM2M-Bootstrap",
232         "EXPORTER-oneM2M-Connection",
233         NULL
234 };
235
236 /* The registry with the service names that are deemed safe for an
237  * anonymous precursor phase; that is, the service names that may offer
238  * ANON-DH initially, and immediately renegotiate an authenticated
239  * connection.  See doc/anonymising-precursor.* for more information.
240  *
241  * The registry is ordered by case-independent service name, so it can
242  * be searched in 2log time.  Service names are as defined by IANA in the
243  * "Service Name and Transport Protocol Port Number Registry".
244  *
245  * The entries in the registry depend on the role played; either as a
246  * client or as a server.  This refers to the local node, and depends on
247  * uncertainty of the remote party's TLS implementation and whether or
248  * not the protocol could lead to the remote sending information that
249  * requires authentication before the secure renogiation into an
250  * authenticated connection has been completed by this side.  This is
251  * a protocol-dependent matter and the registry provided here serves to
252  * encapsulate this knowledge inside the TLS Pool instead of bothering
253  * application designers with it.  Entries that are not found in the
254  * registry are interpreted as not allowing an anonymising precursor.
255  *
256  * Note that ANONPRE_EXTEND_MASTER_SECRET cannot be verified before
257  * GnuTLS version 3.4.0; see "imap" below for the resulting impact.  This
258  * also impacts dynamic linking, because 3.4.0 introduces the new function
259  * gnutls_ext_get_data() that is used for this requirement.
260  */
261 #define ANONPRE_FORBID 0x00
262 #define ANONPRE_CLIENT 0x01
263 #define ANONPRE_SERVER 0x02
264 #define ANONPRE_EITHER (ANONPRE_CLIENT | ANONPRE_SERVER)
265 #define ANONPRE_EXTEND_MASTER_SECRET 0x10
266 struct anonpre_regentry {
267         char *service;
268         uint8_t flags;
269 };
270 struct anonpre_regentry anonpre_registry [] = {
271 /* This registry is commented out for now, although the code to use it seems
272  * to work fine.  GnuTLS however, does not seem to support making the switch
273  * from ANON-ECDH to an authenticated handshake.  Details:
274  * http://lists.gnutls.org/pipermail/gnutls-help/2015-November/003998.html
275  *
276         { "generic_anonpre", ANONPRE_EITHER },  // Name invalid as per RFC 6335
277         { "http", ANONPRE_CLIENT },     // Server also if it ignores client ID
278 #if GNUTLS_VERSION_NUMBER < 0x030400
279         { "imap", ANONPRE_SERVER },
280 #else
281         { "imap", ANONPRE_EITHER | ANONPRE_EXTEND_MASTER_SECRET },
282 #endif
283         { "pop3", ANONPRE_EITHER },
284         { "smtp", ANONPRE_EITHER },
285  *
286  * End of commenting out the registry
287  */
288 };
289 const int anonpre_registry_size = sizeof (anonpre_registry) / sizeof (struct anonpre_regentry);
290
291
292 /* The registry of Key Usage and Extended Key Usage for any given service name.
293  */
294 static const char *http_noncrit [] = { GNUTLS_KP_TLS_WWW_SERVER, GNUTLS_KP_TLS_WWW_CLIENT, NULL };
295 struct svcusage_regentry {
296         char *service;
297         unsigned int usage;
298         const char **oids_non_critical;
299         const char **oids_critical;
300 };
301 struct svcusage_regentry svcusage_registry [] = {
302         { "generic_anonpre",
303                 GNUTLS_KEY_KEY_ENCIPHERMENT |
304                 GNUTLS_KEY_KEY_AGREEMENT,
305                 NULL,
306                 NULL
307         },
308         { "http",
309                 GNUTLS_KEY_DIGITAL_SIGNATURE |
310                 GNUTLS_KEY_KEY_ENCIPHERMENT |
311                 GNUTLS_KEY_KEY_AGREEMENT,
312                 http_noncrit,
313                 NULL
314         },
315 };
316 const int svcusage_registry_size = sizeof (svcusage_registry) / sizeof (struct svcusage_regentry);
317
318
319 /* The maximum number of bytes that can be passed over a TLS connection before
320  * the authentication is complete in case of a anonymous precursor within a
321  * protocol that ensures that this cannot be a problem.
322  */
323 int maxpreauth;
324
325 /* The priorities cache for "NORMAL" -- used to preconfigure the server,
326  * actually to overcome its unwillingness to perform the handshake, and
327  * leave it to srv_clienthello() to setup the priority string.
328  */
329 gnutls_priority_t priority_normal;
330
331
332 /* Map a GnuTLS call (usually a function call) to a POSIX errno,
333  * optionally reporting an errstr to avoid loosing information.
334  * Retain errno if it already exists.
335  * Continue if errno differs from 0, GnuTLS may "damage" it even when OK. */
336 #define E_g2e(errstr,gtlscall) { \
337         if (gtls_errno == GNUTLS_E_SUCCESS) { \
338                 gtls_errno = (gtlscall); \
339                 if (gtls_errno != GNUTLS_E_SUCCESS) { \
340                         error_gnutls2posix (gtls_errno, errstr); \
341                 } \
342         } \
343 }
344
345 /* Cleanup when GnuTLS leaves errno damaged but returns no gtls_errno */
346 #define E_gnutls_clear_errno() { \
347         if (gtls_errno == GNUTLS_E_SUCCESS) { \
348                 errno = 0; \
349         } \
350 }
351
352 /* Error number translation, including error string setup.  See E_g2e(). */
353 void error_gnutls2posix (int gtls_errno, char *new_errstr) {
354         char *errstr;
355         register int newerrno;
356         //
357         // Sanity checks
358         if (gtls_errno == GNUTLS_E_SUCCESS) {
359                 return;
360         }
361         errstr =  error_getstring ();
362         if (errstr != NULL) {
363                 return;
364         }
365         //
366         // Report the textual error
367         if (new_errstr == NULL) {
368                 new_errstr = "GnuTLS error";
369         }
370         tlog (TLOG_TLS, LOG_ERR, "%s: %s",
371                 new_errstr,
372                 gnutls_strerror (gtls_errno));
373         error_setstring (new_errstr);
374         //
375         // Translate error to a POSIX errno value
376         switch (gtls_errno) {
377         case GNUTLS_E_SUCCESS:
378                 return;
379         case GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM:
380         case GNUTLS_E_UNKNOWN_CIPHER_TYPE:
381         case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
382         case GNUTLS_E_UNWANTED_ALGORITHM:
383         case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
384         case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
385         case GNUTLS_E_X509_UNKNOWN_SAN:
386         case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
387         case GNUTLS_E_UNKNOWN_PK_ALGORITHM:
388         case GNUTLS_E_NO_TEMPORARY_RSA_PARAMS:
389         case GNUTLS_E_NO_COMPRESSION_ALGORITHMS:
390         case GNUTLS_E_NO_CIPHER_SUITES:
391         case GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED:
392         case GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE:
393         case GNUTLS_E_UNKNOWN_HASH_ALGORITHM:
394         case GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE:
395         case GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE:
396         case GNUTLS_E_NO_TEMPORARY_DH_PARAMS:
397         case GNUTLS_E_UNKNOWN_ALGORITHM:
398         case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
399         case GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED:
400         case GNUTLS_E_X509_UNSUPPORTED_OID:
401         case GNUTLS_E_CHANNEL_BINDING_NOT_AVAILABLE:
402         case GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL:
403         case GNUTLS_E_ECC_NO_SUPPORTED_CURVES:
404         case GNUTLS_E_ECC_UNSUPPORTED_CURVE:
405         case GNUTLS_E_X509_UNSUPPORTED_EXTENSION:
406         case GNUTLS_E_NO_CERTIFICATE_STATUS:
407         case GNUTLS_E_NO_APPLICATION_PROTOCOL:
408 #ifdef GNUTLS_E_NO_SELF_TEST
409         case GNUTLS_E_NO_SELF_TEST:
410 #endif
411                 newerrno = EOPNOTSUPP;
412                 break;
413         case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
414         case GNUTLS_E_INVALID_REQUEST:
415                 newerrno = EINVAL;
416                 break;
417         case GNUTLS_E_INVALID_SESSION:
418         case GNUTLS_E_REHANDSHAKE:
419         case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
420                 newerrno = ENOTCONN;
421                 break;
422         case GNUTLS_E_PUSH_ERROR:
423         case GNUTLS_E_PULL_ERROR:
424         case GNUTLS_E_PREMATURE_TERMINATION:
425         case GNUTLS_E_SESSION_EOF:
426                 newerrno = ECONNRESET;
427                 break;
428         case GNUTLS_E_UNEXPECTED_PACKET:
429         case GNUTLS_E_WARNING_ALERT_RECEIVED:
430         case GNUTLS_E_FATAL_ALERT_RECEIVED:
431         case GNUTLS_E_LARGE_PACKET:
432         case GNUTLS_E_ERROR_IN_FINISHED_PACKET:
433         case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
434         case GNUTLS_E_MPI_SCAN_FAILED:
435         case GNUTLS_E_DECRYPTION_FAILED:
436         case GNUTLS_E_DECOMPRESSION_FAILED:
437         case GNUTLS_E_COMPRESSION_FAILED:
438         case GNUTLS_E_BASE64_DECODING_ERROR:
439         case GNUTLS_E_MPI_PRINT_FAILED:
440         case GNUTLS_E_GOT_APPLICATION_DATA:
441         case GNUTLS_E_RECORD_LIMIT_REACHED:
442         case GNUTLS_E_ENCRYPTION_FAILED:
443         case GNUTLS_E_PK_ENCRYPTION_FAILED:
444         case GNUTLS_E_PK_DECRYPTION_FAILED:
445         case GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER:
446         case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
447         case GNUTLS_E_PKCS1_WRONG_PAD:
448         case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
449         case GNUTLS_E_FILE_ERROR:
450         case GNUTLS_E_ASN1_ELEMENT_NOT_FOUND:
451         case GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND:
452         case GNUTLS_E_ASN1_DER_ERROR:
453         case GNUTLS_E_ASN1_VALUE_NOT_FOUND:
454         case GNUTLS_E_ASN1_GENERIC_ERROR:
455         case GNUTLS_E_ASN1_VALUE_NOT_VALID:
456         case GNUTLS_E_ASN1_TAG_ERROR:
457         case GNUTLS_E_ASN1_TAG_IMPLICIT:
458         case GNUTLS_E_ASN1_TYPE_ANY_ERROR:
459         case GNUTLS_E_ASN1_SYNTAX_ERROR:
460         case GNUTLS_E_ASN1_DER_OVERFLOW:
461         case GNUTLS_E_TOO_MANY_EMPTY_PACKETS:
462         case GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS:
463         case GNUTLS_E_SRP_PWD_PARSING_ERROR:
464         case GNUTLS_E_BASE64_ENCODING_ERROR:
465         case GNUTLS_E_OPENPGP_KEYRING_ERROR:
466         case GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR:
467         case GNUTLS_E_OPENPGP_SUBKEY_ERROR:
468         case GNUTLS_E_CRYPTO_ALREADY_REGISTERED:
469         case GNUTLS_E_HANDSHAKE_TOO_LARGE:
470         case GNUTLS_E_BAD_COOKIE:
471         case GNUTLS_E_PARSING_ERROR:
472         case GNUTLS_E_CERTIFICATE_LIST_UNSORTED:
473         case GNUTLS_E_NO_PRIORITIES_WERE_SET:
474 #ifdef GNUTLS_E_PK_GENERATION_ERROR
475         case GNUTLS_E_PK_GENERATION_ERROR:
476 #endif
477 #ifdef GNUTLS_E_SELF_TEST_ERROR
478         case GNUTLS_E_SELF_TEST_ERROR:
479 #endif
480 #ifdef GNUTLS_E_SOCKETS_INIT_ERROR
481         case GNUTLS_E_SOCKETS_INIT_ERROR:
482 #endif
483                 newerrno = EIO;
484                 break;
485         case GNUTLS_E_MEMORY_ERROR:
486         case GNUTLS_E_SHORT_MEMORY_BUFFER:
487                 newerrno = ENOMEM;
488                 break;
489         case GNUTLS_E_AGAIN:
490                 newerrno = EAGAIN;
491                 break;
492         case GNUTLS_E_EXPIRED:
493         case GNUTLS_E_TIMEDOUT:
494                 newerrno = ETIMEDOUT;
495                 break;
496         case GNUTLS_E_DB_ERROR:
497 #ifdef ENODATA
498                 newerrno = ENODATA;
499 #else
500                 newerrno = ENOENT;
501 #endif
502                 break;
503         case GNUTLS_E_SRP_PWD_ERROR:
504         case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
505         case GNUTLS_E_HASH_FAILED:
506         case GNUTLS_E_PK_SIGN_FAILED:
507         case GNUTLS_E_CERTIFICATE_ERROR:
508         case GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION:
509         case GNUTLS_E_KEY_USAGE_VIOLATION:
510         case GNUTLS_E_NO_CERTIFICATE_FOUND:
511         case GNUTLS_E_OPENPGP_UID_REVOKED:
512         case GNUTLS_E_OPENPGP_GETKEY_FAILED:
513         case GNUTLS_E_PK_SIG_VERIFY_FAILED:
514         case GNUTLS_E_ILLEGAL_SRP_USERNAME:
515         case GNUTLS_E_INVALID_PASSWORD:
516         case GNUTLS_E_MAC_VERIFY_FAILED:
517         case GNUTLS_E_IA_VERIFY_FAILED:
518         case GNUTLS_E_UNKNOWN_SRP_USERNAME:
519         case GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR:
520         case GNUTLS_E_USER_ERROR:
521         case GNUTLS_E_AUTH_ERROR:
522                 newerrno = EACCES;
523                 break;
524         case GNUTLS_E_INTERRUPTED:
525                 newerrno = EINTR;
526                 break;
527         case GNUTLS_E_INTERNAL_ERROR:
528         case GNUTLS_E_CONSTRAINT_ERROR:
529         case GNUTLS_E_ILLEGAL_PARAMETER:
530                 newerrno = EINVAL;
531                 break;
532         case GNUTLS_E_SAFE_RENEGOTIATION_FAILED:
533                 newerrno = ECONNREFUSED;
534                 break;
535         case GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY:
536         case GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY:
537 #ifdef GNUTLS_E_LIB_IN_ERROR_STATE
538         case GNUTLS_E_LIB_IN_ERROR_STATE:
539 #endif
540                 newerrno = ENOEXEC;
541                 break;
542         case GNUTLS_E_RANDOM_FAILED:
543                 newerrno = EBADF;
544                 break;
545         case GNUTLS_E_CRYPTODEV_IOCTL_ERROR:
546         case GNUTLS_E_CRYPTODEV_DEVICE_ERROR:
547         case GNUTLS_E_HEARTBEAT_PONG_RECEIVED:
548         case GNUTLS_E_HEARTBEAT_PING_RECEIVED:
549         case GNUTLS_E_PKCS11_ERROR:
550         case GNUTLS_E_PKCS11_LOAD_ERROR:
551         case GNUTLS_E_PKCS11_PIN_ERROR:
552         case GNUTLS_E_PKCS11_SLOT_ERROR:
553         case GNUTLS_E_LOCKING_ERROR:
554         case GNUTLS_E_PKCS11_ATTRIBUTE_ERROR:
555         case GNUTLS_E_PKCS11_DEVICE_ERROR:
556         case GNUTLS_E_PKCS11_DATA_ERROR:
557         case GNUTLS_E_PKCS11_UNSUPPORTED_FEATURE_ERROR:
558         case GNUTLS_E_PKCS11_KEY_ERROR:
559         case GNUTLS_E_PKCS11_PIN_EXPIRED:
560         case GNUTLS_E_PKCS11_PIN_LOCKED:
561         case GNUTLS_E_PKCS11_SESSION_ERROR:
562         case GNUTLS_E_PKCS11_SIGNATURE_ERROR:
563         case GNUTLS_E_PKCS11_TOKEN_ERROR:
564         case GNUTLS_E_PKCS11_USER_ERROR:
565         case GNUTLS_E_CRYPTO_INIT_FAILED:
566         case GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE:
567         case GNUTLS_E_TPM_ERROR:
568         case GNUTLS_E_TPM_KEY_PASSWORD_ERROR:
569         case GNUTLS_E_TPM_SRK_PASSWORD_ERROR:
570         case GNUTLS_E_TPM_SESSION_ERROR:
571         case GNUTLS_E_TPM_KEY_NOT_FOUND:
572         case GNUTLS_E_TPM_UNINITIALIZED:
573         case GNUTLS_E_OCSP_RESPONSE_ERROR:
574         case GNUTLS_E_RANDOM_DEVICE_ERROR:
575 #ifdef EREMOTEIO
576                 newerrno = EREMOTEIO;
577 #else
578                 newerrno = EIO;
579 #endif
580                 break;
581         default:
582                 newerrno = EIO;
583                 break;
584         }
585         errno = newerrno;
586         return;
587 }
588
589 /* Generate Diffie-Hellman parameters - for use with DHE
590  * kx algorithms. TODO: These should be discarded and regenerated
591  * once a day, once a week or once a month. Depending on the
592  * security requirements.
593  */
594 static gtls_error generate_dh_params (void) {
595         unsigned int bits;
596         int gtls_errno = GNUTLS_E_SUCCESS;
597         bits = gnutls_sec_param_to_pk_bits (
598                 GNUTLS_PK_DH,
599                 GNUTLS_SEC_PARAM_LEGACY);
600         //TODO// Acquire DH-params lock
601         E_g2e ("Failed to initialise DH params",
602                 gnutls_dh_params_init (
603                         &dh_params));
604         E_g2e ("Failed to generate DH params",
605                 gnutls_dh_params_generate2 (
606                         dh_params,
607                         bits));
608         //TODO// Release DH-params lock
609         return gtls_errno;
610 }
611
612 /* Load Diffie-Hellman parameters from file - or generate them when load fails.
613  */
614 static gtls_error load_dh_params (void) {
615         gnutls_dh_params_t dhp;
616         gnutls_datum_t pkcs3;
617         char *filename = cfg_tls_dhparamfile ();
618         int gtls_errno = GNUTLS_E_SUCCESS;
619         memset (&pkcs3, 0, sizeof (pkcs3));
620         if (filename) {
621                 E_g2e ("No PKCS #3 PEM file with DH params",
622                         gnutls_load_file (
623                                 filename,
624                                 &pkcs3));
625                 E_gnutls_clear_errno ();
626                 E_g2e ("Failed to initialise DH params",
627                         gnutls_dh_params_init (
628                                 &dhp));
629                 E_g2e ("Failed to import DH params from PKCS #3 PEM",
630                         gnutls_dh_params_import_pkcs3 (
631                                 dhp,
632                                 &pkcs3,
633                                 GNUTLS_X509_FMT_PEM));
634                 E_gnutls_clear_errno ();
635         }
636         if (pkcs3.data != NULL) {
637                 free (pkcs3.data);
638         }
639         if (gtls_errno != GNUTLS_E_SUCCESS) {
640                 //
641                 // File failed to load, so try to generate fresh DH params
642                 int gtls_errno_stack0;
643                 gtls_errno = GNUTLS_E_SUCCESS;
644                 tlog (TLOG_CRYPTO, LOG_DEBUG, "Failed to load DH params from %s; generating fresh parameters", filename);
645                 E_g2e ("Failed to generate DH params",
646                         generate_dh_params ());
647                 gtls_errno_stack0 = gtls_errno;
648                 //TODO// Acquire DH-params lock
649                 E_g2e ("Failed to format DH params as PKCS #3 PEM",
650                         gnutls_dh_params_export2_pkcs3 (
651                                 dh_params,
652                                 GNUTLS_X509_FMT_PEM,
653                                 &pkcs3));
654                 //TODO// Release DH-params lock
655                 if ((gtls_errno == GNUTLS_E_SUCCESS) && (filename != NULL)) {
656                         FILE *pemf;
657                         //
658                         // Best effor file save -- readback will parse
659                         pemf = fopen (filename, "w");
660                         if (pemf != NULL) {
661                                 fwrite (pkcs3.data, 1, pkcs3.size, pemf);
662                                 fclose (pemf);
663                                 tlog (TLOG_FILES, LOG_DEBUG, "Saved DH params to %s (best-effort)", filename);
664                         }
665                         E_gnutls_clear_errno ();
666                 }
667                 gtls_errno = gtls_errno_stack0;
668         } else {
669                 gnutls_dh_params_t old_dh;
670                 //TODO// Acquire DH-params lock
671                 old_dh = dh_params;
672                 dh_params = dhp;
673                 //TODO// Release DH-params lock
674                 if (old_dh) {
675                         gnutls_dh_params_deinit (old_dh);
676                 }
677         }
678         return gtls_errno;
679 }
680
681 /* Remove DH parameters, to be used during program cleanup. */
682 static void remove_dh_params (void) {
683         if (dh_params) {
684                 gnutls_dh_params_deinit (dh_params);
685                 dh_params = NULL;
686         }
687 }
688
689
690 /* A log printing function
691  */
692 void log_gnutls (int level, const char *msg) {
693         tlog (TLOG_TLS, level, "GnuTLS: %s", msg);
694 }
695
696
697 /* Implement the GnuTLS function for token insertion callback.  This function
698  * refers back to the generic callback for token insertion.
699  */
700 int gnutls_token_callback (void *const userdata,
701                                 const char *const label,
702                                 unsigned retry) {
703         if (token_callback (label, retry)) {
704                 return GNUTLS_E_SUCCESS;
705         } else {
706                 return GNUTLS_E_PKCS11_TOKEN_ERROR;
707         }
708 }
709
710
711 /*
712  * Implement the GnuTLS function for PIN callback.  This function calls
713  * the generic PIN callback operation.
714  */
715 int gnutls_pin_callback (void *userdata,
716                                 int attempt,
717                                 const char *token_url,
718                                 const char *token_label,
719                                 unsigned int flags,
720                                 char *pin,
721                                 size_t pin_max) {
722         if (flags & GNUTLS_PIN_SO) {
723                 return GNUTLS_E_USER_ERROR;
724         }
725         if (pin_callback (attempt, token_url, NULL, pin, pin_max)) {
726                 return 0;
727         } else {
728                 return GNUTLS_E_PKCS11_PIN_ERROR;
729         }
730 }
731
732
733 /* Register a PKCS #11 provider with the GnuTLS environment. */
734 void starttls_pkcs11_provider (char *p11path) {
735         unsigned int token_seq = 0;
736         char *p11uri;
737         if (gnutls_pkcs11_add_provider (p11path, NULL) != 0) {
738                 fprintf (stderr, "Failed to register PKCS #11 library %s with GnuTLS\n", p11path);
739                 exit (1);
740         }
741         while (gnutls_pkcs11_token_get_url (token_seq, 0, &p11uri) == 0) {
742 #ifdef DEBUG
743                 fprintf (stderr, "DEBUG: Found token URI %s\n", p11uri);
744 #endif
745                 //TODO// if (gnutls_pkcs11_token_get_info (p11uri, GNUTLS_PKCS11_TOKEN_LABEL-of-SERIAL-of-MANUFACTURER-of-MODEL, output, utput_size) == 0) { ... }
746                 gnutls_free (p11uri);
747                 token_seq++;
748         }
749         //TODO// Select token by name (value)
750         //TODO// if PIN available then set it up
751         //TODO:WHY?// free_p11pin ();
752 }
753
754 static void cleanup_starttls_credentials (void);/* Defined below */
755 static void cleanup_starttls_validation (void); /* Defined below */
756 #ifdef HAVE_TLS_KDH
757 static void cleanup_starttls_kerberos (void);   /* Defined below */
758 static int setup_starttls_kerberos (void);      /* Defined below */
759 #endif
760 static int setup_starttls_credentials (void);   /* Defined below */
761
762 /* The global and static setup function for the starttls functions.
763  */
764 void setup_starttls (void) {
765         const char *curver;
766         int gtls_errno = GNUTLS_E_SUCCESS;
767         char *otfsigcrt, *otfsigkey;
768         //
769         // Setup configuration variables
770         maxpreauth = cfg_tls_maxpreauth ();
771         //
772         // Basic library actions
773         tlog (TLOG_TLS, LOG_DEBUG, "Compiled against GnuTLS version %s", GNUTLS_VERSION);
774         curver = gnutls_check_version (GNUTLS_VERSION);
775         tlog (TLOG_TLS, LOG_DEBUG, "Running against %s GnuTLS version %s", curver? "acceptable": "OLDER", curver? curver: gnutls_check_version (NULL));
776         E_g2e ("GnuTLS global initialisation failed",
777                 gnutls_global_init ());
778         E_gnutls_clear_errno ();
779         E_g2e ("GnuTLS PKCS #11 initialisation failed",
780                 gnutls_pkcs11_init (
781                         GNUTLS_PKCS11_FLAG_MANUAL, NULL));
782         //
783         // Setup logging / debugging
784         if (cfg_log_level () == LOG_DEBUG) {
785                 gnutls_global_set_log_function (log_gnutls);
786                 gnutls_global_set_log_level (9);
787         }
788         //
789         // Setup Kerberos
790 #ifdef HAVE_TLS_KDH
791         E_g2e ("Kerberos initialisation failed",
792                 setup_starttls_kerberos ());
793 #endif
794         //
795         // Setup callbacks for user communication
796         gnutls_pkcs11_set_token_function (gnutls_token_callback, NULL);
797         gnutls_pkcs11_set_pin_function (gnutls_pin_callback, NULL);
798         //
799         // Setup DH parameters
800         E_g2e ("Loading DH params failed",
801                 load_dh_params ());
802         //
803         // Setup shared credentials for all client server processes
804         E_g2e ("Failed to setup GnuTLS callback credentials",
805                 setup_starttls_credentials ());
806         //
807         // Parse the default priority string
808 #ifdef HAVE_TLS_KDH
809         E_g2e ("Failed to setup NORMAL priority cache",
810                 gnutls_priority_init (&priority_normal,
811                         "NONE:"
812                         "%ASYM_CERT_TYPES:"
813                         "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
814                         "+COMP-NULL:"
815                         "+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
816                         "+ANON-ECDH:"
817                         "+ECDHE-KRB:" // +ECDHE-KRB-RSA:+ECDHE-KRB-ECDSA:"
818                         "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:"
819                         "+CTYPE-SRV-KRB:+CTYPE-SRV-X.509:+CTYPE-SRV-OPENPGP:"
820                         "+CTYPE-CLI-KRB:+CTYPE-CLI-X.509:+CTYPE-CLI-OPENPGP:"
821                         "+SRP:+SRP-RSA:+SRP-DSS",
822                         NULL));
823 #else
824         E_g2e ("Failed to setup NORMAL priority cache",
825                 gnutls_priority_init (&priority_normal,
826                         "NONE:"
827                         "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
828                         "+COMP-NULL:+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
829                         "+ANON-ECDH:"
830                         "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:"
831                         "+CTYPE-X.509:+CTYPE-OPENPGP:"
832                         "+SRP:+SRP-RSA:+SRP-DSS",
833                         NULL));
834 #endif
835         //
836         // Try to setup on-the-fly signing key / certificate and gen a certkey
837         otfsigcrt = cfg_tls_onthefly_signcert ();
838         otfsigkey = cfg_tls_onthefly_signkey ();
839 fprintf (stderr, "DEBUG: gtls_errno = %d, otfsigcrt == %s, otfsigkey == %s\n", gtls_errno, otfsigcrt? otfsigcrt: "NULL", otfsigkey? otfsigkey: "NULL");
840         if ((gtls_errno == GNUTLS_E_SUCCESS) && (otfsigcrt != NULL)) {
841                 FILE *crtfile = NULL;
842 fprintf (stderr, "DEBUG: gtls_errno==%d when initialising onthefly_issuercrt\n", gtls_errno);
843                 E_g2e ("Failed to initialise on-the-fly issuer certificate structure",
844                         gnutls_x509_crt_init (&onthefly_issuercrt));
845                 if (strncmp (otfsigcrt, "file:", 5) == 0) {
846                         // Provisionary support for the "file:" prefix
847                         otfsigcrt += 5;
848                 }
849                 crtfile = fopen (otfsigcrt, "r");
850                 if (crtfile == NULL) {
851                         E_g2e ("Failed to open on-the-fly issuer certificate file",
852                                 GNUTLS_E_FILE_ERROR);
853 fprintf (stderr, "DEBUG: gtls_errno==%d after failing to open file for onthefly_issuercrt\n", gtls_errno);
854                 } else {
855                         char crt [5001];
856                         size_t len = fread (crt, 1, sizeof (crt), crtfile);
857                         if (ferror (crtfile)) {
858                                 E_g2e ("Failed to read on-the-fly issuer certificate from file",
859                                         GNUTLS_E_FILE_ERROR);
860                         } else if ((len >= sizeof (crt)) || !feof (crtfile)) {
861                                 E_g2e ("Unexpectedly long on-the-fly issuer certificate file",
862                                         GNUTLS_E_FILE_ERROR);
863                         } else {
864                                 gnutls_datum_t cd = {
865                                         .data = (unsigned char *)(&crt[0]),
866                                         .size = len
867                                 };
868 fprintf (stderr, "DEBUG: gtls_errno==%d before importing onthefly_issuercrt\n", gtls_errno);
869                                 E_g2e ("Failed to import on-the-fly certificate from file",
870                                         gnutls_x509_crt_import (onthefly_issuercrt, &cd, GNUTLS_X509_FMT_DER));
871 fprintf (stderr, "DEBUG: gtls_errno==%d after  importing onthefly_issuercrt\n", gtls_errno);
872                         }
873                         fclose (crtfile);
874                 }
875         }
876         if ((gtls_errno == GNUTLS_E_SUCCESS) && (otfsigkey != NULL)) {
877                 E_g2e ("Failed to initialise on-the-fly issuer private key structure",
878                         gnutls_privkey_init (&onthefly_issuerkey));
879 fprintf (stderr, "DEBUG: before onthefly p11 import, gtlserrno = %d\n", gtls_errno);
880                 E_g2e ("Failed to import pkcs11: URI into on-the-fly issuer private key",
881                         gnutls_privkey_import_pkcs11_url (onthefly_issuerkey, otfsigkey));
882 fprintf (stderr, "DEBUG: after  onthefly p11 import, gtlserrno = %d\n", gtls_errno);
883         }
884 fprintf (stderr, "DEBUG: When it matters, gtls_errno = %d, onthefly_issuercrt %s NULL, onthefly_issuerkey %s NULL\n", gtls_errno, onthefly_issuercrt?"!=":"==", onthefly_issuerkey?"!=":"==");
885         if ((gtls_errno == GNUTLS_E_SUCCESS) && (onthefly_issuercrt != NULL) && (onthefly_issuerkey != NULL)) {
886                 E_g2e ("Failed to initialise on-the-fly certificate session key",
887                         gnutls_x509_privkey_init (&onthefly_subjectkey));
888                 E_g2e ("Failed to generate on-the-fly certificate session key",
889                         gnutls_x509_privkey_generate (onthefly_subjectkey, GNUTLS_PK_RSA, 2048 /*TODO:FIXED*/, 0));
890                 if (gtls_errno == GNUTLS_E_SUCCESS) {
891                         tlog (TLOG_TLS, LOG_INFO, "Setup for on-the-fly signing with the TLS Pool");
892                 } else {
893                         tlog (TLOG_TLS, LOG_ERR, "Failed to setup on-the-fly signing (shall continue without it)");
894                         gnutls_x509_privkey_deinit (onthefly_subjectkey);
895                         onthefly_subjectkey = NULL;
896                 }
897         } else {
898                 gtls_errno = GNUTLS_E_SUCCESS;
899                 E_gnutls_clear_errno ();
900         }
901         if (onthefly_subjectkey == NULL) {
902                 if (onthefly_issuercrt != NULL) {
903                         gnutls_x509_crt_deinit (onthefly_issuercrt);
904                         onthefly_issuercrt = NULL;
905                 }
906                 if (onthefly_issuerkey != NULL) {
907                         gnutls_privkey_deinit (onthefly_issuerkey);
908                         onthefly_issuerkey = NULL;
909                 }
910         }
911         //
912         // Finally, check whether there was any error setting up GnuTLS
913         if (gtls_errno != GNUTLS_E_SUCCESS) {
914                 tlog (TLOG_TLS, LOG_CRIT, "FATAL: GnuTLS setup failed: %s", gnutls_strerror (gtls_errno));
915                 exit (1);
916         }
917         //MOVED// //
918         //MOVED// // Setup the management databases
919         //MOVED// tlog (TLOG_DB, LOG_DEBUG, "Setting up management databases");
920         //MOVED// E_e2e ("Failed to setup management databases",
921         //MOVED//       setup_management ());
922         //MOVED// if (errno != 0) {
923         //MOVED//       tlog (TLOG_DB, LOG_CRIT, "FATAL: Management databases setup failed: %s", strerror (errno));
924         //MOVED//       exit (1);
925         //MOVED// }
926 }
927
928 /* Cleanup the structures and resources that were setup for handling TLS.
929  */
930 void cleanup_starttls (void) {
931         //MOVED// cleanup_management ();
932         if (onthefly_subjectkey != NULL) {
933                 gnutls_x509_privkey_deinit (onthefly_subjectkey);
934                 onthefly_subjectkey = NULL;
935         }
936         if (onthefly_issuercrt != NULL) {
937                 gnutls_x509_crt_deinit (onthefly_issuercrt);
938                 onthefly_issuercrt = NULL;
939         }
940         if (onthefly_issuerkey != NULL) {
941                 gnutls_privkey_deinit (onthefly_issuerkey);
942                 onthefly_issuerkey = NULL;
943         }
944
945         cleanup_starttls_credentials ();
946 #ifdef HAVE_TLS_KDH
947         cleanup_starttls_kerberos ();
948 #endif
949         remove_dh_params ();
950         gnutls_pkcs11_set_pin_function (NULL, NULL);
951         gnutls_pkcs11_set_token_function (NULL, NULL);
952         gnutls_pkcs11_deinit ();
953         gnutls_priority_deinit (priority_normal);
954         gnutls_global_deinit ();
955 }
956
957
958 /*
959  * The copycat function is a bidirectional transport between the given
960  * remote and local sockets, but it will encrypt traffic from local to
961  * remote, and decrypt traffic from remote to local.  It will do this
962  * until one of the end points is shut down, at which time it will
963  * return and assume the context will close down both pre-existing
964  * sockets.
965  *
966  * This copycat actually has a few sharp claws to watch for -- shutdown
967  * of sockets may drop the last bit of information sent.  First, the
968  * signal POLLHUP is best ignored because it travels asynchronously.
969  * Second, reading 0 is a good indicator of end-of-file and may be
970  * followed by an shutdown of reading from that stream.  But, more
971  * importantly, the other side must have this information forwarded
972  * so it can shutdown.  This means that a shutdown for writing to that
973  * stream is to be sent.  Even when *both* sides have agreed to not send
974  * anything, they may still not have received all they were offered for
975  * reading, so we should SO_LINGER on the sockets so they can acknowledge,
976  * and after a timeout we can establish that shutdown failed and log and
977  * return an error for it.
978  * Will you believe that I had looked up if close() would suffice?  The man
979  * page clearly stated yes.  However, these articles offer much more detail:
980  * http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable
981  * http://www.greenend.org.uk/rjk/tech/poll.html
982  *
983  * This function blocks during its call to poll(), in a state that can easily
984  * be restarted.  This is when thread cancellation is temporarily enabled.
985  * Other threads may use this to cancel the thread and have it joined with that
986  * thread which will subsume its tasks and restart the handshake.  We might
987  * later make this more advanced, by using a cancel stack push/pull mechanisms
988  * to ensure that recv() always results in send() in spite of cancellation.
989  *
990  * The return value of copycat is a GNUTLS_E_ code, usually GNUTLS_E_SUCCESS.
991  * For the moment, only one special value is of concern, namely
992  * GNUTLS_E_REHANDSHAKE which client or server side may receive when an
993  * attempt is made to renegotiate the security of the connection.
994  */
995 static int copycat (int local, int remote, gnutls_session_t wrapped, pool_handle_t client) {
996         char buf [1024];
997         struct pollfd inout [3];
998         ssize_t sz;
999         struct linger linger = { 1, 10 };
1000         int have_client;
1001         int retval = GNUTLS_E_SUCCESS;
1002
1003 client = INVALID_POOL_HANDLE;
1004         inout [0].fd = local;
1005         inout [1].fd = remote;
1006 #ifdef WINDOWS_PORT
1007         have_client = 0;
1008 #else
1009         inout [2].fd = client;
1010         have_client = inout [2].fd != INVALID_POOL_HANDLE;
1011 #endif
1012         if (!have_client) {
1013                 inout [2].revents = 0;  // Will not be written by poll
1014                 //FORK!=DETACH// inout [2].fd = ctlkey_signalling_fd;
1015         }
1016         inout [0].events = POLLIN;
1017         inout [1].events = POLLIN;
1018         inout [2].events = 0;   // error events only
1019         tlog (TLOG_COPYCAT, LOG_DEBUG, "Starting copycat cycle for local=%d, remote=%d, control=%d", local, remote, client);
1020         while (((inout [0].events | inout [1].events) & POLLIN) != 0) {
1021                 int polled;
1022                 assert (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE,  NULL) == 0);
1023                 pthread_testcancel ();  // Efficiency & Certainty
1024                 polled = poll (inout, have_client? 3: 2, -1);
1025                 assert (pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL) == 0);
1026                 if (polled == -1) {
1027                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat polling returned an error");
1028                         break;  // Polling sees an error
1029                 }
1030                 if (inout [0].revents & POLLIN) {
1031                         // Read local and encrypt to remote
1032                         sz = recv (local, buf, sizeof (buf), RECV_FLAGS);
1033                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat received %d local bytes (or error<0) from %d", (int) sz, local);
1034                         if (sz == -1) {
1035                                 tlog (TLOG_COPYCAT, LOG_ERR, "Error while receiving: %s", strerror (errno));
1036                                 break;  // stream error
1037                         } else if (sz == 0) {
1038                                 inout [0].events &= ~POLLIN;
1039                                 shutdown (local, SHUT_RD);
1040 #ifdef WINDOWS_PORT
1041                                 setsockopt (remote, SOL_SOCKET, SO_LINGER, (const char *) &linger, sizeof (linger));
1042 #else /* WINDOWS_PORT */
1043                                 setsockopt (remote, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
1044 #endif /* WINDOWS_PORT */
1045                                 gnutls_bye (wrapped, GNUTLS_SHUT_WR);
1046                         } else if (gnutls_record_send (wrapped, buf, sz) != sz) {
1047                                 tlog (TLOG_COPYCAT, LOG_ERR, "gnutls_record_send() failed to pass on the requested bytes");
1048                                 break;  // communication error
1049                         } else {
1050                                 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat sent %d bytes to remote %d", (int) sz, remote);
1051                         }
1052                 }
1053                 if (inout [1].revents & POLLIN) {
1054                         // Read remote and decrypt to local
1055                         sz = gnutls_record_recv (wrapped, buf, sizeof (buf));
1056                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat received %d remote bytes from %d (or error if <0)", (int) sz, remote);
1057                         if (sz < 0) {
1058                                 //TODO// Process GNUTLS_E_REHANDSHAKE
1059                                 if (sz == GNUTLS_E_REHANDSHAKE) {
1060                                         tlog (TLOG_TLS, LOG_INFO, "Received renegotiation request over TLS handle %d", remote);
1061                                         retval = GNUTLS_E_REHANDSHAKE;
1062                                         break;
1063                                 } else if (gnutls_error_is_fatal (sz)) {
1064                                         tlog (TLOG_TLS, LOG_ERR, "GnuTLS fatal error: %s", gnutls_strerror (sz));
1065                                         break;  // stream error
1066                                 } else {
1067                                         tlog (TLOG_TLS, LOG_INFO, "GnuTLS recoverable error: %s", gnutls_strerror (sz));
1068                                 }
1069                         } else if (sz == 0) {
1070                                 inout [1].events &= ~POLLIN;
1071                                 shutdown (remote, SHUT_RD);
1072 #ifdef WINDOWS_PORT
1073                                 setsockopt (local, SOL_SOCKET, SO_LINGER, (const char *) &linger, sizeof (linger));
1074 #else /* WINDOWS_PORT */
1075                                 setsockopt (local, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
1076 #endif /* WINDOWS_PORT */
1077                                 shutdown (local, SHUT_WR);
1078                         } else if (send (local, buf, sz, RECV_FLAGS) != sz) {
1079                                 break;  // communication error
1080                         } else {
1081                                 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat sent %d bytes to local %d", (int) sz, local);
1082                         }
1083                 }
1084                 inout [0].revents &= ~(POLLIN | POLLHUP); // Thy copying cat?
1085                 inout [1].revents &= ~(POLLIN | POLLHUP); // Retract thee claws!
1086                 if ((inout [0].revents | inout [1].revents) & ~POLLIN) {
1087                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat data connection polling returned a special condition");
1088                         break;  // Apparently, one of POLLERR, POLLHUP, POLLNVAL
1089                 }
1090 #ifndef WINDOWS_PORT
1091                 if (inout [2].revents & ~POLLIN) {
1092                         if (have_client) {
1093                                 // This case is currently not ever triggered
1094                                 tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat control connection polling returned a special condition");
1095                                 break;  // Apparently, one of POLLERR, POLLHUP, POLLNVAL
1096                         } else {
1097                                 inout [2].fd = client;
1098                                 have_client = inout [2].fd >= 0;
1099                                 if (have_client) {
1100                                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat signalling_fd polling raised a signal to set control fd to %d", inout [2].fd);
1101                                 } else {
1102                                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Copycat signalling_fd polling raised a signal that could be ignored");
1103                                 }
1104                                 continue;
1105                         }
1106                 }
1107 #endif /* !WINDOWS_PORT */
1108         }
1109         tlog (TLOG_COPYCAT, LOG_DEBUG, "Ending copycat cycle for local=%d, remote=%d", local, remote);
1110         return retval;
1111 }
1112
1113
1114 /* The callback function that retrieves certification information from either
1115  * the client or the server in the course of the handshake procedure.
1116  */
1117 gtls_error clisrv_cert_retrieve (gnutls_session_t session,
1118                                 const gnutls_datum_t* req_ca_dn,
1119                                 int nreqs,
1120                                 const gnutls_pk_algorithm_t* pk_algos,
1121                                 int pk_algos_length,
1122                                 gnutls_pcert_st** pcert,
1123                                 unsigned int *pcert_length,
1124                                 gnutls_privkey_t *pkey) {
1125         gnutls_certificate_type_t certtp;
1126         gnutls_pcert_st *pc = NULL;
1127         struct command *cmd;
1128         char *lid, *rid;
1129         gnutls_datum_t privdatum = { NULL, 0 };
1130         gnutls_datum_t certdatum = { NULL, 0 };
1131         gnutls_openpgp_crt_t pgpcert = NULL;
1132         gnutls_openpgp_privkey_t pgppriv = NULL;
1133         int gtls_errno = GNUTLS_E_SUCCESS;
1134         int lidtype;
1135         int lidrole = 0;
1136         char *rolestr;
1137         char sni [sizeof (cmd->cmd.pio_data.pioc_starttls.localid)];
1138         size_t snilen = sizeof (sni);
1139         unsigned int snitype;
1140         int ok;
1141         uint32_t flags;
1142         char *p11priv;
1143         uint8_t *pubdata;
1144         int pubdatalen;
1145         gtls_error fetch_local_credentials (struct command *cmd);
1146         gnutls_pcert_st *load_certificate_chain (uint32_t flags, unsigned int *chainlen, gnutls_datum_t *certdatum);
1147
1148         //
1149         // Setup a number of common references and structures
1150         errno = 0;
1151         *pcert = NULL;
1152         cmd = (struct command *) gnutls_session_get_ptr (session);
1153         if (cmd == NULL) {
1154                 E_g2e ("No data pointer with session",
1155                         GNUTLS_E_INVALID_SESSION);
1156                 return gtls_errno;
1157         }
1158         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
1159                 lidrole = LID_ROLE_CLIENT;
1160                 rolestr = "client";
1161         } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
1162                 lidrole = LID_ROLE_SERVER;
1163                 rolestr = "server";
1164         } else {
1165                 E_g2e ("TLS Pool command supports neither local client nor local server role",
1166                         GNUTLS_E_INVALID_SESSION);
1167                 return gtls_errno;
1168         }
1169         lid = cmd->cmd.pio_data.pioc_starttls.localid;
1170         rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
1171
1172         //
1173         // On a server, lookup the server name and match it against lid.
1174         // TODO: For now assume a single server name in SNI (as that is normal).
1175         if (lidrole == LID_ROLE_SERVER) {
1176                 if (gnutls_server_name_get (session, sni, &snilen, &snitype, 0) || (snitype != GNUTLS_NAME_DNS)) {
1177                         E_g2e ("Requested SNI error or not a DNS name",
1178                                 GNUTLS_E_NO_CERTIFICATE_FOUND);
1179                         return gtls_errno;
1180                 }
1181                 if (*lid != '\0') {
1182                         int atidx;
1183                         for (atidx=128; atidx > 0; atidx--) {
1184                                 if (lid [atidx-1] == '@') {
1185                                         break;
1186                                 }
1187                         }
1188                         if (strncmp (sni, lid + atidx, sizeof (sni)-atidx) != 0) {
1189                                 tlog (TLOG_TLS, LOG_ERR, "SNI %s does not match preset local identity %s", sni, lid);
1190                                 E_g2e ("Requested SNI does not match local identity",
1191                                         GNUTLS_E_NO_CERTIFICATE_FOUND);
1192                                 return gtls_errno;
1193                         }
1194                 } else {
1195                         // TODO: Should ask for permission before accepting SNI
1196                         memcpy (lid, sni, sizeof (sni));
1197                 }
1198         }
1199
1200         //
1201         // Setup the lidtype parameter for responding
1202 #ifdef HAVE_TLS_KDH
1203         certtp = gnutls_certificate_type_get_ours (session);
1204 #else
1205         certtp = gnutls_certificate_type_get (session);
1206 #endif
1207         if (certtp == GNUTLS_CRT_OPENPGP) {
1208                 tlog (TLOG_TLS, LOG_INFO, "Serving OpenPGP certificate request as a %s", rolestr);
1209                 lidtype = LID_TYPE_PGP;
1210         } else if (certtp == GNUTLS_CRT_X509) {
1211                 tlog (TLOG_TLS, LOG_INFO, "Serving X.509 certificate request as a %s", rolestr);
1212                 lidtype = LID_TYPE_X509;
1213 #ifdef HAVE_TLS_KDH
1214         } else if (certtp == GNUTLS_CRT_KRB) {
1215                 tlog (TLOG_TLS, LOG_INFO, "Serving Kerberos Ticket request as a %s", rolestr);
1216                 lidtype = LID_TYPE_KRB5;
1217 #endif
1218         } else {
1219                 // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
1220                 tlog (TLOG_TLS, LOG_ERR, "Funny sort of certificate %d retrieval attempted as a %s", certtp, rolestr);
1221                 E_g2e ("Requested certtype is neither X.509 nor OpenPGP",
1222                         GNUTLS_E_CERTIFICATE_ERROR);
1223                 return gtls_errno;
1224         }
1225
1226         //
1227         // Find the prefetched local identity to use towards this remote
1228         // Send a callback to the user if none is available and accessible
1229         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALID_CHECK) {
1230                 uint32_t oldcmd = cmd->cmd.pio_cmd;
1231                 struct command *resp;
1232                 cmd->cmd.pio_cmd = PIOC_STARTTLS_LOCALID_V2;
1233                 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Calling send_callback_and_await_response with PIOC_STARTTLS_LOCALID_V2");
1234                 resp = send_callback_and_await_response (cmd, 0);
1235                 assert (resp != NULL);  // No timeout, should be non-NULL
1236                 if (resp->cmd.pio_cmd != PIOC_STARTTLS_LOCALID_V2) {
1237                         tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has unexpected command code");
1238                         cmd->cmd.pio_cmd = oldcmd;
1239                         return GNUTLS_E_CERTIFICATE_ERROR;
1240                 }
1241                 assert (resp == cmd);  // No ERROR, so should be the same
1242                 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Processing callback response that sets plainfd:=%d and lid:=\"%s\" for rid==\"%s\"", cmd->passfd, lid, rid);
1243                 cmd->cmd.pio_cmd = oldcmd;
1244                 //
1245                 // Check that new rid is a generalisation of original rid
1246                 // Note: This is only of interest for client operation
1247                 if (lidrole == LID_ROLE_CLIENT) {
1248                         selector_t newrid = donai_from_stable_string (rid, strlen (rid));
1249                         donai_t oldrid = donai_from_stable_string (cmd->orig_starttls->remoteid, strlen (cmd->orig_starttls->remoteid));
1250                         if (!donai_matches_selector (&oldrid, &newrid)) {
1251                                 return GNUTLS_E_NO_CERTIFICATE_FOUND;
1252                         }
1253                 }
1254                 //
1255                 // Now reiterate to lookup lid credentials in db_localid
1256                 E_g2e ("Missing local credentials",
1257                         fetch_local_credentials (cmd));
1258         }
1259         if (cmd->lids [lidtype - LID_TYPE_MIN].data == NULL) {
1260 fprintf (stderr, "DEBUG: Missing certificate for local ID %s and remote ID %s\n", lid, rid);
1261                 E_g2e ("Missing certificate for local ID",
1262                         GNUTLS_E_NO_CERTIFICATE_FOUND);
1263                 return gtls_errno;
1264         }
1265
1266         //
1267         // Split the credential into its various aspects
1268         ok = dbcred_interpret (
1269                 &cmd->lids [lidtype - LID_TYPE_MIN],
1270                 &flags,
1271                 &p11priv,
1272                 &certdatum.data,
1273                 &certdatum.size);
1274         tlog (TLOG_DB, LOG_DEBUG, "BDB entry has flags=0x%08x, p11priv=\"%s\", cert.size=%d", flags, p11priv, certdatum.size);
1275         //TODO// ok = ok && verify_cert_... (...); -- keyidlookup
1276         if (!ok) {
1277                 gtls_errno = GNUTLS_E_CERTIFICATE_ERROR;
1278         }
1279
1280         //
1281         // Allocate response structures
1282         *pcert_length = 0;
1283         *pcert = load_certificate_chain (flags, pcert_length, &certdatum);
1284         if (*pcert == NULL) {
1285                 E_g2e ("Failed to load certificate chain",
1286                         GNUTLS_E_CERTIFICATE_ERROR);
1287                 return gtls_errno;
1288         }
1289         cmd->session_certificate = (intptr_t) (void *) *pcert;  //TODO// Used for session cleanup
1290
1291         //
1292         // Setup private key
1293         E_g2e ("Failed to initialise private key",
1294                 gnutls_privkey_init (
1295                         pkey));
1296         if ((onthefly_subjectkey != NULL) && (strcmp (p11priv, onthefly_p11uri) == 0)) {
1297                 // Setup the on-the-fly certification key as private key
1298                 E_g2e ("Failed to import on-the-fly subject private key",
1299                         gnutls_privkey_import_x509 (
1300                                 *pkey,
1301                                 onthefly_subjectkey,
1302                                 GNUTLS_PRIVKEY_IMPORT_COPY));
1303 #ifdef HAVE_TLS_KDH
1304         } else if (lidtype == LID_TYPE_KRB5) {
1305                 // Fake a private key for Kerberos (we sign it out here, not GnuTLS)
1306                 E_g2e ("Failed to generate a private-key placeholder for Kerberos",
1307                         gnutls_privkey_generate_krb (
1308                                 *pkey,
1309                                 0));
1310 #endif
1311         } else {
1312                 // Import the PKCS #11 key as the private key for use by GnuTLS
1313                 if (gtls_errno == GNUTLS_E_SUCCESS) {
1314                         cmd->session_privatekey = (intptr_t) (void *) *pkey;    //TODO// Used for session cleanup
1315                 }
1316                 E_g2e ("Failed to import PKCS #11 private key URI",
1317                         gnutls_privkey_import_pkcs11_url (
1318                                 *pkey,
1319                                 p11priv));
1320         }
1321         E_gnutls_clear_errno ();
1322
1323 //TODO// Moved out (start)
1324
1325         //
1326         // Setup public key certificate
1327         switch (lidtype) {
1328         case LID_TYPE_X509:
1329                 E_g2e ("MOVED: Failed to import X.509 certificate into chain",
1330                         gnutls_pcert_import_x509_raw (
1331                                 *pcert,
1332                                 &certdatum,
1333                                 GNUTLS_X509_FMT_DER,
1334                                 0));
1335                 break;
1336         case LID_TYPE_PGP:
1337                 E_g2e ("MOVED: Failed to import OpenPGP public key",
1338                         gnutls_pcert_import_openpgp_raw (
1339                                 *pcert,
1340                                 &certdatum,
1341                                 GNUTLS_OPENPGP_FMT_RAW,
1342                                 NULL,   /* use master key */
1343                                 0));
1344                 break;
1345 #ifdef HAVE_TLS_KDH
1346         case LID_TYPE_KRB5:
1347                 if (lidrole == LID_ROLE_CLIENT) {
1348                         //
1349                         // KDH-Only or KDH-Enhanced; fetch ticket for localid
1350                         // and a TGT based on it for service/remoteid@REALM
1351                         //
1352                         // First, try to obtain a TGT and key, in various ways
1353                         krb5_keyblock key;
1354                         krb5_creds *tgt = NULL;
1355                         krb5_creds *ticket = NULL;
1356                         krb5_ccache cc = NULL;
1357                         int status = 0;
1358                         memset (&key,    0, sizeof (key   ));
1359                         status = have_key_tgt_cc (
1360                                 cmd, krbctx_cli,
1361                                 1, 0, 0,
1362                                 p11priv,
1363                                 krb_kt_cli,
1364                                 &key, &tgt, &cc);
1365                         if (status >= 1) {
1366                                 // We never use this key ourselves
1367                                 krb5_free_keyblock_contents (krbctx_cli, &key);
1368                         }
1369                         if (status < 2) {
1370                                 // Stop processing when no tgt was found
1371                                 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1372                                 break;
1373                         }
1374                         //
1375                         // Store client identity in session object
1376                         if (0 != krb5_copy_principal (
1377                                         krbctx_cli,
1378                                         tgt->client,
1379                                         &cmd->krbid_cli)) {
1380                                 krb5_free_creds (krbctx_cli, tgt);
1381                                 tgt = NULL;
1382                                 if (cc != NULL) {
1383                                         krb5_cc_close (krbctx_cli, cc);
1384                                         cc = NULL;
1385                                 }
1386                                 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1387                                 break;
1388                         }
1389                         //
1390                         // Now find a service ticket to talk to, and its key
1391                         //TODO// Pass credcache instead?
1392                         status = have_service_ticket (
1393                                 cmd, krbctx_cli,
1394                                 cc,
1395                                 cmd->krbid_cli,
1396                                 &ticket);
1397                         if (cc != NULL) {
1398                                 // We don't need cc anymore below
1399                                 krb5_cc_close (krbctx_cli, cc);
1400                         }
1401                         if (status < 1) {
1402                                 // Stop processing when no ticket was found
1403                                 krb5_free_creds (krbctx_cli, tgt);
1404                                 tgt = NULL;
1405                                 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1406                                 break;
1407                         }
1408                         //
1409                         // Only for KDH-Only mode can the client rely on a
1410                         // server principal taken from the ticket;
1411                         // So only store krbid_srv for KDH-Only mode.
1412                         if ((gnutls_certificate_type_get_peers (cmd->session)
1413                                                 == GNUTLS_CRT_KRB) &&
1414                                         (0 != krb5_copy_principal (
1415                                                 krbctx_cli,
1416                                                 tgt->server,
1417                                                 &cmd->krbid_srv))) {
1418                                 krb5_free_creds (krbctx_cli, ticket);
1419                                 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1420                                 break;
1421                         }
1422                         krb5_free_creds (krbctx_cli, tgt);
1423                         tgt = NULL;
1424                         if (0 != krb5_copy_keyblock_contents (
1425                                         krbctx_cli,
1426                                         &ticket->keyblock,
1427                                         &cmd->krb_key)) {
1428                                 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1429                                 // continue, with E_g2e() skipping import
1430                         }
1431                         certdatum.data = ticket->ticket.data;
1432                         certdatum.size = ticket->ticket.length;
1433                         E_g2e ("MOVED: Failed to import Kerberos ticket",
1434                                 gnutls_pcert_import_krb_raw (
1435                                         *pcert,
1436                                         &certdatum,
1437                                         0));
1438                         krb5_free_creds (krbctx_cli, ticket);
1439                 } else {
1440                         //
1441                         // For KDH-Only, the server supplies one of:
1442                         //  - a TGT for user-to-user mode (for p2p exchanges)
1443                         //  - an DER NULL to waive u2u mode
1444                         //TODO// E_g2e ("MOVED: Failed to import Kerberos ticket",
1445                         //TODO//        gnutls_pcert_import_krb_raw (
1446                         //TODO//                *pcert,
1447                         //TODO//                &certdatum,     //TODO:WHATSFOUND//
1448                         //TODO//                0));
1449                         int u2u = 0;
1450                         int status = 0;
1451                         krb5_creds *tgt = NULL;
1452                         //
1453                         // Determine whether we want to run in user-to-user mode
1454                         // for which we should supply a TGT to the TLS client
1455                         u2u = u2u || ((PIOF_STARTTLS_BOTHROLES_PEER & ~cmd->cmd.pio_data.pioc_starttls.flags) == 0);
1456                         u2u = u2u || (strchr (rid, '@') != NULL);
1457                         // u2u = u2u || "shaken hands on TLS symmetry extension"
1458                         u2u = u2u && got_cc_srv;  // We may simply not be able!
1459                         //
1460                         // When not in user-to-user mode, deliver DER NULL
1461                         if (!u2u) {
1462                                 static unsigned char der_null_data[] = "\x05\x00";
1463                                 certdatum.data = der_null_data;
1464                                 certdatum.size = 2;
1465                                 E_g2e ("Failed to withhold Kerberos server ticket",
1466                                         gnutls_pcert_import_krb_raw (
1467                                                 *pcert,
1468                                                 &certdatum,
1469                                                 0));
1470                                 break;
1471                         }
1472                         //
1473                         // Continue specifically for user-to-user mode.
1474                         //TODO// Setup server principal identity
1475                         //
1476                         // Fetch the service's key
1477                         status = have_key_tgt_cc (
1478                                 cmd, krbctx_srv,
1479                                 1, 0, 0,        // Hmm... later we know kvno/etype
1480                                 p11priv,
1481                                 krb_kt_srv,
1482                                 &cmd->krb_key, &tgt, NULL);
1483                         if (status == 1) {
1484                                 // There's no use in having just the key
1485                                 krb5_free_keyblock_contents (krbctx_srv, &cmd->krb_key);
1486                                 memset (&cmd->krb_key, 0, sizeof (cmd->krb_key));
1487                         }
1488                         if (status < 2) {
1489                                 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1490                         } else if (0 != krb5_copy_principal (
1491                                                 krbctx_srv,
1492                                                 tgt->server,
1493                                                 &cmd->krbid_srv)) {
1494                                 gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
1495                         }
1496                         certdatum.data = tgt->ticket.data;
1497                         certdatum.size = tgt->ticket.length;
1498                         E_g2e ("Failed to withhold Kerberos server ticket",
1499                                 gnutls_pcert_import_krb_raw (
1500                                         *pcert,
1501                                         &certdatum,
1502                                         0));
1503                         krb5_free_creds (krbctx_cli, tgt);
1504                         tgt = NULL;
1505                 }
1506                 break;
1507 #endif
1508         default:
1509                 /* Should not happen */
1510                 break;
1511         }
1512
1513 //TODO// Moved out (end)
1514
1515 #ifdef ANCIENT_CODE_WHEN_DBERRNO_RAN_IN_PARALLEL
1516         //
1517         // Lap up any overseen POSIX error codes in errno
1518         if (errno) {
1519                 tlog (TLOG_TLS, LOG_DEBUG, "Failing TLS on errno=%d / %s", errno, strerror (errno));
1520                 cmd->session_errno = errno;
1521                 gtls_errno = GNUTLS_E_NO_CIPHER_SUITES; /* Vaguely matching */
1522         }
1523 #endif
1524
1525         //
1526         // Return the overral error code, hopefully GNUTLS_E_SUCCESS
1527         tlog (TLOG_TLS, LOG_DEBUG, "Returning %d / %s from clisrv_cert_retrieve()", gtls_errno, gnutls_strerror (gtls_errno));
1528 fprintf (stderr, "DEBUG: clisrv_cert_retrieve() sets *pcert to 0x%lx (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);
1529         return gtls_errno;
1530 }
1531
1532 /* Load a single certificate in the given gnutls_pcert_st from the given
1533  * gnutls_datum_t.  Use the lidtype to determine how to do this.
1534  */
1535 gtls_error load_certificate (int lidtype, gnutls_pcert_st *pcert, gnutls_datum_t *certdatum) {
1536         int gtls_errno = GNUTLS_E_SUCCESS;
1537         //
1538         // Setup public key certificate
1539         switch (lidtype) {
1540         case LID_TYPE_X509:
1541 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]);
1542                 E_g2e ("Failed to import X.509 certificate into chain",
1543                         gnutls_pcert_import_x509_raw (
1544                                 pcert,
1545                                 certdatum,
1546                                 GNUTLS_X509_FMT_DER,
1547                                 0));
1548                 break;
1549         case LID_TYPE_PGP:
1550                 E_g2e ("Failed to import OpenPGP certificate",
1551                         gnutls_pcert_import_openpgp_raw (
1552                                 pcert,
1553                                 certdatum,
1554                                 GNUTLS_OPENPGP_FMT_RAW,
1555                                 NULL,   /* use master key */
1556                                 0));
1557                 break;
1558         case LID_TYPE_KRB5:
1559                 /* Binary information is currently moot, so do not load it */
1560                 break;
1561         default:
1562                 /* Should not happen */
1563                 break;
1564         }
1565         return gtls_errno;
1566 }
1567
1568
1569 /* Load a certificate chain.  This returns a value for a retrieval function's
1570  * pcert, and also modifies the chainlen.  The latter starts at 0, and is
1571  * incremented in a nested procedure that unrolls until all certificates are
1572  * loaded.
1573  */
1574 gnutls_pcert_st *load_certificate_chain (uint32_t flags, unsigned int *chainlen, gnutls_datum_t *certdatum) {
1575         gnutls_pcert_st *chain;
1576         unsigned int mypos = *chainlen;
1577         int gtls_errno = GNUTLS_E_SUCCESS;
1578
1579         //
1580         // Quick and easy: No chaining required, just add the literal data.
1581         // Note however, this may be the end of a chain, so allocate all
1582         // structures and load the single one at the end.
1583         if ((flags & (LID_CHAINED | LID_NEEDS_CHAIN)) == 0) {
1584                 (*chainlen)++;
1585                 chain = (gnutls_pcert_st *) calloc (*chainlen, sizeof (gnutls_pcert_st));
1586                 if (chain != NULL) {
1587                         memset (chain,
1588                                 0,
1589                                 (*chainlen) * sizeof (gnutls_pcert_st));
1590                 } else {
1591                         gtls_errno = GNUTLS_E_MEMORY_ERROR;
1592                 }
1593                 E_g2e ("Failed to load certificate into chain",
1594                         load_certificate (
1595                                 flags & LID_TYPE_MASK,
1596                                 &chain [mypos],
1597                                 certdatum));
1598                 if (gtls_errno != GNUTLS_E_SUCCESS) {
1599                         if (chain) {
1600                                 free (chain);
1601                         }
1602                         *chainlen = 0;
1603                         chain = NULL;
1604                 }
1605                 return chain;
1606         }
1607
1608         //
1609         // First extended case.  Chain certs in response to LID_CHAINED.
1610         // Recursive calls are depth-first, so we only add our first cert
1611         // after a recursive call succeeds.  Any LID_NEEDS_CHAIN work is
1612         // added after LID_CHAINED, so is higher up in the hierarchy, but
1613         // it is loaded as part of the recursion.  To support that, a
1614         // recursive call with certdatum.size==0 is possible when the
1615         // LID_NEEDS_CHAIN flag is set, and this section then skips.
1616         // Note that this code is also used to load the certificate chain
1617         // provided by LID_NEEDS_CHAIN, but by then the flag in a recursive
1618         // call is replaced with LID_CHAINED and no more LID_NEEDS_CHAIN.
1619         if (((flags & LID_CHAINED) != 0) && (certdatum->size > 0)) {
1620                 long certlen;
1621                 int lenlen;
1622                 gnutls_datum_t nextdatum;
1623                 long nextlen;
1624                 // Note: Accept BER because the outside SEQUENCE is not signed
1625                 certlen = asn1_get_length_ber (
1626                         (certdatum->data) + 1,
1627                         certdatum->size,
1628                         &lenlen);
1629                 certlen += 1 + lenlen;
1630                 tlog (TLOG_CERT, LOG_DEBUG, "Found LID_CHAINED certificate size %d", certlen);
1631                 if (certlen > certdatum->size) {
1632                         tlog (TLOG_CERT, LOG_ERR, "Refusing LID_CHAINED certificate beyond data size %d", certdatum->size);
1633                         *chainlen = 0;
1634                         return NULL;
1635                 } else if (certlen <= 0) {
1636                         tlog (TLOG_CERT, LOG_ERR, "Refusing LID_CHAINED certificate of too-modest data size %d", certlen);
1637                         *chainlen = 0;
1638                         return NULL;
1639                 }
1640                 nextdatum.data = (certdatum->data) + certlen;
1641                 nextdatum.size =  certdatum->size  - certlen;
1642                 certdatum->size = certlen;
1643                 nextlen = asn1_get_length_ber (
1644                         nextdatum.data + 1,
1645                         nextdatum.size,
1646                         &lenlen);
1647                 nextlen += 1 + lenlen;
1648                 if (nextlen == nextdatum.size) {
1649                         // The last cert is loaded thinking it is not CHAINED,
1650                         // but NEEDS_CHAIN can still be present for expansion.
1651                         flags &= ~LID_CHAINED;
1652                 }
1653                 (*chainlen)++;
1654                 chain = load_certificate_chain (flags, chainlen, &nextdatum);
1655                 if (chain != NULL) {
1656                         E_g2e ("Failed to add chained certificate",
1657                                 load_certificate (
1658                                         flags & LID_TYPE_MASK,
1659                                         &chain [mypos],
1660                                         certdatum));
1661                         if (gtls_errno != GNUTLS_E_SUCCESS) {
1662                                 free (chain);
1663                                 chain = NULL;
1664                                 *chainlen = 0;
1665                         }
1666                 }
1667                 return chain;
1668         }
1669
1670         //
1671         // Second extended case.  Chain certs in response to LID_NEEDS_CHAIN.
1672         // These are the highest-up in the hierarchy, above any LID_CHAINED
1673         // certificates.  The procedure for adding them is looking them up
1674         // in a central database by their authority key identifier.  What is
1675         // found is assumed to be a chain, and will be unrolled by replacing
1676         // the LID_NEEDS_CHAIN flag with LID_CHAINED and calling recursively.
1677         if (((flags & LID_NEEDS_CHAIN) != 0) && (certdatum->size == 0)) {
1678                 //TODO//CODE// lookup new certdatum
1679                 flags &= ~LID_NEEDS_CHAIN;
1680                 flags |=  LID_CHAINED;
1681                 //TODO//CODE// recursive call
1682                 //TODO//CODE// no structures to fill here
1683                 //TODO//CODE// cleanup new certdatum
1684         }
1685
1686         //
1687         // Final judgement.  Nothing worked.  Return failure.
1688         *chainlen = 0;
1689         return NULL;
1690 }
1691
1692
1693
1694 /********** KERBEROS SUPPORT FUNCTIONS FOR TLS-KDH **********/
1695
1696
1697
1698 /* Prepare the Kerberos resources for use by clients and/or servers.
1699  */
1700 #ifdef HAVE_TLS_KDH
1701 static int setup_starttls_kerberos (void) {
1702         int k5err = 0;
1703         char *cfg;
1704         int retval = GNUTLS_E_SUCCESS;
1705         krb5_ccache krb_cc_tmp;
1706         const char *cctype_cli = NULL;
1707         const char *cctype_srv = NULL;
1708         //
1709         // Initialise
1710         krbctx_cli = krbctx_srv = NULL;
1711         krb_kt_cli = krb_kt_srv = NULL;
1712         got_cc_cli = got_cc_srv = 0;
1713         //
1714         // Construct credentials caching for Kerberos
1715         if (k5err == 0) {
1716                 k5err = krb5_init_context (&krbctx_cli);
1717         }
1718         if (k5err == 0) {
1719                 k5err = krb5_init_context (&krbctx_srv);
1720         }
1721         //
1722         // Load the various configuration variables
1723         cfg = cfg_krb_client_keytab ();
1724         if ((k5err == 0) && (cfg != NULL)) {
1725                 k5err = krb5_kt_resolve (krbctx_cli, cfg, &krb_kt_cli);
1726         }
1727         cfg = cfg_krb_server_keytab ();
1728         if ((k5err == 0) && (cfg != NULL)) {
1729                 k5err = krb5_kt_resolve (krbctx_srv, cfg, &krb_kt_srv);
1730         }
1731         cfg = cfg_krb_client_credcache ();
1732 #if 0  /* Temporary bypass of cctype checks */
1733         if ((k5err == 0) && (cfg != NULL)) {
1734                 k5err = krb5_cc_set_default_name (krbctx_cli, cfg);
1735                 if (k5err == 0) {
1736                         k5err = krb5_cc_default (krbctx_cli, &krb_cc_tmp);
1737                 }
1738                 if (k5err == 0) {
1739                         got_cc_cli = 1;
1740                         cctype_cli = krb5_cc_get_type (krbctx_cli, krb_cc_tmp);
1741                         krb5_cc_close (krbctx_cli, krb_cc_tmp);
1742                 }
1743         }
1744 #endif
1745         cfg = cfg_krb_server_credcache ();
1746 #if 0  /* Temporary bypass of cctype checks */
1747         if ((k5err == 0) && (cfg != NULL)) {
1748                 k5err = krb5_cc_set_default_name (krbctx_srv, cfg);
1749                 if (k5err == 0) {
1750                         k5err = krb5_cc_default (krbctx_srv, &krb_cc_tmp);
1751                 }
1752                 if (k5err == 0) {
1753                         got_cc_srv = 1;
1754                         cctype_srv = krb5_cc_get_type (krbctx_cli, krb_cc_tmp);
1755                         krb5_cc_close (krbctx_srv, krb_cc_tmp);
1756                 }
1757         }
1758 #endif
1759         //
1760         // Check for consistency and log helpful messages for the sysop
1761         if (k5err != 0) {
1762                 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "Error during STARTTLS setup: %s (acting on %s)",
1763                                 krb5_get_error_message (krbctx_cli, k5err),
1764                                 cfg);
1765                 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1766         }
1767         if (krb_kt_cli != NULL) {
1768                 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_WARNING, "Ignoring the configured kerberos_client_keytab -- it is not implemented yet");
1769         }
1770         if (krb_kt_srv == NULL) {
1771                 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "No kerberos_server_keytab configured, so Kerberos cannot work at all");
1772                 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1773 /* TODO: Only for MIT krb5 1.11 and up
1774         } else if (0 == krb5_kt_have_content (krb_ctx, krb_kt_srv)) {
1775                 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "Keytab in kerberos_server_keytab is absent or empty");
1776                 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1777  */
1778         }
1779         if (krbctx_cli == NULL) {
1780                 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "No kerberos_client_credcache configured, so Kerberos cannot work at all");
1781                 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1782 #if 0  /* Temporary bypass of cctype checks */
1783         } else if (!krb5_cc_support_switch (
1784                         krbctx_cli, cctype_cli)) {
1785                 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "Your kerberos_client_credcache does not support multilpe identities");
1786                 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1787 #endif
1788         }
1789         if (krbctx_srv == NULL) {
1790                 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_WARNING, "No kerberos_server_credcache configured, so user-to-user Kerberos will not work");
1791 #if 0  /* Temporary bypass of cctype checks */
1792         } else if (!krb5_cc_support_switch (
1793                         krbctx_srv, cctype_srv)) {
1794                 tlog (TLOG_DAEMON | TLOG_KERBEROS, LOG_ERR, "Your kerberos_server_credcache does not support multilpe identities");
1795                 retval = GNUTLS_E_UNWANTED_ALGORITHM;
1796 #endif
1797         }
1798         if (retval != GNUTLS_E_SUCCESS) {
1799                 cleanup_starttls_kerberos ();
1800         }
1801         return retval;
1802 }
1803 #endif
1804
1805
1806 /* Cleanup Kerberos resources.  This must be an idempotent function, because
1807  * it is called when Kerberos panics as well as when
1808  */
1809 #ifdef HAVE_TLS_KDH
1810 static void cleanup_starttls_kerberos (void) {
1811         if (krb_kt_srv != NULL) {
1812                 krb5_kt_close (krbctx_srv, krb_kt_srv);
1813                 krb_kt_srv = NULL;
1814         }
1815         if (krb_kt_cli != NULL) {
1816                 krb5_kt_close (krbctx_cli, krb_kt_cli);
1817                 krb_kt_cli = NULL;
1818         }
1819         if (krbctx_srv != NULL) {
1820                 krb5_free_context (krbctx_srv);
1821                 krbctx_srv = NULL;
1822         }
1823         if (krbctx_cli != NULL) {
1824                 krb5_free_context (krbctx_cli);
1825                 krbctx_cli = NULL;
1826         }
1827 }
1828 #endif
1829
1830
1831 /* Prompter callback function for PKCS #11.
1832  *
1833  * TODO: Use "struct pkcs11iter" as data, possibly interact with the user,
1834  * and keep a score on where we stand with password entry and changes.
1835  * Create clisrv_p11krb_setup() and clisrv_p11krb_cleanup() functions.
1836  *
1837  * In the current release for Kerberos, we have a very minimal mode for
1838  * doing this.  We may embellish it later or, preferrably, turn to a more
1839  * PKCS #11 styled approach, perhaps PKINIT or FAST.
1840  */
1841 #ifdef HAVE_TLS_KDH
1842 static krb5_error_code clisrv_p11krb_callback (krb5_context ctx,
1843                                         void *vcmd,
1844                                         const char *name,
1845                                         const char *banner,
1846                                         int num_prompts,
1847                                         krb5_prompt prompts []) {
1848         struct command *cmd = (struct command *) vcmd;
1849         int i;
1850         krb5_prompt_type *codes = krb5_get_prompt_types (ctx);
1851         int attempt = 0;
1852         static const char *token_url = "pkcs11:manufacturer=Kerberos+infrastructure;model=TLS+Pool;serial=%28none%29";
1853         static const char *token_label = "Kerberos infrastructure";
1854         for (i=0; i<num_prompts; i++) {
1855                 //
1856                 // Visit each prompt in turn, setting responses or return failure
1857                 switch (codes [i]) {
1858                 case KRB5_PROMPT_TYPE_PASSWORD:
1859                         //TODO// Read a password from PKCS #11
1860                         //TODO// Do we need to cycle passwords to cover retry?
1861                         //TODO// Delete any failed passwords?
1862                         //TODO:FIXED//
1863                         if (attempt >= MAX_P11ITER_ATTEMPTS) {
1864                                 return KRB5_LIBOS_CANTREADPWD;
1865                         }
1866                         // Nothing in PKCS #11 --> so fallback on manual entry
1867                         if (!pin_callback (attempt,
1868                                         token_url, "Enter Kerberos password:",
1869                                         prompts [i].reply->data,
1870                                         prompts [i].reply->length)) {
1871                                 memset (prompts [i].reply->data, 0, prompts [i].reply->length);
1872                                 return KRB5_LIBOS_CANTREADPWD;
1873                         }
1874                         //TODO// Manage data structure
1875                         prompts [i].reply->length = strlen (prompts [i].reply->data);
1876                         return 0;
1877                 case KRB5_PROMPT_TYPE_NEW_PASSWORD:
1878                 case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
1879                         //TODO// Setup new password in PKCS #11
1880                 case KRB5_PROMPT_TYPE_PREAUTH:
1881                         //TODO// Use FAST, PKINIT, and so on...
1882                 default:
1883                         // Unrecognised and unimplemented prompt types end here
1884                         return KRB5_LIBOS_CANTREADPWD;
1885                 }
1886         }
1887         return 0;
1888 }
1889 #endif
1890
1891
1892 /* Find a Kerberos keyblock and ticket to use for the localid.  Do not look
1893  * into services yet in this function.  This function implements a simple
1894  * procedure, based on optional arguments p11uri, keytab, credcache.  It
1895  * produces <key,tgt> or <key,NULL> or (for errors) <NULL,NULL>.
1896  *
1897  * The procedure followed, fully written out, is outlined below:
1898  *
1899  *      IF      have(credcache) AND acceptable (renewable) time
1900  *      THEN    RETURN <key,tgt>
1901  *      ELSE    IF have (keytab) AND found a suitable key
1902  *              THEN    IF have(credcache) and it works
1903  *                      THEN    fetch cred tgt and key (auth with key in keytab)
1904  *                              create credcache
1905  *                              RETURN <key,tgt>
1906  *                      ELSE    RETURN <key,NULL>
1907  *              ELSE    IF have(p11uri) AND it works
1908  *                      THEN    fetch cred tgt and key (auth with pwd in p11uri)
1909  *                              create credcache
1910  *                              RETURN <key,tgt>
1911  *                      ELSE    RETURN <NULL,NULL>
1912  *
1913  * The function returns a status value counting the number of values returned,
1914  * so 0 means error, 1 means key only and 2 means key and tgt.
1915  */
1916 #ifdef HAVE_TLS_KDH
1917 static int have_key_tgt_cc (struct command *cmd,             // in, session context
1918                                 krb5_context ctx,    // in, kerberos context
1919                                 bool use_cc,         // in, whether to use cc
1920                                 krb5_kvno kvno,      // in, kvno (0 for highest)
1921                                 krb5_enctype enctype,// in, enctype (0 for any)
1922                                 char *p11uri,        // in/opt, PKCS #11 pwd URI
1923                                 krb5_keytab kt,      // in/opt, keytab
1924                                 krb5_keyblock *key,  // opt/opt session key
1925                                 krb5_creds **tgt,    // out/opt, tkt granting tkt
1926                                 krb5_ccache *cc) {   // out/opt, cred cache
1927         int k5err = 0;
1928         krb5_ccache newcc = NULL;
1929         krb5_principal sought  = NULL;
1930         krb5_principal sought1 = NULL;
1931         krb5_principal tgtname = NULL;
1932         krb5_keytab_entry ktentry;
1933         const char *svc = cmd->cmd.pio_data.pioc_starttls.service;
1934         const char *lid = cmd->cmd.pio_data.pioc_starttls.localid;
1935         const char *liddom;
1936         int lid1len;
1937         char **realms;
1938         char realm [128];
1939         uint32_t nametype, nametype_alt;
1940         time_t now = 0;
1941         //
1942         // Assertions, and initialise variables
1943         assert ( cmd != NULL);
1944         assert ( ctx != NULL);
1945         assert ( key != NULL);
1946         assert (*tgt == NULL);
1947         krb5_free_keyblock_contents (ctx, key);
1948         if (cc != NULL) {
1949                 *cc = NULL;
1950         }
1951         //
1952         // Construct the realm name
1953         liddom = strrchr (lid, '@');
1954         if (liddom != NULL) {
1955                 lid1len = ((intptr_t) liddom) - ((intptr_t) lid);
1956                 liddom++;  // Skip '@'
1957         } else {
1958                 liddom = lid;  // localid is a host
1959                 lid1len = strnlen (lid, 128);
1960         }
1961         k5err = krb5_get_host_realm (ctx, liddom, &realms);
1962         if ((k5err == 0) && (realms [0] != NULL) && (*realms [0] != '\0')) {
1963                 strncpy (realm, realms [0], sizeof (realm));
1964                 realm [sizeof (realm)-1] = '\0';
1965         } else {
1966                 int i = 0;
1967                 do {
1968                         realm [i] = toupper (liddom [i]);
1969                         i++;
1970                 } while (liddom [i-1] != '\0');
1971         }
1972         if (k5err == 0) {
1973                 krb5_free_host_realm (ctx, realms);
1974         } else {
1975                 k5err = 0;
1976         }
1977         //
1978         // Construct a sought principal name in a given naming style,
1979         // and try to locate it in the existing cache.
1980         // With @, try liduser@liddom@REALM or else liduser@REALM
1981         // Without @, try svc/liddom@REALM
1982         nametype = (lid == liddom) ? KRB5_NT_SRV_HST : KRB5_NT_ENTERPRISE_PRINCIPAL;
1983 retry:
1984         nametype_alt = nametype;
1985         switch (nametype) {
1986         case KRB5_NT_ENTERPRISE_PRINCIPAL:
1987                 nametype_alt = KRB5_NT_PRINCIPAL;
1988                 k5err = krb5_build_principal_ext (ctx, &sought,
1989                                         strlen (realm), realm,
1990                                         strnlen (lid, 128), lid,
1991                                         0);
1992                 break;
1993         case KRB5_NT_SRV_HST:
1994                 if (strcmp (svc, "http") == 0) {
1995                         svc = "HTTP";
1996                 }
1997                 k5err = krb5_build_principal_ext (ctx, &sought,
1998                                         strlen (realm), realm,
1999                                         strlen (svc), svc,
2000                                         lid1len, lid,
2001                                         0);
2002                 break;
2003         case KRB5_NT_PRINCIPAL:
2004                 k5err = krb5_build_principal_ext (ctx, &sought,
2005                                         strlen (realm), realm,
2006                                         lid1len, lid,
2007                                         0);
2008                 break;
2009         }
2010         if (k5err == 0) {
2011                 sought->type = nametype;
2012         } else {
2013                 sought = NULL;
2014         }
2015         k5err = krb5_cc_cache_match (ctx, sought, &newcc);
2016         if (k5err != 0) {
2017                 if ((nametype_alt != nametype) && (sought1 == NULL)) {
2018                         nametype = nametype_alt;
2019                         sought1  = sought;
2020                         sought   = NULL;
2021                         goto retry;
2022                 }
2023                 //
2024                 // We failed to find an *existing* credentials cache
2025                 // for the local identity.
2026                 //
2027                 // Our new hope is to create a fresh credential, and add
2028                 // it to the current credcache.  To that end, we now try
2029                 // to overrule k5err by getting hold of our default cc.
2030                 goto from_scratch;
2031         }
2032         //
2033         // Construct the TGT name
2034         k5err = krb5_build_principal_ext (ctx, &tgtname,
2035                                 strlen (realm), realm,
2036                                 6, "krbtgt",
2037                                 strlen (realm), realm,
2038                                 0);
2039         if (k5err != 0) {
2040                 tgtname = NULL;
2041                 k5err = 0;
2042         }
2043         tgtname->type = KRB5_NT_SRV_INST;
2044         //
2045         // Try to get the service ticket for the TGT name from the cache
2046         krb5_creds credreq;
2047         memset (&credreq, 0, sizeof (credreq));
2048         credreq.client = sought;
2049         credreq.server = tgtname;
2050         k5err = krb5_get_credentials (ctx,
2051                                 /* KRB5_GC_USER_USER ?|? */
2052                                         ( use_cc ? 0 : KRB5_GC_CACHED ),
2053                                 newcc,
2054                                 &credreq, tgt);
2055         time (&now);
2056         if ((k5err == 0)
2057                                 && (now + 300 > (*tgt)->times.endtime)
2058                                 && (now + 300 < (*tgt)->times.renew_till)) {
2059                 //TODO:NOTHERE// krb5_free_creds (ctx, *tgt);
2060                 //TODO:NOTHERE// *tgt = NULL;
2061                 // Try to renew the ticket
2062                 k5err = krb5_get_renewed_creds (ctx,
2063                                 *tgt,
2064                                 sought,
2065                                 newcc,
2066                                 NULL);   /* krbtgt/REALM@REALM */
2067         }
2068         if ((k5err == 0)
2069                                 && (now + 300 > (*tgt)->times.endtime)) {
2070                 // Thanks, but no thanks!
2071                 krb5_free_creds (ctx, *tgt);
2072                 *tgt = NULL;
2073                 k5err = 666;
2074         }
2075         if (k5err == 0) {
2076                 // First case worked -- return <key,tgt> from credout
2077                 k5err = krb5_copy_keyblock_contents (ctx,
2078                                 &(*tgt)->keyblock,
2079                                 key);
2080                 // On failure, key shows failure
2081                 if (cc != NULL) {
2082                         *cc = newcc;
2083                         newcc = NULL;
2084                 }
2085                 goto cleanup;
2086         }
2087 from_scratch:
2088         //
2089         // Prior attempts failed.  Instead, look for keytab or p11uri presence.
2090         // This is skipped when the use_cc option below welcomes krb5_creds.
2091         if ((key->contents == NULL) && (p11uri == NULL) && (kt == NULL)) {
2092                 // We cannot obtain a new krbtgt
2093                 // We simply return what we've got (which may be nothing)
2094                 goto cleanup;
2095         }
2096         if ((kt == NULL) && (!use_cc)) {
2097                 // We have nowhere to store a new krbtgt if we got it
2098                 // We simply return what we've got (which is at least a key)
2099                 goto cleanup;
2100         }
2101         //
2102         // Either we have a keytab key, or we have a p11uri,
2103         // so we can attempt to create a new credcache with a new krbtgt
2104         if (use_cc) {
2105                 if (newcc == NULL) {
2106                         k5err = krb5_cc_default (ctx, &newcc);
2107                         if (k5err != 0) {
2108                                 // Utter failure to do even the simplest thing
2109                                 goto cleanup;
2110                         }
2111                 }
2112                 *tgt = malloc (sizeof (**tgt));
2113                 if (*tgt == NULL) {
2114                         // Memory error
2115                         goto cleanup;
2116                 }
2117                 memset (*tgt, 0, sizeof (**tgt));
2118                 if ((sought != NULL) && (sought1 == NULL)) {
2119                         // We only tried one name
2120                         sought1 = sought;
2121                         sought = NULL;
2122                 }
2123                 do {
2124                         if (sought1 == NULL) {
2125                                 break;
2126                         }
2127                         if (p11uri == NULL) {
2128                                 k5err = krb5_get_init_creds_keytab (
2129                                                 ctx,
2130                                                 *tgt,
2131                                                 sought1,
2132                                                 kt,
2133                                                 0,    /* start now please */
2134                                                 NULL, /* get a TGT please */
2135                                                 NULL);  //TODO// opts needed?
2136                         } else {
2137                                 //TODO// Prepare PKCS #11 access
2138                                 k5err = krb5_get_init_creds_password (
2139                                                 ctx,
2140                                                 *tgt,
2141                                                 sought1,
2142 #ifdef TOM_IS_WEG
2143                                                 NULL,   // Use callbacks for password
2144                                                 clisrv_p11krb_callback,
2145 #else
2146                                                 "1234",
2147                                                 NULL,
2148 #endif
2149                                                 cmd,  /* callback data pointer */
2150                                                 0,    /* start now please */
2151                                                 NULL, /* get a TGT please */
2152                                                 NULL);  //TODO// opts needed?
2153                                 //TODO// End PKCS #11 access
2154                         }
2155                         krb5_free_principal (ctx, sought1);
2156                         sought1 = sought;
2157                         sought = NULL;
2158                 } while (k5err != 0);
2159                 if (k5err != 0) {
2160                         // Failed to initiate new credentials
2161                         krb5_free_creds (ctx, *tgt);
2162                         *tgt = NULL;
2163                         goto cleanup;
2164                 }
2165                 // Try to store the credential, if it was found
2166                 if (sought1 != NULL) {
2167                         k5err = krb5_cc_initialize (ctx, newcc, sought1);
2168                         if (k5err == 0) {
2169                                 k5err = krb5_cc_store_cred (ctx, newcc, *tgt);
2170                         }
2171                 }
2172                 // Copy the keyblock; any failure will show up in key
2173                 krb5_copy_keyblock_contents (ctx,
2174                         &(*tgt)->keyblock, //TODO:UNINIT// &ktentry.key,
2175                         key);
2176                 //
2177                 // We succeeded in setting up a new Ticket Granting Ticket!
2178                 if (cc != NULL) {
2179                         *cc = newcc;
2180                         newcc = NULL;
2181                 }
2182                 goto cleanup;
2183         }
2184         //
2185         // As a last resort, dig up a key directly from the keytab;
2186         // this is the only place where kvno and enctype are used
2187         if (kt != NULL) {
2188                 //NOTE// Might be more direct as krb5_kt_read_service_key()
2189                 k5err = krb5_kt_get_entry (
2190                                         ctx, kt,
2191                                         sought,
2192                                         kvno, enctype,
2193                                         &ktentry);
2194                 if (k5err == 0) {
2195                         k5err = krb5_copy_keyblock_contents (ctx,
2196                                 &ktentry.key,
2197                                 key);
2198                         krb5_free_keytab_entry_contents (ctx, &ktentry);
2199                         // On failure, key shows failure.
2200                         if (cc != NULL) {
2201                                 *cc = newcc;
2202                                 newcc = NULL;
2203                         }
2204                         goto cleanup;
2205                 }
2206         }
2207         //
2208         // Nothing more to try, so we continue into cleanup
2209 cleanup:
2210         //
2211         // Cleanup and return the <key,tgt> values as they were delivered
2212         if (sought1 != NULL) {
2213                 krb5_free_principal (ctx, sought1);
2214                 sought1 = NULL;
2215         }
2216         if (sought != NULL) {
2217                 krb5_free_principal (ctx, sought);
2218                 sought = NULL;
2219         }
2220         if (tgtname != NULL) {
2221                 krb5_free_principal (ctx, tgtname);
2222                 tgtname = NULL;
2223         }
2224         if (newcc != NULL) {
2225                 krb5_cc_close (ctx, newcc);
2226                 newcc = NULL;
2227         }
2228         if (key->contents == NULL) {
2229                 if (k5err != 0) {
2230                         const char *errmsg = krb5_get_error_message (ctx, k5err);
2231                         tlog (TLOG_DAEMON, LOG_ERR, "Kerberos error in have_key_tgt_cc: %s", errmsg);
2232                         krb5_free_error_message (ctx, errmsg);
2233                 }
2234                 if (*tgt != NULL) {
2235                         krb5_free_creds (ctx, *tgt);
2236                         *tgt = NULL;
2237                 }
2238                 if ((cc != NULL) && (*cc != NULL)) {
2239                         krb5_cc_close (ctx, *cc);
2240                         *cc = NULL;
2241                 }
2242                 return 0;
2243         } else if (tgt == NULL) {
2244                 if ((cc != NULL) && (*cc != NULL)) {
2245                         krb5_cc_close (ctx, *cc);
2246                         *cc = NULL;
2247                 }
2248                 return 1;
2249         } else if ((cc == NULL) || (*cc == NULL)) {
2250                 return 2;
2251         } else {
2252                 return 3;
2253         }
2254 }
2255 #endif
2256
2257
2258 /* Have a ticket for the remote service.  Do this as a client.  The client
2259  * principal and realm are provided, and the ticket to be returned will
2260  * also provide the accompanying key.
2261  *
2262  * This function will incorporate the peer TGT, when it is provided.  This
2263  * is the case in KDH-Only exchanges with a non-empty Server Certificate.
2264  *
2265  * TODO: We are not currently serving backend tickets, but these could be
2266  * passed in as authorization data along with the credential request.
2267  * Note however, that authorization data is copied by default from the TGT,
2268  * but not necessarily from the request.  Not without KDC modifications.
2269  * But then again, the KDC should have responded with an error that it was
2270  * missing backend services; this is not something the client should decide
2271  * on, and certainly not after being requested by the service.  The error
2272  * and recovery could be implemented here (if we can get the error info out
2273  * of the libkrb5 API).  Alternatively, we might consider passing the
2274  * authorization data in the authenticator since we get to control it.
2275  * What will the specification say?
2276  *
2277  * The return value indicates how many of the requested output values have
2278  * been provided, counting from the first.  So, 0 means a total failure and
2279  * anything higher is a (partial) success.
2280  */
2281 #ifdef HAVE_TLS_KDH
2282 static int have_service_ticket (
2283                                 struct command *cmd,  // in, session context
2284                                 krb5_context ctx,     // in, kerberos context
2285                                 krb5_ccache cc_opt,   // in/opt, credcache
2286                                 krb5_principal cli,   // in, client principal
2287                                 krb5_creds **ticket) {// out, tkt granting tkt
2288         int k5err = 0;
2289         krb5_ccache cc = cc_opt;
2290         krb5_flags u2u = 0;
2291         krb5_principal srv = NULL;
2292         krb5_data tkt_srv;
2293         krb5_creds credreq;
2294         //
2295         // Sanity checks and initialisation
2296         memset (&tkt_srv, 0, sizeof (tkt_srv));
2297         memset (&credreq, 0, sizeof (credreq));
2298         *ticket = NULL;
2299         //
2300         // Determine the optional cc parameter if it was not provided
2301         //TODO// This can go if we always get it passed from have_key_tgt_cc()
2302         if (cc == NULL) {
2303                 k5err = krb5_cc_cache_match (ctx, cli, &cc);
2304                 if (k5err != 0) {
2305                         goto cleanup;
2306                 }
2307         }
2308         //
2309         // Build the server's principal name
2310         const char *svc = cmd->cmd.pio_data.pioc_starttls.service;
2311         const char *rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
2312         const char *riddom;
2313         char **realms;
2314         char realm [128];
2315         riddom = strrchr (rid, '@');
2316         if (riddom != NULL) {
2317                 riddom++;  // Skip '@'
2318         } else {
2319                 riddom = rid;  // localid is a host
2320         }
2321         k5err = krb5_get_host_realm (ctx, riddom, &realms);
2322         if ((k5err == 0) && (realms [0] != NULL) && (*realms [0] != '\0')) {
2323                 strncpy (realm, realms [0], sizeof (realm));
2324                 realm [sizeof (realm)-1] = '\0';
2325         } else {
2326                 int i = 0;
2327                 do {
2328                         realm [i] = toupper (riddom [i]);
2329                         i++;
2330                 } while (riddom [i-1] != '\0');
2331         }
2332         if (k5err == 0) {
2333                 krb5_free_host_realm (ctx, realms);
2334         } else {
2335                 k5err = 0;
2336         }
2337         if (strcmp (svc, "http") == 0) {
2338                 svc = "HTTP";
2339         }
2340         k5err = krb5_build_principal_ext (ctx, &srv,
2341                                 strlen (realm), realm,
2342                                 strlen (svc), svc,
2343                                 strlen (rid), rid,
2344                                 0);
2345         if (k5err != 0) {
2346                 goto cleanup;
2347         }
2348         srv->type = KRB5_NT_SRV_HST;
2349         //
2350         // Construct credential request
2351         credreq.client = cli;
2352         credreq.server = srv;
2353         //TODO// credreq.authdata may be used for backend service tickets
2354         //
2355         // See if our peer provided us with a TGT
2356         //  - we are sure of GNUTLS_CRD_CERTIFICATE because we implement it now
2357         //  - we must ensure that this is KDH-Only (remote GNUTLS_CRT_KRB)
2358         //  - we must ensure that the remote provided a non-empty ticket
2359         if (gnutls_certificate_type_get_peers (cmd->session) == GNUTLS_CRT_KRB) {
2360                 // This is KDH-Only -- and the server may present a TGT
2361                 const gnutls_datum_t *opt_srv_tkt;
2362                 unsigned int srv_tkt_count;
2363                 opt_srv_tkt = gnutls_certificate_get_peers (cmd->session, &srv_tkt_count);
2364                 if ((opt_srv_tkt != NULL) && (srv_tkt_count >= 1) && (opt_srv_tkt [0].size > 5)) {
2365                         // Looks good, we'll use only the first (normally only) one
2366                         credreq.second_ticket.data   = opt_srv_tkt [0].data;
2367                         credreq.second_ticket.length = opt_srv_tkt [0].size;
2368                         u2u = KRB5_GC_USER_USER;
2369                 }
2370         }
2371         //
2372         // Fetch the ticket for the service
2373         k5err = krb5_get_credentials (ctx, u2u, cc, &credreq, ticket);
2374         //
2375         // Cleanup and return; the return value depends on k5err
2376 cleanup:
2377         if ((cc != NULL) && (cc_opt == NULL)) {
2378                 //TODO// This can go if we always get it passed from have_key_tgt_cc()
2379                 krb5_cc_close (ctx, cc);
2380                 cc = NULL;
2381         }
2382         if (srv != NULL) {
2383                 krb5_free_principal (ctx, srv);
2384         }
2385         return (k5err == 0) ? 1 : 0;
2386 }
2387 #endif
2388
2389
2390 /* DER utility: This should probably appear in Quick DER sometime soon.
2391  *
2392  * Pack an Int32 or UInt32 and return the number of bytes.  Do not pack a header
2393  * around it.  The function returns the number of bytes taken, even 0 is valid.
2394  */
2395 typedef uint8_t QDERBUF_INT32_T [4];
2396 dercursor qder2b_pack_int32 (uint8_t *target_4b, int32_t value) {
2397         dercursor retval;
2398         int shift = 24;
2399         retval.derptr = target_4b;
2400         retval.derlen = 0;
2401         while (shift >= 0) {
2402                 if ((retval.derlen == 0) && (shift > 0)) {
2403                         // Skip sign-extending initial bytes
2404                         uint32_t neutro = (value >> (shift - 1) ) & 0x000001ff;
2405                         if ((neutro == 0x000001ff) || (neutro == 0x00000000)) {
2406                                 shift -= 8;
2407                                 continue;
2408                         }
2409                 }
2410                 target_4b [retval.derlen] = (value >> shift) & 0xff;
2411                 retval.derlen++;
2412                 shift -= 8;
2413         }
2414         return retval;
2415 }
2416 typedef uint8_t QDERBUF_UINT32_T [5];
2417 dercursor qder2b_pack_uint32 (uint8_t *target_5b, uint32_t value) {
2418         dercursor retval;
2419         int ofs = 0;
2420         if (value & 0x80000000) {
2421                 *target_5b = 0x00;
2422                 ofs = 1;
2423         }
2424         retval = qder2b_pack_int32 (target_5b + ofs, (int32_t) value);
2425         retval.derptr -= ofs;
2426         retval.derlen += ofs;
2427         return retval;
2428 }
2429
2430
2431 /* DER utility: This should probably appear in Quick DER sometime soon.
2432  *
2433  * Unpack an Int32 or UInt32 from a given number of bytes.  Do not assume a header
2434  * around it.  The function returns the value found.
2435  *
2436  * Out of range values are returned as 0.  This value only indicates invalid
2437  * return when len > 1, so check for that.
2438  */
2439 int32_t qder2b_unpack_int32 (dercursor data4) {
2440         int32_t retval = 0;
2441         int idx;
2442         if (data4.derlen > 4) {
2443                 goto done;
2444         }
2445         if ((data4.derlen > 0) && (0x80 & *data4.derptr)) {
2446                 retval = -1;
2447         }
2448         for (idx=0; idx<data4.derlen; idx++) {
2449                 retval <<= 8;
2450                 retval += data4.derptr [idx];
2451         }
2452 done:
2453         return retval;
2454 }
2455 uint32_t qder2b_unpack_uint32 (dercursor data5) {
2456         uint32_t retval = 0;
2457         int ofs = 0;
2458         if (data5.derlen > 5) {
2459                 goto done;
2460         }
2461         if (data5.derlen == 5) {
2462                 if (*data5.derptr != 0x00) {
2463                         goto done;
2464                 }
2465                 // Modify the local copy on our stack
2466                 data5.derlen--;
2467                 data5.derptr++;
2468         }
2469         retval = (uint32_t) qder2b_unpack_int32 (data5);
2470 done:
2471         return retval;
2472 }
2473
2474
2475 #ifdef HAVE_TLS_KDH
2476 /* TODO: Debugging function for printing (descr,ptr,len) ranges */
2477 static inline void prange (char *descr, uint8_t *ptr, int len) {
2478         fprintf (stderr, "%s #%04d: %02x %02x %02x %02x %02x %02x %02x %02x...%02x %02x %02x %02x\n",
2479                         descr, len,
2480                         ptr [0], ptr [1], ptr [2], ptr [3],
2481                         ptr [4], ptr [5], ptr [6], ptr [7],
2482                         ptr [len-4], ptr [len-3], ptr [len-2], ptr [len-1]);
2483 }
2484 static inline void prangefull (char *descr, uint8_t *ptr, int len) {
2485         fprintf (stderr, "%s #%04d:", descr, len);
2486         while (len-- > 0) {
2487                 fprintf (stderr, " %02x", *ptr++);
2488         }
2489         fprintf (stderr, "\n");
2490 }
2491 #endif
2492
2493
2494 /* The callback function that retrieves a TLS-KDH "signature", which is kept
2495  * outside of GnuTLS.  The callback computes an authenticator encrypted to
2496  * the session's Kerberos key.
2497  */
2498 #ifdef HAVE_TLS_KDH
2499 static gtls_error cli_kdhsig_encode (gnutls_session_t session,
2500                         gnutls_datum_t *enc_authenticator,
2501                         gnutls_datum_t *dec_authenticator,
2502                         const gnutls_datum_t *hash,
2503                         int32_t checksum_type) {
2504         //
2505         // Variables, sanity checking, initialisation
2506         struct command *cmd;
2507         int k5err = 0;
2508         authenticator_t auth;
2509         QDERBUF_INT32_T derv5;
2510         QDERBUF_INT32_T dernametype;
2511         QDERBUF_INT32_T dercksumtype;
2512         krb5_keyblock subkey;
2513         gnutls_certificate_type_t peercert;
2514         QDERBUF_INT32_T dersubkey;
2515         krb5_timestamp now_s;
2516         char derctime [100];
2517         krb5_int32 now_us;
2518         QDERBUF_INT32_T dercusec;
2519         cmd = (struct command *) gnutls_session_get_ptr (session);
2520         memset (&auth, 0, sizeof (auth));
2521         memset (&subkey, 0, sizeof (subkey));
2522         assert (cmd->krbid_cli != NULL);
2523         assert (cmd->krb_key.contents != NULL);
2524         static const uint8_t auth_packer [] = {
2525                         DER_PACK_rfc4120_Authenticator, DER_PACK_END };
2526         static const uint8_t encdata_packer [] = {
2527                         DER_PACK_rfc4120_EncryptedData, DER_PACK_END };
2528         //
2529         // Setup secure hash in authenticator (never optional for TLS-KDH)
2530         auth.cksum.cksumtype = qder2b_pack_int32 (dercksumtype, checksum_type);
2531         auth.cksum.checksum.derptr = hash->data;
2532         auth.cksum.checksum.derlen = hash->size;
2533         //
2534         // Optionally include a subkey (namely, for KDH-Only)
2535         peercert = gnutls_certificate_type_get_peers (session);
2536         if (peercert == GNUTLS_CRT_KRB) {
2537                 // This is KDH-Only, for which we MUST create a random subkey
2538                 k5err = krb5_c_make_random_key (
2539                                 krbctx_cli,
2540                                 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
2541                                 &subkey);
2542                 if (k5err != 0) {
2543                         return GNUTLS_E_ENCRYPTION_FAILED;
2544                 }
2545                 auth.subkey.keytype = qder2b_pack_int32 (dersubkey, subkey.enctype);
2546                 auth.subkey.keyvalue.derptr = subkey.contents;
2547                 auth.subkey.keyvalue.derlen = subkey.length;
2548 prange ("cli_K", subkey.contents, subkey.length);
2549         }
2550         //
2551         // Setup the client realm and principal name
2552         auth.crealm.derptr = cmd->krbid_cli->realm.data;
2553         auth.crealm.derlen = cmd->krbid_cli->realm.length;
2554         auth.cname.name_type = qder2b_pack_int32 (dernametype, cmd->krbid_cli->type);
2555         // The SEQUENCE OF with just one component is trivial to prepack
2556         auth.cname.name_string.derptr = cmd->krbid_cli->data [0].data;
2557         auth.cname.name_string.derlen = cmd->krbid_cli->data [0].length;
2558         //
2559         // Setup the Kerberos version number (5)
2560         auth.authenticator_vno = qder2b_pack_int32 (derv5, 5);
2561         //
2562         // Setup the obliged microsecond timer values (ignore error returns)
2563         krb5_us_timeofday (krbctx_cli, &now_s, &now_us);
2564         krb5_timestamp_to_string (now_s, derctime, sizeof (derctime));
2565         derctime [sizeof (derctime)-1] = '\0';
2566         auth.ctime.derptr = derctime;
2567         auth.ctime.derlen = strlen (derctime);
2568         auth.cusec = qder2b_pack_int32 (dercusec, now_us);
2569         //
2570         // Pack the decoded result into dec_authenticator
2571         size_t declen = der_pack (      auth_packer,
2572                                         (const dercursor *) &auth,
2573                                         NULL    // Measure length, no output yet
2574                                         );
2575         uint8_t *decptr = gnutls_malloc (declen);
2576         if (decptr == NULL) {
2577                 return GNUTLS_E_MEMORY_ERROR;
2578         }
2579         der_pack (                      auth_packer,
2580                                         (const dercursor *) &auth,
2581                                         decptr + declen);
2582         krb5_free_keyblock_contents (krbctx_cli, &subkey);
2583 prangefull ("cli_A", decptr, declen);
2584         size_t rawlen;
2585         if (0 != krb5_c_encrypt_length (krbctx_cli,
2586                                         cmd->krb_key.enctype,
2587                                         declen,
2588                                         &rawlen)) {
2589                 gnutls_free (decptr);
2590                 return GNUTLS_E_ENCRYPTION_FAILED;
2591         }
2592         uint8_t *rawptr = gnutls_malloc (rawlen);
2593         if (rawptr == NULL) {
2594                 gnutls_free (decptr);
2595                 return GNUTLS_E_MEMORY_ERROR;
2596         }
2597         krb5_data decdata;
2598         krb5_enc_data rawdata;
2599         memset (&decdata, 0, sizeof (decdata));
2600         memset (&rawdata, 0, sizeof (rawdata));
2601         decdata.data   = decptr;
2602         decdata.length = declen;
2603         rawdata.ciphertext.data   = rawptr;
2604         rawdata.ciphertext.length = rawlen;
2605         if (0 != krb5_c_encrypt (       krbctx_cli,
2606                                         &cmd->krb_key,
2607                                         11 /* stealing key usage from AP-REQ */,
2608                                         NULL,
2609                                         &decdata,
2610                                         &rawdata)) {
2611                 gnutls_free (rawptr);
2612                 gnutls_free (decptr);
2613                 return GNUTLS_E_ENCRYPTION_FAILED;
2614         }
2615         //
2616         // Prepare the header information
2617         QDERBUF_INT32_T deretype;
2618         QDERBUF_UINT32_T derkvno;
2619         encrypted_data_t encdata;
2620         memset (&encdata, 0, sizeof (encdata));
2621         encdata.etype = qder2b_pack_int32 (deretype, cmd->krb_key.enctype);
2622         //NOT// encdata.kvno  = qder2b_pack_int32 (derkvno,  cmd->krb_key.kvno);
2623         encdata.cipher.derptr = rawdata.ciphertext.data;
2624         encdata.cipher.derlen = rawdata.ciphertext.length;
2625         //
2626         // Prepare for packing the header and rawdata as EncryptedData
2627         size_t enclen = der_pack (      encdata_packer,
2628                                         (const dercursor *) &encdata,
2629                                         NULL    // Measure length, no output yet
2630                                         );
2631         uint8_t *encptr = gnutls_malloc (enclen);
2632         if (encptr == NULL) {
2633                 gnutls_free (rawptr);
2634                 gnutls_free (decptr);
2635                 return GNUTLS_E_MEMORY_ERROR;
2636         }
2637         der_pack (                      encdata_packer,
2638                                         (const dercursor *) &encdata,
2639                                         encptr + enclen);
2640         gnutls_free (rawptr);
2641         //
2642         // Return our final verdict on the generation of the Authenticator
2643         dec_authenticator->data = decptr;
2644         dec_authenticator->size = declen;
2645         enc_authenticator->data = encptr;
2646         enc_authenticator->size = enclen;
2647 prange ("cli_D", decptr, declen);
2648 prange ("cli_E", encptr, enclen);
2649         return 0;
2650 }
2651 #endif
2652
2653
2654 /* The callback function that verifies a TLS-KDH "signature", which is kept
2655  * outside of GnuTLS.  The callback verifies the authenticator against the
2656  * provided session hash and returns the decrypted authenticator.
2657  */
2658 #ifdef HAVE_TLS_KDH
2659 static int srv_kdhsig_decode (gnutls_session_t session,
2660                         const gnutls_datum_t *enc_authenticator,
2661                         gnutls_datum_t *dec_authenticator,
2662                         gnutls_datum_t *hash,
2663                         int32_t *checksum_type) {
2664         //
2665         // Variables, sanity checks and initialisation
2666         int k5err = 0;
2667         struct command *cmd;
2668         static const uint8_t encdata_packer [] = {
2669                 DER_PACK_rfc4120_EncryptedData, DER_PACK_END };
2670         static const uint8_t auth_packer [] = {
2671                 DER_PACK_rfc4120_Authenticator, DER_PACK_END };
2672         encrypted_data_t encdata;
2673         cmd = (struct command *) gnutls_session_get_ptr (session);
2674 prange ("srv_E", enc_authenticator->data, enc_authenticator->size);
2675         //
2676         // Retrieve the session key and store it in cmd->krb_key.
2677         //
2678         // Prior setting of cmd->krb_key would be due to user-to-user mode
2679         // having been setup with this as the server-supplied TGT key, in
2680         // which case cmd->krb_key would need to be overwritten by the
2681         // session key.
2682         //
2683         // When no prior cmd->krb_key is available, use the keytab to
2684         // decode the client's ticket.
2685         assert (gnutls_certificate_type_get_peers (session) == GNUTLS_CRT_KRB);
2686         const gnutls_datum_t *certs;
2687         unsigned int num_certs;
2688         certs = gnutls_certificate_get_peers (cmd->session, &num_certs);
2689         if (num_certs != 1) {
2690                 return GNUTLS_E_NO_CERTIFICATE_FOUND;
2691         }
2692         krb5_data krbcert;
2693         krb5_ticket *tkt;
2694         krbcert.data   = certs [0].data;
2695         krbcert.length = certs [0].size;
2696 prange ("srv_C", certs [0].data, certs [0].size);
2697         if (0 != krb5_decode_ticket (&krbcert, &tkt)) {
2698                 return GNUTLS_E_NO_CERTIFICATE_FOUND;
2699         }
2700         if (cmd->krb_key.contents != NULL) {
2701                 // user-to-user mode
2702                 k5err = krb5_decrypt_tkt_part (
2703                                         krbctx_srv,
2704                                         &cmd->krb_key,
2705                                         tkt);
2706                 krb5_free_keyblock_contents (
2707                                         krbctx_srv,
2708                                         &cmd->krb_key);
2709         } else {
2710                 // client-to-server mode
2711                 k5err = krb5_server_decrypt_ticket_keytab (
2712                                         krbctx_srv,
2713                                         krb_kt_srv,
2714                                         tkt);
2715         }
2716         if (k5err == 0) {
2717                 k5err = krb5_copy_keyblock_contents (
2718                                         krbctx_srv,
2719                                         tkt->enc_part2->session,
2720                                         &cmd->krb_key);
2721         }
2722         if (k5err == 0) {
2723                 k5err = krb5_copy_principal (
2724                                         krbctx_srv,
2725                                         tkt->enc_part2->client,
2726                                         &cmd->krbid_cli);
2727         }
2728         if (k5err == 0) {
2729                 if (cmd->krbid_srv != NULL) {
2730                         k5err = krb5_principal_compare (
2731                                                         krbctx_srv,
2732                                                         tkt->server,
2733                                                         cmd->krbid_srv);
2734                                 // Server name changed since u2u setup => k5err
2735                 } else {
2736                         k5err = krb5_copy_principal (
2737                                                         krbctx_srv,
2738                                                         tkt->server,
2739                                                         &cmd->krbid_srv);
2740                 }
2741         }
2742         krb5_free_ticket (krbctx_srv, tkt);
2743         if (k5err != 0) {
2744                 const char *errmsg = krb5_get_error_message (krbctx_srv, k5err);
2745                 tlog (TLOG_DAEMON, LOG_ERR, "Kerberos error in srv_kdhsig_decode: %s", errmsg);
2746                 krb5_free_error_message (krbctx_srv, errmsg);
2747                 return GNUTLS_E_NO_CERTIFICATE_FOUND;
2748         }
2749         //
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 prangefull ("EncData2unpack", enctransport.derptr, enctransport.derlen);
2755         memset (&encdata, 0, sizeof (encdata));
2756         if (0 != der_unpack (           &enctransport,
2757                                         encdata_packer,
2758                                         (dercursor *) &encdata,
2759                                         1)) {
2760                 tlog (TLOG_DAEMON, LOG_ERR, "Failed to der_unpack(EncryptedData) in server: %s", strerror (errno));
2761                 return GNUTLS_E_DECRYPTION_FAILED;
2762         }
2763         if (encdata.kvno.derptr != NULL) {
2764                 //TODO//NOTYET//ANDWHY// return GNUTLS_E_DECRYPTION_FAILED;
2765         }
2766         int32_t etype = qder2b_unpack_int32 (encdata.etype);
2767         //
2768         // Decrypt the EncryptedData fields into the dec_authenticator
2769         krb5_enc_data rawdata;
2770         krb5_data decdata;
2771         memset (&rawdata, 0, sizeof (rawdata));
2772         memset (&decdata, 0, sizeof (decdata));
2773         rawdata.enctype = etype;
2774         rawdata.ciphertext.data   = encdata.cipher.derptr;
2775         rawdata.ciphertext.length = encdata.cipher.derlen;
2776 prange ("srv_R", encdata.cipher.derptr, encdata.cipher.derlen);
2777         decdata.data   = dec_authenticator->data;
2778         decdata.length = dec_authenticator->size;
2779         if (0 != krb5_c_decrypt (       krbctx_srv,
2780                                         &cmd->krb_key,
2781                                         11 /* stealing key usage from AP-REQ */,
2782                                         NULL,
2783                                         &rawdata,
2784                                         &decdata)) {
2785                 return GNUTLS_E_DECRYPTION_FAILED;
2786         }
2787         dec_authenticator->size = decdata.length;
2788 prange ("srv_D", decdata.data, decdata.length);
2789         //
2790         // Unpack the decrypted Authenticator
2791         dercursor decsyntax;
2792         decsyntax.derptr = decdata.data;
2793         decsyntax.derlen = decdata.length;
2794 prangefull ("srv_A", decdata.data, decdata.length);
2795         authenticator_t auth;
2796         memset (&auth, 0, sizeof (auth));
2797         if (0 != der_unpack (           &decsyntax,
2798                                         auth_packer,
2799                                         (dercursor *) &auth,
2800                                         1)) {
2801                 tlog (TLOG_DAEMON, LOG_ERR, "Failed to der_unpack(Authenticator) in server: %s", strerror (errno));
2802                 return GNUTLS_E_DECRYPTION_FAILED;
2803         }
2804         //
2805         // Validate the contents of the Authenticator
2806         if (qder2b_unpack_int32 (auth.authenticator_vno) != 5) {
2807                 return GNUTLS_E_DECRYPTION_FAILED;
2808         }
2809         if (auth.cksum.checksum.derptr == NULL) {
2810                 return GNUTLS_E_DECRYPTION_FAILED;
2811         }
2812         if (auth.cksum.checksum.derlen < 16) {
2813                 return GNUTLS_E_DECRYPTION_FAILED;
2814         }
2815         //TODO// Optionally, for KDH-Only, ensure presence and size of a subkey
2816         //
2817         // Produce the requested content from the Authenticator and return
2818         *checksum_type = qder2b_unpack_int32 (auth.cksum.cksumtype);
2819         hash->data = auth.cksum.checksum.derptr;
2820         hash->size = auth.cksum.checksum.derlen;
2821         return 0;
2822 }
2823 #endif
2824
2825
2826
2827 /********** VALIDATION EXPRESSION LINKUP TO GNUTLS **********/
2828
2829
2830
2831 /*
2832  * The following functions implement the various validation expression
2833  * components in terms of the GnuTLS sessions of this code file.
2834  * Some work is repeated in various expression variables, notably the
2835  * lookup of a session's peer credentials, and possibly importing them
2836  * into X.509 structures.  We may at some point decide to instead do
2837  * this ahead of time, ath the expense of some compleity and possibly
2838  * slow-down of the start of the computations.
2839  */
2840
2841
2842
2843 /* valexp_store_final -- store the valexp outcome in cmd->valexp_result.
2844  */
2845 static void valexp_store_final (void *vcmd, struct valexp *ve, bool result) {
2846         ((struct command *) vcmd)->valexp_result = result;
2847 }
2848
2849 /* valexp_valflag_set -- set a validation flag bit for an uppercase predicate.
2850  */
2851 static void valexp_valflag_set (struct command *cmd, char pred) {
2852         int len = strlen (cmd->valflags);
2853         cmd->valflags [len++] = pred;
2854         cmd->valflags [len  ] = '\0';
2855 }
2856
2857 /* valexp_valflag_start -- get a prior set bit with validation information.
2858  * Where cmd->valflags is a string of uppercase letters that were ensured.
2859  */
2860 static void valexp_valflag_start (void *vcmd, struct valexp *ve, char pred) {
2861         struct command *cmd = (struct command *) vcmd;
2862         pred &= 0xdf;   // lowercase->uppercase
2863         valexp_setpredicate (ve, pred, NULL != strchr (cmd->valflags, pred));
2864 }
2865
2866 /* valexp_0_start -- validation function for the GnuTLS backend.
2867  * This function immediately sends failure on something impossible.
2868  */
2869 static void valexp_0_start (void *vcmd, struct valexp *ve, char pred) {
2870         valexp_setpredicate (ve, pred, 0);
2871 }
2872
2873 /* valexp_1_start -- validation function for the GnuTLS backend.
2874  * This function immediately sends success on something trivial.
2875  */
2876 static void valexp_1_start (void *vcmd, struct valexp *ve, char pred) {
2877         valexp_setpredicate (ve, pred, 1);
2878 }
2879
2880 //TODO// valexp_L_start, valexp_l_start
2881
2882 /* valexp_I_start -- validation function for the GnuTLS backend.
2883  * This function ensures that the remote peer provides an identity.
2884  * TODO: We should compare the hostname as well, or compare if in remoteid
2885  * TODO: We may need to support more than just X509/PGP certificates
2886  */
2887 static void valexp_I_start (void *vcmd, struct valexp *ve, char pred) {
2888         struct command *cmd = (struct command *) vcmd;
2889         int ok = 1;
2890         ok = ok && (cmd->remote_auth_type == GNUTLS_CRD_CERTIFICATE);
2891         ok = ok && (cmd->remote_cert_count > 0);
2892         // Accept most certificates, but not for example GNUTLS_CRT_RAW
2893         ok = ok && (
2894 #ifdef GNUTLS_CRT_KRB
2895                 (cmd->remote_cert_type == GNUTLS_CRT_KRB) ||
2896 #endif
2897                 (cmd->remote_cert_type == GNUTLS_CRT_X509) ||
2898                 (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) );
2899         // peer-returned "certs" points into GnuTLS' internal data structures
2900         valexp_setpredicate (ve, pred, ok);
2901 }
2902
2903 /* valexp_i_start -- is opportunistic and will always succeed
2904  */
2905 #define valexp_i_start valexp_1_start
2906
2907 /* valexp_Ff_start -- validation function for the GnuTLS backend.
2908  * This functin ensures that forward secrecy is applied.
2909  * While _F_ only accepts DHE, _f_ will also accept DH.
2910  * Note: GnuTLS does not seem to show DH that is not also DHE.
2911  */
2912 static void valexp_Ff_start (void *vcmd, struct valexp *ve, char pred) {
2913         struct command *cmd = (struct command *) vcmd;
2914         gnutls_kx_algorithm_t kx = gnutls_kx_get (cmd->session);
2915         switch (kx) {
2916         case GNUTLS_KX_UNKNOWN:
2917         case GNUTLS_KX_RSA:
2918         case GNUTLS_KX_RSA_EXPORT:
2919         case GNUTLS_KX_PSK:
2920         default:
2921                 valexp_setpredicate (ve, pred, 0);
2922                 break;
2923         case GNUTLS_KX_DHE_DSS:
2924         case GNUTLS_KX_DHE_RSA:
2925         case GNUTLS_KX_SRP:
2926         case GNUTLS_KX_SRP_RSA:
2927         case GNUTLS_KX_SRP_DSS:
2928         case GNUTLS_KX_DHE_PSK:
2929         case GNUTLS_KX_ECDHE_RSA:
2930         case GNUTLS_KX_ECDHE_ECDSA:
2931         case GNUTLS_KX_ECDHE_PSK:
2932         case GNUTLS_KX_ANON_ECDH:       // Assume DHE is in fact implemented
2933         case GNUTLS_KX_ANON_DH:         // Assume DHE is in fact implemented
2934                 valexp_setpredicate (ve, pred, 1);
2935                 break;
2936         // case GNUTLS_KX_xxx_DH:
2937         //      valexp_setpredicate (ve, pred, pred != 'F');
2938         //      break;
2939         }
2940 }
2941
2942 /* valexp_A_start -- validation function for the GnuTLS backend.
2943  * This function ensures that an anonymising precursor is used.
2944  */
2945 #define valexp_A_start valexp_valflag_start
2946
2947 /* valexp_a_start -- is opportunistic and will always succeed */
2948 #define valexp_a_start valexp_1_start
2949
2950 /* valexp_Tt_start -- validation function for the GnuTLS backend.
2951  * This function ensures trust based on a trusted certificate/key list.
2952  * In the _t_ case, self-signed certificates are also accepted.
2953  */
2954 static void valexp_Tt_start (void *vcmd, struct valexp *ve, char pred) {
2955         struct command *cmd = (struct command *) vcmd;
2956         int flagval = 0;
2957         unsigned int vfyresult;
2958         int bad;
2959         int i;
2960         if (cmd->vfystatus != 0) {
2961                 goto setflagval;
2962         }
2963         if (cmd->remote_auth_type != GNUTLS_CRD_CERTIFICATE) {
2964                 goto setflagval;
2965         }
2966         //
2967         // Handle self-signed peer certificates in a special way
2968         if (cmd->remote_cert_count == 1) {
2969                 int bad = 0;
2970                 bad = bad || (pred == 'T');     // Reject self-signed
2971                 if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
2972                         vfyresult = 0;
2973                         bad = bad || gnutls_x509_crt_verify (
2974                                 (gnutls_x509_crt_t   ) cmd->remote_cert [0],
2975                                 (gnutls_x509_crt_t *) &cmd->remote_cert [0], 1,
2976                                 GNUTLS_VERIFY_DISABLE_CA_SIGN,
2977                                 &vfyresult);
2978                         // Apply the most stringent test.  This includes all of
2979                         // GNUTLS_CERT_INVALID (always set, often with others)
2980                         // GNUTLS_CERT_NOT_ACTIVATED
2981                         // GNUTLS_CERT_EXPIRED
2982                         // GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
2983                         // GNUTLS_CERT_SIGNER_NOT_FOUND
2984                         // GNUTLS_CERT_SIGNER_NOT_CA => oops...
2985                         //      stopped with GNUTLS_VERIFY_DISABLE_CA_SIGN
2986                         // GNUTLS_CERT_SIGNATURE_FAILURE
2987                         // GNUTLS_CERT_INSECURE_ALGORITHM
2988                         bad = bad || (vfyresult != 0);
2989                         if (!bad) {
2990                                 flagval = 1;
2991                                 goto setflagval;
2992                         }
2993                 } else if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
2994                         //TODO// Prefer to actually check PGP self-signature
2995                         //TODO// But only value is check private-key ownership
2996                         flagval = 0;
2997                         goto setflagval;
2998 #ifdef GNUTLS_CRT_KRB
2999                 } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3000                         // Kerberos has authenticated the ticket for us
3001                         //TODO// Should we try reading from the ticket/auth?
3002                         flagval = 1;
3003                         goto setflagval;
3004 #endif
3005                 }
3006                 if (bad) {
3007                         goto setflagval;
3008                 }
3009         }
3010         if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3011                 // Now check the certificate chain, taking CA bits into account
3012                 for (i=1; i<cmd->remote_cert_count; i++) {
3013                         vfyresult = 0;
3014                         bad = bad || gnutls_x509_crt_verify (
3015                                 (gnutls_x509_crt_t  )  cmd->remote_cert [i-1],
3016                                 (gnutls_x509_crt_t *) &cmd->remote_cert [i], 1,
3017                                 0,
3018                                 &vfyresult);
3019                         // Apply the most stringent test.  This includes all of
3020                         // GNUTLS_CERT_INVALID (always set, often with others)
3021                         // GNUTLS_CERT_NOT_ACTIVATED
3022                         // GNUTLS_CERT_EXPIRED
3023                         // GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
3024                         // GNUTLS_CERT_SIGNER_NOT_FOUND
3025                         // GNUTLS_CERT_SIGNER_NOT_CA => oops...
3026                         //      stopped with GNUTLS_VERIFY_DISABLE_CA_SIGN
3027                         // GNUTLS_CERT_SIGNATURE_FAILURE
3028                         // GNUTLS_CERT_INSECURE_ALGORITHM
3029                         bad = bad || (vfyresult != 0);
3030                 }
3031         } else if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3032                 ; //TODO// Check PGP direct signature (and also use in self-sig)
3033 #ifdef GNUTLS_CRT_KRB
3034         } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3035                 ; // Trust has already been validated through Kerberos
3036 #endif
3037         }
3038 setflagval:
3039         valexp_setpredicate (ve, pred, flagval);
3040 }
3041
3042 /* valexp_Dd_start -- validation function for the GnuTLS backend.
3043  * This function validates through DNSSEC.
3044  * While _D_ enforces DNSSEC, _d_ also accepts opted-out security.
3045  */
3046 static void valexp_Dd_start (void *vcmd, struct valexp *ve, char pred) {
3047         struct command *cmd = (struct command *) vcmd;
3048         int flagval = 0;
3049         dane_state_t stat;
3050         unsigned int vfystat;
3051         char *host;
3052         char *proto;
3053         int sox;
3054         struct sockaddr peername;
3055         socklen_t peernamesz = sizeof (peername);
3056         uint16_t port;
3057         host = strchr (cmd->cmd.pio_data.pioc_starttls.remoteid, '@');
3058         if (host == NULL) {
3059                 host = cmd->cmd.pio_data.pioc_starttls.remoteid;
3060         }
3061         switch (cmd->cmd.pio_data.pioc_starttls.ipproto) {
3062         case IPPROTO_TCP:
3063                 proto = "tcp";
3064                 break;
3065         case IPPROTO_UDP:
3066                 proto = "udp";
3067                 break;
3068 #ifndef WINDOWS_PORT
3069         case IPPROTO_SCTP:
3070                 proto = "sctp";
3071                 break;
3072 #endif
3073         default:
3074                 goto setflagval;
3075         }
3076         sox = gnutls_transport_get_int (cmd->session);
3077         if (sox < 0) {
3078                 goto setflagval;
3079         }
3080         if (getpeername (sox, &peername, &peernamesz) != 0) {
3081                 goto setflagval;
3082         }
3083         if ((peername.sa_family == AF_INET) &&
3084                                 (peernamesz == sizeof (struct sockaddr_in))) {
3085                 port = ntohs (((struct sockaddr_in *) &peername)->sin_port);
3086         } else if ((peername.sa_family == AF_INET6) &&
3087                                 (peernamesz == sizeof (struct sockaddr_in6))) {
3088         } else {
3089                 port = ntohs (((struct sockaddr_in6 *) &peername)->sin6_port);
3090                 goto setflagval;
3091         }
3092         //TODO// We might use online.c code instead?
3093         if (dane_state_init (&stat, /*TODO:*/ 0) != GNUTLS_E_SUCCESS) {
3094                 goto setflagval;
3095         }
3096         if (dane_verify_session_crt (stat,
3097                                 cmd->session,
3098                                 host,
3099                                 proto,
3100                                 port,
3101                                 0,
3102                                 DANE_VFLAG_FAIL_IF_NOT_CHECKED,
3103                                 &vfystat) == DANE_E_SUCCESS) {
3104                 if ((pred == 'D') && (vfystat & DANE_VERIFY_UNKNOWN_DANE_INFO)) {
3105                         dane_state_deinit (stat);
3106                         goto setflagval;
3107                 }
3108                 flagval = ((vfystat & ~DANE_VERIFY_UNKNOWN_DANE_INFO) == 0);
3109         }
3110         dane_state_deinit (stat);
3111 setflagval:
3112         valexp_setpredicate (ve, pred, flagval);
3113 }
3114
3115 /* valexp_Rr_start -- validation function for the GnuTLS backend.
3116  * This function validates through a CRL.
3117  * While _R_ requires the CRL to be present, _r_ accepts confirmed absense.
3118  * TODO: This is not implemented yet.
3119  */
3120 static void valexp_Rr_start (void *vcmd, struct valexp *ve, char pred) {
3121         //TODO//;
3122         valexp_setpredicate (ve, pred, 0);
3123 }
3124
3125 /* valexp_Ee_start -- validation function for the GnuTLS backend.
3126  * This function validates certificate extensions for the named service.
3127  * While _E_ required OIDs to be marked critical, _e_ also accepts non-crit.
3128  */
3129 static void valexp_Ee_start (void *vcmd, struct valexp *ve, char pred) {
3130         //TODO//;
3131         valexp_setpredicate (ve, pred, 0);
3132 }
3133
3134 /* valexp_Oo_start -- validation function for the GnuTLS backend.
3135  * This function validates with online/live information.
3136  * While _O_ required positive confirmation, _o_ also accepts unknown.
3137  *  -> For X.509,    look in OCSP or CRL or Global Directory
3138  *  -> For OpenPGP,  redirect O->G, o->g
3139  *  -> For Kerberos, accept anything as sufficiently live / online
3140  */
3141 static void valexp_Oo_start (void *vcmd, struct valexp *ve, char pred) {
3142         struct command *cmd = (struct command *) vcmd;
3143         int valflag = 0;
3144         online2success_t o2vf;
3145         char *rid;
3146         gnutls_datum_t *raw;
3147         if (cmd->remote_auth_type != GNUTLS_CRD_CERTIFICATE) {
3148                 // No authentication types other than certificates yet
3149                 goto setvalflag;
3150         } else {
3151                 if ((pred >= 'a') && (pred <= 'z')) {
3152                         o2vf = online2success_optional;
3153                 } else {
3154                         o2vf = online2success_enforced;
3155                 }
3156                 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
3157                 raw = (gnutls_datum_t *) cmd->remote_cert_raw;
3158                 if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3159                         valflag = o2vf (online_globaldir_pgp (
3160                                         rid,
3161                                         raw->data, raw->size));
3162                 } else if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3163                         // OCSP inquiry or globaldir
3164                         valflag = o2vf (online_globaldir_x509 (
3165                                         rid,
3166                                         raw->data, raw->size));
3167 #ifdef HAVE_TLS_KDH
3168                 } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3169                         // Kerberos is sufficiently "live" to be pass O
3170                         valflag = 1;
3171                         goto setvalflag;
3172 #endif
3173                 } else {
3174                         // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
3175                         goto setvalflag;
3176                 }
3177         }
3178 setvalflag:
3179         valexp_setpredicate (ve, pred, valflag);
3180 }
3181
3182 /* valexp_Gg_start -- validation function for the GnuTLS backend.
3183  * This function validates through the LDAP global directory.
3184  * While _G_ requires information to be present, _g_ also accepts absense.
3185  *  -> For X.509,   lookup userCertificate
3186  *  -> For OpenPGP, lookup pgpKey
3187  *  -> For KDH,     lookup krbPrincipalName
3188  *  -> For SRP,     nothing is defined
3189  *  -> For OpenSSH, no TLS support
3190  */
3191 static void valexp_Gg_start (void *vcmd, struct valexp *ve, char pred) {
3192         struct command *cmd = (struct command *) vcmd;
3193         int valflag = 0;
3194         online2success_t o2vf;
3195         char *rid;
3196         gnutls_datum_t *raw;
3197         if (cmd->remote_auth_type != GNUTLS_CRD_CERTIFICATE) {
3198                 // No authentication types other than certificates yet
3199                 goto setvalflag;
3200         } else {
3201                 if ((pred >= 'a') && (pred <= 'z')) {
3202                         o2vf = online2success_optional;
3203                 } else {
3204                         o2vf = online2success_enforced;
3205                 }
3206                 rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
3207                 raw = (gnutls_datum_t *) cmd->remote_cert_raw;
3208                 if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3209                         valflag = o2vf (online_globaldir_pgp (
3210                                         rid,
3211                                         raw->data, raw->size));
3212                 } else if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3213                         //TODO// OCSP inquiry or globaldir
3214                         valflag = o2vf (online_globaldir_x509 (
3215                                         rid,
3216                                         raw->data, raw->size));
3217 #ifdef GNUTLS_CRT_KRB
3218                 } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3219                         valflag = 0;
3220                         //TODO// valflag = o2vf (online_globaldir_kerberos (
3221                         //TODO//                rid,
3222                         //TODO//                raw->data, raw->size));
3223 #endif
3224                 } else {
3225                         // GNUTLS_CRT_RAW, GNUTLS_CRT_UNKNOWN, or other
3226                         goto setvalflag;
3227                 }
3228         }
3229 setvalflag:
3230         valexp_setpredicate (ve, pred, valflag);
3231 }
3232
3233 /* valexp_Pp_start -- validation function for the GnuTLS backend.
3234  * This function validates through pinning information.
3235  * While _P_ requires pinning to be present, _p_ will Trust On First Use.
3236  */
3237 static void valexp_Pp_start (void *vcmd, struct valexp *ve, char pred) {
3238         //TODO//;
3239         valexp_setpredicate (ve, pred, 0);
3240 }
3241
3242 /* valexp_U_start -- validation function for the GnuTLS backend.
3243  * This function validates a matching username.
3244  */
3245 static void valexp_U_start (void *vcmd, struct valexp *ve, char pred) {
3246         //TODO//;
3247         valexp_setpredicate (ve, pred, 0);
3248 }
3249
3250 /* valexp_Ss_start -- validation function for the GnuTLS backend.
3251  * This function ensures that the local end is a server.
3252  * While _S_ denies credentials also usable for clients, _s_ permits them.
3253  */
3254 static void valexp_Ss_start (void *vcmd, struct valexp *ve, char pred) {
3255         struct command *cmd = (struct command *) vcmd;
3256         int flagval;
3257         if ((pred == 'S') && (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)) {
3258                 flagval = 0;
3259         } else {
3260                 flagval = (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) != 0;
3261         }
3262         valexp_setpredicate (ve, pred, flagval);
3263 }
3264
3265 /* valexp_Cc_start -- validation function for the GnuTLS backend.
3266  * This function ensures that the local end is a client.
3267  * While _C_ denies credentials also usable for servers, _c_ permits them.
3268  */
3269 static void valexp_Cc_start (void *vcmd, struct valexp *ve, char pred) {
3270         struct command *cmd = (struct command *) vcmd;
3271         int flagval;
3272         if ((pred == 'C') && (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER)) {
3273                 flagval = 0;
3274         } else {
3275                 flagval = (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) != 0;
3276         }
3277         valexp_setpredicate (ve, pred, flagval);
3278 }
3279
3280
3281 static void valexp_error_start (void *handler_data, struct valexp *ve, char pred) {
3282         assert (0);
3283 }
3284 static void valexp_ignore_stop (void *handler_data, struct valexp *ve, char pred) {
3285         ; // Nothing to do
3286 }
3287 static void valexp_ignore_final (void *handler_data, struct valexp *ve, bool value) {
3288         ; // Nothing to do
3289 }
3290
3291
3292 /* Given a predicate, invoke its start routine.
3293  */
3294 static void valexp_switch_start (void *handler_data, struct valexp *ve, char pred) {
3295         switch (pred) {
3296         case 'I':
3297                 valexp_I_start (handler_data, ve, pred);
3298                 break;
3299         case 'i':
3300                 valexp_i_start (handler_data, ve, pred);
3301                 break;
3302         case 'F':
3303         case 'f':
3304                 valexp_Ff_start (handler_data, ve, pred);
3305                 break;
3306         case 'A':
3307                 valexp_A_start (handler_data, ve, pred);
3308                 break;
3309         case 'a':
3310                 valexp_a_start (handler_data, ve, pred);
3311                 break;
3312         case 'T':
3313         case 't':
3314                 valexp_Tt_start (handler_data, ve, pred);
3315                 break;
3316         case 'D':
3317         case 'd':
3318                 valexp_Dd_start (handler_data, ve, pred);
3319                 break;
3320         case 'R':
3321         case 'r':
3322                 valexp_Rr_start (handler_data, ve, pred);
3323                 break;
3324         case 'E':
3325         case 'e':
3326                 valexp_Ee_start (handler_data, ve, pred);
3327                 break;
3328         case 'O':
3329         case 'o':
3330                 valexp_Oo_start (handler_data, ve, pred);
3331                 break;
3332         case 'G':
3333         case 'g':
3334                 valexp_Gg_start (handler_data, ve, pred);
3335                 break;
3336         case 'P':
3337         case 'p':
3338                 valexp_Pp_start (handler_data, ve, pred);
3339                 break;
3340         case 'U':
3341                 valexp_U_start (handler_data, ve, pred);
3342                 break;
3343         case 'S':
3344         case 's':
3345                 valexp_Ss_start (handler_data, ve, pred);
3346                 break;
3347         case 'C':
3348         case 'c':
3349                 valexp_Cc_start (handler_data, ve, pred);
3350                 break;
3351         default:
3352                 // Called on an unregistered symbol, that spells failure
3353                 valexp_setpredicate (ve, pred, 0);
3354                 break;
3355         }
3356 }
3357
3358 /* Return a shared constant structure for valexp_handling with GnuTLS.
3359  * This function does not fail; it always returns a non-NULL value.
3360  */
3361 static const struct valexp_handling *have_starttls_validation (void) {
3362         static const struct valexp_handling starttls_valexp_handling = {
3363                 .handler_start = valexp_switch_start,
3364                 .handler_stop  = valexp_ignore_stop,
3365                 .handler_final = valexp_store_final,
3366         };
3367         return &starttls_valexp_handling;
3368 }
3369
3370
3371
3372 /* If any remote credentials are noted, cleanup on them.  This removes
3373  * any remote_cert[...] entries, counting up to remote_cert_count which
3374  * is naturally set to 0 initially, as well as after this has run.
3375  */
3376 static void cleanup_any_remote_credentials (struct command *cmd) {
3377         while (cmd->remote_cert_count > 0) {
3378                 gnutls_x509_crt_deinit (
3379                         cmd->remote_cert [--cmd->remote_cert_count]);
3380         }
3381         memset (cmd->remote_cert, 0, sizeof (cmd->remote_cert));
3382 }
3383
3384 /* Fetch remote credentials.  This can be done after TLS handshaking has
3385  * completed, to find the certificates or other credentials provided by
3386  * the peer to establish its identity.  The validation expression routines
3387  * can then refer to this resource, and won't have to request the same
3388  * information over and over again.  To this end, the information is stored
3389  * in the session object.  The arrays in which this information is stored
3390  * are size-constrained, but that is also a good security precaution.
3391  *
3392  * The information ends up in the following variables:
3393  *  - remote_auth_type
3394  *  - remote_cert_type (if remote_auth_type == GNUTLS_CRD_CERTIFICATE)
3395  *  - remote_cert[...] (if remote_cert_type == GNUTLS_CRD_CERTIFICATE)
3396  *  - remote_cert_count is the number of entries in remote_cert (up to root)
3397  *
3398  * When certificates are used, the root certificate is looked up, for
3399  * X.509 and PGP.
3400  *
3401  * After running successfully, a call to cleanup_any_remote_credentials()
3402  * must be called to clean up any data in the cmd structure.  This may be
3403  * done on cmd at any time after initialisation, even multiple times and
3404  * even when this call fails.  This call actually cleans up anything it
3405  * setup in the past, before setting up the data anew.
3406  */
3407 static gtls_error fetch_remote_credentials (struct command *cmd) {
3408         gtls_error gtls_errno = GNUTLS_E_SUCCESS;
3409         const gnutls_datum_t *certs;
3410         unsigned int num_certs;
3411         gnutls_x509_crt_t x509peers [11]; // Peers + Root for GNUTLS_CRT_X509
3412         int i;
3413         bool got_chain = 0;
3414         int peer_tad = -1;
3415
3416         // Did we run this before?  Then cleanup.
3417         cleanup_any_remote_credentials (cmd);
3418         //INVOLVES// memset (cmd->remote_cert, 0, sizeof (cmd->remote_cert));
3419         //INVOLVES// cmd->remote_cert_count = 0;
3420         // Prepare as-yet-unset default return values
3421         cmd->remote_auth_type = -1;
3422         cmd->remote_cert_raw = NULL;
3423         //
3424         // Obtain the authentication type for the peer
3425         cmd->remote_auth_type = gnutls_auth_get_type (cmd->session);
3426         switch (cmd->remote_auth_type) {
3427         case GNUTLS_CRD_CERTIFICATE:
3428                 // Continue loading certificates in the GnuTLS format
3429                 break;
3430         case GNUTLS_CRD_ANON:
3431                 // No basis for any identity claim
3432                 cmd->cmd.pio_data.pioc_starttls.remoteid [0] = '\0';
3433                 return GNUTLS_E_SUCCESS;
3434         case GNUTLS_CRD_SRP:
3435                 return GNUTLS_E_SUCCESS;
3436         case GNUTLS_CRD_PSK:
3437                 return GNUTLS_E_SUCCESS;
3438         default:
3439                 return GNUTLS_E_AUTH_ERROR;
3440         }
3441         //
3442         // Continue loading the certificate information: X.509, PGP, ...
3443 #ifdef HAVE_TLS_KDH
3444         cmd->remote_cert_type = gnutls_certificate_type_get_peers (cmd->session);
3445         certs = gnutls_certificate_get_peers (cmd->session, &num_certs);
3446         // Note: server's certs _may_ be DER NULL due to mutual auth in Kerberos
3447 #else
3448         cmd->remote_cert_type = gnutls_certificate_type_get (cmd->session);
3449         certs = gnutls_certificate_get_peers (cmd->session, &num_certs);
3450 #endif
3451         if (certs == NULL) {
3452                 num_certs = 0;
3453         }
3454         // "certs" points into GnuTLS' internal data structures
3455         if ((num_certs < 1) || (num_certs > CERTS_MAX_DEPTH)) {
3456                 return GNUTLS_E_AUTH_ERROR;
3457         }
3458         cmd->remote_cert_raw = (void *) &certs [0];
3459         //
3460         // Turn certificate data into GnuTLS' data structures (to be cleaned)
3461         if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3462                 peer_tad = TAD_TYPE_X509;
3463                 for (i=0; i < num_certs; i++) {
3464                         E_g2e ("Failed to initialise peer X.509 certificate",
3465                                 gnutls_x509_crt_init (
3466                                         (gnutls_x509_crt_t *) &cmd->remote_cert [i]));
3467                         if (gtls_errno == GNUTLS_E_SUCCESS) {
3468                                 cmd->remote_cert_count++;
3469                         }
3470                         E_g2e ("Failed to import peer X.509 certificate",
3471                                 gnutls_x509_crt_import (
3472                                         cmd->remote_cert [i],
3473                                         &certs [i], GNUTLS_X509_FMT_DER));
3474                 }
3475                 if (gtls_errno != GNUTLS_E_SUCCESS) {
3476                         goto cleanup;
3477                 }
3478         } else if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3479                 peer_tad = TAD_TYPE_PGP;
3480                 E_g2e ("Failed to initialise peer PGP key",
3481                                 gnutls_x509_crt_init (
3482                                         (gnutls_x509_crt_t *) &cmd->remote_cert [0]));
3483                 if (gtls_errno == GNUTLS_E_SUCCESS) {
3484                         cmd->remote_cert_count = 1;
3485                 }
3486                 E_g2e ("Failed to import peer PGP key",
3487                                 gnutls_openpgp_crt_import (
3488                                         cmd->remote_cert [0],
3489                                         &certs [0], GNUTLS_OPENPGP_FMT_RAW));
3490                 if (gtls_errno != GNUTLS_E_SUCCESS) {
3491                         goto cleanup;
3492                 }
3493         }
3494
3495         //
3496         // Lookup the trusted party that the peers certificates is promoting.
3497         // Note that even if the peer ends in a CA cert (which it may not
3498         // always send along) then we can still add it ourselves again :-)
3499         // Only worry might be that CA certs require no AuthorityKeyIdentifier.
3500         if (cmd->remote_cert_type == GNUTLS_CRT_X509) {
3501                 // Retrieve the AuthorityKeyIdentifier from last (or semi-last)
3502                 uint8_t id [100];
3503                 size_t idsz;
3504                 DBT rootca;
3505                 DBT anchor;
3506                 DBC *crs_trust = NULL;
3507                 int db_errno;
3508                 gnutls_datum_t anchor_gnutls;
3509                 gnutls_x509_crt_t dbroot;
3510                 dbt_init_empty (&rootca);
3511                 dbt_init_empty (&anchor);
3512                 idsz = sizeof (id);
3513                 gtls_errno = gnutls_x509_crt_get_authority_key_id (
3514                         cmd->remote_cert [cmd->remote_cert_count-1],
3515                         id, &idsz,
3516                         NULL);
3517                 if (gtls_errno == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
3518                         // Only retry if the last is a signer, possibly CA
3519                         if (cmd->remote_cert_count == 1) {
3520                                 // Permit self-signed certificate evaluation
3521                                 gtls_errno = GNUTLS_E_SUCCESS;
3522                         } else if (cmd->remote_cert_count > 1) {
3523                                 // Assume the last is a root cert, as it lacks authid
3524                                 gnutls_x509_crt_deinit (
3525                                         cmd->remote_cert [--cmd->remote_cert_count]);
3526                                 cmd->remote_cert [cmd->remote_cert_count] = NULL;
3527                                 idsz = sizeof (id);
3528                                 gtls_errno = gnutls_x509_crt_get_authority_key_id (
3529                                         cmd->remote_cert [cmd->remote_cert_count-1],
3530                                         id, &idsz,
3531                                         NULL);
3532                         }
3533                 }
3534                 if (gtls_errno != GNUTLS_E_SUCCESS) {
3535                         goto cleanup;
3536                 }
3537                 // Get root cert from trustdb into remote_cert [_count++]
3538                 dbt_init_fixbuf (&rootca, id, idsz);
3539                 dbt_init_malloc (&anchor);
3540                 E_d2e ("Failed to create db_disclose cursor",
3541                         dbh_trust->cursor (
3542                                 dbh_trust,
3543                                 cmd->txn,
3544                                 &crs_trust,
3545                                 0));
3546                 E_d2e ("X.509 authority key identifier not found in trust database",
3547                         dba_trust_iterate (
3548                                 crs_trust, &rootca, &anchor));
3549                 while (db_errno == 0) {
3550                         // Process "anchor" entry (inasfar as meaningful)
3551                         uint32_t anchorflags;
3552                         uint8_t *trustdata;
3553                         int trustdatalen;
3554                         char *valexp;   //TODO// Initiate this before cleanup
3555                         int tstatus = trust_interpret (&anchor, &anchorflags, &valexp, &trustdata, &trustdatalen);
3556                         dbt_free (&anchor);
3557                         if (tstatus != TAD_STATUS_SUCCESS) {
3558                                 // Signal any DB error to bail out of this loop
3559                                 db_errno = DB_KEYEMPTY;
3560                         } else if ((anchorflags & TAD_TYPE_MASK) != peer_tad) {
3561                                 ;       // Skip unsought trust database entry
3562                         } else if ((anchorflags & TAD_TYPE_MASK) == TAD_TYPE_X509) {
3563                                 E_g2e ("Certificate chain too long",
3564                                         (cmd->remote_cert_count >= CERTS_MAX_DEPTH)
3565                                         ? GNUTLS_E_AUTH_ERROR
3566                                         : GNUTLS_E_SUCCESS);
3567                                 // Turn the anchor into an X.509 certificate
3568                                 E_g2e ("Failet to initialise X.509 peer trust anchor",
3569                                         gnutls_x509_crt_init ((gnutls_x509_crt_t *) &cmd->remote_cert [cmd->remote_cert_count]));
3570                                 if (gtls_errno == GNUTLS_E_SUCCESS) {
3571                                         cmd->remote_cert_count++;
3572                                         anchor_gnutls.data = anchor.data;
3573                                         anchor_gnutls.size = anchor.size;
3574                                         E_g2e ("Failed to import X.509 peer trust anchor",
3575                                                 gnutls_x509_crt_import (cmd->remote_cert [cmd->remote_cert_count-1], &anchor_gnutls, GNUTLS_X509_FMT_DER));
3576                                 }
3577                                 if (gtls_errno == GNUTLS_E_SUCCESS) {
3578                                         // Everything worked, we have a chain
3579                                         got_chain = 1;
3580                                         if (cmd->trust_valexp) {
3581                                                 free (cmd->trust_valexp);
3582                                         }
3583                                         cmd->trust_valexp = strdup (valexp);
3584                                 } else {
3585                                         // Signal arbitrary DB error
3586                                         db_errno = DB_KEYEMPTY;
3587                                 }
3588                         } else if ((anchorflags & TAD_TYPE_MASK) == TAD_TYPE_REVOKE_X509) {
3589                                 //TODO// Possibly verify end cert revocation
3590                         } else {
3591                                 /* Ignore entry, continue with the next */;
3592                         }
3593                         db_errno = dba_trust_iterate (crs_trust, &rootca, &anchor);
3594                 }
3595                 if (crs_trust != NULL) {
3596                         crs_trust->close (crs_trust);
3597                         crs_trust = NULL;
3598                 }
3599                 dbt_free (&anchor);
3600                 // No dbt_free (&rootca) because it is set to a fixed buffer
3601                 if (db_errno != DB_NOTFOUND) {
3602                         goto cleanup;
3603                 }
3604         } else if (cmd->remote_cert_type == GNUTLS_CRT_OPENPGP) {
3605                 ; //TODO// Attempt to load PGP direct signer(s)
3606                 ; //OPTION// May use the _count for alternative signers!
3607                 ; //OPTION// May setup/reload a keyring based on trust.db
3608 #ifdef GNUTLS_CRT_KRB
3609         } else if (cmd->remote_cert_type == GNUTLS_CRT_KRB) {
3610                 ; //TODO// Process as appropriate for Kerberos (store Ticket?)
3611 #endif
3612         }
3613         //
3614         // Cleanup (when returning an error code) and return
3615 cleanup:
3616         if (gtls_errno != GNUTLS_E_SUCCESS) {
3617                 cleanup_any_remote_credentials (cmd);
3618         }
3619         while ((!got_chain) && (cmd->remote_cert_count > 1)) {
3620                 --cmd->remote_cert_count;
3621                 gnutls_x509_crt_deinit (
3622                         cmd->remote_cert [cmd->remote_cert_count]);
3623                 cmd->remote_cert [cmd->remote_cert_count] = NULL;
3624         }
3625         return gtls_errno;
3626 }
3627
3628
3629 /* Fetch local credentials.  This can be done before TLS is started, to find
3630  * the possible authentication forms that can be offered.  The function
3631  * can additionally be used after interaction with the client to establish
3632  * a local identity that was not initially provided, or that was not
3633  * considered public at the time.
3634  */
3635 gtls_error fetch_local_credentials (struct command *cmd) {
3636         int lidrole;
3637         char *lid, *rid;
3638         DBC *crs_disclose = NULL;
3639         DBC *crs_localid = NULL;
3640         DBT discpatn;
3641         DBT keydata;
3642         DBT creddata;
3643         selector_t remote_selector;
3644         int gtls_errno = 0;
3645         int db_errno = 0;
3646         int found = 0;
3647         gtls_error certificate_onthefly (struct command *cmd);
3648
3649         //
3650         // When applicable, try to create an on-the-fly certificate
3651         if (((cmd->cmd.pio_cmd == PIOC_STARTTLS_V2) &&
3652                         (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALID_ONTHEFLY))
3653         || ((cmd->cmd.pio_cmd == PIOC_LIDENTRY_CALLBACK_V2) &&
3654                         (cmd->cmd.pio_data.pioc_lidentry.flags & PIOF_LIDENTRY_ONTHEFLY))) {
3655                 gtls_errno = certificate_onthefly (cmd);
3656                 if (gtls_errno != GNUTLS_E_AGAIN) {
3657                         // This includes GNUTLS_E_SUCCESS
3658 fprintf (stderr, "DEBUG: otfcert retrieval returned %d\n", gtls_errno);
3659                         return gtls_errno;
3660                 } else {
3661 fprintf (stderr, "DEBUG: otfcert retrieval returned GNUTLS_E_AGAIN, so skip it\n");
3662                         gtls_errno = GNUTLS_E_SUCCESS;  // Attempt failed, ignore
3663                 }
3664         }
3665
3666         //
3667         // Setup a number of common references and structures
3668         // Note: Current GnuTLS cannot support being a peer
3669         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
3670                 lidrole = LID_ROLE_CLIENT;
3671         } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
3672                 lidrole = LID_ROLE_SERVER;
3673         } else {
3674                 E_g2e ("TLS Pool command supports neither local client nor local server role",
3675                         GNUTLS_E_INVALID_SESSION);
3676                 return gtls_errno;
3677         }
3678         lid = cmd->cmd.pio_data.pioc_starttls.localid;
3679         rid = cmd->cmd.pio_data.pioc_starttls.remoteid;
3680
3681         //
3682         // Refuse to disclose client credentials when the server name is unset;
3683         // note that server-claimed identities are unproven during handshake.
3684         if ((lidrole == LID_ROLE_CLIENT) && (*rid == '\0')) {
3685                 tlog (TLOG_USER, LOG_ERR, "No remote identity (server name) set, so no client credential disclosure");
3686                 E_g2e ("Missing remote ID",
3687                         GNUTLS_E_NO_CERTIFICATE_FOUND);
3688                 return gtls_errno;
3689         }
3690         //
3691         // Setup database iterators to map identities to credentials
3692         if (lidrole == LID_ROLE_CLIENT) {
3693                 E_d2e ("Failed to create db_disclose cursor",
3694                         dbh_disclose->cursor (
3695                                 dbh_disclose,
3696                                 cmd->txn,
3697                                 &crs_disclose,
3698                                 0));
3699         }
3700         E_d2e ("Failed to create db_localid cursor",
3701                 dbh_localid->cursor (
3702                         dbh_localid,
3703                         cmd->txn,
3704                         &crs_localid,
3705                         0));
3706         //
3707         // Prepare for iteration over possible local identities / credentials
3708         char mid [128];
3709         char cid [128];
3710         if (gtls_errno != 0) {
3711                 ; // Skip setup
3712         } else if (lidrole == LID_ROLE_CLIENT) {
3713                 memcpy (cid, rid, sizeof (cid));
3714                 dbt_init_fixbuf (&discpatn, cid, strlen (cid));
3715                 dbt_init_fixbuf (&keydata,  mid, sizeof (mid)-1);
3716                 dbt_init_malloc (&creddata);
3717                 selector_t ridsel;
3718                 donai_t remote_donai = donai_from_stable_string (rid, strlen (rid));
3719                 if (!selector_iterate_init (&remote_selector, &remote_donai)) {
3720                         E_g2e ("Syntax of remote ID unsuitable for selector",
3721                                 GNUTLS_E_INVALID_REQUEST);
3722                 } else {
3723                         E_d2e ("Failed to start iterator on remote ID selector",
3724                                 dbcred_iterate_from_remoteid_selector (
3725                                         crs_disclose,
3726                                         crs_localid,
3727                                         &remote_selector,
3728                                         &discpatn,
3729                                         &keydata,
3730                                         &creddata));
3731                 }
3732         } else {
3733                 dbt_init_fixbuf (&discpatn, "", 0);     // Unused but good style
3734                 dbt_init_fixbuf (&keydata,  lid, strlen (lid));
3735                 dbt_init_malloc (&creddata);
3736                 E_d2e ("Failed to start iterator on local ID",
3737                         dbcred_iterate_from_localid (
3738                         crs_localid,
3739                         &keydata,
3740                         &creddata));
3741         }
3742         if (db_errno != 0) {
3743                 gtls_errno = GNUTLS_E_DB_ERROR;
3744         }
3745
3746         //
3747         // Now store the local identities inasfar as they are usable
3748         db_errno = 0;
3749         while ((gtls_errno == GNUTLS_E_SUCCESS) && (db_errno == 0)) {
3750                 int ok;
3751                 uint32_t flags;
3752                 int lidtype;
3753
3754                 tlog (TLOG_DB, LOG_DEBUG, "Found BDB entry %s disclosed to %s", creddata.data + 4, (lidrole == LID_ROLE_CLIENT)? rid: "all clients");
3755                 ok = dbcred_flags (
3756                         &creddata,
3757                         &flags);
3758                 lidtype = flags & LID_TYPE_MASK;
3759                 ok = ok && ((flags & lidrole) != 0);
3760                 ok = ok && ((flags & LID_NO_PKCS11) == 0);
3761                 ok = ok && (lidtype >= LID_TYPE_MIN);
3762                 ok = ok && (lidtype <= LID_TYPE_MAX);
3763 #ifdef HAVE_TLS_KDH
3764                 // For current/simple Kerberos, refuse data after PKCS #11 URI
3765                 ok = ok && ((lidtype != LID_TYPE_KRB5) || (NULL == memchr (creddata.data + 4, '\0', creddata.size - 4 - 1)));
3766 #endif
3767                 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 ");
3768                 if (ok) {
3769                         if (cmd->lids [lidtype - LID_TYPE_MIN].data != NULL) {
3770                                 free (cmd->lids [lidtype - LID_TYPE_MIN].data);
3771                         }
3772                         // Move the credential into the command structure
3773                         dbt_store (&creddata,
3774                                 &cmd->lids [lidtype - LID_TYPE_MIN]);
3775 fprintf (stderr, "DEBUG: Storing cmd->lids[%d].data %p\n", lidtype-LID_TYPE_MIN, cmd->lids [lidtype-LID_TYPE_MIN].data);
3776                         found = 1;
3777                 } else {
3778                         // Skip the credential by freeing its data structure
3779                         dbt_free (&creddata);
3780                 }
3781                 db_errno = dbcred_iterate_next (crs_disclose, crs_localid, &discpatn, &keydata, &creddata);
3782         }
3783
3784         if (db_errno == DB_NOTFOUND) {
3785                 if (!found) {
3786                         gtls_errno = GNUTLS_E_NO_CERTIFICATE_FOUND;
3787                 }
3788         }
3789         if (crs_localid != NULL) {
3790                 crs_localid->close (crs_localid);
3791                 crs_localid = NULL;
3792         }
3793         if (crs_disclose != NULL) {
3794                 crs_disclose->close (crs_disclose);
3795                 crs_disclose = NULL;
3796         }
3797         return gtls_errno;
3798 }
3799
3800
3801 /*
3802  * Check if a given cmd has the given LID_TYPE setup.
3803  * Return 1 for yes or 0 for no; this is used in priority strings.
3804  */
3805 static inline int lidtpsup (struct command *cmd, int lidtp) {
3806         return cmd->lids [lidtp - LID_TYPE_MIN].data != NULL;
3807 }
3808
3809 /* Configure the GnuTLS session with suitable credentials and priority string.
3810  * The anonpre_ok flag should be non-zero to permit Anonymous Precursor.
3811  *
3812  * The credential setup is optional; when creds is NULL, no changes will
3813  * be made.
3814  */
3815 static int configure_session (struct command *cmd,
3816                         gnutls_session_t session,
3817                         struct credinfo *creds,
3818                         int credcount,
3819                         int anonpre_ok) {
3820         int i;
3821         int gtls_errno = GNUTLS_E_SUCCESS;
3822         //
3823         // Install the shared credentials for the client or server role
3824         if (creds != NULL) {
3825                 gnutls_credentials_clear (session);
3826                 for (i=0; i<credcount; i++) {
3827                         E_g2e ("Failed to install credentials into TLS session",
3828                                 gnutls_credentials_set (
3829                                         session,
3830                                         creds [i].credtp,
3831                                         creds [i].cred  ));
3832                 }
3833         }
3834         //
3835         // Setup the priority string for this session; this avoids future
3836         // credential callbacks that ask for something impossible or
3837         // undesired.
3838         //
3839         // Variation factors:
3840         //  - starting configuration (can it be empty?)
3841         //  - Configured security parameters (database? variable?)
3842         //  - CTYPEs, SRP, ANON-or-not --> fill in as + or - characters
3843         if (gtls_errno == GNUTLS_E_SUCCESS) {
3844                 char priostr [512];
3845 #ifdef HAVE_TLS_KDH
3846                 snprintf (priostr, sizeof (priostr)-1,
3847                         // "NORMAL:-RSA:" -- also ECDH-RSA, ECDHE-RSA, ...DSA...
3848                         "NONE:"
3849                         "%%ASYM_CERT_TYPES:"
3850                         "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
3851                         "+COMP-NULL:"
3852                         "+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
3853                         "%cANON-ECDH:"
3854                         "+ECDHE-KRB:" // +ECDHE-KRB-RSA:+ECDHE-KRB-ECDHE:" // opt?
3855                         "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:" //TODO//
3856                         "+CTYPE-SRV-KRB:+CTYPE-SRV-X.509:+CTYPE-SRV-OPENPGP:"
3857                         "%cCTYPE-CLI-KRB:"
3858                         "%cCTYPE-CLI-X.509:"
3859                         "%cCTYPE-CLI-OPENPGP:"
3860                         "%cSRP:%cSRP-RSA:%cSRP-DSS",
3861                         anonpre_ok                              ?'+':'-',
3862                         1 /* lidtpsup (cmd, LID_TYPE_KRB5)*/            ?'+':'-',
3863                         1 /*lidtpsup (cmd, LID_TYPE_X509)*/             ?'+':'-',
3864                         1 /*lidtpsup (cmd, LID_TYPE_PGP)*/              ?'+':'-',
3865                         //TODO// Temporarily patched out SRP
3866                         lidtpsup (cmd, LID_TYPE_SRP)            ?'+':'-',
3867                         lidtpsup (cmd, LID_TYPE_SRP)            ?'+':'-',
3868                         lidtpsup (cmd, LID_TYPE_SRP)            ?'+':'-');
3869 #else
3870                 // It's not possible to make good decisions on certificate type
3871                 // for both sides based on knowledge of local authentication
3872                 // abilities.  So we permit all (but would like to be subtler).
3873                 snprintf (priostr, sizeof (priostr)-1,
3874                         // "NORMAL:-RSA:" -- also ECDH-RSA, ECDHE-RSA, ...DSA...
3875                         "NONE:"
3876                         "+VERS-TLS-ALL:+VERS-DTLS-ALL:"
3877                         "+COMP-NULL:"
3878                         "+CIPHER-ALL:+CURVE-ALL:+SIGN-ALL:+MAC-ALL:"
3879                         "%cANON-ECDH:"
3880                         "+ECDHE-RSA:+DHE-RSA:+ECDHE-ECDSA:+DHE-DSS:+RSA:" //TODO//
3881                         "%cCTYPE-X.509:"
3882                         "%cCTYPE-OPENPGP:"
3883                         "%cSRP:%cSRP-RSA:%cSRP-DSS",
3884                         anonpre_ok                              ?'+':'-',
3885                         1               ?'+':'-',
3886                         1               ?'+':'-',
3887                         //TODO// Temporarily patched out SRP
3888                         1               ?'+':'-',
3889                         1               ?'+':'-',
3890                         1               ?'+':'-');
3891 #endif
3892                 tlog (TLOG_TLS, LOG_DEBUG, "Constructed priority string %s for local ID %s",
3893                         priostr, cmd->cmd.pio_data.pioc_starttls.localid);
3894                 E_g2e ("Failed to set GnuTLS priority string",
3895                         gnutls_priority_set_direct (
3896                         session,
3897                         priostr,
3898                         NULL));
3899         }
3900         //
3901         // Return the application GNUTLS_E_ code including _SUCCESS
3902         return gtls_errno;
3903 }
3904
3905 /* The callback functions retrieve various bits of information for the client
3906  * or server in the course of the handshake procedure.
3907  *
3908  * The logic here is based on client-sent information, such as:
3909  *  - TLS hints -- X.509 or alternatives like OpenPGP, SRP, PSK
3910  *  - TLS hints -- Server Name Indication
3911  *  - User hints -- local and remote identities provided
3912  */
3913 static int srv_clienthello (gnutls_session_t session, unsigned int htype, unsigned int post, unsigned int incoming, const gnutls_datum_t *msg) {
3914         struct command *cmd;
3915         int gtls_errno = GNUTLS_E_SUCCESS;
3916         char sni [sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid)]; // static
3917         size_t snilen = sizeof (sni);
3918         unsigned int snitype;
3919         char *lid;
3920
3921 tlog (LOG_DAEMON, LOG_INFO, "Invoked %sprocessor for Client Hello, htype=%d, incoming=%d\n",
3922                 post ? "post" : "pre",
3923                 htype,
3924                 incoming);
3925
3926 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3927 errno = 0;
3928 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3929
3930 if (!post) {
3931         //
3932         // Setup a number of common references
3933         cmd = (struct command *) gnutls_session_get_ptr (session);
3934         if (cmd == NULL) {
3935                 return GNUTLS_E_INVALID_SESSION;
3936         }
3937
3938         //
3939         // Setup server-specific credentials and priority string
3940         //TODO// get anonpre value here
3941 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
3942 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3943         E_g2e ("Failed to reconfigure GnuTLS as a server",
3944                 configure_session (cmd,
3945                         session,
3946                         srv_creds, srv_credcount,
3947                         cmd->anonpre & ANONPRE_SERVER));
3948 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
3949
3950 } else {
3951
3952         //
3953         // Setup a number of common references
3954         cmd = (struct command *) gnutls_session_get_ptr (session);
3955         if (cmd == NULL) {
3956                 return GNUTLS_E_INVALID_SESSION;
3957         }
3958         lid = cmd->cmd.pio_data.pioc_starttls.localid;
3959
3960         //
3961         // Setup to ignore/request/require remote identity (from client)
3962 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3963         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_IGNORE_REMOTEID) {
3964                 // Neither Request nor Require remoteid; ignore it
3965                 ;
3966         } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REQUEST_REMOTEID) {
3967                 // Use Request instead of Require for remoteid
3968                 ( //RETURNS_VOID// E_g2e ("Failed to request remote identity",
3969                         gnutls_certificate_server_set_request (
3970                                 session,
3971                                 GNUTLS_CERT_REQUEST));
3972 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
3973         } else {
3974                 // Require a remoteid from the client (default)
3975                 ( //RETURNS_VOID// E_g2e ("Failed to require remote identity (the default)",
3976                         gnutls_certificate_server_set_request (
3977                                 session,
3978                                 GNUTLS_CERT_REQUIRE));
3979 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
3980         }
3981
3982         //
3983         // Find the client-helloed ServerNameIndication, or the service name
3984 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3985         sni [0] = '\0';
3986         if (gnutls_server_name_get (session, sni, &snilen, &snitype, 0) == 0) {
3987 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3988                 switch (snitype) {
3989                 case GNUTLS_NAME_DNS:
3990                         break;
3991                 // Note: In theory, other name types could be sent, and it would
3992                 // be useful to access indexes beyond 0.  In practice, nobody
3993                 // uses other name types than exactly one GNUTLS_NAME_DNS.
3994                 default:
3995                         sni [0] = '\0';
3996                         tlog (TLOG_TLS, LOG_ERR, "Received an unexpected SNI type; that is possible but uncommon; skipping SNI");
3997 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
3998                         break;
3999                 }
4000         }
4001 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
4002         if (sni [0] != '\0') {
4003                 if (*lid != '\0') {
4004                         int atidx;
4005                         for (atidx=128; atidx > 0; atidx--) {
4006                                 if (lid [atidx-1] == '@') {
4007                                         break;
4008                                 }
4009                         }
4010                         if (strncmp (sni, lid + atidx, sizeof (sni)-atidx) != 0) {
4011                                 tlog (TLOG_USER | TLOG_TLS, LOG_ERR, "Mismatch between client-sent SNI %s and local identity %s", sni, lid);
4012 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
4013                                 return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
4014                         }
4015                 } else {
4016                         memcpy (lid, sni, sizeof (sni));
4017 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
4018                 }
4019         } else {
4020                 memcpy (sni, lid, sizeof (sni)-1);
4021 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
4022                 sni [sizeof (sni) - 1] = '\0';
4023         }
4024 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
4025 }
4026
4027         //
4028         // Lap up any unnoticed POSIX error messages
4029         if (errno != 0) {
4030                 cmd->session_errno = errno;
4031 fprintf (stderr, "DEBUG: Got errno = %d / %s at %d\n", errno, strerror (errno), __LINE__);
4032                 gtls_errno = GNUTLS_E_NO_CIPHER_SUITES; /* Vaguely matching */
4033 fprintf (stderr, "DEBUG: Got gtls_errno = %d at %d\n", gtls_errno, __LINE__);
4034         }
4035
4036         //
4037         // Round off with an overal judgement
4038 fprintf (stderr, "DEBUG: Returning gtls_errno = %d or \"%s\" from srv_clihello()\n", gtls_errno, gnutls_strerror (gtls_errno));
4039         return gtls_errno;
4040 }
4041
4042
4043 int cli_srpcreds_retrieve (gnutls_session_t session,
4044                                 char **username,
4045                                 char **password) {
4046         //TODO:FIXED//
4047         tlog (TLOG_CRYPTO, LOG_DEBUG, "Picking up SRP credentials");
4048         *username = strdup ("tester");
4049         *password = strdup ("test");
4050         return GNUTLS_E_SUCCESS;
4051 }
4052
4053
4054 /* Setup credentials to be shared by all clients and servers.
4055  * Credentials are generally implemented through callback functions.
4056  * This should be called after setting up DH parameters.
4057  */
4058 static int setup_starttls_credentials (void) {
4059         gnutls_anon_server_credentials_t srv_anoncred = NULL;
4060         gnutls_anon_client_credentials_t cli_anoncred = NULL;
4061         gnutls_certificate_credentials_t clisrv_certcred = NULL;
4062         //TODO:NOTHERE// int srpbits;
4063         gnutls_srp_server_credentials_t srv_srpcred = NULL;
4064         gnutls_srp_client_credentials_t cli_srpcred = NULL;
4065         //TODO// gnutls_kdh_server_credentials_t srv_kdhcred = NULL;
4066         //TODO// gnutls_kdh_server_credentials_t cli_kdhcred = NULL;
4067         int gtls_errno = GNUTLS_E_SUCCESS;
4068         int gtls_errno_stack0 = GNUTLS_E_SUCCESS;
4069
4070         //
4071         // Construct anonymous server credentials
4072         E_g2e ("Failed to allocate ANON-DH server credentials",
4073                 gnutls_anon_allocate_server_credentials (
4074                         &srv_anoncred));
4075         if (!have_error_codes ()) /* E_g2e (...) */ gnutls_anon_set_server_dh_params (
4076                 srv_anoncred,
4077                 dh_params);
4078         if (gtls_errno == GNUTLS_E_SUCCESS) {
4079                 tlog (TLOG_CRYPTO, LOG_INFO, "Setting server anonymous credentials");
4080                 srv_creds [srv_credcount].credtp = GNUTLS_CRD_ANON;
4081                 srv_creds [srv_credcount].cred   = (void *) srv_anoncred;
4082                 srv_credcount++;
4083         } else if (srv_anoncred != NULL) {
4084                 gnutls_anon_free_server_credentials (srv_anoncred);
4085                 srv_anoncred = NULL;
4086         }
4087
4088         //
4089         // Construct anonymous client credentials
4090         gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4091         E_g2e ("Failed to allocate ANON-DH client credentials",
4092                 gnutls_anon_allocate_client_credentials (
4093                         &cli_anoncred));
4094 #ifdef MIRROR_IMAGE_OF_SERVER_ANONYMOUS_CREDENTIALS
4095         // NOTE: This is not done under TLS; server always provides DH params
4096         if (!have_error_codes ()) gnutls_anon_set_client_dh_params (
4097                 cli_anoncred,
4098                 dh_params);
4099 #endif
4100         if (gtls_errno == GNUTLS_E_SUCCESS) {
4101                 tlog (TLOG_CRYPTO, LOG_INFO, "Setting client anonymous credentials");
4102                 cli_creds [cli_credcount].credtp = GNUTLS_CRD_ANON;
4103                 cli_creds [cli_credcount].cred   = (void *) cli_anoncred;
4104                 cli_credcount++;
4105         } else if (cli_anoncred != NULL) {
4106                 gnutls_anon_free_client_credentials (cli_anoncred);
4107                 cli_anoncred = NULL;
4108         }
4109
4110         //
4111         // Construct certificate credentials for X.509 and OpenPGP cli/srv
4112         gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4113         E_g2e ("Failed to allocate certificate credentials",
4114                 gnutls_certificate_allocate_credentials (
4115                         &clisrv_certcred));
4116         //TODO// What to do here when we add locking on DH params?
4117         gnutls_certificate_set_dh_params (
4118                 clisrv_certcred,
4119                 dh_params);
4120         gtls_errno_stack0 = gtls_errno;
4121         /* TODO: Bad code.  GnuTLS 3.2.1 ignores retrieve_function2 when
4122          * checking if it can handle the OpenPGP certificate type in
4123          * _gnutls_session_cert_type_supported (gnutls_status.c:175) but
4124          * it does see the "1" version field.  It does not callback the
4125          * "1" version if "2" is present though.
4126          */
4127         if (!have_error_codes ()) /* TODO:GnuTLSversions E_g2e (...) */ gnutls_certificate_set_retrieve_function (
4128                 clisrv_certcred,
4129                 (void *) exit);
4130         if (!have_error_codes ()) /* TODO:GnuTLSversions E_g2e (...) */ gnutls_certificate_set_retrieve_function2 (
4131                 clisrv_certcred,
4132                 clisrv_cert_retrieve);
4133 #ifdef HAVE_TLS_KDH
4134         E_g2e ("Failed to set encoding callback for Kerberos Authenticators",
4135                         gnutls_authenticator_set_encode_function (
4136                                         clisrv_certcred,
4137                                         cli_kdhsig_encode));
4138         E_g2e ("Failed to set decoding callback for Kerberos Authenticators",
4139                         gnutls_authenticator_set_decode_function (
4140                                         clisrv_certcred,
4141                                         srv_kdhsig_decode));
4142 #endif
4143         if (gtls_errno == GNUTLS_E_SUCCESS) {
4144                 // Setup for certificates
4145                 tlog (TLOG_CERT, LOG_INFO, "Setting client and server certificate credentials");
4146                 cli_creds [cli_credcount].credtp = GNUTLS_CRD_CERTIFICATE;
4147                 cli_creds [cli_credcount].cred   = (void *) clisrv_certcred;
4148                 cli_credcount++;
4149                 srv_creds [srv_credcount].credtp = GNUTLS_CRD_CERTIFICATE;
4150                 srv_creds [srv_credcount].cred   = (void *) clisrv_certcred;
4151                 srv_credcount++;
4152         } else if (clisrv_certcred != NULL) {
4153                 gnutls_certificate_free_credentials (clisrv_certcred);
4154                 clisrv_certcred = NULL;
4155         }
4156
4157         //
4158         // Construct server credentials for SRP authentication
4159         gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4160         E_g2e ("Failed to allocate SRP server credentials",
4161                 gnutls_srp_allocate_server_credentials (
4162                         &srv_srpcred));
4163         E_g2e ("Failed to set SRP server credentials",
4164                 gnutls_srp_set_server_credentials_file (
4165                         srv_srpcred,
4166                         "../testdata/tlspool-test-srp.passwd",
4167                         "../testdata/tlspool-test-srp.conf"));
4168         if (gtls_errno == GNUTLS_E_SUCCESS) {
4169                 tlog (TLOG_CRYPTO, LOG_INFO, "Setting server SRP credentials");
4170                 srv_creds [srv_credcount].credtp = GNUTLS_CRD_SRP;
4171                 srv_creds [srv_credcount].cred   = (void *) srv_srpcred;
4172                 srv_credcount++;
4173         } else if (srv_srpcred != NULL) {
4174                 gnutls_srp_free_server_credentials (srv_srpcred);
4175                 srv_srpcred = NULL;
4176         }
4177
4178         //
4179         // Construct client credentials for SRP authentication
4180         gtls_errno = gtls_errno_stack0; // Don't pop, just forget last failures
4181         E_g2e ("Failed to allocate SRP client credentials",
4182                 gnutls_srp_allocate_client_credentials (
4183                         &cli_srpcred));
4184         if (!have_error_codes ()) gnutls_srp_set_client_credentials_function (
4185                 cli_srpcred,
4186                 cli_srpcreds_retrieve);
4187         if (gtls_errno == GNUTLS_E_SUCCESS) {
4188                 tlog (TLOG_CRYPTO, LOG_INFO, "Setting client SRP credentials");
4189                 cli_creds [cli_credcount].credtp = GNUTLS_CRD_SRP;
4190                 cli_creds [cli_credcount].cred   = (void *) cli_srpcred;
4191                 cli_credcount++;
4192         } else if (cli_srpcred != NULL) {
4193                 gnutls_srp_free_client_credentials (cli_srpcred);
4194                 cli_srpcred = NULL;
4195         }
4196
4197         //
4198         // Construct server credentials for KDH authentication
4199         //TODO// gtls_errno = gtls_errno_stack0;        // Don't pop, just forget last failures
4200         //TODO// E_g2e ("Failed to allocate KDH server credentials",
4201         //TODO//        gnutls_kdh_allocate_server_credentials (
4202         //TODO//                &srv_kdhcred));
4203         //TODO// E_g2e ("Failed to set KDH server DH params",
4204         //TODO//        gnutls_kdh_set_server_dh_params (
4205         //TODO//                srv_kdhcred,
4206         //TODO//                dh_params));
4207         //TODO// if (gtls_errno == GNUTLS_E_SUCCESS) {
4208         //TODO//        tlog (TLOG_CRYPTO, LOG_INFO, "Setting server KDH credentials");
4209         //TODO//        srv_creds [srv_credcount].credtp = GNUTLS_CRD_KDH;
4210         //TODO//        srv_creds [srv_credcount].cred   = (void *) srv_kdhcred;
4211         //TODO//        srv_credcount++;
4212         //TODO// } else if (srv_kdhcred != NULL) {
4213         //TODO//        gnutls_kdh_free_server_credentials (srv_kdhcred);
4214         //TODO//        srv_kdhcred = NULL;
4215         //TODO// }
4216
4217         //
4218         // Construct client credentials for KDH
4219         //TODO// gtls_errno = gtls_errno_stack0;        // Don't pop, just forget last failures
4220         //TODO// E_g2e ("Failed to allocate KDH client credentials",
4221         //TODO//        gnutls_kdh_allocate_client_credentials (
4222         //TODO//                &cli_kdhcred));
4223         //TODO// E_g2e ("Failed to set KDH client credentials",
4224         //TODO//        gnutls_kdh_set_client_credentials_function (
4225         //TODO//                cli_kdhcred,
4226         //TODO//                cli_kdh_retrieve));
4227         //TODO// if (gtls_errno == GNUTLS_E_SUCCESS) {
4228         //TODO//        tlog (TLOG_CRYPTO, LOG_INFO, "Setting client KDH credentials");
4229         //TODO//        cli_creds [cli_credcount].credtp = GNUTLS_CRD_KDH;
4230         //TODO//        cli_creds [cli_credcount].cred   = (void *) cli_kdhcred;
4231         //TODO//        cli_credcount++;
4232         //TODO// } else if (cli_kdhcred != NULL) {
4233         //TODO//        gnutls_kdh_free_client_credentials (cli_kdhcred);
4234         //TODO//        cli_kdhcred = NULL;
4235         //TODO// }
4236
4237         //
4238         // Ensure that at least one credential has been set
4239         // TODO: Look at the counters; but at boot, we can require all okay
4240         if ((gtls_errno == GNUTLS_E_SUCCESS) &&
4241                         ( (cli_credcount != EXPECTED_CLI_CREDCOUNT) ||
4242                           (srv_credcount != EXPECTED_SRV_CREDCOUNT) ) ) {
4243                 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);
4244                 E_g2e ("Not all credentials could be setup",
4245                         GNUTLS_E_INSUFFICIENT_CREDENTIALS);
4246         }
4247
4248         //
4249         // Report overall error or success
4250         return gtls_errno;
4251 }
4252
4253
4254 /* Cleanup all credentials created, just before exiting the daemon.
4255  */
4256 static void cleanup_starttls_credentials (void) {
4257         while (srv_credcount-- > 0) {
4258                 struct credinfo *crd = &srv_creds [srv_credcount];
4259                 switch (crd->credtp) {
4260                 case GNUTLS_CRD_CERTIFICATE:
4261                         // Shared with client; skipped in server and removed in client
4262                         // gnutls_certificate_free_credentials (crd->cred);
4263                         break;
4264                 case GNUTLS_CRD_ANON:
4265                         gnutls_anon_free_server_credentials (crd->cred);
4266                         break;
4267                 case GNUTLS_CRD_SRP:
4268                         gnutls_srp_free_server_credentials (crd->cred);
4269                         break;
4270                 case GNUTLS_CRD_PSK:
4271                 case GNUTLS_CRD_IA:
4272                         //TODO: not handled
4273                         break;
4274                 //TODO// case GNUTLS_CRD_KDH:
4275                 //TODO//        gnutls_kdh_free_server_credentials (crd->cred);
4276                 //TODO//        break;
4277                 }
4278         }
4279         while (cli_credcount-- > 0) {
4280                 struct credinfo *crd = &cli_creds [cli_credcount];
4281                 switch (crd->credtp) {
4282                 case GNUTLS_CRD_CERTIFICATE:
4283                         // Shared with client; skipped in server and removed in client
4284                         gnutls_certificate_free_credentials (crd->cred);
4285                         break;
4286                 case GNUTLS_CRD_ANON:
4287                         gnutls_anon_free_client_credentials (crd->cred);
4288                         break;
4289                 case GNUTLS_CRD_SRP:
4290                         gnutls_srp_free_client_credentials (crd->cred);
4291                         break;
4292                 case GNUTLS_CRD_PSK:
4293                 case GNUTLS_CRD_IA:
4294                         //TODO: not handled
4295                         break;
4296                 //TODO// case GNUTLS_CRD_KDH:
4297                 //TODO//        gnutls_kdh_free_client_credentials (crd->cred);
4298                 //TODO//        break;
4299                 }
4300         }
4301 }
4302
4303
4304 /*
4305  * The starttls_thread is a main program for the setup of a TLS connection,
4306  * either in client mode or server mode.  Note that the distinction between
4307  * client and server mode is only a TLS concern, but not of interest to the
4308  * application or the records exchanged.
4309  *
4310  * If the STARTTLS operation succeeds, this will be reported back to the
4311  * application, but the TLS pool will continue to be active in a copycat
4312  * procedure: encrypting outgoing traffic and decrypting incoming traffic.
4313  *
4314  * A new handshake may be initiated with a STARTTLS command with the special
4315  * flag PIOF_STARTTLS_RENEGOTIATE and the ctlkey set to a previously setup
4316  * TLS connection.  This command runs in a new thread, that cancels the old
4317  * one (which it can only do while it is waiting in copycat) and then join
4318  * that thread (and its data) with the current one.  This is based on the
4319  * ctlkey, which serves to lookup the old thread's data.  When the
4320  * connection ends for other reasons than a permitted cancel by another
4321  * thread, will the thread cleanup its own resources.  In these situations,
4322  * the new command determines the negotiation parameters, and returns identity
4323  * information.
4324  *
4325  * In addition, the remote side may initiate renegotiation.  This is accepted
4326  * without further ado (although future versions of the TLS Pool may add a
4327  * callback mechanism to get it approved).  The renegotiation now runs under
4328  * the originally supplied negotiation parameters.  In case it needs a new
4329  * local identity, it may also perform callbacks.  Possibly repeating what
4330  * happened before -- but most often, a server will start processing a
4331  * protocol and determine that it requires more for the requested level of
4332  * service, and then renegotiate.  This is common, for example, with HTTPS
4333  * connections that decide they need a client certificate for certain URLs.
4334  * The implementation of this facility is currently as unstructured as the
4335  * facility itself, namely through a goto.  We may come to the conclusion
4336  * that a loop is in fact a warranted alternative, but we're not yet
4337  * convinced that this would match with other "structures" in TLS.
4338  *
4339  * In conclusion, there are three possible ways of running this code:
4340  *  1. For a new connection.  Many variables are not known and build up
4341  *     in the course of running the function.
4342  *  2. After a command requesting renegotiation.  This overtakes the prior
4343  *     connection's thread, and copies its data from the ctlkeynode_tls.
4344  *     The resulting code has a number of variables filled in already at
4345  *     an earlier stage.
4346  *  3. After a remote request for renegotiation.  This loops back to an
4347  *     earlier phase, but after the thread takeover and ctlkeynode_tls copy
4348  *     of the explicit command for renegotation.  Its behaviour is subtly
4349  *     different in that it has no command to act on, and so it cannot
4350  *     send responses or error codes.  It will however log and shutdown
4351  *     as the command-driven options would.  It will not perform callbacks
4352  *     for PIOC_STARTTLS_LOCALID_V2 or PIOC_PLAINTEXT_CONNECT_V2.  It will
4353  *     however trigger the PIOC_LIDENTRY_CALLBACK_V2 through the separate
4354  *     callback command, if one is registered.
4355  * Yeah, it's great fun, coding TLS and keeping it both flexible and secure.
4356  */
4357 static void *starttls_thread (void *cmd_void) {
4358         struct command *cmd, *replycmd;
4359         struct command cmd_copy; // for relooping during renegotiation
4360         struct pioc_starttls orig_starttls;
4361         uint32_t orig_cmdcode;
4362         int plainfd = -1;
4363         int cryptfd = -1;
4364         gnutls_session_t session;
4365         int got_session = 0;
4366         int gtls_errno = GNUTLS_E_SUCCESS;
4367         int i;
4368         struct ctlkeynode_tls *ckn = NULL;
4369         uint32_t tout;
4370         int forked = 0;
4371         int want_remoteid = 1;
4372         int got_remoteid = 0;
4373         int renegotiating = 0;
4374         char *preauth = NULL;
4375         unsigned int preauthlen = 0;
4376         int taking_over = 0;
4377         int my_maxpreauth = 0;
4378         int anonpost = 0;
4379
4380         //
4381         // Block thread cancellation -- and re-enable it in copycat()
4382         assert (pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL) == 0);
4383
4384         //
4385         // General thread setup
4386         replycmd = cmd = (struct command *) cmd_void;
4387         if (cmd == NULL) {
4388                 send_error (replycmd, EINVAL, "Command structure not received");
4389                 assert (pthread_detach (pthread_self ()) == 0);
4390                 return NULL;
4391         }
4392         *cmd->valflags = '\0';
4393         cmd->session_errno = 0;
4394         cmd->anonpre = 0;
4395         orig_cmdcode = cmd->cmd.pio_cmd;
4396         memcpy (&orig_starttls, &cmd->cmd.pio_data.pioc_starttls, sizeof (orig_starttls));
4397         cmd->orig_starttls = &orig_starttls;
4398         cryptfd = cmd->passfd;
4399         cmd->passfd = -1;
4400 //TODO:TEST Removed here because it is tested below
4401 /*
4402         if (cryptfd < 0) {
4403                 tlog (TLOG_UNIXSOCK, LOG_ERR, "No ciphertext file descriptor supplied to TLS Pool");
4404                 send_error (replycmd, EINVAL, "No ciphertext file descriptor supplied to TLS Pool");
4405                 assert (pthread_detach (pthread_self ()) == 0);
4406                 return NULL;
4407         }
4408 */
4409         cmd->session_certificate = (intptr_t) (void *) NULL;
4410         cmd->session_privatekey  = (intptr_t) (void *) NULL;
4411
4412         //
4413         // In case of renegotiation, lookup the previous ctlkeynode by its
4414         // ctlkey.  The fact that we have ckn != NULL indicates that we are
4415         // renegotiating in the code below; it will supply information as
4416         // we continue to run the TLS process.
4417         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_RENEGOTIATE) {
4418 fprintf (stderr, "DEBUG: Got a request to renegotiate existing TLS connection\n");
4419                 //
4420                 // Check that no FD was passed (and ended up in cryptfd)
4421                 if (cryptfd >= 0) {
4422                         tlog (TLOG_UNIXSOCK, LOG_ERR, "Renegotiation started with extraneous file descriptor");
4423                         send_error (replycmd, EPROTO, "File handle supplied for renegotiation");
4424                         close (cryptfd);
4425                         assert (pthread_detach (pthread_self ()) == 0);
4426                         return NULL;
4427                 }
4428                 //
4429                 // First find the ctlkeynode_tls
4430                 ckn = (struct ctlkeynode_tls *) ctlkey_find (cmd->cmd.pio_data.pioc_starttls.ctlkey, security_tls, cmd->clientfd);
4431 fprintf (stderr, "DEBUG: Got ckn == %p\n", (void *) ckn);
4432                 if (ckn == NULL) {
4433                         tlog (TLOG_UNIXSOCK, LOG_ERR, "Failed to find TLS connection for renegotiation by its ctlkey");
4434                         send_error (replycmd, ESRCH, "Cannot find TLS connection for renegotiation");
4435                         assert (pthread_detach (pthread_self ()) == 0);
4436                         return NULL;
4437                 }
4438                 //
4439                 // Now cancel the pthread for this process
4440                 errno = pthread_cancel (ckn->owner);
4441 fprintf (stderr, "DEBUG: pthread_cancel returned %d\n", errno);
4442                 if (errno == 0) {
4443                         void *retval;
4444                         errno = pthread_join (ckn->owner, &retval);
4445 fprintf (stderr, "DEBUG: pthread_join returned %d\n", errno);
4446                 }
4447                 if (errno == 0) {
4448                         // We have now synchronised with the cancelled thread
4449                         // Cleanup any _remote data in ckn->session->cmd
4450                         cleanup_any_remote_credentials (
4451                                 (struct command *) gnutls_session_get_ptr (
4452                                         ckn->session));
4453                 }
4454                 if (errno != 0) {
4455                         tlog (TLOG_UNIXSOCK, LOG_ERR, "Failed to interrupt TLS connection for renegotiation");
4456                         send_error (replycmd, errno, "Cannot interrupt TLS connection for renegotiation");
4457                         ctlkey_unfind (&ckn->regent);
4458                         assert (pthread_detach (pthread_self ()) == 0);
4459                         // Do not free the ckn, as the other thread still runs
4460                         return NULL;
4461                 }
4462                 //
4463                 // We are in control!  Assimilate the TLS connection data.
4464                 renegotiating = 1;
4465                 plainfd = ckn->plainfd;
4466                 cryptfd = ckn->cryptfd;
4467                 session = ckn->session;
4468                 got_session = 1;
4469                 taking_over = 1;
4470                 ctlkey_unfind (&ckn->regent);
4471         }
4472
4473         // Then follows the unstructured entry point for the unstructured
4474         // request to a TLS connection to renegotiate its security parameters.
4475         // Doing this in any other way than with goto would add a lot of
4476         // make-belief structure that only existed to make this looping
4477         // possible.  We'd rather be honest and admit the lack of structure
4478         // that TLS has in this respect.  Maybe we'll capture it one giant loop
4479         // at some point, but for now that does not seem to add any relief.
4480         renegotiate:
4481 fprintf (stderr, "DEBUG: Renegotiating = %d, anonpost = %d, plainfd = %d, cryptfd = %d, flags = 0x%x, session = %p, 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);
4482
4483         //
4484         // If this is server renegotiating, send a request to that end
4485         //TODO// Only invoke gnutls_rehandshake() on the server
4486         if (renegotiating && (taking_over || anonpost) && (gtls_errno == GNUTLS_E_SUCCESS)) {
4487 fprintf (stderr, "DEBUG: Invoking gnutls_rehandshake in renegotiation loop\n");
4488                 gtls_errno = gnutls_rehandshake (session);
4489                 if (gtls_errno == GNUTLS_E_INVALID_REQUEST) {
4490                         // Clients should not do this; be forgiving
4491                         gtls_errno = GNUTLS_E_SUCCESS;
4492 fprintf (stderr, "DEBUG: Client-side invocation flagged as wrong; compensated error\n");
4493                 }
4494         }
4495
4496         //
4497         // When renegotiating TLS security, ensure that it is done securely
4498         if (renegotiating && (gnutls_safe_renegotiation_status (session) == 0)) {
4499                 send_error (replycmd, EPROTO, "Renegotiation requested while secure renegotiation is unavailable on remote");
4500                 if (cryptfd >= 0) {
4501                         close (cryptfd);
4502                         cryptfd = -1;
4503                 }
4504                 if (plainfd >= 0) {
4505                         close (plainfd);
4506                         plainfd = -1;
4507                 }
4508                 if (ckn != NULL) {
4509                         if (ctlkey_unregister (ckn->regent.ctlkey)) {
4510                                 free (ckn);
4511                                 ckn = NULL;
4512                         }
4513                 }
4514                 assert (pthread_detach (pthread_self ()) == 0);
4515                 return NULL;
4516         }
4517
4518         //
4519         // Potentially decouple the controlling fd (ctlkey is in orig_starttls)
4520         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_FORK) {
4521                 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_FORK;
4522                 forked = 1;
4523         }
4524
4525         //
4526         // Setup BDB transactions and reset credential datum fields
4527         if (!anonpost) {
4528                 memset (&cmd->lids, 0, sizeof (cmd->lids));
4529                 manage_txn_begin (&cmd->txn);
4530         }
4531
4532         //
4533         // Permit cancellation of this thread -- TODO: Cleanup?
4534 //TODO:TEST// Defer setcancelstate until copycat() activity
4535 /*
4536         errno = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
4537         if (errno != 0) {
4538                 send_error (replycmd, ESRCH, "STARTTLS handler thread cancellability refused");
4539                 if (cryptfd >= 0) {
4540                         close (cryptfd);
4541                         cryptfd = -1;
4542                 }
4543                 if (plainfd >= 0) {
4544                         close (plainfd);
4545                         plainfd = -1;
4546                 }
4547                 if (ckn != NULL) {
4548                         if (ctlkey_unregister (ckn->regent.ctlkey)) {
4549                                 free (ckn);
4550                                 ckn = NULL;
4551                         }
4552                 }
4553                 manage_txn_rollback (&cmd->txn);
4554                 assert (pthread_detach (pthread_self ()) == 0);
4555                 return NULL;
4556         }
4557 */
4558         //
4559         // Check and setup the plaintext file handle
4560         if (cryptfd < 0) {
4561                 send_error (replycmd, EPROTO, "You must supply a TLS-protected socket");
4562                 if (plainfd >= 0) {
4563                         close (plainfd);
4564                         plainfd = -1;
4565                 }
4566 fprintf (stderr, "ctlkey_unregister under ckn=%p at %d\n", (void *)ckn, __LINE__);
4567                 if (ckn != NULL) {      /* TODO: CHECK NEEDED? */
4568                         if (ctlkey_unregister (ckn->regent.ctlkey)) {
4569                                 free (ckn);
4570                                 ckn = NULL;
4571                         }
4572                 }
4573                 manage_txn_rollback (&cmd->txn);
4574                 assert (pthread_detach (pthread_self ()) == 0);
4575                 return NULL;
4576         }
4577
4578         //
4579         // Decide on support for the Anonymous Precursor, based on the
4580         // service name and its appearance in the anonpre_registry.
4581         // If the remoteid is not interesting to the client then also
4582         // support an Anonymous Precursor; we have nothing to loose.
4583         cmd->anonpre &= ~ANONPRE_EITHER;
4584         if (renegotiating) {
4585                 ; // Indeed, during renegotiation we always disable ANON-DH
4586         } else if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_IGNORE_REMOTEID) {
4587                 cmd->anonpre = ANONPRE_EITHER;
4588                 want_remoteid = 0;
4589         } else {
4590                 int anonpre_regidx =  anonpre_registry_size      >> 1;
4591                 int anonpre_regjmp = (anonpre_registry_size + 1) >> 1;
4592                 int cmp;
4593                 while (anonpre_regjmp > 0) {
4594                         anonpre_regjmp = anonpre_regjmp >> 1;
4595                         cmp = strncasecmp (anonpre_registry [anonpre_regidx].service,
4596                                 (const char *)cmd->cmd.pio_data.pioc_starttls.service,
4597                                 TLSPOOL_SERVICELEN);
4598 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);
4599                         if (cmp == 0) {
4600                                 // anonpre_regent matches
4601                                 cmd->anonpre = anonpre_registry [anonpre_regidx].flags;
4602                                 break;
4603                         } else if (cmp > 0) {
4604                                 // anonpre_regent too high
4605                                 anonpre_regidx -= 1 + anonpre_regjmp;
4606                                 if (anonpre_regidx < 0) {
4607                                         anonpre_regidx = 0;
4608                                 }
4609                         } else {
4610                                 // anonpre_regent too low
4611                                 anonpre_regidx += 1 + anonpre_regjmp;
4612                                 if (anonpre_regidx >= anonpre_registry_size) {
4613                                         anonpre_regidx = anonpre_registry_size - 1;
4614                                 }
4615                         }
4616                 }
4617         }
4618
4619         //
4620         // Setup flags for client and/or server roles (make sure there is one)
4621         if ((!renegotiating) && ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REMOTEROLE_CLIENT) == 0)) {
4622                 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_LOCALROLE_SERVER;
4623         }
4624         if ((!renegotiating) && ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REMOTEROLE_SERVER) == 0)) {
4625                 cmd->cmd.pio_data.pioc_starttls.flags &= ~PIOF_STARTTLS_LOCALROLE_CLIENT;
4626         }
4627         if ((cmd->cmd.pio_data.pioc_starttls.flags & (PIOF_STARTTLS_LOCALROLE_CLIENT | PIOF_STARTTLS_LOCALROLE_SERVER)) == 0) {
4628                 //
4629                 // Neither a TLS client nor a TLS server
4630                 //
4631                 send_error (replycmd, ENOTSUP, "Command not supported");
4632                 close (cryptfd);
4633                 if (plainfd >= 0) {
4634                         close (plainfd);
4635                         plainfd = -1;
4636                 }
4637 fprintf (stderr, "ctlkey_unregister under ckn=%p at %d\n", (void *)ckn, __LINE__);
4638                 if (ckn != NULL) { /* TODO: CHECK NEEDED? */
4639                         if (ctlkey_unregister (ckn->regent.ctlkey)) {
4640                                 free (ckn);
4641                                 ckn = NULL;
4642                         }
4643                 }
4644                 manage_txn_rollback (&cmd->txn);
4645                 assert (pthread_detach (pthread_self ()) == 0);
4646                 return NULL;
4647         }
4648
4649         //
4650         // Setup the TLS session.  Also see doc/p2p-tls.*
4651         //
4652         // TODO: GnuTLS cannot yet setup p2p connections
4653         if (ckn != NULL) {
4654                 gnutls_session_set_ptr (
4655                         session,
4656                         cmd);
4657                 //TODO:DONE?// Clear various settings... creds, flags, modes? CLI/SRV?
4658         } else {
4659                 E_g2e ("Failed to initialise GnuTLS peer session",
4660                         gnutls_init (
4661                                 &session,
4662                                 (((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)? GNUTLS_CLIENT: 0) |
4663                                  ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER)? GNUTLS_SERVER: 0))
4664                                 ));
4665                 if (gtls_errno == GNUTLS_E_SUCCESS) {
4666                         got_session = 1;
4667                         gnutls_session_set_ptr (
4668                                 session,
4669                                 cmd);
4670                 }
4671         }
4672         cmd->session = session;
4673         //
4674         // Setup client-specific behaviour if needed
4675         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) {
4676 if (!renegotiating) {   //TODO:TEST//
4677                 //
4678                 // Setup as a TLS client
4679                 //
4680                 int srpbits;
4681                 //
4682                 // Require a minimum security level for SRP
4683                 srpbits = 3072;
4684                 //TODO:CRASH// if (gtls_errno == GNUTLS_E_SUCCESS) gnutls_srp_set_prime_bits (
4685                         //TODO:CRASH// session,
4686                         //TODO:CRASH// srpbits);
4687                 //
4688                 // Setup as a TLS client
4689                 //
4690                 // Setup for potential sending of SNI
4691                 if ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_WITHOUT_SNI) == 0) {
4692                         char *str = cmd->cmd.pio_data.pioc_starttls.remoteid;
4693                         int ofs = 0;
4694                         int len = 0;
4695                         while (str [len] && (len < 128)) {
4696                                 if (str [len] == '@') {
4697                                         ofs = len + 1;
4698                                 }
4699                                 len++;
4700                         }
4701                         // If no usable remoteid was setup, ignore it
4702                         if ((len > ofs) && (len < 128)) {
4703                                 cmd->cmd.pio_data.pioc_starttls.remoteid [sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid)-1] = '\0';
4704                                 tlog (TLOG_TLS, LOG_DEBUG, "Sending ServerNameIndication \"%.*s\"", len - ofs, str + ofs);
4705                                 E_g2e ("Client failed to setup SNI",
4706                                         gnutls_server_name_set (
4707                                                 session,
4708                                                 GNUTLS_NAME_DNS,
4709                                                 str + ofs,
4710                                                 len - ofs));
4711                         }
4712                 }
4713 } //TODO:TEST//
4714                 //
4715                 // Setup for client credential installation in this session
4716                 //
4717                 // Setup client-specific credentials and priority string
4718 fprintf (stderr, "DEBUG: Configuring client credentials\n");
4719                 E_g2e ("Failed to configure GnuTLS as a client",
4720                         configure_session (cmd,
4721                                 session,
4722                                 anonpost? NULL: cli_creds,
4723                                 anonpost?    0: cli_credcount,
4724                                 cmd->anonpre & ANONPRE_CLIENT));
4725         }
4726         //
4727         // Setup callback to server-specific behaviour if needed
4728         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_SERVER) {
4729 fprintf (stderr, "DEBUG: Configuring for server credentials callback if %d==0\n", gtls_errno);
4730 if (!renegotiating) {   //TODO:TEST//
4731                 if (gtls_errno == GNUTLS_E_SUCCESS) {
4732                         gnutls_handshake_set_hook_function (
4733                                 session,
4734                                 GNUTLS_HANDSHAKE_CLIENT_HELLO,
4735                                 GNUTLS_HOOK_BOTH,
4736                                 srv_clienthello);
4737                 }
4738 } //TODO:TEST//
4739                 //TODO:TEST// configure_session _if_ not setup as a client (too)
4740                 //
4741                 // Setup for server credential installation in this session
4742                 //
4743                 // Setup server-specific credentials and priority string
4744 #if 0
4745                 if (! (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT)) {
4746 fprintf (stderr, "DEBUG: Configuring server credentials (because it is not a client)\n");
4747                         E_g2e ("Failed to configure GnuTLS as a server",
4748                                 configure_session (cmd,
4749                                         session,
4750                                         anonpost? NULL: srv_creds,
4751                                         anonpost?    0: srv_credcount,
4752                                         cmd->anonpre & ANONPRE_SERVER));
4753                 }
4754 #endif
4755         }
4756
4757         //
4758         // Prefetch local identities that might be used in this session
4759         if (!anonpost) {
4760                 E_g2e ("Failed to fetch local credentials",
4761                         fetch_local_credentials (cmd));
4762         }
4763
4764         //
4765         // Setup a temporary priority string so handshaking can start
4766         if ((cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_LOCALROLE_CLIENT) == 0) {
4767                 E_g2e ("Failed to preconfigure server token priority string",
4768                                 gnutls_priority_set (
4769                                         session,
4770                                         priority_normal));
4771         }
4772
4773         //
4774         // Check if past code stored an error code through POSIX
4775         if (cmd->session_errno) {
4776                 gtls_errno = GNUTLS_E_USER_ERROR;
4777         }
4778
4779         //
4780         // Setup a timeout value as specified in the command, where TLS Pool
4781         // defines 0 as default and ~0 as infinite (GnuTLS has 0 as infinite).
4782         tout = cmd->cmd.pio_data.pioc_starttls.timeout;
4783 if (renegotiating) {
4784 ; // Do not set timeout
4785 } else
4786         if (tout == TLSPOOL_TIMEOUT_DEFAULT) {
4787                 gnutls_handshake_set_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
4788         } else if (tout == TLSPOOL_TIMEOUT_INFINITE) {
4789                 gnutls_handshake_set_timeout (session, 0);
4790         } else {
4791                 gnutls_handshake_set_timeout (session, tout);
4792         }
4793
4794         //
4795         // Now setup for the GnuTLS handshake
4796         //
4797 if (renegotiating) {
4798 ; // Do not setup cryptfd
4799 } else
4800         if (gtls_errno == GNUTLS_E_SUCCESS) {
4801                 gnutls_transport_set_int (session, cryptfd);
4802         }
4803         if (gtls_errno != GNUTLS_E_SUCCESS) {
4804                 tlog (TLOG_TLS, LOG_ERR, "Failed to prepare for TLS: %s", gnutls_strerror (gtls_errno));
4805                 if (cmd->session_errno) {
4806                         send_error (replycmd, cmd->session_errno, error_getstring ());
4807                 } else {
4808                         send_error (replycmd, EIO, "Failed to prepare for TLS");
4809                 }
4810                 if (got_session) {
4811 fprintf (stderr, "gnutls_deinit (%p) at %d\n", (void *)session, __LINE__);
4812                         gnutls_deinit (session);
4813                         got_session = 0;
4814                 }
4815                 close (cryptfd);
4816                 if (plainfd >= 0) {
4817                         close (plainfd);
4818                         plainfd = -1;
4819                 }
4820 fprintf (stderr, "ctlkey_unregister under ckn=%p at %d\n", (void *)ckn, __LINE__);
4821                 if (ckn != NULL) {      /* TODO: CHECK NEEDED? */
4822                         if (ctlkey_unregister (ckn->regent.ctlkey)) {
4823                                 free (ckn);
4824                                 ckn = NULL;
4825                         }
4826                 }
4827                 manage_txn_rollback (&cmd->txn);
4828                 assert (pthread_detach (pthread_self ()) == 0);
4829                 return NULL;
4830         }
4831         tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_DEBUG, "TLS handshake started over %d", cryptfd);
4832         do {
4833                 //
4834                 // Take a rehandshaking step forward.
4835                 //
4836                 gtls_errno = gnutls_handshake (session);
4837                 //
4838                 // When data is sent before completing
4839                 // the rehandshake, then it's something
4840                 // harmless, given the criteria for the
4841                 // anonpre_registry.  We pass it on and
4842                 // don't worry about it.  We do report
4843                 // it though!
4844                 //
4845                 // Note: Applications should be willing
4846                 // to buffer or process such early data
4847                 // before the handshake is over or else
4848                 // the handshake will bail out in error.
4849                 //
4850                 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
4851                         if (my_maxpreauth <= 0) {
4852                                 tlog (TLOG_COPYCAT, LOG_ERR, "Received unwanted early data before authentication is complete");
4853                                 break; // Terminate the handshake
4854                         } else if (preauth == NULL) {
4855                                 preauth = malloc (my_maxpreauth);
4856                                 if (preauth == NULL) {
4857                                         gtls_errno = GNUTLS_E_MEMORY_ERROR;
4858                                         break; // Terminate the handshake
4859                                 }
4860                         }
4861                 }
4862                 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
4863                         if (preauthlen >= my_maxpreauth) {
4864                                 tlog (TLOG_COPYCAT, LOG_ERR, "Received more early data than willing to receive (%d bytes)", my_maxpreauth);
4865                                 break; // Terminate the handshake
4866                         }
4867                 }
4868                 if (gtls_errno == GNUTLS_E_GOT_APPLICATION_DATA) {
4869                         ssize_t sz;
4870                         sz = gnutls_record_recv (session, preauth + preauthlen, my_maxpreauth - preauthlen);
4871                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Received %d remote bytes (or error if <0) from %d during anonymous precursor\n", (int) sz, cryptfd);
4872                         if (sz > 0) {
4873                                 preauthlen += sz;
4874                                 gtls_errno = GNUTLS_E_SUCCESS;
4875                         } else {
4876                                 gtls_errno = sz; // It's actually an error code
4877                         }
4878                 }
4879         } while ((gtls_errno < 0) &&
4880                 //DROPPED// (gtls_errno != GNUTLS_E_GOT_APPLICATION_DATA) &&
4881                 //DROPPED// (gtls_errno != GNUTLS_E_WARNING_ALERT_RECEIVED) &&
4882                 (gnutls_error_is_fatal (gtls_errno) == 0));
4883         //
4884         // Handshake done -- initialise remote_xxx, vfystatus, got_remoteid
4885         if ((gtls_errno == 0) && !(cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_IGNORE_REMOTEID)) {
4886                 // We want to try to authenticate the peer
4887                 E_g2e ("Failed to retrieve peer credentials",
4888                                 fetch_remote_credentials (cmd));
4889                 if (gtls_errno == GNUTLS_E_AUTH_ERROR) {
4890                         if (cmd->cmd.pio_data.pioc_starttls.flags & PIOF_STARTTLS_REQUEST_REMOTEID) {
4891                                 // We do not _require_ authentication of the peer
4892                                 gtls_errno = 0;
4893                         }
4894                 }
4895         }
4896         if (gtls_errno == 0) {
4897                 const gnutls_datum_t *certs;
4898                 unsigned int num_certs;
4899                 got_remoteid = 0;
4900                 switch (cmd->remote_auth_type) { // Peer's cred type
4901                 case GNUTLS_CRD_CERTIFICATE:
4902                         if (cmd->remote_cert_count >= 1) {
4903                                 got_remoteid = 1;
4904                         }
4905 #ifdef PHASED_OUT_DIRECT_VALIDATION
4906                         E_g2e ("Failed to validate peer",
4907                                 gnutls_certificate_verify_peers2 (
4908                                         session,
4909                                         &cmd->vfystatus));
4910 #endif
4911                         cmd->vfystatus = 0;
4912                         break;
4913                 case GNUTLS_CRD_PSK:
4914                         // Difficult... what did the history say about this?
4915                         got_remoteid = 0;
4916                         cmd->vfystatus = GNUTLS_CERT_SIGNER_NOT_FOUND;
4917                         break;
4918                 case GNUTLS_CRD_SRP:
4919                         // Got a credential, validation follows later on
4920                         //TODO// SRP does not really auth the server
4921                         got_remoteid = 1;
4922                         cmd->vfystatus = GNUTLS_CERT_SIGNER_NOT_FOUND;
4923                         break;
4924                 case GNUTLS_CRD_ANON:
4925                         // Did not get a credential, perhaps due to anonpre
4926                         got_remoteid = 0;
4927                         cmd->vfystatus = GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNATURE_FAILURE;
4928                         break;
4929                 case GNUTLS_CRD_IA:
4930                         // Inner Application extension is no true credential
4931                         // Should we compare the client-requested service?
4932                         // Should we renegotiate into the ALPN protocol?
4933                         got_remoteid = 0;
4934                         cmd->vfystatus = GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNATURE_FAILURE;
4935                         break;
4936                 default:
4937                         // Unknown creds cautiously considered unauthentitcated
4938                         got_remoteid = 0;
4939                         cmd->vfystatus = ~ (unsigned short) 0;  // It's all bad
4940                         break;
4941                 }
4942                 //
4943                 // Now recognise and handle the Anonymous Precursor
4944                 if (((cmd->anonpre & ANONPRE_EITHER) != 0)
4945                                         && want_remoteid && !got_remoteid) {
4946                         assert (anonpost == 0);
4947                         valexp_valflag_set (cmd, 'A');
4948                         // Disable ANON-protocols but keep creds from before
4949                         //TODO:ELSEWHERE// tlog (TLOG_TLS, LOG_DEBUG, "Reconfiguring TLS over %d without Anonymous Precursor\n", cryptfd);
4950                         //TODO:ELSEWHERE// E_g2e ("Failed to reconfigure GnuTLS without anonymous precursor",
4951                                 //TODO:ELSEWHERE// configure_session (cmd,
4952                                         //TODO:ELSEWHERE// session,
4953                                         //TODO:ELSEWHERE// NULL, 0,
4954                                         //TODO:ELSEWHERE// 0));
4955                         // We do not want to use ANON-DH if the flag
4956                         // ANONPRE_EXTEND_MASTER_SECRET is set for the protocol
4957                         // but the remote peer does not support it.  Only if
4958                         // this problem cannot possibly occur, permit
4959                         // my_maxpreauth > 0 for early data acceptance.
4960                         my_maxpreauth = 0;
4961                         if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
4962 #if GNUTLS_VERSION_NUMBER >= 0x030400
4963                                 gnutls_ext_priv_data_t ext;
4964                                 if (!gnutls_ext_get_data (session, 23, &ext)) {
4965                                         my_maxpreauth = maxpreauth;
4966                                 }
4967 #endif
4968                         } else {
4969                                 my_maxpreauth = maxpreauth;
4970                         }
4971                         if (gtls_errno == 0) {
4972                                 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_DEBUG, "TLS handshake continued over %d after anonymous precursor", cryptfd);
4973                                 renegotiating = 1; // (de)selects steps
4974                                 anonpost = 1;      // (de)selects steps
4975                                 goto renegotiate;
4976                         }
4977                 }
4978         }
4979         if ((gtls_errno == GNUTLS_E_SUCCESS) && cmd->session_errno) {
4980                 gtls_errno = GNUTLS_E_USER_ERROR;
4981         }
4982         taking_over = 0;
4983
4984         //
4985         // Run the validation expression logic, using expressions we ran into
4986 fprintf (stderr, "DEBUG: Prior to valexp, gtls_errno = %d\n", gtls_errno);
4987         if (gtls_errno == GNUTLS_E_SUCCESS) {
4988                 struct valexp *verun = NULL;
4989                 char *valexp_conj [3];
4990                 int valexp_conj_count = 0;
4991                 // Setup for validation expression runthrough
4992                 cmd->valexp_result = -1;
4993                 if ((cmd->trust_valexp != NULL) && (0 != strcmp (cmd->trust_valexp, "1"))) {
4994 fprintf (stderr, "DEBUG: Trust valexp \"%s\" @ %p\n", cmd->trust_valexp, (void *) cmd->trust_valexp);
4995                         valexp_conj [valexp_conj_count++] = cmd->trust_valexp;
4996                 }
4997                 if (cmd->lids [LID_TYPE_VALEXP - LID_TYPE_MIN].data != NULL) {
4998                         // Interpret the entry, abuse p11uri as valexp
4999                         int ok;
5000                         uint32_t flags;
5001                         char *lid_valexp;
5002                         gnutls_datum_t ignored;
5003                         ok = dbcred_interpret (
5004                                 &cmd->lids [LID_TYPE_VALEXP - LID_TYPE_MIN],
5005                                 &flags,
5006                                 &lid_valexp,
5007                                 &ignored.data,
5008                                 &ignored.size);
5009 fprintf (stderr, "DEBUG: LocalID valexp \"%s\" @ %p (ok=%d)\n", lid_valexp, (void *) lid_valexp, ok);
5010                         if (ok && (lid_valexp != NULL)) {
5011                                 valexp_conj [valexp_conj_count++] = lid_valexp;
5012                         } else {
5013                                 gtls_errno = GNUTLS_E_AUTH_ERROR;
5014                         }
5015                 }
5016 fprintf (stderr, "DEBUG: Number of valexp is %d, gtls_errno=%d\n", valexp_conj_count, gtls_errno);
5017                 // Optionally start computing the validation expression
5018                 if ((gtls_errno == GNUTLS_E_SUCCESS) && (valexp_conj_count > 0)) {
5019                         valexp_conj [valexp_conj_count] = NULL;
5020                         verun = valexp_register (
5021                                 valexp_conj,
5022                                 have_starttls_validation (),
5023                                 (void *) cmd);
5024 fprintf (stderr, "DEBUG: Registered to verun = %p\n", (void *) verun);
5025                         if (verun == NULL) {
5026                                 gtls_errno = GNUTLS_E_AUTH_ERROR;
5027                         }
5028                 }
5029                 // When setup, run the validation expressions to completion
5030                 if (verun != NULL) {
5031                         while (cmd->valexp_result == -1) {
5032                                 ; //TODO: Tickle async predicate run completion
5033                         }
5034 fprintf (stderr, "DEBUG: Finishing tickling \"async\" predicates for valexp\n");
5035                         if (cmd->valexp_result != 1) {
5036                                 tlog (TLOG_TLS, LOG_INFO, "TLS validation expression result is %d", cmd->valexp_result);
5037                                 gtls_errno = GNUTLS_E_AUTH_ERROR;
5038 fprintf (stderr, "DEBUG: valexp returns NEGATIVE result\n");
5039                         }
5040 else fprintf (stderr, "DEBUG: valexp returns POSITIVE result\n");
5041                         valexp_unregister (verun);
5042 fprintf (stderr, "DEBUG: Unregistered verun %p\n", (void *) verun);
5043                 }
5044         }
5045
5046         //
5047         // Cleanup any prefetched identities
5048         for (i=LID_TYPE_MIN; i<=LID_TYPE_MAX; i++) {
5049                 if (cmd->lids [i - LID_TYPE_MIN].data != NULL) {
5050 fprintf (stderr, "DEBUG: Freeing cmd->lids[%d].data %p\n", i-LID_TYPE_MIN, (void *)(cmd->lids [i-LID_TYPE_MIN].data));
5051                         free (cmd->lids [i - LID_TYPE_MIN].data);
5052                 }
5053         }
5054         memset (cmd->lids, 0, sizeof (cmd->lids));
5055         //
5056         // Cleanup any trust_valexp duplicate string
5057         if (cmd->trust_valexp != NULL) {
5058                 free (cmd->trust_valexp);
5059                 cmd->trust_valexp = NULL;
5060         }
5061         //
5062         // Cleanup any Kerberos session key -- it served its purpose
5063         if (cmd->krb_key.contents != NULL) {
5064                 // RATHER BLUNT: It shouldn't matter which krbctx_ is used...
5065                 krb5_free_keyblock_contents (krbctx_srv, &cmd->krb_key);
5066                 memset (&cmd->krb_key, 0, sizeof (cmd->krb_key));
5067         }
5068         if (cmd->krbid_srv != NULL) {
5069                 // RATHER BLUNT: It shouldn't matter which krbctx_ is used...
5070                 krb5_free_principal (krbctx_srv, cmd->krbid_srv);
5071                 cmd->krbid_srv = NULL;
5072         }
5073         if (cmd->krbid_cli != NULL) {
5074                 // RATHER BLUNT: It shouldn't matter which krbctx_ is used...
5075                 krb5_free_principal (krbctx_srv, cmd->krbid_cli);
5076                 cmd->krbid_cli = NULL;
5077         }
5078
5079 #if 0
5080 /* This is not proper.  gnutls_certificate_set_key() suggests that these are
5081  * automatically cleaned up, and although this is not repeated in
5082  * gnutls_certificate_set_retrieve_function2() it is likely to be related.
5083  * Plus, renegotiation with this code in place bogged down on failed pcerts;
5084  * they were detected in _gnutls_selected_cert_supported_kx() but their
5085  * key exchange algorithm was never found.
5086  */
5087         if (NULL != (void *) cmd->session_privatekey) {
5088                 gnutls_privkey_deinit ((void *) cmd->session_privatekey);
5089                 cmd->session_privatekey = (intptr_t) (void *) NULL;
5090         }
5091         if (NULL != (void *) cmd->session_certificate) {
5092                 gnutls_pcert_deinit ((void *) cmd->session_certificate);
5093                 free ((void *) cmd->session_certificate);
5094                 cmd->session_certificate = (intptr_t) (void *) NULL;
5095         }
5096 #endif
5097
5098         //
5099         // From here, assume nothing about the cmd->cmd structure; as part of
5100         // the handshake, it may have passed through the client's control, as
5101         // part of a callback.  So, reinitialise the entire return structure.
5102         //TODO// Or backup the (struct pioc_starttls) before handshaking
5103         cmd->cmd.pio_cmd = orig_cmdcode;
5104         cmd->cmd.pio_data.pioc_starttls.localid  [0] =
5105         cmd->cmd.pio_data.pioc_starttls.remoteid [0] = '\0';
5106
5107         //
5108         // Respond to positive or negative outcome of the handshake
5109         if (gtls_errno != GNUTLS_E_SUCCESS) {
5110                 tlog (TLOG_TLS, LOG_ERR, "TLS handshake failed: %s", gnutls_strerror (gtls_errno));
5111                 if (cmd->session_errno) {
5112                         char *errstr;
5113                         tlog (TLOG_TLS, LOG_ERR, "Underlying cause may be: %s", strerror (cmd->session_errno));
5114                         errstr = error_getstring ();
5115                         if (errstr == NULL) {
5116                                 errstr = "TLS handshake failed";
5117                         }
5118                         send_error (replycmd, cmd->session_errno, errstr);
5119                 } else {
5120                         send_error (replycmd, EPERM, "TLS handshake failed");
5121                 }
5122                 if (preauth) {
5123                         free (preauth);
5124                 }
5125                 if (got_session) {
5126 fprintf (stderr, "gnutls_deinit (%p) at %d\n", (void *)session, __LINE__);
5127                         gnutls_deinit (session);
5128                         got_session = 0;
5129                 }
5130                 close (cryptfd);
5131                 if (plainfd >= 0) {
5132                         close (plainfd);
5133                         plainfd = -1;
5134                 }
5135 fprintf (stderr, "ctlkey_unregister under ckn=%p at %d\n", (void *)ckn, __LINE__);
5136                 if (ckn != NULL) {      /* TODO: CHECK NEEDED? */
5137                         if (ctlkey_unregister (ckn->regent.ctlkey)) {
5138                                 free (ckn);
5139                                 ckn = NULL;
5140                         }
5141                 }
5142                 manage_txn_rollback (&cmd->txn);
5143                 assert (pthread_detach (pthread_self ()) == 0);
5144                 return NULL;
5145         } else {
5146                 tlog (TLOG_UNIXSOCK | TLOG_TLS, LOG_INFO, "TLS handshake succeeded over %d", cryptfd);
5147                 //TODO// extract_authenticated_remote_identity (cmd);
5148         }
5149
5150         //
5151         // Request the plaintext file descriptor with a callback
5152         if (plainfd < 0) {
5153                 uint32_t oldcmd = cmd->cmd.pio_cmd;
5154                 struct command *resp;
5155                 cmd->cmd.pio_cmd = PIOC_PLAINTEXT_CONNECT_V2;
5156                 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Calling send_callback_and_await_response with PIOC_PLAINTEXT_CONNECT_V2");
5157                 resp = send_callback_and_await_response (replycmd, 0);
5158                 assert (resp != NULL);  // No timeout, should be non-NULL
5159                 if (resp->cmd.pio_cmd != PIOC_PLAINTEXT_CONNECT_V2) {
5160                         tlog (TLOG_UNIXSOCK, LOG_ERR, "Callback response has unexpected command code");
5161                         send_error (replycmd, EINVAL, "Callback response has bad command code");
5162                         if (preauth) {
5163                                 free (preauth);
5164                         }
5165                         if (got_session) {
5166 fprintf (stderr, "gnutls_deinit (%p) at %d\n", (void *)session, __LINE__);
5167                                 gnutls_deinit (session);
5168                                 got_session = 0;
5169                         }
5170                         close (cryptfd);
5171 fprintf (stderr, "ctlkey_unregister under ckn=%p at %d\n", (void *)ckn, __LINE__);
5172                         if (ckn) {      /* TODO: CHECK NEEDED? PRACTICE=>YES */
5173                                 if (ctlkey_unregister (ckn->regent.ctlkey)) {
5174                                         free (ckn);
5175                                         ckn = NULL;
5176                                 }
5177                         }
5178                         manage_txn_rollback (&cmd->txn);
5179                         assert (pthread_detach (pthread_self ()) == 0);
5180                         return NULL;
5181                 }
5182                 cmd->cmd.pio_cmd = oldcmd;
5183                 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);
5184                 plainfd = resp->passfd;
5185                 resp->passfd = -1;
5186         }
5187         if (plainfd < 0) {
5188                 tlog (TLOG_UNIXSOCK, LOG_ERR, "No plaintext file descriptor supplied to TLS Pool");
5189                 send_error (replycmd, EINVAL, "No plaintext file descriptor supplied to TLS Pool");
5190                 if (preauth) {
5191                         free (preauth);
5192                 }
5193                 if (got_session) {
5194 fprintf (stderr, "gnutls_deinit (%p) at %d\n", (void *)session, __LINE__);
5195                         gnutls_deinit (session);
5196                         got_session = 0;
5197                 }
5198                 close (cryptfd);
5199 fprintf (stderr, "ctlkey_unregister under ckn=%p at %d\n", (void *)ckn, __LINE__);
5200                 if (ckn != NULL) {      /* TODO: CHECK NEEDED? */
5201                         if (ctlkey_unregister (ckn->regent.ctlkey)) {
5202                                 free (ckn);
5203                                 ckn = NULL;
5204                         }
5205                 }
5206                 manage_txn_rollback (&cmd->txn);
5207                 assert (pthread_detach (pthread_self ()) == 0);
5208                 return NULL;
5209         }
5210         //DEFERRED// send_command (replycmd, -1);               // app sent plainfd to us
5211
5212         //
5213         // Copy TLS records until the connection is closed
5214         manage_txn_commit (&cmd->txn);
5215         if (!renegotiating) {
5216                 ckn = (struct ctlkeynode_tls *) malloc (sizeof (struct ctlkeynode_tls));
5217         }
5218         if (ckn == NULL) {
5219                 send_error (replycmd, ENOMEM, "Out of memory allocating control key structure");
5220         } else {
5221                 int detach = (orig_starttls.flags & PIOF_STARTTLS_DETACH) != 0;
5222                 ckn->session = session;
5223                 ckn->owner = pthread_self ();
5224                 ckn->cryptfd = cryptfd;
5225                 ckn->plainfd = plainfd;
5226 //DEBUG// fprintf (stderr, "Registering control key\n");
5227                 if (renegotiating || (ctlkey_register (orig_starttls.ctlkey, &ckn->regent, security_tls, detach ? INVALID_POOL_HANDLE : cmd->clientfd, forked) == 0)) {
5228                         int copied = GNUTLS_E_SUCCESS;
5229                         send_command (replycmd, -1);            // app sent plainfd to us
5230                         if (preauth) {
5231
5232                                 //
5233                                 // Check on extended master secret if desired
5234                                 if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
5235 #if GNUTLS_VERSION_NUMBER >= 0x030400
5236                                         gnutls_ext_priv_data_t ext;
5237                                         if (!gnutls_ext_get_data (session, 23, &ext)) {
5238                                                 cmd->anonpre &= ~ANONPRE_EXTEND_MASTER_SECRET;
5239                                         }
5240 #endif
5241                                 }
5242                                 if (cmd->anonpre & ANONPRE_EXTEND_MASTER_SECRET) {
5243                                         tlog (TLOG_COPYCAT, LOG_ERR, "Received %d remote bytes from anonymous precursor but lacking %s-required authentication through extended master secret", orig_starttls.service);
5244                                         gtls_errno = GNUTLS_E_LARGE_PACKET;
5245                                         copied = 0;
5246
5247                                 } else if (write (plainfd, preauth, preauthlen) == preauthlen) {
5248                                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Passed on %d remote bytes from anonymous precursor to %d\n", preauthlen, plainfd);
5249                                         free (preauth);
5250                                         preauth = NULL;
5251                                         copied = copycat (plainfd, cryptfd, session, detach ? INVALID_POOL_HANDLE : cmd->clientfd);
5252                                 } else {
5253                                         tlog (TLOG_COPYCAT, LOG_DEBUG, "Failed to pass on %d remote bytes from anonymous precursor to %d\n", preauthlen, plainfd);
5254                                 }
5255                         } else {
5256                                 copied = copycat (plainfd, cryptfd, session, detach ? INVALID_POOL_HANDLE : cmd->clientfd);
5257                         }
5258                         // Renegotiate if copycat asked us to
5259                         if (copied == GNUTLS_E_REHANDSHAKE) {
5260                                 // Yes, goto is a dirty technique.  On the
5261                                 // other hand, so is forcing unstructured
5262                                 // code flows into a make-belief structure
5263                                 // that needs changing over and over again.
5264                                 // I fear goto is the most reasonable way
5265                                 // of handling this rather obtuse structure
5266                                 // of renegotiation of security in TLS :(
5267                                 //TODO// Ensure secure renegotiation!!!
5268                                 renegotiating = 1;
5269                                 replycmd = NULL; // Bypass all send_XXX()
5270                                 memcpy (&cmd_copy, cmd, sizeof (cmd_copy));
5271                                 cmd = &cmd_copy;
5272                                 memcpy (cmd->cmd.pio_data.pioc_starttls.localid, orig_starttls.localid, sizeof (cmd->cmd.pio_data.pioc_starttls.localid));
5273                                 memcpy (cmd->cmd.pio_data.pioc_starttls.remoteid, orig_starttls.remoteid, sizeof (cmd->cmd.pio_data.pioc_starttls.remoteid));
5274                                 cmd->cmd.pio_data.pioc_starttls.flags = orig_starttls.flags & ~PIOF_STARTTLS_LOCALID_CHECK;
5275                                 // Disabling the flag causing LOCALID_CHECK
5276                                 // ...and plainfd >= 0 so no PLAINTEXT_CONNECT
5277                                 // ...so there will be no callbacks to cmd
5278 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);
5279                                 goto renegotiate;
5280                         }
5281 //DEBUG// fprintf (stderr, "Unregistering control key\n");
5282                         // Unregister by ctlkey, which should always succeed
5283                         // if the TLS connection hadn't been closed down yet;
5284                         // and if it does, the memory can be freed.  Note that
5285                         // the ctlkey is not taken from the ckn, which may
5286                         // already have been freed if the ctlfd was closed
5287                         // and the connection could not continue detached
5288                         // (such as after forking it).
5289 fprintf (stderr, "ctlkey_unregister under ckn=%p at %d\n", (void *)ckn, __LINE__);
5290                         if (ctlkey_unregister (orig_starttls.ctlkey)) {
5291                                 free (ckn);
5292                         }
5293                         ckn = NULL;
5294 //DEBUG// fprintf (stderr, "Unregistered  control key\n");
5295                 } else {
5296                         send_error (replycmd, ENOENT, "Failed to register control key for TLS connection");
5297                 }
5298         }
5299         if (preauth) {
5300                 free (preauth);
5301                 preauth = NULL;
5302         }
5303         close (plainfd);
5304         close (cryptfd);
5305         cleanup_any_remote_credentials (cmd);
5306         if (got_session) {
5307 fprintf (stderr, "gnutls_deinit (%p) at %d\n", (void *)session, __LINE__);
5308                 gnutls_deinit (session);
5309                 got_session = 0;
5310         }
5311         assert (pthread_detach (pthread_self ()) == 0);
5312         return NULL;
5313 }
5314
5315
5316 /*
5317  * The starttls function responds to an application's request to
5318  * setup TLS for a given file descriptor, and return a file descriptor
5319  * with the unencrypted view when done.  The main thing done here is to
5320  * spark off a new thread that handles the operations.
5321  */
5322 void starttls (struct command *cmd) {
5323         /* Create a thread and, if successful, wait for it to unlock cmd */
5324         errno = pthread_create (&cmd->handler, NULL, starttls_thread, (void *) cmd);
5325         if (errno != 0) {
5326                 send_error (cmd, ESRCH, "STARTTLS thread refused");
5327                 return;
5328         }
5329 //TODO:TEST// Thread detaches itself before terminating w/o followup
5330 /*
5331         errno = pthread_detach (cmd->handler);
5332         if (errno != 0) {
5333                 pthread_cancel (cmd->handler);
5334                 send_error (cmd, ESRCH, "STARTTLS thread detachment refused");
5335                 return;
5336         }
5337 */
5338 }
5339
5340
5341 /*
5342  * Run the PRNG for a TLS connection, identified by its control key.  If the connection
5343  * is not a TLS connection, or if the control key is not found, reply with ERROR;
5344  * otherwise, the session should help to create pseudo-random bytes.
5345  */
5346 void starttls_prng (struct command *cmd) {
5347         uint8_t in1 [TLSPOOL_PRNGBUFLEN];
5348         uint8_t in2 [TLSPOOL_PRNGBUFLEN];
5349         int16_t in1len, in2len, prnglen;
5350         struct ctlkeynode_tls *ckn = NULL;
5351         char **prefixes;
5352         int err = 0;
5353         int gtls_errno = GNUTLS_E_SUCCESS;
5354         struct pioc_prng *prng = &cmd->cmd.pio_data.pioc_prng;
5355         //
5356         // Find arguments and validate them
5357         in1len  = prng->in1_len;
5358         in2len  = prng->in2_len;
5359         prnglen = prng->prng_len;
5360         err = err || (in1len <= 0);
5361         err = err || (prnglen > TLSPOOL_PRNGBUFLEN);
5362         err = err || ((TLSPOOL_CTLKEYLEN + in1len + (in2len >= 0? in2len: 0))
5363                                 > TLSPOOL_PRNGBUFLEN);
5364         if (!err) {
5365                 memcpy (in1, prng->buffer + TLSPOOL_CTLKEYLEN         , in1len);
5366                 if (in2len > 0) {
5367                         memcpy (in2, prng->buffer + TLSPOOL_CTLKEYLEN + in1len, in2len);
5368                 }
5369         }
5370         //  - check the label string
5371         prefixes = tlsprng_label_prefixes;
5372         while ((!err) && (*prefixes)) {
5373                 char *pf = *prefixes++;
5374                 if (strlen (pf) != in1len) {
5375                         continue;
5376                 }
5377                 if (strcmp (pf, (const char *)in1) != 0) {
5378                         continue;
5379                 }
5380         }
5381         if (*prefixes == NULL) {
5382                 // RFC 5705 defines a private-use prefix "EXPERIMENTAL"
5383                 if ((in1len <= 12) || (strncmp ((const char *)in1, "EXPERIMENTAL", 12) != 0)) {
5384                         err = 1;
5385                 }
5386         }
5387         //  - check the ctlkey (and ensure it is for TLS)
5388         if (!err) {
5389 //DEBUG// fprintf (stderr, "Hoping to find control key\n");
5390                 ckn = (struct ctlkeynode_tls *) ctlkey_find (prng->buffer, security_tls, cmd->clientfd);
5391         }
5392         //
5393         // Now wipe the PRNG buffer to get rid of any sensitive bytes
5394         memset (prng->buffer, 0, TLSPOOL_PRNGBUFLEN);
5395         //
5396         // If an error occurrend with the command, report it now
5397         if (err) {
5398                 send_error (cmd, EINVAL, "TLS PRNG request invalid");
5399                 // ckn is NULL if err != 0, so no need for ctlkey_unfind()
5400                 return;
5401         }
5402         if (ckn == NULL) {
5403                 send_error (cmd, ENOENT, "Invalid control key");
5404                 return;
5405         }
5406         //
5407         // Now actually invoke the PRNG command in the GnuTLS backend
5408         errno = 0;
5409         E_g2e ("GnuTLS PRNG based on session master key failed",
5410                 gnutls_prf_rfc5705 (ckn->session,
5411                         in1len, (const char *)in1,
5412                         (in2len >= 0)? in2len: 0,
5413                         (const char *)((in2len >= 0) ? in2: NULL),
5414                         prnglen, (char *)prng->buffer));
5415         err = err || (errno != 0);
5416         //
5417         // Wipe temporary data / buffers for security reasons
5418         memset (in1, 0, sizeof (in1));
5419         memset (in2, 0, sizeof (in2));
5420         ctlkey_unfind ((struct ctlkeynode *) ckn);
5421         //
5422         // Return the outcome to the user
5423         if (err) {
5424                 send_error (cmd, errno? errno: EIO, "PRNG in TLS backend failed");
5425         } else {
5426                 send_command (cmd, -1);
5427         }
5428 }
5429
5430
5431 /* Flying signer functionality.  Create an on-the-fly certificate because
5432  * the lidentry daemon and/or application asks for this to represent the
5433  * local identity.  Note that this will only work if the remote party
5434  * accepts the root identity under which on-the-signing is done.
5435  *
5436  * When no root credentials have been configured, this function will
5437  * fail with GNUTLS_E_AGAIN; it may be used as a hint to try through
5438  * other (more conventional) means to obtain a client certificate.
5439  *
5440  * The API of this function matches that of fetch_local_credentials()
5441  * and that is not a coincidence; this is a drop-in replacement in some
5442  * cases.
5443  *
5444  * Limitations: The current implementation only supports X.509 certificates
5445  * to be generated on the fly.  So, this will set LID_TYPE_X509, if anything.
5446  */
5447 gtls_error certificate_onthefly (struct command *cmd) {
5448         gtls_error gtls_errno = GNUTLS_E_SUCCESS;
5449         gnutls_x509_crt_t otfcert;
5450         time_t now;
5451         gnutls_x509_subject_alt_name_t altnmtp;
5452         int i;
5453
5454         //
5455         // Sanity checks
5456         if ((onthefly_issuercrt == NULL) || (onthefly_issuerkey == NULL) || (onthefly_subjectkey == NULL)) {
5457                 // Not able to supply on-the-fly certificates; try someway else
5458                 return GNUTLS_E_AGAIN;
5459         }
5460         if (cmd->cmd.pio_data.pioc_starttls.localid [0] == '\0') {
5461                 return GNUTLS_E_NO_CERTIFICATE_FOUND;
5462         }
5463         if (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data != NULL) {
5464                 free (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data);
5465                 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data = NULL;
5466                 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
5467         }
5468
5469         //
5470         // Create an empty certificate
5471         E_g2e ("Failed to initialise on-the-fly certificate",
5472                 gnutls_x509_crt_init (&otfcert));
5473         if (gtls_errno != GNUTLS_E_SUCCESS) {
5474                 return gtls_errno;
5475         }
5476
5477         //
5478         // Fill the certificate with the usual field
5479         E_g2e ("Failed to set on-the-fly certificate to non-CA mode",
5480                 gnutls_x509_crt_set_ca_status (otfcert, 0));
5481         E_g2e ("Failed to set on-the-fly certificate version",
5482                 gnutls_x509_crt_set_version (otfcert, 3));
5483         onthefly_serial++;      //TODO// Consider a random byte string
5484         E_g2e ("Failed to set on-the-fly serial number",
5485                 gnutls_x509_crt_set_serial (otfcert, &onthefly_serial, sizeof (onthefly_serial)));
5486         // Skip gnutls_x509_crt_set_issuer_by_dn_by_oid(), added when signing
5487         time (&now);
5488         E_g2e ("Failed to set on-the-fly activation time to now - 2 min",
5489                 gnutls_x509_crt_set_activation_time (otfcert, now - 120));
5490         E_g2e ("Failed to set on-the-fly expiration time to now + 3 min",
5491                 gnutls_x509_crt_set_expiration_time (otfcert, now + 180));
5492         E_g2e ("Setup certificate CN with local identity",
5493                 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? */
5494         E_g2e ("Setup certificate OU with TLS Pool on-the-fly",
5495                 gnutls_x509_crt_set_dn_by_oid (otfcert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, "TLS Pool on-the-fly", 19));
5496         if (strchr (cmd->cmd.pio_data.pioc_starttls.localid, '@')) {
5497                 // localid has the format of an emailAddress
5498                 altnmtp = GNUTLS_SAN_RFC822NAME;
5499         } else {
5500                 // localid has the format of a dnsName
5501                 altnmtp = GNUTLS_SAN_DNSNAME;
5502         }
5503         E_g2e ("Failed to set subjectAltName to localid",
5504                 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));
5505         //TODO:SKIP, hoping that signing adds: gnutls_x509_crt_set_authority_key_id()
5506         //TODO:SKIP, hoping that a cert without also works: gnutls_x509_crt_set_subjectkey_id()
5507         //TODO:SKIP? gnutls_x509_crt_set_extension_by_oid
5508         //TODO:      gnutls_x509_crt_set_key_usage
5509         //TODO:SKIP? gnutls_x509_crt_set_ca_status
5510         for (i=0; i < svcusage_registry_size; i++) {
5511                 if (strcmp (svcusage_registry [i].service, (const char *)(cmd->cmd.pio_data.pioc_starttls.service)) == 0) {
5512                         const char **walker;
5513                         E_g2e ("Failed to setup basic key usage during on-the-fly certificate creation",
5514                                 gnutls_x509_crt_set_key_usage (otfcert, svcusage_registry [i].usage));
5515                         walker = svcusage_registry [i].oids_non_critical;
5516                         if (walker) {
5517                                 while (*walker) {
5518                                         E_g2e ("Failed to append non-critical extended key purpose during on-the-fly certificate creation",
5519                                                 gnutls_x509_crt_set_key_purpose_oid (otfcert, *walker, 0));
5520                                         walker++;
5521                                 }
5522                         }
5523                         walker = svcusage_registry [i].oids_critical;
5524                         if (walker) {
5525                                 while (*walker) {
5526                                         E_g2e ("Failed to append critical extended key purpose during on-the-fly certificate creation",
5527                                                 gnutls_x509_crt_set_key_purpose_oid (otfcert, *walker, 1));
5528                                         walker++;
5529                                 }
5530                         }
5531                         break;
5532                 }
5533         }
5534         E_g2e ("Failed to et the on-the-fly subject key",
5535                 gnutls_x509_crt_set_key (otfcert, onthefly_subjectkey));
5536         /* TODO: The lock below should not be necessary; it is handled by p11-kit
5537          *       or at least it ought to be.  What I found however, was that
5538          *       a client and server would try to use the onthefly_issuerkey
5539          *       at virtually the same time, and then the second call to
5540          *       C_SignInit returns CKR_OPERATION_ACTIVE.  The lock solved this.
5541          *       This makes me frown about server keys stored in PKCS #11...
5542          */
5543 {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"); } }
5544         assert (pthread_mutex_lock (&onthefly_signer_lock) == 0);
5545         E_g2e ("Failed to sign on-the-fly certificate",
5546                 gnutls_x509_crt_privkey_sign (otfcert, onthefly_issuercrt, onthefly_issuerkey, GNUTLS_DIG_SHA256, 0));
5547         pthread_mutex_unlock (&onthefly_signer_lock);
5548
5549         //
5550         // Construct cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data+size for this certificate
5551         cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
5552         if (gtls_errno == GNUTLS_E_SUCCESS) {
5553                 gtls_errno = gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_DER, NULL, &cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size);
5554                 if (gtls_errno == GNUTLS_E_SHORT_MEMORY_BUFFER) {
5555                         // This is as expected, now .size will have been set
5556                         gtls_errno = GNUTLS_E_SUCCESS;
5557                 } else {
5558                         if (gtls_errno == GNUTLS_E_SUCCESS) {
5559                                 // Something must be wrong if we receive OK
5560                                 gtls_errno = GNUTLS_E_INVALID_REQUEST;
5561                         }
5562                 }
5563                 E_g2e ("Error while measuring on-the-fly certificate size",
5564                         gtls_errno);
5565         }
5566         uint8_t *ptr = NULL;
5567         if (gtls_errno == GNUTLS_E_SUCCESS) {
5568                 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size += 4 + strlen (onthefly_p11uri) + 1;
5569                 ptr = malloc (cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size);
5570                 if (ptr == NULL) {
5571                         cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size = 0;
5572                         gnutls_x509_crt_deinit (otfcert);
5573                         return GNUTLS_E_MEMORY_ERROR;
5574                 }
5575         }
5576         if (ptr != NULL) {
5577                 size_t restsz;
5578                 cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].data = ptr;
5579                 * (uint32_t *) ptr = htonl (LID_TYPE_X509 | LID_ROLE_BOTH);
5580                 ptr += 4;
5581                 strcpy ((char *)ptr, onthefly_p11uri);
5582                 ptr += strlen (onthefly_p11uri) + 1;
5583                 restsz = cmd->lids [LID_TYPE_X509 - LID_TYPE_MIN].size - 4 - strlen (onthefly_p11uri) - 1;
5584                 E_g2e ("Failed to export on-the-fly certificate as a credential",
5585                         gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_DER, ptr, &restsz));
5586 char pembuf [10000];
5587 size_t pemlen = sizeof (pembuf) - 1;
5588 int exporterror = gnutls_x509_crt_export (otfcert, GNUTLS_X509_FMT_PEM, pembuf, &pemlen);
5589 if (exporterror == 0) {
5590 pembuf [pemlen] = '\0';
5591 fprintf (stderr, "DEBUG: otfcert ::=\n%s\n", pembuf);
5592 } else {
5593 fprintf (stderr, "DEBUG: otfcert export to PEM failed with %d, gtls_errno already was %d\n", exporterror, gtls_errno);
5594 }
5595         }
5596
5597         //
5598         // Cleanup the allocated and built structures
5599         gnutls_x509_crt_deinit (otfcert);
5600
5601         //
5602         // Return the overall result that might have stopped otf halfway
5603         return gtls_errno;
5604 }
5605