[rt-commit] r181 - in /redwax-tool/trunk: ChangeLog redwax-tool.c redwax-tool.h redwax_openssl.c

rt-commit at redwax.eu rt-commit at redwax.eu
Tue May 28 20:18:06 CEST 2024


Author: minfrin at redwax.eu
Date: Tue May 28 20:18:05 2024
New Revision: 181

Log:
Add --filter-purpose option to allow search and
verify to limit certificates by certificate 
purpose.

Modified:
    redwax-tool/trunk/ChangeLog
    redwax-tool/trunk/redwax-tool.c
    redwax-tool/trunk/redwax-tool.h
    redwax-tool/trunk/redwax_openssl.c

Modified: redwax-tool/trunk/ChangeLog
==============================================================================
--- redwax-tool/trunk/ChangeLog	(original)
+++ redwax-tool/trunk/ChangeLog	Tue May 28 20:18:05 2024
@@ -1,5 +1,9 @@
 
 Changes with v0.9.5
+
+ *) Add --filter-purpose option to allow search and
+    verify to limit certificates by certificate
+    purpose. [Graham Leggett]
 
  *) Fix a crash triggered when keychain is present but
     not used. [Graham Leggett]

Modified: redwax-tool/trunk/redwax-tool.c
==============================================================================
--- redwax-tool/trunk/redwax-tool.c	(original)
+++ redwax-tool/trunk/redwax-tool.c	Tue May 28 20:18:05 2024
@@ -78,6 +78,8 @@
         APR_HOOK_LINK(complete_verify_param);
         APR_HOOK_LINK(set_verify_date);
         APR_HOOK_LINK(set_verify_expiry);
+        APR_HOOK_LINK(set_purpose);
+        APR_HOOK_LINK(complete_purpose);
         APR_HOOK_LINK(process_pem_in);
         APR_HOOK_LINK(process_trust_pem_in);
         APR_HOOK_LINK(complete_pkcs11_in);
@@ -130,6 +132,10 @@
         (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, set_verify_expiry,
         (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, set_purpose,
+        (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, complete_purpose,
+        (redwax_tool_t * r, apr_hash_t *purposes), (r, purposes), OK, DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, process_pem_in,
         (redwax_tool_t * r, const char *arg, const char *secret), (r, arg, secret), DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, process_trust_pem_in,
@@ -225,56 +231,57 @@
 #define REDWAX_TOOL_FILTER_CURRENT 266
 #define REDWAX_TOOL_FILTER_DATE 267
 #define REDWAX_TOOL_FILTER_EXPIRY 268
-#define REDWAX_TOOL_CERT_OUT 269
-#define REDWAX_TOOL_NO_CERT_OUT 270
-#define REDWAX_TOOL_CHAIN_OUT 271
-#define REDWAX_TOOL_NO_CHAIN_OUT 272
-#define REDWAX_TOOL_ROOT_OUT 273
-#define REDWAX_TOOL_NO_ROOT_OUT 274
-#define REDWAX_TOOL_TRUST_OUT 275
-#define REDWAX_TOOL_NO_TRUST_OUT 276
-#define REDWAX_TOOL_CRL_OUT 277
-#define REDWAX_TOOL_NO_CRL_OUT 278
-#define REDWAX_TOOL_PARAM_OUT 279
-#define REDWAX_TOOL_NO_PARAM_OUT 280
-#define REDWAX_TOOL_KEY_IN 281
-#define REDWAX_TOOL_NO_KEY_IN 282
-#define REDWAX_TOOL_KEY_OUT 283
-#define REDWAX_TOOL_NO_KEY_OUT 284
-#define REDWAX_TOOL_AUTO_OUT 285
-#define REDWAX_TOOL_NO_AUTO_OUT 286
-#define REDWAX_TOOL_FILTER_VERIFY_PARAM 287
-#define REDWAX_TOOL_SECRET_SUFFIX_IN 288
-#define REDWAX_TOOL_SECRET_SUFFIX_OUT 289
-#define REDWAX_TOOL_SECRET_TOKEN_IN 290
-#define REDWAX_TOOL_SECRET_TOKEN_OUT 291
-#define REDWAX_TOOL_LABEL_OUT 292
-#define REDWAX_TOOL_NSS_OUT 293
-#define REDWAX_TOOL_NSS_SLOT_OUT 294
-#define REDWAX_TOOL_DER_OUT 295
-#define REDWAX_TOOL_PEM_OUT 296
-#define REDWAX_TOOL_PKCS12_OUT 297
-#define REDWAX_TOOL_PKCS11_OUT 298
-#define REDWAX_TOOL_PKCS11_MODULE_OUT 299
-#define REDWAX_TOOL_METADATA_OUT 300
-#define REDWAX_TOOL_METADATA_THRESHOLD 301
-#define REDWAX_TOOL_FORMAT_OUT 302
-#define REDWAX_TOOL_CALENDAR_OUT 303
-#define REDWAX_TOOL_CALENDAR_ALARM 304
-#define REDWAX_TOOL_REMINDER_OUT 305
-#define REDWAX_TOOL_JWKS_OUT 306
-#define REDWAX_TOOL_TEXT_OUT 307
-#define REDWAX_TOOL_NO_TEXT_OUT 308
-#define REDWAX_TOOL_SSH_PRIVATE_OUT 309
-#define REDWAX_TOOL_SSH_PUBLIC_OUT 310
-#define REDWAX_TOOL_SMIMEA_OUT 311
-#define REDWAX_TOOL_SSHFP_OUT 312
-#define REDWAX_TOOL_TLSA_OUT 313
-#define REDWAX_TOOL_USER_IN 314
-#define REDWAX_TOOL_USER_OUT 315
-#define REDWAX_TOOL_GROUP_IN 316
-#define REDWAX_TOOL_GROUP_OUT 317
-#define REDWAX_TOOL_ORDER_OUT 318
+#define REDWAX_TOOL_FILTER_PURPOSE 269
+#define REDWAX_TOOL_CERT_OUT 270
+#define REDWAX_TOOL_NO_CERT_OUT 271
+#define REDWAX_TOOL_CHAIN_OUT 272
+#define REDWAX_TOOL_NO_CHAIN_OUT 273
+#define REDWAX_TOOL_ROOT_OUT 274
+#define REDWAX_TOOL_NO_ROOT_OUT 275
+#define REDWAX_TOOL_TRUST_OUT 276
+#define REDWAX_TOOL_NO_TRUST_OUT 277
+#define REDWAX_TOOL_CRL_OUT 278
+#define REDWAX_TOOL_NO_CRL_OUT 279
+#define REDWAX_TOOL_PARAM_OUT 280
+#define REDWAX_TOOL_NO_PARAM_OUT 281
+#define REDWAX_TOOL_KEY_IN 282
+#define REDWAX_TOOL_NO_KEY_IN 283
+#define REDWAX_TOOL_KEY_OUT 284
+#define REDWAX_TOOL_NO_KEY_OUT 285
+#define REDWAX_TOOL_AUTO_OUT 286
+#define REDWAX_TOOL_NO_AUTO_OUT 287
+#define REDWAX_TOOL_FILTER_VERIFY_PARAM 288
+#define REDWAX_TOOL_SECRET_SUFFIX_IN 289
+#define REDWAX_TOOL_SECRET_SUFFIX_OUT 290
+#define REDWAX_TOOL_SECRET_TOKEN_IN 291
+#define REDWAX_TOOL_SECRET_TOKEN_OUT 292
+#define REDWAX_TOOL_LABEL_OUT 293
+#define REDWAX_TOOL_NSS_OUT 294
+#define REDWAX_TOOL_NSS_SLOT_OUT 295
+#define REDWAX_TOOL_DER_OUT 296
+#define REDWAX_TOOL_PEM_OUT 297
+#define REDWAX_TOOL_PKCS12_OUT 298
+#define REDWAX_TOOL_PKCS11_OUT 299
+#define REDWAX_TOOL_PKCS11_MODULE_OUT 300
+#define REDWAX_TOOL_METADATA_OUT 301
+#define REDWAX_TOOL_METADATA_THRESHOLD 302
+#define REDWAX_TOOL_FORMAT_OUT 303
+#define REDWAX_TOOL_CALENDAR_OUT 304
+#define REDWAX_TOOL_CALENDAR_ALARM 305
+#define REDWAX_TOOL_REMINDER_OUT 306
+#define REDWAX_TOOL_JWKS_OUT 307
+#define REDWAX_TOOL_TEXT_OUT 308
+#define REDWAX_TOOL_NO_TEXT_OUT 309
+#define REDWAX_TOOL_SSH_PRIVATE_OUT 310
+#define REDWAX_TOOL_SSH_PUBLIC_OUT 311
+#define REDWAX_TOOL_SMIMEA_OUT 312
+#define REDWAX_TOOL_SSHFP_OUT 313
+#define REDWAX_TOOL_TLSA_OUT 314
+#define REDWAX_TOOL_USER_IN 315
+#define REDWAX_TOOL_USER_OUT 316
+#define REDWAX_TOOL_GROUP_IN 317
+#define REDWAX_TOOL_GROUP_OUT 318
+#define REDWAX_TOOL_ORDER_OUT 319
 
 #define REDWAX_EXIT_OK 0
 #define REDWAX_EXIT_INIT 1
@@ -320,6 +327,7 @@
         "  --filter-verify-params=name\tSpecify the name of the set of parameters used\n\t\t\t\tfor verification. If unspecified, set to\n\t\t\t\t'default'." },
     { "filter-date", REDWAX_TOOL_FILTER_DATE, 1, "  --filter-date=date\t\tSet the date to be used for certificate\n\t\t\t\tverification. If unset, it will default to the\n\t\t\t\tcurrent time. Date format is generalized time\n\t\t\t\tsyntax as defined in RFC 4517 section 3.3.13." },
     { "filter-expiry", REDWAX_TOOL_FILTER_EXPIRY, 1, "  --filter-expiry=[option]\tVerify certificate expiry. 'check' does expiry\n\t\t\t\tverification. 'ignore' allows expired\n\t\t\t\tcertificates. 'ignore-leaf' allows expired leaf\n\t\t\t\tcertificates. 'ignore-chain' allows expired\n\t\t\t\tchain certificates. Default is 'check'." },
+    { "filter-purpose", REDWAX_TOOL_FILTER_PURPOSE, 1, "  --filter-purpose=purpose\tSet the purpose of the certificate to verify.\n\t\t\t\tIf unset, it will default to any purpose." },
     { "text-out", REDWAX_TOOL_TEXT_OUT, 0,
         "  --text-out\t\t\tInclude additional text in certificate PEM and\n\t\t\t\tmetadata output." },
     { "no-text-out", REDWAX_TOOL_NO_TEXT_OUT, 0,
@@ -1749,6 +1757,31 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t redwax_complete_purpose(redwax_tool_t *r, const char *arg,
+        redwax_token_quoted_e quoted)
+{
+    apr_hash_t *purposes = apr_hash_make(r->pool);
+
+    apr_hash_index_t *hi;
+    void *val;
+    int arglen =  strlen(arg);
+
+    rt_run_complete_purpose(r, purposes);
+
+    for (hi = apr_hash_first(r->pool, purposes); hi; hi = apr_hash_next(hi)) {
+        apr_hash_this(hi, NULL, NULL, &val);
+
+        if (!strncmp(arg, (const char *)val, arglen)) {
+
+            apr_file_printf(r->out, "%s \n",
+                    redwax_pescape_echo_quoted(r->pool,
+                            (const char *)val, quoted, 1));
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
 static apr_status_t redwax_complete_nss_token_out(redwax_tool_t *r, const char *arg,
         redwax_token_quoted_e quoted)
 {
@@ -2285,6 +2318,17 @@
     return status;
 }
 
+static apr_status_t redwax_set_purpose(redwax_tool_t *r, const char *arg)
+{
+    apr_status_t status = rt_run_set_purpose(r, arg);
+
+    if (status) {
+        r->rc = REDWAX_EXIT_OPTIONS;
+    }
+
+    return status;
+}
+
 static apr_status_t redwax_set_threshold(redwax_tool_t *r, const char *arg)
 {
     r->threshold = atoi(arg) * 86400;
@@ -2645,6 +2689,12 @@
         }
         case REDWAX_TOOL_FILTER_EXPIRY: {
             if (redwax_set_verify_expiry(r, optarg)) {
+                return REDWAX_EXIT_OPTIONS;
+            }
+            break;
+        }
+        case REDWAX_TOOL_FILTER_PURPOSE: {
+            if (redwax_set_purpose(r, optarg)) {
                 return REDWAX_EXIT_OPTIONS;
             }
             break;
@@ -3006,6 +3056,10 @@
                 redwax_complete_verify_param(r, optarg, state.isquoted);
                 break;
             }
+            case REDWAX_TOOL_FILTER_PURPOSE: {
+                redwax_complete_purpose(r, optarg, state.isquoted);
+                break;
+            }
             case REDWAX_TOOL_NSS_OUT: {
                 redwax_complete_directory(r, optarg, state.isquoted);
                 break;
@@ -3212,6 +3266,10 @@
         }
         case REDWAX_TOOL_FILTER_VERIFY_PARAM: {
             redwax_complete_verify_param(r, "", state.isquoted);
+            break;
+        }
+        case REDWAX_TOOL_FILTER_PURPOSE: {
+            redwax_complete_purpose(r, "", state.isquoted);
             break;
         }
         case REDWAX_TOOL_NSS_OUT: {

Modified: redwax-tool/trunk/redwax-tool.h
==============================================================================
--- redwax-tool/trunk/redwax-tool.h	(original)
+++ redwax-tool/trunk/redwax-tool.h	Tue May 28 20:18:05 2024
@@ -132,6 +132,7 @@
     apr_hash_t *cert_relationships;
     const char *verify_param;
     const char *verify_date;
+    const char *purpose;
     const char *secret_suffix_in;
     const char *secret_suffix_out;
     const char *secret_token_in;
@@ -719,6 +720,22 @@
         (redwax_tool_t *r, const char *arg));
 
 /**
+ * Hook to complete purposes.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, complete_purpose,
+        (redwax_tool_t *r, apr_hash_t *purposes));
+
+/**
+ * Hook to set the purposes.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, set_purpose,
+        (redwax_tool_t *r, const char *arg));
+
+/**
  * Hook to search for intermediate and root certificates.
  *
  * @param r The redwax-tool context.

Modified: redwax-tool/trunk/redwax_openssl.c
==============================================================================
--- redwax-tool/trunk/redwax_openssl.c	(original)
+++ redwax-tool/trunk/redwax_openssl.c	Tue May 28 20:18:05 2024
@@ -1660,6 +1660,58 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t redwax_openssl_set_purpose(redwax_tool_t *r, const char *arg)
+{
+    int purpose;
+
+    if (0 > (purpose = X509_PURPOSE_get_by_sname(arg))) {
+
+        int i, nelts;
+        int count = X509_PURPOSE_get_count();
+
+        struct iovec *purposes = apr_palloc(r->pool, count * sizeof(struct iovec) * 2);
+
+        for (i = 0, nelts = 0; i < count; i++) {
+            X509_PURPOSE *purpose = X509_PURPOSE_get0(i);
+            char *name = X509_PURPOSE_get0_sname(purpose);
+            if (nelts) {
+                purposes[nelts].iov_base = ", ";
+                purposes[nelts].iov_len = 2;
+                nelts++;
+            }
+            purposes[nelts].iov_base = name;
+            purposes[nelts].iov_len = strlen(name);
+            nelts++;
+        }
+
+        redwax_print_error(r,
+                "Purpose '%s' not found, must be one of: %s\n", arg,
+                apr_pstrcatv(r->pool, purposes, nelts, NULL));
+
+        return APR_ENOENT;
+    }
+
+    r->purpose = arg;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t redwax_openssl_complete_purpose(redwax_tool_t *r,
+        apr_hash_t *params)
+{
+    int i;
+    int count = X509_PURPOSE_get_count();
+
+    for (i = 0; i < count; i++) {
+        X509_PURPOSE *purpose = X509_PURPOSE_get0(i);
+        char *name = X509_PURPOSE_get0_sname(purpose);
+
+        apr_hash_set(params, name, APR_HASH_KEY_STRING, name);
+    }
+
+    return APR_SUCCESS;
+}
+
 static apr_status_t redwax_openssl_complete_filter_search(redwax_tool_t *r,
         apr_hash_t *filters)
 {
@@ -1671,41 +1723,94 @@
 
 static int search_cert_match(redwax_tool_t *r, const redwax_certificate_t *cert)
 {
+    apr_hash_index_t *hi;
+    const void *key;
+    apr_ssize_t klen;
+
     const unsigned char *der = cert->der;
 
     X509 *x = d2i_X509(NULL, &der, cert->len);
 
-    int match = 0;
-
     if (x) {
 
-        apr_hash_index_t *hi;
-        const void *key;
-        apr_ssize_t klen;
-
-        for (hi = apr_hash_first(r->pool, r->emails); hi; hi = apr_hash_next(hi)) {
-            apr_hash_this(hi, &key, &klen, NULL);
-
-            if (X509_check_email(x, key, klen, 0) == 1) {
-                match = 1;
-            }
-
-        }
-
-        for (hi = apr_hash_first(r->pool, r->hostnames); hi; hi = apr_hash_next(hi)) {
-            apr_hash_this(hi, &key, &klen, NULL);
-
-             if (X509_check_host(x, key, klen, 0, NULL) == 1) {
-                match = 1;
-            }
-
-        }
-
-        for (hi = apr_hash_first(r->pool, r->ips); hi; hi = apr_hash_next(hi)) {
-            apr_hash_this(hi, &key, &klen, NULL);
-
-             if (X509_check_ip_asc(x, key, 0) == 1) {
-                match = 1;
+        if (r->purpose) {
+
+            X509_PURPOSE *xptmp;
+
+            int purpose = X509_PURPOSE_get_by_sname(r->purpose);
+
+            if (purpose == -1) {
+                redwax_print_error(r,
+                        "When searchinging, purpose was not recognised: %s\n", r->purpose);
+                return APR_EINVAL;
+            }
+
+            /* purpose index -> purpose object */
+            xptmp = X509_PURPOSE_get0(purpose);
+
+            /* purpose object -> purpose value */
+            purpose = X509_PURPOSE_get_id(xptmp);
+
+            if (!X509_check_purpose(x, purpose, 0)) {
+                X509_free(x);
+                return 0;
+            }
+        }
+
+        if (apr_hash_count(r->emails)) {
+
+            int match = 0;
+
+            for (hi = apr_hash_first(r->pool, r->emails); hi; hi = apr_hash_next(hi)) {
+                apr_hash_this(hi, &key, &klen, NULL);
+
+                if (X509_check_email(x, key, klen, 0) == 1) {
+                    match = 1;
+                }
+            }
+
+            if (!match) {
+                X509_free(x);
+                return 0;
+            }
+
+        }
+
+        if (apr_hash_count(r->hostnames)) {
+
+            int match = 0;
+
+            for (hi = apr_hash_first(r->pool, r->hostnames); hi; hi = apr_hash_next(hi)) {
+                apr_hash_this(hi, &key, &klen, NULL);
+
+                if (X509_check_host(x, key, klen, 0, NULL) == 1) {
+                    match = 1;
+                }
+
+            }
+            if (!match) {
+                X509_free(x);
+                return 0;
+            }
+
+        }
+
+        if (apr_hash_count(r->ips)) {
+
+            int match = 0;
+
+            for (hi = apr_hash_first(r->pool, r->ips); hi; hi = apr_hash_next(hi)) {
+                apr_hash_this(hi, &key, &klen, NULL);
+
+                if (X509_check_ip_asc(x, key, 0) == 1) {
+                    match = 1;
+                }
+
+            }
+
+            if (!match) {
+                X509_free(x);
+                return 0;
             }
 
         }
@@ -1713,7 +1818,7 @@
         X509_free(x);
     }
 
-    return match;
+    return 1;
 }
 
 static apr_status_t redwax_openssl_process_filter_search(redwax_tool_t *r,
@@ -1947,6 +2052,31 @@
         return APR_ENOENT;
     }
 
+    if (r->purpose) {
+
+        X509_PURPOSE *xptmp;
+
+        int purpose = X509_PURPOSE_get_by_sname(r->purpose);
+
+        if (purpose == -1) {
+            redwax_print_error(r,
+                    "When verifying, purpose was not recognised: %s\n", r->purpose);
+            return APR_EINVAL;
+        }
+
+        /* purpose index -> purpose object */
+        xptmp = X509_PURPOSE_get0(purpose);
+
+        /* purpose object -> purpose value */
+        purpose = X509_PURPOSE_get_id(xptmp);
+
+        if (!X509_VERIFY_PARAM_set_purpose(X509_STORE_get0_param(store), purpose)) {
+            redwax_print_error(r,
+                    "When verifying, purpose could not be specifed\n");
+            redwax_openssl_print_errors(r);
+            return APR_ENOENT;
+        }
+    }
 
     for (i = 0; i < r->certs_in->nelts; i++)
     {
@@ -5972,6 +6102,8 @@
     rt_hook_set_verify_param(redwax_openssl_set_verify_param, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_set_verify_date(redwax_openssl_set_verify_date, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_set_verify_expiry(redwax_openssl_set_verify_expiry, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_complete_purpose(redwax_openssl_complete_purpose, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_set_purpose(redwax_openssl_set_purpose, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_process_pem_in(redwax_openssl_process_pem_in, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_process_trust_pem_in(redwax_openssl_process_trust_pem_in, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_process_pkcs12_in(redwax_openssl_process_pkcs12_in, NULL, NULL, APR_HOOK_MIDDLE);



More information about the rt-commit mailing list