DO management
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
set arm force-mode thumb
|
set arm force-mode thumb
|
||||||
set arm fallback-mode thumb
|
set arm fallback-mode thumb
|
||||||
target remote localhost:3333
|
target remote localhost:3333
|
||||||
monitor reset halt
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ CSRC = $(PORTSRC) \
|
|||||||
$(STMUSBSRC) \
|
$(STMUSBSRC) \
|
||||||
$(USBCDCSRC) \
|
$(USBCDCSRC) \
|
||||||
$(RSASRC) \
|
$(RSASRC) \
|
||||||
main.c hw_config.c usb_lld.c usb_desc.c usb_prop.c usb-icc.c gpg.c
|
main.c hw_config.c usb_lld.c usb_desc.c usb_prop.c usb-icc.c gpg.c ac.c gpg-do.c
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASMSRC = $(PORTASM) \
|
ASMSRC = $(PORTASM) \
|
||||||
|
|||||||
69
src/ac.c
Normal file
69
src/ac.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* ac.c -- Check access condition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ch.h"
|
||||||
|
#include "gnuk.h"
|
||||||
|
|
||||||
|
static uint8_t auth_status = AC_NONE_AUTHORIZED;
|
||||||
|
|
||||||
|
int
|
||||||
|
ac_check_status (uint8_t ac_flag)
|
||||||
|
{
|
||||||
|
if (ac_flag == AC_ALWAYS)
|
||||||
|
return 1;
|
||||||
|
else if (ac_flag == AC_NEVER)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return (ac_flag & auth_status)? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: should be implemented
|
||||||
|
*
|
||||||
|
* string --S2K(SHA1,SALT,ITERATE)--> key
|
||||||
|
* load params from flash with key (key,enc_params --decrypt--> params)
|
||||||
|
* check magic in params
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
verify_pso_cds (uint8_t *pw, int pw_len)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
compute_hash;
|
||||||
|
if (cmp_hash (pw1_hash, hash) == 0)
|
||||||
|
good;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
auth_status |= AC_PSO_CDS_AUTHORIZED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
verify_pso_other (uint8_t *pw, int pw_len)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
compute_hash;
|
||||||
|
if (cmp_hash (pw1_hash, hash) == 0)
|
||||||
|
good;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
auth_status |= AC_PSO_OTHER_AUTHORIZED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
verify_pso_admin (uint8_t *pw, int pw_len)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
compute_hash;
|
||||||
|
if (cmp_hash (pw3_hash, hash) == 0)
|
||||||
|
good;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
auth_status |= AC_ADMIN_AUTHORIZED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
27
src/gnuk.h
27
src/gnuk.h
@@ -1,12 +1,14 @@
|
|||||||
extern Thread *blinker_thread;
|
extern Thread *blinker_thread;
|
||||||
|
|
||||||
extern void put_byte (uint8_t b);
|
extern void put_byte (uint8_t b);
|
||||||
|
extern void put_short (uint16_t x);
|
||||||
extern void put_string (const char *s);
|
extern void put_string (const char *s);
|
||||||
|
|
||||||
extern void _write (const char *, int);
|
extern void _write (const char *, int);
|
||||||
|
|
||||||
extern size_t strlen(const char *s);
|
extern size_t strlen(const char *s);
|
||||||
extern void *memcpy(void *dest, const void *src, size_t n);
|
extern void *memcpy(void *dest, const void *src, size_t n);
|
||||||
|
extern void *memset(void *s, int c, size_t n);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interface between ICC<-->GPG
|
* Interface between ICC<-->GPG
|
||||||
@@ -18,9 +20,32 @@ extern Thread *gpg_thread;
|
|||||||
|
|
||||||
#define EV_EXEC_FINISHED (eventmask_t)2 /* GPG Execution finished */
|
#define EV_EXEC_FINISHED (eventmask_t)2 /* GPG Execution finished */
|
||||||
|
|
||||||
#define MAX_CMD_APDU_SIZE (256) /* XXX: Check OpenPGPcard protocol */
|
/* maximum cmd apdu data is key import 22+4+128+128 (head, e, p, q)*/
|
||||||
|
#define MAX_CMD_APDU_SIZE (7+282) /* header + data */
|
||||||
|
|
||||||
#define MAX_RES_APDU_SIZE (256+2) /* Data + status */
|
#define MAX_RES_APDU_SIZE (256+2) /* Data + status */
|
||||||
extern uint8_t cmd_APDU[MAX_CMD_APDU_SIZE];
|
extern uint8_t cmd_APDU[MAX_CMD_APDU_SIZE];
|
||||||
extern uint8_t res_APDU[MAX_RES_APDU_SIZE];
|
extern uint8_t res_APDU[MAX_RES_APDU_SIZE];
|
||||||
extern int cmd_APDU_size;
|
extern int cmd_APDU_size;
|
||||||
extern int res_APDU_size;
|
extern int res_APDU_size;
|
||||||
|
|
||||||
|
#define AC_NONE_AUTHORIZED 0x00
|
||||||
|
#define AC_PSO_CDS_AUTHORIZED 0x01 /* PW1 with 0x81 verified */
|
||||||
|
#define AC_PSO_OTHER_AUTHORIZED 0x02 /* PW1 with 0x82 verified */
|
||||||
|
#define AC_ADMIN_AUTHORIZED 0x04 /* PW3 verified */
|
||||||
|
#define AC_NEVER 0x80
|
||||||
|
#define AC_ALWAYS 0xFF
|
||||||
|
|
||||||
|
extern int ac_check_status (uint8_t ac_flag);
|
||||||
|
extern int verify_pso_cds (uint8_t *pw, int pw_len);
|
||||||
|
extern int verify_pso_other (uint8_t *pw, int pw_len);
|
||||||
|
extern int verify_pso_admin (uint8_t *pw, int pw_len);
|
||||||
|
|
||||||
|
|
||||||
|
extern void write_res_apdu (const uint8_t *p, int len,
|
||||||
|
uint8_t sw1, uint8_t sw2);
|
||||||
|
#define DEBUG 1
|
||||||
|
|
||||||
|
extern int gpg_do_table_init (void);
|
||||||
|
extern void gpg_do_get_data (uint16_t tag);
|
||||||
|
extern void gpg_do_put_data (uint16_t tag, uint8_t *data, int len);
|
||||||
|
|||||||
221
src/gpg-data.c
221
src/gpg-data.c
@@ -1,172 +1,79 @@
|
|||||||
const char const select_file_TOP_result[] __attribute__ ((aligned (1))) =
|
#include "ch.h"
|
||||||
{ 0x00, 0x00, 0x0b, 0x10, 0x3f, 0x00, 0x38, 0xff, 0xff, 0x44,
|
#include "gnuk.h"
|
||||||
0x44, 0x01, 0x05, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
const char const get_data_64_result[] __attribute__ ((aligned (1))) =
|
const char const select_file_TOP_result[] __attribute__ ((aligned (1))) = {
|
||||||
{
|
0x00, 0x00, /* unused */
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
0x0b, 0x10, /* number of bytes in this directory */
|
||||||
};
|
0x3f, 0x00, /* field of selected file: MF, 3f00 */
|
||||||
|
0x38, /* it's DF */
|
||||||
|
0xff, /* unused */
|
||||||
|
0xff, 0x44, 0x44, /* access conditions */
|
||||||
|
0x01, /* status of the selected file (OK, unblocked) */
|
||||||
|
0x05, /* number of bytes of data follow */
|
||||||
|
0x03, /* Features: unused */
|
||||||
|
0x01, /* number of subdirectories (OpenPGP) */
|
||||||
|
0x01, /* number of elementary files (SerialNo) */
|
||||||
|
0x00, /* number of secret codes */
|
||||||
|
0x00, /* Unused */
|
||||||
|
0x00, 0x00 /* PIN status: OK, PIN blocked?: No */
|
||||||
|
};
|
||||||
|
|
||||||
const char const get_data_5e_result[] __attribute__ ((aligned (1))) =
|
const char const do_5e[] __attribute__ ((aligned (1))) = {
|
||||||
{ /* Login Data */
|
6,
|
||||||
'g', 'n', 'i', 'i', 'b', 'e'
|
'g', 'n', 'i', 'i', 'b', 'e'
|
||||||
};
|
};
|
||||||
|
|
||||||
/***** do_6e is compound object of { do_47, do_4f, do_c0,..,c6,cd }*/
|
const char const do_c4[] __attribute__ ((aligned (1))) = {
|
||||||
const char const do_6e_head[] __attribute__ ((aligned (1))) =
|
7,
|
||||||
{
|
1, 127, 127, 127, 3, 0, 3
|
||||||
0x6e, 0x81, 2*10+3+16+1+1+1+1+7+60+60+12 /* (> 128) */
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_47[] __attribute__ ((aligned (1))) = /* Card Capabilities */
|
const char const do_c7[] __attribute__ ((aligned (1))) = {
|
||||||
{
|
20,
|
||||||
0x47, 3,
|
/* sign */
|
||||||
0x00 /*???*/, 0x00 /*???*/, 0x00 /*???*/
|
0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d,
|
||||||
/* XXX: See ISO 7816-4 for first byte and second byte */
|
0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc,
|
||||||
};
|
0xe5, 0x02, 0xbf, 0xcd,
|
||||||
|
};
|
||||||
|
|
||||||
const char const do_4f[] __attribute__ ((aligned (1))) = /* AID */
|
const char const do_ca[] __attribute__ ((aligned (1))) = {
|
||||||
{
|
20,
|
||||||
0x4f, 16,
|
0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d,
|
||||||
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
|
0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc,
|
||||||
0x01, 0x01, /* Version 1.1 */
|
0xe5, 0x02, 0xbf, 0xcd,
|
||||||
0xF5, 0x17, /* Manufacturer (FSIJ) */
|
};
|
||||||
0x00, 0x00, 0x00, 0x02, /* Serial */
|
|
||||||
0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_c0[] __attribute__ ((aligned (1))) =
|
const char const do_ce[] __attribute__ ((aligned (1))) = {
|
||||||
{ /* Extended capability */
|
4,
|
||||||
0xc0, 1,
|
0x49, 0x8a, 0x50, 0x7a, /* 0xce */
|
||||||
0x00
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_c1[] __attribute__ ((aligned (1))) =
|
const char const do_5b[] __attribute__ ((aligned (1))) = {
|
||||||
{ /* Algorithm Attributes Signature ??? */
|
12,
|
||||||
0xc1, 1,
|
'N', 'I', 'I', 'B', 'E', ' ', 'Y', 'u', 't', 'a', 'k', 'a'
|
||||||
0x01, /* RSA */ /*??? should have length modulus, length exponent ??? */
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_c2[] __attribute__ ((aligned (1))) =
|
const char const do_5f2d[] __attribute__ ((aligned (1))) = {
|
||||||
{ /* Algorithm Attributes Decryption ??? */
|
2,
|
||||||
0xc2, 1,
|
'j', 'a'
|
||||||
0x00
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_c3[] __attribute__ ((aligned (1))) =
|
const char const do_5f35[] __attribute__ ((aligned (1))) = {
|
||||||
{ /* Algorithm Attributes Authentication ??? */
|
1,
|
||||||
0xc3, 1,
|
'1'
|
||||||
0x00
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_c4[] __attribute__ ((aligned (1))) =
|
|
||||||
{ /* CHV status bytes */
|
|
||||||
0xc4, 7,
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01
|
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_c5[] __attribute__ ((aligned (1))) =
|
|
||||||
{
|
|
||||||
0xc5, 60,
|
|
||||||
/* sign */
|
|
||||||
0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d,
|
|
||||||
0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc,
|
|
||||||
0xe5, 0x02, 0xbf, 0xcd,
|
|
||||||
/* enc */
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
/* auth */
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_c6[] __attribute__ ((aligned (1))) = /* CA Fingerprints */
|
|
||||||
{
|
|
||||||
0xc6, 60,
|
|
||||||
/* c6 */
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
/* c7 */
|
|
||||||
0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d,
|
|
||||||
0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc,
|
|
||||||
0xe5, 0x02, 0xbf, 0xcd,
|
|
||||||
/* c8 */
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_cd[] __attribute__ ((aligned (1))) =
|
|
||||||
{ /* Generation time */
|
|
||||||
0xcd, 12,
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x49, 0x8a, 0x50, 0x7a, /* 0xce */
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
/*************************/
|
|
||||||
|
|
||||||
/***** do_65 is compound object of { do_5b, do_5f2d, do_5f35 }*/
|
|
||||||
const char const do_65_head[] __attribute__ ((aligned (1))) =
|
|
||||||
{
|
|
||||||
0x65, 2*1+3*2+12+2+1
|
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_5b[] __attribute__ ((aligned (1))) =
|
|
||||||
{
|
|
||||||
0x5b, 12,
|
|
||||||
'N', 'I', 'I', 'B', 'E', ' ', 'Y', 'u', 't', 'a', 'k', 'a'
|
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_5f2d[] __attribute__ ((aligned (1))) =
|
|
||||||
{
|
|
||||||
0x5f, 0x2d, 2,
|
|
||||||
'j', 'a'
|
|
||||||
};
|
|
||||||
|
|
||||||
const char const do_5f35[] __attribute__ ((aligned (1))) =
|
|
||||||
{
|
|
||||||
0x5f, 0x35, 1,
|
|
||||||
'1'
|
|
||||||
};
|
|
||||||
/****************************/
|
|
||||||
|
|
||||||
/* do_7a is compound object of { do_93 } */
|
|
||||||
const char const do_7a_head[] __attribute__ ((aligned (1))) =
|
|
||||||
{
|
|
||||||
0x7a, 2+3
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Digital Signature Counter (3-bytes) */
|
/* Digital Signature Counter (3-bytes) */
|
||||||
const char const do_93[] __attribute__ ((aligned (1))) =
|
const char const do_93[] __attribute__ ((aligned (1))) = {
|
||||||
{
|
3,
|
||||||
0x93, 3,
|
0, 0, 0
|
||||||
0, 0, 0
|
};
|
||||||
};
|
|
||||||
/****************************/
|
|
||||||
|
|
||||||
|
const char const do_5f50[] __attribute__ ((aligned (1))) = {
|
||||||
const char const do_5f50[] __attribute__ ((aligned (1))) =
|
20,
|
||||||
{
|
'h', 't', 't', 'p', ':', '/', '/', 'w', 'w', 'w',
|
||||||
0x5f, 0x50, 20,
|
'.', 'f', 's', 'i', 'j', '.', 'o', 'r', 'g', '/'
|
||||||
'h', 't', 't', 'p', ':', '/', '/', 'w', 'w', 'w',
|
};
|
||||||
'.', 'f', 's', 'i', 'j', '.', 'o', 'r', 'g', '/'
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Historycal bytes */
|
|
||||||
const char const do_5f52[] __attribute__ ((aligned (1))) =
|
|
||||||
{
|
|
||||||
0x5f, 0x52, 10,
|
|
||||||
0x00,
|
|
||||||
0x31, 0xc0, /* full DF name, partial DF name supported */
|
|
||||||
0x73,
|
|
||||||
0xc0, 0x01, 0x00, /* full DF name, partial DF name supported */
|
|
||||||
/* 1-byte */
|
|
||||||
/* no command chaining, no ext lc_le */
|
|
||||||
0x00, 0x90, 0x00 /* Status info */
|
|
||||||
};
|
|
||||||
|
|
||||||
const char const get_data_rb_result[] __attribute__ ((aligned (1))) = {
|
const char const get_data_rb_result[] __attribute__ ((aligned (1))) = {
|
||||||
0x5a, 0x4, 0x01, 0x02, 0x03, 0x04
|
0x5a, 0x4, 0x01, 0x02, 0x03, 0x04
|
||||||
|
|||||||
946
src/gpg-data.s
946
src/gpg-data.s
File diff suppressed because it is too large
Load Diff
729
src/gpg-do.c
Normal file
729
src/gpg-do.c
Normal file
@@ -0,0 +1,729 @@
|
|||||||
|
/*
|
||||||
|
* gpg-do.c -- OpenPGP card Data Objects (DO) handling
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Free Software Initiative of Japan
|
||||||
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
*
|
||||||
|
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||||
|
*
|
||||||
|
* Gnuk 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.
|
||||||
|
*
|
||||||
|
* Gnuk 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 "ch.h"
|
||||||
|
#include "gnuk.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compile time vars:
|
||||||
|
* AID, Historical Bytes (template), Extended Capabilities,
|
||||||
|
* and Algorithm Attributes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* AID */
|
||||||
|
static const uint8_t const aid[] __attribute__ ((aligned (1))) = {
|
||||||
|
16,
|
||||||
|
0xd2, 0x76, 0x00, 0x01, 0x24, 0x01,
|
||||||
|
0x02, 0x00, /* Version 2.0 */
|
||||||
|
0xf5, 0x17, /* Manufacturer (FSIJ) */
|
||||||
|
0x00, 0x00, 0x00, 0x01, /* Serial */
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Historical Bytes (template) */
|
||||||
|
static const uint8_t const historical_bytes[] __attribute__ ((aligned (1))) = {
|
||||||
|
10,
|
||||||
|
0x00,
|
||||||
|
0x31, 0x80, /* Full DF name */
|
||||||
|
0x73,
|
||||||
|
0x80, 0x01, 0x40, /* Full DF name */
|
||||||
|
/* 1-byte */
|
||||||
|
/* No command chaining */
|
||||||
|
/* Extended Lc and Le */
|
||||||
|
0x00, 0x90, 0x00 /* Status info (no life cycle management) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Extended Capabilities */
|
||||||
|
static const uint8_t const extended_capabilities[] __attribute__ ((aligned (1))) = {
|
||||||
|
10,
|
||||||
|
0x30, /*
|
||||||
|
* No SM, No get challenge,
|
||||||
|
* Key import supported,
|
||||||
|
* PW status byte can be put,
|
||||||
|
* No private_use_DO,
|
||||||
|
* No algo change allowed
|
||||||
|
*/
|
||||||
|
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
|
||||||
|
0x00, 0x00, /* Max get challenge */
|
||||||
|
0x00, 0x00, /* max. length of cardholder certificate */
|
||||||
|
(MAX_CMD_APDU_SIZE>>8), (MAX_CMD_APDU_SIZE&0xff), /* Max. length of command data */
|
||||||
|
(MAX_RES_APDU_SIZE>>8), (MAX_RES_APDU_SIZE&0xff), /* Max. length of response data */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Algorithm Attributes */
|
||||||
|
static const uint8_t const algorithm_attr[] __attribute__ ((aligned (1))) = {
|
||||||
|
6,
|
||||||
|
0x01, /* RSA */
|
||||||
|
0x08, 0x00, /* Length modulus (in bit): 2048 */
|
||||||
|
0x00, 0x20, /* Length exponent (in bit): 32 */
|
||||||
|
0x00 /* 0: p&q , 3: CRT with N (not yet supported) */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define SIZE_PW_STATUS_BYTES 7
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
1, /* PW1 valid for several PSO:CDS commands */
|
||||||
|
127, 127, 127, /* max length of PW1, RC, and PW3 */
|
||||||
|
3, 0, 3 /* Error counter of PW1, RC, and PW3 */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZE_DIGITAL_SIGNATURE_COUNTER 3
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
0, 0, 0 /* 3-byte binary */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZE_FINGER_PRINT 20
|
||||||
|
#define SIZE_KEYGEN_TIME 4 /* RFC4880 */
|
||||||
|
|
||||||
|
/* Runtime vars: PSO */
|
||||||
|
|
||||||
|
struct key_store {
|
||||||
|
uint8_t p[128];
|
||||||
|
uint8_t q[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_store key_sig, key_dec, key_aut;
|
||||||
|
|
||||||
|
#define HASH_SIZE 20
|
||||||
|
static uint8_t pw3_hash[HASH_SIZE];
|
||||||
|
|
||||||
|
enum do_type {
|
||||||
|
DO_FIXED,
|
||||||
|
DO_VAR,
|
||||||
|
DO_CN_READ,
|
||||||
|
DO_PROC_READ,
|
||||||
|
DO_PROC_WRITE,
|
||||||
|
DO_HASH,
|
||||||
|
DO_KEYPTR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct do_table_entry {
|
||||||
|
uint16_t tag;
|
||||||
|
enum do_type do_type;
|
||||||
|
uint8_t ac_read;
|
||||||
|
uint8_t ac_write;
|
||||||
|
const void *obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t *res_p;
|
||||||
|
static int with_tag;
|
||||||
|
|
||||||
|
static void copy_do_1 (uint16_t tag, const uint8_t *do_data);
|
||||||
|
static struct do_table_entry *get_do_entry (uint16_t tag);
|
||||||
|
|
||||||
|
#define GNUK_DO_KEYPTR_SIG 0xff01
|
||||||
|
#define GNUK_DO_KEYPTR_DEC 0xff02
|
||||||
|
#define GNUK_DO_KEYPTR_AUT 0xff03
|
||||||
|
#define GNUK_DO_HASH_PW3 0xff04
|
||||||
|
|
||||||
|
#define GPG_DO_AID 0x004f
|
||||||
|
#define GPG_DO_NAME 0x005b
|
||||||
|
#define GPG_DO_LOGIN_DATA 0x005e
|
||||||
|
#define GPG_DO_CH_DATA 0x0065
|
||||||
|
#define GPG_DO_APP_DATA 0x006e
|
||||||
|
/* XXX: 0x0073 ??? */
|
||||||
|
#define GPG_DO_SS_TEMP 0x007a
|
||||||
|
#define GPG_DO_DS_COUNT 0x0093
|
||||||
|
#define GPG_DO_EXTCAP 0x00c0
|
||||||
|
#define GPG_DO_ALG_SIG 0x00c1
|
||||||
|
#define GPG_DO_ALG_DEC 0x00c2
|
||||||
|
#define GPG_DO_ALG_AUT 0x00c3
|
||||||
|
#define GPG_DO_PW_STATUS 0x00c4
|
||||||
|
#define GPG_DO_FP_ALL 0x00c5
|
||||||
|
#define GPG_DO_CAFP_ALL 0x00c6
|
||||||
|
#define GPG_DO_FP_SIG 0x00c7
|
||||||
|
#define GPG_DO_FP_DEC 0x00c8
|
||||||
|
#define GPG_DO_FP_AUT 0x00c9
|
||||||
|
#define GPG_DO_CAFP_1 0x00ca
|
||||||
|
#define GPG_DO_CAFP_2 0x00cb
|
||||||
|
#define GPG_DO_CAFP_3 0x00cc
|
||||||
|
#define GPG_DO_KGTIME_ALL 0x00cd
|
||||||
|
#define GPG_DO_KGTIME_SIG 0x00ce
|
||||||
|
#define GPG_DO_KGTIME_DEC 0x00cf
|
||||||
|
#define GPG_DO_KGTIME_AUT 0x00d0
|
||||||
|
#define GPG_DO_RESETTING_CODE 0x00d3
|
||||||
|
#define GPG_DO_KEY_IMPORT 0x3fff
|
||||||
|
#define GPG_DO_LANGUAGE 0x5f2d
|
||||||
|
#define GPG_DO_SEX 0x5f35
|
||||||
|
#define GPG_DO_URL 0x5f50
|
||||||
|
#define GPG_DO_HIST_BYTES 0x5f52
|
||||||
|
#define GPG_DO_CH_CERTIFICATE 0x7f21
|
||||||
|
|
||||||
|
static void
|
||||||
|
copy_tag (uint16_t tag)
|
||||||
|
{
|
||||||
|
if (tag < 0x0100)
|
||||||
|
*res_p++ = (tag & 0xff);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*res_p++ = (tag >> 8);
|
||||||
|
*res_p++ = (tag & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_hist_bytes (uint16_t tag)
|
||||||
|
{
|
||||||
|
/* XXX: For now, no life cycle management, just return template as is. */
|
||||||
|
/* XXX: Supporing TERMINATE DF / ACTIVATE FILE, we need to fix here */
|
||||||
|
copy_do_1 (tag, historical_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SIZE_FP 20
|
||||||
|
#define SIZE_KGTIME 4
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_fp_all (uint16_t tag)
|
||||||
|
{
|
||||||
|
struct do_table_entry *do_p;
|
||||||
|
const uint8_t *do_data;
|
||||||
|
|
||||||
|
if (with_tag)
|
||||||
|
{
|
||||||
|
copy_tag (tag);
|
||||||
|
*res_p++ = SIZE_FP*3;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_FP_SIG);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_FP);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_FP);
|
||||||
|
res_p += SIZE_FP;
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_FP_DEC);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_FP);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_FP);
|
||||||
|
res_p += SIZE_FP;
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_FP_AUT);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_FP);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_FP);
|
||||||
|
res_p += SIZE_FP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_cafp_all (uint16_t tag)
|
||||||
|
{
|
||||||
|
struct do_table_entry *do_p;
|
||||||
|
const uint8_t *do_data;
|
||||||
|
|
||||||
|
if (with_tag)
|
||||||
|
{
|
||||||
|
copy_tag (tag);
|
||||||
|
*res_p++ = SIZE_FP*3;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_CAFP_1);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_FP);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_FP);
|
||||||
|
res_p += SIZE_FP;
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_CAFP_2);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_FP);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_FP);
|
||||||
|
res_p += SIZE_FP;
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_CAFP_3);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_FP);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_FP);
|
||||||
|
res_p += SIZE_FP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_kgtime_all (uint16_t tag)
|
||||||
|
{
|
||||||
|
struct do_table_entry *do_p;
|
||||||
|
const uint8_t *do_data;
|
||||||
|
|
||||||
|
if (with_tag)
|
||||||
|
{
|
||||||
|
copy_tag (tag);
|
||||||
|
*res_p++ = SIZE_KGTIME*3;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_KGTIME_SIG);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_KGTIME);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_KGTIME);
|
||||||
|
res_p += SIZE_KGTIME;
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_KGTIME_DEC);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_KGTIME);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_KGTIME);
|
||||||
|
res_p += SIZE_KGTIME;
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_KGTIME_AUT);
|
||||||
|
do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data)
|
||||||
|
memcpy (res_p, &do_data[1], SIZE_KGTIME);
|
||||||
|
else
|
||||||
|
memset (res_p, 0, SIZE_KGTIME);
|
||||||
|
res_p += SIZE_KGTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
put_hex (uint8_t nibble)
|
||||||
|
{
|
||||||
|
uint8_t c;
|
||||||
|
|
||||||
|
if (nibble < 0x0a)
|
||||||
|
c = '0' + nibble;
|
||||||
|
else
|
||||||
|
c = 'a' + nibble - 0x0a;
|
||||||
|
|
||||||
|
_write (&c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
o_put_byte (uint8_t b)
|
||||||
|
{
|
||||||
|
_write (" ", 1);
|
||||||
|
put_hex (b >> 4);
|
||||||
|
put_hex (b &0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4d, xx, xx: Extended Header List
|
||||||
|
* b6 00 (SIG) / b8 00 (DEC) / a4 00 (AUT)
|
||||||
|
* 7f48, xx: cardholder private key template
|
||||||
|
* 91 xx
|
||||||
|
* 92 xx
|
||||||
|
* 93 xx
|
||||||
|
* 5f48, xx: cardholder privatge key
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
proc_key_import (uint16_t tag, uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
o_put_byte (data[i]);
|
||||||
|
if ((i & 0x0f) == 0x0f)
|
||||||
|
_write ("\r\n", 2);
|
||||||
|
}
|
||||||
|
_write ("\r\n", 2);
|
||||||
|
|
||||||
|
write_res_apdu (NULL, 0, 0x65, 0x81); /* memory failure */
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint16_t const cn_ch_data[] = {
|
||||||
|
3,
|
||||||
|
GPG_DO_NAME,
|
||||||
|
GPG_DO_LANGUAGE,
|
||||||
|
GPG_DO_SEX,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint16_t const cn_app_data[] = {
|
||||||
|
10,
|
||||||
|
GPG_DO_AID,
|
||||||
|
GPG_DO_HIST_BYTES,
|
||||||
|
/* XXX Discretionary data objects 0x0073 ??? */
|
||||||
|
GPG_DO_EXTCAP,
|
||||||
|
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
|
||||||
|
GPG_DO_PW_STATUS,
|
||||||
|
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint16_t const cn_ss_temp[] = { 1, GPG_DO_DS_COUNT };
|
||||||
|
|
||||||
|
static struct do_table_entry
|
||||||
|
gpg_do_table[] = {
|
||||||
|
/* Pseudo DO (private): not user accessible */
|
||||||
|
{ GNUK_DO_KEYPTR_SIG, DO_KEYPTR, AC_NEVER, AC_NEVER, NULL },
|
||||||
|
{ GNUK_DO_KEYPTR_DEC, DO_KEYPTR, AC_NEVER, AC_NEVER, NULL },
|
||||||
|
{ GNUK_DO_KEYPTR_AUT, DO_KEYPTR, AC_NEVER, AC_NEVER, NULL },
|
||||||
|
{ GNUK_DO_HASH_PW3, DO_HASH, AC_NEVER, AC_NEVER, NULL },
|
||||||
|
/* Pseudo DO: calculated */
|
||||||
|
{ GPG_DO_HIST_BYTES, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_hist_bytes },
|
||||||
|
{ GPG_DO_FP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_fp_all },
|
||||||
|
{ GPG_DO_CAFP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_cafp_all },
|
||||||
|
{ GPG_DO_KGTIME_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_kgtime_all },
|
||||||
|
/* Fixed data */
|
||||||
|
{ GPG_DO_AID, DO_FIXED, AC_ALWAYS, AC_NEVER, aid },
|
||||||
|
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
|
||||||
|
{ GPG_DO_ALG_SIG, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr },
|
||||||
|
{ GPG_DO_ALG_DEC, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr },
|
||||||
|
{ GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr },
|
||||||
|
/* Variable(s): Fixed size, not changeable by user */
|
||||||
|
{ GPG_DO_DS_COUNT, DO_VAR, AC_ALWAYS, AC_NEVER, NULL },
|
||||||
|
/* Variables: Fixed size */
|
||||||
|
{ GPG_DO_PW_STATUS, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_SEX, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_FP_SIG, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_FP_DEC, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_FP_AUT, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_CAFP_1, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_CAFP_2, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_CAFP_3, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_KGTIME_SIG, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_KGTIME_DEC, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_KGTIME_AUT, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
/* Variables: Variable size */
|
||||||
|
{ GPG_DO_LOGIN_DATA, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_URL, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_NAME, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_LANGUAGE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
{ GPG_DO_CH_CERTIFICATE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
/* Variable(s): Variable size, write only by user */
|
||||||
|
{ GPG_DO_RESETTING_CODE, DO_VAR, AC_NEVER, AC_ADMIN_AUTHORIZED, NULL },
|
||||||
|
/* Compound data: Read access only */
|
||||||
|
{ GPG_DO_CH_DATA, DO_CN_READ, AC_ALWAYS, AC_NEVER, cn_ch_data },
|
||||||
|
{ GPG_DO_APP_DATA, DO_CN_READ, AC_ALWAYS, AC_NEVER, cn_app_data },
|
||||||
|
{ GPG_DO_SS_TEMP, DO_CN_READ, AC_ALWAYS, AC_NEVER, cn_ss_temp },
|
||||||
|
/* Compound data: Write access only*/
|
||||||
|
{ GPG_DO_KEY_IMPORT, DO_PROC_WRITE, AC_NEVER, AC_ADMIN_AUTHORIZED,
|
||||||
|
proc_key_import },
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NUM_DO_ENTRIES (int)(sizeof (gpg_do_table) / sizeof (struct do_table_entry))
|
||||||
|
|
||||||
|
extern const uint8_t const do_5e[];
|
||||||
|
extern const uint8_t const do_c4[];
|
||||||
|
extern const uint8_t const do_c7[];
|
||||||
|
extern const uint8_t const do_ca[];
|
||||||
|
extern const uint8_t const do_ce[];
|
||||||
|
extern const uint8_t const do_5b[];
|
||||||
|
extern const uint8_t const do_5f2d[];
|
||||||
|
extern const uint8_t const do_5f35[];
|
||||||
|
extern const uint8_t const do_93[];
|
||||||
|
extern const uint8_t const do_5f50[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize GPG_DO_TABLE reading from Flash ROM
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
gpg_do_table_init (void)
|
||||||
|
{
|
||||||
|
struct do_table_entry *do_p;
|
||||||
|
|
||||||
|
do_p = get_do_entry (GPG_DO_LOGIN_DATA);
|
||||||
|
do_p->obj = do_5e;
|
||||||
|
do_p = get_do_entry (GPG_DO_PW_STATUS);
|
||||||
|
do_p->obj = do_c4;
|
||||||
|
#if 0
|
||||||
|
do_p = get_do_entry (GPG_DO_FP_SIG);
|
||||||
|
do_p->obj = do_c7;
|
||||||
|
do_p = get_do_entry (GPG_DO_CAFP_1);
|
||||||
|
do_p->obj = do_ca;
|
||||||
|
do_p = get_do_entry (GPG_DO_KGTIME_SIG);
|
||||||
|
do_p->obj = do_ce;
|
||||||
|
#endif
|
||||||
|
do_p = get_do_entry (GPG_DO_NAME);
|
||||||
|
do_p->obj = do_5b;
|
||||||
|
do_p = get_do_entry (GPG_DO_LANGUAGE);
|
||||||
|
do_p->obj = do_5f2d;
|
||||||
|
do_p = get_do_entry (GPG_DO_SEX);
|
||||||
|
do_p->obj = do_5f35;
|
||||||
|
do_p = get_do_entry (GPG_DO_DS_COUNT);
|
||||||
|
do_p->obj = do_93;
|
||||||
|
do_p = get_do_entry (GPG_DO_URL);
|
||||||
|
do_p->obj = do_5f50;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct do_table_entry *
|
||||||
|
get_do_entry (uint16_t tag)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_DO_ENTRIES; i++)
|
||||||
|
if (gpg_do_table[i].tag == tag)
|
||||||
|
return &gpg_do_table[i];
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
copy_do_1 (uint16_t tag, const uint8_t *do_data)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (with_tag)
|
||||||
|
{
|
||||||
|
copy_tag (tag);
|
||||||
|
|
||||||
|
if (do_data[0] < 127)
|
||||||
|
len = do_data[0] + 1;
|
||||||
|
else if (do_data[1] == 0x81)
|
||||||
|
len = do_data[1] + 2;
|
||||||
|
else /* 0x82 */
|
||||||
|
len = ((do_data[1] << 8) | do_data[2]) + 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (do_data[0] < 127)
|
||||||
|
{
|
||||||
|
len = do_data[0];
|
||||||
|
do_data++;
|
||||||
|
}
|
||||||
|
else if (do_data[1] == 0x81)
|
||||||
|
{
|
||||||
|
len = do_data[1];
|
||||||
|
do_data += 2;
|
||||||
|
}
|
||||||
|
else /* 0x82 */
|
||||||
|
{
|
||||||
|
len = ((do_data[1] << 8) | do_data[2]);
|
||||||
|
do_data += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (res_p, do_data, len);
|
||||||
|
res_p += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
copy_do (struct do_table_entry *do_p)
|
||||||
|
{
|
||||||
|
if (do_p == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ac_check_status (do_p->ac_read) == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (do_p->do_type)
|
||||||
|
{
|
||||||
|
case DO_FIXED:
|
||||||
|
case DO_VAR:
|
||||||
|
{
|
||||||
|
const uint8_t *do_data = (const uint8_t *)do_p->obj;
|
||||||
|
if (do_data == NULL)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
copy_do_1 (do_p->tag, do_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DO_CN_READ:
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const uint16_t *cn_data = (const uint16_t *)do_p->obj;
|
||||||
|
int num_components = cn_data[0];
|
||||||
|
uint8_t *len_p;
|
||||||
|
|
||||||
|
copy_tag (do_p->tag);
|
||||||
|
*res_p++ = 0x81;
|
||||||
|
len_p = res_p;
|
||||||
|
*res_p++ = 0; /* for now */
|
||||||
|
with_tag = 1;
|
||||||
|
|
||||||
|
for (i = 0; i < num_components; i++)
|
||||||
|
{
|
||||||
|
uint16_t tag0;
|
||||||
|
struct do_table_entry *do0_p;
|
||||||
|
|
||||||
|
tag0 = cn_data[i+1];
|
||||||
|
do0_p = get_do_entry (tag0);
|
||||||
|
if (copy_do (do0_p) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*len_p = (res_p - len_p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DO_PROC_READ:
|
||||||
|
{
|
||||||
|
void (*do_func)(uint16_t) = (void (*)(uint16_t))do_p->obj;
|
||||||
|
|
||||||
|
do_func (do_p->tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DO_PROC_WRITE:
|
||||||
|
case DO_HASH:
|
||||||
|
case DO_KEYPTR:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process GET_DATA request on Data Object specified by TAG
|
||||||
|
* Call write_res_adpu to fill data returned
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gpg_do_get_data (uint16_t tag)
|
||||||
|
{
|
||||||
|
struct do_table_entry *do_p = get_do_entry (tag);
|
||||||
|
|
||||||
|
res_p = res_APDU;
|
||||||
|
with_tag = 0;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
put_string (" ");
|
||||||
|
put_short (tag);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (do_p)
|
||||||
|
{
|
||||||
|
if (copy_do (do_p) < 0)
|
||||||
|
/* Overwrite partially written result */
|
||||||
|
write_res_apdu (NULL, 0, 0x69, 0x82);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*res_p++ = 0x90;
|
||||||
|
*res_p++ = 0x00;
|
||||||
|
res_APDU_size = res_p - res_APDU;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* No record */
|
||||||
|
write_res_apdu (NULL, 0, 0x6a, 0x88);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *
|
||||||
|
flash_do_write (uint16_t tag, uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
static uint8_t do_pool[1024];
|
||||||
|
static uint8_t *last_p = do_pool;
|
||||||
|
uint8_t *p = last_p;
|
||||||
|
|
||||||
|
if (last_p - do_pool + len + 2 + 3 > 1024)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*last_p++ = (tag >> 8);
|
||||||
|
*last_p++ = (tag & 0xff);
|
||||||
|
if (len < 128)
|
||||||
|
*last_p++ = len;
|
||||||
|
else if (len < 256)
|
||||||
|
{
|
||||||
|
*last_p++ = 0x81;
|
||||||
|
*last_p++ = len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*last_p++ = 0x82;
|
||||||
|
*last_p++ = (len >> 8);
|
||||||
|
*last_p++ = (len & 0xff);
|
||||||
|
}
|
||||||
|
memcpy (last_p, data, len);
|
||||||
|
last_p += len;
|
||||||
|
|
||||||
|
return p + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gpg_do_put_data (uint16_t tag, uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
struct do_table_entry *do_p = get_do_entry (tag);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
put_string (" ");
|
||||||
|
put_short (tag);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (do_p)
|
||||||
|
{
|
||||||
|
if (ac_check_status (do_p->ac_write) == 0)
|
||||||
|
{
|
||||||
|
write_res_apdu (NULL, 0, 0x69, 0x82);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (do_p->do_type)
|
||||||
|
{
|
||||||
|
case DO_FIXED:
|
||||||
|
case DO_CN_READ:
|
||||||
|
case DO_PROC_READ:
|
||||||
|
case DO_HASH:
|
||||||
|
case DO_KEYPTR:
|
||||||
|
write_res_apdu (NULL, 0, 0x69, 0x82);
|
||||||
|
break;
|
||||||
|
case DO_VAR:
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
const uint8_t *do_data = (const uint8_t *)do_p->obj;
|
||||||
|
|
||||||
|
flash_do_release (do_data);
|
||||||
|
#endif
|
||||||
|
if (tag == GPG_DO_PW_STATUS)
|
||||||
|
{
|
||||||
|
/* XXX: only the first byte can be changed */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
/* make DO empty */
|
||||||
|
do_p->obj = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
do_p->obj = flash_do_write (tag, data, len);
|
||||||
|
if (do_p->obj)
|
||||||
|
write_res_apdu (NULL, 0, 0x90, 0x00); /* success */
|
||||||
|
else
|
||||||
|
write_res_apdu (NULL, 0, 0x65, 0x81); /* memory failure */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (tag == GPG_DO_RESETTING_CODE)
|
||||||
|
{
|
||||||
|
/* XXX: Changing Resetting code,
|
||||||
|
* we need to reset RC counter in GPG_DO_PW_STATUS */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DO_PROC_WRITE:
|
||||||
|
{
|
||||||
|
void (*proc_func)(uint16_t, uint8_t *, int)
|
||||||
|
= (void (*)(uint16_t, uint8_t *, int))do_p->obj;
|
||||||
|
|
||||||
|
proc_func (tag, data, len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* No record */
|
||||||
|
write_res_apdu (NULL, 0, 0x6a, 0x88);
|
||||||
|
}
|
||||||
363
src/gpg.c
363
src/gpg.c
@@ -46,6 +46,16 @@ put_byte (uint8_t b)
|
|||||||
_write ("\r\n", 2);
|
_write ("\r\n", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
put_short (uint16_t x)
|
||||||
|
{
|
||||||
|
put_hex (x >> 12);
|
||||||
|
put_hex ((x >> 8)&0x0f);
|
||||||
|
put_hex ((x >> 4)&0x0f);
|
||||||
|
put_hex (x & 0x0f);
|
||||||
|
_write ("\r\n", 2);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
put_string (const char *s)
|
put_string (const char *s)
|
||||||
{
|
{
|
||||||
@@ -53,10 +63,11 @@ put_string (const char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define RSA_SIGNATURE_LENGTH 128 /* 256 byte == 2048-bit */
|
#define RSA_SIGNATURE_LENGTH 128 /* 256 *//* 256 byte == 2048-bit */
|
||||||
extern unsigned char *rsa_sign (unsigned char *);
|
extern unsigned char *rsa_sign (unsigned char *);
|
||||||
|
|
||||||
#define INS_PUT_DATA 0xDA
|
#define INS_PUT_DATA 0xDA
|
||||||
|
#define INS_PUT_DATA_ODD 0xDB /* For key import */
|
||||||
#define INS_VERIFY 0x20
|
#define INS_VERIFY 0x20
|
||||||
#define INS_GET_DATA 0xCA
|
#define INS_GET_DATA 0xCA
|
||||||
#define INS_GET_RESPONSE 0xC0
|
#define INS_GET_RESPONSE 0xC0
|
||||||
@@ -66,50 +77,12 @@ extern unsigned char *rsa_sign (unsigned char *);
|
|||||||
#define INS_PSO 0x2A
|
#define INS_PSO 0x2A
|
||||||
|
|
||||||
extern const char const select_file_TOP_result[20];
|
extern const char const select_file_TOP_result[20];
|
||||||
extern const char const get_data_64_result[7];
|
|
||||||
extern const char const get_data_5e_result[6];
|
|
||||||
extern const char const do_6e_head[3];
|
|
||||||
extern const char const do_47[2+3];
|
|
||||||
extern const char const do_4f[2+16];
|
|
||||||
extern const char const do_c0[2+1];
|
|
||||||
extern const char const do_c1[2+1];
|
|
||||||
extern const char const do_c2[2+1];
|
|
||||||
extern const char const do_c3[2+1];
|
|
||||||
extern const char const do_c4[2+7];
|
|
||||||
extern const char const do_c5[2+60];
|
|
||||||
extern const char const do_c6[2+60];
|
|
||||||
extern const char const do_cd[2+12];
|
|
||||||
extern const char const do_65_head[2];
|
|
||||||
extern const char const do_5b[2+12];
|
|
||||||
extern const char const do_5f2d[3+2];
|
|
||||||
extern const char const do_5f35[3+1];
|
|
||||||
extern const char const do_7a_head[2];
|
|
||||||
extern const char const do_93[2+3];
|
|
||||||
extern const char const do_5f50[3+20];
|
|
||||||
extern const char const do_5f52[3+10];
|
|
||||||
extern const char const get_data_rb_result[6];
|
extern const char const get_data_rb_result[6];
|
||||||
extern const char const get_data_sigkey_result[7+128];
|
extern const char const get_data_sigkey_result[7+128];
|
||||||
extern const char const get_data_enckey_result[7+128];
|
extern const char const get_data_enckey_result[7+128];
|
||||||
|
|
||||||
|
|
||||||
/*
|
void
|
||||||
* 73
|
|
||||||
* 101
|
|
||||||
* 102
|
|
||||||
* 103
|
|
||||||
* 104
|
|
||||||
*
|
|
||||||
* 65 - 5b, 5f2d, 5f35
|
|
||||||
* 6e - 47, 4f, c0, c1, c2, c3, c4, c5, c6, cd
|
|
||||||
* 7a - 93
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* 65 L-65 [5b L-5b .... ] [5f2d 2 'j' 'a'] [5f35 1 '1']
|
|
||||||
* 6e L-6e [47 3 x x x ] [4f L-4f ...] [c0 L-c0 ...] ...
|
|
||||||
* 7a L-7a [93 L-93 ... ]
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2)
|
write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2)
|
||||||
{
|
{
|
||||||
res_APDU_size = 2 + len;
|
res_APDU_size = 2 + len;
|
||||||
@@ -119,25 +92,62 @@ write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2)
|
|||||||
res_APDU[len+1] = sw2;
|
res_APDU[len+1] = sw2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
#define FILE_NONE -1
|
||||||
|
#define FILE_DF_OPENPGP 0
|
||||||
|
#define FILE_MF 1
|
||||||
|
#define FILE_EF_DIR 2
|
||||||
|
#define FILE_EF_SERIAL 3
|
||||||
|
|
||||||
|
static int file_selection = FILE_NONE;
|
||||||
|
|
||||||
|
static void
|
||||||
process_command_apdu (void)
|
process_command_apdu (void)
|
||||||
{
|
{
|
||||||
/*
|
uint16_t tag;
|
||||||
INS_VERIFY
|
uint8_t *data;
|
||||||
|
int len;
|
||||||
|
|
||||||
00 20 00 81 06 - ???
|
if (cmd_APDU[1] == INS_VERIFY)
|
||||||
CHV1
|
{
|
||||||
00 20 00 82 06 - ???
|
uint8_t p2 = cmd_APDU[3];
|
||||||
CHV2
|
int r;
|
||||||
00 20 00 83 08 - ???
|
|
||||||
CHV3
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (cmd_APDU[1] == INS_PUT_DATA)
|
put_string (" - VERIFY\r\n");
|
||||||
|
|
||||||
|
len = cmd_APDU[4];
|
||||||
|
if (p2 == 0x81)
|
||||||
|
r = verify_pso_cds (&cmd_APDU[5], len);
|
||||||
|
else if (p2 == 0x82)
|
||||||
|
r = verify_pso_other (&cmd_APDU[5], len);
|
||||||
|
else
|
||||||
|
r = verify_pso_admin (&cmd_APDU[5], len);
|
||||||
|
|
||||||
|
if (r < 0)
|
||||||
|
write_res_apdu (NULL, 0, 0x69, 0x82);
|
||||||
|
else
|
||||||
|
write_res_apdu (NULL, 0, 0x90, 0x00);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd_APDU[1] == INS_PUT_DATA || cmd_APDU[1] == INS_PUT_DATA_ODD)
|
||||||
{
|
{
|
||||||
put_string (" - PUT DATA\r\n");
|
put_string (" - PUT DATA\r\n");
|
||||||
write_res_apdu (NULL, 0, 0x90, 0x00); /* 0x6a, 0x88: No record */
|
|
||||||
return 0;
|
if (file_selection != FILE_DF_OPENPGP)
|
||||||
|
write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */
|
||||||
|
|
||||||
|
tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
|
||||||
|
len = cmd_APDU_size - 5;
|
||||||
|
data = &cmd_APDU[5];
|
||||||
|
if (len >= 256)
|
||||||
|
/* extended Lc */
|
||||||
|
{
|
||||||
|
data += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpg_do_put_data (tag, data, len);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_APDU[1] == INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR)
|
if (cmd_APDU[1] == INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR)
|
||||||
@@ -183,218 +193,82 @@ INS_VERIFY
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cmd_APDU[1] == INS_READ_BINARY)
|
else if (cmd_APDU[1] == INS_READ_BINARY)
|
||||||
{ /* it must be for DF 0x2f02 */
|
{
|
||||||
put_string (" - Read binary\r\n");
|
put_string (" - Read binary\r\n");
|
||||||
|
|
||||||
if (cmd_APDU[3] >= 6)
|
if (file_selection == FILE_EF_SERIAL)
|
||||||
{
|
{
|
||||||
write_res_apdu (NULL, 0, 0x6b, 0x00); /* BAD_P0_P1 */
|
if (cmd_APDU[3] >= 6)
|
||||||
|
write_res_apdu (NULL, 0, 0x6b, 0x00); /* BAD_P0_P1 */
|
||||||
|
else
|
||||||
|
/* Tag 5a, serial number */
|
||||||
|
write_res_apdu (get_data_rb_result,
|
||||||
|
sizeof (get_data_rb_result), 0x90, 0x00);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ /* Tag 5a, serial number */
|
write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */
|
||||||
write_res_apdu (get_data_rb_result,
|
|
||||||
sizeof (get_data_rb_result), 0x90, 0x00);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (cmd_APDU[1] == INS_SELECT_FILE)
|
else if (cmd_APDU[1] == INS_SELECT_FILE)
|
||||||
{
|
{
|
||||||
if (cmd_APDU[2] == 4) /* Selection by DF name */
|
if (cmd_APDU[2] == 4) /* Selection by DF name */
|
||||||
{
|
{
|
||||||
put_string (" - select DF by name\r\n");
|
put_string (" - select DF by name\r\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: Should return contents.
|
* P2 == 0, LC=6, name = D2 76 00 01 24 01
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (1)
|
file_selection = FILE_DF_OPENPGP;
|
||||||
{
|
|
||||||
write_res_apdu (NULL, 0, 0x90, 0x00);
|
/* XXX: Should return contents??? */
|
||||||
}
|
write_res_apdu (NULL, 0, 0x90, 0x00);
|
||||||
}
|
}
|
||||||
else if (cmd_APDU[4] == 2
|
else if (cmd_APDU[4] == 2
|
||||||
&& cmd_APDU[5] == 0x2f
|
&& cmd_APDU[5] == 0x2f
|
||||||
&& cmd_APDU[6] == 02)
|
&& cmd_APDU[6] == 0x02)
|
||||||
{
|
{
|
||||||
put_string (" - select 0x2f02 EF\r\n");
|
put_string (" - select 0x2f02 EF\r\n");
|
||||||
/*
|
/*
|
||||||
* MF.EF-GDO -- Serial number of the card and name of the owner
|
* MF.EF-GDO -- Serial number of the card and name of the owner
|
||||||
*/
|
*/
|
||||||
write_res_apdu (NULL, 0, 0x90, 0x00);
|
write_res_apdu (NULL, 0, 0x90, 0x00);
|
||||||
|
file_selection = FILE_EF_SERIAL;
|
||||||
|
}
|
||||||
|
else if (cmd_APDU[4] == 2
|
||||||
|
&& cmd_APDU[5] == 0x3f
|
||||||
|
&& cmd_APDU[6] == 0x00)
|
||||||
|
{
|
||||||
|
put_string (" - select ROOT MF\r\n");
|
||||||
|
if (cmd_APDU[3] == 0x0c)
|
||||||
|
{
|
||||||
|
write_res_apdu (NULL, 0, 0x90, 0x00);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_res_apdu (select_file_TOP_result,
|
||||||
|
sizeof (select_file_TOP_result), 0x90, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_selection = FILE_MF;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (cmd_APDU[4] == 2
|
{
|
||||||
&& cmd_APDU[5] == 0x3f
|
put_string (" - select ?? \r\n");
|
||||||
&& cmd_APDU[6] == 0)
|
|
||||||
{
|
|
||||||
put_string (" - select ROOT MF\r\n");
|
|
||||||
if (cmd_APDU[3] == 0x0c)
|
|
||||||
{
|
|
||||||
write_res_apdu (NULL, 0, 0x90, 0x00);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
write_res_apdu (select_file_TOP_result,
|
|
||||||
sizeof (select_file_TOP_result), 0x90, 0x00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
put_string (" - select ?? \r\n");
|
|
||||||
|
|
||||||
write_res_apdu (NULL, 0, 0x6a, 0x82); /* File missing */
|
write_res_apdu (NULL, 0, 0x6a, 0x82); /* File missing */
|
||||||
}
|
file_selection = FILE_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (cmd_APDU[1] == INS_GET_DATA)
|
else if (cmd_APDU[1] == INS_GET_DATA)
|
||||||
{
|
{
|
||||||
|
tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
|
||||||
|
|
||||||
put_string (" - Get Data\r\n");
|
put_string (" - Get Data\r\n");
|
||||||
|
|
||||||
switch (((cmd_APDU[2]<<8) | cmd_APDU[3]))
|
if (file_selection != FILE_DF_OPENPGP)
|
||||||
{
|
write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */
|
||||||
case 0x4f: /* AID */
|
|
||||||
{
|
gpg_do_get_data (tag);
|
||||||
put_string (" AID\r\n");
|
|
||||||
write_res_apdu (&do_4f[2],
|
|
||||||
sizeof (do_4f) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x5e: /* Login data */
|
|
||||||
{
|
|
||||||
put_string (" Login data\r\n");
|
|
||||||
write_res_apdu (get_data_5e_result,
|
|
||||||
sizeof (get_data_5e_result), 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x64:
|
|
||||||
{
|
|
||||||
put_string (" 64\r\n");
|
|
||||||
write_res_apdu (get_data_64_result,
|
|
||||||
sizeof (get_data_64_result), 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xc0:
|
|
||||||
{
|
|
||||||
put_string (" c0\r\n");
|
|
||||||
write_res_apdu (&do_c0[2],
|
|
||||||
sizeof (do_c0) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xc1:
|
|
||||||
{
|
|
||||||
put_string (" c1\r\n");
|
|
||||||
write_res_apdu (&do_c1[2],
|
|
||||||
sizeof (do_c1) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xc2:
|
|
||||||
{
|
|
||||||
put_string (" c2\r\n");
|
|
||||||
write_res_apdu (&do_c2[2],
|
|
||||||
sizeof (do_c2) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xc3:
|
|
||||||
{
|
|
||||||
put_string (" c3\r\n");
|
|
||||||
write_res_apdu (&do_c3[2],
|
|
||||||
sizeof (do_c3) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xc4:
|
|
||||||
{
|
|
||||||
put_string (" c4\r\n");
|
|
||||||
write_res_apdu (&do_c4[2],
|
|
||||||
sizeof (do_c4) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x5b: /* Name */
|
|
||||||
{
|
|
||||||
put_string (" 5b\r\n");
|
|
||||||
write_res_apdu (&do_5b[2],
|
|
||||||
sizeof (do_5b) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x93: /* Digital Signature Counter (3-bytes) */
|
|
||||||
{
|
|
||||||
put_string (" 93\r\n");
|
|
||||||
write_res_apdu (&do_93[2],
|
|
||||||
sizeof (do_93) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xc5: /* Fingerprints */
|
|
||||||
{
|
|
||||||
put_string (" c5\r\n");
|
|
||||||
write_res_apdu (&do_c5[2],
|
|
||||||
sizeof (do_c5) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x5f2d: /* Language preference */
|
|
||||||
{
|
|
||||||
put_string (" 5f2d\r\n");
|
|
||||||
write_res_apdu (&do_5f2d[3],
|
|
||||||
sizeof (do_5f2d) - 3, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x5f35: /* Sex */
|
|
||||||
{
|
|
||||||
put_string (" 5f35\r\n");
|
|
||||||
write_res_apdu (&do_5f35[3],
|
|
||||||
sizeof (do_5f35) - 3, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x5f50: /* URL */
|
|
||||||
{
|
|
||||||
put_string (" 5f50\r\n");
|
|
||||||
write_res_apdu (&do_5f50[3],
|
|
||||||
sizeof (do_5f50) - 3, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x5f52: /* Historycal bytes */
|
|
||||||
{
|
|
||||||
put_string (" 5f52\r\n");
|
|
||||||
write_res_apdu (&do_5f52[3],
|
|
||||||
sizeof (do_5f52) - 3, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x65: /* Card Holder Related Data (Tag) */
|
|
||||||
{
|
|
||||||
put_string (" 65\r\n");
|
|
||||||
write_res_apdu (do_65_head,
|
|
||||||
do_65_head[1] + 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x6e: /* Application Related Data (Tag) */
|
|
||||||
{
|
|
||||||
put_string (" 6e\r\n");
|
|
||||||
write_res_apdu (do_6e_head,
|
|
||||||
do_6e_head[2] + 3, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x7a: /* Security Support Template (Tag) */
|
|
||||||
{
|
|
||||||
put_string (" 7a\r\n");
|
|
||||||
write_res_apdu (do_7a_head,
|
|
||||||
do_7a_head[1] + 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xc6: /* List of CA fingerprints */
|
|
||||||
{
|
|
||||||
put_string (" c6\r\n");
|
|
||||||
write_res_apdu (&do_c6[2],
|
|
||||||
sizeof (do_c6) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xcd: /* List of generation dates/times public-key pairs */
|
|
||||||
{
|
|
||||||
put_string (" cd\r\n");
|
|
||||||
write_res_apdu (&do_cd[2],
|
|
||||||
sizeof (do_cd) - 2, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
put_string (" ?");
|
|
||||||
put_byte (((cmd_APDU[2]<<8) | cmd_APDU[3]));
|
|
||||||
write_res_apdu (NULL, 0, 0x90, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (cmd_APDU[1] == INS_PSO)
|
else if (cmd_APDU[1] == INS_PSO)
|
||||||
{
|
{
|
||||||
@@ -402,11 +276,14 @@ INS_VERIFY
|
|||||||
|
|
||||||
if (cmd_APDU[2] == 0x9E && cmd_APDU[3] == 0x9A)
|
if (cmd_APDU[2] == 0x9E && cmd_APDU[3] == 0x9A)
|
||||||
{
|
{
|
||||||
if (cmd_APDU_size != 5 + 35 && cmd_APDU_size != 5 + 35 + 1)
|
if (cmd_APDU_size != 8 + 35 && cmd_APDU_size != 8 + 35 + 1)
|
||||||
put_string (" wrong length\r\n");
|
{
|
||||||
|
put_string (" wrong length: ");
|
||||||
|
put_short (cmd_APDU_size);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned char * r = rsa_sign (&cmd_APDU[5]);
|
unsigned char * r = rsa_sign (&cmd_APDU[7]);
|
||||||
write_res_apdu (r, RSA_SIGNATURE_LENGTH, 0x90, 0x00);
|
write_res_apdu (r, RSA_SIGNATURE_LENGTH, 0x90, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,17 +291,19 @@ INS_VERIFY
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
put_string (" - ???\r\n");
|
put_string (" - ??");
|
||||||
|
put_byte (cmd_APDU[2]);
|
||||||
|
put_string (" - ??");
|
||||||
|
put_byte (cmd_APDU[3]);
|
||||||
write_res_apdu (NULL, 0, 0x90, 0x00);
|
write_res_apdu (NULL, 0, 0x90, 0x00);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
put_string (" - ???\r\n");
|
put_string (" - ??");
|
||||||
write_res_apdu (NULL, 0, 0x90, 0x00);
|
put_byte (cmd_APDU[1]);
|
||||||
|
write_res_apdu (NULL, 0, 0x6D, 0x00); /* INS not supported. */
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread *gpg_thread;
|
Thread *gpg_thread;
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
#include "usb_lld.h"
|
#include "usb_lld.h"
|
||||||
|
|
||||||
|
#include "gnuk.h"
|
||||||
|
|
||||||
#include "usb_lib.h"
|
#include "usb_lib.h"
|
||||||
#include "usb_istr.h"
|
#include "usb_istr.h"
|
||||||
#include "usb_desc.h"
|
#include "usb_desc.h"
|
||||||
@@ -73,11 +75,11 @@ stdout_init (void)
|
|||||||
stdout.str = NULL;
|
stdout.str = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
_write (const char *s, int size)
|
_write (const char *s, int size)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
chMtxLock (&stdout.m);
|
chMtxLock (&stdout.m);
|
||||||
while (stdout.str)
|
while (stdout.str)
|
||||||
@@ -87,7 +89,6 @@ _write (const char *s, int size)
|
|||||||
chCondSignal (&stdout.start_cnd);
|
chCondSignal (&stdout.start_cnd);
|
||||||
chCondWait (&stdout.finish_cnd);
|
chCondWait (&stdout.finish_cnd);
|
||||||
chMtxUnlock ();
|
chMtxUnlock ();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint32_t count_in;
|
extern uint32_t count_in;
|
||||||
@@ -180,6 +181,8 @@ int main(int argc, char **argv)
|
|||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
|
gpg_do_table_init ();
|
||||||
|
|
||||||
usb_lld_init ();
|
usb_lld_init ();
|
||||||
USB_Init();
|
USB_Init();
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ rsa_sign (unsigned char *raw_message)
|
|||||||
{
|
{
|
||||||
rsa_context ctx;
|
rsa_context ctx;
|
||||||
mpi P1, Q1, H;
|
mpi P1, Q1, H;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = (cmd_APDU[5]<<8) | cmd_APDU[6]; /* cmd_APDU_size - 6 */
|
||||||
|
|
||||||
mpi_init( &P1, &Q1, &H, NULL );
|
mpi_init( &P1, &Q1, &H, NULL );
|
||||||
rsa_init( &ctx, RSA_PKCS_V15, 0, NULL, NULL );
|
rsa_init( &ctx, RSA_PKCS_V15, 0, NULL, NULL );
|
||||||
@@ -104,10 +107,11 @@ rsa_sign (unsigned char *raw_message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
rsa_pkcs1_sign( &ctx, RSA_PRIVATE, SIG_RSA_SHA256, 0, raw_message, output);
|
rsa_pkcs1_sign( &ctx, RSA_PRIVATE, SIG_RSA_RAW, len, raw_message, output);
|
||||||
|
put_string ("done.\r\n");
|
||||||
|
return output;
|
||||||
#else
|
#else
|
||||||
rsa_pkcs1_sign( &ctx, RSA_PRIVATE, SIG_RSA_RAW, 35, raw_message, output );
|
rsa_pkcs1_sign( &ctx, RSA_PRIVATE, SIG_RSA_RAW, len, raw_message, output );
|
||||||
|
|
||||||
put_string ("done.\r\n");
|
put_string ("done.\r\n");
|
||||||
return output;
|
return output;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -130,12 +130,16 @@ EP5_OUT_Callback (void)
|
|||||||
icc_data_size = len - ICC_MSG_HEADER_SIZE;
|
icc_data_size = len - ICC_MSG_HEADER_SIZE;
|
||||||
icc_seq = icc_header->seq;
|
icc_seq = icc_header->seq;
|
||||||
|
|
||||||
if (icc_data_size < 0 || icc_data_size != icc_header->data_len)
|
if (icc_data_size < 0)
|
||||||
/* just ignore short invalid packet, enable Rx again */
|
/* just ignore short invalid packet, enable Rx again */
|
||||||
SetEPRxValid (ENDP5);
|
SetEPRxValid (ENDP5);
|
||||||
else
|
else
|
||||||
/* Notify icc_thread */
|
/* Notify icc_thread */
|
||||||
chEvtSignalI (icc_thread, EV_RX_DATA_READY);
|
chEvtSignalI (icc_thread, EV_RX_DATA_READY);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* what if (icc_data_size != icc_header->data_len)???
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
enum icc_state
|
enum icc_state
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ static const uint8_t gnukConfigDescriptor[] = {
|
|||||||
0, 0, 0, 0, /* dwSynchProtocols: FIXED VALUE */
|
0, 0, 0, 0, /* dwSynchProtocols: FIXED VALUE */
|
||||||
0, 0, 0, 0, /* dwMechanical: FIXED VALUE */
|
0, 0, 0, 0, /* dwMechanical: FIXED VALUE */
|
||||||
0x40, 0x08, 0x04, 0x00, /* dwFeatures: Short and extended ADPU level */
|
0x40, 0x08, 0x04, 0x00, /* dwFeatures: Short and extended ADPU level */
|
||||||
0x0f, 0x01, 0, 0, /* dwMaxCCIDMessageLength: 261+10 XXX */
|
0x40, 0x00, 0, 0, /* dwMaxCCIDMessageLength: 64 */
|
||||||
0xff, /* bClassGetResponse: */
|
0xff, /* bClassGetResponse: */
|
||||||
0xff, /* bClassEnvelope: */
|
0xff, /* bClassEnvelope: */
|
||||||
0, 0, /* wLCDLayout: FIXED VALUE */
|
0, 0, /* wLCDLayout: FIXED VALUE */
|
||||||
@@ -108,7 +108,7 @@ static const uint8_t gnukConfigDescriptor[] = {
|
|||||||
5, /* bFunctionLength */
|
5, /* bFunctionLength */
|
||||||
0x24, /* bDescriptorType: CS_INTERFACE */
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
0x01, /* bDescriptorSubtype: Call Management Func Desc */
|
0x01, /* bDescriptorSubtype: Call Management Func Desc */
|
||||||
0x00, /* bmCapabilities: D0+D1 */
|
0x03, /* bmCapabilities: D0+D1 */
|
||||||
0x02, /* bDataInterface: 2 */
|
0x02, /* bDataInterface: 2 */
|
||||||
/*ACM Functional Descriptor*/
|
/*ACM Functional Descriptor*/
|
||||||
4, /* bFunctionLength */
|
4, /* bFunctionLength */
|
||||||
|
|||||||
Reference in New Issue
Block a user