Add separate API function stubs for HMAC/CMAC context initialization. 47/69447/9
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 17 May 2016 09:57:12 +0000 (11:57 +0200)
committerDariusz Michaluk <d.michaluk@samsung.com>
Thu, 19 May 2016 12:11:21 +0000 (14:11 +0200)
MACs are symmetric equivalent for asymmetric signatures. For asymmetric
signatures the signing algorithm can be easily deduced from the key. This is
not the case for MAC's where plain symmetric key tells us nothing about the MAC
algorithm we want to use. Considered solutions:

1. Introducing new key types for MACs. Cons:
 - unclear how to handle plain symmetric keys,
 - introduces an artificial division in symmetric keys,
 - new enum values,
 - CMAC cipher has to be set via ctx params.

2. Deducing MAC algorithm from digest algorithm. Digest->HMAC, no digest->CMAC.
   Cons:
 - unclear which algorithm will be used,
 - adding new MAC algorithm may require a significant API change,
 - CMAC cipher has to be set via ctx params.

3. Leaving CMAC as a digest algorithm. Cons:
 - CMAC is not a digest algorithm. It's an equivalent of HMAC, RSA, DSA,...etc,
 - CMAC can't be used for calculating message digest alone,
 - CMAC can't be used as a digest algorithm for HMAC
 - CMAC cipher has to be set via ctx params.

4. Adding new API for CMAC and HMAC context creation. Cons:
 - 1 new functions per MAC algo for context initalization,
 - 1 function for signature comparison
 - low API flexibility

This is an initial commit for solution 4.

Change-Id: I745854fd7b7d87f2c114475b709566ec512d7bbd

api/yaca/crypto.h
api/yaca/error.h
api/yaca/sign.h
src/crypto.c
src/sign.c

index 9959df0..76a2897 100644 (file)
@@ -181,6 +181,17 @@ int yaca_get_output_length(const yaca_ctx_h ctx, size_t input_len, size_t *outpu
  */
 #define yaca_get_block_length(ctxa, output_len) yaca_get_output_length((ctxa), 0, (output_len))
 
+/**
+ * @brief  Safely compares first @b len bytes of two buffers.
+ *
+ * @param[in]  first  Pointer to the first buffer.
+ * @param[in]  second Pointer to the second buffer.
+ * @param[in]  len    Length to compare.
+ *
+ * @return 0 when buffers are equal otherwise #YACA_ERROR_DATA_MISMATCH
+ */
+int yaca_memcmp(const void *first, const void *second, size_t len);
+
 /**@}*/
 
 #ifdef __cplusplus
index 22030dd..8aa150b 100644 (file)
@@ -44,7 +44,7 @@ enum __yaca_error_code {
        YACA_ERROR_INTERNAL           = -3,
        YACA_ERROR_TOO_BIG_ARGUMENT   = -4,
        YACA_ERROR_OUT_OF_MEMORY      = -5,
-       YACA_ERROR_SIGNATURE_INVALID  = -6,
+       YACA_ERROR_DATA_MISMATCH      = -6,
        YACA_ERROR_PASSWORD_INVALID   = -7
 };
 
index f018a31..9dcbe43 100644 (file)
@@ -41,57 +41,115 @@ extern "C" {
  */
 
 /**
- * @brief  Initializes a signature context.
+ * @brief  Initializes a signature context for asymmetric signatures.
+ *
+ * For verification use yaca_verify_init(), yaca_verify_update() and
+ * yaca_verify_final() functions with matching public key.
  *
  * @param[out] ctx   Newly created context (must be freed with yaca_ctx_free()).
  * @param[in]  algo  Digest algorithm that will be used.
- * @param[in]  key   Private or symmetric key that will be used (algorithm is deduced based on key type).
+ * @param[in]  key   Private key that will be used. Algorithm is deduced based
+ *                   on key type. Supported key types:
+ *                   - #YACA_KEY_TYPE_RSA_PRIV,
+ *                   - #YACA_KEY_TYPE_DSA_PRIV,
+ *                   - #YACA_KEY_TYPE_ECDSA_PRIV.
  *
  * @return 0 on success, negative on error.
- * @see #yaca_digest_algo_e, yaca_sign_update(), yaca_sign_final()
+ * @see #yaca_key_type_e, #yaca_digest_algo_e, yaca_sign_update(),
+ *      yaca_sign_final(), yaca_verify_init(), yaca_verify_update(),
+ *      yaca_verify_final()
  */
 int yaca_sign_init(yaca_ctx_h *ctx,
                    yaca_digest_algo_e algo,
                    const yaca_key_h key);
 
 /**
- * @brief  Feeds the data into the digital signature algorithm.
+ * @brief  Initializes a signature context for HMAC.
+ *
+ * For verification, calculate message HMAC and compare with received MAC using
+ * yaca_memcmp().
+ *
+ * @param[out] ctx   Newly created context (must be freed with yaca_ctx_free()).
+ * @param[in]  algo  Digest algorithm that will be used.
+ * @param[in]  key   Symmetric key that will be used. Supported key types:
+ *                   - #YACA_KEY_TYPE_SYMMETRIC,
+ *                   - #YACA_KEY_TYPE_DES.
+ *
+ * @return 0 on success, negative on error.
+ * @see #yaca_key_type_e, #yaca_digest_algo_e, yaca_sign_update(),
+ *      yaca_sign_final(), yaca_memcmp()
+ */
+int yaca_sign_hmac_init(yaca_ctx_h *ctx,
+                        yaca_digest_algo_e algo,
+                        const yaca_key_h key);
+
+/**
+ * @brief  Initializes a signature context for CMAC.
  *
- * @param[in,out] ctx       Context created by yaca_sign_init().
+ * For verification, calculate message CMAC and compare with received MAC using
+ * yaca_memcmp().
+ *
+ * @param[out] ctx   Newly created context (must be freed with yaca_ctx_free()).
+ * @param[in]  algo  Encryption algorithm that will be used.
+ * @param[in]  key   Symmetric key that will be used. Supported key types:
+ *                   - #YACA_KEY_TYPE_SYMMETRIC,
+ *                   - #YACA_KEY_TYPE_DES.
+ *
+ * @return 0 on success, negative on error.
+ * @see #yaca_key_type_e, #yaca_enc_algo_e, yaca_sign_update(),
+ *      yaca_sign_final(), yaca_memcmp()
+ */
+int yaca_sign_cmac_init(yaca_ctx_h *ctx,
+                        yaca_enc_algo_e algo,
+                        const yaca_key_h key);
+
+/**
+ * @brief  Feeds the data into the digital signature or MAC algorithm.
+ *
+ * @param[in,out] ctx       Context created by yaca_sign_init(),
+ *                          yaca_sign_hmac_init() or yaca_sign_cmac_init().
  * @param[in]     data      Data to be signed.
  * @param[in]     data_len  Length of the data.
  *
  * @return 0 on success, negative on error.
- * @see yaca_sign_init(), yaca_sign_final()
+ * @see yaca_sign_init(), yaca_sign_final(), yaca_sign_hmac_init(),
+ *      yaca_sign_cmac_init()
  */
 int yaca_sign_update(yaca_ctx_h ctx,
                      const char *data,
                      size_t data_len);
 
 /**
- * @brief  Calculates the final signature.
+ * @brief  Calculates the final signature or MAC.
  *
- * @param[in,out] ctx      A valid sign context.
- * @param[out]    mac      Buffer for the MAC or the signature (must be allocated by client, see
- *                         yaca_get_sign_length()).
- * @param[out]    mac_len  Length of the MAC or the signature, actual number of bytes written will be returned here.
+ * @param[in,out] ctx              A valid sign context.
+ * @param[out]    signature        Buffer for the MAC or the signature,
+ *                                 (must be allocated by client, see yaca_get_sign_length()).
+ * @param[out]    signature_len    Length of the MAC or the signature,
+ *                                 actual number of bytes written will be returned here.
  *
  * @return 0 on success, negative on error.
- * @see yaca_sign_init(), yaca_sign_update()
+ * @see yaca_sign_init(), yaca_sign_update(), yaca_sign_hmac_init(),
+ *      yaca_sign_cmac_init()
  */
 int yaca_sign_final(yaca_ctx_h ctx,
-                    char *mac,
-                    size_t *mac_len);
+                    char *signature,
+                    size_t *signature_len);
 
 /**
- * @brief  Initializes a signature verification context.
+ * @brief  Initializes a signature verification context for asymmetric signatures
  *
  * @param[out] ctx   Newly created context (must be freed with yaca_ctx_free()).
  * @param[in]  algo  Digest algorithm that will be used.
- * @param[in]  key   Private or symmetric key that will be used (algorithm is deduced based on key type).
+ * @param[in]  key   Public key that will be used. Algorithm is deduced based on
+ *                   key type. Supported key types:
+ *                   - #YACA_KEY_TYPE_RSA_PUB,
+ *                   - #YACA_KEY_TYPE_DSA_PUB,
+ *                   - #YACA_KEY_TYPE_ECDSA_PUB.
  *
  * @return 0 on success, negative on error.
- * @see #yaca_digest_algo_e, yaca_verify_update(), yaca_verify_final()
+ * @see #yaca_key_type_e, #yaca_digest_algo_e, yaca_verify_update(),
+ *      yaca_verify_final()
  */
 int yaca_verify_init(yaca_ctx_h *ctx,
                      yaca_digest_algo_e algo,
@@ -114,16 +172,17 @@ int yaca_verify_update(yaca_ctx_h ctx,
 /**
  * @brief  Performs the verification.
  *
- * @param[in,out] ctx      A valid verify context.
- * @param[in]     mac      Input MAC or signature (returned by yaca_sign_final()).
- * @param[in]     mac_len  Size of the MAC or the signature.
+ * @param[in,out] ctx            A valid verify context.
+ * @param[in]     signature      Input signature (returned by yaca_sign_final()).
+ * @param[in]     signature_len  Size of the signature.
  *
- * @return 0 on success, negative on error.
+ * @return 0 on success, YACA_ERROR_DATA_MISMATCH if verification fails,
+ *         negative on error.
  * @see yaca_verify_init(), yaca_verify_update()
  */
 int yaca_verify_final(yaca_ctx_h ctx,
-                      const char *mac,
-                      size_t mac_len);
+                      const char *signature,
+                      size_t signature_len);
 
 /**@}*/
 
index df5ba7d..bca42a8 100644 (file)
@@ -127,3 +127,11 @@ API int yaca_get_output_length(const yaca_ctx_h ctx, size_t input_len, size_t *o
 
        return ctx->get_output_length(ctx, input_len, output_len);
 }
+
+API int yaca_memcmp(const void *first, const void *second, size_t len)
+{
+       if (CRYPTO_memcmp(first, second, len) == 0)
+               return 0;
+
+       return YACA_ERROR_DATA_MISMATCH;
+}
index 9573c4c..e47c839 100644 (file)
@@ -356,17 +356,17 @@ API int yaca_sign_update(yaca_ctx_h ctx,
 }
 
 API int yaca_sign_final(yaca_ctx_h ctx,
-                       char *mac,
-                       size_t *mac_len)
+                       char *signature,
+                       size_t *signature_len)
 {
        struct yaca_sign_ctx_s *c = get_sign_ctx(ctx);
        int ret;
 
        if (c == NULL ||  c->op_type != OP_SIGN ||
-           mac == NULL || mac_len == NULL || *mac_len == 0)
+           signature == NULL || signature_len == NULL || *signature_len == 0)
                return YACA_ERROR_INVALID_ARGUMENT;
 
-       ret = EVP_DigestSignFinal(c->mdctx, (unsigned char *)mac, mac_len);
+       ret = EVP_DigestSignFinal(c->mdctx, (unsigned char *)signature, signature_len);
        if(ret != 1) {
                ret = YACA_ERROR_INTERNAL;
                ERROR_DUMP(ret);
@@ -499,15 +499,15 @@ API int yaca_verify_update(yaca_ctx_h ctx,
 }
 
 API int yaca_verify_final(yaca_ctx_h ctx,
-                         const char *mac,
-                         size_t mac_len)
+                          const char *signature,
+                          size_t signature_len)
 {
        struct yaca_sign_ctx_s *c = get_sign_ctx(ctx);
-       char mac_cmp[mac_len];
-       size_t mac_cmp_len = mac_len;
+       char mac_cmp[signature_len];
+       size_t mac_cmp_len = signature_len;
        int ret;
 
-       if (c == NULL || mac == NULL || mac_len == 0)
+       if (c == NULL || signature == NULL || signature_len == 0)
                return YACA_ERROR_INVALID_ARGUMENT;
 
        switch (c->op_type)
@@ -522,19 +522,19 @@ API int yaca_verify_final(yaca_ctx_h ctx,
                        return ret;
                }
 
-               if (mac_len != mac_cmp_len || CRYPTO_memcmp(mac, mac_cmp, mac_len) != 0)
-                       return YACA_ERROR_SIGNATURE_INVALID;
+               if (signature_len != mac_cmp_len || CRYPTO_memcmp(signature, mac_cmp, signature_len) != 0)
+                       return YACA_ERROR_DATA_MISMATCH;
 
                return 0;
        case OP_VERIFY_ASYMMETRIC:
                ret = EVP_DigestVerifyFinal(c->mdctx,
-                                           (unsigned char *)mac,
-                                           mac_len);
+                                           (unsigned char *)signature,
+                                           signature_len);
                if (ret == 1)
                        return 0;
 
                if (ret == 0)
-                       ret = YACA_ERROR_SIGNATURE_INVALID;
+                       ret = YACA_ERROR_DATA_MISMATCH;
                else
                        ret = YACA_ERROR_INTERNAL;