From aba9bca31cc2507671e25f7ca8e642fce5e38671 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Tue, 10 Mar 2020 23:05:09 +0100 Subject: [PATCH] APPS: Add ctrl_str()-like functionality for X509 and X509_REQ This should really be part of libcrypto, but since this looks like added legacy support, it's preferable to keep it in apps for now. This allows to build functions that add user given verification options to X509 and X509_REQ structures. Fixes #11293 Reviewed-by: Paul Yang (Merged from https://github.com/openssl/openssl/pull/11302) --- apps/include/apps.h | 4 ++ apps/lib/app_x509.c | 134 ++++++++++++++++++++++++++++++++++++++++++++ apps/lib/build.info | 2 +- apps/req.c | 29 ++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 apps/lib/app_x509.c diff --git a/apps/include/apps.h b/apps/include/apps.h index 78be647619..ccafaef5f1 100644 --- a/apps/include/apps.h +++ b/apps/include/apps.h @@ -197,12 +197,16 @@ X509_NAME *parse_name(const char *str, long chtype, int multirdn); void policies_print(X509_STORE_CTX *ctx); int bio_to_mem(unsigned char **out, int maxlen, BIO *in); int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value); +int x509_ctrl_string(X509 *x, const char *value); +int x509_req_ctrl_string(X509_REQ *x, const char *value); int init_gen_str(EVP_PKEY_CTX **pctx, const char *algname, ENGINE *e, int do_param); int do_X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts); int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts); +int do_X509_REQ_verify(X509_REQ *x, EVP_PKEY *pkey, + STACK_OF(OPENSSL_STRING) *vfyopts); int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts); diff --git a/apps/lib/app_x509.c b/apps/lib/app_x509.c new file mode 100644 index 0000000000..89c5960fa6 --- /dev/null +++ b/apps/lib/app_x509.c @@ -0,0 +1,134 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include "apps.h" + +/* + * X509_ctrl_str() is sorely lacking in libcrypto, but is still needed to + * allow the application to process verification options in a manner similar + * to signature or other options that pass through EVP_PKEY_CTX_ctrl_str(), + * for uniformity. + * + * As soon as more stuff is added, the code will need serious rework. For + * the moment, it only handles the FIPS 196 / SM2 distinguishing ID. + */ +#ifdef EVP_PKEY_CTRL_SET1_ID +static ASN1_OCTET_STRING *mk_octet_string(void *value, size_t value_n) +{ + ASN1_OCTET_STRING *v = ASN1_OCTET_STRING_new(); + + if (v == NULL) { + BIO_printf(bio_err, "error: allocation failed\n"); + } else if (!ASN1_OCTET_STRING_set(v, value, value_n)) { + ASN1_OCTET_STRING_free(v); + v = NULL; + } + return v; +} +#endif + +static int x509_ctrl(void *object, int cmd, void *value, size_t value_n) +{ + switch (cmd) { +#ifdef EVP_PKEY_CTRL_SET1_ID + case EVP_PKEY_CTRL_SET1_ID: + { + ASN1_OCTET_STRING *v = mk_octet_string(value, value_n); + + if (v == NULL) { + BIO_printf(bio_err, + "error: setting distinguishing ID in certificate failed\n"); + return 0; + } + + X509_set0_distinguishing_id(object, v); + return 1; + } +#endif + default: + break; + } + return -2; /* typical EVP_PKEY return for "unsupported" */ +} + +static int x509_req_ctrl(void *object, int cmd, void *value, size_t value_n) +{ + switch (cmd) { +#ifdef EVP_PKEY_CTRL_SET1_ID + case EVP_PKEY_CTRL_SET1_ID: + { + ASN1_OCTET_STRING *v = mk_octet_string(value, value_n); + + if (v == NULL) { + BIO_printf(bio_err, + "error: setting distinguishing ID in certificate signing request failed\n"); + return 0; + } + + X509_REQ_set0_distinguishing_id(object, v); + return 1; + } +#endif + default: + break; + } + return -2; /* typical EVP_PKEY return for "unsupported" */ +} + +static int do_x509_ctrl_string(int (*ctrl)(void *object, int cmd, + void *value, size_t value_n), + void *object, const char *value) +{ + int rv = 0; + char *stmp, *vtmp = NULL; + size_t vtmp_len = 0; + int cmd = 0; /* Will get command values that make sense somehow */ + + stmp = OPENSSL_strdup(value); + if (stmp == NULL) + return -1; + vtmp = strchr(stmp, ':'); + if (vtmp != NULL) { + *vtmp = 0; + vtmp++; + vtmp_len = strlen(vtmp); + } + + if (strcmp(stmp, "distid") == 0) { +#ifdef EVP_PKEY_CTRL_SET1_ID + cmd = EVP_PKEY_CTRL_SET1_ID; /* ... except we put it in X509 */ +#endif + } else if (strcmp(stmp, "hexdistid") == 0) { + long hexid_len = 0; + void *hexid = OPENSSL_hexstr2buf((const char *)vtmp, &hexid_len); + + OPENSSL_free(stmp); + stmp = vtmp = hexid; + vtmp_len = (size_t)hexid_len; +#ifdef EVP_PKEY_CTRL_SET1_ID + cmd = EVP_PKEY_CTRL_SET1_ID; /* ... except we put it in X509 */ +#endif + } + + rv = ctrl(object, cmd, vtmp, vtmp_len); + + OPENSSL_free(stmp); + return rv; +} + +int x509_ctrl_string(X509 *x, const char *value) +{ + return do_x509_ctrl_string(x509_ctrl, x, value); +} + +int x509_req_ctrl_string(X509_REQ *x, const char *value) +{ + return do_x509_ctrl_string(x509_req_ctrl, x, value); +} diff --git a/apps/lib/build.info b/apps/lib/build.info index a7be58b101..129ffce933 100644 --- a/apps/lib/build.info +++ b/apps/lib/build.info @@ -9,7 +9,7 @@ ENDIF # Source for libapps $LIBAPPSSRC=apps.c apps_ui.c opt.c fmt.c s_cb.c s_socket.c app_rand.c \ - columns.c app_params.c names.c app_provider.c + columns.c app_params.c names.c app_provider.c app_x509.c IF[{- !$disabled{apps} -}] LIBS{noinst}=../libapps.a diff --git a/apps/req.c b/apps/req.c index 5186017282..d1c93a68f7 100644 --- a/apps/req.c +++ b/apps/req.c @@ -1685,6 +1685,25 @@ static int genpkey_cb(EVP_PKEY_CTX *ctx) return 1; } +static int do_x509_req_init(X509_REQ *x, STACK_OF(OPENSSL_STRING) *opts) +{ + int i; + + if (opts == NULL) + return 1; + + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (x509_req_ctrl_string(x, opt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", opt); + ERR_print_errors(bio_err); + return 0; + } + } + + return 1; +} + static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) { @@ -1780,6 +1799,16 @@ int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, return rv; } +int do_X509_REQ_verify(X509_REQ *x, EVP_PKEY *pkey, + STACK_OF(OPENSSL_STRING) *vfyopts) +{ + int rv = 0; + + if (do_x509_req_init(x, vfyopts) > 0) + rv = (X509_REQ_verify(x, pkey) > 0); + return rv; +} + int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) { -- 2.25.1