Line data Source code
1 : /*
2 : * Copyright (c) 2006 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 <pkcs10_asn1.h>
36 :
37 : typedef struct abitstring_s {
38 : unsigned char *feats;
39 : size_t feat_bytes;
40 : } *abitstring;
41 :
42 : struct hx509_request_data {
43 : hx509_context context;
44 : hx509_name name;
45 : SubjectPublicKeyInfo key;
46 : KeyUsage ku;
47 : ExtKeyUsage eku;
48 : GeneralNames san;
49 : BasicConstraints bc;
50 : struct abitstring_s authorized_EKUs;
51 : struct abitstring_s authorized_SANs;
52 : uint32_t nunsupported_crit; /* Count of unsupported critical features requested */
53 : uint32_t nunsupported_opt; /* Count of unsupported optional features requested */
54 : uint32_t nauthorized; /* Count of supported features authorized */
55 : uint32_t ca_is_authorized:1;
56 : uint32_t ku_are_authorized:1;
57 : uint32_t include_BasicConstraints:1;
58 : };
59 :
60 : /**
61 : * Allocate and initialize an hx509_request structure representing a PKCS#10
62 : * certificate signing request.
63 : *
64 : * @param context An hx509 context.
65 : * @param req Where to put the new hx509_request object.
66 : *
67 : * @return An hx509 error code, see hx509_get_error_string().
68 : *
69 : * @ingroup hx509_request
70 : */
71 : HX509_LIB_FUNCTION int HX509_LIB_CALL
72 0 : hx509_request_init(hx509_context context, hx509_request *req)
73 : {
74 0 : *req = calloc(1, sizeof(**req));
75 0 : if (*req == NULL)
76 0 : return ENOMEM;
77 :
78 0 : (*req)->context = context;
79 0 : return 0;
80 : }
81 :
82 : /**
83 : * Free a certificate signing request object.
84 : *
85 : * @param req A pointer to the hx509_request to free.
86 : *
87 : * @ingroup hx509_request
88 : */
89 : HX509_LIB_FUNCTION void HX509_LIB_CALL
90 0 : hx509_request_free(hx509_request *reqp)
91 : {
92 0 : hx509_request req = *reqp;
93 :
94 0 : *reqp = NULL;
95 0 : if (req == NULL)
96 0 : return;
97 0 : if (req->name)
98 0 : hx509_name_free(&req->name);
99 0 : free(req->authorized_EKUs.feats);
100 0 : free(req->authorized_SANs.feats);
101 0 : free_SubjectPublicKeyInfo(&req->key);
102 0 : free_ExtKeyUsage(&req->eku);
103 0 : free_GeneralNames(&req->san);
104 0 : free_BasicConstraints(&req->bc);
105 0 : memset(req, 0, sizeof(*req));
106 0 : free(req);
107 : }
108 :
109 : /**
110 : * Make the CSR request a CA certificate
111 : *
112 : * @param context An hx509 context.
113 : * @param req The hx509_request to alter.
114 : * @param pathLenConstraint the pathLenConstraint for the BasicConstraints (optional)
115 : *
116 : * @return An hx509 error code, see hx509_get_error_string().
117 : *
118 : * @ingroup hx509_request
119 : */
120 : HX509_LIB_FUNCTION int HX509_LIB_CALL
121 0 : hx509_request_set_cA(hx509_context context,
122 : hx509_request req,
123 : unsigned *pathLenConstraint)
124 : {
125 0 : req->bc.cA = 1;
126 0 : if (pathLenConstraint) {
127 0 : if (req->bc.pathLenConstraint == NULL)
128 0 : req->bc.pathLenConstraint = malloc(sizeof(*pathLenConstraint));
129 0 : if (req->bc.pathLenConstraint == NULL)
130 0 : return ENOMEM;
131 0 : *req->bc.pathLenConstraint = *pathLenConstraint;
132 : }
133 0 : return 0;
134 : }
135 :
136 : /**
137 : * Make the CSR request an EE (end-entity, i.e., not a CA) certificate
138 : *
139 : * @param context An hx509 context.
140 : * @param req The hx509_request to alter.
141 : *
142 : * @ingroup hx509_request
143 : */
144 : HX509_LIB_FUNCTION void HX509_LIB_CALL
145 0 : hx509_request_set_eE(hx509_context context, hx509_request req)
146 : {
147 0 : req->bc.cA = 0;
148 0 : free(req->bc.pathLenConstraint);
149 0 : req->include_BasicConstraints = 1;
150 0 : req->ca_is_authorized = 0;
151 0 : }
152 :
153 : /**
154 : * Set the subjectName of the CSR.
155 : *
156 : * @param context An hx509 context.
157 : * @param req The hx509_request to alter.
158 : * @param name The subjectName.
159 : *
160 : * @return An hx509 error code, see hx509_get_error_string().
161 : *
162 : * @ingroup hx509_request
163 : */
164 : HX509_LIB_FUNCTION int HX509_LIB_CALL
165 0 : hx509_request_set_name(hx509_context context,
166 : hx509_request req,
167 : hx509_name name)
168 : {
169 0 : if (req->name)
170 0 : hx509_name_free(&req->name);
171 0 : if (name) {
172 0 : int ret = hx509_name_copy(context, name, &req->name);
173 0 : if (ret)
174 0 : return ret;
175 : }
176 0 : return 0;
177 : }
178 :
179 : /**
180 : * Get the subject name requested by a CSR.
181 : *
182 : * @param context An hx509 context.
183 : * @param req The hx509_request object.
184 : * @param name Where to put the name.
185 : *
186 : * @return An hx509 error code, see hx509_get_error_string().
187 : *
188 : * @ingroup hx509_request
189 : */
190 : HX509_LIB_FUNCTION int HX509_LIB_CALL
191 0 : hx509_request_get_name(hx509_context context,
192 : hx509_request req,
193 : hx509_name *name)
194 : {
195 0 : if (req->name == NULL) {
196 0 : hx509_set_error_string(context, 0, EINVAL, "Request has no name");
197 0 : return EINVAL;
198 : }
199 0 : return hx509_name_copy(context, req->name, name);
200 : }
201 :
202 : /**
203 : * Set the subject public key requested by a CSR.
204 : *
205 : * @param context An hx509 context.
206 : * @param req The hx509_request object.
207 : * @param key The public key.
208 : *
209 : * @return An hx509 error code, see hx509_get_error_string().
210 : *
211 : * @ingroup hx509_request
212 : */
213 : HX509_LIB_FUNCTION int HX509_LIB_CALL
214 0 : hx509_request_set_SubjectPublicKeyInfo(hx509_context context,
215 : hx509_request req,
216 : const SubjectPublicKeyInfo *key)
217 : {
218 0 : free_SubjectPublicKeyInfo(&req->key);
219 0 : return copy_SubjectPublicKeyInfo(key, &req->key);
220 : }
221 :
222 : /**
223 : * Get the subject public key requested by a CSR.
224 : *
225 : * @param context An hx509 context.
226 : * @param req The hx509_request object.
227 : * @param key Where to put the key.
228 : *
229 : * @return An hx509 error code, see hx509_get_error_string().
230 : *
231 : * @ingroup hx509_request
232 : */
233 : HX509_LIB_FUNCTION int HX509_LIB_CALL
234 0 : hx509_request_get_SubjectPublicKeyInfo(hx509_context context,
235 : hx509_request req,
236 : SubjectPublicKeyInfo *key)
237 : {
238 0 : return copy_SubjectPublicKeyInfo(&req->key, key);
239 : }
240 :
241 : /**
242 : * Set the key usage requested by a CSR.
243 : *
244 : * @param context An hx509 context.
245 : * @param req The hx509_request object.
246 : * @param ku The key usage.
247 : *
248 : * @return An hx509 error code, see hx509_get_error_string().
249 : *
250 : * @ingroup hx509_request
251 : */
252 : HX509_LIB_FUNCTION int HX509_LIB_CALL
253 0 : hx509_request_set_ku(hx509_context context, hx509_request req, KeyUsage ku)
254 : {
255 0 : uint64_t n = KeyUsage2int(ku);
256 :
257 0 : if ((KeyUsage2int(req->ku) & n) != n)
258 0 : req->ku_are_authorized = 0;
259 0 : req->ku = ku;
260 0 : return 0;
261 : }
262 :
263 : /**
264 : * Get the key usage requested by a CSR.
265 : *
266 : * @param context An hx509 context.
267 : * @param req The hx509_request object.
268 : * @param ku Where to put the key usage.
269 : *
270 : * @return An hx509 error code, see hx509_get_error_string().
271 : *
272 : * @ingroup hx509_request
273 : */
274 : HX509_LIB_FUNCTION int HX509_LIB_CALL
275 0 : hx509_request_get_ku(hx509_context context, hx509_request req, KeyUsage *ku)
276 : {
277 0 : *ku = req->ku;
278 0 : return 0;
279 : }
280 :
281 : /**
282 : * Add an extended key usage OID to a CSR.
283 : *
284 : * @param context An hx509 context.
285 : * @param req The hx509_request object.
286 : * @param oid The EKU OID.
287 : *
288 : * @return An hx509 error code, see hx509_get_error_string().
289 : *
290 : * @ingroup hx509_request
291 : */
292 : HX509_LIB_FUNCTION int HX509_LIB_CALL
293 0 : hx509_request_add_eku(hx509_context context,
294 : hx509_request req,
295 : const heim_oid *oid)
296 : {
297 0 : void *val;
298 0 : int ret;
299 :
300 0 : val = realloc(req->eku.val, sizeof(req->eku.val[0]) * (req->eku.len + 1));
301 0 : if (val == NULL)
302 0 : return ENOMEM;
303 0 : req->eku.val = val;
304 :
305 0 : ret = der_copy_oid(oid, &req->eku.val[req->eku.len]);
306 0 : if (ret)
307 0 : return ret;
308 :
309 0 : req->eku.len += 1;
310 :
311 0 : return 0;
312 : }
313 :
314 : /**
315 : * Add a GeneralName (Jabber ID) subject alternative name to a CSR.
316 : *
317 : * XXX Make this take a heim_octet_string, not a GeneralName*.
318 : *
319 : * @param context An hx509 context.
320 : * @param req The hx509_request object.
321 : * @param gn The GeneralName object.
322 : *
323 : * @return An hx509 error code, see hx509_get_error_string().
324 : *
325 : * @ingroup hx509_request
326 : */
327 : HX509_LIB_FUNCTION int HX509_LIB_CALL
328 0 : hx509_request_add_GeneralName(hx509_context context,
329 : hx509_request req,
330 : const GeneralName *gn)
331 : {
332 0 : return add_GeneralNames(&req->san, gn);
333 : }
334 :
335 : static int
336 0 : add_utf8_other_san(hx509_context context,
337 : GeneralNames *gns,
338 : const heim_oid *oid,
339 : const char *s)
340 : {
341 0 : const PKIXXmppAddr us = (const PKIXXmppAddr)(uintptr_t)s;
342 0 : GeneralName gn;
343 0 : size_t size;
344 0 : int ret;
345 :
346 0 : gn.element = choice_GeneralName_otherName;
347 0 : gn.u.otherName.type_id.length = 0;
348 0 : gn.u.otherName.type_id.components = 0;
349 0 : gn.u.otherName.value.data = NULL;
350 0 : gn.u.otherName.value.length = 0;
351 0 : ret = der_copy_oid(oid, &gn.u.otherName.type_id);
352 0 : if (ret == 0)
353 0 : ASN1_MALLOC_ENCODE(PKIXXmppAddr, gn.u.otherName.value.data,
354 : gn.u.otherName.value.length, &us, &size, ret);
355 0 : if (ret == 0 && size != gn.u.otherName.value.length)
356 0 : _hx509_abort("internal ASN.1 encoder error");
357 0 : if (ret == 0)
358 0 : ret = add_GeneralNames(gns, &gn);
359 0 : free_GeneralName(&gn);
360 0 : if (ret)
361 0 : hx509_set_error_string(context, 0, ret, "Out of memory");
362 0 : return ret;
363 : }
364 :
365 : /**
366 : * Add an xmppAddr (Jabber ID) subject alternative name to a CSR.
367 : *
368 : * @param context An hx509 context.
369 : * @param req The hx509_request object.
370 : * @param jid The XMPP address.
371 : *
372 : * @return An hx509 error code, see hx509_get_error_string().
373 : *
374 : * @ingroup hx509_request
375 : */
376 : HX509_LIB_FUNCTION int HX509_LIB_CALL
377 0 : hx509_request_add_xmpp_name(hx509_context context,
378 : hx509_request req,
379 : const char *jid)
380 : {
381 0 : return add_utf8_other_san(context, &req->san,
382 : &asn1_oid_id_pkix_on_xmppAddr, jid);
383 : }
384 :
385 : /**
386 : * Add a Microsoft UPN subject alternative name to a CSR.
387 : *
388 : * @param context An hx509 context.
389 : * @param req The hx509_request object.
390 : * @param hostname The XMPP address.
391 : *
392 : * @return An hx509 error code, see hx509_get_error_string().
393 : *
394 : * @ingroup hx509_request
395 : */
396 : HX509_LIB_FUNCTION int HX509_LIB_CALL
397 0 : hx509_request_add_ms_upn_name(hx509_context context,
398 : hx509_request req,
399 : const char *upn)
400 : {
401 0 : return add_utf8_other_san(context, &req->san, &asn1_oid_id_pkinit_ms_san,
402 : upn);
403 : }
404 :
405 : /**
406 : * Add a dNSName (hostname) subject alternative name to a CSR.
407 : *
408 : * @param context An hx509 context.
409 : * @param req The hx509_request object.
410 : * @param hostname The fully-qualified hostname.
411 : *
412 : * @return An hx509 error code, see hx509_get_error_string().
413 : *
414 : * @ingroup hx509_request
415 : */
416 : HX509_LIB_FUNCTION int HX509_LIB_CALL
417 0 : hx509_request_add_dns_name(hx509_context context,
418 : hx509_request req,
419 : const char *hostname)
420 : {
421 0 : GeneralName name;
422 :
423 0 : memset(&name, 0, sizeof(name));
424 0 : name.element = choice_GeneralName_dNSName;
425 0 : name.u.dNSName.data = rk_UNCONST(hostname);
426 0 : name.u.dNSName.length = strlen(hostname);
427 :
428 0 : return add_GeneralNames(&req->san, &name);
429 : }
430 :
431 : /**
432 : * Add a dnsSRV (_service.hostname) subject alternative name to a CSR.
433 : *
434 : * @param context An hx509 context.
435 : * @param req The hx509_request object.
436 : * @param dnssrv The DNS SRV name.
437 : *
438 : * @return An hx509 error code, see hx509_get_error_string().
439 : *
440 : * @ingroup hx509_request
441 : */
442 : HX509_LIB_FUNCTION int HX509_LIB_CALL
443 0 : hx509_request_add_dns_srv(hx509_context context,
444 : hx509_request req,
445 : const char *dnssrv)
446 : {
447 0 : GeneralName gn;
448 0 : SRVName n;
449 0 : size_t size;
450 0 : int ret;
451 :
452 0 : memset(&n, 0, sizeof(n));
453 0 : memset(&gn, 0, sizeof(gn));
454 0 : gn.element = choice_GeneralName_otherName;
455 0 : gn.u.otherName.type_id.length = 0;
456 0 : gn.u.otherName.type_id.components = 0;
457 0 : gn.u.otherName.value.data = NULL;
458 0 : gn.u.otherName.value.length = 0;
459 0 : n.length = strlen(dnssrv);
460 0 : n.data = (void *)(uintptr_t)dnssrv;
461 0 : ASN1_MALLOC_ENCODE(SRVName,
462 : gn.u.otherName.value.data,
463 : gn.u.otherName.value.length, &n, &size, ret);
464 0 : if (ret == 0)
465 0 : ret = der_copy_oid(&asn1_oid_id_pkix_on_dnsSRV, &gn.u.otherName.type_id);
466 0 : if (ret == 0)
467 0 : ret = add_GeneralNames(&req->san, &gn);
468 0 : free_GeneralName(&gn);
469 0 : return ret;
470 : }
471 :
472 : /**
473 : * Add an rfc822Name (e-mail address) subject alternative name to a CSR.
474 : *
475 : * @param context An hx509 context.
476 : * @param req The hx509_request object.
477 : * @param email The e-mail address.
478 : *
479 : * @return An hx509 error code, see hx509_get_error_string().
480 : *
481 : * @ingroup hx509_request
482 : */
483 : HX509_LIB_FUNCTION int HX509_LIB_CALL
484 0 : hx509_request_add_email(hx509_context context,
485 : hx509_request req,
486 : const char *email)
487 : {
488 0 : GeneralName name;
489 :
490 0 : memset(&name, 0, sizeof(name));
491 0 : name.element = choice_GeneralName_rfc822Name;
492 0 : name.u.rfc822Name.data = rk_UNCONST(email);
493 0 : name.u.rfc822Name.length = strlen(email);
494 :
495 0 : return add_GeneralNames(&req->san, &name);
496 : }
497 :
498 : /**
499 : * Add a registeredID (OID) subject alternative name to a CSR.
500 : *
501 : * @param context An hx509 context.
502 : * @param req The hx509_request object.
503 : * @param oid The OID.
504 : *
505 : * @return An hx509 error code, see hx509_get_error_string().
506 : *
507 : * @ingroup hx509_request
508 : */
509 : HX509_LIB_FUNCTION int HX509_LIB_CALL
510 0 : hx509_request_add_registered(hx509_context context,
511 : hx509_request req,
512 : heim_oid *oid)
513 : {
514 0 : GeneralName name;
515 0 : int ret;
516 :
517 0 : memset(&name, 0, sizeof(name));
518 0 : name.element = choice_GeneralName_registeredID;
519 0 : ret = der_copy_oid(oid, &name.u.registeredID);
520 0 : if (ret)
521 0 : return ret;
522 0 : ret = add_GeneralNames(&req->san, &name);
523 0 : free_GeneralName(&name);
524 0 : return ret;
525 : }
526 :
527 : /**
528 : * Add a Kerberos V5 principal subject alternative name to a CSR.
529 : *
530 : * @param context An hx509 context.
531 : * @param req The hx509_request object.
532 : * @param princ The Kerberos principal name.
533 : *
534 : * @return An hx509 error code, see hx509_get_error_string().
535 : *
536 : * @ingroup hx509_request
537 : */
538 : HX509_LIB_FUNCTION int HX509_LIB_CALL
539 0 : hx509_request_add_pkinit(hx509_context context,
540 : hx509_request req,
541 : const char *princ)
542 : {
543 0 : KRB5PrincipalName kn;
544 0 : GeneralName gn;
545 0 : int ret;
546 :
547 0 : memset(&kn, 0, sizeof(kn));
548 0 : memset(&gn, 0, sizeof(gn));
549 0 : gn.element = choice_GeneralName_otherName;
550 0 : gn.u.otherName.type_id.length = 0;
551 0 : gn.u.otherName.type_id.components = 0;
552 0 : gn.u.otherName.value.data = NULL;
553 0 : gn.u.otherName.value.length = 0;
554 0 : ret = der_copy_oid(&asn1_oid_id_pkinit_san, &gn.u.otherName.type_id);
555 0 : if (ret == 0)
556 0 : ret = _hx509_make_pkinit_san(context, princ, &gn.u.otherName.value);
557 0 : if (ret == 0)
558 0 : ret = add_GeneralNames(&req->san, &gn);
559 0 : free_GeneralName(&gn);
560 0 : return ret;
561 : }
562 :
563 : /* XXX Add DNSSRV and other SANs */
564 :
565 : static int
566 0 : get_exts(hx509_context context,
567 : const hx509_request req,
568 : Extensions *exts)
569 : {
570 0 : size_t size;
571 0 : int ret = 0;
572 :
573 0 : exts->val = NULL;
574 0 : exts->len = 0;
575 :
576 0 : if (req->bc.cA || req->include_BasicConstraints) {
577 0 : Extension e;
578 :
579 : /*
580 : * If `!req->bc.cA' then we don't include BasicConstraints unless
581 : * hx509_request_set_eE() was called on this request, and in that case
582 : * we make this extension non-critical. We do this to emulate Dell
583 : * iDRAC CSR-making software.
584 : *
585 : * If `req->bc.cA' then we make the BasicConstraints critical,
586 : * obviously.
587 : */
588 0 : memset(&e, 0, sizeof(e));
589 0 : e.critical = req->bc.cA ? 1 : 0;
590 0 : if (ret == 0)
591 0 : ASN1_MALLOC_ENCODE(BasicConstraints, e.extnValue.data, e.extnValue.length,
592 : &req->bc, &size, ret);
593 0 : if (ret == 0)
594 0 : ret = der_copy_oid(&asn1_oid_id_x509_ce_basicConstraints, &e.extnID);
595 0 : if (ret == 0)
596 0 : ret = add_Extensions(exts, &e);
597 0 : free_Extension(&e);
598 : }
599 0 : if (KeyUsage2int(req->ku)) {
600 0 : Extension e;
601 :
602 0 : memset(&e, 0, sizeof(e));
603 : /* The critical field needs to be made DEFAULT FALSE... */
604 0 : e.critical = 1;
605 0 : if (ret == 0)
606 0 : ASN1_MALLOC_ENCODE(KeyUsage, e.extnValue.data, e.extnValue.length,
607 : &req->ku, &size, ret);
608 0 : if (ret == 0)
609 0 : ret = der_copy_oid(&asn1_oid_id_x509_ce_keyUsage, &e.extnID);
610 0 : if (ret == 0)
611 0 : ret = add_Extensions(exts, &e);
612 0 : free_Extension(&e);
613 : }
614 0 : if (ret == 0 && req->eku.len) {
615 0 : Extension e;
616 :
617 0 : memset(&e, 0, sizeof(e));
618 0 : e.critical = 1;
619 0 : if (ret == 0)
620 0 : ASN1_MALLOC_ENCODE(ExtKeyUsage,
621 : e.extnValue.data, e.extnValue.length,
622 : &req->eku, &size, ret);
623 0 : if (ret == 0)
624 0 : ret = der_copy_oid(&asn1_oid_id_x509_ce_extKeyUsage, &e.extnID);
625 0 : if (ret == 0)
626 0 : ret = add_Extensions(exts, &e);
627 0 : free_Extension(&e);
628 : }
629 0 : if (ret == 0 && req->san.len) {
630 0 : Extension e;
631 :
632 0 : memset(&e, 0, sizeof(e));
633 : /*
634 : * SANs are critical when the subject Name is empty.
635 : *
636 : * The empty DN check could probably stand to be a function we export.
637 : */
638 0 : e.critical = FALSE;
639 0 : if (req->name &&
640 0 : req->name->der_name.element == choice_Name_rdnSequence &&
641 0 : req->name->der_name.u.rdnSequence.len == 0)
642 0 : e.critical = 1;
643 0 : if (ret == 0)
644 0 : ASN1_MALLOC_ENCODE(GeneralNames,
645 : e.extnValue.data, e.extnValue.length,
646 : &req->san,
647 : &size, ret);
648 0 : if (ret == 0)
649 0 : ret = der_copy_oid(&asn1_oid_id_x509_ce_subjectAltName, &e.extnID);
650 0 : if (ret == 0)
651 0 : ret = add_Extensions(exts, &e);
652 0 : free_Extension(&e);
653 : }
654 :
655 0 : return ret;
656 : }
657 :
658 : /**
659 : * Get the KU/EKUs/SANs set on a request as a DER-encoding of Extensions.
660 : *
661 : * @param context An hx509 context.
662 : * @param req The hx509_request object.
663 : * @param exts_der Where to put the DER-encoded Extensions.
664 : *
665 : * @return An hx509 error code, see hx509_get_error_string().
666 : *
667 : * @ingroup hx509_request
668 : */
669 : HX509_LIB_FUNCTION int HX509_LIB_CALL
670 0 : hx509_request_get_exts(hx509_context context,
671 : const hx509_request req,
672 : heim_octet_string *exts_der)
673 : {
674 0 : Extensions exts;
675 0 : size_t size;
676 0 : int ret;
677 :
678 0 : exts_der->data = NULL;
679 0 : exts_der->length = 0;
680 0 : ret = get_exts(context, req, &exts);
681 0 : if (ret == 0 && exts.len /* Extensions has a min size constraint of 1 */)
682 0 : ASN1_MALLOC_ENCODE(Extensions, exts_der->data, exts_der->length,
683 : &exts, &size, ret);
684 0 : free_Extensions(&exts);
685 0 : return ret;
686 : }
687 :
688 : /* XXX Add PEM */
689 :
690 : /**
691 : * Encode a CSR.
692 : *
693 : * @param context An hx509 context.
694 : * @param req The hx509_request object.
695 : * @param signer The private key corresponding to the CSR's subject public key.
696 : * @param request Where to put the DER-encoded CSR.
697 : *
698 : * @return An hx509 error code, see hx509_get_error_string().
699 : *
700 : * @ingroup hx509_request
701 : */
702 : HX509_LIB_FUNCTION int HX509_LIB_CALL
703 0 : hx509_request_to_pkcs10(hx509_context context,
704 : const hx509_request req,
705 : const hx509_private_key signer,
706 : heim_octet_string *request)
707 : {
708 0 : CertificationRequest r;
709 0 : Extensions exts;
710 0 : heim_octet_string data;
711 0 : size_t size;
712 0 : int ret;
713 :
714 0 : request->data = NULL;
715 0 : request->length = 0;
716 :
717 0 : data.length = 0;
718 0 : data.data = NULL;
719 :
720 0 : if (req->name == NULL) {
721 0 : hx509_set_error_string(context, 0, EINVAL,
722 : "PKCS10 needs to have a subject");
723 0 : return EINVAL;
724 : }
725 :
726 0 : memset(&r, 0, sizeof(r));
727 :
728 : /* Setup CSR */
729 0 : r.certificationRequestInfo.version = pkcs10_v1;
730 0 : ret = copy_Name(&req->name->der_name,
731 : &r.certificationRequestInfo.subject);
732 0 : if (ret == 0)
733 0 : ret = copy_SubjectPublicKeyInfo(&req->key,
734 : &r.certificationRequestInfo.subjectPKInfo);
735 :
736 : /* Encode extReq attribute with requested Certificate Extensions */
737 :
738 0 : if (ret == 0)
739 0 : ret = get_exts(context, req, &exts);
740 0 : if (ret == 0 && exts.len) {
741 0 : Attribute *a = NULL; /* Quiet VC */
742 0 : heim_any extns;
743 :
744 0 : extns.data = NULL;
745 0 : extns.length = 0;
746 0 : r.certificationRequestInfo.attributes =
747 0 : calloc(1, sizeof(r.certificationRequestInfo.attributes[0]));
748 0 : if (r.certificationRequestInfo.attributes == NULL)
749 0 : ret = ENOMEM;
750 0 : if (ret == 0) {
751 0 : r.certificationRequestInfo.attributes[0].len = 1;
752 0 : r.certificationRequestInfo.attributes[0].val =
753 0 : calloc(1, sizeof(r.certificationRequestInfo.attributes[0].val[0]));
754 0 : if (r.certificationRequestInfo.attributes[0].val == NULL)
755 0 : ret = ENOMEM;
756 0 : if (ret == 0)
757 0 : a = r.certificationRequestInfo.attributes[0].val;
758 : }
759 0 : if (ret == 0)
760 0 : ASN1_MALLOC_ENCODE(Extensions, extns.data, extns.length,
761 : &exts, &size, ret);
762 0 : if (ret == 0 && a)
763 0 : ret = der_copy_oid(&asn1_oid_id_pkcs9_extReq, &a->type);
764 0 : if (ret == 0)
765 0 : ret = add_AttributeValues(&a->value, &extns);
766 0 : free_heim_any(&extns);
767 : }
768 :
769 : /* Encode CSR body for signing */
770 0 : if (ret == 0)
771 0 : ASN1_MALLOC_ENCODE(CertificationRequestInfo, data.data, data.length,
772 : &r.certificationRequestInfo, &size, ret);
773 0 : if (ret == 0 && data.length != size)
774 0 : abort();
775 :
776 : /* Self-sign CSR body */
777 0 : if (ret == 0) {
778 0 : ret = _hx509_create_signature_bitstring(context, signer,
779 : _hx509_crypto_default_sig_alg,
780 : &data,
781 : &r.signatureAlgorithm,
782 : &r.signature);
783 : }
784 0 : free(data.data);
785 :
786 : /* Encode CSR */
787 0 : if (ret == 0)
788 0 : ASN1_MALLOC_ENCODE(CertificationRequest, request->data, request->length,
789 : &r, &size, ret);
790 0 : if (ret == 0 && request->length != size)
791 0 : abort();
792 :
793 0 : free_CertificationRequest(&r);
794 0 : free_Extensions(&exts);
795 0 : return ret;
796 : }
797 :
798 : /**
799 : * Parse an encoded CSR and verify its self-signature.
800 : *
801 : * @param context An hx509 context.
802 : * @param der The DER-encoded CSR.
803 : * @param req Where to put request object.
804 : *
805 : * @return An hx509 error code, see hx509_get_error_string().
806 : *
807 : * @ingroup hx509_request
808 : */
809 : HX509_LIB_FUNCTION int HX509_LIB_CALL
810 0 : hx509_request_parse_der(hx509_context context,
811 : heim_octet_string *der,
812 : hx509_request *req)
813 : {
814 0 : CertificationRequestInfo *rinfo = NULL;
815 0 : CertificationRequest r;
816 0 : hx509_cert signer = NULL;
817 0 : Extensions exts;
818 0 : size_t i, size;
819 0 : int ret;
820 :
821 0 : memset(&exts, 0, sizeof(exts));
822 :
823 : /* Initial setup and decoding of CSR */
824 0 : ret = hx509_request_init(context, req);
825 0 : if (ret)
826 0 : return ret;
827 0 : ret = decode_CertificationRequest(der->data, der->length, &r, &size);
828 0 : if (ret) {
829 0 : hx509_set_error_string(context, 0, ret, "Failed to decode CSR");
830 0 : free(*req);
831 0 : *req = NULL;
832 0 : return ret;
833 : }
834 0 : rinfo = &r.certificationRequestInfo;
835 :
836 : /*
837 : * Setup a 'signer' for verifying the self-signature for proof of
838 : * possession.
839 : *
840 : * Sadly we need a "certificate" here because _hx509_verify_signature_*()
841 : * functions want one as a signer even though all the verification
842 : * functions that use the signer argument only ever use the spki of the
843 : * signer certificate.
844 : *
845 : * FIXME Change struct signature_alg's verify_signature's prototype to use
846 : * an spki instead of an hx509_cert as the signer! The we won't have
847 : * to do this.
848 : */
849 0 : if (ret == 0) {
850 0 : Certificate c;
851 0 : memset(&c, 0, sizeof(c));
852 0 : c.tbsCertificate.subjectPublicKeyInfo = rinfo->subjectPKInfo;
853 0 : if ((signer = hx509_cert_init(context, &c, NULL)) == NULL)
854 0 : ret = ENOMEM;
855 : }
856 :
857 : /* Verify the signature */
858 0 : if (ret == 0)
859 0 : ret = _hx509_verify_signature_bitstring(context, signer,
860 : &r.signatureAlgorithm,
861 0 : &rinfo->_save,
862 : &r.signature);
863 0 : if (ret)
864 0 : hx509_set_error_string(context, 0, ret,
865 : "CSR signature verification failed");
866 0 : hx509_cert_free(signer);
867 :
868 : /* Populate the hx509_request */
869 0 : if (ret == 0)
870 0 : ret = hx509_request_set_SubjectPublicKeyInfo(context, *req,
871 0 : &rinfo->subjectPKInfo);
872 0 : if (ret == 0)
873 0 : ret = _hx509_name_from_Name(&rinfo->subject, &(*req)->name);
874 :
875 : /* Extract KUs, EKUs, and SANs from the CSR's attributes */
876 0 : if (ret || !rinfo->attributes || !rinfo->attributes[0].len)
877 0 : goto out;
878 :
879 0 : for (i = 0; ret == 0 && i < rinfo->attributes[0].len; i++) {
880 0 : Attribute *a = &rinfo->attributes[0].val[i];
881 0 : heim_any *av = NULL;
882 :
883 : /* We only support Extensions request attributes */
884 0 : if (der_heim_oid_cmp(&a->type, &asn1_oid_id_pkcs9_extReq) != 0) {
885 0 : char *oidstr = NULL;
886 :
887 : /*
888 : * We need an HX509_TRACE facility for this sort of warning.
889 : *
890 : * We'd put the warning in the context and then allow the caller to
891 : * extract and reset the warning.
892 : *
893 : * FIXME
894 : */
895 0 : der_print_heim_oid(&a->type, '.', &oidstr);
896 0 : warnx("Unknown or unsupported CSR attribute %s",
897 0 : oidstr ? oidstr : "<error decoding OID>");
898 0 : free(oidstr);
899 0 : continue;
900 : }
901 0 : if (!a->value.val)
902 0 : continue;
903 :
904 0 : av = a->value.val;
905 0 : ret = decode_Extensions(av->data, av->length, &exts, NULL);
906 0 : if (ret) {
907 0 : hx509_set_error_string(context, 0, ret,
908 : "CSR signature verification failed "
909 : "due to invalid extReq attribute");
910 0 : goto out;
911 : }
912 : }
913 0 : for (i = 0; ret == 0 && i < exts.len; i++) {
914 0 : const char *what = "";
915 0 : Extension *e = &exts.val[i];
916 :
917 0 : if (der_heim_oid_cmp(&e->extnID,
918 : &asn1_oid_id_x509_ce_keyUsage) == 0) {
919 0 : ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length,
920 0 : &(*req)->ku, NULL);
921 0 : what = "keyUsage";
922 : /*
923 : * Count all KUs as one requested extension to be authorized,
924 : * though the caller will have to check the KU values individually.
925 : */
926 0 : if (KeyUsage2int((*req)->ku) & ~KeyUsage2int(int2KeyUsage(~0ULL))) {
927 0 : if (e->critical)
928 0 : (*req)->nunsupported_crit++;
929 : else
930 0 : (*req)->nunsupported_opt++;
931 : }
932 0 : } else if (der_heim_oid_cmp(&e->extnID,
933 : &asn1_oid_id_x509_ce_extKeyUsage) == 0) {
934 0 : ret = decode_ExtKeyUsage(e->extnValue.data, e->extnValue.length,
935 0 : &(*req)->eku, NULL);
936 0 : what = "extKeyUsage";
937 :
938 : /*
939 : * Count each EKU as a separate requested extension to be
940 : * authorized.
941 : */
942 0 : } else if (der_heim_oid_cmp(&e->extnID,
943 : &asn1_oid_id_x509_ce_subjectAltName) == 0) {
944 0 : ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length,
945 0 : &(*req)->san, NULL);
946 0 : what = "subjectAlternativeName";
947 :
948 : /*
949 : * Count each SAN as a separate requested extension to be
950 : * authorized.
951 : */
952 0 : } else if (der_heim_oid_cmp(&e->extnID,
953 : &asn1_oid_id_x509_ce_basicConstraints) == 0) {
954 0 : (*req)->include_BasicConstraints = 1;
955 0 : ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length,
956 0 : &(*req)->bc, NULL);
957 : } else {
958 0 : char *oidstr = NULL;
959 :
960 0 : if (e->critical)
961 0 : (*req)->nunsupported_crit++;
962 : else
963 0 : (*req)->nunsupported_opt++;
964 :
965 : /*
966 : * We need an HX509_TRACE facility for this sort of warning.
967 : *
968 : * We'd put the warning in the context and then allow the caller to
969 : * extract and reset the warning.
970 : *
971 : * FIXME
972 : */
973 0 : der_print_heim_oid(&e->extnID, '.', &oidstr);
974 0 : warnx("Unknown or unsupported CSR extension request %s",
975 0 : oidstr ? oidstr : "<error decoding OID>");
976 0 : free(oidstr);
977 : }
978 0 : if (ret) {
979 0 : hx509_set_error_string(context, 0, ret,
980 : "CSR signature verification failed "
981 : "due to invalid %s extension", what);
982 0 : break;
983 : }
984 : }
985 :
986 0 : out:
987 0 : free_CertificationRequest(&r);
988 0 : free_Extensions(&exts);
989 0 : if (ret)
990 0 : hx509_request_free(req);
991 0 : return ret;
992 : }
993 :
994 : /**
995 : * Parse an encoded CSR and verify its self-signature.
996 : *
997 : * @param context An hx509 context.
998 : * @param csr The name of a store containing the CSR ("PKCS10:/path/to/file")
999 : * @param req Where to put request object.
1000 : *
1001 : * @return An hx509 error code, see hx509_get_error_string().
1002 : *
1003 : * @ingroup hx509_request
1004 : */
1005 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1006 0 : hx509_request_parse(hx509_context context,
1007 : const char *csr,
1008 : hx509_request *req)
1009 : {
1010 0 : heim_octet_string d;
1011 0 : int ret;
1012 :
1013 : /* XXX Add support for PEM */
1014 0 : if (strncmp(csr, "PKCS10:", 7) != 0) {
1015 0 : hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
1016 : "CSR location does not start with \"PKCS10:\": %s",
1017 : csr);
1018 0 : return HX509_UNSUPPORTED_OPERATION;
1019 : }
1020 :
1021 0 : ret = rk_undumpdata(csr + 7, &d.data, &d.length);
1022 0 : if (ret) {
1023 0 : hx509_set_error_string(context, 0, ret, "Could not read %s", csr);
1024 0 : return ret;
1025 : }
1026 :
1027 0 : ret = hx509_request_parse_der(context, &d, req);
1028 0 : free(d.data);
1029 0 : if (ret)
1030 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1031 : " (while parsing CSR from %s)", csr);
1032 0 : return ret;
1033 : }
1034 :
1035 : /**
1036 : * Get some EKU from a CSR. Usable as an iterator.
1037 : *
1038 : * @param context An hx509 context.
1039 : * @param req The hx509_request object.
1040 : * @param idx The index of the EKU (0 for the first) to return
1041 : * @param out A pointer to a char * variable where the OID will be placed
1042 : * (caller must free with free())
1043 : *
1044 : * @return Zero on success, HX509_NO_ITEM if no such item exists (denoting
1045 : * iteration end), or an error.
1046 : *
1047 : * @ingroup hx509_request
1048 : */
1049 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1050 0 : hx509_request_get_eku(hx509_request req,
1051 : size_t idx,
1052 : char **out)
1053 : {
1054 0 : *out = NULL;
1055 0 : if (idx >= req->eku.len)
1056 0 : return HX509_NO_ITEM;
1057 0 : return der_print_heim_oid(&req->eku.val[idx], '.', out);
1058 : }
1059 :
1060 : static int
1061 0 : abitstring_check(abitstring a, size_t n, int idx)
1062 : {
1063 0 : size_t bytes;
1064 :
1065 0 : if (idx >= n)
1066 0 : return HX509_NO_ITEM;
1067 :
1068 0 : bytes = (idx + 1) / CHAR_BIT + (((idx + 1) % CHAR_BIT) ? 1 : 0);
1069 0 : if (a->feat_bytes < bytes)
1070 0 : return 0;
1071 :
1072 0 : return !!(a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT)));
1073 : }
1074 :
1075 : /*
1076 : * Sets and returns 0 if not already set, -1 if already set. Positive return
1077 : * values are system errors.
1078 : */
1079 : static int
1080 0 : abitstring_set(abitstring a, size_t n, int idx)
1081 : {
1082 0 : size_t bytes;
1083 :
1084 0 : if (idx >= n)
1085 0 : return HX509_NO_ITEM;
1086 :
1087 0 : bytes = n / CHAR_BIT + ((n % CHAR_BIT) ? 1 : 0);
1088 0 : if (a->feat_bytes < bytes) {
1089 0 : unsigned char *tmp;
1090 :
1091 0 : if ((tmp = realloc(a->feats, bytes)) == NULL)
1092 0 : return ENOMEM;
1093 0 : memset(tmp + a->feat_bytes, 0, bytes - a->feat_bytes);
1094 0 : a->feats = tmp;
1095 0 : a->feat_bytes = bytes;
1096 : }
1097 :
1098 0 : if (!(a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT)))) {
1099 0 : a->feats[idx / CHAR_BIT] |= 1UL<<(idx % CHAR_BIT);
1100 0 : return 0;
1101 : }
1102 0 : return -1;
1103 : }
1104 :
1105 : /*
1106 : * Resets and returns 0 if not already reset, -1 if already reset. Positive
1107 : * return values are system errors.
1108 : */
1109 : static int
1110 0 : abitstring_reset(abitstring a, size_t n, int idx)
1111 : {
1112 0 : size_t bytes;
1113 :
1114 0 : if (idx >= n)
1115 0 : return HX509_NO_ITEM;
1116 :
1117 0 : bytes = (idx + 1) / CHAR_BIT + (((idx + 1) % CHAR_BIT) ? 1 : 0);
1118 0 : if (a->feat_bytes >= bytes &&
1119 0 : (a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT)))) {
1120 0 : a->feats[idx / CHAR_BIT] &= ~(1UL<<(idx % CHAR_BIT));
1121 0 : return 0;
1122 : }
1123 0 : return -1;
1124 : }
1125 :
1126 : static int
1127 0 : authorize_feat(hx509_request req, abitstring a, size_t n, int idx)
1128 : {
1129 0 : int ret;
1130 :
1131 0 : ret = abitstring_set(a, n, idx);
1132 0 : switch (ret) {
1133 0 : case 0:
1134 0 : req->nauthorized++;
1135 : HEIM_FALLTHROUGH;
1136 0 : case -1:
1137 0 : return 0;
1138 0 : default:
1139 0 : return ret;
1140 : }
1141 : }
1142 :
1143 : static int
1144 0 : reject_feat(hx509_request req, abitstring a, size_t n, int idx)
1145 : {
1146 0 : int ret;
1147 :
1148 0 : ret = abitstring_reset(a, n, idx);
1149 0 : switch (ret) {
1150 0 : case 0:
1151 0 : req->nauthorized--;
1152 : HEIM_FALLTHROUGH;
1153 0 : case -1:
1154 0 : return 0;
1155 0 : default:
1156 0 : return ret;
1157 : }
1158 : }
1159 :
1160 : /**
1161 : * Authorize issuance of a CA certificate as requested.
1162 : *
1163 : * @param req The hx509_request object.
1164 : * @param pathLenConstraint the pathLenConstraint for the BasicConstraints (optional)
1165 : *
1166 : * @return an hx509 or system error.
1167 : *
1168 : * @ingroup hx509_request
1169 : */
1170 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1171 0 : hx509_request_authorize_cA(hx509_request req, unsigned *pathLenConstraint)
1172 : {
1173 0 : int ret;
1174 :
1175 0 : ret = hx509_request_set_cA(NULL, req, pathLenConstraint);
1176 0 : req->ca_is_authorized++;
1177 0 : return ret;
1178 : }
1179 :
1180 : /**
1181 : * Filter the requested KeyUsage and mark it authorized.
1182 : *
1183 : * @param req The hx509_request object.
1184 : * @param ku Permitted KeyUsage
1185 : *
1186 : * @ingroup hx509_request
1187 : */
1188 : HX509_LIB_FUNCTION void HX509_LIB_CALL
1189 0 : hx509_request_authorize_ku(hx509_request req, KeyUsage ku)
1190 : {
1191 0 : (void) hx509_request_set_ku(NULL, req, ku);
1192 0 : req->ku = int2KeyUsage(KeyUsage2int(req->ku) & KeyUsage2int(ku));
1193 0 : if (KeyUsage2int(ku))
1194 0 : req->ku_are_authorized = 1;
1195 0 : }
1196 :
1197 : /**
1198 : * Mark a requested EKU as authorized.
1199 : *
1200 : * @param req The hx509_request object.
1201 : * @param idx The index of an EKU that can be fetched with
1202 : * hx509_request_get_eku()
1203 : *
1204 : * @return Zero on success, an error otherwise.
1205 : *
1206 : * @ingroup hx509_request
1207 : */
1208 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1209 0 : hx509_request_authorize_eku(hx509_request req, size_t idx)
1210 : {
1211 0 : return authorize_feat(req, &req->authorized_EKUs, req->eku.len, idx);
1212 : }
1213 :
1214 : /**
1215 : * Mark a requested EKU as not authorized.
1216 : *
1217 : * @param req The hx509_request object.
1218 : * @param idx The index of an EKU that can be fetched with
1219 : * hx509_request_get_eku()
1220 : *
1221 : * @return Zero on success, an error otherwise.
1222 : *
1223 : * @ingroup hx509_request
1224 : */
1225 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1226 0 : hx509_request_reject_eku(hx509_request req, size_t idx)
1227 : {
1228 0 : return reject_feat(req, &req->authorized_EKUs, req->eku.len, idx);
1229 : }
1230 :
1231 : /**
1232 : * Check if an EKU has been marked authorized.
1233 : *
1234 : * @param req The hx509_request object.
1235 : * @param idx The index of an EKU that can be fetched with
1236 : * hx509_request_get_eku()
1237 : *
1238 : * @return Non-zero if authorized, zero if not.
1239 : *
1240 : * @ingroup hx509_request
1241 : */
1242 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1243 0 : hx509_request_eku_authorized_p(hx509_request req, size_t idx)
1244 : {
1245 0 : return abitstring_check(&req->authorized_EKUs, req->eku.len, idx);
1246 : }
1247 :
1248 : /**
1249 : * Mark a requested SAN as authorized.
1250 : *
1251 : * @param req The hx509_request object.
1252 : * @param idx The cursor as modified by a SAN iterator.
1253 : *
1254 : * @return Zero on success, an error otherwise.
1255 : *
1256 : * @ingroup hx509_request
1257 : */
1258 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1259 0 : hx509_request_authorize_san(hx509_request req, size_t idx)
1260 : {
1261 0 : return authorize_feat(req, &req->authorized_SANs, req->san.len, idx);
1262 : }
1263 :
1264 : /**
1265 : * Mark a requested SAN as not authorized.
1266 : *
1267 : * @param req The hx509_request object.
1268 : * @param idx The cursor as modified by a SAN iterator.
1269 : *
1270 : * @return Zero on success, an error otherwise.
1271 : *
1272 : * @ingroup hx509_request
1273 : */
1274 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1275 0 : hx509_request_reject_san(hx509_request req, size_t idx)
1276 : {
1277 0 : return reject_feat(req, &req->authorized_SANs, req->san.len, idx);
1278 : }
1279 :
1280 : /**
1281 : * Check if a SAN has been marked authorized.
1282 : *
1283 : * @param req The hx509_request object.
1284 : * @param idx The index of a SAN that can be fetched with
1285 : * hx509_request_get_san()
1286 : *
1287 : * @return Non-zero if authorized, zero if not.
1288 : *
1289 : * @ingroup hx509_request
1290 : */
1291 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1292 0 : hx509_request_san_authorized_p(hx509_request req, size_t idx)
1293 : {
1294 0 : return abitstring_check(&req->authorized_SANs, req->san.len, idx);
1295 : }
1296 :
1297 : /**
1298 : * Return the count of unsupported requested certificate extensions.
1299 : *
1300 : * @param req The hx509_request object.
1301 : * @return The number of unsupported certificate extensions requested.
1302 : *
1303 : * @ingroup hx509_request
1304 : */
1305 : HX509_LIB_FUNCTION size_t HX509_LIB_CALL
1306 0 : hx509_request_count_unsupported(hx509_request req)
1307 : {
1308 0 : return req->nunsupported_crit;
1309 : }
1310 :
1311 : /**
1312 : * Return the count of as-yet unauthorized certificate extensions requested.
1313 : *
1314 : * @param req The hx509_request object.
1315 : * @return The number of as-yet unauthorized certificate extensions requested.
1316 : *
1317 : * @ingroup hx509_request
1318 : */
1319 : HX509_LIB_FUNCTION size_t HX509_LIB_CALL
1320 0 : hx509_request_count_unauthorized(hx509_request req)
1321 : {
1322 0 : size_t nrequested = req->eku.len + req->san.len +
1323 0 : (KeyUsage2int(req->ku) ? 1 : 0) + !!req->bc.cA +
1324 0 : req->nunsupported_crit;
1325 :
1326 0 : return nrequested - (req->nauthorized + req->ku_are_authorized + req->ca_is_authorized);
1327 : }
1328 :
1329 : static hx509_san_type
1330 0 : san_map_type(GeneralName *san)
1331 : {
1332 0 : static const struct {
1333 : const heim_oid *oid;
1334 : hx509_san_type type;
1335 : } map[] = {
1336 : { &asn1_oid_id_pkix_on_dnsSRV, HX509_SAN_TYPE_DNSSRV },
1337 : { &asn1_oid_id_pkinit_san, HX509_SAN_TYPE_PKINIT },
1338 : { &asn1_oid_id_pkix_on_xmppAddr, HX509_SAN_TYPE_XMPP },
1339 : { &asn1_oid_id_pkinit_ms_san, HX509_SAN_TYPE_MS_UPN },
1340 : { &asn1_oid_id_pkix_on_permanentIdentifier, HX509_SAN_TYPE_PERMANENT_ID },
1341 : { &asn1_oid_id_on_hardwareModuleName, HX509_SAN_TYPE_HW_MODULE },
1342 : };
1343 0 : size_t i;
1344 :
1345 0 : switch (san->element) {
1346 0 : case choice_GeneralName_rfc822Name: return HX509_SAN_TYPE_EMAIL;
1347 0 : case choice_GeneralName_dNSName: return HX509_SAN_TYPE_DNSNAME;
1348 0 : case choice_GeneralName_directoryName: return HX509_SAN_TYPE_DN;
1349 0 : case choice_GeneralName_registeredID: return HX509_SAN_TYPE_REGISTERED_ID;
1350 0 : case choice_GeneralName_otherName: {
1351 0 : for (i = 0; i < sizeof(map)/sizeof(map[0]); i++)
1352 0 : if (der_heim_oid_cmp(&san->u.otherName.type_id, map[i].oid) == 0)
1353 0 : return map[i].type;
1354 : }
1355 : HEIM_FALLTHROUGH;
1356 0 : default: return HX509_SAN_TYPE_UNSUPPORTED;
1357 : }
1358 : }
1359 :
1360 : /**
1361 : * Return the count of as-yet unauthorized certificate extensions requested.
1362 : *
1363 : * @param req The hx509_request object.
1364 : *
1365 : * @ingroup hx509_request
1366 : */
1367 : HX509_LIB_FUNCTION size_t HX509_LIB_CALL
1368 0 : hx509_request_get_san(hx509_request req,
1369 : size_t idx,
1370 : hx509_san_type *type,
1371 : char **out)
1372 : {
1373 0 : struct rk_strpool *pool = NULL;
1374 0 : GeneralName *san;
1375 :
1376 0 : *out = NULL;
1377 0 : if (idx >= req->san.len)
1378 0 : return HX509_NO_ITEM;
1379 :
1380 0 : san = &req->san.val[idx];
1381 0 : switch ((*type = san_map_type(san))) {
1382 0 : case HX509_SAN_TYPE_UNSUPPORTED: return 0;
1383 0 : case HX509_SAN_TYPE_EMAIL:
1384 0 : *out = strndup(san->u.rfc822Name.data,
1385 : san->u.rfc822Name.length);
1386 0 : break;
1387 0 : case HX509_SAN_TYPE_DNSNAME:
1388 0 : *out = strndup(san->u.dNSName.data,
1389 : san->u.dNSName.length);
1390 0 : break;
1391 0 : case HX509_SAN_TYPE_DNSSRV: {
1392 0 : SRVName name;
1393 0 : size_t size;
1394 0 : int ret;
1395 :
1396 0 : ret = decode_SRVName(san->u.otherName.value.data,
1397 : san->u.otherName.value.length, &name, &size);
1398 0 : if (ret)
1399 0 : return ret;
1400 0 : *out = strndup(name.data, name.length);
1401 0 : break;
1402 : }
1403 0 : case HX509_SAN_TYPE_PERMANENT_ID: {
1404 0 : PermanentIdentifier pi;
1405 0 : size_t size;
1406 0 : char *s = NULL;
1407 0 : int ret;
1408 :
1409 0 : ret = decode_PermanentIdentifier(san->u.otherName.value.data,
1410 : san->u.otherName.value.length,
1411 : &pi, &size);
1412 0 : if (ret == 0 && pi.assigner) {
1413 0 : ret = der_print_heim_oid(pi.assigner, '.', &s);
1414 0 : if (ret == 0 &&
1415 0 : (pool = rk_strpoolprintf(NULL, "%s", s)) == NULL)
1416 0 : ret = ENOMEM;
1417 0 : } else if (ret == 0) {
1418 0 : pool = rk_strpoolprintf(NULL, "-");
1419 : }
1420 0 : if (ret == 0 &&
1421 0 : (pool = rk_strpoolprintf(pool, "%s%s",
1422 0 : *pi.identifierValue ? " " : "",
1423 0 : *pi.identifierValue ? *pi.identifierValue : "")) == NULL)
1424 0 : ret = ENOMEM;
1425 0 : if (ret == 0 && (*out = rk_strpoolcollect(pool)) == NULL)
1426 0 : ret = ENOMEM;
1427 0 : free_PermanentIdentifier(&pi);
1428 0 : free(s);
1429 0 : return ret;
1430 : }
1431 0 : case HX509_SAN_TYPE_HW_MODULE: {
1432 0 : HardwareModuleName hn;
1433 0 : size_t size;
1434 0 : char *s = NULL;
1435 0 : int ret;
1436 :
1437 0 : ret = decode_HardwareModuleName(san->u.otherName.value.data,
1438 : san->u.otherName.value.length,
1439 : &hn, &size);
1440 0 : if (ret == 0 && hn.hwSerialNum.length > 256)
1441 0 : hn.hwSerialNum.length = 256;
1442 0 : if (ret == 0)
1443 0 : ret = der_print_heim_oid(&hn.hwType, '.', &s);
1444 0 : if (ret == 0)
1445 0 : pool = rk_strpoolprintf(NULL, "%s", s);
1446 0 : if (ret == 0 && pool)
1447 0 : pool = rk_strpoolprintf(pool, " %.*s",
1448 0 : (int)hn.hwSerialNum.length,
1449 0 : (char *)hn.hwSerialNum.data);
1450 0 : if (ret == 0 &&
1451 0 : (pool == NULL || (*out = rk_strpoolcollect(pool)) == NULL))
1452 0 : ret = ENOMEM;
1453 0 : free_HardwareModuleName(&hn);
1454 0 : return ret;
1455 : }
1456 0 : case HX509_SAN_TYPE_DN: {
1457 0 : Name name;
1458 :
1459 0 : if (san->u.directoryName.element == choice_Name_rdnSequence) {
1460 0 : name.element = choice_Name_rdnSequence;
1461 0 : name.u.rdnSequence = san->u.directoryName.u.rdnSequence;
1462 0 : return _hx509_Name_to_string(&name, out);
1463 : }
1464 0 : *type = HX509_SAN_TYPE_UNSUPPORTED;
1465 0 : return 0;
1466 : }
1467 0 : case HX509_SAN_TYPE_REGISTERED_ID:
1468 0 : return der_print_heim_oid(&san->u.registeredID, '.', out);
1469 0 : case HX509_SAN_TYPE_XMPP:
1470 0 : HEIM_FALLTHROUGH;
1471 : case HX509_SAN_TYPE_MS_UPN: {
1472 0 : int ret;
1473 :
1474 0 : ret = _hx509_unparse_utf8_string_name(req->context, &pool,
1475 0 : &san->u.otherName.value);
1476 0 : if ((*out = rk_strpoolcollect(pool)) == NULL)
1477 0 : return hx509_enomem(req->context);
1478 0 : return ret;
1479 : }
1480 0 : case HX509_SAN_TYPE_PKINIT: {
1481 0 : int ret;
1482 :
1483 0 : ret = _hx509_unparse_KRB5PrincipalName(req->context, &pool,
1484 0 : &san->u.otherName.value);
1485 0 : if ((*out = rk_strpoolcollect(pool)) == NULL)
1486 0 : return hx509_enomem(req->context);
1487 0 : return ret;
1488 : }
1489 0 : default:
1490 0 : *type = HX509_SAN_TYPE_UNSUPPORTED;
1491 0 : return 0;
1492 : }
1493 0 : if (*out == NULL)
1494 0 : return ENOMEM;
1495 0 : return 0;
1496 : }
1497 :
1498 : /**
1499 : * Indicate if a CSR requested a CA certificate.
1500 : *
1501 : * @param context An hx509 context.
1502 : * @param req The hx509_request object.
1503 : *
1504 : * @return 1 if the CSR requested CA certificate, 0 otherwise.
1505 : *
1506 : * @ingroup hx509_request
1507 : */
1508 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1509 0 : hx509_request_get_cA(hx509_context context,
1510 : hx509_request req)
1511 : {
1512 0 : return req->bc.cA;
1513 : }
1514 :
1515 : /**
1516 : * Return the CSR's requested BasicConstraints pathLenConstraint.
1517 : *
1518 : * @param context An hx509 context.
1519 : * @param req The hx509_request object.
1520 : *
1521 : * @return -1 if no pathLenConstraint was requested (or the BasicConstraints
1522 : * does not request a CA certificate), or the actual requested
1523 : * pathLenConstraint.
1524 : *
1525 : * @ingroup hx509_request
1526 : */
1527 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1528 0 : hx509_request_get_cA_pathLenConstraint(hx509_context context,
1529 : hx509_request req)
1530 : {
1531 0 : if (req->bc.cA && req->bc.pathLenConstraint &&
1532 0 : *req->bc.pathLenConstraint < INT_MAX)
1533 0 : return *req->bc.pathLenConstraint;
1534 0 : return -1;
1535 : }
1536 :
1537 : /**
1538 : * Display a CSR.
1539 : *
1540 : * @param context An hx509 context.
1541 : * @param req The hx509_request object.
1542 : * @param f A FILE * to print the CSR to.
1543 : *
1544 : * @return An hx509 error code, see hx509_get_error_string().
1545 : *
1546 : * @ingroup hx509_request
1547 : */
1548 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1549 0 : hx509_request_print(hx509_context context, hx509_request req, FILE *f)
1550 : {
1551 0 : uint64_t ku_num;
1552 0 : size_t i;
1553 0 : char *s = NULL;
1554 0 : int ret = 0;
1555 :
1556 : /*
1557 : * It's really unformatunate that we can't reuse more of the
1558 : * lib/hx509/print.c infrastructure here, as it's too focused on
1559 : * Certificates.
1560 : *
1561 : * For that matter, it's really annoying that CSRs don't more resemble
1562 : * Certificates. Indeed, an ideal CSR would look like this:
1563 : *
1564 : * CSRInfo ::= {
1565 : * desiredTbsCertificate TBSCertificate,
1566 : * attributes [1] SEQUENCE OF Attribute OPTIONAL,
1567 : * }
1568 : * CSR :: = {
1569 : * csrInfo CSRInfo,
1570 : * sigAlg AlgorithmIdentifier,
1571 : * signature BIT STRING
1572 : * }
1573 : *
1574 : * with everything related to the desired certificate in
1575 : * desiredTbsCertificate and anything not related to the CSR's contents in
1576 : * the 'attributes' field.
1577 : *
1578 : * That wouldn't allow one to have optional desired TBSCertificate
1579 : * features, but hey. One could express "gimme all or gimme nothing" as an
1580 : * attribute, or "gimme what you can", then check what one got.
1581 : */
1582 0 : fprintf(f, "PKCS#10 CertificationRequest:\n");
1583 :
1584 0 : if (req->include_BasicConstraints) {
1585 0 : fprintf(f, " cA: %s\n", req->bc.cA ? "yes" : "no");
1586 0 : if (req->bc.pathLenConstraint)
1587 0 : fprintf(f, " pathLenConstraint: %u\n", *req->bc.pathLenConstraint);
1588 : else
1589 0 : fprintf(f, " pathLenConstraint: unspecified\n");
1590 : }
1591 0 : if (req->name) {
1592 0 : char *subject;
1593 0 : ret = hx509_name_to_string(req->name, &subject);
1594 0 : if (ret) {
1595 0 : hx509_set_error_string(context, 0, ret, "Failed to print name");
1596 0 : return ret;
1597 : }
1598 0 : fprintf(f, " name: %s\n", subject);
1599 0 : free(subject);
1600 : }
1601 : /* XXX Use hx509_request_get_ku() accessor */
1602 0 : if ((ku_num = KeyUsage2int(req->ku))) {
1603 0 : const struct units *u;
1604 0 : const char *first = " ";
1605 :
1606 0 : fprintf(f, " key usage:");
1607 0 : for (u = asn1_KeyUsage_units(); u->name; ++u) {
1608 0 : if ((ku_num & u->mult)) {
1609 0 : fprintf(f, "%s%s", first, u->name);
1610 0 : first = ", ";
1611 0 : ku_num &= ~u->mult;
1612 : }
1613 : }
1614 0 : if (ku_num)
1615 0 : fprintf(f, "%s<unknown-KeyUsage-value(s)>", first);
1616 0 : fprintf(f, "\n");
1617 : }
1618 0 : if (req->eku.len) {
1619 0 : const char *first = " ";
1620 :
1621 0 : fprintf(f, " eku:");
1622 0 : for (i = 0; ret == 0; i++) {
1623 0 : free(s); s = NULL;
1624 0 : ret = hx509_request_get_eku(req, i, &s);
1625 0 : if (ret)
1626 0 : break;
1627 0 : fprintf(f, "%s{%s}", first, s);
1628 0 : first = ", ";
1629 : }
1630 0 : fprintf(f, "\n");
1631 : }
1632 0 : free(s); s = NULL;
1633 0 : if (ret == HX509_NO_ITEM)
1634 0 : ret = 0;
1635 0 : for (i = 0; ret == 0; i++) {
1636 0 : hx509_san_type san_type;
1637 :
1638 0 : free(s); s = NULL;
1639 0 : ret = hx509_request_get_san(req, i, &san_type, &s);
1640 0 : if (ret)
1641 0 : break;
1642 0 : switch (san_type) {
1643 0 : case HX509_SAN_TYPE_EMAIL:
1644 0 : fprintf(f, " san: rfc822Name: %s\n", s);
1645 0 : break;
1646 0 : case HX509_SAN_TYPE_DNSNAME:
1647 0 : fprintf(f, " san: dNSName: %s\n", s);
1648 0 : break;
1649 0 : case HX509_SAN_TYPE_DN:
1650 0 : fprintf(f, " san: dn: %s\n", s);
1651 0 : break;
1652 0 : case HX509_SAN_TYPE_REGISTERED_ID:
1653 0 : fprintf(f, " san: registeredID: %s\n", s);
1654 0 : break;
1655 0 : case HX509_SAN_TYPE_XMPP:
1656 0 : fprintf(f, " san: xmpp: %s\n", s);
1657 0 : break;
1658 0 : case HX509_SAN_TYPE_PKINIT:
1659 0 : fprintf(f, " san: pkinit: %s\n", s);
1660 0 : break;
1661 0 : case HX509_SAN_TYPE_MS_UPN:
1662 0 : fprintf(f, " san: ms-upn: %s\n", s);
1663 0 : break;
1664 0 : default:
1665 0 : fprintf(f, " san: <SAN type not supported>\n");
1666 0 : break;
1667 : }
1668 : }
1669 0 : if (req->nunsupported_crit) {
1670 0 : fprintf(f, " unsupported_critical_extensions_count: %u\n",
1671 0 : (unsigned)req->nunsupported_crit);
1672 : }
1673 0 : if (req->nunsupported_opt) {
1674 0 : fprintf(f, " unsupported_optional_extensions_count: %u\n",
1675 0 : (unsigned)req->nunsupported_opt);
1676 : }
1677 0 : free(s); s = NULL;
1678 0 : if (ret == HX509_NO_ITEM)
1679 0 : ret = 0;
1680 0 : return ret;
1681 : }
|