mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
scd:nks: Support decryption using ECDH.
* scd/app-nks.c (struct fid_cache_s): Add field 'algo'. (keygripstr_from_pk_file): Add arg 'r_algo' to return the algo. (find_fid_by_keyref): Ditto. (get_dispserialno): New. (make_prompt): New. (verify_pin): Provide better prompts. (do_decipher): Support ECDH. (parse_pwidstr): Add hack tospecify any pwid.. (do_change_pin): Support Signature Card V2.0 (NKS15) style NullPIN. Provide a better prompt. -- GnuPG-bug-id: 4938 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
ee6d29f179
commit
af45d884aa
382
scd/app-nks.c
382
scd/app-nks.c
@ -19,30 +19,53 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Notes:
|
/* Notes:
|
||||||
|
*
|
||||||
- We are now targeting TCOS 3 cards and it may happen that there is
|
* - We are now targeting TCOS 3 cards and it may happen that there is
|
||||||
a regression towards TCOS 2 cards. Please report.
|
* a regression towards TCOS 2 cards. Please report.
|
||||||
|
*
|
||||||
- The NKS3 AUT key is not used. It seems that it is only useful for
|
* - The NKS3 AUT key is not used. It seems that it is only useful for
|
||||||
the internal authentication command and not accessible by other
|
* the internal authentication command and not accessible by other
|
||||||
applications. The key itself is in the encryption class but the
|
* applications. The key itself is in the encryption class but the
|
||||||
corresponding certificate has only the digitalSignature
|
* corresponding certificate has only the digitalSignature
|
||||||
capability.
|
* capability.
|
||||||
Update: This changed for the Signature Card V2 (nks version 15)
|
* Update: This changed for the Signature Card V2 (nks version 15)
|
||||||
|
*
|
||||||
- If required, we automagically switch between the NKS application
|
* - If required, we automagically switch between the NKS application
|
||||||
and the SigG or eSign application. This avoids to use the DINSIG
|
* and the SigG or eSign application. This avoids to use the DINSIG
|
||||||
application which is somewhat limited, has no support for Secure
|
* application which is somewhat limited, has no support for Secure
|
||||||
Messaging as required by TCOS 3 and has no way to change the PIN
|
* Messaging as required by TCOS 3 and has no way to change the PIN
|
||||||
or even set the NullPIN. With the Signature Card v2 (nks version
|
* or even set the NullPIN. With the Signature Card v2 (nks version
|
||||||
15) the Esign application is used instead of the SigG.
|
* 15) the Esign application is used instead of the SigG.
|
||||||
|
*
|
||||||
- We use the prefix NKS-DF01 for TCOS 2 cards and NKS-NKS3 for newer
|
* - We use the prefix NKS-DF01 for TCOS 2 cards and NKS-NKS3 for newer
|
||||||
cards. This is because the NKS application has moved to DF02 with
|
* cards. This is because the NKS application has moved to DF02 with
|
||||||
TCOS 3 and thus we better use a DF independent tag.
|
* TCOS 3 and thus we better use a DF independent tag.
|
||||||
|
*
|
||||||
- We use only the global PINs for the NKS application.
|
* - We use only the global PINs for the NKS application.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Here is a table with PIN stati collected from 3 cards.
|
||||||
|
*
|
||||||
|
* | app | pwid | NKS3 | SIG_B | SIG_N |
|
||||||
|
* |-----+------+-----------+-----------+-----------|
|
||||||
|
* | NKS | 0x00 | null - | - - | - - |
|
||||||
|
* | | 0x01 | 0 3 | - - | - - |
|
||||||
|
* | | 0x02 | 3 null | 15 3 | 15 null |
|
||||||
|
* | | 0x03 | - 3 | null - | null - |
|
||||||
|
* | SIG | 0x00 | null - | - - | - - |
|
||||||
|
* | | 0x01 | 0 null | - null | - null |
|
||||||
|
* | | 0x02 | 3 null | 15 0 | 15 0 |
|
||||||
|
* | | 0x03 | - 0 | null null | null null |
|
||||||
|
* - SIG is either SIGG or ESIGN.
|
||||||
|
* - "-" indicates reference not found (SW 6A88).
|
||||||
|
* - "null" indicates a NULLPIN (SW 6985).
|
||||||
|
* - The first value in each cell is the global PIN;
|
||||||
|
* the second is the local PIN (high bit of pwid set).
|
||||||
|
* - The NKS3 card is some older test card.
|
||||||
|
* - The SIG_B is a Signature Card V2.0 with Brainpool curves.
|
||||||
|
* Here the PIN 0x82 has been changed from the NULLPIN.
|
||||||
|
* - The SIG_N is a Signature Card V2.0 with NIST curves.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@ -139,7 +162,8 @@ static struct
|
|||||||
struct fid_cache_s {
|
struct fid_cache_s {
|
||||||
struct fid_cache_s *next;
|
struct fid_cache_s *next;
|
||||||
int fid; /* Zero for an unused slot. */
|
int fid; /* Zero for an unused slot. */
|
||||||
unsigned int got_keygrip:1; /* The keygrip is valid. */
|
unsigned int got_keygrip:1; /* The keygrip and algo are valid. */
|
||||||
|
int algo;
|
||||||
char keygripstr[2*KEYGRIP_LEN+1];
|
char keygripstr[2*KEYGRIP_LEN+1];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -205,15 +229,18 @@ all_zero_p (void *buffer, size_t length)
|
|||||||
* used and Read Record needs to be replaced by read binary. Given
|
* used and Read Record needs to be replaced by read binary. Given
|
||||||
* all the ECC parameters required, we don't do that but rely that the
|
* all the ECC parameters required, we don't do that but rely that the
|
||||||
* corresponding certificate at CFID is already available and get the
|
* corresponding certificate at CFID is already available and get the
|
||||||
* public key from there. */
|
* public key from there. If R_ALGO is not NULL the public key
|
||||||
|
* algorithm for the returned KEYGRIP is stored there. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr)
|
keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr,
|
||||||
|
int *r_algo)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
unsigned char grip[20];
|
unsigned char grip[20];
|
||||||
unsigned char *buffer[2];
|
unsigned char *buffer[2];
|
||||||
size_t buflen[2];
|
size_t buflen[2];
|
||||||
gcry_sexp_t sexp = NULL;
|
gcry_sexp_t sexp = NULL;
|
||||||
|
int algo = 0; /* Public key algo. */
|
||||||
int i;
|
int i;
|
||||||
int offset[2] = { 0, 0 };
|
int offset[2] = { 0, 0 };
|
||||||
struct fid_cache_s *ci;
|
struct fid_cache_s *ci;
|
||||||
@ -224,6 +251,8 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr)
|
|||||||
if (!ci->got_keygrip)
|
if (!ci->got_keygrip)
|
||||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||||
memcpy (r_gripstr, ci->keygripstr, 2*KEYGRIP_LEN+1);
|
memcpy (r_gripstr, ci->keygripstr, 2*KEYGRIP_LEN+1);
|
||||||
|
if (r_algo)
|
||||||
|
*r_algo = ci->algo;
|
||||||
return 0; /* Found in cache. */
|
return 0; /* Found in cache. */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +280,7 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = app_help_get_keygrip_string_pk (pk, pklen, r_gripstr, NULL, NULL);
|
err = app_help_get_keygrip_string_pk (pk, pklen, r_gripstr, NULL, &algo);
|
||||||
xfree (pk);
|
xfree (pk);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("nks: error getting keygrip for certificate %04X: %s\n",
|
log_error ("nks: error getting keygrip for certificate %04X: %s\n",
|
||||||
@ -333,6 +362,7 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
algo = GCRY_PK_RSA;
|
||||||
if (!err)
|
if (!err)
|
||||||
err = gcry_sexp_build (&sexp, NULL,
|
err = gcry_sexp_build (&sexp, NULL,
|
||||||
"(public-key (rsa (n %b) (e %b)))",
|
"(public-key (rsa (n %b) (e %b)))",
|
||||||
@ -352,6 +382,8 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
bin2hex (grip, 20, r_gripstr);
|
bin2hex (grip, 20, r_gripstr);
|
||||||
|
if (r_algo)
|
||||||
|
*r_algo = algo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -363,8 +395,9 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr)
|
|||||||
if (ci->fid && ci->fid == pkfid)
|
if (ci->fid && ci->fid == pkfid)
|
||||||
{
|
{
|
||||||
/* Update the keygrip. */
|
/* Update the keygrip. */
|
||||||
ci->got_keygrip = 1;
|
|
||||||
memcpy (ci->keygripstr, r_gripstr, 2*KEYGRIP_LEN+1);
|
memcpy (ci->keygripstr, r_gripstr, 2*KEYGRIP_LEN+1);
|
||||||
|
ci->algo = algo;
|
||||||
|
ci->got_keygrip = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!ci)
|
if (!ci)
|
||||||
@ -380,6 +413,7 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr)
|
|||||||
{
|
{
|
||||||
ci->fid = pkfid;
|
ci->fid = pkfid;
|
||||||
memcpy (ci->keygripstr, r_gripstr, 2*KEYGRIP_LEN+1);
|
memcpy (ci->keygripstr, r_gripstr, 2*KEYGRIP_LEN+1);
|
||||||
|
ci->algo = algo;
|
||||||
ci->got_keygrip = 1;
|
ci->got_keygrip = 1;
|
||||||
ci->next = app->app_local->fid_cache;
|
ci->next = app->app_local->fid_cache;
|
||||||
app->app_local->fid_cache = ci;
|
app->app_local->fid_cache = ci;
|
||||||
@ -392,9 +426,10 @@ keygripstr_from_pk_file (app_t app, int pkfid, int cfid, char *r_gripstr)
|
|||||||
|
|
||||||
|
|
||||||
/* Parse KEYREF and return the index into the FILELIST at R_IDX.
|
/* Parse KEYREF and return the index into the FILELIST at R_IDX.
|
||||||
* Returns 0 on success and switches to the requested application. */
|
* Returns 0 on success and switches to the requested application.
|
||||||
|
* The public key algo is stored at R_ALGO unless it is NULL. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
find_fid_by_keyref (app_t app, const char *keyref, int *r_idx)
|
find_fid_by_keyref (app_t app, const char *keyref, int *r_idx, int *r_algo)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
int idx, fid, nks_app_id;
|
int idx, fid, nks_app_id;
|
||||||
@ -407,7 +442,7 @@ find_fid_by_keyref (app_t app, const char *keyref, int *r_idx)
|
|||||||
struct fid_cache_s *ci;
|
struct fid_cache_s *ci;
|
||||||
|
|
||||||
for (ci = app->app_local->fid_cache; ci; ci = ci->next)
|
for (ci = app->app_local->fid_cache; ci; ci = ci->next)
|
||||||
if (ci->fid && ci->got_keygrip && !strcmp (ci->keygripstr, keygripstr))
|
if (ci->fid && ci->got_keygrip && !strcmp (ci->keygripstr, keyref))
|
||||||
break;
|
break;
|
||||||
if (ci) /* Cached */
|
if (ci) /* Cached */
|
||||||
{
|
{
|
||||||
@ -423,6 +458,8 @@ find_fid_by_keyref (app_t app, const char *keyref, int *r_idx)
|
|||||||
err = switch_application (app, filelist[idx].nks_app_id);
|
err = switch_application (app, filelist[idx].nks_app_id);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
if (r_algo)
|
||||||
|
*r_algo = ci->algo;
|
||||||
}
|
}
|
||||||
else /* Not cached. */
|
else /* Not cached. */
|
||||||
{
|
{
|
||||||
@ -440,10 +477,10 @@ find_fid_by_keyref (app_t app, const char *keyref, int *r_idx)
|
|||||||
|
|
||||||
err = keygripstr_from_pk_file (app, filelist[idx].fid,
|
err = keygripstr_from_pk_file (app, filelist[idx].fid,
|
||||||
filelist[idx].iskeypair,
|
filelist[idx].iskeypair,
|
||||||
keygripstr);
|
keygripstr, r_algo);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_info ("nks: no keygrip for FID 0x%04X: %s\n",
|
log_info ("nks: no keygrip for FID 0x%04X: %s - ignored\n",
|
||||||
filelist[idx].fid, gpg_strerror (err));
|
filelist[idx].fid, gpg_strerror (err));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -502,6 +539,16 @@ find_fid_by_keyref (app_t app, const char *keyref, int *r_idx)
|
|||||||
err = switch_application (app, nks_app_id);
|
err = switch_application (app, nks_app_id);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
if (r_algo)
|
||||||
|
{
|
||||||
|
/* We need to get the public key algo. */
|
||||||
|
err = keygripstr_from_pk_file (app, filelist[idx].fid,
|
||||||
|
filelist[idx].iskeypair,
|
||||||
|
keygripstr, r_algo);
|
||||||
|
if (err)
|
||||||
|
log_error ("nks: no keygrip for FID 0x%04X: %s\n",
|
||||||
|
filelist[idx].fid, gpg_strerror (err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
@ -679,7 +726,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags,
|
|||||||
int usageidx = 0;
|
int usageidx = 0;
|
||||||
|
|
||||||
err = keygripstr_from_pk_file (app, filelist[i].fid,
|
err = keygripstr_from_pk_file (app, filelist[i].fid,
|
||||||
filelist[i].iskeypair, gripstr);
|
filelist[i].iskeypair, gripstr, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("can't get keygrip from FID 0x%04X: %s\n",
|
log_error ("can't get keygrip from FID 0x%04X: %s\n",
|
||||||
filelist[i].fid, gpg_strerror (err));
|
filelist[i].fid, gpg_strerror (err));
|
||||||
@ -1045,6 +1092,79 @@ do_writekey (app_t app, ctrl_t ctrl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return an allocated string with the serial number in a format to be
|
||||||
|
* show to the user. May return NULL on malloc problem. */
|
||||||
|
static char *
|
||||||
|
get_dispserialno (app_t app)
|
||||||
|
{
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
/* We only need to strip the last zero which is not printed on the
|
||||||
|
* card. */
|
||||||
|
result = app_get_serialno (app);
|
||||||
|
if (result && *result && result[strlen(result)-1] == '0')
|
||||||
|
result[strlen(result)-1] = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return an allocated string to be used as prompt. Returns NULL on
|
||||||
|
* malloc error. */
|
||||||
|
static char *
|
||||||
|
make_prompt (app_t app, int remaining, const char *firstline,
|
||||||
|
const char *extraline)
|
||||||
|
{
|
||||||
|
char *serial, *tmpbuf, *result;
|
||||||
|
|
||||||
|
serial = get_dispserialno (app);
|
||||||
|
|
||||||
|
/* TRANSLATORS: Put a \x1f right before a colon. This can be
|
||||||
|
* used by pinentry to nicely align the names and values. Keep
|
||||||
|
* the %s at the start and end of the string. */
|
||||||
|
result = xtryasprintf (_("%s"
|
||||||
|
"Number\x1f: %s%%0A"
|
||||||
|
"Holder\x1f: %s"
|
||||||
|
"%s"),
|
||||||
|
"\x1e",
|
||||||
|
serial,
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
xfree (serial);
|
||||||
|
if (!result)
|
||||||
|
return NULL; /* Out of core. */
|
||||||
|
|
||||||
|
/* Append a "remaining attempts" info if needed. */
|
||||||
|
if (remaining != -1 && remaining < 3)
|
||||||
|
{
|
||||||
|
char *rembuf;
|
||||||
|
|
||||||
|
/* TRANSLATORS: This is the number of remaining attempts to
|
||||||
|
* enter a PIN. Use %%0A (double-percent,0A) for a linefeed. */
|
||||||
|
rembuf = xtryasprintf (_("Remaining attempts: %d"), remaining);
|
||||||
|
if (rembuf)
|
||||||
|
{
|
||||||
|
tmpbuf = strconcat (firstline, "%0A%0A", result,
|
||||||
|
"%0A%0A", rembuf, NULL);
|
||||||
|
xfree (rembuf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tmpbuf = NULL;
|
||||||
|
xfree (result);
|
||||||
|
result = tmpbuf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmpbuf = strconcat (firstline, "%0A%0A", result,
|
||||||
|
extraline? "%0A%0A":"", extraline,
|
||||||
|
NULL);
|
||||||
|
xfree (result);
|
||||||
|
result = tmpbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
basic_pin_checks (const char *pinvalue, int minlen, int maxlen)
|
basic_pin_checks (const char *pinvalue, int minlen, int maxlen)
|
||||||
{
|
{
|
||||||
@ -1068,21 +1188,43 @@ verify_pin (app_t app, int pwid, const char *desc,
|
|||||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
pininfo_t pininfo;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
pininfo_t pininfo;
|
||||||
|
char *prompt;
|
||||||
|
const char *extrapromptline = NULL;
|
||||||
|
int remaining, nullpin;
|
||||||
|
|
||||||
if (!desc)
|
if (!desc)
|
||||||
desc = "PIN";
|
desc = "||PIN";
|
||||||
|
|
||||||
memset (&pininfo, 0, sizeof pininfo);
|
memset (&pininfo, 0, sizeof pininfo);
|
||||||
pininfo.fixedlen = -1;
|
pininfo.fixedlen = -1;
|
||||||
pininfo.minlen = 6;
|
pininfo.minlen = 6;
|
||||||
pininfo.maxlen = 16;
|
pininfo.maxlen = 16;
|
||||||
|
|
||||||
|
remaining = iso7816_verify_status (app_get_slot (app), pwid);
|
||||||
|
nullpin = (remaining == ISO7816_VERIFY_NULLPIN);
|
||||||
|
if (remaining < 0)
|
||||||
|
remaining = -1; /* We don't care about the concrete error. */
|
||||||
|
if (remaining < 3)
|
||||||
|
{
|
||||||
|
if (remaining >= 0)
|
||||||
|
log_info ("nks: PIN has %d attempts left\n", remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullpin)
|
||||||
|
{
|
||||||
|
log_info ("nks: The NullPIN for PIN 0x%02x has not yet been changed\n",
|
||||||
|
pwid);
|
||||||
|
extrapromptline = _("Note: You need to change the PIN first!");
|
||||||
|
}
|
||||||
|
|
||||||
if (!opt.disable_pinpad
|
if (!opt.disable_pinpad
|
||||||
&& !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) )
|
&& !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) )
|
||||||
{
|
{
|
||||||
rc = pincb (pincb_arg, desc, NULL);
|
prompt = make_prompt (app, remaining, desc, extrapromptline);
|
||||||
|
rc = pincb (pincb_arg, prompt, NULL);
|
||||||
|
xfree (prompt);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_info (_("PIN callback returned error: %s\n"),
|
log_info (_("PIN callback returned error: %s\n"),
|
||||||
@ -1097,7 +1239,9 @@ verify_pin (app_t app, int pwid, const char *desc,
|
|||||||
{
|
{
|
||||||
char *pinvalue;
|
char *pinvalue;
|
||||||
|
|
||||||
rc = pincb (pincb_arg, desc, &pinvalue);
|
prompt = make_prompt (app, remaining, desc, extrapromptline);
|
||||||
|
rc = pincb (pincb_arg, prompt, &pinvalue);
|
||||||
|
xfree (prompt);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
|
log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
|
||||||
@ -1161,7 +1305,7 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||||||
default: return gpg_error (GPG_ERR_INV_VALUE);
|
default: return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = find_fid_by_keyref (app, keyidstr, &idx);
|
err = find_fid_by_keyref (app, keyidstr, &idx, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -1258,6 +1402,10 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
|||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
int idx;
|
int idx;
|
||||||
int kid;
|
int kid;
|
||||||
|
int algo;
|
||||||
|
int pwid;
|
||||||
|
int padind;
|
||||||
|
int extended_mode;
|
||||||
|
|
||||||
(void)ctrl;
|
(void)ctrl;
|
||||||
(void)r_info;
|
(void)r_info;
|
||||||
@ -1265,7 +1413,7 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
|||||||
if (!indatalen)
|
if (!indatalen)
|
||||||
return gpg_error (GPG_ERR_INV_VALUE);
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
err = find_fid_by_keyref (app, keyidstr, &idx);
|
err = find_fid_by_keyref (app, keyidstr, &idx, &algo);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -1274,7 +1422,30 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
|||||||
|
|
||||||
kid = filelist[idx].kid;
|
kid = filelist[idx].kid;
|
||||||
|
|
||||||
if (app->app_local->nks_version > 2)
|
if (app->app_local->nks_version <= 2)
|
||||||
|
{
|
||||||
|
static const unsigned char mse[] =
|
||||||
|
{
|
||||||
|
0x80, 1, 0x10, /* Select algorithm RSA. */
|
||||||
|
0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
|
||||||
|
};
|
||||||
|
err = iso7816_manage_security_env (app_get_slot (app), 0xC1, 0xB8,
|
||||||
|
mse, sizeof mse);
|
||||||
|
extended_mode = 0;
|
||||||
|
padind = 0x81;
|
||||||
|
}
|
||||||
|
else if (algo == GCRY_PK_ECC)
|
||||||
|
{
|
||||||
|
unsigned char mse[3];
|
||||||
|
mse[0] = 0x84; /* Private key reference. */
|
||||||
|
mse[1] = 1;
|
||||||
|
mse[2] = kid;
|
||||||
|
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
|
||||||
|
mse, sizeof mse);
|
||||||
|
extended_mode = 0;
|
||||||
|
padind = 0x00;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
unsigned char mse[6];
|
unsigned char mse[6];
|
||||||
mse[0] = 0x80; /* Algorithm reference. */
|
mse[0] = 0x80; /* Algorithm reference. */
|
||||||
@ -1285,46 +1456,52 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
|||||||
mse[5] = kid;
|
mse[5] = kid;
|
||||||
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
|
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
|
||||||
mse, sizeof mse);
|
mse, sizeof mse);
|
||||||
|
extended_mode = 1;
|
||||||
|
padind = 0x81;
|
||||||
}
|
}
|
||||||
else
|
if (err)
|
||||||
{
|
{
|
||||||
static const unsigned char mse[] =
|
log_error ("nks: MSE failed: %s\n", gpg_strerror (err));
|
||||||
{
|
goto leave;
|
||||||
0x80, 1, 0x10, /* Select algorithm RSA. */
|
|
||||||
0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
|
|
||||||
};
|
|
||||||
err = iso7816_manage_security_env (app_get_slot (app), 0xC1, 0xB8,
|
|
||||||
mse, sizeof mse);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!err)
|
if (app->app_local->nks_version == 15)
|
||||||
err = verify_pin (app, 0, NULL, pincb, pincb_arg);
|
pwid = 0x03;
|
||||||
|
else
|
||||||
|
pwid = 0x00;
|
||||||
|
|
||||||
/* Note that we need to use extended length APDUs for TCOS 3 cards.
|
err = verify_pin (app, pwid, NULL, pincb, pincb_arg);
|
||||||
Command chaining does not work. */
|
if (err)
|
||||||
if (!err)
|
goto leave;
|
||||||
err = iso7816_decipher (app_get_slot (app),
|
|
||||||
app->app_local->nks_version > 2? 1:0,
|
err = iso7816_decipher (app_get_slot (app), extended_mode,
|
||||||
indata, indatalen, 0, 0x81,
|
indata, indatalen, 0, padind,
|
||||||
outdata, outdatalen);
|
outdata, outdatalen);
|
||||||
|
|
||||||
|
leave:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Parse a password ID string. Returns NULL on error or a string
|
/* Parse a password ID string. Returns NULL on error or a string
|
||||||
suitable as passphrase prompt on success. On success stores the
|
* suitable as passphrase prompt on success. On success stores the
|
||||||
reference value for the password at R_PWID and a flag indicating
|
* reference value for the password at R_PWID and a flag indicating
|
||||||
that the SigG application is to be used at R_SIGG. If NEW_MODE is
|
* which app is to be used at R_NKS_APP_ID. If NEW_MODE is true, the
|
||||||
true, the returned description is suitable for a new Password.
|
* returned description is suitable for a new Password. Supported
|
||||||
Supported values for PWIDSTR are:
|
* values for PWIDSTR are:
|
||||||
|
*
|
||||||
PW1.CH - Global password 1
|
* PW1.CH - id 0x00 - Global password 1
|
||||||
PW2.CH - Global password 2
|
* PW2.CH - id 0x01 - Global password 2
|
||||||
PW1.CH.SIG - SigG password 1
|
* PW1.CH.SIG - id 0x81 - SigG password 1
|
||||||
PW2.CH.SIG - SigG password 2
|
* PW2.CH.SIG - id 0x83 - SigG password 2
|
||||||
FIXME: What about the ESIGN passwords?
|
*
|
||||||
|
* It is also possible to specify the PIN id directly but the prompts
|
||||||
|
* are then not very descriptive (Use this for testing):
|
||||||
|
*
|
||||||
|
* NKS.0xnn - Switch to NKS and select id 0xnn
|
||||||
|
* SIGG.0xnn - Switch to SigG and select id 0xnn
|
||||||
|
* ESIGN.0xnn - Switch to ESIGN and select id 0xnn
|
||||||
*/
|
*/
|
||||||
static const char *
|
static const char *
|
||||||
parse_pwidstr (const char *pwidstr, int new_mode
|
parse_pwidstr (const char *pwidstr, int new_mode
|
||||||
@ -1374,6 +1551,36 @@ parse_pwidstr (const char *pwidstr, int new_mode
|
|||||||
: _("|P|Please enter the PIN Unblocking Code (PUK) "
|
: _("|P|Please enter the PIN Unblocking Code (PUK) "
|
||||||
"for the key to create qualified signatures."));
|
"for the key to create qualified signatures."));
|
||||||
}
|
}
|
||||||
|
else if (!strncmp (pwidstr, "NKS.0x", 6)
|
||||||
|
&& hexdigitp (pwidstr+6) && hexdigitp (pwidstr+7) && !pwidstr[8])
|
||||||
|
{
|
||||||
|
/* Hack to help debugging. */
|
||||||
|
*r_nks_app_id = NKS_APP_NKS;
|
||||||
|
*r_pwid = xtoi_2 (pwidstr+6);
|
||||||
|
desc = (new_mode
|
||||||
|
? "|N|Please enter a new PIN for the given NKS pwid"
|
||||||
|
: "||Please enter the PIN for the given NKS pwid" );
|
||||||
|
}
|
||||||
|
else if (!strncmp (pwidstr, "SIGG.0x", 7)
|
||||||
|
&& hexdigitp (pwidstr+7) && hexdigitp (pwidstr+8) && !pwidstr[9])
|
||||||
|
{
|
||||||
|
/* Hack to help debugging. */
|
||||||
|
*r_nks_app_id = NKS_APP_SIGG;
|
||||||
|
*r_pwid = xtoi_2 (pwidstr+7);
|
||||||
|
desc = (new_mode
|
||||||
|
? "|N|Please enter a new PIN for the given SIGG pwid"
|
||||||
|
: "||Please enter the PIN for the given SIGG pwid" );
|
||||||
|
}
|
||||||
|
else if (!strncmp (pwidstr, "ESIGN.0x", 8)
|
||||||
|
&& hexdigitp (pwidstr+8) && hexdigitp (pwidstr+9) && !pwidstr[10])
|
||||||
|
{
|
||||||
|
/* Hack to help debugging. */
|
||||||
|
*r_nks_app_id = NKS_APP_ESIGN;
|
||||||
|
*r_pwid = xtoi_2 (pwidstr+8);
|
||||||
|
desc = (new_mode
|
||||||
|
? "|N|Please enter a new PIN for the given ESIGN pwid"
|
||||||
|
: "||Please enter the PIN for the given ESIGN pwid" );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*r_pwid = 0; /* Only to avoid gcc warning in calling function. */
|
*r_pwid = 0; /* Only to avoid gcc warning in calling function. */
|
||||||
@ -1401,6 +1608,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
const char *newdesc;
|
const char *newdesc;
|
||||||
int pwid;
|
int pwid;
|
||||||
pininfo_t pininfo;
|
pininfo_t pininfo;
|
||||||
|
int remaining;
|
||||||
|
char *prompt;
|
||||||
|
|
||||||
(void)ctrl;
|
(void)ctrl;
|
||||||
|
|
||||||
@ -1421,6 +1630,15 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
remaining = iso7816_verify_status (app_get_slot (app), pwid);
|
||||||
|
if (remaining < 0)
|
||||||
|
remaining = -1; /* We don't care about the concrete error. */
|
||||||
|
if (remaining < 3)
|
||||||
|
{
|
||||||
|
if (remaining >= 0)
|
||||||
|
log_info ("nks: PIN has %d attempts left\n", remaining);
|
||||||
|
}
|
||||||
|
|
||||||
if ((flags & APP_CHANGE_FLAG_NULLPIN))
|
if ((flags & APP_CHANGE_FLAG_NULLPIN))
|
||||||
{
|
{
|
||||||
/* With the nullpin flag, we do not verify the PIN - it would
|
/* With the nullpin flag, we do not verify the PIN - it would
|
||||||
@ -1431,7 +1649,15 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
oldpinlen = 6;
|
if (app->app_local->nks_version == 15)
|
||||||
|
{
|
||||||
|
memset (oldpin, '0', 5);
|
||||||
|
oldpinlen = 5; /* 5 ascii zeroes. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oldpinlen = 6; /* 6 binary Nuls. */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1463,7 +1689,10 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
/* Regular change mode: Ask for the old PIN. */
|
/* Regular change mode: Ask for the old PIN. */
|
||||||
desc = parse_pwidstr (pwidstr, 0, &dummy1, &dummy2);
|
desc = parse_pwidstr (pwidstr, 0, &dummy1, &dummy2);
|
||||||
}
|
}
|
||||||
err = pincb (pincb_arg, desc, &oldpin);
|
|
||||||
|
prompt = make_prompt (app, remaining, desc, NULL);
|
||||||
|
err = pincb (pincb_arg, prompt, &oldpin);
|
||||||
|
xfree (prompt);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("error getting old PIN: %s\n", gpg_strerror (err));
|
log_error ("error getting old PIN: %s\n", gpg_strerror (err));
|
||||||
@ -1475,7 +1704,10 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pincb (pincb_arg, newdesc, &newpin);
|
|
||||||
|
prompt = make_prompt (app, -1, newdesc, NULL);
|
||||||
|
err = pincb (pincb_arg, prompt, &newpin);
|
||||||
|
xfree (prompt);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error (_("error getting new PIN: %s\n"), gpg_strerror (err));
|
log_error (_("error getting new PIN: %s\n"), gpg_strerror (err));
|
||||||
@ -1602,7 +1834,7 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action,
|
|||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
err = keygripstr_from_pk_file (app, filelist[idx].fid,
|
err = keygripstr_from_pk_file (app, filelist[idx].fid,
|
||||||
filelist[idx].iskeypair, keygripstr);
|
filelist[idx].iskeypair, keygripstr, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("can't get keygrip from FID 0x%04X: %s\n",
|
log_error ("can't get keygrip from FID 0x%04X: %s\n",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user