1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

Merge branch 'STABLE-BRANCH-2-2' into master

This commit is contained in:
Werner Koch 2018-03-27 08:48:00 +02:00
commit d4dc4245bf
No known key found for this signature in database
GPG key ID: E3FDFF218E45B72B
36 changed files with 516 additions and 135 deletions

View file

@ -289,6 +289,23 @@ start_agent (ctrl_t ctrl, int flag_for_card)
}
}
/* Pass on the request origin. */
if (opt.request_origin)
{
char *tmp = xasprintf ("OPTION pretend-request-origin=%s",
str_request_origin (opt.request_origin));
rc = assuan_transact (agent_ctx, tmp,
NULL, NULL, NULL, NULL, NULL, NULL);
xfree (tmp);
if (rc)
{
log_error ("setting request origin '%s' failed: %s\n",
str_request_origin (opt.request_origin),
gpg_strerror (rc));
write_status_error ("set_request_origin", rc);
}
}
/* In DE_VS mode under Windows we require that the JENT RNG
* is active. */
#ifdef HAVE_W32_SYSTEM
@ -591,6 +608,8 @@ learn_status_cb (void *opaque, const char *line)
parm->extcap.ki = abool;
else if (!strcmp (p, "aac"))
parm->extcap.aac = abool;
else if (!strcmp (p, "kdf"))
parm->extcap.kdf = abool;
else if (!strcmp (p, "si"))
parm->status_indicator = strtoul (p2, NULL, 10);
}

View file

@ -67,6 +67,7 @@ struct agent_card_info_s
struct {
unsigned int ki:1; /* Key import available. */
unsigned int aac:1; /* Algorithm attributes are changeable. */
unsigned int kdf:1; /* KDF object to support PIN hashing available. */
} extcap;
unsigned int status_indicator;
};

View file

@ -659,7 +659,7 @@ current_card_status (ctrl_t ctrl, estream_t fp,
/* Print all available information for specific card with SERIALNO.
Print all available information for current card when SERIALNO is NULL.
Or print llfor all cards when SERIALNO is "all". */
Or print for all cards when SERIALNO is "all". */
void
card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
{
@ -1797,6 +1797,7 @@ factory_reset (void)
scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
scd apdu 00 e6 00 00
scd apdu 00 44 00 00
scd reset
/echo Card has been reset to factory defaults
but tries to find out something about the card first.
@ -1809,7 +1810,7 @@ factory_reset (void)
else if (err)
{
log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
return;
goto leave;
}
if (!termstate)
@ -1859,10 +1860,16 @@ factory_reset (void)
command because there is no machinery in scdaemon to catch
the verify command and ask for the PIN when the "APDU"
command is used. */
/* Here, the length of dummy wrong PIN is 32-byte, also
supporting authentication with KDF DO. */
for (i=0; i < 4; i++)
send_apdu ("00200081084040404040404040", "VERIFY", 0xffff);
send_apdu ("0020008120"
"40404040404040404040404040404040"
"40404040404040404040404040404040", "VERIFY", 0xffff);
for (i=0; i < 4; i++)
send_apdu ("00200083084040404040404040", "VERIFY", 0xffff);
send_apdu ("0020008320"
"40404040404040404040404040404040"
"40404040404040404040404040404040", "VERIFY", 0xffff);
/* Send terminate datafile command. */
err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
@ -1878,8 +1885,16 @@ factory_reset (void)
/* Finally we reset the card reader once more. */
err = send_apdu (NULL, "RESET", 0);
if (err)
goto leave;
/* Then, connect the card again. */
if (!err)
{
char *serialno0;
err = agent_scd_serialno (&serialno0, NULL);
if (!err)
xfree (serialno0);
}
leave:
xfree (answer);
@ -1887,6 +1902,104 @@ factory_reset (void)
}
#define USER_PIN_DEFAULT "123456"
#define ADMIN_PIN_DEFAULT "12345678"
#define KDF_DATA_LENGTH 110
/* Generate KDF data. */
static gpg_error_t
gen_kdf_data (unsigned char *data)
{
const unsigned char h0[] = { 0x81, 0x01, 0x03,
0x82, 0x01, 0x08,
0x83, 0x04 };
const unsigned char h1[] = { 0x84, 0x08 };
const unsigned char h2[] = { 0x85, 0x08 };
const unsigned char h3[] = { 0x86, 0x08 };
const unsigned char h4[] = { 0x87, 0x20 };
const unsigned char h5[] = { 0x88, 0x20 };
unsigned char *p, *salt_user, *salt_admin;
unsigned char s2k_char;
unsigned int iterations;
unsigned char count_4byte[4];
gpg_error_t err = 0;
p = data;
s2k_char = encode_s2k_iterations (0);
iterations = S2K_DECODE_COUNT (s2k_char);
count_4byte[0] = (iterations >> 24) & 0xff;
count_4byte[1] = (iterations >> 16) & 0xff;
count_4byte[2] = (iterations >> 8) & 0xff;
count_4byte[3] = (iterations & 0xff);
memcpy (p, h0, sizeof h0);
p += sizeof h0;
memcpy (p, count_4byte, sizeof count_4byte);
p += sizeof count_4byte;
memcpy (p, h1, sizeof h1);
salt_user = (p += sizeof h1);
gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8;
memcpy (p, h2, sizeof h2);
p += sizeof h2;
gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8;
memcpy (p, h3, sizeof h3);
salt_admin = (p += sizeof h3);
gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8;
memcpy (p, h4, sizeof h4);
p += sizeof h4;
err = gcry_kdf_derive (USER_PIN_DEFAULT, strlen (USER_PIN_DEFAULT),
GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256,
salt_user, 8, iterations, 32, p);
p += 32;
if (!err)
{
memcpy (p, h5, sizeof h5);
p += sizeof h5;
err = gcry_kdf_derive (ADMIN_PIN_DEFAULT, strlen (ADMIN_PIN_DEFAULT),
GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256,
salt_admin, 8, iterations, 32, p);
}
return err;
}
/* Setup KDF data object which is used for PIN authentication. */
static void
kdf_setup (void)
{
struct agent_card_info_s info;
gpg_error_t err;
unsigned char kdf_data[KDF_DATA_LENGTH];
memset (&info, 0, sizeof info);
err = agent_scd_getattr ("EXTCAP", &info);
if (err)
{
log_error (_("error getting card info: %s\n"), gpg_strerror (err));
return;
}
if (!info.extcap.kdf)
{
log_error (_("This command is not supported by this card\n"));
goto leave;
}
if (!(err = gen_kdf_data (kdf_data))
&& !(err = agent_scd_setattr ("KDF", kdf_data, KDF_DATA_LENGTH, NULL)))
err = agent_scd_getattr ("KDF", &info);
if (err)
log_error (_("error for setup KDF: %s\n"), gpg_strerror (err));
leave:
agent_release_card_info (&info);
}
/* Data used by the command parser. This needs to be outside of the
function scope to allow readline based command completion. */
@ -1896,7 +2009,7 @@ enum cmdids
cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET,
cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
cmdINVCMD
};
@ -1930,6 +2043,7 @@ static struct
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
{ "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
/* Note, that we do not announce these command yet. */
{ "privatedo", cmdPRIVATEDO, 0, NULL },
{ "readcert", cmdREADCERT, 0, NULL },
@ -2213,6 +2327,10 @@ card_edit (ctrl_t ctrl, strlist_t commands)
factory_reset ();
break;
case cmdKDFSETUP:
kdf_setup ();
break;
case cmdQUIT:
goto leave;

View file

@ -428,6 +428,7 @@ enum cmd_and_opt_values
oDisableSignerUID,
oSender,
oKeyOrigin,
oRequestOrigin,
oNoop
};
@ -719,6 +720,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"),
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"),
ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"),
ARGPARSE_s_i (oCommandFD, "command-fd", "@"),
ARGPARSE_s_s (oCommandFile, "command-file", "@"),
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
@ -3158,6 +3160,12 @@ main (int argc, char **argv)
log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
break;
case oRequestOrigin:
opt.request_origin = parse_request_origin (pargs.r.ret_str);
if (opt.request_origin == -1)
log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
break;
case oCommandFD:
opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
if (! gnupg_fd_valid (opt.command_fd))

View file

@ -24,6 +24,10 @@
correct value and may be of advantage if we ever have to do
special things. */
#ifdef HAVE_W32_SYSTEM
# define WIN32_LEAN_AND_MEAN 1
#endif
#ifdef GPG_ERR_SOURCE_DEFAULT
#error GPG_ERR_SOURCE_DEFAULT already defined
#endif

View file

@ -1134,8 +1134,10 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
if (err)
goto leave;
/* Note that when using --dry-run we don't change the
* passphrase but merely verify the current passphrase. */
desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1);
err = agent_passwd (ctrl, hexgrip, desc, 0,
err = agent_passwd (ctrl, hexgrip, desc, !!opt.dry_run,
&cache_nonce, &passwd_nonce);
xfree (desc);

View file

@ -42,6 +42,7 @@
#include <time.h>
#include <process.h>
#ifdef HAVE_WINSOCK2_H
# define WIN32_LEAN_AND_MEAN 1
# include <winsock2.h>
#endif
#include <windows.h>

View file

@ -278,6 +278,7 @@ struct
int passphrase_repeat;
int pinentry_mode;
int request_origin;
int unwrap_encryption;
int only_sign_text_ids;

View file

@ -971,10 +971,10 @@ skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
}
/* Read PKTLEN bytes form INP and return them in a newly allocated
buffer. In case of an error (including reading fewer than PKTLEN
bytes from INP before EOF is returned), NULL is returned and an
error message is logged. */
/* Read PKTLEN bytes from INP and return them in a newly allocated
* buffer. In case of an error (including reading fewer than PKTLEN
* bytes from INP before EOF is returned), NULL is returned and an
* error message is logged. */
static void *
read_rest (IOBUF inp, size_t pktlen)
{
@ -1741,6 +1741,8 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
}
if (buflen < n)
goto too_short;
if (!buflen)
goto no_type_byte;
type = *buffer;
if (type & 0x80)
{
@ -1815,6 +1817,13 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
if (start)
*start = -1;
return NULL;
no_type_byte:
if (opt.verbose)
log_info ("type octet missing in subpacket\n");
if (start)
*start = -1;
return NULL;
}

View file

@ -191,7 +191,7 @@ import_ownertrust (ctrl_t ctrl, const char *fname )
while (fprlen < MAX_FINGERPRINT_LEN)
fpr[fprlen++] = 0;
rc = tdbio_search_trust_byfpr (fpr, &rec);
rc = tdbio_search_trust_byfpr (ctrl, fpr, &rec);
if( !rc ) { /* found: update */
if (rec.r.trust.ownertrust != otrust)
{

View file

@ -105,16 +105,17 @@ struct cmp_xdir_struct
/* The name of the trustdb file. */
static char *db_name;
/* The handle for locking the trustdb file and a flag to record
whether a lock has been taken. */
/* The handle for locking the trustdb file and a counter to record how
* often this lock has been taken. That counter is required becuase
* dotlock does not implemen recursive locks. */
static dotlock_t lockhandle;
static int is_locked;
static unsigned int is_locked;
/* The file descriptor of the trustdb. */
static int db_fd = -1;
/* A flag indicating that a transaction is active. */
static int in_transaction;
/* static int in_transaction; Not yet used. */
@ -125,7 +126,7 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type);
/*
* Take a lock on the trustdb file name. I a lock file can't be
* created the function terminates the process. Excvept for a
* created the function terminates the process. Except for a
* different return code the function does nothing if the lock has
* already been taken.
*
@ -135,6 +136,8 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type);
static int
take_write_lock (void)
{
int rc;
if (!lockhandle)
lockhandle = dotlock_create (db_name, 0);
if (!lockhandle)
@ -144,12 +147,16 @@ take_write_lock (void)
{
if (dotlock_take (lockhandle, -1) )
log_fatal ( _("can't lock '%s'\n"), db_name );
else
is_locked = 1;
return 0;
rc = 0;
}
else
return 1;
rc = 1;
if (opt.lock_once)
is_locked = 1;
else
is_locked++;
return rc;
}
@ -160,10 +167,22 @@ take_write_lock (void)
static void
release_write_lock (void)
{
if (!opt.lock_once)
if (!dotlock_release (lockhandle))
is_locked = 0;
if (opt.lock_once)
return; /* Don't care; here IS_LOCKED is fixed to 1. */
if (!is_locked)
{
log_error ("Ooops, tdbio:release_write_lock with no lock held\n");
return;
}
if (--is_locked)
return;
if (dotlock_release (lockhandle))
log_error ("Oops, tdbio:release_write_locked failed\n");
}
/*************************************
************* record cache **********
@ -329,6 +348,7 @@ put_record_into_cache (ulong recno, const char *data)
}
/* No clean entries: We have to flush some dirty entries. */
#if 0 /* Transactions are not yet used. */
if (in_transaction)
{
/* But we can't do this while in a transaction. Thus we
@ -352,6 +372,7 @@ put_record_into_cache (ulong recno, const char *data)
log_info (_("trustdb transaction too large\n"));
return GPG_ERR_RESOURCE_LIMIT;
}
#endif
if (dirty_count)
{
@ -418,8 +439,10 @@ tdbio_sync()
if( db_fd == -1 )
open_db();
#if 0 /* Transactions are not yet used. */
if( in_transaction )
log_bug("tdbio: syncing while in transaction\n");
#endif
if( !cache_is_dirty )
return 0;
@ -560,7 +583,7 @@ tdbio_update_version_record (ctrl_t ctrl)
/*
* Create and write the trustdb version record.
*
* This is called with the writelock activ.
* Returns: 0 on success or an error code.
*/
static int
@ -951,10 +974,12 @@ tdbio_write_nextcheck (ctrl_t ctrl, ulong stamp)
* Return: record number
*/
static ulong
get_trusthashrec(void)
get_trusthashrec (ctrl_t ctrl)
{
static ulong trusthashtbl; /* Record number of the trust hashtable. */
(void)ctrl;
if (!trusthashtbl)
{
TRUSTREC vr;
@ -965,6 +990,20 @@ get_trusthashrec(void)
log_fatal (_("%s: error reading version record: %s\n"),
db_name, gpg_strerror (rc) );
if (!vr.r.ver.trusthashtbl)
{
/* Oops: the trustdb is corrupt because the hashtable is
* always created along with the version record. However,
* if something went initially wrong it may happen that
* there is just the version record. We try to fix it here.
* If we can't do that we return 0 - this is the version
* record and thus the actual read will detect the mismatch
* and bail out. Note that create_hashtable updates VR. */
take_write_lock ();
if (lseek (db_fd, 0, SEEK_END) == TRUST_RECORD_LEN)
create_hashtable (ctrl, &vr, 0);
release_write_lock ();
}
trusthashtbl = vr.r.ver.trusthashtbl;
}
@ -1269,6 +1308,13 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen,
int msb;
int level = 0;
if (!table)
{
rc = gpg_error (GPG_ERR_INV_RECORD);
log_error("lookup_hashtable failed: %s\n", "request for record 0");
return rc;
}
hashrec = table;
next_level:
msb = key[level];
@ -1358,7 +1404,7 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen,
static int
update_trusthashtbl (ctrl_t ctrl, TRUSTREC *tr)
{
return upd_hashtable (ctrl, get_trusthashrec (),
return upd_hashtable (ctrl, get_trusthashrec (ctrl),
tr->r.trust.fingerprint, 20, tr->recnum);
}
@ -1441,7 +1487,7 @@ tdbio_dump_record (TRUSTREC *rec, estream_t fp)
* EXPECTED is not 0 reading any other record type will return an
* error.
*
* Return: 0 on success, -1 on EOF, or an error code.
* Return: 0 on success or an error code.
*/
int
tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected)
@ -1466,7 +1512,7 @@ tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected)
n = read (db_fd, readbuf, TRUST_RECORD_LEN);
if (!n)
{
return -1; /* eof */
return gpg_error (GPG_ERR_EOF);
}
else if (n != TRUST_RECORD_LEN)
{
@ -1700,7 +1746,7 @@ tdbio_delete_record (ctrl_t ctrl, ulong recnum)
;
else if (rec.rectype == RECTYPE_TRUST)
{
rc = drop_from_hashtable (ctrl, get_trusthashrec(),
rc = drop_from_hashtable (ctrl, get_trusthashrec (ctrl),
rec.r.trust.fingerprint, 20, rec.recnum);
}
@ -1746,20 +1792,14 @@ tdbio_new_recnum (ctrl_t ctrl)
recnum = vr.r.ver.firstfree;
rc = tdbio_read_record (recnum, &rec, RECTYPE_FREE);
if (rc)
{
log_error (_("%s: error reading free record: %s\n"),
db_name, gpg_strerror (rc));
return rc;
}
log_fatal (_("%s: error reading free record: %s\n"),
db_name, gpg_strerror (rc));
/* Update dir record. */
vr.r.ver.firstfree = rec.r.free.next;
rc = tdbio_write_record (ctrl, &vr);
if (rc)
{
log_error (_("%s: error writing dir record: %s\n"),
db_name, gpg_strerror (rc));
return rc;
}
log_fatal (_("%s: error writing dir record: %s\n"),
db_name, gpg_strerror (rc));
/* Zero out the new record. */
memset (&rec, 0, sizeof rec);
rec.rectype = 0; /* Mark as unused record (actually already done
@ -1776,7 +1816,7 @@ tdbio_new_recnum (ctrl_t ctrl)
if (offset == (off_t)(-1))
log_fatal ("trustdb: lseek to end failed: %s\n", strerror (errno));
recnum = offset / TRUST_RECORD_LEN;
log_assert (recnum); /* this is will never be the first record */
log_assert (recnum); /* This will never be the first record */
/* We must write a record, so that the next call to this
* function returns another recnum. */
memset (&rec, 0, sizeof rec);
@ -1798,13 +1838,13 @@ tdbio_new_recnum (ctrl_t ctrl)
{
rc = gpg_error_from_syserror ();
log_error (_("trustdb rec %lu: write failed (n=%d): %s\n"),
recnum, n, strerror (errno));
recnum, n, gpg_strerror (rc));
}
}
if (rc)
log_fatal (_("%s: failed to append a record: %s\n"),
db_name, gpg_strerror (rc));
db_name, gpg_strerror (rc));
}
return recnum ;
@ -1828,12 +1868,12 @@ cmp_trec_fpr ( const void *fpr, const TRUSTREC *rec )
* Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code.
*/
gpg_error_t
tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec)
tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint, TRUSTREC *rec)
{
int rc;
/* Locate the trust record using the hash table */
rc = lookup_hashtable (get_trusthashrec(), fingerprint, 20,
rc = lookup_hashtable (get_trusthashrec (ctrl), fingerprint, 20,
cmp_trec_fpr, fingerprint, rec );
return rc;
}
@ -1846,7 +1886,7 @@ tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec)
* Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code.
*/
gpg_error_t
tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec)
tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec)
{
byte fingerprint[MAX_FINGERPRINT_LEN];
size_t fingerlen;
@ -1854,7 +1894,7 @@ tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec)
fingerprint_from_pk( pk, fingerprint, &fingerlen );
for (; fingerlen < 20; fingerlen++)
fingerprint[fingerlen] = 0;
return tdbio_search_trust_byfpr (fingerprint, rec);
return tdbio_search_trust_byfpr (ctrl, fingerprint, rec);
}

View file

@ -110,8 +110,10 @@ int tdbio_end_transaction(void);
int tdbio_cancel_transaction(void);
int tdbio_delete_record (ctrl_t ctrl, ulong recnum);
ulong tdbio_new_recnum (ctrl_t ctrl);
gpg_error_t tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec);
gpg_error_t tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec);
gpg_error_t tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint,
TRUSTREC *rec);
gpg_error_t tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk,
TRUSTREC *rec);
void tdbio_how_to_fix (void);
void tdbio_invalid(void);

View file

@ -649,7 +649,7 @@ read_trust_record (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec)
int rc;
init_trustdb (ctrl, 0);
rc = tdbio_search_trust_bypk (pk, rec);
rc = tdbio_search_trust_bypk (ctrl, pk, rec);
if (rc)
{
if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)