APPS: Add ctrl_str()-like functionality for X509 and X509_REQ
authorRichard Levitte <levitte@openssl.org>
Tue, 10 Mar 2020 22:05:09 +0000 (23:05 +0100)
committerRichard Levitte <levitte@openssl.org>
Sun, 15 Mar 2020 18:42:05 +0000 (19:42 +0100)
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 <kaishen.yy@antfin.com>
(Merged from https://github.com/openssl/openssl/pull/11302)

apps/include/apps.h
apps/lib/app_x509.c [new file with mode: 0644]
apps/lib/build.info
apps/req.c

index 78be6476190028b069f28fba3118bcf7401de492..ccafaef5f104cee30787a7155fef9a3b8eea7fcc 100644 (file)
@@ -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);
 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 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);
 
 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 (file)
index 0000000..89c5960
--- /dev/null
@@ -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 <string.h>
+#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);
+}
index a7be58b101663076871bbc3e424843124c545741..129ffce9335983f3d1f0233923245122b72a9a3b 100644 (file)
@@ -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 \
 
 # 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
 
 IF[{- !$disabled{apps} -}]
   LIBS{noinst}=../libapps.a
index 518601728276778d0c461eb593293712029faf16..d1c93a68f7906c68730a3dca4cad5364925a0a16 100644 (file)
@@ -1685,6 +1685,25 @@ static int genpkey_cb(EVP_PKEY_CTX *ctx)
     return 1;
 }
 
     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)
 {
 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;
 }
 
     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)
 {
 int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md,
                      STACK_OF(OPENSSL_STRING) *sigopts)
 {