LCOV - code coverage report
Current view: top level - source4/heimdal/lib/hx509 - revoke.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 6 689 0.9 %
Date: 2021-09-23 10:06:22 Functions: 2 24 8.3 %

          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 certifiates 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 revokation context. Free with hx509_revoke_free().
      85             :  *
      86             :  * @param context A hx509 context.
      87             :  * @param ctx returns a newly allocated revokation context.
      88             :  *
      89             :  * @return An hx509 error code, see hx509_get_error_string().
      90             :  *
      91             :  * @ingroup hx509_revoke
      92             :  */
      93             : 
      94             : int
      95           0 : hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
      96             : {
      97           0 :     *ctx = calloc(1, sizeof(**ctx));
      98           0 :     if (*ctx == NULL)
      99           0 :         return ENOMEM;
     100             : 
     101           0 :     (*ctx)->ref = 1;
     102           0 :     (*ctx)->crls.len = 0;
     103           0 :     (*ctx)->crls.val = NULL;
     104           0 :     (*ctx)->ocsps.len = 0;
     105           0 :     (*ctx)->ocsps.val = NULL;
     106             : 
     107           0 :     return 0;
     108             : }
     109             : 
     110             : hx509_revoke_ctx
     111          94 : _hx509_revoke_ref(hx509_revoke_ctx ctx)
     112             : {
     113          94 :     if (ctx == NULL)
     114          86 :         return NULL;
     115           0 :     if (ctx->ref == 0)
     116           0 :         _hx509_abort("revoke ctx refcount == 0 on ref");
     117           0 :     ctx->ref++;
     118           0 :     if (ctx->ref == UINT_MAX)
     119           0 :         _hx509_abort("revoke ctx refcount == UINT_MAX on ref");
     120           0 :     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 revokation context.
     134             :  *
     135             :  * @param ctx context to be freed
     136             :  *
     137             :  * @ingroup hx509_revoke
     138             :  */
     139             : 
     140             : void
     141         112 : hx509_revoke_free(hx509_revoke_ctx *ctx)
     142             : {
     143             :     size_t i ;
     144             : 
     145         112 :     if (ctx == NULL || *ctx == NULL)
     146         112 :         return;
     147             : 
     148           0 :     if ((*ctx)->ref == 0)
     149           0 :         _hx509_abort("revoke ctx refcount == 0 on free");
     150           0 :     if (--(*ctx)->ref > 0)
     151           0 :         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             :     hx509_query q;
     178             :     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)
     206           0 :         goto out;
     207             : 
     208             :     /*
     209             :      * If signer certificate isn't the CA certificate, lets check the
     210             :      * it is the CA that signed the signer certificate and the OCSP EKU
     211             :      * is set.
     212             :      */
     213           0 :     if (hx509_cert_cmp(signer, parent) != 0) {
     214           0 :         Certificate *p = _hx509_get_cert(parent);
     215           0 :         Certificate *s = _hx509_get_cert(signer);
     216             : 
     217           0 :         ret = _hx509_cert_is_parent_cmp(s, p, 0);
     218           0 :         if (ret != 0) {
     219           0 :             ret = HX509_PARENT_NOT_CA;
     220           0 :             hx509_set_error_string(context, 0, ret, "Revoke OCSP signer is "
     221             :                                    "doesn't have CA as signer certificate");
     222           0 :             goto out;
     223             :         }
     224             : 
     225           0 :         ret = _hx509_verify_signature_bitstring(context,
     226             :                                                 parent,
     227           0 :                                                 &s->signatureAlgorithm,
     228           0 :                                                 &s->tbsCertificate._save,
     229           0 :                                                 &s->signatureValue);
     230           0 :         if (ret) {
     231           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     232             :                                    "OCSP signer signature invalid");
     233           0 :             goto out;
     234             :         }
     235             : 
     236           0 :         ret = hx509_cert_check_eku(context, signer,
     237             :                                    &asn1_oid_id_pkix_kp_OCSPSigning, 0);
     238           0 :         if (ret)
     239           0 :             goto out;
     240             :     }
     241             : 
     242           0 :     ret = _hx509_verify_signature_bitstring(context,
     243             :                                             signer,
     244           0 :                                             &ocsp->ocsp.signatureAlgorithm,
     245           0 :                                             &ocsp->ocsp.tbsResponseData._save,
     246           0 :                                             &ocsp->ocsp.signature);
     247           0 :     if (ret) {
     248           0 :         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     249             :                                "OCSP signature invalid");
     250           0 :         goto out;
     251             :     }
     252             : 
     253           0 :     ocsp->signer = signer;
     254           0 :     signer = NULL;
     255           0 : out:
     256           0 :     if (signer)
     257           0 :         hx509_cert_free(signer);
     258             : 
     259           0 :     return ret;
     260             : }
     261             : 
     262             : /*
     263             :  *
     264             :  */
     265             : 
     266             : static int
     267           0 : parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
     268             : {
     269             :     OCSPResponse resp;
     270             :     size_t size;
     271             :     int ret;
     272             : 
     273           0 :     memset(basic, 0, sizeof(*basic));
     274             : 
     275           0 :     ret = decode_OCSPResponse(data, length, &resp, &size);
     276           0 :     if (ret)
     277           0 :         return ret;
     278           0 :     if (length != size) {
     279           0 :         free_OCSPResponse(&resp);
     280           0 :         return ASN1_EXTRA_DATA;
     281             :     }
     282             : 
     283           0 :     switch (resp.responseStatus) {
     284           0 :     case successful:
     285           0 :         break;
     286           0 :     default:
     287           0 :         free_OCSPResponse(&resp);
     288           0 :         return HX509_REVOKE_WRONG_DATA;
     289             :     }
     290             : 
     291           0 :     if (resp.responseBytes == NULL) {
     292           0 :         free_OCSPResponse(&resp);
     293           0 :         return EINVAL;
     294             :     }
     295             : 
     296           0 :     ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
     297             :                            &asn1_oid_id_pkix_ocsp_basic);
     298           0 :     if (ret != 0) {
     299           0 :         free_OCSPResponse(&resp);
     300           0 :         return HX509_REVOKE_WRONG_DATA;
     301             :     }
     302             : 
     303           0 :     ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
     304           0 :                                        resp.responseBytes->response.length,
     305             :                                        basic,
     306             :                                        &size);
     307           0 :     if (ret) {
     308           0 :         free_OCSPResponse(&resp);
     309           0 :         return ret;
     310             :     }
     311           0 :     if (size != resp.responseBytes->response.length) {
     312           0 :         free_OCSPResponse(&resp);
     313           0 :         free_OCSPBasicOCSPResponse(basic);
     314           0 :         return ASN1_EXTRA_DATA;
     315             :     }
     316           0 :     free_OCSPResponse(&resp);
     317             : 
     318           0 :     return 0;
     319             : }
     320             : 
     321             : /*
     322             :  *
     323             :  */
     324             : 
     325             : static int
     326           0 : load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
     327             : {
     328             :     OCSPBasicOCSPResponse basic;
     329           0 :     hx509_certs certs = NULL;
     330             :     size_t length;
     331             :     struct stat sb;
     332             :     void *data;
     333             :     int ret;
     334             : 
     335           0 :     ret = rk_undumpdata(ocsp->path, &data, &length);
     336           0 :     if (ret)
     337           0 :         return ret;
     338             : 
     339           0 :     ret = stat(ocsp->path, &sb);
     340           0 :     if (ret)
     341           0 :         return errno;
     342             : 
     343           0 :     ret = parse_ocsp_basic(data, length, &basic);
     344           0 :     rk_xfree(data);
     345           0 :     if (ret) {
     346           0 :         hx509_set_error_string(context, 0, ret,
     347             :                                "Failed to parse OCSP response");
     348           0 :         return ret;
     349             :     }
     350             : 
     351           0 :     if (basic.certs) {
     352             :         size_t i;
     353             : 
     354           0 :         ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
     355             :                                NULL, &certs);
     356           0 :         if (ret) {
     357           0 :             free_OCSPBasicOCSPResponse(&basic);
     358           0 :             return ret;
     359             :         }
     360             : 
     361           0 :         for (i = 0; i < basic.certs->len; i++) {
     362             :             hx509_cert c;
     363             : 
     364           0 :             ret = hx509_cert_init(context, &basic.certs->val[i], &c);
     365           0 :             if (ret)
     366           0 :                 continue;
     367             : 
     368           0 :             ret = hx509_certs_add(context, certs, c);
     369           0 :             hx509_cert_free(c);
     370           0 :             if (ret)
     371           0 :                 continue;
     372             :         }
     373             :     }
     374             : 
     375           0 :     ocsp->last_modfied = sb.st_mtime;
     376             : 
     377           0 :     free_OCSPBasicOCSPResponse(&ocsp->ocsp);
     378           0 :     hx509_certs_free(&ocsp->certs);
     379           0 :     hx509_cert_free(ocsp->signer);
     380             : 
     381           0 :     ocsp->ocsp = basic;
     382           0 :     ocsp->certs = certs;
     383           0 :     ocsp->signer = NULL;
     384             : 
     385           0 :     return 0;
     386             : }
     387             : 
     388             : /**
     389             :  * Add a OCSP file to the revokation context.
     390             :  *
     391             :  * @param context hx509 context
     392             :  * @param ctx hx509 revokation context
     393             :  * @param path path to file that is going to be added to the context.
     394             :  *
     395             :  * @return An hx509 error code, see hx509_get_error_string().
     396             :  *
     397             :  * @ingroup hx509_revoke
     398             :  */
     399             : 
     400             : int
     401           0 : hx509_revoke_add_ocsp(hx509_context context,
     402             :                       hx509_revoke_ctx ctx,
     403             :                       const char *path)
     404             : {
     405             :     void *data;
     406             :     int ret;
     407             :     size_t i;
     408             : 
     409           0 :     if (strncmp(path, "FILE:", 5) != 0) {
     410           0 :         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
     411             :                                "unsupport type in %s", path);
     412           0 :         return HX509_UNSUPPORTED_OPERATION;
     413             :     }
     414             : 
     415           0 :     path += 5;
     416             : 
     417           0 :     for (i = 0; i < ctx->ocsps.len; i++) {
     418           0 :         if (strcmp(ctx->ocsps.val[0].path, path) == 0)
     419           0 :             return 0;
     420             :     }
     421             : 
     422           0 :     data = realloc(ctx->ocsps.val,
     423           0 :                    (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
     424           0 :     if (data == NULL) {
     425           0 :         hx509_clear_error_string(context);
     426           0 :         return ENOMEM;
     427             :     }
     428             : 
     429           0 :     ctx->ocsps.val = data;
     430             : 
     431           0 :     memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
     432             :            sizeof(ctx->ocsps.val[0]));
     433             : 
     434           0 :     ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
     435           0 :     if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
     436           0 :         hx509_clear_error_string(context);
     437           0 :         return ENOMEM;
     438             :     }
     439             : 
     440           0 :     ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
     441           0 :     if (ret) {
     442           0 :         free(ctx->ocsps.val[ctx->ocsps.len].path);
     443           0 :         return ret;
     444             :     }
     445           0 :     ctx->ocsps.len++;
     446             : 
     447           0 :     return ret;
     448             : }
     449             : 
     450             : /*
     451             :  *
     452             :  */
     453             : 
     454             : static int
     455           0 : verify_crl(hx509_context context,
     456             :            hx509_revoke_ctx ctx,
     457             :            CRLCertificateList *crl,
     458             :            time_t time_now,
     459             :            hx509_certs certs,
     460             :            hx509_cert parent)
     461             : {
     462             :     hx509_cert signer;
     463             :     hx509_query q;
     464             :     time_t t;
     465             :     int ret;
     466             : 
     467           0 :     t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
     468           0 :     if (t > time_now) {
     469           0 :         hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
     470             :                                "CRL used before time");
     471           0 :         return HX509_CRL_USED_BEFORE_TIME;
     472             :     }
     473             : 
     474           0 :     if (crl->tbsCertList.nextUpdate == NULL) {
     475           0 :         hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
     476             :                                "CRL missing nextUpdate");
     477           0 :         return HX509_CRL_INVALID_FORMAT;
     478             :     }
     479             : 
     480           0 :     t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
     481           0 :     if (t < time_now) {
     482           0 :         hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
     483             :                                "CRL used after time");
     484           0 :         return HX509_CRL_USED_AFTER_TIME;
     485             :     }
     486             : 
     487           0 :     _hx509_query_clear(&q);
     488             : 
     489             :     /*
     490             :      * If it's the signer have CRLSIGN bit set, use that as the signer
     491             :      * cert for the certificate, otherwise, search for a certificate.
     492             :      */
     493           0 :     if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
     494           0 :         signer = hx509_cert_ref(parent);
     495             :     } else {
     496           0 :         q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
     497           0 :         q.match |= HX509_QUERY_KU_CRLSIGN;
     498           0 :         q.subject_name = &crl->tbsCertList.issuer;
     499             : 
     500           0 :         ret = hx509_certs_find(context, certs, &q, &signer);
     501           0 :         if (ret) {
     502           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     503             :                                    "Failed to find certificate for CRL");
     504           0 :             return ret;
     505             :         }
     506             :     }
     507             : 
     508           0 :     ret = _hx509_verify_signature_bitstring(context,
     509             :                                             signer,
     510           0 :                                             &crl->signatureAlgorithm,
     511           0 :                                             &crl->tbsCertList._save,
     512           0 :                                             &crl->signatureValue);
     513           0 :     if (ret) {
     514           0 :         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     515             :                                "CRL signature invalid");
     516           0 :         goto out;
     517             :     }
     518             : 
     519             :     /*
     520             :      * If signer is not CA cert, need to check revoke status of this
     521             :      * CRL signing cert too, this include all parent CRL signer cert
     522             :      * up to the root *sigh*, assume root at least hve CERTSIGN flag
     523             :      * set.
     524             :      */
     525           0 :     while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
     526             :         hx509_cert crl_parent;
     527             : 
     528           0 :         _hx509_query_clear(&q);
     529             : 
     530           0 :         q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
     531           0 :         q.match |= HX509_QUERY_KU_CRLSIGN;
     532           0 :         q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
     533             : 
     534           0 :         ret = hx509_certs_find(context, certs, &q, &crl_parent);
     535           0 :         if (ret) {
     536           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     537             :                                    "Failed to find parent of CRL signer");
     538           0 :             goto out;
     539             :         }
     540             : 
     541           0 :         ret = hx509_revoke_verify(context,
     542             :                                   ctx,
     543             :                                   certs,
     544             :                                   time_now,
     545             :                                   signer,
     546             :                                   crl_parent);
     547           0 :         hx509_cert_free(signer);
     548           0 :         signer = crl_parent;
     549           0 :         if (ret) {
     550           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
     551             :                                    "Failed to verify revoke "
     552             :                                    "status of CRL signer");
     553           0 :             goto out;
     554             :         }
     555             :     }
     556             : 
     557           0 : out:
     558           0 :     hx509_cert_free(signer);
     559             : 
     560           0 :     return ret;
     561             : }
     562             : 
     563             : static int
     564           0 : load_crl(const char *path, time_t *t, CRLCertificateList *crl)
     565             : {
     566             :     size_t length, size;
     567             :     struct stat sb;
     568             :     void *data;
     569             :     int ret;
     570             : 
     571           0 :     memset(crl, 0, sizeof(*crl));
     572             : 
     573           0 :     ret = rk_undumpdata(path, &data, &length);
     574           0 :     if (ret)
     575           0 :         return ret;
     576             : 
     577           0 :     ret = stat(path, &sb);
     578           0 :     if (ret)
     579           0 :         return errno;
     580             : 
     581           0 :     *t = sb.st_mtime;
     582             : 
     583           0 :     ret = decode_CRLCertificateList(data, length, crl, &size);
     584           0 :     rk_xfree(data);
     585           0 :     if (ret)
     586           0 :         return ret;
     587             : 
     588             :     /* check signature is aligned */
     589           0 :     if (crl->signatureValue.length & 7) {
     590           0 :         free_CRLCertificateList(crl);
     591           0 :         return HX509_CRYPTO_SIG_INVALID_FORMAT;
     592             :     }
     593           0 :     return 0;
     594             : }
     595             : 
     596             : /**
     597             :  * Add a CRL file to the revokation context.
     598             :  *
     599             :  * @param context hx509 context
     600             :  * @param ctx hx509 revokation context
     601             :  * @param path path to file that is going to be added to the context.
     602             :  *
     603             :  * @return An hx509 error code, see hx509_get_error_string().
     604             :  *
     605             :  * @ingroup hx509_revoke
     606             :  */
     607             : 
     608             : int
     609           0 : hx509_revoke_add_crl(hx509_context context,
     610             :                      hx509_revoke_ctx ctx,
     611             :                      const char *path)
     612             : {
     613             :     void *data;
     614             :     size_t i;
     615             :     int ret;
     616             : 
     617           0 :     if (strncmp(path, "FILE:", 5) != 0) {
     618           0 :         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
     619             :                                "unsupport type in %s", path);
     620           0 :         return HX509_UNSUPPORTED_OPERATION;
     621             :     }
     622             : 
     623             : 
     624           0 :     path += 5;
     625             : 
     626           0 :     for (i = 0; i < ctx->crls.len; i++) {
     627           0 :         if (strcmp(ctx->crls.val[0].path, path) == 0)
     628           0 :             return 0;
     629             :     }
     630             : 
     631           0 :     data = realloc(ctx->crls.val,
     632           0 :                    (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
     633           0 :     if (data == NULL) {
     634           0 :         hx509_clear_error_string(context);
     635           0 :         return ENOMEM;
     636             :     }
     637           0 :     ctx->crls.val = data;
     638             : 
     639           0 :     memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
     640             : 
     641           0 :     ctx->crls.val[ctx->crls.len].path = strdup(path);
     642           0 :     if (ctx->crls.val[ctx->crls.len].path == NULL) {
     643           0 :         hx509_clear_error_string(context);
     644           0 :         return ENOMEM;
     645             :     }
     646             : 
     647           0 :     ret = load_crl(path,
     648           0 :                    &ctx->crls.val[ctx->crls.len].last_modfied,
     649           0 :                    &ctx->crls.val[ctx->crls.len].crl);
     650           0 :     if (ret) {
     651           0 :         free(ctx->crls.val[ctx->crls.len].path);
     652           0 :         return ret;
     653             :     }
     654             : 
     655           0 :     ctx->crls.len++;
     656             : 
     657           0 :     return ret;
     658             : }
     659             : 
     660             : /**
     661             :  * Check that a certificate is not expired according to a revokation
     662             :  * context. Also need the parent certificte to the check OCSP
     663             :  * parent identifier.
     664             :  *
     665             :  * @param context hx509 context
     666             :  * @param ctx hx509 revokation context
     667             :  * @param certs
     668             :  * @param now
     669             :  * @param cert
     670             :  * @param parent_cert
     671             :  *
     672             :  * @return An hx509 error code, see hx509_get_error_string().
     673             :  *
     674             :  * @ingroup hx509_revoke
     675             :  */
     676             : 
     677             : 
     678             : int
     679           0 : hx509_revoke_verify(hx509_context context,
     680             :                     hx509_revoke_ctx ctx,
     681             :                     hx509_certs certs,
     682             :                     time_t now,
     683             :                     hx509_cert cert,
     684             :                     hx509_cert parent_cert)
     685             : {
     686           0 :     const Certificate *c = _hx509_get_cert(cert);
     687           0 :     const Certificate *p = _hx509_get_cert(parent_cert);
     688             :     unsigned long i, j, k;
     689             :     int ret;
     690             : 
     691           0 :     hx509_clear_error_string(context);
     692             : 
     693           0 :     for (i = 0; i < ctx->ocsps.len; i++) {
     694           0 :         struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
     695             :         struct stat sb;
     696             : 
     697             :         /* check this ocsp apply to this cert */
     698             : 
     699             :         /* check if there is a newer version of the file */
     700           0 :         ret = stat(ocsp->path, &sb);
     701           0 :         if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
     702           0 :             ret = load_ocsp(context, ocsp);
     703           0 :             if (ret)
     704           0 :                 continue;
     705             :         }
     706             : 
     707             :         /* verify signature in ocsp if not already done */
     708           0 :         if (ocsp->signer == NULL) {
     709           0 :             ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
     710           0 :             if (ret)
     711           0 :                 continue;
     712             :         }
     713             : 
     714           0 :         for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
     715             :             heim_octet_string os;
     716             : 
     717           0 :             ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
     718           0 :                                    &c->tbsCertificate.serialNumber);
     719           0 :             if (ret != 0)
     720           0 :                 continue;
     721             : 
     722             :             /* verify issuer hashes hash */
     723           0 :             ret = _hx509_verify_signature(context,
     724             :                                           NULL,
     725           0 :                                           &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
     726             :                                           &c->tbsCertificate.issuer._save,
     727           0 :                                           &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
     728           0 :             if (ret != 0)
     729           0 :                 continue;
     730             : 
     731           0 :             os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
     732           0 :             os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
     733             : 
     734           0 :             ret = _hx509_verify_signature(context,
     735             :                                           NULL,
     736           0 :                                           &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
     737             :                                           &os,
     738           0 :                                           &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
     739           0 :             if (ret != 0)
     740           0 :                 continue;
     741             : 
     742           0 :             switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
     743           0 :             case choice_OCSPCertStatus_good:
     744           0 :                 break;
     745           0 :             case choice_OCSPCertStatus_revoked:
     746           0 :                 hx509_set_error_string(context, 0,
     747             :                                        HX509_CERT_REVOKED,
     748             :                                        "Certificate revoked by issuer in OCSP");
     749           0 :                 return HX509_CERT_REVOKED;
     750           0 :             case choice_OCSPCertStatus_unknown:
     751           0 :                 continue;
     752             :             }
     753             : 
     754             :             /* don't allow the update to be in the future */
     755           0 :             if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
     756           0 :                 now + context->ocsp_time_diff)
     757           0 :                 continue;
     758             : 
     759             :             /* don't allow the next update to be in the past */
     760           0 :             if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
     761           0 :                 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
     762           0 :                     continue;
     763             :             } /* else should force a refetch, but can we ? */
     764             : 
     765           0 :             return 0;
     766             :         }
     767             :     }
     768             : 
     769           0 :     for (i = 0; i < ctx->crls.len; i++) {
     770           0 :         struct revoke_crl *crl = &ctx->crls.val[i];
     771             :         struct stat sb;
     772             :         int diff;
     773             : 
     774             :         /* check if cert.issuer == crls.val[i].crl.issuer */
     775           0 :         ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
     776           0 :                               &crl->crl.tbsCertList.issuer, &diff);
     777           0 :         if (ret || diff)
     778           0 :             continue;
     779             : 
     780           0 :         ret = stat(crl->path, &sb);
     781           0 :         if (ret == 0 && crl->last_modfied != sb.st_mtime) {
     782             :             CRLCertificateList cl;
     783             : 
     784           0 :             ret = load_crl(crl->path, &crl->last_modfied, &cl);
     785           0 :             if (ret == 0) {
     786           0 :                 free_CRLCertificateList(&crl->crl);
     787           0 :                 crl->crl = cl;
     788           0 :                 crl->verified = 0;
     789           0 :                 crl->failed_verify = 0;
     790             :             }
     791             :         }
     792           0 :         if (crl->failed_verify)
     793           0 :             continue;
     794             : 
     795             :         /* verify signature in crl if not already done */
     796           0 :         if (crl->verified == 0) {
     797           0 :             ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
     798           0 :             if (ret) {
     799           0 :                 crl->failed_verify = 1;
     800           0 :                 continue;
     801             :             }
     802           0 :             crl->verified = 1;
     803             :         }
     804             : 
     805           0 :         if (crl->crl.tbsCertList.crlExtensions) {
     806           0 :             for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
     807           0 :                 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
     808           0 :                     hx509_set_error_string(context, 0,
     809             :                                            HX509_CRL_UNKNOWN_EXTENSION,
     810             :                                            "Unknown CRL extension");
     811           0 :                     return HX509_CRL_UNKNOWN_EXTENSION;
     812             :                 }
     813             :             }
     814             :         }
     815             : 
     816           0 :         if (crl->crl.tbsCertList.revokedCertificates == NULL)
     817           0 :             return 0;
     818             : 
     819             :         /* check if cert is in crl */
     820           0 :         for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
     821             :             time_t t;
     822             : 
     823           0 :             ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
     824           0 :                                        &c->tbsCertificate.serialNumber);
     825           0 :             if (ret != 0)
     826           0 :                 continue;
     827             : 
     828           0 :             t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
     829           0 :             if (t > now)
     830           0 :                 continue;
     831             : 
     832           0 :             if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
     833           0 :                 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
     834           0 :                     if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
     835           0 :                         return HX509_CRL_UNKNOWN_EXTENSION;
     836             : 
     837           0 :             hx509_set_error_string(context, 0,
     838             :                                    HX509_CERT_REVOKED,
     839             :                                    "Certificate revoked by issuer in CRL");
     840           0 :             return HX509_CERT_REVOKED;
     841             :         }
     842             : 
     843           0 :         return 0;
     844             :     }
     845             : 
     846             : 
     847           0 :     if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
     848           0 :         return 0;
     849           0 :     hx509_set_error_string(context, HX509_ERROR_APPEND,
     850             :                            HX509_REVOKE_STATUS_MISSING,
     851             :                            "No revoke status found for "
     852             :                            "certificates");
     853           0 :     return HX509_REVOKE_STATUS_MISSING;
     854             : }
     855             : 
     856             : struct ocsp_add_ctx {
     857             :     OCSPTBSRequest *req;
     858             :     hx509_certs certs;
     859             :     const AlgorithmIdentifier *digest;
     860             :     hx509_cert parent;
     861             : };
     862             : 
     863             : static int
     864           0 : add_to_req(hx509_context context, void *ptr, hx509_cert cert)
     865             : {
     866           0 :     struct ocsp_add_ctx *ctx = ptr;
     867             :     OCSPInnerRequest *one;
     868           0 :     hx509_cert parent = NULL;
     869           0 :     Certificate *p, *c = _hx509_get_cert(cert);
     870             :     heim_octet_string os;
     871             :     int ret;
     872             :     hx509_query q;
     873             :     void *d;
     874             : 
     875           0 :     d = realloc(ctx->req->requestList.val,
     876             :                 sizeof(ctx->req->requestList.val[0]) *
     877           0 :                 (ctx->req->requestList.len + 1));
     878           0 :     if (d == NULL)
     879           0 :         return ENOMEM;
     880           0 :     ctx->req->requestList.val = d;
     881             : 
     882           0 :     one = &ctx->req->requestList.val[ctx->req->requestList.len];
     883           0 :     memset(one, 0, sizeof(*one));
     884             : 
     885           0 :     _hx509_query_clear(&q);
     886             : 
     887           0 :     q.match |= HX509_QUERY_FIND_ISSUER_CERT;
     888           0 :     q.subject = c;
     889             : 
     890           0 :     ret = hx509_certs_find(context, ctx->certs, &q, &parent);
     891           0 :     if (ret)
     892           0 :         goto out;
     893             : 
     894           0 :     if (ctx->parent) {
     895           0 :         if (hx509_cert_cmp(ctx->parent, parent) != 0) {
     896           0 :             ret = HX509_REVOKE_NOT_SAME_PARENT;
     897           0 :             hx509_set_error_string(context, 0, ret,
     898             :                                    "Not same parent certifate as "
     899             :                                    "last certificate in request");
     900           0 :             goto out;
     901             :         }
     902             :     } else
     903           0 :         ctx->parent = hx509_cert_ref(parent);
     904             : 
     905           0 :     p = _hx509_get_cert(parent);
     906             : 
     907           0 :     ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
     908           0 :     if (ret)
     909           0 :         goto out;
     910             : 
     911           0 :     ret = _hx509_create_signature(context,
     912             :                                   NULL,
     913           0 :                                   &one->reqCert.hashAlgorithm,
     914           0 :                                   &c->tbsCertificate.issuer._save,
     915             :                                   NULL,
     916             :                                   &one->reqCert.issuerNameHash);
     917           0 :     if (ret)
     918           0 :         goto out;
     919             : 
     920           0 :     os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
     921           0 :     os.length =
     922           0 :         p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
     923             : 
     924           0 :     ret = _hx509_create_signature(context,
     925             :                                   NULL,
     926           0 :                                   &one->reqCert.hashAlgorithm,
     927             :                                   &os,
     928             :                                   NULL,
     929             :                                   &one->reqCert.issuerKeyHash);
     930           0 :     if (ret)
     931           0 :         goto out;
     932             : 
     933           0 :     ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
     934             :                                        &one->reqCert.serialNumber);
     935           0 :     if (ret)
     936           0 :         goto out;
     937             : 
     938           0 :     ctx->req->requestList.len++;
     939           0 : out:
     940           0 :     hx509_cert_free(parent);
     941           0 :     if (ret) {
     942           0 :         free_OCSPInnerRequest(one);
     943           0 :         memset(one, 0, sizeof(*one));
     944             :     }
     945             : 
     946           0 :     return ret;
     947             : }
     948             : 
     949             : /**
     950             :  * Create an OCSP request for a set of certificates.
     951             :  *
     952             :  * @param context a hx509 context
     953             :  * @param reqcerts list of certificates to request ocsp data for
     954             :  * @param pool certificate pool to use when signing
     955             :  * @param signer certificate to use to sign the request
     956             :  * @param digest the signing algorithm in the request, if NULL use the
     957             :  * default signature algorithm,
     958             :  * @param request the encoded request, free with free_heim_octet_string().
     959             :  * @param nonce nonce in the request, free with free_heim_octet_string().
     960             :  *
     961             :  * @return An hx509 error code, see hx509_get_error_string().
     962             :  *
     963             :  * @ingroup hx509_revoke
     964             :  */
     965             : 
     966             : int
     967           0 : hx509_ocsp_request(hx509_context context,
     968             :                    hx509_certs reqcerts,
     969             :                    hx509_certs pool,
     970             :                    hx509_cert signer,
     971             :                    const AlgorithmIdentifier *digest,
     972             :                    heim_octet_string *request,
     973             :                    heim_octet_string *nonce)
     974             : {
     975             :     OCSPRequest req;
     976             :     size_t size;
     977             :     int ret;
     978             :     struct ocsp_add_ctx ctx;
     979             :     Extensions *es;
     980             : 
     981           0 :     memset(&req, 0, sizeof(req));
     982             : 
     983           0 :     if (digest == NULL)
     984           0 :         digest = _hx509_crypto_default_digest_alg;
     985             : 
     986           0 :     ctx.req = &req.tbsRequest;
     987           0 :     ctx.certs = pool;
     988           0 :     ctx.digest = digest;
     989           0 :     ctx.parent = NULL;
     990             : 
     991           0 :     ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx);
     992           0 :     hx509_cert_free(ctx.parent);
     993           0 :     if (ret)
     994           0 :         goto out;
     995             : 
     996           0 :     if (nonce) {
     997           0 :         req.tbsRequest.requestExtensions =
     998           0 :             calloc(1, sizeof(*req.tbsRequest.requestExtensions));
     999           0 :         if (req.tbsRequest.requestExtensions == NULL) {
    1000           0 :             ret = ENOMEM;
    1001           0 :             goto out;
    1002             :         }
    1003             : 
    1004           0 :         es = req.tbsRequest.requestExtensions;
    1005             : 
    1006           0 :         es->val = calloc(es->len, sizeof(es->val[0]));
    1007           0 :         if (es->val == NULL) {
    1008           0 :             ret = ENOMEM;
    1009           0 :             goto out;
    1010             :         }
    1011           0 :         es->len = 1;
    1012           0 :         ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID);
    1013           0 :         if (ret) {
    1014           0 :             free_OCSPRequest(&req);
    1015           0 :             return ret;
    1016             :         }
    1017             : 
    1018           0 :         es->val[0].extnValue.data = malloc(10);
    1019           0 :         if (es->val[0].extnValue.data == NULL) {
    1020           0 :             ret = ENOMEM;
    1021           0 :             goto out;
    1022             :         }
    1023           0 :         es->val[0].extnValue.length = 10;
    1024             : 
    1025           0 :         ret = RAND_bytes(es->val[0].extnValue.data,
    1026           0 :                          es->val[0].extnValue.length);
    1027           0 :         if (ret != 1) {
    1028           0 :             ret = HX509_CRYPTO_INTERNAL_ERROR;
    1029           0 :             goto out;
    1030             :         }
    1031           0 :         ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
    1032           0 :         if (ret) {
    1033           0 :             ret = ENOMEM;
    1034           0 :             goto out;
    1035             :         }
    1036             :     }
    1037             : 
    1038           0 :     ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
    1039             :                        &req, &size, ret);
    1040           0 :     free_OCSPRequest(&req);
    1041           0 :     if (ret)
    1042           0 :         goto out;
    1043           0 :     if (size != request->length)
    1044           0 :         _hx509_abort("internal ASN.1 encoder error");
    1045             : 
    1046           0 :     return 0;
    1047             : 
    1048           0 : out:
    1049           0 :     free_OCSPRequest(&req);
    1050           0 :     return ret;
    1051             : }
    1052             : 
    1053             : static char *
    1054           0 : printable_time(time_t t)
    1055             : {
    1056             :     static char s[128];
    1057             :     char *p;
    1058           0 :     if ((p = ctime(&t)) == NULL)
    1059           0 :        strlcpy(s, "?", sizeof(s));
    1060             :     else {
    1061           0 :        strlcpy(s, p + 4, sizeof(s));
    1062           0 :        s[20] = 0;
    1063             :     }
    1064           0 :     return s;
    1065             : }
    1066             : 
    1067             : /**
    1068             :  * Print the OCSP reply stored in a file.
    1069             :  *
    1070             :  * @param context a hx509 context
    1071             :  * @param path path to a file with a OCSP reply
    1072             :  * @param out the out FILE descriptor to print the reply on
    1073             :  *
    1074             :  * @return An hx509 error code, see hx509_get_error_string().
    1075             :  *
    1076             :  * @ingroup hx509_revoke
    1077             :  */
    1078             : 
    1079             : int
    1080           0 : hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
    1081             : {
    1082             :     struct revoke_ocsp ocsp;
    1083             :     int ret;
    1084             :     size_t i;
    1085             : 
    1086           0 :     if (out == NULL)
    1087           0 :         out = stdout;
    1088             : 
    1089           0 :     memset(&ocsp, 0, sizeof(ocsp));
    1090             : 
    1091           0 :     ocsp.path = strdup(path);
    1092           0 :     if (ocsp.path == NULL)
    1093           0 :         return ENOMEM;
    1094             : 
    1095           0 :     ret = load_ocsp(context, &ocsp);
    1096           0 :     if (ret) {
    1097           0 :         free_ocsp(&ocsp);
    1098           0 :         return ret;
    1099             :     }
    1100             : 
    1101           0 :     fprintf(out, "signer: ");
    1102             : 
    1103           0 :     switch(ocsp.ocsp.tbsResponseData.responderID.element) {
    1104           0 :     case choice_OCSPResponderID_byName: {
    1105             :         hx509_name n;
    1106             :         char *s;
    1107           0 :         _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
    1108           0 :         hx509_name_to_string(n, &s);
    1109           0 :         hx509_name_free(&n);
    1110           0 :         fprintf(out, " byName: %s\n", s);
    1111           0 :         free(s);
    1112           0 :         break;
    1113             :     }
    1114           0 :     case choice_OCSPResponderID_byKey: {
    1115             :         char *s;
    1116           0 :         hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
    1117             :                    ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
    1118             :                    &s);
    1119           0 :         fprintf(out, " byKey: %s\n", s);
    1120           0 :         free(s);
    1121           0 :         break;
    1122             :     }
    1123           0 :     default:
    1124           0 :         _hx509_abort("choice_OCSPResponderID unknown");
    1125             :         break;
    1126             :     }
    1127             : 
    1128           0 :     fprintf(out, "producedAt: %s\n",
    1129             :             printable_time(ocsp.ocsp.tbsResponseData.producedAt));
    1130             : 
    1131           0 :     fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
    1132             : 
    1133           0 :     for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
    1134             :         const char *status;
    1135           0 :         switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
    1136           0 :         case choice_OCSPCertStatus_good:
    1137           0 :             status = "good";
    1138           0 :             break;
    1139           0 :         case choice_OCSPCertStatus_revoked:
    1140           0 :             status = "revoked";
    1141           0 :             break;
    1142           0 :         case choice_OCSPCertStatus_unknown:
    1143           0 :             status = "unknown";
    1144           0 :             break;
    1145           0 :         default:
    1146           0 :             status = "element unknown";
    1147             :         }
    1148             : 
    1149           0 :         fprintf(out, "\t%zu. status: %s\n", i, status);
    1150             : 
    1151           0 :         fprintf(out, "\tthisUpdate: %s\n",
    1152           0 :                 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
    1153           0 :         if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
    1154           0 :             fprintf(out, "\tproducedAt: %s\n",
    1155           0 :                     printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
    1156             : 
    1157             :     }
    1158             : 
    1159           0 :     fprintf(out, "appended certs:\n");
    1160           0 :     if (ocsp.certs)
    1161           0 :         ret = hx509_certs_iter_f(context, ocsp.certs, hx509_ci_print_names, out);
    1162             : 
    1163           0 :     free_ocsp(&ocsp);
    1164           0 :     return ret;
    1165             : }
    1166             : 
    1167             : /**
    1168             :  * Verify that the certificate is part of the OCSP reply and it's not
    1169             :  * expired. Doesn't verify signature the OCSP reply or it's done by a
    1170             :  * authorized sender, that is assumed to be already done.
    1171             :  *
    1172             :  * @param context a hx509 context
    1173             :  * @param now the time right now, if 0, use the current time.
    1174             :  * @param cert the certificate to verify
    1175             :  * @param flags flags control the behavior
    1176             :  * @param data pointer to the encode ocsp reply
    1177             :  * @param length the length of the encode ocsp reply
    1178             :  * @param expiration return the time the OCSP will expire and need to
    1179             :  * be rechecked.
    1180             :  *
    1181             :  * @return An hx509 error code, see hx509_get_error_string().
    1182             :  *
    1183             :  * @ingroup hx509_verify
    1184             :  */
    1185             : 
    1186             : int
    1187           0 : hx509_ocsp_verify(hx509_context context,
    1188             :                   time_t now,
    1189             :                   hx509_cert cert,
    1190             :                   int flags,
    1191             :                   const void *data, size_t length,
    1192             :                   time_t *expiration)
    1193             : {
    1194           0 :     const Certificate *c = _hx509_get_cert(cert);
    1195             :     OCSPBasicOCSPResponse basic;
    1196             :     int ret;
    1197             :     size_t i;
    1198             : 
    1199           0 :     if (now == 0)
    1200           0 :         now = time(NULL);
    1201             : 
    1202           0 :     *expiration = 0;
    1203             : 
    1204           0 :     ret = parse_ocsp_basic(data, length, &basic);
    1205           0 :     if (ret) {
    1206           0 :         hx509_set_error_string(context, 0, ret,
    1207             :                                "Failed to parse OCSP response");
    1208           0 :         return ret;
    1209             :     }
    1210             : 
    1211           0 :     for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
    1212             : 
    1213           0 :         ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
    1214           0 :                                &c->tbsCertificate.serialNumber);
    1215           0 :         if (ret != 0)
    1216           0 :             continue;
    1217             : 
    1218             :         /* verify issuer hashes hash */
    1219           0 :         ret = _hx509_verify_signature(context,
    1220             :                                       NULL,
    1221           0 :                                       &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
    1222             :                                       &c->tbsCertificate.issuer._save,
    1223           0 :                                       &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
    1224           0 :         if (ret != 0)
    1225           0 :             continue;
    1226             : 
    1227           0 :         switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
    1228           0 :         case choice_OCSPCertStatus_good:
    1229           0 :             break;
    1230           0 :         case choice_OCSPCertStatus_revoked:
    1231             :         case choice_OCSPCertStatus_unknown:
    1232           0 :             continue;
    1233             :         }
    1234             : 
    1235             :         /* don't allow the update to be in the future */
    1236           0 :         if (basic.tbsResponseData.responses.val[i].thisUpdate >
    1237           0 :             now + context->ocsp_time_diff)
    1238           0 :             continue;
    1239             : 
    1240             :         /* don't allow the next update to be in the past */
    1241           0 :         if (basic.tbsResponseData.responses.val[i].nextUpdate) {
    1242           0 :             if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
    1243           0 :                 continue;
    1244           0 :             *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
    1245             :         } else
    1246           0 :             *expiration = now;
    1247             : 
    1248           0 :         free_OCSPBasicOCSPResponse(&basic);
    1249           0 :         return 0;
    1250             :     }
    1251             : 
    1252           0 :     free_OCSPBasicOCSPResponse(&basic);
    1253             : 
    1254             :     {
    1255             :         hx509_name name;
    1256             :         char *subject;
    1257             : 
    1258           0 :         ret = hx509_cert_get_subject(cert, &name);
    1259           0 :         if (ret) {
    1260           0 :             hx509_clear_error_string(context);
    1261           0 :             goto out;
    1262             :         }
    1263           0 :         ret = hx509_name_to_string(name, &subject);
    1264           0 :         hx509_name_free(&name);
    1265           0 :         if (ret) {
    1266           0 :             hx509_clear_error_string(context);
    1267           0 :             goto out;
    1268             :         }
    1269           0 :         hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
    1270             :                                "Certificate %s not in OCSP response "
    1271             :                                "or not good",
    1272             :                                subject);
    1273           0 :         free(subject);
    1274             :     }
    1275           0 : out:
    1276           0 :     return HX509_CERT_NOT_IN_OCSP;
    1277             : }
    1278             : 
    1279             : struct hx509_crl {
    1280             :     hx509_certs revoked;
    1281             :     time_t expire;
    1282             : };
    1283             : 
    1284             : /**
    1285             :  * Create a CRL context. Use hx509_crl_free() to free the CRL context.
    1286             :  *
    1287             :  * @param context a hx509 context.
    1288             :  * @param crl return pointer to a newly allocated CRL context.
    1289             :  *
    1290             :  * @return An hx509 error code, see hx509_get_error_string().
    1291             :  *
    1292             :  * @ingroup hx509_verify
    1293             :  */
    1294             : 
    1295             : int
    1296           0 : hx509_crl_alloc(hx509_context context, hx509_crl *crl)
    1297             : {
    1298             :     int ret;
    1299             : 
    1300           0 :     *crl = calloc(1, sizeof(**crl));
    1301           0 :     if (*crl == NULL) {
    1302           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1303           0 :         return ENOMEM;
    1304             :     }
    1305             : 
    1306           0 :     ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
    1307           0 :     if (ret) {
    1308           0 :         free(*crl);
    1309           0 :         *crl = NULL;
    1310           0 :         return ret;
    1311             :     }
    1312           0 :     (*crl)->expire = 0;
    1313           0 :     return ret;
    1314             : }
    1315             : 
    1316             : /**
    1317             :  * Add revoked certificate to an CRL context.
    1318             :  *
    1319             :  * @param context a hx509 context.
    1320             :  * @param crl the CRL to add the revoked certificate to.
    1321             :  * @param certs keyset of certificate to revoke.
    1322             :  *
    1323             :  * @return An hx509 error code, see hx509_get_error_string().
    1324             :  *
    1325             :  * @ingroup hx509_verify
    1326             :  */
    1327             : 
    1328             : int
    1329           0 : hx509_crl_add_revoked_certs(hx509_context context,
    1330             :                             hx509_crl crl,
    1331             :                             hx509_certs certs)
    1332             : {
    1333           0 :     return hx509_certs_merge(context, crl->revoked, certs);
    1334             : }
    1335             : 
    1336             : /**
    1337             :  * Set the lifetime of a CRL context.
    1338             :  *
    1339             :  * @param context a hx509 context.
    1340             :  * @param crl a CRL context
    1341             :  * @param delta delta time the certificate is valid, library adds the
    1342             :  * current time to this.
    1343             :  *
    1344             :  * @return An hx509 error code, see hx509_get_error_string().
    1345             :  *
    1346             :  * @ingroup hx509_verify
    1347             :  */
    1348             : 
    1349             : int
    1350           0 : hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
    1351             : {
    1352           0 :     crl->expire = time(NULL) + delta;
    1353           0 :     return 0;
    1354             : }
    1355             : 
    1356             : /**
    1357             :  * Free a CRL context.
    1358             :  *
    1359             :  * @param context a hx509 context.
    1360             :  * @param crl a CRL context to free.
    1361             :  *
    1362             :  * @ingroup hx509_verify
    1363             :  */
    1364             : 
    1365             : void
    1366           0 : hx509_crl_free(hx509_context context, hx509_crl *crl)
    1367             : {
    1368           0 :     if (*crl == NULL)
    1369           0 :         return;
    1370           0 :     hx509_certs_free(&(*crl)->revoked);
    1371           0 :     memset(*crl, 0, sizeof(**crl));
    1372           0 :     free(*crl);
    1373           0 :     *crl = NULL;
    1374             : }
    1375             : 
    1376             : static int
    1377           0 : add_revoked(hx509_context context, void *ctx, hx509_cert cert)
    1378             : {
    1379           0 :     TBSCRLCertList *c = ctx;
    1380             :     unsigned int num;
    1381             :     void *ptr;
    1382             :     int ret;
    1383             : 
    1384           0 :     num = c->revokedCertificates->len;
    1385           0 :     ptr = realloc(c->revokedCertificates->val,
    1386           0 :                   (num + 1) * sizeof(c->revokedCertificates->val[0]));
    1387           0 :     if (ptr == NULL) {
    1388           0 :         hx509_clear_error_string(context);
    1389           0 :         return ENOMEM;
    1390             :     }
    1391           0 :     c->revokedCertificates->val = ptr;
    1392             : 
    1393           0 :     ret = hx509_cert_get_serialnumber(cert,
    1394           0 :                                       &c->revokedCertificates->val[num].userCertificate);
    1395           0 :     if (ret) {
    1396           0 :         hx509_clear_error_string(context);
    1397           0 :         return ret;
    1398             :     }
    1399           0 :     c->revokedCertificates->val[num].revocationDate.element =
    1400             :         choice_Time_generalTime;
    1401           0 :     c->revokedCertificates->val[num].revocationDate.u.generalTime =
    1402           0 :         time(NULL) - 3600 * 24;
    1403           0 :     c->revokedCertificates->val[num].crlEntryExtensions = NULL;
    1404             : 
    1405           0 :     c->revokedCertificates->len++;
    1406             : 
    1407           0 :     return 0;
    1408             : }
    1409             : 
    1410             : /**
    1411             :  * Sign a CRL and return an encode certificate.
    1412             :  *
    1413             :  * @param context a hx509 context.
    1414             :  * @param signer certificate to sign the CRL with
    1415             :  * @param crl the CRL to sign
    1416             :  * @param os return the signed and encoded CRL, free with
    1417             :  * free_heim_octet_string()
    1418             :  *
    1419             :  * @return An hx509 error code, see hx509_get_error_string().
    1420             :  *
    1421             :  * @ingroup hx509_verify
    1422             :  */
    1423             : 
    1424             : int
    1425           0 : hx509_crl_sign(hx509_context context,
    1426             :                hx509_cert signer,
    1427             :                hx509_crl crl,
    1428             :                heim_octet_string *os)
    1429             : {
    1430           0 :     const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg;
    1431             :     CRLCertificateList c;
    1432             :     size_t size;
    1433             :     int ret;
    1434             :     hx509_private_key signerkey;
    1435             : 
    1436           0 :     memset(&c, 0, sizeof(c));
    1437             : 
    1438           0 :     signerkey = _hx509_cert_private_key(signer);
    1439           0 :     if (signerkey == NULL) {
    1440           0 :         ret = HX509_PRIVATE_KEY_MISSING;
    1441           0 :         hx509_set_error_string(context, 0, ret,
    1442             :                                "Private key missing for CRL signing");
    1443           0 :         return ret;
    1444             :     }
    1445             : 
    1446           0 :     c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
    1447           0 :     if (c.tbsCertList.version == NULL) {
    1448           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1449           0 :         return ENOMEM;
    1450             :     }
    1451             : 
    1452           0 :     *c.tbsCertList.version = 1;
    1453             : 
    1454           0 :     ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
    1455           0 :     if (ret) {
    1456           0 :         hx509_clear_error_string(context);
    1457           0 :         goto out;
    1458             :     }
    1459             : 
    1460           0 :     ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
    1461             :                     &c.tbsCertList.issuer);
    1462           0 :     if (ret) {
    1463           0 :         hx509_clear_error_string(context);
    1464           0 :         goto out;
    1465             :     }
    1466             : 
    1467           0 :     c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
    1468           0 :     c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
    1469             : 
    1470           0 :     c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
    1471           0 :     if (c.tbsCertList.nextUpdate == NULL) {
    1472           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1473           0 :         ret = ENOMEM;
    1474           0 :         goto out;
    1475             :     }
    1476             : 
    1477             :     {
    1478           0 :         time_t next = crl->expire;
    1479           0 :         if (next == 0)
    1480           0 :             next = time(NULL) + 24 * 3600 * 365;
    1481             : 
    1482           0 :         c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
    1483           0 :         c.tbsCertList.nextUpdate->u.generalTime = next;
    1484             :     }
    1485             : 
    1486           0 :     c.tbsCertList.revokedCertificates =
    1487           0 :         calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
    1488           0 :     if (c.tbsCertList.revokedCertificates == NULL) {
    1489           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1490           0 :         ret = ENOMEM;
    1491           0 :         goto out;
    1492             :     }
    1493           0 :     c.tbsCertList.crlExtensions = NULL;
    1494             : 
    1495           0 :     ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList);
    1496           0 :     if (ret)
    1497           0 :         goto out;
    1498             : 
    1499             :     /* if not revoked certs, remove OPTIONAL entry */
    1500           0 :     if (c.tbsCertList.revokedCertificates->len == 0) {
    1501           0 :         free(c.tbsCertList.revokedCertificates);
    1502           0 :         c.tbsCertList.revokedCertificates = NULL;
    1503             :     }
    1504             : 
    1505           0 :     ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
    1506             :                        &c.tbsCertList, &size, ret);
    1507           0 :     if (ret) {
    1508           0 :         hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
    1509           0 :         goto out;
    1510             :     }
    1511           0 :     if (size != os->length)
    1512           0 :         _hx509_abort("internal ASN.1 encoder error");
    1513             : 
    1514             : 
    1515           0 :     ret = _hx509_create_signature_bitstring(context,
    1516             :                                             signerkey,
    1517             :                                             sigalg,
    1518             :                                             os,
    1519             :                                             &c.signatureAlgorithm,
    1520             :                                             &c.signatureValue);
    1521           0 :     free(os->data);
    1522           0 :     if (ret) {
    1523           0 :         hx509_set_error_string(context, 0, ret, "Failed to sign CRL");
    1524           0 :         goto out;
    1525             :     }
    1526             : 
    1527           0 :     ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
    1528             :                        &c, &size, ret);
    1529           0 :     if (ret) {
    1530           0 :         hx509_set_error_string(context, 0, ret, "failed to encode CRL");
    1531           0 :         goto out;
    1532             :     }
    1533           0 :     if (size != os->length)
    1534           0 :         _hx509_abort("internal ASN.1 encoder error");
    1535             : 
    1536           0 :     free_CRLCertificateList(&c);
    1537             : 
    1538           0 :     return 0;
    1539             : 
    1540           0 : out:
    1541           0 :     free_CRLCertificateList(&c);
    1542           0 :     return ret;
    1543             : }

Generated by: LCOV version 1.13