EC key generation, extract public and get_bit_length 19/80119/1
authorLukasz Pawelczyk <l.pawelczyk@samsung.com>
Mon, 11 Jul 2016 10:29:12 +0000 (12:29 +0200)
committerLukasz Pawelczyk <l.pawelczyk@samsung.com>
Thu, 14 Jul 2016 14:53:04 +0000 (16:53 +0200)
Change-Id: I55f22032778eaf6eaeb5d598eec1fe94fe684765

api/yaca/yaca_key.h
api/yaca/yaca_types.h
src/key.c

index c877766..f5de839 100755 (executable)
@@ -54,6 +54,8 @@ extern "C" {
  * @return #YACA_ERROR_NONE on success, negative on error
  * @retval #YACA_ERROR_NONE Successful
  * @retval #YACA_ERROR_INVALID_PARAMETER Either of the params is NULL
+ *
+ * @see #yaca_key_type_e
  */
 int yaca_key_get_type(const yaca_key_h key, yaca_key_type_e *key_type);
 
@@ -62,6 +64,8 @@ int yaca_key_get_type(const yaca_key_h key, yaca_key_type_e *key_type);
  *
  * @since_tizen 3.0
  *
+ * @remarks  For elliptic curves @a key_bit_len returns values from #yaca_key_bit_length_ec_e
+ *
  * @param[in]  key          Key which length we return
  * @param[out] key_bit_len  Key length in bits
  *
@@ -69,6 +73,9 @@ int yaca_key_get_type(const yaca_key_h key, yaca_key_type_e *key_type);
  * @retval #YACA_ERROR_NONE Successful
  * @retval #YACA_ERROR_INVALID_PARAMETER Either of the params is NULL
  * @retval #YACA_ERROR_INTERNAL Internal error
+ *
+ * @see #yaca_key_bit_length_e
+ * @see #yaca_key_bit_length_ec_e
  */
 int yaca_key_get_bit_length(const yaca_key_h key, size_t *key_bit_len);
 
@@ -194,6 +201,7 @@ int yaca_key_export(const yaca_key_h key,
  * @remarks  Supported key lengths:
  *           - RSA: length >= 256bits
  *           - DSA: length >= 512bits, multiple of 64
+ *           - EC: @a key_bit_len takes values from #yaca_key_bit_length_ec_e
  *
  * @remarks  The @a key should be released using yaca_key_destroy()
  *
@@ -210,6 +218,7 @@ int yaca_key_export(const yaca_key_h key,
  *
  * @see #yaca_key_type_e
  * @see #yaca_key_bit_length_e
+ * @see #yaca_key_bit_length_ec_e
  * @see yaca_key_destroy()
  */
 int yaca_key_generate(yaca_key_type_e key_type,
index cd78f88..8c3a5b1 100755 (executable)
@@ -33,6 +33,68 @@ extern "C" {
  * @{
  */
 
+/* The format of the unsigned int used to indicate key_bit_len is as follows:
+ *
+ *      Bits indicating a type:
+ *           bits 31-30 (2 bits) indicate key_length type:
+ *                00(0) - regular type for RSA, DSA and DH
+ *                01(1) - elliptic curve
+ *                remaining combinations reserved
+ *
+ *      Bits for a regular type:
+ *           bits 29-0 (30 bits) indicate length of the key in bits
+ *
+ *      Bits for an elliptic curve type:
+ *           bits 29-26 (4 bits) indicate type of an elliptic curve:
+ *                0000(0) - X9.62 Prime
+ *                0001(1) - SECP
+ *                0010(2) - SECT
+ *                0011(3) - Brainpool
+ *                remaining combinations reserved (c2pnb, c2tnb, c2onb...)
+ *           bits 25-22 (4 bits) indicate a letter:
+ *                0000(0) - v
+ *                0001(1) - r
+ *                0010(2) - k
+ *                0011(3) - t
+ *                remaining combinations reserved (w...)
+ *           bits 21-18 (4 bits) indicate a number:
+ *                0000(0) - 1
+ *                0001(1) - 2
+ *                0010(2) - 3
+ *                0011(3) - 4
+ *                remaining combinations reserved
+ *           bits 17-0 (18 bits) - length of the prime field in bits
+ *
+ * For now this is mostly used for elliptic curves. For any other keys key_bit_len can be
+ * passed just as a number of bits (2 most significant bits set to 00, 30 bits for bit length).
+ *
+ * For elliptic curves don't use those defines directly, use enums in yaca_key_bit_length_ec_e.
+ * Not all combinations are valid and other valid combinations are not guaranteed to be
+ * implemented (they most surely aren't).
+ */
+
+/** @cond  Don't include those defines in doxygen, they are not to be used directly */
+#define YACA_KEY_LEN_TYPE_MASK     (3U << 30)
+
+#define YACA_KEY_LEN_TYPE_REGULAR  (0U << 30)
+#define YACA_KEY_LEN_TYPE_EC       (1U << 30)
+
+#define YACA_KEY_LEN_EC_PRIME      (0U << 26)
+#define YACA_KEY_LEN_EC_SECP       (1U << 26)
+#define YACA_KEY_LEN_EC_SECT       (2U << 26)
+#define YACA_KEY_LEN_EC_BRAINPOOL  (3U << 26)
+
+#define YACA_KEY_LEN_EC_V          (0U << 22)
+#define YACA_KEY_LEN_EC_R          (1U << 22)
+#define YACA_KEY_LEN_EC_K          (2U << 22)
+#define YACA_KEY_LEN_EC_T          (3U << 22)
+
+#define YACA_KEY_LEN_EC_1          (0U << 18)
+#define YACA_KEY_LEN_EC_2          (1U << 18)
+#define YACA_KEY_LEN_EC_3          (2U << 18)
+#define YACA_KEY_LEN_EC_4          (3U << 18)
+/** @endcond */
+
 /**
  * @brief The context handle.
  *
@@ -152,6 +214,26 @@ typedef enum {
 } yaca_key_bit_length_e;
 
 /**
+ * @brief Enumeration of YACA elliptic curve types with their bit lengths.
+ *        It's meant to be passed or returned as a @a key_bit_len param
+ *        in appropriate functions when dealing with elliptic curves.
+ *
+ * @since_tizen 3.0
+ */
+typedef enum {
+       /** Elliptic curve prime192v1 */
+       YACA_KEY_LENGTH_EC_PRIME192V1 = YACA_KEY_LEN_TYPE_EC | YACA_KEY_LEN_EC_PRIME | YACA_KEY_LEN_EC_V | YACA_KEY_LEN_EC_1 | 192U,
+       /** Elliptic curve prime256v1 */
+       YACA_KEY_LENGTH_EC_PRIME256V1 = YACA_KEY_LEN_TYPE_EC | YACA_KEY_LEN_EC_PRIME | YACA_KEY_LEN_EC_V | YACA_KEY_LEN_EC_1 | 256U,
+       /** Elliptic curve secp256k1 */
+       YACA_KEY_LENGTH_EC_SECP256K1 = YACA_KEY_LEN_TYPE_EC | YACA_KEY_LEN_EC_SECP | YACA_KEY_LEN_EC_K | YACA_KEY_LEN_EC_1 | 256U,
+       /** Elliptic curve secp384r1 */
+       YACA_KEY_LENGTH_EC_SECP384R1 = YACA_KEY_LEN_TYPE_EC | YACA_KEY_LEN_EC_SECP | YACA_KEY_LEN_EC_R | YACA_KEY_LEN_EC_1 | 384U,
+       /** Elliptic curve secp521r1 */
+       YACA_KEY_LENGTH_EC_SECP521R1 = YACA_KEY_LEN_TYPE_EC | YACA_KEY_LEN_EC_SECP | YACA_KEY_LEN_EC_R | YACA_KEY_LEN_EC_1 | 521U
+} yaca_key_bit_length_ec_e;
+
+/**
  * @brief Enumeration of YACA message digest algorithms.
  *
  * @since_tizen 3.0
index 706e9dc..b2df812 100644 (file)
--- a/src/key.c
+++ b/src/key.c
 #include <yaca_crypto.h>
 #include <yaca_error.h>
 #include <yaca_key.h>
+#include <yaca_types.h>
 
 #include "internal.h"
 
+const static struct {
+       size_t key_bit_len_ec;
+       int nid;
+} EC_NID_PAIRS[] = {
+       {YACA_KEY_LENGTH_EC_PRIME192V1, NID_X9_62_prime192v1},
+       {YACA_KEY_LENGTH_EC_PRIME256V1, NID_X9_62_prime256v1},
+       {YACA_KEY_LENGTH_EC_SECP256K1,  NID_secp256k1},
+       {YACA_KEY_LENGTH_EC_SECP384R1,  NID_secp384r1},
+       {YACA_KEY_LENGTH_EC_SECP521R1,  NID_secp521r1}
+};
+
+const static size_t EC_NID_PAIRS_SIZE = sizeof(EC_NID_PAIRS) / sizeof(EC_NID_PAIRS[0]);
+
 struct openssl_password_data {
        bool password_requested;
        const char *password;
@@ -739,6 +753,9 @@ int generate_simple(struct yaca_key_simple_s **out, size_t key_bit_len)
 {
        assert(out != NULL);
 
+       if (key_bit_len % 8 != 0)
+               return YACA_ERROR_INVALID_PARAMETER;
+
        int ret;
        struct yaca_key_simple_s *nk;
        size_t key_byte_len = key_bit_len / 8;
@@ -811,6 +828,38 @@ exit:
        return ret;
 }
 
+int convert_ec_to_nid(size_t key_bit_len_ec, int *nid)
+{
+       assert(nid != NULL);
+
+       size_t i;
+
+       for (i = 0; i < EC_NID_PAIRS_SIZE; ++i) {
+               if (EC_NID_PAIRS[i].key_bit_len_ec == key_bit_len_ec) {
+                       *nid = EC_NID_PAIRS[i].nid;
+                       return YACA_ERROR_NONE;
+               }
+       }
+
+       return YACA_ERROR_INVALID_PARAMETER;
+}
+
+size_t convert_nid_to_ec(int nid, size_t *key_bit_len_ec)
+{
+       assert(key_bit_len_ec != NULL);
+
+       size_t i;
+
+       for (i = 0; i < EC_NID_PAIRS_SIZE; ++i) {
+               if (EC_NID_PAIRS[i].nid == nid) {
+                       *key_bit_len_ec = EC_NID_PAIRS[i].key_bit_len_ec;
+                       return YACA_ERROR_NONE;
+               }
+       }
+
+       return YACA_ERROR_INVALID_PARAMETER;
+}
+
 int generate_evp(struct yaca_key_evp_s **out, yaca_key_type_e key_type, size_t key_bit_len)
 {
        assert(out != NULL);
@@ -825,29 +874,40 @@ int generate_evp(struct yaca_key_evp_s **out, yaca_key_type_e key_type, size_t k
        EVP_PKEY *params = NULL;
        struct yaca_key_evp_s *nk;
 
-       switch(key_type) {
+       switch (key_type) {
        case YACA_KEY_TYPE_RSA_PRIV:
-               assert(key_bit_len % 8 == 0);
+               if ((key_bit_len & YACA_KEY_LEN_TYPE_MASK) != YACA_KEY_LEN_TYPE_REGULAR ||
+                   key_bit_len % 8 != 0)
+                       return YACA_ERROR_INVALID_PARAMETER;
 
                id = EVP_PKEY_RSA;
                do_params = false;
                break;
        case YACA_KEY_TYPE_DSA_PRIV:
-               assert(key_bit_len % 8 == 0);
-
-               /* Openssl generates 512-bit key for key lengths smaller than 512. It also
-                * rounds key size to multiplication of 64. */
-               if (key_bit_len < 512 || key_bit_len % 64 != 0)
+               if ((key_bit_len & YACA_KEY_LEN_TYPE_MASK) != YACA_KEY_LEN_TYPE_REGULAR ||
+                   /* Openssl generates 512-bit key for key lengths smaller than 512. It also
+                    * rounds key size to multiplication of 64. */
+                   key_bit_len < 512 || key_bit_len % 64 != 0)
                        return YACA_ERROR_INVALID_PARAMETER;
+
                id = EVP_PKEY_DSA;
                do_params = true;
                break;
        case YACA_KEY_TYPE_DH_PRIV:
-               assert(key_bit_len % 8 == 0);
+               if ((key_bit_len & YACA_KEY_LEN_TYPE_MASK) != YACA_KEY_LEN_TYPE_REGULAR ||
+                   key_bit_len % 8 != 0)
+                       return YACA_ERROR_INVALID_PARAMETER;
 
                id = EVP_PKEY_DH;
                do_params = true;
                break;
+       case YACA_KEY_TYPE_EC_PRIV:
+               if ((key_bit_len & YACA_KEY_LEN_TYPE_MASK) != YACA_KEY_LEN_TYPE_EC)
+                       return YACA_ERROR_INVALID_PARAMETER;
+
+               id = EVP_PKEY_EC;
+               do_params = true;
+               break;
        default:
                return YACA_ERROR_INVALID_PARAMETER;
        }
@@ -871,19 +931,30 @@ int generate_evp(struct yaca_key_evp_s **out, yaca_key_type_e key_type, size_t k
                        goto exit;
                }
 
-               switch(id) {
+               switch (id) {
                case EVP_PKEY_DSA:
                        ret = EVP_PKEY_CTX_set_dsa_paramgen_bits(pctx, key_bit_len);
                        break;
                case EVP_PKEY_DH:
                        ret = EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx, key_bit_len);
                        break;
+               case EVP_PKEY_EC: {
+                       int nid;
+                       ret = convert_ec_to_nid(key_bit_len, &nid);
+                       if (ret != YACA_ERROR_NONE)
+                               goto exit;
+                       ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid);
+                       if (ret == 1)
+                               ret = EVP_PKEY_CTX_set_ec_param_enc(pctx, OPENSSL_EC_NAMED_CURVE);
+                       break;
+               }
                default:
                        /* We shouldn't be here */
                        assert(false);
                        ret = YACA_ERROR_INTERNAL;
                        goto exit;
                }
+
                if (ret != 1) {
                        ret = YACA_ERROR_INTERNAL;
                        ERROR_DUMP(ret);
@@ -983,6 +1054,8 @@ struct yaca_key_evp_s *key_get_evp(const yaca_key_h key)
        case YACA_KEY_TYPE_DSA_PRIV:
        case YACA_KEY_TYPE_DH_PUB:
        case YACA_KEY_TYPE_DH_PRIV:
+       case YACA_KEY_TYPE_EC_PUB:
+       case YACA_KEY_TYPE_EC_PRIV:
                k = (struct yaca_key_evp_s *)key;
 
                /* sanity check */
@@ -1068,16 +1141,44 @@ API int yaca_key_get_bit_length(const yaca_key_h key, size_t *key_bit_len)
        if (evp_key != NULL) {
                int ret;
 
-               // TODO: handle ECC keys when they're implemented
-               ret = EVP_PKEY_bits(evp_key->evp);
-               if (ret <= 0) {
-                       ret = YACA_ERROR_INTERNAL;
-                       ERROR_DUMP(ret);
-                       return ret;
-               }
+               switch (evp_key->key.type) {
+               case YACA_KEY_TYPE_RSA_PRIV:
+               case YACA_KEY_TYPE_RSA_PUB:
+               case YACA_KEY_TYPE_DSA_PRIV:
+               case YACA_KEY_TYPE_DSA_PUB:
+               case YACA_KEY_TYPE_DH_PRIV:
+               case YACA_KEY_TYPE_DH_PUB:
+                       ret = EVP_PKEY_bits(evp_key->evp);
+                       if (ret <= 0) {
+                               ret = YACA_ERROR_INTERNAL;
+                               ERROR_DUMP(ret);
+                               return ret;
+                       }
 
-               *key_bit_len = ret;
-               return YACA_ERROR_NONE;
+                       *key_bit_len = ret;
+                       return YACA_ERROR_NONE;
+               case YACA_KEY_TYPE_EC_PRIV:
+               case YACA_KEY_TYPE_EC_PUB: {
+                       assert(EVP_PKEY_type(evp_key->evp->type) == EVP_PKEY_EC);
+
+                       const EC_KEY *eck = EVP_PKEY_get0(evp_key->evp);
+                       const EC_GROUP *ecg = EC_KEY_get0_group(eck);
+                       int flags = EC_GROUP_get_asn1_flag(ecg);
+                       int nid;
+
+                       if (!(flags & OPENSSL_EC_NAMED_CURVE))
+                               /* This is case of a custom (not named) curve, that can happen when someone
+                                  imports such a key into YACA. There is nothing that can be returned here */
+                               return YACA_ERROR_INVALID_PARAMETER;
+
+                       nid = EC_GROUP_get_curve_name(ecg);
+                       return convert_nid_to_ec(nid, key_bit_len);
+               }
+               default:
+                       /* We shouldn't be here */
+                       assert(false);
+                       return YACA_ERROR_INTERNAL;
+               }
        }
 
        return YACA_ERROR_INVALID_PARAMETER;
@@ -1163,7 +1264,7 @@ API int yaca_key_generate(yaca_key_type_e key_type,
        struct yaca_key_simple_s *nk_simple = NULL;
        struct yaca_key_evp_s *nk_evp = NULL;
 
-       if (key == NULL || key_bit_len == 0 || key_bit_len % 8 != 0)
+       if (key == NULL || key_bit_len == 0)
                return YACA_ERROR_INVALID_PARAMETER;
 
        switch (key_type) {
@@ -1177,10 +1278,9 @@ API int yaca_key_generate(yaca_key_type_e key_type,
        case YACA_KEY_TYPE_RSA_PRIV:
        case YACA_KEY_TYPE_DSA_PRIV:
        case YACA_KEY_TYPE_DH_PRIV:
+       case YACA_KEY_TYPE_EC_PRIV:
                ret = generate_evp(&nk_evp, key_type, key_bit_len);
                break;
-       case YACA_KEY_TYPE_EC_PRIV:
-               //TODO NOT_IMPLEMENTED
        default:
                return YACA_ERROR_INVALID_PARAMETER;
        }
@@ -1197,7 +1297,6 @@ API int yaca_key_generate(yaca_key_type_e key_type,
        }
 
        return YACA_ERROR_NONE;
-
 }
 
 API int yaca_key_extract_public(const yaca_key_h prv_key, yaca_key_h *pub_key)