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