gpg: Add new field no 18 to the colon listing.

* g10/misc.c (gnupg_pk_is_compliant): New.
* g10/keylist.c (print_compliance_flags): New.
(list_keyblock_colon): Call it here.
* sm/keylist.c (print_compliance_flags): New.
(list_cert_colon): Call it here.
--

This patch is to convey information about DE_VS compliant keys to the
caller.  The double digit value is used so that parsers do the right
thing and don't just look for a single digit.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2017-03-20 10:09:40 +01:00
parent e2c63a13e2
commit fe0b37e123
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
5 changed files with 168 additions and 25 deletions

View File

@ -218,6 +218,15 @@ described here.
For pub, sub, sec, and ssb records this field is used for the ECC
curve name.
*** Field 18 - Compliance flags
Space separated list of asserted compliance modes for this key.
Valid values are:
- 8 :: The key is compliant with RFC4880bis
- 23 :: The key is compliant with compliance mode "de-vs".
** Special fields
*** PKD - Public key data

View File

@ -1170,6 +1170,29 @@ print_revokers (estream_t fp, PKT_public_key * pk)
}
/* Print the compliance flags to field 18. PK is the public key.
* KEYLENGTH is the length of the key in bits and CURVENAME is either
* NULL or the name of the curve. The latter two args are here
* merely because the caller has already computed them. */
static void
print_compliance_flags (PKT_public_key *pk,
unsigned int keylength, const char *curvename)
{
int any = 0;
if (pk->version == 5)
{
es_fputs ("8", es_stdout);
any++;
}
if (gnupg_pk_is_compliant (CO_DE_VS, pk, keylength, curvename))
{
es_fputs (any? " 23":"23", es_stdout);
any++;
}
}
/* List a key in colon mode. If SECRET is true this is a secret key
record (i.e. requested via --list-secret-key). If HAS_SECRET a
secret key is available even if SECRET is not set. */
@ -1191,6 +1214,9 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
const char *hexgrip = NULL;
char *serialno = NULL;
int stubkey;
unsigned int keylength;
char *curve = NULL;
const char *curvename = NULL;
/* Get the keyid from the keyblock. */
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@ -1239,14 +1265,16 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
else
ownertrust_print = 0;
keylength = nbits_from_pk (pk);
es_fputs (secret? "sec:":"pub:", es_stdout);
if (trustletter_print)
es_putc (trustletter_print, es_stdout);
es_fprintf (es_stdout, ":%u:%d:%08lX%08lX:%s:%s::",
nbits_from_pk (pk),
pk->pubkey_algo,
(ulong) keyid[0], (ulong) keyid[1],
colon_datestr_from_pk (pk), colon_strtime (pk->expiredate));
keylength,
pk->pubkey_algo,
(ulong) keyid[0], (ulong) keyid[1],
colon_datestr_from_pk (pk), colon_strtime (pk->expiredate));
if (ownertrust_print)
es_putc (ownertrust_print, es_stdout);
@ -1272,14 +1300,14 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
const char *name = openpgp_oid_to_curve (curve, 0);
if (!name)
name = curve;
es_fputs (name, es_stdout);
xfree (curve);
curve = openpgp_oid_to_str (pk->pkey[0]);
curvename = openpgp_oid_to_curve (curve, 0);
if (!curvename)
curvename = curve;
es_fputs (curvename, es_stdout);
}
es_putc (':', es_stdout); /* End of field 17. */
print_compliance_flags (pk, keylength, curvename);
es_putc (':', es_stdout); /* End of field 18. */
es_putc ('\n', es_stdout);
@ -1380,13 +1408,13 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
if (trustletter)
es_fprintf (es_stdout, "%c", trustletter);
}
keylength = nbits_from_pk (pk2);
es_fprintf (es_stdout, ":%u:%d:%08lX%08lX:%s:%s:::::",
nbits_from_pk (pk2),
pk2->pubkey_algo,
(ulong) keyid2[0], (ulong) keyid2[1],
colon_datestr_from_pk (pk2), colon_strtime (pk2->expiredate)
/* fixme: add LID and ownertrust here */
);
keylength,
pk2->pubkey_algo,
(ulong) keyid2[0], (ulong) keyid2[1],
colon_datestr_from_pk (pk2),
colon_strtime (pk2->expiredate));
print_capabilities (pk2, NULL);
es_putc (':', es_stdout); /* End of field 13. */
es_putc (':', es_stdout); /* End of field 14. */
@ -1405,14 +1433,16 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
|| pk2->pubkey_algo == PUBKEY_ALGO_EDDSA
|| pk2->pubkey_algo == PUBKEY_ALGO_ECDH)
{
char *curve = openpgp_oid_to_str (pk2->pkey[0]);
const char *name = openpgp_oid_to_curve (curve, 0);
if (!name)
name = curve;
es_fputs (name, es_stdout);
xfree (curve);
curve = openpgp_oid_to_str (pk2->pkey[0]);
curvename = openpgp_oid_to_curve (curve, 0);
if (!curvename)
curvename = curve;
es_fputs (curvename, es_stdout);
}
es_putc (':', es_stdout); /* End of field 17. */
print_compliance_flags (pk2, keylength, curvename);
es_putc (':', es_stdout); /* End of field 18. */
es_putc ('\n', es_stdout);
print_fingerprint (NULL, pk2, 0);
if (hexgrip)
@ -1540,6 +1570,7 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
}
}
xfree (curve);
xfree (hexgrip_buffer);
xfree (serialno);
}

View File

@ -125,6 +125,9 @@ int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use);
int openpgp_pk_algo_usage ( int algo );
const char *openpgp_pk_algo_name (pubkey_algo_t algo);
int gnupg_pk_is_compliant (int compliance, PKT_public_key *pk,
unsigned int keylength, const char *curvename);
enum gcry_md_algos map_md_openpgp_to_gcry (digest_algo_t algo);
int openpgp_md_test_algo (digest_algo_t algo);
const char *openpgp_md_algo_name (int algo);

View File

@ -640,7 +640,7 @@ openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use)
if (!ga)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
/* No check whether Libgcrypt has support for the algorithm. */
/* Now check whether Libgcrypt has support for the algorithm. */
return gcry_pk_algo_info (ga, GCRYCTL_TEST_ALGO, NULL, &use_buf);
}
@ -704,6 +704,94 @@ openpgp_pk_algo_name (pubkey_algo_t algo)
}
/* Return true if PK is compliant to the give COMPLIANCE mode. If
* KEYLENGTH and CURVENAME are not 0/NULL the are assumed to be the
* already computed values from PK. */
int
gnupg_pk_is_compliant (int compliance, PKT_public_key *pk,
unsigned int keylength, const char *curvename)
{
enum { is_rsa, is_pgp5, is_elg_sign, is_ecc } algotype;
int result;
switch (pk->pubkey_algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S:
algotype = is_rsa;
break;
case PUBKEY_ALGO_ELGAMAL_E:
case PUBKEY_ALGO_DSA:
algotype = is_pgp5;
break;
case PUBKEY_ALGO_ECDH:
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_EDDSA:
algotype = is_ecc;
break;
case PUBKEY_ALGO_ELGAMAL:
algotype = is_elg_sign;
break;
default: /* Unknown. */
return 0;
}
if (compliance == CO_DE_VS)
{
char *curve = NULL;
switch (algotype)
{
case is_pgp5:
result = 0;
break;
case is_rsa:
if (!keylength)
keylength = nbits_from_pk (pk);
result = (keylength >= 2048);
break;
case is_ecc:
if (!curvename)
{
curve = openpgp_oid_to_str (pk->pkey[0]);
curvename = openpgp_oid_to_curve (curve, 0);
if (!curvename)
curvename = curve;
}
result = (curvename
&& pk->pubkey_algo != PUBKEY_ALGO_EDDSA
&& (!strcmp (curvename, "brainpoolP256r1")
|| !strcmp (curvename, "brainpoolP384r1")
|| !strcmp (curvename, "brainpoolP512r1")));
break;
default:
result = 0;
}
xfree (curve);
}
else if (algotype == is_elg_sign)
{
/* An Elgamal signing key is only RFC-2440 compliant. */
result = (compliance == RFC2440);
}
else
{
result = 1; /* Assume compliance. */
}
return result;
}
/* Explicit mapping of OpenPGP digest algos to Libgcrypt. */
/* FIXME: We do not yes use it everywhere. */
enum gcry_md_algos

View File

@ -346,6 +346,14 @@ email_kludge (const char *name)
}
/* Print the compliance flags to field 18. ALGO is the gcrypt algo
* number. NBITS is the length of the key in bits. */
static void
print_compliance_flags (int algo, unsigned int nbits, estream_t fp)
{
if (algo == GCRY_PK_RSA && nbits >= 2048)
es_fputs ("23", fp);
}
/* List one certificate in colon mode */
@ -496,6 +504,8 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
print_capabilities (cert, fp);
/* Field 13, not used: */
es_putc (':', fp);
/* Field 14, not used: */
es_putc (':', fp);
if (have_secret || ctrl->with_secret)
{
char *cardsn;
@ -504,18 +514,20 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
if (!gpgsm_agent_keyinfo (ctrl, p, &cardsn)
&& (cardsn || ctrl->with_secret))
{
/* Field 14, not used: */
es_putc (':', fp);
/* Field 15: Token serial number or secret key indicator. */
if (cardsn)
es_fputs (cardsn, fp);
else if (ctrl->with_secret)
es_putc ('+', fp);
es_putc (':', fp);
}
xfree (cardsn);
xfree (p);
}
es_putc (':', fp); /* End of field 15. */
es_putc (':', fp); /* End of field 16. */
es_putc (':', fp); /* End of field 17. */
print_compliance_flags (algo, nbits, fp);
es_putc (':', fp); /* End of field 18. */
es_putc ('\n', fp);
/* FPR record */