Esempio n. 1
0
static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
                                  const UI_METHOD *ui_method, void *ui_data)
{
    OSSL_STORE_INFO *result = NULL;

    ctx->errcnt = 0;
    ERR_clear_error();

    if (ctx->type == is_dir) {
        do {
            char *newname = NULL;

            if (ctx->_.dir.last_entry == NULL) {
                if (!ctx->_.dir.end_reached) {
                    char errbuf[256];
                    assert(ctx->_.dir.last_errno != 0);
                    errno = ctx->_.dir.last_errno;
                    ctx->errcnt++;
                    openssl_strerror_r(errno, errbuf, sizeof(errbuf));
                    OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_SYS_LIB);
                    ERR_add_error_data(1, errbuf);
                }
                return NULL;
            }

            if (ctx->_.dir.last_entry[0] != '.'
                && file_name_check(ctx, ctx->_.dir.last_entry)
                && !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname))
                return NULL;

            /*
             * On the first call (with a NULL context), OPENSSL_DIR_read()
             * cares about the second argument.  On the following calls, it
             * only cares that it isn't NULL.  Therefore, we can safely give
             * it our URI here.
             */
            ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx,
                                                     ctx->_.dir.uri);
            ctx->_.dir.last_errno = errno;
            if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0)
                ctx->_.dir.end_reached = 1;

            if (newname != NULL
                && (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) {
                OPENSSL_free(newname);
                OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_OSSL_STORE_LIB);
                return NULL;
            }
        } while (result == NULL && !file_eof(ctx));
    } else {
        int matchcount = -1;

     again:
        result = file_load_try_repeat(ctx, ui_method, ui_data);
        if (result != NULL)
            return result;

        if (file_eof(ctx))
            return NULL;

        do {
            char *pem_name = NULL;      /* PEM record name */
            char *pem_header = NULL;    /* PEM record header */
            unsigned char *data = NULL; /* DER encoded data */
            long len = 0;               /* DER encoded data length */

            matchcount = -1;
            if (ctx->type == is_pem) {
                if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header,
                                   &data, &len, ui_method, ui_data,
                                   (ctx->flags & FILE_FLAG_SECMEM) != 0)) {
                    ctx->errcnt++;
                    goto endloop;
                }
            } else {
                if (!file_read_asn1(ctx->_.file.file, &data, &len)) {
                    ctx->errcnt++;
                    goto endloop;
                }
            }

            result = file_load_try_decode(ctx, pem_name, pem_header, data, len,
                                          ui_method, ui_data, &matchcount);

            if (result != NULL)
                goto endloop;

            /*
             * If a PEM name matches more than one handler, the handlers are
             * badly coded.
             */
            if (!ossl_assert(pem_name == NULL || matchcount <= 1)) {
                ctx->errcnt++;
                goto endloop;
            }

            if (matchcount > 1) {
                OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD,
                              OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE);
            } else if (matchcount == 1) {
                /*
                 * If there are other errors on the stack, they already show
                 * what the problem is.
                 */
                if (ERR_peek_error() == 0) {
                    OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD,
                                  OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE);
                    if (pem_name != NULL)
                        ERR_add_error_data(3, "PEM type is '", pem_name, "'");
                }
            }
            if (matchcount > 0)
                ctx->errcnt++;

         endloop:
            pem_free_flag(pem_name, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0);
            pem_free_flag(pem_header, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0);
            pem_free_flag(data, (ctx->flags & FILE_FLAG_SECMEM) != 0, len);
        } while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx));

        /* We bail out on ambiguity */
        if (matchcount > 1)
            return NULL;

        if (result != NULL
            && ctx->expected_type != 0
            && ctx->expected_type != OSSL_STORE_INFO_get_type(result)) {
            OSSL_STORE_INFO_free(result);
            goto again;
        }
    }

    return result;
}
Esempio n. 2
0
static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,
                                             const char *pem_name,
                                             const char *pem_header,
                                             unsigned char *data, size_t len,
                                             const UI_METHOD *ui_method,
                                             void *ui_data, int *matchcount)
{
    OSSL_STORE_INFO *result = NULL;
    BUF_MEM *new_mem = NULL;
    char *new_pem_name = NULL;
    int t = 0;

 again:
    {
        size_t i = 0;
        void *handler_ctx = NULL;
        const FILE_HANDLER **matching_handlers =
            OPENSSL_zalloc(sizeof(*matching_handlers)
                           * OSSL_NELEM(file_handlers));

        if (matching_handlers == NULL) {
            OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD_TRY_DECODE,
                          ERR_R_MALLOC_FAILURE);
            goto err;
        }

        *matchcount = 0;
        for (i = 0; i < OSSL_NELEM(file_handlers); i++) {
            const FILE_HANDLER *handler = file_handlers[i];
            int try_matchcount = 0;
            void *tmp_handler_ctx = NULL;
            OSSL_STORE_INFO *tmp_result =
                handler->try_decode(pem_name, pem_header, data, len,
                                    &tmp_handler_ctx, &try_matchcount,
                                    ui_method, ui_data);

            if (try_matchcount > 0) {

                matching_handlers[*matchcount] = handler;

                if (handler_ctx)
                    handler->destroy_ctx(&handler_ctx);
                handler_ctx = tmp_handler_ctx;

                if ((*matchcount += try_matchcount) > 1) {
                    /* more than one match => ambiguous, kill any result */
                    OSSL_STORE_INFO_free(result);
                    OSSL_STORE_INFO_free(tmp_result);
                    if (handler->destroy_ctx != NULL)
                        handler->destroy_ctx(&handler_ctx);
                    handler_ctx = NULL;
                    tmp_result = NULL;
                    result = NULL;
                }
                if (result == NULL)
                    result = tmp_result;
            }
        }

        if (*matchcount == 1 && matching_handlers[0]->repeatable) {
            ctx->_.file.last_handler = matching_handlers[0];
            ctx->_.file.last_handler_ctx = handler_ctx;
        }

        OPENSSL_free(matching_handlers);
    }

 err:
    OPENSSL_free(new_pem_name);
    BUF_MEM_free(new_mem);

    if (result != NULL
        && (t = OSSL_STORE_INFO_get_type(result)) == OSSL_STORE_INFO_EMBEDDED) {
        pem_name = new_pem_name =
            ossl_store_info_get0_EMBEDDED_pem_name(result);
        new_mem = ossl_store_info_get0_EMBEDDED_buffer(result);
        data = (unsigned char *)new_mem->data;
        len = new_mem->length;
        OPENSSL_free(result);
        result = NULL;
        goto again;
    }

    if (result != NULL)
        ERR_clear_error();

    return result;
}
Esempio n. 3
0
static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata,
                   int text, int noout, int recursive, int indent, BIO *out)
{
    OSSL_STORE_CTX *store_ctx = NULL;
    int ret = 1, items = 0;

    if ((store_ctx = OSSL_STORE_open(uri, uimeth, uidata, NULL, NULL))
        == NULL) {
        BIO_printf(bio_err, "Couldn't open file or uri %s\n", uri);
        ERR_print_errors(bio_err);
        return ret;
    }

    /* From here on, we count errors, and we'll return the count at the end */
    ret = 0;

    for (;;) {
        OSSL_STORE_INFO *info = OSSL_STORE_load(store_ctx);
        int type = info == NULL ? 0 : OSSL_STORE_INFO_get_type(info);
        const char *infostr =
            info == NULL ? NULL : OSSL_STORE_INFO_type_string(type);

        if (info == NULL) {
            if (OSSL_STORE_eof(store_ctx))
                break;

            if (OSSL_STORE_error(store_ctx)) {
                if (recursive)
                    ERR_clear_error();
                else
                    ERR_print_errors(bio_err);
                ret++;
                continue;
            }

            BIO_printf(bio_err,
                       "ERROR: OSSL_STORE_load() returned NULL without "
                       "eof or error indications\n");
            BIO_printf(bio_err, "       This is an error in the loader\n");
            ERR_print_errors(bio_err);
            ret++;
            break;
        }

        if (type == OSSL_STORE_INFO_NAME) {
            const char *name = OSSL_STORE_INFO_get0_NAME(info);
            const char *desc = OSSL_STORE_INFO_get0_NAME_description(info);
            indent_printf(indent, bio_out, "%d: %s: %s\n", items, infostr,
                          name);
            if (desc != NULL)
                indent_printf(indent, bio_out, "%s\n", desc);
        } else {
            indent_printf(indent, bio_out, "%d: %s\n", items, infostr);
        }

        /*
         * Unfortunately, PEM_X509_INFO_write_bio() is sorely lacking in
         * functionality, so we must figure out how exactly to write things
         * ourselves...
         */
        switch (type) {
        case OSSL_STORE_INFO_NAME:
            if (recursive) {
                const char *suburi = OSSL_STORE_INFO_get0_NAME(info);
                ret += process(suburi, uimeth, uidata, text, noout, recursive,
                               indent + 2, out);
            }
            break;
        case OSSL_STORE_INFO_PARAMS:
            if (text)
                EVP_PKEY_print_params(out, OSSL_STORE_INFO_get0_PARAMS(info),
                                      0, NULL);
            if (!noout)
                PEM_write_bio_Parameters(out,
                                         OSSL_STORE_INFO_get0_PARAMS(info));
            break;
        case OSSL_STORE_INFO_PKEY:
            if (text)
                EVP_PKEY_print_private(out, OSSL_STORE_INFO_get0_PKEY(info),
                                       0, NULL);
            if (!noout)
                PEM_write_bio_PrivateKey(out, OSSL_STORE_INFO_get0_PKEY(info),
                                         NULL, NULL, 0, NULL, NULL);
            break;
        case OSSL_STORE_INFO_CERT:
            if (text)
                X509_print(out, OSSL_STORE_INFO_get0_CERT(info));
            if (!noout)
                PEM_write_bio_X509(out, OSSL_STORE_INFO_get0_CERT(info));
            break;
        case OSSL_STORE_INFO_CRL:
            if (text)
                X509_CRL_print(out, OSSL_STORE_INFO_get0_CRL(info));
            if (!noout)
                PEM_write_bio_X509_CRL(out, OSSL_STORE_INFO_get0_CRL(info));
            break;
        default:
            BIO_printf(bio_err, "!!! Unknown code\n");
            ret++;
            break;
        }
        items++;
        OSSL_STORE_INFO_free(info);
    }
    indent_printf(indent, out, "Total found: %d\n", items);

    if (!OSSL_STORE_close(store_ctx)) {
        ERR_print_errors(bio_err);
        ret++;
    }

    return ret;
}