Skip to content

Commit 6ae30f2

Browse files
committed
Put realloc logic into pem_read()
Signed-off-by: Steffen Jaeckel <[email protected]>
1 parent def00a6 commit 6ae30f2

File tree

5 files changed

+182
-107
lines changed

5 files changed

+182
-107
lines changed

src/headers/tomcrypt_private.h

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -382,19 +382,41 @@ struct bufp {
382382
};
383383

384384
#define SET_BUFP(n, d, l) n.start = (char*)d, n.work = (char*)d, n.end = (char*)d + l + 1
385+
#define UPDATE_BUFP(n, d, w, l) n.start = (char*)d, n.work = (char*)d + w, n.end = (char*)d + l + 1
385386

386-
struct get_char {
387+
struct get_char;
388+
struct get_char_api {
387389
int (*get)(struct get_char*);
390+
int (*reset)(struct get_char*);
391+
unsigned long (*len)(struct get_char*);
392+
};
393+
394+
struct get_char {
395+
struct get_char_api api;
388396
union {
389397
#ifndef LTC_NO_FILE
390-
FILE *f;
398+
struct {
399+
FILE *f;
400+
long original_pos;
401+
} f;
391402
#endif /* LTC_NO_FILE */
392403
struct bufp buf;
393404
} data;
394405
struct str unget_buf;
395406
char unget_buf_[LTC_PEM_DECODE_BUFSZ];
396407
int prev_get;
397408
};
409+
410+
#define pem_get_char_init(b, l) { \
411+
.api = get_char_buffer_api, \
412+
SET_BUFP(.data.buf, (b), (l)) \
413+
}
414+
415+
#define pem_get_char_init_filehandle(fi) { \
416+
.api = get_char_filehandle_api, \
417+
.data.f.f = (fi), \
418+
.data.f.original_pos = ftell(fi) \
419+
}
398420
#endif
399421

400422
/* others */
@@ -417,10 +439,10 @@ int pem_decrypt(unsigned char *data, unsigned long *datalen,
417439
const struct blockcipher_info *info,
418440
enum padding_type padding);
419441
#ifndef LTC_NO_FILE
420-
int pem_get_char_from_file(struct get_char *g);
442+
extern const struct get_char_api get_char_filehandle_api;
421443
#endif /* LTC_NO_FILE */
422-
int pem_get_char_from_buf(struct get_char *g);
423-
int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g);
444+
extern const struct get_char_api get_char_buffer_api;
445+
int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g);
424446
#endif
425447

426448
/* tomcrypt_pk.h */
@@ -709,7 +731,7 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i
709731

710732
int x509_get_pka(const ltc_asn1_list *pub, enum ltc_pka_id *pka);
711733
int x509_get_sig_alg(const ltc_asn1_list *pub, ltc_x509_signature_algorithm *sig_alg);
712-
int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root);
734+
int x509_import_spki(const unsigned char *buf, unsigned long len, ltc_pka_key *k, ltc_asn1_list **root);
713735
int x509_get_extensions(const ltc_asn1_list *seq, ltc_x509_extensions *extensions);
714736
void x509_free_extensions(const ltc_x509_extensions *extensions);
715737
int x509_get_serial(const ltc_asn1_list *asn1, ltc_x509_string *serial);

src/misc/pem/pem_pkcs.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,21 +127,16 @@ static const import_fn s_import_openssl_fns[LTC_PKA_NUM] = {
127127
static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
128128
{
129129
unsigned char *asn1_cert = NULL;
130-
unsigned long w, asn1_len, n;
130+
unsigned long w = 0, asn1_len, n;
131131
int err = CRYPT_ERROR;
132132
struct pem_headers hdr = { 0 };
133133
struct password pw = { 0 };
134134
enum ltc_pka_id pka;
135135
XMEMSET(k, 0, sizeof(*k));
136-
w = LTC_PEM_READ_BUFSIZE * 2;
137-
retry:
138-
asn1_cert = XREALLOC(asn1_cert, w);
139136
for (n = 0; n < pem_std_headers_num; ++n) {
140137
hdr.id = &pem_std_headers[n];
141-
err = pem_read(asn1_cert, &w, &hdr, g);
142-
if (err == CRYPT_BUFFER_OVERFLOW) {
143-
goto retry;
144-
} else if (err == CRYPT_OK) {
138+
err = pem_read((void**)&asn1_cert, &w, &hdr, g);
139+
if (err == CRYPT_OK) {
145140
break;
146141
} else if (err != CRYPT_UNKNOWN_PEM) {
147142
goto cleanup;
@@ -204,7 +199,7 @@ int pem_decode_pkcs_filehandle(FILE *f, ltc_pka_key *k, const password_ctx *pw_c
204199
LTC_ARGCHK(f != NULL);
205200
LTC_ARGCHK(k != NULL);
206201
{
207-
struct get_char g = { .get = pem_get_char_from_file, .data.f = f };
202+
struct get_char g = pem_get_char_init_filehandle(f);
208203
return s_decode(&g, k, pw_ctx);
209204
}
210205
}
@@ -216,7 +211,7 @@ int pem_decode_pkcs(const void *buf, unsigned long len, ltc_pka_key *k, const pa
216211
LTC_ARGCHK(len != 0);
217212
LTC_ARGCHK(k != NULL);
218213
{
219-
struct get_char g = { .get = pem_get_char_from_buf, SET_BUFP(.data.buf, buf, len) };
214+
struct get_char g = pem_get_char_init(buf, len);
220215
return s_decode(&g, k, pw_ctx);
221216
}
222217
}

src/misc/pem/pem_read.c

Lines changed: 135 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,98 @@ extern const struct str pem_dek_info_start;
1717
extern const struct blockcipher_info pem_dek_infos[];
1818
extern const unsigned long pem_dek_infos_num;
1919

20+
static LTC_INLINE unsigned long s_bufp_alloc_len(struct bufp *buf)
21+
{
22+
if (buf->start == NULL || buf->end == NULL)
23+
return 0;
24+
return buf->end - buf->start - 1;
25+
}
26+
27+
static LTC_INLINE unsigned long s_bufp_used_len(struct bufp *buf)
28+
{
29+
if (buf->start == NULL || buf->end == NULL)
30+
return 0;
31+
return buf->work - buf->start;
32+
}
33+
34+
static LTC_INLINE int s_bufp_grow(struct bufp *buf)
35+
{
36+
int err = CRYPT_OK;
37+
void *ret;
38+
unsigned long alloc_len = s_bufp_alloc_len(buf), realloc_len;
39+
unsigned long work_offset = s_bufp_used_len(buf);
40+
if (alloc_len == 0)
41+
realloc_len = LTC_PEM_READ_BUFSIZE;
42+
else
43+
realloc_len = alloc_len * 2;
44+
if (realloc_len < alloc_len)
45+
return CRYPT_OVERFLOW;
46+
ret = XREALLOC(buf->start, realloc_len);
47+
if (ret == NULL) {
48+
err = CRYPT_MEM;
49+
} else {
50+
UPDATE_BUFP((*buf), ret, work_offset, realloc_len);
51+
}
52+
return err;
53+
}
54+
55+
static LTC_INLINE int s_bufp_fits(struct bufp *buf, unsigned long to_write)
56+
{
57+
char *d = buf->work;
58+
char *e = buf->end;
59+
char *w = d + to_write;
60+
if (d == NULL || w < d || w > e)
61+
return 0;
62+
return 1;
63+
}
64+
65+
static LTC_INLINE int s_bufp_add(struct bufp *buf, const void *src, unsigned long len)
66+
{
67+
int err;
68+
if (!s_bufp_fits(buf, len)) {
69+
if ((err = s_bufp_grow(buf)) != CRYPT_OK) {
70+
return err;
71+
}
72+
}
73+
XMEMCPY(buf->work, src, len);
74+
buf->work += len;
75+
return CRYPT_OK;
76+
}
77+
2078
#ifndef LTC_NO_FILE
21-
int pem_get_char_from_file(struct get_char *g)
79+
static int s_pem_get_char_from_file(struct get_char *g)
80+
{
81+
return getc(g->data.f.f);
82+
}
83+
84+
static int s_pem_get_char_reset_file(struct get_char *g)
2285
{
23-
return getc(g->data.f);
86+
if (g->data.f.original_pos == -1)
87+
return -1;
88+
return fseek(g->data.f.f, g->data.f.original_pos, SEEK_SET);
2489
}
90+
91+
static unsigned long s_pem_get_char_len_file(struct get_char *g)
92+
{
93+
FILE *f = g->data.f.f;
94+
long len, cur_pos = ftell(f);
95+
if (cur_pos != -1) {
96+
fseek(f, 0, SEEK_END);
97+
len = ftell(f);
98+
fseek(f, cur_pos, SEEK_SET);
99+
return len - cur_pos;
100+
}
101+
return LTC_PEM_READ_BUFSIZE * 2;
102+
}
103+
104+
const struct get_char_api get_char_filehandle_api = {
105+
.get = s_pem_get_char_from_file,
106+
.reset = s_pem_get_char_reset_file,
107+
.len = s_pem_get_char_len_file,
108+
};
25109
#endif /* LTC_NO_FILE */
26110

27-
int pem_get_char_from_buf(struct get_char *g)
111+
static int s_pem_get_char_from_buf(struct get_char *g)
28112
{
29113
int ret;
30114
if (g->data.buf.work == g->data.buf.end) {
@@ -35,6 +119,25 @@ int pem_get_char_from_buf(struct get_char *g)
35119
return ret;
36120
}
37121

122+
static int s_pem_get_char_reset(struct get_char *g)
123+
{
124+
g->data.buf.work = g->data.buf.start;
125+
return 0;
126+
}
127+
128+
129+
130+
static unsigned long s_pem_get_char_len(struct get_char *g)
131+
{
132+
return s_bufp_alloc_len(&g->data.buf);
133+
}
134+
135+
const struct get_char_api get_char_buffer_api = {
136+
.get = s_pem_get_char_from_buf,
137+
.reset = s_pem_get_char_reset,
138+
.len = s_pem_get_char_len,
139+
};
140+
38141
static void s_unget_line(char *buf, unsigned long buflen, struct get_char *g)
39142
{
40143
if (buflen > sizeof(g->unget_buf_))
@@ -81,7 +184,7 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g,
81184
while(blen < *buflen || search_for_start) {
82185
wr = blen < *buflen ? blen : *buflen - 1;
83186
c_ = g->prev_get;
84-
g->prev_get = g->get(g);
187+
g->prev_get = g->api.get(g);
85188
if (g->prev_get == '\n') {
86189
buf[wr] = '\0';
87190
if (c_ == '\r') {
@@ -103,26 +206,16 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g,
103206
return NULL;
104207
}
105208

106-
LTC_INLINE static char* s_get_first_line(char *buf, unsigned long *buflen, struct get_char *g)
209+
static LTC_INLINE char* s_get_first_line(char *buf, unsigned long *buflen, struct get_char *g)
107210
{
108211
return s_get_line_i(buf, buflen, g, 1);
109212
}
110213

111-
LTC_INLINE static char* s_get_line(char *buf, unsigned long *buflen, struct get_char *g)
214+
static LTC_INLINE char* s_get_line(char *buf, unsigned long *buflen, struct get_char *g)
112215
{
113216
return s_get_line_i(buf, buflen, g, 0);
114217
}
115218

116-
static LTC_INLINE int s_fits_buf(void *dest, unsigned long to_write, void *end)
117-
{
118-
unsigned char *d = dest;
119-
unsigned char *e = end;
120-
unsigned char *w = d + to_write;
121-
if (w < d || w > e)
122-
return 0;
123-
return 1;
124-
}
125-
126219
static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
127220
{
128221
char buf[LTC_PEM_DECODE_BUFSZ], *alg_start;
@@ -190,31 +283,29 @@ static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
190283
return CRYPT_OK;
191284
}
192285

193-
int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g)
286+
int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g)
194287
{
195-
char buf[LTC_PEM_DECODE_BUFSZ];
196-
char *wpem = asn1_cert;
197-
char *end = wpem + *asn1_len;
288+
char line[LTC_PEM_DECODE_BUFSZ];
289+
struct bufp b_ = {0}, *b = &b_;
198290
const char pem_start[] = "----";
199291
unsigned long slen, linelen;
200292
int err, hdr_ok = 0;
201-
int would_overflow = 0;
202293
unsigned char empty_lines = 0;
203294

204295
g->prev_get = 0;
205296
do {
206-
linelen = sizeof(buf);
207-
if (s_get_first_line(buf, &linelen, g) == NULL) {
297+
linelen = sizeof(line);
298+
if (s_get_first_line(line, &linelen, g) == NULL) {
208299
if (g->prev_get == -1)
209300
return CRYPT_NOP;
210301
else
211302
return CRYPT_INVALID_PACKET;
212303
}
213304
if (linelen < sizeof(pem_start) - 1)
214305
continue;
215-
} while(XMEMCMP(buf, pem_start, sizeof(pem_start) - 1) != 0);
216-
if (hdr->id->start.len != linelen || XMEMCMP(buf, hdr->id->start.p, hdr->id->start.len)) {
217-
s_unget_line(buf, linelen, g);
306+
} while(XMEMCMP(line, pem_start, sizeof(pem_start) - 1) != 0);
307+
if (hdr->id->start.len != linelen || XMEMCMP(line, hdr->id->start.p, hdr->id->start.len)) {
308+
s_unget_line(line, linelen, g);
218309
return CRYPT_UNKNOWN_PEM;
219310
}
220311

@@ -223,9 +314,9 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
223314
return err;
224315

225316
/* Read the base64 encoded part of the PEM */
226-
slen = sizeof(buf);
227-
while (s_get_line(buf, &slen, g)) {
228-
if (slen == hdr->id->end.len && !XMEMCMP(buf, hdr->id->end.p, slen)) {
317+
slen = sizeof(line);
318+
while (s_get_line(line, &slen, g)) {
319+
if (slen == hdr->id->end.len && !XMEMCMP(line, hdr->id->end.p, slen)) {
229320
hdr_ok = 1;
230321
break;
231322
}
@@ -234,34 +325,25 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
234325
break;
235326
empty_lines++;
236327
}
237-
if (!would_overflow && s_fits_buf(wpem, slen, end)) {
238-
XMEMCPY(wpem, buf, slen);
239-
} else {
240-
would_overflow = 1;
328+
if ((err = s_bufp_add(b, line, slen)) != CRYPT_OK) {
329+
goto error_out;
241330
}
242-
wpem += slen;
243-
slen = sizeof(buf);
331+
slen = sizeof(line);
244332
}
245-
if (!hdr_ok)
246-
return CRYPT_INVALID_PACKET;
247-
248-
if (would_overflow || !s_fits_buf(wpem, 1, end)) {
249-
/* NUL termination */
250-
wpem++;
251-
/* prevent a wrap-around */
252-
if (wpem < (char*)asn1_cert)
253-
return CRYPT_OVERFLOW;
254-
*asn1_len = wpem - (char*)asn1_cert;
255-
return CRYPT_BUFFER_OVERFLOW;
333+
if (!hdr_ok) {
334+
err = CRYPT_INVALID_PACKET;
335+
} else {
336+
slen = s_bufp_alloc_len(b);
337+
err = base64_strict_decode(b->start, s_bufp_used_len(b), (void*)b->start, &slen);
256338
}
257-
258-
*asn1_len = wpem - (char*)asn1_cert;
259-
*wpem++ = '\0';
260-
261-
if ((err = base64_strict_decode(asn1_cert, *asn1_len, asn1_cert, asn1_len)) != CRYPT_OK) {
262-
return err;
339+
if (err == CRYPT_OK) {
340+
*dest = b->start;
341+
*len = slen;
342+
} else {
343+
error_out:
344+
XFREE(b->start);
263345
}
264-
return CRYPT_OK;
346+
return err;
265347
}
266348

267349
#endif /* LTC_PEM */

0 commit comments

Comments
 (0)