Skip to content

Commit 5efe294

Browse files
Earle F. Philhower, IIIigrr
authored andcommitted
Apply CVE fixes for X509 parsing
Apply patches developed by Sze Yiu which correct a vulnerability in X509 parsing. See CVE-2018-16150 and CVE-2018-16149 for more info.
1 parent e634adf commit 5efe294

File tree

2 files changed

+76
-38
lines changed

2 files changed

+76
-38
lines changed

ssl/os_port.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@ static inline int strlen_P(const char *str) {
142142
while (pgm_read_byte(str++)) cnt++;
143143
return cnt;
144144
}
145+
static inline int memcmp_P(const void *a1, const void *b1, size_t len) {
146+
const uint8_t* a = (const uint8_t*)(a1);
147+
uint8_t* b = (uint8_t*)(b1);
148+
for (size_t i=0; i<len; i++) {
149+
uint8_t d = pgm_read_byte(a) - pgm_read_byte(b);
150+
if (d) return d;
151+
a++;
152+
b++;
153+
}
154+
return 0;
155+
}
156+
145157
#define printf(fmt, ...) do { static const char fstr[] PROGMEM = fmt; char rstr[sizeof(fmt)]; memcpy_P(rstr, fstr, sizeof(rstr)); ets_printf(rstr, ##__VA_ARGS__); } while (0)
146158
#define strcpy_P(dst, src) do { static const char fstr[] PROGMEM = src; memcpy_P(dst, fstr, sizeof(src)); } while (0)
147159

ssl/x509.c

Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,6 @@ static int x509_v3_basic_constraints(const uint8_t *cert, int offset,
4949
X509_CTX *x509_ctx);
5050
static int x509_v3_key_usage(const uint8_t *cert, int offset,
5151
X509_CTX *x509_ctx);
52-
53-
/**
54-
* Retrieve the signature from a certificate.
55-
*/
56-
static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
57-
{
58-
int offset = 0;
59-
const uint8_t *ptr = NULL;
60-
61-
if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
62-
asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
63-
goto end_get_sig;
64-
65-
if (asn1_sig[offset++] != ASN1_OCTET_STRING)
66-
goto end_get_sig;
67-
*len = get_asn1_length(asn1_sig, &offset);
68-
ptr = &asn1_sig[offset]; /* all ok */
69-
70-
end_get_sig:
71-
return ptr;
72-
}
73-
7452
#endif
7553

7654
/**
@@ -412,17 +390,56 @@ void x509_free(X509_CTX *x509_ctx)
412390
}
413391

414392
#ifdef CONFIG_SSL_CERT_VERIFICATION
393+
static const uint8_t sig_prefix_md5[] PROGMEM = {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10};
394+
static const uint8_t sig_prefix_sha1[] PROGMEM = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
395+
static const uint8_t sig_prefix_sha256[] PROGMEM = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
396+
static const uint8_t sig_prefix_sha384[] PROGMEM = {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30};
397+
static const uint8_t sig_prefix_sha512[] PROGMEM = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
398+
415399
/**
416400
* Take a signature and decrypt it.
417401
*/
418-
static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
402+
static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, uint8_t sig_type,
419403
bigint *modulus, bigint *pub_exp)
420404
{
421-
int i, size;
405+
int i;
422406
bigint *decrypted_bi, *dat_bi;
423407
bigint *bir = NULL;
424408
uint8_t *block = (uint8_t *)malloc(sig_len);
425409

410+
const uint8_t *sig_prefix = NULL;
411+
uint8_t sig_prefix_size = 0, hash_len = 0;
412+
/* adjust our expections */
413+
switch (sig_type)
414+
{
415+
case SIG_TYPE_MD5:
416+
sig_prefix = sig_prefix_md5;
417+
sig_prefix_size = sizeof(sig_prefix_md5);
418+
break;
419+
case SIG_TYPE_SHA1:
420+
sig_prefix = sig_prefix_sha1;
421+
sig_prefix_size = sizeof(sig_prefix_sha1);
422+
break;
423+
case SIG_TYPE_SHA256:
424+
sig_prefix = sig_prefix_sha256;
425+
sig_prefix_size = sizeof(sig_prefix_sha256);
426+
break;
427+
case SIG_TYPE_SHA384:
428+
sig_prefix = sig_prefix_sha384;
429+
sig_prefix_size = sizeof(sig_prefix_sha384);
430+
break;
431+
case SIG_TYPE_SHA512:
432+
sig_prefix = sig_prefix_sha512;
433+
sig_prefix_size = sizeof(sig_prefix_sha512);
434+
break;
435+
}
436+
if (sig_prefix)
437+
hash_len = sig_prefix[sig_prefix_size - 1];
438+
439+
/* check length (#A) */
440+
if (sig_len < 2 + 8 + 1 + sig_prefix_size + hash_len)
441+
goto err;
442+
426443
/* decrypt */
427444
dat_bi = bi_import(ctx, sig, sig_len);
428445
ctx->mod_offset = BIGINT_M_OFFSET;
@@ -433,21 +450,30 @@ static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
433450
bi_export(ctx, decrypted_bi, block, sig_len);
434451
ctx->mod_offset = BIGINT_M_OFFSET;
435452

436-
i = 10; /* start at the first possible non-padded byte */
437-
while (block[i++] && i < sig_len);
438-
size = sig_len - i;
439-
440-
/* get only the bit we want */
441-
if (size > 0)
442-
{
443-
int len;
444-
const uint8_t *sig_ptr = get_signature(&block[i], &len);
453+
/* check the first 2 bytes */
454+
if (block[0] != 0 || block[1] != 1)
455+
goto err;
445456

446-
if (sig_ptr)
447-
{
448-
bir = bi_import(ctx, sig_ptr, len);
449-
}
457+
/* check the padding */
458+
i = 2; /* start at the first padding byte */
459+
while (i < sig_len - 1 - sig_prefix_size - hash_len)
460+
{ /* together with (#A), we require at least 8 bytes of padding */
461+
if (block[i++] != 0xFF)
462+
goto err;
450463
}
464+
465+
/* check end of padding */
466+
if (block[i++] != 0)
467+
goto err;
468+
469+
/* check the ASN.1 metadata */
470+
if (memcmp_P(block+i, sig_prefix, sig_prefix_size))
471+
goto err;
472+
473+
/* now we can get the hash we need */
474+
bir = bi_import(ctx, block + i + sig_prefix_size, hash_len);
475+
476+
err:
451477
free(block);
452478
/* save a few bytes of memory */
453479
bi_clear_cache(ctx);
@@ -600,7 +626,7 @@ int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert,
600626
}
601627

602628
/* check the signature */
603-
cert_sig = sig_verify(ctx, cert->signature, cert->sig_len,
629+
cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, cert->sig_type,
604630
bi_clone(ctx, mod), bi_clone(ctx, expn));
605631

606632
if (cert_sig && cert->digest)

0 commit comments

Comments
 (0)