Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F35221306
seckey-cert.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
8 KB
Subscribers
None
seckey-cert.c
View Options
/* seckey-cert.c - secret key certifucate packet handling
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GNUPG.
*
* GNUPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GNUPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<assert.h>
#include
"util.h"
#include
"memory.h"
#include
"packet.h"
#include
"mpi.h"
#include
"keydb.h"
#include
"cipher.h"
#include
"main.h"
#include
"options.h"
#include
"i18n.h"
static
int
do_check
(
PKT_secret_key
*
sk
)
{
byte
*
buffer
;
u16
csum
=
0
;
int
i
,
res
;
unsigned
nbytes
;
if
(
sk
->
is_protected
)
{
/* remove the protection */
DEK
*
dek
=
NULL
;
u32
keyid
[
2
];
CIPHER_HANDLE
cipher_hd
=
NULL
;
PKT_secret_key
*
save_sk
;
char
save_iv
[
8
];
if
(
sk
->
protect
.
algo
==
CIPHER_ALGO_NONE
)
BUG
();
if
(
check_cipher_algo
(
sk
->
protect
.
algo
)
)
return
G10ERR_CIPHER_ALGO
;
/* unsupported protection algorithm */
if
(
cipher_get_blocksize
(
sk
->
protect
.
algo
)
!=
8
)
return
G10ERR_CIPHER_ALGO
;
/* unsupported protection algorithm */
keyid_from_sk
(
sk
,
keyid
);
dek
=
passphrase_to_dek
(
keyid
,
sk
->
protect
.
algo
,
&
sk
->
protect
.
s2k
,
0
);
cipher_hd
=
cipher_open
(
sk
->
protect
.
algo
,
CIPHER_MODE_AUTO_CFB
,
1
);
cipher_setkey
(
cipher_hd
,
dek
->
key
,
dek
->
keylen
);
cipher_setiv
(
cipher_hd
,
NULL
);
m_free
(
dek
);
save_sk
=
copy_secret_key
(
NULL
,
sk
);
memcpy
(
save_iv
,
sk
->
protect
.
iv
,
8
);
cipher_decrypt
(
cipher_hd
,
sk
->
protect
.
iv
,
sk
->
protect
.
iv
,
8
);
csum
=
0
;
if
(
sk
->
version
>=
4
)
{
int
ndata
;
byte
*
p
,
*
data
;
i
=
pubkey_get_npkey
(
sk
->
pubkey_algo
);
assert
(
mpi_is_opaque
(
sk
->
skey
[
i
]
)
);
p
=
mpi_get_opaque
(
sk
->
skey
[
i
],
&
ndata
);
data
=
m_alloc_secure
(
ndata
);
cipher_decrypt
(
cipher_hd
,
data
,
p
,
ndata
);
mpi_free
(
sk
->
skey
[
i
]
);
sk
->
skey
[
i
]
=
NULL
;
p
=
data
;
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
];
}
/* must check it here otherwise the mpi_read_xx would fail
* because the length das an abritary 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
;
}
}
m_free
(
data
);
}
else
{
for
(
i
=
pubkey_get_npkey
(
sk
->
pubkey_algo
);
i
<
pubkey_get_nskey
(
sk
->
pubkey_algo
);
i
++
)
{
buffer
=
mpi_get_secure_buffer
(
sk
->
skey
[
i
],
&
nbytes
,
NULL
);
cipher_sync
(
cipher_hd
);
assert
(
mpi_is_protected
(
sk
->
skey
[
i
])
);
cipher_decrypt
(
cipher_hd
,
buffer
,
buffer
,
nbytes
);
mpi_set_buffer
(
sk
->
skey
[
i
],
buffer
,
nbytes
,
0
);
mpi_clear_protect_flag
(
sk
->
skey
[
i
]
);
csum
+=
checksum_mpi
(
sk
->
skey
[
i
]
);
m_free
(
buffer
);
}
if
(
opt
.
emulate_bugs
&
EMUBUG_GPGCHKSUM
)
{
csum
=
sk
->
csum
;
}
}
cipher_close
(
cipher_hd
);
/* now let's see whether we have used the right passphrase */
if
(
csum
!=
sk
->
csum
)
{
copy_secret_key
(
sk
,
save_sk
);
free_secret_key
(
save_sk
);
memcpy
(
sk
->
protect
.
iv
,
save_iv
,
8
);
return
G10ERR_BAD_PASS
;
}
/* the checksum may fail, so we also check the key itself */
res
=
pubkey_check_secret_key
(
sk
->
pubkey_algo
,
sk
->
skey
);
if
(
res
)
{
copy_secret_key
(
sk
,
save_sk
);
free_secret_key
(
save_sk
);
memcpy
(
sk
->
protect
.
iv
,
save_iv
,
8
);
return
G10ERR_BAD_PASS
;
}
free_secret_key
(
save_sk
);
sk
->
is_protected
=
0
;
}
else
{
/* not protected, assume it is okay if the checksum is okay */
csum
=
0
;
for
(
i
=
pubkey_get_npkey
(
sk
->
pubkey_algo
);
i
<
pubkey_get_nskey
(
sk
->
pubkey_algo
);
i
++
)
{
csum
+=
checksum_mpi
(
sk
->
skey
[
i
]
);
}
if
(
csum
!=
sk
->
csum
)
return
G10ERR_CHECKSUM
;
}
return
0
;
}
/****************
* Check the secret key
* Ask up to 3 times for a correct passphrase
*/
int
check_secret_key
(
PKT_secret_key
*
sk
)
{
int
rc
=
G10ERR_BAD_PASS
;
int
i
;
for
(
i
=
0
;
i
<
3
&&
rc
==
G10ERR_BAD_PASS
;
i
++
)
{
if
(
i
)
log_error
(
_
(
"Invalid passphrase; please try again ...
\n
"
));
rc
=
do_check
(
sk
);
#if 0
/* set to 1 to enable the workaround */
if( rc == G10ERR_BAD_PASS && sk->is_protected
&& sk->protect.algo == CIPHER_ALGO_BLOWFISH
&& sk->pubkey_algo != PUBKEY_ALGO_ELGAMAL ) {
/* Workaround for a bug in 0.2.16 which still used
* a 160 bit key for BLOWFISH. */
log_info("trying workaround for 0.2.16 passphrase bug ...\n");
log_info("If you don't need this, uncomment it in g10/seckey-cert.c\n\n");
sk->protect.algo = CIPHER_ALGO_BLOWFISH160;
rc = do_check( sk );
if( rc )
rc = G10ERR_BAD_PASS;
sk->protect.algo = CIPHER_ALGO_BLOWFISH;
}
#endif
if
(
get_passphrase_fd
()
!=
-1
)
break
;
}
return
rc
;
}
/****************
* check whether the secret key is protected.
* Returns: 0 not protected, -1 on error or the protection algorithm
*/
int
is_secret_key_protected
(
PKT_secret_key
*
sk
)
{
return
sk
->
is_protected
?
sk
->
protect
.
algo
:
0
;
}
/****************
* Protect the secret key with the passphrase from DEK
*/
int
protect_secret_key
(
PKT_secret_key
*
sk
,
DEK
*
dek
)
{
int
i
,
j
,
rc
=
0
;
byte
*
buffer
;
unsigned
nbytes
;
u16
csum
;
if
(
!
dek
)
return
0
;
if
(
!
sk
->
is_protected
)
{
/* okay, apply the protection */
CIPHER_HANDLE
cipher_hd
=
NULL
;
if
(
check_cipher_algo
(
sk
->
protect
.
algo
)
)
rc
=
G10ERR_CIPHER_ALGO
;
/* unsupport protection algorithm */
else
if
(
cipher_get_blocksize
(
sk
->
protect
.
algo
)
!=
8
)
rc
=
G10ERR_CIPHER_ALGO
;
/* unsupport protection algorithm */
else
{
cipher_hd
=
cipher_open
(
sk
->
protect
.
algo
,
CIPHER_MODE_AUTO_CFB
,
1
);
cipher_setkey
(
cipher_hd
,
dek
->
key
,
dek
->
keylen
);
cipher_setiv
(
cipher_hd
,
NULL
);
cipher_encrypt
(
cipher_hd
,
sk
->
protect
.
iv
,
sk
->
protect
.
iv
,
8
);
if
(
sk
->
version
>=
4
)
{
#define NMPIS (PUBKEY_MAX_NSKEY - PUBKEY_MAX_NPKEY)
byte
*
buffer
[
NMPIS
];
unsigned
nbytes
[
NMPIS
];
unsigned
nbits
[
NMPIS
];
int
ndata
=
0
;
byte
*
p
,
*
data
;
for
(
j
=
0
,
i
=
pubkey_get_npkey
(
sk
->
pubkey_algo
);
i
<
pubkey_get_nskey
(
sk
->
pubkey_algo
);
i
++
,
j
++
)
{
assert
(
!
mpi_is_opaque
(
sk
->
skey
[
i
]
)
);
buffer
[
j
]
=
mpi_get_buffer
(
sk
->
skey
[
i
],
&
nbytes
[
j
],
NULL
);
nbits
[
j
]
=
mpi_get_nbits
(
sk
->
skey
[
i
]
);
ndata
+=
nbytes
[
j
]
+
2
;
}
for
(
;
j
<
NMPIS
;
j
++
)
buffer
[
j
]
=
NULL
;
ndata
+=
2
;
/* for checksum */
data
=
m_alloc_secure
(
ndata
);
p
=
data
;
for
(
j
=
0
;
j
<
NMPIS
&&
buffer
[
j
];
j
++
)
{
p
[
0
]
=
nbits
[
j
]
>>
8
;
p
[
1
]
=
nbits
[
j
];
p
+=
2
;
memcpy
(
p
,
buffer
[
j
],
nbytes
[
j
]
);
p
+=
nbytes
[
j
];
m_free
(
buffer
[
j
]);
}
#undef NMPIS
csum
=
checksum
(
data
,
ndata
-2
);
sk
->
csum
=
csum
;
*
p
++
=
csum
>>
8
;
*
p
++
=
csum
;
assert
(
p
==
data
+
ndata
);
cipher_encrypt
(
cipher_hd
,
data
,
data
,
ndata
);
for
(
i
=
pubkey_get_npkey
(
sk
->
pubkey_algo
);
i
<
pubkey_get_nskey
(
sk
->
pubkey_algo
);
i
++
)
{
mpi_free
(
sk
->
skey
[
i
]
);
sk
->
skey
[
i
]
=
NULL
;
}
i
=
pubkey_get_npkey
(
sk
->
pubkey_algo
);
sk
->
skey
[
i
]
=
mpi_set_opaque
(
NULL
,
data
,
ndata
);
}
else
{
/* NOTE: we always recalculate the checksum because there
* are some test releases which calculated it wrong */
csum
=
0
;
for
(
i
=
pubkey_get_npkey
(
sk
->
pubkey_algo
);
i
<
pubkey_get_nskey
(
sk
->
pubkey_algo
);
i
++
)
{
csum
+=
checksum_mpi_counted_nbits
(
sk
->
skey
[
i
]
);
buffer
=
mpi_get_buffer
(
sk
->
skey
[
i
],
&
nbytes
,
NULL
);
cipher_sync
(
cipher_hd
);
assert
(
!
mpi_is_protected
(
sk
->
skey
[
i
])
);
cipher_encrypt
(
cipher_hd
,
buffer
,
buffer
,
nbytes
);
mpi_set_buffer
(
sk
->
skey
[
i
],
buffer
,
nbytes
,
0
);
mpi_set_protect_flag
(
sk
->
skey
[
i
]
);
m_free
(
buffer
);
}
sk
->
csum
=
csum
;
}
sk
->
is_protected
=
1
;
cipher_close
(
cipher_hd
);
}
}
return
rc
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Feb 3, 11:36 PM (7 h, 21 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a6/75/ffac3464f88da91fa745e57b165e
Attached To
rG GnuPG
Event Timeline
Log In to Comment