more changes

This commit is contained in:
NIIBE Yutaka
2010-09-04 00:42:36 +09:00
parent 40455cd4a5
commit 3c9e24c7e2
19 changed files with 1584 additions and 1297 deletions

36
doc/NOTES Normal file
View File

@@ -0,0 +1,36 @@
USB communication
=================
* No command chaining, but extended APDU and extended Lc and Le
* dwMaxCCIDMessageLength: 64
OpenPGP card protocol implementation
====================================
* No clear password(s)
PW1
* Support of Resetting code
KEY
=======
KEYPTR
----> [ P ][ Q ][ N ]
<---encrypted----><--- plain ---->
key_addr 4-byte
additional_data_encrypted 16-byte
dek_encrypted_by_keystring_pw1 16-byte
dek_encrypted_by_keystring_rc 16-byte
dek_encrypted_by_keystring_pw3 16-byte
... decrypted to
[ P ][ Q ]
check 4-byte
random 4-byte
magic[] 8-byte

3
doc/NOTES~ Normal file
View File

@@ -0,0 +1,3 @@
PW1
* Support of Resetting code

View File

@@ -83,7 +83,7 @@ CSRC = $(PORTSRC) \
$(CRYPTSRC) \
main.c debug.c usb_lld.c \
hw_config.c usb_desc.c usb_prop.c \
usb-icc.c gpg.c ac.c openpgp-do.c flash.c
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c hardclock.c
# List ASM source files here
ASMSRC = $(PORTASM) \

219
src/ac.c
View File

@@ -21,50 +21,195 @@ ac_check_status (uint8_t ac_flag)
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 (const uint8_t *pw, int pw_len)
{
int r;
const uint8_t *pw_status_bytes = gpg_do_read_simple (GNUK_DO_PW_STATUS);
uint8_t keystring[KEYSTRING_SIZE_PW1];
uint8_t pwsb[SIZE_PW_STATUS_BYTES];
uint8_t keystring_pw1[KEYSTRING_LEN] = {
0x62, 0x10, 0x27, 0x44, 0x34, 0x05, 0x2f, 0x20,
0xfc, 0xb8, 0x3e, 0x1d, 0x0f, 0x49, 0x22, 0x04,
0xfc, 0xb1, 0x18, 0x84
};
if (pw_status_bytes == NULL
|| pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */
return 0;
keystring[0] = pw_len;
sha1 (pw, pw_len, keystring+1);
memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES);
if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNATURE, 1, keystring+1)) < 0)
{
pwsb[PW_STATUS_PW1]--;
gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
return r;
}
else
{
pwsb[PW_STATUS_PW1] = 3;
gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
}
auth_status |= AC_PSO_CDS_AUTHORIZED;
return 1;
}
void
reset_pso_cds (void)
{
auth_status &= ~AC_PSO_CDS_AUTHORIZED;
}
int
verify_pso_cds (uint8_t *pw, int pw_len)
verify_pso_other (const uint8_t *pw, int pw_len)
{
int r;
const uint8_t *pw_status_bytes = gpg_do_read_simple (GNUK_DO_PW_STATUS);
uint8_t keystring[KEYSTRING_SIZE_PW1];
uint8_t pwsb[SIZE_PW_STATUS_BYTES];
if (pw_status_bytes == NULL
|| pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */
return 0;
keystring[0] = pw_len;
sha1 (pw, pw_len, keystring+1);
memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES);
if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPT, 1, keystring+1)) < 0)
{
pwsb[PW_STATUS_PW1]--;
gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
return r;
}
else
{
pwsb[PW_STATUS_PW1] = 3;
gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
}
auth_status |= AC_PSO_OTHER_AUTHORIZED;
return 1;
}
/*
* For keystring of PW3, we use SALT+ITER+MD format
*/
static sha1_context sha1_ctx;
static uint32_t
decode_iterate_count (uint8_t x)
{
return (16UL + ((x) & 15)) << (((x) >> 4) + 6);
}
static void
calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len,
uint8_t md[KEYSTRING_MD_SIZE])
{
sha1_starts (&sha1_ctx);
while (count > pw_len + 8)
{
sha1_update (&sha1_ctx, salt, 8);
sha1_update (&sha1_ctx, pw, pw_len);
count -= pw_len + 8;
}
if (count < 8)
sha1_update (&sha1_ctx, salt, count);
else
{
sha1_update (&sha1_ctx, salt, 8);
count -= 8;
sha1_update (&sha1_ctx, pw, count);
}
sha1_finish (&sha1_ctx, md);
memset (&sha1_ctx, 0, sizeof (sha1_ctx));
}
int
verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
{
const uint8_t *pw3_keystring;
const uint8_t *pw_status_bytes = gpg_do_read_simple (GNUK_DO_PW_STATUS);
int pw_len;
if (pw_status_bytes == NULL
|| pw_status_bytes[PW_STATUS_PW3] == 0) /* locked */
return 0;
pw3_keystring = gpg_do_read_simple (GNUK_DO_KEYSTRING_PW3);
if (pw3_keystring != NULL)
{
int count;
uint8_t md[KEYSTRING_MD_SIZE];
const uint8_t *salt;
uint8_t pwsb[SIZE_PW_STATUS_BYTES];
pw_len = pw3_keystring[0];
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len)
goto failure;
salt = &pw3_keystring[1];
count = decode_iterate_count (pw3_keystring[1+8]);
calc_md (count, salt, pw, pw_len, md);
memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES);
if (memcmp (md, &pw3_keystring[1+8+1], KEYSTRING_MD_SIZE) != 0)
{
failure:
pwsb[PW_STATUS_PW3]--;
gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
return -1;
}
else
{ /* OK, the user is now authenticated */
pwsb[PW_STATUS_PW3] = 3;
gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
}
}
else
/* For empty PW3, pass phrase should be "12345678" */
{
if ((pw_len_known >=0 && pw_len_known != 8)
|| buf_len < 8 || strncmp ((const char *)pw, "12345678", 8) != 0)
/* It is failure, but we don't try to lock for the case of empty PW3 */
return -1;
pw_len = 8;
}
return pw_len;
}
void
gpg_set_pw3 (const uint8_t *newpw, int newpw_len)
{
uint8_t ks[KEYSTRING_SIZE_PW3];
uint32_t random;
ks[0] = newpw_len;
random = get_random ();
memcpy (&ks[1], &random, sizeof (random));
random = get_random ();
memcpy (&ks[5], &random, sizeof (random));
ks[9] = 0x60; /* 65536 iterations */
calc_md (65536, &ks[1], newpw, newpw_len, &ks[10]);
gpg_do_write_simple (GNUK_DO_KEYSTRING_PW3, ks, KEYSTRING_SIZE_PW3);
}
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
int
verify_admin (const uint8_t *pw, int pw_len)
{
int r;
sha1 (pw, pw_len, keystring_pw1);
if ((r = gpg_load_key (GPG_KEY_FOR_SIGNATURE)) < 0)
r = verify_admin_0 (pw, pw_len, pw_len);
if (r <= 0)
return r;
auth_status |= AC_PSO_CDS_AUTHORIZED;
return 0;
}
int
verify_pso_other (uint8_t *pw, int pw_len)
{
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
sha1 (pw, pw_len, keystring_md_pw3);
auth_status |= AC_ADMIN_AUTHORIZED;
return 0;
return 1;
}

View File

@@ -1,4 +1,8 @@
#define DEBUG 1
/* #undef DEBUG */
#ifdef DEBUG
#define ENABLE_VIRTUAL_COM_PORT 1
#endif
#define GNUK_MAX_PACKET_SIZE 64 /* USB */

View File

@@ -35,7 +35,7 @@ put_hex (uint8_t nibble)
else
c = 'a' + nibble - 0x0a;
_write (&c, 1);
_write ((const char *)&c, 1);
}
void
@@ -64,6 +64,20 @@ put_short (uint16_t x)
_write ("\r\n", 2);
}
void
put_binary (const char *s, int len)
{
int i;
for (i = 0; i < len; i++)
{
put_byte_with_no_nl (s[i]);
if ((i & 0x0f) == 0x0f)
_write ("\r\n", 2);
}
_write ("\r\n", 2);
}
void
put_string (const char *s)
{

View File

@@ -34,10 +34,10 @@ static uint8_t *last_p = do_pool;
/*
* TLV (Tag, Length, and Value)
*/
uint8_t *
flash_do_write (uint16_t tag, uint8_t *data, int len)
const uint8_t *
flash_do_write (uint16_t tag, const uint8_t *data, int len)
{
uint8_t *p = last_p;
const uint8_t *p = last_p;
if (last_p - do_pool + len + 2 + 3 > 1024)
return NULL;
@@ -63,10 +63,16 @@ flash_do_write (uint16_t tag, uint8_t *data, int len)
return p + 2;
}
static uint8_t k1[KEY_CONTENT_LEN];
void
flash_do_release (const uint8_t *data)
{
(void)data;/*XXX*/
}
static uint8_t k1[KEY_CONTENT_LEN*2]; /* p, q and N */
#if 0
static uint8_t k2[KEY_CONTENT_LEN];
static uint8_t k3[KEY_CONTENT_LEN];
static uint8_t k2[KEY_CONTENT_LEN*2];
static uint8_t k3[KEY_CONTENT_LEN*2];
#endif
uint8_t *
@@ -89,8 +95,16 @@ flash_key_alloc (enum kind_of_key kk)
}
int
flash_key_write (uint8_t *key_addr, uint8_t *key_data)
flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
const uint8_t *modulus)
{
memcpy (key_addr, key_data, KEY_CONTENT_LEN);
memcpy (key_addr+KEY_CONTENT_LEN, modulus, KEY_CONTENT_LEN);
return 0;
}
void
flash_key_release (const uint8_t *key_addr)
{
(void)key_addr; /*XXX*/
}

View File

@@ -4,12 +4,17 @@ extern void put_byte (uint8_t b);
extern void put_byte_with_no_nl (uint8_t b);
extern void put_short (uint16_t x);
extern void put_string (const char *s);
extern void put_binary (const char *s, int len);
extern void _write (const char *, int);
extern size_t strlen(const char *s);
extern void *memcpy(void *dest, const void *src, size_t n);
extern void *memset(void *s, int c, size_t n);
extern size_t strlen (const char *s);
extern int strncmp(const char *s1, const char *s2, size_t n);
extern void *memcpy (void *dest, const void *src, size_t n);
extern void *memset (void *s, int c, size_t n);
extern void *malloc (size_t size);
extern int memcmp (const void *s1, const void *s2, size_t n);
extern void free (void *ptr);
/*
* Interface between ICC<-->GPG
@@ -21,10 +26,10 @@ extern Thread *gpg_thread;
#define EV_EXEC_FINISHED (eventmask_t)2 /* GPG Execution finished */
/* maximum cmd apdu data is key import 22+4+128+128 (head, e, p, q)*/
/* maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */
#define MAX_CMD_APDU_SIZE (7+282) /* header + data */
#define MAX_RES_APDU_SIZE (256+2) /* Data + status */
/* maximum res apdu data is public key 5+9+256+2 (gpg_do_public_key) */
#define MAX_RES_APDU_SIZE ((5+9+256)+2) /* Data + status */
extern uint8_t cmd_APDU[MAX_CMD_APDU_SIZE];
extern uint8_t res_APDU[MAX_RES_APDU_SIZE];
extern int cmd_APDU_size;
@@ -38,9 +43,13 @@ extern int res_APDU_size;
#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 int verify_pso_cds (const uint8_t *pw, int pw_len);
extern int verify_pso_other (const uint8_t *pw, int pw_len);
extern int verify_admin (const uint8_t *pw, int pw_len);
extern int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known);
extern void reset_pso_cds (void);
extern void write_res_apdu (const uint8_t *p, int len,
@@ -48,9 +57,10 @@ extern void write_res_apdu (const uint8_t *p, int len,
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);
extern void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
extern void gpg_do_public_key (uint8_t kk_byte);
extern uint8_t * flash_do_write (uint16_t tag, uint8_t *data, int len);
enum kind_of_key {
GPG_KEY_FOR_SIGNATURE,
@@ -58,27 +68,100 @@ enum kind_of_key {
GPG_KEY_FOR_AUTHENTICATION,
};
extern void flash_do_release (const uint8_t *);
extern const uint8_t *flash_do_write (uint16_t tag, const uint8_t *data, int len);
extern uint8_t *flash_key_alloc (enum kind_of_key);
extern void flash_key_release (const uint8_t *);
#define KEY_MAGIC_LEN 8
#define KEY_CONTENT_LEN 256
#define KEY_CONTENT_LEN 256 /* p and q */
#define GNUK_MAGIC "Gnuk KEY"
#define KEYSTORE_LEN (KEY_MAGIC_LEN+4+4+KEY_CONTENT_LEN)
#define KEYSTORE_LEN (KEY_MAGIC_LEN+4+4+KEY_CONTENT_LEN*2)
/* encrypted data content */
struct key_data {
uint8_t *key_addr;
/* encrypted data content */
char magic[KEY_MAGIC_LEN];
uint32_t random;
uint8_t data[KEY_CONTENT_LEN]; /* p and q */
uint32_t check;
uint8_t data[KEY_CONTENT_LEN];
uint32_t random;
char magic[KEY_MAGIC_LEN];
};
extern int flash_key_write (uint8_t *key_addr, uint8_t *key_data);
#define ADDITIONAL_DATA_SIZE 16
#define DATA_ENCRYPTION_KEY_SIZE 16
struct prvkey_data {
const uint8_t *key_addr;
uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE];
uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE];
uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE];
uint8_t dek_encrypted_3[DATA_ENCRYPTION_KEY_SIZE];
};
#define KEYSTRING_LEN 20 /* Use 16-byte for AES encryption */
extern uint8_t keystring_pw1[KEYSTRING_LEN];
extern uint32_t get_random (void);
extern int gpg_load_key (enum kind_of_key kk);
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const uint8_t *modulus);
#define KEYSTRING_PASSLEN_SIZE 1
#define KEYSTRING_SALT_SIZE 8 /* optional */
#define KEYSTRING_ITER_SIZE 1 /* optional */
#define KEYSTRING_MD_SIZE 20
#define KEYSTRING_SIZE_PW1 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE)
#define KEYSTRING_SIZE_RC (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE)
#define KEYSTRING_SIZE_PW3 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_SALT_SIZE \
+KEYSTRING_ITER_SIZE+KEYSTRING_MD_SIZE)
extern int gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring);
extern int gpg_do_chks_prvkey (enum kind_of_key kk,
int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks);
extern int gpg_change_keystring (int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks);
extern struct key_data kd;
#ifdef DEBUG
#define DEBUG_INFO(msg) put_string (msg)
#define DEBUG_SHORT(h) put_short (h)
#define DEBUG_BYTE(b) put_byte (b)
#define DEBUG_BINARY(s,len) put_binary ((const char *)s,len)
#else
#define DEBUG_INFO(msg)
#define DEBUG_SHORT(h)
#define DEBUG_BYTE(b)
#define DEBUG_BINARY(s,len)
#endif
extern int rsa_sign (const uint8_t *, uint8_t *, int);
extern const uint8_t *modulus_calc (const uint8_t *, int);
extern void modulus_free (const uint8_t *);
extern int gpg_do_write_privkey (enum kind_of_key kk, const uint8_t *key_data, int key_len);
extern const uint8_t *gpg_do_read_simple (uint16_t);
extern void gpg_do_write_simple (uint16_t, const uint8_t *, int);
extern void gpg_do_increment_digital_signature_counter (void);
#define PW_STATUS_PW1 4
#define PW_STATUS_RC 5
#define PW_STATUS_PW3 6
extern void gpg_set_pw3 (const uint8_t *newpw, int newpw_len);
extern void fatal (void);
extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
#define GNUK_DO_PRVKEY_SIG 0xff01
#define GNUK_DO_PRVKEY_DEC 0xff02
#define GNUK_DO_PRVKEY_AUT 0xff03
#define GNUK_DO_KEYSTRING_PW1 0xff04
#define GNUK_DO_KEYSTRING_RC 0xff05
#define GNUK_DO_KEYSTRING_PW3 0xff06
#define GNUK_DO_PW_STATUS 0xff07
#define SIZE_PW_STATUS_BYTES 7
/* 16-byte random bytes */
extern uint8_t *get_data_encryption_key (void);
extern void dek_free (uint8_t *);
extern uint32_t hardclock (void);

View File

@@ -23,31 +23,6 @@ const char const do_5e[] __attribute__ ((aligned (1))) = {
'g', 'n', 'i', 'i', 'b', 'e'
};
const char const do_c4[] __attribute__ ((aligned (1))) = {
7,
1, 127, 127, 127, 3, 0, 3
};
const char const do_c7[] __attribute__ ((aligned (1))) = {
20,
/* sign */
0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d,
0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc,
0xe5, 0x02, 0xbf, 0xcd,
};
const char const do_ca[] __attribute__ ((aligned (1))) = {
20,
0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d,
0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc,
0xe5, 0x02, 0xbf, 0xcd,
};
const char const do_ce[] __attribute__ ((aligned (1))) = {
4,
0x49, 0x8a, 0x50, 0x7a, /* 0xce */
};
const char const do_5b[] __attribute__ ((aligned (1))) = {
12,
'N', 'I', 'I', 'B', 'E', ' ', 'Y', 'u', 't', 'a', 'k', 'a'
@@ -63,12 +38,6 @@ const char const do_5f35[] __attribute__ ((aligned (1))) = {
'1'
};
/* Digital Signature Counter (3-bytes) */
const char const do_93[] __attribute__ ((aligned (1))) = {
3,
0, 0, 0
};
const char const do_5f50[] __attribute__ ((aligned (1))) = {
20,
'h', 't', 't', 'p', ':', '/', '/', 'w', 'w', 'w',
@@ -78,51 +47,3 @@ const char const do_5f50[] __attribute__ ((aligned (1))) = {
const char const get_data_rb_result[] __attribute__ ((aligned (1))) = {
0x5a, 0x4, 0x01, 0x02, 0x03, 0x04
};
const char const get_data_sigkey_result[] __attribute__ ((aligned (1))) = {
0x7f, 0x49, 0x81, 0x88,
0x81, 0x81, 0x80,
/* 128-byte data */
/* modulus */
0xdb, 0xca, 0x58, 0x74, 0x44, 0x8e, 0x1a, 0x2c,
0xa0, 0x91, 0xac, 0xc4, 0xe2, 0x77, 0x2b, 0x90,
0xcf, 0x3c, 0x7e, 0x81, 0xdc, 0x8d, 0xb0, 0xe2,
0xf1, 0xfe, 0x56, 0x7e, 0x54, 0x57, 0xf0, 0xd8,
0xb1, 0xb1, 0xaa, 0x9d, 0x8f, 0xb0, 0x56, 0x01,
0xaa, 0x6b, 0xa7, 0x2e, 0xce, 0x01, 0x20, 0xd2,
0xf8, 0xf5, 0x85, 0x3a, 0xc2, 0x73, 0xf9, 0x66,
0x30, 0x28, 0x65, 0x5e, 0x3f, 0x91, 0xaf, 0x3f,
0xf6, 0x1c, 0x31, 0x2f, 0xa2, 0x91, 0xbb, 0x41,
0x91, 0x41, 0x08, 0x0a, 0xc5, 0x3e, 0x39, 0xda,
0x2f, 0x6f, 0x58, 0x51, 0xe2, 0xd2, 0xe9, 0x42,
0x8a, 0x7b, 0x72, 0x7b, 0x15, 0xf6, 0xf6, 0x6a,
0x12, 0x6e, 0x0c, 0x15, 0x24, 0x13, 0x16, 0x55,
0x3a, 0xf1, 0xa7, 0x16, 0x3e, 0xe9, 0xc8, 0x3d,
0x2c, 0x3d, 0xae, 0x51, 0x2d, 0x7f, 0xef, 0x92,
0x25, 0x6a, 0xbb, 0x02, 0x03, 0x70, 0x45, 0x3d,
/* public exponent */
0x82, 3, 0x01, 0x00, 0x01
};
const char const get_data_enckey_result[] __attribute__ ((aligned (1))) = {
0x7f, 0x49, 0x81, 0x88,
0x81, 0x81, 0x80,
/* 128-byte data */
0xB2, 0x19, 0x91, 0x42, 0x27, 0xC7, 0x97, 0xFE,
0x92, 0x64, 0x42, 0xCA, 0xE3, 0x66, 0x4D, 0xD0,
0x31, 0xE4, 0x10, 0x31, 0x0F, 0xC7, 0x07, 0x4A,
0xAA, 0x6D, 0x31, 0xA2, 0x88, 0x68, 0xAF, 0x45,
0x8E, 0x42, 0x12, 0xFF, 0xB6, 0xEF, 0x6E, 0x54,
0x7E, 0x51, 0x8E, 0xBC, 0xE8, 0x18, 0x79, 0xA7,
0xBC, 0xA8, 0x14, 0x8B, 0xE7, 0x91, 0x57, 0x38,
0xCE, 0x4F, 0x6E, 0x16, 0x48, 0xCB, 0xD6, 0x0B,
0x3A, 0x53, 0x70, 0xF3, 0xFC, 0xFA, 0xC3, 0x58,
0x3D, 0xE7, 0x2A, 0x5E, 0xDD, 0xE1, 0x38, 0x82,
0x57, 0x87, 0x3A, 0xDC, 0x34, 0xDE, 0xCD, 0x5D,
0x33, 0x1C, 0xAB, 0xB0, 0x1B, 0xEE, 0x82, 0x43,
0x7B, 0xAC, 0xF8, 0xF0, 0xB2, 0x62, 0xB2, 0x6D,
0x09, 0xED, 0x2E, 0xD1, 0xBA, 0xB8, 0xC6, 0x96,
0xFA, 0x3E, 0xB4, 0xE3, 0xFE, 0x68, 0xF9, 0x51,
0x9A, 0x8C, 0x8B, 0x20, 0x93, 0xD0, 0x2E, 0x0F,
0x82, 3, 0x01, 0x00, 0x01
};

View File

@@ -55,77 +55,6 @@ do_5e:
.byte 105
.byte 98
.byte 101
.global do_c4
.type do_c4, %object
.size do_c4, 8
do_c4:
.byte 7
.byte 1
.byte 127
.byte 127
.byte 127
.byte 3
.byte 0
.byte 3
.global do_c7
.type do_c7, %object
.size do_c7, 21
do_c7:
.byte 20
.byte 91
.byte -123
.byte 103
.byte 60
.byte 8
.byte 79
.byte -128
.byte 13
.byte 84
.byte -84
.byte -107
.byte 28
.byte 53
.byte 21
.byte -105
.byte -52
.byte -27
.byte 2
.byte -65
.byte -51
.global do_ca
.type do_ca, %object
.size do_ca, 21
do_ca:
.byte 20
.byte 91
.byte -123
.byte 103
.byte 60
.byte 8
.byte 79
.byte -128
.byte 13
.byte 84
.byte -84
.byte -107
.byte 28
.byte 53
.byte 21
.byte -105
.byte -52
.byte -27
.byte 2
.byte -65
.byte -51
.global do_ce
.type do_ce, %object
.size do_ce, 5
do_ce:
.byte 4
.byte 73
.byte -118
.byte 80
.byte 122
.global do_5b
.type do_5b, %object
.size do_5b, 13
@@ -156,14 +85,6 @@ do_5f2d:
do_5f35:
.byte 1
.byte 49
.global do_93
.type do_93, %object
.size do_93, 4
do_93:
.byte 3
.byte 0
.byte 0
.byte 0
.global do_5f50
.type do_5f50, %object
.size do_5f50, 21
@@ -199,307 +120,19 @@ get_data_rb_result:
.byte 2
.byte 3
.byte 4
.global get_data_sigkey_result
.type get_data_sigkey_result, %object
.size get_data_sigkey_result, 140
get_data_sigkey_result:
.byte 127
.byte 73
.byte -127
.byte -120
.byte -127
.byte -127
.byte -128
.byte -37
.byte -54
.byte 88
.byte 116
.byte 68
.byte -114
.byte 26
.byte 44
.byte -96
.byte -111
.byte -84
.byte -60
.byte -30
.byte 119
.byte 43
.byte -112
.byte -49
.byte 60
.byte 126
.byte -127
.byte -36
.byte -115
.byte -80
.byte -30
.byte -15
.byte -2
.byte 86
.byte 126
.byte 84
.byte 87
.byte -16
.byte -40
.byte -79
.byte -79
.byte -86
.byte -99
.byte -113
.byte -80
.byte 86
.byte 1
.byte -86
.byte 107
.byte -89
.byte 46
.byte -50
.byte 1
.byte 32
.byte -46
.byte -8
.byte -11
.byte -123
.byte 58
.byte -62
.byte 115
.byte -7
.byte 102
.byte 48
.byte 40
.byte 101
.byte 94
.byte 63
.byte -111
.byte -81
.byte 63
.byte -10
.byte 28
.byte 49
.byte 47
.byte -94
.byte -111
.byte -69
.byte 65
.byte -111
.byte 65
.byte 8
.byte 10
.byte -59
.byte 62
.byte 57
.byte -38
.byte 47
.byte 111
.byte 88
.byte 81
.byte -30
.byte -46
.byte -23
.byte 66
.byte -118
.byte 123
.byte 114
.byte 123
.byte 21
.byte -10
.byte -10
.byte 106
.byte 18
.byte 110
.byte 12
.byte 21
.byte 36
.byte 19
.byte 22
.byte 85
.byte 58
.byte -15
.byte -89
.byte 22
.byte 62
.byte -23
.byte -56
.byte 61
.byte 44
.byte 61
.byte -82
.byte 81
.byte 45
.byte 127
.byte -17
.byte -110
.byte 37
.byte 106
.byte -69
.byte 2
.byte 3
.byte 112
.byte 69
.byte 61
.byte -126
.byte 3
.byte 1
.byte 0
.byte 1
.global get_data_enckey_result
.type get_data_enckey_result, %object
.size get_data_enckey_result, 140
get_data_enckey_result:
.byte 127
.byte 73
.byte -127
.byte -120
.byte -127
.byte -127
.byte -128
.byte -78
.byte 25
.byte -111
.byte 66
.byte 39
.byte -57
.byte -105
.byte -2
.byte -110
.byte 100
.byte 66
.byte -54
.byte -29
.byte 102
.byte 77
.byte -48
.byte 49
.byte -28
.byte 16
.byte 49
.byte 15
.byte -57
.byte 7
.byte 74
.byte -86
.byte 109
.byte 49
.byte -94
.byte -120
.byte 104
.byte -81
.byte 69
.byte -114
.byte 66
.byte 18
.byte -1
.byte -74
.byte -17
.byte 110
.byte 84
.byte 126
.byte 81
.byte -114
.byte -68
.byte -24
.byte 24
.byte 121
.byte -89
.byte -68
.byte -88
.byte 20
.byte -117
.byte -25
.byte -111
.byte 87
.byte 56
.byte -50
.byte 79
.byte 110
.byte 22
.byte 72
.byte -53
.byte -42
.byte 11
.byte 58
.byte 83
.byte 112
.byte -13
.byte -4
.byte -6
.byte -61
.byte 88
.byte 61
.byte -25
.byte 42
.byte 94
.byte -35
.byte -31
.byte 56
.byte -126
.byte 87
.byte -121
.byte 58
.byte -36
.byte 52
.byte -34
.byte -51
.byte 93
.byte 51
.byte 28
.byte -85
.byte -80
.byte 27
.byte -18
.byte -126
.byte 67
.byte 123
.byte -84
.byte -8
.byte -16
.byte -78
.byte 98
.byte -78
.byte 109
.byte 9
.byte -19
.byte 46
.byte -47
.byte -70
.byte -72
.byte -58
.byte -106
.byte -6
.byte 62
.byte -76
.byte -29
.byte -2
.byte 104
.byte -7
.byte 81
.byte -102
.byte -116
.byte -117
.byte 32
.byte -109
.byte -48
.byte 46
.byte 15
.byte -126
.byte 3
.byte 1
.byte 0
.byte 1
.text
.Letext0:
.file 1 "gpg-data.c"
.section .debug_info
.4byte 0x264
.4byte 0x183
.2byte 0x2
.4byte .Ldebug_abbrev0
.byte 0x4
.uleb128 0x1
.4byte .LASF24
.4byte .LASF17
.byte 0x1
.4byte .LASF25
.4byte .LASF26
.4byte .LASF18
.4byte .LASF19
.4byte .Ltext0
.4byte .Letext0
.4byte .Ldebug_line0
@@ -546,17 +179,17 @@ get_data_enckey_result:
.uleb128 0x4
.byte 0x4
.byte 0x7
.uleb128 0x5
.4byte 0x7e
.4byte 0x7e
.uleb128 0x6
.4byte 0x6b
.byte 0x13
.byte 0x0
.uleb128 0x3
.byte 0x1
.byte 0x8
.4byte .LASF9
.uleb128 0x5
.4byte 0x6e
.4byte 0x85
.uleb128 0x6
.4byte 0x6b
.byte 0x13
.byte 0x0
.uleb128 0x7
.4byte .LASF10
.byte 0x1
@@ -567,9 +200,9 @@ get_data_enckey_result:
.byte 0x3
.4byte select_file_TOP_result
.uleb128 0x8
.4byte 0x6e
.4byte 0x75
.uleb128 0x5
.4byte 0x7e
.4byte 0x6e
.4byte 0xac
.uleb128 0x6
.4byte 0x6b
@@ -587,11 +220,11 @@ get_data_enckey_result:
.uleb128 0x8
.4byte 0x9c
.uleb128 0x5
.4byte 0x7e
.4byte 0x6e
.4byte 0xd3
.uleb128 0x6
.4byte 0x6b
.byte 0x7
.byte 0xc
.byte 0x0
.uleb128 0x7
.4byte .LASF12
@@ -601,15 +234,15 @@ get_data_enckey_result:
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_c4
.4byte do_5b
.uleb128 0x8
.4byte 0xc3
.uleb128 0x5
.4byte 0x7e
.4byte 0x6e
.4byte 0xfa
.uleb128 0x6
.4byte 0x6b
.byte 0x14
.byte 0x2
.byte 0x0
.uleb128 0x7
.4byte .LASF13
@@ -619,168 +252,63 @@ get_data_enckey_result:
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_c7
.4byte do_5f2d
.uleb128 0x8
.4byte 0xea
.uleb128 0x5
.4byte 0x6e
.4byte 0x121
.uleb128 0x6
.4byte 0x6b
.byte 0x1
.byte 0x0
.uleb128 0x7
.4byte .LASF14
.byte 0x1
.byte 0x27
.4byte 0x123
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_ca
.uleb128 0x8
.4byte 0xea
.uleb128 0x5
.4byte 0x7e
.4byte 0x138
.uleb128 0x6
.4byte 0x6b
.byte 0x4
.byte 0x0
.uleb128 0x7
.4byte .LASF15
.byte 0x1
.byte 0x2e
.4byte 0x14a
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_ce
.uleb128 0x8
.4byte 0x128
.uleb128 0x5
.4byte 0x7e
.4byte 0x15f
.uleb128 0x6
.4byte 0x6b
.byte 0xc
.byte 0x0
.uleb128 0x7
.4byte .LASF16
.byte 0x1
.byte 0x33
.4byte 0x171
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_5b
.uleb128 0x8
.4byte 0x14f
.uleb128 0x5
.4byte 0x7e
.4byte 0x186
.uleb128 0x6
.4byte 0x6b
.byte 0x2
.byte 0x0
.uleb128 0x7
.4byte .LASF17
.byte 0x1
.byte 0x38
.4byte 0x198
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_5f2d
.uleb128 0x8
.4byte 0x176
.uleb128 0x5
.4byte 0x7e
.4byte 0x1ad
.uleb128 0x6
.4byte 0x6b
.byte 0x1
.byte 0x0
.uleb128 0x7
.4byte .LASF18
.byte 0x1
.byte 0x3d
.4byte 0x1bf
.byte 0x24
.4byte 0x133
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_5f35
.uleb128 0x8
.4byte 0x19d
.4byte 0x111
.uleb128 0x5
.4byte 0x7e
.4byte 0x1d4
.4byte 0x6e
.4byte 0x148
.uleb128 0x6
.4byte 0x6b
.byte 0x3
.byte 0x14
.byte 0x0
.uleb128 0x7
.4byte .LASF19
.4byte .LASF15
.byte 0x1
.byte 0x43
.4byte 0x1e6
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_93
.uleb128 0x8
.4byte 0x1c4
.uleb128 0x7
.4byte .LASF20
.byte 0x1
.byte 0x48
.4byte 0x1fd
.byte 0x29
.4byte 0x15a
.byte 0x1
.byte 0x5
.byte 0x3
.4byte do_5f50
.uleb128 0x8
.4byte 0xea
.4byte 0x138
.uleb128 0x5
.4byte 0x7e
.4byte 0x212
.4byte 0x6e
.4byte 0x16f
.uleb128 0x6
.4byte 0x6b
.byte 0x5
.byte 0x0
.uleb128 0x7
.4byte .LASF21
.4byte .LASF16
.byte 0x1
.byte 0x4e
.4byte 0x224
.byte 0x2f
.4byte 0x181
.byte 0x1
.byte 0x5
.byte 0x3
.4byte get_data_rb_result
.uleb128 0x8
.4byte 0x202
.uleb128 0x5
.4byte 0x7e
.4byte 0x239
.uleb128 0x6
.4byte 0x6b
.byte 0x8b
.byte 0x0
.uleb128 0x7
.4byte .LASF22
.byte 0x1
.byte 0x52
.4byte 0x24b
.byte 0x1
.byte 0x5
.byte 0x3
.4byte get_data_sigkey_result
.uleb128 0x8
.4byte 0x229
.uleb128 0x7
.4byte .LASF23
.byte 0x1
.byte 0x6b
.4byte 0x262
.byte 0x1
.byte 0x5
.byte 0x3
.4byte get_data_enckey_result
.uleb128 0x8
.4byte 0x229
.4byte 0x15f
.byte 0x0
.section .debug_abbrev
.uleb128 0x1
@@ -877,92 +405,64 @@ get_data_enckey_result:
.byte 0x0
.byte 0x0
.section .debug_pubnames,"",%progbits
.4byte 0xe0
.4byte 0x78
.2byte 0x2
.4byte .Ldebug_info0
.4byte 0x268
.4byte 0x187
.4byte 0x85
.ascii "select_file_TOP_result\000"
.4byte 0xac
.ascii "do_5e\000"
.4byte 0xd3
.ascii "do_c4\000"
.4byte 0xfa
.ascii "do_c7\000"
.4byte 0x111
.ascii "do_ca\000"
.4byte 0x138
.ascii "do_ce\000"
.4byte 0x15f
.ascii "do_5b\000"
.4byte 0x186
.4byte 0xfa
.ascii "do_5f2d\000"
.4byte 0x1ad
.4byte 0x121
.ascii "do_5f35\000"
.4byte 0x1d4
.ascii "do_93\000"
.4byte 0x1eb
.4byte 0x148
.ascii "do_5f50\000"
.4byte 0x212
.4byte 0x16f
.ascii "get_data_rb_result\000"
.4byte 0x239
.ascii "get_data_sigkey_result\000"
.4byte 0x250
.ascii "get_data_enckey_result\000"
.4byte 0x0
.section .debug_str,"MS",%progbits,1
.LASF7:
.ascii "long long int\000"
.LASF4:
.ascii "short unsigned int\000"
.LASF0:
.ascii "unsigned int\000"
.LASF2:
.ascii "unsigned char\000"
.LASF17:
.LASF13:
.ascii "do_5f2d\000"
.LASF23:
.ascii "get_data_enckey_result\000"
.LASF6:
.ascii "long unsigned int\000"
.LASF8:
.ascii "long long unsigned int\000"
.LASF19:
.ascii "do_93\000"
.LASF14:
.ascii "do_ca\000"
.LASF24:
.LASF10:
.ascii "select_file_TOP_result\000"
.LASF17:
.ascii "GNU C 4.4.2\000"
.LASF15:
.ascii "do_ce\000"
.LASF18:
.LASF2:
.ascii "unsigned char\000"
.LASF14:
.ascii "do_5f35\000"
.LASF9:
.ascii "char\000"
.LASF21:
.LASF16:
.ascii "get_data_rb_result\000"
.LASF5:
.ascii "long int\000"
.LASF20:
.LASF15:
.ascii "do_5f50\000"
.LASF12:
.ascii "do_c4\000"
.LASF10:
.ascii "select_file_TOP_result\000"
.LASF13:
.ascii "do_c7\000"
.LASF18:
.ascii "gpg-data.c\000"
.LASF4:
.ascii "short unsigned int\000"
.LASF1:
.ascii "signed char\000"
.LASF22:
.ascii "get_data_sigkey_result\000"
.LASF26:
.LASF19:
.ascii "/var/tmp/stm32/gnuk/src\000"
.LASF3:
.ascii "short int\000"
.LASF16:
.LASF12:
.ascii "do_5b\000"
.LASF11:
.ascii "do_5e\000"
.LASF25:
.ascii "gpg-data.c\000"
.ident "GCC: (GNU) 4.4.2"

296
src/gpg.c
View File

@@ -1,296 +0,0 @@
/*
* gpg.c -- OpenPGP card protocol support
*
* 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 "hal.h"
#include "gnuk.h"
#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */
extern unsigned char *rsa_sign (unsigned char *);
#define INS_PUT_DATA 0xDA
#define INS_PUT_DATA_ODD 0xDB /* For key import */
#define INS_VERIFY 0x20
#define INS_GET_DATA 0xCA
#define INS_GET_RESPONSE 0xC0
#define INS_SELECT_FILE 0xA4
#define INS_READ_BINARY 0xB0
#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47
#define INS_PSO 0x2A
extern const char const select_file_TOP_result[20];
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_enckey_result[7+128];
void
write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2)
{
res_APDU_size = 2 + len;
if (len)
memcpy (res_APDU, p, len);
res_APDU[len] = sw1;
res_APDU[len+1] = sw2;
}
#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)
{
uint16_t tag;
uint8_t *data;
int len;
if (cmd_APDU[1] == INS_VERIFY)
{
uint8_t p2 = cmd_APDU[3];
int r;
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");
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)
{
put_string (" - Generate Asymmetric Key Pair\r\n");
if (cmd_APDU[2] == 0x81)
{
/*
* tag: 0x7f49 public key data
* tag: 0x0081 RSA modulus
* tag: 0x0082 RSA exponent
*
* TAG
* [0x7f 0x49][LEN][DATA]
* _______/ \_________________
* / \
* [0x81][128][DATA][0x82][3][DATA]
* __/ \__ 0x01, 0x00, 0x01
* / \
* 0x81 0x80
*/
if (cmd_APDU[6] == 0x00 && cmd_APDU[5] == 0xb6)
{ /* Key for Sign */
write_res_apdu (get_data_sigkey_result,
sizeof (get_data_sigkey_result), 0x90, 0x00);
}
else if (cmd_APDU[6] == 0x00 && cmd_APDU[5] == 0xb8)
{ /* Key for Encryption */
write_res_apdu (get_data_enckey_result,
sizeof (get_data_enckey_result), 0x90, 0x00);
}
/* cmd_APDU[5] == 0xa4 */
else
{
write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */
}
}
else
{
write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */
}
}
else if (cmd_APDU[1] == INS_READ_BINARY)
{
put_string (" - Read binary\r\n");
if (file_selection == FILE_EF_SERIAL)
{
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
write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */
}
else if (cmd_APDU[1] == INS_SELECT_FILE)
{
if (cmd_APDU[2] == 4) /* Selection by DF name */
{
put_string (" - select DF by name\r\n");
/*
* P2 == 0, LC=6, name = D2 76 00 01 24 01
*/
file_selection = FILE_DF_OPENPGP;
/* XXX: Should return contents??? */
write_res_apdu (NULL, 0, 0x90, 0x00);
}
else if (cmd_APDU[4] == 2
&& cmd_APDU[5] == 0x2f
&& cmd_APDU[6] == 0x02)
{
put_string (" - select 0x2f02 EF\r\n");
/*
* MF.EF-GDO -- Serial number of the card and name of the owner
*/
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
{
put_string (" - select ?? \r\n");
write_res_apdu (NULL, 0, 0x6a, 0x82); /* File missing */
file_selection = FILE_NONE;
}
}
else if (cmd_APDU[1] == INS_GET_DATA)
{
tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
put_string (" - Get Data\r\n");
if (file_selection != FILE_DF_OPENPGP)
write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */
gpg_do_get_data (tag);
}
else if (cmd_APDU[1] == INS_PSO)
{
put_string (" - PSO\r\n");
if (cmd_APDU[2] == 0x9E && cmd_APDU[3] == 0x9A)
{
if (cmd_APDU_size != 8 + 35 && cmd_APDU_size != 8 + 35 + 1)
/* Extended Lc: 3-byte */
{
put_string (" wrong length: ");
put_short (cmd_APDU_size);
}
else
{
unsigned char * r = rsa_sign (&cmd_APDU[7]);
write_res_apdu (r, RSA_SIGNATURE_LENGTH, 0x90, 0x00);
}
put_string ("done.\r\n");
}
else
{
put_string (" - ??");
put_byte (cmd_APDU[2]);
put_string (" - ??");
put_byte (cmd_APDU[3]);
write_res_apdu (NULL, 0, 0x90, 0x00);
}
}
else
{
put_string (" - ??");
put_byte (cmd_APDU[1]);
write_res_apdu (NULL, 0, 0x6D, 0x00); /* INS not supported. */
}
}
Thread *gpg_thread;
msg_t
GPGthread (void *arg)
{
(void)arg;
gpg_thread = chThdSelf ();
chEvtClear (ALL_EVENTS);
while (1)
{
eventmask_t m;
m = chEvtWaitOne (ALL_EVENTS);
_write ("GPG!\r\n", 6);
process_command_apdu ();
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
}
return 0;
}

8
src/hardclock.c Normal file
View File

@@ -0,0 +1,8 @@
#include "ch.h"
#include "hal.h"
uint32_t
hardclock (void)
{
return SysTick->VAL;
}

View File

@@ -53,6 +53,7 @@ Thread1 (void *arg)
return 0;
}
#ifdef DEBUG
static
struct stdout {
Mutex m;
@@ -94,9 +95,8 @@ extern uint8_t buffer_in[VIRTUAL_COM_PORT_DATA_SIZE];
extern uint8_t buffer_out[VIRTUAL_COM_PORT_DATA_SIZE];
extern void USB_Init (void);
static WORKING_AREA(waThread2, 128);
static msg_t Thread2 (void *arg)
static WORKING_AREA(waSTDOUTthread, 128);
static msg_t STDOUTthread (void *arg)
{
(void)arg;
@@ -160,6 +160,19 @@ static msg_t Thread2 (void *arg)
goto again;
return 0;
}
#else
static void
stdout_init (void)
{
}
void
_write (const char *s, int size)
{
(void)s;
(void)size;
}
#endif
static WORKING_AREA(waUSBthread, 128*2);
extern msg_t USBthread (void *arg);
@@ -167,6 +180,66 @@ extern msg_t USBthread (void *arg);
static WORKING_AREA(waGPGthread, 128*16);
extern msg_t GPGthread (void *arg);
/*
* XXX: I have tried havege_rand, but it requires too much memory...
*/
/*
* Multiply-with-carry method by George Marsaglia
*/
static uint32_t m_w;
static uint32_t m_z;
static void
random_init (void)
{
static uint8_t s = 0;
again:
switch ((s & 1))
{
case 0:
m_w = (m_w << 8) ^ hardclock ();
break;
case 1:
m_z = (m_z << 8) ^ hardclock ();
break;
}
s++;
if (m_w == 0 || m_z == 0)
goto again;
}
uint32_t
get_random (void)
{
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
return (m_z << 16) + m_w;
}
uint8_t dek[16];
uint8_t *get_data_encryption_key (void)
{
uint32_t r;
r = get_random ();
memcpy (dek, &r, 4);
r = get_random ();
memcpy (dek+4, &r, 4);
r = get_random ();
memcpy (dek+8, &r, 4);
r = get_random ();
memcpy (dek+12, &r, 4);
return dek;
}
void dek_free (uint8_t *dek)
{
(void)dek;
}
/*
* Entry point, note, the main() function is already a thread in the system
* on entry.
@@ -190,10 +263,12 @@ main (int argc, char **argv)
*/
chThdCreateStatic (waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
#ifdef DEBUG
/*
* Creates 'stdout' thread.
*/
chThdCreateStatic (waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);
chThdCreateStatic (waSTDOUTthread2, sizeof(waSTDOUTthread2), NORMALPRIO, STDOUTthread2, NULL);
#endif
chThdCreateStatic (waUSBthread, sizeof(waUSBthread), NORMALPRIO, USBthread, NULL);
chThdCreateStatic (waGPGthread, sizeof(waGPGthread), NORMALPRIO, GPGthread, NULL);
@@ -207,9 +282,15 @@ main (int argc, char **argv)
chThdSleepMilliseconds (100);
if (bDeviceState != CONFIGURED)
random_init ();
if (bDeviceState == CONFIGURED && (count % 300) == 0)
{
_write ("0123456789"+((count / 300)%10), 1);
uint32_t r;
r = get_random ();
DEBUG_SHORT (r);
_write ("\r\nThis is ChibiOS 2.0.2 on Olimex STM32-H103.\r\n"
"Testing USB driver.\n\n"
"Hello world\r\n\r\n", 47+21+15);
@@ -219,3 +300,10 @@ main (int argc, char **argv)
return 0;
}
void
fatal (void)
{
_write ("fatal\r\n", 7);
for (;;);
}

View File

@@ -25,9 +25,11 @@
#include "ch.h"
#include "gnuk.h"
#include "openpgp.h"
#include "polarssl/config.h"
#include "polarssl/aes.h"
#include "polarssl/sha1.h"
/*
* Compile time vars:
@@ -84,39 +86,19 @@ static const uint8_t const algorithm_attr[] __attribute__ ((aligned (1))) = {
0x00 /* 0: p&q , 3: CRT with N (not yet supported) */
};
#define SIZE_PW_STATUS_BYTES 7
#if 0
const uint8_t const pw_status_bytes_template[] =
{
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
/* 3-byte binary (big endian) */
#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,
@@ -124,8 +106,6 @@ enum do_type {
DO_PROC_READ,
DO_PROC_WRITE,
DO_PROC_READWRITE,
DO_HASH,
DO_KEYPTR
};
struct do_table_entry {
@@ -142,13 +122,6 @@ 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 GNUK_DO_HASH_RC 0xff05
#define GNUK_DO_PW_STATUS 0xff06
#define GPG_DO_AID 0x004f
#define GPG_DO_NAME 0x005b
#define GPG_DO_LOGIN_DATA 0x005e
@@ -194,18 +167,19 @@ copy_tag (uint16_t tag)
}
}
static void
static int
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);
return 0;
}
#define SIZE_FP 20
#define SIZE_KGTIME 4
static void
static int
do_fp_all (uint16_t tag)
{
struct do_table_entry *do_p;
@@ -240,9 +214,11 @@ do_fp_all (uint16_t tag)
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
return 0;
}
static void
static int
do_cafp_all (uint16_t tag)
{
struct do_table_entry *do_p;
@@ -277,9 +253,11 @@ do_cafp_all (uint16_t tag)
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
return 0;
}
static void
static int
do_kgtime_all (uint16_t tag)
{
struct do_table_entry *do_p;
@@ -314,33 +292,38 @@ do_kgtime_all (uint16_t tag)
else
memset (res_p, 0, SIZE_KGTIME);
res_p += SIZE_KGTIME;
return 0;
}
static void
rw_pw_status (uint16_t tag, uint8_t *data, int len, int is_write)
static int
rw_pw_status (uint16_t tag, const uint8_t *data, int len, int is_write)
{
struct do_table_entry *do_p;
if (is_write)
{
const uint8_t *do_data;
uint8_t pwsb[SIZE_PW_STATUS_BYTES];
(void)len;
do_p = get_do_entry (GNUK_DO_PW_STATUS);
if (do_p)
do_data = (const uint8_t *)do_p->obj;
if (do_data)
{
do_data = (const uint8_t *)do_p->obj;
if (do_data)
memcpy (data, &do_data[2], SIZE_PW_STATUS_BYTES - 1);
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 */
memcpy (pwsb, &do_data[1], SIZE_PW_STATUS_BYTES);
flash_do_release (do_p->obj);
}
else
/* No record */
write_res_apdu (NULL, 0, 0x6a, 0x88);
memcpy (pwsb, pw_status_bytes_template, SIZE_PW_STATUS_BYTES);
pwsb[0] = data[0];
do_p->obj = flash_do_write (tag, pwsb, SIZE_PW_STATUS_BYTES);
if (do_p->obj)
GPG_SUCCESS ();
else
GPG_MEMORY_FAILURE();
return 0;
}
else
{
@@ -360,184 +343,308 @@ rw_pw_status (uint16_t tag, uint8_t *data, int len, int is_write)
res_p += SIZE_PW_STATUS_BYTES;
}
else
/* No record */
write_res_apdu (NULL, 0, 0x6a, 0x88);
return -1;
}
}
static void
proc_resetting_code (uint16_t tag, uint8_t *data, int len)
{
/* Not implementad yet */
/*
* calculate hash, write it to GNUK_DO_HASH_RC.
*/
/* Then, we need to reset RC counter in GNUK_DO_PW_STATUS */
return 0;
}
static uint8_t iv[16];
static aes_context aes;
static uint8_t iv[16];
static int iv_offset;
static void
encrypt (uint8_t *key_str, uint8_t *data)
proc_resetting_code (const uint8_t *data, int len)
{
const uint8_t *old_ks = keystring_md_pw3;
uint8_t new_ks0[KEYSTRING_MD_SIZE+1];
uint8_t *new_ks = &new_ks0[1];
const uint8_t *newpw;
int newpw_len;
int r;
uint8_t pwsb[SIZE_PW_STATUS_BYTES];
struct do_table_entry *do_p;
const uint8_t *do_data;
newpw_len = len;
newpw = data;
sha1 (newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
r = gpg_change_keystring (3, old_ks, 2, new_ks);
if (r < -2)
{
GPG_MEMORY_FAILURE ();
return;
}
else if (r < 0)
{
GPG_SECURITY_FAILURE ();
return;
}
else if (r == 0)
gpg_do_write_simple (GNUK_DO_KEYSTRING_RC, new_ks0, KEYSTRING_SIZE_RC);
else
GPG_SUCCESS ();
/* Reset RC counter in GNUK_DO_PW_STATUS */
do_p = get_do_entry (GNUK_DO_PW_STATUS);
do_data = (const uint8_t *)do_p->obj;
if (do_data)
{
memcpy (pwsb, &do_data[1], SIZE_PW_STATUS_BYTES);
pwsb[PW_STATUS_RC] = 3;
flash_do_release (do_data);
}
else
{
memcpy (pwsb, pw_status_bytes_template, SIZE_PW_STATUS_BYTES);
pwsb[5] = 3;
}
gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
}
static void
encrypt (const uint8_t *key_str, uint8_t *data, int len)
{
aes_setkey_enc (&aes, key_str, 128);
memset (iv, 0, 16);
iv_offset = 0;
aes_crypt_cfb128 (&aes, AES_ENCRYPT, KEYSTORE_LEN, &iv_offset, iv, data, data);
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv, data, data);
{
int i, len = KEYSTORE_LEN;
put_string ("ENC\r\n");
for (i = 0; i < len; i++)
{
put_byte_with_no_nl (data[i]);
if ((i & 0x0f) == 0x0f)
_write ("\r\n", 2);
}
_write ("\r\n", 2);
}
DEBUG_INFO ("ENC\r\n");
DEBUG_BINARY (data, KEYSTORE_LEN);
}
struct key_data kd;
static void
decrypt (uint8_t *key_str, uint8_t *data)
decrypt (const uint8_t *key_str, uint8_t *data, int len)
{
aes_setkey_enc (&aes, key_str, 128);
memset (iv, 0, 16);
iv_offset = 0;
aes_crypt_cfb128 (&aes, AES_DECRYPT, KEYSTORE_LEN, &iv_offset, iv, data, data);
{
int i, len = KEYSTORE_LEN;
put_string ("DEC\r\n");
for (i = 0; i < len; i++)
{
put_byte_with_no_nl (data[i]);
if ((i & 0x0f) == 0x0f)
_write ("\r\n", 2);
}
_write ("\r\n", 2);
}
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv, data, data);
DEBUG_INFO ("DEC\r\n");
DEBUG_BINARY (data, KEYSTORE_LEN);
}
int
gpg_load_key (enum kind_of_key kk)
static uint16_t
get_tag_for_kk (enum kind_of_key kk)
{
struct do_table_entry *do_p;
switch (kk)
{
case GPG_KEY_FOR_SIGNATURE:
do_p = get_do_entry (GNUK_DO_KEYPTR_SIG);
break;
return GNUK_DO_PRVKEY_SIG;
case GPG_KEY_FOR_DECRYPT:
do_p = get_do_entry (GNUK_DO_KEYPTR_DEC);
break;
return GNUK_DO_PRVKEY_DEC;
case GPG_KEY_FOR_AUTHENTICATION:
do_p = get_do_entry (GNUK_DO_KEYPTR_AUT);
break;
return GNUK_DO_PRVKEY_AUT;
}
if (do_p == NULL)
return -1;
return GNUK_DO_PRVKEY_SIG;
}
kd.key_addr = *(uint8_t **)&((uint8_t *)do_p->obj)[1];
memcpy (((uint8_t *)&kd)+4, ((uint8_t *)do_p->obj)+5, KEY_MAGIC_LEN+4+4);
memcpy (kd.data, kd.key_addr, KEY_CONTENT_LEN);
/*
* Return 1 on success,
* 0 if none,
* -1 on error,
*/
int
gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
{
uint16_t tag = get_tag_for_kk (kk);
struct do_table_entry *do_p = get_do_entry (tag);
uint8_t *key_addr;
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
decrypt (keystring_pw1, ((uint8_t *)&kd) + 4);
if (do_p->obj == NULL)
return 0;
key_addr = *(uint8_t **)&((uint8_t *)do_p->obj)[1];
memcpy (kd.data, key_addr, KEY_CONTENT_LEN);
memcpy (((uint8_t *)&kd.check), ((uint8_t *)do_p->obj)+5, ADDITIONAL_DATA_SIZE);
memcpy (dek, ((uint8_t *)do_p->obj)+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE);
decrypt (dek, (uint8_t *)&kd, sizeof (kd));
if (memcmp (kd.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
return -1;
/* XXX: more sanity check */
return 0;
}
uint32_t
get_random (void)
{
return 0x80808080; /* XXX: for now */
return 1;
}
static uint32_t
calc_check (uint8_t *data, int len)
calc_check32 (const uint8_t *p, int len)
{
uint32_t check = 0;
uint32_t *data = (uint32_t *)p;
int i;
for (i = 0; i < len; i++)
for (i = 0; i < len/4; i++)
check += data[i];
return check;
}
static int
gpg_write_do_keyptr (enum kind_of_key kk, uint8_t *key_data, int key_len)
int
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
const uint8_t *keystring)
{
uint8_t *p;
int len;
const uint8_t *p;
int r;
uint32_t key_addr;
struct do_table_entry *do_p;
const uint8_t *modulus;
struct key_data *kd;
struct prvkey_data *pd;
uint8_t *key_addr;
uint8_t *dek;
uint16_t tag = get_tag_for_kk (kk);
const uint8_t *ks_pw1 = gpg_do_read_simple (GNUK_DO_KEYSTRING_PW1);
const uint8_t *ks_rc = gpg_do_read_simple (GNUK_DO_KEYSTRING_RC);
#if 0
assert (key_len == KEY_CONTENT_LEN+4);
/* key_data should starts with 00 01 00 01 (E) */
assert (key_len == KEY_CONTENT_LEN);
#endif
put_short (key_len);
DEBUG_SHORT (key_len);
key_data += 4;
kd.key_addr = flash_key_alloc (kk);
if (kd.key_addr == NULL)
kd = (struct key_data *)malloc (sizeof (struct key_data));
if (kd == NULL)
return -1;
memcpy (kd.magic, GNUK_MAGIC, KEY_MAGIC_LEN);
kd.check = calc_check (key_data, KEY_CONTENT_LEN);
kd.random = get_random ();
memcpy (kd.data, key_data, KEY_CONTENT_LEN);
put_string ("enc...");
encrypt (keystring_pw1, ((uint8_t *)&kd) + 4);
put_string ("done\r\n");
if ((r = flash_key_write (kd.key_addr, kd.data)) < 0)
return r;
switch (kk)
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
{
case GPG_KEY_FOR_SIGNATURE:
p = flash_do_write (GNUK_DO_KEYPTR_SIG, &kd,
sizeof (kd) - KEY_CONTENT_LEN);
do_p = get_do_entry (GNUK_DO_KEYPTR_SIG);
do_p->obj = p;
break;
case GPG_KEY_FOR_DECRYPT:
p = flash_do_write (GNUK_DO_KEYPTR_DEC, &kd,
sizeof (kd) - KEY_CONTENT_LEN);
do_p = get_do_entry (GNUK_DO_KEYPTR_DEC);
do_p->obj = p;
break;
case GPG_KEY_FOR_AUTHENTICATION:
p = flash_do_write (GNUK_DO_KEYPTR_AUT, &kd,
sizeof (kd) - KEY_CONTENT_LEN);
do_p = get_do_entry (GNUK_DO_KEYPTR_AUT);
do_p->obj = p;
break;
free (kd);
return -1;
}
modulus = modulus_calc (key_data, key_len);
if (modulus == NULL)
{
free (kd);
free (pd);
return -1;
}
key_addr = flash_key_alloc (kk);
if (key_addr == NULL)
{
free (kd);
free (pd);
modulus_free (modulus);
return -1;
}
memcpy (kd->data, key_data, KEY_CONTENT_LEN);
kd->check = calc_check32 (key_data, KEY_CONTENT_LEN);
kd->random = get_random ();
memcpy (kd->magic, GNUK_MAGIC, KEY_MAGIC_LEN);
DEBUG_INFO ("enc...");
dek = get_data_encryption_key (); /* 16-byte random bytes */
encrypt (dek, (uint8_t *)kd, sizeof (kd));
DEBUG_INFO ("done\r\n");
r = flash_key_write (key_addr, kd->data, modulus);
modulus_free (modulus);
if (r < 0)
{
dek_free (dek);
free (pd);
free (kd);
return r;
}
pd->key_addr = key_addr;
memcpy (pd->crm_encrypted, (uint8_t *)&kd->check, ADDITIONAL_DATA_SIZE);
reset_pso_cds ();
if (ks_pw1)
{
memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
/* Only its length */
gpg_do_write_simple (GNUK_DO_KEYSTRING_PW1, ks_pw1, 1);
}
else
{
uint8_t ks123_pw1[KEYSTRING_SIZE_PW1];
ks123_pw1[0] = 6;
sha1 ((uint8_t *)"123456", 6, ks123_pw1+1);
memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
encrypt (ks123_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
/* Only but its length */
gpg_do_write_simple (GNUK_DO_KEYSTRING_PW1, ks123_pw1, 1);
}
if (ks_rc)
{
memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE);
encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE);
/* Only its length */
gpg_do_write_simple (GNUK_DO_KEYSTRING_RC, ks_rc, 1);
}
else
memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE);
encrypt (keystring, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
p = flash_do_write (tag, (const uint8_t *)pd, sizeof (struct prvkey_data));
do_p = get_do_entry (tag);
do_p->obj = p;
dek_free (dek);
free (kd);
free (pd);
if (p == NULL)
return -1;
return 0;
}
int
gpg_do_chks_prvkey (enum kind_of_key kk,
int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks)
{
uint16_t tag = get_tag_for_kk (kk);
struct do_table_entry *do_p = get_do_entry (tag);
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
struct prvkey_data *pd;
const uint8_t *p;
uint8_t *dek_p;
if (do_p->obj == NULL)
return 0; /* No private key */
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
return -1;
memcpy (pd, &((uint8_t *)do_p->obj)[1], sizeof (struct prvkey_data));
dek_p = ((uint8_t *)pd) + 4 + ADDITIONAL_DATA_SIZE + DATA_ENCRYPTION_KEY_SIZE * (who_old - 1);
memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE);
decrypt (old_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
encrypt (new_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
dek_p += DATA_ENCRYPTION_KEY_SIZE * (who_new - who_old);
memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE);
p = flash_do_write (tag, (const uint8_t *)pd, sizeof (struct prvkey_data));
do_p->obj = p;
free (pd);
if (p == NULL)
return -1;
return 1;
}
/*
* 4d, xx, xx: Extended Header List
* b6 00 (SIG) / b8 00 (DEC) / a4 00 (AUT)
@@ -548,31 +655,45 @@ gpg_write_do_keyptr (enum kind_of_key kk, uint8_t *key_data, int key_len)
* 5f48, xx: cardholder private key
*/
static void
proc_key_import (uint16_t tag, uint8_t *data, int len)
proc_key_import (const uint8_t *data, int len)
{
int i, r;
int r;
enum kind_of_key kk;
for (i = 0; i < len; i++)
{
put_byte_with_no_nl (data[i]);
if ((i & 0x0f) == 0x0f)
_write ("\r\n", 2);
}
_write ("\r\n", 2);
DEBUG_BINARY (data, len);
if (data[4] == 0xa4)
kk = GPG_KEY_FOR_AUTHENTICATION;
if (data[4] == 0xb6)
kk = GPG_KEY_FOR_SIGNATURE;
else if (data[4] == 0xb8)
kk = GPG_KEY_FOR_DECRYPT;
else /* 0xb6 */
kk = GPG_KEY_FOR_SIGNATURE;
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
r = gpg_write_do_keyptr (kk, &data[22], len - 22);
if (len <= 22)
{ /* Deletion of the key */
uint16_t tag = get_tag_for_kk (kk);
struct do_table_entry *do_p = get_do_entry (tag);
if (do_p->obj)
{
uint8_t *key_addr = *(uint8_t **)&((uint8_t *)do_p->obj)[1];
flash_do_release (do_p->obj);
flash_key_release (key_addr);
}
do_p->obj = NULL;
GPG_SUCCESS ();
return;
}
/* It should starts with 00 01 00 01 (E) */
/* Skip E, 4-byte */
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_md_pw3);
if (r < 0)
write_res_apdu (NULL, 0, 0x65, 0x81); /* memory failure */
GPG_MEMORY_FAILURE();
else
write_res_apdu (NULL, 0, 0x90, 0x00); /* success */
GPG_SUCCESS ();
}
static const uint16_t const cn_ch_data[] = {
@@ -597,12 +718,13 @@ 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 },
{ GNUK_DO_HASH_RC, DO_HASH, AC_NEVER, AC_NEVER, NULL },
/* Pseudo DO (private): not directly user accessible */
{ GNUK_DO_PRVKEY_SIG, DO_VAR, AC_NEVER, AC_NEVER, NULL },
{ GNUK_DO_PRVKEY_DEC, DO_VAR, AC_NEVER, AC_NEVER, NULL },
{ GNUK_DO_PRVKEY_AUT, DO_VAR, AC_NEVER, AC_NEVER, NULL },
{ GNUK_DO_KEYSTRING_PW1, DO_VAR, AC_NEVER, AC_NEVER, NULL },
{ GNUK_DO_KEYSTRING_PW3, DO_VAR, AC_NEVER, AC_NEVER, NULL },
{ GNUK_DO_KEYSTRING_RC, DO_VAR, AC_NEVER, AC_NEVER, NULL },
{ GNUK_DO_PW_STATUS, DO_VAR, AC_NEVER, AC_NEVER, NULL },
/* Pseudo DO READ: calculated */
{ GPG_DO_HIST_BYTES, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_hist_bytes },
@@ -652,14 +774,9 @@ gpg_do_table[] = {
#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[];
/*
@@ -673,23 +790,13 @@ gpg_do_table_init (void)
do_p = get_do_entry (GPG_DO_LOGIN_DATA);
do_p->obj = do_5e;
do_p = get_do_entry (GNUK_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->obj = pw_status_bytes_template;
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;
@@ -753,7 +860,7 @@ copy_do (struct do_table_entry *do_p)
if (do_p == NULL)
return 0;
if (ac_check_status (do_p->ac_read) == 0)
if (!ac_check_status (do_p->ac_read))
return -1;
switch (do_p->do_type)
@@ -797,22 +904,18 @@ copy_do (struct do_table_entry *do_p)
}
case DO_PROC_READ:
{
void (*do_func)(uint16_t) = (void (*)(uint16_t))do_p->obj;
int (*do_func)(uint16_t) = (int (*)(uint16_t))do_p->obj;
do_func (do_p->tag);
break;
return do_func (do_p->tag);
}
case DO_PROC_READWRITE:
{
void (*rw_func)(uint16_t, uint8_t *, int, int)
= (void (*)(uint16_t, uint8_t *, int, int))do_p->obj;
int (*rw_func)(uint16_t, uint8_t *, int, int)
= (int (*)(uint16_t, uint8_t *, int, int))do_p->obj;
rw_func (do_p->tag, NULL, 0, 0);
break;
return rw_func (do_p->tag, NULL, 0, 0);
}
case DO_PROC_WRITE:
case DO_HASH:
case DO_KEYPTR:
return -1;
}
@@ -831,16 +934,14 @@ gpg_do_get_data (uint16_t tag)
res_p = res_APDU;
with_tag = 0;
#ifdef DEBUG
put_string (" ");
put_short (tag);
#endif
DEBUG_INFO (" ");
DEBUG_SHORT (tag);
if (do_p)
{
if (copy_do (do_p) < 0)
/* Overwrite partially written result */
write_res_apdu (NULL, 0, 0x69, 0x82);
/* Overwriting partially written result */
GPG_SECURITY_FAILURE ();
else
{
*res_p++ = 0x90;
@@ -849,25 +950,22 @@ gpg_do_get_data (uint16_t tag)
}
}
else
/* No record */
write_res_apdu (NULL, 0, 0x6a, 0x88);
GPG_NO_RECORD();
}
void
gpg_do_put_data (uint16_t tag, uint8_t *data, int len)
gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
{
struct do_table_entry *do_p = get_do_entry (tag);
#ifdef DEBUG
put_string (" ");
put_short (tag);
#endif
DEBUG_INFO (" ");
DEBUG_SHORT (tag);
if (do_p)
{
if (ac_check_status (do_p->ac_write) == 0)
if (!ac_check_status (do_p->ac_write))
{
write_res_apdu (NULL, 0, 0x69, 0x82);
GPG_SECURITY_FAILURE ();
return;
}
@@ -876,17 +974,15 @@ gpg_do_put_data (uint16_t tag, uint8_t *data, int len)
case DO_FIXED:
case DO_CN_READ:
case DO_PROC_READ:
case DO_HASH:
case DO_KEYPTR:
write_res_apdu (NULL, 0, 0x69, 0x82);
GPG_SECURITY_FAILURE ();
break;
case DO_VAR:
{
#if 0
const uint8_t *do_data = (const uint8_t *)do_p->obj;
flash_do_release (do_data);
#endif
if (do_data)
flash_do_release (do_data);
if (len == 0)
/* make DO empty */
do_p->obj = NULL;
@@ -894,31 +990,134 @@ gpg_do_put_data (uint16_t tag, uint8_t *data, int len)
{
do_p->obj = flash_do_write (tag, data, len);
if (do_p->obj)
write_res_apdu (NULL, 0, 0x90, 0x00); /* success */
GPG_SUCCESS ();
else
write_res_apdu (NULL, 0, 0x65, 0x81); /* memory failure */
GPG_MEMORY_FAILURE();
}
break;
}
case DO_PROC_READWRITE:
{
void (*rw_func)(uint16_t, uint8_t *, int, int)
= (void (*)(uint16_t, uint8_t *, int, int))do_p->obj;
int (*rw_func)(uint16_t, const uint8_t *, int, int)
= (int (*)(uint16_t, const uint8_t *, int, int))do_p->obj;
rw_func (tag, data, len, 1);
break;
}
case DO_PROC_WRITE:
{
void (*proc_func)(uint16_t, uint8_t *, int)
= (void (*)(uint16_t, uint8_t *, int))do_p->obj;
void (*proc_func)(const uint8_t *, int)
= (void (*)(const uint8_t *, int))do_p->obj;
proc_func (tag, data, len);
proc_func (data, len);
break;
}
}
}
else
/* No record */
write_res_apdu (NULL, 0, 0x6a, 0x88);
GPG_NO_RECORD();
}
void
gpg_do_public_key (uint8_t kk_byte)
{
struct do_table_entry *do_p;
uint8_t *key_addr;
if (kk_byte == 0xa4)
do_p = get_do_entry (GNUK_DO_PRVKEY_AUT);
else if (kk_byte == 0xb8)
do_p = get_do_entry (GNUK_DO_PRVKEY_DEC);
else /* 0xb6 */
do_p = get_do_entry (GNUK_DO_PRVKEY_SIG);
if (do_p->obj == NULL)
{
GPG_NO_RECORD();
return;
}
key_addr = *(uint8_t **)&((uint8_t *)do_p->obj)[1];
res_p = res_APDU;
/* TAG */
*res_p++ = 0x7f; *res_p++ = 0x49;
/* LEN = 9+256 */
*res_p++ = 0x82; *res_p++ = 0x01; *res_p++ = 0x09;
{
/*TAG*/ /*LEN = 256 */
*res_p++ = 0x81; *res_p++ = 0x82; *res_p++ = 0x01; *res_p++ = 0x00;
/* 256-byte binary (big endian) */
memcpy (res_p, key_addr + KEY_CONTENT_LEN, KEY_CONTENT_LEN);
res_p += 256;
}
{
/*TAG*/ /*LEN= 3 */
*res_p++ = 0x82; *res_p++ = 3;
/* 3-byte E=0x10001 (big endian) */
*res_p++ = 0x01; *res_p++ = 0x00; *res_p++ = 0x01;
/* Success */
*res_p++ = 0x90; *res_p++ = 0x00;
res_APDU_size = res_p - res_APDU;
}
return;
}
const uint8_t *
gpg_do_read_simple (uint16_t tag)
{
struct do_table_entry *do_p;
const uint8_t *do_data;
do_p = get_do_entry (tag);
do_data = (const uint8_t *)do_p->obj;
if (do_data == NULL)
return NULL;
return do_data+1;
}
void
gpg_do_write_simple (uint16_t tag, const uint8_t *data, int size)
{
struct do_table_entry *do_p;
const uint8_t *do_data;
do_p = get_do_entry (tag);
do_data = (const uint8_t *)do_p->obj;
if (do_data)
flash_do_release (do_p->obj);
do_p->obj = flash_do_write (tag, data, size);
if (do_p->obj)
GPG_SUCCESS ();
else
GPG_MEMORY_FAILURE();
}
void
gpg_do_increment_digital_signature_counter (void)
{
struct do_table_entry *do_p;
const uint8_t *do_data;
uint32_t count;
uint8_t count_data[SIZE_DIGITAL_SIGNATURE_COUNTER];
do_p = get_do_entry (GPG_DO_DS_COUNT);
do_data = (const uint8_t *)do_p->obj;
if (do_data == NULL) /* No object means count 0 */
count = 0;
else
count = (do_data[1]<<16) | (do_data[2]<<8) | do_data[3];
count++;
count_data[0] = (count >> 16) & 0xff;
count_data[1] = (count >> 8) & 0xff;
count_data[2] = count & 0xff;
do_p->obj = flash_do_write (GPG_DO_DS_COUNT, count_data,
SIZE_DIGITAL_SIGNATURE_COUNTER);
}

536
src/openpgp.c Normal file
View File

@@ -0,0 +1,536 @@
/*
* openpgp.c -- OpenPGP card protocol support
*
* 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 "hal.h"
#include "gnuk.h"
#include "openpgp.h"
#include "polarssl/config.h"
#include "polarssl/sha1.h"
#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */
#define INS_VERIFY 0x20
#define INS_CHANGE_REFERENCE_DATA 0x24
#define INS_PSO 0x2a
#define INS_RESET_RETRY_COUNTER 0x2c
#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47
#define INS_SELECT_FILE 0xa4
#define INS_READ_BINARY 0xb0
#define INS_GET_DATA 0xca
#define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb /* For key import */
extern const char const select_file_TOP_result[20];
extern const char const get_data_rb_result[6];
void
write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2)
{
res_APDU_size = 2 + len;
if (len)
memcpy (res_APDU, p, len);
res_APDU[len] = sw1;
res_APDU[len+1] = sw2;
}
#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
cmd_verify (void)
{
int len;
uint8_t p2 = cmd_APDU[3];
int r;
DEBUG_INFO (" - 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_admin (&cmd_APDU[5], len);
if (r < 0)
GPG_SECURITY_FAILURE ();
else if (r == 0)
GPG_SECURITY_AUTH_BLOCKED ();
else
GPG_SUCCESS ();
}
int
gpg_change_keystring (int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks)
{
int r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNATURE, who_old, old_ks);
if (r <= 0)
return r;
r = gpg_do_chks_prvkey (GPG_KEY_FOR_SIGNATURE, who_old, old_ks,
who_new, new_ks);
if (r < 0)
return -2;
return r;
}
static void
cmd_change_password (void)
{
uint8_t old_ks[KEYSTRING_MD_SIZE];
uint8_t new_ks0[KEYSTRING_MD_SIZE+1];
uint8_t *new_ks = &new_ks0[1];
uint8_t p2 = cmd_APDU[3];
int len = cmd_APDU[4];
const uint8_t *pw = &cmd_APDU[5];
const uint8_t *newpw;
int pw_len, newpw_len;
int who = p2 - 0x80;
int r;
if (who == 1) /* PW1 */
{
const uint8_t *pk = gpg_do_read_simple (GNUK_DO_KEYSTRING_PW1);
if (pk == NULL)
{
if (len < 6)
{
GPG_SECURITY_FAILURE ();
return;
}
/* pk==NULL implies we have no prvkey */
pw_len = 6;
newpw = pw + pw_len;
newpw_len = len - pw_len;
goto no_prvkey;
}
else
{
pw_len = pk[0];
newpw = pw + pw_len;
newpw_len = len - pw_len;
}
}
else /* PW3 (0x83) */
{
pw_len = verify_admin_0 (pw, len, -1);
if (pw_len < 0)
{
GPG_SECURITY_FAILURE ();
return;
}
else if (pw_len == 0)
{
GPG_SECURITY_AUTH_BLOCKED ();
return;
}
else
{
newpw = pw + pw_len;
newpw_len = len - pw_len;
gpg_set_pw3 (newpw, newpw_len);
}
}
sha1 (pw, pw_len, old_ks);
sha1 (newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
r = gpg_change_keystring (who, old_ks, who, new_ks);
if (r < -2)
GPG_MEMORY_FAILURE ();
else if (r < 0)
GPG_SECURITY_FAILURE ();
else if (r == 0 && who == 1) /* no prvkey */
{
no_prvkey:
gpg_do_write_simple (GNUK_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
reset_pso_cds ();
}
else if (r > 0 && who == 1)
{
gpg_do_write_simple (GNUK_DO_KEYSTRING_PW1, new_ks0, 1);
reset_pso_cds ();
}
else /* r >= 0 && who == 3 */
GPG_SUCCESS ();
}
static void
cmd_reset_user_password (void)
{
uint8_t p1 = cmd_APDU[2];
int len = cmd_APDU[3];
const uint8_t *pw = &cmd_APDU[4];
const uint8_t *newpw;
int pw_len, newpw_len;
int r;
if (p1 == 0x00) /* by User with Reseting Code */
{
const uint8_t *pw_status_bytes = gpg_do_read_simple (GNUK_DO_PW_STATUS);
const uint8_t *ks_rc = gpg_do_read_simple (GNUK_DO_KEYSTRING_RC);
uint8_t old_ks[KEYSTRING_MD_SIZE];
uint8_t new_ks0[KEYSTRING_MD_SIZE+1];
uint8_t *new_ks = &new_ks0[1];
if (pw_status_bytes == NULL
|| pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */
{
GPG_SECURITY_AUTH_BLOCKED ();
return;
}
if (ks_rc == NULL)
{
GPG_SECURITY_FAILURE ();
return;
}
pw_len = ks_rc[0];
newpw = pw + pw_len;
newpw_len = len - pw_len;
sha1 (pw, pw_len, old_ks);
sha1 (newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
r = gpg_change_keystring (2, old_ks, 1, new_ks);
if (r < -2)
GPG_MEMORY_FAILURE ();
else if (r < 0)
{
uint8_t pwsb[SIZE_PW_STATUS_BYTES];
sec_fail:
memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES);
pwsb[PW_STATUS_RC]--;
gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
GPG_SECURITY_FAILURE ();
}
else if (r == 0)
{
if (memcmp (ks_rc+1, old_ks, KEYSTRING_MD_SIZE) != 0)
goto sec_fail;
gpg_do_write_simple (GNUK_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
reset_pso_cds ();
}
else
{
reset_pso_cds ();
GPG_SUCCESS ();
}
}
else /* by Admin (p1 == 0x02) */
{
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
GPG_SECURITY_FAILURE ();
else
{
const uint8_t *old_ks = keystring_md_pw3;
uint8_t new_ks0[KEYSTRING_MD_SIZE+1];
uint8_t *new_ks = &new_ks0[1];
newpw_len = len;
newpw = pw;
sha1 (newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
r = gpg_change_keystring (3, old_ks, 1, new_ks);
if (r < -2)
GPG_MEMORY_FAILURE ();
else if (r < 0)
GPG_SECURITY_FAILURE ();
else if (r == 0)
{
gpg_do_write_simple (GNUK_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
reset_pso_cds ();
}
else
{
reset_pso_cds ();
GPG_SUCCESS ();
}
}
}
}
static void
cmd_put_data (void)
{
uint8_t *data;
uint16_t tag;
int len;
DEBUG_INFO (" - PUT DATA\r\n");
if (file_selection != FILE_DF_OPENPGP)
GPG_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);
}
static void
cmd_pgp_gakp (void)
{
DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
if (cmd_APDU[2] == 0x81)
/* Get public key */
gpg_do_public_key (cmd_APDU[5]);
else
{ /* Generate key pair */
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
GPG_SECURITY_FAILURE ();
/* XXX: Not yet supported */
write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */
}
}
static void
cmd_read_binary (void)
{
DEBUG_INFO (" - Read binary\r\n");
if (file_selection == FILE_EF_SERIAL)
{
if (cmd_APDU[3] >= 6)
GPG_BAD_P0_P1 ();
else
/* Tag 5a, serial number */
write_res_apdu ((const uint8_t *)get_data_rb_result,
sizeof (get_data_rb_result), 0x90, 0x00);
}
else
GPG_NO_RECORD();
}
static void
cmd_select_file (void)
{
if (cmd_APDU[2] == 4) /* Selection by DF name */
{
DEBUG_INFO (" - select DF by name\r\n");
/*
* P2 == 0, LC=6, name = D2 76 00 01 24 01
*/
file_selection = FILE_DF_OPENPGP;
/* XXX: Should return contents??? */
GPG_SUCCESS ();
}
else if (cmd_APDU[4] == 2
&& cmd_APDU[5] == 0x2f
&& cmd_APDU[6] == 0x02)
{
DEBUG_INFO (" - select 0x2f02 EF\r\n");
/*
* MF.EF-GDO -- Serial number of the card and name of the owner
*/
GPG_SUCCESS ();
file_selection = FILE_EF_SERIAL;
}
else if (cmd_APDU[4] == 2
&& cmd_APDU[5] == 0x3f
&& cmd_APDU[6] == 0x00)
{
DEBUG_INFO (" - select ROOT MF\r\n");
if (cmd_APDU[3] == 0x0c)
{
GPG_SUCCESS ();
}
else
{
write_res_apdu ((const uint8_t *)select_file_TOP_result,
sizeof (select_file_TOP_result), 0x90, 0x00);
}
file_selection = FILE_MF;
}
else
{
DEBUG_INFO (" - select ?? \r\n");
file_selection = FILE_NONE;
GPG_NO_FILE();
}
}
static void
cmd_get_data (void)
{
uint16_t tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
DEBUG_INFO (" - Get Data\r\n");
if (file_selection != FILE_DF_OPENPGP)
GPG_NO_RECORD();
gpg_do_get_data (tag);
}
static void
cmd_pso (void)
{
DEBUG_INFO (" - PSO\r\n");
if (cmd_APDU[2] == 0x9E && cmd_APDU[3] == 0x9A)
{
if (!ac_check_status (AC_PSO_CDS_AUTHORIZED))
{
GPG_SECURITY_FAILURE ();
return;
}
if (cmd_APDU_size != 8 + 35 && cmd_APDU_size != 8 + 35 + 1)
/* Extended Lc: 3-byte */
{
DEBUG_INFO (" wrong length: ");
DEBUG_SHORT (cmd_APDU_size);
}
else
{
int len = (cmd_APDU[5]<<8) | cmd_APDU[6];
int r;
DEBUG_BYTE (len); /* Should be cmd_APDU_size - 6 */
r = rsa_sign (&cmd_APDU[7], res_APDU, len);
if (r < 0)
/* XXX: fail code??? */
write_res_apdu (NULL, 0, 0x69, 0x85);
else
{ /* Success */
const uint8_t *pw_status_bytes = gpg_do_read_simple (GNUK_DO_PW_STATUS);
res_APDU[RSA_SIGNATURE_LENGTH] = 0x90;
res_APDU[RSA_SIGNATURE_LENGTH+1] = 0x00;
res_APDU_size = RSA_SIGNATURE_LENGTH + 2;
if (pw_status_bytes[0] == 0)
reset_pso_cds ();
gpg_do_increment_digital_signature_counter ();
}
}
DEBUG_INFO ("done.\r\n");
}
else
{ /* XXX: not yet supported */
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd_APDU[2]);
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd_APDU[3]);
GPG_SUCCESS ();
}
}
struct command
{
uint8_t command;
void (*cmd_handler) (void);
};
struct command cmds[] = {
{ INS_VERIFY, cmd_verify },
{ INS_CHANGE_REFERENCE_DATA, cmd_change_password },
{ INS_PSO, cmd_pso },
{ INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
{ INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
{ INS_SELECT_FILE, cmd_select_file },
{ INS_READ_BINARY, cmd_read_binary },
{ INS_GET_DATA, cmd_get_data },
{ INS_PUT_DATA, cmd_put_data },
{ INS_PUT_DATA_ODD, cmd_put_data },
};
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
static void
process_command_apdu (void)
{
int i;
uint8_t cmd = cmd_APDU[1];
for (i = 0; i < NUM_CMDS; i++)
if (cmds[i].command == cmd)
break;
if (i < NUM_CMDS)
cmds[i].cmd_handler ();
else
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd);
GPG_NO_INS ();
}
}
Thread *gpg_thread;
msg_t
GPGthread (void *arg)
{
(void)arg;
gpg_thread = chThdSelf ();
chEvtClear (ALL_EVENTS);
while (1)
{
eventmask_t m;
m = chEvtWaitOne (ALL_EVENTS);
DEBUG_INFO ("GPG!\r\n");
process_command_apdu ();
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
}
return 0;
}

8
src/openpgp.h Normal file
View File

@@ -0,0 +1,8 @@
#define GPG_MEMORY_FAILURE() write_res_apdu (NULL, 0, 0x65, 0x81)
#define GPG_SECURITY_FAILURE() write_res_apdu (NULL, 0, 0x69, 0x82)
#define GPG_SECURITY_AUTH_BLOCKED() write_res_apdu (NULL, 0, 0x69, 0x83)
#define GPG_NO_FILE() write_res_apdu (NULL, 0, 0x6a, 0x82)
#define GPG_NO_RECORD() write_res_apdu (NULL, 0, 0x6a, 0x88)
#define GPG_BAD_P0_P1() write_res_apdu (NULL, 0, 0x6b, 0x00)
#define GPG_NO_INS() write_res_apdu (NULL, 0, 0x6d, 0x00)
#define GPG_SUCCESS() write_res_apdu (NULL, 0, 0x90, 0x00)

View File

@@ -3,20 +3,14 @@
#include "polarssl/config.h"
#include "polarssl/rsa.h"
static unsigned char output[256];
static rsa_context ctx;
unsigned char *
rsa_sign (unsigned char *raw_message)
int
rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len)
{
mpi P1, Q1, H;
int len;
int r;
len = (cmd_APDU[5]<<8) | cmd_APDU[6];
put_byte (len);
/* cmd_APDU_size - 6 */
mpi_init( &P1, &Q1, &H, NULL );
rsa_init( &ctx, RSA_PKCS_V15, 0 );
@@ -34,24 +28,54 @@ rsa_sign (unsigned char *raw_message)
mpi_inv_mod ( &ctx.QP, &ctx.Q, &ctx.P);
mpi_free (&P1, &Q1, &H, NULL);
put_string ("RSA...");
{
int r;
if ((r = rsa_check_privkey ( &ctx )) == 0)
put_string ("ok...");
else
{
put_string ("failed.\r\n");
put_byte (r);
rsa_free (&ctx);
return output;
}
}
DEBUG_INFO ("RSA...");
if ((r = rsa_check_privkey ( &ctx )) == 0)
DEBUG_INFO ("ok...");
else
{
DEBUG_INFO ("failed.\r\n");
DEBUG_BYTE (r);
rsa_free (&ctx);
return r;
}
r = rsa_pkcs1_sign ( &ctx, RSA_PRIVATE, SIG_RSA_RAW,
len, raw_message, output );
put_short (r);
put_string ("done.\r\n");
msg_len, raw_message, output );
rsa_free (&ctx);
return output;
DEBUG_INFO ("done.\r\n");
if (r < 0)
{
DEBUG_SHORT (r);
return r;
}
else
return 0;
}
const uint8_t *
modulus_calc (const uint8_t *p, int len)
{
mpi P, Q, N;
uint8_t *modulus;
(void)len; /* 2048-bit assumed */
modulus = malloc (2048 / 8);
if (modulus == NULL)
return NULL;
mpi_init (&P, &Q, &N, NULL);
mpi_read_binary (&P, p, 2048 / 8 / 2);
mpi_read_binary (&Q, p + 128, 2048 / 8 / 2);
mpi_mul_mpi (&N, &P, &Q);
mpi_write_binary (&N, modulus, 2048 / 8);
mpi_free (&P, &Q, &N, NULL);
return modulus;
}
void
modulus_free (const uint8_t *p)
{
free ((void *)p);
}

View File

@@ -180,14 +180,14 @@ icc_power_on (void)
if (!icc_tx_ready ())
{
_write ("ERR0B\r\n", 7);
DEBUG_INFO ("ERR0B\r\n");
}
else
{
icc_tx_size = ICC_MSG_DATA_OFFSET + size_atr;
USB_SIL_Write (EP4_IN, icc_tx_data, icc_tx_size);
SetEPTxValid (ENDP4);
_write ("ON\r\n", 4);
DEBUG_INFO ("ON\r\n");
}
return ICC_STATE_WAIT;
@@ -214,7 +214,7 @@ icc_send_status (void)
if (!icc_tx_ready ())
{
_write ("ERR0C\r\n", 7);
DEBUG_INFO ("ERR0C\r\n");
}
else
{
@@ -222,7 +222,7 @@ icc_send_status (void)
USB_SIL_Write (EP4_IN, icc_tx_data, icc_tx_size);
SetEPTxValid (ENDP4);
}
_write ("St\r\n", 4);
DEBUG_INFO ("St\r\n");
}
enum icc_state
@@ -230,7 +230,7 @@ icc_power_off (void)
{
icc_send_status ();
_write ("OFF\r\n", 5);
DEBUG_INFO ("OFF\r\n");
return ICC_STATE_START;
}
@@ -261,14 +261,14 @@ icc_send_data_block (uint8_t status, uint8_t error, uint8_t chain,
if (!icc_tx_ready ())
{ /* not ready to send */
_write ("ERR09\r\n", 7);
DEBUG_INFO ("ERR09\r\n");
}
else
{
icc_tx_size = ICC_MSG_DATA_OFFSET + len;
USB_SIL_Write (EP4_IN, icc_tx_data, icc_tx_size);
SetEPTxValid (ENDP4);
_write ("DATA\r\n", 6);
DEBUG_INFO ("DATA\r\n");
}
}
@@ -288,7 +288,7 @@ icc_handle_data (void)
icc_send_status ();
else
{ /* XXX: error */
_write ("ERR01\r\n", 7);
DEBUG_INFO ("ERR01\r\n");
}
break;
case ICC_STATE_WAIT:
@@ -320,13 +320,13 @@ icc_handle_data (void)
}
else
{ /* XXX: error */;
_write ("ERR02\r\n", 7);
DEBUG_INFO ("ERR02\r\n");
}
}
else
{ /* XXX: error */
_write ("ERR03\r\n", 7);
put_byte (icc_header->msg_type);
DEBUG_INFO ("ERR03\r\n");
DEBUG_BYTE (icc_header->msg_type);
next_state = ICC_STATE_START;
}
break;
@@ -340,8 +340,8 @@ icc_handle_data (void)
icc_send_status ();
else
{ /* XXX: error */
_write ("ERR04\r\n", 7);
put_byte (icc_header->msg_type);
DEBUG_INFO ("ERR04\r\n");
DEBUG_BYTE (icc_header->msg_type);
next_state = ICC_STATE_START;
}
break;
@@ -368,7 +368,7 @@ icc_handle_data (void)
icc_send_data_block (0, 0, 0x10, NULL, 0);
else
{ /* XXX: error */
_write ("ERR08\r\n", 7);
DEBUG_INFO ("ERR08\r\n");
}
}
else /* Overrun */
@@ -380,8 +380,8 @@ icc_handle_data (void)
}
else
{ /* XXX: error */
_write ("ERR05\r\n", 7);
put_byte (icc_header->msg_type);
DEBUG_INFO ("ERR05\r\n");
DEBUG_BYTE (icc_header->msg_type);
next_state = ICC_STATE_START;
}
break;
@@ -409,16 +409,16 @@ icc_handle_data (void)
}
else
{ /* XXX: error */
_write ("ERR0A\r\n", 7);
put_byte (icc_header->param >> 8);
put_byte (icc_header->param & 0xff);
DEBUG_INFO ("ERR0A\r\n");
DEBUG_BYTE (icc_header->param >> 8);
DEBUG_BYTE (icc_header->param & 0xff);
next_state = ICC_STATE_WAIT;
}
}
else
{ /* XXX: error */
_write ("ERR06\r\n", 7);
put_byte (icc_header->msg_type);
DEBUG_INFO ("ERR06\r\n");
DEBUG_BYTE (icc_header->msg_type);
next_state = ICC_STATE_START;
}
break;
@@ -491,7 +491,7 @@ USBthread (void *arg)
}
else
{ /* XXX: error */
_write ("ERR07\r\n", 7);
DEBUG_INFO ("ERR07\r\n");
}
}
else /* Timeout */

View File

@@ -66,7 +66,7 @@ static const uint8_t gnukConfigDescriptor[] = {
0xfe, 0, 0, 0, /* dwMaxIFSD: */
0, 0, 0, 0, /* dwSynchProtocols: 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 APDU level */
0x40, 0x00, 0, 0, /* dwMaxCCIDMessageLength: 64 */
0xff, /* bClassGetResponse: */
0xff, /* bClassEnvelope: */