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

Generated by: LCOV version 1.13