Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/heimdal/lib/hx509/revoke.c
Line
Count
Source
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
hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
96
0
{
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
0
}
109
110
HX509_LIB_FUNCTION hx509_revoke_ctx HX509_LIB_CALL
111
_hx509_revoke_ref(hx509_revoke_ctx ctx)
112
0
{
113
0
    if (ctx == NULL)
114
0
  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
0
}
122
123
static void
124
free_ocsp(struct revoke_ocsp *ocsp)
125
0
{
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
hx509_revoke_free(hx509_revoke_ctx *ctx)
142
0
{
143
0
    size_t i ;
144
145
0
    if (ctx == NULL || *ctx == NULL)
146
0
  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
0
    }
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
0
}
168
169
static int
170
verify_ocsp(hx509_context context,
171
      struct revoke_ocsp *ocsp,
172
      time_t time_now,
173
      hx509_certs certs,
174
      hx509_cert parent)
175
0
{
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
0
    }
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
0
           "doesn't have CA as signer certificate");
224
0
      goto out;
225
0
  }
226
227
0
  ret = _hx509_verify_signature_bitstring(context,
228
0
            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
0
           "OCSP signer signature invalid");
235
0
      goto out;
236
0
  }
237
238
0
  ret = hx509_cert_check_eku(context, signer,
239
0
           &asn1_oid_id_pkix_kp_OCSPSigning, 0);
240
0
  if (ret)
241
0
      goto out;
242
0
    }
243
244
0
    ret = _hx509_verify_signature_bitstring(context,
245
0
              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
0
             "OCSP signature invalid");
252
0
  goto out;
253
0
    }
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
0
}
263
264
/*
265
 *
266
 */
267
268
static int
269
parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
270
0
{
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
0
    }
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
0
    }
292
293
0
    if (resp.responseBytes == NULL) {
294
0
  free_OCSPResponse(&resp);
295
0
  return EINVAL;
296
0
    }
297
298
0
    ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
299
0
         &asn1_oid_id_pkix_ocsp_basic);
300
0
    if (ret != 0) {
301
0
  free_OCSPResponse(&resp);
302
0
  return HX509_REVOKE_WRONG_DATA;
303
0
    }
304
305
0
    ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
306
0
               resp.responseBytes->response.length,
307
0
               basic,
308
0
               &size);
309
0
    if (ret) {
310
0
  free_OCSPResponse(&resp);
311
0
  return ret;
312
0
    }
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
0
    }
318
0
    free_OCSPResponse(&resp);
319
320
0
    return 0;
321
0
}
322
323
/*
324
 *
325
 */
326
327
static int
328
load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
329
0
{
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
0
    }
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
0
             "Failed to parse OCSP response");
352
0
  return ret;
353
0
    }
354
355
0
    if (basic.certs) {
356
0
  size_t i;
357
358
0
  ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
359
0
             NULL, &certs);
360
0
  if (ret) {
361
0
      free_OCSPBasicOCSPResponse(&basic);
362
0
      return ret;
363
0
  }
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
0
  }
377
0
    }
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
0
}
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
hx509_revoke_add_ocsp(hx509_context context,
406
          hx509_revoke_ctx ctx,
407
          const char *path)
408
0
{
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
0
             "unsupported type in %s", path);
416
0
  return HX509_UNSUPPORTED_OPERATION;
417
0
    }
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
0
    }
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
0
    }
432
433
0
    ctx->ocsps.val = data;
434
435
0
    memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
436
0
     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
0
    }
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
0
    }
449
0
    ctx->ocsps.len++;
450
451
0
    return ret;
452
0
}
453
454
/*
455
 *
456
 */
457
458
static int
459
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
0
{
466
0
    hx509_cert signer;
467
0
    hx509_query q;
468
0
    time_t t;
469
0
    int ret;
470
471
0
    t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
472
0
    if (t > time_now) {
473
0
  hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
474
0
             "CRL used before time");
475
0
  return HX509_CRL_USED_BEFORE_TIME;
476
0
    }
477
478
0
    if (crl->tbsCertList.nextUpdate == NULL) {
479
0
  hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
480
0
             "CRL missing nextUpdate");
481
0
  return HX509_CRL_INVALID_FORMAT;
482
0
    }
483
484
0
    t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
485
0
    if (t < time_now) {
486
0
  hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
487
0
             "CRL used after time");
488
0
  return HX509_CRL_USED_AFTER_TIME;
489
0
    }
490
491
0
    _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
0
    if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
498
0
  signer = hx509_cert_ref(parent);
499
0
    } 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
0
           "Failed to find certificate for CRL");
510
0
      return ret;
511
0
  }
512
0
    }
513
514
0
    ret = _hx509_verify_signature_bitstring(context,
515
0
              signer,
516
0
              &crl->signatureAlgorithm,
517
0
              &crl->tbsCertList._save,
518
0
              &crl->signatureValue);
519
0
    if (ret) {
520
0
  hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
521
0
             "CRL signature invalid");
522
0
  goto out;
523
0
    }
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
0
    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
0
           "Failed to find parent of CRL signer");
544
0
      goto out;
545
0
  }
546
547
0
  ret = hx509_revoke_verify(context,
548
0
          ctx,
549
0
          certs,
550
0
          time_now,
551
0
          signer,
552
0
          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
0
           "Failed to verify revocation "
558
0
           "status of CRL signer");
559
0
      goto out;
560
0
  }
561
0
    }
562
563
0
out:
564
0
    hx509_cert_free(signer);
565
566
0
    return ret;
567
0
}
568
569
static int
570
crl_parser(hx509_context context, const char *type,
571
     const hx509_pem_header *header,
572
     const void *data, size_t len, void *ctx)
573
0
{
574
0
    CRLCertificateList *crl = (CRLCertificateList *)ctx;
575
0
    size_t size;
576
0
    int ret;
577
578
0
    if (strcasecmp("X509 CRL", type) != 0)
579
0
  return HX509_CRYPTO_SIG_INVALID_FORMAT;
580
581
0
    ret = decode_CRLCertificateList(data, len, crl, &size);
582
0
    if (ret)
583
0
  return ret;
584
585
    /* check signature is aligned */
586
0
    if (crl->signatureValue.length & 7) {
587
0
  free_CRLCertificateList(crl);
588
0
  return HX509_CRYPTO_SIG_INVALID_FORMAT;
589
0
    }
590
591
0
    return 0;
592
0
}
593
594
static int
595
load_crl(hx509_context context, const char *path, time_t *t, CRLCertificateList *crl)
596
0
{
597
0
    struct stat sb;
598
0
    size_t length;
599
0
    void *data;
600
0
    FILE *f;
601
0
    int ret;
602
603
0
    *t = 0;
604
0
    memset(crl, 0, sizeof(*crl));
605
  
606
0
    if ((f = fopen(path, "r")) == NULL)
607
0
  return errno;
608
609
0
    rk_cloexec_file(f);
610
0
    if (fstat(fileno(f), &sb) == 0)
611
0
  *t = sb.st_mtime;
612
613
0
    ret = hx509_pem_read(context, f, crl_parser, crl);
614
0
    fclose(f);
615
616
0
    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
0
    }
625
0
    return ret;
626
0
}
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
hx509_revoke_add_crl(hx509_context context,
642
         hx509_revoke_ctx ctx,
643
         const char *path)
644
0
{
645
0
    void *data;
646
0
    size_t i;
647
0
    int ret;
648
649
0
    if (strncmp(path, "FILE:", 5) != 0) {
650
0
  hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
651
0
             "unsupported type in %s", path);
652
0
  return HX509_UNSUPPORTED_OPERATION;
653
0
    }
654
655
656
0
    path += 5;
657
658
0
    for (i = 0; i < ctx->crls.len; i++) {
659
0
  if (strcmp(ctx->crls.val[i].path, path) == 0)
660
0
      return 0;
661
0
    }
662
663
0
    data = realloc(ctx->crls.val,
664
0
       (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
665
0
    if (data == NULL) {
666
0
  hx509_clear_error_string(context);
667
0
  return ENOMEM;
668
0
    }
669
0
    ctx->crls.val = data;
670
671
0
    memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
672
673
0
    ctx->crls.val[ctx->crls.len].path = strdup(path);
674
0
    if (ctx->crls.val[ctx->crls.len].path == NULL) {
675
0
  hx509_clear_error_string(context);
676
0
  return ENOMEM;
677
0
    }
678
679
0
    ret = load_crl(context,
680
0
       path,
681
0
       &ctx->crls.val[ctx->crls.len].last_modfied,
682
0
       &ctx->crls.val[ctx->crls.len].crl);
683
0
    if (ret) {
684
0
  free(ctx->crls.val[ctx->crls.len].path);
685
0
  return ret;
686
0
    }
687
688
0
    ctx->crls.len++;
689
690
0
    return ret;
691
0
}
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
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
0
{
718
0
    const Certificate *c = _hx509_get_cert(cert);
719
0
    const Certificate *p = _hx509_get_cert(parent_cert);
720
0
    unsigned long i, j, k;
721
0
    int ret;
722
723
0
    hx509_clear_error_string(context);
724
725
0
    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
0
  }
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
0
  }
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
0
            NULL,
757
0
            &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
758
0
            &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
0
            NULL,
768
0
            &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
769
0
            &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
0
               HX509_CERT_REVOKED,
780
0
               "Certificate revoked by issuer in OCSP");
781
0
    return HX509_CERT_REVOKED;
782
0
      case choice_OCSPCertStatus_unknown:
783
0
    continue;
784
0
      }
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
0
      } /* else should force a refetch, but can we ? */
796
797
0
      return 0;
798
0
  }
799
0
    }
800
801
0
    for (i = 0; i < ctx->crls.len; i++) {
802
0
  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
0
  ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
808
0
            &crl->crl.tbsCertList.issuer, &diff);
809
0
  if (ret || diff)
810
0
      continue;
811
812
0
  ret = stat(crl->path, &sb);
813
0
  if (ret == 0 && crl->last_modfied != sb.st_mtime) {
814
0
      CRLCertificateList cl;
815
816
0
      ret = load_crl(context, crl->path, &crl->last_modfied, &cl);
817
0
      if (ret == 0) {
818
0
    free_CRLCertificateList(&crl->crl);
819
0
    crl->crl = cl;
820
0
    crl->verified = 0;
821
0
    crl->failed_verify = 0;
822
0
      }
823
0
  }
824
0
  if (crl->failed_verify)
825
0
      continue;
826
827
  /* verify signature in crl if not already done */
828
0
  if (crl->verified == 0) {
829
0
      ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
830
0
      if (ret) {
831
0
    crl->failed_verify = 1;
832
0
    continue;
833
0
      }
834
0
      crl->verified = 1;
835
0
  }
836
837
0
  if (crl->crl.tbsCertList.crlExtensions) {
838
0
      for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
839
0
    if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
840
0
        hx509_set_error_string(context, 0,
841
0
             HX509_CRL_UNKNOWN_EXTENSION,
842
0
             "Unknown CRL extension");
843
0
        return HX509_CRL_UNKNOWN_EXTENSION;
844
0
    }
845
0
      }
846
0
  }
847
848
0
  if (crl->crl.tbsCertList.revokedCertificates == NULL)
849
0
      return 0;
850
851
  /* check if cert is in crl */
852
0
  for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
853
0
      time_t t;
854
855
0
      ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
856
0
               &c->tbsCertificate.serialNumber);
857
0
      if (ret != 0)
858
0
    continue;
859
860
0
      t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
861
0
      if (t > now)
862
0
    continue;
863
864
0
      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
0
      hx509_set_error_string(context, 0,
870
0
           HX509_CERT_REVOKED,
871
0
           "Certificate revoked by issuer in CRL");
872
0
      return HX509_CERT_REVOKED;
873
0
  }
874
875
0
  return 0;
876
0
    }
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
0
         HX509_REVOKE_STATUS_MISSING,
883
0
         "No revocation status found for certificates");
884
0
    return HX509_REVOKE_STATUS_MISSING;
885
0
}
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
add_to_req(hx509_context context, void *ptr, hx509_cert cert)
896
0
{
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
0
    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
0
           "Not same parent certificate as "
930
0
           "last certificate in request");
931
0
      goto out;
932
0
  }
933
0
    } 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
0
          NULL,
944
0
          &one->reqCert.hashAlgorithm,
945
0
          &c->tbsCertificate.issuer._save,
946
0
          NULL,
947
0
          &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
0
          NULL,
957
0
          &one->reqCert.hashAlgorithm,
958
0
          &os,
959
0
          NULL,
960
0
          &one->reqCert.issuerKeyHash);
961
0
    if (ret)
962
0
  goto out;
963
964
0
    ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
965
0
               &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
0
    }
976
977
0
    return ret;
978
0
}
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
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
0
{
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
0
  }
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
0
  }
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
0
  }
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
0
  }
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
0
  }
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
0
  }
1067
0
    }
1068
1069
0
    ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
1070
0
           &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
0
}
1083
1084
static char *
1085
printable_time(time_t t)
1086
0
{
1087
0
    static char s[128];
1088
0
    char *p;
1089
0
    if ((p = ctime(&t)) == NULL)
1090
0
       strlcpy(s, "?", sizeof(s));
1091
0
    else {
1092
0
       strlcpy(s, p + 4, sizeof(s));
1093
0
       s[20] = 0;
1094
0
    }
1095
0
    return s;
1096
0
}
1097
1098
/*
1099
 *
1100
 */
1101
1102
static int
1103
print_ocsp(hx509_context context, struct revoke_ocsp *ocsp, FILE *out)
1104
0
{
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
0
    }
1121
0
    case choice_OCSPResponderID_byKey: {
1122
0
  char *s;
1123
0
  hex_encode(ocsp->ocsp.tbsResponseData.responderID.u.byKey.data,
1124
0
       ocsp->ocsp.tbsResponseData.responderID.u.byKey.length,
1125
0
       &s);
1126
0
  fprintf(out, " byKey: %s\n", s);
1127
0
  free(s);
1128
0
  break;
1129
0
    }
1130
0
    default:
1131
0
  _hx509_abort("choice_OCSPResponderID unknown");
1132
0
  break;
1133
0
    }
1134
1135
0
    fprintf(out, "producedAt: %s\n",
1136
0
      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
0
  }
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
0
    }
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
0
}
1172
     
1173
static int
1174
print_crl(hx509_context context, struct revoke_crl *crl, FILE *out)
1175
0
{
1176
0
    {
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
0
    }
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
0
}
1191
1192
1193
/*
1194
 *
1195
 */
1196
1197
HX509_LIB_FUNCTION int HX509_LIB_CALL
1198
hx509_revoke_print(hx509_context context,
1199
       hx509_revoke_ctx ctx,
1200
       FILE *out)
1201
0
{
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
0
  }
1215
0
    }
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
0
  }
1227
0
    }
1228
0
    return saved_ret;
1229
1230
0
}
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
hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
1246
0
{
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
0
    }
1264
1265
0
    ret = print_ocsp(context, &ocsp, out);
1266
1267
0
    free_ocsp(&ocsp);
1268
0
    return ret;
1269
0
}
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
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
0
{
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
0
             "Failed to parse OCSP response");
1312
0
  return ret;
1313
0
    }
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
0
              NULL,
1325
0
              &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
1326
0
              &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
0
  case choice_OCSPCertStatus_unknown:
1336
0
      continue;
1337
0
  }
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
0
  } else
1350
0
      *expiration = now;
1351
1352
0
  free_OCSPBasicOCSPResponse(&basic);
1353
0
  return 0;
1354
0
    }
1355
1356
0
    free_OCSPBasicOCSPResponse(&basic);
1357
1358
0
    {
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
0
  }
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
0
  }
1373
0
  hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
1374
0
             "Certificate %s not in OCSP response "
1375
0
             "or not good",
1376
0
             subject);
1377
0
  free(subject);
1378
0
    }
1379
0
out:
1380
0
    return HX509_CERT_NOT_IN_OCSP;
1381
0
}
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
hx509_crl_alloc(hx509_context context, hx509_crl *crl)
1401
0
{
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
0
    }
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
0
    }
1416
0
    (*crl)->expire = 0;
1417
0
    return ret;
1418
0
}
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
hx509_crl_add_revoked_certs(hx509_context context,
1434
          hx509_crl crl,
1435
          hx509_certs certs)
1436
0
{
1437
0
    return hx509_certs_merge(context, crl->revoked, certs);
1438
0
}
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
hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
1455
0
{
1456
0
    crl->expire = time(NULL) + delta;
1457
0
    return 0;
1458
0
}
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
hx509_crl_free(hx509_context context, hx509_crl *crl)
1471
0
{
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
0
}
1479
1480
static int HX509_LIB_CALL
1481
add_revoked(hx509_context context, void *ctx, hx509_cert cert)
1482
0
{
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
0
    }
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
0
    }
1503
0
    c->revokedCertificates->val[num].revocationDate.element =
1504
0
  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
0
}
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
hx509_crl_sign(hx509_context context,
1530
         hx509_cert signer,
1531
         hx509_crl crl,
1532
         heim_octet_string *os)
1533
0
{
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
0
             "Private key missing for CRL signing");
1547
0
  return ret;
1548
0
    }
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
0
    }
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
0
    }
1563
1564
0
    ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
1565
0
        &c.tbsCertList.issuer);
1566
0
    if (ret) {
1567
0
  hx509_clear_error_string(context);
1568
0
  goto out;
1569
0
    }
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
0
    }
1580
1581
0
    {
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
0
    }
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
0
    }
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
0
    }
1608
1609
0
    ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
1610
0
           &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
0
    }
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
0
              signerkey,
1621
0
              sigalg,
1622
0
              os,
1623
0
              &c.signatureAlgorithm,
1624
0
              &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
0
    }
1630
1631
0
    ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
1632
0
           &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
0
    }
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
0
}