├── .dockerignore ├── ALPHA_VERSION ├── runtime.txt ├── LICENSE ├── STABLE_VERSION ├── .envrc ├── docs └── solo │ ├── repo-readme.md │ ├── images │ ├── conforms.PNG │ ├── favicon.ico │ ├── solo_conforms.PNG │ └── logo.svg │ ├── index.md │ ├── documenting.md │ ├── metadata-statements.md │ ├── solo-extras.md │ ├── contributing.md │ ├── signed-updates.md │ ├── bootloader-mode.md │ ├── code-overview.md │ ├── porting.md │ └── fido2-impl.md ├── targets └── stm32l432 │ ├── requirements.txt │ ├── src │ ├── cmsis │ │ ├── stm32l4xx.h │ │ ├── stm32l432xx.h │ │ ├── stm32l442xx.h │ │ ├── core_cmFunc.h │ │ ├── core_cmInstr.h │ │ ├── core_cmSimd.h │ │ └── arm_const_structs.h │ ├── u2f_compat.h │ ├── sense.h │ ├── user_feedback.h │ ├── solo.h │ ├── app-common.h │ ├── rng.h │ ├── led_colors.h │ ├── led.h │ ├── flash.h │ ├── init.h │ ├── redirect.c │ ├── main.c │ ├── nfc.h │ ├── fifo.h │ ├── rng.c │ ├── bsp.h │ ├── fifo.c │ ├── app.h │ ├── memory_layout.h │ ├── user_feedback.c │ └── sense.c │ ├── README.md │ ├── bootloader │ ├── version_check.c │ ├── pubkey_bootloader.c │ └── bootloader.h │ ├── lib │ ├── usbd │ │ ├── usbd_composite.h │ │ ├── usbd_ccid.h │ │ ├── usbd_conf.h │ │ └── usbd_desc.h │ └── stm32l4xx_ll_pwr.c │ ├── build │ ├── buildinfo.mk │ ├── common.mk │ ├── bootloader.mk │ └── application.mk │ ├── linker │ ├── bootloader_stm32l4xx_extra.ld │ ├── bootloader_stm32l4xx.ld-old │ ├── bootloader_stm32l4xx.ld.in │ ├── stm32l4xx.ld-old │ ├── stm32l4xx_extra.ld │ └── stm32l4xx.ld.in │ └── cubeconfig_stm32l442.ioc ├── tests ├── ssh-fedora.dockerfile ├── ssh-ubuntu.dockerfile └── ssh-tests.mk ├── tools ├── requirements.txt ├── test_sw_token.sh ├── gencert │ ├── v3.ext │ ├── print_x_y.py │ ├── ca_sign.sh │ ├── genca.sh │ ├── dump_pem.py │ ├── attest │ ├── gen_intermediate.sh │ ├── verify_certs.sh │ └── cbytes.py ├── convert_log_to_c.py ├── nfcmon.py └── gadgetfs │ └── Makefile ├── keys ├── attestation │ ├── device_key-dummy.hex │ ├── dev │ │ ├── device_key.hex │ │ ├── device_cert.der │ │ ├── root_key.pem │ │ ├── device_key.pem │ │ ├── device_key.txt │ │ ├── root_cert.pem │ │ ├── device_cert.pem │ │ ├── device_cert.txt │ │ └── device_cert.cdump │ ├── device_cert.der │ ├── device_cert.pem │ └── device_cert.txt ├── bootloader-dev.pem └── bootloader-dev-public.txt ├── ci-scripts └── copy_common_scripts_key.sh ├── .editorconfig ├── fido2 ├── version.c ├── util.c ├── version.mk ├── data_migration.h ├── util.h ├── cose_key.h ├── version.h ├── extensions │ ├── solo.h │ ├── extensions.h │ ├── wallet.h │ └── solo.c ├── Makefile ├── example_app.h ├── stubs.c ├── storage.h ├── apdu.h ├── ctap_parse.h ├── crypto.h ├── log.h ├── log.c ├── ctap_errors.h ├── ctaphid.h ├── apdu.c └── u2f.h ├── SECURITY.md ├── udev ├── README.md ├── 70-nitrokey-fido2-legacy-access.rules ├── 70-nitrokey-fido2-access.rules └── Makefile ├── .gitmodules ├── .travis.yml ├── in-docker-build.sh ├── MAINTAINERS.md ├── LICENSE-MIT ├── crypto ├── aes-gcm │ └── aes_gcm.c └── sha256 │ └── sha256.h ├── .gitignore ├── Dockerfile ├── .gitlab-ci.yml ├── mkdocs.yml ├── docker_build.mk ├── pc ├── app.h └── main.c └── Makefile /.dockerignore: -------------------------------------------------------------------------------- 1 | *.o 2 | -------------------------------------------------------------------------------- /ALPHA_VERSION: -------------------------------------------------------------------------------- 1 | 2.0.0 2 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | 3.6 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache-2.0 OR MIT 2 | -------------------------------------------------------------------------------- /STABLE_VERSION: -------------------------------------------------------------------------------- 1 | 2.4.0.nitrokey 2 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | source venv/bin/activate 2 | -------------------------------------------------------------------------------- /docs/solo/repo-readme.md: -------------------------------------------------------------------------------- 1 | ../../README.md -------------------------------------------------------------------------------- /targets/stm32l432/requirements.txt: -------------------------------------------------------------------------------- 1 | intelhex 2 | -------------------------------------------------------------------------------- /tests/ssh-fedora.dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:rawhide 2 | RUN dnf install openssh-clients 3 | 4 | -------------------------------------------------------------------------------- /tools/requirements.txt: -------------------------------------------------------------------------------- 1 | ecdsa 2 | intelhex 3 | pyserial 4 | solo-python 5 | pyusb 6 | wheel 7 | -------------------------------------------------------------------------------- /keys/attestation/device_key-dummy.hex: -------------------------------------------------------------------------------- 1 | 8611a1acd28d9dd41fbb5047c030818d5d4d7328baf87bf8141f70d396f2ae14 -------------------------------------------------------------------------------- /tests/ssh-ubuntu.dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:devel 2 | RUN apt update && apt install openssh-client -y 3 | -------------------------------------------------------------------------------- /keys/attestation/dev/device_key.hex: -------------------------------------------------------------------------------- 1 | dcc5ce47acd601a4ab22e13032429db1d57ca1669e40dbd76a5df47d536e8685 2 | -------------------------------------------------------------------------------- /docs/solo/images/conforms.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido2-firmware/HEAD/docs/solo/images/conforms.PNG -------------------------------------------------------------------------------- /docs/solo/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido2-firmware/HEAD/docs/solo/images/favicon.ico -------------------------------------------------------------------------------- /keys/attestation/device_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido2-firmware/HEAD/keys/attestation/device_cert.der -------------------------------------------------------------------------------- /docs/solo/images/solo_conforms.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido2-firmware/HEAD/docs/solo/images/solo_conforms.PNG -------------------------------------------------------------------------------- /keys/attestation/dev/device_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido2-firmware/HEAD/keys/attestation/dev/device_cert.der -------------------------------------------------------------------------------- /targets/stm32l432/src/cmsis/stm32l4xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido2-firmware/HEAD/targets/stm32l432/src/cmsis/stm32l4xx.h -------------------------------------------------------------------------------- /targets/stm32l432/src/cmsis/stm32l432xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido2-firmware/HEAD/targets/stm32l432/src/cmsis/stm32l432xx.h -------------------------------------------------------------------------------- /targets/stm32l432/src/cmsis/stm32l442xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitrokey/nitrokey-fido2-firmware/HEAD/targets/stm32l432/src/cmsis/stm32l442xx.h -------------------------------------------------------------------------------- /tools/test_sw_token.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./main 4 | 5 | while [ $? == 100 ] ; do 6 | echo "Restarting software authentictor." 7 | ./main 8 | done 9 | -------------------------------------------------------------------------------- /targets/stm32l432/README.md: -------------------------------------------------------------------------------- 1 | # STM32L432 Solo 2 | 3 | Check out our [official documentation](https://docs.solokeys.io/solo/building/) 4 | for instructions on building and programming! 5 | -------------------------------------------------------------------------------- /docs/solo/index.md: -------------------------------------------------------------------------------- 1 | Welcome to the technical documentation for [solokeys/solo](https://github.com/solokeys/solo). 2 | 3 | Use the table of contents on the left to browse this documentation. 4 | 5 | -------------------------------------------------------------------------------- /tools/gencert/v3.ext: -------------------------------------------------------------------------------- 1 | subjectKeyIdentifier=hash 2 | authorityKeyIdentifier=keyid,issuer 3 | basicConstraints=CA:FALSE 4 | keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment 5 | -------------------------------------------------------------------------------- /keys/bootloader-dev.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIF8TwXebdPKZSqWCeFwYMNR2ycwXO9tslxZT1UibF0CIoAoGCCqGSM49 3 | AwEHoUQDQgAEttHSg6rJZ3Io307KBSv8VBljK7Do7G2y+tQ3+E0edgegwtI9rxNN 4 | OeKkFTDsHl8jZQMcroPjQ/nRdEhH7I9g0g== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /targets/stm32l432/src/u2f_compat.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef U2F_COMPAT_H 3 | #define U2F_COMPAT_H 4 | 5 | // FIXME finish or remove sanity check handling 6 | #define sanity_check_passed (1) 7 | 8 | #define u2f_delay(ms) delay(ms) 9 | #define data 10 | 11 | 12 | #endif //U2F_COMPAT_H 13 | -------------------------------------------------------------------------------- /targets/stm32l432/src/sense.h: -------------------------------------------------------------------------------- 1 | #ifndef _SENSE_H_ 2 | #define _SENSE_H_ 3 | 4 | #include 5 | 6 | void tsc_init(void); 7 | 8 | int tsc_sensor_exists(void); 9 | 10 | // Read button0 or button1 11 | // Returns 1 if pressed, 0 if not. 12 | uint32_t tsc_read_button(uint32_t index); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /ci-scripts/copy_common_scripts_key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | echo "-----BEGIN OPENSSH PRIVATE KEY-----" > ~/.ssh/common_scripts_key 5 | echo "$COMMON_SCRIPTS_KEY" >> ~/.ssh/common_scripts_key 6 | echo "-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/common_scripts_key 7 | chmod 600 ~/.ssh/common_scripts_key -------------------------------------------------------------------------------- /keys/attestation/dev/root_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BggqhkjOPQMBBw== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MHcCAQEEILvWYfnu4yFDctgZ21wikGrUq4mlP0yfjabMI4/EoXWwoAoGCCqGSM49 6 | AwEHoUQDQgAEBI7GmHY8y5sj87ESy70EL4QhDAkrDs0jbpIVdt2ikAMiiftNpau1 7 | teyLKTL1kSFEYplXhlGKOFvBD6x9v6vT/w== 8 | -----END EC PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /keys/attestation/dev/device_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BggqhkjOPQMBBw== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MHcCAQEEINzFzkes1gGkqyLhMDJCnbHVfKFmnkDb12pd9H1TboaFoAoGCCqGSM49 6 | AwEHoUQDQgAEf72OGV5xGbgBOjTOOt4FWK3tUPHT82EhwCalyGsdZ0siM65jHJOq 7 | f+4TcdFThlnR3jTCN5S+FLYjtlyGBcV4KA== 8 | -----END EC PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /docs/solo/documenting.md: -------------------------------------------------------------------------------- 1 | Documentation of the `master` branch is deployed to Netlify automatically. 2 | 3 | To host or develop locally: 4 | 5 | ``` 6 | pip install mkdocs mkdocs-material markdown-include 7 | ``` 8 | 9 | `mkdocs serve` and visit [localhost:8000](http://localhost:8000). 10 | 11 | The file `runtime.txt` is necessary to tell Netlify to use Python3. 12 | -------------------------------------------------------------------------------- /docs/solo/metadata-statements.md: -------------------------------------------------------------------------------- 1 | For information on what this is, see the [spec](https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-metadata-statement-v2.0-rd-20180702.html#fido2-example). 2 | ## CTAP2 3 | 4 | ``` 5 | {!metadata/Solo-FIDO2-CTAP2-Authenticator.json!} 6 | ``` 7 | 8 | ## U2F 9 | 10 | ``` 11 | {!metadata/Solo-FIDO2-U2F-Authenticator.json!} 12 | ``` 13 | -------------------------------------------------------------------------------- /targets/stm32l432/src/user_feedback.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef USER_FEEDBACK_H 3 | #define USER_FEEDBACK_H 4 | 5 | #include "stdint.h" 6 | 7 | // Delay in milliseconds to wait for user input 8 | #define U2F_MS_USER_INPUT_WAIT 100 9 | 10 | 11 | int8_t u2f_get_user_feedback(); 12 | int8_t u2f_get_user_feedback_extended_wipe(); 13 | 14 | 15 | #endif //CONOR_SOLO_USER_FEEDBACK_H 16 | -------------------------------------------------------------------------------- /tests/ssh-tests.mk: -------------------------------------------------------------------------------- 1 | IMAGE=nkfido2-tests-ssh-ubuntu 2 | KPATH='/root/.ssh/id_ecdsa_sk' 3 | CMD=/usr/bin/ssh-keygen -t ecdsa-sk -f $(KPATH) -v 4 | CMD2=$(CMD) -O resident 5 | .PHONY: ubuntu-ssh 6 | ubuntu-ssh: 7 | sudo docker build -t $(IMAGE) -f ssh-ubuntu.dockerfile . 8 | sudo docker run -it --rm --privileged $(IMAGE) $(CMD) 9 | sudo docker run -it --rm --privileged $(IMAGE) $(CMD2) 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties 2 | 3 | # editorconfig.org 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | end_of_line = lf 9 | indent_style = space 10 | indent_size = 4 11 | tab_width = 4 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | 15 | [Makefile] 16 | indent_style = tab 17 | 18 | [*.{yml,yaml}] 19 | indent_size = 2 20 | -------------------------------------------------------------------------------- /targets/stm32l432/bootloader/version_check.c: -------------------------------------------------------------------------------- 1 | #include "version.h" 2 | 3 | // FIXME test version check function 4 | bool is_newer(const version_t* const newer, const version_t* const older){ 5 | return (newer->major > older->major) || 6 | (newer->major == older->major && newer->minor > older->minor) || 7 | (newer->major == older->major && newer->minor == older->minor && newer->patch >= older->patch); 8 | } 9 | -------------------------------------------------------------------------------- /keys/attestation/dev/device_key.txt: -------------------------------------------------------------------------------- 1 | Private key in various formats: 2 | 3 | [220, 197, 206, 71, 172, 214, 1, 164, 171, 34, 225, 48, 50, 66, 157, 177, 213, 124, 161, 102, 158, 64, 219, 215, 106, 93, 244, 125, 83, 110, 134, 133] 4 | 5 | dcc5ce47acd601a4ab22e13032429db1d57ca1669e40dbd76a5df47d536e8685 6 | 7 | "\xdc\xc5\xce\x47\xac\xd6\x01\xa4\xab\x22\xe1\x30\x32\x42\x9d\xb1\xd5\x7c\xa1\x66\x9e\x40\xdb\xd7\x6a\x5d\xf4\x7d\x53\x6e\x86\x85" 8 | 9 | -------------------------------------------------------------------------------- /tools/gencert/print_x_y.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | import sys 5 | from ecdsa import SigningKey, NIST256p 6 | 7 | sk = SigningKey.from_pem(open(sys.argv[1]).read()) 8 | 9 | 10 | print('Private key in various formats:') 11 | print() 12 | print([c for c in sk.to_string()]) 13 | print() 14 | print(''.join(['%02x' % c for c in sk.to_string()])) 15 | print() 16 | print('"\\x' + '\\x'.join(['%02x' % c for c in sk.to_string()]) + '"') 17 | print() 18 | -------------------------------------------------------------------------------- /fido2/version.c: -------------------------------------------------------------------------------- 1 | #include "version.h" 2 | #include "app.h" 3 | 4 | const version_t firmware_version 5 | #ifdef SOLO 6 | __attribute__ ((section (".flag"))) __attribute__ ((__used__)) 7 | #endif 8 | = { 9 | .major = SOLO_VERSION_MAJ, 10 | .minor = SOLO_VERSION_MIN, 11 | .patch = SOLO_VERSION_PATCH, 12 | .reserved = 0 13 | }; 14 | 15 | 16 | // from tinycbor, for a quick static_assert 17 | #include 18 | cbor_static_assert(sizeof(version_t) == 4); 19 | -------------------------------------------------------------------------------- /tools/gencert/ca_sign.sh: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | [[ "$#" != 4 ]] && echo "usage: $0 " && exit 1 4 | 5 | # generate a "signing request" 6 | echo "generate request" 7 | openssl req -new -key "$1" -out "$1".csr 8 | 9 | # CA sign the request 10 | echo "sign request with CA key" 11 | openssl x509 -days 18250 -req -in "$1".csr -extfile v3.ext -CA "$2" -CAkey "$3" -out "$4" -set_serial 0 12 | 13 | echo "output as der" 14 | openssl x509 -in "$4" -outform der -out "$4".der 15 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | 4 | ## Reporting a Vulnerability 5 | 6 | To report vulnerabilities you have found please contact us with OpenPGP encrypted email: 7 | - szczepan@nitrokey.com, key fingerprint `8681 8406 9239 FF65 DE0B CD7D D9BA E359 91DE 5B22`; 8 | - jan@nitrokey.com, key fingerprint `2D18 9F66 1901 9CA4 E58F AA3C B69C 9138 1B3B 83C7`. 9 | 10 | You can find additional information at: 11 | - https://www.nitrokey.com/contact#e-mail-encryption 12 | - https://www.nitrokey.com/contact 13 | 14 | -------------------------------------------------------------------------------- /udev/README.md: -------------------------------------------------------------------------------- 1 | # Udev rules installation 2 | 3 | 4 | This is for Linux systems only. Check out our [official documentation](https://www.nitrokey.com/documentation/installation) for the details. 5 | 6 | To install the separate Nitrokey FIDO2 udev rules, allowing access to your key, run 7 | 8 | ``` 9 | make setup 10 | ``` 11 | 12 | This should work assuming your system is reasonably up-to-date. If not, try 13 | 14 | ``` 15 | make setup-legacy 16 | ``` 17 | 18 | which would install Udev rules in the legacy format. 19 | -------------------------------------------------------------------------------- /targets/stm32l432/src/solo.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOLO_H_ 2 | #define _SOLO_H_ 3 | 4 | void device_init(); 5 | 6 | void main_loop_delay(); 7 | void usbhid_init(); 8 | void usbhid_close(); 9 | int usbhid_recv(uint8_t * msg); 10 | 11 | void heartbeat(); 12 | 13 | // Called each main loop. Doesn't need to do anything. 14 | void device_manage(); 15 | 16 | void device_init_button(); 17 | 18 | // For Solo hacker 19 | void boot_solo_bootloader(); 20 | void boot_st_bootloader(); 21 | 22 | 23 | void delay(uint32_t ms); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /targets/stm32l432/src/app-common.h: -------------------------------------------------------------------------------- 1 | #ifndef FIDO2_PR_APP_COMMON_H 2 | #define FIDO2_PR_APP_COMMON_H 3 | 4 | 5 | #define USBD_VID 0x20a0 6 | #define USBD_PID 0x42b1 7 | #define USBD_LANGID_STRING 0x409 8 | #define USBD_MANUFACTURER_STRING "Nitrokey" 9 | #define USBD_PRODUCT_FS_STRING SOLO_PRODUCT_NAME 10 | #define USBD_SERIAL_NUM "0123456789ABCDEF" 11 | 12 | #define APP_EXECS_BOOTLOADER 13 | //#define BUTTON_EXECS_BOOTLOADER 14 | 15 | 16 | #endif //FIDO2_PR_APP_COMMON_H 17 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tinycbor"] 2 | path = tinycbor 3 | url = https://github.com/intel/tinycbor 4 | [submodule "crypto/micro-ecc"] 5 | path = crypto/micro-ecc 6 | url = https://github.com/kmackay/micro-ecc.git 7 | [submodule "crypto/tiny-AES-c"] 8 | path = crypto/tiny-AES-c 9 | url = https://github.com/kokke/tiny-AES-c 10 | [submodule "targets/stm32l442/dfuse-tool"] 11 | path = targets/stm32l442/dfuse-tool 12 | url = https://github.com/solokeys/dfuse-tool 13 | [submodule "crypto/cifra"] 14 | path = crypto/cifra 15 | url = https://github.com/solokeys/cifra.git 16 | -------------------------------------------------------------------------------- /fido2/util.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #include 8 | #include 9 | 10 | void dump_hex(uint8_t * buf, int size) 11 | { 12 | while(size--) 13 | { 14 | printf("%02x ", *buf++); 15 | } 16 | printf("\n"); 17 | } 18 | -------------------------------------------------------------------------------- /fido2/version.mk: -------------------------------------------------------------------------------- 1 | 2 | SOLO_VERSION_FULL?=$(shell git describe) 3 | SOLO_VERSION:=$(shell python3 -c 'print("$(SOLO_VERSION_FULL)".split("-")[0])') 4 | SOLO_VERSION_MAJ:=$(shell python3 -c 'print("$(SOLO_VERSION)".split(".")[0])') 5 | SOLO_VERSION_MIN:=$(shell python3 -c 'print("$(SOLO_VERSION)".split(".")[1])') 6 | SOLO_VERSION_PAT:=$(shell python3 -c 'print("$(SOLO_VERSION)".split(".")[2])') 7 | 8 | SOLO_VERSION_FLAGS := -DSOLO_VERSION_MAJ=$(SOLO_VERSION_MAJ) -DSOLO_VERSION_MIN=$(SOLO_VERSION_MIN) \ 9 | -DSOLO_VERSION_PATCH=$(SOLO_VERSION_PAT) -DSOLO_VERSION=\"$(SOLO_VERSION_FULL)\" 10 | -------------------------------------------------------------------------------- /targets/stm32l432/src/rng.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #ifndef _RNG_H_ 9 | #define _RNG_H_ 10 | #include 11 | 12 | void rng_get_bytes(uint8_t * dst, size_t sz); 13 | float shannon_entropy(float * p, size_t sz); 14 | float rng_test(size_t n); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /fido2/data_migration.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #ifndef FIDO2_PR_DATA_MIGRATION_H 9 | #define FIDO2_PR_DATA_MIGRATION_H 10 | 11 | #include "storage.h" 12 | 13 | void do_migration_if_required(AuthenticatorState* state_current); 14 | 15 | #endif //FIDO2_PR_DATA_MIGRATION_H 16 | -------------------------------------------------------------------------------- /targets/stm32l432/lib/usbd/usbd_composite.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_COMPOSITE_H 2 | #define __USB_COMPOSITE_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "usbd_ioreq.h" 9 | 10 | #define MAX_CLASSES 4 11 | 12 | #define MAX_ENDPOINTS 16 13 | 14 | extern USBD_ClassTypeDef USBD_Composite; 15 | 16 | extern int in_endpoint_to_class[MAX_ENDPOINTS]; 17 | 18 | extern int out_endpoint_to_class[MAX_ENDPOINTS]; 19 | 20 | void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1, USBD_ClassTypeDef *class2); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /targets/stm32l432/src/led_colors.h: -------------------------------------------------------------------------------- 1 | #ifndef LED_COLORS_H 2 | #define LED_COLORS_H 3 | 4 | // FIDO2 reset 5 | #define LED_COLOR_DATA_DELETION (0xFF0000) 6 | // firmware update, settings update 7 | #define LED_COLOR_SYSTEM (0xFFFF00) 8 | // touch accepted for the request 9 | #define LED_COLOR_TOUCH_CONSUMED (0x00FF00) 10 | // regular color for all other operations 11 | #define LED_COLOR_REGULAR (0xFFFFFF) 12 | // touch charged 13 | #define LED_COLOR_CHARGED (0x0000FF) 14 | // initial blink just before being ready 15 | #define LED_COLOR_INIT (LED_COLOR_REGULAR) 16 | 17 | #endif //LED_COLORS_H 18 | -------------------------------------------------------------------------------- /fido2/util.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _UTIL_H 8 | #define _UTIL_H 9 | 10 | #include 11 | 12 | void dump_hex(uint8_t * buf, int size); 13 | 14 | #ifndef MIN 15 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) 16 | #endif 17 | 18 | #ifndef MAX 19 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) 20 | #endif 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /docs/solo/solo-extras.md: -------------------------------------------------------------------------------- 1 | # Solo Extras 2 | 3 | ## Random number generation 4 | 5 | Solo contains a True Random Number Generator (TRNG). A TRNG is a hardware based mechanism 6 | that leverages natural phenomenon to generate random numbers, which can be better than a traditional 7 | RNG that has state and updates deterministically using cryptographic methods. 8 | 9 | You can easily access the TRNG stream on Solo using our python tool [`solo-python`](https://github.com/solokeys/solo-python). 10 | 11 | ``` 12 | solo key rng raw > random.bin 13 | ``` 14 | 15 | Or you can seed the state of the RNG on your kernel (`/dev/random`). 16 | 17 | ``` 18 | solo key rng feedkernel 19 | ``` 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | language: c 3 | compiler: gcc 4 | addons: 5 | apt: 6 | sources: 7 | - ubuntu-toolchain-r-test 8 | packages: 9 | - gcc-8 10 | - cppcheck 11 | - python3-venv 12 | - python3-pip 13 | - python3-distutils 14 | - python3-setuptools 15 | - python3-wheel 16 | - make 17 | #services: 18 | # - docker 19 | before_install: 20 | - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa 21 | - sudo apt-get update -q 22 | - sudo apt-get install -y gcc-arm-embedded 23 | - pip3 install -U pip 24 | - pip3 install pynitrokey==0.3.2 25 | script: 26 | - export CC=gcc-8 27 | - make travis 28 | -------------------------------------------------------------------------------- /keys/attestation/dev/root_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN TRUSTED CERTIFICATE----- 2 | MIIBmTCCAT8CFAUT1uavZNaR/FVnRtkOx+tKXvbXMAoGCCqGSM49BAMCME4xCzAJ 3 | BgNVBAYTAkRFMRYwFAYDVQQKDA1OaXRyb2tleSBHbWJIMRAwDgYDVQQLDAdSb290 4 | IENBMRUwEwYDVQQDDAxuaXRyb2tleS5jb20wIBcNMjAwNDI4MDcwNzM5WhgPMjA3 5 | MDA0MTYwNzA3MzlaME4xCzAJBgNVBAYTAkRFMRYwFAYDVQQKDA1OaXRyb2tleSBH 6 | bWJIMRAwDgYDVQQLDAdSb290IENBMRUwEwYDVQQDDAxuaXRyb2tleS5jb20wWTAT 7 | BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQEjsaYdjzLmyPzsRLLvQQvhCEMCSsOzSNu 8 | khV23aKQAyKJ+02lq7W17IspMvWRIURimVeGUYo4W8EPrH2/q9P/MAoGCCqGSM49 9 | BAMCA0gAMEUCIHzMP//x6ZswTk6BOxl1VZ5eK/Kj2aCcf9MprW5ccdHfAiEAxSD8 10 | ICQbI0K9v7fq9JjDxyYPt6ZM0Y/LPsO7qS6/380= 11 | -----END TRUSTED CERTIFICATE----- 12 | -------------------------------------------------------------------------------- /udev/70-nitrokey-fido2-legacy-access.rules: -------------------------------------------------------------------------------- 1 | # Notify ModemManager this device should be ignored 2 | ACTION!="add|change|move", GOTO="mm_usb_device_blacklist_end" 3 | SUBSYSTEM!="usb", GOTO="mm_usb_device_blacklist_end" 4 | ENV{DEVTYPE}!="usb_device", GOTO="mm_usb_device_blacklist_end" 5 | 6 | ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", ENV{ID_MM_DEVICE_IGNORE}="1" 7 | 8 | LABEL="mm_usb_device_blacklist_end" 9 | 10 | # Nitrokey FIDO2 11 | SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", MODE="0660", GROUP="plugdev" 12 | 13 | # Nitrokey FIDO2 development console (not needed) 14 | # SUBSYSTEM=="tty", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", MODE="0660", GROUP="plugdev" 15 | -------------------------------------------------------------------------------- /targets/stm32l432/src/led.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _LED_H_ 8 | #define _LED_H_ 9 | 10 | #include 11 | 12 | #include "led_colors.h" 13 | 14 | void led_rgb(uint32_t hex); 15 | void led_test_colors(); 16 | 17 | #define LED_PIN_G LL_GPIO_PIN_0 18 | #define LED_PIN_B LL_GPIO_PIN_1 19 | #define LED_PIN_R LL_GPIO_PIN_2 20 | #define LED_PORT GPIOA 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /tools/gencert/genca.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | keyname=key.pem 4 | certname=cert.pem 5 | smallcertname=cert.der 6 | curve=prime256v1 7 | 8 | # generate EC private key 9 | openssl ecparam -genkey -name "$curve" -out "$keyname" -rand seed.txt 10 | # generate a "signing request" 11 | openssl req -new -key "$keyname" -out "$keyname".csr -subj "/C=US/ST=Maryland/O=SOLO HACKER/OU=Root CA/CN=solokeys.com/emailAddress=hello@solokeys.com" 12 | # self sign the request 13 | openssl x509 -trustout -req -days 18250 -in "$keyname".csr -signkey "$keyname" -out "$certname" -sha256 14 | 15 | # convert to smaller size format DER 16 | openssl x509 -in $certname -outform der -out $smallcertname 17 | 18 | openssl x509 -in $certname -text -noout 19 | -------------------------------------------------------------------------------- /udev/70-nitrokey-fido2-access.rules: -------------------------------------------------------------------------------- 1 | # Notify ModemManager this device should be ignored 2 | ACTION!="add|change|move", GOTO="mm_usb_device_blacklist_end" 3 | SUBSYSTEM!="usb", GOTO="mm_usb_device_blacklist_end" 4 | ENV{DEVTYPE}!="usb_device", GOTO="mm_usb_device_blacklist_end" 5 | 6 | ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", ENV{ID_MM_DEVICE_IGNORE}="1" 7 | 8 | LABEL="mm_usb_device_blacklist_end" 9 | 10 | # Nitrokey FIDO2 11 | SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", TAG+="uaccess", SYMLINK+="nitrokey-fido2-device" 12 | 13 | # Nitrokey FIDO2 development console (not needed) 14 | SUBSYSTEM=="tty", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", TAG+="uaccess", SYMLINK+="nitrokey-fido2-serial" 15 | -------------------------------------------------------------------------------- /tools/gencert/dump_pem.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | from __future__ import print_function 5 | import sys, fileinput, binascii 6 | 7 | try: 8 | import ecdsa 9 | except: 10 | print('python ecdsa module is required') 11 | print('try running: ') 12 | print(' pip install ecdsa') 13 | sys.exit(1) 14 | 15 | 16 | if len(sys.argv) not in [2]: 17 | print('usage: %s ' % sys.argv[0]) 18 | sys.exit(1) 19 | 20 | pemkey = sys.argv[1] 21 | attestkey = ecdsa.SigningKey.from_pem(open(pemkey).read()) 22 | 23 | hstr = binascii.hexlify(attestkey.to_string()) 24 | print(hstr) 25 | 26 | cstr = '' 27 | it = iter(hstr) 28 | for d1 in it: 29 | d2 = next(it) 30 | cstr += '\\x' + d1 + d2 31 | 32 | print('"%s"' % cstr) 33 | -------------------------------------------------------------------------------- /tools/convert_log_to_c.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | import sys 5 | from sys import argv 6 | 7 | if len(argv) != 2: 8 | print("usage: %s " % argv[0]) 9 | sys.exit(1) 10 | 11 | log = open(argv[1]).readlines() 12 | 13 | nums = [] 14 | 15 | for x in log: 16 | parse = [] 17 | for i in x.split(" "): 18 | try: 19 | n = int(i, 16) 20 | parse.append(n) 21 | except: 22 | pass 23 | if len(parse) == 0: 24 | continue 25 | assert len(parse) == 64 26 | nums.append(parse) 27 | 28 | hexlines = [] 29 | 30 | for l in nums: 31 | s = "" 32 | for x in l: 33 | s += "\\x%02x" % x 34 | hexlines.append(s) 35 | 36 | for x in hexlines: 37 | print('"' + x + '"') 38 | -------------------------------------------------------------------------------- /fido2/cose_key.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _COSE_KEY_H 8 | #define _COSE_KEY_H 9 | 10 | #define COSE_KEY_LABEL_KTY 1 11 | #define COSE_KEY_LABEL_ALG 3 12 | #define COSE_KEY_LABEL_CRV -1 13 | #define COSE_KEY_LABEL_X -2 14 | #define COSE_KEY_LABEL_Y -3 15 | 16 | #define COSE_KEY_KTY_EC2 2 17 | #define COSE_KEY_CRV_P256 1 18 | 19 | #define COSE_ALG_ES256 -7 20 | #define COSE_ALG_ECDH_ES_HKDF_256 -25 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /tools/gencert/attest: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB+zCCAaGgAwIBAgIBADAKBggqhkjOPQQDAjAsMQswCQYDVQQGEwJVUzELMAkG 3 | A1UECAwCTUQxEDAOBgNVBAoMB1RFU1QgQ0EwIBcNMTgwNTEwMDMwNjIwWhgPMjA2 4 | ODA0MjcwMzA2MjBaMHwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDEPMA0GA1UE 5 | BwwGTGF1cmVsMRUwEwYDVQQKDAxURVNUIENPTVBBTlkxIjAgBgNVBAsMGUF1dGhl 6 | bnRpY2F0b3IgQXR0ZXN0YXRpb24xFDASBgNVBAMMC2Nvbm9ycHAuY29tMFkwEwYH 7 | KoZIzj0CAQYIKoZIzj0DAQcDQgAERakCwS6cCjP6PoRQSrgC3E25rxWxtjrqjT8D 8 | A1VlfXA/tAKkl/SDuKb5PNAYrZIMt4paPhRIku8I+Mrq+zKrIKNiMGAwRgYDVR0j 9 | BD8wPaEwpC4wLDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1EMRAwDgYDVQQKDAdU 10 | RVNUIENBggkA98nsifJjlNkwCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwCgYIKoZI 11 | zj0EAwIDSAAwRQIgGDiwRQNpqqe3OGIBrySXXn50ZBuje/fm0695KNvcpYgCIQDN 12 | BvHjqxYhjtjAFK8JT1tz716eS+c1692bbY9988Q61w== 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /keys/bootloader-dev-public.txt: -------------------------------------------------------------------------------- 1 | Signing key for signing device firmware: bootloader.pem 2 | Public key in various formats: 3 | 4 | [182, 209, 210, 131, 170, 201, 103, 114, 40, 223, 78, 202, 5, 43, 252, 84, 25, 99, 43, 176, 232, 236, 109, 178, 250, 212, 55, 248, 77, 30, 118, 7, 160, 194, 210, 61, 175, 19, 77, 57, 226, 164, 21, 48, 236, 30, 95, 35, 101, 3, 28, 174, 131, 227, 67, 249, 209, 116, 72, 71, 236, 143, 96, 210] 5 | 6 | b6d1d283aac9677228df4eca052bfc5419632bb0e8ec6db2fad437f84d1e7607a0c2d23daf134d39e2a41530ec1e5f2365031cae83e343f9d1744847ec8f60d2 7 | 8 | "\xb6\xd1\xd2\x83\xaa\xc9\x67\x72\x28\xdf\x4e\xca\x05\x2b\xfc\x54\x19\x63\x2b\xb0\xe8\xec\x6d\xb2\xfa\xd4\x37\xf8\x4d\x1e\x76\x07\xa0\xc2\xd2\x3d\xaf\x13\x4d\x39\xe2\xa4\x15\x30\xec\x1e\x5f\x23\x65\x03\x1c\xae\x83\xe3\x43\xf9\xd1\x74\x48\x47\xec\x8f\x60\xd2" 9 | 10 | -------------------------------------------------------------------------------- /tools/nfcmon.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | import datetime, sys 5 | from binascii import hexlify 6 | 7 | import Chameleon 8 | 9 | 10 | def verboseLog(text): 11 | formatString = "[{}] {}" 12 | timeString = datetime.datetime.utcnow() 13 | print(formatString.format(timeString, text)) 14 | 15 | 16 | chameleon = Chameleon.Device(verboseLog) 17 | 18 | p = None 19 | for p in Chameleon.Device.listDevices(): 20 | break 21 | 22 | if p: 23 | chameleon.connect(p) 24 | else: 25 | raise RuntimeError("No chameleon mini connected") 26 | 27 | chameleon.execCmd("LOGMODE=LIVE") 28 | 29 | while 1: 30 | b = chameleon.read(1, 20) 31 | h = hexlify(b) 32 | h = h.decode() 33 | sys.stdout.write(h) 34 | sys.stdout.flush() 35 | 36 | chameleon.execCmd("LOGMODE=NONE") 37 | -------------------------------------------------------------------------------- /tools/gencert/gen_intermediate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | keyname=interkey.pem 4 | certname=intercert.pem 5 | smallcertname=intercert.der 6 | curve=prime256v1 7 | 8 | [[ "$#" != 2 ]] && echo "usage: $0 " && exit 1 9 | 10 | # generate EC private key 11 | openssl ecparam -genkey -name "$curve" -out "$keyname" -rand seed.txt 12 | 13 | # generate a "signing request" 14 | openssl req -new -key "$keyname" -out "$keyname".csr -subj "/C=US/ST=Maryland/O=SOLO HACKER/OU=Authenticator Attestation/CN=solokeys.com/emailAddress=hello@solokeys.com" 15 | 16 | # sign the request 17 | openssl x509 -req -days 18250 -in "$keyname".csr -extfile v3.ext -CA "$2" -CAkey "$1" -set_serial 01 -out "$certname" -sha256 18 | 19 | # convert to smaller size format DER 20 | openssl x509 -in $certname -outform der -out $smallcertname 21 | 22 | openssl x509 -in $certname -text -noout 23 | -------------------------------------------------------------------------------- /in-docker-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | cp -rf /solo-base/ /solo/ 3 | 4 | cd /solo/targets/stm32l432 5 | pwd 6 | 7 | out_dir="/builds" 8 | rm -rf ${out_dir}/* 9 | 10 | function build() { 11 | part=${1} 12 | output=${2} 13 | release=${3} 14 | pages=${4} 15 | HWREV=${5:-3} 16 | what="${part}" 17 | 18 | rm -rf release/* 19 | make ${what} RELEASE=${release} PAGES=${pages} HWREV=${HWREV} 20 | mkdir -p ${out_dir}/${output}/ 21 | cp release/* ${out_dir}/${output}/ 22 | } 23 | 24 | build debug-release-buildv debug-256 0 128 25 | build debug-release-buildv debug-128 0 64 26 | build debug-release-buildv debug-128-no-touchbutton-HWREV0 0 64 0 27 | build release-buildv release-256 1 128 28 | build release-buildv release-128 1 64 29 | 30 | arm-none-eabi-gcc --version | head -1 31 | find ${out_dir} -type f | xargs sha256sum | sort || true 32 | echo "done" 33 | -------------------------------------------------------------------------------- /fido2/version.h: -------------------------------------------------------------------------------- 1 | #ifndef _VERSION_H_ 2 | #define _VERSION_H_ 3 | 4 | 5 | #ifndef SOLO_VERSION_MAJ 6 | 7 | #define SOLO_VERSION_MAJ 0 8 | #define SOLO_VERSION_MIN 0 9 | #define SOLO_VERSION_PATCH 0 10 | 11 | #endif 12 | 13 | #define __STR_HELPER(x) #x 14 | #define __STR(x) __STR_HELPER(x) 15 | 16 | #ifndef SOLO_VERSION 17 | #define SOLO_VERSION __STR(SOLO_VERSION_MAJ) "." __STR(SOLO_VERSION_MIN) "." __STR(SOLO_VERSION_PATCH) 18 | #endif 19 | 20 | #include 21 | #include 22 | 23 | typedef struct { 24 | union{ 25 | uint32_t raw; 26 | struct { 27 | uint8_t major; 28 | uint8_t minor; 29 | uint8_t patch; 30 | uint8_t reserved; 31 | }; 32 | }; 33 | } version_t; 34 | 35 | bool is_newer(const version_t* const newer, const version_t* const older); 36 | extern const version_t firmware_version ; 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /tools/gencert/verify_certs.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 SoloKeys, Inc. 3 | # 4 | # 5 | 6 | # verify that the root CA/keypair and intermediate CA/keypairs are set up correctly. 7 | 8 | [[ "$#" != 4 ]] && echo "usage: $0 " && exit 1 9 | 10 | ikey=$1 11 | icert=$2 12 | 13 | rkey=$3 14 | rcert=$4 15 | 16 | echo 'challenge $RANDOM' > chal.txt 17 | 18 | # check that they are actual key pairs 19 | openssl dgst -sha256 -sign "$ikey" -out sig.txt chal.txt 20 | openssl dgst -sha256 -verify <(openssl x509 -in "$icert" -pubkey -noout) -signature sig.txt chal.txt 21 | 22 | openssl dgst -sha256 -sign "$rkey" -out sig.txt chal.txt 23 | openssl dgst -sha256 -verify <(openssl x509 -in "$rcert" -pubkey -noout) -signature sig.txt chal.txt 24 | 25 | # Check they are a chain 26 | openssl verify -verbose -CAfile "$rcert" "$icert" 27 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | ## Firmware release process 2 | 1. Tag the commit to be released with the next firmware version 3 | 1. Build the firmware using Docker 4 | 2. Sign the binary firmware 5 | 3. Upload signed binary to the Github releases 6 | 4. Bump ./STABLE_RELEASE file with the latest version 7 | 5. Run update script on the update server (if needed) 8 | 9 | ## Signing firmware 10 | 11 | To sign the firmware it suffices to call pynitrokey like this: 12 | 13 | ```text 14 | nitropy fido2 util sign VERIFYING_KEY APP_HEX OUTPUT_JSON 15 | ``` 16 | 17 | ### 128kB variant 18 | 19 | During the firmware signing the smaller MCU version has to be indicated during signing with the `--pages` switch, like: 20 | 21 | ```text 22 | nitropy fido2 util sign --pages 64 .... 23 | ``` 24 | 25 | The rest of the invocation is the same, e.g.: 26 | ```text 27 | nitropy fido2 util sign --pages 64 VERIFYING_KEY APP_HEX OUTPUT_JSON 28 | ``` -------------------------------------------------------------------------------- /targets/stm32l432/build/buildinfo.mk: -------------------------------------------------------------------------------- 1 | 2 | $(TARGET)-linking.buildinfo: $(TARGET).elf 3 | 4 | $(TARGET)-sections.buildinfo: $(TARGET)-linking.buildinfo 5 | grep -o -E "removing unused section '.*?' in file '.*?'" $< | sort | uniq -c | sort -k1rn > $@ 6 | 7 | 8 | .PHONY: $(TARGET).buildinfo 9 | $(TARGET).buildinfo: 10 | date > $@ 11 | $(CC) --version >> $@ 12 | -git describe --long >> $@ 13 | -git describe --long --all >> $@ 14 | @echo CC=$(CC) >> $@ 15 | @echo CFLAGS=$(CFLAGS) >> $@ 16 | @echo >> $@ 17 | @echo LDFLAGS=$(LDFLAGS) >> $@ 18 | @echo AOBJARM=$(AOBJARM) >> $@ 19 | @echo THUMB=$(THUMB) >> $@ 20 | @echo ALL_CFLAGS=$(ALL_CFLAGS) >> $@ 21 | @echo AOBJ=$(AOBJ) >> $@ 22 | @echo COBJARM=$(COBJARM) >> $@ 23 | @echo COBJ=$(COBJ) >> $@ 24 | @echo CPPOBJ=$(CPPOBJ) >> $@ 25 | @echo CPPOBJARM=$(CPPOBJARM) >> $@ 26 | @echo ECC_CFLAGS=$(ECC_CFLAGS) >> $@ 27 | @echo "Writing build information to $@" 28 | -------------------------------------------------------------------------------- /targets/stm32l432/src/flash.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _FLASH_H_ 8 | #define _FLASH_H_ 9 | 10 | void flash_erase_page(uint8_t page); 11 | void flash_write_dword(uint32_t addr, uint64_t data); 12 | void flash_write(uint32_t addr, uint8_t * data, size_t sz); 13 | void flash_write_fast(uint32_t addr, uint32_t * data); 14 | void flash_option_bytes_init(int boot_from_dfu); 15 | 16 | #define FLASH_PAGE_SIZE 2048 17 | 18 | #define flash_addr(page) (0x08000000 + ((page)*FLASH_PAGE_SIZE)) 19 | 20 | #define FLASH_PAGE_START 0 21 | #define FLASH_PAGE_END 127 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /docs/solo/contributing.md: -------------------------------------------------------------------------------- 1 | We are very open to contributions! 2 | 3 | [Currently](https://github.com/solokeys/solo/issues), most work will go towards 4 | 5 | * ~~implementing STM32L432~~ 6 | * implementing NFC 7 | * adding documentation and improving accessability of the code 8 | 9 | In the future, we would love to see creative plugins/extensions, putting the TRNG and other features of the STM32L432 to good use! 10 | 11 | Feel free to send a [pull request](https://github.com/solokeys/solo/pulls) at any time, please note that we do require a lightweight copyright license agreement in order to accept contributions. Reason and procedure: . 12 | 13 | If you want to discuss your plans in quasi-realtime beforehand, you can also join our [solokeys.public](https://keybase.io/team/solokeys.public) Keybase team. 14 | 15 | But first: [join our mailing list!](https://solokeys.us19.list-manage.com/subscribe/post?u=cc0c298fb99cd136bdec8294b&id=6550fc947a) 16 | -------------------------------------------------------------------------------- /keys/attestation/device_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICcjCCAhigAwIBAgIBATAKBggqhkjOPQQDAjBOMQswCQYDVQQGEwJERTEWMBQG 3 | A1UECgwNTml0cm9rZXkgR21iSDEQMA4GA1UECwwHUm9vdCBDQTEVMBMGA1UEAwwM 4 | bml0cm9rZXkuY29tMCAXDTIwMDUwODA5MzUzNVoYDzIwNzAwNDI2MDkzNTM1WjBg 5 | MQswCQYDVQQGEwJERTEWMBQGA1UECgwNTml0cm9rZXkgR21iSDEiMCAGA1UECwwZ 6 | QXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEVMBMGA1UEAwwMbml0cm9rZXkuY29t 7 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtqgCHQndSI8x2+N+JtbNpUQRwzQn 8 | kyBuUQoMfyzIh7mnPEq0ZCq3jKHYw4CfcSzCmnNd7y2kZiWgOs9Ja9ICh6OB0jCB 9 | zzAdBgNVHQ4EFgQULltFflYQtOXdtKkoC9Ef6P7lxkYwcwYDVR0jBGwwaqFSpFAw 10 | TjELMAkGA1UEBhMCREUxFjAUBgNVBAoMDU5pdHJva2V5IEdtYkgxEDAOBgNVBAsM 11 | B1Jvb3QgQ0ExFTATBgNVBAMMDG5pdHJva2V5LmNvbYIUFmIElunZ9P8tpEnxfCX2 12 | qFfrZugwCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwIQYLKwYBBAGC5RwBAQQEEgQQ 13 | w577pvz0TD6Ci/xKYRWg/zAKBggqhkjOPQQDAgNIADBFAiAkOHFZwI/nne/DyNxy 14 | aoLCYkuvgm+ydAscXx8BDL5OVAIhAJqbbWFLhG+N99aal5Zl4oxPWAxRARbG3qtW 15 | gwRf0Lsa 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /keys/attestation/dev/device_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICcjCCAhigAwIBAgIBATAKBggqhkjOPQQDAjBOMQswCQYDVQQGEwJERTEWMBQG 3 | A1UECgwNTml0cm9rZXkgR21iSDEQMA4GA1UECwwHUm9vdCBDQTEVMBMGA1UEAwwM 4 | bml0cm9rZXkuY29tMCAXDTIwMDUwODEyMDAwNFoYDzIwNzAwNDI2MTIwMDA0WjBg 5 | MQswCQYDVQQGEwJERTEWMBQGA1UECgwNTml0cm9rZXkgR21iSDEiMCAGA1UECwwZ 6 | QXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEVMBMGA1UEAwwMbml0cm9rZXkuY29t 7 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEf72OGV5xGbgBOjTOOt4FWK3tUPHT 8 | 82EhwCalyGsdZ0siM65jHJOqf+4TcdFThlnR3jTCN5S+FLYjtlyGBcV4KKOB0jCB 9 | zzAdBgNVHQ4EFgQUHNj/6wvh/Sn9X7GynD6spnnmcvIwcwYDVR0jBGwwaqFSpFAw 10 | TjELMAkGA1UEBhMCREUxFjAUBgNVBAoMDU5pdHJva2V5IEdtYkgxEDAOBgNVBAsM 11 | B1Jvb3QgQ0ExFTATBgNVBAMMDG5pdHJva2V5LmNvbYIUBRPW5q9k1pH8VWdG2Q7H 12 | 60pe9tcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwIQYLKwYBBAGC5RwBAQQEEgQQ 13 | w577pvz0TD6Ci/xKYRWg/zAKBggqhkjOPQQDAgNIADBFAiEAn4VCdNPhI78V2+tB 14 | tundQ6NEddPdJpyy9gkA7HWHKLwCIAGysWQSBf/3lsZEuyYUZAVaXt00AjTFn04y 15 | Nq+w5GwD 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /fido2/extensions/solo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 SoloKeys, Inc. 3 | * 4 | * This file is part of Solo. 5 | * 6 | * Solo is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Solo is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Solo. If not, see 18 | * 19 | * This code is available under licenses for commercial use. 20 | * Please contact SoloKeys for more information. 21 | */ 22 | #ifndef SOLO_H_ 23 | #define SOLO_H_ 24 | 25 | int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /udev/Makefile: -------------------------------------------------------------------------------- 1 | # On modern systems, udev has a TAG uaccess, which is used in 73-seat-late.rules 2 | # On older systems, we use GROUP plugdev with MODE 3 | # --> Try `make setup` first, if it doesn't work, try `make legacy-setup`. 4 | 5 | 6 | setup: | install activate 7 | @echo "*** Setup finished. You can now use the Nitrokey FIDO2 device." 8 | 9 | legacy-setup: | install-legacy activate 10 | @echo "*** Setup for the legacy systems finished. You can now use the Nitrokey FIDO2 device." 11 | 12 | RULES_PATH=/etc/udev/rules.d 13 | 14 | activate: 15 | @echo "*** This action will reload the udev deamon" 16 | sudo udevadm control --reload-rules 17 | sudo udevadm trigger 18 | 19 | install: 20 | @echo "*** This action will copy the rules file to the $(RULES_PATH) directory" 21 | sudo cp $(PWD)/70-nitrokey-fido2-access.rules ${RULES_PATH}/70-nitrokey-fido2-access.rules 22 | 23 | install-legacy: 24 | @echo "*** This action will copy the legacy rules file to the $(RULES_PATH) directory" 25 | sudo cp $(PWD)/70-nitrokey-fido2-legacy-access.rules ${RULES_PATH}/70-nitrokey-fido2-access.rules 26 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /crypto/aes-gcm/aes_gcm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "aes.h" 7 | #include "crypto.h" 8 | #include "util.h" 9 | 10 | #define BLOCK_SIZE 16 11 | 12 | static struct AES_ctx aes_ctx; 13 | 14 | // void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); 15 | 16 | int8_t crypto_aes256_gcm_encrypt(uint8_t * data, uint32_t length, uint8_t * authtag) 17 | { 18 | memset(authtag, 0, BLOCK_SIZE); 19 | AES_CTR_xcrypt_buffer(&aes_ctx, authtag, BLOCK_SIZE); 20 | 21 | return 0; 22 | } 23 | 24 | #ifdef TEST 25 | 26 | int main(int argc, char * argv[]) 27 | { 28 | uint8_t nonce[16]; 29 | uint8_t key[32]; 30 | uint8_t authtag[BLOCK_SIZE]; 31 | 32 | // uint8_t * authtag1 = (uint8_t *)"\x53\x0f\x8a\xfb\xc7\x45\x36\xb9\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b"; 33 | 34 | memset(nonce,0,16); 35 | memset(key,0,16); 36 | 37 | AES_init_ctx_iv(&aes_ctx, key, nonce); 38 | 39 | crypto_aes256_gcm_encrypt(NULL, 0, authtag); 40 | 41 | printf("Auth tag: "); dump_hex(authtag, BLOCK_SIZE); 42 | 43 | 44 | return 0; 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | targets/*/*.hex 38 | targets/*/*.sha2 39 | 40 | # Debug files 41 | *.dSYM/ 42 | *.su 43 | *.idb 44 | *.pdb 45 | 46 | # Kernel Module Compile Results 47 | *.mod* 48 | *.cmd 49 | .tmp_versions/ 50 | modules.order 51 | Module.symvers 52 | Mkfile.old 53 | dkms.conf 54 | 55 | *.swp 56 | *.pem 57 | *.der 58 | *.csr 59 | *.stackdump 60 | 61 | tools/attest 62 | 63 | sdk_15.0.0/ 64 | _build/ 65 | 66 | GNU\ * 67 | Keil\ * 68 | efm32/hw 69 | 70 | mbedtls/ 71 | sl_crypto/ 72 | tools/python-fido2/* 73 | *.pem 74 | *.bin 75 | *.key 76 | site/ 77 | _site/ 78 | venv/ 79 | env2/ 80 | env3/ 81 | .project 82 | .tags* 83 | targets/*/docs/ 84 | main 85 | 86 | builds/* 87 | tools/testing/.idea/* 88 | tools/testing/tests/__pycache__/* 89 | *.gcda 90 | *.gcno 91 | *.234r.expand 92 | -------------------------------------------------------------------------------- /targets/stm32l432/src/init.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 SoloKeys, Inc. 3 | * 4 | * This file is part of Solo. 5 | * 6 | * Solo is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Solo is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Solo. If not, see 18 | * 19 | * This code is available under licenses for commercial use. 20 | * Please contact SoloKeys for more information. 21 | */ 22 | #ifndef _INIT_H_ 23 | #define _INIT_H_ 24 | 25 | void init_usb(void); 26 | void init_gpio(void); 27 | void init_debug_uart(void); 28 | void init_pwm(void); 29 | void init_millisecond_timer(int lf); 30 | void init_rng(void); 31 | void init_spi(void); 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /fido2/Makefile: -------------------------------------------------------------------------------- 1 | include version.mk 2 | 3 | ifndef APP_CONFIG 4 | APP_CONFIG=example_app.h 5 | endif 6 | 7 | INC = -I./ -I./extensions 8 | INC += -I../tinycbor/src 9 | INC += -I../crypto/sha256 -I../crypto/micro-ecc -I../crypto/tiny-AES-c 10 | INC += -I../crypto/cifra/src -I../crypto/cifra/src/ext 11 | 12 | INT_CFLAGS = -DAPP_CONFIG=\"$(APP_CONFIG)\" 13 | INT_CFLAGS += $(INC) 14 | INT_CFLAGS += $(SOLO_VERSION_FLAGS) 15 | 16 | SRC = apdu.c util.c u2f.c test_power.c 17 | SRC += stubs.c log.c ctaphid.c ctap.c 18 | SRC += ctap_parse.c crypto.c 19 | SRC += device.c 20 | SRC += version.c 21 | SRC += data_migration.c 22 | SRC += extensions/extensions.c extensions/solo.c 23 | SRC += extensions/wallet.c 24 | 25 | # Crypto libs 26 | SRC += ../crypto/sha256/sha256.c ../crypto/micro-ecc/uECC.c ../crypto/tiny-AES-c/aes.c 27 | SRC += ../crypto/cifra/src/sha512.c ../crypto/cifra/src/blockwise.c 28 | 29 | OBJ = $(SRC:.c=.o) 30 | 31 | all: libsolo.a 32 | 33 | libsolo.a: $(OBJ) 34 | $(AR) cqs $@ $^ 35 | 36 | %.o: %.c 37 | $(CC) $^ $(INT_CFLAGS) $(CFLAGS) -c -o $@ 38 | 39 | ../crypto/micro-ecc/uECC.o: ../crypto/micro-ecc/uECC.c 40 | $(CC) $^ $(INT_CFLAGS) $(ECC_CFLAGS) -c -o $@ 41 | 42 | clean: 43 | rm -f $(OBJ) libsolo.a 44 | 45 | -------------------------------------------------------------------------------- /tools/gencert/cbytes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | from __future__ import print_function 5 | import base64 6 | 7 | """ 8 | cbytes.py 9 | 10 | Output a c file with the DER certificate. 11 | Read der file as input 12 | """ 13 | import sys, fileinput, binascii 14 | 15 | if len(sys.argv) not in [2, 3]: 16 | print('usage: %s [-s]' % sys.argv[0]) 17 | print(' -s: just output c string (for general use)') 18 | sys.exit(1) 19 | 20 | buf = None 21 | try: 22 | buf = bytearray(open(sys.argv[1], 'rb').read()) 23 | except: 24 | n = sys.argv[1].replace('\n', '') 25 | n = sys.argv[1].replace('\r', '') 26 | buf = bytearray(binascii.unhexlify(n)) 27 | 28 | c_str = '' 29 | size = len(buf) 30 | 31 | a = ''.join(map(lambda c: '\\x%02x' % c, buf)) 32 | 33 | for i in range(0, len(a), 80): 34 | c_str += "\"" + a[i : i + 80] + "\"\n" 35 | 36 | if '-s' in sys.argv: 37 | print(c_str) 38 | sys.exit(0) 39 | 40 | print('// generated') 41 | print('#include ') 42 | print() 43 | print('code uint8_t __attest[] = \n%s;' % c_str) 44 | print('const uint16_t __attest_size = sizeof(__attest)-1;') 45 | 46 | b = base64.b64encode(buf) 47 | print('b64: ') 48 | print(b) 49 | -------------------------------------------------------------------------------- /fido2/extensions/extensions.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef EXTENSIONS_H_ 8 | #define EXTENSIONS_H_ 9 | #include "u2f.h" 10 | #include "apdu.h" 11 | 12 | int16_t bridge_u2f_to_extensions(uint8_t * chal, uint8_t * appid, uint8_t klen, uint8_t * keyh); 13 | 14 | // return 1 if request is a wallet request 15 | int is_extension_request(uint8_t * req, int len); 16 | 17 | int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len); 18 | 19 | int16_t extend_fido2(CredentialId * credid, uint8_t * output); 20 | 21 | int bootloader_bridge(int klen, uint8_t * keyh); 22 | 23 | int is_extension_request(uint8_t * kh, int len); 24 | 25 | 26 | void extension_writeback_init(uint8_t * buffer, uint8_t size); 27 | void extension_writeback(uint8_t * buf, uint8_t size); 28 | 29 | typedef enum { 30 | REQ_SRC_UNKNOWN = 0, 31 | REQ_SRC_U2F, 32 | REQ_SRC_FIDO2, 33 | } ReqSrcEnum; 34 | ReqSrcEnum get_request_source(void); 35 | 36 | 37 | #endif /* EXTENSIONS_H_ */ 38 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.10 2 | MAINTAINER Nitrokey 3 | 4 | # Install necessary packages 5 | RUN apt-get update \ 6 | && apt-get install -y --no-install-recommends \ 7 | ca-certificates \ 8 | make \ 9 | wget \ 10 | bzip2 \ 11 | git \ 12 | python3 \ 13 | python3-pip \ 14 | && rm -rf /var/lib/apt/lists/* 15 | 16 | ENV GCC_URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2018q4/gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2?revision=d830f9dd-cd4f-406d-8672-cca9210dd220?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,8-2018-q4-major" 17 | ENV GCC_NAME="gcc-arm-none-eabi-8-2018-q4-major" 18 | ENV GCC_SHA256="fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 gcc.tar.bz2" 19 | ENV GCC_MD5="f55f90d483ddb3bcf4dae5882c2094cd gcc.tar.bz2" 20 | 21 | # Install ARM compiler 22 | RUN set -eux; \ 23 | wget -O gcc.tar.bz2 ${GCC_URL} || echo "Wget returned error"; \ 24 | echo ${GCC_MD5} | md5sum -c -; \ 25 | echo ${GCC_SHA256} | sha256sum -c -; \ 26 | tar -C /opt -xf gcc.tar.bz2; \ 27 | rm gcc.tar.bz2; 28 | 29 | ENV PATH="/opt/${GCC_NAME}/bin/:${PATH}" 30 | 31 | RUN pip install -U git+https://github.com/Nitrokey/pynitrokey 32 | RUN pip install -U fido2==0.8.1 33 | RUN nitropy version && arm-none-eabi-gcc --version | head -1 34 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | include: 'https://raw.githubusercontent.com/Nitrokey/common-ci-jobs/master/common_jobs.yml' 2 | 3 | stages: 4 | - pull-github 5 | - build 6 | - deploy 7 | 8 | variables: 9 | REPO_NAME: nitrokey-fido2-firmware 10 | MAIN_BRANCH: master 11 | 12 | build: 13 | rules: 14 | - if: '$CI_PIPELINE_SOURCE == "push"' 15 | - if: '$CI_PIPELINE_SOURCE == "schedule"' 16 | - if: '$CI_PIPELINE_SOURCE == "web"' 17 | tags: 18 | - lxc 19 | stage: build 20 | script: 21 | - make ci 22 | - mv builds artifacts 23 | after_script: 24 | - wget $icon_server/checkmark/$CI_COMMIT_REF_NAME/$CI_COMMIT_SHA/$CI_JOB_NAME/$CI_JOB_STATUS/${CI_JOB_URL#*/*/*/} 25 | artifacts: 26 | paths: 27 | - artifacts 28 | 29 | 30 | build-simulation: 31 | rules: 32 | - if: '$CI_PIPELINE_SOURCE == "push"' 33 | - if: '$CI_PIPELINE_SOURCE == "schedule"' 34 | - if: '$CI_PIPELINE_SOURCE == "web"' 35 | image: ubuntu:20.04 36 | tags: 37 | - lxc 38 | stage: build 39 | before_script: 40 | - apt update -y 41 | - apt install -y git make make python3 42 | - git submodule update --init --recursive --recommend-shallow 43 | script: 44 | - make all 45 | after_script: 46 | - wget $icon_server/checkmark/$CI_COMMIT_REF_NAME/$CI_COMMIT_SHA/$CI_JOB_NAME/$CI_JOB_STATUS/${CI_JOB_URL#*/*/*/} 47 | 48 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Solo Technical Documentation 2 | site_author: SoloKeys 3 | site_description: 'Documentation for the SoloKeys solo software' 4 | site_url: 'https://docs.solokeys.io/solo/' 5 | repo_url: 'https://github.com/solokeys/solo' 6 | repo_name: 'solokeys/solo' 7 | copyright: 'Copyright © 2018 - 2019 SoloKeys' 8 | 9 | nav: 10 | - Home: solo/index.md 11 | - FIDO2 Implementation: solo/fido2-impl.md 12 | - Metadata Statements: solo/metadata-statements.md 13 | - Build instructions: solo/building.md 14 | - Programming instructions: solo/programming.md 15 | - Bootloader mode: solo/bootloader-mode.md 16 | - Customization: solo/customization.md 17 | - Solo Extras: solo/solo-extras.md 18 | - Application Ideas: solo/application-ideas.md 19 | - Running on Nucleo32 board: solo/nucleo32-board.md 20 | - Signed update process: solo/signed-updates.md 21 | - Usage and Porting guide: solo/porting.md 22 | - Code documentation: solo/code-overview.md 23 | - Contributing Code: solo/contributing.md 24 | - Contributing Docs: solo/documenting.md 25 | - udev Rules: solo/udev.md 26 | - About: solo/repo-readme.md 27 | 28 | theme: 29 | name: material 30 | logo: 'solo/images/logo.svg' 31 | favicon: 'solo/images/favicon.ico' 32 | 33 | markdown_extensions: 34 | - markdown_include.include 35 | -------------------------------------------------------------------------------- /crypto/sha256/sha256.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha256.h 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Defines the API for the corresponding SHA1 implementation. 7 | *********************************************************************/ 8 | 9 | #ifndef SHA256_H 10 | #define SHA256_H 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | 15 | /****************************** MACROS ******************************/ 16 | #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest 17 | 18 | /**************************** DATA TYPES ****************************/ 19 | typedef unsigned char BYTE; // 8-bit byte 20 | typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines 21 | 22 | typedef struct { 23 | BYTE data[64]; 24 | WORD datalen; 25 | unsigned long long bitlen; 26 | WORD state[8]; 27 | } SHA256_CTX; 28 | 29 | /*********************** FUNCTION DECLARATIONS **********************/ 30 | void sha256_init(SHA256_CTX *ctx); 31 | void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); 32 | void sha256_final(SHA256_CTX *ctx, BYTE hash[]); 33 | 34 | #endif // SHA256_H 35 | -------------------------------------------------------------------------------- /docker_build.mk: -------------------------------------------------------------------------------- 1 | DOCKER_TOOLCHAIN_IMAGE := nitrokey/nitrokey-fido2-firmware-build 2 | 3 | docker-build-toolchain: 4 | docker build -t $(DOCKER_TOOLCHAIN_IMAGE) . 5 | docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION} 6 | docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ} 7 | docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}.${SOLO_VERSION_MIN} 8 | 9 | uncached-docker-build-toolchain: 10 | docker build --no-cache -t $(DOCKER_TOOLCHAIN_IMAGE) . 11 | docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION} 12 | docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ} 13 | docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}.${SOLO_VERSION_MIN} 14 | 15 | docker-build-all: 16 | docker run --rm -v "$(CURDIR)/builds:/builds" \ 17 | -v "$(CURDIR):/solo-base:ro" \ 18 | $(DOCKER_TOOLCHAIN_IMAGE) "solo-base/in-docker-build.sh" ${SOLO_VERSION_FULL} 19 | # -u $(shell id -u ${USER}):$(shell id -g ${USER}) \ # this was in line 18 but it breaks the ci 20 | 21 | test-docker: 22 | rm -rf builds/* 23 | $(MAKE) uncached-docker-build-toolchain 24 | NTAGS=$$(docker images | grep -c "$(DOCKER_TOOLCHAIN_IMAGE)") && [ $$NTAGS -eq 4 ] 25 | $(MAKE) docker-build-all 26 | -------------------------------------------------------------------------------- /pc/app.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #ifndef SRC_APP_H_ 9 | #define SRC_APP_H_ 10 | #include 11 | 12 | #define USING_DEV_BOARD 13 | 14 | #define USING_PC 15 | 16 | #define DEBUG_LEVEL 1 17 | 18 | #define ENABLE_U2F 19 | #define ENABLE_U2F_EXTENSIONS 20 | //#define BRIDGE_TO_WALLET 21 | 22 | void printing_init(); 23 | 24 | 25 | // 0xRRGGBB 26 | #define LED_INIT_VALUE 0x000800 27 | #define LED_WINK_VALUE 0x000008 28 | #define LED_MAX_SCALER 30 29 | #define LED_MIN_SCALER 1 30 | // # of ms between each change in LED 31 | #define HEARTBEAT_PERIOD 100 32 | // Each LED channel will be multiplied by a integer between LED_MAX_SCALER 33 | // and LED_MIN_SCALER to cause the slow pulse. E.g. 34 | // #define LED_INIT_VALUE 0x301000 35 | // #define LED_MAX_SCALER 30 36 | // #define LED_MIN_SCALER 1 37 | // #define HEARTBEAT_PERIOD 8 38 | // Will pulse from 0x301000 to 0x903000 to 0x301000 ... 39 | // Which will take ~8 * (30)*2 ms 40 | 41 | 42 | #endif /* SRC_APP_H_ */ 43 | -------------------------------------------------------------------------------- /fido2/example_app.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #ifndef SRC_APP_H_ 9 | #define SRC_APP_H_ 10 | #include 11 | 12 | #define USING_DEV_BOARD 13 | 14 | #define USING_PC 15 | 16 | #define ENABLE_U2F 17 | #define ENABLE_U2F_EXTENSIONS 18 | //#define BRIDGE_TO_WALLET 19 | 20 | void printing_init(); 21 | 22 | extern bool use_udp; 23 | 24 | // 0xRRGGBB 25 | #define LED_INIT_VALUE 0x000800 26 | #define LED_WINK_VALUE 0x000008 27 | #define LED_MAX_SCALER 30 28 | #define LED_MIN_SCALER 1 29 | // # of ms between each change in LED 30 | #define HEARTBEAT_PERIOD 100 31 | // Each LED channel will be multiplied by a integer between LED_MAX_SCALER 32 | // and LED_MIN_SCALER to cause the slow pulse. E.g. 33 | // #define LED_INIT_VALUE 0x301000 34 | // #define LED_MAX_SCALER 30 35 | // #define LED_MIN_SCALER 1 36 | // #define HEARTBEAT_PERIOD 8 37 | // Will pulse from 0x301000 to 0x903000 to 0x301000 ... 38 | // Which will take ~8 * (30)*2 ms 39 | 40 | 41 | #endif /* SRC_APP_H_ */ 42 | -------------------------------------------------------------------------------- /fido2/stubs.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #include 8 | #include "device.h" 9 | #include "util.h" 10 | #include "ctap.h" 11 | #include "u2f.h" 12 | 13 | #if defined(STUB_CTAPHID) || defined(STUB_CTAP) 14 | 15 | 16 | 17 | void ctap_init() 18 | { 19 | printf1(TAG_GEN,"STUB: ctap_init\n"); 20 | } 21 | #endif 22 | 23 | #if defined(STUB_CTAPHID) 24 | void ctaphid_init() 25 | { 26 | printf1(TAG_GEN,"STUB: ctaphid_init\n"); 27 | } 28 | void ctaphid_handle_packet(uint8_t * hidmsg) 29 | { 30 | printf1(TAG_GEN,"STUB: ctaphid_handle_packet\n"); 31 | } 32 | 33 | void ctaphid_check_timeouts() 34 | { 35 | 36 | } 37 | 38 | #endif 39 | 40 | 41 | #ifdef STUB_CTAP 42 | 43 | void ctap_reset_state() 44 | { 45 | printf1(TAG_GEN,"STUB: ctap_reset_state\n"); 46 | } 47 | 48 | void ctap_response_init(CTAP_RESPONSE * resp) 49 | { 50 | } 51 | 52 | void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) 53 | { 54 | printf1(TAG_GEN,"STUB: u2f_request\n"); 55 | } 56 | 57 | uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp) 58 | { 59 | printf1(TAG_GEN,"STUB: ctap_request\n"); 60 | return 0; 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /targets/stm32l432/src/redirect.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #include "stm32l4xx_ll_usart.h" 8 | #include "usbd_cdc_if.h" 9 | 10 | #include APP_CONFIG 11 | #include "fifo.h" 12 | 13 | #if DEBUG_LEVEL>0 14 | 15 | void _putchar(char c) 16 | { 17 | #if NON_BLOCK_PRINTING 18 | fifo_debug_add(&c); 19 | #else 20 | while (! LL_USART_IsActiveFlag_TXE(DEBUG_UART)) 21 | ; 22 | LL_USART_TransmitData8(DEBUG_UART,c); 23 | #endif 24 | } 25 | 26 | 27 | int _write (int fd, const void *buf, unsigned long int len) 28 | { 29 | uint8_t * data = (uint8_t *) buf; 30 | #if DEBUG_LEVEL>0 31 | // static uint8_t logbuf[1000] = {0}; 32 | // static int logbuflen = 0; 33 | // if (logbuflen + len > sizeof(logbuf)) { 34 | // int mlen = logbuflen + len - sizeof(logbuf); 35 | // memmove(logbuf, &logbuf[mlen], sizeof(logbuf) - mlen); 36 | // logbuflen -= mlen; 37 | // } 38 | // memcpy(&logbuf[logbuflen], data, len); 39 | // logbuflen += len; 40 | 41 | // Send out USB serial 42 | CDC_Transmit_FS(data, len); 43 | // if (res == USBD_OK) 44 | // logbuflen = 0; 45 | #endif 46 | #ifdef ENABLE_SERIAL_PRINTING 47 | // Send out UART serial 48 | while(len--) 49 | { 50 | _putchar(*data++); 51 | } 52 | #endif 53 | return 0; 54 | 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /docs/solo/signed-updates.md: -------------------------------------------------------------------------------- 1 | 2 | Solo has a bootloader that's fixed in memory to allow for signed firmware updates. It is not a built-in bootloader provided by the chip 3 | manufacturer, it is our own. We plan to use Ed25519 signatures, which have [efficient constant-time implementations on Cortex-M4 chips](http://www.cs.haifa.ac.il/~orrd/LC17/paper39.pdf). 4 | 5 | On the STM32L432, there is 256 KB of memory. The first 14 KB of memory is reserved for the bootloader. 6 | The bootloader is the first thing that boots, and if the button of the device is not held for 2 seconds, the 7 | application is immediately booted. 8 | 9 | Consider the following memory layout of the device. 10 | 11 | | 14 KB | 226 KB | 16KB | 12 | |---|---|---| 13 | | --boot-- | -------application------- | --data-- | 14 | 15 | Our bootloader resides at address 0, followed by the application, and then the final 16 KB allocated for secret data. 16 | 17 | The bootloader is allowed to replace any data in the application segment. When the application is first written to, 18 | a mass erase of the application segment is triggered and a flag in the data segment is set indicating the application 19 | is not safe to boot. 20 | 21 | In order to boot the application, a valid signature must be provided to the bootloader. The bootloader will verify the 22 | signature using a public key stored in the bootloader section, and the data in the application section. If the signature 23 | is valid, the boot flag in the data section will be changed to allow boot. 24 | 25 | We are working to make the signature checking process redundantly to make glitching attacks more difficult. Also random delays 26 | between redundant checks. 27 | -------------------------------------------------------------------------------- /targets/stm32l432/bootloader/pubkey_bootloader.c: -------------------------------------------------------------------------------- 1 | #include "stdint.h" 2 | #include 3 | #include APP_CONFIG 4 | 5 | #ifdef NK_TEST_MODE 6 | #warning "Using test bootloader key" 7 | 8 | uint8_t pubkey_boot[] = "\xb6\xd1\xd2\x83\xaa\xc9\x67\x72\x28\xdf\x4e\xca\x05\x2b\xfc\x54\x19" 9 | "\x63\x2b\xb0\xe8\xec\x6d\xb2\xfa\xd4\x37\xf8\x4d\x1e\x76\x07\xa0\xc2" 10 | "\xd2\x3d\xaf\x13\x4d\x39\xe2\xa4\x15\x30\xec\x1e\x5f\x23\x65\x03\x1c" 11 | "\xae\x83\xe3\x43\xf9\xd1\x74\x48\x47\xec\x8f\x60\xd2"; 12 | #else 13 | #warning "Using production bootloader key" 14 | 15 | #if PAGES==64 16 | #warning "Selecting prod bootloader key for pages==64" 17 | uint8_t pubkey_boot[] = "\xd0\xdd\x90\x21\x45\x9b\x72\x72\xaa\x90\xaa\xcf\x98\x7a\x63\x3a\x4c" 18 | "\xb5\x44\x96\xc5\x70\x43\x4d\x6a\xea\xd3\x0f\xba\x5d\x85\xa3\xd8\xae" 19 | "\xc0\x19\x33\x50\xf1\x5d\xda\xe3\x9d\xa8\x49\x38\x68\xeb\x28\x8e\x46" 20 | "\x7e\x14\xfc\x46\xa2\x95\x9b\xb0\xd6\x35\xf1\x18\x55"; 21 | #else 22 | #warning "Selecting prod bootloader key for pages==128" 23 | uint8_t pubkey_boot[] = "\x72\x09\xdc\x50\x1d\xff\xbf\x99\xfd\x2d\x91\x3b\x1a\x29\x6e\xbd\x91" 24 | "\x74\x3a\x15\xb5\x35\xfe\xd3\x91\x9e\x6e\x5f\x66\x02\xb9\x3e\xf7\x0f" 25 | "\x0e\x0a\x59\x08\xb4\x12\x54\xf6\x62\x22\xab\x00\x51\x5b\x68\x49\xe8" 26 | "\x99\xb0\x23\xbe\xcd\x61\xdb\xed\x78\x6d\xfd\x6e\xe8"; 27 | #endif 28 | 29 | #endif 30 | 31 | const uint8_t pubkey_boot_size = sizeof(pubkey_boot)-1; 32 | 33 | static_assert(sizeof(pubkey_boot)-1 == 64, "Invalid key size"); 34 | 35 | -------------------------------------------------------------------------------- /fido2/storage.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _STORAGE_H 8 | #define _STORAGE_H 9 | 10 | #include "ctap.h" 11 | 12 | #define KEY_SPACE_BYTES 128 13 | #define MAX_KEYS (1) 14 | #define PIN_SALT_LEN (32) 15 | #define STATE_VERSION (2) 16 | 17 | 18 | #define BACKUP_MARKER 0x5A 19 | #define INITIALIZED_MARKER 0xA5 20 | 21 | #define ERR_NO_KEY_SPACE (-1) 22 | #define ERR_KEY_SPACE_TAKEN (-2) 23 | #define ERR_KEY_SPACE_EMPTY (-2) 24 | 25 | typedef struct 26 | { 27 | // Pin information 28 | uint8_t is_initialized; 29 | uint8_t is_pin_set; 30 | uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE]; 31 | int pin_code_length; 32 | int8_t remaining_tries; 33 | 34 | uint16_t rk_stored; 35 | 36 | uint16_t key_lens[MAX_KEYS]; 37 | uint8_t key_space[KEY_SPACE_BYTES]; 38 | } AuthenticatorState_0xFF; 39 | 40 | 41 | typedef struct 42 | { 43 | // Pin information 44 | uint8_t is_initialized; 45 | uint8_t is_pin_set; 46 | uint8_t PIN_CODE_HASH[32]; 47 | uint8_t PIN_SALT[PIN_SALT_LEN]; 48 | int _reserved; 49 | int8_t remaining_tries; 50 | 51 | uint16_t rk_stored; 52 | 53 | uint16_t key_lens[MAX_KEYS]; 54 | uint8_t key_space[KEY_SPACE_BYTES]; 55 | uint8_t data_version; 56 | } AuthenticatorState_0x01; 57 | 58 | typedef AuthenticatorState_0x01 AuthenticatorState; 59 | 60 | 61 | typedef struct 62 | { 63 | uint32_t addr; 64 | uint8_t * filename; 65 | uint32_t count; 66 | } AuthenticatorCounter; 67 | 68 | extern AuthenticatorState STATE; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /targets/stm32l432/lib/usbd/usbd_ccid.h: -------------------------------------------------------------------------------- 1 | #ifndef _USBD_H_ 2 | #define _USBD_H_ 3 | 4 | #include "usbd_ioreq.h" 5 | 6 | #define CCID_HEADER_SIZE 10 7 | typedef struct 8 | { 9 | uint8_t type; 10 | uint32_t len; 11 | uint8_t slot; 12 | uint8_t seq; 13 | uint8_t rsvd; 14 | uint16_t param; 15 | } __attribute__((packed)) CCID_HEADER; 16 | 17 | #define CCID_IN_EP 0x86U /* EP1 for data IN */ 18 | #define CCID_OUT_EP 0x04U /* EP1 for data OUT */ 19 | #define CCID_CMD_EP 0x85U /* EP2 for CDC commands */ 20 | 21 | #define CCID_DATA_PACKET_SIZE 64 22 | 23 | #define CCID_SET_PARAMS 0x61 24 | #define CCID_POWER_ON 0x62 25 | #define CCID_POWER_OFF 0x63 26 | #define CCID_SLOT_STATUS 0x65 27 | #define CCID_SECURE 0x69 28 | #define CCID_GET_PARAMS 0x6C 29 | #define CCID_RESET_PARAMS 0x6D 30 | #define CCID_XFR_BLOCK 0x6F 31 | 32 | #define CCID_STATUS_ON 0x00 33 | #define CCID_STATUS_OFF 0x02 34 | 35 | #define CCID_DATA_BLOCK_RES 0x80 36 | #define CCID_SLOT_STATUS_RES 0x81 37 | #define CCID_PARAMS_RES 0x82 38 | 39 | extern USBD_ClassTypeDef USBD_CCID; 40 | 41 | typedef struct 42 | { 43 | uint32_t data[CCID_DATA_PACKET_SIZE / 4U]; 44 | uint8_t CmdOpCode; 45 | uint8_t CmdLength; 46 | uint8_t *RxBuffer; 47 | uint8_t *TxBuffer; 48 | uint32_t RxLength; 49 | uint32_t TxLength; 50 | 51 | __IO uint32_t TxState; 52 | __IO uint32_t RxState; 53 | } 54 | USBD_CCID_HandleTypeDef; 55 | 56 | uint8_t usb_ccid_recieve_callback(USBD_HandleTypeDef *pdev, uint8_t epnum); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /pc/main.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "cbor.h" 15 | #include "device.h" 16 | #include "ctaphid.h" 17 | //#include "bsp.h" 18 | #include "util.h" 19 | #include "log.h" 20 | #include "ctap.h" 21 | #include "app.h" 22 | 23 | 24 | void device_init(int argc, char *argv[]); 25 | int usbhid_recv(uint8_t * msg); 26 | 27 | 28 | 29 | int main(int argc, char *argv[]) 30 | { 31 | uint8_t hidmsg[64]; 32 | 33 | set_logging_mask( 34 | // -1 | 35 | /*0*/ 36 | // TAG_GEN| 37 | // TAG_MC | 38 | // TAG_GA | 39 | TAG_WALLET | 40 | TAG_STOR | 41 | TAG_BUTTON | 42 | //TAG_NFC_APDU | 43 | TAG_NFC | 44 | // TAG_CP | 45 | // TAG_CTAP| 46 | // TAG_HID| 47 | TAG_U2F| 48 | // TAG_PARSE | 49 | //TAG_TIME| 50 | // TAG_DUMP| 51 | // TAG_DUMP2| 52 | TAG_GREEN| 53 | TAG_RED| 54 | TAG_EXT| 55 | TAG_CCID| 56 | TAG_ERR 57 | ); 58 | 59 | device_init(argc, argv); 60 | 61 | memset(hidmsg,0,sizeof(hidmsg)); 62 | 63 | 64 | while(1) 65 | { 66 | 67 | if (usbhid_recv(hidmsg) > 0) 68 | { 69 | ctaphid_handle_packet(hidmsg); 70 | memset(hidmsg, 0, sizeof(hidmsg)); 71 | } 72 | else 73 | { 74 | } 75 | 76 | ctaphid_check_timeouts(); 77 | 78 | struct timespec ts; 79 | ts.tv_sec = 0; 80 | ts.tv_nsec = 1000*1000*10; 81 | nanosleep(&ts,NULL); 82 | } 83 | 84 | // Should never get here 85 | printf1(TAG_GREEN, "done\n"); 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /targets/stm32l432/src/main.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "cbor.h" 14 | #include "device.h" 15 | #include "ctaphid.h" 16 | //#include "bsp.h" 17 | #include "util.h" 18 | #include "log.h" 19 | #include "ctap.h" 20 | #include APP_CONFIG 21 | 22 | #if !defined(TEST) 23 | 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | uint8_t hidmsg[64]; 28 | uint32_t t1 = 0; 29 | 30 | set_logging_mask( 31 | // -1 | 32 | /*0*/ 33 | TAG_GEN| 34 | TAG_MC | 35 | TAG_GA | 36 | TAG_WALLET | 37 | TAG_STOR | 38 | // TAG_NFC_APDU | 39 | // TAG_NFC | 40 | TAG_CP | 41 | TAG_CTAP| 42 | TAG_HID| 43 | TAG_U2F| 44 | //TAG_PARSE | 45 | //TAG_TIME| 46 | // TAG_DUMP| 47 | TAG_GREEN| 48 | TAG_RED| 49 | TAG_EXT| 50 | TAG_CCID| 51 | TAG_ERR | 52 | TAG_BUTTON 53 | ); 54 | 55 | device_init(argc, argv); 56 | 57 | memset(hidmsg,0,sizeof(hidmsg)); 58 | 59 | 60 | while(1) 61 | { 62 | if (millis() - t1 > HEARTBEAT_PERIOD) 63 | { 64 | heartbeat(); 65 | t1 = millis(); 66 | } 67 | 68 | device_manage(); 69 | 70 | if (usbhid_recv(hidmsg) > 0) 71 | { 72 | ctaphid_handle_packet(hidmsg); 73 | memset(hidmsg, 0, sizeof(hidmsg)); 74 | } 75 | else 76 | { 77 | } 78 | ctaphid_check_timeouts(); 79 | 80 | } 81 | 82 | // Should never get here 83 | usbhid_close(); 84 | printf1(TAG_GREEN, "done\n"); 85 | return 0; 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /keys/attestation/device_cert.txt: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 1 (0x1) 5 | Signature Algorithm: ecdsa-with-SHA256 6 | Issuer: C = DE, O = Nitrokey GmbH, OU = Root CA, CN = nitrokey.com 7 | Validity 8 | Not Before: May 8 09:35:35 2020 GMT 9 | Not After : Apr 26 09:35:35 2070 GMT 10 | Subject: C = DE, O = Nitrokey GmbH, OU = Authenticator Attestation, CN = nitrokey.com 11 | Subject Public Key Info: 12 | Public Key Algorithm: id-ecPublicKey 13 | Public-Key: (256 bit) 14 | pub: 15 | 04:b6:a8:02:1d:09:dd:48:8f:31:db:e3:7e:26:d6: 16 | cd:a5:44:11:c3:34:27:93:20:6e:51:0a:0c:7f:2c: 17 | c8:87:b9:a7:3c:4a:b4:64:2a:b7:8c:a1:d8:c3:80: 18 | 9f:71:2c:c2:9a:73:5d:ef:2d:a4:66:25:a0:3a:cf: 19 | 49:6b:d2:02:87 20 | ASN1 OID: prime256v1 21 | NIST CURVE: P-256 22 | X509v3 extensions: 23 | X509v3 Subject Key Identifier: 24 | 2E:5B:45:7E:56:10:B4:E5:DD:B4:A9:28:0B:D1:1F:E8:FE:E5:C6:46 25 | X509v3 Authority Key Identifier: 26 | DirName:/C=DE/O=Nitrokey GmbH/OU=Root CA/CN=nitrokey.com 27 | serial:16:62:04:96:E9:D9:F4:FF:2D:A4:49:F1:7C:25:F6:A8:57:EB:66:E8 28 | 29 | X509v3 Basic Constraints: 30 | CA:FALSE 31 | X509v3 Key Usage: 32 | Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment 33 | 1.3.6.1.4.1.45724.1.1.4: 34 | ........L>...Ja... 35 | Signature Algorithm: ecdsa-with-SHA256 36 | 30:45:02:20:24:38:71:59:c0:8f:e7:9d:ef:c3:c8:dc:72:6a: 37 | 82:c2:62:4b:af:82:6f:b2:74:0b:1c:5f:1f:01:0c:be:4e:54: 38 | 02:21:00:9a:9b:6d:61:4b:84:6f:8d:f7:d6:9a:97:96:65:e2: 39 | 8c:4f:58:0c:51:01:16:c6:de:ab:56:83:04:5f:d0:bb:1a 40 | -------------------------------------------------------------------------------- /keys/attestation/dev/device_cert.txt: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 1 (0x1) 5 | Signature Algorithm: ecdsa-with-SHA256 6 | Issuer: C = DE, O = Nitrokey GmbH, OU = Root CA, CN = nitrokey.com 7 | Validity 8 | Not Before: May 8 12:00:04 2020 GMT 9 | Not After : Apr 26 12:00:04 2070 GMT 10 | Subject: C = DE, O = Nitrokey GmbH, OU = Authenticator Attestation, CN = nitrokey.com 11 | Subject Public Key Info: 12 | Public Key Algorithm: id-ecPublicKey 13 | Public-Key: (256 bit) 14 | pub: 15 | 04:7f:bd:8e:19:5e:71:19:b8:01:3a:34:ce:3a:de: 16 | 05:58:ad:ed:50:f1:d3:f3:61:21:c0:26:a5:c8:6b: 17 | 1d:67:4b:22:33:ae:63:1c:93:aa:7f:ee:13:71:d1: 18 | 53:86:59:d1:de:34:c2:37:94:be:14:b6:23:b6:5c: 19 | 86:05:c5:78:28 20 | ASN1 OID: prime256v1 21 | NIST CURVE: P-256 22 | X509v3 extensions: 23 | X509v3 Subject Key Identifier: 24 | 1C:D8:FF:EB:0B:E1:FD:29:FD:5F:B1:B2:9C:3E:AC:A6:79:E6:72:F2 25 | X509v3 Authority Key Identifier: 26 | DirName:/C=DE/O=Nitrokey GmbH/OU=Root CA/CN=nitrokey.com 27 | serial:05:13:D6:E6:AF:64:D6:91:FC:55:67:46:D9:0E:C7:EB:4A:5E:F6:D7 28 | 29 | X509v3 Basic Constraints: 30 | CA:FALSE 31 | X509v3 Key Usage: 32 | Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment 33 | 1.3.6.1.4.1.45724.1.1.4: 34 | ........L>...Ja... 35 | Signature Algorithm: ecdsa-with-SHA256 36 | 30:45:02:21:00:9f:85:42:74:d3:e1:23:bf:15:db:eb:41:b6: 37 | e9:dd:43:a3:44:75:d3:dd:26:9c:b2:f6:09:00:ec:75:87:28: 38 | bc:02:20:01:b2:b1:64:12:05:ff:f7:96:c6:44:bb:26:14:64: 39 | 05:5a:5e:dd:34:02:34:c5:9f:4e:32:36:af:b0:e4:6c:03 40 | -------------------------------------------------------------------------------- /fido2/apdu.h: -------------------------------------------------------------------------------- 1 | #ifndef _APDU_H_ 2 | #define _APDU_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct 9 | { 10 | uint8_t cla; 11 | uint8_t ins; 12 | uint8_t p1; 13 | uint8_t p2; 14 | uint8_t lc; 15 | } __attribute__((packed)) APDU_HEADER; 16 | 17 | typedef struct 18 | { 19 | uint8_t cla; 20 | uint8_t ins; 21 | uint8_t p1; 22 | uint8_t p2; 23 | uint8_t lc[3]; 24 | } __attribute__((packed)) EXT_APDU_HEADER; 25 | 26 | typedef struct 27 | { 28 | uint8_t cla; 29 | uint8_t ins; 30 | uint8_t p1; 31 | uint8_t p2; 32 | uint16_t lc; 33 | uint8_t *data; 34 | uint32_t le; 35 | bool extended_apdu; 36 | uint8_t case_type; 37 | } __attribute__((packed)) APDU_STRUCT; 38 | 39 | extern uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu); 40 | 41 | #define APDU_FIDO_U2F_REGISTER 0x01 42 | #define APDU_FIDO_U2F_AUTHENTICATE 0x02 43 | #define APDU_FIDO_U2F_VERSION 0x03 44 | #define APDU_FIDO_NFCCTAP_MSG 0x10 45 | #define APDU_FIDO_U2F_VENDOR_FIRST 0xc0 // First vendor defined command 46 | #define APDU_FIDO_U2F_VENDOR_LAST 0xff // Last vendor defined command 47 | #define APDU_SOLO_RESET 0xee 48 | 49 | #define APDU_INS_SELECT 0xA4 50 | #define APDU_INS_READ_BINARY 0xB0 51 | #define APDU_GET_RESPONSE 0xC0 52 | 53 | #define SW_SUCCESS 0x9000 54 | #define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE. 55 | #define SW_WRONG_LENGTH 0x6700 56 | #define SW_COND_USE_NOT_SATISFIED 0x6985 57 | #define SW_FILE_NOT_FOUND 0x6a82 58 | #define SW_INCORRECT_P1P2 0x6a86 59 | #define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid 60 | #define SW_CLA_INVALID 0x6e00 61 | #define SW_INTERNAL_EXCEPTION 0x6f00 62 | 63 | #endif //_APDU_H_ 64 | -------------------------------------------------------------------------------- /targets/stm32l432/build/common.mk: -------------------------------------------------------------------------------- 1 | include ../../fido2/version.mk 2 | 3 | CC=$(PREFIX)arm-none-eabi-gcc 4 | CP=$(PREFIX)arm-none-eabi-objcopy 5 | SZ=$(PREFIX)arm-none-eabi-size 6 | AR=$(PREFIX)arm-none-eabi-ar 7 | AS=$(PREFIX)arm-none-eabi-as 8 | 9 | DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_ll_gpio.c \ 10 | lib/stm32l4xx_ll_rcc.c lib/stm32l4xx_ll_rng.c lib/stm32l4xx_ll_tim.c \ 11 | lib/stm32l4xx_ll_usb.c lib/stm32l4xx_ll_utils.c lib/stm32l4xx_ll_pwr.c \ 12 | lib/stm32l4xx_ll_usart.c lib/stm32l4xx_ll_spi.c lib/stm32l4xx_ll_exti.c 13 | 14 | USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \ 15 | lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \ 16 | lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c \ 17 | lib/usbd/usbd_ccid.c 18 | 19 | VERSION:=$(shell git describe --abbrev=0 ) 20 | VERSION_FULL_RAW:=$(shell git describe) 21 | VERSION_FULL:=$(shell python3 -c 'print("$(VERSION_FULL_RAW)".strip(".nitrokey")) if ".nitrokey" in "$(VERSION_FULL_RAW)" else exit(1)') 22 | VERSION_FULL:=$(if $(VERSION_FULL),$(VERSION_FULL),$(error Invalid version tag - no '.nitrokey' suffix)) 23 | 24 | VERSION_MAJ:=$(shell python3 -c 'print("$(VERSION)".split(".")[0])') 25 | VERSION_MIN:=$(shell python3 -c 'print("$(VERSION)".split(".")[1])') 26 | VERSION_PAT:=$(shell python3 -c 'print("$(VERSION)".split(".")[2])') 27 | 28 | #VERSION_FULL?=$(SOLO_VERSION_FULL) 29 | #VERSION:=$(SOLO_VERSION) 30 | #VERSION_MAJ:=$(SOLO_VERSION_MAJ) 31 | #VERSION_MIN:=$(SOLO_VERSION_MIN) 32 | #VERSION_PAT:=$(SOLO_VERSION_PAT) 33 | 34 | VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \ 35 | -DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\" 36 | 37 | .PHONY: version-all 38 | version-all: 39 | @echo $(VERSION_FULL_RAW) 40 | @echo $(SOLO_VERSION_FULL) 41 | @echo $(SOLO_VERSION_MAJ) 42 | @echo $(SOLO_VERSION_MIN) 43 | @echo $(SOLO_VERSION_PAT) 44 | 45 | %.o: %.s 46 | @echo "*** $<" 47 | $(AS) -o $@ $^ 48 | -------------------------------------------------------------------------------- /fido2/ctap_parse.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _CTAP_PARSE_H 8 | #define _CTAP_PARSE_H 9 | 10 | 11 | #define check_ret(r) _check_ret(r,__LINE__, __FILE__);\ 12 | if ((r) != CborNoError) return CTAP2_ERR_CBOR_PARSING; 13 | 14 | #define check_retr(r) _check_ret(r,__LINE__, __FILE__);\ 15 | if ((r) != CborNoError) return r; 16 | 17 | 18 | extern void _check_ret(CborError ret, int line, const char * filename); 19 | 20 | 21 | const char * cbor_value_get_type_string(const CborValue *value); 22 | 23 | 24 | uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val); 25 | uint8_t parse_pub_key_cred_param(CborValue * val, uint8_t * cred_type, int32_t * alg_type); 26 | uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val); 27 | uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, unsigned int len); 28 | uint8_t parse_rp_id(struct rpId * rp, CborValue * val); 29 | uint8_t parse_rp(struct rpId * rp, CborValue * val); 30 | uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up); 31 | 32 | uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it); 33 | uint8_t parse_cose_key(CborValue * it, COSE_key * cose); 34 | 35 | 36 | uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length); 37 | uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length); 38 | uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length); 39 | uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length); 40 | uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred); 41 | 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /targets/stm32l432/src/nfc.h: -------------------------------------------------------------------------------- 1 | #ifndef _NFC_H_ 2 | #define _NFC_H_ 3 | 4 | #include 5 | #include 6 | #include "apdu.h" 7 | 8 | // Return number of bytes read if any. 9 | int nfc_loop(void); 10 | 11 | int nfc_init(void); 12 | 13 | typedef struct 14 | { 15 | uint8_t cclen_hi; 16 | uint8_t cclen_lo; 17 | uint8_t version; 18 | uint8_t MLe_hi; 19 | uint8_t MLe_lo; 20 | uint8_t MLc_hi; 21 | uint8_t MLc_lo; 22 | uint8_t tlv[8]; 23 | } __attribute__((packed)) CAPABILITY_CONTAINER; 24 | 25 | // WTX time in ms 26 | #define WTX_TIME_DEFAULT 300 27 | 28 | #define NFC_CMD_REQA 0x26 29 | #define NFC_CMD_WUPA 0x52 30 | #define NFC_CMD_HLTA 0x50 31 | #define NFC_CMD_RATS 0xe0 32 | 33 | #define NFC_CMD_PPSS 0xd0 34 | #define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS) 35 | #define NFC_CMD_IBLOCK 0x00 36 | #define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) ) 37 | #define NFC_CMD_RBLOCK 0xa0 38 | #define NFC_CMD_RBLOCK_ACK 0x10 39 | #define IS_RBLOCK(x) ( (((x) & 0xe0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) ) 40 | #define NFC_CMD_SBLOCK 0xc0 41 | #define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) ) 42 | 43 | extern uint8_t p14443_block_offset(uint8_t pcb); 44 | 45 | #define NFC_SBLOCK_DESELECT 0x30 46 | #define NFC_SBLOCK_WTX 0x30 47 | 48 | #define AID_NDEF_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x01" 49 | #define AID_NDEF_MIFARE_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x00" 50 | #define AID_CAPABILITY_CONTAINER "\xE1\x03" 51 | #define AID_NDEF_TAG "\xE1\x04" 52 | #define AID_FIDO "\xa0\x00\x00\x06\x47\x2f\x00\x01" 53 | 54 | typedef enum 55 | { 56 | APP_NOTHING = 0, 57 | APP_NDEF_TYPE_4 = 1, 58 | APP_MIFARE_TYPE_4, 59 | APP_CAPABILITY_CONTAINER, 60 | APP_NDEF_TAG, 61 | APP_FIDO, 62 | } APPLETS; 63 | 64 | void WTX_timer_exec(void); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /targets/stm32l432/src/fifo.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _FIFO_H_ 8 | #define _FIFO_H_ 9 | 10 | #include APP_CONFIG 11 | 12 | #ifndef TEST_FIFO 13 | #define TEST_FIFO 0 14 | #endif 15 | 16 | #define FIFO_CREATE(NAME,LENGTH,BYTES)\ 17 | int __##NAME##_WRITE_PTR = 0;\ 18 | int __##NAME##_READ_PTR = 0;\ 19 | int __##NAME##_SIZE = 0;\ 20 | static uint8_t __##NAME##_WRITE_BUF[BYTES * LENGTH];\ 21 | \ 22 | int fifo_##NAME##_add(uint8_t * c)\ 23 | {\ 24 | if (__##NAME##_SIZE < LENGTH)\ 25 | {\ 26 | memmove(__##NAME##_WRITE_BUF + __##NAME##_WRITE_PTR * BYTES, c, BYTES);\ 27 | __##NAME##_WRITE_PTR ++;\ 28 | if (__##NAME##_WRITE_PTR >= LENGTH)\ 29 | __##NAME##_WRITE_PTR = 0;\ 30 | __##NAME##_SIZE++;\ 31 | return 0;\ 32 | }\ 33 | return -1;\ 34 | }\ 35 | \ 36 | int fifo_##NAME##_take(uint8_t * c)\ 37 | {\ 38 | memmove(c, __##NAME##_WRITE_BUF + __##NAME##_READ_PTR * BYTES, BYTES);\ 39 | if ( __##NAME##_SIZE > 0)\ 40 | {\ 41 | __##NAME##_READ_PTR ++;\ 42 | if (__##NAME##_READ_PTR >= LENGTH)\ 43 | __##NAME##_READ_PTR = 0;\ 44 | __##NAME##_SIZE --;\ 45 | return 0;\ 46 | }\ 47 | return -1;\ 48 | }\ 49 | \ 50 | uint32_t fifo_##NAME##_size()\ 51 | {\ 52 | return (__##NAME##_SIZE);\ 53 | }\ 54 | uint32_t fifo_##NAME##_rhead()\ 55 | {\ 56 | return (__##NAME##_READ_PTR);\ 57 | }\ 58 | uint32_t fifo_##NAME##_whead()\ 59 | {\ 60 | return (__##NAME##_WRITE_PTR);\ 61 | }\ 62 | 63 | #define FIFO_CREATE_H(NAME)\ 64 | int fifo_##NAME##_add(uint8_t * c);\ 65 | int fifo_##NAME##_take(uint8_t * c);\ 66 | uint32_t fifo_##NAME##_size();\ 67 | uint32_t fifo_##NAME##_rhead();\ 68 | uint32_t fifo_##NAME##_whead();\ 69 | 70 | FIFO_CREATE_H(hidmsg) 71 | 72 | FIFO_CREATE_H(debug) 73 | 74 | FIFO_CREATE_H(test) 75 | 76 | void fifo_test(); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /targets/stm32l432/linker/bootloader_stm32l4xx_extra.ld: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 SoloKeys Developers */ 2 | /* */ 3 | /* Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be */ 6 | /* copied, modified, or distributed except according to those terms. */ 7 | 8 | ENTRY(Reset_Handler) 9 | 10 | /* End of RAM */ 11 | _estack = 0x2000c000; 12 | 13 | _MIN_STACK_SIZE = 0x400; 14 | 15 | /* 16 | flash_cfg is for storing bootloader data, like last used firmware version. 17 | bootloader_configuration should be equal to (APPLICATION_END_PAGE) page address, from targets/stm32l432/src/memory_layout.h:30; and equal to flash_cfg origin 18 | */ 19 | 20 | bootloader_configuration = 0x08000000 + 216*1024+8; 21 | 22 | MEMORY 23 | { 24 | flash (rx) : ORIGIN = 0x08000000, LENGTH = 32K 25 | flash_cfg (rx) : ORIGIN = 0x08000000 + 216*1024+8, LENGTH = 2K-8 26 | ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K 27 | sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K 28 | } 29 | 30 | SECTIONS 31 | { 32 | .isr_vector : 33 | { 34 | . = ALIGN(8); 35 | KEEP(*(.isr_vector)) 36 | . = ALIGN(8); 37 | } >flash 38 | 39 | .text : 40 | { 41 | . = ALIGN(8); 42 | *(.text*) 43 | *(.rodata*) 44 | KEEP(*(.init)) 45 | KEEP(*(.finit)) 46 | . = ALIGN(8); 47 | _etext = .; 48 | } >flash 49 | 50 | .flag2 bootloader_configuration : 51 | { 52 | KEEP(*(.flag2)) ; 53 | } > flash_cfg 54 | 55 | _sidata = LOADADDR(.data); 56 | 57 | .data : 58 | { 59 | . = ALIGN(8); 60 | _sdata = .; 61 | *(.data*) 62 | . = ALIGN(8); 63 | _edata = .; 64 | } >ram AT> flash 65 | 66 | .bss : 67 | { 68 | . = ALIGN(4); 69 | _sbss = .; 70 | __bss_start__ = _sbss; 71 | *(.bss*) 72 | *(COMMON) 73 | . = ALIGN(4); 74 | _ebss = .; 75 | __bss_end__ = _ebss; 76 | } > ram 77 | 78 | ._stack : 79 | { 80 | . = ALIGN(8); 81 | end = .; 82 | _end = .; 83 | . = . + _MIN_STACK_SIZE; 84 | . = ALIGN(8); 85 | } > ram 86 | 87 | } 88 | -------------------------------------------------------------------------------- /targets/stm32l432/linker/bootloader_stm32l4xx.ld-old: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 SoloKeys Developers */ 2 | /* */ 3 | /* Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be */ 6 | /* copied, modified, or distributed except according to those terms. */ 7 | 8 | ENTRY(Reset_Handler) 9 | 10 | /* End of RAM */ 11 | _estack = 0x2000c000; 12 | 13 | _MIN_STACK_SIZE = 0x400; 14 | 15 | /* 16 | flash_cfg is for storing bootloader data, like last used firmware version. 17 | bootloader_configuration should be equal to (APPLICATION_END_PAGE) page address, from targets/stm32l432/src/memory_layout.h:30; and equal to flash_cfg origin 18 | */ 19 | 20 | bootloader_configuration = 0x08000000 + (128-40)*1024+8; 21 | 22 | MEMORY 23 | { 24 | flash (rx) : ORIGIN = 0x08000000, LENGTH = 20K 25 | flash_cfg (rx) : ORIGIN = 0x08000000 + (128-40)*1024+8, LENGTH = 2K-8 26 | ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K 27 | sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K 28 | } 29 | 30 | SECTIONS 31 | { 32 | .isr_vector : 33 | { 34 | . = ALIGN(8); 35 | KEEP(*(.isr_vector)) 36 | . = ALIGN(8); 37 | } >flash 38 | 39 | .text : 40 | { 41 | . = ALIGN(8); 42 | *(.text*) 43 | *(.rodata*) 44 | KEEP(*(.init)) 45 | KEEP(*(.finit)) 46 | . = ALIGN(8); 47 | _etext = .; 48 | } >flash 49 | 50 | .flag2 bootloader_configuration : 51 | { 52 | KEEP(*(.flag2)) ; 53 | } > flash_cfg 54 | 55 | _sidata = LOADADDR(.data); 56 | 57 | .data : 58 | { 59 | . = ALIGN(8); 60 | _sdata = .; 61 | *(.data*) 62 | . = ALIGN(8); 63 | _edata = .; 64 | } >ram AT> flash 65 | 66 | .bss : 67 | { 68 | . = ALIGN(4); 69 | _sbss = .; 70 | __bss_start__ = _sbss; 71 | *(.bss*) 72 | *(COMMON) 73 | . = ALIGN(4); 74 | _ebss = .; 75 | __bss_end__ = _ebss; 76 | } > ram 77 | 78 | ._stack : 79 | { 80 | . = ALIGN(8); 81 | end = .; 82 | _end = .; 83 | . = . + _MIN_STACK_SIZE; 84 | . = ALIGN(8); 85 | } > ram 86 | 87 | } 88 | -------------------------------------------------------------------------------- /targets/stm32l432/src/rng.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "stm32l4xx_ll_rng.h" 12 | 13 | #include "rng.h" 14 | #include "log.h" 15 | 16 | int __errno = 0; 17 | 18 | void rng_get_bytes(uint8_t * dst, size_t sz) 19 | { 20 | uint8_t r[4]; 21 | unsigned int i,j; 22 | for (i = 0; i < sz; i += 4) 23 | { 24 | while( !LL_RNG_IsActiveFlag_DRDY(RNG) ) 25 | ; 26 | *(uint32_t*)&r = LL_RNG_ReadRandData32(RNG); 27 | 28 | if (RNG->SR & 0x66) 29 | { 30 | // FIXME [ERR] src/rng.c:30: Error RNG: 40 31 | printf2(TAG_ERR,"Error RNG: %02lx\r\n", RNG->SR); 32 | exit(1); 33 | } 34 | 35 | for (j = 0; j < 4; j++) 36 | { 37 | if ((i + j) >= sz) 38 | { 39 | return; 40 | } 41 | dst[i + j] = r[j]; 42 | } 43 | } 44 | } 45 | 46 | float shannon_entropy(float * p, size_t sz) 47 | { 48 | 49 | unsigned int i; 50 | float entropy = 0.0f; 51 | 52 | for(i=0; i < sz; i++) 53 | { 54 | if (p[i] > 0.0) 55 | { 56 | entropy -= p[i] * (float) log( (double) p[i]); 57 | } 58 | } 59 | 60 | entropy = entropy / (float) log ((double) 2.0); 61 | 62 | return entropy; 63 | } 64 | 65 | // Measure shannon entropy of RNG 66 | float rng_test(size_t n) 67 | { 68 | unsigned int i; 69 | int sz = 0; 70 | uint8_t buf[4]; 71 | int counts[256]; 72 | float p[256]; 73 | 74 | memset(counts, 0, sizeof(counts)); 75 | 76 | for(i=0; i < n; i+=4) 77 | { 78 | rng_get_bytes(buf, 4); 79 | sz += 4; 80 | 81 | counts[buf[0]]++; 82 | counts[buf[1]]++; 83 | counts[buf[2]]++; 84 | counts[buf[3]]++; 85 | } 86 | 87 | for (i = 0; i < 256; i++) 88 | { 89 | p[i] = ((float)counts[i])/sz; 90 | } 91 | 92 | return shannon_entropy(p, 256); 93 | } 94 | -------------------------------------------------------------------------------- /fido2/crypto.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _CRYPTO_H 8 | #define _CRYPTO_H 9 | 10 | #include 11 | 12 | void crypto_sha256_init(); 13 | void crypto_sha256_update(uint8_t * data, size_t len); 14 | void crypto_sha256_update_secret(); 15 | void crypto_sha256_final(uint8_t * hash); 16 | 17 | void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac); 18 | void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac); 19 | 20 | void crypto_sha512_init(); 21 | void crypto_sha512_update(const uint8_t * data, size_t len); 22 | void crypto_sha512_final(uint8_t * hash); 23 | 24 | void crypto_ecc256_init(); 25 | void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y); 26 | void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey); 27 | 28 | void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2); 29 | void crypto_ecc256_load_attestation_key(); 30 | void crypto_load_external_key(uint8_t * key, int len); 31 | void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig); 32 | void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_ID); 33 | 34 | 35 | void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey); 36 | void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey); 37 | void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret); 38 | 39 | #define CRYPTO_TRANSPORT_KEY2 ((uint8_t*)2) 40 | #define CRYPTO_TRANSPORT_KEY ((uint8_t*)1) 41 | #define CRYPTO_MASTER_KEY ((uint8_t*)0) 42 | 43 | void crypto_aes256_init(uint8_t * key, uint8_t * nonce); 44 | void crypto_aes256_reset_iv(uint8_t * nonce); 45 | 46 | // buf length must be multiple of 16 bytes 47 | void crypto_aes256_decrypt(uint8_t * buf, int lenth); 48 | void crypto_aes256_encrypt(uint8_t * buf, int lenth); 49 | 50 | void crypto_reset_master_secret(); 51 | void crypto_load_master_secret(uint8_t * key); 52 | 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /targets/stm32l432/linker/bootloader_stm32l4xx.ld.in: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 SoloKeys Developers */ 2 | /* */ 3 | /* Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be */ 6 | /* copied, modified, or distributed except according to those terms. */ 7 | 8 | ENTRY(Reset_Handler) 9 | 10 | /* End of RAM */ 11 | _estack = 0x2000c000; 12 | 13 | _MIN_STACK_SIZE = 0x400; 14 | 15 | /* 16 | flash_cfg is for storing bootloader data, like last used firmware version. 17 | bootloader_configuration should be equal to (APPLICATION_END_PAGE) page address, from targets/stm32l432/src/memory_layout.h:30; and equal to flash_cfg origin 18 | 19 | Template parameters: 20 | PAGES=__PAGES__ 21 | */ 22 | 23 | bootloader_configuration = 0x08000000 + (__PAGES__*2-40)*1024+8; 24 | 25 | MEMORY 26 | { 27 | flash (rx) : ORIGIN = 0x08000000, LENGTH = 20K 28 | flash_cfg (rx) : ORIGIN = 0x08000000 + (__PAGES__*2-40)*1024+8, LENGTH = 2K-8 29 | ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K 30 | sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K 31 | } 32 | 33 | SECTIONS 34 | { 35 | .isr_vector : 36 | { 37 | . = ALIGN(8); 38 | KEEP(*(.isr_vector)) 39 | . = ALIGN(8); 40 | } >flash 41 | 42 | .text : 43 | { 44 | . = ALIGN(8); 45 | *(.text*) 46 | *(.rodata*) 47 | KEEP(*(.init)) 48 | KEEP(*(.finit)) 49 | . = ALIGN(8); 50 | _etext = .; 51 | } >flash 52 | 53 | .flag2 bootloader_configuration : 54 | { 55 | KEEP(*(.flag2)) ; 56 | } > flash_cfg 57 | 58 | _sidata = LOADADDR(.data); 59 | 60 | .data : 61 | { 62 | . = ALIGN(8); 63 | _sdata = .; 64 | *(.data*) 65 | . = ALIGN(8); 66 | _edata = .; 67 | } >ram AT> flash 68 | 69 | .bss : 70 | { 71 | . = ALIGN(4); 72 | _sbss = .; 73 | __bss_start__ = _sbss; 74 | *(.bss*) 75 | *(COMMON) 76 | . = ALIGN(4); 77 | _ebss = .; 78 | __bss_end__ = _ebss; 79 | } > ram 80 | 81 | ._stack : 82 | { 83 | . = ALIGN(8); 84 | end = .; 85 | _end = .; 86 | . = . + _MIN_STACK_SIZE; 87 | . = ALIGN(8); 88 | } > ram 89 | 90 | } 91 | -------------------------------------------------------------------------------- /docs/solo/bootloader-mode.md: -------------------------------------------------------------------------------- 1 | # Booting into bootloader mode 2 | 3 | If you have a recent version of Solo, you can put it into bootloader mode by running this command. 4 | 5 | ```bash 6 | solo program aux enter-bootloader 7 | ``` 8 | 9 | If your Solo is a bit older (<=2.5.3) You can put Solo into bootloader mode by using the button method: 10 | Hold down button while plugging in Solo. After 2 seconds, bootloader mode will activate. 11 | You'll see a yellowish flashing light and you can let go of the button. 12 | 13 | Now Solo is ready to [accept firmware updates](/solo/signed-updates). If the Solo is a secured model, it can only accept signed updates, typically in the `firmware-*.json` format. 14 | 15 | # The boot stages of Solo 16 | 17 | Solo has 3 boot stages. 18 | 19 | ## DFU 20 | 21 | The first stage is the DFU (Device Firmware Update) which is in a ROM on Solo. It is baked into the chip and is not implemented by us. 22 | This is what allows the entire firmware of Solo to be programmed. **It's not recommended to develop for Solo using the DFU because 23 | if you program broken firmware, you could brick your device**. 24 | 25 | On hacker/nonverifying-bootloader devices, you can boot into the DFU by holding down the button for 5 seconds, 26 | when Solo is already in bootloader mode. 27 | 28 | You can also run this command when Solo is in bootloader mode to put it in DFU mode. 29 | 30 | ```bash 31 | solo program aux enter-dfu 32 | ``` 33 | 34 | Note it will stay in DFU mode until you to tell it to boot again. You can boot it again by running the following. 35 | 36 | ```bash 37 | solo program aux leave-dfu 38 | ``` 39 | 40 | *Warning*: If you change the firmware to something broken, and you tell the DFU to boot it, you could brick your device. 41 | 42 | ## Solo Bootloader 43 | 44 | The next boot stage is the "Solo bootloader". So when we say to put your Solo into bootloader mode, it is this stage. 45 | This bootloader is written by us and allows signed firmware updates to be written. On Solo Hackers, there is no signature checking 46 | and will allow any firmware updates. 47 | 48 | It is safe to develop for Solo using our Solo bootloader. If broken firmware is uploaded to the device, then the Solo 49 | bootloader can always be booted again by holding down the button when plugging in. 50 | 51 | ## Solo application 52 | 53 | This is what contains all the important functionality of Solo. FIDO2, U2F, etc. This is what Solo will boot to by default. 54 | -------------------------------------------------------------------------------- /targets/stm32l432/src/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 "app.h" 33 | #include "device.h" 34 | #include "stm32l4xx_ll_gpio.h" 35 | 36 | /* 37 | * U2F_BUTTON_RESET is a MTPM pin. Requires HIGH state to keep 38 | * NORMAL power mode on MTCH101 39 | * */ 40 | 41 | #define IS_BUTTON_PRESSED_RAW() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN)) 42 | 43 | extern volatile uint8_t LED_STATE; 44 | 45 | #include "led.h" 46 | 47 | #define LED_ON() { led_rgb(led_default_color); } 48 | #define LED_OFF() { led_rgb(0); } 49 | #define BUTTON_RESET_ON() { LL_GPIO_ResetOutputPin(SOLO_BUTTON_R_PORT, SOLO_BUTTON_R_PIN); } 50 | #define BUTTON_RESET_OFF() { LL_GPIO_SetOutputPin(SOLO_BUTTON_R_PORT, SOLO_BUTTON_R_PIN); } 51 | #define IS_LED_ON() (LED_STATE == 1) 52 | 53 | #define get_ms() millis() 54 | 55 | 56 | #endif /* BSP_H_ */ 57 | -------------------------------------------------------------------------------- /targets/stm32l432/bootloader/bootloader.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #ifndef _APP_H_ 9 | #define _APP_H_ 10 | #include 11 | #include "version.h" 12 | #include "solo.h" 13 | #define DEBUG_UART USART1 14 | 15 | #ifndef DEBUG_LEVEL 16 | #define DEBUG_LEVEL 0 17 | #endif 18 | 19 | #define NON_BLOCK_PRINTING 0 20 | 21 | #define BOOT_TO_DFU 0 22 | 23 | 24 | #define SOLO 1 25 | #define IS_BOOTLOADER 1 26 | 27 | #define ENABLE_U2F_EXTENSIONS 28 | // #define ENABLE_U2F 29 | 30 | #define DISABLE_CTAPHID_PING 31 | #define DISABLE_CTAPHID_WINK 32 | #define DISABLE_CTAPHID_CBOR 33 | 34 | // 0xRRGGBB 35 | #define LED_INIT_VALUE 0x0a0300 36 | #define LED_MAX_SCALER 40 37 | #define LED_MIN_SCALER 1 38 | // # of ms between each change in LED 39 | #define HEARTBEAT_PERIOD 5 40 | #define BOOTLOADER_HEARTBEAT 41 | // Each LED channel will be multiplied by a integer between LED_MAX_SCALER 42 | // and LED_MIN_SCALER to cause the slow pulse. E.g. 43 | // #define LED_INIT_VALUE 0x301000 44 | // #define LED_MAX_SCALER 30 45 | // #define LED_MIN_SCALER 1 46 | // #define HEARTBEAT_PERIOD 8 47 | // Will pulse from 0x301000 to 0x903000 to 0x301000 ... 48 | // Which will take ~8 * (30)*2 ms 49 | 50 | // Button 51 | #define SOLO_BUTTON_PORT GPIOA 52 | #define SOLO_BUTTON_PIN LL_GPIO_PIN_0 53 | 54 | #define SKIP_BUTTON_CHECK_WITH_DELAY 0 55 | #define SKIP_BUTTON_CHECK_FAST 1 56 | 57 | #if DEBUG_LEVEL > 0 || defined(NK_TEST_MODE) 58 | #warning "Selected development name for bootloader" 59 | #define SOLO_PRODUCT_NAME ("Nitrokey FIDO2 Bootloader Development " SOLO_VERSION) 60 | #else 61 | #define SOLO_PRODUCT_NAME ("Nitrokey FIDO2 Bootloader " SOLO_VERSION) 62 | #endif 63 | 64 | #include "app-common.h" 65 | 66 | 67 | void printing_init(); 68 | void hw_init(int lf); 69 | 70 | // Trigger software reset 71 | void device_reboot(); 72 | 73 | int is_authorized_to_boot(); 74 | int is_bootloader_disabled(); 75 | void bootloader_heartbeat(); 76 | 77 | // Return 1 if Solo is secure/locked. 78 | int solo_is_locked(); 79 | 80 | 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /docs/solo/code-overview.md: -------------------------------------------------------------------------------- 1 | # Overview of firmware 2 | 3 | This is a high level overview of the code. We aim to make the code self documenting 4 | and easy to understand, especially when paired with a high level overview. 5 | 6 | ## FIDO2 codebase 7 | 8 | * `main.c` - calls high level functions and implements event loop. 9 | 10 | * `ctaphid.c` - implements [USBHID protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb) for FIDO. 11 | 12 | * `u2f.c` - implements [U2F protocol](https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html). 13 | 14 | * `ctap.c` - implements [CTAP2 protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html). 15 | 16 | * `ctap_parse.c` - implements parsing for CTAP protocol. 17 | * this could use some work minimizing. 18 | 19 | * `log.c` - embedded friendly debug logging. 20 | 21 | * `crypto.c` - software implementation of the crypto needs of the application. Generally this will be copied and edited for different platforms. API defined in `crypto.h` should be the same. 22 | 23 | * `device.h` - definitions of functions that are platform specific and should be implemented separately. See `device.c` in any of the implementations to see examples. 24 | 25 | ## Data flow 26 | 27 | The main loop will poll the USB peripheral to see if any messages arrived, 28 | and then pass each one to the USBHID layer. 29 | 30 | Once a USBHID message is fully buffered, it will be acted on, unless there was a previous error. 31 | This will get passed up to U2F or CTAP2 layer. The response is buffered and then written out to USB. 32 | 33 | Depending on platform, there should be a minimum number of interrupts configured. USB will need interrupts, 34 | and possibly timer interrupts for keeping track of time. ST implementation users a 16-bit timer to track time, 35 | and interrupts to count overflows. 36 | 37 | If the application is waiting on user input in CTAP2, then USBHID messages need to be continued to be polled, 38 | to catch any [cancel command](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-hid-cancel). 39 | Also, every 100ms or so, an update needs to be sent via USBHID if the CTAP2 application is still processing a getAssertion request, 40 | a makeCredential request, or is waiting on user input. ST leverages same 16-bit timer interrupt for this. 41 | -------------------------------------------------------------------------------- /fido2/extensions/wallet.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef WALLET_H_ 8 | #define WALLET_H_ 9 | 10 | #include 11 | 12 | #define WALLET_MAX_BUFFER (32 + 255) 13 | 14 | // Sign request 15 | // op: 0x10 16 | // authType: 0x00 //sign? 17 | // reserved: 0x00 // mbedtls signature alg identifier 18 | // pinAuth: data[16] 19 | // challenge-length: 1-255 20 | // challenge: data[1-255] 21 | // keyID-length: 1-255 22 | // keyID: data[1-255] 23 | 24 | // Resp: normal U2F auth response 25 | 26 | // Register request 27 | // op: 0x11 28 | // formatType: 0x00 //sign? [0x00: WIF, 0x01: raw] 29 | // keyType: 0x03 // mbedtls signature alg identifier 30 | // key-length: 1-255 31 | // key: data[1-255] 32 | 33 | 34 | // Resp: modded U2F auth response 35 | 36 | // PIN request 37 | // op: 0x12 38 | // subcmd: 0x00 // Same as CTAP pin subcommands 39 | // reserved: 0x03 // mbedtls signature alg identifier 40 | // publickey: data[64] 41 | // OR 42 | // pinAuth data[64] 43 | // OR 44 | // pinHashEnc data[64] 45 | // OR 46 | // newPinEnc data[64] 47 | 48 | // key: data[1-255] 49 | // keyID-length: 1-255 50 | // keyID: data[1-255] 51 | 52 | // Resp: modded U2F auth response 53 | // Returns public key OR pinAuth 54 | 55 | // Only response to this challenge to prevent interference 56 | #define WALLET_TAG "\x8C\x27\x90\xf6" 57 | 58 | #define WALLET_MIN_LENGTH (4 + 4 + 16) 59 | 60 | #define WALLET_VERSION "WALLET_V1.0" 61 | 62 | #define MAX_CHALLENGE_SIZE 229 63 | #define MAX_KEYID_SIZE 228 64 | 65 | #define MAX_PAYLOAD_SIZE (255 - 16 - 4 - 4) 66 | 67 | typedef struct 68 | { 69 | uint8_t operation; 70 | uint8_t p1; 71 | uint8_t p2; 72 | uint8_t numArgs; 73 | uint8_t tag[4]; 74 | uint8_t pinAuth[16]; 75 | uint8_t payload[MAX_PAYLOAD_SIZE]; 76 | }__attribute__((packed)) wallet_request; 77 | 78 | 79 | typedef enum 80 | { 81 | WalletSign = 0x10, 82 | WalletRegister = 0x11, 83 | WalletPin = 0x12, 84 | WalletReset= 0x13, 85 | WalletVersion= 0x14, 86 | WalletRng = 0x15, 87 | WalletBootloader = 0x20, 88 | } WalletOperation; 89 | 90 | 91 | int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen); 92 | 93 | void wallet_init(); 94 | 95 | #endif /* WALLET_H_ */ 96 | -------------------------------------------------------------------------------- /targets/stm32l432/linker/stm32l4xx.ld-old: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 SoloKeys Developers */ 2 | /* */ 3 | /* Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be */ 6 | /* copied, modified, or distributed except according to those terms. */ 7 | 8 | ENTRY(Reset_Handler) 9 | 10 | /* End of RAM */ 11 | _estack = 0x2000c000; 12 | 13 | _MIN_STACK_SIZE = 0x400; 14 | 15 | /* 16 | len | 20 KB/10p| 196KB-8-8/98p | 2kB/1p | 38 KB/19p | 17 | pos | 0->20 KB | 20->216KB-8-8 | 216kB -> 218 kB | 218->256 KB | 18 | posp | 0-10 | 10-113 | 113-114 | 113-128 | 19 | desc | bootloader | application | bootloader data | secrets/data | 20 | 21 | Last 8 bytes in application space are occupied by bootloader flags - app 22 | authorization and bootloader activation flag. 23 | */ 24 | 25 | /* Current firmware version number is concatenated to the firmware code - see .flag marker */ 26 | /* flash length is (APPLICATION_END_PAGE-20*1024), where 20K is bootloader */ 27 | 28 | MEMORY 29 | { 30 | flash (rx) : ORIGIN = 0x08000000 + 20K, LENGTH = 128K - 20K - 8 - 38K -2K 31 | ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K 32 | sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K 33 | } 34 | 35 | SECTIONS 36 | { 37 | .isr_vector : 38 | { 39 | . = ALIGN(8); 40 | KEEP(*(.isr_vector)) 41 | . = ALIGN(8); 42 | } >flash 43 | 44 | .text : 45 | { 46 | . = ALIGN(8); 47 | *(.text*) 48 | *(.rodata*) 49 | KEEP(*(.init)) 50 | KEEP(*(.finit)) 51 | . = ALIGN(8); 52 | _etext = .; 53 | } >flash 54 | 55 | _sidata = LOADADDR(.data); 56 | 57 | .data : 58 | { 59 | . = ALIGN(8); 60 | _sdata = .; 61 | *(.data*) 62 | . = ALIGN(8); 63 | _edata = .; 64 | } >sram2 AT> flash 65 | 66 | .flag : 67 | { 68 | . = ALIGN(8); 69 | KEEP(*(.flag)) ; 70 | } > flash 71 | 72 | .bss : 73 | { 74 | . = ALIGN(4); 75 | _sbss = .; 76 | __bss_start__ = _sbss; 77 | *(.bss*) 78 | *(COMMON) 79 | . = ALIGN(4); 80 | _ebss = .; 81 | __bss_end__ = _ebss; 82 | } > ram 83 | 84 | ._stack : 85 | { 86 | . = ALIGN(8); 87 | end = .; 88 | _end = .; 89 | . = . + _MIN_STACK_SIZE; 90 | . = ALIGN(8); 91 | } > ram 92 | 93 | } 94 | -------------------------------------------------------------------------------- /targets/stm32l432/linker/stm32l4xx_extra.ld: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 SoloKeys Developers */ 2 | /* */ 3 | /* Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be */ 6 | /* copied, modified, or distributed except according to those terms. */ 7 | 8 | ENTRY(Reset_Handler) 9 | 10 | /* End of RAM */ 11 | _estack = 0x2000c000; 12 | 13 | _MIN_STACK_SIZE = 0x400; 14 | 15 | /* 16 | len | 32 KB/16p| 184KB-8-8/92p | 2kB/1p | 38 KB/19p | 17 | pos | 0->32 KB | 32->216KB-8-8 | 216kB -> 218 kB | 218->256 KB | 18 | posp | 0-16 | 16-113 | 113-114 | 113-128 | 19 | desc | bootloader | application | bootloader data | secrets/data | 20 | 21 | Last 8 bytes in application space are occupied by bootloader flags - app 22 | authorization and bootloader activation flag. 23 | */ 24 | 25 | /* Current firmware version number is concatenated to the firmware code - see .flag marker */ 26 | /* flash length is (APPLICATION_END_PAGE-20*1024), where 20K is bootloader */ 27 | 28 | MEMORY 29 | { 30 | flash (rx) : ORIGIN = 0x08000000 + 20K + 12K, LENGTH = 216K - 20K - 12K - 8 31 | ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K 32 | sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K 33 | } 34 | 35 | SECTIONS 36 | { 37 | .isr_vector : 38 | { 39 | . = ALIGN(8); 40 | KEEP(*(.isr_vector)) 41 | . = ALIGN(8); 42 | } >flash 43 | 44 | .text : 45 | { 46 | . = ALIGN(8); 47 | *(.text*) 48 | *(.rodata*) 49 | KEEP(*(.init)) 50 | KEEP(*(.finit)) 51 | . = ALIGN(8); 52 | _etext = .; 53 | } >flash 54 | 55 | _sidata = LOADADDR(.data); 56 | 57 | .data : 58 | { 59 | . = ALIGN(8); 60 | _sdata = .; 61 | *(.data*) 62 | . = ALIGN(8); 63 | _edata = .; 64 | } >ram AT> flash 65 | 66 | .flag : 67 | { 68 | . = ALIGN(8); 69 | KEEP(*(.flag)) ; 70 | } > flash 71 | 72 | .bss : 73 | { 74 | . = ALIGN(4); 75 | _sbss = .; 76 | __bss_start__ = _sbss; 77 | *(.bss*) 78 | *(COMMON) 79 | . = ALIGN(4); 80 | _ebss = .; 81 | __bss_end__ = _ebss; 82 | } > ram 83 | 84 | ._stack : 85 | { 86 | . = ALIGN(8); 87 | end = .; 88 | _end = .; 89 | . = . + _MIN_STACK_SIZE; 90 | . = ALIGN(8); 91 | } > ram 92 | 93 | } 94 | -------------------------------------------------------------------------------- /docs/solo/porting.md: -------------------------------------------------------------------------------- 1 | # Usage and Porting 2 | 3 | Solo is designed to be used as a library or ported to other platforms easily. Here is an example 4 | `main()` function. 5 | 6 | ```c 7 | int main() 8 | { 9 | uint8_t hidmsg[64]; 10 | uint32_t t1 = 0; 11 | 12 | device_init(); 13 | memset(hidmsg,0,sizeof(hidmsg)); 14 | 15 | while(1) 16 | { 17 | 18 | if (usbhid_recv(hidmsg) > 0) 19 | { 20 | ctaphid_handle_packet(hidmsg); // pass into libsolo! 21 | memset(hidmsg, 0, sizeof(hidmsg)); 22 | } 23 | 24 | 25 | ctaphid_check_timeouts(); 26 | } 27 | 28 | } 29 | 30 | ``` 31 | 32 | `ctaphid_handle_packet(hidmsg);` is the entrance into the HID layer of libsolo, and will buffer packets and pass them 33 | into FIDO2 or U2F layers. 34 | 35 | Everything in the library is cross-platform, but it needs some functions implemented that are usually 36 | platform specific. For example, how should libsolo implement an atomic counter? Where should it save state? 37 | For all of these platform specific functions, the library contains it's own `weak` definition, so the library will compile and run. 38 | LibSolo by default will not try to use an atomic 39 | counter or save data persistently -- that needs to be implemented externally. 40 | 41 | If you are using libsolo on another platform, 42 | you should take a look at these possibly platform specific functions. They are listed in `fido2/device.h`. 43 | If you'd like to reimplement any of the functions, then simply implement the function and compile normally. 44 | GCC will replace libsolo's `weak` defined functions (everything in `fido2/device.h`) with your functions. By doing this, you 45 | are replacing the function that is used by libsolo. 46 | 47 | To get the library to compile 48 | and run, you only need to implement one function for libsolo: `usbhid_send(uint8_t * send)`, which 49 | is called by the library to send a 64 byte packet over a USB HID endpoint. In essence, you are giving 50 | libsolo a function to write to USB. 51 | 52 | The rest of the definitions in `fido2/device.h` are not required to compile and run so you can 53 | immediately hit the ground running and iterative add what else you need. You'll definitely want 54 | to continue implementing other functions in `fido2/device.h`. For example, no data will be stored 55 | persistently until you define how it can be done! 56 | 57 | For examples, check out the build for STM32L4 and PC (check out `pc/device` and `targets/stm32l432/src/device.c`). 58 | 59 | If there's something that doesn't work for you -- send a pull request! It's better if we can 60 | work together off of the same repo and not fork. -------------------------------------------------------------------------------- /targets/stm32l432/linker/stm32l4xx.ld.in: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 SoloKeys Developers */ 2 | /* */ 3 | /* Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be */ 6 | /* copied, modified, or distributed except according to those terms. */ 7 | 8 | ENTRY(Reset_Handler) 9 | 10 | /* End of RAM */ 11 | _estack = 0x2000c000; 12 | 13 | _MIN_STACK_SIZE = 0x400; 14 | 15 | /* 16 | For PAGES == 256 17 | len | 20 KB/10p| 196KB-8-8/98p | 2kB/1p | 38 KB/19p | 18 | pos | 0->20 KB | 20->216KB-8-8 | 216kB -> 218 kB | 218->256 KB | 19 | posp | 0-10 | 10-113 | 113-114 | 113-128 | 20 | desc | bootloader | application | bootloader data | secrets/data | 21 | 22 | Last 8 bytes in application space are occupied by bootloader flags - app 23 | authorization and bootloader activation flag. 24 | */ 25 | 26 | /* Current firmware version number is concatenated to the firmware code - see .flag marker */ 27 | /* flash length is (APPLICATION_END_PAGE-20*1024), where 20K is bootloader 28 | Template parameters: 29 | PAGES=__PAGES__ 30 | */ 31 | 32 | MEMORY 33 | { 34 | flash (rx) : ORIGIN = 0x08000000 + 20K, LENGTH = __PAGES__*2K - 20K - 8 - 38K -2K 35 | ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K 36 | sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K 37 | } 38 | 39 | SECTIONS 40 | { 41 | .isr_vector : 42 | { 43 | . = ALIGN(8); 44 | KEEP(*(.isr_vector)) 45 | . = ALIGN(8); 46 | } >flash 47 | 48 | .text : 49 | { 50 | . = ALIGN(8); 51 | *(.text*) 52 | *(.rodata*) 53 | KEEP(*(.init)) 54 | KEEP(*(.finit)) 55 | . = ALIGN(8); 56 | _etext = .; 57 | } >flash 58 | 59 | _sidata = LOADADDR(.data); 60 | 61 | .data : 62 | { 63 | . = ALIGN(8); 64 | _sdata = .; 65 | *(.data*) 66 | . = ALIGN(8); 67 | _edata = .; 68 | } >sram2 AT> flash 69 | 70 | .flag : 71 | { 72 | . = ALIGN(8); 73 | KEEP(*(.flag)) ; 74 | } > flash 75 | 76 | .bss : 77 | { 78 | . = ALIGN(4); 79 | _sbss = .; 80 | __bss_start__ = _sbss; 81 | *(.bss*) 82 | *(COMMON) 83 | . = ALIGN(4); 84 | _ebss = .; 85 | __bss_end__ = _ebss; 86 | } > ram 87 | 88 | ._stack : 89 | { 90 | . = ALIGN(8); 91 | end = .; 92 | _end = .; 93 | . = . + _MIN_STACK_SIZE; 94 | . = ALIGN(8); 95 | } > ram 96 | 97 | } 98 | -------------------------------------------------------------------------------- /tools/gadgetfs/Makefile: -------------------------------------------------------------------------------- 1 | TOP := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) 2 | KERNEL_FULL_VERSION := $(shell uname -r) 3 | KERNEL_VERSION := $(shell uname -r | grep -o "^[^-]*") 4 | KERNEL_MAJOR := $(shell uname -r | cut -d. -f1) 5 | KERNEL_MINOR := $(shell uname -r | cut -d. -f2) 6 | 7 | MANUFACTURER = "Solo" 8 | SERIAL = "1234567890" 9 | IDVENDOR = "0x0483" 10 | IDPRODUCT = "0xa2ca" 11 | PRODUCT = "Solo Software Authenticator" 12 | CONFIGFS = /sys/kernel/config 13 | CONFIGFS_FIDO2 = $(CONFIGFS)/usb_gadget/fido2 14 | 15 | obj-m := dummy_hcd.o 16 | KVERSION := $(shell uname -r) 17 | SHELL := /bin/bash 18 | 19 | all: dummy_hcd.ko 20 | 21 | install: dummy_hcd.ko 22 | modprobe libcomposite 23 | insmod dummy_hcd.ko 24 | mkdir -p $(CONFIGFS_FIDO2) 25 | mkdir -p $(CONFIGFS_FIDO2)/configs/c.1 26 | mkdir -p $(CONFIGFS_FIDO2)/functions/hid.usb0 27 | echo 0 > $(CONFIGFS_FIDO2)/functions/hid.usb0/protocol 28 | echo 0 > $(CONFIGFS_FIDO2)/functions/hid.usb0/subclass 29 | echo 64 > $(CONFIGFS_FIDO2)/functions/hid.usb0/report_length 30 | echo -ne "\x06\xd0\xf1\x09\x01\xa1\x01\x09\x20\x15\x00\x26\xff\x00\x75\x08\x95\x40\x81\x02\x09\x21\x15\x00\x26\xff\x00\x75\x08\x95\x40\x91\x02\xc0" > $(CONFIGFS_FIDO2)/functions/hid.usb0/report_desc 31 | mkdir $(CONFIGFS_FIDO2)/strings/0x409 32 | mkdir $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409 33 | echo $(IDPRODUCT) > $(CONFIGFS_FIDO2)/idProduct 34 | echo $(IDVENDOR) > $(CONFIGFS_FIDO2)/idVendor 35 | echo $(SERIAL) > $(CONFIGFS_FIDO2)/strings/0x409/serialnumber 36 | echo $(MANUFACTURER) > $(CONFIGFS_FIDO2)/strings/0x409/manufacturer 37 | echo $(PRODUCT) > $(CONFIGFS_FIDO2)/strings/0x409/product 38 | echo "Configuration 1" > $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409/configuration 39 | echo 120 > $(CONFIGFS_FIDO2)/configs/c.1/MaxPower 40 | ln -s $(CONFIGFS_FIDO2)/functions/hid.usb0 $(CONFIGFS_FIDO2)/configs/c.1 41 | echo "dummy_udc.0" > $(CONFIGFS_FIDO2)/UDC 42 | 43 | uninstall: 44 | echo "" > $(CONFIGFS_FIDO2)/UDC 45 | rm $(CONFIGFS_FIDO2)/configs/c.1/hid.usb0 46 | rmdir $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409 47 | rmdir $(CONFIGFS_FIDO2)/configs/c.1 48 | rmdir $(CONFIGFS_FIDO2)/functions/hid.usb0 49 | rmdir $(CONFIGFS_FIDO2)/strings/0x409 50 | rmdir $(CONFIGFS_FIDO2) 51 | rmmod dummy_hcd.ko 52 | 53 | dummy_hcd.ko: dummy_hcd.c 54 | $(MAKE) -C /lib/modules/$(KERNEL_FULL_VERSION)/build M=$(TOP) modules 55 | 56 | dummy_hcd.c: /usr/src/linux-source-$(KERNEL_VERSION).tar.bz2 57 | tar -xvf $^ linux-source-$(KERNEL_VERSION)/drivers/usb/gadget/udc/dummy_hcd.c 58 | cp linux-source-$(KERNEL_VERSION)/drivers/usb/gadget/udc/dummy_hcd.c $@ 59 | 60 | clean: 61 | $(MAKE) -C /lib/modules/$(KERNEL_FULL_VERSION)/build M=$(TOP) clean 62 | rm -rf linux-source-$(KERNEL_VERSION) 63 | rm -f dummy_hcd.c 64 | 65 | 66 | -------------------------------------------------------------------------------- /fido2/log.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _LOG_H 8 | #define _LOG_H 9 | 10 | #ifdef APP_CONFIG 11 | #include APP_CONFIG 12 | #endif 13 | 14 | #include 15 | 16 | #ifndef DEBUG_LEVEL 17 | #define DEBUG_LEVEL 0 18 | #endif 19 | 20 | #define ENABLE_FILE_LOGGING 21 | 22 | void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...); 23 | void LOG_HEX(uint32_t tag, uint8_t * data, int length); 24 | 25 | void set_logging_tag(uint32_t tag); 26 | 27 | typedef enum 28 | { 29 | TAG_GEN = (1 << 0), 30 | TAG_MC = (1 << 1), 31 | TAG_GA = (1 << 2), 32 | TAG_CP = (1 << 3), 33 | TAG_ERR = (1 << 4), 34 | TAG_PARSE = (1 << 5), 35 | TAG_CTAP = (1 << 6), 36 | TAG_U2F = (1 << 7), 37 | TAG_DUMP = (1 << 8), 38 | TAG_GREEN = (1 << 9), 39 | TAG_RED = (1 << 10), 40 | TAG_TIME = (1 << 11), 41 | TAG_HID = (1 << 12), 42 | TAG_USB = (1 << 13), 43 | TAG_WALLET = (1 << 14), 44 | TAG_STOR = (1 << 15), 45 | TAG_DUMP2 = (1 << 16), 46 | TAG_BOOT = (1 << 17), 47 | TAG_EXT = (1 << 18), 48 | TAG_NFC = (1 << 19), 49 | TAG_NFC_APDU = (1 << 20), 50 | TAG_CCID = (1 << 21), 51 | TAG_CM = (1 << 22), 52 | TAG_BUTTON = (1 << 26), 53 | 54 | TAG_NO_TAG = (1UL << 30), 55 | TAG_FILENO = (1UL << 31) 56 | } LOG_TAG; 57 | 58 | #if defined(DEBUG_LEVEL) && DEBUG_LEVEL > 0 59 | 60 | void set_logging_mask(uint32_t mask); 61 | #define printf1(tag,fmt, ...) LOG(tag & ~(TAG_FILENO), NULL, 0, fmt, ##__VA_ARGS__) 62 | #define printf2(tag,fmt, ...) LOG(tag | TAG_FILENO,__FILE__, __LINE__, fmt, ##__VA_ARGS__) 63 | #define printf3(tag,fmt, ...) LOG(tag | TAG_FILENO,__FILE__, __LINE__, fmt, ##__VA_ARGS__) 64 | 65 | #define _dump_hex1(tag,data,len) LOG_HEX(tag,data,len) 66 | #define dump_hex1(tag, data, len) printf1(((tag)|TAG_NO_TAG), "%s[%d]: ", #data, len); _dump_hex1(tag, ((uint8_t *) (data)), len); 67 | #define dump_arr(tag, data) printf1(tag,"Dump of %20s: ", #data); _dump_hex1(tag, data, sizeof(data)); 68 | #define dump_arrl(tag, data, len) printf1(tag,"Dump of %20s: ", #data); _dump_hex1(tag, data, len); 69 | uint32_t timestamp(); 70 | 71 | #else 72 | 73 | #define set_logging_mask(mask) 74 | #define printf1(tag,fmt, ...) 75 | #define printf2(tag,fmt, ...) 76 | #define printf3(tag,fmt, ...) 77 | #define dump_hex1(tag,data,len) 78 | #define dump_arr(tag, data) 79 | #define dump_arrl(tag, data, len) 80 | #define timestamp() 81 | 82 | #endif 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /fido2/log.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #include 8 | #include 9 | #include 10 | #include "log.h" 11 | #include "util.h" 12 | #include "device.h" 13 | 14 | #if DEBUG_LEVEL > 0 15 | 16 | static uint32_t LOGMASK = TAG_FILENO; 17 | 18 | 19 | void set_logging_mask(uint32_t mask) 20 | { 21 | LOGMASK = mask; 22 | } 23 | 24 | 25 | struct logtag 26 | { 27 | uint32_t tagn; 28 | const char * tag; 29 | }; 30 | 31 | struct logtag tagtable[] = { 32 | {TAG_GEN,""}, 33 | {TAG_MC,"MC"}, 34 | {TAG_GA,"GA"}, 35 | {TAG_CP,"CP"}, 36 | {TAG_ERR,"ERR"}, 37 | {TAG_PARSE,"PARSE"}, 38 | {TAG_CTAP,"CTAP"}, 39 | {TAG_U2F,"U2F"}, 40 | {TAG_DUMP,"DUMP"}, 41 | {TAG_DUMP2,"DUMP2"}, 42 | {TAG_HID,"HID"}, 43 | {TAG_USB,"USB"}, 44 | {TAG_GREEN,"DEBUG"}, 45 | {TAG_RED,"DEBUG"}, 46 | {TAG_TIME,"TIME"}, 47 | {TAG_WALLET,"WALLET"}, 48 | {TAG_STOR,"STOR"}, 49 | {TAG_BOOT,"BOOT"}, 50 | {TAG_EXT,"EXT"}, 51 | {TAG_NFC,"NFC"}, 52 | {TAG_NFC_APDU, "NAPDU"}, 53 | {TAG_CCID, "CCID"}, 54 | {TAG_CM, "CRED_MGMT"}, 55 | {TAG_BUTTON, "BUTTON"}, 56 | }; 57 | 58 | 59 | __attribute__((weak)) void set_logging_tag(uint32_t tag) 60 | { 61 | // nothing 62 | } 63 | 64 | void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...) 65 | { 66 | unsigned int i; 67 | 68 | if (((tag & 0x7fffffff) & LOGMASK) == 0) 69 | { 70 | return; 71 | } 72 | for (i = 0; i < sizeof(tagtable)/sizeof(struct logtag); i++) 73 | { 74 | if (tag & tagtable[i].tagn) 75 | { 76 | if (tagtable[i].tag[0] && !(tag & TAG_NO_TAG)) printf("[%s] ", tagtable[i].tag); 77 | i = 0; 78 | break; 79 | } 80 | } 81 | if (i != 0) 82 | { 83 | printf2(TAG_ERR,"INVALID LOG TAG\n"); 84 | exit(1); 85 | } 86 | set_logging_tag(tag); 87 | #ifdef ENABLE_FILE_LOGGING 88 | if (tag & TAG_FILENO) 89 | { 90 | printf("%s:%d: ", filename, num); 91 | } 92 | #endif 93 | va_list args; 94 | va_start(args, fmt); 95 | vprintf(fmt, args); 96 | va_end(args); 97 | } 98 | 99 | void LOG_HEX(uint32_t tag, uint8_t * data, int length) 100 | { 101 | if (((tag & 0x7fffffff) & LOGMASK) == 0) 102 | { 103 | return; 104 | } 105 | set_logging_tag(tag); 106 | dump_hex(data,length); 107 | } 108 | 109 | uint32_t timestamp() 110 | { 111 | static uint32_t t1 = 0; 112 | uint32_t t2 = millis(); 113 | uint32_t diff = t2 - t1; 114 | t1 = t2; 115 | return diff; 116 | } 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /targets/stm32l432/build/bootloader.mk: -------------------------------------------------------------------------------- 1 | include build/common.mk 2 | 3 | # ST related 4 | SRC = bootloader/main.c bootloader/bootloader.c 5 | SRC += bootloader/pubkey_bootloader.c bootloader/version_check.c 6 | SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c 7 | SRC += src/fifo.c src/attestation.c src/sense.c 8 | SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c 9 | SRC += $(DRIVER_LIBS) $(USB_LIB) 10 | 11 | # FIDO2 lib 12 | SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/extensions/extensions.c 13 | SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c 14 | SRC += ../../fido2/crypto.c 15 | 16 | # Crypto libs 17 | SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c 18 | SRC += ../../crypto/cifra/src/sha512.c ../../crypto/cifra/src/blockwise.c 19 | 20 | OBJ1=$(SRC:.c=.o) 21 | OBJ=$(OBJ1:.s=.o) 22 | 23 | 24 | INC = -Ibootloader/ -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions 25 | INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc 26 | INC += -I../../crypto/tiny-AES-c 27 | INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext 28 | 29 | ifndef LDSCRIPT 30 | LDSCRIPT=linker/bootloader_stm32l4xx.ld 31 | endif 32 | 33 | CFLAGS= $(INC) 34 | 35 | TARGET=bootloader 36 | HW=-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb 37 | 38 | # Solo or Nucleo board 39 | CHIP=STM32L432xx 40 | 41 | ifndef DEBUG 42 | DEBUG=0 43 | endif 44 | 45 | DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"bootloader.h\" $(EXTRA_DEFINES) 46 | # DEFINES += -DTEST_SOLO_STM32 -DTEST -DTEST_FIFO=1 47 | 48 | CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections $(HW) -g $(VERSION_FLAGS) 49 | LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys 50 | LDFLAGS_INFO=-Wl,--print-memory-usage -Wl,--print-gc-sections 51 | LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic $(LDFLAGS_INFO) 52 | 53 | 54 | .PRECIOUS: %.o 55 | include build/buildinfo.mk 56 | 57 | all: $(TARGET).elf 58 | $(SZ) $^ 59 | 60 | 61 | %.o: %.c $(LDSCRIPT) 62 | @echo "*** bootloader: $<" 63 | @$(CC) $< $(HW) -Os $(CFLAGS) -o $@ 64 | 65 | ../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c 66 | @echo "*** $<" 67 | @$(CC) $^ $(HW) -Os $(CFLAGS) -o $@ 68 | 69 | %.o: %.s 70 | @echo "*** bootloader: $<" 71 | @$(CC) $^ $(HW) -Os $(CFLAGS) -o $@ 72 | 73 | ifndef PAGES 74 | PAGES=64 75 | $(warning PAGES is not defined - setting to new value: "$(PAGES)") 76 | endif 77 | $(LDSCRIPT): $(LDSCRIPT).in 78 | sed 's/__PAGES__/$(PAGES)/g' < $< >$@ 79 | 80 | %.elf: $(OBJ) 81 | $(CC) $^ $(HW) $(LDFLAGS) -o $@ 2>&1 | tee $(TARGET)-linking.buildinfo 82 | $(SZ) $@ 83 | 84 | %.hex: %.elf $(TARGET).buildinfo $(TARGET)-sections.buildinfo 85 | $(CP) -O ihex $< $(TARGET).hex 86 | @echo "Bootloader built flags: $(CFLAGS)" 87 | 88 | clean: 89 | -cp $(LDSCRIPT){,-} -v 90 | rm -f *.o src/*.o bootloader/*.o *.elf $(OBJ) $(LDSCRIPT) 91 | -------------------------------------------------------------------------------- /fido2/ctap_errors.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #define CTAP1_ERR_SUCCESS 0x00 8 | #define CTAP2_OK 0x00 9 | #define CTAP1_ERR_INVALID_COMMAND 0x01 10 | #define CTAP1_ERR_INVALID_PARAMETER 0x02 11 | #define CTAP1_ERR_INVALID_LENGTH 0x03 12 | #define CTAP1_ERR_INVALID_SEQ 0x04 13 | #define CTAP1_ERR_TIMEOUT 0x05 14 | #define CTAP1_ERR_CHANNEL_BUSY 0x06 15 | #define CTAP1_ERR_LOCK_REQUIRED 0x0A 16 | #define CTAP1_ERR_INVALID_CHANNEL 0x0B 17 | #define CTAP2_ERR_CBOR_PARSING 0x12 18 | #define CTAP2_ERR_CBOR_UNEXPECTED_TYPE 0x11 19 | #define CTAP2_ERR_INVALID_CBOR 0x12 20 | #define CTAP2_ERR_INVALID_CBOR_TYPE 0x12 21 | #define CTAP2_ERR_MISSING_PARAMETER 0x14 22 | #define CTAP2_ERR_LIMIT_EXCEEDED 0x15 23 | #define CTAP2_ERR_UNSUPPORTED_EXTENSION 0x16 24 | #define CTAP2_ERR_TOO_MANY_ELEMENTS 0x17 25 | #define CTAP2_ERR_EXTENSION_NOT_SUPPORTED 0x18 26 | #define CTAP2_ERR_CREDENTIAL_EXCLUDED 0x19 27 | #define CTAP2_ERR_CREDENTIAL_NOT_VALID 0x20 28 | #define CTAP2_ERR_PROCESSING 0x21 29 | #define CTAP2_ERR_INVALID_CREDENTIAL 0x22 30 | #define CTAP2_ERR_USER_ACTION_PENDING 0x23 31 | #define CTAP2_ERR_OPERATION_PENDING 0x24 32 | #define CTAP2_ERR_NO_OPERATIONS 0x25 33 | #define CTAP2_ERR_UNSUPPORTED_ALGORITHM 0x26 34 | #define CTAP2_ERR_OPERATION_DENIED 0x27 35 | #define CTAP2_ERR_KEY_STORE_FULL 0x28 36 | #define CTAP2_ERR_NOT_BUSY 0x29 37 | #define CTAP2_ERR_NO_OPERATION_PENDING 0x2A 38 | #define CTAP2_ERR_UNSUPPORTED_OPTION 0x2B 39 | #define CTAP2_ERR_INVALID_OPTION 0x2C 40 | #define CTAP2_ERR_KEEPALIVE_CANCEL 0x2D 41 | #define CTAP2_ERR_NO_CREDENTIALS 0x2E 42 | #define CTAP2_ERR_USER_ACTION_TIMEOUT 0x2F 43 | #define CTAP2_ERR_NOT_ALLOWED 0x30 44 | #define CTAP2_ERR_PIN_INVALID 0x31 45 | #define CTAP2_ERR_PIN_BLOCKED 0x32 46 | #define CTAP2_ERR_PIN_AUTH_INVALID 0x33 47 | #define CTAP2_ERR_PIN_AUTH_BLOCKED 0x34 48 | #define CTAP2_ERR_PIN_NOT_SET 0x35 49 | #define CTAP2_ERR_PIN_REQUIRED 0x36 50 | #define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37 51 | #define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38 52 | #define CTAP2_ERR_REQUEST_TOO_LARGE 0x39 53 | #define CTAP2_ERR_ACTION_TIMEOUT 0x3A 54 | #define CTAP1_ERR_OTHER 0x7F 55 | #define CTAP2_ERR_SPEC_LAST 0xDF 56 | #define CTAP2_ERR_EXTENSION_FIRST 0xE0 57 | #define CTAP2_ERR_EXTENSION_LAST 0xEF 58 | #define CTAP2_ERR_VENDOR_FIRST 0xF0 59 | #define CTAP2_ERR_VENDOR_LAST 0xFF 60 | -------------------------------------------------------------------------------- /targets/stm32l432/lib/usbd/usbd_conf.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file USB_Device/HID_Standalone/Inc/usbd_conf.h 4 | * @author MCD Application Team 5 | * @brief General low level driver configuration 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 10 | * All rights reserved.

11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted, provided that the following conditions are met: 14 | * 15 | * 1. Redistribution of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright notice, 18 | * this list of conditions and the following disclaimer in the documentation 19 | * and/or other materials provided with the distribution. 20 | * 3. Neither the name of STMicroelectronics nor the names of other 21 | * contributors to this software may be used to endorse or promote products 22 | * derived from this software without specific written permission. 23 | * 4. This software, including modifications and/or derivative works of this 24 | * software, must execute solely and exclusively on microcontroller or 25 | * microprocessor devices manufactured by or for STMicroelectronics. 26 | * 5. Redistribution and use of this software other than as permitted under 27 | * this license is void and will automatically terminate your rights under 28 | * this license. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 31 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 32 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 33 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 34 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 35 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 36 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 38 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 41 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | * 43 | ****************************************************************************** 44 | */ 45 | #ifndef __USBD_CONF_H 46 | #define __USBD_CONF_H 47 | 48 | #include "stm32l4xx_hal.h" 49 | #include 50 | #include 51 | #include 52 | 53 | #define USBD_MAX_NUM_INTERFACES 1 54 | #define USBD_MAX_NUM_CONFIGURATION 1 55 | #define USBD_SELF_POWERED 0 56 | #define USBD_DEBUG_LEVEL 0 57 | 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /targets/stm32l432/lib/usbd/usbd_desc.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file USB_Device/HID_Standalone/Inc/usbd_desc.h 4 | * @author MCD Application Team 5 | * @brief Header for usbd_desc.c module 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 10 | * All rights reserved.

11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted, provided that the following conditions are met: 14 | * 15 | * 1. Redistribution of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright notice, 18 | * this list of conditions and the following disclaimer in the documentation 19 | * and/or other materials provided with the distribution. 20 | * 3. Neither the name of STMicroelectronics nor the names of other 21 | * contributors to this software may be used to endorse or promote products 22 | * derived from this software without specific written permission. 23 | * 4. This software, including modifications and/or derivative works of this 24 | * software, must execute solely and exclusively on microcontroller or 25 | * microprocessor devices manufactured by or for STMicroelectronics. 26 | * 5. Redistribution and use of this software other than as permitted under 27 | * this license is void and will automatically terminate your rights under 28 | * this license. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 31 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 32 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 33 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 34 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 35 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 36 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 38 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 41 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | * 43 | ****************************************************************************** 44 | */ 45 | 46 | /* Define to prevent recursive inclusion -------------------------------------*/ 47 | #ifndef __USBD_DESC_H 48 | #define __USBD_DESC_H 49 | 50 | /* Includes ------------------------------------------------------------------*/ 51 | #include "usbd_def.h" 52 | 53 | #define USB_SIZ_BOS_DESC 0x0C 54 | #define USB_SIZ_STRING_SERIAL 0x1A 55 | 56 | extern USBD_DescriptorsTypeDef Solo_Desc; 57 | 58 | #endif /* __USBD_DESC_H */ 59 | 60 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 61 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include fido2/version.mk 2 | 3 | #define uECC_arch_other 0 4 | #define uECC_x86 1 5 | #define uECC_x86_64 2 6 | #define uECC_arm 3 7 | #define uECC_arm_thumb 4 8 | #define uECC_arm_thumb2 5 9 | #define uECC_arm64 6 10 | #define uECC_avr 7 11 | ecc_platform=2 12 | 13 | src = pc/device.c pc/main.c 14 | 15 | obj = $(src:.c=.o) 16 | 17 | LIBCBOR = tinycbor/lib/libtinycbor.a 18 | LIBSOLO = fido2/libsolo.a 19 | 20 | ifeq ($(shell uname -s),Darwin) 21 | export LDFLAGS = -Wl,-dead_strip 22 | else 23 | export LDFLAGS = -Wl,--gc-sections 24 | endif 25 | LDFLAGS += $(LIBSOLO) $(LIBCBOR) 26 | 27 | 28 | CFLAGS = -O2 -fdata-sections -ffunction-sections -g 29 | ECC_CFLAGS = -O2 -fdata-sections -ffunction-sections -DuECC_PLATFORM=$(ecc_platform) 30 | 31 | INCLUDES = -I../ -I./fido2/ -I./pc -I../pc -I./tinycbor/src 32 | 33 | CFLAGS += $(INCLUDES) 34 | CFLAGS += -DAES256=1 -DSOLO_EXPERIMENTAL=1 -DDEBUG_LEVEL=1 35 | 36 | name = main 37 | 38 | .PHONY: all $(LIBCBOR) $(LIBSOLO) black blackcheck cppcheck wink fido2-test clean full-clean ci test clean version 39 | all: $(name) 40 | 41 | tinycbor/Makefile crypto/tiny-AES-c/aes.c: 42 | git submodule update --init 43 | 44 | .PHONY: cbor 45 | cbor: $(LIBCBOR) 46 | 47 | $(LIBCBOR): 48 | cd tinycbor/ && $(MAKE) LDFLAGS='' -j8 49 | 50 | $(LIBSOLO): 51 | cd fido2/ && $(MAKE) CFLAGS="$(CFLAGS)" ECC_CFLAGS="$(ECC_CFLAGS)" APP_CONFIG=app.h -j8 52 | 53 | version: 54 | @git describe 55 | 56 | test: venv 57 | $(MAKE) clean 58 | -$(MAKE) -C . main 59 | $(MAKE) clean 60 | $(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)" VERSION_FULL=${SOLO_VERSION_FULL} 61 | $(MAKE) clean 62 | -$(MAKE) cppcheck 63 | 64 | $(name): $(obj) $(LIBCBOR) $(LIBSOLO) 65 | $(CC) $(LDFLAGS) -o $@ $(obj) $(LDFLAGS) 66 | 67 | venv: 68 | python3 -m venv venv 69 | venv/bin/pip -q install --upgrade pip 70 | venv/bin/pip -q install --upgrade -r tools/requirements.txt 71 | venv/bin/pip -q install --upgrade black 72 | 73 | # selectively reformat our own code 74 | black: venv 75 | venv/bin/black --skip-string-normalization --check tools/ 76 | 77 | wink: venv 78 | venv/bin/solo key wink 79 | 80 | fido2-test: venv 81 | venv/bin/python tools/ctap_test.py 82 | 83 | update: 84 | git fetch --tags 85 | git checkout master 86 | git rebase origin/master 87 | git submodule update --init --recursive 88 | 89 | 90 | CPPCHECK_FLAGS=--quiet --error-exitcode=2 91 | 92 | cppcheck: 93 | cppcheck $(CPPCHECK_FLAGS) crypto/aes-gcm 94 | cppcheck $(CPPCHECK_FLAGS) crypto/sha256 95 | cppcheck $(CPPCHECK_FLAGS) fido2 96 | cppcheck $(CPPCHECK_FLAGS) pc 97 | 98 | clean: 99 | rm -f *.o main.exe main $(obj) 100 | for f in crypto/tiny-AES-c/Makefile tinycbor/Makefile ; do \ 101 | if [ -f "$$f" ]; then \ 102 | (cd `dirname $$f` ; git checkout -- .) ;\ 103 | (cd `dirname $$f` ; make clean) ;\ 104 | fi ;\ 105 | done 106 | cd fido2 && $(MAKE) clean 107 | 108 | full-clean: clean 109 | rm -rf venv 110 | 111 | ci: 112 | git submodule update --init --recursive 113 | $(MAKE) docker-build-toolchain 114 | $(MAKE) docker-build-all 115 | 116 | .PHONY: simulation 117 | simulation: main 118 | -rm -v authenticator_state*.bin resident_keys.bin 119 | while true; do ./main; sleep 0.1; done; 120 | 121 | include docker_build.mk 122 | -------------------------------------------------------------------------------- /targets/stm32l432/src/fifo.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #include 8 | #include 9 | #include 10 | #include "fifo.h" 11 | #include "log.h" 12 | 13 | 14 | FIFO_CREATE(debug,4096,1) 15 | 16 | FIFO_CREATE(hidmsg,100,64) 17 | 18 | #if TEST_FIFO 19 | FIFO_CREATE(test,10,100) 20 | void fifo_test() 21 | { 22 | int ret; 23 | uint8_t data[10][100]; 24 | uint8_t verif[10][100]; 25 | 26 | printf1(TAG_GREEN,"init\r\n"); 27 | for (int i = 0; i < 10; i++) 28 | { 29 | memset(data[i],i,100); 30 | } 31 | 32 | for (int i = 0; i < 10; i++) 33 | { 34 | printf1(TAG_GREEN,"rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead()); 35 | ret = fifo_test_add(data[i]); 36 | printf1(TAG_GREEN,"%d\r\n",i); 37 | if (ret != 0) 38 | { 39 | printf1(TAG_GREEN,"fifo_test_add fail\r\n"); 40 | goto fail; 41 | } 42 | } 43 | 44 | for (int i = 0; i < 10; i++) 45 | { 46 | printf1(TAG_GREEN,"rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead()); 47 | ret = fifo_test_take(verif[i]); 48 | printf1(TAG_GREEN,"%d\r\n",i ); 49 | if (ret != 0) 50 | { 51 | printf1(TAG_GREEN,"fifo_test_take fail\r\n"); 52 | goto fail; 53 | } 54 | 55 | if (memcmp(verif[i], data[i], 100) != 0) 56 | { 57 | printf1(TAG_GREEN,"fifo_test_take result fail\r\n"); 58 | dump_hex1(TAG_GREEN,data[i],100); 59 | dump_hex1(TAG_GREEN,verif[i],100); 60 | goto fail; 61 | } 62 | } 63 | 64 | for (int i = 0; i < 10; i++) 65 | { 66 | printf1(TAG_GREEN,"rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead()); 67 | ret = fifo_test_add(data[i]); 68 | if (ret != 0) 69 | { 70 | printf1(TAG_GREEN,"fifo_test_add 2 fail\r\n"); 71 | goto fail; 72 | } 73 | } 74 | 75 | ret = fifo_test_add(data[0]); 76 | if (ret == 0) 77 | { 78 | printf1(TAG_GREEN,"fifo_test_add should have failed\r\n"); 79 | goto fail; 80 | } 81 | 82 | 83 | 84 | for (int i = 0; i < 10; i++) 85 | { 86 | printf1(TAG_GREEN,"rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead()); 87 | ret = fifo_test_take(verif[i]); 88 | if (ret != 0) 89 | { 90 | printf1(TAG_GREEN,"fifo_test_take fail\r\n"); 91 | goto fail; 92 | } 93 | 94 | if (memcmp(verif[i], data[i], 100) != 0) 95 | { 96 | printf1(TAG_GREEN,"fifo_test_take result fail\r\n"); 97 | goto fail; 98 | } 99 | } 100 | 101 | ret = fifo_test_take(verif[0]); 102 | if (ret == 0) 103 | { 104 | printf1(TAG_GREEN,"fifo_test_take should have failed\r\n"); 105 | goto fail; 106 | } 107 | 108 | printf1(TAG_GREEN,"test pass!\r\n"); 109 | return ; 110 | fail: 111 | while(1) 112 | ; 113 | } 114 | #endif 115 | -------------------------------------------------------------------------------- /targets/stm32l432/src/app.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _APP_H_ 8 | #define _APP_H_ 9 | #include 10 | #include "version.h" 11 | #include "solo.h" 12 | 13 | #define SOLO 14 | 15 | #define DEBUG_UART USART1 16 | 17 | #ifndef DEBUG_LEVEL 18 | // Enable the CDC ACM USB interface & debug logs (DEBUG_LEVEL > 0) 19 | #define DEBUG_LEVEL 0 20 | #endif 21 | 22 | // Enable the CCID USB interface 23 | // #define ENABLE_CCID 24 | 25 | #define NON_BLOCK_PRINTING 0 26 | 27 | 28 | #define BOOT_TO_DFU 0 29 | 30 | //#define USING_DEV_BOARD 31 | 32 | #define ENABLE_U2F_EXTENSIONS 33 | // #define ENABLE_WALLET 34 | 35 | #define ENABLE_U2F 36 | 37 | // #define DISABLE_CTAPHID_PING 38 | // #define DISABLE_CTAPHID_WINK 39 | // #define DISABLE_CTAPHID_CBOR 40 | 41 | // #define ENABLE_SERIAL_PRINTING 42 | 43 | void printing_init(); 44 | void hw_init(int lf); 45 | 46 | // Return 1 if Solo is secure/locked. 47 | int solo_is_locked(); 48 | 49 | //#define TEST 50 | //#define TEST_POWER 51 | 52 | // 0xRRGGBB 53 | #define LED_INIT_VALUE 0xFFFFFF 54 | //#define LED_WINK_VALUE 0xFFFFFF 55 | #define LED_MAX_SCALER 15 56 | #define LED_MIN_SCALER 1 57 | // # of ms between each change in LED 58 | #define HEARTBEAT_PERIOD 150 59 | // Each LED channel will be multiplied by a integer between LED_MAX_SCALER 60 | // and LED_MIN_SCALER to cause the slow pulse. E.g. 61 | 62 | // #define LED_INIT_VALUE 0x301000 63 | // #define LED_MAX_SCALER 30 64 | // #define LED_MIN_SCALER 1 65 | // #define HEARTBEAT_PERIOD 8 66 | // Will pulse from 0x301000 to 0x903000 to 0x301000 ... 67 | // Which will take ~8 * (30)*2 ms 68 | 69 | // Button 70 | #ifndef HWREV 71 | #pragma message "Using default hardware revision - 3" 72 | #define HWREV 3 73 | #endif 74 | 75 | #if HWREV <= 2 76 | #define SOLO_BUTTON_PORT GPIOA 77 | #define SOLO_BUTTON_PIN LL_GPIO_PIN_0 78 | #elif HWREV == 3 79 | #define SOLO_BUTTON_PORT GPIOB 80 | #define SOLO_BUTTON_PIN LL_GPIO_PIN_1 81 | #endif 82 | 83 | #define SOLO_BUTTON_R_PORT GPIOA 84 | #define SOLO_BUTTON_R_PIN LL_GPIO_PIN_15 85 | 86 | #if HWREV == 0 87 | #warning "Skipping button check" 88 | #define SKIP_BUTTON_CHECK_WITH_DELAY 0 89 | #define SKIP_BUTTON_CHECK_FAST 1 90 | #else 91 | #define SKIP_BUTTON_CHECK_WITH_DELAY 0 92 | #define SKIP_BUTTON_CHECK_FAST 0 93 | #endif 94 | 95 | #define SOLO_AMS_CS_PORT GPIOB 96 | #define SOLO_AMS_CS_PIN LL_GPIO_PIN_0 97 | 98 | #define SOLO_AMS_IRQ_PORT GPIOC 99 | #define SOLO_AMS_IRQ_PIN LL_GPIO_PIN_15 100 | 101 | 102 | #if DEBUG_LEVEL > 0 || defined(NK_TEST_MODE) 103 | #define STRINGIFY(a) _STRINGIFY(a) 104 | #define _STRINGIFY(a) #a 105 | #warning "Selected development name" 106 | #define SOLO_PRODUCT_NAME "Nitrokey FIDO2 Development " STRINGIFY(PAGES) " " SOLO_VERSION 107 | #else 108 | #define SOLO_PRODUCT_NAME "Nitrokey FIDO2 " SOLO_VERSION 109 | #undef STRINGIFY 110 | #undef _STRINGIFY 111 | #endif 112 | 113 | #include "app-common.h" 114 | 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /fido2/extensions/solo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 SoloKeys, Inc. 3 | * 4 | * This file is part of Solo. 5 | * 6 | * Solo is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Solo is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Solo. If not, see 18 | * 19 | * This code is available under licenses for commercial use. 20 | * Please contact SoloKeys for more information. 21 | */ 22 | 23 | #include 24 | #include "extensions.h" 25 | #include "u2f.h" 26 | #include "wallet.h" 27 | #include "device.h" 28 | #include "ctap.h" 29 | #include "ctap_errors.h" 30 | 31 | #include "log.h" 32 | #include APP_CONFIG 33 | 34 | 35 | 36 | // output must be at least 71 bytes 37 | int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen) 38 | { 39 | int8_t ret = 0; 40 | 41 | wallet_request * req = (wallet_request *) keyh; 42 | extension_writeback_init(output, 71); 43 | 44 | printf1(TAG_WALLET, "u2f-solo [%d]: ", keylen); dump_hex1(TAG_WALLET, keyh, keylen); 45 | 46 | switch(req->operation) { 47 | case WalletVersion: 48 | output[0] = SOLO_VERSION_MAJ; 49 | output[1] = SOLO_VERSION_MIN; 50 | output[2] = SOLO_VERSION_PATCH; 51 | break; 52 | #ifdef APP_EXECS_BOOTLOADER 53 | case WalletBootloader: { 54 | printf1(TAG_WALLET, "WalletBootloader\n"); 55 | uint8_t feedback = 0; 56 | if (get_request_source() == REQ_SRC_U2F) { 57 | feedback = ctap_user_presence_test_config(CTAP2_UP_CONFIG_DELAY_MS) == 1; 58 | } else if (get_request_source() == REQ_SRC_FIDO2) { 59 | feedback = ctap2_user_presence_test(WalletBootloader) == 0; 60 | } else { //unknown source 61 | feedback = 0; 62 | } 63 | if (feedback) { 64 | printf1(TAG_WALLET, "WalletBootloader confirmed\n"); 65 | boot_solo_bootloader(); 66 | } else { 67 | ret = CTAP2_ERR_OPERATION_DENIED; 68 | } 69 | } 70 | break; 71 | #endif 72 | case WalletRng: 73 | printf1(TAG_WALLET,"SoloRng\n"); 74 | 75 | ret = ctap_generate_rng(output, 71); 76 | if (ret != 1) 77 | { 78 | printf1(TAG_WALLET,"Rng failed\n"); 79 | ret = CTAP2_ERR_PROCESSING; 80 | goto cleanup; 81 | } 82 | ret = 0; 83 | 84 | break; 85 | 86 | #ifdef ENABLE_WALLET 87 | case WalletSign: 88 | case WalletRegister: 89 | case WalletPin: 90 | case WalletReset: 91 | return bridge_to_wallet(keyh, keylen); 92 | #endif 93 | 94 | default: 95 | printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation); 96 | ret = CTAP1_ERR_INVALID_COMMAND; 97 | break; 98 | } 99 | 100 | cleanup: 101 | 102 | return ret; 103 | } 104 | -------------------------------------------------------------------------------- /targets/stm32l432/src/memory_layout.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _MEMORY_LAYOUT_H_ 8 | #define _MEMORY_LAYOUT_H_ 9 | 10 | #define PAGE_SIZE 2048 11 | #ifndef PAGES 12 | #error PAGES value not specified 13 | #define PAGES 128 14 | 15 | #elif PAGES == 128 16 | #warning Setting pages to 128 17 | #elif PAGES == 64 18 | #warning Setting pages to 64 19 | #else 20 | #error Unexpected PAGES value 21 | #endif 22 | 23 | 24 | // Pages 119-127 are data 25 | // Location of counter page and it's backup page 26 | // The flash is wear leveled and counter should be fault tolerant 27 | #define COUNTER2_PAGE (PAGES - 4) 28 | #define COUNTER1_PAGE (PAGES - 3) 29 | 30 | // State of FIDO2 application 31 | #define STATE2_PAGE (PAGES - 2) 32 | #define STATE1_PAGE (PAGES - 1) 33 | 34 | #define STATE1_PAGE_ADDR (0x08000000 + ((STATE1_PAGE)*PAGE_SIZE)) 35 | #define STATE2_PAGE_ADDR (0x08000000 + ((STATE2_PAGE)*PAGE_SIZE)) 36 | 37 | // Storage of FIDO2 resident keys 38 | #define RK_NUM_PAGES 10 39 | #define RK_START_PAGE (PAGES - 14) 40 | #define RK_END_PAGE (PAGES - 14 + RK_NUM_PAGES) // not included 41 | 42 | // Start of application code 43 | #ifndef APPLICATION_START_PAGE 44 | #define APPLICATION_START_PAGE (10) 45 | #endif 46 | #define APPLICATION_START_ADDR (0x08000000 + ((APPLICATION_START_PAGE)*PAGE_SIZE)) 47 | 48 | // where attestation key is located 49 | #define ATTESTATION_PAGE (PAGES - 15) 50 | #define ATTESTATION_PAGE_ADDR (0x08000000 + ATTESTATION_PAGE*PAGE_SIZE) 51 | 52 | // End of application code. Leave some extra room for future data storage. 53 | // NOT included in application 54 | #define APPLICATION_END_PAGE ((PAGES - 20)) 55 | #define APPLICATION_END_ADDR ((0x08000000 + ((APPLICATION_END_PAGE)*PAGE_SIZE))-8) 56 | 57 | // Bootloader state. 58 | #define AUTH_WORD_ADDR (APPLICATION_END_ADDR) 59 | 60 | #define LAST_ADDR (APPLICATION_END_ADDR-2048 + 8) 61 | #define BOOT_VERSION_PAGE (APPLICATION_END_PAGE) 62 | #define BOOT_VERSION_ADDR (0x08000000 + BOOT_VERSION_PAGE*FLASH_PAGE_SIZE + 8) 63 | #define LAST_PAGE (APPLICATION_END_PAGE-1) 64 | 65 | struct flash_memory_st{ 66 | uint8_t bootloader[APPLICATION_START_PAGE*2*1024]; 67 | 68 | uint8_t application[(APPLICATION_END_PAGE-APPLICATION_START_PAGE)*2*1024-8]; 69 | uint8_t auth_word[4]; 70 | uint8_t bootloader_disabled[4]; 71 | 72 | // place for more user data 73 | uint8_t _reserved_application_end_mark[8]; 74 | uint8_t bootloader_data[2*1024-8]; 75 | 76 | uint8_t user_data[38*1024]; 77 | } __attribute__((packed)); 78 | 79 | typedef struct flash_memory_st flash_memory_st; 80 | 81 | #include 82 | static_assert(sizeof(flash_memory_st) == (PAGES)*2*1024, "Data structure doesn't match flash size"); 83 | 84 | #define ATTESTATION_CONFIGURED_TAG 0xaa551e79 85 | 86 | struct flash_attestation_page{ 87 | uint8_t attestation_key[32]; 88 | // DWORD padded. 89 | uint64_t device_settings; 90 | uint64_t attestation_cert_size; 91 | uint8_t attestation_cert[2048 - 32 - 8 - 8]; 92 | } __attribute__((packed)); 93 | 94 | typedef struct flash_attestation_page flash_attestation_page; 95 | 96 | static_assert(sizeof(flash_attestation_page) == 2048, "Data structure doesn't match flash size"); 97 | 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /keys/attestation/dev/device_cert.cdump: -------------------------------------------------------------------------------- 1 | // generated 2 | #include 3 | 4 | code uint8_t __attest[] = 5 | "\x30\x82\x02\x72\x30\x82\x02\x18\xa0\x03\x02\x01\x02\x02\x01\x01\x30\x0a\x06\x08" 6 | "\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x4e\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13" 7 | "\x02\x44\x45\x31\x16\x30\x14\x06\x03\x55\x04\x0a\x0c\x0d\x4e\x69\x74\x72\x6f\x6b" 8 | "\x65\x79\x20\x47\x6d\x62\x48\x31\x10\x30\x0e\x06\x03\x55\x04\x0b\x0c\x07\x52\x6f" 9 | "\x6f\x74\x20\x43\x41\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0c\x0c\x6e\x69\x74\x72" 10 | "\x6f\x6b\x65\x79\x2e\x63\x6f\x6d\x30\x20\x17\x0d\x32\x30\x30\x35\x30\x38\x31\x32" 11 | "\x30\x30\x30\x34\x5a\x18\x0f\x32\x30\x37\x30\x30\x34\x32\x36\x31\x32\x30\x30\x30" 12 | "\x34\x5a\x30\x60\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x16\x30" 13 | "\x14\x06\x03\x55\x04\x0a\x0c\x0d\x4e\x69\x74\x72\x6f\x6b\x65\x79\x20\x47\x6d\x62" 14 | "\x48\x31\x22\x30\x20\x06\x03\x55\x04\x0b\x0c\x19\x41\x75\x74\x68\x65\x6e\x74\x69" 15 | "\x63\x61\x74\x6f\x72\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x31\x15\x30" 16 | "\x13\x06\x03\x55\x04\x03\x0c\x0c\x6e\x69\x74\x72\x6f\x6b\x65\x79\x2e\x63\x6f\x6d" 17 | "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d" 18 | "\x03\x01\x07\x03\x42\x00\x04\x7f\xbd\x8e\x19\x5e\x71\x19\xb8\x01\x3a\x34\xce\x3a" 19 | "\xde\x05\x58\xad\xed\x50\xf1\xd3\xf3\x61\x21\xc0\x26\xa5\xc8\x6b\x1d\x67\x4b\x22" 20 | "\x33\xae\x63\x1c\x93\xaa\x7f\xee\x13\x71\xd1\x53\x86\x59\xd1\xde\x34\xc2\x37\x94" 21 | "\xbe\x14\xb6\x23\xb6\x5c\x86\x05\xc5\x78\x28\xa3\x81\xd2\x30\x81\xcf\x30\x1d\x06" 22 | "\x03\x55\x1d\x0e\x04\x16\x04\x14\x1c\xd8\xff\xeb\x0b\xe1\xfd\x29\xfd\x5f\xb1\xb2" 23 | "\x9c\x3e\xac\xa6\x79\xe6\x72\xf2\x30\x73\x06\x03\x55\x1d\x23\x04\x6c\x30\x6a\xa1" 24 | "\x52\xa4\x50\x30\x4e\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x16" 25 | "\x30\x14\x06\x03\x55\x04\x0a\x0c\x0d\x4e\x69\x74\x72\x6f\x6b\x65\x79\x20\x47\x6d" 26 | "\x62\x48\x31\x10\x30\x0e\x06\x03\x55\x04\x0b\x0c\x07\x52\x6f\x6f\x74\x20\x43\x41" 27 | "\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0c\x0c\x6e\x69\x74\x72\x6f\x6b\x65\x79\x2e" 28 | "\x63\x6f\x6d\x82\x14\x05\x13\xd6\xe6\xaf\x64\xd6\x91\xfc\x55\x67\x46\xd9\x0e\xc7" 29 | "\xeb\x4a\x5e\xf6\xd7\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03" 30 | "\x55\x1d\x0f\x04\x04\x03\x02\x04\xf0\x30\x21\x06\x0b\x2b\x06\x01\x04\x01\x82\xe5" 31 | "\x1c\x01\x01\x04\x04\x12\x04\x10\xc3\x9e\xfb\xa6\xfc\xf4\x4c\x3e\x82\x8b\xfc\x4a" 32 | "\x61\x15\xa0\xff\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00\x30" 33 | "\x45\x02\x21\x00\x9f\x85\x42\x74\xd3\xe1\x23\xbf\x15\xdb\xeb\x41\xb6\xe9\xdd\x43" 34 | "\xa3\x44\x75\xd3\xdd\x26\x9c\xb2\xf6\x09\x00\xec\x75\x87\x28\xbc\x02\x20\x01\xb2" 35 | "\xb1\x64\x12\x05\xff\xf7\x96\xc6\x44\xbb\x26\x14\x64\x05\x5a\x5e\xdd\x34\x02\x34" 36 | "\xc5\x9f\x4e\x32\x36\xaf\xb0\xe4\x6c\x03" 37 | ; 38 | const uint16_t __attest_size = sizeof(__attest)-1; 39 | b64: 40 | b'MIICcjCCAhigAwIBAgIBATAKBggqhkjOPQQDAjBOMQswCQYDVQQGEwJERTEWMBQGA1UECgwNTml0cm9rZXkgR21iSDEQMA4GA1UECwwHUm9vdCBDQTEVMBMGA1UEAwwMbml0cm9rZXkuY29tMCAXDTIwMDUwODEyMDAwNFoYDzIwNzAwNDI2MTIwMDA0WjBgMQswCQYDVQQGEwJERTEWMBQGA1UECgwNTml0cm9rZXkgR21iSDEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEVMBMGA1UEAwwMbml0cm9rZXkuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEf72OGV5xGbgBOjTOOt4FWK3tUPHT82EhwCalyGsdZ0siM65jHJOqf+4TcdFThlnR3jTCN5S+FLYjtlyGBcV4KKOB0jCBzzAdBgNVHQ4EFgQUHNj/6wvh/Sn9X7GynD6spnnmcvIwcwYDVR0jBGwwaqFSpFAwTjELMAkGA1UEBhMCREUxFjAUBgNVBAoMDU5pdHJva2V5IEdtYkgxEDAOBgNVBAsMB1Jvb3QgQ0ExFTATBgNVBAMMDG5pdHJva2V5LmNvbYIUBRPW5q9k1pH8VWdG2Q7H60pe9tcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwIQYLKwYBBAGC5RwBAQQEEgQQw577pvz0TD6Ci/xKYRWg/zAKBggqhkjOPQQDAgNIADBFAiEAn4VCdNPhI78V2+tBtundQ6NEddPdJpyy9gkA7HWHKLwCIAGysWQSBf/3lsZEuyYUZAVaXt00AjTFn04yNq+w5GwD' 41 | -------------------------------------------------------------------------------- /fido2/ctaphid.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _CTAPHID_H_H 8 | #define _CTAPHID_H_H 9 | 10 | #include "device.h" 11 | #include "ctap_errors.h" 12 | 13 | #define TYPE_INIT 0x80 14 | #define TYPE_CONT 0x00 15 | 16 | #define CTAPHID_PING (TYPE_INIT | 0x01) 17 | #define CTAPHID_MSG (TYPE_INIT | 0x03) 18 | #define CTAPHID_LOCK (TYPE_INIT | 0x04) 19 | #define CTAPHID_INIT (TYPE_INIT | 0x06) 20 | #define CTAPHID_WINK (TYPE_INIT | 0x08) 21 | #define CTAPHID_CBOR (TYPE_INIT | 0x10) 22 | #define CTAPHID_CANCEL (TYPE_INIT | 0x11) 23 | #define CTAPHID_ERROR (TYPE_INIT | 0x3f) 24 | #define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3b) 25 | 26 | // Custom commands between 0x40-0x7f 27 | #define CTAPHID_BOOT (TYPE_INIT | 0x50) 28 | #define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51) 29 | #define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52) 30 | #define CTAPHID_REBOOT (TYPE_INIT | 0x53) 31 | #define CTAPHID_GETRNG (TYPE_INIT | 0x60) 32 | #define CTAPHID_GETVERSION (TYPE_INIT | 0x61) 33 | #define CTAPHID_LOADKEY (TYPE_INIT | 0x62) 34 | // reserved for debug, not implemented except for HACKER and DEBUG_LEVEl > 0 35 | #define CTAPHID_PROBE (TYPE_INIT | 0x70) 36 | #define CTAPHID_GETSTATUS (TYPE_INIT | 0x71) 37 | 38 | #define ERR_INVALID_CMD 0x01 39 | #define ERR_INVALID_PAR 0x02 40 | #define ERR_INVALID_SEQ 0x04 41 | #define ERR_MSG_TIMEOUT 0x05 42 | #define ERR_CHANNEL_BUSY 0x06 43 | 44 | #define CTAPHID_PROTOCOL_VERSION 2 45 | 46 | #define CTAPHID_STATUS_IDLE 0 47 | #define CTAPHID_STATUS_PROCESSING 1 48 | #define CTAPHID_STATUS_UPNEEDED 2 49 | 50 | #define CTAPHID_INIT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-7) 51 | #define CTAPHID_CONT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-5) 52 | 53 | #define CTAPHID_BROADCAST_CID 0xffffffff 54 | 55 | #define CTAPHID_BUFFER_SIZE 7609 56 | 57 | #define CAPABILITY_WINK 0x01 58 | #define CAPABILITY_LOCK 0x02 59 | #define CAPABILITY_CBOR 0x04 60 | #define CAPABILITY_NMSG 0x08 61 | 62 | #define CTAP_CAPABILITIES (CAPABILITY_WINK | CAPABILITY_CBOR) 63 | 64 | #define HID_MESSAGE_SIZE 64 65 | 66 | typedef struct 67 | { 68 | uint32_t cid; 69 | union{ 70 | struct{ 71 | uint8_t cmd; 72 | uint8_t bcnth; 73 | uint8_t bcntl; 74 | uint8_t payload[CTAPHID_INIT_PAYLOAD_SIZE]; 75 | } init; 76 | struct{ 77 | uint8_t seq; 78 | uint8_t payload[CTAPHID_CONT_PAYLOAD_SIZE]; 79 | } cont; 80 | } pkt; 81 | } CTAPHID_PACKET; 82 | 83 | 84 | typedef struct 85 | { 86 | uint8_t nonce[8]; 87 | uint32_t cid; 88 | uint8_t protocol_version; 89 | uint8_t version_major; 90 | uint8_t version_minor; 91 | uint8_t build_version; 92 | uint8_t capabilities; 93 | } __attribute__((packed)) CTAPHID_INIT_RESPONSE; 94 | 95 | 96 | 97 | void ctaphid_init(); 98 | 99 | uint8_t ctaphid_handle_packet(uint8_t * pkt_raw); 100 | 101 | void ctaphid_check_timeouts(); 102 | 103 | void ctaphid_update_status(int8_t status); 104 | 105 | 106 | #define ctaphid_packet_len(pkt) ((uint16_t)((pkt)->pkt.init.bcnth << 8) | ((pkt)->pkt.init.bcntl)) 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /targets/stm32l432/build/application.mk: -------------------------------------------------------------------------------- 1 | include build/common.mk 2 | 3 | # ST related 4 | SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c 5 | SRC += src/fifo.c src/attestation.c src/nfc.c src/ams.c src/sense.c 6 | SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c 7 | SRC += $(DRIVER_LIBS) $(USB_LIB) 8 | SRC += src/gpio.c 9 | SRC += src/user_feedback.c 10 | 11 | # FIDO2 lib 12 | SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c 13 | SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c 14 | SRC += ../../fido2/ctap_parse.c ../../fido2/crypto.c 15 | SRC += ../../fido2/version.c 16 | SRC += ../../fido2/data_migration.c 17 | SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c 18 | SRC += ../../fido2/extensions/wallet.c 19 | 20 | # Crypto libs 21 | SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c ../../crypto/tiny-AES-c/aes.c 22 | SRC += ../../crypto/cifra/src/sha512.c ../../crypto/cifra/src/blockwise.c 23 | 24 | OBJ1=$(SRC:.c=.o) 25 | OBJ=$(OBJ1:.s=.o) 26 | 27 | INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ 28 | 29 | INC+= -I../../fido2/ -I../../fido2/extensions 30 | INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc 31 | INC += -I../../crypto/tiny-AES-c 32 | INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext 33 | 34 | SEARCH=-L../../tinycbor/lib 35 | 36 | ifndef LDSCRIPT 37 | LDSCRIPT=linker/stm32l4xx.ld 38 | endif 39 | 40 | CFLAGS= $(INC) 41 | 42 | TARGET=solo 43 | HW=-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb 44 | 45 | # Solo or Nucleo board 46 | CHIP=STM32L432xx 47 | 48 | DEBUG ?= 0 49 | 50 | DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"app.h\" $(EXTRA_DEFINES) 51 | 52 | CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections \ 53 | -fomit-frame-pointer $(HW) $(VERSION_FLAGS) -Os -g3 54 | LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys 55 | LDFLAGS_INFO=-Wl,--print-memory-usage -Wl,--print-gc-sections 56 | LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic -ltinycbor $(LDFLAGS_INFO) 57 | 58 | ECC_CFLAGS = $(CFLAGS) -DuECC_PLATFORM=5 -DuECC_OPTIMIZATION_LEVEL=4 -DuECC_SQUARE_FUNC=1 -DuECC_SUPPORT_COMPRESSED_POINT=0 59 | 60 | 61 | .PRECIOUS: %.o 62 | include build/buildinfo.mk 63 | 64 | all: $(TARGET).elf 65 | $(SZ) $^ 66 | 67 | %.o: %.c $(LDSCRIPT) 68 | @echo "*** $<" 69 | @$(CC) $< $(HW) $(CFLAGS) -o $@ 70 | 71 | ../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c 72 | @echo "*** $<" 73 | @$(CC) $^ $(HW) -O3 $(ECC_CFLAGS) -o $@ 74 | 75 | %.elf: $(OBJ) 76 | @echo $(CC) 'FILES' $(HW) $(LDFLAGS) -o $@ 77 | @$(CC) $^ $(HW) $(LDFLAGS) -o $@ 2>&1 | tee $(TARGET)-linking.buildinfo 78 | @echo "*** Built version: $(VERSION_FLAGS)" 79 | @echo "*** Built flags: $(DEFINES)" 80 | @echo "*** Built CFLAGS: $(CFLAGS)" 81 | 82 | %.hex: %.elf $(TARGET).buildinfo $(TARGET)-sections.buildinfo 83 | $(SZ) $< 84 | $(CP) -O ihex $< $(TARGET).hex 85 | $(CP) -O binary $< $(TARGET).bin 86 | 87 | clean: 88 | @rm -f *.o src/*.o *.elf bootloader/*.o $(OBJ) $(LDSCRIPT) 89 | 90 | 91 | cbor: 92 | cd ../../tinycbor/ && make clean 93 | cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \ 94 | LDFLAGS="$(LDFLAGS_LIB)" \ 95 | CFLAGS="$(CFLAGS) -Os -g3 -DCBOR_PARSER_MAX_RECURSIONS=3" 96 | 97 | 98 | ifndef PAGES 99 | PAGES=64 100 | $(warning PAGES is not defined - setting to new value: "$(PAGES)") 101 | endif 102 | $(LDSCRIPT): $(LDSCRIPT).in 103 | sed 's/__PAGES__/$(PAGES)/g' < $< >$@ 104 | -------------------------------------------------------------------------------- /targets/stm32l432/cubeconfig_stm32l442.ioc: -------------------------------------------------------------------------------- 1 | #MicroXplorer Configuration settings - do not modify 2 | File.Version=6 3 | KeepUserPlacement=false 4 | Mcu.Family=STM32L4 5 | Mcu.IP0=NVIC 6 | Mcu.IP1=RCC 7 | Mcu.IP2=SYS 8 | Mcu.IP3=USART1 9 | Mcu.IPNb=4 10 | Mcu.Name=STM32L442KCUx 11 | Mcu.Package=UFQFPN32 12 | Mcu.Pin0=PA9 13 | Mcu.Pin1=PA10 14 | Mcu.Pin2=VP_SYS_VS_Systick 15 | Mcu.PinsNb=3 16 | Mcu.ThirdPartyNb=0 17 | Mcu.UserConstants= 18 | Mcu.UserName=STM32L442KCUx 19 | MxCube.Version=4.27.0 20 | MxDb.Version=DB.4.0.270 21 | NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false 22 | NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false 23 | NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false 24 | NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false 25 | NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false 26 | NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false 27 | NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 28 | NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false 29 | NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false 30 | NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false 31 | PA10.Mode=Asynchronous 32 | PA10.Signal=USART1_RX 33 | PA9.Mode=Asynchronous 34 | PA9.Signal=USART1_TX 35 | PCC.Checker=true 36 | PCC.Line=STM32L4x2 37 | PCC.MCU=STM32L442KCUx 38 | PCC.PartNumber=STM32L442KCUx 39 | PCC.Seq0=0 40 | PCC.Series=STM32L4 41 | PCC.Temperature=25 42 | PCC.Vdd=null 43 | PinOutPanel.RotationAngle=0 44 | RCC.ADCFreq_Value=192000000 45 | RCC.AHBFreq_Value=48000000 46 | RCC.APB1CLKDivider=RCC_HCLK_DIV16 47 | RCC.APB1Freq_Value=3000000 48 | RCC.APB1TimFreq_Value=6000000 49 | RCC.APB2CLKDivider=RCC_HCLK_DIV16 50 | RCC.APB2Freq_Value=3000000 51 | RCC.APB2TimFreq_Value=6000000 52 | RCC.CortexFreq_Value=48000000 53 | RCC.FCLKCortexFreq_Value=48000000 54 | RCC.FamilyName=M 55 | RCC.HCLKFreq_Value=48000000 56 | RCC.HSE_VALUE=8000000 57 | RCC.HSI48_VALUE=48000000 58 | RCC.HSI_VALUE=16000000 59 | RCC.I2C1Freq_Value=3000000 60 | RCC.I2C3Freq_Value=3000000 61 | RCC.IPParameters=ADCFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C3Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,MSIClockRange,MSI_VALUE,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLSAI1PoutputFreq_Value,PLLSAI1QoutputFreq_Value,PLLSAI1RoutputFreq_Value,PWRFreq_Value,RNGFreq_Value,SAI1Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,USART1Freq_Value,USART2Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAI1OutputFreq_Value 62 | RCC.LPTIM1Freq_Value=3000000 63 | RCC.LPTIM2Freq_Value=3000000 64 | RCC.LPUART1Freq_Value=3000000 65 | RCC.LSCOPinFreq_Value=32000 66 | RCC.LSE_VALUE=32768 67 | RCC.LSI_VALUE=32000 68 | RCC.MCO1PinFreq_Value=48000000 69 | RCC.MSIClockRange=RCC_MSIRANGE_11 70 | RCC.MSI_VALUE=48000000 71 | RCC.PLLPoutputFreq_Value=54857142.85714286 72 | RCC.PLLQoutputFreq_Value=192000000 73 | RCC.PLLRCLKFreq_Value=192000000 74 | RCC.PLLSAI1PoutputFreq_Value=54857142.85714286 75 | RCC.PLLSAI1QoutputFreq_Value=192000000 76 | RCC.PLLSAI1RoutputFreq_Value=192000000 77 | RCC.PWRFreq_Value=48000000 78 | RCC.RNGFreq_Value=192000000 79 | RCC.SAI1Freq_Value=54857142.85714286 80 | RCC.SWPMI1Freq_Value=3000000 81 | RCC.SYSCLKFreq_VALUE=48000000 82 | RCC.USART1Freq_Value=3000000 83 | RCC.USART2Freq_Value=3000000 84 | RCC.USBFreq_Value=192000000 85 | RCC.VCOInputFreq_Value=48000000 86 | RCC.VCOOutputFreq_Value=384000000 87 | RCC.VCOSAI1OutputFreq_Value=384000000 88 | USART1.IPParameters=VirtualMode-Asynchronous 89 | USART1.VirtualMode-Asynchronous=VM_ASYNC 90 | VP_SYS_VS_Systick.Mode=SysTick 91 | VP_SYS_VS_Systick.Signal=SYS_VS_Systick 92 | board=custom 93 | -------------------------------------------------------------------------------- /targets/stm32l432/src/user_feedback.c: -------------------------------------------------------------------------------- 1 | #include "user_feedback.h" 2 | 3 | #include "bsp.h" 4 | #include "gpio.h" 5 | #include "log.h" 6 | 7 | #include "u2f_compat.h" 8 | 9 | static bool first_request_accepted = false; 10 | 11 | /** 12 | * Confirm user presence by getting touch button, or device insertion. 13 | * Returns: '0' - user presence confirmed, '1' otherwise 14 | */ 15 | static int8_t _u2f_get_user_feedback(BUTTON_STATE_T target_button_state, bool blink) 16 | { 17 | uint32_t t; 18 | uint8_t user_presence = 0; 19 | 20 | // Accept first request in the first SELF_ACCEPT_MAX_T_MS after power cycle. 21 | // Solution only for a short touch request, not for configuration changes. 22 | if (!first_request_accepted && (get_ms() < SELF_ACCEPT_MAX_T_MS) 23 | && (target_button_state == BST_PRESSED_REGISTERED) ){ 24 | first_request_accepted = true; 25 | led_rgb(LED_COLOR_TOUCH_CONSUMED); 26 | stop_blinking(); 27 | printf1(TAG_BUTTON, "first_request_accepted\n"); 28 | return 0; 29 | } 30 | 31 | // Auto touch for BST_PRESSED_CONSUMED_ACTIVE state. 32 | // For the short activation period BUTTON_VALID_CONSUMED_T_MS after a touch is consumed, only simple actions 33 | if (button_get_press() && target_button_state == BST_PRESSED_REGISTERED) { 34 | printf1(TAG_BUTTON, "Touch active\n"); 35 | return 0; 36 | } 37 | 38 | // Reject all requests, if device is not ready yet for touch button feedback, 39 | // or if the touch is already consumed 40 | if (button_press_is_consumed() || button_get_press_state() < BST_META_READY_TO_USE) { 41 | printf1(TAG_BUTTON, "Touch consumed or button not ready\n"); 42 | u2f_delay(20); 43 | return 1; 44 | } 45 | 46 | if (blink == true && led_is_blinking() == false){ 47 | led_blink(50, LED_BLINK_PERIOD); 48 | } 49 | else if (blink == false) 50 | stop_blinking(); 51 | 52 | t = get_ms(); 53 | while(button_get_press_state() != target_button_state) // Wait to push button 54 | { 55 | led_blink_manager(); // Run led driver to ensure blinking 56 | button_manager(); // Run button driver 57 | if (get_ms() - t > U2F_MS_USER_INPUT_WAIT // 100ms elapsed without button press 58 | && !button_press_in_progress()) // Button press has not been started 59 | break; // Timeout 60 | u2f_delay(10); 61 | #ifdef FAKE_TOUCH 62 | if (get_ms() - t > 1010) break; //1212 63 | #endif 64 | } 65 | 66 | #ifndef FAKE_TOUCH 67 | if (button_get_press_state() == target_button_state) 68 | #else //FAKE_TOUCH 69 | if (true) 70 | #endif 71 | { 72 | printf1(TAG_BUTTON, "Touch registered\n"); 73 | // Button has been pushed in time 74 | user_presence = 1; 75 | button_press_set_consumed(target_button_state); 76 | stop_blinking(); 77 | #ifdef SHOW_TOUCH_REGISTERED 78 | //show short confirming animation 79 | t = get_ms(); 80 | while(get_ms() - t < 110){ 81 | led_on(); 82 | u2f_delay(12); 83 | led_off(); 84 | u2f_delay(25); 85 | } 86 | stop_blinking(); 87 | #endif 88 | } else { // Button hasnt been pushed within the timeout 89 | user_presence = 0; // Return error code 90 | } 91 | 92 | 93 | return user_presence? 0 : 1; 94 | } 95 | 96 | int8_t u2f_get_user_feedback(){ 97 | return _u2f_get_user_feedback(BST_PRESSED_REGISTERED, true); 98 | } 99 | 100 | int8_t u2f_get_user_feedback_extended_wipe(){ 101 | return _u2f_get_user_feedback(BST_PRESSED_REGISTERED_EXT, true); 102 | } 103 | -------------------------------------------------------------------------------- /targets/stm32l432/src/cmsis/core_cmFunc.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file core_cmFunc.h 3 | * @brief CMSIS Cortex-M Core Function Access Header File 4 | * @version V4.30 5 | * @date 20. October 2015 6 | ******************************************************************************/ 7 | /* Copyright (c) 2009 - 2015 ARM LIMITED 8 | 9 | All rights reserved. 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | - Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | - Neither the name of ARM nor the names of its contributors may be used 18 | to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | * 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | ---------------------------------------------------------------------------*/ 33 | 34 | 35 | #if defined ( __ICCARM__ ) 36 | #pragma system_include /* treat file as system include file for MISRA check */ 37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 38 | #pragma clang system_header /* treat file as system include file */ 39 | #endif 40 | 41 | #ifndef __CORE_CMFUNC_H 42 | #define __CORE_CMFUNC_H 43 | 44 | 45 | /* ########################### Core Function Access ########################### */ 46 | /** \ingroup CMSIS_Core_FunctionInterface 47 | \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions 48 | @{ 49 | */ 50 | 51 | /*------------------ RealView Compiler -----------------*/ 52 | #if defined ( __CC_ARM ) 53 | #include "cmsis_armcc.h" 54 | 55 | /*------------------ ARM Compiler V6 -------------------*/ 56 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 57 | #include "cmsis_armcc_V6.h" 58 | 59 | /*------------------ GNU Compiler ----------------------*/ 60 | #elif defined ( __GNUC__ ) 61 | #include "cmsis_gcc.h" 62 | 63 | /*------------------ ICC Compiler ----------------------*/ 64 | #elif defined ( __ICCARM__ ) 65 | #include 66 | 67 | /*------------------ TI CCS Compiler -------------------*/ 68 | #elif defined ( __TMS470__ ) 69 | #include 70 | 71 | /*------------------ TASKING Compiler ------------------*/ 72 | #elif defined ( __TASKING__ ) 73 | /* 74 | * The CMSIS functions have been implemented as intrinsics in the compiler. 75 | * Please use "carm -?i" to get an up to date list of all intrinsics, 76 | * Including the CMSIS ones. 77 | */ 78 | 79 | /*------------------ COSMIC Compiler -------------------*/ 80 | #elif defined ( __CSMC__ ) 81 | #include 82 | 83 | #endif 84 | 85 | /*@} end of CMSIS_Core_RegAccFunctions */ 86 | 87 | #endif /* __CORE_CMFUNC_H */ 88 | -------------------------------------------------------------------------------- /targets/stm32l432/src/sense.c: -------------------------------------------------------------------------------- 1 | #include "sense.h" 2 | #include "device.h" 3 | #include "log.h" 4 | 5 | #include "stm32l4xx_ll_gpio.h" 6 | #include "stm32l4xx_hal_tsc.h" 7 | 8 | #define ELECTRODE_0 TSC_GROUP2_IO1 9 | #define ELECTRODE_1 TSC_GROUP2_IO2 10 | 11 | void tsc_init(void) 12 | { 13 | LL_GPIO_InitTypeDef GPIO_InitStruct; 14 | // Enable TSC clock 15 | RCC->AHB1ENR |= (1<<16); 16 | 17 | /** TSC GPIO Configuration 18 | PA4 ------> Channel 1 19 | PA5 ------> Channel 2 20 | */ 21 | GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_4; 22 | GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; 23 | GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; 24 | GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; 25 | GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; 26 | GPIO_InitStruct.Alternate = LL_GPIO_AF_9; 27 | LL_GPIO_Init(GPIOB, &GPIO_InitStruct); 28 | 29 | /** TSC GPIO Configuration 30 | PA6 ------> sampling cap 31 | */ 32 | GPIO_InitStruct.Pin = LL_GPIO_PIN_6; 33 | GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; 34 | LL_GPIO_Init(GPIOB, &GPIO_InitStruct); 35 | 36 | // Channel IOs 37 | uint32_t channel_ios = TSC_GROUP2_IO1 | TSC_GROUP2_IO2; 38 | 39 | // enable 40 | TSC->CR = TSC_CR_TSCE; 41 | 42 | TSC->CR |= (TSC_CTPH_8CYCLES | 43 | TSC_CTPL_10CYCLES | 44 | (uint32_t)(1 << TSC_CR_SSD_Pos) | 45 | TSC_SS_PRESC_DIV1 | 46 | TSC_PG_PRESC_DIV16 | 47 | TSC_MCV_16383 | 48 | TSC_SYNC_POLARITY_FALLING | 49 | TSC_ACQ_MODE_NORMAL); 50 | 51 | // Spread spectrum 52 | if (0) 53 | { 54 | TSC->CR |= TSC_CR_SSE; 55 | } 56 | 57 | // Schmitt trigger and hysteresis 58 | TSC->IOHCR = (uint32_t)(~(channel_ios | 0 | TSC_GROUP2_IO3)); 59 | 60 | // Sampling IOs 61 | TSC->IOSCR = TSC_GROUP2_IO3; 62 | 63 | // Groups 64 | uint32_t grps = 0x02; 65 | TSC->IOGCSR = grps; 66 | 67 | TSC->IER &= (uint32_t)(~(TSC_IT_EOA | TSC_IT_MCE)); 68 | TSC->ICR = (TSC_FLAG_EOA | TSC_FLAG_MCE); 69 | 70 | } 71 | 72 | void tsc_set_electrode(uint32_t channel_ids) 73 | { 74 | TSC->IOCCR = (channel_ids); 75 | } 76 | 77 | void tsc_start_acq(void) 78 | { 79 | TSC->CR &= ~(TSC_CR_START); 80 | 81 | TSC->ICR = TSC_FLAG_EOA | TSC_FLAG_MCE; 82 | 83 | // Set IO output to output push-pull low 84 | TSC->CR &= (~TSC_CR_IODEF); 85 | 86 | TSC->CR |= TSC_CR_START; 87 | } 88 | 89 | void tsc_wait_on_acq(void) 90 | { 91 | while ( ! (TSC->ISR & TSC_FLAG_EOA) ) 92 | ; 93 | if ( TSC->ISR & TSC_FLAG_MCE ) 94 | { 95 | printf1(TAG_ERR,"Max count reached\r\n"); 96 | } 97 | } 98 | 99 | uint32_t tsc_read(uint32_t indx) 100 | { 101 | return TSC->IOGXCR[indx]; 102 | } 103 | 104 | uint32_t tsc_read_button(uint32_t index) 105 | { 106 | switch(index) 107 | { 108 | case 0: 109 | tsc_set_electrode(ELECTRODE_0); 110 | break; 111 | case 1: 112 | tsc_set_electrode(ELECTRODE_1); 113 | break; 114 | } 115 | tsc_start_acq(); 116 | tsc_wait_on_acq(); 117 | return tsc_read(1) < 45; 118 | } 119 | 120 | int tsc_sensor_exists(void) 121 | { 122 | static uint8_t does = 0; 123 | if (does) return 1; 124 | 125 | LL_GPIO_SetPinMode(GPIOB, (1 << 1), LL_GPIO_MODE_INPUT); 126 | LL_GPIO_SetPinPull(GPIOB, (1 << 1), LL_GPIO_PULL_UP); 127 | 128 | // Short delay before reading pin 129 | asm("nop"); asm("nop"); asm("nop"); asm("nop"); 130 | 131 | does = (LL_GPIO_ReadInputPort(GPIOB) & (1 << 1)) == 0; 132 | 133 | LL_GPIO_SetPinPull(GPIOB, 1, LL_GPIO_PULL_NO); 134 | 135 | return does; 136 | } 137 | -------------------------------------------------------------------------------- /docs/solo/fido2-impl.md: -------------------------------------------------------------------------------- 1 | This page aims to document the security related aspects of the FIDO2 2 | implementation on Solo. This is to make it easier for public review and 3 | comments. 4 | 5 | # Key generation 6 | 7 | Solo aims to achieve 256 bit (32 byte) security with its FIDO2 implementation, 8 | even in light of physical side channels. 9 | 10 | When Solo is first programmed, it will be "uninitialized," meaning it won't 11 | have any secret material, until the first time it boots, then it will leverage 12 | the TRNG to generate all necessary material. This only happens once. 13 | 14 | A master secret, `M`, is generated at initialization. This is only used for 15 | all key generation and derivation in FIDO2. Solo uses a key wrapping method 16 | for FIDO2 operation. 17 | 18 | ** NOTE: The masked implementation of AES is planned, but not yet implemented. Currently it is normal AES. ** 19 | 20 | ## Key wrapping 21 | 22 | When you register a service with a FIDO2 or U2F authenticator, the 23 | authenticator must generate a new keypair unique to that service. This keypair 24 | could be stored on the authenticator to be used in subsequent authentications, 25 | but a certain amount of memory would need to be allocated for this. On embedded 26 | devices, there isn't much memory to spare and users would frustratingly 27 | hit the limit of this memory. 28 | 29 | The answer to this problem is to do key wrapping. The authenticator just 30 | stores `M` and uses `M` and the TRNG to generate new keys and derive previous 31 | keys on the fly. A random number, `R`, is generated, and is placed in the 32 | FIDO2/U2F `KEYID` parameter. The service stores `KEYID` after registering a 33 | key and will issue it back to the authenticator for subsequent authentications. 34 | 35 | In essence, the following happens at registration. 36 | 37 | 1. Generate `R`, calculate private key, `K`, using `HMAC(M,R)` 38 | 2. Derive public key, `P`, from `K` 39 | 3. Return `P` and `R` to service. (`R` is in `KEYID` parameter) 40 | 4. Service stores `P` and `R`. 41 | 42 | Now on authentication. 43 | 44 | 1. Service issues authentication request with `R` in `KEYID` parameter. 45 | 2. \* Authenticator generates `K` by calculating `HMAC(M,R)`. 46 | 3. Proceed normally as if `K` was loaded from storage memory. 47 | 48 | 49 | 57 | 58 | ## Key derivation 59 | 60 | ** Planned, but not yet implemented. ** 61 | 62 | Master secret `M` consists of 64 bytes, split into equal parts `M1` and `M2`. 63 | In theory, we should only need 32 bytes to achieve 256 security, but we also 64 | plan to have side channel security hence the added bytes. 65 | 66 | Our HMAC currently is a two step process. First, just generate a normal 67 | `SHA256-HMAC`. 68 | 69 | 1. `tmp = SHA256_HMAC(M1, R)` 70 | 71 | We could proceed using `tmp` as our secret key, `K`. But our `SHA256-HMAC` 72 | implementation isn't side channel resistant and we won't bother trying to add 73 | side channel resistance. So we add an additional stage that is side channel 74 | resistant. 75 | 76 | 2. `K = aes256_masked(M2, tmp)` 77 | 78 | We add a masked AES encryption to provide side channel resistance. Masked AES 79 | is well studied and relatively easy to implement. An adversary may be able to 80 | recover `M1` via SCA but not `M2`. 81 | 82 | 83 | 84 | * There are other details I leave out. There's also an authentication tag 85 | in the `KEYID` parameter to ensure this is a key generated by the Solo 86 | key. 87 | -------------------------------------------------------------------------------- /targets/stm32l432/src/cmsis/core_cmInstr.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file core_cmInstr.h 3 | * @brief CMSIS Cortex-M Core Instruction Access Header File 4 | * @version V4.30 5 | * @date 20. October 2015 6 | ******************************************************************************/ 7 | /* Copyright (c) 2009 - 2015 ARM LIMITED 8 | 9 | All rights reserved. 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | - Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | - Neither the name of ARM nor the names of its contributors may be used 18 | to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | * 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | ---------------------------------------------------------------------------*/ 33 | 34 | 35 | #if defined ( __ICCARM__ ) 36 | #pragma system_include /* treat file as system include file for MISRA check */ 37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 38 | #pragma clang system_header /* treat file as system include file */ 39 | #endif 40 | 41 | #ifndef __CORE_CMINSTR_H 42 | #define __CORE_CMINSTR_H 43 | 44 | 45 | /* ########################## Core Instruction Access ######################### */ 46 | /** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface 47 | Access to dedicated instructions 48 | @{ 49 | */ 50 | 51 | /*------------------ RealView Compiler -----------------*/ 52 | #if defined ( __CC_ARM ) 53 | #include "cmsis_armcc.h" 54 | 55 | /*------------------ ARM Compiler V6 -------------------*/ 56 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 57 | #include "cmsis_armcc_V6.h" 58 | 59 | /*------------------ GNU Compiler ----------------------*/ 60 | #elif defined ( __GNUC__ ) 61 | #include "cmsis_gcc.h" 62 | 63 | /*------------------ ICC Compiler ----------------------*/ 64 | #elif defined ( __ICCARM__ ) 65 | #include 66 | 67 | /*------------------ TI CCS Compiler -------------------*/ 68 | #elif defined ( __TMS470__ ) 69 | #include 70 | 71 | /*------------------ TASKING Compiler ------------------*/ 72 | #elif defined ( __TASKING__ ) 73 | /* 74 | * The CMSIS functions have been implemented as intrinsics in the compiler. 75 | * Please use "carm -?i" to get an up to date list of all intrinsics, 76 | * Including the CMSIS ones. 77 | */ 78 | 79 | /*------------------ COSMIC Compiler -------------------*/ 80 | #elif defined ( __CSMC__ ) 81 | #include 82 | 83 | #endif 84 | 85 | /*@}*/ /* end of group CMSIS_Core_InstructionInterface */ 86 | 87 | #endif /* __CORE_CMINSTR_H */ 88 | -------------------------------------------------------------------------------- /targets/stm32l432/src/cmsis/core_cmSimd.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file core_cmSimd.h 3 | * @brief CMSIS Cortex-M SIMD Header File 4 | * @version V4.30 5 | * @date 20. October 2015 6 | ******************************************************************************/ 7 | /* Copyright (c) 2009 - 2015 ARM LIMITED 8 | 9 | All rights reserved. 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | - Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | - Neither the name of ARM nor the names of its contributors may be used 18 | to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | * 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | ---------------------------------------------------------------------------*/ 33 | 34 | 35 | #if defined ( __ICCARM__ ) 36 | #pragma system_include /* treat file as system include file for MISRA check */ 37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 38 | #pragma clang system_header /* treat file as system include file */ 39 | #endif 40 | 41 | #ifndef __CORE_CMSIMD_H 42 | #define __CORE_CMSIMD_H 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | 49 | /* ################### Compiler specific Intrinsics ########################### */ 50 | /** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics 51 | Access to dedicated SIMD instructions 52 | @{ 53 | */ 54 | 55 | /*------------------ RealView Compiler -----------------*/ 56 | #if defined ( __CC_ARM ) 57 | #include "cmsis_armcc.h" 58 | 59 | /*------------------ ARM Compiler V6 -------------------*/ 60 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 61 | #include "cmsis_armcc_V6.h" 62 | 63 | /*------------------ GNU Compiler ----------------------*/ 64 | #elif defined ( __GNUC__ ) 65 | #include "cmsis_gcc.h" 66 | 67 | /*------------------ ICC Compiler ----------------------*/ 68 | #elif defined ( __ICCARM__ ) 69 | #include 70 | 71 | /*------------------ TI CCS Compiler -------------------*/ 72 | #elif defined ( __TMS470__ ) 73 | #include 74 | 75 | /*------------------ TASKING Compiler ------------------*/ 76 | #elif defined ( __TASKING__ ) 77 | /* 78 | * The CMSIS functions have been implemented as intrinsics in the compiler. 79 | * Please use "carm -?i" to get an up to date list of all intrinsics, 80 | * Including the CMSIS ones. 81 | */ 82 | 83 | /*------------------ COSMIC Compiler -------------------*/ 84 | #elif defined ( __CSMC__ ) 85 | #include 86 | 87 | #endif 88 | 89 | /*@} end of group CMSIS_SIMD_intrinsics */ 90 | 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | 96 | #endif /* __CORE_CMSIMD_H */ 97 | -------------------------------------------------------------------------------- /docs/solo/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /fido2/apdu.c: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | // iso7816:2013. 5.3.2 Decoding conventions for command bodies 9 | 10 | #include "apdu.h" 11 | 12 | uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu) 13 | { 14 | EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data; 15 | 16 | apdu->cla = hapdu->cla & 0xef; // mask chaining bit if any 17 | apdu->ins = hapdu->ins; 18 | apdu->p1 = hapdu->p1; 19 | apdu->p2 = hapdu->p2; 20 | 21 | apdu->lc = 0; 22 | apdu->data = NULL; 23 | apdu->le = 0; 24 | apdu->extended_apdu = false; 25 | apdu->case_type = 0x00; 26 | 27 | uint8_t b0 = hapdu->lc[0]; 28 | 29 | // case 1 30 | if (len == 4) 31 | { 32 | apdu->case_type = 0x01; 33 | } 34 | 35 | // case 2S (Le) 36 | if (len == 5) 37 | { 38 | apdu->case_type = 0x02; 39 | apdu->le = b0; 40 | if (!apdu->le) 41 | apdu->le = 0x100; 42 | } 43 | 44 | // case 3S (Lc + data) 45 | if (len == 5U + b0 && b0 != 0) 46 | { 47 | apdu->case_type = 0x03; 48 | apdu->lc = b0; 49 | } 50 | 51 | // case 4S (Lc + data + Le) 52 | if (len == 5U + b0 + 1U && b0 != 0) 53 | { 54 | apdu->case_type = 0x04; 55 | apdu->lc = b0; 56 | apdu->le = data[len - 1]; 57 | if (!apdu->le) 58 | apdu->le = 0x100; 59 | } 60 | 61 | // extended length apdu 62 | if (len >= 7 && b0 == 0) 63 | { 64 | uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; 65 | 66 | if (len - 7 < extlen) 67 | { 68 | return SW_WRONG_LENGTH; 69 | } 70 | 71 | // case 2E (Le) - extended 72 | if (len == 7) 73 | { 74 | apdu->case_type = 0x12; 75 | apdu->extended_apdu = true; 76 | apdu->le = extlen; 77 | if (!apdu->le) 78 | apdu->le = 0x10000; 79 | } 80 | 81 | // case 3E (Lc + data) - extended 82 | if (len == 7U + extlen) 83 | { 84 | apdu->case_type = 0x13; 85 | apdu->extended_apdu = true; 86 | apdu->lc = extlen; 87 | } 88 | 89 | // case 4E (Lc + data + Le) - extended 2-byte Le 90 | if (len == 7U + extlen + 2U) 91 | { 92 | apdu->case_type = 0x14; 93 | apdu->extended_apdu = true; 94 | apdu->lc = extlen; 95 | apdu->le = (data[len - 2] << 8) + data[len - 1]; 96 | if (!apdu->le) 97 | apdu->le = 0x10000; 98 | } 99 | 100 | // case 4E (Lc + data + Le) - extended 3-byte Le 101 | if (len == 7U + extlen + 3U && data[len - 3] == 0) 102 | { 103 | apdu->case_type = 0x24; 104 | apdu->extended_apdu = true; 105 | apdu->lc = extlen; 106 | apdu->le = (data[len - 2] << 8) + data[len - 1]; 107 | if (!apdu->le) 108 | apdu->le = 0x10000; 109 | } 110 | } 111 | else 112 | { 113 | if ((len > 5) && (len - 5 < hapdu->lc[0])) 114 | { 115 | return SW_WRONG_LENGTH; 116 | } 117 | } 118 | 119 | if (!apdu->case_type) 120 | { 121 | return SW_COND_USE_NOT_SATISFIED; 122 | } 123 | 124 | if (apdu->lc) 125 | { 126 | if (apdu->extended_apdu) 127 | { 128 | apdu->data = data + 7; 129 | } else { 130 | apdu->data = data + 5; 131 | } 132 | 133 | } 134 | 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /targets/stm32l432/lib/stm32l4xx_ll_pwr.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32l4xx_ll_pwr.c 4 | * @author MCD Application Team 5 | * @brief PWR LL module driver. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© COPYRIGHT(c) 2017 STMicroelectronics

10 | * 11 | * Redistribution and use in source and binary forms, with or without modification, 12 | * are permitted provided that the following conditions are met: 13 | * 1. Redistributions of source code must retain the above copyright notice, 14 | * this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | ****************************************************************************** 34 | */ 35 | #if defined(USE_FULL_LL_DRIVER) 36 | 37 | /* Includes ------------------------------------------------------------------*/ 38 | #include "stm32l4xx_ll_pwr.h" 39 | #include "stm32l4xx_ll_bus.h" 40 | 41 | /** @addtogroup STM32L4xx_LL_Driver 42 | * @{ 43 | */ 44 | 45 | #if defined(PWR) 46 | 47 | /** @defgroup PWR_LL PWR 48 | * @{ 49 | */ 50 | 51 | /* Private types -------------------------------------------------------------*/ 52 | /* Private variables ---------------------------------------------------------*/ 53 | /* Private constants ---------------------------------------------------------*/ 54 | /* Private macros ------------------------------------------------------------*/ 55 | /* Private function prototypes -----------------------------------------------*/ 56 | 57 | /* Exported functions --------------------------------------------------------*/ 58 | /** @addtogroup PWR_LL_Exported_Functions 59 | * @{ 60 | */ 61 | 62 | /** @addtogroup PWR_LL_EF_Init 63 | * @{ 64 | */ 65 | 66 | /** 67 | * @brief De-initialize the PWR registers to their default reset values. 68 | * @retval An ErrorStatus enumeration value: 69 | * - SUCCESS: PWR registers are de-initialized 70 | * - ERROR: not applicable 71 | */ 72 | ErrorStatus LL_PWR_DeInit(void) 73 | { 74 | /* Force reset of PWR clock */ 75 | LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_PWR); 76 | 77 | /* Release reset of PWR clock */ 78 | LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_PWR); 79 | 80 | return SUCCESS; 81 | } 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /** 92 | * @} 93 | */ 94 | #endif /* defined(PWR) */ 95 | /** 96 | * @} 97 | */ 98 | 99 | #endif /* USE_FULL_LL_DRIVER */ 100 | 101 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 102 | -------------------------------------------------------------------------------- /fido2/u2f.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 SoloKeys Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | #ifndef _U2F_H_ 8 | #define _U2F_H_ 9 | 10 | #include 11 | #include "ctap.h" 12 | 13 | #define U2F_EC_FMT_UNCOMPRESSED 0x04 14 | 15 | #define U2F_EC_POINT_SIZE 32 16 | #define U2F_EC_PUBKEY_SIZE 65 17 | #define U2F_APDU_SIZE 7 18 | #define U2F_CHALLENGE_SIZE 32 19 | #define U2F_APPLICATION_SIZE 32 20 | #define U2F_KEY_HANDLE_TAG_SIZE 16 21 | #define U2F_KEY_HANDLE_KEY_SIZE 32 22 | #define U2F_KEY_HANDLE_SIZE (U2F_KEY_HANDLE_KEY_SIZE+U2F_KEY_HANDLE_TAG_SIZE) 23 | #define U2F_REGISTER_REQUEST_SIZE (U2F_CHALLENGE_SIZE+U2F_APPLICATION_SIZE) 24 | #define U2F_MAX_REQUEST_PAYLOAD (1 + U2F_CHALLENGE_SIZE+U2F_APPLICATION_SIZE + 1 + U2F_KEY_HANDLE_SIZE) 25 | 26 | 27 | // U2F native commands 28 | #define U2F_REGISTER 0x01 29 | #define U2F_AUTHENTICATE 0x02 30 | #define U2F_VERSION 0x03 31 | #define U2F_VENDOR_FIRST 0xc0 32 | #define U2F_VENDOR_LAST 0xff 33 | 34 | // U2F_CMD_REGISTER command defines 35 | #define U2F_REGISTER_ID 0x05 36 | #define U2F_REGISTER_HASH_ID 0x00 37 | 38 | // U2F Authenticate 39 | #define U2F_AUTHENTICATE_CHECK 0x7 40 | #define U2F_AUTHENTICATE_SIGN 0x3 41 | #define U2F_AUTHENTICATE_SIGN_NO_USER 0x8 42 | 43 | 44 | // Command status responses 45 | #define U2F_SW_NO_ERROR 0x9000 46 | #define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 47 | #define U2F_SW_INS_NOT_SUPPORTED 0x6d00 48 | #define U2F_SW_WRONG_LENGTH 0x6700 49 | #define U2F_SW_CLASS_NOT_SUPPORTED 0x6E00 50 | #define U2F_SW_WRONG_DATA 0x6a80 51 | #define U2F_SW_INSUFFICIENT_MEMORY 0x9210 52 | 53 | // Delay in milliseconds to wait for user input 54 | #define U2F_MS_USER_INPUT_WAIT 3000 55 | 56 | struct u2f_request_apdu 57 | { 58 | uint8_t cla; 59 | uint8_t ins; 60 | uint8_t p1; 61 | uint8_t p2; 62 | uint8_t LC1; 63 | uint8_t LC2; 64 | uint8_t LC3; 65 | uint8_t payload[U2F_MAX_REQUEST_PAYLOAD]; 66 | }; 67 | 68 | struct u2f_ec_point 69 | { 70 | uint8_t fmt; 71 | uint8_t x[U2F_EC_POINT_SIZE]; 72 | uint8_t y[U2F_EC_POINT_SIZE]; 73 | }; 74 | 75 | struct u2f_register_request 76 | { 77 | uint8_t chal[U2F_CHALLENGE_SIZE]; 78 | uint8_t app[U2F_APPLICATION_SIZE]; 79 | }; 80 | 81 | 82 | struct u2f_key_handle 83 | { 84 | uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE]; 85 | uint8_t key[U2F_KEY_HANDLE_KEY_SIZE]; 86 | }; 87 | 88 | 89 | struct u2f_authenticate_request 90 | { 91 | uint8_t chal[U2F_CHALLENGE_SIZE]; 92 | uint8_t app[U2F_APPLICATION_SIZE]; 93 | uint8_t khl; 94 | struct u2f_key_handle kh; 95 | }; 96 | 97 | // u2f_request send a U2F message to U2F protocol 98 | // @req U2F message 99 | void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp); 100 | 101 | // u2f_request send a U2F message to NFC protocol 102 | // @req data with iso7816 apdu message 103 | // @len data length 104 | void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp); 105 | 106 | int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t key_handle_len, uint8_t * appid); 107 | 108 | int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len); 109 | void u2f_reset_response(); 110 | void u2f_set_writeback_buffer(CTAP_RESPONSE * resp); 111 | 112 | int16_t u2f_version(); 113 | 114 | 115 | #endif /* U2F_H_ */ 116 | -------------------------------------------------------------------------------- /targets/stm32l432/src/cmsis/arm_const_structs.h: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------- 2 | * Copyright (C) 2010-2014 ARM Limited. All rights reserved. 3 | * 4 | * $Date: 19. March 2015 5 | * $Revision: V.1.4.5 6 | * 7 | * Project: CMSIS DSP Library 8 | * Title: arm_const_structs.h 9 | * 10 | * Description: This file has constant structs that are initialized for 11 | * user convenience. For example, some can be given as 12 | * arguments to the arm_cfft_f32() function. 13 | * 14 | * Target Processor: Cortex-M4/Cortex-M3 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * - Redistributions of source code must retain the above copyright 20 | * notice, this list of conditions and the following disclaimer. 21 | * - Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in 23 | * the documentation and/or other materials provided with the 24 | * distribution. 25 | * - Neither the name of ARM LIMITED nor the names of its contributors 26 | * may be used to endorse or promote products derived from this 27 | * software without specific prior written permission. 28 | * 29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 32 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 33 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 34 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 35 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 36 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 37 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 39 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 | * POSSIBILITY OF SUCH DAMAGE. 41 | * -------------------------------------------------------------------- */ 42 | 43 | #ifndef _ARM_CONST_STRUCTS_H 44 | #define _ARM_CONST_STRUCTS_H 45 | 46 | #include "arm_math.h" 47 | #include "arm_common_tables.h" 48 | 49 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len16; 50 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len32; 51 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len64; 52 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len128; 53 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len256; 54 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len512; 55 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len1024; 56 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len2048; 57 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len4096; 58 | 59 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len16; 60 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len32; 61 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len64; 62 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len128; 63 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len256; 64 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len512; 65 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len1024; 66 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len2048; 67 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len4096; 68 | 69 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len16; 70 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len32; 71 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len64; 72 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len128; 73 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len256; 74 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len512; 75 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len1024; 76 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len2048; 77 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len4096; 78 | 79 | #endif 80 | --------------------------------------------------------------------------------