root/crypto/libecc/src/curves/curves.c
/*
 *  Copyright (C) 2017 - This file is part of libecc project
 *
 *  Authors:
 *      Ryad BENADJILA <ryadbenadjila@gmail.com>
 *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
 *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
 *
 *  Contributors:
 *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
 *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
 *
 *  This software is licensed under a dual BSD and GPL v2 license.
 *  See LICENSE file at the root folder of the project.
 */
#include <libecc/curves/curves.h>

/*
 * From a null-terminated string 'ec_name' of exact length 'ec_name_len'
 * (including final null character), the function returns a pointer
 * to the parameters for that curve via 'ec_params'. The function returns
 * -1 on error or if the search was unsuccessful. It returns 0 on success.
 * 'ec_params' is not meaningful on error.
 */
int ec_get_curve_params_by_name(const u8 *ec_name, u8 ec_name_len,
                                const ec_str_params **ec_s_params)
{
        const ec_str_params *params;
        u8 comp_len, name_len;
        u32 len;
        const ec_mapping *map;
        const u8 *name;
        unsigned int i;
        int ret, check;

        MUST_HAVE((ec_name != NULL), ret, err);
        MUST_HAVE((ec_s_params != NULL), ret, err);
        MUST_HAVE(((ec_name_len > 2) && (ec_name_len <= MAX_CURVE_NAME_LEN)), ret, err);

        /*
         * User has been warned ec_name_len is expected to include final
         * null character.
         */
        ret = local_strnlen((const char *)ec_name, ec_name_len, &len); EG(ret, err);
        comp_len = (u8)len;
        MUST_HAVE(((comp_len + 1) == ec_name_len), ret, err);

        /* Iterate on our list of curves */
        ret = -1;
        for (i = 0; i < EC_CURVES_NUM; i++) {
                map = &ec_maps[i];
                params = map->params;

                MUST_HAVE((params != NULL), ret, err);
                MUST_HAVE((params->name != NULL), ret, err);
                MUST_HAVE((params->name->buf != NULL), ret, err);

                name = params->name->buf;
                name_len = params->name->buflen;

                if (name_len != ec_name_len) {
                        continue;
                }

                if ((!are_str_equal((const char *)ec_name, (const char *)name, &check)) && check) {
                        (*ec_s_params) = params;
                        ret = 0;
                        break;
                }
        }

 err:
        return ret;
}

/*
 * From given curve type 'ec_type', the function provides a pointer to the
 * parameters for that curve if it is known, using 'ec_params' out parameter.
 * On error, or if the curve is unknown, the function returns -1, in which
 * case 'ec_params' is not meaningful. The function returns 0 on success.
 */
int ec_get_curve_params_by_type(ec_curve_type ec_type,
                                const ec_str_params **ec_s_params)
{
        const ec_str_params *params;
        const ec_mapping *map;
        const u8 *name;
        u32 len;
        u8 name_len;
        unsigned int i;
        int ret;

        MUST_HAVE((ec_s_params != NULL), ret, err);

        ret = -1;
        for (i = 0; i < EC_CURVES_NUM; i++) {
                map = &ec_maps[i];
                params = map->params;

                MUST_HAVE((params != NULL), ret, err);

                if (ec_type == map->type) {
                        /* Do some sanity check before returning */
                        MUST_HAVE((params->name != NULL), ret, err);
                        MUST_HAVE((params->name->buf != NULL), ret, err);

                        name = params->name->buf;
                        ret = local_strlen((const char *)name, &len); EG(ret, err);
                        MUST_HAVE(len < 256, ret, err);
                        name_len = (u8)len;

                        MUST_HAVE((params->name->buflen == (name_len + 1)), ret, err);

                        (*ec_s_params) = params;
                        ret = 0;
                        break;
                }
        }

err:
        return ret;
}

/*
 * From a null-terminated string 'ec_name' of exact length 'ec_name_len'
 * (including final null character), the function returns the curve type
 * via 'ec_type'. The function returns -1 on error or if the search was
 * unsuccessful. It returns 0 on success. 'ec_types' is not meaningful
 * on error.
 */
int ec_get_curve_type_by_name(const u8 *ec_name, u8 ec_name_len,
                              ec_curve_type *ec_type)
{
        const ec_str_params *params;
        u32 len;
        u8 name_len, comp_len;
        const ec_mapping *map;
        const u8 *name;
        unsigned int i;
        int ret, check;

        /* No need to bother w/ obvious crap */
        MUST_HAVE(((ec_name_len > 2) && (ec_name_len <= MAX_CURVE_NAME_LEN)), ret, err);
        MUST_HAVE((ec_type != NULL), ret, err);
        MUST_HAVE((ec_name != NULL), ret, err);

        /*
         * User has been warned ec_name_len is expected to include final
         * null character.
         */
        ret = local_strnlen((const char *)ec_name, ec_name_len, &len); EG(ret, err);
        MUST_HAVE(len < 256, ret, err);
        comp_len = (u8)len;
        MUST_HAVE(((comp_len + 1) == ec_name_len), ret, err);

        /* Iterate on our list of curves */
        ret = -1;
        for (i = 0; i < EC_CURVES_NUM; i++) {
                map = &ec_maps[i];
                params = map->params;

                MUST_HAVE((params != NULL), ret, err);
                MUST_HAVE((params->name != NULL), ret, err);
                MUST_HAVE((params->name->buf != NULL), ret, err);

                name = params->name->buf;
                name_len = params->name->buflen;

                if (name_len != ec_name_len) {
                        continue;
                }

                if((!are_str_equal((const char *)ec_name, (const char *)name, &check)) && check) {
                        (*ec_type) = map->type;
                        ret = 0;
                        break;
                }
        }

 err:
        return ret;
}

/*
 * Given a curve type, the function finds the curve described by given type
 * and write its name (null terminated string) to given output buffer 'out'
 * of length 'outlen'. 0 is returned on success, -1 otherwise.
 */
int ec_get_curve_name_by_type(const ec_curve_type ec_type, u8 *out, u8 outlen)
{
        const ec_str_params *by_type;
        const u8 *name;
        u8 name_len;
        int ret;

        MUST_HAVE((out != NULL), ret, err);

        /* Let's first do the lookup by type */
        ret =  ec_get_curve_params_by_type(ec_type, &by_type); EG(ret, err);

        /* Found a curve for that type. Let's check name matches. */
        MUST_HAVE((by_type != NULL), ret, err);
        MUST_HAVE((by_type->name != NULL), ret, err);
        MUST_HAVE((by_type->name->buf != NULL), ret, err);

        name_len = by_type->name->buflen;
        name = by_type->name->buf;

        /* Not enough room to copy curve name? */
        MUST_HAVE((name_len <= outlen), ret, err);

        ret = local_memcpy(out, name, name_len);

 err:
        return ret;
}

/*
 * The function verifies the coherency between given curve type value and
 * associated name 'ec_name' of length 'ec_name_len' (including final
 * null character). The function returns 0 if the curve type is known
 * and provided name matches expected one. The function returns -1
 * otherwise.
 */
int ec_check_curve_type_and_name(const ec_curve_type ec_type,
                                 const u8 *ec_name, u8 ec_name_len)
{
        const ec_str_params *by_type;
        const u8 *name;
        u8 name_len;
        int ret, check;

        /* No need to bother w/ obvious crap */
        MUST_HAVE((ec_name != NULL), ret, err);
        MUST_HAVE(((ec_name_len > 2) && (ec_name_len <= MAX_CURVE_NAME_LEN)), ret, err);

        /* Let's first do the lookup by type */
        ret = ec_get_curve_params_by_type(ec_type, &by_type); EG(ret, err);

        /* Found a curve for that type. Let's check name matches. */
        MUST_HAVE((by_type != NULL), ret, err);
        MUST_HAVE((by_type->name != NULL), ret, err);
        MUST_HAVE((by_type->name->buf != NULL), ret, err);

        name = by_type->name->buf;
        name_len = by_type->name->buflen;

        MUST_HAVE((name_len == ec_name_len), ret, err);

        if ((!are_str_equal((const char *)ec_name, (const char *)name, &check)) && (!check)) {
                ret = -1;
        }

err:
        return ret;
}