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 0 : void *val;
249 0 : 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 0 : GeneralName gn;
294 0 : size_t size;
295 0 : 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 0 : 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 0 : GeneralName gn;
399 0 : SRVName n;
400 0 : size_t size;
401 0 : 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 0 : 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 0 : GeneralName name;
466 0 : 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 0 : KRB5PrincipalName kn;
495 0 : GeneralName gn;
496 0 : 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 0 : 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 0 : 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 0 : 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 0 : 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 0 : Extensions exts;
603 0 : size_t size;
604 0 : 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 0 : CertificationRequest r;
637 0 : Extensions exts;
638 0 : heim_octet_string data;
639 0 : size_t size;
640 0 : 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 0 : heim_any extns;
671 :
672 0 : extns.data = NULL;
673 0 : extns.length = 0;
674 0 : r.certificationRequestInfo.attributes =
675 0 : calloc(1, sizeof(r.certificationRequestInfo.attributes[0]));
676 0 : if (r.certificationRequestInfo.attributes == NULL)
677 0 : ret = ENOMEM;
678 0 : if (ret == 0) {
679 0 : r.certificationRequestInfo.attributes[0].len = 1;
680 0 : r.certificationRequestInfo.attributes[0].val =
681 0 : calloc(1, sizeof(r.certificationRequestInfo.attributes[0].val[0]));
682 0 : if (r.certificationRequestInfo.attributes[0].val == NULL)
683 0 : ret = ENOMEM;
684 0 : if (ret == 0)
685 0 : a = r.certificationRequestInfo.attributes[0].val;
686 : }
687 0 : if (ret == 0)
688 0 : ASN1_MALLOC_ENCODE(Extensions, extns.data, extns.length,
689 : &exts, &size, ret);
690 0 : if (ret == 0 && a)
691 0 : ret = der_copy_oid(&asn1_oid_id_pkcs9_extReq, &a->type);
692 0 : if (ret == 0)
693 0 : ret = add_AttributeValues(&a->value, &extns);
694 0 : free_heim_any(&extns);
695 : }
696 :
697 : /* Encode CSR body for signing */
698 0 : if (ret == 0)
699 0 : ASN1_MALLOC_ENCODE(CertificationRequestInfo, data.data, data.length,
700 : &r.certificationRequestInfo, &size, ret);
701 0 : if (ret == 0 && data.length != size)
702 0 : abort();
703 :
704 : /* Self-sign CSR body */
705 0 : if (ret == 0) {
706 0 : ret = _hx509_create_signature_bitstring(context, signer,
707 : _hx509_crypto_default_sig_alg,
708 : &data,
709 : &r.signatureAlgorithm,
710 : &r.signature);
711 : }
712 0 : free(data.data);
713 :
714 : /* Encode CSR */
715 0 : if (ret == 0)
716 0 : ASN1_MALLOC_ENCODE(CertificationRequest, request->data, request->length,
717 : &r, &size, ret);
718 0 : if (ret == 0 && request->length != size)
719 0 : abort();
720 :
721 0 : free_CertificationRequest(&r);
722 0 : free_Extensions(&exts);
723 0 : return ret;
724 : }
725 :
726 : /**
727 : * Parse an encoded CSR and verify its self-signature.
728 : *
729 : * @param context An hx509 context.
730 : * @param der The DER-encoded CSR.
731 : * @param req Where to put request object.
732 : *
733 : * @return An hx509 error code, see hx509_get_error_string().
734 : *
735 : * @ingroup hx509_request
736 : */
737 : HX509_LIB_FUNCTION int HX509_LIB_CALL
738 0 : hx509_request_parse_der(hx509_context context,
739 : heim_octet_string *der,
740 : hx509_request *req)
741 : {
742 0 : CertificationRequestInfo *rinfo = NULL;
743 0 : CertificationRequest r;
744 0 : hx509_cert signer = NULL;
745 0 : Extensions exts;
746 0 : size_t i, size;
747 0 : int ret;
748 :
749 0 : memset(&exts, 0, sizeof(exts));
750 :
751 : /* Initial setup and decoding of CSR */
752 0 : ret = hx509_request_init(context, req);
753 0 : if (ret)
754 0 : return ret;
755 0 : ret = decode_CertificationRequest(der->data, der->length, &r, &size);
756 0 : if (ret) {
757 0 : hx509_set_error_string(context, 0, ret, "Failed to decode CSR");
758 0 : free(*req);
759 0 : *req = NULL;
760 0 : return ret;
761 : }
762 0 : rinfo = &r.certificationRequestInfo;
763 :
764 : /*
765 : * Setup a 'signer' for verifying the self-signature for proof of
766 : * possession.
767 : *
768 : * Sadly we need a "certificate" here because _hx509_verify_signature_*()
769 : * functions want one as a signer even though all the verification
770 : * functions that use the signer argument only ever use the spki of the
771 : * signer certificate.
772 : *
773 : * FIXME Change struct signature_alg's verify_signature's prototype to use
774 : * an spki instead of an hx509_cert as the signer! The we won't have
775 : * to do this.
776 : */
777 0 : if (ret == 0) {
778 0 : Certificate c;
779 0 : memset(&c, 0, sizeof(c));
780 0 : c.tbsCertificate.subjectPublicKeyInfo = rinfo->subjectPKInfo;
781 0 : if ((signer = hx509_cert_init(context, &c, NULL)) == NULL)
782 0 : ret = ENOMEM;
783 : }
784 :
785 : /* Verify the signature */
786 0 : if (ret == 0)
787 0 : ret = _hx509_verify_signature_bitstring(context, signer,
788 : &r.signatureAlgorithm,
789 0 : &rinfo->_save,
790 : &r.signature);
791 0 : if (ret)
792 0 : hx509_set_error_string(context, 0, ret,
793 : "CSR signature verification failed");
794 0 : hx509_cert_free(signer);
795 :
796 : /* Populate the hx509_request */
797 0 : if (ret == 0)
798 0 : ret = hx509_request_set_SubjectPublicKeyInfo(context, *req,
799 0 : &rinfo->subjectPKInfo);
800 0 : if (ret == 0)
801 0 : ret = _hx509_name_from_Name(&rinfo->subject, &(*req)->name);
802 :
803 : /* Extract KUs, EKUs, and SANs from the CSR's attributes */
804 0 : if (ret || !rinfo->attributes || !rinfo->attributes[0].len)
805 0 : goto out;
806 :
807 0 : for (i = 0; ret == 0 && i < rinfo->attributes[0].len; i++) {
808 0 : Attribute *a = &rinfo->attributes[0].val[i];
809 0 : heim_any *av = NULL;
810 :
811 : /* We only support Extensions request attributes */
812 0 : if (der_heim_oid_cmp(&a->type, &asn1_oid_id_pkcs9_extReq) != 0) {
813 0 : char *oidstr = NULL;
814 :
815 : /*
816 : * We need an HX509_TRACE facility for this sort of warning.
817 : *
818 : * We'd put the warning in the context and then allow the caller to
819 : * extract and reset the warning.
820 : *
821 : * FIXME
822 : */
823 0 : der_print_heim_oid(&a->type, '.', &oidstr);
824 0 : warnx("Unknown or unsupported CSR attribute %s",
825 0 : oidstr ? oidstr : "<error decoding OID>");
826 0 : free(oidstr);
827 0 : continue;
828 : }
829 0 : if (!a->value.val)
830 0 : continue;
831 :
832 0 : av = a->value.val;
833 0 : ret = decode_Extensions(av->data, av->length, &exts, NULL);
834 0 : if (ret) {
835 0 : hx509_set_error_string(context, 0, ret,
836 : "CSR signature verification failed "
837 : "due to invalid extReq attribute");
838 0 : goto out;
839 : }
840 : }
841 0 : for (i = 0; ret == 0 && i < exts.len; i++) {
842 0 : const char *what = "";
843 0 : Extension *e = &exts.val[i];
844 :
845 0 : if (der_heim_oid_cmp(&e->extnID,
846 : &asn1_oid_id_x509_ce_keyUsage) == 0) {
847 0 : ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length,
848 0 : &(*req)->ku, NULL);
849 0 : what = "keyUsage";
850 : /*
851 : * Count all KUs as one requested extension to be authorized,
852 : * though the caller will have to check the KU values individually.
853 : */
854 0 : if (KeyUsage2int((*req)->ku) & ~KeyUsage2int(int2KeyUsage(~0)))
855 0 : (*req)->nunsupported++;
856 0 : } else if (der_heim_oid_cmp(&e->extnID,
857 : &asn1_oid_id_x509_ce_extKeyUsage) == 0) {
858 0 : ret = decode_ExtKeyUsage(e->extnValue.data, e->extnValue.length,
859 0 : &(*req)->eku, NULL);
860 0 : what = "extKeyUsage";
861 :
862 : /*
863 : * Count each EKU as a separate requested extension to be
864 : * authorized.
865 : */
866 0 : } else if (der_heim_oid_cmp(&e->extnID,
867 : &asn1_oid_id_x509_ce_subjectAltName) == 0) {
868 0 : ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length,
869 0 : &(*req)->san, NULL);
870 0 : what = "subjectAlternativeName";
871 :
872 : /*
873 : * Count each SAN as a separate requested extension to be
874 : * authorized.
875 : */
876 : } else {
877 0 : char *oidstr = NULL;
878 :
879 0 : (*req)->nunsupported++;
880 :
881 : /*
882 : * We need an HX509_TRACE facility for this sort of warning.
883 : *
884 : * We'd put the warning in the context and then allow the caller to
885 : * extract and reset the warning.
886 : *
887 : * FIXME
888 : */
889 0 : der_print_heim_oid(&e->extnID, '.', &oidstr);
890 0 : warnx("Unknown or unsupported CSR extension request %s",
891 0 : oidstr ? oidstr : "<error decoding OID>");
892 0 : free(oidstr);
893 : }
894 0 : if (ret) {
895 0 : hx509_set_error_string(context, 0, ret,
896 : "CSR signature verification failed "
897 : "due to invalid %s extension", what);
898 0 : break;
899 : }
900 : }
901 :
902 0 : out:
903 0 : free_CertificationRequest(&r);
904 0 : free_Extensions(&exts);
905 0 : if (ret)
906 0 : hx509_request_free(req);
907 0 : return ret;
908 : }
909 :
910 : /**
911 : * Parse an encoded CSR and verify its self-signature.
912 : *
913 : * @param context An hx509 context.
914 : * @param csr The name of a store containing the CSR ("PKCS10:/path/to/file")
915 : * @param req Where to put request object.
916 : *
917 : * @return An hx509 error code, see hx509_get_error_string().
918 : *
919 : * @ingroup hx509_request
920 : */
921 : HX509_LIB_FUNCTION int HX509_LIB_CALL
922 0 : hx509_request_parse(hx509_context context,
923 : const char *csr,
924 : hx509_request *req)
925 : {
926 0 : heim_octet_string d;
927 0 : int ret;
928 :
929 : /* XXX Add support for PEM */
930 0 : if (strncmp(csr, "PKCS10:", 7) != 0) {
931 0 : hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
932 : "CSR location does not start with \"PKCS10:\": %s",
933 : csr);
934 0 : return HX509_UNSUPPORTED_OPERATION;
935 : }
936 :
937 0 : ret = rk_undumpdata(csr + 7, &d.data, &d.length);
938 0 : if (ret) {
939 0 : hx509_set_error_string(context, 0, ret, "Could not read %s", csr);
940 0 : return ret;
941 : }
942 :
943 0 : ret = hx509_request_parse_der(context, &d, req);
944 0 : free(d.data);
945 0 : if (ret)
946 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
947 : " (while parsing CSR from %s)", csr);
948 0 : return ret;
949 : }
950 :
951 : /**
952 : * Get some EKU from a CSR. Usable as an iterator.
953 : *
954 : * @param context An hx509 context.
955 : * @param req The hx509_request object.
956 : * @param idx The index of the EKU (0 for the first) to return
957 : * @param out A pointer to a char * variable where the OID will be placed
958 : * (caller must free with free())
959 : *
960 : * @return Zero on success, HX509_NO_ITEM if no such item exists (denoting
961 : * iteration end), or an error.
962 : *
963 : * @ingroup hx509_request
964 : */
965 : HX509_LIB_FUNCTION int HX509_LIB_CALL
966 0 : hx509_request_get_eku(hx509_request req,
967 : size_t idx,
968 : char **out)
969 : {
970 0 : *out = NULL;
971 0 : if (idx >= req->eku.len)
972 0 : return HX509_NO_ITEM;
973 0 : return der_print_heim_oid(&req->eku.val[idx], '.', out);
974 : }
975 :
976 : static int
977 0 : abitstring_check(abitstring a, size_t n, int idx)
978 : {
979 0 : size_t bytes;
980 :
981 0 : if (idx >= n)
982 0 : return HX509_NO_ITEM;
983 :
984 0 : bytes = (idx + 1) / CHAR_BIT + (((idx + 1) % CHAR_BIT) ? 1 : 0);
985 0 : if (a->feat_bytes < bytes)
986 0 : return 0;
987 :
988 0 : return !!(a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT)));
989 : }
990 :
991 : /*
992 : * Sets and returns 0 if not already set, -1 if already set. Positive return
993 : * values are system errors.
994 : */
995 : static int
996 0 : abitstring_set(abitstring a, size_t n, int idx)
997 : {
998 0 : size_t bytes;
999 :
1000 0 : if (idx >= n)
1001 0 : return HX509_NO_ITEM;
1002 :
1003 0 : bytes = n / CHAR_BIT + ((n % CHAR_BIT) ? 1 : 0);
1004 0 : if (a->feat_bytes < bytes) {
1005 0 : unsigned char *tmp;
1006 :
1007 0 : if ((tmp = realloc(a->feats, bytes)) == NULL)
1008 0 : return ENOMEM;
1009 0 : memset(tmp + a->feat_bytes, 0, bytes - a->feat_bytes);
1010 0 : a->feats = tmp;
1011 0 : a->feat_bytes = bytes;
1012 : }
1013 :
1014 0 : if (!(a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT)))) {
1015 0 : a->feats[idx / CHAR_BIT] |= 1UL<<(idx % CHAR_BIT);
1016 0 : return 0;
1017 : }
1018 0 : return -1;
1019 : }
1020 :
1021 : /*
1022 : * Resets and returns 0 if not already reset, -1 if already reset. Positive
1023 : * return values are system errors.
1024 : */
1025 : static int
1026 0 : abitstring_reset(abitstring a, size_t n, int idx)
1027 : {
1028 0 : size_t bytes;
1029 :
1030 0 : if (idx >= n)
1031 0 : return HX509_NO_ITEM;
1032 :
1033 0 : bytes = (idx + 1) / CHAR_BIT + (((idx + 1) % CHAR_BIT) ? 1 : 0);
1034 0 : if (a->feat_bytes >= bytes &&
1035 0 : (a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT)))) {
1036 0 : a->feats[idx / CHAR_BIT] &= ~(1UL<<(idx % CHAR_BIT));
1037 0 : return 0;
1038 : }
1039 0 : return -1;
1040 : }
1041 :
1042 : static int
1043 0 : authorize_feat(hx509_request req, abitstring a, size_t n, int idx)
1044 : {
1045 0 : int ret;
1046 :
1047 0 : ret = abitstring_set(a, n, idx);
1048 0 : switch (ret) {
1049 0 : case 0:
1050 0 : req->nauthorized++;
1051 : HEIM_FALLTHROUGH;
1052 0 : case -1:
1053 0 : return 0;
1054 0 : default:
1055 0 : return ret;
1056 : }
1057 : }
1058 :
1059 : static int
1060 0 : reject_feat(hx509_request req, abitstring a, size_t n, int idx)
1061 : {
1062 0 : int ret;
1063 :
1064 0 : ret = abitstring_reset(a, n, idx);
1065 0 : switch (ret) {
1066 0 : case 0:
1067 0 : req->nauthorized--;
1068 : HEIM_FALLTHROUGH;
1069 0 : case -1:
1070 0 : return 0;
1071 0 : default:
1072 0 : return ret;
1073 : }
1074 : }
1075 :
1076 : /**
1077 : * Filter the requested KeyUsage and mark it authorized.
1078 : *
1079 : * @param req The hx509_request object.
1080 : * @param ku Permitted KeyUsage
1081 : *
1082 : * @ingroup hx509_request
1083 : */
1084 : HX509_LIB_FUNCTION void HX509_LIB_CALL
1085 0 : hx509_request_authorize_ku(hx509_request req, KeyUsage ku)
1086 : {
1087 0 : (void) hx509_request_set_ku(NULL, req, ku);
1088 0 : req->ku = int2KeyUsage(KeyUsage2int(req->ku) & KeyUsage2int(ku));
1089 0 : if (KeyUsage2int(ku))
1090 0 : req->ku_are_authorized = 1;
1091 0 : }
1092 :
1093 : /**
1094 : * Mark a requested EKU as authorized.
1095 : *
1096 : * @param req The hx509_request object.
1097 : * @param idx The index of an EKU that can be fetched with
1098 : * hx509_request_get_eku()
1099 : *
1100 : * @return Zero on success, an error otherwise.
1101 : *
1102 : * @ingroup hx509_request
1103 : */
1104 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1105 0 : hx509_request_authorize_eku(hx509_request req, size_t idx)
1106 : {
1107 0 : return authorize_feat(req, &req->authorized_EKUs, req->eku.len, idx);
1108 : }
1109 :
1110 : /**
1111 : * Mark a requested EKU as not authorized.
1112 : *
1113 : * @param req The hx509_request object.
1114 : * @param idx The index of an EKU that can be fetched with
1115 : * hx509_request_get_eku()
1116 : *
1117 : * @return Zero on success, an error otherwise.
1118 : *
1119 : * @ingroup hx509_request
1120 : */
1121 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1122 0 : hx509_request_reject_eku(hx509_request req, size_t idx)
1123 : {
1124 0 : return reject_feat(req, &req->authorized_EKUs, req->eku.len, idx);
1125 : }
1126 :
1127 : /**
1128 : * Check if an EKU has been marked authorized.
1129 : *
1130 : * @param req The hx509_request object.
1131 : * @param idx The index of an EKU that can be fetched with
1132 : * hx509_request_get_eku()
1133 : *
1134 : * @return Non-zero if authorized, zero if not.
1135 : *
1136 : * @ingroup hx509_request
1137 : */
1138 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1139 0 : hx509_request_eku_authorized_p(hx509_request req, size_t idx)
1140 : {
1141 0 : return abitstring_check(&req->authorized_EKUs, req->eku.len, idx);
1142 : }
1143 :
1144 : /**
1145 : * Mark a requested SAN as authorized.
1146 : *
1147 : * @param req The hx509_request object.
1148 : * @param idx The cursor as modified by a SAN iterator.
1149 : *
1150 : * @return Zero on success, an error otherwise.
1151 : *
1152 : * @ingroup hx509_request
1153 : */
1154 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1155 0 : hx509_request_authorize_san(hx509_request req, size_t idx)
1156 : {
1157 0 : return authorize_feat(req, &req->authorized_SANs, req->san.len, idx);
1158 : }
1159 :
1160 : /**
1161 : * Mark a requested SAN as not authorized.
1162 : *
1163 : * @param req The hx509_request object.
1164 : * @param idx The cursor as modified by a SAN iterator.
1165 : *
1166 : * @return Zero on success, an error otherwise.
1167 : *
1168 : * @ingroup hx509_request
1169 : */
1170 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1171 0 : hx509_request_reject_san(hx509_request req, size_t idx)
1172 : {
1173 0 : return reject_feat(req, &req->authorized_SANs, req->san.len, idx);
1174 : }
1175 :
1176 : /**
1177 : * Check if a SAN has been marked authorized.
1178 : *
1179 : * @param req The hx509_request object.
1180 : * @param idx The index of a SAN that can be fetched with
1181 : * hx509_request_get_san()
1182 : *
1183 : * @return Non-zero if authorized, zero if not.
1184 : *
1185 : * @ingroup hx509_request
1186 : */
1187 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1188 0 : hx509_request_san_authorized_p(hx509_request req, size_t idx)
1189 : {
1190 0 : return abitstring_check(&req->authorized_SANs, req->san.len, idx);
1191 : }
1192 :
1193 : /**
1194 : * Return the count of unsupported requested certificate extensions.
1195 : *
1196 : * @param req The hx509_request object.
1197 : * @return The number of unsupported certificate extensions requested.
1198 : *
1199 : * @ingroup hx509_request
1200 : */
1201 : HX509_LIB_FUNCTION size_t HX509_LIB_CALL
1202 0 : hx509_request_count_unsupported(hx509_request req)
1203 : {
1204 0 : return req->nunsupported;
1205 : }
1206 :
1207 : /**
1208 : * Return the count of as-yet unauthorized certificate extensions requested.
1209 : *
1210 : * @param req The hx509_request object.
1211 : * @return The number of as-yet unauthorized certificate extensions requested.
1212 : *
1213 : * @ingroup hx509_request
1214 : */
1215 : HX509_LIB_FUNCTION size_t HX509_LIB_CALL
1216 0 : hx509_request_count_unauthorized(hx509_request req)
1217 : {
1218 0 : size_t nrequested = req->eku.len + req->san.len +
1219 0 : (KeyUsage2int(req->ku) ? 1 : 0) + req->nunsupported;
1220 :
1221 0 : return nrequested - (req->nauthorized + req->ku_are_authorized);
1222 : }
1223 :
1224 : static hx509_san_type
1225 0 : san_map_type(GeneralName *san)
1226 : {
1227 0 : static const struct {
1228 : const heim_oid *oid;
1229 : hx509_san_type type;
1230 : } map[] = {
1231 : { &asn1_oid_id_pkix_on_dnsSRV, HX509_SAN_TYPE_DNSSRV },
1232 : { &asn1_oid_id_pkinit_san, HX509_SAN_TYPE_PKINIT },
1233 : { &asn1_oid_id_pkix_on_xmppAddr, HX509_SAN_TYPE_XMPP },
1234 : { &asn1_oid_id_pkinit_ms_san, HX509_SAN_TYPE_MS_UPN },
1235 : { &asn1_oid_id_pkix_on_permanentIdentifier, HX509_SAN_TYPE_PERMANENT_ID },
1236 : { &asn1_oid_id_on_hardwareModuleName, HX509_SAN_TYPE_HW_MODULE },
1237 : };
1238 0 : size_t i;
1239 :
1240 0 : switch (san->element) {
1241 0 : case choice_GeneralName_rfc822Name: return HX509_SAN_TYPE_EMAIL;
1242 0 : case choice_GeneralName_dNSName: return HX509_SAN_TYPE_DNSNAME;
1243 0 : case choice_GeneralName_directoryName: return HX509_SAN_TYPE_DN;
1244 0 : case choice_GeneralName_registeredID: return HX509_SAN_TYPE_REGISTERED_ID;
1245 0 : case choice_GeneralName_otherName: {
1246 0 : for (i = 0; i < sizeof(map)/sizeof(map[0]); i++)
1247 0 : if (der_heim_oid_cmp(&san->u.otherName.type_id, map[i].oid) == 0)
1248 0 : return map[i].type;
1249 : }
1250 : HEIM_FALLTHROUGH;
1251 0 : default: return HX509_SAN_TYPE_UNSUPPORTED;
1252 : }
1253 : }
1254 :
1255 : /**
1256 : * Return the count of as-yet unauthorized certificate extensions requested.
1257 : *
1258 : * @param req The hx509_request object.
1259 : *
1260 : * @ingroup hx509_request
1261 : */
1262 : HX509_LIB_FUNCTION size_t HX509_LIB_CALL
1263 0 : hx509_request_get_san(hx509_request req,
1264 : size_t idx,
1265 : hx509_san_type *type,
1266 : char **out)
1267 : {
1268 0 : struct rk_strpool *pool = NULL;
1269 0 : GeneralName *san;
1270 :
1271 0 : *out = NULL;
1272 0 : if (idx >= req->san.len)
1273 0 : return HX509_NO_ITEM;
1274 :
1275 0 : san = &req->san.val[idx];
1276 0 : switch ((*type = san_map_type(san))) {
1277 0 : case HX509_SAN_TYPE_UNSUPPORTED: return 0;
1278 0 : case HX509_SAN_TYPE_EMAIL:
1279 0 : *out = strndup(san->u.rfc822Name.data,
1280 : san->u.rfc822Name.length);
1281 0 : break;
1282 0 : case HX509_SAN_TYPE_DNSNAME:
1283 0 : *out = strndup(san->u.dNSName.data,
1284 : san->u.dNSName.length);
1285 0 : break;
1286 0 : case HX509_SAN_TYPE_DNSSRV: {
1287 0 : SRVName name;
1288 0 : size_t size;
1289 0 : int ret;
1290 :
1291 0 : ret = decode_SRVName(san->u.otherName.value.data,
1292 : san->u.otherName.value.length, &name, &size);
1293 0 : if (ret)
1294 0 : return ret;
1295 0 : *out = strndup(name.data, name.length);
1296 0 : break;
1297 : }
1298 0 : case HX509_SAN_TYPE_PERMANENT_ID: {
1299 0 : PermanentIdentifier pi;
1300 0 : size_t size;
1301 0 : char *s = NULL;
1302 0 : int ret;
1303 :
1304 0 : ret = decode_PermanentIdentifier(san->u.otherName.value.data,
1305 : san->u.otherName.value.length,
1306 : &pi, &size);
1307 0 : if (ret == 0 && pi.assigner) {
1308 0 : ret = der_print_heim_oid(pi.assigner, '.', &s);
1309 0 : if (ret == 0 &&
1310 0 : (pool = rk_strpoolprintf(NULL, "%s", s)) == NULL)
1311 0 : ret = ENOMEM;
1312 0 : } else if (ret == 0) {
1313 0 : pool = rk_strpoolprintf(NULL, "-");
1314 : }
1315 0 : if (ret == 0 &&
1316 0 : (pool = rk_strpoolprintf(pool, "%s%s",
1317 0 : *pi.identifierValue ? " " : "",
1318 0 : *pi.identifierValue ? *pi.identifierValue : "")) == NULL)
1319 0 : ret = ENOMEM;
1320 0 : if (ret == 0 && (*out = rk_strpoolcollect(pool)) == NULL)
1321 0 : ret = ENOMEM;
1322 0 : free_PermanentIdentifier(&pi);
1323 0 : free(s);
1324 0 : return ret;
1325 : }
1326 0 : case HX509_SAN_TYPE_HW_MODULE: {
1327 0 : HardwareModuleName hn;
1328 0 : size_t size;
1329 0 : char *s = NULL;
1330 0 : int ret;
1331 :
1332 0 : ret = decode_HardwareModuleName(san->u.otherName.value.data,
1333 : san->u.otherName.value.length,
1334 : &hn, &size);
1335 0 : if (ret == 0 && hn.hwSerialNum.length > 256)
1336 0 : hn.hwSerialNum.length = 256;
1337 0 : if (ret == 0)
1338 0 : ret = der_print_heim_oid(&hn.hwType, '.', &s);
1339 0 : if (ret == 0)
1340 0 : pool = rk_strpoolprintf(NULL, "%s", s);
1341 0 : if (ret == 0 && pool)
1342 0 : pool = rk_strpoolprintf(pool, " %.*s",
1343 0 : (int)hn.hwSerialNum.length,
1344 0 : (char *)hn.hwSerialNum.data);
1345 0 : if (ret == 0 &&
1346 0 : (pool == NULL || (*out = rk_strpoolcollect(pool)) == NULL))
1347 0 : ret = ENOMEM;
1348 0 : free_HardwareModuleName(&hn);
1349 0 : return ret;
1350 : }
1351 0 : case HX509_SAN_TYPE_DN: {
1352 0 : Name name;
1353 :
1354 0 : if (san->u.directoryName.element == choice_Name_rdnSequence) {
1355 0 : name.element = choice_Name_rdnSequence;
1356 0 : name.u.rdnSequence = san->u.directoryName.u.rdnSequence;
1357 0 : return _hx509_Name_to_string(&name, out);
1358 : }
1359 0 : *type = HX509_SAN_TYPE_UNSUPPORTED;
1360 0 : return 0;
1361 : }
1362 0 : case HX509_SAN_TYPE_REGISTERED_ID:
1363 0 : return der_print_heim_oid(&san->u.registeredID, '.', out);
1364 0 : case HX509_SAN_TYPE_XMPP:
1365 0 : HEIM_FALLTHROUGH;
1366 : case HX509_SAN_TYPE_MS_UPN: {
1367 0 : int ret;
1368 :
1369 0 : ret = _hx509_unparse_utf8_string_name(req->context, &pool,
1370 0 : &san->u.otherName.value);
1371 0 : if ((*out = rk_strpoolcollect(pool)) == NULL)
1372 0 : return hx509_enomem(req->context);
1373 0 : return ret;
1374 : }
1375 0 : case HX509_SAN_TYPE_PKINIT: {
1376 0 : int ret;
1377 :
1378 0 : ret = _hx509_unparse_KRB5PrincipalName(req->context, &pool,
1379 0 : &san->u.otherName.value);
1380 0 : if ((*out = rk_strpoolcollect(pool)) == NULL)
1381 0 : return hx509_enomem(req->context);
1382 0 : return ret;
1383 : }
1384 0 : default:
1385 0 : *type = HX509_SAN_TYPE_UNSUPPORTED;
1386 0 : return 0;
1387 : }
1388 0 : if (*out == NULL)
1389 0 : return ENOMEM;
1390 0 : return 0;
1391 : }
1392 :
1393 : /**
1394 : * Display a CSR.
1395 : *
1396 : * @param context An hx509 context.
1397 : * @param req The hx509_request object.
1398 : * @param f A FILE * to print the CSR to.
1399 : *
1400 : * @return An hx509 error code, see hx509_get_error_string().
1401 : *
1402 : * @ingroup hx509_request
1403 : */
1404 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1405 0 : hx509_request_print(hx509_context context, hx509_request req, FILE *f)
1406 : {
1407 0 : uint64_t ku_num;
1408 0 : size_t i;
1409 0 : char *s = NULL;
1410 0 : int ret = 0;
1411 :
1412 : /*
1413 : * It's really unformatunate that we can't reuse more of the
1414 : * lib/hx509/print.c infrastructure here, as it's too focused on
1415 : * Certificates.
1416 : *
1417 : * For that matter, it's really annoying that CSRs don't more resemble
1418 : * Certificates. Indeed, an ideal CSR would look like this:
1419 : *
1420 : * CSRInfo ::= {
1421 : * desiredTbsCertificate TBSCertificate,
1422 : * attributes [1] SEQUENCE OF Attribute OPTIONAL,
1423 : * }
1424 : * CSR :: = {
1425 : * csrInfo CSRInfo,
1426 : * sigAlg AlgorithmIdentifier,
1427 : * signature BIT STRING
1428 : * }
1429 : *
1430 : * with everything related to the desired certificate in
1431 : * desiredTbsCertificate and anything not related to the CSR's contents in
1432 : * the 'attributes' field.
1433 : *
1434 : * That wouldn't allow one to have optional desired TBSCertificate
1435 : * features, but hey. One could express "gimme all or gimme nothing" as an
1436 : * attribute, or "gimme what you can", then check what one got.
1437 : */
1438 0 : fprintf(f, "PKCS#10 CertificationRequest:\n");
1439 :
1440 0 : if (req->name) {
1441 0 : char *subject;
1442 0 : ret = hx509_name_to_string(req->name, &subject);
1443 0 : if (ret) {
1444 0 : hx509_set_error_string(context, 0, ret, "Failed to print name");
1445 0 : return ret;
1446 : }
1447 0 : fprintf(f, " name: %s\n", subject);
1448 0 : free(subject);
1449 : }
1450 : /* XXX Use hx509_request_get_ku() accessor */
1451 0 : if ((ku_num = KeyUsage2int(req->ku))) {
1452 0 : const struct units *u;
1453 0 : const char *first = " ";
1454 :
1455 0 : fprintf(f, " key usage:");
1456 0 : for (u = asn1_KeyUsage_units(); u->name; ++u) {
1457 0 : if ((ku_num & u->mult)) {
1458 0 : fprintf(f, "%s%s", first, u->name);
1459 0 : first = ", ";
1460 0 : ku_num &= ~u->mult;
1461 : }
1462 : }
1463 0 : if (ku_num)
1464 0 : fprintf(f, "%s<unknown-KeyUsage-value(s)>", first);
1465 0 : fprintf(f, "\n");
1466 : }
1467 0 : if (req->eku.len) {
1468 0 : const char *first = " ";
1469 :
1470 0 : fprintf(f, " eku:");
1471 0 : for (i = 0; ret == 0; i++) {
1472 0 : free(s); s = NULL;
1473 0 : ret = hx509_request_get_eku(req, i, &s);
1474 0 : if (ret)
1475 0 : break;
1476 0 : fprintf(f, "%s{%s}", first, s);
1477 0 : first = ", ";
1478 : }
1479 0 : fprintf(f, "\n");
1480 : }
1481 0 : free(s); s = NULL;
1482 0 : if (ret == HX509_NO_ITEM)
1483 0 : ret = 0;
1484 0 : for (i = 0; ret == 0; i++) {
1485 0 : hx509_san_type san_type;
1486 :
1487 0 : free(s); s = NULL;
1488 0 : ret = hx509_request_get_san(req, i, &san_type, &s);
1489 0 : if (ret)
1490 0 : break;
1491 0 : switch (san_type) {
1492 0 : case HX509_SAN_TYPE_EMAIL:
1493 0 : fprintf(f, " san: rfc822Name: %s\n", s);
1494 0 : break;
1495 0 : case HX509_SAN_TYPE_DNSNAME:
1496 0 : fprintf(f, " san: dNSName: %s\n", s);
1497 0 : break;
1498 0 : case HX509_SAN_TYPE_DN:
1499 0 : fprintf(f, " san: dn: %s\n", s);
1500 0 : break;
1501 0 : case HX509_SAN_TYPE_REGISTERED_ID:
1502 0 : fprintf(f, " san: registeredID: %s\n", s);
1503 0 : break;
1504 0 : case HX509_SAN_TYPE_XMPP:
1505 0 : fprintf(f, " san: xmpp: %s\n", s);
1506 0 : break;
1507 0 : case HX509_SAN_TYPE_PKINIT:
1508 0 : fprintf(f, " san: pkinit: %s\n", s);
1509 0 : break;
1510 0 : case HX509_SAN_TYPE_MS_UPN:
1511 0 : fprintf(f, " san: ms-upn: %s\n", s);
1512 0 : break;
1513 0 : default:
1514 0 : fprintf(f, " san: <SAN type not supported>\n");
1515 0 : break;
1516 : }
1517 : }
1518 0 : free(s); s = NULL;
1519 0 : if (ret == HX509_NO_ITEM)
1520 0 : ret = 0;
1521 0 : return ret;
1522 : }
|