mirror of
git://git.gnupg.org/gnupg.git
synced 2025-02-23 20:08:04 +01:00
scd:nks: Implement writecert for the Signature card v2.
* scd/iso7816.c (CMD_UPDATE_BINARY): New. (iso7816_update_binary): New. * scd/app-nks.c (do_deinit): Factor some code out to... (flush_fid_cache): new. (do_writecert): New. (app_select_nks): Register new handler. -- This has been backported only to make the following backpoorts easier. The code is only used in 2.3; for details see the original commit message. Signed-off-by: Werner Koch <wk@gnupg.org> Backported-from-master: c1663c690b29d2dea8bc782c42de5eca08a24cc9 GnuPG-bug-id: 6252
This commit is contained in:
parent
c99870f790
commit
fe698586b5
112
scd/app-nks.c
112
scd/app-nks.c
@ -172,7 +172,7 @@ static struct
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Object to cache information gathred from FIDs. */
|
/* Object to cache information gathered from FIDs. */
|
||||||
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. */
|
||||||
@ -202,22 +202,33 @@ struct app_local_s {
|
|||||||
static gpg_error_t readcert_from_ef (app_t app, int fid,
|
static gpg_error_t readcert_from_ef (app_t app, int fid,
|
||||||
unsigned char **cert, size_t *certlen);
|
unsigned char **cert, size_t *certlen);
|
||||||
static gpg_error_t switch_application (app_t app, int nks_app_id);
|
static gpg_error_t switch_application (app_t app, int nks_app_id);
|
||||||
|
static const char *parse_pwidstr (app_t app, const char *pwidstr, int new_mode,
|
||||||
|
int *r_nks_app_id, int *r_pwid);
|
||||||
|
static gpg_error_t verify_pin (app_t app, int pwid, const char *desc,
|
||||||
|
gpg_error_t (*pincb)(void*, const char *,
|
||||||
|
char **),
|
||||||
|
void *pincb_arg);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Release local data. */
|
|
||||||
static void
|
static void
|
||||||
do_deinit (app_t app)
|
flush_fid_cache (app_t app)
|
||||||
{
|
{
|
||||||
if (app && app->app_local)
|
|
||||||
{
|
|
||||||
while (app->app_local->fid_cache)
|
while (app->app_local->fid_cache)
|
||||||
{
|
{
|
||||||
struct fid_cache_s *next = app->app_local->fid_cache->next;
|
struct fid_cache_s *next = app->app_local->fid_cache->next;
|
||||||
xfree (app->app_local->fid_cache);
|
xfree (app->app_local->fid_cache);
|
||||||
app->app_local->fid_cache = next;
|
app->app_local->fid_cache = next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release local data. */
|
||||||
|
static void
|
||||||
|
do_deinit (app_t app)
|
||||||
|
{
|
||||||
|
if (app && app->app_local)
|
||||||
|
{
|
||||||
|
flush_fid_cache (app);
|
||||||
xfree (app->app_local);
|
xfree (app->app_local);
|
||||||
app->app_local = NULL;
|
app->app_local = NULL;
|
||||||
}
|
}
|
||||||
@ -1089,6 +1100,96 @@ do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write the certificate (CERT,CERTLEN) to the card at CERTREFSTR.
|
||||||
|
* CERTREFSTR is of the form "NKS_<yyy>.<four_hexdigit_keyref>". */
|
||||||
|
static gpg_error_t
|
||||||
|
do_writecert (app_t app, ctrl_t ctrl,
|
||||||
|
const char *certid,
|
||||||
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
|
void *pincb_arg,
|
||||||
|
const unsigned char *cert, size_t certlen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int i, fid, pwid;
|
||||||
|
int nks_app_id, tmp_app_id;
|
||||||
|
const char *desc;
|
||||||
|
|
||||||
|
(void)ctrl;
|
||||||
|
|
||||||
|
if (!strncmp (certid, "NKS-NKS3.", 9))
|
||||||
|
nks_app_id = NKS_APP_NKS;
|
||||||
|
else if (!strncmp (certid, "NKS-ESIGN.", 10))
|
||||||
|
nks_app_id = NKS_APP_ESIGN;
|
||||||
|
else if (!strncmp (certid, "NKS-SIGG.", 9))
|
||||||
|
nks_app_id = NKS_APP_SIGG;
|
||||||
|
else if (!strncmp (certid, "NKS-DF01.", 9))
|
||||||
|
nks_app_id = NKS_APP_NKS;
|
||||||
|
else if (!strncmp (certid, "NKS-IDLM.", 9))
|
||||||
|
nks_app_id = NKS_APP_IDLM;
|
||||||
|
else
|
||||||
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
certid += nks_app_id == NKS_APP_ESIGN? 10 : 9;
|
||||||
|
|
||||||
|
err = switch_application (app, nks_app_id);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!hexdigitp (certid) || !hexdigitp (certid+1)
|
||||||
|
|| !hexdigitp (certid+2) || !hexdigitp (certid+3)
|
||||||
|
|| certid[4])
|
||||||
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
fid = xtoi_4 (certid);
|
||||||
|
for (i=0; filelist[i].fid; i++)
|
||||||
|
if ((filelist[i].certtype || filelist[i].iskeypair)
|
||||||
|
&& filelist[i].nks_app_id == nks_app_id
|
||||||
|
&& filelist[i].fid == fid)
|
||||||
|
break;
|
||||||
|
if (!filelist[i].fid)
|
||||||
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||||
|
|
||||||
|
/* If the requested objects is a plain public key, redirect it to
|
||||||
|
* the corresponding certificate. This makes it easier for the user
|
||||||
|
* to figure out which CERTID to use. For example gpg-card shows
|
||||||
|
* the id of the key and not of the certificate. */
|
||||||
|
if (filelist[i].iskeypair)
|
||||||
|
fid = filelist[i].iskeypair;
|
||||||
|
|
||||||
|
/* We have no selective flush mechanism and given the rare use of
|
||||||
|
* writecert it won't harm to flush the entire cache. */
|
||||||
|
flush_fid_cache (app);
|
||||||
|
|
||||||
|
|
||||||
|
/* The certificates we support all require PW1.CH. Note that we
|
||||||
|
* check that the nks_app_id matches which sorts out CERTID values
|
||||||
|
* which are subkecy to a different nks_app_id. */
|
||||||
|
desc = parse_pwidstr (app, "PW1.CH", 0, &tmp_app_id, &pwid);
|
||||||
|
if (!desc || tmp_app_id != nks_app_id)
|
||||||
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
err = verify_pin (app, pwid, desc, pincb, pincb_arg);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Select the file and write the certificate. */
|
||||||
|
err = iso7816_select_file (app_get_slot (app), fid, 0);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("nks: error selecting FID 0x%04X: %s\n",
|
||||||
|
fid, gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = iso7816_update_binary (app_get_slot (app), 1, 0, cert, certlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("nks: error updating certificate at FID 0x%04X: %s\n",
|
||||||
|
fid, gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Handle the WRITEKEY command for NKS. This function expects a
|
/* Handle the WRITEKEY command for NKS. This function expects a
|
||||||
canonical encoded S-expression with the public key in KEYDATA and
|
canonical encoded S-expression with the public key in KEYDATA and
|
||||||
its length in KEYDATALEN. The only supported KEYID is
|
its length in KEYDATALEN. The only supported KEYID is
|
||||||
@ -2196,6 +2297,7 @@ app_select_nks (app_t app)
|
|||||||
app->fnc.readkey = do_readkey;
|
app->fnc.readkey = do_readkey;
|
||||||
app->fnc.getattr = do_getattr;
|
app->fnc.getattr = do_getattr;
|
||||||
app->fnc.setattr = NULL;
|
app->fnc.setattr = NULL;
|
||||||
|
app->fnc.writecert = do_writecert;
|
||||||
app->fnc.writekey = do_writekey;
|
app->fnc.writekey = do_writekey;
|
||||||
app->fnc.genkey = NULL;
|
app->fnc.genkey = NULL;
|
||||||
app->fnc.sign = do_sign;
|
app->fnc.sign = do_sign;
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
#define CMD_GET_CHALLENGE 0x84
|
#define CMD_GET_CHALLENGE 0x84
|
||||||
#define CMD_READ_BINARY 0xB0
|
#define CMD_READ_BINARY 0xB0
|
||||||
#define CMD_READ_RECORD 0xB2
|
#define CMD_READ_RECORD 0xB2
|
||||||
|
#define CMD_UPDATE_BINARY 0xD6
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
map_sw (int sw)
|
map_sw (int sw)
|
||||||
@ -1025,6 +1026,7 @@ iso7816_read_record_ext (int slot, int recno, int reccount, int short_ef,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
iso7816_read_record (int slot, int recno, int reccount, int short_ef,
|
iso7816_read_record (int slot, int recno, int reccount, int short_ef,
|
||||||
unsigned char **result, size_t *resultlen)
|
unsigned char **result, size_t *resultlen)
|
||||||
@ -1032,3 +1034,23 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
|
|||||||
return iso7816_read_record_ext (slot, recno, reccount, short_ef,
|
return iso7816_read_record_ext (slot, recno, reccount, short_ef,
|
||||||
result, resultlen, NULL);
|
result, resultlen, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Perform an UPDATE BINARY command on card in SLOT. Write DATA of
|
||||||
|
* length DATALEN to a transparent file at OFFSET. */
|
||||||
|
gpg_error_t
|
||||||
|
iso7816_update_binary (int slot, int extended_mode, size_t offset,
|
||||||
|
const void *data, size_t datalen)
|
||||||
|
{
|
||||||
|
int sw;
|
||||||
|
|
||||||
|
/* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
|
||||||
|
* we check for this limit. */
|
||||||
|
if (offset > 32767)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
sw = apdu_send_simple (slot, extended_mode, 0x00, CMD_UPDATE_BINARY,
|
||||||
|
((offset>>8) & 0xff), (offset & 0xff),
|
||||||
|
datalen, (const char*)data);
|
||||||
|
return map_sw (sw);
|
||||||
|
}
|
||||||
|
@ -150,5 +150,7 @@ gpg_error_t iso7816_read_record_ext (int slot, int recno, int reccount,
|
|||||||
gpg_error_t iso7816_read_record (int slot, int recno, int reccount,
|
gpg_error_t iso7816_read_record (int slot, int recno, int reccount,
|
||||||
int short_ef,
|
int short_ef,
|
||||||
unsigned char **result, size_t *resultlen);
|
unsigned char **result, size_t *resultlen);
|
||||||
|
gpg_error_t iso7816_update_binary (int slot, int extended_mode, size_t offset,
|
||||||
|
const void *data, size_t datalen);
|
||||||
|
|
||||||
#endif /*ISO7816_H*/
|
#endif /*ISO7816_H*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user