gnuk/src/openpgp-do.c

1294 lines
30 KiB
C
Raw Normal View History

2010-08-26 10:50:06 +00:00
/*
2010-08-30 02:39:10 +00:00
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
2010-08-26 10:50:06 +00:00
*
* 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/>.
*
*/
2010-09-08 05:24:12 +00:00
#include <stdlib.h>
2010-08-30 02:39:10 +00:00
2010-09-08 05:24:12 +00:00
#include "config.h"
2010-08-26 10:50:06 +00:00
#include "ch.h"
#include "gnuk.h"
2010-09-03 15:42:36 +00:00
#include "openpgp.h"
2010-08-26 10:50:06 +00:00
2010-08-30 11:02:22 +00:00
#include "polarssl/config.h"
#include "polarssl/aes.h"
2010-09-03 15:42:36 +00:00
#include "polarssl/sha1.h"
2010-08-30 11:02:22 +00:00
2010-09-13 02:47:21 +00:00
uint16_t data_objects_number_of_bytes;
2010-08-26 10:50:06 +00:00
/*
* Compile time vars:
* AID, Historical Bytes (template), Extended Capabilities,
* and Algorithm Attributes
*/
/* AID */
2010-09-09 08:50:34 +00:00
const uint8_t openpgpcard_aid[17] __attribute__ ((aligned (1))) = {
2010-08-26 10:50:06 +00:00
16,
0xd2, 0x76, 0x00, 0x01, 0x24, 0x01,
0x02, 0x00, /* Version 2.0 */
2010-09-08 05:24:12 +00:00
MANUFACTURER_IN_AID,
SERIAL_NUMBER_IN_AID,
2010-08-26 10:50:06 +00:00
0x00, 0x00
};
/* Historical Bytes (template) */
2010-09-05 16:55:29 +00:00
static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
2010-08-26 10:50:06 +00:00
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 */
2010-09-05 16:55:29 +00:00
static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
2010-08-26 10:50:06 +00:00
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 */
2010-09-05 16:55:29 +00:00
static const uint8_t algorithm_attr[] __attribute__ ((aligned (1))) = {
2010-08-26 10:50:06 +00:00
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) */
};
2010-09-09 08:50:34 +00:00
static const uint8_t do_ds_count_initial_value[] __attribute__ ((aligned (1))) = {
3,
0, 0, 0
};
static const uint8_t do_pw_status_bytes_template[] __attribute__ ((aligned (1))) = {
2010-09-04 04:48:26 +00:00
7,
2010-09-09 08:50:34 +00:00
0, /* PW1 is valid for single PSO:CDS command */
2010-08-26 10:50:06 +00:00
127, 127, 127, /* max length of PW1, RC, and PW3 */
3, 0, 3 /* Error counter of PW1, RC, and PW3 */
};
2010-09-04 04:48:26 +00:00
#define PW_STATUS_BYTES_TEMPLATE (do_pw_status_bytes_template+1)
2010-08-26 10:50:06 +00:00
#define SIZE_DIGITAL_SIGNATURE_COUNTER 3
2010-09-03 15:42:36 +00:00
/* 3-byte binary (big endian) */
2010-08-26 10:50:06 +00:00
#define SIZE_FINGER_PRINT 20
#define SIZE_KEYGEN_TIME 4 /* RFC4880 */
enum do_type {
DO_FIXED,
DO_VAR,
DO_CN_READ,
DO_PROC_READ,
DO_PROC_WRITE,
2010-08-30 11:02:22 +00:00
DO_PROC_READWRITE,
2010-08-26 10:50:06 +00:00
};
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);
2010-09-04 09:44:01 +00:00
static const struct do_table_entry *get_do_entry (uint16_t tag);
2010-08-26 10:50:06 +00:00
2010-09-05 09:10:54 +00:00
#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
2010-08-26 10:50:06 +00:00
#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
2010-09-04 09:44:01 +00:00
#define NUM_DO_OBJS 23
static const uint8_t *do_ptr[NUM_DO_OBJS];
2010-09-05 09:10:54 +00:00
static uint8_t
do_tag_to_nr (uint16_t tag)
{
switch (tag)
{
case GNUK_DO_PRVKEY_SIG:
return NR_DO_PRVKEY_SIG;
case GNUK_DO_PRVKEY_DEC:
return NR_DO_PRVKEY_DEC;
case GNUK_DO_PRVKEY_AUT:
return NR_DO_PRVKEY_AUT;
case GNUK_DO_KEYSTRING_PW1:
return NR_DO_KEYSTRING_PW1;
case GNUK_DO_KEYSTRING_RC:
return NR_DO_KEYSTRING_RC;
case GNUK_DO_KEYSTRING_PW3:
return NR_DO_KEYSTRING_PW3;
case GNUK_DO_PW_STATUS:
return NR_DO_PW_STATUS;
case GPG_DO_DS_COUNT:
return NR_DO_DS_COUNT;
case GPG_DO_SEX:
return NR_DO_SEX;
case GPG_DO_FP_SIG:
return NR_DO_FP_SIG;
case GPG_DO_FP_DEC:
return NR_DO_FP_DEC;
case GPG_DO_FP_AUT:
return NR_DO_FP_AUT;
case GPG_DO_CAFP_1:
return NR_DO_CAFP_1;
case GPG_DO_CAFP_2:
return NR_DO_CAFP_2;
case GPG_DO_CAFP_3:
return NR_DO_CAFP_3;
case GPG_DO_KGTIME_SIG:
return NR_DO_KGTIME_SIG;
case GPG_DO_KGTIME_DEC:
return NR_DO_KGTIME_DEC;
case GPG_DO_KGTIME_AUT:
return NR_DO_KGTIME_AUT;
case GPG_DO_LOGIN_DATA:
return NR_DO_LOGIN_DATA;
case GPG_DO_URL:
return NR_DO_URL;
case GPG_DO_NAME:
return NR_DO_NAME;
case GPG_DO_LANGUAGE:
return NR_DO_LANGUAGE;
case GPG_DO_CH_CERTIFICATE:
return NR_DO_CH_CERTIFICATE;
default:
fatal ();
}
}
2010-09-04 09:44:01 +00:00
2010-08-26 10:50:06 +00:00
static void
copy_tag (uint16_t tag)
{
if (tag < 0x0100)
*res_p++ = (tag & 0xff);
else
{
*res_p++ = (tag >> 8);
*res_p++ = (tag & 0xff);
}
}
2010-09-03 15:42:36 +00:00
static int
2010-08-26 10:50:06 +00:00
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);
2010-09-03 15:42:36 +00:00
return 0;
2010-08-26 10:50:06 +00:00
}
#define SIZE_FP 20
#define SIZE_KGTIME 4
2010-09-03 15:42:36 +00:00
static int
2010-08-26 10:50:06 +00:00
do_fp_all (uint16_t tag)
{
2010-09-04 09:44:01 +00:00
const uint8_t *data;
2010-08-26 10:50:06 +00:00
if (with_tag)
{
copy_tag (tag);
*res_p++ = SIZE_FP*3;
}
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_FP_SIG);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_FP);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_FP_DEC);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_FP);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_FP_AUT);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_FP);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
2010-09-03 15:42:36 +00:00
return 0;
2010-08-26 10:50:06 +00:00
}
2010-09-03 15:42:36 +00:00
static int
2010-08-26 10:50:06 +00:00
do_cafp_all (uint16_t tag)
{
2010-09-04 09:44:01 +00:00
const uint8_t *data;
2010-08-26 10:50:06 +00:00
if (with_tag)
{
copy_tag (tag);
*res_p++ = SIZE_FP*3;
}
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_CAFP_1);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_FP);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_CAFP_2);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_FP);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_CAFP_2);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_FP);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_FP);
res_p += SIZE_FP;
2010-09-03 15:42:36 +00:00
return 0;
2010-08-26 10:50:06 +00:00
}
2010-09-03 15:42:36 +00:00
static int
2010-08-26 10:50:06 +00:00
do_kgtime_all (uint16_t tag)
{
2010-09-04 09:44:01 +00:00
const uint8_t *data;
2010-08-26 10:50:06 +00:00
if (with_tag)
{
copy_tag (tag);
*res_p++ = SIZE_KGTIME*3;
}
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_KGTIME_SIG);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_KGTIME);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_KGTIME);
res_p += SIZE_KGTIME;
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_KGTIME_DEC);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_KGTIME);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_KGTIME);
res_p += SIZE_KGTIME;
2010-09-05 09:10:54 +00:00
data = gpg_do_read_simple (NR_DO_KGTIME_AUT);
2010-09-04 09:44:01 +00:00
if (data)
memcpy (res_p, data, SIZE_KGTIME);
2010-08-26 10:50:06 +00:00
else
memset (res_p, 0, SIZE_KGTIME);
res_p += SIZE_KGTIME;
2010-09-03 15:42:36 +00:00
return 0;
2010-08-26 10:50:06 +00:00
}
2010-09-03 15:42:36 +00:00
static int
rw_pw_status (uint16_t tag, const uint8_t *data, int len, int is_write)
2010-08-26 10:50:06 +00:00
{
2010-09-04 09:44:01 +00:00
const uint8_t *do_data = do_ptr[NR_DO_PW_STATUS];
2010-08-30 11:02:22 +00:00
if (is_write)
{
2010-09-03 15:42:36 +00:00
uint8_t pwsb[SIZE_PW_STATUS_BYTES];
2010-08-26 10:50:06 +00:00
2010-09-03 15:42:36 +00:00
(void)len;
if (do_data)
2010-08-30 11:02:22 +00:00
{
2010-09-03 15:42:36 +00:00
memcpy (pwsb, &do_data[1], SIZE_PW_STATUS_BYTES);
2010-09-04 09:44:01 +00:00
flash_do_release (do_data);
2010-08-30 11:02:22 +00:00
}
else
2010-09-04 04:48:26 +00:00
memcpy (pwsb, PW_STATUS_BYTES_TEMPLATE, SIZE_PW_STATUS_BYTES);
2010-09-03 15:42:36 +00:00
pwsb[0] = data[0];
2010-09-04 09:44:01 +00:00
do_ptr[NR_DO_PW_STATUS]
2010-09-05 09:10:54 +00:00
= flash_do_write (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
2010-09-04 09:44:01 +00:00
if (do_ptr[NR_DO_PW_STATUS])
2010-09-03 15:42:36 +00:00
GPG_SUCCESS ();
else
GPG_MEMORY_FAILURE();
return 0;
2010-08-30 11:02:22 +00:00
}
2010-08-26 10:50:06 +00:00
else
2010-08-30 11:02:22 +00:00
{
if (do_data)
{
2010-09-04 04:48:26 +00:00
if (with_tag)
{
copy_tag (tag);
*res_p++ = SIZE_PW_STATUS_BYTES;
}
2010-08-30 11:02:22 +00:00
memcpy (res_p, &do_data[1], SIZE_PW_STATUS_BYTES);
res_p += SIZE_PW_STATUS_BYTES;
2010-09-04 04:48:26 +00:00
return 1;
2010-08-30 11:02:22 +00:00
}
else
2010-09-04 04:48:26 +00:00
return 0;
2010-08-30 11:02:22 +00:00
}
}
static void
2010-09-03 15:42:36 +00:00
proc_resetting_code (const uint8_t *data, int len)
2010-08-30 11:02:22 +00:00
{
2010-09-03 15:42:36 +00:00
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;
2010-08-30 11:02:22 +00:00
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("Resetting Code!\r\n");
2010-09-03 15:42:36 +00:00
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)
{
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("memory error.\r\n");
2010-09-03 15:42:36 +00:00
GPG_MEMORY_FAILURE ();
return;
}
else if (r < 0)
{
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("security error.\r\n");
2010-09-03 15:42:36 +00:00
GPG_SECURITY_FAILURE ();
return;
}
else if (r == 0)
2010-09-05 09:10:54 +00:00
{
DEBUG_INFO ("done (no prvkey).\r\n");
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KEYSTRING_SIZE_RC);
}
2010-09-03 15:42:36 +00:00
else
2010-09-05 09:10:54 +00:00
{
DEBUG_INFO ("done.\r\n");
gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, 1);
GPG_SUCCESS ();
}
2010-08-30 11:02:22 +00:00
2010-09-03 15:42:36 +00:00
/* Reset RC counter in GNUK_DO_PW_STATUS */
2010-09-04 09:44:01 +00:00
gpg_do_reset_pw_counter (PW_STATUS_RC);
2010-09-03 15:42:36 +00:00
}
2010-08-26 10:50:06 +00:00
2010-08-30 11:02:22 +00:00
static void
2010-09-03 15:42:36 +00:00
encrypt (const uint8_t *key_str, uint8_t *data, int len)
2010-08-30 11:02:22 +00:00
{
2010-09-08 05:24:12 +00:00
aes_context aes;
uint8_t iv[16];
int iv_offset;
2010-09-04 04:48:26 +00:00
DEBUG_INFO ("ENC\r\n");
DEBUG_BINARY (data, len);
2010-08-30 11:02:22 +00:00
aes_setkey_enc (&aes, key_str, 128);
memset (iv, 0, 16);
iv_offset = 0;
2010-09-03 15:42:36 +00:00
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv, data, data);
2010-08-26 10:50:06 +00:00
}
2010-08-30 11:02:22 +00:00
struct key_data kd;
2010-08-26 10:50:06 +00:00
static void
2010-09-03 15:42:36 +00:00
decrypt (const uint8_t *key_str, uint8_t *data, int len)
2010-08-30 11:02:22 +00:00
{
2010-09-08 05:24:12 +00:00
aes_context aes;
uint8_t iv[16];
int iv_offset;
2010-08-30 11:02:22 +00:00
aes_setkey_enc (&aes, key_str, 128);
memset (iv, 0, 16);
iv_offset = 0;
2010-09-03 15:42:36 +00:00
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv, data, data);
2010-09-04 04:48:26 +00:00
2010-09-03 15:42:36 +00:00
DEBUG_INFO ("DEC\r\n");
2010-09-04 04:48:26 +00:00
DEBUG_BINARY (data, len);
2010-08-30 11:02:22 +00:00
}
2010-09-04 09:44:01 +00:00
static uint8_t
get_do_ptr_nr_for_kk (enum kind_of_key kk)
{
switch (kk)
{
2010-09-09 08:50:34 +00:00
case GPG_KEY_FOR_SIGNING:
2010-09-04 09:44:01 +00:00
return NR_DO_PRVKEY_SIG;
2010-09-09 08:50:34 +00:00
case GPG_KEY_FOR_DECRYPTION:
2010-09-04 09:44:01 +00:00
return NR_DO_PRVKEY_DEC;
case GPG_KEY_FOR_AUTHENTICATION:
return NR_DO_PRVKEY_AUT;
}
return NR_DO_PRVKEY_SIG;
}
2010-09-03 15:42:36 +00:00
/*
* 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)
{
2010-09-04 09:44:01 +00:00
uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *do_data = do_ptr[nr];
2010-09-03 15:42:36 +00:00
uint8_t *key_addr;
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
2010-09-04 09:44:01 +00:00
if (do_data == NULL)
2010-09-03 15:42:36 +00:00
return 0;
2010-09-04 09:44:01 +00:00
key_addr = *(uint8_t **)&(do_data)[1];
2010-09-03 15:42:36 +00:00
memcpy (kd.data, key_addr, KEY_CONTENT_LEN);
2010-09-04 09:44:01 +00:00
memcpy (((uint8_t *)&kd.check), do_data+5, ADDITIONAL_DATA_SIZE);
memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
2010-08-30 11:02:22 +00:00
2010-09-03 15:42:36 +00:00
decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE);
2010-09-04 04:48:26 +00:00
decrypt (dek, (uint8_t *)&kd, sizeof (struct key_data));
2010-08-30 11:02:22 +00:00
if (memcmp (kd.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
2010-09-05 09:10:54 +00:00
{
DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
return -1;
}
2010-09-09 08:50:34 +00:00
/* more sanity check??? */
2010-09-03 15:42:36 +00:00
return 1;
2010-08-30 11:02:22 +00:00
}
static uint32_t
2010-09-03 15:42:36 +00:00
calc_check32 (const uint8_t *p, int len)
2010-08-30 11:02:22 +00:00
{
uint32_t check = 0;
2010-09-03 15:42:36 +00:00
uint32_t *data = (uint32_t *)p;
2010-08-30 11:02:22 +00:00
int i;
2010-09-03 15:42:36 +00:00
for (i = 0; i < len/4; i++)
2010-08-30 11:02:22 +00:00
check += data[i];
return check;
}
2010-09-09 08:50:34 +00:00
static int8_t num_prv_keys;
2010-09-03 15:42:36 +00:00
int
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
const uint8_t *keystring)
2010-08-26 10:50:06 +00:00
{
2010-09-04 09:44:01 +00:00
uint8_t nr = get_do_ptr_nr_for_kk (kk);
2010-09-03 15:42:36 +00:00
const uint8_t *p;
2010-08-30 11:02:22 +00:00
int r;
2010-09-03 15:42:36 +00:00
const uint8_t *modulus;
struct prvkey_data *pd;
uint8_t *key_addr;
2010-09-05 16:55:29 +00:00
const uint8_t *dek;
2010-09-09 08:50:34 +00:00
const uint8_t *do_data = do_ptr[nr];
const uint8_t *ks_pw1;
const uint8_t *ks_rc;
2010-08-30 11:02:22 +00:00
#if 0
2010-09-03 15:42:36 +00:00
assert (key_len == KEY_CONTENT_LEN);
2010-08-30 11:02:22 +00:00
#endif
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("Key import\r\n");
2010-09-03 15:42:36 +00:00
DEBUG_SHORT (key_len);
2010-08-30 11:02:22 +00:00
2010-09-03 15:42:36 +00:00
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
2010-09-04 04:48:26 +00:00
return -1;
2010-08-30 11:02:22 +00:00
2010-09-03 15:42:36 +00:00
modulus = modulus_calc (key_data, key_len);
if (modulus == NULL)
{
free (pd);
return -1;
}
2010-08-30 11:02:22 +00:00
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("Getting keystore address...\r\n");
key_addr = flash_key_alloc ();
2010-09-03 15:42:36 +00:00
if (key_addr == NULL)
{
free (pd);
modulus_free (modulus);
return -1;
}
2010-08-30 11:02:22 +00:00
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("key_addr: ");
DEBUG_WORD ((uint32_t)key_addr);
2010-09-04 04:48:26 +00:00
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);
2010-08-30 11:02:22 +00:00
2010-09-09 08:50:34 +00:00
if (do_data) /* We have old prvkey */
{
/* Write new prvkey resetting PW1 and RC */
/* Note: if you have other prvkey(s), it becomes bogus */
memcpy (pd, do_data+1, sizeof (struct prvkey_data));
decrypt (keystring_md_pw3, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
dek = pd->dek_encrypted_3;
memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
flash_do_release (do_data);
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
flash_key_release (pd->key_addr);
flash_do_release (do_data);
ks_pw1 = NULL;
ks_rc = NULL;
}
else
{
dek = random_bytes_get (); /* 16-byte random bytes */
memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE);
memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE);
ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
}
2010-08-30 11:02:22 +00:00
2010-09-04 04:48:26 +00:00
encrypt (dek, (uint8_t *)&kd, sizeof (struct key_data));
2010-09-03 15:42:36 +00:00
2010-09-04 04:48:26 +00:00
r = flash_key_write (key_addr, kd.data, modulus);
2010-09-03 15:42:36 +00:00
modulus_free (modulus);
if (r < 0)
2010-08-30 11:02:22 +00:00
{
2010-09-09 08:50:34 +00:00
if (do_data == NULL)
random_bytes_free (dek);
2010-09-03 15:42:36 +00:00
free (pd);
return r;
}
pd->key_addr = key_addr;
2010-09-04 04:48:26 +00:00
memcpy (pd->crm_encrypted, (uint8_t *)&kd.check, ADDITIONAL_DATA_SIZE);
2010-09-03 15:42:36 +00:00
2010-09-04 09:44:01 +00:00
ac_reset_pso_cds ();
2010-09-03 15:42:36 +00:00
if (ks_pw1)
2010-09-09 08:50:34 +00:00
encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
2010-09-03 15:42:36 +00:00
else
{
uint8_t ks123_pw1[KEYSTRING_SIZE_PW1];
2010-09-09 08:50:34 +00:00
ks123_pw1[0] = strlen (OPENPGP_CARD_INITIAL_PW1);
sha1 ((uint8_t *)OPENPGP_CARD_INITIAL_PW1, 6, ks123_pw1+1);
2010-09-03 15:42:36 +00:00
encrypt (ks123_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
}
if (ks_rc)
2010-09-09 08:50:34 +00:00
encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE);
2010-09-03 15:42:36 +00:00
else
memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
2010-08-30 11:02:22 +00:00
2010-09-03 15:42:36 +00:00
encrypt (keystring, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
2010-09-05 09:10:54 +00:00
p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
2010-09-04 09:44:01 +00:00
do_ptr[nr] = p;
2010-09-03 15:42:36 +00:00
2010-09-09 08:50:34 +00:00
if (do_data == NULL)
random_bytes_free (dek);
2010-09-03 15:42:36 +00:00
free (pd);
2010-08-30 11:02:22 +00:00
if (p == NULL)
return -1;
2010-09-09 08:50:34 +00:00
if (do_data == NULL
&& ++num_prv_keys == NUM_ALL_PRV_KEYS) /* All keys are registered. */
{
/* Remove contents of keystrings from DO, but length */
if (ks_pw1)
{
uint8_t ks_pw1_len = ks_pw1[0];
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
}
if (ks_rc)
{
uint8_t ks_rc_len = ks_rc[0];
gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
}
}
2010-08-30 11:02:22 +00:00
return 0;
2010-08-26 10:50:06 +00:00
}
2010-09-03 15:42:36 +00:00
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)
{
2010-09-04 09:44:01 +00:00
uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *do_data = do_ptr[nr];
2010-09-03 15:42:36 +00:00
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
struct prvkey_data *pd;
const uint8_t *p;
uint8_t *dek_p;
2010-09-04 09:44:01 +00:00
if (do_data == NULL)
2010-09-03 15:42:36 +00:00
return 0; /* No private key */
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
return -1;
2010-09-04 09:44:01 +00:00
memcpy (pd, &(do_data)[1], sizeof (struct prvkey_data));
2010-09-03 15:42:36 +00:00
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);
2010-09-05 09:10:54 +00:00
p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
2010-09-04 09:44:01 +00:00
do_ptr[nr] = p;
2010-09-03 15:42:36 +00:00
2010-09-09 08:50:34 +00:00
flash_do_release (do_data);
2010-09-03 15:42:36 +00:00
free (pd);
if (p == NULL)
return -1;
return 1;
}
2010-08-26 10:50:06 +00:00
/*
* 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
2010-08-30 11:02:22 +00:00
* 5f48, xx: cardholder private key
2010-08-26 10:50:06 +00:00
*/
static void
2010-09-03 15:42:36 +00:00
proc_key_import (const uint8_t *data, int len)
2010-08-26 10:50:06 +00:00
{
2010-09-03 15:42:36 +00:00
int r;
2010-08-30 11:02:22 +00:00
enum kind_of_key kk;
2010-08-26 10:50:06 +00:00
2010-09-03 15:42:36 +00:00
DEBUG_BINARY (data, len);
2010-08-26 10:50:06 +00:00
2010-09-03 15:42:36 +00:00
if (data[4] == 0xb6)
2010-09-09 08:50:34 +00:00
kk = GPG_KEY_FOR_SIGNING;
2010-08-30 11:02:22 +00:00
else if (data[4] == 0xb8)
2010-09-09 08:50:34 +00:00
kk = GPG_KEY_FOR_DECRYPTION;
2010-09-03 15:42:36 +00:00
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
if (len <= 22)
{ /* Deletion of the key */
2010-09-04 09:44:01 +00:00
uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *do_data = do_ptr[nr];
2010-09-03 15:42:36 +00:00
2010-09-09 08:50:34 +00:00
/* Delete the key */
2010-09-04 09:44:01 +00:00
if (do_data)
2010-09-03 15:42:36 +00:00
{
2010-09-04 09:44:01 +00:00
uint8_t *key_addr = *(uint8_t **)&do_data[1];
2010-08-30 11:02:22 +00:00
2010-09-03 15:42:36 +00:00
flash_key_release (key_addr);
2010-09-09 08:50:34 +00:00
flash_do_release (do_data);
2010-09-03 15:42:36 +00:00
}
2010-09-04 09:44:01 +00:00
do_ptr[nr] = NULL;
2010-09-09 08:50:34 +00:00
if (--num_prv_keys == 0)
{
/* Delete PW1 and RC if any */
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
}
2010-09-03 15:42:36 +00:00
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);
2010-08-30 11:02:22 +00:00
if (r < 0)
2010-09-03 15:42:36 +00:00
GPG_MEMORY_FAILURE();
2010-08-30 11:02:22 +00:00
else
2010-09-03 15:42:36 +00:00
GPG_SUCCESS ();
2010-08-26 10:50:06 +00:00
}
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 };
2010-09-04 09:44:01 +00:00
static const struct do_table_entry
2010-08-26 10:50:06 +00:00
gpg_do_table[] = {
2010-09-03 15:42:36 +00:00
/* Pseudo DO (private): not directly user accessible */
2010-09-04 09:44:01 +00:00
{ GNUK_DO_PRVKEY_SIG, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[0] },
{ GNUK_DO_PRVKEY_DEC, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[1] },
{ GNUK_DO_PRVKEY_AUT, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[2] },
{ GNUK_DO_KEYSTRING_PW1, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[3] },
{ GNUK_DO_KEYSTRING_RC, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[4] },
{ GNUK_DO_KEYSTRING_PW3, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[5] },
{ GNUK_DO_PW_STATUS, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[6] },
2010-08-26 10:50:06 +00:00
/* Variable(s): Fixed size, not changeable by user */
2010-09-04 09:44:01 +00:00
{ GPG_DO_DS_COUNT, DO_VAR, AC_ALWAYS, AC_NEVER, &do_ptr[7] },
2010-08-26 10:50:06 +00:00
/* Variables: Fixed size */
2010-09-04 09:44:01 +00:00
{ GPG_DO_SEX, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[8] },
{ GPG_DO_FP_SIG, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[9] },
{ GPG_DO_FP_DEC, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[10] },
{ GPG_DO_FP_AUT, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[11] },
{ GPG_DO_CAFP_1, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[12] },
{ GPG_DO_CAFP_2, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[13] },
{ GPG_DO_CAFP_3, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[14] },
{ GPG_DO_KGTIME_SIG, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[15] },
{ GPG_DO_KGTIME_DEC, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[16] },
{ GPG_DO_KGTIME_AUT, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[17] },
2010-08-26 10:50:06 +00:00
/* Variables: Variable size */
2010-09-04 09:44:01 +00:00
{ GPG_DO_LOGIN_DATA, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[18] },
{ GPG_DO_URL, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[19] },
{ GPG_DO_NAME, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[20] },
{ GPG_DO_LANGUAGE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[21] },
{ GPG_DO_CH_CERTIFICATE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[22] },
2010-09-04 04:48:26 +00:00
/* Pseudo DO READ: 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 },
/* Pseudo DO READ/WRITE: calculated */
{ GPG_DO_PW_STATUS, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
rw_pw_status },
/* Fixed data */
2010-09-09 08:50:34 +00:00
{ GPG_DO_AID, DO_FIXED, AC_ALWAYS, AC_NEVER, openpgpcard_aid },
2010-09-04 04:48:26 +00:00
{ 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 },
2010-09-09 08:50:34 +00:00
{ GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr },
2010-08-26 10:50:06 +00:00
/* 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 },
2010-08-30 11:02:22 +00:00
/* Simple data: write access only */
{ GPG_DO_RESETTING_CODE, DO_PROC_WRITE, AC_NEVER, AC_ADMIN_AUTHORIZED,
proc_resetting_code },
2010-08-26 10:50:06 +00:00
/* 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))
/*
2010-09-05 09:10:54 +00:00
* Initialize DO_PTR reading from Flash ROM
2010-08-26 10:50:06 +00:00
*/
int
gpg_do_table_init (void)
{
2010-09-05 09:10:54 +00:00
const uint8_t *p, *p_start;
2010-09-13 02:47:21 +00:00
int i, len;
2010-09-05 09:10:54 +00:00
2010-09-09 08:50:34 +00:00
do_ptr[NR_DO_DS_COUNT] = do_ds_count_initial_value;
2010-09-04 09:44:01 +00:00
do_ptr[NR_DO_PW_STATUS] = do_pw_status_bytes_template;
2010-09-05 09:10:54 +00:00
p_start = flash_do_pool ();
/* Traverse DO pool */
p = p_start;
while (*p != 0xff)
{
uint8_t nr = *p++;
uint8_t check = *p++;
if (check == 0xff)
do_ptr[nr] = p;
if (*p < 128)
len = *p++;
else if (*p == 0x81)
{
p++;
len = *p++;
}
else /* 0x82 */
{
p++;
len = (*p << 8) + *(p+1);
p += 2;
}
p += len;
if (((uint32_t)p & 1))
p++;
}
flash_set_do_pool_last (p);
2010-09-09 08:50:34 +00:00
num_prv_keys = 0;
if (do_ptr[NR_DO_PRVKEY_SIG] != NULL)
num_prv_keys++;
if (do_ptr[NR_DO_PRVKEY_DEC] != NULL)
num_prv_keys++;
if (do_ptr[NR_DO_PRVKEY_AUT] != NULL)
num_prv_keys++;
2010-09-13 02:47:21 +00:00
data_objects_number_of_bytes = 0;
for (i = 0; i < NR_DO_LAST; i++)
if (do_ptr[i] != NULL)
data_objects_number_of_bytes += *do_ptr[i];
2010-08-26 10:50:06 +00:00
return 0;
}
2010-09-04 09:44:01 +00:00
static const struct do_table_entry *
2010-08-26 10:50:06 +00:00
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;
2010-11-03 04:47:28 +00:00
else if (do_data[0] == 0x81)
2010-08-26 10:50:06 +00:00
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++;
}
2010-11-03 04:47:28 +00:00
else if (do_data[0] == 0x81)
2010-08-26 10:50:06 +00:00
{
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
2010-09-04 09:44:01 +00:00
copy_do (const struct do_table_entry *do_p)
2010-08-26 10:50:06 +00:00
{
if (do_p == NULL)
return 0;
2010-09-03 15:42:36 +00:00
if (!ac_check_status (do_p->ac_read))
2010-08-26 10:50:06 +00:00
return -1;
switch (do_p->do_type)
{
case DO_FIXED:
{
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;
}
2010-09-04 09:44:01 +00:00
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;
}
2010-08-26 10:50:06 +00:00
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;
2010-09-04 09:44:01 +00:00
const struct do_table_entry *do0_p;
2010-08-26 10:50:06 +00:00
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:
{
2010-09-03 15:42:36 +00:00
int (*do_func)(uint16_t) = (int (*)(uint16_t))do_p->obj;
2010-08-26 10:50:06 +00:00
2010-09-03 15:42:36 +00:00
return do_func (do_p->tag);
2010-08-26 10:50:06 +00:00
}
2010-08-30 11:02:22 +00:00
case DO_PROC_READWRITE:
{
2010-09-03 15:42:36 +00:00
int (*rw_func)(uint16_t, uint8_t *, int, int)
= (int (*)(uint16_t, uint8_t *, int, int))do_p->obj;
2010-08-30 11:02:22 +00:00
2010-09-03 15:42:36 +00:00
return rw_func (do_p->tag, NULL, 0, 0);
2010-08-30 11:02:22 +00:00
}
2010-08-26 10:50:06 +00:00
case DO_PROC_WRITE:
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)
{
2010-09-04 09:44:01 +00:00
const struct do_table_entry *do_p = get_do_entry (tag);
2010-08-26 10:50:06 +00:00
res_p = res_APDU;
with_tag = 0;
2010-09-03 15:42:36 +00:00
DEBUG_INFO (" ");
DEBUG_SHORT (tag);
2010-08-26 10:50:06 +00:00
if (do_p)
{
if (copy_do (do_p) < 0)
2010-09-03 15:42:36 +00:00
/* Overwriting partially written result */
GPG_SECURITY_FAILURE ();
2010-08-26 10:50:06 +00:00
else
{
*res_p++ = 0x90;
*res_p++ = 0x00;
res_APDU_size = res_p - res_APDU;
}
}
else
2010-09-03 15:42:36 +00:00
GPG_NO_RECORD();
2010-08-26 10:50:06 +00:00
}
void
2010-09-03 15:42:36 +00:00
gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
2010-08-26 10:50:06 +00:00
{
2010-09-04 09:44:01 +00:00
const struct do_table_entry *do_p = get_do_entry (tag);
2010-08-26 10:50:06 +00:00
2010-09-03 15:42:36 +00:00
DEBUG_INFO (" ");
DEBUG_SHORT (tag);
2010-08-26 10:50:06 +00:00
if (do_p)
{
2010-09-03 15:42:36 +00:00
if (!ac_check_status (do_p->ac_write))
2010-08-26 10:50:06 +00:00
{
2010-09-03 15:42:36 +00:00
GPG_SECURITY_FAILURE ();
2010-08-26 10:50:06 +00:00
return;
}
switch (do_p->do_type)
{
case DO_FIXED:
case DO_CN_READ:
case DO_PROC_READ:
2010-09-03 15:42:36 +00:00
GPG_SECURITY_FAILURE ();
2010-08-26 10:50:06 +00:00
break;
case DO_VAR:
{
2010-09-04 09:44:01 +00:00
const uint8_t **do_data_p = (const uint8_t **)do_p->obj;
2010-08-26 10:50:06 +00:00
2010-09-04 09:44:01 +00:00
if (*do_data_p)
flash_do_release (*do_data_p);
2010-09-03 15:42:36 +00:00
2010-08-30 11:02:22 +00:00
if (len == 0)
/* make DO empty */
2010-09-04 09:44:01 +00:00
*do_data_p = NULL;
2010-08-26 10:50:06 +00:00
else
{
2010-09-05 09:10:54 +00:00
uint8_t nr = do_tag_to_nr (tag);
*do_data_p = flash_do_write (nr, data, len);
2010-09-04 09:44:01 +00:00
if (*do_data_p)
2010-09-03 15:42:36 +00:00
GPG_SUCCESS ();
2010-08-26 10:50:06 +00:00
else
2010-09-03 15:42:36 +00:00
GPG_MEMORY_FAILURE();
2010-08-26 10:50:06 +00:00
}
2010-08-30 11:02:22 +00:00
break;
}
case DO_PROC_READWRITE:
{
2010-09-03 15:42:36 +00:00
int (*rw_func)(uint16_t, const uint8_t *, int, int)
= (int (*)(uint16_t, const uint8_t *, int, int))do_p->obj;
2010-08-26 10:50:06 +00:00
2010-08-30 11:02:22 +00:00
rw_func (tag, data, len, 1);
2010-08-26 10:50:06 +00:00
break;
}
case DO_PROC_WRITE:
{
2010-09-03 15:42:36 +00:00
void (*proc_func)(const uint8_t *, int)
= (void (*)(const uint8_t *, int))do_p->obj;
2010-08-26 10:50:06 +00:00
2010-09-03 15:42:36 +00:00
proc_func (data, len);
2010-08-26 10:50:06 +00:00
break;
}
}
}
else
2010-09-03 15:42:36 +00:00
GPG_NO_RECORD();
}
void
gpg_do_public_key (uint8_t kk_byte)
{
2010-09-04 09:44:01 +00:00
const uint8_t *do_data;
2010-09-05 16:55:29 +00:00
const uint8_t *key_addr;
2010-09-03 15:42:36 +00:00
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("Public key\r\n");
2010-09-05 16:55:29 +00:00
DEBUG_BYTE (kk_byte);
2010-09-05 09:10:54 +00:00
2010-09-04 09:44:01 +00:00
if (kk_byte == 0xb6)
do_data = do_ptr[NR_DO_PRVKEY_SIG];
2010-09-03 15:42:36 +00:00
else if (kk_byte == 0xb8)
2010-09-04 09:44:01 +00:00
do_data = do_ptr[NR_DO_PRVKEY_DEC];
else /* 0xa4 */
do_data = do_ptr[NR_DO_PRVKEY_AUT];
if (do_data == NULL)
2010-09-03 15:42:36 +00:00
{
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("none.\r\n");
2010-09-03 15:42:36 +00:00
GPG_NO_RECORD();
return;
}
2010-09-05 16:55:29 +00:00
key_addr = *(const uint8_t **)&do_data[1];
2010-09-03 15:42:36 +00:00
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;
}
2010-09-05 09:10:54 +00:00
DEBUG_INFO ("done.\r\n");
2010-09-03 15:42:36 +00:00
return;
}
const uint8_t *
2010-09-05 09:10:54 +00:00
gpg_do_read_simple (uint8_t nr)
2010-09-03 15:42:36 +00:00
{
const uint8_t *do_data;
2010-09-05 09:10:54 +00:00
do_data = do_ptr[nr];
2010-09-03 15:42:36 +00:00
if (do_data == NULL)
return NULL;
2010-09-04 04:48:26 +00:00
if (do_data[0] < 128)
return do_data+1;
else if (do_data[0] == 0x81)
return do_data+2;
else /* 0x82 */
return do_data+3;
2010-09-03 15:42:36 +00:00
}
void
2010-09-05 09:10:54 +00:00
gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
2010-09-03 15:42:36 +00:00
{
2010-09-04 09:44:01 +00:00
const uint8_t **do_data_p;
2010-09-03 15:42:36 +00:00
2010-09-05 09:10:54 +00:00
do_data_p = (const uint8_t **)&do_ptr[nr];
2010-09-04 09:44:01 +00:00
if (*do_data_p)
flash_do_release (*do_data_p);
2010-09-03 15:42:36 +00:00
2010-09-09 08:50:34 +00:00
if (data != NULL)
{
*do_data_p = flash_do_write (nr, data, size);
if (*do_data_p)
GPG_SUCCESS ();
else
GPG_MEMORY_FAILURE();
}
2010-09-03 15:42:36 +00:00
else
2010-09-09 08:50:34 +00:00
{
*do_data_p = NULL;
GPG_SUCCESS ();
}
2010-09-03 15:42:36 +00:00
}
void
gpg_do_increment_digital_signature_counter (void)
{
const uint8_t *do_data;
uint32_t count;
uint8_t count_data[SIZE_DIGITAL_SIGNATURE_COUNTER];
2010-09-04 09:44:01 +00:00
do_data = do_ptr[NR_DO_DS_COUNT];
2010-09-03 15:42:36 +00:00
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;
2010-09-09 08:50:34 +00:00
flash_do_release (do_data);
2010-09-05 09:10:54 +00:00
do_ptr[NR_DO_DS_COUNT] = flash_do_write (NR_DO_DS_COUNT, count_data,
2010-09-04 09:44:01 +00:00
SIZE_DIGITAL_SIGNATURE_COUNTER);
}
void
gpg_do_reset_pw_counter (uint8_t which)
{
uint8_t pwsb[SIZE_PW_STATUS_BYTES];
const uint8_t *do_data = do_ptr[NR_DO_PW_STATUS];
/* Reset PW1/RC/PW3 counter in GNUK_DO_PW_STATUS */
if (do_data)
{
memcpy (pwsb, &do_data[1], SIZE_PW_STATUS_BYTES);
2010-09-05 16:55:29 +00:00
if (pwsb[which] == 3)
return;
2010-09-04 09:44:01 +00:00
pwsb[which] = 3;
flash_do_release (do_data);
}
else
{
memcpy (pwsb, PW_STATUS_BYTES_TEMPLATE, SIZE_PW_STATUS_BYTES);
2010-09-05 16:55:29 +00:00
if (pwsb[which] == 3)
return;
2010-09-04 09:44:01 +00:00
pwsb[which] = 3;
}
2010-09-05 09:10:54 +00:00
gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES);
2010-08-26 10:50:06 +00:00
}