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

Generated by: LCOV version 1.14