Skip to content

Commit d9b0684

Browse files
committed
Put retry/realloc logic into pem_read()
Signed-off-by: Steffen Jaeckel <[email protected]>
1 parent bc68659 commit d9b0684

File tree

5 files changed

+139
-76
lines changed

5 files changed

+139
-76
lines changed

src/headers/tomcrypt_private.h

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -383,18 +383,39 @@ struct bufp {
383383

384384
#define SET_BUFP(n, d, l) n.start = (char*)d, n.work = (char*)d, n.end = (char*)d + l + 1
385385

386-
struct get_char {
386+
struct get_char;
387+
struct get_char_api {
387388
int (*get)(struct get_char*);
389+
int (*reset)(struct get_char*);
390+
unsigned long (*len)(struct get_char*);
391+
};
392+
393+
struct get_char {
394+
struct get_char_api api;
388395
union {
389396
#ifndef LTC_NO_FILE
390-
FILE *f;
397+
struct {
398+
FILE *f;
399+
long original_pos;
400+
} f;
391401
#endif /* LTC_NO_FILE */
392402
struct bufp buf;
393403
} data;
394404
struct str unget_buf;
395405
char unget_buf_[LTC_PEM_DECODE_BUFSZ];
396406
int prev_get;
397407
};
408+
409+
#define pem_get_char_init(b, l) { \
410+
.api = get_char_buffer_api, \
411+
SET_BUFP(.data.buf, (b), (l)) \
412+
}
413+
414+
#define pem_get_char_init_filehandle(fi) { \
415+
.api = get_char_filehandle_api, \
416+
.data.f.f = (fi), \
417+
.data.f.original_pos = ftell(fi) \
418+
}
398419
#endif
399420

400421
/* others */
@@ -417,10 +438,10 @@ int pem_decrypt(unsigned char *data, unsigned long *datalen,
417438
const struct blockcipher_info *info,
418439
enum padding_type padding);
419440
#ifndef LTC_NO_FILE
420-
int pem_get_char_from_file(struct get_char *g);
441+
extern const struct get_char_api get_char_filehandle_api;
421442
#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);
443+
extern const struct get_char_api get_char_buffer_api;
444+
int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g);
424445
#endif
425446

426447
/* tomcrypt_pk.h */
@@ -708,7 +729,7 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i
708729

709730
int x509_get_pka(const ltc_asn1_list *pub, enum ltc_pka_id *pka);
710731
int x509_get_sig_alg(const ltc_asn1_list *pub, ltc_x509_signature_algorithm *sig_alg);
711-
int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root);
732+
int x509_import_spki(const unsigned char *buf, unsigned long len, ltc_pka_key *k, ltc_asn1_list **root);
712733
int x509_get_extensions(const ltc_asn1_list *seq, ltc_x509_extensions *extensions);
713734
void x509_free_extensions(const ltc_x509_extensions *extensions);
714735
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: 93 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,39 @@ extern const struct blockcipher_info pem_dek_infos[];
1818
extern const unsigned long pem_dek_infos_num;
1919

2020
#ifndef LTC_NO_FILE
21-
int pem_get_char_from_file(struct get_char *g)
21+
static int s_pem_get_char_from_file(struct get_char *g)
2222
{
23-
return getc(g->data.f);
23+
return getc(g->data.f.f);
2424
}
25+
26+
static int s_pem_get_char_reset_file(struct get_char *g)
27+
{
28+
if (g->data.f.original_pos == -1)
29+
return -1;
30+
return fseek(g->data.f.f, g->data.f.original_pos, SEEK_SET);
31+
}
32+
33+
static unsigned long s_pem_get_char_len_file(struct get_char *g)
34+
{
35+
FILE *f = g->data.f.f;
36+
long len, cur_pos = ftell(f);
37+
if (cur_pos != -1) {
38+
fseek(f, 0, SEEK_END);
39+
len = ftell(f);
40+
fseek(f, cur_pos, SEEK_SET);
41+
return len - cur_pos;
42+
}
43+
return LTC_PEM_READ_BUFSIZE * 2;
44+
}
45+
46+
const struct get_char_api get_char_filehandle_api = {
47+
.get = s_pem_get_char_from_file,
48+
.reset = s_pem_get_char_reset_file,
49+
.len = s_pem_get_char_len_file,
50+
};
2551
#endif /* LTC_NO_FILE */
2652

27-
int pem_get_char_from_buf(struct get_char *g)
53+
static int s_pem_get_char_from_buf(struct get_char *g)
2854
{
2955
int ret;
3056
if (g->data.buf.work == g->data.buf.end) {
@@ -35,6 +61,23 @@ int pem_get_char_from_buf(struct get_char *g)
3561
return ret;
3662
}
3763

64+
static int s_pem_get_char_reset(struct get_char *g)
65+
{
66+
g->data.buf.work = g->data.buf.start;
67+
return 0;
68+
}
69+
70+
static unsigned long s_pem_get_char_len(struct get_char *g)
71+
{
72+
return g->data.buf.end - g->data.buf.start - 1;
73+
}
74+
75+
const struct get_char_api get_char_buffer_api = {
76+
.get = s_pem_get_char_from_buf,
77+
.reset = s_pem_get_char_reset,
78+
.len = s_pem_get_char_len,
79+
};
80+
3881
static void s_unget_line(char *buf, unsigned long buflen, struct get_char *g)
3982
{
4083
if (buflen > sizeof(g->unget_buf_))
@@ -81,7 +124,7 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g,
81124
while(blen < *buflen || search_for_start) {
82125
wr = blen < *buflen ? blen : *buflen - 1;
83126
c_ = g->prev_get;
84-
g->prev_get = g->get(g);
127+
g->prev_get = g->api.get(g);
85128
if (g->prev_get == '\n') {
86129
buf[wr] = '\0';
87130
if (c_ == '\r') {
@@ -190,11 +233,11 @@ static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
190233
return CRYPT_OK;
191234
}
192235

193-
int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g)
236+
static int s_pem_read(void *buf, unsigned long *len, struct pem_headers *hdr, struct get_char *g)
194237
{
195-
char buf[LTC_PEM_DECODE_BUFSZ];
196-
char *wpem = asn1_cert;
197-
char *end = wpem + *asn1_len;
238+
char line[LTC_PEM_DECODE_BUFSZ];
239+
char *wpem = buf;
240+
char *end = wpem + *len;
198241
const char pem_start[] = "----";
199242
unsigned long slen, linelen;
200243
int err, hdr_ok = 0;
@@ -203,18 +246,18 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
203246

204247
g->prev_get = 0;
205248
do {
206-
linelen = sizeof(buf);
207-
if (s_get_first_line(buf, &linelen, g) == NULL) {
249+
linelen = sizeof(line);
250+
if (s_get_first_line(line, &linelen, g) == NULL) {
208251
if (g->prev_get == -1)
209252
return CRYPT_NOP;
210253
else
211254
return CRYPT_INVALID_PACKET;
212255
}
213256
if (linelen < sizeof(pem_start) - 1)
214257
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);
258+
} while(XMEMCMP(line, pem_start, sizeof(pem_start) - 1) != 0);
259+
if (hdr->id->start.len != linelen || XMEMCMP(line, hdr->id->start.p, hdr->id->start.len)) {
260+
s_unget_line(line, linelen, g);
218261
return CRYPT_UNKNOWN_PEM;
219262
}
220263

@@ -223,9 +266,9 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
223266
return err;
224267

225268
/* 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)) {
269+
slen = sizeof(line);
270+
while (s_get_line(line, &slen, g)) {
271+
if (slen == hdr->id->end.len && !XMEMCMP(line, hdr->id->end.p, slen)) {
229272
hdr_ok = 1;
230273
break;
231274
}
@@ -235,12 +278,12 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
235278
empty_lines++;
236279
}
237280
if (!would_overflow && s_fits_buf(wpem, slen, end)) {
238-
XMEMCPY(wpem, buf, slen);
281+
XMEMCPY(wpem, line, slen);
239282
} else {
240283
would_overflow = 1;
241284
}
242285
wpem += slen;
243-
slen = sizeof(buf);
286+
slen = sizeof(line);
244287
}
245288
if (!hdr_ok)
246289
return CRYPT_INVALID_PACKET;
@@ -249,19 +292,47 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
249292
/* NUL termination */
250293
wpem++;
251294
/* prevent a wrap-around */
252-
if (wpem < (char*)asn1_cert)
295+
if (wpem < (char*)buf)
253296
return CRYPT_OVERFLOW;
254-
*asn1_len = wpem - (char*)asn1_cert;
297+
*len = wpem - (char*)buf;
255298
return CRYPT_BUFFER_OVERFLOW;
256299
}
257300

258-
*asn1_len = wpem - (char*)asn1_cert;
301+
*len = wpem - (char*)buf;
259302
*wpem++ = '\0';
260303

261-
if ((err = base64_strict_decode(asn1_cert, *asn1_len, asn1_cert, asn1_len)) != CRYPT_OK) {
304+
if ((err = base64_strict_decode(buf, *len, buf, len)) != CRYPT_OK) {
262305
return err;
263306
}
264307
return CRYPT_OK;
265308
}
266309

310+
int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g)
311+
{
312+
int err, once = 0;
313+
void *work = NULL, *work_;
314+
unsigned long work_len = g->api.len(g);
315+
retry:
316+
work_ = XREALLOC(work, work_len);
317+
if (work_ == NULL) {
318+
goto error_out;
319+
}
320+
work = work_;
321+
once++;
322+
if ((err = s_pem_read(work, &work_len, hdr, g)) == CRYPT_BUFFER_OVERFLOW
323+
&& once == 1) {
324+
if (g->api.reset(g) != -1) {
325+
goto retry;
326+
}
327+
}
328+
if (err != CRYPT_OK) {
329+
error_out:
330+
XFREE(work);
331+
work = NULL;
332+
}
333+
*dest = work;
334+
*len = work_len;
335+
return err;
336+
}
337+
267338
#endif /* LTC_PEM */

src/misc/pem/pem_ssh.c

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -712,20 +712,15 @@ static const unsigned long pem_openssh_num = LTC_ARRAY_SIZE(pem_openssh);
712712
static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
713713
{
714714
unsigned char *pem = NULL, *p, *privkey = NULL, *tag;
715-
unsigned long n, w, l, privkey_len, taglen;
715+
unsigned long n, w = 0, l, privkey_len, taglen;
716716
int err;
717717
struct pem_headers hdr;
718718
struct kdf_options opts = { 0 };
719719
XMEMSET(k, 0, sizeof(*k));
720-
w = LTC_PEM_READ_BUFSIZE * 2;
721-
retry:
722-
pem = XREALLOC(pem, w);
723720
for (n = 0; n < pem_openssh_num; ++n) {
724721
hdr.id = &pem_openssh[n];
725-
err = pem_read(pem, &w, &hdr, g);
726-
if (err == CRYPT_BUFFER_OVERFLOW) {
727-
goto retry;
728-
} else if (err == CRYPT_OK) {
722+
err = pem_read((void**)&pem, &w, &hdr, g);
723+
if (err == CRYPT_OK) {
729724
break;
730725
} else if (err != CRYPT_UNKNOWN_PEM) {
731726
goto cleanup;
@@ -791,7 +786,9 @@ static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_c
791786
zeromem(privkey, privkey_len);
792787
XFREE(privkey);
793788
}
794-
XFREE(pem);
789+
if (pem) {
790+
XFREE(pem);
791+
}
795792
return err;
796793
}
797794

@@ -801,7 +798,7 @@ int pem_decode_openssh_filehandle(FILE *f, ltc_pka_key *k, const password_ctx *p
801798
LTC_ARGCHK(f != NULL);
802799
LTC_ARGCHK(k != NULL);
803800
{
804-
struct get_char g = { .get = pem_get_char_from_file, .data.f = f };
801+
struct get_char g = pem_get_char_init_filehandle(f);
805802
return s_decode_openssh(&g, k, pw_ctx);
806803
}
807804
}
@@ -841,7 +838,7 @@ int pem_decode_openssh(const void *buf, unsigned long len, ltc_pka_key *k, const
841838
LTC_ARGCHK(len != 0);
842839
LTC_ARGCHK(k != NULL);
843840
{
844-
struct get_char g = { .get = pem_get_char_from_buf, SET_BUFP(.data.buf, buf, len) };
841+
struct get_char g = pem_get_char_init(buf, len);
845842
return s_decode_openssh(&g, k, pw_ctx);
846843
}
847844
}

0 commit comments

Comments
 (0)