Line data Source code
1 : /*
2 : * Copyright (c) 2006 - 2010 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 : #include "hx_locl.h"
35 :
36 : /**
37 : * @page page_ca Hx509 CA functions
38 : *
39 : * See the library functions here: @ref hx509_ca
40 : */
41 :
42 : struct hx509_ca_tbs {
43 : hx509_name subject;
44 : SubjectPublicKeyInfo spki;
45 : KeyUsage ku;
46 : ExtKeyUsage eku;
47 : GeneralNames san;
48 : CertificatePolicies cps;
49 : PolicyMappings pms;
50 : heim_integer serial;
51 : struct {
52 : unsigned int proxy:1;
53 : unsigned int ca:1;
54 : unsigned int key:1;
55 : unsigned int serial:1;
56 : unsigned int domaincontroller:1;
57 : unsigned int xUniqueID:1;
58 : } flags;
59 : time_t notBefore;
60 : time_t notAfter;
61 : HeimPkinitPrincMaxLifeSecs pkinitTicketMaxLife;
62 : int pathLenConstraint; /* both for CA and Proxy */
63 : CRLDistributionPoints crldp;
64 : heim_bit_string subjectUniqueID;
65 : heim_bit_string issuerUniqueID;
66 : AlgorithmIdentifier *sigalg;
67 : };
68 :
69 : /**
70 : * Allocate an to-be-signed certificate object that will be converted
71 : * into an certificate.
72 : *
73 : * @param context A hx509 context.
74 : * @param tbs returned to-be-signed certicate object, free with
75 : * hx509_ca_tbs_free().
76 : *
77 : * @return An hx509 error code, see hx509_get_error_string().
78 : *
79 : * @ingroup hx509_ca
80 : */
81 :
82 : HX509_LIB_FUNCTION int HX509_LIB_CALL
83 0 : hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs)
84 : {
85 0 : *tbs = calloc(1, sizeof(**tbs));
86 0 : if (*tbs == NULL)
87 0 : return ENOMEM;
88 :
89 0 : return 0;
90 : }
91 :
92 : /**
93 : * Free an To Be Signed object.
94 : *
95 : * @param tbs object to free.
96 : *
97 : * @ingroup hx509_ca
98 : */
99 :
100 : HX509_LIB_FUNCTION void HX509_LIB_CALL
101 0 : hx509_ca_tbs_free(hx509_ca_tbs *tbs)
102 : {
103 0 : if (tbs == NULL || *tbs == NULL)
104 0 : return;
105 :
106 0 : free_SubjectPublicKeyInfo(&(*tbs)->spki);
107 0 : free_CertificatePolicies(&(*tbs)->cps);
108 0 : free_PolicyMappings(&(*tbs)->pms);
109 0 : free_GeneralNames(&(*tbs)->san);
110 0 : free_ExtKeyUsage(&(*tbs)->eku);
111 0 : der_free_heim_integer(&(*tbs)->serial);
112 0 : free_CRLDistributionPoints(&(*tbs)->crldp);
113 0 : der_free_bit_string(&(*tbs)->subjectUniqueID);
114 0 : der_free_bit_string(&(*tbs)->issuerUniqueID);
115 0 : if ((*tbs)->subject)
116 0 : hx509_name_free(&(*tbs)->subject);
117 0 : if ((*tbs)->sigalg) {
118 0 : free_AlgorithmIdentifier((*tbs)->sigalg);
119 0 : free((*tbs)->sigalg);
120 : }
121 :
122 0 : memset(*tbs, 0, sizeof(**tbs));
123 0 : free(*tbs);
124 0 : *tbs = NULL;
125 : }
126 :
127 : /**
128 : * Set the absolute time when the certificate is valid from. If not
129 : * set the current time will be used.
130 : *
131 : * @param context A hx509 context.
132 : * @param tbs object to be signed.
133 : * @param t time the certificated will start to be valid
134 : *
135 : * @return An hx509 error code, see hx509_get_error_string().
136 : *
137 : * @ingroup hx509_ca
138 : */
139 :
140 : HX509_LIB_FUNCTION int HX509_LIB_CALL
141 0 : hx509_ca_tbs_set_notBefore(hx509_context context,
142 : hx509_ca_tbs tbs,
143 : time_t t)
144 : {
145 0 : tbs->notBefore = t;
146 0 : return 0;
147 : }
148 :
149 : /**
150 : * Set the absolute time when the certificate is valid to.
151 : *
152 : * @param context A hx509 context.
153 : * @param tbs object to be signed.
154 : * @param t time when the certificate will expire
155 : *
156 : * @return An hx509 error code, see hx509_get_error_string().
157 : *
158 : * @ingroup hx509_ca
159 : */
160 :
161 : HX509_LIB_FUNCTION int HX509_LIB_CALL
162 0 : hx509_ca_tbs_set_notAfter(hx509_context context,
163 : hx509_ca_tbs tbs,
164 : time_t t)
165 : {
166 0 : tbs->notAfter = t;
167 0 : return 0;
168 : }
169 :
170 : /**
171 : * Set the relative time when the certificiate is going to expire.
172 : *
173 : * @param context A hx509 context.
174 : * @param tbs object to be signed.
175 : * @param delta seconds to the certificate is going to expire.
176 : *
177 : * @return An hx509 error code, see hx509_get_error_string().
178 : *
179 : * @ingroup hx509_ca
180 : */
181 :
182 : HX509_LIB_FUNCTION int HX509_LIB_CALL
183 0 : hx509_ca_tbs_set_notAfter_lifetime(hx509_context context,
184 : hx509_ca_tbs tbs,
185 : time_t delta)
186 : {
187 0 : return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta);
188 : }
189 :
190 : HX509_LIB_FUNCTION int HX509_LIB_CALL
191 0 : hx509_ca_tbs_set_pkinit_max_life(hx509_context context,
192 : hx509_ca_tbs tbs,
193 : time_t max_life)
194 : {
195 0 : tbs->pkinitTicketMaxLife = max_life;
196 0 : return 0;
197 : }
198 :
199 : static const struct units templatebits[] = {
200 : { "ExtendedKeyUsage", HX509_CA_TEMPLATE_EKU },
201 : { "KeyUsage", HX509_CA_TEMPLATE_KU },
202 : { "SPKI", HX509_CA_TEMPLATE_SPKI },
203 : { "notAfter", HX509_CA_TEMPLATE_NOTAFTER },
204 : { "notBefore", HX509_CA_TEMPLATE_NOTBEFORE },
205 : { "serial", HX509_CA_TEMPLATE_SERIAL },
206 : { "subject", HX509_CA_TEMPLATE_SUBJECT },
207 : { "pkinitMaxLife", HX509_CA_TEMPLATE_PKINIT_MAX_LIFE },
208 : { NULL, 0 }
209 : };
210 :
211 : /**
212 : * Make of template units, use to build flags argument to
213 : * hx509_ca_tbs_set_template() with parse_units().
214 : *
215 : * @return an units structure.
216 : *
217 : * @ingroup hx509_ca
218 : */
219 :
220 : HX509_LIB_FUNCTION const struct units * HX509_LIB_CALL
221 0 : hx509_ca_tbs_template_units(void)
222 : {
223 0 : return templatebits;
224 : }
225 :
226 : /**
227 : * Initialize the to-be-signed certificate object from a template certificate.
228 : *
229 : * @param context A hx509 context.
230 : * @param tbs object to be signed.
231 : * @param flags bit field selecting what to copy from the template
232 : * certificate.
233 : * @param cert template certificate.
234 : *
235 : * @return An hx509 error code, see hx509_get_error_string().
236 : *
237 : * @ingroup hx509_ca
238 : */
239 :
240 : HX509_LIB_FUNCTION int HX509_LIB_CALL
241 0 : hx509_ca_tbs_set_template(hx509_context context,
242 : hx509_ca_tbs tbs,
243 : int flags,
244 : hx509_cert cert)
245 : {
246 : int ret;
247 :
248 0 : if (flags & HX509_CA_TEMPLATE_SUBJECT) {
249 0 : if (tbs->subject)
250 0 : hx509_name_free(&tbs->subject);
251 0 : ret = hx509_cert_get_subject(cert, &tbs->subject);
252 0 : if (ret) {
253 0 : hx509_set_error_string(context, 0, ret,
254 : "Failed to get subject from template");
255 0 : return ret;
256 : }
257 : }
258 0 : if (flags & HX509_CA_TEMPLATE_SERIAL) {
259 0 : der_free_heim_integer(&tbs->serial);
260 0 : ret = hx509_cert_get_serialnumber(cert, &tbs->serial);
261 0 : tbs->flags.serial = !ret;
262 0 : if (ret) {
263 0 : hx509_set_error_string(context, 0, ret,
264 : "Failed to copy serial number");
265 0 : return ret;
266 : }
267 : }
268 0 : if (flags & HX509_CA_TEMPLATE_NOTBEFORE)
269 0 : tbs->notBefore = hx509_cert_get_notBefore(cert);
270 0 : if (flags & HX509_CA_TEMPLATE_NOTAFTER)
271 0 : tbs->notAfter = hx509_cert_get_notAfter(cert);
272 0 : if (flags & HX509_CA_TEMPLATE_SPKI) {
273 0 : free_SubjectPublicKeyInfo(&tbs->spki);
274 0 : ret = hx509_cert_get_SPKI(context, cert, &tbs->spki);
275 0 : tbs->flags.key = !ret;
276 0 : if (ret)
277 0 : return ret;
278 : }
279 0 : if (flags & HX509_CA_TEMPLATE_KU) {
280 0 : ret = _hx509_cert_get_keyusage(context, cert, &tbs->ku);
281 0 : if (ret)
282 0 : return ret;
283 : }
284 0 : if (flags & HX509_CA_TEMPLATE_EKU) {
285 : ExtKeyUsage eku;
286 : size_t i;
287 0 : ret = _hx509_cert_get_eku(context, cert, &eku);
288 0 : if (ret)
289 0 : return ret;
290 0 : for (i = 0; i < eku.len; i++) {
291 0 : ret = hx509_ca_tbs_add_eku(context, tbs, &eku.val[i]);
292 0 : if (ret) {
293 0 : free_ExtKeyUsage(&eku);
294 0 : return ret;
295 : }
296 : }
297 0 : free_ExtKeyUsage(&eku);
298 : }
299 0 : if (flags & HX509_CA_TEMPLATE_PKINIT_MAX_LIFE) {
300 : time_t max_life;
301 :
302 0 : if ((max_life = hx509_cert_get_pkinit_max_life(context, cert, 0)) > 0)
303 0 : hx509_ca_tbs_set_pkinit_max_life(context, tbs, max_life);
304 : }
305 0 : return 0;
306 : }
307 :
308 : /**
309 : * Make the to-be-signed certificate object a CA certificate. If the
310 : * pathLenConstraint is negative path length constraint is used.
311 : *
312 : * @param context A hx509 context.
313 : * @param tbs object to be signed.
314 : * @param pathLenConstraint path length constraint, negative, no
315 : * constraint.
316 : *
317 : * @return An hx509 error code, see hx509_get_error_string().
318 : *
319 : * @ingroup hx509_ca
320 : */
321 :
322 : HX509_LIB_FUNCTION int HX509_LIB_CALL
323 0 : hx509_ca_tbs_set_ca(hx509_context context,
324 : hx509_ca_tbs tbs,
325 : int pathLenConstraint)
326 : {
327 0 : tbs->flags.ca = 1;
328 0 : tbs->pathLenConstraint = pathLenConstraint;
329 0 : return 0;
330 : }
331 :
332 : /**
333 : * Make the to-be-signed certificate object a proxy certificate. If the
334 : * pathLenConstraint is negative path length constraint is used.
335 : *
336 : * @param context A hx509 context.
337 : * @param tbs object to be signed.
338 : * @param pathLenConstraint path length constraint, negative, no
339 : * constraint.
340 : *
341 : * @return An hx509 error code, see hx509_get_error_string().
342 : *
343 : * @ingroup hx509_ca
344 : */
345 :
346 : HX509_LIB_FUNCTION int HX509_LIB_CALL
347 0 : hx509_ca_tbs_set_proxy(hx509_context context,
348 : hx509_ca_tbs tbs,
349 : int pathLenConstraint)
350 : {
351 0 : tbs->flags.proxy = 1;
352 0 : tbs->pathLenConstraint = pathLenConstraint;
353 0 : return 0;
354 : }
355 :
356 :
357 : /**
358 : * Make the to-be-signed certificate object a windows domain controller certificate.
359 : *
360 : * @param context A hx509 context.
361 : * @param tbs object to be signed.
362 : *
363 : * @return An hx509 error code, see hx509_get_error_string().
364 : *
365 : * @ingroup hx509_ca
366 : */
367 :
368 : HX509_LIB_FUNCTION int HX509_LIB_CALL
369 0 : hx509_ca_tbs_set_domaincontroller(hx509_context context,
370 : hx509_ca_tbs tbs)
371 : {
372 0 : tbs->flags.domaincontroller = 1;
373 0 : return 0;
374 : }
375 :
376 : /**
377 : * Set the subject public key info (SPKI) in the to-be-signed certificate
378 : * object. SPKI is the public key and key related parameters in the
379 : * certificate.
380 : *
381 : * @param context A hx509 context.
382 : * @param tbs object to be signed.
383 : * @param spki subject public key info to use for the to-be-signed certificate object.
384 : *
385 : * @return An hx509 error code, see hx509_get_error_string().
386 : *
387 : * @ingroup hx509_ca
388 : */
389 :
390 : HX509_LIB_FUNCTION int HX509_LIB_CALL
391 0 : hx509_ca_tbs_set_spki(hx509_context context,
392 : hx509_ca_tbs tbs,
393 : const SubjectPublicKeyInfo *spki)
394 : {
395 : int ret;
396 0 : free_SubjectPublicKeyInfo(&tbs->spki);
397 0 : ret = copy_SubjectPublicKeyInfo(spki, &tbs->spki);
398 0 : tbs->flags.key = !ret;
399 0 : return ret;
400 : }
401 :
402 : /**
403 : * Set the serial number to use for to-be-signed certificate object.
404 : *
405 : * @param context A hx509 context.
406 : * @param tbs object to be signed.
407 : * @param serialNumber serial number to use for the to-be-signed
408 : * certificate object.
409 : *
410 : * @return An hx509 error code, see hx509_get_error_string().
411 : *
412 : * @ingroup hx509_ca
413 : */
414 :
415 : HX509_LIB_FUNCTION int HX509_LIB_CALL
416 0 : hx509_ca_tbs_set_serialnumber(hx509_context context,
417 : hx509_ca_tbs tbs,
418 : const heim_integer *serialNumber)
419 : {
420 : int ret;
421 0 : der_free_heim_integer(&tbs->serial);
422 0 : ret = der_copy_heim_integer(serialNumber, &tbs->serial);
423 0 : tbs->flags.serial = !ret;
424 0 : return ret;
425 : }
426 :
427 : /**
428 : * Copy elements of a CSR into a TBS, but only if all of them are authorized.
429 : *
430 : * @param context A hx509 context.
431 : * @param tbs object to be signed.
432 : * @param req CSR
433 : *
434 : * @return An hx509 error code, see hx509_get_error_string().
435 : *
436 : * @ingroup hx509_ca
437 : */
438 :
439 : HX509_LIB_FUNCTION int HX509_LIB_CALL
440 0 : hx509_ca_tbs_set_from_csr(hx509_context context,
441 : hx509_ca_tbs tbs,
442 : hx509_request req)
443 : {
444 : hx509_san_type san_type;
445 0 : heim_oid oid = { 0, 0 };
446 : KeyUsage ku;
447 : size_t i;
448 0 : char *s = NULL;
449 : int ret;
450 :
451 0 : if (hx509_request_count_unauthorized(req)) {
452 0 : hx509_set_error_string(context, 0, ENOMEM, "out of memory");
453 0 : return EACCES;
454 : }
455 :
456 0 : ret = hx509_request_get_ku(context, req, &ku);
457 0 : if (ret == 0 && KeyUsage2int(ku))
458 0 : ret = hx509_ca_tbs_add_ku(context, tbs, ku);
459 :
460 0 : for (i = 0; ret == 0; i++) {
461 0 : free(s); s = NULL;
462 0 : der_free_oid(&oid);
463 0 : ret = hx509_request_get_eku(req, i, &s);
464 0 : if (ret == 0)
465 0 : ret = der_parse_heim_oid(s, ".", &oid);
466 0 : if (ret == 0)
467 0 : ret = hx509_ca_tbs_add_eku(context, tbs, &oid);
468 : }
469 0 : if (ret == HX509_NO_ITEM)
470 0 : ret = 0;
471 :
472 0 : for (i = 0; ret == 0; i++) {
473 0 : free(s); s = NULL;
474 0 : ret = hx509_request_get_san(req, i, &san_type, &s);
475 0 : if (ret == 0)
476 0 : ret = hx509_ca_tbs_add_san(context, tbs, san_type, s);
477 : }
478 0 : if (ret == HX509_NO_ITEM)
479 0 : ret = 0;
480 :
481 0 : der_free_oid(&oid);
482 0 : free(s);
483 0 : return ret;
484 : }
485 :
486 : /**
487 : * An an extended key usage to the to-be-signed certificate object.
488 : * Duplicates will detected and not added.
489 : *
490 : * @param context A hx509 context.
491 : * @param tbs object to be signed.
492 : * @param oid extended key usage to add.
493 : *
494 : * @return An hx509 error code, see hx509_get_error_string().
495 : *
496 : * @ingroup hx509_ca
497 : */
498 :
499 : HX509_LIB_FUNCTION int HX509_LIB_CALL
500 0 : hx509_ca_tbs_add_ku(hx509_context context,
501 : hx509_ca_tbs tbs,
502 : KeyUsage ku)
503 : {
504 0 : tbs->ku = ku;
505 0 : return 0;
506 : }
507 :
508 : /**
509 : * An an extended key usage to the to-be-signed certificate object.
510 : * Duplicates will detected and not added.
511 : *
512 : * @param context A hx509 context.
513 : * @param tbs object to be signed.
514 : * @param oid extended key usage to add.
515 : *
516 : * @return An hx509 error code, see hx509_get_error_string().
517 : *
518 : * @ingroup hx509_ca
519 : */
520 :
521 : HX509_LIB_FUNCTION int HX509_LIB_CALL
522 0 : hx509_ca_tbs_add_eku(hx509_context context,
523 : hx509_ca_tbs tbs,
524 : const heim_oid *oid)
525 : {
526 : void *ptr;
527 : int ret;
528 : unsigned i;
529 :
530 : /* search for duplicates */
531 0 : for (i = 0; i < tbs->eku.len; i++) {
532 0 : if (der_heim_oid_cmp(oid, &tbs->eku.val[i]) == 0)
533 0 : return 0;
534 : }
535 :
536 0 : ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1));
537 0 : if (ptr == NULL) {
538 0 : hx509_set_error_string(context, 0, ENOMEM, "out of memory");
539 0 : return ENOMEM;
540 : }
541 0 : tbs->eku.val = ptr;
542 0 : ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]);
543 0 : if (ret) {
544 0 : hx509_set_error_string(context, 0, ret, "out of memory");
545 0 : return ret;
546 : }
547 0 : tbs->eku.len += 1;
548 0 : return 0;
549 : }
550 :
551 : /**
552 : * Add a certificate policy to the to-be-signed certificate object. Duplicates
553 : * will detected and not added.
554 : *
555 : * @param context A hx509 context.
556 : * @param tbs object to be signed.
557 : * @param oid policy OID.
558 : * @param cps_uri CPS URI to qualify policy with.
559 : * @param user_notice user notice display text to qualify policy with.
560 : *
561 : * @return An hx509 error code, see hx509_get_error_string().
562 : *
563 : * @ingroup hx509_ca
564 : */
565 :
566 : HX509_LIB_FUNCTION int HX509_LIB_CALL
567 0 : hx509_ca_tbs_add_pol(hx509_context context,
568 : hx509_ca_tbs tbs,
569 : const heim_oid *oid,
570 : const char *cps_uri,
571 : const char *user_notice)
572 : {
573 : PolicyQualifierInfos pqis;
574 : PolicyQualifierInfo pqi;
575 : PolicyInformation pi;
576 : size_t i, size;
577 0 : int ret = 0;
578 :
579 : /* search for duplicates */
580 0 : for (i = 0; i < tbs->cps.len; i++) {
581 0 : if (der_heim_oid_cmp(oid, &tbs->cps.val[i].policyIdentifier) == 0)
582 0 : return 0;
583 : }
584 :
585 0 : memset(&pi, 0, sizeof(pi));
586 0 : memset(&pqi, 0, sizeof(pqi));
587 0 : memset(&pqis, 0, sizeof(pqis));
588 :
589 0 : pi.policyIdentifier = *oid;
590 0 : if (cps_uri) {
591 : CPSuri uri;
592 :
593 0 : uri.length = strlen(cps_uri);
594 0 : uri.data = (void *)(uintptr_t)cps_uri;
595 0 : pqi.policyQualifierId = asn1_oid_id_pkix_qt_cps;
596 :
597 0 : ASN1_MALLOC_ENCODE(CPSuri,
598 : pqi.qualifier.data,
599 : pqi.qualifier.length,
600 : &uri, &size, ret);
601 0 : if (ret == 0) {
602 0 : ret = add_PolicyQualifierInfos(&pqis, &pqi);
603 0 : free_heim_any(&pqi.qualifier);
604 : }
605 : }
606 0 : if (ret == 0 && user_notice) {
607 : DisplayText dt;
608 : UserNotice un;
609 :
610 0 : dt.element = choice_DisplayText_utf8String;
611 0 : dt.u.utf8String = (void *)(uintptr_t)user_notice;
612 0 : un.explicitText = &dt;
613 0 : un.noticeRef = 0;
614 :
615 0 : pqi.policyQualifierId = asn1_oid_id_pkix_qt_unotice;
616 0 : ASN1_MALLOC_ENCODE(UserNotice,
617 : pqi.qualifier.data,
618 : pqi.qualifier.length,
619 : &un, &size, ret);
620 0 : if (ret == 0) {
621 0 : ret = add_PolicyQualifierInfos(&pqis, &pqi);
622 0 : free_heim_any(&pqi.qualifier);
623 : }
624 : }
625 :
626 0 : pi.policyQualifiers = pqis.len ? &pqis : 0;
627 :
628 0 : if (ret == 0)
629 0 : ret = add_CertificatePolicies(&tbs->cps, &pi);
630 :
631 0 : free_PolicyQualifierInfos(&pqis);
632 0 : return ret;
633 : }
634 :
635 : /**
636 : * Add a certificate policy mapping to the to-be-signed certificate object.
637 : * Duplicates will detected and not added.
638 : *
639 : * @param context A hx509 context.
640 : * @param tbs object to be signed.
641 : * @param issuer issuerDomainPolicy policy OID.
642 : * @param subject subjectDomainPolicy policy OID.
643 : *
644 : * @return An hx509 error code, see hx509_get_error_string().
645 : *
646 : * @ingroup hx509_ca
647 : */
648 :
649 : HX509_LIB_FUNCTION int HX509_LIB_CALL
650 0 : hx509_ca_tbs_add_pol_mapping(hx509_context context,
651 : hx509_ca_tbs tbs,
652 : const heim_oid *issuer,
653 : const heim_oid *subject)
654 : {
655 : PolicyMapping pm;
656 : size_t i;
657 :
658 : /* search for duplicates */
659 0 : for (i = 0; i < tbs->pms.len; i++) {
660 0 : PolicyMapping *pmp = &tbs->pms.val[i];
661 0 : if (der_heim_oid_cmp(issuer, &pmp->issuerDomainPolicy) == 0 &&
662 0 : der_heim_oid_cmp(subject, &pmp->subjectDomainPolicy) == 0)
663 0 : return 0;
664 : }
665 :
666 0 : memset(&pm, 0, sizeof(pm));
667 0 : pm.issuerDomainPolicy = *issuer;
668 0 : pm.subjectDomainPolicy = *subject;
669 0 : return add_PolicyMappings(&tbs->pms, &pm);
670 : }
671 :
672 : /**
673 : * Add CRL distribution point URI to the to-be-signed certificate
674 : * object.
675 : *
676 : * @param context A hx509 context.
677 : * @param tbs object to be signed.
678 : * @param uri uri to the CRL.
679 : * @param issuername name of the issuer.
680 : *
681 : * @return An hx509 error code, see hx509_get_error_string().
682 : *
683 : * @ingroup hx509_ca
684 : */
685 :
686 : HX509_LIB_FUNCTION int HX509_LIB_CALL
687 0 : hx509_ca_tbs_add_crl_dp_uri(hx509_context context,
688 : hx509_ca_tbs tbs,
689 : const char *uri,
690 : hx509_name issuername)
691 : {
692 : DistributionPointName dpn;
693 : DistributionPoint dp;
694 : GeneralNames crlissuer;
695 : GeneralName gn, ign;
696 : Name in;
697 : int ret;
698 :
699 0 : memset(&dp, 0, sizeof(dp));
700 0 : memset(&gn, 0, sizeof(gn));
701 0 : memset(&ign, 0, sizeof(ign));
702 0 : memset(&in, 0, sizeof(in));
703 0 : gn.element = choice_GeneralName_uniformResourceIdentifier;
704 0 : gn.u.uniformResourceIdentifier.data = rk_UNCONST(uri);
705 0 : gn.u.uniformResourceIdentifier.length = strlen(uri);
706 0 : dpn.element = choice_DistributionPointName_fullName;
707 0 : dpn.u.fullName.len = 1;
708 0 : dpn.u.fullName.val = &gn;
709 0 : dp.distributionPoint = &dpn;
710 :
711 0 : if (issuername) {
712 0 : ign.element = choice_GeneralName_directoryName;
713 0 : ret = hx509_name_to_Name(issuername, &ign.u.directoryName);
714 0 : if (ret) {
715 0 : hx509_set_error_string(context, 0, ret, "out of memory");
716 0 : return ret;
717 : }
718 0 : crlissuer.len = 1;
719 0 : crlissuer.val = &ign;
720 0 : dp.cRLIssuer = &crlissuer;
721 : }
722 :
723 0 : ret = add_CRLDistributionPoints(&tbs->crldp, &dp);
724 0 : if (issuername)
725 0 : free_Name(&ign.u.directoryName);
726 :
727 0 : if (ret)
728 0 : hx509_set_error_string(context, 0, ret, "out of memory");
729 0 : return ret;
730 : }
731 :
732 : /**
733 : * Add Subject Alternative Name otherName to the to-be-signed
734 : * certificate object.
735 : *
736 : * @param context A hx509 context.
737 : * @param tbs object to be signed.
738 : * @param oid the oid of the OtherName.
739 : * @param os data in the other name.
740 : *
741 : * @return An hx509 error code, see hx509_get_error_string().
742 : *
743 : * @ingroup hx509_ca
744 : */
745 :
746 : HX509_LIB_FUNCTION int HX509_LIB_CALL
747 0 : hx509_ca_tbs_add_san_otherName(hx509_context context,
748 : hx509_ca_tbs tbs,
749 : const heim_oid *oid,
750 : const heim_octet_string *os)
751 : {
752 : GeneralName gn;
753 :
754 0 : memset(&gn, 0, sizeof(gn));
755 0 : gn.element = choice_GeneralName_otherName;
756 0 : gn.u.otherName.type_id = *oid;
757 0 : gn.u.otherName.value = *os;
758 :
759 0 : return add_GeneralNames(&tbs->san, &gn);
760 : }
761 :
762 : static
763 : int
764 0 : dequote_strndup(hx509_context context, const char *in, size_t len, char **out)
765 : {
766 : size_t i, k;
767 : char *s;
768 :
769 0 : *out = NULL;
770 0 : if ((s = malloc(len + 1)) == NULL) {
771 0 : hx509_set_error_string(context, 0, ENOMEM, "malloc: out of memory");
772 0 : return ENOMEM;
773 : }
774 :
775 0 : for (k = i = 0; i < len; i++) {
776 0 : if (in[i] == '\\') {
777 0 : switch (in[++i]) {
778 0 : case 't': s[k++] = '\t'; break;
779 0 : case 'b': s[k++] = '\b'; break;
780 0 : case 'n': s[k++] = '\n'; break;
781 0 : case '0':
782 0 : for (i++; i < len; i++) {
783 0 : if (in[i] == '\0')
784 0 : break;
785 0 : if (in[i++] == '\\' && in[i] == '0')
786 0 : continue;
787 0 : hx509_set_error_string(context, 0,
788 : HX509_PARSING_NAME_FAILED,
789 : "embedded NULs not supported in "
790 : "PKINIT SANs");
791 0 : free(s);
792 0 : return HX509_PARSING_NAME_FAILED;
793 : }
794 0 : break;
795 0 : case '\0':
796 0 : hx509_set_error_string(context, 0,
797 : HX509_PARSING_NAME_FAILED,
798 : "trailing unquoted backslashes not "
799 : "allowed in PKINIT SANs");
800 0 : free(s);
801 0 : return HX509_PARSING_NAME_FAILED;
802 0 : default: s[k++] = in[i]; break;
803 : }
804 : } else {
805 0 : s[k++] = in[i];
806 : }
807 : }
808 0 : s[k] = '\0';
809 :
810 0 : *out = s;
811 0 : return 0;
812 : }
813 :
814 : int
815 0 : _hx509_make_pkinit_san(hx509_context context,
816 : const char *principal,
817 : heim_octet_string *os)
818 : {
819 : KRB5PrincipalName p;
820 : size_t size;
821 : int ret;
822 :
823 0 : os->data = NULL;
824 0 : os->length = 0;
825 0 : memset(&p, 0, sizeof(p));
826 :
827 : /* Parse principal */
828 : {
829 : const char *str, *str_start;
830 : size_t n, i;
831 :
832 : /* Count number of components */
833 0 : n = 1;
834 0 : for (str = principal; *str != '\0' && *str != '@'; str++) {
835 0 : if (*str == '\\') {
836 0 : if (str[1] == '\0') {
837 0 : ret = HX509_PARSING_NAME_FAILED;
838 0 : hx509_set_error_string(context, 0, ret,
839 : "trailing \\ in principal name");
840 0 : goto out;
841 : }
842 0 : str++;
843 0 : } else if(*str == '/') {
844 0 : n++;
845 0 : } else if(*str == '@') {
846 0 : break;
847 : }
848 : }
849 0 : if (*str != '@') {
850 : /* Note that we allow the realm to be empty */
851 0 : ret = HX509_PARSING_NAME_FAILED;
852 0 : hx509_set_error_string(context, 0, ret, "Missing @ in principal");
853 0 : goto out;
854 : };
855 :
856 0 : p.principalName.name_string.val =
857 0 : calloc(n, sizeof(*p.principalName.name_string.val));
858 0 : if (p.principalName.name_string.val == NULL) {
859 0 : ret = ENOMEM;
860 0 : hx509_set_error_string(context, 0, ret, "malloc: out of memory");
861 0 : goto out;
862 : }
863 0 : p.principalName.name_string.len = n;
864 0 : p.principalName.name_type = KRB5_NT_PRINCIPAL;
865 :
866 0 : for (i = 0, str_start = str = principal; *str != '\0'; str++) {
867 0 : if (*str=='\\') {
868 0 : str++;
869 0 : } else if(*str == '/') {
870 : /* Note that we allow components to be empty */
871 0 : ret = dequote_strndup(context, str_start, str - str_start,
872 0 : &p.principalName.name_string.val[i++]);
873 0 : if (ret)
874 0 : goto out;
875 0 : str_start = str + 1;
876 0 : } else if(*str == '@') {
877 0 : ret = dequote_strndup(context, str_start, str - str_start,
878 0 : &p.principalName.name_string.val[i++]);
879 0 : if (ret == 0)
880 0 : ret = dequote_strndup(context, str + 1, strlen(str + 1), &p.realm);
881 0 : if (ret)
882 0 : goto out;
883 0 : break;
884 : }
885 : }
886 : }
887 :
888 0 : ASN1_MALLOC_ENCODE(KRB5PrincipalName, os->data, os->length, &p, &size, ret);
889 0 : if (ret) {
890 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
891 0 : goto out;
892 : }
893 0 : if (size != os->length)
894 0 : _hx509_abort("internal ASN.1 encoder error");
895 :
896 0 : out:
897 0 : free_KRB5PrincipalName(&p);
898 0 : return ret;
899 : }
900 :
901 : static int
902 0 : add_ia5string_san(hx509_context context,
903 : hx509_ca_tbs tbs,
904 : const heim_oid *oid,
905 : const char *string)
906 : {
907 : SRVName ustring;
908 : heim_octet_string os;
909 : size_t size;
910 : int ret;
911 :
912 0 : ustring.data = (void *)(uintptr_t)string;
913 0 : ustring.length = strlen(string);
914 :
915 0 : os.length = 0;
916 0 : os.data = NULL;
917 :
918 0 : ASN1_MALLOC_ENCODE(SRVName, os.data, os.length, &ustring, &size, ret);
919 0 : if (ret) {
920 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
921 0 : return ret;
922 : }
923 0 : if (size != os.length)
924 0 : _hx509_abort("internal ASN.1 encoder error");
925 :
926 0 : ret = hx509_ca_tbs_add_san_otherName(context, tbs, oid, &os);
927 0 : free(os.data);
928 0 : return ret;
929 : }
930 :
931 : /**
932 : * Add DNSSRV Subject Alternative Name to the to-be-signed certificate object.
933 : *
934 : * @param context A hx509 context.
935 : * @param tbs object to be signed.
936 : * @param dnssrv An ASCII string of the for _Service.Name.
937 : *
938 : * @return An hx509 error code, see hx509_get_error_string().
939 : *
940 : * @ingroup hx509_ca
941 : */
942 :
943 : HX509_LIB_FUNCTION int HX509_LIB_CALL
944 0 : hx509_ca_tbs_add_san_dnssrv(hx509_context context,
945 : hx509_ca_tbs tbs,
946 : const char *dnssrv)
947 : {
948 : size_t i, len;
949 :
950 : /* Minimal DNSSRV input validation */
951 0 : if (dnssrv == 0 || dnssrv[0] != '_') {
952 0 : hx509_set_error_string(context, 0, EINVAL, "Invalid DNSSRV name");
953 0 : return EINVAL;
954 : }
955 0 : for (i = 1, len = strlen(dnssrv); i < len; i++) {
956 0 : if (dnssrv[i] == '.' && dnssrv[i + 1] != '\0')
957 0 : break;
958 : }
959 0 : if (i == len) {
960 0 : hx509_set_error_string(context, 0, EINVAL, "Invalid DNSSRV name");
961 0 : return EINVAL;
962 : }
963 :
964 0 : return add_ia5string_san(context, tbs,
965 : &asn1_oid_id_pkix_on_dnsSRV, dnssrv);
966 : }
967 :
968 : /**
969 : * Add Kerberos Subject Alternative Name to the to-be-signed
970 : * certificate object. The principal string is a UTF8 string.
971 : *
972 : * @param context A hx509 context.
973 : * @param tbs object to be signed.
974 : * @param principal Kerberos principal to add to the certificate.
975 : *
976 : * @return An hx509 error code, see hx509_get_error_string().
977 : *
978 : * @ingroup hx509_ca
979 : */
980 :
981 : HX509_LIB_FUNCTION int HX509_LIB_CALL
982 0 : hx509_ca_tbs_add_san_pkinit(hx509_context context,
983 : hx509_ca_tbs tbs,
984 : const char *principal)
985 : {
986 : heim_octet_string os;
987 : int ret;
988 :
989 0 : ret = _hx509_make_pkinit_san(context, principal, &os);
990 0 : if (ret == 0)
991 0 : ret = hx509_ca_tbs_add_san_otherName(context, tbs,
992 : &asn1_oid_id_pkinit_san, &os);
993 0 : free(os.data);
994 0 : return ret;
995 : }
996 :
997 : /*
998 : *
999 : */
1000 :
1001 : static int
1002 0 : add_utf8_san(hx509_context context,
1003 : hx509_ca_tbs tbs,
1004 : const heim_oid *oid,
1005 : const char *string)
1006 : {
1007 0 : const PKIXXmppAddr ustring = (const PKIXXmppAddr)(uintptr_t)string;
1008 : heim_octet_string os;
1009 : size_t size;
1010 : int ret;
1011 :
1012 0 : os.length = 0;
1013 0 : os.data = NULL;
1014 :
1015 0 : ASN1_MALLOC_ENCODE(PKIXXmppAddr, os.data, os.length, &ustring, &size, ret);
1016 0 : if (ret) {
1017 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1018 0 : return ret;
1019 : }
1020 0 : if (size != os.length)
1021 0 : _hx509_abort("internal ASN.1 encoder error");
1022 :
1023 0 : ret = hx509_ca_tbs_add_san_otherName(context, tbs, oid, &os);
1024 0 : free(os.data);
1025 0 : return ret;
1026 : }
1027 :
1028 : /**
1029 : * Add Microsoft UPN Subject Alternative Name to the to-be-signed
1030 : * certificate object. The principal string is a UTF8 string.
1031 : *
1032 : * @param context A hx509 context.
1033 : * @param tbs object to be signed.
1034 : * @param principal Microsoft UPN string.
1035 : *
1036 : * @return An hx509 error code, see hx509_get_error_string().
1037 : *
1038 : * @ingroup hx509_ca
1039 : */
1040 :
1041 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1042 0 : hx509_ca_tbs_add_san_ms_upn(hx509_context context,
1043 : hx509_ca_tbs tbs,
1044 : const char *principal)
1045 : {
1046 0 : return add_utf8_san(context, tbs, &asn1_oid_id_pkinit_ms_san, principal);
1047 : }
1048 :
1049 : /**
1050 : * Add a Jabber/XMPP jid Subject Alternative Name to the to-be-signed
1051 : * certificate object. The jid is an UTF8 string.
1052 : *
1053 : * @param context A hx509 context.
1054 : * @param tbs object to be signed.
1055 : * @param jid string of an a jabber id in UTF8.
1056 : *
1057 : * @return An hx509 error code, see hx509_get_error_string().
1058 : *
1059 : * @ingroup hx509_ca
1060 : */
1061 :
1062 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1063 0 : hx509_ca_tbs_add_san_jid(hx509_context context,
1064 : hx509_ca_tbs tbs,
1065 : const char *jid)
1066 : {
1067 0 : return add_utf8_san(context, tbs, &asn1_oid_id_pkix_on_xmppAddr, jid);
1068 : }
1069 :
1070 :
1071 : /**
1072 : * Add a Subject Alternative Name hostname to to-be-signed certificate
1073 : * object. A domain match starts with ., an exact match does not.
1074 : *
1075 : * Example of a an domain match: .domain.se matches the hostname
1076 : * host.domain.se.
1077 : *
1078 : * @param context A hx509 context.
1079 : * @param tbs object to be signed.
1080 : * @param dnsname a hostame.
1081 : *
1082 : * @return An hx509 error code, see hx509_get_error_string().
1083 : *
1084 : * @ingroup hx509_ca
1085 : */
1086 :
1087 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1088 0 : hx509_ca_tbs_add_san_hostname(hx509_context context,
1089 : hx509_ca_tbs tbs,
1090 : const char *dnsname)
1091 : {
1092 : GeneralName gn;
1093 :
1094 0 : memset(&gn, 0, sizeof(gn));
1095 0 : gn.element = choice_GeneralName_dNSName;
1096 0 : gn.u.dNSName.data = rk_UNCONST(dnsname);
1097 0 : gn.u.dNSName.length = strlen(dnsname);
1098 :
1099 0 : return add_GeneralNames(&tbs->san, &gn);
1100 : }
1101 :
1102 : /**
1103 : * Add a Subject Alternative Name rfc822 (email address) to
1104 : * to-be-signed certificate object.
1105 : *
1106 : * @param context A hx509 context.
1107 : * @param tbs object to be signed.
1108 : * @param rfc822Name a string to a email address.
1109 : *
1110 : * @return An hx509 error code, see hx509_get_error_string().
1111 : *
1112 : * @ingroup hx509_ca
1113 : */
1114 :
1115 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1116 0 : hx509_ca_tbs_add_san_rfc822name(hx509_context context,
1117 : hx509_ca_tbs tbs,
1118 : const char *rfc822Name)
1119 : {
1120 : GeneralName gn;
1121 :
1122 0 : memset(&gn, 0, sizeof(gn));
1123 0 : gn.element = choice_GeneralName_rfc822Name;
1124 0 : gn.u.rfc822Name.data = rk_UNCONST(rfc822Name);
1125 0 : gn.u.rfc822Name.length = strlen(rfc822Name);
1126 :
1127 0 : return add_GeneralNames(&tbs->san, &gn);
1128 : }
1129 :
1130 : /*
1131 : * PermanentIdentifier is one SAN for naming devices with TPMs after their
1132 : * endorsement keys or EK certificates. See TPM 2.0 Keys for Device Identity
1133 : * and Attestation, Version 1.00, Revision 2, 9/17/2020 (DRAFT).
1134 : *
1135 : * The text on the form of permanent identifiers for TPM endorsement keys sans
1136 : * certificates is clearly problematic, saying: "When the TPM does not have an
1137 : * EK certificate, the identifierValue is a digest of a concatenation of the
1138 : * UTF8 string “EkPubkey” (terminating NULL not included) with the binary EK
1139 : * public key", but since arbitrary binary is not necessarily valid UTF-8...
1140 : * and since NULs embedded in UTF-8 might be OK in some contexts but really
1141 : * isn't in C (and Heimdal's ASN.1 compiler does not allow NULs in the
1142 : * middle of strings)... That just cannot be correct. Since elsewhere the TCG
1143 : * specs use the hex encoding of the SHA-256 digest of the DER encoding of
1144 : * public keys, that's what we should support in Heimdal, and maybe send in a
1145 : * comment.
1146 : *
1147 : * Also, even where one should use hex encoding of the SHA-256 digest of the
1148 : * DER encoding of public keys, how should the public keys be represented?
1149 : * Presumably as SPKIs, with all the required parameters and no more.
1150 : */
1151 :
1152 : /**
1153 : * Add a Subject Alternative Name of PermanentIdentifier type to a to-be-signed
1154 : * certificate object. The permanent identifier form for TPM endorsement key
1155 : * certificates is the hex encoding of the SHA-256 digest of the DER encoding
1156 : * of the certificate. The permanent identifier form for TPM endorsement keys
1157 : * are of the form "EkPubkey<public-key>", where the form of <public-key> is
1158 : * not well specified at this point. It is the caller's responsibility to
1159 : * format the identifierValue.
1160 : *
1161 : * @param context A hx509 context.
1162 : * @param tbs object to be signed.
1163 : * @param str permanent identifier name in the form "[<assigner-oid>]:[<id>]".
1164 : * @param assigner The OID of an assigner.
1165 : *
1166 : * @return An hx509 error code, see hx509_get_error_string().
1167 : *
1168 : * @ingroup hx509_ca
1169 : */
1170 :
1171 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1172 0 : hx509_ca_tbs_add_san_permanentIdentifier_string(hx509_context context,
1173 : hx509_ca_tbs tbs,
1174 : const char *str)
1175 : {
1176 0 : const heim_oid *found = NULL;
1177 : heim_oid oid;
1178 : const char *oidstr, *id;
1179 : char *freeme, *p;
1180 : int ret;
1181 :
1182 0 : if ((freeme = strdup(str)) == NULL)
1183 0 : return hx509_enomem(context);
1184 :
1185 0 : oidstr = freeme;
1186 0 : p = strchr(freeme, ':');
1187 0 : if (!p) {
1188 0 : hx509_set_error_string(context, 0, EINVAL,
1189 : "Invalid PermanentIdentifier string (should be \"[<oid>]:[<id>]\")",
1190 : oidstr);
1191 0 : free(freeme);
1192 0 : return EINVAL;
1193 : }
1194 0 : if (p) {
1195 0 : *(p++) = '\0';
1196 0 : id = p;
1197 : }
1198 0 : if (oidstr[0] != '\0') {
1199 0 : ret = der_find_heim_oid_by_name(oidstr, &found);
1200 0 : if (ret) {
1201 0 : ret = der_parse_heim_oid(oidstr, " .", &oid);
1202 0 : if (ret == 0)
1203 0 : found = &oid;
1204 : }
1205 : }
1206 0 : ret = hx509_ca_tbs_add_san_permanentIdentifier(context, tbs, id, found);
1207 0 : if (found == &oid)
1208 0 : der_free_oid(&oid);
1209 0 : free(freeme);
1210 0 : return ret;
1211 : }
1212 :
1213 : /**
1214 : * Add a Subject Alternative Name of PermanentIdentifier type to a to-be-signed
1215 : * certificate object. The permanent identifier form for TPM endorsement key
1216 : * certificates is the hex encoding of the SHA-256 digest of the DER encoding
1217 : * of the certificate. The permanent identifier form for TPM endorsement keys
1218 : * are of the form "EkPubkey<public-key>", where the form of <public-key> is
1219 : * not well specified at this point. It is the caller's responsibility to
1220 : * format the identifierValue.
1221 : *
1222 : * @param context A hx509 context.
1223 : * @param tbs object to be signed.
1224 : * @param identifierValue The permanent identifier name.
1225 : * @param assigner The OID of an assigner.
1226 : *
1227 : * @return An hx509 error code, see hx509_get_error_string().
1228 : *
1229 : * @ingroup hx509_ca
1230 : */
1231 :
1232 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1233 0 : hx509_ca_tbs_add_san_permanentIdentifier(hx509_context context,
1234 : hx509_ca_tbs tbs,
1235 : const char *identifierValue,
1236 : const heim_oid *assigner)
1237 : {
1238 : PermanentIdentifier pi;
1239 0 : heim_utf8_string s = (void *)(uintptr_t)identifierValue;
1240 : heim_octet_string os;
1241 : size_t size;
1242 : int ret;
1243 :
1244 0 : pi.identifierValue = &s;
1245 0 : pi.assigner = (heim_oid*)(uintptr_t)assigner;
1246 0 : os.length = 0;
1247 0 : os.data = NULL;
1248 :
1249 0 : ASN1_MALLOC_ENCODE(PermanentIdentifier, os.data, os.length, &pi, &size,
1250 : ret);
1251 0 : if (ret) {
1252 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1253 0 : return ret;
1254 : }
1255 0 : if (size != os.length)
1256 0 : _hx509_abort("internal ASN.1 encoder error");
1257 :
1258 0 : ret = hx509_ca_tbs_add_san_otherName(context, tbs,
1259 : &asn1_oid_id_pkix_on_permanentIdentifier,
1260 : &os);
1261 0 : free(os.data);
1262 0 : return ret;
1263 : }
1264 :
1265 : /**
1266 : * Add a Subject Alternative Name of HardwareModuleName type to a to-be-signed
1267 : * certificate object.
1268 : *
1269 : * @param context A hx509 context.
1270 : * @param tbs object to be signed.
1271 : * @param str a string of the form "<oid>:<serial>".
1272 : * @param hwserial The serial number.
1273 : *
1274 : * @return An hx509 error code, see hx509_get_error_string().
1275 : *
1276 : * @ingroup hx509_ca
1277 : */
1278 :
1279 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1280 0 : hx509_ca_tbs_add_san_hardwareModuleName_string(hx509_context context,
1281 : hx509_ca_tbs tbs,
1282 : const char *str)
1283 : {
1284 0 : const heim_oid *found = NULL;
1285 : heim_oid oid;
1286 : const char *oidstr, *sno;
1287 : char *freeme, *p;
1288 : int ret;
1289 :
1290 0 : if ((freeme = strdup(str)) == NULL)
1291 0 : return hx509_enomem(context);
1292 :
1293 0 : oidstr = freeme;
1294 0 : p = strchr(freeme, ':');
1295 0 : if (!p) {
1296 0 : hx509_set_error_string(context, 0, EINVAL,
1297 : "Invalid HardwareModuleName string (should be "
1298 : "\"<oid>:<serial>\")",
1299 : oidstr);
1300 0 : free(freeme);
1301 0 : return EINVAL;
1302 : }
1303 0 : if (p) {
1304 0 : *(p++) = '\0';
1305 0 : sno = p;
1306 : }
1307 0 : if (oidstr[0] == '\0') {
1308 0 : found = &asn1_oid_tcg_tpm20;
1309 : } else {
1310 0 : ret = der_find_heim_oid_by_name(oidstr, &found);
1311 0 : if (ret) {
1312 0 : ret = der_parse_heim_oid(oidstr, " .", &oid);
1313 0 : if (ret == 0)
1314 0 : found = &oid;
1315 : }
1316 : }
1317 0 : if (!found) {
1318 0 : hx509_set_error_string(context, 0, EINVAL,
1319 : "Could not resolve or parse OID \"%s\"",
1320 : oidstr);
1321 0 : free(freeme);
1322 0 : return EINVAL;
1323 : }
1324 0 : ret = hx509_ca_tbs_add_san_hardwareModuleName(context, tbs, found, sno);
1325 0 : if (found == &oid)
1326 0 : der_free_oid(&oid);
1327 0 : free(freeme);
1328 0 : return ret;
1329 : }
1330 :
1331 : /**
1332 : * Add a Subject Alternative Name of HardwareModuleName type to a to-be-signed
1333 : * certificate object.
1334 : *
1335 : * @param context A hx509 context.
1336 : * @param tbs object to be signed.
1337 : * @param hwtype The hardwar module type (e.g., `&asn1_oid_tcg_tpm20').
1338 : * @param hwserial The serial number.
1339 : *
1340 : * @return An hx509 error code, see hx509_get_error_string().
1341 : *
1342 : * @ingroup hx509_ca
1343 : */
1344 :
1345 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1346 0 : hx509_ca_tbs_add_san_hardwareModuleName(hx509_context context,
1347 : hx509_ca_tbs tbs,
1348 : const heim_oid *hwtype,
1349 : const char *hwserial)
1350 : {
1351 : HardwareModuleName hm;
1352 : heim_octet_string os;
1353 : size_t size;
1354 : int ret;
1355 :
1356 0 : hm.hwType = *hwtype;
1357 0 : hm.hwSerialNum.data = (void *)(uintptr_t)hwserial;
1358 0 : hm.hwSerialNum.length = strlen(hwserial);
1359 0 : os.length = 0;
1360 0 : os.data = NULL;
1361 :
1362 0 : ASN1_MALLOC_ENCODE(HardwareModuleName, os.data, os.length, &hm, &size,
1363 : ret);
1364 0 : if (ret) {
1365 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1366 0 : return ret;
1367 : }
1368 0 : if (size != os.length)
1369 0 : _hx509_abort("internal ASN.1 encoder error");
1370 :
1371 0 : ret = hx509_ca_tbs_add_san_otherName(context, tbs,
1372 : &asn1_oid_id_on_hardwareModuleName,
1373 : &os);
1374 0 : free(os.data);
1375 0 : return ret;
1376 : }
1377 :
1378 : /**
1379 : * Add a Subject Alternative Name of the given type to the
1380 : * to-be-signed certificate object.
1381 : *
1382 : * @param context A hx509 context.
1383 : * @param tbs object to be signed.
1384 : * @param rfc822Name a string to a email address.
1385 : *
1386 : * @return An hx509 error code, see hx509_get_error_string().
1387 : *
1388 : * @ingroup hx509_ca
1389 : */
1390 :
1391 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1392 0 : hx509_ca_tbs_add_san(hx509_context context,
1393 : hx509_ca_tbs tbs,
1394 : hx509_san_type type,
1395 : const char *s)
1396 : {
1397 0 : switch (type) {
1398 0 : case HX509_SAN_TYPE_EMAIL:
1399 0 : return hx509_ca_tbs_add_san_rfc822name(context, tbs, s);
1400 0 : case HX509_SAN_TYPE_DNSNAME:
1401 0 : return hx509_ca_tbs_add_san_hostname(context, tbs, s);
1402 0 : case HX509_SAN_TYPE_DN:
1403 0 : return ENOTSUP;
1404 0 : case HX509_SAN_TYPE_REGISTERED_ID:
1405 0 : return ENOTSUP;
1406 0 : case HX509_SAN_TYPE_XMPP:
1407 0 : return hx509_ca_tbs_add_san_jid(context, tbs, s);
1408 0 : case HX509_SAN_TYPE_PKINIT:
1409 0 : return hx509_ca_tbs_add_san_pkinit(context, tbs, s);
1410 0 : case HX509_SAN_TYPE_MS_UPN:
1411 0 : return hx509_ca_tbs_add_san_ms_upn(context, tbs, s);
1412 0 : default:
1413 0 : return ENOTSUP;
1414 : }
1415 : }
1416 :
1417 : /**
1418 : * Set the subject name of a to-be-signed certificate object.
1419 : *
1420 : * @param context A hx509 context.
1421 : * @param tbs object to be signed.
1422 : * @param subject the name to set a subject.
1423 : *
1424 : * @return An hx509 error code, see hx509_get_error_string().
1425 : *
1426 : * @ingroup hx509_ca
1427 : */
1428 :
1429 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1430 0 : hx509_ca_tbs_set_subject(hx509_context context,
1431 : hx509_ca_tbs tbs,
1432 : hx509_name subject)
1433 : {
1434 0 : if (tbs->subject)
1435 0 : hx509_name_free(&tbs->subject);
1436 0 : return hx509_name_copy(context, subject, &tbs->subject);
1437 : }
1438 :
1439 : /**
1440 : * Set the issuerUniqueID and subjectUniqueID
1441 : *
1442 : * These are only supposed to be used considered with version 2
1443 : * certificates, replaced by the two extensions SubjectKeyIdentifier
1444 : * and IssuerKeyIdentifier. This function is to allow application
1445 : * using legacy protocol to issue them.
1446 : *
1447 : * @param context A hx509 context.
1448 : * @param tbs object to be signed.
1449 : * @param issuerUniqueID to be set
1450 : * @param subjectUniqueID to be set
1451 : *
1452 : * @return An hx509 error code, see hx509_get_error_string().
1453 : *
1454 : * @ingroup hx509_ca
1455 : */
1456 :
1457 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1458 0 : hx509_ca_tbs_set_unique(hx509_context context,
1459 : hx509_ca_tbs tbs,
1460 : const heim_bit_string *subjectUniqueID,
1461 : const heim_bit_string *issuerUniqueID)
1462 : {
1463 : int ret;
1464 :
1465 0 : der_free_bit_string(&tbs->subjectUniqueID);
1466 0 : der_free_bit_string(&tbs->issuerUniqueID);
1467 :
1468 0 : if (subjectUniqueID) {
1469 0 : ret = der_copy_bit_string(subjectUniqueID, &tbs->subjectUniqueID);
1470 0 : if (ret)
1471 0 : return ret;
1472 : }
1473 :
1474 0 : if (issuerUniqueID) {
1475 0 : ret = der_copy_bit_string(issuerUniqueID, &tbs->issuerUniqueID);
1476 0 : if (ret)
1477 0 : return ret;
1478 : }
1479 :
1480 0 : return 0;
1481 : }
1482 :
1483 : /**
1484 : * Expand the the subject name in the to-be-signed certificate object
1485 : * using hx509_name_expand().
1486 : *
1487 : * @param context A hx509 context.
1488 : * @param tbs object to be signed.
1489 : * @param env environment variable to expand variables in the subject
1490 : * name, see hx509_env_init().
1491 : *
1492 : * @return An hx509 error code, see hx509_get_error_string().
1493 : *
1494 : * @ingroup hx509_ca
1495 : */
1496 :
1497 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1498 0 : hx509_ca_tbs_subject_expand(hx509_context context,
1499 : hx509_ca_tbs tbs,
1500 : hx509_env env)
1501 : {
1502 0 : return hx509_name_expand(context, tbs->subject, env);
1503 : }
1504 :
1505 : /**
1506 : * Get the name of a to-be-signed certificate object.
1507 : *
1508 : * @param context A hx509 context.
1509 : * @param tbs object to be signed.
1510 : *
1511 : * @return An hx509 name.
1512 : *
1513 : * @ingroup hx509_ca
1514 : */
1515 :
1516 : HX509_LIB_FUNCTION hx509_name HX509_LIB_CALL
1517 0 : hx509_ca_tbs_get_name(hx509_ca_tbs tbs)
1518 : {
1519 0 : return tbs->subject;
1520 : }
1521 :
1522 : /**
1523 : * Set signature algorithm on the to be signed certificate
1524 : *
1525 : * @param context A hx509 context.
1526 : * @param tbs object to be signed.
1527 : * @param sigalg signature algorithm to use
1528 : *
1529 : * @return An hx509 error code, see hx509_get_error_string().
1530 : *
1531 : * @ingroup hx509_ca
1532 : */
1533 :
1534 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1535 0 : hx509_ca_tbs_set_signature_algorithm(hx509_context context,
1536 : hx509_ca_tbs tbs,
1537 : const AlgorithmIdentifier *sigalg)
1538 : {
1539 : int ret;
1540 :
1541 0 : tbs->sigalg = calloc(1, sizeof(*tbs->sigalg));
1542 0 : if (tbs->sigalg == NULL) {
1543 0 : hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
1544 0 : return ENOMEM;
1545 : }
1546 0 : ret = copy_AlgorithmIdentifier(sigalg, tbs->sigalg);
1547 0 : if (ret) {
1548 0 : free(tbs->sigalg);
1549 0 : tbs->sigalg = NULL;
1550 0 : return ret;
1551 : }
1552 0 : return 0;
1553 : }
1554 :
1555 : /*
1556 : *
1557 : */
1558 :
1559 : static int
1560 0 : add_extension(hx509_context context,
1561 : TBSCertificate *tbsc,
1562 : int critical_flag,
1563 : const heim_oid *oid,
1564 : const heim_octet_string *data)
1565 : {
1566 : Extension ext;
1567 : int ret;
1568 :
1569 0 : memset(&ext, 0, sizeof(ext));
1570 :
1571 0 : ext.critical = critical_flag;
1572 0 : ret = der_copy_oid(oid, &ext.extnID);
1573 0 : if (ret) {
1574 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1575 0 : goto out;
1576 : }
1577 0 : ret = der_copy_octet_string(data, &ext.extnValue);
1578 0 : if (ret) {
1579 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1580 0 : goto out;
1581 : }
1582 0 : ret = add_Extensions(tbsc->extensions, &ext);
1583 0 : if (ret) {
1584 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1585 0 : goto out;
1586 : }
1587 0 : out:
1588 0 : free_Extension(&ext);
1589 0 : return ret;
1590 : }
1591 :
1592 : static int
1593 0 : build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject)
1594 : {
1595 : char *tstr;
1596 : time_t t;
1597 : int ret;
1598 :
1599 0 : ret = copy_Name(issuer, subject);
1600 0 : if (ret) {
1601 0 : hx509_set_error_string(context, 0, ret,
1602 : "Failed to copy subject name");
1603 0 : return ret;
1604 : }
1605 :
1606 0 : t = time(NULL);
1607 0 : ret = asprintf(&tstr, "ts-%lu", (unsigned long)t);
1608 0 : if (ret == -1 || tstr == NULL) {
1609 0 : hx509_set_error_string(context, 0, ENOMEM,
1610 : "Failed to copy subject name");
1611 0 : return ENOMEM;
1612 : }
1613 : /* prefix with CN=<ts>,...*/
1614 0 : ret = _hx509_name_modify(context, subject, 1, &asn1_oid_id_at_commonName, tstr);
1615 0 : free(tstr);
1616 0 : if (ret)
1617 0 : free_Name(subject);
1618 0 : return ret;
1619 : }
1620 :
1621 : static int
1622 0 : ca_sign(hx509_context context,
1623 : hx509_ca_tbs tbs,
1624 : hx509_private_key signer,
1625 : const AuthorityKeyIdentifier *ai,
1626 : const Name *issuername,
1627 : hx509_cert *certificate)
1628 : {
1629 0 : heim_error_t error = NULL;
1630 : heim_octet_string data;
1631 : Certificate c;
1632 : TBSCertificate *tbsc;
1633 : size_t size;
1634 : int ret;
1635 : const AlgorithmIdentifier *sigalg;
1636 : time_t notBefore;
1637 : time_t notAfter;
1638 :
1639 0 : sigalg = tbs->sigalg;
1640 0 : if (sigalg == NULL)
1641 0 : sigalg = _hx509_crypto_default_sig_alg;
1642 :
1643 0 : memset(&c, 0, sizeof(c));
1644 :
1645 : /*
1646 : * Default values are: Valid since 24h ago, valid one year into
1647 : * the future, KeyUsage digitalSignature and keyEncipherment set,
1648 : * and keyCertSign for CA certificates.
1649 : */
1650 0 : notBefore = tbs->notBefore;
1651 0 : if (notBefore == 0)
1652 0 : notBefore = time(NULL) - 3600 * 24;
1653 0 : notAfter = tbs->notAfter;
1654 0 : if (notAfter == 0)
1655 0 : notAfter = time(NULL) + 3600 * 24 * 365;
1656 :
1657 0 : if (tbs->flags.ca) {
1658 0 : tbs->ku.keyCertSign = 1;
1659 0 : tbs->ku.cRLSign = 1;
1660 0 : } else if (KeyUsage2int(tbs->ku) == 0) {
1661 0 : tbs->ku.digitalSignature = 1;
1662 0 : tbs->ku.keyEncipherment = 1;
1663 : }
1664 :
1665 : /*
1666 : *
1667 : */
1668 :
1669 0 : tbsc = &c.tbsCertificate;
1670 :
1671 : /* Default subject Name to empty */
1672 0 : if (tbs->subject == NULL &&
1673 0 : (ret = hx509_empty_name(context, &tbs->subject)))
1674 0 : return ret;
1675 :
1676 : /* Sanity checks */
1677 0 : if (tbs->flags.key == 0) {
1678 0 : ret = EINVAL;
1679 0 : hx509_set_error_string(context, 0, ret, "No public key set");
1680 0 : return ret;
1681 : }
1682 : /*
1683 : * Don't put restrictions on proxy certificate's subject name, it
1684 : * will be generated below.
1685 : */
1686 0 : if (!tbs->flags.proxy) {
1687 0 : if (hx509_name_is_null_p(tbs->subject) && tbs->san.len == 0) {
1688 0 : hx509_set_error_string(context, 0, EINVAL,
1689 : "Empty subject and no SubjectAltNames");
1690 0 : return EINVAL;
1691 : }
1692 : }
1693 0 : if (tbs->flags.ca && tbs->flags.proxy) {
1694 0 : hx509_set_error_string(context, 0, EINVAL, "Can't be proxy and CA "
1695 : "at the same time");
1696 0 : return EINVAL;
1697 : }
1698 0 : if (tbs->flags.proxy) {
1699 0 : if (tbs->san.len > 0) {
1700 0 : hx509_set_error_string(context, 0, EINVAL,
1701 : "Proxy certificate is not allowed "
1702 : "to have SubjectAltNames");
1703 0 : return EINVAL;
1704 : }
1705 : }
1706 :
1707 : /* version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */
1708 0 : tbsc->version = calloc(1, sizeof(*tbsc->version));
1709 0 : if (tbsc->version == NULL) {
1710 0 : ret = ENOMEM;
1711 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1712 0 : goto out;
1713 : }
1714 0 : *tbsc->version = rfc3280_version_3;
1715 : /* serialNumber CertificateSerialNumber, */
1716 0 : if (tbs->flags.serial) {
1717 0 : ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber);
1718 0 : if (ret) {
1719 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1720 0 : goto out;
1721 : }
1722 : } else {
1723 : /*
1724 : * If no explicit serial number is specified, 20 random bytes should be
1725 : * sufficiently collision resistant. Since the serial number must be a
1726 : * positive integer, ensure minimal ASN.1 DER form by forcing the high
1727 : * bit off and the next bit on (thus avoiding an all zero first octet).
1728 : */
1729 0 : tbsc->serialNumber.length = 20;
1730 0 : tbsc->serialNumber.data = malloc(tbsc->serialNumber.length);
1731 0 : if (tbsc->serialNumber.data == NULL){
1732 0 : ret = ENOMEM;
1733 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1734 0 : goto out;
1735 : }
1736 0 : RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length);
1737 0 : ((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f;
1738 0 : ((unsigned char *)tbsc->serialNumber.data)[0] |= 0x40;
1739 : }
1740 : /* signature AlgorithmIdentifier, */
1741 0 : ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature);
1742 0 : if (ret) {
1743 0 : hx509_set_error_string(context, 0, ret, "Failed to copy signature alg");
1744 0 : goto out;
1745 : }
1746 : /* issuer Name, */
1747 0 : if (issuername)
1748 0 : ret = copy_Name(issuername, &tbsc->issuer);
1749 : else
1750 0 : ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer);
1751 0 : if (ret) {
1752 0 : hx509_set_error_string(context, 0, ret, "Failed to copy issuer name");
1753 0 : goto out;
1754 : }
1755 : /* validity Validity, */
1756 : {
1757 : /*
1758 : * From RFC 5280, section 4.1.2.5:
1759 : *
1760 : * CAs conforming to this profile MUST always encode certificate
1761 : * validity dates through the year 2049 as UTCTime; certificate validity
1762 : * dates in 2050 or later MUST be encoded as GeneralizedTime.
1763 : * Conforming applications MUST be able to process validity dates that
1764 : * are encoded in either UTCTime or GeneralizedTime.
1765 : *
1766 : * 2524608000 is seconds since the epoch for 2050-01-01T00:00:00Z.
1767 : *
1768 : * Both, ...u.generalTime and ...u..utcTime are time_t.
1769 : */
1770 0 : if (notBefore < 1 || (int64_t)notBefore < 2524608000)
1771 0 : tbsc->validity.notBefore.element = choice_Time_utcTime;
1772 : else
1773 0 : tbsc->validity.notBefore.element = choice_Time_generalTime;
1774 0 : tbsc->validity.notBefore.u.generalTime = notBefore;
1775 :
1776 0 : if (notAfter < 1 || (int64_t)notAfter < 2524608000)
1777 0 : tbsc->validity.notAfter.element = choice_Time_utcTime;
1778 : else
1779 0 : tbsc->validity.notAfter.element = choice_Time_generalTime;
1780 0 : tbsc->validity.notAfter.u.generalTime = notAfter;
1781 : }
1782 : /* subject Name, */
1783 0 : if (tbs->flags.proxy) {
1784 0 : ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject);
1785 0 : if (ret)
1786 0 : goto out;
1787 : } else {
1788 0 : ret = hx509_name_to_Name(tbs->subject, &tbsc->subject);
1789 0 : if (ret) {
1790 0 : hx509_set_error_string(context, 0, ret,
1791 : "Failed to copy subject name");
1792 0 : goto out;
1793 : }
1794 : }
1795 : /* subjectPublicKeyInfo SubjectPublicKeyInfo, */
1796 0 : ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo);
1797 0 : if (ret) {
1798 0 : hx509_set_error_string(context, 0, ret, "Failed to copy spki");
1799 0 : goto out;
1800 : }
1801 : /* issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL */
1802 0 : if (tbs->issuerUniqueID.length) {
1803 0 : tbsc->issuerUniqueID = calloc(1, sizeof(*tbsc->issuerUniqueID));
1804 0 : if (tbsc->issuerUniqueID == NULL) {
1805 0 : ret = ENOMEM;
1806 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1807 0 : goto out;
1808 : }
1809 0 : ret = der_copy_bit_string(&tbs->issuerUniqueID, tbsc->issuerUniqueID);
1810 0 : if (ret) {
1811 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1812 0 : goto out;
1813 : }
1814 : }
1815 : /* subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL */
1816 0 : if (tbs->subjectUniqueID.length) {
1817 0 : tbsc->subjectUniqueID = calloc(1, sizeof(*tbsc->subjectUniqueID));
1818 0 : if (tbsc->subjectUniqueID == NULL) {
1819 0 : ret = ENOMEM;
1820 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1821 0 : goto out;
1822 : }
1823 :
1824 0 : ret = der_copy_bit_string(&tbs->subjectUniqueID, tbsc->subjectUniqueID);
1825 0 : if (ret) {
1826 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1827 0 : goto out;
1828 : }
1829 : }
1830 :
1831 : /* extensions [3] EXPLICIT Extensions OPTIONAL */
1832 0 : tbsc->extensions = calloc(1, sizeof(*tbsc->extensions));
1833 0 : if (tbsc->extensions == NULL) {
1834 0 : ret = ENOMEM;
1835 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1836 0 : goto out;
1837 : }
1838 :
1839 : /* Add the text BMP string Domaincontroller to the cert */
1840 0 : if (tbs->flags.domaincontroller) {
1841 0 : data.data = rk_UNCONST("\x1e\x20\x00\x44\x00\x6f\x00\x6d"
1842 : "\x00\x61\x00\x69\x00\x6e\x00\x43"
1843 : "\x00\x6f\x00\x6e\x00\x74\x00\x72"
1844 : "\x00\x6f\x00\x6c\x00\x6c\x00\x65"
1845 : "\x00\x72");
1846 0 : data.length = 34;
1847 :
1848 0 : ret = add_extension(context, tbsc, 0,
1849 : &asn1_oid_id_ms_cert_enroll_domaincontroller,
1850 : &data);
1851 0 : if (ret)
1852 0 : goto out;
1853 : }
1854 :
1855 : /* Add KeyUsage */
1856 0 : if (KeyUsage2int(tbs->ku) > 0) {
1857 0 : ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length,
1858 : &tbs->ku, &size, ret);
1859 0 : if (ret) {
1860 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1861 0 : goto out;
1862 : }
1863 0 : if (size != data.length)
1864 0 : _hx509_abort("internal ASN.1 encoder error");
1865 0 : ret = add_extension(context, tbsc, 1,
1866 : &asn1_oid_id_x509_ce_keyUsage, &data);
1867 0 : free(data.data);
1868 0 : if (ret)
1869 0 : goto out;
1870 : }
1871 :
1872 : /* Add ExtendedKeyUsage */
1873 0 : if (tbs->eku.len > 0) {
1874 0 : ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length,
1875 : &tbs->eku, &size, ret);
1876 0 : if (ret) {
1877 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1878 0 : goto out;
1879 : }
1880 0 : if (size != data.length)
1881 0 : _hx509_abort("internal ASN.1 encoder error");
1882 0 : ret = add_extension(context, tbsc, 1,
1883 : &asn1_oid_id_x509_ce_extKeyUsage, &data);
1884 0 : free(data.data);
1885 0 : if (ret)
1886 0 : goto out;
1887 : }
1888 :
1889 : /* Add Subject Alternative Name */
1890 0 : if (tbs->san.len > 0) {
1891 0 : ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length,
1892 : &tbs->san, &size, ret);
1893 0 : if (ret) {
1894 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1895 0 : goto out;
1896 : }
1897 0 : if (size != data.length)
1898 0 : _hx509_abort("internal ASN.1 encoder error");
1899 :
1900 : /* The SAN extension is critical if the subject Name is empty */
1901 0 : ret = add_extension(context, tbsc, hx509_name_is_null_p(tbs->subject),
1902 : &asn1_oid_id_x509_ce_subjectAltName, &data);
1903 0 : free(data.data);
1904 0 : if (ret)
1905 0 : goto out;
1906 : }
1907 :
1908 : /* Add Authority Key Identifier */
1909 0 : if (ai) {
1910 0 : ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length,
1911 : ai, &size, ret);
1912 0 : if (ret) {
1913 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1914 0 : goto out;
1915 : }
1916 0 : if (size != data.length)
1917 0 : _hx509_abort("internal ASN.1 encoder error");
1918 0 : ret = add_extension(context, tbsc, 0,
1919 : &asn1_oid_id_x509_ce_authorityKeyIdentifier,
1920 : &data);
1921 0 : free(data.data);
1922 0 : if (ret)
1923 0 : goto out;
1924 : }
1925 :
1926 : /* Add Subject Key Identifier */
1927 : {
1928 : SubjectKeyIdentifier si;
1929 : unsigned char hash[SHA_DIGEST_LENGTH];
1930 :
1931 : {
1932 : EVP_MD_CTX *ctx;
1933 :
1934 0 : ctx = EVP_MD_CTX_create();
1935 0 : EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
1936 0 : EVP_DigestUpdate(ctx, tbs->spki.subjectPublicKey.data,
1937 0 : tbs->spki.subjectPublicKey.length / 8);
1938 0 : EVP_DigestFinal_ex(ctx, hash, NULL);
1939 0 : EVP_MD_CTX_destroy(ctx);
1940 : }
1941 :
1942 0 : si.data = hash;
1943 0 : si.length = sizeof(hash);
1944 :
1945 0 : ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length,
1946 : &si, &size, ret);
1947 0 : if (ret) {
1948 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1949 0 : goto out;
1950 : }
1951 0 : if (size != data.length)
1952 0 : _hx509_abort("internal ASN.1 encoder error");
1953 0 : ret = add_extension(context, tbsc, 0,
1954 : &asn1_oid_id_x509_ce_subjectKeyIdentifier,
1955 : &data);
1956 0 : free(data.data);
1957 0 : if (ret)
1958 0 : goto out;
1959 : }
1960 :
1961 : /* Add BasicConstraints */
1962 : {
1963 : BasicConstraints bc;
1964 : unsigned int path;
1965 :
1966 0 : memset(&bc, 0, sizeof(bc));
1967 :
1968 0 : if (tbs->flags.ca) {
1969 0 : bc.cA = 1;
1970 0 : if (tbs->pathLenConstraint >= 0) {
1971 0 : path = tbs->pathLenConstraint;
1972 0 : bc.pathLenConstraint = &path;
1973 : }
1974 : }
1975 :
1976 0 : ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length,
1977 : &bc, &size, ret);
1978 0 : if (ret) {
1979 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
1980 0 : goto out;
1981 : }
1982 0 : if (size != data.length)
1983 0 : _hx509_abort("internal ASN.1 encoder error");
1984 : /* Critical if this is a CA */
1985 0 : ret = add_extension(context, tbsc, tbs->flags.ca,
1986 : &asn1_oid_id_x509_ce_basicConstraints,
1987 : &data);
1988 0 : free(data.data);
1989 0 : if (ret)
1990 0 : goto out;
1991 : }
1992 :
1993 : /* Add Proxy */
1994 0 : if (tbs->flags.proxy) {
1995 : ProxyCertInfo info;
1996 :
1997 0 : memset(&info, 0, sizeof(info));
1998 :
1999 0 : if (tbs->pathLenConstraint >= 0) {
2000 0 : info.pCPathLenConstraint =
2001 0 : malloc(sizeof(*info.pCPathLenConstraint));
2002 0 : if (info.pCPathLenConstraint == NULL) {
2003 0 : ret = ENOMEM;
2004 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2005 0 : goto out;
2006 : }
2007 0 : *info.pCPathLenConstraint = tbs->pathLenConstraint;
2008 : }
2009 :
2010 0 : ret = der_copy_oid(&asn1_oid_id_pkix_ppl_inheritAll,
2011 : &info.proxyPolicy.policyLanguage);
2012 0 : if (ret) {
2013 0 : free_ProxyCertInfo(&info);
2014 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2015 0 : goto out;
2016 : }
2017 :
2018 0 : ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length,
2019 : &info, &size, ret);
2020 0 : free_ProxyCertInfo(&info);
2021 0 : if (ret) {
2022 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2023 0 : goto out;
2024 : }
2025 0 : if (size != data.length)
2026 0 : _hx509_abort("internal ASN.1 encoder error");
2027 0 : ret = add_extension(context, tbsc, 0,
2028 : &asn1_oid_id_pkix_pe_proxyCertInfo,
2029 : &data);
2030 0 : free(data.data);
2031 0 : if (ret)
2032 0 : goto out;
2033 : }
2034 :
2035 : /* Add CRL distribution point */
2036 0 : if (tbs->crldp.len) {
2037 0 : ASN1_MALLOC_ENCODE(CRLDistributionPoints, data.data, data.length,
2038 : &tbs->crldp, &size, ret);
2039 0 : if (ret) {
2040 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2041 0 : goto out;
2042 : }
2043 0 : if (size != data.length)
2044 0 : _hx509_abort("internal ASN.1 encoder error");
2045 0 : ret = add_extension(context, tbsc, FALSE,
2046 : &asn1_oid_id_x509_ce_cRLDistributionPoints,
2047 : &data);
2048 0 : free(data.data);
2049 0 : if (ret)
2050 0 : goto out;
2051 : }
2052 :
2053 : /* Add CertificatePolicies */
2054 0 : if (tbs->cps.len) {
2055 0 : ASN1_MALLOC_ENCODE(CertificatePolicies, data.data, data.length,
2056 : &tbs->cps, &size, ret);
2057 0 : if (ret) {
2058 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2059 0 : goto out;
2060 : }
2061 0 : if (size != data.length)
2062 0 : _hx509_abort("internal ASN.1 encoder error");
2063 0 : ret = add_extension(context, tbsc, FALSE,
2064 : &asn1_oid_id_x509_ce_certificatePolicies, &data);
2065 0 : free(data.data);
2066 0 : if (ret)
2067 0 : goto out;
2068 : }
2069 :
2070 : /* Add PolicyMappings */
2071 0 : if (tbs->cps.len) {
2072 0 : ASN1_MALLOC_ENCODE(PolicyMappings, data.data, data.length,
2073 : &tbs->pms, &size, ret);
2074 0 : if (ret) {
2075 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2076 0 : goto out;
2077 : }
2078 0 : if (size != data.length)
2079 0 : _hx509_abort("internal ASN.1 encoder error");
2080 0 : ret = add_extension(context, tbsc, FALSE,
2081 : &asn1_oid_id_x509_ce_policyMappings, &data);
2082 0 : free(data.data);
2083 0 : if (ret)
2084 0 : goto out;
2085 : }
2086 :
2087 : /* Add Heimdal PKINIT ticket max life extension */
2088 0 : if (tbs->pkinitTicketMaxLife > 0) {
2089 0 : ASN1_MALLOC_ENCODE(HeimPkinitPrincMaxLifeSecs, data.data, data.length,
2090 : &tbs->pkinitTicketMaxLife, &size, ret);
2091 0 : if (ret) {
2092 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2093 0 : goto out;
2094 : }
2095 0 : if (size != data.length)
2096 0 : _hx509_abort("internal ASN.1 encoder error");
2097 0 : ret = add_extension(context, tbsc, FALSE,
2098 : &asn1_oid_id_heim_ce_pkinit_princ_max_life, &data);
2099 0 : free(data.data);
2100 0 : if (ret)
2101 0 : goto out;
2102 : }
2103 :
2104 0 : ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret);
2105 0 : if (ret) {
2106 0 : hx509_set_error_string(context, 0, ret, "malloc out of memory");
2107 0 : goto out;
2108 : }
2109 0 : if (data.length != size)
2110 0 : _hx509_abort("internal ASN.1 encoder error");
2111 :
2112 0 : ret = _hx509_create_signature_bitstring(context,
2113 : signer,
2114 : sigalg,
2115 : &data,
2116 : &c.signatureAlgorithm,
2117 : &c.signatureValue);
2118 0 : free(data.data);
2119 0 : if (ret)
2120 0 : goto out;
2121 :
2122 0 : *certificate = hx509_cert_init(context, &c, &error);
2123 0 : if (*certificate == NULL) {
2124 0 : ret = heim_error_get_code(error);
2125 0 : heim_release(error);
2126 0 : goto out;
2127 : }
2128 :
2129 0 : free_Certificate(&c);
2130 :
2131 0 : return 0;
2132 :
2133 0 : out:
2134 0 : free_Certificate(&c);
2135 0 : return ret;
2136 : }
2137 :
2138 : static int
2139 0 : get_AuthorityKeyIdentifier(hx509_context context,
2140 : const Certificate *certificate,
2141 : AuthorityKeyIdentifier *ai)
2142 : {
2143 : SubjectKeyIdentifier si;
2144 : int ret;
2145 :
2146 0 : ret = _hx509_find_extension_subject_key_id(certificate, &si);
2147 0 : if (ret == 0) {
2148 0 : ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier));
2149 0 : if (ai->keyIdentifier == NULL) {
2150 0 : free_SubjectKeyIdentifier(&si);
2151 0 : ret = ENOMEM;
2152 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2153 0 : goto out;
2154 : }
2155 0 : ret = der_copy_octet_string(&si, ai->keyIdentifier);
2156 0 : free_SubjectKeyIdentifier(&si);
2157 0 : if (ret) {
2158 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2159 0 : goto out;
2160 : }
2161 : } else {
2162 : GeneralNames gns;
2163 : GeneralName gn;
2164 : Name name;
2165 :
2166 0 : memset(&gn, 0, sizeof(gn));
2167 0 : memset(&gns, 0, sizeof(gns));
2168 0 : memset(&name, 0, sizeof(name));
2169 :
2170 0 : ai->authorityCertIssuer =
2171 0 : calloc(1, sizeof(*ai->authorityCertIssuer));
2172 0 : if (ai->authorityCertIssuer == NULL) {
2173 0 : ret = ENOMEM;
2174 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2175 0 : goto out;
2176 : }
2177 0 : ai->authorityCertSerialNumber =
2178 0 : calloc(1, sizeof(*ai->authorityCertSerialNumber));
2179 0 : if (ai->authorityCertSerialNumber == NULL) {
2180 0 : ret = ENOMEM;
2181 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2182 0 : goto out;
2183 : }
2184 :
2185 : /*
2186 : * XXX unbreak when asn1 compiler handle IMPLICIT
2187 : *
2188 : * This is so horrible.
2189 : */
2190 :
2191 0 : ret = copy_Name(&certificate->tbsCertificate.subject, &name);
2192 0 : if (ret) {
2193 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2194 0 : goto out;
2195 : }
2196 :
2197 0 : memset(&gn, 0, sizeof(gn));
2198 0 : gn.element = choice_GeneralName_directoryName;
2199 0 : gn.u.directoryName.element = choice_Name_rdnSequence;
2200 0 : gn.u.directoryName.u.rdnSequence = name.u.rdnSequence;
2201 :
2202 0 : ret = add_GeneralNames(&gns, &gn);
2203 0 : if (ret) {
2204 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2205 0 : goto out;
2206 : }
2207 :
2208 0 : ai->authorityCertIssuer->val = gns.val;
2209 0 : ai->authorityCertIssuer->len = gns.len;
2210 :
2211 0 : ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber,
2212 : ai->authorityCertSerialNumber);
2213 0 : if (ai->authorityCertSerialNumber == NULL) {
2214 0 : ret = ENOMEM;
2215 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
2216 0 : goto out;
2217 : }
2218 : }
2219 0 : out:
2220 0 : if (ret)
2221 0 : free_AuthorityKeyIdentifier(ai);
2222 0 : return ret;
2223 : }
2224 :
2225 :
2226 : /**
2227 : * Sign a to-be-signed certificate object with a issuer certificate.
2228 : *
2229 : * The caller needs to at least have called the following functions on the
2230 : * to-be-signed certificate object:
2231 : * - hx509_ca_tbs_init()
2232 : * - hx509_ca_tbs_set_subject()
2233 : * - hx509_ca_tbs_set_spki()
2234 : *
2235 : * When done the to-be-signed certificate object should be freed with
2236 : * hx509_ca_tbs_free().
2237 : *
2238 : * When creating self-signed certificate use hx509_ca_sign_self() instead.
2239 : *
2240 : * @param context A hx509 context.
2241 : * @param tbs object to be signed.
2242 : * @param signer the CA certificate object to sign with (need private key).
2243 : * @param certificate return cerificate, free with hx509_cert_free().
2244 : *
2245 : * @return An hx509 error code, see hx509_get_error_string().
2246 : *
2247 : * @ingroup hx509_ca
2248 : */
2249 :
2250 : HX509_LIB_FUNCTION int HX509_LIB_CALL
2251 0 : hx509_ca_sign(hx509_context context,
2252 : hx509_ca_tbs tbs,
2253 : hx509_cert signer,
2254 : hx509_cert *certificate)
2255 : {
2256 : const Certificate *signer_cert;
2257 : AuthorityKeyIdentifier ai;
2258 : int ret;
2259 :
2260 0 : memset(&ai, 0, sizeof(ai));
2261 :
2262 0 : signer_cert = _hx509_get_cert(signer);
2263 :
2264 0 : ret = get_AuthorityKeyIdentifier(context, signer_cert, &ai);
2265 0 : if (ret)
2266 0 : goto out;
2267 :
2268 0 : ret = ca_sign(context,
2269 : tbs,
2270 : _hx509_cert_private_key(signer),
2271 : &ai,
2272 : &signer_cert->tbsCertificate.subject,
2273 : certificate);
2274 :
2275 0 : out:
2276 0 : free_AuthorityKeyIdentifier(&ai);
2277 :
2278 0 : return ret;
2279 : }
2280 :
2281 : /**
2282 : * Work just like hx509_ca_sign() but signs it-self.
2283 : *
2284 : * @param context A hx509 context.
2285 : * @param tbs object to be signed.
2286 : * @param signer private key to sign with.
2287 : * @param certificate return cerificate, free with hx509_cert_free().
2288 : *
2289 : * @return An hx509 error code, see hx509_get_error_string().
2290 : *
2291 : * @ingroup hx509_ca
2292 : */
2293 :
2294 : HX509_LIB_FUNCTION int HX509_LIB_CALL
2295 0 : hx509_ca_sign_self(hx509_context context,
2296 : hx509_ca_tbs tbs,
2297 : hx509_private_key signer,
2298 : hx509_cert *certificate)
2299 : {
2300 0 : return ca_sign(context,
2301 : tbs,
2302 : signer,
2303 : NULL,
2304 : NULL,
2305 : certificate);
2306 : }
2307 :
2308 : /*
2309 : * The following used to be `kdc_issue_certificate()', which was added for
2310 : * kx509 support in the kdc, then adapted for bx509d. It now has no
2311 : * kdc-specific code and very little krb5-specific code, and is named
2312 : * `hx509_ca_issue_certificate()'.
2313 : */
2314 :
2315 : /* From lib/krb5/principal.c */
2316 : #define princ_num_comp(P) ((P)->principalName.name_string.len)
2317 : #define princ_type(P) ((P)->principalName.name_type)
2318 : #define princ_comp(P) ((P)->principalName.name_string.val)
2319 : #define princ_ncomp(P, N) ((P)->principalName.name_string.val[(N)])
2320 : #define princ_realm(P) ((P)->realm)
2321 :
2322 : static const char *
2323 0 : princ_get_comp_string(KRB5PrincipalName *principal, unsigned int component)
2324 : {
2325 0 : if (component >= princ_num_comp(principal))
2326 0 : return NULL;
2327 0 : return princ_ncomp(principal, component);
2328 : }
2329 : /* XXX Add unparse_name() */
2330 :
2331 : typedef enum {
2332 : CERT_NOTSUP = 0,
2333 : CERT_CLIENT = 1,
2334 : CERT_SERVER = 2,
2335 : CERT_MIXED = 3
2336 : } cert_type;
2337 :
2338 : static void
2339 0 : frees(char **s)
2340 : {
2341 0 : free(*s);
2342 0 : *s = NULL;
2343 0 : }
2344 :
2345 : static heim_error_code
2346 0 : count_sans(hx509_request req, size_t *n)
2347 : {
2348 : size_t i;
2349 0 : char *s = NULL;
2350 0 : int ret = 0;
2351 :
2352 0 : *n = 0;
2353 0 : for (i = 0; ret == 0; i++) {
2354 : hx509_san_type san_type;
2355 :
2356 0 : ret = hx509_request_get_san(req, i, &san_type, &s);
2357 0 : if (ret)
2358 0 : break;
2359 0 : switch (san_type) {
2360 0 : case HX509_SAN_TYPE_DNSNAME:
2361 : case HX509_SAN_TYPE_EMAIL:
2362 : case HX509_SAN_TYPE_XMPP:
2363 : case HX509_SAN_TYPE_PKINIT:
2364 : case HX509_SAN_TYPE_MS_UPN:
2365 0 : (*n)++;
2366 0 : break;
2367 0 : default:
2368 0 : ret = ENOTSUP;
2369 : }
2370 0 : frees(&s);
2371 : }
2372 0 : free(s);
2373 0 : return ret == HX509_NO_ITEM ? 0 : ret;
2374 : }
2375 :
2376 : static int
2377 0 : has_sans(hx509_request req)
2378 : {
2379 : hx509_san_type san_type;
2380 0 : char *s = NULL;
2381 0 : int ret = hx509_request_get_san(req, 0, &san_type, &s);
2382 :
2383 0 : frees(&s);
2384 0 : return ret == HX509_NO_ITEM ? 0 : 1;
2385 : }
2386 :
2387 : static cert_type
2388 0 : characterize_cprinc(hx509_context context,
2389 : KRB5PrincipalName *cprinc)
2390 : {
2391 0 : unsigned int ncomp = princ_num_comp(cprinc);
2392 0 : const char *comp1 = princ_get_comp_string(cprinc, 1);
2393 :
2394 0 : switch (ncomp) {
2395 0 : case 1:
2396 0 : return CERT_CLIENT;
2397 0 : case 2:
2398 0 : if (strchr(comp1, '.') == NULL)
2399 0 : return CERT_CLIENT;
2400 0 : return CERT_SERVER;
2401 0 : case 3:
2402 0 : if (strchr(comp1, '.'))
2403 0 : return CERT_SERVER;
2404 0 : return CERT_NOTSUP;
2405 0 : default:
2406 0 : return CERT_NOTSUP;
2407 : }
2408 : }
2409 :
2410 : /* Characterize request as client or server cert req */
2411 : static cert_type
2412 0 : characterize(hx509_context context,
2413 : KRB5PrincipalName *cprinc,
2414 : hx509_request req)
2415 : {
2416 0 : heim_error_code ret = 0;
2417 0 : cert_type res = CERT_NOTSUP;
2418 : size_t i;
2419 0 : char *s = NULL;
2420 0 : int want_ekus = 0;
2421 :
2422 0 : if (!has_sans(req))
2423 0 : return characterize_cprinc(context, cprinc);
2424 :
2425 0 : for (i = 0; ret == 0; i++) {
2426 : heim_oid oid;
2427 :
2428 0 : frees(&s);
2429 0 : ret = hx509_request_get_eku(req, i, &s);
2430 0 : if (ret)
2431 0 : break;
2432 :
2433 0 : want_ekus = 1;
2434 0 : ret = der_parse_heim_oid(s, ".", &oid);
2435 0 : if (ret)
2436 0 : break;
2437 : /*
2438 : * If the client wants only a server certificate, then we'll be
2439 : * willing to issue one that may be longer-lived than the client's
2440 : * ticket/token.
2441 : *
2442 : * There may be other server EKUs, but these are the ones we know
2443 : * of.
2444 : */
2445 0 : if (der_heim_oid_cmp(&asn1_oid_id_pkix_kp_serverAuth, &oid) &&
2446 0 : der_heim_oid_cmp(&asn1_oid_id_pkix_kp_OCSPSigning, &oid) &&
2447 0 : der_heim_oid_cmp(&asn1_oid_id_pkix_kp_secureShellServer, &oid))
2448 0 : res |= CERT_CLIENT;
2449 : else
2450 0 : res |= CERT_SERVER;
2451 0 : der_free_oid(&oid);
2452 : }
2453 0 : frees(&s);
2454 0 : if (ret == HX509_NO_ITEM)
2455 0 : ret = 0;
2456 :
2457 0 : for (i = 0; ret == 0; i++) {
2458 : hx509_san_type san_type;
2459 :
2460 0 : frees(&s);
2461 0 : ret = hx509_request_get_san(req, i, &san_type, &s);
2462 0 : if (ret)
2463 0 : break;
2464 0 : switch (san_type) {
2465 0 : case HX509_SAN_TYPE_DNSNAME:
2466 0 : if (!want_ekus)
2467 0 : res |= CERT_SERVER;
2468 0 : break;
2469 0 : case HX509_SAN_TYPE_EMAIL:
2470 : case HX509_SAN_TYPE_XMPP:
2471 : case HX509_SAN_TYPE_PKINIT:
2472 : case HX509_SAN_TYPE_MS_UPN:
2473 0 : if (!want_ekus)
2474 0 : res |= CERT_CLIENT;
2475 0 : break;
2476 0 : default:
2477 0 : ret = ENOTSUP;
2478 : }
2479 0 : if (ret)
2480 0 : break;
2481 : }
2482 0 : frees(&s);
2483 0 : if (ret == HX509_NO_ITEM)
2484 0 : ret = 0;
2485 0 : return ret ? CERT_NOTSUP : res;
2486 : }
2487 :
2488 : /*
2489 : * Get a configuration sub-tree for kx509 based on what's being requested and
2490 : * by whom.
2491 : *
2492 : * We have a number of cases:
2493 : *
2494 : * - default certificate (no CSR used, or no certificate extensions requested)
2495 : * - for client principals
2496 : * - for service principals
2497 : * - client certificate requested (CSR used and client-y SANs/EKUs requested)
2498 : * - server certificate requested (CSR used and server-y SANs/EKUs requested)
2499 : * - mixed client/server certificate requested (...)
2500 : */
2501 : static heim_error_code
2502 0 : get_cf(hx509_context context,
2503 : const heim_config_binding *cf,
2504 : heim_log_facility *logf,
2505 : hx509_request req,
2506 : KRB5PrincipalName *cprinc,
2507 : const heim_config_binding **out)
2508 : {
2509 : heim_error_code ret;
2510 0 : unsigned int ncomp = princ_num_comp(cprinc);
2511 0 : const char *realm = princ_realm(cprinc);
2512 0 : const char *comp0 = princ_get_comp_string(cprinc, 0);
2513 0 : const char *comp1 = princ_get_comp_string(cprinc, 1);
2514 0 : const char *label = NULL;
2515 0 : const char *svc = NULL;
2516 0 : const char *def = NULL;
2517 0 : cert_type certtype = CERT_NOTSUP;
2518 0 : size_t nsans = 0;
2519 :
2520 0 : *out = NULL;
2521 0 : if (ncomp == 0) {
2522 0 : heim_log_msg(context->hcontext, logf, 5, NULL,
2523 : "Client principal has no components!");
2524 0 : hx509_set_error_string(context, 0, ret = ENOTSUP,
2525 : "Client principal has no components!");
2526 0 : return ret;
2527 : }
2528 :
2529 0 : if ((ret = count_sans(req, &nsans)) ||
2530 : (certtype = characterize(context, cprinc, req)) == CERT_NOTSUP) {
2531 0 : heim_log_msg(context->hcontext, logf, 5, NULL,
2532 : "Could not characterize CSR");
2533 0 : hx509_set_error_string(context, 0, ret, "Could not characterize CSR");
2534 0 : return ret;
2535 : }
2536 :
2537 0 : if (nsans) {
2538 0 : def = "custom";
2539 : /* Client requested some certificate extension, a SAN or EKU */
2540 0 : switch (certtype) {
2541 0 : case CERT_MIXED: label = "mixed"; break;
2542 0 : case CERT_CLIENT: label = "client"; break;
2543 0 : case CERT_SERVER: label = "server"; break;
2544 0 : default:
2545 0 : hx509_set_error_string(context, 0, ret = ENOTSUP,
2546 : "Requested SAN/EKU combination not "
2547 : "supported");
2548 0 : return ret;
2549 : }
2550 : } else {
2551 0 : def = "default";
2552 : /* Default certificate desired */
2553 0 : if (ncomp == 1) {
2554 0 : label = "user";
2555 0 : } else if (ncomp == 2 && strcmp(comp1, "root") == 0) {
2556 0 : label = "root_user";
2557 0 : } else if (ncomp == 2 && strcmp(comp1, "admin") == 0) {
2558 0 : label = "admin_user";
2559 0 : } else if (strchr(comp1, '.')) {
2560 0 : label = "hostbased_service";
2561 0 : svc = comp0;
2562 : } else {
2563 0 : label = "other";
2564 : }
2565 : }
2566 :
2567 0 : *out = heim_config_get_list(context->hcontext, cf, label, svc, NULL);
2568 0 : if (*out) {
2569 0 : ret = 0;
2570 : } else {
2571 0 : heim_log_msg(context->hcontext, logf, 3, NULL,
2572 : "No configuration for %s %s certificate's realm "
2573 : "-> %s -> kx509 -> %s%s%s", def, label, realm, label,
2574 : svc ? " -> " : "", svc ? svc : "");
2575 0 : hx509_set_error_string(context, 0, EACCES,
2576 : "No configuration for %s %s certificate's realm "
2577 : "-> %s -> kx509 -> %s%s%s", def, label, realm, label,
2578 : svc ? " -> " : "", svc ? svc : "");
2579 : }
2580 0 : return ret;
2581 : }
2582 :
2583 :
2584 : /*
2585 : * Find and set a certificate template using a configuration sub-tree
2586 : * appropriate to the requesting principal.
2587 : *
2588 : * This allows for the specification of the following in configuration:
2589 : *
2590 : * - certificates as templates, with ${var} tokens in subjectName attribute
2591 : * values that will be expanded later
2592 : * - a plain string with ${var} tokens to use as the subjectName
2593 : * - EKUs
2594 : * - whether to include a PKINIT SAN
2595 : */
2596 : static heim_error_code
2597 0 : set_template(hx509_context context,
2598 : heim_log_facility *logf,
2599 : const heim_config_binding *cf,
2600 : hx509_ca_tbs tbs)
2601 : {
2602 0 : heim_error_code ret = 0;
2603 0 : const char *cert_template = NULL;
2604 0 : const char *subj_name = NULL;
2605 0 : char **ekus = NULL;
2606 :
2607 0 : if (cf == NULL)
2608 0 : return EACCES; /* Can't happen */
2609 :
2610 0 : cert_template = heim_config_get_string(context->hcontext, cf,
2611 : "template_cert", NULL);
2612 0 : subj_name = heim_config_get_string(context->hcontext, cf, "subject_name",
2613 : NULL);
2614 0 : ekus = heim_config_get_strings(context->hcontext, cf, "ekus", NULL);
2615 :
2616 0 : if (cert_template) {
2617 : hx509_certs certs;
2618 : hx509_cert template;
2619 :
2620 0 : ret = hx509_certs_init(context, cert_template, 0, NULL, &certs);
2621 0 : if (ret == 0)
2622 0 : ret = hx509_get_one_cert(context, certs, &template);
2623 0 : hx509_certs_free(&certs);
2624 0 : if (ret) {
2625 0 : heim_log_msg(context->hcontext, logf, 1, NULL,
2626 : "Failed to load certificate template from %s",
2627 : cert_template);
2628 0 : hx509_set_error_string(context, 0, EACCES,
2629 : "Failed to load certificate template from "
2630 : "%s", cert_template);
2631 0 : return ret;
2632 : }
2633 :
2634 : /*
2635 : * Only take the subjectName, the keyUsage, and EKUs from the template
2636 : * certificate.
2637 : */
2638 0 : ret = hx509_ca_tbs_set_template(context, tbs,
2639 : HX509_CA_TEMPLATE_SUBJECT |
2640 : HX509_CA_TEMPLATE_KU |
2641 : HX509_CA_TEMPLATE_EKU,
2642 : template);
2643 0 : hx509_cert_free(template);
2644 0 : if (ret)
2645 0 : return ret;
2646 : }
2647 :
2648 0 : if (subj_name) {
2649 0 : hx509_name dn = NULL;
2650 :
2651 0 : ret = hx509_parse_name(context, subj_name, &dn);
2652 0 : if (ret == 0)
2653 0 : ret = hx509_ca_tbs_set_subject(context, tbs, dn);
2654 0 : hx509_name_free(&dn);
2655 0 : if (ret)
2656 0 : return ret;
2657 : }
2658 :
2659 0 : if (cert_template == NULL && subj_name == NULL) {
2660 0 : hx509_name dn = NULL;
2661 :
2662 0 : ret = hx509_empty_name(context, &dn);
2663 0 : if (ret == 0)
2664 0 : ret = hx509_ca_tbs_set_subject(context, tbs, dn);
2665 0 : hx509_name_free(&dn);
2666 0 : if (ret)
2667 0 : return ret;
2668 : }
2669 :
2670 0 : if (ekus) {
2671 : size_t i;
2672 :
2673 0 : for (i = 0; ret == 0 && ekus[i]; i++) {
2674 0 : heim_oid oid = { 0, 0 };
2675 :
2676 0 : if ((ret = der_find_or_parse_heim_oid(ekus[i], ".", &oid)) == 0)
2677 0 : ret = hx509_ca_tbs_add_eku(context, tbs, &oid);
2678 0 : der_free_oid(&oid);
2679 : }
2680 0 : heim_config_free_strings(ekus);
2681 : }
2682 :
2683 : /*
2684 : * XXX A KeyUsage template would be nice, but it needs some smarts to
2685 : * remove, e.g., encipherOnly, decipherOnly, keyEncipherment, if the SPKI
2686 : * algorithm does not support encryption. The same logic should be added
2687 : * to hx509_ca_tbs_set_template()'s HX509_CA_TEMPLATE_KU functionality.
2688 : */
2689 0 : return ret;
2690 : }
2691 :
2692 : /*
2693 : * Find and set a certificate template, set "variables" in `env', and add add
2694 : * default SANs/EKUs as appropriate.
2695 : *
2696 : * TODO:
2697 : * - lookup a template for the client principal in its HDB entry
2698 : * - lookup subjectName, SANs for a principal in its HDB entry
2699 : * - lookup a host-based client principal's HDB entry and add its canonical
2700 : * name / aliases as dNSName SANs
2701 : * (this would have to be if requested by the client, perhaps)
2702 : */
2703 : static heim_error_code
2704 0 : set_tbs(hx509_context context,
2705 : heim_log_facility *logf,
2706 : const heim_config_binding *cf,
2707 : hx509_request req,
2708 : KRB5PrincipalName *cprinc,
2709 : hx509_env *env,
2710 : hx509_ca_tbs tbs)
2711 : {
2712 0 : KRB5PrincipalName cprinc_no_realm = *cprinc;
2713 : heim_error_code ret;
2714 0 : unsigned int ncomp = princ_num_comp(cprinc);
2715 0 : const char *realm = princ_realm(cprinc);
2716 0 : const char *comp0 = princ_get_comp_string(cprinc, 0);
2717 0 : const char *comp1 = princ_get_comp_string(cprinc, 1);
2718 0 : const char *comp2 = princ_get_comp_string(cprinc, 2);
2719 : struct rk_strpool *strpool;
2720 0 : char *princ_no_realm = NULL;
2721 0 : char *princ = NULL;
2722 :
2723 0 : strpool = _hx509_unparse_kerberos_name(NULL, cprinc);
2724 0 : if (strpool)
2725 0 : princ = rk_strpoolcollect(strpool);
2726 0 : cprinc_no_realm.realm = NULL;
2727 0 : strpool = _hx509_unparse_kerberos_name(NULL, &cprinc_no_realm);
2728 0 : if (strpool)
2729 0 : princ_no_realm = rk_strpoolcollect(strpool);
2730 0 : if (princ == NULL || princ_no_realm == NULL) {
2731 0 : free(princ);
2732 0 : return hx509_enomem(context);
2733 : }
2734 0 : strpool = NULL;
2735 0 : ret = hx509_env_add(context, env, "principal-name-without-realm",
2736 : princ_no_realm);
2737 0 : if (ret == 0)
2738 0 : ret = hx509_env_add(context, env, "principal-name", princ);
2739 0 : if (ret == 0)
2740 0 : ret = hx509_env_add(context, env, "principal-name-realm",
2741 : realm);
2742 :
2743 : /* Populate requested certificate extensions from CSR/CSRPlus if allowed */
2744 0 : if (ret == 0)
2745 0 : ret = hx509_ca_tbs_set_from_csr(context, tbs, req);
2746 0 : if (ret == 0)
2747 0 : ret = set_template(context, logf, cf, tbs);
2748 :
2749 : /*
2750 : * Optionally add PKINIT SAN.
2751 : *
2752 : * Adding an id-pkinit-san means the client can use the certificate to
2753 : * initiate PKINIT. That might seem odd, but it enables a sort of PKIX
2754 : * credential delegation by allowing forwarded Kerberos tickets to be
2755 : * used to acquire PKIX credentials. Thus this can work:
2756 : *
2757 : * PKIX (w/ HW token) -> Kerberos ->
2758 : * PKIX (w/ softtoken) -> Kerberos ->
2759 : * PKIX (w/ softtoken) -> Kerberos ->
2760 : * ...
2761 : *
2762 : * Note that we may not have added the PKINIT EKU -- that depends on the
2763 : * template, and host-based service templates might well not include it.
2764 : */
2765 0 : if (ret == 0 && !has_sans(req) &&
2766 0 : heim_config_get_bool_default(context->hcontext, cf, FALSE,
2767 : "include_pkinit_san", NULL)) {
2768 0 : ret = hx509_ca_tbs_add_san_pkinit(context, tbs, princ);
2769 : }
2770 :
2771 0 : if (ret)
2772 0 : goto out;
2773 :
2774 0 : if (ncomp == 1) {
2775 : const char *email_domain;
2776 :
2777 0 : ret = hx509_env_add(context, env, "principal-component0",
2778 : princ_no_realm);
2779 :
2780 : /*
2781 : * If configured, include an rfc822Name that's just the client's
2782 : * principal name sans realm @ configured email domain.
2783 : */
2784 0 : if (ret == 0 && !has_sans(req) &&
2785 0 : (email_domain = heim_config_get_string(context->hcontext, cf,
2786 : "email_domain", NULL))) {
2787 : char *email;
2788 :
2789 0 : if (asprintf(&email, "%s@%s", princ_no_realm, email_domain) == -1 ||
2790 0 : email == NULL)
2791 : goto enomem;
2792 0 : ret = hx509_ca_tbs_add_san_rfc822name(context, tbs, email);
2793 0 : free(email);
2794 : }
2795 0 : } else if (ncomp == 2 || ncomp == 3) {
2796 : /*
2797 : * 2- and 3-component principal name.
2798 : *
2799 : * We do not have a reliable name-type indicator. If the second
2800 : * component has a '.' in it then we'll assume that the name is a
2801 : * host-based (2-component) or domain-based (3-component) service
2802 : * principal name. Else we'll assume it's a two-component admin-style
2803 : * username.
2804 : */
2805 :
2806 0 : ret = hx509_env_add(context, env, "principal-component0", comp0);
2807 0 : if (ret == 0)
2808 0 : ret = hx509_env_add(context, env, "principal-component1", comp1);
2809 0 : if (ret == 0 && ncomp == 3)
2810 0 : ret = hx509_env_add(context, env, "principal-component2", comp2);
2811 0 : if (ret == 0 && strchr(comp1, '.')) {
2812 : /* Looks like host-based or domain-based service */
2813 0 : ret = hx509_env_add(context, env, "principal-service-name", comp0);
2814 0 : if (ret == 0)
2815 0 : ret = hx509_env_add(context, env, "principal-host-name",
2816 : comp1);
2817 0 : if (ret == 0 && ncomp == 3)
2818 0 : ret = hx509_env_add(context, env, "principal-domain-name",
2819 : comp2);
2820 0 : if (ret == 0 && !has_sans(req) &&
2821 0 : heim_config_get_bool_default(context->hcontext, cf, FALSE,
2822 : "include_dnsname_san", NULL)) {
2823 0 : ret = hx509_ca_tbs_add_san_hostname(context, tbs, comp1);
2824 : }
2825 : }
2826 : } else {
2827 0 : heim_log_msg(context->hcontext, logf, 5, NULL,
2828 : "kx509/bx509 client %s has too many components!", princ);
2829 0 : hx509_set_error_string(context, 0, ret = EACCES,
2830 : "kx509/bx509 client %s has too many "
2831 : "components!", princ);
2832 : }
2833 :
2834 0 : out:
2835 0 : if (ret == ENOMEM)
2836 0 : goto enomem;
2837 0 : free(princ_no_realm);
2838 0 : free(princ);
2839 0 : return ret;
2840 :
2841 0 : enomem:
2842 0 : heim_log_msg(context->hcontext, logf, 0, NULL,
2843 : "Could not set up TBSCertificate: Out of memory");
2844 0 : ret = hx509_enomem(context);
2845 0 : goto out;
2846 : }
2847 :
2848 : /*
2849 : * Set the notBefore/notAfter for the certificate to be issued.
2850 : *
2851 : * Here `starttime' is the supplicant's credentials' notBefore equivalent,
2852 : * while `endtime' is the supplicant's credentials' notAfter equivalent.
2853 : *
2854 : * `req_life' is the lifetime requested by the supplicant.
2855 : *
2856 : * `endtime' must be larger than the current time.
2857 : *
2858 : * `starttime' can be zero or negative, in which case the notBefore will be the
2859 : * current time minus five minutes.
2860 : *
2861 : * `endtime', `req_life' and configuration parameters will be used to compute
2862 : * the actual notAfter.
2863 : */
2864 : static heim_error_code
2865 0 : tbs_set_times(hx509_context context,
2866 : const heim_config_binding *cf,
2867 : heim_log_facility *logf,
2868 : time_t starttime,
2869 : time_t endtime,
2870 : time_t req_life,
2871 : hx509_ca_tbs tbs)
2872 : {
2873 0 : time_t now = time(NULL);
2874 0 : time_t force = heim_config_get_time_default(context->hcontext,
2875 : cf, 5 * 24 * 3600,
2876 : "force_cert_lifetime", NULL);
2877 0 : time_t clamp = heim_config_get_time_default(context->hcontext, cf, 0,
2878 : "max_cert_lifetime", NULL);
2879 0 : int allow_more = heim_config_get_bool_default(context->hcontext, cf, FALSE,
2880 : "allow_extra_lifetime",
2881 : NULL);
2882 0 : starttime = starttime > 0 ? starttime : now - 5 * 60;
2883 :
2884 0 : if (endtime < now) {
2885 0 : heim_log_msg(context->hcontext, logf, 3, NULL,
2886 : "Endtime is in the past");
2887 0 : hx509_set_error_string(context, 0, ERANGE, "Endtime is in the past");
2888 0 : return ERANGE;
2889 : }
2890 :
2891 : /* Apply requested lifetime if shorter or if allowed more */
2892 0 : if (req_life > 0 && req_life <= endtime - now)
2893 0 : endtime = now + req_life;
2894 0 : else if (req_life > 0 && allow_more)
2895 0 : endtime = now + req_life;
2896 :
2897 : /* Apply floor */
2898 0 : if (force > 0 && force > endtime - now)
2899 0 : endtime = now + force;
2900 :
2901 : /* Apply ceiling */
2902 0 : if (clamp > 0 && clamp < endtime - now)
2903 0 : endtime = now + clamp;
2904 :
2905 0 : hx509_ca_tbs_set_notAfter(context, tbs, endtime);
2906 0 : hx509_ca_tbs_set_notBefore(context, tbs, starttime);
2907 0 : return 0;
2908 : }
2909 :
2910 : /*
2911 : * Build a certifate for `principal' and its CSR.
2912 : *
2913 : * XXX Make `cprinc' a GeneralName! That's why this is private for now.
2914 : */
2915 : heim_error_code
2916 0 : _hx509_ca_issue_certificate(hx509_context context,
2917 : const heim_config_binding *cf,
2918 : heim_log_facility *logf,
2919 : hx509_request req,
2920 : KRB5PrincipalName *cprinc,
2921 : time_t starttime,
2922 : time_t endtime,
2923 : time_t req_life,
2924 : int send_chain,
2925 : hx509_certs *out)
2926 : {
2927 : heim_error_code ret;
2928 : const char *ca;
2929 0 : hx509_ca_tbs tbs = NULL;
2930 0 : hx509_certs chain = NULL;
2931 0 : hx509_cert signer = NULL;
2932 0 : hx509_cert cert = NULL;
2933 0 : hx509_env env = NULL;
2934 : KeyUsage ku;
2935 :
2936 0 : *out = NULL;
2937 : /* Force KU */
2938 0 : ku = int2KeyUsage(0);
2939 0 : ku.digitalSignature = 1;
2940 0 : hx509_request_authorize_ku(req, ku);
2941 :
2942 0 : ret = get_cf(context, cf, logf, req, cprinc, &cf);
2943 0 : if (ret)
2944 0 : return ret;
2945 :
2946 0 : if ((ca = heim_config_get_string(context->hcontext, cf,
2947 : "ca", NULL)) == NULL) {
2948 0 : heim_log_msg(context->hcontext, logf, 3, NULL,
2949 : "No kx509 CA issuer credential specified");
2950 0 : hx509_set_error_string(context, 0, ret = EACCES,
2951 : "No kx509 CA issuer credential specified");
2952 0 : return ret;
2953 : }
2954 :
2955 0 : ret = hx509_ca_tbs_init(context, &tbs);
2956 0 : if (ret) {
2957 0 : heim_log_msg(context->hcontext, logf, 0, NULL,
2958 : "Failed to create certificate: Out of memory");
2959 0 : return ret;
2960 : }
2961 :
2962 : /* Lookup a template and set things in `env' and `tbs' as appropriate */
2963 0 : if (ret == 0)
2964 0 : ret = set_tbs(context, logf, cf, req, cprinc, &env, tbs);
2965 :
2966 : /* Populate generic template "env" variables */
2967 :
2968 : /*
2969 : * The `tbs' and `env' are now complete as to naming and EKUs.
2970 : *
2971 : * We check that the `tbs' is not name-less, after which all remaining
2972 : * failures here will not be policy failures. So we also log the intent to
2973 : * issue a certificate now.
2974 : */
2975 0 : if (ret == 0 && hx509_name_is_null_p(hx509_ca_tbs_get_name(tbs)) &&
2976 0 : !has_sans(req)) {
2977 0 : heim_log_msg(context->hcontext, logf, 3, NULL,
2978 : "Not issuing certificate because it would have no names");
2979 0 : hx509_set_error_string(context, 0, ret = EACCES,
2980 : "Not issuing certificate because it "
2981 : "would have no names");
2982 : }
2983 0 : if (ret)
2984 0 : goto out;
2985 :
2986 : /*
2987 : * Still to be done below:
2988 : *
2989 : * - set certificate spki
2990 : * - set certificate validity
2991 : * - expand variables in certificate subject name template
2992 : * - sign certificate
2993 : * - encode certificate and chain
2994 : */
2995 :
2996 : /* Load the issuer certificate and private key */
2997 : {
2998 : hx509_certs certs;
2999 : hx509_query *q;
3000 :
3001 0 : ret = hx509_certs_init(context, ca, 0, NULL, &certs);
3002 0 : if (ret) {
3003 0 : heim_log_msg(context->hcontext, logf, 1, NULL,
3004 : "Failed to load CA certificate and private key %s",
3005 : ca);
3006 0 : hx509_set_error_string(context, 0, ret, "Failed to load "
3007 : "CA certificate and private key %s", ca);
3008 0 : goto out;
3009 : }
3010 0 : ret = hx509_query_alloc(context, &q);
3011 0 : if (ret) {
3012 0 : hx509_certs_free(&certs);
3013 0 : goto out;
3014 : }
3015 :
3016 0 : hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
3017 0 : hx509_query_match_option(q, HX509_QUERY_OPTION_KU_KEYCERTSIGN);
3018 :
3019 0 : ret = hx509_certs_find(context, certs, q, &signer);
3020 0 : hx509_query_free(context, q);
3021 0 : hx509_certs_free(&certs);
3022 0 : if (ret) {
3023 0 : heim_log_msg(context->hcontext, logf, 1, NULL,
3024 : "Failed to find a CA certificate in %s", ca);
3025 0 : hx509_set_error_string(context, 0, ret,
3026 : "Failed to find a CA certificate in %s",
3027 : ca);
3028 0 : goto out;
3029 : }
3030 : }
3031 :
3032 : /* Populate the subject public key in the TBS context */
3033 : {
3034 : SubjectPublicKeyInfo spki;
3035 :
3036 0 : ret = hx509_request_get_SubjectPublicKeyInfo(context,
3037 : req, &spki);
3038 0 : if (ret == 0)
3039 0 : ret = hx509_ca_tbs_set_spki(context, tbs, &spki);
3040 0 : free_SubjectPublicKeyInfo(&spki);
3041 0 : if (ret)
3042 0 : goto out;
3043 : }
3044 :
3045 : /* Work out cert expiration */
3046 0 : if (ret == 0)
3047 0 : ret = tbs_set_times(context, cf, logf, starttime, endtime, req_life,
3048 : tbs);
3049 :
3050 : /* Expand the subjectName template in the TBS using the env */
3051 0 : if (ret == 0)
3052 0 : ret = hx509_ca_tbs_subject_expand(context, tbs, env);
3053 0 : hx509_env_free(&env);
3054 :
3055 : /* All done with the TBS, sign/issue the certificate */
3056 0 : if (ret == 0)
3057 0 : ret = hx509_ca_sign(context, tbs, signer, &cert);
3058 :
3059 : /*
3060 : * Gather the certificate and chain into a MEMORY store, being careful not
3061 : * to include private keys in the chain.
3062 : *
3063 : * We could have specified a separate configuration parameter for an hx509
3064 : * store meant to have only the chain and no private keys, but expecting
3065 : * the full chain in the issuer credential store and copying only the certs
3066 : * (but not the private keys) is safer and easier to configure.
3067 : */
3068 0 : if (ret == 0)
3069 0 : ret = hx509_certs_init(context, "MEMORY:certs",
3070 : HX509_CERTS_NO_PRIVATE_KEYS, NULL, out);
3071 0 : if (ret == 0)
3072 0 : ret = hx509_certs_add(context, *out, cert);
3073 0 : if (ret == 0 && send_chain) {
3074 0 : ret = hx509_certs_init(context, ca,
3075 : HX509_CERTS_NO_PRIVATE_KEYS, NULL, &chain);
3076 0 : if (ret == 0)
3077 0 : ret = hx509_certs_merge(context, *out, chain);
3078 : }
3079 :
3080 0 : out:
3081 0 : hx509_certs_free(&chain);
3082 0 : if (env)
3083 0 : hx509_env_free(&env);
3084 0 : if (tbs)
3085 0 : hx509_ca_tbs_free(&tbs);
3086 0 : if (cert)
3087 0 : hx509_cert_free(cert);
3088 0 : if (signer)
3089 0 : hx509_cert_free(signer);
3090 0 : if (ret)
3091 0 : hx509_certs_free(out);
3092 0 : return ret;
3093 : }
|