Skip to content

Commit

Permalink
Merge pull request #111 from LedgerHQ/develop
Browse files Browse the repository at this point in the history
Merge to master
  • Loading branch information
cedelavergne-ledger authored Sep 23, 2024
2 parents 8b59bb8 + 1c74157 commit 859878a
Show file tree
Hide file tree
Showing 154 changed files with 529 additions and 326 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codeql_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
name: Analyse
strategy:
matrix:
sdk: [ "$NANOS_SDK", "$NANOX_SDK", "$NANOSP_SDK", "$STAX_SDK" ]
sdk: [ "$NANOS_SDK", "$NANOX_SDK", "$NANOSP_SDK", "$STAX_SDK", "$FLEX_SDK" ]
#'cpp' covers C and C++
language: [ 'cpp' ]
runs-on: ubuntu-latest
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ APPNAME = OpenPGP

# Application version
APPVERSION_M = 2
APPVERSION_N = 2
APPVERSION_P = 2
APPVERSION_N = 3
APPVERSION_P = 0
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

SPECVERSION:="3.3.1"
Expand All @@ -50,6 +50,7 @@ ICON_NANOS = icons/gpg_16px.gif
ICON_NANOX = icons/gpg_14px.gif
ICON_NANOSP = icons/gpg_14px.gif
ICON_STAX = icons/gpg_32px.gif
ICON_FLEX = icons/gpg_40px.gif

# Application allowed derivation curves.
# Possibles curves are: secp256k1, secp256r1, ed25519 and bls12381g1
Expand Down Expand Up @@ -124,6 +125,8 @@ DEFINES += HAVE_USB_CLASS_CCID
DEFINES += HAVE_RSA
# Watchdog issue causing the device reset with long prime number computation
# DEFINES += WITH_SUPPORT_RSA4096
# Limitation (maybe due to openpgp itself): no support of DEC operation with cv25519
DEFINES += NO_DECRYPT_cv25519

ifeq ($(TARGET_NAME),TARGET_NANOS)
DEFINES += HAVE_UX_LEGACY
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ You can choose which device to compile and load for by setting the `BOLOS_SDK` e
- `BOLOS_SDK=$NANOX_SDK`
- `BOLOS_SDK=$NANOSP_SDK`
- `BOLOS_SDK=$STAX_SDK`
- `BOLOS_SDK=$FLEX_SDK`

### Loading on a physical device

Expand Down
16 changes: 15 additions & 1 deletion doc/developer/quick-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ opensc-pkcs11: opensc-pkcs11.so
user-pin-initialized
protected-authentication-path
token-initialized
```

Check the installation of CCID driver and more particularly its device config:

Expand All @@ -103,11 +104,14 @@ Usage: ./manual.sh <options>

Options:

-c <init|card|encrypt|decryptsign|verify> : Requested command
-c <init|reset|card|encrypt|decrypt|sign|verify|default> : Requested command
-e : Expert mode
-v : Verbose mode
-h : Displays this help
```

> Note: This script allows to automatically use a test gpg directory, like setting `GNUGPGHOME`
The `init` command allows to prepare a local `gnupg` home directory, with the default minimal config file for *scdaemon*.
For further investigations, you can also add in the file `manual-tests/gnupg/scdaemon.conf` the following lines:

Expand All @@ -117,6 +121,16 @@ debug 11
log-file /tmp/scdaemon.log
```

The `reset` command just allows to kill running *scdaemon* or *gpg-agent* processes. Useful to start clean tests.

The `card` command is a shortcut to the `gpg --card-edit` command.

The `default` command, used **after** keys creation, allows to configure the default keys for signature and decryption.
The information is written in the file `manual-tests/gnupg/gpg.conf`.
This step is very useful when playing with backup/restore to ensure the default key will be found.

The other commands are shortcuts allowing basic operations to test the key.

## Step 3: Verify the card status and the pin code

Launch the Application on the device.
Expand Down
3 changes: 3 additions & 0 deletions doc/user/0001-plist.patch
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string>0x2C97</string>
<string>0x2C97</string>
+ <string>0x2C97</string>
+ <string>0x2C97</string>
+ <string>0x2C97</string>
<string>0x17EF</string>
<string>0x17EF</string>
Expand All @@ -19,6 +20,7 @@
+ <string>0x4009</string>
+ <string>0x5009</string>
+ <string>0x6009</string>
+ <string>0x7009</string>
<string>0x6007</string>
<string>0x6055</string>
<string>0x6111</string>
Expand All @@ -28,6 +30,7 @@
<string>Ledger Nano X</string>
+ <string>Ledger Nano S Plus</string>
+ <string>Ledger Stax</string>
+ <string>Ledger Flex</string>
<string>Lenovo Lenovo USB Smartcard Keyboard</string>
<string>Lenovo Lenovo USB Smartcard Keyboard</string>
<string>Lenovo Lenovo Smartcard Wired Keyboard II</string>
Binary file modified doc/user/app-openpgp.pdf
Binary file not shown.
14 changes: 10 additions & 4 deletions doc/user/app-openpgp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ Thus, you must ensure (or add):
- ifdProductID: 0x6009
- ifdFriendlyName: Ledger Stax

- for Flex:

- ifdVendorID: 0x2C97
- ifdProductID: 0x7009
- ifdFriendlyName: Ledger Flex

Notes:

- The 3 entry nodes must be added for each device. It can be easier to add new ones at the end of each list.
Expand Down Expand Up @@ -197,7 +203,7 @@ with:
Select Slot
-------------

For Nanos, this menu is only available on *XL* version. It is available on all other devices.
This menu is not available on Nanos, limited to a single slot. It is available on all other devices.

A Slot is a set of 3 key pairs *Signature, Decryption, Authentication* as defined by gnupg specification.

Expand Down Expand Up @@ -414,7 +420,7 @@ Configuration

In order to use a Ledger device with gpg it is needed to explicitly setup
the reader and the delegated PIN support.
Edit the file ``~/.gnupg/scdaemon.conf`` and add the following lines:
Create or edit the file ``~/.gnupg/scdaemon.conf`` and add the following lines:

| ``reader-port "Ledger Token"``
| ``allow-admin``
Expand Down Expand Up @@ -1137,7 +1143,7 @@ Finally run the following command:

| ``python3 -m gpgcard.gpgcli --pinpad --set-template ed255519:cv25519:ed255519 --set-fingerprints``
| ``'2C688345BDDA0EDFB24DB4FB8451AAF7D43D1095:DF157BD4AC3BD1EE991099C80953D871FC4B9EA4:CEC59AE6A76614BC3C6D37D9C5A8FB078520ABBB'``
| ``--set-serial 'FD6C11BE' --seed-key``
| ``--serial 'FD6C11BE' --seed-key``
Restore lost Keyring
~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -1576,7 +1582,7 @@ To *restore* a backup, simply use the tool like this:

| ``$ ./backup.py --restore --adm-pin 12345678 --user-pin 123456 --seed-key``
| ``Connect to card 'Ledger'...``
| ``Configuration saved in file 'gpg_backup'.``
| ``Configuration restored from file 'gpg_backup'.``
Annexes
=======
Expand Down
Binary file added icons/gpg_40px.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion ledger_app.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[app]
build_directory = "./"
sdk = "C"
devices = ["nanos", "nanox", "nanos+", "stax"]
devices = ["nanos", "nanox", "nanos+", "stax", "flex"]

[tests]
unit_directory = "./unit-tests/"
Expand Down
41 changes: 30 additions & 11 deletions manual-tests/manual.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ help() {
echo
echo "Options:"
echo
echo " -c <init|reset|card|encrypt|decryptsign|verify> : Requested command"
echo " -e : Expert mode mode"
echo " -c <init|reset|card|encrypt|decrypt|sign|verify|default> : Requested command"
echo " -e : Expert mode"
echo " -v : Verbose mode"
echo " -h : Displays this help"
echo
Expand All @@ -42,6 +42,30 @@ reset() {
killall scdaemon gpg-agent 2>/dev/null
}

#===============================================================================
#
# default - Set default key in conf file
#
#===============================================================================
default() {
dir=$(basename "${gnupg_home_dir}")
if [[ ! -d "${dir}" ]]; then
mkdir "${dir}"
chmod 700 "${dir}"
fi

recipient=$(gpg --homedir "${gnupg_home_dir}" --card-status | grep "General key info" | awk '{print $NF}')

if [[ ${recipient} =~ "none" ]]; then
read -r -p "Enter default key name: " recipient
fi

{
echo "default-key ${recipient}"
echo "default-recipient ${recipient}"
} > "${dir}/gpg.conf"
}

#===============================================================================
#
# init - Init the gnupg config, start from an empty keyring
Expand Down Expand Up @@ -93,19 +117,15 @@ card() {
#
#===============================================================================
encrypt() {
local recipient=""
local verbose_mode=""

reset
rm -fr foo*
echo CLEAR > foo.txt

[[ ${VERBOSE} == true ]] && verbose_mode="--verbose"

recipient=$(gpg --homedir "${gnupg_home_dir}" --card-status | grep "General key info" | awk '{print $NF}')

echo "Encrypt with recipient '${recipient}'"

gpg --homedir "${gnupg_home_dir}" ${verbose_mode} --encrypt --recipient "${recipient}" foo.txt
gpg --homedir "${gnupg_home_dir}" ${verbose_mode} --encrypt foo.txt
}

#===============================================================================
Expand All @@ -123,8 +143,7 @@ decrypt() {
gpg --homedir "${gnupg_home_dir}" ${verbose_mode} --decrypt foo.txt.gpg > foo_dec.txt

# Check with original clear file
diff foo.txt foo_dec.txt >/dev/null
if [[ $? -eq 0 ]]; then
if diff foo.txt foo_dec.txt >/dev/null; then
echo "Success !"
else
echo "Decryption error!"
Expand Down Expand Up @@ -180,7 +199,7 @@ while getopts ":c:evh" opt; do

c)
case ${OPTARG} in
init|reset|card|encrypt|decrypt|sign|verify)
init|reset|card|encrypt|decrypt|sign|verify|default)
CMD=${OPTARG}
;;
*)
Expand Down
5 changes: 4 additions & 1 deletion pytools/gpgapp/gpgcard.py
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,7 @@ def asymmetric_key(self, key: str, action: str) -> dict:

op = KEY_OPERATIONS[action]
attributes = None
b_key: int = 0
if key == KeyTypes.KEY_SIG:
attributes = self.data.sig.attribute
b_key = DataObject.DO_SIG_KEY
Expand Down Expand Up @@ -1167,6 +1168,7 @@ def _set_key_date_now(self, key: str) -> None:

dt = datetime.utcnow().replace(microsecond=0)
bdate = int(dt.timestamp()).to_bytes(4, "big")
tag: Optional[DataObject] = None
if key == KeyTypes.KEY_SIG:
self.data.sig.date = dt
tag = DataObject.DO_DATES_WR_SIG
Expand All @@ -1176,7 +1178,8 @@ def _set_key_date_now(self, key: str) -> None:
elif key == KeyTypes.KEY_DEC:
self.data.dec.date = dt
tag = DataObject.DO_DATES_WR_DEC
self._put_data(tag, bdate)
if tag:
self._put_data(tag, bdate)


def _decode_tlv(self, tlv: bytes) -> dict:
Expand Down
12 changes: 12 additions & 0 deletions src/gpg_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ int gpg_apdu_put_data(unsigned int ref) {
cx_err_t error = CX_INTERNAL_ERROR;
unsigned int pkey_size = 0;
unsigned int ksz, curve;
#ifdef NO_DECRYPT_cv25519
bool decKey = false;
#endif

G_gpg_vstate.DO_current = ref;

Expand Down Expand Up @@ -655,6 +658,9 @@ int gpg_apdu_put_data(unsigned int ref) {
case 0xC2:
ptr_l = &G_gpg_vstate.kslot->dec.attributes.length;
ptr_v = G_gpg_vstate.kslot->dec.attributes.value;
#ifdef NO_DECRYPT_cv25519
decKey = true;
#endif
goto WRITE_ATTRIBUTES;
case 0xC3:
ptr_l = &G_gpg_vstate.kslot->aut.attributes.length;
Expand All @@ -679,6 +685,12 @@ int gpg_apdu_put_data(unsigned int ref) {
case KEY_ID_EDDSA:
curve =
gpg_oid2curve(G_gpg_vstate.work.io_buffer + 1, G_gpg_vstate.io_length - 1);
#ifdef NO_DECRYPT_cv25519
if ((decKey) && (curve == CX_CURVE_Curve25519)) {
sw = SW_WRONG_DATA;
break;
}
#endif
if (curve == CX_CURVE_NONE) {
sw = SW_WRONG_DATA;
} else {
Expand Down
4 changes: 0 additions & 4 deletions src/gpg_gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,9 @@ static int gpg_gen_rsa_kyey(gpg_key_t *keygpg, uint8_t *name) {
case 3072 / 8:
pkey_size = sizeof(cx_rsa_3072_private_key_t);
break;
#ifdef WITH_SUPPORT_RSA4096
case 4096 / 8:
pkey_size = sizeof(cx_rsa_4096_private_key_t);
break;
#endif
default:
break;
}
Expand Down Expand Up @@ -195,14 +193,12 @@ static int gpg_read_rsa_kyey(gpg_key_t *keygpg) {
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *) &keygpg->priv_key.rsa3072.n);
break;
#ifdef WITH_SUPPORT_RSA4096
case 4096 / 8:
if (keygpg->priv_key.rsa4096.size == 0) {
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *) &keygpg->priv_key.rsa4096.n);
break;
#endif
default:
return SW_REFERENCED_DATA_NOT_FOUND;
}
Expand Down
2 changes: 1 addition & 1 deletion src/gpg_pin.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ int gpg_apdu_change_ref_data() {
}

/**
* APDU handler to Reste PinCode or Counter
* APDU handler to Reset PinCode or Counter
*
* @return Status Word
*
Expand Down
Loading

0 comments on commit 859878a

Please sign in to comment.