source: branches/samba-3.5.x/source4/heimdal/lib/hx509/ca.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 16 years ago

Samba 3.5.0: Initial import

File size: 36.6 KB
Line 
1/*
2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "hx_locl.h"
35#include <pkinit_asn1.h>
36
37/**
38 * @page page_ca Hx509 CA functions
39 *
40 * See the library functions here: @ref hx509_ca
41 */
42
43struct 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 } flags;
57 time_t notBefore;
58 time_t notAfter;
59 int pathLenConstraint; /* both for CA and Proxy */
60 CRLDistributionPoints crldp;
61};
62
63/**
64 * Allocate an to-be-signed certificate object that will be converted
65 * into an certificate.
66 *
67 * @param context A hx509 context.
68 * @param tbs returned to-be-signed certicate object, free with
69 * hx509_ca_tbs_free().
70 *
71 * @return An hx509 error code, see hx509_get_error_string().
72 *
73 * @ingroup hx509_ca
74 */
75
76int
77hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs)
78{
79 *tbs = calloc(1, sizeof(**tbs));
80 if (*tbs == NULL)
81 return ENOMEM;
82
83 (*tbs)->subject = NULL;
84 (*tbs)->san.len = 0;
85 (*tbs)->san.val = NULL;
86 (*tbs)->eku.len = 0;
87 (*tbs)->eku.val = NULL;
88 (*tbs)->pathLenConstraint = 0;
89 (*tbs)->crldp.len = 0;
90 (*tbs)->crldp.val = NULL;
91
92 return 0;
93}
94
95/**
96 * Free an To Be Signed object.
97 *
98 * @param tbs object to free.
99 *
100 * @ingroup hx509_ca
101 */
102
103void
104hx509_ca_tbs_free(hx509_ca_tbs *tbs)
105{
106 if (tbs == NULL || *tbs == NULL)
107 return;
108
109 free_SubjectPublicKeyInfo(&(*tbs)->spki);
110 free_GeneralNames(&(*tbs)->san);
111 free_ExtKeyUsage(&(*tbs)->eku);
112 der_free_heim_integer(&(*tbs)->serial);
113 free_CRLDistributionPoints(&(*tbs)->crldp);
114
115 hx509_name_free(&(*tbs)->subject);
116
117 memset(*tbs, 0, sizeof(**tbs));
118 free(*tbs);
119 *tbs = NULL;
120}
121
122/**
123 * Set the absolute time when the certificate is valid from. If not
124 * set the current time will be used.
125 *
126 * @param context A hx509 context.
127 * @param tbs object to be signed.
128 * @param t time the certificated will start to be valid
129 *
130 * @return An hx509 error code, see hx509_get_error_string().
131 *
132 * @ingroup hx509_ca
133 */
134
135int
136hx509_ca_tbs_set_notBefore(hx509_context context,
137 hx509_ca_tbs tbs,
138 time_t t)
139{
140 tbs->notBefore = t;
141 return 0;
142}
143
144/**
145 * Set the absolute time when the certificate is valid to.
146 *
147 * @param context A hx509 context.
148 * @param tbs object to be signed.
149 * @param t time when the certificate will expire
150 *
151 * @return An hx509 error code, see hx509_get_error_string().
152 *
153 * @ingroup hx509_ca
154 */
155
156int
157hx509_ca_tbs_set_notAfter(hx509_context context,
158 hx509_ca_tbs tbs,
159 time_t t)
160{
161 tbs->notAfter = t;
162 return 0;
163}
164
165/**
166 * Set the relative time when the certificiate is going to expire.
167 *
168 * @param context A hx509 context.
169 * @param tbs object to be signed.
170 * @param delta seconds to the certificate is going to expire.
171 *
172 * @return An hx509 error code, see hx509_get_error_string().
173 *
174 * @ingroup hx509_ca
175 */
176
177int
178hx509_ca_tbs_set_notAfter_lifetime(hx509_context context,
179 hx509_ca_tbs tbs,
180 time_t delta)
181{
182 return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta);
183}
184
185static 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 }
194};
195
196/**
197 * Make of template units, use to build flags argument to
198 * hx509_ca_tbs_set_template() with parse_units().
199 *
200 * @return an units structure.
201 *
202 * @ingroup hx509_ca
203 */
204
205const struct units *
206hx509_ca_tbs_template_units(void)
207{
208 return templatebits;
209}
210
211/**
212 * Initialize the to-be-signed certificate object from a template certifiate.
213 *
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.
219 *
220 * @return An hx509 error code, see hx509_get_error_string().
221 *
222 * @ingroup hx509_ca
223 */
224
225int
226hx509_ca_tbs_set_template(hx509_context context,
227 hx509_ca_tbs tbs,
228 int flags,
229 hx509_cert cert)
230{
231 int ret;
232
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;
241 }
242 }
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;
251 }
252 }
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;
263 }
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);
270 }
271 if (flags & HX509_CA_TEMPLATE_EKU) {
272 ExtKeyUsage eku;
273 int 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;
282 }
283 }
284 free_ExtKeyUsage(&eku);
285 }
286 return 0;
287}
288
289/**
290 * Make the to-be-signed certificate object a CA certificate. If the
291 * pathLenConstraint is negative path length constraint is used.
292 *
293 * @param context A hx509 context.
294 * @param tbs object to be signed.
295 * @param pathLenConstraint path length constraint, negative, no
296 * constraint.
297 *
298 * @return An hx509 error code, see hx509_get_error_string().
299 *
300 * @ingroup hx509_ca
301 */
302
303int
304hx509_ca_tbs_set_ca(hx509_context context,
305 hx509_ca_tbs tbs,
306 int pathLenConstraint)
307{
308 tbs->flags.ca = 1;
309 tbs->pathLenConstraint = pathLenConstraint;
310 return 0;
311}
312
313/**
314 * Make the to-be-signed certificate object a proxy certificate. If the
315 * pathLenConstraint is negative path length constraint is used.
316 *
317 * @param context A hx509 context.
318 * @param tbs object to be signed.
319 * @param pathLenConstraint path length constraint, negative, no
320 * constraint.
321 *
322 * @return An hx509 error code, see hx509_get_error_string().
323 *
324 * @ingroup hx509_ca
325 */
326
327int
328hx509_ca_tbs_set_proxy(hx509_context context,
329 hx509_ca_tbs tbs,
330 int pathLenConstraint)
331{
332 tbs->flags.proxy = 1;
333 tbs->pathLenConstraint = pathLenConstraint;
334 return 0;
335}
336
337
338/**
339 * Make the to-be-signed certificate object a windows domain controller certificate.
340 *
341 * @param context A hx509 context.
342 * @param tbs object to be signed.
343 *
344 * @return An hx509 error code, see hx509_get_error_string().
345 *
346 * @ingroup hx509_ca
347 */
348
349int
350hx509_ca_tbs_set_domaincontroller(hx509_context context,
351 hx509_ca_tbs tbs)
352{
353 tbs->flags.domaincontroller = 1;
354 return 0;
355}
356
357/**
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.
361 *
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.
365 *
366 * @return An hx509 error code, see hx509_get_error_string().
367 *
368 * @ingroup hx509_ca
369 */
370
371int
372hx509_ca_tbs_set_spki(hx509_context context,
373 hx509_ca_tbs tbs,
374 const SubjectPublicKeyInfo *spki)
375{
376 int ret;
377 free_SubjectPublicKeyInfo(&tbs->spki);
378 ret = copy_SubjectPublicKeyInfo(spki, &tbs->spki);
379 tbs->flags.key = !ret;
380 return ret;
381}
382
383/**
384 * Set the serial number to use for to-be-signed certificate object.
385 *
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.
390 *
391 * @return An hx509 error code, see hx509_get_error_string().
392 *
393 * @ingroup hx509_ca
394 */
395
396int
397hx509_ca_tbs_set_serialnumber(hx509_context context,
398 hx509_ca_tbs tbs,
399 const heim_integer *serialNumber)
400{
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;
406}
407
408/**
409 * An an extended key usage to the to-be-signed certificate object.
410 * Duplicates will detected and not added.
411 *
412 * @param context A hx509 context.
413 * @param tbs object to be signed.
414 * @param oid extended key usage to add.
415 *
416 * @return An hx509 error code, see hx509_get_error_string().
417 *
418 * @ingroup hx509_ca
419 */
420
421int
422hx509_ca_tbs_add_eku(hx509_context context,
423 hx509_ca_tbs tbs,
424 const heim_oid *oid)
425{
426 void *ptr;
427 int ret;
428 unsigned i;
429
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;
434 }
435
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;
440 }
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;
446 }
447 tbs->eku.len += 1;
448 return 0;
449}
450
451/**
452 * Add CRL distribution point URI to the to-be-signed certificate
453 * object.
454 *
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.
459 *
460 * @return An hx509 error code, see hx509_get_error_string().
461 *
462 * @ingroup hx509_ca
463 */
464
465int
466hx509_ca_tbs_add_crl_dp_uri(hx509_context context,
467 hx509_ca_tbs tbs,
468 const char *uri,
469 hx509_name issuername)
470{
471 DistributionPoint dp;
472 int ret;
473
474 memset(&dp, 0, sizeof(dp));
475
476 dp.distributionPoint = ecalloc(1, sizeof(*dp.distributionPoint));
477
478 {
479 DistributionPointName name;
480 GeneralName gn;
481 size_t size;
482
483 name.element = choice_DistributionPointName_fullName;
484 name.u.fullName.len = 1;
485 name.u.fullName.val = &gn;
486
487 gn.element = choice_GeneralName_uniformResourceIdentifier;
488 gn.u.uniformResourceIdentifier = rk_UNCONST(uri);
489
490 ASN1_MALLOC_ENCODE(DistributionPointName,
491 dp.distributionPoint->data,
492 dp.distributionPoint->length,
493 &name, &size, ret);
494 if (ret) {
495 hx509_set_error_string(context, 0, ret,
496 "Failed to encoded DistributionPointName");
497 goto out;
498 }
499 if (dp.distributionPoint->length != size)
500 _hx509_abort("internal ASN.1 encoder error");
501 }
502
503 if (issuername) {
504#if 1
505 /**
506 * issuername not supported
507 */
508 hx509_set_error_string(context, 0, EINVAL,
509 "CRLDistributionPoints.name.issuername not yet supported");
510 return EINVAL;
511#else
512 GeneralNames *crlissuer;
513 GeneralName gn;
514 Name n;
515
516 crlissuer = calloc(1, sizeof(*crlissuer));
517 if (crlissuer == NULL) {
518 return ENOMEM;
519 }
520 memset(&gn, 0, sizeof(gn));
521
522 gn.element = choice_GeneralName_directoryName;
523 ret = hx509_name_to_Name(issuername, &n);
524 if (ret) {
525 hx509_set_error_string(context, 0, ret, "out of memory");
526 goto out;
527 }
528
529 gn.u.directoryName.element = n.element;
530 gn.u.directoryName.u.rdnSequence = n.u.rdnSequence;
531
532 ret = add_GeneralNames(&crlissuer, &gn);
533 free_Name(&n);
534 if (ret) {
535 hx509_set_error_string(context, 0, ret, "out of memory");
536 goto out;
537 }
538
539 dp.cRLIssuer = &crlissuer;
540#endif
541 }
542
543 ret = add_CRLDistributionPoints(&tbs->crldp, &dp);
544 if (ret) {
545 hx509_set_error_string(context, 0, ret, "out of memory");
546 goto out;
547 }
548
549out:
550 free_DistributionPoint(&dp);
551
552 return ret;
553}
554
555/**
556 * Add Subject Alternative Name otherName to the to-be-signed
557 * certificate object.
558 *
559 * @param context A hx509 context.
560 * @param tbs object to be signed.
561 * @param oid the oid of the OtherName.
562 * @param os data in the other name.
563 *
564 * @return An hx509 error code, see hx509_get_error_string().
565 *
566 * @ingroup hx509_ca
567 */
568
569int
570hx509_ca_tbs_add_san_otherName(hx509_context context,
571 hx509_ca_tbs tbs,
572 const heim_oid *oid,
573 const heim_octet_string *os)
574{
575 GeneralName gn;
576
577 memset(&gn, 0, sizeof(gn));
578 gn.element = choice_GeneralName_otherName;
579 gn.u.otherName.type_id = *oid;
580 gn.u.otherName.value = *os;
581
582 return add_GeneralNames(&tbs->san, &gn);
583}
584
585/**
586 * Add Kerberos Subject Alternative Name to the to-be-signed
587 * certificate object. The principal string is a UTF8 string.
588 *
589 * @param context A hx509 context.
590 * @param tbs object to be signed.
591 * @param principal Kerberos principal to add to the certificate.
592 *
593 * @return An hx509 error code, see hx509_get_error_string().
594 *
595 * @ingroup hx509_ca
596 */
597
598int
599hx509_ca_tbs_add_san_pkinit(hx509_context context,
600 hx509_ca_tbs tbs,
601 const char *principal)
602{
603 heim_octet_string os;
604 KRB5PrincipalName p;
605 size_t size;
606 int ret;
607 char *s = NULL;
608
609 memset(&p, 0, sizeof(p));
610
611 /* parse principal */
612 {
613 const char *str;
614 char *q;
615 int n;
616
617 /* count number of component */
618 n = 1;
619 for(str = principal; *str != '\0' && *str != '@'; str++){
620 if(*str=='\\'){
621 if(str[1] == '\0' || str[1] == '@') {
622 ret = HX509_PARSING_NAME_FAILED;
623 hx509_set_error_string(context, 0, ret,
624 "trailing \\ in principal name");
625 goto out;
626 }
627 str++;
628 } else if(*str == '/')
629 n++;
630 }
631 p.principalName.name_string.val =
632 calloc(n, sizeof(*p.principalName.name_string.val));
633 if (p.principalName.name_string.val == NULL) {
634 ret = ENOMEM;
635 hx509_set_error_string(context, 0, ret, "malloc: out of memory");
636 goto out;
637 }
638 p.principalName.name_string.len = n;
639
640 p.principalName.name_type = KRB5_NT_PRINCIPAL;
641 q = s = strdup(principal);
642 if (q == NULL) {
643 ret = ENOMEM;
644 hx509_set_error_string(context, 0, ret, "malloc: out of memory");
645 goto out;
646 }
647 p.realm = strrchr(q, '@');
648 if (p.realm == NULL) {
649 ret = HX509_PARSING_NAME_FAILED;
650 hx509_set_error_string(context, 0, ret, "Missing @ in principal");
651 goto out;
652 };
653 *p.realm++ = '\0';
654
655 n = 0;
656 while (q) {
657 p.principalName.name_string.val[n++] = q;
658 q = strchr(q, '/');
659 if (q)
660 *q++ = '\0';
661 }
662 }
663
664 ASN1_MALLOC_ENCODE(KRB5PrincipalName, os.data, os.length, &p, &size, ret);
665 if (ret) {
666 hx509_set_error_string(context, 0, ret, "Out of memory");
667 goto out;
668 }
669 if (size != os.length)
670 _hx509_abort("internal ASN.1 encoder error");
671
672 ret = hx509_ca_tbs_add_san_otherName(context,
673 tbs,
674 &asn1_oid_id_pkinit_san,
675 &os);
676 free(os.data);
677out:
678 if (p.principalName.name_string.val)
679 free (p.principalName.name_string.val);
680 if (s)
681 free(s);
682 return ret;
683}
684
685/*
686 *
687 */
688
689static int
690add_utf8_san(hx509_context context,
691 hx509_ca_tbs tbs,
692 const heim_oid *oid,
693 const char *string)
694{
695 const PKIXXmppAddr ustring = (const PKIXXmppAddr)string;
696 heim_octet_string os;
697 size_t size;
698 int ret;
699
700 os.length = 0;
701 os.data = NULL;
702
703 ASN1_MALLOC_ENCODE(PKIXXmppAddr, os.data, os.length, &ustring, &size, ret);
704 if (ret) {
705 hx509_set_error_string(context, 0, ret, "Out of memory");
706 goto out;
707 }
708 if (size != os.length)
709 _hx509_abort("internal ASN.1 encoder error");
710
711 ret = hx509_ca_tbs_add_san_otherName(context,
712 tbs,
713 oid,
714 &os);
715 free(os.data);
716out:
717 return ret;
718}
719
720/**
721 * Add Microsoft UPN Subject Alternative Name to the to-be-signed
722 * certificate object. The principal string is a UTF8 string.
723 *
724 * @param context A hx509 context.
725 * @param tbs object to be signed.
726 * @param principal Microsoft UPN string.
727 *
728 * @return An hx509 error code, see hx509_get_error_string().
729 *
730 * @ingroup hx509_ca
731 */
732
733int
734hx509_ca_tbs_add_san_ms_upn(hx509_context context,
735 hx509_ca_tbs tbs,
736 const char *principal)
737{
738 return add_utf8_san(context, tbs, &asn1_oid_id_pkinit_ms_san, principal);
739}
740
741/**
742 * Add a Jabber/XMPP jid Subject Alternative Name to the to-be-signed
743 * certificate object. The jid is an UTF8 string.
744 *
745 * @param context A hx509 context.
746 * @param tbs object to be signed.
747 * @param jid string of an a jabber id in UTF8.
748 *
749 * @return An hx509 error code, see hx509_get_error_string().
750 *
751 * @ingroup hx509_ca
752 */
753
754int
755hx509_ca_tbs_add_san_jid(hx509_context context,
756 hx509_ca_tbs tbs,
757 const char *jid)
758{
759 return add_utf8_san(context, tbs, &asn1_oid_id_pkix_on_xmppAddr, jid);
760}
761
762
763/**
764 * Add a Subject Alternative Name hostname to to-be-signed certificate
765 * object. A domain match starts with ., an exact match does not.
766 *
767 * Example of a an domain match: .domain.se matches the hostname
768 * host.domain.se.
769 *
770 * @param context A hx509 context.
771 * @param tbs object to be signed.
772 * @param dnsname a hostame.
773 *
774 * @return An hx509 error code, see hx509_get_error_string().
775 *
776 * @ingroup hx509_ca
777 */
778
779int
780hx509_ca_tbs_add_san_hostname(hx509_context context,
781 hx509_ca_tbs tbs,
782 const char *dnsname)
783{
784 GeneralName gn;
785
786 memset(&gn, 0, sizeof(gn));
787 gn.element = choice_GeneralName_dNSName;
788 gn.u.dNSName = rk_UNCONST(dnsname);
789
790 return add_GeneralNames(&tbs->san, &gn);
791}
792
793/**
794 * Add a Subject Alternative Name rfc822 (email address) to
795 * to-be-signed certificate object.
796 *
797 * @param context A hx509 context.
798 * @param tbs object to be signed.
799 * @param rfc822Name a string to a email address.
800 *
801 * @return An hx509 error code, see hx509_get_error_string().
802 *
803 * @ingroup hx509_ca
804 */
805
806int
807hx509_ca_tbs_add_san_rfc822name(hx509_context context,
808 hx509_ca_tbs tbs,
809 const char *rfc822Name)
810{
811 GeneralName gn;
812
813 memset(&gn, 0, sizeof(gn));
814 gn.element = choice_GeneralName_rfc822Name;
815 gn.u.rfc822Name = rk_UNCONST(rfc822Name);
816
817 return add_GeneralNames(&tbs->san, &gn);
818}
819
820/**
821 * Set the subject name of a to-be-signed certificate object.
822 *
823 * @param context A hx509 context.
824 * @param tbs object to be signed.
825 * @param subject the name to set a subject.
826 *
827 * @return An hx509 error code, see hx509_get_error_string().
828 *
829 * @ingroup hx509_ca
830 */
831
832int
833hx509_ca_tbs_set_subject(hx509_context context,
834 hx509_ca_tbs tbs,
835 hx509_name subject)
836{
837 if (tbs->subject)
838 hx509_name_free(&tbs->subject);
839 return hx509_name_copy(context, subject, &tbs->subject);
840}
841
842/**
843 * Expand the the subject name in the to-be-signed certificate object
844 * using hx509_name_expand().
845 *
846 * @param context A hx509 context.
847 * @param tbs object to be signed.
848 * @param env enviroment variable to expand variables in the subject
849 * name, see hx509_env_init().
850 *
851 * @return An hx509 error code, see hx509_get_error_string().
852 *
853 * @ingroup hx509_ca
854 */
855
856int
857hx509_ca_tbs_subject_expand(hx509_context context,
858 hx509_ca_tbs tbs,
859 hx509_env env)
860{
861 return hx509_name_expand(context, tbs->subject, env);
862}
863
864static int
865add_extension(hx509_context context,
866 TBSCertificate *tbsc,
867 int critical_flag,
868 const heim_oid *oid,
869 const heim_octet_string *data)
870{
871 Extension ext;
872 int ret;
873
874 memset(&ext, 0, sizeof(ext));
875
876 if (critical_flag) {
877 ext.critical = malloc(sizeof(*ext.critical));
878 if (ext.critical == NULL) {
879 ret = ENOMEM;
880 hx509_set_error_string(context, 0, ret, "Out of memory");
881 goto out;
882 }
883 *ext.critical = TRUE;
884 }
885
886 ret = der_copy_oid(oid, &ext.extnID);
887 if (ret) {
888 hx509_set_error_string(context, 0, ret, "Out of memory");
889 goto out;
890 }
891 ret = der_copy_octet_string(data, &ext.extnValue);
892 if (ret) {
893 hx509_set_error_string(context, 0, ret, "Out of memory");
894 goto out;
895 }
896 ret = add_Extensions(tbsc->extensions, &ext);
897 if (ret) {
898 hx509_set_error_string(context, 0, ret, "Out of memory");
899 goto out;
900 }
901out:
902 free_Extension(&ext);
903 return ret;
904}
905
906static int
907build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject)
908{
909 char *tstr;
910 time_t t;
911 int ret;
912
913 ret = copy_Name(issuer, subject);
914 if (ret) {
915 hx509_set_error_string(context, 0, ret,
916 "Failed to copy subject name");
917 return ret;
918 }
919
920 t = time(NULL);
921 asprintf(&tstr, "ts-%lu", (unsigned long)t);
922 if (tstr == NULL) {
923 hx509_set_error_string(context, 0, ENOMEM,
924 "Failed to copy subject name");
925 return ENOMEM;
926 }
927 /* prefix with CN=<ts>,...*/
928 ret = _hx509_name_modify(context, subject, 1, &asn1_oid_id_at_commonName, tstr);
929 free(tstr);
930 if (ret)
931 free_Name(subject);
932 return ret;
933}
934
935static int
936ca_sign(hx509_context context,
937 hx509_ca_tbs tbs,
938 hx509_private_key signer,
939 const AuthorityKeyIdentifier *ai,
940 const Name *issuername,
941 hx509_cert *certificate)
942{
943 heim_octet_string data;
944 Certificate c;
945 TBSCertificate *tbsc;
946 size_t size;
947 int ret;
948 const AlgorithmIdentifier *sigalg;
949 time_t notBefore;
950 time_t notAfter;
951 unsigned key_usage;
952
953 sigalg = _hx509_crypto_default_sig_alg;
954
955 memset(&c, 0, sizeof(c));
956
957 /*
958 * Default values are: Valid since 24h ago, valid one year into
959 * the future, KeyUsage digitalSignature and keyEncipherment set,
960 * and keyCertSign for CA certificates.
961 */
962 notBefore = tbs->notBefore;
963 if (notBefore == 0)
964 notBefore = time(NULL) - 3600 * 24;
965 notAfter = tbs->notAfter;
966 if (notAfter == 0)
967 notAfter = time(NULL) + 3600 * 24 * 365;
968
969 key_usage = tbs->key_usage;
970 if (key_usage == 0) {
971 KeyUsage ku;
972 memset(&ku, 0, sizeof(ku));
973 ku.digitalSignature = 1;
974 ku.keyEncipherment = 1;
975 key_usage = KeyUsage2int(ku);
976 }
977
978 if (tbs->flags.ca) {
979 KeyUsage ku;
980 memset(&ku, 0, sizeof(ku));
981 ku.keyCertSign = 1;
982 ku.cRLSign = 1;
983 key_usage |= KeyUsage2int(ku);
984 }
985
986 /*
987 *
988 */
989
990 tbsc = &c.tbsCertificate;
991
992 if (tbs->flags.key == 0) {
993 ret = EINVAL;
994 hx509_set_error_string(context, 0, ret, "No public key set");
995 return ret;
996 }
997 /*
998 * Don't put restrictions on proxy certificate's subject name, it
999 * will be generated below.
1000 */
1001 if (!tbs->flags.proxy) {
1002 if (tbs->subject == NULL) {
1003 hx509_set_error_string(context, 0, EINVAL, "No subject name set");
1004 return EINVAL;
1005 }
1006 if (hx509_name_is_null_p(tbs->subject) && tbs->san.len == 0) {
1007 hx509_set_error_string(context, 0, EINVAL,
1008 "NULL subject and no SubjectAltNames");
1009 return EINVAL;
1010 }
1011 }
1012 if (tbs->flags.ca && tbs->flags.proxy) {
1013 hx509_set_error_string(context, 0, EINVAL, "Can't be proxy and CA "
1014 "at the same time");
1015 return EINVAL;
1016 }
1017 if (tbs->flags.proxy) {
1018 if (tbs->san.len > 0) {
1019 hx509_set_error_string(context, 0, EINVAL,
1020 "Proxy certificate is not allowed "
1021 "to have SubjectAltNames");
1022 return EINVAL;
1023 }
1024 }
1025
1026 /* version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */
1027 tbsc->version = calloc(1, sizeof(*tbsc->version));
1028 if (tbsc->version == NULL) {
1029 ret = ENOMEM;
1030 hx509_set_error_string(context, 0, ret, "Out of memory");
1031 goto out;
1032 }
1033 *tbsc->version = rfc3280_version_3;
1034 /* serialNumber CertificateSerialNumber, */
1035 if (tbs->flags.serial) {
1036 ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber);
1037 if (ret) {
1038 hx509_set_error_string(context, 0, ret, "Out of memory");
1039 goto out;
1040 }
1041 } else {
1042 tbsc->serialNumber.length = 20;
1043 tbsc->serialNumber.data = malloc(tbsc->serialNumber.length);
1044 if (tbsc->serialNumber.data == NULL){
1045 ret = ENOMEM;
1046 hx509_set_error_string(context, 0, ret, "Out of memory");
1047 goto out;
1048 }
1049 /* XXX diffrent */
1050 RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length);
1051 ((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f;
1052 }
1053 /* signature AlgorithmIdentifier, */
1054 ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature);
1055 if (ret) {
1056 hx509_set_error_string(context, 0, ret, "Failed to copy sigature alg");
1057 goto out;
1058 }
1059 /* issuer Name, */
1060 if (issuername)
1061 ret = copy_Name(issuername, &tbsc->issuer);
1062 else
1063 ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer);
1064 if (ret) {
1065 hx509_set_error_string(context, 0, ret, "Failed to copy issuer name");
1066 goto out;
1067 }
1068 /* validity Validity, */
1069 tbsc->validity.notBefore.element = choice_Time_generalTime;
1070 tbsc->validity.notBefore.u.generalTime = notBefore;
1071 tbsc->validity.notAfter.element = choice_Time_generalTime;
1072 tbsc->validity.notAfter.u.generalTime = notAfter;
1073 /* subject Name, */
1074 if (tbs->flags.proxy) {
1075 ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject);
1076 if (ret)
1077 goto out;
1078 } else {
1079 ret = hx509_name_to_Name(tbs->subject, &tbsc->subject);
1080 if (ret) {
1081 hx509_set_error_string(context, 0, ret,
1082 "Failed to copy subject name");
1083 goto out;
1084 }
1085 }
1086 /* subjectPublicKeyInfo SubjectPublicKeyInfo, */
1087 ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo);
1088 if (ret) {
1089 hx509_set_error_string(context, 0, ret, "Failed to copy spki");
1090 goto out;
1091 }
1092 /* issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL */
1093 /* subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL */
1094 /* extensions [3] EXPLICIT Extensions OPTIONAL */
1095 tbsc->extensions = calloc(1, sizeof(*tbsc->extensions));
1096 if (tbsc->extensions == NULL) {
1097 ret = ENOMEM;
1098 hx509_set_error_string(context, 0, ret, "Out of memory");
1099 goto out;
1100 }
1101
1102 /* Add the text BMP string Domaincontroller to the cert */
1103 if (tbs->flags.domaincontroller) {
1104 data.data = rk_UNCONST("\x1e\x20\x00\x44\x00\x6f\x00\x6d"
1105 "\x00\x61\x00\x69\x00\x6e\x00\x43"
1106 "\x00\x6f\x00\x6e\x00\x74\x00\x72"
1107 "\x00\x6f\x00\x6c\x00\x6c\x00\x65"
1108 "\x00\x72");
1109 data.length = 34;
1110
1111 ret = add_extension(context, tbsc, 0,
1112 &asn1_oid_id_ms_cert_enroll_domaincontroller,
1113 &data);
1114 if (ret)
1115 goto out;
1116 }
1117
1118 /* add KeyUsage */
1119 {
1120 KeyUsage ku;
1121
1122 ku = int2KeyUsage(key_usage);
1123 ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret);
1124 if (ret) {
1125 hx509_set_error_string(context, 0, ret, "Out of memory");
1126 goto out;
1127 }
1128 if (size != data.length)
1129 _hx509_abort("internal ASN.1 encoder error");
1130 ret = add_extension(context, tbsc, 1,
1131 &asn1_oid_id_x509_ce_keyUsage, &data);
1132 free(data.data);
1133 if (ret)
1134 goto out;
1135 }
1136
1137 /* add ExtendedKeyUsage */
1138 if (tbs->eku.len > 0) {
1139 ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length,
1140 &tbs->eku, &size, ret);
1141 if (ret) {
1142 hx509_set_error_string(context, 0, ret, "Out of memory");
1143 goto out;
1144 }
1145 if (size != data.length)
1146 _hx509_abort("internal ASN.1 encoder error");
1147 ret = add_extension(context, tbsc, 0,
1148 &asn1_oid_id_x509_ce_extKeyUsage, &data);
1149 free(data.data);
1150 if (ret)
1151 goto out;
1152 }
1153
1154 /* add Subject Alternative Name */
1155 if (tbs->san.len > 0) {
1156 ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length,
1157 &tbs->san, &size, ret);
1158 if (ret) {
1159 hx509_set_error_string(context, 0, ret, "Out of memory");
1160 goto out;
1161 }
1162 if (size != data.length)
1163 _hx509_abort("internal ASN.1 encoder error");
1164 ret = add_extension(context, tbsc, 0,
1165 &asn1_oid_id_x509_ce_subjectAltName,
1166 &data);
1167 free(data.data);
1168 if (ret)
1169 goto out;
1170 }
1171
1172 /* Add Authority Key Identifier */
1173 if (ai) {
1174 ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length,
1175 ai, &size, ret);
1176 if (ret) {
1177 hx509_set_error_string(context, 0, ret, "Out of memory");
1178 goto out;
1179 }
1180 if (size != data.length)
1181 _hx509_abort("internal ASN.1 encoder error");
1182 ret = add_extension(context, tbsc, 0,
1183 &asn1_oid_id_x509_ce_authorityKeyIdentifier,
1184 &data);
1185 free(data.data);
1186 if (ret)
1187 goto out;
1188 }
1189
1190 /* Add Subject Key Identifier */
1191 {
1192 SubjectKeyIdentifier si;
1193 unsigned char hash[SHA_DIGEST_LENGTH];
1194
1195 {
1196 SHA_CTX m;
1197
1198 SHA1_Init(&m);
1199 SHA1_Update(&m, tbs->spki.subjectPublicKey.data,
1200 tbs->spki.subjectPublicKey.length / 8);
1201 SHA1_Final (hash, &m);
1202 }
1203
1204 si.data = hash;
1205 si.length = sizeof(hash);
1206
1207 ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length,
1208 &si, &size, ret);
1209 if (ret) {
1210 hx509_set_error_string(context, 0, ret, "Out of memory");
1211 goto out;
1212 }
1213 if (size != data.length)
1214 _hx509_abort("internal ASN.1 encoder error");
1215 ret = add_extension(context, tbsc, 0,
1216 &asn1_oid_id_x509_ce_subjectKeyIdentifier,
1217 &data);
1218 free(data.data);
1219 if (ret)
1220 goto out;
1221 }
1222
1223 /* Add BasicConstraints */
1224 {
1225 BasicConstraints bc;
1226 int aCA = 1;
1227 unsigned int path;
1228
1229 memset(&bc, 0, sizeof(bc));
1230
1231 if (tbs->flags.ca) {
1232 bc.cA = &aCA;
1233 if (tbs->pathLenConstraint >= 0) {
1234 path = tbs->pathLenConstraint;
1235 bc.pathLenConstraint = &path;
1236 }
1237 }
1238
1239 ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length,
1240 &bc, &size, ret);
1241 if (ret) {
1242 hx509_set_error_string(context, 0, ret, "Out of memory");
1243 goto out;
1244 }
1245 if (size != data.length)
1246 _hx509_abort("internal ASN.1 encoder error");
1247 /* Critical if this is a CA */
1248 ret = add_extension(context, tbsc, tbs->flags.ca,
1249 &asn1_oid_id_x509_ce_basicConstraints,
1250 &data);
1251 free(data.data);
1252 if (ret)
1253 goto out;
1254 }
1255
1256 /* add Proxy */
1257 if (tbs->flags.proxy) {
1258 ProxyCertInfo info;
1259
1260 memset(&info, 0, sizeof(info));
1261
1262 if (tbs->pathLenConstraint >= 0) {
1263 info.pCPathLenConstraint =
1264 malloc(sizeof(*info.pCPathLenConstraint));
1265 if (info.pCPathLenConstraint == NULL) {
1266 ret = ENOMEM;
1267 hx509_set_error_string(context, 0, ret, "Out of memory");
1268 goto out;
1269 }
1270 *info.pCPathLenConstraint = tbs->pathLenConstraint;
1271 }
1272
1273 ret = der_copy_oid(&asn1_oid_id_pkix_ppl_inheritAll,
1274 &info.proxyPolicy.policyLanguage);
1275 if (ret) {
1276 free_ProxyCertInfo(&info);
1277 hx509_set_error_string(context, 0, ret, "Out of memory");
1278 goto out;
1279 }
1280
1281 ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length,
1282 &info, &size, ret);
1283 free_ProxyCertInfo(&info);
1284 if (ret) {
1285 hx509_set_error_string(context, 0, ret, "Out of memory");
1286 goto out;
1287 }
1288 if (size != data.length)
1289 _hx509_abort("internal ASN.1 encoder error");
1290 ret = add_extension(context, tbsc, 0,
1291 &asn1_oid_id_pkix_pe_proxyCertInfo,
1292 &data);
1293 free(data.data);
1294 if (ret)
1295 goto out;
1296 }
1297
1298 if (tbs->crldp.len) {
1299
1300 ASN1_MALLOC_ENCODE(CRLDistributionPoints, data.data, data.length,
1301 &tbs->crldp, &size, ret);
1302 if (ret) {
1303 hx509_set_error_string(context, 0, ret, "Out of memory");
1304 goto out;
1305 }
1306 if (size != data.length)
1307 _hx509_abort("internal ASN.1 encoder error");
1308 ret = add_extension(context, tbsc, FALSE,
1309 &asn1_oid_id_x509_ce_cRLDistributionPoints,
1310 &data);
1311 free(data.data);
1312 if (ret)
1313 goto out;
1314 }
1315
1316 ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret);
1317 if (ret) {
1318 hx509_set_error_string(context, 0, ret, "malloc out of memory");
1319 goto out;
1320 }
1321 if (data.length != size)
1322 _hx509_abort("internal ASN.1 encoder error");
1323
1324 ret = _hx509_create_signature_bitstring(context,
1325 signer,
1326 sigalg,
1327 &data,
1328 &c.signatureAlgorithm,
1329 &c.signatureValue);
1330 free(data.data);
1331 if (ret)
1332 goto out;
1333
1334 ret = hx509_cert_init(context, &c, certificate);
1335 if (ret)
1336 goto out;
1337
1338 free_Certificate(&c);
1339
1340 return 0;
1341
1342out:
1343 free_Certificate(&c);
1344 return ret;
1345}
1346
1347static int
1348get_AuthorityKeyIdentifier(hx509_context context,
1349 const Certificate *certificate,
1350 AuthorityKeyIdentifier *ai)
1351{
1352 SubjectKeyIdentifier si;
1353 int ret;
1354
1355 ret = _hx509_find_extension_subject_key_id(certificate, &si);
1356 if (ret == 0) {
1357 ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier));
1358 if (ai->keyIdentifier == NULL) {
1359 free_SubjectKeyIdentifier(&si);
1360 ret = ENOMEM;
1361 hx509_set_error_string(context, 0, ret, "Out of memory");
1362 goto out;
1363 }
1364 ret = der_copy_octet_string(&si, ai->keyIdentifier);
1365 free_SubjectKeyIdentifier(&si);
1366 if (ret) {
1367 hx509_set_error_string(context, 0, ret, "Out of memory");
1368 goto out;
1369 }
1370 } else {
1371 GeneralNames gns;
1372 GeneralName gn;
1373 Name name;
1374
1375 memset(&gn, 0, sizeof(gn));
1376 memset(&gns, 0, sizeof(gns));
1377 memset(&name, 0, sizeof(name));
1378
1379 ai->authorityCertIssuer =
1380 calloc(1, sizeof(*ai->authorityCertIssuer));
1381 if (ai->authorityCertIssuer == NULL) {
1382 ret = ENOMEM;
1383 hx509_set_error_string(context, 0, ret, "Out of memory");
1384 goto out;
1385 }
1386 ai->authorityCertSerialNumber =
1387 calloc(1, sizeof(*ai->authorityCertSerialNumber));
1388 if (ai->authorityCertSerialNumber == NULL) {
1389 ret = ENOMEM;
1390 hx509_set_error_string(context, 0, ret, "Out of memory");
1391 goto out;
1392 }
1393
1394 /*
1395 * XXX unbreak when asn1 compiler handle IMPLICIT
1396 *
1397 * This is so horrible.
1398 */
1399
1400 ret = copy_Name(&certificate->tbsCertificate.subject, &name);
1401 if (ret) {
1402 hx509_set_error_string(context, 0, ret, "Out of memory");
1403 goto out;
1404 }
1405
1406 memset(&gn, 0, sizeof(gn));
1407 gn.element = choice_GeneralName_directoryName;
1408 gn.u.directoryName.element =
1409 choice_GeneralName_directoryName_rdnSequence;
1410 gn.u.directoryName.u.rdnSequence = name.u.rdnSequence;
1411
1412 ret = add_GeneralNames(&gns, &gn);
1413 if (ret) {
1414 hx509_set_error_string(context, 0, ret, "Out of memory");
1415 goto out;
1416 }
1417
1418 ai->authorityCertIssuer->val = gns.val;
1419 ai->authorityCertIssuer->len = gns.len;
1420
1421 ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber,
1422 ai->authorityCertSerialNumber);
1423 if (ai->authorityCertSerialNumber == NULL) {
1424 ret = ENOMEM;
1425 hx509_set_error_string(context, 0, ret, "Out of memory");
1426 goto out;
1427 }
1428 }
1429out:
1430 if (ret)
1431 free_AuthorityKeyIdentifier(ai);
1432 return ret;
1433}
1434
1435
1436/**
1437 * Sign a to-be-signed certificate object with a issuer certificate.
1438 *
1439 * The caller needs to at least have called the following functions on the
1440 * to-be-signed certificate object:
1441 * - hx509_ca_tbs_init()
1442 * - hx509_ca_tbs_set_subject()
1443 * - hx509_ca_tbs_set_spki()
1444 *
1445 * When done the to-be-signed certificate object should be freed with
1446 * hx509_ca_tbs_free().
1447 *
1448 * When creating self-signed certificate use hx509_ca_sign_self() instead.
1449 *
1450 * @param context A hx509 context.
1451 * @param tbs object to be signed.
1452 * @param signer the CA certificate object to sign with (need private key).
1453 * @param certificate return cerificate, free with hx509_cert_free().
1454 *
1455 * @return An hx509 error code, see hx509_get_error_string().
1456 *
1457 * @ingroup hx509_ca
1458 */
1459
1460int
1461hx509_ca_sign(hx509_context context,
1462 hx509_ca_tbs tbs,
1463 hx509_cert signer,
1464 hx509_cert *certificate)
1465{
1466 const Certificate *signer_cert;
1467 AuthorityKeyIdentifier ai;
1468 int ret;
1469
1470 memset(&ai, 0, sizeof(ai));
1471
1472 signer_cert = _hx509_get_cert(signer);
1473
1474 ret = get_AuthorityKeyIdentifier(context, signer_cert, &ai);
1475 if (ret)
1476 goto out;
1477
1478 ret = ca_sign(context,
1479 tbs,
1480 _hx509_cert_private_key(signer),
1481 &ai,
1482 &signer_cert->tbsCertificate.subject,
1483 certificate);
1484
1485out:
1486 free_AuthorityKeyIdentifier(&ai);
1487
1488 return ret;
1489}
1490
1491/**
1492 * Work just like hx509_ca_sign() but signs it-self.
1493 *
1494 * @param context A hx509 context.
1495 * @param tbs object to be signed.
1496 * @param signer private key to sign with.
1497 * @param certificate return cerificate, free with hx509_cert_free().
1498 *
1499 * @return An hx509 error code, see hx509_get_error_string().
1500 *
1501 * @ingroup hx509_ca
1502 */
1503
1504int
1505hx509_ca_sign_self(hx509_context context,
1506 hx509_ca_tbs tbs,
1507 hx509_private_key signer,
1508 hx509_cert *certificate)
1509{
1510 return ca_sign(context,
1511 tbs,
1512 signer,
1513 NULL,
1514 NULL,
1515 certificate);
1516}
Note: See TracBrowser for help on using the repository browser.