Signing using Netkey 3 cards does now work.

This commit is contained in:
Werner Koch 2009-03-26 19:27:04 +00:00
parent 6e63e54b00
commit 990585ad7d
14 changed files with 153 additions and 49 deletions

2
NEWS
View File

@ -17,6 +17,8 @@ Noteworthy changes in version 2.0.12 (not released)
* Better synchronization of several smartcard sessions.
* Support for the Telesec Netkey 3 cards.
Noteworthy changes in version 2.0.11 (2009-03-03)
-------------------------------------------------

View File

@ -1,5 +1,9 @@
2009-03-26 Werner Koch <wk@g10code.com>
* agent.h (MAX_DIGEST_LEN): Change to 64.
* command.c (cmd_sethash): Allow digest length of 48 and 64.
(cmd_sethash): Allow more hash algos.
* trustlist.c (reformat_name): New.
(agent_marktrusted): Use a reformatted name. Reload the table
before the update and always reload it at the end.

View File

@ -42,7 +42,7 @@
#define MD_USER_TLS_MD5SHA1 (GCRY_MODULE_ID_USER+1)
/* Maximum length of a digest. */
#define MAX_DIGEST_LEN 36
#define MAX_DIGEST_LEN 64
/* A large struct name "opt" to keep global flags */
struct

View File

@ -637,8 +637,14 @@ cmd_sethash (assuan_context_t ctx, char *line)
{
if (has_option (line, "--hash=sha1"))
algo = GCRY_MD_SHA1;
else if (has_option (line, "--hash=sha224"))
algo = GCRY_MD_SHA224;
else if (has_option (line, "--hash=sha256"))
algo = GCRY_MD_SHA256;
else if (has_option (line, "--hash=sha384"))
algo = GCRY_MD_SHA384;
else if (has_option (line, "--hash=sha512"))
algo = GCRY_MD_SHA512;
else if (has_option (line, "--hash=rmd160"))
algo = GCRY_MD_RMD160;
else if (has_option (line, "--hash=md5"))
@ -671,7 +677,8 @@ cmd_sethash (assuan_context_t ctx, char *line)
n /= 2;
if (algo == MD_USER_TLS_MD5SHA1 && n == 36)
;
else if (n != 16 && n != 20 && n != 24 && n != 32)
else if (n != 16 && n != 20 && n != 24
&& n != 28 && n != 32 && n != 48 && n != 64)
return set_error (GPG_ERR_ASS_PARAMETER, "unsupported length of hash");
if (n > MAX_DIGEST_LEN)

View File

@ -568,6 +568,12 @@ encryption. For convenience the strings @code{3DES}, @code{AES} and
@code{AES256} may be used instead of their OIDs. The default is
@code{3DES} (1.2.840.113549.3.7).
@item --digest-algo @code{name}
Use @code{name} as the message digest algorithm. Usually this
algorithm is deduced from the respective signing certificate. This
option forces the use of the given algorithm and may lead to severe
interoperability problems.
@end table

View File

@ -1,3 +1,16 @@
2009-03-26 Werner Koch <wk@g10code.com>
* command.c (cmd_pksign): Allow more hash algorithms.
* scdaemon.h (MAX_DIGEST_LEN): Change to 64.
* apdu.c (open_ccid_reader): Clear the is_to flag.
* app-nks.c (filelist): Add field KID.
(do_getattr): Change standard authentication key.
(do_sign): Setup a security environment for TCOS 3 cards and support
all SHA-2 algorithms.
2009-03-24 Werner Koch <wk@g10code.com>
* command.c (struct server_local_s): Add flag

View File

@ -1951,6 +1951,9 @@ open_ccid_reader (const char *portstr)
reader_table[slot].send_apdu_reader = send_apdu_ccid;
reader_table[slot].check_keypad = check_ccid_keypad;
reader_table[slot].dump_status_reader = dump_ccid_reader_status;
/* Our CCID reader code does not support T=0 at all, thus reset the
flag. */
reader_table[slot].is_t0 = 0;
dump_reader_status (slot);
return slot;
@ -2839,10 +2842,10 @@ send_le (int slot, int class, int ins, int p0, int p1,
if (lc != -1 && (lc > 255 || lc < 0))
{
/* Data does not fit into an APDU. What we do now dependes on
/* Data does not fit into an APDU. What we do now depends on
the EXTENDED_MODE parameter. */
if (!extended_mode)
return SW_WRONG_LENGTH; /* No way. to send such an APDU. */
return SW_WRONG_LENGTH; /* No way to send such an APDU. */
else if (extended_mode > 0)
return SW_HOST_NOT_SUPPORTED; /* FIXME. */
else if (extended_mode < 0)

View File

@ -19,10 +19,11 @@
/* Notes:
- This is still work in progress. We are now targeting TCOS 3 cards
but try to keep compatibility to TCOS 2. Both are not fully
working as of now. TCOS 3 PIN management seems to work. Use GPA
from SVN trunk to test it.
- We are now targeting TCOS 3 cards and it may happen that there is
a regression towards TCOS 2 cards. Please report.
- The TKS3 AUT key is not used by our authentication command but
accessible via the decrypt command.
- If required, we automagically switch between the NKS application
and the SigG application. This avoids to use the DINSIG
@ -63,25 +64,26 @@ static struct
int fid; /* File ID. */
int nks_ver; /* 0 for NKS version 2, 3 for version 3. */
int certtype; /* Type of certificate or 0 if it is not a certificate. */
int iskeypair; /* If true has the FID of the correspoding certificate. */
int iskeypair; /* If true has the FID of the corresponding certificate. */
int issignkey; /* True if file is a key usable for signing. */
int isenckey; /* True if file is a key usable for decryption. */
unsigned char kid; /* Corresponding key references. */
} filelist[] = {
{ 0, 0x4531, 0, 0, 0xC000, 1, 0 }, /* EF_PK.NKS.SIG */
{ 1, 0x4531, 3, 0, 0x0000, 1, 1 }, /* EF_PK.CH.SIG */
{ 0, 0xC000, 0, 101 }, /* EF_C.NKS.SIG */
{ 1, 0xC000, 0, 101 }, /* EF_C.CH.SIG */
{ 0, 0x4531, 0, 0, 0xC000, 1, 0, 0x80 }, /* EF_PK.NKS.SIG */
{ 1, 0x4531, 3, 0, 0x0000, 1, 1, 0x84 }, /* EF_PK.CH.SIG */
{ 0, 0xC000, 0, 101 }, /* EF_C.NKS.SIG */
{ 1, 0xC000, 0, 101 }, /* EF_C.CH.SIG */
{ 0, 0x4331, 0, 100 },
{ 0, 0x4332, 0, 100 },
{ 0, 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */
{ 0, 0x45B1, 0, 0, 0xC200, 0, 1 }, /* EF_PK.NKS.ENC */
{ 0, 0xC200, 0, 101 }, /* EF_C.NKS.ENC */
{ 0, 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */
{ 0, 0x45B1, 0, 0, 0xC200, 0, 1, 0x81 }, /* EF_PK.NKS.ENC */
{ 0, 0xC200, 0, 101 }, /* EF_C.NKS.ENC */
{ 0, 0x43B1, 0, 100 },
{ 0, 0x43B2, 0, 100 },
{ 0, 0x4571, 3, 0, 0xc500, 0, 0 }, /* EF_PK.NKS.AUT */
{ 0, 0xC500, 3, 101 }, /* EF_C.NKS.AUT */
{ 0, 0x45B2, 3, 0, 0xC201, 0, 1 }, /* EF_PK.NKS.ENC1024 */
{ 0, 0xC201, 3, 101 }, /* EF_C.NKS.ENC1024 */
{ 0, 0x4571, 3, 0, 0xc500, 0, 0, 0x82 }, /* EF_PK.NKS.AUT */
{ 0, 0xC500, 3, 101 }, /* EF_C.NKS.AUT */
{ 0, 0x45B2, 3, 0, 0xC201, 0, 1, 0x83 }, /* EF_PK.NKS.ENC1024 */
{ 0, 0xC201, 3, 101 }, /* EF_C.NKS.ENC1024 */
/* { 1, 0xB000, 3, ... */
{ 0, 0 }
};
@ -303,10 +305,12 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
{
case 1: /* $AUTHKEYID */
{
/* NetKey 3.0 cards define this key for authentication.
FIXME: We don't have the readkey command, so this
information is pretty useless. */
char const tmp[] = "NKS-NKS3.4571";
/* NetKey 3.0 cards define an authentication key but according
to the specs this key is only usable for encryption and not
signing. it might work anyway but it has not yet been
tested - fixme. Thus for now we use the NKS signature key
for authentication. */
char const tmp[] = "NKS-NKS3.4531";
send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
}
break;
@ -685,13 +689,18 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
int rc, i;
int is_sigg = 0;
int fid;
unsigned char data[35]; /* Must be large enough for a SHA-1 digest
+ the largest OID _prefix above. */
unsigned char kid;
unsigned char data[83]; /* Must be large enough for a SHA-1 digest
+ the largest OID prefix. */
size_t datalen;
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
if (indatalen != 20 && indatalen != 16 && indatalen != 35)
return gpg_error (GPG_ERR_INV_VALUE);
switch (indatalen)
{
case 16: case 20: case 35: case 47: case 51: case 67: case 83: break;
default: return gpg_error (GPG_ERR_INV_VALUE);
}
/* Check that the provided ID is valid. This is not really needed
but we do it to enforce correct usage by the caller. */
@ -721,22 +730,35 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
return gpg_error (GPG_ERR_NOT_FOUND);
if (!filelist[i].issignkey)
return gpg_error (GPG_ERR_INV_ID);
kid = filelist[i].kid;
/* Prepare the DER object from INDATA. */
if (indatalen == 35)
/* Prepare the DER object from INDATA. */
if (app->app_local->nks_version > 2 && (indatalen == 35
|| indatalen == 47
|| indatalen == 51
|| indatalen == 67
|| indatalen == 83))
{
/* The caller send data matching the length of the ASN.1 encoded
hash for SHA-{1,224,256,384,512}. Assume that is okay. */
assert (indatalen <= sizeof data);
memcpy (data, indata, indatalen);
datalen = indatalen;
}
else if (indatalen == 35)
{
/* Alright, the caller was so kind to send us an already
prepared DER object. Check that it is waht we want and that
it matches the hash algorithm. */
prepared DER object. This is for TCOS 2. */
if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15))
;
else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15))
else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata,rmd160_prefix,15))
;
else
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
memcpy (data, indata, indatalen);
datalen = 35;
}
else
else if (indatalen == 20)
{
if (hashalgo == GCRY_MD_SHA1)
memcpy (data, sha1_prefix, 15);
@ -745,11 +767,32 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
else
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
memcpy (data+15, indata, indatalen);
datalen = 35;
}
else
return gpg_error (GPG_ERR_INV_VALUE);
rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
/* Send an MSE for PSO:Computer_Signature. */
if (app->app_local->nks_version > 2)
{
unsigned char mse[6];
mse[0] = 0x80; /* Algorithm reference. */
mse[1] = 1;
mse[2] = 2; /* RSA, card does pkcs#1 v1.5 padding, no ASN.1 check. */
mse[3] = 0x84; /* Private key reference. */
mse[4] = 1;
mse[5] = kid;
rc = iso7816_manage_security_env (app->slot, 0x41, 0xB6,
mse, sizeof mse);
}
/* Verify using PW1.CH. */
if (!rc)
rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
/* Compute the signature. */
if (!rc)
rc = iso7816_compute_ds (app->slot, data, datalen, outdata, outdatalen);
return rc;
}

View File

@ -905,7 +905,7 @@ pin_cb (void *opaque, const char *info, char **retstr)
}
/* PKSIGN [--hash=[rmd160|sha1|md5]] <hexified_id>
/* PKSIGN [--hash=[rmd160|sha{1,224,256,384,512}|md5]] <hexified_id>
The --hash option is optional; the default is SHA1.
@ -924,6 +924,14 @@ cmd_pksign (assuan_context_t ctx, char *line)
hash_algo = GCRY_MD_RMD160;
else if (has_option (line, "--hash=sha1"))
hash_algo = GCRY_MD_SHA1;
else if (has_option (line, "--hash=sha224"))
hash_algo = GCRY_MD_SHA224;
else if (has_option (line, "--hash=sha256"))
hash_algo = GCRY_MD_SHA256;
else if (has_option (line, "--hash=sha384"))
hash_algo = GCRY_MD_SHA384;
else if (has_option (line, "--hash=sha512"))
hash_algo = GCRY_MD_SHA512;
else if (has_option (line, "--hash=md5"))
hash_algo = GCRY_MD_MD5;
else if (!strstr (line, "--"))

View File

@ -39,7 +39,7 @@
#define MD_USER_TLS_MD5SHA1 (GCRY_MODULE_ID_USER+1)
/* Maximum length of a digest. */
#define MAX_DIGEST_LEN 36
#define MAX_DIGEST_LEN 64

View File

@ -1,5 +1,12 @@
2009-03-26 Werner Koch <wk@g10code.com>
* gpgsm.c (main): s/def_digest_string/forced_digest_algo/ and
activate the --digest-algo option.
* gpgsm.h (struct opt): s/def_digest_algo/forced_digest_algo/.
* sign.c (gpgsm_sign): Implement --digest-algo.
* sign.c (MAX_DIGEST_LEN): Change to 64.
* call-agent.c (gpgsm_agent_marktrusted): Format the issuer name.
2009-03-25 Werner Koch <wk@g10code.com>

View File

@ -843,8 +843,8 @@ main ( int argc, char **argv)
int use_random_seed = 1;
int no_common_certs_import = 0;
int with_fpr = 0;
char *def_digest_string = NULL;
char *extra_digest_algo = NULL;
const char *forced_digest_algo = NULL;
const char *extra_digest_algo = NULL;
enum cmd_and_opt_values cmd = 0;
struct server_control_s ctrl;
certlist_t recplist = NULL;
@ -1301,7 +1301,7 @@ main ( int argc, char **argv)
break;
case oDigestAlgo:
/* Dummy for now. */
forced_digest_algo = pargs.r.ret_str;
break;
case oExtraDigestAlgo:
@ -1460,12 +1460,10 @@ main ( int argc, char **argv)
|| !gcry_cipher_mode_from_oid (opt.def_cipher_algoid))
log_error (_("selected cipher algorithm is invalid\n"));
if (def_digest_string)
if (forced_digest_algo)
{
opt.def_digest_algo = gcry_md_map_name (def_digest_string);
xfree (def_digest_string);
def_digest_string = NULL;
if (our_md_test_algo(opt.def_digest_algo) )
opt.forced_digest_algo = gcry_md_map_name (forced_digest_algo);
if (our_md_test_algo(opt.forced_digest_algo) )
log_error (_("selected digest algorithm is invalid\n"));
}
if (extra_digest_algo)

View File

@ -33,7 +33,7 @@
#include "../common/estream.h"
#include "../common/audit.h"
#define MAX_DIGEST_LEN 24
#define MAX_DIGEST_LEN 64
struct keyserver_spec
{
@ -92,9 +92,10 @@ struct
const char *def_cipher_algoid; /* cipher algorithm to use if
nothing else is specified */
int def_digest_algo; /* Ditto for hash algorithm */
int def_compress_algo; /* Ditto for compress algorithm */
int forced_digest_algo; /* User forced hash algorithm. */
char *def_recipient; /* userID of the default recipient */
int def_recipient_self; /* The default recipient is the default key */

View File

@ -399,11 +399,22 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
/* Figure out the hash algorithm to use. We do not want to use the
one for the certificate but if possible an OID for the plain
algorithm. */
if (opt.forced_digest_algo && opt.verbose)
log_info ("user requested hash algorithm %d\n", opt.forced_digest_algo);
for (i=0, cl=signerlist; cl; cl = cl->next, i++)
{
const char *oid = ksba_cert_get_digest_algo (cl->cert);
cl->hash_algo = oid ? gcry_md_map_name (oid) : 0;
if (opt.forced_digest_algo)
{
oid = NULL;
cl->hash_algo = opt.forced_digest_algo;
}
else
{
oid = ksba_cert_get_digest_algo (cl->cert);
cl->hash_algo = oid ? gcry_md_map_name (oid) : 0;
}
switch (cl->hash_algo)
{
case GCRY_MD_SHA1: oid = "1.3.14.3.2.26"; break;
@ -427,6 +438,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
}
cl->hash_algo_oid = oid;
}
if (opt.verbose)
{
for (i=0, cl=signerlist; cl; cl = cl->next, i++)