diff options
Diffstat (limited to 'g10')
46 files changed, 3006 insertions, 1932 deletions
diff --git a/g10/armor.c b/g10/armor.c index cc8096862..972766503 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -1,4 +1,4 @@ -/* armor.c - Armor flter +/* armor.c - Armor filter * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007 Free Software Foundation, Inc. * @@ -37,17 +37,10 @@ #define MAX_LINELEN 20000 -#define CRCINIT 0xB704CE -#define CRCPOLY 0X864CFB -#define CRCUPDATE(a,c) do { \ - a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \ - a &= 0x00ffffff; \ - } while(0) -static u32 crc_table[256]; -static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; -static byte asctobin[256]; /* runtime initialized */ +static const byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; +static u32 asctobin[4][256]; /* runtime initialized */ static int is_initialized; @@ -121,9 +114,22 @@ armor_filter_context_t * new_armor_context (void) { armor_filter_context_t *afx; + gpg_error_t err; afx = xcalloc (1, sizeof *afx); - afx->refcount = 1; + if (afx) + { + err = gcry_md_open (&afx->crc_md, GCRY_MD_CRC24_RFC2440, 0); + if (err != 0) + { + log_error ("gcry_md_open failed for GCRY_MD_CRC24_RFC2440: %s", + gpg_strerror (err)); + xfree (afx); + return NULL; + } + + afx->refcount = 1; + } return afx; } @@ -138,6 +144,7 @@ release_armor_context (armor_filter_context_t *afx) log_assert (afx->refcount); if ( --afx->refcount ) return; + gcry_md_close (afx->crc_md); xfree (afx); } @@ -161,35 +168,42 @@ push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf) static void initialize(void) { - int i, j; - u32 t; - byte *s; - - /* init the crc lookup table */ - crc_table[0] = 0; - for(i=j=0; j < 128; j++ ) { - t = crc_table[j]; - if( t & 0x00800000 ) { - t <<= 1; - crc_table[i++] = t ^ CRCPOLY; - crc_table[i++] = t; - } - else { - t <<= 1; - crc_table[i++] = t; - crc_table[i++] = t ^ CRCPOLY; - } - } - /* build the helptable for radix64 to bin conversion */ - for(i=0; i < 256; i++ ) - asctobin[i] = 255; /* used to detect invalid characters */ + u32 i; + const byte *s; + + /* Build the helptable for radix64 to bin conversion. Value 0xffffffff is + used to detect invalid characters. */ + memset (asctobin, 0xff, sizeof(asctobin)); for(s=bintoasc,i=0; *s; s++,i++ ) - asctobin[*s] = i; + { + asctobin[0][*s] = i << (0 * 6); + asctobin[1][*s] = i << (1 * 6); + asctobin[2][*s] = i << (2 * 6); + asctobin[3][*s] = i << (3 * 6); + } is_initialized=1; } +static inline u32 +get_afx_crc (armor_filter_context_t *afx) +{ + const byte *crc_buf; + u32 crc; + + crc_buf = gcry_md_read (afx->crc_md, GCRY_MD_CRC24_RFC2440); + + crc = crc_buf[0]; + crc <<= 8; + crc |= crc_buf[1]; + crc <<= 8; + crc |= crc_buf[2]; + + return crc; +} + + /* * Check whether this is an armored file. See also * parse-packet.c for details on this code. @@ -592,7 +606,7 @@ check_input( armor_filter_context_t *afx, IOBUF a ) afx->faked = 1; else { afx->inp_checked = 1; - afx->crc = CRCINIT; + gcry_md_reset (afx->crc_md); afx->idx = 0; afx->radbuf[0] = 0; } @@ -768,7 +782,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, } } afx->inp_checked = 1; - afx->crc = CRCINIT; + gcry_md_reset (afx->crc_md); afx->idx = 0; afx->radbuf[0] = 0; } @@ -793,14 +807,14 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, byte *buf, size_t size ) { byte val; - int c=0, c2; /*init c because gcc is not clever enough for the continue*/ + int c; + u32 binc; int checkcrc=0; int rc = 0; size_t n = 0; - int idx, i, onlypad=0; - u32 crc; + int idx, onlypad=0; + int skip_fast = 0; - crc = afx->crc; idx = afx->idx; val = afx->radbuf[0]; for( n=0; n < size; ) { @@ -820,6 +834,122 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, } again: + binc = asctobin[0][c]; + + if( binc != 0xffffffffUL ) + { + if( idx == 0 && skip_fast == 0 + && afx->buffer_pos + (16 - 1) < afx->buffer_len + && n + 12 < size) + { + /* Fast path for radix64 to binary conversion. */ + u32 b0,b1,b2,b3; + + /* Speculatively load 15 more input bytes. */ + b0 = binc << (3 * 6); + b0 |= asctobin[2][afx->buffer[afx->buffer_pos + 0]]; + b0 |= asctobin[1][afx->buffer[afx->buffer_pos + 1]]; + b0 |= asctobin[0][afx->buffer[afx->buffer_pos + 2]]; + b1 = asctobin[3][afx->buffer[afx->buffer_pos + 3]]; + b1 |= asctobin[2][afx->buffer[afx->buffer_pos + 4]]; + b1 |= asctobin[1][afx->buffer[afx->buffer_pos + 5]]; + b1 |= asctobin[0][afx->buffer[afx->buffer_pos + 6]]; + b2 = asctobin[3][afx->buffer[afx->buffer_pos + 7]]; + b2 |= asctobin[2][afx->buffer[afx->buffer_pos + 8]]; + b2 |= asctobin[1][afx->buffer[afx->buffer_pos + 9]]; + b2 |= asctobin[0][afx->buffer[afx->buffer_pos + 10]]; + b3 = asctobin[3][afx->buffer[afx->buffer_pos + 11]]; + b3 |= asctobin[2][afx->buffer[afx->buffer_pos + 12]]; + b3 |= asctobin[1][afx->buffer[afx->buffer_pos + 13]]; + b3 |= asctobin[0][afx->buffer[afx->buffer_pos + 14]]; + + /* Check if any of the input bytes were invalid. */ + if( (b0 | b1 | b2 | b3) != 0xffffffffUL ) + { + /* All 16 bytes are valid. */ + buf[n + 0] = b0 >> (2 * 8); + buf[n + 1] = b0 >> (1 * 8); + buf[n + 2] = b0 >> (0 * 8); + buf[n + 3] = b1 >> (2 * 8); + buf[n + 4] = b1 >> (1 * 8); + buf[n + 5] = b1 >> (0 * 8); + buf[n + 6] = b2 >> (2 * 8); + buf[n + 7] = b2 >> (1 * 8); + buf[n + 8] = b2 >> (0 * 8); + buf[n + 9] = b3 >> (2 * 8); + buf[n + 10] = b3 >> (1 * 8); + buf[n + 11] = b3 >> (0 * 8); + afx->buffer_pos += 16 - 1; + n += 12; + continue; + } + else if( b0 == 0xffffffffUL ) + { + /* byte[1..3] have invalid character(s). Switch to slow + path. */ + skip_fast = 1; + } + else if( b1 == 0xffffffffUL ) + { + /* byte[4..7] have invalid character(s), first 4 bytes are + valid. */ + buf[n + 0] = b0 >> (2 * 8); + buf[n + 1] = b0 >> (1 * 8); + buf[n + 2] = b0 >> (0 * 8); + afx->buffer_pos += 4 - 1; + n += 3; + skip_fast = 1; + continue; + } + else if( b2 == 0xffffffffUL ) + { + /* byte[8..11] have invalid character(s), first 8 bytes are + valid. */ + buf[n + 0] = b0 >> (2 * 8); + buf[n + 1] = b0 >> (1 * 8); + buf[n + 2] = b0 >> (0 * 8); + buf[n + 3] = b1 >> (2 * 8); + buf[n + 4] = b1 >> (1 * 8); + buf[n + 5] = b1 >> (0 * 8); + afx->buffer_pos += 8 - 1; + n += 6; + skip_fast = 1; + continue; + } + else /*if( b3 == 0xffffffffUL )*/ + { + /* byte[12..15] have invalid character(s), first 12 bytes + are valid. */ + buf[n + 0] = b0 >> (2 * 8); + buf[n + 1] = b0 >> (1 * 8); + buf[n + 2] = b0 >> (0 * 8); + buf[n + 3] = b1 >> (2 * 8); + buf[n + 4] = b1 >> (1 * 8); + buf[n + 5] = b1 >> (0 * 8); + buf[n + 6] = b2 >> (2 * 8); + buf[n + 7] = b2 >> (1 * 8); + buf[n + 8] = b2 >> (0 * 8); + afx->buffer_pos += 12 - 1; + n += 9; + skip_fast = 1; + continue; + } + } + + switch(idx) + { + case 0: val = binc << 2; break; + case 1: val |= (binc>>4)&3; buf[n++]=val;val=(binc<<4)&0xf0;break; + case 2: val |= (binc>>2)&15; buf[n++]=val;val=(binc<<6)&0xc0;break; + case 3: val |= binc&0x3f; buf[n++] = val; break; + } + idx = (idx+1) % 4; + + continue; + } + + skip_fast = 0; + if( c == '\n' || c == ' ' || c == '\r' || c == '\t' ) continue; else if( c == '=' ) { /* pad character: stop */ @@ -850,10 +980,10 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, if (afx->buffer_pos + 6 < afx->buffer_len && afx->buffer[afx->buffer_pos + 0] == '3' && afx->buffer[afx->buffer_pos + 1] == 'D' - && asctobin[afx->buffer[afx->buffer_pos + 2]] != 255 - && asctobin[afx->buffer[afx->buffer_pos + 3]] != 255 - && asctobin[afx->buffer[afx->buffer_pos + 4]] != 255 - && asctobin[afx->buffer[afx->buffer_pos + 5]] != 255 + && asctobin[0][afx->buffer[afx->buffer_pos + 2]] != 0xffffffffUL + && asctobin[0][afx->buffer[afx->buffer_pos + 3]] != 0xffffffffUL + && asctobin[0][afx->buffer[afx->buffer_pos + 4]] != 0xffffffffUL + && asctobin[0][afx->buffer[afx->buffer_pos + 5]] != 0xffffffffUL && afx->buffer[afx->buffer_pos + 6] == '\n') { afx->buffer_pos += 2; @@ -868,27 +998,20 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, checkcrc++; break; } - else if( (c = asctobin[(c2=c)]) == 255 ) { - log_error(_("invalid radix64 character %02X skipped\n"), c2); + else { + log_error(_("invalid radix64 character %02X skipped\n"), c); continue; } - switch(idx) { - case 0: val = c << 2; break; - case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break; - case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break; - case 3: val |= c&0x3f; buf[n++] = val; break; - } - idx = (idx+1) % 4; } - for(i=0; i < n; i++ ) - crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]]; - crc &= 0x00ffffff; - afx->crc = crc; afx->idx = idx; afx->radbuf[0] = val; + if( n ) + gcry_md_write (afx->crc_md, buf, n); + if( checkcrc ) { + gcry_md_final (afx->crc_md); afx->any_data = 1; afx->inp_checked=0; afx->faked = 0; @@ -911,19 +1034,19 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, continue; break; } - if( c == -1 ) + if( !afx->buffer_len ) log_error(_("premature eof (no CRC)\n")); else { u32 mycrc = 0; idx = 0; do { - if( (c = asctobin[c]) == 255 ) + if( (binc = asctobin[0][c]) == 0xffffffffUL ) break; switch(idx) { - case 0: val = c << 2; break; - case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break; - case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break; - case 3: val |= c&0x3f; mycrc |= val; break; + case 0: val = binc << 2; break; + case 1: val |= (binc>>4)&3; mycrc |= val << 16;val=(binc<<4)&0xf0;break; + case 2: val |= (binc>>2)&15; mycrc |= val << 8;val=(binc<<6)&0xc0;break; + case 3: val |= binc&0x3f; mycrc |= val; break; } for(;;) { if( afx->buffer_pos < afx->buffer_len ) @@ -945,7 +1068,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, if( !afx->buffer_len ) break; /* eof */ } while( ++idx < 4 ); - if( c == -1 ) { + if( !afx->buffer_len ) { log_info(_("premature eof (in CRC)\n")); rc = invalid_crc(); } @@ -957,10 +1080,10 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, log_info(_("malformed CRC\n")); rc = invalid_crc(); } - else if( mycrc != afx->crc ) { - log_info (_("CRC error; %06lX - %06lX\n"), - (ulong)afx->crc, (ulong)mycrc); - rc = invalid_crc(); + else if( mycrc != get_afx_crc (afx) ) { + log_info (_("CRC error; %06lX - %06lX\n"), + (ulong)get_afx_crc (afx), (ulong)mycrc); + rc = invalid_crc(); } else { rc = 0; @@ -997,6 +1120,121 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, return rc; } +static void +armor_output_buf_as_radix64 (armor_filter_context_t *afx, IOBUF a, + byte *buf, size_t size) +{ + byte radbuf[sizeof (afx->radbuf)]; + byte outbuf[64 + sizeof (afx->eol)]; + unsigned int eollen = strlen (afx->eol); + u32 in, in2; + int idx, idx2; + int i; + + idx = afx->idx; + idx2 = afx->idx2; + memcpy (radbuf, afx->radbuf, sizeof (afx->radbuf)); + + if (size && (idx || idx2)) + { + /* preload eol to outbuf buffer */ + memcpy (outbuf + 4, afx->eol, sizeof (afx->eol)); + + for (; size && (idx || idx2); buf++, size--) + { + radbuf[idx++] = *buf; + if (idx > 2) + { + idx = 0; + in = (u32)radbuf[0] << (2 * 8); + in |= (u32)radbuf[1] << (1 * 8); + in |= (u32)radbuf[2] << (0 * 8); + outbuf[0] = bintoasc[(in >> 18) & 077]; + outbuf[1] = bintoasc[(in >> 12) & 077]; + outbuf[2] = bintoasc[(in >> 6) & 077]; + outbuf[3] = bintoasc[(in >> 0) & 077]; + if (++idx2 >= (64/4)) + { /* pgp doesn't like 72 here */ + idx2=0; + iobuf_write (a, outbuf, 4 + eollen); + } + else + { + iobuf_write (a, outbuf, 4); + } + } + } + } + + if (size >= (64/4)*3) + { + /* preload eol to outbuf buffer */ + memcpy (outbuf + 64, afx->eol, sizeof(afx->eol)); + + do + { + /* idx and idx2 == 0 */ + + for (i = 0; i < (64/8); i++) + { + in = (u32)buf[0] << (2 * 8); + in |= (u32)buf[1] << (1 * 8); + in |= (u32)buf[2] << (0 * 8); + in2 = (u32)buf[3] << (2 * 8); + in2 |= (u32)buf[4] << (1 * 8); + in2 |= (u32)buf[5] << (0 * 8); + outbuf[i*8+0] = bintoasc[(in >> 18) & 077]; + outbuf[i*8+1] = bintoasc[(in >> 12) & 077]; + outbuf[i*8+2] = bintoasc[(in >> 6) & 077]; + outbuf[i*8+3] = bintoasc[(in >> 0) & 077]; + outbuf[i*8+4] = bintoasc[(in2 >> 18) & 077]; + outbuf[i*8+5] = bintoasc[(in2 >> 12) & 077]; + outbuf[i*8+6] = bintoasc[(in2 >> 6) & 077]; + outbuf[i*8+7] = bintoasc[(in2 >> 0) & 077]; + buf+=6; + size-=6; + } + + /* pgp doesn't like 72 here */ + iobuf_write (a, outbuf, 64 + eollen); + } + while (size >= (64/4)*3); + + /* restore eol for tail handling */ + if (size) + memcpy (outbuf + 4, afx->eol, sizeof (afx->eol)); + } + + for (; size; buf++, size--) + { + radbuf[idx++] = *buf; + if (idx > 2) + { + idx = 0; + in = (u32)radbuf[0] << (2 * 8); + in |= (u32)radbuf[1] << (1 * 8); + in |= (u32)radbuf[2] << (0 * 8); + outbuf[0] = bintoasc[(in >> 18) & 077]; + outbuf[1] = bintoasc[(in >> 12) & 077]; + outbuf[2] = bintoasc[(in >> 6) & 077]; + outbuf[3] = bintoasc[(in >> 0) & 077]; + if (++idx2 >= (64/4)) + { /* pgp doesn't like 72 here */ + idx2=0; + iobuf_write (a, outbuf, 4 + eollen); + } + else + { + iobuf_write (a, outbuf, 4); + } + } + } + + memcpy (afx->radbuf, radbuf, sizeof (afx->radbuf)); + afx->idx = idx; + afx->idx2 = idx2; +} + /**************** * This filter is used to handle the armor stuff */ @@ -1006,7 +1244,7 @@ armor_filter( void *opaque, int control, { size_t size = *ret_len; armor_filter_context_t *afx = opaque; - int rc=0, i, c; + int rc=0, c; byte radbuf[3]; int idx, idx2; size_t n=0; @@ -1188,43 +1426,13 @@ armor_filter( void *opaque, int control, afx->status++; afx->idx = 0; afx->idx2 = 0; - afx->crc = CRCINIT; - + gcry_md_reset (afx->crc_md); } - crc = afx->crc; - idx = afx->idx; - idx2 = afx->idx2; - for(i=0; i < idx; i++ ) - radbuf[i] = afx->radbuf[i]; - - for(i=0; i < size; i++ ) - crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]]; - crc &= 0x00ffffff; - - for( ; size; buf++, size-- ) { - radbuf[idx++] = *buf; - if( idx > 2 ) { - idx = 0; - c = bintoasc[(*radbuf >> 2) & 077]; - iobuf_put(a, c); - c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077]; - iobuf_put(a, c); - c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; - iobuf_put(a, c); - c = bintoasc[radbuf[2]&077]; - iobuf_put(a, c); - if( ++idx2 >= (64/4) ) - { /* pgp doesn't like 72 here */ - iobuf_writestr(a,afx->eol); - idx2=0; - } - } - } - for(i=0; i < idx; i++ ) - afx->radbuf[i] = radbuf[i]; - afx->idx = idx; - afx->idx2 = idx2; - afx->crc = crc; + + if( size ) { + gcry_md_write (afx->crc_md, buf, size); + armor_output_buf_as_radix64 (afx, a, buf, size); + } } else if( control == IOBUFCTRL_INIT ) { @@ -1250,7 +1458,8 @@ armor_filter( void *opaque, int control, if( afx->cancel ) ; else if( afx->status ) { /* pad, write cecksum, and bottom line */ - crc = afx->crc; + gcry_md_final (afx->crc_md); + crc = get_afx_crc (afx); idx = afx->idx; idx2 = afx->idx2; if( idx ) { @@ -1350,221 +1559,3 @@ make_radix64_string( const byte *data, size_t len ) *p = 0; return buffer; } - - -/*********************************************** - * For the pipemode command we can't use the armor filter for various - * reasons, so we use this new unarmor_pump stuff to remove the armor - */ - -enum unarmor_state_e { - STA_init = 0, - STA_bypass, - STA_wait_newline, - STA_wait_dash, - STA_first_dash, - STA_compare_header, - STA_found_header_wait_newline, - STA_skip_header_lines, - STA_skip_header_lines_non_ws, - STA_read_data, - STA_wait_crc, - STA_read_crc, - STA_ready -}; - -struct unarmor_pump_s { - enum unarmor_state_e state; - byte val; - int checkcrc; - int pos; /* counts from 0..3 */ - u32 crc; - u32 mycrc; /* the one store in the data */ -}; - - - -UnarmorPump -unarmor_pump_new (void) -{ - UnarmorPump x; - - if( !is_initialized ) - initialize(); - x = xmalloc_clear (sizeof *x); - return x; -} - -void -unarmor_pump_release (UnarmorPump x) -{ - xfree (x); -} - -/* - * Get the next character from the ascii armor taken from the IOBUF - * created earlier by unarmor_pump_new(). - * Return: c = Character - * 256 = ignore this value - * -1 = End of current armor - * -2 = Premature EOF (not used) - * -3 = Invalid armor - */ -int -unarmor_pump (UnarmorPump x, int c) -{ - int rval = 256; /* default is to ignore the return value */ - - switch (x->state) { - case STA_init: - { - byte tmp[2]; - tmp[0] = c; - tmp[1] = 0; - if ( is_armored (tmp) ) - x->state = c == '-'? STA_first_dash : STA_wait_newline; - else { - x->state = STA_bypass; - return c; - } - } - break; - case STA_bypass: - return c; /* return here to avoid crc calculation */ - case STA_wait_newline: - if (c == '\n') - x->state = STA_wait_dash; - break; - case STA_wait_dash: - x->state = c == '-'? STA_first_dash : STA_wait_newline; - break; - case STA_first_dash: /* just need for initialization */ - x->pos = 0; - x->state = STA_compare_header; /* fall through */ - case STA_compare_header: - if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) { - if ( x->pos == 28 ) - x->state = STA_found_header_wait_newline; - } - else - x->state = c == '\n'? STA_wait_dash : STA_wait_newline; - break; - case STA_found_header_wait_newline: - /* to make CR,LF issues easier we simply allow for white space - behind the 5 dashes */ - if ( c == '\n' ) - x->state = STA_skip_header_lines; - else if ( c != '\r' && c != ' ' && c != '\t' ) - x->state = STA_wait_dash; /* garbage after the header line */ - break; - case STA_skip_header_lines: - /* i.e. wait for one empty line */ - if ( c == '\n' ) { - x->state = STA_read_data; - x->crc = CRCINIT; - x->val = 0; - x->pos = 0; - } - else if ( c != '\r' && c != ' ' && c != '\t' ) - x->state = STA_skip_header_lines_non_ws; - break; - case STA_skip_header_lines_non_ws: - /* like above but we already encountered non white space */ - if ( c == '\n' ) - x->state = STA_skip_header_lines; - break; - case STA_read_data: - /* fixme: we don't check for the trailing dash lines but rely - * on the armor stop characters */ - if( c == '\n' || c == ' ' || c == '\r' || c == '\t' ) - break; /* skip all kind of white space */ - - if( c == '=' ) { /* pad character: stop */ - if( x->pos == 1 ) /* in this case val has some value */ - rval = x->val; - x->state = STA_wait_crc; - break; - } - - { - int c2; - if( (c = asctobin[(c2=c)]) == 255 ) { - log_error(_("invalid radix64 character %02X skipped\n"), c2); - break; - } - } - - switch(x->pos) { - case 0: - x->val = c << 2; - break; - case 1: - x->val |= (c>>4)&3; - rval = x->val; - x->val = (c<<4)&0xf0; - break; - case 2: - x->val |= (c>>2)&15; - rval = x->val; - x->val = (c<<6)&0xc0; - break; - case 3: - x->val |= c&0x3f; - rval = x->val; - break; - } - x->pos = (x->pos+1) % 4; - break; - case STA_wait_crc: - if( c == '\n' || c == ' ' || c == '\r' || c == '\t' || c == '=' ) - break; /* skip ws and pad characters */ - /* assume that we are at the next line */ - x->state = STA_read_crc; - x->pos = 0; - x->mycrc = 0; /* fall through */ - case STA_read_crc: - if( (c = asctobin[c]) == 255 ) { - rval = -1; /* ready */ - if( x->crc != x->mycrc ) { - log_info (_("CRC error; %06lX - %06lX\n"), - (ulong)x->crc, (ulong)x->mycrc); - if ( invalid_crc() ) - rval = -3; - } - x->state = STA_ready; /* not sure whether this is correct */ - break; - } - - switch(x->pos) { - case 0: - x->val = c << 2; - break; - case 1: - x->val |= (c>>4)&3; - x->mycrc |= x->val << 16; - x->val = (c<<4)&0xf0; - break; - case 2: - x->val |= (c>>2)&15; - x->mycrc |= x->val << 8; - x->val = (c<<6)&0xc0; - break; - case 3: - x->val |= c&0x3f; - x->mycrc |= x->val; - break; - } - x->pos = (x->pos+1) % 4; - break; - case STA_ready: - rval = -1; - break; - } - - if ( !(rval & ~255) ) { /* compute the CRC */ - x->crc = (x->crc << 8) ^ crc_table[((x->crc >> 16)&0xff) ^ rval]; - x->crc &= 0x00ffffff; - } - - return rval; -} diff --git a/g10/build-packet.c b/g10/build-packet.c index b4e03d007..07fccb099 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -243,12 +243,15 @@ build_packet_and_meta (iobuf_t out, PACKET *pkt) /* - * Write the mpi A to OUT. + * Write the mpi A to OUT. If R_NWRITTEN is not NULL the number of + * bytes written is stored there. To only get the number of bytes + * which would be written NULL may be passed for OUT. */ gpg_error_t -gpg_mpi_write (iobuf_t out, gcry_mpi_t a) +gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten) { - int rc; + gpg_error_t err; + unsigned int nwritten = 0; if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) { @@ -277,9 +280,17 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a) /* gcry_log_debughex (" ", p, (nbits+7)/8); */ lenhdr[0] = nbits >> 8; lenhdr[1] = nbits; - rc = iobuf_write (out, lenhdr, 2); - if (!rc && p) - rc = iobuf_write (out, p, (nbits+7)/8); + err = out? iobuf_write (out, lenhdr, 2) : 0; + if (!err) + { + nwritten += 2; + if (p) + { + err = out? iobuf_write (out, p, (nbits+7)/8) : 0; + if (!err) + nwritten += (nbits+7)/8; + } + } } else { @@ -287,18 +298,25 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a) size_t nbytes; nbytes = DIM(buffer); - rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a ); - if( !rc ) - rc = iobuf_write( out, buffer, nbytes ); - else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT ) + err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a ); + if (!err) + { + err = out? iobuf_write (out, buffer, nbytes) : 0; + if (!err) + nwritten += nbytes; + } + else if (gpg_err_code (err) == GPG_ERR_TOO_SHORT ) { log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a)); - /* The buffer was too small. We better tell the user about the MPI. */ - rc = gpg_error (GPG_ERR_TOO_LARGE); + /* The buffer was too small. We better tell the user about + * the MPI. */ + err = gpg_error (GPG_ERR_TOO_LARGE); } } - return rc; + if (r_nwritten) + *r_nwritten = nwritten; + return err; } @@ -463,29 +481,29 @@ static int do_key (iobuf_t out, int ctb, PKT_public_key *pk) { gpg_error_t err = 0; - /* The length of the body is stored in the packet's header, which - occurs before the body. Unfortunately, we don't know the length - of the packet's body until we've written all of the data! To - work around this, we first write the data into this temporary - buffer, then generate the header, and finally copy the contents - of this buffer to OUT. */ - iobuf_t a = iobuf_temp(); + iobuf_t a; int i, nskey, npkey; + u32 pkbytes = 0; + int is_v5; - log_assert (pk->version == 0 || pk->version == 4); + log_assert (pk->version == 0 || pk->version == 4 || pk->version == 5); log_assert (ctb_pkttype (ctb) == PKT_PUBLIC_KEY || ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY || ctb_pkttype (ctb) == PKT_SECRET_KEY || ctb_pkttype (ctb) == PKT_SECRET_SUBKEY); - /* Write the version number - if none is specified, use 4 */ - if ( !pk->version ) - iobuf_put ( a, 4 ); - else - iobuf_put ( a, pk->version ); - write_32 (a, pk->timestamp ); + /* The length of the body is stored in the packet's header, which + * occurs before the body. Unfortunately, we don't know the length + * of the packet's body until we've written all of the data! To + * work around this, we first write the data into this temporary + * buffer, then generate the header, and finally copy the content + * of this buffer to OUT. */ + a = iobuf_temp(); + + /* Note that the Version number, Timestamp, Algo, and the v5 Key + * material count are written at the end of the function. */ - iobuf_put (a, pk->pubkey_algo ); + is_v5 = (pk->version == 5); /* Get number of secret and public parameters. They are held in one array: the public ones followed by the secret ones. */ @@ -509,11 +527,13 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk) || (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2))) err = gpg_mpi_write_nohdr (a, pk->pkey[i]); else - err = gpg_mpi_write (a, pk->pkey[i]); + err = gpg_mpi_write (a, pk->pkey[i], NULL); if (err) goto leave; } + /* Record the length of the public key part. */ + pkbytes = iobuf_get_temp_length (a); if (pk->seckey_info) { @@ -523,9 +543,26 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk) /* Build the header for protected (encrypted) secret parameters. */ if (ski->is_protected) { - /* OpenPGP protection according to rfc2440. */ - iobuf_put (a, ski->sha1chk? 0xfe : 0xff); - iobuf_put (a, ski->algo); + iobuf_put (a, ski->sha1chk? 0xfe : 0xff); /* S2k usage. */ + if (is_v5) + { + /* For a v5 key determine the count of the following + * key-protection material and write it. */ + int count = 1; /* Pubkey algo octet. */ + if (ski->s2k.mode >= 1000) + count += 6; /* GNU specific mode descriptor. */ + else + count += 2; /* Mode and hash algo. */ + if (ski->s2k.mode == 1 || ski->s2k.mode == 3) + count += 8; /* Salt. */ + if (ski->s2k.mode == 3) + count++; /* S2K.COUNT */ + if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002) + count += ski->ivlen; + + iobuf_put (a, count); + } + iobuf_put (a, ski->algo); /* Pubkey algo octet. */ if (ski->s2k.mode >= 1000) { /* These modes are not possible in OpenPGP, we use them @@ -556,13 +593,24 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk) } else /* Not protected. */ - iobuf_put (a, 0 ); + { + iobuf_put (a, 0 ); /* S2K usage = not protected. */ + if (is_v5) + iobuf_put (a, 0); /* Zero octets of key-protection + * material follows. */ + } if (ski->s2k.mode == 1001) - ; /* GnuPG extension - don't write a secret key at all. */ + { + /* GnuPG extension - don't write a secret key at all. */ + if (is_v5) + write_32 (a, 0); /* Zero octets of key material. */ + } else if (ski->s2k.mode == 1002) { /* GnuPG extension - divert to OpenPGP smartcard. */ + if (is_v5) + write_32 (a, 1 + ski->ivlen); /* Length of the serial number or 0 for no serial number. */ iobuf_put (a, ski->ivlen ); /* The serial number gets stored in the IV field. */ @@ -576,15 +624,36 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk) log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE)); p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits); + /* For v5 keys we first write the number of octets of the + * following encrypted key material. */ + if (is_v5) + write_32 (a, p? (ndatabits+7)/8 : 0); if (p) iobuf_write (a, p, (ndatabits+7)/8 ); } else { /* Non-protected key. */ + if (is_v5) + { + unsigned int skbytes = 0; + unsigned int n; + int j; + + for (j=i; j < nskey; j++ ) + { + if ((err = gpg_mpi_write (NULL, pk->pkey[j], &n))) + goto leave; + skbytes += n; + } + + write_32 (a, skbytes); + } + for ( ; i < nskey; i++ ) - if ( (err = gpg_mpi_write (a, pk->pkey[i]))) + if ( (err = gpg_mpi_write (a, pk->pkey[i], NULL))) goto leave; + write_16 (a, ski->csum ); } } @@ -593,11 +662,23 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk) if (!err) { /* Build the header of the packet - which we must do after - writing all the other stuff, so that we know the length of - the packet */ - write_header2 (out, ctb, iobuf_get_temp_length(a), 0); + * writing all the other stuff, so that we know the length of + * the packet */ + u32 len = iobuf_get_temp_length (a); + len += 1; /* version number */ + len += 4; /* timestamp */ + len += 1; /* algo */ + if (is_v5) + len += 4; /* public key material count */ + + write_header2 (out, ctb, len, 0); /* And finally write it out to the real stream. */ - err = iobuf_write_temp (out, a); + iobuf_put (out, pk->version? pk->version : 4); /* version number */ + write_32 (out, pk->timestamp ); + iobuf_put (out, pk->pubkey_algo); /* algo */ + if (is_v5) + write_32 (out, pkbytes); /* public key material count */ + err = iobuf_write_temp (out, a); /* pub and sec key material */ } iobuf_close (a); /* Close the temporary buffer */ @@ -688,7 +769,7 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1) rc = gpg_mpi_write_nohdr (a, enc->data[i]); else - rc = gpg_mpi_write (a, enc->data[i]); + rc = gpg_mpi_write (a, enc->data[i], NULL); } if (!rc) @@ -1135,10 +1216,10 @@ build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk) /* Write the new ISSUER_FPR subpacket. */ fingerprint_from_pk (pksk, buf+1, &fprlen); - if (fprlen == 20) + if (fprlen == 20 || fprlen == 32) { buf[0] = pksk->version; - build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21); + build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, fprlen + 1); } /* Write the timestamp. */ @@ -1297,7 +1378,7 @@ string_to_notation(const char *string,int is_utf8) } notation->name=xmalloc((s-string)+1); - strncpy(notation->name,string,s-string); + memcpy(notation->name,string,s-string); notation->name[s-string]='\0'; if(!saw_at && !opt.expert) @@ -1536,7 +1617,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig ) else iobuf_put( a, sig->version ); if ( sig->version < 4 ) - iobuf_put (a, 5 ); /* Constant */ + iobuf_put (a, 5 ); /* Constant used by pre-v4 signatures. */ iobuf_put (a, sig->sig_class ); if ( sig->version < 4 ) { @@ -1567,7 +1648,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig ) if ( !n ) write_fake_data( a, sig->data[0] ); for (i=0; i < n && !rc ; i++ ) - rc = gpg_mpi_write (a, sig->data[i] ); + rc = gpg_mpi_write (a, sig->data[i], NULL); if (!rc) { diff --git a/g10/call-agent.c b/g10/call-agent.c index 755f2e30b..83777534e 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -609,6 +609,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, "bt")) + parm->extcap.bt = abool; else if (!strcmp (p, "kdf")) parm->extcap.kdf = abool; else if (!strcmp (p, "si")) @@ -705,6 +707,21 @@ learn_status_cb (void *opaque, const char *line) xfree (parm->private_do[no]); parm->private_do[no] = unescape_status_string (line); } + else if (keywordlen == 3 && !memcmp (keyword, "KDF", 3)) + { + parm->kdf_do_enabled = 1; + } + else if (keywordlen == 5 && !memcmp (keyword, "UIF-", 4) + && strchr("123", keyword[4])) + { + unsigned char *data; + int no = keyword[4] - '1'; + + log_assert (no >= 0 && no <= 2); + data = unescape_status_string (line); + parm->uif[no] = (data[0] != 0xff); + xfree (data); + } return 0; } @@ -1201,7 +1218,7 @@ agent_scd_cardlist (strlist_t *result) memset (&parm, 0, sizeof parm); *result = NULL; - err = start_agent (NULL, 1); + err = start_agent (NULL, 1 | FLAG_FOR_CARD_SUPPRESS_ERRORS); if (err) return err; @@ -1444,19 +1461,19 @@ gpg_agent_get_confirmation (const char *desc) } -/* Return the S2K iteration count as computed by gpg-agent. */ -gpg_error_t -agent_get_s2k_count (unsigned long *r_count) +/* Return the S2K iteration count as computed by gpg-agent. On error + * print a warning and return a default value. */ +unsigned long +agent_get_s2k_count (void) { gpg_error_t err; membuf_t data; char *buf; - - *r_count = 0; + unsigned long count = 0; err = start_agent (NULL, 0); if (err) - return err; + goto leave; init_membuf (&data, 32); err = assuan_transact (agent_ctx, "GETINFO s2k_count", @@ -1472,11 +1489,23 @@ agent_get_s2k_count (unsigned long *r_count) err = gpg_error_from_syserror (); else { - *r_count = strtoul (buf, NULL, 10); + count = strtoul (buf, NULL, 10); xfree (buf); } } - return err; + + leave: + if (err || count < 65536) + { + /* Don't print an error if an older agent is used. */ + if (err && gpg_err_code (err) != GPG_ERR_ASS_PARAMETER) + log_error (_("problem with the agent: %s\n"), gpg_strerror (err)); + + /* Default to 65536 which was used up to 2.0.13. */ + count = 65536; + } + + return count; } diff --git a/g10/call-agent.h b/g10/call-agent.h index 59e4ff486..8619a34f8 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -69,8 +69,11 @@ struct agent_card_info_s 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. */ + unsigned int bt:1; /* Button for confirmation available. */ } extcap; unsigned int status_indicator; + int kdf_do_enabled; /* True if card has a KDF object. */ + int uif[3]; /* True if User Interaction Flag is on. */ }; @@ -143,7 +146,7 @@ gpg_error_t agent_clear_passphrase (const char *cache_id); gpg_error_t gpg_agent_get_confirmation (const char *desc); /* Return the S2K iteration count as computed by gpg-agent. */ -gpg_error_t agent_get_s2k_count (unsigned long *r_count); +unsigned long agent_get_s2k_count (void); /* Check whether a secret key for public key PK is available. Returns 0 if the secret key is available. */ @@ -192,14 +195,14 @@ gpg_error_t agent_keywrap_key (ctrl_t ctrl, int forexport, gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr, const void *key, size_t keylen, int unattended, int force, - u32 *keyid, u32 *mainkeyid, int pubkey_algo); + u32 *keyid, u32 *mainkeyid, int pubkey_algo); /* Receive a key from the agent. */ gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc, int openpgp_protected, char **cache_nonce_addr, unsigned char **r_result, size_t *r_resultlen, - u32 *keyid, u32 *mainkeyid, int pubkey_algo); + u32 *keyid, u32 *mainkeyid, int pubkey_algo); /* Delete a key from the agent. */ gpg_error_t agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 11663b9b1..8f83c087f 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -608,6 +608,12 @@ gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr, NULL, NULL, ks_status_cb, &stparm); if (!err) err = cb (cb_value, 0, NULL); /* Send EOF. */ + else if (parm.stparm->source) + { + /* Error but we received a SOURCE status. Tell via callback but + * ignore errors. */ + parm.data_cb (parm.data_cb_value, 1, parm.stparm->source); + } xfree (get_membuf (&parm.saveddata, NULL)); xfree (parm.helpbuf); @@ -650,6 +656,7 @@ ks_get_data_cb (void *opaque, const void *data, size_t datalen) If R_SOURCE is not NULL the source of the data is stored as a malloced string there. If a source is not known NULL is stored. + Note that this may even be returned after an error. If there are too many patterns the function returns an error. That could be fixed by issuing several search commands or by @@ -737,13 +744,13 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, *r_fp = parm.memfp; parm.memfp = NULL; - if (r_source) + + leave: + if (r_source && stparm.source) { *r_source = stparm.source; stparm.source = NULL; } - - leave: es_fclose (parm.memfp); xfree (stparm.source); xfree (line); @@ -1076,7 +1083,7 @@ ks_put_inq_cb (void *opaque, const char *line) /* Send a key to the configured server. {DATA,DATLEN} contains the key in OpenPGP binary transport format. If KEYBLOCK is not NULL it - has the internal representaion of that key; this is for example + has the internal representation of that key; this is for example used to convey meta data to LDAP keyservers. */ gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock) diff --git a/g10/card-util.c b/g10/card-util.c index e9c0120a1..08844bae3 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -216,6 +216,7 @@ get_manufacturer (unsigned int no) case 0x1337: return "Warsaw Hackerspace"; case 0x2342: return "warpzone"; /* hackerspace Muenster. */ + case 0x4354: return "Confidential Technologies"; /* cotech.de */ case 0x63AF: return "Trustica"; case 0xBD0E: return "Paranoidlabs"; case 0xF517: return "FSIJ"; @@ -275,7 +276,7 @@ print_keygrip (estream_t fp, const unsigned char *grp) { tty_fprintf (fp, " keygrip ....: "); for (i=0; i < 20 ; i++, grp++) - es_fprintf (fp, "%02X", *grp); + tty_fprintf (fp, "%02X", *grp); tty_fprintf (fp, "\n"); } } @@ -511,6 +512,15 @@ current_card_status (ctrl_t ctrl, estream_t fp, es_fprintf (fp, "pinretry:%d:%d:%d:\n", info.chvretry[0], info.chvretry[1], info.chvretry[2]); es_fprintf (fp, "sigcount:%lu:::\n", info.sig_counter); + if (info.extcap.kdf) + { + es_fprintf (fp, "kdf:%s:\n", info.kdf_do_enabled ? "on" : "off"); + } + if (info.extcap.bt) + { + es_fprintf (fp, "uif:%d:%d:%d:\n", + info.uif[0], info.uif[1], info.uif[2]); + } for (i=0; i < 4; i++) { @@ -617,6 +627,17 @@ current_card_status (ctrl_t ctrl, estream_t fp, tty_fprintf (fp, "PIN retry counter : %d %d %d\n", info.chvretry[0], info.chvretry[1], info.chvretry[2]); tty_fprintf (fp, "Signature counter : %lu\n", info.sig_counter); + if (info.extcap.kdf) + { + tty_fprintf (fp, "KDF setting ......: %s\n", + info.kdf_do_enabled ? "on" : "off"); + } + if (info.extcap.bt) + { + tty_fprintf (fp, "UIF setting ......: Sign=%s Decrypt=%s Auth=%s\n", + info.uif[0] ? "on" : "off", info.uif[1] ? "on" : "off", + info.uif[2] ? "on" : "off"); + } tty_fprintf (fp, "Signature key ....:"); print_shax_fpr (fp, info.fpr1len? info.fpr1:NULL, info.fpr1len); if (info.fpr1len && info.fpr1time) @@ -647,7 +668,7 @@ current_card_status (ctrl_t ctrl, estream_t fp, info.fpr3len? info.fpr3 : NULL); thefprlen = (info.fpr1len? info.fpr1len : info.fpr2len? info.fpr2len : info.fpr3len? info.fpr3len : 0); - /* If the fingerprint is all 0xff, the key has no asssociated + /* If the fingerprint is all 0xff, the key has no associated OpenPGP certificate. */ if ( thefpr && !fpr_is_ff (thefpr, thefprlen) && !get_pubkey_byfprint (ctrl, pk, &keyblock, thefpr, thefprlen)) @@ -674,7 +695,7 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno) { int err; strlist_t card_list, sl; - char *serialno0; + char *serialno0, *serialno1; int all_cards = 0; if (serialno == NULL) @@ -700,8 +721,6 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno) for (sl = card_list; sl; sl = sl->next) { - char *serialno1; - if (!all_cards && strcmp (serialno, sl->d)) continue; @@ -722,7 +741,8 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno) } /* Select the original card again. */ - err = agent_scd_serialno (&serialno0, serialno0); + err = agent_scd_serialno (&serialno1, serialno0); + xfree (serialno1); leave: xfree (serialno0); @@ -2019,7 +2039,7 @@ gen_kdf_data (unsigned char *data, int single_salt) p = data; - s2k_char = encode_s2k_iterations (0); + s2k_char = encode_s2k_iterations (agent_get_s2k_count ()); iterations = S2K_DECODE_COUNT (s2k_char); count_4byte[0] = (iterations >> 24) & 0xff; count_4byte[1] = (iterations >> 16) & 0xff; @@ -2110,6 +2130,49 @@ kdf_setup (const char *args) leave: agent_release_card_info (&info); } + +static void +uif (int arg_number, const char *arg_rest) +{ + struct agent_card_info_s info; + int feature_available; + gpg_error_t err; + char name[100]; + unsigned char data[2]; + + 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; + } + + feature_available = info.extcap.bt; + agent_release_card_info (&info); + + if (!feature_available) + { + log_error (_("This command is not supported by this card\n")); + tty_printf ("\n"); + return; + } + + snprintf (name, sizeof name, "UIF-%d", arg_number); + if ( !strcmp (arg_rest, "off") ) + data[0] = 0x00; + else if ( !strcmp (arg_rest, "on") ) + data[0] = 0x01; + else if ( !strcmp (arg_rest, "permanent") ) + data[0] = 0x02; + + data[1] = 0x20; + + err = agent_scd_setattr (name, data, 2, NULL); + if (err) + log_error (_("error for setup UIF: %s\n"), gpg_strerror (err)); +} /* Data used by the command parser. This needs to be outside of the function scope to allow readline based command completion. */ @@ -2120,7 +2183,7 @@ enum cmdids cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR, cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT, cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP, - cmdKEYATTR, + cmdKEYATTR, cmdUIF, cmdINVCMD }; @@ -2152,10 +2215,11 @@ static struct { "generate", cmdGENERATE, 1, N_("generate new keys")}, { "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")}, { "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")}, - { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") }, + { "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")}, { "key-attr", cmdKEYATTR, 1, N_("change the key attribute")}, + { "uif", cmdUIF, 1, N_("change the User Interaction Flag")}, /* Note, that we do not announce these command yet. */ { "privatedo", cmdPRIVATEDO, 0, NULL }, { "readcert", cmdREADCERT, 0, NULL }, @@ -2447,6 +2511,14 @@ card_edit (ctrl_t ctrl, strlist_t commands) key_attr (); break; + case cmdUIF: + if ( arg_number < 1 || arg_number > 3 ) + tty_printf ("usage: uif N [on|off|permanent]\n" + " 1 <= N <= 3\n"); + else + uif (arg_number, arg_rest); + break; + case cmdQUIT: goto leave; diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c index f9a996c80..b14b85444 100644 --- a/g10/cipher-aead.c +++ b/g10/cipher-aead.c @@ -278,7 +278,7 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size) if (DBG_FILTER) log_debug ("chunksize %ju reached;" " cur buflen=%zu using %zu of %zu\n", - (uintmax_t)cfx->chunksize, (uintmax_t)cfx->buflen, + cfx->chunksize, cfx->buflen, n1, n); n = n1; } @@ -142,7 +142,8 @@ write_status ( int no ) /* Write a status line with code NO followed by the string TEXT and - directly followed by the remaining strings up to a NULL. */ + * directly followed by the remaining strings up to a NULL. Embedded + * CR and LFs in the strings (but not in TEXT) are C-style escaped.*/ void write_status_strings (int no, const char *text, ...) { @@ -187,13 +188,13 @@ write_status_text (int no, const char *text) } -/* Write a status line with code NO followed by the outout of the - * printf style FORMAT. The caller needs to make sure that LFs and - * CRs are not printed. */ +/* Write a status line with code NO followed by the output of the + * printf style FORMAT. Embedded CR and LFs are C-style escaped. */ void write_status_printf (int no, const char *format, ...) { va_list arg_ptr; + char *buf; if (!statusfp || !status_currently_allowed (no) ) return; /* Not enabled or allowed. */ @@ -204,7 +205,30 @@ write_status_printf (int no, const char *format, ...) { es_putc ( ' ', statusfp); va_start (arg_ptr, format); - es_vfprintf (statusfp, format, arg_ptr); + buf = gpgrt_vbsprintf (format, arg_ptr); + if (!buf) + log_error ("error printing status line: %s\n", + gpg_strerror (gpg_err_code_from_syserror ())); + else + { + if (strpbrk (buf, "\r\n")) + { + const byte *s; + for (s=buf; *s; s++) + { + if (*s == '\n') + es_fputs ("\\n", statusfp); + else if (*s == '\r') + es_fputs ("\\r", statusfp); + else + es_fputc (*s, statusfp); + } + } + else + es_fputs (buf, statusfp); + gpgrt_free (buf); + } + va_end (arg_ptr); } es_putc ('\n', statusfp); diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index a3151b5ed..4d9dc86d9 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -42,7 +42,7 @@ static int decode_filter ( void *opaque, int control, IOBUF a, /* Our context object. */ struct decode_filter_context_s { - /* Recounter (max value is 2). We need it becuase we do not know + /* Recounter (max value is 2). We need it because we do not know * whether the iobuf or the outer control code frees this object * first. */ int refcount; @@ -551,31 +551,42 @@ fill_buffer (decode_filter_ctx_t dfx, iobuf_t stream, byte *buffer, size_t nbytes, size_t offset) { size_t nread = offset; - int c; + size_t curr; + int ret; if (dfx->partial) { - for (; nread < nbytes; nread++ ) + while (nread < nbytes) { - if ((c = iobuf_get (stream)) == -1) + curr = nbytes - nread; + + ret = iobuf_read (stream, &buffer[nread], curr); + if (ret == -1) { dfx->eof_seen = 1; /* Normal EOF. */ break; } - buffer[nread] = c; + + nread += ret; } } else { - for (; nread < nbytes && dfx->length; nread++, dfx->length--) + while (nread < nbytes && dfx->length) { - c = iobuf_get (stream); - if (c == -1) + curr = nbytes - nread; + if (curr > dfx->length) + curr = dfx->length; + + ret = iobuf_read (stream, &buffer[nread], curr); + if (ret == -1) { dfx->eof_seen = 3; /* Premature EOF. */ break; } - buffer[nread] = c; + + nread += ret; + dfx->length -= ret; } if (!dfx->length) dfx->eof_seen = 1; /* Normal EOF. */ @@ -647,7 +658,7 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) * case when a chunk ends within the buffer. */ if (DBG_FILTER) log_debug ("decrypt: chunklen=%ju total=%ju size=%zu len=%zu%s\n", - (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, size, len, + dfx->chunklen, dfx->total, size, len, dfx->eof_seen? " eof":""); while (len && dfx->chunklen + len >= dfx->chunksize) @@ -683,7 +694,7 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) len -= n; if (DBG_FILTER) - log_debug ("ndecrypted: %zu (nchunk=%zu) bytes left: %zu at off=%zu\n", + log_debug ("ndecrypted: %zu (nchunk=%ju) bytes left: %zu at off=%zu\n", totallen, dfx->chunklen, len, off); /* Check the tag. */ @@ -765,7 +776,7 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) dfx->chunklen += len; dfx->total += len; if (DBG_FILTER) - log_debug ("ndecrypted: %zu (nchunk=%zu)\n", totallen, dfx->chunklen); + log_debug ("ndecrypted: %zu (nchunk=%ju)\n", totallen, dfx->chunklen); } if (dfx->eof_seen) @@ -873,7 +884,6 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, decode_filter_ctx_t dfx = opaque; size_t n, size = *ret_len; int rc = 0; - int c; /* Note: We need to distinguish between a partial and a fixed length packet. The first is the usual case as created by GPG. However @@ -894,25 +904,7 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, log_assert (size > 44); /* Our code requires at least this size. */ /* Get at least 22 bytes and put it ahead in the buffer. */ - if (dfx->partial) - { - for (n=22; n < 44; n++) - { - if ( (c = iobuf_get(a)) == -1 ) - break; - buf[n] = c; - } - } - else - { - for (n=22; n < 44 && dfx->length; n++, dfx->length--) - { - c = iobuf_get (a); - if (c == -1) - break; /* Premature EOF. */ - buf[n] = c; - } - } + n = fill_buffer (dfx, a, buf, 44, 22); if (n == 44) { /* We have enough stuff - flush the holdback buffer. */ @@ -923,37 +915,11 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, } else { - memcpy (buf, dfx->holdback, 22); } + /* Fill up the buffer. */ - if (dfx->partial) - { - for (; n < size; n++ ) - { - if ( (c = iobuf_get(a)) == -1 ) - { - dfx->eof_seen = 1; /* Normal EOF. */ - break; - } - buf[n] = c; - } - } - else - { - for (; n < size && dfx->length; n++, dfx->length--) - { - c = iobuf_get(a); - if (c == -1) - { - dfx->eof_seen = 3; /* Premature EOF. */ - break; - } - buf[n] = c; - } - if (!dfx->length) - dfx->eof_seen = 1; /* Normal EOF. */ - } + n = fill_buffer (dfx, a, buf, size, n); /* Move the trailing 22 bytes back to the holdback buffer. We have at least 44 bytes thus a memmove is not needed. */ @@ -1008,7 +974,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) decode_filter_ctx_t fc = opaque; size_t size = *ret_len; size_t n; - int c, rc = 0; + int rc = 0; if ( control == IOBUFCTRL_UNDERFLOW && fc->eof_seen ) @@ -1020,34 +986,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { log_assert (a); - if (fc->partial) - { - for (n=0; n < size; n++ ) - { - c = iobuf_get(a); - if (c == -1) - { - fc->eof_seen = 1; /* Normal EOF. */ - break; - } - buf[n] = c; - } - } - else - { - for (n=0; n < size && fc->length; n++, fc->length--) - { - c = iobuf_get(a); - if (c == -1) - { - fc->eof_seen = 3; /* Premature EOF. */ - break; - } - buf[n] = c; - } - if (!fc->length) - fc->eof_seen = 1; /* Normal EOF. */ - } + n = fill_buffer (fc, a, buf, size, 0); if (n) { if (fc->cipher_hd) diff --git a/g10/delkey.c b/g10/delkey.c index bf8c4e93b..cc5673846 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -69,9 +69,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, /* Search the userid. */ err = classify_user_id (username, &desc, 1); - exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR - || desc.mode == KEYDB_SEARCH_MODE_FPR16 - || desc.mode == KEYDB_SEARCH_MODE_FPR20); + exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR); if (!err) err = keydb_search (hd, &desc, 1, NULL); if (err) diff --git a/g10/encrypt.c b/g10/encrypt.c index 04a9ab214..972d13c7c 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -732,7 +732,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, /* In case 3DES has been selected, print a warning if any key does not have a preference for AES. This should help to - indentify why encrypting to several recipients falls back to + identify why encrypting to several recipients falls back to 3DES. */ if (opt.verbose && cfx.dek->algo == CIPHER_ALGO_3DES) warn_missing_aes_from_pklist (pk_list); @@ -1003,7 +1003,7 @@ encrypt_filter (void *opaque, int control, /* In case 3DES has been selected, print a warning if any key does not have a preference for AES. This - should help to indentify why encrypting to several + should help to identify why encrypting to several recipients falls back to 3DES. */ if (opt.verbose && efx->cfx.dek->algo == CIPHER_ALGO_3DES) diff --git a/g10/export.c b/g10/export.c index e94e959fb..4f6c9137e 100644 --- a/g10/export.c +++ b/g10/export.c @@ -97,7 +97,7 @@ cleanup_export_globals (void) } -/* Option parser for export options. See parse_options fro +/* Option parser for export options. See parse_options for details. */ int parse_export_options(char *str,unsigned int *options,int noisy) @@ -114,6 +114,8 @@ parse_export_options(char *str,unsigned int *options,int noisy) N_("remove unusable parts from key during export")}, {"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL, N_("remove as much as possible from key during export")}, + {"export-drop-uids", EXPORT_DROP_UIDS, NULL, + N_("Do not export user id or attribute packets")}, {"export-pka", EXPORT_PKA_FORMAT, NULL, NULL }, {"export-dane", EXPORT_DANE_FORMAT, NULL, NULL }, @@ -136,14 +138,20 @@ parse_export_options(char *str,unsigned int *options,int noisy) int rc; rc = parse_options (str, options, export_opts, noisy); - if (rc && (*options & EXPORT_BACKUP)) + if (!rc) + return 0; + + /* Alter other options we want or don't want for restore. */ + if ((*options & EXPORT_BACKUP)) { - /* Alter other options we want or don't want for restore. */ *options |= (EXPORT_LOCAL_SIGS | EXPORT_ATTRIBUTES | EXPORT_SENSITIVE_REVKEYS); *options &= ~(EXPORT_CLEAN | EXPORT_MINIMAL | EXPORT_PKA_FORMAT | EXPORT_DANE_FORMAT); } + /* Dropping uids also means to drop attributes. */ + if ((*options & EXPORT_DROP_UIDS)) + *options &= ~(EXPORT_ATTRIBUTES); return rc; } @@ -443,10 +451,8 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node) keyid_from_pk (node->pkt->pkt.public_key, kid); break; - case KEYDB_SEARCH_MODE_FPR16: - case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: - fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen); + fingerprint_from_pk (node->pkt->pkt.public_key, fpr, &fprlen); break; default: @@ -465,14 +471,8 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node) result = 1; break; - case KEYDB_SEARCH_MODE_FPR16: - if (!memcmp (desc->u.fpr, fpr, 16)) - result = 1; - break; - - case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: - if (!memcmp (desc->u.fpr, fpr, 20)) + if (fprlen == desc->fprlen && !memcmp (desc->u.fpr, fpr, desc->fprlen)) result = 1; break; @@ -1171,7 +1171,7 @@ print_status_exported (PKT_public_key *pk) * passphrase-protected. Otherwise, store secret key material in the * clear. * - * CACHE_NONCE_ADDR is used to share nonce for multple key retrievals. + * CACHE_NONCE_ADDR is used to share nonce for multiple key retrievals. */ gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, @@ -1461,7 +1461,7 @@ print_pka_or_dane_records (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk, continue; xfree (mbox); - mbox = mailbox_from_userid (uid->name); + mbox = mailbox_from_userid (uid->name, 0); if (!mbox) continue; @@ -1575,7 +1575,7 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, if (node->pkt->pkttype == PKT_COMMENT) continue; - /* Skip ring trust packets - they should not ne here anyway. */ + /* Skip ring trust packets - they should not be here anyway. */ if (node->pkt->pkttype == PKT_RING_TRUST) continue; @@ -1650,6 +1650,19 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, } } + /* Don't export user ids (and attributes)? This is not RFC-4880 + * compliant but we allow it anyway. */ + if ((options & EXPORT_DROP_UIDS) + && node->pkt->pkttype == PKT_USER_ID) + { + /* Skip until we get to something that is not a user id (or + * attrib) or a signature on it. */ + while (kbctx->next && kbctx->next->pkt->pkttype == PKT_SIGNATURE) + kbctx = kbctx->next; + + continue; + } + /* Don't export attribs? */ if (!(options & EXPORT_ATTRIBUTES) && node->pkt->pkttype == PKT_USER_ID diff --git a/g10/filter.h b/g10/filter.h index 6daf273fa..b2ef3828f 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -61,7 +61,7 @@ typedef struct { byte radbuf[4]; int idx, idx2; - u32 crc; + gcry_md_hd_t crc_md; int status; /* an internal state flag */ int cancel; @@ -69,8 +69,6 @@ typedef struct { int pending_lf; /* used together with faked */ } armor_filter_context_t; -struct unarmor_pump_s; -typedef struct unarmor_pump_s *UnarmorPump; struct compress_filter_context_s { @@ -172,9 +170,6 @@ armor_filter_context_t *new_armor_context (void); void release_armor_context (armor_filter_context_t *afx); int push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf); int use_armor_filter( iobuf_t a ); -UnarmorPump unarmor_pump_new (void); -void unarmor_pump_release (UnarmorPump x); -int unarmor_pump (UnarmorPump x, int c); /*-- compress.c --*/ gpg_error_t push_compress_filter (iobuf_t out, compress_filter_context_t *zfx, diff --git a/g10/getkey.c b/g10/getkey.c index ea2dee21d..9dae879d2 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -60,7 +60,7 @@ struct getkey_ctx_s search or not. A search that is exact requires that a key or subkey meet all of the specified criteria. A search that is not exact allows selecting a different key or subkey from the - keyblock that matched the critera. Further, an exact search + keyblock that matched the criteria. Further, an exact search returns the key or subkey that matched whereas a non-exact search typically returns the primary key. See finish_lookup for details. */ @@ -897,8 +897,6 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist, if (!include_unusable && ctx->items[n].mode != KEYDB_SEARCH_MODE_SHORT_KID && ctx->items[n].mode != KEYDB_SEARCH_MODE_LONG_KID - && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR16 - && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR20 && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR) { ctx->items[n].skipfnc = skip_unusable; @@ -1373,7 +1371,7 @@ pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old, n; n = find_next_kbnode (n, PKT_USER_ID)) { PKT_user_id *uid = n->pkt->pkt.user_id; - char *mbox = mailbox_from_userid (uid->name); + char *mbox = mailbox_from_userid (uid->name, 0); int match = mbox ? strcasecmp (name, mbox) == 0 : 0; xfree (mbox); @@ -1654,7 +1652,7 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock, if (r_keyblock) *r_keyblock = NULL; - if (fprint_len == 20 || fprint_len == 16) + if (fprint_len == 32 || fprint_len == 20 || fprint_len == 16) { struct getkey_ctx_s ctx; KBNODE kb = NULL; @@ -1670,9 +1668,9 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock, return gpg_error_from_syserror (); ctx.nitems = 1; - ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16 - : KEYDB_SEARCH_MODE_FPR20; + ctx.items[0].mode = KEYDB_SEARCH_MODE_FPR; memcpy (ctx.items[0].u.fpr, fprint, fprint_len); + ctx.items[0].fprlen = fprint_len; if (pk) ctx.req_usage = pk->req_usage; rc = lookup (ctrl, &ctx, 0, &kb, &found_key); @@ -1745,8 +1743,6 @@ get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd, for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++) fprbuf[i] = fprint[i]; - while (i < MAX_FINGERPRINT_LEN) - fprbuf[i++] = 0; hd = keydb_new (); if (!hd) @@ -1770,7 +1766,7 @@ get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd, if (r_hd) *r_hd = hd; - err = keydb_search_fpr (hd, fprbuf); + err = keydb_search_fpr (hd, fprbuf, fprint_len); if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) { if (!r_hd) @@ -2577,10 +2573,22 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked, xrealloc (pk->revkey, sizeof (struct revocation_key) * (pk->numrevkeys + sig->numrevkeys)); - for (i = 0; i < sig->numrevkeys; i++) - memcpy (&pk->revkey[pk->numrevkeys++], - &sig->revkey[i], - sizeof (struct revocation_key)); + for (i = 0; i < sig->numrevkeys; i++, pk->numrevkeys++) + { + pk->revkey[pk->numrevkeys].class + = sig->revkey[i].class; + pk->revkey[pk->numrevkeys].algid + = sig->revkey[i].algid; + pk->revkey[pk->numrevkeys].fprlen + = sig->revkey[i].fprlen; + memcpy (pk->revkey[pk->numrevkeys].fpr, + sig->revkey[i].fpr, sig->revkey[i].fprlen); + memset (pk->revkey[pk->numrevkeys].fpr + + sig->revkey[i].fprlen, + 0, + sizeof (sig->revkey[i].fpr) + - sig->revkey[i].fprlen); + } } if (sig->timestamp >= sigdate) @@ -3364,7 +3372,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) * * 1. No requested usage and no primary key requested * Examples for this case are that we have a keyID to be used - * for decrytion or verification. + * for decryption or verification. * 2. No usage but primary key requested * This is the case for all functions which work on an * entire keyblock, e.g. for editing or listing @@ -2009,6 +2009,8 @@ parse_list_options(char *str) N_("show expiration dates during signature listings")}, {"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL, NULL}, + {"show-only-fpr-mbox",LIST_SHOW_ONLY_FPR_MBOX, NULL, + NULL}, {NULL,0,NULL,NULL} }; @@ -2146,6 +2148,8 @@ static struct gnupg_compliance_option compliance_options[] = static void set_compliance_option (enum cmd_and_opt_values option) { + opt.flags.rfc4880bis = 0; /* Clear becuase it is initially set. */ + switch (option) { case oRFC4880bis: @@ -2192,7 +2196,10 @@ set_compliance_option (enum cmd_and_opt_values option) break; case oPGP7: opt.compliance = CO_PGP7; break; case oPGP8: opt.compliance = CO_PGP8; break; - case oGnuPG: opt.compliance = CO_GNUPG; break; + case oGnuPG: + opt.compliance = CO_GNUPG; + opt.flags.rfc4880bis = 1; + break; case oDE_VS: set_compliance_option (oOpenPGP); @@ -2439,6 +2446,8 @@ main (int argc, char **argv) opt.passphrase_repeat = 1; opt.emit_version = 0; opt.weak_digests = NULL; + opt.compliance = CO_GNUPG; + opt.flags.rfc4880bis = 1; /* Check whether we have a config file on the command line. */ orig_argc = argc; @@ -3130,7 +3139,7 @@ main (int argc, char **argv) break; case oSender: { - char *mbox = mailbox_from_userid (pargs.r.ret_str); + char *mbox = mailbox_from_userid (pargs.r.ret_str, 0); if (!mbox) log_error (_("\"%s\" is not a proper mail address\n"), pargs.r.ret_str); @@ -3554,7 +3563,7 @@ main (int argc, char **argv) case oAutoKeyLocate: if (default_akl) { - /* This is the first time --aito-key-locate is seen. + /* This is the first time --auto-key-locate is seen. * We need to reset the default akl. */ default_akl = 0; release_akl(); @@ -3728,7 +3737,7 @@ main (int argc, char **argv) log_info(_("WARNING: program may create a core file!\n")); if (opt.flags.rfc4880bis) - log_info ("WARNING: using experimental features from RFC4880bis!\n"); + log_info ("Note: RFC4880bis features are enabled.\n"); else { opt.mimemode = 0; /* This will use text mode instead. */ @@ -3891,7 +3900,7 @@ main (int argc, char **argv) keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP)) log_error(_("invalid personal compress preferences\n")); - /* Check chunk size. Please fix also the man page if you chnage + /* Check chunk size. Please fix also the man page if you change * the default. The limits are given by the specs. */ if (!opt.chunk_size) opt.chunk_size = 27; /* Default to the suggested max of 128 MiB. */ @@ -4875,9 +4884,9 @@ main (int argc, char **argv) while( endless || count ) { byte *p; - /* Wee need a multiple of 3, so that in case of + /* We need a multiple of 3, so that in case of armored output we get a correct string. No - linefolding is done, as it is best to levae this to + linefolding is done, as it is best to leave this to other tools */ size_t n = !endless && count < 99? count : 99; @@ -5073,8 +5082,6 @@ main (int argc, char **argv) if (! (desc.mode == KEYDB_SEARCH_MODE_SHORT_KID || desc.mode == KEYDB_SEARCH_MODE_LONG_KID - || desc.mode == KEYDB_SEARCH_MODE_FPR16 - || desc.mode == KEYDB_SEARCH_MODE_FPR20 || desc.mode == KEYDB_SEARCH_MODE_FPR || desc.mode == KEYDB_SEARCH_MODE_KEYGRIP)) { diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index b3f7ecdce..e882fa8e3 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -25,6 +25,7 @@ #include "keydb.h" #include "main.h" #include "options.h" +#include "call-agent.h" static int do_debug; #define debug(fmt, ...) \ @@ -2248,9 +2249,12 @@ sk_esk (const char *option, int argc, char *argv[], void *cookie) log_assert (sizeof (si.salt) == sizeof (ske->s2k.salt)); memcpy (ske->s2k.salt, si.salt, sizeof (ske->s2k.salt)); if (! si.s2k_is_session_key) - /* 0 means get the default. */ - ske->s2k.count = encode_s2k_iterations (si.iterations); - + { + if (!si.iterations) + ske->s2k.count = encode_s2k_iterations (agent_get_s2k_count ()); + else + ske->s2k.count = encode_s2k_iterations (si.iterations); + } /* Derive the symmetric key that is either the session key or the key used to encrypt the session key. */ @@ -2281,16 +2285,27 @@ sk_esk (const char *option, int argc, char *argv[], void *cookie) /* Encrypt the session key using the s2k specifier. */ { DEK *sesdekp = &sesdek; + void *enckey; + size_t enckeylen; /* Now encrypt the session key (or rather, the algorithm used to - encrypt the SKESK plus the session key) using ENCKEY. */ - err = encrypt_seskey (&s2kdek, 0, &sesdekp, - (void**)&ske->seskey, (size_t *)&ske->seskeylen); + encrypt the SKESK plus the session key) using S2KDEK. */ + err = encrypt_seskey (&s2kdek, 0, &sesdekp, &enckey, &enckeylen); + if (err) log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err)); + if (enckeylen - 1 > sesdek.keylen) + log_fatal ("key size is too big: %zu\n", enckeylen); + else + { + ske->seskeylen = (byte)enckeylen; + memcpy (ske->seskey, enckey, enckeylen); + } + /* Save the session key for later. */ session_key = sesdek; + xfree (enckey); } pkt.pkttype = PKT_SYMKEY_ENC; @@ -3060,10 +3075,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, } void -show_basic_key_info (ctrl_t ctrl, KBNODE keyblock) +show_basic_key_info (ctrl_t ctrl, KBNODE keyblock, int made_from_sec) { (void)ctrl; - (void) keyblock; + (void)keyblock; + (void)made_from_sec; } int diff --git a/g10/import.c b/g10/import.c index 73f795cd9..c2a1dd033 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1,6 +1,6 @@ /* import.c - import a key into our key storage. * Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc. - * Copyright (C) 2014, 2016, 2017 Werner Koch + * Copyright (C) 2014, 2016, 2017, 2019 Werner Koch * * This file is part of GnuPG. * @@ -75,6 +75,8 @@ struct import_stats_s #define NODE_DELETION_MARK 4 /* A node flag used to temporary mark a node. */ #define NODE_FLAG_A 8 +/* A flag used by transfer_secret_keys. */ +#define NODE_TRANSFER_SECKEY 16 /* An object and a global instance to store selectors created from @@ -109,11 +111,16 @@ static gpg_error_t import_one (ctrl_t ctrl, unsigned char **fpr, size_t *fpr_len, unsigned int options, int from_sk, int silent, import_screener_t screener, void *screener_arg, - int origin, const char *url); -static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock, + int origin, const char *url, int *r_valid); +static gpg_error_t import_matching_seckeys ( + ctrl_t ctrl, kbnode_t seckeys, + const byte *mainfpr, size_t mainfprlen, + struct import_stats_s *stats, int batch); +static gpg_error_t import_secret_one (ctrl_t ctrl, kbnode_t keyblock, struct import_stats_s *stats, int batch, unsigned int options, int for_migration, - import_screener_t screener, void *screener_arg); + import_screener_t screener, void *screener_arg, + kbnode_t *r_secattic); static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, struct import_stats_s *stats); static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, @@ -121,6 +128,7 @@ static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, unsigned int options); static int any_uid_left (kbnode_t keyblock); +static int remove_all_uids (kbnode_t *keyblock); static int merge_blocks (ctrl_t ctrl, unsigned int options, kbnode_t keyblock_orig, kbnode_t keyblock, u32 *keyid, @@ -181,6 +189,9 @@ parse_import_options(char *str,unsigned int *options,int noisy) {"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL, N_("remove as much as possible from key after import")}, + {"import-drop-uids", IMPORT_DROP_UIDS, NULL, + N_("Do not import user id or attribute packets")}, + {"import-export", IMPORT_EXPORT, NULL, N_("run import filters and export key immediately")}, @@ -562,6 +573,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats, kbnode_t keyblock = NULL; /* Need to initialize because gcc can't grasp the return semantics of read_block. */ + kbnode_t secattic = NULL; /* Kludge for PGP desktop percularity */ int rc = 0; int v3keys; @@ -582,18 +594,63 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats, { stats->v3keys += v3keys; if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY) - rc = import_one (ctrl, keyblock, - stats, fpr, fpr_len, options, 0, 0, - screener, screener_arg, origin, url); + { + rc = import_one (ctrl, keyblock, + stats, fpr, fpr_len, options, 0, 0, + screener, screener_arg, origin, url, NULL); + if (secattic) + { + byte tmpfpr[MAX_FINGERPRINT_LEN]; + size_t tmpfprlen; + + if (!rc && !(opt.dry_run || (options & IMPORT_DRY_RUN))) + { + /* Kudge for PGP desktop - see below. */ + fingerprint_from_pk (keyblock->pkt->pkt.public_key, + tmpfpr, &tmpfprlen); + rc = import_matching_seckeys (ctrl, secattic, + tmpfpr, tmpfprlen, + stats, opt.batch); + } + release_kbnode (secattic); + secattic = NULL; + } + } else if (keyblock->pkt->pkttype == PKT_SECRET_KEY) - rc = import_secret_one (ctrl, keyblock, stats, - opt.batch, options, 0, - screener, screener_arg); + { + release_kbnode (secattic); + secattic = NULL; + rc = import_secret_one (ctrl, keyblock, stats, + opt.batch, options, 0, + screener, screener_arg, &secattic); + keyblock = NULL; /* Ownership was transferred. */ + if (secattic) + { + if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY) + rc = 0; /* Try import after the next pubkey. */ + + /* The attic is a workaround for the peculiar PGP + * Desktop method of exporting a secret key: The + * exported file is the concatenation of two armored + * keyblocks; first the private one and then the public + * one. The strange thing is that the secret one has no + * binding signatures at all and thus we have not + * imported it. The attic stores that secret keys and + * we try to import it once after the very next public + * keyblock. */ + } + } else if (keyblock->pkt->pkttype == PKT_SIGNATURE && IS_KEY_REV (keyblock->pkt->pkt.signature) ) - rc = import_revoke_cert (ctrl, keyblock, options, stats); + { + release_kbnode (secattic); + secattic = NULL; + rc = import_revoke_cert (ctrl, keyblock, options, stats); + } else { + release_kbnode (secattic); + secattic = NULL; log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype); } release_kbnode (keyblock); @@ -619,6 +676,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats, else if (rc && gpg_err_code (rc) != GPG_ERR_INV_KEYRING) log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (rc)); + release_kbnode (secattic); return rc; } @@ -655,8 +713,11 @@ import_old_secring (ctrl_t ctrl, const char *fname) while (!(err = read_block (inp, 0, &pending_pkt, &keyblock, &v3keys))) { if (keyblock->pkt->pkttype == PKT_SECRET_KEY) - err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1, - NULL, NULL); + { + err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1, + NULL, NULL, NULL); + keyblock = NULL; /* Ownership was transferred. */ + } release_kbnode (keyblock); if (err) break; @@ -924,6 +985,8 @@ read_block( IOBUF a, int with_meta, add_kbnode (root, new_kbnode (pkt)); pkt = xmalloc (sizeof *pkt); } + else + free_packet (pkt, &parsectx); init_packet(pkt); break; } @@ -1078,23 +1141,14 @@ print_import_ok (PKT_public_key *pk, unsigned int reason) static void print_import_check (PKT_public_key * pk, PKT_user_id * id) { - char * buf; - byte fpr[24]; + byte hexfpr[2*MAX_FINGERPRINT_LEN+1]; u32 keyid[2]; - size_t i, n; - size_t pos = 0; - buf = xmalloc (17+41+id->len+32); keyid_from_pk (pk, keyid); - sprintf (buf, "%08X%08X ", keyid[0], keyid[1]); - pos = 17; - fingerprint_from_pk (pk, fpr, &n); - for (i = 0; i < n; i++, pos += 2) - sprintf (buf+pos, "%02X", fpr[i]); - strcat (buf, " "); - strcat (buf, id->name); - write_status_text (STATUS_IMPORT_CHECK, buf); - xfree (buf); + hexfingerprint (pk, hexfpr, sizeof hexfpr); + write_status_printf (STATUS_IMPORT_CHECK, "%08X%08X %s %s", + keyid[0], keyid[1], hexfpr, id->name); + } @@ -1258,7 +1312,7 @@ impex_filter_getval (void *cookie, const char *propname) { if (!uid->mbox) { - uid->mbox = mailbox_from_userid (uid->name); + uid->mbox = mailbox_from_userid (uid->name, 0); } result = uid->mbox; } @@ -1669,7 +1723,10 @@ update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url) * the internal errorcount, so that invalid input can be detected by * programs which called gpg. If SILENT is no messages are printed - * even most error messages are suppressed. ORIGIN is the origin of - * the key (0 for unknown) and URL the corresponding URL. + * the key (0 for unknown) and URL the corresponding URL. FROM_SK + * indicates that the key has been made from a secret key. If R_SAVED + * is not NULL a boolean will be stored indicating whether the keyblock + * has valid parts. */ static gpg_error_t import_one (ctrl_t ctrl, @@ -1677,7 +1734,7 @@ import_one (ctrl_t ctrl, unsigned char **fpr, size_t *fpr_len, unsigned int options, int from_sk, int silent, import_screener_t screener, void *screener_arg, - int origin, const char *url) + int origin, const char *url, int *r_valid) { gpg_error_t err = 0; PKT_public_key *pk; @@ -1696,6 +1753,9 @@ import_one (ctrl_t ctrl, int any_filter = 0; KEYDB_HANDLE hd = NULL; + if (r_valid) + *r_valid = 0; + /* If show-only is active we don't won't any extra output. */ if ((options & (IMPORT_SHOW | IMPORT_DRY_RUN))) silent = 1; @@ -1713,9 +1773,11 @@ import_one (ctrl_t ctrl, keyid_from_pk( pk, keyid ); uidnode = find_next_kbnode( keyblock, PKT_USER_ID ); - if (opt.verbose && !opt.interactive && !silent) + if (opt.verbose && !opt.interactive && !silent && !from_sk) { - log_info( "pub %s/%s %s ", + /* Note that we do not print this info in FROM_SK mode + * because import_secret_one already printed that. */ + log_info ("pub %s/%s %s ", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk(pk), datestr_from_pk(pk) ); if (uidnode) @@ -1726,7 +1788,9 @@ import_one (ctrl_t ctrl, } - if (!uidnode ) + /* Unless import-drop-uids has been requested we don't allow import + * of a key without UIDs. */ + if (!uidnode && !(options & IMPORT_DROP_UIDS)) { if (!silent) log_error( _("key %s: no user ID\n"), keystr_from_pk(pk)); @@ -1746,14 +1810,18 @@ import_one (ctrl_t ctrl, print_import_check (pk, uidnode->pkt->pkt.user_id); merge_keys_and_selfsig (ctrl, keyblock); tty_printf ("\n"); - show_basic_key_info (ctrl, keyblock); + show_basic_key_info (ctrl, keyblock, from_sk); tty_printf ("\n"); if (!cpr_get_answer_is_yes ("import.okay", "Do you want to import this key? (y/N) ")) return 0; } - collapse_uids(&keyblock); + /* Remove or collapse the user ids. */ + if ((options & IMPORT_DROP_UIDS)) + remove_all_uids (&keyblock); + else + collapse_uids (&keyblock); /* Clean the key that we're about to import, to cut down on things that we have to clean later. This has no practical impact on the @@ -1800,7 +1868,10 @@ import_one (ctrl_t ctrl, } } - if (!delete_inv_parts (ctrl, keyblock, keyid, options ) ) + /* Delete invalid parts and without the drop option bail out if + * there are no user ids. */ + if (!delete_inv_parts (ctrl, keyblock, keyid, options) + && !(options & IMPORT_DROP_UIDS) ) { if (!silent) { @@ -1840,6 +1911,10 @@ import_one (ctrl_t ctrl, return 0; } + /* The keyblock is valid and ready for real import. */ + if (r_valid) + *r_valid = 1; + /* Show the key in the form it is merged or inserted. We skip this * if "import-export" is also active without --armor or the output * file has explicily been given. */ @@ -2163,12 +2238,15 @@ import_one (ctrl_t ctrl, /* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The - function prints diagnostics and returns an error code. If BATCH is - true the secret keys are stored by gpg-agent in the transfer format - (i.e. no re-protection and aksing for passphrases). */ + * function prints diagnostics and returns an error code. If BATCH is + * true the secret keys are stored by gpg-agent in the transfer format + * (i.e. no re-protection and aksing for passphrases). If ONLY_MARKED + * is set, only those nodes with flag NODE_TRANSFER_SECKEY are + * processed. */ gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, - kbnode_t sec_keyblock, int batch, int force) + kbnode_t sec_keyblock, int batch, int force, + int only_marked) { gpg_error_t err = 0; void *kek = NULL; @@ -2209,12 +2287,16 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, xfree (kek); kek = NULL; + /* Note: We need to use walk_kbnode so that we skip nodes which are + * marked as deleted. */ main_pk = NULL; while ((node = walk_kbnode (sec_keyblock, &ctx, 0))) { if (node->pkt->pkttype != PKT_SECRET_KEY && node->pkt->pkttype != PKT_SECRET_SUBKEY) continue; + if (only_marked && !(node->flag & NODE_TRANSFER_SECKEY)) + continue; pk = node->pkt->pkt.public_key; if (!main_pk) main_pk = pk; @@ -2454,14 +2536,21 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, /* Walk a secret keyblock and produce a public keyblock out of it. - Returns a new node or NULL on error. */ + * Returns a new node or NULL on error. Modifies the tag field of the + * nodes. */ static kbnode_t sec_to_pub_keyblock (kbnode_t sec_keyblock) { kbnode_t pub_keyblock = NULL; kbnode_t ctx = NULL; kbnode_t secnode, pubnode; + unsigned int tag = 0; + + /* Set a tag to all nodes. */ + for (secnode = sec_keyblock; secnode; secnode = secnode->next) + secnode->tag = ++tag; + /* Copy. */ while ((secnode = walk_kbnode (sec_keyblock, &ctx, 0))) { if (secnode->pkt->pkttype == PKT_SECRET_KEY @@ -2491,6 +2580,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock) { pubnode = clone_kbnode (secnode); } + pubnode->tag = secnode->tag; if (!pub_keyblock) pub_keyblock = pubnode; @@ -2501,25 +2591,223 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock) return pub_keyblock; } -/**************** - * Ditto for secret keys. Handling is simpler than for public keys. - * We allow secret key importing only when allow is true, this is so - * that a secret key can not be imported accidentally and thereby tampering - * with the trust calculation. + +/* Delete all notes in the keyblock at R_KEYBLOCK which are not in + * PUB_KEYBLOCK. Modifies the tags of both keyblock's nodes. */ +static gpg_error_t +resync_sec_with_pub_keyblock (kbnode_t *r_keyblock, kbnode_t pub_keyblock, + kbnode_t *r_removedsecs) +{ + kbnode_t sec_keyblock = *r_keyblock; + kbnode_t node, prevnode; + unsigned int *taglist; + unsigned int ntaglist, n; + kbnode_t attic = NULL; + kbnode_t *attic_head = &attic; + + /* Collect all tags in an array for faster searching. */ + for (ntaglist = 0, node = pub_keyblock; node; node = node->next) + ntaglist++; + taglist = xtrycalloc (ntaglist, sizeof *taglist); + if (!taglist) + return gpg_error_from_syserror (); + for (ntaglist = 0, node = pub_keyblock; node; node = node->next) + taglist[ntaglist++] = node->tag; + + /* Walks over the secret keyblock and delete all nodes which are not + * in the tag list. Those nodes have been deleted in the + * pub_keyblock. Sequential search is a bit lazy and could be + * optimized by sorting and bsearch; however secret keyrings are + * short and there are easier ways to DoS the import. */ + again: + for (prevnode=NULL, node=sec_keyblock; node; prevnode=node, node=node->next) + { + for (n=0; n < ntaglist; n++) + if (taglist[n] == node->tag) + break; + if (n == ntaglist) /* Not in public keyblock. */ + { + if (node->pkt->pkttype == PKT_SECRET_KEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + { + if (!prevnode) + sec_keyblock = node->next; + else + prevnode->next = node->next; + node->next = NULL; + *attic_head = node; + attic_head = &node->next; + goto again; /* That's lame; I know. */ + } + else + delete_kbnode (node); + } + } + + xfree (taglist); + + /* Commit the as deleted marked nodes and return the possibly + * modified keyblock and a list of removed secret key nodes. */ + commit_kbnode (&sec_keyblock); + *r_keyblock = sec_keyblock; + *r_removedsecs = attic; + return 0; +} + + +/* Helper for import_secret_one. */ +static gpg_error_t +do_transfer (ctrl_t ctrl, kbnode_t keyblock, PKT_public_key *pk, + struct import_stats_s *stats, int batch, int only_marked) + +{ + gpg_error_t err; + struct import_stats_s subkey_stats = {0}; + + err = transfer_secret_keys (ctrl, &subkey_stats, keyblock, + batch, 0, only_marked); + if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED) + { + /* TRANSLATORS: For a smartcard, each private key on host has a + * reference (stub) to a smartcard and actual private key data + * is stored on the card. A single smartcard can have up to + * three private key data. Importing private key stub is always + * skipped in 2.1, and it returns GPG_ERR_NOT_PROCESSED. + * Instead, user should be suggested to run 'gpg --card-status', + * then, references to a card will be automatically created + * again. */ + log_info (_("To migrate '%s', with each smartcard, " + "run: %s\n"), "secring.gpg", "gpg --card-status"); + err = 0; + } + + if (!err) + { + int status = 16; + + if (!opt.quiet) + log_info (_("key %s: secret key imported\n"), keystr_from_pk (pk)); + if (subkey_stats.secret_imported) + { + status |= 1; + stats->secret_imported += 1; + } + if (subkey_stats.secret_dups) + stats->secret_dups += 1; + + if (is_status_enabled ()) + print_import_ok (pk, status); + } + + return err; +} + + +/* If the secret keys (main or subkey) in SECKEYS have a corresponding + * public key in the public key described by (FPR,FPRLEN) import these + * parts. */ -static int +static gpg_error_t +import_matching_seckeys (ctrl_t ctrl, kbnode_t seckeys, + const byte *mainfpr, size_t mainfprlen, + struct import_stats_s *stats, int batch) +{ + gpg_error_t err; + kbnode_t pub_keyblock = NULL; + kbnode_t node; + struct { byte fpr[MAX_FINGERPRINT_LEN]; size_t fprlen; } *fprlist = NULL; + size_t n, nfprlist; + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fprlen; + PKT_public_key *pk; + + /* Get the entire public key block from our keystore and put all its + * fingerprints into an array. */ + err = get_pubkey_byfprint (ctrl, NULL, &pub_keyblock, mainfpr, mainfprlen); + if (err) + goto leave; + log_assert (pub_keyblock && pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY); + pk = pub_keyblock->pkt->pkt.public_key; + + for (nfprlist = 0, node = pub_keyblock; node; node = node->next) + if (node->pkt->pkttype == PKT_PUBLIC_KEY + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) + nfprlist++; + log_assert (nfprlist); + fprlist = xtrycalloc (nfprlist, sizeof *fprlist); + if (!fprlist) + { + err = gpg_error_from_syserror (); + goto leave; + } + for (n = 0, node = pub_keyblock; node; node = node->next) + if (node->pkt->pkttype == PKT_PUBLIC_KEY + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) + { + fingerprint_from_pk (node->pkt->pkt.public_key, + fprlist[n].fpr, &fprlist[n].fprlen); + n++; + } + log_assert (n == nfprlist); + + /* for (n=0; n < nfprlist; n++) */ + /* log_printhex (fprlist[n].fpr, fprlist[n].fprlen, "pubkey %zu:", n); */ + + /* Mark all secret keys which have a matching public key part in + * PUB_KEYBLOCK. */ + for (node = seckeys; node; node = node->next) + { + if (node->pkt->pkttype != PKT_SECRET_KEY + && node->pkt->pkttype != PKT_SECRET_SUBKEY) + continue; /* Should not happen. */ + fingerprint_from_pk (node->pkt->pkt.public_key, fpr, &fprlen); + node->flag &= ~NODE_TRANSFER_SECKEY; + for (n=0; n < nfprlist; n++) + if (fprlist[n].fprlen == fprlen && !memcmp (fprlist[n].fpr,fpr,fprlen)) + { + node->flag |= NODE_TRANSFER_SECKEY; + /* log_debug ("found matching seckey\n"); */ + break; + } + } + + /* Transfer all marked keys. */ + err = do_transfer (ctrl, seckeys, pk, stats, batch, 1); + + leave: + xfree (fprlist); + release_kbnode (pub_keyblock); + return err; +} + + +/* Import function for a single secret keyblock. Handling is simpler + * than for public keys. We allow secret key importing only when + * allow is true, this is so that a secret key can not be imported + * accidentally and thereby tampering with the trust calculation. + * + * Ownership of KEYBLOCK is transferred to this function! + * + * If R_SECATTIC is not null the last special sec_keyblock is stored + * there. + */ +static gpg_error_t import_secret_one (ctrl_t ctrl, kbnode_t keyblock, - struct import_stats_s *stats, int batch, unsigned int options, - int for_migration, - import_screener_t screener, void *screener_arg) + struct import_stats_s *stats, int batch, + unsigned int options, int for_migration, + import_screener_t screener, void *screener_arg, + kbnode_t *r_secattic) { PKT_public_key *pk; struct seckey_info *ski; kbnode_t node, uidnode; u32 keyid[2]; - int rc = 0; + gpg_error_t err = 0; int nr_prev; kbnode_t pub_keyblock; + kbnode_t attic = NULL; + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fprlen; char pkstrbuf[PUBKEY_STRING_SIZE]; /* Get the key and print some info about it */ @@ -2529,6 +2817,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, pk = node->pkt->pkt.public_key; + fingerprint_from_pk (pk, fpr, &fprlen); keyid_from_pk (pk, keyid); uidnode = find_next_kbnode (keyblock, PKT_USER_ID); @@ -2536,12 +2825,13 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, { log_error (_("secret key %s: %s\n"), keystr_from_pk (pk), _("rejected by import screener")); + release_kbnode (keyblock); return 0; } if (opt.verbose && !for_migration) { - log_info ("sec %s/%s %s ", + log_info ("sec %s/%s %s ", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk (pk), datestr_from_pk (pk)); if (uidnode) @@ -2555,6 +2845,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, { if (!for_migration) log_error (_("importing secret keys not allowed\n")); + release_kbnode (keyblock); return 0; } @@ -2562,6 +2853,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, { if (!for_migration) log_error( _("key %s: no user ID\n"), keystr_from_pk (pk)); + release_kbnode (keyblock); return 0; } @@ -2570,6 +2862,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, { /* Actually an internal error. */ log_error ("key %s: secret key info missing\n", keystr_from_pk (pk)); + release_kbnode (keyblock); return 0; } @@ -2580,6 +2873,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, if (!for_migration) log_error (_("key %s: secret key with invalid cipher %d" " - skipped\n"), keystr_from_pk (pk), ski->algo); + release_kbnode (keyblock); return 0; } @@ -2590,6 +2884,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, to put a secret key into the keyring and the user might later be tricked into signing stuff with that key. */ log_error (_("importing secret keys not allowed\n")); + release_kbnode (keyblock); return 0; } #endif @@ -2601,20 +2896,62 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, /* Make a public key out of the key. */ pub_keyblock = sec_to_pub_keyblock (keyblock); if (!pub_keyblock) - log_error ("key %s: failed to create public key from secret key\n", - keystr_from_pk (pk)); + { + err = gpg_error_from_syserror (); + log_error ("key %s: failed to create public key from secret key\n", + keystr_from_pk (pk)); + } else { + int valid; + /* Note that this outputs an IMPORT_OK status message for the public key block, and below we will output another one for the secret keys. FIXME? */ import_one (ctrl, pub_keyblock, stats, NULL, NULL, options, 1, for_migration, - screener, screener_arg, 0, NULL); + screener, screener_arg, 0, NULL, &valid); + + /* The secret keyblock may not have nodes which are deleted in + * the public keyblock. Otherwise we would import just the + * secret key without having the public key. That would be + * surprising and clutters out private-keys-v1.d. */ + err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock, &attic); + if (err) + goto leave; + + if (!valid) + { + /* If the block was not valid the primary key is left in the + * original keyblock because we require that for the first + * node. Move it to ATTIC. */ + if (keyblock && keyblock->pkt->pkttype == PKT_SECRET_KEY) + { + node = keyblock; + keyblock = node->next; + node->next = NULL; + if (attic) + { + node->next = attic; + attic = node; + } + else + attic = node; + } + + /* Try to import the secret key iff we have a public key. */ + if (attic && !(opt.dry_run || (options & IMPORT_DRY_RUN))) + err = import_matching_seckeys (ctrl, attic, fpr, fprlen, + stats, batch); + else + err = gpg_error (GPG_ERR_NO_SECKEY); + goto leave; + } - /* Fixme: We should check for an invalid keyblock and - cancel the secret key import in this case. */ - release_kbnode (pub_keyblock); + /* log_debug ("attic is:\n"); */ + /* dump_kbnode (attic); */ + + /* Proceed with the valid parts of PUBKEYBLOCK. */ /* At least we cancel the secret key import when the public key import was skipped due to MERGE_ONLY option and a new @@ -2622,63 +2959,40 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, if (!(opt.dry_run || (options & IMPORT_DRY_RUN)) && stats->skipped_new_keys <= nr_prev) { - /* Read the keyblock again to get the effects of a merge. */ - /* Fixme: we should do this based on the fingerprint or - even better let import_one return the merged - keyblock. */ - node = get_pubkeyblock (ctrl, keyid); - if (!node) - log_error ("key %s: failed to re-lookup public key\n", - keystr_from_pk (pk)); + /* Read the keyblock again to get the effects of a merge for + * the public key. */ + err = get_pubkey_byfprint (ctrl, NULL, &node, fpr, fprlen); + if (err || !node) + log_error ("key %s: failed to re-lookup public key: %s\n", + keystr_from_pk (pk), gpg_strerror (err)); else { - gpg_error_t err; - - /* transfer_secret_keys collects subkey stats. */ - struct import_stats_s subkey_stats = {0}; + err = do_transfer (ctrl, keyblock, pk, stats, batch, 0); + if (!err) + check_prefs (ctrl, node); + release_kbnode (node); - err = transfer_secret_keys (ctrl, &subkey_stats, keyblock, - batch, 0); - if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED) + if (!err && attic) { - /* TRANSLATORS: For smartcard, each private key on - host has a reference (stub) to a smartcard and - actual private key data is stored on the card. A - single smartcard can have up to three private key - data. Importing private key stub is always - skipped in 2.1, and it returns - GPG_ERR_NOT_PROCESSED. Instead, user should be - suggested to run 'gpg --card-status', then, - references to a card will be automatically - created again. */ - log_info (_("To migrate '%s', with each smartcard, " - "run: %s\n"), "secring.gpg", "gpg --card-status"); - err = 0; + /* Try to import invalid subkeys. This can be the + * case if the primary secret key was imported due + * to --allow-non-selfsigned-uid. */ + err = import_matching_seckeys (ctrl, attic, fpr, fprlen, + stats, batch); } - if (!err) - { - int status = 16; - if (!opt.quiet) - log_info (_("key %s: secret key imported\n"), - keystr_from_pk (pk)); - if (subkey_stats.secret_imported) - { - status |= 1; - stats->secret_imported += 1; - } - if (subkey_stats.secret_dups) - stats->secret_dups += 1; - if (is_status_enabled ()) - print_import_ok (pk, status); - check_prefs (ctrl, node); - } - release_kbnode (node); } } } - return rc; + leave: + release_kbnode (keyblock); + release_kbnode (pub_keyblock); + if (r_secattic) + *r_secattic = attic; + else + release_kbnode (attic); + return err; } @@ -2942,9 +3256,7 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, size_t an; fingerprint_from_pk (pk, afp, &an); - while (an < MAX_FINGERPRINT_LEN) - afp[an++] = 0; - rc = keydb_search_fpr (hd, afp); + rc = keydb_search_fpr (hd, afp, an); } if (rc) { @@ -3058,7 +3370,7 @@ chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self) kbnode_t bsnode = NULL; /* Subkey binding signature node. */ u32 bsdate = 0; /* Timestamp of that node. */ kbnode_t rsnode = NULL; /* Subkey recocation signature node. */ - u32 rsdate = 0; /* Timestamp of tha node. */ + u32 rsdate = 0; /* Timestamp of that node. */ PKT_signature *sig; int rc; kbnode_t n; @@ -3415,14 +3727,51 @@ any_uid_left (kbnode_t keyblock) -/**************** +/* Delete all user ids from KEYBLOCK. + * Returns: True if the keyblock has changed. */ +static int +remove_all_uids (kbnode_t *keyblock) +{ + kbnode_t node; + int any = 0; + + for (node = *keyblock; node; node = node->next) + { + if (is_deleted_kbnode (node)) + continue; + + if (node->pkt->pkttype != PKT_USER_ID) + continue; + + /* We are at the first user id. Delete everything up to the + * first subkey. */ + for (; node; node = node->next) + { + if (is_deleted_kbnode (node)) + continue; + + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + break; + delete_kbnode (node); + any = 1; + } + break; /* All done. */ + } + + commit_kbnode (keyblock); + return any; +} + + +/* * It may happen that the imported keyblock has duplicated user IDs. * We check this here and collapse those user IDs together with their * sigs into one. * Returns: True if the keyblock has changed. */ int -collapse_uids( kbnode_t *keyblock ) +collapse_uids (kbnode_t *keyblock) { kbnode_t uid1; int any=0; @@ -3562,7 +3911,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock) u32 keyid[2]; keyid_from_fingerprint (ctrl, sig->revkey[idx].fpr, - MAX_FINGERPRINT_LEN, keyid); + sig->revkey[idx].fprlen, keyid); for(inode=keyblock->next;inode;inode=inode->next) { @@ -3582,7 +3931,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock) err = get_pubkey_byfprint_fast (NULL, sig->revkey[idx].fpr, - MAX_FINGERPRINT_LEN); + sig->revkey[idx].fprlen); if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY || gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY) { @@ -3598,13 +3947,13 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock) tempkeystr,keystr(keyid)); keyserver_import_fprint (ctrl, sig->revkey[idx].fpr, - MAX_FINGERPRINT_LEN, + sig->revkey[idx].fprlen, opt.keyserver, 0); /* Do we have it now? */ err = get_pubkey_byfprint_fast (NULL, sig->revkey[idx].fpr, - MAX_FINGERPRINT_LEN); + sig->revkey[idx].fprlen); } if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY diff --git a/g10/kbnode.c b/g10/kbnode.c index 64def0509..93035e8f6 100644 --- a/g10/kbnode.c +++ b/g10/kbnode.c @@ -68,8 +68,8 @@ alloc_node (void) n->next = NULL; n->pkt = NULL; n->flag = 0; + n->tag = 0; n->private_flag=0; - n->recno = 0; return n; } diff --git a/g10/key-clean.c b/g10/key-clean.c index f66a0dbb4..d701a6665 100644 --- a/g10/key-clean.c +++ b/g10/key-clean.c @@ -500,7 +500,7 @@ clean_one_subkey_dupsigs (ctrl_t ctrl, kbnode_t subkeynode) log_debug ("\tchecking subkey %08lX for dupsigs\n", (ulong) keyid_from_pk (pk, NULL)); - /* First check that the choosen flag has been set. Note that we + /* First check that the chosen flag has been set. Note that we * only look at plain signatures so to keep all revocation * signatures which may carry important information. */ for (node = subkeynode->next; @@ -519,7 +519,7 @@ clean_one_subkey_dupsigs (ctrl_t ctrl, kbnode_t subkeynode) } if (!any_choosen) - return 0; /* Ooops no choosen flag set - we can't decide. */ + return 0; /* Ooops no chosen flag set - we can't decide. */ for (node = subkeynode->next; node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY diff --git a/g10/key-clean.h b/g10/key-clean.h index a0fb76950..c4f164928 100644 --- a/g10/key-clean.h +++ b/g10/key-clean.h @@ -23,7 +23,7 @@ #include "gpg.h" -/* No explict cleaning. */ +/* No explicit cleaning. */ #define KEY_CLEAN_NONE 0 /* Remove only invalid subkeys (ie. missing key-bindings) */ #define KEY_CLEAN_INVALID 1 diff --git a/g10/keydb.c b/g10/keydb.c index 03fadfd54..8c067e1df 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -81,6 +81,7 @@ enum keyblock_cache_states { struct keyblock_cache { enum keyblock_cache_states state; byte fpr[MAX_FINGERPRINT_LEN]; + byte fprlen; iobuf_t iobuf; /* Image of the keyblock. */ int pk_no; int uid_no; @@ -558,17 +559,9 @@ keydb_search_desc_dump (struct keydb_search_desc *desc) case KEYDB_SEARCH_MODE_LONG_KID: return xasprintf ("LONG_KID: '%s'", format_keyid (desc->u.kid, KF_LONG, b, sizeof (b))); - case KEYDB_SEARCH_MODE_FPR16: - bin2hex (desc->u.fpr, 16, fpr); - return xasprintf ("FPR16: '%s'", - format_hexfingerprint (fpr, b, sizeof (b))); - case KEYDB_SEARCH_MODE_FPR20: - bin2hex (desc->u.fpr, 20, fpr); - return xasprintf ("FPR20: '%s'", - format_hexfingerprint (fpr, b, sizeof (b))); case KEYDB_SEARCH_MODE_FPR: - bin2hex (desc->u.fpr, 20, fpr); - return xasprintf ("FPR: '%s'", + bin2hex (desc->u.fpr, desc->fprlen, fpr); + return xasprintf ("FPR%02d: '%s'", desc->fprlen, format_hexfingerprint (fpr, b, sizeof (b))); case KEYDB_SEARCH_MODE_ISSUER: return xasprintf ("ISSUER: '%s'", desc->u.name); @@ -1529,8 +1522,11 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb) memset (&desc, 0, sizeof (desc)); fingerprint_from_pk (pk, desc.u.fpr, &len); - if (len == 20) - desc.mode = KEYDB_SEARCH_MODE_FPR20; + if (len == 20 || len == 32) + { + desc.mode = KEYDB_SEARCH_MODE_FPR; + desc.fprlen = len; + } else log_bug ("%s: Unsupported key length: %zu\n", __func__, len); @@ -1862,6 +1858,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, int was_reset = hd->is_reset; /* If an entry is already in the cache, then don't add it again. */ int already_in_cache = 0; + int fprlen; if (descindex) *descindex = 0; /* Make sure it is always set on return. */ @@ -1902,12 +1899,17 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, /* NB: If one of the exact search modes below is used in a loop to walk over all keys (with the same fingerprint) the caching must have been disabled for the handle. */ + if (desc[0].mode == KEYDB_SEARCH_MODE_FPR) + fprlen = desc[0].fprlen; + else + fprlen = 0; + if (!hd->no_caching && ndesc == 1 - && (desc[0].mode == KEYDB_SEARCH_MODE_FPR20 - || desc[0].mode == KEYDB_SEARCH_MODE_FPR) - && hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED - && !memcmp (hd->keyblock_cache.fpr, desc[0].u.fpr, 20) + && fprlen + && hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED + && hd->keyblock_cache.fprlen == fprlen + && !memcmp (hd->keyblock_cache.fpr, desc[0].u.fpr, fprlen) /* Make sure the current file position occurs before the cached result to avoid an infinite loop. */ && (hd->current < hd->keyblock_cache.resource @@ -1922,8 +1924,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, hd->current = hd->keyblock_cache.resource; /* HD->KEYBLOCK_CACHE.OFFSET is the last byte in the record. Seek just beyond that. */ - keybox_seek (hd->active[hd->current].u.kb, - hd->keyblock_cache.offset + 1); + keybox_seek (hd->active[hd->current].u.kb, hd->keyblock_cache.offset + 1); keydb_stats.found_cached++; return 0; } @@ -1986,8 +1987,8 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, keyblock_cache_clear (hd); if (!hd->no_caching && !rc - && ndesc == 1 && (desc[0].mode == KEYDB_SEARCH_MODE_FPR20 - || desc[0].mode == KEYDB_SEARCH_MODE_FPR) + && ndesc == 1 + && fprlen && hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYBOX) { hd->keyblock_cache.state = KEYBLOCK_CACHE_PREPARED; @@ -1997,11 +1998,14 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, within the record. */ hd->keyblock_cache.offset = keybox_offset (hd->active[hd->current].u.kb) - 1; - memcpy (hd->keyblock_cache.fpr, desc[0].u.fpr, 20); + memcpy (hd->keyblock_cache.fpr, desc[0].u.fpr, fprlen); + hd->keyblock_cache.fprlen = fprlen; } if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND - && ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID && was_reset + && ndesc == 1 + && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID + && was_reset && !already_in_cache) kid_not_found_insert (desc[0].u.kid); @@ -2078,12 +2082,13 @@ keydb_search_kid (KEYDB_HANDLE hd, u32 *kid) * off. If you want to search the whole database, then you need to * first call keydb_search_reset(). */ gpg_error_t -keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr) +keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr, size_t fprlen) { KEYDB_SEARCH_DESC desc; memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_FPR; - memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN); + memcpy (desc.u.fpr, fpr, fprlen); + desc.fprlen = fprlen; return keydb_search (hd, &desc, 1, NULL); } diff --git a/g10/keydb.h b/g10/keydb.h index 1def2bb81..7cdfe9bbf 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -52,12 +52,13 @@ typedef struct getkey_ctx_s *getkey_ctx_t; * This structure is also used to bind arbitrary packets together. */ -struct kbnode_struct { - KBNODE next; - PACKET *pkt; - int flag; - int private_flag; - ulong recno; /* used while updating the trustdb */ +struct kbnode_struct +{ + kbnode_t next; + PACKET *pkt; + int flag; /* Local use during keyblock processing (not cloned).*/ + unsigned int tag; /* Ditto. */ + int private_flag; }; #define is_deleted_kbnode(a) ((a)->private_flag & 1) @@ -244,9 +245,9 @@ gpg_error_t keydb_search_next (KEYDB_HANDLE hd); key id. */ gpg_error_t keydb_search_kid (KEYDB_HANDLE hd, u32 *kid); -/* This is a convenience function for searching for keys with a long - (20 byte) fingerprint. */ -gpg_error_t keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr); +/* This is a convenience function for searching for keys by + * fingerprint. */ +gpg_error_t keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr, size_t fprlen); /*-- pkclist.c --*/ @@ -276,7 +277,6 @@ gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr, SK_LIST *ret_sk_list, unsigned use); /*-- passphrase.h --*/ -unsigned char encode_s2k_iterations (int iterations); int have_static_passphrase(void); const char *get_static_passphrase (void); void set_passphrase_from_string(const char *pass); diff --git a/g10/keyedit.c b/g10/keyedit.c index 9716ed9d6..c28a565b1 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1894,7 +1894,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, node = new_kbnode (pkt); /* Transfer it to gpg-agent which handles secret keys. */ - err = transfer_secret_keys (ctrl, NULL, node, 1, 1); + err = transfer_secret_keys (ctrl, NULL, node, 1, 1, 0); /* Treat the pkt as a public key. */ pkt->pkttype = PKT_PUBLIC_KEY; @@ -2564,9 +2564,7 @@ find_by_primary_fpr (ctrl_t ctrl, const char *fpr, *r_kdbhd = NULL; if (classify_user_id (fpr, &desc, 1) - || !(desc.mode == KEYDB_SEARCH_MODE_FPR - || desc.mode == KEYDB_SEARCH_MODE_FPR16 - || desc.mode == KEYDB_SEARCH_MODE_FPR20)) + || desc.mode != KEYDB_SEARCH_MODE_FPR) { log_error (_("\"%s\" is not a fingerprint\n"), fpr); err = gpg_error (GPG_ERR_INV_NAME); @@ -2581,19 +2579,9 @@ find_by_primary_fpr (ctrl_t ctrl, const char *fpr, /* Check that the primary fingerprint has been given. */ fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen); - if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16 - && !memcmp (fprbin, desc.u.fpr, 16)) - ; - else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR - && !memcmp (fprbin, desc.u.fpr, 16) - && !desc.u.fpr[16] - && !desc.u.fpr[17] - && !desc.u.fpr[18] - && !desc.u.fpr[19]) - ; - else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20 - || desc.mode == KEYDB_SEARCH_MODE_FPR) - && !memcmp (fprbin, desc.u.fpr, 20)) + if (desc.mode == KEYDB_SEARCH_MODE_FPR + && fprlen == desc.fprlen + && !memcmp (fprbin, desc.u.fpr, fprlen)) ; else { @@ -2917,8 +2905,7 @@ keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr, /* Parse the fingerprint. */ if (classify_user_id (subkeyfprs[idx], &desc, 1) - || !(desc.mode == KEYDB_SEARCH_MODE_FPR - || desc.mode == KEYDB_SEARCH_MODE_FPR20)) + || desc.mode != KEYDB_SEARCH_MODE_FPR) { log_error (_("\"%s\" is not a proper fingerprint\n"), subkeyfprs[idx] ); @@ -3524,7 +3511,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp, algo = gcry_pk_algo_name (pk->revkey[i].algid); keyid_from_fingerprint (ctrl, pk->revkey[i].fpr, - MAX_FINGERPRINT_LEN, r_keyid); + pk->revkey[i].fprlen, r_keyid); user = get_user_id_string_native (ctrl, r_keyid); tty_fprintf (fp, @@ -3690,13 +3677,14 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp, /* Display basic key information. This function is suitable to show - information on the key without any dependencies on the trustdb or - any other internal GnuPG stuff. KEYBLOCK may either be a public or - a secret key. This function may be called with KEYBLOCK containing - secret keys and thus the printing of "pub" vs. "sec" does only - depend on the packet type and not by checking with gpg-agent. */ + * information on the key without any dependencies on the trustdb or + * any other internal GnuPG stuff. KEYBLOCK may either be a public or + * a secret key. This function may be called with KEYBLOCK containing + * secret keys and thus the printing of "pub" vs. "sec" does only + * depend on the packet type and not by checking with gpg-agent. If + * PRINT_SEC ist set "sec" is printed instead of "pub". */ void -show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock) +show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock, int print_sec) { KBNODE node; int i; @@ -3709,13 +3697,17 @@ show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock) || node->pkt->pkttype == PKT_SECRET_KEY) { PKT_public_key *pk = node->pkt->pkt.public_key; + const char *tag; + + if (node->pkt->pkttype == PKT_SECRET_KEY || print_sec) + tag = "sec"; + else + tag = "pub"; /* Note, we use the same format string as in other show functions to make the translation job easier. */ tty_printf ("%s %s/%s ", - node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" : - node->pkt->pkttype == PKT_PUBLIC_SUBKEY ? "sub" : - node->pkt->pkttype == PKT_SECRET_KEY ? "sec" :"ssb", + tag, pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk (pk)); tty_printf (_("created: %s"), datestr_from_pk (pk)); @@ -4309,13 +4301,14 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive) xfree (answer); fingerprint_from_pk (revoker_pk, revkey.fpr, &fprlen); - if (fprlen != 20) + if (fprlen != 20 && fprlen != 32) { log_error (_("cannot appoint a PGP 2.x style key as a " "designated revoker\n")); continue; } + revkey.fprlen = fprlen; revkey.class = 0x80; if (sensitive) revkey.class |= 0x40; diff --git a/g10/keyedit.h b/g10/keyedit.h index d1f453a6f..af5e99664 100644 --- a/g10/keyedit.h +++ b/g10/keyedit.h @@ -50,7 +50,7 @@ void keyedit_quick_set_expire (ctrl_t ctrl, char **subkeyfprs); void keyedit_quick_set_primary (ctrl_t ctrl, const char *username, const char *primaryuid); -void show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock); +void show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock, int print_sec); int keyedit_print_one_sig (ctrl_t ctrl, estream_t fp, int rc, kbnode_t keyblock, kbnode_t node, int *inv_sigs, int *no_key, diff --git a/g10/keygen.c b/g10/keygen.c index 817704040..64fefd231 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1,6 +1,6 @@ /* keygen.c - Generate a key pair * Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc. - * Copyright (C) 2014, 2015, 2016 Werner Koch + * Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch * * This file is part of GnuPG. * @@ -59,6 +59,7 @@ const char *default_expiration_interval = "2y"; /* Flag bits used during key generation. */ #define KEYGEN_FLAG_NO_PROTECTION 1 #define KEYGEN_FLAG_TRANSIENT_KEY 2 +#define KEYGEN_FLAG_CREATE_V5_KEY 4 /* Maximum number of supported algorithm preferences. */ #define MAX_PREFS 30 @@ -90,7 +91,9 @@ enum para_name { pHANDLE, pKEYSERVER, pKEYGRIP, - pSUBKEYGRIP + pSUBKEYGRIP, + pVERSION, /* Desired version of the key packet. */ + pSUBVERSION, /* Ditto for the subpacket. */ }; struct para_data_s { @@ -148,13 +151,13 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, - const char **r_curve); + const char **r_curve, int *r_version); static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, struct output_control_s *outctrl, int card ); static int write_keyblock (iobuf_t out, kbnode_t node); static gpg_error_t gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root, u32 *timestamp, - u32 expireval); + u32 expireval, int keygen_flags); static unsigned int get_keysize_range (int algo, unsigned int *min, unsigned int *max); @@ -450,7 +453,7 @@ keygen_set_std_prefs (const char *string,int personal) } /* In case we have no compress algo at all, declare that - we prefer no compresssion. */ + we prefer no compression. */ if (!any_compress) strcat(dummy_string,"Z0 "); @@ -761,6 +764,48 @@ add_feature_aead (PKT_signature *sig, int enabled) static void +add_feature_v5 (PKT_signature *sig, int enabled) +{ + const byte *s; + size_t n; + int i; + char *buf; + + s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n ); + if (s && n && ((enabled && (s[0] & 0x04)) || (!enabled && !(s[0] & 0x04)))) + return; /* Already set or cleared */ + + if (!s || !n) + { /* Create a new one */ + n = 1; + buf = xmalloc_clear (n); + } + else + { + buf = xmalloc (n); + memcpy (buf, s, n); + } + + if (enabled) + buf[0] |= 0x04; /* v5 key supported */ + else + buf[0] &= ~0x04; + + /* Are there any bits set? */ + for (i=0; i < n; i++) + if (buf[i]) + break; + + if (i == n) + delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES); + else + build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); + + xfree (buf); +} + + +static void add_keyserver_modify (PKT_signature *sig,int enabled) { const byte *s; @@ -848,6 +893,7 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque) /* Make sure that the MDC feature flag is set if needed. */ add_feature_mdc (sig,mdc_available); add_feature_aead (sig, aead_available); + add_feature_v5 (sig, opt.flags.rfc4880bis); add_keyserver_modify (sig,ks_modify); keygen_add_keyserver_url(sig,NULL); @@ -943,11 +989,13 @@ keygen_add_revkey (PKT_signature *sig, void *opaque) struct revocation_key *revkey = opaque; byte buf[2+MAX_FINGERPRINT_LEN]; + log_assert (revkey->fprlen <= MAX_FINGERPRINT_LEN); buf[0] = revkey->class; buf[1] = revkey->algid; - memcpy (&buf[2], revkey->fpr, MAX_FINGERPRINT_LEN); + memcpy (buf + 2, revkey->fpr, revkey->fprlen); + memset (buf + 2 + revkey->fprlen, 0, sizeof (revkey->fpr) - revkey->fprlen); - build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+MAX_FINGERPRINT_LEN); + build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+revkey->fprlen); /* All sigs with revocation keys set are nonrevocable. */ sig->flags.revocable = 0; @@ -1368,7 +1416,7 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, static int do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip, kbnode_t pub_root, u32 timestamp, u32 expireval, - int is_subkey) + int is_subkey, int keygen_flags) { int err; PACKET *pkt; @@ -1415,7 +1463,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip, } pk->timestamp = timestamp; - pk->version = 4; + pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; @@ -1482,7 +1530,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem, } pk->timestamp = timestamp; - pk->version = 4; + pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; @@ -2926,7 +2974,7 @@ ask_user_id (int mode, int full, KBNODE keyblock) /* Basic key generation. Here we divert to the actual generation routines based on the requested algorithm. */ static int -do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root, +do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root, u32 timestamp, u32 expiredate, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) @@ -3005,12 +3053,14 @@ generate_user_id (KBNODE keyblock, const char *uidstr) * for any parameter. FOR_SUBKEY shall be true if this is used as a * subkey. If CLEAR_CERT is set a default CERT usage will be cleared; * this is useful if for example the default algorithm is used for a - * subkey. */ + * subkey. If R_KEYVERSION is not NULL it will receive the version of + * the key; this is currently 4 but can be changed with the flag "v5" + * to create a v5 key. */ static gpg_error_t parse_key_parameter_part (char *string, int for_subkey, int clear_cert, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, - char const **r_curve) + char const **r_curve, int *r_keyversion) { char *flags; int algo; @@ -3019,6 +3069,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, int ecdh_or_ecdsa = 0; unsigned int size; int keyuse; + int keyversion = 4; int i; const char *s; @@ -3117,6 +3168,13 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, return gpg_error (GPG_ERR_INV_FLAG); } } + else if (!ascii_strcasecmp (s, "v5")) + { + if (opt.flags.rfc4880bis) + keyversion = 5; + } + else if (!ascii_strcasecmp (s, "v4")) + keyversion = 4; else { xfree (tokens); @@ -3192,10 +3250,13 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, *r_keyuse = keyuse; if (r_curve) *r_curve = curve; + if (r_keyversion) + *r_keyversion = keyversion; return 0; } + /* Parse and return the standard key generation parameter. * The string is expected to be in this format: * @@ -3226,6 +3287,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert, * ecdsa := Use algorithm ECDSA. * eddsa := Use algorithm EdDSA. * ecdh := Use algorithm ECDH. + * v5 := Create version 5 key (requires option --rfc4880bis) * * There are several defaults and fallbacks depending on the * algorithm. PART can be used to select which part of STRING is @@ -3244,9 +3306,11 @@ parse_key_parameter_string (const char *string, int part, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, char const **r_curve, + int *r_version, int *r_subalgo, unsigned int *r_subsize, - unsigned *r_subkeyuse, - char const **r_subcurve) + unsigned int *r_subkeyuse, + char const **r_subcurve, + int *r_subversion) { gpg_error_t err = 0; char *primary, *secondary; @@ -3259,6 +3323,8 @@ parse_key_parameter_string (const char *string, int part, *r_keyuse = 0; if (r_curve) *r_curve = NULL; + if (r_version) + *r_version = 4; if (r_subalgo) *r_subalgo = 0; if (r_subsize) @@ -3267,6 +3333,8 @@ parse_key_parameter_string (const char *string, int part, *r_subkeyuse = 0; if (r_subcurve) *r_subcurve = NULL; + if (r_subversion) + *r_subversion = 4; if (!string || !*string || !ascii_strcasecmp (string, "default") || !strcmp (string, "-")) @@ -3281,11 +3349,11 @@ parse_key_parameter_string (const char *string, int part, *secondary++ = 0; if (part == -1 || part == 0) { - err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size, - r_keyuse, r_curve); + err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size, + r_keyuse, r_curve, r_version); if (!err && part == -1) err = parse_key_parameter_part (secondary, 1, 0, r_subalgo, r_subsize, - r_subkeyuse, r_subcurve); + r_subkeyuse, r_subcurve, r_subversion); } else if (part == 1) { @@ -3298,14 +3366,17 @@ parse_key_parameter_string (const char *string, int part, if (secondary) { err = parse_key_parameter_part (secondary, 1, 0, - r_algo, r_size, r_keyuse, r_curve); + r_algo, r_size, r_keyuse, r_curve, + r_version); if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse)) err = parse_key_parameter_part (primary, 1, 1 /*(clear cert)*/, - r_algo, r_size, r_keyuse, r_curve); + r_algo, r_size, r_keyuse, r_curve, + r_version); } else err = parse_key_parameter_part (primary, 1, 0, - r_algo, r_size, r_keyuse, r_curve); + r_algo, r_size, r_keyuse, r_curve, + r_version); } xfree (primary); @@ -3393,9 +3464,8 @@ get_parameter_algo( struct para_data_s *para, enum para_name key, * compatibility with the batch key generation. It would be * better to make full use of parse_key_parameter_string. */ parse_key_parameter_string (NULL, 0, 0, - &i, NULL, NULL, NULL, - NULL, NULL, NULL, NULL); - + &i, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL); if (r_default) *r_default = 1; } @@ -3526,6 +3596,8 @@ parse_revocation_key (const char *fname, revkey.fpr[i]=c; } + if (i != 20 && i != 32) + goto fail; /* skip to the tag */ while(*pn && *pn!='s' && *pn!='S') @@ -3538,7 +3610,7 @@ parse_revocation_key (const char *fname, return 0; - fail: + fail: log_error("%s:%d: invalid revocation key\n", fname, r->lnr ); return -1; /* error */ } @@ -3806,6 +3878,8 @@ read_parameter_file (ctrl_t ctrl, const char *fname ) { "Keygrip", pKEYGRIP }, { "Key-Grip", pKEYGRIP }, { "Subkey-grip", pSUBKEYGRIP }, + { "Key-Version", pVERSION }, + { "Subkey-Version", pSUBVERSION }, { NULL, 0 } }; IOBUF fp; @@ -3950,12 +4024,19 @@ read_parameter_file (ctrl_t ctrl, const char *fname ) break; } } - r = xmalloc_clear( sizeof *r + strlen( value ) ); - r->lnr = lnr; - r->key = keywords[i].key; - strcpy( r->u.value, value ); - r->next = para; - para = r; + + if (!opt.flags.rfc4880bis && (keywords[i].key == pVERSION + || keywords[i].key == pSUBVERSION)) + ; /* Ignore version unless --rfc4880bis is active. */ + else + { + r = xmalloc_clear( sizeof *r + strlen( value ) ); + r->lnr = lnr; + r->key = keywords[i].key; + strcpy( r->u.value, value ); + r->next = para; + para = r; + } } if( err ) log_error("%s:%d: %s\n", fname, lnr, err ); @@ -3990,7 +4071,8 @@ read_parameter_file (ctrl_t ctrl, const char *fname ) /* Helper for quick_generate_keypair. */ static struct para_data_s * quickgen_set_para (struct para_data_s *para, int for_subkey, - int algo, int nbits, const char *curve, unsigned int use) + int algo, int nbits, const char *curve, unsigned int use, + int version) { struct para_data_s *r; @@ -4029,6 +4111,15 @@ quickgen_set_para (struct para_data_s *para, int for_subkey, para = r; } + if (opt.flags.rfc4880bis) + { + r = xmalloc_clear (sizeof *r + 20); + r->key = for_subkey? pSUBVERSION : pVERSION; + snprintf (r->u.value, 20, "%d", version); + r->next = para; + para = r; + } + return para; } @@ -4121,25 +4212,26 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, || !strcmp (usagestr, "-"))) { /* Use default key parameters. */ - int algo, subalgo; + int algo, subalgo, version, subversion; unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; err = parse_key_parameter_string (algostr, -1, 0, - &algo, &size, &keyuse, &curve, + &algo, &size, &keyuse, &curve, &version, &subalgo, &subsize, &subkeyuse, - &subcurve); + &subcurve, &subversion); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); goto leave; } - para = quickgen_set_para (para, 0, algo, size, curve, keyuse); + para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version); if (subalgo) para = quickgen_set_para (para, 1, - subalgo, subsize, subcurve, subkeyuse); + subalgo, subsize, subcurve, subkeyuse, + subversion); if (*expirestr) { @@ -4162,21 +4254,22 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, else { /* Extended unattended mode. Creates only the primary key. */ - int algo; + int algo, version; unsigned int use; u32 expire; unsigned int nbits; const char *curve; err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr, - &algo, &use, &expire, &nbits, &curve); + &algo, &use, &expire, &nbits, &curve, + &version); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); goto leave; } - para = quickgen_set_para (para, 0, algo, nbits, curve, use); + para = quickgen_set_para (para, 0, algo, nbits, curve, use, version); r = xmalloc_clear (sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; @@ -4490,7 +4583,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, } else /* Default key generation. */ { - int subalgo; + int subalgo, version, subversion; unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; @@ -4505,18 +4598,19 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, , "--full-generate-key" ); err = parse_key_parameter_string (NULL, -1, 0, - &algo, &size, &keyuse, &curve, + &algo, &size, &keyuse, &curve, &version, &subalgo, &subsize, - &subkeyuse, &subcurve); + &subkeyuse, &subcurve, &subversion); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); return; } - para = quickgen_set_para (para, 0, algo, size, curve, keyuse); + para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version); if (subalgo) para = quickgen_set_para (para, 1, - subalgo, subsize, subcurve, subkeyuse); + subalgo, subsize, subcurve, subkeyuse, + subversion); } @@ -4736,6 +4830,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, int algo; u32 expire; const char *key_from_hexgrip = NULL; + unsigned int keygen_flags; if (outctrl->dryrun) { @@ -4804,9 +4899,14 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, algo = get_parameter_algo( para, pKEYTYPE, NULL ); expire = get_parameter_u32( para, pKEYEXPIRE ); key_from_hexgrip = get_parameter_value (para, pKEYGRIP); + + keygen_flags = outctrl->keygen_flags; + if (get_parameter_uint (para, pVERSION) == 5) + keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; + if (key_from_hexgrip) err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, - pub_root, timestamp, expire, 0); + pub_root, timestamp, expire, 0, keygen_flags); else if (!card) err = do_create (algo, get_parameter_uint( para, pKEYLENGTH ), @@ -4814,13 +4914,13 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, pub_root, timestamp, expire, 0, - outctrl->keygen_flags, + keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL); else err = gen_card_key (1, algo, 1, pub_root, ×tamp, - expire); + expire, keygen_flags); /* Get the pointer to the generated public key packet. */ if (!err) @@ -4859,7 +4959,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, if (!err && card && get_parameter (para, pAUTHKEYTYPE)) { err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ), - 0, pub_root, ×tamp, expire); + 0, pub_root, ×tamp, expire, keygen_flags); if (!err) err = write_keybinding (ctrl, pub_root, pri_psk, NULL, PUBKEY_USAGE_AUTH, timestamp, cache_nonce); @@ -4871,11 +4971,16 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, s = NULL; key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP); + + keygen_flags = outctrl->keygen_flags; + if (get_parameter_uint (para, pSUBVERSION) == 5) + keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; + if (key_from_hexgrip) err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip, pub_root, timestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), - 1); + 1, keygen_flags); else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY))) { err = do_create (subkey_algo, @@ -4884,7 +4989,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, pub_root, timestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, - s ? KEYGEN_FLAG_NO_PROTECTION : outctrl->keygen_flags, + s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL); /* Get the pointer to the generated public subkey packet. */ @@ -4904,7 +5009,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, } else { - err = gen_card_key (2, subkey_algo, 0, pub_root, ×tamp, expire); + err = gen_card_key (2, subkey_algo, 0, pub_root, ×tamp, expire, + keygen_flags); } if (!err) @@ -5028,13 +5134,15 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *algostr, const char *usagestr, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, - unsigned int *r_nbits, const char **r_curve) + unsigned int *r_nbits, const char **r_curve, + int *r_version) { gpg_error_t err; int algo; unsigned int use, nbits; u32 expire; int wantuse; + int version = 4; const char *curve = NULL; *r_curve = NULL; @@ -5052,8 +5160,8 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, err = parse_key_parameter_string (algostr, for_subkey? 1 : 0, usagestr? parse_usagestr (usagestr):0, - &algo, &nbits, &use, &curve, - NULL, NULL, NULL, NULL); + &algo, &nbits, &use, &curve, &version, + NULL, NULL, NULL, NULL, NULL); if (err) return err; @@ -5091,6 +5199,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, *r_usage = use; *r_expire = expire; *r_nbits = nbits; + *r_version = version; return 0; } @@ -5118,6 +5227,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, char *serialno = NULL; char *cache_nonce = NULL; char *passwd_nonce = NULL; + int keygen_flags = 0; interactive = (!algostr || !usagestr || !expirestr); @@ -5199,10 +5309,16 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, } else /* Unattended mode. */ { + int version; + err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr, - &algo, &use, &expire, &nbits, &curve); + &algo, &use, &expire, &nbits, &curve, + &version); if (err) goto leave; + + if (version == 5) + keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; } /* Verify the passphrase now so that we get a cache item for the @@ -5225,7 +5341,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, if (key_from_hexgrip) { err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, - keyblock, cur_time, expire, 1); + keyblock, cur_time, expire, 1, + keygen_flags); } else { @@ -5241,7 +5358,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, passwd = NULL; err = do_create (algo, nbits, curve, - keyblock, cur_time, expire, 1, 0, + keyblock, cur_time, expire, 1, keygen_flags, passwd, &cache_nonce, &passwd_nonce); } if (err) @@ -5289,6 +5406,7 @@ generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock, PKT_public_key *sub_pk = NULL; int algo; struct agent_card_info_s info; + int keygen_flags = 0; /* FIXME!!! */ log_assert (keyno >= 1 && keyno <= 3); @@ -5359,7 +5477,8 @@ generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock, /* Note, that depending on the backend, the card key generation may update CUR_TIME. */ - err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire); + err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire, + keygen_flags); /* Get the pointer to the generated public subkey packet. */ if (!err) { @@ -5405,10 +5524,11 @@ write_keyblock( IOBUF out, KBNODE node ) } -/* Note that timestamp is an in/out arg. */ +/* Note that timestamp is an in/out arg. + * FIXME: Does not yet support v5 keys. */ static gpg_error_t gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root, - u32 *timestamp, u32 expireval) + u32 *timestamp, u32 expireval, int keygen_flags) { #ifdef ENABLE_CARD_SUPPORT gpg_error_t err; @@ -5482,7 +5602,7 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root, } pk->timestamp = *timestamp; - pk->version = 4; + pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; diff --git a/g10/keyid.c b/g10/keyid.c index a9034ee46..aa77b47e2 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -136,19 +136,21 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize) } -/* Hash a public key. This function is useful for v4 fingerprints and - for v3 or v4 key signing. */ +/* Hash a public key. This function is useful for v4 and v5 + * fingerprints and for v3 or v4 key signing. */ void hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) { - unsigned int n = 6; + unsigned int n; unsigned int nn[PUBKEY_MAX_NPKEY]; byte *pp[PUBKEY_MAX_NPKEY]; int i; unsigned int nbits; size_t nbytes; int npkey = pubkey_get_npkey (pk->pubkey_algo); + int is_v5 = pk->version == 5; + n = is_v5? 10 : 6; /* FIXME: We can avoid the extra malloc by calling only the first mpi_print here which computes the required length and calling the real mpi_print only at the end. The speed advantage would only be @@ -201,12 +203,22 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) } } - gcry_md_putc ( md, 0x99 ); /* ctb */ - /* What does it mean if n is greater than 0xFFFF ? */ - gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */ - gcry_md_putc ( md, n ); - gcry_md_putc ( md, pk->version ); - + if (is_v5) + { + 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_putc ( md, pk->version ); + } + else + { + gcry_md_putc ( md, 0x99 ); /* ctb */ + gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */ + gcry_md_putc ( md, n ); + gcry_md_putc ( md, pk->version ); + } gcry_md_putc ( md, pk->timestamp >> 24 ); gcry_md_putc ( md, pk->timestamp >> 16 ); gcry_md_putc ( md, pk->timestamp >> 8 ); @@ -214,6 +226,15 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) gcry_md_putc ( md, pk->pubkey_algo ); + if (is_v5) + { + n -= 10; + gcry_md_putc ( md, n >> 24 ); + gcry_md_putc ( md, n >> 16 ); + gcry_md_putc ( md, n >> 8 ); + gcry_md_putc ( md, n ); + } + if(npkey==0 && pk->pkey[0] && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE)) { @@ -237,10 +258,10 @@ do_fingerprint_md( PKT_public_key *pk ) { gcry_md_hd_t md; - if (gcry_md_open (&md, DIGEST_ALGO_SHA1, 0)) + if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0)) BUG (); - hash_public_key(md,pk); - gcry_md_final( md ); + hash_public_key (md,pk); + gcry_md_final (md); return md; } @@ -472,18 +493,27 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc) case KEYDB_SEARCH_MODE_SHORT_KID: return keystr(desc->u.kid); - case KEYDB_SEARCH_MODE_FPR20: + case KEYDB_SEARCH_MODE_FPR: { u32 keyid[2]; - keyid[0] = buf32_to_u32 (desc->u.fpr+12); - keyid[1] = buf32_to_u32 (desc->u.fpr+16); + if (desc->fprlen == 32) + { + keyid[0] = buf32_to_u32 (desc->u.fpr); + keyid[1] = buf32_to_u32 (desc->u.fpr+4); + } + else if (desc->fprlen == 20) + { + keyid[0] = buf32_to_u32 (desc->u.fpr+12); + keyid[1] = buf32_to_u32 (desc->u.fpr+16); + } + else if (desc->fprlen == 16) + return "?v3 fpr?"; + else /* oops */ + return "?vx fpr?"; return keystr(keyid); } - case KEYDB_SEARCH_MODE_FPR16: - return "?v3 fpr?"; - default: BUG(); } @@ -491,13 +521,12 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc) /* - * Get the keyid from the public key and put it into keyid - * if this is not NULL. Return the 32 low bits of the keyid. + * Get the keyid from the public key PK and store it at KEYID unless + * this is NULL. Returns the 32 bit short keyid. */ u32 keyid_from_pk (PKT_public_key *pk, u32 *keyid) { - u32 lowbits; u32 dummy_keyid[2]; if (!keyid) @@ -507,7 +536,6 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid) { keyid[0] = pk->keyid[0]; keyid[1] = pk->keyid[1]; - lowbits = keyid[1]; } else { @@ -518,24 +546,32 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid) if(md) { dp = gcry_md_read ( md, 0 ); - keyid[0] = buf32_to_u32 (dp+12); - keyid[1] = buf32_to_u32 (dp+16); - lowbits = keyid[1]; + if (pk->version == 5) + { + keyid[0] = buf32_to_u32 (dp); + keyid[1] = buf32_to_u32 (dp+4); + } + else + { + keyid[0] = buf32_to_u32 (dp+12); + keyid[1] = buf32_to_u32 (dp+16); + } gcry_md_close (md); pk->keyid[0] = keyid[0]; pk->keyid[1] = keyid[1]; } else - pk->keyid[0]=pk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF; + pk->keyid[0] = pk->keyid[1] = keyid[0]= keyid[1] = 0xFFFFFFFF; } - return lowbits; + return keyid[1]; /*FIXME:shortkeyid ist different for v5*/ } /* - * Get the keyid from the fingerprint. This function is simple for most - * keys, but has to do a keylookup for old stayle keys. + * Get the keyid from the fingerprint. This function is simple for + * most keys, but has to do a key lookup for old v3 keys where the + * keyid is not part of the fingerprint. */ u32 keyid_from_fingerprint (ctrl_t ctrl, const byte *fprint, @@ -546,7 +582,7 @@ keyid_from_fingerprint (ctrl_t ctrl, const byte *fprint, if( !keyid ) keyid = dummy_keyid; - if (fprint_len != 20) + if (fprint_len != 20 && fprint_len != 32) { /* This is special as we have to lookup the key first. */ PKT_public_key pk; @@ -556,7 +592,8 @@ keyid_from_fingerprint (ctrl_t ctrl, const byte *fprint, rc = get_pubkey_byfprint (ctrl, &pk, NULL, fprint, fprint_len); if( rc ) { - log_error("Oops: keyid_from_fingerprint: no pubkey\n"); + log_printhex (fprint, fprint_len, + "Oops: keyid_from_fingerprint: no pubkey; fpr:"); keyid[0] = 0; keyid[1] = 0; } @@ -566,8 +603,16 @@ keyid_from_fingerprint (ctrl_t ctrl, const byte *fprint, else { const byte *dp = fprint; - keyid[0] = buf32_to_u32 (dp+12); - keyid[1] = buf32_to_u32 (dp+16); + if (fprint_len == 20) /* v4 key */ + { + keyid[0] = buf32_to_u32 (dp+12); + keyid[1] = buf32_to_u32 (dp+16); + } + else /* v5 key */ + { + keyid[0] = buf32_to_u32 (dp); + keyid[1] = buf32_to_u32 (dp+4); + } } return keyid[1]; @@ -582,7 +627,7 @@ keyid_from_sig (PKT_signature *sig, u32 *keyid) keyid[0] = sig->keyid[0]; keyid[1] = sig->keyid[1]; } - return sig->keyid[1]; + return sig->keyid[1]; /*FIXME:shortkeyid*/ } @@ -772,15 +817,23 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) size_t len; gcry_md_hd_t md; - md = do_fingerprint_md(pk); - dp = gcry_md_read( md, 0 ); + md = do_fingerprint_md (pk); + dp = gcry_md_read (md, 0); len = gcry_md_get_algo_dlen (gcry_md_get_algo (md)); - log_assert( len <= MAX_FINGERPRINT_LEN ); + log_assert (len <= MAX_FINGERPRINT_LEN); if (!array) array = xmalloc ( len ); memcpy (array, dp, len ); - pk->keyid[0] = buf32_to_u32 (dp+12); - pk->keyid[1] = buf32_to_u32 (dp+16); + if (pk->version == 5) + { + pk->keyid[0] = buf32_to_u32 (dp); + pk->keyid[1] = buf32_to_u32 (dp+4); + } + else + { + pk->keyid[0] = buf32_to_u32 (dp+12); + pk->keyid[1] = buf32_to_u32 (dp+16); + } gcry_md_close( md); if (ret_len) @@ -975,7 +1028,12 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) if (!gcry_pk_get_keygrip (s_pkey, array)) { - log_info ("error computing keygrip\n"); + char *hexfpr; + + hexfpr = hexfingerprint (pk, NULL, 0); + log_info ("error computing keygrip (fpr=%s)\n", hexfpr); + xfree (hexfpr); + memset (array, 0, 20); err = gpg_error (GPG_ERR_GENERAL); } diff --git a/g10/keylist.c b/g10/keylist.c index 8b7da76ee..8d5b2e0b9 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -212,7 +212,7 @@ print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk) else p = get_user_id_native (ctrl, keyid); - if (fp) + if (!fp) tty_printf ("\n"); tty_fprintf (fp, "%s %s/%s %s %s\n", pk->flags.primary? "pub":"sub", @@ -541,7 +541,7 @@ list_all (ctrl_t ctrl, int secret, int mark_secret) ; /* Secret key listing requested but this isn't one. */ else { - if (!opt.with_colons) + if (!opt.with_colons && !(opt.list_options & LIST_SHOW_ONLY_FPR_MBOX)) { resname = keydb_get_resource_name (hd); if (lastresname != resname) @@ -611,6 +611,7 @@ list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret) { log_error ("error reading key: %s\n", gpg_strerror (rc)); getkey_end (ctrl, ctx); + write_status_error ("keylist.getkey", rc); return; } @@ -1020,7 +1021,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, char *mbox, *hash, *p; char hashbuf[32]; - mbox = mailbox_from_userid (uid->name); + mbox = mailbox_from_userid (uid->name, 0); if (mbox && (p = strchr (mbox, '@'))) { *p++ = 0; @@ -1254,6 +1255,57 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, xfree (hexgrip); } + +/* Do a simple key listing printing only the fingerprint and the mail + * address of valid keys. */ +static void +list_keyblock_simple (ctrl_t ctrl, kbnode_t keyblock) +{ + gpg_err_code_t ec; + kbnode_t kbctx; + kbnode_t node; + char hexfpr[2*MAX_FINGERPRINT_LEN+1]; + char *mbox; + + (void)ctrl; + + node = find_kbnode (keyblock, PKT_PUBLIC_KEY); + if (!node) + { + log_error ("Oops; key lost!\n"); + dump_kbnode (keyblock); + return; + } + hexfingerprint (node->pkt->pkt.public_key, hexfpr, sizeof hexfpr); + + for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) + { + if (node->pkt->pkttype == PKT_USER_ID) + { + PKT_user_id *uid = node->pkt->pkt.user_id; + + if (uid->attrib_data) + continue; + + if (uid->flags.expired || uid->flags.revoked) + continue; + + mbox = mailbox_from_userid (uid->name, 0); + if (!mbox) + { + ec = gpg_err_code_from_syserror (); + if (ec != GPG_ERR_EINVAL) + log_error ("error getting mailbox from user-id: %s\n", + gpg_strerror (ec)); + continue; + } + es_fprintf (es_stdout, "%s %s\n", hexfpr, mbox); + xfree (mbox); + } + } +} + + void print_revokers (estream_t fp, PKT_public_key * pk) { @@ -1270,7 +1322,7 @@ print_revokers (estream_t fp, PKT_public_key * pk) es_fprintf (fp, "rvk:::%d::::::", pk->revkey[i].algid); p = pk->revkey[i].fpr; - for (j = 0; j < 20; j++, p++) + for (j = 0; j < pk->revkey[i].fprlen; j++, p++) es_fprintf (fp, "%02X", *p); es_fprintf (fp, ":%02x%s:\n", pk->revkey[i].class, @@ -1807,6 +1859,12 @@ list_keyblock (ctrl_t ctrl, if (opt.with_colons) list_keyblock_colon (ctrl, keyblock, secret, has_secret); + else if ((opt.list_options & LIST_SHOW_ONLY_FPR_MBOX)) + { + if (!listctx->no_validity) + check_trustdb_stale (ctrl); + list_keyblock_simple (ctrl, keyblock); + } else list_keyblock_print (ctrl, keyblock, secret, fpr, listctx); @@ -2044,10 +2102,18 @@ print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret) tty_fprintf (fp, "/%s", keystr_from_pk (pk)); tty_fprintf (fp, " %s", datestr_from_pk (pk)); - if ((opt.list_options & LIST_SHOW_USAGE)) + if (pk->flags.primary + && !(openpgp_pk_algo_usage (pk->pubkey_algo) + & (PUBKEY_USAGE_CERT| PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH))) + { + /* A primary key which is really not capable to sign. */ + tty_fprintf (fp, " [INVALID_ALGO]"); + } + else if ((opt.list_options & LIST_SHOW_USAGE)) { tty_fprintf (fp, " [%s]", usagestr_from_pk (pk, 0)); } + if (pk->flags.revoked) { tty_fprintf (fp, " ["); diff --git a/g10/keyring.c b/g10/keyring.c index 25ef50747..21791a6ac 100644 --- a/g10/keyring.c +++ b/g10/keyring.c @@ -995,8 +995,6 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, case KEYDB_SEARCH_MODE_LONG_KID: need_keyid = 1; break; - case KEYDB_SEARCH_MODE_FPR16: - case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: need_fpr = 1; break; @@ -1134,11 +1132,12 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, pk = pkt.pkt.public_key; ++pk_no; - if (need_fpr) { - fingerprint_from_pk (pk, afp, &an); - while (an < 20) /* fill up to 20 bytes */ - afp[an++] = 0; - } + if (need_fpr) + { + fingerprint_from_pk (pk, afp, &an); + while (an < 32) /* fill up to 32 bytes */ + afp[an++] = 0; + } if (need_keyid) keyid_from_pk (pk, aki); @@ -1180,13 +1179,9 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, && desc[n].u.kid[1] == aki[1]) goto found; break; - case KEYDB_SEARCH_MODE_FPR16: - if (pk && !memcmp (desc[n].u.fpr, afp, 16)) - goto found; - break; - case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: - if (pk && !memcmp (desc[n].u.fpr, afp, 20)) + if (pk && desc[n].fprlen >= 16 && desc[n].fprlen <= 32 + && !memcmp (desc[n].u.fpr, afp, desc[n].fprlen)) goto found; break; case KEYDB_SEARCH_MODE_FIRST: diff --git a/g10/keyserver.c b/g10/keyserver.c index a8c222d3f..66900f7a9 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -470,7 +470,6 @@ parse_preferred_keyserver(PKT_signature *sig) static void print_keyrec (ctrl_t ctrl, int number,struct keyrec *keyrec) { - int i; iobuf_writebyte(keyrec->uidbuf,0); iobuf_flush_temp(keyrec->uidbuf); @@ -509,20 +508,11 @@ print_keyrec (ctrl_t ctrl, int number,struct keyrec *keyrec) es_printf ("key %s",keystr(keyrec->desc.u.kid)); break; - /* If it gave us a PGP 2.x fingerprint, not much we can do - beyond displaying it. */ - case KEYDB_SEARCH_MODE_FPR16: - es_printf ("key "); - for(i=0;i<16;i++) - es_printf ("%02X",keyrec->desc.u.fpr[i]); - break; - - /* If we get a modern fingerprint, we have the most - flexibility. */ - case KEYDB_SEARCH_MODE_FPR20: + case KEYDB_SEARCH_MODE_FPR: { u32 kid[2]; - keyid_from_fingerprint (ctrl, keyrec->desc.u.fpr,20,kid); + keyid_from_fingerprint (ctrl, keyrec->desc.u.fpr, keyrec->desc.fprlen, + kid); es_printf("key %s",keystr(kid)); } break; @@ -613,8 +603,7 @@ parse_keyrec(char *keystring) err = classify_user_id (tok, &work->desc, 1); if (err || (work->desc.mode != KEYDB_SEARCH_MODE_SHORT_KID && work->desc.mode != KEYDB_SEARCH_MODE_LONG_KID - && work->desc.mode != KEYDB_SEARCH_MODE_FPR16 - && work->desc.mode != KEYDB_SEARCH_MODE_FPR20)) + && work->desc.mode != KEYDB_SEARCH_MODE_FPR)) { work->desc.mode=KEYDB_SEARCH_MODE_NONE; return ret; @@ -995,8 +984,7 @@ keyserver_export (ctrl_t ctrl, strlist_t users) err = classify_user_id (users->d, &desc, 1); if (err || (desc.mode != KEYDB_SEARCH_MODE_SHORT_KID && desc.mode != KEYDB_SEARCH_MODE_LONG_KID - && desc.mode != KEYDB_SEARCH_MODE_FPR16 - && desc.mode != KEYDB_SEARCH_MODE_FPR20)) + && desc.mode != KEYDB_SEARCH_MODE_FPR)) { log_error(_("\"%s\" not a key ID: skipping\n"),users->d); continue; @@ -1065,14 +1053,9 @@ keyserver_retrieval_screener (kbnode_t keyblock, void *opaque) /* Compare requested and returned fingerprints if available. */ for (n = 0; n < ndesc; n++) { - if (desc[n].mode == KEYDB_SEARCH_MODE_FPR20) - { - if (fpr_len == 20 && !memcmp (fpr, desc[n].u.fpr, 20)) - return 0; - } - else if (desc[n].mode == KEYDB_SEARCH_MODE_FPR16) + if (desc[n].mode == KEYDB_SEARCH_MODE_FPR) { - if (fpr_len == 16 && !memcmp (fpr, desc[n].u.fpr, 16)) + if (fpr_len == desc[n].fprlen && !memcmp (fpr, desc[n].u.fpr, 32)) return 0; } else if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID) @@ -1110,8 +1093,7 @@ keyserver_import (ctrl_t ctrl, strlist_t users) err = classify_user_id (users->d, &desc[count], 1); if (err || (desc[count].mode != KEYDB_SEARCH_MODE_SHORT_KID && desc[count].mode != KEYDB_SEARCH_MODE_LONG_KID - && desc[count].mode != KEYDB_SEARCH_MODE_FPR16 - && desc[count].mode != KEYDB_SEARCH_MODE_FPR20)) + && desc[count].mode != KEYDB_SEARCH_MODE_FPR)) { log_error (_("\"%s\" not a key ID: skipping\n"), users->d); continue; @@ -1167,14 +1149,13 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, memset(&desc,0,sizeof(desc)); - if(fprint_len==16) - desc.mode=KEYDB_SEARCH_MODE_FPR16; - else if(fprint_len==20) - desc.mode=KEYDB_SEARCH_MODE_FPR20; + if (fprint_len == 16 || fprint_len == 20 || fprint_len == 32) + desc.mode = KEYDB_SEARCH_MODE_FPR; else return -1; memcpy(desc.u.fpr,fprint,fprint_len); + desc.fprlen = fprint_len; /* TODO: Warn here if the fingerprint we got doesn't match the one we asked for? */ @@ -1291,20 +1272,21 @@ keyidlist (ctrl_t ctrl, strlist_t users, KEYDB_SEARCH_DESC **klist, This is because it's easy to calculate any sort of keyid from a v4 fingerprint, but not a v3 fingerprint. */ - if(node->pkt->pkt.public_key->version<4) + if (node->pkt->pkt.public_key->version < 4) { (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID; keyid_from_pk(node->pkt->pkt.public_key, (*klist)[*count].u.kid); } else - { - size_t dummy; + { + size_t fprlen; - (*klist)[*count].mode=KEYDB_SEARCH_MODE_FPR20; - fingerprint_from_pk(node->pkt->pkt.public_key, - (*klist)[*count].u.fpr,&dummy); - } + fingerprint_from_pk (node->pkt->pkt.public_key, + (*klist)[*count].u.fpr, &fprlen); + (*klist)[*count].mode = KEYDB_SEARCH_MODE_FPR; + (*klist)[*count].fprlen = fprlen; + } /* This is a little hackish, using the skipfncvalue as a void* pointer to the keyserver spec, but we don't need @@ -1528,7 +1510,7 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens) err = gpg_dirmngr_ks_search (ctrl, searchstr, search_line_handler, &parm); - if (parm.not_found) + if (parm.not_found || gpg_err_code (err) == GPG_ERR_NO_DATA) { if (parm.searchstr_disp) log_info (_("key \"%s\" not found on keyserver\n"), @@ -1539,6 +1521,8 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens) if (gpg_err_code (err) == GPG_ERR_NO_KEYSERVER) log_error (_("no keyserver known (use option --keyserver)\n")); + else if (gpg_err_code (err) == GPG_ERR_NO_DATA) + err = gpg_error (GPG_ERR_NOT_FOUND); else if (err) log_error ("error searching keyserver: %s\n", gpg_strerror (err)); @@ -1618,10 +1602,9 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, { int quiet = 0; - if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20 - || desc[idx].mode == KEYDB_SEARCH_MODE_FPR16) + if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR) { - n = 1+2+2*20; + n = 1+2+2*desc[idx].fprlen; if (idx && linelen + n > MAX_KS_GET_LINELEN) break; /* Declare end of this chunk. */ linelen += n; @@ -1632,11 +1615,9 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, else { strcpy (pattern[npat], "0x"); - bin2hex (desc[idx].u.fpr, - desc[idx].mode == KEYDB_SEARCH_MODE_FPR20? 20 : 16, - pattern[npat]+2); + bin2hex (desc[idx].u.fpr, desc[idx].fprlen, pattern[npat]+2); npat++; - if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20) + if (desc[idx].fprlen == 20 || desc[idx].fprlen == 32) npat_fpr++; } } @@ -1715,7 +1696,7 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, } } - /* Remember now many of search items were considered. Note that + /* Remember how many of the search items were considered. Note that this is different from NPAT. */ *r_ndesc_used = idx; @@ -2053,7 +2034,7 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick, /* We want to work on the mbox. That is what dirmngr will do anyway * and we need the mbox for the import filter anyway. */ - mbox = mailbox_from_userid (name); + mbox = mailbox_from_userid (name, 0); if (!mbox) { err = gpg_error_from_syserror (); diff --git a/g10/main.h b/g10/main.h index 768f7cfb8..34a932b16 100644 --- a/g10/main.h +++ b/g10/main.h @@ -41,7 +41,9 @@ # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_3DES #endif -#if GCRYPT_VERSION_NUMBER < 0x019000 +/* We will start using OCB mode by default only if the yet to be + * released libgcrypt 1.9 is used. */ +#if GCRYPT_VERSION_NUMBER < 0x010900 # define DEFAULT_AEAD_ALGO AEAD_ALGO_OCB #else # define DEFAULT_AEAD_ALGO AEAD_ALGO_EAX @@ -392,7 +394,8 @@ struct impex_filter_parm_s const char *impex_filter_getval (void *cookie, const char *propname); gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, - kbnode_t sec_keyblock, int batch, int force); + kbnode_t sec_keyblock, int batch, int force, + int only_marked); int collapse_uids( KBNODE *keyblock ); @@ -505,8 +508,6 @@ gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock); int card_store_subkey (KBNODE node, int use); #endif -#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) - /*-- migrate.c --*/ void migrate_secring (ctrl_t ctrl); diff --git a/g10/mainproc.c b/g10/mainproc.c index 6ec15894d..7acf67b1e 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -86,6 +86,7 @@ struct mainproc_context int trustletter; /* Temporary usage in list_node. */ ulong symkeys; /* Number of symmetrically encrypted session keys. */ struct pubkey_enc_list *pkenc_list; /* List of encryption packets. */ + int seen_pkt_encrypted_aead; /* PKT_ENCRYPTED_AEAD packet seen. */ struct { unsigned int sig_seen:1; /* Set to true if a signature packet has been seen. */ @@ -137,6 +138,7 @@ release_list( CTX c ) c->any.data = 0; c->any.uncompress_failed = 0; c->last_was_session_key = 0; + c->seen_pkt_encrypted_aead = 0; xfree (c->dek); c->dek = NULL; } @@ -479,6 +481,7 @@ proc_pubkey_enc (CTX c, PACKET *pkt) x->keyid[0] = enc->keyid[0]; x->keyid[1] = enc->keyid[1]; x->pubkey_algo = enc->pubkey_algo; + x->result = -1; x->data[0] = x->data[1] = NULL; if (enc->data[0]) { @@ -536,6 +539,9 @@ proc_encrypted (CTX c, PACKET *pkt) int result = 0; int early_plaintext = literals_seen; + if (pkt->pkttype == PKT_ENCRYPTED_AEAD) + c->seen_pkt_encrypted_aead = 1; + if (early_plaintext) { log_info (_("WARNING: multiple plaintexts seen\n")); @@ -572,22 +578,21 @@ proc_encrypted (CTX c, PACKET *pkt) { c->dek = xmalloc_secure_clear (sizeof *c->dek); result = get_session_key (c->ctrl, c->pkenc_list, c->dek); - if (result == GPG_ERR_NO_SECKEY) - { - if (is_status_enabled ()) - { - struct pubkey_enc_list *list; - - for (list = c->pkenc_list; list; list = list->next) - { - char buf[20]; - snprintf (buf, sizeof buf, "%08lX%08lX", - (ulong)list->keyid[0], (ulong)list->keyid[1]); - write_status_text (STATUS_NO_SECKEY, buf); - } - } + if (is_status_enabled ()) + { + struct pubkey_enc_list *list; + + for (list = c->pkenc_list; list; list = list->next) + if (list->result == GPG_ERR_NO_SECKEY) + { + char buf[20]; + snprintf (buf, sizeof buf, "%08lX%08lX", + (ulong)list->keyid[0], (ulong)list->keyid[1]); + write_status_text (STATUS_NO_SECKEY, buf); + } } - else if (result) + + if (result) { log_info (_("public key decryption failed: %s\n"), gpg_strerror (result)); @@ -704,7 +709,6 @@ proc_encrypted (CTX c, PACKET *pkt) } - if (!result) result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek ); @@ -804,14 +808,31 @@ proc_encrypted (CTX c, PACKET *pkt) } +static int +have_seen_pkt_encrypted_aead( CTX c ) +{ + CTX cc; + + for (cc = c; cc; cc = cc->anchor) + { + if (cc->seen_pkt_encrypted_aead) + return 1; + } + + return 0; +} + + static void proc_plaintext( CTX c, PACKET *pkt ) { PKT_plaintext *pt = pkt->pkt.plaintext; int any, clearsig, rc; kbnode_t n; + unsigned char *extrahash; + size_t extrahashlen; - /* This is a literal data packet. Bumb a counter for later checks. */ + /* This is a literal data packet. Bump a counter for later checks. */ literals_seen++; if (pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8)) @@ -843,7 +864,10 @@ proc_plaintext( CTX c, PACKET *pkt ) /* The onepass signature case. */ if (n->pkt->pkt.onepass_sig->digest_algo) { - gcry_md_enable (c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo); + if (!opt.skip_verify) + gcry_md_enable (c->mfx.md, + n->pkt->pkt.onepass_sig->digest_algo); + any = 1; } } @@ -861,7 +885,8 @@ proc_plaintext( CTX c, PACKET *pkt ) * documents. */ clearsig = (*data == 0x01); for (data++, datalen--; datalen; datalen--, data++) - gcry_md_enable (c->mfx.md, *data); + if (!opt.skip_verify) + gcry_md_enable (c->mfx.md, *data); any = 1; break; /* Stop here as one-pass signature packets are not expected. */ @@ -869,12 +894,13 @@ proc_plaintext( CTX c, PACKET *pkt ) else if (n->pkt->pkttype == PKT_SIGNATURE) { /* The SIG+LITERAL case that PGP used to use. */ - gcry_md_enable ( c->mfx.md, n->pkt->pkt.signature->digest_algo ); + if (!opt.skip_verify) + gcry_md_enable (c->mfx.md, n->pkt->pkt.signature->digest_algo); any = 1; } } - if (!any && !opt.skip_verify) + if (!any && !opt.skip_verify && !have_seen_pkt_encrypted_aead(c)) { /* This is for the old GPG LITERAL+SIG case. It's not legal according to 2440, so hopefully it won't come up that often. @@ -920,12 +946,37 @@ proc_plaintext( CTX c, PACKET *pkt ) if (rc) log_error ("handle plaintext failed: %s\n", gpg_strerror (rc)); + /* We add a marker control packet instead of the plaintext packet. + * This is so that we can later detect invalid packet sequences. + * The apcket is further used to convey extra data from the + * plaintext packet to the signature verification. */ + extrahash = xtrymalloc (6 + pt->namelen); + if (!extrahash) + { + /* No way to return an error. */ + rc = gpg_error_from_syserror (); + log_error ("malloc failed in %s: %s\n", __func__, gpg_strerror (rc)); + extrahashlen = 0; + } + else + { + extrahash[0] = pt->mode; + extrahash[1] = pt->namelen; + if (pt->namelen) + memcpy (extrahash+2, pt->name, pt->namelen); + extrahashlen = 2 + pt->namelen; + extrahash[extrahashlen++] = pt->timestamp >> 24; + extrahash[extrahashlen++] = pt->timestamp >> 16; + extrahash[extrahashlen++] = pt->timestamp >> 8; + extrahash[extrahashlen++] = pt->timestamp ; + } + free_packet (pkt, NULL); c->last_was_session_key = 0; - /* We add a marker control packet instead of the plaintext packet. - * This is so that we can later detect invalid packet sequences. */ - n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0)); + n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, + extrahash, extrahashlen)); + xfree (extrahash); if (c->list) add_kbnode (c->list, n); else @@ -995,7 +1046,8 @@ proc_compressed (CTX c, PACKET *pkt) * found. Returns: 0 = valid signature or an error code */ static int -do_check_sig (CTX c, kbnode_t node, int *is_selfsig, +do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen, + int *is_selfsig, int *is_expkey, int *is_revkey, PKT_public_key **r_pk) { PKT_signature *sig; @@ -1081,14 +1133,16 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig, /* We only get here if we are checking the signature of a binary (0x00) or text document (0x01). */ - rc = check_signature2 (c->ctrl, sig, md, NULL, is_expkey, is_revkey, r_pk); + rc = check_signature2 (c->ctrl, sig, md, extrahash, extrahashlen, + NULL, is_expkey, is_revkey, r_pk); if (! rc) md_good = md; else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2) { PKT_public_key *pk2; - rc = check_signature2 (c->ctrl, sig, md2, NULL, is_expkey, is_revkey, + rc = check_signature2 (c->ctrl, sig, md2, extrahash, extrahashlen, + NULL, is_expkey, is_revkey, r_pk? &pk2 : NULL); if (!rc) { @@ -1251,7 +1305,7 @@ list_node (CTX c, kbnode_t node) if (opt.check_sigs) { fflush (stdout); - rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL, NULL); + rc2 = do_check_sig (c, node, NULL, 0, &is_selfsig, NULL, NULL, NULL); switch (gpg_err_code (rc2)) { case 0: sigrc = '!'; break; @@ -1714,7 +1768,7 @@ akl_has_wkd_method (void) } -/* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN. +/* Return the ISSUER fingerprint buffer and its length at R_LEN. * Returns NULL if not available. The returned buffer is valid as * long as SIG is not modified. */ const byte * @@ -1724,7 +1778,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len) size_t n; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n); - if (p && n == 21 && p[0] == 4) + if (p && ((n == 21 && p[0] == 4) || (n == 33 && p[0] == 5))) { *r_len = n - 1; return p+1; @@ -1787,6 +1841,8 @@ check_sig_and_print (CTX c, kbnode_t node) char *issuer_fpr = NULL; PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */ int tried_ks_by_fpr; + const void *extrahash = NULL; + size_t extrahashlen = 0; if (opt.skip_verify) { @@ -1844,6 +1900,8 @@ check_sig_and_print (CTX c, kbnode_t node) { if (n->next) goto ambiguous; /* We only allow one P packet. */ + extrahash = n->pkt->pkt.gpg_control->data; + extrahashlen = n->pkt->pkt.gpg_control->datalen; } else goto ambiguous; @@ -1858,6 +1916,9 @@ check_sig_and_print (CTX c, kbnode_t node) && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK))) goto ambiguous; + extrahash = n->pkt->pkt.gpg_control->data; + extrahashlen = n->pkt->pkt.gpg_control->datalen; + for (n_sig=0, n = n->next; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) n_sig++; @@ -1888,6 +1949,8 @@ check_sig_and_print (CTX c, kbnode_t node) && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK))) goto ambiguous; + extrahash = n->pkt->pkt.gpg_control->data; + extrahashlen = n->pkt->pkt.gpg_control->datalen; for (n_sig=0, n = n->next; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) n_sig++; @@ -1933,7 +1996,8 @@ check_sig_and_print (CTX c, kbnode_t node) if (sig->signers_uid) log_info (_(" issuer \"%s\"\n"), sig->signers_uid); - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); /* If the key isn't found, check for a preferred keyserver. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks) @@ -1968,8 +2032,8 @@ check_sig_and_print (CTX c, kbnode_t node) res = keyserver_import_keyid (c->ctrl, sig->keyid,spec, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) - rc = do_check_sig (c, node, NULL, - &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); free_keyserver_spec (spec); if (!rc) @@ -2004,7 +2068,8 @@ check_sig_and_print (CTX c, kbnode_t node) glo_ctrl.in_auto_key_retrieve--; free_keyserver_spec (spec); if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); } } } @@ -2026,7 +2091,7 @@ check_sig_and_print (CTX c, kbnode_t node) p = issuer_fpr_raw (sig, &n); if (p) { - /* v4 packet with a SHA-1 fingerprint. */ + /* v4 or v5 packet with a SHA-1/256 fingerprint. */ free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; @@ -2034,7 +2099,8 @@ check_sig_and_print (CTX c, kbnode_t node) tried_ks_by_fpr = 1; glo_ctrl.in_auto_key_retrieve--; if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); } } @@ -2056,7 +2122,8 @@ check_sig_and_print (CTX c, kbnode_t node) /* Fixme: If the fingerprint is embedded in the signature, * compare it to the fingerprint of the returned key. */ if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); } /* If the above methods did't work, our next try is to use a @@ -2074,7 +2141,8 @@ check_sig_and_print (CTX c, kbnode_t node) res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); } if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE) diff --git a/g10/misc.c b/g10/misc.c index d7a3ee3f2..0541d2b77 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -513,6 +513,7 @@ map_pk_gcry_to_openpgp (enum gcry_pk_algos algo) { switch (algo) { + case GCRY_PK_EDDSA: return PUBKEY_ALGO_EDDSA; case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA; case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH; default: return algo < 110 ? (pubkey_algo_t)algo : 0; @@ -549,7 +550,7 @@ openpgp_cipher_blocklen (cipher_algo_t algo) /**************** * Wrapper around the libgcrypt function with additional checks on - * the OpenPGP contraints for the algo ID. + * the OpenPGP constraints for the algo ID. */ int openpgp_cipher_test_algo (cipher_algo_t algo) @@ -712,7 +713,7 @@ openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use) #endif case PUBKEY_ALGO_ELGAMAL: - /* Dont't allow type 20 keys unless in rfc2440 mode. */ + /* Don't allow type 20 keys unless in rfc2440 mode. */ if (RFC2440) ga = GCRY_PK_ELG; break; @@ -723,6 +724,13 @@ openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use) if (!ga) return gpg_error (GPG_ERR_PUBKEY_ALGO); + /* Elgamal in OpenPGP used to support signing and Libgcrypt still + * does. However, we removed the signing capability from gpg ages + * ago. This function should reflect this so that errors are thrown + * early and not only when we try to sign using Elgamal. */ + if (ga == GCRY_PK_ELG && (use & (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG))) + return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); + /* Now check whether Libgcrypt has support for the algorithm. */ return gcry_pk_algo_info (ga, GCRYCTL_TEST_ALGO, NULL, &use_buf); } @@ -1521,6 +1529,8 @@ optlen(const char *s) return strlen(s); } + +/* Note: This function returns true on success. */ int parse_options(char *str,unsigned int *options, struct parse_options *opts,int noisy) diff --git a/g10/options.h b/g10/options.h index 7defbda76..8adf09f08 100644 --- a/g10/options.h +++ b/g10/options.h @@ -360,6 +360,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; #define IMPORT_RESTORE (1<<10) #define IMPORT_REPAIR_KEYS (1<<11) #define IMPORT_DRY_RUN (1<<12) +#define IMPORT_DROP_UIDS (1<<13) #define EXPORT_LOCAL_SIGS (1<<0) #define EXPORT_ATTRIBUTES (1<<1) @@ -370,6 +371,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; #define EXPORT_PKA_FORMAT (1<<6) #define EXPORT_DANE_FORMAT (1<<7) #define EXPORT_BACKUP (1<<10) +#define EXPORT_DROP_UIDS (1<<13) #define LIST_SHOW_PHOTOS (1<<0) #define LIST_SHOW_POLICY_URLS (1<<1) @@ -384,6 +386,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; #define LIST_SHOW_SIG_EXPIRE (1<<9) #define LIST_SHOW_SIG_SUBPACKETS (1<<10) #define LIST_SHOW_USAGE (1<<11) +#define LIST_SHOW_ONLY_FPR_MBOX (1<<12) #define VERIFY_SHOW_PHOTOS (1<<0) #define VERIFY_SHOW_POLICY_URLS (1<<1) diff --git a/g10/packet.h b/g10/packet.h index 6e1438be6..41dd1a95a 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -34,11 +34,11 @@ #define DEBUG_PARSE_PACKET 1 -/* Constants to allocate static MPI arrays. */ -#define PUBKEY_MAX_NPKEY 5 -#define PUBKEY_MAX_NSKEY 7 -#define PUBKEY_MAX_NSIG 2 -#define PUBKEY_MAX_NENC 2 +/* Constants to allocate static MPI arrays. */ +#define PUBKEY_MAX_NPKEY OPENPGP_MAX_NPKEY +#define PUBKEY_MAX_NSKEY OPENPGP_MAX_NSKEY +#define PUBKEY_MAX_NSIG OPENPGP_MAX_NSIG +#define PUBKEY_MAX_NENC OPENPGP_MAX_NENC /* Usage flags */ #define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */ @@ -137,6 +137,7 @@ struct pubkey_enc_list struct pubkey_enc_list *next; u32 keyid[2]; int pubkey_algo; + int result; gcry_mpi_t data[PUBKEY_MAX_NENC]; }; @@ -180,6 +181,8 @@ struct revocation_key { byte class; /* The public-key algorithm ID. */ byte algid; + /* The length of the fingerprint. */ + byte fprlen; /* The fingerprint of the authorized key. */ byte fpr[MAX_FINGERPRINT_LEN]; }; @@ -244,7 +247,7 @@ typedef struct const byte *trust_regexp; struct revocation_key *revkey; int numrevkeys; - int help_counter; /* Used internally bu some fucntions. */ + int help_counter; /* Used internally bu some functions. */ pka_info_t *pka_info; /* Malloced PKA data or NULL if not available. See also flags.pka_tried. */ char *signers_uid; /* Malloced value of the SIGNERS_UID @@ -850,7 +853,7 @@ PACKET *create_gpg_control ( ctrlpkttype_t type, /*-- build-packet.c --*/ int build_packet (iobuf_t out, PACKET *pkt); gpg_error_t build_packet_and_meta (iobuf_t out, PACKET *pkt); -gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a); +gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *t_nwritten); gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a); u32 calc_packet_length( PACKET *pkt ); void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, @@ -897,6 +900,7 @@ int check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest); * it and verifying the signature. */ gpg_error_t check_signature2 (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest, + const void *extrahash, size_t extrahashlen, u32 *r_expiredate, int *r_expired, int *r_revoked, PKT_public_key **r_pk); diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 92c65294a..5b4b1c900 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1644,7 +1644,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type) if (n < 8) break; return 0; - case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */ + case SIGSUBPKT_ISSUER_FPR: /* issuer key fingerprint */ if (n < 21) break; return 0; @@ -1905,21 +1905,23 @@ parse_revkeys (PKT_signature * sig) while ((revkey = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REV_KEY, &len, &seq, NULL))) { - if (/* The only valid length is 22 bytes. See RFC 4880 - 5.2.3.15. */ - len == 22 - /* 0x80 bit must be set on the class. */ + /* Consider only valid packets. They must have a length of + * either 2+20 or 2+32 octets and bit 7 of the class octet must + * be set. */ + if ((len == 22 || len == 34) && (revkey[0] & 0x80)) { sig->revkey = xrealloc (sig->revkey, sizeof (struct revocation_key) * (sig->numrevkeys + 1)); - /* Copy the individual fields. */ sig->revkey[sig->numrevkeys].class = revkey[0]; sig->revkey[sig->numrevkeys].algid = revkey[1]; - memcpy (sig->revkey[sig->numrevkeys].fpr, &revkey[2], 20); - + len -= 2; + sig->revkey[sig->numrevkeys].fprlen = len; + memcpy (sig->revkey[sig->numrevkeys].fpr, revkey+2, len); + memset (sig->revkey[sig->numrevkeys].fpr+len, 0, + sizeof (sig->revkey[sig->numrevkeys].fpr) - len); sig->numrevkeys++; } } @@ -1932,7 +1934,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, { int md5_len = 0; unsigned n; - int is_v4 = 0; + int is_v4or5 = 0; int rc = 0; int i, ndata; @@ -1945,8 +1947,8 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, } sig->version = iobuf_get_noeof (inp); pktlen--; - if (sig->version == 4) - is_v4 = 1; + if (sig->version == 4 || sig->version == 5) + is_v4or5 = 1; else if (sig->version != 2 && sig->version != 3) { log_error ("packet(%d) with unknown version %d\n", @@ -1957,7 +1959,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, goto leave; } - if (!is_v4) + if (!is_v4or5) { if (pktlen == 0) goto underflow; @@ -1968,7 +1970,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, goto underflow; sig->sig_class = iobuf_get_noeof (inp); pktlen--; - if (!is_v4) + if (!is_v4or5) { if (pktlen < 12) goto underflow; @@ -1987,7 +1989,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, pktlen--; sig->flags.exportable = 1; sig->flags.revocable = 1; - if (is_v4) /* Read subpackets. */ + if (is_v4or5) /* Read subpackets. */ { if (pktlen < 2) goto underflow; @@ -2058,7 +2060,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, sig->digest_start[1] = iobuf_get_noeof (inp); pktlen--; - if (is_v4 && sig->pubkey_algo) /* Extract required information. */ + if (is_v4or5 && sig->pubkey_algo) /* Extract required information. */ { const byte *p; size_t len; @@ -2076,10 +2078,23 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, && opt.verbose) log_info ("signature packet without timestamp\n"); - p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER); - if (p) - { - sig->keyid[0] = buf32_to_u32 (p); + /* Set the key id. We first try the issuer fingerprint and if + * it is a v4 signature the fallback to the issuer. Note that + * only the issuer packet is also searched in the unhashed area. */ + p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &len); + if (p && len == 21 && p[0] == 4) + { + sig->keyid[0] = buf32_to_u32 (p + 1 + 12); + sig->keyid[1] = buf32_to_u32 (p + 1 + 16); + } + else if (p && len == 33 && p[0] == 5) + { + sig->keyid[0] = buf32_to_u32 (p + 1 ); + sig->keyid[1] = buf32_to_u32 (p + 1 + 4); + } + else if ((p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER))) + { + sig->keyid[0] = buf32_to_u32 (p); sig->keyid[1] = buf32_to_u32 (p + 4); } else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110) @@ -2159,7 +2174,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, (ulong) sig->keyid[0], (ulong) sig->keyid[1], sig->version, (ulong) sig->timestamp, md5_len, sig->sig_class, sig->digest_algo, sig->digest_start[0], sig->digest_start[1]); - if (is_v4) + if (is_v4or5) { parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL); parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL); @@ -2285,6 +2300,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, int npkey, nskey; u32 keyid[2]; PKT_public_key *pk; + int is_v5; + unsigned int pkbytes; /* For v5 keys: Number of bytes in the public + * key material. For v4 keys: 0. */ (void) hdr; @@ -2316,12 +2334,13 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, return 0; } else if (version == 4) - { - /* The only supported version. Use an older gpg - version (i.e. gpg 1.4) to parse v3 packets. */ - } + is_v5 = 0; + else if (version == 5) + is_v5 = 1; else if (version == 2 || version == 3) { + /* Not anymore supported since 2.1. Use an older gpg version + * (i.e. gpg 1.4) to parse v3 packets. */ if (opt.verbose > 1) log_info ("packet(%d) with obsolete version %d\n", pkttype, version); if (list_mode) @@ -2339,7 +2358,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, goto leave; } - if (pktlen < 11) + if (pktlen < (is_v5? 15:11)) { log_error ("packet(%d) too short\n", pkttype); if (list_mode) @@ -2351,7 +2370,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, { log_error ("packet(%d) too large\n", pkttype); if (list_mode) - es_fputs (":key packet: [too larget]\n", listfp); + es_fputs (":key packet: [too large]\n", listfp); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } @@ -2362,14 +2381,28 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, max_expiredate = 0; algorithm = iobuf_get_noeof (inp); pktlen--; + if (is_v5) + { + pkbytes = read_32 (inp); + pktlen -= 4; + } + else + pkbytes = 0; + if (list_mode) - es_fprintf (listfp, ":%s key packet:\n" - "\tversion %d, algo %d, created %lu, expires %lu\n", - pkttype == PKT_PUBLIC_KEY ? "public" : - pkttype == PKT_SECRET_KEY ? "secret" : - pkttype == PKT_PUBLIC_SUBKEY ? "public sub" : - pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??", - version, algorithm, timestamp, expiredate); + { + es_fprintf (listfp, ":%s key packet:\n" + "\tversion %d, algo %d, created %lu, expires %lu", + pkttype == PKT_PUBLIC_KEY ? "public" : + pkttype == PKT_SECRET_KEY ? "secret" : + pkttype == PKT_PUBLIC_SUBKEY ? "public sub" : + pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??", + version, algorithm, timestamp, expiredate); + if (is_v5) + es_fprintf (listfp, ", pkbytes %u\n", pkbytes); + else + es_fprintf (listfp, "\n"); + } pk->timestamp = timestamp; pk->expiredate = expiredate; @@ -2444,6 +2477,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, struct seckey_info *ski; byte temp[16]; size_t snlen = 0; + unsigned int skbytes; if (pktlen < 1) { @@ -2460,23 +2494,42 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, ski->algo = iobuf_get_noeof (inp); pktlen--; + + if (is_v5) + { + unsigned int protcount = 0; + + /* Read the one octet count of the following key-protection + * material. Only required in case of unknown values. */ + if (!pktlen) + { + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + protcount = iobuf_get_noeof (inp); + pktlen--; + if (list_mode) + es_fprintf (listfp, "\tprotbytes: %u\n", protcount); + } + if (ski->algo) { ski->is_protected = 1; ski->s2k.count = 0; if (ski->algo == 254 || ski->algo == 255) { - if (pktlen < 3) + if (pktlen < 3) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - ski->sha1chk = (ski->algo == 254); + + ski->sha1chk = (ski->algo == 254); ski->algo = iobuf_get_noeof (inp); pktlen--; /* Note that a ski->algo > 110 is illegal, but I'm not - erroring on it here as otherwise there would be no - way to delete such a key. */ + * erroring out here as otherwise there would be no way + * to delete such a key. */ ski->s2k.mode = iobuf_get_noeof (inp); pktlen--; ski->s2k.hash_algo = iobuf_get_noeof (inp); @@ -2502,10 +2555,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, } /* Read the salt. */ - switch (ski->s2k.mode) + if (ski->s2k.mode == 3 || ski->s2k.mode == 1) { - case 1: - case 3: for (i = 0; i < 8 && pktlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); if (i < 8) @@ -2514,7 +2565,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, goto leave; } memcpy (ski->s2k.salt, temp, 8); - break; } /* Check the mode. */ @@ -2614,7 +2664,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, * ski->ivlen = cipher_get_blocksize (ski->algo); * won't work. The only solution I see is to hardwire it. * NOTE: if you change the ivlen above 16, don't forget to - * enlarge temp. */ + * enlarge temp. + * FIXME: For v5 keys we can deduce this info! + */ ski->ivlen = openpgp_cipher_blocklen (ski->algo); log_assert (ski->ivlen <= sizeof (temp)); @@ -2642,6 +2694,20 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, memcpy (ski->iv, temp, ski->ivlen); } + /* Skip count of secret key material. */ + if (is_v5) + { + if (pktlen < 4) + { + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + skbytes = read_32 (inp); + pktlen -= 4; + if (list_mode) + es_fprintf (listfp, "\tskbytes: %u\n", skbytes); + } + /* It does not make sense to read it into secure memory. * If the user is so careless, not to protect his secret key, * we can assume, that he operates an open system :=(. @@ -2664,13 +2730,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, /* Ugly: The length is encrypted too, so we read all stuff * up to the end of the packet into the first SKEY - * element. */ + * element. + * FIXME: We can do better for v5 keys. */ pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen), pktlen * 8); /* Mark that MPI as protected - we need this information for - importing a key. The OPAQUE flag can't be used because - we also store public EdDSA values in opaque MPIs. */ + * importing a key. The OPAQUE flag can't be used because + * we also store public EdDSA values in opaque MPIs. */ if (pk->pkey[npkey]) gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1); pktlen = 0; @@ -3180,7 +3247,7 @@ parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen, pt->name[i] = c; } /* Fill up NAME so that a check with valgrind won't complain about - * reading from uninitalized memory. This case may be triggred by + * reading from uninitialized memory. This case may be triggred by * corrupted packets. */ for (; i < namelen; i++) pt->name[i] = 0; @@ -3507,11 +3574,13 @@ create_gpg_control (ctrlpkttype_t type, const byte * data, size_t datalen) PACKET *packet; byte *p; + if (!data) + datalen = 0; + packet = xmalloc (sizeof *packet); init_packet (packet); packet->pkttype = PKT_GPG_CONTROL; - packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control - + datalen - 1); + packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control + datalen); packet->pkt.gpg_control->control = type; packet->pkt.gpg_control->datalen = datalen; p = packet->pkt.gpg_control->data; diff --git a/g10/passphrase.c b/g10/passphrase.c index 10574ec6a..99a2c0dc2 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -48,57 +48,6 @@ static char *next_pw = NULL; static char *last_pw = NULL; - -/* Pack an s2k iteration count into the form specified in 2440. If - we're in between valid values, round up. With value 0 return the - old default. */ -unsigned char -encode_s2k_iterations (int iterations) -{ - gpg_error_t err; - unsigned char c=0; - unsigned char result; - unsigned int count; - - if (!iterations) - { - unsigned long mycnt; - - /* Ask the gpg-agent for a useful iteration count. */ - err = agent_get_s2k_count (&mycnt); - if (err || mycnt < 65536) - { - /* Don't print an error if an older agent is used. */ - if (err && gpg_err_code (err) != GPG_ERR_ASS_PARAMETER) - log_error (_("problem with the agent: %s\n"), gpg_strerror (err)); - /* Default to 65536 which we used up to 2.0.13. */ - return 96; - } - else if (mycnt >= 65011712) - return 255; /* Largest possible value. */ - else - return encode_s2k_iterations ((int)mycnt); - } - - if (iterations <= 1024) - return 0; /* Command line arg compatibility. */ - - if (iterations >= 65011712) - return 255; - - /* Need count to be in the range 16-31 */ - for (count=iterations>>6; count>=32; count>>=1) - c++; - - result = (c<<4)|(count-16); - - if (S2K_DECODE_COUNT(result) < iterations) - result++; - - return result; -} - - int have_static_passphrase() { @@ -106,6 +55,7 @@ have_static_passphrase() && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)); } + /* Return a static passphrase. The returned value is only valid as long as no other passphrase related function is called. NULL may be returned if no passphrase has been set; better use @@ -342,7 +292,7 @@ passphrase_to_dek (int cipher_algo, STRING2KEY *s2k, call out to gpg-agent and that should not be done during option processing in main(). */ if (!opt.s2k_count) - opt.s2k_count = encode_s2k_iterations (0); + opt.s2k_count = encode_s2k_iterations (agent_get_s2k_count ()); s2k->count = opt.s2k_count; } } diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 32b1ed08b..055c39b8f 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -110,6 +110,16 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) continue; } + /* FIXME: The list needs to be sorted so that we try the keys in + * an appropriate order. For example: + * - On-disk keys w/o protection + * - On-disk keys with a cached passphrase + * - On-card keys of an active card + * - On-disk keys with protection + * - On-card keys from cards which are not plugged it. Here a + * cancel-all button should stop asking for other cards. + * Without any anonymous keys the sorting can be skipped. + */ for (k = list; k; k = k->next) { if (!(k->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E @@ -122,6 +132,8 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) if (openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC)) continue; + k->result = GPG_ERR_NO_SECKEY; + if (sk->pubkey_algo != k->pubkey_algo) continue; @@ -129,6 +141,9 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) if (!k->keyid[0] && !k->keyid[1]) { + if (opt.skip_hidden_recipients) + continue; + if (!opt.quiet) log_info (_("anonymous recipient; trying secret key %s ...\n"), keystr (keyid)); @@ -142,6 +157,7 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) rc = get_it (ctrl, k, dek, sk, keyid); if (!rc) { + k->result = 0; if (!opt.quiet && !k->keyid[0] && !k->keyid[1]) log_info (_("okay, we are the anonymous recipient.\n")); search_for_secret_keys = 0; diff --git a/g10/revoke.c b/g10/revoke.c index b778684b0..e8ce3544c 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -277,12 +277,12 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr) fingerprint_from_pk (list->pk, fpr, &fprlen); - /* Don't get involved with keys that don't have 160 - bit fingerprints */ - if(fprlen!=20) + /* Don't get involved with keys that don't have a v4 + * or v5 fingerprint */ + if (fprlen != 20 && fprlen != 32) continue; - if(memcmp(fpr,pk->revkey[i].fpr,20)==0) + if (!memcmp(fpr,pk->revkey[i].fpr, fprlen)) break; } @@ -295,7 +295,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr) { pk2 = xmalloc_clear (sizeof *pk2); rc = get_pubkey_byfprint (ctrl, pk2, NULL, - pk->revkey[i].fpr, MAX_FINGERPRINT_LEN); + pk->revkey[i].fpr, pk->revkey[i].fprlen); } /* We have the revocation key. */ @@ -388,15 +388,18 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr) for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++) { - if(pk->revkey[i].class== - signode->pkt->pkt.signature->revkey[j].class && - pk->revkey[i].algid== - signode->pkt->pkt.signature->revkey[j].algid && - memcmp(pk->revkey[i].fpr, - signode->pkt->pkt.signature->revkey[j].fpr, - MAX_FINGERPRINT_LEN)==0) + if (pk->revkey[i].class + == signode->pkt->pkt.signature->revkey[j].class + && pk->revkey[i].algid + == signode->pkt->pkt.signature->revkey[j].algid + && pk->revkey[i].fprlen + == signode->pkt->pkt.signature->revkey[j].fprlen + && !memcmp + (pk->revkey[i].fpr, + signode->pkt->pkt.signature->revkey[j].fpr, + pk->revkey[i].fprlen)) { - revkey=signode->pkt->pkt.signature; + revkey = signode->pkt->pkt.signature; break; } } diff --git a/g10/seskey.c b/g10/seskey.c index 15490179d..fb71ad5cd 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -95,7 +95,7 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits) output be a multiple of 8 bytes. */ if (openpgp_pk_algo == PUBKEY_ALGO_ECDH) { - /* Pad to 8 byte granulatiry; the padding byte is the number of + /* Pad to 8 byte granularity; the padding byte is the number of * padded bytes. * * A DEK(k bytes) CSUM(2 bytes) 0x 0x 0x 0x ... 0x @@ -143,7 +143,7 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits) * * 0 2 RND(i bytes) 0 A DEK(k bytes) CSUM(2 bytes) * - * (But how can we store the leading 0 - the external representaion + * (But how can we store the leading 0 - the external representation * of MPIs doesn't allow leading zeroes =:-) * * RND are (at least 1) non-zero random bytes. diff --git a/g10/sig-check.c b/g10/sig-check.c index 0ec384347..e7f97de65 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -37,11 +37,14 @@ static int check_signature_end (PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest, + const void *extrahash, size_t extrahashlen, int *r_expired, int *r_revoked, PKT_public_key *ret_pk); static int check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, - gcry_md_hd_t digest); + gcry_md_hd_t digest, + const void *extrahash, + size_t extrahashlen); /* Statistics for signature verification. */ @@ -69,7 +72,7 @@ sig_check_dump_stats (void) int check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest) { - return check_signature2 (ctrl, sig, digest, NULL, NULL, NULL, NULL); + return check_signature2 (ctrl, sig, digest, NULL, 0, NULL, NULL, NULL, NULL); } @@ -95,6 +98,9 @@ check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest) * signature data from the version number through the hashed subpacket * data (inclusive) is hashed.") * + * EXTRAHASH and EXTRAHASHLEN is additional data which is hashed with + * v5 signatures. They may be NULL to use the default. + * * If R_EXPIREDATE is not NULL, R_EXPIREDATE is set to the key's * expiry. * @@ -112,7 +118,9 @@ check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest) * Returns 0 on success. An error code otherwise. */ gpg_error_t check_signature2 (ctrl_t ctrl, - PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate, + PKT_signature *sig, gcry_md_hd_t digest, + const void *extrahash, size_t extrahashlen, + u32 *r_expiredate, int *r_expired, int *r_revoked, PKT_public_key **r_pk) { int rc=0; @@ -179,7 +187,8 @@ check_signature2 (ctrl_t ctrl, if (r_expiredate) *r_expiredate = pk->expiredate; - rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL); + rc = check_signature_end (pk, sig, digest, extrahash, extrahashlen, + r_expired, r_revoked, NULL); /* Check the backsig. This is a back signature (0x19) from * the subkey on the primary key. The idea here is that it @@ -424,6 +433,7 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig, static int check_signature_end (PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest, + const void *extrahash, size_t extrahashlen, int *r_expired, int *r_revoked, PKT_public_key *ret_pk) { int rc = 0; @@ -432,7 +442,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig, r_expired, r_revoked))) return rc; - if ((rc = check_signature_end_simple (pk, sig, digest))) + if ((rc = check_signature_end_simple (pk, sig, digest, + extrahash, extrahashlen))) return rc; if (!rc && ret_pk) @@ -447,7 +458,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig, * expiration, revocation, etc. */ static int check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, - gcry_md_hd_t digest) + gcry_md_hd_t digest, + const void *extrahash, size_t extrahashlen) { gcry_mpi_t result = NULL; int rc = 0; @@ -480,7 +492,8 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, } /* For data signatures check that the key has sign usage. */ - if (IS_SIG (sig) && !(pk->pubkey_usage & PUBKEY_USAGE_SIG)) + if (!IS_BACK_SIG (sig) && IS_SIG (sig) + && !(pk->pubkey_usage & PUBKEY_USAGE_SIG)) { rc = gpg_error (GPG_ERR_WRONG_KEY_USAGE); if (!opt.quiet) @@ -509,8 +522,10 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, } else { - byte buf[6]; + byte buf[10]; + int i; size_t n; + gcry_md_putc (digest, sig->pubkey_algo); gcry_md_putc (digest, sig->digest_algo); if (sig->hashed) @@ -529,14 +544,44 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, gcry_md_putc (digest, 0); n = 6; } - /* add some magic per Section 5.2.4 of RFC 4880. */ - buf[0] = sig->version; - buf[1] = 0xff; - buf[2] = n >> 24; - buf[3] = n >> 16; - buf[4] = n >> 8; - buf[5] = n; - gcry_md_write( digest, buf, 6 ); + /* Hash data from the literal data packet. */ + if (sig->version >= 5 + && (sig->sig_class == 0x00 || sig->sig_class == 0x01)) + { + /* - One octet content format + * - File name (one octet length followed by the name) + * - Four octet timestamp */ + if (extrahash && extrahashlen) + gcry_md_write (digest, extrahash, extrahashlen); + else /* Detached signature. */ + { + memset (buf, 0, 6); + gcry_md_write (digest, buf, 6); + } + } + /* Add some magic per Section 5.2.4 of RFC 4880. */ + i = 0; + buf[i++] = sig->version; + buf[i++] = 0xff; + if (sig->version >= 5) + { +#if SIZEOF_SIZE_T > 4 + buf[i++] = n >> 56; + buf[i++] = n >> 48; + buf[i++] = n >> 40; + buf[i++] = n >> 32; +#else + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; +#endif + } + buf[i++] = n >> 24; + buf[i++] = n >> 16; + buf[i++] = n >> 8; + buf[i++] = n; + gcry_md_write (digest, buf, i); } gcry_md_final( digest ); @@ -571,7 +616,7 @@ hash_uid_packet (PKT_user_id *uid, gcry_md_hd_t md, PKT_signature *sig ) { if (uid->attrib_data) { - if (sig->version >=4) + if (sig->version >= 4) { byte buf[5]; buf[0] = 0xd1; /* packet of type 17 */ @@ -585,7 +630,7 @@ hash_uid_packet (PKT_user_id *uid, gcry_md_hd_t md, PKT_signature *sig ) } else { - if (sig->version >=4) + if (sig->version >= 4) { byte buf[5]; buf[0] = 0xb4; /* indicates a userid packet */ @@ -706,8 +751,8 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig) /* The revoker's keyid. */ u32 keyid[2]; - keyid_from_fingerprint (ctrl, pk->revkey[i].fpr, - MAX_FINGERPRINT_LEN, keyid); + keyid_from_fingerprint (ctrl, pk->revkey[i].fpr, pk->revkey[i].fprlen, + keyid); if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1]) /* The signature was generated by a designated revoker. @@ -762,7 +807,7 @@ check_backsig (PKT_public_key *main_pk,PKT_public_key *sub_pk, { hash_public_key(md,main_pk); hash_public_key(md,sub_pk); - rc = check_signature_end (sub_pk, backsig, md, NULL, NULL, NULL); + rc = check_signature_end (sub_pk, backsig, md, NULL, 0, NULL, NULL, NULL); cache_sig_result(backsig,rc); gcry_md_close(md); } @@ -949,28 +994,28 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer, { log_assert (packet->pkttype == PKT_PUBLIC_KEY); hash_public_key (md, packet->pkt.public_key); - rc = check_signature_end_simple (signer, sig, md); + rc = check_signature_end_simple (signer, sig, md, NULL, 0); } else if (IS_BACK_SIG (sig)) { log_assert (packet->pkttype == PKT_PUBLIC_KEY); hash_public_key (md, packet->pkt.public_key); hash_public_key (md, signer); - rc = check_signature_end_simple (signer, sig, md); + rc = check_signature_end_simple (signer, sig, md, NULL, 0); } else if (IS_SUBKEY_SIG (sig) || IS_SUBKEY_REV (sig)) { log_assert (packet->pkttype == PKT_PUBLIC_SUBKEY); hash_public_key (md, pripk); hash_public_key (md, packet->pkt.public_key); - rc = check_signature_end_simple (signer, sig, md); + rc = check_signature_end_simple (signer, sig, md, NULL, 0); } else if (IS_UID_SIG (sig) || IS_UID_REV (sig)) { log_assert (packet->pkttype == PKT_USER_ID); hash_public_key (md, pripk); hash_uid_packet (packet->pkt.user_id, md, sig); - rc = check_signature_end_simple (signer, sig, md); + rc = check_signature_end_simple (signer, sig, md, NULL, 0); } else { diff --git a/g10/sign.c b/g10/sign.c index 581a08f5b..176940bff 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -49,10 +49,23 @@ #define LF "\n" #endif -static int recipient_digest_algo=0; +/* Hack */ +static int recipient_digest_algo; -/**************** - * Create notations and other stuff. It is assumed that the stings in + +/* A type for the extra data we hash into v5 signature packets. */ +struct pt_extra_hash_data_s +{ + unsigned char mode; + u32 timestamp; + unsigned char namelen; + char name[1]; +}; +typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t; + + +/* + * Create notations and other stuff. It is assumed that the strings in * STRLIST are already checked to contain only printable data and have * a valid NAME=VALUE format. */ @@ -152,7 +165,8 @@ mk_notation_policy_etc (PKT_signature *sig, char *mbox; /* For now we use the uid which was used to locate the key. */ - if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name))) + if (pksk->user_id + && (mbox = mailbox_from_userid (pksk->user_id->name, 0))) { if (DBG_LOOKUP) log_debug ("setting Signer's UID to '%s'\n", mbox); @@ -214,12 +228,16 @@ hash_uid (gcry_md_hd_t md, int sigversion, const PKT_user_id *uid) /* - * Helper to hash some parts from the signature + * Helper to hash some parts from the signature. EXTRAHASH gives the + * extra data to be hashed into v5 signatures; it may by NULL for + * detached signatures. */ static void -hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig) +hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig, + pt_extra_hash_data_t extrahash) { - byte buf[6]; + byte buf[10]; + int i; size_t n; gcry_md_putc (md, sig->version); @@ -240,14 +258,49 @@ hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig) gcry_md_putc (md, 0); n = 6; } + /* Hash data from the literal data packet. */ + if (sig->version >= 5 && (sig->sig_class == 0x00 || sig->sig_class == 0x01)) + { + /* - One octet content format + * - File name (one octet length followed by the name) + * - Four octet timestamp */ + if (extrahash) + { + buf[0] = extrahash->mode; + buf[1] = extrahash->namelen; + gcry_md_write (md, buf, 2); + if (extrahash->namelen) + gcry_md_write (md, extrahash->name, extrahash->namelen); + buf[0] = extrahash->timestamp >> 24; + buf[1] = extrahash->timestamp >> 16; + buf[2] = extrahash->timestamp >> 8; + buf[3] = extrahash->timestamp; + gcry_md_write (md, buf, 4); + } + else /* Detached signatures */ + { + memset (buf, 0, 6); + gcry_md_write (md, buf, 6); + } + } /* Add some magic. */ - buf[0] = sig->version; - buf[1] = 0xff; - buf[2] = n >> 24; /* (n is only 16 bit, so this is always 0) */ - buf[3] = n >> 16; - buf[4] = n >> 8; - buf[5] = n; - gcry_md_write (md, buf, 6); + i = 0; + buf[i++] = sig->version; + buf[i++] = 0xff; + if (sig->version >= 5) + { + /* Note: We don't hashed any data larger than 2^32 and thus we + * can always use 0 here. See also note below. */ + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + buf[i++] = 0; + } + buf[i++] = n >> 24; /* (n is only 16 bit, so this is always 0) */ + buf[i++] = n >> 16; + buf[i++] = n >> 8; + buf[i++] = n; + gcry_md_write (md, buf, i); } @@ -574,136 +627,173 @@ print_status_sig_created (PKT_public_key *pk, PKT_signature *sig, int what) * Loop over the secret certificates in SK_LIST and build the one pass * signature packets. OpenPGP says that the data should be bracket by * the onepass-sig and signature-packet; so we build these onepass - * packet here in reverse order + * packet here in reverse order. */ static int write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass ) { - int skcount; - SK_LIST sk_rover; + int skcount; + SK_LIST sk_rover; - for (skcount=0, sk_rover=sk_list; sk_rover; sk_rover = sk_rover->next) - skcount++; + for (skcount=0, sk_rover=sk_list; sk_rover; sk_rover = sk_rover->next) + skcount++; - for (; skcount; skcount--) { - PKT_public_key *pk; - PKT_onepass_sig *ops; - PACKET pkt; - int i, rc; + for (; skcount; skcount--) + { + PKT_public_key *pk; + PKT_onepass_sig *ops; + PACKET pkt; + int i, rc; - for (i=0, sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { - if (++i == skcount) - break; - } + for (i=0, sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) + if (++i == skcount) + break; - pk = sk_rover->pk; - ops = xmalloc_clear (sizeof *ops); - ops->sig_class = sigclass; - ops->digest_algo = hash_for (pk); - ops->pubkey_algo = pk->pubkey_algo; - keyid_from_pk (pk, ops->keyid); - ops->last = (skcount == 1); - - init_packet(&pkt); - pkt.pkttype = PKT_ONEPASS_SIG; - pkt.pkt.onepass_sig = ops; - rc = build_packet (out, &pkt); - free_packet (&pkt, NULL); - if (rc) { - log_error ("build onepass_sig packet failed: %s\n", - gpg_strerror (rc)); - return rc; + pk = sk_rover->pk; + ops = xmalloc_clear (sizeof *ops); + ops->sig_class = sigclass; + ops->digest_algo = hash_for (pk); + ops->pubkey_algo = pk->pubkey_algo; + keyid_from_pk (pk, ops->keyid); + ops->last = (skcount == 1); + + init_packet (&pkt); + pkt.pkttype = PKT_ONEPASS_SIG; + pkt.pkt.onepass_sig = ops; + rc = build_packet (out, &pkt); + free_packet (&pkt, NULL); + if (rc) + { + log_error ("build onepass_sig packet failed: %s\n", + gpg_strerror (rc)); + return rc; } } - return 0; + return 0; } + /* - * Helper to write the plaintext (literal data) packet + * Helper to write the plaintext (literal data) packet. At + * R_EXTRAHASH a malloced object with the with the extra data hashed + * into v5 signatures is stored. */ static int -write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode) +write_plaintext_packet (iobuf_t out, iobuf_t inp, + const char *fname, int ptmode, + pt_extra_hash_data_t *r_extrahash) { - PKT_plaintext *pt = NULL; - u32 filesize; - int rc = 0; + PKT_plaintext *pt = NULL; + u32 filesize; + int rc = 0; - if (!opt.no_literal) - pt=setup_plaintext_name(fname,inp); + if (!opt.no_literal) + pt = setup_plaintext_name (fname, inp); - /* try to calculate the length of the data */ - if ( !iobuf_is_pipe_filename (fname) && *fname ) - { - off_t tmpsize; - int overflow; - - if( !(tmpsize = iobuf_get_filelength(inp, &overflow)) - && !overflow && opt.verbose) - log_info (_("WARNING: '%s' is an empty file\n"), fname); - - /* We can't encode the length of very large files because - OpenPGP uses only 32 bit for file sizes. So if the size of - a file is larger than 2^32 minus some bytes for packet - headers, we switch to partial length encoding. */ - if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) ) - filesize = tmpsize; - else - filesize = 0; - - /* Because the text_filter modifies the length of the - * data, it is not possible to know the used length - * without a double read of the file - to avoid that - * we simple use partial length packets. */ - if ( ptmode == 't' || ptmode == 'u' || ptmode == 'm') - filesize = 0; - } - else - filesize = opt.set_filesize? opt.set_filesize : 0; /* stdin */ - - if (!opt.no_literal) { - PACKET pkt; - - /* Note that PT has been initialized above in no_literal mode. */ - pt->timestamp = make_timestamp (); - pt->mode = ptmode; - pt->len = filesize; - pt->new_ctb = !pt->len; - pt->buf = inp; - init_packet(&pkt); - pkt.pkttype = PKT_PLAINTEXT; - pkt.pkt.plaintext = pt; - /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/ - if( (rc = build_packet (out, &pkt)) ) - log_error ("build_packet(PLAINTEXT) failed: %s\n", - gpg_strerror (rc) ); - pt->buf = NULL; - free_packet (&pkt, NULL); + /* Try to calculate the length of the data. */ + if ( !iobuf_is_pipe_filename (fname) && *fname) + { + off_t tmpsize; + int overflow; + + if (!(tmpsize = iobuf_get_filelength (inp, &overflow)) + && !overflow && opt.verbose) + log_info (_("WARNING: '%s' is an empty file\n"), fname); + + /* We can't encode the length of very large files because + * OpenPGP uses only 32 bit for file sizes. So if the size of a + * file is larger than 2^32 minus some bytes for packet headers, + * we switch to partial length encoding. */ + if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536)) + filesize = tmpsize; + else + filesize = 0; + + /* Because the text_filter modifies the length of the + * data, it is not possible to know the used length + * without a double read of the file - to avoid that + * we simple use partial length packets. */ + if (ptmode == 't' || ptmode == 'u' || ptmode == 'm') + filesize = 0; } - else { - byte copy_buffer[4096]; - int bytes_copied; - - while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1) - if ( (rc=iobuf_write(out, copy_buffer, bytes_copied)) ) { - log_error ("copying input to output failed: %s\n", - gpg_strerror (rc)); - break; - } - wipememory(copy_buffer,4096); /* burn buffer */ + else + filesize = opt.set_filesize? opt.set_filesize : 0; /* stdin */ + + if (!opt.no_literal) + { + PACKET pkt; + + /* Note that PT has been initialized above in no_literal mode. */ + pt->timestamp = make_timestamp (); + pt->mode = ptmode; + pt->len = filesize; + pt->new_ctb = !pt->len; + pt->buf = inp; + init_packet (&pkt); + pkt.pkttype = PKT_PLAINTEXT; + pkt.pkt.plaintext = pt; + /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/ + if ((rc = build_packet (out, &pkt))) + log_error ("build_packet(PLAINTEXT) failed: %s\n", + gpg_strerror (rc) ); + + *r_extrahash = xtrymalloc (sizeof **r_extrahash + pt->namelen); + if (!*r_extrahash) + rc = gpg_error_from_syserror (); + else + { + (*r_extrahash)->mode = pt->mode; + (*r_extrahash)->timestamp = pt->timestamp; + (*r_extrahash)->namelen = pt->namelen; + /* Note that the last byte of NAME won't be initialized + * because we don't need it. */ + memcpy ((*r_extrahash)->name, pt->name, pt->namelen); + } + pt->buf = NULL; + free_packet (&pkt, NULL); } - /* fixme: it seems that we never freed pt/pkt */ + else + { + byte copy_buffer[4096]; + int bytes_copied; - return rc; + *r_extrahash = xtrymalloc (sizeof **r_extrahash); + if (!*r_extrahash) + { + rc = gpg_error_from_syserror (); + goto leave; + } + /* FIXME: We need to parse INP to get the to be hashed data from + * it. */ + (*r_extrahash)->mode = 0; + (*r_extrahash)->timestamp = 0; + (*r_extrahash)->namelen = 0; + + while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1) + if ((rc = iobuf_write (out, copy_buffer, bytes_copied))) + { + log_error ("copying input to output failed: %s\n", + gpg_strerror (rc)); + break; + } + wipememory (copy_buffer, 4096); /* burn buffer */ + } + + leave: + return rc; } + /* - * Write the signatures from the SK_LIST to OUT. HASH must be a non-finalized - * hash which will not be changes here. + * Write the signatures from the SK_LIST to OUT. HASH must be a + * non-finalized hash which will not be changes here. EXTRAHASH is + * either NULL or the extra data tro be hashed into v5 signatures. */ static int write_signature_packets (ctrl_t ctrl, SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash, + pt_extra_hash_data_t extrahash, int sigclass, u32 timestamp, u32 duration, int status_letter, const char *cache_nonce) { @@ -724,11 +814,10 @@ write_signature_packets (ctrl_t ctrl, if (!sig) return gpg_error_from_syserror (); - if (duration || opt.sig_policy_url - || opt.sig_notations || opt.sig_keyserver_url) - sig->version = 4; + if (pk->version >= 5) + sig->version = 5; /* Required for v5 keys. */ else - sig->version = pk->version; + sig->version = 4; /* Required. */ keyid_from_pk (pk, sig->keyid); sig->digest_algo = hash_for (pk); @@ -744,13 +833,9 @@ write_signature_packets (ctrl_t ctrl, if (gcry_md_copy (&md, hash)) BUG (); - if (sig->version >= 4) - { - build_sig_subpkt_from_sig (sig, pk); - mk_notation_policy_etc (sig, NULL, pk); - } - - hash_sigversion_to_magic (md, sig); + build_sig_subpkt_from_sig (sig, pk); + mk_notation_policy_etc (sig, NULL, pk); + hash_sigversion_to_magic (md, sig, extrahash); gcry_md_final (md); rc = do_sign (ctrl, pk, sig, md, hash_for (pk), cache_nonce); @@ -782,7 +867,7 @@ write_signature_packets (ctrl_t ctrl, } -/**************** +/* * Sign the files whose names are in FILENAME. * If DETACHED has the value true, * make a detached signature. If FILENAMES->d is NULL read from stdin @@ -798,62 +883,66 @@ int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int encryptflag, strlist_t remusr, const char *outfile ) { - const char *fname; - armor_filter_context_t *afx; - compress_filter_context_t zfx; - md_filter_context_t mfx; - text_filter_context_t tfx; - progress_filter_context_t *pfx; - encrypt_filter_context_t efx; - IOBUF inp = NULL, out = NULL; - PACKET pkt; - int rc = 0; - PK_LIST pk_list = NULL; - SK_LIST sk_list = NULL; - SK_LIST sk_rover = NULL; - int multifile = 0; - u32 duration=0; - - pfx = new_progress_context (); - afx = new_armor_context (); - memset( &zfx, 0, sizeof zfx); - memset( &mfx, 0, sizeof mfx); - memset( &efx, 0, sizeof efx); - efx.ctrl = ctrl; - init_packet( &pkt ); - - if( filenames ) { - fname = filenames->d; - multifile = !!filenames->next; + const char *fname; + armor_filter_context_t *afx; + compress_filter_context_t zfx; + md_filter_context_t mfx; + text_filter_context_t tfx; + progress_filter_context_t *pfx; + encrypt_filter_context_t efx; + iobuf_t inp = NULL; + iobuf_t out = NULL; + PACKET pkt; + int rc = 0; + PK_LIST pk_list = NULL; + SK_LIST sk_list = NULL; + SK_LIST sk_rover = NULL; + int multifile = 0; + u32 duration=0; + pt_extra_hash_data_t extrahash = NULL; + + pfx = new_progress_context (); + afx = new_armor_context (); + memset (&zfx, 0, sizeof zfx); + memset (&mfx, 0, sizeof mfx); + memset (&efx, 0, sizeof efx); + efx.ctrl = ctrl; + init_packet (&pkt); + + if (filenames) + { + fname = filenames->d; + multifile = !!filenames->next; } - else - fname = NULL; + else + fname = NULL; - if( fname && filenames->next && (!detached || encryptflag) ) - log_bug("multiple files can only be detached signed"); + if (fname && filenames->next && (!detached || encryptflag)) + log_bug ("multiple files can only be detached signed"); - if(encryptflag==2 - && (rc=setup_symkey(&efx.symkey_s2k,&efx.symkey_dek))) - goto leave; + if (encryptflag == 2 + && (rc = setup_symkey (&efx.symkey_s2k, &efx.symkey_dek))) + goto leave; - if (opt.ask_sig_expire && !opt.batch) - duration = ask_expire_interval(1,opt.def_sig_expire); - else - duration = parse_expire_string(opt.def_sig_expire); + if (opt.ask_sig_expire && !opt.batch) + duration = ask_expire_interval(1,opt.def_sig_expire); + else + duration = parse_expire_string(opt.def_sig_expire); - /* Note: In the old non-agent version the following call used to - unprotect the secret key. This is now done on demand by the agent. */ - if( (rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) ) - goto leave; + /* Note: In the old non-agent version the following call used to + * unprotect the secret key. This is now done on demand by the agent. */ + if ((rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG ))) + goto leave; - if (encryptflag - && (rc=build_pk_list (ctrl, remusr, &pk_list))) - goto leave; + if (encryptflag + && (rc = build_pk_list (ctrl, remusr, &pk_list))) + goto leave; - /* prepare iobufs */ - if( multifile ) /* have list of filenames */ - inp = NULL; /* we do it later */ - else { + /* Prepare iobufs. */ + if (multifile) /* have list of filenames */ + inp = NULL; /* we do it later */ + else + { inp = iobuf_open(fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { @@ -861,407 +950,437 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, inp = NULL; gpg_err_set_errno (EPERM); } - if( !inp ) + if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", - strerror(errno) ); + strerror (errno)); goto leave; } - handle_progress (pfx, inp, fname); + handle_progress (pfx, inp, fname); } - if( outfile ) { - if (is_secured_filename ( outfile )) { - out = NULL; - gpg_err_set_errno (EPERM); + if (outfile) + { + if (is_secured_filename (outfile)) + { + out = NULL; + gpg_err_set_errno (EPERM); } - else - out = iobuf_create (outfile, 0); - if( !out ) - { - rc = gpg_error_from_syserror (); - log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) ); - goto leave; - } - else if( opt.verbose ) - log_info(_("writing to '%s'\n"), outfile ); + else + out = iobuf_create (outfile, 0); + if (!out) + { + rc = gpg_error_from_syserror (); + log_error (_("can't create '%s': %s\n"), outfile, gpg_strerror (rc)); + goto leave; + } + else if (opt.verbose) + log_info (_("writing to '%s'\n"), outfile); + } + else if ((rc = open_outfile (-1, fname, + opt.armor? 1 : detached? 2 : 0, 0, &out))) + { + goto leave; } - else if( (rc = open_outfile (-1, fname, - opt.armor? 1: detached? 2:0, 0, &out))) - goto leave; - /* prepare to calculate the MD over the input */ - if( opt.textmode && !outfile && !multifile ) - { - memset( &tfx, 0, sizeof tfx); - iobuf_push_filter( inp, text_filter, &tfx ); - } + /* Prepare to calculate the MD over the input. */ + if (opt.textmode && !outfile && !multifile) + { + memset (&tfx, 0, sizeof tfx); + iobuf_push_filter (inp, text_filter, &tfx); + } - if ( gcry_md_open (&mfx.md, 0, 0) ) - BUG (); - if (DBG_HASHING) - gcry_md_debug (mfx.md, "sign"); - - /* If we're encrypting and signing, it is reasonable to pick the - hash algorithm to use out of the recipient key prefs. This is - best effort only, as in a DSA2 and smartcard world there are - cases where we cannot please everyone with a single hash (DSA2 - wants >160 and smartcards want =160). In the future this could - be more complex with different hashes for each sk, but the - current design requires a single hash for all SKs. */ - if(pk_list) - { - if(opt.def_digest_algo) - { - if(!opt.expert && - select_algo_from_prefs(pk_list,PREFTYPE_HASH, - opt.def_digest_algo, - NULL)!=opt.def_digest_algo) - log_info(_("WARNING: forcing digest algorithm %s (%d)" - " violates recipient preferences\n"), - gcry_md_algo_name (opt.def_digest_algo), - opt.def_digest_algo ); - } - else - { - int algo, smartcard=0; - union pref_hint hint; - - hint.digest_length = 0; - - /* Of course, if the recipient asks for something - unreasonable (like the wrong hash for a DSA key) then - don't do it. Check all sk's - if any are DSA or live - on a smartcard, then the hash has restrictions and we - may not be able to give the recipient what they want. - For DSA, pass a hint for the largest q we have. Note - that this means that a q>160 key will override a q=160 - key and force the use of truncation for the q=160 key. - The alternative would be to ignore the recipient prefs - completely and get a different hash for each DSA key in - hash_for(). The override behavior here is more or less - reasonable as it is under the control of the user which - keys they sign with for a given message and the fact - that the message with multiple signatures won't be - usable on an implementation that doesn't understand - DSA2 anyway. */ - - for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) - { - if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA - || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) - { - int temp_hashlen = (gcry_mpi_get_nbits - (sk_rover->pk->pkey[1])); - - if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) - temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen); - temp_hashlen = (temp_hashlen+7)/8; - - /* Pick a hash that is large enough for our - largest q */ - - if (hint.digest_length<temp_hashlen) - hint.digest_length=temp_hashlen; - } - /* FIXME: need to check gpg-agent for this. */ - /* else if (sk_rover->pk->is_protected */ - /* && sk_rover->pk->protect.s2k.mode == 1002) */ - /* smartcard = 1; */ - } - - /* Current smartcards only do 160-bit hashes. If we have - to have a >160-bit hash, then we can't use the - recipient prefs as we'd need both =160 and >160 at the - same time and recipient prefs currently require a - single hash for all signatures. All this may well have - to change as the cards add algorithms. */ - - if (!smartcard || (smartcard && hint.digest_length==20)) - if ( (algo= - select_algo_from_prefs(pk_list,PREFTYPE_HASH,-1,&hint)) > 0) - recipient_digest_algo=algo; - } - } + if (gcry_md_open (&mfx.md, 0, 0)) + BUG (); + if (DBG_HASHING) + gcry_md_debug (mfx.md, "sign"); + + /* If we're encrypting and signing, it is reasonable to pick the + * hash algorithm to use out of the recipient key prefs. This is + * best effort only, as in a DSA2 and smartcard world there are + * cases where we cannot please everyone with a single hash (DSA2 + * wants >160 and smartcards want =160). In the future this could + * be more complex with different hashes for each sk, but the + * current design requires a single hash for all SKs. */ + if (pk_list) + { + if (opt.def_digest_algo) + { + if (!opt.expert + && select_algo_from_prefs (pk_list,PREFTYPE_HASH, + opt.def_digest_algo, + NULL) != opt.def_digest_algo) + { + log_info (_("WARNING: forcing digest algorithm %s (%d)" + " violates recipient preferences\n"), + gcry_md_algo_name (opt.def_digest_algo), + opt.def_digest_algo); + } + } + else + { + int algo; + int smartcard=0; + union pref_hint hint; + + hint.digest_length = 0; + + /* Of course, if the recipient asks for something + * unreasonable (like the wrong hash for a DSA key) then + * don't do it. Check all sk's - if any are DSA or live + * on a smartcard, then the hash has restrictions and we + * may not be able to give the recipient what they want. + * For DSA, pass a hint for the largest q we have. Note + * that this means that a q>160 key will override a q=160 + * key and force the use of truncation for the q=160 key. + * The alternative would be to ignore the recipient prefs + * completely and get a different hash for each DSA key in + * hash_for(). The override behavior here is more or less + * reasonable as it is under the control of the user which + * keys they sign with for a given message and the fact + * that the message with multiple signatures won't be + * usable on an implementation that doesn't understand + * DSA2 anyway. */ + for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) + { + if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA + || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) + { + int temp_hashlen = gcry_mpi_get_nbits (sk_rover->pk->pkey[1]); + + if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) + temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen); + + temp_hashlen = (temp_hashlen+7)/8; + + /* Pick a hash that is large enough for our largest Q */ + if (hint.digest_length < temp_hashlen) + hint.digest_length = temp_hashlen; + } + /* FIXME: need to check gpg-agent for this. */ + /* else if (sk_rover->pk->is_protected */ + /* && sk_rover->pk->protect.s2k.mode == 1002) */ + /* smartcard = 1; */ + } - for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) - gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); + /* Current smartcards only do 160-bit hashes. If we have + * to have a >160-bit hash, then we can't use the + * recipient prefs as we'd need both =160 and >160 at the + * same time and recipient prefs currently require a + * single hash for all signatures. All this may well have + * to change as the cards add algorithms. */ + if ((!smartcard || (smartcard && hint.digest_length==20)) + && ((algo = select_algo_from_prefs (pk_list, PREFTYPE_HASH, + -1, &hint)) > 0)) + { + recipient_digest_algo = algo; + } + } + } + + for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) + gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); - if( !multifile ) - iobuf_push_filter( inp, md_filter, &mfx ); + if (!multifile) + iobuf_push_filter (inp, md_filter, &mfx); - if( detached && !encryptflag) - afx->what = 2; + if (detached && !encryptflag) + afx->what = 2; - if( opt.armor && !outfile ) - push_armor_filter (afx, out); + if (opt.armor && !outfile) + push_armor_filter (afx, out); - if( encryptflag ) { - efx.pk_list = pk_list; - /* fixme: set efx.cfx.datalen if known */ - iobuf_push_filter( out, encrypt_filter, &efx ); + if (encryptflag) + { + efx.pk_list = pk_list; + /* fixme: set efx.cfx.datalen if known */ + iobuf_push_filter (out, encrypt_filter, &efx); } - if (opt.compress_algo && !outfile && !detached) - { - int compr_algo=opt.compress_algo; - - /* If not forced by user */ - if(compr_algo==-1) - { - /* If we're not encrypting, then select_algo_from_prefs - will fail and we'll end up with the default. If we are - encrypting, select_algo_from_prefs cannot fail since - there is an assumed preference for uncompressed data. - Still, if it did fail, we'll also end up with the - default. */ - - if((compr_algo= - select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1) - compr_algo=default_compress_algo(); - } - else if(!opt.expert && pk_list - && select_algo_from_prefs(pk_list,PREFTYPE_ZIP, - compr_algo,NULL)!=compr_algo) - log_info(_("WARNING: forcing compression algorithm %s (%d)" - " violates recipient preferences\n"), - compress_algo_to_string(compr_algo),compr_algo); - - /* algo 0 means no compression */ - if( compr_algo ) - push_compress_filter(out,&zfx,compr_algo); - } + if (opt.compress_algo && !outfile && !detached) + { + int compr_algo = opt.compress_algo; - /* Write the one-pass signature packets if needed */ - if (!detached) { - rc = write_onepass_sig_packets (sk_list, out, - opt.textmode && !outfile ? 0x01:0x00); - if (rc) - goto leave; + /* If not forced by user */ + if (compr_algo==-1) + { + /* If we're not encrypting, then select_algo_from_prefs + * will fail and we'll end up with the default. If we are + * encrypting, select_algo_from_prefs cannot fail since + * there is an assumed preference for uncompressed data. + * Still, if it did fail, we'll also end up with the + * default. */ + if ((compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, + -1, NULL)) == -1) + { + compr_algo = default_compress_algo(); + } + } + else if (!opt.expert && pk_list + && select_algo_from_prefs (pk_list, PREFTYPE_ZIP, + compr_algo, NULL) != compr_algo) + { + log_info (_("WARNING: forcing compression algorithm %s (%d)" + " violates recipient preferences\n"), + compress_algo_to_string (compr_algo), compr_algo); + } + + /* Algo 0 means no compression. */ + if (compr_algo) + push_compress_filter (out, &zfx, compr_algo); + } + + /* Write the one-pass signature packets if needed */ + if (!detached) + { + rc = write_onepass_sig_packets (sk_list, out, + opt.textmode && !outfile ? 0x01:0x00); + if (rc) + goto leave; } - write_status_begin_signing (mfx.md); - - /* Setup the inner packet. */ - if( detached ) { - if( multifile ) { - strlist_t sl; - - if( opt.verbose ) - log_info(_("signing:") ); - /* must walk reverse trough this list */ - for( sl = strlist_last(filenames); sl; - sl = strlist_prev( filenames, sl ) ) { - inp = iobuf_open(sl->d); - if (inp && is_secured_file (iobuf_get_fd (inp))) - { - iobuf_close (inp); - inp = NULL; - gpg_err_set_errno (EPERM); - } - if( !inp ) - { - rc = gpg_error_from_syserror (); - log_error(_("can't open '%s': %s\n"), - sl->d,strerror(errno)); - goto leave; - } - handle_progress (pfx, inp, sl->d); - if( opt.verbose ) - log_printf (" '%s'", sl->d ); - if(opt.textmode) - { - memset( &tfx, 0, sizeof tfx); - iobuf_push_filter( inp, text_filter, &tfx ); - } - iobuf_push_filter( inp, md_filter, &mfx ); - while( iobuf_get(inp) != -1 ) - ; - iobuf_close(inp); inp = NULL; + write_status_begin_signing (mfx.md); + + /* Setup the inner packet. */ + if (detached) + { + if (multifile) + { + strlist_t sl; + + if (opt.verbose) + log_info (_("signing:") ); + /* Must walk reverse trough this list. */ + for (sl = strlist_last(filenames); + sl; + sl = strlist_prev( filenames, sl)) + { + inp = iobuf_open (sl->d); + if (inp && is_secured_file (iobuf_get_fd (inp))) + { + iobuf_close (inp); + inp = NULL; + gpg_err_set_errno (EPERM); + } + if (!inp) + { + rc = gpg_error_from_syserror (); + log_error (_("can't open '%s': %s\n"), + sl->d, gpg_strerror (rc)); + goto leave; + } + handle_progress (pfx, inp, sl->d); + if (opt.verbose) + log_printf (" '%s'", sl->d ); + if (opt.textmode) + { + memset (&tfx, 0, sizeof tfx); + iobuf_push_filter (inp, text_filter, &tfx); + } + iobuf_push_filter (inp, md_filter, &mfx); + while (iobuf_get (inp) != -1) + ; + iobuf_close (inp); + inp = NULL; } - if( opt.verbose ) - log_printf ("\n"); + if (opt.verbose) + log_printf ("\n"); } - else { - /* read, so that the filter can calculate the digest */ - while( iobuf_get(inp) != -1 ) - ; + else + { + /* Read, so that the filter can calculate the digest. */ + while (iobuf_get(inp) != -1) + ; } } - else { - rc = write_plaintext_packet (out, inp, fname, - opt.textmode && !outfile ? - (opt.mimemode? 'm':'t'):'b'); + else + { + rc = write_plaintext_packet (out, inp, fname, + (opt.textmode && !outfile) ? + (opt.mimemode? 'm' : 't') : 'b', + &extrahash); } - /* catch errors from above */ - if (rc) - goto leave; + /* Catch errors from above. */ + if (rc) + goto leave; - /* write the signatures */ - rc = write_signature_packets (ctrl, sk_list, out, mfx.md, - opt.textmode && !outfile? 0x01 : 0x00, - 0, duration, detached ? 'D':'S', NULL); - if( rc ) - goto leave; + /* Write the signatures. */ + rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash, + opt.textmode && !outfile? 0x01 : 0x00, + 0, duration, detached ? 'D':'S', NULL); + if (rc) + goto leave; - leave: - if( rc ) - iobuf_cancel(out); - else { - iobuf_close(out); - if (encryptflag) - write_status( STATUS_END_ENCRYPTION ); + leave: + if (rc) + iobuf_cancel (out); + else + { + iobuf_close (out); + if (encryptflag) + write_status (STATUS_END_ENCRYPTION); } - iobuf_close(inp); - gcry_md_close ( mfx.md ); - release_sk_list( sk_list ); - release_pk_list( pk_list ); - recipient_digest_algo=0; - release_progress_context (pfx); - release_armor_context (afx); - return rc; + iobuf_close (inp); + gcry_md_close (mfx.md); + release_sk_list (sk_list); + release_pk_list (pk_list); + recipient_digest_algo = 0; + release_progress_context (pfx); + release_armor_context (afx); + xfree (extrahash); + return rc; } - -/**************** - * make a clear signature. note that opt.armor is not needed +/* + * Make a clear signature. Note that opt.armor is not needed. */ int clearsign_file (ctrl_t ctrl, - const char *fname, strlist_t locusr, const char *outfile ) + const char *fname, strlist_t locusr, const char *outfile) { - armor_filter_context_t *afx; - progress_filter_context_t *pfx; - gcry_md_hd_t textmd = NULL; - IOBUF inp = NULL, out = NULL; - PACKET pkt; - int rc = 0; - SK_LIST sk_list = NULL; - SK_LIST sk_rover = NULL; - u32 duration=0; - - pfx = new_progress_context (); - afx = new_armor_context (); - init_packet( &pkt ); - - if (opt.ask_sig_expire && !opt.batch) - duration = ask_expire_interval (1,opt.def_sig_expire); - else - duration = parse_expire_string (opt.def_sig_expire); - - /* Note: In the old non-agent version the following call used to - unprotect the secret key. This is now done on demand by the agent. */ - if( (rc=build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) ) - goto leave; - - /* prepare iobufs */ - inp = iobuf_open(fname); - if (inp && is_secured_file (iobuf_get_fd (inp))) - { - iobuf_close (inp); - inp = NULL; - gpg_err_set_errno (EPERM); - } - if( !inp ) { - rc = gpg_error_from_syserror (); - log_error (_("can't open '%s': %s\n"), - fname? fname: "[stdin]", strerror(errno) ); - goto leave; + armor_filter_context_t *afx; + progress_filter_context_t *pfx; + gcry_md_hd_t textmd = NULL; + iobuf_t inp = NULL; + iobuf_t out = NULL; + PACKET pkt; + int rc = 0; + SK_LIST sk_list = NULL; + SK_LIST sk_rover = NULL; + u32 duration = 0; + + pfx = new_progress_context (); + afx = new_armor_context (); + init_packet( &pkt ); + + if (opt.ask_sig_expire && !opt.batch) + duration = ask_expire_interval (1, opt.def_sig_expire); + else + duration = parse_expire_string (opt.def_sig_expire); + + /* Note: In the old non-agent version the following call used to + * unprotect the secret key. This is now done on demand by the agent. */ + if ((rc=build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG))) + goto leave; + + /* Prepare iobufs. */ + inp = iobuf_open (fname); + if (inp && is_secured_file (iobuf_get_fd (inp))) + { + iobuf_close (inp); + inp = NULL; + gpg_err_set_errno (EPERM); + } + if (!inp) + { + rc = gpg_error_from_syserror (); + log_error (_("can't open '%s': %s\n"), + fname? fname: "[stdin]", gpg_strerror (rc)); + goto leave; } - handle_progress (pfx, inp, fname); + handle_progress (pfx, inp, fname); - if( outfile ) { - if (is_secured_filename (outfile) ) { - outfile = NULL; - gpg_err_set_errno (EPERM); + if (outfile) + { + if (is_secured_filename (outfile)) + { + outfile = NULL; + gpg_err_set_errno (EPERM); } - else - out = iobuf_create (outfile, 0); - if( !out ) - { - rc = gpg_error_from_syserror (); - log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) ); - goto leave; - } - else if( opt.verbose ) - log_info(_("writing to '%s'\n"), outfile ); - } - else if ((rc = open_outfile (-1, fname, 1, 0, &out))) - goto leave; + else + out = iobuf_create (outfile, 0); - iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----" LF ); + if (!out) + { + rc = gpg_error_from_syserror (); + log_error (_("can't create '%s': %s\n"), outfile, gpg_strerror (rc)); + goto leave; + } + else if (opt.verbose) + log_info (_("writing to '%s'\n"), outfile); + } + else if ((rc = open_outfile (-1, fname, 1, 0, &out))) { - const char *s; - int any = 0; - byte hashs_seen[256]; - - memset( hashs_seen, 0, sizeof hashs_seen ); - iobuf_writestr(out, "Hash: " ); - for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { - int i = hash_for (sk_rover->pk); - - if( !hashs_seen[ i & 0xff ] ) { - s = gcry_md_algo_name ( i ); - if( s ) { - hashs_seen[ i & 0xff ] = 1; - if( any ) - iobuf_put(out, ',' ); - iobuf_writestr(out, s ); - any = 1; - } - } - } - log_assert(any); - iobuf_writestr(out, LF ); + goto leave; } - if( opt.not_dash_escaped ) - iobuf_writestr( out, - "NotDashEscaped: You need "GPG_NAME - " to verify this message" LF ); - iobuf_writestr(out, LF ); + iobuf_writestr (out, "-----BEGIN PGP SIGNED MESSAGE-----" LF); - if ( gcry_md_open (&textmd, 0, 0) ) - BUG (); + { + const char *s; + int any = 0; + byte hashs_seen[256]; + + memset (hashs_seen, 0, sizeof hashs_seen); + iobuf_writestr (out, "Hash: " ); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) - gcry_md_enable (textmd, hash_for(sk_rover->pk)); + { + int i = hash_for (sk_rover->pk); - if ( DBG_HASHING ) - gcry_md_debug ( textmd, "clearsign" ); + if (!hashs_seen[ i & 0xff ]) + { + s = gcry_md_algo_name (i); + if (s) + { + hashs_seen[ i & 0xff ] = 1; + if (any) + iobuf_put (out, ','); + iobuf_writestr (out, s); + any = 1; + } + } + } + log_assert (any); + iobuf_writestr (out, LF); + } + + if (opt.not_dash_escaped) + iobuf_writestr (out, + "NotDashEscaped: You need "GPG_NAME + " to verify this message" LF); + iobuf_writestr (out, LF ); + + if (gcry_md_open (&textmd, 0, 0)) + BUG (); + for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) + gcry_md_enable (textmd, hash_for(sk_rover->pk)); - copy_clearsig_text (out, inp, textmd, !opt.not_dash_escaped, - opt.escape_from); - /* fixme: check for read errors */ + if (DBG_HASHING) + gcry_md_debug (textmd, "clearsign"); - /* now write the armor */ - afx->what = 2; - push_armor_filter (afx, out); + copy_clearsig_text (out, inp, textmd, !opt.not_dash_escaped, opt.escape_from); + /* fixme: check for read errors */ - /* Write the signatures. */ - rc = write_signature_packets (ctrl, sk_list, out, textmd, 0x01, 0, - duration, 'C', NULL); - if( rc ) - goto leave; + /* Now write the armor. */ + afx->what = 2; + push_armor_filter (afx, out); + + /* Write the signatures. */ + rc = write_signature_packets (ctrl, sk_list, out, textmd, NULL, 0x01, 0, + duration, 'C', NULL); + if (rc) + goto leave; - leave: - if( rc ) - iobuf_cancel(out); - else - iobuf_close(out); - iobuf_close(inp); - gcry_md_close ( textmd ); - release_sk_list( sk_list ); - release_progress_context (pfx); - release_armor_context (afx); - return rc; + leave: + if (rc) + iobuf_cancel (out); + else + iobuf_close (out); + iobuf_close (inp); + gcry_md_close (textmd); + release_sk_list (sk_list); + release_progress_context (pfx); + release_armor_context (afx); + return rc; } + /* * Sign and conventionally encrypt the given file. * FIXME: Far too much code is duplicated - revamp the whole file. @@ -1269,175 +1388,182 @@ clearsign_file (ctrl_t ctrl, int sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr) { - armor_filter_context_t *afx; - progress_filter_context_t *pfx; - compress_filter_context_t zfx; - md_filter_context_t mfx; - text_filter_context_t tfx; - cipher_filter_context_t cfx; - IOBUF inp = NULL, out = NULL; - PACKET pkt; - STRING2KEY *s2k = NULL; - int rc = 0; - SK_LIST sk_list = NULL; - SK_LIST sk_rover = NULL; - int algo; - u32 duration=0; - int canceled; - - pfx = new_progress_context (); - afx = new_armor_context (); - memset( &zfx, 0, sizeof zfx); - memset( &mfx, 0, sizeof mfx); - memset( &tfx, 0, sizeof tfx); - memset( &cfx, 0, sizeof cfx); - init_packet( &pkt ); - - if (opt.ask_sig_expire && !opt.batch) - duration = ask_expire_interval (1, opt.def_sig_expire); - else - duration = parse_expire_string (opt.def_sig_expire); - - /* Note: In the old non-agent version the following call used to - unprotect the secret key. This is now done on demand by the agent. */ - rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG); - if (rc) - goto leave; - - /* prepare iobufs */ - inp = iobuf_open(fname); - if (inp && is_secured_file (iobuf_get_fd (inp))) - { - iobuf_close (inp); - inp = NULL; - gpg_err_set_errno (EPERM); - } - if( !inp ) { - rc = gpg_error_from_syserror (); - log_error (_("can't open '%s': %s\n"), - fname? fname: "[stdin]", strerror(errno) ); - goto leave; + armor_filter_context_t *afx; + progress_filter_context_t *pfx; + compress_filter_context_t zfx; + md_filter_context_t mfx; + text_filter_context_t tfx; + cipher_filter_context_t cfx; + iobuf_t inp = NULL; + iobuf_t out = NULL; + PACKET pkt; + STRING2KEY *s2k = NULL; + int rc = 0; + SK_LIST sk_list = NULL; + SK_LIST sk_rover = NULL; + int algo; + u32 duration = 0; + int canceled; + pt_extra_hash_data_t extrahash = NULL; + + pfx = new_progress_context (); + afx = new_armor_context (); + memset (&zfx, 0, sizeof zfx); + memset (&mfx, 0, sizeof mfx); + memset (&tfx, 0, sizeof tfx); + memset (&cfx, 0, sizeof cfx); + init_packet (&pkt); + + if (opt.ask_sig_expire && !opt.batch) + duration = ask_expire_interval (1, opt.def_sig_expire); + else + duration = parse_expire_string (opt.def_sig_expire); + + /* Note: In the old non-agent version the following call used to + * unprotect the secret key. This is now done on demand by the agent. */ + rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG); + if (rc) + goto leave; + + /* Prepare iobufs. */ + inp = iobuf_open (fname); + if (inp && is_secured_file (iobuf_get_fd (inp))) + { + iobuf_close (inp); + inp = NULL; + gpg_err_set_errno (EPERM); } - handle_progress (pfx, inp, fname); + if (!inp) + { + rc = gpg_error_from_syserror (); + log_error (_("can't open '%s': %s\n"), + fname? fname: "[stdin]", gpg_strerror (rc)); + goto leave; + } + handle_progress (pfx, inp, fname); - /* prepare key */ - s2k = xmalloc_clear( sizeof *s2k ); - s2k->mode = opt.s2k_mode; - s2k->hash_algo = S2K_DIGEST_ALGO; + /* Prepare key. */ + s2k = xmalloc_clear (sizeof *s2k); + s2k->mode = opt.s2k_mode; + s2k->hash_algo = S2K_DIGEST_ALGO; - algo = default_cipher_algo(); - cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled); + algo = default_cipher_algo (); + cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled); - if (!cfx.dek || !cfx.dek->keylen) { - rc = gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); - log_error(_("error creating passphrase: %s\n"), gpg_strerror (rc) ); - goto leave; + if (!cfx.dek || !cfx.dek->keylen) + { + rc = gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); + log_error (_("error creating passphrase: %s\n"), gpg_strerror (rc)); + goto leave; } - cfx.dek->use_aead = use_aead (NULL, cfx.dek->algo); - if (!cfx.dek->use_aead) - cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo); - - if (!opt.quiet || !opt.batch) - log_info (_("%s.%s encryption will be used\n"), - openpgp_cipher_algo_name (algo), - cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead) - /**/ : "CFB"); - - /* now create the outfile */ - rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out); - if (rc) - goto leave; - - /* prepare to calculate the MD over the input */ - if (opt.textmode) - iobuf_push_filter (inp, text_filter, &tfx); - if ( gcry_md_open (&mfx.md, 0, 0) ) - BUG (); - if ( DBG_HASHING ) - gcry_md_debug (mfx.md, "symc-sign"); + cfx.dek->use_aead = use_aead (NULL, cfx.dek->algo); + if (!cfx.dek->use_aead) + cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo); + + if (!opt.quiet || !opt.batch) + log_info (_("%s.%s encryption will be used\n"), + openpgp_cipher_algo_name (algo), + cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead) + /**/ : "CFB"); + + /* Now create the outfile. */ + rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out); + if (rc) + goto leave; + + /* Prepare to calculate the MD over the input. */ + if (opt.textmode) + iobuf_push_filter (inp, text_filter, &tfx); + if (gcry_md_open (&mfx.md, 0, 0)) + BUG (); + if (DBG_HASHING) + gcry_md_debug (mfx.md, "symc-sign"); - for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) - gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); + for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) + gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); - iobuf_push_filter (inp, md_filter, &mfx); + iobuf_push_filter (inp, md_filter, &mfx); - /* Push armor output filter */ - if (opt.armor) - push_armor_filter (afx, out); + /* Push armor output filter */ + if (opt.armor) + push_armor_filter (afx, out); - /* Write the symmetric key packet */ - /*(current filters: armor)*/ + /* Write the symmetric key packet */ + /* (current filters: armor)*/ + { + PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc ); + + enc->version = 4; + enc->cipher_algo = cfx.dek->algo; + enc->s2k = *s2k; + pkt.pkttype = PKT_SYMKEY_ENC; + pkt.pkt.symkey_enc = enc; + if ((rc = build_packet (out, &pkt))) + log_error ("build symkey packet failed: %s\n", gpg_strerror (rc)); + xfree (enc); + } + + /* Push the encryption filter */ + iobuf_push_filter (out, + cfx.dek->use_aead? cipher_filter_aead + /**/ : cipher_filter_cfb, + &cfx); + + /* Push the compress filter */ + if (default_compress_algo()) { - PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc ); - enc->version = 4; - enc->cipher_algo = cfx.dek->algo; - enc->s2k = *s2k; - pkt.pkttype = PKT_SYMKEY_ENC; - pkt.pkt.symkey_enc = enc; - if( (rc = build_packet( out, &pkt )) ) - log_error("build symkey packet failed: %s\n", gpg_strerror (rc) ); - xfree(enc); + if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) + zfx.new_ctb = 1; + push_compress_filter (out, &zfx,default_compress_algo() ); } - /* Push the encryption filter */ - iobuf_push_filter (out, - cfx.dek->use_aead? cipher_filter_aead - /**/ : cipher_filter_cfb, - &cfx); + /* Write the one-pass signature packets */ + /* (current filters: zip - encrypt - armor) */ + rc = write_onepass_sig_packets (sk_list, out, opt.textmode? 0x01:0x00); + if (rc) + goto leave; - /* Push the compress filter */ - if (default_compress_algo()) - { - if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) - zfx.new_ctb = 1; - push_compress_filter (out, &zfx,default_compress_algo() ); - } + write_status_begin_signing (mfx.md); - /* Write the one-pass signature packets */ - /*(current filters: zip - encrypt - armor)*/ - rc = write_onepass_sig_packets (sk_list, out, - opt.textmode? 0x01:0x00); - if (rc) - goto leave; + /* Pipe data through all filters; i.e. write the signed stuff. */ + /* (current filters: zip - encrypt - armor) */ + rc = write_plaintext_packet (out, inp, fname, + opt.textmode ? (opt.mimemode?'m':'t'):'b', + &extrahash); + if (rc) + goto leave; - write_status_begin_signing (mfx.md); - - /* Pipe data through all filters; i.e. write the signed stuff */ - /*(current filters: zip - encrypt - armor)*/ - rc = write_plaintext_packet (out, inp, fname, - opt.textmode ? (opt.mimemode?'m':'t'):'b'); - if (rc) - goto leave; - - /* Write the signatures */ - /*(current filters: zip - encrypt - armor)*/ - rc = write_signature_packets (ctrl, sk_list, out, mfx.md, - opt.textmode? 0x01 : 0x00, - 0, duration, 'S', NULL); - if( rc ) - goto leave; + /* Write the signatures. */ + /* (current filters: zip - encrypt - armor) */ + rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash, + opt.textmode? 0x01 : 0x00, + 0, duration, 'S', NULL); + if (rc) + goto leave; - leave: - if( rc ) - iobuf_cancel(out); - else { - iobuf_close(out); - write_status( STATUS_END_ENCRYPTION ); + leave: + if (rc) + iobuf_cancel (out); + else + { + iobuf_close (out); + write_status (STATUS_END_ENCRYPTION); } - iobuf_close(inp); - release_sk_list( sk_list ); - gcry_md_close( mfx.md ); - xfree(cfx.dek); - xfree(s2k); - release_progress_context (pfx); - release_armor_context (afx); - return rc; + iobuf_close (inp); + release_sk_list (sk_list); + gcry_md_close (mfx.md); + xfree (cfx.dek); + xfree (s2k); + release_progress_context (pfx); + release_armor_context (afx); + xfree (extrahash); + return rc; } -/**************** +/* * Create a v4 signature in *RET_SIG. * * PK is the primary key to sign (required for all sigs) @@ -1472,105 +1598,102 @@ make_keysig_packet (ctrl_t ctrl, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce) { - PKT_signature *sig; - int rc=0; - int sigversion; - gcry_md_hd_t md; + PKT_signature *sig; + int rc = 0; + int sigversion; + gcry_md_hd_t md; - log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F - || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19 - || sigclass == 0x30 || sigclass == 0x28 ); + log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F + || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19 + || sigclass == 0x30 || sigclass == 0x28 ); + if (pksk->version >= 5) + sigversion = 5; + else sigversion = 4; - if (sigversion < pksk->version) - sigversion = pksk->version; - if( !digest_algo ) - { - /* Basically, this means use SHA1 always unless the user - specified something (use whatever they said), or it's DSA - (use the best match). They still can't pick an - inappropriate hash for DSA or the signature will fail. - Note that this still allows the caller of - make_keysig_packet to override the user setting if it - must. */ - - if(opt.cert_digest_algo) - digest_algo=opt.cert_digest_algo; - else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA) - digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); - else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA - || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) - { - if (openpgp_oid_is_ed25519 (pksk->pkey[0])) - digest_algo = DIGEST_ALGO_SHA256; - else - digest_algo = match_dsa_hash - (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); - } - else - digest_algo = DEFAULT_DIGEST_ALGO; - } + if (!digest_algo) + { + /* Basically, this means use SHA1 always unless the user + * specified something (use whatever they said), or it's DSA + * (use the best match). They still can't pick an inappropriate + * hash for DSA or the signature will fail. Note that this + * still allows the caller of make_keysig_packet to override the + * user setting if it must. */ + + if (opt.cert_digest_algo) + digest_algo = opt.cert_digest_algo; + else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) + digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); + else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) + { + if (openpgp_oid_is_ed25519 (pksk->pkey[0])) + digest_algo = DIGEST_ALGO_SHA256; + else + digest_algo = match_dsa_hash + (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); + } + else + digest_algo = DEFAULT_DIGEST_ALGO; + } - if ( gcry_md_open (&md, digest_algo, 0 ) ) - BUG (); + if (gcry_md_open (&md, digest_algo, 0)) + BUG (); - /* Hash the public key certificate. */ - hash_public_key( md, pk ); + /* Hash the public key certificate. */ + hash_public_key (md, pk); - if( sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x28 ) - { - /* hash the subkey binding/backsig/revocation */ - hash_public_key( md, subpk ); - } - else if( sigclass != 0x1F && sigclass != 0x20 ) - { - /* hash the user id */ - hash_uid (md, sigversion, uid); - } - /* and make the signature packet */ - sig = xmalloc_clear( sizeof *sig ); - sig->version = sigversion; - sig->flags.exportable=1; - sig->flags.revocable=1; - keyid_from_pk (pksk, sig->keyid); - sig->pubkey_algo = pksk->pubkey_algo; - sig->digest_algo = digest_algo; - if(timestamp) - sig->timestamp=timestamp; - else - sig->timestamp=make_timestamp(); - if(duration) - sig->expiredate=sig->timestamp+duration; - sig->sig_class = sigclass; - - build_sig_subpkt_from_sig (sig, pksk); - mk_notation_policy_etc (sig, pk, pksk); - - /* Crucial that the call to mksubpkt comes LAST before the calls - to finalize the sig as that makes it possible for the mksubpkt - function to get a reliable pointer to the subpacket area. */ - if (mksubpkt) - rc = (*mksubpkt)( sig, opaque ); - - if( !rc ) { - hash_sigversion_to_magic (md, sig); - gcry_md_final (md); - - rc = complete_sig (ctrl, sig, pksk, md, cache_nonce); + if (sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x28) + { + /* Hash the subkey binding/backsig/revocation. */ + hash_public_key (md, subpk); + } + else if (sigclass != 0x1F && sigclass != 0x20) + { + /* Hash the user id. */ + hash_uid (md, sigversion, uid); + } + /* Make the signature packet. */ + sig = xmalloc_clear (sizeof *sig); + sig->version = sigversion; + sig->flags.exportable = 1; + sig->flags.revocable = 1; + keyid_from_pk (pksk, sig->keyid); + sig->pubkey_algo = pksk->pubkey_algo; + sig->digest_algo = digest_algo; + sig->timestamp = timestamp? timestamp : make_timestamp (); + if (duration) + sig->expiredate = sig->timestamp + duration; + sig->sig_class = sigclass; + + build_sig_subpkt_from_sig (sig, pksk); + mk_notation_policy_etc (sig, pk, pksk); + + /* Crucial that the call to mksubpkt comes LAST before the calls + * to finalize the sig as that makes it possible for the mksubpkt + * function to get a reliable pointer to the subpacket area. */ + if (mksubpkt) + rc = (*mksubpkt)(sig, opaque); + + if (!rc) + { + hash_sigversion_to_magic (md, sig, NULL); + gcry_md_final (md); + rc = complete_sig (ctrl, sig, pksk, md, cache_nonce); } - gcry_md_close (md); - if( rc ) - free_seckey_enc( sig ); - else - *ret_sig = sig; - return rc; + gcry_md_close (md); + if (rc) + free_seckey_enc (sig); + else + *ret_sig = sig; + return rc; } -/**************** +/* * Create a new signature packet based on an existing one. * Only user ID signatures are supported for now. * PK is the public key to work on. @@ -1589,82 +1712,82 @@ update_keysig_packet (ctrl_t ctrl, int (*mksubpkt)(PKT_signature *, void *), void *opaque) { - PKT_signature *sig; - gpg_error_t rc = 0; - int digest_algo; - gcry_md_hd_t md; - - if ((!orig_sig || !pk || !pksk) - || (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid) - || (orig_sig->sig_class == 0x18 && !subpk)) - return GPG_ERR_GENERAL; - - if ( opt.cert_digest_algo ) - digest_algo = opt.cert_digest_algo; - else - digest_algo = orig_sig->digest_algo; + PKT_signature *sig; + gpg_error_t rc = 0; + int digest_algo; + gcry_md_hd_t md; + + if ((!orig_sig || !pk || !pksk) + || (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid) + || (orig_sig->sig_class == 0x18 && !subpk)) + return GPG_ERR_GENERAL; + + if (opt.cert_digest_algo) + digest_algo = opt.cert_digest_algo; + else + digest_algo = orig_sig->digest_algo; - if ( gcry_md_open (&md, digest_algo, 0 ) ) - BUG (); + if (gcry_md_open (&md, digest_algo, 0)) + BUG (); - /* Hash the public key certificate and the user id. */ - hash_public_key( md, pk ); + /* Hash the public key certificate and the user id. */ + hash_public_key (md, pk); - if( orig_sig->sig_class == 0x18 ) - hash_public_key( md, subpk ); - else - hash_uid (md, orig_sig->version, uid); + if (orig_sig->sig_class == 0x18) + hash_public_key (md, subpk); + else + hash_uid (md, orig_sig->version, uid); - /* create a new signature packet */ - sig = copy_signature (NULL, orig_sig); + /* Create a new signature packet. */ + sig = copy_signature (NULL, orig_sig); - sig->digest_algo=digest_algo; + sig->digest_algo = digest_algo; - /* We need to create a new timestamp so that new sig expiration - calculations are done correctly... */ - sig->timestamp=make_timestamp(); + /* We need to create a new timestamp so that new sig expiration + * calculations are done correctly... */ + sig->timestamp = make_timestamp(); - /* ... but we won't make a timestamp earlier than the existing - one. */ - { - int tmout = 0; - while(sig->timestamp<=orig_sig->timestamp) - { - if (++tmout > 5 && !opt.ignore_time_conflict) - { - rc = gpg_error (GPG_ERR_TIME_CONFLICT); - goto leave; - } - gnupg_sleep (1); - sig->timestamp=make_timestamp(); - } - } - - /* Note that already expired sigs will remain expired (with a - duration of 1) since build-packet.c:build_sig_subpkt_from_sig - detects this case. */ + /* ... but we won't make a timestamp earlier than the existing + * one. */ + { + int tmout = 0; + while (sig->timestamp <= orig_sig->timestamp) + { + if (++tmout > 5 && !opt.ignore_time_conflict) + { + rc = gpg_error (GPG_ERR_TIME_CONFLICT); + goto leave; + } + gnupg_sleep (1); + sig->timestamp = make_timestamp(); + } + } - /* Put the updated timestamp into the sig. Note that this will - automagically lower any sig expiration dates to correctly - correspond to the differences in the timestamps (i.e. the - duration will shrink). */ - build_sig_subpkt_from_sig (sig, pksk); + /* Note that already expired sigs will remain expired (with a + * duration of 1) since build-packet.c:build_sig_subpkt_from_sig + * detects this case. */ - if (mksubpkt) - rc = (*mksubpkt)(sig, opaque); + /* Put the updated timestamp into the sig. Note that this will + * automagically lower any sig expiration dates to correctly + * correspond to the differences in the timestamps (i.e. the + * duration will shrink). */ + build_sig_subpkt_from_sig (sig, pksk); - if (!rc) { - hash_sigversion_to_magic (md, sig); - gcry_md_final (md); + if (mksubpkt) + rc = (*mksubpkt)(sig, opaque); - rc = complete_sig (ctrl, sig, pksk, md, NULL); + if (!rc) + { + hash_sigversion_to_magic (md, sig, NULL); + gcry_md_final (md); + rc = complete_sig (ctrl, sig, pksk, md, NULL); } leave: - gcry_md_close (md); - if( rc ) - free_seckey_enc (sig); - else - *ret_sig = sig; - return rc; + gcry_md_close (md); + if (rc) + free_seckey_enc (sig); + else + *ret_sig = sig; + return rc; } diff --git a/g10/skclist.c b/g10/skclist.c index fd747fb2b..c9c41d0d9 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -337,7 +337,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) kbnode_t keyblock; kbnode_t node; getkey_ctx_t ctx; - pubkey_t results; + SK_LIST results; } *c = *context; if (!c) @@ -345,7 +345,11 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) /* Make a new context. */ c = xtrycalloc (1, sizeof *c); if (!c) - return gpg_error_from_syserror (); + { + err = gpg_error_from_syserror (); + free_public_key (sk); + return err; + } *context = c; } @@ -354,7 +358,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) /* Free the context. */ xfree (c->serialno); free_strlist (c->card_list); - pubkeys_free (c->results); + release_sk_list (c->results); release_kbnode (c->keyblock); getkey_end (ctrl, c->ctx); xfree (c); @@ -363,7 +367,10 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) } if (c->eof) - return gpg_error (GPG_ERR_EOF); + { + free_public_key (sk); + return gpg_error (GPG_ERR_EOF); + } for (;;) { @@ -373,6 +380,8 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) /* Loop over the list of secret keys. */ do { + char *serialno; + name = NULL; keyblock = NULL; switch (c->state) @@ -408,8 +417,6 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) case 4: /* Get next item from card list. */ if (c->sl) { - char *serialno; - err = agent_scd_serialno (&serialno, c->sl->d); if (err) { @@ -437,9 +444,13 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) } else { - if (c->serialno) - /* Select the original card again. */ - agent_scd_serialno (&c->serialno, c->serialno); + serialno = c->serialno; + if (serialno) + { + /* Select the original card again. */ + agent_scd_serialno (&c->serialno, serialno); + xfree (serialno); + } c->state++; } break; @@ -475,6 +486,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) default: /* No more names to check - stop. */ c->eof = 1; + free_public_key (sk); return gpg_error (GPG_ERR_EOF); } } @@ -504,7 +516,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) if (c->node->pkt->pkttype == PKT_PUBLIC_KEY || c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { - pubkey_t r; + SK_LIST r; /* Skip this candidate if it's already enumerated. */ for (r = c->results; r; r = r->next) @@ -525,7 +537,6 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) } r->pk = sk; - r->keyblock = NULL; r->next = c->results; c->results = r; diff --git a/g10/tdbio.c b/g10/tdbio.c index fed0cf5ab..b6c38bd24 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -106,7 +106,7 @@ struct cmp_xdir_struct static char *db_name; /* The handle for locking the trustdb file and a counter to record how - * often this lock has been taken. That counter is required becuase + * often this lock has been taken. That counter is required because * dotlock does not implemen recursive locks. */ static dotlock_t lockhandle; static unsigned int is_locked; @@ -562,6 +562,12 @@ tdbio_update_version_record (ctrl_t ctrl) { TRUSTREC rec; int rc; + int opt_tm; + + /* Never store a TOFU trust model in the trustdb. Use PGP instead. */ + opt_tm = opt.trust_model; + if (opt_tm == TM_TOFU || opt_tm == TM_TOFU_PGP) + opt_tm = TM_PGP; memset (&rec, 0, sizeof rec); @@ -572,7 +578,7 @@ tdbio_update_version_record (ctrl_t ctrl) rec.r.ver.marginals = opt.marginals_needed; rec.r.ver.completes = opt.completes_needed; rec.r.ver.cert_depth = opt.max_cert_depth; - rec.r.ver.trust_model = opt.trust_model; + rec.r.ver.trust_model = opt_tm; rec.r.ver.min_cert_level = opt.min_cert_level; rc = tdbio_write_record (ctrl, &rec); } @@ -583,7 +589,7 @@ tdbio_update_version_record (ctrl_t ctrl) /* * Create and write the trustdb version record. - * This is called with the writelock activ. + * This is called with the writelock active. * Returns: 0 on success or an error code. */ static int @@ -591,6 +597,12 @@ create_version_record (ctrl_t ctrl) { TRUSTREC rec; int rc; + int opt_tm; + + /* Never store a TOFU trust model in the trustdb. Use PGP instead. */ + opt_tm = opt.trust_model; + if (opt_tm == TM_TOFU || opt_tm == TM_TOFU_PGP) + opt_tm = TM_PGP; memset (&rec, 0, sizeof rec); rec.r.ver.version = 3; @@ -598,8 +610,8 @@ create_version_record (ctrl_t ctrl) rec.r.ver.marginals = opt.marginals_needed; rec.r.ver.completes = opt.completes_needed; rec.r.ver.cert_depth = opt.max_cert_depth; - if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC) - rec.r.ver.trust_model = opt.trust_model; + if (opt_tm == TM_PGP || opt_tm == TM_CLASSIC) + rec.r.ver.trust_model = opt_tm; else rec.r.ver.trust_model = TM_PGP; rec.r.ver.min_cert_level = opt.min_cert_level; @@ -883,16 +895,25 @@ tdbio_db_matches_options() { TRUSTREC vr; int rc; + int opt_tm, tm; rc = tdbio_read_record (0, &vr, RECTYPE_VER); if( rc ) log_fatal( _("%s: error reading version record: %s\n"), db_name, gpg_strerror (rc) ); + /* Consider tofu and pgp the same. */ + tm = vr.r.ver.trust_model; + if (tm == TM_TOFU || tm == TM_TOFU_PGP) + tm = TM_PGP; + opt_tm = opt.trust_model; + if (opt_tm == TM_TOFU || opt_tm == TM_TOFU_PGP) + opt_tm = TM_PGP; + yes_no = vr.r.ver.marginals == opt.marginals_needed && vr.r.ver.completes == opt.completes_needed && vr.r.ver.cert_depth == opt.max_cert_depth - && vr.r.ver.trust_model == opt.trust_model + && tm == opt_tm && vr.r.ver.min_cert_level == opt.min_cert_level; } @@ -1118,7 +1139,7 @@ upd_hashtable (ctrl_t ctrl, ulong table, byte *key, int keylen, ulong newrecnum) if (rec.r.hlst.next) { - /* read the next reord of the list. */ + /* read the next record of the list. */ rc = tdbio_read_record (rec.r.hlst.next, &rec, RECTYPE_HLST); if (rc) { diff --git a/g10/tofu.c b/g10/tofu.c index 762b19b7a..44f354512 100644 --- a/g10/tofu.c +++ b/g10/tofu.c @@ -3292,7 +3292,7 @@ show_warning (const char *fingerprint, strlist_t user_id_list) static char * email_from_user_id (const char *user_id) { - char *email = mailbox_from_userid (user_id); + char *email = mailbox_from_userid (user_id, 0); if (! email) { /* Hmm, no email address was provided or we are out of core. Just diff --git a/g10/trustdb.c b/g10/trustdb.c index 8ef6db542..a230a6c03 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -1131,7 +1131,7 @@ tdb_get_validity_core (ctrl_t ctrl, if (sig && sig->signers_uid) /* Make sure the UID matches. */ { - char *email = mailbox_from_userid (user_id->name); + char *email = mailbox_from_userid (user_id->name, 0); if (!email || !*email || strcmp (sig->signers_uid, email) != 0) { if (DBG_TRUST) @@ -1506,7 +1506,7 @@ store_validation_status (ctrl_t ctrl, int depth, /* Returns a sanitized copy of the regexp (which might be "", but not NULL). */ #ifndef DISABLE_REGEX -/* Operator charactors except '.' and backslash. +/* Operator characters except '.' and backslash. See regex(7) on BSD. */ #define REGEXP_OPERATOR_CHARS "^[$()|*+?{" diff --git a/g10/verify.c b/g10/verify.c index caeb1a244..73ac4bad8 100644 --- a/g10/verify.c +++ b/g10/verify.c @@ -69,7 +69,7 @@ verify_signatures (ctrl_t ctrl, int nfiles, char **files ) * we can do it is by reading one byte from stdin and then unget * it; the problem here is that we may be reading from the * terminal (which could be detected using isatty() but won't work - * when under contol of a pty using program (e.g. expect)) and + * when under control of a pty using program (e.g. expect)) and * might get us in trouble when stdin is used for another purpose * (--passphrase-fd 0). So we have to break with the behaviour * prior to gpg 1.0.4 by assuming that case 3 is a normal |