URL: https://github.com/SSSD/sssd/pull/674
Author: sumit-bose
 Title: #674: p11_child: add OCSP and CRL check ot the OpenSSL version
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/674/head:pr674
git checkout pr674
From 9b807cd962983c971c3259e12ba613752ab81f84 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 10 Oct 2018 15:37:16 +0200
Subject: [PATCH 1/2] p11_child: add OCSP check ot the OpenSSL version

Related to https://pagure.io/SSSD/sssd/issue/3489
---
 src/man/sssd.conf.5.xml           |  26 ++-
 src/p11_child/p11_child_openssl.c | 335 ++++++++++++++++++++++++++++++
 src/tests/cmocka/test_utils.c     |   3 +
 src/util/util.c                   |   2 +
 4 files changed, 359 insertions(+), 7 deletions(-)

diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index c8d53f01f3..5e3ae48d04 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -479,8 +479,8 @@
                                         be replaced with the URL of the OCSP
                                         default responder e.g.
                                         http://example.com:80/ocsp.</para>
-                                        <para>This option must be used together
-                                        with
+                                        <para>(NSS Version) This option must be
+                                        used together with
                                         ocsp_default_responder_signing_cert.
                                         </para>
                                     </listitem>
@@ -489,17 +489,29 @@
                                     <term>
                                     ocsp_default_responder_signing_cert=NAME</term>
                                     <listitem>
-                                        <para>The nickname of the cert to trust
-                                        (expected) to sign the OCSP responses.
-                                        The certificate with the given nickname
-                                        must be available in the systems NSS
-                                        database.</para>
+                                        <para>(NSS Version) The nickname of the
+                                        cert to trust (expected) to sign the
+                                        OCSP responses.  The certificate with
+                                        the given nickname must be available in
+                                        the systems NSS database.</para>
                                         <para>This option must be used together
                                         with ocsp_default_responder.</para>
+                                        <para>(OpenSSL version) This option is
+                                        currently ignored. All needed
+                                        certificates must be available in the
+                                        PEM file given by
+                                        pam_cert_db_path.</para>
                                     </listitem>
                                 </varlistentry>
                                 </variablelist>
                             </para>
+                            <para condition="with_nss">
+                                This man page was generated for the NSS version.
+                            </para>
+                            <para condition="with_openssl">
+                                This man page was generated for the OpenSSL
+                                version.
+                            </para>
                             <para>
                                 Unknown options are reported but ignored.
                             </para>
diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
index 000e1c94f1..47c44cd57f 100644
--- a/src/p11_child/p11_child_openssl.c
+++ b/src/p11_child/p11_child_openssl.c
@@ -28,6 +28,7 @@
 #include <openssl/x509.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
+#include <openssl/ocsp.h>
 #include <p11-kit/p11-kit.h>
 #include <p11-kit/uri.h>
 
@@ -42,8 +43,333 @@ struct p11_ctx {
     X509_STORE *x509_store;
     const char *ca_db;
     bool wait_for_card;
+    struct cert_verify_opts *cert_verify_opts;
 };
 
+static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host,
+                                      const char *path,
+                                      OCSP_REQUEST *req, int req_timeout)
+{
+    int fd;
+    int rv;
+    OCSP_REQ_CTX *ctx = NULL;
+    OCSP_RESPONSE *rsp = NULL;
+    fd_set confds;
+    struct timeval tv;
+
+    if (req_timeout != -1) {
+        BIO_set_nbio(cbio, 1);
+    }
+
+    rv = BIO_do_connect(cbio);
+
+    if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
+        DEBUG(SSSDBG_OP_FAILURE, "Error connecting BIO\n");
+        return NULL;
+    }
+
+    if (BIO_get_fd(cbio, &fd) < 0) {
+        DEBUG(SSSDBG_OP_FAILURE, "Can't get connection fd\n");
+        goto err;
+    }
+
+    if (req_timeout != -1 && rv <= 0) {
+        FD_ZERO(&confds);
+        FD_SET(fd, &confds);
+        tv.tv_usec = 0;
+        tv.tv_sec = req_timeout;
+        rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
+        if (rv == 0) {
+            DEBUG(SSSDBG_OP_FAILURE, "Timeout on connect\n");
+            return NULL;
+        }
+    }
+
+    ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
+    if (ctx == NULL) {
+        return NULL;
+    }
+
+    if (OCSP_REQ_CTX_add1_header(ctx, "Host", host) == 0) {
+        goto err;
+    }
+
+    if (!OCSP_REQ_CTX_set1_req(ctx, req)) {
+        goto err;
+    }
+
+    for (;;) {
+        rv = OCSP_sendreq_nbio(&rsp, ctx);
+        if (rv != -1)
+            break;
+        if (req_timeout == -1)
+            continue;
+        FD_ZERO(&confds);
+        FD_SET(fd, &confds);
+        tv.tv_usec = 0;
+        tv.tv_sec = req_timeout;
+        if (BIO_should_read(cbio)) {
+            rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv);
+        } else if (BIO_should_write(cbio)) {
+            rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE, "Unexpected retry condition\n");
+            goto err;
+        }
+        if (rv == 0) {
+            DEBUG(SSSDBG_OP_FAILURE, "Timeout on request\n");
+            break;
+        }
+        if (rv == -1) {
+            DEBUG(SSSDBG_OP_FAILURE, "Select error\n");
+            break;
+        }
+
+    }
+ err:
+    OCSP_REQ_CTX_free(ctx);
+
+    return rsp;
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#define TLS_client_method SSLv23_client_method
+#define OCSP_REQUEST_add0_id OCSP_request_add0_id
+#endif
+
+OCSP_RESPONSE *process_responder(OCSP_REQUEST *req,
+                                 const char *host, const char *path,
+                                 const char *port, int use_ssl,
+                                 int req_timeout)
+{
+    BIO *cbio = NULL;
+    SSL_CTX *ctx = NULL;
+    OCSP_RESPONSE *resp = NULL;
+
+    cbio = BIO_new_connect(host);
+    if (cbio == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Error creating connect BIO\n");
+        goto end;
+    }
+    if (port != NULL)
+        BIO_set_conn_port(cbio, port);
+    if (use_ssl == 1) {
+        BIO *sbio;
+        ctx = SSL_CTX_new(TLS_client_method());
+        if (ctx == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "Error creating SSL context.\n");
+            goto end;
+        }
+        SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+        sbio = BIO_new_ssl(ctx, 1);
+        cbio = BIO_push(sbio, cbio);
+    }
+
+    resp = query_responder(cbio, host, path, req, req_timeout);
+    if (resp == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Error querying OCSP responder\n");
+    }
+
+ end:
+    BIO_free_all(cbio);
+    SSL_CTX_free(ctx);
+    return resp;
+}
+
+static errno_t do_ocsp(struct p11_ctx *p11_ctx, X509 *cert)
+{
+    OCSP_REQUEST *ocsp_req = NULL;
+    OCSP_RESPONSE *ocsp_resp = NULL;
+    OCSP_BASICRESP *ocsp_basic = NULL;
+    OCSP_CERTID *cid = NULL;
+    STACK_OF(OPENSSL_STRING) *ocsp_urls = NULL;
+    char *url_str;
+    X509 *issuer = NULL;
+    int req_timeout = -1;
+    int status;
+    int ret = EIO;
+    int reason;
+    ASN1_GENERALIZEDTIME *revtime;
+    ASN1_GENERALIZEDTIME *thisupd;
+    ASN1_GENERALIZEDTIME *nextupd;
+    long grace_time = (5 * 60); /* Allow 5 minutes time difference when
+                                 * checking the validity of the OCSP response */
+    char *host = NULL;
+    char *path = NULL;
+    char *port = NULL;
+    int use_ssl;
+    X509_NAME *issuer_name = NULL;
+    X509_OBJECT *x509_obj;
+
+    ocsp_urls = X509_get1_ocsp(cert);
+    if (ocsp_urls == NULL
+            && p11_ctx->cert_verify_opts->ocsp_default_responder == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "No OCSP URL in certificate and no default responder defined, "
+              "skipping OCSP check.\n");
+        return EOK;
+    }
+
+    if (p11_ctx->cert_verify_opts->ocsp_default_responder != NULL) {
+        url_str = p11_ctx->cert_verify_opts->ocsp_default_responder;
+    } else {
+        if (sk_OPENSSL_STRING_num(ocsp_urls) > 1) {
+            DEBUG(SSSDBG_CONF_SETTINGS,
+                  "Found more than 1 OCSP URLs, just using the first.\n");
+        }
+
+        url_str = sk_OPENSSL_STRING_value(ocsp_urls, 0);
+    }
+
+    DEBUG(SSSDBG_TRACE_ALL, "Using OCSP URL [%s].\n", url_str);
+
+    ret = OCSP_parse_url(url_str, &host, &port, &path, &use_ssl);
+    if (ret != 1) {
+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_parse_url failed to parse [%s].\n",
+                                 url_str);
+        ret = EIO;
+        goto done;
+    }
+
+    issuer_name = X509_get_issuer_name(cert);
+    if (issuer_name == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Certificate has no issuer, "
+                                   "cannot run OCSP check.\n");
+        ret = EINVAL;
+        goto done;
+    }
+
+    x509_obj = X509_OBJECT_retrieve_by_subject(p11_ctx->x509_store->objs,
+                                               X509_LU_X509, issuer_name);
+    if (x509_obj == NULL || x509_obj->type != X509_LU_X509) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Issuer not found.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    issuer = x509_obj->data.x509;
+
+    ocsp_req = OCSP_REQUEST_new();
+    if (ocsp_req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_REQUEST_new failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    cid = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
+    if (cid == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_cert_to_id failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    if (OCSP_REQUEST_add0_id(ocsp_req, cid) == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_REQUEST_add0_id failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    OCSP_request_add1_nonce(ocsp_req, NULL, -1);
+
+    ocsp_resp = process_responder(ocsp_req, host, path, port, use_ssl,
+                                  req_timeout);
+    if (ocsp_resp == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "process_responder failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    status = OCSP_response_status(ocsp_resp);
+    if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP response error: [%d][%s].\n",
+                                   status, OCSP_response_status_str(status));
+        ret = EIO;
+        goto done;
+    }
+
+    ocsp_basic = OCSP_response_get1_basic(ocsp_resp);
+    if (ocsp_resp == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "OCSP_response_get1_basic failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    switch (OCSP_check_nonce(ocsp_req, ocsp_basic)) {
+    case -1:
+        DEBUG(SSSDBG_CRIT_FAILURE, "No nonce in OCSP response. This might "
+              "indicate a replay attack or an OCSP responder which does not "
+              "support nonces.  Accepting response.\n");
+        break;
+    case 0:
+        DEBUG(SSSDBG_CRIT_FAILURE, "Nonce in OCSP response does not match the "
+                                   "one used in the request.\n");
+        ret = EIO;
+        goto done;
+        break;
+    case 1:
+        DEBUG(SSSDBG_TRACE_ALL, "Nonce in OCSP response is the same as the one "
+                                "used in the request.\n");
+        break;
+    case 2:
+    case 3:
+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing nonce in OCSP request, this should"
+                                   "never happen.\n");
+        ret = EIO;
+        goto done;
+        break;
+    default:
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected result of OCSP_check_nonce.\n");
+    }
+
+    status = OCSP_basic_verify(ocsp_basic, NULL, p11_ctx->x509_store, 0);
+    if (status != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP_base_verify failed to verify OCSP "
+                                   "response.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    ret = OCSP_resp_find_status(ocsp_basic, cid, &status, &reason,
+                                &revtime, &thisupd, &nextupd);
+    if (ret != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP response does not contain status of "
+                                   "our certificate.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    if (status != V_OCSP_CERTSTATUS_GOOD) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP check failed with [%d][%s].\n",
+                                   status, OCSP_cert_status_str(status));
+        if (status == V_OCSP_CERTSTATUS_REVOKED) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Certificate is revoked [%d][%s].\n",
+                                       reason, OCSP_crl_reason_str(reason));
+        }
+        ret = EIO;
+        goto done;
+    }
+
+    if (OCSP_check_validity(thisupd, nextupd, grace_time, -1) != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "OCSP response is not valid anymore.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_ALL, "OCSP check was successful.\n");
+    ret = EOK;
+
+done:
+    OCSP_BASICRESP_free(ocsp_basic);
+    OCSP_RESPONSE_free(ocsp_resp);
+    OCSP_REQUEST_free(ocsp_req);
+
+    OPENSSL_free(host);
+    OPENSSL_free(port);
+    OPENSSL_free(path);
+    X509_email_free(ocsp_urls);
+
+    return ret;
+}
 
 static char *get_pkcs11_uri(TALLOC_CTX *mem_ctx, CK_INFO *module_info,
                             CK_SLOT_INFO *slot_info, CK_SLOT_ID slot_id,
@@ -191,6 +517,7 @@ errno_t init_verification(struct p11_ctx *p11_ctx,
     }
 
     p11_ctx->x509_store = store;
+    p11_ctx->cert_verify_opts = cert_verify_opts;
     talloc_set_destructor(p11_ctx, talloc_free_x509_store);
 
     ret = EOK;
@@ -262,6 +589,14 @@ bool do_verification(struct p11_ctx *p11_ctx, X509 *cert)
         goto done;
     }
 
+    if (p11_ctx->cert_verify_opts->do_ocsp) {
+        ret = do_ocsp(p11_ctx, cert);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "do_ocsp failed.\n");
+            goto done;
+        }
+    }
+
     res = true;
 
 done:
diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
index 1a8699a2a8..c86e526e82 100644
--- a/src/tests/cmocka/test_utils.c
+++ b/src/tests/cmocka/test_utils.c
@@ -1612,6 +1612,8 @@ static void test_parse_cert_verify_opts(void **state)
                                  &cv_opts);
     assert_int_equal(ret, EINVAL);
 
+/* Only NSS requires that both are set */
+#ifdef HAVE_NSS
     ret = parse_cert_verify_opts(global_talloc_context,
                                  "ocsp_default_responder=abc", &cv_opts);
     assert_int_equal(ret, EINVAL);
@@ -1620,6 +1622,7 @@ static void test_parse_cert_verify_opts(void **state)
                                  "ocsp_default_responder_signing_cert=def",
                                  &cv_opts);
     assert_int_equal(ret, EINVAL);
+#endif
 
     ret = parse_cert_verify_opts(global_talloc_context,
                                  "ocsp_default_responder=abc,"
diff --git a/src/util/util.c b/src/util/util.c
index 53dd9a13ab..7f475fa9b5 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1123,6 +1123,7 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
         }
     }
 
+#ifdef HAVE_NSS
     if ((cert_verify_opts->ocsp_default_responder == NULL
             && cert_verify_opts->ocsp_default_responder_signing_cert != NULL)
         || (cert_verify_opts->ocsp_default_responder != NULL
@@ -1135,6 +1136,7 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
         ret = EINVAL;
         goto done;
     }
+#endif
 
     ret = EOK;
 

From afdb22c11e15ba39319b5b4f8284fecadc973989 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Thu, 11 Oct 2018 17:35:24 +0200
Subject: [PATCH 2/2] p11_child: add crl_file option for the OpenSSL build

In the NSS build a Certificate Revocation List (CRL) can just be added
to the NSS database. For OpenSSL a separate file is needed.

Related to https://pagure.io/SSSD/sssd/issue/3489
---
 src/man/sssd.conf.5.xml           | 24 ++++++++++++++++++++++++
 src/p11_child/p11_child_common.c  | 12 ++++++------
 src/p11_child/p11_child_openssl.c | 26 +++++++++++++++++++++++++-
 src/tests/cmocka/test_utils.c     | 16 ++++++++++++++++
 src/util/util.c                   | 13 +++++++++++++
 src/util/util.h                   |  1 +
 6 files changed, 85 insertions(+), 7 deletions(-)

diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 5e3ae48d04..bea25c6228 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -503,6 +503,30 @@
                                         pam_cert_db_path.</para>
                                     </listitem>
                                 </varlistentry>
+                                <varlistentry>
+                                    <term>crl_file=/PATH/TO/CRL/FILE</term>
+                                    <listitem>
+                                        <para>(NSS Version) This option is
+                                        ignored, please see
+                                            <citerefentry>
+                                                <refentrytitle>crlutil</refentrytitle>
+                                                <manvolnum>1</manvolnum>
+                                            </citerefentry>
+                                        how to import a Certificate Revocation
+                                        List (CRL) into a NSS database.</para>
+
+                                        <para>(OpenSSL Version) Use the
+                                        Certificate Revocation List (CRL) from
+                                        the given file during the verification
+                                        of the certificate. The CRL must be
+                                        given in PEM format, see
+                                            <citerefentry>
+                                                <refentrytitle>crl</refentrytitle>
+                                                <manvolnum>1ssl</manvolnum>
+                                            </citerefentry>
+                                        for details.</para>
+                                    </listitem>
+                                </varlistentry>
                                 </variablelist>
                             </para>
                             <para condition="with_nss">
diff --git a/src/p11_child/p11_child_common.c b/src/p11_child/p11_child_common.c
index 097e7fa07f..b992aeb71e 100644
--- a/src/p11_child/p11_child_common.c
+++ b/src/p11_child/p11_child_common.c
@@ -48,7 +48,7 @@ static const char *op_mode_str(enum op_mode mode)
         return "pre-auth";
         break;
     case OP_VERIFIY:
-        return "verifiy";
+        return "verify";
         break;
     default:
         return "unknown";
@@ -219,7 +219,7 @@ int main(int argc, const char *argv[])
         case 'a':
             if (mode != OP_NONE) {
                 fprintf(stderr,
-                        "\n--verifiy, --auth and --pre are mutually " \
+                        "\n--verify, --auth and --pre are mutually " \
                         "exclusive and should be only used once.\n\n");
                 poptPrintUsage(pc, stderr, 0);
                 _exit(-1);
@@ -229,7 +229,7 @@ int main(int argc, const char *argv[])
         case 'p':
             if (mode != OP_NONE) {
                 fprintf(stderr,
-                        "\n--verifiy, --auth and --pre are mutually " \
+                        "\n--verify, --auth and --pre are mutually " \
                         "exclusive and should be only used once.\n\n");
                 poptPrintUsage(pc, stderr, 0);
                 _exit(-1);
@@ -239,7 +239,7 @@ int main(int argc, const char *argv[])
         case 'v':
             if (mode != OP_NONE) {
                 fprintf(stderr,
-                        "\n--verifiy, --auth and --pre are mutually " \
+                        "\n--verify, --auth and --pre are mutually " \
                         "exclusive and should be only used once.\n\n");
                 poptPrintUsage(pc, stderr, 0);
                 _exit(-1);
@@ -283,7 +283,7 @@ int main(int argc, const char *argv[])
 
     if (mode == OP_NONE) {
         fprintf(stderr, "\nMissing operation mode, either " \
-                        "--verifiy, --auth or --pre must be specified.\n\n");
+                        "--verify, --auth or --pre must be specified.\n\n");
         poptPrintUsage(pc, stderr, 0);
         _exit(-1);
     } else if (mode == OP_AUTH && pin_mode == PIN_NONE) {
@@ -350,7 +350,7 @@ int main(int argc, const char *argv[])
 
     ret = parse_cert_verify_opts(main_ctx, verify_opts, &cert_verify_opts);
     if (ret != EOK) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse verifiy option.\n");
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse verify option.\n");
         goto fail;
     }
 
diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
index 47c44cd57f..379f34aaf1 100644
--- a/src/p11_child/p11_child_openssl.c
+++ b/src/p11_child/p11_child_openssl.c
@@ -490,6 +490,7 @@ errno_t init_verification(struct p11_ctx *p11_ctx,
     X509_STORE *store = NULL;
     unsigned long err;
     X509_LOOKUP *lookup = NULL;
+    X509_VERIFY_PARAM *verify_param = NULL;
 
     store = X509_STORE_new();
     if (store == NULL) {
@@ -516,6 +517,30 @@ errno_t init_verification(struct p11_ctx *p11_ctx,
         goto done;
     }
 
+    if (cert_verify_opts->crl_file != NULL) {
+        verify_param = X509_VERIFY_PARAM_new();
+        if (verify_param == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "X509_VERIFY_PARAM_new failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        X509_VERIFY_PARAM_set_flags(verify_param, (X509_V_FLAG_CRL_CHECK
+                                                  | X509_V_FLAG_CRL_CHECK_ALL));
+
+        X509_STORE_set1_param(store, verify_param);
+
+        ret = X509_load_crl_file(lookup, cert_verify_opts->crl_file,
+                                 X509_FILETYPE_PEM);
+        if (ret == 0) {
+            err = ERR_get_error();
+            DEBUG(SSSDBG_OP_FAILURE, "X509_load_crl_file failed [%lu][%s].\n",
+                                     err, ERR_error_string(err, NULL));
+            ret = EIO;
+            goto done;
+        }
+    }
+
     p11_ctx->x509_store = store;
     p11_ctx->cert_verify_opts = cert_verify_opts;
     talloc_set_destructor(p11_ctx, talloc_free_x509_store);
@@ -525,7 +550,6 @@ errno_t init_verification(struct p11_ctx *p11_ctx,
 done:
     if (ret != EOK) {
         X509_STORE_free(store);
-        X509_LOOKUP_free(lookup);
     }
 
     return ret;
diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
index c86e526e82..cf1c2ae678 100644
--- a/src/tests/cmocka/test_utils.c
+++ b/src/tests/cmocka/test_utils.c
@@ -1567,6 +1567,7 @@ static void test_parse_cert_verify_opts(void **state)
     assert_true(cv_opts->do_ocsp);
     assert_null(cv_opts->ocsp_default_responder);
     assert_null(cv_opts->ocsp_default_responder_signing_cert);
+    assert_null(cv_opts->crl_file);
     talloc_free(cv_opts);
 
     ret = parse_cert_verify_opts(global_talloc_context, "wedfkwefjk", &cv_opts);
@@ -1575,6 +1576,7 @@ static void test_parse_cert_verify_opts(void **state)
     assert_true(cv_opts->do_ocsp);
     assert_null(cv_opts->ocsp_default_responder);
     assert_null(cv_opts->ocsp_default_responder_signing_cert);
+    assert_null(cv_opts->crl_file);
     talloc_free(cv_opts);
 
     ret = parse_cert_verify_opts(global_talloc_context, "no_ocsp", &cv_opts);
@@ -1583,6 +1585,7 @@ static void test_parse_cert_verify_opts(void **state)
     assert_false(cv_opts->do_ocsp);
     assert_null(cv_opts->ocsp_default_responder);
     assert_null(cv_opts->ocsp_default_responder_signing_cert);
+    assert_null(cv_opts->crl_file);
     talloc_free(cv_opts);
 
     ret = parse_cert_verify_opts(global_talloc_context, "no_verification",
@@ -1592,6 +1595,7 @@ static void test_parse_cert_verify_opts(void **state)
     assert_true(cv_opts->do_ocsp);
     assert_null(cv_opts->ocsp_default_responder);
     assert_null(cv_opts->ocsp_default_responder_signing_cert);
+    assert_null(cv_opts->crl_file);
     talloc_free(cv_opts);
 
     ret = parse_cert_verify_opts(global_talloc_context,
@@ -1601,6 +1605,7 @@ static void test_parse_cert_verify_opts(void **state)
     assert_false(cv_opts->do_ocsp);
     assert_null(cv_opts->ocsp_default_responder);
     assert_null(cv_opts->ocsp_default_responder_signing_cert);
+    assert_null(cv_opts->crl_file);
     talloc_free(cv_opts);
 
     ret = parse_cert_verify_opts(global_talloc_context,
@@ -1633,6 +1638,17 @@ static void test_parse_cert_verify_opts(void **state)
     assert_true(cv_opts->do_ocsp);
     assert_string_equal(cv_opts->ocsp_default_responder, "abc");
     assert_string_equal(cv_opts->ocsp_default_responder_signing_cert, "def");
+    assert_null(cv_opts->crl_file);
+    talloc_free(cv_opts);
+
+    ret = parse_cert_verify_opts(global_talloc_context, "crl_file=hij",
+                                 &cv_opts);
+    assert_int_equal(ret, EOK);
+    assert_true(cv_opts->do_verification);
+    assert_true(cv_opts->do_ocsp);
+    assert_null(cv_opts->ocsp_default_responder);
+    assert_null(cv_opts->ocsp_default_responder_signing_cert);
+    assert_string_equal(cv_opts->crl_file, "hij");
     talloc_free(cv_opts);
 }
 
diff --git a/src/util/util.c b/src/util/util.c
index 7f475fa9b5..cbe6a2870c 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1024,6 +1024,7 @@ static struct cert_verify_opts *init_cert_verify_opts(TALLOC_CTX *mem_ctx)
     cert_verify_opts->do_verification = true;
     cert_verify_opts->ocsp_default_responder = NULL;
     cert_verify_opts->ocsp_default_responder_signing_cert = NULL;
+    cert_verify_opts->crl_file = NULL;
 
     return cert_verify_opts;
 }
@@ -1035,6 +1036,8 @@ static struct cert_verify_opts *init_cert_verify_opts(TALLOC_CTX *mem_ctx)
                                           "ocsp_default_responder_signing_cert="
 #define OCSP_DEFAUL_RESPONDER_SIGNING_CERT_LEN \
                                 (sizeof(OCSP_DEFAUL_RESPONDER_SIGNING_CERT) - 1)
+#define CRL_FILE "crl_file="
+#define CRL_FILE_LEN (sizeof(CRL_FILE) -1)
 
 errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
                                struct cert_verify_opts **_cert_verify_opts)
@@ -1116,6 +1119,16 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
             DEBUG(SSSDBG_TRACE_ALL,
                   "Using OCSP default responder signing cert nickname [%s]\n",
                   cert_verify_opts->ocsp_default_responder_signing_cert);
+        } else if (strncasecmp(opts[c], CRL_FILE, CRL_FILE_LEN) == 0) {
+            cert_verify_opts->crl_file = talloc_strdup(cert_verify_opts,
+                                                       &opts[c][CRL_FILE_LEN]);
+            if (cert_verify_opts->crl_file == NULL
+                    || *cert_verify_opts->crl_file == '\0') {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "Failed to parse crl_file option [%s].\n", opts[c]);
+                ret = EINVAL;
+                goto done;
+            }
         } else {
             DEBUG(SSSDBG_CRIT_FAILURE,
                   "Unsupported certificate verification option [%s], " \
diff --git a/src/util/util.h b/src/util/util.h
index e3e9100972..7e9b3d6a6f 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -371,6 +371,7 @@ struct cert_verify_opts {
     bool do_verification;
     char *ocsp_default_responder;
     char *ocsp_default_responder_signing_cert;
+    char *crl_file;
 };
 
 errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: https://getfedora.org/code-of-conduct.html
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org

Reply via email to