LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - revoke.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 125 810 15.4 %
Date: 2024-04-21 15:09:00 Functions: 8 27 29.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : /**
      35             :  * @page page_revoke Revocation methods
      36             :  *
      37             :  * There are two revocation method for PKIX/X.509: CRL and OCSP.
      38             :  * Revocation is needed if the private key is lost and
      39             :  * stolen. Depending on how picky you are, you might want to make
      40             :  * revocation for destroyed private keys too (smartcard broken), but
      41             :  * that should not be a problem.
      42             :  *
      43             :  * CRL is a list of certificates that have expired.
      44             :  *
      45             :  * OCSP is an online checking method where the requestor sends a list
      46             :  * of certificates to the OCSP server to return a signed reply if they
      47             :  * are valid or not. Some services sends a OCSP reply as part of the
      48             :  * hand-shake to make the revoktion decision simpler/faster for the
      49             :  * client.
      50             :  */
      51             : 
      52             : #include "hx_locl.h"
      53             : 
      54             : struct revoke_crl {
      55             :     char *path;
      56             :     time_t last_modfied;
      57             :     CRLCertificateList crl;
      58             :     int verified;
      59             :     int failed_verify;
      60             : };
      61             : 
      62             : struct revoke_ocsp {
      63             :     char *path;
      64             :     time_t last_modfied;
      65             :     OCSPBasicOCSPResponse ocsp;
      66             :     hx509_certs certs;
      67             :     hx509_cert signer;
      68             : };
      69             : 
      70             : 
      71             : struct hx509_revoke_ctx_data {
      72             :     unsigned int ref;
      73             :     struct {
      74             :         struct revoke_crl *val;
      75             :         size_t len;
      76             :     } crls;
      77             :     struct {
      78             :         struct revoke_ocsp *val;
      79             :         size_t len;
      80             :     } ocsps;
      81             : };
      82             : 
      83             : /**
      84             :  * Allocate a revocation context. Free with hx509_revoke_free().
      85             :  *
      86             :  * @param context A hx509 context.
      87             :  * @param ctx returns a newly allocated revocation context.
      88             :  *
      89             :  * @return An hx509 error code, see hx509_get_error_string().
      90             :  *
      91             :  * @ingroup hx509_revoke
      92             :  */
      93             : 
      94             : HX509_LIB_FUNCTION int HX509_LIB_CALL
      95          54 : hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
      96             : {
      97          54 :     *ctx = calloc(1, sizeof(**ctx));
      98          54 :     if (*ctx == NULL)
      99           0 :         return ENOMEM;
     100             : 
     101          54 :     (*ctx)->ref = 1;
     102          54 :     (*ctx)->crls.len = 0;
     103          54 :     (*ctx)->crls.val = NULL;
     104          54 :     (*ctx)->ocsps.len = 0;
     105          54 :     (*ctx)->ocsps.val = NULL;
     106             : 
     107          54 :     return 0;
     108             : }
     109             : 
     110             : HX509_LIB_FUNCTION hx509_revoke_ctx HX509_LIB_CALL
     111         239 : _hx509_revoke_ref(hx509_revoke_ctx ctx)
     112             : {
     113         239 :     if (ctx == NULL)
     114         124 :         return NULL;
     115         115 :     if (ctx->ref == 0)
     116           0 :         _hx509_abort("revoke ctx refcount == 0 on ref");
     117         115 :     ctx->ref++;
     118         115 :     if (ctx->ref == UINT_MAX)
     119           0 :         _hx509_abort("revoke ctx refcount == UINT_MAX on ref");
     120         107 :     return ctx;
     121             : }
     122             : 
     123             : static void
     124           0 : free_ocsp(struct revoke_ocsp *ocsp)
     125             : {
     126           0 :     free(ocsp->path);
     127           0 :     free_OCSPBasicOCSPResponse(&ocsp->ocsp);
     128           0 :     hx509_certs_free(&ocsp->certs);
     129           0 :     hx509_cert_free(ocsp->signer);
     130           0 : }
     131             : 
     132             : /**
     133             :  * Free a hx509 revocation context.
     134             :  *
     135             :  * @param ctx context to be freed
     136             :  *
     137             :  * @ingroup hx509_revoke
     138             :  */
     139             : 
     140             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     141         224 : hx509_revoke_free(hx509_revoke_ctx *ctx)
     142             : {
     143           0 :     size_t i ;
     144             : 
     145         224 :     if (ctx == NULL || *ctx == NULL)
     146         163 :         return;
     147             : 
     148          61 :     if ((*ctx)->ref == 0)
     149           0 :         _hx509_abort("revoke ctx refcount == 0 on free");
     150          61 :     if (--(*ctx)->ref > 0)
     151          61 :         return;
     152             : 
     153           0 :     for (i = 0; i < (*ctx)->crls.len; i++) {
     154           0 :         free((*ctx)->crls.val[i].path);
     155           0 :         free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
     156             :     }
     157             : 
     158           0 :     for (i = 0; i < (*ctx)->ocsps.len; i++)
     159           0 :         free_ocsp(&(*ctx)->ocsps.val[i]);
     160           0 :     free((*ctx)->ocsps.val);
     161             : 
     162           0 :     free((*ctx)->crls.val);
     163             : 
     164           0 :     memset(*ctx, 0, sizeof(**ctx));
     165           0 :     free(*ctx);
     166           0 :     *ctx = NULL;
     167             : }
     168             : 
     169             : static int
     170           0 : verify_ocsp(hx509_context context,
     171             :             struct revoke_ocsp *ocsp,
     172             :             time_t time_now,
     173             :             hx509_certs certs,
     174             :             hx509_cert parent)
     175             : {
     176           0 :     hx509_cert signer = NULL;
     177           0 :     hx509_query q;
     178           0 :     int ret;
     179             : 
     180           0 :     _hx509_query_clear(&q);
     181             : 
     182             :     /*
     183             :      * Need to match on issuer too in case there are two CA that have
     184             :      * issued the same name to a certificate. One example of this is
     185             :      * the www.openvalidation.org test's ocsp validator.
     186             :      */
     187             : 
     188           0 :     q.match = HX509_QUERY_MATCH_ISSUER_NAME;
     189           0 :     q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer;
     190             : 
     191           0 :     switch(ocsp->ocsp.tbsResponseData.responderID.element) {
     192           0 :     case choice_OCSPResponderID_byName:
     193           0 :         q.match |= HX509_QUERY_MATCH_SUBJECT_NAME;
     194           0 :         q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName;
     195           0 :         break;
     196           0 :     case choice_OCSPResponderID_byKey:
     197           0 :         q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1;
     198           0 :         q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey;
     199           0 :         break;
     200             :     }
     201             : 
     202           0 :     ret = hx509_certs_find(context, certs, &q, &signer);
     203           0 :     if (ret && ocsp->certs)
     204           0 :         ret = hx509_certs_find(context, ocsp->certs, &q, &signer);
     205           0 :     if (ret == 0 && signer == NULL)
     206           0 :         ret = HX509_CERT_NOT_FOUND;
     207           0 :     if (ret)
     208           0 :         goto out;
     209             : 
     210             :     /*
     211             :      * If signer certificate isn't the CA certificate, let's check that
     212             :      * it is the CA that signed the signer certificate and that the OCSP EKU
     213             :      * is set.
     214             :      */
     215           0 :     if (hx509_cert_cmp(signer, parent) != 0) {
     216           0 :         Certificate *p = _hx509_get_cert(parent);
     217           0 :         Certificate *s = _hx509_get_cert(signer);
     218             : 
     219           0 :         ret = _hx509_cert_is_parent_cmp(s, p, 0);
     220           0 :         if (ret != 0) {
     221           0 :             ret = HX509_PARENT_NOT_CA;
     222           0 :             hx509_set_error_string(context, 0, ret, "Revoke OCSP signer "
     223             :                                    "doesn't have CA as signer certificate");
     224           0 :             goto out;
     225             :         }
     226             : 
     227           0 :         ret = _hx509_verify_signature_bitstring(context,
     228             :                                                 parent,
     229           0 :                                                 &s->signatureAlgorithm,
     230           0 :                                                 &s->tbsCertificate._save,
     231           0 :                                                 &s->signatureValue);
     232           0 :         if (ret) {
     233           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     234             :                                    "OCSP signer signature invalid");
     235           0 :             goto out;
     236             :         }
     237             : 
     238           0 :         ret = hx509_cert_check_eku(context, signer,
     239             :                                    &asn1_oid_id_pkix_kp_OCSPSigning, 0);
     240           0 :         if (ret)
     241           0 :             goto out;
     242             :     }
     243             : 
     244           0 :     ret = _hx509_verify_signature_bitstring(context,
     245             :                                             signer,
     246           0 :                                             &ocsp->ocsp.signatureAlgorithm,
     247           0 :                                             &ocsp->ocsp.tbsResponseData._save,
     248           0 :                                             &ocsp->ocsp.signature);
     249           0 :     if (ret) {
     250           0 :         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     251             :                                "OCSP signature invalid");
     252           0 :         goto out;
     253             :     }
     254             : 
     255           0 :     ocsp->signer = signer;
     256           0 :     signer = NULL;
     257           0 : out:
     258           0 :     if (signer)
     259           0 :         hx509_cert_free(signer);
     260             : 
     261           0 :     return ret;
     262             : }
     263             : 
     264             : /*
     265             :  *
     266             :  */
     267             : 
     268             : static int
     269           0 : parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
     270             : {
     271           0 :     OCSPResponse resp;
     272           0 :     size_t size;
     273           0 :     int ret;
     274             : 
     275           0 :     memset(basic, 0, sizeof(*basic));
     276             : 
     277           0 :     ret = decode_OCSPResponse(data, length, &resp, &size);
     278           0 :     if (ret)
     279           0 :         return ret;
     280           0 :     if (length != size) {
     281           0 :         free_OCSPResponse(&resp);
     282           0 :         return ASN1_EXTRA_DATA;
     283             :     }
     284             : 
     285           0 :     switch (resp.responseStatus) {
     286           0 :     case successful:
     287           0 :         break;
     288           0 :     default:
     289           0 :         free_OCSPResponse(&resp);
     290           0 :         return HX509_REVOKE_WRONG_DATA;
     291             :     }
     292             : 
     293           0 :     if (resp.responseBytes == NULL) {
     294           0 :         free_OCSPResponse(&resp);
     295           0 :         return EINVAL;
     296             :     }
     297             : 
     298           0 :     ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
     299             :                            &asn1_oid_id_pkix_ocsp_basic);
     300           0 :     if (ret != 0) {
     301           0 :         free_OCSPResponse(&resp);
     302           0 :         return HX509_REVOKE_WRONG_DATA;
     303             :     }
     304             : 
     305           0 :     ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
     306           0 :                                        resp.responseBytes->response.length,
     307             :                                        basic,
     308             :                                        &size);
     309           0 :     if (ret) {
     310           0 :         free_OCSPResponse(&resp);
     311           0 :         return ret;
     312             :     }
     313           0 :     if (size != resp.responseBytes->response.length) {
     314           0 :         free_OCSPResponse(&resp);
     315           0 :         free_OCSPBasicOCSPResponse(basic);
     316           0 :         return ASN1_EXTRA_DATA;
     317             :     }
     318           0 :     free_OCSPResponse(&resp);
     319             : 
     320           0 :     return 0;
     321             : }
     322             : 
     323             : /*
     324             :  *
     325             :  */
     326             : 
     327             : static int
     328           0 : load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
     329             : {
     330           0 :     OCSPBasicOCSPResponse basic;
     331           0 :     hx509_certs certs = NULL;
     332           0 :     size_t length;
     333           0 :     struct stat sb;
     334           0 :     void *data;
     335           0 :     int ret;
     336             : 
     337           0 :     ret = rk_undumpdata(ocsp->path, &data, &length);
     338           0 :     if (ret)
     339           0 :         return ret;
     340             : 
     341           0 :     ret = stat(ocsp->path, &sb);
     342           0 :     if (ret) {
     343           0 :         rk_xfree(data);
     344           0 :         return errno;
     345             :     }
     346             : 
     347           0 :     ret = parse_ocsp_basic(data, length, &basic);
     348           0 :     rk_xfree(data);
     349           0 :     if (ret) {
     350           0 :         hx509_set_error_string(context, 0, ret,
     351             :                                "Failed to parse OCSP response");
     352           0 :         return ret;
     353             :     }
     354             : 
     355           0 :     if (basic.certs) {
     356           0 :         size_t i;
     357             : 
     358           0 :         ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
     359             :                                NULL, &certs);
     360           0 :         if (ret) {
     361           0 :             free_OCSPBasicOCSPResponse(&basic);
     362           0 :             return ret;
     363             :         }
     364             : 
     365           0 :         for (i = 0; i < basic.certs->len; i++) {
     366           0 :             hx509_cert c;
     367             : 
     368           0 :             c = hx509_cert_init(context, &basic.certs->val[i], NULL);
     369           0 :             if (c == NULL)
     370           0 :                 continue;
     371             : 
     372           0 :             ret = hx509_certs_add(context, certs, c);
     373           0 :             hx509_cert_free(c);
     374           0 :             if (ret)
     375           0 :                 continue;
     376             :         }
     377             :     }
     378             : 
     379           0 :     ocsp->last_modfied = sb.st_mtime;
     380             : 
     381           0 :     free_OCSPBasicOCSPResponse(&ocsp->ocsp);
     382           0 :     hx509_certs_free(&ocsp->certs);
     383           0 :     hx509_cert_free(ocsp->signer);
     384             : 
     385           0 :     ocsp->ocsp = basic;
     386           0 :     ocsp->certs = certs;
     387           0 :     ocsp->signer = NULL;
     388             : 
     389           0 :     return 0;
     390             : }
     391             : 
     392             : /**
     393             :  * Add a OCSP file to the revocation context.
     394             :  *
     395             :  * @param context hx509 context
     396             :  * @param ctx hx509 revocation context
     397             :  * @param path path to file that is going to be added to the context.
     398             :  *
     399             :  * @return An hx509 error code, see hx509_get_error_string().
     400             :  *
     401             :  * @ingroup hx509_revoke
     402             :  */
     403             : 
     404             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     405           0 : hx509_revoke_add_ocsp(hx509_context context,
     406             :                       hx509_revoke_ctx ctx,
     407             :                       const char *path)
     408             : {
     409           0 :     void *data;
     410           0 :     int ret;
     411           0 :     size_t i;
     412             : 
     413           0 :     if (strncmp(path, "FILE:", 5) != 0) {
     414           0 :         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
     415             :                                "unsupported type in %s", path);
     416           0 :         return HX509_UNSUPPORTED_OPERATION;
     417             :     }
     418             : 
     419           0 :     path += 5;
     420             : 
     421           0 :     for (i = 0; i < ctx->ocsps.len; i++) {
     422           0 :         if (strcmp(ctx->ocsps.val[0].path, path) == 0)
     423           0 :             return 0;
     424             :     }
     425             : 
     426           0 :     data = realloc(ctx->ocsps.val,
     427           0 :                    (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
     428           0 :     if (data == NULL) {
     429           0 :         hx509_clear_error_string(context);
     430           0 :         return ENOMEM;
     431             :     }
     432             : 
     433           0 :     ctx->ocsps.val = data;
     434             : 
     435           0 :     memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
     436             :            sizeof(ctx->ocsps.val[0]));
     437             : 
     438           0 :     ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
     439           0 :     if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
     440           0 :         hx509_clear_error_string(context);
     441           0 :         return ENOMEM;
     442             :     }
     443             : 
     444           0 :     ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
     445           0 :     if (ret) {
     446           0 :         free(ctx->ocsps.val[ctx->ocsps.len].path);
     447           0 :         return ret;
     448             :     }
     449           0 :     ctx->ocsps.len++;
     450             : 
     451           0 :     return ret;
     452             : }
     453             : 
     454             : /*
     455             :  *
     456             :  */
     457             : 
     458             : static int
     459           7 : verify_crl(hx509_context context,
     460             :            hx509_revoke_ctx ctx,
     461             :            CRLCertificateList *crl,
     462             :            time_t time_now,
     463             :            hx509_certs certs,
     464             :            hx509_cert parent)
     465             : {
     466           0 :     hx509_cert signer;
     467           0 :     hx509_query q;
     468           0 :     time_t t;
     469           0 :     int ret;
     470             : 
     471           7 :     t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
     472           7 :     if (t > time_now) {
     473           0 :         hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
     474             :                                "CRL used before time");
     475           0 :         return HX509_CRL_USED_BEFORE_TIME;
     476             :     }
     477             : 
     478           7 :     if (crl->tbsCertList.nextUpdate == NULL) {
     479           0 :         hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
     480             :                                "CRL missing nextUpdate");
     481           0 :         return HX509_CRL_INVALID_FORMAT;
     482             :     }
     483             : 
     484           7 :     t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
     485           7 :     if (t < time_now) {
     486           0 :         hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
     487             :                                "CRL used after time");
     488           0 :         return HX509_CRL_USED_AFTER_TIME;
     489             :     }
     490             : 
     491           7 :     _hx509_query_clear(&q);
     492             : 
     493             :     /*
     494             :      * If it's the signer have CRLSIGN bit set, use that as the signer
     495             :      * cert for the certificate, otherwise, search for a certificate.
     496             :      */
     497           7 :     if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
     498           7 :         signer = hx509_cert_ref(parent);
     499             :     } else {
     500           0 :         q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
     501           0 :         q.match |= HX509_QUERY_KU_CRLSIGN;
     502           0 :         q.subject_name = &crl->tbsCertList.issuer;
     503             : 
     504           0 :         ret = hx509_certs_find(context, certs, &q, &signer);
     505           0 :         if (ret == 0 && signer == NULL)
     506           0 :             ret = HX509_CERT_NOT_FOUND;
     507           0 :         if (ret) {
     508           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     509             :                                    "Failed to find certificate for CRL");
     510           0 :             return ret;
     511             :         }
     512             :     }
     513             : 
     514           7 :     ret = _hx509_verify_signature_bitstring(context,
     515             :                                             signer,
     516           7 :                                             &crl->signatureAlgorithm,
     517           7 :                                             &crl->tbsCertList._save,
     518           7 :                                             &crl->signatureValue);
     519           7 :     if (ret) {
     520           0 :         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     521             :                                "CRL signature invalid");
     522           0 :         goto out;
     523             :     }
     524             : 
     525             :     /*
     526             :      * If signer is not CA cert, need to check revoke status of this
     527             :      * CRL signing cert too, this include all parent CRL signer cert
     528             :      * up to the root *sigh*, assume root at least has CERTSIGN flag
     529             :      * set.
     530             :      */
     531           7 :     while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
     532           0 :         hx509_cert crl_parent;
     533             : 
     534           0 :         _hx509_query_clear(&q);
     535             : 
     536           0 :         q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
     537           0 :         q.match |= HX509_QUERY_KU_CRLSIGN;
     538           0 :         q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
     539             : 
     540           0 :         ret = hx509_certs_find(context, certs, &q, &crl_parent);
     541           0 :         if (ret) {
     542           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     543             :                                    "Failed to find parent of CRL signer");
     544           0 :             goto out;
     545             :         }
     546             : 
     547           0 :         ret = hx509_revoke_verify(context,
     548             :                                   ctx,
     549             :                                   certs,
     550             :                                   time_now,
     551             :                                   signer,
     552             :                                   crl_parent);
     553           0 :         hx509_cert_free(signer);
     554           0 :         signer = crl_parent;
     555           0 :         if (ret) {
     556           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     557             :                                    "Failed to verify revocation "
     558             :                                    "status of CRL signer");
     559           0 :             goto out;
     560             :         }
     561             :     }
     562             : 
     563           7 : out:
     564           7 :     hx509_cert_free(signer);
     565             : 
     566           7 :     return ret;
     567             : }
     568             : 
     569             : static int
     570          57 : crl_parser(hx509_context context, const char *type,
     571             :            const hx509_pem_header *header,
     572             :            const void *data, size_t len, void *ctx)
     573             : {
     574          57 :     CRLCertificateList *crl = (CRLCertificateList *)ctx;
     575           8 :     size_t size;
     576           8 :     int ret;
     577             : 
     578          57 :     if (strcasecmp("X509 CRL", type) != 0)
     579           0 :         return HX509_CRYPTO_SIG_INVALID_FORMAT;
     580             : 
     581          57 :     ret = decode_CRLCertificateList(data, len, crl, &size);
     582          57 :     if (ret)
     583           0 :         return ret;
     584             : 
     585             :     /* check signature is aligned */
     586          57 :     if (crl->signatureValue.length & 7) {
     587           0 :         free_CRLCertificateList(crl);
     588           0 :         return HX509_CRYPTO_SIG_INVALID_FORMAT;
     589             :     }
     590             : 
     591          49 :     return 0;
     592             : }
     593             : 
     594             : static int
     595          57 : load_crl(hx509_context context, const char *path, time_t *t, CRLCertificateList *crl)
     596             : {
     597           8 :     struct stat sb;
     598           8 :     size_t length;
     599           8 :     void *data;
     600           8 :     FILE *f;
     601           8 :     int ret;
     602             : 
     603          57 :     *t = 0;
     604          57 :     memset(crl, 0, sizeof(*crl));
     605             :         
     606          57 :     if ((f = fopen(path, "r")) == NULL)
     607           0 :         return errno;
     608             : 
     609          57 :     rk_cloexec_file(f);
     610          57 :     if (fstat(fileno(f), &sb) == 0)
     611          57 :         *t = sb.st_mtime;
     612             : 
     613          57 :     ret = hx509_pem_read(context, f, crl_parser, crl);
     614          57 :     fclose(f);
     615             : 
     616          57 :     if (ret == HX509_PARSING_KEY_FAILED) {
     617             : 
     618           0 :         ret = rk_undumpdata(path, &data, &length);
     619           0 :         if (ret)
     620           0 :             return ret;
     621             : 
     622           0 :         ret = crl_parser(context, "X509 CRL", NULL, data, length, crl);
     623           0 :         rk_xfree(data);
     624             :     }
     625          49 :     return ret;
     626             : }
     627             : 
     628             : /**
     629             :  * Add a CRL file to the revocation context.
     630             :  *
     631             :  * @param context hx509 context
     632             :  * @param ctx hx509 revocation context
     633             :  * @param path path to file that is going to be added to the context.
     634             :  *
     635             :  * @return An hx509 error code, see hx509_get_error_string().
     636             :  *
     637             :  * @ingroup hx509_revoke
     638             :  */
     639             : 
     640             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     641          54 : hx509_revoke_add_crl(hx509_context context,
     642             :                      hx509_revoke_ctx ctx,
     643             :                      const char *path)
     644             : {
     645           8 :     void *data;
     646           8 :     size_t i;
     647           8 :     int ret;
     648             : 
     649          54 :     if (strncmp(path, "FILE:", 5) != 0) {
     650           0 :         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
     651             :                                "unsupported type in %s", path);
     652           0 :         return HX509_UNSUPPORTED_OPERATION;
     653             :     }
     654             : 
     655             : 
     656          54 :     path += 5;
     657             : 
     658          54 :     for (i = 0; i < ctx->crls.len; i++) {
     659           0 :         if (strcmp(ctx->crls.val[i].path, path) == 0)
     660           0 :             return 0;
     661             :     }
     662             : 
     663          54 :     data = realloc(ctx->crls.val,
     664          46 :                    (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
     665          54 :     if (data == NULL) {
     666           0 :         hx509_clear_error_string(context);
     667           0 :         return ENOMEM;
     668             :     }
     669          54 :     ctx->crls.val = data;
     670             : 
     671          54 :     memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
     672             : 
     673          54 :     ctx->crls.val[ctx->crls.len].path = strdup(path);
     674          54 :     if (ctx->crls.val[ctx->crls.len].path == NULL) {
     675           0 :         hx509_clear_error_string(context);
     676           0 :         return ENOMEM;
     677             :     }
     678             : 
     679          54 :     ret = load_crl(context,
     680             :                    path,
     681          46 :                    &ctx->crls.val[ctx->crls.len].last_modfied,
     682          46 :                    &ctx->crls.val[ctx->crls.len].crl);
     683          54 :     if (ret) {
     684           0 :         free(ctx->crls.val[ctx->crls.len].path);
     685           0 :         return ret;
     686             :     }
     687             : 
     688          54 :     ctx->crls.len++;
     689             : 
     690          54 :     return ret;
     691             : }
     692             : 
     693             : /**
     694             :  * Check that a certificate is not expired according to a revocation
     695             :  * context. Also need the parent certificate to check the OCSP
     696             :  * parent identifier.
     697             :  *
     698             :  * @param context hx509 context
     699             :  * @param ctx hx509 revocation context
     700             :  * @param certs
     701             :  * @param now
     702             :  * @param cert
     703             :  * @param parent_cert
     704             :  *
     705             :  * @return An hx509 error code, see hx509_get_error_string().
     706             :  *
     707             :  * @ingroup hx509_revoke
     708             :  */
     709             : 
     710             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     711          61 : hx509_revoke_verify(hx509_context context,
     712             :                     hx509_revoke_ctx ctx,
     713             :                     hx509_certs certs,
     714             :                     time_t now,
     715             :                     hx509_cert cert,
     716             :                     hx509_cert parent_cert)
     717             : {
     718          61 :     const Certificate *c = _hx509_get_cert(cert);
     719          61 :     const Certificate *p = _hx509_get_cert(parent_cert);
     720           0 :     unsigned long i, j, k;
     721           0 :     int ret;
     722             : 
     723          61 :     hx509_clear_error_string(context);
     724             : 
     725          61 :     for (i = 0; i < ctx->ocsps.len; i++) {
     726           0 :         struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
     727           0 :         struct stat sb;
     728             : 
     729             :         /* check if this ocsp applies to this cert */
     730             : 
     731             :         /* check if there is a newer version of the file */
     732           0 :         ret = stat(ocsp->path, &sb);
     733           0 :         if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
     734           0 :             ret = load_ocsp(context, ocsp);
     735           0 :             if (ret)
     736           0 :                 continue;
     737             :         }
     738             : 
     739             :         /* verify signature in ocsp if not already done */
     740           0 :         if (ocsp->signer == NULL) {
     741           0 :             ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
     742           0 :             if (ret)
     743           0 :                 continue;
     744             :         }
     745             : 
     746           0 :         for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
     747           0 :             heim_octet_string os;
     748             : 
     749           0 :             ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
     750           0 :                                    &c->tbsCertificate.serialNumber);
     751           0 :             if (ret != 0)
     752           0 :                 continue;
     753             : 
     754             :             /* verify issuer hashes hash */
     755           0 :             ret = _hx509_verify_signature(context,
     756             :                                           NULL,
     757           0 :                                           &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
     758             :                                           &c->tbsCertificate.issuer._save,
     759           0 :                                           &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
     760           0 :             if (ret != 0)
     761           0 :                 continue;
     762             : 
     763           0 :             os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
     764           0 :             os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
     765             : 
     766           0 :             ret = _hx509_verify_signature(context,
     767             :                                           NULL,
     768           0 :                                           &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
     769             :                                           &os,
     770           0 :                                           &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
     771           0 :             if (ret != 0)
     772           0 :                 continue;
     773             : 
     774           0 :             switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
     775           0 :             case choice_OCSPCertStatus_good:
     776           0 :                 break;
     777           0 :             case choice_OCSPCertStatus_revoked:
     778           0 :                 hx509_set_error_string(context, 0,
     779             :                                        HX509_CERT_REVOKED,
     780             :                                        "Certificate revoked by issuer in OCSP");
     781           0 :                 return HX509_CERT_REVOKED;
     782           0 :             case choice_OCSPCertStatus_unknown:
     783           0 :                 continue;
     784             :             }
     785             : 
     786             :             /* don't allow the update to be in the future */
     787           0 :             if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
     788           0 :                 now + context->ocsp_time_diff)
     789           0 :                 continue;
     790             : 
     791             :             /* don't allow the next update to be in the past */
     792           0 :             if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
     793           0 :                 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
     794           0 :                     continue;
     795             :             } /* else should force a refetch, but can we ? */
     796             : 
     797           0 :             return 0;
     798             :         }
     799             :     }
     800             : 
     801          61 :     for (i = 0; i < ctx->crls.len; i++) {
     802          61 :         struct revoke_crl *crl = &ctx->crls.val[i];
     803           0 :         struct stat sb;
     804           0 :         int diff;
     805             : 
     806             :         /* check if cert.issuer == crls.val[i].crl.issuer */
     807          61 :         ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
     808          61 :                               &crl->crl.tbsCertList.issuer, &diff);
     809          61 :         if (ret || diff)
     810           0 :             continue;
     811             : 
     812          61 :         ret = stat(crl->path, &sb);
     813          61 :         if (ret == 0 && crl->last_modfied != sb.st_mtime) {
     814           0 :             CRLCertificateList cl;
     815             : 
     816           3 :             ret = load_crl(context, crl->path, &crl->last_modfied, &cl);
     817           3 :             if (ret == 0) {
     818           3 :                 free_CRLCertificateList(&crl->crl);
     819           3 :                 crl->crl = cl;
     820           3 :                 crl->verified = 0;
     821           3 :                 crl->failed_verify = 0;
     822             :             }
     823             :         }
     824          61 :         if (crl->failed_verify)
     825           0 :             continue;
     826             : 
     827             :         /* verify signature in crl if not already done */
     828          61 :         if (crl->verified == 0) {
     829           7 :             ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
     830           7 :             if (ret) {
     831           0 :                 crl->failed_verify = 1;
     832           0 :                 continue;
     833             :             }
     834           7 :             crl->verified = 1;
     835             :         }
     836             : 
     837          61 :         if (crl->crl.tbsCertList.crlExtensions) {
     838         244 :             for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
     839         183 :                 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
     840           0 :                     hx509_set_error_string(context, 0,
     841             :                                            HX509_CRL_UNKNOWN_EXTENSION,
     842             :                                            "Unknown CRL extension");
     843          61 :                     return HX509_CRL_UNKNOWN_EXTENSION;
     844             :                 }
     845             :             }
     846             :         }
     847             : 
     848          61 :         if (crl->crl.tbsCertList.revokedCertificates == NULL)
     849          48 :             return 0;
     850             : 
     851             :         /* check if cert is in crl */
     852          24 :         for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
     853           0 :             time_t t;
     854             : 
     855          13 :             ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
     856          13 :                                        &c->tbsCertificate.serialNumber);
     857          13 :             if (ret != 0)
     858          11 :                 continue;
     859             : 
     860           2 :             t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
     861           2 :             if (t > now)
     862           0 :                 continue;
     863             : 
     864           2 :             if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
     865           0 :                 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
     866           0 :                     if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
     867           0 :                         return HX509_CRL_UNKNOWN_EXTENSION;
     868             : 
     869           2 :             hx509_set_error_string(context, 0,
     870             :                                    HX509_CERT_REVOKED,
     871             :                                    "Certificate revoked by issuer in CRL");
     872           2 :             return HX509_CERT_REVOKED;
     873             :         }
     874             : 
     875          11 :         return 0;
     876             :     }
     877             : 
     878             : 
     879           0 :     if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
     880           0 :         return 0;
     881           0 :     hx509_set_error_string(context, HX509_ERROR_APPEND,
     882             :                            HX509_REVOKE_STATUS_MISSING,
     883             :                            "No revocation status found for certificates");
     884           0 :     return HX509_REVOKE_STATUS_MISSING;
     885             : }
     886             : 
     887             : struct ocsp_add_ctx {
     888             :     OCSPTBSRequest *req;
     889             :     hx509_certs certs;
     890             :     const AlgorithmIdentifier *digest;
     891             :     hx509_cert parent;
     892             : };
     893             : 
     894             : static int HX509_LIB_CALL
     895           0 : add_to_req(hx509_context context, void *ptr, hx509_cert cert)
     896             : {
     897           0 :     struct ocsp_add_ctx *ctx = ptr;
     898           0 :     OCSPInnerRequest *one;
     899           0 :     hx509_cert parent = NULL;
     900           0 :     Certificate *p, *c = _hx509_get_cert(cert);
     901           0 :     heim_octet_string os;
     902           0 :     int ret;
     903           0 :     hx509_query q;
     904           0 :     void *d;
     905             : 
     906           0 :     d = realloc(ctx->req->requestList.val,
     907             :                 sizeof(ctx->req->requestList.val[0]) *
     908           0 :                 (ctx->req->requestList.len + 1));
     909           0 :     if (d == NULL)
     910           0 :         return ENOMEM;
     911           0 :     ctx->req->requestList.val = d;
     912             : 
     913           0 :     one = &ctx->req->requestList.val[ctx->req->requestList.len];
     914           0 :     memset(one, 0, sizeof(*one));
     915             : 
     916           0 :     _hx509_query_clear(&q);
     917             : 
     918           0 :     q.match |= HX509_QUERY_FIND_ISSUER_CERT;
     919           0 :     q.subject = c;
     920             : 
     921           0 :     ret = hx509_certs_find(context, ctx->certs, &q, &parent);
     922           0 :     if (ret)
     923           0 :         goto out;
     924             : 
     925           0 :     if (ctx->parent) {
     926           0 :         if (hx509_cert_cmp(ctx->parent, parent) != 0) {
     927           0 :             ret = HX509_REVOKE_NOT_SAME_PARENT;
     928           0 :             hx509_set_error_string(context, 0, ret,
     929             :                                    "Not same parent certificate as "
     930             :                                    "last certificate in request");
     931           0 :             goto out;
     932             :         }
     933             :     } else
     934           0 :         ctx->parent = hx509_cert_ref(parent);
     935             : 
     936           0 :     p = _hx509_get_cert(parent);
     937             : 
     938           0 :     ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
     939           0 :     if (ret)
     940           0 :         goto out;
     941             : 
     942           0 :     ret = _hx509_create_signature(context,
     943             :                                   NULL,
     944           0 :                                   &one->reqCert.hashAlgorithm,
     945           0 :                                   &c->tbsCertificate.issuer._save,
     946             :                                   NULL,
     947             :                                   &one->reqCert.issuerNameHash);
     948           0 :     if (ret)
     949           0 :         goto out;
     950             : 
     951           0 :     os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
     952           0 :     os.length =
     953           0 :         p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
     954             : 
     955           0 :     ret = _hx509_create_signature(context,
     956             :                                   NULL,
     957           0 :                                   &one->reqCert.hashAlgorithm,
     958             :                                   &os,
     959             :                                   NULL,
     960             :                                   &one->reqCert.issuerKeyHash);
     961           0 :     if (ret)
     962           0 :         goto out;
     963             : 
     964           0 :     ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
     965             :                                        &one->reqCert.serialNumber);
     966           0 :     if (ret)
     967           0 :         goto out;
     968             : 
     969           0 :     ctx->req->requestList.len++;
     970           0 : out:
     971           0 :     hx509_cert_free(parent);
     972           0 :     if (ret) {
     973           0 :         free_OCSPInnerRequest(one);
     974           0 :         memset(one, 0, sizeof(*one));
     975             :     }
     976             : 
     977           0 :     return ret;
     978             : }
     979             : 
     980             : /**
     981             :  * Create an OCSP request for a set of certificates.
     982             :  *
     983             :  * @param context a hx509 context
     984             :  * @param reqcerts list of certificates to request ocsp data for
     985             :  * @param pool certificate pool to use when signing
     986             :  * @param signer certificate to use to sign the request
     987             :  * @param digest the signing algorithm in the request, if NULL use the
     988             :  * default signature algorithm,
     989             :  * @param request the encoded request, free with free_heim_octet_string().
     990             :  * @param nonce nonce in the request, free with free_heim_octet_string().
     991             :  *
     992             :  * @return An hx509 error code, see hx509_get_error_string().
     993             :  *
     994             :  * @ingroup hx509_revoke
     995             :  */
     996             : 
     997             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     998           0 : hx509_ocsp_request(hx509_context context,
     999             :                    hx509_certs reqcerts,
    1000             :                    hx509_certs pool,
    1001             :                    hx509_cert signer,
    1002             :                    const AlgorithmIdentifier *digest,
    1003             :                    heim_octet_string *request,
    1004             :                    heim_octet_string *nonce)
    1005             : {
    1006           0 :     OCSPRequest req;
    1007           0 :     size_t size;
    1008           0 :     int ret;
    1009           0 :     struct ocsp_add_ctx ctx;
    1010           0 :     Extensions *es;
    1011             : 
    1012           0 :     memset(&req, 0, sizeof(req));
    1013             : 
    1014           0 :     if (digest == NULL)
    1015           0 :         digest = _hx509_crypto_default_digest_alg;
    1016             : 
    1017           0 :     ctx.req = &req.tbsRequest;
    1018           0 :     ctx.certs = pool;
    1019           0 :     ctx.digest = digest;
    1020           0 :     ctx.parent = NULL;
    1021             : 
    1022           0 :     ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx);
    1023           0 :     hx509_cert_free(ctx.parent);
    1024           0 :     if (ret)
    1025           0 :         goto out;
    1026             : 
    1027           0 :     if (nonce) {
    1028           0 :         req.tbsRequest.requestExtensions =
    1029           0 :             calloc(1, sizeof(*req.tbsRequest.requestExtensions));
    1030           0 :         if (req.tbsRequest.requestExtensions == NULL) {
    1031           0 :             ret = ENOMEM;
    1032           0 :             goto out;
    1033             :         }
    1034             : 
    1035           0 :         es = req.tbsRequest.requestExtensions;
    1036             : 
    1037           0 :         es->val = calloc(es->len, sizeof(es->val[0]));
    1038           0 :         if (es->val == NULL) {
    1039           0 :             ret = ENOMEM;
    1040           0 :             goto out;
    1041             :         }
    1042           0 :         es->len = 1;
    1043           0 :         ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID);
    1044           0 :         if (ret) {
    1045           0 :             free_OCSPRequest(&req);
    1046           0 :             return ret;
    1047             :         }
    1048             : 
    1049           0 :         es->val[0].extnValue.data = malloc(10);
    1050           0 :         if (es->val[0].extnValue.data == NULL) {
    1051           0 :             ret = ENOMEM;
    1052           0 :             goto out;
    1053             :         }
    1054           0 :         es->val[0].extnValue.length = 10;
    1055             : 
    1056           0 :         ret = RAND_bytes(es->val[0].extnValue.data,
    1057           0 :                          es->val[0].extnValue.length);
    1058           0 :         if (ret != 1) {
    1059           0 :             ret = HX509_CRYPTO_INTERNAL_ERROR;
    1060           0 :             goto out;
    1061             :         }
    1062           0 :         ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
    1063           0 :         if (ret) {
    1064           0 :             ret = ENOMEM;
    1065           0 :             goto out;
    1066             :         }
    1067             :     }
    1068             : 
    1069           0 :     ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
    1070             :                        &req, &size, ret);
    1071           0 :     free_OCSPRequest(&req);
    1072           0 :     if (ret)
    1073           0 :         goto out;
    1074           0 :     if (size != request->length)
    1075           0 :         _hx509_abort("internal ASN.1 encoder error");
    1076             : 
    1077           0 :     return 0;
    1078             : 
    1079           0 : out:
    1080           0 :     free_OCSPRequest(&req);
    1081           0 :     return ret;
    1082             : }
    1083             : 
    1084             : static char *
    1085           0 : printable_time(time_t t)
    1086             : {
    1087           0 :     static char s[128];
    1088           0 :     char *p;
    1089           0 :     if ((p = ctime(&t)) == NULL)
    1090           0 :        strlcpy(s, "?", sizeof(s));
    1091             :     else {
    1092           0 :        strlcpy(s, p + 4, sizeof(s));
    1093           0 :        s[20] = 0;
    1094             :     }
    1095           0 :     return s;
    1096             : }
    1097             : 
    1098             : /*
    1099             :  *
    1100             :  */
    1101             : 
    1102             : static int
    1103           0 : print_ocsp(hx509_context context, struct revoke_ocsp *ocsp, FILE *out)
    1104             : {
    1105           0 :     int ret = 0;
    1106           0 :     size_t i;
    1107             : 
    1108           0 :     fprintf(out, "signer: ");
    1109             : 
    1110           0 :     switch(ocsp->ocsp.tbsResponseData.responderID.element) {
    1111           0 :     case choice_OCSPResponderID_byName: {
    1112           0 :         hx509_name n;
    1113           0 :         char *s;
    1114           0 :         _hx509_name_from_Name(&ocsp->ocsp.tbsResponseData.responderID.u.byName, &n);
    1115           0 :         hx509_name_to_string(n, &s);
    1116           0 :         hx509_name_free(&n);
    1117           0 :         fprintf(out, " byName: %s\n", s);
    1118           0 :         free(s);
    1119           0 :         break;
    1120             :     }
    1121           0 :     case choice_OCSPResponderID_byKey: {
    1122           0 :         char *s;
    1123           0 :         hex_encode(ocsp->ocsp.tbsResponseData.responderID.u.byKey.data,
    1124             :                    ocsp->ocsp.tbsResponseData.responderID.u.byKey.length,
    1125             :                    &s);
    1126           0 :         fprintf(out, " byKey: %s\n", s);
    1127           0 :         free(s);
    1128           0 :         break;
    1129             :     }
    1130           0 :     default:
    1131           0 :         _hx509_abort("choice_OCSPResponderID unknown");
    1132           0 :         break;
    1133             :     }
    1134             : 
    1135           0 :     fprintf(out, "producedAt: %s\n",
    1136             :             printable_time(ocsp->ocsp.tbsResponseData.producedAt));
    1137             : 
    1138           0 :     fprintf(out, "replies: %d\n", ocsp->ocsp.tbsResponseData.responses.len);
    1139             : 
    1140           0 :     for (i = 0; i < ocsp->ocsp.tbsResponseData.responses.len; i++) {
    1141           0 :         const char *status;
    1142           0 :         switch (ocsp->ocsp.tbsResponseData.responses.val[i].certStatus.element) {
    1143           0 :         case choice_OCSPCertStatus_good:
    1144           0 :             status = "good";
    1145           0 :             break;
    1146           0 :         case choice_OCSPCertStatus_revoked:
    1147           0 :             status = "revoked";
    1148           0 :             break;
    1149           0 :         case choice_OCSPCertStatus_unknown:
    1150           0 :             status = "unknown";
    1151           0 :             break;
    1152           0 :         default:
    1153           0 :             status = "element unknown";
    1154             :         }
    1155             : 
    1156           0 :         fprintf(out, "\t%llu. status: %s\n", (unsigned long long)i, status);
    1157             : 
    1158           0 :         fprintf(out, "\tthisUpdate: %s\n",
    1159           0 :                 printable_time(ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate));
    1160           0 :         if (ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate)
    1161           0 :             fprintf(out, "\tproducedAt: %s\n",
    1162           0 :                     printable_time(ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate));
    1163             : 
    1164             :     }
    1165             : 
    1166           0 :     fprintf(out, "appended certs:\n");
    1167           0 :     if (ocsp->certs)
    1168           0 :         ret = hx509_certs_iter_f(context, ocsp->certs, hx509_ci_print_names, out);
    1169             : 
    1170           0 :     return ret;
    1171             : }
    1172             :            
    1173             : static int
    1174           0 : print_crl(hx509_context context, struct revoke_crl *crl, FILE *out)
    1175             : {
    1176             :     {
    1177           0 :         hx509_name n;
    1178           0 :         char *s;
    1179           0 :         _hx509_name_from_Name(&crl->crl.tbsCertList.issuer, &n);
    1180           0 :         hx509_name_to_string(n, &s);
    1181           0 :         hx509_name_free(&n);
    1182           0 :         fprintf(out, " issuer: %s\n", s);
    1183           0 :         free(s);
    1184             :     }
    1185             : 
    1186           0 :     fprintf(out, " thisUpdate: %s\n", 
    1187           0 :             printable_time(_hx509_Time2time_t(&crl->crl.tbsCertList.thisUpdate)));
    1188             : 
    1189           0 :     return 0;
    1190             : }
    1191             : 
    1192             : 
    1193             : /*
    1194             :  *
    1195             :  */
    1196             : 
    1197             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1198           0 : hx509_revoke_print(hx509_context context,
    1199             :                    hx509_revoke_ctx ctx,
    1200             :                    FILE *out)
    1201             : {
    1202           0 :     int saved_ret = 0, ret;
    1203           0 :     size_t n;
    1204             : 
    1205           0 :     for (n = 0; n < ctx->ocsps.len; n++) {
    1206           0 :         struct revoke_ocsp *ocsp = &ctx->ocsps.val[n];
    1207             : 
    1208           0 :         fprintf(out, "OCSP %s\n", ocsp->path);
    1209             : 
    1210           0 :         ret = print_ocsp(context, ocsp, out);
    1211           0 :         if (ret) {
    1212           0 :             fprintf(out, "failure printing OCSP: %d\n", ret);
    1213           0 :             saved_ret = ret;
    1214             :         }
    1215             :     }
    1216             : 
    1217           0 :     for (n = 0; n < ctx->crls.len; n++) {
    1218           0 :         struct revoke_crl *crl = &ctx->crls.val[n];
    1219             : 
    1220           0 :         fprintf(out, "CRL %s\n", crl->path);
    1221             : 
    1222           0 :         ret = print_crl(context, crl, out);
    1223           0 :         if (ret) {
    1224           0 :             fprintf(out, "failure printing CRL: %d\n", ret);
    1225           0 :             saved_ret = ret;
    1226             :         }
    1227             :     }
    1228           0 :     return saved_ret;
    1229             : 
    1230             : }
    1231             : 
    1232             : /**
    1233             :  * Print the OCSP reply stored in a file.
    1234             :  *
    1235             :  * @param context a hx509 context
    1236             :  * @param path path to a file with a OCSP reply
    1237             :  * @param out the out FILE descriptor to print the reply on
    1238             :  *
    1239             :  * @return An hx509 error code, see hx509_get_error_string().
    1240             :  *
    1241             :  * @ingroup hx509_revoke
    1242             :  */
    1243             : 
    1244             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1245           0 : hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
    1246             : {
    1247           0 :     struct revoke_ocsp ocsp;
    1248           0 :     int ret;
    1249             : 
    1250           0 :     if (out == NULL)
    1251           0 :         out = stdout;
    1252             : 
    1253           0 :     memset(&ocsp, 0, sizeof(ocsp));
    1254             : 
    1255           0 :     ocsp.path = strdup(path);
    1256           0 :     if (ocsp.path == NULL)
    1257           0 :         return ENOMEM;
    1258             : 
    1259           0 :     ret = load_ocsp(context, &ocsp);
    1260           0 :     if (ret) {
    1261           0 :         free_ocsp(&ocsp);
    1262           0 :         return ret;
    1263             :     }
    1264             : 
    1265           0 :     ret = print_ocsp(context, &ocsp, out);
    1266             : 
    1267           0 :     free_ocsp(&ocsp);
    1268           0 :     return ret;
    1269             : }
    1270             : 
    1271             : /**
    1272             :  * Verify that the certificate is part of the OCSP reply and it's not
    1273             :  * expired. Doesn't verify signature the OCSP reply or it's done by a
    1274             :  * authorized sender, that is assumed to be already done.
    1275             :  *
    1276             :  * @param context a hx509 context
    1277             :  * @param now the time right now, if 0, use the current time.
    1278             :  * @param cert the certificate to verify
    1279             :  * @param flags flags control the behavior
    1280             :  * @param data pointer to the encode ocsp reply
    1281             :  * @param length the length of the encode ocsp reply
    1282             :  * @param expiration return the time the OCSP will expire and need to
    1283             :  * be rechecked.
    1284             :  *
    1285             :  * @return An hx509 error code, see hx509_get_error_string().
    1286             :  *
    1287             :  * @ingroup hx509_verify
    1288             :  */
    1289             : 
    1290             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1291           0 : hx509_ocsp_verify(hx509_context context,
    1292             :                   time_t now,
    1293             :                   hx509_cert cert,
    1294             :                   int flags,
    1295             :                   const void *data, size_t length,
    1296             :                   time_t *expiration)
    1297             : {
    1298           0 :     const Certificate *c = _hx509_get_cert(cert);
    1299           0 :     OCSPBasicOCSPResponse basic;
    1300           0 :     int ret;
    1301           0 :     size_t i;
    1302             : 
    1303           0 :     if (now == 0)
    1304           0 :         now = time(NULL);
    1305             : 
    1306           0 :     *expiration = 0;
    1307             : 
    1308           0 :     ret = parse_ocsp_basic(data, length, &basic);
    1309           0 :     if (ret) {
    1310           0 :         hx509_set_error_string(context, 0, ret,
    1311             :                                "Failed to parse OCSP response");
    1312           0 :         return ret;
    1313             :     }
    1314             : 
    1315           0 :     for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
    1316             : 
    1317           0 :         ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
    1318           0 :                                &c->tbsCertificate.serialNumber);
    1319           0 :         if (ret != 0)
    1320           0 :             continue;
    1321             : 
    1322             :         /* verify issuer hashes hash */
    1323           0 :         ret = _hx509_verify_signature(context,
    1324             :                                       NULL,
    1325           0 :                                       &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
    1326             :                                       &c->tbsCertificate.issuer._save,
    1327           0 :                                       &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
    1328           0 :         if (ret != 0)
    1329           0 :             continue;
    1330             : 
    1331           0 :         switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
    1332           0 :         case choice_OCSPCertStatus_good:
    1333           0 :             break;
    1334           0 :         case choice_OCSPCertStatus_revoked:
    1335             :         case choice_OCSPCertStatus_unknown:
    1336           0 :             continue;
    1337             :         }
    1338             : 
    1339             :         /* don't allow the update to be in the future */
    1340           0 :         if (basic.tbsResponseData.responses.val[i].thisUpdate >
    1341           0 :             now + context->ocsp_time_diff)
    1342           0 :             continue;
    1343             : 
    1344             :         /* don't allow the next update to be in the past */
    1345           0 :         if (basic.tbsResponseData.responses.val[i].nextUpdate) {
    1346           0 :             if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
    1347           0 :                 continue;
    1348           0 :             *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
    1349             :         } else
    1350           0 :             *expiration = now;
    1351             : 
    1352           0 :         free_OCSPBasicOCSPResponse(&basic);
    1353           0 :         return 0;
    1354             :     }
    1355             : 
    1356           0 :     free_OCSPBasicOCSPResponse(&basic);
    1357             : 
    1358             :     {
    1359           0 :         hx509_name name;
    1360           0 :         char *subject;
    1361             : 
    1362           0 :         ret = hx509_cert_get_subject(cert, &name);
    1363           0 :         if (ret) {
    1364           0 :             hx509_clear_error_string(context);
    1365           0 :             goto out;
    1366             :         }
    1367           0 :         ret = hx509_name_to_string(name, &subject);
    1368           0 :         hx509_name_free(&name);
    1369           0 :         if (ret) {
    1370           0 :             hx509_clear_error_string(context);
    1371           0 :             goto out;
    1372             :         }
    1373           0 :         hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
    1374             :                                "Certificate %s not in OCSP response "
    1375             :                                "or not good",
    1376             :                                subject);
    1377           0 :         free(subject);
    1378             :     }
    1379           0 : out:
    1380           0 :     return HX509_CERT_NOT_IN_OCSP;
    1381             : }
    1382             : 
    1383             : struct hx509_crl {
    1384             :     hx509_certs revoked;
    1385             :     time_t expire;
    1386             : };
    1387             : 
    1388             : /**
    1389             :  * Create a CRL context. Use hx509_crl_free() to free the CRL context.
    1390             :  *
    1391             :  * @param context a hx509 context.
    1392             :  * @param crl return pointer to a newly allocated CRL context.
    1393             :  *
    1394             :  * @return An hx509 error code, see hx509_get_error_string().
    1395             :  *
    1396             :  * @ingroup hx509_verify
    1397             :  */
    1398             : 
    1399             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1400           0 : hx509_crl_alloc(hx509_context context, hx509_crl *crl)
    1401             : {
    1402           0 :     int ret;
    1403             : 
    1404           0 :     *crl = calloc(1, sizeof(**crl));
    1405           0 :     if (*crl == NULL) {
    1406           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1407           0 :         return ENOMEM;
    1408             :     }
    1409             : 
    1410           0 :     ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
    1411           0 :     if (ret) {
    1412           0 :         free(*crl);
    1413           0 :         *crl = NULL;
    1414           0 :         return ret;
    1415             :     }
    1416           0 :     (*crl)->expire = 0;
    1417           0 :     return ret;
    1418             : }
    1419             : 
    1420             : /**
    1421             :  * Add revoked certificate to an CRL context.
    1422             :  *
    1423             :  * @param context a hx509 context.
    1424             :  * @param crl the CRL to add the revoked certificate to.
    1425             :  * @param certs keyset of certificate to revoke.
    1426             :  *
    1427             :  * @return An hx509 error code, see hx509_get_error_string().
    1428             :  *
    1429             :  * @ingroup hx509_verify
    1430             :  */
    1431             : 
    1432             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1433           0 : hx509_crl_add_revoked_certs(hx509_context context,
    1434             :                             hx509_crl crl,
    1435             :                             hx509_certs certs)
    1436             : {
    1437           0 :     return hx509_certs_merge(context, crl->revoked, certs);
    1438             : }
    1439             : 
    1440             : /**
    1441             :  * Set the lifetime of a CRL context.
    1442             :  *
    1443             :  * @param context a hx509 context.
    1444             :  * @param crl a CRL context
    1445             :  * @param delta delta time the certificate is valid, library adds the
    1446             :  * current time to this.
    1447             :  *
    1448             :  * @return An hx509 error code, see hx509_get_error_string().
    1449             :  *
    1450             :  * @ingroup hx509_verify
    1451             :  */
    1452             : 
    1453             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1454           0 : hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
    1455             : {
    1456           0 :     crl->expire = time(NULL) + delta;
    1457           0 :     return 0;
    1458             : }
    1459             : 
    1460             : /**
    1461             :  * Free a CRL context.
    1462             :  *
    1463             :  * @param context a hx509 context.
    1464             :  * @param crl a CRL context to free.
    1465             :  *
    1466             :  * @ingroup hx509_verify
    1467             :  */
    1468             : 
    1469             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    1470           0 : hx509_crl_free(hx509_context context, hx509_crl *crl)
    1471             : {
    1472           0 :     if (*crl == NULL)
    1473           0 :         return;
    1474           0 :     hx509_certs_free(&(*crl)->revoked);
    1475           0 :     memset(*crl, 0, sizeof(**crl));
    1476           0 :     free(*crl);
    1477           0 :     *crl = NULL;
    1478             : }
    1479             : 
    1480             : static int HX509_LIB_CALL
    1481           0 : add_revoked(hx509_context context, void *ctx, hx509_cert cert)
    1482             : {
    1483           0 :     TBSCRLCertList *c = ctx;
    1484           0 :     unsigned int num;
    1485           0 :     void *ptr;
    1486           0 :     int ret;
    1487             : 
    1488           0 :     num = c->revokedCertificates->len;
    1489           0 :     ptr = realloc(c->revokedCertificates->val,
    1490           0 :                   (num + 1) * sizeof(c->revokedCertificates->val[0]));
    1491           0 :     if (ptr == NULL) {
    1492           0 :         hx509_clear_error_string(context);
    1493           0 :         return ENOMEM;
    1494             :     }
    1495           0 :     c->revokedCertificates->val = ptr;
    1496             : 
    1497           0 :     ret = hx509_cert_get_serialnumber(cert,
    1498           0 :                                       &c->revokedCertificates->val[num].userCertificate);
    1499           0 :     if (ret) {
    1500           0 :         hx509_clear_error_string(context);
    1501           0 :         return ret;
    1502             :     }
    1503           0 :     c->revokedCertificates->val[num].revocationDate.element =
    1504             :         choice_Time_generalTime;
    1505           0 :     c->revokedCertificates->val[num].revocationDate.u.generalTime =
    1506           0 :         time(NULL) - 3600 * 24;
    1507           0 :     c->revokedCertificates->val[num].crlEntryExtensions = NULL;
    1508             : 
    1509           0 :     c->revokedCertificates->len++;
    1510             : 
    1511           0 :     return 0;
    1512             : }
    1513             : 
    1514             : /**
    1515             :  * Sign a CRL and return an encode certificate.
    1516             :  *
    1517             :  * @param context a hx509 context.
    1518             :  * @param signer certificate to sign the CRL with
    1519             :  * @param crl the CRL to sign
    1520             :  * @param os return the signed and encoded CRL, free with
    1521             :  * free_heim_octet_string()
    1522             :  *
    1523             :  * @return An hx509 error code, see hx509_get_error_string().
    1524             :  *
    1525             :  * @ingroup hx509_verify
    1526             :  */
    1527             : 
    1528             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1529           0 : hx509_crl_sign(hx509_context context,
    1530             :                hx509_cert signer,
    1531             :                hx509_crl crl,
    1532             :                heim_octet_string *os)
    1533             : {
    1534           0 :     const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg;
    1535           0 :     CRLCertificateList c;
    1536           0 :     size_t size;
    1537           0 :     int ret;
    1538           0 :     hx509_private_key signerkey;
    1539             : 
    1540           0 :     memset(&c, 0, sizeof(c));
    1541             : 
    1542           0 :     signerkey = _hx509_cert_private_key(signer);
    1543           0 :     if (signerkey == NULL) {
    1544           0 :         ret = HX509_PRIVATE_KEY_MISSING;
    1545           0 :         hx509_set_error_string(context, 0, ret,
    1546             :                                "Private key missing for CRL signing");
    1547           0 :         return ret;
    1548             :     }
    1549             : 
    1550           0 :     c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
    1551           0 :     if (c.tbsCertList.version == NULL) {
    1552           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1553           0 :         return ENOMEM;
    1554             :     }
    1555             : 
    1556           0 :     *c.tbsCertList.version = 1;
    1557             : 
    1558           0 :     ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
    1559           0 :     if (ret) {
    1560           0 :         hx509_clear_error_string(context);
    1561           0 :         goto out;
    1562             :     }
    1563             : 
    1564           0 :     ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
    1565             :                     &c.tbsCertList.issuer);
    1566           0 :     if (ret) {
    1567           0 :         hx509_clear_error_string(context);
    1568           0 :         goto out;
    1569             :     }
    1570             : 
    1571           0 :     c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
    1572           0 :     c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
    1573             : 
    1574           0 :     c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
    1575           0 :     if (c.tbsCertList.nextUpdate == NULL) {
    1576           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1577           0 :         ret = ENOMEM;
    1578           0 :         goto out;
    1579             :     }
    1580             : 
    1581             :     {
    1582           0 :         time_t next = crl->expire;
    1583           0 :         if (next == 0)
    1584           0 :             next = time(NULL) + 24 * 3600 * 365;
    1585             : 
    1586           0 :         c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
    1587           0 :         c.tbsCertList.nextUpdate->u.generalTime = next;
    1588             :     }
    1589             : 
    1590           0 :     c.tbsCertList.revokedCertificates =
    1591           0 :         calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
    1592           0 :     if (c.tbsCertList.revokedCertificates == NULL) {
    1593           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1594           0 :         ret = ENOMEM;
    1595           0 :         goto out;
    1596             :     }
    1597           0 :     c.tbsCertList.crlExtensions = NULL;
    1598             : 
    1599           0 :     ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList);
    1600           0 :     if (ret)
    1601           0 :         goto out;
    1602             : 
    1603             :     /* if not revoked certs, remove OPTIONAL entry */
    1604           0 :     if (c.tbsCertList.revokedCertificates->len == 0) {
    1605           0 :         free(c.tbsCertList.revokedCertificates);
    1606           0 :         c.tbsCertList.revokedCertificates = NULL;
    1607             :     }
    1608             : 
    1609           0 :     ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
    1610             :                        &c.tbsCertList, &size, ret);
    1611           0 :     if (ret) {
    1612           0 :         hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
    1613           0 :         goto out;
    1614             :     }
    1615           0 :     if (size != os->length)
    1616           0 :         _hx509_abort("internal ASN.1 encoder error");
    1617             : 
    1618             : 
    1619           0 :     ret = _hx509_create_signature_bitstring(context,
    1620             :                                             signerkey,
    1621             :                                             sigalg,
    1622             :                                             os,
    1623             :                                             &c.signatureAlgorithm,
    1624             :                                             &c.signatureValue);
    1625           0 :     free(os->data);
    1626           0 :     if (ret) {
    1627           0 :         hx509_set_error_string(context, 0, ret, "Failed to sign CRL");
    1628           0 :         goto out;
    1629             :     }
    1630             : 
    1631           0 :     ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
    1632             :                        &c, &size, ret);
    1633           0 :     if (ret) {
    1634           0 :         hx509_set_error_string(context, 0, ret, "failed to encode CRL");
    1635           0 :         goto out;
    1636             :     }
    1637           0 :     if (size != os->length)
    1638           0 :         _hx509_abort("internal ASN.1 encoder error");
    1639             : 
    1640           0 :     free_CRLCertificateList(&c);
    1641             : 
    1642           0 :     return 0;
    1643             : 
    1644           0 : out:
    1645           0 :     free_CRLCertificateList(&c);
    1646           0 :     return ret;
    1647             : }

Generated by: LCOV version 1.14