Coverage Report

Created: 2025-07-23 07:04

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