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