Blame src/plugins/preauth/pkinit/pkinit_identity.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/*
Packit fd8b60
 * COPYRIGHT (C) 2007
Packit fd8b60
 * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
Packit fd8b60
 * ALL RIGHTS RESERVED
Packit fd8b60
 *
Packit fd8b60
 * Permission is granted to use, copy, create derivative works
Packit fd8b60
 * and redistribute this software and such derivative works
Packit fd8b60
 * for any purpose, so long as the name of The University of
Packit fd8b60
 * Michigan is not used in any advertising or publicity
Packit fd8b60
 * pertaining to the use of distribution of this software
Packit fd8b60
 * without specific, written prior authorization.  If the
Packit fd8b60
 * above copyright notice or any other identification of the
Packit fd8b60
 * University of Michigan is included in any copy of any
Packit fd8b60
 * portion of this software, then the disclaimer below must
Packit fd8b60
 * also be included.
Packit fd8b60
 *
Packit fd8b60
 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
Packit fd8b60
 * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
Packit fd8b60
 * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
Packit fd8b60
 * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
Packit fd8b60
 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
Packit fd8b60
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
Packit fd8b60
 * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
Packit fd8b60
 * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
Packit fd8b60
 * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
Packit fd8b60
 * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
Packit fd8b60
 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
Packit fd8b60
 * SUCH DAMAGES.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
#include "pkinit.h"
Packit fd8b60
#include <dlfcn.h>
Packit fd8b60
#include <dirent.h>
Packit fd8b60
Packit fd8b60
static void
Packit fd8b60
free_list(char **list)
Packit fd8b60
{
Packit fd8b60
    int i;
Packit fd8b60
Packit fd8b60
    if (list == NULL)
Packit fd8b60
        return;
Packit fd8b60
Packit fd8b60
    for (i = 0; list[i] != NULL; i++)
Packit fd8b60
        free(list[i]);
Packit fd8b60
    free(list);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
copy_list(char ***dst, char **src)
Packit fd8b60
{
Packit fd8b60
    int i;
Packit fd8b60
    char **newlist;
Packit fd8b60
Packit fd8b60
    if (dst == NULL)
Packit fd8b60
        return EINVAL;
Packit fd8b60
    *dst = NULL;
Packit fd8b60
Packit fd8b60
    if (src == NULL)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    for (i = 0; src[i] != NULL; i++);
Packit fd8b60
Packit fd8b60
    newlist = calloc(1, (i + 1) * sizeof(*newlist));
Packit fd8b60
    if (newlist == NULL)
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    for (i = 0; src[i] != NULL; i++) {
Packit fd8b60
        newlist[i] = strdup(src[i]);
Packit fd8b60
        if (newlist[i] == NULL)
Packit fd8b60
            goto cleanup;
Packit fd8b60
    }
Packit fd8b60
    newlist[i] = NULL;
Packit fd8b60
    *dst = newlist;
Packit fd8b60
    return 0;
Packit fd8b60
cleanup:
Packit fd8b60
    free_list(newlist);
Packit fd8b60
    return ENOMEM;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
char *
Packit fd8b60
idtype2string(int idtype)
Packit fd8b60
{
Packit fd8b60
    switch(idtype) {
Packit fd8b60
    case IDTYPE_FILE: return "FILE"; break;
Packit fd8b60
    case IDTYPE_DIR: return "DIR"; break;
Packit fd8b60
    case IDTYPE_PKCS11: return "PKCS11"; break;
Packit fd8b60
    case IDTYPE_PKCS12: return "PKCS12"; break;
Packit fd8b60
    case IDTYPE_ENVVAR: return "ENV"; break;
Packit fd8b60
    default: return "INVALID"; break;
Packit fd8b60
    }
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
char *
Packit fd8b60
catype2string(int catype)
Packit fd8b60
{
Packit fd8b60
    switch(catype) {
Packit fd8b60
    case CATYPE_ANCHORS: return "ANCHORS"; break;
Packit fd8b60
    case CATYPE_INTERMEDIATES: return "INTERMEDIATES"; break;
Packit fd8b60
    case CATYPE_CRLS: return "CRLS"; break;
Packit fd8b60
    default: return "INVALID"; break;
Packit fd8b60
    }
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
krb5_error_code
Packit fd8b60
pkinit_init_identity_opts(pkinit_identity_opts **idopts)
Packit fd8b60
{
Packit fd8b60
    pkinit_identity_opts *opts = NULL;
Packit fd8b60
Packit fd8b60
    *idopts = NULL;
Packit fd8b60
    opts = calloc(1, sizeof(pkinit_identity_opts));
Packit fd8b60
    if (opts == NULL)
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    opts->identity = NULL;
Packit fd8b60
    opts->anchors = NULL;
Packit fd8b60
    opts->intermediates = NULL;
Packit fd8b60
    opts->crls = NULL;
Packit fd8b60
Packit fd8b60
    opts->cert_filename = NULL;
Packit fd8b60
    opts->key_filename = NULL;
Packit fd8b60
#ifndef WITHOUT_PKCS11
Packit fd8b60
    opts->p11_module_name = NULL;
Packit fd8b60
    opts->slotid = PK_NOSLOT;
Packit fd8b60
    opts->token_label = NULL;
Packit fd8b60
    opts->cert_id_string = NULL;
Packit fd8b60
    opts->cert_label = NULL;
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
    *idopts = opts;
Packit fd8b60
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
krb5_error_code
Packit fd8b60
pkinit_dup_identity_opts(pkinit_identity_opts *src_opts,
Packit fd8b60
                         pkinit_identity_opts **dest_opts)
Packit fd8b60
{
Packit fd8b60
    pkinit_identity_opts *newopts;
Packit fd8b60
    krb5_error_code retval;
Packit fd8b60
Packit fd8b60
    *dest_opts = NULL;
Packit fd8b60
    retval = pkinit_init_identity_opts(&newopts);
Packit fd8b60
    if (retval)
Packit fd8b60
        return retval;
Packit fd8b60
Packit fd8b60
    retval = ENOMEM;
Packit fd8b60
Packit fd8b60
    if (src_opts->identity != NULL) {
Packit fd8b60
        newopts->identity = strdup(src_opts->identity);
Packit fd8b60
        if (newopts->identity == NULL)
Packit fd8b60
            goto cleanup;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    retval = copy_list(&newopts->anchors, src_opts->anchors);
Packit fd8b60
    if (retval)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    retval = copy_list(&newopts->intermediates,src_opts->intermediates);
Packit fd8b60
    if (retval)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    retval = copy_list(&newopts->crls, src_opts->crls);
Packit fd8b60
    if (retval)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    if (src_opts->cert_filename != NULL) {
Packit fd8b60
        newopts->cert_filename = strdup(src_opts->cert_filename);
Packit fd8b60
        if (newopts->cert_filename == NULL)
Packit fd8b60
            goto cleanup;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (src_opts->key_filename != NULL) {
Packit fd8b60
        newopts->key_filename = strdup(src_opts->key_filename);
Packit fd8b60
        if (newopts->key_filename == NULL)
Packit fd8b60
            goto cleanup;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
#ifndef WITHOUT_PKCS11
Packit fd8b60
    if (src_opts->p11_module_name != NULL) {
Packit fd8b60
        newopts->p11_module_name = strdup(src_opts->p11_module_name);
Packit fd8b60
        if (newopts->p11_module_name == NULL)
Packit fd8b60
            goto cleanup;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    newopts->slotid = src_opts->slotid;
Packit fd8b60
Packit fd8b60
    if (src_opts->token_label != NULL) {
Packit fd8b60
        newopts->token_label = strdup(src_opts->token_label);
Packit fd8b60
        if (newopts->token_label == NULL)
Packit fd8b60
            goto cleanup;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (src_opts->cert_id_string != NULL) {
Packit fd8b60
        newopts->cert_id_string = strdup(src_opts->cert_id_string);
Packit fd8b60
        if (newopts->cert_id_string == NULL)
Packit fd8b60
            goto cleanup;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (src_opts->cert_label != NULL) {
Packit fd8b60
        newopts->cert_label = strdup(src_opts->cert_label);
Packit fd8b60
        if (newopts->cert_label == NULL)
Packit fd8b60
            goto cleanup;
Packit fd8b60
    }
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
Packit fd8b60
    *dest_opts = newopts;
Packit fd8b60
    return 0;
Packit fd8b60
cleanup:
Packit fd8b60
    pkinit_fini_identity_opts(newopts);
Packit fd8b60
    return retval;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
void
Packit fd8b60
pkinit_fini_identity_opts(pkinit_identity_opts *idopts)
Packit fd8b60
{
Packit fd8b60
    if (idopts == NULL)
Packit fd8b60
        return;
Packit fd8b60
Packit fd8b60
    if (idopts->identity != NULL)
Packit fd8b60
        free(idopts->identity);
Packit fd8b60
    free_list(idopts->anchors);
Packit fd8b60
    free_list(idopts->intermediates);
Packit fd8b60
    free_list(idopts->crls);
Packit fd8b60
    free_list(idopts->identity_alt);
Packit fd8b60
Packit fd8b60
    free(idopts->cert_filename);
Packit fd8b60
    free(idopts->key_filename);
Packit fd8b60
#ifndef WITHOUT_PKCS11
Packit fd8b60
    free(idopts->p11_module_name);
Packit fd8b60
    free(idopts->token_label);
Packit fd8b60
    free(idopts->cert_id_string);
Packit fd8b60
    free(idopts->cert_label);
Packit fd8b60
#endif
Packit fd8b60
    free(idopts);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
#ifndef WITHOUT_PKCS11
Packit fd8b60
static krb5_error_code
Packit fd8b60
parse_pkcs11_options(krb5_context context,
Packit fd8b60
                     pkinit_identity_opts *idopts,
Packit fd8b60
                     const char *residual)
Packit fd8b60
{
Packit fd8b60
    char *s, *cp, *vp, *save;
Packit fd8b60
    krb5_error_code retval = ENOMEM;
Packit fd8b60
Packit fd8b60
    if (residual == NULL || residual[0] == '\0')
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    /* Split string into attr=value substrings */
Packit fd8b60
    s = strdup(residual);
Packit fd8b60
    if (s == NULL)
Packit fd8b60
        return retval;
Packit fd8b60
Packit fd8b60
    for (cp = strtok_r(s, ":", &save); cp; cp = strtok_r(NULL, ":", &save)) {
Packit fd8b60
        vp = strchr(cp, '=');
Packit fd8b60
Packit fd8b60
        /* If there is no "=", this is a pkcs11 module name */
Packit fd8b60
        if (vp == NULL) {
Packit fd8b60
            free(idopts->p11_module_name);
Packit fd8b60
            idopts->p11_module_name = strdup(cp);
Packit fd8b60
            if (idopts->p11_module_name == NULL)
Packit fd8b60
                goto cleanup;
Packit fd8b60
            continue;
Packit fd8b60
        }
Packit fd8b60
        *vp++ = '\0';
Packit fd8b60
        if (!strcmp(cp, "module_name")) {
Packit fd8b60
            free(idopts->p11_module_name);
Packit fd8b60
            idopts->p11_module_name = strdup(vp);
Packit fd8b60
            if (idopts->p11_module_name == NULL)
Packit fd8b60
                goto cleanup;
Packit fd8b60
        } else if (!strcmp(cp, "slotid")) {
Packit fd8b60
            long slotid = strtol(vp, NULL, 10);
Packit fd8b60
            if ((slotid == LONG_MIN || slotid == LONG_MAX) && errno != 0) {
Packit fd8b60
                retval = EINVAL;
Packit fd8b60
                goto cleanup;
Packit fd8b60
            }
Packit fd8b60
            if ((long) (int) slotid != slotid) {
Packit fd8b60
                retval = EINVAL;
Packit fd8b60
                goto cleanup;
Packit fd8b60
            }
Packit fd8b60
            idopts->slotid = slotid;
Packit fd8b60
        } else if (!strcmp(cp, "token")) {
Packit fd8b60
            free(idopts->token_label);
Packit fd8b60
            idopts->token_label = strdup(vp);
Packit fd8b60
            if (idopts->token_label == NULL)
Packit fd8b60
                goto cleanup;
Packit fd8b60
        } else if (!strcmp(cp, "certid")) {
Packit fd8b60
            free(idopts->cert_id_string);
Packit fd8b60
            idopts->cert_id_string = strdup(vp);
Packit fd8b60
            if (idopts->cert_id_string == NULL)
Packit fd8b60
                goto cleanup;
Packit fd8b60
        } else if (!strcmp(cp, "certlabel")) {
Packit fd8b60
            free(idopts->cert_label);
Packit fd8b60
            idopts->cert_label = strdup(vp);
Packit fd8b60
            if (idopts->cert_label == NULL)
Packit fd8b60
                goto cleanup;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
    retval = 0;
Packit fd8b60
cleanup:
Packit fd8b60
    free(s);
Packit fd8b60
    return retval;
Packit fd8b60
}
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
parse_fs_options(krb5_context context,
Packit fd8b60
                 pkinit_identity_opts *idopts,
Packit fd8b60
                 const char *residual)
Packit fd8b60
{
Packit fd8b60
    char *certname, *keyname, *save;
Packit fd8b60
    char *cert_filename = NULL, *key_filename = NULL;
Packit fd8b60
    krb5_error_code retval = ENOMEM;
Packit fd8b60
Packit fd8b60
    if (residual == NULL || residual[0] == '\0' || residual[0] == ',')
Packit fd8b60
        return EINVAL;
Packit fd8b60
Packit fd8b60
    certname = strdup(residual);
Packit fd8b60
    if (certname == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    certname = strtok_r(certname, ",", &save);
Packit fd8b60
    if (certname == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
    keyname = strtok_r(NULL, ",", &save);
Packit fd8b60
Packit fd8b60
    cert_filename = strdup(certname);
Packit fd8b60
    if (cert_filename == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    key_filename = strdup((keyname != NULL) ? keyname : certname);
Packit fd8b60
    if (key_filename == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    idopts->cert_filename = cert_filename;
Packit fd8b60
    idopts->key_filename = key_filename;
Packit fd8b60
    cert_filename = key_filename = NULL;
Packit fd8b60
    retval = 0;
Packit fd8b60
Packit fd8b60
cleanup:
Packit fd8b60
    free(certname);
Packit fd8b60
    free(cert_filename);
Packit fd8b60
    free(key_filename);
Packit fd8b60
    return retval;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
parse_pkcs12_options(krb5_context context,
Packit fd8b60
                     pkinit_identity_opts *idopts,
Packit fd8b60
                     const char *residual)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code retval = ENOMEM;
Packit fd8b60
Packit fd8b60
    if (residual == NULL || residual[0] == '\0')
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    idopts->cert_filename = strdup(residual);
Packit fd8b60
    if (idopts->cert_filename == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    idopts->key_filename = strdup(residual);
Packit fd8b60
    if (idopts->key_filename == NULL)
Packit fd8b60
        goto cleanup;
Packit fd8b60
Packit fd8b60
    pkiDebug("%s: cert_filename '%s' key_filename '%s'\n",
Packit fd8b60
             __FUNCTION__, idopts->cert_filename,
Packit fd8b60
             idopts->key_filename);
Packit fd8b60
    retval = 0;
Packit fd8b60
cleanup:
Packit fd8b60
    return retval;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
process_option_identity(krb5_context context,
Packit fd8b60
                        pkinit_plg_crypto_context plg_cryptoctx,
Packit fd8b60
                        pkinit_req_crypto_context req_cryptoctx,
Packit fd8b60
                        pkinit_identity_opts *idopts,
Packit fd8b60
                        pkinit_identity_crypto_context id_cryptoctx,
Packit fd8b60
                        const char *value)
Packit fd8b60
{
Packit fd8b60
    const char *residual;
Packit fd8b60
    int idtype;
Packit fd8b60
    krb5_error_code retval = 0;
Packit fd8b60
Packit fd8b60
    pkiDebug("%s: processing value '%s'\n",
Packit fd8b60
             __FUNCTION__, value ? value : "NULL");
Packit fd8b60
    if (value == NULL)
Packit fd8b60
        return EINVAL;
Packit fd8b60
Packit fd8b60
    residual = strchr(value, ':');
Packit fd8b60
    if (residual != NULL) {
Packit fd8b60
        unsigned int typelen;
Packit fd8b60
        residual++; /* skip past colon */
Packit fd8b60
        typelen = residual - value;
Packit fd8b60
        if (strncmp(value, "FILE:", typelen) == 0) {
Packit fd8b60
            idtype = IDTYPE_FILE;
Packit fd8b60
#ifndef WITHOUT_PKCS11
Packit fd8b60
        } else if (strncmp(value, "PKCS11:", typelen) == 0) {
Packit fd8b60
            idtype = IDTYPE_PKCS11;
Packit fd8b60
#endif
Packit fd8b60
        } else if (strncmp(value, "PKCS12:", typelen) == 0) {
Packit fd8b60
            idtype = IDTYPE_PKCS12;
Packit fd8b60
        } else if (strncmp(value, "DIR:", typelen) == 0) {
Packit fd8b60
            idtype = IDTYPE_DIR;
Packit fd8b60
        } else if (strncmp(value, "ENV:", typelen) == 0) {
Packit fd8b60
            idtype = IDTYPE_ENVVAR;
Packit fd8b60
        } else {
Packit fd8b60
            pkiDebug("%s: Unsupported type while processing '%s'\n",
Packit fd8b60
                     __FUNCTION__, value);
Packit fd8b60
            krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
Packit fd8b60
                                   _("Unsupported type while processing "
Packit fd8b60
                                     "'%s'\n"), value);
Packit fd8b60
            return KRB5_PREAUTH_FAILED;
Packit fd8b60
        }
Packit fd8b60
    } else {
Packit fd8b60
        idtype = IDTYPE_FILE;
Packit fd8b60
        residual = value;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    idopts->idtype = idtype;
Packit fd8b60
    pkiDebug("%s: idtype is %s\n", __FUNCTION__, idtype2string(idopts->idtype));
Packit fd8b60
    switch (idtype) {
Packit fd8b60
    case IDTYPE_ENVVAR:
Packit fd8b60
        return process_option_identity(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                       idopts, id_cryptoctx,
Packit fd8b60
                                       secure_getenv(residual));
Packit fd8b60
        break;
Packit fd8b60
    case IDTYPE_FILE:
Packit fd8b60
        retval = parse_fs_options(context, idopts, residual);
Packit fd8b60
        break;
Packit fd8b60
    case IDTYPE_PKCS12:
Packit fd8b60
        retval = parse_pkcs12_options(context, idopts, residual);
Packit fd8b60
        break;
Packit fd8b60
#ifndef WITHOUT_PKCS11
Packit fd8b60
    case IDTYPE_PKCS11:
Packit fd8b60
        retval = parse_pkcs11_options(context, idopts, residual);
Packit fd8b60
        break;
Packit fd8b60
#endif
Packit fd8b60
    case IDTYPE_DIR:
Packit fd8b60
        idopts->cert_filename = strdup(residual);
Packit fd8b60
        if (idopts->cert_filename == NULL)
Packit fd8b60
            retval = ENOMEM;
Packit fd8b60
        break;
Packit fd8b60
    default:
Packit fd8b60
        krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
Packit fd8b60
                               _("Internal error parsing "
Packit fd8b60
                                 "X509_user_identity\n"));
Packit fd8b60
        retval = EINVAL;
Packit fd8b60
        break;
Packit fd8b60
    }
Packit fd8b60
    return retval;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
process_option_ca_crl(krb5_context context,
Packit fd8b60
                      pkinit_plg_crypto_context plg_cryptoctx,
Packit fd8b60
                      pkinit_req_crypto_context req_cryptoctx,
Packit fd8b60
                      pkinit_identity_opts *idopts,
Packit fd8b60
                      pkinit_identity_crypto_context id_cryptoctx,
Packit fd8b60
                      const char *value,
Packit fd8b60
                      int catype)
Packit fd8b60
{
Packit fd8b60
    char *residual;
Packit fd8b60
    unsigned int typelen;
Packit fd8b60
    int idtype;
Packit fd8b60
Packit fd8b60
    pkiDebug("%s: processing catype %s, value '%s'\n",
Packit fd8b60
             __FUNCTION__, catype2string(catype), value);
Packit fd8b60
    residual = strchr(value, ':');
Packit fd8b60
    if (residual == NULL) {
Packit fd8b60
        pkiDebug("No type given for '%s'\n", value);
Packit fd8b60
        return EINVAL;
Packit fd8b60
    }
Packit fd8b60
    residual++; /* skip past colon */
Packit fd8b60
    typelen = residual - value;
Packit fd8b60
    if (strncmp(value, "FILE:", typelen) == 0) {
Packit fd8b60
        idtype = IDTYPE_FILE;
Packit fd8b60
    } else if (strncmp(value, "DIR:", typelen) == 0) {
Packit fd8b60
        idtype = IDTYPE_DIR;
Packit fd8b60
    } else {
Packit fd8b60
        return ENOTSUP;
Packit fd8b60
    }
Packit fd8b60
    return crypto_load_cas_and_crls(context,
Packit fd8b60
                                    plg_cryptoctx,
Packit fd8b60
                                    req_cryptoctx,
Packit fd8b60
                                    idopts, id_cryptoctx,
Packit fd8b60
                                    idtype, catype, residual);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Load any identity information which doesn't require us to ask a controlling
Packit fd8b60
 * user any questions, and record the names of anything else which would
Packit fd8b60
 * require us to ask questions.
Packit fd8b60
 */
Packit fd8b60
krb5_error_code
Packit fd8b60
pkinit_identity_initialize(krb5_context context,
Packit fd8b60
                           pkinit_plg_crypto_context plg_cryptoctx,
Packit fd8b60
                           pkinit_req_crypto_context req_cryptoctx,
Packit fd8b60
                           pkinit_identity_opts *idopts,
Packit fd8b60
                           pkinit_identity_crypto_context id_cryptoctx,
Packit fd8b60
                           krb5_clpreauth_callbacks cb,
Packit fd8b60
                           krb5_clpreauth_rock rock,
Packit fd8b60
                           krb5_principal princ)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code retval = EINVAL;
Packit fd8b60
    int i;
Packit fd8b60
Packit fd8b60
    pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
Packit fd8b60
    if (!(princ &&
Packit fd8b60
          krb5_principal_compare_any_realm(context, princ,
Packit fd8b60
                                           krb5_anonymous_principal()))) {
Packit fd8b60
        if (idopts == NULL || id_cryptoctx == NULL)
Packit fd8b60
            goto errout;
Packit fd8b60
Packit fd8b60
        /*
Packit fd8b60
         * If identity was specified, use that.  (For the kdc, this
Packit fd8b60
         * is specified as pkinit_identity in the kdc.conf.  For users,
Packit fd8b60
         * this is specified on the command line via X509_user_identity.)
Packit fd8b60
         * If a user did not specify identity on the command line,
Packit fd8b60
         * then we will try alternatives which may have been specified
Packit fd8b60
         * in the config file.
Packit fd8b60
         */
Packit fd8b60
        if (idopts->identity != NULL) {
Packit fd8b60
            retval = process_option_identity(context, plg_cryptoctx,
Packit fd8b60
                                             req_cryptoctx, idopts,
Packit fd8b60
                                             id_cryptoctx, idopts->identity);
Packit fd8b60
        } else if (idopts->identity_alt != NULL) {
Packit fd8b60
            for (i = 0; retval != 0 && idopts->identity_alt[i] != NULL; i++) {
Packit fd8b60
                retval = process_option_identity(context, plg_cryptoctx,
Packit fd8b60
                                                 req_cryptoctx, idopts,
Packit fd8b60
                                                 id_cryptoctx,
Packit fd8b60
                                                 idopts->identity_alt[i]);
Packit fd8b60
            }
Packit fd8b60
        } else {
Packit fd8b60
            retval = KRB5_PREAUTH_FAILED;
Packit fd8b60
            krb5_set_error_message(context, retval,
Packit fd8b60
                                   _("No user identity options specified"));
Packit fd8b60
            pkiDebug("%s: no user identity options specified\n", __FUNCTION__);
Packit fd8b60
            goto errout;
Packit fd8b60
        }
Packit fd8b60
        if (retval)
Packit fd8b60
            goto errout;
Packit fd8b60
Packit fd8b60
        retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                   idopts, id_cryptoctx, princ, TRUE);
Packit fd8b60
        if (retval)
Packit fd8b60
            goto errout;
Packit fd8b60
Packit fd8b60
        crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                              id_cryptoctx);
Packit fd8b60
    } else {
Packit fd8b60
        /* We're the anonymous principal. */
Packit fd8b60
        retval = 0;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
errout:
Packit fd8b60
    return retval;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Load identity information, including that which requires us to ask a
Packit fd8b60
 * controlling user any questions.  If we have PIN/password values which
Packit fd8b60
 * correspond to a given identity, use that, otherwise, if one is available,
Packit fd8b60
 * we'll use the prompter callback.
Packit fd8b60
 */
Packit fd8b60
krb5_error_code
Packit fd8b60
pkinit_identity_prompt(krb5_context context,
Packit fd8b60
                       pkinit_plg_crypto_context plg_cryptoctx,
Packit fd8b60
                       pkinit_req_crypto_context req_cryptoctx,
Packit fd8b60
                       pkinit_identity_opts *idopts,
Packit fd8b60
                       pkinit_identity_crypto_context id_cryptoctx,
Packit fd8b60
                       krb5_clpreauth_callbacks cb,
Packit fd8b60
                       krb5_clpreauth_rock rock,
Packit fd8b60
                       int do_matching,
Packit fd8b60
                       krb5_principal princ)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code retval = EINVAL;
Packit fd8b60
    const char *signer_identity;
Packit fd8b60
    int i;
Packit fd8b60
Packit fd8b60
    pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
Packit fd8b60
    if (!(princ &&
Packit fd8b60
          krb5_principal_compare_any_realm(context, princ,
Packit fd8b60
                                           krb5_anonymous_principal()))) {
Packit fd8b60
        retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                   idopts, id_cryptoctx, princ, FALSE);
Packit fd8b60
        if (retval)
Packit fd8b60
            goto errout;
Packit fd8b60
Packit fd8b60
        if (do_matching) {
Packit fd8b60
            /*
Packit fd8b60
             * Try to select exactly one certificate based on matching
Packit fd8b60
             * criteria.  Typical used for clients.
Packit fd8b60
             */
Packit fd8b60
            retval = pkinit_cert_matching(context, plg_cryptoctx,
Packit fd8b60
                                          req_cryptoctx, id_cryptoctx, princ);
Packit fd8b60
            if (retval) {
Packit fd8b60
                crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                      id_cryptoctx);
Packit fd8b60
                goto errout;
Packit fd8b60
            }
Packit fd8b60
        } else {
Packit fd8b60
            /*
Packit fd8b60
             * Tell crypto code to use the "default" identity.  Typically used
Packit fd8b60
             * for KDCs.
Packit fd8b60
             */
Packit fd8b60
            retval = crypto_cert_select_default(context, plg_cryptoctx,
Packit fd8b60
                                                req_cryptoctx, id_cryptoctx);
Packit fd8b60
            if (retval) {
Packit fd8b60
                crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                      id_cryptoctx);
Packit fd8b60
                goto errout;
Packit fd8b60
            }
Packit fd8b60
        }
Packit fd8b60
Packit fd8b60
        if (rock != NULL && cb != NULL && retval == 0) {
Packit fd8b60
            /* Save the signer identity if we're the client. */
Packit fd8b60
            if (crypto_retrieve_signer_identity(context, id_cryptoctx,
Packit fd8b60
                                                &signer_identity) == 0) {
Packit fd8b60
                cb->set_cc_config(context, rock, "X509_user_identity",
Packit fd8b60
                                  signer_identity);
Packit fd8b60
            }
Packit fd8b60
        }
Packit fd8b60
Packit fd8b60
        retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                       id_cryptoctx);
Packit fd8b60
        if (retval)
Packit fd8b60
            goto errout;
Packit fd8b60
    } /* Not anonymous principal */
Packit fd8b60
Packit fd8b60
    for (i = 0; idopts->anchors != NULL && idopts->anchors[i] != NULL; i++) {
Packit fd8b60
        retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                       idopts, id_cryptoctx,
Packit fd8b60
                                       idopts->anchors[i], CATYPE_ANCHORS);
Packit fd8b60
        if (retval)
Packit fd8b60
            goto errout;
Packit fd8b60
    }
Packit fd8b60
    for (i = 0; idopts->intermediates != NULL
Packit fd8b60
             && idopts->intermediates[i] != NULL; i++) {
Packit fd8b60
        retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                       idopts, id_cryptoctx,
Packit fd8b60
                                       idopts->intermediates[i],
Packit fd8b60
                                       CATYPE_INTERMEDIATES);
Packit fd8b60
        if (retval)
Packit fd8b60
            goto errout;
Packit fd8b60
    }
Packit fd8b60
    for (i = 0; idopts->crls != NULL && idopts->crls[i] != NULL; i++) {
Packit fd8b60
        retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
Packit fd8b60
                                       idopts, id_cryptoctx, idopts->crls[i],
Packit fd8b60
                                       CATYPE_CRLS);
Packit fd8b60
        if (retval)
Packit fd8b60
            goto errout;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
errout:
Packit fd8b60
    return retval;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Create an entry in the passed-in list for the named identity, optionally
Packit fd8b60
 * with the specified token flag value and/or supplied password, replacing any
Packit fd8b60
 * existing entry with the same identity name.
Packit fd8b60
 */
Packit fd8b60
krb5_error_code
Packit fd8b60
pkinit_set_deferred_id(pkinit_deferred_id **identities,
Packit fd8b60
                       const char *identity, unsigned long ck_flags,
Packit fd8b60
                       const char *password)
Packit fd8b60
{
Packit fd8b60
    int i;
Packit fd8b60
    pkinit_deferred_id *out = NULL, *ids;
Packit fd8b60
    char *tmp;
Packit fd8b60
Packit fd8b60
    /* Search for an entry that's already in the list. */
Packit fd8b60
    ids = *identities;
Packit fd8b60
    for (i = 0; ids != NULL && ids[i] != NULL; i++) {
Packit fd8b60
        if (strcmp(ids[i]->identity, identity) == 0) {
Packit fd8b60
            /* Replace its password value, then we're done. */
Packit fd8b60
            tmp = password ? strdup(password) : NULL;
Packit fd8b60
            if (password != NULL && tmp == NULL)
Packit fd8b60
                return ENOMEM;
Packit fd8b60
            ids[i]->ck_flags = ck_flags;
Packit fd8b60
            free(ids[i]->password);
Packit fd8b60
            ids[i]->password = tmp;
Packit fd8b60
            return 0;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* Resize the list. */
Packit fd8b60
    out = realloc(ids, sizeof(*ids) * (i + 2));
Packit fd8b60
    if (out == NULL)
Packit fd8b60
        goto oom;
Packit fd8b60
    *identities = out;
Packit fd8b60
Packit fd8b60
    /* Allocate the new final entry. */
Packit fd8b60
    out[i] = malloc(sizeof(*(out[i])));
Packit fd8b60
    if (out[i] == NULL)
Packit fd8b60
        goto oom;
Packit fd8b60
Packit fd8b60
    /* Populate the new entry. */
Packit fd8b60
    out[i]->magic = PKINIT_DEFERRED_ID_MAGIC;
Packit fd8b60
    out[i]->identity = strdup(identity);
Packit fd8b60
    if (out[i]->identity == NULL)
Packit fd8b60
        goto oom;
Packit fd8b60
Packit fd8b60
    out[i]->ck_flags = ck_flags;
Packit fd8b60
    out[i]->password = password ? strdup(password) : NULL;
Packit fd8b60
    if (password != NULL && out[i]->password == NULL)
Packit fd8b60
        goto oom;
Packit fd8b60
Packit fd8b60
    /* Terminate the list. */
Packit fd8b60
    out[i + 1] = NULL;
Packit fd8b60
    return 0;
Packit fd8b60
Packit fd8b60
oom:
Packit fd8b60
    if (out != NULL && out[i] != NULL) {
Packit fd8b60
        free(out[i]->identity);
Packit fd8b60
        free(out[i]);
Packit fd8b60
        out[i] = NULL;
Packit fd8b60
    }
Packit fd8b60
    return ENOMEM;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Return a password which we've associated with the named identity, if we've
Packit fd8b60
 * stored one.  Otherwise return NULL.
Packit fd8b60
 */
Packit fd8b60
const char *
Packit fd8b60
pkinit_find_deferred_id(pkinit_deferred_id *identities,
Packit fd8b60
                        const char *identity)
Packit fd8b60
{
Packit fd8b60
    int i;
Packit fd8b60
Packit fd8b60
    for (i = 0; identities != NULL && identities[i] != NULL; i++) {
Packit fd8b60
        if (strcmp(identities[i]->identity, identity) == 0)
Packit fd8b60
            return identities[i]->password;
Packit fd8b60
    }
Packit fd8b60
    return NULL;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Return the flags associated with the specified identity, or 0 if we don't
Packit fd8b60
 * have such an identity.
Packit fd8b60
 */
Packit fd8b60
unsigned long
Packit fd8b60
pkinit_get_deferred_id_flags(pkinit_deferred_id *identities,
Packit fd8b60
                             const char *identity)
Packit fd8b60
{
Packit fd8b60
    int i;
Packit fd8b60
Packit fd8b60
    for (i = 0; identities != NULL && identities[i] != NULL; i++) {
Packit fd8b60
        if (strcmp(identities[i]->identity, identity) == 0)
Packit fd8b60
            return identities[i]->ck_flags;
Packit fd8b60
    }
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Free a deferred_id list.
Packit fd8b60
 */
Packit fd8b60
void
Packit fd8b60
pkinit_free_deferred_ids(pkinit_deferred_id *identities)
Packit fd8b60
{
Packit fd8b60
    int i;
Packit fd8b60
Packit fd8b60
    for (i = 0; identities != NULL && identities[i] != NULL; i++) {
Packit fd8b60
        free(identities[i]->identity);
Packit fd8b60
        free(identities[i]->password);
Packit fd8b60
        free(identities[i]);
Packit fd8b60
    }
Packit fd8b60
    free(identities);
Packit fd8b60
}