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:
parent
e906ef5f5b
commit
60e0b2ad92
15
doc/gpg.sgml
15
doc/gpg.sgml
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 );
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
@ -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 ) {
|
||||||
|
@ -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 {
|
||||||
/* must check it here otherwise the mpi_read_xx would fail
|
if( ndata < 2 ) {
|
||||||
* because the length may have an arbitrary value */
|
log_error("not enough bytes for checksum\n");
|
||||||
if( sk->csum == csum ) {
|
sk->csum = 0;
|
||||||
for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
csum = 1;
|
||||||
nbytes = ndata;
|
}
|
||||||
sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 );
|
else {
|
||||||
ndata -= nbytes;
|
csum = checksum( data, ndata-2);
|
||||||
p += nbytes;
|
sk->csum = data[ndata-2] << 8 | data[ndata-1];
|
||||||
}
|
if ( sk->csum != csum ) {
|
||||||
/* at this point ndata should be equal to 2 (the checksum) */
|
/* 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
|
||||||
|
because the length may have an arbitrary value */
|
||||||
|
if( sk->csum == csum ) {
|
||||||
|
for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||||
|
nbytes = ndata;
|
||||||
|
sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 );
|
||||||
|
ndata -= nbytes;
|
||||||
|
p += nbytes;
|
||||||
|
}
|
||||||
|
/* 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++ ) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user