├── tools ├── gencert │ ├── info.sh │ ├── ca │ │ ├── cert.der │ │ ├── key.pem │ │ ├── ca_sign.sh │ │ └── genca.sh │ ├── Makefile │ ├── gencert.sh │ ├── cbytes.py │ ├── cdwef │ ├── hex2pubkey.c │ └── signcert.c ├── u2f_zero_client │ ├── requirements.txt │ ├── setup.sh │ ├── Pipfile │ └── Pipfile.lock ├── rkey ├── wkey ├── verify │ ├── bytes.py │ ├── Makefile │ └── ecdsa-verify.c ├── opensslerror │ ├── Makefile │ └── error.c ├── flashing │ └── program.sh ├── crc16 │ └── main.c ├── testing │ ├── u2f_test.py │ └── u2f_server.py ├── setup_device.sh └── monitor.sh ├── nku2f.jpg ├── firmware ├── SETUP.hex.gz ├── .settings │ └── com.silabs.ide.project.core.prefs ├── release │ ├── u2f-firmware.hex.gz │ └── update_version.sh ├── inc │ ├── config │ │ ├── efm8_config.h │ │ └── usbconfig.h │ ├── InitDevice.h │ ├── usb_serial.h │ ├── version.h.in │ ├── configuration.h │ ├── descriptors.h │ ├── sanity-check.h │ ├── custom.h │ ├── eeprom.h │ ├── gpio.h │ ├── i2c.h │ ├── bsp.h │ ├── u2f_hid.h │ ├── app.h │ ├── atecc508a.h │ └── u2f.h ├── lib │ ├── efm8_assert │ │ ├── assert.c │ │ └── assert.h │ ├── efm8_usb │ │ └── Readme.txt │ └── efm8ub1 │ │ └── peripheralDrivers │ │ └── src │ │ └── usb_0.c ├── .project ├── src │ ├── cert.c │ ├── configuration.c │ ├── eeprom.c │ ├── i2c.c │ ├── sanity-check.c │ ├── usb_serial.c │ ├── callback.c │ ├── bsp.c │ ├── Interrupts.c │ ├── descriptors.c │ ├── main.c │ ├── custom.c │ ├── SILABS_STARTUP.A51 │ ├── gpio.c │ └── u2f.c └── tests │ └── tests.h ├── doc ├── images │ ├── u2f-registration.dia │ ├── u2f-registration.png │ ├── u2f-authentication.dia │ ├── u2f-authentication.png │ ├── keys_usage-configuration.dia │ ├── keys_usage-configuration.png │ ├── keys_usage-u2f_registration.dia │ ├── keys_usage-u2f_registration.png │ ├── keys_usage-u2f_authentication.dia │ └── keys_usage-u2f_authentication.png ├── touch_button.md └── security_architecture.md ├── 70-u2f.rules ├── install_rules.sh ├── .travis.yml ├── .gitignore ├── LICENSE.txt └── README.md /tools/gencert/info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | openssl x509 -in $1 -inform der -text 4 | -------------------------------------------------------------------------------- /tools/u2f_zero_client/requirements.txt: -------------------------------------------------------------------------------- 1 | setuptools 2 | hidapi 3 | ecdsa 4 | pyyaml 5 | -------------------------------------------------------------------------------- /nku2f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/nku2f.jpg -------------------------------------------------------------------------------- /tools/rkey: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/tools/rkey -------------------------------------------------------------------------------- /tools/wkey: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/tools/wkey -------------------------------------------------------------------------------- /firmware/SETUP.hex.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/firmware/SETUP.hex.gz -------------------------------------------------------------------------------- /firmware/.settings/com.silabs.ide.project.core.prefs: -------------------------------------------------------------------------------- 1 | copiedFilesOriginState={} 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /tools/gencert/ca/cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/tools/gencert/ca/cert.der -------------------------------------------------------------------------------- /doc/images/u2f-registration.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/u2f-registration.dia -------------------------------------------------------------------------------- /doc/images/u2f-registration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/u2f-registration.png -------------------------------------------------------------------------------- /doc/images/u2f-authentication.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/u2f-authentication.dia -------------------------------------------------------------------------------- /doc/images/u2f-authentication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/u2f-authentication.png -------------------------------------------------------------------------------- /firmware/release/u2f-firmware.hex.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/firmware/release/u2f-firmware.hex.gz -------------------------------------------------------------------------------- /doc/images/keys_usage-configuration.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/keys_usage-configuration.dia -------------------------------------------------------------------------------- /doc/images/keys_usage-configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/keys_usage-configuration.png -------------------------------------------------------------------------------- /doc/images/keys_usage-u2f_registration.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/keys_usage-u2f_registration.dia -------------------------------------------------------------------------------- /doc/images/keys_usage-u2f_registration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/keys_usage-u2f_registration.png -------------------------------------------------------------------------------- /doc/images/keys_usage-u2f_authentication.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/keys_usage-u2f_authentication.dia -------------------------------------------------------------------------------- /doc/images/keys_usage-u2f_authentication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido-u2f-firmware/HEAD/doc/images/keys_usage-u2f_authentication.png -------------------------------------------------------------------------------- /70-u2f.rules: -------------------------------------------------------------------------------- 1 | ACTION!="add", GOTO="rules_end" 2 | 3 | SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess" 4 | 5 | LABEL="rules_end" 6 | -------------------------------------------------------------------------------- /tools/verify/bytes.py: -------------------------------------------------------------------------------- 1 | import fileinput 2 | import sys 3 | 4 | 5 | line = sys.stdin.read() 6 | 7 | sys.stdout.write(''.join([chr(int(''.join(c), 16)) for c in zip(line[0::2],line[1::2])])) 8 | -------------------------------------------------------------------------------- /tools/u2f_zero_client/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | virtualenv env2 -p `which python2` 4 | . ./env2/bin/activate 5 | pip install -r requirements.txt 6 | 7 | echo "Run . ./env2/bin/activate" 8 | 9 | -------------------------------------------------------------------------------- /tools/verify/Makefile: -------------------------------------------------------------------------------- 1 | src = $(wildcard *.c) 2 | obj = $(src:.c=.o) 3 | 4 | LDFLAGS = -lcrypto 5 | 6 | verify: $(obj) 7 | $(CC) -O3 -Wall -Werror -o $@ $^ $(LDFLAGS) 8 | 9 | clean: 10 | rm -f $(obj) verify 11 | -------------------------------------------------------------------------------- /tools/opensslerror/Makefile: -------------------------------------------------------------------------------- 1 | src = $(wildcard *.c) 2 | obj = $(src:.c=.o) 3 | 4 | LDFLAGS = -lcrypto 5 | 6 | error: $(obj) 7 | $(CC) -O3 -Wall -Werror -o $@ $^ $(LDFLAGS) 8 | 9 | clean: 10 | rm -f $(obj) error 11 | -------------------------------------------------------------------------------- /firmware/release/update_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | V=`git describe` 4 | PLACEHOLDER="GIT_VERSION_PLACEHOLDER-------" 5 | VPATH=../inc/version.h.in 6 | VOUT=../inc/version.h 7 | 8 | sed -e "s/$PLACEHOLDER/$V/g" < $VPATH | tee $VOUT | grep GIT_VERSION 9 | -------------------------------------------------------------------------------- /tools/u2f_zero_client/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | hidapi = "*" 10 | ecdsa = "*" 11 | PyYAML = "*" 12 | 13 | [requires] 14 | python_version = "2.7" 15 | -------------------------------------------------------------------------------- /tools/gencert/ca/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BggqhkjOPQMBBw== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MHcCAQEEID1T6nlzXl0SksfOwX2/qqWEe+kQkaSsI5XTV96P0I0DoAoGCCqGSM49 6 | AwEHoUQDQgAEM9kl9wqt+uvLdZpmlVBu7puypoIPA02tbq3HD4KF3waqRwokF+2m 7 | vHwE/Clp8z27wfdQH4NELAYieDzxRkxmlg== 8 | -----END EC PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /firmware/inc/config/efm8_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __SILICON_LABS_EFM8_CONFIG_H 2 | #define __SILICON_LABS_EFM8_CONFIG_H 3 | 4 | // $[USB driver options] 5 | #define EFM8PDL_USB0_USE 1 6 | #define EFM8PDL_USB0_IN_DATA_ENABLED 1 7 | #define EFM8PDL_USB0_OUT_DATA_ENABLED 1 8 | // [USB driver options]$ 9 | 10 | #endif // __SILICON_LABS_EFM8_CONFIG_H 11 | -------------------------------------------------------------------------------- /install_rules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 3 | echo "Install Nitrokey FIDO U2F Udev rules file on Ubuntu-like OS." 4 | echo 5 | echo "*** Copy rules file and restart udev service" 6 | set -x 7 | 8 | sudo cp ./70-u2f.rules /etc/udev/rules.d/ -v --backup 9 | sudo udevadm control --reload-rules && sudo udevadm trigger 10 | 11 | set +x 12 | echo "*** Finished" 13 | echo 14 | -------------------------------------------------------------------------------- /tools/gencert/ca/ca_sign.sh: -------------------------------------------------------------------------------- 1 | 2 | [[ "$#" != 4 ]] && echo "usage: $0 " && exit 1 3 | 4 | # generate a "signing request" 5 | openssl req -new -key "$1" -out "$1".csr 6 | 7 | # CA sign the request 8 | openssl x509 -days 18250 -req -in "$1".csr -CA "$2" -CAkey "$3" -out "$4" -set_serial 0 9 | 10 | 11 | openssl x509 -in "$4" -outform der -out "$4".der 12 | -------------------------------------------------------------------------------- /tools/gencert/Makefile: -------------------------------------------------------------------------------- 1 | 2 | LDFLAGS = -lssl -lcrypto 3 | 4 | all: signcert hex2pubkey 5 | 6 | signcert: signcert.o 7 | $(CC) -O3 -Wall -Werror -o $@ $^ $(LDFLAGS) 8 | 9 | hex2pubkey: hex2pubkey.o 10 | $(CC) -O3 -Wall -Werror -o $@ $^ $(LDFLAGS) 11 | 12 | signcert.o: signcert.c 13 | $(CC) -c $(CFLAGS) -o $@ $^ 14 | 15 | hex2pubkey.o: hex2pubkey.c 16 | $(CC) -c $(CFLAGS) -o $@ $^ 17 | 18 | clean: 19 | rm -f $(obj) signcert hex2pubkey 20 | -------------------------------------------------------------------------------- /tools/gencert/gencert.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | if [[ $# != "3" ]] 4 | then 5 | 6 | echo "usage: $0 " 7 | exit 1 8 | 9 | fi 10 | 11 | export PATH=$PATH:. 12 | 13 | key=$1 14 | pub=$2 15 | cert=$3 16 | 17 | hex2pubkey $pub pubkey.pem 18 | [[ "$?" -ne "0" ]] && exit 1 19 | signcert $key pubkey.pem $cert 20 | [[ "$?" -ne "0" ]] && exit 2 21 | cbytes.py $cert 22 | [[ "$?" -ne "0" ]] && exit 3 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /firmware/lib/efm8_assert/assert.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. 3 | * 4 | * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt 5 | *****************************************************************************/ 6 | 7 | #ifndef NDEBUG 8 | void slab_Assert() 9 | { 10 | while ( 1 ); 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: C 2 | sudo: false 3 | os: linux 4 | dist: trusty 5 | addons: 6 | apt: 7 | packages: 8 | - cppcheck 9 | 10 | 11 | install: 12 | - true 13 | 14 | script: 15 | - cppcheck -q --enable=all --error-exitcode=10 firmware/src 2> err.txt 16 | - cat err.txt 17 | - cppcheck -q --inconclusive --error-exitcode=0 --enable=all firmware/src 2> err-inconc.txt 18 | - sort err.txt err-inconc.txt | uniq -u 19 | -------------------------------------------------------------------------------- /tools/flashing/program.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | ret=$(curl --request POST http://127.0.0.1:4040/ --data "port=$2" --data "firmware=$(cat "$1")") 5 | 6 | if [[ $ret != *"Success"* ]] 7 | then 8 | exit 1 9 | fi 10 | 11 | exit 0 12 | #export FW=$2 13 | 14 | #PORT=$1 python - < 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | int main(int argc, char * argv[]) 15 | { 16 | if (argc != 5) 17 | { 18 | fprintf(stderr,"usage: %s \n",argv[0]); 19 | exit(1); 20 | } 21 | ERR_load_crypto_strings(); 22 | 23 | printf("all: %s\n", ERR_error_string(atoi(argv[4]),NULL)); 24 | printf("lib: %s\n", ERR_lib_error_string(atoi(argv[1]))); 25 | printf("func: %s\n", ERR_func_error_string(atoi(argv[2]))); 26 | printf("reason: %s\n", ERR_reason_error_string(atoi(argv[3]))); 27 | 28 | ERR_free_strings(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /doc/touch_button.md: -------------------------------------------------------------------------------- 1 | ## Touch button state machine diagram 2 | 3 | ![Touch button state machine][touch-button] 4 | 5 | ### States description 6 | Excerpt from `gpio.h`: 7 | ``` 8 | typedef enum { 9 | BST_INITIALIZING, // wait for the charge to settle down 10 | BST_INITIALIZING_READY_TO_CLEAR, // ready for clearing 11 | BST_READY_TO_USE, // META state (never used), to ease testing, 12 | // if button is ready (e.g. >READY) or not ( [-s]' % sys.argv[0]) 13 | print(' -s: just output c string (for general use)') 14 | sys.exit(1) 15 | 16 | buf = None 17 | try: 18 | buf = bytearray(open(sys.argv[1], 'rb').read()) 19 | except: 20 | n = sys.argv[1].replace('\n','') 21 | n = sys.argv[1].replace('\r','') 22 | buf = bytearray(binascii.unhexlify(n)) 23 | 24 | c_str = '' 25 | size = len(buf) 26 | 27 | a = ''.join(map(lambda c:'\\x%02x'%c, buf)) 28 | 29 | for i in range(0,len(a), 80): 30 | c_str += ("\""+a[i:i+80]+"\"\n") 31 | 32 | if '-s' in sys.argv: 33 | print(c_str) 34 | sys.exit(0) 35 | 36 | print('// generated') 37 | print('#include ') 38 | print() 39 | print('code uint8_t __attest[] = \n%s;' % c_str) 40 | print('const uint16_t __attest_size = sizeof(__attest)-1;') 41 | 42 | 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.a 13 | *.la 14 | *.lo 15 | 16 | # Shared objects (inc. Windows DLLs) 17 | *.dll 18 | *.so 19 | *.so.* 20 | *.dylib 21 | 22 | # Executables 23 | *.exe 24 | *.out 25 | *.app 26 | *.i*86 27 | *.x86_64 28 | u2f-firmware.hex 29 | pubkey.hex 30 | prog.hex 31 | 32 | # Debug files 33 | *.dSYM/ 34 | 35 | # kicad 36 | *.bak 37 | *-bak 38 | *_bak 39 | _saved* 40 | _autosave* 41 | gerbers/* 42 | 43 | # simplicity studio 44 | firmware/Keil* 45 | 46 | # vim 47 | *.swp 48 | 49 | # keys 50 | *.pem 51 | *.csr 52 | *.der 53 | 54 | # binaries 55 | hex2pubkey 56 | signcert 57 | 58 | #other 59 | pubkey.c.txt 60 | *.lst 61 | *.obj 62 | *.OBJ 63 | *.__i 64 | *.__ia 65 | release/ 66 | workers/ 67 | *~ 68 | *.DS_Store 69 | 70 | # hardware 71 | *.gbr 72 | gerbers/ 73 | 74 | # IDEs 75 | .idea 76 | .cproject* 77 | .vscode 78 | .settings 79 | 80 | # various WIP files 81 | *.log 82 | *.txt 83 | *.html 84 | *.patch 85 | tmp 86 | env* 87 | -------------------------------------------------------------------------------- /firmware/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | u2f-firmware 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | org.eclipse.cdt.core.cnature 23 | com.silabs.ss.framework.ide.project.sls.core.SLSProjectNature 24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 26 | 27 | 28 | 29 | lib/efm8ub3/peripheralDrivers/inc/usb_0.h 30 | 1 31 | STUDIO_SDK_LOC/Device/EFM8UB3/peripheral_driver/inc/usb_0.h 32 | 33 | 34 | lib/efm8ub3/peripheralDrivers/src/usb_0.c 35 | 1 36 | STUDIO_SDK_LOC/Device/EFM8UB3/peripheral_driver/src/usb_0.c 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /tools/gencert/cdwef: -------------------------------------------------------------------------------- 1 | "\x30\x82\x01\x59\x30\x82\x01\x00\x02\x01\x01\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d" 2 | "\x04\x03\x02\x30\x39\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x56\x41\x31\x14" 3 | "\x30\x12\x06\x03\x55\x04\x0a\x13\x0b\x43\x6f\x6e\x6f\x72\x43\x6f\x20\x4c\x4c\x43" 4 | "\x31\x14\x30\x12\x06\x03\x55\x04\x03\x13\x0b\x75\x32\x66\x7a\x65\x72\x6f\x2e\x63" 5 | "\x6f\x6d\x30\x1e\x17\x0d\x31\x36\x30\x33\x32\x38\x32\x33\x34\x35\x32\x34\x5a\x17" 6 | "\x0d\x32\x32\x30\x33\x32\x37\x32\x33\x34\x35\x32\x34\x5a\x30\x39\x31\x0b\x30\x09" 7 | "\x06\x03\x55\x04\x06\x13\x02\x56\x41\x31\x14\x30\x12\x06\x03\x55\x04\x0a\x13\x0b" 8 | "\x43\x6f\x6e\x6f\x72\x43\x6f\x20\x4c\x4c\x43\x31\x14\x30\x12\x06\x03\x55\x04\x03" 9 | "\x13\x0b\x75\x32\x66\x7a\x65\x72\x6f\x2e\x63\x6f\x6d\x30\x59\x30\x13\x06\x07\x2a" 10 | "\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04" 11 | "\xc9\x9d\xad\xb0\x96\x78\xb1\x0c\x10\x6c\xa5\xe9\x45\x49\x5d\x24\x12\x0e\x02\x03" 12 | "\x7d\x5a\x02\x41\x95\x91\x5e\xaa\xbd\xa0\x3f\x9d\xf7\x79\x12\x8d\xe6\x54\xe1\xb9" 13 | "\xca\x05\x0f\x4c\xf2\x65\x85\xf6\x63\xf7\xd2\xf7\x16\x7e\xc4\x69\xb8\x6e\xb2\xd8" 14 | "\xdc\x24\x14\x79\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x47\x00\x30" 15 | "\x44\x02\x20\x49\xb9\x43\x37\x9a\x28\xb3\x92\x6d\x31\x2b\xfb\x59\x50\x74\xa5\xe0" 16 | "\x24\x06\x3d\xa3\x24\xc4\x6b\x4b\x63\xf8\x7b\xf3\x0e\x30\x02\x02\x20\x78\x66\x1c" 17 | "\xca\x95\x73\xa1\x74\x82\xce\xc6\x94\xe2\x14\xc9\x26\x92\x70\x22\x79\xf7\xd8\xbb" 18 | "\x22\x74\x69\xe9\xf8\xa3\x1e\x5c\x23" 19 | -------------------------------------------------------------------------------- /firmware/inc/InitDevice.h: -------------------------------------------------------------------------------- 1 | //========================================================= 2 | // inc/InitDevice.h: generated by Hardware Configurator 3 | // 4 | // This file will be regenerated when saving a document. 5 | // leave the sections inside the "$[...]" comment tags alone 6 | // or they will be overwritten! 7 | //========================================================= 8 | #ifndef __INIT_DEVICE_H__ 9 | #define __INIT_DEVICE_H__ 10 | 11 | // USER CONSTANTS 12 | // USER PROTOTYPES 13 | 14 | // $[Mode Transition Prototypes] 15 | extern void enter_DefaultMode_from_RESET(void); 16 | // [Mode Transition Prototypes]$ 17 | 18 | // $[Config(Per-Module Mode)Transition Prototypes] 19 | extern void WDT_0_enter_DefaultMode_from_RESET(void); 20 | extern void VREG_0_enter_DefaultMode_from_RESET(void); 21 | extern void PORTS_0_enter_DefaultMode_from_RESET(void); 22 | extern void PORTS_1_enter_DefaultMode_from_RESET(void); 23 | extern void PBCFG_0_enter_DefaultMode_from_RESET(void); 24 | extern void CIP51_0_enter_DefaultMode_from_RESET(void); 25 | extern void CLOCK_0_enter_DefaultMode_from_RESET(void); 26 | extern void TIMER01_0_enter_DefaultMode_from_RESET(void); 27 | extern void TIMER16_2_enter_DefaultMode_from_RESET(void); 28 | extern void TIMER16_3_enter_DefaultMode_from_RESET(void); 29 | extern void TIMER_SETUP_0_enter_DefaultMode_from_RESET(void); 30 | extern void SMBUS_0_enter_DefaultMode_from_RESET(void); 31 | extern void INTERRUPT_0_enter_DefaultMode_from_RESET(void); 32 | extern void USBLIB_0_enter_DefaultMode_from_RESET(void); 33 | // [Config(Per-Module Mode)Transition Prototypes]$ 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Conor Patrick 2 | Copyright (c) 2018, Nitrokey UG 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | The views and conclusions contained in the software and documentation are those 26 | of the authors and should not be interpreted as representing official policies, 27 | either expressed or implied, of the FreeBSD Project. 28 | -------------------------------------------------------------------------------- /firmware/inc/usb_serial.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Nitrokey UG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | */ 26 | 27 | #ifndef INC_USB_SERIAL_H_ 28 | #define INC_USB_SERIAL_H_ 29 | 30 | void get_serial_num(); 31 | void update_USB_serial(); 32 | 33 | 34 | #endif /* INC_USB_SERIAL_H_ */ 35 | -------------------------------------------------------------------------------- /tools/crc16/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | uint16_t feed_crc(uint16_t crc, uint8_t b) 6 | { 7 | crc ^= b; 8 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 9 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 10 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 11 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 12 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 13 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 14 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 15 | return crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 16 | } 17 | 18 | uint16_t reverse_bits(uint16_t crc) 19 | { 20 | // efficient bit reversal for 16 bit int 21 | crc = (((crc & 0xaaaa) >> 1) | ((crc & 0x5555) << 1)); 22 | crc = (((crc & 0xcccc) >> 2) | ((crc & 0x3333) << 2)); 23 | crc = (((crc & 0xf0f0) >> 4) | ((crc & 0x0f0f) << 4)); 24 | return (((crc & 0xff00) >> 8) | ((crc & 0x00ff) << 8)); 25 | } 26 | 27 | uint8_t d[] = 28 | "\x01\x23\x6d\x10\x00\x00\x50\x00\xd7\x2c\xa5\x71\xee\xc0\x85\x00\xc0\x00\x55\x00\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x83\xa0\x00\x00\x00\x1f\x00\x60\x00\x60\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x55\x55\xff\xff\x00\x00\x00\x00\x00\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x13\x00\x33\x00"; 29 | 30 | int main() 31 | { 32 | uint16_t crc = 0; 33 | int i; 34 | for (i=0; i< sizeof(d)-1; i++) 35 | { 36 | crc = feed_crc(crc,d[i]); 37 | } 38 | printf("crc: %hx\n",reverse_bits(crc)); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /firmware/inc/version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Nitrokey UG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | */ 26 | 27 | #ifndef INC_VERSION_H_ 28 | #define INC_VERSION_H_ 29 | #include 30 | 31 | #define GIT_VERSION_PLACEHOLDER "GIT_VERSION_PLACEHOLDER-------" 32 | 33 | extern uint8_t GIT_DESCRIPTION[]; 34 | extern uint8_t GIT_DESCRIPTION_SIZE; 35 | 36 | #endif /* INC_VERSION_H_ */ 37 | -------------------------------------------------------------------------------- /firmware/src/cert.c: -------------------------------------------------------------------------------- 1 | // generated 2 | #include 3 | 4 | code uint8_t __attest[] = 5 | "\x30\x82\x01\x7c\x30\x82\x01\x22\xa0\x03\x02\x01\x02\x02\x09\x00\xda\x88\x21\xd2" 6 | "\xc5\xcb\x24\xf1\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x1d\x31\x1b" 7 | "\x30\x19\x06\x03\x55\x04\x03\x0c\x12\x4e\x69\x74\x72\x6f\x6b\x65\x79\x20\x52\x6f" 8 | "\x6f\x74\x20\x43\x41\x20\x32\x30\x1e\x17\x0d\x31\x38\x31\x30\x33\x30\x30\x31\x34" 9 | "\x35\x35\x39\x5a\x17\x0d\x33\x38\x31\x30\x32\x35\x30\x31\x34\x35\x35\x39\x5a\x30" 10 | "\x26\x31\x24\x30\x22\x06\x03\x55\x04\x03\x0c\x1b\x4e\x69\x74\x72\x6f\x6b\x65\x79" 11 | "\x20\x46\x49\x44\x4f\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x20\x32\x30" 12 | "\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03" 13 | "\x01\x07\x03\x42\x00\x04\x40\x2a\x6d\xfb\x22\x49\xa8\x03\xe9\xfc\xd8\xf0\x75\x37" 14 | "\xa4\x37\x43\xdf\x68\xdf\x73\x81\x20\xc9\xb0\xb6\x2b\x2a\x1b\x1d\x9c\xbb\x53\x72" 15 | "\x32\x44\xcf\xc7\xe2\x1e\x83\x95\x8f\xfc\x10\x81\x39\x84\x86\x56\x46\x0d\x45\xce" 16 | "\x8a\xcb\xfa\xc8\xeb\xfe\x88\x89\x40\x00\xa3\x42\x30\x40\x30\x1d\x06\x03\x55\x1d" 17 | "\x0e\x04\x16\x04\x14\xef\x17\x6e\x2e\xe4\xa5\x35\xfa\xc6\x43\xbc\x38\xf6\xf6\xbe" 18 | "\xd0\x03\x4d\xa3\x5f\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x9b\xc0" 19 | "\x52\xe8\xc1\x65\x60\x42\x61\xe4\x5c\x9c\x26\xcf\x6b\xe8\xfd\xc6\x6f\x91\x30\x0a" 20 | "\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00\x30\x45\x02\x21\x00\xd8\x26" 21 | "\xa3\x55\x60\xca\x4f\x5e\xbd\x4b\x4f\x2f\x11\xaf\x9d\x67\xf3\x60\x83\xef\x16\x6e" 22 | "\x7b\xdc\x89\x13\xd0\x02\x2f\xb9\xa2\xed\x02\x20\x2d\xcd\xa3\x10\xd8\xa2\xf5\x6f" 23 | "\x60\xcd\xb8\xa9\xf0\xc2\x5a\x06\x4d\xec\xfc\x03\x1e\x41\x12\x17\x55\xa5\x70\xf1" 24 | "\x83\x63\xe8\x1f" 25 | ; 26 | const uint16_t __attest_size = sizeof(__attest)-1; 27 | -------------------------------------------------------------------------------- /firmware/src/configuration.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Nitrokey UG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | */ 26 | 27 | #include "configuration.h" 28 | #include "eeprom.h" 29 | 30 | Configuration configuration; 31 | 32 | void configuration_write(){ 33 | eeprom_erase(EEPROM_DATA_CONFIG); 34 | eeprom_write(EEPROM_DATA_CONFIG, (uint8_t*)&configuration, sizeof(configuration)); 35 | } 36 | 37 | Configuration * configuration_read(){ 38 | eeprom_read(EEPROM_DATA_CONFIG, (uint8_t*)&configuration, sizeof(configuration)); 39 | return &configuration; 40 | } 41 | -------------------------------------------------------------------------------- /firmware/inc/configuration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Nitrokey UG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | */ 26 | 27 | #ifndef INC_CONFIGURATION_H_ 28 | #define INC_CONFIGURATION_H_ 29 | 30 | #include 31 | 32 | typedef struct { 33 | uint8_t show_serial_on_USB; 34 | } 35 | Configuration; 36 | 37 | extern Configuration configuration; 38 | 39 | void configuration_write(); 40 | Configuration * configuration_read(); 41 | 42 | typedef enum { 43 | CONFIG_FALSE = 0x00, 44 | CONFIG_TRUE = 0x01, 45 | CONFIG_NOT_SET = 0xFF 46 | } ConfigValue; 47 | 48 | #endif /* INC_CONFIGURATION_H_ */ 49 | -------------------------------------------------------------------------------- /firmware/inc/descriptors.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * @file descriptors.h 3 | * @brief USB descriptors header file. 4 | *******************************************************************************/ 5 | 6 | //============================================================================= 7 | // inc/descriptors.h: generated by Hardware Configurator 8 | // 9 | // This file will be regenerated when saving a document. leave the sections 10 | // inside the "$[...]" comment tags alone or they will be overwritten! 11 | //============================================================================= 12 | #ifndef __SILICON_LABS_DESCRIPTORS_H 13 | #define __SILICON_LABS_DESCRIPTORS_H 14 | 15 | //----------------------------------------------------------------------------- 16 | // Includes 17 | //----------------------------------------------------------------------------- 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | extern uint8_t dynamic_serial[2*17]; 29 | 30 | // $[Vendor ID] 31 | #define USB_VENDOR_ID htole16(0x20a0) 32 | // [Vendor ID]$ 33 | 34 | // $[Product ID] 35 | #define USB_PRODUCT_ID htole16(0x4287) 36 | // [Product ID]$ 37 | 38 | #define HID_PACKET_SIZE 64 39 | 40 | extern SI_SEGMENT_VARIABLE(ReportDescriptor0[34], const uint8_t, SI_SEG_CODE); 41 | 42 | #if 0 43 | // $[HID Report Descriptors] 44 | extern SI_SEGMENT_VARIABLE(ReportDescriptor0[0], const uint8_t, SI_SEG_CODE); 45 | // [HID Report Descriptors]$ 46 | #endif 47 | 48 | extern SI_SEGMENT_VARIABLE(deviceDesc[], const USB_DeviceDescriptor_TypeDef, SI_SEG_CODE); 49 | extern SI_SEGMENT_VARIABLE(configDesc[], const uint8_t, SI_SEG_CODE); 50 | extern SI_SEGMENT_VARIABLE(initstruct, const USBD_Init_TypeDef, SI_SEG_XDATA); 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Nitrokey FIDO U2F 3 | 4 | ![Nitrokey Fido U2F Rev.5](nku2f.jpg) 5 | 6 | Nitrokey FIDO U2F is based on [U2F Zero](https://github.com/conorpp/u2f-zero/), an open source, open hardware U2F token for 2 factor authentication. It is implemented securely and works with Google accounts, Github, Duo, and anything else supporting U2F. Uses key derivation and has no limit on registrations. 7 | 8 | Hardware files are provided [here](https://github.com/Nitrokey/nitrokey-fido-u2f-hardware). Nitrokey's device differs in using a touch button instead of a regular one, as well as using smaller PCB and bigger flash MCU. 9 | 10 | ## Documentation 11 | U2F key derivation algorithm, and other working details, are documented in files placed in the [doc](doc) folder. 12 | 13 | ## Build (Ubuntu 18.04) 14 | 15 | ### UB10 16 | Instructions for H/W Rev4 and lower, based on UB10 MCU. 17 | 18 | 1. Download Simplicity Studio 3 [link](https://www.silabs.com/products/development-tools/software/simplicity-studio-version3) (v4 will make bigger binary, which will not fit). 19 | 2. Unpack it and run `./setup.sh` script. 20 | 3. Rename internal wine installation: `cd SimplicityStudio_v3/developer/utilities/third-party && mv wine{,_}`. 21 | 3. Install `wine-stable` package: `sudo apt install wine-stable`. 22 | 4. Run Studio. 23 | 5. Select and download proper dev kit (will be autodetected if debugger and device are connected). 24 | 6. Register KEIL compiler. 25 | 7. Build the source. 26 | 27 | ### UB30 28 | Pending. Simplicity Studio 4 will be used. 29 | 30 | ## Usage (Ubuntu 18.04) 31 | Udev rules might be required to use the device without administrator privileges. Please run `./install_rules.sh` script, which will copy rules file (./70-u2f.rules) to system directory on Ubuntu. For other OSes - please check the proper path and issue the copying manually. 32 | 33 | Client and setup scripts are in `./tools/` directory. 34 | 35 | 36 | ## License 37 | 38 | License is the same as the base project: [Simplified BSD License](LICENSE.txt). 39 | -------------------------------------------------------------------------------- /firmware/inc/sanity-check.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Nitrokey UG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | */ 26 | 27 | 28 | 29 | #ifndef INC_SANITY_CHECK_H_ 30 | #define INC_SANITY_CHECK_H_ 31 | 32 | typedef struct { 33 | uint8_t constants_filled : 1; 34 | // compilation switches 35 | uint8_t eeprom_protection : 1; 36 | uint8_t fake_touch : 1; 37 | uint8_t disable_watchdog : 1; 38 | uint8_t setup_firmware : 1; 39 | } check_info; 40 | 41 | check_info sanity_check_builder(); 42 | bool sanity_check(check_info *out_c); 43 | 44 | extern bool sanity_check_passed; 45 | extern check_info sanity_check_info; 46 | 47 | #endif /* INC_SANITY_CHECK_H_ */ 48 | -------------------------------------------------------------------------------- /firmware/tests/tests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | 30 | #ifndef TESTS_H_ 31 | #define TESTS_H_ 32 | 33 | //#define ENABLE_TESTS 34 | 35 | //#define TEST_SHA 36 | //#define TEST_ATECC_EEPROM 37 | //#define TEST_EFM8UB1_EEPROM 38 | //#define TEST_KEY_SIGNING // requires key and locked eeprom 39 | 40 | #ifdef ENABLE_TESTS 41 | 42 | void run_tests(); 43 | 44 | #else 45 | 46 | #define run_tests(x) 47 | 48 | #endif 49 | 50 | #endif /* TESTS_H_ */ 51 | -------------------------------------------------------------------------------- /firmware/inc/custom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | 28 | #ifndef CUSTOM_H_ 29 | #define CUSTOM_H_ 30 | 31 | #include "app.h" 32 | #include "u2f_hid.h" 33 | 34 | #define U2F_CUSTOM_GET_RNG (U2FHID_VENDOR_FIRST+0) 35 | #define U2F_CUSTOM_SEED_RNG (U2FHID_VENDOR_FIRST+1) 36 | #define U2F_CUSTOM_WINK (U2FHID_VENDOR_FIRST+2) 37 | #define U2F_CUSTOM_FACTORY_RESET (U2FHID_VENDOR_FIRST+3) 38 | #define U2F_CUSTOM_UPDATE_CONFIG (U2FHID_VENDOR_FIRST+4) 39 | #define U2F_CUSTOM_STATUS (U2FHID_VENDOR_FIRST+5) 40 | #define U2F_SANITY_CHECK (U2FHID_VENDOR_FIRST+6) 41 | 42 | 43 | 44 | uint8_t custom_command(struct u2f_hid_msg * msg); 45 | 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /firmware/lib/efm8_usb/Readme.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | Readme.txt 3 | ------------------------------------------------------------------------------- 4 | 5 | Copyright 2014 Silicon Laboratories, Inc. 6 | http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt 7 | 8 | Program Description: 9 | ------------------- 10 | 11 | This is the generic EFM8 USB Firmware Library. Please see the EFM8 Libraries 12 | Documentation for more information (/doc/EFM8/software/Lib/index.html). 13 | 14 | Known Issues and Limitations: 15 | ---------------------------- 16 | 17 | 1) The library does not reset its Data Toggle after receiving a SET_INTERFACE 18 | request. 19 | 20 | Target and Tool Chain Information: 21 | --------------------------------- 22 | 23 | Target: EFM8UB1, EFM8UB2, C8051F320/1, C8051F326/7, C8051F34x, C8051F38x 24 | Tool chain: Keil 25 | 26 | File List: 27 | --------- 28 | 29 | /inc/efm8_usb.h 30 | /src/efm8_usbd.c 31 | /src/efm8_usbdch9.c 32 | /src/efm8_usbdep.c 33 | /src/efm8_usbdint.c 34 | 35 | Release Information: 36 | ------------------- 37 | 38 | Version 1.0.0 39 | - Initial release. 40 | 41 | Version 1.0.1 42 | - Fixed bug in logic of remote wakeup feature where the device would 43 | attempt to wake the host before enabling its USB transceiver. 44 | - Fixed bug where the device would stall the Data Phase instead of the 45 | Setup Phase when sending a procedural stall on Endpoint 0. 46 | - Fixed bug where a bus-powered device would look at VBUS after a USB Reset 47 | to determine if it should enter the Default or Attached State. VBUS is 48 | always present on a bus-powered device, so it should automatically enter 49 | the Default State. 50 | - Removed code that generated a compiler warning when 51 | USB_PWRSAVE_MODE_FASTWAKE was enabled. 52 | - Improved documentation of USB_PWRSAVE_MODE_FASTWAKE feature. 53 | 54 | ------------------------------------------------------------------------------- 55 | End Of File 56 | ------------------------------------------------------------------------------- 57 | -------------------------------------------------------------------------------- /tools/gencert/hex2pubkey.c: -------------------------------------------------------------------------------- 1 | // 2 | // hex2pubkey 3 | // 4 | // converts a hex string of (x,y) coordinates 5 | // for a prime256v1 ECC public key to a PEM file 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | 22 | EC_KEY * hex2pubkey(char * pubxy) 23 | { 24 | EC_KEY * key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); 25 | 26 | BIGNUM * bnx = NULL, * bny = NULL; 27 | 28 | char x[65], y[65]; 29 | 30 | if (key == NULL) 31 | { return NULL; } 32 | 33 | memmove(x, pubxy, 64); 34 | memmove(y, pubxy+64, 64); 35 | 36 | x[64] = y[64] = 0; 37 | 38 | if (!BN_hex2bn(&bnx, x)) 39 | { return NULL; } 40 | if (!BN_hex2bn(&bny, y)) 41 | { return NULL; } 42 | 43 | if (!EC_KEY_set_public_key_affine_coordinates(key,bnx,bny)) 44 | { return NULL; } 45 | 46 | EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE); 47 | 48 | BN_free(bnx); 49 | BN_free(bny); 50 | 51 | return key; 52 | } 53 | 54 | 55 | int main(int argc, char * argv[]) 56 | { 57 | EC_KEY * key; 58 | char * pubkey, * out; 59 | 60 | if (argc != 3) 61 | { 62 | fprintf(stderr, "usage: %s \n" 63 | ,argv[0]); 64 | return 1; 65 | } 66 | 67 | pubkey = argv[1]; 68 | out = argv[2]; 69 | 70 | FILE * fp = fopen(out,"w+"); 71 | if (fp == NULL) 72 | { 73 | perror("fopen"); 74 | return 1; 75 | } 76 | 77 | ERR_load_crypto_strings(); 78 | 79 | key = hex2pubkey(pubkey); 80 | 81 | if (key == NULL) 82 | { 83 | fprintf(stderr,"signature error: %s\n", ERR_error_string(ERR_get_error(),NULL) ); 84 | return 1; 85 | } 86 | 87 | EVP_PKEY * pkey = EVP_PKEY_new(); 88 | EVP_PKEY_assign_EC_KEY(pkey, key); 89 | 90 | PEM_write_PUBKEY(fp, pkey); 91 | 92 | ERR_free_strings(); 93 | EVP_PKEY_free(pkey); 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /tools/testing/u2f_test.py: -------------------------------------------------------------------------------- 1 | from u2flib_host import u2f, exc 2 | import sys 3 | import requests 4 | import json 5 | 6 | facet = 'http://localhost:8081' 7 | if 1: 8 | try: 9 | registrationRequest = json.loads(requests.get("http://localhost:8081/enroll").text) 10 | 11 | print registrationRequest 12 | 13 | registrationRequest = registrationRequest['registerRequests'][0] 14 | 15 | 16 | # Enumerate available devices 17 | devices = u2f.list_devices() 18 | 19 | for device in devices: 20 | # The with block ensures that the device is opened and closed. 21 | with device as dev: 22 | # Register the device with some service 23 | print 'Reg: press button . . .' 24 | sys.stdout.flush() 25 | registrationResponse = u2f.register(device, registrationRequest, facet) 26 | print registrationResponse 27 | registrationResponse['version'] = 'U2F_V2' 28 | bindres = (requests.post("http://localhost:8081/bind", data={'data':json.dumps(registrationResponse)}).text) 29 | 30 | if bindres == 'true': 31 | print 'Success reg' 32 | else: 33 | print 'Fail reg' 34 | sys.stdout.flush() 35 | 36 | sign = json.loads(requests.get("http://localhost:8081/sign").text) 37 | key = sign['registeredKeys'][0] 38 | for i in key: 39 | sign[i] = key[i] 40 | print 'Auth: press button . . . ' 41 | sys.stdout.flush() 42 | auth = u2f.authenticate(device, sign, facet) 43 | auth['signatureData'] = auth['signatureData'].replace('1','2') 44 | print auth 45 | authres = (requests.post("http://localhost:8081/verify", data={'data':json.dumps(auth)}).text) 46 | try: 47 | authres = json.loads(authres) 48 | assert(authres['counter'] > 0) 49 | print 'Success auth' 50 | except: 51 | print 'Fail auth' 52 | 53 | except: 54 | print 'skip' 55 | 56 | -------------------------------------------------------------------------------- /firmware/lib/efm8_assert/assert.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2014 by Silicon Laboratories Inc. All rights reserved. 3 | * 4 | * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt 5 | *****************************************************************************/ 6 | 7 | #ifndef __ASSERT_H__ 8 | 9 | #include "efm8_config.h" 10 | 11 | /**************************************************************************//** 12 | * @addtogroup efm8_assert 13 | * @{ 14 | * 15 | * @brief Runtime assert for EFM8 16 | * 17 | * This module contains a runtime assert macro. It can be compiled out by setting 18 | * the NDEBUG flag. 19 | * 20 | *****************************************************************************/ 21 | 22 | 23 | /**************************************************************************//** 24 | * @def NDEBUG 25 | * @brief Controls if the asserts are present. 26 | * 27 | * Asserts are removed if this symbol is defined 28 | * 29 | *****************************************************************************/ 30 | 31 | /**************************************************************************//** 32 | * @def USER_ASSERT 33 | * @brief User implemented assert function. 34 | * 35 | * When asserts are enabled the default handler can be be replaced with a user defined 36 | * function of the form 'void userAssertName( const char * file, int line )' by setting 37 | * the value of USER_ASSERT to the userAssertName. 38 | * 39 | *****************************************************************************/ 40 | 41 | /**************************************************************************//** 42 | * @def SLAB_ASSERT(expr) 43 | * @brief default implementation of assert_failed. 44 | * 45 | * This function can be replaced by a user defined assert function by setting the USER_ASSERT flag 46 | *****************************************************************************/ 47 | 48 | #ifdef NDEBUG 49 | #define SLAB_ASSERT(expr) 50 | #else 51 | #ifdef USER_ASSERT 52 | #define SLAB_ASSERT(expr) ((expr) ? ((void)0) : USER_ASSERT( __FILE__, __LINE__ )) 53 | #else 54 | void slab_Assert(); 55 | //Yes this is smaller than if(!expr){assert} 56 | #define SLAB_ASSERT(expr) if(expr){}else{slab_Assert();} 57 | #endif 58 | #endif 59 | 60 | #endif //!__ASSERT_H__ 61 | -------------------------------------------------------------------------------- /firmware/inc/eeprom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | 28 | #ifndef EEPROM_H_ 29 | #define EEPROM_H_ 30 | 31 | #include "app.h" 32 | 33 | void eeprom_init(); 34 | 35 | void eeprom_read(uint16_t addr, uint8_t * buf, uint8_t len); 36 | void eeprom_xor(uint16_t addr, uint8_t * out_buf, uint8_t len); 37 | 38 | void _eeprom_write(uint16_t addr, uint8_t * buf, uint8_t len, uint8_t flags); 39 | 40 | 41 | #define eeprom_write(a,b,l) _eeprom_write((a),(b),(l),0x1) 42 | #define eeprom_erase(a) _eeprom_write((a),appdata.tmp,1,0x3) 43 | 44 | #define EEPROM_PAGE_START(p) (0x200*(p)) 45 | #define EEPROM_KB_START(p) (EEPROM_PAGE_START(2*(p))) 46 | #define EEPROM_PAGE_COUNT (79) 47 | #define EEPROM_LAST_PAGE_NUM (EEPROM_PAGE_COUNT-1) 48 | // 0x8000 -> 20kB -> EEPROM page 40 49 | #define EEPROM_DATA_START (EEPROM_PAGE_START(40)) 50 | // pages are 512-bytes each, required to be cleared separately 51 | // FIXME allocate all constants on one page (36 + 36 + 16), when required 52 | #define EEPROM_DATA_RMASK EEPROM_PAGE_START(40) 53 | #define EEPROM_DATA_WMASK EEPROM_PAGE_START(41) 54 | #define EEPROM_DATA_U2F_CONST EEPROM_PAGE_START(42) 55 | #define EEPROM_DATA_SERIAL EEPROM_PAGE_START(43) 56 | #define EEPROM_DATA_CONFIG EEPROM_PAGE_START(44) 57 | 58 | #define U2F_CONST_LENGTH (32) 59 | #define EEPROM_DATA_RWMASK_LENGTH (36) 60 | 61 | #endif /* EEPROM_H_ */ 62 | -------------------------------------------------------------------------------- /firmware/inc/gpio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | 28 | #ifndef GPIO_H_ 29 | #define GPIO_H_ 30 | 31 | #define U2F_MS_CLEAR_BUTTON_PERIOD (20*1000) 32 | #define U2F_MS_INIT_BUTTON_PERIOD (2*1000) 33 | 34 | void button_manager (void); 35 | uint8_t button_get_press (void); 36 | uint8_t button_get_press_extended (void); 37 | 38 | uint8_t button_press_in_progress(void); 39 | void button_press_set_consumed(void); 40 | uint8_t button_press_is_consumed(void); 41 | void _clear_button_press(bool forced); 42 | void clear_button_press(); 43 | 44 | // debug / status functions 45 | uint8_t last_button_cleared_time_delta(); 46 | uint8_t last_button_pushed_time_delta(); 47 | 48 | void led_on (void); 49 | void led_off (void); 50 | bool led_is_blinking(void); 51 | void led_blink (uint8_t blink_num, uint16_t period_t); 52 | void led_blink_manager (void); 53 | void led_change_ON_time(uint16_t ON_time); 54 | 55 | typedef enum { 56 | BST_INITIALIZING, // wait for the charge to settle down 57 | BST_INITIALIZING_READY_TO_CLEAR, // ready for clearing 58 | BST_META_READY_TO_USE, // META state (never used), to ease testing, 59 | // if button is ready (e.g. >READY) or not ( 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | int verify(char * digest, char * pubxy, char * rs ) 16 | { 17 | EC_KEY * key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); 18 | 19 | BIGNUM * bnx = NULL, * bny = NULL, * bnsig = NULL; 20 | 21 | char r[65], s[65], x[65], y[65]; 22 | 23 | if (key == NULL) 24 | { return -1; } 25 | 26 | memmove(x, pubxy, 64); 27 | memmove(y, pubxy+64, 64); 28 | 29 | r[64] = s[64] = x[64] = y[64] = 0; 30 | if (!BN_hex2bn(&bnx, x)) 31 | { return -1; } 32 | if (!BN_hex2bn(&bny, y)) 33 | { return -1; } 34 | 35 | unsigned char binsig[520]; 36 | if (!BN_hex2bn(&bnsig, rs)) 37 | { return -1; } 38 | 39 | int len = BN_bn2bin(bnsig,binsig); 40 | 41 | if (!EC_KEY_set_public_key_affine_coordinates(key,bnx,bny)) 42 | { return -1; } 43 | 44 | int ret = ECDSA_verify(0, digest, SHA256_DIGEST_LENGTH, binsig, len, key); 45 | 46 | EC_KEY_free(key); 47 | BN_free(bnx); 48 | BN_free(bny); 49 | BN_free(bnsig); 50 | 51 | printf("returning\n"); 52 | return ret; 53 | 54 | } 55 | 56 | 57 | int main(int argc, char * argv[]) 58 | { 59 | 60 | char buf[256], c; 61 | char digest[SHA256_DIGEST_LENGTH]; 62 | int take_digest = 1; 63 | 64 | SHA256_CTX sha256; 65 | int n, ret; 66 | int e; 67 | 68 | char * pubkey, * sig; 69 | 70 | if (argc != 3 && argc != 4) 71 | { 72 | fprintf(stderr, "usage: %s [-d]\n" 73 | " -d: don't take sha256sum of stdin input\n",argv[0]); 74 | return 1; 75 | } 76 | 77 | ERR_load_crypto_strings(); 78 | 79 | pubkey = argv[1]; 80 | sig = argv[2]; 81 | 82 | while ( (c = getopt(argc, argv, "d") ) != -1) 83 | { 84 | switch (c) 85 | { 86 | case 'd': 87 | take_digest = 0; 88 | break; 89 | } 90 | } 91 | 92 | if (take_digest) 93 | { 94 | SHA256_Init(&sha256); 95 | 96 | while ((n = read(STDIN_FILENO, buf, sizeof(buf)))>0) 97 | { 98 | SHA256_Update(&sha256, buf, n); 99 | } 100 | 101 | SHA256_Final(digest, &sha256); 102 | } 103 | else 104 | { 105 | read(STDIN_FILENO, digest, sizeof(digest)); 106 | } 107 | 108 | ret = verify(digest, 109 | pubkey, 110 | sig); 111 | 112 | switch(ret) 113 | { 114 | case -1: 115 | printf("signature error:\n"); 116 | while((e=ERR_get_error())!=0) 117 | { 118 | fprintf(stderr,"%s\n", ERR_error_string(e,NULL) ); 119 | } 120 | break; 121 | case 0: 122 | printf("signature incorrect\n"); 123 | break; 124 | case 1: 125 | printf("signature correct\n"); 126 | break; 127 | } 128 | 129 | ERR_free_strings(); 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /tools/setup_device.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SETUP_HEX=../firmware/SETUP.hex 4 | FINAL_HEX=../firmware/release/u2f-firmware.hex 5 | FLASH_TOOLS=0 6 | SN= 7 | SN_build= 8 | SN_setup= 9 | 10 | if [[ $# != "2" ]] && [[ $# != "6" ]] 11 | then 12 | 13 | echo "usage: $0 [debugger-SN new-SN-for-U2F-token setup-hex-file setup-SN]" 14 | echo "eg.: $0 gencert/ca/key.pem gencert/ca/cert.der" 15 | exit 1 16 | 17 | fi 18 | 19 | attest_priv=$1 20 | attest_pub=$2 21 | 22 | if [[ $# != "2" ]] ; then 23 | FLASH_TOOLS=1 24 | SN=$3 25 | SN_build=$4 26 | SETUP_HEX=$5 27 | SN_setup=$6 28 | fi 29 | 30 | export PATH=$PATH:gencert:u2f_zero_client:flashing 31 | 32 | if [[ $FLASH_TOOLS = 1 ]] 33 | then 34 | 35 | # setup atecc 36 | #echo "erasing..." 37 | #erase.sh $SN 38 | 39 | echo "programming setup..." 40 | program.sh $SETUP_HEX $SN 41 | 42 | while [[ "$?" -ne "0" ]] ; do 43 | echo "$SN is retrying program... " 44 | sleep 0.2 45 | program.sh $SETUP_HEX $SN 46 | done 47 | 48 | fi 49 | 50 | echo "configuring..." 51 | 52 | if [[ -n $SN_setup ]] ; then 53 | client.py configure $attest_priv pubkey.hex -s $SN_setup --reuse-keys #>/dev/null 54 | else 55 | client.py configure $attest_priv pubkey.hex --reuse-keys #>/dev/null 56 | fi 57 | 58 | while [[ "$?" -ne "0" ]] ; do 59 | sleep .2 60 | 61 | if [[ -n $SN_setup ]] ; then 62 | client.py configure $attest_priv pubkey.hex -s $SN_setup 63 | else 64 | client.py configure $attest_priv pubkey.hex 65 | fi 66 | 67 | done 68 | 69 | 70 | echo "generate attestation certificate..." 71 | echo "for file $attest_pub" 72 | cbytes.py $attest_pub > ../firmware/src/cert.c 73 | 74 | [[ "$?" -ne "0" ]] && exit 1 75 | 76 | wkey=$(cbytes.py "$(cat pubkey.hex|head -n 1)" -s) 77 | [[ "$?" -ne "0" ]] && exit 1 78 | 79 | rkey=$(cbytes.py "$(cat pubkey.hex|tail -n 1)" -s) 80 | [[ "$?" -ne "0" ]] && exit 1 81 | 82 | 83 | echo "" >> ../firmware/src/cert.c 84 | echo "code uint8_t WMASK[] = $wkey;" >> ../firmware/src/cert.c 85 | echo "code uint8_t RMASK[] = $rkey;" >> ../firmware/src/cert.c 86 | 87 | 88 | if [[ -n $SN_build ]] ; then 89 | echo "setting SN to $SN_build" 90 | sed -i "/#define SER_STRING.*/c\#define SER_STRING \"$SN_build\"" ../firmware/src/descriptors.c 91 | rm ../firmware/release/u2f-firmware.omf 92 | fi 93 | 94 | echo "done." 95 | echo "building..." 96 | 97 | if [[ $FLASH_TOOLS != 1 ]] 98 | then 99 | 100 | echo "Open Simplicity Studio and rebuild final program." 101 | echo "Then you can erase and reprogram U2F Token." 102 | exit 1 103 | 104 | fi 105 | 106 | PATH1=$PATH 107 | cur=`pwd` 108 | cd ../firmware/release && make all && cd $cur 109 | 110 | [[ "$?" -ne "0" ]] && exit 1 111 | 112 | export PATH=$PATH1 113 | 114 | echo "programming final build..." 115 | cp $FINAL_HEX prog.hex 116 | program.sh prog.hex $SN 117 | 118 | while [[ "$?" -ne "0" ]] ; do 119 | sleep .2 120 | program.sh prog.hex $SN 121 | done 122 | 123 | [[ "$?" -ne "0" ]] && exit 1 124 | 125 | echo "waiting to unplug" 126 | sleep 0.2 127 | 128 | while [[ "$?" -eq 0 ]] ; do 129 | 130 | sleep 0.5 131 | client.py wink -s "$SN_build" 132 | 133 | done 134 | 135 | echo "done." 136 | -------------------------------------------------------------------------------- /tools/u2f_zero_client/Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "9818a7e700402c9ed50478e7ac1c9712502338434fdbf0d1780c1f85875b8dec" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "2.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "ecdsa": { 20 | "hashes": [ 21 | "sha256:881fa5e12bb992972d3d1b3d4dfbe149ab76a89f13da02daa5ea1ec7dea6e747", 22 | "sha256:cfc046a2ddd425adbd1a78b3c46f0d1325c657811c0f45ecc3a0a6236c1e50ff" 23 | ], 24 | "index": "pypi", 25 | "version": "==0.16.1" 26 | }, 27 | "hidapi": { 28 | "hashes": [ 29 | "sha256:0c92b398f6907654b07f7dbd7e06661abe9ad6119b403eb5fd3c2af4ce66a3b7", 30 | "sha256:310c53aa81697bf16b5f0c127afda36e5e9ea37794147afe1461422623263ef7", 31 | "sha256:3b93d3f9bae38a3459491194ba1abf5c292b59dbd8738c3ac66f01b593cf3724", 32 | "sha256:4bab0e8ab066527e09856a6a345e2e0c10061f2640e9281323da9a04b94bdec1", 33 | "sha256:59f5205928dbe92513038c50dfb4f939395f8f781e176259a40f37d7a291313f", 34 | "sha256:a1170b18050bc57fae3840a51084e8252fd319c0fc6043d68c8501deb0e25846", 35 | "sha256:b1becc9f09c85c473e91cf869b592d5d87fb8b89672988de33776b20b4c53ce1", 36 | "sha256:b686b2b547890c8ed17ebeabded0050ce377180a56daefa20822b4d66d3a5dea", 37 | "sha256:f49a0de45217366b85597c2edb4be8bd61c9f26f533b854b058dded4352dd89d" 38 | ], 39 | "index": "pypi", 40 | "version": "==0.10.1" 41 | }, 42 | "pyyaml": { 43 | "hashes": [ 44 | "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", 45 | "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", 46 | "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", 47 | "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e", 48 | "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", 49 | "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", 50 | "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", 51 | "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", 52 | "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", 53 | "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a", 54 | "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", 55 | "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", 56 | "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" 57 | ], 58 | "index": "pypi", 59 | "version": "==5.3.1" 60 | }, 61 | "six": { 62 | "hashes": [ 63 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", 64 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" 65 | ], 66 | "version": "==1.15.0" 67 | } 68 | }, 69 | "develop": {} 70 | } 71 | -------------------------------------------------------------------------------- /firmware/src/eeprom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | #include 28 | #include 29 | 30 | #include "eeprom.h" 31 | #include "bsp.h" 32 | 33 | //See EFM8UB1 Reference Manual, 4.3.1 Security Options 34 | #define SECURITY_BYTE_POSITION (0xFBFF) 35 | #define SECURITY_BYTE_UNSET (0xFF) 36 | #define SECURITY_BYTE_PAGE (0xFBC0) 37 | 38 | //number of pages has to be 1's complement 39 | #define LOCK_FIRST_N_PAGES(x) (0xFF^(x)) 40 | //page has 512 bytes 41 | #define LOCK_FIRST_N_KBYTES(x) (LOCK_FIRST_N_PAGES( (x)*2 )) 42 | 43 | void eeprom_init() 44 | { 45 | uint8_t secbyte; 46 | eeprom_read(SECURITY_BYTE_POSITION,&secbyte,1); 47 | if (secbyte == SECURITY_BYTE_UNSET) 48 | { 49 | eeprom_erase(SECURITY_BYTE_PAGE); 50 | secbyte = LOCK_FIRST_N_KBYTES(40); 51 | eeprom_write(SECURITY_BYTE_POSITION, &secbyte, 1); 52 | } 53 | } 54 | 55 | void eeprom_xor(uint16_t addr, uint8_t * out_buf, uint8_t len){ 56 | uint8_t code * eepaddr = (uint8_t code *) addr; 57 | bit old_int; 58 | 59 | watchdog(); 60 | while(len--) 61 | { 62 | old_int = IE_EA; 63 | IE_EA = 0; 64 | *out_buf++ ^= *eepaddr++; 65 | IE_EA = old_int; 66 | } 67 | watchdog(); 68 | } 69 | 70 | void eeprom_read(uint16_t addr, uint8_t * buf, uint8_t len) 71 | { 72 | uint8_t code * eepaddr = (uint8_t code *) addr; 73 | bit old_int; 74 | 75 | watchdog(); 76 | while(len--) 77 | { 78 | old_int = IE_EA; 79 | IE_EA = 0; 80 | *buf++ = *eepaddr++; 81 | IE_EA = old_int; 82 | } 83 | watchdog(); 84 | } 85 | 86 | void _eeprom_write(uint16_t addr, uint8_t * buf, uint8_t len, uint8_t flags) 87 | { 88 | uint8_t xdata * data eepaddr = (uint8_t xdata *) addr; 89 | bit old_int; 90 | 91 | while(len--) 92 | { 93 | old_int = IE_EA; 94 | IE_EA = 0; 95 | // Enable VDD monitor 96 | VDM0CN = 0x80; 97 | RSTSRC = 0x02; 98 | 99 | // unlock key 100 | FLKEY = 0xA5; 101 | FLKEY = 0xF1; 102 | PSCTL |= flags; 103 | 104 | *eepaddr = *buf; 105 | PSCTL &= ~flags; 106 | IE_EA = old_int; 107 | 108 | eepaddr++; 109 | buf++; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /firmware/src/i2c.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | #include 28 | #include 29 | #include 30 | 31 | #include "i2c.h" 32 | 33 | #include "bsp.h" 34 | #include "app.h" 35 | 36 | uint8_t smb_read (uint8_t addr, uint8_t* dest, uint8_t count) 37 | { 38 | while(SMB_IS_BUSY()){} 39 | 40 | SMB_crc = 0; 41 | SMB_crc_offset = 0; 42 | SMB_FLAGS = SMB_READ | SMB_BUSY | SMB_preflags; 43 | SMB_preflags = 0; 44 | 45 | SMB_read_offset = 0; 46 | SMB_addr = addr; 47 | SMB_read_len = count; 48 | SMB_read_buf = dest; 49 | SMB0CN0_STA = 1; 50 | 51 | while(SMB_IS_BUSY()){} 52 | return SMB_read_len; 53 | } 54 | 55 | 56 | void smb_write (uint8_t addr, uint8_t* buf, uint8_t len) 57 | { 58 | while(SMB_IS_BUSY()){} 59 | 60 | SMB_crc = 0; 61 | SMB_crc_offset = 0; 62 | SMB_FLAGS = SMB_WRITE | SMB_BUSY | SMB_preflags; 63 | SMB_preflags = 0; 64 | 65 | SMB_write_len = len; 66 | SMB_write_buf = buf; 67 | SMB_write_offset = 0; 68 | SMB_addr = addr; 69 | 70 | SMB0CN0_STA = 1; 71 | while(SMB_IS_BUSY()){} 72 | } 73 | 74 | void smb_set_ext_write( uint8_t* extbuf, uint8_t extlen) 75 | { 76 | while(SMB_IS_BUSY()){} 77 | SMB_write_ext_len = extlen; 78 | SMB_write_ext_buf = extbuf; 79 | SMB_write_ext_offset = 0; 80 | SMB_preflags |= SMB_WRITE_EXT; 81 | } 82 | 83 | // CRC-16 appropriate for a byte model interrupt routine. 84 | uint16_t feed_crc(uint16_t crc, uint8_t b) 85 | { 86 | crc ^= b; 87 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 88 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 89 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 90 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 91 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 92 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 93 | crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 94 | return crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1; 95 | } 96 | 97 | // Resulting CRC should be reversed to be correct CRC-16 98 | uint16_t reverse_bits(uint16_t crc) 99 | { 100 | // efficient bit reversal for 16 bit int 101 | crc = (((crc & 0xaaaa) >> 1) | ((crc & 0x5555) << 1)); 102 | crc = (((crc & 0xcccc) >> 2) | ((crc & 0x3333) << 2)); 103 | crc = (((crc & 0xf0f0) >> 4) | ((crc & 0x0f0f) << 4)); 104 | return (((crc & 0xff00) >> 8) | ((crc & 0x00ff) << 8)); 105 | } 106 | 107 | void smb_init() 108 | { 109 | SMB_FLAGS = 0; 110 | } 111 | -------------------------------------------------------------------------------- /firmware/inc/i2c.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | */ 26 | 27 | #ifndef I2C_H_ 28 | #define I2C_H_ 29 | 30 | struct smb_interrupt_interface 31 | { 32 | uint8_t addr; 33 | uint16_t crc; 34 | uint8_t crc_offset; 35 | 36 | uint8_t* write_buf; 37 | uint8_t write_len; 38 | uint8_t write_offset; 39 | 40 | uint8_t read_len; 41 | uint8_t read_offset; 42 | uint8_t* read_buf; 43 | 44 | uint8_t* write_ext_buf; 45 | uint8_t write_ext_len; 46 | uint8_t write_ext_offset; 47 | 48 | uint8_t preflags; 49 | }; 50 | 51 | extern data uint8_t SMB_addr; 52 | extern uint8_t * SMB_write_buf; 53 | extern data uint8_t SMB_write_len; 54 | extern data uint8_t SMB_write_offset; 55 | extern data uint8_t SMB_read_len; 56 | extern data uint8_t SMB_read_offset; 57 | extern uint8_t * SMB_read_buf; 58 | extern uint8_t * SMB_write_ext_buf; 59 | extern data uint8_t SMB_write_ext_len; 60 | extern data uint8_t SMB_write_ext_offset; 61 | extern uint8_t SMB_preflags; 62 | extern uint16_t SMB_crc; 63 | extern data uint8_t SMB_crc_offset; 64 | 65 | //extern struct smb_interrupt_interface SMB; 66 | extern data volatile uint8_t SMB_FLAGS; 67 | 68 | #define SMB_MAX_ERRORS 15 69 | #define SMB_ERRORS_EXCEEDED(inter) ((inter)->errors > SMB_MAX_ERRORS) 70 | 71 | #define SMB_WRITE 0x0 72 | #define SMB_READ 0x1 73 | #define SMB_BUSY 0x2 74 | #define SMB_WRITE_EXT 0x4 75 | #define SMB_READ_TRUNC 0x10 76 | #define SMB_RECV_NACK 0x40 77 | 78 | #define SMB_READING() ((SMB_FLAGS & SMB_READ)) 79 | #define SMB_WRITING() (!(SMB_FLAGS & SMB_READ)) 80 | #define SMB_WRITING_EXT() ((SMB_FLAGS & SMB_WRITE_EXT)) 81 | #define SMB_IS_BUSY() ((SMB_FLAGS & SMB_BUSY)) 82 | #define SMB_BUSY_CLEAR() (SMB_FLAGS &= ~SMB_BUSY) 83 | #define SMB_WAS_NACKED() (SMB_FLAGS & SMB_RECV_NACK) 84 | 85 | void smb_init(); 86 | 87 | // read from I2C device, returns number of bytes read. 88 | // sets truncated flag if it had to stop because count wasn't 89 | // large enough 90 | uint8_t smb_read (uint8_t addr, uint8_t* dest, uint8_t count); 91 | 92 | // write to I2C device 93 | void smb_write (uint8_t addr, uint8_t* buf, uint8_t len); 94 | 95 | void smb_set_ext_write( uint8_t* extbuf, uint8_t extlen); 96 | 97 | // reverse bits for a 16 bit int 98 | uint16_t reverse_bits(uint16_t crc); 99 | 100 | // does a crc on byte @b and accumulates it to crc @crc 101 | uint16_t feed_crc(uint16_t crc, uint8_t b); 102 | 103 | #endif /* I2C_H_ */ 104 | -------------------------------------------------------------------------------- /firmware/inc/bsp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | 28 | #ifndef BSP_H_ 29 | #define BSP_H_ 30 | 31 | #include 32 | #include 33 | #include 34 | #include "descriptors.h" 35 | #include "app.h" 36 | 37 | extern data uint32_t _MS_; 38 | extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG); 39 | 40 | SI_SBIT(U2F_BUTTON, SFR_P0, 1); 41 | SI_SBIT(U2F_LED, SFR_P0, 6); 42 | SI_SBIT(U2F_BUTTON_RESET, SFR_P0, 7); 43 | 44 | /* 45 | * U2F_BUTTON_RESET is a MTPM pin. Requires HIGH state to keep 46 | * NORMAL power mode on MTCH101 47 | * */ 48 | 49 | 50 | #define IS_BUTTON_PRESSED() (U2F_BUTTON == 0) 51 | #define LED_ON() { U2F_LED = 0; } 52 | #define LED_OFF() { U2F_LED = 1; } 53 | #define BUTTON_RESET_ON() { U2F_BUTTON_RESET = 0; } 54 | #define BUTTON_RESET_OFF() { U2F_BUTTON_RESET = 1; } 55 | #define IS_LED_ON() (U2F_LED == 0) 56 | #define GetEp(epAddr) (&myUsbDevice.ep0 + epAddr) 57 | #ifndef DISABLE_WATCHDOG 58 | #define watchdog() (WDTCN = 0xA5) 59 | #else 60 | #define watchdog() 61 | #endif 62 | #define reboot() (RSTSRC = 1 << 4) 63 | #define get_ms() _MS_ 64 | 65 | void u2f_delay (uint32_t ms); 66 | void usb_write (uint8_t* buf, uint8_t len); 67 | 68 | #ifdef U2F_PRINT 69 | 70 | void dump_hex(uint8_t* hex, uint8_t len); 71 | 72 | void u2f_putd(uint32_t i); 73 | void u2f_putx(uint32_t i); 74 | 75 | #define u2f_putb(x) u2f_putx((uint8_t) (x)) 76 | #define u2f_putl(x) u2f_putd((uint32_t) (x)) 77 | #define u2f_putlx(x) u2f_putx((uint32_t) (x)) 78 | 79 | void u2f_prints(const char * str); 80 | void u2f_printb(const char * tag, uint8_t c, ...); 81 | void u2f_printd(const char * tag, uint8_t c, ...); 82 | void u2f_printx(const char * tag, uint8_t c, ...); 83 | void u2f_printl(const char * tag, uint8_t c, ...); 84 | void u2f_printlx(const char * tag, uint8_t c, ...); 85 | 86 | #else 87 | 88 | #define u2f_printx(x, y, z) 89 | #define u2f_printb(x, y, z) 90 | #define u2f_printlx(x, y, z, zz) 91 | #define u2f_printl(x) 92 | #define u2f_printd(x) 93 | #define u2f_prints(x) 94 | 95 | #define u2f_putx(x) 96 | #define u2f_putb(x) 97 | #define u2f_putl(x) 98 | #define u2f_putlx(x) 99 | 100 | #define putf(x) 101 | #define dump_hex(x, y) 102 | 103 | #endif 104 | 105 | 106 | 107 | 108 | #endif /* BSP_H_ */ 109 | -------------------------------------------------------------------------------- /firmware/src/sanity-check.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Nitrokey UG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | */ 26 | 27 | #include 28 | #include "eeprom.h" 29 | #include 30 | #include "sanity-check.h" 31 | 32 | #ifdef _SECURE_EEPROM 33 | #define _secure_eeprom 1 34 | #else 35 | #define _secure_eeprom 0 36 | #endif 37 | 38 | #ifdef FAKE_TOUCH 39 | #define _fake_touch 1 40 | #else 41 | #define _fake_touch 0 42 | #endif 43 | 44 | #ifdef DISABLE_WATCHDOG 45 | #define _disable_watchdog 1 46 | #else 47 | #define _disable_watchdog 0 48 | #endif 49 | 50 | #ifdef ATECC_SETUP_DEVICE 51 | #define _setup 1 52 | #else 53 | #define _setup 0 54 | #endif 55 | 56 | bool sanity_check_passed = false; 57 | check_info sanity_check_info; 58 | 59 | bool test_if_memory_empty(uint16_t addr, uint8_t len){ 60 | uint8_t buf[36]; 61 | uint8_t i, zeroes = 0; 62 | bool res = true; 63 | if (len > sizeof(buf)) return false; 64 | 65 | eeprom_read(addr, buf, len); 66 | 67 | // make it constant time, do not return early 68 | // reject all 0xFF's 69 | for (i=0; i 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | int generate_cert(EVP_PKEY * signer, EVP_PKEY * pubkey, X509 ** outcert) 27 | { 28 | int ret; 29 | X509 * x509, * x509_issuer; 30 | X509_NAME * name, * issuer_name; 31 | 32 | x509 = X509_new(); 33 | x509_issuer = X509_new(); 34 | 35 | 36 | if (!ASN1_INTEGER_set(X509_get_serialNumber(x509), 1)) 37 | { return 0; } 38 | 39 | if (!X509_gmtime_adj(X509_get_notBefore(x509), 0)) 40 | { return 0; } 41 | if (!X509_gmtime_adj(X509_get_notAfter(x509), 189216000L)) // 6 yrs 42 | { return 0; } 43 | if (!X509_set_pubkey(x509, pubkey)) 44 | { return 0; } 45 | 46 | name = X509_get_subject_name(x509); 47 | X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, 48 | (unsigned char *)"US", -1, -1, 0); 49 | X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, 50 | (unsigned char *)"U2F Zero", -1, -1, 0); 51 | X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, 52 | (unsigned char *)"u2fzero.com", -1, -1, 0); 53 | 54 | issuer_name = X509_get_subject_name(x509_issuer); 55 | X509_NAME_add_entry_by_txt(issuer_name, "C", MBSTRING_ASC, 56 | (unsigned char *)"US", -1, -1, 0); 57 | X509_NAME_add_entry_by_txt(issuer_name, "ST", MBSTRING_ASC, 58 | (unsigned char *)"Some state", -1, -1, 0); 59 | X509_NAME_add_entry_by_txt(issuer_name, "L", MBSTRING_ASC, 60 | (unsigned char *)"Some city", -1, -1, 0); 61 | X509_NAME_add_entry_by_txt(issuer_name, "O", MBSTRING_ASC, 62 | (unsigned char *)"Some company", -1, -1, 0); 63 | X509_NAME_add_entry_by_txt(issuer_name, "OU", MBSTRING_ASC, 64 | (unsigned char *)"Some department", -1, -1, 0); 65 | X509_NAME_add_entry_by_txt(issuer_name, "CN", MBSTRING_ASC, 66 | (unsigned char *)"conorpp.com", -1, -1, 0); 67 | 68 | 69 | if (!X509_set_issuer_name(x509, issuer_name)) 70 | { return 0; } 71 | 72 | if (!X509_sign(x509, signer, EVP_sha256())) 73 | { return 0; } 74 | 75 | *outcert = x509; 76 | return 1; 77 | } 78 | 79 | static void openssl_die() 80 | { 81 | 82 | fprintf(stderr,"signature error: %s\n", 83 | ERR_error_string(ERR_get_error(),NULL) ); 84 | exit(2); 85 | } 86 | 87 | 88 | int main(int argc, char * argv[]) 89 | { 90 | 91 | if (argc != 4) 92 | { 93 | fprintf(stderr, "usage: %s \n", argv[0]); 94 | return 1; 95 | } 96 | 97 | X509 * gencert = NULL; 98 | EVP_PKEY * privkey = NULL; 99 | EVP_PKEY * pubkey = NULL; 100 | 101 | FILE* fpriv = fopen(argv[1], "r"); 102 | FILE* fpub = fopen(argv[2], "r"); 103 | 104 | if (fpriv == NULL || fpub == NULL) 105 | { 106 | perror("fopen"); 107 | return 2; 108 | } 109 | 110 | ERR_load_crypto_strings(); 111 | 112 | PEM_read_PrivateKey(fpriv, &privkey, NULL, NULL); 113 | PEM_read_PUBKEY(fpub, &pubkey, NULL, NULL); 114 | 115 | if (!generate_cert(privkey, pubkey, &gencert)) 116 | { openssl_die(); } 117 | 118 | FILE * fcert; 119 | fcert = fopen(argv[3], "wb"); 120 | if (fcert == NULL) 121 | { 122 | perror("fopen"); 123 | return 2; 124 | } 125 | 126 | if (!i2d_X509_fp(fcert, gencert)) 127 | { openssl_die(); } 128 | 129 | 130 | fclose(fcert); 131 | X509_free(gencert); 132 | EVP_PKEY_free(privkey); 133 | ERR_free_strings(); 134 | fclose(fpriv); 135 | 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /tools/monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | export PATH=$PATH:`pwd`/flashing:../../../u2f_zero_client:../../../gencert 5 | 6 | export attest_priv=gencert/ca/key.pem 7 | export attest_pub=gencert/ca/attest.der 8 | adapters[0]=0 9 | adapters[1]=COM3 10 | adapters[2]=COM4 11 | num_adapters=2 12 | firmware=../firmware 13 | export setup=setup_device.sh 14 | export starting_SN=DAFE1E340AB70000 15 | setup_SNs=(0 CAFEBABEFFFFFFF0 CAFEBABEFFFFFFF1 CAFEBABEFFFFFFF2) 16 | 17 | if [[ -n "$1" ]] ; then 18 | starting_SN=$((0x$starting_SN + $1)) 19 | fi 20 | 21 | function inc_hex { 22 | a=$((0x$1 + 1)) 23 | a=$(printf "%x\n" $a) 24 | echo ${a^^} 25 | } 26 | 27 | function is_running { 28 | 29 | sn=$1 30 | if [[ -f workers/$sn/worker/.finished ]] ; then 31 | pwd 32 | echo "$sn finished" 33 | return 1 34 | fi 35 | 36 | pwd 37 | echo "$sn still running" 38 | return 0 39 | 40 | } 41 | 42 | function remove_lock { 43 | 44 | sn=$1 45 | touch workers/$sn/worker/.finished 46 | 47 | } 48 | 49 | function start_programming { 50 | 51 | sn=$1 52 | setupf=$2 53 | setup_sn=$3 54 | rm -f workers/$sn/worker/.finished 55 | cd workers/$sn/worker && ./$setup ../../../$attest_priv ../../../$attest_pub $sn $starting_SN $setupf $setup_sn \ 56 | && touch .finished && cd ../../.. & 57 | export starting_SN=$(inc_hex $starting_SN) 58 | 59 | } 60 | 61 | 62 | #for i in `seq 1 100` ; do 63 | 64 | #adapters[$i]=$(FlashUtilCL.exe DeviceSN $i) 65 | 66 | #if [[ ${adapters[$i]} = *"out of range"* ]] 67 | #then 68 | #break 69 | #fi 70 | 71 | #num_adapters=$(($num_adapters + 1)) 72 | #done 73 | 74 | export num_adapters=$num_adapters 75 | export adapters=$adapters 76 | 77 | rm -rf workers 78 | mkdir workers 79 | 80 | for i in `seq 1 $num_adapters` ; do 81 | 82 | echo "$i :" ${adapters[$i]} 83 | mkdir workers/${adapters[$i]} 84 | mkdir workers/${adapters[$i]}/worker 85 | cp -rf $firmware workers/${adapters[$i]} 86 | cp $setup workers/${adapters[$i]}/worker 87 | touch workers/${adapters[$i]}/worker/.finished 88 | 89 | # fix path in meta file to point to new location for files that are "dynamic" 90 | sed -i "s/firmware.*src.*cert.c/tools\/workers\/${adapters[$i]}\/firmware\/src\/cert.c/g" \ 91 | workers/${adapters[$i]}/firmware/release/src/cert.__i 92 | sed -i "s/firmware.*src.*descriptors.c/tools\/workers\/${adapters[$i]}\/firmware\/src\/descriptors.c/g" \ 93 | workers/${adapters[$i]}/firmware/release/src/descriptors.__i 94 | 95 | done 96 | 97 | #cd workers/${adapters[1]}/worker && ./$setup ../../../$key ${adapters[1]} CAFEBABE00000001 98 | 99 | starting_SN=$(inc_hex $starting_SN) 100 | echo $starting_SN 101 | 102 | #cd workers/${adapters[1]}/worker && ./$setup ../../../$key ${adapters[1]} CAFEBABE00000001 & 103 | #is_running ${adapters[1]} 104 | #echo $? 105 | 106 | #exit 0 107 | 108 | c_stack=(0 0 0 0) 109 | 110 | for (( ; ; )) 111 | do 112 | 113 | read -n 1 j 114 | 115 | if [[ $j -gt $num_adapters ]] ; then 116 | 117 | echo "$j is too big" 118 | continue 119 | 120 | fi 121 | 122 | # 3 element queue 123 | c_stack+=($j) 124 | c_stack=("${c_stack[@]:1}") 125 | 126 | if [[ "${c_stack[1]}" -eq "${c_stack[2]}" ]] ; then 127 | 128 | if [[ "${c_stack[2]}" -eq "${c_stack[3]}" ]] ; then 129 | 130 | # if entered 3 times in a row, remove lock 131 | remove_lock ${adapters[$j]} 132 | c_stack=(0 0 0 0) 133 | echo 134 | echo 135 | echo "restarting $j: ${adapters[$j]}" 136 | echo 137 | echo 138 | 139 | fi 140 | 141 | fi 142 | 143 | jobs 144 | 145 | 146 | 147 | is_running ${adapters[$j]} 148 | 149 | if [[ $? -eq 1 ]] ; then 150 | echo "starting $j ${adapters[$j]}" 151 | start_programming ${adapters[$j]} ../firmware/SETUP_"${setup_SNs[$j]}".hex ${setup_SNs[$j]} 152 | else 153 | echo "$j ${adapters[$j]} is already running" 154 | fi 155 | 156 | done 157 | 158 | -------------------------------------------------------------------------------- /firmware/src/usb_serial.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Nitrokey UG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | 26 | Control USB serial number. Get it from ATECC508A chip, and expose where requested. 27 | 28 | */ 29 | 30 | 31 | #include "configuration.h" 32 | #include "descriptors.h" 33 | #include 34 | #include "eeprom.h" 35 | #include "atecc508a.h" 36 | 37 | #define NK_SERIAL_LEN (13) 38 | #define NK_SERIAL_ASCII_LEN (NK_SERIAL_LEN*2) 39 | 40 | typedef struct { 41 | uint8_t header[3]; 42 | uint8_t serial_ascii[NK_SERIAL_ASCII_LEN+1]; 43 | } USBSerialDescr; 44 | 45 | USBSerialDescr serial_descriptor; 46 | 47 | /** 48 | * Convert single hex digit to ascii character. 49 | */ 50 | static uint8_t hex2ascii(uint8_t c){ 51 | if (c > 15){ 52 | return 'x'; 53 | } 54 | if(c <= 9){ 55 | return c + '0'; 56 | } 57 | c -= 10; 58 | return c + 'A'; 59 | } 60 | 61 | /** 62 | * Convert uint8_t to string, e.g. 0x21 to "21". 63 | */ 64 | static void convert_bin_to_hex(uint8_t *src, uint8_t src_len, uint8_t *dest, uint8_t dest_len){ 65 | uint8_t i, c; 66 | 67 | if (src_len*2 > dest_len) 68 | return; 69 | 70 | for (i=0; i>= 4; 73 | dest[i*2] = hex2ascii(c); 74 | 75 | c = 0x0F & src[i]; 76 | dest[i*2+1] = hex2ascii(c); 77 | } 78 | } 79 | 80 | /** 81 | * Update USB serial of the device, with a value read from EEPROM. 82 | */ 83 | void update_USB_serial(){ 84 | if(configuration.show_serial_on_USB != CONFIG_TRUE) 85 | return; 86 | 87 | memset(serial_descriptor.serial_ascii, 0, sizeof(serial_descriptor.serial_ascii)); 88 | // load target USB serial number 89 | eeprom_read(EEPROM_DATA_SERIAL, serial_descriptor.serial_ascii, NK_SERIAL_ASCII_LEN); 90 | 91 | serial_descriptor.header[0] = USB_STRING_DESCRIPTOR_UTF16LE_PACKED; 92 | serial_descriptor.header[1] = sizeof(serial_descriptor.serial_ascii)*2; 93 | serial_descriptor.header[2] = USB_STRING_DESCRIPTOR; 94 | 95 | initstruct.stringDescriptors[3] = (uint8_t*) &serial_descriptor; 96 | } 97 | 98 | 99 | /** 100 | * Get serial number from the ATECC508A chip and save it on MCU's FLASH memory. 101 | * Serial is exposed in the first 12 bytes of ATECC508A configuration zone. 102 | * Abort, if the memory slot is not empty. 103 | * Requires ATECC508A to be configured and awake. 104 | * See 2.2 EEPROM Configuration Zone, ATECC508A Datasheet Complete DS20005927A-page 13 105 | */ 106 | void get_serial_num(){ 107 | uint8_t atecc_buf[32+8]; 108 | uint8_t serial_ascii[NK_SERIAL_ASCII_LEN]; 109 | struct atecc_response res; 110 | uint8_t i; 111 | 112 | if(configuration.show_serial_on_USB != CONFIG_TRUE) 113 | return; 114 | 115 | eeprom_read(EEPROM_DATA_SERIAL, serial_ascii, NK_SERIAL_ASCII_LEN); 116 | for (i=0; i 28 | #include 29 | #include 30 | #include "app.h" 31 | #include "bsp.h" 32 | #include "descriptors.h" 33 | #include "u2f_hid.h" 34 | 35 | #define UNUSED(expr) do { (void)(expr); } while (0) 36 | 37 | #define HID_INTERFACE_INDEX 0 38 | 39 | uint8_t tmpBuffer; 40 | 41 | //#define PRINT_EVENTS 42 | 43 | #ifdef PRINT_EVENTS 44 | 45 | #define u2f_print_ev(s) u2f_prints(s) 46 | 47 | #else 48 | #define u2f_print_ev(x) 49 | #endif 50 | 51 | 52 | void USBD_ResetCb(void) { 53 | u2f_print_ev("USBD_ResetCb\r\n"); 54 | } 55 | 56 | 57 | void USBD_DeviceStateChangeCb(USBD_State_TypeDef oldState, 58 | USBD_State_TypeDef newState) { 59 | 60 | UNUSED(oldState); 61 | UNUSED(newState); 62 | 63 | u2f_print_ev("USBD_DeviceStateChangeCb\r\n"); 64 | } 65 | 66 | bool USBD_IsSelfPoweredCb(void) { 67 | return false; 68 | } 69 | 70 | // Necessary routine for USB HID 71 | USB_Status_TypeDef USBD_SetupCmdCb( 72 | SI_VARIABLE_SEGMENT_POINTER(setup, USB_Setup_TypeDef, MEM_MODEL_SEG)) { 73 | 74 | USB_Status_TypeDef retVal = USB_STATUS_REQ_UNHANDLED; 75 | 76 | 77 | if ((setup->bmRequestType.Type == USB_SETUP_TYPE_STANDARD) 78 | && (setup->bmRequestType.Direction == USB_SETUP_DIR_IN) 79 | && (setup->bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE)) { 80 | // A HID device must extend the standard GET_DESCRIPTOR command 81 | // with support for HID descriptors. 82 | 83 | switch (setup->bRequest) { 84 | case GET_DESCRIPTOR: 85 | if (setup->wIndex == 0) 86 | { 87 | if ((setup->wValue >> 8) == USB_HID_REPORT_DESCRIPTOR) { 88 | 89 | USBD_Write(EP0, ReportDescriptor0, 90 | EFM8_MIN(sizeof(ReportDescriptor0), setup->wLength), 91 | false); 92 | retVal = USB_STATUS_OK; 93 | 94 | } else if ((setup->wValue >> 8) == USB_HID_DESCRIPTOR) { 95 | 96 | USBD_Write(EP0, (&configDesc[18]), 97 | EFM8_MIN(USB_HID_DESCSIZE, setup->wLength), false); 98 | retVal = USB_STATUS_OK; 99 | 100 | } 101 | } 102 | break; 103 | } 104 | } 105 | else if ((setup->bmRequestType.Type == USB_SETUP_TYPE_CLASS) 106 | && (setup->bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE) 107 | && (setup->wIndex == HID_INTERFACE_INDEX)) 108 | { 109 | // Implement the necessary HID class specific commands. 110 | switch (setup->bRequest) 111 | { 112 | case USB_HID_SET_IDLE: 113 | if (((setup->wValue & 0xFF) == 0) // Report ID 114 | && (setup->wLength == 0) 115 | && (setup->bmRequestType.Direction != USB_SETUP_DIR_IN)) 116 | { 117 | retVal = USB_STATUS_OK; 118 | } 119 | break; 120 | 121 | case USB_HID_GET_IDLE: 122 | if ((setup->wValue == 0) // Report ID 123 | && (setup->wLength == 1) 124 | && (setup->bmRequestType.Direction == USB_SETUP_DIR_IN)) 125 | { 126 | tmpBuffer = 24; 127 | USBD_Write(EP0, &tmpBuffer, 1, false); 128 | retVal = USB_STATUS_OK; 129 | } 130 | break; 131 | default: 132 | break; 133 | } 134 | } 135 | 136 | return retVal; 137 | } 138 | 139 | 140 | 141 | 142 | uint8_t hidmsgbuf[64]; 143 | uint16_t USBD_XferCompleteCb(uint8_t epAddr, USB_Status_TypeDef status, 144 | uint16_t xferred, uint16_t remaining ) { 145 | 146 | UNUSED(status); 147 | UNUSED(xferred); 148 | UNUSED(remaining); 149 | 150 | 151 | if (epAddr == EP1OUT) 152 | { 153 | set_app_u2f_hid_msg((struct u2f_hid_msg *) hidmsgbuf ); 154 | } 155 | return 0; 156 | } 157 | 158 | 159 | -------------------------------------------------------------------------------- /firmware/src/bsp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "app.h" 32 | #include "bsp.h" 33 | #include "gpio.h" 34 | 35 | 36 | void u2f_delay(uint32_t ms) { 37 | uint32_t ms_now = get_ms(); 38 | while((get_ms() - ms_now) < ms) 39 | { 40 | // make sure at least 1ms pass between watchdog calls (better time resolution is not required) 41 | // see Errata, https://www.silabs.com/documents/public/errata/EFM8UB1-Errata.pdf 42 | // 2.2 WDT_E101 – Restrictions on Watchdog Timer Refresh Interval 43 | while((get_ms() - ms_now) <= 1) 44 | ; 45 | watchdog(); 46 | led_blink_manager(); 47 | } 48 | } 49 | 50 | void usb_write(uint8_t* buf, uint8_t len) 51 | { 52 | uint8_t errors = 0; 53 | while (USB_STATUS_OK != (USBD_Write(EP1IN, buf, len, false))) 54 | { 55 | u2f_delay(2); 56 | if (errors++ > 30) 57 | { 58 | set_app_error(ERROR_USB_WRITE); 59 | break; 60 | } 61 | } 62 | } 63 | 64 | 65 | // Painfully lightweight printing routines 66 | #ifdef U2F_PRINT 67 | 68 | void putf(char c) 69 | { 70 | uint8_t i; 71 | SBUF0 = c; 72 | // Blocking delay that works for 115200 baud on this device (<1ms) 73 | for (i=0; i<200; i++){} 74 | for (i=0; i<200; i++){} 75 | for (i=0; i<190; i++){} 76 | watchdog(); 77 | } 78 | 79 | 80 | void dump_hex(uint8_t* hex, uint8_t len) 81 | { 82 | uint8_t i; 83 | for (i=0 ; i < len ; i++) 84 | { 85 | if (hex[i]<0x10) 86 | { 87 | putf('0'); 88 | } 89 | u2f_putb(hex[i]); 90 | } 91 | u2f_prints("\r\n"); 92 | } 93 | 94 | 95 | void u2f_prints(char* d) 96 | { 97 | while(*d) 98 | { 99 | // UART0 output queue 100 | putf(*d++); 101 | } 102 | } 103 | 104 | static void int2str_reduce_n(char ** snum, uint32_t copy, uint8_t n) 105 | { 106 | do 107 | { 108 | copy /= n; 109 | }while(copy); 110 | } 111 | 112 | 113 | static const char * __digits = "0123456789abcdef"; 114 | static char __int2str_buf[9]; 115 | 116 | static void int2str_map_n(char ** snum, uint32_t i, uint8_t n) 117 | { 118 | do 119 | { 120 | *--*snum = __digits[i % n]; 121 | i /= n; 122 | }while(i); 123 | } 124 | 125 | #define dint2str(i) __int2strn(i,10) 126 | #define xint2str(i) __int2strn(i,16) 127 | 128 | char * __int2strn(int32_t i, uint8_t n) 129 | { 130 | char * snum = __int2str_buf; 131 | if (i<0) *snum++ = '-'; 132 | int2str_reduce_n(&snum, i, n); 133 | *snum = '\0'; 134 | int2str_map_n(&snum, i, n); 135 | return snum; 136 | } 137 | 138 | void u2f_putd(int32_t i) 139 | { 140 | u2f_prints(dint2str((int32_t)i)); 141 | } 142 | 143 | void u2f_putx(int32_t i) 144 | { 145 | u2f_prints(xint2str(i)); 146 | } 147 | 148 | static void put_space() 149 | { 150 | u2f_prints(" "); 151 | } 152 | static void put_line() 153 | { 154 | u2f_prints("\r\n"); 155 | } 156 | 157 | void u2f_printd(const char * tag, uint8_t c, ...) 158 | { 159 | va_list args; 160 | u2f_prints(tag); 161 | va_start(args,c); 162 | while(c--) 163 | { 164 | u2f_putd((int32_t)va_arg(args, int16_t)); 165 | 166 | } 167 | put_line(); 168 | va_end(args); 169 | } 170 | 171 | void u2f_printl(const char * tag, uint8_t c, ...) 172 | { 173 | va_list args; 174 | u2f_prints(tag); 175 | va_start(args,c); 176 | while(c--) 177 | { 178 | u2f_putl(va_arg(args, int32_t)); 179 | u2f_prints(" "); 180 | } 181 | put_line(); 182 | va_end(args); 183 | } 184 | 185 | void u2f_printx(const char * tag, uint8_t c, ...) 186 | { 187 | va_list args; 188 | u2f_prints(tag); 189 | va_start(args,c); 190 | while(c--) 191 | { 192 | u2f_putx((int32_t)va_arg(args, uint16_t)); 193 | u2f_prints(" "); 194 | } 195 | put_line(); 196 | va_end(args); 197 | } 198 | 199 | void u2f_printb(const char * tag, uint8_t c, ...) 200 | { 201 | va_list args; 202 | u2f_prints(tag); 203 | va_start(args,c); 204 | while(c--) 205 | { 206 | u2f_putb(va_arg(args, uint8_t)); 207 | put_space(); 208 | } 209 | put_line(); 210 | va_end(args); 211 | } 212 | 213 | void u2f_printlx(const char * tag, uint8_t c, ...) 214 | { 215 | va_list args; 216 | u2f_prints(tag); 217 | va_start(args,c); 218 | while(c--) 219 | { 220 | u2f_putlx(va_arg(args, int32_t)); 221 | put_space(); 222 | } 223 | put_line(); 224 | va_end(args); 225 | } 226 | 227 | #else 228 | 229 | 230 | 231 | 232 | #endif 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /firmware/src/Interrupts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | 28 | #include 29 | #include 30 | #include "app.h" 31 | #include "i2c.h" 32 | 33 | #include "bsp.h" 34 | 35 | // millisecond timer 36 | uint32_t data _MS_ = 0; 37 | SI_INTERRUPT (TIMER2_ISR, TIMER2_IRQn) 38 | { 39 | TMR2CN0_TF2H = 0; 40 | ++_MS_; 41 | } 42 | 43 | #define SMB_STATUS_START 0xE0 44 | #define SMB_STATUS_MTX 0xC0 45 | #define SMB_STATUS_MRX 0x80 46 | #define SMB_STATE_MASK 0xF0 47 | 48 | 49 | #define SMB_TX_STATE_MASK (SMB_WRITE_EXT|SMB_WRITE) 50 | #define SMB_TX_EXT (SMB_WRITE|SMB_WRITE_EXT) 51 | #define SMB_TX (SMB_WRITE) 52 | 53 | data uint8_t SMB_addr = 0; 54 | uint8_t * SMB_write_buf = NULL; 55 | data uint8_t SMB_write_len = 0; 56 | data uint8_t SMB_write_offset = 0; 57 | data uint8_t SMB_read_len = 0; 58 | data uint8_t SMB_read_offset = 0; 59 | uint8_t * SMB_read_buf = NULL; 60 | uint8_t * SMB_write_ext_buf = NULL; 61 | data uint8_t SMB_write_ext_len = 0; 62 | data uint8_t SMB_write_ext_offset = 0; 63 | uint8_t SMB_preflags = 0; 64 | uint16_t SMB_crc = 0; 65 | data uint8_t SMB_crc_offset = 0; 66 | data volatile uint8_t SMB_FLAGS = 0; 67 | 68 | static void update_from_packet_length() 69 | { 70 | if (SMB_read_buf[0] <= SMB_read_len) 71 | { 72 | SMB_read_len = SMB_read_buf[0]; 73 | } 74 | else 75 | { 76 | // truncated read 77 | SMB_FLAGS |= SMB_READ_TRUNC; 78 | } 79 | } 80 | 81 | static void _feed_crc(uint8_t b) 82 | { 83 | SMB_crc = feed_crc(SMB_crc,b); 84 | } 85 | 86 | static void restart_bus() 87 | { 88 | SMB0CF &= ~0x80; 89 | SMB0CF |= 0x80; 90 | SMB0CN0_STA = 0; 91 | SMB0CN0_STO = 0; 92 | SMB0CN0_ACK = 0; 93 | SMB_BUSY_CLEAR(); 94 | } 95 | 96 | SI_INTERRUPT (SMBUS0_ISR, SMBUS0_IRQn) 97 | { 98 | data uint8_t bus = SMB0CN0 & SMB_STATE_MASK; 99 | data uint8_t c; 100 | if (SMB0CN0_ARBLOST != 0) 101 | { 102 | goto fail; 103 | } 104 | 105 | switch (bus) 106 | { 107 | case SMB_STATUS_START: 108 | SMB0DAT = SMB_addr | (SMB_FLAGS & SMB_READ); 109 | SMB0CN0_STA = 0; 110 | break; 111 | 112 | case SMB_STATUS_MTX: 113 | if (!SMB0CN0_ACK) 114 | { 115 | // NACK 116 | // end transaction 117 | SMB0CN0_STO = 1; 118 | SMB_FLAGS |= SMB_RECV_NACK; 119 | SMB_BUSY_CLEAR(); 120 | } 121 | else if (!SMB_WRITING()) 122 | { 123 | // do nothing and switch to receive mode 124 | } 125 | else if (SMB_write_offset < SMB_write_len) 126 | { 127 | // start writing first buffer 128 | // dont crc first byte for atecc508a 129 | c = SMB_write_buf[SMB_write_offset++]; 130 | if (SMB_write_offset > 1) _feed_crc(c); 131 | SMB0DAT = c; 132 | 133 | } 134 | else if(SMB_WRITING_EXT() && SMB_write_ext_offset < SMB_write_ext_len) 135 | { 136 | // start writing second optional buffer 137 | c = SMB_write_ext_buf[SMB_write_ext_offset++]; 138 | _feed_crc(c); 139 | SMB0DAT = c; 140 | } 141 | else 142 | { 143 | // write optional CRC 144 | switch(SMB_crc_offset++) 145 | { 146 | case 0: 147 | SMB_crc = reverse_bits(SMB_crc); 148 | SMB0DAT = (uint8_t)SMB_crc; 149 | break; 150 | case 1: 151 | SMB0DAT = (uint8_t)(SMB_crc>>8); 152 | break; 153 | case 2: 154 | SMB0CN0_STO = 1; 155 | SMB_BUSY_CLEAR(); 156 | } 157 | } 158 | 159 | break; 160 | 161 | case SMB_STATUS_MRX: 162 | // read in buffer 163 | 164 | if (SMB_read_offset < SMB_read_len) 165 | { 166 | c = SMB0DAT; 167 | SMB_read_buf[SMB_read_offset] = c; 168 | 169 | // update with length from packet 170 | // warning this is device specific to atecc508a 171 | if (SMB_read_offset == 0) 172 | { 173 | update_from_packet_length(); 174 | } 175 | 176 | if ((SMB_read_offset < (SMB_read_len - 2))) 177 | { 178 | SMB_crc = feed_crc(SMB_crc, c); 179 | } 180 | 181 | SMB_read_offset++; 182 | SMB0CN0_ACK = 1; 183 | } 184 | else 185 | { 186 | // end transaction 187 | 188 | SMB_crc = reverse_bits(SMB_crc); 189 | SMB_BUSY_CLEAR(); 190 | SMB0CN0_ACK = 0; 191 | SMB0CN0_STO = 1; 192 | } 193 | 194 | break; 195 | 196 | default: 197 | goto fail; 198 | break; 199 | 200 | } 201 | 202 | 203 | // interrupt flag 204 | SMB0CN0_SI = 0; 205 | return; 206 | 207 | fail: 208 | u2f_printb("smbus fail ",1,bus); 209 | //restart_bus(); 210 | SMB0CN0_SI = 0; 211 | } 212 | 213 | 214 | // A Timer3 interrupt indicates an SMBus SCL low timeout. 215 | // The SMBus is disabled and re-enabled here 216 | SI_INTERRUPT (TIMER3_ISR, TIMER3_IRQn) 217 | { 218 | //restart_bus(); 219 | } 220 | 221 | 222 | 223 | 224 | -------------------------------------------------------------------------------- /firmware/lib/efm8ub1/peripheralDrivers/src/usb_0.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. 3 | * 4 | * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt 5 | *****************************************************************************/ 6 | 7 | #include "usb_0.h" 8 | #include 9 | #include 10 | 11 | /** @addtogroup usb_0_runtime USB0 Runtime API */ 12 | 13 | // ----------------------------------------------------------------------------- 14 | // Functions 15 | 16 | // ------------------------------- 17 | // Utility Functions 18 | 19 | /**************************************************************************//** 20 | * @brief Reads a 16-bit indirect USB register value 21 | * @param regAddr 22 | * Address of high byte of 16-bit USB indirect register to read 23 | * @return 16-bit register value 24 | *****************************************************************************/ 25 | static uint16_t USB_GetShortRegister(uint8_t regAddr) 26 | { 27 | uint16_t retVal; 28 | 29 | USB_READ_BYTE(regAddr); 30 | retVal = (USB0DAT << 8); 31 | USB_READ_BYTE((regAddr - 1)); 32 | retVal |= USB0DAT; 33 | 34 | return retVal; 35 | } 36 | 37 | // ------------------------------- 38 | // USB0 Peripheral Driver Functions 39 | 40 | void USB_SetIndex(uint8_t epsel) 41 | { 42 | USB_WRITE_BYTE(INDEX, epsel); 43 | } 44 | 45 | uint8_t USB_GetCommonInts(void) 46 | { 47 | USB_READ_BYTE(CMINT); 48 | return USB0DAT; 49 | } 50 | 51 | uint8_t USB_GetInInts(void) 52 | { 53 | USB_READ_BYTE(IN1INT); 54 | return USB0DAT; 55 | } 56 | 57 | uint8_t USB_GetOutInts(void) 58 | { 59 | USB_READ_BYTE(OUT1INT); 60 | return USB0DAT; 61 | } 62 | 63 | uint8_t USB_GetIndex(void) 64 | { 65 | USB_READ_BYTE(INDEX); 66 | return USB0DAT; 67 | } 68 | 69 | bool USB_IsSuspended(void) 70 | { 71 | USB_READ_BYTE(POWER); 72 | return USB0DAT & POWER_SUSMD__SUSPENDED; 73 | } 74 | 75 | bool USB_GetSetupEnd(void) 76 | { 77 | USB_READ_BYTE(E0CSR); 78 | return USB0DAT & E0CSR_SUEND__SET; 79 | } 80 | 81 | bool USB_Ep0SentStall(void) 82 | { 83 | USB_READ_BYTE(E0CSR); 84 | return USB0DAT & E0CSR_STSTL__SET; 85 | } 86 | 87 | bool USB_Ep0OutPacketReady(void) 88 | { 89 | USB_READ_BYTE(E0CSR); 90 | return USB0DAT & E0CSR_OPRDY__SET; 91 | } 92 | 93 | bool USB_Ep0InPacketReady(void) 94 | { 95 | USB_READ_BYTE(E0CSR); 96 | return USB0DAT & E0CSR_INPRDY__SET; 97 | } 98 | 99 | uint8_t USB_Ep0GetCount(void) 100 | { 101 | USB_READ_BYTE(E0CNT); 102 | return USB0DAT; 103 | } 104 | 105 | bool USB_EpnInGetSentStall(void) 106 | { 107 | USB_READ_BYTE(EINCSRL); 108 | return (bool)(USB0DAT & EINCSRL_STSTL__SET); 109 | } 110 | 111 | void USB_AbortInEp(uint8_t fifoNum) 112 | { 113 | USB_SetIndex(fifoNum); 114 | USB_EpnInFlush(); 115 | USB_EpnInFlush(); 116 | } 117 | 118 | bool USB_EpnOutGetSentStall(void) 119 | { 120 | USB_READ_BYTE(EOUTCSRL); 121 | return (bool)(USB0DAT & EOUTCSRL_STSTL__SET); 122 | } 123 | 124 | bool USB_EpnGetOutPacketReady(void) 125 | { 126 | USB_READ_BYTE(EOUTCSRL); 127 | return (bool)(USB0DAT & EOUTCSRL_OPRDY__SET); 128 | } 129 | 130 | uint16_t USB_EpOutGetCount(void) 131 | { 132 | return USB_GetShortRegister(EOUTCNTH); 133 | } 134 | 135 | void USB_AbortOutEp(uint8_t fifoNum) 136 | { 137 | USB_SetIndex(fifoNum); 138 | USB_EpnOutFlush(); 139 | USB_EpnOutFlush(); 140 | } 141 | 142 | void USB_ActivateEp(uint8_t ep, 143 | uint16_t packetSize, 144 | bool inDir, 145 | bool splitMode, 146 | bool isoMode) 147 | { 148 | uint8_t CSRH_mask = 0; 149 | uint16_t fifoSize; 150 | 151 | USB_SetIndex(ep); 152 | 153 | // Determine the available fifoSize for a given endpoint based on the 154 | // splitMode setting 155 | fifoSize = (splitMode == true) ? (16 << ep) : (32 << ep); 156 | 157 | if (packetSize <= fifoSize) 158 | { 159 | CSRH_mask |= EINCSRH_DBIEN__ENABLED; 160 | } 161 | 162 | if (isoMode == true) 163 | { 164 | CSRH_mask |= EINCSRH_ISO__ENABLED; 165 | } 166 | 167 | if (inDir == true) 168 | { 169 | CSRH_mask |= EINCSRH_DIRSEL__IN; 170 | 171 | if (splitMode == true) 172 | { 173 | CSRH_mask |= EINCSRH_SPLIT__ENABLED; 174 | } 175 | USB_WRITE_BYTE(EINCSRL, EINCSRL_CLRDT__BMASK); 176 | USB_WRITE_BYTE(EINCSRH, CSRH_mask); 177 | } 178 | else // OUT 179 | { 180 | USB_WRITE_BYTE(EOUTCSRL, EOUTCSRL_CLRDT__BMASK); 181 | USB_WRITE_BYTE(EOUTCSRH, CSRH_mask); 182 | 183 | if (splitMode == false) 184 | { 185 | USB_WRITE_BYTE(EINCSRH, 0); 186 | } 187 | } 188 | } 189 | 190 | uint16_t USB_GetSofNumber(void) 191 | { 192 | return USB_GetShortRegister(FRAMEH); 193 | } 194 | 195 | bool USB_GetIntsEnabled(void) 196 | { 197 | SFRPAGE = PG2_PAGE; 198 | return (bool)(EIE2 & EIE2_EUSB0__ENABLED); 199 | } 200 | 201 | bool USB_IsPrefetchEnabled(void) 202 | { 203 | SFRPAGE = PG2_PAGE; 204 | return (bool)(PFE0CN & PFE0CN_PFEN__ENABLED); 205 | } 206 | 207 | bool USB_IsRegulatorEnabled(void) 208 | { 209 | SFRPAGE = PG3_PAGE; 210 | return !(REG1CN & REG1CN_REG1ENB__DISABLED); 211 | } 212 | 213 | void USB_SuspendOscillator(void) 214 | { 215 | uint8_t clkSelSave = CLKSEL & 0x7F; 216 | 217 | CLKSEL = (CLKSEL_CLKDIV__SYSCLK_DIV_8 | CLKSEL_CLKSL__HFOSC0); 218 | SFRPAGE = LEGACY_PAGE; 219 | PCON1 |= PCON1_SUSPEND__SUSPEND; 220 | CLKSEL = clkSelSave; 221 | 222 | // If the target frequency is over 24MHz, our write to CLKSEL will be ignored. 223 | // If this is the case we need to do two writes: one to 24 MHz followed by the 224 | // actual value. 225 | if ((CLKSEL & 0x7F) != clkSelSave) 226 | { 227 | CLKSEL = (CLKSEL_CLKDIV__SYSCLK_DIV_1 | CLKSEL_CLKSL__HFOSC0); 228 | CLKSEL = clkSelSave; 229 | } 230 | } 231 | 232 | /** @} (end addtogroup usb_0_runtime USB0 Runtime API) */ 233 | -------------------------------------------------------------------------------- /firmware/inc/u2f_hid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | * 27 | * 28 | * U2F HID spec: https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-hid-protocol.html 29 | * 30 | */ 31 | 32 | #ifndef U2F_HID_H_ 33 | #define U2F_HID_H_ 34 | 35 | #include 36 | #include "descriptors.h" 37 | 38 | #define TYPE_MASK 0x80 // Frame type mask 39 | #define TYPE_INIT 0x80 // Initial frame identifier 40 | #define TYPE_CONT 0x00 // Continuation frame identifier 41 | 42 | #define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only 43 | #define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame 44 | #define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command 45 | #define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization 46 | #define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink 47 | #define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response 48 | 49 | #define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command 50 | #define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command 51 | 52 | #define ERR_NONE 0x00 // No error 53 | #define ERR_INVALID_CMD 0x01 // Invalid command 54 | #define ERR_INVALID_PAR 0x02 // Invalid parameter 55 | #define ERR_INVALID_LEN 0x03 // Invalid message length 56 | #define ERR_INVALID_SEQ 0x04 // Invalid message sequencing 57 | #define ERR_MSG_TIMEOUT 0x05 // Message has timed out 58 | #define ERR_CHANNEL_BUSY 0x06 // Channel busy 59 | #define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock 60 | #define ERR_SYNC_FAIL 0x0b // SYNC command failed 61 | #define ERR_OTHER 0x7f // Other unspecified error 62 | 63 | #define CAPABILITY_WINK 0x01 64 | #define CAPABILITY_LOCK 0x02 65 | 66 | #define U2FHID_BROADCAST 0xffffffff 67 | 68 | #define U2FHID_INIT_PAYLOAD_SIZE (HID_PACKET_SIZE-7) 69 | #define U2FHID_CONT_PAYLOAD_SIZE (HID_PACKET_SIZE-5) 70 | // 7609 = 128*U2FHID_CONT_PAYLOAD_SIZE+1*U2FHID_INIT_PAYLOAD_SIZE (128 continuation frames + 1 init frame) 71 | #define U2FHID_MAX_PAYLOAD_SIZE (7609) 72 | 73 | #define U2FHID_LEN(req) (*(uint16_t*)&req->pkt.init.bcnth) 74 | #define U2FHID_SET_LEN(req,len) (*(uint16_t*)&req->pkt.init.bcnth = (uint16_t)len) 75 | 76 | #define U2FHID_TIMEOUT_MS 5000 77 | #define U2FHID_TIMEOUT(hid) (get_ms() - (hid)->last_buffered > U2FHID_TIMEOUT_MS) 78 | 79 | struct u2f_hid_msg 80 | { 81 | uint32_t cid; 82 | union{ 83 | struct{ 84 | uint8_t cmd; 85 | uint8_t bcnth; // length high 86 | uint8_t bcntl; // length low 87 | uint8_t payload[U2FHID_INIT_PAYLOAD_SIZE]; 88 | } init; 89 | struct{ 90 | uint8_t seq; 91 | uint8_t payload[U2FHID_CONT_PAYLOAD_SIZE]; 92 | } cont; 93 | } pkt; 94 | }; 95 | 96 | struct u2f_hid_nonce 97 | { 98 | uint8_t nonce[8]; 99 | }; 100 | 101 | struct u2f_hid_init_response 102 | { 103 | // struct u2f_hid_nonce nonce; 104 | uint32_t cid; 105 | uint8_t version_id; 106 | uint8_t version_major; 107 | uint8_t version_minor; 108 | uint8_t version_build; 109 | uint8_t cflags; 110 | }; 111 | 112 | struct CID 113 | { 114 | uint32_t cid; 115 | uint32_t last_used; 116 | uint8_t busy; 117 | uint8_t last_cmd; 118 | }; 119 | 120 | typedef enum 121 | { 122 | U2FHID_REPLY=0, 123 | U2FHID_WAIT, 124 | U2FHID_INCOMPLETE, 125 | U2FHID_FAIL, 126 | } U2FHID_STATUS; 127 | 128 | 129 | void u2f_hid_init(); 130 | 131 | 132 | // set the length of the total payload to be sent 133 | // @len length of payload in bytes 134 | void u2f_hid_set_len(uint16_t len); 135 | 136 | // u2f_hid_writeback handles the sequencing and per packet buffering 137 | // @payload the buffer to write 138 | // @len length of buffer 139 | // @prereq is that hid_layer.current_cid, hid_layer.res_len each set to correct values 140 | void u2f_hid_writeback(uint8_t * payload, uint16_t len); 141 | 142 | // u2f_hid_flush flush any remaining data that may be buffered. 143 | void u2f_hid_flush(); 144 | 145 | // u2f_hid_request entry function for U2F HID protocol. 146 | // It will pass up to U2F protocol if necessary. 147 | // @param req the U2F HID message 148 | void u2f_hid_request(struct u2f_hid_msg* req); 149 | 150 | struct CID* get_cid(uint32_t cid); 151 | 152 | // set_app_error set global error value 153 | // must be implemented elsewhere for specific platform used 154 | // @ec error values defined in app.h 155 | extern void set_app_error(uint8_t ec); 156 | 157 | // Call from main loop to ensure stale channels get timeout error. 158 | void u2f_hid_check_timeouts(); 159 | void u2f_print_hid_check_timeouts(); 160 | 161 | #define U2FHID_IS_INIT(cmd) ((cmd) & 0x80) 162 | 163 | 164 | #endif /* U2F_HID_H_ */ 165 | -------------------------------------------------------------------------------- /firmware/src/descriptors.c: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // src/descriptors.c: generated by Hardware Configurator 3 | // 4 | // This file is only generated if it does not exist. Modifications in this file 5 | // will persist even if Configurator generates code. To refresh this file, 6 | // you must first delete it and then regenerate code. 7 | //============================================================================= 8 | //----------------------------------------------------------------------------- 9 | // Includes 10 | //----------------------------------------------------------------------------- 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "descriptors.h" 17 | #include "app.h" 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | // HID Report Descriptor for Interface 0 24 | SI_SEGMENT_VARIABLE(ReportDescriptor0[34], 25 | const uint8_t, 26 | SI_SEG_CODE) = 27 | { 28 | 29 | 0x06, 0xd0, 0xf1,// USAGE_PAGE (FIDO Alliance) 30 | 0x09, 0x01,// USAGE (Keyboard) 31 | 0xa1, 0x01,// COLLECTION (Application) 32 | 33 | 0x09, 0x20, // USAGE (Input Report Data) 34 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 35 | 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 36 | 0x75, 0x08, // REPORT_SIZE (8) 37 | 0x95, HID_PACKET_SIZE, // REPORT_COUNT (64) 38 | 0x81, 0x02, // INPUT (Data,Var,Abs) 39 | 0x09, 0x21, // USAGE(Output Report Data) 40 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 41 | 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 42 | 0x75, 0x08, // REPORT_SIZE (8) 43 | 0x95, HID_PACKET_SIZE, // REPORT_COUNT (64) 44 | 0x91, 0x02, // OUTPUT (Data,Var,Abs) 45 | 46 | 47 | 0xc0,// END_COLLECTION 48 | 49 | }; 50 | SI_SEGMENT_VARIABLE(deviceDesc[], 51 | const USB_DeviceDescriptor_TypeDef, 52 | SI_SEG_CODE) = 53 | { 54 | USB_DEVICE_DESCSIZE, // bLength 55 | USB_DEVICE_DESCRIPTOR,// bLength 56 | htole16(0x0200),// bcdUSB 57 | 0,// bDeviceClass 58 | 0,// bDeviceSubClass 59 | 0,// bDeviceProtocol 60 | 64,// bMaxPacketSize 61 | USB_VENDOR_ID,// idVendor 62 | USB_PRODUCT_ID,// idProduct 63 | htole16(NK_FIRMWARE_VERSION), // bcdDevice 64 | 1,// iManufacturer 65 | 2,// iProduct 66 | 3,// iSerialNumber 67 | 1,// bNumConfigurations 68 | }; 69 | 70 | SI_SEGMENT_VARIABLE(configDesc[], 71 | const uint8_t, 72 | SI_SEG_CODE) = 73 | { 74 | USB_CONFIG_DESCSIZE, // bLength 75 | USB_CONFIG_DESCRIPTOR,// bLength 76 | 0x29,// wTotalLength(LSB) 77 | 0x00,// wTotalLength(MSB) 78 | 1,// bNumInterfaces 79 | 1,// bConfigurationValue 80 | 0,// iConfiguration 81 | 82 | CONFIG_DESC_BM_RESERVED_D7,// bmAttrib: Bus powered 83 | 84 | CONFIG_DESC_MAXPOWER_mA(100),// bMaxPower: 100 mA 85 | 86 | //Interface 0 Descriptor 87 | USB_INTERFACE_DESCSIZE,// bLength 88 | USB_INTERFACE_DESCRIPTOR,// bDescriptorType 89 | 0,// bInterfaceNumber 90 | 0,// bAlternateSetting 91 | 2,// bNumEndpoints 92 | 3,// bInterfaceClass: HID (Human Interface Device) 93 | 0,// bInterfaceSubClass 94 | 0,// bInterfaceProtocol 95 | 4,// iInterface 96 | 97 | //HID Descriptor 98 | USB_HID_DESCSIZE,// bLength 99 | USB_HID_DESCRIPTOR,// bLength 100 | 0x11,// bcdHID (LSB) 101 | 0x01,// bcdHID (MSB) 102 | 0,// bCountryCode 103 | 1,// bNumDescriptors 104 | USB_HID_REPORT_DESCRIPTOR,// bDescriptorType 105 | sizeof( ReportDescriptor0 ),// wDescriptorLength(LSB) 106 | sizeof( ReportDescriptor0 )>>8,// wDescriptorLength(MSB) 107 | 108 | //Endpoint 1 IN Descriptor 109 | USB_ENDPOINT_DESCSIZE,// bLength 110 | USB_ENDPOINT_DESCRIPTOR,// bDescriptorType 111 | 0x81,// bEndpointAddress 112 | USB_EPTYPE_INTR,// bAttrib 113 | HID_PACKET_SIZE,// wMaxPacketSize (LSB) 114 | 0x00,// wMaxPacketSize (MSB) 115 | 5,// bInterval 116 | 117 | //Endpoint 1 OUT Descriptor 118 | USB_ENDPOINT_DESCSIZE,// bLength 119 | USB_ENDPOINT_DESCRIPTOR,// bDescriptorType 120 | 0x01,// bEndpointAddress 121 | USB_EPTYPE_INTR,// bAttrib 122 | HID_PACKET_SIZE,// wMaxPacketSize (LSB) 123 | 0x00,// wMaxPacketSize (MSB) 124 | 5,// bInterval 125 | }; 126 | 127 | #define LANG_STRING htole16( SLAB_USB_LANGUAGE ) 128 | 129 | #define MFR_STRING "Nitrokey" 130 | #define PROD_STRING "Nitrokey FIDO U2F" 131 | 132 | #ifdef _PRODUCTION_RELEASE 133 | 134 | #ifdef ATECC_SETUP_DEVICE 135 | #define SER_STRING "CAFEBABEFFFFFFFF" 136 | #else 137 | #define SER_STRING "0000000000000000" 138 | #endif 139 | 140 | #else //!_PRODUCTION_RELEASE 141 | 142 | #ifdef ATECC_SETUP_DEVICE 143 | #define SER_STRING "DEV-FIRM-setup-" 144 | #else 145 | #define SER_STRING "DEV-FIRM--prod--" 146 | #endif 147 | 148 | #endif //_PRODUCTION_RELEASE 149 | 150 | #define INT0_STRING "Nitrokey FIDO U2F" 151 | 152 | 153 | LANGID_STATIC_CONST_STRING_DESC( langDesc[], LANG_STRING ); 154 | UTF16LE_PACKED_STATIC_CONST_STRING_DESC( mfrDesc[], MFR_STRING, 9 ); 155 | UTF16LE_PACKED_STATIC_CONST_STRING_DESC( prodDesc[], PROD_STRING, 18 ); 156 | UTF16LE_PACKED_STATIC_CONST_STRING_DESC( serDesc[], SER_STRING, 17 ); 157 | UTF16LE_PACKED_STATIC_CONST_STRING_DESC( int0Desc[], INT0_STRING, 18 ); 158 | 159 | //----------------------------------------------------------------------------- 160 | SI_SEGMENT_POINTER(myUsbStringTable_USEnglish[], 161 | static const USB_StringDescriptor_TypeDef, 162 | const SI_SEG_XDATA) = 163 | { 164 | langDesc, 165 | mfrDesc, 166 | prodDesc, 167 | serDesc, 168 | int0Desc, 169 | 170 | }; 171 | 172 | //----------------------------------------------------------------------------- 173 | SI_SEGMENT_VARIABLE(initstruct, 174 | const USBD_Init_TypeDef, 175 | SI_SEG_XDATA) = 176 | { 177 | deviceDesc, // deviceDescriptor 178 | configDesc,// configDescriptor 179 | myUsbStringTable_USEnglish,// stringDescriptors 180 | sizeof(myUsbStringTable_USEnglish) / sizeof(void *)// numberOfStrings 181 | }; 182 | 183 | #ifdef __cplusplus 184 | } 185 | #endif 186 | 187 | -------------------------------------------------------------------------------- /firmware/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | * 27 | * main.c 28 | * This file contains the main loop of the application. 29 | * It listens for messages on USB and upon receiving a message, 30 | * it will pass it up to the U2F HID layer, implemented in u2f_hid.c. 31 | * 32 | */ 33 | #include "configuration.h" 34 | #include 35 | #include 36 | 37 | #include "InitDevice.h" 38 | #include "app.h" 39 | #include "i2c.h" 40 | #include "gpio.h" 41 | #include "atecc508a.h" 42 | #include "eeprom.h" 43 | #include "bsp.h" 44 | #include "custom.h" 45 | #include "u2f.h" 46 | #include "tests.h" 47 | #include "sanity-check.h" 48 | 49 | data struct APP_DATA appdata; 50 | 51 | uint8_t error; 52 | uint8_t state; 53 | 54 | 55 | struct u2f_hid_msg * hid_msg; 56 | 57 | 58 | static void init(struct APP_DATA* ap) 59 | { 60 | 61 | u2f_hid_init(); 62 | smb_init(); 63 | atecc_idle(); 64 | #ifdef _SECURE_EEPROM 65 | eeprom_init(); 66 | #endif 67 | 68 | state = APP_NOTHING; 69 | error = ERROR_NOTHING; 70 | } 71 | 72 | void set_app_error(APP_ERROR_CODE ec) 73 | { 74 | error = ec; 75 | } 76 | 77 | uint8_t get_app_error() 78 | { 79 | return error; 80 | } 81 | 82 | uint8_t get_app_state() 83 | { 84 | return state; 85 | } 86 | 87 | 88 | void set_app_u2f_hid_msg(struct u2f_hid_msg * msg ) 89 | { 90 | state = APP_HID_MSG; 91 | hid_msg = msg; 92 | } 93 | 94 | 95 | int16_t main(void) { 96 | data uint8_t xdata * clear = 0; 97 | uint16_t i; 98 | 99 | configuration_read(); 100 | // initialize USB 101 | update_USB_serial(); 102 | enter_DefaultMode_from_RESET(); 103 | 104 | // ~800 ms interval watchdog 105 | WDTCN = 5; 106 | 107 | watchdog(); 108 | init(&appdata); 109 | 110 | atecc_sleep(); 111 | 112 | #ifdef DISABLE_WATCHDOG 113 | IE_EA = 0; 114 | WDTCN = 0xDE; 115 | WDTCN = 0xAD; 116 | #endif 117 | // Enable interrupts 118 | IE_EA = 1; 119 | watchdog(); 120 | 121 | get_serial_num(); 122 | 123 | if (RSTSRC & RSTSRC_WDTRSF__SET) 124 | { 125 | u2f_prints("r"); 126 | } 127 | u2f_prints("U2F ZERO ==================================\r\n"); 128 | 129 | #ifndef _PRODUCTION_RELEASE 130 | run_tests(); 131 | #endif 132 | BUTTON_RESET_OFF(); 133 | led_off(); 134 | 135 | sanity_check(NULL); 136 | 137 | if (sanity_check_passed) 138 | led_blink(1, 0); // Blink once after successful startup 139 | else{ 140 | led_blink(LED_BLINK_NUM_INF, 200); // blink error 141 | led_change_ON_time(100); 142 | } 143 | 144 | while (1) { 145 | watchdog(); 146 | 147 | clear_button_press(); 148 | button_manager(); 149 | led_blink_manager(); 150 | #ifdef __BUTTON_TEST__ 151 | // if (!LedBlinkNum) { 152 | if (button_get_press()) { led_on(); } 153 | else { led_off(); } 154 | // } 155 | #endif 156 | 157 | if (!USBD_EpIsBusy(EP1OUT) && !USBD_EpIsBusy(EP1IN) && state != APP_HID_MSG) 158 | { 159 | if (USBD_Read(EP1OUT, hidmsgbuf, sizeof(hidmsgbuf), true) != USB_STATUS_OK){ 160 | set_app_error(ERROR_USB_WRITE); 161 | } 162 | } 163 | 164 | u2f_hid_check_timeouts(); 165 | 166 | switch(state) { 167 | case APP_NOTHING: {}break; // Idle state: 168 | 169 | case APP_HID_MSG: { // HID msg received, pass to protocols: 170 | #ifndef ATECC_SETUP_DEVICE 171 | struct CID* cid = NULL; 172 | cid = get_cid(hid_msg->cid); 173 | if (cid == NULL || !cid->busy) { // There is no ongoing U2FHID transfer 174 | if (!custom_command(hid_msg)) { 175 | u2f_hid_request(hid_msg); 176 | } 177 | } else { 178 | u2f_hid_request(hid_msg); 179 | } 180 | #else //!ATECC_SETUP_DEVICE 181 | if (!custom_command(hid_msg)) { 182 | u2f_hid_request(hid_msg); 183 | } 184 | #endif //ATECC_SETUP_DEVICE 185 | if (state == APP_HID_MSG) { // The USB msg doesnt ask a special app state 186 | state = APP_NOTHING; // We can go back to idle 187 | } 188 | }break; 189 | } 190 | 191 | watchdog(); 192 | if(atecc_used){ 193 | atecc_sleep(); 194 | atecc_used = 0; 195 | } 196 | 197 | if (error) 198 | { 199 | u2f_printx("error: ", 1, (uint16_t)error); 200 | 201 | clear = 0; 202 | for (i=0; i<2048; i++) // wipe ram 203 | { 204 | if (clear == &i) 205 | continue; 206 | *(clear++) = 0; 207 | } 208 | 209 | #ifdef ON_ERROR_RESET_IMMEDIATELY 210 | u2f_delay(100); 211 | RSTSRC = RSTSRC_SWRSF__SET | RSTSRC_PORSF__SET; 212 | #endif 213 | 214 | #ifdef U2F_BLINK_ERRORS 215 | LedBlink(LED_BLINK_NUM_INF, 50); 216 | // wait for watchdog to reset 217 | while(1) 218 | { 219 | led_blink_manager(); 220 | } 221 | 222 | #else //!U2F_BLINK_ERRORS 223 | // wait for watchdog to reset 224 | while(1) 225 | ; 226 | #endif //U2F_BLINK_ERRORS 227 | 228 | } 229 | } 230 | } 231 | 232 | -------------------------------------------------------------------------------- /firmware/src/custom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | * 27 | * 28 | * These are commands are "middleware" for HID messages. So they don't need 29 | * the HID U2F layer to be called. Thus they are custom commands not necessary for U2F. 30 | * 31 | */ 32 | 33 | #include 34 | #include "custom.h" 35 | #include "bsp.h" 36 | #include "gpio.h" 37 | #include "atecc508a.h" 38 | #include "eeprom.h" 39 | #include "u2f.h" 40 | #include "configuration.h" 41 | #include "sanity-check.h" 42 | #include "version.h" 43 | 44 | #define _MIN(a,b) ((a)<=(b))? (a):(b) 45 | 46 | uint8_t custom_command(struct u2f_hid_msg * msg) 47 | { 48 | struct atecc_response res; 49 | uint8_t ec; 50 | uint8_t *out = msg->pkt.init.payload; 51 | 52 | switch(msg->pkt.init.cmd) 53 | { 54 | #ifdef FEAT_SANITY_CHECK 55 | case U2F_SANITY_CHECK: 56 | memset(out, 0xEE, sizeof(msg->pkt.init.payload)); 57 | 58 | out[0] = sanity_check_passed; 59 | out[1] = *((uint8_t*) &sanity_check_info); 60 | 61 | U2FHID_SET_LEN(msg, sizeof(msg->pkt.init.payload)); 62 | usb_write((uint8_t*)msg, 64); 63 | break; 64 | #endif //FEAT_SANITY_CHECK 65 | 66 | case U2F_CUSTOM_STATUS: 67 | memset(out, 0xEE, sizeof(msg->pkt.init.payload)); 68 | out[0] = IS_BUTTON_PRESSED(); 69 | out[1] = button_get_press_state(); 70 | out[2] = last_button_cleared_time_delta(); 71 | out[3] = last_button_pushed_time_delta(); 72 | out[4] = led_is_blinking(); 73 | out[5] = U2F_MS_CLEAR_BUTTON_PERIOD / 100; 74 | out[6] = U2F_MS_INIT_BUTTON_PERIOD / 100; 75 | out[7] = BUTTON_MIN_PRESS_T_MS / 10; 76 | out[8] = _MIN(30, GIT_DESCRIPTION_SIZE); 77 | memcpy(out+9, GIT_DESCRIPTION, _MIN(30, GIT_DESCRIPTION_SIZE)); 78 | 79 | U2FHID_SET_LEN(msg, sizeof(msg->pkt.init.payload)); 80 | usb_write((uint8_t*)msg, 64); 81 | break; 82 | 83 | case U2F_CUSTOM_UPDATE_CONFIG: 84 | if(u2f_get_user_feedback_extended_wipe()){ 85 | memset(out, 0xEE, sizeof(msg->pkt.init.payload)); 86 | out[0] = 0; 87 | U2FHID_SET_LEN(msg, sizeof(msg->pkt.init.payload)); 88 | usb_write((uint8_t*)msg, 64); 89 | break; 90 | } 91 | 92 | eeprom_erase(EEPROM_DATA_CONFIG); 93 | eeprom_write(EEPROM_DATA_CONFIG, msg->pkt.init.payload, sizeof(Configuration)); 94 | configuration_read(); 95 | memset(out, 0xEE, sizeof(msg->pkt.init.payload)); 96 | #ifndef _PRODUCTION_RELEASE 97 | eeprom_read(EEPROM_DATA_CONFIG, out+2, sizeof(Configuration)); 98 | #endif 99 | out[0] = 1; 100 | U2FHID_SET_LEN(msg, sizeof(msg->pkt.init.payload)); 101 | usb_write((uint8_t*)msg, 64); 102 | u2f_delay(100); 103 | RSTSRC = RSTSRC_SWRSF__SET | RSTSRC_PORSF__SET; 104 | break; 105 | 106 | #ifdef FEAT_FACTORY_RESET 107 | case U2F_CUSTOM_FACTORY_RESET: 108 | memset(out, 0xEE, sizeof(msg->pkt.init.payload)); 109 | 110 | if(u2f_get_user_feedback_extended_wipe()){ 111 | U2FHID_SET_LEN(msg, sizeof(msg->pkt.init.payload)); 112 | usb_write((uint8_t*)msg, 64); 113 | break; 114 | } 115 | 116 | // clear device key explicitly 117 | memset(device_configuration.RMASK, 0, sizeof(device_configuration.RMASK)); 118 | memset(device_configuration.WMASK, 0, sizeof(device_configuration.WMASK)); 119 | eeprom_erase(EEPROM_DATA_WMASK); 120 | eeprom_erase(EEPROM_DATA_RMASK); 121 | eeprom_erase(EEPROM_DATA_U2F_CONST); 122 | eeprom_erase(EEPROM_DATA_CONFIG); 123 | 124 | #ifndef _PRODUCTION_RELEASE 125 | eeprom_read(EEPROM_DATA_WMASK, out+3+8+8+8+8+8, 4); 126 | eeprom_read(EEPROM_DATA_RMASK, out+3+8+8+8+8+8+4, 4); 127 | #endif //#ifndef _PRODUCTION_RELEASE 128 | out[0] = generate_WMASK(appdata.tmp, sizeof(appdata.tmp)); 129 | out[1] = generate_RMASK(appdata.tmp, sizeof(appdata.tmp)); 130 | out[2] = generate_device_key(NULL, appdata.tmp, sizeof(appdata.tmp)); 131 | #ifndef _PRODUCTION_RELEASE 132 | memmove(out+3, device_configuration.WMASK, 8); 133 | memmove(out+3+8, device_configuration.RMASK, 8); 134 | eeprom_read(EEPROM_DATA_U2F_CONST, out+3+8+8, 8); 135 | eeprom_read(EEPROM_DATA_WMASK, out+3+8+8+8, 8); 136 | eeprom_read(EEPROM_DATA_RMASK, out+3+8+8+8+8, 8); 137 | #endif //#ifndef _PRODUCTION_RELEASE 138 | 139 | U2FHID_SET_LEN(msg, sizeof(msg->pkt.init.payload)); 140 | usb_write((uint8_t*)msg, 64); 141 | break; 142 | #endif // #ifdef FEAT_FACTORY_RESET 143 | 144 | #ifdef U2F_SUPPORT_RNG_CUSTOM 145 | case U2F_CUSTOM_GET_RNG: 146 | if (atecc_send_recv(ATECC_CMD_RNG,ATECC_RNG_P1,ATECC_RNG_P2, 147 | NULL, 0, 148 | appdata.tmp, 149 | sizeof(appdata.tmp), &res) == 0 ) 150 | { 151 | memmove(msg->pkt.init.payload, res.buf, 32); 152 | U2FHID_SET_LEN(msg, 32); 153 | usb_write((uint8_t*)msg, 64); 154 | } 155 | else 156 | { 157 | U2FHID_SET_LEN(msg, 0); 158 | usb_write((uint8_t*)msg, 64); 159 | } 160 | 161 | break; 162 | #endif //#ifdef U2F_SUPPORT_RNG_CUSTOM 163 | #ifdef U2F_SUPPORT_WINK 164 | case U2F_CUSTOM_WINK: 165 | if(led_is_blinking() == false) 166 | led_blink(5, LED_BLINK_PERIOD); 167 | break; 168 | #endif //#ifdef U2F_SUPPORT_WINK 169 | default: 170 | return 0; 171 | } 172 | return 1; 173 | } 174 | -------------------------------------------------------------------------------- /firmware/inc/app.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | 28 | #ifndef APP_H_ 29 | #define APP_H_ 30 | 31 | #include 32 | #include "u2f_hid.h" 33 | 34 | // hw settings 35 | #define BUTTON_MIN_PRESS_T_MS 500 36 | #define BUTTON_MIN_PRESS_T_MS_EXT (10*1000) 37 | #define BUTTON_MAX_PRESS_T_MS (3*1000) 38 | 39 | // set time after the power on, during which a single U2F or configuration 40 | // request would be accepted 41 | #define SELF_ACCEPT_MAX_T_MS (2*1000) 42 | 43 | #define LED_BLINK_T_ON (LED_BLINK_PERIOD/2) // ms 44 | #define LED_BLINK_T_OFF (led_blink_period_t - led_blink_ON_t) // ms 45 | #define LED_BLINK_PERIOD (780) // ms 46 | #define LED_BLINK_NUM_INF 255 47 | 48 | // application settings 49 | #define U2F_ATTESTATION_KEY_SLOT 15 50 | #define U2F_MASTER_KEY_SLOT 1 51 | #define U2F_TEMP_KEY_SLOT 2 52 | #define U2F_WKEY_KEY_SLOT 1 53 | #define U2F_DEVICE_KEY_SLOT 5 54 | 55 | // this a BCD, e.g. version 12.34 -> 0x1234 56 | #define NK_FIRMWARE_VERSION 0x0100 57 | 58 | #define U2F_SUPPORT_WINK 59 | #define U2F_SUPPORT_HID_LOCK 60 | #define U2F_SUPPORT_RNG_CUSTOM 61 | 62 | #define SHOW_TOUCH_REGISTERED 63 | 64 | //#define DISABLE_WATCHDOG 65 | //#define FAKE_TOUCH 66 | //#define DEBUG_GATHER_ATECC_ERRORS 67 | 68 | #define FEAT_FACTORY_RESET 69 | #define FEAT_SANITY_CHECK 70 | 71 | // Uncomment this to make configuration firmware (stage 1 firmware) 72 | #define ATECC_SETUP_DEVICE 73 | 74 | // Uncomment to make a production firmware release, with selected flags 75 | //#define _PRODUCTION_RELEASE 76 | 77 | // Touch button test function 78 | //#define __BUTTON_TEST__ // Button drives directly the LED. Minimal required press time is determined by BUTTON_MIN_PRESS_T_MS 79 | 80 | //#define U2F_PRINT 81 | //#define U2F_BLINK_ERRORS 82 | 83 | #ifdef _PRODUCTION_RELEASE 84 | #undef DEBUG_GATHER_ATECC_ERRORS 85 | #undef FAKE_TOUCH 86 | #undef SHOW_TOUCH_REGISTERED 87 | #undef DISABLE_WATCHDOG 88 | #undef U2F_PRINT 89 | #undef U2F_BLINK_ERRORS 90 | #undef __BUTTON_TEST__ 91 | #undef U2F_USING_BOOTLOADER 92 | #ifndef FEAT_FACTORY_RESET 93 | #define FEAT_FACTORY_RESET 94 | #endif 95 | #ifndef FEAT_SANITY_CHECK 96 | #define FEAT_SANITY_CHECK 97 | #endif 98 | #ifndef ATECC_SETUP_DEVICE 99 | #define _SECURE_EEPROM 100 | #endif 101 | #endif 102 | 103 | 104 | typedef enum 105 | { 106 | APP_NOTHING = 0, 107 | APP_HID_MSG, 108 | APP_WINK, 109 | _APP_WINK, 110 | } 111 | APP_STATE; 112 | 113 | 114 | typedef enum 115 | { 116 | ERROR_NOTHING = 0, 117 | ERROR_I2C_ERRORS_EXCEEDED = 2, 118 | ERROR_READ_TRUNCATED = 6, 119 | ERROR_ATECC_VERIFY = 0x01, 120 | ERROR_ATECC_PARSE = 0x03, 121 | ERROR_ATECC_FAULT = 0x05, 122 | ERROR_ATECC_EXECUTION = 0x0f, 123 | ERROR_ATECC_WAKE = 0x11, 124 | ERROR_ATECC_WATCHDOG = 0xee, 125 | ERROR_ATECC_CRC = 0xff, 126 | ERROR_I2C_CRC = 0x15, 127 | ERROR_SEQ_EXCEEDED = 0x12, 128 | ERROR_BAD_KEY_STORE = 0x13, 129 | ERROR_USB_WRITE = 0x14, 130 | ERROR_I2C_BAD_LEN = 0x16, 131 | ERROR_HID_BUFFER_FULL = 0x17, 132 | ERROR_HID_INVALID_CMD = 0x18, 133 | ERROR_DAMN_WATCHDOG = 0x19, 134 | ERROR_OUT_OF_CIDS = 0x20, 135 | ERROR_I2C_RESTART = 0x21, 136 | } 137 | APP_ERROR_CODE; 138 | 139 | struct APP_DATA 140 | { 141 | // must be at least 70 bytes 142 | uint8_t tmp[70]; 143 | }; 144 | 145 | #define U2F_CONFIG_GET_SERIAL_NUM 0x80 146 | #define U2F_CONFIG_IS_BUILD 0x81 147 | #define U2F_CONFIG_IS_CONFIGURED 0x82 148 | #define U2F_CONFIG_LOCK 0x83 149 | //#define U2F_CONFIG_GENKEY 0x84 150 | #define U2F_CONFIG_LOAD_TRANS_KEY 0x85 151 | #define U2F_CONFIG_LOAD_WRITE_KEY 0x86 152 | #define U2F_CONFIG_LOAD_ATTEST_KEY 0x87 153 | #define U2F_CONFIG_BOOTLOADER 0x88 154 | #define U2F_CONFIG_BOOTLOADER_DESTROY 0x89 155 | #define U2F_CONFIG_ATECC_PASSTHROUGH 0x8a 156 | #define U2F_CONFIG_LOAD_RMASK_KEY 0x8b 157 | #define U2F_CONFIG_GEN_DEVICE_KEY 0x8c 158 | #define U2F_CONFIG_GET_SLOTS_FINGERPRINTS 0x8d 159 | #define U2F_CONFIG_TEST_CONFIG 0x8e 160 | #define U2F_CONFIG_GET_CONSTANTS 0x8f 161 | 162 | struct config_msg 163 | { 164 | uint8_t cmd; 165 | uint8_t buf[HID_PACKET_SIZE-1]; 166 | }; 167 | 168 | extern uint8_t hidmsgbuf[64]; 169 | extern data struct APP_DATA appdata; 170 | 171 | void set_app_u2f_hid_msg(struct u2f_hid_msg * msg ); 172 | 173 | void set_app_error(APP_ERROR_CODE ec); 174 | 175 | uint8_t get_app_error(); 176 | 177 | uint8_t get_app_state(); 178 | 179 | void set_app_state(APP_STATE s); 180 | 181 | 182 | 183 | #ifdef ATECC_SETUP_DEVICE 184 | 185 | #include "atecc508a.h" 186 | 187 | void atecc_setup_device(struct config_msg * msg); 188 | 189 | 190 | void u2f_config_request(); 191 | 192 | #define U2F_HID_DISABLE 193 | #define U2F_DISABLE 194 | #define u2f_hid_init(x) 195 | #define u2f_hid_request(x) atecc_setup_device((struct config_msg*)x) 196 | #define u2f_hid_set_len(x) 197 | #define u2f_hid_flush(x) 198 | #define u2f_hid_writeback(x) 199 | #define u2f_hid_check_timeouts(x) 200 | 201 | #else 202 | 203 | #define atecc_setup_device(x) 204 | #endif 205 | 206 | 207 | #endif /* APP_H_ */ 208 | -------------------------------------------------------------------------------- /firmware/inc/config/usbconfig.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * @file usbconfig.h 3 | * @brief USB protocol stack library, application supplied configuration options. 4 | *******************************************************************************/ 5 | 6 | //============================================================================= 7 | // inc/config/usbconfig.h: generated by Hardware Configurator 8 | // 9 | // This file will be regenerated when saving a document. leave the sections 10 | // inside the "$[...]" comment tags alone or they will be overwritten! 11 | //============================================================================= 12 | #ifndef __SILICON_LABS_USBCONFIG_H 13 | #define __SILICON_LABS_USBCONFIG_H 14 | 15 | // ----------------------------------------------------------------------------- 16 | // Specify bus- or self-powered 17 | // ----------------------------------------------------------------------------- 18 | // $[Device Power] 19 | #define SLAB_USB_BUS_POWERED 1 20 | // [Device Power]$ 21 | 22 | // ----------------------------------------------------------------------------- 23 | // Specify USB speed 24 | // ----------------------------------------------------------------------------- 25 | // $[USB Speed] 26 | #define SLAB_USB_FULL_SPEED 1 27 | // [USB Speed]$ 28 | 29 | // ----------------------------------------------------------------------------- 30 | // Enable or disable the clock recovery 31 | // ----------------------------------------------------------------------------- 32 | // $[Clock Recovery] 33 | #define SLAB_USB_CLOCK_RECOVERY_ENABLED 1 34 | // [Clock Recovery]$ 35 | 36 | // ----------------------------------------------------------------------------- 37 | // Enable or disable remote wakeup 38 | // ----------------------------------------------------------------------------- 39 | // $[Remote Wake-up] 40 | #define SLAB_USB_REMOTE_WAKEUP_ENABLED 0 41 | // [Remote Wake-up]$ 42 | 43 | // ----------------------------------------------------------------------------- 44 | // Specify number of interfaces and whether any interfaces support alternate 45 | // settings 46 | // ----------------------------------------------------------------------------- 47 | // $[Number of Interfaces] 48 | #define SLAB_USB_NUM_INTERFACES 1 49 | #define SLAB_USB_SUPPORT_ALT_INTERFACES 0 50 | // [Number of Interfaces]$ 51 | 52 | // ----------------------------------------------------------------------------- 53 | // Enable or disable each endpoint 54 | // ----------------------------------------------------------------------------- 55 | // $[Endpoints Used] 56 | #define SLAB_USB_EP1IN_USED 1 57 | #define SLAB_USB_EP1OUT_USED 1 58 | #define SLAB_USB_EP2IN_USED 0 59 | #define SLAB_USB_EP2OUT_USED 0 60 | #define SLAB_USB_EP3IN_USED 0 61 | #define SLAB_USB_EP3OUT_USED 0 62 | // [Endpoints Used]$ 63 | 64 | // ----------------------------------------------------------------------------- 65 | // Specify maximum packet size for each endpoint 66 | // ----------------------------------------------------------------------------- 67 | // $[Endpoint Max Packet Size] 68 | #define SLAB_USB_EP1IN_MAX_PACKET_SIZE 64 69 | #define SLAB_USB_EP1OUT_MAX_PACKET_SIZE 64 70 | #define SLAB_USB_EP2IN_MAX_PACKET_SIZE 1 71 | #define SLAB_USB_EP2OUT_MAX_PACKET_SIZE 1 72 | #define SLAB_USB_EP3IN_MAX_PACKET_SIZE 1 73 | #define SLAB_USB_EP3OUT_MAX_PACKET_SIZE 1 74 | // [Endpoint Max Packet Size]$ 75 | 76 | // ----------------------------------------------------------------------------- 77 | // Specify transfer type of each endpoint 78 | // ----------------------------------------------------------------------------- 79 | // $[Endpoint Transfer Type] 80 | #define SLAB_USB_EP1IN_TRANSFER_TYPE USB_EPTYPE_INTR 81 | #define SLAB_USB_EP1OUT_TRANSFER_TYPE USB_EPTYPE_INTR 82 | #define SLAB_USB_EP2IN_TRANSFER_TYPE USB_EPTYPE_BULK 83 | #define SLAB_USB_EP2OUT_TRANSFER_TYPE USB_EPTYPE_BULK 84 | #define SLAB_USB_EP3IN_TRANSFER_TYPE USB_EPTYPE_ISOC 85 | #define SLAB_USB_EP3OUT_TRANSFER_TYPE USB_EPTYPE_ISOC 86 | // [Endpoint Transfer Type]$ 87 | 88 | // ----------------------------------------------------------------------------- 89 | // Enable or disable callback functions 90 | // ----------------------------------------------------------------------------- 91 | // $[Callback Functions] 92 | #define SLAB_USB_HANDLER_CB 0 93 | #define SLAB_USB_IS_SELF_POWERED_CB 1 94 | #define SLAB_USB_RESET_CB 1 95 | #define SLAB_USB_SETUP_CMD_CB 1 96 | #define SLAB_USB_SOF_CB 0 97 | #define SLAB_USB_STATE_CHANGE_CB 1 98 | // [Callback Functions]$ 99 | 100 | // ----------------------------------------------------------------------------- 101 | // Specify number of languages supported by string descriptors. 102 | // ----------------------------------------------------------------------------- 103 | // $[Number of Languages] 104 | #define SLAB_USB_NUM_LANGUAGES 1 105 | // [Number of Languages]$ 106 | 107 | // ----------------------------------------------------------------------------- 108 | // If only one descriptor language is supported, specify that language here. 109 | // If multiple descriptor languages are supported, this value is ignored and 110 | // the supported languages must listed in the 111 | // myUsbStringTableLanguageIDsDescriptor structure. 112 | // ----------------------------------------------------------------------------- 113 | // $[USB Language] 114 | #define SLAB_USB_LANGUAGE USB_LANGID_ENUS 115 | // [USB Language]$ 116 | 117 | // ----------------------------------------------------------------------------- 118 | // 119 | // Set the power saving mode 120 | // 121 | // SLAB_USB_PWRSAVE_MODE configures when the device will automatically enter 122 | // the USB power-save mode. It is a bitmask constant with bit values: 123 | // USB_PWRSAVE_MODE_OFF - No energy saving mode selected 124 | // USB_PWRSAVE_MODE_ONSUSPEND - Enter USB power-save mode on USB suspend 125 | // USB_PWRSAVE_MODE_ONVBUSOFF - Enter USB power-save mode when not attached 126 | // to the USB host. 127 | // USB_PWRSAVE_MODE_FASTWAKE - Exit USB power-save mode more quickly. 128 | // This is useful for some applications that 129 | // support remote wakeup. 130 | // 131 | // ----------------------------------------------------------------------------- 132 | // $[Power Save Mode] 133 | #define SLAB_USB_PWRSAVE_MODE USB_PWRSAVE_MODE_OFF 134 | // [Power Save Mode]$ 135 | 136 | // ----------------------------------------------------------------------------- 137 | // Enable or disable polled mode 138 | // 139 | // When enabled, the application must call USBD_Run() periodically to process 140 | // USB events. 141 | // When disabled, USB events will be handled automatically by an interrupt 142 | // handler. 143 | // ----------------------------------------------------------------------------- 144 | // $[Polled Mode] 145 | #define SLAB_USB_POLLED_MODE 0 146 | // [Polled Mode]$ 147 | 148 | #endif // __SILICON_LABS_USBCONFIG_H 149 | -------------------------------------------------------------------------------- /firmware/src/SILABS_STARTUP.A51: -------------------------------------------------------------------------------- 1 | $NOMOD51 2 | ;------------------------------------------------------------------------------ 3 | ; This file is part of the C51 Compiler package 4 | ; Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc. 5 | ; Version 8.01 6 | ; 7 | ; *** <<< Use Configuration Wizard in Context Menu >>> *** 8 | ;------------------------------------------------------------------------------ 9 | ; STARTUP.A51: This code is executed after processor reset. 10 | ; 11 | ; To translate this file use A51 with the following invocation: 12 | ; 13 | ; A51 STARTUP.A51 14 | ; 15 | ; To link the modified STARTUP.OBJ file to your application use the following 16 | ; Lx51 invocation: 17 | ; 18 | ; Lx51 your object file list, STARTUP.OBJ controls 19 | ; 20 | ;------------------------------------------------------------------------------ 21 | ; 22 | ; User-defined Power-On Initialization of Memory 23 | ; 24 | ; With the following EQU statements the initialization of memory 25 | ; at processor reset can be defined: 26 | ; 27 | ; IDATALEN: IDATA memory size <0x0-0x100> 28 | ; Note: The absolute start-address of IDATA memory is always 0 29 | ; The IDATA space overlaps physically the DATA and BIT areas. 30 | IDATALEN EQU 80H 31 | ; 32 | ; XDATASTART: XDATA memory start address <0x0-0xFFFF> 33 | ; The absolute start address of XDATA memory 34 | XDATASTART EQU 0 35 | ; 36 | ; XDATALEN: XDATA memory size <0x0-0xFFFF> 37 | ; The length of XDATA memory in bytes. 38 | XDATALEN EQU 0 39 | ; 40 | ; PDATASTART: PDATA memory start address <0x0-0xFFFF> 41 | ; The absolute start address of PDATA memory 42 | PDATASTART EQU 0H 43 | ; 44 | ; PDATALEN: PDATA memory size <0x0-0xFF> 45 | ; The length of PDATA memory in bytes. 46 | PDATALEN EQU 0H 47 | ; 48 | ; 49 | ;------------------------------------------------------------------------------ 50 | ; 51 | ; Reentrant Stack Initialization 52 | ; 53 | ; The following EQU statements define the stack pointer for reentrant 54 | ; functions and initialized it: 55 | ; 56 | ; Stack Space for reentrant functions in the SMALL model. 57 | ; IBPSTACK: Enable SMALL model reentrant stack 58 | ; Stack space for reentrant functions in the SMALL model. 59 | IBPSTACK EQU 0 ; set to 1 if small reentrant is used. 60 | ; IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF> 61 | ; Set the top of the stack to the highest location. 62 | IBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1 63 | ; 64 | ; 65 | ; Stack Space for reentrant functions in the LARGE model. 66 | ; XBPSTACK: Enable LARGE model reentrant stack 67 | ; Stack space for reentrant functions in the LARGE model. 68 | XBPSTACK EQU 0 ; set to 1 if large reentrant is used. 69 | ; XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF> 70 | ; Set the top of the stack to the highest location. 71 | XBPSTACKTOP EQU 0xFFFF +1 ; default 0FFFFH+1 72 | ; 73 | ; 74 | ; Stack Space for reentrant functions in the COMPACT model. 75 | ; PBPSTACK: Enable COMPACT model reentrant stack 76 | ; Stack space for reentrant functions in the COMPACT model. 77 | PBPSTACK EQU 0 ; set to 1 if compact reentrant is used. 78 | ; 79 | ; PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF> 80 | ; Set the top of the stack to the highest location. 81 | PBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1 82 | ; 83 | ; 84 | ;------------------------------------------------------------------------------ 85 | ; 86 | ; Memory Page for Using the Compact Model with 64 KByte xdata RAM 87 | ; Compact Model Page Definition 88 | ; 89 | ; Define the XDATA page used for PDATA variables. 90 | ; PPAGE must conform with the PPAGE set in the linker invocation. 91 | ; 92 | ; Enable pdata memory page initalization 93 | PPAGEENABLE EQU 0 ; set to 1 if pdata object are used. 94 | ; 95 | ; PPAGE number <0x0-0xFF> 96 | ; uppermost 256-byte address of the page used for PDATA variables. 97 | PPAGE EQU 0 98 | ; 99 | ; SFR address which supplies uppermost address byte <0x0-0xFF> 100 | ; most 8051 variants use P2 as uppermost address byte 101 | PPAGE_SFR DATA 0A0H 102 | ; 103 | ; 104 | ;------------------------------------------------------------------------------ 105 | 106 | ; Standard SFR Symbols 107 | ACC DATA 0E0H 108 | B DATA 0F0H 109 | SP DATA 81H 110 | DPL DATA 82H 111 | DPH DATA 83H 112 | 113 | NAME ?C_STARTUP 114 | 115 | 116 | ?C_C51STARTUP SEGMENT CODE 117 | ?STACK SEGMENT IDATA 118 | 119 | RSEG ?STACK 120 | DS 1 121 | 122 | EXTRN CODE (?C_START) 123 | PUBLIC ?C_STARTUP 124 | 125 | CSEG AT 0 126 | ?C_STARTUP: LJMP STARTUP1 127 | 128 | RSEG ?C_C51STARTUP 129 | 130 | STARTUP1: 131 | 132 | $IF (SILABS_STARTUP = 1) 133 | EXTRN CODE (SiLabs_Startup) 134 | LCALL SiLabs_Startup 135 | $ENDIF 136 | 137 | IF IDATALEN <> 0 138 | MOV R0,#IDATALEN - 1 139 | CLR A 140 | IDATALOOP: MOV @R0,A 141 | DJNZ R0,IDATALOOP 142 | ENDIF 143 | 144 | IF XDATALEN <> 0 145 | MOV DPTR,#XDATASTART 146 | MOV R7,#LOW (XDATALEN) 147 | IF (LOW (XDATALEN)) <> 0 148 | MOV R6,#(HIGH (XDATALEN)) +1 149 | ELSE 150 | MOV R6,#HIGH (XDATALEN) 151 | ENDIF 152 | CLR A 153 | XDATALOOP: MOVX @DPTR,A 154 | INC DPTR 155 | DJNZ R7,XDATALOOP 156 | DJNZ R6,XDATALOOP 157 | ENDIF 158 | 159 | IF PPAGEENABLE <> 0 160 | MOV PPAGE_SFR,#PPAGE 161 | ENDIF 162 | 163 | IF PDATALEN <> 0 164 | MOV R0,#LOW (PDATASTART) 165 | MOV R7,#LOW (PDATALEN) 166 | CLR A 167 | PDATALOOP: MOVX @R0,A 168 | INC R0 169 | DJNZ R7,PDATALOOP 170 | ENDIF 171 | 172 | IF IBPSTACK <> 0 173 | EXTRN DATA (?C_IBP) 174 | 175 | MOV ?C_IBP,#LOW IBPSTACKTOP 176 | ENDIF 177 | 178 | IF XBPSTACK <> 0 179 | EXTRN DATA (?C_XBP) 180 | 181 | MOV ?C_XBP,#HIGH XBPSTACKTOP 182 | MOV ?C_XBP+1,#LOW XBPSTACKTOP 183 | ENDIF 184 | 185 | IF PBPSTACK <> 0 186 | EXTRN DATA (?C_PBP) 187 | MOV ?C_PBP,#LOW PBPSTACKTOP 188 | ENDIF 189 | 190 | MOV SP,#?STACK-1 191 | 192 | ; This code is required if you use L51_BANK.A51 with Banking Mode 4 193 | ; Code Banking 194 | ; Select Bank 0 for L51_BANK.A51 Mode 4 195 | $IF (USE_BANKING = 1) 196 | ; Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4. 197 | EXTRN CODE (?B_SWITCH0) 198 | CALL ?B_SWITCH0 ; init bank mechanism to code bank 0 199 | $ENDIF 200 | ; 201 | LJMP ?C_START 202 | 203 | END 204 | -------------------------------------------------------------------------------- /firmware/inc/atecc508a.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | */ 27 | 28 | #ifndef ATECC508A_H_ 29 | #define ATECC508A_H_ 30 | 31 | #define ATECC508A_ADDR 0xc0 32 | 33 | #define ATECC_CMD_COUNTER 0x24 34 | // P1 35 | #define ATECC_COUNTER_READ 0 36 | #define ATECC_COUNTER_INC 1 37 | // P2 38 | #define ATECC_COUNTER0 0 39 | #define ATECC_COUNTER1 1 40 | 41 | 42 | #define ATECC_CMD_RNG 0x1B 43 | #define ATECC_RNG_P1 0 44 | #define ATECC_RNG_P2 0 45 | 46 | #define ATECC_CMD_SHA 0x47 47 | // P1 48 | #define ATECC_SHA_START 0x0 49 | #define ATECC_SHA_UPDATE 0x1 50 | #define ATECC_SHA_END 0x2 51 | #define ATECC_SHA_HMACSTART 0x4 52 | #define ATECC_SHA_HMACEND 0x5 53 | // P2 is keyslot ID for hmac and message length otherwise 54 | 55 | #define ATECC_CMD_READ 0x02 56 | // P1 57 | #define ATECC_RW_CONFIG 0x00 58 | #define ATECC_RW_OTP 0x01 59 | #define ATECC_RW_DATA 0x02 60 | #define ATECC_RW_EXT 0x80 61 | // P2 read addr 62 | #define ATECC_RW_LENGTH (4) 63 | #define ATECC_RW_LENGTH_EXT (32) 64 | #define ATECC_RW_SUFFIX_LENGTH (4) 65 | 66 | #define ATECC_CONFIG_LOCK_VALUE_POS (86) 67 | #define ATECC_CONFIG_LOCK_CONFIG_POS (87) 68 | 69 | #define ATECC_CMD_WRITE 0x12 70 | // P1 same as for read 71 | #define ATECC_RW_ENCRYPTED 0x40 72 | // P2 write addr 73 | 74 | #define ATECC_EEPROM_SLOT(x) (0x5 + ((x)>>1)) 75 | #define ATECC_EEPROM_SLOT_OFFSET(x) ( (x) & 1 ? 2 : 0 ) 76 | #define ATECC_EEPROM_SLOT_SIZE 0x2 77 | 78 | #define ATECC_EEPROM_KEY(x) (24 + ((x)>>1)) 79 | #define ATECC_EEPROM_KEY_OFFSET(x) ( (x) & 1 ? 2 : 0 ) 80 | #define ATECC_EEPROM_KEY_SIZE 0x2 81 | 82 | #define ATECC_EEPROM_DATA_SLOT(x) (x<<3) 83 | 84 | #define ATECC_EEPROM_B2A(b) ((b)>>2) 85 | #define ATECC_EEPROM_B2O(b) ((b)&0x3) 86 | 87 | #define ATECC_CMD_LOCK 0x17 88 | // P1 flags 89 | #define ATECC_LOCK_CONFIG 0x00 90 | #define ATECC_LOCK_DATA_OTP 0x01 91 | #define ATECC_LOCK_SLOT 0x02 92 | #define ATECC_LOCK_SLOTNUM(x) (((x)&0xf)<<2) 93 | #define ATECC_LOCK_IGNORE_SUMMARY 0x80 94 | // P2 is CRC or 0 95 | 96 | #define ATECC_CMD_GENKEY 0x40 97 | // P1 98 | #define ATECC_GENKEY_PRIVATE 0x04 99 | #define ATECC_GENKEY_PUBLIC 0x00 100 | #define ATECC_GENKEY_PUBDIGEST 0x08 101 | #define ATECC_GENKEY_PUBDIGEST2 0x10 102 | // P2 is keyid 103 | 104 | #define ATECC_CMD_NONCE 0x16 105 | // P1 106 | #define ATECC_NONCE_RNG_UPDATE 0x0 107 | #define ATECC_NONCE_TEMP_UPDATE 0x3 108 | // P2 is 0 109 | 110 | #define ATECC_CMD_SIGN 0x41 111 | // P1 112 | #define ATECC_SIGN_INTERNAL 0x00 113 | #define ATECC_SIGN_EXTERNAL 0x80 114 | // P2 is keyid 115 | 116 | #define ATECC_CMD_GENDIG 0x15 117 | // P1 same as for read 118 | // P2 is keyid 119 | 120 | #define ATECC_CMD_INFO 0x30 121 | // P1 same as for read 122 | #define ATECC_INFO_REVISION 0x00 123 | #define ATECC_INFO_KEYVALID 0x01 124 | #define ATECC_INFO_STATE 0x02 125 | #define ATECC_INFO_GPIO 0x03 126 | // P2 is keyid 127 | 128 | #define ATECC_CMD_PRIVWRITE 0x46 129 | // P1 130 | #define ATECC_PRIVWRITE_ENC 0x40 131 | // P2 is keyid 132 | 133 | #include 134 | 135 | struct atecc_response 136 | { 137 | // length of payload 138 | uint8_t len; 139 | // payload 140 | uint8_t* buf; 141 | }; 142 | 143 | #ifdef ATECC_SETUP_DEVICE 144 | 145 | struct atecc_slot_config 146 | { 147 | uint8_t readkey : 4; 148 | uint8_t nomac : 1; 149 | uint8_t limiteduse : 1; 150 | uint8_t encread : 1; 151 | uint8_t secret : 1; 152 | uint8_t writekey : 4; 153 | uint8_t writeconfig : 4; 154 | }; 155 | 156 | struct atecc_key_config 157 | { 158 | uint8_t private : 1; 159 | uint8_t pubinfo : 1; 160 | uint8_t keytype : 3; 161 | uint8_t lockable : 1; 162 | uint8_t reqrandom : 1; 163 | uint8_t reqauth : 1; 164 | uint8_t authkey : 4; 165 | uint8_t intrusiondisable : 1; 166 | uint8_t rfu : 1; 167 | uint8_t x509id : 2; 168 | }; 169 | #endif 170 | 171 | #ifdef FEAT_FACTORY_RESET 172 | // 1 page - 64 bytes 173 | extern struct DevConf{ 174 | uint8_t RMASK[36]; 175 | uint8_t WMASK[36]; 176 | } device_configuration; 177 | #endif 178 | 179 | extern struct SHA_context{ 180 | uint8_t shabuf[70]; //64 bytes of data + 6 bytes of response header 181 | uint8_t shaoffset; 182 | uint8_t SHA_FLAGS; 183 | uint8_t SHA_HMAC_KEY; 184 | } sha_ctx; 185 | 186 | extern struct atecc_response res_digest; 187 | 188 | // ATECC's configuration 189 | extern uint8_t get_readable_config(uint8_t * out_slotconfig, uint8_t slotconfig_len, 190 | uint8_t * out_keyconfig, uint8_t keyconfig_len); 191 | extern uint8_t atecc_setup_config(uint8_t* buf); 192 | extern void dump_config(uint8_t* buf); 193 | extern uint8_t compare_binary_readable_configs(uint8_t* out_config, uint8_t out_len); 194 | 195 | extern void u2f_sha256_start(uint8_t hmac_key, uint8_t sha_flags); 196 | extern void u2f_sha256_start_default(); 197 | extern void u2f_sha256_update (uint8_t * buf, uint8_t len); 198 | extern void compute_key_hash (uint8_t * key, uint16_t mask, int slot); 199 | extern struct atecc_response* u2f_sha256_finish(); 200 | extern int atecc_prep_encryption(); 201 | extern int atecc_privwrite(uint16_t keyslot, uint8_t * key, uint16_t mask, uint8_t * digest); 202 | 203 | void atecc_idle(); 204 | void atecc_wake(); 205 | void atecc_sleep(); 206 | extern uint8_t atecc_used; 207 | 208 | int8_t atecc_send(uint8_t cmd, uint8_t p1, uint16_t p2, 209 | uint8_t * buf, uint8_t len); 210 | 211 | int8_t atecc_recv(uint8_t * buf, uint8_t buflen, struct atecc_response* res); 212 | 213 | int8_t atecc_send_recv(uint8_t cmd, uint8_t p1, uint16_t p2, 214 | uint8_t* tx, uint8_t txlen, uint8_t * rx, 215 | uint8_t rxlen, struct atecc_response* res); 216 | 217 | int8_t atecc_write_eeprom(uint8_t base, uint8_t offset, uint8_t* srcbuf, uint8_t len); 218 | 219 | int8_t read_masks(); 220 | int8_t write_masks(); 221 | 222 | uint8_t generate_device_key(uint8_t *output_debug, uint8_t *buf, uint8_t buflen); 223 | uint8_t generate_RMASK(uint8_t *temporary_buffer, uint8_t bufsize); 224 | uint8_t generate_WMASK(uint8_t *temporary_buffer, uint8_t bufsize); 225 | 226 | #endif /* ATECC508A_H_ */ 227 | -------------------------------------------------------------------------------- /tools/testing/u2f_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2013 Yubico AB 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or 6 | # without modification, are permitted provided that the following 7 | # conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above 12 | # copyright notice, this list of conditions and the following 13 | # disclaimer in the documentation and/or other materials provided 14 | # with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 | # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 26 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. 28 | 29 | """ 30 | Example web server providing single factor U2F enrollment and authentication. 31 | It is intended to be run standalone in a single process, and stores user data 32 | in memory only, with no permanent storage. 33 | 34 | Enrollment will overwrite existing users. 35 | If username is omitted, a default value of "user" will be used. 36 | 37 | Any error will be returned as a stacktrace with a 400 response code. 38 | 39 | Note that this is intended for test/demo purposes, not production use! 40 | 41 | This example requires webob to be installed. 42 | """ 43 | 44 | from u2flib_server.u2f import (begin_registration, begin_authentication, 45 | complete_registration, complete_authentication) 46 | from cryptography import x509 47 | from cryptography.hazmat.backends import default_backend 48 | from cryptography.hazmat.primitives.serialization import Encoding 49 | from webob.dec import wsgify 50 | from webob import exc 51 | import logging as log 52 | import json 53 | import traceback 54 | import argparse 55 | import binascii 56 | 57 | from u2flib_server.utils import websafe_encode, websafe_decode 58 | 59 | 60 | def get_origin(environ): 61 | if environ.get('HTTP_HOST'): 62 | host = environ['HTTP_HOST'] 63 | else: 64 | host = environ['SERVER_NAME'] 65 | if environ['wsgi.url_scheme'] == 'https': 66 | if environ['SERVER_PORT'] != '443': 67 | host += ':' + environ['SERVER_PORT'] 68 | else: 69 | if environ['SERVER_PORT'] != '80': 70 | host += ':' + environ['SERVER_PORT'] 71 | 72 | return '%s://%s' % (environ['wsgi.url_scheme'], host) 73 | 74 | 75 | class U2FServer(object): 76 | 77 | """ 78 | Very basic server providing a REST API to enroll one or more U2F device with 79 | a user, and to perform authentication with the enrolled devices. 80 | Only one challenge is valid at a time. 81 | 82 | Four calls are provided: enroll, bind, sign and verify. Each of these 83 | expects a username parameter, and bind and verify expect a 84 | second parameter, data, containing the JSON formatted data which is output 85 | by the U2F browser API upon calling the ENROLL or SIGN commands. 86 | """ 87 | 88 | def __init__(self): 89 | self.users = {} 90 | 91 | @wsgify 92 | def __call__(self, request): 93 | self.facet = get_origin(request.environ) 94 | self.app_id = self.facet 95 | 96 | page = request.path_info_pop() 97 | 98 | if not page: 99 | return json.dumps([self.facet]) 100 | 101 | try: 102 | username = request.params.get('username', 'user') 103 | data = request.params.get('data', None) 104 | log.info('Request') 105 | if page == 'enroll': 106 | return self.enroll(username) 107 | elif page == 'bind': 108 | return self.bind(username, data) 109 | elif page == 'sign': 110 | return self.sign(username) 111 | elif page == 'verify': 112 | return self.verify(username, data) 113 | else: 114 | raise exc.HTTPNotFound() 115 | except Exception: 116 | log.exception("Exception in call to '%s'", page) 117 | return exc.HTTPBadRequest(comment=traceback.format_exc()) 118 | 119 | def enroll(self, username): 120 | if username not in self.users: 121 | self.users[username] = {} 122 | 123 | user = self.users[username] 124 | enroll = begin_registration(self.app_id, user.get('_u2f_devices_', [])) 125 | user['_u2f_enroll_'] = enroll.json 126 | return json.dumps(enroll.data_for_client) 127 | 128 | def bind(self, username, data): 129 | user = self.users[username] 130 | enroll = user.pop('_u2f_enroll_') 131 | device, cert = complete_registration(enroll, data, [self.facet]) 132 | print 133 | print 'device, ' , device 134 | print 'key handle', binascii.hexlify(websafe_decode(device['keyHandle'])) 135 | print 136 | user.setdefault('_u2f_devices_', []).append(device.json) 137 | 138 | log.info("U2F device enrolled. Username: %s", username) 139 | cert = x509.load_der_x509_certificate(cert, default_backend()) 140 | log.debug("Attestation certificate:\n%s", 141 | cert.public_bytes(Encoding.PEM)) 142 | 143 | return json.dumps(True) 144 | 145 | def sign(self, username): 146 | user = self.users[username] 147 | challenge = begin_authentication( 148 | self.app_id, user.get('_u2f_devices_', [])) 149 | user['_u2f_challenge_'] = challenge.json 150 | return json.dumps(challenge.data_for_client) 151 | 152 | def verify(self, username, data): 153 | user = self.users[username] 154 | 155 | challenge = user.pop('_u2f_challenge_') 156 | device, c, t = complete_authentication(challenge, data, [self.facet]) 157 | return json.dumps({ 158 | 'keyHandle': device['keyHandle'], 159 | 'touch': t, 160 | 'counter': c 161 | }) 162 | 163 | application = U2FServer() 164 | 165 | if __name__ == '__main__': 166 | from wsgiref.simple_server import make_server 167 | 168 | parser = argparse.ArgumentParser( 169 | description='U2F test server', 170 | add_help=True, 171 | formatter_class=argparse.ArgumentDefaultsHelpFormatter 172 | ) 173 | parser.add_argument('-i', '--interface', nargs='?', default='localhost', 174 | help='network interface to bind to') 175 | parser.add_argument('-p', '--port', nargs='?', type=int, default=8081, 176 | help='TCP port to bind to') 177 | 178 | args = parser.parse_args() 179 | 180 | log.basicConfig(level=log.DEBUG, format='%(asctime)s %(message)s', 181 | datefmt='[%d/%b/%Y %H:%M:%S]') 182 | log.info("Starting server on http://%s:%d", args.interface, args.port) 183 | httpd = make_server(args.interface, args.port, application) 184 | httpd.serve_forever() 185 | -------------------------------------------------------------------------------- /doc/security_architecture.md: -------------------------------------------------------------------------------- 1 | # FIDO U2F Security Architecture 2 | 3 | This description is reduced to the relevant aspects so that length fields and other fields are not mentioned (indicated with “...”). The complete overview of request and response fields is covered in the official FIDO specifications. 4 | In this document "`||`" symbol means data concatenation. 5 | 6 | Global use counter is set to zero initially. It is defined per-device and incremented for each registration and authentication. 7 | 8 | During both registration and authentication procedures, private keys are generated. These have to be transferred temporary between MCU and ATECC chip to perform further cryptographic operations. To maintain security, they are XORed with both `wkey` and `rkey` to keep the I2C bus communication encrypted: 9 | - `rkey` is present only on the MCU. This is a XOR-key for I2C bus encryption on read (modifying data read from ATECC chip). 10 | - `wkey` is created on the host from the SHA-256 hash of the `device_key` number. Similarly to `wkey`, it is present only on the MCU. This is a XOR-key for I2C bus encryption on write (to the ATECC chip). 11 | 12 | # Phases 13 | 14 | ## Certificate and attestation key generation 15 | 16 | Certificate and attestation key are generated on the vendor's computer in this phase and stored on hard drive. 17 | 18 | ## Configuration / SETUP phase 19 | 20 | 1. RNG is run on the host to produce three 32-byte random numbers for `device key`, `_wkey` and `_rkey`. The former is the device-specific secret for U2F functionality which - after setup - won't leave the ATECC. The latter two will be used during the device's work for encrypting communication with the ATECC chip on the I2C bus. 21 | 2. `device key` is loaded to the ATECC chip unmodified. 22 | 3. `_rkey` and `_wkey` are SHA256-hashed with a known constant. The outcomes are target `rkey` and `wkey` respectively, and written to the FINAL firmware (to the `cert.c` file). 23 | 4. `wkey` is loaded to the device and kept in the RAM. 24 | 5. Attestation key is sent to the device and saved to RAM. 25 | 6. A key hash is calculated to authenticate its encrypted write to the ATECC chip. 26 | 7. Attestation key is XORed with `wkey` and written to the ATECC chip using previously calculated key hash MAC. 27 | 28 | 29 | ![Keys handling diagram - setup][keys-setup] 30 | 31 | 32 | 33 | ## Firmware compilation 34 | During the compilation the attestation certificate and `wkey`/`rkey` constants are included directly into the firmware files as static binary blobs. 35 | 36 | 37 | ## Registration 38 | 39 | ### Registration Request: 40 | - challenge parameter: SHA-256 hash 41 | - application parameter: SHA-256 hash of application identity. This parameter could be also wrongly phrased as AppID, while both are actually different (but related) values. 42 | 43 | ### Registration calculation: 44 | 1. Generate random nonce from RNG 45 | 2. `private key := HMAC-SHA256(device key, application parameter || nonce)` - this private key is application-specific 46 | 3. `user public key := derive from private key` 47 | 4. `MAC := HMAC-SHA256(device key, private key || application parameter)` 48 | 5. `Key handle := nonce || MAC` 49 | 6. `signature := ecdsa(private key, application parameter || challenge parameter || key handle || user public key || ...)` 50 | 51 | ### Registration Response: 52 | - A user public key [65 bytes]. This is the (uncompressed) x,y-representation of a curve point on the P-256 NIST elliptic curve. 53 | - key handle: This a handle that allows the U2F token to identify the generated key pair. U2F tokens may wrap the generated private key and the application id it was generated for, and output that as the key handle. 54 | - signature: This is a ECDSA signature (on P-256) over the following byte string: 55 | - The application parameter [32 bytes] from the registration request message. 56 | - The challenge parameter[32 bytes] from the registration request message. 57 | - The above key handle [variable length]. (Note that the key handle length is not included in the signature base string. This doesn't cause confusion in the signature base string, since all other parameters in the signature base string are fixed-length.) 58 | - The above user public key [65 bytes]. 59 | - ... 60 | 61 | ![Registration diagram][register] 62 | 63 | ### Transport Encryption During Registration 64 | 1. `priv_user_key_rkey := priv_user_key ^ rkey` - a generated private key is XORed with `rkey`. 65 | 2. `key_write_auth_mac := sha256(wkey || priv_user_key_rkey || privwrite_const)` - the modified key is used to compute write authentication hash for ATECC chip. 66 | 3. `priv_user_key_rkey_wkey := priv_user_key_rkey ^ wkey` - the modified key is once again XORed with `wkey` 67 | 4. `privwrite(priv_user_key_rkey_wkey, device_key || key_write_auth_mac)` - private key is saved to the device using previously calculated write hash. 68 | 5. `priv_user_key_rkey:= priv_user_key_rkey_wkey ^ wkey` - on ATECC the received data is decrypted with `wkey`, leaving `rkey` mask applied to the sent key. 69 | 70 | ![Keys handling diagram - registration][keys-registration] 71 | 72 | 73 | ## Authentication 74 | ### Authentication Request: 75 | - The challenge parameter [32 bytes]. The challenge parameter is the SHA-256 hash of the Client Data, a stringified JSON data structure that the FIDO Client prepares. Among other things, the Client Data contains the challenge from the relying party (hence the name of the parameter). See below for a detailed explanation of Client Data. 76 | - The application parameter [32 bytes]. The application parameter is the SHA-256 hash of the UTF-8 encoding of the application identity of the application requesting the authentication as provided by the relying party. 77 | - A key handle [length specified in previous field]. The key handle. This is provided by the relying party, and was obtained by the relying party during registration. `Key handle = nonce || MAC` 78 | - … 79 | 80 | ### Authentication calculation: 81 | 1. `nonce := subtract from key handle` 82 | 2. `MAC1 := subtract from key handle` 83 | 3. `private key := HMAC-SHA256(device key, application parameter || nonce)` - this is the same calculation as during registration 84 | 4. `MAC2 := HMAC-SHA256(device key, private key || application parameter)` 85 | 5. `verify: MAC1 == MAC2` - during authentication, the MAC helps to ensure that a key handle is only valid for the particular combination of device and AppID that it was created for during registration 86 | 6. `signature := ecdsa(private key, application parameter || challenge parameter || global use counter || ...)` 87 | 7. increment global use counter 88 | 89 | ### Authentication Response: 90 | - A signature. This is a ECDSA signature (on P-256) over the following byte string: 91 | - The application parameter [32 bytes] from the authentication request message. 92 | - The challenge parameter [32 bytes] from the authentication request message. 93 | - ... 94 | 95 | ![Authentication diagram][auth] 96 | 97 | ### Transport Encryption During Authentication 98 | Authentication differs from Registration usage by not computing the write MAC for the ATECC chip, and instead reusing the `key_handle`, which contains the computed on registration value. 99 | 100 | ![Keys handling diagram - authentication][keys-authentication] 101 | 102 | 103 | 104 | 105 | [register]: images/u2f-registration.png "U2F Registeration" 106 | [auth]: images/u2f-authentication.png "U2F Authorization" 107 | [keys-setup]: images/keys_usage-configuration.png "Keys handling diagram - setup" 108 | [keys-registration]: images/keys_usage-u2f_registration.png "Keys handling diagram - registration" 109 | [keys-authentication]: images/keys_usage-u2f_authentication.png "Keys handling diagram - authentication" 110 | 111 | -------------------------------------------------------------------------------- /firmware/inc/u2f.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | * 27 | * U2F spec: https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-raw-message-formats.html 28 | */ 29 | 30 | #ifndef _U2F_H_ 31 | #define _U2F_H_ 32 | 33 | #include 34 | 35 | #define U2F_EC_FMT_UNCOMPRESSED 0x04 36 | 37 | #define U2F_EC_POINT_SIZE 32 38 | #define U2F_EC_PUBKEY_SIZE 65 39 | #define U2F_EC_PUBKEY_RAW_SIZE 64 40 | #define U2F_APDU_SIZE 7 41 | #define U2F_CHALLENGE_SIZE 32 42 | #define U2F_APPLICATION_SIZE 32 43 | // U2F_KEY_HANDLE_ID_SIZE up to 32 bytes, if bigger is required then 44 | // gen_u2f_zero_tag needs to be modified 45 | #define U2F_KEY_HANDLE_ID_SIZE 28 46 | #define U2F_KEY_HANDLE_KEY_SIZE 36 47 | #define U2F_KEY_HANDLE_SIZE (U2F_KEY_HANDLE_KEY_SIZE+U2F_KEY_HANDLE_ID_SIZE) 48 | #define U2F_REGISTER_REQUEST_SIZE (U2F_CHALLENGE_SIZE+U2F_APPLICATION_SIZE) 49 | #define U2F_MAX_REQUEST_PAYLOAD (1 + U2F_CHALLENGE_SIZE+U2F_APPLICATION_SIZE + 1 + U2F_KEY_HANDLE_SIZE) 50 | // See FIDO U2F Raw Message Formats, chapter 4.3 Registration Response Message: Success 51 | #define U2F_REGISTER_RESERVED_BYTE (0x05) 52 | 53 | // U2F native commands 54 | #define U2F_REGISTER 0x01 55 | #define U2F_AUTHENTICATE 0x02 56 | #define U2F_VERSION 0x03 57 | #define U2F_VENDOR_FIRST 0xc0 58 | #define U2F_VENDOR_LAST 0xff 59 | 60 | // U2F_CMD_REGISTER command defines 61 | #define U2F_REGISTER_ID 0x05 62 | #define U2F_REGISTER_HASH_ID 0x00 63 | 64 | // U2F Authenticate 65 | #define U2F_AUTHENTICATE_CHECK 0x7 66 | #define U2F_AUTHENTICATE_SIGN 0x3 67 | 68 | 69 | // Command status responses 70 | #define U2F_SW_NO_ERROR 0x9000 71 | #define U2F_SW_WRONG_DATA 0x6984 72 | #define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 73 | #define U2F_SW_INS_NOT_SUPPORTED 0x6d00 74 | #define U2F_SW_WRONG_LENGTH 0x6700 75 | #define U2F_SW_CLASS_NOT_SUPPORTED 0x6E00 76 | #define U2F_SW_WRONG_PAYLOAD 0x6a80 77 | #define U2F_SW_INSUFFICIENT_MEMORY 0x9210 78 | #define U2F_SW_LENGTH (2) 79 | #define U2F_SW_OPERATION_FAILED (U2F_SW_WRONG_DATA+0x20) 80 | 81 | // Custom errors 82 | #define U2F_SW_CUSTOM_RNG_GENERATION 0x920f 83 | #define U2F_SW_CUSTOM_PRIVWRITE 0x921e 84 | #define U2F_SW_CUSTOM_GENKEY 0x921d 85 | 86 | // Delay in milliseconds to wait for user input 87 | #define U2F_MS_USER_INPUT_WAIT 100 88 | 89 | 90 | struct u2f_request_apdu 91 | { 92 | uint8_t cla; 93 | uint8_t ins; 94 | uint8_t p1; 95 | uint8_t p2; 96 | uint8_t LC1; 97 | uint8_t LC2; 98 | uint8_t LC3; 99 | uint8_t payload[U2F_MAX_REQUEST_PAYLOAD]; 100 | }; 101 | 102 | struct u2f_register_request 103 | { 104 | uint8_t challenge[U2F_CHALLENGE_SIZE]; 105 | uint8_t application[U2F_APPLICATION_SIZE]; 106 | }; 107 | 108 | struct u2f_authenticate_request 109 | { 110 | uint8_t challenge[U2F_CHALLENGE_SIZE]; 111 | uint8_t application[U2F_APPLICATION_SIZE]; 112 | uint8_t key_handle_length; 113 | uint8_t key_handle[U2F_KEY_HANDLE_SIZE]; 114 | } ; 115 | 116 | // u2f_request send a U2F message to U2F protocol 117 | // @req U2F message 118 | void u2f_request(struct u2f_request_apdu* req); 119 | 120 | 121 | 122 | ////////////////////////////////////////////////////////////////// 123 | /* Platform specific functions that must be implemented by user */ 124 | ////////////////////////////////////////////////////////////////// 125 | 126 | // Key id/handle for the private key for attestation 127 | #define U2F_ATTESTATION_HANDLE NULL 128 | 129 | // u2f_attestation_cert_size return size of the DER formatted attestation certificate 130 | extern uint16_t u2f_attestation_cert_size(); 131 | 132 | // u2f_response_writeback callback for u2f to send back response data 133 | // @buf data to write back 134 | // @len length of buf in bytes 135 | extern void u2f_response_writeback(uint8_t * buf, uint16_t len); 136 | 137 | // u2f_response_flush callback when u2f finishes and will 138 | // indicate when all buffer data, if any, should be written 139 | extern void u2f_response_flush(); 140 | 141 | // u2f_response_start callback when u2f starts a new transaction 142 | extern void u2f_response_start(); 143 | 144 | // u2f_get_user_feedback return 0 if user provides feedback, -1 if not 145 | // This should block as long as it needs to get feedback 146 | // before failing. 147 | extern int8_t u2f_get_user_feedback(); 148 | extern int8_t u2f_get_user_feedback_extended_wipe(); 149 | 150 | 151 | // u2f_sha256_start callback for u2f to start a sha256 hash 152 | extern void u2f_sha256_start_default(); 153 | extern void u2f_sha256_start(uint8_t hmac_key, uint8_t sha_flags); 154 | 155 | // u2f_sha256_update callback for u2f to add data to started sha256 state 156 | // @buf data to update hash with 157 | // @len length of buf in bytes 158 | extern void u2f_sha256_update(uint8_t * buf, uint8_t len); 159 | 160 | // u2f_sha256_finish callback for u2f to harvest hash from 161 | // returns pointer to result buffer via atecc_response 162 | extern struct atecc_response* u2f_sha256_finish(); 163 | 164 | 165 | // u2f_ecdsa_sign callback for u2f to compute signature on the previously computed sha256 digest 166 | // @dest atleast 64 bytes to write back signature R and S values 167 | // @handle for the private key to use 168 | // @return -1 for failure, 0 for success 169 | extern int8_t u2f_ecdsa_sign(uint8_t * dest, uint8_t * handle, uint8_t * appid); 170 | 171 | 172 | // u2f_new_keypair callback to get a new key handle 173 | // @handle location to write the key handle (should be U2F_KEY_HANDLE_SIZE bytes long) 174 | // @appid the new application ID to associate with key pair. 32 bytes. 175 | // @pubkey location to write the public key R & S (64 bytes) 176 | // @return -1 for failure, 0 for success 177 | int8_t u2f_new_keypair(uint8_t * handle, uint8_t * appid, uint8_t * pubkey); 178 | 179 | // u2f_appid_eq must check if app id is equal to app id associated with key pair handle 180 | /// @handle the handle for the key pair 181 | /// @appid the 32 byte app id to check against 182 | /// @return non-zero not equal, 0 equal 183 | int8_t u2f_appid_eq(uint8_t * handle, uint8_t * appid); 184 | 185 | // u2f_load_key Load a key into memory or check to see that the handle exists 186 | // @handle the key handle to check 187 | // @return -1 if it doesn't exist, 0 for success 188 | extern int8_t u2f_load_key(uint8_t * handle, uint8_t * appid); 189 | 190 | // u2f_get_attestation_cert method to return pointer to attestation cert 191 | extern uint8_t * u2f_get_attestation_cert(); 192 | 193 | // u2f_count Should increment a 4 byte persistent/atomic counter and return it. 194 | // @return the counter 195 | extern uint32_t u2f_count(); 196 | 197 | // set_response_length method to set the total length of the response for use by underlying layer 198 | // @len the length of U2F response in bytes 199 | extern void set_response_length(uint16_t len); 200 | 201 | #endif /* U2F_H_ */ 202 | -------------------------------------------------------------------------------- /firmware/src/gpio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Nitrokey UG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | * 26 | * gpio.c 27 | * This file contains the GPIO access functions. 28 | * It provides abstractions for access to the LED as well as the user button. 29 | * 30 | */ 31 | #include 32 | 33 | #include "bsp.h" 34 | #include "app.h" 35 | #include "gpio.h" 36 | #include "sanity-check.h" 37 | 38 | #define ms_since(ms,num) (((uint16_t)get_ms() - (ms)) >= num ? ((ms=(uint16_t)get_ms())):0) 39 | 40 | data uint32_t button_press_t; // Timer for TaskButton() timings 41 | data BUTTON_STATE_T button_state = BST_INITIALIZING; // Holds the actual registered logical state of the button 42 | 43 | static data uint32_t led_blink_tim = 0; // Timer for TaskLedBlink() timings 44 | static data uint16_t led_blink_period_t; // Period time register 45 | static data uint16_t led_blink_ON_t; // ON time register 46 | static data uint8_t led_blink_num; // Blink number counter, also an indicator if blinking is on 47 | 48 | static data uint32_t button_manager_start_t = 0; 49 | 50 | void button_manager (void) { // Requires at least a 750ms long button press to register a valid user button press 51 | 52 | if (button_state == BST_INITIALIZING){ 53 | if (button_manager_start_t == 0){ 54 | button_manager_start_t = get_ms(); 55 | return; 56 | } 57 | if (get_ms() - button_manager_start_t <= U2F_MS_INIT_BUTTON_PERIOD){ 58 | return; 59 | } 60 | button_state = BST_INITIALIZING_READY_TO_CLEAR; 61 | } 62 | if (button_state == BST_INITIALIZING_READY_TO_CLEAR){ 63 | return; 64 | } 65 | 66 | if (IS_BUTTON_PRESSED()) { // Button's physical state: pressed 67 | switch (button_state) { // Handle press phase 68 | case BST_UNPRESSED: { // It happened at this moment 69 | button_state = BST_PRESSED_RECENTLY; // Update button state 70 | button_press_t = get_ms(); // Start measure press time 71 | }break; 72 | case BST_PRESSED_RECENTLY: { // Button is already pressed, press time measurement is ongoing 73 | if (get_ms() - button_press_t >= BUTTON_MIN_PRESS_T_MS) { // Press time reached the critical value to register a valid user touch 74 | button_state = BST_PRESSED_REGISTERED; // Update button state 75 | } 76 | }break; 77 | case BST_PRESSED_CONSUMED: 78 | break; 79 | case BST_PRESSED_REGISTERED: 80 | if (get_ms() - button_press_t >= BUTTON_MAX_PRESS_T_MS) { 81 | button_state = BST_PRESSED_REGISTERED_TRANSITIONAL; 82 | } 83 | break; 84 | case BST_PRESSED_REGISTERED_TRANSITIONAL: 85 | if (get_ms() - button_press_t >= BUTTON_MIN_PRESS_T_MS_EXT) { 86 | button_state = BST_PRESSED_REGISTERED_EXT; 87 | } 88 | break; 89 | default: 90 | break; 91 | } 92 | } else { // Button is unprssed 93 | button_state = BST_UNPRESSED; // Update button state 94 | } 95 | } 96 | 97 | uint8_t button_get_press (void) { 98 | return ((button_state == BST_PRESSED_REGISTERED)? 1 : 0); 99 | } 100 | 101 | BUTTON_STATE_T button_get_press_state (void) { 102 | return button_state; 103 | } 104 | 105 | uint8_t button_get_press_extended (void) { 106 | return ((button_state == BST_PRESSED_REGISTERED_EXT)? 1 : 0); 107 | } 108 | 109 | uint8_t button_press_in_progress(void){ 110 | return ( (button_state > BST_UNPRESSED)? 1 : 0); 111 | } 112 | 113 | void button_press_set_consumed(void){ 114 | button_state = BST_PRESSED_CONSUMED; 115 | } 116 | 117 | uint8_t button_press_is_consumed(void){ 118 | return ((button_state == BST_PRESSED_CONSUMED)? 1 : 0); 119 | } 120 | 121 | 122 | void led_on (void) { 123 | if (sanity_check_passed) 124 | led_blink_num = 0; // Stop ongoing blinking 125 | LED_ON(); // LED physical state -> ON 126 | } 127 | 128 | void led_off (void) { 129 | if (sanity_check_passed) 130 | led_blink_num = 0; // Stop ongoing blinking 131 | LED_OFF(); // LED physical state -> OFF 132 | } 133 | 134 | bool led_is_blinking(void){ 135 | return led_blink_num != 0; 136 | } 137 | 138 | void led_change_ON_time(uint16_t ON_time){ 139 | led_blink_ON_t = ON_time; 140 | } 141 | 142 | void led_blink (uint8_t blink_num, uint16_t period_t) { 143 | led_blink_num = blink_num; 144 | led_blink_period_t = period_t; 145 | led_blink_ON_t = LED_BLINK_T_ON; 146 | 147 | if ( (button_get_press_state() > BST_META_READY_TO_USE && (get_ms() - led_blink_tim >= LED_BLINK_T_OFF) ) 148 | || led_blink_num == 1) 149 | LED_ON(); 150 | if (!sanity_check_passed) 151 | led_blink_num = LED_BLINK_NUM_INF; 152 | 153 | led_blink_tim = get_ms(); 154 | } 155 | 156 | void led_blink_manager (void) { 157 | if (button_get_press_state() < BST_META_READY_TO_USE && led_blink_num != 1 && sanity_check_passed) 158 | return; 159 | 160 | if (led_blink_num) { // LED blinking is on 161 | if (IS_LED_ON()) { // ON state 162 | if (get_ms() - led_blink_tim >= led_blink_ON_t) { // ON time expired 163 | LED_OFF(); // LED physical state -> OFF 164 | if (led_blink_num) { // It isnt the last blink round: initialize OFF state: 165 | led_blink_tim = get_ms(); // Init OFF timer 166 | if (led_blink_num != LED_BLINK_NUM_INF) { // Not endless blinking: 167 | led_blink_num--; // Update the remaining blink num 168 | } 169 | } 170 | } 171 | } else { // OFF state 172 | if (get_ms() - led_blink_tim >= LED_BLINK_T_OFF) { // OFF time expired 173 | LED_ON(); // LED physical state -> ON 174 | led_blink_tim = get_ms(); // Init ON timer 175 | } 176 | } 177 | } 178 | } 179 | 180 | static void set_button_cleared(){ 181 | button_state = BST_UNPRESSED; 182 | } 183 | 184 | 185 | static uint32_t last_button_cleared_time = 0; 186 | 187 | uint8_t last_button_cleared_time_delta(){ 188 | // range [0.0-25.5] [s/10] 189 | return (get_ms() - last_button_cleared_time)/100; 190 | } 191 | 192 | uint8_t last_button_pushed_time_delta(){ 193 | // range [0.0-25.5] [s/10] 194 | return (get_ms() - button_press_t)/100; 195 | } 196 | 197 | void clear_button_press(){ 198 | _clear_button_press(false); 199 | } 200 | 201 | void _clear_button_press(bool forced){ 202 | if(!forced){ 203 | // do not clear if enough time has not passed, unless button is ready to be cleared 204 | if (button_get_press_state() != BST_INITIALIZING_READY_TO_CLEAR 205 | && (get_ms() - last_button_cleared_time < U2F_MS_CLEAR_BUTTON_PERIOD) ) 206 | return; 207 | // do not clear, when: 208 | if (button_get_press_state() == BST_INITIALIZING // button is not ready for clear yet 209 | || button_get_press_state() > BST_UNPRESSED // button is pressed by the user 210 | ){ 211 | return; 212 | } 213 | } 214 | 215 | last_button_cleared_time = get_ms(); 216 | led_off(); 217 | 218 | 219 | BUTTON_RESET_ON(); 220 | do { 221 | u2f_delay(6); //6ms activation time + 105ms maximum sleep in NORMAL power mode 222 | } while (IS_BUTTON_PRESSED()); // Wait to release button 223 | BUTTON_RESET_OFF(); 224 | 225 | 226 | if (button_get_press_state() == BST_INITIALIZING_READY_TO_CLEAR){ 227 | set_button_cleared(); 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /firmware/src/u2f.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Conor Patrick 3 | * Copyright (c) 2018, Nitrokey UG 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | * 27 | * u2f.c 28 | * Cross platform implementation of U2F. See API docs in u2f.h. 29 | * 30 | * U2F spec: https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-raw-message-formats.html 31 | * 32 | */ 33 | 34 | #include "app.h" 35 | 36 | 37 | #ifndef U2F_DISABLE 38 | 39 | #include "bsp.h" 40 | #include "u2f.h" 41 | 42 | 43 | // void u2f_response_writeback(uint8_t * buf, uint8_t len); 44 | static int16_t u2f_register(struct u2f_register_request * req); 45 | static int16_t u2f_version(); 46 | static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control); 47 | 48 | void u2f_request(struct u2f_request_apdu * req) 49 | { 50 | uint16_t * rcode = (uint16_t *)req; 51 | uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16)); 52 | 53 | u2f_response_start(); 54 | 55 | if (req->cla != 0) 56 | { 57 | u2f_hid_set_len(U2F_SW_LENGTH); 58 | *rcode = U2F_SW_CLASS_NOT_SUPPORTED; 59 | goto end; 60 | } 61 | 62 | switch(req->ins) 63 | { 64 | case U2F_REGISTER: 65 | if (len != 64) 66 | { 67 | u2f_hid_set_len(U2F_SW_LENGTH); 68 | *rcode = U2F_SW_WRONG_LENGTH; 69 | } 70 | else 71 | { 72 | *rcode = u2f_register((struct u2f_register_request*)req->payload); 73 | } 74 | break; 75 | case U2F_AUTHENTICATE: 76 | *rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1); 77 | break; 78 | case U2F_VERSION: 79 | if (len) 80 | { 81 | u2f_hid_set_len(U2F_SW_LENGTH); 82 | *rcode = U2F_SW_WRONG_LENGTH; 83 | } 84 | else 85 | { 86 | *rcode = u2f_version(); 87 | } 88 | break; 89 | case U2F_VENDOR_FIRST: 90 | case U2F_VENDOR_LAST: 91 | *rcode = U2F_SW_NO_ERROR; 92 | break; 93 | default: 94 | u2f_hid_set_len(U2F_SW_LENGTH); 95 | *rcode = U2F_SW_INS_NOT_SUPPORTED; 96 | break; 97 | } 98 | 99 | end: 100 | u2f_response_writeback((uint8_t*)rcode,U2F_SW_LENGTH); 101 | u2f_response_flush(); 102 | } 103 | 104 | static uint8_t get_signature_length(uint8_t * sig) 105 | { 106 | return 0x46 + ((sig[32] & 0x80) == 0x80) + ((sig[0] & 0x80) == 0x80); 107 | } 108 | 109 | static void dump_signature_der(uint8_t * sig) 110 | { 111 | uint8_t pad_s = (sig[32] & 0x80) == 0x80; 112 | uint8_t pad_r = (sig[0] & 0x80) == 0x80; 113 | uint8_t i[] = {0x30, 0x44}; 114 | i[1] += (pad_s + pad_r); 115 | 116 | 117 | // DER encoded signature 118 | // write der sequence 119 | // has to be minimum distance and padded with 0x00 if MSB is a 1. 120 | u2f_response_writeback(i,2); 121 | i[1] = 0; 122 | 123 | // length of R value plus 0x00 pad if necessary 124 | u2f_response_writeback("\x02",1); 125 | i[0] = 0x20 + pad_r; 126 | u2f_response_writeback(i,1 + pad_r); 127 | 128 | // R value 129 | u2f_response_writeback(sig, 32); 130 | 131 | // length of S value plus 0x00 pad if necessary 132 | u2f_response_writeback("\x02",1); 133 | i[0] = 0x20 + pad_s; 134 | u2f_response_writeback(i,1 + pad_s); 135 | 136 | // S value 137 | u2f_response_writeback(sig+32, 32); 138 | } 139 | 140 | #include "sanity-check.h" 141 | 142 | static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control) 143 | { 144 | uint8_t users_presence_flag = 1; 145 | uint32_t counter; 146 | 147 | if (control == U2F_AUTHENTICATE_CHECK) 148 | { 149 | u2f_hid_set_len(U2F_SW_LENGTH); 150 | if (u2f_appid_eq(req->key_handle, req->application) == 0) 151 | { 152 | return U2F_SW_CONDITIONS_NOT_SATISFIED; 153 | } 154 | else 155 | { 156 | return U2F_SW_WRONG_DATA; 157 | } 158 | } 159 | 160 | if(req->key_handle_length != U2F_KEY_HANDLE_SIZE){ 161 | u2f_hid_set_len(U2F_SW_LENGTH); 162 | return U2F_SW_WRONG_LENGTH; 163 | } 164 | 165 | if ( 166 | control != U2F_AUTHENTICATE_SIGN || 167 | u2f_appid_eq(req->key_handle, req->application) != 0 || // Order of checks is important 168 | u2f_load_key(req->key_handle, req->application) != 0 169 | ) 170 | { 171 | u2f_hid_set_len(U2F_SW_LENGTH); 172 | return U2F_SW_WRONG_PAYLOAD; 173 | } 174 | 175 | 176 | 177 | if (!sanity_check_passed || u2f_get_user_feedback()) 178 | { 179 | u2f_hid_set_len(U2F_SW_LENGTH); 180 | return U2F_SW_CONDITIONS_NOT_SATISFIED; 181 | } 182 | 183 | counter = u2f_count(); 184 | 185 | u2f_sha256_start_default(); 186 | u2f_sha256_update(req->application,sizeof(req->application)); 187 | u2f_sha256_update(&users_presence_flag,1); 188 | u2f_sha256_update((uint8_t *)&counter,4); 189 | u2f_sha256_update(req->challenge,sizeof(req->challenge)); 190 | 191 | u2f_sha256_finish(); 192 | 193 | if (u2f_ecdsa_sign((uint8_t*)req, req->key_handle, req->application) == -1) 194 | { 195 | return U2F_SW_OPERATION_FAILED; //FIXME custom error code - change to any from spec? 196 | } 197 | 198 | u2f_hid_set_len(U2F_SW_LENGTH + 1 + 4 199 | + get_signature_length((uint8_t*)req)); 200 | 201 | u2f_response_writeback(&users_presence_flag,1); 202 | u2f_response_writeback((uint8_t *)&counter,4); 203 | dump_signature_der((uint8_t*)req); 204 | 205 | return U2F_SW_NO_ERROR; 206 | } 207 | 208 | static int16_t u2f_register(struct u2f_register_request * req) 209 | { 210 | uint8_t i[] = {0x0,U2F_EC_FMT_UNCOMPRESSED}; 211 | 212 | uint8_t key_handle[U2F_KEY_HANDLE_SIZE]; 213 | uint8_t pubkey[U2F_EC_PUBKEY_RAW_SIZE]; 214 | int8_t status_code = 0; 215 | 216 | const uint16_t attest_size = u2f_attestation_cert_size(); 217 | 218 | if (!sanity_check_passed ||u2f_get_user_feedback()) 219 | { 220 | u2f_hid_set_len(U2F_SW_LENGTH); 221 | return U2F_SW_CONDITIONS_NOT_SATISFIED; 222 | } 223 | 224 | status_code = u2f_new_keypair(key_handle, req->application, pubkey); 225 | if (status_code != 0) 226 | { 227 | u2f_hid_set_len(U2F_SW_LENGTH); 228 | return U2F_SW_INSUFFICIENT_MEMORY+status_code; //FIXME non-standard SW 229 | } 230 | 231 | u2f_sha256_start_default(); 232 | u2f_sha256_update(i,1); // 0 233 | u2f_sha256_update(req->application,sizeof(req->application)); 234 | u2f_sha256_update(req->challenge,sizeof(req->challenge)); 235 | u2f_sha256_update(key_handle,sizeof(key_handle)); 236 | u2f_sha256_update(i+1,1); // U2F_EC_FMT_UNCOMPRESSED 237 | u2f_sha256_update(pubkey,sizeof(pubkey)); 238 | u2f_sha256_finish(); 239 | 240 | if (u2f_ecdsa_sign((uint8_t*)req, U2F_ATTESTATION_HANDLE, req->application) == -1) 241 | { 242 | return U2F_SW_WRONG_DATA; 243 | } 244 | 245 | u2f_hid_set_len(2 + 1 246 | + U2F_SW_LENGTH 247 | + sizeof(pubkey) 248 | + get_signature_length((uint8_t*)req) 249 | + U2F_KEY_HANDLE_SIZE 250 | + u2f_attestation_cert_size()); 251 | i[0] = U2F_REGISTER_RESERVED_BYTE; 252 | u2f_response_writeback(i,2); 253 | u2f_response_writeback(pubkey,sizeof(pubkey)); 254 | i[0] = U2F_KEY_HANDLE_SIZE; 255 | u2f_response_writeback(i,1); 256 | u2f_response_writeback(key_handle,U2F_KEY_HANDLE_SIZE); 257 | u2f_response_writeback(u2f_get_attestation_cert(),u2f_attestation_cert_size()); 258 | 259 | dump_signature_der((uint8_t*)req); 260 | 261 | return U2F_SW_NO_ERROR; 262 | } 263 | 264 | static int16_t u2f_version() 265 | { 266 | code const char version[] = "U2F_V2"; 267 | u2f_hid_set_len(U2F_SW_LENGTH + sizeof(version)-1); 268 | u2f_response_writeback(version, sizeof(version)-1); 269 | return U2F_SW_NO_ERROR; 270 | } 271 | 272 | #endif 273 | --------------------------------------------------------------------------------