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 |
|
---|
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 | } 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 |
|
---|
76 | int
|
---|
77 | hx509_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 |
|
---|
103 | void
|
---|
104 | hx509_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 |
|
---|
135 | int
|
---|
136 | hx509_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 |
|
---|
156 | int
|
---|
157 | hx509_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 |
|
---|
177 | int
|
---|
178 | hx509_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 |
|
---|
185 | static const struct units templatebits[] = {
|
---|
186 | { "ExtendedKeyUsage", HX509_CA_TEMPLATE_EKU },
|
---|
187 | { "KeyUsage", HX509_CA_TEMPLATE_KU },
|
---|
188 | { "SPKI", HX509_CA_TEMPLATE_SPKI },
|
---|
189 | { "notAfter", HX509_CA_TEMPLATE_NOTAFTER },
|
---|
190 | { "notBefore", HX509_CA_TEMPLATE_NOTBEFORE },
|
---|
191 | { "serial", HX509_CA_TEMPLATE_SERIAL },
|
---|
192 | { "subject", HX509_CA_TEMPLATE_SUBJECT },
|
---|
193 | { NULL, 0 }
|
---|
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 |
|
---|
205 | const struct units *
|
---|
206 | hx509_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 |
|
---|
225 | int
|
---|
226 | hx509_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 |
|
---|
303 | int
|
---|
304 | hx509_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 |
|
---|
327 | int
|
---|
328 | hx509_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 |
|
---|
349 | int
|
---|
350 | hx509_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 |
|
---|
371 | int
|
---|
372 | hx509_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 |
|
---|
396 | int
|
---|
397 | hx509_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 |
|
---|
421 | int
|
---|
422 | hx509_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 |
|
---|
465 | int
|
---|
466 | hx509_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 |
|
---|
549 | out:
|
---|
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 |
|
---|
569 | int
|
---|
570 | hx509_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 |
|
---|
598 | int
|
---|
599 | hx509_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);
|
---|
677 | out:
|
---|
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 |
|
---|
689 | static int
|
---|
690 | add_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);
|
---|
716 | out:
|
---|
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 |
|
---|
733 | int
|
---|
734 | hx509_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 |
|
---|
754 | int
|
---|
755 | hx509_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 |
|
---|
779 | int
|
---|
780 | hx509_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 |
|
---|
806 | int
|
---|
807 | hx509_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 |
|
---|
832 | int
|
---|
833 | hx509_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 |
|
---|
856 | int
|
---|
857 | hx509_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 |
|
---|
864 | static int
|
---|
865 | add_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 | }
|
---|
901 | out:
|
---|
902 | free_Extension(&ext);
|
---|
903 | return ret;
|
---|
904 | }
|
---|
905 |
|
---|
906 | static int
|
---|
907 | build_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 |
|
---|
935 | static int
|
---|
936 | ca_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 |
|
---|
1342 | out:
|
---|
1343 | free_Certificate(&c);
|
---|
1344 | return ret;
|
---|
1345 | }
|
---|
1346 |
|
---|
1347 | static int
|
---|
1348 | get_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 | }
|
---|
1429 | out:
|
---|
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 |
|
---|
1460 | int
|
---|
1461 | hx509_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 |
|
---|
1485 | out:
|
---|
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 |
|
---|
1504 | int
|
---|
1505 | hx509_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 | }
|
---|