Mbed-TLS / mbedtls

An open source, portable, easy to use, readable and flexible TLS library, and reference implementation of the PSA Cryptography API. Releases are on a varying cadence, typically around 3 - 6 months between releases.
https://www.trustedfirmware.org/projects/mbed-tls/
Other
5.54k stars 2.6k forks source link

Support mbedtls_cipher_write/check_tag for CCM #8545

Open soloicesky opened 12 months ago

soloicesky commented 12 months ago

Suggested enhancement

GCM and CCM are both belongs to AEAD category, why we don't support write/check tag operation for CCM in cipher.c. see below code blocks: ···

if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)

int mbedtls_cipher_write_tag(mbedtls_cipher_context_t ctx, unsigned char tag, size_t tag_len) { if (ctx->cipher_info == NULL) { return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; }

if (MBEDTLS_ENCRYPT != ctx->operation) {
    return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}

if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_DEPRECATED_REMOVED)

if (ctx->psa_enabled == 1) {
    /* While PSA Crypto has an API for multipart
     * operations, we currently don't make it
     * accessible through the cipher layer. */
    return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
}

endif / MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_DEPRECATED_REMOVED /

if defined(MBEDTLS_GCM_C)

if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) {
    size_t output_length;
    /* The code here doesn't yet support alternative implementations
     * that can delay up to a block of output. */
    return mbedtls_gcm_finish((mbedtls_gcm_context *) ctx->cipher_ctx,
                              NULL, 0, &output_length,
                              tag, tag_len);
}

endif

if defined(MBEDTLS_CHACHAPOLY_C)

if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) {
    /* Don't allow truncated MAC for Poly1305 */
    if (tag_len != 16U) {
        return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
    }

    return mbedtls_chachapoly_finish(
        (mbedtls_chachapoly_context *) ctx->cipher_ctx, tag);
}

endif

return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;

}

int mbedtls_cipher_check_tag(mbedtls_cipher_context_t ctx, const unsigned char tag, size_t tag_len) { unsigned char check_tag[16]; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;

if (ctx->cipher_info == NULL) {
    return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}

if (MBEDTLS_DECRYPT != ctx->operation) {
    return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}

if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_DEPRECATED_REMOVED)

if (ctx->psa_enabled == 1) {
    /* While PSA Crypto has an API for multipart
     * operations, we currently don't make it
     * accessible through the cipher layer. */
    return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
}

endif / MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_DEPRECATED_REMOVED /

/* Status to return on a non-authenticated algorithm. */
ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;

if defined(MBEDTLS_GCM_C)

if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) {
    size_t output_length;
    /* The code here doesn't yet support alternative implementations
     * that can delay up to a block of output. */

    if (tag_len > sizeof(check_tag)) {
        return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
    }

    if (0 != (ret = mbedtls_gcm_finish(
                  (mbedtls_gcm_context *) ctx->cipher_ctx,
                  NULL, 0, &output_length,
                  check_tag, tag_len))) {
        return ret;
    }

    /* Check the tag in "constant-time" */
    if (mbedtls_ct_memcmp(tag, check_tag, tag_len) != 0) {
        ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
        goto exit;
    }
}

endif / MBEDTLS_GCM_C /

if defined(MBEDTLS_CHACHAPOLY_C)

if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) {
    /* Don't allow truncated MAC for Poly1305 */
    if (tag_len != sizeof(check_tag)) {
        return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
    }

    ret = mbedtls_chachapoly_finish(
        (mbedtls_chachapoly_context *) ctx->cipher_ctx, check_tag);
    if (ret != 0) {
        return ret;
    }

    /* Check the tag in "constant-time" */
    if (mbedtls_ct_memcmp(tag, check_tag, tag_len) != 0) {
        ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
        goto exit;
    }
}

endif / MBEDTLS_CHACHAPOLY_C /

exit: mbedtls_platform_zeroize(check_tag, tag_len); return ret; }

endif / MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C /

···

Justification

···

if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) || defined(MBEDTLS_CCM_C)

int mbedtls_cipher_write_tag(mbedtls_cipher_context_t ctx, unsigned char tag, size_t tag_len) { if (ctx->cipher_info == NULL) { return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; }

if (MBEDTLS_ENCRYPT != ctx->operation) {
    return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}

if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_DEPRECATED_REMOVED)

if (ctx->psa_enabled == 1) {
    /* While PSA Crypto has an API for multipart
     * operations, we currently don't make it
     * accessible through the cipher layer. */
    return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
}

endif / MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_DEPRECATED_REMOVED /

if defined(MBEDTLS_GCM_C)

if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) {
    size_t output_length;
    /* The code here doesn't yet support alternative implementations
     * that can delay up to a block of output. */
    return mbedtls_gcm_finish((mbedtls_gcm_context *) ctx->cipher_ctx,
                              NULL, 0, &output_length,
                              tag, tag_len);
}

endif

if defined(MBEDTLS_CCM_C)

if (MBEDTLS_MODE_CCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) {
    size_t output_length;
    /* The code here doesn't yet support alternative implementations
     * that can delay up to a block of output. */
    return mbedtls_ccm_finish((mbedtls_gcm_context *) ctx->cipher_ctx,
                              NULL, 0, &output_length,
                              tag, tag_len);
}

endif

if defined(MBEDTLS_CHACHAPOLY_C)

if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) {
    /* Don't allow truncated MAC for Poly1305 */
    if (tag_len != 16U) {
        return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
    }

    return mbedtls_chachapoly_finish(
        (mbedtls_chachapoly_context *) ctx->cipher_ctx, tag);
}

endif

return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;

}

int mbedtls_cipher_check_tag(mbedtls_cipher_context_t ctx, const unsigned char tag, size_t tag_len) { unsigned char check_tag[16]; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;

if (ctx->cipher_info == NULL) {
    return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}

if (MBEDTLS_DECRYPT != ctx->operation) {
    return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}

if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_DEPRECATED_REMOVED)

if (ctx->psa_enabled == 1) {
    /* While PSA Crypto has an API for multipart
     * operations, we currently don't make it
     * accessible through the cipher layer. */
    return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
}

endif / MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_DEPRECATED_REMOVED /

/* Status to return on a non-authenticated algorithm. */
ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;

if defined(MBEDTLS_GCM_C)

if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) {
    size_t output_length;
    /* The code here doesn't yet support alternative implementations
     * that can delay up to a block of output. */

    if (tag_len > sizeof(check_tag)) {
        return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
    }

    if (0 != (ret = mbedtls_gcm_finish(
                  (mbedtls_gcm_context *) ctx->cipher_ctx,
                  NULL, 0, &output_length,
                  check_tag, tag_len))) {
        return ret;
    }

    /* Check the tag in "constant-time" */
    if (mbedtls_ct_memcmp(tag, check_tag, tag_len) != 0) {
        ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
        goto exit;
    }
}

endif / MBEDTLS_GCM_C /

if defined(MBEDTLS_GCM_C)

if (MBEDTLS_MODE_GCM == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) {
    size_t output_length;
    /* The code here doesn't yet support alternative implementations
     * that can delay up to a block of output. */
    return mbedtls_gcm_finish((mbedtls_gcm_context *) ctx->cipher_ctx,
                              NULL, 0, &output_length,
                              tag, tag_len);
}

endif

if defined(MBEDTLS_CHACHAPOLY_C)

if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ((mbedtls_cipher_type_t) ctx->cipher_info->type)) {
    /* Don't allow truncated MAC for Poly1305 */
    if (tag_len != sizeof(check_tag)) {
        return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
    }

    ret = mbedtls_chachapoly_finish(
        (mbedtls_chachapoly_context *) ctx->cipher_ctx, check_tag);
    if (ret != 0) {
        return ret;
    }

    /* Check the tag in "constant-time" */
    if (mbedtls_ct_memcmp(tag, check_tag, tag_len) != 0) {
        ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
        goto exit;
    }
}

endif / MBEDTLS_CHACHAPOLY_C /

exit: mbedtls_platform_zeroize(check_tag, tag_len); return ret; }

endif / MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C || MBEDTLS_CCM_C /

···

Mbed TLS needs this because CCM is the same kind as GCM.

gilles-peskine-arm commented 11 months ago

The cipher module does not support multipart operation with CCM. This is a bit unfortunate. But at this point, cipher.h is a deprecated API. Please use the PSA API instead for multipart CCM.

Due to limited bandwidth, we are not going to implement multipart CCM in cipher.h. If you can make a pull request with passing tests before the 3.6 LTS release in February or March 2024, we'll try to review it, but I can't promise even that. After that, there will be no new features in cipher.h.

soloicesky commented 11 months ago

您好,你的邮件已收到,我会尽快回复你。                               best regards                                      zaixing_liu