From 0556942284d7dcdf0a5e7a31e94b925378a338a8 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 14 Dec 2018 13:17:17 -0500 Subject: [PATCH] Use a single path for all PEM-like objects in get_next_token() Previously, we would decode the PEM wrapper for keys twice: once in get_next_token, and once later in PEM decode. Now we just do all of the wrapper and base64 stuff in get_next_token, and store the base64-decoded part in the token object for keys and non-keys alike. This change should speed up parsing slightly by letting us skip a bunch of stuff in crypto_pk_read_*from_string(), including the tag detection parts of pem_decode(), and an extra key allocation and deallocation pair. Retaining the base64-decoded part in the token object will allow us to speed up our microdesc parsing, since it is the asn1 portion that we actually want to retain. --- src/feature/dirparse/parsecommon.c | 24 +++++++++++++----------- src/test/test_parsecommon.c | 8 ++++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/feature/dirparse/parsecommon.c b/src/feature/dirparse/parsecommon.c index 91b775533b..2e7cea8169 100644 --- a/src/feature/dirparse/parsecommon.c +++ b/src/feature/dirparse/parsecommon.c @@ -266,7 +266,7 @@ get_next_token(memarea_t *area, * attack, a bug, or some other nonsense. */ #define MAX_LINE_LENGTH (128*1024) - const char *next, *eol, *obstart; + const char *next, *eol; size_t obname_len; int i; directory_token_t *tok; @@ -352,7 +352,6 @@ get_next_token(memarea_t *area, if (!eol || eol-*s<11 || strcmpstart(*s, "-----BEGIN ")) /* No object. */ goto check_object; - obstart = *s; /* Set obstart to start of object spec */ if (eol - *s <= 16 || memchr(*s+11,'\0',eol-*s-16) || /* no short lines, */ strcmp_len(eol-5, "-----", 5) || /* nuls or invalid endings */ (eol-*s) > MAX_UNPARSED_OBJECT_SIZE) { /* name too long */ @@ -383,15 +382,7 @@ get_next_token(memarea_t *area, if (next - *s > MAX_UNPARSED_OBJECT_SIZE) RET_ERR("Couldn't parse object: missing footer or object much too big."); - if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */ - tok->key = crypto_pk_new(); - if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart)) - RET_ERR("Couldn't parse public key."); - } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */ - tok->key = crypto_pk_new(); - if (crypto_pk_read_private_key_from_string(tok->key, obstart, eol-obstart)) - RET_ERR("Couldn't parse private key."); - } else { /* If it's something else, try to base64-decode it */ + { int r; size_t maxsize = base64_decode_maxsize(next-*s); tok->object_body = ALLOC(maxsize); @@ -400,6 +391,17 @@ get_next_token(memarea_t *area, RET_ERR("Malformed object: bad base64-encoded data"); tok->object_size = r; } + + if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */ + tok->key = crypto_pk_asn1_decode(tok->object_body, tok->object_size); + if (! tok->key) + RET_ERR("Couldn't parse public key."); + } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */ + tok->key = crypto_pk_asn1_decode_private(tok->object_body, + tok->object_size); + if (! tok->key) + RET_ERR("Couldn't parse private key."); + } *s = eol; check_object: diff --git a/src/test/test_parsecommon.c b/src/test/test_parsecommon.c index 6da125dd0a..8e74fcdb4d 100644 --- a/src/test/test_parsecommon.c +++ b/src/test/test_parsecommon.c @@ -300,8 +300,8 @@ test_parsecommon_get_next_token_parse_keys(void *arg) tt_int_op(token->tp, OP_EQ, R_IPO_ONION_KEY); tt_int_op(token->n_args, OP_EQ, 0); tt_str_op(token->object_type, OP_EQ, "RSA PUBLIC KEY"); - tt_int_op(token->object_size, OP_EQ, 0); - tt_assert(!token->object_body); + tt_int_op(token->object_size, OP_EQ, 140); + tt_assert(token->object_body); tt_assert(token->key); tt_assert(!token->error); @@ -335,8 +335,8 @@ test_parsecommon_get_next_token_parse_keys(void *arg) tt_int_op(token2->tp, OP_EQ, C_CLIENT_KEY); tt_int_op(token2->n_args, OP_EQ, 0); tt_str_op(token2->object_type, OP_EQ, "RSA PRIVATE KEY"); - tt_int_op(token2->object_size, OP_EQ, 0); - tt_assert(!token2->object_body); + tt_int_op(token2->object_size, OP_EQ, 608); + tt_assert(token2->object_body); tt_assert(token2->key); tt_assert(!token->error); -- 2.11.4.GIT