Merge branch 'master' into ecc_p256
This commit is contained in:
@@ -3,9 +3,6 @@
|
||||
BOARD_DIR=@BOARD_DIR@
|
||||
@PINPAD_MAKE_OPTION@
|
||||
@DEBUG_MAKE_OPTION@
|
||||
ifneq ($(ENABLE_DEBUG),)
|
||||
ENABLE_VCOMPORT=1
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
# Build global options
|
||||
@@ -14,7 +11,7 @@ endif
|
||||
|
||||
# Compiler options here.
|
||||
ifeq ($(USE_OPT),)
|
||||
USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
|
||||
USE_OPT = -O3 -Os -ggdb -fomit-frame-pointer -falign-functions=16
|
||||
endif
|
||||
|
||||
# C++ specific options here (added to USE_OPT).
|
||||
@@ -70,8 +67,6 @@ include $(CHIBIOS)/os/hal/platforms/STM32/platform.mk
|
||||
include $(CHIBIOS)/os/hal/hal.mk
|
||||
include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/port.mk
|
||||
include $(CHIBIOS)/os/kernel/kernel.mk
|
||||
include stmusb.mk
|
||||
include vcomport.mk
|
||||
include crypt.mk
|
||||
|
||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
@@ -81,17 +76,15 @@ CSRC = $(PORTSRC) \
|
||||
$(HALSRC) \
|
||||
$(PLATFORMSRC) \
|
||||
$(BOARDSRC) \
|
||||
../boards/common/hw_config.c \
|
||||
$(BOARD_DIR)/board.c \
|
||||
$(CHIBIOS)/os/various/evtimer.c \
|
||||
$(CHIBIOS)/os/various/syscalls.c \
|
||||
$(STMUSBSRC) \
|
||||
$(VCOMSRC) \
|
||||
$(CRYPTSRC) \
|
||||
main.c usb_lld.c \
|
||||
usb_desc.c usb_prop.c \
|
||||
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c hardclock.c \
|
||||
random.c neug.c bn.c modp256.c jpc.c mod.c ec_p256.c
|
||||
usb_desc.c usb_ctrl.c \
|
||||
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c \
|
||||
bn.c modp256.c jpc.c mod.c ec_p256.c \
|
||||
random.c neug.c sys.c
|
||||
|
||||
ifneq ($(ENABLE_DEBUG),)
|
||||
CSRC += debug.c
|
||||
@@ -101,11 +94,15 @@ ifneq ($(ENABLE_PINPAD),)
|
||||
CSRC += pin-$(ENABLE_PINPAD).c
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_PINPAD),dnd)
|
||||
CSRC += usb-msc.c
|
||||
endif
|
||||
|
||||
# List ASM source files here
|
||||
ASMSRC = $(PORTASM) \
|
||||
$(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/vectors.s
|
||||
|
||||
INCDIR = $(CRYPTINCDIR) $(STMUSBINCDIR) $(VCOMDIR) \
|
||||
INCDIR = $(CRYPTINCDIR) \
|
||||
$(PORTINC) $(KERNINC) $(TESTINC) \
|
||||
$(HALINC) $(PLATFORMINC) ../boards/common $(BOARD_DIR) \
|
||||
$(CHIBIOS)/os/various
|
||||
@@ -179,7 +176,7 @@ DLIBS =
|
||||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
UDEFS =
|
||||
UDEFS = @KEYGEN_SUPPORT@
|
||||
|
||||
# Define ASM defines here
|
||||
UADEFS =
|
||||
@@ -197,14 +194,8 @@ ULIBS =
|
||||
# End of user defines
|
||||
##############################################################################
|
||||
|
||||
ifeq ($(USE_FWLIB),yes)
|
||||
include $(CHIBIOS)/ext/stm32lib/stm32lib.mk
|
||||
CSRC += $(STM32SRC)
|
||||
INCDIR += $(STM32INC)
|
||||
USE_OPT += -DUSE_STDPERIPH_DRIVER
|
||||
endif
|
||||
|
||||
include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk
|
||||
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
|
||||
|
||||
distclean: clean
|
||||
-rm -f Makefile gnuk.ld config.h
|
||||
-rm -f Makefile gnuk.ld config.h *.inc
|
||||
|
||||
96
src/ac.c
96
src/ac.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ac.c -- Check access condition
|
||||
*
|
||||
* Copyright (C) 2010 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -24,9 +24,7 @@
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/sha1.h"
|
||||
#include "sha256.h"
|
||||
|
||||
uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */
|
||||
|
||||
@@ -57,11 +55,11 @@ ac_reset_other (void)
|
||||
}
|
||||
|
||||
int
|
||||
verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
const uint8_t *ks_pw1)
|
||||
{
|
||||
int pw_len;
|
||||
int r;
|
||||
int r1, r2;
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
|
||||
if (gpg_pw_locked (PW_ERR_PW1))
|
||||
@@ -75,7 +73,7 @@ verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
|| strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW1, pw_len))
|
||||
goto failure;
|
||||
else
|
||||
goto success;
|
||||
goto success_one_step;
|
||||
}
|
||||
else
|
||||
pw_len = ks_pw1[0];
|
||||
@@ -88,15 +86,28 @@ verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
return -1;
|
||||
}
|
||||
|
||||
sha1 (pw, pw_len, keystring);
|
||||
if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring))
|
||||
< 0)
|
||||
goto failure;
|
||||
else if (r == 0)
|
||||
if (memcmp (ks_pw1+1, keystring, KEYSTRING_MD_SIZE) != 0)
|
||||
success_one_step:
|
||||
s2k (BY_USER, pw, pw_len, keystring);
|
||||
if (access == AC_PSO_CDS_AUTHORIZED)
|
||||
{
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
|
||||
r2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring);
|
||||
r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, keystring);
|
||||
}
|
||||
|
||||
if (r1 < 0 || r2 < 0)
|
||||
{
|
||||
gpg_pw_increment_err_counter (PW_ERR_PW1);
|
||||
return -1;
|
||||
}
|
||||
else if (r1 == 0 && r2 == 0)
|
||||
if (ks_pw1 != NULL && memcmp (ks_pw1+1, keystring, KEYSTRING_MD_SIZE) != 0)
|
||||
goto failure;
|
||||
|
||||
success:
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
return pw_len;
|
||||
}
|
||||
@@ -113,7 +124,7 @@ verify_pso_cds (const uint8_t *pw, int pw_len)
|
||||
DEBUG_INFO ("verify_pso_cds\r\n");
|
||||
DEBUG_BYTE (pw_len);
|
||||
|
||||
r = verify_user_0 (pw, pw_len, pw_len, ks_pw1);
|
||||
r = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, pw_len, pw_len, ks_pw1);
|
||||
if (r > 0)
|
||||
auth_status |= AC_PSO_CDS_AUTHORIZED;
|
||||
return r;
|
||||
@@ -122,29 +133,16 @@ verify_pso_cds (const uint8_t *pw, int pw_len)
|
||||
int
|
||||
verify_other (const uint8_t *pw, int pw_len)
|
||||
{
|
||||
int r1, r2;
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
int r;
|
||||
|
||||
DEBUG_INFO ("verify_other\r\n");
|
||||
DEBUG_BYTE (pw_len);
|
||||
|
||||
if (gpg_pw_locked (PW_ERR_PW1))
|
||||
return 0;
|
||||
|
||||
sha1 (pw, pw_len, keystring);
|
||||
if ((r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring)) < 0
|
||||
|| (r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER,
|
||||
keystring)) < 0)
|
||||
{
|
||||
gpg_pw_increment_err_counter (PW_ERR_PW1);
|
||||
return -1;
|
||||
}
|
||||
else if (r1 == 0 && r2 == 0)
|
||||
/* No key is available. Fail even if password can match. */
|
||||
return -1;
|
||||
|
||||
gpg_pw_reset_err_counter (PW_ERR_PW1);
|
||||
auth_status |= AC_OTHER_AUTHORIZED;
|
||||
return 1;
|
||||
r = verify_user_0 (AC_OTHER_AUTHORIZED, pw, pw_len, pw_len, ks_pw1);
|
||||
if (r > 0)
|
||||
auth_status |= AC_OTHER_AUTHORIZED;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -161,28 +159,27 @@ static void
|
||||
calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len,
|
||||
uint8_t md[KEYSTRING_MD_SIZE])
|
||||
{
|
||||
sha1_context sha1_ctx;
|
||||
sha256_context sha256_ctx;
|
||||
|
||||
sha1_starts (&sha1_ctx);
|
||||
sha256_start (&sha256_ctx);
|
||||
|
||||
while (count > pw_len + 8)
|
||||
{
|
||||
sha1_update (&sha1_ctx, salt, 8);
|
||||
sha1_update (&sha1_ctx, pw, pw_len);
|
||||
sha256_update (&sha256_ctx, salt, 8);
|
||||
sha256_update (&sha256_ctx, pw, pw_len);
|
||||
count -= pw_len + 8;
|
||||
}
|
||||
|
||||
if (count < 8)
|
||||
sha1_update (&sha1_ctx, salt, count);
|
||||
if (count <= 8)
|
||||
sha256_update (&sha256_ctx, salt, count);
|
||||
else
|
||||
{
|
||||
sha1_update (&sha1_ctx, salt, 8);
|
||||
sha256_update (&sha256_ctx, salt, 8);
|
||||
count -= 8;
|
||||
sha1_update (&sha1_ctx, pw, count);
|
||||
sha256_update (&sha256_ctx, pw, count);
|
||||
}
|
||||
|
||||
sha1_finish (&sha1_ctx, md);
|
||||
memset (&sha1_ctx, 0, sizeof (sha1_ctx));
|
||||
sha256_finish (&sha256_ctx, md);
|
||||
}
|
||||
|
||||
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
|
||||
@@ -205,7 +202,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
|
||||
return 0;
|
||||
|
||||
pw_len = pw3_keystring[0];
|
||||
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len)
|
||||
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len > buf_len)
|
||||
goto failure;
|
||||
|
||||
salt = &pw3_keystring[1];
|
||||
@@ -230,7 +227,8 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
|
||||
|
||||
if (ks_pw1 != NULL)
|
||||
{ /* empty PW3, but PW1 exists */
|
||||
int r = verify_user_0 (pw, buf_len, pw_len_known, ks_pw1);
|
||||
int r = verify_user_0 (AC_PSO_CDS_AUTHORIZED,
|
||||
pw, buf_len, pw_len_known, ks_pw1);
|
||||
|
||||
if (r > 0)
|
||||
admin_authorized = BY_USER;
|
||||
@@ -282,7 +280,7 @@ verify_admin (const uint8_t *pw, int pw_len)
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
sha1 (pw, pw_len, keystring_md_pw3);
|
||||
s2k (admin_authorized, pw, pw_len, keystring_md_pw3);
|
||||
auth_status |= AC_ADMIN_AUTHORIZED;
|
||||
return 1;
|
||||
}
|
||||
@@ -292,6 +290,7 @@ ac_reset_admin (void)
|
||||
{
|
||||
memset (keystring_md_pw3, 0, KEYSTRING_MD_SIZE);
|
||||
auth_status &= ~AC_ADMIN_AUTHORIZED;
|
||||
admin_authorized = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -302,4 +301,5 @@ ac_fini (void)
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION);
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION);
|
||||
auth_status = AC_NONE_AUTHORIZED;
|
||||
admin_authorized = 0;
|
||||
}
|
||||
|
||||
133
src/call-rsa.c
133
src/call-rsa.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
|
||||
*
|
||||
* Copyright (C) 2010 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -25,10 +25,13 @@
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "gnuk.h"
|
||||
#include "openpgp.h"
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/rsa.h"
|
||||
|
||||
#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */
|
||||
#define RSA_SIGNATURE_LENGTH KEY_CONTENT_LEN
|
||||
/* 256 byte == 2048-bit */
|
||||
/* 128 byte == 1024-bit */
|
||||
|
||||
static rsa_context rsa_ctx;
|
||||
|
||||
@@ -43,11 +46,13 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
|
||||
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");
|
||||
rsa_ctx.len = KEY_CONTENT_LEN;
|
||||
mpi_lset (&rsa_ctx.E, 0x10001);
|
||||
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_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2], rsa_ctx.len / 2);
|
||||
#if 0 /* Using CRT, we don't use N */
|
||||
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
|
||||
#endif
|
||||
mpi_sub_int (&P1, &rsa_ctx.P, 1);
|
||||
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
|
||||
mpi_mul_mpi (&H, &P1, &Q1);
|
||||
@@ -58,17 +63,6 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
|
||||
mpi_free (&P1, &Q1, &H, NULL);
|
||||
|
||||
DEBUG_INFO ("RSA sign...");
|
||||
#if 0
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = rsa_pkcs1_sign (&rsa_ctx, RSA_PRIVATE, SIG_RSA_RAW,
|
||||
msg_len, raw_message, temp);
|
||||
@@ -82,31 +76,32 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
|
||||
}
|
||||
else
|
||||
{
|
||||
res_APDU[RSA_SIGNATURE_LENGTH] = 0x90;
|
||||
res_APDU[RSA_SIGNATURE_LENGTH+1] = 0x00;
|
||||
res_APDU_size = RSA_SIGNATURE_LENGTH + 2;
|
||||
res_APDU_size = RSA_SIGNATURE_LENGTH;
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* LEN: length in byte
|
||||
*/
|
||||
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);
|
||||
modulus = malloc (len);
|
||||
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_read_binary (&P, p, len / 2);
|
||||
mpi_read_binary (&Q, p + len / 2, len / 2);
|
||||
mpi_mul_mpi (&N, &P, &Q);
|
||||
|
||||
mpi_write_binary (&N, modulus, 2048 / 8);
|
||||
mpi_write_binary (&N, modulus, len);
|
||||
mpi_free (&P, &Q, &N, NULL);
|
||||
return modulus;
|
||||
}
|
||||
@@ -134,10 +129,13 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
rsa_ctx.len = msg_len;
|
||||
DEBUG_WORD (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_lset (&rsa_ctx.E, 0x10001);
|
||||
mpi_read_binary (&rsa_ctx.P, &kd->data[0], KEY_CONTENT_LEN / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2],
|
||||
KEY_CONTENT_LEN / 2);
|
||||
#if 0 /* Using CRT, we don't use N */
|
||||
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
|
||||
#endif
|
||||
mpi_sub_int (&P1, &rsa_ctx.P, 1);
|
||||
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
|
||||
mpi_mul_mpi (&H, &P1, &Q1);
|
||||
@@ -148,21 +146,9 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
mpi_free (&P1, &Q1, &H, NULL);
|
||||
|
||||
DEBUG_INFO ("RSA decrypt ...");
|
||||
#if 0
|
||||
/* This consume some memory */
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = rsa_pkcs1_decrypt (&rsa_ctx, RSA_PRIVATE, &output_len,
|
||||
input, output, MAX_RES_APDU_SIZE - 2);
|
||||
input, output, MAX_RES_APDU_DATA_SIZE);
|
||||
rsa_free (&rsa_ctx);
|
||||
if (r < 0)
|
||||
{
|
||||
@@ -172,10 +158,71 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
}
|
||||
else
|
||||
{
|
||||
res_APDU[output_len] = 0x90;
|
||||
res_APDU[output_len+1] = 0x00;
|
||||
res_APDU_size = output_len + 2;
|
||||
res_APDU_size = output_len;
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
|
||||
{
|
||||
int r;
|
||||
|
||||
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
|
||||
rsa_ctx.len = KEY_CONTENT_LEN;
|
||||
mpi_lset (&rsa_ctx.E, 0x10001);
|
||||
mpi_read_binary (&rsa_ctx.N, pubkey, KEY_CONTENT_LEN);
|
||||
|
||||
DEBUG_INFO ("RSA verify...");
|
||||
|
||||
r = rsa_pkcs1_verify (&rsa_ctx, RSA_PUBLIC, SIG_RSA_SHA256, 32, hash, sig);
|
||||
|
||||
rsa_free (&rsa_ctx);
|
||||
if (r < 0)
|
||||
{
|
||||
DEBUG_INFO ("fail:");
|
||||
DEBUG_SHORT (r);
|
||||
return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO ("verified.\r\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define RSA_EXPONENT 0x10001
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
const uint8_t *
|
||||
rsa_genkey (void)
|
||||
{
|
||||
int r;
|
||||
uint8_t index = 0;
|
||||
uint8_t *p_q_modulus = (uint8_t *)malloc (KEY_CONTENT_LEN*2);
|
||||
uint8_t *p = p_q_modulus;
|
||||
uint8_t *q = p_q_modulus + KEY_CONTENT_LEN/2;
|
||||
uint8_t *modulus = p_q_modulus + KEY_CONTENT_LEN;
|
||||
|
||||
if (p_q_modulus == NULL)
|
||||
return NULL;
|
||||
|
||||
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
|
||||
r = rsa_gen_key (&rsa_ctx, random_byte, &index,
|
||||
KEY_CONTENT_LEN * 8, RSA_EXPONENT);
|
||||
if (r < 0)
|
||||
{
|
||||
free (p_q_modulus);
|
||||
rsa_free (&rsa_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mpi_write_binary (&rsa_ctx.P, p, KEY_CONTENT_LEN/2);
|
||||
mpi_write_binary (&rsa_ctx.Q, q, KEY_CONTENT_LEN/2);
|
||||
mpi_write_binary (&rsa_ctx.N, modulus, KEY_CONTENT_LEN);
|
||||
rsa_free (&rsa_ctx);
|
||||
return p_q_modulus;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,3 +5,5 @@
|
||||
@DFU_DEFINE@
|
||||
@PINPAD_DEFINE@
|
||||
@PINPAD_MORE_DEFINE@
|
||||
@CERTDO_DEFINE@
|
||||
#define FLASH_PAGE_SIZE @FLASH_PAGE_SIZE@
|
||||
|
||||
127
src/configure
vendored
127
src/configure
vendored
@@ -3,7 +3,7 @@
|
||||
#
|
||||
# This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka
|
||||
#
|
||||
# Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
# Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
#
|
||||
# This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
# Gnuk is free software: you can redistribute it and/or modify it
|
||||
@@ -21,17 +21,14 @@
|
||||
|
||||
# Default settings
|
||||
help=no
|
||||
vidpid=none
|
||||
target=OLIMEX_STM32_H103
|
||||
verbose=no
|
||||
with_dfu=default
|
||||
debug=no
|
||||
pinpad=no
|
||||
|
||||
# check /dev/random
|
||||
if test ! -e /dev/random; then
|
||||
echo "/dev/random is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
certdo=no
|
||||
keygen=no
|
||||
|
||||
# Process each option
|
||||
for option; do
|
||||
@@ -43,20 +40,28 @@ for option; do
|
||||
case $option in
|
||||
-h | --help)
|
||||
help=yes ;;
|
||||
--target=*)
|
||||
target=$optarg ;;
|
||||
-v | --verbose)
|
||||
verbose=yes ;;
|
||||
--vidpid=*)
|
||||
vidpid=$optarg ;;
|
||||
--target=*)
|
||||
target=$optarg ;;
|
||||
--enable-debug)
|
||||
debug=yes ;;
|
||||
--disable-debug)
|
||||
debug=no ;;
|
||||
--enable-pinpad)
|
||||
pinpad=yes ;;
|
||||
--enable-pinpad=*)
|
||||
pinpad=$optarg ;;
|
||||
--disable-pinpad)
|
||||
pinpad=no ;;
|
||||
--enable-certdo)
|
||||
certdo=yes ;;
|
||||
--disable-certdo)
|
||||
certdo=no ;;
|
||||
--enable-keygen)
|
||||
keygen=yes ;;
|
||||
--disable-keygen)
|
||||
keygen=no ;;
|
||||
--with-dfu)
|
||||
with_dfu=yes ;;
|
||||
--without-dfu)
|
||||
@@ -77,6 +82,7 @@ Defaults for the options are specified in brackets.
|
||||
|
||||
Configuration:
|
||||
-h, --help display this help and exit [no]
|
||||
--vidpid=VID:PID specify vendor/product ID [<NONE>]
|
||||
--target=TARGET specify target [OLIMEX_STM32_H103]
|
||||
supported targes are:
|
||||
OLIMEX_STM32_H103
|
||||
@@ -85,14 +91,22 @@ Configuration:
|
||||
STBEE_MINI
|
||||
STM8S_DISCOVERY
|
||||
STBEE
|
||||
FST_01
|
||||
--enable-debug debug with virtual COM port [no]
|
||||
--enable-pinpad={cir,dial}
|
||||
PIN input device support [no]
|
||||
PIN entry support [no]
|
||||
--enable-certdo support CERT.3 data object [no]
|
||||
--enable-keygen support key generation [no]
|
||||
--with-dfu build image for DFU [<target specific>]
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test "$vidpid" = "none"; then
|
||||
echo "Please specify Vendor ID and Product ID by --vidpid option."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BOARD_DIR=../boards/$target
|
||||
if test -d $BOARD_DIR; then
|
||||
echo "Configured for target: $target"
|
||||
@@ -147,6 +161,7 @@ if test "$with_dfu" = "yes"; then
|
||||
FLASH_SIZE=`expr $FLASH_SIZE - 12`
|
||||
DFU_DEFINE="#define DFU_SUPPORT 1"
|
||||
else
|
||||
with_dfu=no
|
||||
echo "Configured for bare system (no-DFU)"
|
||||
ORIGIN=0x08000000
|
||||
DFU_DEFINE="#undef DFU_SUPPORT"
|
||||
@@ -158,11 +173,6 @@ if test "$pinpad" = "no"; then
|
||||
PINPAD_DEFINE="#undef PINPAD_SUPPORT"
|
||||
PINPAD_MORE_DEFINE=""
|
||||
echo "PIN pad option disabled"
|
||||
elif test "$pinpad" = "yes"; then
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=cir"
|
||||
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
|
||||
PINPAD_MORE_DEFINE="#define PINPAD_CIR_SUPPORT 1"
|
||||
echo "PIN pad option enabled (cir)"
|
||||
else
|
||||
PINPAD_MAKE_OPTION="ENABLE_PINPAD=$pinpad"
|
||||
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
|
||||
@@ -170,16 +180,93 @@ else
|
||||
echo "PIN pad option enabled ($pinpad)"
|
||||
fi
|
||||
|
||||
# --enable-certdo option
|
||||
if test "$certdo" = "yes"; then
|
||||
CERTDO_DEFINE="#define CERTDO_SUPPORT 1"
|
||||
echo "CERT.3 Data Object is supported"
|
||||
else
|
||||
CERTDO_DEFINE="#undef CERTDO_SUPPORT"
|
||||
echo "CERT.3 Data Object is NOT supported"
|
||||
fi
|
||||
|
||||
# --enable-keygen option
|
||||
if test "$keygen" = "yes"; then
|
||||
KEYGEN_SUPPORT="-DKEYGEN_SUPPORT"
|
||||
echo "Key generation on device is supported"
|
||||
else
|
||||
KEYGEN_SUPPORT=""
|
||||
echo "Key generation on device is NOT supported"
|
||||
fi
|
||||
|
||||
REVISION=`git describe --dirty="-modified"`
|
||||
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo:keygen=$keygen"
|
||||
|
||||
if !(IFS=" "
|
||||
while read VIDPID VERSION PRODUCT VENDOR; do
|
||||
if test "$vidpid" = "$VIDPID"; then
|
||||
(echo $VIDPID | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\n 0x\4, 0x\3, /* idProduct */%p"
|
||||
echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
|
||||
) > usb-vid-pid-ver.c.inc
|
||||
(echo 'static const uint8_t gnukStringVendor[] = {'
|
||||
echo " ${#VENDOR}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* Manufacturer: \"$VENDOR\" */"
|
||||
echo $VENDOR | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo 'static const uint8_t gnukStringProduct[] = {'
|
||||
echo " ${#PRODUCT}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* Product name: \"$PRODUCT\" */"
|
||||
echo $PRODUCT | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo '#ifdef USB_STRINGS_FOR_GNUK'
|
||||
echo 'static const uint8_t gnuk_revision_detail[] = {'
|
||||
echo " ${#REVISION}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* revision detail: \"$REVISION\" */"
|
||||
echo $REVISION | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo 'static const uint8_t gnuk_config_options[] = {'
|
||||
echo " ${#CONFIG}*2+2, /* bLength */"
|
||||
echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */"
|
||||
echo " /* configure options: \"$CONFIG\" */"
|
||||
echo $CONFIG | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p"
|
||||
echo '};'
|
||||
echo '#endif'
|
||||
) >usb-strings.c.inc
|
||||
exit 0
|
||||
fi
|
||||
done; exit 1) < ../GNUK_USB_DEVICE_ID
|
||||
then
|
||||
echo "Please specify valid Vendor ID and Product ID."
|
||||
echo "Check ../GNUK_USB_DEVICE_ID."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed -e "s%@BOARD_DIR@%$BOARD_DIR%" \
|
||||
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
|
||||
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
|
||||
-e "s%@KEYGEN_SUPPORT@%$KEYGEN_SUPPORT%" \
|
||||
< Makefile.in > Makefile
|
||||
sed -e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
if test "$certdo" = "yes"; then
|
||||
sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \
|
||||
-e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
< gnuk.ld.in > gnuk.ld
|
||||
else
|
||||
sed -e "/^@CERTDO_SUPPORT_START@$/,/^@CERTDO_SUPPORT_END@$/ d" \
|
||||
-e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
< gnuk.ld.in > gnuk.ld
|
||||
fi
|
||||
sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \
|
||||
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
|
||||
-e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \
|
||||
-e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \
|
||||
-e "s/@DFU_DEFINE@/$DFU_DEFINE/" \
|
||||
-e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \
|
||||
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
|
||||
< config.h.in > config.h
|
||||
exit 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CRYPTDIR = ../polarssl-0.14.0
|
||||
CRYPTSRCDIR = $(CRYPTDIR)/library
|
||||
CRYPTINCDIR = $(CRYPTDIR)/include
|
||||
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/sha1.c \
|
||||
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c \
|
||||
$(CRYPTSRCDIR)/aes.c \
|
||||
call-rsa.c
|
||||
sha256.c call-rsa.c
|
||||
|
||||
184
src/flash.c
184
src/flash.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -32,108 +32,9 @@
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "sys.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
#define FLASH_KEY1 0x45670123UL
|
||||
#define FLASH_KEY2 0xCDEF89ABUL
|
||||
|
||||
enum flash_status
|
||||
{
|
||||
FLASH_BUSY = 1,
|
||||
FLASH_ERROR_PG,
|
||||
FLASH_ERROR_WRP,
|
||||
FLASH_COMPLETE,
|
||||
FLASH_TIMEOUT
|
||||
};
|
||||
|
||||
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 0x00010000
|
||||
#define FLASH_ERASE_TIMEOUT 0x01000000
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_erase_page (uint32_t addr)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
|
||||
chSysLock ();
|
||||
if (status == FLASH_COMPLETE)
|
||||
{
|
||||
FLASH->CR |= FLASH_CR_PER;
|
||||
FLASH->AR = addr;
|
||||
FLASH->CR |= FLASH_CR_STRT;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
if (status != FLASH_TIMEOUT)
|
||||
FLASH->CR &= ~FLASH_CR_PER;
|
||||
}
|
||||
chSysUnlock ()
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flash memory map
|
||||
*
|
||||
@@ -145,7 +46,7 @@ flash_erase_page (uint32_t addr)
|
||||
* .data
|
||||
* _bss_start
|
||||
* .bss
|
||||
* _end
|
||||
* _end
|
||||
* <alignment to page>
|
||||
* ch_certificate_startp
|
||||
* <2048 bytes>
|
||||
@@ -154,14 +55,11 @@ flash_erase_page (uint32_t addr)
|
||||
* _keystore_pool
|
||||
* 1.5-KiB Key store (512-byte (p, q and N) key-store * 3)
|
||||
*/
|
||||
#define KEY_SIZE 512 /* P, Q and N */
|
||||
|
||||
#define FLASH_DATA_POOL_HEADER_SIZE 2
|
||||
#if defined(STM32F10X_HD)
|
||||
#define FLASH_PAGE_SIZE 2048
|
||||
#else
|
||||
#define FLASH_PAGE_SIZE 1024
|
||||
#endif
|
||||
#define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2)
|
||||
#define FLASH_KEYSTORE_SIZE (512*3)
|
||||
#define FLASH_KEYSTORE_SIZE (KEY_SIZE*3)
|
||||
|
||||
static const uint8_t *data_pool;
|
||||
extern uint8_t _keystore_pool;
|
||||
@@ -200,7 +98,7 @@ flash_init (void)
|
||||
/* Seek empty keystore */
|
||||
p = &_keystore_pool;
|
||||
while (*p != 0xff || *(p+1) != 0xff)
|
||||
p += 512;
|
||||
p += KEY_SIZE;
|
||||
|
||||
keystore = p;
|
||||
|
||||
@@ -294,14 +192,14 @@ flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len)
|
||||
|
||||
addr = (uint32_t)p;
|
||||
hw = nr | (len << 8);
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
addr += 2;
|
||||
|
||||
for (i = 0; i < len/2; i++)
|
||||
{
|
||||
hw = data[i*2] | (data[i*2+1]<<8);
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
addr += 2;
|
||||
}
|
||||
@@ -309,9 +207,8 @@ flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len)
|
||||
if ((len & 1))
|
||||
{
|
||||
hw = data[i*2] | 0xff00;
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
addr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,20 +257,19 @@ flash_do_release (const uint8_t *do_data)
|
||||
/* Fill zero for content and pad */
|
||||
for (i = 0; i < len/2; i ++)
|
||||
{
|
||||
if (flash_program_halfword (addr, 0) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, 0) != 0)
|
||||
flash_warning ("fill-zero failure");
|
||||
addr += 2;
|
||||
}
|
||||
|
||||
if ((len & 1))
|
||||
{
|
||||
if (flash_program_halfword (addr, 0) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, 0) != 0)
|
||||
flash_warning ("fill-zero pad failure");
|
||||
addr += 2;
|
||||
}
|
||||
|
||||
/* Fill 0x0000 for "tag_number and length" word */
|
||||
if (flash_program_halfword (addr_tag, 0) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr_tag, 0) != 0)
|
||||
flash_warning ("fill-zero tag_nr failure");
|
||||
}
|
||||
|
||||
@@ -385,7 +281,7 @@ flash_key_alloc (void)
|
||||
if ((k - &_keystore_pool) >= FLASH_KEYSTORE_SIZE)
|
||||
return NULL;
|
||||
|
||||
keystore += 512;
|
||||
keystore += KEY_SIZE;
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -401,7 +297,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
|
||||
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)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
return -1;
|
||||
addr += 2;
|
||||
}
|
||||
@@ -409,7 +305,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
|
||||
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)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
return -1;
|
||||
addr += 2;
|
||||
}
|
||||
@@ -581,28 +477,13 @@ flash_cnt123_clear (const uint8_t **addr_p)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
flash_check_blank (const uint8_t *page, int size)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
for (p = page; p < page + size; p++)
|
||||
if (*p != 0xff)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define FLASH_CH_CERTIFICATE_SIZE 2048
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
int
|
||||
flash_erase_binary (uint8_t file_id)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
if (file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
p = &ch_certificate_start;
|
||||
const uint8_t *p = &ch_certificate_start;
|
||||
if (flash_check_blank (p, FLASH_CH_CERTIFICATE_SIZE) == 0)
|
||||
{
|
||||
flash_erase_page ((uint32_t)p);
|
||||
@@ -613,9 +494,10 @@ flash_erase_binary (uint8_t file_id)
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
@@ -625,16 +507,23 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
|
||||
uint16_t maxsize;
|
||||
const uint8_t *p;
|
||||
|
||||
if (file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
maxsize = FLASH_CH_CERTIFICATE_SIZE;
|
||||
p = &ch_certificate_start;
|
||||
}
|
||||
else if (file_id == FILEID_SERIAL_NO)
|
||||
if (file_id == FILEID_SERIAL_NO)
|
||||
{
|
||||
maxsize = 6;
|
||||
p = &openpgpcard_aid[8];
|
||||
}
|
||||
else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
|
||||
{
|
||||
maxsize = KEY_CONTENT_LEN;
|
||||
p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
|
||||
}
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
else if (file_id == FILEID_CH_CERTIFICATE)
|
||||
{
|
||||
maxsize = FLASH_CH_CERTIFICATE_SIZE;
|
||||
p = &ch_certificate_start;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -646,11 +535,14 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
|
||||
uint32_t addr;
|
||||
int i;
|
||||
|
||||
if (flash_check_blank (p + offset, len) == 0)
|
||||
return -1;
|
||||
|
||||
addr = (uint32_t)p + offset;
|
||||
for (i = 0; i < len/2; i++)
|
||||
{
|
||||
hw = data[i*2] | (data[i*2+1]<<8);
|
||||
if (flash_program_halfword (addr, hw) != FLASH_COMPLETE)
|
||||
if (flash_program_halfword (addr, hw) != 0)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
addr += 2;
|
||||
}
|
||||
|
||||
164
src/gnuk.h
164
src/gnuk.h
@@ -1,3 +1,17 @@
|
||||
/*
|
||||
* We declare some of libc functions here, because we will
|
||||
* remove dependency on libc in future, possibly.
|
||||
*/
|
||||
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 int memcmp (const void *s1, const void *s2, size_t n);
|
||||
extern void *memmove(void *dest, const void *src, size_t n);
|
||||
|
||||
/*
|
||||
* Debug functions
|
||||
*/
|
||||
extern Thread *stdout_thread;
|
||||
#define EV_TX_READY ((eventmask_t)1)
|
||||
|
||||
@@ -11,44 +25,49 @@ 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.
|
||||
* Application layer <-> CCID layer data structure
|
||||
*/
|
||||
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 int memcmp (const void *s1, const void *s2, size_t n);
|
||||
extern void *memmove(void *dest, const void *src, size_t n);
|
||||
struct apdu {
|
||||
uint8_t seq;
|
||||
|
||||
/* command APDU */
|
||||
uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */
|
||||
uint8_t *cmd_apdu_data;
|
||||
uint16_t cmd_apdu_data_len; /* Nc, calculated by Lc field */
|
||||
uint16_t expected_res_size; /* Ne, calculated by Le field */
|
||||
|
||||
/* response APDU */
|
||||
uint16_t sw;
|
||||
uint8_t *res_apdu_data;
|
||||
uint16_t res_apdu_data_len;
|
||||
};
|
||||
|
||||
extern struct apdu apdu;
|
||||
|
||||
#define EV_EXEC_FINISHED ((eventmask_t)2) /* GPG Execution finished */
|
||||
|
||||
/* maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */
|
||||
#define MAX_CMD_APDU_SIZE (7+282) /* header + data */
|
||||
/* 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 */
|
||||
/* GPG thread */
|
||||
#define EV_PINPAD_INPUT_DONE ((eventmask_t)1)
|
||||
#define EV_NOP ((eventmask_t)2)
|
||||
#define EV_CMD_AVAILABLE ((eventmask_t)4)
|
||||
#define EV_VERIFY_CMD_AVAILABLE ((eventmask_t)8)
|
||||
#define EV_MODIFY_CMD_AVAILABLE ((eventmask_t)16)
|
||||
|
||||
/* Maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */
|
||||
#define MAX_CMD_APDU_DATA_SIZE (22+4+128+128) /* without header */
|
||||
/* Maximum res apdu data is public key 5+9+256 (gpg_do_public_key) */
|
||||
#define MAX_RES_APDU_DATA_SIZE (5+9+256) /* without trailer */
|
||||
|
||||
#define ICC_MSG_HEADER_SIZE 10
|
||||
|
||||
#define cmd_APDU (&icc_buffer[ICC_MSG_HEADER_SIZE])
|
||||
#define res_APDU (&icc_buffer[ICC_MSG_HEADER_SIZE])
|
||||
extern int icc_data_size;
|
||||
#define cmd_APDU_size icc_data_size
|
||||
extern int res_APDU_size;
|
||||
extern const uint8_t *res_APDU_pointer;
|
||||
#define res_APDU apdu.res_apdu_data
|
||||
#define res_APDU_size apdu.res_apdu_data_len
|
||||
|
||||
/* USB buffer size of LL (Low-level): size of single Bulk transaction */
|
||||
#define USB_LL_BUF_SIZE 64
|
||||
|
||||
/*
|
||||
* USB buffer size of USB-ICC driver
|
||||
* (Changing this, dwMaxCCIDMessageLength too !!)
|
||||
*/
|
||||
#define USB_BUF_SIZE ((10 + 10 + MAX_CMD_APDU_SIZE + USB_LL_BUF_SIZE - 1) \
|
||||
/ USB_LL_BUF_SIZE * USB_LL_BUF_SIZE)
|
||||
extern uint8_t icc_buffer[USB_BUF_SIZE];
|
||||
|
||||
enum icc_state
|
||||
{
|
||||
ICC_STATE_START, /* Initial */
|
||||
@@ -57,9 +76,12 @@ enum icc_state
|
||||
ICC_STATE_EXECUTE, /* Busy4 */
|
||||
ICC_STATE_RECEIVE, /* APDU Received Partially */
|
||||
ICC_STATE_SEND, /* APDU Sent Partially */
|
||||
|
||||
ICC_STATE_EXITED, /* ICC Thread Terminated */
|
||||
ICC_STATE_EXEC_REQUESTED, /* Exec requested */
|
||||
};
|
||||
|
||||
extern volatile enum icc_state icc_state;
|
||||
extern enum icc_state *icc_state_p;
|
||||
|
||||
extern volatile uint8_t auth_status;
|
||||
#define AC_NONE_AUTHORIZED 0x00
|
||||
@@ -72,6 +94,7 @@ extern volatile uint8_t auth_status;
|
||||
#define PW_ERR_PW1 0
|
||||
#define PW_ERR_RC 1
|
||||
#define PW_ERR_PW3 2
|
||||
extern int gpg_pw_get_retry_counter (int who);
|
||||
extern int gpg_pw_locked (uint8_t which);
|
||||
extern void gpg_pw_reset_err_counter (uint8_t which);
|
||||
extern void gpg_pw_increment_err_counter (uint8_t which);
|
||||
@@ -79,8 +102,8 @@ extern void gpg_pw_increment_err_counter (uint8_t which);
|
||||
extern int ac_check_status (uint8_t ac_flag);
|
||||
extern int verify_pso_cds (const uint8_t *pw, int pw_len);
|
||||
extern int verify_other (const uint8_t *pw, int pw_len);
|
||||
extern int verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known,
|
||||
const uint8_t *ks_pw1);
|
||||
extern int verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len,
|
||||
int pw_len_known, const uint8_t *ks_pw1);
|
||||
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);
|
||||
|
||||
@@ -90,7 +113,7 @@ extern void ac_reset_admin (void);
|
||||
extern void ac_fini (void);
|
||||
|
||||
|
||||
extern void set_res_apdu (uint8_t sw1, uint8_t sw2);
|
||||
extern void set_res_sw (uint8_t sw1, uint8_t sw2);
|
||||
extern uint16_t data_objects_number_of_bytes;
|
||||
|
||||
extern void gpg_data_scan (const uint8_t *p);
|
||||
@@ -98,7 +121,9 @@ extern void gpg_data_copy (const uint8_t *p);
|
||||
extern void gpg_do_get_data (uint16_t tag, int with_tag);
|
||||
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 void gpg_do_keygen (uint8_t kk_byte);
|
||||
|
||||
extern const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
|
||||
|
||||
|
||||
enum kind_of_key {
|
||||
@@ -107,30 +132,36 @@ enum kind_of_key {
|
||||
GPG_KEY_FOR_AUTHENTICATION,
|
||||
};
|
||||
|
||||
extern void flash_unlock (void);
|
||||
extern const uint8_t *flash_init (void);
|
||||
extern void flash_do_release (const uint8_t *);
|
||||
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
|
||||
extern uint8_t *flash_key_alloc (void);
|
||||
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
|
||||
const uint8_t *modulus);
|
||||
extern void flash_keystore_release (void);
|
||||
extern void flash_set_data_pool_last (const uint8_t *p);
|
||||
extern void flash_clear_halfword (uint32_t addr);
|
||||
extern void flash_increment_counter (uint8_t counter_tag_nr);
|
||||
extern void flash_reset_counter (uint8_t counter_tag_nr);
|
||||
|
||||
#define FILEID_CH_CERTIFICATE 0
|
||||
#define FILEID_RANDOM 1
|
||||
#define FILEID_SERIAL_NO 2
|
||||
#define FILEID_SERIAL_NO 0
|
||||
#define FILEID_UPDATE_KEY_0 1
|
||||
#define FILEID_UPDATE_KEY_1 2
|
||||
#define FILEID_UPDATE_KEY_2 3
|
||||
#define FILEID_UPDATE_KEY_3 4
|
||||
#define FILEID_CH_CERTIFICATE 5
|
||||
extern int flash_erase_binary (uint8_t file_id);
|
||||
extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t len, uint16_t offset);
|
||||
|
||||
#define FLASH_CH_CERTIFICATE_SIZE 2048
|
||||
|
||||
/* Linker set these two symbols */
|
||||
extern uint8_t ch_certificate_start;
|
||||
extern uint8_t random_bits_start;
|
||||
|
||||
#define KEY_MAGIC_LEN 8
|
||||
#define KEY_CONTENT_LEN 256 /* p and q */
|
||||
#define GNUK_MAGIC "Gnuk KEY"
|
||||
#define INITIAL_VECTOR_SIZE 16
|
||||
#define DATA_ENCRYPTION_KEY_SIZE 16
|
||||
|
||||
/* encrypted data content */
|
||||
struct key_data {
|
||||
@@ -139,22 +170,21 @@ struct key_data {
|
||||
|
||||
struct key_data_internal {
|
||||
uint8_t data[KEY_CONTENT_LEN]; /* p and q */
|
||||
uint32_t check;
|
||||
uint32_t random;
|
||||
char magic[KEY_MAGIC_LEN];
|
||||
uint8_t checksum[DATA_ENCRYPTION_KEY_SIZE];
|
||||
};
|
||||
|
||||
#define ADDITIONAL_DATA_SIZE 16
|
||||
#define DATA_ENCRYPTION_KEY_SIZE 16
|
||||
struct prvkey_data {
|
||||
const uint8_t *key_addr;
|
||||
/*
|
||||
* CRM: [C]heck, [R]andom, and [M]agic in struct key_data_internal
|
||||
*
|
||||
* IV: Initial Vector
|
||||
*/
|
||||
uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE];
|
||||
uint8_t iv[INITIAL_VECTOR_SIZE];
|
||||
/*
|
||||
* DEK: Data Encryption Key
|
||||
* Checksum
|
||||
*/
|
||||
uint8_t checksum_encrypted[DATA_ENCRYPTION_KEY_SIZE];
|
||||
/*
|
||||
* DEK (Data Encryption Key) encrypted
|
||||
*/
|
||||
uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; /* For user */
|
||||
uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; /* For resetcode */
|
||||
@@ -165,12 +195,14 @@ struct prvkey_data {
|
||||
#define BY_RESETCODE 2
|
||||
#define BY_ADMIN 3
|
||||
|
||||
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const uint8_t *modulus);
|
||||
extern void s2k (int who, const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32]);
|
||||
|
||||
|
||||
#define KEYSTRING_PASSLEN_SIZE 1
|
||||
#define KEYSTRING_SALT_SIZE 8 /* optional */
|
||||
#define KEYSTRING_ITER_SIZE 1 /* optional */
|
||||
#define KEYSTRING_MD_SIZE 20
|
||||
#define KEYSTRING_MD_SIZE 32
|
||||
#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 \
|
||||
@@ -205,6 +237,9 @@ extern int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *);
|
||||
extern const uint8_t *modulus_calc (const uint8_t *, int);
|
||||
extern void modulus_free (const uint8_t *);
|
||||
extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
|
||||
extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash,
|
||||
const uint8_t *signature);
|
||||
extern const uint8_t *rsa_genkey (void);
|
||||
|
||||
extern const uint8_t *gpg_do_read_simple (uint8_t);
|
||||
extern void gpg_do_write_simple (uint8_t, const uint8_t *, int);
|
||||
@@ -272,7 +307,7 @@ extern uint8_t admin_authorized;
|
||||
/*
|
||||
* Representation of Boolean object:
|
||||
* 0: No record in flash memory
|
||||
* 1: 0xc?00
|
||||
* 1: 0xf000
|
||||
*/
|
||||
#define NR_BOOL_PW1_LIFETIME 0xf0
|
||||
/*
|
||||
@@ -281,7 +316,7 @@ extern uint8_t admin_authorized;
|
||||
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
|
||||
/*
|
||||
* Representation of 123-counters:
|
||||
* 0: No record in flash memory
|
||||
* 0: No record in flash memory
|
||||
* 1: 0xfe?? 0xffff
|
||||
* 2: 0xfe?? 0xc3c3
|
||||
* 3: 0xfe?? 0x0000
|
||||
@@ -298,11 +333,11 @@ extern const uint8_t *random_bytes_get (void);
|
||||
extern void random_bytes_free (const uint8_t *);
|
||||
/* 4-byte salt */
|
||||
extern uint32_t get_salt (void);
|
||||
/* iterator returning a byta at a time */
|
||||
extern uint8_t random_byte (void *arg);
|
||||
|
||||
extern uint32_t hardclock (void);
|
||||
|
||||
extern void set_led (int);
|
||||
|
||||
#define NUM_ALL_PRV_KEYS 3 /* SIG, DEC and AUT */
|
||||
|
||||
extern uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
|
||||
@@ -330,17 +365,31 @@ extern void flash_bool_write_internal (const uint8_t *p, int nr);
|
||||
extern void flash_cnt123_write_internal (const uint8_t *p, int which, int v);
|
||||
extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len);
|
||||
|
||||
extern const unsigned char *unique_device_id (void);
|
||||
extern const uint8_t gnukStringSerial[];
|
||||
|
||||
#define LED_ONESHOT ((eventmask_t)1)
|
||||
#define LED_TWOSHOTS ((eventmask_t)2)
|
||||
#define LED_SHOW_STATUS ((eventmask_t)4)
|
||||
#define LED_START_COMMAND ((eventmask_t)8)
|
||||
#define LED_FINISH_COMMAND ((eventmask_t)16)
|
||||
#define LED_FATAL ((eventmask_t)32)
|
||||
extern void led_blink (int spec);
|
||||
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
# if defined(PINPAD_CIR_SUPPORT)
|
||||
extern void cir_ext_disable (void);
|
||||
extern void cir_ext_enable (void);
|
||||
#elif defined(PINPAD_DIAL_SUPPORT)
|
||||
# elif defined(PINPAD_DIAL_SUPPORT)
|
||||
extern void dial_sw_disable (void);
|
||||
extern void dial_sw_enable (void);
|
||||
#endif
|
||||
# elif defined(PINPAD_DND_SUPPORT)
|
||||
extern uint8_t media_available;
|
||||
extern void msc_init (void);
|
||||
extern void msc_media_insert_change (int available);
|
||||
extern int msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size);
|
||||
extern int msc_scsi_read (uint32_t lba, const uint8_t **sector_p);
|
||||
extern void msc_scsi_stop (uint8_t code);
|
||||
# endif
|
||||
#define PIN_INPUT_CURRENT 1
|
||||
#define PIN_INPUT_NEW 2
|
||||
#define PIN_INPUT_CONFIRM 3
|
||||
@@ -348,5 +397,8 @@ extern void dial_sw_enable (void);
|
||||
extern uint8_t pin_input_buffer[MAX_PIN_CHARS];
|
||||
extern uint8_t pin_input_len;
|
||||
|
||||
extern msg_t pin_main (void *arg);
|
||||
extern int pinpad_getline (int msg_code, systime_t timeout);
|
||||
|
||||
#endif
|
||||
|
||||
extern uint8_t _regnual_start, __heap_end__;
|
||||
|
||||
@@ -27,16 +27,21 @@
|
||||
/*
|
||||
* ST32F103 memory setup.
|
||||
*/
|
||||
__main_stack_size__ = 0x0200;
|
||||
__main_stack_size__ = 0x0400;
|
||||
__process_stack_size__ = 0x0200;
|
||||
__stacks_total_size__ = __main_stack_size__ + __process_stack_size__;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
flash : org = @ORIGIN@, len = @FLASH_SIZE@k
|
||||
flash0 : org = @ORIGIN@, len = 4k
|
||||
flash : org = @ORIGIN@+0x1000, len = @FLASH_SIZE@k - 4k
|
||||
ram : org = 0x20000000, len = 20k
|
||||
}
|
||||
|
||||
/* __flash_start__: flash ROM start address regardless of DFU_SUPPORT */
|
||||
__flash_start__ = 0x08001000;
|
||||
__flash_end__ = ORIGIN(flash) + LENGTH(flash);
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = LENGTH(ram);
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
@@ -45,6 +50,22 @@ SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
.sys : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
_sys = .;
|
||||
KEEP(*(.vectors))
|
||||
. = ALIGN(16);
|
||||
*(.sys.version)
|
||||
sys.o(.text)
|
||||
sys.o(.text.*)
|
||||
sys.o(.rodata)
|
||||
sys.o(.rodata.*)
|
||||
. = ALIGN(1024);
|
||||
*(.sys.0)
|
||||
*(.sys.1)
|
||||
*(.sys.2)
|
||||
} > flash0
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
_text = .;
|
||||
@@ -114,7 +135,10 @@ SECTIONS
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
. = ALIGN(512);
|
||||
_regnual_start = .;
|
||||
|
||||
@CERTDO_SUPPORT_START@
|
||||
.gnuk_ch_certificate :
|
||||
{
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
@@ -123,9 +147,11 @@ SECTIONS
|
||||
. += 1920;
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
} > flash =0xffffffff
|
||||
@CERTDO_SUPPORT_END@
|
||||
|
||||
.gnuk_flash :
|
||||
{
|
||||
. = ALIGN (@FLASH_PAGE_SIZE@);
|
||||
_data_pool = .;
|
||||
KEEP(*(.gnuk_data))
|
||||
. = ALIGN(@FLASH_PAGE_SIZE@);
|
||||
@@ -133,6 +159,9 @@ SECTIONS
|
||||
_keystore_pool = .;
|
||||
. += 512*3;
|
||||
. = ALIGN(@FLASH_PAGE_SIZE@);
|
||||
_updatekey_store = .;
|
||||
. += 1024;
|
||||
. = ALIGN(@FLASH_PAGE_SIZE@);
|
||||
} > flash =0xffffffff
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
uint32_t
|
||||
hardclock (void)
|
||||
{
|
||||
uint32_t r = SysTick->VAL;
|
||||
|
||||
DEBUG_INFO ("Random: ");
|
||||
DEBUG_WORD (r);
|
||||
return r;
|
||||
}
|
||||
344
src/main.c
344
src/main.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* main.c - main routine of Gnuk
|
||||
*
|
||||
* Copyright (C) 2010 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -22,16 +22,12 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "usb_lib.h"
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "sys.h"
|
||||
#include "gnuk.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb_istr.h"
|
||||
#include "usb_desc.h"
|
||||
#include "hw_config.h"
|
||||
#include "usb_pwr.h"
|
||||
#include "usb-cdc.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
struct stdout {
|
||||
@@ -106,10 +102,14 @@ STDOUTthread (void *arg)
|
||||
|
||||
p = stdout.str;
|
||||
len = stdout.size;
|
||||
while (len > 0)
|
||||
while (1)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (len == 0)
|
||||
if (count_in != VIRTUAL_COM_PORT_DATA_SIZE)
|
||||
break;
|
||||
|
||||
if (len < VIRTUAL_COM_PORT_DATA_SIZE)
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
@@ -128,8 +128,7 @@ STDOUTthread (void *arg)
|
||||
|
||||
chEvtClear (EV_TX_READY);
|
||||
|
||||
USB_SIL_Write (EP3_IN, buffer_in, count_in);
|
||||
SetEPTxValid (ENDP3);
|
||||
usb_lld_write (ENDP3, buffer_in, count_in);
|
||||
|
||||
chEvtWaitOne (EV_TX_READY);
|
||||
}
|
||||
@@ -143,6 +142,19 @@ STDOUTthread (void *arg)
|
||||
goto again;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
EP3_IN_Callback (void)
|
||||
{
|
||||
if (stdout_thread)
|
||||
chEvtSignalI (stdout_thread, EV_TX_READY);
|
||||
}
|
||||
|
||||
void
|
||||
EP5_OUT_Callback (void)
|
||||
{
|
||||
usb_lld_rx_enable (ENDP5);
|
||||
}
|
||||
#else
|
||||
void
|
||||
_write (const char *s, int size)
|
||||
@@ -158,13 +170,15 @@ extern msg_t USBthread (void *arg);
|
||||
/*
|
||||
* main thread does 1-bit LED display output
|
||||
*/
|
||||
#define LED_TIMEOUT_INTERVAL MS2ST(100)
|
||||
#define LED_TIMEOUT_ZERO MS2ST(50)
|
||||
#define LED_TIMEOUT_ONE MS2ST(200)
|
||||
#define LED_TIMEOUT_STOP MS2ST(500)
|
||||
#define MAIN_TIMEOUT_INTERVAL MS2ST(5000)
|
||||
|
||||
#define LED_TIMEOUT_INTERVAL MS2ST(75)
|
||||
#define LED_TIMEOUT_ZERO MS2ST(25)
|
||||
#define LED_TIMEOUT_ONE MS2ST(100)
|
||||
#define LED_TIMEOUT_STOP MS2ST(200)
|
||||
|
||||
|
||||
#define ID_OFFSET 12
|
||||
#define ID_OFFSET 24
|
||||
static void
|
||||
device_initialize_once (void)
|
||||
{
|
||||
@@ -182,7 +196,7 @@ device_initialize_once (void)
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
uint8_t b = u[i];
|
||||
uint8_t nibble;
|
||||
uint8_t nibble;
|
||||
|
||||
nibble = (b >> 4);
|
||||
nibble += (nibble >= 10 ? ('A' - 10) : '0');
|
||||
@@ -196,6 +210,115 @@ device_initialize_once (void)
|
||||
|
||||
static volatile uint8_t fatal_code;
|
||||
|
||||
static Thread *main_thread;
|
||||
|
||||
static void display_fatal_code (void)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (1);
|
||||
if (fatal_code & 1)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if (fatal_code & 2)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL*10);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t led_inverted;
|
||||
|
||||
static eventmask_t emit_led (int on_time, int off_time)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
set_led (!led_inverted);
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, on_time);
|
||||
set_led (led_inverted);
|
||||
if (m) return m;
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, off_time)))
|
||||
return m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static eventmask_t display_status_code (void)
|
||||
{
|
||||
enum icc_state icc_state;
|
||||
eventmask_t m;
|
||||
|
||||
if (icc_state_p == NULL)
|
||||
icc_state = ICC_STATE_START;
|
||||
else
|
||||
icc_state = *icc_state_p;
|
||||
|
||||
if (icc_state == ICC_STATE_START)
|
||||
return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
|
||||
else
|
||||
/* GPGthread running */
|
||||
{
|
||||
if ((m = emit_led ((auth_status & AC_ADMIN_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
if ((m = emit_led ((auth_status & AC_OTHER_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
if ((m = emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
|
||||
if (icc_state == ICC_STATE_WAIT)
|
||||
{
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP * 2)))
|
||||
return m;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL)))
|
||||
return m;
|
||||
|
||||
if ((m = emit_led (icc_state == ICC_STATE_RECEIVE?
|
||||
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
||||
LED_TIMEOUT_STOP)))
|
||||
return m;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
led_blink (int spec)
|
||||
{
|
||||
chEvtSignal (main_thread, spec);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Entry point.
|
||||
*
|
||||
@@ -203,19 +326,28 @@ static volatile uint8_t fatal_code;
|
||||
* See the hwinit1_common function.
|
||||
*/
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int count = 0;
|
||||
unsigned int count = 0;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
main_thread = chThdSelf ();
|
||||
|
||||
flash_unlock ();
|
||||
device_initialize_once ();
|
||||
usb_lld_init ();
|
||||
USB_Init ();
|
||||
usb_lld_init (Config_Descriptor.Descriptor[7]);
|
||||
random_init ();
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (bDeviceState != UNCONNECTED)
|
||||
break;
|
||||
|
||||
chThdSleepMilliseconds (250);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
stdout_init ();
|
||||
|
||||
@@ -229,107 +361,53 @@ main (int argc, char **argv)
|
||||
chThdCreateStatic (waUSBthread, sizeof(waUSBthread),
|
||||
NORMALPRIO, USBthread, NULL);
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
msc_init ();
|
||||
#endif
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
if (icc_state_p != NULL && *icc_state_p == ICC_STATE_EXEC_REQUESTED)
|
||||
break;
|
||||
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, MAIN_TIMEOUT_INTERVAL);
|
||||
got_it:
|
||||
count++;
|
||||
|
||||
if (fatal_code != 0)
|
||||
switch (m)
|
||||
{
|
||||
case LED_ONESHOT:
|
||||
if ((m = emit_led (MS2ST (100), MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
||||
break;
|
||||
case LED_TWOSHOTS:
|
||||
if ((m = emit_led (MS2ST (50), MS2ST (50)))) goto got_it;
|
||||
if ((m = emit_led (MS2ST (50), MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
||||
break;
|
||||
case LED_SHOW_STATUS:
|
||||
if ((count & 0x07) != 0) continue; /* Display once for eight times */
|
||||
if ((m = display_status_code ())) goto got_it;
|
||||
break;
|
||||
case LED_START_COMMAND:
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
led_inverted = 1;
|
||||
break;
|
||||
case LED_FINISH_COMMAND:
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP);
|
||||
led_inverted = 0;
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (1);
|
||||
if (fatal_code & 1)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if (fatal_code & 2)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
}
|
||||
|
||||
if (bDeviceState != CONFIGURED)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 3);
|
||||
if (m)
|
||||
goto got_it;
|
||||
break;
|
||||
case LED_FATAL:
|
||||
display_fatal_code ();
|
||||
break;
|
||||
default:
|
||||
if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP)))
|
||||
goto got_it;
|
||||
break;
|
||||
}
|
||||
else
|
||||
/* Device configured */
|
||||
if (icc_state == ICC_STATE_START)
|
||||
{
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 3);
|
||||
}
|
||||
else
|
||||
/* GPGthread running */
|
||||
{
|
||||
set_led (1);
|
||||
if ((auth_status & AC_ADMIN_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if ((auth_status & AC_OTHER_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0)
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
else
|
||||
chThdSleep (LED_TIMEOUT_ZERO);
|
||||
|
||||
if (icc_state == ICC_STATE_WAIT)
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP * 2);
|
||||
}
|
||||
else if (icc_state == ICC_STATE_RECEIVE)
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_ONE);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
set_led (1);
|
||||
chThdSleep (LED_TIMEOUT_STOP);
|
||||
set_led (0);
|
||||
chThdSleep (LED_TIMEOUT_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MORE
|
||||
if (bDeviceState == CONFIGURED && (count % 10) == 0)
|
||||
@@ -342,6 +420,41 @@ main (int argc, char **argv)
|
||||
#endif
|
||||
}
|
||||
|
||||
set_led (1);
|
||||
usb_lld_shutdown ();
|
||||
/* Disable SysTick */
|
||||
SysTick->CTRL = 0;
|
||||
/* Disable all interrupts */
|
||||
port_disable ();
|
||||
/* Set vector */
|
||||
SCB->VTOR = (uint32_t)&_regnual_start;
|
||||
#ifdef DFU_SUPPORT
|
||||
#define FLASH_SYS_START_ADDR 0x08000000
|
||||
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
|
||||
{
|
||||
extern uint8_t _sys;
|
||||
uint32_t addr;
|
||||
handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
|
||||
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10];
|
||||
|
||||
/* Kill DFU */
|
||||
for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
|
||||
addr += FLASH_PAGE_SIZE)
|
||||
flash_erase_page (addr);
|
||||
|
||||
/* copy system service routines */
|
||||
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
|
||||
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
(*func) (*((void (**)(void))(&_regnual_start+4)));
|
||||
for (;;);
|
||||
}
|
||||
#else
|
||||
/* Leave Gnuk to exec reGNUal */
|
||||
flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));
|
||||
#endif
|
||||
|
||||
/* Never reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -349,6 +462,7 @@ void
|
||||
fatal (uint8_t code)
|
||||
{
|
||||
fatal_code = code;
|
||||
chEvtSignal (main_thread, LED_FATAL);
|
||||
_write ("fatal\r\n", 7);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
@@ -32,15 +32,15 @@ static Thread *rng_thread;
|
||||
|
||||
/* Total number of channels to be sampled by a single ADC operation.*/
|
||||
#define ADC_GRP1_NUM_CHANNELS 2
|
||||
|
||||
|
||||
/* Depth of the conversion buffer, channels are sampled one time each.*/
|
||||
#define ADC_GRP1_BUF_DEPTH 4
|
||||
|
||||
|
||||
/*
|
||||
* ADC samples buffer.
|
||||
*/
|
||||
static adcsample_t samp[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
|
||||
|
||||
|
||||
static void adccb (adcsample_t *buffer, size_t n);
|
||||
|
||||
/*
|
||||
|
||||
431
src/openpgp-do.c
431
src/openpgp-do.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -25,12 +25,12 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "sys.h"
|
||||
#include "gnuk.h"
|
||||
#include "openpgp.h"
|
||||
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/aes.h"
|
||||
#include "polarssl/sha1.h"
|
||||
|
||||
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
|
||||
static const uint8_t *pw_err_counter_p[3];
|
||||
@@ -41,6 +41,17 @@ gpg_pw_get_err_counter (uint8_t which)
|
||||
return flash_cnt123_get_value (pw_err_counter_p[which]);
|
||||
}
|
||||
|
||||
int
|
||||
gpg_pw_get_retry_counter (int who)
|
||||
{
|
||||
if (who == 0x81 || who == 0x82)
|
||||
return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_PW1);
|
||||
else if (who == 0x83)
|
||||
return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_PW3);
|
||||
else
|
||||
return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_RC);
|
||||
}
|
||||
|
||||
int
|
||||
gpg_pw_locked (uint8_t which)
|
||||
{
|
||||
@@ -77,12 +88,11 @@ uint16_t data_objects_number_of_bytes;
|
||||
static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
|
||||
10,
|
||||
0x00,
|
||||
0x31, 0x80, /* Full DF name */
|
||||
0x31, 0x84, /* Full DF name, GET DATA, MF */
|
||||
0x73,
|
||||
0x80, 0x01, 0x40, /* Full DF name */
|
||||
0x80, 0x01, 0x80, /* Full DF name */
|
||||
/* 1-byte */
|
||||
/* No command chaining */
|
||||
/* Extended Lc and Le */
|
||||
/* Command chaining, No extended Lc and Le */
|
||||
0x00, 0x90, 0x00 /* Status info (no life cycle management) */
|
||||
};
|
||||
|
||||
@@ -90,23 +100,24 @@ static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = {
|
||||
static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
|
||||
10,
|
||||
0x30, /*
|
||||
* No SM, No get challenge,
|
||||
* 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 */
|
||||
0x07, 0xfe, /* max. length of cardholder certificate (2KB - 2)*/
|
||||
/* Max. length of command data */
|
||||
(MAX_CMD_APDU_SIZE>>8), (MAX_CMD_APDU_SIZE&0xff),
|
||||
/* Max. length of response data */
|
||||
#if 0
|
||||
(MAX_RES_APDU_SIZE>>8), (MAX_RES_APDU_SIZE&0xff),
|
||||
0x00, 0x00, /* Max get challenge (0: Get challenge not supported) */
|
||||
#ifdef CERTDO_SUPPORT
|
||||
0x08, 0x00, /* max. length of cardholder certificate (2KiB) */
|
||||
#else
|
||||
0x08, 0x00, /* the case of cardholder ceritificate */
|
||||
0x00, 0x00,
|
||||
#endif
|
||||
/* Max. length of command APDU data */
|
||||
0x00, 0xff,
|
||||
/* Max. length of response APDU data */
|
||||
0x01, 0x00,
|
||||
};
|
||||
|
||||
/* Algorithm Attributes */
|
||||
@@ -162,6 +173,17 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gpg_reset_digital_signature_counter (void)
|
||||
{
|
||||
if (digital_signature_counter != 0)
|
||||
{
|
||||
flash_put_data (NR_COUNTER_DS);
|
||||
flash_put_data (NR_COUNTER_DS_LSB);
|
||||
digital_signature_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gpg_increment_digital_signature_counter (void)
|
||||
{
|
||||
@@ -413,10 +435,12 @@ do_kgtime_all (uint16_t tag, int with_tag)
|
||||
}
|
||||
|
||||
const uint8_t openpgpcard_aid[] = {
|
||||
0xd2, 0x76, 0x00, 0x01, 0x24, 0x01,
|
||||
0x02, 0x00, /* Version 2.0 */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */
|
||||
0xd2, 0x76, /* D: National, 276: DEU ISO 3166-1 */
|
||||
0x00, 0x01, 0x24, /* Registered Application Provider Identifier */
|
||||
0x01, /* Application: OpenPGPcard */
|
||||
0x02, 0x00, /* Version 2.0 */
|
||||
/* v. id */ /* serial number */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -529,7 +553,7 @@ proc_resetting_code (const uint8_t *data, int len)
|
||||
|
||||
newpw_len = len;
|
||||
newpw = data;
|
||||
sha1 (newpw, newpw_len, new_ks);
|
||||
s2k (BY_RESETCODE, newpw, newpw_len, new_ks);
|
||||
new_ks0[0] = newpw_len;
|
||||
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
|
||||
if (r <= -2)
|
||||
@@ -558,40 +582,58 @@ proc_resetting_code (const uint8_t *data, int len)
|
||||
}
|
||||
|
||||
static void
|
||||
encrypt (const uint8_t *key_str, uint8_t *data, int len)
|
||||
encrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
|
||||
{
|
||||
aes_context aes;
|
||||
uint8_t iv[16];
|
||||
uint8_t iv0[INITIAL_VECTOR_SIZE];
|
||||
int iv_offset;
|
||||
|
||||
DEBUG_INFO ("ENC\r\n");
|
||||
DEBUG_BINARY (data, len);
|
||||
|
||||
aes_setkey_enc (&aes, key_str, 128);
|
||||
memset (iv, 0, 16);
|
||||
aes_setkey_enc (&aes, key, 128);
|
||||
memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
|
||||
iv_offset = 0;
|
||||
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv, data, data);
|
||||
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv0, data, data);
|
||||
}
|
||||
|
||||
/* Signing, Decryption, and Authentication */
|
||||
struct key_data kd[3];
|
||||
|
||||
static void
|
||||
decrypt (const uint8_t *key_str, uint8_t *data, int len)
|
||||
decrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
|
||||
{
|
||||
aes_context aes;
|
||||
uint8_t iv[16];
|
||||
uint8_t iv0[INITIAL_VECTOR_SIZE];
|
||||
int iv_offset;
|
||||
|
||||
aes_setkey_enc (&aes, key_str, 128);
|
||||
memset (iv, 0, 16);
|
||||
aes_setkey_enc (&aes, key, 128); /* This is setkey_enc, because of CFB. */
|
||||
memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
|
||||
iv_offset = 0;
|
||||
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv, data, data);
|
||||
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv0, data, data);
|
||||
|
||||
DEBUG_INFO ("DEC\r\n");
|
||||
DEBUG_BINARY (data, len);
|
||||
}
|
||||
|
||||
static void
|
||||
encrypt_dek (const uint8_t *key_string, uint8_t *dek)
|
||||
{
|
||||
aes_context aes;
|
||||
|
||||
aes_setkey_enc (&aes, key_string, 128);
|
||||
aes_crypt_ecb (&aes, AES_ENCRYPT, dek, dek);
|
||||
}
|
||||
|
||||
static void
|
||||
decrypt_dek (const uint8_t *key_string, uint8_t *dek)
|
||||
{
|
||||
aes_context aes;
|
||||
|
||||
aes_setkey_dec (&aes, key_string, 128);
|
||||
aes_crypt_ecb (&aes, AES_DECRYPT, dek, dek);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
get_do_ptr_nr_for_kk (enum kind_of_key kk)
|
||||
{
|
||||
@@ -613,6 +655,25 @@ gpg_do_clear_prvkey (enum kind_of_key kk)
|
||||
memset ((void *)&kd[kk], 0, sizeof (struct key_data));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
compute_key_data_checksum (struct key_data_internal *kdi, int check_or_calc)
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t d[4] = { 0, 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < KEY_CONTENT_LEN / sizeof (uint32_t); i++)
|
||||
d[i&3] ^= *(uint32_t *)(&kdi->data[i*4]);
|
||||
|
||||
if (check_or_calc == 0) /* store */
|
||||
{
|
||||
memcpy (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
else /* check */
|
||||
return memcmp (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 on success,
|
||||
* 0 if none,
|
||||
@@ -623,66 +684,58 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
|
||||
{
|
||||
uint8_t nr = get_do_ptr_nr_for_kk (kk);
|
||||
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
|
||||
uint8_t *key_addr;
|
||||
const uint8_t *key_addr;
|
||||
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
|
||||
const uint8_t *iv;
|
||||
struct key_data_internal kdi;
|
||||
|
||||
DEBUG_INFO ("Loading private key: ");
|
||||
DEBUG_BYTE (kk);
|
||||
|
||||
if (do_data == NULL)
|
||||
return 0;
|
||||
|
||||
key_addr = *(uint8_t **)&(do_data)[1];
|
||||
key_addr = *(const uint8_t **)&(do_data)[1]; /* Possible unaligned access */
|
||||
memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
|
||||
memcpy (((uint8_t *)&kdi.check), do_data+5, ADDITIONAL_DATA_SIZE);
|
||||
iv = do_data+5;
|
||||
memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
memcpy (dek, do_data+5+16*(who+1), DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt_dek (keystring, dek);
|
||||
|
||||
decrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
if (memcmp (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
|
||||
decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
memset (dek, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
if (!compute_key_data_checksum (&kdi, 1))
|
||||
{
|
||||
DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
|
||||
return -1;
|
||||
}
|
||||
/* more sanity check??? */
|
||||
|
||||
memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN);
|
||||
DEBUG_BINARY (&kd[kk], KEY_CONTENT_LEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
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/4; i++)
|
||||
check += data[i];
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
static int8_t num_prv_keys;
|
||||
|
||||
static int
|
||||
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
const uint8_t *keystring_admin)
|
||||
const uint8_t *keystring_admin, const uint8_t *modulus)
|
||||
{
|
||||
uint8_t nr = get_do_ptr_nr_for_kk (kk);
|
||||
const uint8_t *p;
|
||||
int r;
|
||||
const uint8_t *modulus;
|
||||
struct prvkey_data *pd;
|
||||
uint8_t *key_addr;
|
||||
const uint8_t *dek;
|
||||
const uint8_t *dek, *iv;
|
||||
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
|
||||
const uint8_t *ks_pw1;
|
||||
const uint8_t *ks_rc;
|
||||
struct key_data_internal kdi;
|
||||
|
||||
#if 0
|
||||
assert (key_len == KEY_CONTENT_LEN);
|
||||
#endif
|
||||
int modulus_allocated_here = 0;
|
||||
uint8_t ks_pw1_len = 0;
|
||||
uint8_t ks_rc_len = 0;
|
||||
|
||||
DEBUG_INFO ("Key import\r\n");
|
||||
DEBUG_SHORT (key_len);
|
||||
@@ -691,15 +744,23 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
/* No replace support, you need to remove it first. */
|
||||
return -1;
|
||||
|
||||
if (key_len != KEY_CONTENT_LEN)
|
||||
return -1;
|
||||
|
||||
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
|
||||
if (pd == NULL)
|
||||
return -1;
|
||||
|
||||
modulus = modulus_calc (key_data, key_len);
|
||||
if (modulus == NULL)
|
||||
{
|
||||
free (pd);
|
||||
return -1;
|
||||
modulus = modulus_calc (key_data, key_len);
|
||||
if (modulus == NULL)
|
||||
{
|
||||
free (pd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
modulus_allocated_here = 1;
|
||||
}
|
||||
|
||||
DEBUG_INFO ("Getting keystore address...\r\n");
|
||||
@@ -707,7 +768,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
if (key_addr == NULL)
|
||||
{
|
||||
free (pd);
|
||||
modulus_free (modulus);
|
||||
if (modulus_allocated_here)
|
||||
modulus_free (modulus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -715,21 +777,21 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
DEBUG_WORD ((uint32_t)key_addr);
|
||||
|
||||
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
|
||||
kdi.check = calc_check32 (key_data, KEY_CONTENT_LEN);
|
||||
kdi.random = get_salt ();
|
||||
memcpy (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN);
|
||||
compute_key_data_checksum (&kdi, 0);
|
||||
|
||||
dek = random_bytes_get (); /* 16-byte random bytes */
|
||||
dek = random_bytes_get (); /* 32-byte random bytes */
|
||||
iv = dek + DATA_ENCRYPTION_KEY_SIZE;
|
||||
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);
|
||||
|
||||
encrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
encrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
|
||||
|
||||
r = flash_key_write (key_addr, kdi.data, modulus);
|
||||
modulus_free (modulus);
|
||||
if (modulus_allocated_here)
|
||||
modulus_free (modulus);
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
@@ -739,32 +801,33 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
}
|
||||
|
||||
pd->key_addr = key_addr;
|
||||
memcpy (pd->crm_encrypted, (uint8_t *)&kdi.check, ADDITIONAL_DATA_SIZE);
|
||||
|
||||
if (kk == GPG_KEY_FOR_SIGNING)
|
||||
ac_reset_pso_cds ();
|
||||
else
|
||||
ac_reset_other ();
|
||||
memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE);
|
||||
memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
if (ks_pw1)
|
||||
encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
|
||||
{
|
||||
ks_pw1_len = ks_pw1[0];
|
||||
encrypt_dek (ks_pw1+1, pd->dek_encrypted_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t ks123_pw1[KEYSTRING_SIZE_PW1];
|
||||
uint8_t ks[KEYSTRING_MD_SIZE];
|
||||
|
||||
ks123_pw1[0] = strlen (OPENPGP_CARD_INITIAL_PW1);
|
||||
sha1 ((uint8_t *)OPENPGP_CARD_INITIAL_PW1,
|
||||
strlen (OPENPGP_CARD_INITIAL_PW1), ks123_pw1+1);
|
||||
encrypt (ks123_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
|
||||
s2k (BY_USER, (const uint8_t *)OPENPGP_CARD_INITIAL_PW1,
|
||||
strlen (OPENPGP_CARD_INITIAL_PW1), ks);
|
||||
encrypt_dek (ks, pd->dek_encrypted_1);
|
||||
}
|
||||
|
||||
if (ks_rc)
|
||||
encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE);
|
||||
{
|
||||
ks_rc_len = ks_rc[0];
|
||||
encrypt_dek (ks_rc+1, pd->dek_encrypted_2);
|
||||
}
|
||||
else
|
||||
memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
if (keystring_admin)
|
||||
encrypt (keystring_admin, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
|
||||
encrypt_dek (keystring_admin, pd->dek_encrypted_3);
|
||||
else
|
||||
memset (pd->dek_encrypted_3, 0, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
@@ -779,17 +842,11 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
if (++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_pw1_len)
|
||||
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);
|
||||
}
|
||||
if (ks_rc_len)
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -814,19 +871,21 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
|
||||
if (pd == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy (pd, &(do_data)[1], sizeof (struct prvkey_data));
|
||||
dek_p = ((uint8_t *)pd) + 4 + ADDITIONAL_DATA_SIZE
|
||||
+ DATA_ENCRYPTION_KEY_SIZE * (who_old - 1);
|
||||
memcpy (pd, &do_data[1], sizeof (struct prvkey_data));
|
||||
flash_do_release (do_data);
|
||||
|
||||
dek_p = ((uint8_t *)pd) + 4 + INITIAL_VECTOR_SIZE
|
||||
+ DATA_ENCRYPTION_KEY_SIZE * who_old;
|
||||
memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt (old_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
encrypt (new_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt_dek (old_ks, dek);
|
||||
encrypt_dek (new_ks, dek);
|
||||
dek_p += DATA_ENCRYPTION_KEY_SIZE * (who_new - who_old);
|
||||
memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
do_ptr[nr - NR_DO__FIRST__] = NULL;
|
||||
p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
|
||||
do_ptr[nr - NR_DO__FIRST__] = p;
|
||||
|
||||
flash_do_release (do_data);
|
||||
free (pd);
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
@@ -835,13 +894,13 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
|
||||
}
|
||||
|
||||
/*
|
||||
* 4d, xx, xx: Extended Header List
|
||||
* 4d, xx, xx, xx: Extended Header List
|
||||
* b6 00 (SIG) / b8 00 (DEC) / a4 00 (AUT)
|
||||
* 7f48, xx: cardholder private key template
|
||||
* 91 xx
|
||||
* 92 xx
|
||||
* 93 xx
|
||||
* 5f48, xx: cardholder private key
|
||||
* 92 xx xx
|
||||
* 93 xx xx
|
||||
* 5f48, xx xx xx: cardholder private key
|
||||
*/
|
||||
static int
|
||||
proc_key_import (const uint8_t *data, int len)
|
||||
@@ -849,6 +908,7 @@ proc_key_import (const uint8_t *data, int len)
|
||||
int r;
|
||||
enum kind_of_key kk;
|
||||
const uint8_t *keystring_admin;
|
||||
const uint8_t *p = data;
|
||||
|
||||
if (admin_authorized == BY_ADMIN)
|
||||
keystring_admin = keystring_md_pw3;
|
||||
@@ -857,12 +917,31 @@ proc_key_import (const uint8_t *data, int len)
|
||||
|
||||
DEBUG_BINARY (data, len);
|
||||
|
||||
if (data[4] == 0xb6)
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
else if (data[4] == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
if (*p++ != 0x4d)
|
||||
return 0;
|
||||
|
||||
/* length field */
|
||||
if (*p == 0x82)
|
||||
p += 3;
|
||||
else if (*p == 0x81)
|
||||
p += 2;
|
||||
else
|
||||
p += 1;
|
||||
|
||||
if (*p == 0xb6)
|
||||
{
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
ac_reset_pso_cds ();
|
||||
gpg_reset_digital_signature_counter ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*p == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
ac_reset_other ();
|
||||
}
|
||||
|
||||
if (len <= 22)
|
||||
{ /* Deletion of the key */
|
||||
@@ -882,6 +961,11 @@ proc_key_import (const uint8_t *data, int len)
|
||||
/* 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);
|
||||
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_other ();
|
||||
if (admin_authorized == BY_USER)
|
||||
ac_reset_admin ();
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -889,7 +973,7 @@ proc_key_import (const uint8_t *data, int len)
|
||||
|
||||
/* It should starts with 00 01 00 01 (E) */
|
||||
/* Skip E, 4-byte */
|
||||
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin);
|
||||
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
else
|
||||
@@ -970,7 +1054,7 @@ gpg_do_table[] = {
|
||||
/ sizeof (struct do_table_entry))
|
||||
|
||||
/*
|
||||
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
|
||||
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
|
||||
*/
|
||||
void
|
||||
gpg_data_scan (const uint8_t *p_start)
|
||||
@@ -1020,18 +1104,18 @@ gpg_data_scan (const uint8_t *p_start)
|
||||
}
|
||||
else
|
||||
switch (nr)
|
||||
{
|
||||
case NR_BOOL_PW1_LIFETIME:
|
||||
pw1_lifetime_p = p - 1;
|
||||
p++;
|
||||
continue;
|
||||
case NR_COUNTER_123:
|
||||
p++;
|
||||
if (second_byte <= PW_ERR_PW3)
|
||||
pw_err_counter_p[second_byte] = p;
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
{
|
||||
case NR_BOOL_PW1_LIFETIME:
|
||||
pw1_lifetime_p = p - 1;
|
||||
p++;
|
||||
continue;
|
||||
case NR_COUNTER_123:
|
||||
p++;
|
||||
if (second_byte <= PW_ERR_PW3)
|
||||
pw_err_counter_p[second_byte] = p;
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1218,8 +1302,8 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
|
||||
}
|
||||
case DO_PROC_READWRITE:
|
||||
{
|
||||
int (*rw_func)(uint16_t, int, uint8_t *, int, int)
|
||||
= (int (*)(uint16_t, int, uint8_t *, int, int))do_p->obj;
|
||||
int (*rw_func)(uint16_t, int, const uint8_t *, int, int)
|
||||
= (int (*)(uint16_t, int, const uint8_t *, int, int))do_p->obj;
|
||||
|
||||
return rw_func (do_p->tag, with_tag, NULL, 0, 0);
|
||||
}
|
||||
@@ -1237,20 +1321,22 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
|
||||
void
|
||||
gpg_do_get_data (uint16_t tag, int with_tag)
|
||||
{
|
||||
#if defined(CERTDO_SUPPORT)
|
||||
if (tag == GPG_DO_CH_CERTIFICATE)
|
||||
{
|
||||
res_APDU_pointer = &ch_certificate_start;
|
||||
res_APDU_size = ((res_APDU_pointer[2] << 8) | res_APDU_pointer[3]);
|
||||
if (res_APDU_size == 0xffff)
|
||||
apdu.res_apdu_data = &ch_certificate_start;
|
||||
apdu.res_apdu_data_len = ((apdu.res_apdu_data[2] << 8) | apdu.res_apdu_data[3]);
|
||||
if (apdu.res_apdu_data_len == 0xffff)
|
||||
{
|
||||
res_APDU_pointer = NULL;
|
||||
apdu.res_apdu_data_len = 0;
|
||||
GPG_NO_RECORD ();
|
||||
}
|
||||
else
|
||||
/* Add length of (tag+len) and status word (0x9000) at the end */
|
||||
res_APDU_size += 4 + 2;
|
||||
/* Add length of (tag+len) */
|
||||
apdu.res_apdu_data_len += 4;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
const struct do_table_entry *do_p = get_do_entry (tag);
|
||||
|
||||
@@ -1266,9 +1352,8 @@ gpg_do_get_data (uint16_t tag, int with_tag)
|
||||
GPG_SECURITY_FAILURE ();
|
||||
else
|
||||
{
|
||||
*res_p++ = 0x90;
|
||||
*res_p++ = 0x00;
|
||||
res_APDU_size = res_p - res_APDU;
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1307,8 +1392,11 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
|
||||
flash_do_release (*do_data_p);
|
||||
|
||||
if (len == 0)
|
||||
/* make DO empty */
|
||||
*do_data_p = NULL;
|
||||
{
|
||||
/* make DO empty */
|
||||
*do_data_p = NULL;
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
else if (len > 255)
|
||||
GPG_MEMORY_FAILURE ();
|
||||
else
|
||||
@@ -1319,6 +1407,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
|
||||
GPG_MEMORY_FAILURE ();
|
||||
else
|
||||
{
|
||||
*do_data_p = NULL;
|
||||
*do_data_p = flash_do_write (nr, data, len);
|
||||
if (*do_data_p)
|
||||
GPG_SUCCESS ();
|
||||
@@ -1402,8 +1491,8 @@ gpg_do_public_key (uint8_t kk_byte)
|
||||
*res_p++ = 0x01; *res_p++ = 0x00; *res_p++ = 0x01;
|
||||
|
||||
/* Success */
|
||||
*res_p++ = 0x90; *res_p++ = 0x00;
|
||||
res_APDU_size = res_p - res_APDU;
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
@@ -1433,6 +1522,7 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
*do_data_p = NULL;
|
||||
*do_data_p = flash_do_write (nr, data, size);
|
||||
if (*do_data_p == NULL)
|
||||
flash_warning ("DO WRITE ERROR");
|
||||
@@ -1440,3 +1530,78 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
|
||||
else
|
||||
*do_data_p = NULL;
|
||||
}
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
void
|
||||
gpg_do_keygen (uint8_t kk_byte)
|
||||
{
|
||||
enum kind_of_key kk;
|
||||
const uint8_t *keystring_admin;
|
||||
const uint8_t *p_q_modulus;
|
||||
const uint8_t *p_q;
|
||||
const uint8_t *modulus;
|
||||
int r;
|
||||
|
||||
DEBUG_INFO ("Keygen\r\n");
|
||||
DEBUG_BYTE (kk_byte);
|
||||
|
||||
if (kk_byte == 0xb6)
|
||||
kk = GPG_KEY_FOR_SIGNING;
|
||||
else if (kk_byte == 0xb8)
|
||||
kk = GPG_KEY_FOR_DECRYPTION;
|
||||
else /* 0xa4 */
|
||||
kk = GPG_KEY_FOR_AUTHENTICATION;
|
||||
|
||||
if (admin_authorized == BY_ADMIN)
|
||||
keystring_admin = keystring_md_pw3;
|
||||
else
|
||||
keystring_admin = NULL;
|
||||
|
||||
p_q_modulus = rsa_genkey ();
|
||||
if (p_q_modulus == NULL)
|
||||
{
|
||||
GPG_MEMORY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
|
||||
p_q = p_q_modulus;
|
||||
modulus = p_q_modulus + KEY_CONTENT_LEN;
|
||||
|
||||
r = gpg_do_write_prvkey (kk, p_q, KEY_CONTENT_LEN,
|
||||
keystring_admin, modulus);
|
||||
free ((uint8_t *)p_q_modulus);
|
||||
if (r < 0)
|
||||
{
|
||||
GPG_ERROR ();
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_INFO ("Calling gpg_do_public_key...\r\n");
|
||||
|
||||
if (kk == GPG_KEY_FOR_SIGNING)
|
||||
{
|
||||
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
uint8_t keystring[KEYSTRING_MD_SIZE];
|
||||
const uint8_t *ks;
|
||||
|
||||
/* GnuPG expects it's ready for signing. */
|
||||
/* Don't call ac_reset_pso_cds here, but load the private key */
|
||||
|
||||
if (ks_pw1)
|
||||
ks = ks_pw1+1;
|
||||
else
|
||||
{
|
||||
const uint8_t * pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
|
||||
|
||||
s2k (BY_USER, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring);
|
||||
ks = keystring;
|
||||
}
|
||||
|
||||
gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, ks);
|
||||
}
|
||||
else
|
||||
ac_reset_other ();
|
||||
|
||||
gpg_do_public_key (kk_byte);
|
||||
}
|
||||
#endif
|
||||
|
||||
845
src/openpgp.c
845
src/openpgp.c
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,12 @@
|
||||
#define GPG_MEMORY_FAILURE() set_res_apdu (0x65, 0x81)
|
||||
#define GPG_SECURITY_FAILURE() set_res_apdu (0x69, 0x82)
|
||||
#define GPG_SECURITY_AUTH_BLOCKED() set_res_apdu (0x69, 0x83)
|
||||
#define GPG_COMMAND_NOT_ALLOWED() set_res_apdu (0x69, 0x86)
|
||||
#define GPG_NO_FILE() set_res_apdu (0x6a, 0x82)
|
||||
#define GPG_NO_RECORD() set_res_apdu (0x6a, 0x88)
|
||||
#define GPG_BAD_P0_P1() set_res_apdu (0x6b, 0x00)
|
||||
#define GPG_NO_INS() set_res_apdu (0x6d, 0x00)
|
||||
#define GPG_ERROR() set_res_apdu (0x6f, 0x00)
|
||||
#define GPG_SUCCESS() set_res_apdu (0x90, 0x00)
|
||||
#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
|
||||
#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82)
|
||||
#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83)
|
||||
#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85)
|
||||
#define GPG_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
|
||||
#define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81)
|
||||
#define GPG_NO_FILE() set_res_sw (0x6a, 0x82)
|
||||
#define GPG_NO_RECORD() set_res_sw (0x6a, 0x88)
|
||||
#define GPG_BAD_P1_P2() set_res_sw (0x6b, 0x00)
|
||||
#define GPG_NO_INS() set_res_sw (0x6d, 0x00)
|
||||
#define GPG_ERROR() set_res_sw (0x6f, 0x00)
|
||||
#define GPG_SUCCESS() set_res_sw (0x90, 0x00)
|
||||
|
||||
683
src/pin-cir.c
683
src/pin-cir.c
@@ -27,13 +27,41 @@
|
||||
#include "board.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
#if 0
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_CIR 1
|
||||
#endif
|
||||
|
||||
uint8_t pin_input_buffer[MAX_PIN_CHARS];
|
||||
uint8_t pin_input_len;
|
||||
|
||||
/*
|
||||
* Supported/tested TV controllers:
|
||||
*
|
||||
* Controller of Toshiba REGZA
|
||||
* Controller of Sony BRAVIA
|
||||
* Controller of Sharp AQUOS
|
||||
* Dell Wireless Travel Remote MR425
|
||||
*
|
||||
* The code supports RC-5 protocol in fact, but I don't have any
|
||||
* controller at hand which I can test with, so I don't have any data
|
||||
* for controller of RC-5.
|
||||
*
|
||||
* Current code assumes following mapping:
|
||||
*
|
||||
* --------------------------------------
|
||||
* Protocol Controller
|
||||
* --------------------------------------
|
||||
* RC-6 Dell MR425
|
||||
* NEC Toshiba REGZA
|
||||
* Sharp Sharp AQUOS
|
||||
* Sony Sony BRAVIA
|
||||
* --------------------------------------
|
||||
*
|
||||
* In future, when I will have other controllers, this mapping will be
|
||||
* (should be) configurable, at compile time at least, preferably at
|
||||
* runtime.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Philips RC-5 Protocol: 14-bit (MSB first)
|
||||
*
|
||||
@@ -69,18 +97,26 @@ uint8_t pin_input_len;
|
||||
*/
|
||||
|
||||
/*
|
||||
* PB0 / TIM3_CH3
|
||||
* The implementation note of CIR signal decoding (on STM32).
|
||||
*
|
||||
* (1) Use EXTI interrupt to detect the first edge of signal.
|
||||
* (2) Use Timer (with PWM input mode) to measure timings of square wave.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Timer settings.
|
||||
*
|
||||
* See THE reference manual (RM0008) section 15.3.6 PWM input mode.
|
||||
*
|
||||
* 72MHz
|
||||
*
|
||||
* Prescaler = 72
|
||||
*
|
||||
* 1us
|
||||
*
|
||||
*
|
||||
* TIM3_CR1
|
||||
* CKD = 10 (sampling x4)
|
||||
* ARPE = 0 (not buffered)
|
||||
* TIMx_CR1
|
||||
* CKD = 00 (tDTS = tCK_INT)
|
||||
* ARPE = 1 (buffered)
|
||||
* CMS = 00 (up counter)
|
||||
* DIR = 0 (up counter)
|
||||
* OPM = 0 (up counter)
|
||||
@@ -88,13 +124,13 @@ uint8_t pin_input_len;
|
||||
* UDIS = 0 (UEV (update event) enabled)
|
||||
* CEN = 1 (counter enable)
|
||||
*
|
||||
* TIM3_CR2
|
||||
* TIMx_CR2
|
||||
* TI1S = 1 (TI1 is XOR of ch1, ch2, ch3)
|
||||
* MMS = 000 (TRGO at Reset)
|
||||
* CCDS = 0 (DMA on capture)
|
||||
* RSVD = 000
|
||||
*
|
||||
* TIM3_SMCR
|
||||
* TIMx_SMCR
|
||||
* ETP = 0
|
||||
* ECE = 0
|
||||
* ETPS = 00
|
||||
@@ -104,61 +140,37 @@ uint8_t pin_input_len;
|
||||
* RSVD = 0
|
||||
* SMS = 100 (Reset-mode)
|
||||
*
|
||||
* TIM3_DIER
|
||||
* TIMx_DIER
|
||||
*
|
||||
* TIM3_SR
|
||||
* TIMx_SR
|
||||
*
|
||||
* TIM3_EGR
|
||||
* TIMx_EGR
|
||||
*
|
||||
* TIM3_CCMR1
|
||||
* TIMx_CCMR1
|
||||
* CC1S = 01 (TI1 selected)
|
||||
* CC2S = 10 (TI1 selected)
|
||||
* IC1F = 1001 (fSAMPLING=fDTS/8, N=8)
|
||||
* IC2F = 1001 (fSAMPLING=fDTS/8, N=8)
|
||||
*
|
||||
* TIM3_CCMR2
|
||||
* TIMx_CCMR2
|
||||
*
|
||||
* TIM3_CCER
|
||||
* TIMx_CCER
|
||||
* CC2P = 1 (polarity = falling edge: TI1FP1)
|
||||
* CC2E = 1
|
||||
* CC1P = 0 (polarity = rising edge: TI1FP1)
|
||||
* CC1E = 1
|
||||
*
|
||||
* TIM3_CNT
|
||||
* TIM3_PSC = 71
|
||||
* TIM3_ARR = 18000
|
||||
* TIMx_CNT
|
||||
* TIMx_PSC = 71
|
||||
* TIMx_ARR = 18000
|
||||
*
|
||||
* TIM3_CCR1 period
|
||||
* TIM3_CCR2 duty
|
||||
* TIMx_CCR1 period
|
||||
* TIMx_CCR2 duty
|
||||
*
|
||||
* TIM3_DCR
|
||||
* TIM3_DMAR
|
||||
* TIMx_DCR
|
||||
* TIMx_DMAR
|
||||
*/
|
||||
|
||||
#define PINDISP_TIMEOUT_INTERVAL0 MS2ST(25)
|
||||
#define PINDISP_TIMEOUT_INTERVAL1 MS2ST(300)
|
||||
|
||||
static void
|
||||
pindisp (uint8_t c)
|
||||
{
|
||||
#if defined(HAVE_7SEGLED)
|
||||
switch (c)
|
||||
{
|
||||
case 'G':
|
||||
palWritePort (IOPORT2, 0xa1ff);
|
||||
break;
|
||||
case 'P':
|
||||
palWritePort (IOPORT2, 0x98ff);
|
||||
break;
|
||||
case '.':
|
||||
palWritePort (IOPORT2, 0x7fff);
|
||||
break;
|
||||
default:
|
||||
palWritePort (IOPORT2, 0xffff);
|
||||
}
|
||||
#else
|
||||
(void)c;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(DEBUG_CIR)
|
||||
static uint16_t intr_ext;
|
||||
static uint16_t intr_trg;
|
||||
@@ -179,14 +191,6 @@ static uint8_t cir_proto;
|
||||
#define CIR_PROTO_NEC 5
|
||||
#define CIR_PROTO_SHARP 6
|
||||
|
||||
#define CIR_KEY_RC6_ENTER 0x0d /* Mute */
|
||||
#define CIR_KEY_RC6_BACKSPACE 0xa4 /* <= */
|
||||
#define CIR_KEY_NEC_ENTER 0x3d /* 'kettei' */
|
||||
#define CIR_KEY_NEC_BACKSPACE 0x3b /* 'modoru' */
|
||||
#define CIR_KEY_SONY_ENTER 0x65 /* 'kettei' */
|
||||
#define CIR_KEY_SONY_BACKSPACE 0xa3 /* 'modoru' */
|
||||
#define CIR_KEY_SHARP_ENTER 0x0252 /* 'kettei' */
|
||||
#define CIR_KEY_SHARP_BACKSPACE 0xe4 /* 'modoru' */
|
||||
|
||||
/* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */
|
||||
static uint8_t cir_data_zero;
|
||||
@@ -196,6 +200,388 @@ static uint8_t cir_seq;
|
||||
static systime_t cir_input_last;
|
||||
#define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */
|
||||
|
||||
static void
|
||||
cir_init (void)
|
||||
{
|
||||
cir_data = 0;
|
||||
cir_seq = 0;
|
||||
/* Don't touch cir_proto here */
|
||||
cir_ext_enable ();
|
||||
}
|
||||
|
||||
|
||||
#define CH_RETURN 0x0d
|
||||
#define CH_BACKSPACE 0x08
|
||||
|
||||
struct codetable {
|
||||
uint16_t cir_code;
|
||||
uint8_t char_code;
|
||||
};
|
||||
|
||||
/* NOTE: no way to input '0' */
|
||||
static const struct codetable
|
||||
cir_codetable_dell_mr425[] = {
|
||||
{0x10, '7' }, /* Speaker Louder */
|
||||
{0x11, '8' }, /* Speaker Quieter */
|
||||
{0x0d, '9' }, /* Speaker Mute */
|
||||
{0xce, 'a' }, /* Black triangle UP */
|
||||
{0xcf, 'b' }, /* Black triangle DOWN */
|
||||
{0x58, 'c' }, /* White triangle UP */
|
||||
{0x5a, 'd' }, /* White triangle LEFT */
|
||||
{0x5c, CH_RETURN }, /* Check */
|
||||
{0x5b, 'e' }, /* White triangle RIGHT */
|
||||
{0xa4, CH_BACKSPACE }, /* Back */
|
||||
{0x59, 'f' }, /* White triangle DOWN */
|
||||
{0x2f, '1' }, /* Rewind */
|
||||
{0x2c, '2' }, /* Play / Pause */
|
||||
{0x2e, '3' }, /* Forward */
|
||||
{0x21, '4' }, /* Skip backward */
|
||||
{0x31, '5' }, /* Stop */
|
||||
{0x20, '6' }, /* Skip forward */
|
||||
|
||||
{0, 0} /* <<END>> */
|
||||
};
|
||||
|
||||
#define CIR_ADDR_SHARP_AQUOS 0x028f
|
||||
static const struct codetable
|
||||
cir_codetable_aquos[] = {
|
||||
{ 0x0116, ' ' }, /* Power */
|
||||
{ 0x025e, '0' }, /* d */
|
||||
{ 0x024e, '1' }, /* 1 */
|
||||
{ 0x024f, '2' }, /* 2 */
|
||||
{ 0x0250, '3' }, /* 3 */
|
||||
{ 0x0251, '4' }, /* 4 */
|
||||
{ 0x0252, '5' }, /* 5 */
|
||||
{ 0x0253, '6' }, /* 6 */
|
||||
{ 0x0254, '7' }, /* 7 */
|
||||
{ 0x0255, '8' }, /* 8 */
|
||||
{ 0x0256, '9' }, /* 9 */
|
||||
{ 0x0257, 'a' }, /* 10/0 */
|
||||
{ 0x0258, 'b' }, /* 11 */
|
||||
{ 0x0259, 'c' }, /* 12 */
|
||||
{ 0x0111, 'd' }, /* Ch ^ */
|
||||
{ 0x0112, 'e' }, /* Ch v */
|
||||
{ 0x0114, 'f' }, /* Vol + */
|
||||
{ 0x0115, 'g' }, /* Vol - */
|
||||
{ 0x0117, 'h' }, /* Mute */
|
||||
{ 0x0280, 'i' }, /* BLUE */
|
||||
{ 0x0281, 'j' }, /* RED */
|
||||
{ 0x0282, 'k' }, /* GREEN */
|
||||
{ 0x0283, 'l' }, /* YELLOW */
|
||||
{ 0x011b, 'm' }, /* DISPLAY CONTROL (gamen hyouji) */
|
||||
{ 0x01d5, 'n' }, /* DISPLAY SIZE */
|
||||
{ 0x0157, 'o' }, /* UP */
|
||||
{ 0x01d7, 'p' }, /* LEFT */
|
||||
{ 0x01d8, 'q' }, /* RIGHT */
|
||||
{ 0x0120, 'r' }, /* DOWN */
|
||||
{ 0x0152, CH_RETURN }, /* Commit (kettei) */
|
||||
{ 0x01e4, CH_BACKSPACE }, /* Back (modoru) */
|
||||
{ 0x01f5, 's' }, /* Quit (shuuryou) */
|
||||
{ 0x0b03, 't' }, /* Rewind (hayamodoshi) */
|
||||
{ 0x0b01, 'u' }, /* Play (saisei) */
|
||||
{ 0x0b04, 'v' }, /* Forward (hayaokuri) */
|
||||
{ 0x0b02, 'w' }, /* Stop (teishi) */
|
||||
{ 0x028a, 'x' }, /* BS */
|
||||
{ 0x028b, 'y' }, /* CS */
|
||||
{ 0x025f, 'z' }, /* Program information (bangumi jouhou) */
|
||||
{ 0x0260, '\\' }, /* Program table (bangumi hyou) */
|
||||
{ 0x0118, '|' }, /* Sound channel (onsei kirikae) */
|
||||
{ 0x028e, '[' }, /* Ground Analog (chijou A) */
|
||||
{ 0x0289, ']' }, /* Ground Digital (chijou D) */
|
||||
|
||||
{ 0x0b07, '\"' }, /* Feature select (kinou sentaku) */
|
||||
{ 0x026b, '.' }, /* TV/Radio/Data (terebi/rajio/data) */
|
||||
{ 0x025a, ',' }, /* 3 code input (3 keta nyuuryoku) */
|
||||
{ 0x0267, ':' }, /* subtitle (jimaku) */
|
||||
{ 0x0159, ';' }, /* hold (seishi) */
|
||||
|
||||
{ 0x01c4, 'A' }, /* Menu */
|
||||
{ 0x011a, 'B' }, /* Off timer */
|
||||
{ 0x0121, 'C' }, /* CATV */
|
||||
{ 0x0b05, 'D' }, /* Record */
|
||||
{ 0x0b06, 'E' }, /* Recording stop */
|
||||
{ 0x0113, 'F' }, /* Inputs (nyuuryoku kirikae) */
|
||||
{ 0x0275, 'G' }, /* other programs (ura bangumi) */
|
||||
{ 0x0266, 'H' }, /* signal control (eizou kirikae) */
|
||||
{ 0x01e7, 'I' }, /* AV position */
|
||||
{ 0x027f, 'J' }, /* i.LINK */
|
||||
{ 0x0b00, 'K' }, /* Recorder power */
|
||||
{ 0x028f, 'L' }, /* as you like it (okonomi senkyoku) */
|
||||
|
||||
{0, 0} /* <<END>> */
|
||||
};
|
||||
|
||||
#define CIR_ADDR_TOSHIBA_REGZA 0xbf40
|
||||
static const struct codetable
|
||||
cir_codetable_regza[] = {
|
||||
{ 0x12, ' ' }, /* Power */
|
||||
{ 0x14, '0' }, /* d (data) */
|
||||
{ 0x01, '1' }, /* 1 */
|
||||
{ 0x02, '2' }, /* 2 */
|
||||
{ 0x03, '3' }, /* 3 */
|
||||
{ 0x04, '4' }, /* 4 */
|
||||
{ 0x05, '5' }, /* 5 */
|
||||
{ 0x06, '6' }, /* 6 */
|
||||
{ 0x07, '7' }, /* 7 */
|
||||
{ 0x08, '8' }, /* 8 */
|
||||
{ 0x09, '9' }, /* 9 */
|
||||
{ 0x0a, 'a' }, /* 10 */
|
||||
{ 0x0b, 'b' }, /* 11 */
|
||||
{ 0x0c, 'c' }, /* 12 */
|
||||
{ 0x1b, 'd' }, /* Ch ^ */
|
||||
{ 0x1f, 'e' }, /* Ch v */
|
||||
{ 0x1a, 'f' }, /* Vol + */
|
||||
{ 0x1e, 'g' }, /* Vol - */
|
||||
{ 0x10, 'h' }, /* Mute */
|
||||
{ 0x73, 'i' }, /* BLUE */
|
||||
{ 0x74, 'j' }, /* RED */
|
||||
{ 0x75, 'k' }, /* GREEN */
|
||||
{ 0x76, 'l' }, /* YELLOW */
|
||||
{ 0x1c, 'm' }, /* Display control */
|
||||
{ 0x2b, 'n' }, /* Display size */
|
||||
{ 0x3e, 'o' }, /* UP */
|
||||
{ 0x5f, 'p' }, /* LEFT */
|
||||
{ 0x5b, 'q' }, /* RIGHT */
|
||||
{ 0x3f, 'r' }, /* DOWN */
|
||||
{ 0x3d, CH_RETURN }, /* Commit (kettei) */
|
||||
{ 0x3b, CH_BACKSPACE }, /* Back (modoru) */
|
||||
{ 0x3c, 's' }, /* Quit (shuuryou) */
|
||||
{ 0x2c, 't' }, /* << (Rewind) */
|
||||
{ 0x2d, 'u' }, /* >/|| (Play/Stop) */
|
||||
{ 0x2e, 'v' }, /* >> (Forward) */
|
||||
{ 0x2b, 'w' }, /* Stop (teishi) */
|
||||
{ 0x7c, 'x' }, /* BS */
|
||||
{ 0x7d, 'y' }, /* CS */
|
||||
{ 0x71, 'z' }, /* Program information (bangumi setsumei) */
|
||||
{ 0x77, '\\' }, /* Mini program table (mini bangumihyou) */
|
||||
{ 0x13, '|' }, /* Sound (onta kirikae) */
|
||||
{ 0x7a, '[' }, /* Ground Digital (chideji) */
|
||||
{ 0x7b, ']' }, /* Ground Analog (chiana) */
|
||||
|
||||
{ 0xd0, '\"' }, /* Settings Menu (settei menu) */
|
||||
{ 0x6d, '.' }, /* Radio/Data (rajio/data) */
|
||||
{ 0x60, ',' }, /* CH 10-key input (search) */
|
||||
{ 0x52, ':' }, /* subtitle (jimaku) */
|
||||
{ 0x50, ';' }, /* hold (seishi) */
|
||||
|
||||
{ 0x3a, 'A' }, /* Input- (nyuuryokukirikae-) */
|
||||
{ 0x0f, 'B' }, /* Input+ (nyuuryokukirikae+) */
|
||||
{ 0x29, 'C' }, /* Two screens (nigamen) */
|
||||
{ 0x25, 'D' }, /* Broadband */
|
||||
{ 0x27, 'E' }, /* |<< Skip backward */
|
||||
{ 0x26, 'F' }, /* >>| Skip forward */
|
||||
{ 0x61, '!' }, /* 1 NHK1 */
|
||||
{ 0x62, '@' }, /* 2 NHK2 */
|
||||
{ 0x63, '#' }, /* 3 NHKh */
|
||||
{ 0x64, '$' }, /* 4 BS Nihon TV */
|
||||
{ 0x65, '%' }, /* 5 BS Asahi */
|
||||
{ 0x66, '^' }, /* 6 BS-i */
|
||||
{ 0x67, '&' }, /* 7 BSJ */
|
||||
{ 0x68, '*' }, /* 8 BS Fuji */
|
||||
{ 0x69, '(' }, /* 9 WOW */
|
||||
{ 0x6a, ')' }, /* 10 Star */
|
||||
{ 0x6b, '-' }, /* 11 BS11 */
|
||||
{ 0x6c, '+' }, /* 12 TwellV */
|
||||
{ 0x27, '=' }, /* Quick (Delete) */
|
||||
{ 0x34, '<' }, /* REGZA link */
|
||||
{ 0x6e, '>' }, /* Program Table */
|
||||
{ 0x20, '/' }, /* ^^ */
|
||||
{ 0x22, '\'' }, /* << */
|
||||
{ 0x23, '?' }, /* >> */
|
||||
{ 0x21, '_' }, /* vv */
|
||||
|
||||
{0, 0} /* <<END>> */
|
||||
};
|
||||
|
||||
static const struct codetable
|
||||
cir_codetable_bravia[] = {
|
||||
{ 0x15, ' ' }, /* Power */
|
||||
{ 0x95, '0' }, /* d (16-bit: 0x4b) */
|
||||
{ 0x00, '1' }, /* 1 */
|
||||
{ 0x01, '2' }, /* 2 */
|
||||
{ 0x02, '3' }, /* 3 */
|
||||
{ 0x03, '4' }, /* 4 */
|
||||
{ 0x04, '5' }, /* 5 */
|
||||
{ 0x05, '6' }, /* 6 */
|
||||
{ 0x06, '7' }, /* 7 */
|
||||
{ 0x07, '8' }, /* 8 */
|
||||
{ 0x08, '9' }, /* 9 */
|
||||
{ 0x09, 'a' }, /* 10 */
|
||||
{ 0x0a, 'b' }, /* 11 */
|
||||
{ 0x0b, 'c' }, /* 12 */
|
||||
{ 0x10, 'd' }, /* CH+ */
|
||||
{ 0x11, 'd' }, /* CH- */
|
||||
{ 0x12, 'f' }, /* Vol+ */
|
||||
{ 0x13, 'g' }, /* Vol- */
|
||||
{ 0x14, 'h' }, /* Mute */
|
||||
{ 0xa4, 'i' }, /* BLUE (16-bit: 0x4b) */
|
||||
{ 0xa5, 'j' }, /* RED (16-bit: 0x4b) */
|
||||
{ 0xa6, 'k' }, /* GREEN (16-bit: 0x4b) */
|
||||
{ 0xa7, 'l' }, /* YELLOW (16-bit: 0x4b) */
|
||||
{ 0x3a, 'm' }, /* DISPLAY control (gamen hyouji) */
|
||||
{ 0x3d, 'n' }, /* Display Wide (waido kirikae) */
|
||||
{ 0x74, 'o' }, /* UP */
|
||||
{ 0x75, 'p' }, /* DOWN */
|
||||
{ 0x33, 'q' }, /* RIGHT */
|
||||
{ 0x34, 'r' }, /* LEFT */
|
||||
{ 0x65, CH_RETURN }, /* Commit (kettei) */
|
||||
{ 0xa3, CH_BACKSPACE }, /* Back (modoru) (16-bit: 0x4b) */
|
||||
{ 0xac, 's' }, /* BS (16-bit: 0x4b) */
|
||||
{ 0xab, 't' }, /* CS (16-bit: 0x4b) */
|
||||
{ 0x5b, 'u' }, /* Program table (bangumi hyou) (16-bit: 0x52) */
|
||||
{ 0x17, 'v' }, /* Sound channel (onsei kirikae) */
|
||||
{ 0xa8, 'w' }, /* subtitle (jimaku) (16-bit: 0x4b) */
|
||||
{ 0x5c, 'x' }, /* hold (memo) */
|
||||
{ 0xb6, 'y' }, /* Tool (16-bit: 0x4b) */
|
||||
{ 0x8c, 'z' }, /* 10 key input (10ki-) (16-bit: 0x4b) */
|
||||
{ 0x60, '!' }, /* Menu */
|
||||
{ 0xae, '@' }, /* Analog (16-bit: 0x4b) */
|
||||
{ 0xb2, '#' }, /* Digital (16-bit: 0x4b) */
|
||||
{ 0x25, '$' }, /* Input (nyuuryoku kirikae) */
|
||||
|
||||
{0, 0} /* <<END>> */,
|
||||
};
|
||||
|
||||
static int
|
||||
ch_is_backspace (int ch)
|
||||
{
|
||||
return ch == CH_BACKSPACE;
|
||||
}
|
||||
|
||||
static int
|
||||
ch_is_enter (int ch)
|
||||
{
|
||||
return ch == CH_RETURN;
|
||||
}
|
||||
|
||||
/* liner search is good enough for this small amount of data */
|
||||
static uint8_t
|
||||
find_char_codetable (uint32_t cir_code, const struct codetable *ctp)
|
||||
{
|
||||
while (ctp->cir_code != 0x0000 || ctp->char_code != 0x00)
|
||||
if (ctp->cir_code == cir_code)
|
||||
return ctp->char_code;
|
||||
else
|
||||
ctp++;
|
||||
|
||||
/* Not found */
|
||||
return cir_code & 0xff;
|
||||
}
|
||||
|
||||
static int
|
||||
hex (int x)
|
||||
{
|
||||
if (x < 10)
|
||||
return x + '0';
|
||||
else
|
||||
return (x - 10) + 'a';
|
||||
}
|
||||
|
||||
static int
|
||||
cir_getchar (systime_t timeout)
|
||||
{
|
||||
uint16_t cir_addr;
|
||||
eventmask_t m;
|
||||
#if defined(DEBUG_CIR)
|
||||
uint16_t *p;
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_CIR)
|
||||
cirinput_p = cirinput;
|
||||
#endif
|
||||
|
||||
chEvtClear (ALL_EVENTS);
|
||||
cir_init ();
|
||||
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, timeout);
|
||||
if (m == 0)
|
||||
return -1;
|
||||
|
||||
#if defined(DEBUG_CIR)
|
||||
DEBUG_INFO ("****\r\n");
|
||||
DEBUG_SHORT (intr_ext);
|
||||
DEBUG_SHORT (intr_trg);
|
||||
DEBUG_SHORT (intr_ovf);
|
||||
DEBUG_INFO ("----\r\n");
|
||||
for (p = cirinput; p < cirinput_p; p++)
|
||||
DEBUG_SHORT (*p);
|
||||
DEBUG_INFO ("====\r\n");
|
||||
|
||||
cirinput_p = cirinput;
|
||||
|
||||
DEBUG_INFO ("**** CIR data:");
|
||||
DEBUG_WORD (cir_data);
|
||||
if (cir_seq > 48)
|
||||
DEBUG_SHORT (cir_data_more);
|
||||
DEBUG_BYTE (cir_seq);
|
||||
#endif
|
||||
|
||||
switch (cir_proto)
|
||||
{
|
||||
case CIR_PROTO_RC5:
|
||||
cir_data &= 0x003f;
|
||||
goto err;
|
||||
case CIR_PROTO_RC6:
|
||||
cir_addr = cir_data >> 8; /* in case of cir_seq == 16. 32??? */
|
||||
cir_data &= 0x00ff;
|
||||
return find_char_codetable (cir_data, cir_codetable_dell_mr425);
|
||||
case CIR_PROTO_NEC:
|
||||
cir_addr = cir_data&0xffff;
|
||||
if (cir_addr == CIR_ADDR_TOSHIBA_REGZA)
|
||||
{
|
||||
cir_data = (cir_data >> 16) & 0x00ff;
|
||||
return find_char_codetable (cir_data, cir_codetable_regza);
|
||||
}
|
||||
else
|
||||
goto err;
|
||||
case CIR_PROTO_SHARP:
|
||||
cir_addr = cir_data&0x0fff;
|
||||
if (cir_addr == CIR_ADDR_SHARP_AQUOS)
|
||||
{
|
||||
cir_data = (cir_data>>16)&0x0fff;
|
||||
return find_char_codetable (cir_data, cir_codetable_aquos);
|
||||
}
|
||||
else
|
||||
goto err;
|
||||
case CIR_PROTO_SONY:
|
||||
/* Remove ADDRESS bits and filter COMMAND bits */
|
||||
if (cir_seq == 1 + 12)
|
||||
{
|
||||
cir_addr = cir_data >> 7;
|
||||
cir_data = cir_data & 0x007f;
|
||||
/* ADDRESS = 0x01 (5-bit) */
|
||||
}
|
||||
else
|
||||
{
|
||||
cir_addr = cir_data >> 8;
|
||||
cir_data = cir_data & 0x00ff;
|
||||
/* ADDRESS = 0x4b or 0x52 (7-bit) */
|
||||
}
|
||||
return find_char_codetable (cir_data, cir_codetable_bravia);
|
||||
err:
|
||||
default:
|
||||
/* encode debug information */
|
||||
pin_input_len = 16;
|
||||
pin_input_buffer[0] = hex (cir_proto >> 4);
|
||||
pin_input_buffer[1] = hex (cir_proto & 0x0f);
|
||||
pin_input_buffer[2] = ':';
|
||||
pin_input_buffer[3] = hex ((cir_data >> 28) & 0x0f);
|
||||
pin_input_buffer[4] = hex ((cir_data >> 24) & 0x0f);
|
||||
pin_input_buffer[5] = hex ((cir_data >> 20) & 0x0f);
|
||||
pin_input_buffer[6] = hex ((cir_data >> 16) & 0x0f);
|
||||
pin_input_buffer[7] = hex ((cir_data >> 12) & 0x0f);
|
||||
pin_input_buffer[8] = hex ((cir_data >> 8) & 0x0f);
|
||||
pin_input_buffer[9] = hex ((cir_data >> 4) & 0x0f);
|
||||
pin_input_buffer[10] = hex (cir_data & 0x0f);
|
||||
pin_input_buffer[11] = ':';
|
||||
pin_input_buffer[12] = hex ((cir_data_more >> 12) & 0x0f);
|
||||
pin_input_buffer[13] = hex ((cir_data_more >> 8) & 0x0f);
|
||||
pin_input_buffer[14] = hex ((cir_data_more >> 4) & 0x0f);
|
||||
pin_input_buffer[15] = hex (cir_data_more & 0x0f);
|
||||
return CH_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RC-5 protocol doesn't have a start bit, while any other protocols
|
||||
* have the one.
|
||||
@@ -207,125 +593,56 @@ static systime_t cir_input_last;
|
||||
#define CIR_BIT_PERIOD 1500
|
||||
#define CIR_BIT_SIRC_PERIOD_ON 1000
|
||||
|
||||
static void
|
||||
cir_init (void)
|
||||
{
|
||||
cir_data = 0;
|
||||
cir_seq = 0;
|
||||
/* Don't touch cir_proto here */
|
||||
cir_ext_enable ();
|
||||
}
|
||||
|
||||
static Thread *pin_thread;
|
||||
|
||||
static int
|
||||
cir_key_is_backspace (void)
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
*/
|
||||
int
|
||||
pinpad_getline (int msg_code, systime_t timeout)
|
||||
{
|
||||
return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_BACKSPACE)
|
||||
|| (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_BACKSPACE)
|
||||
|| (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_BACKSPACE)
|
||||
|| (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_BACKSPACE);
|
||||
}
|
||||
|
||||
static int
|
||||
cir_key_is_enter (void)
|
||||
{
|
||||
return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_ENTER)
|
||||
|| (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_ENTER)
|
||||
|| (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_ENTER)
|
||||
|| (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_ENTER);
|
||||
}
|
||||
|
||||
msg_t
|
||||
pin_main (void *arg)
|
||||
{
|
||||
uint8_t s = 0;
|
||||
int msg_code = (int)arg;
|
||||
|
||||
(void)msg_code;
|
||||
|
||||
pin_thread = chThdSelf ();
|
||||
|
||||
#if defined(DEBUG_CIR)
|
||||
cirinput_p = cirinput;
|
||||
#endif
|
||||
DEBUG_INFO (">>>\r\n");
|
||||
|
||||
pin_input_len = 0;
|
||||
chEvtClear (ALL_EVENTS);
|
||||
cir_init ();
|
||||
|
||||
while (!chThdShouldTerminate ())
|
||||
while (1)
|
||||
{
|
||||
eventmask_t m;
|
||||
int ch;
|
||||
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, PINDISP_TIMEOUT_INTERVAL1);
|
||||
ch = cir_getchar (timeout);
|
||||
if (ch < 0)
|
||||
return 0; /* timeout */
|
||||
|
||||
if (m)
|
||||
if (ch_is_backspace (ch))
|
||||
{
|
||||
#if defined(DEBUG_CIR)
|
||||
uint16_t *p;
|
||||
|
||||
DEBUG_INFO ("****\r\n");
|
||||
DEBUG_SHORT (intr_ext);
|
||||
DEBUG_SHORT (intr_trg);
|
||||
DEBUG_SHORT (intr_ovf);
|
||||
DEBUG_INFO ("----\r\n");
|
||||
for (p = cirinput; p < cirinput_p; p++)
|
||||
DEBUG_SHORT (*p);
|
||||
DEBUG_INFO ("====\r\n");
|
||||
|
||||
cirinput_p = cirinput;
|
||||
#endif
|
||||
DEBUG_INFO ("**** CIR data:");
|
||||
DEBUG_WORD (cir_data);
|
||||
if (cir_seq > 48)
|
||||
{
|
||||
DEBUG_SHORT (cir_data_more);
|
||||
}
|
||||
DEBUG_BYTE (cir_seq);
|
||||
|
||||
if (cir_key_is_backspace ())
|
||||
{
|
||||
if (pin_input_len > 0)
|
||||
pin_input_len--;
|
||||
}
|
||||
else if (cir_key_is_enter ())
|
||||
{
|
||||
pindisp (' ');
|
||||
chThdExit (0);
|
||||
}
|
||||
else if (pin_input_len < MAX_PIN_CHARS)
|
||||
pin_input_buffer[pin_input_len++] = (uint8_t)cir_data;
|
||||
|
||||
cir_init ();
|
||||
led_blink (LED_TWOSHOTS);
|
||||
if (pin_input_len > 0)
|
||||
pin_input_len--;
|
||||
}
|
||||
|
||||
switch (s++)
|
||||
else if (ch_is_enter (ch))
|
||||
break;
|
||||
else if (pin_input_len < MAX_PIN_CHARS)
|
||||
{
|
||||
case 0:
|
||||
pindisp ('G');
|
||||
break;
|
||||
case 1:
|
||||
pindisp ('P');
|
||||
break;
|
||||
case 2:
|
||||
pindisp ('G');
|
||||
break;
|
||||
case 3:
|
||||
pindisp ('.');
|
||||
break;
|
||||
default:
|
||||
pindisp (' ');
|
||||
s = 0;
|
||||
break;
|
||||
led_blink (LED_ONESHOT);
|
||||
pin_input_buffer[pin_input_len++] = ch;
|
||||
}
|
||||
|
||||
chThdSleep (PINDISP_TIMEOUT_INTERVAL0);
|
||||
}
|
||||
|
||||
cir_ext_disable ();
|
||||
return 0;
|
||||
|
||||
return pin_input_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Interrupt handler of EXTI.
|
||||
* @note This handler will be invoked at the beginning of signal.
|
||||
* Setup timer to measure period and duty using PWM input mode.
|
||||
*/
|
||||
void
|
||||
cir_ext_interrupt (void)
|
||||
{
|
||||
@@ -340,29 +657,33 @@ cir_ext_interrupt (void)
|
||||
}
|
||||
#endif
|
||||
|
||||
TIM3->EGR = TIM_EGR_UG; /* Generate UEV to load PSC and ARR */
|
||||
TIMx->EGR = TIM_EGR_UG; /* Generate UEV to load PSC and ARR */
|
||||
/* Enable Timer */
|
||||
TIM3->SR &= ~(TIM_SR_UIF
|
||||
TIMx->SR &= ~(TIM_SR_UIF
|
||||
| TIM_SR_CC1IF | TIM_SR_CC2IF
|
||||
| TIM_SR_TIF
|
||||
| TIM_SR_CC1OF | TIM_SR_CC2OF);
|
||||
TIM3->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/;
|
||||
TIM3->CR1 |= TIM_CR1_CEN;
|
||||
TIMx->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/;
|
||||
TIMx->CR1 |= TIM_CR1_CEN;
|
||||
}
|
||||
|
||||
#define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \
|
||||
* CIR_BIT_PERIOD_RC6 * 3 / 2)
|
||||
|
||||
/**
|
||||
* @brief Interrupt handler of timer.
|
||||
* @note Timer is PWM input mode, this handler will be invoked on each cycle
|
||||
*/
|
||||
void
|
||||
cir_timer_interrupt (void)
|
||||
{
|
||||
uint16_t period, on, off;
|
||||
|
||||
period = TIM3->CCR1;
|
||||
on = TIM3->CCR2;
|
||||
period = TIMx->CCR1;
|
||||
on = TIMx->CCR2;
|
||||
off = period - on;
|
||||
|
||||
if ((TIM3->SR & TIM_SR_TIF))
|
||||
if ((TIMx->SR & TIM_SR_TIF))
|
||||
{
|
||||
if (cir_seq == 0)
|
||||
{
|
||||
@@ -477,23 +798,23 @@ cir_timer_interrupt (void)
|
||||
intr_trg++;
|
||||
#endif
|
||||
|
||||
TIM3->EGR = TIM_EGR_UG; /* Generate UEV */
|
||||
TIM3->SR &= ~TIM_SR_TIF;
|
||||
TIMx->EGR = TIM_EGR_UG; /* Generate UEV */
|
||||
TIMx->SR &= ~TIM_SR_TIF;
|
||||
}
|
||||
else
|
||||
/* overflow occurred */
|
||||
{
|
||||
systime_t now = chTimeNow ();
|
||||
|
||||
TIM3->SR &= ~TIM_SR_UIF;
|
||||
TIMx->SR &= ~TIM_SR_UIF;
|
||||
|
||||
if (on > 0)
|
||||
{
|
||||
uint8_t ignore_input = 0;
|
||||
|
||||
/* Disable the timer */
|
||||
TIM3->CR1 &= ~TIM_CR1_CEN;
|
||||
TIM3->DIER = 0;
|
||||
TIMx->CR1 &= ~TIM_CR1_CEN;
|
||||
TIMx->DIER = 0;
|
||||
|
||||
if (cir_seq == 12 || cir_seq == 15)
|
||||
{
|
||||
@@ -536,14 +857,9 @@ cir_timer_interrupt (void)
|
||||
cir_input_last = now;
|
||||
ignore_input = 1;
|
||||
}
|
||||
/* Remove ADDRESS bits and filter COMMAND bits */
|
||||
else if (cir_proto == CIR_PROTO_SONY)
|
||||
{
|
||||
if (cir_seq == 1 + 12)
|
||||
cir_data = cir_data & 0x007f;
|
||||
else if (cir_seq == 1 + 15)
|
||||
cir_data = cir_data & 0x00ff;
|
||||
else
|
||||
if (cir_seq != 1 + 12 && cir_seq != 1 + 15)
|
||||
ignore_input = 1;
|
||||
}
|
||||
else if (cir_proto == CIR_PROTO_OTHER)
|
||||
@@ -551,10 +867,7 @@ cir_timer_interrupt (void)
|
||||
if (cir_seq == 1 + 32)
|
||||
{
|
||||
if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff))
|
||||
{
|
||||
cir_proto = CIR_PROTO_NEC;
|
||||
cir_data = (cir_data >> 16) & 0x00ff;
|
||||
}
|
||||
cir_proto = CIR_PROTO_NEC;
|
||||
else
|
||||
ignore_input = 1;
|
||||
}
|
||||
@@ -569,10 +882,7 @@ cir_timer_interrupt (void)
|
||||
^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f)
|
||||
^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f)
|
||||
^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f)))
|
||||
{
|
||||
cir_proto = CIR_PROTO_SHARP;
|
||||
cir_data = (cir_data >> 16) & 0x0fff;
|
||||
}
|
||||
cir_proto = CIR_PROTO_SHARP;
|
||||
else
|
||||
ignore_input = 1;
|
||||
}
|
||||
@@ -581,16 +891,12 @@ cir_timer_interrupt (void)
|
||||
}
|
||||
else if (cir_proto == CIR_PROTO_RC6)
|
||||
{
|
||||
if (cir_seq == 16 || cir_seq == 32)
|
||||
cir_data &= 0x00ff;
|
||||
else
|
||||
if (cir_seq != 16 && cir_seq != 32)
|
||||
ignore_input = 1;
|
||||
}
|
||||
else if (cir_proto == CIR_PROTO_RC5)
|
||||
{
|
||||
if (cir_seq == 14)
|
||||
cir_data &= 0x003f;
|
||||
else
|
||||
if (cir_seq != 14)
|
||||
ignore_input = 1;
|
||||
}
|
||||
else
|
||||
@@ -603,7 +909,8 @@ cir_timer_interrupt (void)
|
||||
{
|
||||
cir_input_last = now;
|
||||
/* Notify thread */
|
||||
chEvtSignal (pin_thread, (eventmask_t)1);
|
||||
if (pin_thread)
|
||||
chEvtSignalI (pin_thread, EV_PINPAD_INPUT_DONE);
|
||||
}
|
||||
|
||||
#if defined(DEBUG_CIR)
|
||||
|
||||
@@ -51,7 +51,7 @@ uint8_t pin_input_len;
|
||||
|
||||
#define OFF '\x00'
|
||||
#define ENTER '\x0a'
|
||||
static struct led_pattern { uint8_t c, v; } led_pattern[] =
|
||||
static struct led_pattern { uint8_t c, v; } led_pattern[] =
|
||||
{
|
||||
/* char : dp a b c d e f g */
|
||||
{ ENTER, 0xf8 }, /* |- : 1 1 1 1 1 0 0 0 (enter) */
|
||||
@@ -117,21 +117,19 @@ blink_dp (void)
|
||||
}
|
||||
|
||||
static Thread *pin_thread;
|
||||
#define EV_SW_PUSH (eventmask_t)1
|
||||
|
||||
void
|
||||
dial_sw_interrupt (void)
|
||||
{
|
||||
dial_sw_disable ();
|
||||
chEvtSignalI (pin_thread, EV_SW_PUSH);
|
||||
chEvtSignalI (pin_thread, EV_PINPAD_INPUT_DONE);
|
||||
palClearPad (IOPORT1, GPIOA_LED2);
|
||||
}
|
||||
|
||||
|
||||
msg_t
|
||||
pin_main (void *arg)
|
||||
int
|
||||
pinpad_getline (int msg_code, systime_t timeout)
|
||||
{
|
||||
int msg_code = (int)arg;
|
||||
uint16_t count, count_prev;
|
||||
uint8_t input_mode;
|
||||
uint8_t sw_push_count;
|
||||
@@ -150,7 +148,7 @@ pin_main (void *arg)
|
||||
sw_push_count = 0;
|
||||
sw_event = 0;
|
||||
|
||||
while (!chThdShouldTerminate ())
|
||||
while (1)
|
||||
{
|
||||
eventmask_t m;
|
||||
|
||||
@@ -158,7 +156,7 @@ pin_main (void *arg)
|
||||
dial_sw_enable ();
|
||||
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_DISP_BLINK_INTERVAL0);
|
||||
|
||||
if (m == EV_SW_PUSH || sw_push_count)
|
||||
if (m == EV_PINPAD_INPUT_DONE || sw_push_count)
|
||||
{
|
||||
if (palReadPad (IOPORT2, GPIOB_BUTTON) == 0)
|
||||
sw_push_count++;
|
||||
@@ -218,5 +216,5 @@ pin_main (void *arg)
|
||||
led_disp (OFF);
|
||||
TIM4->CR1 &= ~TIM_CR1_CEN;
|
||||
dial_sw_disable ();
|
||||
return 0;
|
||||
return pin_input_len;
|
||||
}
|
||||
|
||||
372
src/pin-dnd.c
Normal file
372
src/pin-dnd.c
Normal file
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* pin-dnd.c -- PIN input support (Drag and Drop with File Manager)
|
||||
*
|
||||
* Copyright (C) 2011 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 "config.h"
|
||||
#include "ch.h"
|
||||
#include "board.h"
|
||||
#include "gnuk.h"
|
||||
#include "usb-msc.h"
|
||||
|
||||
struct folder {
|
||||
uint8_t parent;
|
||||
uint8_t children[7];
|
||||
};
|
||||
|
||||
static struct folder folders[8];
|
||||
static const struct folder folder_ini = { 0, { 1, 2, 3, 4, 5, 6, 7 } };
|
||||
|
||||
|
||||
uint8_t pin_input_buffer[MAX_PIN_CHARS];
|
||||
uint8_t pin_input_len;
|
||||
|
||||
static Thread *pin_thread;
|
||||
|
||||
/*
|
||||
* Let user input PIN string.
|
||||
* Return length of the string.
|
||||
* The string itself is in PIN_INPUT_BUFFER.
|
||||
*/
|
||||
int
|
||||
pinpad_getline (int msg_code, systime_t timeout)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
(void)msg_code;
|
||||
(void)timeout;
|
||||
|
||||
DEBUG_INFO (">>>\r\n");
|
||||
|
||||
pin_input_len = 0;
|
||||
|
||||
msc_media_insert_change (1);
|
||||
|
||||
memset (folders, 0, sizeof folders);
|
||||
memcpy (folders, &folder_ini, sizeof folder_ini);
|
||||
|
||||
while (1)
|
||||
{
|
||||
chSysLock ();
|
||||
pin_thread = chThdSelf ();
|
||||
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
|
||||
led_blink (LED_ONESHOT);
|
||||
if (msg != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
msc_media_insert_change (0);
|
||||
|
||||
if (msg == 1)
|
||||
return pin_input_len;
|
||||
else
|
||||
return -1; /* cancel */
|
||||
}
|
||||
|
||||
static void pinpad_input (void)
|
||||
{
|
||||
chSysLock ();
|
||||
pin_thread->p_u.rdymsg = 0;
|
||||
chSchReadyI (pin_thread);
|
||||
chSysUnlock ();
|
||||
}
|
||||
|
||||
static void pinpad_finish_entry (int cancel)
|
||||
{
|
||||
chSysLock ();
|
||||
if (cancel)
|
||||
pin_thread->p_u.rdymsg = 2;
|
||||
else
|
||||
pin_thread->p_u.rdymsg = 1;
|
||||
chSchReadyI (pin_thread);
|
||||
chSysUnlock ();
|
||||
}
|
||||
|
||||
#define TOTAL_SECTOR 68
|
||||
|
||||
/*
|
||||
|
||||
blk=0: master boot record sector
|
||||
blk=1: fat0
|
||||
blk=2: fat1
|
||||
blk=3: root directory
|
||||
blk=4: fat cluster #2
|
||||
...
|
||||
blk=4+63: fat cluster #2+63
|
||||
*/
|
||||
|
||||
static const uint8_t d0_0_sector[] = {
|
||||
0xeb, 0x3c, /* Jump instruction */
|
||||
0x90, /* NOP */
|
||||
|
||||
0x6d, 0x6b, 0x64, 0x6f, 0x73, 0x66, 0x73, 0x20, /* "mkdosfs " */
|
||||
|
||||
0x00, 0x02, /* Bytes per sector: 512 */
|
||||
|
||||
0x01, /* sectors per cluster: 1 */
|
||||
0x01, 0x00, /* reserved sector count: 1 */
|
||||
0x02, /* Number of FATs: 2 */
|
||||
0x10, 0x00, /* Max. root directory entries: 16 (1 sector) */
|
||||
TOTAL_SECTOR, 0x00, /* total sectors: 68 */
|
||||
0xf8, /* media descriptor: fixed disk */
|
||||
0x01, 0x00, /* sectors per FAT: 1 */
|
||||
0x04, 0x00, /* sectors per track: 4 */
|
||||
0x01, 0x00, /* number of heads: 1 */
|
||||
0x00, 0x00, 0x00, 0x00, /* hidden sectors: 0 */
|
||||
0x00, 0x00, 0x00, 0x00, /* total sectors (long) */
|
||||
0x00, /* drive number */
|
||||
0x00, /* reserved */
|
||||
0x29, /* extended boot signature */
|
||||
0xbf, 0x86, 0x75, 0xea, /* Volume ID (serial number) (Little endian) */
|
||||
|
||||
/* Volume label: DNDpinentry */
|
||||
'D', 'n', 'D', 'p', 'i', 'n', 'e', 'n', 't', 'r', 'y',
|
||||
|
||||
0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, /* FAT12 */
|
||||
|
||||
0x0e, /* push cs */
|
||||
0x1f, /* pop ds */
|
||||
0xbe, 0x5b, 0x7c, /* mov si, offset message_txt */
|
||||
0xac, /* 1: lodsb */
|
||||
0x22, 0xc0, /* and al, al */
|
||||
0x74, 0x0b, /* jz 2f */
|
||||
0x56, /* push si */
|
||||
0xb4, 0x0e, /* mov ah, 0eh */
|
||||
0xbb, 0x07, 0x00, /* mov bx, 0007h */
|
||||
0xcd, 0x10, /* int 10h ; output char color=white */
|
||||
0x5e, /* pop si */
|
||||
0xeb, 0xf0, /* jmp 1b */
|
||||
0x32, 0xe4, /* 2: xor ah, ah */
|
||||
0xcd, 0x16, /* int 16h; key input */
|
||||
0xcd, 0x19, /* int 19h; load OS */
|
||||
0xeb, 0xfe, /* 3: jmp 3b */
|
||||
|
||||
/* "This is not a bootable disk... \r\n" */
|
||||
0x54, 0x68, 0x69, 0x73, 0x20,
|
||||
0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61,
|
||||
0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2e, 0x20,
|
||||
0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20,
|
||||
0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61,
|
||||
0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79,
|
||||
0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72,
|
||||
0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20,
|
||||
0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74,
|
||||
0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e,
|
||||
0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t d0_fat0_sector[] = {
|
||||
0xf8, 0xff, 0xff, /* Media descriptor: fixed disk */ /* EOC */
|
||||
0xff, 0xff, 0xff, /* cluster 2: used */ /* cluster 3: used */
|
||||
0xff, 0xff, 0xff, /* cluster 4: used */ /* cluster 5: used */
|
||||
0xff, 0xff, 0xff, /* cluster 6: used */ /* cluster 7: used */
|
||||
0xff, 0x0f, 0x00, /* cluster 8: used */ /* cluster 9: free */
|
||||
};
|
||||
|
||||
static uint8_t the_sector[512];
|
||||
|
||||
#define FOLDER_INDEX_TO_CLUSTER_NO(i) (i+1)
|
||||
#define CLUSTER_NO_TO_FOLDER_INDEX(n) (n-1)
|
||||
#define FOLDER_INDEX_TO_LBA(i) (i+3)
|
||||
#define LBA_TO_FOLDER_INDEX(lba) (lba-3)
|
||||
#define FOLDER_INDEX_TO_DIRCHAR(i) ('A'+i-1)
|
||||
#define DIRCHAR_TO_FOLDER_INDEX(c) (c - 'A' + 1)
|
||||
|
||||
static uint8_t *fill_file_entry (uint8_t *p, const uint8_t *filename,
|
||||
uint16_t cluster_no)
|
||||
{
|
||||
memcpy (p, filename, 8+3);
|
||||
p += 11;
|
||||
*p++ = 0x10; /* directory */
|
||||
*p++ = 0x00; /* reserved */
|
||||
memcpy (p, "\x64\x3b\xa7\x61\x3f", 5); /* create time */
|
||||
p += 5;
|
||||
memcpy (p, "\x61\x3f", 2); /* last access */
|
||||
p += 2;
|
||||
*p++ = 0x00; *p++ = 0x00; /* ea-index */
|
||||
memcpy (p, "\x3b\xa7\x61\x3f", 4); /* last modified */
|
||||
p += 4;
|
||||
memcpy (p, &cluster_no, 2); /* cluster # */
|
||||
p += 2;
|
||||
*p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* file size */
|
||||
return p;
|
||||
}
|
||||
|
||||
static void build_directory_sector (uint8_t *p, uint8_t index)
|
||||
{
|
||||
uint16_t cluster_no = FOLDER_INDEX_TO_CLUSTER_NO (index);
|
||||
int i;
|
||||
uint8_t filename[11] = { 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20 };
|
||||
uint8_t child;
|
||||
|
||||
memset (p, 0, 512);
|
||||
|
||||
if (index != 0)
|
||||
{
|
||||
p = fill_file_entry (p, filename, cluster_no);
|
||||
filename[1] = 0x2e;
|
||||
p = fill_file_entry (p, filename, 0);
|
||||
filename[1] = 0x20;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
if ((child = folders[index].children[i]) != 0)
|
||||
{
|
||||
filename[0] = FOLDER_INDEX_TO_DIRCHAR (child);
|
||||
p = fill_file_entry (p, filename, FOLDER_INDEX_TO_CLUSTER_NO (child));
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
int
|
||||
msc_scsi_read (uint32_t lba, const uint8_t **sector_p)
|
||||
{
|
||||
if (!media_available)
|
||||
return SCSI_ERROR_NOT_READY;
|
||||
|
||||
if (lba >= TOTAL_SECTOR)
|
||||
return SCSI_ERROR_ILLEAGAL_REQUEST;
|
||||
|
||||
switch (lba)
|
||||
{
|
||||
case 0:
|
||||
*sector_p = the_sector;
|
||||
memcpy (the_sector, d0_0_sector, sizeof d0_0_sector);
|
||||
memset (the_sector + sizeof d0_0_sector, 0, 512 - sizeof d0_0_sector);
|
||||
the_sector[510] = 0x55;
|
||||
the_sector[511] = 0xaa;
|
||||
return 0;
|
||||
case 1:
|
||||
case 2:
|
||||
*sector_p = the_sector;
|
||||
memcpy (the_sector, d0_fat0_sector, sizeof d0_fat0_sector);
|
||||
memset (the_sector + sizeof d0_fat0_sector, 0,
|
||||
512 - sizeof d0_fat0_sector);
|
||||
return 0;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
*sector_p = the_sector;
|
||||
build_directory_sector (the_sector, LBA_TO_FOLDER_INDEX (lba));
|
||||
return 0;
|
||||
default:
|
||||
*sector_p = the_sector;
|
||||
memset (the_sector, 0, 512);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void parse_directory_sector (const uint8_t *p, uint8_t index)
|
||||
{
|
||||
int i;
|
||||
uint8_t child;
|
||||
int input = 0;
|
||||
int num_children = 0;
|
||||
|
||||
if (index != 0)
|
||||
{
|
||||
uint16_t cluster_no;
|
||||
uint8_t dest_index;
|
||||
|
||||
p += 32; /* skip "." */
|
||||
|
||||
/* ".." */
|
||||
cluster_no = p[26] | (p[27] << 8);
|
||||
dest_index = CLUSTER_NO_TO_FOLDER_INDEX (cluster_no);
|
||||
|
||||
if (dest_index < 1 || dest_index > 7)
|
||||
; /* it can be 255 : root_dir */
|
||||
else
|
||||
if (pin_input_len < MAX_PIN_CHARS - 2)
|
||||
{
|
||||
pin_input_buffer[pin_input_len++]
|
||||
= FOLDER_INDEX_TO_DIRCHAR (index);
|
||||
pin_input_buffer[pin_input_len++]
|
||||
= FOLDER_INDEX_TO_DIRCHAR (dest_index);
|
||||
input = 1;
|
||||
}
|
||||
|
||||
p += 32;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
if (*p >= 'A' && *p <= 'G')
|
||||
{
|
||||
child = DIRCHAR_TO_FOLDER_INDEX (*p);
|
||||
folders[index].children[i] = child;
|
||||
num_children++;
|
||||
}
|
||||
else
|
||||
folders[index].children[i] = 0;
|
||||
p += 32;
|
||||
}
|
||||
|
||||
if (index == 0 && num_children == 1)
|
||||
pinpad_finish_entry (0);
|
||||
else if (input)
|
||||
pinpad_input ();
|
||||
}
|
||||
|
||||
int
|
||||
msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
if (!media_available)
|
||||
return SCSI_ERROR_NOT_READY;
|
||||
|
||||
if (lba >= TOTAL_SECTOR)
|
||||
return SCSI_ERROR_ILLEAGAL_REQUEST;
|
||||
|
||||
if (lba == 1)
|
||||
return 0; /* updating FAT, just ignore */
|
||||
|
||||
if (lba <= 2 || lba >= 11)
|
||||
return SCSI_ERROR_DATA_PROTECT;
|
||||
else
|
||||
{
|
||||
uint8_t index = LBA_TO_FOLDER_INDEX (lba);
|
||||
|
||||
parse_directory_sector (buf, index);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
msc_scsi_stop (uint8_t code)
|
||||
{
|
||||
(void)code;
|
||||
pinpad_finish_entry (1);
|
||||
}
|
||||
32
src/random.c
32
src/random.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* random.c -- get random bytes
|
||||
*
|
||||
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
|
||||
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
@@ -59,6 +59,7 @@ void
|
||||
random_bytes_free (const uint8_t *p)
|
||||
{
|
||||
(void)p;
|
||||
memset (random_word, 0, RANDOM_BYTES_LENGTH);
|
||||
neug_flush ();
|
||||
}
|
||||
|
||||
@@ -70,3 +71,32 @@ get_salt (void)
|
||||
{
|
||||
return neug_get (NEUG_KICK_FILLING);
|
||||
}
|
||||
|
||||
|
||||
#ifdef KEYGEN_SUPPORT
|
||||
/*
|
||||
* Random byte iterator
|
||||
*/
|
||||
uint8_t
|
||||
random_byte (void *arg)
|
||||
{
|
||||
uint8_t *index_p = (uint8_t *)arg;
|
||||
uint8_t index = *index_p;
|
||||
uint8_t *p = ((uint8_t *)random_word) + index;
|
||||
uint8_t v;
|
||||
|
||||
neug_wait_full ();
|
||||
|
||||
v = *p;
|
||||
|
||||
if (++index >= RANDOM_BYTES_LENGTH)
|
||||
{
|
||||
index = 0;
|
||||
neug_flush ();
|
||||
}
|
||||
|
||||
*index_p = index;
|
||||
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
221
src/sha256.c
Normal file
221
src/sha256.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* sha256.c -- Compute SHA-256 hash
|
||||
*
|
||||
* Just for little endian architecture.
|
||||
*
|
||||
* Code taken from:
|
||||
* http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
|
||||
*
|
||||
* File names are sha2.c, sha2.h, brg_types.h, brg_endian.h
|
||||
* in the archive sha2-07-01-07.zip.
|
||||
*
|
||||
* Code is modified in the style of PolarSSL API.
|
||||
*
|
||||
* See original copyright notice below.
|
||||
*/
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "sha256.h"
|
||||
|
||||
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
|
||||
|
||||
static void bswap32_buf (uint32_t *p, int n)
|
||||
{
|
||||
while (n--)
|
||||
p[n] = __builtin_bswap32 (p[n]); /* bswap32 is GCC extention */
|
||||
}
|
||||
|
||||
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
|
||||
|
||||
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
|
||||
|
||||
/* round transforms for SHA256 compression functions */
|
||||
#define vf(n,i) v[(n - i) & 7]
|
||||
|
||||
#define hf(i) (p[i & 15] += \
|
||||
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
|
||||
|
||||
#define v_cycle(i,j) \
|
||||
vf(7,i) += (j ? hf(i) : p[i]) + k_0[i+j] \
|
||||
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
|
||||
vf(3,i) += vf(7,i); \
|
||||
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
|
||||
|
||||
#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
|
||||
#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
|
||||
#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
|
||||
#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
|
||||
#define k_0 k256
|
||||
|
||||
const uint32_t k256[64] = {
|
||||
0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5,
|
||||
0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5,
|
||||
0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3,
|
||||
0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174,
|
||||
0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC,
|
||||
0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA,
|
||||
0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7,
|
||||
0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967,
|
||||
0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13,
|
||||
0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85,
|
||||
0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3,
|
||||
0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070,
|
||||
0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5,
|
||||
0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3,
|
||||
0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208,
|
||||
0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2,
|
||||
};
|
||||
|
||||
void
|
||||
sha256_process (sha256_context *ctx)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t *p = ctx->wbuf;
|
||||
uint32_t v[8];
|
||||
|
||||
memcpy (v, ctx->state, 8 * sizeof (uint32_t));
|
||||
|
||||
for (i = 0; i < 64; i += 16)
|
||||
{
|
||||
v_cycle ( 0, i);
|
||||
v_cycle ( 1, i);
|
||||
v_cycle ( 2, i);
|
||||
v_cycle ( 3, i);
|
||||
v_cycle ( 4, i);
|
||||
v_cycle ( 5, i);
|
||||
v_cycle ( 6, i);
|
||||
v_cycle ( 7, i);
|
||||
v_cycle ( 8, i);
|
||||
v_cycle ( 9, i);
|
||||
v_cycle (10, i);
|
||||
v_cycle (11, i);
|
||||
v_cycle (12, i);
|
||||
v_cycle (13, i);
|
||||
v_cycle (14, i);
|
||||
v_cycle (15, i);
|
||||
}
|
||||
|
||||
ctx->state[0] += v[0];
|
||||
ctx->state[1] += v[1];
|
||||
ctx->state[2] += v[2];
|
||||
ctx->state[3] += v[3];
|
||||
ctx->state[4] += v[4];
|
||||
ctx->state[5] += v[5];
|
||||
ctx->state[6] += v[6];
|
||||
ctx->state[7] += v[7];
|
||||
}
|
||||
|
||||
void
|
||||
sha256_update (sha256_context *ctx, const unsigned char *input,
|
||||
unsigned int ilen)
|
||||
{
|
||||
uint32_t left = (ctx->total[0] & SHA256_MASK);
|
||||
uint32_t fill = SHA256_BLOCK_SIZE - left;
|
||||
|
||||
ctx->total[0] += ilen;
|
||||
if (ctx->total[0] < ilen)
|
||||
ctx->total[1]++;
|
||||
|
||||
while (ilen >= fill)
|
||||
{
|
||||
memcpy (((unsigned char*)ctx->wbuf) + left, input, fill);
|
||||
bswap32_buf (ctx->wbuf, SHA256_BLOCK_SIZE >> 2);
|
||||
sha256_process (ctx);
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
left = 0;
|
||||
fill = SHA256_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen);
|
||||
}
|
||||
|
||||
void
|
||||
sha256_finish (sha256_context *ctx, unsigned char output[32])
|
||||
{
|
||||
uint32_t last = (ctx->total[0] & SHA256_MASK);
|
||||
|
||||
bswap32_buf (ctx->wbuf, (last + 3) >> 2);
|
||||
|
||||
ctx->wbuf[last >> 2] &= 0xffffff80 << (8 * (~last & 3));
|
||||
ctx->wbuf[last >> 2] |= 0x00000080 << (8 * (~last & 3));
|
||||
|
||||
if (last > SHA256_BLOCK_SIZE - 9)
|
||||
{
|
||||
if (last < 60)
|
||||
ctx->wbuf[15] = 0;
|
||||
sha256_process (ctx);
|
||||
last = 0;
|
||||
}
|
||||
else
|
||||
last = (last >> 2) + 1;
|
||||
|
||||
while (last < 14)
|
||||
ctx->wbuf[last++] = 0;
|
||||
|
||||
ctx->wbuf[14] = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
|
||||
ctx->wbuf[15] = ctx->total[0] << 3;
|
||||
sha256_process (ctx);
|
||||
|
||||
bswap32_buf (ctx->state, SHA256_DIGEST_SIZE >> 2);
|
||||
memcpy (output, ctx->state, SHA256_DIGEST_SIZE);
|
||||
memset (ctx, 0, sizeof (sha256_context));
|
||||
}
|
||||
|
||||
const uint32_t initial_state[8] =
|
||||
{
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
void
|
||||
sha256_start (sha256_context *ctx)
|
||||
{
|
||||
ctx->total[0] = ctx->total[1] = 0;
|
||||
memcpy (ctx->state, initial_state, 8 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void
|
||||
sha256 (const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32])
|
||||
{
|
||||
sha256_context ctx;
|
||||
|
||||
sha256_start (&ctx);
|
||||
sha256_update (&ctx, input, ilen);
|
||||
sha256_finish (&ctx, output);
|
||||
}
|
||||
17
src/sha256.h
Normal file
17
src/sha256.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#define SHA256_BLOCK_SIZE 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total[2];
|
||||
uint32_t state[8];
|
||||
uint32_t wbuf[16];
|
||||
} sha256_context;
|
||||
|
||||
extern void sha256 (const unsigned char *input, unsigned int ilen,
|
||||
unsigned char output[32]);
|
||||
extern void sha256_start (sha256_context *ctx);
|
||||
extern void sha256_finish (sha256_context *ctx, unsigned char output[32]);
|
||||
extern void sha256_update (sha256_context *ctx, const unsigned char *input,
|
||||
unsigned int ilen);
|
||||
extern void sha256_process (sha256_context *ctx);
|
||||
@@ -1,7 +0,0 @@
|
||||
STMUSBDIR = ../STM32_USB-FS-Device_Driver
|
||||
STMUSBSRCDIR = $(STMUSBDIR)/src
|
||||
STMUSBINCDIR = $(STMUSBDIR)/inc
|
||||
STMUSBSRC= $(STMUSBSRCDIR)/usb_sil.c \
|
||||
$(STMUSBSRCDIR)/usb_init.c $(STMUSBSRCDIR)/usb_int.c \
|
||||
$(STMUSBSRCDIR)/usb_mem.c $(STMUSBSRCDIR)/usb_core.c \
|
||||
$(STMUSBSRCDIR)/usb_regs.c
|
||||
307
src/sys.c
Normal file
307
src/sys.c
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* sys.c - system services at the first flash ROM blocks
|
||||
*
|
||||
* Copyright (C) 2012 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 "config.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "board.h"
|
||||
#include "usb_lld.h"
|
||||
|
||||
extern uint8_t __flash_start__, __flash_end__;
|
||||
|
||||
|
||||
static void
|
||||
usb_cable_config (int enable)
|
||||
{
|
||||
#if defined(SET_USB_CONDITION)
|
||||
if (SET_USB_CONDITION (enable))
|
||||
palSetPad (IOPORT_USB, GPIO_USB);
|
||||
else
|
||||
palClearPad (IOPORT_USB, GPIO_USB);
|
||||
#else
|
||||
(void)enable;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
set_led (int on)
|
||||
{
|
||||
if (SET_LED_CONDITION (on))
|
||||
palSetPad (IOPORT_LED, GPIO_LED);
|
||||
else
|
||||
palClearPad (IOPORT_LED, GPIO_LED);
|
||||
}
|
||||
|
||||
|
||||
#define FLASH_KEY1 0x45670123UL
|
||||
#define FLASH_KEY2 0xCDEF89ABUL
|
||||
|
||||
static void
|
||||
flash_unlock (void)
|
||||
{
|
||||
FLASH->KEYR = FLASH_KEY1;
|
||||
FLASH->KEYR = FLASH_KEY2;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
flash_wait_for_last_operation (uint32_t timeout)
|
||||
{
|
||||
int status;
|
||||
|
||||
do
|
||||
{
|
||||
status = FLASH->SR;
|
||||
if (--timeout == 0)
|
||||
break;
|
||||
}
|
||||
while ((status & FLASH_SR_BSY) != 0);
|
||||
|
||||
return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR);
|
||||
}
|
||||
|
||||
#define FLASH_PROGRAM_TIMEOUT 0x00010000
|
||||
#define FLASH_ERASE_TIMEOUT 0x01000000
|
||||
|
||||
static int
|
||||
flash_program_halfword (uint32_t addr, uint16_t data)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
|
||||
|
||||
port_disable ();
|
||||
if (status == 0)
|
||||
{
|
||||
FLASH->CR |= FLASH_CR_PG;
|
||||
|
||||
*(volatile uint16_t *)addr = data;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
|
||||
FLASH->CR &= ~FLASH_CR_PG;
|
||||
}
|
||||
port_enable ();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_erase_page (uint32_t addr)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
|
||||
port_disable ();
|
||||
if (status == 0)
|
||||
{
|
||||
FLASH->CR |= FLASH_CR_PER;
|
||||
FLASH->AR = addr;
|
||||
FLASH->CR |= FLASH_CR_STRT;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
FLASH->CR &= ~FLASH_CR_PER;
|
||||
}
|
||||
port_enable ();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_check_blank (const uint8_t *p_start, size_t size)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
for (p = p_start; p < p_start + size; p++)
|
||||
if (*p != 0xff)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
|
||||
{
|
||||
int status;
|
||||
uint32_t flash_start = (uint32_t)&__flash_start__;
|
||||
uint32_t flash_end = (uint32_t)&__flash_end__;
|
||||
|
||||
if (dst_addr < flash_start || dst_addr + len > flash_end)
|
||||
return 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
uint16_t hw = *src++;
|
||||
|
||||
hw |= (*src++ << 8);
|
||||
status = flash_program_halfword (dst_addr, hw);
|
||||
if (status != 0)
|
||||
return 0; /* error return */
|
||||
|
||||
dst_addr += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define OPTION_BYTES_ADDR 0x1ffff800
|
||||
|
||||
static int
|
||||
flash_protect (void)
|
||||
{
|
||||
int status;
|
||||
uint32_t option_bytes_value;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
|
||||
port_disable ();
|
||||
if (status == 0)
|
||||
{
|
||||
FLASH->OPTKEYR = FLASH_KEY1;
|
||||
FLASH->OPTKEYR = FLASH_KEY2;
|
||||
|
||||
FLASH->CR |= FLASH_CR_OPTER;
|
||||
FLASH->CR |= FLASH_CR_STRT;
|
||||
|
||||
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
|
||||
FLASH->CR &= ~FLASH_CR_OPTER;
|
||||
}
|
||||
port_enable ();
|
||||
|
||||
if (status != 0)
|
||||
return 0;
|
||||
|
||||
option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR;
|
||||
return (option_bytes_value & 0xff) == 0xff ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((naked))
|
||||
flash_erase_all_and_exec (void (*entry)(void))
|
||||
{
|
||||
uint32_t addr = (uint32_t)&__flash_start__;
|
||||
uint32_t end = (uint32_t)&__flash_end__;
|
||||
int r;
|
||||
|
||||
while (addr < end)
|
||||
{
|
||||
r = flash_erase_page (addr);
|
||||
if (r != 0)
|
||||
break;
|
||||
|
||||
addr += FLASH_PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (addr >= end)
|
||||
(*entry) ();
|
||||
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static void
|
||||
nvic_enable_vector (uint32_t n, uint32_t prio)
|
||||
{
|
||||
unsigned int sh = (n & 3) << 3;
|
||||
|
||||
NVIC_IPR (n >> 2) = (NVIC_IPR(n >> 2) & ~(0xFF << sh)) | (prio << sh);
|
||||
NVIC_ICPR (n >> 5) = 1 << (n & 0x1F);
|
||||
NVIC_ISER (n >> 5) = 1 << (n & 0x1F);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
nvic_enable_vector (USB_LP_CAN1_RX0_IRQn,
|
||||
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
|
||||
/*
|
||||
* Note that we also have other IRQ(s):
|
||||
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
|
||||
* USBWakeUp_IRQn (suspend/resume)
|
||||
*/
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB1RSTR = 0;
|
||||
|
||||
usb_cable_config (1);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
|
||||
usb_cable_config (0);
|
||||
}
|
||||
|
||||
#define SYSRESETREQ 0x04
|
||||
static void
|
||||
nvic_system_reset (void)
|
||||
{
|
||||
SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ);
|
||||
asm volatile ("dsb");
|
||||
}
|
||||
|
||||
static void __attribute__ ((naked))
|
||||
reset (void)
|
||||
{
|
||||
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
|
||||
"mov.w r0, #0xed00\n\t" /* r0 = SCR */
|
||||
"movt r0, #0xe000\n\t"
|
||||
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
|
||||
"mov r2, #0x1000\n\t"
|
||||
"add r1, r1, r2\n\t"
|
||||
"sub r2, r2, #1\n\t"
|
||||
"bic r1, r1, r2\n\t"
|
||||
"str r1, [r0, #8]\n\t" /* Set SCR->VCR */
|
||||
"ldr r0, [r1], #4\n\t"
|
||||
"msr MSP, r0\n\t" /* Main (exception handler) stack. */
|
||||
"ldr r0, [r1]\n\t" /* Reset handler. */
|
||||
"bx r0\n"
|
||||
: /* no output */ : /* no input */ : "memory");
|
||||
}
|
||||
|
||||
typedef void (*handler)(void);
|
||||
extern uint8_t __ram_end__;
|
||||
|
||||
handler vector[] __attribute__ ((section(".vectors"))) = {
|
||||
(handler)&__ram_end__,
|
||||
reset,
|
||||
(handler)set_led,
|
||||
flash_unlock,
|
||||
(handler)flash_program_halfword,
|
||||
(handler)flash_erase_page,
|
||||
(handler)flash_check_blank,
|
||||
(handler)flash_write,
|
||||
(handler)flash_protect,
|
||||
(handler)flash_erase_all_and_exec,
|
||||
usb_lld_sys_init,
|
||||
usb_lld_sys_shutdown,
|
||||
nvic_system_reset,
|
||||
};
|
||||
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE*/
|
||||
/* sys version: "1.0" */
|
||||
'1', 0, '.', 0, '0', 0,
|
||||
};
|
||||
95
src/sys.h
Normal file
95
src/sys.h
Normal file
@@ -0,0 +1,95 @@
|
||||
extern const uint8_t sys_version[8];
|
||||
|
||||
typedef void (*handler)(void);
|
||||
extern handler vector[14];
|
||||
|
||||
static inline const uint8_t *
|
||||
unique_device_id (void)
|
||||
{
|
||||
/* STM32F103 has 96-bit unique device identifier */
|
||||
const uint8_t *addr = (const uint8_t *)0x1ffff7e8;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_led (int on)
|
||||
{
|
||||
void (*func) (int) = (void (*)(int))vector[2];
|
||||
|
||||
return (*func) (on);
|
||||
}
|
||||
|
||||
static inline void
|
||||
flash_unlock (void)
|
||||
{
|
||||
(*vector[3]) ();
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_program_halfword (uint32_t addr, uint16_t data)
|
||||
{
|
||||
int (*func) (uint32_t, uint16_t) = (int (*)(uint32_t, uint16_t))vector[4];
|
||||
|
||||
return (*func) (addr, data);
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_erase_page (uint32_t addr)
|
||||
{
|
||||
int (*func) (uint32_t) = (int (*)(uint32_t))vector[5];
|
||||
|
||||
return (*func) (addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_check_blank (const uint8_t *p_start, size_t size)
|
||||
{
|
||||
int (*func) (const uint8_t *, int) = (int (*)(const uint8_t *, int))vector[6];
|
||||
|
||||
return (*func) (p_start, size);
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
|
||||
{
|
||||
int (*func) (uint32_t, const uint8_t *, size_t)
|
||||
= (int (*)(uint32_t, const uint8_t *, size_t))vector[7];
|
||||
|
||||
return (*func) (dst_addr, src, len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
flash_protect (void)
|
||||
{
|
||||
int (*func) (void) = (int (*)(void))vector[8];
|
||||
|
||||
return (*func) ();
|
||||
}
|
||||
|
||||
static inline void __attribute__((noreturn))
|
||||
flash_erase_all_and_exec (void (*entry)(void))
|
||||
{
|
||||
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))vector[9];
|
||||
|
||||
(*func) (entry);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static inline void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
(*vector[10]) ();
|
||||
}
|
||||
|
||||
static inline void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
(*vector[11]) ();
|
||||
}
|
||||
|
||||
static inline void
|
||||
nvic_system_reset (void)
|
||||
{
|
||||
(*vector[12]) ();
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* This file is included by usb_prop.c to provide Virtual COM port feature
|
||||
*/
|
||||
|
||||
/* Original is ../Virtual_COM_Port/usb_prop.c by STMicroelectronics */
|
||||
/* Chopped and modified for Gnuk */
|
||||
|
||||
#include "usb-cdc.h"
|
||||
|
||||
/* Original copyright notice is following: */
|
||||
/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
|
||||
* File Name : usb_prop.c
|
||||
* Author : MCD Application Team
|
||||
* Version : V3.1.1
|
||||
* Date : 04/07/2010
|
||||
* Description : All processing related to Virtual Com Port Demo
|
||||
********************************************************************************
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
|
||||
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
|
||||
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
|
||||
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*******************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t bitrate;
|
||||
uint8_t format;
|
||||
uint8_t paritytype;
|
||||
uint8_t datatype;
|
||||
} LINE_CODING;
|
||||
|
||||
static LINE_CODING linecoding = {
|
||||
115200, /* baud rate*/
|
||||
0x00, /* stop bits-1*/
|
||||
0x00, /* parity - none*/
|
||||
0x08 /* no. of bits 8*/
|
||||
};
|
||||
|
||||
static uint8_t *Virtual_Com_Port_GetLineCoding(uint16_t Length)
|
||||
{
|
||||
if (Length == 0)
|
||||
{
|
||||
pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (uint8_t *)&linecoding;
|
||||
}
|
||||
|
||||
static uint8_t *Virtual_Com_Port_SetLineCoding(uint16_t Length)
|
||||
{
|
||||
if (Length == 0)
|
||||
{
|
||||
pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (uint8_t *)&linecoding;
|
||||
}
|
||||
|
||||
static RESULT
|
||||
Virtual_Com_Port_Data_Setup (uint8_t RequestNo)
|
||||
{
|
||||
uint8_t *(*CopyRoutine)(uint16_t);
|
||||
|
||||
CopyRoutine = NULL;
|
||||
|
||||
if (RequestNo == USB_CDC_REQ_GET_LINE_CODING)
|
||||
CopyRoutine = Virtual_Com_Port_GetLineCoding;
|
||||
else if (RequestNo == USB_CDC_REQ_SET_LINE_CODING)
|
||||
CopyRoutine = Virtual_Com_Port_SetLineCoding;
|
||||
|
||||
if (CopyRoutine == NULL)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
pInformation->Ctrl_Info.CopyData = CopyRoutine;
|
||||
pInformation->Ctrl_Info.Usb_wOffset = 0;
|
||||
(*CopyRoutine) (0); /* Set Ctrl_Info.Usb_wLength */
|
||||
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
|
||||
static RESULT
|
||||
Virtual_Com_Port_NoData_Setup (uint8_t RequestNo)
|
||||
{
|
||||
if (RequestNo == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||
/* Do nothing and success */
|
||||
return USB_SUCCESS;
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
@@ -5,3 +5,6 @@
|
||||
#define USB_CDC_REQ_GET_LINE_CODING 0x21
|
||||
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
|
||||
#define USB_CDC_REQ_SEND_BREAK 0x23
|
||||
|
||||
#define VIRTUAL_COM_PORT_DATA_SIZE 16
|
||||
#define VIRTUAL_COM_PORT_INT_SIZE 8
|
||||
|
||||
1423
src/usb-icc.c
1423
src/usb-icc.c
File diff suppressed because it is too large
Load Diff
550
src/usb-msc.c
Normal file
550
src/usb-msc.c
Normal file
@@ -0,0 +1,550 @@
|
||||
/*
|
||||
* usb-msc.c -- USB Mass Storage Class protocol handling
|
||||
*
|
||||
* Copyright (C) 2011, 2012 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 "config.h"
|
||||
#include "ch.h"
|
||||
#include "gnuk.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb-msc.h"
|
||||
|
||||
struct usb_endp_in {
|
||||
const uint8_t *txbuf; /* Pointer to the transmission buffer. */
|
||||
size_t txsize; /* Transmit transfer size remained. */
|
||||
size_t txcnt; /* Transmitted bytes so far. */
|
||||
};
|
||||
|
||||
struct usb_endp_out {
|
||||
uint8_t *rxbuf; /* Pointer to the receive buffer. */
|
||||
size_t rxsize; /* Requested receive transfer size. */
|
||||
size_t rxcnt; /* Received bytes so far. */
|
||||
};
|
||||
|
||||
static struct usb_endp_in ep6_in;
|
||||
static struct usb_endp_out ep6_out;
|
||||
|
||||
static Thread *the_thread;
|
||||
|
||||
#define ENDP_MAX_SIZE 64
|
||||
|
||||
static uint8_t msc_state;
|
||||
|
||||
|
||||
static void usb_start_transmit (const uint8_t *p, size_t n)
|
||||
{
|
||||
size_t pkt_len = n > ENDP_MAX_SIZE ? ENDP_MAX_SIZE : n;
|
||||
|
||||
ep6_in.txbuf = p;
|
||||
ep6_in.txsize = n;
|
||||
ep6_in.txcnt = 0;
|
||||
|
||||
usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, pkt_len);
|
||||
}
|
||||
|
||||
/* "Data Transmitted" callback */
|
||||
void EP6_IN_Callback (void)
|
||||
{
|
||||
size_t n = (size_t)usb_lld_tx_data_len (ENDP6);
|
||||
|
||||
ep6_in.txbuf += n;
|
||||
ep6_in.txcnt += n;
|
||||
ep6_in.txsize -= n;
|
||||
|
||||
if (ep6_in.txsize > 0) /* More data to be sent */
|
||||
{
|
||||
if (ep6_in.txsize > ENDP_MAX_SIZE)
|
||||
n = ENDP_MAX_SIZE;
|
||||
else
|
||||
n = ep6_in.txsize;
|
||||
usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, n);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Transmit has been completed, notify the waiting thread */
|
||||
switch (msc_state)
|
||||
{
|
||||
case MSC_SENDING_CSW:
|
||||
case MSC_DATA_IN:
|
||||
if (the_thread != NULL) {
|
||||
Thread *tp;
|
||||
chSysLockFromIsr ();
|
||||
tp = the_thread;
|
||||
the_thread = NULL;
|
||||
tp->p_u.rdymsg = RDY_OK;
|
||||
chSchReadyI (tp);
|
||||
chSysUnlockFromIsr ();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void usb_start_receive (uint8_t *p, size_t n)
|
||||
{
|
||||
ep6_out.rxbuf = p;
|
||||
ep6_out.rxsize = n;
|
||||
ep6_out.rxcnt = 0;
|
||||
usb_lld_rx_enable (ENDP6);
|
||||
}
|
||||
|
||||
/* "Data Received" call back */
|
||||
void EP6_OUT_Callback (void)
|
||||
{
|
||||
size_t n = (size_t)usb_lld_rx_data_len (ENDP6);
|
||||
int err = 0;
|
||||
|
||||
if (n > ep6_out.rxsize)
|
||||
{ /* buffer overflow */
|
||||
err = 1;
|
||||
n = ep6_out.rxsize;
|
||||
}
|
||||
|
||||
usb_lld_rxcpy (ep6_out.rxbuf, ENDP6, 0, n);
|
||||
ep6_out.rxbuf += n;
|
||||
ep6_out.rxcnt += n;
|
||||
ep6_out.rxsize -= n;
|
||||
|
||||
if (n == ENDP_MAX_SIZE && ep6_out.rxsize != 0)
|
||||
{ /* More data to be received */
|
||||
usb_lld_rx_enable (ENDP6);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Receiving has been completed, notify the waiting thread */
|
||||
switch (msc_state)
|
||||
{
|
||||
case MSC_IDLE:
|
||||
case MSC_DATA_OUT:
|
||||
if (the_thread != NULL) {
|
||||
Thread *tp;
|
||||
chSysLockFromIsr ();
|
||||
tp = the_thread;
|
||||
the_thread = NULL;
|
||||
tp->p_u.rdymsg = err? RDY_RESET : RDY_OK;
|
||||
chSchReadyI (tp);
|
||||
chSysUnlockFromIsr ();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t scsi_inquiry_data_00[] = { 0, 0, 0, 0, 0 };
|
||||
|
||||
static const uint8_t scsi_inquiry_data[] = {
|
||||
0x00, /* Direct Access Device. */
|
||||
0x80, /* RMB = 1: Removable Medium. */
|
||||
0x05, /* Version: SPC-3. */
|
||||
0x02, /* Response format: SPC-3. */
|
||||
36 - 4, /* Additional Length. */
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
/* Vendor Identification */
|
||||
'F', 'S', 'I', 'J', ' ', ' ', ' ', ' ',
|
||||
/* Product Identification */
|
||||
'V', 'i', 'r', 't', 'u', 'a', 'l', ' ',
|
||||
'D', 'i', 's', 'k', ' ', ' ', ' ', ' ',
|
||||
/* Product Revision Level */
|
||||
'1', '.', '0', ' '
|
||||
};
|
||||
|
||||
static uint8_t scsi_sense_data_desc[] = {
|
||||
0x72, /* Response Code: descriptor, current */
|
||||
0x02, /* Sense Key */
|
||||
0x3a, /* ASC (additional sense code) */
|
||||
0x00, /* ASCQ (additional sense code qualifier) */
|
||||
0x00, 0x00, 0x00,
|
||||
0x00, /* Additional Sense Length */
|
||||
};
|
||||
|
||||
static uint8_t scsi_sense_data_fixed[] = {
|
||||
0x70, /* Response Code: fixed, current */
|
||||
0x00,
|
||||
0x02, /* Sense Key */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, /* Additional Sense Length */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x3a, /* ASC (additional sense code) */
|
||||
0x00, /* ASCQ (additional sense code qualifier) */
|
||||
0x00,
|
||||
0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static void set_scsi_sense_data(uint8_t sense_key, uint8_t asc) {
|
||||
scsi_sense_data_desc[1] = scsi_sense_data_fixed[2] = sense_key;
|
||||
scsi_sense_data_desc[2] = scsi_sense_data_fixed[12] = asc;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t buf[512];
|
||||
|
||||
static uint8_t contingent_allegiance;
|
||||
static uint8_t keep_contingent_allegiance;
|
||||
|
||||
uint8_t media_available;
|
||||
|
||||
void msc_media_insert_change (int available)
|
||||
{
|
||||
contingent_allegiance = 1;
|
||||
media_available = available;
|
||||
if (available)
|
||||
{
|
||||
set_scsi_sense_data (0x06, 0x28); /* UNIT_ATTENTION */
|
||||
keep_contingent_allegiance = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_scsi_sense_data (0x02, 0x3a); /* NOT_READY */
|
||||
keep_contingent_allegiance = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t scsi_read_format_capacities (uint32_t *nblocks,
|
||||
uint32_t *secsize)
|
||||
{
|
||||
*nblocks = 68;
|
||||
*secsize = 512;
|
||||
if (media_available)
|
||||
return 2; /* Formatted Media.*/
|
||||
else
|
||||
return 3; /* No Media.*/
|
||||
}
|
||||
|
||||
static struct CBW CBW;
|
||||
|
||||
static struct CSW CSW;
|
||||
|
||||
|
||||
static int msc_recv_data (void)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
chSysLock ();
|
||||
msc_state = MSC_DATA_OUT;
|
||||
the_thread = chThdSelf ();
|
||||
usb_start_receive (buf, 512);
|
||||
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void msc_send_data (const uint8_t *p, size_t n)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
chSysLock ();
|
||||
msc_state = MSC_DATA_IN;
|
||||
the_thread = chThdSelf ();
|
||||
usb_start_transmit (p, n);
|
||||
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
CSW.dCSWDataResidue -= (uint32_t)n;
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
static void msc_send_result (const uint8_t *p, size_t n)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
if (n > CBW.dCBWDataTransferLength)
|
||||
n = CBW.dCBWDataTransferLength;
|
||||
|
||||
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||
msc_send_data (p, n);
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||
}
|
||||
|
||||
CSW.dCSWSignature = MSC_CSW_SIGNATURE;
|
||||
chSysLock ();
|
||||
msc_state = MSC_SENDING_CSW;
|
||||
the_thread = chThdSelf ();
|
||||
usb_start_transmit ((uint8_t *)&CSW, sizeof CSW);
|
||||
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void msc_handle_command (void)
|
||||
{
|
||||
size_t n;
|
||||
uint32_t nblocks, secsize;
|
||||
uint32_t lba;
|
||||
int r;
|
||||
msg_t msg;
|
||||
|
||||
chSysLock();
|
||||
msc_state = MSC_IDLE;
|
||||
the_thread = chThdSelf ();
|
||||
usb_start_receive ((uint8_t *)&CBW, sizeof CBW);
|
||||
chSchGoSleepTimeoutS (THD_STATE_SUSPENDED, MS2ST (1000));
|
||||
msg = chThdSelf ()->p_u.rdymsg;
|
||||
chSysUnlock ();
|
||||
|
||||
if (msg != RDY_OK)
|
||||
{
|
||||
/* Error occured, ignore the request and go into error state */
|
||||
msc_state = MSC_ERROR;
|
||||
if (msg != RDY_TIMEOUT)
|
||||
{
|
||||
chSysLock ();
|
||||
usb_lld_stall_rx (ENDP6);
|
||||
chSysUnlock ();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n = ep6_out.rxcnt;
|
||||
|
||||
if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE))
|
||||
{
|
||||
msc_state = MSC_ERROR;
|
||||
chSysLock ();
|
||||
usb_lld_stall_rx (ENDP6);
|
||||
chSysUnlock ();
|
||||
return;
|
||||
}
|
||||
|
||||
CSW.dCSWTag = CBW.dCBWTag;
|
||||
switch (CBW.CBWCB[0]) {
|
||||
case SCSI_REQUEST_SENSE:
|
||||
if (CBW.CBWCB[1] & 0x01) /* DESC */
|
||||
msc_send_result ((uint8_t *)&scsi_sense_data_desc,
|
||||
sizeof scsi_sense_data_desc);
|
||||
else
|
||||
msc_send_result ((uint8_t *)&scsi_sense_data_fixed,
|
||||
sizeof scsi_sense_data_fixed);
|
||||
/* After the error is reported, clear it, if it's . */
|
||||
if (!keep_contingent_allegiance)
|
||||
{
|
||||
contingent_allegiance = 0;
|
||||
set_scsi_sense_data (0x00, 0x00);
|
||||
}
|
||||
return;
|
||||
case SCSI_INQUIRY:
|
||||
if (CBW.CBWCB[1] & 0x01) /* EVPD */
|
||||
/* assume page 00 */
|
||||
msc_send_result ((uint8_t *)&scsi_inquiry_data_00,
|
||||
sizeof scsi_inquiry_data_00);
|
||||
else
|
||||
msc_send_result ((uint8_t *)&scsi_inquiry_data,
|
||||
sizeof scsi_inquiry_data);
|
||||
return;
|
||||
case SCSI_READ_FORMAT_CAPACITIES:
|
||||
buf[8] = scsi_read_format_capacities (&nblocks, &secsize);
|
||||
buf[0] = buf[1] = buf[2] = 0;
|
||||
buf[3] = 8;
|
||||
buf[4] = (uint8_t)(nblocks >> 24);
|
||||
buf[5] = (uint8_t)(nblocks >> 16);
|
||||
buf[6] = (uint8_t)(nblocks >> 8);
|
||||
buf[7] = (uint8_t)(nblocks >> 0);
|
||||
buf[9] = (uint8_t)(secsize >> 16);
|
||||
buf[10] = (uint8_t)(secsize >> 8);
|
||||
buf[11] = (uint8_t)(secsize >> 0);
|
||||
msc_send_result (buf, 12);
|
||||
return;
|
||||
case SCSI_START_STOP_UNIT:
|
||||
if (CBW.CBWCB[4] == 0x00 /* stop */
|
||||
|| CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */)
|
||||
{
|
||||
msc_scsi_stop (CBW.CBWCB[4]);
|
||||
set_scsi_sense_data (0x05, 0x24); /* ILLEGAL_REQUEST */
|
||||
contingent_allegiance = 1;
|
||||
keep_contingent_allegiance = 1;
|
||||
}
|
||||
/* CBW.CBWCB[4] == 0x01 *//* start */
|
||||
goto success;
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
if (contingent_allegiance)
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||
CSW.dCSWDataResidue = 0;
|
||||
msc_send_result (NULL, 0);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
success:
|
||||
case SCSI_SYNCHRONIZE_CACHE:
|
||||
case SCSI_VERIFY10:
|
||||
case SCSI_ALLOW_MEDIUM_REMOVAL:
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||
msc_send_result (NULL, 0);
|
||||
return;
|
||||
case SCSI_MODE_SENSE6:
|
||||
buf[0] = 0x03;
|
||||
buf[1] = buf[2] = buf[3] = 0;
|
||||
msc_send_result (buf, 4);
|
||||
return;
|
||||
case SCSI_READ_CAPACITY10:
|
||||
scsi_read_format_capacities (&nblocks, &secsize);
|
||||
buf[0] = (uint8_t)((nblocks - 1) >> 24);
|
||||
buf[1] = (uint8_t)((nblocks - 1) >> 16);
|
||||
buf[2] = (uint8_t)((nblocks - 1) >> 8);
|
||||
buf[3] = (uint8_t)((nblocks - 1) >> 0);
|
||||
buf[4] = (uint8_t)(secsize >> 24);
|
||||
buf[5] = (uint8_t)(secsize >> 16);
|
||||
buf[6] = (uint8_t)(secsize >> 8);
|
||||
buf[7] = (uint8_t)(secsize >> 0);
|
||||
msc_send_result (buf, 8);
|
||||
return;
|
||||
case SCSI_READ10:
|
||||
case SCSI_WRITE10:
|
||||
break;
|
||||
default:
|
||||
if (CBW.dCBWDataTransferLength == 0)
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||
CSW.dCSWDataResidue = 0;
|
||||
msc_send_result (NULL, 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
msc_state = MSC_ERROR;
|
||||
chSysLock ();
|
||||
usb_lld_stall_tx (ENDP6);
|
||||
usb_lld_stall_rx (ENDP6);
|
||||
chSysUnlock ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lba = (CBW.CBWCB[2] << 24) | (CBW.CBWCB[3] << 16)
|
||||
| (CBW.CBWCB[4] << 8) | CBW.CBWCB[5];
|
||||
|
||||
/* Transfer direction.*/
|
||||
if (CBW.bmCBWFlags & 0x80)
|
||||
{
|
||||
/* IN, Device to Host.*/
|
||||
msc_state = MSC_DATA_IN;
|
||||
if (CBW.CBWCB[0] == SCSI_READ10)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
CSW.dCSWDataResidue = 0;
|
||||
while (1)
|
||||
{
|
||||
if (CBW.CBWCB[7] == 0 && CBW.CBWCB[8] == 0)
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((r = msc_scsi_read (lba, &p)) == 0)
|
||||
{
|
||||
msc_send_data (p, 512);
|
||||
if (++CBW.CBWCB[5] == 0)
|
||||
if (++CBW.CBWCB[4] == 0)
|
||||
if (++CBW.CBWCB[3] == 0)
|
||||
++CBW.CBWCB[2];
|
||||
if (CBW.CBWCB[8]-- == 0)
|
||||
CBW.CBWCB[7]--;
|
||||
CSW.dCSWDataResidue += 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||
contingent_allegiance = 1;
|
||||
if (r == SCSI_ERROR_NOT_READY)
|
||||
set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
|
||||
else
|
||||
set_scsi_sense_data (r, 0x00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
msc_send_result (NULL, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* OUT, Host to Device.*/
|
||||
if (CBW.CBWCB[0] == SCSI_WRITE10)
|
||||
{
|
||||
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (CBW.CBWCB[8] == 0 && CBW.CBWCB[7] == 0)
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||
break;
|
||||
}
|
||||
|
||||
msc_recv_data ();
|
||||
if ((r = msc_scsi_write (lba, buf, 512)) == 0)
|
||||
{
|
||||
if (++CBW.CBWCB[5] == 0)
|
||||
if (++CBW.CBWCB[4] == 0)
|
||||
if (++CBW.CBWCB[3] == 0)
|
||||
++CBW.CBWCB[2];
|
||||
if (CBW.CBWCB[8]-- == 0)
|
||||
CBW.CBWCB[7]--;
|
||||
CSW.dCSWDataResidue -= 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||
contingent_allegiance = 1;
|
||||
if (r == SCSI_ERROR_NOT_READY)
|
||||
set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
|
||||
else
|
||||
set_scsi_sense_data (r, 0x00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
msc_send_result (NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static msg_t
|
||||
msc_main (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
/* Initially, it starts with no media */
|
||||
msc_media_insert_change (0);
|
||||
while (1)
|
||||
msc_handle_command ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WORKING_AREA(wa_msc_thread, 128);
|
||||
|
||||
void msc_init (void)
|
||||
{
|
||||
chThdCreateStatic (wa_msc_thread, sizeof (wa_msc_thread),
|
||||
NORMALPRIO, msc_main, NULL);
|
||||
}
|
||||
52
src/usb-msc.h
Normal file
52
src/usb-msc.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#define MSC_CBW_SIGNATURE 0x43425355
|
||||
#define MSC_CSW_SIGNATURE 0x53425355
|
||||
|
||||
#define MSC_GET_MAX_LUN_COMMAND 0xFE
|
||||
#define MSC_MASS_STORAGE_RESET_COMMAND 0xFF
|
||||
|
||||
#define MSC_CSW_STATUS_PASSED 0
|
||||
#define MSC_CSW_STATUS_FAILED 1
|
||||
|
||||
#define SCSI_INQUIRY 0x12
|
||||
#define SCSI_MODE_SENSE6 0x1A
|
||||
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E
|
||||
#define SCSI_READ10 0x28
|
||||
#define SCSI_READ_CAPACITY10 0x25
|
||||
#define SCSI_REQUEST_SENSE 0x03
|
||||
#define SCSI_START_STOP_UNIT 0x1B
|
||||
#define SCSI_TEST_UNIT_READY 0x00
|
||||
#define SCSI_WRITE10 0x2A
|
||||
#define SCSI_VERIFY10 0x2F
|
||||
#define SCSI_READ_FORMAT_CAPACITIES 0x23
|
||||
|
||||
#define SCSI_SYNCHRONIZE_CACHE 0x35
|
||||
|
||||
#define MSC_IDLE 0
|
||||
#define MSC_DATA_OUT 1
|
||||
#define MSC_DATA_IN 2
|
||||
#define MSC_SENDING_CSW 3
|
||||
#define MSC_ERROR 4
|
||||
|
||||
struct CBW {
|
||||
uint32_t dCBWSignature;
|
||||
uint32_t dCBWTag;
|
||||
uint32_t dCBWDataTransferLength;
|
||||
uint8_t bmCBWFlags;
|
||||
uint8_t bCBWLUN;
|
||||
uint8_t bCBWCBLength;
|
||||
uint8_t CBWCB[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CSW {
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SCSI_ERROR_NOT_READY 2
|
||||
#define SCSI_ERROR_ILLEAGAL_REQUEST 5
|
||||
#define SCSI_ERROR_UNIT_ATTENTION 6
|
||||
#define SCSI_ERROR_DATA_PROTECT 7
|
||||
|
||||
extern uint8_t media_available;
|
||||
@@ -1,37 +1,40 @@
|
||||
/* USB configuration file for USB-FS-Device_Lib */
|
||||
/*
|
||||
* For detail, please see the documentation of
|
||||
* STM32F10x USB Full Speed Device Library (USB-FS-Device_Lib)
|
||||
* by STMicroelectronics
|
||||
*/
|
||||
/* USB buffer memory definition and number of string descriptors */
|
||||
|
||||
#ifndef __USB_CONF_H
|
||||
#define __USB_CONF_H
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#define EP_NUM (6)
|
||||
#else
|
||||
#define EP_NUM (3)
|
||||
#endif
|
||||
|
||||
#define BTABLE_ADDRESS (0x00)
|
||||
#define NUM_STRING_DESC 7
|
||||
|
||||
/* Control pipe */
|
||||
/* EP0 */
|
||||
#define ENDP0_RXADDR (0x40)
|
||||
#define ENDP0_TXADDR (0x80)
|
||||
|
||||
/* CCID/ICCD BULK_IN, BULK_OUT */
|
||||
/* EP1 */
|
||||
#define ENDP1_TXADDR (0xc0)
|
||||
#define ENDP1_RXADDR (0x100)
|
||||
|
||||
/* HID INTR_IN, INTR_OUT */
|
||||
/* EP2 */
|
||||
#define ENDP2_RXADDR (0x100)
|
||||
#define ENDP2_TXADDR (0x140)
|
||||
#define ENDP2_RXADDR (0x148)
|
||||
|
||||
/* CDC BULK_IN, INTR_IN, BULK_OUT */
|
||||
/* EP3 */
|
||||
#define ENDP3_TXADDR (0x140)
|
||||
#define ENDP3_TXADDR (0x14a)
|
||||
/* EP4 */
|
||||
#define ENDP4_TXADDR (0x180)
|
||||
#define ENDP4_TXADDR (0x15a)
|
||||
/* EP5 */
|
||||
#define ENDP5_RXADDR (0x190)
|
||||
#define ENDP5_RXADDR (0x162)
|
||||
|
||||
#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )
|
||||
/* 0x172 - 0x180 : 14-byte */
|
||||
|
||||
/* MSC BULK_IN, BULK_OUT */
|
||||
/* EP6 */
|
||||
#define ENDP6_TXADDR (0x180)
|
||||
#define ENDP6_RXADDR (0x1c0)
|
||||
|
||||
/* EP7: free */
|
||||
|
||||
#endif /* __USB_CONF_H */
|
||||
|
||||
454
src/usb_ctrl.c
Normal file
454
src/usb_ctrl.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
||||
*
|
||||
* Copyright (C) 2010, 2011, 2012 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Packet size of USB Bulk transfer for full speed */
|
||||
#define GNUK_MAX_PACKET_SIZE 64
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb_conf.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#include "usb-cdc.h"
|
||||
|
||||
struct line_coding
|
||||
{
|
||||
uint32_t bitrate;
|
||||
uint8_t format;
|
||||
uint8_t paritytype;
|
||||
uint8_t datatype;
|
||||
};
|
||||
|
||||
static struct line_coding line_coding = {
|
||||
115200, /* baud rate: 115200 */
|
||||
0x00, /* stop bits: 1 */
|
||||
0x00, /* parity: none */
|
||||
0x08 /* bits: 8 */
|
||||
};
|
||||
|
||||
static int
|
||||
vcom_port_data_setup (uint8_t req, uint8_t req_no)
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
|
||||
{
|
||||
usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else /* USB_SETUP_SET (req) */
|
||||
{
|
||||
if (req_no == USB_CDC_REQ_SET_LINE_CODING)
|
||||
{
|
||||
usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||
/* Do nothing and success */
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
#define VCOM_NUM_INTERFACES 2
|
||||
#else
|
||||
#define VCOM_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
#include "usb-msc.h"
|
||||
#define MSC_NUM_INTERFACES 1
|
||||
#else
|
||||
#define MSC_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#define NUM_INTERFACES (1+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
|
||||
#define MSC_INTERFACE_NO (1+VCOM_NUM_INTERFACES)
|
||||
|
||||
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
|
||||
|
||||
static void
|
||||
gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
|
||||
{
|
||||
if (interface == 0)
|
||||
{
|
||||
if (!stop)
|
||||
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR, ENDP1_TXADDR,
|
||||
GNUK_MAX_PACKET_SIZE);
|
||||
else
|
||||
{
|
||||
usb_lld_stall_rx (ENDP1);
|
||||
usb_lld_stall_tx (ENDP1);
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (interface == 1)
|
||||
{
|
||||
if (!stop)
|
||||
usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
|
||||
else
|
||||
usb_lld_stall_tx (ENDP4);
|
||||
}
|
||||
else if (interface == 2)
|
||||
{
|
||||
if (!stop)
|
||||
{
|
||||
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
|
||||
usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
|
||||
VIRTUAL_COM_PORT_DATA_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_lld_stall_tx (ENDP3);
|
||||
usb_lld_stall_rx (ENDP5);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
else if (interface == MSC_INTERFACE_NO)
|
||||
{
|
||||
if (!stop)
|
||||
{
|
||||
usb_lld_setup_endpoint (ENDP6, EP_BULK, 0,
|
||||
ENDP6_RXADDR, ENDP6_TXADDR, 64);
|
||||
usb_lld_stall_rx (ENDP6);
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_lld_stall_tx (ENDP6);
|
||||
usb_lld_stall_rx (ENDP6);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_device_reset (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Set DEVICE as not configured */
|
||||
usb_lld_set_configuration (0);
|
||||
|
||||
/* Current Feature initialization */
|
||||
usb_lld_set_feature (Config_Descriptor.Descriptor[7]);
|
||||
|
||||
usb_lld_reset ();
|
||||
|
||||
/* Initialize Endpoint 0 */
|
||||
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
|
||||
GNUK_MAX_PACKET_SIZE);
|
||||
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i, 0);
|
||||
|
||||
bDeviceState = ATTACHED;
|
||||
}
|
||||
|
||||
#define USB_CCID_REQ_ABORT 0x01
|
||||
#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02
|
||||
#define USB_CCID_REQ_GET_DATA_RATES 0x03
|
||||
|
||||
static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
|
||||
|
||||
static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
|
||||
|
||||
#if defined(PINPAD_DND_SUPPORT)
|
||||
static const uint8_t lun_table[] = { 0, 0, 0, 0, };
|
||||
#endif
|
||||
|
||||
static const uint8_t *const mem_info[] = { &_regnual_start, &__heap_end__, };
|
||||
|
||||
#define USB_FSIJ_GNUK_MEMINFO 0
|
||||
#define USB_FSIJ_GNUK_DOWNLOAD 1
|
||||
#define USB_FSIJ_GNUK_EXEC 2
|
||||
|
||||
static uint32_t rbit (uint32_t v)
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
|
||||
return r;
|
||||
}
|
||||
|
||||
/* After calling this function, CRC module remain enabled. */
|
||||
static int download_check_crc32 (const uint32_t *end_p)
|
||||
{
|
||||
uint32_t crc32 = *end_p;
|
||||
const uint32_t *p;
|
||||
|
||||
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
||||
CRC->CR = CRC_CR_RESET;
|
||||
|
||||
for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
|
||||
CRC->DR = rbit (*p);
|
||||
|
||||
if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
|
||||
return USB_SUCCESS;
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int
|
||||
gnuk_setup (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == USB_FSIJ_GNUK_MEMINFO)
|
||||
{
|
||||
usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else /* SETUP_SET */
|
||||
{
|
||||
uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
|
||||
|
||||
if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
|
||||
{
|
||||
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (addr < &_regnual_start || addr + len > &__heap_end__)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (index + len < 256)
|
||||
memset (addr + index + len, 0, 256 - (index + len));
|
||||
|
||||
usb_lld_set_data_to_recv (addr, len);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0)
|
||||
{
|
||||
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
if (((uint32_t)addr & 0x03))
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
return download_check_crc32 ((uint32_t *)addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
||||
if (index == 0)
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
|
||||
{
|
||||
usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
|
||||
{
|
||||
usb_lld_set_data_to_send (data_rate_table,
|
||||
sizeof (data_rate_table));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (req_no == USB_CCID_REQ_ABORT)
|
||||
/* wValue: bSeq, bSlot */
|
||||
/* Abortion is not supported in Gnuk */
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (index == 1)
|
||||
return vcom_port_data_setup (req, req_no);
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
else if (index == MSC_INTERFACE_NO)
|
||||
{
|
||||
if (USB_SETUP_GET (req))
|
||||
{
|
||||
if (req_no == MSC_GET_MAX_LUN_COMMAND)
|
||||
{
|
||||
usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
|
||||
/* Should call resetting MSC thread, something like msc_reset() */
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static void gnuk_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index,
|
||||
uint16_t len)
|
||||
{
|
||||
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
|
||||
&& USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0)
|
||||
{
|
||||
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
||||
return;
|
||||
|
||||
(void)value; (void)index;
|
||||
usb_lld_prepare_shutdown (); /* No further USB communication */
|
||||
*icc_state_p = ICC_STATE_EXEC_REQUESTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
||||
{
|
||||
(void)index;
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Device_Descriptor.Descriptor,
|
||||
Device_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
{
|
||||
usb_lld_set_data_to_send (Config_Descriptor.Descriptor,
|
||||
Config_Descriptor.Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
uint8_t desc_index = value & 0xff;
|
||||
|
||||
if (desc_index < NUM_STRING_DESC)
|
||||
{
|
||||
usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor,
|
||||
String_Descriptors[desc_index].Descriptor_Size);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int gnuk_usb_event (uint8_t event_type, uint16_t value)
|
||||
{
|
||||
int i;
|
||||
uint8_t current_conf;
|
||||
|
||||
switch (event_type)
|
||||
{
|
||||
case USB_EVENT_ADDRESS:
|
||||
bDeviceState = ADDRESSED;
|
||||
return USB_SUCCESS;
|
||||
case USB_EVENT_CONFIG:
|
||||
current_conf = usb_lld_current_configuration ();
|
||||
if (current_conf == 0)
|
||||
{
|
||||
if (value != 1)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
usb_lld_set_configuration (value);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i, 0);
|
||||
bDeviceState = CONFIGURED;
|
||||
}
|
||||
else if (current_conf != value)
|
||||
{
|
||||
if (value != 0)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
usb_lld_set_configuration (0);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
gnuk_setup_endpoints_for_interface (i, 1);
|
||||
bDeviceState = ADDRESSED;
|
||||
}
|
||||
/* Do nothing when current_conf == value */
|
||||
return USB_SUCCESS;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
||||
{
|
||||
static uint8_t zero = 0;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case USB_SET_INTERFACE:
|
||||
if (alt != 0)
|
||||
return USB_UNSUPPORT;
|
||||
else
|
||||
{
|
||||
gnuk_setup_endpoints_for_interface (interface, 0);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
|
||||
case USB_GET_INTERFACE:
|
||||
usb_lld_set_data_to_send (&zero, 1);
|
||||
return USB_SUCCESS;
|
||||
|
||||
default:
|
||||
case USB_QUERY_INTERFACE:
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to USB core
|
||||
*/
|
||||
|
||||
const struct usb_device_method Device_Method = {
|
||||
gnuk_device_reset,
|
||||
gnuk_ctrl_write_finish,
|
||||
gnuk_setup,
|
||||
gnuk_get_descriptor,
|
||||
gnuk_usb_event,
|
||||
gnuk_interface,
|
||||
};
|
||||
|
||||
CH_IRQ_HANDLER (Vector90)
|
||||
{
|
||||
CH_IRQ_PROLOGUE();
|
||||
chSysLockFromIsr();
|
||||
|
||||
usb_interrupt_handler ();
|
||||
|
||||
chSysUnlockFromIsr();
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
133
src/usb_desc.c
133
src/usb_desc.c
@@ -3,8 +3,11 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "usb_lib.h"
|
||||
#include "usb_desc.h"
|
||||
#include "ch.h"
|
||||
#include "sys.h"
|
||||
#include "usb_lld.h"
|
||||
#include "usb_conf.h"
|
||||
#include "usb-cdc.h"
|
||||
|
||||
#define USB_ICC_INTERFACE_CLASS 0x0B
|
||||
#define USB_ICC_INTERFACE_SUBCLASS 0x00
|
||||
@@ -15,28 +18,41 @@
|
||||
static const uint8_t gnukDeviceDescriptor[] = {
|
||||
18, /* bLength */
|
||||
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
0x00, 0x02, /* bcdUSB = 2.00 */
|
||||
0x10, 0x01, /* bcdUSB = 1.1 */
|
||||
0x00, /* bDeviceClass: 0 means deferred to interface */
|
||||
0x00, /* bDeviceSubClass */
|
||||
0x00, /* bDeviceProtocol */
|
||||
0x40, /* bMaxPacketSize0 */
|
||||
0x4b, 0x23, /* idVendor = 0x234b (FSIJ) */
|
||||
0x00, 0x00, /* idProduct = 0x0000 (FSIJ USB Token) */
|
||||
0x00, 0x02, /* bcdDevice = 2.00 */
|
||||
#include "usb-vid-pid-ver.c.inc"
|
||||
1, /* Index of string descriptor describing manufacturer */
|
||||
2, /* Index of string descriptor describing product */
|
||||
3, /* Index of string descriptor describing the device's serial number */
|
||||
0x01 /* bNumConfigurations */
|
||||
};
|
||||
|
||||
#define ICC_TOTAL_LENGTH (9+9+54+7+7)
|
||||
#define ICC_NUM_INTERFACES 1
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#define W_TOTAL_LENGTH (9+9+54+7+7+9+5+5+4+5+7+9+7+7)
|
||||
#define NUM_INTERFACES 3 /* two for CDC, one for GPG */
|
||||
#define VCOM_TOTAL_LENGTH (9+5+5+4+5+7+9+7+7)
|
||||
#define VCOM_NUM_INTERFACES 2
|
||||
#else
|
||||
#define W_TOTAL_LENGTH (9+9+54+7+7)
|
||||
#define NUM_INTERFACES 1 /* GPG only */
|
||||
#define VCOM_TOTAL_LENGTH 0
|
||||
#define VCOM_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
#define MSC_TOTAL_LENGTH (9+7+7)
|
||||
#define MSC_NUM_INTERFACES 1
|
||||
#else
|
||||
#define MSC_TOTAL_LENGTH 0
|
||||
#define MSC_NUM_INTERFACES 0
|
||||
#endif
|
||||
|
||||
#define W_TOTAL_LENGTH (ICC_TOTAL_LENGTH+VCOM_TOTAL_LENGTH+MSC_TOTAL_LENGTH)
|
||||
#define NUM_INTERFACES (ICC_NUM_INTERFACES+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
|
||||
|
||||
|
||||
/* Configuation Descriptor */
|
||||
static const uint8_t gnukConfigDescriptor[] = {
|
||||
9, /* bLength: Configuation Descriptor size */
|
||||
@@ -86,8 +102,8 @@ static const uint8_t gnukConfigDescriptor[] = {
|
||||
* It is different now for better interaction to GPG's in-stock
|
||||
* ccid-driver.
|
||||
*/
|
||||
0x42, 0x08, 0x04, 0x00, /* dwFeatures (not ICCD):
|
||||
* Short and extended APDU level: 0x40000 *
|
||||
0x42, 0x08, 0x02, 0x00, /* dwFeatures (not ICCD):
|
||||
* Short APDU level : 0x20000 *
|
||||
* (what? means ICCD?) : 0x00800 *
|
||||
* Automatic IFSD : 0x00400
|
||||
* NAD value other than 0x00 : 0x00200
|
||||
@@ -100,12 +116,12 @@ static const uint8_t gnukConfigDescriptor[] = {
|
||||
* Auto activaction of ICC : 0x00004
|
||||
* Automatic conf. based on ATR : 0x00002 g
|
||||
*/
|
||||
0x40, 0x01, 0, 0, /* dwMaxCCIDMessageLength */
|
||||
0x0f, 0x01, 0, 0, /* dwMaxCCIDMessageLength: 271 */
|
||||
0xff, /* bClassGetResponse: */
|
||||
0xff, /* bClassEnvelope: */
|
||||
0, 0, /* wLCDLayout: FIXED VALUE */
|
||||
#if defined(PINPAD_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT)
|
||||
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DND_SUPPORT)
|
||||
1, /* bPinSupport: with PIN pad (verify) */
|
||||
#elif defined(PINPAD_DIAL_SUPPORT)
|
||||
3, /* bPinSupport: with PIN pad (verify, modify) */
|
||||
@@ -114,17 +130,17 @@ static const uint8_t gnukConfigDescriptor[] = {
|
||||
0, /* bPinSupport: No PIN pad */
|
||||
#endif
|
||||
1, /* bMaxCCIDBusySlots: 1 */
|
||||
/*Endpoint 1 Descriptor*/
|
||||
/*Endpoint IN1 Descriptor*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
0x81, /* bEndpointAddress: (IN1) */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
USB_ICC_DATA_SIZE, 0x00, /* wMaxPacketSize: */
|
||||
0x00, /* bInterval */
|
||||
/*Endpoint 2 Descriptor*/
|
||||
/*Endpoint OUT1 Descriptor*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
0x02, /* bEndpointAddress: (OUT2) */
|
||||
0x01, /* bEndpointAddress: (OUT1) */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
USB_ICC_DATA_SIZE, 0x00, /* wMaxPacketSize: */
|
||||
0x00, /* bInterval */
|
||||
@@ -193,7 +209,40 @@ static const uint8_t gnukConfigDescriptor[] = {
|
||||
0x83, /* bEndpointAddress: (IN3) */
|
||||
0x02, /* bmAttributes: Bulk */
|
||||
VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */
|
||||
0x00 /* bInterval */
|
||||
0x00, /* bInterval */
|
||||
#endif
|
||||
#ifdef PINPAD_DND_SUPPORT
|
||||
/* Interface Descriptor.*/
|
||||
9, /* bLength: Interface Descriptor size */
|
||||
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
0x03, /* bInterfaceNumber. */
|
||||
#else
|
||||
0x01, /* bInterfaceNumber. */
|
||||
#endif
|
||||
0x00, /* bAlternateSetting. */
|
||||
0x02, /* bNumEndpoints. */
|
||||
0x08, /* bInterfaceClass (Mass Stprage). */
|
||||
0x06, /* bInterfaceSubClass (SCSI
|
||||
transparent command set, MSCO
|
||||
chapter 2). */
|
||||
0x50, /* bInterfaceProtocol (Bulk-Only
|
||||
Mass Storage, MSCO chapter 3). */
|
||||
0x00, /* iInterface. */
|
||||
/* Endpoint Descriptor.*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
0x86, /* bEndpointAddress: (IN6) */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00, /* bInterval (ignored for bulk). */
|
||||
/* Endpoint Descriptor.*/
|
||||
7, /* bLength: Endpoint Descriptor size */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||
0x06, /* bEndpointAddress: (OUT6) */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00, /* bInterval (ignored for bulk). */
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -205,48 +254,36 @@ static const uint8_t gnukStringLangID[] = {
|
||||
0x09, 0x04 /* LangID = 0x0409: US-English */
|
||||
};
|
||||
|
||||
static const uint8_t gnukStringVendor[] = {
|
||||
33*2+2, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType*/
|
||||
/* Manufacturer: "Free Software Initiative of Japan" */
|
||||
'F', 0, 'r', 0, 'e', 0, 'e', 0, ' ', 0, 'S', 0, 'o', 0, 'f', 0,
|
||||
't', 0, 'w', 0, 'a', 0, 'r', 0, 'e', 0, ' ', 0, 'I', 0, 'n', 0,
|
||||
'i', 0, 't', 0, 'i', 0, 'a', 0, 't', 0, 'i', 0, 'v', 0, 'e', 0,
|
||||
' ', 0, 'o', 0, 'f', 0, ' ', 0, 'J', 0, 'a', 0, 'p', 0, 'a', 0,
|
||||
'n', 0
|
||||
};
|
||||
|
||||
static const uint8_t gnukStringProduct[] = {
|
||||
14*2+2, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
/* Product name: "FSIJ USB Token" */
|
||||
'F', 0, 'S', 0, 'I', 0, 'J', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0,
|
||||
' ', 0, 'T', 0, 'o', 0, 'k', 0, 'e', 0, 'n', 0
|
||||
};
|
||||
#define USB_STRINGS_FOR_GNUK 1
|
||||
#include "usb-strings.c.inc"
|
||||
|
||||
const uint8_t gnukStringSerial[] = {
|
||||
13*2+2, /* bLength */
|
||||
19*2+2, /* bLength */
|
||||
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
'0', 0, '.', 0, '1', 0, '4', 0, /* Version number of Gnuk */
|
||||
/* FSIJ-1.0 */
|
||||
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
|
||||
'1', 0, '.', 0, '0', 0, '.', 0, '1', 0, /* Version number of Gnuk */
|
||||
'-', 0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
|
||||
|
||||
const ONE_DESCRIPTOR Device_Descriptor = {
|
||||
(uint8_t*)gnukDeviceDescriptor,
|
||||
const struct Descriptor Device_Descriptor = {
|
||||
gnukDeviceDescriptor,
|
||||
sizeof (gnukDeviceDescriptor)
|
||||
};
|
||||
|
||||
const ONE_DESCRIPTOR Config_Descriptor = {
|
||||
(uint8_t*)gnukConfigDescriptor,
|
||||
const struct Descriptor Config_Descriptor = {
|
||||
gnukConfigDescriptor,
|
||||
sizeof (gnukConfigDescriptor)
|
||||
};
|
||||
|
||||
const ONE_DESCRIPTOR String_Descriptor[] = {
|
||||
{(uint8_t*)gnukStringLangID, sizeof (gnukStringLangID)},
|
||||
{(uint8_t*)gnukStringVendor, sizeof (gnukStringVendor)},
|
||||
{(uint8_t*)gnukStringProduct, sizeof (gnukStringProduct)},
|
||||
{(uint8_t*)gnukStringSerial, sizeof (gnukStringSerial)},
|
||||
const struct Descriptor String_Descriptors[NUM_STRING_DESC] = {
|
||||
{gnukStringLangID, sizeof (gnukStringLangID)},
|
||||
{gnukStringVendor, sizeof (gnukStringVendor)},
|
||||
{gnukStringProduct, sizeof (gnukStringProduct)},
|
||||
{gnukStringSerial, sizeof (gnukStringSerial)},
|
||||
{gnuk_revision_detail, sizeof (gnuk_revision_detail)},
|
||||
{gnuk_config_options, sizeof (gnuk_config_options)},
|
||||
{sys_version, sizeof (sys_version)},
|
||||
};
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Virtual COM port (for debug output only)
|
||||
*/
|
||||
|
||||
#include "usb_lib.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "ch.h"
|
||||
#include "gnuk.h"
|
||||
|
||||
void
|
||||
EP3_IN_Callback(void)
|
||||
{
|
||||
if (stdout_thread)
|
||||
chEvtSignalI (stdout_thread, EV_TX_READY);
|
||||
}
|
||||
|
||||
void
|
||||
EP5_OUT_Callback(void)
|
||||
{
|
||||
SetEPRxValid (ENDP3);
|
||||
}
|
||||
1221
src/usb_lld.c
1221
src/usb_lld.c
File diff suppressed because it is too large
Load Diff
158
src/usb_lld.h
158
src/usb_lld.h
@@ -1,2 +1,158 @@
|
||||
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
|
||||
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
|
||||
#define USB_STRING_DESCRIPTOR_TYPE 0x03
|
||||
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
|
||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
|
||||
|
||||
#define STANDARD_ENDPOINT_DESC_SIZE 0x09
|
||||
|
||||
/* endpoints enumeration */
|
||||
#define ENDP0 ((uint8_t)0)
|
||||
#define ENDP1 ((uint8_t)1)
|
||||
#define ENDP2 ((uint8_t)2)
|
||||
#define ENDP3 ((uint8_t)3)
|
||||
#define ENDP4 ((uint8_t)4)
|
||||
#define ENDP5 ((uint8_t)5)
|
||||
#define ENDP6 ((uint8_t)6)
|
||||
#define ENDP7 ((uint8_t)7)
|
||||
|
||||
/* EP_TYPE[1:0] EndPoint TYPE */
|
||||
#define EP_BULK (0x0000) /* EndPoint BULK */
|
||||
#define EP_CONTROL (0x0200) /* EndPoint CONTROL */
|
||||
#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */
|
||||
#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */
|
||||
|
||||
enum RECIPIENT_TYPE
|
||||
{
|
||||
DEVICE_RECIPIENT, /* Recipient device */
|
||||
INTERFACE_RECIPIENT, /* Recipient interface */
|
||||
ENDPOINT_RECIPIENT, /* Recipient endpoint */
|
||||
OTHER_RECIPIENT
|
||||
};
|
||||
|
||||
enum DESCRIPTOR_TYPE
|
||||
{
|
||||
DEVICE_DESCRIPTOR = 1,
|
||||
CONFIG_DESCRIPTOR,
|
||||
STRING_DESCRIPTOR,
|
||||
INTERFACE_DESCRIPTOR,
|
||||
ENDPOINT_DESCRIPTOR
|
||||
};
|
||||
|
||||
#define REQUEST_DIR 0x80 /* Mask to get request dir */
|
||||
#define REQUEST_TYPE 0x60 /* Mask to get request type */
|
||||
#define STANDARD_REQUEST 0x00 /* Standard request */
|
||||
#define CLASS_REQUEST 0x20 /* Class request */
|
||||
#define VENDOR_REQUEST 0x40 /* Vendor request */
|
||||
#define RECIPIENT 0x1F /* Mask to get recipient */
|
||||
|
||||
#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0)
|
||||
#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0)
|
||||
|
||||
struct Descriptor
|
||||
{
|
||||
const uint8_t *Descriptor;
|
||||
uint16_t Descriptor_Size;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
USB_UNSUPPORT = 0,
|
||||
USB_SUCCESS = 1,
|
||||
};
|
||||
|
||||
struct usb_device_method
|
||||
{
|
||||
void (*reset) (void);
|
||||
void (*ctrl_write_finish) (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len);
|
||||
int (*setup) (uint8_t req, uint8_t req_no,
|
||||
uint16_t value, uint16_t index, uint16_t len);
|
||||
int (*get_descriptor) (uint8_t desc_type, uint16_t index, uint16_t value);
|
||||
int (*event) (uint8_t event_type, uint16_t value);
|
||||
int (*interface) (uint8_t cmd, uint16_t interface, uint16_t value);
|
||||
};
|
||||
|
||||
enum {
|
||||
USB_EVENT_ADDRESS,
|
||||
USB_EVENT_CONFIG,
|
||||
USB_EVENT_SUSPEND,
|
||||
USB_EVENT_WAKEUP,
|
||||
USB_EVENT_STALL,
|
||||
};
|
||||
|
||||
enum {
|
||||
USB_SET_INTERFACE,
|
||||
USB_GET_INTERFACE,
|
||||
USB_QUERY_INTERFACE,
|
||||
};
|
||||
|
||||
extern void USB_Cable_Config (int NewState);
|
||||
|
||||
extern const struct usb_device_method Device_Method;
|
||||
|
||||
extern const struct Descriptor Device_Descriptor;
|
||||
extern const struct Descriptor Config_Descriptor;
|
||||
extern const struct Descriptor String_Descriptors[];
|
||||
|
||||
enum DEVICE_STATE
|
||||
{
|
||||
UNCONNECTED,
|
||||
ATTACHED,
|
||||
POWERED,
|
||||
SUSPENDED,
|
||||
ADDRESSED,
|
||||
CONFIGURED
|
||||
};
|
||||
|
||||
extern uint32_t bDeviceState;
|
||||
|
||||
#define STM32_USB_IRQ_PRIORITY 11
|
||||
void usb_lld_init (void);
|
||||
|
||||
extern void usb_lld_init (uint8_t feature);
|
||||
|
||||
extern void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
|
||||
|
||||
extern void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n);
|
||||
|
||||
extern void usb_lld_stall_tx (int ep_num);
|
||||
|
||||
extern void usb_lld_stall_rx (int ep_num);
|
||||
|
||||
extern int usb_lld_tx_data_len (int ep_num);
|
||||
|
||||
extern void usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len);
|
||||
|
||||
extern void usb_lld_tx_enable (int ep_num, size_t len);
|
||||
|
||||
extern void usb_lld_write (uint8_t ep_num, const void *buf, size_t len);
|
||||
|
||||
extern void usb_lld_rx_enable (int ep_num);
|
||||
|
||||
extern int usb_lld_rx_data_len (int ep_num);
|
||||
|
||||
extern void usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len);
|
||||
|
||||
extern void usb_lld_reset (void);
|
||||
|
||||
extern void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
|
||||
int ep_rx_addr, int ep_tx_addr,
|
||||
int ep_rx_memory_size);
|
||||
|
||||
extern void usb_lld_set_configuration (uint8_t config);
|
||||
|
||||
extern uint8_t usb_lld_current_configuration (void);
|
||||
|
||||
extern void usb_lld_set_feature (uint8_t feature);
|
||||
|
||||
extern void usb_lld_set_data_to_send (const void *p, size_t len);
|
||||
|
||||
extern inline void usb_lld_set_data_to_recv (void *p, size_t len)
|
||||
{
|
||||
usb_lld_set_data_to_send ((const void *)p, len);
|
||||
}
|
||||
|
||||
extern void usb_lld_prepare_shutdown (void);
|
||||
extern void usb_lld_shutdown (void);
|
||||
|
||||
extern void usb_interrupt_handler (void);
|
||||
|
||||
338
src/usb_prop.c
338
src/usb_prop.c
@@ -1,338 +0,0 @@
|
||||
/*
|
||||
* usb_prop.c - glue/interface code between Gnuk and USB-FS-Device_Lib
|
||||
*
|
||||
* Copyright (C) 2010, 2011 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Packet size of USB Bulk transfer for full speed */
|
||||
#define GNUK_MAX_PACKET_SIZE 64
|
||||
|
||||
#include "config.h"
|
||||
#include "usb_lib.h"
|
||||
#include "usb_conf.h"
|
||||
#include "usb_prop.h"
|
||||
#include "usb_desc.h"
|
||||
#include "usb_pwr.h"
|
||||
#include "hw_config.h"
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#include "usb-cdc-vport.c"
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
gnuk_device_init (void)
|
||||
{
|
||||
pInformation->Current_Configuration = 0;
|
||||
|
||||
/* Connect the device */
|
||||
PowerOn ();
|
||||
|
||||
/* Perform basic device initialization operations */
|
||||
USB_SIL_Init ();
|
||||
|
||||
bDeviceState = UNCONNECTED;
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_device_reset (void)
|
||||
{
|
||||
/* Set DEVICE as not configured */
|
||||
pInformation->Current_Configuration = 0;
|
||||
|
||||
/* Current Feature initialization */
|
||||
pInformation->Current_Feature = Config_Descriptor.Descriptor[7];
|
||||
|
||||
/* Set DEVICE with the default Interface*/
|
||||
pInformation->Current_Interface = 0;
|
||||
|
||||
SetBTABLE (BTABLE_ADDRESS);
|
||||
|
||||
/* Initialize Endpoint 0 */
|
||||
SetEPType (ENDP0, EP_CONTROL);
|
||||
SetEPTxStatus (ENDP0, EP_TX_STALL);
|
||||
SetEPRxAddr (ENDP0, ENDP0_RXADDR);
|
||||
SetEPTxAddr (ENDP0, ENDP0_TXADDR);
|
||||
Clear_Status_Out (ENDP0);
|
||||
SetEPRxCount (ENDP0, GNUK_MAX_PACKET_SIZE);
|
||||
SetEPRxValid (ENDP0);
|
||||
|
||||
/* Initialize Endpoint 1 */
|
||||
SetEPType (ENDP1, EP_BULK);
|
||||
SetEPTxAddr (ENDP1, ENDP1_TXADDR);
|
||||
SetEPTxStatus (ENDP1, EP_TX_NAK);
|
||||
SetEPRxStatus (ENDP1, EP_RX_DIS);
|
||||
|
||||
/* Initialize Endpoint 2 */
|
||||
SetEPType (ENDP2, EP_BULK);
|
||||
SetEPRxAddr (ENDP2, ENDP2_RXADDR);
|
||||
SetEPRxCount (ENDP2, GNUK_MAX_PACKET_SIZE);
|
||||
SetEPRxStatus (ENDP2, EP_RX_VALID);
|
||||
SetEPTxStatus (ENDP2, EP_TX_DIS);
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
/* Initialize Endpoint 3 */
|
||||
SetEPType (ENDP3, EP_BULK);
|
||||
SetEPTxAddr (ENDP3, ENDP3_TXADDR);
|
||||
SetEPTxStatus (ENDP3, EP_TX_NAK);
|
||||
SetEPRxStatus (ENDP3, EP_RX_DIS);
|
||||
|
||||
/* Initialize Endpoint 4 */
|
||||
SetEPType (ENDP4, EP_INTERRUPT);
|
||||
SetEPTxAddr (ENDP4, ENDP4_TXADDR);
|
||||
SetEPTxStatus (ENDP4, EP_TX_NAK);
|
||||
SetEPRxStatus (ENDP4, EP_RX_DIS);
|
||||
|
||||
/* Initialize Endpoint 5 */
|
||||
SetEPType (ENDP5, EP_BULK);
|
||||
SetEPRxAddr (ENDP5, ENDP5_RXADDR);
|
||||
SetEPRxCount (ENDP5, VIRTUAL_COM_PORT_DATA_SIZE);
|
||||
SetEPRxStatus (ENDP5, EP_RX_VALID);
|
||||
SetEPTxStatus (ENDP5, EP_TX_DIS);
|
||||
#endif
|
||||
|
||||
/* Set this device to response on default address */
|
||||
SetDeviceAddress (0);
|
||||
|
||||
bDeviceState = ATTACHED;
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_device_SetConfiguration (void)
|
||||
{
|
||||
DEVICE_INFO *pInfo = &Device_Info;
|
||||
|
||||
if (pInfo->Current_Configuration != 0)
|
||||
/* Device configured */
|
||||
bDeviceState = CONFIGURED;
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_device_SetInterface (void)
|
||||
{
|
||||
uint16_t intf = pInformation->USBwIndex0;
|
||||
|
||||
/* alternateSetting: pInformation->USBwValue0 should be 0 */
|
||||
|
||||
if (intf == 0)
|
||||
{
|
||||
ClearDTOG_RX (ENDP2);
|
||||
ClearDTOG_TX (ENDP1);
|
||||
}
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
else if (intf == 1)
|
||||
{
|
||||
ClearDTOG_TX (ENDP4);
|
||||
}
|
||||
else if (intf == 2)
|
||||
{
|
||||
ClearDTOG_RX (ENDP5);
|
||||
ClearDTOG_TX (ENDP3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
gnuk_device_SetDeviceAddress (void)
|
||||
{
|
||||
bDeviceState = ADDRESSED;
|
||||
}
|
||||
|
||||
/* IN from port 0 */
|
||||
static void
|
||||
gnuk_device_Status_In (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* OUT to port 0 */
|
||||
static void
|
||||
gnuk_device_Status_Out (void)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
gnuk_device_GetDeviceDescriptor (uint16_t Length)
|
||||
{
|
||||
return Standard_GetDescriptorData (Length,
|
||||
(PONE_DESCRIPTOR)&Device_Descriptor);
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
gnuk_device_GetConfigDescriptor (uint16_t Length)
|
||||
{
|
||||
return Standard_GetDescriptorData (Length,
|
||||
(PONE_DESCRIPTOR)&Config_Descriptor);
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
gnuk_device_GetStringDescriptor (uint16_t Length)
|
||||
{
|
||||
uint8_t wValue0 = pInformation->USBwValue0;
|
||||
|
||||
if (wValue0 >= (sizeof (String_Descriptor) / sizeof (ONE_DESCRIPTOR)))
|
||||
return NULL;
|
||||
else
|
||||
return
|
||||
Standard_GetDescriptorData (Length,
|
||||
(PONE_DESCRIPTOR)&String_Descriptor[wValue0]);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||
#define NUM_INTERFACES 3 /* two for CDC, one for CCID */
|
||||
#else
|
||||
#define NUM_INTERFACES 1 /* CCID only */
|
||||
#endif
|
||||
|
||||
static RESULT
|
||||
gnuk_device_Get_Interface_Setting (uint8_t Interface, uint8_t AlternateSetting)
|
||||
{
|
||||
if (AlternateSetting > 0) /* Any interface, we have no alternate */
|
||||
return USB_UNSUPPORT;
|
||||
else if (Interface > NUM_INTERFACES)
|
||||
return USB_UNSUPPORT;
|
||||
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
|
||||
#define USB_CCID_REQ_ABORT 0x01
|
||||
#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02
|
||||
#define USB_CCID_REQ_GET_DATA_RATES 0x03
|
||||
|
||||
static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
|
||||
static uint8_t *
|
||||
gnuk_clock_frequencies (uint16_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
pInformation->Ctrl_Info.Usb_wLength = sizeof (freq_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (uint8_t *)freq_table;
|
||||
}
|
||||
|
||||
static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
|
||||
static uint8_t *
|
||||
gnuk_data_rates (uint16_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
pInformation->Ctrl_Info.Usb_wLength = sizeof (data_rate_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (uint8_t *)data_rate_table;
|
||||
}
|
||||
|
||||
static RESULT
|
||||
gnuk_setup_with_data (uint8_t RequestNo)
|
||||
{
|
||||
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
||||
if (pInformation->USBwIndex0 == 0) /* Interface */
|
||||
{
|
||||
if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
|
||||
{
|
||||
pInformation->Ctrl_Info.CopyData = gnuk_clock_frequencies;
|
||||
pInformation->Ctrl_Info.Usb_wOffset = 0;
|
||||
gnuk_clock_frequencies (0);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES)
|
||||
{
|
||||
pInformation->Ctrl_Info.CopyData = gnuk_data_rates;
|
||||
pInformation->Ctrl_Info.Usb_wOffset = 0;
|
||||
gnuk_data_rates (0);
|
||||
return USB_SUCCESS;
|
||||
}
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_VIRTUAL_COM_PORT)
|
||||
return Virtual_Com_Port_Data_Setup (RequestNo);
|
||||
#else
|
||||
return USB_UNSUPPORT;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
static RESULT
|
||||
gnuk_setup_with_nodata (uint8_t RequestNo)
|
||||
{
|
||||
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
||||
if (pInformation->USBwIndex0 == 0) /* Interface */
|
||||
{
|
||||
if (RequestNo == USB_CCID_REQ_ABORT)
|
||||
/* wValue: bSeq, bSlot */
|
||||
/* Abortion is not supported in Gnuk */
|
||||
return USB_UNSUPPORT;
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_VIRTUAL_COM_PORT)
|
||||
return Virtual_Com_Port_NoData_Setup (RequestNo);
|
||||
#else
|
||||
return USB_UNSUPPORT;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return USB_UNSUPPORT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to USB core
|
||||
*/
|
||||
|
||||
const DEVICE_PROP Device_Property = {
|
||||
gnuk_device_init,
|
||||
gnuk_device_reset,
|
||||
gnuk_device_Status_In,
|
||||
gnuk_device_Status_Out,
|
||||
gnuk_setup_with_data,
|
||||
gnuk_setup_with_nodata,
|
||||
gnuk_device_Get_Interface_Setting,
|
||||
gnuk_device_GetDeviceDescriptor,
|
||||
gnuk_device_GetConfigDescriptor,
|
||||
gnuk_device_GetStringDescriptor,
|
||||
0,
|
||||
GNUK_MAX_PACKET_SIZE
|
||||
};
|
||||
|
||||
const DEVICE Device_Table = {
|
||||
EP_NUM,
|
||||
1
|
||||
};
|
||||
|
||||
const USER_STANDARD_REQUESTS User_Standard_Requests = {
|
||||
NOP_Process, /* GetConfiguration */
|
||||
gnuk_device_SetConfiguration,
|
||||
NOP_Process, /* GetInterface */
|
||||
gnuk_device_SetInterface,
|
||||
NOP_Process, /* GetStatus */
|
||||
NOP_Process, /* ClearFeature */
|
||||
NOP_Process, /* SetEndPointFeature */
|
||||
NOP_Process, /* SetDeviceFeature */
|
||||
gnuk_device_SetDeviceAddress
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef __usb_prop_H
|
||||
#define __usb_prop_H
|
||||
|
||||
extern const ONE_DESCRIPTOR Device_Descriptor;
|
||||
extern const ONE_DESCRIPTOR Config_Descriptor;
|
||||
extern const ONE_DESCRIPTOR String_Descriptor[4];
|
||||
#endif /* __usb_prop_H */
|
||||
@@ -1,5 +0,0 @@
|
||||
VCOMDIR = ../Virtual_COM_Port
|
||||
VCOMSRC= $(VCOMDIR)/usb_istr.c $(VCOMDIR)/usb_pwr.c
|
||||
ifneq ($(ENABLE_VCOMPORT),)
|
||||
VCOMSRC += usb_endp.c
|
||||
endif
|
||||
Reference in New Issue
Block a user