LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - req.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 0 692 0.0 %
Date: 2024-01-11 09:59:51 Functions: 0 46 0.0 %

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

Generated by: LCOV version 1.14