|
| 1 | +/* |
| 2 | + * This file is part of the MicroPython project, http://micropython.org/ |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + * |
| 6 | + * Copyright The Mbed TLS Contributors |
| 7 | + * Copyright (c) 2024 Damien P. George |
| 8 | + * |
| 9 | + * This file provides default fallback functions for use with alternate |
| 10 | + * cryptography functions implemented in Python. |
| 11 | + */ |
| 12 | +#if MICROPY_PY_SSL_ECDSA_SIGN_ALT |
| 13 | +#if defined(MBEDTLS_ECP_RESTARTABLE) || defined(MBEDTLS_ECDSA_DETERMINISTIC) |
| 14 | +#error "MICROPY_PY_SSL_ECDSA_SIGN_ALT cannot be used with MBEDTLS_ECP_RESTARTABLE or MBEDTLS_ECDSA_DETERMINISTIC" |
| 15 | +#endif |
| 16 | + |
| 17 | +#include <string.h> |
| 18 | +#define MBEDTLS_ALLOW_PRIVATE_ACCESS |
| 19 | +#include "mbedtls/platform.h" |
| 20 | +#include "mbedtls/ssl.h" |
| 21 | +#include "mbedtls/error.h" |
| 22 | +#include "mbedtls/ecdsa.h" |
| 23 | +#include "mbedtls/asn1write.h" |
| 24 | + |
| 25 | +extern int micropy_mbedtls_ecdsa_sign_alt(const mbedtls_mpi *d, const unsigned char *hash, size_t hlen, |
| 26 | + unsigned char *sig, size_t sig_size, size_t *slen); |
| 27 | + |
| 28 | + |
| 29 | +// Compute and write signature |
| 30 | +// See lib/mbedtls/library/ecdsa.c:688 |
| 31 | +// |
| 32 | +// Note: To avoid duplicating a lot of code, MBEDTLS_ECDSA_SIGN_ALT is not defined, |
| 33 | +// which allows the default mbedtls_ecdsa_sign to be used as a fallback function. |
| 34 | +// However, mbedtls_ecdsa_sign cannot be wrapped because it is called internally |
| 35 | +// within its object file, so we wrap mbedtls_ecdsa_read/write_signature instead. |
| 36 | +int __wrap_mbedtls_ecdsa_write_signature(mbedtls_ecdsa_context *ctx, |
| 37 | + mbedtls_md_type_t md_alg, |
| 38 | + const unsigned char *hash, size_t hlen, |
| 39 | + unsigned char *sig, size_t sig_size, size_t *slen, |
| 40 | + int (*f_rng)(void *, unsigned char *, size_t), |
| 41 | + void *p_rng) { |
| 42 | + |
| 43 | + (void)md_alg; |
| 44 | + |
| 45 | + if (f_rng == NULL) { |
| 46 | + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; |
| 47 | + } |
| 48 | + |
| 49 | + // Check if curve is supported for ECDSA. |
| 50 | + if (!mbedtls_ecdsa_can_do(ctx->grp.id) || ctx->grp.N.p == NULL) { |
| 51 | + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; |
| 52 | + } |
| 53 | + |
| 54 | + // Try signing with the alternative function first. |
| 55 | + int ret = micropy_mbedtls_ecdsa_sign_alt(&ctx->d, hash, hlen, sig, sig_size, slen); |
| 56 | + |
| 57 | + // Fallback to the default mbedtls implementation if needed. |
| 58 | + if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED) { |
| 59 | + mbedtls_mpi r, s; |
| 60 | + mbedtls_mpi_init(&r); |
| 61 | + mbedtls_mpi_init(&s); |
| 62 | + |
| 63 | + size_t len = 0; |
| 64 | + unsigned char buf[MBEDTLS_ECDSA_MAX_LEN] = { 0 }; |
| 65 | + unsigned char *p = buf + sizeof(buf); |
| 66 | + |
| 67 | + MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign(&ctx->grp, &r, &s, &ctx->d, hash, hlen, f_rng, p_rng)); |
| 68 | + MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_mpi(&p, buf, &s)); |
| 69 | + MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_mpi(&p, buf, &r)); |
| 70 | + MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&p, buf, len)); |
| 71 | + MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&p, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); |
| 72 | + |
| 73 | + if (len > sig_size) { |
| 74 | + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; |
| 75 | + } else { |
| 76 | + ret = 0; |
| 77 | + *slen = len; |
| 78 | + memcpy(sig, p, len); |
| 79 | + } |
| 80 | + |
| 81 | + cleanup: |
| 82 | + mbedtls_mpi_free(&r); |
| 83 | + mbedtls_mpi_free(&s); |
| 84 | + } |
| 85 | + |
| 86 | + return ret; |
| 87 | +} |
| 88 | +#endif |
0 commit comments