1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-23 10:29:58 +01:00

* parse-packet.c (parse_key): Support a SHA1 checksum as per

draft-rfc2440-bis04.
* packet.h (PKT_secret_key): Add field sha1chk.
* seckey-cert.c (do_check): Check the SHA1 checksum
(protect_secret_key): And create it.
* build-packet.c (do_secret_key): Mark it as sha-1 protected.
* g10.c, options.h: New option --simple-sk-checksum.
This commit is contained in:
Werner Koch 2002-04-17 16:00:03 +00:00
parent e906ef5f5b
commit 60e0b2ad92
8 changed files with 113 additions and 34 deletions

View File

@ -581,6 +581,9 @@ The second form of the command has the special property to
render the secret part of the primary key useless; this is render the secret part of the primary key useless; this is
a GNU extension to OpenPGP and other implementations can a GNU extension to OpenPGP and other implementations can
not be expected to successfully import such a key. not be expected to successfully import such a key.
See the option --simple-sk-checksum if you want to import such an
exported key with an older OpenPGP implementation.
</para></listitem></varlistentry> </para></listitem></varlistentry>
@ -1324,6 +1327,18 @@ for conventional encryption.
</para></listitem></varlistentry> </para></listitem></varlistentry>
<varlistentry>
<term>--simple-sk-checksum</term>
<listitem><para>
Secret keys are integrity protected by using a SHA-1 checksum. This
method will be part of an enhanced OpenPGP specification but GnuPG
already uses it as a countermeasure against certain attacks. Old
applications don't understand this new format, so this option may be
used to switch back to the old behaviour. Using this this option
bears a security risk.
</para></listitem></varlistentry>
<varlistentry> <varlistentry>
<term>--compress-algo &ParmN;</term> <term>--compress-algo &ParmN;</term>
<listitem><para> <listitem><para>

View File

@ -1,3 +1,16 @@
2002-04-17 Werner Koch <wk@gnupg.org>
2002-04-16 Werner Koch <wk@gnupg.org>
* parse-packet.c (parse_key): Support a SHA1 checksum as per
draft-rfc2440-bis04.
* packet.h (PKT_secret_key): Add field sha1chk.
* seckey-cert.c (do_check): Check the SHA1 checksum
(protect_secret_key): And create it.
* build-packet.c (do_secret_key): Mark it as sha-1 protected.
* g10.c, options.h: New option --simple-sk-checksum.
2002-04-13 David Shaw <dshaw@jabberwocky.com> 2002-04-13 David Shaw <dshaw@jabberwocky.com>
* parse-packet.c (parse_signature): Minor fix - signatures should * parse-packet.c (parse_signature): Minor fix - signatures should

View File

@ -389,7 +389,7 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
} }
else { else {
/* OpenPGP protection according to rfc2440 */ /* OpenPGP protection according to rfc2440 */
iobuf_put(a, 0xff ); iobuf_put(a, sk->protect.sha1chk? 0xfe : 0xff );
iobuf_put(a, sk->protect.algo ); iobuf_put(a, sk->protect.algo );
if( sk->protect.s2k.mode >= 1000 ) { if( sk->protect.s2k.mode >= 1000 ) {
/* These modes are not possible in OpenPGP, we use them /* These modes are not possible in OpenPGP, we use them

View File

@ -218,6 +218,7 @@ enum cmd_and_opt_values { aNull = 0,
oS2KMode, oS2KMode,
oS2KDigest, oS2KDigest,
oS2KCipher, oS2KCipher,
oSimpleSKChecksum,
oCharset, oCharset,
oNotDashEscaped, oNotDashEscaped,
oEscapeFrom, oEscapeFrom,
@ -412,6 +413,7 @@ static ARGPARSE_OPTS opts[] = {
N_("|NAME|use message digest algorithm NAME for passphrases")}, N_("|NAME|use message digest algorithm NAME for passphrases")},
{ oS2KCipher, "s2k-cipher-algo",2, { oS2KCipher, "s2k-cipher-algo",2,
N_("|NAME|use cipher algorithm NAME for passphrases")}, N_("|NAME|use cipher algorithm NAME for passphrases")},
{ oSimpleSKChecksum, "simple-sk-checksum", 0, "@"},
{ oCipherAlgo, "cipher-algo", 2 , N_("|NAME|use cipher algorithm NAME")}, { oCipherAlgo, "cipher-algo", 2 , N_("|NAME|use cipher algorithm NAME")},
{ oDigestAlgo, "digest-algo", 2 , N_("|NAME|use message digest algorithm NAME")}, { oDigestAlgo, "digest-algo", 2 , N_("|NAME|use message digest algorithm NAME")},
{ oCompressAlgo, "compress-algo", 1 , N_("|N|use compress algorithm N")}, { oCompressAlgo, "compress-algo", 1 , N_("|N|use compress algorithm N")},
@ -1132,7 +1134,7 @@ main( int argc, char **argv )
case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break; case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break;
case oS2KDigest: s2k_digest_string = m_strdup(pargs.r.ret_str); break; case oS2KDigest: s2k_digest_string = m_strdup(pargs.r.ret_str); break;
case oS2KCipher: s2k_cipher_string = m_strdup(pargs.r.ret_str); break; case oS2KCipher: s2k_cipher_string = m_strdup(pargs.r.ret_str); break;
case oSimpleSKChecksum: opt.simple_sk_checksum = 1; break;
case oNoEncryptTo: opt.no_encrypt_to = 1; break; case oNoEncryptTo: opt.no_encrypt_to = 1; break;
case oEncryptTo: /* store the recipient in the second list */ case oEncryptTo: /* store the recipient in the second list */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );

View File

@ -94,6 +94,8 @@ struct {
int s2k_mode; int s2k_mode;
int s2k_digest_algo; int s2k_digest_algo;
int s2k_cipher_algo; int s2k_cipher_algo;
int simple_sk_checksum; /* create the deprecated rfc2440 secret
key protection*/
int not_dash_escaped; int not_dash_escaped;
int escape_from; int escape_from;
int lock_once; int lock_once;

View File

@ -232,6 +232,7 @@ typedef struct {
/* and should never be passed to a mpi_xxx() */ /* and should never be passed to a mpi_xxx() */
struct { struct {
byte algo; /* cipher used to protect the secret information*/ byte algo; /* cipher used to protect the secret information*/
byte sha1chk; /* SHA1 is used instead of a 16 bit checksum */
STRING2KEY s2k; STRING2KEY s2k;
byte ivlen; /* used length of the iv */ byte ivlen; /* used length of the iv */
byte iv[16]; /* initialization vector for CFB mode */ byte iv[16]; /* initialization vector for CFB mode */

View File

@ -1494,14 +1494,16 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
if (rc) /* one of the MPIs were bad */ if (rc) /* one of the MPIs were bad */
goto leave; goto leave;
sk->protect.algo = iobuf_get_noeof(inp); pktlen--; sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
sk->protect.sha1chk = 0;
if( sk->protect.algo ) { if( sk->protect.algo ) {
sk->is_protected = 1; sk->is_protected = 1;
sk->protect.s2k.count = 0; sk->protect.s2k.count = 0;
if( sk->protect.algo == 255 ) { if( sk->protect.algo == 254 || sk->protect.algo == 255 ) {
if( pktlen < 3 ) { if( pktlen < 3 ) {
rc = G10ERR_INVALID_PACKET; rc = G10ERR_INVALID_PACKET;
goto leave; goto leave;
} }
sk->protect.sha1chk = (sk->protect.algo == 254);
sk->protect.algo = iobuf_get_noeof(inp); pktlen--; sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
sk->protect.s2k.mode = iobuf_get_noeof(inp); pktlen--; sk->protect.s2k.mode = iobuf_get_noeof(inp); pktlen--;
sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--; sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--;
@ -1550,8 +1552,10 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
} }
if( list_mode ) { if( list_mode ) {
printf(", algo: %d, hash: %d", printf(", algo: %d,%s hash: %d",
sk->protect.algo, sk->protect.algo,
sk->protect.sha1chk? ""
:" simple checksum,",
sk->protect.s2k.hash_algo ); sk->protect.s2k.hash_algo );
if( sk->protect.s2k.mode == 1 if( sk->protect.s2k.mode == 1
|| sk->protect.s2k.mode == 3 ) { || sk->protect.s2k.mode == 3 ) {

View File

@ -90,31 +90,54 @@ do_check( PKT_secret_key *sk, const char *tryagain_text )
cipher_decrypt( cipher_hd, data, p, ndata ); cipher_decrypt( cipher_hd, data, p, ndata );
mpi_free( sk->skey[i] ); sk->skey[i] = NULL ; mpi_free( sk->skey[i] ); sk->skey[i] = NULL ;
p = data; p = data;
if( ndata < 2 ) { if (sk->protect.sha1chk) {
log_error("not enough bytes for checksum\n"); /* This is the new SHA1 checksum method to detect
sk->csum = 0; tampering with the key as used by the Klima/Rosa
csum = 1; attack */
} sk->csum = 0;
else { csum = 1;
csum = checksum( data, ndata-2); if( ndata < 20 )
sk->csum = data[ndata-2] << 8 | data[ndata-1]; log_error("not enough bytes for SHA-1 checksum\n");
if ( sk->csum != csum ) { else {
/* This is a PGP 7.0.0 workaround */ MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
sk->csum = csumc; /* take the encrypted one */ if (!h)
BUG(); /* algo not available */
md_write (h, data, ndata - 20);
md_final (h);
if (!memcmp (md_read (h, DIGEST_ALGO_SHA1),
data + ndata - 20, 20) )
csum = 0; /* digest does match */
md_close (h);
} }
} }
else {
if( ndata < 2 ) {
log_error("not enough bytes for checksum\n");
sk->csum = 0;
csum = 1;
}
else {
csum = checksum( data, ndata-2);
sk->csum = data[ndata-2] << 8 | data[ndata-1];
if ( sk->csum != csum ) {
/* This is a PGP 7.0.0 workaround */
sk->csum = csumc; /* take the encrypted one */
}
}
}
/* must check it here otherwise the mpi_read_xx would fail /* must check it here otherwise the mpi_read_xx would fail
* because the length may have an arbitrary value */ because the length may have an arbitrary value */
if( sk->csum == csum ) { if( sk->csum == csum ) {
for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) { for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
nbytes = ndata; nbytes = ndata;
sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 ); sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 );
ndata -= nbytes; ndata -= nbytes;
p += nbytes; p += nbytes;
} }
/* at this point ndata should be equal to 2 (the checksum) */ /* Note: at this point ndata should be 2 for a simple
} checksum or 20 for the sha1 digest */
}
m_free(data); m_free(data);
} }
else { else {
@ -265,7 +288,7 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
} }
for( ; j < PUBKEY_MAX_NSKEY; j++ ) for( ; j < PUBKEY_MAX_NSKEY; j++ )
bufarr[j] = NULL; bufarr[j] = NULL;
ndata += 2; /* for checksum */ ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */
data = m_alloc_secure( ndata ); data = m_alloc_secure( ndata );
p = data; p = data;
@ -277,11 +300,30 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
p += narr[j]; p += narr[j];
m_free(bufarr[j]); m_free(bufarr[j]);
} }
csum = checksum( data, ndata-2);
sk->csum = csum; if (opt.simple_sk_checksum) {
*p++ = csum >> 8; log_info (_("generating the deprecated 16-bit checksum"
*p++ = csum; " for secret key protection\n"));
assert( p == data+ndata ); csum = checksum( data, ndata-2);
sk->csum = csum;
*p++ = csum >> 8;
*p++ = csum;
sk->protect.sha1chk = 0;
}
else {
MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
if (!h)
BUG(); /* algo not available */
md_write (h, data, ndata - 20);
md_final (h);
memcpy (p, md_read (h, DIGEST_ALGO_SHA1), 20);
p += 20;
md_close (h);
sk->csum = csum = 0;
sk->protect.sha1chk = 1;
}
assert( p == data+ndata );
cipher_encrypt( cipher_hd, data, data, ndata ); cipher_encrypt( cipher_hd, data, data, ndata );
for(i = pubkey_get_npkey(sk->pubkey_algo); for(i = pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) { i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {