Skip to content

Commit 612f211

Browse files
authored
Merge pull request #783 from libtom/pr/der-misc-issues
various DER related fixes/improvements
2 parents a8ed78c + 209df8a commit 612f211

17 files changed

Lines changed: 70 additions & 21 deletions

‎src/headers/tomcrypt_private.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ struct bufp {
372372
char *start, *work, *end;
373373
};
374374

375-
#define SET_BUFP(n, d, l) n.start = (char*)d, n.work = (char*)d, n.end = (char*)d + l + 1
376-
#define UPDATE_BUFP(n, d, w, l) n.start = (char*)d, n.work = (char*)d + w, n.end = (char*)d + l + 1
375+
#define SET_BUFP(n, d, l) n.start = (char*)d, n.work = (char*)d, n.end = (char*)d + l
376+
#define UPDATE_BUFP(n, d, w, l) n.start = (char*)d, n.work = (char*)d + w, n.end = (char*)d + l
377377

378378
struct get_char;
379379
struct get_char_api {

‎src/misc/pem/pem_pkcs.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ static int s_import_pkcs8(unsigned char *asn1_cert, unsigned long asn1_len, ltc_
7373
{
7474
int err;
7575
enum ltc_oid_id oid_id;
76-
ltc_asn1_list *alg_id, *priv_key;
76+
ltc_asn1_list *alg_id = NULL, *priv_key = NULL;
7777
ltc_asn1_list *p8_asn1 = NULL;
7878
if ((err = pkcs8_decode_flexi(asn1_cert, asn1_len, pw_ctx, &p8_asn1)) != CRYPT_OK) {
7979
goto cleanup;

‎src/misc/pem/pem_read.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ static LTC_INLINE unsigned long s_bufp_alloc_len(struct bufp *buf)
2121
{
2222
if (buf->start == NULL || buf->end == NULL)
2323
return 0;
24-
return buf->end - buf->start - 1;
24+
return buf->end - buf->start;
2525
}
2626

2727
static LTC_INLINE unsigned long s_bufp_used_len(struct bufp *buf)

‎src/pk/asn1/der/custom_type/der_decode_custom_type.c‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,8 @@ int der_decode_custom_type_ex(const unsigned char *in, unsigned long inlen,
341341

342342
case LTC_ASN1_SETOF:
343343
case LTC_ASN1_SEQUENCE:
344-
/* detect if we have the right type */
345-
if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
344+
/* detect if we have the right type, the inlen test keeps in[x] inside the packet */
345+
if ((inlen == 0) || (type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
346346
err = CRYPT_INVALID_PACKET;
347347
goto LBL_ERR;
348348
}
@@ -390,6 +390,11 @@ int der_decode_custom_type_ex(const unsigned char *in, unsigned long inlen,
390390
err = CRYPT_INVALID_ARG;
391391
goto LBL_ERR;
392392
}
393+
/* z is the canonical length of the decoded value, not always the octets consumed; without this test inlen wraps and the next element is read OOB */
394+
if (z > inlen) {
395+
err = CRYPT_INVALID_PACKET;
396+
goto LBL_ERR;
397+
}
393398
x += z;
394399
inlen -= z;
395400
list[i].used = 1;

‎src/pk/asn1/der/generalizedtime/der_decode_generalizedtime.c‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ static LTC_INLINE int s_char_to_int(unsigned char x)
3131
#endif
3232

3333
#define DECODE_V(y, max) do {\
34+
if (x + 2 > declen) return CRYPT_INVALID_PACKET; \
3435
y = s_char_to_int(buf[x])*10 + s_char_to_int(buf[x+1]); \
3536
if (y >= max) return CRYPT_INVALID_PACKET; \
3637
x += 2; \
3738
} while(0)
3839

3940
#define DECODE_V4(y, max) do {\
41+
if (x + 4 > declen) return CRYPT_INVALID_PACKET; \
4042
y = s_char_to_int(buf[x])*1000 + s_char_to_int(buf[x+1])*100 + s_char_to_int(buf[x+2])*10 + s_char_to_int(buf[x+3]); \
4143
if (y >= max) return CRYPT_INVALID_PACKET; \
4244
x += 4; \
@@ -52,8 +54,8 @@ static LTC_INLINE int s_char_to_int(unsigned char x)
5254
int der_decode_generalizedtime(const unsigned char *in, unsigned long *inlen,
5355
ltc_generalizedtime *out)
5456
{
55-
unsigned char buf[32];
56-
unsigned long x;
57+
unsigned char buf[32] = { 0 }; /* initialize as all zeroes */
58+
unsigned long x, declen;
5759
int y;
5860

5961
LTC_ARGCHK(in != NULL);
@@ -78,9 +80,10 @@ int der_decode_generalizedtime(const unsigned char *in, unsigned long *inlen,
7880
}
7981
buf[x] = y;
8082
}
83+
declen = x; /* octets decoded into buf - the parsing below must not read past them */
8184
*inlen = 2 + x;
8285

83-
if (x < 15) {
86+
if (declen < 15) {
8487
return CRYPT_INVALID_PACKET;
8588
}
8689

@@ -107,14 +110,16 @@ YYYYMMDDhhmmss.fs-hh'mm'
107110
out->fs = 0;
108111

109112
/* now is it Z or . */
113+
if (x >= declen) {
114+
return CRYPT_INVALID_PACKET;
115+
}
110116
if (buf[x] == 'Z') {
111117
return CRYPT_OK;
112118
}
113119
if (buf[x] == '.') {
114120
x++;
115-
while (buf[x] >= '0' && buf[x] <= '9') {
121+
while (x < declen && buf[x] >= '0' && buf[x] <= '9') {
116122
unsigned fs = out->fs;
117-
if (x >= sizeof(buf)) return CRYPT_INVALID_PACKET;
118123
out->fs *= 10;
119124
out->fs += s_char_to_int(buf[x]);
120125
if (fs > out->fs) return CRYPT_OVERFLOW;
@@ -123,6 +128,9 @@ YYYYMMDDhhmmss.fs-hh'mm'
123128
}
124129

125130
/* now is it Z, +, - */
131+
if (x >= declen) {
132+
return CRYPT_INVALID_PACKET;
133+
}
126134
if (buf[x] == 'Z') {
127135
return CRYPT_OK;
128136
}

‎src/pk/asn1/der/integer/der_decode_integer.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num)
4343
}
4444
x += inlen;
4545

46+
/* an INTEGER holds at least one content octet, so in[x] below stays inside the packet */
47+
if (y == 0) {
48+
return CRYPT_INVALID_PACKET;
49+
}
50+
4651
if ((err = ltc_mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) {
4752
return err;
4853
}

‎src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ int der_flexi_sequence_cmp(const ltc_asn1_list *flexi, der_flexi_check *check)
4141
cur = cur->next;
4242
check++;
4343
}
44+
/* the loop above also ends when the decoded list runs out early; returning CRYPT_OK then would leave the caller's output pointers unassigned */
45+
while (check->t != LTC_ASN1_EOL) {
46+
if (!check->optional) {
47+
return CRYPT_INVALID_PACKET;
48+
}
49+
check++;
50+
}
4451
return CRYPT_OK;
4552
}
4653

‎src/pk/asn1/der/short_integer/der_decode_short_integer.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsig
4242
return CRYPT_INVALID_PACKET;
4343
}
4444

45+
/* an INTEGER holds at least one content octet */
46+
if (len == 0) {
47+
return CRYPT_INVALID_PACKET;
48+
}
49+
4550
if (len > sizeof(unsigned long)) {
4651
return CRYPT_OVERFLOW;
4752
}

‎src/pk/asn1/der/utctime/der_decode_utctime.c‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static LTC_INLINE int s_char_to_int(unsigned char x)
3030
#endif
3131

3232
#define DECODE_V(y, max) \
33+
if (x + 2 > declen) return CRYPT_INVALID_PACKET; \
3334
y = s_char_to_int(buf[x])*10 + s_char_to_int(buf[x+1]); \
3435
if (y >= max) return CRYPT_INVALID_PACKET; \
3536
x += 2;
@@ -45,7 +46,7 @@ int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
4546
ltc_utctime *out)
4647
{
4748
unsigned char buf[32] = { 0 }; /* initialize as all zeroes */
48-
unsigned long x;
49+
unsigned long x, declen;
4950
int y;
5051

5152
LTC_ARGCHK(in != NULL);
@@ -65,6 +66,7 @@ int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
6566
}
6667
buf[x] = y;
6768
}
69+
declen = x; /* octets decoded into buf - the parsing below must not read past them */
6870
*inlen = 2 + x;
6971

7072

@@ -90,6 +92,9 @@ YYMMDDhhmmss-hh'mm'
9092
out->off_dir = out->off_hh = out->off_mm = out->ss = 0;
9193

9294
/* now is it Z, +, - or 0-9 */
95+
if (x >= declen) {
96+
return CRYPT_INVALID_PACKET;
97+
}
9398
if (buf[x] == 'Z') {
9499
return CRYPT_OK;
95100
}
@@ -104,6 +109,9 @@ YYMMDDhhmmss-hh'mm'
104109
DECODE_V(out->ss, 60);
105110

106111
/* now is it Z, +, - */
112+
if (x >= declen) {
113+
return CRYPT_INVALID_PACKET;
114+
}
107115
if (buf[x] == 'Z') {
108116
return CRYPT_OK;
109117
}

‎src/pk/asn1/pkcs8/pkcs8_get.c‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@ int pkcs8_get_children(const ltc_asn1_list *decoded_list, enum ltc_oid_id *pka,
1414
int err;
1515
unsigned long n;
1616
der_flexi_check flexi_should[4];
17-
ltc_asn1_list *seq_l, *version;
17+
ltc_asn1_list *seq_l = NULL, *priv_l = NULL, *version = NULL;
1818

1919
LTC_ARGCHK(ltc_mp.name != NULL);
2020

2121
if (alg_id == NULL) alg_id = &seq_l;
22+
if (priv_key == NULL) priv_key = &priv_l;
23+
24+
/* der_flexi_sequence_cmp() writes only matched outputs, so unmatched ones stay NULL */
25+
*alg_id = NULL;
26+
*priv_key = NULL;
2227

2328
/* Setup for basic structure */
2429
n=0;
@@ -35,13 +40,19 @@ int pkcs8_get_children(const ltc_asn1_list *decoded_list, enum ltc_oid_id *pka,
3540
* we get an 'input too long' error but the rest is already decoded and can be
3641
* handled the same as for version 0
3742
*/
43+
if (version == NULL) {
44+
return CRYPT_INVALID_PACKET;
45+
}
3846
if (ltc_mp_cmp_d(version->data, 0) != LTC_MP_EQ && ltc_mp_cmp_d(version->data, 1) != LTC_MP_EQ) {
3947
return CRYPT_INVALID_PACKET;
4048
}
4149
break;
4250
default:
4351
return err;
4452
}
53+
if ((*alg_id == NULL) || ((*alg_id)->child == NULL) || (*priv_key == NULL)) {
54+
return CRYPT_INVALID_PACKET;
55+
}
4556
return pk_get_oid_from_asn1((*alg_id)->child, pka);
4657
}
4758

0 commit comments

Comments
 (0)