Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F23020885
protect-tool.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
16 KB
Subscribers
None
protect-tool.c
View Options
/* protect-tool.c - A tool to test the secret key protection
* Copyright (C) 2002, 2003, 2004, 2006 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<stddef.h>
#include
<stdarg.h>
#include
<string.h>
#include
<errno.h>
#include
<assert.h>
#include
<sys/stat.h>
#include
<unistd.h>
#ifdef HAVE_LOCALE_H
#include
<locale.h>
#endif
#ifdef HAVE_LANGINFO_CODESET
#include
<langinfo.h>
#endif
#ifdef HAVE_DOSISH_SYSTEM
#include
<fcntl.h>
/* for setmode() */
#endif
#include
"agent.h"
#include
"i18n.h"
#include
"get-passphrase.h"
#include
"sysutils.h"
#include
"../common/init.h"
enum
cmd_and_opt_values
{
aNull
=
0
,
oVerbose
=
'v'
,
oArmor
=
'a'
,
oPassphrase
=
'P'
,
oProtect
=
'p'
,
oUnprotect
=
'u'
,
oNoVerbose
=
500
,
oShadow
,
oShowShadowInfo
,
oShowKeygrip
,
oS2Kcalibration
,
oCanonical
,
oStore
,
oForce
,
oHaveCert
,
oNoFailOnExist
,
oHomedir
,
oPrompt
,
oStatusMsg
,
oAgentProgram
};
struct
rsa_secret_key_s
{
gcry_mpi_t
n
;
/* public modulus */
gcry_mpi_t
e
;
/* public exponent */
gcry_mpi_t
d
;
/* exponent */
gcry_mpi_t
p
;
/* prime p. */
gcry_mpi_t
q
;
/* prime q. */
gcry_mpi_t
u
;
/* inverse of p mod q. */
};
static
const
char
*
opt_homedir
;
static
int
opt_armor
;
static
int
opt_canonical
;
static
int
opt_store
;
static
int
opt_force
;
static
int
opt_no_fail_on_exist
;
static
int
opt_have_cert
;
static
const
char
*
opt_passphrase
;
static
char
*
opt_prompt
;
static
int
opt_status_msg
;
static
const
char
*
opt_agent_program
;
static
char
*
get_passphrase
(
int
promptno
);
static
void
release_passphrase
(
char
*
pw
);
static
ARGPARSE_OPTS
opts
[]
=
{
ARGPARSE_group
(
300
,
N_
(
"@Commands:
\n
"
)),
ARGPARSE_c
(
oProtect
,
"protect"
,
"protect a private key"
),
ARGPARSE_c
(
oUnprotect
,
"unprotect"
,
"unprotect a private key"
),
ARGPARSE_c
(
oShadow
,
"shadow"
,
"create a shadow entry for a public key"
),
ARGPARSE_c
(
oShowShadowInfo
,
"show-shadow-info"
,
"return the shadow info"
),
ARGPARSE_c
(
oShowKeygrip
,
"show-keygrip"
,
"show the
\"
keygrip
\"
"
),
ARGPARSE_c
(
oS2Kcalibration
,
"s2k-calibration"
,
"@"
),
ARGPARSE_group
(
301
,
N_
(
"@
\n
Options:
\n
"
)),
ARGPARSE_s_n
(
oVerbose
,
"verbose"
,
"verbose"
),
ARGPARSE_s_n
(
oArmor
,
"armor"
,
"write output in advanced format"
),
ARGPARSE_s_n
(
oCanonical
,
"canonical"
,
"write output in canonical format"
),
ARGPARSE_s_s
(
oPassphrase
,
"passphrase"
,
"|STRING|use passphrase STRING"
),
ARGPARSE_s_n
(
oHaveCert
,
"have-cert"
,
"certificate to export provided on STDIN"
),
ARGPARSE_s_n
(
oStore
,
"store"
,
"store the created key in the appropriate place"
),
ARGPARSE_s_n
(
oForce
,
"force"
,
"force overwriting"
),
ARGPARSE_s_n
(
oNoFailOnExist
,
"no-fail-on-exist"
,
"@"
),
ARGPARSE_s_s
(
oHomedir
,
"homedir"
,
"@"
),
ARGPARSE_s_s
(
oPrompt
,
"prompt"
,
"|ESCSTRING|use ESCSTRING as prompt in pinentry"
),
ARGPARSE_s_n
(
oStatusMsg
,
"enable-status-msg"
,
"@"
),
ARGPARSE_s_s
(
oAgentProgram
,
"agent-program"
,
"@"
),
ARGPARSE_end
()
};
static
const
char
*
my_strusage
(
int
level
)
{
const
char
*
p
;
switch
(
level
)
{
case
11
:
p
=
"gpg-protect-tool ("
GNUPG_NAME
")"
;
break
;
case
13
:
p
=
VERSION
;
break
;
case
17
:
p
=
PRINTABLE_OS_NAME
;
break
;
case
19
:
p
=
_
(
"Please report bugs to <@EMAIL@>.
\n
"
);
break
;
case
1
:
case
40
:
p
=
_
(
"Usage: gpg-protect-tool [options] (-h for help)
\n
"
);
break
;
case
41
:
p
=
_
(
"Syntax: gpg-protect-tool [options] [args]
\n
"
"Secret key maintenance tool
\n
"
);
break
;
default
:
p
=
NULL
;
}
return
p
;
}
/* static void */
/* print_mpi (const char *text, gcry_mpi_t a) */
/* { */
/* char *buf; */
/* void *bufaddr = &buf; */
/* int rc; */
/* rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */
/* if (rc) */
/* log_info ("%s: [error printing number: %s]\n", text, gpg_strerror (rc)); */
/* else */
/* { */
/* log_info ("%s: %s\n", text, buf); */
/* gcry_free (buf); */
/* } */
/* } */
static
unsigned
char
*
make_canonical
(
const
char
*
fname
,
const
char
*
buf
,
size_t
buflen
)
{
int
rc
;
size_t
erroff
,
len
;
gcry_sexp_t
sexp
;
unsigned
char
*
result
;
rc
=
gcry_sexp_sscan
(
&
sexp
,
&
erroff
,
buf
,
buflen
);
if
(
rc
)
{
log_error
(
"invalid S-Expression in '%s' (off=%u): %s
\n
"
,
fname
,
(
unsigned
int
)
erroff
,
gpg_strerror
(
rc
));
return
NULL
;
}
len
=
gcry_sexp_sprint
(
sexp
,
GCRYSEXP_FMT_CANON
,
NULL
,
0
);
assert
(
len
);
result
=
xmalloc
(
len
);
len
=
gcry_sexp_sprint
(
sexp
,
GCRYSEXP_FMT_CANON
,
result
,
len
);
assert
(
len
);
gcry_sexp_release
(
sexp
);
return
result
;
}
static
char
*
make_advanced
(
const
unsigned
char
*
buf
,
size_t
buflen
)
{
int
rc
;
size_t
erroff
,
len
;
gcry_sexp_t
sexp
;
char
*
result
;
rc
=
gcry_sexp_sscan
(
&
sexp
,
&
erroff
,
(
const
char
*
)
buf
,
buflen
);
if
(
rc
)
{
log_error
(
"invalid canonical S-Expression (off=%u): %s
\n
"
,
(
unsigned
int
)
erroff
,
gpg_strerror
(
rc
));
return
NULL
;
}
len
=
gcry_sexp_sprint
(
sexp
,
GCRYSEXP_FMT_ADVANCED
,
NULL
,
0
);
assert
(
len
);
result
=
xmalloc
(
len
);
len
=
gcry_sexp_sprint
(
sexp
,
GCRYSEXP_FMT_ADVANCED
,
result
,
len
);
assert
(
len
);
gcry_sexp_release
(
sexp
);
return
result
;
}
static
char
*
read_file
(
const
char
*
fname
,
size_t
*
r_length
)
{
FILE
*
fp
;
char
*
buf
;
size_t
buflen
;
if
(
!
strcmp
(
fname
,
"-"
))
{
size_t
nread
,
bufsize
=
0
;
fp
=
stdin
;
#ifdef HAVE_DOSISH_SYSTEM
setmode
(
fileno
(
fp
)
,
O_BINARY
);
#endif
buf
=
NULL
;
buflen
=
0
;
#define NCHUNK 8192
do
{
bufsize
+=
NCHUNK
;
if
(
!
buf
)
buf
=
xmalloc
(
bufsize
);
else
buf
=
xrealloc
(
buf
,
bufsize
);
nread
=
fread
(
buf
+
buflen
,
1
,
NCHUNK
,
fp
);
if
(
nread
<
NCHUNK
&&
ferror
(
fp
))
{
log_error
(
"error reading '[stdin]': %s
\n
"
,
strerror
(
errno
));
xfree
(
buf
);
return
NULL
;
}
buflen
+=
nread
;
}
while
(
nread
==
NCHUNK
);
#undef NCHUNK
}
else
{
struct
stat
st
;
fp
=
fopen
(
fname
,
"rb"
);
if
(
!
fp
)
{
log_error
(
"can't open '%s': %s
\n
"
,
fname
,
strerror
(
errno
));
return
NULL
;
}
if
(
fstat
(
fileno
(
fp
),
&
st
))
{
log_error
(
"can't stat '%s': %s
\n
"
,
fname
,
strerror
(
errno
));
fclose
(
fp
);
return
NULL
;
}
buflen
=
st
.
st_size
;
buf
=
xmalloc
(
buflen
+
1
);
if
(
fread
(
buf
,
buflen
,
1
,
fp
)
!=
1
)
{
log_error
(
"error reading '%s': %s
\n
"
,
fname
,
strerror
(
errno
));
fclose
(
fp
);
xfree
(
buf
);
return
NULL
;
}
fclose
(
fp
);
}
*
r_length
=
buflen
;
return
buf
;
}
static
unsigned
char
*
read_key
(
const
char
*
fname
)
{
char
*
buf
;
size_t
buflen
;
unsigned
char
*
key
;
buf
=
read_file
(
fname
,
&
buflen
);
if
(
!
buf
)
return
NULL
;
key
=
make_canonical
(
fname
,
buf
,
buflen
);
xfree
(
buf
);
return
key
;
}
static
void
read_and_protect
(
const
char
*
fname
)
{
int
rc
;
unsigned
char
*
key
;
unsigned
char
*
result
;
size_t
resultlen
;
char
*
pw
;
key
=
read_key
(
fname
);
if
(
!
key
)
return
;
pw
=
get_passphrase
(
1
);
rc
=
agent_protect
(
key
,
pw
,
&
result
,
&
resultlen
,
0
);
release_passphrase
(
pw
);
xfree
(
key
);
if
(
rc
)
{
log_error
(
"protecting the key failed: %s
\n
"
,
gpg_strerror
(
rc
));
return
;
}
if
(
opt_armor
)
{
char
*
p
=
make_advanced
(
result
,
resultlen
);
xfree
(
result
);
if
(
!
p
)
return
;
result
=
(
unsigned
char
*
)
p
;
resultlen
=
strlen
(
p
);
}
fwrite
(
result
,
resultlen
,
1
,
stdout
);
xfree
(
result
);
}
static
void
read_and_unprotect
(
const
char
*
fname
)
{
int
rc
;
unsigned
char
*
key
;
unsigned
char
*
result
;
size_t
resultlen
;
char
*
pw
;
gnupg_isotime_t
protected_at
;
key
=
read_key
(
fname
);
if
(
!
key
)
return
;
rc
=
agent_unprotect
(
NULL
,
key
,
(
pw
=
get_passphrase
(
1
)),
protected_at
,
&
result
,
&
resultlen
);
release_passphrase
(
pw
);
xfree
(
key
);
if
(
rc
)
{
if
(
opt_status_msg
)
log_info
(
"[PROTECT-TOOL:] bad-passphrase
\n
"
);
log_error
(
"unprotecting the key failed: %s
\n
"
,
gpg_strerror
(
rc
));
return
;
}
if
(
opt
.
verbose
)
log_info
(
"key protection done at %.4s-%.2s-%.2s %.2s:%.2s:%s
\n
"
,
protected_at
,
protected_at
+
4
,
protected_at
+
6
,
protected_at
+
9
,
protected_at
+
11
,
protected_at
+
13
);
if
(
opt_armor
)
{
char
*
p
=
make_advanced
(
result
,
resultlen
);
xfree
(
result
);
if
(
!
p
)
return
;
result
=
(
unsigned
char
*
)
p
;
resultlen
=
strlen
(
p
);
}
fwrite
(
result
,
resultlen
,
1
,
stdout
);
xfree
(
result
);
}
static
void
read_and_shadow
(
const
char
*
fname
)
{
int
rc
;
unsigned
char
*
key
;
unsigned
char
*
result
;
size_t
resultlen
;
unsigned
char
dummy_info
[]
=
"(8:313233342:43)"
;
key
=
read_key
(
fname
);
if
(
!
key
)
return
;
rc
=
agent_shadow_key
(
key
,
dummy_info
,
&
result
);
xfree
(
key
);
if
(
rc
)
{
log_error
(
"shadowing the key failed: %s
\n
"
,
gpg_strerror
(
rc
));
return
;
}
resultlen
=
gcry_sexp_canon_len
(
result
,
0
,
NULL
,
NULL
);
assert
(
resultlen
);
if
(
opt_armor
)
{
char
*
p
=
make_advanced
(
result
,
resultlen
);
xfree
(
result
);
if
(
!
p
)
return
;
result
=
(
unsigned
char
*
)
p
;
resultlen
=
strlen
(
p
);
}
fwrite
(
result
,
resultlen
,
1
,
stdout
);
xfree
(
result
);
}
static
void
show_shadow_info
(
const
char
*
fname
)
{
int
rc
;
unsigned
char
*
key
;
const
unsigned
char
*
info
;
size_t
infolen
;
key
=
read_key
(
fname
);
if
(
!
key
)
return
;
rc
=
agent_get_shadow_info
(
key
,
&
info
);
xfree
(
key
);
if
(
rc
)
{
log_error
(
"get_shadow_info failed: %s
\n
"
,
gpg_strerror
(
rc
));
return
;
}
infolen
=
gcry_sexp_canon_len
(
info
,
0
,
NULL
,
NULL
);
assert
(
infolen
);
if
(
opt_armor
)
{
char
*
p
=
make_advanced
(
info
,
infolen
);
if
(
!
p
)
return
;
fwrite
(
p
,
strlen
(
p
),
1
,
stdout
);
xfree
(
p
);
}
else
fwrite
(
info
,
infolen
,
1
,
stdout
);
}
static
void
show_file
(
const
char
*
fname
)
{
unsigned
char
*
key
;
size_t
keylen
;
char
*
p
;
key
=
read_key
(
fname
);
if
(
!
key
)
return
;
keylen
=
gcry_sexp_canon_len
(
key
,
0
,
NULL
,
NULL
);
assert
(
keylen
);
if
(
opt_canonical
)
{
fwrite
(
key
,
keylen
,
1
,
stdout
);
}
else
{
p
=
make_advanced
(
key
,
keylen
);
if
(
p
)
{
fwrite
(
p
,
strlen
(
p
),
1
,
stdout
);
xfree
(
p
);
}
}
xfree
(
key
);
}
static
void
show_keygrip
(
const
char
*
fname
)
{
unsigned
char
*
key
;
gcry_sexp_t
private
;
unsigned
char
grip
[
20
];
int
i
;
key
=
read_key
(
fname
);
if
(
!
key
)
return
;
if
(
gcry_sexp_new
(
&
private
,
key
,
0
,
0
))
{
log_error
(
"gcry_sexp_new failed
\n
"
);
return
;
}
xfree
(
key
);
if
(
!
gcry_pk_get_keygrip
(
private
,
grip
))
{
log_error
(
"can't calculate keygrip
\n
"
);
return
;
}
gcry_sexp_release
(
private
);
for
(
i
=
0
;
i
<
20
;
i
++
)
printf
(
"%02X"
,
grip
[
i
]);
putchar
(
'\n'
);
}
int
main
(
int
argc
,
char
**
argv
)
{
ARGPARSE_ARGS
pargs
;
int
cmd
=
0
;
const
char
*
fname
;
early_system_init
();
set_strusage
(
my_strusage
);
gcry_control
(
GCRYCTL_SUSPEND_SECMEM_WARN
);
log_set_prefix
(
"gpg-protect-tool"
,
1
);
/* Make sure that our subsystems are ready. */
i18n_init
();
init_common_subsystems
(
&
argc
,
&
argv
);
if
(
!
gcry_check_version
(
NEED_LIBGCRYPT_VERSION
)
)
{
log_fatal
(
_
(
"%s is too old (need %s, have %s)
\n
"
),
"libgcrypt"
,
NEED_LIBGCRYPT_VERSION
,
gcry_check_version
(
NULL
)
);
}
setup_libgcrypt_logging
();
gcry_control
(
GCRYCTL_INIT_SECMEM
,
16384
,
0
);
opt_homedir
=
default_homedir
();
pargs
.
argc
=
&
argc
;
pargs
.
argv
=
&
argv
;
pargs
.
flags
=
1
;
/* (do not remove the args) */
while
(
arg_parse
(
&
pargs
,
opts
)
)
{
switch
(
pargs
.
r_opt
)
{
case
oVerbose
:
opt
.
verbose
++
;
break
;
case
oArmor
:
opt_armor
=
1
;
break
;
case
oCanonical
:
opt_canonical
=
1
;
break
;
case
oHomedir
:
opt_homedir
=
pargs
.
r
.
ret_str
;
break
;
case
oAgentProgram
:
opt_agent_program
=
pargs
.
r
.
ret_str
;
break
;
case
oProtect
:
cmd
=
oProtect
;
break
;
case
oUnprotect
:
cmd
=
oUnprotect
;
break
;
case
oShadow
:
cmd
=
oShadow
;
break
;
case
oShowShadowInfo
:
cmd
=
oShowShadowInfo
;
break
;
case
oShowKeygrip
:
cmd
=
oShowKeygrip
;
break
;
case
oS2Kcalibration
:
cmd
=
oS2Kcalibration
;
break
;
case
oPassphrase
:
opt_passphrase
=
pargs
.
r
.
ret_str
;
break
;
case
oStore
:
opt_store
=
1
;
break
;
case
oForce
:
opt_force
=
1
;
break
;
case
oNoFailOnExist
:
opt_no_fail_on_exist
=
1
;
break
;
case
oHaveCert
:
opt_have_cert
=
1
;
break
;
case
oPrompt
:
opt_prompt
=
pargs
.
r
.
ret_str
;
break
;
case
oStatusMsg
:
opt_status_msg
=
1
;
break
;
default
:
pargs
.
err
=
ARGPARSE_PRINT_ERROR
;
break
;
}
}
if
(
log_get_errorcount
(
0
))
exit
(
2
);
fname
=
"-"
;
if
(
argc
==
1
)
fname
=
*
argv
;
else
if
(
argc
>
1
)
usage
(
1
);
/* Set the information which can't be taken from envvars. */
gnupg_prepare_get_passphrase
(
GPG_ERR_SOURCE_DEFAULT
,
opt
.
verbose
,
opt_homedir
,
opt_agent_program
,
NULL
,
NULL
,
NULL
);
if
(
opt_prompt
)
opt_prompt
=
percent_plus_unescape
(
opt_prompt
,
0
);
if
(
cmd
==
oProtect
)
read_and_protect
(
fname
);
else
if
(
cmd
==
oUnprotect
)
read_and_unprotect
(
fname
);
else
if
(
cmd
==
oShadow
)
read_and_shadow
(
fname
);
else
if
(
cmd
==
oShowShadowInfo
)
show_shadow_info
(
fname
);
else
if
(
cmd
==
oShowKeygrip
)
show_keygrip
(
fname
);
else
if
(
cmd
==
oS2Kcalibration
)
{
if
(
!
opt
.
verbose
)
opt
.
verbose
++
;
/* We need to see something. */
get_standard_s2k_count
();
}
else
show_file
(
fname
);
agent_exit
(
0
);
return
8
;
/*NOTREACHED*/
}
void
agent_exit
(
int
rc
)
{
rc
=
rc
?
rc
:
log_get_errorcount
(
0
)
?
2
:
0
;
exit
(
rc
);
}
/* Return the passphrase string and ask the agent if it has not been
set from the command line PROMPTNO select the prompt to display:
0 = default
1 = taken from the option --prompt
2 = for unprotecting a pkcs#12 object
3 = for protecting a new pkcs#12 object
4 = for protecting an imported pkcs#12 in our system
*/
static
char
*
get_passphrase
(
int
promptno
)
{
char
*
pw
;
int
err
;
const
char
*
desc
;
char
*
orig_codeset
;
int
repeat
=
0
;
if
(
opt_passphrase
)
return
xstrdup
(
opt_passphrase
);
orig_codeset
=
i18n_switchto_utf8
();
if
(
promptno
==
1
&&
opt_prompt
)
{
desc
=
opt_prompt
;
}
else
if
(
promptno
==
2
)
{
desc
=
_
(
"Please enter the passphrase to unprotect the "
"PKCS#12 object."
);
}
else
if
(
promptno
==
3
)
{
desc
=
_
(
"Please enter the passphrase to protect the "
"new PKCS#12 object."
);
repeat
=
1
;
}
else
if
(
promptno
==
4
)
{
desc
=
_
(
"Please enter the passphrase to protect the "
"imported object within the GnuPG system."
);
repeat
=
1
;
}
else
desc
=
_
(
"Please enter the passphrase or the PIN
\n
"
"needed to complete this operation."
);
i18n_switchback
(
orig_codeset
);
err
=
gnupg_get_passphrase
(
NULL
,
NULL
,
_
(
"Passphrase:"
),
desc
,
repeat
,
repeat
,
1
,
&
pw
);
if
(
err
)
{
if
(
gpg_err_code
(
err
)
==
GPG_ERR_CANCELED
||
gpg_err_code
(
err
)
==
GPG_ERR_FULLY_CANCELED
)
log_info
(
_
(
"cancelled
\n
"
));
else
log_error
(
_
(
"error while asking for the passphrase: %s
\n
"
),
gpg_strerror
(
err
));
agent_exit
(
0
);
}
assert
(
pw
);
return
pw
;
}
static
void
release_passphrase
(
char
*
pw
)
{
if
(
pw
)
{
wipememory
(
pw
,
strlen
(
pw
));
xfree
(
pw
);
}
}
/* Stub function. */
gpg_error_t
convert_from_openpgp_native
(
gcry_sexp_t
s_pgp
,
const
char
*
passphrase
,
unsigned
char
**
r_key
)
{
(
void
)
s_pgp
;
(
void
)
passphrase
;
(
void
)
r_key
;
return
gpg_error
(
GPG_ERR_BUG
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Mon, May 12, 6:47 PM (16 h, 7 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
f6/89/987f03c37981778588ebbd1996b1
Attached To
rG GnuPG
Event Timeline
Log In to Comment