Skip to content

Commit 59fa912

Browse files
committed
Put realloc logic into pem_read()
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
1 parent 959d17d commit 59fa912

File tree

4 files changed

+143
-80
lines changed

4 files changed

+143
-80
lines changed

src/headers/tomcrypt_private.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,19 +355,40 @@ struct bufp {
355355
};
356356

357357
#define SET_BUFP(n, d, l) n.start = (char*)d, n.work = (char*)d, n.end = (char*)d + l + 1
358+
#define UPDATE_BUFP(n, d, w, l) n.start = (char*)d, n.work = (char*)d + w, n.end = (char*)d + l + 1
358359

359-
struct get_char {
360+
struct get_char;
361+
struct get_char_api {
360362
int (*get)(struct get_char*);
363+
};
364+
365+
struct get_char {
366+
struct get_char_api api;
361367
union {
362368
#ifndef LTC_NO_FILE
363-
FILE *f;
369+
struct {
370+
FILE *f;
371+
} f;
364372
#endif /* LTC_NO_FILE */
365373
struct bufp buf;
366374
} data;
367375
struct str unget_buf;
368376
char unget_buf_[LTC_PEM_DECODE_BUFSZ];
369377
int prev_get;
378+
unsigned long total_read;
370379
};
380+
381+
#define pem_get_char_init(b, l) { \
382+
.api = get_char_buffer_api, \
383+
SET_BUFP(.data.buf, (b), (l)), \
384+
.total_read = 0, \
385+
}
386+
387+
#define pem_get_char_init_filehandle(fi) { \
388+
.api = get_char_filehandle_api, \
389+
.data.f.f = (fi), \
390+
.total_read = 0, \
391+
}
371392
#endif
372393

373394
/* others */
@@ -390,10 +411,10 @@ int pem_decrypt(unsigned char *data, unsigned long *datalen,
390411
const struct blockcipher_info *info,
391412
enum padding_type padding);
392413
#ifndef LTC_NO_FILE
393-
int pem_get_char_from_file(struct get_char *g);
414+
extern const struct get_char_api get_char_filehandle_api;
394415
#endif /* LTC_NO_FILE */
395-
int pem_get_char_from_buf(struct get_char *g);
396-
int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g);
416+
extern const struct get_char_api get_char_buffer_api;
417+
int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g);
397418
#endif
398419

399420
/* tomcrypt_pk.h */

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: 104 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,76 @@ 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)
2280
{
23-
return getc(g->data.f);
81+
return getc(g->data.f.f);
2482
}
83+
84+
const struct get_char_api get_char_filehandle_api = {
85+
.get = s_pem_get_char_from_file,
86+
};
2587
#endif /* LTC_NO_FILE */
2688

27-
int pem_get_char_from_buf(struct get_char *g)
89+
static int s_pem_get_char_from_buf(struct get_char *g)
2890
{
2991
int ret;
3092
if (g->data.buf.work == g->data.buf.end) {
@@ -35,6 +97,10 @@ int pem_get_char_from_buf(struct get_char *g)
3597
return ret;
3698
}
3799

100+
const struct get_char_api get_char_buffer_api = {
101+
.get = s_pem_get_char_from_buf,
102+
};
103+
38104
static void s_unget_line(char *buf, unsigned long buflen, struct get_char *g)
39105
{
40106
if (buflen > sizeof(g->unget_buf_))
@@ -81,14 +147,15 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g,
81147
while(blen < *buflen || search_for_start) {
82148
wr = blen < *buflen ? blen : *buflen - 1;
83149
c_ = g->prev_get;
84-
g->prev_get = g->get(g);
150+
g->prev_get = g->api.get(g);
85151
if (g->prev_get == '\n') {
86152
buf[wr] = '\0';
87153
if (c_ == '\r') {
88154
buf[--wr] = '\0';
89155
}
90156
s_tts(buf, &wr);
91157
*buflen = wr;
158+
g->total_read++;
92159
return buf;
93160
}
94161
if (g->prev_get == -1 || g->prev_get == '\0') {
@@ -99,30 +166,21 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g,
99166
}
100167
buf[wr] = g->prev_get;
101168
blen++;
169+
g->total_read++;
102170
}
103171
return NULL;
104172
}
105173

106-
LTC_INLINE static char* s_get_first_line(char *buf, unsigned long *buflen, struct get_char *g)
174+
static LTC_INLINE char* s_get_first_line(char *buf, unsigned long *buflen, struct get_char *g)
107175
{
108176
return s_get_line_i(buf, buflen, g, 1);
109177
}
110178

111-
LTC_INLINE static char* s_get_line(char *buf, unsigned long *buflen, struct get_char *g)
179+
static LTC_INLINE char* s_get_line(char *buf, unsigned long *buflen, struct get_char *g)
112180
{
113181
return s_get_line_i(buf, buflen, g, 0);
114182
}
115183

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-
126184
static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
127185
{
128186
char buf[LTC_PEM_DECODE_BUFSZ], *alg_start;
@@ -190,31 +248,30 @@ static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
190248
return CRYPT_OK;
191249
}
192250

193-
int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g)
251+
int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g)
194252
{
195-
char buf[LTC_PEM_DECODE_BUFSZ];
196-
char *wpem = asn1_cert;
197-
char *end = wpem + *asn1_len;
253+
char line[LTC_PEM_DECODE_BUFSZ];
254+
struct bufp b_ = {0}, *b = &b_;
198255
const char pem_start[] = "----";
199-
unsigned long slen, linelen;
256+
unsigned long slen, read_len = 0;
200257
int err, hdr_ok = 0;
201-
int would_overflow = 0;
202258
unsigned char empty_lines = 0;
203259

204260
g->prev_get = 0;
205261
do {
206-
linelen = sizeof(buf);
207-
if (s_get_first_line(buf, &linelen, g) == NULL) {
262+
slen = sizeof(line);
263+
if (s_get_first_line(line, &slen, g) == NULL) {
208264
if (g->prev_get == -1)
209265
return CRYPT_NOP;
210266
else
211267
return CRYPT_INVALID_PACKET;
212268
}
213-
if (linelen < sizeof(pem_start) - 1)
269+
read_len += slen;
270+
if (slen < sizeof(pem_start) - 1)
214271
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);
272+
} while(XMEMCMP(line, pem_start, sizeof(pem_start) - 1) != 0);
273+
if (hdr->id->start.len != slen || XMEMCMP(line, hdr->id->start.p, hdr->id->start.len)) {
274+
s_unget_line(line, slen, g);
218275
return CRYPT_UNKNOWN_PEM;
219276
}
220277

@@ -223,9 +280,10 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
223280
return err;
224281

225282
/* 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)) {
283+
slen = sizeof(line);
284+
while (s_get_line(line, &slen, g)) {
285+
read_len += slen;
286+
if (slen == hdr->id->end.len && !XMEMCMP(line, hdr->id->end.p, slen)) {
229287
hdr_ok = 1;
230288
break;
231289
}
@@ -234,34 +292,26 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
234292
break;
235293
empty_lines++;
236294
}
237-
if (!would_overflow && s_fits_buf(wpem, slen, end)) {
238-
XMEMCPY(wpem, buf, slen);
239-
} else {
240-
would_overflow = 1;
295+
if ((err = s_bufp_add(b, line, slen)) != CRYPT_OK) {
296+
goto error_out;
241297
}
242-
wpem += slen;
243-
slen = sizeof(buf);
298+
slen = sizeof(line);
244299
}
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;
300+
if (!hdr_ok) {
301+
err = CRYPT_INVALID_PACKET;
302+
} else {
303+
slen = s_bufp_alloc_len(b);
304+
err = base64_strict_decode(b->start, s_bufp_used_len(b), (void*)b->start, &slen);
256305
}
306+
if (err == CRYPT_OK) {
307+
*dest = b->start;
308+
*len = slen;
257309

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;
310+
} else {
311+
error_out:
312+
XFREE(b->start);
263313
}
264-
return CRYPT_OK;
314+
return err;
265315
}
266316

267317
#endif /* LTC_PEM */

0 commit comments

Comments
 (0)