mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-20 14:37:08 +01:00
common: New function cmp_canon_sexp.
* common/sexputil.c (cmp_canon_sexp): New. (cmp_canon_sexp_def_tcmp): New. * common/t-sexputil.c (test_cmp_canon_sexp): Add a simple test. -- To be used to fix GnuPG-bug-id: 5061 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
9a94db1f66
commit
b6ba6a79ce
@ -263,6 +263,96 @@ cmp_simple_canon_sexp (const unsigned char *a_orig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for cmp_canon_sexp. */
|
||||||
|
static int
|
||||||
|
cmp_canon_sexp_def_tcmp (void *ctx, int depth,
|
||||||
|
const unsigned char *aval, size_t alen,
|
||||||
|
const unsigned char *bval, size_t blen)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
(void)depth;
|
||||||
|
|
||||||
|
if (alen > blen)
|
||||||
|
return 1;
|
||||||
|
else if (alen < blen)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return memcmp (aval, bval, alen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compare the two canonical encoded s-expressions A with maximum
|
||||||
|
* length ALEN and B with maximum length BLEN.
|
||||||
|
*
|
||||||
|
* Returns 0 if they match.
|
||||||
|
*
|
||||||
|
* If TCMP is NULL, this is not different really different from a
|
||||||
|
* memcmp but does not consider any garbage after the last closing
|
||||||
|
* parentheses.
|
||||||
|
*
|
||||||
|
* If TCMP is not NULL, it is expected to be a function to compare the
|
||||||
|
* values of each token. TCMP is called for each token while parsing
|
||||||
|
* the s-expressions until TCMP return a non-zero value. Here the CTX
|
||||||
|
* receives the provided value TCMPCTX, DEPTH is the number of
|
||||||
|
* currently open parentheses and (AVAL,ALEN) and (BVAL,BLEN) the
|
||||||
|
* values of the current token. TCMP needs to return zero to indicate
|
||||||
|
* that the tokens match. */
|
||||||
|
int
|
||||||
|
cmp_canon_sexp (const unsigned char *a, size_t alen,
|
||||||
|
const unsigned char *b, size_t blen,
|
||||||
|
int (*tcmp)(void *ctx, int depth,
|
||||||
|
const unsigned char *aval, size_t avallen,
|
||||||
|
const unsigned char *bval, size_t bvallen),
|
||||||
|
void *tcmpctx)
|
||||||
|
{
|
||||||
|
const unsigned char *a_buf, *a_tok;
|
||||||
|
const unsigned char *b_buf, *b_tok;
|
||||||
|
size_t a_buflen, a_toklen;
|
||||||
|
size_t b_buflen, b_toklen;
|
||||||
|
int a_depth, b_depth, ret;
|
||||||
|
|
||||||
|
if ((!a && !b) || (!alen && !blen))
|
||||||
|
return 0; /* Both are NULL, they are identical. */
|
||||||
|
if (!a || !b)
|
||||||
|
return !!a - !!b; /* One is NULL, they are not identical. */
|
||||||
|
if (*a != '(' || *b != '(')
|
||||||
|
log_bug ("invalid S-exp in %s\n", __func__);
|
||||||
|
|
||||||
|
if (!tcmp)
|
||||||
|
tcmp = cmp_canon_sexp_def_tcmp;
|
||||||
|
|
||||||
|
a_depth = 0;
|
||||||
|
a_buf = a;
|
||||||
|
a_buflen = alen;
|
||||||
|
b_depth = 0;
|
||||||
|
b_buf = b;
|
||||||
|
b_buflen = blen;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (parse_sexp (&a_buf, &a_buflen, &a_depth, &a_tok, &a_toklen))
|
||||||
|
return -1; /* A is invalid. */
|
||||||
|
if (parse_sexp (&b_buf, &b_buflen, &b_depth, &b_tok, &b_toklen))
|
||||||
|
return -1; /* B is invalid. */
|
||||||
|
if (!a_depth && !b_depth)
|
||||||
|
return 0; /* End of both expressions - they match. */
|
||||||
|
if (a_depth != b_depth)
|
||||||
|
return a_depth - b_depth; /* Not the same structure */
|
||||||
|
if (!a_tok && !b_tok)
|
||||||
|
; /* parens */
|
||||||
|
else if (a_tok && b_tok)
|
||||||
|
{
|
||||||
|
ret = tcmp (tcmpctx, a_depth, a_tok, a_toklen, b_tok, b_toklen);
|
||||||
|
if (ret)
|
||||||
|
return ret; /* Mismatch */
|
||||||
|
}
|
||||||
|
else /* One has a paren other has not. */
|
||||||
|
return !!a_tok - !!b_tok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Create a simple S-expression from the hex string at LINE. Returns
|
/* Create a simple S-expression from the hex string at LINE. Returns
|
||||||
a newly allocated buffer with that canonical encoded S-expression
|
a newly allocated buffer with that canonical encoded S-expression
|
||||||
or NULL in case of an error. On return the number of characters
|
or NULL in case of an error. On return the number of characters
|
||||||
|
@ -178,6 +178,107 @@ test_make_canon_sexp_from_rsa_pk (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Communiacation object for tcmp. */
|
||||||
|
struct tcmp_parm_s {
|
||||||
|
int curve_seen;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Helper for test_cmp_canon_sexp. */
|
||||||
|
static int
|
||||||
|
tcmp1 (void *opaque, int depth,
|
||||||
|
const unsigned char *aval, size_t alen,
|
||||||
|
const unsigned char *bval, size_t blen)
|
||||||
|
{
|
||||||
|
struct tcmp_parm_s *parm = opaque;
|
||||||
|
|
||||||
|
(void)depth;
|
||||||
|
|
||||||
|
if (parm->curve_seen)
|
||||||
|
{
|
||||||
|
/* Last token was "curve", canonicalize its argument. */
|
||||||
|
parm->curve_seen = 0;
|
||||||
|
|
||||||
|
if (alen == 8 && !memcmp (aval, "nistp256", alen))
|
||||||
|
{
|
||||||
|
alen = 19;
|
||||||
|
aval = "1.2.840.10045.3.1.7";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blen == 8 && !memcmp (bval, "nistp256", blen))
|
||||||
|
{
|
||||||
|
blen = 19;
|
||||||
|
bval = "1.2.840.10045.3.1.7";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (alen == 5 && !memcmp (aval, "curve", 5))
|
||||||
|
parm->curve_seen = 1;
|
||||||
|
else
|
||||||
|
parm->curve_seen = 0;
|
||||||
|
|
||||||
|
if (alen > blen)
|
||||||
|
return 1;
|
||||||
|
else if (alen < blen)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return memcmp (aval, bval, alen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_cmp_canon_sexp (void)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
unsigned char *a;
|
||||||
|
unsigned char *b;
|
||||||
|
int expected0; /* Expected result without compare function. */
|
||||||
|
int expected1; /* Expected result with compare function tcmp1. */
|
||||||
|
}
|
||||||
|
tests[] = {
|
||||||
|
{
|
||||||
|
"(10:public-key(3:ecc(5:curve8:nistp256)(1:q10:qqqqqqqqqq)))",
|
||||||
|
"(10:public-key(3:ecc(5:curve8:nistp256)(1:q10:qqqqqqqqqq)))",
|
||||||
|
0, 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"(10:public-key(3:ecc(5:curve19:1.2.840.10045.3.1.7)(1:q10:qqqqqqqqqq)))",
|
||||||
|
"(10:public-key(3:ecc(5:curve19:1.2.840.10045.3.1.7)(1:q10:qqqqqqqqqq)))",
|
||||||
|
0, 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"(10:public-key(3:ecc(5:curve8:nistp256)(1:q10:qqqqqqqqqq)))",
|
||||||
|
"(10:public-key(3:ecc(5:curve19:1.2.840.10045.3.1.7)(1:q10:qqqqqqqqqq)))",
|
||||||
|
-1, 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"(10:public-key(3:ecc(5:curve19:1.2.840.10045.3.1.7)(1:q10:qqqqqqqqqq)))",
|
||||||
|
"(10:public-key(3:ecc(5:curve8:nistp256)(1:q10:qqqqqqqqqq)))",
|
||||||
|
1, 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NULL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct tcmp_parm_s parm = {0};
|
||||||
|
int idx;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
for (idx=0; tests[idx].a; idx++)
|
||||||
|
{
|
||||||
|
res = cmp_canon_sexp (tests[idx].a, strlen (tests[idx].a),
|
||||||
|
tests[idx].b, strlen (tests[idx].b),
|
||||||
|
NULL, NULL);
|
||||||
|
if (res != tests[idx].expected0)
|
||||||
|
fail (idx);
|
||||||
|
res = cmp_canon_sexp (tests[idx].a, strlen (tests[idx].a),
|
||||||
|
tests[idx].b, strlen (tests[idx].b),
|
||||||
|
tcmp1, &parm);
|
||||||
|
if (res != tests[idx].expected1)
|
||||||
|
fail (idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -186,6 +287,7 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
test_hash_algo_from_sigval ();
|
test_hash_algo_from_sigval ();
|
||||||
test_make_canon_sexp_from_rsa_pk ();
|
test_make_canon_sexp_from_rsa_pk ();
|
||||||
|
test_cmp_canon_sexp ();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -242,8 +242,8 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
|
|||||||
returned as a pointer into the original buffer at TOK and TOKLEN.
|
returned as a pointer into the original buffer at TOK and TOKLEN.
|
||||||
If a parentheses is the next token, TOK will be set to NULL.
|
If a parentheses is the next token, TOK will be set to NULL.
|
||||||
TOKLEN is checked to be within the bounds. On error an error code
|
TOKLEN is checked to be within the bounds. On error an error code
|
||||||
is returned and no pointer is not guaranteed to point to
|
is returned and pointers are not guaranteed to point to
|
||||||
a meaningful value. DEPTH should be initialized to 0 and will
|
meaningful values. DEPTH should be initialized to 0 and will
|
||||||
reflect on return the actual depth of the tree. To detect the end
|
reflect on return the actual depth of the tree. To detect the end
|
||||||
of the S-expression it is advisable to check DEPTH after a
|
of the S-expression it is advisable to check DEPTH after a
|
||||||
successful return.
|
successful return.
|
||||||
|
@ -185,6 +185,12 @@ gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, int secure,
|
|||||||
gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
|
gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
|
||||||
unsigned char *grip);
|
unsigned char *grip);
|
||||||
int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b);
|
int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b);
|
||||||
|
int cmp_canon_sexp (const unsigned char *a, size_t alen,
|
||||||
|
const unsigned char *b, size_t blen,
|
||||||
|
int (*tcmp)(void *ctx, int depth,
|
||||||
|
const unsigned char *aval, size_t avallen,
|
||||||
|
const unsigned char *bval, size_t bvallen),
|
||||||
|
void *tcmpctx);
|
||||||
unsigned char *make_simple_sexp_from_hexstr (const char *line,
|
unsigned char *make_simple_sexp_from_hexstr (const char *line,
|
||||||
size_t *nscanned);
|
size_t *nscanned);
|
||||||
int hash_algo_from_sigval (const unsigned char *sigval);
|
int hash_algo_from_sigval (const unsigned char *sigval);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user