New vulnerabilities found in mbed TLS

mbedtls_mpi_mod_exp gives wrong result for negative parameters

Reported privately to ARM on December 16th 2016.

#include <mbedtls/bignum.h>
#include <openssl/bn.h>
#include <stddef.h>
#include <stdio.h>

#define NUMSTR1 "-1"
#define NUMSTR2 "0"
#define NUMSTR3 "55555"

void mod_exp_openssl(void)
{
    BIGNUM *A = NULL, *B = NULL, *C = NULL, *D = NULL;
    BN_CTX *ctx = NULL;
    char* str;

    if ( (ctx = BN_CTX_new()) == NULL ) {
        goto end;
    }

    A = BN_new();
    B = BN_new();
    C = BN_new();

    if ( BN_dec2bn(&B, NUMSTR1) == 0 ) {
        goto end;
    }

    if ( BN_dec2bn(&C, NUMSTR2) == 0 ) {
        goto end;
    }

    if ( BN_dec2bn(&D, NUMSTR3) == 0 ) {
        goto end;
    }

    if ( BN_mod_exp(A, B, C, D, ctx) == 0 ) {
        goto end;
    }

    str = BN_bn2dec(A);
    printf("openssl mod exp result %s\n", str);

    OPENSSL_free(str);

end:
    BN_free(A);
    BN_free(B);
    BN_free(C);

    BN_CTX_free(ctx);
}

void mod_exp_mbedtls(void)
{
    char buf[1024];
    size_t olen;
    mbedtls_mpi A, B, C, D;

    mbedtls_mpi_init(&A);
    mbedtls_mpi_init(&B);
    mbedtls_mpi_init(&C);
    mbedtls_mpi_init(&D);

    if ( mbedtls_mpi_read_string(&B, 10, NUMSTR1) != 0 ) {
        goto end;
    }
    if ( mbedtls_mpi_read_string(&C, 10, NUMSTR2) != 0 ) {
        goto end;
    }
    if ( mbedtls_mpi_read_string(&D, 10, NUMSTR3) != 0 ) {
        goto end;
    }

    if ( mbedtls_mpi_exp_mod(&A, &B, &C, &D, NULL) != 0 ) {
        goto end;
    }

    if ( mbedtls_mpi_write_string(&A, 10, buf, sizeof(buf), &olen) != 0 ) {
        goto end;
    }

    printf("mbedtls mod exp result: %s\n", buf);

end:
    mbedtls_mpi_free(&A);
    mbedtls_mpi_free(&B);
    mbedtls_mpi_free(&C);
}

int main(void)
{
    mod_exp_openssl();
    mod_exp_mbedtls();
    return 0;
}

See also: Wolfram Alpha

As far as I could verify, the library’s internal cryptographic function do not operate on negative numbers and are thus unlikely to be vulnerable. Software that calls this function directly might produce unintended behavior as a result of this bug.

mbedtls_mpi_gcd gives wrong result for negative parameters

Reported privately to ARM on December 22th 2016.

#include <mbedtls/bignum.h>
#include <openssl/bn.h>
#include <stddef.h>
#include <stdio.h>

#define NUMSTR1 "-1"
#define NUMSTR2 "0"

void gcd_openssl(void)
{
    BIGNUM *A = NULL, *B = NULL, *C = NULL;
    BN_CTX *ctx = NULL;
    char* str;

    if ( (ctx = BN_CTX_new()) == NULL ) {
        goto end;
    }

    A = BN_new();
    B = BN_new();
    C = BN_new();

    if ( BN_dec2bn(&B, NUMSTR1) == 0 ) {
        goto end;
    }

    if ( BN_dec2bn(&C, NUMSTR2) == 0 ) {
        goto end;
    }

    if ( BN_gcd(A, B, C, ctx) == 0 ) {
        goto end;
    }

    str = BN_bn2dec(A);
    printf("openssl gcd result %s\n", str);

    OPENSSL_free(str);
end:
    BN_free(A);
    BN_free(B);
    BN_free(C);

    BN_CTX_free(ctx);
}

void gcd_mbedtls(void)
{
    char buf[1024];
    size_t olen;
    mbedtls_mpi A, B, C;

    mbedtls_mpi_init(&A);
    mbedtls_mpi_init(&B);
    mbedtls_mpi_init(&C);

    if ( mbedtls_mpi_read_string(&B, 10, NUMSTR1) != 0 ) {
        goto end;
    }
    if ( mbedtls_mpi_read_string(&C, 10, NUMSTR2) != 0 ) {
        goto end;
    }

    if ( mbedtls_mpi_gcd(&A, &B, &C) != 0 ) {
        goto end;
    }

    if ( mbedtls_mpi_write_string(&A, 10, buf, sizeof(buf), &olen) != 0 ) {
        goto end;
    }

    printf("mbedtls gcd result: %s\n", buf);

end:
    mbedtls_mpi_free(&A);
    mbedtls_mpi_free(&B);
    mbedtls_mpi_free(&C);
}

int main(void)
{
    gcd_openssl();
    gcd_mbedtls();
    return 0;
}

See also: Wolfram Alpha

As far as I could verify, the library’s internal cryptographic function do not operate on negative numbers and are thus unlikely to be vulnerable. Software that calls this function directly might produce unintended behavior as a result of this bug.

Memory corruption in mbedtls_mpi_read_file

Reported privately to ARM on January 18th 2017.

604 char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
605
606 memset( s, 0, sizeof( s ) );
607 if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
608 return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
609
610 slen = strlen( s );
611 if( slen == sizeof( s ) - 2 )
612 return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
613
614 if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
615 if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }

Proof of concept:

#include <mbedtls/bignum.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    mbedtls_mpi X;

    mbedtls_mpi_init(&X);
    mbedtls_mpi_read_file(&X, 16, stdin);
    mbedtls_mpi_free(&X);
    return 0;
}

ASAN will be triggered if you do:

echo -en '\x00' | ./a.out

If the byte preceding the ‘s’ buffer happens to be 0x0A, stack memory corruption occurs. And if the byte before that is 0x0D, it happens again.

Not exploitable remotely (unless application software uses this function to load data from an untrusted file)

Memory corruption in mbedtls_mpi_write_string

Reported privately to ARM on January 5th 2017.

Proof of concept:

#include <mbedtls/bignum.h>
#include <stdlib.h>
#define NUMSTR1 "-066666666666666666666000000000000000000000000000000000000000000000000077771111111111111000009000000000000000"
int main(void)
{
    mbedtls_mpi A;
    char* buf;
    size_t olen;
    mbedtls_mpi_init(&A);
    if ( mbedtls_mpi_read_string(&A, 16, NUMSTR1) != 0 ) {
        return -1;
    }
    if ( mbedtls_mpi_write_string(&A, 16, NULL, 0, &olen) != MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ) {
        return -1;
    }
    buf = malloc(olen);
    if ( mbedtls_mpi_write_string(&A, 16, buf, olen, &olen) != 0 ) {
        return -1;
    }
    free(buf);
    mbedtls_mpi_free(&A);
    return 0;
}

Typically not exploitable remotely.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.