]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Add support for PKINIT deferring identity prompts
authorNalin Dahyabhai <nalin@redhat.com>
Fri, 28 Jun 2013 21:12:39 +0000 (17:12 -0400)
committerGreg Hudson <ghudson@mit.edu>
Wed, 17 Jul 2013 16:24:20 +0000 (12:24 -0400)
Learn to manage a list of deferred identities, for which we want to
prompt for passwords or PINs, in pkinit_identity_crypto_context
structures, along with their associated token flags.  These are opaque
outside of pkinit_crypto_openssl and pkinit_crypto_nss, so both
implementations need to provide wrapper functions that can be called
from elsewhere in the module to populate and query the lists.

ticket: 7680

src/plugins/preauth/pkinit/pkinit.h
src/plugins/preauth/pkinit/pkinit_crypto.h
src/plugins/preauth/pkinit/pkinit_crypto_nss.c
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
src/plugins/preauth/pkinit/pkinit_identity.c

index b44dfe7b7bed38d2a3dbff8bd01e36203ff18270..38a43f5038c1d59c3fb1ba8fa11ea9a168aefce1 100644 (file)
@@ -71,6 +71,7 @@ extern int longhorn;      /* XXX Talking to a Longhorn server? */
 
 #define PKINIT_CTX_MAGIC       0x05551212
 #define PKINIT_REQ_CTX_MAGIC   0xdeadbeef
+#define PKINIT_DEFERRED_ID_MAGIC    0x3ca20d21
 
 #define PKINIT_DEFAULT_DH_MIN_BITS  2048
 #define PKINIT_DH_MIN_CONFIG_BITS   1024
@@ -308,6 +309,26 @@ krb5_error_code pkinit_cert_matching
        pkinit_identity_crypto_context id_cryptoctx,
        krb5_principal princ);
 
+/*
+ * Client's list of identities for which it needs PINs or passwords
+ */
+struct _pkinit_deferred_id {
+    int magic;
+    char *identity;
+    unsigned long ck_flags;
+    char *password;
+};
+typedef struct _pkinit_deferred_id *pkinit_deferred_id;
+
+krb5_error_code pkinit_set_deferred_id
+       (pkinit_deferred_id **identities, const char *identity,
+        unsigned long ck_flags, const char *password);
+const char * pkinit_find_deferred_id
+       (pkinit_deferred_id *identities, const char *identity);
+unsigned long pkinit_get_deferred_id_flags
+       (pkinit_deferred_id *identities, const char *identity);
+void pkinit_free_deferred_ids(pkinit_deferred_id *identities);
+
 /*
  * initialization and free functions
  */
index 8c2b0063a82593cb6ac1d97bd45857d9fd2cd727..b483affed6f7cb2b9a0b01a79d364711b8f529c3 100644 (file)
@@ -423,6 +423,17 @@ krb5_error_code create_issuerAndSerial
        unsigned int *kdcId_len);                       /* OUT
                    receives length of encoded kdcPKId */
 
+/*
+ * These functions manipulate the deferred-identities list in the identity
+ * context, which is opaque outside of the crypto-specific bits.
+ */
+const pkinit_deferred_id * crypto_get_deferred_ids
+       (krb5_context context, pkinit_identity_crypto_context id_cryptoctx);
+krb5_error_code crypto_set_deferred_id
+       (krb5_context context,
+        pkinit_identity_crypto_context id_cryptoctx,
+        const char *identity, const char *password);
+
 /*
  * process the values from idopts and obtain the cert(s)
  * specified by those options, populating the id_cryptoctx.
index ef0e94d6897d9b074fcfb116e94ee58c97d75c10..3c6a87d5e48ad906811d0477650caf859dedd02b 100644 (file)
@@ -149,6 +149,8 @@ struct _pkinit_identity_crypto_context {
         krb5_prompter_fct prompter;
         void *prompter_data;
     } pwcb_args;
+    krb5_boolean defer_id_prompt;
+    pkinit_deferred_id *deferred_ids;
 };
 
 struct _pkinit_cert_info {      /* aka _pkinit_cert_handle */
@@ -785,6 +787,8 @@ pkinit_fini_identity_crypto(pkinit_identity_crypto_context id_cryptoctx)
     pkiDebug("%s\n", __FUNCTION__);
     /* The order of cleanup here is intended to ensure that nothing gets
      * freed before anything that might have a reference to it. */
+    if (id_cryptoctx->deferred_ids != NULL)
+        pkinit_free_deferred_ids(id_cryptoctx->deferred_ids);
     if (id_cryptoctx->id_cert != NULL)
         CERT_DestroyCertificate(id_cryptoctx->id_cert);
     CERT_DestroyCertList(id_cryptoctx->ca_certs);
@@ -2895,6 +2899,8 @@ crypto_load_certs(krb5_context context,
 {
     SECStatus status;
 
+    id_cryptoctx->defer_id_prompt = defer_id_prompts;
+
     switch (idopts->idtype) {
     case IDTYPE_FILE:
         status = crypto_load_files(context,
@@ -5550,3 +5556,37 @@ cms_signeddata_verify(krb5_context context,
 
     return 0;
 }
+
+/*
+ * Add an item to the pkinit_identity_crypto_context's list of deferred
+ * identities.
+ */
+krb5_error_code
+crypto_set_deferred_id(krb5_context context,
+                       pkinit_identity_crypto_context id_cryptoctx,
+                       const char *identity, const char *password)
+{
+    unsigned long ck_flags;
+
+    ck_flags = pkinit_get_deferred_id_flags(id_cryptoctx->deferred_ids,
+                                            identity);
+    return pkinit_set_deferred_id(&id_cryptoctx->deferred_ids,
+                                  identity, ck_flags, password);
+}
+
+/*
+ * Retrieve a read-only copy of the pkinit_identity_crypto_context's list of
+ * deferred identities, sure to be valid only until the next time someone calls
+ * either pkinit_set_deferred_id() or crypto_set_deferred_id().
+ */
+const pkinit_deferred_id *
+crypto_get_deferred_ids(krb5_context context,
+                        pkinit_identity_crypto_context id_cryptoctx)
+{
+    pkinit_deferred_id *deferred;
+    const pkinit_deferred_id *ret;
+
+    deferred = id_cryptoctx->deferred_ids;
+    ret = (const pkinit_deferred_id *)deferred;
+    return ret;
+}
index a780e7122d972f3f865bcf61d131c603da2da4e3..1312555b650734e2acf785c95ec0e73822098bea 100644 (file)
@@ -510,6 +510,8 @@ pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
         return;
 
     pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, idctx);
+    if (idctx->deferred_ids != NULL)
+        pkinit_free_deferred_ids(idctx->deferred_ids);
     free(idctx->identity);
     pkinit_fini_certs(idctx);
     pkinit_fini_pkcs11(idctx);
@@ -4797,6 +4799,8 @@ crypto_load_certs(krb5_context context,
 {
     krb5_error_code retval;
 
+    id_cryptoctx->defer_id_prompt = defer_id_prompts;
+
     switch(idopts->idtype) {
     case IDTYPE_FILE:
         retval = pkinit_get_certs_fs(context, plg_cryptoctx,
@@ -6078,3 +6082,37 @@ pkinit_pkcs11_code_to_text(int err)
     snprintf(uc, sizeof(uc), _("unknown code 0x%x"), err);
     return (uc);
 }
+
+/*
+ * Add an item to the pkinit_identity_crypto_context's list of deferred
+ * identities.
+ */
+krb5_error_code
+crypto_set_deferred_id(krb5_context context,
+                       pkinit_identity_crypto_context id_cryptoctx,
+                       const char *identity, const char *password)
+{
+    unsigned long flags;
+
+    flags = pkinit_get_deferred_id_flags(id_cryptoctx->deferred_ids,
+                                         identity);
+    return pkinit_set_deferred_id(&id_cryptoctx->deferred_ids,
+                                  identity, flags, password);
+}
+
+/*
+ * Retrieve a read-only copy of the pkinit_identity_crypto_context's list of
+ * deferred identities, sure to be valid only until the next time someone calls
+ * either pkinit_set_deferred_id() or crypto_set_deferred_id().
+ */
+const pkinit_deferred_id *
+crypto_get_deferred_ids(krb5_context context,
+                        pkinit_identity_crypto_context id_cryptoctx)
+{
+    pkinit_deferred_id *deferred;
+    const pkinit_deferred_id *ret;
+
+    deferred = id_cryptoctx->deferred_ids;
+    ret = (const pkinit_deferred_id *)deferred;
+    return ret;
+}
index 0c14e0047e52250abb8a9dbc1ff07e8fbb972a3b..3c7339419a692aefe30f61a9e60b6f77a549f07d 100644 (file)
@@ -86,6 +86,8 @@ struct _pkinit_identity_crypto_context {
     int cert_id_len;
     CK_MECHANISM_TYPE mech;
 #endif
+    krb5_boolean defer_id_prompt;
+    pkinit_deferred_id *deferred_ids;
 };
 
 struct _pkinit_plg_crypto_context {
index a53810c5c92da3db24b4415ab1f536565738d86c..eb198f4f76491e4d71aecab3e1c521d10c4069d5 100644 (file)
@@ -683,3 +683,117 @@ pkinit_identity_prompt(krb5_context context,
 errout:
     return retval;
 }
+
+/*
+ * Create an entry in the passed-in list for the named identity, optionally
+ * with the specified token flag value and/or supplied password, replacing any
+ * existing entry with the same identity name.
+ */
+krb5_error_code
+pkinit_set_deferred_id(pkinit_deferred_id **identities,
+                       const char *identity, unsigned long ck_flags,
+                       const char *password)
+{
+    int i;
+    pkinit_deferred_id *out = NULL, *ids;
+    char *tmp;
+
+    /* Search for an entry that's already in the list. */
+    ids = *identities;
+    for (i = 0; ids != NULL && ids[i] != NULL; i++) {
+        if (strcmp(ids[i]->identity, identity) == 0) {
+            /* Replace its password value, then we're done. */
+            tmp = password ? strdup(password) : NULL;
+            if (password != NULL && tmp == NULL)
+                return ENOMEM;
+            ids[i]->ck_flags = ck_flags;
+            free(ids[i]->password);
+            ids[i]->password = tmp;
+            return 0;
+        }
+    }
+
+    /* Resize the list. */
+    out = realloc(ids, sizeof(*ids) * (i + 2));
+    if (out == NULL)
+        goto oom;
+    *identities = out;
+
+    /* Allocate the new final entry. */
+    out[i] = malloc(sizeof(*(out[i])));
+    if (out[i] == NULL)
+        goto oom;
+
+    /* Populate the new entry. */
+    out[i]->magic = PKINIT_DEFERRED_ID_MAGIC;
+    out[i]->identity = strdup(identity);
+    if (out[i]->identity == NULL)
+        goto oom;
+
+    out[i]->ck_flags = ck_flags;
+    out[i]->password = password ? strdup(password) : NULL;
+    if (password != NULL && out[i]->password == NULL)
+        goto oom;
+
+    /* Terminate the list. */
+    out[i + 1] = NULL;
+    return 0;
+
+oom:
+    if (out != NULL && out[i] != NULL) {
+        free(out[i]->identity);
+        free(out[i]);
+        out[i] = NULL;
+    }
+    return ENOMEM;
+}
+
+/*
+ * Return a password which we've associated with the named identity, if we've
+ * stored one.  Otherwise return NULL.
+ */
+const char *
+pkinit_find_deferred_id(pkinit_deferred_id *identities,
+                        const char *identity)
+{
+    int i;
+
+    for (i = 0; identities != NULL && identities[i] != NULL; i++) {
+        if (strcmp(identities[i]->identity, identity) == 0)
+            return identities[i]->password;
+    }
+    return NULL;
+}
+
+/*
+ * Return the flags associated with the specified identity, or 0 if we don't
+ * have such an identity.
+ */
+unsigned long
+pkinit_get_deferred_id_flags(pkinit_deferred_id *identities,
+                             const char *identity)
+{
+    int i;
+
+    for (i = 0; identities != NULL && identities[i] != NULL; i++) {
+        if (strcmp(identities[i]->identity, identity) == 0)
+            return identities[i]->ck_flags;
+    }
+    return 0;
+}
+
+/*
+ * Free a deferred_id list.
+ */
+void
+pkinit_free_deferred_ids(pkinit_deferred_id *identities)
+{
+    int i;
+
+    for (i = 0; identities != NULL && identities[i] != NULL; i++) {
+        free(identities[i]->identity);
+        free(identities[i]->password);
+        free(identities[i]);
+    }
+    free(identities);
+}