Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/hx509/revoke.c
34879 views
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
hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
96
{
97
*ctx = calloc(1, sizeof(**ctx));
98
if (*ctx == NULL)
99
return ENOMEM;
100
101
(*ctx)->ref = 1;
102
(*ctx)->crls.len = 0;
103
(*ctx)->crls.val = NULL;
104
(*ctx)->ocsps.len = 0;
105
(*ctx)->ocsps.val = NULL;
106
107
return 0;
108
}
109
110
hx509_revoke_ctx
111
_hx509_revoke_ref(hx509_revoke_ctx ctx)
112
{
113
if (ctx == NULL)
114
return NULL;
115
if (ctx->ref == 0)
116
_hx509_abort("revoke ctx refcount == 0 on ref");
117
ctx->ref++;
118
if (ctx->ref == UINT_MAX)
119
_hx509_abort("revoke ctx refcount == UINT_MAX on ref");
120
return ctx;
121
}
122
123
static void
124
free_ocsp(struct revoke_ocsp *ocsp)
125
{
126
free(ocsp->path);
127
free_OCSPBasicOCSPResponse(&ocsp->ocsp);
128
hx509_certs_free(&ocsp->certs);
129
hx509_cert_free(ocsp->signer);
130
}
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
hx509_revoke_free(hx509_revoke_ctx *ctx)
142
{
143
size_t i ;
144
145
if (ctx == NULL || *ctx == NULL)
146
return;
147
148
if ((*ctx)->ref == 0)
149
_hx509_abort("revoke ctx refcount == 0 on free");
150
if (--(*ctx)->ref > 0)
151
return;
152
153
for (i = 0; i < (*ctx)->crls.len; i++) {
154
free((*ctx)->crls.val[i].path);
155
free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
156
}
157
158
for (i = 0; i < (*ctx)->ocsps.len; i++)
159
free_ocsp(&(*ctx)->ocsps.val[i]);
160
free((*ctx)->ocsps.val);
161
162
free((*ctx)->crls.val);
163
164
memset(*ctx, 0, sizeof(**ctx));
165
free(*ctx);
166
*ctx = NULL;
167
}
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
{
176
hx509_cert signer = NULL;
177
hx509_query q;
178
int ret;
179
180
_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
q.match = HX509_QUERY_MATCH_ISSUER_NAME;
189
q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer;
190
191
switch(ocsp->ocsp.tbsResponseData.responderID.element) {
192
case choice_OCSPResponderID_byName:
193
q.match |= HX509_QUERY_MATCH_SUBJECT_NAME;
194
q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName;
195
break;
196
case choice_OCSPResponderID_byKey:
197
q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1;
198
q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey;
199
break;
200
}
201
202
ret = hx509_certs_find(context, certs, &q, &signer);
203
if (ret && ocsp->certs)
204
ret = hx509_certs_find(context, ocsp->certs, &q, &signer);
205
if (ret)
206
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
if (hx509_cert_cmp(signer, parent) != 0) {
214
Certificate *p = _hx509_get_cert(parent);
215
Certificate *s = _hx509_get_cert(signer);
216
217
ret = _hx509_cert_is_parent_cmp(s, p, 0);
218
if (ret != 0) {
219
ret = HX509_PARENT_NOT_CA;
220
hx509_set_error_string(context, 0, ret, "Revoke OCSP signer is "
221
"doesn't have CA as signer certificate");
222
goto out;
223
}
224
225
ret = _hx509_verify_signature_bitstring(context,
226
parent,
227
&s->signatureAlgorithm,
228
&s->tbsCertificate._save,
229
&s->signatureValue);
230
if (ret) {
231
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
232
"OCSP signer signature invalid");
233
goto out;
234
}
235
236
ret = hx509_cert_check_eku(context, signer,
237
&asn1_oid_id_pkix_kp_OCSPSigning, 0);
238
if (ret)
239
goto out;
240
}
241
242
ret = _hx509_verify_signature_bitstring(context,
243
signer,
244
&ocsp->ocsp.signatureAlgorithm,
245
&ocsp->ocsp.tbsResponseData._save,
246
&ocsp->ocsp.signature);
247
if (ret) {
248
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
249
"OCSP signature invalid");
250
goto out;
251
}
252
253
ocsp->signer = signer;
254
signer = NULL;
255
out:
256
if (signer)
257
hx509_cert_free(signer);
258
259
return ret;
260
}
261
262
/*
263
*
264
*/
265
266
static int
267
parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
268
{
269
OCSPResponse resp;
270
size_t size;
271
int ret;
272
273
memset(basic, 0, sizeof(*basic));
274
275
ret = decode_OCSPResponse(data, length, &resp, &size);
276
if (ret)
277
return ret;
278
if (length != size) {
279
free_OCSPResponse(&resp);
280
return ASN1_EXTRA_DATA;
281
}
282
283
switch (resp.responseStatus) {
284
case successful:
285
break;
286
default:
287
free_OCSPResponse(&resp);
288
return HX509_REVOKE_WRONG_DATA;
289
}
290
291
if (resp.responseBytes == NULL) {
292
free_OCSPResponse(&resp);
293
return EINVAL;
294
}
295
296
ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
297
&asn1_oid_id_pkix_ocsp_basic);
298
if (ret != 0) {
299
free_OCSPResponse(&resp);
300
return HX509_REVOKE_WRONG_DATA;
301
}
302
303
ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
304
resp.responseBytes->response.length,
305
basic,
306
&size);
307
if (ret) {
308
free_OCSPResponse(&resp);
309
return ret;
310
}
311
if (size != resp.responseBytes->response.length) {
312
free_OCSPResponse(&resp);
313
free_OCSPBasicOCSPResponse(basic);
314
return ASN1_EXTRA_DATA;
315
}
316
free_OCSPResponse(&resp);
317
318
return 0;
319
}
320
321
/*
322
*
323
*/
324
325
static int
326
load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
327
{
328
OCSPBasicOCSPResponse basic;
329
hx509_certs certs = NULL;
330
size_t length;
331
struct stat sb;
332
void *data;
333
int ret;
334
335
ret = rk_undumpdata(ocsp->path, &data, &length);
336
if (ret)
337
return ret;
338
339
ret = stat(ocsp->path, &sb);
340
if (ret)
341
return errno;
342
343
ret = parse_ocsp_basic(data, length, &basic);
344
rk_xfree(data);
345
if (ret) {
346
hx509_set_error_string(context, 0, ret,
347
"Failed to parse OCSP response");
348
return ret;
349
}
350
351
if (basic.certs) {
352
size_t i;
353
354
ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
355
NULL, &certs);
356
if (ret) {
357
free_OCSPBasicOCSPResponse(&basic);
358
return ret;
359
}
360
361
for (i = 0; i < basic.certs->len; i++) {
362
hx509_cert c;
363
364
ret = hx509_cert_init(context, &basic.certs->val[i], &c);
365
if (ret)
366
continue;
367
368
ret = hx509_certs_add(context, certs, c);
369
hx509_cert_free(c);
370
if (ret)
371
continue;
372
}
373
}
374
375
ocsp->last_modfied = sb.st_mtime;
376
377
free_OCSPBasicOCSPResponse(&ocsp->ocsp);
378
hx509_certs_free(&ocsp->certs);
379
hx509_cert_free(ocsp->signer);
380
381
ocsp->ocsp = basic;
382
ocsp->certs = certs;
383
ocsp->signer = NULL;
384
385
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
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
if (strncmp(path, "FILE:", 5) != 0) {
410
hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
411
"unsupport type in %s", path);
412
return HX509_UNSUPPORTED_OPERATION;
413
}
414
415
path += 5;
416
417
for (i = 0; i < ctx->ocsps.len; i++) {
418
if (strcmp(ctx->ocsps.val[0].path, path) == 0)
419
return 0;
420
}
421
422
data = realloc(ctx->ocsps.val,
423
(ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
424
if (data == NULL) {
425
hx509_clear_error_string(context);
426
return ENOMEM;
427
}
428
429
ctx->ocsps.val = data;
430
431
memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
432
sizeof(ctx->ocsps.val[0]));
433
434
ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
435
if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
436
hx509_clear_error_string(context);
437
return ENOMEM;
438
}
439
440
ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
441
if (ret) {
442
free(ctx->ocsps.val[ctx->ocsps.len].path);
443
return ret;
444
}
445
ctx->ocsps.len++;
446
447
return ret;
448
}
449
450
/*
451
*
452
*/
453
454
static int
455
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
t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
468
if (t > time_now) {
469
hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
470
"CRL used before time");
471
return HX509_CRL_USED_BEFORE_TIME;
472
}
473
474
if (crl->tbsCertList.nextUpdate == NULL) {
475
hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
476
"CRL missing nextUpdate");
477
return HX509_CRL_INVALID_FORMAT;
478
}
479
480
t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
481
if (t < time_now) {
482
hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
483
"CRL used after time");
484
return HX509_CRL_USED_AFTER_TIME;
485
}
486
487
_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
if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
494
signer = hx509_cert_ref(parent);
495
} else {
496
q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
497
q.match |= HX509_QUERY_KU_CRLSIGN;
498
q.subject_name = &crl->tbsCertList.issuer;
499
500
ret = hx509_certs_find(context, certs, &q, &signer);
501
if (ret) {
502
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
503
"Failed to find certificate for CRL");
504
return ret;
505
}
506
}
507
508
ret = _hx509_verify_signature_bitstring(context,
509
signer,
510
&crl->signatureAlgorithm,
511
&crl->tbsCertList._save,
512
&crl->signatureValue);
513
if (ret) {
514
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
515
"CRL signature invalid");
516
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
while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
526
hx509_cert crl_parent;
527
528
_hx509_query_clear(&q);
529
530
q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
531
q.match |= HX509_QUERY_KU_CRLSIGN;
532
q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
533
534
ret = hx509_certs_find(context, certs, &q, &crl_parent);
535
if (ret) {
536
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
537
"Failed to find parent of CRL signer");
538
goto out;
539
}
540
541
ret = hx509_revoke_verify(context,
542
ctx,
543
certs,
544
time_now,
545
signer,
546
crl_parent);
547
hx509_cert_free(signer);
548
signer = crl_parent;
549
if (ret) {
550
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
551
"Failed to verify revoke "
552
"status of CRL signer");
553
goto out;
554
}
555
}
556
557
out:
558
hx509_cert_free(signer);
559
560
return ret;
561
}
562
563
static int
564
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
memset(crl, 0, sizeof(*crl));
572
573
ret = rk_undumpdata(path, &data, &length);
574
if (ret)
575
return ret;
576
577
ret = stat(path, &sb);
578
if (ret)
579
return errno;
580
581
*t = sb.st_mtime;
582
583
ret = decode_CRLCertificateList(data, length, crl, &size);
584
rk_xfree(data);
585
if (ret)
586
return ret;
587
588
/* check signature is aligned */
589
if (crl->signatureValue.length & 7) {
590
free_CRLCertificateList(crl);
591
return HX509_CRYPTO_SIG_INVALID_FORMAT;
592
}
593
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
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
if (strncmp(path, "FILE:", 5) != 0) {
618
hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
619
"unsupport type in %s", path);
620
return HX509_UNSUPPORTED_OPERATION;
621
}
622
623
624
path += 5;
625
626
for (i = 0; i < ctx->crls.len; i++) {
627
if (strcmp(ctx->crls.val[0].path, path) == 0)
628
return 0;
629
}
630
631
data = realloc(ctx->crls.val,
632
(ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
633
if (data == NULL) {
634
hx509_clear_error_string(context);
635
return ENOMEM;
636
}
637
ctx->crls.val = data;
638
639
memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
640
641
ctx->crls.val[ctx->crls.len].path = strdup(path);
642
if (ctx->crls.val[ctx->crls.len].path == NULL) {
643
hx509_clear_error_string(context);
644
return ENOMEM;
645
}
646
647
ret = load_crl(path,
648
&ctx->crls.val[ctx->crls.len].last_modfied,
649
&ctx->crls.val[ctx->crls.len].crl);
650
if (ret) {
651
free(ctx->crls.val[ctx->crls.len].path);
652
return ret;
653
}
654
655
ctx->crls.len++;
656
657
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
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
const Certificate *c = _hx509_get_cert(cert);
687
const Certificate *p = _hx509_get_cert(parent_cert);
688
unsigned long i, j, k;
689
int ret;
690
691
hx509_clear_error_string(context);
692
693
for (i = 0; i < ctx->ocsps.len; i++) {
694
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
ret = stat(ocsp->path, &sb);
701
if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
702
ret = load_ocsp(context, ocsp);
703
if (ret)
704
continue;
705
}
706
707
/* verify signature in ocsp if not already done */
708
if (ocsp->signer == NULL) {
709
ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
710
if (ret)
711
continue;
712
}
713
714
for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
715
heim_octet_string os;
716
717
ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
718
&c->tbsCertificate.serialNumber);
719
if (ret != 0)
720
continue;
721
722
/* verify issuer hashes hash */
723
ret = _hx509_verify_signature(context,
724
NULL,
725
&ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
726
&c->tbsCertificate.issuer._save,
727
&ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
728
if (ret != 0)
729
continue;
730
731
os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
732
os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
733
734
ret = _hx509_verify_signature(context,
735
NULL,
736
&ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
737
&os,
738
&ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
739
if (ret != 0)
740
continue;
741
742
switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
743
case choice_OCSPCertStatus_good:
744
break;
745
case choice_OCSPCertStatus_revoked:
746
hx509_set_error_string(context, 0,
747
HX509_CERT_REVOKED,
748
"Certificate revoked by issuer in OCSP");
749
return HX509_CERT_REVOKED;
750
case choice_OCSPCertStatus_unknown:
751
continue;
752
}
753
754
/* don't allow the update to be in the future */
755
if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
756
now + context->ocsp_time_diff)
757
continue;
758
759
/* don't allow the next update to be in the past */
760
if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
761
if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
762
continue;
763
} /* else should force a refetch, but can we ? */
764
765
return 0;
766
}
767
}
768
769
for (i = 0; i < ctx->crls.len; i++) {
770
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
ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
776
&crl->crl.tbsCertList.issuer, &diff);
777
if (ret || diff)
778
continue;
779
780
ret = stat(crl->path, &sb);
781
if (ret == 0 && crl->last_modfied != sb.st_mtime) {
782
CRLCertificateList cl;
783
784
ret = load_crl(crl->path, &crl->last_modfied, &cl);
785
if (ret == 0) {
786
free_CRLCertificateList(&crl->crl);
787
crl->crl = cl;
788
crl->verified = 0;
789
crl->failed_verify = 0;
790
}
791
}
792
if (crl->failed_verify)
793
continue;
794
795
/* verify signature in crl if not already done */
796
if (crl->verified == 0) {
797
ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
798
if (ret) {
799
crl->failed_verify = 1;
800
continue;
801
}
802
crl->verified = 1;
803
}
804
805
if (crl->crl.tbsCertList.crlExtensions) {
806
for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
807
if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
808
hx509_set_error_string(context, 0,
809
HX509_CRL_UNKNOWN_EXTENSION,
810
"Unknown CRL extension");
811
return HX509_CRL_UNKNOWN_EXTENSION;
812
}
813
}
814
}
815
816
if (crl->crl.tbsCertList.revokedCertificates == NULL)
817
return 0;
818
819
/* check if cert is in crl */
820
for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
821
time_t t;
822
823
ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
824
&c->tbsCertificate.serialNumber);
825
if (ret != 0)
826
continue;
827
828
t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
829
if (t > now)
830
continue;
831
832
if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
833
for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
834
if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
835
return HX509_CRL_UNKNOWN_EXTENSION;
836
837
hx509_set_error_string(context, 0,
838
HX509_CERT_REVOKED,
839
"Certificate revoked by issuer in CRL");
840
return HX509_CERT_REVOKED;
841
}
842
843
return 0;
844
}
845
846
847
if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
848
return 0;
849
hx509_set_error_string(context, HX509_ERROR_APPEND,
850
HX509_REVOKE_STATUS_MISSING,
851
"No revoke status found for "
852
"certificates");
853
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
add_to_req(hx509_context context, void *ptr, hx509_cert cert)
865
{
866
struct ocsp_add_ctx *ctx = ptr;
867
OCSPInnerRequest *one;
868
hx509_cert parent = NULL;
869
Certificate *p, *c = _hx509_get_cert(cert);
870
heim_octet_string os;
871
int ret;
872
hx509_query q;
873
void *d;
874
875
d = realloc(ctx->req->requestList.val,
876
sizeof(ctx->req->requestList.val[0]) *
877
(ctx->req->requestList.len + 1));
878
if (d == NULL)
879
return ENOMEM;
880
ctx->req->requestList.val = d;
881
882
one = &ctx->req->requestList.val[ctx->req->requestList.len];
883
memset(one, 0, sizeof(*one));
884
885
_hx509_query_clear(&q);
886
887
q.match |= HX509_QUERY_FIND_ISSUER_CERT;
888
q.subject = c;
889
890
ret = hx509_certs_find(context, ctx->certs, &q, &parent);
891
if (ret)
892
goto out;
893
894
if (ctx->parent) {
895
if (hx509_cert_cmp(ctx->parent, parent) != 0) {
896
ret = HX509_REVOKE_NOT_SAME_PARENT;
897
hx509_set_error_string(context, 0, ret,
898
"Not same parent certifate as "
899
"last certificate in request");
900
goto out;
901
}
902
} else
903
ctx->parent = hx509_cert_ref(parent);
904
905
p = _hx509_get_cert(parent);
906
907
ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
908
if (ret)
909
goto out;
910
911
ret = _hx509_create_signature(context,
912
NULL,
913
&one->reqCert.hashAlgorithm,
914
&c->tbsCertificate.issuer._save,
915
NULL,
916
&one->reqCert.issuerNameHash);
917
if (ret)
918
goto out;
919
920
os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
921
os.length =
922
p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
923
924
ret = _hx509_create_signature(context,
925
NULL,
926
&one->reqCert.hashAlgorithm,
927
&os,
928
NULL,
929
&one->reqCert.issuerKeyHash);
930
if (ret)
931
goto out;
932
933
ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
934
&one->reqCert.serialNumber);
935
if (ret)
936
goto out;
937
938
ctx->req->requestList.len++;
939
out:
940
hx509_cert_free(parent);
941
if (ret) {
942
free_OCSPInnerRequest(one);
943
memset(one, 0, sizeof(*one));
944
}
945
946
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
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
memset(&req, 0, sizeof(req));
982
983
if (digest == NULL)
984
digest = _hx509_crypto_default_digest_alg;
985
986
ctx.req = &req.tbsRequest;
987
ctx.certs = pool;
988
ctx.digest = digest;
989
ctx.parent = NULL;
990
991
ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx);
992
hx509_cert_free(ctx.parent);
993
if (ret)
994
goto out;
995
996
if (nonce) {
997
req.tbsRequest.requestExtensions =
998
calloc(1, sizeof(*req.tbsRequest.requestExtensions));
999
if (req.tbsRequest.requestExtensions == NULL) {
1000
ret = ENOMEM;
1001
goto out;
1002
}
1003
1004
es = req.tbsRequest.requestExtensions;
1005
1006
es->val = calloc(es->len, sizeof(es->val[0]));
1007
if (es->val == NULL) {
1008
ret = ENOMEM;
1009
goto out;
1010
}
1011
es->len = 1;
1012
ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID);
1013
if (ret) {
1014
free_OCSPRequest(&req);
1015
return ret;
1016
}
1017
1018
es->val[0].extnValue.data = malloc(10);
1019
if (es->val[0].extnValue.data == NULL) {
1020
ret = ENOMEM;
1021
goto out;
1022
}
1023
es->val[0].extnValue.length = 10;
1024
1025
ret = RAND_bytes(es->val[0].extnValue.data,
1026
es->val[0].extnValue.length);
1027
if (ret != 1) {
1028
ret = HX509_CRYPTO_INTERNAL_ERROR;
1029
goto out;
1030
}
1031
ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
1032
if (ret) {
1033
ret = ENOMEM;
1034
goto out;
1035
}
1036
}
1037
1038
ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
1039
&req, &size, ret);
1040
free_OCSPRequest(&req);
1041
if (ret)
1042
goto out;
1043
if (size != request->length)
1044
_hx509_abort("internal ASN.1 encoder error");
1045
1046
return 0;
1047
1048
out:
1049
free_OCSPRequest(&req);
1050
return ret;
1051
}
1052
1053
static char *
1054
printable_time(time_t t)
1055
{
1056
static char s[128];
1057
char *p;
1058
if ((p = ctime(&t)) == NULL)
1059
strlcpy(s, "?", sizeof(s));
1060
else {
1061
strlcpy(s, p + 4, sizeof(s));
1062
s[20] = 0;
1063
}
1064
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
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
if (out == NULL)
1087
out = stdout;
1088
1089
memset(&ocsp, 0, sizeof(ocsp));
1090
1091
ocsp.path = strdup(path);
1092
if (ocsp.path == NULL)
1093
return ENOMEM;
1094
1095
ret = load_ocsp(context, &ocsp);
1096
if (ret) {
1097
free_ocsp(&ocsp);
1098
return ret;
1099
}
1100
1101
fprintf(out, "signer: ");
1102
1103
switch(ocsp.ocsp.tbsResponseData.responderID.element) {
1104
case choice_OCSPResponderID_byName: {
1105
hx509_name n;
1106
char *s;
1107
_hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
1108
hx509_name_to_string(n, &s);
1109
hx509_name_free(&n);
1110
fprintf(out, " byName: %s\n", s);
1111
free(s);
1112
break;
1113
}
1114
case choice_OCSPResponderID_byKey: {
1115
char *s;
1116
hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
1117
ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
1118
&s);
1119
fprintf(out, " byKey: %s\n", s);
1120
free(s);
1121
break;
1122
}
1123
default:
1124
_hx509_abort("choice_OCSPResponderID unknown");
1125
break;
1126
}
1127
1128
fprintf(out, "producedAt: %s\n",
1129
printable_time(ocsp.ocsp.tbsResponseData.producedAt));
1130
1131
fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
1132
1133
for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
1134
const char *status;
1135
switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
1136
case choice_OCSPCertStatus_good:
1137
status = "good";
1138
break;
1139
case choice_OCSPCertStatus_revoked:
1140
status = "revoked";
1141
break;
1142
case choice_OCSPCertStatus_unknown:
1143
status = "unknown";
1144
break;
1145
default:
1146
status = "element unknown";
1147
}
1148
1149
fprintf(out, "\t%zu. status: %s\n", i, status);
1150
1151
fprintf(out, "\tthisUpdate: %s\n",
1152
printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1153
if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
1154
fprintf(out, "\tproducedAt: %s\n",
1155
printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1156
1157
}
1158
1159
fprintf(out, "appended certs:\n");
1160
if (ocsp.certs)
1161
ret = hx509_certs_iter_f(context, ocsp.certs, hx509_ci_print_names, out);
1162
1163
free_ocsp(&ocsp);
1164
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
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
const Certificate *c = _hx509_get_cert(cert);
1195
OCSPBasicOCSPResponse basic;
1196
int ret;
1197
size_t i;
1198
1199
if (now == 0)
1200
now = time(NULL);
1201
1202
*expiration = 0;
1203
1204
ret = parse_ocsp_basic(data, length, &basic);
1205
if (ret) {
1206
hx509_set_error_string(context, 0, ret,
1207
"Failed to parse OCSP response");
1208
return ret;
1209
}
1210
1211
for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
1212
1213
ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
1214
&c->tbsCertificate.serialNumber);
1215
if (ret != 0)
1216
continue;
1217
1218
/* verify issuer hashes hash */
1219
ret = _hx509_verify_signature(context,
1220
NULL,
1221
&basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
1222
&c->tbsCertificate.issuer._save,
1223
&basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
1224
if (ret != 0)
1225
continue;
1226
1227
switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
1228
case choice_OCSPCertStatus_good:
1229
break;
1230
case choice_OCSPCertStatus_revoked:
1231
case choice_OCSPCertStatus_unknown:
1232
continue;
1233
}
1234
1235
/* don't allow the update to be in the future */
1236
if (basic.tbsResponseData.responses.val[i].thisUpdate >
1237
now + context->ocsp_time_diff)
1238
continue;
1239
1240
/* don't allow the next update to be in the past */
1241
if (basic.tbsResponseData.responses.val[i].nextUpdate) {
1242
if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
1243
continue;
1244
*expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
1245
} else
1246
*expiration = now;
1247
1248
free_OCSPBasicOCSPResponse(&basic);
1249
return 0;
1250
}
1251
1252
free_OCSPBasicOCSPResponse(&basic);
1253
1254
{
1255
hx509_name name;
1256
char *subject;
1257
1258
ret = hx509_cert_get_subject(cert, &name);
1259
if (ret) {
1260
hx509_clear_error_string(context);
1261
goto out;
1262
}
1263
ret = hx509_name_to_string(name, &subject);
1264
hx509_name_free(&name);
1265
if (ret) {
1266
hx509_clear_error_string(context);
1267
goto out;
1268
}
1269
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
free(subject);
1274
}
1275
out:
1276
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
hx509_crl_alloc(hx509_context context, hx509_crl *crl)
1297
{
1298
int ret;
1299
1300
*crl = calloc(1, sizeof(**crl));
1301
if (*crl == NULL) {
1302
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1303
return ENOMEM;
1304
}
1305
1306
ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
1307
if (ret) {
1308
free(*crl);
1309
*crl = NULL;
1310
return ret;
1311
}
1312
(*crl)->expire = 0;
1313
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
hx509_crl_add_revoked_certs(hx509_context context,
1330
hx509_crl crl,
1331
hx509_certs certs)
1332
{
1333
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
hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
1351
{
1352
crl->expire = time(NULL) + delta;
1353
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
hx509_crl_free(hx509_context context, hx509_crl *crl)
1367
{
1368
if (*crl == NULL)
1369
return;
1370
hx509_certs_free(&(*crl)->revoked);
1371
memset(*crl, 0, sizeof(**crl));
1372
free(*crl);
1373
*crl = NULL;
1374
}
1375
1376
static int
1377
add_revoked(hx509_context context, void *ctx, hx509_cert cert)
1378
{
1379
TBSCRLCertList *c = ctx;
1380
unsigned int num;
1381
void *ptr;
1382
int ret;
1383
1384
num = c->revokedCertificates->len;
1385
ptr = realloc(c->revokedCertificates->val,
1386
(num + 1) * sizeof(c->revokedCertificates->val[0]));
1387
if (ptr == NULL) {
1388
hx509_clear_error_string(context);
1389
return ENOMEM;
1390
}
1391
c->revokedCertificates->val = ptr;
1392
1393
ret = hx509_cert_get_serialnumber(cert,
1394
&c->revokedCertificates->val[num].userCertificate);
1395
if (ret) {
1396
hx509_clear_error_string(context);
1397
return ret;
1398
}
1399
c->revokedCertificates->val[num].revocationDate.element =
1400
choice_Time_generalTime;
1401
c->revokedCertificates->val[num].revocationDate.u.generalTime =
1402
time(NULL) - 3600 * 24;
1403
c->revokedCertificates->val[num].crlEntryExtensions = NULL;
1404
1405
c->revokedCertificates->len++;
1406
1407
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
hx509_crl_sign(hx509_context context,
1426
hx509_cert signer,
1427
hx509_crl crl,
1428
heim_octet_string *os)
1429
{
1430
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
memset(&c, 0, sizeof(c));
1437
1438
signerkey = _hx509_cert_private_key(signer);
1439
if (signerkey == NULL) {
1440
ret = HX509_PRIVATE_KEY_MISSING;
1441
hx509_set_error_string(context, 0, ret,
1442
"Private key missing for CRL signing");
1443
return ret;
1444
}
1445
1446
c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
1447
if (c.tbsCertList.version == NULL) {
1448
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1449
return ENOMEM;
1450
}
1451
1452
*c.tbsCertList.version = 1;
1453
1454
ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
1455
if (ret) {
1456
hx509_clear_error_string(context);
1457
goto out;
1458
}
1459
1460
ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
1461
&c.tbsCertList.issuer);
1462
if (ret) {
1463
hx509_clear_error_string(context);
1464
goto out;
1465
}
1466
1467
c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
1468
c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
1469
1470
c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
1471
if (c.tbsCertList.nextUpdate == NULL) {
1472
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1473
ret = ENOMEM;
1474
goto out;
1475
}
1476
1477
{
1478
time_t next = crl->expire;
1479
if (next == 0)
1480
next = time(NULL) + 24 * 3600 * 365;
1481
1482
c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
1483
c.tbsCertList.nextUpdate->u.generalTime = next;
1484
}
1485
1486
c.tbsCertList.revokedCertificates =
1487
calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
1488
if (c.tbsCertList.revokedCertificates == NULL) {
1489
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1490
ret = ENOMEM;
1491
goto out;
1492
}
1493
c.tbsCertList.crlExtensions = NULL;
1494
1495
ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList);
1496
if (ret)
1497
goto out;
1498
1499
/* if not revoked certs, remove OPTIONAL entry */
1500
if (c.tbsCertList.revokedCertificates->len == 0) {
1501
free(c.tbsCertList.revokedCertificates);
1502
c.tbsCertList.revokedCertificates = NULL;
1503
}
1504
1505
ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
1506
&c.tbsCertList, &size, ret);
1507
if (ret) {
1508
hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
1509
goto out;
1510
}
1511
if (size != os->length)
1512
_hx509_abort("internal ASN.1 encoder error");
1513
1514
1515
ret = _hx509_create_signature_bitstring(context,
1516
signerkey,
1517
sigalg,
1518
os,
1519
&c.signatureAlgorithm,
1520
&c.signatureValue);
1521
free(os->data);
1522
if (ret) {
1523
hx509_set_error_string(context, 0, ret, "Failed to sign CRL");
1524
goto out;
1525
}
1526
1527
ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
1528
&c, &size, ret);
1529
if (ret) {
1530
hx509_set_error_string(context, 0, ret, "failed to encode CRL");
1531
goto out;
1532
}
1533
if (size != os->length)
1534
_hx509_abort("internal ASN.1 encoder error");
1535
1536
free_CRLCertificateList(&c);
1537
1538
return 0;
1539
1540
out:
1541
free_CRLCertificateList(&c);
1542
return ret;
1543
}
1544
1545