commit
89be9d6e18
File diff suppressed because it is too large
Load Diff
|
@ -106,6 +106,7 @@ enum {
|
||||||
SC_CARD_TYPE_OPENPGP_BASE = 9000,
|
SC_CARD_TYPE_OPENPGP_BASE = 9000,
|
||||||
SC_CARD_TYPE_OPENPGP_V1,
|
SC_CARD_TYPE_OPENPGP_V1,
|
||||||
SC_CARD_TYPE_OPENPGP_V2,
|
SC_CARD_TYPE_OPENPGP_V2,
|
||||||
|
SC_CARD_TYPE_OPENPGP_GNUK,
|
||||||
|
|
||||||
/* jcop driver */
|
/* jcop driver */
|
||||||
SC_CARD_TYPE_JCOP_BASE = 10000,
|
SC_CARD_TYPE_JCOP_BASE = 10000,
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
|
int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
|
||||||
|
static int sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *);
|
||||||
|
|
||||||
|
|
||||||
#define PGP_USER_PIN_FLAGS (SC_PKCS15_PIN_FLAG_CASE_SENSITIVE \
|
#define PGP_USER_PIN_FLAGS (SC_PKCS15_PIN_FLAG_CASE_SENSITIVE \
|
||||||
|
@ -43,6 +44,8 @@ int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
|
||||||
| SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED \
|
| SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED \
|
||||||
| SC_PKCS15_PIN_FLAG_SO_PIN)
|
| SC_PKCS15_PIN_FLAG_SO_PIN)
|
||||||
|
|
||||||
|
#define PGP_NUM_PRIVDO 4
|
||||||
|
|
||||||
typedef struct _pgp_pin_cfg {
|
typedef struct _pgp_pin_cfg {
|
||||||
const char *label;
|
const char *label;
|
||||||
int reference;
|
int reference;
|
||||||
|
@ -153,7 +156,8 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
||||||
u8 c4data[10];
|
u8 c4data[10];
|
||||||
u8 c5data[70];
|
u8 c5data[70];
|
||||||
int r, i;
|
int r, i;
|
||||||
const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V2) ? pin_cfg_v2 : pin_cfg_v1;
|
const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK)
|
||||||
|
? pin_cfg_v2 : pin_cfg_v1;
|
||||||
sc_path_t path;
|
sc_path_t path;
|
||||||
sc_file_t *file;
|
sc_file_t *file;
|
||||||
|
|
||||||
|
@ -356,6 +360,9 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PKCS#15 DATA object from OpenPGP private DOs */
|
||||||
|
r = sc_pkcs15emu_openpgp_add_data(p15card);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
failed: sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to initialize OpenPGP emulation: %s\n",
|
failed: sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to initialize OpenPGP emulation: %s\n",
|
||||||
|
@ -363,9 +370,57 @@ failed: sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to initialize OpenPGP e
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *p15card)
|
||||||
|
{
|
||||||
|
sc_context_t *ctx = p15card->card->ctx;
|
||||||
|
int i, r;
|
||||||
|
|
||||||
|
LOG_FUNC_CALLED(ctx);
|
||||||
|
/* There is 4 private DO from 0101 to 0104 */
|
||||||
|
for (i = 1; i <= PGP_NUM_PRIVDO; i++) {
|
||||||
|
sc_pkcs15_data_info_t dat_info;
|
||||||
|
sc_pkcs15_object_t dat_obj;
|
||||||
|
char name[8];
|
||||||
|
char path[9];
|
||||||
|
u8 content[254];
|
||||||
|
memset(&dat_info, 0, sizeof(dat_info));
|
||||||
|
memset(&dat_obj, 0, sizeof(dat_obj));
|
||||||
|
|
||||||
|
sprintf(name, "PrivDO%d", i);
|
||||||
|
sprintf(path, "3F00010%d", i);
|
||||||
|
|
||||||
|
/* Check if the DO can be read.
|
||||||
|
* We won't expose pkcs15 DATA object if DO is empty.
|
||||||
|
*/
|
||||||
|
r = read_file(p15card->card, path, content, sizeof(content));
|
||||||
|
if (r <= 0 ) {
|
||||||
|
sc_log(ctx, "No data get from DO 010%d", i);
|
||||||
|
/* Skip */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sc_format_path(path, &dat_info.path);
|
||||||
|
strlcpy(dat_obj.label, name, sizeof(dat_obj.label));
|
||||||
|
strlcpy(dat_info.app_label, name, sizeof(dat_info.app_label));
|
||||||
|
|
||||||
|
/* Add DATA object to slot protected by PIN2 (PW1 with Ref 0x82) */
|
||||||
|
dat_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE;
|
||||||
|
dat_obj.auth_id.len = 1;
|
||||||
|
if (i == 1 || i == 3)
|
||||||
|
dat_obj.auth_id.value[0] = 2;
|
||||||
|
else
|
||||||
|
dat_obj.auth_id.value[0] = 3;
|
||||||
|
|
||||||
|
sc_log(ctx, "Add %s data object", name);
|
||||||
|
r = sc_pkcs15emu_add_data_object(p15card, &dat_obj, &dat_info);
|
||||||
|
}
|
||||||
|
LOG_FUNC_RETURN(ctx, r);
|
||||||
|
}
|
||||||
|
|
||||||
static int openpgp_detect_card(sc_pkcs15_card_t *p15card)
|
static int openpgp_detect_card(sc_pkcs15_card_t *p15card)
|
||||||
{
|
{
|
||||||
if (p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2)
|
if (p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2
|
||||||
|
|| p15card->card->type == SC_CARD_TYPE_OPENPGP_GNUK)
|
||||||
return SC_SUCCESS;
|
return SC_SUCCESS;
|
||||||
else
|
else
|
||||||
return SC_ERROR_WRONG_CARD;
|
return SC_ERROR_WRONG_CARD;
|
||||||
|
|
|
@ -117,6 +117,7 @@ int sc_pkcs15_is_emulation_only(sc_card_t *card)
|
||||||
case SC_CARD_TYPE_GEMSAFEV1_PTEID:
|
case SC_CARD_TYPE_GEMSAFEV1_PTEID:
|
||||||
case SC_CARD_TYPE_OPENPGP_V1:
|
case SC_CARD_TYPE_OPENPGP_V1:
|
||||||
case SC_CARD_TYPE_OPENPGP_V2:
|
case SC_CARD_TYPE_OPENPGP_V2:
|
||||||
|
case SC_CARD_TYPE_OPENPGP_GNUK:
|
||||||
case SC_CARD_TYPE_SC_HSM:
|
case SC_CARD_TYPE_SC_HSM:
|
||||||
case SC_CARD_TYPE_DNIE_BASE:
|
case SC_CARD_TYPE_DNIE_BASE:
|
||||||
case SC_CARD_TYPE_DNIE_BLANK:
|
case SC_CARD_TYPE_DNIE_BLANK:
|
||||||
|
|
|
@ -236,13 +236,16 @@ static int openpgp_emu_update_tokeninfo(sc_profile_t *profile, sc_pkcs15_card_t
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openpgp_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
static int openpgp_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
||||||
struct sc_pkcs15_object *obj, struct sc_pkcs15_der *content,
|
struct sc_pkcs15_object *obj, struct sc_pkcs15_der *content,
|
||||||
struct sc_path *path)
|
struct sc_path *path)
|
||||||
{
|
{
|
||||||
sc_card_t *card = p15card->card;
|
sc_card_t *card = p15card->card;
|
||||||
|
sc_context_t *ctx = card->ctx;
|
||||||
sc_file_t *file;
|
sc_file_t *file;
|
||||||
sc_pkcs15_cert_info_t *cinfo;
|
sc_pkcs15_cert_info_t *cinfo;
|
||||||
sc_pkcs15_id_t *cid;
|
sc_pkcs15_id_t *cid;
|
||||||
|
sc_pkcs15_data_info_t *dinfo;
|
||||||
|
u8 buf[254];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
LOG_FUNC_CALLED(card->ctx);
|
LOG_FUNC_CALLED(card->ctx);
|
||||||
|
@ -276,10 +279,42 @@ static int openpgp_store_data(struct sc_pkcs15_card *p15card, struct sc_profile
|
||||||
r = sc_select_file(card, path, &file);
|
r = sc_select_file(card, path, &file);
|
||||||
LOG_TEST_RET(card->ctx, r, "Cannot select cert file");
|
LOG_TEST_RET(card->ctx, r, "Cannot select cert file");
|
||||||
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
|
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
|
||||||
|
sc_log(card->ctx, "Data to write is %d long", content->len);
|
||||||
if (r >= 0 && content->len)
|
if (r >= 0 && content->len)
|
||||||
|
r = sc_put_data(p15card->card, 0x7F21, (const unsigned char *) content->value, content->len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
||||||
|
dinfo = (sc_pkcs15_data_info_t *) obj->data;
|
||||||
|
/* dinfo->app_label contains filename */
|
||||||
|
sc_log(ctx, "===== App label %s", dinfo->app_label);
|
||||||
|
/* Currently, we only support DO 0101. The reason is that when initializing this
|
||||||
|
* pkcs15 emulation, PIN authentication is not applied and we can expose only this DO,
|
||||||
|
* which is "read always".
|
||||||
|
* If we support other DOs, they will not be exposed, and not helpful to user.
|
||||||
|
* I haven't found a way to refresh the list of exposed DOs after verifying PIN yet.
|
||||||
|
* http://sourceforge.net/mailarchive/message.php?msg_id=30646373
|
||||||
|
**/
|
||||||
|
sc_log(ctx, "About to write to DO 0101");
|
||||||
|
sc_format_path("0101", path);
|
||||||
|
r = sc_select_file(card, path, &file);
|
||||||
|
LOG_TEST_RET(card->ctx, r, "Cannot select private DO");
|
||||||
|
r = sc_read_binary(card, 0, buf, sizeof(buf), 0);
|
||||||
|
if (r < 0) {
|
||||||
|
sc_log(ctx, "Cannot read DO 0101");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r > 0) {
|
||||||
|
sc_log(ctx, "DO 0101 is full.");
|
||||||
|
r = SC_ERROR_TOO_MANY_OBJECTS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
|
||||||
|
if (r >= 0 && content->len) {
|
||||||
r = sc_update_binary(p15card->card, 0,
|
r = sc_update_binary(p15card->card, 0,
|
||||||
(const unsigned char *) content->value,
|
(const unsigned char *) content->value,
|
||||||
content->len, 0);
|
content->len, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -21,8 +21,17 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
/* For dup() and dup2() functions */
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* Windows:
|
||||||
|
* https://msdn.microsoft.com/en-us/library/8syseb29.aspx
|
||||||
|
* https://msdn.microsoft.com/en-us/library/886kc0as.aspx
|
||||||
|
*/
|
||||||
|
#include <io.h>
|
||||||
|
#include <process.h>
|
||||||
#endif
|
#endif
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -32,14 +41,16 @@
|
||||||
#include "libopensc/asn1.h"
|
#include "libopensc/asn1.h"
|
||||||
#include "libopensc/cards.h"
|
#include "libopensc/cards.h"
|
||||||
#include "libopensc/cardctl.h"
|
#include "libopensc/cardctl.h"
|
||||||
|
#include "libopensc/log.h"
|
||||||
#include "libopensc/errors.h"
|
#include "libopensc/errors.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "libopensc/log.h"
|
#include "libopensc/log.h"
|
||||||
|
|
||||||
#define OPT_RAW 256
|
#define OPT_RAW 256
|
||||||
#define OPT_PRETTY 257
|
#define OPT_PRETTY 257
|
||||||
#define OPT_VERIFY 258
|
#define OPT_VERIFY 258
|
||||||
#define OPT_PIN 259
|
#define OPT_PIN 259
|
||||||
|
#define OPT_DELKEY 260
|
||||||
|
|
||||||
/* define structures */
|
/* define structures */
|
||||||
struct ef_name_map {
|
struct ef_name_map {
|
||||||
|
@ -75,6 +86,8 @@ static int opt_verify = 0;
|
||||||
static char *verifytype = NULL;
|
static char *verifytype = NULL;
|
||||||
static int opt_pin = 0;
|
static int opt_pin = 0;
|
||||||
static const char *pin = NULL;
|
static const char *pin = NULL;
|
||||||
|
static int opt_erase = 0;
|
||||||
|
static int opt_delkey = 0;
|
||||||
static int opt_dump_do = 0;
|
static int opt_dump_do = 0;
|
||||||
static u8 do_dump_idx;
|
static u8 do_dump_idx;
|
||||||
|
|
||||||
|
@ -93,8 +106,10 @@ static const struct option options[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "verbose", no_argument, NULL, 'v' },
|
{ "verbose", no_argument, NULL, 'v' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
{ "erase", no_argument, NULL, 'E' },
|
||||||
{ "verify", required_argument, NULL, OPT_VERIFY },
|
{ "verify", required_argument, NULL, OPT_VERIFY },
|
||||||
{ "pin", required_argument, NULL, OPT_PIN },
|
{ "pin", required_argument, NULL, OPT_PIN },
|
||||||
|
{ "del-key", required_argument, NULL, OPT_DELKEY },
|
||||||
{ "do", required_argument, NULL, 'd' },
|
{ "do", required_argument, NULL, 'd' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
@ -112,8 +127,10 @@ static const char *option_help[] = {
|
||||||
/* h */ "Print this help message",
|
/* h */ "Print this help message",
|
||||||
/* v */ "Verbose operation. Use several times to enable debug output.",
|
/* v */ "Verbose operation. Use several times to enable debug output.",
|
||||||
/* V */ "Show version number",
|
/* V */ "Show version number",
|
||||||
|
/* E */ "Erase (reset) the card",
|
||||||
"Verify PIN (CHV1, CHV2, CHV3...)",
|
"Verify PIN (CHV1, CHV2, CHV3...)",
|
||||||
"PIN string",
|
"PIN string",
|
||||||
|
"Delete key (1, 2, 3 or all)"
|
||||||
/* d */ "Dump private data object number <arg> (i.e. PRIVATE-DO-<arg>)"
|
/* d */ "Dump private data object number <arg> (i.e. PRIVATE-DO-<arg>)"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -168,16 +185,16 @@ static char *prettify_language(char *str)
|
||||||
{
|
{
|
||||||
if (str != NULL) {
|
if (str != NULL) {
|
||||||
switch (strlen(str)) {
|
switch (strlen(str)) {
|
||||||
case 8: memmove(str+7, str+6, 1+strlen(str+6));
|
case 8: memmove(str+7, str+6, 1+strlen(str+6));
|
||||||
str[6] = ',';
|
str[6] = ',';
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 6: memmove(str+5, str+4, 1+strlen(str+4));
|
case 6: memmove(str+5, str+4, 1+strlen(str+4));
|
||||||
str[4] = ',';
|
str[4] = ',';
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 4: memmove(str+3, str+2, 1+strlen(str+2));
|
case 4: memmove(str+3, str+2, 1+strlen(str+2));
|
||||||
str[2] = ',';
|
str[2] = ',';
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 2: return str;
|
case 2: return str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -189,10 +206,10 @@ static char *prettify_gender(char *str)
|
||||||
{
|
{
|
||||||
if (str != NULL) {
|
if (str != NULL) {
|
||||||
switch (*str) {
|
switch (*str) {
|
||||||
case '0': return "unknown";
|
case '0': return "unknown";
|
||||||
case '1': return "male";
|
case '1': return "male";
|
||||||
case '2': return "female";
|
case '2': return "female";
|
||||||
case '9': return "not applicable";
|
case '9': return "not applicable";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -289,6 +306,15 @@ static int decode_options(int argc, char **argv)
|
||||||
show_version();
|
show_version();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
break;
|
break;
|
||||||
|
case 'E':
|
||||||
|
opt_erase++;
|
||||||
|
break;
|
||||||
|
case OPT_DELKEY:
|
||||||
|
opt_delkey++;
|
||||||
|
if (strcmp(optarg, "all") != 0) /* Arg string is not 'all' */
|
||||||
|
key_id = optarg[0] - '0';
|
||||||
|
else /* Arg string is 'all' */
|
||||||
|
key_id = 'a';
|
||||||
case 'd':
|
case 'd':
|
||||||
do_dump_idx = optarg[0] - '0';
|
do_dump_idx = optarg[0] - '0';
|
||||||
opt_dump_do++;
|
opt_dump_do++;
|
||||||
|
@ -312,7 +338,7 @@ static int do_userinfo(sc_card_t *card)
|
||||||
for (i = 0; openpgp_data[i].ef != NULL; i++) {
|
for (i = 0; openpgp_data[i].ef != NULL; i++) {
|
||||||
sc_path_t path;
|
sc_path_t path;
|
||||||
sc_file_t *file;
|
sc_file_t *file;
|
||||||
int count;
|
unsigned int count;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
sc_format_path(openpgp_data[i].ef, &path);
|
sc_format_path(openpgp_data[i].ef, &path);
|
||||||
|
@ -322,24 +348,24 @@ static int do_userinfo(sc_card_t *card)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = file->size;
|
count = (unsigned int)file->size;
|
||||||
if (!count)
|
if (!count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (count > (int)sizeof(buf) - 1) {
|
if (count > (unsigned int)sizeof(buf) - 1) {
|
||||||
fprintf(stderr, "Too small buffer to read the OpenPGP data\n");
|
fprintf(stderr, "Too small buffer to read the OpenPGP data\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sc_read_binary(card, 0, buf, count, 0);
|
r = sc_read_binary(card, 0, buf, (size_t)count, 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "%s: read failed - %s\n", openpgp_data[i].ef, sc_strerror(r));
|
fprintf(stderr, "%s: read failed - %s\n", openpgp_data[i].ef, sc_strerror(r));
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (r != count) {
|
if (r != count) {
|
||||||
fprintf(stderr, "%s: expecting %d, got only %d bytes\n", openpgp_data[i].ef, count, r);
|
fprintf(stderr, "%s: expecting %d, got only %d bytes\n", openpgp_data[i].ef, count, r);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[count] = '\0';
|
buf[count] = '\0';
|
||||||
|
|
||||||
|
@ -369,14 +395,22 @@ static int do_dump_do(sc_card_t *card, unsigned int tag)
|
||||||
|
|
||||||
if(opt_raw) {
|
if(opt_raw) {
|
||||||
r = 0;
|
r = 0;
|
||||||
|
#ifndef _WIN32
|
||||||
tmp = dup(fileno(stdout));
|
tmp = dup(fileno(stdout));
|
||||||
|
#else
|
||||||
|
tmp = _dup(_fileno(stdout));
|
||||||
|
#endif
|
||||||
if (tmp < 0)
|
if (tmp < 0)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
fp = freopen(NULL, "wb", stdout);
|
fp = freopen(NULL, "wb", stdout);
|
||||||
if(fp) {
|
if (fp) {
|
||||||
r = fwrite(buffer, sizeof(char), sizeof(buffer), fp);
|
r = (int)fwrite(buffer, sizeof(char), sizeof(buffer), fp);
|
||||||
}
|
}
|
||||||
|
#ifndef _WIN32
|
||||||
dup2(tmp, fileno(stdout));
|
dup2(tmp, fileno(stdout));
|
||||||
|
#else
|
||||||
|
_dup2(tmp, _fileno(stdout));
|
||||||
|
#endif
|
||||||
clearerr(stdout);
|
clearerr(stdout);
|
||||||
close(tmp);
|
close(tmp);
|
||||||
if (sizeof(buffer) != r)
|
if (sizeof(buffer) != r)
|
||||||
|
@ -444,11 +478,103 @@ int do_verify(sc_card_t *card, char *type, const char *pin)
|
||||||
data.pin_type = SC_AC_CHV;
|
data.pin_type = SC_AC_CHV;
|
||||||
data.pin_reference = type[3] - '0';
|
data.pin_reference = type[3] - '0';
|
||||||
data.pin1.data = (unsigned char *) pin;
|
data.pin1.data = (unsigned char *) pin;
|
||||||
data.pin1.len = strlen(pin);
|
data.pin1.len = (int)strlen(pin);
|
||||||
r = sc_pin_cmd(card, &data, &tries_left);
|
r = sc_pin_cmd(card, &data, &tries_left);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete key, for OpenPGP card.
|
||||||
|
* This function is not complete and is reserved for future version (> 2) of OpenPGP card.
|
||||||
|
**/
|
||||||
|
int delete_key_openpgp(sc_card_t *card, u8 key_id)
|
||||||
|
{
|
||||||
|
char *del_fingerprint = "00:DA:00:C6:14:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00";
|
||||||
|
char *del_creationtime = "00:DA:00:CD:04:00:00:00:00";
|
||||||
|
/* We need to replace the 4th byte later */
|
||||||
|
char *apdustring = NULL;
|
||||||
|
u8 buf[SC_MAX_APDU_BUFFER_SIZE];
|
||||||
|
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||||
|
sc_apdu_t apdu;
|
||||||
|
size_t len0;
|
||||||
|
int i;
|
||||||
|
int r = SC_SUCCESS;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
if (i == 0) /* Reset fingerprint */
|
||||||
|
apdustring = del_fingerprint;
|
||||||
|
else /* Reset creation time */
|
||||||
|
apdustring = del_creationtime;
|
||||||
|
/* Convert the string to binary array */
|
||||||
|
len0 = sizeof(buf);
|
||||||
|
sc_hex_to_bin(apdustring, buf, &len0);
|
||||||
|
|
||||||
|
/* Replace DO tag, subject to key ID */
|
||||||
|
buf[3] = buf[3] + key_id;
|
||||||
|
|
||||||
|
/* Build APDU from binary array */
|
||||||
|
r = sc_bytes2apdu(card->ctx, buf, len0, &apdu);
|
||||||
|
if (r) {
|
||||||
|
fprintf(stderr, "Failed to build APDU: %s\n", sc_strerror(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
apdu.resp = rbuf;
|
||||||
|
apdu.resplen = sizeof(rbuf);
|
||||||
|
|
||||||
|
/* Send APDU to card */
|
||||||
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
|
if (r) {
|
||||||
|
fprintf(stderr, "Transmiting APDU failed: %s\n", sc_strerror(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* TODO: Rewrite Extended Header List.
|
||||||
|
* Not support by OpenGPG v2 yet */
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_delete_key(sc_card_t *card, u8 key_id)
|
||||||
|
{
|
||||||
|
sc_path_t path;
|
||||||
|
int r = SC_SUCCESS;
|
||||||
|
|
||||||
|
/* Currently, only Gnuk supports deleting keys */
|
||||||
|
if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) {
|
||||||
|
printf("Only Gnuk supports deleting keys. General OpenPGP doesn't.");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_id < 1 || (key_id > 3 && key_id != 'a')) {
|
||||||
|
printf("Error: Invalid key id %d", key_id);
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
}
|
||||||
|
if (key_id == 1 || key_id == 'a') {
|
||||||
|
sc_format_path("B601", &path);
|
||||||
|
r |= sc_delete_file(card, &path);
|
||||||
|
}
|
||||||
|
if (key_id == 2 || key_id == 'a') {
|
||||||
|
sc_format_path("B801", &path);
|
||||||
|
r |= sc_delete_file(card, &path);
|
||||||
|
}
|
||||||
|
if (key_id == 3 || key_id == 'a') {
|
||||||
|
sc_format_path("A401", &path);
|
||||||
|
r |= sc_delete_file(card, &path);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_erase(sc_card_t *card)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
/* Check card version */
|
||||||
|
if (card->type != SC_CARD_TYPE_OPENPGP_V2) {
|
||||||
|
printf("Do not erase card which is not OpenPGP v2\n");
|
||||||
|
}
|
||||||
|
printf("Erase card\n");
|
||||||
|
r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
sc_context_t *ctx = NULL;
|
sc_context_t *ctx = NULL;
|
||||||
|
@ -487,8 +613,10 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
/* check card type */
|
/* check card type */
|
||||||
if ((card->type != SC_CARD_TYPE_OPENPGP_V1) &&
|
if ((card->type != SC_CARD_TYPE_OPENPGP_V1) &&
|
||||||
(card->type != SC_CARD_TYPE_OPENPGP_V2)) {
|
(card->type != SC_CARD_TYPE_OPENPGP_V2) &&
|
||||||
|
(card->type != SC_CARD_TYPE_OPENPGP_GNUK)) {
|
||||||
util_error("not an OpenPGP card");
|
util_error("not an OpenPGP card");
|
||||||
|
fprintf(stderr, "Card type %X\n", card->type);
|
||||||
exit_status = EXIT_FAILURE;
|
exit_status = EXIT_FAILURE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -520,12 +648,22 @@ int main(int argc, char **argv)
|
||||||
sc_unlock(card);
|
sc_unlock(card);
|
||||||
sc_disconnect_card(card);
|
sc_disconnect_card(card);
|
||||||
sc_release_context(ctx);
|
sc_release_context(ctx);
|
||||||
|
#ifndef _WIN32
|
||||||
execv(exec_program, largv);
|
execv(exec_program, largv);
|
||||||
|
#else
|
||||||
|
_execv(exec_program, largv);
|
||||||
|
#endif
|
||||||
/* we should not get here */
|
/* we should not get here */
|
||||||
perror("execv()");
|
perror("execv()");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt_delkey)
|
||||||
|
exit_status |= do_delete_key(card, key_id);
|
||||||
|
|
||||||
|
if (opt_erase)
|
||||||
|
exit_status |= do_erase(card);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
sc_unlock(card);
|
sc_unlock(card);
|
||||||
sc_disconnect_card(card);
|
sc_disconnect_card(card);
|
||||||
|
|
Loading…
Reference in New Issue