diff options
author | Werner Koch <[email protected]> | 2024-03-12 15:00:55 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2024-03-12 15:00:55 +0000 |
commit | 4485930f9fd9ff02ca5c8472cf6aed3fdb1280cf (patch) | |
tree | 683140a4a33b0f3accf5b1f2455274d251581970 /g10/keyid.c | |
parent | gpg: Fix a possible segv due to an uninitialized gcrypt context. (diff) | |
parent | Post release updates (diff) | |
download | gnupg-4485930f9fd9ff02ca5c8472cf6aed3fdb1280cf.tar.gz gnupg-4485930f9fd9ff02ca5c8472cf6aed3fdb1280cf.zip |
Merge branch 'STABLE-BRANCH-2-4'
--
Resolved conflicts:
NEWS
common/exechelp-w32.c
configure.ac
Diffstat (limited to 'g10/keyid.c')
-rw-r--r-- | g10/keyid.c | 178 |
1 files changed, 156 insertions, 22 deletions
diff --git a/g10/keyid.c b/g10/keyid.c index ed76818a2..7e4c50b59 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -145,6 +145,130 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize) } +/* Helper for compare_pubkey_string. This skips leading spaces, + * commas and optional condition operators and returns a pointer to + * the first non-space character or NULL in case of an error. The + * length of a prefix consisting of letters is then returned ar PFXLEN + * and the value of the number (e.g. 384 for "brainpoolP384r1") at + * NUMBER. R_LENGTH receives the entire length of the algorithm name + * which is terminated by a space, nul, or a comma. If R_CONDITION is + * not NULL, 0 is stored for a leading "=", 1 for a ">", 2 for a ">=", + * -1 for a "<", and -2 for a "<=". If R_CONDITION is NULL no + * condition prefix is allowed. */ +static const char * +parse_one_algo_string (const char *str, size_t *pfxlen, unsigned int *number, + size_t *r_length, int *r_condition) +{ + int condition = 0; + const char *result; + + while (spacep (str) || *str ==',') + str++; + if (!r_condition) + ; + else if (*str == '>' && str[1] == '=') + condition = 2, str += 2; + else if (*str == '>' ) + condition = 1, str += 1; + else if (*str == '<' && str[1] == '=') + condition = -2, str += 2; + else if (*str == '<') + condition = -1, str += 1; + else if (*str == '=') /* Default. */ + str += 1; + + if (!alphap (str)) + return NULL; /* Error. */ + + *pfxlen = 1; + for (result = str++; alphap (str); str++) + ++*pfxlen; + while (*str == '-' || *str == '+') + str++; + *number = atoi (str); + while (*str && !spacep (str) && *str != ',') + str++; + + *r_length = str - result; + if (r_condition) + *r_condition = condition; + return result; +} + +/* Helper for compare_pubkey_string. If BPARSED is set to 0 on + * return, an error in ASTR or BSTR was found and further checks are + * not possible. */ +static int +compare_pubkey_string_part (const char *astr, const char *bstr_arg, + size_t *bparsed) +{ + const char *bstr = bstr_arg; + size_t alen, apfxlen, blen, bpfxlen; + unsigned int anumber, bnumber; + int condition; + + *bparsed = 0; + astr = parse_one_algo_string (astr, &apfxlen, &anumber, &alen, &condition); + if (!astr) + return 0; /* Invalid algorithm name. */ + bstr = parse_one_algo_string (bstr, &bpfxlen, &bnumber, &blen, &condition); + if (!bstr) + return 0; /* Invalid algorithm name. */ + *bparsed = blen + (bstr - bstr_arg); + if (apfxlen != bpfxlen || ascii_strncasecmp (astr, bstr, apfxlen)) + return 0; /* false. */ + switch (condition) + { + case 2: return anumber >= bnumber; + case 1: return anumber > bnumber; + case -1: return anumber < bnumber; + case -2: return anumber <= bnumber; + } + + return alen == blen && !ascii_strncasecmp (astr, bstr, alen); +} + + +/* Check whether ASTR matches the constraints given by BSTR. ASTR may + * be any algo string like "rsa2048", "ed25519" and BSTR may be a + * constraint which is in the simplest case just another algo string. + * BSTR may have more that one string in which case they are comma + * separated and any match will return true. It is possible to prefix + * BSTR with ">", ">=", "<=", or "<". That prefix operator is applied + * to the number part of the algorithm, i.e. the first sequence of + * digits found before end-of-string or a comma. Examples: + * + * | ASTR | BSTR | result | + * |----------+----------------------+--------| + * | rsa2048 | rsa2048 | true | + * | rsa2048 | >=rsa2048 | true | + * | rsa2048 | >rsa2048 | false | + * | ed25519 | >rsa1024 | false | + * | ed25519 | ed25519 | true | + * | nistp384 | >nistp256 | true | + * | nistp521 | >=rsa3072, >nistp384 | true | + */ +int +compare_pubkey_string (const char *astr, const char *bstr) +{ + size_t bparsed; + int result; + + while (*bstr) + { + result = compare_pubkey_string_part (astr, bstr, &bparsed); + if (result) + return 1; + if (!bparsed) + return 0; /* Syntax error in ASTR or BSTR. */ + bstr += bparsed; + } + + return 0; +} + + + /* Hash a public key and allow to specify the to be used format. * Note that if the v5 format is requested for a v4 key, a 0x04 as * version is hashed instead of the 0x05. */ @@ -239,20 +363,16 @@ do_hash_public_key (gcry_md_hd_t md, PKT_public_key *pk, int use_v5) if (use_v5) { gcry_md_putc ( md, 0x9a ); /* ctb */ - gcry_md_putc ( md, n >> 24 ); /* 4 byte length header */ + gcry_md_putc ( md, n >> 24 ); /* 4 byte length header (upper bits) */ gcry_md_putc ( md, n >> 16 ); - gcry_md_putc ( md, n >> 8 ); - gcry_md_putc ( md, n ); - /* Note that the next byte may either be 4 or 5. */ - gcry_md_putc ( md, pk->version ); } else { gcry_md_putc ( md, 0x99 ); /* ctb */ - gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */ - gcry_md_putc ( md, n ); - gcry_md_putc ( md, pk->version ); } + gcry_md_putc ( md, n >> 8 ); /* lower bits of the length header. */ + gcry_md_putc ( md, n ); + gcry_md_putc ( md, pk->version ); gcry_md_putc ( md, pk->timestamp >> 24 ); gcry_md_putc ( md, pk->timestamp >> 16 ); gcry_md_putc ( md, pk->timestamp >> 8 ); @@ -260,7 +380,7 @@ do_hash_public_key (gcry_md_hd_t md, PKT_public_key *pk, int use_v5) gcry_md_putc ( md, pk->pubkey_algo ); - if (use_v5) + if (use_v5) /* Hash the 32 bit length */ { n -= 10; gcry_md_putc ( md, n >> 24 ); @@ -936,6 +1056,32 @@ v5_fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) /* + * This is the core of fpr20_from_pk which directly takes a + * fingerprint and its length instead of the public key. See below + * for details. + */ +void +fpr20_from_fpr (const byte *fpr, unsigned int fprlen, byte array[20]) +{ + if (fprlen >= 32) /* v5 fingerprint (or larger) */ + { + memcpy (array + 0, fpr + 20, 4); + memcpy (array + 4, fpr + 24, 4); + memcpy (array + 8, fpr + 28, 4); + memcpy (array + 12, fpr + 0, 4); /* kid[0] */ + memcpy (array + 16, fpr + 4, 4); /* kid[1] */ + } + else if (fprlen == 20) /* v4 fingerprint */ + memcpy (array, fpr, 20); + else /* v3 or too short: fill up with zeroes. */ + { + memset (array, 0, 20); + memcpy (array, fpr, fprlen); + } +} + + +/* * Get FPR20 for the given PK/SK into ARRAY. * * FPR20 is special form of fingerprint of length 20 for the record of @@ -951,19 +1097,7 @@ fpr20_from_pk (PKT_public_key *pk, byte array[20]) if (!pk->fprlen) compute_fingerprint (pk); - if (!array) - array = xmalloc (pk->fprlen); - - if (pk->fprlen == 32) /* v5 fingerprint */ - { - memcpy (array + 0, pk->fpr + 20, 4); - memcpy (array + 4, pk->fpr + 24, 4); - memcpy (array + 8, pk->fpr + 28, 4); - memcpy (array + 12, pk->fpr + 0, 4); /* kid[0] */ - memcpy (array + 16, pk->fpr + 4, 4); /* kid[1] */ - } - else /* v4 fingerprint */ - memcpy (array, pk->fpr, 20); + fpr20_from_fpr (pk->fpr, pk->fprlen, array); } |