mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-02 12:01:32 +01:00
gpg: Implement searching keys via keygrip.
* kbx/keybox-defs.h (struct _keybox_openpgp_key_info): Add field grip. * kbx/keybox-openpgp.c (struct keyparm_s): New. (keygrip_from_keyparm): New. (parse_key): Compute keygrip. * kbx/keybox-search.c (blob_openpgp_has_grip): New. (has_keygrip): Call it. -- This has been marked for too long as not yet working. However, it is a pretty useful feature and will come pretty handy when looking for all keys matching one keygrip. Can be optimized a lot by storing the keygrip in the meta data. This will be done along with the upgrade of KBX for v5 fingerprints. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
f382984966
commit
c128667b3c
@ -135,7 +135,7 @@ RFC-2253 encoded DN of the issuer. See note above.
|
|||||||
@item By keygrip.
|
@item By keygrip.
|
||||||
This is indicated by an ampersand followed by the 40 hex digits of a
|
This is indicated by an ampersand followed by the 40 hex digits of a
|
||||||
keygrip. @command{gpgsm} prints the keygrip when using the command
|
keygrip. @command{gpgsm} prints the keygrip when using the command
|
||||||
@option{--dump-cert}. It does not yet work for OpenPGP keys.
|
@option{--dump-cert}.
|
||||||
|
|
||||||
@cartouche
|
@cartouche
|
||||||
@example
|
@example
|
||||||
@ -171,6 +171,3 @@ Using the RFC-2253 format of DNs has the drawback that it is not
|
|||||||
possible to map them back to the original encoding, however we don't
|
possible to map them back to the original encoding, however we don't
|
||||||
have to do this because our key database stores this encoding as meta
|
have to do this because our key database stores this encoding as meta
|
||||||
data.
|
data.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -329,6 +329,18 @@ dump_fpr (const unsigned char *buffer, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
dump_grip (const unsigned char *buffer, size_t len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i < len; i++, buffer++)
|
||||||
|
{
|
||||||
|
printf ("%02X", buffer[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
|
dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
|
||||||
{
|
{
|
||||||
@ -338,6 +350,9 @@ dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
|
|||||||
info->primary.keyid[6], info->primary.keyid[7] );
|
info->primary.keyid[6], info->primary.keyid[7] );
|
||||||
dump_fpr (info->primary.fpr, info->primary.fprlen);
|
dump_fpr (info->primary.fpr, info->primary.fprlen);
|
||||||
putchar ('\n');
|
putchar ('\n');
|
||||||
|
fputs ("grp ", stdout);
|
||||||
|
dump_grip (info->primary.grip, 20);
|
||||||
|
putchar ('\n');
|
||||||
if (info->nsubkeys)
|
if (info->nsubkeys)
|
||||||
{
|
{
|
||||||
struct _keybox_openpgp_key_info *k;
|
struct _keybox_openpgp_key_info *k;
|
||||||
@ -351,6 +366,9 @@ dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
|
|||||||
k->keyid[6], k->keyid[7] );
|
k->keyid[6], k->keyid[7] );
|
||||||
dump_fpr (k->fpr, k->fprlen);
|
dump_fpr (k->fpr, k->fprlen);
|
||||||
putchar ('\n');
|
putchar ('\n');
|
||||||
|
fputs ("grp ", stdout);
|
||||||
|
dump_grip (k->grip, 20);
|
||||||
|
putchar ('\n');
|
||||||
k = k->next;
|
k = k->next;
|
||||||
}
|
}
|
||||||
while (k);
|
while (k);
|
||||||
|
@ -94,11 +94,12 @@ struct keybox_handle {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Openpgp helper structures. */
|
/* OpenPGP helper structures. */
|
||||||
struct _keybox_openpgp_key_info
|
struct _keybox_openpgp_key_info
|
||||||
{
|
{
|
||||||
struct _keybox_openpgp_key_info *next;
|
struct _keybox_openpgp_key_info *next;
|
||||||
int algo;
|
int algo;
|
||||||
|
unsigned char grip[20];
|
||||||
unsigned char keyid[8];
|
unsigned char keyid[8];
|
||||||
int fprlen; /* Either 16 or 20 */
|
int fprlen; /* Either 16 or 20 */
|
||||||
unsigned char fpr[20];
|
unsigned char fpr[20];
|
||||||
|
@ -38,6 +38,13 @@
|
|||||||
#include "../common/openpgpdefs.h"
|
#include "../common/openpgpdefs.h"
|
||||||
#include "../common/host2net.h"
|
#include "../common/host2net.h"
|
||||||
|
|
||||||
|
struct keyparm_s
|
||||||
|
{
|
||||||
|
const char *mpi;
|
||||||
|
int len; /* int to avoid a cast in gcry_sexp_build. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Assume a valid OpenPGP packet at the address pointed to by BUFBTR
|
/* Assume a valid OpenPGP packet at the address pointed to by BUFBTR
|
||||||
which has a maximum length as stored at BUFLEN. Return the header
|
which has a maximum length as stored at BUFLEN. Return the header
|
||||||
information of that packet and advance the pointer stored at BUFPTR
|
information of that packet and advance the pointer stored at BUFPTR
|
||||||
@ -165,6 +172,86 @@ next_packet (unsigned char const **bufptr, size_t *buflen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Take a list of key parameters KP for the OpenPGP ALGO and compute
|
||||||
|
* the keygrip which will be stored at GRIP. GRIP needs to be a
|
||||||
|
* buffer of 20 bytes. */
|
||||||
|
static gpg_error_t
|
||||||
|
keygrip_from_keyparm (int algo, struct keyparm_s *kp, unsigned char *grip)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
gcry_sexp_t s_pkey = NULL;
|
||||||
|
|
||||||
|
switch (algo)
|
||||||
|
{
|
||||||
|
case PUBKEY_ALGO_DSA:
|
||||||
|
err = gcry_sexp_build (&s_pkey, NULL,
|
||||||
|
"(public-key(dsa(p%b)(q%b)(g%b)(y%b)))",
|
||||||
|
kp[0].len, kp[0].mpi,
|
||||||
|
kp[1].len, kp[1].mpi,
|
||||||
|
kp[2].len, kp[2].mpi,
|
||||||
|
kp[3].len, kp[3].mpi);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PUBKEY_ALGO_ELGAMAL:
|
||||||
|
case PUBKEY_ALGO_ELGAMAL_E:
|
||||||
|
err = gcry_sexp_build (&s_pkey, NULL,
|
||||||
|
"(public-key(elg(p%b)(g%b)(y%b)))",
|
||||||
|
kp[0].len, kp[0].mpi,
|
||||||
|
kp[1].len, kp[1].mpi,
|
||||||
|
kp[2].len, kp[2].mpi);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PUBKEY_ALGO_RSA:
|
||||||
|
case PUBKEY_ALGO_RSA_S:
|
||||||
|
case PUBKEY_ALGO_RSA_E:
|
||||||
|
err = gcry_sexp_build (&s_pkey, NULL,
|
||||||
|
"(public-key(rsa(n%b)(e%b)))",
|
||||||
|
kp[0].len, kp[0].mpi,
|
||||||
|
kp[1].len, kp[1].mpi);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PUBKEY_ALGO_EDDSA:
|
||||||
|
case PUBKEY_ALGO_ECDSA:
|
||||||
|
case PUBKEY_ALGO_ECDH:
|
||||||
|
{
|
||||||
|
char *curve = openpgp_oidbuf_to_str (kp[0].mpi, kp[0].len);
|
||||||
|
if (!curve)
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = gcry_sexp_build
|
||||||
|
(&s_pkey, NULL,
|
||||||
|
(algo == PUBKEY_ALGO_EDDSA)?
|
||||||
|
"(public-key(ecc(curve%s)(flags eddsa)(q%b)))":
|
||||||
|
(algo == PUBKEY_ALGO_ECDH
|
||||||
|
&& openpgp_oidbuf_is_cv25519 (kp[0].mpi, kp[0].len))?
|
||||||
|
"(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))":
|
||||||
|
"(public-key(ecc(curve%s)(q%b)))",
|
||||||
|
curve, kp[1].len, kp[1].mpi);
|
||||||
|
xfree (curve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!err && !gcry_pk_get_keygrip (s_pkey, grip))
|
||||||
|
{
|
||||||
|
log_info ("kbx: error computing keygrip\n");
|
||||||
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
gcry_sexp_release (s_pkey);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
memset (grip, 0, 20);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Parse a key packet and store the information in KI. */
|
/* Parse a key packet and store the information in KI. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
parse_key (const unsigned char *data, size_t datalen,
|
parse_key (const unsigned char *data, size_t datalen,
|
||||||
@ -176,10 +263,10 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||||||
size_t n;
|
size_t n;
|
||||||
int npkey;
|
int npkey;
|
||||||
unsigned char hashbuffer[768];
|
unsigned char hashbuffer[768];
|
||||||
const unsigned char *mpi_n = NULL;
|
|
||||||
size_t mpi_n_len = 0, mpi_e_len = 0;
|
|
||||||
gcry_md_hd_t md;
|
gcry_md_hd_t md;
|
||||||
int is_ecc = 0;
|
int is_ecc = 0;
|
||||||
|
struct keyparm_s keyparm[OPENPGP_MAX_NPKEY];
|
||||||
|
unsigned char *helpmpibuf[OPENPGP_MAX_NPKEY] = { NULL };
|
||||||
|
|
||||||
if (datalen < 5)
|
if (datalen < 5)
|
||||||
return gpg_error (GPG_ERR_INV_PACKET);
|
return gpg_error (GPG_ERR_INV_PACKET);
|
||||||
@ -245,6 +332,9 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||||||
nbytes++; /* The size byte itself. */
|
nbytes++; /* The size byte itself. */
|
||||||
if (datalen < nbytes)
|
if (datalen < nbytes)
|
||||||
return gpg_error (GPG_ERR_INV_PACKET);
|
return gpg_error (GPG_ERR_INV_PACKET);
|
||||||
|
|
||||||
|
keyparm[i].mpi = data;
|
||||||
|
keyparm[i].len = nbytes;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -254,21 +344,40 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||||||
nbytes = (nbits+7) / 8;
|
nbytes = (nbits+7) / 8;
|
||||||
if (datalen < nbytes)
|
if (datalen < nbytes)
|
||||||
return gpg_error (GPG_ERR_INV_PACKET);
|
return gpg_error (GPG_ERR_INV_PACKET);
|
||||||
/* For use by v3 fingerprint calculation we need to know the RSA
|
|
||||||
modulus and exponent. */
|
keyparm[i].mpi = data;
|
||||||
if (i==0)
|
keyparm[i].len = nbytes;
|
||||||
{
|
|
||||||
mpi_n = data;
|
|
||||||
mpi_n_len = nbytes;
|
|
||||||
}
|
|
||||||
else if (i==1)
|
|
||||||
mpi_e_len = nbytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data += nbytes; datalen -= nbytes;
|
data += nbytes; datalen -= nbytes;
|
||||||
}
|
}
|
||||||
n = data - data_start;
|
n = data - data_start;
|
||||||
|
|
||||||
|
|
||||||
|
/* Note: Starting here we need to jump to leave on error. */
|
||||||
|
|
||||||
|
/* Make sure the MPIs are unsigned. */
|
||||||
|
for (i=0; i < npkey; i++)
|
||||||
|
{
|
||||||
|
if (!keyparm[i].len || (keyparm[i].mpi[0] & 0x80))
|
||||||
|
{
|
||||||
|
helpmpibuf[i] = xtrymalloc (1+keyparm[i].len);
|
||||||
|
if (!helpmpibuf[i])
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
helpmpibuf[i][0] = 0;
|
||||||
|
memcpy (helpmpibuf[i]+1, keyparm[i].mpi, keyparm[i].len);
|
||||||
|
keyparm[i].mpi = helpmpibuf[i];
|
||||||
|
keyparm[i].len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = keygrip_from_keyparm (algorithm, keyparm, ki->grip);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
if (version < 4)
|
if (version < 4)
|
||||||
{
|
{
|
||||||
/* We do not support any other algorithm than RSA in v3
|
/* We do not support any other algorithm than RSA in v3
|
||||||
@ -279,20 +388,20 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||||||
err = gcry_md_open (&md, GCRY_MD_MD5, 0);
|
err = gcry_md_open (&md, GCRY_MD_MD5, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err; /* Oops */
|
return err; /* Oops */
|
||||||
gcry_md_write (md, mpi_n, mpi_n_len);
|
gcry_md_write (md, keyparm[0].mpi, keyparm[0].len);
|
||||||
gcry_md_write (md, mpi_n+mpi_n_len+2, mpi_e_len);
|
gcry_md_write (md, keyparm[1].mpi, keyparm[1].len);
|
||||||
memcpy (ki->fpr, gcry_md_read (md, 0), 16);
|
memcpy (ki->fpr, gcry_md_read (md, 0), 16);
|
||||||
gcry_md_close (md);
|
gcry_md_close (md);
|
||||||
ki->fprlen = 16;
|
ki->fprlen = 16;
|
||||||
|
|
||||||
if (mpi_n_len < 8)
|
if (keyparm[0].len < 8)
|
||||||
{
|
{
|
||||||
/* Moduli less than 64 bit are out of the specs scope. Zero
|
/* Moduli less than 64 bit are out of the specs scope. Zero
|
||||||
them out because this is what gpg does too. */
|
them out because this is what gpg does too. */
|
||||||
memset (ki->keyid, 0, 8);
|
memset (ki->keyid, 0, 8);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
memcpy (ki->keyid, mpi_n + mpi_n_len - 8, 8);
|
memcpy (ki->keyid, keyparm[0].mpi + keyparm[0].len - 8, 8);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -327,7 +436,11 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||||||
memcpy (ki->keyid, ki->fpr+12, 8);
|
memcpy (ki->keyid, ki->fpr+12, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
leave:
|
||||||
|
for (i=0; i < npkey; i++)
|
||||||
|
xfree (helpmpibuf[i]);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -497,6 +497,58 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
|
||||||
|
* We don't have the keygrips as meta data, thus we need to parse the
|
||||||
|
* certificate. Fixme: We might want to return proper error codes
|
||||||
|
* instead of failing a search for invalid certificates etc. */
|
||||||
|
static int
|
||||||
|
blob_openpgp_has_grip (KEYBOXBLOB blob, const unsigned char *grip)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
const unsigned char *buffer;
|
||||||
|
size_t length;
|
||||||
|
size_t cert_off, cert_len;
|
||||||
|
struct _keybox_openpgp_info info;
|
||||||
|
struct _keybox_openpgp_key_info *k;
|
||||||
|
|
||||||
|
buffer = _keybox_get_blob_image (blob, &length);
|
||||||
|
if (length < 40)
|
||||||
|
return 0; /* Too short. */
|
||||||
|
cert_off = get32 (buffer+8);
|
||||||
|
cert_len = get32 (buffer+12);
|
||||||
|
if ((uint64_t)cert_off+(uint64_t)cert_len > (uint64_t)length)
|
||||||
|
return 0; /* Too short. */
|
||||||
|
|
||||||
|
if (_keybox_parse_openpgp (buffer + cert_off, cert_len, NULL, &info))
|
||||||
|
return 0; /* Parse error. */
|
||||||
|
|
||||||
|
if (!memcmp (info.primary.grip, grip, 20))
|
||||||
|
{
|
||||||
|
rc = 1;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.nsubkeys)
|
||||||
|
{
|
||||||
|
k = &info.subkeys;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!memcmp (k->grip, grip, 20))
|
||||||
|
{
|
||||||
|
rc = 1;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
k = k->next;
|
||||||
|
}
|
||||||
|
while (k);
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
_keybox_destroy_openpgp_info (&info);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef KEYBOX_WITH_X509
|
#ifdef KEYBOX_WITH_X509
|
||||||
/* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
|
/* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
|
||||||
We don't have the keygrips as meta data, thus we need to parse the
|
We don't have the keygrips as meta data, thus we need to parse the
|
||||||
@ -606,12 +658,11 @@ has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
|
|||||||
static inline int
|
static inline int
|
||||||
has_keygrip (KEYBOXBLOB blob, const unsigned char *grip)
|
has_keygrip (KEYBOXBLOB blob, const unsigned char *grip)
|
||||||
{
|
{
|
||||||
|
if (blob_get_type (blob) == KEYBOX_BLOBTYPE_PGP)
|
||||||
|
return blob_openpgp_has_grip (blob, grip);
|
||||||
#ifdef KEYBOX_WITH_X509
|
#ifdef KEYBOX_WITH_X509
|
||||||
if (blob_get_type (blob) == KEYBOX_BLOBTYPE_X509)
|
if (blob_get_type (blob) == KEYBOX_BLOBTYPE_X509)
|
||||||
return blob_x509_has_grip (blob, grip);
|
return blob_x509_has_grip (blob, grip);
|
||||||
#else
|
|
||||||
(void)blob;
|
|
||||||
(void)grip;
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user