+ Support for all of X.509, OpenPGP and SRP schemes (undecided on PSK)
+ Extension of GnuTLS' PKCS #11 support to OpenPGP, PSK and SRP
- TOFU callbacks and storage of (signed?) acceptance
-- Incorporate session resumption (on both ends) (store creds in database?)
+- Incorporate session resumption (on both ends) (store creds in memcache?)
- Key derivation API with the PRF functionality of TLS 1.2 (RFC 5705)
+- RFC 5705: repeated seeding labels? overlap proto-fixed ones? session revival?
+ Error translation from GnuTLS and BerkeleyDB to errno (with detail report)
+ Transactions for an entire thread
- Thread cleanup with pthread_setcanceltype(), pthread_cleanup_push()
- Regularly refresh DH parameters ; find out how to apply refcnt and/or locks
- Introduce (at least a basic form of) certificate validation
+ Support X.509 certificate chains
-- Derive GnuTLS priority string automatically from credentials for localid
++ Derive GnuTLS priority string automatically from credentials for localid
+ Migrate from fprintf (stderr, ...) to syslog()
- Migrate from file-based SRP to SRP #11 when GnuTLS offers it
- Add support for TLS-KDH when GnuTLS offers it
+ Move database environment and names into configuration parameters
+ Move DH params file to a configuration parameter
+- Explain how to generate X.509 and GnuPG certificates with PKCS #11
+- Recognise callbacks with a "same" file handle as session access requests
+- Move PID file handling to daemon.c; make -k switch after new initialisation
.c.o:
gcc -ggdb3 -pthread -I ../include -I /usr/local/include -I /usr/include/p11-kit-1 -c -o $@ $<
-tlspool: daemon.o config.o manage.o service.o cache.o pinentry.o handler.o localid.o remote.o error.o
- @# gcc -ggdb3 -pthread -o $@ daemon.o config.o manage.o service.o cache.o pinentry.o handler.o localid.o remote.o error.o -L /usr/local/lib -L /usr/lib -L /usr/lib/x86_64-linux-gnu -lgnutls -ldb -lmemcached -lldap -lp11-kit -ltasn1
- gcc -ggdb3 -pthread -o $@ daemon.o config.o manage.o service.o cache.o pinentry.o handler.o localid.o remote.o error.o -L /usr/local/lib -L /usr/lib -L /usr/lib/x86_64-linux-gnu -ldb -lgnutls -lp11-kit -ltasn1
- @#STATLINK# gcc -ggdb3 -pthread -o $@ daemon.o config.o manage.o service.o cache.o pinentry.o handler.o localid.o remote.o error.o -L /usr/local/lib -L /usr/lib -L /usr/lib/x86_64-linux-gnu /usr/lib/libdb.a /usr/local/lib/libgnutls.a /usr/local/lib/libnettle.a /usr/local/lib/libhogweed.a /usr/lib/libgmp.a /usr/local/lib/libp11-kit.so /usr/lib/libz.a /usr/lib/libtasn1.a
+tlspool: daemon.o config.o manage.o service.o cache.o pinentry.o handler.o donai.o remote.o error.o
+ @# gcc -ggdb3 -pthread -o $@ daemon.o config.o manage.o service.o cache.o pinentry.o handler.o donai.o remote.o error.o -L /usr/local/lib -L /usr/lib -L /usr/lib/x86_64-linux-gnu -lgnutls -ldb -lmemcached -lldap -lp11-kit -ltasn1
+ gcc -ggdb3 -pthread -o $@ daemon.o config.o manage.o service.o cache.o pinentry.o handler.o donai.o remote.o error.o -L /usr/local/lib -L /usr/lib -L /usr/lib/x86_64-linux-gnu -ldb -lgnutls -lp11-kit -ltasn1
+ @#STATLINK# gcc -ggdb3 -pthread -o $@ daemon.o config.o manage.o service.o cache.o pinentry.o handler.o donai.o remote.o error.o -L /usr/local/lib -L /usr/lib -L /usr/lib/x86_64-linux-gnu /usr/lib/libdb.a /usr/local/lib/libgnutls.a /usr/local/lib/libnettle.a /usr/local/lib/libhogweed.a /usr/lib/libgmp.a /usr/local/lib/libp11-kit.so /usr/lib/libz.a /usr/lib/libtasn1.a
#
--- /dev/null
+/* tlspool/localid.c -- Map the keys of local identities to credentials */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <syslog.h>
+#include <errno.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/abstract.h>
+
+#include <tlspool/internal.h>
+
+#include "manage.h"
+#include "donai.h"
+
+
+/*
+ * Lookup local identities from a BDB database. The identities take the
+ * form of a NAI, and are the keys for a key-values lookup. The outcome
+ * may offer multiple values, each representing an identity. The general
+ * structure of a value is:
+ *
+ * - 4 netbytes, a flags field for local identity management (see LID_xxx below)
+ * - NUL-terminated string with a pkcs11 URI [ draft-pechanec-pkcs11uri ]
+ * - Binary string holding the identity in binary form
+ *
+ * There may be prefixes for generic management, but these are not made
+ * available to this layer.
+ */
+
+
+
+/* Retrieve flags from the credentials structure found in dbh_localid.
+ * The function returns non-zero on success (zero indicates syntax error).
+ */
+int dbcred_flags (DBT *creddata, uint32_t *flags) {
+ int p11privlen;
+ if (creddata->size <= 4) {
+ return 0;
+ }
+ *flags = ntohl (* (uint32_t *) creddata->data);
+ return 1;
+}
+
+
+/* Interpret the credentials structure found in dbh_localid.
+ * This comes down to splitting the (data,size) structure into fields:
+ * - a 32-bit flags field
+ * - a char * sharing the PKCS #11 private key location, NULL on LID_NO_PKCS11
+ * - a (data,size) structure for the public credential, also when LID_CHAINED
+ * The function returns non-zero on success (zero indicates syntax error).
+ */
+int dbcred_interpret (gnutls_datum_t *creddata, uint32_t *flags, char **p11priv, uint8_t **pubdata, int *pubdatalen) {
+ int p11privlen;
+ if (creddata->size <= 4) {
+ return 0;
+ }
+ *flags = ntohl (* (uint32_t *) creddata->data);
+ if ((*flags) & LID_NO_PKCS11) {
+ *p11priv = NULL;
+ } else {
+ *p11priv = ((char *) creddata->data) + 4;
+ p11privlen = strnlen (*p11priv, creddata->size - 4);
+ if (p11privlen == creddata->size - 4) {
+ return 0;
+ }
+#ifdef TODO_PKCS11_ADDED
+ if (strncmp (*p11priv, "pkcs11:", 7) != 0) {
+ return 0;
+ }
+#endif
+ }
+ *pubdata = ((uint8_t *) creddata->data) + 4 + p11privlen + 1;
+ *pubdatalen = creddata->size - 4 - p11privlen - 1;
+ if (*pubdatalen < 20) {
+ // Unbelievably short certificate (arbitrary sanity limit 20)
+ return 0;
+ }
+ return 1;
+}
+
+
+/* Create an iterator for a given localid value. Use keys from dhb_lid.
+ * The first value is delivered; continue with dbcred_iterate_next().
+ *
+ * The cursor must have been opened on dbh_localid within the desired
+ * transaction context; the caller must close it after iteration.
+ *
+ * The value returned is only non-zero if a value was setup.
+ * The DB_NOTFOUND value indicates that the key was not found.
+ */
+gtls_error dbcred_iterate_from_localid (DBC *cursor, DBT *keydata, DBT *creddata) {
+ int gtls_errno = GNUTLS_E_SUCCESS;
+ E_d2ge ("Key not found in db_localid",
+ cursor->get (cursor, keydata, creddata, DB_SET));
+ return gtls_errno;
+}
+
+
+/* Construct an iterator for a given remoteid selector. Apply stepwise
+ * generalisation to find the most concrete match. The first value found
+ * is delivered; continue with dbcred_iterate_next().
+ *
+ * The remotesel value in string representation is the key to discpatn,
+ * forming the initial disclosure pattern. This key should be setup with
+ * enough space to store the pattern (which is never longer than the original
+ * remoteid) plus a terminating NUL character.
+ *
+ * Note that remotesel already has the first value activated, usually the
+ * same as the remoteid. This is assumed to be available, so don't call
+ * this function otherwise. In practice, this is hardly a problem; any
+ * valid remoteid will provide a valid selector whose first iteration is to
+ * repeat the remoteid. Failure to start even this is a sign of a syntax
+ * error, which is good to be treating separately from not-found conditions.
+ *
+ * The started iteration is a nested iteration over dbh_disclose for the
+ * pattern found, and inside that an iteration over dbh_localid for the
+ * localid values that this gave. This means that two cursors are needed,
+ * both here and in the subsequent dbcred_iterate_next() calls.
+ *
+ * The cursors crs_disclose and crs_localid must have been opened on
+ * dbh_disclose and dbh_localid within the desired transaction context;
+ * the caller must close them after iteration.
+ *
+ * The value returned is zero if a value was setup; otherwise an error code.
+ * The DB_NOTFOUND value indicates that no selector matching the remoteid
+ * was found in dbh_disclose.
+ */
+gtls_error dbcred_iterate_from_remoteid_selector (DBC *crs_disclose, DBC *crs_localid, selector_t *remotesel, DBT *discpatn, DBT *keydata, DBT *creddata) {
+ int gtls_errno = GNUTLS_E_SUCCESS;
+ int more = 1;
+ while (more) {
+ int fnd;
+ discpatn->size = donai_iterate_memput (discpatn->data, remotesel);
+ tlog (TLOG_DB, LOG_DEBUG, "Looking up remote selector %.*s", discpatn->size, (char *) discpatn->data);
+ fnd = crs_disclose->get (crs_disclose, discpatn, keydata, DB_SET);
+ if (fnd == 0) {
+ // Got the selector pattern!
+ // Now continue, even when no localids will work.
+ E_d2ge ("Key not found in db_localid",
+ crs_localid->get (
+ crs_localid,
+ keydata,
+ creddata,
+ DB_SET));
+ return gtls_errno;
+ } else if (fnd != DB_NOTFOUND) {
+ E_d2ge ("Failed while searching with remote ID selector", fnd);
+ break;
+ }
+ more = selector_iterate_next (remotesel);
+ }
+ // Ended here with nothing more to find
+ E_d2ge ("No selector matches remote ID in db_disclose",
+ DB_NOTFOUND);
+ return gtls_errno;
+}
+
+
+/* Move an iterator to the next credential data value. When done, the value
+ * returned should be DB_NOTFOUND.
+ *
+ * The outer cursor (for dbh_disclose) is optional, and is only used when
+ * the prior call was from dbcred_iterate_from_remoteid().
+ *
+ * The optional discpatn must be supplied only when dbh_disclose is provided.
+ * It holds the key value for the dbh_disclose outer cursor.
+ *
+ * The keydata will be filled with the intermediate key when dbh_disclose is
+ * provided. It is also used to match the next record with the current one.
+ *
+ * The value returned is zero if a value was setup; otherwise an error code.
+ * The DB_NOTFOUND value indicates that no further duplicate was not found.
+ */
+db_error dbcred_iterate_next (DBC *opt_crs_disclose, DBC *crs_localid, DBT *opt_discpatn, DBT *keydata, DBT *creddata) {
+ int db_errno = 0;
+ db_errno = crs_localid->get (crs_localid, keydata, creddata, DB_NEXT_DUP);
+ if (db_errno != DB_NOTFOUND) {
+ return db_errno;
+ }
+ // Inner loop ended in DB_NOTFOUND, optionally continue in outer loop
+ if ((opt_crs_disclose != NULL) && (opt_discpatn != NULL)) {
+ while (db_errno == DB_NOTFOUND) {
+ db_errno = opt_crs_disclose->get (opt_crs_disclose, opt_discpatn, keydata, DB_NEXT_DUP);
+ if (db_errno == DB_NOTFOUND) {
+ return db_errno;
+ }
+ db_errno = crs_localid->get (crs_localid, keydata, creddata, DB_SET);
+ }
+ }
+ return db_errno;
+}
+
+
+/* Iterate over selector values that would generalise the donai. The
+ * selector_t shares data from the donai, so it allocates no internal
+ * storage and so it can be dropped at any time during the iteration.
+ * Meanwhile, the donai must not drop storage before iteration stops.
+ *
+ * The value returned is only non-zero if a value was setup.
+ */
+int selector_iterate_init (selector_t *iterator, donai_t *donai) {
+ //
+ // If the user name is not NULL but empty, bail out in horror
+ if ((donai->user != NULL) && (donai->userlen <= 0)) {
+ return 0;
+ }
+ //
+ // If the domain name is empty or NULL, bail out in horror
+ if ((donai->domain == NULL) || (donai->domlen == 0)) {
+ return 0;
+ }
+ //
+ // The first and most concrete pattern is the donai itself
+ memcpy (iterator, donai, sizeof (*iterator));
+ return 1;
+}
+
+int selector_iterate_next (selector_t *iterator) {
+ int skip;
+ //
+ // If the user name is not NULL but empty, bail out in horror
+ if ((iterator->user != NULL) && (iterator->userlen == 0)) {
+ return 0;
+ }
+ //
+ // If the domain name is empty or NULL, bail out in horror
+ if ((iterator->domain == NULL) || (iterator->domlen == 0)) {
+ return 0;
+ }
+ //
+ // If there is a user component and it is non-empty, make it empty
+ // If it was empty, permit it to become non-empty again, and continue
+ if (iterator->user) {
+ if (iterator->userlen > 0) {
+ iterator->userlen = -iterator->userlen;
+ return 1;
+ }
+ iterator->userlen = -iterator->userlen;
+ }
+ //
+ // If the domain is a single dot, we're done
+ if ((iterator->domlen == 1) && (*iterator->domain == '.')) {
+ return 0;
+ }
+ //
+ // Replace the domain (known >= 1 chars) with the next dot's domain
+ skip = 1;
+ while ((skip < iterator->domlen) && (iterator->domain [skip] != '.')) {
+ skip++;
+ }
+ if (skip == iterator->domlen) {
+ iterator->domain = "."; // Last resort domain
+ iterator->domlen = 1;
+ } else {
+ iterator->domain += skip;
+ iterator->domlen -= skip;
+ }
+ return 1;
+}
+
+
+/* Check if a selector is a pattern that matches the given donai value.
+ * The value returned is non-zero for a match, zero for a non-match.
+ */
+int donai_matches_selector (donai_t *donai, selector_t *pattern) {
+ int extra;
+ //
+ // Bail out in horror on misconfigurations
+ if ((donai->user != NULL) && (donai->userlen <= 0)) {
+ return 0;
+ }
+ if ((donai ->domain == NULL) || (donai ->domlen <= 0)) {
+ return 0;
+ }
+ if ((pattern->domain == NULL) || (pattern->domlen <= 0)) {
+ return 0;
+ }
+ //
+ // User name handling first
+ if (pattern->user) {
+ //
+ // Pattern has a user? Then request a user in the donai too
+ if (donai->user == NULL) {
+ return 0;
+ }
+ //
+ // Non-empty user in pattern? Then match everything
+ if (*pattern->user) {
+ if (pattern->userlen > 0) {
+ if (donai->userlen != pattern->userlen) {
+ return 0;
+ }
+ if (memcmp (donai->user, pattern->user, donai->userlen) != 0) {
+ return 0;
+ }
+ }
+ }
+ } else {
+ //
+ // Pattern without user, then donai may not have one either
+ if (donai->user != NULL) {
+ return 0;
+ }
+ }
+ //
+ // Domain name handling second
+ if (*pattern->domain == '.') {
+ extra = donai->domlen - pattern->domlen;
+ if (extra < 0) {
+ //
+ // No good having a longer pattern than a donai.domain
+ return 0;
+ }
+ } else {
+ extra = 0;
+ }
+ return (memcmp (donai->domain + extra, pattern->domain, pattern->domlen) == 0);
+}
+
+
+/* Fill a donai structure from a stable string. The donai will share parts
+ * of the string. The function can also be used to construct a selector
+ * from a string; their structures are the same and the syntax is not
+ * parsed to ensure non-empty usernames and non-dot-prefixed domain names.
+ */
+donai_t donai_from_stable_string (char *stable, int stablelen) {
+ donai_t retval;
+ retval.userlen = stablelen - 1;
+ while (retval.userlen > 0) {
+ if (stable [retval.userlen] == '@') {
+ break;
+ }
+ retval.userlen--;
+ }
+ if (stable [retval.userlen] == '@') {
+ retval.user = stable;
+ retval.domain = stable + (retval.userlen + 1);
+ retval.domlen = stablelen - 1 - retval.userlen;
+ } else {
+ retval.user = NULL;
+ retval.domain = stable;
+ retval.domlen = stablelen;
+ }
+ return retval;
+}
+
+/* Print a donai or iterated selector to the given text buffer. The
+ * text will be precisely the same as the originally parsed text. An
+ * iterator may deliver values that are shorter, not longer. The value
+ * returned is the number of bytes written. No trailing NUL character
+ * will be written.
+ */
+int donai_iterate_memput (char *selector_text, donai_t *iterator) {
+ int len = 0;
+ if (iterator->user != NULL) {
+ if (iterator->userlen > 0) {
+ memcpy (selector_text, iterator->user, iterator->userlen);
+ len += iterator->userlen;
+ }
+ selector_text [len++] = '@';
+ }
+ memcpy (selector_text + len, iterator->domain, iterator->domlen);
+ len += iterator->domlen;
+ return len;
+}
+
--- /dev/null
+/* tlspool/localid.h -- Map the keys of local identities to credentials */
+
+
+/*
+ * Lookup local identities from a BDB database. The identities take the
+ * form of a NAI, and are the keys for a key-values lookup. The outcome
+ * may offer multiple values, each representing an identity. The general
+ * structure of a value is:
+ *
+ * - 4 netbytes, a flags field for local identity management (see LID_xxx below)
+ * - NUL-terminated string with a pkcs11 URI [ draft-pechanec-pkcs11uri ]
+ * - Binary string holding the identity in binary form
+ *
+ * There may be prefixes for generic management, but these are not made
+ * available to this layer.
+ */
+
+
+#define LID_HDRSZ (MGT_HDRSZ + 4)
+
+
+#define LID_TYPE_MASK 0x000000ff /* Separate out the LID_TYPE_xxx bits */
+#define LID_TYPE_ANY 0x000000ff /* No filter, permit anything */
+#define LID_TYPE_X509 0x00000001 /* X.509 certificate, DER-encoded */
+#define LID_TYPE_PGP 0x00000002 /* OpenPGP public key, binary form */
+#define LID_TYPE_SRP 0x00000003 /* No data, flags existence */
+#define LID_TYPE_KRB5 0x00000004 /* Ticket */
+
+#define LID_TYPE_MIN LID_TYPE_X509
+#define LID_TYPE_MAX LID_TYPE_KRB5
+#define LID_TYPE_OFS LID_TYPE_MIN
+#define LID_TYPE_CNT (1 + LID_TYPE_MAX - LID_TYPE_MIN)
+
+#define LID_ROLE_MASK 0x00000300 /* Separate out the LID_ROLE_xxx bits */
+#define LID_ROLE_CLIENT 0x00000100 /* This may be used for clients */
+#define LID_ROLE_SERVER 0x00000200 /* This may be used for servers */
+#define LID_ROLE_BOTH 0x00000300 /* This may be used for both roles */
+#define LID_ROLE_NONE 0x00000000 /* This may be used for neither role */
+
+#define LID_NO_PKCS11 0x00001000 /* No prefixed PKCS #11 URI + NUL */
+#define LID_CHAINED 0x00002000 /* Credential isa type-specific chain */
+//TODO// Encode LID_NEEDS_CHAIN support
+#define LID_NEEDS_CHAIN 0x00004000 /* Chain certs are in central storage */
+
+
+/* Impose a practial upper bound to the lenght of a DoNAI, a domain-or-NAI.
+ * This is important to avoid overzealous allocations and subsequent buffer
+ * or stack overflows. Sigh, we live in a world where networks can carry
+ * the size between memory segments in a brief time.
+ */
+#define DONAI_MAXLEN 512
+
+
+/* A donai is a structure holding either user@domain.name or domain.name.
+ * A selector is a simple pattern that can match with a donain, by stripping
+ * local components. For instance user@domain.name or @domain.name or @.name
+ * or @. to match with user@domain.name; and, for instance domain.name or
+ * .name or . to match with domain.name.
+ */
+
+struct userdomain {
+ char *user; /* not NUL-terminated; user==NULL for no @ at all */
+ int userlen; /* valid if user!=NULL; userlen<0 in selector_t for 0 */
+ char *domain; /* not NULL, start . signifies a pattern */
+ int domlen; /* always >0 */
+};
+
+
+typedef struct userdomain donai_t; /* (user==NULL OR userlen>0) AND *domain!='.' */
+
+typedef struct userdomain selector_t; /* userlen<0 should be read as userlen==0 */
+
+
+
+/* Setup a DBT data handle to point to a pre-allocated, fixed-size
+ * data buffer that will be used throughout the use of the handle.
+ * Cleanup is not necessary, but the buffer must not be cleared
+ * before the last use of the data handle.
+ */
+static inline void dbt_init_fixbuf (DBT *dbt, void *buffer, u_int32_t bufsize) {
+ bzero (dbt, sizeof (DBT));
+ dbt->data = buffer;
+ dbt->size =
+ dbt->ulen = bufsize;
+ dbt->flags |= DB_DBT_USERMEM;
+}
+
+/* Setup a DBT data handle for malloc() by the database, and free() by the
+ * calling program.
+ * Cleanup with dbt_free() or dbt_store() is needed after every lookup
+ * that succeeded.
+ */
+static inline void dbt_init_malloc (DBT *dbt) {
+ bzero (dbt, sizeof (DBT));
+ dbt->flags |= DB_DBT_MALLOC;
+}
+
+/* Free the DBT data handle that was setup with dbt_init_malloc(). This
+ * or dbt_store() must be called after every successfully returned data
+ * item.
+ */
+static inline void dbt_free (DBT *dbt) {
+ /* assert (dbt->flags & DB_DBT_MALLOC); */
+ free (dbt->data);
+ dbt->data = NULL;
+}
+
+/* Store the DBT data handle's data into external structures, moving both
+ * the data pointer and size. The data handle must have been setup with
+ * dbt_init_malloc(). Afterwards, clear the data handle for use in
+ * another iteration.
+ */
+static inline void dbt_store (DBT *dbt, gnutls_datum_t *output) {
+ /* assert (dbt->flags & DB_DBT_MALLOC); */
+ output->data = dbt->data;
+ output->size = dbt->size;
+ dbt->data = NULL;
+}
+
+
+/* Create an iterator for a given localid value. Use keys from dhb_lid.
+ * The first value is delivered; continue with dbcred_iterate_next().
+ *
+ * The cursor must have been opened on dbh_localid within the desired
+ * transaction context; the caller must close it after iteration.
+ *
+ * The value returned is only non-zero if a value was setup.
+ * The DB_NOTFOUND value indicates that the key was not found.
+ */
+int dbcred_iterate_from_localid (DBC *cursor, DBT *keydata, DBT *creddata);
+
+/* Construct an iterator for a given remoteid selector. Apply stepwise
+ * generalisation to find the most concrete match. The first value found
+ * is delivered; continue with dbcred_iterate_next().
+ *
+ * The remotesel value in string representation is the key to discpatn,
+ * forming the initial disclosure pattern. This key should be setup with
+ * enough space to store the pattern (which is never longer than the original
+ * remoteid) plus a terminating NUL character.
+ *
+ * Note that remotesel already has the first value activated, usually the
+ * same as the remoteid. This is assumed to be available, so don't call
+ * this function otherwise. In practice, this is hardly a problem; any
+ * valid remoteid will provide a valid selector whose first iteration is to
+ * repeat the remoteid. Failure to start even this is a sign of a syntax
+ * error, which is good to be treating separately from not-found conditions.
+ *
+ * The started iteration is a nested iteration over dbh_disclose for the
+ * pattern found, and inside that an iteration over dbh_localid for the
+ * localid values that this gave. This means that two cursors are needed,
+ * both here and in the subsequent dbcred_iterate_next() calls.
+ *
+ * The cursors crs_disclose and crs_localid must have been opened on
+ * dbh_disclose and dbh_localid within the desired transaction context;
+ * the caller must close them after iteration.
+ *
+ * The value returned is zero if a value was setup; otherwise an error code.
+ * The DB_NOTFOUND value indicates that no selector matching the remoteid
+ * was found in dbh_disclose.
+ */
+int dbcred_iterate_from_remoteid_selector (DBC *crs_disclose, DBC *crs_localid, selector_t *remotesel, DBT *discpatn, DBT *keydata, DBT *creddata);
+
+/* Move an iterator to the next credential data value. When done, the value
+ * returned should be DB_NOTFOUND.
+ *
+ * The outer cursor (for dbh_disclose) is optional, and is only used when
+ * the prior call was from dbcred_iterate_from_remoteid().
+ *
+ * The optional discpatn must be supplied only when dbh_disclose is provided.
+ * It holds the key value for the dbh_disclose outer cursor.
+ *
+ * The keydata will be filled with the intermediate key when dbh_disclose is
+ * provided. It is also used to match the next record with the current one.
+ *
+ * The value returned is zero if a value was setup; otherwise an error code.
+ * The DB_NOTFOUND value indicates that no further duplicate was not found.
+ */
+int dbcred_iterate_next (DBC *opt_crs_disclose, DBC *crs_localid, DBT *opt_discpatn, DBT *keydata, DBT *creddata);
+
+
+
+/* Interpret the credentials structure found in dbh_localid.
+ * This comes down to splitting the (data,size) structure into fields:
+ * - a 32-bit flags field
+ * - a char * sharing the PKCS #11 private key location
+ * - a (data,size) structure for the public credential
+ * The function returns non-zero on success (zero indicates syntax error).
+ */
+int dbcred_interpret (gnutls_datum_t *creddata, uint32_t *flags, char **p11priv, uint8_t **pubdata, int *pubdatalen);
+
+
+/* Iterate over selector values that would generalise the donai. The
+ * selector_t shares data from the donai, so it allocates no internal
+ * storage and so it can be dropped at any time during the iteration.
+ * Meanwhile, the donai must not drop storage before iteration stops.
+ *
+ * The value returned is only non-zero if a value was setup.
+ */
+int selector_iterate_init (selector_t *iterator, donai_t *donai);
+int selector_iterate_next (selector_t *iterator);
+
+/* Print a donai or iterated selector to the given text buffer. The
+ * text will be precisely the same as the originally parsed text. An
+ * iterator may deliver values that are shorter, not longer. The value
+ * returned is the number of bytes written. No trailing NUL character
+ * will be written.
+ */
+int donai_iterate_memput (char *selector_text, donai_t *iterator);
+
+
+/* Check if a selector is a pattern that matches the given donai value.
+ * The value returned is non-zero for a match, zero for a non-match.
+ */
+int donai_matches_selector (donai_t *donai, selector_t *pattern);
+
+
+/* Fill a donai structure from a stable string. The donai will share parts
+ * of the string. The function can also be used to construct a selector
+ * from a string; their structures are the same and the syntax is not
+ * parsed to ensure non-empty usernames and non-dot-prefixed domain names.
+ */
+donai_t donai_from_stable_string (char *stable, int stablelen);
+
#include "manage.h"
-#include "localid.h"
+#include "donai.h"
#if EXPECTED_LID_TYPE_COUNT != LID_TYPE_CNT
/*
+ * Check if a given cmd has the given LID_TYPE setup.
+ * Return 1 for yes or 0 for no; this is used in priority strings.
+ */
+static inline int lidtpsup (struct command *cmd, int lidtp) {
+ return cmd->lids [lidtp - LID_TYPE_MIN].data != NULL;
+}
+
+/*
* The starttls_thread is a main program for the setup of a TLS connection,
* either in client mode or server mode. Note that the distinction between
* client and server mode is only a TLS concern, but not of interest to the
fetch_local_credentials (cmd));
//
- // Setup the priority string for this session
- // TODO: Derive the sting from available local identities
+ // Setup the priority string for this session; this avoids future
+ // credential callbacks that ask for something impossible or
+ // undesired.
+ //
// Variation factors:
// - starting configuration (can it be empty?)
// - Configured security parameters (database? variable?)
// - CTYPEs, SRP, ANON-or-not --> fill in as + or - characters
+ //TODO// Support for ANON-DH where appropriate
if (gtls_errno == GNUTLS_E_SUCCESS) {
+ char priostr [256];
+ snprintf (priostr, sizeof (priostr)-1,
+ "NORMAL:"
+ "%cCTYPE-X.509:"
+ "%cCTYPE-OPENPGP:"
+ "%cSRP:%cSRP-RSA:%cSRP-DSS:"
+ "%cANON-ECDH:%cANON-DH",
+ lidtpsup (cmd, LID_TYPE_X509) ?'+':'-',
+ lidtpsup (cmd, LID_TYPE_PGP) ?'+':'-',
+ lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
+ lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
+ lidtpsup (cmd, LID_TYPE_SRP) ?'+':'-',
+ 0 /* TODO: ANON-DH */ ?'+':'-',
+ 0 /* TODO: ANON-DH */ ?'+':'-');
+ tlog (TLOG_TLS, LOG_DEBUG, "Constructed priority string %s for local ID %s",
+ priostr, cmd->cmd.pio_data.pioc_starttls.localid);
E_g2e ("Failed to set GnuTLS priority string",
gnutls_priority_set_direct (
session,
// "NORMAL:-KX-ALL:+SRP:+SRP-RSA:+SRP-DSS",
- "NORMAL:+CTYPE-X.509:-CTYPE-OPENPGP:+CTYPE-X.509",
+ // "NORMAL:+CTYPE-X.509:-CTYPE-OPENPGP:+CTYPE-X.509",
// "NORMAL:-CTYPE-X.509:+CTYPE-OPENPGP:-CTYPE-X.509",
// "NORMAL:+ANON-ECDH:+ANON-DH",
+ priostr,
NULL));
}
+++ /dev/null
-/* tlspool/localid.c -- Map the keys of local identities to credentials */
-
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <syslog.h>
-#include <errno.h>
-
-#include <gnutls/gnutls.h>
-#include <gnutls/abstract.h>
-
-#include <tlspool/internal.h>
-
-#include "manage.h"
-#include "localid.h"
-
-
-/*
- * Lookup local identities from a BDB database. The identities take the
- * form of a NAI, and are the keys for a key-values lookup. The outcome
- * may offer multiple values, each representing an identity. The general
- * structure of a value is:
- *
- * - 4 netbytes, a flags field for local identity management (see LID_xxx below)
- * - NUL-terminated string with a pkcs11 URI [ draft-pechanec-pkcs11uri ]
- * - Binary string holding the identity in binary form
- *
- * There may be prefixes for generic management, but these are not made
- * available to this layer.
- */
-
-
-
-/* Retrieve flags from the credentials structure found in dbh_localid.
- * The function returns non-zero on success (zero indicates syntax error).
- */
-int dbcred_flags (DBT *creddata, uint32_t *flags) {
- int p11privlen;
- if (creddata->size <= 4) {
- return 0;
- }
- *flags = ntohl (* (uint32_t *) creddata->data);
- return 1;
-}
-
-
-/* Interpret the credentials structure found in dbh_localid.
- * This comes down to splitting the (data,size) structure into fields:
- * - a 32-bit flags field
- * - a char * sharing the PKCS #11 private key location, NULL on LID_NO_PKCS11
- * - a (data,size) structure for the public credential, also when LID_CHAINED
- * The function returns non-zero on success (zero indicates syntax error).
- */
-int dbcred_interpret (gnutls_datum_t *creddata, uint32_t *flags, char **p11priv, uint8_t **pubdata, int *pubdatalen) {
- int p11privlen;
- if (creddata->size <= 4) {
- return 0;
- }
- *flags = ntohl (* (uint32_t *) creddata->data);
- if ((*flags) & LID_NO_PKCS11) {
- *p11priv = NULL;
- } else {
- *p11priv = ((char *) creddata->data) + 4;
- p11privlen = strnlen (*p11priv, creddata->size - 4);
- if (p11privlen == creddata->size - 4) {
- return 0;
- }
-#ifdef TODO_PKCS11_ADDED
- if (strncmp (*p11priv, "pkcs11:", 7) != 0) {
- return 0;
- }
-#endif
- }
- *pubdata = ((uint8_t *) creddata->data) + 4 + p11privlen + 1;
- *pubdatalen = creddata->size - 4 - p11privlen - 1;
- if (*pubdatalen < 20) {
- // Unbelievably short certificate (arbitrary sanity limit 20)
- return 0;
- }
- return 1;
-}
-
-
-/* Create an iterator for a given localid value. Use keys from dhb_lid.
- * The first value is delivered; continue with dbcred_iterate_next().
- *
- * The cursor must have been opened on dbh_localid within the desired
- * transaction context; the caller must close it after iteration.
- *
- * The value returned is only non-zero if a value was setup.
- * The DB_NOTFOUND value indicates that the key was not found.
- */
-gtls_error dbcred_iterate_from_localid (DBC *cursor, DBT *keydata, DBT *creddata) {
- int gtls_errno = GNUTLS_E_SUCCESS;
- E_d2ge ("Key not found in db_localid",
- cursor->get (cursor, keydata, creddata, DB_SET));
- return gtls_errno;
-}
-
-
-/* Construct an iterator for a given remoteid selector. Apply stepwise
- * generalisation to find the most concrete match. The first value found
- * is delivered; continue with dbcred_iterate_next().
- *
- * The remotesel value in string representation is the key to discpatn,
- * forming the initial disclosure pattern. This key should be setup with
- * enough space to store the pattern (which is never longer than the original
- * remoteid) plus a terminating NUL character.
- *
- * Note that remotesel already has the first value activated, usually the
- * same as the remoteid. This is assumed to be available, so don't call
- * this function otherwise. In practice, this is hardly a problem; any
- * valid remoteid will provide a valid selector whose first iteration is to
- * repeat the remoteid. Failure to start even this is a sign of a syntax
- * error, which is good to be treating separately from not-found conditions.
- *
- * The started iteration is a nested iteration over dbh_disclose for the
- * pattern found, and inside that an iteration over dbh_localid for the
- * localid values that this gave. This means that two cursors are needed,
- * both here and in the subsequent dbcred_iterate_next() calls.
- *
- * The cursors crs_disclose and crs_localid must have been opened on
- * dbh_disclose and dbh_localid within the desired transaction context;
- * the caller must close them after iteration.
- *
- * The value returned is zero if a value was setup; otherwise an error code.
- * The DB_NOTFOUND value indicates that no selector matching the remoteid
- * was found in dbh_disclose.
- */
-gtls_error dbcred_iterate_from_remoteid_selector (DBC *crs_disclose, DBC *crs_localid, selector_t *remotesel, DBT *discpatn, DBT *keydata, DBT *creddata) {
- int gtls_errno = GNUTLS_E_SUCCESS;
- int more = 1;
- while (more) {
- int fnd;
- discpatn->size = donai_iterate_memput (discpatn->data, remotesel);
- tlog (TLOG_DB, LOG_DEBUG, "Looking up remote selector %.*s", discpatn->size, (char *) discpatn->data);
- fnd = crs_disclose->get (crs_disclose, discpatn, keydata, DB_SET);
- if (fnd == 0) {
- // Got the selector pattern!
- // Now continue, even when no localids will work.
- E_d2ge ("Key not found in db_localid",
- crs_localid->get (
- crs_localid,
- keydata,
- creddata,
- DB_SET));
- return gtls_errno;
- } else if (fnd != DB_NOTFOUND) {
- E_d2ge ("Failed while searching with remote ID selector", fnd);
- break;
- }
- more = selector_iterate_next (remotesel);
- }
- // Ended here with nothing more to find
- E_d2ge ("No selector matches remote ID in db_disclose",
- DB_NOTFOUND);
- return gtls_errno;
-}
-
-
-/* Move an iterator to the next credential data value. When done, the value
- * returned should be DB_NOTFOUND.
- *
- * The outer cursor (for dbh_disclose) is optional, and is only used when
- * the prior call was from dbcred_iterate_from_remoteid().
- *
- * The optional discpatn must be supplied only when dbh_disclose is provided.
- * It holds the key value for the dbh_disclose outer cursor.
- *
- * The keydata will be filled with the intermediate key when dbh_disclose is
- * provided. It is also used to match the next record with the current one.
- *
- * The value returned is zero if a value was setup; otherwise an error code.
- * The DB_NOTFOUND value indicates that no further duplicate was not found.
- */
-db_error dbcred_iterate_next (DBC *opt_crs_disclose, DBC *crs_localid, DBT *opt_discpatn, DBT *keydata, DBT *creddata) {
- int db_errno = 0;
- db_errno = crs_localid->get (crs_localid, keydata, creddata, DB_NEXT_DUP);
- if (db_errno != DB_NOTFOUND) {
- return db_errno;
- }
- // Inner loop ended in DB_NOTFOUND, optionally continue in outer loop
- if ((opt_crs_disclose != NULL) && (opt_discpatn != NULL)) {
- while (db_errno == DB_NOTFOUND) {
- db_errno = opt_crs_disclose->get (opt_crs_disclose, opt_discpatn, keydata, DB_NEXT_DUP);
- if (db_errno == DB_NOTFOUND) {
- return db_errno;
- }
- db_errno = crs_localid->get (crs_localid, keydata, creddata, DB_SET);
- }
- }
- return db_errno;
-}
-
-
-/* Iterate over selector values that would generalise the donai. The
- * selector_t shares data from the donai, so it allocates no internal
- * storage and so it can be dropped at any time during the iteration.
- * Meanwhile, the donai must not drop storage before iteration stops.
- *
- * The value returned is only non-zero if a value was setup.
- */
-int selector_iterate_init (selector_t *iterator, donai_t *donai) {
- //
- // If the user name is not NULL but empty, bail out in horror
- if ((donai->user != NULL) && (donai->userlen <= 0)) {
- return 0;
- }
- //
- // If the domain name is empty or NULL, bail out in horror
- if ((donai->domain == NULL) || (donai->domlen == 0)) {
- return 0;
- }
- //
- // The first and most concrete pattern is the donai itself
- memcpy (iterator, donai, sizeof (*iterator));
- return 1;
-}
-
-int selector_iterate_next (selector_t *iterator) {
- int skip;
- //
- // If the user name is not NULL but empty, bail out in horror
- if ((iterator->user != NULL) && (iterator->userlen == 0)) {
- return 0;
- }
- //
- // If the domain name is empty or NULL, bail out in horror
- if ((iterator->domain == NULL) || (iterator->domlen == 0)) {
- return 0;
- }
- //
- // If there is a user component and it is non-empty, make it empty
- // If it was empty, permit it to become non-empty again, and continue
- if (iterator->user) {
- if (iterator->userlen > 0) {
- iterator->userlen = -iterator->userlen;
- return 1;
- }
- iterator->userlen = -iterator->userlen;
- }
- //
- // If the domain is a single dot, we're done
- if ((iterator->domlen == 1) && (*iterator->domain == '.')) {
- return 0;
- }
- //
- // Replace the domain (known >= 1 chars) with the next dot's domain
- skip = 1;
- while ((skip < iterator->domlen) && (iterator->domain [skip] != '.')) {
- skip++;
- }
- if (skip == iterator->domlen) {
- iterator->domain = "."; // Last resort domain
- iterator->domlen = 1;
- } else {
- iterator->domain += skip;
- iterator->domlen -= skip;
- }
- return 1;
-}
-
-
-/* Check if a selector is a pattern that matches the given donai value.
- * The value returned is non-zero for a match, zero for a non-match.
- */
-int donai_matches_selector (donai_t *donai, selector_t *pattern) {
- int extra;
- //
- // Bail out in horror on misconfigurations
- if ((donai->user != NULL) && (donai->userlen <= 0)) {
- return 0;
- }
- if ((donai ->domain == NULL) || (donai ->domlen <= 0)) {
- return 0;
- }
- if ((pattern->domain == NULL) || (pattern->domlen <= 0)) {
- return 0;
- }
- //
- // User name handling first
- if (pattern->user) {
- //
- // Pattern has a user? Then request a user in the donai too
- if (donai->user == NULL) {
- return 0;
- }
- //
- // Non-empty user in pattern? Then match everything
- if (*pattern->user) {
- if (pattern->userlen > 0) {
- if (donai->userlen != pattern->userlen) {
- return 0;
- }
- if (memcmp (donai->user, pattern->user, donai->userlen) != 0) {
- return 0;
- }
- }
- }
- } else {
- //
- // Pattern without user, then donai may not have one either
- if (donai->user != NULL) {
- return 0;
- }
- }
- //
- // Domain name handling second
- if (*pattern->domain == '.') {
- extra = donai->domlen - pattern->domlen;
- if (extra < 0) {
- //
- // No good having a longer pattern than a donai.domain
- return 0;
- }
- } else {
- extra = 0;
- }
- return (memcmp (donai->domain + extra, pattern->domain, pattern->domlen) == 0);
-}
-
-
-/* Fill a donai structure from a stable string. The donai will share parts
- * of the string. The function can also be used to construct a selector
- * from a string; their structures are the same and the syntax is not
- * parsed to ensure non-empty usernames and non-dot-prefixed domain names.
- */
-donai_t donai_from_stable_string (char *stable, int stablelen) {
- donai_t retval;
- retval.userlen = stablelen - 1;
- while (retval.userlen > 0) {
- if (stable [retval.userlen] == '@') {
- break;
- }
- retval.userlen--;
- }
- if (stable [retval.userlen] == '@') {
- retval.user = stable;
- retval.domain = stable + (retval.userlen + 1);
- retval.domlen = stablelen - 1 - retval.userlen;
- } else {
- retval.user = NULL;
- retval.domain = stable;
- retval.domlen = stablelen;
- }
- return retval;
-}
-
-/* Print a donai or iterated selector to the given text buffer. The
- * text will be precisely the same as the originally parsed text. An
- * iterator may deliver values that are shorter, not longer. The value
- * returned is the number of bytes written. No trailing NUL character
- * will be written.
- */
-int donai_iterate_memput (char *selector_text, donai_t *iterator) {
- int len = 0;
- if (iterator->user != NULL) {
- if (iterator->userlen > 0) {
- memcpy (selector_text, iterator->user, iterator->userlen);
- len += iterator->userlen;
- }
- selector_text [len++] = '@';
- }
- memcpy (selector_text + len, iterator->domain, iterator->domlen);
- len += iterator->domlen;
- return len;
-}
-
+++ /dev/null
-/* tlspool/localid.h -- Map the keys of local identities to credentials */
-
-
-/*
- * Lookup local identities from a BDB database. The identities take the
- * form of a NAI, and are the keys for a key-values lookup. The outcome
- * may offer multiple values, each representing an identity. The general
- * structure of a value is:
- *
- * - 4 netbytes, a flags field for local identity management (see LID_xxx below)
- * - NUL-terminated string with a pkcs11 URI [ draft-pechanec-pkcs11uri ]
- * - Binary string holding the identity in binary form
- *
- * There may be prefixes for generic management, but these are not made
- * available to this layer.
- */
-
-
-#define LID_HDRSZ (MGT_HDRSZ + 4)
-
-
-#define LID_TYPE_MASK 0x000000ff /* Separate out the LID_TYPE_xxx bits */
-#define LID_TYPE_ANY 0x000000ff /* No filter, permit anything */
-#define LID_TYPE_X509 0x00000001 /* X.509 certificate, DER-encoded */
-#define LID_TYPE_PGP 0x00000002 /* OpenPGP public key, binary form */
-#define LID_TYPE_SRP 0x00000003 /* No data, flags existence */
-#define LID_TYPE_KRB5 0x00000004 /* Ticket */
-
-#define LID_TYPE_MIN LID_TYPE_X509
-#define LID_TYPE_MAX LID_TYPE_KRB5
-#define LID_TYPE_OFS LID_TYPE_MIN
-#define LID_TYPE_CNT (1 + LID_TYPE_MAX - LID_TYPE_MIN)
-
-#define LID_ROLE_MASK 0x00000300 /* Separate out the LID_ROLE_xxx bits */
-#define LID_ROLE_CLIENT 0x00000100 /* This may be used for clients */
-#define LID_ROLE_SERVER 0x00000200 /* This may be used for servers */
-#define LID_ROLE_BOTH 0x00000300 /* This may be used for both roles */
-#define LID_ROLE_NONE 0x00000000 /* This may be used for neither role */
-
-#define LID_NO_PKCS11 0x00001000 /* No prefixed PKCS #11 URI + NUL */
-#define LID_CHAINED 0x00002000 /* Credential isa type-specific chain */
-//TODO// Encode LID_NEEDS_CHAIN support
-#define LID_NEEDS_CHAIN 0x00004000 /* Chain certs are in central storage */
-
-
-/* Impose a practial upper bound to the lenght of a DoNAI, a domain-or-NAI.
- * This is important to avoid overzealous allocations and subsequent buffer
- * or stack overflows. Sigh, we live in a world where networks can carry
- * the size between memory segments in a brief time.
- */
-#define DONAI_MAXLEN 512
-
-
-/* A donai is a structure holding either user@domain.name or domain.name.
- * A selector is a simple pattern that can match with a donain, by stripping
- * local components. For instance user@domain.name or @domain.name or @.name
- * or @. to match with user@domain.name; and, for instance domain.name or
- * .name or . to match with domain.name.
- */
-
-struct userdomain {
- char *user; /* not NUL-terminated; user==NULL for no @ at all */
- int userlen; /* valid if user!=NULL; userlen<0 in selector_t for 0 */
- char *domain; /* not NULL, start . signifies a pattern */
- int domlen; /* always >0 */
-};
-
-
-typedef struct userdomain donai_t; /* (user==NULL OR userlen>0) AND *domain!='.' */
-
-typedef struct userdomain selector_t; /* userlen<0 should be read as userlen==0 */
-
-
-
-/* Setup a DBT data handle to point to a pre-allocated, fixed-size
- * data buffer that will be used throughout the use of the handle.
- * Cleanup is not necessary, but the buffer must not be cleared
- * before the last use of the data handle.
- */
-static inline void dbt_init_fixbuf (DBT *dbt, void *buffer, u_int32_t bufsize) {
- bzero (dbt, sizeof (DBT));
- dbt->data = buffer;
- dbt->size =
- dbt->ulen = bufsize;
- dbt->flags |= DB_DBT_USERMEM;
-}
-
-/* Setup a DBT data handle for malloc() by the database, and free() by the
- * calling program.
- * Cleanup with dbt_free() or dbt_store() is needed after every lookup
- * that succeeded.
- */
-static inline void dbt_init_malloc (DBT *dbt) {
- bzero (dbt, sizeof (DBT));
- dbt->flags |= DB_DBT_MALLOC;
-}
-
-/* Free the DBT data handle that was setup with dbt_init_malloc(). This
- * or dbt_store() must be called after every successfully returned data
- * item.
- */
-static inline void dbt_free (DBT *dbt) {
- /* assert (dbt->flags & DB_DBT_MALLOC); */
- free (dbt->data);
- dbt->data = NULL;
-}
-
-/* Store the DBT data handle's data into external structures, moving both
- * the data pointer and size. The data handle must have been setup with
- * dbt_init_malloc(). Afterwards, clear the data handle for use in
- * another iteration.
- */
-static inline void dbt_store (DBT *dbt, gnutls_datum_t *output) {
- /* assert (dbt->flags & DB_DBT_MALLOC); */
- output->data = dbt->data;
- output->size = dbt->size;
- dbt->data = NULL;
-}
-
-
-/* Create an iterator for a given localid value. Use keys from dhb_lid.
- * The first value is delivered; continue with dbcred_iterate_next().
- *
- * The cursor must have been opened on dbh_localid within the desired
- * transaction context; the caller must close it after iteration.
- *
- * The value returned is only non-zero if a value was setup.
- * The DB_NOTFOUND value indicates that the key was not found.
- */
-int dbcred_iterate_from_localid (DBC *cursor, DBT *keydata, DBT *creddata);
-
-/* Construct an iterator for a given remoteid selector. Apply stepwise
- * generalisation to find the most concrete match. The first value found
- * is delivered; continue with dbcred_iterate_next().
- *
- * The remotesel value in string representation is the key to discpatn,
- * forming the initial disclosure pattern. This key should be setup with
- * enough space to store the pattern (which is never longer than the original
- * remoteid) plus a terminating NUL character.
- *
- * Note that remotesel already has the first value activated, usually the
- * same as the remoteid. This is assumed to be available, so don't call
- * this function otherwise. In practice, this is hardly a problem; any
- * valid remoteid will provide a valid selector whose first iteration is to
- * repeat the remoteid. Failure to start even this is a sign of a syntax
- * error, which is good to be treating separately from not-found conditions.
- *
- * The started iteration is a nested iteration over dbh_disclose for the
- * pattern found, and inside that an iteration over dbh_localid for the
- * localid values that this gave. This means that two cursors are needed,
- * both here and in the subsequent dbcred_iterate_next() calls.
- *
- * The cursors crs_disclose and crs_localid must have been opened on
- * dbh_disclose and dbh_localid within the desired transaction context;
- * the caller must close them after iteration.
- *
- * The value returned is zero if a value was setup; otherwise an error code.
- * The DB_NOTFOUND value indicates that no selector matching the remoteid
- * was found in dbh_disclose.
- */
-int dbcred_iterate_from_remoteid_selector (DBC *crs_disclose, DBC *crs_localid, selector_t *remotesel, DBT *discpatn, DBT *keydata, DBT *creddata);
-
-/* Move an iterator to the next credential data value. When done, the value
- * returned should be DB_NOTFOUND.
- *
- * The outer cursor (for dbh_disclose) is optional, and is only used when
- * the prior call was from dbcred_iterate_from_remoteid().
- *
- * The optional discpatn must be supplied only when dbh_disclose is provided.
- * It holds the key value for the dbh_disclose outer cursor.
- *
- * The keydata will be filled with the intermediate key when dbh_disclose is
- * provided. It is also used to match the next record with the current one.
- *
- * The value returned is zero if a value was setup; otherwise an error code.
- * The DB_NOTFOUND value indicates that no further duplicate was not found.
- */
-int dbcred_iterate_next (DBC *opt_crs_disclose, DBC *crs_localid, DBT *opt_discpatn, DBT *keydata, DBT *creddata);
-
-
-
-/* Interpret the credentials structure found in dbh_localid.
- * This comes down to splitting the (data,size) structure into fields:
- * - a 32-bit flags field
- * - a char * sharing the PKCS #11 private key location
- * - a (data,size) structure for the public credential
- * The function returns non-zero on success (zero indicates syntax error).
- */
-int dbcred_interpret (gnutls_datum_t *creddata, uint32_t *flags, char **p11priv, uint8_t **pubdata, int *pubdatalen);
-
-
-/* Iterate over selector values that would generalise the donai. The
- * selector_t shares data from the donai, so it allocates no internal
- * storage and so it can be dropped at any time during the iteration.
- * Meanwhile, the donai must not drop storage before iteration stops.
- *
- * The value returned is only non-zero if a value was setup.
- */
-int selector_iterate_init (selector_t *iterator, donai_t *donai);
-int selector_iterate_next (selector_t *iterator);
-
-/* Print a donai or iterated selector to the given text buffer. The
- * text will be precisely the same as the originally parsed text. An
- * iterator may deliver values that are shorter, not longer. The value
- * returned is the number of bytes written. No trailing NUL character
- * will be written.
- */
-int donai_iterate_memput (char *selector_text, donai_t *iterator);
-
-
-/* Check if a selector is a pattern that matches the given donai value.
- * The value returned is non-zero for a match, zero for a non-match.
- */
-int donai_matches_selector (donai_t *donai, selector_t *pattern);
-
-
-/* Fill a donai structure from a stable string. The donai will share parts
- * of the string. The function can also be used to construct a selector
- * from a string; their structures are the same and the syntax is not
- * parsed to ensure non-empty usernames and non-dot-prefixed domain names.
- */
-donai_t donai_from_stable_string (char *stable, int stablelen);
-