gpg: Implement encryption to ADSKs.

* g10/getkey.c (get_pubkey_fromfile): Add optional arg r_keyblock.
* g10/pkclist.c (find_and_check_key): Also encrypt to RENC subkeys.
* g10/getkey.c (parse_key_usage): Make public.
* g10/misc.c (openpgp_pk_algo_usage): Take PUBKEY_USAGE_RENC in
account.
* g10/packet.h (PKT_public_key): Change pubkey_usage from byte to u16.
(PKT_user_id): Cosmetic fix: change help_key_usage from int to u16.
* g10/sig-check.c (check_signature_metadata_validity): Handle time
conflict for ADSKs.
--

GnuPG-bug-id: 6395

This patch handles ADSK keys and encrypts to them.  It does not yet
allow the creation of them.  We backport this from master early to get
this part of the code out into the field.
This commit is contained in:
Werner Koch 2023-03-01 18:56:29 +01:00
parent fde59f9ae6
commit e4f61df850
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
6 changed files with 54 additions and 24 deletions

View File

@ -1794,7 +1794,8 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
* is not found.
* is not found. If R_KEYBLOCK is not NULL and a key was found the
* keyblock is stored there; otherwiese NULL is stored there.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. The caller must release the content of PK by
@ -1802,13 +1803,17 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
* free_public_key).
*/
gpg_error_t
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname,
kbnode_t *r_keyblock)
{
gpg_error_t err;
kbnode_t keyblock;
kbnode_t found_key;
unsigned int infoflags;
if (r_keyblock)
*r_keyblock = NULL;
err = read_key_from_file_or_buffer (ctrl, fname, NULL, 0, &keyblock);
if (!err)
{
@ -1823,7 +1828,10 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
release_kbnode (keyblock);
if (!err && r_keyblock)
*r_keyblock = keyblock;
else
release_kbnode (keyblock);
return err;
}
@ -1885,12 +1893,12 @@ get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
* returned public key may be a subkey rather than the primary key.
* Note: The self-signed data has already been merged into the public
* key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* release_public_key_parts (or, if PK was allocated using xmalloc, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If PK->REQ_USAGE is set, it is used to filter the search results.
* (Thus, if PK is not NULL, PK->REQ_USAGE must be valid!!!) See the
* Thus, if PK is not NULL, PK->REQ_USAGE must be valid! See the
* documentation for finish_lookup to understand exactly how this is
* used.
*
@ -2491,7 +2499,8 @@ merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock)
}
static int
/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
unsigned int
parse_key_usage (PKT_signature * sig)
{
int key_usage = 0;

View File

@ -377,7 +377,8 @@ gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
/* Get a public key directly from file FNAME. */
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
PKT_public_key *pk, const char *fname);
PKT_public_key *pk, const char *fname,
kbnode_t *r_keyblock);
/* Get a public key from a buffer. */
gpg_error_t get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
@ -453,6 +454,9 @@ void setup_main_keyids (kbnode_t keyblock);
data structures. */
void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock);
/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
unsigned int parse_key_usage (PKT_signature *sig);
char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);

View File

@ -782,21 +782,21 @@ openpgp_pk_algo_usage ( int algo )
switch ( algo ) {
case PUBKEY_ALGO_RSA:
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC | PUBKEY_USAGE_AUTH);
break;
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_ECDH:
use = PUBKEY_USAGE_ENC;
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_RSA_S:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
break;
case PUBKEY_ALGO_ELGAMAL:
if (RFC2440)
use = PUBKEY_USAGE_ENC;
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_ELGAMAL_E:
use = PUBKEY_USAGE_ENC;
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;

View File

@ -290,7 +290,7 @@ typedef struct
/* The length of ATTRIB_DATA. */
unsigned long attrib_len;
byte *namehash;
int help_key_usage;
u16 help_key_usage;
u32 help_key_expire;
int help_full_count;
int help_marginal_count;
@ -388,7 +388,7 @@ typedef struct
byte selfsigversion; /* highest version of all of the self-sigs */
/* The public key algorithm. (Serialized.) */
byte pubkey_algo;
byte pubkey_usage; /* for now only used to pass it to getkey() */
u16 pubkey_usage; /* carries the usage info. */
byte req_usage; /* hack to pass a request to getkey() */
u32 has_expired; /* set to the expiration date if expired */
/* keyid of the primary key. Never access this value directly.

View File

@ -821,7 +821,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
{
int rc;
PKT_public_key *pk;
KBNODE keyblock = NULL;
kbnode_t keyblock = NULL;
kbnode_t node;
if (!name || !*name)
return gpg_error (GPG_ERR_INV_USER_ID);
@ -832,7 +833,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
pk->req_usage = use;
if (from_file)
rc = get_pubkey_fromfile (ctrl, pk, name);
rc = get_pubkey_fromfile (ctrl, pk, name, &keyblock);
else
rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
NULL, pk, name, &keyblock, 0);
@ -871,10 +872,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
int trustlevel;
trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1);
release_kbnode (keyblock);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
{
/* Key has been disabled. */
release_kbnode (keyblock);
send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk);
@ -884,6 +885,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
if ( !do_we_trust_pre (ctrl, pk, trustlevel) )
{
/* We don't trust this key. */
release_kbnode (keyblock);
send_status_inv_recp (10, name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
@ -902,19 +904,33 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
{
pk_list_t r;
r = xtrymalloc (sizeof *r);
if (!r)
{
rc = gpg_error_from_syserror ();
free_public_key (pk);
return rc;
}
r = xmalloc (sizeof *r);
r->pk = pk;
r->next = *pk_list_addr;
r->flags = mark_hidden? 1:0;
*pk_list_addr = r;
}
for (node = keyblock; node; node = node->next)
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
&& ((pk=node->pkt->pkt.public_key)->pubkey_usage & PUBKEY_USAGE_RENC)
&& pk->flags.valid
&& !pk->flags.revoked
&& !pk->flags.disabled
&& !pk->has_expired
&& key_present_in_pk_list (*pk_list_addr, pk))
{
pk_list_t r;
r = xmalloc (sizeof *r);
r->pk = copy_public_key (NULL, pk);
r->next = *pk_list_addr;
r->flags = mark_hidden? 1:0; /* FIXME: Use PK_LIST_HIDDEN ? */
*pk_list_addr = r;
}
release_kbnode (keyblock);
return 0;
}

View File

@ -335,7 +335,8 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
if (r_revoked)
*r_revoked = 0;
if (pk->timestamp > sig->timestamp )
if (pk->timestamp > sig->timestamp
&& !(parse_key_usage (sig) & PUBKEY_USAGE_RENC))
{
ulong d = pk->timestamp - sig->timestamp;
if ( d < 86400 )