test debug
[heimdal.git] / lib / hx509 / ca.c
blob623e0f2ce350900962d4b3387180946a022b4cd0
1 /*
2 * Copyright (c) 2006 - 2007 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>
36 RCSID("$Id$");
38 /**
39 * @page page_ca Hx509 CA functions
41 * See the library functions here: @ref hx509_ca
44 struct hx509_ca_tbs {
45 hx509_name subject;
46 SubjectPublicKeyInfo spki;
47 ExtKeyUsage eku;
48 GeneralNames san;
49 unsigned key_usage;
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 } flags;
58 time_t notBefore;
59 time_t notAfter;
60 int pathLenConstraint; /* both for CA and Proxy */
61 CRLDistributionPoints crldp;
64 /**
65 * Allocate an to-be-signed certificate object that will be converted
66 * into an certificate.
68 * @param context A hx509 context.
69 * @param tbs returned to-be-signed certicate object, free with
70 * hx509_ca_tbs_free().
72 * @return An hx509 error code, see hx509_get_error_string().
74 * @ingroup hx509_ca
77 int
78 hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs)
80 *tbs = calloc(1, sizeof(**tbs));
81 if (*tbs == NULL)
82 return ENOMEM;
84 (*tbs)->subject = NULL;
85 (*tbs)->san.len = 0;
86 (*tbs)->san.val = NULL;
87 (*tbs)->eku.len = 0;
88 (*tbs)->eku.val = NULL;
89 (*tbs)->pathLenConstraint = 0;
90 (*tbs)->crldp.len = 0;
91 (*tbs)->crldp.val = NULL;
93 return 0;
96 /**
97 * Free an To Be Signed object.
99 * @param tbs object to free.
101 * @ingroup hx509_ca
104 void
105 hx509_ca_tbs_free(hx509_ca_tbs *tbs)
107 if (tbs == NULL || *tbs == NULL)
108 return;
110 free_SubjectPublicKeyInfo(&(*tbs)->spki);
111 free_GeneralNames(&(*tbs)->san);
112 free_ExtKeyUsage(&(*tbs)->eku);
113 der_free_heim_integer(&(*tbs)->serial);
114 free_CRLDistributionPoints(&(*tbs)->crldp);
116 hx509_name_free(&(*tbs)->subject);
118 memset(*tbs, 0, sizeof(**tbs));
119 free(*tbs);
120 *tbs = NULL;
124 * Set the absolute time when the certificate is valid from. If not
125 * set the current time will be used.
127 * @param context A hx509 context.
128 * @param tbs object to be signed.
129 * @param t time the certificated will start to be valid
131 * @return An hx509 error code, see hx509_get_error_string().
133 * @ingroup hx509_ca
137 hx509_ca_tbs_set_notBefore(hx509_context context,
138 hx509_ca_tbs tbs,
139 time_t t)
141 tbs->notBefore = t;
142 return 0;
146 * Set the absolute time when the certificate is valid to.
148 * @param context A hx509 context.
149 * @param tbs object to be signed.
150 * @param t time when the certificate will expire
152 * @return An hx509 error code, see hx509_get_error_string().
154 * @ingroup hx509_ca
158 hx509_ca_tbs_set_notAfter(hx509_context context,
159 hx509_ca_tbs tbs,
160 time_t t)
162 tbs->notAfter = t;
163 return 0;
167 * Set the relative time when the certificiate is going to expire.
169 * @param context A hx509 context.
170 * @param tbs object to be signed.
171 * @param delta seconds to the certificate is going to expire.
173 * @return An hx509 error code, see hx509_get_error_string().
175 * @ingroup hx509_ca
179 hx509_ca_tbs_set_notAfter_lifetime(hx509_context context,
180 hx509_ca_tbs tbs,
181 time_t delta)
183 return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta);
186 static const struct units templatebits[] = {
187 { "ExtendedKeyUsage", HX509_CA_TEMPLATE_EKU },
188 { "KeyUsage", HX509_CA_TEMPLATE_KU },
189 { "SPKI", HX509_CA_TEMPLATE_SPKI },
190 { "notAfter", HX509_CA_TEMPLATE_NOTAFTER },
191 { "notBefore", HX509_CA_TEMPLATE_NOTBEFORE },
192 { "serial", HX509_CA_TEMPLATE_SERIAL },
193 { "subject", HX509_CA_TEMPLATE_SUBJECT },
194 { NULL, 0 }
198 * Make of template units, use to build flags argument to
199 * hx509_ca_tbs_set_template() with parse_units().
201 * @return an units structure.
203 * @ingroup hx509_ca
206 const struct units *
207 hx509_ca_tbs_template_units(void)
209 return templatebits;
213 * Initialize the to-be-signed certificate object from a template certifiate.
215 * @param context A hx509 context.
216 * @param tbs object to be signed.
217 * @param flags bit field selecting what to copy from the template
218 * certifiate.
219 * @param cert template certificate.
221 * @return An hx509 error code, see hx509_get_error_string().
223 * @ingroup hx509_ca
227 hx509_ca_tbs_set_template(hx509_context context,
228 hx509_ca_tbs tbs,
229 int flags,
230 hx509_cert cert)
232 int ret;
234 if (flags & HX509_CA_TEMPLATE_SUBJECT) {
235 if (tbs->subject)
236 hx509_name_free(&tbs->subject);
237 ret = hx509_cert_get_subject(cert, &tbs->subject);
238 if (ret) {
239 hx509_set_error_string(context, 0, ret,
240 "Failed to get subject from template");
241 return ret;
244 if (flags & HX509_CA_TEMPLATE_SERIAL) {
245 der_free_heim_integer(&tbs->serial);
246 ret = hx509_cert_get_serialnumber(cert, &tbs->serial);
247 tbs->flags.serial = !ret;
248 if (ret) {
249 hx509_set_error_string(context, 0, ret,
250 "Failed to copy serial number");
251 return ret;
254 if (flags & HX509_CA_TEMPLATE_NOTBEFORE)
255 tbs->notBefore = hx509_cert_get_notBefore(cert);
256 if (flags & HX509_CA_TEMPLATE_NOTAFTER)
257 tbs->notAfter = hx509_cert_get_notAfter(cert);
258 if (flags & HX509_CA_TEMPLATE_SPKI) {
259 free_SubjectPublicKeyInfo(&tbs->spki);
260 ret = hx509_cert_get_SPKI(cert, &tbs->spki);
261 tbs->flags.key = !ret;
262 if (ret) {
263 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
264 return ret;
267 if (flags & HX509_CA_TEMPLATE_KU) {
268 KeyUsage ku;
269 ret = _hx509_cert_get_keyusage(context, cert, &ku);
270 if (ret)
271 return ret;
272 tbs->key_usage = KeyUsage2int(ku);
274 if (flags & HX509_CA_TEMPLATE_EKU) {
275 ExtKeyUsage eku;
276 int i;
277 ret = _hx509_cert_get_eku(context, cert, &eku);
278 if (ret)
279 return ret;
280 for (i = 0; i < eku.len; i++) {
281 ret = hx509_ca_tbs_add_eku(context, tbs, &eku.val[i]);
282 if (ret) {
283 free_ExtKeyUsage(&eku);
284 return ret;
287 free_ExtKeyUsage(&eku);
289 return 0;
293 * Make the to-be-signed certificate object a CA certificate. If the
294 * pathLenConstraint is negative path length constraint is used.
296 * @param context A hx509 context.
297 * @param tbs object to be signed.
298 * @param pathLenConstraint path length constraint, negative, no
299 * constraint.
301 * @return An hx509 error code, see hx509_get_error_string().
303 * @ingroup hx509_ca
307 hx509_ca_tbs_set_ca(hx509_context context,
308 hx509_ca_tbs tbs,
309 int pathLenConstraint)
311 tbs->flags.ca = 1;
312 tbs->pathLenConstraint = pathLenConstraint;
313 return 0;
317 * Make the to-be-signed certificate object a proxy certificate. If the
318 * pathLenConstraint is negative path length constraint is used.
320 * @param context A hx509 context.
321 * @param tbs object to be signed.
322 * @param pathLenConstraint path length constraint, negative, no
323 * constraint.
325 * @return An hx509 error code, see hx509_get_error_string().
327 * @ingroup hx509_ca
331 hx509_ca_tbs_set_proxy(hx509_context context,
332 hx509_ca_tbs tbs,
333 int pathLenConstraint)
335 tbs->flags.proxy = 1;
336 tbs->pathLenConstraint = pathLenConstraint;
337 return 0;
342 * Make the to-be-signed certificate object a windows domain controller certificate.
344 * @param context A hx509 context.
345 * @param tbs object to be signed.
347 * @return An hx509 error code, see hx509_get_error_string().
349 * @ingroup hx509_ca
353 hx509_ca_tbs_set_domaincontroller(hx509_context context,
354 hx509_ca_tbs tbs)
356 tbs->flags.domaincontroller = 1;
357 return 0;
361 * Set the subject public key info (SPKI) in the to-be-signed certificate
362 * object. SPKI is the public key and key related parameters in the
363 * certificate.
365 * @param context A hx509 context.
366 * @param tbs object to be signed.
367 * @param spki subject public key info to use for the to-be-signed certificate object.
369 * @return An hx509 error code, see hx509_get_error_string().
371 * @ingroup hx509_ca
375 hx509_ca_tbs_set_spki(hx509_context context,
376 hx509_ca_tbs tbs,
377 const SubjectPublicKeyInfo *spki)
379 int ret;
380 free_SubjectPublicKeyInfo(&tbs->spki);
381 ret = copy_SubjectPublicKeyInfo(spki, &tbs->spki);
382 tbs->flags.key = !ret;
383 return ret;
387 * Set the serial number to use for to-be-signed certificate object.
389 * @param context A hx509 context.
390 * @param tbs object to be signed.
391 * @param serialNumber serial number to use for the to-be-signed
392 * certificate object.
394 * @return An hx509 error code, see hx509_get_error_string().
396 * @ingroup hx509_ca
400 hx509_ca_tbs_set_serialnumber(hx509_context context,
401 hx509_ca_tbs tbs,
402 const heim_integer *serialNumber)
404 int ret;
405 der_free_heim_integer(&tbs->serial);
406 ret = der_copy_heim_integer(serialNumber, &tbs->serial);
407 tbs->flags.serial = !ret;
408 return ret;
412 * An an extended key usage to the to-be-signed certificate object.
413 * Duplicates will detected and not added.
415 * @param context A hx509 context.
416 * @param tbs object to be signed.
417 * @param oid extended key usage to add.
419 * @return An hx509 error code, see hx509_get_error_string().
421 * @ingroup hx509_ca
425 hx509_ca_tbs_add_eku(hx509_context context,
426 hx509_ca_tbs tbs,
427 const heim_oid *oid)
429 void *ptr;
430 int ret;
431 unsigned i;
433 /* search for duplicates */
434 for (i = 0; i < tbs->eku.len; i++) {
435 if (der_heim_oid_cmp(oid, &tbs->eku.val[i]) == 0)
436 return 0;
439 ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1));
440 if (ptr == NULL) {
441 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
442 return ENOMEM;
444 tbs->eku.val = ptr;
445 ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]);
446 if (ret) {
447 hx509_set_error_string(context, 0, ret, "out of memory");
448 return ret;
450 tbs->eku.len += 1;
451 return 0;
455 * Add CRL distribution point URI to the to-be-signed certificate
456 * object.
458 * @param context A hx509 context.
459 * @param tbs object to be signed.
460 * @param uri uri to the CRL.
461 * @param issuername name of the issuer.
463 * @return An hx509 error code, see hx509_get_error_string().
465 * @ingroup hx509_ca
469 hx509_ca_tbs_add_crl_dp_uri(hx509_context context,
470 hx509_ca_tbs tbs,
471 const char *uri,
472 hx509_name issuername)
474 DistributionPoint dp;
475 int ret;
477 memset(&dp, 0, sizeof(dp));
479 dp.distributionPoint = ecalloc(1, sizeof(*dp.distributionPoint));
482 DistributionPointName name;
483 GeneralName gn;
484 size_t size;
486 name.element = choice_DistributionPointName_fullName;
487 name.u.fullName.len = 1;
488 name.u.fullName.val = &gn;
490 gn.element = choice_GeneralName_uniformResourceIdentifier;
491 gn.u.uniformResourceIdentifier = rk_UNCONST(uri);
493 ASN1_MALLOC_ENCODE(DistributionPointName,
494 dp.distributionPoint->data,
495 dp.distributionPoint->length,
496 &name, &size, ret);
497 if (ret) {
498 hx509_set_error_string(context, 0, ret,
499 "Failed to encoded DistributionPointName");
500 goto out;
502 if (dp.distributionPoint->length != size)
503 _hx509_abort("internal ASN.1 encoder error");
506 if (issuername) {
507 #if 1
509 * issuername not supported
511 hx509_set_error_string(context, 0, EINVAL,
512 "CRLDistributionPoints.name.issuername not yet supported");
513 return EINVAL;
514 #else
515 GeneralNames *crlissuer;
516 GeneralName gn;
517 Name n;
519 crlissuer = calloc(1, sizeof(*crlissuer));
520 if (crlissuer == NULL) {
521 return ENOMEM;
523 memset(&gn, 0, sizeof(gn));
525 gn.element = choice_GeneralName_directoryName;
526 ret = hx509_name_to_Name(issuername, &n);
527 if (ret) {
528 hx509_set_error_string(context, 0, ret, "out of memory");
529 goto out;
532 gn.u.directoryName.element = n.element;
533 gn.u.directoryName.u.rdnSequence = n.u.rdnSequence;
535 ret = add_GeneralNames(&crlissuer, &gn);
536 free_Name(&n);
537 if (ret) {
538 hx509_set_error_string(context, 0, ret, "out of memory");
539 goto out;
542 dp.cRLIssuer = &crlissuer;
543 #endif
546 ret = add_CRLDistributionPoints(&tbs->crldp, &dp);
547 if (ret) {
548 hx509_set_error_string(context, 0, ret, "out of memory");
549 goto out;
552 out:
553 free_DistributionPoint(&dp);
555 return ret;
559 * Add Subject Alternative Name otherName to the to-be-signed
560 * certificate object.
562 * @param context A hx509 context.
563 * @param tbs object to be signed.
564 * @param oid the oid of the OtherName.
565 * @param os data in the other name.
567 * @return An hx509 error code, see hx509_get_error_string().
569 * @ingroup hx509_ca
573 hx509_ca_tbs_add_san_otherName(hx509_context context,
574 hx509_ca_tbs tbs,
575 const heim_oid *oid,
576 const heim_octet_string *os)
578 GeneralName gn;
580 memset(&gn, 0, sizeof(gn));
581 gn.element = choice_GeneralName_otherName;
582 gn.u.otherName.type_id = *oid;
583 gn.u.otherName.value = *os;
585 return add_GeneralNames(&tbs->san, &gn);
589 * Add Kerberos Subject Alternative Name to the to-be-signed
590 * certificate object. The principal string is a UTF8 string.
592 * @param context A hx509 context.
593 * @param tbs object to be signed.
594 * @param principal Kerberos principal to add to the certificate.
596 * @return An hx509 error code, see hx509_get_error_string().
598 * @ingroup hx509_ca
602 hx509_ca_tbs_add_san_pkinit(hx509_context context,
603 hx509_ca_tbs tbs,
604 const char *principal)
606 heim_octet_string os;
607 KRB5PrincipalName p;
608 size_t size;
609 int ret;
610 char *s = NULL;
612 memset(&p, 0, sizeof(p));
614 /* parse principal */
616 const char *str;
617 char *q;
618 int n;
620 /* count number of component */
621 n = 1;
622 for(str = principal; *str != '\0' && *str != '@'; str++){
623 if(*str=='\\'){
624 if(str[1] == '\0' || str[1] == '@') {
625 ret = HX509_PARSING_NAME_FAILED;
626 hx509_set_error_string(context, 0, ret,
627 "trailing \\ in principal name");
628 goto out;
630 str++;
631 } else if(*str == '/')
632 n++;
634 p.principalName.name_string.val =
635 calloc(n, sizeof(*p.principalName.name_string.val));
636 if (p.principalName.name_string.val == NULL) {
637 ret = ENOMEM;
638 hx509_set_error_string(context, 0, ret, "malloc: out of memory");
639 goto out;
641 p.principalName.name_string.len = n;
643 p.principalName.name_type = KRB5_NT_PRINCIPAL;
644 q = s = strdup(principal);
645 if (q == NULL) {
646 ret = ENOMEM;
647 hx509_set_error_string(context, 0, ret, "malloc: out of memory");
648 goto out;
650 p.realm = strrchr(q, '@');
651 if (p.realm == NULL) {
652 ret = HX509_PARSING_NAME_FAILED;
653 hx509_set_error_string(context, 0, ret, "Missing @ in principal");
654 goto out;
656 *p.realm++ = '\0';
658 n = 0;
659 while (q) {
660 p.principalName.name_string.val[n++] = q;
661 q = strchr(q, '/');
662 if (q)
663 *q++ = '\0';
667 ASN1_MALLOC_ENCODE(KRB5PrincipalName, os.data, os.length, &p, &size, ret);
668 if (ret) {
669 hx509_set_error_string(context, 0, ret, "Out of memory");
670 goto out;
672 if (size != os.length)
673 _hx509_abort("internal ASN.1 encoder error");
675 ret = hx509_ca_tbs_add_san_otherName(context,
676 tbs,
677 oid_id_pkinit_san(),
678 &os);
679 free(os.data);
680 out:
681 if (p.principalName.name_string.val)
682 free (p.principalName.name_string.val);
683 if (s)
684 free(s);
685 return ret;
692 static int
693 add_utf8_san(hx509_context context,
694 hx509_ca_tbs tbs,
695 const heim_oid *oid,
696 const char *string)
698 const PKIXXmppAddr ustring = (const PKIXXmppAddr)string;
699 heim_octet_string os;
700 size_t size;
701 int ret;
703 os.length = 0;
704 os.data = NULL;
706 ASN1_MALLOC_ENCODE(PKIXXmppAddr, os.data, os.length, &ustring, &size, ret);
707 if (ret) {
708 hx509_set_error_string(context, 0, ret, "Out of memory");
709 goto out;
711 if (size != os.length)
712 _hx509_abort("internal ASN.1 encoder error");
714 ret = hx509_ca_tbs_add_san_otherName(context,
715 tbs,
716 oid,
717 &os);
718 free(os.data);
719 out:
720 return ret;
724 * Add Microsoft UPN Subject Alternative Name to the to-be-signed
725 * certificate object. The principal string is a UTF8 string.
727 * @param context A hx509 context.
728 * @param tbs object to be signed.
729 * @param principal Microsoft UPN string.
731 * @return An hx509 error code, see hx509_get_error_string().
733 * @ingroup hx509_ca
737 hx509_ca_tbs_add_san_ms_upn(hx509_context context,
738 hx509_ca_tbs tbs,
739 const char *principal)
741 return add_utf8_san(context, tbs, oid_id_pkinit_ms_san(), principal);
745 * Add a Jabber/XMPP jid Subject Alternative Name to the to-be-signed
746 * certificate object. The jid is an UTF8 string.
748 * @param context A hx509 context.
749 * @param tbs object to be signed.
750 * @param jid string of an a jabber id in UTF8.
752 * @return An hx509 error code, see hx509_get_error_string().
754 * @ingroup hx509_ca
758 hx509_ca_tbs_add_san_jid(hx509_context context,
759 hx509_ca_tbs tbs,
760 const char *jid)
762 return add_utf8_san(context, tbs, oid_id_pkix_on_xmppAddr(), jid);
767 * Add a Subject Alternative Name hostname to to-be-signed certificate
768 * object. A domain match starts with ., an exact match does not.
770 * Example of a an domain match: .domain.se matches the hostname
771 * host.domain.se.
773 * @param context A hx509 context.
774 * @param tbs object to be signed.
775 * @param dnsname a hostame.
777 * @return An hx509 error code, see hx509_get_error_string().
779 * @ingroup hx509_ca
783 hx509_ca_tbs_add_san_hostname(hx509_context context,
784 hx509_ca_tbs tbs,
785 const char *dnsname)
787 GeneralName gn;
789 memset(&gn, 0, sizeof(gn));
790 gn.element = choice_GeneralName_dNSName;
791 gn.u.dNSName = rk_UNCONST(dnsname);
793 return add_GeneralNames(&tbs->san, &gn);
797 * Add a Subject Alternative Name rfc822 (email address) to
798 * to-be-signed certificate object.
800 * @param context A hx509 context.
801 * @param tbs object to be signed.
802 * @param rfc822Name a string to a email address.
804 * @return An hx509 error code, see hx509_get_error_string().
806 * @ingroup hx509_ca
810 hx509_ca_tbs_add_san_rfc822name(hx509_context context,
811 hx509_ca_tbs tbs,
812 const char *rfc822Name)
814 GeneralName gn;
816 memset(&gn, 0, sizeof(gn));
817 gn.element = choice_GeneralName_rfc822Name;
818 gn.u.rfc822Name = rk_UNCONST(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 * Expand the the subject name in the to-be-signed certificate object
847 * using hx509_name_expand().
849 * @param context A hx509 context.
850 * @param tbs object to be signed.
851 * @param env enviroment variable to expand variables in the subject
852 * name, see hx509_env_init().
854 * @return An hx509 error code, see hx509_get_error_string().
856 * @ingroup hx509_ca
860 hx509_ca_tbs_subject_expand(hx509_context context,
861 hx509_ca_tbs tbs,
862 hx509_env env)
864 return hx509_name_expand(context, tbs->subject, env);
867 static int
868 add_extension(hx509_context context,
869 TBSCertificate *tbsc,
870 int critical_flag,
871 const heim_oid *oid,
872 const heim_octet_string *data)
874 Extension ext;
875 int ret;
877 memset(&ext, 0, sizeof(ext));
879 if (critical_flag) {
880 ext.critical = malloc(sizeof(*ext.critical));
881 if (ext.critical == NULL) {
882 ret = ENOMEM;
883 hx509_set_error_string(context, 0, ret, "Out of memory");
884 goto out;
886 *ext.critical = TRUE;
889 ret = der_copy_oid(oid, &ext.extnID);
890 if (ret) {
891 hx509_set_error_string(context, 0, ret, "Out of memory");
892 goto out;
894 ret = der_copy_octet_string(data, &ext.extnValue);
895 if (ret) {
896 hx509_set_error_string(context, 0, ret, "Out of memory");
897 goto out;
899 ret = add_Extensions(tbsc->extensions, &ext);
900 if (ret) {
901 hx509_set_error_string(context, 0, ret, "Out of memory");
902 goto out;
904 out:
905 free_Extension(&ext);
906 return ret;
909 static int
910 build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject)
912 char *tstr;
913 time_t t;
914 int ret;
916 ret = copy_Name(issuer, subject);
917 if (ret) {
918 hx509_set_error_string(context, 0, ret,
919 "Failed to copy subject name");
920 return ret;
923 t = time(NULL);
924 asprintf(&tstr, "ts-%lu", (unsigned long)t);
925 if (tstr == NULL) {
926 hx509_set_error_string(context, 0, ENOMEM,
927 "Failed to copy subject name");
928 return ENOMEM;
930 /* prefix with CN=<ts>,...*/
931 ret = _hx509_name_modify(context, subject, 1, oid_id_at_commonName(), tstr);
932 free(tstr);
933 if (ret)
934 free_Name(subject);
935 return ret;
938 static int
939 ca_sign(hx509_context context,
940 hx509_ca_tbs tbs,
941 hx509_private_key signer,
942 const AuthorityKeyIdentifier *ai,
943 const Name *issuername,
944 hx509_cert *certificate)
946 heim_octet_string data;
947 Certificate c;
948 TBSCertificate *tbsc;
949 size_t size;
950 int ret;
951 const AlgorithmIdentifier *sigalg;
952 time_t notBefore;
953 time_t notAfter;
954 unsigned key_usage;
956 sigalg = _hx509_crypto_default_sig_alg;
958 memset(&c, 0, sizeof(c));
961 * Default values are: Valid since 24h ago, valid one year into
962 * the future, KeyUsage digitalSignature and keyEncipherment set,
963 * and keyCertSign for CA certificates.
965 notBefore = tbs->notBefore;
966 if (notBefore == 0)
967 notBefore = time(NULL) - 3600 * 24;
968 notAfter = tbs->notAfter;
969 if (notAfter == 0)
970 notAfter = time(NULL) + 3600 * 24 * 365;
972 key_usage = tbs->key_usage;
973 if (key_usage == 0) {
974 KeyUsage ku;
975 memset(&ku, 0, sizeof(ku));
976 ku.digitalSignature = 1;
977 ku.keyEncipherment = 1;
978 key_usage = KeyUsage2int(ku);
981 if (tbs->flags.ca) {
982 KeyUsage ku;
983 memset(&ku, 0, sizeof(ku));
984 ku.keyCertSign = 1;
985 ku.cRLSign = 1;
986 key_usage |= KeyUsage2int(ku);
993 tbsc = &c.tbsCertificate;
995 if (tbs->flags.key == 0) {
996 ret = EINVAL;
997 hx509_set_error_string(context, 0, ret, "No public key set");
998 return ret;
1001 * Don't put restrictions on proxy certificate's subject name, it
1002 * will be generated below.
1004 if (!tbs->flags.proxy) {
1005 if (tbs->subject == NULL) {
1006 hx509_set_error_string(context, 0, EINVAL, "No subject name set");
1007 return EINVAL;
1009 if (hx509_name_is_null_p(tbs->subject) && tbs->san.len == 0) {
1010 hx509_set_error_string(context, 0, EINVAL,
1011 "NULL subject and no SubjectAltNames");
1012 return EINVAL;
1015 if (tbs->flags.ca && tbs->flags.proxy) {
1016 hx509_set_error_string(context, 0, EINVAL, "Can't be proxy and CA "
1017 "at the same time");
1018 return EINVAL;
1020 if (tbs->flags.proxy) {
1021 if (tbs->san.len > 0) {
1022 hx509_set_error_string(context, 0, EINVAL,
1023 "Proxy certificate is not allowed "
1024 "to have SubjectAltNames");
1025 return EINVAL;
1029 /* version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */
1030 tbsc->version = calloc(1, sizeof(*tbsc->version));
1031 if (tbsc->version == NULL) {
1032 ret = ENOMEM;
1033 hx509_set_error_string(context, 0, ret, "Out of memory");
1034 goto out;
1036 *tbsc->version = rfc3280_version_3;
1037 /* serialNumber CertificateSerialNumber, */
1038 if (tbs->flags.serial) {
1039 ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber);
1040 if (ret) {
1041 hx509_set_error_string(context, 0, ret, "Out of memory");
1042 goto out;
1044 } else {
1045 tbsc->serialNumber.length = 20;
1046 tbsc->serialNumber.data = malloc(tbsc->serialNumber.length);
1047 if (tbsc->serialNumber.data == NULL){
1048 ret = ENOMEM;
1049 hx509_set_error_string(context, 0, ret, "Out of memory");
1050 goto out;
1052 /* XXX diffrent */
1053 RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length);
1054 ((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f;
1056 /* signature AlgorithmIdentifier, */
1057 ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature);
1058 if (ret) {
1059 hx509_set_error_string(context, 0, ret, "Failed to copy sigature alg");
1060 goto out;
1062 /* issuer Name, */
1063 if (issuername)
1064 ret = copy_Name(issuername, &tbsc->issuer);
1065 else
1066 ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer);
1067 if (ret) {
1068 hx509_set_error_string(context, 0, ret, "Failed to copy issuer name");
1069 goto out;
1071 /* validity Validity, */
1072 tbsc->validity.notBefore.element = choice_Time_generalTime;
1073 tbsc->validity.notBefore.u.generalTime = notBefore;
1074 tbsc->validity.notAfter.element = choice_Time_generalTime;
1075 tbsc->validity.notAfter.u.generalTime = notAfter;
1076 /* subject Name, */
1077 if (tbs->flags.proxy) {
1078 ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject);
1079 if (ret)
1080 goto out;
1081 } else {
1082 ret = hx509_name_to_Name(tbs->subject, &tbsc->subject);
1083 if (ret) {
1084 hx509_set_error_string(context, 0, ret,
1085 "Failed to copy subject name");
1086 goto out;
1089 /* subjectPublicKeyInfo SubjectPublicKeyInfo, */
1090 ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo);
1091 if (ret) {
1092 hx509_set_error_string(context, 0, ret, "Failed to copy spki");
1093 goto out;
1095 /* issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL */
1096 /* subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL */
1097 /* extensions [3] EXPLICIT Extensions OPTIONAL */
1098 tbsc->extensions = calloc(1, sizeof(*tbsc->extensions));
1099 if (tbsc->extensions == NULL) {
1100 ret = ENOMEM;
1101 hx509_set_error_string(context, 0, ret, "Out of memory");
1102 goto out;
1105 /* Add the text BMP string Domaincontroller to the cert */
1106 if (tbs->flags.domaincontroller) {
1107 data.data = rk_UNCONST("\x1e\x20\x00\x44\x00\x6f\x00\x6d"
1108 "\x00\x61\x00\x69\x00\x6e\x00\x43"
1109 "\x00\x6f\x00\x6e\x00\x74\x00\x72"
1110 "\x00\x6f\x00\x6c\x00\x6c\x00\x65"
1111 "\x00\x72");
1112 data.length = 34;
1114 ret = add_extension(context, tbsc, 0,
1115 oid_id_ms_cert_enroll_domaincontroller(),
1116 &data);
1117 if (ret)
1118 goto out;
1121 /* add KeyUsage */
1123 KeyUsage ku;
1125 ku = int2KeyUsage(key_usage);
1126 ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret);
1127 if (ret) {
1128 hx509_set_error_string(context, 0, ret, "Out of memory");
1129 goto out;
1131 if (size != data.length)
1132 _hx509_abort("internal ASN.1 encoder error");
1133 ret = add_extension(context, tbsc, 1,
1134 oid_id_x509_ce_keyUsage(), &data);
1135 free(data.data);
1136 if (ret)
1137 goto out;
1140 /* add ExtendedKeyUsage */
1141 if (tbs->eku.len > 0) {
1142 ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length,
1143 &tbs->eku, &size, ret);
1144 if (ret) {
1145 hx509_set_error_string(context, 0, ret, "Out of memory");
1146 goto out;
1148 if (size != data.length)
1149 _hx509_abort("internal ASN.1 encoder error");
1150 ret = add_extension(context, tbsc, 0,
1151 oid_id_x509_ce_extKeyUsage(), &data);
1152 free(data.data);
1153 if (ret)
1154 goto out;
1157 /* add Subject Alternative Name */
1158 if (tbs->san.len > 0) {
1159 ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length,
1160 &tbs->san, &size, ret);
1161 if (ret) {
1162 hx509_set_error_string(context, 0, ret, "Out of memory");
1163 goto out;
1165 if (size != data.length)
1166 _hx509_abort("internal ASN.1 encoder error");
1167 ret = add_extension(context, tbsc, 0,
1168 oid_id_x509_ce_subjectAltName(),
1169 &data);
1170 free(data.data);
1171 if (ret)
1172 goto out;
1175 /* Add Authority Key Identifier */
1176 if (ai) {
1177 ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length,
1178 ai, &size, ret);
1179 if (ret) {
1180 hx509_set_error_string(context, 0, ret, "Out of memory");
1181 goto out;
1183 if (size != data.length)
1184 _hx509_abort("internal ASN.1 encoder error");
1185 ret = add_extension(context, tbsc, 0,
1186 oid_id_x509_ce_authorityKeyIdentifier(),
1187 &data);
1188 free(data.data);
1189 if (ret)
1190 goto out;
1193 /* Add Subject Key Identifier */
1195 SubjectKeyIdentifier si;
1196 unsigned char hash[SHA_DIGEST_LENGTH];
1199 SHA_CTX m;
1201 SHA1_Init(&m);
1202 SHA1_Update(&m, tbs->spki.subjectPublicKey.data,
1203 tbs->spki.subjectPublicKey.length / 8);
1204 SHA1_Final (hash, &m);
1207 si.data = hash;
1208 si.length = sizeof(hash);
1210 ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length,
1211 &si, &size, ret);
1212 if (ret) {
1213 hx509_set_error_string(context, 0, ret, "Out of memory");
1214 goto out;
1216 if (size != data.length)
1217 _hx509_abort("internal ASN.1 encoder error");
1218 ret = add_extension(context, tbsc, 0,
1219 oid_id_x509_ce_subjectKeyIdentifier(),
1220 &data);
1221 free(data.data);
1222 if (ret)
1223 goto out;
1226 /* Add BasicConstraints */
1228 BasicConstraints bc;
1229 int aCA = 1;
1230 uint32_t path;
1232 memset(&bc, 0, sizeof(bc));
1234 if (tbs->flags.ca) {
1235 bc.cA = &aCA;
1236 if (tbs->pathLenConstraint >= 0) {
1237 path = tbs->pathLenConstraint;
1238 bc.pathLenConstraint = &path;
1242 ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length,
1243 &bc, &size, ret);
1244 if (ret) {
1245 hx509_set_error_string(context, 0, ret, "Out of memory");
1246 goto out;
1248 if (size != data.length)
1249 _hx509_abort("internal ASN.1 encoder error");
1250 /* Critical if this is a CA */
1251 ret = add_extension(context, tbsc, tbs->flags.ca,
1252 oid_id_x509_ce_basicConstraints(),
1253 &data);
1254 free(data.data);
1255 if (ret)
1256 goto out;
1259 /* add Proxy */
1260 if (tbs->flags.proxy) {
1261 ProxyCertInfo info;
1263 memset(&info, 0, sizeof(info));
1265 if (tbs->pathLenConstraint >= 0) {
1266 info.pCPathLenConstraint =
1267 malloc(sizeof(*info.pCPathLenConstraint));
1268 if (info.pCPathLenConstraint == NULL) {
1269 ret = ENOMEM;
1270 hx509_set_error_string(context, 0, ret, "Out of memory");
1271 goto out;
1273 *info.pCPathLenConstraint = tbs->pathLenConstraint;
1276 ret = der_copy_oid(oid_id_pkix_ppl_inheritAll(),
1277 &info.proxyPolicy.policyLanguage);
1278 if (ret) {
1279 free_ProxyCertInfo(&info);
1280 hx509_set_error_string(context, 0, ret, "Out of memory");
1281 goto out;
1284 ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length,
1285 &info, &size, ret);
1286 free_ProxyCertInfo(&info);
1287 if (ret) {
1288 hx509_set_error_string(context, 0, ret, "Out of memory");
1289 goto out;
1291 if (size != data.length)
1292 _hx509_abort("internal ASN.1 encoder error");
1293 ret = add_extension(context, tbsc, 0,
1294 oid_id_pkix_pe_proxyCertInfo(),
1295 &data);
1296 free(data.data);
1297 if (ret)
1298 goto out;
1301 if (tbs->crldp.len) {
1303 ASN1_MALLOC_ENCODE(CRLDistributionPoints, data.data, data.length,
1304 &tbs->crldp, &size, ret);
1305 if (ret) {
1306 hx509_set_error_string(context, 0, ret, "Out of memory");
1307 goto out;
1309 if (size != data.length)
1310 _hx509_abort("internal ASN.1 encoder error");
1311 ret = add_extension(context, tbsc, FALSE,
1312 oid_id_x509_ce_cRLDistributionPoints(),
1313 &data);
1314 free(data.data);
1315 if (ret)
1316 goto out;
1319 ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret);
1320 if (ret) {
1321 hx509_set_error_string(context, 0, ret, "malloc out of memory");
1322 goto out;
1324 if (data.length != size)
1325 _hx509_abort("internal ASN.1 encoder error");
1327 ret = _hx509_create_signature_bitstring(context,
1328 signer,
1329 sigalg,
1330 &data,
1331 &c.signatureAlgorithm,
1332 &c.signatureValue);
1333 free(data.data);
1334 if (ret)
1335 goto out;
1337 ret = hx509_cert_init(context, &c, certificate);
1338 if (ret)
1339 goto out;
1341 free_Certificate(&c);
1343 return 0;
1345 out:
1346 free_Certificate(&c);
1347 return ret;
1350 static int
1351 get_AuthorityKeyIdentifier(hx509_context context,
1352 const Certificate *certificate,
1353 AuthorityKeyIdentifier *ai)
1355 SubjectKeyIdentifier si;
1356 int ret;
1358 ret = _hx509_find_extension_subject_key_id(certificate, &si);
1359 if (ret == 0) {
1360 ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier));
1361 if (ai->keyIdentifier == NULL) {
1362 free_SubjectKeyIdentifier(&si);
1363 ret = ENOMEM;
1364 hx509_set_error_string(context, 0, ret, "Out of memory");
1365 goto out;
1367 ret = der_copy_octet_string(&si, ai->keyIdentifier);
1368 free_SubjectKeyIdentifier(&si);
1369 if (ret) {
1370 hx509_set_error_string(context, 0, ret, "Out of memory");
1371 goto out;
1373 } else {
1374 GeneralNames gns;
1375 GeneralName gn;
1376 Name name;
1378 memset(&gn, 0, sizeof(gn));
1379 memset(&gns, 0, sizeof(gns));
1380 memset(&name, 0, sizeof(name));
1382 ai->authorityCertIssuer =
1383 calloc(1, sizeof(*ai->authorityCertIssuer));
1384 if (ai->authorityCertIssuer == NULL) {
1385 ret = ENOMEM;
1386 hx509_set_error_string(context, 0, ret, "Out of memory");
1387 goto out;
1389 ai->authorityCertSerialNumber =
1390 calloc(1, sizeof(*ai->authorityCertSerialNumber));
1391 if (ai->authorityCertSerialNumber == NULL) {
1392 ret = ENOMEM;
1393 hx509_set_error_string(context, 0, ret, "Out of memory");
1394 goto out;
1398 * XXX unbreak when asn1 compiler handle IMPLICIT
1400 * This is so horrible.
1403 ret = copy_Name(&certificate->tbsCertificate.subject, &name);
1404 if (ai->authorityCertSerialNumber == NULL) {
1405 ret = ENOMEM;
1406 hx509_set_error_string(context, 0, ret, "Out of memory");
1407 goto out;
1410 memset(&gn, 0, sizeof(gn));
1411 gn.element = choice_GeneralName_directoryName;
1412 gn.u.directoryName.element =
1413 choice_GeneralName_directoryName_rdnSequence;
1414 gn.u.directoryName.u.rdnSequence = name.u.rdnSequence;
1416 ret = add_GeneralNames(&gns, &gn);
1417 if (ret) {
1418 hx509_set_error_string(context, 0, ret, "Out of memory");
1419 goto out;
1422 ai->authorityCertIssuer->val = gns.val;
1423 ai->authorityCertIssuer->len = gns.len;
1425 ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber,
1426 ai->authorityCertSerialNumber);
1427 if (ai->authorityCertSerialNumber == NULL) {
1428 ret = ENOMEM;
1429 hx509_set_error_string(context, 0, ret, "Out of memory");
1430 goto out;
1433 out:
1434 if (ret)
1435 free_AuthorityKeyIdentifier(ai);
1436 return ret;
1441 * Sign a to-be-signed certificate object with a issuer certificate.
1443 * The caller needs to at least have called the following functions on the
1444 * to-be-signed certificate object:
1445 * - hx509_ca_tbs_init()
1446 * - hx509_ca_tbs_set_subject()
1447 * - hx509_ca_tbs_set_spki()
1449 * When done the to-be-signed certificate object should be freed with
1450 * hx509_ca_tbs_free().
1452 * When creating self-signed certificate use hx509_ca_sign_self() instead.
1454 * @param context A hx509 context.
1455 * @param tbs object to be signed.
1456 * @param signer the CA certificate object to sign with (need private key).
1457 * @param certificate return cerificate, free with hx509_cert_free().
1459 * @return An hx509 error code, see hx509_get_error_string().
1461 * @ingroup hx509_ca
1465 hx509_ca_sign(hx509_context context,
1466 hx509_ca_tbs tbs,
1467 hx509_cert signer,
1468 hx509_cert *certificate)
1470 const Certificate *signer_cert;
1471 AuthorityKeyIdentifier ai;
1472 int ret;
1474 memset(&ai, 0, sizeof(ai));
1476 signer_cert = _hx509_get_cert(signer);
1478 ret = get_AuthorityKeyIdentifier(context, signer_cert, &ai);
1479 if (ret)
1480 goto out;
1482 ret = ca_sign(context,
1483 tbs,
1484 _hx509_cert_private_key(signer),
1485 &ai,
1486 &signer_cert->tbsCertificate.subject,
1487 certificate);
1489 out:
1490 free_AuthorityKeyIdentifier(&ai);
1492 return ret;
1496 * Work just like hx509_ca_sign() but signs it-self.
1498 * @param context A hx509 context.
1499 * @param tbs object to be signed.
1500 * @param signer private key to sign with.
1501 * @param certificate return cerificate, free with hx509_cert_free().
1503 * @return An hx509 error code, see hx509_get_error_string().
1505 * @ingroup hx509_ca
1509 hx509_ca_sign_self(hx509_context context,
1510 hx509_ca_tbs tbs,
1511 hx509_private_key signer,
1512 hx509_cert *certificate)
1514 return ca_sign(context,
1515 tbs,
1516 signer,
1517 NULL,
1518 NULL,
1519 certificate);