From 38e05331568d948cf4a468239e899d75bd3be39e Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Sun, 5 Sep 2010 18:10:54 +0900 Subject: [PATCH] works again --- README | 138 +++++++++++++++++++---- src/Makefile | 7 +- src/ac.c | 22 ++-- src/call-rsa.c | 164 +++++++++++++++++++++++++++ src/chconf.h | 4 +- src/crypt.mk | 2 +- src/debug.c | 14 +++ src/flash.c | 282 ++++++++++++++++++++++++++++++++++++++++------- src/gnuk.h | 57 +++++++--- src/gnuk.ld | 20 +++- src/main.c | 10 +- src/openpgp-do.c | 228 +++++++++++++++++++++++++------------- src/openpgp.c | 125 ++++++++++++++++----- src/openpgp.h | 1 + src/rsa-sign.c | 84 -------------- src/usb-icc.c | 2 + src/usb_desc.c | 6 +- 17 files changed, 871 insertions(+), 295 deletions(-) create mode 100644 src/call-rsa.c delete mode 100644 src/rsa-sign.c diff --git a/README b/README index 603a15f..035376b 100644 --- a/README +++ b/README @@ -1,33 +1,49 @@ -Gnuk - A USB Token software implementation +Gnuk - software for GPG USB Token - Version 0.0 2010-09-01 + Version 0.0 2010-09-05 Niibe Yutaka What's Gnuk =========== -Gnuk is a USB token software implementation to use with GNU privacy -guard. Gnuk supports OpenPGP card protocol version 2, and it runs on -Olimex STM32-H103 board. +Gnuk is software implementation of a USB token for GNU privacy guard. +Gnuk supports OpenPGP card protocol version 2, and it runs on STM32 +processor. Release notes ============= -Initially, the development was started with a copy of the files in -ChibiOS_2.0.2/demos/ARMCM3-STM32F103-GCC/*, Makefile, linker script, -and header files (chconf.h, halconf.h, and mcuconf.h). +This is initial release of Gnuk, and it is experimental yet. +It is not yet daily use. -Since this is the initial release, some garbages still remain. +Supported and tested features are: + + * Personalization of the card + + * Changing Login name, URL, Name, Sex, Language, etc. + + * Password handling (PW1, RC, PW3) + + * Single key import + + * PSO: Digital Signature -Target -====== +It is known not-working: + + * Multiple key import + + * PSO: Decipher + + +Targets +======= We use Olimex STM32-H103 board. -I think that it runs on Olimex STM32-P103 too. We are porting to -STM32 Primer 2. +I think that it runs on Olimex STM32-P103, STBee, or STBee mini too. +Besides, we are porting it to STM32 Primer 2. Souce code @@ -49,35 +65,46 @@ External source code Gnuk is distributed with external source code. * ChibiOS_2.0.2/ -- ChibiOS/RT 2.0.2 -Taken from http://chibios.sourceforge.net/ -Note that CRLF is converted to LF in this repository. -We use ChibiOS/RT as the kernel for Gnuk. + + Taken from http://chibios.sourceforge.net/ + Note that CRLF is converted to LF in this repository. + We use ChibiOS/RT as the kernel for Gnuk. * polarssl-0.14.0/ -- PolarSSL 0.14.0 -Taken from http://polarssl.org/ -We use PolarSSL for RSA computation. + Taken from http://polarssl.org/ + We use PolarSSL for RSA computation. * STM32_USB-FS-Device_Driver/ -- a part of USB-FS-Device_Lib * Virtual_COM_Port/ -- a part of USB-FS-Device_Lib -STM32F10x USB Full Speed Device Library (USB-FS-Device_Lib) -is a STM32F10x library for USB functionality. + STM32F10x USB Full Speed Device Library (USB-FS-Device_Lib) + is a STM32F10x library for USB functionality. -I took Libraries/STM32_USB-FS-Device_Driver and a part of -Project/ in STM32_USB-FS-Device_Lib distribution. -See http://www.st.com for detail. + I took Libraries/STM32_USB-FS-Device_Driver and a part of + Project/ in STM32_USB-FS-Device_Lib distribution. + See http://www.st.com for detail. How to compile ============== -You need GNU Toolchain and newlib for 'arm-none-eabi' target. +You need GNU toolchain and newlib for 'arm-none-eabi' target. See http://github.com/esden/summon-arm-toolchain/ for preparation of GNU Toolchain for 'arm-none-eabi' target. $ cd gnuk-VERSION/src + +Edit the Makefile. Comment out the line: +---------------- +ENABLE_DEBUG=1 +---------------- + +if you don't want to debug Gnuk. + +Type: + $ make Then, we will have "gnuk.elf". @@ -99,6 +126,54 @@ Then, with another terminal, type following to write "gnuk.elf" to Flash ROM: > exit $ +If you compiled with ENABLE_DEBUG=1, Gnuk has two interfaces +(one is CCID/ICCD device and another is virtual COM port). Open +virtual COM port by: + + $ cu -l /dev/ttyACM0 + +and you will see debug output of Gnuk. + + +For libccid, we need following change: + +--- /etc/libccid_Info.plist.dpkg-dist 2009-07-29 06:50:20.000000000 +0900 ++++ /etc/libccid_Info.plist 2010-09-05 09:09:49.000000000 +0900 +@@ -104,6 +104,7 @@ + + ifdVendorID + ++ 0x234B + 0x08E6 + 0x08E6 + 0x08E6 +@@ -237,6 +238,7 @@ + + ifdProductID + ++ 0x0000 + 0x2202 + 0x3437 + 0x3438 +@@ -370,6 +372,7 @@ + + ifdFriendlyName + ++ FSIJ USB Token + Gemplus Gem e-Seal Pro + Gemplus GemPC Twin + Gemplus GemPC Key +------------------ + + +Then, try following to see Gnuk runs: + + $ gpg --card-status + + +For more, see doc/HOWTO_GNUK. + + How to debug ============ @@ -107,4 +182,19 @@ We can use GDB. $ arm-none-eabi-gdb gnuk.elf + +Inside GDB, we can connect OpenOCD by: + + (gdb) target remote localhost:3333 + + + +Development history +=================== + +Initially, the development was started with a copy of the files in +ChibiOS_2.0.2/demos/ARMCM3-STM32F103-GCC/*, Makefile, linker script, +and header files (chconf.h, halconf.h, and mcuconf.h). + +Since this is the initial release, some garbages may still remain. -- diff --git a/src/Makefile b/src/Makefile index e394a36..ce44b19 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,5 @@ # Makefile for Gnuk -# # ENABLE_DEBUG=1 @@ -88,10 +87,14 @@ CSRC = $(PORTSRC) \ $(STMUSBSRC) \ $(VCOMSRC) \ $(CRYPTSRC) \ - main.c debug.c usb_lld.c \ + main.c usb_lld.c \ hw_config.c usb_desc.c usb_prop.c \ usb-icc.c openpgp.c ac.c openpgp-do.c flash.c hardclock.c random.c +ifneq ($(ENABLE_DEBUG),) +CSRC += debug.c +endif + # List ASM source files here ASMSRC = $(PORTASM) \ $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/vectors.s diff --git a/src/ac.c b/src/ac.c index 3828133..f387768 100644 --- a/src/ac.c +++ b/src/ac.c @@ -26,7 +26,7 @@ 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); + const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); uint8_t keystring[KEYSTRING_SIZE_PW1]; uint8_t pwsb[SIZE_PW_STATUS_BYTES]; @@ -40,13 +40,13 @@ verify_pso_cds (const uint8_t *pw, int pw_len) 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); + gpg_do_write_simple (NR_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); + gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); } auth_status |= AC_PSO_CDS_AUTHORIZED; @@ -63,7 +63,7 @@ int 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); + const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); uint8_t keystring[KEYSTRING_SIZE_PW1]; uint8_t pwsb[SIZE_PW_STATUS_BYTES]; @@ -77,13 +77,13 @@ verify_pso_other (const uint8_t *pw, int pw_len) 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); + gpg_do_write_simple (NR_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); + gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); } auth_status |= AC_PSO_OTHER_AUTHORIZED; @@ -131,14 +131,14 @@ 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); + const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_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); + pw3_keystring = gpg_do_read_simple (NR_DO_KEYSTRING_PW3); if (pw3_keystring != NULL) { int count; @@ -159,13 +159,13 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) { failure: pwsb[PW_STATUS_PW3]--; - gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + gpg_do_write_simple (NR_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); + gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); } } else @@ -196,7 +196,7 @@ gpg_set_pw3 (const uint8_t *newpw, int newpw_len) 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); + gpg_do_write_simple (NR_DO_KEYSTRING_PW3, ks, KEYSTRING_SIZE_PW3); } uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE]; diff --git a/src/call-rsa.c b/src/call-rsa.c new file mode 100644 index 0000000..88a189e --- /dev/null +++ b/src/call-rsa.c @@ -0,0 +1,164 @@ +/* + * call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol + * + * Copyright (C) 2010 Free Software Initiative of Japan + * Author: NIIBE Yutaka + * + * 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 . + * + */ + +#include "config.h" +#include "ch.h" +#include "gnuk.h" +#include "polarssl/config.h" +#include "polarssl/rsa.h" + +static rsa_context rsa_ctx; + +int +rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len) +{ + mpi P1, Q1, H; + int r; + + mpi_init (&P1, &Q1, &H, NULL); + rsa_init (&rsa_ctx, RSA_PKCS_V15, 0); + + rsa_ctx.len = 2048 / 8; + mpi_read_string (&rsa_ctx.E, 16, "10001"); + mpi_read_binary (&rsa_ctx.P, &kd.data[0], rsa_ctx.len / 2); + mpi_read_binary (&rsa_ctx.Q, &kd.data[128], rsa_ctx.len / 2); + mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q); + mpi_sub_int (&P1, &rsa_ctx.P, 1); + mpi_sub_int (&Q1, &rsa_ctx.Q, 1); + mpi_mul_mpi (&H, &P1, &Q1); + mpi_inv_mod (&rsa_ctx.D , &rsa_ctx.E, &H); + mpi_mod_mpi (&rsa_ctx.DP, &rsa_ctx.D, &P1); + mpi_mod_mpi (&rsa_ctx.DQ, &rsa_ctx.D, &Q1); + mpi_inv_mod (&rsa_ctx.QP, &rsa_ctx.Q, &rsa_ctx.P); + mpi_free (&P1, &Q1, &H, NULL); + + DEBUG_INFO ("RSA..."); + + if ((r = rsa_check_privkey (&rsa_ctx)) == 0) + DEBUG_INFO ("ok..."); + else + { + DEBUG_INFO ("failed.\r\n"); + DEBUG_SHORT (r); + rsa_free (&rsa_ctx); + return r; + } + + r = rsa_pkcs1_sign (&rsa_ctx, RSA_PRIVATE, SIG_RSA_RAW, + msg_len, raw_message, output); + rsa_free (&rsa_ctx); + if (r < 0) + { + DEBUG_INFO ("fail:"); + DEBUG_SHORT (r); + return r; + } + else + { + DEBUG_INFO ("done.\r\n"); + 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); +} + +int +rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len) +{ + mpi P1, Q1, H; + int r; + int output_len; + + mpi_init (&P1, &Q1, &H, NULL); + rsa_init (&rsa_ctx, RSA_PKCS_V15, 0); + + rsa_ctx.len = msg_len; + mpi_read_string (&rsa_ctx.E, 16, "10001"); + mpi_read_binary (&rsa_ctx.P, &kd.data[0], 2048 / 8 / 2); + mpi_read_binary (&rsa_ctx.Q, &kd.data[128], 2048 / 8 / 2); + mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q); + mpi_sub_int (&P1, &rsa_ctx.P, 1); + mpi_sub_int (&Q1, &rsa_ctx.Q, 1); + mpi_mul_mpi (&H, &P1, &Q1); + mpi_inv_mod (&rsa_ctx.D , &rsa_ctx.E, &H); + mpi_mod_mpi (&rsa_ctx.DP, &rsa_ctx.D, &P1); + mpi_mod_mpi (&rsa_ctx.DQ, &rsa_ctx.D, &Q1); + mpi_inv_mod (&rsa_ctx.QP, &rsa_ctx.Q, &rsa_ctx.P); + mpi_free (&P1, &Q1, &H, NULL); + + DEBUG_INFO ("RSA..."); + + if ((r = rsa_check_privkey (&rsa_ctx)) == 0) + DEBUG_INFO ("ok..."); + else + { + DEBUG_INFO ("failed.\r\n"); + DEBUG_SHORT (r); + rsa_free (&rsa_ctx); + return r; + } + + r = rsa_pkcs1_decrypt (&rsa_ctx, RSA_PRIVATE, &output_len, + input, output, MAX_RES_APDU_SIZE - 2); + rsa_free (&rsa_ctx); + if (r < 0) + { + DEBUG_INFO ("fail:"); + DEBUG_SHORT (r); + return r; + } + else + { + res_APDU[output_len] = 0x90; + res_APDU[output_len+1] = 0x00; + res_APDU_size = output_len + 2; + + DEBUG_INFO ("done.\r\n"); + return 0; + } +} diff --git a/src/chconf.h b/src/chconf.h index 543634b..dadce7e 100644 --- a/src/chconf.h +++ b/src/chconf.h @@ -18,14 +18,14 @@ #define CH_USE_CONDVARS_TIMEOUT TRUE #define CH_USE_EVENTS TRUE /* We use this! */ #define CH_USE_EVENTS_TIMEOUT TRUE /* We use this! */ -#define CH_USE_MESSAGES TRUE +#define CH_USE_MESSAGES FALSE #define CH_USE_MESSAGES_PRIORITY FALSE #define CH_USE_MAILBOXES FALSE #define CH_USE_QUEUES FALSE #define CH_USE_MEMCORE TRUE #define CH_USE_HEAP TRUE #define CH_USE_MALLOC_HEAP FALSE -#define CH_USE_MEMPOOLS TRUE +#define CH_USE_MEMPOOLS FALSE #define CH_USE_DYNAMIC FALSE /* Debug options */ diff --git a/src/crypt.mk b/src/crypt.mk index 0304fdc..f0b7ea5 100644 --- a/src/crypt.mk +++ b/src/crypt.mk @@ -3,4 +3,4 @@ CRYPTSRCDIR = $(CRYPTDIR)/library CRYPTINCDIR = $(CRYPTDIR)/include CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/sha1.c \ $(CRYPTSRCDIR)/aes.c \ - rsa-sign.c + call-rsa.c diff --git a/src/debug.c b/src/debug.c index 0002593..c295320 100644 --- a/src/debug.c +++ b/src/debug.c @@ -64,6 +64,20 @@ put_short (uint16_t x) _write ("\r\n", 2); } +void +put_word (uint32_t x) +{ + put_hex (x >> 28); + put_hex ((x >> 24)&0x0f); + put_hex ((x >> 20)&0x0f); + put_hex ((x >> 16)&0x0f); + put_hex ((x >> 12)&0x0f); + put_hex ((x >> 8)&0x0f); + put_hex ((x >> 4)&0x0f); + put_hex (x & 0x0f); + _write ("\r\n", 2); +} + void put_binary (const char *s, int len) { diff --git a/src/flash.c b/src/flash.c index f94843a..b99914d 100644 --- a/src/flash.c +++ b/src/flash.c @@ -22,90 +22,288 @@ */ /* - * Writing to Flash ROM is NOT YET IMPLEMENTED, just API only + * Note: Garbage collection and page management with flash erase + * is *NOT YET* implemented */ #include "config.h" #include "ch.h" +#include "hal.h" #include "gnuk.h" -static uint8_t do_pool[256]; -static uint8_t *last_p = do_pool; +#define FLASH_KEY1 0x45670123UL +#define FLASH_KEY2 0xCDEF89ABUL + +enum flash_status +{ + FLASH_BUSY = 1, + FLASH_ERROR_PG, + FLASH_ERROR_WRP, + FLASH_COMPLETE, + FLASH_TIMEOUT +}; + +static void +flash_unlock (void) +{ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; +} + +static int +flash_get_status (void) +{ + int status; + + if ((FLASH->SR & FLASH_SR_BSY) != 0) + status = FLASH_BUSY; + else if ((FLASH->SR & FLASH_SR_PGERR) != 0) + status = FLASH_ERROR_PG; + else if((FLASH->SR & FLASH_SR_WRPRTERR) != 0 ) + status = FLASH_ERROR_WRP; + else + status = FLASH_COMPLETE; + + return status; +} + +static int +flash_wait_for_last_operation (uint32_t timeout) +{ + int status; + + do + if (--timeout == 0) + return FLASH_TIMEOUT; + else + status = flash_get_status (); + while (status == FLASH_BUSY); + + return status; +} + +#define FLASH_PROGRAM_TIMEOUT 0x10000 + +static int +flash_program_halfword (uint32_t addr, uint16_t data) +{ + int status; + + status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); + + chSysLock (); + if (status == FLASH_COMPLETE) + { + FLASH->CR |= FLASH_CR_PG; + + *(volatile uint16_t *)addr = data; + + status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); + if (status != FLASH_TIMEOUT) + FLASH->CR &= ~FLASH_CR_PG; + } + chSysUnlock (); + + return status; +} /* - * TLV (Tag, Length, and Value) + * Flash memory map + * + * _text + * .text + * .ctors + * .dtors + * _etext + * .data + * ... + * _etext + (_edata - _data) + * + * 1-KiB align padding + * + * 1-KiB DO pool * 3 + * + * 3-KiB Key store (512-byte (p, q and N) key-store * 6) */ + +static const uint8_t *do_pool; +static const uint8_t *keystore_pool; + +static const uint8_t *last_p; +static const uint8_t *keystore; + +const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = { + 0xff, 0xff, 0xff, 0xff +}; + +void +flash_init (void) +{ + const uint8_t *p; + extern uint8_t _do_pool; + extern uint8_t _keystore_pool; + + do_pool = &_do_pool; + keystore_pool = &_keystore_pool; + + /* Seek empty keystore */ + p = keystore_pool; + while (*p != 0xff || *(p+1) != 0xff) + p += 512; + + keystore = p; + + flash_unlock (); +} + const uint8_t * -flash_do_write (uint16_t tag, const uint8_t *data, int len) +flash_do_pool (void) +{ + return do_pool; +} + +void +flash_set_do_pool_last (const uint8_t *p) +{ + last_p = p; +} + +const uint8_t * +flash_do_write (uint8_t nr, const uint8_t *data, int len) { const uint8_t *p = last_p; + uint16_t hw; + uint32_t addr; + int state = 0; + int i; - if (last_p - do_pool + len + 2 + 3 > 1024) + if (last_p - do_pool + len + 2 + 3 > 1024*3) return NULL; - *last_p++ = (tag >> 8); - *last_p++ = (tag & 0xff); + DEBUG_INFO ("flash DO\r\n"); + + addr = (uint32_t)last_p; + hw = nr | (0xff << 8); + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return NULL; + addr += 2; + if (len < 128) - *last_p++ = len; + { + hw = len; + state = 1; + } else if (len < 256) { - *last_p++ = 0x81; - *last_p++ = len; + hw = 0x81 | (len << 8); + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return NULL; + addr += 2; + state = 0; } else { - *last_p++ = 0x82; - *last_p++ = (len >> 8); - *last_p++ = (len & 0xff); + hw = 0x82 | ((len >> 8) << 8); + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return NULL; + addr += 2; + hw = (len & 0xff); + state = 1; } - memcpy (last_p, data, len); - last_p += len; + if (state == 0) + { + for (i = 0; i < len/2; i ++) + { + hw = data[i*2] | (data[i*2+1]<<8); + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return NULL; + addr += 2; + } + + if ((len & 1)) + { + hw = data[i*2] | 0xff00; + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return NULL; + addr += 2; + } + } + else + { + hw |= data[0]<<8; + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return NULL; + addr += 2; + + for (i = 0; i < (len - 1)/2; i ++) + { + hw = data[i*2+1] | (data[i*2+2]<<8); + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return NULL; + addr += 2; + } + + if (((len - 1) & 1)) + { + hw = data[i*2+1] | 0xff00; + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return NULL; + addr += 2; + } + } + + last_p = (const uint8_t *)addr; + + DEBUG_INFO ("flash DO...done\r\n"); return p + 2; } void -flash_do_release (const uint8_t *data) +flash_do_release (const uint8_t *data_p) { - (void)data;/*XXX*/ + (void)data_p; } -static uint8_t k1[KEY_CONTENT_LEN*2]; /* p, q and N */ -#if 0 -static uint8_t k2[KEY_CONTENT_LEN*2]; -static uint8_t k3[KEY_CONTENT_LEN*2]; -#endif - uint8_t * -flash_key_alloc (enum kind_of_key kk) +flash_key_alloc (void) { - switch (kk) - { - case GPG_KEY_FOR_SIGNATURE: - return k1; -#if 0 - case GPG_KEY_FOR_DECRYPT: - return k2; - case GPG_KEY_FOR_AUTHENTICATION: - return k3; -#else - default: - return k1; -#endif - } + uint8_t *k = (uint8_t *)keystore; + + keystore += 512; + return k; } int 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); + uint16_t hw; + uint32_t addr; + int i; + + addr = (uint32_t)key_addr; + for (i = 0; i < KEY_CONTENT_LEN/2; i ++) + { + hw = key_data[i*2] | (key_data[i*2+1]<<8); + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return -1; + addr += 2; + } + + for (i = 0; i < KEY_CONTENT_LEN/2; i ++) + { + hw = modulus[i*2] | (modulus[i*2+1]<<8); + if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + return -1; + addr += 2; + } + return 0; } void flash_key_release (const uint8_t *key_addr) { - (void)key_addr; /*XXX*/ + (void)key_addr; } diff --git a/src/gnuk.h b/src/gnuk.h index 036d090..2db6f79 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -3,11 +3,16 @@ extern Thread *blinker_thread; 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_word (uint32_t x); extern void put_string (const char *s); extern void put_binary (const char *s, int len); extern void _write (const char *, int); +/* + * We declare some of libc functions here, because we will + * remove dependency on libc in future. + */ 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); @@ -68,10 +73,13 @@ enum kind_of_key { GPG_KEY_FOR_AUTHENTICATION, }; +extern void flash_init (void); 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 const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len); +extern uint8_t *flash_key_alloc (void); extern void flash_key_release (const uint8_t *); +extern const uint8_t *flash_do_pool (void); +extern void flash_set_do_pool_last (const uint8_t *p); #define KEY_MAGIC_LEN 8 #define KEY_CONTENT_LEN 256 /* p and q */ @@ -118,11 +126,13 @@ extern struct key_data kd; #ifdef DEBUG #define DEBUG_INFO(msg) put_string (msg) +#define DEBUG_WORD(w) put_word (w) #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_WORD(w) #define DEBUG_SHORT(h) #define DEBUG_BYTE(b) #define DEBUG_BINARY(s,len) @@ -131,11 +141,12 @@ extern struct key_data kd; 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 rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len); -extern int gpg_do_write_privkey (enum kind_of_key kk, const uint8_t *key_data, int key_len); +extern int gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, const uint8_t *keystring); -extern const uint8_t *gpg_do_read_simple (uint16_t); -extern void gpg_do_write_simple (uint16_t, const uint8_t *, int); +extern const uint8_t *gpg_do_read_simple (uint8_t); +extern void gpg_do_write_simple (uint8_t, const uint8_t *, int); extern void gpg_do_increment_digital_signature_counter (void); #define PW_STATUS_PW1 4 @@ -144,21 +155,37 @@ extern void gpg_do_increment_digital_signature_counter (void); extern void gpg_set_pw3 (const uint8_t *newpw, int newpw_len); -extern void fatal (void); +extern void fatal (void) __attribute__ ((noreturn)); 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 NR_DO_PRVKEY_SIG 0 +#define NR_DO_PRVKEY_DEC 1 +#define NR_DO_PRVKEY_AUT 2 +#define NR_DO_KEYSTRING_PW1 3 +#define NR_DO_KEYSTRING_RC 4 +#define NR_DO_KEYSTRING_PW3 5 +#define NR_DO_PW_STATUS 6 +#define NR_DO_DS_COUNT 7 +#define NR_DO_SEX 8 +#define NR_DO_FP_SIG 9 +#define NR_DO_FP_DEC 10 +#define NR_DO_FP_AUT 11 +#define NR_DO_CAFP_1 12 +#define NR_DO_CAFP_2 13 +#define NR_DO_CAFP_3 14 +#define NR_DO_KGTIME_SIG 15 +#define NR_DO_KGTIME_DEC 16 +#define NR_DO_KGTIME_AUT 17 +#define NR_DO_LOGIN_DATA 18 +#define NR_DO_URL 19 +#define NR_DO_NAME 20 +#define NR_DO_LANGUAGE 21 +#define NR_DO_CH_CERTIFICATE 22 + #define SIZE_PW_STATUS_BYTES 7 -/* 16-byte random bytes */ -extern uint8_t *get_data_encryption_key (void); +extern uint8_t *get_data_encryption_key (void); /* 16-byte random bytes */ extern void dek_free (uint8_t *); extern uint32_t get_random (void); extern void random_init (void); diff --git a/src/gnuk.ld b/src/gnuk.ld index d64ee32..0cfea61 100644 --- a/src/gnuk.ld +++ b/src/gnuk.ld @@ -110,11 +110,23 @@ SECTIONS *(COMMON) . = ALIGN(4); _bss_end = .; - } > ram -} + } > ram -PROVIDE(end = .); -_end = .; + PROVIDE(end = .); + _end = .; + + .gnuk_flash : ALIGN (1024) + { + _do_pool = .; + KEEP(*(.gnuk_data)) + FILL(0xffffffff); + . = ALIGN(1024); + . += 1024*2; + _keystore_pool = .; + FILL(0xffffffff); + . += 1024*3; + } > flash +} __heap_base__ = _end; __heap_end__ = __ram_end__ - __stacks_total_size__; diff --git a/src/main.c b/src/main.c index dbf253e..c0d42fc 100644 --- a/src/main.c +++ b/src/main.c @@ -173,12 +173,14 @@ main (int argc, char **argv) { eventmask_t m; int count = 0; + uint8_t once = 0; (void)argc; (void)argv; blinker_thread = chThdSelf (); + flash_init (); gpg_do_table_init (); usb_lld_init (); @@ -198,7 +200,8 @@ main (int argc, char **argv) while (1) { - uint8_t once = 0; + uint32_t r; + #if 0 if (palReadPad(IOPORT1, GPIOA_BUTTON)) palSetPad (IOPORT3, GPIOC_LED); @@ -212,14 +215,15 @@ main (int argc, char **argv) { random_init (); once = 1; + r = get_random (); + DEBUG_WORD (r); } if (bDeviceState == CONFIGURED && (count % 100) == 0) { - uint32_t r; r = get_random (); - DEBUG_SHORT (r); + DEBUG_WORD (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); diff --git a/src/openpgp-do.c b/src/openpgp-do.c index b97989a..eb68895 100644 --- a/src/openpgp-do.c +++ b/src/openpgp-do.c @@ -124,6 +124,13 @@ static int with_tag; static void copy_do_1 (uint16_t tag, const uint8_t *do_data); static const struct do_table_entry *get_do_entry (uint16_t tag); +#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 GPG_DO_AID 0x004f #define GPG_DO_NAME 0x005b #define GPG_DO_LOGIN_DATA 0x005e @@ -159,29 +166,62 @@ static const struct do_table_entry *get_do_entry (uint16_t tag); #define NUM_DO_OBJS 23 static const uint8_t *do_ptr[NUM_DO_OBJS]; -#define NR_DO_PRVKEY_SIG 0 -#define NR_DO_PRVKEY_DEC 1 -#define NR_DO_PRVKEY_AUT 2 -#define NR_DO_KEYSTRING_PW1 3 -#define NR_DO_KEYSTRING_RC 4 -#define NR_DO_KEYSTRING_PW3 5 -#define NR_DO_PW_STATUS 6 -#define NR_DO_DS_COUNT 7 -#define NR_DO_SEX 8 -#define NR_DO_FP_SIG 9 -#define NR_DO_FP_DEC 10 -#define NR_DO_FP_AUT 11 -#define NR_DO_CAFP_1 12 -#define NR_DO_CAFP_2 13 -#define NR_DO_CAFP_3 14 -#define NR_DO_KGTIME_SIG 15 -#define NR_DO_KGTIME_DEC 16 -#define NR_DO_KGTIME_AUT 17 -#define NR_DO_LOGIN_DATA 18 -#define NR_DO_URL 19 -#define NR_DO_NAME 20 -#define NR_DO_LANGUAGE 21 -#define NR_DO_CH_CERTIFICATE 22 + +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 (); + } +} static void copy_tag (uint16_t tag) @@ -218,21 +258,21 @@ do_fp_all (uint16_t tag) *res_p++ = SIZE_FP*3; } - data = gpg_do_read_simple (GPG_DO_FP_SIG); + data = gpg_do_read_simple (NR_DO_FP_SIG); if (data) memcpy (res_p, data, SIZE_FP); else memset (res_p, 0, SIZE_FP); res_p += SIZE_FP; - data = gpg_do_read_simple (GPG_DO_FP_DEC); + data = gpg_do_read_simple (NR_DO_FP_DEC); if (data) memcpy (res_p, data, SIZE_FP); else memset (res_p, 0, SIZE_FP); res_p += SIZE_FP; - data = gpg_do_read_simple (GPG_DO_FP_AUT); + data = gpg_do_read_simple (NR_DO_FP_AUT); if (data) memcpy (res_p, data, SIZE_FP); else @@ -253,21 +293,21 @@ do_cafp_all (uint16_t tag) *res_p++ = SIZE_FP*3; } - data = gpg_do_read_simple (GPG_DO_CAFP_1); + data = gpg_do_read_simple (NR_DO_CAFP_1); if (data) memcpy (res_p, data, SIZE_FP); else memset (res_p, 0, SIZE_FP); res_p += SIZE_FP; - data = gpg_do_read_simple (GPG_DO_CAFP_2); + data = gpg_do_read_simple (NR_DO_CAFP_2); if (data) memcpy (res_p, data, SIZE_FP); else memset (res_p, 0, SIZE_FP); res_p += SIZE_FP; - data = gpg_do_read_simple (GPG_DO_CAFP_2); + data = gpg_do_read_simple (NR_DO_CAFP_2); if (data) memcpy (res_p, data, SIZE_FP); else @@ -288,21 +328,21 @@ do_kgtime_all (uint16_t tag) *res_p++ = SIZE_KGTIME*3; } - data = gpg_do_read_simple (GPG_DO_KGTIME_SIG); + data = gpg_do_read_simple (NR_DO_KGTIME_SIG); if (data) memcpy (res_p, data, SIZE_KGTIME); else memset (res_p, 0, SIZE_KGTIME); res_p += SIZE_KGTIME; - data = gpg_do_read_simple (GPG_DO_KGTIME_DEC); + data = gpg_do_read_simple (NR_DO_KGTIME_DEC); if (data) memcpy (res_p, data, SIZE_KGTIME); else memset (res_p, 0, SIZE_KGTIME); res_p += SIZE_KGTIME; - data = gpg_do_read_simple (GPG_DO_KGTIME_AUT); + data = gpg_do_read_simple (NR_DO_KGTIME_AUT); if (data) memcpy (res_p, data, SIZE_KGTIME); else @@ -331,7 +371,7 @@ rw_pw_status (uint16_t tag, const uint8_t *data, int len, int is_write) pwsb[0] = data[0]; do_ptr[NR_DO_PW_STATUS] - = flash_do_write (tag, pwsb, SIZE_PW_STATUS_BYTES); + = flash_do_write (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); if (do_ptr[NR_DO_PW_STATUS]) GPG_SUCCESS (); else @@ -372,6 +412,8 @@ proc_resetting_code (const uint8_t *data, int len) int newpw_len; int r; + DEBUG_INFO ("Resetting Code!\r\n"); + newpw_len = len; newpw = data; sha1 (newpw, newpw_len, new_ks); @@ -379,18 +421,27 @@ proc_resetting_code (const uint8_t *data, int len) r = gpg_change_keystring (3, old_ks, 2, new_ks); if (r < -2) { + DEBUG_INFO ("memory error.\r\n"); GPG_MEMORY_FAILURE (); return; } else if (r < 0) { + DEBUG_INFO ("security error.\r\n"); GPG_SECURITY_FAILURE (); return; } else if (r == 0) - gpg_do_write_simple (GNUK_DO_KEYSTRING_RC, new_ks0, KEYSTRING_SIZE_RC); + { + DEBUG_INFO ("done (no prvkey).\r\n"); + gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KEYSTRING_SIZE_RC); + } else - GPG_SUCCESS (); + { + DEBUG_INFO ("done.\r\n"); + gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, 1); + GPG_SUCCESS (); + } /* Reset RC counter in GNUK_DO_PW_STATUS */ gpg_do_reset_pw_counter (PW_STATUS_RC); @@ -422,21 +473,6 @@ decrypt (const uint8_t *key_str, uint8_t *data, int len) DEBUG_BINARY (data, len); } -static uint16_t -get_tag_for_kk (enum kind_of_key kk) -{ - switch (kk) - { - case GPG_KEY_FOR_SIGNATURE: - return GNUK_DO_PRVKEY_SIG; - case GPG_KEY_FOR_DECRYPT: - return GNUK_DO_PRVKEY_DEC; - case GPG_KEY_FOR_AUTHENTICATION: - return GNUK_DO_PRVKEY_AUT; - } - return GNUK_DO_PRVKEY_SIG; -} - static uint8_t get_do_ptr_nr_for_kk (enum kind_of_key kk) { @@ -476,7 +512,10 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring) decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE); decrypt (dek, (uint8_t *)&kd, sizeof (struct key_data)); if (memcmp (kd.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0) - return -1; + { + DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n"); + return -1; + } /* XXX: more sanity check */ return 1; } @@ -498,7 +537,6 @@ int gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, const uint8_t *keystring) { - uint16_t tag = get_tag_for_kk (kk); uint8_t nr = get_do_ptr_nr_for_kk (kk); const uint8_t *p; int r; @@ -506,13 +544,14 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, struct prvkey_data *pd; uint8_t *key_addr; uint8_t *dek; - 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); + const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); + const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC); #if 0 assert (key_len == KEY_CONTENT_LEN); #endif + DEBUG_INFO ("Key import\r\n"); DEBUG_SHORT (key_len); pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data)); @@ -526,7 +565,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, return -1; } - key_addr = flash_key_alloc (kk); + DEBUG_INFO ("Getting keystore address...\r\n"); + key_addr = flash_key_alloc (); if (key_addr == NULL) { free (pd); @@ -534,6 +574,9 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, return -1; } + DEBUG_INFO ("key_addr: "); + DEBUG_WORD ((uint32_t)key_addr); + memcpy (kd.data, key_data, KEY_CONTENT_LEN); kd.check = calc_check32 (key_data, KEY_CONTENT_LEN); kd.random = get_random (); @@ -565,7 +608,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, 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); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, ks_pw1, 1); } else { @@ -576,7 +619,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, 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); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, ks123_pw1, 1); } if (ks_rc) @@ -584,7 +627,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, 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); + gpg_do_write_simple (NR_DO_KEYSTRING_RC, ks_rc, 1); } else memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE); @@ -592,7 +635,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, 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)); + p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); do_ptr[nr] = p; dek_free (dek); @@ -608,7 +651,6 @@ 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); uint8_t nr = get_do_ptr_nr_for_kk (kk); const uint8_t *do_data = do_ptr[nr]; uint8_t dek[DATA_ENCRYPTION_KEY_SIZE]; @@ -631,7 +673,7 @@ gpg_do_chks_prvkey (enum kind_of_key kk, 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)); + p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); do_ptr[nr] = p; free (pd); @@ -770,12 +812,48 @@ gpg_do_table[] = { #define NUM_DO_ENTRIES (int)(sizeof (gpg_do_table) / sizeof (struct do_table_entry)) /* - * Initialize GPG_DO_TABLE reading from Flash ROM + * Initialize DO_PTR reading from Flash ROM */ int gpg_do_table_init (void) { + const uint8_t *p, *p_start; + int len; + do_ptr[NR_DO_PW_STATUS] = do_pw_status_bytes_template; + 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); + return 0; } @@ -972,7 +1050,9 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len) *do_data_p = NULL; else { - *do_data_p = flash_do_write (tag, data, len); + uint8_t nr = do_tag_to_nr (tag); + + *do_data_p = flash_do_write (nr, data, len); if (*do_data_p) GPG_SUCCESS (); else @@ -1008,6 +1088,8 @@ gpg_do_public_key (uint8_t kk_byte) const uint8_t *do_data; uint8_t *key_addr; + DEBUG_INFO ("Public key\r\n"); + if (kk_byte == 0xb6) do_data = do_ptr[NR_DO_PRVKEY_SIG]; else if (kk_byte == 0xb8) @@ -1017,6 +1099,7 @@ gpg_do_public_key (uint8_t kk_byte) if (do_data == NULL) { + DEBUG_INFO ("none.\r\n"); GPG_NO_RECORD(); return; } @@ -1048,17 +1131,16 @@ gpg_do_public_key (uint8_t kk_byte) res_APDU_size = res_p - res_APDU; } + DEBUG_INFO ("done.\r\n"); return; } const uint8_t * -gpg_do_read_simple (uint16_t tag) +gpg_do_read_simple (uint8_t nr) { - const 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); + do_data = do_ptr[nr]; if (do_data == NULL) return NULL; @@ -1071,17 +1153,15 @@ gpg_do_read_simple (uint16_t tag) } void -gpg_do_write_simple (uint16_t tag, const uint8_t *data, int size) +gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size) { - const struct do_table_entry *do_p; const uint8_t **do_data_p; - do_p = get_do_entry (tag); - do_data_p = (const uint8_t **)do_p->obj; + do_data_p = (const uint8_t **)&do_ptr[nr]; if (*do_data_p) flash_do_release (*do_data_p); - *do_data_p = flash_do_write (tag, data, size); + *do_data_p = flash_do_write (nr, data, size); if (*do_data_p) GPG_SUCCESS (); else @@ -1106,7 +1186,7 @@ gpg_do_increment_digital_signature_counter (void) count_data[1] = (count >> 8) & 0xff; count_data[2] = count & 0xff; - do_ptr[NR_DO_DS_COUNT] = flash_do_write (GPG_DO_DS_COUNT, count_data, + do_ptr[NR_DO_DS_COUNT] = flash_do_write (NR_DO_DS_COUNT, count_data, SIZE_DIGITAL_SIGNATURE_COUNTER); } @@ -1129,5 +1209,5 @@ gpg_do_reset_pw_counter (uint8_t which) pwsb[which] = 3; } - gpg_do_write_simple (GNUK_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); } diff --git a/src/openpgp.c b/src/openpgp.c index b0926e8..7977b2e 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -61,7 +61,7 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = { }; static const uint8_t const -get_data_rb_result[] __attribute__ ((aligned (1))) = { +read_binary_result[] __attribute__ ((aligned (1))) = { 0x5a, 0x4, 0x01, 0x02, 0x03, 0x04 }; @@ -91,6 +91,7 @@ cmd_verify (void) int r; DEBUG_INFO (" - VERIFY\r\n"); + DEBUG_BYTE (p2); len = cmd_APDU[4]; if (p2 == 0x81) @@ -101,11 +102,20 @@ cmd_verify (void) r = verify_admin (&cmd_APDU[5], len); if (r < 0) - GPG_SECURITY_FAILURE (); + { + DEBUG_INFO ("failed\r\n"); + GPG_SECURITY_FAILURE (); + } else if (r == 0) - GPG_SECURITY_AUTH_BLOCKED (); + { + DEBUG_INFO ("blocked\r\n"); + GPG_SECURITY_AUTH_BLOCKED (); + } else - GPG_SUCCESS (); + { + DEBUG_INFO ("good\r\n"); + GPG_SUCCESS (); + } } int @@ -139,14 +149,18 @@ cmd_change_password (void) int who = p2 - 0x80; int r; + DEBUG_INFO ("Change PW\r\n"); + DEBUG_BYTE (who); + if (who == 1) /* PW1 */ { - const uint8_t *pk = gpg_do_read_simple (GNUK_DO_KEYSTRING_PW1); + const uint8_t *pk = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); if (pk == NULL) { if (len < 6) { + DEBUG_INFO ("permission denied.\r\n"); GPG_SECURITY_FAILURE (); return; } @@ -170,11 +184,13 @@ cmd_change_password (void) if (pw_len < 0) { + DEBUG_INFO ("permission denied.\r\n"); GPG_SECURITY_FAILURE (); return; } else if (pw_len == 0) { + DEBUG_INFO ("blocked.\r\n"); GPG_SECURITY_AUTH_BLOCKED (); return; } @@ -192,24 +208,33 @@ cmd_change_password (void) r = gpg_change_keystring (who, old_ks, who, new_ks); if (r < -2) - GPG_MEMORY_FAILURE (); + { + DEBUG_INFO ("memory error.\r\n"); + GPG_MEMORY_FAILURE (); + } else if (r < 0) - GPG_SECURITY_FAILURE (); + { + DEBUG_INFO ("security error.\r\n"); + 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); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); gpg_do_reset_pw_counter (PW_STATUS_PW1); + DEBUG_INFO ("Changed DO_KEYSTRING_PW1\r\n"); } else if (r > 0 && who == 1) { - gpg_do_write_simple (GNUK_DO_KEYSTRING_PW1, new_ks0, 1); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1); ac_reset_pso_cds (); gpg_do_reset_pw_counter (PW_STATUS_PW1); + DEBUG_INFO ("Removed content of DO_KEYSTRING_PW1\r\n"); } else /* r >= 0 && who == 3 */ { + DEBUG_INFO ("done.\r\n"); gpg_do_reset_pw_counter (PW_STATUS_PW3); GPG_SUCCESS (); } @@ -225,10 +250,13 @@ cmd_reset_user_password (void) int pw_len, newpw_len; int r; + DEBUG_INFO ("Reset PW1\r\n"); + DEBUG_BYTE (p1); + 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); + const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); + const uint8_t *ks_rc = gpg_do_read_simple (NR_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]; @@ -236,12 +264,14 @@ cmd_reset_user_password (void) if (pw_status_bytes == NULL || pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */ { + DEBUG_INFO ("blocked.\r\n"); GPG_SECURITY_AUTH_BLOCKED (); return; } if (ks_rc == NULL) { + DEBUG_INFO ("security error.\r\n"); GPG_SECURITY_FAILURE (); return; } @@ -254,27 +284,33 @@ cmd_reset_user_password (void) new_ks0[0] = newpw_len; r = gpg_change_keystring (2, old_ks, 1, new_ks); if (r < -2) - GPG_MEMORY_FAILURE (); + { + DEBUG_INFO ("memory error.\r\n"); + GPG_MEMORY_FAILURE (); + } else if (r < 0) { uint8_t pwsb[SIZE_PW_STATUS_BYTES]; sec_fail: + DEBUG_INFO ("failed.\r\n"); 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_do_write_simple (NR_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); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); gpg_do_reset_pw_counter (PW_STATUS_PW1); + DEBUG_INFO ("done (no prvkey).\r\n"); } else { + DEBUG_INFO ("done.\r\n"); ac_reset_pso_cds (); gpg_do_reset_pw_counter (PW_STATUS_PW1); GPG_SUCCESS (); @@ -283,7 +319,10 @@ cmd_reset_user_password (void) else /* by Admin (p1 == 0x02) */ { if (!ac_check_status (AC_ADMIN_AUTHORIZED)) - GPG_SECURITY_FAILURE (); + { + DEBUG_INFO ("permission denied.\r\n"); + GPG_SECURITY_FAILURE (); + } else { const uint8_t *old_ks = keystring_md_pw3; @@ -296,17 +335,25 @@ cmd_reset_user_password (void) new_ks0[0] = newpw_len; r = gpg_change_keystring (3, old_ks, 1, new_ks); if (r < -2) - GPG_MEMORY_FAILURE (); + { + DEBUG_INFO ("memory error.\r\n"); + GPG_MEMORY_FAILURE (); + } else if (r < 0) - GPG_SECURITY_FAILURE (); + { + DEBUG_INFO ("security error.\r\n"); + GPG_SECURITY_FAILURE (); + } else if (r == 0) { - gpg_do_write_simple (GNUK_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); + DEBUG_INFO ("done (no privkey).\r\n"); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); gpg_do_reset_pw_counter (PW_STATUS_PW1); } else { + DEBUG_INFO ("done.\r\n"); ac_reset_pso_cds (); gpg_do_reset_pw_counter (PW_STATUS_PW1); GPG_SUCCESS (); @@ -344,6 +391,7 @@ static void cmd_pgp_gakp (void) { DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n"); + DEBUG_BYTE (cmd_APDU[2]); if (cmd_APDU[2] == 0x81) /* Get public key */ @@ -354,7 +402,7 @@ cmd_pgp_gakp (void) GPG_SECURITY_FAILURE (); /* XXX: Not yet supported */ - write_res_apdu (NULL, 0, 0x6a, 0x88); /* No record */ + GPG_ERROR (); } } @@ -369,8 +417,8 @@ cmd_read_binary (void) 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); + write_res_apdu (read_binary_result, + sizeof (read_binary_result), 0x90, 0x00); } else GPG_NO_RECORD(); @@ -388,8 +436,6 @@ cmd_select_file (void) */ file_selection = FILE_DF_OPENPGP; - - /* XXX: Should return contents??? */ GPG_SUCCESS (); } else if (cmd_APDU[4] == 2 @@ -445,12 +491,16 @@ cmd_get_data (void) static void cmd_pso (void) { + int len; + int r; + DEBUG_INFO (" - PSO\r\n"); - if (cmd_APDU[2] == 0x9E && cmd_APDU[3] == 0x9A) + if (cmd_APDU[2] == 0x9e && cmd_APDU[3] == 0x9a) { if (!ac_check_status (AC_PSO_CDS_AUTHORIZED)) { + DEBUG_INFO ("security error."); GPG_SECURITY_FAILURE (); return; } @@ -463,18 +513,16 @@ cmd_pso (void) } else { - int len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - int r; + len = (cmd_APDU[5]<<8) | cmd_APDU[6]; 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); + GPG_ERROR (); else { /* Success */ - const uint8_t *pw_status_bytes = gpg_do_read_simple (GNUK_DO_PW_STATUS); + const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); res_APDU[RSA_SIGNATURE_LENGTH] = 0x90; res_APDU[RSA_SIGNATURE_LENGTH+1] = 0x00; @@ -486,8 +534,23 @@ cmd_pso (void) gpg_do_increment_digital_signature_counter (); } } + } + else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86) + { + len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - DEBUG_INFO ("done.\r\n"); + if (!ac_check_status (AC_PSO_OTHER_AUTHORIZED)) + { + DEBUG_INFO ("security error."); + GPG_SECURITY_FAILURE (); + return; + } + + DEBUG_BYTE (len); + + r = rsa_decrypt (&cmd_APDU[7], res_APDU, len); + if (r < 0) + GPG_ERROR (); } else { /* XXX: not yet supported */ @@ -497,6 +560,8 @@ cmd_pso (void) DEBUG_BYTE (cmd_APDU[3]); GPG_SUCCESS (); } + + DEBUG_INFO ("PSO done.\r\n"); } struct command diff --git a/src/openpgp.h b/src/openpgp.h index 8f720a4..fd4175d 100644 --- a/src/openpgp.h +++ b/src/openpgp.h @@ -5,4 +5,5 @@ #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_ERROR() write_res_apdu (NULL, 0, 0x6f, 0x00) #define GPG_SUCCESS() write_res_apdu (NULL, 0, 0x90, 0x00) diff --git a/src/rsa-sign.c b/src/rsa-sign.c deleted file mode 100644 index 5c07733..0000000 --- a/src/rsa-sign.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "config.h" -#include "ch.h" -#include "gnuk.h" -#include "polarssl/config.h" -#include "polarssl/rsa.h" - -static rsa_context rsa_ctx; - -int -rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len) -{ - mpi P1, Q1, H; - int r; - - DEBUG_BINARY (kd.data, 256); - - mpi_init (&P1, &Q1, &H, NULL); - rsa_init (&rsa_ctx, RSA_PKCS_V15, 0); - - rsa_ctx.len = 2048 / 8; - mpi_read_string (&rsa_ctx.E, 16, "10001"); - mpi_read_binary (&rsa_ctx.P, &kd.data[0], rsa_ctx.len / 2); - mpi_read_binary (&rsa_ctx.Q, &kd.data[128], rsa_ctx.len / 2); - mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q); - mpi_sub_int (&P1, &rsa_ctx.P, 1); - mpi_sub_int (&Q1, &rsa_ctx.Q, 1); - mpi_mul_mpi (&H, &P1, &Q1); - mpi_inv_mod (&rsa_ctx.D , &rsa_ctx.E, &H); - mpi_mod_mpi (&rsa_ctx.DP, &rsa_ctx.D, &P1); - mpi_mod_mpi (&rsa_ctx.DQ, &rsa_ctx.D, &Q1); - mpi_inv_mod (&rsa_ctx.QP, &rsa_ctx.Q, &rsa_ctx.P); - mpi_free (&P1, &Q1, &H, NULL); - - DEBUG_INFO ("RSA..."); - - if ((r = rsa_check_privkey (&rsa_ctx)) == 0) - DEBUG_INFO ("ok..."); - else - { - DEBUG_INFO ("failed.\r\n"); - DEBUG_SHORT (r); - rsa_free (&rsa_ctx); - return r; - } - - r = rsa_pkcs1_sign (&rsa_ctx, RSA_PRIVATE, SIG_RSA_RAW, - msg_len, raw_message, output); - rsa_free (&rsa_ctx); - 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); -} diff --git a/src/usb-icc.c b/src/usb-icc.c index 3b856c0..bb529dc 100644 --- a/src/usb-icc.c +++ b/src/usb-icc.c @@ -435,7 +435,9 @@ icc_handle_timeout (void) switch (icc_state) { case ICC_STATE_EXECUTE: +#if 0 icc_send_data_block (ICC_CMD_STATUS_TIMEEXT, 0, 0, NULL, 0); +#endif break; case ICC_STATE_RECEIVE: case ICC_STATE_SEND: diff --git a/src/usb_desc.c b/src/usb_desc.c index 26f7cdc..71260a1 100644 --- a/src/usb_desc.c +++ b/src/usb_desc.c @@ -1,5 +1,5 @@ /* - * + * usb_desc.c - USB Descriptor */ #include "config.h" @@ -20,8 +20,8 @@ static const uint8_t gnukDeviceDescriptor[] = { 0x00, /* bDeviceSubClass */ 0x00, /* bDeviceProtocol */ 0x40, /* bMaxPacketSize0 */ - 0xff, 0xff, /* idVendor = 0xffff */ - 0x01, 0x00, /* idProduct = 0x0001 */ + 0x4b, 0x23, /* idVendor = 0x234b (FSIJ) */ + 0x00, 0x00, /* idProduct = 0x0000 (FSIJ USB Token) */ 0x00, 0x02, /* bcdDevice = 2.00 */ 1, /* Index of string descriptor describing manufacturer */ 2, /* Index of string descriptor describing product */