Add ability to specifiy PKCS#11 slot number when using hx509
[heimdal.git] / lib / hx509 / ca.c
blob418a404b4aa976dc7009e96c43e27b70174ca0ca
1 /*
2 * Copyright (c) 2006 - 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "hx_locl.h"
35 #include <pkinit_asn1.h>
37 /**
38 * @page page_ca Hx509 CA functions
40 * See the library functions here: @ref hx509_ca
43 struct hx509_ca_tbs {
44 hx509_name subject;
45 SubjectPublicKeyInfo spki;
46 ExtKeyUsage eku;
47 GeneralNames san;
48 unsigned key_usage;
49 heim_integer serial;
50 struct {
51 unsigned int proxy:1;
52 unsigned int ca:1;
53 unsigned int key:1;
54 unsigned int serial:1;
55 unsigned int domaincontroller:1;
56 unsigned int xUniqueID:1;
57 } flags;
58 time_t notBefore;
59 time_t notAfter;
60 int pathLenConstraint; /* both for CA and Proxy */
61 CRLDistributionPoints crldp;
62 heim_bit_string subjectUniqueID;
63 heim_bit_string issuerUniqueID;
64 AlgorithmIdentifier *sigalg;
67 /**
68 * Allocate an to-be-signed certificate object that will be converted
69 * into an certificate.
71 * @param context A hx509 context.
72 * @param tbs returned to-be-signed certicate object, free with
73 * hx509_ca_tbs_free().
75 * @return An hx509 error code, see hx509_get_error_string().
77 * @ingroup hx509_ca
80 int
81 hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs)
83 *tbs = calloc(1, sizeof(**tbs));
84 if (*tbs == NULL)
85 return ENOMEM;
87 return 0;
90 /**
91 * Free an To Be Signed object.
93 * @param tbs object to free.
95 * @ingroup hx509_ca
98 void
99 hx509_ca_tbs_free(hx509_ca_tbs *tbs)
101 if (tbs == NULL || *tbs == NULL)
102 return;
104 free_SubjectPublicKeyInfo(&(*tbs)->spki);
105 free_GeneralNames(&(*tbs)->san);
106 free_ExtKeyUsage(&(*tbs)->eku);
107 der_free_heim_integer(&(*tbs)->serial);
108 free_CRLDistributionPoints(&(*tbs)->crldp);
109 der_free_bit_string(&(*tbs)->subjectUniqueID);
110 der_free_bit_string(&(*tbs)->issuerUniqueID);
111 hx509_name_free(&(*tbs)->subject);
112 if ((*tbs)->sigalg) {
113 free_AlgorithmIdentifier((*tbs)->sigalg);
114 free((*tbs)->sigalg);
117 memset(*tbs, 0, sizeof(**tbs));
118 free(*tbs);
119 *tbs = NULL;
123 * Set the absolute time when the certificate is valid from. If not
124 * set the current time will be used.
126 * @param context A hx509 context.
127 * @param tbs object to be signed.
128 * @param t time the certificated will start to be valid
130 * @return An hx509 error code, see hx509_get_error_string().
132 * @ingroup hx509_ca
136 hx509_ca_tbs_set_notBefore(hx509_context context,
137 hx509_ca_tbs tbs,
138 time_t t)
140 tbs->notBefore = t;
141 return 0;
145 * Set the absolute time when the certificate is valid to.
147 * @param context A hx509 context.
148 * @param tbs object to be signed.
149 * @param t time when the certificate will expire
151 * @return An hx509 error code, see hx509_get_error_string().
153 * @ingroup hx509_ca
157 hx509_ca_tbs_set_notAfter(hx509_context context,
158 hx509_ca_tbs tbs,
159 time_t t)
161 tbs->notAfter = t;
162 return 0;
166 * Set the relative time when the certificiate is going to expire.
168 * @param context A hx509 context.
169 * @param tbs object to be signed.
170 * @param delta seconds to the certificate is going to expire.
172 * @return An hx509 error code, see hx509_get_error_string().
174 * @ingroup hx509_ca
178 hx509_ca_tbs_set_notAfter_lifetime(hx509_context context,
179 hx509_ca_tbs tbs,
180 time_t delta)
182 return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta);
185 static const struct units templatebits[] = {
186 { "ExtendedKeyUsage", HX509_CA_TEMPLATE_EKU },
187 { "KeyUsage", HX509_CA_TEMPLATE_KU },
188 { "SPKI", HX509_CA_TEMPLATE_SPKI },
189 { "notAfter", HX509_CA_TEMPLATE_NOTAFTER },
190 { "notBefore", HX509_CA_TEMPLATE_NOTBEFORE },
191 { "serial", HX509_CA_TEMPLATE_SERIAL },
192 { "subject", HX509_CA_TEMPLATE_SUBJECT },
193 { NULL, 0 }
197 * Make of template units, use to build flags argument to
198 * hx509_ca_tbs_set_template() with parse_units().
200 * @return an units structure.
202 * @ingroup hx509_ca
205 const struct units *
206 hx509_ca_tbs_template_units(void)
208 return templatebits;
212 * Initialize the to-be-signed certificate object from a template certifiate.
214 * @param context A hx509 context.
215 * @param tbs object to be signed.
216 * @param flags bit field selecting what to copy from the template
217 * certifiate.
218 * @param cert template certificate.
220 * @return An hx509 error code, see hx509_get_error_string().
222 * @ingroup hx509_ca
226 hx509_ca_tbs_set_template(hx509_context context,
227 hx509_ca_tbs tbs,
228 int flags,
229 hx509_cert cert)
231 int ret;
233 if (flags & HX509_CA_TEMPLATE_SUBJECT) {
234 if (tbs->subject)
235 hx509_name_free(&tbs->subject);
236 ret = hx509_cert_get_subject(cert, &tbs->subject);
237 if (ret) {
238 hx509_set_error_string(context, 0, ret,
239 "Failed to get subject from template");
240 return ret;
243 if (flags & HX509_CA_TEMPLATE_SERIAL) {
244 der_free_heim_integer(&tbs->serial);
245 ret = hx509_cert_get_serialnumber(cert, &tbs->serial);
246 tbs->flags.serial = !ret;
247 if (ret) {
248 hx509_set_error_string(context, 0, ret,
249 "Failed to copy serial number");
250 return ret;
253 if (flags & HX509_CA_TEMPLATE_NOTBEFORE)
254 tbs->notBefore = hx509_cert_get_notBefore(cert);
255 if (flags & HX509_CA_TEMPLATE_NOTAFTER)
256 tbs->notAfter = hx509_cert_get_notAfter(cert);
257 if (flags & HX509_CA_TEMPLATE_SPKI) {
258 free_SubjectPublicKeyInfo(&tbs->spki);
259 ret = hx509_cert_get_SPKI(context, cert, &tbs->spki);
260 tbs->flags.key = !ret;
261 if (ret)
262 return ret;
264 if (flags & HX509_CA_TEMPLATE_KU) {
265 KeyUsage ku;
266 ret = _hx509_cert_get_keyusage(context, cert, &ku);
267 if (ret)
268 return ret;
269 tbs->key_usage = KeyUsage2int(ku);
271 if (flags & HX509_CA_TEMPLATE_EKU) {
272 ExtKeyUsage eku;
273 size_t i;
274 ret = _hx509_cert_get_eku(context, cert, &eku);
275 if (ret)
276 return ret;
277 for (i = 0; i < eku.len; i++) {
278 ret = hx509_ca_tbs_add_eku(context, tbs, &eku.val[i]);
279 if (ret) {
280 free_ExtKeyUsage(&eku);
281 return ret;
284 free_ExtKeyUsage(&eku);
286 return 0;
290 * Make the to-be-signed certificate object a CA certificate. If the
291 * pathLenConstraint is negative path length constraint is used.
293 * @param context A hx509 context.
294 * @param tbs object to be signed.
295 * @param pathLenConstraint path length constraint, negative, no
296 * constraint.
298 * @return An hx509 error code, see hx509_get_error_string().
300 * @ingroup hx509_ca
304 hx509_ca_tbs_set_ca(hx509_context context,
305 hx509_ca_tbs tbs,
306 int pathLenConstraint)
308 tbs->flags.ca = 1;
309 tbs->pathLenConstraint = pathLenConstraint;
310 return 0;
314 * Make the to-be-signed certificate object a proxy certificate. If the
315 * pathLenConstraint is negative path length constraint is used.
317 * @param context A hx509 context.
318 * @param tbs object to be signed.
319 * @param pathLenConstraint path length constraint, negative, no
320 * constraint.
322 * @return An hx509 error code, see hx509_get_error_string().
324 * @ingroup hx509_ca
328 hx509_ca_tbs_set_proxy(hx509_context context,
329 hx509_ca_tbs tbs,
330 int pathLenConstraint)
332 tbs->flags.proxy = 1;
333 tbs->pathLenConstraint = pathLenConstraint;
334 return 0;
339 * Make the to-be-signed certificate object a windows domain controller certificate.
341 * @param context A hx509 context.
342 * @param tbs object to be signed.
344 * @return An hx509 error code, see hx509_get_error_string().
346 * @ingroup hx509_ca
350 hx509_ca_tbs_set_domaincontroller(hx509_context context,
351 hx509_ca_tbs tbs)
353 tbs->flags.domaincontroller = 1;
354 return 0;
358 * Set the subject public key info (SPKI) in the to-be-signed certificate
359 * object. SPKI is the public key and key related parameters in the
360 * certificate.
362 * @param context A hx509 context.
363 * @param tbs object to be signed.
364 * @param spki subject public key info to use for the to-be-signed certificate object.
366 * @return An hx509 error code, see hx509_get_error_string().
368 * @ingroup hx509_ca
372 hx509_ca_tbs_set_spki(hx509_context context,
373 hx509_ca_tbs tbs,
374 const SubjectPublicKeyInfo *spki)
376 int ret;
377 free_SubjectPublicKeyInfo(&tbs->spki);
378 ret = copy_SubjectPublicKeyInfo(spki, &tbs->spki);
379 tbs->flags.key = !ret;
380 return ret;
384 * Set the serial number to use for to-be-signed certificate object.
386 * @param context A hx509 context.
387 * @param tbs object to be signed.
388 * @param serialNumber serial number to use for the to-be-signed
389 * certificate object.
391 * @return An hx509 error code, see hx509_get_error_string().
393 * @ingroup hx509_ca
397 hx509_ca_tbs_set_serialnumber(hx509_context context,
398 hx509_ca_tbs tbs,
399 const heim_integer *serialNumber)
401 int ret;
402 der_free_heim_integer(&tbs->serial);
403 ret = der_copy_heim_integer(serialNumber, &tbs->serial);
404 tbs->flags.serial = !ret;
405 return ret;
409 * An an extended key usage to the to-be-signed certificate object.
410 * Duplicates will detected and not added.
412 * @param context A hx509 context.
413 * @param tbs object to be signed.
414 * @param oid extended key usage to add.
416 * @return An hx509 error code, see hx509_get_error_string().
418 * @ingroup hx509_ca
422 hx509_ca_tbs_add_eku(hx509_context context,
423 hx509_ca_tbs tbs,
424 const heim_oid *oid)
426 void *ptr;
427 int ret;
428 unsigned i;
430 /* search for duplicates */
431 for (i = 0; i < tbs->eku.len; i++) {
432 if (der_heim_oid_cmp(oid, &tbs->eku.val[i]) == 0)
433 return 0;
436 ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1));
437 if (ptr == NULL) {
438 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
439 return ENOMEM;
441 tbs->eku.val = ptr;
442 ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]);
443 if (ret) {
444 hx509_set_error_string(context, 0, ret, "out of memory");
445 return ret;
447 tbs->eku.len += 1;
448 return 0;
452 * Add CRL distribution point URI to the to-be-signed certificate
453 * object.
455 * @param context A hx509 context.
456 * @param tbs object to be signed.
457 * @param uri uri to the CRL.
458 * @param issuername name of the issuer.
460 * @return An hx509 error code, see hx509_get_error_string().
462 * @ingroup hx509_ca
466 hx509_ca_tbs_add_crl_dp_uri(hx509_context context,
467 hx509_ca_tbs tbs,
468 const char *uri,
469 hx509_name issuername)
471 DistributionPoint dp;
472 int ret;
474 memset(&dp, 0, sizeof(dp));
476 dp.distributionPoint = ecalloc(1, sizeof(*dp.distributionPoint));
479 DistributionPointName name;
480 GeneralName gn;
481 size_t size;
483 name.element = choice_DistributionPointName_fullName;
484 name.u.fullName.len = 1;
485 name.u.fullName.val = &gn;
487 gn.element = choice_GeneralName_uniformResourceIdentifier;
488 gn.u.uniformResourceIdentifier.data = rk_UNCONST(uri);
489 gn.u.uniformResourceIdentifier.length = strlen(uri);
491 ASN1_MALLOC_ENCODE(DistributionPointName,
492 dp.distributionPoint->data,
493 dp.distributionPoint->length,
494 &name, &size, ret);
495 if (ret) {
496 hx509_set_error_string(context, 0, ret,
497 "Failed to encoded DistributionPointName");
498 goto out;
500 if (dp.distributionPoint->length != size)
501 _hx509_abort("internal ASN.1 encoder error");
504 if (issuername) {
505 #if 1
507 * issuername not supported
509 hx509_set_error_string(context, 0, EINVAL,
510 "CRLDistributionPoints.name.issuername not yet supported");
511 return EINVAL;
512 #else
513 GeneralNames *crlissuer;
514 GeneralName gn;
515 Name n;
517 crlissuer = calloc(1, sizeof(*crlissuer));
518 if (crlissuer == NULL) {
519 return ENOMEM;
521 memset(&gn, 0, sizeof(gn));
523 gn.element = choice_GeneralName_directoryName;
524 ret = hx509_name_to_Name(issuername, &n);
525 if (ret) {
526 hx509_set_error_string(context, 0, ret, "out of memory");
527 goto out;
530 gn.u.directoryName.element = n.element;
531 gn.u.directoryName.u.rdnSequence = n.u.rdnSequence;
533 ret = add_GeneralNames(&crlissuer, &gn);
534 free_Name(&n);
535 if (ret) {
536 hx509_set_error_string(context, 0, ret, "out of memory");
537 goto out;
540 dp.cRLIssuer = &crlissuer;
541 #endif
544 ret = add_CRLDistributionPoints(&tbs->crldp, &dp);
545 if (ret) {
546 hx509_set_error_string(context, 0, ret, "out of memory");
547 goto out;
550 out:
551 free_DistributionPoint(&dp);
553 return ret;
557 * Add Subject Alternative Name otherName to the to-be-signed
558 * certificate object.
560 * @param context A hx509 context.
561 * @param tbs object to be signed.
562 * @param oid the oid of the OtherName.
563 * @param os data in the other name.
565 * @return An hx509 error code, see hx509_get_error_string().
567 * @ingroup hx509_ca
571 hx509_ca_tbs_add_san_otherName(hx509_context context,
572 hx509_ca_tbs tbs,
573 const heim_oid *oid,
574 const heim_octet_string *os)
576 GeneralName gn;
578 memset(&gn, 0, sizeof(gn));
579 gn.element = choice_GeneralName_otherName;
580 gn.u.otherName.type_id = *oid;
581 gn.u.otherName.value = *os;
583 return add_GeneralNames(&tbs->san, &gn);
587 * Add Kerberos Subject Alternative Name to the to-be-signed
588 * certificate object. The principal string is a UTF8 string.
590 * @param context A hx509 context.
591 * @param tbs object to be signed.
592 * @param principal Kerberos principal to add to the certificate.
594 * @return An hx509 error code, see hx509_get_error_string().
596 * @ingroup hx509_ca
600 hx509_ca_tbs_add_san_pkinit(hx509_context context,
601 hx509_ca_tbs tbs,
602 const char *principal)
604 heim_octet_string os;
605 KRB5PrincipalName p;
606 size_t size;
607 int ret;
608 char *s = NULL;
610 memset(&p, 0, sizeof(p));
612 /* parse principal */
614 const char *str;
615 char *q;
616 int n;
618 /* count number of component */
619 n = 1;
620 for(str = principal; *str != '\0' && *str != '@'; str++){
621 if(*str=='\\'){
622 if(str[1] == '\0' || str[1] == '@') {
623 ret = HX509_PARSING_NAME_FAILED;
624 hx509_set_error_string(context, 0, ret,
625 "trailing \\ in principal name");
626 goto out;
628 str++;
629 } else if(*str == '/')
630 n++;
632 p.principalName.name_string.val =
633 calloc(n, sizeof(*p.principalName.name_string.val));
634 if (p.principalName.name_string.val == NULL) {
635 ret = ENOMEM;
636 hx509_set_error_string(context, 0, ret, "malloc: out of memory");
637 goto out;
639 p.principalName.name_string.len = n;
641 p.principalName.name_type = KRB5_NT_PRINCIPAL;
642 q = s = strdup(principal);
643 if (q == NULL) {
644 ret = ENOMEM;
645 hx509_set_error_string(context, 0, ret, "malloc: out of memory");
646 goto out;
648 p.realm = strrchr(q, '@');
649 if (p.realm == NULL) {
650 ret = HX509_PARSING_NAME_FAILED;
651 hx509_set_error_string(context, 0, ret, "Missing @ in principal");
652 goto out;
654 *p.realm++ = '\0';
656 n = 0;
657 while (q) {
658 p.principalName.name_string.val[n++] = q;
659 q = strchr(q, '/');
660 if (q)
661 *q++ = '\0';
665 ASN1_MALLOC_ENCODE(KRB5PrincipalName, os.data, os.length, &p, &size, ret);
666 if (ret) {
667 hx509_set_error_string(context, 0, ret, "Out of memory");
668 goto out;
670 if (size != os.length)
671 _hx509_abort("internal ASN.1 encoder error");
673 ret = hx509_ca_tbs_add_san_otherName(context,
674 tbs,
675 &asn1_oid_id_pkinit_san,
676 &os);
677 free(os.data);
678 out:
679 if (p.principalName.name_string.val)
680 free (p.principalName.name_string.val);
681 if (s)
682 free(s);
683 return ret;
690 static int
691 add_utf8_san(hx509_context context,
692 hx509_ca_tbs tbs,
693 const heim_oid *oid,
694 const char *string)
696 const PKIXXmppAddr ustring = (const PKIXXmppAddr)(intptr_t)string;
697 heim_octet_string os;
698 size_t size;
699 int ret;
701 os.length = 0;
702 os.data = NULL;
704 ASN1_MALLOC_ENCODE(PKIXXmppAddr, os.data, os.length, &ustring, &size, ret);
705 if (ret) {
706 hx509_set_error_string(context, 0, ret, "Out of memory");
707 goto out;
709 if (size != os.length)
710 _hx509_abort("internal ASN.1 encoder error");
712 ret = hx509_ca_tbs_add_san_otherName(context,
713 tbs,
714 oid,
715 &os);
716 free(os.data);
717 out:
718 return ret;
722 * Add Microsoft UPN Subject Alternative Name to the to-be-signed
723 * certificate object. The principal string is a UTF8 string.
725 * @param context A hx509 context.
726 * @param tbs object to be signed.
727 * @param principal Microsoft UPN string.
729 * @return An hx509 error code, see hx509_get_error_string().
731 * @ingroup hx509_ca
735 hx509_ca_tbs_add_san_ms_upn(hx509_context context,
736 hx509_ca_tbs tbs,
737 const char *principal)
739 return add_utf8_san(context, tbs, &asn1_oid_id_pkinit_ms_san, principal);
743 * Add a Jabber/XMPP jid Subject Alternative Name to the to-be-signed
744 * certificate object. The jid is an UTF8 string.
746 * @param context A hx509 context.
747 * @param tbs object to be signed.
748 * @param jid string of an a jabber id in UTF8.
750 * @return An hx509 error code, see hx509_get_error_string().
752 * @ingroup hx509_ca
756 hx509_ca_tbs_add_san_jid(hx509_context context,
757 hx509_ca_tbs tbs,
758 const char *jid)
760 return add_utf8_san(context, tbs, &asn1_oid_id_pkix_on_xmppAddr, jid);
765 * Add a Subject Alternative Name hostname to to-be-signed certificate
766 * object. A domain match starts with ., an exact match does not.
768 * Example of a an domain match: .domain.se matches the hostname
769 * host.domain.se.
771 * @param context A hx509 context.
772 * @param tbs object to be signed.
773 * @param dnsname a hostame.
775 * @return An hx509 error code, see hx509_get_error_string().
777 * @ingroup hx509_ca
781 hx509_ca_tbs_add_san_hostname(hx509_context context,
782 hx509_ca_tbs tbs,
783 const char *dnsname)
785 GeneralName gn;
787 memset(&gn, 0, sizeof(gn));
788 gn.element = choice_GeneralName_dNSName;
789 gn.u.dNSName.data = rk_UNCONST(dnsname);
790 gn.u.dNSName.length = strlen(dnsname);
792 return add_GeneralNames(&tbs->san, &gn);
796 * Add a Subject Alternative Name rfc822 (email address) to
797 * to-be-signed certificate object.
799 * @param context A hx509 context.
800 * @param tbs object to be signed.
801 * @param rfc822Name a string to a email address.
803 * @return An hx509 error code, see hx509_get_error_string().
805 * @ingroup hx509_ca
809 hx509_ca_tbs_add_san_rfc822name(hx509_context context,
810 hx509_ca_tbs tbs,
811 const char *rfc822Name)
813 GeneralName gn;
815 memset(&gn, 0, sizeof(gn));
816 gn.element = choice_GeneralName_rfc822Name;
817 gn.u.rfc822Name.data = rk_UNCONST(rfc822Name);
818 gn.u.rfc822Name.length = strlen(rfc822Name);
820 return add_GeneralNames(&tbs->san, &gn);
824 * Set the subject name of a to-be-signed certificate object.
826 * @param context A hx509 context.
827 * @param tbs object to be signed.
828 * @param subject the name to set a subject.
830 * @return An hx509 error code, see hx509_get_error_string().
832 * @ingroup hx509_ca
836 hx509_ca_tbs_set_subject(hx509_context context,
837 hx509_ca_tbs tbs,
838 hx509_name subject)
840 if (tbs->subject)
841 hx509_name_free(&tbs->subject);
842 return hx509_name_copy(context, subject, &tbs->subject);
846 * Set the issuerUniqueID and subjectUniqueID
848 * These are only supposed to be used considered with version 2
849 * certificates, replaced by the two extensions SubjectKeyIdentifier
850 * and IssuerKeyIdentifier. This function is to allow application
851 * using legacy protocol to issue them.
853 * @param context A hx509 context.
854 * @param tbs object to be signed.
855 * @param issuerUniqueID to be set
856 * @param subjectUniqueID to be set
858 * @return An hx509 error code, see hx509_get_error_string().
860 * @ingroup hx509_ca
864 hx509_ca_tbs_set_unique(hx509_context context,
865 hx509_ca_tbs tbs,
866 const heim_bit_string *subjectUniqueID,
867 const heim_bit_string *issuerUniqueID)
869 int ret;
871 der_free_bit_string(&tbs->subjectUniqueID);
872 der_free_bit_string(&tbs->issuerUniqueID);
874 if (subjectUniqueID) {
875 ret = der_copy_bit_string(subjectUniqueID, &tbs->subjectUniqueID);
876 if (ret)
877 return ret;
880 if (issuerUniqueID) {
881 ret = der_copy_bit_string(issuerUniqueID, &tbs->issuerUniqueID);
882 if (ret)
883 return ret;
886 return 0;
890 * Expand the the subject name in the to-be-signed certificate object
891 * using hx509_name_expand().
893 * @param context A hx509 context.
894 * @param tbs object to be signed.
895 * @param env environment variable to expand variables in the subject
896 * name, see hx509_env_init().
898 * @return An hx509 error code, see hx509_get_error_string().
900 * @ingroup hx509_ca
904 hx509_ca_tbs_subject_expand(hx509_context context,
905 hx509_ca_tbs tbs,
906 hx509_env env)
908 return hx509_name_expand(context, tbs->subject, env);
912 * Set signature algorithm on the to be signed certificate
914 * @param context A hx509 context.
915 * @param tbs object to be signed.
916 * @param sigalg signature algorithm to use
918 * @return An hx509 error code, see hx509_get_error_string().
920 * @ingroup hx509_ca
924 hx509_ca_tbs_set_signature_algorithm(hx509_context context,
925 hx509_ca_tbs tbs,
926 const AlgorithmIdentifier *sigalg)
928 int ret;
930 tbs->sigalg = calloc(1, sizeof(*tbs->sigalg));
931 if (tbs->sigalg == NULL) {
932 hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
933 return ENOMEM;
935 ret = copy_AlgorithmIdentifier(sigalg, tbs->sigalg);
936 if (ret) {
937 free(tbs->sigalg);
938 tbs->sigalg = NULL;
939 return ret;
941 return 0;
948 static int
949 add_extension(hx509_context context,
950 TBSCertificate *tbsc,
951 int critical_flag,
952 const heim_oid *oid,
953 const heim_octet_string *data)
955 Extension ext;
956 int ret;
958 memset(&ext, 0, sizeof(ext));
960 if (critical_flag) {
961 ext.critical = malloc(sizeof(*ext.critical));
962 if (ext.critical == NULL) {
963 ret = ENOMEM;
964 hx509_set_error_string(context, 0, ret, "Out of memory");
965 goto out;
967 *ext.critical = TRUE;
970 ret = der_copy_oid(oid, &ext.extnID);
971 if (ret) {
972 hx509_set_error_string(context, 0, ret, "Out of memory");
973 goto out;
975 ret = der_copy_octet_string(data, &ext.extnValue);
976 if (ret) {
977 hx509_set_error_string(context, 0, ret, "Out of memory");
978 goto out;
980 ret = add_Extensions(tbsc->extensions, &ext);
981 if (ret) {
982 hx509_set_error_string(context, 0, ret, "Out of memory");
983 goto out;
985 out:
986 free_Extension(&ext);
987 return ret;
990 static int
991 build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject)
993 char *tstr;
994 time_t t;
995 int ret;
997 ret = copy_Name(issuer, subject);
998 if (ret) {
999 hx509_set_error_string(context, 0, ret,
1000 "Failed to copy subject name");
1001 return ret;
1004 t = time(NULL);
1005 ret = asprintf(&tstr, "ts-%lu", (unsigned long)t);
1006 if (ret == -1 || tstr == NULL) {
1007 hx509_set_error_string(context, 0, ENOMEM,
1008 "Failed to copy subject name");
1009 return ENOMEM;
1011 /* prefix with CN=<ts>,...*/
1012 ret = _hx509_name_modify(context, subject, 1, &asn1_oid_id_at_commonName, tstr);
1013 free(tstr);
1014 if (ret)
1015 free_Name(subject);
1016 return ret;
1019 static int
1020 ca_sign(hx509_context context,
1021 hx509_ca_tbs tbs,
1022 hx509_private_key signer,
1023 const AuthorityKeyIdentifier *ai,
1024 const Name *issuername,
1025 hx509_cert *certificate)
1027 heim_error_t error = NULL;
1028 heim_octet_string data;
1029 Certificate c;
1030 TBSCertificate *tbsc;
1031 size_t size;
1032 int ret;
1033 const AlgorithmIdentifier *sigalg;
1034 time_t notBefore;
1035 time_t notAfter;
1036 unsigned key_usage;
1038 sigalg = tbs->sigalg;
1039 if (sigalg == NULL)
1040 sigalg = _hx509_crypto_default_sig_alg;
1042 memset(&c, 0, sizeof(c));
1045 * Default values are: Valid since 24h ago, valid one year into
1046 * the future, KeyUsage digitalSignature and keyEncipherment set,
1047 * and keyCertSign for CA certificates.
1049 notBefore = tbs->notBefore;
1050 if (notBefore == 0)
1051 notBefore = time(NULL) - 3600 * 24;
1052 notAfter = tbs->notAfter;
1053 if (notAfter == 0)
1054 notAfter = time(NULL) + 3600 * 24 * 365;
1056 key_usage = tbs->key_usage;
1057 if (key_usage == 0) {
1058 KeyUsage ku;
1059 memset(&ku, 0, sizeof(ku));
1060 ku.digitalSignature = 1;
1061 ku.keyEncipherment = 1;
1062 key_usage = KeyUsage2int(ku);
1065 if (tbs->flags.ca) {
1066 KeyUsage ku;
1067 memset(&ku, 0, sizeof(ku));
1068 ku.keyCertSign = 1;
1069 ku.cRLSign = 1;
1070 key_usage |= KeyUsage2int(ku);
1077 tbsc = &c.tbsCertificate;
1079 if (tbs->flags.key == 0) {
1080 ret = EINVAL;
1081 hx509_set_error_string(context, 0, ret, "No public key set");
1082 return ret;
1085 * Don't put restrictions on proxy certificate's subject name, it
1086 * will be generated below.
1088 if (!tbs->flags.proxy) {
1089 if (tbs->subject == NULL) {
1090 hx509_set_error_string(context, 0, EINVAL, "No subject name set");
1091 return EINVAL;
1093 if (hx509_name_is_null_p(tbs->subject) && tbs->san.len == 0) {
1094 hx509_set_error_string(context, 0, EINVAL,
1095 "NULL subject and no SubjectAltNames");
1096 return EINVAL;
1099 if (tbs->flags.ca && tbs->flags.proxy) {
1100 hx509_set_error_string(context, 0, EINVAL, "Can't be proxy and CA "
1101 "at the same time");
1102 return EINVAL;
1104 if (tbs->flags.proxy) {
1105 if (tbs->san.len > 0) {
1106 hx509_set_error_string(context, 0, EINVAL,
1107 "Proxy certificate is not allowed "
1108 "to have SubjectAltNames");
1109 return EINVAL;
1113 /* version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */
1114 tbsc->version = calloc(1, sizeof(*tbsc->version));
1115 if (tbsc->version == NULL) {
1116 ret = ENOMEM;
1117 hx509_set_error_string(context, 0, ret, "Out of memory");
1118 goto out;
1120 *tbsc->version = rfc3280_version_3;
1121 /* serialNumber CertificateSerialNumber, */
1122 if (tbs->flags.serial) {
1123 ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber);
1124 if (ret) {
1125 hx509_set_error_string(context, 0, ret, "Out of memory");
1126 goto out;
1128 } else {
1130 * If no explicit serial number is specified, 20 random bytes should be
1131 * sufficiently collision resistant. Since the serial number must be a
1132 * positive integer, ensure minimal ASN.1 DER form by forcing the high
1133 * bit off and the next bit on (thus avoiding an all zero first octet).
1135 tbsc->serialNumber.length = 20;
1136 tbsc->serialNumber.data = malloc(tbsc->serialNumber.length);
1137 if (tbsc->serialNumber.data == NULL){
1138 ret = ENOMEM;
1139 hx509_set_error_string(context, 0, ret, "Out of memory");
1140 goto out;
1142 RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length);
1143 ((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f;
1144 ((unsigned char *)tbsc->serialNumber.data)[0] |= 0x40;
1146 /* signature AlgorithmIdentifier, */
1147 ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature);
1148 if (ret) {
1149 hx509_set_error_string(context, 0, ret, "Failed to copy sigature alg");
1150 goto out;
1152 /* issuer Name, */
1153 if (issuername)
1154 ret = copy_Name(issuername, &tbsc->issuer);
1155 else
1156 ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer);
1157 if (ret) {
1158 hx509_set_error_string(context, 0, ret, "Failed to copy issuer name");
1159 goto out;
1161 /* validity Validity, */
1162 tbsc->validity.notBefore.element = choice_Time_generalTime;
1163 tbsc->validity.notBefore.u.generalTime = notBefore;
1164 tbsc->validity.notAfter.element = choice_Time_generalTime;
1165 tbsc->validity.notAfter.u.generalTime = notAfter;
1166 /* subject Name, */
1167 if (tbs->flags.proxy) {
1168 ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject);
1169 if (ret)
1170 goto out;
1171 } else {
1172 ret = hx509_name_to_Name(tbs->subject, &tbsc->subject);
1173 if (ret) {
1174 hx509_set_error_string(context, 0, ret,
1175 "Failed to copy subject name");
1176 goto out;
1179 /* subjectPublicKeyInfo SubjectPublicKeyInfo, */
1180 ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo);
1181 if (ret) {
1182 hx509_set_error_string(context, 0, ret, "Failed to copy spki");
1183 goto out;
1185 /* issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL */
1186 if (tbs->issuerUniqueID.length) {
1187 tbsc->issuerUniqueID = calloc(1, sizeof(*tbsc->issuerUniqueID));
1188 if (tbsc->issuerUniqueID == NULL) {
1189 ret = ENOMEM;
1190 hx509_set_error_string(context, 0, ret, "Out of memory");
1191 goto out;
1193 ret = der_copy_bit_string(&tbs->issuerUniqueID, tbsc->issuerUniqueID);
1194 if (ret) {
1195 hx509_set_error_string(context, 0, ret, "Out of memory");
1196 goto out;
1199 /* subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL */
1200 if (tbs->subjectUniqueID.length) {
1201 tbsc->subjectUniqueID = calloc(1, sizeof(*tbsc->subjectUniqueID));
1202 if (tbsc->subjectUniqueID == NULL) {
1203 ret = ENOMEM;
1204 hx509_set_error_string(context, 0, ret, "Out of memory");
1205 goto out;
1208 ret = der_copy_bit_string(&tbs->subjectUniqueID, tbsc->subjectUniqueID);
1209 if (ret) {
1210 hx509_set_error_string(context, 0, ret, "Out of memory");
1211 goto out;
1215 /* extensions [3] EXPLICIT Extensions OPTIONAL */
1216 tbsc->extensions = calloc(1, sizeof(*tbsc->extensions));
1217 if (tbsc->extensions == NULL) {
1218 ret = ENOMEM;
1219 hx509_set_error_string(context, 0, ret, "Out of memory");
1220 goto out;
1223 /* Add the text BMP string Domaincontroller to the cert */
1224 if (tbs->flags.domaincontroller) {
1225 data.data = rk_UNCONST("\x1e\x20\x00\x44\x00\x6f\x00\x6d"
1226 "\x00\x61\x00\x69\x00\x6e\x00\x43"
1227 "\x00\x6f\x00\x6e\x00\x74\x00\x72"
1228 "\x00\x6f\x00\x6c\x00\x6c\x00\x65"
1229 "\x00\x72");
1230 data.length = 34;
1232 ret = add_extension(context, tbsc, 0,
1233 &asn1_oid_id_ms_cert_enroll_domaincontroller,
1234 &data);
1235 if (ret)
1236 goto out;
1239 /* add KeyUsage */
1241 KeyUsage ku;
1243 ku = int2KeyUsage(key_usage);
1244 ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret);
1245 if (ret) {
1246 hx509_set_error_string(context, 0, ret, "Out of memory");
1247 goto out;
1249 if (size != data.length)
1250 _hx509_abort("internal ASN.1 encoder error");
1251 ret = add_extension(context, tbsc, 1,
1252 &asn1_oid_id_x509_ce_keyUsage, &data);
1253 free(data.data);
1254 if (ret)
1255 goto out;
1258 /* add ExtendedKeyUsage */
1259 if (tbs->eku.len > 0) {
1260 ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length,
1261 &tbs->eku, &size, ret);
1262 if (ret) {
1263 hx509_set_error_string(context, 0, ret, "Out of memory");
1264 goto out;
1266 if (size != data.length)
1267 _hx509_abort("internal ASN.1 encoder error");
1268 ret = add_extension(context, tbsc, 0,
1269 &asn1_oid_id_x509_ce_extKeyUsage, &data);
1270 free(data.data);
1271 if (ret)
1272 goto out;
1275 /* add Subject Alternative Name */
1276 if (tbs->san.len > 0) {
1277 ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length,
1278 &tbs->san, &size, ret);
1279 if (ret) {
1280 hx509_set_error_string(context, 0, ret, "Out of memory");
1281 goto out;
1283 if (size != data.length)
1284 _hx509_abort("internal ASN.1 encoder error");
1285 ret = add_extension(context, tbsc, 0,
1286 &asn1_oid_id_x509_ce_subjectAltName,
1287 &data);
1288 free(data.data);
1289 if (ret)
1290 goto out;
1293 /* Add Authority Key Identifier */
1294 if (ai) {
1295 ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length,
1296 ai, &size, ret);
1297 if (ret) {
1298 hx509_set_error_string(context, 0, ret, "Out of memory");
1299 goto out;
1301 if (size != data.length)
1302 _hx509_abort("internal ASN.1 encoder error");
1303 ret = add_extension(context, tbsc, 0,
1304 &asn1_oid_id_x509_ce_authorityKeyIdentifier,
1305 &data);
1306 free(data.data);
1307 if (ret)
1308 goto out;
1311 /* Add Subject Key Identifier */
1313 SubjectKeyIdentifier si;
1314 unsigned char hash[SHA_DIGEST_LENGTH];
1317 EVP_MD_CTX *ctx;
1319 ctx = EVP_MD_CTX_create();
1320 EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
1321 EVP_DigestUpdate(ctx, tbs->spki.subjectPublicKey.data,
1322 tbs->spki.subjectPublicKey.length / 8);
1323 EVP_DigestFinal_ex(ctx, hash, NULL);
1324 EVP_MD_CTX_destroy(ctx);
1327 si.data = hash;
1328 si.length = sizeof(hash);
1330 ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length,
1331 &si, &size, ret);
1332 if (ret) {
1333 hx509_set_error_string(context, 0, ret, "Out of memory");
1334 goto out;
1336 if (size != data.length)
1337 _hx509_abort("internal ASN.1 encoder error");
1338 ret = add_extension(context, tbsc, 0,
1339 &asn1_oid_id_x509_ce_subjectKeyIdentifier,
1340 &data);
1341 free(data.data);
1342 if (ret)
1343 goto out;
1346 /* Add BasicConstraints */
1348 BasicConstraints bc;
1349 int aCA = 1;
1350 unsigned int path;
1352 memset(&bc, 0, sizeof(bc));
1354 if (tbs->flags.ca) {
1355 bc.cA = &aCA;
1356 if (tbs->pathLenConstraint >= 0) {
1357 path = tbs->pathLenConstraint;
1358 bc.pathLenConstraint = &path;
1362 ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length,
1363 &bc, &size, ret);
1364 if (ret) {
1365 hx509_set_error_string(context, 0, ret, "Out of memory");
1366 goto out;
1368 if (size != data.length)
1369 _hx509_abort("internal ASN.1 encoder error");
1370 /* Critical if this is a CA */
1371 ret = add_extension(context, tbsc, tbs->flags.ca,
1372 &asn1_oid_id_x509_ce_basicConstraints,
1373 &data);
1374 free(data.data);
1375 if (ret)
1376 goto out;
1379 /* add Proxy */
1380 if (tbs->flags.proxy) {
1381 ProxyCertInfo info;
1383 memset(&info, 0, sizeof(info));
1385 if (tbs->pathLenConstraint >= 0) {
1386 info.pCPathLenConstraint =
1387 malloc(sizeof(*info.pCPathLenConstraint));
1388 if (info.pCPathLenConstraint == NULL) {
1389 ret = ENOMEM;
1390 hx509_set_error_string(context, 0, ret, "Out of memory");
1391 goto out;
1393 *info.pCPathLenConstraint = tbs->pathLenConstraint;
1396 ret = der_copy_oid(&asn1_oid_id_pkix_ppl_inheritAll,
1397 &info.proxyPolicy.policyLanguage);
1398 if (ret) {
1399 free_ProxyCertInfo(&info);
1400 hx509_set_error_string(context, 0, ret, "Out of memory");
1401 goto out;
1404 ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length,
1405 &info, &size, ret);
1406 free_ProxyCertInfo(&info);
1407 if (ret) {
1408 hx509_set_error_string(context, 0, ret, "Out of memory");
1409 goto out;
1411 if (size != data.length)
1412 _hx509_abort("internal ASN.1 encoder error");
1413 ret = add_extension(context, tbsc, 0,
1414 &asn1_oid_id_pkix_pe_proxyCertInfo,
1415 &data);
1416 free(data.data);
1417 if (ret)
1418 goto out;
1421 if (tbs->crldp.len) {
1423 ASN1_MALLOC_ENCODE(CRLDistributionPoints, data.data, data.length,
1424 &tbs->crldp, &size, ret);
1425 if (ret) {
1426 hx509_set_error_string(context, 0, ret, "Out of memory");
1427 goto out;
1429 if (size != data.length)
1430 _hx509_abort("internal ASN.1 encoder error");
1431 ret = add_extension(context, tbsc, FALSE,
1432 &asn1_oid_id_x509_ce_cRLDistributionPoints,
1433 &data);
1434 free(data.data);
1435 if (ret)
1436 goto out;
1439 ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret);
1440 if (ret) {
1441 hx509_set_error_string(context, 0, ret, "malloc out of memory");
1442 goto out;
1444 if (data.length != size)
1445 _hx509_abort("internal ASN.1 encoder error");
1447 ret = _hx509_create_signature_bitstring(context,
1448 signer,
1449 sigalg,
1450 &data,
1451 &c.signatureAlgorithm,
1452 &c.signatureValue);
1453 free(data.data);
1454 if (ret)
1455 goto out;
1457 *certificate = hx509_cert_init(context, &c, &error);
1458 if (*certificate == NULL) {
1459 ret = heim_error_get_code(error);
1460 heim_release(error);
1461 goto out;
1464 free_Certificate(&c);
1466 return 0;
1468 out:
1469 free_Certificate(&c);
1470 return ret;
1473 static int
1474 get_AuthorityKeyIdentifier(hx509_context context,
1475 const Certificate *certificate,
1476 AuthorityKeyIdentifier *ai)
1478 SubjectKeyIdentifier si;
1479 int ret;
1481 ret = _hx509_find_extension_subject_key_id(certificate, &si);
1482 if (ret == 0) {
1483 ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier));
1484 if (ai->keyIdentifier == NULL) {
1485 free_SubjectKeyIdentifier(&si);
1486 ret = ENOMEM;
1487 hx509_set_error_string(context, 0, ret, "Out of memory");
1488 goto out;
1490 ret = der_copy_octet_string(&si, ai->keyIdentifier);
1491 free_SubjectKeyIdentifier(&si);
1492 if (ret) {
1493 hx509_set_error_string(context, 0, ret, "Out of memory");
1494 goto out;
1496 } else {
1497 GeneralNames gns;
1498 GeneralName gn;
1499 Name name;
1501 memset(&gn, 0, sizeof(gn));
1502 memset(&gns, 0, sizeof(gns));
1503 memset(&name, 0, sizeof(name));
1505 ai->authorityCertIssuer =
1506 calloc(1, sizeof(*ai->authorityCertIssuer));
1507 if (ai->authorityCertIssuer == NULL) {
1508 ret = ENOMEM;
1509 hx509_set_error_string(context, 0, ret, "Out of memory");
1510 goto out;
1512 ai->authorityCertSerialNumber =
1513 calloc(1, sizeof(*ai->authorityCertSerialNumber));
1514 if (ai->authorityCertSerialNumber == NULL) {
1515 ret = ENOMEM;
1516 hx509_set_error_string(context, 0, ret, "Out of memory");
1517 goto out;
1521 * XXX unbreak when asn1 compiler handle IMPLICIT
1523 * This is so horrible.
1526 ret = copy_Name(&certificate->tbsCertificate.subject, &name);
1527 if (ret) {
1528 hx509_set_error_string(context, 0, ret, "Out of memory");
1529 goto out;
1532 memset(&gn, 0, sizeof(gn));
1533 gn.element = choice_GeneralName_directoryName;
1534 gn.u.directoryName.element =
1535 choice_GeneralName_directoryName_rdnSequence;
1536 gn.u.directoryName.u.rdnSequence = name.u.rdnSequence;
1538 ret = add_GeneralNames(&gns, &gn);
1539 if (ret) {
1540 hx509_set_error_string(context, 0, ret, "Out of memory");
1541 goto out;
1544 ai->authorityCertIssuer->val = gns.val;
1545 ai->authorityCertIssuer->len = gns.len;
1547 ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber,
1548 ai->authorityCertSerialNumber);
1549 if (ai->authorityCertSerialNumber == NULL) {
1550 ret = ENOMEM;
1551 hx509_set_error_string(context, 0, ret, "Out of memory");
1552 goto out;
1555 out:
1556 if (ret)
1557 free_AuthorityKeyIdentifier(ai);
1558 return ret;
1563 * Sign a to-be-signed certificate object with a issuer certificate.
1565 * The caller needs to at least have called the following functions on the
1566 * to-be-signed certificate object:
1567 * - hx509_ca_tbs_init()
1568 * - hx509_ca_tbs_set_subject()
1569 * - hx509_ca_tbs_set_spki()
1571 * When done the to-be-signed certificate object should be freed with
1572 * hx509_ca_tbs_free().
1574 * When creating self-signed certificate use hx509_ca_sign_self() instead.
1576 * @param context A hx509 context.
1577 * @param tbs object to be signed.
1578 * @param signer the CA certificate object to sign with (need private key).
1579 * @param certificate return cerificate, free with hx509_cert_free().
1581 * @return An hx509 error code, see hx509_get_error_string().
1583 * @ingroup hx509_ca
1587 hx509_ca_sign(hx509_context context,
1588 hx509_ca_tbs tbs,
1589 hx509_cert signer,
1590 hx509_cert *certificate)
1592 const Certificate *signer_cert;
1593 AuthorityKeyIdentifier ai;
1594 int ret;
1596 memset(&ai, 0, sizeof(ai));
1598 signer_cert = _hx509_get_cert(signer);
1600 ret = get_AuthorityKeyIdentifier(context, signer_cert, &ai);
1601 if (ret)
1602 goto out;
1604 ret = ca_sign(context,
1605 tbs,
1606 _hx509_cert_private_key(signer),
1607 &ai,
1608 &signer_cert->tbsCertificate.subject,
1609 certificate);
1611 out:
1612 free_AuthorityKeyIdentifier(&ai);
1614 return ret;
1618 * Work just like hx509_ca_sign() but signs it-self.
1620 * @param context A hx509 context.
1621 * @param tbs object to be signed.
1622 * @param signer private key to sign with.
1623 * @param certificate return cerificate, free with hx509_cert_free().
1625 * @return An hx509 error code, see hx509_get_error_string().
1627 * @ingroup hx509_ca
1631 hx509_ca_sign_self(hx509_context context,
1632 hx509_ca_tbs tbs,
1633 hx509_private_key signer,
1634 hx509_cert *certificate)
1636 return ca_sign(context,
1637 tbs,
1638 signer,
1639 NULL,
1640 NULL,
1641 certificate);