Fix linter output and formatting

pull/94/head
Charles-Edouard de la Vergne 11 months ago
parent 8f03f2378f
commit 91714aac94
No known key found for this signature in database
GPG Key ID: F12296941B7BB9C6

@ -1,119 +1,18 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
BasedOnStyle: Google
IndentWidth: 4
Language: Cpp
ColumnLimit: 100
PointerAlignment: Right
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
#AlignConsecutiveMacros: true
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
#AllowAllArgumentsOnNextLine: false
#AllowAllConstructorInitializersOnNextLine: false
AlignConsecutiveMacros: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
SortIncludes: false
SpaceAfterCStyleCast: true
AllowShortCaseLabelsOnASingleLine: false
AllowAllArgumentsOnNextLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
#AllowShortLambdasOnASingleLine: None
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: BeforeHash
IndentWidth: 2
IndentWrappedFunctionNames: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
RawStringFormats:
- Delimiter: pb
Language: TextProto
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...
---

42
.gitignore vendored

@ -1,10 +1,32 @@
# Glyphs auto-generated
src/glyphs.*
# Build files
dep
obj
release
bin
debug
build
# Compilation files of the application
build/
# Legacy compilation output
bin/
debug/
# Temporary directory with snapshots taken during test runs
tests/snapshots-tmp/
# Unit tests and code coverage
unit-tests/build/
unit-tests/coverage/
unit-tests/coverage.info
# Fuzzing
fuzzing/build/
# Python
*.pyc[cod]
*.egg
__pycache__/
*.egg-info/
.eggs/
.python-version
# Doxygen
doc/html
doc/latex
# Virtual env for sideload (macOS and Windows)
ledger/

@ -1,49 +1,48 @@
## GnuPG application: blue-app-gnupg
# GnuPG application
GnuPG application for Nano S and Nano X
This application implements "The OpenPGP card" specification revision 3.0. This specification is available in *doc* directory and at https://g10code.com/p-card.html .
This application implements "The OpenPGP card" specification revision 3.3.
This specification is available in *doc* directory and at <https://g10code.com/p-card.html>.
The application supports:
- RSA with key up to 4096 bits
- ECDSA with secp256k1
- EDDSA with Ed25519 curve
- ECDH with secp256k1 and curve25519 curves
- RSA with key up to 4096 bits
- ECDSA with secp256k1
- EDDSA with Ed25519 curve
- ECDH with secp256k1 and curve25519 curves
This release has known missing parts (see also Add-on) :
* Ledger Blue support
* Seed mode ON/OFF via apdu
- Ledger Blue support
- Seed mode ON/OFF via apdu
## Installation and Usage
See the full doc at https://github.com/LedgerHQ/blue-app-openpgp-card/blob/master/doc/user/blue-app-openpgp-card.pdf
See the full doc at <https://github.com/LedgerHQ/blue-app-openpgp-card/blob/master/doc/user/blue-app-openpgp-card.pdf>
## Add-on
The GnuPG application implements the following addon:
- serial modification
- on screen reset
- 3 independent key slots
- seeded key generation
Technical specification is available at https://github.com/LedgerHQ/blue-app-openpgp-card/blob/master/doc/developper/gpgcard3.0-addon.rst
- serial modification
- on screen reset
- 3 independent key slots
- seeded key generation
Technical specification is available at <https://github.com/LedgerHQ/blue-app-openpgp-card/blob/master/doc/developer/gpgcard3.0-addon.rst>
### Key slot
"The OpenPGP card" specification specifies:
- 3 asymmetric keys : Signature, Decryption, Authentication
- 1 symmetric key
The blue application allow you to store 3 different key sets, named slot. Each slot contains the above 4 keys.
- 3 asymmetric keys : Signature, Decryption, Authentication
- 1 symmetric key
The application allows you to store 3 different key sets, named slot. Each slot contains the above 4 keys.
You can choose the active slot on the main screen.
When installed the default slot is "1". You can change it in settings.
### seeded key generation
A seeded mode is implemented in order to restore private keys on a new token.
@ -51,9 +50,8 @@ In this mode key material is generated from the global token seeded.
Please consider SEED mode as experimental.
More details to come...
More details to come...
### On screen reset
The application can be reset as if it was fresh installed. In settings, choose reset and confirm.

@ -35,7 +35,7 @@ OpenPGP Application manage four keys for cryptographic operation (PSO) plus two
for secure channel.
The first four keys are defined as follow:
- One asymmetric signature private key (RSA or EC), named 'sig';
- One asymmetric signature private key (RSA or EC), named 'sig'
- One asymmetric decryption private key (RSA or EC), named 'dec'
- One asymmetric authentication private key (RSA or EC), named 'aut'
- One symmetric decryption private key (AES), named 'sym0'
@ -49,7 +49,7 @@ It's never possible to retrieve private key from the card.
This add-on specification propose a solution to derive those keys from the
master seed managed by the Ledger Token.
This allow owner to restore a broken token without the needs to keep track of keys
This allows owner to restore a broken token without the needs to keep track of keys
outside the card.
Moreover this add-on specification propose to manage multiple set of the
@ -69,7 +69,7 @@ This add-on specification propose new type of random generation:
Key Backup
~~~~~~~~~~
A full keybackup mecanism is provided.
A full keybackup mechanism is provided.
GPG-ledger
@ -79,7 +79,7 @@ Definitions
-----------
- The application is named GPG-ledger
- A keys set is named 'keys slot'
- A keys set is named 'keys slot'
How
---
@ -95,7 +95,7 @@ Deterministic key derivation maybe activated in:
This activation remains effective until *set off* is selected or the application
ends.
The key management remains the same if seed mode is on or off, i.e. key are stored in memory key containers. So their is no perfomance inpact when using seeded keys.
The key management remains the same if seed mode is on or off, i.e. key are stored in memory key containers. So there is no performance impact when using seeded keys.
Seeded keys are generated as follow:
@ -133,7 +133,7 @@ Generate RSA key pair as usual.
- n = p*q
- d = inv(e) mod (p-1)(q-1)
*ECC key genration* :
*ECC key generation* :
Generate one seed Sd in step2 with :
- i = 1
@ -188,16 +188,18 @@ For a given length *L* and seed *S*:
Key Backup & Restore
~~~~~~~~~~~~~~~~~~~~
In order to backup/restore private key the commands `put_data` and
`get_data` accept the tag `B6` (signature key), `B8`(encryption key),
`A4` (authentication).
In order to backup/restore private key the commands `put_data` and
`get_data` accept the tags:
- `B6` (signature key)
- `B8`(encryption key)
- `A4` (authentication).
put_data command accept the exact output of get_data. The get_data command
`put_data` command accept the exact output of `get_data`. The `get_data` command
return both the public and private key.
For security and confidentiality private key is returned encryped in AES.
The key used is derived according to previously described AES key derivation
with name 'key '.
For security and confidentiality, private key is returned encrypted in AES.
The key used is derived according to previously described AES key derivation
with name 'key'.
The data payload is formatted as follow:
@ -227,7 +229,7 @@ APDU Modification
Key Slot management
~~~~~~~~~~~~~~~~~~~~
Key slots are managed by data object 01F1 and 01F2 witch are
Key slots are managed by data object *01F1* and *01F2* witch are
manageable by PUT/GET DATA command as for others DO and organized as follow.
On application reset, the *01F2* content is set to *Default Slot* value
@ -255,8 +257,6 @@ Byte 3 is endoced as follow:
| \- | \- | \- | \- | \- | \- | x | \- | selection by screen |
+----+----+----+----+----+----+----+----+-------------------------+
*01F2:*
@ -302,7 +302,7 @@ P2 parameter of GENERATE ASYMMETRIC KEY PAIR is set to (hex value):
Deterministic random number
~~~~~~~~~~~~~~~~~~~~~~~~~~~
P1 parameter of GET CHALLENGE is a bits field encoded as follow:
P1 parameter of GET CHALLENGE is a bit-field encoded as follow:
+----+-----+----+----+----+----+----+----+-------------------------+
| b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | Meaning |
@ -320,7 +320,7 @@ the length of random bytes to generate.
Other minor add-on
------------------
GnuPG use both fingerprints and serial number to identfy key on card.
So, the put data command is able to modify the AID file with '4F' tag.
In that case the data field shall be four bytes length and shall contain
GnuPG use both fingerprints and serial number to identify key on card.
So, the `put_data` command is able to modify the AID file with '4F' tag.
In that case the data field shall be four bytes length and shall contain
the new serial number. '4F' is protected by PW3 (admin) PIN.

@ -1,20 +1,30 @@
Step1: ...
-----
Jump into any temp dir
Jump into any temp dir
Step2: install nanos
-----
-----
Do a fresh install of gpg application 1.1.0 from google app manager
Step3: setup conf
-----
Create a 'manual-test' directory
$ mkdir manual-test
Install needed tools if needed (some are optional)
$ sudo apt install scdaemon opensc-pkcs11 pcscd sssd libpam-sss gnutls-bin opensc pcsc-tools
Check the tools are operational
$ p11-kit list-modules
$ p11tool --list-tokens
$ pkcs15-tool --list-certificates
Check installation of CCID driver and more particularly its device config:
Edit the file /etc/libccid_Info.plist, and check the Ledger devices.
Please take care, the lists are ordered in the same way. Do not insert elements anywhere!
To add a new Ledger device, check file in doc/developer/user/blue-app-openpgp-card.rst
Create a 'manual-test/gnupg'
$ mkdir manual-test/gnupg
$ mkdir -p manual-test/gnupg
Create a 'manual-test/gnupg/scdaemon.conf' file with content:
reader-port "Ledger Token [Nano S] (0001) 01 00"
@ -76,7 +86,7 @@ Launch gpg NanoS application and:
Authentication key: [none]
General key info..: [none]
gpg/card>
gpg/card>
Then on nanos, goto settings->PIN mode, and select 'Host'
Then on nanos, goto settings->PIN mode, and select 'Set as default'
@ -144,8 +154,8 @@ In 'manual-test' directory, ask key generation. Nota that during this phase PIN
GnuPG needs to construct a user ID to identify your key.
Real name: testkey
Email address:
Comment:
Email address:
Comment:
You selected this USER-ID:
"testkey"
@ -180,17 +190,17 @@ encrypt
Force pin to asked
$ killall gpg-agent scdaemon
$ killall gpg-agent scdaemon
decrypt
$ gpg2 --homedir `pwd`/gnupg foo.txt.gpg
$ gpg2 --homedir `pwd`/gnupg foo.txt.gpg
gpg: WARNING: unsafe permissions on homedir '/home/cme/Projects/Git/ledgerblue/blue-app-openpgp-card/manual-test/gnupg'
gpg: encrypted with 2047-bit RSA key, ID 602FE5EB7BFA4B00, created 2017-10-03
"testkey"
File 'foo.txt' exists. Overwrite? (y/N) y
Step7: pin on screen
Step7: pin on screen
------
Restart from Step1, but skip step4

@ -3,7 +3,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -53,9 +53,9 @@ The application supports:
- RSA with key up to 4096 bits
- ECDSA with secp256k1, secp256r1, brainpool 256r1 and brainpool 256t1 curves
- EDDSA with Ed25519 curve
- ECDH with secp256k1, secp256r1, brainpool 256r1, brainpool 256t1 and
- ECDH with secp256k1, secp256r1, brainpool 256r1, brainpool 256t1 and
curve25519 curves
This release has known missing parts (see also [GPGADD]) :
- Ledger Blue support
@ -78,14 +78,14 @@ Use the "Ledger Manager" Chrome App. See https://www.ledgerwallet.com/apps/manag
As the "OpenPGP card" application is not fully compliant with UI and documentation guidelines, the application is in developer section: click on "Show developers items" on the bottom right corner to see it.
- Launch the Ledger Manager. See `Ledger Manager <https://www.ledgerwallet.com/apps/manager>`_
and ` <https://ledger.groovehq.com/knowledge_base/topics/ledger-manager>`_
- Launch the Ledger Manager. See `Ledger Manager <https://www.ledgerwallet.com/apps/manager>`_
and ` <https://ledger.groovehq.com/knowledge_base/topics/ledger-manager>`_
for details about installing and using the manager;
- Connect your Nano S or your Blue, enter your PIN, and stay on the
- Connect your Nano S or your Blue, enter your PIN, and stay on the
dashboard;
- Click on *show developer items* on the bottom right corner;
- Click on the green bottom arrow icon near the Ledger *Open PGP* logo;
- Confirm the installation when required on your device by pressing the
- Confirm the installation when required on your device by pressing the
right button above the check mark;
- Quit the Ledger Manager
@ -118,7 +118,7 @@ If you are using an old version of CCID, you have to have to add the NanoS to /e
- In <key>ifdVendorID</key> add the entry <string>0x2C97</string>
- In <key>ifdProductID</key> add the entry <string>0x0001</string>
- In <key>ifdFriendlyName</key> add the entry <string>Ledger Token</string>
These 3 entries must be added at the end of each list.
For the NanoX :
@ -138,7 +138,7 @@ MAC
- In <key>ifdVendorID</key> add the entry <string>0x2C97</string>
- In <key>ifdProductID</key> add the entry <string>0x0001</string>
- In <key>ifdFriendlyName</key> add the entry <string>Ledger Token</string>
This 3 entries must be added at the end of each list.
3. [Enable SIP](https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html)
@ -191,13 +191,13 @@ The full menu layout is :
| Confirm only #+
| Trust
| Reset
| About
| About
| \ *OpenPGP Card*
| \ *(c) Ledger SAS*
| \ *Spec 3.0*
| \ *App 1.0.1*
| Emphasis entries are not selectable and just provide information.
| Emphasis entries are not selectable and just provide information.
| A "**#**" after the entry label means default value on reset.
| A "**+**" after the entry label means current value.
@ -224,13 +224,13 @@ Select Slot
This menu is only available on ``XL`` version
A Slot is a set of
three key pairs *Signature, Decryption, Authentication* as defined by gnupg
three key pairs *Signature, Decryption, Authentication* as defined by gnupg
specification.
Usually a GPG card application only manages a single set. Ledger version enhances
this and allows you to manage three key sets.
this and allows you to manage three key sets.
The *Select Slot* menu allows you to select the slot you want to play with, and
The *Select Slot* menu allows you to select the slot you want to play with, and
to set the default slot when the application start.
To change the current slot, display the slot you want and select it
@ -245,8 +245,8 @@ Settings
Key Template
~~~~~~~~~~~~
A key template is defined by the OpenGPG card application specification. It
describes the key to be generated with the ``generate`` command in
A key template is defined by the OpenGPG card application specification. It
describes the key to be generated with the ``generate`` command in
``gpg --card-edit``
To set up a new ECC template you have three choices: the ``gpg --edit-card``
@ -303,10 +303,10 @@ To show the current template use the ``gpg --card-status`` command.
**gpg-connect-agent**
This method suppose you have correctly configured your GnuPG tool.
This method suppose you have correctly configured your GnuPG tool.
See the dedicated section for that.
In a terminal launch :
In a terminal launch :
| ``gpg-connect-agent "SCD SETATTR KEY-ATTR --force 1 <tag> <curvename>" /bye``
| ``gpg-connect-agent "SCD SETATTR KEY-ATTR --force 2 18 <curvename>" /bye``
@ -327,7 +327,7 @@ To show the current template use the ``gpg --card-status`` command.
**NanoS menu**
First under *Choose Key* menu, select the one of three keys for which you want to modify
the template. Then under "Choose Type", select the desired key template.
the template. Then under "Choose Type", select the desired key template.
Finally select "Set Template" entry to set it.
To show the current template use the ``gpg --card-status`` command.
@ -349,13 +349,13 @@ When the application starts, the seeded mode is always set to *OFF*
PIN mode
~~~~~~~~
Some operations require the user to enter his PIN code.
Some operations require the user to enter his PIN code.
The default PIN values are:
- user: ``123456``
- admin: ``12345678``
The PIN entry can be done using four methods, named
The PIN entry can be done using four methods, named
"*Host*", "*On Screen*", "*Confirm only*", "*Trust*".
After each mode a *+* or *#* symbol may appear to tell which mode is the current one
@ -363,14 +363,14 @@ and which one is the default when the application starts.
The default mode can be changed by first selecting the desired mode and then
selecting the *Set default" menu. Note that *Trust* can not be set as default mode.
Before you can change the PIN mode, you need to verify the PIN on the client. To do this,
Before you can change the PIN mode, you need to verify the PIN on the client. To do this,
run ``gpg --card-edit``, then ``admin`` and finally ``verify`` on you PC. You will then
be asked to enter the current PIN. After doing so, you can change the PIN mode on your
device.
Note that *On Screen*", "*Confirm only*" and "*Trust*" may not work if the
client application does not support it. In that case the "*Host*" should be
Note that *On Screen*", "*Confirm only*" and "*Trust*" may not work if the
client application does not support it. In that case the "*Host*" should be
automatically used by the client in a transparent way.
**Host**
@ -393,36 +393,36 @@ letter
.. image:: pin_validate.png
:align: middle
If you want to change the previous digit select the **'C'** (Cancel) letter.
.. image:: pin_cancel.png
:align: middle
Finally if you want to abort the PIN entry, select the **'A'** (Abort) letter.
.. image:: pin_abort.png
:align: middle
**Confirm only**
The user is requested, on the NanoS or Blue screen, to confirm
The user is requested, on the NanoS or Blue screen, to confirm
the PIN validation. The PIN value is not required, the user just has
to push the *REJECT* or *OK* button on the device.
to push the *REJECT* or *OK* button on the device.
This is the default mode after application installation.
This is the default mode after application installation.
.. image:: pin_confirm.png
:align: middle
**Trust**
Act as if the PIN is always validated. This is a dangerous mode which should only be
used in a highly secure environment.
used in a highly secure environment.
UIF mode
~~~~~~~~
@ -438,9 +438,9 @@ When activated, a '+' symbol appears after the operation name.
Reset
~~~~~
Selecting the menu will erase all OpenPGP Card Application data and will
Selecting the menu will erase all OpenPGP Card Application data and will
reset the application in its '*just installed*' state.
Nano S OpenPGP Card application usage
@ -460,8 +460,8 @@ keyring before starting, except if your are sure about what you do.
Configuration
~~~~~~~~~~~~~
In order to use a Ledger device with gpg it is needed to explicitly setup
the reader and the delegated PIN support.
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:
| ``reader-port "Ledger Token [Nano S] (0001) 01 00"``
@ -519,7 +519,7 @@ installation it should look like this:
| ``Authentication key: [none]``
| ``General key info..: [none]``
You can set the user information with the ``gpg --card-edit`` command and
You can set the user information with the ``gpg --card-edit`` command and
``name``, ``url``, ``login``, ``lang``, ``sex`` subcommands. For example if you
want to set up your name:
@ -558,9 +558,9 @@ want to set up your name:
Notes:
* Modifying the user information will prompt you to enter ``User PIN``.
* Setting user information is not required for using gpg client.
* Setting user information is not required for using gpg client.
Generate new key pair
@ -570,7 +570,7 @@ For generating a new key pair follow those steps:
- Select the desired NanoS OpenPGP Card application slot
- Setup the desired key template for this slot
- Generate the new key set
- Generate the new key set
**Step 1**
@ -586,23 +586,23 @@ Starting from main menu:
**Step 2**
The default template for each three keys (*signature*, *decryption*,
The default template for each three keys (*signature*, *decryption*,
*authentication*) is ``RSA 2048``. If you want another kind of key
you have to set the template before generating keys.
!WARNING!: changing the current template of a key automatically erases
!WARNING!: changing the current template of a key automatically erases
the associated key.
Starting from main menu:
- Select *Settings* menu
- Select *Key template* menu
- Select *Key template* menu
- Select *Choose Key...* menu (a)
- Scroll and select which key you want to set the new template for
- Select *Choose type...* menu
- Scroll and select among the supported key types and sizes
- Select *Set template*
- Repeat this process from (a) if you want to modify another key
- Repeat this process from (a) if you want to modify another key
template
- Select *Back* to return to main menu.
@ -610,7 +610,7 @@ Starting from main menu:
**Step 3**
Once the template has been set, it's possible to generate new key pairs
with ``gpg``.
with ``gpg``.
!WARNING!: gpg will generate the three key pairs and
will overwrite any key already present in the selected slot.
@ -650,18 +650,18 @@ the three key templates are ``NIST P256``.
**Request new key generation without backup**
| ``gpg/card>`` *generate*
| ``Make off-card backup of encryption key? (Y/n)`` **n**
| ``Make off-card backup of encryption key? (Y/n)`` **n**
**Unlock user level ``81``**
| ``Please unlock the card``
| ``Please unlock the card``
| ````
| ``Number: 2C97 AFB1142B``
| ``Holder: Cedric Mesnil``
| ````
| ``Use the reader's pinpad for input.``
| `` OK``
| ``Press any key to continue. ``
| ``Press any key to continue. ``
**Set key validity**
@ -676,12 +676,12 @@ the three key templates are ``NIST P256``.
| ``Is this correct? (y/N)``*y*
**Set user ID**
| ``GnuPG needs to construct a user ID to identify your key.``
| ````
| ``Real name: Cedric Mesnil``
| ``Email address: cedric@ledger.fr``
| ``Comment: ``
| ``Comment: ``
| ``You selected this USER-ID:``
| `` "Cedric Mesnil <cedric@ledger.fr>"``
| ````
@ -692,7 +692,7 @@ the three key templates are ``NIST P256``.
**Unlock admin level ``83``**
| ``Please enter the Admin PIN ``
| ``Please enter the Admin PIN ``
| ````
| ``Number: 2C97 AFB1142B``
| ``Holder: Cedric Mesnil``
@ -748,9 +748,9 @@ the three key templates are ``NIST P256``.
| ``General key info..: pub nistp256/F8A4A3533CBFCAA5 2017-08-22 cedric mesnilCedric Mesnil <cedric@ledger>``
| ``sec> nistp256/F8A4A3533CBFCAA5 created: 2017-08-22 expires: never ``
| `` card-no: 2C97 AFB1142B``
| ``ssb> nistp256/2345A677CE9D8223 created: 2017-08-22 expires: never ``
| ``ssb> nistp256/2345A677CE9D8223 created: 2017-08-22 expires: never ``
| `` card-no: 2C97 AFB1142B``
| ``ssb> nistp256/E13728E913B877E1 created: 2017-08-22 expires: never ``
| ``ssb> nistp256/E13728E913B877E1 created: 2017-08-22 expires: never ``
| `` card-no: 2C97 AFB1142B``
**Say goodbye
@ -789,7 +789,7 @@ The key to transfer here is a RSA 4096 bits key:
In case of transfer it is not necessary to previously set the template.
It will be automatically changed.
When generating a new key, the three keys (*signature*, *decryption*,
When generating a new key, the three keys (*signature*, *decryption*,
*authentication*)) are automatically generated.
When transferring existing ones, it is possible to choose which one will be
moved.
@ -804,7 +804,7 @@ moved.
| ``Secret key is available.``
| ````
| ``sec rsa4096/9B93CB47F954FB53``
| `` created: 2017-04-26 expires: never usage: SC ``
| `` created: 2017-04-26 expires: never usage: SC ``
| `` trust: ultimate validity: ultimate``
| ``ssb rsa4096/49EE12B0F5CBDF26``
| `` created: 2017-04-26 expires: never usage: E ``
@ -821,7 +821,7 @@ moved.
| `` created: 2017-04-26 expires: never usage: E ``
| ``[ultimate] (1). RSA 4096``
**Move**
**Move**
| ``gpg> `` **keytocard**
| ``Please select where to store the key:``
@ -890,8 +890,8 @@ Decrypting and Signing
Decrypting and Signing will act exactly the same way as if keys were not on
the card. The only difference is ``gpg`` will request the PIN code instead
of the passphrase.
the card. The only difference is ``gpg`` will request the PIN code instead
of the passphrase.
SSH
@ -902,7 +902,7 @@ Overview
~~~~~~~~
In order to use gpg for SSH authentication, an "authentication" is needed.
There are two solutions for that, either generate one on the device
There are two solutions for that, either generate one on the device
or add an authentication sub-key to your existing master gpg key.
Once done, it is necessary to configure ssh to point to the right key and
@ -914,7 +914,7 @@ Generate new key on device
The important thing to keep in mind here is there is no way to tell gpg to
only generate the authentication key. So generating this key will also
generate the two other under a new identity and will erase existing keys
generate the two other under a new identity and will erase existing keys
on the current slot on the device.
Nevertheless, if you want to use a different identity for ssh login, you can use
@ -1021,7 +1021,7 @@ Add sub-key
| ``generator a better chance to gain enough entropy.``
| ``sec rsa2048/831415DA94A9A15C``
| `` created: 2017-08-25 expires: never usage: SC ``
| `` created: 2017-08-25 expires: never usage: SC ``
| `` trust: ultimate validity: ultimate``
| ``ssb rsa2048/8E95F2999EEC38C4``
| `` created: 2017-08-25 expires: never usage: E ``
@ -1053,7 +1053,7 @@ Add sub-key
| ``ssb rsa2048/8E95F2999EEC38C4``
| `` created: 2017-08-25 expires: never usage: E ``
| ``ssb* rsa2048/C20B90E12F68F035``
| `` created: 2017-08-28 expires: never usage: A ``
| `` created: 2017-08-28 expires: never usage: A ``
| ``[ultimate] (1). cedric``
@ -1074,7 +1074,7 @@ to your .gpg-agent.conf:
``enable-ssh-support``
Starting with gpg2 it necessary to add some configuration options to make the *pinentry*
Starting with gpg2 it necessary to add some configuration options to make the *pinentry*
work properly. Add the following line to ~/.bashrc file:
| ``export SSH_AUTH_SOCK=`gpgconf --list-dirs agent-ssh-socket` ``
@ -1093,7 +1093,7 @@ And add the following line to your ~/.gnupg/gpg.conf:
``pinentry-mode loopback``
Then export your authentication public key. First execute the
Then export your authentication public key. First execute the
``gpg -k --with-subkey-fingerprint --with-keygrip cedric`` command.
@ -1113,7 +1113,7 @@ to .gnupg/sshcontrol file:
| ``$ echo 6D60CB58D9D66EE09804E7FE460E865A91F5E41A > .gnupg/sshcontrol``
Export your authentication key, identifier by its fingerprint, in a SSH compliant format.
Export your authentication key, identifier by its fingerprint, in a SSH compliant format.
| ``$ gpg --export-ssh-key 2D0E4FFFAA448AA2770C7F02C20B90E12F68F035``
| ``ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCIARKh0IZTHld+I6oA8nwrgnCUQE8f``
@ -1122,8 +1122,8 @@ Export your authentication key, identifier by its fingerprint, in a SSH complian
| ``3uEBsaY5PR1Tuko/GwywLyZu0SwfEobl/RPjL7P8rUSc7DTHpQMw8fjJFb4BNvIHAlaVC``
| ``5FwZwkuogygaJdN/44MayHFmOZmzx9CAgYgLpTzen35+CcyhlqCqi+HjNlnHL2DDWd4iR``
| ``d3Y6pY8LjS3xQkECc3Bhedptp17D+H9AVJt openpgp:0x2F68F035``
Finally copy the above export (``ssh-rsa AAAAB...Jt openpgp:0x2F68F035``) into the
Finally copy the above export (``ssh-rsa AAAAB...Jt openpgp:0x2F68F035``) into the
~/.ssh/authorized_keys file on your remote server.
@ -1143,11 +1143,11 @@ Backup and Restore
Introduction
~~~~~~~~~~~~
"The OpenPGP card" specification does not provide any mechanism for backuping you key.
"The OpenPGP card" specification does not provide any mechanism for backuping you key.
Thus if you generate your keys on device and loose it, you definitively loose you private key.
In order to avoid such extreme panic situation, a backup/restore mechanism is provided.
At any time you can backup a snapshot of your device data, including your private keys.
At any time you can backup a snapshot of your device data, including your private keys.
All public data are retrieve in clear form. The private key are stored
encrypted with a key derived from your seed, i.e. from your 24 BIP words.
@ -1161,13 +1161,13 @@ The backup/restore tool is located in ``pytools`` directory:
| ``optional arguments:``
| `` -h, --help show this help message and exit``
| `` --adm-pin PIN Administrative PIN, if pinpad not used``
| `` --backup Perfom a full backup except the key``
| `` --backup-keys Perfom keys encrypted backup``
| `` --backup Perform a full backup except the key``
| `` --backup-keys Perform keys encrypted backup``
| `` --file FILE basckup/restore file``
| `` --pinpad PIN validation will be deledated to pinpad``
| `` --reader READER PCSC reader``
| `` --reset Reset the application. All data are erased``
| `` --restore Perfom a full restore except the key``
| `` --restore Perform a full restore except the key``
| `` --set-serial SERIAL set the four serial bytes``
| `` --set-fp SIG:DEC:AUT sig:dec:aut fingerprints, 20 bytes each in hexa``
| `` --seed-key Regenerate all keys, based on seed mode``
@ -1175,20 +1175,20 @@ The backup/restore tool is located in ``pytools`` directory:
| `` --user-pin PIN User PIN, if pinpad not used``
First you must either provide your pin codes or use the pinpad (onscreen pin). This is
First you must either provide your pin codes or use the pinpad (onscreen pin). This is
done by giving either ``--adm-pin`` AND ``--user-pin`` or ``--pinpad``. Note that
using ``--xx-pin`` may compromise your pin codes.
Then you must precise if you want a backup or a restore with ``--backup`` or ``--restore``
By default backup is performed without saving keys, assuming you use the seed mode.
If you also want to backup keys you have to pass the ``--backup-keys`` option.
If you also want to backup keys you have to pass the ``--backup-keys`` option.
In a general manner it is better to also save your keys with ``--backup-keys`` option.
Note that backup and restore works on current slot, so you have to perform a backup per slot
even if some data are shared. You can precise the slot/backup to restore with ``--slot``
If you encounter an error when performing the backup/restore, reload your scdaemon with
If you encounter an error when performing the backup/restore, reload your scdaemon with
``gpgconf --reload scdaemon``
@ -1198,7 +1198,7 @@ Backup and Restore example
First you must have the path of the `ledger-app-openpgp-card/pytools` in your PYTHONPATH.
full backup command:
| ``python3 -m gpgcard.gpgcli --backup --pinpad --backup-keys --file my_bck_file_name.pickle``
backup command without private keys:
@ -1207,20 +1207,20 @@ backup command without private keys:
full restore command:
| ``python3 -m gpgcard.gpgcli --restore --pinpad --file my_bck_file_name.pickle``
full restore command with seed key generation:
| ``python3 -m gpgcard.gpgcli --restore --pinpad --seed-key --file my_bck_file_name.pickle``
Restore without backup
~~~~~~~~~~~~~~~~~~~~~~
If you have seeded key but do not have done a backup and still have your keyring, there is a
solution to restore at least the key and their related information: serial and fingerprints.
If you have seeded key but do not have done a backup and still have your keyring, there is a
solution to restore at least the key and their related information: serial and fingerprints.
All other information such as name, url, ... shall be set manually with ``gpg --card-edit``.
@ -1251,7 +1251,7 @@ Run the command ``gpg --edit-key John``, replace John by your own key id.
|
| ``gpg> ``
|
The ``usage`` field tells you each key purpose: ``SC`` or ``S`` for signature, ``A`` for authentication, ``E`` for encryption.
@ -1261,7 +1261,7 @@ You should have three or less keys with the same serial. These are the keys we w
For each key you also have the key template (rsa2048, rsa3072, rsa4096, ed2559, cv25519) followed by the
short fingerprint, e.g. ``ed25519/8451AAF7D43D1095``
Note the serial and the three key template names: ``FD6C11BE`` , ``ed25519:cv25519:ed25519``.
Note the serial and the three key template names: ``FD6C11BE`` , ``ed25519:cv25519:ed25519``.
Take care of the order: ``SC:E:A``.
Now type the ``quit`` command.
@ -1281,8 +1281,8 @@ To get the full fingerprint of each key, run (yes twice ``--fingerprint``):
| ``sub cv25519 2018-10-10 [E]``
| `` DF15 7BD4 AC3B D1EE 9910 99C8 0953 D871 FC4B 9EA4``
Assemble the three full fingerprint, corresponding to the one identified previously,
in the the following order ``SC:E:A`` :
Assemble the three full fingerprint, corresponding to the one identified previously,
in the the following order ``SC:E:A`` :
``2C688345BDDA0EDFB24DB4FB8451AAF7D43D1095:DF157BD4AC3BD1EE991099C80953D871FC4B9EA4:
CEC59AE6A76614BC3C6D37D9C5A8FB078520ABBB``.
@ -1294,7 +1294,7 @@ If you only have one key to restore you can omit the others, for example to only
**Step 1: restore**
Plug you Nano S and run the OpenPGP application.
Plug you Nano S and run the OpenPGP application.
Finally run the following command :
@ -1323,19 +1323,19 @@ logout/login
**Q:** It does not work at all, HELP ME!!!
**R** Please keep calm and do not cry.
**R** Please keep calm and do not cry.
Add the following option to ~/.gnupg/gpg-agent.conf
| ``debug-level guru``
| ``log-file /tmp/gpgagent.log``
Add the following option to ~/.gnupg/scdaemon.conf
| ``log-file /tmp/scd.log``
| ``debug-level guru``
| ``debug-all``
Make a nice issue report under github providing log and and command line you run.
Make a nice issue report under github providing log and and command line you run.
**!*WARNING*!** : this may reveal confidential information such as key values. Do your log with a test key.

@ -208,7 +208,7 @@ $endfor$
{\scshape\LARGE OpenPGP Card Application \par}
{\scshape \LARGE User Guide \par}
\vspace{1cm}
% {\scshape\Large Ledger SAS \par}
\vspace{1cm}
\begin{figure}[h]

@ -8,4 +8,3 @@ Thanks to gnupg.org for the original images.
Others under this directory are covered by Apache License Version 2.0,

@ -1,15 +1,14 @@
# Copyright 2017 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -1,11 +1,11 @@
# Copyright 2017 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

@ -847,4 +847,3 @@ class GPGCard() :
'e': tags[0x82],
'd': tags[0x98],
}

@ -80,7 +80,7 @@ try:
gpgcard.connect(args.reader)
print("OK")
print("Verfify PINs...", end='', flush=True)
print("Verify PINs...", end='', flush=True)
if args.pinpad:
if not gpgcard.verify_pin(0x82, "", True) or not gpgcard.verify_pin(0x83, "", True):
error("PIN not verified")
@ -122,7 +122,7 @@ try:
'rsa3072' : "010C00002001",
'rsa4096' : "011000002001",
'nistp256' : "132A8648CE3D030107",
'ed255519' : "162B06010401DA470F01",
'ed25519' : "162B06010401DA470F01",
'cv25519' : "122B060104019755010501"
}
sig,dec,aut = args.set_templates.split(":")

@ -1,11 +1,11 @@
# Copyright 2017 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

@ -18,17 +18,17 @@
void USBD_CCID_activate_pinpad(int enabled);
unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len);
unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len);
unsigned char *gpg_curve2oid(unsigned int cv, unsigned int *len);
unsigned int gpg_curve2domainlen(unsigned int cv);
unsigned int gpg_curve2domainlen(unsigned int cv);
void gpg_init(void);
void gpg_init_ux(void);
void gpg_install(unsigned char app_state);
void gpg_install_slot(gpg_key_slot_t *slot);
int gpg_dispatch(void);
int gpg_dispatch(void);
int gpg_apdu_select_data(unsigned int ref, int reccord);
int gpg_apdu_select_data(unsigned int ref, int record);
int gpg_apdu_get_data(unsigned int ref);
int gpg_apdu_get_next_data(unsigned int ref);
int gpg_apdu_put_data(unsigned int ref);
@ -38,13 +38,13 @@ int gpg_apdu_put_key_data(unsigned int ref);
void gpg_pso_derive_slot_seed(int slot, unsigned char *seed);
void gpg_pso_derive_key_seed(unsigned char *Sn,
unsigned char *key_name,
unsigned int idx,
unsigned int idx,
unsigned char *Ski,
unsigned int Ski_len);
int gpg_apdu_pso(void);
int gpg_apdu_internal_authenticate(void);
int gpg_apdu_gen(void);
int gpg_apdu_get_challenge(void);
unsigned int Ski_len);
int gpg_apdu_pso(void);
int gpg_apdu_internal_authenticate(void);
int gpg_apdu_gen(void);
int gpg_apdu_get_challenge(void);
int gpg_apdu_select(void);
@ -53,11 +53,11 @@ int gpg_apdu_change_ref_data(void);
int gpg_apdu_reset_retry_counter(void);
gpg_pin_t *gpg_pin_get_pin(int id);
int gpg_pin_is_blocked(gpg_pin_t *pin);
int gpg_pin_is_verified(int pinID);
int gpg_pin_set_verified(int pinID, int verified);
int gpg_pin_check(gpg_pin_t *pin, int pinID, unsigned char *pin_val, unsigned int pin_len);
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
int gpg_pin_is_blocked(gpg_pin_t *pin);
int gpg_pin_is_verified(int pinID);
int gpg_pin_set_verified(int pinID, int verified);
int gpg_pin_check(gpg_pin_t *pin, int pinID, unsigned char *pin_val, unsigned int pin_len);
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len);
int gpg_mse_reset();
int gpg_apdu_mse();
@ -81,16 +81,16 @@ void gpg_io_insert_t(unsigned int T);
void gpg_io_insert_tl(unsigned int T, unsigned int L);
void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V);
void gpg_io_fetch_buffer(unsigned char *buffer, unsigned int len);
void gpg_io_fetch_buffer(unsigned char *buffer, unsigned int len);
unsigned int gpg_io_fetch_u32(void);
unsigned int gpg_io_fetch_u24(void);
unsigned int gpg_io_fetch_u16(void);
unsigned int gpg_io_fetch_u8(void);
int gpg_io_fetch_t(unsigned int *T);
int gpg_io_fetch_l(unsigned int *L);
int gpg_io_fetch_tl(unsigned int *T, unsigned int *L);
int gpg_io_fetch_nv(unsigned char *buffer, int len);
int gpg_io_fetch(unsigned char *buffer, int len);
int gpg_io_fetch_t(unsigned int *T);
int gpg_io_fetch_l(unsigned int *L);
int gpg_io_fetch_tl(unsigned int *T, unsigned int *L);
int gpg_io_fetch_nv(unsigned char *buffer, int len);
int gpg_io_fetch(unsigned char *buffer, int len);
int gpg_io_do(unsigned int io_flags);
@ -108,7 +108,7 @@ void io_usb_ccid_set_card_inserted(unsigned int inserted);
#else
#define gpg_nvm_write nvm_write
#define gpg_nvm_write nvm_write
#define gpg_io_exchange io_exchange
#endif

@ -20,48 +20,56 @@
#include "gpg_vars.h"
int gpg_apdu_get_challenge() {
unsigned int olen, hlen;
unsigned int olen, hlen;
if ((G_gpg_vstate.io_p1 & 0x80) == 0x80) {
olen = G_gpg_vstate.io_p2;
} else {
olen = G_gpg_vstate.io_le;
}
if (olen == 0 || olen > GPG_EXT_CHALLENGE_LENTH) {
THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH;
}
if ((G_gpg_vstate.io_p1 & 0x80) == 0x80) {
olen = G_gpg_vstate.io_p2;
} else {
olen = G_gpg_vstate.io_le;
}
if (olen == 0 || olen > GPG_EXT_CHALLENGE_LENTH) {
THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH;
}
if ((G_gpg_vstate.io_p1 & 0x82) == 0x82) {
unsigned int path[2];
unsigned char chain[32];
unsigned char Sr[32];
if ((G_gpg_vstate.io_p1 & 0x82) == 0x82) {
unsigned int path[2];
unsigned char chain[32];
unsigned char Sr[32];
memset(chain, 0, 32);
path[0] = 0x80475047;
path[1] = 0x0F0F0F0F;
os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2, Sr, chain);
chain[0] = 'r';
chain[1] = 'n';
chain[2] = 'd';
memset(chain, 0, 32);
path[0] = 0x80475047;
path[1] = 0x0F0F0F0F;
os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2, Sr, chain);
chain[0] = 'r';
chain[1] = 'n';
chain[2] = 'd';
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, Sr, 32, NULL, 0);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, chain, 3, NULL, 0);
hlen = cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, CX_LAST, G_gpg_vstate.work.io_buffer,
G_gpg_vstate.io_length, G_gpg_vstate.work.io_buffer, 32);
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha256, 0, Sr, 32, NULL, 0);
cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha256, 0, chain, 3, NULL, 0);
hlen = cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha256,
CX_LAST,
G_gpg_vstate.work.io_buffer,
G_gpg_vstate.io_length,
G_gpg_vstate.work.io_buffer,
32);
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3, CX_LAST, G_gpg_vstate.work.io_buffer, hlen,
G_gpg_vstate.work.io_buffer, olen);
} else {
cx_rng(G_gpg_vstate.work.io_buffer, olen);
}
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, olen);
cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha3,
CX_LAST,
G_gpg_vstate.work.io_buffer,
hlen,
G_gpg_vstate.work.io_buffer,
olen);
} else {
cx_rng(G_gpg_vstate.work.io_buffer, olen);
}
if ((G_gpg_vstate.io_p1 & 0x81) == 0x81) {
cx_math_next_prime(G_gpg_vstate.work.io_buffer, olen);
}
gpg_io_discard(0);
gpg_io_inserted(olen);
return SW_OK;
if ((G_gpg_vstate.io_p1 & 0x81) == 0x81) {
cx_math_next_prime(G_gpg_vstate.work.io_buffer, olen);
}
gpg_io_discard(0);
gpg_io_inserted(olen);
return SW_OK;
}

File diff suppressed because it is too large Load Diff

@ -20,407 +20,410 @@
#include "gpg_vars.h"
void gpg_check_access_ins() {
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (G_gpg_vstate.io_ins) {
case INS_EXIT:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
#ifdef GPG_LOG
#warning GPG_LOG activated
case INS_GET_LOG:
return;
#endif
case INS_SELECT:
return;
case INS_GET_DATA:
case INS_GET_NEXT_DATA:
return;
case INS_VERIFY:
return;
case INS_CHANGE_REFERENCE_DATA:
return;
case INS_RESET_RETRY_COUNTER:
if (gpg_pin_is_verified(PIN_ID_PW3) || gpg_pin_is_verified(PIN_ID_RC)) {
return;
}
break;
case INS_PUT_DATA:
case INS_PUT_DATA_ODD:
return;
case INS_GEN_ASYM_KEYPAIR:
if (G_gpg_vstate.io_p1 == 0x81) {
return;
}
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
case INS_MSE:
return;
case INS_PSO:
if ((ref == 0x9e9a) && gpg_pin_is_verified(PIN_ID_PW1)) {
// pso:sign
if (N_gpg_pstate->PW_status[0] == 0) {
gpg_pin_set_verified(PIN_ID_PW1, 0);
}
return;
}
if (((ref == 0x8086) || (ref == 0x8680)) && gpg_pin_is_verified(PIN_ID_PW2)) {
// pso:dec/enc
return;
}
break;
case INS_INTERNAL_AUTHENTICATE:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
case INS_GET_CHALLENGE:
return;
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (G_gpg_vstate.io_ins) {
case INS_EXIT:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
#ifdef GPG_LOG
#warning GPG_LOG activated
case INS_GET_LOG:
return;
#endif
case INS_TERMINATE_DF:
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
case INS_SELECT:
return;
case INS_GET_DATA:
case INS_GET_NEXT_DATA:
return;
case INS_VERIFY:
return;
case INS_CHANGE_REFERENCE_DATA:
return;
case INS_RESET_RETRY_COUNTER:
if (gpg_pin_is_verified(PIN_ID_PW3) || gpg_pin_is_verified(PIN_ID_RC)) {
return;
}
break;
case INS_PUT_DATA:
case INS_PUT_DATA_ODD:
return;
case INS_GEN_ASYM_KEYPAIR:
if (G_gpg_vstate.io_p1 == 0x81) {
return;
}
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
case INS_MSE:
return;
case INS_PSO:
if ((ref == 0x9e9a) && gpg_pin_is_verified(PIN_ID_PW1)) {
// pso:sign
if (N_gpg_pstate->PW_status[0] == 0) {
gpg_pin_set_verified(PIN_ID_PW1, 0);
}
return;
}
if (((ref == 0x8086) || (ref == 0x8680)) && gpg_pin_is_verified(PIN_ID_PW2)) {
// pso:dec/enc
return;
}
break;
case INS_INTERNAL_AUTHENTICATE:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
case INS_GET_CHALLENGE:
return;
case INS_TERMINATE_DF:
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
case INS_ACTIVATE_FILE:
return;
default:
THROW(SW_INS_NOT_SUPPORTED);
break;
}
break;
case INS_ACTIVATE_FILE:
return;
default:
THROW(SW_INS_NOT_SUPPORTED);
break;
}
THROW(SW_CONDITIONS_NOT_SATISFIED);
THROW(SW_CONDITIONS_NOT_SATISFIED);
}
void gpg_check_access_read_DO() {
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (ref) {
// ALWAYS
case 0x0101:
case 0x0102:
case 0x01F0:
case 0x01F1:
case 0x01F2:
case 0x01F8:
case 0x006E:
case 0x0065:
case 0x0073:
case 0x007A:
case 0x004F:
case 0x005E:
case 0x005B:
case 0x5F2D:
case 0x5F35:
case 0x5F50:
case 0x5F52:
case 0x7F21:
case 0x0093:
case 0x00C0:
case 0x00C1:
case 0x00C2:
case 0x00C3:
case 0x00C4:
case 0x00C5:
case 0x00C7:
case 0x00C8:
case 0x00C9:
case 0x00C6:
case 0x00CA:
case 0x00CD:
case 0x00CC:
case 0x00CE:
case 0x00CF:
case 0x00D0:
case 0x7F74:
case 0x7F66:
case 0x00D6:
case 0x00D7:
case 0x00D8:
return;
// PW2
case 0x0103:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
// PW3
case 0x00B6:
case 0x00A4:
case 0x00B8:
case 0x0104:
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (ref) {
// ALWAYS
case 0x0101:
case 0x0102:
case 0x01F0:
case 0x01F1:
case 0x01F2:
case 0x01F8:
case 0x006E:
case 0x0065:
case 0x0073:
case 0x007A:
case 0x004F:
case 0x005E:
case 0x005B:
case 0x5F2D:
case 0x5F35:
case 0x5F50:
case 0x5F52:
case 0x7F21:
case 0x0093:
case 0x00C0:
case 0x00C1:
case 0x00C2:
case 0x00C3:
case 0x00C4:
case 0x00C5:
case 0x00C7:
case 0x00C8:
case 0x00C9:
case 0x00C6:
case 0x00CA:
case 0x00CD:
case 0x00CC:
case 0x00CE:
case 0x00CF:
case 0x00D0:
case 0x7F74:
case 0x7F66:
case 0x00D6:
case 0x00D7:
case 0x00D8:
return;
// PW2
case 0x0103:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
// PW3
case 0x00B6:
case 0x00A4:
case 0x00B8:
case 0x0104:
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
}
break;
}
THROW(SW_CONDITIONS_NOT_SATISFIED);
THROW(SW_CONDITIONS_NOT_SATISFIED);
}
char debugbuff[5];
void gpg_check_access_write_DO() {
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (ref) {
// PW2
case 0x0101:
case 0x0103:
case 0x01F2:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
unsigned int ref;
ref = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (ref) {
// PW2
case 0x0101:
case 0x0103:
case 0x01F2:
if (gpg_pin_is_verified(PIN_ID_PW2)) {
return;
}
break;
// PW3
case 0x3FFF: // only used for putkey under PW3 control
case 0x4f:
case 0x0102:
case 0x0104:
case 0x01F1:
case 0x01F8:
case 0x005E:
case 0x005B:
case 0x5F2D:
case 0x5F35:
case 0x5F50:
case 0x5F48:
case 0x7F21:
case 0x00B6:
case 0x00A4:
case 0x00B8:
case 0x00C1:
case 0x00C2:
case 0x00C3:
case 0x00C4:
case 0x00C5:
case 0x00C7:
case 0x00C8:
case 0x00C9:
case 0x00C6:
case 0x00CA:
case 0x00CB:
case 0x00CC:
case 0x00CD:
case 0x00CE:
case 0x00CF:
case 0x00D0:
case 0x00D1:
case 0x00D2:
case 0x00D3:
case 0x00D5:
case 0x00F4:
case 0x00D6:
case 0x00D7:
case 0x00D8:
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
}
break;
// PW3
case 0x3FFF: // only used for putkey under PW3 control
case 0x4f:
case 0x0102:
case 0x0104:
case 0x01F1:
case 0x01F8:
case 0x005E:
case 0x005B:
case 0x5F2D:
case 0x5F35:
case 0x5F50:
case 0x5F48:
case 0x7F21:
case 0x00B6:
case 0x00A4:
case 0x00B8:
case 0x00C1:
case 0x00C2:
case 0x00C3:
case 0x00C4:
case 0x00C5:
case 0x00C7:
case 0x00C8:
case 0x00C9:
case 0x00C6:
case 0x00CA:
case 0x00CB:
case 0x00CC:
case 0x00CD:
case 0x00CE:
case 0x00CF:
case 0x00D0:
case 0x00D1:
case 0x00D2:
case 0x00D3:
case 0x00D5:
case 0x00F4:
case 0x00D6:
case 0x00D7:
case 0x00D8:
if (gpg_pin_is_verified(PIN_ID_PW3)) {
return;
}
break;
}
THROW(SW_CONDITIONS_NOT_SATISFIED);
THROW(SW_CONDITIONS_NOT_SATISFIED);
}
/* assume command is fully received */
int gpg_dispatch() {
unsigned int tag, t, l;
int sw;
if ((G_gpg_vstate.io_cla != 0x00) && (G_gpg_vstate.io_cla != 0x10) && (G_gpg_vstate.io_cla != 0xEF)) {
THROW(SW_CLA_NOT_SUPPORTED);
return SW_CLA_NOT_SUPPORTED;
}
tag = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
switch (G_gpg_vstate.io_ins) {
#ifdef GPG_LOG
case INS_GET_LOG:
gpg_io_discard(1);
gpg_io_insert(G_gpg_vstate.log_buffer, 32);
return SW_OK;
#endif
/* --- SELECT --- */
case INS_SELECT:
sw = gpg_apdu_select();
return sw;
break;
unsigned int tag, t, l;
int sw;
/* --- ACTIVATE/TERMINATE FILE --- */
case INS_ACTIVATE_FILE:
gpg_io_discard(0);
if (N_gpg_pstate->histo[7] == STATE_TERMINATE) {
gpg_install(STATE_ACTIVATE);
}
return (SW_OK);
break;
case INS_TERMINATE_DF:
gpg_io_discard(0);
if (gpg_pin_is_verified(PIN_ID_PW3) || (N_gpg_pstate->PW3.counter == 0)) {
gpg_install(STATE_TERMINATE);
return (SW_OK);
break;
if ((G_gpg_vstate.io_cla != 0x00) && (G_gpg_vstate.io_cla != 0x10) &&
(G_gpg_vstate.io_cla != 0xEF)) {
THROW(SW_CLA_NOT_SUPPORTED);
return SW_CLA_NOT_SUPPORTED;
}
THROW(SW_CONDITIONS_NOT_SATISFIED);
break;
}
/* Other commands allowed if not terminated */
if (N_gpg_pstate->histo[7] != 0x07) {
THROW(SW_STATE_TERMINATED);
}
tag = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
/* Process */
gpg_check_access_ins();
switch (G_gpg_vstate.io_ins) {
#ifdef GPG_DEBUG_APDU
case 0x42:
sw = debug_apdu();
break;
switch (G_gpg_vstate.io_ins) {
#ifdef GPG_LOG
case INS_GET_LOG:
gpg_io_discard(1);
gpg_io_insert(G_gpg_vstate.log_buffer, 32);
return SW_OK;
#endif
case INS_EXIT:
os_sched_exit(0);
sw = SW_OK;
break;
/* --- CHALLENGE --- */
case INS_GET_CHALLENGE:
sw = gpg_apdu_get_challenge();
break;
/* --- DATA --- */
case INS_SELECT_DATA:
if ((G_gpg_vstate.io_p1 > 2) || (G_gpg_vstate.io_p2 != 0x04)) {
THROW(SW_WRONG_P1P2);
}
gpg_io_fetch_tl(&t, &l);
if (t != 0x60) {
// TODO add l check
THROW(SW_DATA_INVALID);
}
gpg_io_fetch_tl(&t, &l);
if (t != 0x5C) {
// TODO add l check
THROW(SW_WRONG_DATA);
}
if (l == 1) {
tag = gpg_io_fetch_u8();
} else if (l == 2) {
tag = gpg_io_fetch_u16();
} else {
THROW(SW_WRONG_DATA);
}
sw = gpg_apdu_select_data(tag, G_gpg_vstate.io_p1);
break;
case INS_GET_DATA:
gpg_check_access_read_DO();
switch (tag) {
case 0x00B6:
case 0x00A4:
case 0x00B8:
sw = gpg_apdu_get_key_data(tag);
break;
default:
sw = gpg_apdu_get_data(tag);
break;
/* --- SELECT --- */
case INS_SELECT:
sw = gpg_apdu_select();
return sw;
break;
/* --- ACTIVATE/TERMINATE FILE --- */
case INS_ACTIVATE_FILE:
gpg_io_discard(0);
if (N_gpg_pstate->histo[7] == STATE_TERMINATE) {
gpg_install(STATE_ACTIVATE);
}
return (SW_OK);
break;
case INS_TERMINATE_DF:
gpg_io_discard(0);
if (gpg_pin_is_verified(PIN_ID_PW3) || (N_gpg_pstate->PW3.counter == 0)) {
gpg_install(STATE_TERMINATE);
return (SW_OK);
break;
}
THROW(SW_CONDITIONS_NOT_SATISFIED);
break;
}
break;
case INS_GET_NEXT_DATA:
gpg_check_access_read_DO();
sw = gpg_apdu_get_next_data(tag);
break;
case INS_PUT_DATA_ODD:
case INS_PUT_DATA:
gpg_check_access_write_DO();
switch (tag) {
case 0x00B6:
case 0x00A4:
case 0x00B8:
sw = gpg_apdu_put_key_data(tag);
break;
default:
sw = gpg_apdu_put_data(tag);
break;
}
break;
/* --- PIN -- */
case INS_VERIFY:
if ((G_gpg_vstate.io_p2 == 0x81) || (G_gpg_vstate.io_p2 == 0x82) || (G_gpg_vstate.io_p2 == 0x83)) {
sw = gpg_apdu_verify();
break;
}
THROW(SW_INCORRECT_P1P2);
case INS_CHANGE_REFERENCE_DATA:
if ((G_gpg_vstate.io_p2 == 0x81) || (G_gpg_vstate.io_p2 == 0x83)) {
sw = gpg_apdu_change_ref_data();
break;
/* Other commands allowed if not terminated */
if (N_gpg_pstate->histo[7] != STATE_ACTIVATE) {
THROW(SW_STATE_TERMINATED);
}
THROW(SW_INCORRECT_P1P2);
case INS_RESET_RETRY_COUNTER:
if ((G_gpg_vstate.io_p2 == 0x81) && ((G_gpg_vstate.io_p1 == 0) || (G_gpg_vstate.io_p1 == 2))) {
sw = gpg_apdu_reset_retry_counter();
break;
}
THROW(SW_INCORRECT_P1P2);
/* --- Key Management --- */
case INS_GEN_ASYM_KEYPAIR:
sw = gpg_apdu_gen();
break;
/* --- MSE --- */
case INS_MSE:
sw = gpg_apdu_mse(tag);
break;
/* Process */
gpg_check_access_ins();
/* --- PSO --- */
case INS_PSO:
sw = gpg_apdu_pso();
break;
case INS_INTERNAL_AUTHENTICATE:
sw = gpg_apdu_internal_authenticate();
break;
switch (G_gpg_vstate.io_ins) {
#ifdef GPG_DEBUG_APDU
case 0x42:
sw = debug_apdu();
break;
#endif
default:
THROW(SW_INS_NOT_SUPPORTED);
break;
}
case INS_EXIT:
os_sched_exit(0);
sw = SW_OK;
break;
/* --- CHALLENGE --- */
case INS_GET_CHALLENGE:
sw = gpg_apdu_get_challenge();
break;
/* --- DATA --- */
case INS_SELECT_DATA:
if ((G_gpg_vstate.io_p1 > 2) || (G_gpg_vstate.io_p2 != 0x04)) {
THROW(SW_WRONG_P1P2);
}
gpg_io_fetch_tl(&t, &l);
if (t != 0x60) {
// TODO add l check
THROW(SW_DATA_INVALID);
}
gpg_io_fetch_tl(&t, &l);
if (t != 0x5C) {
// TODO add l check
THROW(SW_WRONG_DATA);
}
if (l == 1) {
tag = gpg_io_fetch_u8();
} else if (l == 2) {
tag = gpg_io_fetch_u16();
} else {
THROW(SW_WRONG_DATA);
}
sw = gpg_apdu_select_data(tag, G_gpg_vstate.io_p1);
break;
case INS_GET_DATA:
gpg_check_access_read_DO();
switch (tag) {
case 0x00B6:
case 0x00A4:
case 0x00B8:
sw = gpg_apdu_get_key_data(tag);
break;
default:
sw = gpg_apdu_get_data(tag);
break;
}
break;
case INS_GET_NEXT_DATA:
gpg_check_access_read_DO();
sw = gpg_apdu_get_next_data(tag);
break;
case INS_PUT_DATA_ODD:
case INS_PUT_DATA:
gpg_check_access_write_DO();
switch (tag) {
case 0x00B6:
case 0x00A4:
case 0x00B8:
sw = gpg_apdu_put_key_data(tag);
break;
default:
sw = gpg_apdu_put_data(tag);
break;
}
break;
/* --- PIN -- */
case INS_VERIFY:
if ((G_gpg_vstate.io_p2 == 0x81) || (G_gpg_vstate.io_p2 == 0x82) ||
(G_gpg_vstate.io_p2 == 0x83)) {
sw = gpg_apdu_verify();
break;
}
THROW(SW_INCORRECT_P1P2);
case INS_CHANGE_REFERENCE_DATA:
if ((G_gpg_vstate.io_p2 == 0x81) || (G_gpg_vstate.io_p2 == 0x83)) {
sw = gpg_apdu_change_ref_data();
break;
}
THROW(SW_INCORRECT_P1P2);
case INS_RESET_RETRY_COUNTER:
if ((G_gpg_vstate.io_p2 == 0x81) &&
((G_gpg_vstate.io_p1 == 0) || (G_gpg_vstate.io_p1 == 2))) {
sw = gpg_apdu_reset_retry_counter();
break;
}
THROW(SW_INCORRECT_P1P2);
/* --- Key Management --- */
case INS_GEN_ASYM_KEYPAIR:
sw = gpg_apdu_gen();
break;
/* --- MSE --- */
case INS_MSE:
sw = gpg_apdu_mse(tag);
break;
/* --- PSO --- */
case INS_PSO:
sw = gpg_apdu_pso();
break;
case INS_INTERNAL_AUTHENTICATE:
sw = gpg_apdu_internal_authenticate();
break;
default:
THROW(SW_INS_NOT_SUPPORTED);
break;
}
return sw;
return sw;
}

@ -23,13 +23,13 @@
* @out seed 32 bytes master seed for given slot
*/
void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
unsigned int path[2];
unsigned char chain[32];
unsigned int path[2];
unsigned char chain[32];
memset(chain, 0, 32);
path[0] = 0x80475047;
path[1] = slot + 1;
os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2, seed, chain);
memset(chain, 0, 32);
path[0] = 0x80475047;
path[1] = slot + 1;
os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 2, seed, chain);
}
/* @in Sn master seed slot number
@ -40,245 +40,265 @@ void gpg_pso_derive_slot_seed(int slot, unsigned char *seed) {
*/
void gpg_pso_derive_key_seed(unsigned char *Sn,
unsigned char *key_name,
unsigned int idx,
unsigned int idx,
unsigned char *Ski,
unsigned int Ski_len) {
unsigned char h[32];
h[0] = idx >> 8;
h[1] = idx;
unsigned int Ski_len) {
unsigned char h[32];
h[0] = idx >> 8;
h[1] = idx;
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, Sn, 32, NULL, 0);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, 0, (unsigned char *)key_name, 4, NULL, 0);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, CX_LAST, h, 2, h, 32);
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha256, 0, Sn, 32, NULL, 0);
cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha256, 0, (unsigned char *) key_name, 4, NULL, 0);
cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha256, CX_LAST, h, 2, h, 32);
#ifdef GPG_SHAKE256
cx_shake256_init(&G_gpg_vstate.work.md.sha3, Ski_len);
cx_sha3_update(&G_gpg_vstate.work.md.sha3, h, 32);
cx_sha3_final(&G_gpg_vstate.work.md.sha3, Ski);
cx_shake256_init(&G_gpg_vstate.work.md.sha3, Ski_len);
cx_sha3_update(&G_gpg_vstate.work.md.sha3, h, 32);
cx_sha3_final(&G_gpg_vstate.work.md.sha3, Ski);
#else
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, Ski_len);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha3, CX_LAST, h, 32, Ski, Ski_len);
cx_sha3_xof_init(&G_gpg_vstate.work.md.sha3, 256, Ski_len);
cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha3, CX_LAST, h, 32, Ski, Ski_len);
#endif
}
/* assume command is fully received */
int gpg_apdu_gen() {
unsigned int t, l, ksz, reset_cnt;
gpg_key_t * keygpg;
unsigned char seed[66];
unsigned char *name;
unsigned int t, l, ksz, reset_cnt;
gpg_key_t *keygpg;
unsigned char seed[66];
unsigned char *name;
switch ((G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2) {
case 0x8000:
case 0x8001:
case 0x8100:
break;
default:
THROW(SW_INCORRECT_P1P2);
return SW_INCORRECT_P1P2;
}
switch ((G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2) {
case 0x8000:
case 0x8001:
case 0x8100:
break;
default:
THROW(SW_INCORRECT_P1P2);
return SW_INCORRECT_P1P2;
}
if (G_gpg_vstate.io_lc != 2) {
THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH;
}
if (G_gpg_vstate.io_lc != 2) {
THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH;
}
gpg_io_fetch_tl(&t, &l);
gpg_io_discard(1);
reset_cnt = 0;
switch (t) {
case 0xB6:
keygpg = &G_gpg_vstate.kslot->sig;
name = (unsigned char *)PIC("sig ");
gpg_io_fetch_tl(&t, &l);
gpg_io_discard(1);
reset_cnt = 0;
break;
case 0xA4:
keygpg = &G_gpg_vstate.kslot->aut;
name = (unsigned char *)PIC("aut ");
break;
case 0xB8:
keygpg = &G_gpg_vstate.kslot->dec;
name = (unsigned char *)PIC("dec ");
break;
default:
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
switch (t) {
case 0xB6:
keygpg = &G_gpg_vstate.kslot->sig;
name = (unsigned char *) PIC("sig ");
reset_cnt = 0;
break;
case 0xA4:
keygpg = &G_gpg_vstate.kslot->aut;
name = (unsigned char *) PIC("aut ");
break;
case 0xB8:
keygpg = &G_gpg_vstate.kslot->dec;
name = (unsigned char *) PIC("dec ");
break;
default:
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
switch ((G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2) {
// -- generate keypair ---
case 0x8000:
case 0x8001:
// RSA
if (keygpg->attributes.value[0] == 0x01) {
unsigned char * pq;
cx_rsa_public_key_t * rsa_pub;
cx_rsa_private_key_t *rsa_priv, *pkey;
unsigned int pkey_size;
switch ((G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2) {
// -- generate keypair ---
case 0x8000:
case 0x8001:
// RSA
if (keygpg->attributes.value[0] == 0x01) {
unsigned char *pq;
cx_rsa_public_key_t *rsa_pub;
cx_rsa_private_key_t *rsa_priv, *pkey;
unsigned int pkey_size;
ksz = (keygpg->attributes.value[1] << 8) | keygpg->attributes.value[2];
ksz = ksz >> 3;
rsa_pub = (cx_rsa_public_key_t *)&G_gpg_vstate.work.rsa.public;
rsa_priv = (cx_rsa_private_key_t *)&G_gpg_vstate.work.rsa.private;
pkey = &keygpg->priv_key.rsa;
switch (ksz) {
case 1024 / 8:
pkey_size = sizeof(cx_rsa_1024_private_key_t);
break;
case 2048 / 8:
pkey_size = sizeof(cx_rsa_2048_private_key_t);
break;
case 3072 / 8:
pkey_size = sizeof(cx_rsa_3072_private_key_t);
break;
case 4096 / 8:
pkey_size = sizeof(cx_rsa_4096_private_key_t);
break;
default:
THROW(SW_WRONG_DATA);
}
pq = NULL;
if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)) {
pq = &rsa_pub->n[0];
unsigned int size;
size = ksz >> 1;
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, pq, size);
gpg_pso_derive_key_seed(seed, name, 2, pq + size, size);
*pq |= 0x80;
*(pq + size) |= 0x80;
cx_math_next_prime(pq, size);
cx_math_next_prime(pq + size, size);
}
ksz = (keygpg->attributes.value[1] << 8) | keygpg->attributes.value[2];
ksz = ksz >> 3;
rsa_pub = (cx_rsa_public_key_t *) &G_gpg_vstate.work.rsa.public;
rsa_priv = (cx_rsa_private_key_t *) &G_gpg_vstate.work.rsa.private;
pkey = &keygpg->priv_key.rsa;
switch (ksz) {
case 1024 / 8:
pkey_size = sizeof(cx_rsa_1024_private_key_t);
break;
case 2048 / 8:
pkey_size = sizeof(cx_rsa_2048_private_key_t);
break;
case 3072 / 8:
pkey_size = sizeof(cx_rsa_3072_private_key_t);
break;
case 4096 / 8:
pkey_size = sizeof(cx_rsa_4096_private_key_t);
break;
default:
THROW(SW_WRONG_DATA);
}
pq = NULL;
if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)) {
pq = &rsa_pub->n[0];
unsigned int size;
size = ksz >> 1;
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, pq, size);
gpg_pso_derive_key_seed(seed, name, 2, pq + size, size);
*pq |= 0x80;
*(pq + size) |= 0x80;
cx_math_next_prime(pq, size);
cx_math_next_prime(pq + size, size);
}
cx_rsa_generate_pair(ksz, rsa_pub, rsa_priv, (const unsigned char *)N_gpg_pstate->default_RSA_exponent, 4, pq);
cx_rsa_generate_pair(ksz,
rsa_pub,
rsa_priv,
(const unsigned char *) N_gpg_pstate->default_RSA_exponent,
4,
pq);
nvm_write(pkey, rsa_priv, pkey_size);
nvm_write(&keygpg->pub_key.rsa[0], rsa_pub->e, 4);
if (reset_cnt) {
reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count, &reset_cnt, sizeof(unsigned int));
}
gpg_io_clear();
nvm_write(pkey, rsa_priv, pkey_size);
nvm_write(&keygpg->pub_key.rsa[0], rsa_pub->e, 4);
if (reset_cnt) {
reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count, &reset_cnt, sizeof(unsigned int));
}
gpg_io_clear();
goto send_rsa_pub;
}
// ECC
if ((keygpg->attributes.value[0] == 18) || (keygpg->attributes.value[0] == 19) ||
(keygpg->attributes.value[0] == 22)) {
unsigned int curve, keepprivate;
keepprivate = 0;
curve = gpg_oid2curve(keygpg->attributes.value + 1, keygpg->attributes.length - 1);
if (curve == CX_CURVE_NONE) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)) {
ksz = gpg_curve2domainlen(curve);
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, seed, ksz);
cx_ecfp_init_private_key(curve, seed, ksz, &G_gpg_vstate.work.ecfp.private);
keepprivate = 1;
}
goto send_rsa_pub;
}
// ECC
if ((keygpg->attributes.value[0] == 18) || (keygpg->attributes.value[0] == 19) ||
(keygpg->attributes.value[0] == 22)) {
unsigned int curve, keepprivate;
keepprivate = 0;
curve = gpg_oid2curve(keygpg->attributes.value + 1, keygpg->attributes.length - 1);
if (curve == CX_CURVE_NONE) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
if ((G_gpg_vstate.io_p2 == 0x01) || (G_gpg_vstate.seed_mode)) {
ksz = gpg_curve2domainlen(curve);
gpg_pso_derive_slot_seed(G_gpg_vstate.slot, seed);
gpg_pso_derive_key_seed(seed, name, 1, seed, ksz);
cx_ecfp_init_private_key(curve, seed, ksz, &G_gpg_vstate.work.ecfp.private);
keepprivate = 1;
}
cx_ecfp_generate_pair(curve, &G_gpg_vstate.work.ecfp.public, &G_gpg_vstate.work.ecfp.private, keepprivate);
nvm_write(&keygpg->priv_key.ecfp, &G_gpg_vstate.work.ecfp.private, sizeof(cx_ecfp_private_key_t));
nvm_write(&keygpg->pub_key.ecfp, &G_gpg_vstate.work.ecfp.public, sizeof(cx_ecfp_public_key_t));
if (reset_cnt) {
reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count, &reset_cnt, sizeof(unsigned int));
}
gpg_io_clear();
goto send_ecc_pub;
}
break;
cx_ecfp_generate_pair(curve,
&G_gpg_vstate.work.ecfp.public,
&G_gpg_vstate.work.ecfp.private,
keepprivate);
nvm_write(&keygpg->priv_key.ecfp,
&G_gpg_vstate.work.ecfp.private,
sizeof(cx_ecfp_private_key_t));
nvm_write(&keygpg->pub_key.ecfp,
&G_gpg_vstate.work.ecfp.public,
sizeof(cx_ecfp_public_key_t));
if (reset_cnt) {
reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count, &reset_cnt, sizeof(unsigned int));
}
gpg_io_clear();
goto send_ecc_pub;
}
break;
// --- read pubkey ---
case 0x8100:
if (keygpg->attributes.value[0] == 0x01) {
/// read RSA
send_rsa_pub:
gpg_io_discard(1);
// check length
ksz = (keygpg->attributes.value[1] << 8) | keygpg->attributes.value[2];
ksz = ksz >> 3;
gpg_io_mark();
switch (ksz) {
case 1024 / 8:
if (keygpg->priv_key.rsa1024.size == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *)&keygpg->priv_key.rsa1024.n);
break;
case 2048 / 8:
if (keygpg->priv_key.rsa2048.size == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *)&keygpg->priv_key.rsa2048.n);
break;
case 3072 / 8:
if (keygpg->priv_key.rsa3072.size == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *)&keygpg->priv_key.rsa3072.n);
break;
case 4096 / 8:
if (keygpg->priv_key.rsa4096.size == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *)&keygpg->priv_key.rsa4096.n);
break;
}
gpg_io_insert_tlv(0x82, 4, keygpg->pub_key.rsa);
// --- read pubkey ---
case 0x8100:
if (keygpg->attributes.value[0] == 0x01) {
/// read RSA
send_rsa_pub:
gpg_io_discard(1);
// check length
ksz = (keygpg->attributes.value[1] << 8) | keygpg->attributes.value[2];
ksz = ksz >> 3;
gpg_io_mark();
switch (ksz) {
case 1024 / 8:
if (keygpg->priv_key.rsa1024.size == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *) &keygpg->priv_key.rsa1024.n);
break;
case 2048 / 8:
if (keygpg->priv_key.rsa2048.size == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *) &keygpg->priv_key.rsa2048.n);
break;
case 3072 / 8:
if (keygpg->priv_key.rsa3072.size == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *) &keygpg->priv_key.rsa3072.n);
break;
case 4096 / 8:
if (keygpg->priv_key.rsa4096.size == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
gpg_io_insert_tlv(0x81, ksz, (unsigned char *) &keygpg->priv_key.rsa4096.n);
break;
}
gpg_io_insert_tlv(0x82, 4, keygpg->pub_key.rsa);
l = G_gpg_vstate.io_length;
gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_tl(0x7f49, l);
gpg_io_set_offset(IO_OFFSET_END);
l = G_gpg_vstate.io_length;
gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_tl(0x7f49, l);
gpg_io_set_offset(IO_OFFSET_END);
return SW_OK;
}
return SW_OK;
}
if ((keygpg->attributes.value[0] == 18) || (keygpg->attributes.value[0] == 19) ||
(keygpg->attributes.value[0] == 22)) {
unsigned int curve;
/// read ECC
send_ecc_pub:
if ((keygpg->attributes.value[0] == 18) || (keygpg->attributes.value[0] == 19) ||
(keygpg->attributes.value[0] == 22)) {
unsigned int curve;
/// read ECC
send_ecc_pub:
if (keygpg->pub_key.ecfp256.W_len == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
gpg_io_discard(1);
gpg_io_mark();
curve = gpg_oid2curve(keygpg->attributes.value + 1, keygpg->attributes.length - 1);
if (curve == CX_CURVE_Ed25519) {
memmove(G_gpg_vstate.work.io_buffer + 128, keygpg->pub_key.ecfp256.W, keygpg->pub_key.ecfp256.W_len);
cx_edward_compress_point(CX_CURVE_Ed25519, G_gpg_vstate.work.io_buffer + 128, 65);
gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer + 129); // 129: discard 02
} else if (curve == CX_CURVE_Curve25519) {
unsigned int i, len;
len = keygpg->pub_key.ecfp256.W_len - 1;
for (i = 0; i <= len; i++) {
G_gpg_vstate.work.io_buffer[128 + i] = keygpg->pub_key.ecfp256.W[len - i];
}
gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer + 128);
} else {
gpg_io_insert_tlv(0x86, keygpg->pub_key.ecfp256.W_len, (unsigned char *)&keygpg->pub_key.ecfp256.W);
}
l = G_gpg_vstate.io_length;
gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_tl(0x7f49, l);
gpg_io_set_offset(IO_OFFSET_END);
return SW_OK;
if (keygpg->pub_key.ecfp256.W_len == 0) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return 0;
}
gpg_io_discard(1);
gpg_io_mark();
curve = gpg_oid2curve(keygpg->attributes.value + 1, keygpg->attributes.length - 1);
if (curve == CX_CURVE_Ed25519) {
memmove(G_gpg_vstate.work.io_buffer + 128,
keygpg->pub_key.ecfp256.W,
keygpg->pub_key.ecfp256.W_len);
cx_edward_compress_point(CX_CURVE_Ed25519,
G_gpg_vstate.work.io_buffer + 128,
65);
gpg_io_insert_tlv(0x86,
32,
G_gpg_vstate.work.io_buffer + 129); // 129: discard 02
} else if (curve == CX_CURVE_Curve25519) {
unsigned int i, len;
len = keygpg->pub_key.ecfp256.W_len - 1;
for (i = 0; i <= len; i++) {
G_gpg_vstate.work.io_buffer[128 + i] = keygpg->pub_key.ecfp256.W[len - i];
}
gpg_io_insert_tlv(0x86, 32, G_gpg_vstate.work.io_buffer + 128);
} else {
gpg_io_insert_tlv(0x86,
keygpg->pub_key.ecfp256.W_len,
(unsigned char *) &keygpg->pub_key.ecfp256.W);
}
l = G_gpg_vstate.io_length;
gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_tl(0x7f49, l);
gpg_io_set_offset(IO_OFFSET_END);
return SW_OK;
}
break;
}
break;
}
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}

@ -19,7 +19,7 @@
#include "gpg_api.h"
#include "gpg_vars.h"
#define SHORT(x) ((x) >> 8) & 0xFF, (x)&0xFF
#define SHORT(x) ((x) >> 8) & 0xFF, (x) &0xFF
/* ----------------------*/
/* -- A Kind of Magic -- */
/* ----------------------*/
@ -68,115 +68,132 @@ const unsigned char C_OID_BRAINPOOL512R1[9] = {
// Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1
const unsigned char C_OID_Ed25519[9] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
0x2B,
0x06,
0x01,
0x04,
0x01,
0xDA,
0x47,
0x0F,
0x01,
};
// Ed25519/curve25519: 1.3.6.1.4.1.11591.15.1
const unsigned char C_OID_cv25519[10] = {
0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01,
0x2B,
0x06,
0x01,
0x04,
0x01,
0x97,
0x55,
0x01,
0x05,
0x01,
};
unsigned int gpg_oid2curve(unsigned char *oid, unsigned int len) {
if ((len == sizeof(C_OID_SECP256R1)) && (memcmp(oid, C_OID_SECP256R1, len) == 0)) {
return CX_CURVE_SECP256R1;
}
/*
if ( (len == sizeof(C_OID_SECP256K1)) && (memcmp(oid, C_OID_SECP256K1, len)==0) ) {
return CX_CURVE_SECP256K1;
}
if ( (len == sizeof(C_OID_SECP384R1)) && (memcmp(oid, C_OID_SECP384R1, len)==0) ) {
return CX_CURVE_SECP384R1;
}
if ( (len == sizeof(C_OID_SECP521R1)) && (memcmp(oid, C_OID_SECP521R1, len)==0) ) {
return CX_CURVE_SECP521R1;
}
*/
if ((len == sizeof(C_OID_SECP256R1)) && (memcmp(oid, C_OID_SECP256R1, len) == 0)) {
return CX_CURVE_SECP256R1;
}
/*
if ( (len == sizeof(C_OID_SECP256K1)) && (memcmp(oid, C_OID_SECP256K1, len)==0) ) {
return CX_CURVE_SECP256K1;
}
/*
if ( (len == sizeof(C_OID_BRAINPOOL256R1)) && (memcmp(oid, C_OID_BRAINPOOL256R1, len)==0) ) {
return CX_CURVE_BrainPoolP256R1;
}
if ( (len == sizeof(C_OID_BRAINPOOL384R1)) && (memcmp(oid, C_OID_BRAINPOOL384R1, len)==0) ) {
return CX_CURVE_BrainPoolP384R1;
}
if ( (len == sizeof(C_OID_BRAINPOOL512R1)) && (memcmp(oid, C_OID_BRAINPOOL512R1, len)==0) ) {
return CX_CURVE_BrainPoolP512R1;
}
*/
if ((len == sizeof(C_OID_Ed25519)) && (memcmp(oid, C_OID_Ed25519, len) == 0)) {
return CX_CURVE_Ed25519;
}
if ((len == sizeof(C_OID_cv25519)) && (memcmp(oid, C_OID_cv25519, len) == 0)) {
return CX_CURVE_Curve25519;
}
/*
if ( (len == sizeof(C_OID_SECP256K1)) && (memcmp(oid, C_OID_SECP256K1, len)==0) ) {
return CX_CURVE_256K1;
}
if ( (len == sizeof(C_OID_BRAINPOOL256T1)) && (memcmp(oid, C_OID_BRAINPOOL256T1, len)==0) ) {
return CX_CURVE_BrainPoolP256T1;
}
*/
return CX_CURVE_NONE;
if ( (len == sizeof(C_OID_SECP384R1)) && (memcmp(oid, C_OID_SECP384R1, len)==0) ) {
return CX_CURVE_SECP384R1;
}
if ( (len == sizeof(C_OID_SECP521R1)) && (memcmp(oid, C_OID_SECP521R1, len)==0) ) {
return CX_CURVE_SECP521R1;
}
*/
/*
if ( (len == sizeof(C_OID_BRAINPOOL256R1)) && (memcmp(oid, C_OID_BRAINPOOL256R1, len)==0) ) {
return CX_CURVE_BrainPoolP256R1;
}
if ( (len == sizeof(C_OID_BRAINPOOL384R1)) && (memcmp(oid, C_OID_BRAINPOOL384R1, len)==0) ) {
return CX_CURVE_BrainPoolP384R1;
}
if ( (len == sizeof(C_OID_BRAINPOOL512R1)) && (memcmp(oid, C_OID_BRAINPOOL512R1, len)==0) ) {
return CX_CURVE_BrainPoolP512R1;
}
*/
if ((len == sizeof(C_OID_Ed25519)) && (memcmp(oid, C_OID_Ed25519, len) == 0)) {
return CX_CURVE_Ed25519;
}
if ((len == sizeof(C_OID_cv25519)) && (memcmp(oid, C_OID_cv25519, len) == 0)) {
return CX_CURVE_Curve25519;
}
/*
if ( (len == sizeof(C_OID_SECP256K1)) && (memcmp(oid, C_OID_SECP256K1, len)==0) ) {
return CX_CURVE_256K1;
}
if ( (len == sizeof(C_OID_BRAINPOOL256T1)) && (memcmp(oid, C_OID_BRAINPOOL256T1, len)==0) ) {
return CX_CURVE_BrainPoolP256T1;
}
*/
return CX_CURVE_NONE;
}
unsigned char *gpg_curve2oid(unsigned int cv, unsigned int *len) {
switch (cv) {
case CX_CURVE_SECP256R1:
*len = sizeof(C_OID_SECP256R1);
return (unsigned char *)PIC(C_OID_SECP256R1);
/*
case CX_CURVE_SECP256K1:
*len = sizeof(C_OID_SECP256K1);
return (unsigned char*)PIC(C_OID_SECP256K1);
case CX_CURVE_SECP384R1:
*len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_SECP521R1:
*len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1);
*/
/*
case CX_CURVE_BrainPoolP256R1:
*len = sizeof(C_OID_SECP256R1);
return (unsigned char*)PIC(C_OID_SECP256R1);
case CX_CURVE_BrainPoolP384R1:
*len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_BrainPoolP512R1:
*len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1);
*/
case CX_CURVE_Ed25519:
*len = sizeof(C_OID_Ed25519);
return (unsigned char *)PIC(C_OID_Ed25519);
case CX_CURVE_Curve25519:
*len = sizeof(C_OID_cv25519);
return (unsigned char *)PIC(C_OID_cv25519);
}
*len = 0;
return NULL;
switch (cv) {
case CX_CURVE_SECP256R1:
*len = sizeof(C_OID_SECP256R1);
return (unsigned char *) PIC(C_OID_SECP256R1);
/*
case CX_CURVE_SECP256K1:
*len = sizeof(C_OID_SECP256K1);
return (unsigned char*)PIC(C_OID_SECP256K1);
case CX_CURVE_SECP384R1:
*len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_SECP521R1:
*len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1);
*/
/*
case CX_CURVE_BrainPoolP256R1:
*len = sizeof(C_OID_SECP256R1);
return (unsigned char*)PIC(C_OID_SECP256R1);
case CX_CURVE_BrainPoolP384R1:
*len = sizeof(C_OID_SECP384R1);
return (unsigned char*)PIC(C_OID_SECP384R1);
case CX_CURVE_BrainPoolP512R1:
*len = sizeof(C_OID_SECP521R1);
return (unsigned char*)PIC(C_OID_SECP521R1);
*/
case CX_CURVE_Ed25519:
*len = sizeof(C_OID_Ed25519);
return (unsigned char *) PIC(C_OID_Ed25519);
case CX_CURVE_Curve25519:
*len = sizeof(C_OID_cv25519);
return (unsigned char *) PIC(C_OID_cv25519);
}
*len = 0;
return NULL;
}
unsigned int gpg_curve2domainlen(unsigned int cv) {
switch (cv) {
case CX_CURVE_SECP256R1:
case CX_CURVE_Ed25519:
case CX_CURVE_Curve25519:
return 32;
}
return 0;
switch (cv) {
case CX_CURVE_SECP256R1:
case CX_CURVE_Ed25519:
case CX_CURVE_Curve25519:
return 32;
}
return 0;
}
/* -------------------------------*/
@ -201,30 +218,49 @@ const unsigned char C_ext_capabilities[10] = {
};
const unsigned char C_ext_length[8] = {0x02, 0x02, SHORT(GPG_APDU_LENGTH), 0x02, 0x02, SHORT(GPG_APDU_LENGTH)};
const unsigned char C_ext_length[8] =
{0x02, 0x02, SHORT(GPG_APDU_LENGTH), 0x02, 0x02, SHORT(GPG_APDU_LENGTH)};
/* ---------------------*/
/* -- default values -- */
/* ---------------------*/
const unsigned char C_default_AID[] = {0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
// version
0x03, 0x03,
// manufacturer
0x2C, 0x97,
// serial
0x00, 0x00, 0x00, 0x00,
// RFU
0x00, 0x00};
const unsigned char C_default_Histo[] = {0x00, 0x31,
0xC5, // select method: by DF/partialDF; IO-file:readbinary; RFU???
0x73,
0xC0, // select method: by DF/partialDF ,
0x01, // data coding style: ontime/byte
0x80, // chaining
0x7F, // zero state
0x90, 0x00};
const unsigned char C_default_AID[] = {
// RID: Registered application provider Identifier
0xD2,
0x76,
0x00,
0x01,
0x24,
// PIX: Proprietary application identifier extension
// application
0x01,
// version
0x03,
0x03,
// manufacturer
0x2C,
0x97,
// serial
0x00,
0x00,
0x00,
0x00,
// RFU
0x00,
0x00};
const unsigned char C_default_Histo[] = {
0x00,
0x31,
0xC5, // select method: by DF/partialDF; IO-file:readbinary; RFU???
0x73,
0xC0, // select method: by DF/partialDF ,
0x01, // data coding style: ontime/byte
0x80, // chaining
0x7F, // zero state
0x90,
0x00};
// Default template: RSA2048 010800002001 / 010800002001
#if 1
@ -232,18 +268,22 @@ const unsigned char C_default_AlgoAttr_sig[] = {
// RSA
0x01,
// Modulus default length 2048
0x08, 0x00,
0x08,
0x00,
// PubExp length 32
0x00, 0x20,
0x00,
0x20,
// std: e,p,q with modulus (n)
0x01};
const unsigned char C_default_AlgoAttr_dec[] = {
// RSA
0x01,
// Modulus default length 2048
0x08, 0x00,
0x08,
0x00,
// PubExp length 32
0x00, 0x20,
0x00,
0x20,
// std: e,p,q with modulus (n)
0x01};
#endif
@ -296,135 +336,138 @@ const unsigned char C_sha256_PW2[] = {
/* ----------------------------------------------------------------------- */
void gpg_init() {
memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t));
// first init ?
if (memcmp((void *)(N_gpg_pstate->magic), (void *)C_MAGIC, sizeof(C_MAGIC)) != 0) {
gpg_install(STATE_ACTIVATE);
gpg_nvm_write((void *)(N_gpg_pstate->magic), (void *)C_MAGIC, sizeof(C_MAGIC));
memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t));
}
// key conf
G_gpg_vstate.slot = N_gpg_pstate->config_slot[1];
G_gpg_vstate.kslot = (gpg_key_slot_t *)&N_gpg_pstate->keys[G_gpg_vstate.slot];
gpg_mse_reset();
// pin conf
G_gpg_vstate.pinmode = N_gpg_pstate->config_pin[0];
// ux conf
gpg_init_ux();
// first init ?
if (memcmp((void *) (N_gpg_pstate->magic), (void *) C_MAGIC, sizeof(C_MAGIC)) != 0) {
gpg_install(STATE_ACTIVATE);
gpg_nvm_write((void *) (N_gpg_pstate->magic), (void *) C_MAGIC, sizeof(C_MAGIC));
memset(&G_gpg_vstate, 0, sizeof(gpg_v_state_t));
}
// key conf
G_gpg_vstate.slot = N_gpg_pstate->config_slot[1];
G_gpg_vstate.kslot = (gpg_key_slot_t *) &N_gpg_pstate->keys[G_gpg_vstate.slot];
gpg_mse_reset();
// pin conf
G_gpg_vstate.pinmode = N_gpg_pstate->config_pin[0];
// ux conf
gpg_init_ux();
}
void gpg_init_ux() {
G_gpg_vstate.ux_type = -1;
G_gpg_vstate.ux_key = -1;
G_gpg_vstate.ux_type = -1;
G_gpg_vstate.ux_key = -1;
}
/* ----------------------------------------------------------------------- */
/* --- Install/ReInstall GPGapp --- */
/* ----------------------------------------------------------------------- */
void gpg_install_slot(gpg_key_slot_t *slot) {
unsigned char tmp[4];
unsigned int l;
unsigned char tmp[4];
unsigned int l;
gpg_nvm_write(slot, 0, sizeof(gpg_key_slot_t));
gpg_nvm_write(slot, 0, sizeof(gpg_key_slot_t));
cx_rng(tmp, 4);
gpg_nvm_write((void *)(slot->serial), tmp, 4);
cx_rng(tmp, 4);
gpg_nvm_write((void *) (slot->serial), tmp, 4);
l = sizeof(C_default_AlgoAttr_sig);
gpg_nvm_write((void *)(&slot->sig.attributes.value), (void *)C_default_AlgoAttr_sig, l);
gpg_nvm_write((void *)(&slot->sig.attributes.length), &l, sizeof(unsigned int));
gpg_nvm_write((void *)(&slot->aut.attributes.value), (void *)C_default_AlgoAttr_sig, l);
gpg_nvm_write((void *)(&slot->aut.attributes.length), &l, sizeof(unsigned int));
l = sizeof(C_default_AlgoAttr_sig);
gpg_nvm_write((void *) (&slot->sig.attributes.value), (void *) C_default_AlgoAttr_sig, l);
gpg_nvm_write((void *) (&slot->sig.attributes.length), &l, sizeof(unsigned int));
gpg_nvm_write((void *) (&slot->aut.attributes.value), (void *) C_default_AlgoAttr_sig, l);
gpg_nvm_write((void *) (&slot->aut.attributes.length), &l, sizeof(unsigned int));
l = sizeof(C_default_AlgoAttr_dec);
gpg_nvm_write((void *)(&slot->dec.attributes.value), (void *)C_default_AlgoAttr_dec, l);
gpg_nvm_write((void *)(&slot->dec.attributes.length), &l, sizeof(unsigned int));
l = sizeof(C_default_AlgoAttr_dec);
gpg_nvm_write((void *) (&slot->dec.attributes.value), (void *) C_default_AlgoAttr_dec, l);
gpg_nvm_write((void *) (&slot->dec.attributes.length), &l, sizeof(unsigned int));
tmp[0] = 0x00;
tmp[1] = 0x20;
gpg_nvm_write((void *)(&slot->sig.UIF), &tmp, 2);
gpg_nvm_write((void *)(&slot->dec.UIF), &tmp, 2);
gpg_nvm_write((void *)(&slot->aut.UIF), &tmp, 2);
tmp[0] = 0x00;
tmp[1] = 0x20;
gpg_nvm_write((void *) (&slot->sig.UIF), &tmp, 2);
gpg_nvm_write((void *) (&slot->dec.UIF), &tmp, 2);
gpg_nvm_write((void *) (&slot->aut.UIF), &tmp, 2);
}
void gpg_install(unsigned char app_state) {
gpg_pin_t pin;
// full reset data
gpg_nvm_write((void *)(N_gpg_pstate), NULL, sizeof(gpg_nv_state_t));
// historical bytes
memmove(G_gpg_vstate.work.io_buffer, C_default_Histo, sizeof(C_default_Histo));
G_gpg_vstate.work.io_buffer[7] = app_state;
gpg_nvm_write((void *)(N_gpg_pstate->histo), G_gpg_vstate.work.io_buffer, sizeof(C_default_Histo));
// AID
memmove(G_gpg_vstate.work.io_buffer, C_default_AID, sizeof(C_default_AID));
gpg_nvm_write((void *)(N_gpg_pstate->AID), &G_gpg_vstate.work.io_buffer, sizeof(C_default_AID));
if (app_state == STATE_ACTIVATE) {
// default sex: none
G_gpg_vstate.work.io_buffer[0] = 0x39;
gpg_nvm_write((void *)(&N_gpg_pstate->sex), G_gpg_vstate.work.io_buffer, 1);
// default PW1/PW2: 1 2 3 4 5 6
memmove(pin.value, C_sha256_PW1, sizeof(C_sha256_PW1));
pin.length = 6;
pin.counter = 3;
pin.ref = PIN_ID_PW1;
gpg_nvm_write((void *)(&N_gpg_pstate->PW1), &pin, sizeof(gpg_pin_t));
// default PW3: 1 2 3 4 5 6 7 8
memmove(pin.value, C_sha256_PW2, sizeof(C_sha256_PW2));
pin.length = 8;
pin.counter = 3;
pin.ref = PIN_ID_PW3;
gpg_nvm_write((void *)(&N_gpg_pstate->PW3), &pin, sizeof(gpg_pin_t));
// PWs status
G_gpg_vstate.work.io_buffer[0] = 1;
G_gpg_vstate.work.io_buffer[1] = GPG_MAX_PW_LENGTH;
G_gpg_vstate.work.io_buffer[2] = GPG_MAX_PW_LENGTH;
G_gpg_vstate.work.io_buffer[3] = GPG_MAX_PW_LENGTH;
gpg_nvm_write((void *)(&N_gpg_pstate->PW_status), G_gpg_vstate.work.io_buffer, 4);
// config slot
G_gpg_vstate.work.io_buffer[0] = GPG_KEYS_SLOTS;
G_gpg_vstate.work.io_buffer[1] = 0;
G_gpg_vstate.work.io_buffer[2] = 3; // 3: selection by APDU and screen
gpg_nvm_write((void *)(&N_gpg_pstate->config_slot), G_gpg_vstate.work.io_buffer, 3);
// config rsa pub
G_gpg_vstate.work.io_buffer[0] = (GPG_RSA_DEFAULT_PUB >> 24) & 0xFF;
G_gpg_vstate.work.io_buffer[1] = (GPG_RSA_DEFAULT_PUB >> 16) & 0xFF;
G_gpg_vstate.work.io_buffer[2] = (GPG_RSA_DEFAULT_PUB >> 8) & 0xFF;
G_gpg_vstate.work.io_buffer[3] = (GPG_RSA_DEFAULT_PUB >> 0) & 0xFF;
nvm_write((void *)(&N_gpg_pstate->default_RSA_exponent), G_gpg_vstate.work.io_buffer, 4);
// config pin
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM;
gpg_nvm_write((void *)(&N_gpg_pstate->config_pin), G_gpg_vstate.work.io_buffer, 1);
USBD_CCID_activate_pinpad(3);
// default key template: RSA 2048)
for (int s = 0; s < GPG_KEYS_SLOTS; s++) {
gpg_install_slot((gpg_key_slot_t *)&N_gpg_pstate->keys[s]);
gpg_pin_t pin;
// full reset data
gpg_nvm_write((void *) (N_gpg_pstate), NULL, sizeof(gpg_nv_state_t));
// historical bytes
memmove(G_gpg_vstate.work.io_buffer, C_default_Histo, sizeof(C_default_Histo));
G_gpg_vstate.work.io_buffer[7] = app_state;
gpg_nvm_write((void *) (N_gpg_pstate->histo),
G_gpg_vstate.work.io_buffer,
sizeof(C_default_Histo));
// AID
memmove(G_gpg_vstate.work.io_buffer, C_default_AID, sizeof(C_default_AID));
gpg_nvm_write((void *) (N_gpg_pstate->AID),
&G_gpg_vstate.work.io_buffer,
sizeof(C_default_AID));
if (app_state == STATE_ACTIVATE) {
// default sex: none
G_gpg_vstate.work.io_buffer[0] = 0x39;
gpg_nvm_write((void *) (&N_gpg_pstate->sex), G_gpg_vstate.work.io_buffer, 1);
// default PW1/PW2: 1 2 3 4 5 6
memmove(pin.value, C_sha256_PW1, sizeof(C_sha256_PW1));
pin.length = 6;
pin.counter = 3;
pin.ref = PIN_ID_PW1;
gpg_nvm_write((void *) (&N_gpg_pstate->PW1), &pin, sizeof(gpg_pin_t));
// default PW3: 1 2 3 4 5 6 7 8
memmove(pin.value, C_sha256_PW2, sizeof(C_sha256_PW2));
pin.length = 8;
pin.counter = 3;
pin.ref = PIN_ID_PW3;
gpg_nvm_write((void *) (&N_gpg_pstate->PW3), &pin, sizeof(gpg_pin_t));
// PWs status
G_gpg_vstate.work.io_buffer[0] = 1;
G_gpg_vstate.work.io_buffer[1] = GPG_MAX_PW_LENGTH;
G_gpg_vstate.work.io_buffer[2] = GPG_MAX_PW_LENGTH;
G_gpg_vstate.work.io_buffer[3] = GPG_MAX_PW_LENGTH;
gpg_nvm_write((void *) (&N_gpg_pstate->PW_status), G_gpg_vstate.work.io_buffer, 4);
// config slot
G_gpg_vstate.work.io_buffer[0] = GPG_KEYS_SLOTS;
G_gpg_vstate.work.io_buffer[1] = 0;
G_gpg_vstate.work.io_buffer[2] = 3; // 3: selection by APDU and screen
gpg_nvm_write((void *) (&N_gpg_pstate->config_slot), G_gpg_vstate.work.io_buffer, 3);
// config rsa pub
G_gpg_vstate.work.io_buffer[0] = (GPG_RSA_DEFAULT_PUB >> 24) & 0xFF;
G_gpg_vstate.work.io_buffer[1] = (GPG_RSA_DEFAULT_PUB >> 16) & 0xFF;
G_gpg_vstate.work.io_buffer[2] = (GPG_RSA_DEFAULT_PUB >> 8) & 0xFF;
G_gpg_vstate.work.io_buffer[3] = (GPG_RSA_DEFAULT_PUB >> 0) & 0xFF;
nvm_write((void *) (&N_gpg_pstate->default_RSA_exponent), G_gpg_vstate.work.io_buffer, 4);
// config pin
G_gpg_vstate.work.io_buffer[0] = PIN_MODE_CONFIRM;
gpg_nvm_write((void *) (&N_gpg_pstate->config_pin), G_gpg_vstate.work.io_buffer, 1);
USBD_CCID_activate_pinpad(3);
// default key template: RSA 2048)
for (int s = 0; s < GPG_KEYS_SLOTS; s++) {
gpg_install_slot((gpg_key_slot_t *) &N_gpg_pstate->keys[s]);
}
}
}
}
// TODO: Check if needed
void USBD_CCID_activate_pinpad(int enabled) {
#ifdef HAVE_USB_CLASS_CCID
unsigned short length;
uint8_t * cfgDesc;
unsigned char e;
e = enabled ? 3 : 0;
length = 0;
cfgDesc = USBD_GetCfgDesc_impl(&length);
nvm_write(cfgDesc + (length - 16), &e, 1);
//unsigned short length = 0;
//uint8_t *cfgDesc = NULL;
unsigned char e;
e = enabled ? 3 : 0;
//cfgDesc = USBD_GetCfgDesc_impl(&length);
//nvm_write(cfgDesc + (length - 16), &e, 1);
#else
UNUSED(enabled);
UNUSED(enabled);
#endif
}

@ -30,38 +30,38 @@
/* ----------------------------------------------------------------------- */
void gpg_io_set_offset(unsigned int offset) {
if (offset == IO_OFFSET_END) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_length;
} else if (offset == IO_OFFSET_MARK) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_mark;
} else if (offset < G_gpg_vstate.io_length) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_length;
} else {
THROW(ERROR_IO_OFFSET);
return;
}
if (offset == IO_OFFSET_END) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_length;
} else if (offset == IO_OFFSET_MARK) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_mark;
} else if (offset < G_gpg_vstate.io_length) {
G_gpg_vstate.io_offset = G_gpg_vstate.io_length;
} else {
THROW(ERROR_IO_OFFSET);
return;
}
}
void gpg_io_mark() {
G_gpg_vstate.io_mark = G_gpg_vstate.io_offset;
G_gpg_vstate.io_mark = G_gpg_vstate.io_offset;
}
void gpg_io_inserted(unsigned int len) {
G_gpg_vstate.io_offset += len;
G_gpg_vstate.io_length += len;
G_gpg_vstate.io_offset += len;
G_gpg_vstate.io_length += len;
}
void gpg_io_discard(int clear) {
G_gpg_vstate.io_length = 0;
G_gpg_vstate.io_offset = 0;
G_gpg_vstate.io_mark = 0;
if (clear) {
gpg_io_clear();
}
G_gpg_vstate.io_length = 0;
G_gpg_vstate.io_offset = 0;
G_gpg_vstate.io_mark = 0;
if (clear) {
gpg_io_clear();
}
}
void gpg_io_clear() {
memset(G_gpg_vstate.work.io_buffer, 0, GPG_IO_BUFFER_LENGTH);
memset(G_gpg_vstate.work.io_buffer, 0, GPG_IO_BUFFER_LENGTH);
}
/* ----------------------------------------------------------------------- */
@ -69,72 +69,73 @@ void gpg_io_clear() {
/* ----------------------------------------------------------------------- */
void gpg_io_hole(unsigned int sz) {
if ((G_gpg_vstate.io_length + sz) > GPG_IO_BUFFER_LENGTH) {
THROW(ERROR_IO_FULL);
return;
}
memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + sz,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, G_gpg_vstate.io_length - G_gpg_vstate.io_offset);
G_gpg_vstate.io_length += sz;
if ((G_gpg_vstate.io_length + sz) > GPG_IO_BUFFER_LENGTH) {
THROW(ERROR_IO_FULL);
return;
}
memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + sz,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
G_gpg_vstate.io_length - G_gpg_vstate.io_offset);
G_gpg_vstate.io_length += sz;
}
void gpg_io_insert(unsigned char const *buff, unsigned int len) {
gpg_io_hole(len);
memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, buff, len);
G_gpg_vstate.io_offset += len;
gpg_io_hole(len);
memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, buff, len);
G_gpg_vstate.io_offset += len;
}
void gpg_io_insert_u32(unsigned int v32) {
gpg_io_hole(4);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v32 >> 24;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v32 >> 16;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] = v32 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 3] = v32 >> 0;
G_gpg_vstate.io_offset += 4;
gpg_io_hole(4);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v32 >> 24;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v32 >> 16;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] = v32 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 3] = v32 >> 0;
G_gpg_vstate.io_offset += 4;
}
void gpg_io_insert_u24(unsigned int v24) {
gpg_io_hole(3);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v24 >> 16;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v24 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] = v24 >> 0;
G_gpg_vstate.io_offset += 3;
gpg_io_hole(3);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v24 >> 16;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v24 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] = v24 >> 0;
G_gpg_vstate.io_offset += 3;
}
void gpg_io_insert_u16(unsigned int v16) {
gpg_io_hole(2);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v16 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v16 >> 0;
G_gpg_vstate.io_offset += 2;
gpg_io_hole(2);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v16 >> 8;
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] = v16 >> 0;
G_gpg_vstate.io_offset += 2;
}
void gpg_io_insert_u8(unsigned int v8) {
gpg_io_hole(1);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v8;
G_gpg_vstate.io_offset += 1;
gpg_io_hole(1);
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] = v8;
G_gpg_vstate.io_offset += 1;
}
void gpg_io_insert_t(unsigned int T) {
if (T & 0xFF00) {
gpg_io_insert_u16(T);
} else {
gpg_io_insert_u8(T);
}
if (T & 0xFF00) {
gpg_io_insert_u16(T);
} else {
gpg_io_insert_u8(T);
}
}
void gpg_io_insert_tl(unsigned int T, unsigned int L) {
gpg_io_insert_t(T);
if (L < 128) {
gpg_io_insert_u8(L);
} else if (L < 256) {
gpg_io_insert_u16(0x8100 | L);
} else {
gpg_io_insert_u8(0x82);
gpg_io_insert_u16(L);
}
gpg_io_insert_t(T);
if (L < 128) {
gpg_io_insert_u8(L);
} else if (L < 256) {
gpg_io_insert_u16(0x8100 | L);
} else {
gpg_io_insert_u8(0x82);
gpg_io_insert_u16(L);
}
}
void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) {
gpg_io_insert_tl(T, L);
gpg_io_insert(V, L);
gpg_io_insert_tl(T, L);
gpg_io_insert(V, L);
}
/* ----------------------------------------------------------------------- */
@ -142,87 +143,87 @@ void gpg_io_insert_tlv(unsigned int T, unsigned int L, unsigned char const *V) {
/* ----------------------------------------------------------------------- */
unsigned int gpg_io_fetch_u32() {
unsigned int v32;
v32 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 24) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 16) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 3] << 0));
G_gpg_vstate.io_offset += 4;
return v32;
unsigned int v32;
v32 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 24) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 16) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 3] << 0));
G_gpg_vstate.io_offset += 4;
return v32;
}
unsigned int gpg_io_fetch_u24() {
unsigned int v24;
v24 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 16) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] << 0));
G_gpg_vstate.io_offset += 3;
return v24;
unsigned int v24;
v24 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 16) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2] << 0));
G_gpg_vstate.io_offset += 3;
return v24;
}
unsigned int gpg_io_fetch_u16() {
unsigned int v16;
v16 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 0));
G_gpg_vstate.io_offset += 2;
return v16;
unsigned int v16;
v16 = ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 0] << 8) |
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 0));
G_gpg_vstate.io_offset += 2;
return v16;
}
unsigned int gpg_io_fetch_u8() {
unsigned int v8;
v8 = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
G_gpg_vstate.io_offset += 1;
return v8;
unsigned int v8;
v8 = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
G_gpg_vstate.io_offset += 1;
return v8;
}
int gpg_io_fetch_t(unsigned int *T) {
*T = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
G_gpg_vstate.io_offset++;
if ((*T & 0x1F) == 0x1F) {
*T = (*T << 8) | G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
*T = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
G_gpg_vstate.io_offset++;
}
return 0;
if ((*T & 0x1F) == 0x1F) {
*T = (*T << 8) | G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
G_gpg_vstate.io_offset++;
}
return 0;
}
int gpg_io_fetch_l(unsigned int *L) {
*L = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
if ((*L & 0x80) != 0) {
*L &= 0x7F;
if (*L == 1) {
*L = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1];
G_gpg_vstate.io_offset += 2;
} else if (*L == 2) {
*L = (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 8) |
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2];
G_gpg_vstate.io_offset += 3;
*L = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
if ((*L & 0x80) != 0) {
*L &= 0x7F;
if (*L == 1) {
*L = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1];
G_gpg_vstate.io_offset += 2;
} else if (*L == 2) {
*L = (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 1] << 8) |
G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset + 2];
G_gpg_vstate.io_offset += 3;
} else {
*L = -1;
}
} else {
*L = -1;
G_gpg_vstate.io_offset += 1;
}
} else {
G_gpg_vstate.io_offset += 1;
}
return 0;
return 0;
}
int gpg_io_fetch_tl(unsigned int *T, unsigned int *L) {
gpg_io_fetch_t(T);
gpg_io_fetch_l(L);
return 0;
gpg_io_fetch_t(T);
gpg_io_fetch_l(L);
return 0;
}
int gpg_io_fetch_nv(unsigned char *buffer, int len) {
gpg_nvm_write(buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
G_gpg_vstate.io_offset += len;
return len;
gpg_nvm_write(buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
G_gpg_vstate.io_offset += len;
return len;
}
int gpg_io_fetch(unsigned char *buffer, int len) {
if (buffer) {
memmove(buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
}
G_gpg_vstate.io_offset += len;
return len;
if (buffer) {
memmove(buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
}
G_gpg_vstate.io_offset += len;
return len;
}
/* ----------------------------------------------------------------------- */
@ -232,123 +233,128 @@ int gpg_io_fetch(unsigned char *buffer, int len) {
#define MAX_OUT GPG_APDU_LENGTH
int gpg_io_do(unsigned int io_flags) {
unsigned int rx = 0;
// if pending input chaining
if (G_gpg_vstate.io_cla & 0x10) {
goto in_chaining;
}
if (io_flags & IO_ASYNCH_REPLY) {
// if IO_ASYNCH_REPLY has been set,
// gpg_io_exchange will return when IO_RETURN_AFTER_TX will set in ui
rx = gpg_io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, 0);
} else {
// --- full out chaining ---
G_gpg_vstate.io_offset = 0;
while (G_gpg_vstate.io_length > MAX_OUT) {
unsigned int tx, xx;
// send chunk
tx = MAX_OUT - 2;
memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, tx);
G_gpg_vstate.io_length -= tx;
G_gpg_vstate.io_offset += tx;
G_io_apdu_buffer[tx] = 0x61;
if (G_gpg_vstate.io_length > MAX_OUT - 2) {
xx = MAX_OUT - 2;
} else {
xx = G_gpg_vstate.io_length - 2;
}
G_io_apdu_buffer[tx + 1] = xx;
rx = gpg_io_exchange(CHANNEL_APDU, tx + 2);
// check get response
if ((G_io_apdu_buffer[0] != 0x00) || (G_io_apdu_buffer[1] != 0xc0) || (G_io_apdu_buffer[2] != 0x00) ||
(G_io_apdu_buffer[3] != 0x00)) {
THROW(SW_COMMAND_NOT_ALLOWED);
return 0;
}
unsigned int rx = 0;
// if pending input chaining
if (G_gpg_vstate.io_cla & 0x10) {
goto in_chaining;
}
memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, G_gpg_vstate.io_length);
if (io_flags & IO_RETURN_AFTER_TX) {
rx = gpg_io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_gpg_vstate.io_length);
return 0;
if (io_flags & IO_ASYNCH_REPLY) {
// if IO_ASYNCH_REPLY has been set,
// gpg_io_exchange will return when IO_RETURN_AFTER_TX will set in ui
rx = gpg_io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, 0);
} else {
rx = gpg_io_exchange(CHANNEL_APDU, G_gpg_vstate.io_length);
}
}
//--- full in chaining ---
if (rx < 4) {
THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED;
}
if (rx == 4) {
G_io_apdu_buffer[4] = 0;
rx = 4;
}
G_gpg_vstate.io_offset = 0;
G_gpg_vstate.io_length = 0;
G_gpg_vstate.io_cla = G_io_apdu_buffer[0];
G_gpg_vstate.io_ins = G_io_apdu_buffer[1];
G_gpg_vstate.io_p1 = G_io_apdu_buffer[2];
G_gpg_vstate.io_p2 = G_io_apdu_buffer[3];
G_gpg_vstate.io_lc = 0;
G_gpg_vstate.io_le = 0;
switch (G_gpg_vstate.io_ins) {
case INS_GET_DATA:
case INS_GET_RESPONSE:
case INS_TERMINATE_DF:
case INS_ACTIVATE_FILE:
G_gpg_vstate.io_le = G_io_apdu_buffer[4];
break;
case INS_GET_CHALLENGE:
if (G_gpg_vstate.io_p1 == 0) {
G_gpg_vstate.io_le = G_io_apdu_buffer[4];
break;
// --- full out chaining ---
G_gpg_vstate.io_offset = 0;
while (G_gpg_vstate.io_length > MAX_OUT) {
unsigned int tx, xx;
// send chunk
tx = MAX_OUT - 2;
memmove(G_io_apdu_buffer, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, tx);
G_gpg_vstate.io_length -= tx;
G_gpg_vstate.io_offset += tx;
G_io_apdu_buffer[tx] = 0x61;
if (G_gpg_vstate.io_length > MAX_OUT - 2) {
xx = MAX_OUT - 2;
} else {
xx = G_gpg_vstate.io_length - 2;
}
G_io_apdu_buffer[tx + 1] = xx;
rx = gpg_io_exchange(CHANNEL_APDU, tx + 2);
// check get response
if ((G_io_apdu_buffer[0] != 0x00) || (G_io_apdu_buffer[1] != 0xc0) ||
(G_io_apdu_buffer[2] != 0x00) || (G_io_apdu_buffer[3] != 0x00)) {
THROW(SW_COMMAND_NOT_ALLOWED);
return 0;
}
}
memmove(G_io_apdu_buffer,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
G_gpg_vstate.io_length);
if (io_flags & IO_RETURN_AFTER_TX) {
rx = gpg_io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_gpg_vstate.io_length);
return 0;
} else {
rx = gpg_io_exchange(CHANNEL_APDU, G_gpg_vstate.io_length);
}
}
__attribute__((fallthrough));
case INS_VERIFY:
case INS_CHANGE_REFERENCE_DATA:
if (G_io_apdu_buffer[4] == 0) {
break;
}
goto _default;
default:
_default:
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer + 5, G_gpg_vstate.io_lc);
G_gpg_vstate.io_length = G_gpg_vstate.io_lc;
break;
}
while (G_gpg_vstate.io_cla & 0x10) {
G_io_apdu_buffer[0] = 0x90;
G_io_apdu_buffer[1] = 0x00;
rx = gpg_io_exchange(CHANNEL_APDU, 2);
in_chaining:
if ((rx < 4) || ((G_io_apdu_buffer[0] & 0xEF) != (G_gpg_vstate.io_cla & 0xEF)) ||
(G_io_apdu_buffer[1] != G_gpg_vstate.io_ins) || (G_io_apdu_buffer[2] != G_gpg_vstate.io_p1) ||
(G_io_apdu_buffer[3] != G_gpg_vstate.io_p2)) {
THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED;
//--- full in chaining ---
if (rx < 4) {
THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED;
}
if (rx == 4) {
G_io_apdu_buffer[4] = 0;
rx = 4;
G_io_apdu_buffer[4] = 0;
rx = 4;
}
G_gpg_vstate.io_offset = 0;
G_gpg_vstate.io_length = 0;
G_gpg_vstate.io_cla = G_io_apdu_buffer[0];
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
if ((G_gpg_vstate.io_length + G_gpg_vstate.io_lc) > GPG_IO_BUFFER_LENGTH) {
return 1;
G_gpg_vstate.io_ins = G_io_apdu_buffer[1];
G_gpg_vstate.io_p1 = G_io_apdu_buffer[2];
G_gpg_vstate.io_p2 = G_io_apdu_buffer[3];
G_gpg_vstate.io_lc = 0;
G_gpg_vstate.io_le = 0;
switch (G_gpg_vstate.io_ins) {
case INS_GET_DATA:
case INS_GET_RESPONSE:
case INS_TERMINATE_DF:
case INS_ACTIVATE_FILE:
G_gpg_vstate.io_le = G_io_apdu_buffer[4];
break;
case INS_GET_CHALLENGE:
if (G_gpg_vstate.io_p1 == 0) {
G_gpg_vstate.io_le = G_io_apdu_buffer[4];
break;
}
__attribute__((fallthrough));
case INS_VERIFY:
case INS_CHANGE_REFERENCE_DATA:
if (G_io_apdu_buffer[4] == 0) {
break;
}
goto _default;
default:
_default:
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
memmove(G_gpg_vstate.work.io_buffer, G_io_apdu_buffer + 5, G_gpg_vstate.io_lc);
G_gpg_vstate.io_length = G_gpg_vstate.io_lc;
break;
}
while (G_gpg_vstate.io_cla & 0x10) {
G_io_apdu_buffer[0] = 0x90;
G_io_apdu_buffer[1] = 0x00;
rx = gpg_io_exchange(CHANNEL_APDU, 2);
in_chaining:
if ((rx < 4) || ((G_io_apdu_buffer[0] & 0xEF) != (G_gpg_vstate.io_cla & 0xEF)) ||
(G_io_apdu_buffer[1] != G_gpg_vstate.io_ins) ||
(G_io_apdu_buffer[2] != G_gpg_vstate.io_p1) ||
(G_io_apdu_buffer[3] != G_gpg_vstate.io_p2)) {
THROW(SW_COMMAND_NOT_ALLOWED);
return SW_COMMAND_NOT_ALLOWED;
}
if (rx == 4) {
G_io_apdu_buffer[4] = 0;
rx = 4;
}
G_gpg_vstate.io_cla = G_io_apdu_buffer[0];
G_gpg_vstate.io_lc = G_io_apdu_buffer[4];
if ((G_gpg_vstate.io_length + G_gpg_vstate.io_lc) > GPG_IO_BUFFER_LENGTH) {
return 1;
}
memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_length,
G_io_apdu_buffer + 5,
G_gpg_vstate.io_lc);
G_gpg_vstate.io_length += G_gpg_vstate.io_lc;
}
memmove(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_length, G_io_apdu_buffer + 5, G_gpg_vstate.io_lc);
G_gpg_vstate.io_length += G_gpg_vstate.io_lc;
}
return 0;
return 0;
}

@ -22,7 +22,6 @@
#include "gpg_vars.h"
#include "gpg_ux_nanos.h"
//#include "gpg_ux_blue.h"
#include "os_io_seproxyhal.h"
#include "string.h"
@ -33,161 +32,161 @@
/* ----------------------------------------------------------------------- */
void gpg_main(void) {
unsigned int io_flags;
io_flags = 0;
for (;;) {
volatile unsigned short sw = 0;
BEGIN_TRY {
TRY {
gpg_io_do(io_flags);
sw = gpg_dispatch();
}
CATCH_OTHER(e) {
gpg_io_discard(1);
if ((e & 0xFFFF0000) || (((e & 0xF000) != 0x6000) && ((e & 0xF000) != 0x9000))) {
gpg_io_insert_u32(e);
sw = 0x6f42;
} else {
sw = e;
unsigned int io_flags;
io_flags = 0;
for (;;) {
volatile unsigned short sw = 0;
BEGIN_TRY {
TRY {
gpg_io_do(io_flags);
sw = gpg_dispatch();
}
CATCH_OTHER(e) {
gpg_io_discard(1);
if ((e & 0xFFFF0000) || (((e & 0xF000) != 0x6000) && ((e & 0xF000) != 0x9000))) {
gpg_io_insert_u32(e);
sw = 0x6f42;
} else {
sw = e;
}
}
FINALLY {
if (sw) {
gpg_io_insert_u16(sw);
io_flags = 0;
} else {
io_flags = IO_ASYNCH_REPLY;
}
}
}
}
FINALLY {
if (sw) {
gpg_io_insert_u16(sw);
io_flags = 0;
} else {
io_flags = IO_ASYNCH_REPLY;
}
}
END_TRY;
}
END_TRY;
}
}
unsigned char io_event(unsigned char channel) {
UNUSED(channel);
// nothing done with the event, throw an error on the transport layer if
// needed
// can't have more than one tag in the reply, not supported yet.
switch (G_io_seproxyhal_spi_buffer[0]) {
case SEPROXYHAL_TAG_FINGER_EVENT:
UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
break;
// power off if long push, else pass to the application callback if any
case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: // for Nano S
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
break;
// other events are propagated to the UX just in case
default:
UX_DEFAULT_EVENT();
break;
case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
UX_DISPLAYED_EVENT({});
break;
case SEPROXYHAL_TAG_TICKER_EVENT:
UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {
// only allow display when not locked of overlayed by an OS UX.
if (UX_ALLOWED) {
UX_REDISPLAY();
}
});
break;
}
// close the event if not done previously (by a display or whatever)
if (!io_seproxyhal_spi_is_status_sent()) {
io_seproxyhal_general_status();
}
// command has been processed, DO NOT reset the current APDU transport
return 1;
UNUSED(channel);
// nothing done with the event, throw an error on the transport layer if
// needed
// can't have more than one tag in the reply, not supported yet.
switch (G_io_seproxyhal_spi_buffer[0]) {
case SEPROXYHAL_TAG_FINGER_EVENT:
UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
break;
// power off if long push, else pass to the application callback if any
case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: // for Nano S
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
break;
// other events are propagated to the UX just in case
default:
UX_DEFAULT_EVENT();
break;
case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
UX_DISPLAYED_EVENT({});
break;
case SEPROXYHAL_TAG_TICKER_EVENT:
UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {
// only allow display when not locked of overlaid by an OS UX.
if (UX_ALLOWED) {
UX_REDISPLAY();
}
});
break;
}
// close the event if not done previously (by a display or whatever)
if (!io_seproxyhal_spi_is_status_sent()) {
io_seproxyhal_general_status();
}
// command has been processed, DO NOT reset the current APDU transport
return 1;
}
unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
switch (channel & ~(IO_FLAGS)) {
case CHANNEL_KEYBOARD:
break;
// multiplexed io exchange over a SPI channel and TLV encapsulated protocol
case CHANNEL_SPI:
if (tx_len) {
io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
if (channel & IO_RESET_AFTER_REPLIED) {
reset();
}
return 0; // nothing received from the master so far (it's a tx
// transaction)
} else {
return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
switch (channel & ~(IO_FLAGS)) {
case CHANNEL_KEYBOARD:
break;
// multiplexed io exchange over a SPI channel and TLV encapsulated protocol
case CHANNEL_SPI:
if (tx_len) {
io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
if (channel & IO_RESET_AFTER_REPLIED) {
reset();
}
return 0; // nothing received from the master so far (it's a tx
// transaction)
} else {
return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
}
default:
THROW(INVALID_PARAMETER);
return 0;
}
default:
THROW(INVALID_PARAMETER);
return 0;
}
return 0;
}
void app_exit(void) {
BEGIN_TRY_L(exit) {
TRY_L(exit) {
os_sched_exit(-1);
}
FINALLY_L(exit) {
BEGIN_TRY_L(exit) {
TRY_L(exit) {
os_sched_exit(-1);
}
FINALLY_L(exit) {
}
}
}
END_TRY_L(exit);
END_TRY_L(exit);
}
/* -------------------------------------------------------------- */
__attribute__((section(".boot"))) int main(void) {
// exit critical section
__asm volatile("cpsie i");
// exit critical section
__asm volatile("cpsie i");
// ensure exception will work as planned
os_boot();
for (;;) {
UX_INIT();
// ensure exception will work as planned
os_boot();
for (;;) {
UX_INIT();
BEGIN_TRY {
TRY {
// start communication with MCU
io_seproxyhal_init();
BEGIN_TRY {
TRY {
// start communication with MCU
io_seproxyhal_init();
USB_power(1);
USB_power(1);
#if HAVE_USB_CLASS_CCID
io_usb_ccid_set_card_inserted(1);
io_usb_ccid_set_card_inserted(1);
#endif
// set up
gpg_init();
// set up initial screen
ui_init();
// start the application
// the first exchange will:
// - display the initial screen
// - send the ATR
// - receive the first command
gpg_main();
}
CATCH(EXCEPTION_IO_RESET) {
// reset IO and UX
continue;
}
CATCH_ALL {
break;
}
FINALLY {
}
// set up
gpg_init();
// set up initial screen
ui_init();
// start the application
// the first exchange will:
// - display the initial screen
// - send the ATR
// - receive the first command
gpg_main();
}
CATCH(EXCEPTION_IO_RESET) {
// reset IO and UX
continue;
}
CATCH_ALL {
break;
}
FINALLY {
}
}
END_TRY;
}
END_TRY;
}
app_exit();
app_exit();
}
#endif

@ -20,53 +20,54 @@
#include "gpg_vars.h"
static int gpg_mse_set(int crt, int ref) {
if (crt == 0xA4) {
if (ref == 0x02) {
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->dec;
if (crt == 0xA4) {
if (ref == 0x02) {
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->dec;
}
if (ref == 0x03) {
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->aut;
}
}
if (ref == 0x03) {
G_gpg_vstate.mse_aut = &G_gpg_vstate.kslot->aut;
}
}
if (crt == 0xB8) {
if (ref == 0x02) {
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->dec;
}
if (ref == 0x03) {
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->aut;
if (crt == 0xB8) {
if (ref == 0x02) {
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->dec;
}
if (ref == 0x03) {
G_gpg_vstate.mse_dec = &G_gpg_vstate.kslot->aut;
}
}
}
return 0;
return 0;
}
int gpg_mse_reset() {
gpg_mse_set(0xA4, 0x03);
gpg_mse_set(0xB8, 0x02);
return 0;
gpg_mse_set(0xA4, 0x03);
gpg_mse_set(0xB8, 0x02);
return 0;
}
int gpg_apdu_mse() {
int crt, ref;
int crt, ref;
if ((G_gpg_vstate.io_p1 != 0x41) || ((G_gpg_vstate.io_p2 != 0xA4) && (G_gpg_vstate.io_p2 != 0xB8))) {
THROW(SW_INCORRECT_P1P2);
return SW_INCORRECT_P1P2;
}
if ((G_gpg_vstate.io_p1 != 0x41) ||
((G_gpg_vstate.io_p2 != 0xA4) && (G_gpg_vstate.io_p2 != 0xB8))) {
THROW(SW_INCORRECT_P1P2);
return SW_INCORRECT_P1P2;
}
crt = gpg_io_fetch_u16();
if (crt != 0x8301) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
crt = gpg_io_fetch_u16();
if (crt != 0x8301) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
ref = gpg_io_fetch_u8();
if ((ref != 0x02) && (ref != 0x03)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
ref = gpg_io_fetch_u8();
if ((ref != 0x02) && (ref != 0x03)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_mse_set(crt, ref);
gpg_io_discard(1);
return SW_OK;
}
gpg_mse_set(crt, ref);
gpg_io_discard(1);
return SW_OK;
}

@ -22,257 +22,266 @@
#include "gpg_ux_nanos.h"
gpg_pin_t *gpg_pin_get_pin(int pinref) {
switch (pinref) {
case PIN_ID_PW1:
case PIN_ID_PW2:
return (gpg_pin_t *)&N_gpg_pstate->PW1;
case PIN_ID_PW3:
return (gpg_pin_t *)&N_gpg_pstate->PW3;
case PIN_ID_RC:
return (gpg_pin_t *)&N_gpg_pstate->RC;
}
return NULL;
switch (pinref) {
case PIN_ID_PW1:
case PIN_ID_PW2:
return (gpg_pin_t *) &N_gpg_pstate->PW1;
case PIN_ID_PW3:
return (gpg_pin_t *) &N_gpg_pstate->PW3;
case PIN_ID_RC:
return (gpg_pin_t *) &N_gpg_pstate->RC;
}
return NULL;
}
static int gpg_pin_get_state_index(unsigned int pinref) {
switch (pinref) {
case PIN_ID_PW1:
return 1;
case PIN_ID_PW2:
return 2;
case PIN_ID_PW3:
return 3;
case PIN_ID_RC:
return 4;
}
return -1;
switch (pinref) {
case PIN_ID_PW1:
return 1;
case PIN_ID_PW2:
return 2;
case PIN_ID_PW3:
return 3;
case PIN_ID_RC:
return 4;
}
return -1;
}
static int gpg_pin_check_internal(gpg_pin_t *pin, unsigned char *pin_val, int pin_len) {
unsigned int counter;
if (pin->counter == 0) {
return SW_PIN_BLOCKED;
}
counter = pin->counter - 1;
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *)&G_gpg_vstate.work.md.sha256, CX_LAST, pin_val, pin_len, G_gpg_vstate.work.md.H,
sizeof(G_gpg_vstate.work.md.H));
if (memcmp(G_gpg_vstate.work.md.H, pin->value, 32)) {
return SW_SECURITY_STATUS_NOT_SATISFIED;
}
counter = 3;
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
return SW_OK;
unsigned int counter;
if (pin->counter == 0) {
return SW_PIN_BLOCKED;
}
counter = pin->counter - 1;
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
cx_sha256_init(&G_gpg_vstate.work.md.sha256);
cx_hash((cx_hash_t *) &G_gpg_vstate.work.md.sha256,
CX_LAST,
pin_val,
pin_len,
G_gpg_vstate.work.md.H,
sizeof(G_gpg_vstate.work.md.H));
if (memcmp(G_gpg_vstate.work.md.H, pin->value, 32)) {
return SW_SECURITY_STATUS_NOT_SATISFIED;
}
counter = 3;
gpg_nvm_write(&(pin->counter), &counter, sizeof(int));
return SW_OK;
}
static void gpg_pin_check_throw(gpg_pin_t *pin, int pinID, unsigned char *pin_val, int pin_len) {
int sw;
gpg_pin_set_verified(pinID, 0);
sw = gpg_pin_check_internal(pin, pin_val, pin_len);
if (sw == SW_OK) {
gpg_pin_set_verified(pinID, 1);
int sw;
gpg_pin_set_verified(pinID, 0);
sw = gpg_pin_check_internal(pin, pin_val, pin_len);
if (sw == SW_OK) {
gpg_pin_set_verified(pinID, 1);
return;
}
THROW(sw);
return;
}
THROW(sw);
return;
}
int gpg_pin_check(gpg_pin_t *pin, int pinID, unsigned char *pin_val, unsigned int pin_len) {
int sw;
gpg_pin_set_verified(pinID, 0);
sw = gpg_pin_check_internal(pin, pin_val, pin_len);
if (sw == SW_OK) {
gpg_pin_set_verified(pinID, 1);
}
return sw;
int sw;
gpg_pin_set_verified(pinID, 0);
sw = gpg_pin_check_internal(pin, pin_val, pin_len);
if (sw == SW_OK) {
gpg_pin_set_verified(pinID, 1);
}
return sw;
}
void gpg_pin_set(gpg_pin_t *pin, unsigned char *pin_val, unsigned int pin_len) {
cx_sha256_t sha256;
cx_sha256_t sha256;
gpg_pin_t newpin;
gpg_pin_t newpin;
cx_sha256_init(&sha256);
cx_hash((cx_hash_t *)&sha256, CX_LAST, pin_val, pin_len, newpin.value, 32);
newpin.length = pin_len;
newpin.counter = 3;
cx_sha256_init(&sha256);
cx_hash((cx_hash_t *) &sha256, CX_LAST, pin_val, pin_len, newpin.value, 32);
newpin.length = pin_len;
newpin.counter = 3;
gpg_nvm_write(pin, &newpin, sizeof(gpg_pin_t));
gpg_nvm_write(pin, &newpin, sizeof(gpg_pin_t));
}
int gpg_pin_set_verified(int pinID, int verified) {
int idx;
idx = gpg_pin_get_state_index(pinID);
if (idx >= 0) {
G_gpg_vstate.verified_pin[idx] = verified;
return verified;
}
return 0;
int idx;
idx = gpg_pin_get_state_index(pinID);
if (idx >= 0) {
G_gpg_vstate.verified_pin[idx] = verified;
return verified;
}
return 0;
}
int gpg_pin_is_verified(int pinID) {
int idx;
idx = gpg_pin_get_state_index(pinID);
if (idx >= 0) {
return G_gpg_vstate.verified_pin[idx];
}
return 0;
int idx;
idx = gpg_pin_get_state_index(pinID);
if (idx >= 0) {
return G_gpg_vstate.verified_pin[idx];
}
return 0;
}
int gpg_pin_is_blocked(gpg_pin_t *pin) {
return pin->counter == 0;
return pin->counter == 0;
}
int gpg_apdu_verify() {
gpg_pin_t *pin;
gpg_pin_t *pin;
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
if (pin == NULL) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
// PINPAD
if (G_gpg_vstate.io_cla == 0xEF) {
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
if (pin == NULL) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
if (G_gpg_vstate.pinmode == PIN_MODE_SCREEN) {
// Delegate pin check to ui
gpg_io_discard(1);
ui_menu_pinentry_display(0);
return 0;
// PINPAD
if (G_gpg_vstate.io_cla == 0xEF) {
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
}
if (G_gpg_vstate.pinmode == PIN_MODE_SCREEN) {
// Delegate pin check to ui
gpg_io_discard(1);
ui_menu_pinentry_display(0);
return 0;
}
if (G_gpg_vstate.pinmode == PIN_MODE_CONFIRM) {
// Delegate pin check to ui
gpg_io_discard(1);
ui_menu_pinconfirm_display(0);
return 0;
}
if (G_gpg_vstate.pinmode == PIN_MODE_TRUST) {
gpg_pin_set_verified(G_gpg_vstate.io_p2, 1);
gpg_io_discard(1);
return SW_OK;
}
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
if (G_gpg_vstate.pinmode == PIN_MODE_CONFIRM) {
// Delegate pin check to ui
gpg_io_discard(1);
ui_menu_pinconfirm_display(0);
return 0;
}
if (G_gpg_vstate.pinmode == PIN_MODE_TRUST) {
gpg_pin_set_verified(G_gpg_vstate.io_p2, 1);
gpg_io_discard(1);
return SW_OK;
}
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
// NORMAL CHECK
if ((G_gpg_vstate.io_p1 == 0) && G_gpg_vstate.io_length) {
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
// NORMAL CHECK
if ((G_gpg_vstate.io_p1 == 0) && G_gpg_vstate.io_length) {
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
}
gpg_pin_check_throw(pin,
G_gpg_vstate.io_p2,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
G_gpg_vstate.io_length);
gpg_io_discard(1);
return SW_OK;
}
gpg_pin_check_throw(pin, G_gpg_vstate.io_p2, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
G_gpg_vstate.io_length);
gpg_io_discard(1);
return SW_OK;
}
gpg_io_discard(1);
gpg_io_discard(1);
// STATUS REQUEST
if ((G_gpg_vstate.io_p1 == 0) && G_gpg_vstate.io_length == 0) {
if (gpg_pin_is_verified(G_gpg_vstate.io_p2)) {
return SW_OK;
// STATUS REQUEST
if ((G_gpg_vstate.io_p1 == 0) && G_gpg_vstate.io_length == 0) {
if (gpg_pin_is_verified(G_gpg_vstate.io_p2)) {
return SW_OK;
}
return 0x63C0 | pin->counter;
}
return 0x63C0 | pin->counter;
}
// RESET REQUEST
if ((G_gpg_vstate.io_p1 == 0xFF) && G_gpg_vstate.io_length == 0) {
gpg_pin_set_verified(G_gpg_vstate.io_p2, 0);
return SW_OK;
}
// RESET REQUEST
if ((G_gpg_vstate.io_p1 == 0xFF) && G_gpg_vstate.io_length == 0) {
gpg_pin_set_verified(G_gpg_vstate.io_p2, 0);
return SW_OK;
}
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
int gpg_apdu_change_ref_data() {
gpg_pin_t *pin;
int len, newlen;
gpg_pin_t *pin;
int len, newlen;
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
if (pin == NULL) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_pin_set_verified(pin->ref, 0);
// --- PW1/PW3 pin ---
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
}
// avoid any-overflow whitout giving info
if (G_gpg_vstate.io_length == 0) {
if (G_gpg_vstate.pinmode != PIN_MODE_HOST) {
// Delegate pin change to ui
gpg_io_discard(1);
ui_menu_pinentry_display(0);
return 0;
pin = gpg_pin_get_pin(G_gpg_vstate.io_p2);
if (pin == NULL) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
}
if (pin->length > G_gpg_vstate.io_length) {
len = G_gpg_vstate.io_length;
} else {
len = pin->length;
}
gpg_pin_check_throw(pin, pin->ref, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
gpg_pin_set_verified(pin->ref, 0);
newlen = G_gpg_vstate.io_length - len;
if ((newlen > GPG_MAX_PW_LENGTH) || ((pin->ref == PIN_ID_PW1) && (newlen < 6)) ||
((pin->ref == PIN_ID_PW3) && (newlen < 8))) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_pin_set(pin, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + len, newlen);
gpg_io_discard(1);
return SW_OK;
}
// --- PW1/PW3 pin ---
if (gpg_pin_is_blocked(pin)) {
THROW(SW_PIN_BLOCKED);
return SW_PIN_BLOCKED;
}
// avoid any-overflow without giving info
if (G_gpg_vstate.io_length == 0) {
if (G_gpg_vstate.pinmode != PIN_MODE_HOST) {
// Delegate pin change to ui
gpg_io_discard(1);
ui_menu_pinentry_display(0);
return 0;
}
}
int gpg_apdu_reset_retry_counter() {
gpg_pin_t *pin_pw1;
gpg_pin_t *pin_rc;
int rc_len, pw1_len;
if (pin->length > G_gpg_vstate.io_length) {
len = G_gpg_vstate.io_length;
} else {
len = pin->length;
}
pin_pw1 = gpg_pin_get_pin(PIN_ID_PW1);
pin_rc = gpg_pin_get_pin(PIN_ID_RC);
gpg_pin_check_throw(pin, pin->ref, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, len);
if (G_gpg_vstate.io_p1 == 2) {
if (!gpg_pin_is_verified(PIN_ID_PW3)) {
THROW(SW_SECURITY_STATUS_NOT_SATISFIED);
return SW_SECURITY_STATUS_NOT_SATISFIED;
newlen = G_gpg_vstate.io_length - len;
if ((newlen > GPG_MAX_PW_LENGTH) || ((pin->ref == PIN_ID_PW1) && (newlen < 6)) ||
((pin->ref == PIN_ID_PW3) && (newlen < 8))) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
rc_len = 0;
pw1_len = G_gpg_vstate.io_length;
} else {
// avoid any-overflow whitout giving info
if (pin_rc->length > G_gpg_vstate.io_length) {
rc_len = G_gpg_vstate.io_length;
gpg_pin_set(pin, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + len, newlen);
gpg_io_discard(1);
return SW_OK;
}
int gpg_apdu_reset_retry_counter() {
gpg_pin_t *pin_pw1;
gpg_pin_t *pin_rc;
int rc_len, pw1_len;
pin_pw1 = gpg_pin_get_pin(PIN_ID_PW1);
pin_rc = gpg_pin_get_pin(PIN_ID_RC);
if (G_gpg_vstate.io_p1 == 2) {
if (!gpg_pin_is_verified(PIN_ID_PW3)) {
THROW(SW_SECURITY_STATUS_NOT_SATISFIED);
return SW_SECURITY_STATUS_NOT_SATISFIED;
}
rc_len = 0;
pw1_len = G_gpg_vstate.io_length;
} else {
rc_len = pin_rc->length;
// avoid any-overflow without giving info
if (pin_rc->length > G_gpg_vstate.io_length) {
rc_len = G_gpg_vstate.io_length;
} else {
rc_len = pin_rc->length;
}
pw1_len = G_gpg_vstate.io_length - rc_len;
gpg_pin_check_throw(pin_rc,
pin_rc->ref,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
rc_len);
}
pw1_len = G_gpg_vstate.io_length - rc_len;
gpg_pin_check_throw(pin_rc, pin_rc->ref, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, rc_len);
}
if ((pw1_len > GPG_MAX_PW_LENGTH) || (pw1_len < 6)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_pin_set(pin_pw1, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + rc_len, pw1_len);
gpg_io_discard(1);
return SW_OK;
if ((pw1_len > GPG_MAX_PW_LENGTH) || (pw1_len < 6)) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_pin_set(pin_pw1, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset + rc_len, pw1_len);
gpg_io_discard(1);
return SW_OK;
}

@ -20,316 +20,401 @@
#include "gpg_vars.h"
#include "gpg_ux_nanos.h"
const unsigned char gpg_oid_sha256[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
const unsigned char gpg_oid_sha512[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
const unsigned char gpg_oid_sha256[] = {0x30,
0x31,
0x30,
0x0d,
0x06,
0x09,
0x60,
0x86,
0x48,
0x01,
0x65,
0x03,
0x04,
0x02,
0x01,
0x05,
0x00,
0x04,
0x20};
const unsigned char gpg_oid_sha512[] = {0x30,
0x51,
0x30,
0x0d,
0x06,
0x09,
0x60,
0x86,
0x48,
0x01,
0x65,
0x03,
0x04,
0x02,
0x03,
0x05,
0x00,
0x04,
0x40};
static void gpg_pso_reset_PW1() {
if (N_gpg_pstate->PW_status[0] == 0) {
gpg_pin_set_verified(PIN_ID_PW1, 0);
}
if (N_gpg_pstate->PW_status[0] == 0) {
gpg_pin_set_verified(PIN_ID_PW1, 0);
}
}
static int gpg_sign(gpg_key_t *sigkey) {
// --- RSA
if (sigkey->attributes.value[0] == 1) {
cx_rsa_private_key_t *key;
unsigned int ksz, l;
ksz = (sigkey->attributes.value[1] << 8) | sigkey->attributes.value[2];
ksz = ksz >> 3;
switch (ksz) {
case 1024 / 8:
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa1024;
break;
case 2048 / 8:
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa2048;
break;
case 3072 / 8:
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa3072;
break;
case 4096 / 8:
key = (cx_rsa_private_key_t *)&sigkey->priv_key.rsa4096;
break;
}
if (key->size != ksz) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
// --- RSA
if (sigkey->attributes.value[0] == 1) {
cx_rsa_private_key_t *key;
unsigned int ksz, l;
ksz = (sigkey->attributes.value[1] << 8) | sigkey->attributes.value[2];
ksz = ksz >> 3;
switch (ksz) {
case 1024 / 8:
key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa1024;
break;
case 2048 / 8:
key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa2048;
break;
case 3072 / 8:
key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa3072;
break;
case 4096 / 8:
key = (cx_rsa_private_key_t *) &sigkey->priv_key.rsa4096;
break;
}
if (key->size != ksz) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
// sign
if (ksz < G_gpg_vstate.io_length) {
THROW(SW_WRONG_LENGTH);
// sign
if (ksz < G_gpg_vstate.io_length) {
THROW(SW_WRONG_LENGTH);
}
l = ksz - G_gpg_vstate.io_length;
memmove(G_gpg_vstate.work.io_buffer + l,
G_gpg_vstate.work.io_buffer,
G_gpg_vstate.io_length);
memset(G_gpg_vstate.work.io_buffer, 0xFF, l);
G_gpg_vstate.work.io_buffer[0] = 0;
G_gpg_vstate.work.io_buffer[1] = 1;
G_gpg_vstate.work.io_buffer[l - 1] = 0;
ksz = cx_rsa_decrypt(key,
CX_PAD_NONE,
CX_NONE,
G_gpg_vstate.work.io_buffer,
ksz,
G_gpg_vstate.work.io_buffer,
ksz);
// send
gpg_io_discard(0);
gpg_io_inserted(ksz);
gpg_pso_reset_PW1();
return SW_OK;
}
l = ksz - G_gpg_vstate.io_length;
memmove(G_gpg_vstate.work.io_buffer + l, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
memset(G_gpg_vstate.work.io_buffer, 0xFF, l);
G_gpg_vstate.work.io_buffer[0] = 0;
G_gpg_vstate.work.io_buffer[1] = 1;
G_gpg_vstate.work.io_buffer[l - 1] = 0;
ksz = cx_rsa_decrypt(key, CX_PAD_NONE, CX_NONE, G_gpg_vstate.work.io_buffer, ksz, G_gpg_vstate.work.io_buffer, ksz);
// send
gpg_io_discard(0);
gpg_io_inserted(ksz);
gpg_pso_reset_PW1();
return SW_OK;
}
// --- ECDSA/EdDSA
if ((sigkey->attributes.value[0] == 19) || (sigkey->attributes.value[0] == 22)) {
cx_ecfp_private_key_t *key;
unsigned int sz, i, rs_len, info;
unsigned char * rs;
// --- ECDSA/EdDSA
if ((sigkey->attributes.value[0] == 19) || (sigkey->attributes.value[0] == 22)) {
cx_ecfp_private_key_t *key;
unsigned int sz, i, rs_len, info;
unsigned char *rs;
key = &sigkey->priv_key.ecfp;
key = &sigkey->priv_key.ecfp;
// sign
#define RS (G_gpg_vstate.work.io_buffer + (GPG_IO_BUFFER_LENGTH - 256))
if (sigkey->attributes.value[0] == 19) {
sz = (unsigned int) gpg_curve2domainlen(key->curve);
if ((sz == 0) || (key->d_len != sz)) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
sz = cx_ecdsa_sign(key, CX_RND_TRNG, CX_NONE, G_gpg_vstate.work.io_buffer, sz, RS, 256, &info);
// reencode r,s in MPI format
gpg_io_discard(0);
if (sigkey->attributes.value[0] == 19) {
sz = (unsigned int) gpg_curve2domainlen(key->curve);
if ((sz == 0) || (key->d_len != sz)) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
sz = cx_ecdsa_sign(key,
CX_RND_TRNG,
CX_NONE,
G_gpg_vstate.work.io_buffer,
sz,
RS,
256,
&info);
// reencode r,s in MPI format
gpg_io_discard(0);
rs_len = RS[3];
rs = &RS[4];
rs_len = RS[3];
rs = &RS[4];
for (i = 0; i < 2; i++) {
if (*rs == 0) {
rs++;
rs_len--;
for (i = 0; i < 2; i++) {
if (*rs == 0) {
rs++;
rs_len--;
}
gpg_io_insert_u8(0);
gpg_io_insert(rs, rs_len);
rs = rs + rs_len;
rs_len = rs[1];
rs += 2;
}
} else {
sz = cx_eddsa_sign(key,
CX_NONE,
CX_SHA512,
G_gpg_vstate.work.io_buffer,
G_gpg_vstate.io_length,
NULL,
0,
RS,
256,
NULL);
gpg_io_discard(0);
gpg_io_insert(RS, sz);
}
gpg_io_insert_u8(0);
gpg_io_insert(rs, rs_len);
rs = rs + rs_len;
rs_len = rs[1];
rs += 2;
}
} else {
sz = cx_eddsa_sign(key, CX_NONE, CX_SHA512, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, NULL, 0, RS, 256,
NULL);
gpg_io_discard(0);
gpg_io_insert(RS, sz);
}
#undef RS
// send
gpg_pso_reset_PW1();
return SW_OK;
}
// --- PSO:CDS NOT SUPPORTED
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
// send
gpg_pso_reset_PW1();
return SW_OK;
}
// --- PSO:CDS NOT SUPPORTED
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
int gpg_apdu_pso() {
unsigned int t, l, ksz;
unsigned int t, l, ksz;
unsigned int pso;
unsigned int sz;
unsigned int pso;
unsigned int sz;
pso = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
pso = (G_gpg_vstate.io_p1 << 8) | G_gpg_vstate.io_p2;
// UIF HANDLE
switch (pso) {
// --- PSO:CDS ---
case 0x9e9a:
if (G_gpg_vstate.kslot->sig.UIF[0]) {
if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0);
return 0;
}
G_gpg_vstate.UIF_flags = 0;
}
break;
// --- PSO:DEC ---
case 0x8086:
case 0x8680:
if (G_gpg_vstate.kslot->dec.UIF[0]) {
if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0);
return 0;
}
G_gpg_vstate.UIF_flags = 0;
// UIF HANDLE
switch (pso) {
// --- PSO:CDS ---
case 0x9e9a:
if (G_gpg_vstate.kslot->sig.UIF[0]) {
if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0);
return 0;
}
G_gpg_vstate.UIF_flags = 0;
}
break;
// --- PSO:DEC ---
case 0x8086:
case 0x8680:
if (G_gpg_vstate.kslot->dec.UIF[0]) {
if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0);
return 0;
}
G_gpg_vstate.UIF_flags = 0;
}
break;
}
break;
}
// --- PSO:ENC ---
switch (pso) {
// --- PSO:CDS ---
case 0x9e9a: {
unsigned int cnt;
int sw;
sw = gpg_sign(&G_gpg_vstate.kslot->sig);
cnt = G_gpg_vstate.kslot->sig_count + 1;
nvm_write(&G_gpg_vstate.kslot->sig_count, &cnt, sizeof(unsigned int));
return sw;
}
// --- PSO:ENC ---
case 0x8680: {
unsigned int msg_len;
cx_aes_key_t *key;
key = &G_gpg_vstate.kslot->AES_dec;
if (!(key->size != 16)) {
THROW(SW_CONDITIONS_NOT_SATISFIED + 5);
return SW_CONDITIONS_NOT_SATISFIED;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_aes(key, CX_ENCRYPT | CX_CHAIN_CBC | CX_LAST, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, msg_len,
G_gpg_vstate.work.io_buffer + 1, GPG_IO_BUFFER_LENGTH - 1);
// send
gpg_io_discard(0);
G_gpg_vstate.work.io_buffer[0] = 0x02;
gpg_io_inserted(1 + sz);
return SW_OK;
}
// --- PSO:ENC ---
switch (pso) {
// --- PSO:CDS ---
case 0x9e9a: {
unsigned int cnt;
int sw;
sw = gpg_sign(&G_gpg_vstate.kslot->sig);
cnt = G_gpg_vstate.kslot->sig_count + 1;
nvm_write(&G_gpg_vstate.kslot->sig_count, &cnt, sizeof(unsigned int));
return sw;
}
// --- PSO:ENC ---
case 0x8680: {
unsigned int msg_len;
cx_aes_key_t *key;
key = &G_gpg_vstate.kslot->AES_dec;
if (!(key->size != 16)) {
THROW(SW_CONDITIONS_NOT_SATISFIED + 5);
return SW_CONDITIONS_NOT_SATISFIED;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_aes(key,
CX_ENCRYPT | CX_CHAIN_CBC | CX_LAST,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
msg_len,
G_gpg_vstate.work.io_buffer + 1,
GPG_IO_BUFFER_LENGTH - 1);
// send
gpg_io_discard(0);
G_gpg_vstate.work.io_buffer[0] = 0x02;
gpg_io_inserted(1 + sz);
return SW_OK;
}
// --- PSO:DEC ---
case 0x8086: {
unsigned int msg_len;
unsigned int pad_byte;
pad_byte = gpg_io_fetch_u8();
// --- PSO:DEC ---
case 0x8086: {
unsigned int msg_len;
unsigned int pad_byte;
pad_byte = gpg_io_fetch_u8();
switch (pad_byte) {
// --- PSO:DEC:RSA
case 0x00: {
cx_rsa_private_key_t *key;
if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x01) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
ksz = (G_gpg_vstate.mse_dec->attributes.value[1] << 8) | G_gpg_vstate.mse_dec->attributes.value[2];
ksz = ksz >> 3;
key = NULL;
switch (ksz) {
case 1024 / 8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa1024;
break;
case 2048 / 8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa2048;
break;
case 3072 / 8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa3072;
break;
case 4096 / 8:
key = (cx_rsa_private_key_t *)&G_gpg_vstate.mse_dec->priv_key.rsa4096;
break;
}
switch (pad_byte) {
// --- PSO:DEC:RSA
case 0x00: {
cx_rsa_private_key_t *key;
if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x01) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
ksz = (G_gpg_vstate.mse_dec->attributes.value[1] << 8) |
G_gpg_vstate.mse_dec->attributes.value[2];
ksz = ksz >> 3;
key = NULL;
switch (ksz) {
case 1024 / 8:
key = (cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa1024;
break;
case 2048 / 8:
key = (cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa2048;
break;
case 3072 / 8:
key = (cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa3072;
break;
case 4096 / 8:
key = (cx_rsa_private_key_t *) &G_gpg_vstate.mse_dec->priv_key.rsa4096;
break;
}
if ((key == NULL) || (key->size != ksz)) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_rsa_decrypt(key, CX_PAD_PKCS1_1o5, CX_NONE, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, msg_len,
G_gpg_vstate.work.io_buffer, ksz);
// send
gpg_io_discard(0);
gpg_io_inserted(sz);
return SW_OK;
}
if ((key == NULL) || (key->size != ksz)) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_rsa_decrypt(key,
CX_PAD_PKCS1_1o5,
CX_NONE,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
msg_len,
G_gpg_vstate.work.io_buffer,
ksz);
// send
gpg_io_discard(0);
gpg_io_inserted(sz);
return SW_OK;
}
// --- PSO:DEC:AES
case 0x02: {
cx_aes_key_t *key;
key = &G_gpg_vstate.kslot->AES_dec;
if (!(key->size != 16)) {
THROW(SW_CONDITIONS_NOT_SATISFIED + 5);
return SW_CONDITIONS_NOT_SATISFIED;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_aes(key, CX_DECRYPT | CX_CHAIN_CBC | CX_LAST, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
msg_len, G_gpg_vstate.work.io_buffer, GPG_IO_BUFFER_LENGTH);
// send
gpg_io_discard(0);
gpg_io_inserted(sz);
return SW_OK;
}
// --- PSO:DEC:AES
case 0x02: {
cx_aes_key_t *key;
key = &G_gpg_vstate.kslot->AES_dec;
if (!(key->size != 16)) {
THROW(SW_CONDITIONS_NOT_SATISFIED + 5);
return SW_CONDITIONS_NOT_SATISFIED;
}
msg_len = G_gpg_vstate.io_length - G_gpg_vstate.io_offset;
sz = cx_aes(key,
CX_DECRYPT | CX_CHAIN_CBC | CX_LAST,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
msg_len,
G_gpg_vstate.work.io_buffer,
GPG_IO_BUFFER_LENGTH);
// send
gpg_io_discard(0);
gpg_io_inserted(sz);
return SW_OK;
}
// --- PSO:DEC:ECDH
case 0xA6: {
cx_ecfp_private_key_t *key;
unsigned int curve;
if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x12) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
key = &G_gpg_vstate.mse_dec->priv_key.ecfp;
gpg_io_fetch_l(&l);
gpg_io_fetch_tl(&t, &l);
if (t != 0x7f49) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_io_fetch_tl(&t, &l);
if (t != 0x86) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
// --- PSO:DEC:ECDH
case 0xA6: {
cx_ecfp_private_key_t *key;
unsigned int curve;
curve = gpg_oid2curve(G_gpg_vstate.mse_dec->attributes.value + 1, G_gpg_vstate.mse_dec->attributes.length - 1);
if (key->curve != curve) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
if (curve == CX_CURVE_Curve25519) {
unsigned int i;
if (G_gpg_vstate.mse_dec->attributes.value[0] != 0x12) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
key = &G_gpg_vstate.mse_dec->priv_key.ecfp;
gpg_io_fetch_l(&l);
gpg_io_fetch_tl(&t, &l);
if (t != 0x7f49) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
gpg_io_fetch_tl(&t, &l);
if (t != 0x86) {
THROW(SW_WRONG_DATA);
return SW_WRONG_DATA;
}
for (i = 0; i <= 31; i++) {
G_gpg_vstate.work.io_buffer[512 + i] = (G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset)[31 - i];
}
G_gpg_vstate.work.io_buffer[511] = 0x02;
sz = cx_ecdh(key, CX_ECDH_X, G_gpg_vstate.work.io_buffer + 511, 65, G_gpg_vstate.work.io_buffer + 256, 160);
for (i = 0; i <= 31; i++) {
G_gpg_vstate.work.io_buffer[128 + i] = G_gpg_vstate.work.io_buffer[287 - i];
curve = gpg_oid2curve(G_gpg_vstate.mse_dec->attributes.value + 1,
G_gpg_vstate.mse_dec->attributes.length - 1);
if (key->curve != curve) {
THROW(SW_CONDITIONS_NOT_SATISFIED);
return SW_CONDITIONS_NOT_SATISFIED;
}
if (curve == CX_CURVE_Curve25519) {
unsigned int i;
for (i = 0; i <= 31; i++) {
G_gpg_vstate.work.io_buffer[512 + i] =
(G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset)[31 - i];
}
G_gpg_vstate.work.io_buffer[511] = 0x02;
sz = cx_ecdh(key,
CX_ECDH_X,
G_gpg_vstate.work.io_buffer + 511,
65,
G_gpg_vstate.work.io_buffer + 256,
160);
for (i = 0; i <= 31; i++) {
G_gpg_vstate.work.io_buffer[128 + i] =
G_gpg_vstate.work.io_buffer[287 - i];
}
sz = 32;
} else {
sz = cx_ecdh(key,
CX_ECDH_X,
G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset,
65,
G_gpg_vstate.work.io_buffer + 128,
160);
}
// send
gpg_io_discard(0);
gpg_io_insert(G_gpg_vstate.work.io_buffer + 128, sz);
return SW_OK;
}
// --- PSO:DEC:xx NOT SUPPORTED
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
}
sz = 32;
} else {
sz = cx_ecdh(key, CX_ECDH_X, G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset, 65,
G_gpg_vstate.work.io_buffer + 128, 160);
}
// send
gpg_io_discard(0);
gpg_io_insert(G_gpg_vstate.work.io_buffer + 128, sz);
return SW_OK;
}
// --- PSO:DEC:xx NOT SUPPORTDED
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
//--- PSO:yy NOT SUPPORTED ---
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
}
//--- PSO:yy NOT SUPPPORTED ---
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
THROW(SW_REFERENCED_DATA_NOT_FOUND);
return SW_REFERENCED_DATA_NOT_FOUND;
}
int gpg_apdu_internal_authenticate() {
// --- PSO:AUTH ---
if (G_gpg_vstate.kslot->aut.UIF[0]) {
if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0);
return 0;
// --- PSO:AUTH ---
if (G_gpg_vstate.kslot->aut.UIF[0]) {
if ((G_gpg_vstate.UIF_flags) == 0) {
ui_menu_uifconfirm_display(0);
return 0;
}
G_gpg_vstate.UIF_flags = 0;
}
G_gpg_vstate.UIF_flags = 0;
}
if (G_gpg_vstate.mse_aut->attributes.value[0] == 1) {
if (G_gpg_vstate.io_length >
((G_gpg_vstate.mse_aut->attributes.value[1] << 8) | G_gpg_vstate.mse_aut->attributes.value[2]) * 40 / 100) {
THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH;
if (G_gpg_vstate.mse_aut->attributes.value[0] == 1) {
if (G_gpg_vstate.io_length > ((G_gpg_vstate.mse_aut->attributes.value[1] << 8) |
G_gpg_vstate.mse_aut->attributes.value[2]) *
40 / 100) {
THROW(SW_WRONG_LENGTH);
return SW_WRONG_LENGTH;
}
}
}
return gpg_sign(G_gpg_vstate.mse_aut);
return gpg_sign(G_gpg_vstate.mse_aut);
}

@ -22,21 +22,21 @@
#ifndef TARGET_NANOS
#include "ux.h"
ux_state_t G_ux;
ux_state_t G_ux;
bolos_ux_params_t G_ux_params;
#else
ux_state_t ux;
ux_state_t ux;
#endif
#ifndef GPG_DEBUG_MAIN
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
#else
extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
int apdu_n;
int apdu_n;
#endif
gpg_v_state_t G_gpg_vstate;
#ifdef HAVE_RSA
union cx_u G_cx;
#endif // HAVE_RSA
#endif // HAVE_RSA

@ -21,37 +21,39 @@
const unsigned char C_MF[] = {0x3F, 0x00};
int gpg_apdu_select() {
int sw;
int sw;
// MF
if ((G_gpg_vstate.io_length == 2) && (memcmp(G_gpg_vstate.work.io_buffer, C_MF, G_gpg_vstate.io_length) == 0)) {
gpg_io_discard(0);
sw = SW_OK;
}
// AID APP
else if ((G_gpg_vstate.io_length == 6) &&
(memcmp(G_gpg_vstate.work.io_buffer, (const void *)N_gpg_pstate->AID, G_gpg_vstate.io_length) == 0)) {
G_gpg_vstate.DO_current = 0;
G_gpg_vstate.DO_reccord = 0;
G_gpg_vstate.DO_offset = 0;
if (G_gpg_vstate.selected == 0) {
G_gpg_vstate.verified_pin[0] = 0;
G_gpg_vstate.verified_pin[1] = 0;
G_gpg_vstate.verified_pin[2] = 0;
G_gpg_vstate.verified_pin[3] = 0;
G_gpg_vstate.verified_pin[4] = 0;
// MF
if ((G_gpg_vstate.io_length == 2) &&
(memcmp(G_gpg_vstate.work.io_buffer, C_MF, G_gpg_vstate.io_length) == 0)) {
gpg_io_discard(0);
sw = SW_OK;
}
// AID APP
else if ((G_gpg_vstate.io_length == 6) && (memcmp(G_gpg_vstate.work.io_buffer,
(const void *) N_gpg_pstate->AID,
G_gpg_vstate.io_length) == 0)) {
G_gpg_vstate.DO_current = 0;
G_gpg_vstate.DO_reccord = 0;
G_gpg_vstate.DO_offset = 0;
if (G_gpg_vstate.selected == 0) {
G_gpg_vstate.verified_pin[0] = 0;
G_gpg_vstate.verified_pin[1] = 0;
G_gpg_vstate.verified_pin[2] = 0;
G_gpg_vstate.verified_pin[3] = 0;
G_gpg_vstate.verified_pin[4] = 0;
}
gpg_io_discard(0);
if (N_gpg_pstate->histo[7] != 0x07) {
THROW(SW_STATE_TERMINATED);
gpg_io_discard(0);
if (N_gpg_pstate->histo[7] != STATE_ACTIVATE) {
THROW(SW_STATE_TERMINATED);
}
sw = SW_OK;
}
sw = SW_OK;
}
// NOT FOUND
else {
THROW(SW_FILE_NOT_FOUND);
return SW_FILE_NOT_FOUND;
}
return sw;
// NOT FOUND
else {
THROW(SW_FILE_NOT_FOUND);
return SW_FILE_NOT_FOUND;
}
return sw;
}

@ -26,11 +26,11 @@
/* big private DO */
#define GPG_EXT_PRIVATE_DO_LENGTH 512
/* will be fixed..1024 is not enougth */
/* will be fixed..1024 is not enough */
#define GPG_EXT_CARD_HOLDER_CERT_LENTH 2560
/* random choice */
#define GPG_EXT_CHALLENGE_LENTH 254
/* accpet long PW, but less than one sha256 block */
/* accept long PW, but less than one sha256 block */
#define GPG_MAX_PW_LENGTH 12
#if GPG_MULTISLOT
@ -44,137 +44,137 @@
#define GPG_RSA_DEFAULT_PUB 0x00010001U
struct gpg_pin_s {
unsigned int ref;
// initial pin length, 0 means not set
unsigned int length;
unsigned int counter;
// only store sha256 of PIN/RC
unsigned char value[32];
unsigned int ref;
// initial pin length, 0 means not set
unsigned int length;
unsigned int counter;
// only store sha256 of PIN/RC
unsigned char value[32];
};
typedef struct gpg_pin_s gpg_pin_t;
#define LV(name, maxlen) \
struct { \
unsigned int length; \
unsigned char value[maxlen]; \
} name
#define LV(name, maxlen) \
struct { \
unsigned int length; \
unsigned char value[maxlen]; \
} name
typedef struct gpg_lv_s {
unsigned int length;
unsigned char value[];
unsigned int length;
unsigned char value[];
} gpg_lv_t;
typedef struct gpg_key_s {
/* C1 C2 C3 */
LV(attributes, GPG_KEY_ATTRIBUTES_LENGTH);
/* key value */
/* WARN: changing the cx_<key>_t structures breaks backup/restore. Adapt backup/restore code
* to ensure backward compatibility.
*/
union {
cx_rsa_private_key_t rsa;
cx_rsa_1024_private_key_t rsa1024;
cx_rsa_2048_private_key_t rsa2048;
cx_rsa_3072_private_key_t rsa3072;
cx_rsa_4096_private_key_t rsa4096;
cx_ecfp_private_key_t ecfp;
cx_ecfp_256_private_key_t ecfp256;
cx_ecfp_384_private_key_t ecfp384;
cx_ecfp_512_private_key_t ecfp512;
cx_ecfp_640_private_key_t ecfp640;
} priv_key;
union {
unsigned char rsa[4];
cx_ecfp_public_key_t ecfp;
cx_ecfp_256_public_key_t ecfp256;
cx_ecfp_384_public_key_t ecfp384;
cx_ecfp_512_public_key_t ecfp512;
cx_ecfp_640_public_key_t ecfp640;
} pub_key;
/* C7 C8 C9 , C5 = C7|C8|C9*/
unsigned char fingerprints[20];
/* 7F21 */
LV(CA, GPG_EXT_CARD_HOLDER_CERT_LENTH);
/* C7 C8 C9, C6 = C7|C8|C9*/
unsigned char CA_fingerprints[20];
/* CE CF D0, CD = CE|CF|D0 */
unsigned char date[4];
/* D6/D7/D8- */
unsigned char UIF[2];
/* C1 C2 C3 */
LV(attributes, GPG_KEY_ATTRIBUTES_LENGTH);
/* key value */
/* WARN: changing the cx_<key>_t structures breaks backup/restore. Adapt backup/restore code
* to ensure backward compatibility.
*/
union {
cx_rsa_private_key_t rsa;
cx_rsa_1024_private_key_t rsa1024;
cx_rsa_2048_private_key_t rsa2048;
cx_rsa_3072_private_key_t rsa3072;
cx_rsa_4096_private_key_t rsa4096;
cx_ecfp_private_key_t ecfp;
cx_ecfp_256_private_key_t ecfp256;
cx_ecfp_384_private_key_t ecfp384;
cx_ecfp_512_private_key_t ecfp512;
cx_ecfp_640_private_key_t ecfp640;
} priv_key;
union {
unsigned char rsa[4];
cx_ecfp_public_key_t ecfp;
cx_ecfp_256_public_key_t ecfp256;
cx_ecfp_384_public_key_t ecfp384;
cx_ecfp_512_public_key_t ecfp512;
cx_ecfp_640_public_key_t ecfp640;
} pub_key;
/* C7 C8 C9 , C5 = C7|C8|C9*/
unsigned char fingerprints[20];
/* 7F21 */
LV(CA, GPG_EXT_CARD_HOLDER_CERT_LENTH);
/* C7 C8 C9, C6 = C7|C8|C9*/
unsigned char CA_fingerprints[20];
/* CE CF D0, CD = CE|CF|D0 */
unsigned char date[4];
/* D6/D7/D8- */
unsigned char UIF[2];
} gpg_key_t;
typedef struct gpg_key_slot_s {
unsigned char serial[4];
/* */
gpg_key_t sig;
gpg_key_t aut;
gpg_key_t dec;
/* -- Security support template -- */
/* 93 */
unsigned int sig_count;
/* D5 */
cx_aes_key_t AES_dec;
unsigned char serial[4];
/* */
gpg_key_t sig;
gpg_key_t aut;
gpg_key_t dec;
/* -- Security support template -- */
/* 93 */
unsigned int sig_count;
/* D5 */
cx_aes_key_t AES_dec;
} gpg_key_slot_t;
struct gpg_nv_state_s {
/* magic */
unsigned char magic[8];
/* pin mode */
unsigned char config_pin[1];
/* 01F1 (01F2 is volatile)*/
unsigned char config_slot[3];
/* RSA exponent */
unsigned char default_RSA_exponent[4];
/* 0101 0102 0103 0104 */
LV(private_DO1, GPG_EXT_PRIVATE_DO_LENGTH);
LV(private_DO2, GPG_EXT_PRIVATE_DO_LENGTH);
LV(private_DO3, GPG_EXT_PRIVATE_DO_LENGTH);
LV(private_DO4, GPG_EXT_PRIVATE_DO_LENGTH);
/* 5E */
LV(login, GPG_EXT_PRIVATE_DO_LENGTH);
/* 5F50 */
LV(url, GPG_EXT_PRIVATE_DO_LENGTH);
/* -- Cardholder Related Data -- */
/* 5B */
LV(name, 39);
/* 5F2D */
LV(lang, 8);
/* 5F35 */
unsigned char sex[1];
/* -- Application Related Data -- */
/* 4F */
unsigned char AID[16];
/* 5F52 */
unsigned char histo[15];
/* 7f66 */
// unsigned char ext_length_info[8];
/* C0 */
// unsigned char ext_capabilities[10];
/* C4 */
unsigned char PW_status[4];
/* PINs */
gpg_pin_t PW1;
gpg_pin_t PW3;
gpg_pin_t RC;
/* gpg keys */
gpg_key_slot_t keys[GPG_KEYS_SLOTS];
/* --- SM --- */
/* D1 */
cx_aes_key_t SM_enc;
/* D2 */
cx_aes_key_t SM_mac;
/* magic */
unsigned char magic[8];
/* pin mode */
unsigned char config_pin[1];
/* 01F1 (01F2 is volatile)*/
unsigned char config_slot[3];
/* RSA exponent */
unsigned char default_RSA_exponent[4];
/* 0101 0102 0103 0104 */
LV(private_DO1, GPG_EXT_PRIVATE_DO_LENGTH);
LV(private_DO2, GPG_EXT_PRIVATE_DO_LENGTH);
LV(private_DO3, GPG_EXT_PRIVATE_DO_LENGTH);
LV(private_DO4, GPG_EXT_PRIVATE_DO_LENGTH);
/* 5E */
LV(login, GPG_EXT_PRIVATE_DO_LENGTH);
/* 5F50 */
LV(url, GPG_EXT_PRIVATE_DO_LENGTH);
/* -- Cardholder Related Data -- */
/* 5B */
LV(name, 39);
/* 5F2D */
LV(lang, 8);
/* 5F35 */
unsigned char sex[1];
/* -- Application Related Data -- */
/* 4F */
unsigned char AID[16];
/* 5F52 */
unsigned char histo[15];
/* 7f66 */
// unsigned char ext_length_info[8];
/* C0 */
// unsigned char ext_capabilities[10];
/* C4 */
unsigned char PW_status[4];
/* PINs */
gpg_pin_t PW1;
gpg_pin_t PW3;
gpg_pin_t RC;
/* gpg keys */
gpg_key_slot_t keys[GPG_KEYS_SLOTS];
/* --- SM --- */
/* D1 */
cx_aes_key_t SM_enc;
/* D2 */
cx_aes_key_t SM_mac;
};
typedef struct gpg_nv_state_s gpg_nv_state_t;
@ -182,105 +182,106 @@ typedef struct gpg_nv_state_s gpg_nv_state_t;
#define GPG_IO_BUFFER_LENGTH (1512)
struct gpg_v_state_s {
/* app state */
unsigned char selected;
unsigned char slot; /* DO 01F2 */
gpg_key_slot_t *kslot;
gpg_key_t * mse_aut;
gpg_key_t * mse_dec;
unsigned char seed_mode;
unsigned char UIF_flags;
/* io state*/
unsigned char io_cla;
unsigned char io_ins;
unsigned char io_p1;
unsigned char io_p2;
unsigned char io_lc;
unsigned char io_le;
unsigned short io_length;
unsigned short io_offset;
unsigned short io_mark;
union {
unsigned char io_buffer[GPG_IO_BUFFER_LENGTH];
struct {
union {
cx_rsa_public_key_t public;
cx_rsa_1024_public_key_t public1024;
cx_rsa_2048_public_key_t public2048;
cx_rsa_3072_public_key_t public3072;
cx_rsa_4096_public_key_t public4096;
};
union {
cx_rsa_private_key_t private;
cx_rsa_1024_private_key_t private1024;
cx_rsa_2048_private_key_t private2048;
cx_rsa_3072_private_key_t private3072;
cx_rsa_4096_private_key_t private4096;
};
} rsa;
struct {
union {
cx_ecfp_public_key_t public;
cx_ecfp_256_public_key_t public256;
cx_ecfp_384_public_key_t public384;
cx_ecfp_512_public_key_t public512;
cx_ecfp_640_public_key_t public640;
};
union {
cx_ecfp_private_key_t private;
cx_ecfp_256_private_key_t private256;
cx_ecfp_384_private_key_t private384;
cx_ecfp_512_private_key_t private512;
cx_ecfp_640_private_key_t private640;
};
} ecfp;
struct {
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH - (32 + MAX(sizeof(cx_sha3_t), sizeof(cx_sha256_t)))];
unsigned char H[32];
union {
cx_sha3_t sha3;
cx_sha256_t sha256;
};
} md;
} work;
/* data state */
unsigned short DO_current;
unsigned short DO_reccord;
unsigned short DO_offset;
/* PINs state */
unsigned char verified_pin[5];
unsigned char pinmode;
/* ux menus */
char menu[112];
unsigned char ux_pinentry[12];
unsigned int ux_key;
unsigned int ux_type;
/* app state */
unsigned char selected;
unsigned char slot; /* DO 01F2 */
gpg_key_slot_t *kslot;
gpg_key_t *mse_aut;
gpg_key_t *mse_dec;
unsigned char seed_mode;
unsigned char UIF_flags;
/* io state*/
unsigned char io_cla;
unsigned char io_ins;
unsigned char io_p1;
unsigned char io_p2;
unsigned char io_lc;
unsigned char io_le;
unsigned short io_length;
unsigned short io_offset;
unsigned short io_mark;
union {
unsigned char io_buffer[GPG_IO_BUFFER_LENGTH];
struct {
union {
cx_rsa_public_key_t public;
cx_rsa_1024_public_key_t public1024;
cx_rsa_2048_public_key_t public2048;
cx_rsa_3072_public_key_t public3072;
cx_rsa_4096_public_key_t public4096;
};
union {
cx_rsa_private_key_t private;
cx_rsa_1024_private_key_t private1024;
cx_rsa_2048_private_key_t private2048;
cx_rsa_3072_private_key_t private3072;
cx_rsa_4096_private_key_t private4096;
};
} rsa;
struct {
union {
cx_ecfp_public_key_t public;
cx_ecfp_256_public_key_t public256;
cx_ecfp_384_public_key_t public384;
cx_ecfp_512_public_key_t public512;
cx_ecfp_640_public_key_t public640;
};
union {
cx_ecfp_private_key_t private;
cx_ecfp_256_private_key_t private256;
cx_ecfp_384_private_key_t private384;
cx_ecfp_512_private_key_t private512;
cx_ecfp_640_private_key_t private640;
};
} ecfp;
struct {
unsigned char md_buffer[GPG_IO_BUFFER_LENGTH -
(32 + MAX(sizeof(cx_sha3_t), sizeof(cx_sha256_t)))];
unsigned char H[32];
union {
cx_sha3_t sha3;
cx_sha256_t sha256;
};
} md;
} work;
/* data state */
unsigned short DO_current;
unsigned short DO_reccord;
unsigned short DO_offset;
/* PINs state */
unsigned char verified_pin[5];
unsigned char pinmode;
/* ux menus */
char menu[112];
unsigned char ux_pinentry[12];
unsigned int ux_key;
unsigned int ux_type;
#ifdef UI_NANO_S
ux_menu_entry_t ui_dogsays[2];
ux_menu_entry_t ui_dogsays[2];
#endif
#ifdef UI_NANO_X
char ux_buff1[32];
char ux_buff2[32];
char ux_buff3[32];
char ux_buff4[32];
char ux_buff5[32];
char ux_buff1[32];
char ux_buff2[32];
char ux_buff3[32];
char ux_buff4[32];
char ux_buff5[32];
#endif
#ifdef GPG_LOG
#ifdef GPG_LOG
unsigned char log_buffer[32];
#endif
#endif
#ifdef GPG_DEBUG
unsigned char print;
unsigned char print;
#endif
};
typedef struct gpg_v_state_s gpg_v_state_t;
@ -290,29 +291,29 @@ typedef struct gpg_v_state_s gpg_v_state_t;
#define ERROR(x) ((x) << 16)
#define ERROR_IO_OFFSET ERROR(1)
#define ERROR_IO_FULL ERROR(2)
#define ERROR_IO_FULL ERROR(2)
/* --- IDentifiers --- */
#define ID_AUTH 1
#define ID_DEC 2
#define ID_SIG 3
#define ID_DEC 2
#define ID_SIG 3
#define STATE_ACTIVATE 0x07
#define STATE_ACTIVATE 0x07
#define STATE_TERMINATE 0x03
#define IO_OFFSET_END (unsigned int)-1
#define IO_OFFSET_MARK (unsigned int)-2
#define IO_OFFSET_END (unsigned int) -1
#define IO_OFFSET_MARK (unsigned int) -2
#define PIN_ID_PW1 0x81
#define PIN_ID_PW2 0x82
#define PIN_ID_PW3 0x83
#define PIN_ID_RC 0x84
#define PIN_ID_RC 0x84
#define PIN_MODE_HOST 1
#define PIN_MODE_SCREEN 2
#define PIN_MODE_HOST 1
#define PIN_MODE_SCREEN 2
#define PIN_MODE_CONFIRM 3
#define PIN_MODE_TRUST 4
#define PIN_MODE_TRUST 4
/* --- INS --- */
#define INS_EXIT 0x02
@ -320,73 +321,73 @@ typedef struct gpg_v_state_s gpg_v_state_t;
#define INS_GET_LOG 0x04
#endif
#define INS_SELECT 0xa4
#define INS_TERMINATE_DF 0xe6
#define INS_SELECT 0xa4
#define INS_TERMINATE_DF 0xe6
#define INS_ACTIVATE_FILE 0x44
#define INS_SELECT_DATA 0xa5
#define INS_GET_DATA 0xca
#define INS_SELECT_DATA 0xa5
#define INS_GET_DATA 0xca
#define INS_GET_NEXT_DATA 0xcc
#define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb
#define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb
#define INS_VERIFY 0x20
#define INS_MSE 0x22
#define INS_VERIFY 0x20
#define INS_MSE 0x22
#define INS_CHANGE_REFERENCE_DATA 0x24
#define INS_RESET_RETRY_COUNTER 0x2c
#define INS_RESET_RETRY_COUNTER 0x2c
#define INS_GEN_ASYM_KEYPAIR 0x47
#define INS_PSO 0x2a
//#define INS_COMPUTEDIGSIG 0x2a
//#define INS_DECIPHER 0x2a
#define INS_PSO 0x2a
// #define INS_COMPUTEDIGSIG 0x2a
// #define INS_DECIPHER 0x2a
#define INS_INTERNAL_AUTHENTICATE 0x88
#define INS_GET_CHALLENGE 0x84
#define INS_GET_RESPONSE 0xc0
#define INS_GET_RESPONSE 0xc0
/* --- IO constants --- */
#define OFFSET_CLA 0
#define OFFSET_INS 1
#define OFFSET_P1 2
#define OFFSET_P2 3
#define OFFSET_P3 4
#define OFFSET_CDATA 5
#define OFFSET_CLA 0
#define OFFSET_INS 1
#define OFFSET_P1 2
#define OFFSET_P2 3
#define OFFSET_P3 4
#define OFFSET_CDATA 5
#define OFFSET_EXT_CDATA 7
#define SW_OK 0x9000
#define SW_OK 0x9000
#define SW_ALGORITHM_UNSUPPORTED 0x9484
#define SW_BYTES_REMAINING_00 0x6100
#define SW_WARNING_STATE_UNCHANGED 0x6200
#define SW_STATE_TERMINATED 0x6285
#define SW_STATE_TERMINATED 0x6285
#define SW_MORE_DATA_AVAILABLE 0x6310
#define SW_WRONG_LENGTH 0x6700
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881
#define SW_SECURE_MESSAGING_NOT_SUPPORTED 0x6882
#define SW_LAST_COMMAND_EXPECTED 0x6883
#define SW_LAST_COMMAND_EXPECTED 0x6883
#define SW_COMMAND_CHAINING_NOT_SUPPORTED 0x6884
#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982
#define SW_FILE_INVALID 0x6983
#define SW_PIN_BLOCKED 0x6983
#define SW_DATA_INVALID 0x6984
#define SW_CONDITIONS_NOT_SATISFIED 0x6985
#define SW_COMMAND_NOT_ALLOWED 0x6986
#define SW_APPLET_SELECT_FAILED 0x6999
#define SW_WRONG_DATA 0x6a80
#define SW_FUNC_NOT_SUPPORTED 0x6a81
#define SW_FILE_NOT_FOUND 0x6a82
#define SW_RECORD_NOT_FOUND 0x6a83
#define SW_FILE_FULL 0x6a84
#define SW_INCORRECT_P1P2 0x6a86
#define SW_FILE_INVALID 0x6983
#define SW_PIN_BLOCKED 0x6983
#define SW_DATA_INVALID 0x6984
#define SW_CONDITIONS_NOT_SATISFIED 0x6985
#define SW_COMMAND_NOT_ALLOWED 0x6986
#define SW_APPLET_SELECT_FAILED 0x6999
#define SW_WRONG_DATA 0x6a80
#define SW_FUNC_NOT_SUPPORTED 0x6a81
#define SW_FILE_NOT_FOUND 0x6a82
#define SW_RECORD_NOT_FOUND 0x6a83
#define SW_FILE_FULL 0x6a84
#define SW_INCORRECT_P1P2 0x6a86
#define SW_REFERENCED_DATA_NOT_FOUND 0x6a88
#define SW_WRONG_P1P2 0x6b00
#define SW_WRONG_P1P2 0x6b00
#define SW_CORRECT_LENGTH_00 0x6c00
#define SW_INS_NOT_SUPPORTED 0x6d00
#define SW_CLA_NOT_SUPPORTED 0x6e00

@ -13,24 +13,24 @@
* limitations under the License.
*/
const char *const C_TEMPLATE_TYPE = "Key type";
const char *const C_TEMPLATE_KEY = "Key";
const char *const C_TEMPLATE_TYPE = "Key type";
const char *const C_TEMPLATE_KEY = "Key";
const char *const C_INVALID_SELECTION = "Invalid selection";
const char *const C_OK = "OK";
const char *const C_OK = "OK";
const char *const C_NOK = "NOK";
const char *const C_WRONG_PIN = "PIN Incorrect";
const char *const C_RIGHT_PIN = "PIN Correct";
const char *const C_WRONG_PIN = "PIN Incorrect";
const char *const C_RIGHT_PIN = "PIN Correct";
const char *const C_PIN_CHANGED = "PIN changed";
const char *const C_PIN_DIFFERS = "2 PINs differs";
const char *const C_PIN_USER = "User PIN";
const char *const C_PIN_ADMIN = "Admin PIN";
const char *const C_PIN_USER = "User PIN";
const char *const C_PIN_ADMIN = "Admin PIN";
const char *const C_VERIFIED = "Verified";
const char *const C_VERIFIED = "Verified";
const char *const C_NOT_VERIFIED = "Not Verified";
const char *const C_ALLOWED = "Allowed";
const char *const C_NOT_ALLOWED = "Not Allowed ";
const char *const C_ALLOWED = "Allowed";
const char *const C_NOT_ALLOWED = "Not Allowed ";
const char *const C_DEFAULT_MODE = "Default mode";

@ -39,25 +39,25 @@ extern const char *const C_DEFAULT_MODE;
extern const char *const C_UIF_LOCKED;
extern const char *const C_UIF_INVALID;
#define PICSTR(x) ((char *)PIC(x))
#define PICSTR(x) ((char *) PIC(x))
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
#define TEMPLATE_KEY PICSTR(C_TEMPLATE_KEY)
#define TEMPLATE_TYPE PICSTR(C_TEMPLATE_TYPE)
#define TEMPLATE_KEY PICSTR(C_TEMPLATE_KEY)
#define INVALID_SELECTION PICSTR(C_INVALID_SELECTION)
#define OK PICSTR(C_OK)
#define NOK PICSTR(C_NOK)
#define WRONG_PIN PICSTR(C_WRONG_PIN)
#define RIGHT_PIN PICSTR(C_RIGHT_PIN)
#define PIN_CHANGED PICSTR(C_PIN_CHANGED)
#define PIN_DIFFERS PICSTR(C_PIN_DIFFERS)
#define PIN_USER PICSTR(C_PIN_USER)
#define PIN_ADMIN PICSTR(C_PIN_ADMIN)
#define VERIFIED PICSTR(C_VERIFIED)
#define NOT_VERIFIED PICSTR(C_NOT_VERIFIED)
#define ALLOWED PICSTR(C_ALLOWED)
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
#define UIF_LOCKED PICSTR(C_UIF_LOCKED)
#define UIF_INVALID PICSTR(C_UIF_INVALID)
#define OK PICSTR(C_OK)
#define NOK PICSTR(C_NOK)
#define WRONG_PIN PICSTR(C_WRONG_PIN)
#define RIGHT_PIN PICSTR(C_RIGHT_PIN)
#define PIN_CHANGED PICSTR(C_PIN_CHANGED)
#define PIN_DIFFERS PICSTR(C_PIN_DIFFERS)
#define PIN_USER PICSTR(C_PIN_USER)
#define PIN_ADMIN PICSTR(C_PIN_ADMIN)
#define VERIFIED PICSTR(C_VERIFIED)
#define NOT_VERIFIED PICSTR(C_NOT_VERIFIED)
#define ALLOWED PICSTR(C_ALLOWED)
#define NOT_ALLOWED PICSTR(C_NOT_ALLOWED)
#define DEFAULT_MODE PICSTR(C_DEFAULT_MODE)
#define UIF_LOCKED PICSTR(C_UIF_LOCKED)
#define UIF_INVALID PICSTR(C_UIF_INVALID)
#endif

File diff suppressed because it is too large Load Diff

@ -22,4 +22,4 @@ void ui_main_display(unsigned int value);
void ui_menu_pinconfirm_display(unsigned int value);
void ui_menu_pinentry_display(unsigned int value);
void ui_menu_uifconfirm_display(unsigned int value);
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -36,10 +36,10 @@ extern gpg_v_state_t G_gpg_vstate;
#ifndef TARGET_NANOS
extern const gpg_nv_state_t N_state_pic;
#define N_gpg_pstate ((volatile gpg_nv_state_t *)PIC(&N_state_pic))
#define N_gpg_pstate ((volatile gpg_nv_state_t *) PIC(&N_state_pic))
#else
extern gpg_nv_state_t N_state_pic;
#define N_gpg_pstate ((WIDE gpg_nv_state_t *)PIC(&N_state_pic))
#define N_gpg_pstate ((WIDE gpg_nv_state_t *) PIC(&N_state_pic))
#endif
#ifdef GPG_DEBUG_MAIN
@ -51,5 +51,5 @@ extern ux_state_t ux;
#ifdef HAVE_RSA
#include "cx_ram.h"
extern union cx_u G_cx;
#endif // HAVE_RSA
#endif // HAVE_RSA
#endif

Loading…
Cancel
Save