mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Merge branch 'master' into switch-to-gpgk
--
This commit is contained in:
commit
a52d883fdb
237 changed files with 21268 additions and 4575 deletions
|
@ -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
|
||||
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] );
|
||||
dump_fpr (info->primary.fpr, info->primary.fprlen);
|
||||
putchar ('\n');
|
||||
fputs ("grp ", stdout);
|
||||
dump_grip (info->primary.grip, 20);
|
||||
putchar ('\n');
|
||||
if (info->nsubkeys)
|
||||
{
|
||||
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] );
|
||||
dump_fpr (k->fpr, k->fprlen);
|
||||
putchar ('\n');
|
||||
fputs ("grp ", stdout);
|
||||
dump_grip (k->grip, 20);
|
||||
putchar ('\n');
|
||||
k = k->next;
|
||||
}
|
||||
while (k);
|
||||
|
|
|
@ -62,7 +62,8 @@
|
|||
2 = OpenPGP
|
||||
3 = X509
|
||||
- byte Version number of this blob type
|
||||
1 = The only defined value
|
||||
1 = Blob with 20 byte fingerprints
|
||||
2 = Blob with 32 byte fingerprints and no keyids.
|
||||
- u16 Blob flags
|
||||
bit 0 = contains secret key material (not used)
|
||||
bit 1 = ephemeral blob (e.g. used while querying external resources)
|
||||
|
@ -70,19 +71,36 @@
|
|||
certificate
|
||||
- u32 The length of the keyblock or certificate
|
||||
- u16 [NKEYS] Number of keys (at least 1!) [X509: always 1]
|
||||
- u16 Size of the key information structure (at least 28).
|
||||
- u16 Size of the key information structure (at least 28 or 56).
|
||||
- NKEYS times:
|
||||
Version 1 blob:
|
||||
- b20 The fingerprint of the key.
|
||||
Fingerprints are always 20 bytes, MD5 left padded with zeroes.
|
||||
- u32 Offset to the n-th key's keyID (a keyID is always 8 byte)
|
||||
or 0 if not known which is the case only for X.509.
|
||||
Note that this separate keyid is not anymore used by
|
||||
gnupg since the support for v3 keys has been removed.
|
||||
We create this field anyway for backward compatibility with
|
||||
old EOL-ed versions. Eventually we will completely move
|
||||
to the version 2 blob format.
|
||||
- u16 Key flags
|
||||
bit 0 = qualified signature (not yet implemented}
|
||||
- u16 RFU
|
||||
- bN Optional filler up to the specified length of this
|
||||
structure.
|
||||
Version 2 blob:
|
||||
- b32 The fingerprint of the key. This fingerprint is
|
||||
either 20 or 32 bytes. A 20 byte fingerprint is
|
||||
right filled with zeroes.
|
||||
- u16 Key flags
|
||||
bit 0 = qualified signature (not yet implemented}
|
||||
bit 7 = 32 byte fingerprint in use.
|
||||
- u16 RFU
|
||||
- b20 keygrip
|
||||
- bN Optional filler up to the specified length of this
|
||||
structure.
|
||||
- u16 Size of the serial number (may be zero)
|
||||
- bN The serial number. N as giiven above.
|
||||
- bN The serial number. N as given above.
|
||||
- u16 Number of user IDs
|
||||
- u16 [NUIDS] Size of user ID information structure
|
||||
- NUIDS times:
|
||||
|
@ -172,15 +190,12 @@ struct membuf {
|
|||
};
|
||||
|
||||
|
||||
/* #if MAX_FINGERPRINT_LEN < 20 */
|
||||
/* #error fingerprints are 20 bytes */
|
||||
/* #endif */
|
||||
|
||||
struct keyboxblob_key {
|
||||
char fpr[20];
|
||||
char fpr[32];
|
||||
u32 off_kid;
|
||||
ulong off_kid_addr;
|
||||
u16 flags;
|
||||
u16 fprlen; /* Either 20 or 32 */
|
||||
};
|
||||
struct keyboxblob_uid {
|
||||
u32 off;
|
||||
|
@ -380,10 +395,9 @@ pgp_create_key_part_single (KEYBOXBLOB blob, int n,
|
|||
int off;
|
||||
|
||||
fprlen = kinfo->fprlen;
|
||||
if (fprlen > 20)
|
||||
fprlen = 20;
|
||||
memcpy (blob->keys[n].fpr, kinfo->fpr, fprlen);
|
||||
if (fprlen != 20) /* v3 fpr - shift right and fill with zeroes. */
|
||||
blob->keys[n].fprlen = fprlen;
|
||||
if (fprlen < 20) /* v3 fpr - shift right and fill with zeroes. */
|
||||
{
|
||||
memmove (blob->keys[n].fpr + 20 - fprlen, blob->keys[n].fpr, fprlen);
|
||||
memset (blob->keys[n].fpr, 0, 20 - fprlen);
|
||||
|
@ -533,30 +547,51 @@ release_kid_list (struct keyid_list *kl)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* Create a new blob header. If WANT_FPR32 is set a version 2 blob is
|
||||
* created. */
|
||||
static int
|
||||
create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral)
|
||||
create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral,
|
||||
int want_fpr32)
|
||||
{
|
||||
struct membuf *a = blob->buf;
|
||||
int i;
|
||||
|
||||
put32 ( a, 0 ); /* blob length, needs fixup */
|
||||
put8 ( a, blobtype);
|
||||
put8 ( a, 1 ); /* blob type version */
|
||||
put8 ( a, want_fpr32? 2:1 ); /* blob type version */
|
||||
put16 ( a, as_ephemeral? 2:0 ); /* blob flags */
|
||||
|
||||
put32 ( a, 0 ); /* offset to the raw data, needs fixup */
|
||||
put32 ( a, 0 ); /* length of the raw data, needs fixup */
|
||||
|
||||
put16 ( a, blob->nkeys );
|
||||
put16 ( a, 20 + 4 + 2 + 2 ); /* size of key info */
|
||||
if (want_fpr32)
|
||||
put16 ( a, 32 + 2 + 2 + 20); /* size of key info */
|
||||
else
|
||||
put16 ( a, 20 + 4 + 2 + 2 ); /* size of key info */
|
||||
for ( i=0; i < blob->nkeys; i++ )
|
||||
{
|
||||
put_membuf (a, blob->keys[i].fpr, 20);
|
||||
blob->keys[i].off_kid_addr = a->len;
|
||||
put32 ( a, 0 ); /* offset to keyid, fixed up later */
|
||||
put16 ( a, blob->keys[i].flags );
|
||||
put16 ( a, 0 ); /* reserved */
|
||||
if (want_fpr32)
|
||||
{
|
||||
put_membuf (a, blob->keys[i].fpr, blob->keys[i].fprlen);
|
||||
blob->keys[i].off_kid_addr = a->len;
|
||||
if (blob->keys[i].fprlen == 32)
|
||||
put16 ( a, (blob->keys[i].flags | 0x80));
|
||||
else
|
||||
put16 ( a, blob->keys[i].flags);
|
||||
put16 ( a, 0 ); /* reserved */
|
||||
/* FIXME: Put the real grip here instead of the filler. */
|
||||
put_membuf (a, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_assert (blob->keys[i].fprlen <= 20);
|
||||
put_membuf (a, blob->keys[i].fpr, 20);
|
||||
blob->keys[i].off_kid_addr = a->len;
|
||||
put32 ( a, 0 ); /* offset to keyid, fixed up later */
|
||||
put16 ( a, blob->keys[i].flags );
|
||||
put16 ( a, 0 ); /* reserved */
|
||||
}
|
||||
}
|
||||
|
||||
put16 (a, blob->seriallen); /*fixme: check that it fits into 16 bits*/
|
||||
|
@ -593,11 +628,14 @@ create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral)
|
|||
|
||||
/* space where we write keyIDs and other stuff so that the
|
||||
pointers can actually point to somewhere */
|
||||
if (blobtype == KEYBOX_BLOBTYPE_PGP)
|
||||
if (blobtype == KEYBOX_BLOBTYPE_PGP && !want_fpr32)
|
||||
{
|
||||
/* We need to store the keyids for all pgp v3 keys because those key
|
||||
IDs are not part of the fingerprint. While we are doing that, we
|
||||
fixup all the keyID offsets */
|
||||
/* For version 1 blobs, we need to store the keyids for all v3
|
||||
* keys because those key IDs are not part of the fingerprint.
|
||||
* While we are doing that, we fixup all the keyID offsets. For
|
||||
* version 2 blobs (which can't carry v3 keys) we compute the
|
||||
* keyids in the fly because they are just stripped down
|
||||
* fingerprints. */
|
||||
for (i=0; i < blob->nkeys; i++ )
|
||||
{
|
||||
if (blob->keys[i].off_kid)
|
||||
|
@ -616,7 +654,7 @@ create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral)
|
|||
if (blobtype == KEYBOX_BLOBTYPE_X509)
|
||||
{
|
||||
/* We don't want to point to ASN.1 encoded UserIDs (DNs) but to
|
||||
the utf-8 string represenation of them */
|
||||
the utf-8 string representation of them */
|
||||
for (i=0; i < blob->nuids; i++ )
|
||||
{
|
||||
if (blob->uids[i].name)
|
||||
|
@ -711,9 +749,27 @@ _keybox_create_openpgp_blob (KEYBOXBLOB *r_blob,
|
|||
{
|
||||
gpg_error_t err;
|
||||
KEYBOXBLOB blob;
|
||||
int need_fpr32 = 0;
|
||||
|
||||
*r_blob = NULL;
|
||||
|
||||
|
||||
/* Check whether we need a blob with 32 bit fingerprints. We could
|
||||
* use this always but for backward compatiblity we do this only for
|
||||
* v5 keys. */
|
||||
if (info->primary.version == 5)
|
||||
need_fpr32 = 1;
|
||||
else
|
||||
{
|
||||
struct _keybox_openpgp_key_info *kinfo;
|
||||
for (kinfo = &info->subkeys; kinfo; kinfo = kinfo->next)
|
||||
if (kinfo->version == 5)
|
||||
{
|
||||
need_fpr32 = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
blob = xtrycalloc (1, sizeof *blob);
|
||||
if (!blob)
|
||||
return gpg_error_from_syserror ();
|
||||
|
@ -756,7 +812,8 @@ _keybox_create_openpgp_blob (KEYBOXBLOB *r_blob,
|
|||
|
||||
init_membuf (&blob->bufbuf, 1024);
|
||||
blob->buf = &blob->bufbuf;
|
||||
err = create_blob_header (blob, KEYBOX_BLOBTYPE_PGP, as_ephemeral);
|
||||
err = create_blob_header (blob, KEYBOX_BLOBTYPE_PGP,
|
||||
as_ephemeral, need_fpr32);
|
||||
if (err)
|
||||
goto leave;
|
||||
err = pgp_create_blob_keyblock (blob, image, imagelen);
|
||||
|
@ -943,7 +1000,7 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert,
|
|||
init_membuf (&blob->bufbuf, 1024);
|
||||
blob->buf = &blob->bufbuf;
|
||||
/* write out what we already have */
|
||||
rc = create_blob_header (blob, KEYBOX_BLOBTYPE_X509, as_ephemeral);
|
||||
rc = create_blob_header (blob, KEYBOX_BLOBTYPE_X509, as_ephemeral, 0);
|
||||
if (rc)
|
||||
goto leave;
|
||||
rc = x509_create_blob_cert (blob, cert);
|
||||
|
|
|
@ -94,14 +94,16 @@ struct keybox_handle {
|
|||
};
|
||||
|
||||
|
||||
/* Openpgp helper structures. */
|
||||
/* OpenPGP helper structures. */
|
||||
struct _keybox_openpgp_key_info
|
||||
{
|
||||
struct _keybox_openpgp_key_info *next;
|
||||
int algo;
|
||||
int version;
|
||||
unsigned char grip[20];
|
||||
unsigned char keyid[8];
|
||||
int fprlen; /* Either 16 or 20 */
|
||||
unsigned char fpr[20];
|
||||
int fprlen; /* Either 16, 20 or 32 */
|
||||
unsigned char fpr[32];
|
||||
};
|
||||
|
||||
struct _keybox_openpgp_uid_info
|
||||
|
|
|
@ -170,6 +170,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
|
|||
ulong nserial;
|
||||
ulong unhashed;
|
||||
const byte *p;
|
||||
int is_fpr32; /* blob ersion 2 */
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
|
||||
|
@ -207,7 +208,9 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
|
|||
fprintf (fp, "[can't dump this blob type]\n");
|
||||
return 0;
|
||||
}
|
||||
/* Here we have either BLOGTYPE_X509 or BLOBTYPE_OPENPGP */
|
||||
fprintf (fp, "Version: %d\n", buffer[5]);
|
||||
is_fpr32 = buffer[5] == 2;
|
||||
|
||||
if (length < 40)
|
||||
{
|
||||
|
@ -267,15 +270,24 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
|
|||
ulong kidoff, kflags;
|
||||
|
||||
fprintf (fp, "Key-Fpr[%lu]: ", n );
|
||||
for (i=0; i < 20; i++ )
|
||||
fprintf (fp, "%02X", p[i]);
|
||||
kidoff = get32 (p + 20);
|
||||
fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
|
||||
fprintf (fp, "Key-Kid[%lu]: ", n );
|
||||
/* fixme: check bounds */
|
||||
for (i=0; i < 8; i++ )
|
||||
fprintf (fp, "%02X", buffer[kidoff+i] );
|
||||
kflags = get16 (p + 24 );
|
||||
if (is_fpr32)
|
||||
{
|
||||
kflags = get16 (p + 32 );
|
||||
for (i=0; i < ((kflags & 0x80)?32:20); i++ )
|
||||
fprintf (fp, "%02X", p[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < 20; i++ )
|
||||
fprintf (fp, "%02X", p[i]);
|
||||
kidoff = get32 (p + 20);
|
||||
fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
|
||||
fprintf (fp, "Key-Kid[%lu]: ", n );
|
||||
/* fixme: check bounds */
|
||||
for (i=0; i < 8; i++ )
|
||||
fprintf (fp, "%02X", buffer[kidoff+i] );
|
||||
kflags = get16 (p + 24 );
|
||||
}
|
||||
fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* keybox_strerror:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* This function returns a textual representation of the given
|
||||
* errorcode. If this is an unknown value, a string with the value
|
||||
* is returned (Beware: it is hold in a static buffer).
|
||||
*
|
||||
|
|
|
@ -38,6 +38,13 @@
|
|||
#include "../common/openpgpdefs.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
|
||||
which has a maximum length as stored at BUFLEN. Return the header
|
||||
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. */
|
||||
static gpg_error_t
|
||||
parse_key (const unsigned char *data, size_t datalen,
|
||||
|
@ -176,16 +263,19 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||
size_t n;
|
||||
int npkey;
|
||||
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;
|
||||
int is_ecc = 0;
|
||||
int is_v5;
|
||||
/* unsigned int pkbytes; for v5: # of octets of the public key params. */
|
||||
struct keyparm_s keyparm[OPENPGP_MAX_NPKEY];
|
||||
unsigned char *helpmpibuf[OPENPGP_MAX_NPKEY] = { NULL };
|
||||
|
||||
if (datalen < 5)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
version = *data++; datalen--;
|
||||
if (version < 2 || version > 4 )
|
||||
if (version < 2 || version > 5 )
|
||||
return gpg_error (GPG_ERR_INV_PACKET); /* Invalid version. */
|
||||
is_v5 = version == 5;
|
||||
|
||||
/*timestamp = ((data[0]<<24)|(data[1]<<16)|(data[2]<<8)|(data[3]));*/
|
||||
data +=4; datalen -=4;
|
||||
|
@ -201,6 +291,15 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
algorithm = *data++; datalen--;
|
||||
|
||||
if (is_v5)
|
||||
{
|
||||
if (datalen < 4)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
/* pkbytes = buf32_to_uint (data); */
|
||||
data += 4;
|
||||
datalen -= 4;
|
||||
}
|
||||
|
||||
switch (algorithm)
|
||||
{
|
||||
case PUBKEY_ALGO_RSA:
|
||||
|
@ -228,6 +327,7 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||
return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
|
||||
}
|
||||
|
||||
ki->version = version;
|
||||
ki->algo = algorithm;
|
||||
|
||||
for (i=0; i < npkey; i++ )
|
||||
|
@ -245,6 +345,9 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||
nbytes++; /* The size byte itself. */
|
||||
if (datalen < nbytes)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
|
||||
keyparm[i].mpi = data;
|
||||
keyparm[i].len = nbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -254,21 +357,40 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||
nbytes = (nbits+7) / 8;
|
||||
if (datalen < nbytes)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
/* For use by v3 fingerprint calculation we need to know the RSA
|
||||
modulus and exponent. */
|
||||
if (i==0)
|
||||
{
|
||||
mpi_n = data;
|
||||
mpi_n_len = nbytes;
|
||||
}
|
||||
else if (i==1)
|
||||
mpi_e_len = nbytes;
|
||||
|
||||
keyparm[i].mpi = data;
|
||||
keyparm[i].len = nbytes;
|
||||
}
|
||||
|
||||
data += nbytes; datalen -= nbytes;
|
||||
}
|
||||
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)
|
||||
{
|
||||
/* We do not support any other algorithm than RSA in v3
|
||||
|
@ -279,20 +401,20 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||
err = gcry_md_open (&md, GCRY_MD_MD5, 0);
|
||||
if (err)
|
||||
return err; /* Oops */
|
||||
gcry_md_write (md, mpi_n, mpi_n_len);
|
||||
gcry_md_write (md, mpi_n+mpi_n_len+2, mpi_e_len);
|
||||
gcry_md_write (md, keyparm[0].mpi, keyparm[0].len);
|
||||
gcry_md_write (md, keyparm[1].mpi, keyparm[1].len);
|
||||
memcpy (ki->fpr, gcry_md_read (md, 0), 16);
|
||||
gcry_md_close (md);
|
||||
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
|
||||
them out because this is what gpg does too. */
|
||||
memset (ki->keyid, 0, 8);
|
||||
}
|
||||
else
|
||||
memcpy (ki->keyid, mpi_n + mpi_n_len - 8, 8);
|
||||
memcpy (ki->keyid, keyparm[0].mpi + keyparm[0].len - 8, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -302,32 +424,70 @@ parse_key (const unsigned char *data, size_t datalen,
|
|||
have a scatter-gather enabled hash function. What we do here
|
||||
is to use a static buffer if this one is large enough and
|
||||
only use the regular hash functions if this buffer is not
|
||||
large enough. */
|
||||
if ( 3 + n < sizeof hashbuffer )
|
||||
large enough.
|
||||
FIXME: Factor this out to a shared fingerprint function.
|
||||
*/
|
||||
if (version == 5)
|
||||
{
|
||||
hashbuffer[0] = 0x99; /* CTB */
|
||||
hashbuffer[1] = (n >> 8); /* 2 byte length header. */
|
||||
hashbuffer[2] = n;
|
||||
memcpy (hashbuffer + 3, data_start, n);
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, ki->fpr, hashbuffer, 3 + n);
|
||||
if ( 5 + n < sizeof hashbuffer )
|
||||
{
|
||||
hashbuffer[0] = 0x9a; /* CTB */
|
||||
hashbuffer[1] = (n >> 24);/* 4 byte length header. */
|
||||
hashbuffer[2] = (n >> 16);
|
||||
hashbuffer[3] = (n >> 8);
|
||||
hashbuffer[4] = (n );
|
||||
memcpy (hashbuffer + 5, data_start, n);
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA256, ki->fpr, hashbuffer, 5 + n);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = gcry_md_open (&md, GCRY_MD_SHA256, 0);
|
||||
if (err)
|
||||
return err; /* Oops */
|
||||
gcry_md_putc (md, 0x9a ); /* CTB */
|
||||
gcry_md_putc (md, (n >> 24)); /* 4 byte length header. */
|
||||
gcry_md_putc (md, (n >> 16));
|
||||
gcry_md_putc (md, (n >> 8));
|
||||
gcry_md_putc (md, (n ));
|
||||
gcry_md_write (md, data_start, n);
|
||||
memcpy (ki->fpr, gcry_md_read (md, 0), 32);
|
||||
gcry_md_close (md);
|
||||
}
|
||||
ki->fprlen = 32;
|
||||
memcpy (ki->keyid, ki->fpr, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
|
||||
if (err)
|
||||
return err; /* Oops */
|
||||
gcry_md_putc (md, 0x99 ); /* CTB */
|
||||
gcry_md_putc (md, (n >> 8) ); /* 2 byte length header. */
|
||||
gcry_md_putc (md, n );
|
||||
gcry_md_write (md, data_start, n);
|
||||
memcpy (ki->fpr, gcry_md_read (md, 0), 20);
|
||||
gcry_md_close (md);
|
||||
if ( 3 + n < sizeof hashbuffer )
|
||||
{
|
||||
hashbuffer[0] = 0x99; /* CTB */
|
||||
hashbuffer[1] = (n >> 8); /* 2 byte length header. */
|
||||
hashbuffer[2] = (n );
|
||||
memcpy (hashbuffer + 3, data_start, n);
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, ki->fpr, hashbuffer, 3 + n);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
|
||||
if (err)
|
||||
return err; /* Oops */
|
||||
gcry_md_putc (md, 0x99 ); /* CTB */
|
||||
gcry_md_putc (md, (n >> 8)); /* 2 byte length header. */
|
||||
gcry_md_putc (md, (n ));
|
||||
gcry_md_write (md, data_start, n);
|
||||
memcpy (ki->fpr, gcry_md_read (md, 0), 20);
|
||||
gcry_md_close (md);
|
||||
}
|
||||
ki->fprlen = 20;
|
||||
memcpy (ki->keyid, ki->fpr+12, 8);
|
||||
}
|
||||
ki->fprlen = 20;
|
||||
memcpy (ki->keyid, ki->fpr+12, 8);
|
||||
}
|
||||
|
||||
return 0;
|
||||
leave:
|
||||
for (i=0; i < npkey; i++)
|
||||
xfree (helpmpibuf[i]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,9 +36,7 @@ typedef enum {
|
|||
KEYDB_SEARCH_MODE_WORDS,
|
||||
KEYDB_SEARCH_MODE_SHORT_KID,
|
||||
KEYDB_SEARCH_MODE_LONG_KID,
|
||||
KEYDB_SEARCH_MODE_FPR16,
|
||||
KEYDB_SEARCH_MODE_FPR20,
|
||||
KEYDB_SEARCH_MODE_FPR,
|
||||
KEYDB_SEARCH_MODE_FPR, /* (Length of fpr in .fprlen) */
|
||||
KEYDB_SEARCH_MODE_ISSUER,
|
||||
KEYDB_SEARCH_MODE_ISSUER_SN,
|
||||
KEYDB_SEARCH_MODE_SN,
|
||||
|
@ -49,7 +47,7 @@ typedef enum {
|
|||
} KeydbSearchMode;
|
||||
|
||||
|
||||
/* Forwward declaration. See g10/packet.h. */
|
||||
/* Forward declaration. See g10/packet.h. */
|
||||
struct gpg_pkt_user_id_s;
|
||||
typedef struct gpg_pkt_user_id_s *gpg_pkt_user_id_t;
|
||||
|
||||
|
@ -69,10 +67,11 @@ struct keydb_search_desc
|
|||
int snlen; /* -1 := sn is a hex string */
|
||||
union {
|
||||
const char *name;
|
||||
unsigned char fpr[24];
|
||||
unsigned char fpr[32];
|
||||
u32 kid[2]; /* Note that this is in native endianness. */
|
||||
unsigned char grip[20];
|
||||
} u;
|
||||
byte fprlen; /* Only used with KEYDB_SEARCH_MODE_FPR. */
|
||||
int exact; /* Use exactly this key ('!' suffix in gpg). */
|
||||
};
|
||||
|
||||
|
|
|
@ -66,18 +66,31 @@ blob_get_first_keyid (KEYBOXBLOB blob, u32 *kid)
|
|||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length, nkeys, keyinfolen;
|
||||
int fpr32;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 48)
|
||||
return 0; /* blob too short */
|
||||
fpr32 = buffer[5] == 2;
|
||||
if (fpr32 && length < 56)
|
||||
return 0; /* blob to short */
|
||||
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18);
|
||||
if (!nkeys || keyinfolen < 28)
|
||||
if (!nkeys || keyinfolen < (fpr32?56:28))
|
||||
return 0; /* invalid blob */
|
||||
|
||||
kid[0] = get32 (buffer + 32);
|
||||
kid[1] = get32 (buffer + 36);
|
||||
if (fpr32 && (get16 (buffer + 20 + 32) & 0x80))
|
||||
{
|
||||
/* 32 byte fingerprint. */
|
||||
kid[0] = get32 (buffer + 20);
|
||||
kid[1] = get32 (buffer + 20 + 4);
|
||||
}
|
||||
else /* 20 byte fingerprint. */
|
||||
{
|
||||
kid[0] = get32 (buffer + 20 + 12);
|
||||
kid[1] = get32 (buffer + 20 + 16);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -229,22 +242,23 @@ blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
|
|||
For X.509 this is always 1, for OpenPGP this is 1 for the primary
|
||||
key and 2 and more for the subkeys. */
|
||||
static int
|
||||
blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
|
||||
blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
int idx;
|
||||
int idx, fpr32, storedfprlen;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
fpr32 = buffer[5] == 2;
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
if (keyinfolen < (fpr32?56:28))
|
||||
return 0; /* invalid blob */
|
||||
pos = 20;
|
||||
if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length)
|
||||
|
@ -253,12 +267,19 @@ blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
|
|||
for (idx=0; idx < nkeys; idx++)
|
||||
{
|
||||
off = pos + idx*keyinfolen;
|
||||
if (!memcmp (buffer + off, fpr, 20))
|
||||
if (fpr32)
|
||||
storedfprlen = (get16 (buffer + off + 32) & 0x80)? 32:20;
|
||||
else
|
||||
storedfprlen = 20;
|
||||
if (storedfprlen == fprlen
|
||||
&& !memcmp (buffer + off, fpr, storedfprlen))
|
||||
return idx+1; /* found */
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
/* Helper for has_short_kid and has_long_kid. */
|
||||
static int
|
||||
blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
|
||||
int fproff, int fprlen)
|
||||
|
@ -267,25 +288,33 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
|
|||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
int idx;
|
||||
int idx, fpr32, storedfprlen;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
fpr32 = buffer[5] == 2;
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
if (keyinfolen < (fpr32?56:28))
|
||||
return 0; /* invalid blob */
|
||||
pos = 20;
|
||||
if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
if (fpr32)
|
||||
fproff = 0; /* keyid are the high-order bits. */
|
||||
for (idx=0; idx < nkeys; idx++)
|
||||
{
|
||||
off = pos + idx*keyinfolen;
|
||||
if (!memcmp (buffer + off + fproff, fpr, fprlen))
|
||||
if (fpr32)
|
||||
storedfprlen = (get16 (buffer + off + 32) & 0x80)? 32:20;
|
||||
else
|
||||
storedfprlen = 20;
|
||||
if (storedfprlen == fproff + fprlen
|
||||
&& !memcmp (buffer + off + fproff, fpr, fprlen))
|
||||
return idx+1; /* found */
|
||||
}
|
||||
return 0; /* not found */
|
||||
|
@ -497,6 +526,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
|
||||
/* 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
|
||||
|
@ -598,20 +679,19 @@ has_long_kid (KEYBOXBLOB blob, u32 mkid, u32 lkid)
|
|||
}
|
||||
|
||||
static inline int
|
||||
has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
|
||||
has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen)
|
||||
{
|
||||
return blob_cmp_fpr (blob, fpr);
|
||||
return blob_cmp_fpr (blob, fpr, fprlen);
|
||||
}
|
||||
|
||||
static inline int
|
||||
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
|
||||
if (blob_get_type (blob) == KEYBOX_BLOBTYPE_X509)
|
||||
return blob_x509_has_grip (blob, grip);
|
||||
#else
|
||||
(void)blob;
|
||||
(void)grip;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -996,12 +1076,13 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
|
|||
if (pk_no)
|
||||
goto found;
|
||||
break;
|
||||
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
pk_no = has_fingerprint (blob, desc[n].u.fpr);
|
||||
pk_no = has_fingerprint (blob, desc[n].u.fpr, desc[n].fprlen);
|
||||
if (pk_no)
|
||||
goto found;
|
||||
break;
|
||||
|
||||
case KEYDB_SEARCH_MODE_KEYGRIP:
|
||||
if (has_keygrip (blob, desc[n].u.grip))
|
||||
goto found;
|
||||
|
@ -1069,7 +1150,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
|
|||
|
||||
|
||||
/* Return the last found keyblock. Returns 0 on success and stores a
|
||||
* new iobuf at R_IOBUF. R_UID_NO and R_PK_NO are used to retun the
|
||||
* new iobuf at R_IOBUF. R_UID_NO and R_PK_NO are used to return the
|
||||
* number of the key or user id which was matched the search criteria;
|
||||
* if not known they are set to 0. */
|
||||
gpg_error_t
|
||||
|
|
|
@ -29,7 +29,7 @@ cat <<EOF
|
|||
* keybox_strerror:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* This function returns a textual representation of the given
|
||||
* errorcode. If this is an unknown value, a string with the value
|
||||
* is returned (Beware: it is hold in a static buffer).
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue