LCOV - code coverage report
Current view: top level - third_party/heimdal/kdc - pkinit-ec.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 8 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include <config.h>
      37             : #include <roken.h>
      38             : 
      39             : #ifdef PKINIT
      40             : 
      41             : /*
      42             :  * As with the other *-ec.c files in Heimdal, this is a bit of a hack.
      43             :  *
      44             :  * The idea is to use OpenSSL for EC because hcrypto doesn't have the
      45             :  * required functionality at this time.  To do this we segregate
      46             :  * EC-using code into separate source files and then we arrange for them
      47             :  * to get the OpenSSL headers and not the conflicting hcrypto ones.
      48             :  *
      49             :  * Because of auto-generated *-private.h headers, we end up needing to
      50             :  * make sure various types are defined before we include them, thus the
      51             :  * strange header include order here.
      52             :  */
      53             : 
      54             : #ifdef HAVE_HCRYPTO_W_OPENSSL
      55             : #include <openssl/ec.h>
      56             : #include <openssl/ecdh.h>
      57             : #include <openssl/evp.h>
      58             : #include <openssl/bn.h>
      59             : #define HEIM_NO_CRYPTO_HDRS
      60             : #endif /* HAVE_HCRYPTO_W_OPENSSL */
      61             : 
      62             : #define NO_HCRYPTO_POLLUTION
      63             : 
      64             : #include "kdc_locl.h"
      65             : #include <hcrypto/des.h>
      66             : #include <heim_asn1.h>
      67             : #include <rfc2459_asn1.h>
      68             : #include <cms_asn1.h>
      69             : #include <pkinit_asn1.h>
      70             : 
      71             : #include <hx509.h>
      72             : 
      73             : #ifdef HAVE_HCRYPTO_W_OPENSSL
      74             : static void
      75             : free_client_ec_param(krb5_context context,
      76             :                      EC_KEY *ec_key_pk,
      77             :                      EC_KEY *ec_key_key)
      78             : {
      79             :     if (ec_key_pk != NULL)
      80             :         EC_KEY_free(ec_key_pk);
      81             :     if (ec_key_key != NULL)
      82             :         EC_KEY_free(ec_key_key);
      83             : }
      84             : #endif
      85             : 
      86             : void
      87           0 : _kdc_pk_free_client_ec_param(krb5_context context,
      88             :                              void *ec_key_pk,
      89             :                              void *ec_key_key)
      90             : {
      91             : #ifdef HAVE_HCRYPTO_W_OPENSSL
      92             :     free_client_ec_param(context, ec_key_pk, ec_key_key);
      93             : #endif
      94           0 : }
      95             : 
      96             : #ifdef HAVE_HCRYPTO_W_OPENSSL
      97             : static krb5_error_code
      98             : generate_ecdh_keyblock(krb5_context context,
      99             :                        EC_KEY *ec_key_pk,    /* the client's public key */
     100             :                        EC_KEY **ec_key_key,  /* the KDC's ephemeral private */
     101             :                        unsigned char **dh_gen_key, /* shared secret */
     102             :                        size_t *dh_gen_keylen)
     103             : {
     104             :     const EC_GROUP *group;
     105             :     EC_KEY *ephemeral;
     106             :     krb5_keyblock key;
     107             :     krb5_error_code ret;
     108             :     unsigned char *p;
     109             :     size_t size;
     110             :     int len;
     111             : 
     112             :     *dh_gen_key = NULL;
     113             :     *dh_gen_keylen = 0;
     114             :     *ec_key_key = NULL;
     115             : 
     116             :     memset(&key, 0, sizeof(key));
     117             : 
     118             :     if (ec_key_pk == NULL) {
     119             :         ret = KRB5KRB_ERR_GENERIC;
     120             :         krb5_set_error_message(context, ret, "public_key");
     121             :         return ret;
     122             :     }
     123             : 
     124             :     group = EC_KEY_get0_group(ec_key_pk);
     125             :     if (group == NULL) {
     126             :         ret = KRB5KRB_ERR_GENERIC;
     127             :         krb5_set_error_message(context, ret, "failed to get the group of "
     128             :                                "the client's public key");
     129             :         return ret;
     130             :     }
     131             : 
     132             :     ephemeral = EC_KEY_new();
     133             :     if (ephemeral == NULL)
     134             :         return krb5_enomem(context);
     135             : 
     136             :     EC_KEY_set_group(ephemeral, group);
     137             : 
     138             :     if (EC_KEY_generate_key(ephemeral) != 1) {
     139             :         EC_KEY_free(ephemeral);
     140             :         return krb5_enomem(context);
     141             :     }
     142             : 
     143             :     size = (EC_GROUP_get_degree(group) + 7) / 8;
     144             :     p = malloc(size);
     145             :     if (p == NULL) {
     146             :         EC_KEY_free(ephemeral);
     147             :         return krb5_enomem(context);
     148             :     }
     149             : 
     150             :     len = ECDH_compute_key(p, size,
     151             :                            EC_KEY_get0_public_key(ec_key_pk),
     152             :                            ephemeral, NULL);
     153             :     if (len <= 0) {
     154             :         free(p);
     155             :         EC_KEY_free(ephemeral);
     156             :         ret = KRB5KRB_ERR_GENERIC;
     157             :         krb5_set_error_message(context, ret, "Failed to compute ECDH "
     158             :                                "public shared secret");
     159             :         return ret;
     160             :     }
     161             : 
     162             :     *ec_key_key = ephemeral;
     163             :     *dh_gen_key = p;
     164             :     *dh_gen_keylen = len;
     165             : 
     166             :     return 0;
     167             : }
     168             : #endif /* HAVE_HCRYPTO_W_OPENSSL */
     169             : 
     170             : krb5_error_code
     171           0 : _kdc_generate_ecdh_keyblock(krb5_context context,
     172             :                             void *ec_key_pk,    /* the client's public key */
     173             :                             void **ec_key_key,  /* the KDC's ephemeral private */
     174             :                             unsigned char **dh_gen_key, /* shared secret */
     175             :                             size_t *dh_gen_keylen)
     176             : {
     177             : #ifdef HAVE_HCRYPTO_W_OPENSSL
     178             :     return generate_ecdh_keyblock(context, ec_key_pk,
     179             :                                   (EC_KEY **)ec_key_key,
     180             :                                   dh_gen_key, dh_gen_keylen);
     181             : #else
     182           0 :     return ENOTSUP;
     183             : #endif /* HAVE_HCRYPTO_W_OPENSSL */
     184             : }
     185             : 
     186             : #ifdef HAVE_HCRYPTO_W_OPENSSL
     187             : static krb5_error_code
     188             : get_ecdh_param(krb5_context context,
     189             :                krb5_kdc_configuration *config,
     190             :                SubjectPublicKeyInfo *dh_key_info,
     191             :                EC_KEY **out)
     192             : {
     193             :     ECParameters ecp;
     194             :     EC_KEY *public = NULL;
     195             :     krb5_error_code ret;
     196             :     const unsigned char *p;
     197             :     size_t len;
     198             :     int nid;
     199             : 
     200             :     if (dh_key_info->algorithm.parameters == NULL) {
     201             :         krb5_set_error_message(context, KRB5_BADMSGTYPE,
     202             :                                "PKINIT missing algorithm parameter "
     203             :                                "in clientPublicValue");
     204             :         return KRB5_BADMSGTYPE;
     205             :     }
     206             : 
     207             :     memset(&ecp, 0, sizeof(ecp));
     208             : 
     209             :     ret = decode_ECParameters(dh_key_info->algorithm.parameters->data,
     210             :                               dh_key_info->algorithm.parameters->length, &ecp, &len);
     211             :     if (ret)
     212             :         goto out;
     213             : 
     214             :     if (ecp.element != choice_ECParameters_namedCurve) {
     215             :         ret = KRB5_BADMSGTYPE;
     216             :         goto out;
     217             :     }
     218             : 
     219             :     if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0)
     220             :         nid = NID_X9_62_prime256v1;
     221             :     else {
     222             :         ret = KRB5_BADMSGTYPE;
     223             :         goto out;
     224             :     }
     225             : 
     226             :     /* XXX verify group is ok */
     227             : 
     228             :     public = EC_KEY_new_by_curve_name(nid);
     229             : 
     230             :     p = dh_key_info->subjectPublicKey.data;
     231             :     len = dh_key_info->subjectPublicKey.length / 8;
     232             :     if (o2i_ECPublicKey(&public, &p, len) == NULL) {
     233             :         ret = KRB5_BADMSGTYPE;
     234             :         krb5_set_error_message(context, ret,
     235             :                                "PKINIT failed to decode ECDH key");
     236             :         goto out;
     237             :     }
     238             :     *out = public;
     239             :     public = NULL;
     240             : 
     241             :  out:
     242             :     if (public)
     243             :         EC_KEY_free(public);
     244             :     free_ECParameters(&ecp);
     245             :     return ret;
     246             : }
     247             : #endif /* HAVE_HCRYPTO_W_OPENSSL */
     248             : 
     249             : krb5_error_code
     250           0 : _kdc_get_ecdh_param(krb5_context context,
     251             :                     krb5_kdc_configuration *config,
     252             :                     SubjectPublicKeyInfo *dh_key_info,
     253             :                     void **out)
     254             : {
     255             : #ifdef HAVE_HCRYPTO_W_OPENSSL
     256             :     return get_ecdh_param(context, config, dh_key_info, (EC_KEY **)out);
     257             : #else
     258           0 :     return ENOTSUP;
     259             : #endif /* HAVE_HCRYPTO_W_OPENSSL */
     260             : }
     261             : 
     262             : 
     263             : /*
     264             :  *
     265             :  */
     266             : 
     267             : #ifdef HAVE_HCRYPTO_W_OPENSSL
     268             : static krb5_error_code
     269             : serialize_ecdh_key(krb5_context context,
     270             :                    EC_KEY *key,
     271             :                    unsigned char **out,
     272             :                    size_t *out_len)
     273             : {
     274             :     krb5_error_code ret = 0;
     275             :     unsigned char *p;
     276             :     int len;
     277             : 
     278             :     *out = NULL;
     279             :     *out_len = 0;
     280             : 
     281             :     len = i2o_ECPublicKey(key, NULL);
     282             :     if (len <= 0)
     283             :         return EOVERFLOW;
     284             : 
     285             :     *out = malloc(len);
     286             :     if (*out == NULL)
     287             :         return krb5_enomem(context);
     288             : 
     289             :     p = *out;
     290             :     len = i2o_ECPublicKey(key, &p);
     291             :     if (len <= 0) {
     292             :         free(*out);
     293             :         *out = NULL;
     294             :         ret = EINVAL; /* XXX Better error please */
     295             :         krb5_set_error_message(context, ret,
     296             :                                "PKINIT failed to encode ECDH key");
     297             :         return ret;
     298             :     }
     299             : 
     300             :     *out_len = len * 8;
     301             :     return ret;
     302             : }
     303             : #endif
     304             : 
     305             : krb5_error_code
     306           0 : _kdc_serialize_ecdh_key(krb5_context context,
     307             :                         void *key,
     308             :                         unsigned char **out,
     309             :                         size_t *out_len)
     310             : {
     311             : #ifdef HAVE_HCRYPTO_W_OPENSSL
     312             :     return serialize_ecdh_key(context, key, out, out_len);
     313             : #else
     314           0 :     return ENOTSUP;
     315             : #endif
     316             : }
     317             : 
     318             : #endif

Generated by: LCOV version 1.13