Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90e77f7c61 | ||
|
|
504d90a2b3 | ||
|
|
c35d6f73d9 | ||
|
|
595455bbbc | ||
|
|
7a27dde253 | ||
|
|
e4fec2ab22 | ||
|
|
45d174b8bf | ||
|
|
73053bdc6d | ||
|
|
7936e20b9a | ||
|
|
9606e34630 | ||
|
|
81b012c0dd | ||
|
|
42a13b2777 | ||
|
|
9742991deb | ||
|
|
d938720ab5 | ||
|
|
b80a4693c6 | ||
|
|
321d02eb0d | ||
|
|
296fbd142f | ||
|
|
b606b75a12 | ||
|
|
331f4f1c4e | ||
|
|
abb432dd31 | ||
|
|
f3b7f3b42d | ||
|
|
d76e53f80b | ||
|
|
fc663cfdd6 | ||
|
|
47ac55abd1 | ||
|
|
286893bdb6 | ||
|
|
41ae81067c | ||
|
|
9c878cc5b6 | ||
|
|
31ac28c7de | ||
|
|
33ce1c50aa | ||
|
|
edfcd087c1 | ||
|
|
a713eb4e03 | ||
|
|
f2fe6dd5c2 | ||
|
|
1a24a9ed1b | ||
|
|
b62573a6bd | ||
|
|
58a9d9cf97 | ||
|
|
bc9681e7b0 | ||
|
|
c39b87019e | ||
|
|
f34cdac00b | ||
|
|
f9c1178f4d | ||
|
|
68ac692de6 | ||
|
|
4480e29ecc | ||
|
|
fccc48de43 | ||
|
|
d5a0d85b71 | ||
|
|
6dbc8f8f56 | ||
|
|
11840f1471 | ||
|
|
fc4391b433 | ||
|
|
b8a3969fad | ||
|
|
0cf673ac6d | ||
|
|
142511c494 | ||
|
|
6de499e435 | ||
|
|
ddb6b4b936 | ||
|
|
5ec7402e81 | ||
|
|
153c60fb47 | ||
|
|
3e5f882071 | ||
|
|
34c35ed36f | ||
|
|
7aefacd1d3 | ||
|
|
f11017fd13 | ||
|
|
9f91376bed | ||
|
|
4e96b0ce5a | ||
|
|
d35e67c790 | ||
|
|
a42c387e02 | ||
|
|
7050e6b19f | ||
|
|
1015d2f697 | ||
|
|
5629500a22 | ||
|
|
46d35bd50f | ||
|
|
abb4d2326c | ||
|
|
79912339b0 | ||
|
|
95a4f7201b | ||
|
|
b1161c4614 | ||
|
|
64a2d240d4 | ||
|
|
eaa8851719 | ||
|
|
fa8026bca2 | ||
|
|
e63a58a49e | ||
|
|
6fc27c97ca | ||
|
|
7533585540 | ||
|
|
de9f53acd8 | ||
|
|
7f24b9f6b8 | ||
|
|
1d508f254d | ||
|
|
09af4625a9 | ||
|
|
befe99576c | ||
|
|
77299f7047 | ||
|
|
2fd07a7dc3 | ||
|
|
6e11171416 | ||
|
|
631ffbe4a7 | ||
|
|
88e19bae35 | ||
|
|
90af0da7a0 | ||
|
|
cb2d784522 | ||
|
|
08a40e757a | ||
|
|
939c7fa7ab | ||
|
|
91bcd9f9cd | ||
|
|
88f5bbfd58 | ||
|
|
e480d57881 |
50
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
50
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
## Summary
|
||||||
|
|
||||||
|
Describe in plain language what this PR does and why.
|
||||||
|
|
||||||
|
- What problem does it solve?
|
||||||
|
- Is it a bug fix, a new feature, a cleanup/refactor…?
|
||||||
|
|
||||||
|
|
||||||
|
## Details / Impact
|
||||||
|
|
||||||
|
Please include any relevant details:
|
||||||
|
|
||||||
|
- Hardware / board(s) tested:
|
||||||
|
- Firmware / commit/base version:
|
||||||
|
- Security impact (if any):
|
||||||
|
- e.g. changes PIN handling, touches key storage, affects attestation, etc.
|
||||||
|
- Behavior changes:
|
||||||
|
- e.g. new command, new API surface, different defaults, etc.
|
||||||
|
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
How did you test this change?
|
||||||
|
|
||||||
|
- Steps to reproduce / validate:
|
||||||
|
- Expected vs actual results:
|
||||||
|
- Any logs / traces (please remove secrets):
|
||||||
|
|
||||||
|
|
||||||
|
## Licensing confirmation (required)
|
||||||
|
|
||||||
|
By checking the box below, you confirm ALL of the following:
|
||||||
|
|
||||||
|
- You are the author of this contribution, or you have the right to contribute it.
|
||||||
|
- You have read `CONTRIBUTING.md`.
|
||||||
|
- You agree that this contribution may be merged, used, modified, and redistributed:
|
||||||
|
- under the AGPLv3 Community Edition, **and**
|
||||||
|
- under any proprietary / commercial / Enterprise editions of this project,
|
||||||
|
now or in the future.
|
||||||
|
- You understand that submitting this PR does not create any support obligation,
|
||||||
|
SLA, or guarantee of merge.
|
||||||
|
|
||||||
|
**I confirm the above licensing terms:**
|
||||||
|
|
||||||
|
- [ ] Yes, I agree
|
||||||
|
|
||||||
|
|
||||||
|
## Anything else?
|
||||||
|
|
||||||
|
Optional: mention known limitations, follow-ups, or if this is related to an existing Issue.
|
||||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
|||||||
language: [ 'cpp', 'python' ]
|
language: [ 'cpp', 'python' ]
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
mode: [ 'pico', 'esp32', 'local' ]
|
mode: [ 'pico', 'local' ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
|
|||||||
42
.github/workflows/nightly.yml
vendored
Normal file
42
.github/workflows/nightly.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
name: "Nightly deploy"
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 2 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nightly:
|
||||||
|
name: Deploy nightly
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
refs: [main]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ matrix.refs }}
|
||||||
|
submodules: 'recursive'
|
||||||
|
- name: Restore private key
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.PRIVATE_KEY_B64 }}" | base64 -d > private.pem
|
||||||
|
chmod 600 private.pem
|
||||||
|
- name : Build
|
||||||
|
env:
|
||||||
|
PICO_SDK_PATH: ../pico-sdk
|
||||||
|
SECURE_BOOT_PKEY: ../private.pem
|
||||||
|
run: |
|
||||||
|
./workflows/autobuild.sh pico
|
||||||
|
./build_pico_openpgp.sh --no-eddsa
|
||||||
|
./workflows/autobuild.sh esp32
|
||||||
|
- name: Delete private key
|
||||||
|
run: rm private.pem
|
||||||
|
- name: Update nightly release
|
||||||
|
uses: pyTooling/Actions/releaser@main
|
||||||
|
with:
|
||||||
|
tag: nightly-${{ matrix.refs }}
|
||||||
|
rm: true
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
files: release/*.*
|
||||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -14,10 +14,10 @@ name: "Emulation and test"
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches: [ "main", "piv" ]
|
branches: [ "main", "piv", "eddsa" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: [ "main", "piv" ]
|
branches: [ "main", "piv", "eddsa" ]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '23 5 * * 4'
|
- cron: '23 5 * * 4'
|
||||||
|
|
||||||
|
|||||||
126
CMakeLists.txt
126
CMakeLists.txt
@@ -18,81 +18,107 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
if(ESP_PLATFORM)
|
if(ESP_PLATFORM)
|
||||||
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
|
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
else()
|
else()
|
||||||
|
if(NOT ENABLE_EMULATION)
|
||||||
|
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
|
||||||
|
include(pico_sdk_import.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ENABLE_EMULATION)
|
project(pico_openpgp C CXX ASM)
|
||||||
else()
|
|
||||||
include(pico_sdk_import.cmake)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
project(pico_openpgp C CXX ASM)
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
if(NOT DEFINED __FOR_CI)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(__FOR_CI 0)
|
||||||
|
endif()
|
||||||
|
if(__FOR_CI)
|
||||||
|
add_definitions(-D__FOR_CI)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ENABLE_EMULATION)
|
add_executable(pico_openpgp)
|
||||||
else()
|
|
||||||
pico_sdk_init()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_executable(pico_openpgp)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(USB_ITF_CCID 1)
|
||||||
|
set(USB_ITF_WCID 1)
|
||||||
|
include(pico-keys-sdk/pico_keys_sdk_import.cmake)
|
||||||
|
|
||||||
|
if(NOT ESP_PLATFORM)
|
||||||
|
set(SOURCES ${PICO_KEYS_SOURCES})
|
||||||
|
endif()
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/files.c
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/files.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/piv.c
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/piv.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/management.c
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/management.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_select.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_get_data.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_verify.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_put_data.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_select_data.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_import_data.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_version.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_change_pin.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_mse.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_internal_aut.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_challenge.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_activate_file.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_terminate_df.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_pso.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_keypair_gen.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_reset_retry.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/do.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/defs.c
|
||||||
)
|
)
|
||||||
|
|
||||||
set(USB_ITF_CCID 1)
|
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/openpgp/version.h" 2)
|
||||||
set(USB_ITF_WCID 1)
|
|
||||||
include(pico-keys-sdk/pico_keys_sdk_import.cmake)
|
|
||||||
if(ESP_PLATFORM)
|
if(ESP_PLATFORM)
|
||||||
project(pico_openpgp)
|
project(pico_openpgp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(INCLUDES ${INCLUDES}
|
set(INCLUDES ${INCLUDES}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp
|
${CMAKE_CURRENT_LIST_DIR}/src/openpgp
|
||||||
)
|
)
|
||||||
if(NOT ESP_PLATFORM)
|
if(NOT ESP_PLATFORM)
|
||||||
target_sources(pico_openpgp PUBLIC ${SOURCES})
|
target_sources(pico_openpgp PUBLIC ${SOURCES})
|
||||||
target_include_directories(pico_openpgp PUBLIC ${INCLUDES})
|
target_include_directories(pico_openpgp PUBLIC ${INCLUDES})
|
||||||
|
|
||||||
|
target_compile_options(pico_openpgp PUBLIC
|
||||||
|
-Wall
|
||||||
|
)
|
||||||
|
if(NOT MSVC)
|
||||||
target_compile_options(pico_openpgp PUBLIC
|
target_compile_options(pico_openpgp PUBLIC
|
||||||
-Wall
|
-Werror
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_EMULATION)
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
target_compile_options(pico_openpgp PUBLIC
|
target_compile_options(pico_openpgp PUBLIC
|
||||||
-Werror
|
-fdata-sections
|
||||||
)
|
-ffunction-sections
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
if(APPLE)
|
||||||
|
target_link_options(pico_openpgp PUBLIC
|
||||||
|
-Wl,-dead_strip
|
||||||
|
)
|
||||||
|
elseif(MSVC)
|
||||||
|
target_compile_options(pico_openpgp PUBLIC
|
||||||
|
-WX
|
||||||
|
)
|
||||||
|
|
||||||
if(ENABLE_EMULATION)
|
target_link_libraries(pico_openpgp PUBLIC wsock32 ws2_32 Bcrypt)
|
||||||
if(NOT MSVC)
|
else()
|
||||||
target_compile_options(pico_openpgp PUBLIC
|
target_link_options(pico_openpgp PUBLIC
|
||||||
-fdata-sections
|
-Wl,--gc-sections
|
||||||
-ffunction-sections
|
)
|
||||||
)
|
endif(APPLE)
|
||||||
endif()
|
target_link_libraries(pico_openpgp PRIVATE pthread m)
|
||||||
if(APPLE)
|
else()
|
||||||
target_link_options(pico_openpgp PUBLIC
|
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
|
||||||
-Wl,-dead_strip
|
endif()
|
||||||
)
|
|
||||||
elseif(MSVC)
|
|
||||||
target_compile_options(pico_openpgp PUBLIC
|
|
||||||
-WX
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(pico_openpgp PUBLIC wsock32 ws2_32 Bcrypt)
|
|
||||||
else()
|
|
||||||
target_link_options(pico_openpgp PUBLIC
|
|
||||||
-Wl,--gc-sections
|
|
||||||
)
|
|
||||||
endif(APPLE)
|
|
||||||
target_link_libraries(pico_openpgp PRIVATE pthread m)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
105
CONTRIBUTING.md
Normal file
105
CONTRIBUTING.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
Thank you for your interest in contributing to this project.
|
||||||
|
|
||||||
|
This repository is published in two forms:
|
||||||
|
- a Community Edition released under AGPLv3, and
|
||||||
|
- a proprietary / commercial / Enterprise Edition offered to organizations.
|
||||||
|
|
||||||
|
To keep that model legally clean, we need to be explicit about how contributions can be used.
|
||||||
|
|
||||||
|
By opening a pull request, you agree to all of the following:
|
||||||
|
|
||||||
|
1. **You have the right to contribute this code.**
|
||||||
|
You are either the original author of the contribution, or you have obtained the necessary rights/permissions to contribute it under these terms.
|
||||||
|
|
||||||
|
2. **Dual licensing permission.**
|
||||||
|
You agree that your contribution may be:
|
||||||
|
- merged into this repository, and
|
||||||
|
- used, copied, modified, sublicensed, and redistributed
|
||||||
|
- under the AGPLv3 Community Edition, and
|
||||||
|
- under any proprietary / commercial / Enterprise editions of this project,
|
||||||
|
now or in the future.
|
||||||
|
|
||||||
|
In other words: you are granting the project maintainer(s) the right to include
|
||||||
|
your contribution in both the open-source (AGPLv3) codebase and in closed-source /
|
||||||
|
commercially licensed builds, without any additional approval or payment.
|
||||||
|
|
||||||
|
3. **Attribution.**
|
||||||
|
The maintainers may keep or add attribution lines such as
|
||||||
|
`Copyright (c) <your name>` or an AUTHORS / CONTRIBUTORS list.
|
||||||
|
The maintainers may also make changes for clarity, style, security, refactoring,
|
||||||
|
or integration reasons.
|
||||||
|
|
||||||
|
4. **No automatic SLA.**
|
||||||
|
Submitting a pull request does *not* create any support obligation,
|
||||||
|
service-level agreement, warranty, or guarantee that the contribution
|
||||||
|
will be reviewed, merged, or maintained.
|
||||||
|
|
||||||
|
5. **Potential rejection for business reasons.**
|
||||||
|
Features that fall under "Enterprise / Commercial" functionality
|
||||||
|
(e.g. multi-tenant provisioning at scale, centralized audit trails,
|
||||||
|
corporate policy enforcement, attestation/branding flows, key escrow / dual-control,
|
||||||
|
etc.) may be declined for the public AGPLv3 tree even if technically valid.
|
||||||
|
That is normal: some functionality is intentionally offered only
|
||||||
|
under commercial terms.
|
||||||
|
|
||||||
|
If you are not comfortable with these terms, **do not open a pull request yet.**
|
||||||
|
Instead, please open an Issue to start a discussion.
|
||||||
|
|
||||||
|
## How to contribute (technical side)
|
||||||
|
|
||||||
|
### 1. Bug reports / issues
|
||||||
|
- Please include:
|
||||||
|
- hardware / board revision
|
||||||
|
- firmware / commit hash
|
||||||
|
- exact steps to reproduce
|
||||||
|
- expected vs actual behavior
|
||||||
|
- logs / traces if available (strip secrets)
|
||||||
|
|
||||||
|
Security-sensitive findings: do **not** post publicly.
|
||||||
|
Send a short report by email instead so it can be triaged responsibly.
|
||||||
|
|
||||||
|
### 2. Small fixes / minor improvements
|
||||||
|
- You can open a PR directly for:
|
||||||
|
- bug fixes
|
||||||
|
- portability fixes / new board definitions
|
||||||
|
- clarifications in code comments
|
||||||
|
- build / tooling cleanup
|
||||||
|
- documentation of existing behavior
|
||||||
|
|
||||||
|
Please keep PRs focused (one logical change per PR if possible).
|
||||||
|
|
||||||
|
### 3. Larger features / behavior changes
|
||||||
|
- Please open an Issue first and describe:
|
||||||
|
- what problem you're solving (not just "add feature X")
|
||||||
|
- impact on existing flows / security model
|
||||||
|
- any new dependencies
|
||||||
|
|
||||||
|
This helps avoid doing a bunch of work on something that won't be accepted
|
||||||
|
in the Community Edition.
|
||||||
|
|
||||||
|
### 4. Coding style / security posture
|
||||||
|
- Aim for clarity and small, auditable changes. This code runs in places
|
||||||
|
where secrets live.
|
||||||
|
- No debug backdoors, no "just for testing" shortcuts left enabled.
|
||||||
|
- Keep external dependencies minimal and license-compatible
|
||||||
|
(MIT / Apache 2.0 / similarly permissive is usually fine).
|
||||||
|
|
||||||
|
### 5. Commit / PR format
|
||||||
|
- Use descriptive commit messages ("Fix PIN retry counter wrap" is better than "fix stuff").
|
||||||
|
- In the PR description, please include a short summary of what was changed and why.
|
||||||
|
- At the bottom of the PR description, **copy/paste and confirm the licensing line below**:
|
||||||
|
|
||||||
|
> I confirm that I have read `CONTRIBUTING.md` and I agree that this contribution may be used under both the AGPLv3 Community Edition and any proprietary / commercial / Enterprise editions of this project, now or in the future.
|
||||||
|
|
||||||
|
A PR without that confirmation may be delayed or closed without merge.
|
||||||
|
|
||||||
|
## Thank you
|
||||||
|
|
||||||
|
This project exists because people build on it, break it, fix it,
|
||||||
|
and push it into places it wasn't originally designed to go.
|
||||||
|
|
||||||
|
Whether you are here for research, hacking on hardware,
|
||||||
|
rolling out secure keys for a team, or building a commercial product:
|
||||||
|
thank you for helping improve it.
|
||||||
116
ENTERPRISE.md
Normal file
116
ENTERPRISE.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# Enterprise / Commercial Edition
|
||||||
|
|
||||||
|
This project is offered under two editions:
|
||||||
|
|
||||||
|
## 1. Community Edition (FOSS)
|
||||||
|
|
||||||
|
The Community Edition is released under the GNU Affero General Public License v3 (AGPLv3).
|
||||||
|
|
||||||
|
Intended for:
|
||||||
|
- individual users and researchers
|
||||||
|
- evaluation / prototyping
|
||||||
|
- internal lab / security testing
|
||||||
|
|
||||||
|
You are allowed to:
|
||||||
|
- read and study the source code
|
||||||
|
- modify it
|
||||||
|
- run it internally
|
||||||
|
|
||||||
|
Obligations under AGPLv3:
|
||||||
|
- If you distribute modified firmware/binaries/libraries to third parties, you must provide the corresponding source code of your modifications.
|
||||||
|
- If you run a modified version of this project as a network-accessible service (internal or external), you must offer the source code of those modifications to the users of that service.
|
||||||
|
- No warranty, no support, no SLA.
|
||||||
|
- Enterprise features (bulk provisioning, multi-user policy enforcement, device inventory / revocation, corporate PIN rules, custom attestation/identity, etc.) are NOT included.
|
||||||
|
|
||||||
|
The Community Edition will continue to exist.
|
||||||
|
|
||||||
|
## 2. Enterprise / Commercial Edition
|
||||||
|
|
||||||
|
The Enterprise / Commercial Edition is a proprietary license for organizations that need to:
|
||||||
|
|
||||||
|
- deploy this in production at scale (multiple devices / multiple users / multiple teams)
|
||||||
|
- integrate it into their own physical product or appliance
|
||||||
|
- run it as an internal service (VM / container / private cloud "HSM / auth backend") for multiple internal teams or tenants
|
||||||
|
- enforce internal security policy (admin vs user roles, mandatory PIN rules, secure offboarding / revocation)
|
||||||
|
- avoid any AGPLv3 disclosure obligations for their own modifications and integration code
|
||||||
|
|
||||||
|
### What the Enterprise Edition provides
|
||||||
|
|
||||||
|
**Base license package (always included):**
|
||||||
|
- **Commercial license (proprietary).**
|
||||||
|
You may run and integrate the software/firmware in production — including virtualized / internal-cloud style deployments — without being required to disclose derivative source code under AGPLv3.
|
||||||
|
- **Official signed builds.**
|
||||||
|
You receive signed builds from the original developer so you can prove integrity and provenance.
|
||||||
|
- **Onboarding call (up to 1 hour).**
|
||||||
|
A live remote session to get you from "we have it" to "it’s actually running in our environment" with minimal guesswork.
|
||||||
|
|
||||||
|
**Optional enterprise components (available on demand, scoped and priced per customer):**
|
||||||
|
- **Production / multi-user readiness.**
|
||||||
|
Permission to operate the system with multiple users, multiple devices and multiple teams in real environments.
|
||||||
|
- **Bulk / fleet provisioning.**
|
||||||
|
Automated enrollment for many tokens/devices/users at once (CSV / directory import), scripted onboarding of new users, initial PIN assignment / reset workflows, and role-based access (admin vs user).
|
||||||
|
- **Policy & lifecycle tooling.**
|
||||||
|
Corporate PIN policy enforcement, per-user / per-team access control, device inventory / traceability, and secure revocation / retirement when someone leaves.
|
||||||
|
- **Custom attestation / per-organization identity.**
|
||||||
|
Per-company certificate chains and attestation keys so devices can prove "this token/HSM is officially ours," including anti-cloning / unique device identity for OEM and fleet use.
|
||||||
|
- **Virtualization / internal cloud deployment support.**
|
||||||
|
Guidance and components to run this as an internal service (VM, container, private-cloud HSM/auth backend) serving multiple internal teams or tenants under your brand.
|
||||||
|
- **Post-quantum (PQC) key material handling.**
|
||||||
|
Integration/roadmap support for PQC algorithms (auth / signing) and secure PQC key storage inside the device or service.
|
||||||
|
- **Hierarchical deterministic key derivation (HD).**
|
||||||
|
Wallet-style hierarchical key trees (BIP32-like concepts adapted to this platform) for issuing per-user / per-tenant / per-purpose subkeys without exporting the root secret — e.g. embedded wallet logic, tenant isolation, firmware signing trees, large fleets.
|
||||||
|
- **Cryptographically signed audit trail / tamper-evident event logging.**
|
||||||
|
High-assurance logging of sensitive actions (key use, provisioning, PIN resets, revocations) with integrity protection for forensic / compliance needs.
|
||||||
|
- **Dual-control / two-person approval ("four-eyes").**
|
||||||
|
Require multi-party authorization for high-risk actions such as firmware signing, key export, or critical configuration changes — standard in high-assurance / regulated environments.
|
||||||
|
- **Secure key escrow / disaster recovery design.**
|
||||||
|
Split-secret or escrowed backup strategies so you don’t lose critical signing keys if a single admin disappears or hardware is lost.
|
||||||
|
- **Release-signing / supply-chain hardening pipeline.**
|
||||||
|
Reference tooling and process so every production firmware/binary is signed with hardware-backed keys, proving origin and preventing tampering in transit or at manufacturing.
|
||||||
|
- **Policy-locked hardened mode ("FIPS-style profile").**
|
||||||
|
Restricted algorithms, debug disabled, no raw key export, tamper-evident configuration for regulated / high-assurance deployments.
|
||||||
|
- **Priority support / security response SLA.**
|
||||||
|
A direct line and guaranteed response window for production-impacting security issues.
|
||||||
|
- **White-label demo / pre-sales bundle.**
|
||||||
|
Branded demo firmware + safe onboarding script so you can show "your product" to your own customers without exposing real production secrets.
|
||||||
|
|
||||||
|
These components are NOT automatically bundled. They are available case-by-case depending on your use case and are priced separately.
|
||||||
|
|
||||||
|
### Licensing models
|
||||||
|
|
||||||
|
- **Internal Use License**
|
||||||
|
Internal production use within one legal entity (your company), including internal private cloud / virtualized deployments for multiple internal teams.
|
||||||
|
Optional enterprise components can be added as needed.
|
||||||
|
|
||||||
|
- **OEM / Redistribution / Service License**
|
||||||
|
Integration into a product/appliance you ship to customers, OR operating this as a managed service / hosted feature for external clients or third parties.
|
||||||
|
Optional enterprise components (attestation branding, PQC support, HD key derivation, multi-tenant service hardening, audit trail, etc.) can be added as required.
|
||||||
|
|
||||||
|
Pricing depends on scope, fleet size, number of users/tenants, regulatory requirements, and which optional components you select.
|
||||||
|
|
||||||
|
### Request a quote
|
||||||
|
|
||||||
|
Email: pol@henarejos.me
|
||||||
|
Subject: `ENTERPRISE LICENSE <your company name>`
|
||||||
|
|
||||||
|
Please include:
|
||||||
|
- Company name and country
|
||||||
|
- Intended use:
|
||||||
|
- Internal private deployment
|
||||||
|
- OEM / external service to third parties
|
||||||
|
- Approximate scale (number of devices/tokens, number of users/tenants)
|
||||||
|
- Which optional components you are interested in (bulk provisioning, policy & lifecycle tooling, attestation branding / anti-cloning, virtualization/cloud, PQC, HD key derivation, audit trail, dual-control, key escrow, supply-chain signing, hardened mode, SLA, white-label demo)
|
||||||
|
|
||||||
|
You will receive:
|
||||||
|
1. A short commercial license agreement naming your company.
|
||||||
|
2. Access to the base package (and any optional components agreed).
|
||||||
|
3. Scheduling of the onboarding call.
|
||||||
|
|
||||||
|
## Why Enterprise exists
|
||||||
|
|
||||||
|
- Companies often need hardware-backed security (HSM, FIDO2, OpenPGP, etc.) under their own control, but cannot or will not open-source their internal security workflows.
|
||||||
|
- They also need multi-user / fleet-management features that hobby users do not.
|
||||||
|
- The commercial license funds continued development, maintenance and new hardware support.
|
||||||
|
|
||||||
|
The Community Edition remains AGPLv3.
|
||||||
|
The Enterprise Edition is for production, scale, and legal clarity.
|
||||||
143
LICENSE
143
LICENSE
@@ -1,5 +1,5 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
@@ -7,17 +7,15 @@
|
|||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
software and other kinds of works.
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
The licenses for most software and other practical works are designed
|
||||||
to take away your freedom to share and change the works. By contrast,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
share and change all versions of a program--to make sure it remains free
|
share and change all versions of a program--to make sure it remains free
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
software for all its users.
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
When we speak of free software, we are referring to freedom, not
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
@@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
|
|||||||
want it, that you can change the software or use pieces of it in new
|
want it, that you can change the software or use pieces of it in new
|
||||||
free programs, and that you know you can do these things.
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
Developers that use our General Public Licenses protect your rights
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
you this License which gives you legal permission to copy, distribute
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
and/or modify the software.
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
A secondary benefit of defending all users' freedom is that
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
improvements made in alternate versions of the program, if they
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
receive widespread use, become available for other developers to
|
||||||
or can get the source code. And you must show them these terms so they
|
incorporate. Many developers of free software are heartened and
|
||||||
know their rights.
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
The GNU Affero General Public License is designed specifically to
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
ensure that, in such cases, the modified source code becomes available
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
An older license, called the Affero General Public License and
|
||||||
that there is no warranty for this free software. For both users' and
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
changed, so that their problems will not be attributed erroneously to
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
authors of previous versions.
|
this license.
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
@@ -72,7 +60,7 @@ modification follow.
|
|||||||
|
|
||||||
0. Definitions.
|
0. Definitions.
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
works, such as semiconductor masks.
|
works, such as semiconductor masks.
|
||||||
@@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
|
|||||||
the Program, the only way you could satisfy both those terms and this
|
the Program, the only way you could satisfy both those terms and this
|
||||||
License would be to refrain entirely from conveying the Program.
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
Notwithstanding any other provision of this License, you have
|
||||||
permission to link or combine any covered work with a work licensed
|
permission to link or combine any covered work with a work licensed
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
under version 3 of the GNU General Public License into a single
|
||||||
combined work, and to convey the resulting work. The terms of this
|
combined work, and to convey the resulting work. The terms of this
|
||||||
License will continue to apply to the part which is the covered work,
|
License will continue to apply to the part which is the covered work,
|
||||||
but the special requirements of the GNU Affero General Public License,
|
but the work with which it is combined will remain governed by version
|
||||||
section 13, concerning interaction through a network will apply to the
|
3 of the GNU General Public License.
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
the GNU General Public License from time to time. Such new versions will
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
Each version is given a distinguishing version number. If the
|
||||||
Program specifies that a certain numbered version of the GNU General
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
Public License "or any later version" applies to it, you have the
|
Public License "or any later version" applies to it, you have the
|
||||||
option of following the terms and conditions either of that numbered
|
option of following the terms and conditions either of that numbered
|
||||||
version or of any later version published by the Free Software
|
version or of any later version published by the Free Software
|
||||||
Foundation. If the Program does not specify a version number of the
|
Foundation. If the Program does not specify a version number of the
|
||||||
GNU General Public License, you may choose any version ever published
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
by the Free Software Foundation.
|
by the Free Software Foundation.
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
If the Program specifies that a proxy can decide which future
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
public statement of acceptance of a version permanently authorizes you
|
public statement of acceptance of a version permanently authorizes you
|
||||||
to choose that version for the Program.
|
to choose that version for the Program.
|
||||||
|
|
||||||
@@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||||||
Copyright (C) <year> <name of author>
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
If your software can interact with users remotely through a computer
|
||||||
notice like this when it starts in an interactive mode:
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
<program> Copyright (C) <year> <name of author>
|
interface could display a "Source" link that leads users to an archive
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
of the code. There are many ways you could offer source, and different
|
||||||
This is free software, and you are welcome to redistribute it
|
solutions will be better for different programs; see section 13 for the
|
||||||
under certain conditions; type `show c' for details.
|
specific requirements.
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
<https://www.gnu.org/licenses/>.
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
||||||
49
README.md
49
README.md
@@ -3,6 +3,8 @@ This project aims at transforming your Raspberry Pico or ESP32 microcontroller i
|
|||||||
|
|
||||||
OpenPGP cards are used to manage PGP keys and do cryptographic operations, such as keypair generation, signing and asymmetric deciphering. Pico OpenPGP follows the [**OpenPGP 3.4.1** specifications](https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf "**OpenPGP 3.4.1** specifications"), available at [GnuPG](http://gnupg.org "GnuPG").
|
OpenPGP cards are used to manage PGP keys and do cryptographic operations, such as keypair generation, signing and asymmetric deciphering. Pico OpenPGP follows the [**OpenPGP 3.4.1** specifications](https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf "**OpenPGP 3.4.1** specifications"), available at [GnuPG](http://gnupg.org "GnuPG").
|
||||||
|
|
||||||
|
If you are looking for a OpenPGP + Fido, see: https://github.com/polhenarejos/pico-fido2
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
Pico OpenPGP has implemented the following features:
|
Pico OpenPGP has implemented the following features:
|
||||||
|
|
||||||
@@ -170,6 +172,53 @@ OpenSC relies on PCSC driver, which reads a list (`Info.plist`) that contains a
|
|||||||
- Use the pure-browser online [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner") that commissions the Pico Key on-the-fly without external tools.
|
- Use the pure-browser online [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner") that commissions the Pico Key on-the-fly without external tools.
|
||||||
- Build and configure the project with the proper VID/PID with `USB_VID` and `USB_PID` parameters in `CMake` (see [Build section](#build "Build section")). Note that you cannot distribute the patched/compiled binary if you do not own the VID/PID or have an explicit authorization.
|
- Build and configure the project with the proper VID/PID with `USB_VID` and `USB_PID` parameters in `CMake` (see [Build section](#build "Build section")). Note that you cannot distribute the patched/compiled binary if you do not own the VID/PID or have an explicit authorization.
|
||||||
|
|
||||||
|
## License and Commercial Use
|
||||||
|
|
||||||
|
This project is available under two editions:
|
||||||
|
|
||||||
|
**Community Edition (FOSS)**
|
||||||
|
- Released under the GNU Affero General Public License v3 (AGPLv3).
|
||||||
|
- You are free to study, modify, and run the code, including for internal evaluation.
|
||||||
|
- If you distribute modified binaries/firmware, OR if you run a modified version of this project as a network-accessible service, you must provide the corresponding source code to the users of that binary or service, as required by AGPLv3.
|
||||||
|
- No warranty. No SLA. No guaranteed support.
|
||||||
|
|
||||||
|
**Enterprise / Commercial Edition**
|
||||||
|
- Proprietary license for organizations that want to:
|
||||||
|
- run this in production with multiple users/devices,
|
||||||
|
- integrate it into their own product/appliance,
|
||||||
|
- enforce corporate policies (PIN policy, admin/user roles, revocation),
|
||||||
|
- deploy it as an internal virtualized / cloud-style service,
|
||||||
|
- and *not* be required to publish derivative source code.
|
||||||
|
- Base package includes:
|
||||||
|
- commercial license (no AGPLv3 disclosure obligation for your modifications / integration)
|
||||||
|
- onboarding call
|
||||||
|
- access to officially signed builds
|
||||||
|
- Optional / on-demand enterprise components that can be added case-by-case:
|
||||||
|
- ability to operate in multi-user / multi-device environments
|
||||||
|
- device inventory, traceability and secure revocation/offboarding
|
||||||
|
- custom attestation, per-organization device identity / anti-cloning
|
||||||
|
- virtualization / internal "HSM or auth backend" service for multiple teams or tenants
|
||||||
|
- post-quantum (PQC) key material handling and secure PQC credential storage
|
||||||
|
- hierarchical deterministic key derivation (HD wallet–style key trees for per-user / per-tenant keys, firmware signing trees, etc.)
|
||||||
|
- cryptographically signed audit trail / tamper-evident logging
|
||||||
|
- dual-control / two-person approval for high-risk operations
|
||||||
|
- secure key escrow / disaster recovery strategy
|
||||||
|
- release-signing / supply-chain hardening toolchain
|
||||||
|
- policy-locked hardened mode ("FIPS-style profile")
|
||||||
|
- priority security-response SLA
|
||||||
|
- white-label demo / pre-sales bundle
|
||||||
|
|
||||||
|
Typical licensing models:
|
||||||
|
- Internal use (single legal entity, including internal private cloud / virtualized deployments).
|
||||||
|
- OEM / Redistribution / Service (ship in your product OR offer it as a service to third parties).
|
||||||
|
|
||||||
|
These options are scoped and priced individually depending on which components you actually need.
|
||||||
|
|
||||||
|
For commercial licensing and enterprise features, email pol@henarejos.me
|
||||||
|
Subject: `ENTERPRISE LICENSE <your company name>`
|
||||||
|
|
||||||
|
See `ENTERPRISE.md` for details.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
Pico OpenPGP uses the following libraries or portion of code:
|
Pico OpenPGP uses the following libraries or portion of code:
|
||||||
- MbedTLS for cryptographic operations.
|
- MbedTLS for cryptographic operations.
|
||||||
|
|||||||
@@ -1,108 +1,48 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
VERSION_MAJOR="3"
|
VERSION_MAJOR="4"
|
||||||
VERSION_MINOR="0"
|
VERSION_MINOR="0"
|
||||||
|
NO_EDDSA=0
|
||||||
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
|
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
|
||||||
#if ! [[ -z "${GITHUB_SHA}" ]]; then
|
#if ! [[ -z "${GITHUB_SHA}" ]]; then
|
||||||
# SUFFIX="${SUFFIX}.${GITHUB_SHA}"
|
# SUFFIX="${SUFFIX}.${GITHUB_SHA}"
|
||||||
#fi
|
#fi
|
||||||
|
|
||||||
rm -rf release/*
|
if [[ $1 == "--no-eddsa" ]]; then
|
||||||
|
NO_EDDSA=1
|
||||||
|
echo "Skipping EDDSA build"
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p build_release
|
mkdir -p build_release
|
||||||
mkdir -p release
|
mkdir -p release
|
||||||
|
mkdir -p release_eddsa
|
||||||
|
rm -rf -- release/*
|
||||||
|
if [[ $NO_EDDSA -eq 0 ]]; then
|
||||||
|
rm -rf -- release_eddsa/*
|
||||||
|
fi
|
||||||
cd build_release
|
cd build_release
|
||||||
|
|
||||||
for board in 0xcb_helios \
|
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}"
|
||||||
adafruit_feather_rp2040_usb_host \
|
SECURE_BOOT_PKEY="${SECURE_BOOT_PKEY:-../../ec_private_key.pem}"
|
||||||
adafruit_feather_rp2040 \
|
board_dir=${PICO_SDK_PATH}/src/boards/include/boards
|
||||||
adafruit_itsybitsy_rp2040 \
|
for board in "$board_dir"/*
|
||||||
adafruit_kb2040 \
|
|
||||||
adafruit_macropad_rp2040 \
|
|
||||||
adafruit_qtpy_rp2040 \
|
|
||||||
adafruit_trinkey_qt2040 \
|
|
||||||
amethyst_fpga \
|
|
||||||
archi \
|
|
||||||
arduino_nano_rp2040_connect \
|
|
||||||
cytron_maker_pi_rp2040 \
|
|
||||||
datanoisetv_rp2040_dsp \
|
|
||||||
eetree_gamekit_rp2040 \
|
|
||||||
garatronic_pybstick26_rp2040 \
|
|
||||||
gen4_rp2350_24 \
|
|
||||||
gen4_rp2350_24ct \
|
|
||||||
gen4_rp2350_24t \
|
|
||||||
gen4_rp2350_28 \
|
|
||||||
gen4_rp2350_28ct \
|
|
||||||
gen4_rp2350_28t \
|
|
||||||
gen4_rp2350_32 \
|
|
||||||
gen4_rp2350_32ct \
|
|
||||||
gen4_rp2350_32t \
|
|
||||||
gen4_rp2350_35 \
|
|
||||||
gen4_rp2350_35ct \
|
|
||||||
gen4_rp2350_35t \
|
|
||||||
hellbender_2350A_devboard \
|
|
||||||
ilabs_challenger_rp2350_bconnect \
|
|
||||||
ilabs_challenger_rp2350_wifi_ble \
|
|
||||||
ilabs_opendec02 \
|
|
||||||
melopero_perpetuo_rp2350_lora \
|
|
||||||
melopero_shake_rp2040 \
|
|
||||||
metrotech_xerxes_rp2040 \
|
|
||||||
net8086_usb_interposer \
|
|
||||||
nullbits_bit_c_pro \
|
|
||||||
phyx_rick_tny_rp2350 \
|
|
||||||
pi-plates_micropi \
|
|
||||||
pico \
|
|
||||||
pico_w \
|
|
||||||
pico2 \
|
|
||||||
pimoroni_badger2040 \
|
|
||||||
pimoroni_interstate75 \
|
|
||||||
pimoroni_keybow2040 \
|
|
||||||
pimoroni_motor2040 \
|
|
||||||
pimoroni_pga2040 \
|
|
||||||
pimoroni_pga2350 \
|
|
||||||
pimoroni_pico_plus2_rp2350 \
|
|
||||||
pimoroni_picolipo_4mb \
|
|
||||||
pimoroni_picolipo_16mb \
|
|
||||||
pimoroni_picosystem \
|
|
||||||
pimoroni_plasma2040 \
|
|
||||||
pimoroni_plasma2350 \
|
|
||||||
pimoroni_servo2040 \
|
|
||||||
pimoroni_tiny2040 \
|
|
||||||
pimoroni_tiny2040_2mb \
|
|
||||||
pimoroni_tiny2350 \
|
|
||||||
pololu_3pi_2040_robot \
|
|
||||||
pololu_zumo_2040_robot \
|
|
||||||
seeed_xiao_rp2040 \
|
|
||||||
seeed_xiao_rp2350 \
|
|
||||||
solderparty_rp2040_stamp \
|
|
||||||
solderparty_rp2040_stamp_carrier \
|
|
||||||
solderparty_rp2040_stamp_round_carrier \
|
|
||||||
solderparty_rp2350_stamp_xl \
|
|
||||||
solderparty_rp2350_stamp \
|
|
||||||
sparkfun_micromod \
|
|
||||||
sparkfun_promicro \
|
|
||||||
sparkfun_promicro_rp2350 \
|
|
||||||
sparkfun_thingplus \
|
|
||||||
switchscience_picossci2_conta_base \
|
|
||||||
switchscience_picossci2_dev_board \
|
|
||||||
switchscience_picossci2_micro \
|
|
||||||
switchscience_picossci2_rp2350_breakout \
|
|
||||||
switchscience_picossci2_tiny \
|
|
||||||
tinycircuits_thumby_color_rp2350 \
|
|
||||||
vgaboard \
|
|
||||||
waveshare_rp2040_lcd_0.96 \
|
|
||||||
waveshare_rp2040_lcd_1.28 \
|
|
||||||
waveshare_rp2040_one \
|
|
||||||
waveshare_rp2040_plus_4mb \
|
|
||||||
waveshare_rp2040_plus_16mb \
|
|
||||||
waveshare_rp2040_zero \
|
|
||||||
weact_studio_rp2040_2mb \
|
|
||||||
weact_studio_rp2040_4mb \
|
|
||||||
weact_studio_rp2040_8mb \
|
|
||||||
weact_studio_rp2040_16mb \
|
|
||||||
wiznet_w5100s_evb_pico
|
|
||||||
do
|
do
|
||||||
rm -rf *
|
board_name="$(basename -- "$board" .h)"
|
||||||
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}" cmake .. -DPICO_BOARD=$board
|
rm -rf -- ./*
|
||||||
|
PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name -DSECURE_BOOT_PKEY=${SECURE_BOOT_PKEY}
|
||||||
make -j`nproc`
|
make -j`nproc`
|
||||||
mv pico_openpgp.uf2 ../release/pico_openpgp_$board-$SUFFIX.uf2
|
mv pico_openpgp.uf2 ../release/pico_openpgp_$board_name-$SUFFIX.uf2
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Build with EDDSA
|
||||||
|
|
||||||
|
if [[ $NO_EDDSA -eq 0 ]]; then
|
||||||
|
for board in "$board_dir"/*
|
||||||
|
do
|
||||||
|
board_name="$(basename -- "$board" .h)"
|
||||||
|
rm -rf -- ./*
|
||||||
|
PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name -DSECURE_BOOT_PKEY=${SECURE_BOOT_PKEY} -DENABLE_EDDSA=1
|
||||||
|
make -j`nproc`
|
||||||
|
mv pico_openpgp.uf2 ../release_eddsa/pico_openpgp_$board_name-$SUFFIX-eddsa1.uf2
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|||||||
Submodule pico-keys-sdk updated: 8c25e9be87...d0dea3d0c5
@@ -4,11 +4,14 @@
|
|||||||
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
|
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
|
||||||
|
|
||||||
CONFIG_TINYUSB=y
|
CONFIG_TINYUSB=y
|
||||||
|
CONFIG_TINYUSB_TASK_STACK_SIZE=16384
|
||||||
|
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
|
||||||
CONFIG_PARTITION_TABLE_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
|
CONFIG_PARTITION_TABLE_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
|
||||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
CONFIG_WL_SECTOR_SIZE_512=y
|
CONFIG_WL_SECTOR_SIZE_512=y
|
||||||
CONFIG_WL_SECTOR_MODE_PERF=y
|
CONFIG_WL_SECTOR_MODE_PERF=y
|
||||||
COMPILER_OPTIMIZATION="Performance"
|
COMPILER_OPTIMIZATION="Performance"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS ${SOURCES}
|
SRCS ${SOURCES}
|
||||||
INCLUDE_DIRS . ../../pico-keys-sdk/src ../../pico-keys-sdk/src/fs ../../pico-keys-sdk/src/rng ../../pico-keys-sdk/src/usb
|
INCLUDE_DIRS . ../../pico-keys-sdk/src ../../pico-keys-sdk/src/fs ../../pico-keys-sdk/src/rng ../../pico-keys-sdk/src/usb ../../pico-keys-sdk/tinycbor/src
|
||||||
REQUIRES bootloader_support esp_partition esp_tinyusb zorxx__neopixel mbedtls efuse
|
REQUIRES mbedtls efuse
|
||||||
)
|
)
|
||||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||||
|
|||||||
22
src/openpgp/cmd_activate_file.c
Normal file
22
src/openpgp/cmd_activate_file.c
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
|
||||||
|
int cmd_activate_file() {
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
29
src/openpgp/cmd_challenge.c
Normal file
29
src/openpgp/cmd_challenge.c
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
|
int cmd_challenge() {
|
||||||
|
uint8_t *rb = (uint8_t *) random_bytes_get(apdu.ne);
|
||||||
|
if (!rb) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
memcpy(res_APDU, rb, apdu.ne);
|
||||||
|
res_APDU_size = apdu.ne;
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
69
src/openpgp/cmd_change_pin.c
Normal file
69
src/openpgp/cmd_change_pin.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "otp.h"
|
||||||
|
|
||||||
|
int cmd_change_pin() {
|
||||||
|
if (P1(apdu) != 0x0) {
|
||||||
|
return SW_WRONG_P1P2();
|
||||||
|
}
|
||||||
|
uint16_t fid = 0x1000 | P2(apdu);
|
||||||
|
file_t *pw;
|
||||||
|
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
uint8_t pin_len = file_get_data(pw)[0];
|
||||||
|
uint16_t r = 0;
|
||||||
|
r = check_pin(pw, apdu.data, pin_len);
|
||||||
|
if (r != 0x9000) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if ((r = load_dek()) != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otp_key_1) {
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
dek[IV_SIZE + i] ^= otp_key_1[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t dhash[33];
|
||||||
|
dhash[0] = apdu.nc - pin_len;
|
||||||
|
double_hash_pin(apdu.data + pin_len, apdu.nc - pin_len, dhash + 1);
|
||||||
|
file_put_data(pw, dhash, sizeof(dhash));
|
||||||
|
|
||||||
|
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF);
|
||||||
|
if (!tf) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32] = {0};
|
||||||
|
memcpy(def, file_get_data(tf), file_get_size(tf));
|
||||||
|
if (P2(apdu) == 0x81) {
|
||||||
|
hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw1);
|
||||||
|
memcpy(def + IV_SIZE, dek + IV_SIZE, 32);
|
||||||
|
aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32);
|
||||||
|
}
|
||||||
|
else if (P2(apdu) == 0x83) {
|
||||||
|
hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw3);
|
||||||
|
memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32);
|
||||||
|
aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32);
|
||||||
|
}
|
||||||
|
file_put_data(tf, def, sizeof(def));
|
||||||
|
low_flash_available();
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
128
src/openpgp/cmd_get_data.c
Normal file
128
src/openpgp/cmd_get_data.c
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "asn1.h"
|
||||||
|
|
||||||
|
int cmd_get_data() {
|
||||||
|
if (apdu.nc > 0) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
uint16_t fid = (P1(apdu) << 8) | P2(apdu);
|
||||||
|
file_t *ef;
|
||||||
|
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected
|
||||||
|
ef = currentEF;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
select_file(ef);
|
||||||
|
}
|
||||||
|
if (ef->data) {
|
||||||
|
if (fid == EF_PW_STATUS || fid == EF_HIST_BYTES || fid == EF_FULL_AID || fid == EF_SEC_TPL) {
|
||||||
|
is_gpg = true;
|
||||||
|
}
|
||||||
|
uint16_t fids[] = { 1, fid };
|
||||||
|
uint16_t data_len = parse_do(fids, 1);
|
||||||
|
uint8_t *p = NULL;
|
||||||
|
uint16_t tg = 0;
|
||||||
|
uint16_t tg_len = 0;
|
||||||
|
asn1_ctx_t ctxi;
|
||||||
|
asn1_ctx_init(res_APDU, data_len, &ctxi);
|
||||||
|
if (walk_tlv(&ctxi, &p, &tg, &tg_len, NULL)) {
|
||||||
|
uint8_t dec = 2;
|
||||||
|
if ((tg & 0x1f) == 0x1f) {
|
||||||
|
dec++;
|
||||||
|
}
|
||||||
|
if ((res_APDU[dec - 1] & 0xF0) == 0x80) {
|
||||||
|
dec += (res_APDU[dec - 1] & 0x0F);
|
||||||
|
}
|
||||||
|
if (tg_len + dec == data_len) {
|
||||||
|
memmove(res_APDU, res_APDU + dec, data_len - dec);
|
||||||
|
data_len -= dec;
|
||||||
|
res_APDU_size -= dec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_gpg == false) {
|
||||||
|
uint8_t off = 2;
|
||||||
|
if (P1(apdu) > 0x0) {
|
||||||
|
off++;
|
||||||
|
}
|
||||||
|
if (data_len >= 128) {
|
||||||
|
off++;
|
||||||
|
}
|
||||||
|
if (data_len >= 256) {
|
||||||
|
off++;
|
||||||
|
}
|
||||||
|
memmove(res_APDU + off, res_APDU, data_len);
|
||||||
|
off = 0;
|
||||||
|
if (P1(apdu) > 0x0) {
|
||||||
|
res_APDU[off++] = P1(apdu);
|
||||||
|
res_APDU[off++] = P2(apdu);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_APDU[off++] = P2(apdu);
|
||||||
|
}
|
||||||
|
if (data_len >= 256) {
|
||||||
|
res_APDU[off++] = 0x82;
|
||||||
|
res_APDU[off++] = (data_len >> 8) & 0xff;
|
||||||
|
res_APDU[off++] = data_len & 0xff;
|
||||||
|
}
|
||||||
|
else if (data_len >= 128) {
|
||||||
|
res_APDU[off++] = 0x81;
|
||||||
|
res_APDU[off++] = data_len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_APDU[off++] = data_len;
|
||||||
|
}
|
||||||
|
res_APDU_size += off;
|
||||||
|
}
|
||||||
|
// if (apdu.ne > data_len)
|
||||||
|
// apdu.ne = data_len;
|
||||||
|
}
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_get_next_data() {
|
||||||
|
file_t *ef = NULL;
|
||||||
|
if (apdu.nc > 0) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
if (!currentEF) {
|
||||||
|
return SW_RECORD_NOT_FOUND();
|
||||||
|
}
|
||||||
|
uint16_t fid = (P1(apdu) << 8) | P2(apdu);
|
||||||
|
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
if ((currentEF->fid & 0x1FF0) != (fid & 0x1FF0)) {
|
||||||
|
return SW_WRONG_P1P2();
|
||||||
|
}
|
||||||
|
fid = currentEF->fid + 1; //curentEF contains private DO. so, we select the next one
|
||||||
|
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
select_file(ef);
|
||||||
|
return cmd_get_data();
|
||||||
|
}
|
||||||
216
src/openpgp/cmd_import_data.c
Normal file
216
src/openpgp/cmd_import_data.c
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
#include "esp_compat.h"
|
||||||
|
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||||
|
#else
|
||||||
|
#include "common.h"
|
||||||
|
#endif
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "random.h"
|
||||||
|
#include "do.h"
|
||||||
|
|
||||||
|
uint16_t tag_len(uint8_t **data) {
|
||||||
|
size_t len = *(*data)++;
|
||||||
|
if (len == 0x82) {
|
||||||
|
len = *(*data)++ << 8;
|
||||||
|
len |= *(*data)++;
|
||||||
|
}
|
||||||
|
else if (len == 0x81) {
|
||||||
|
len = *(*data)++;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_import_data() {
|
||||||
|
file_t *ef = NULL;
|
||||||
|
uint16_t fid = 0x0;
|
||||||
|
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
|
||||||
|
return SW_WRONG_P1P2();
|
||||||
|
}
|
||||||
|
if (apdu.nc < 5) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
uint8_t *start = apdu.data;
|
||||||
|
if (*start++ != 0x4D) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
uint16_t tgl = tag_len(&start);
|
||||||
|
if (*start != 0xB6 && *start != 0xB8 && *start != 0xA4) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
if (*start == 0xB6) {
|
||||||
|
fid = EF_PK_SIG;
|
||||||
|
}
|
||||||
|
else if (*start == 0xB8) {
|
||||||
|
fid = EF_PK_DEC;
|
||||||
|
}
|
||||||
|
else if (*start == 0xA4) {
|
||||||
|
fid = EF_PK_AUT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
start++;
|
||||||
|
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
start += (*start + 1);
|
||||||
|
if (*start++ != 0x7F || *start++ != 0x48) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
tgl = tag_len(&start);
|
||||||
|
uint8_t *end = start + tgl, *p[9] = { 0 };
|
||||||
|
uint16_t len[9] = { 0 };
|
||||||
|
while (start < end) {
|
||||||
|
uint8_t tag = *start++;
|
||||||
|
if ((tag >= 0x91 && tag <= 0x97) || tag == 0x99) {
|
||||||
|
len[tag - 0x91] = tag_len(&start);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*start++ != 0x5F || *start++ != 0x48) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
tgl = tag_len(&start);
|
||||||
|
end = start + tgl;
|
||||||
|
for (int t = 0; start < end && t < 9; t++) {
|
||||||
|
if (len[t] > 0) {
|
||||||
|
p[t] = start;
|
||||||
|
start += len[t];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file_t *algo_ef = search_by_fid(fid - 0x0010, NULL, SPECIFY_EF);
|
||||||
|
if (!algo_ef) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
const uint8_t *algo = algorithm_attr_rsa2k + 1;
|
||||||
|
uint16_t algo_len = algorithm_attr_rsa2k[0];
|
||||||
|
if (algo_ef && algo_ef->data) {
|
||||||
|
algo = file_get_data(algo_ef);
|
||||||
|
algo_len = file_get_size(algo_ef);
|
||||||
|
}
|
||||||
|
int r = 0;
|
||||||
|
if (algo[0] == ALGO_RSA) {
|
||||||
|
mbedtls_rsa_context rsa;
|
||||||
|
if (p[0] == NULL || len[0] == 0 || p[1] == NULL || len[1] == 0 || p[2] == NULL ||
|
||||||
|
len[2] == 0) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
mbedtls_rsa_init(&rsa);
|
||||||
|
r = mbedtls_mpi_read_binary(&rsa.E, p[0], len[0]);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = mbedtls_mpi_read_binary(&rsa.P, p[1], len[1]);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = mbedtls_mpi_read_binary(&rsa.Q, p[2], len[2]);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = mbedtls_rsa_import(&rsa, NULL, &rsa.P, &rsa.Q, NULL, &rsa.E);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = mbedtls_rsa_complete(&rsa);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = mbedtls_rsa_check_privkey(&rsa);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = store_keys(&rsa, ALGO_RSA, fid, true);
|
||||||
|
make_rsa_response(&rsa);
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (algo[0] == ALGO_ECDSA || algo[0] == ALGO_ECDH || algo[0] == ALGO_EDDSA) {
|
||||||
|
mbedtls_ecp_keypair ecdsa;
|
||||||
|
if (p[1] == NULL || len[1] == 0) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
mbedtls_ecp_group_id gid = get_ec_group_id_from_attr(algo + 1, algo_len - 1);
|
||||||
|
if (gid == MBEDTLS_ECP_DP_NONE) {
|
||||||
|
return SW_FUNC_NOT_SUPPORTED();
|
||||||
|
}
|
||||||
|
mbedtls_ecp_keypair_init(&ecdsa);
|
||||||
|
if (gid == MBEDTLS_ECP_DP_CURVE25519) {
|
||||||
|
mbedtls_ecp_group_load(&ecdsa.grp, gid);
|
||||||
|
r = mbedtls_mpi_read_binary(&ecdsa.d, p[1], len[1]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = mbedtls_ecp_read_key(gid, &ecdsa, p[1], len[1]);
|
||||||
|
}
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_ecp_keypair_free(&ecdsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
#ifdef MBEDTLS_EDDSA_C
|
||||||
|
if (ecdsa.grp.id == MBEDTLS_ECP_DP_ED25519) {
|
||||||
|
r = mbedtls_ecp_point_edwards(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, random_gen, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
r = mbedtls_ecp_mul(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, &ecdsa.grp.G, random_gen, NULL);
|
||||||
|
}
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_ecp_keypair_free(&ecdsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = store_keys(&ecdsa, ALGO_ECDSA, fid, true);
|
||||||
|
make_ecdsa_response(&ecdsa);
|
||||||
|
mbedtls_ecp_keypair_free(&ecdsa);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SW_FUNC_NOT_SUPPORTED();
|
||||||
|
}
|
||||||
|
if (fid == EF_PK_SIG) {
|
||||||
|
reset_sig_count();
|
||||||
|
}
|
||||||
|
file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
|
||||||
|
if (!pbef) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
r = file_put_data(pbef, res_APDU, res_APDU_size);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
res_APDU_size = 0; //make_*_response sets a response. we need to overwrite
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
77
src/openpgp/cmd_internal_aut.c
Normal file
77
src/openpgp/cmd_internal_aut.c
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "do.h"
|
||||||
|
|
||||||
|
int cmd_internal_aut() {
|
||||||
|
if (P1(apdu) != 0x00 || P2(apdu) != 0x00) {
|
||||||
|
return SW_WRONG_P1P2();
|
||||||
|
}
|
||||||
|
if (!has_pw3 && !has_pw2) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
file_t *algo_ef = search_by_fid(algo_aut, NULL, SPECIFY_EF);
|
||||||
|
if (!algo_ef) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
const uint8_t *algo = algorithm_attr_rsa2k + 1;
|
||||||
|
if (algo_ef && algo_ef->data) {
|
||||||
|
algo = file_get_data(algo_ef);
|
||||||
|
}
|
||||||
|
file_t *ef = search_by_fid(pk_aut, NULL, SPECIFY_EF);
|
||||||
|
if (!ef) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (wait_button_pressed_fid(EF_UIF_AUT) == true) {
|
||||||
|
return SW_SECURE_MESSAGE_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
int r = PICOKEY_OK;
|
||||||
|
if (algo[0] == ALGO_RSA) {
|
||||||
|
mbedtls_rsa_context ctx;
|
||||||
|
mbedtls_rsa_init(&ctx);
|
||||||
|
r = load_private_key_rsa(&ctx, ef, true);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
mbedtls_rsa_free(&ctx);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
size_t olen = 0;
|
||||||
|
r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
|
||||||
|
mbedtls_rsa_free(&ctx);
|
||||||
|
if (r != 0) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
res_APDU_size = olen;
|
||||||
|
}
|
||||||
|
else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
|
||||||
|
mbedtls_ecp_keypair ctx;
|
||||||
|
mbedtls_ecp_keypair_init(&ctx);
|
||||||
|
r = load_private_key_ecdsa(&ctx, ef, true);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
mbedtls_ecp_keypair_free(&ctx);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
size_t olen = 0;
|
||||||
|
r = ecdsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
|
||||||
|
mbedtls_ecp_keypair_free(&ctx);
|
||||||
|
if (r != 0) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
res_APDU_size = olen;
|
||||||
|
}
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
138
src/openpgp/cmd_keypair_gen.c
Normal file
138
src/openpgp/cmd_keypair_gen.c
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "do.h"
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
|
int cmd_keypair_gen() {
|
||||||
|
if (P2(apdu) != 0x0) {
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
|
}
|
||||||
|
if (apdu.nc != 2 && apdu.nc != 5) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
if (!has_pw3 && P1(apdu) == 0x80) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t fid = 0x0;
|
||||||
|
int r = PICOKEY_OK;
|
||||||
|
if (apdu.data[0] == 0xB6) {
|
||||||
|
fid = EF_PK_SIG;
|
||||||
|
}
|
||||||
|
else if (apdu.data[0] == 0xB8) {
|
||||||
|
fid = EF_PK_DEC;
|
||||||
|
}
|
||||||
|
else if (apdu.data[0] == 0xA4) {
|
||||||
|
fid = EF_PK_AUT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
|
||||||
|
file_t *algo_ef = search_by_fid(fid - 0x0010, NULL, SPECIFY_EF);
|
||||||
|
if (!algo_ef) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
const uint8_t *algo = algorithm_attr_rsa2k + 1;
|
||||||
|
uint16_t algo_len = algorithm_attr_rsa2k[0];
|
||||||
|
if (algo_ef && algo_ef->data) {
|
||||||
|
algo = file_get_data(algo_ef);
|
||||||
|
algo_len = file_get_size(algo_ef);
|
||||||
|
}
|
||||||
|
if (P1(apdu) == 0x80) { //generate
|
||||||
|
if (algo[0] == ALGO_RSA) {
|
||||||
|
int exponent = 65537, nlen = (algo[1] << 8) | algo[2];
|
||||||
|
printf("KEYPAIR RSA %d\r\n", nlen);
|
||||||
|
//if (nlen != 2048 && nlen != 4096)
|
||||||
|
// return SW_FUNC_NOT_SUPPORTED();
|
||||||
|
mbedtls_rsa_context rsa;
|
||||||
|
mbedtls_rsa_init(&rsa);
|
||||||
|
uint8_t index = 0;
|
||||||
|
r = mbedtls_rsa_gen_key(&rsa, random_gen, &index, nlen, exponent);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = store_keys(&rsa, ALGO_RSA, fid, true);
|
||||||
|
make_rsa_response(&rsa);
|
||||||
|
mbedtls_rsa_free(&rsa);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
|
||||||
|
printf("KEYPAIR ECDSA\r\n");
|
||||||
|
mbedtls_ecp_group_id gid = get_ec_group_id_from_attr(algo + 1, algo_len - 1);
|
||||||
|
if (gid == MBEDTLS_ECP_DP_NONE) {
|
||||||
|
return SW_FUNC_NOT_SUPPORTED();
|
||||||
|
}
|
||||||
|
mbedtls_ecp_keypair ecdsa;
|
||||||
|
mbedtls_ecp_keypair_init(&ecdsa);
|
||||||
|
uint8_t index = 0;
|
||||||
|
r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, &index);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_ecp_keypair_free(&ecdsa);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
r = store_keys(&ecdsa, algo[0], fid, true);
|
||||||
|
make_ecdsa_response(&ecdsa);
|
||||||
|
mbedtls_ecp_keypair_free(&ecdsa);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SW_FUNC_NOT_SUPPORTED();
|
||||||
|
}
|
||||||
|
file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
|
||||||
|
if (!pbef) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
r = file_put_data(pbef, res_APDU, res_APDU_size);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
if (fid == EF_PK_SIG) {
|
||||||
|
reset_sig_count();
|
||||||
|
}
|
||||||
|
else if (fid == EF_PK_DEC) {
|
||||||
|
// OpenPGP does not allow generating AES keys. So, we generate a new one when gen for DEC is called.
|
||||||
|
// It is a 256 AES key by default.
|
||||||
|
uint8_t aes_key[32]; //maximum AES key size
|
||||||
|
uint8_t key_size = 32;
|
||||||
|
memcpy(aes_key, random_bytes_get(key_size), key_size);
|
||||||
|
r = store_keys(aes_key, ALGO_AES_256, EF_AES_KEY, true);
|
||||||
|
/* if storing the key fails, we silently continue */
|
||||||
|
//if (r != PICOKEY_OK)
|
||||||
|
// return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
low_flash_available();
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
else if (P1(apdu) == 0x81) { //read
|
||||||
|
file_t *ef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
|
||||||
|
if (!file_has_data(ef)) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
res_APDU_size = file_get_size(ef);
|
||||||
|
memcpy(res_APDU, file_get_data(ef), res_APDU_size);
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
|
}
|
||||||
49
src/openpgp/cmd_mse.c
Normal file
49
src/openpgp/cmd_mse.c
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
|
||||||
|
int cmd_mse() {
|
||||||
|
if (P1(apdu) != 0x41 || (P2(apdu) != 0xA4 && P2(apdu) != 0xB8)) {
|
||||||
|
return SW_WRONG_P1P2();
|
||||||
|
}
|
||||||
|
if (apdu.data[0] != 0x83 || apdu.data[1] != 0x1 ||
|
||||||
|
(apdu.data[2] != 0x2 && apdu.data[2] != 0x3)) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
if (P2(apdu) == 0xA4) {
|
||||||
|
if (apdu.data[2] == 0x2) {
|
||||||
|
algo_dec = EF_ALGO_PRIV2;
|
||||||
|
pk_dec = EF_PK_DEC;
|
||||||
|
}
|
||||||
|
else if (apdu.data[2] == 0x3) {
|
||||||
|
algo_dec = EF_ALGO_PRIV3;
|
||||||
|
pk_dec = EF_PK_AUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (P2(apdu) == 0xB8) {
|
||||||
|
if (apdu.data[2] == 0x2) {
|
||||||
|
algo_aut = EF_ALGO_PRIV2;
|
||||||
|
pk_aut = EF_PK_DEC;
|
||||||
|
}
|
||||||
|
else if (apdu.data[2] == 0x3) {
|
||||||
|
algo_aut = EF_ALGO_PRIV3;
|
||||||
|
pk_aut = EF_PK_AUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
213
src/openpgp/cmd_pso.c
Normal file
213
src/openpgp/cmd_pso.c
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
#include "esp_compat.h"
|
||||||
|
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||||
|
#else
|
||||||
|
#include "common.h"
|
||||||
|
#endif
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "do.h"
|
||||||
|
#include "random.h"
|
||||||
|
#include "mbedtls/ecdh.h"
|
||||||
|
#include "mbedtls/asn1.h"
|
||||||
|
|
||||||
|
int cmd_pso() {
|
||||||
|
uint16_t algo_fid = 0x0, pk_fid = 0x0;
|
||||||
|
bool is_aes = false;
|
||||||
|
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
|
||||||
|
if (!has_pw3 && !has_pw1) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
algo_fid = EF_ALGO_PRIV1;
|
||||||
|
pk_fid = EF_PK_SIG;
|
||||||
|
}
|
||||||
|
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
|
||||||
|
if (!has_pw3 && !has_pw2) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
algo_fid = algo_dec;
|
||||||
|
pk_fid = pk_dec;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
|
}
|
||||||
|
file_t *algo_ef = search_by_fid(algo_fid, NULL, SPECIFY_EF);
|
||||||
|
if (!algo_ef) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
const uint8_t *algo = algorithm_attr_rsa2k + 1;
|
||||||
|
if (algo_ef && algo_ef->data) {
|
||||||
|
algo = file_get_data(algo_ef);
|
||||||
|
}
|
||||||
|
if (apdu.data[0] == 0x2) { //AES PSO?
|
||||||
|
if (((apdu.nc - 1) % 16 == 0 && P1(apdu) == 0x80 && P2(apdu) == 0x86) ||
|
||||||
|
(apdu.nc % 16 == 0 && P1(apdu) == 0x86 && P2(apdu) == 0x80)) {
|
||||||
|
pk_fid = EF_AES_KEY;
|
||||||
|
is_aes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_t *ef = search_by_fid(pk_fid, NULL, SPECIFY_EF);
|
||||||
|
if (!ef) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (wait_button_pressed_fid(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) {
|
||||||
|
return SW_SECURE_MESSAGE_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
int r = PICOKEY_OK;
|
||||||
|
int key_size = file_get_size(ef);
|
||||||
|
if (is_aes) {
|
||||||
|
uint8_t aes_key[32];
|
||||||
|
r = load_aes_key(aes_key, ef);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
memset(aes_key, 0, sizeof(aes_key));
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { //decipher
|
||||||
|
r = aes_decrypt(aes_key, NULL, key_size, PICO_KEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1);
|
||||||
|
memset(aes_key, 0, sizeof(aes_key));
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
memcpy(res_APDU, apdu.data + 1, apdu.nc - 1);
|
||||||
|
res_APDU_size = apdu.nc - 1;
|
||||||
|
}
|
||||||
|
else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { //encipher
|
||||||
|
r = aes_encrypt(aes_key, NULL, key_size, PICO_KEYS_AES_MODE_CBC, apdu.data, apdu.nc);
|
||||||
|
memset(aes_key, 0, sizeof(aes_key));
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
res_APDU[0] = 0x2;
|
||||||
|
memcpy(res_APDU + 1, apdu.data, apdu.nc);
|
||||||
|
res_APDU_size = apdu.nc + 1;
|
||||||
|
}
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
if (algo[0] == ALGO_RSA) {
|
||||||
|
mbedtls_rsa_context ctx;
|
||||||
|
mbedtls_rsa_init(&ctx);
|
||||||
|
r = load_private_key_rsa(&ctx, ef, true);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
mbedtls_rsa_free(&ctx);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
|
||||||
|
size_t olen = 0;
|
||||||
|
r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
|
||||||
|
mbedtls_rsa_free(&ctx);
|
||||||
|
if (r != 0) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
res_APDU_size = olen;
|
||||||
|
//apdu.ne = key_size;
|
||||||
|
inc_sig_count();
|
||||||
|
}
|
||||||
|
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
|
||||||
|
if (apdu.nc < key_size) { //needs padding
|
||||||
|
memset(apdu.data + apdu.nc, 0, key_size - apdu.nc);
|
||||||
|
}
|
||||||
|
size_t olen = 0;
|
||||||
|
r = mbedtls_rsa_pkcs1_decrypt(&ctx,
|
||||||
|
random_gen,
|
||||||
|
NULL,
|
||||||
|
&olen,
|
||||||
|
apdu.data + 1,
|
||||||
|
res_APDU,
|
||||||
|
key_size);
|
||||||
|
mbedtls_rsa_free(&ctx);
|
||||||
|
if (r != 0) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
res_APDU_size = olen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
|
||||||
|
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
|
||||||
|
mbedtls_ecp_keypair ctx;
|
||||||
|
mbedtls_ecp_keypair_init(&ctx);
|
||||||
|
r = load_private_key_ecdsa(&ctx, ef, true);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
mbedtls_ecp_keypair_free(&ctx);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
size_t olen = 0;
|
||||||
|
r = ecdsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
|
||||||
|
mbedtls_ecp_keypair_free(&ctx);
|
||||||
|
if (r != 0) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
res_APDU_size = olen;
|
||||||
|
inc_sig_count();
|
||||||
|
}
|
||||||
|
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
|
||||||
|
mbedtls_ecdh_context ctx;
|
||||||
|
uint8_t kdata[67];
|
||||||
|
uint8_t *data = apdu.data, *end = data + apdu.nc;
|
||||||
|
size_t len = 0;
|
||||||
|
if (mbedtls_asn1_get_tag(&data, end, &len, 0xA6) != 0) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
if (*data++ != 0x7f) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
if (mbedtls_asn1_get_tag(&data, end, &len,
|
||||||
|
0x49) != 0 ||
|
||||||
|
mbedtls_asn1_get_tag(&data, end, &len, 0x86) != 0) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
//if (len != 2*key_size-1)
|
||||||
|
// return SW_WRONG_LENGTH();
|
||||||
|
memcpy(kdata, file_get_data(ef), key_size);
|
||||||
|
if (dek_decrypt(kdata, key_size) != 0) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
mbedtls_ecdh_init(&ctx);
|
||||||
|
mbedtls_ecp_group_id gid = kdata[0];
|
||||||
|
r = mbedtls_ecdh_setup(&ctx, gid);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_ecdh_free(&ctx);
|
||||||
|
return SW_DATA_INVALID();
|
||||||
|
}
|
||||||
|
r = mbedtls_ecp_read_key(gid, (mbedtls_ecdsa_context *)&ctx.ctx.mbed_ecdh, kdata + 1, key_size - 1);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_ecdh_free(&ctx);
|
||||||
|
return SW_DATA_INVALID();
|
||||||
|
}
|
||||||
|
r = mbedtls_ecdh_read_public(&ctx, data - 1, len + 1);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_ecdh_free(&ctx);
|
||||||
|
return SW_DATA_INVALID();
|
||||||
|
}
|
||||||
|
size_t olen = 0;
|
||||||
|
r = mbedtls_ecdh_calc_secret(&ctx,
|
||||||
|
&olen,
|
||||||
|
res_APDU,
|
||||||
|
MBEDTLS_ECP_MAX_BYTES,
|
||||||
|
random_gen,
|
||||||
|
NULL);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_ecdh_free(&ctx);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
res_APDU_size = olen;
|
||||||
|
mbedtls_ecdh_free(&ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
74
src/openpgp/cmd_put_data.c
Normal file
74
src/openpgp/cmd_put_data.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
|
||||||
|
int cmd_put_data() {
|
||||||
|
uint16_t fid = (P1(apdu) << 8) | P2(apdu);
|
||||||
|
file_t *ef;
|
||||||
|
if (fid == EF_RESET_CODE) {
|
||||||
|
fid = EF_RC;
|
||||||
|
}
|
||||||
|
else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) {
|
||||||
|
fid |= 0x1000;
|
||||||
|
}
|
||||||
|
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
if (fid == EF_PW_STATUS) {
|
||||||
|
fid = EF_PW_PRIV;
|
||||||
|
apdu.nc = 4; //we silently ommit the reset parameters
|
||||||
|
}
|
||||||
|
if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected
|
||||||
|
ef = currentEF;
|
||||||
|
}
|
||||||
|
if (apdu.nc > 0 && (ef->type & FILE_DATA_FLASH)) {
|
||||||
|
int r = 0;
|
||||||
|
if (fid == EF_RC) {
|
||||||
|
has_rc = false;
|
||||||
|
if ((r = load_dek()) != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
uint8_t dhash[33];
|
||||||
|
dhash[0] = apdu.nc;
|
||||||
|
double_hash_pin(apdu.data, apdu.nc, dhash + 1);
|
||||||
|
r = file_put_data(ef, dhash, sizeof(dhash));
|
||||||
|
|
||||||
|
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF);
|
||||||
|
if (!tf) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32];
|
||||||
|
memcpy(def, file_get_data(tf), file_get_size(tf));
|
||||||
|
hash_multi(apdu.data, apdu.nc, session_rc);
|
||||||
|
memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32);
|
||||||
|
aes_encrypt_cfb_256(session_rc, def, def + IV_SIZE + 32, 32);
|
||||||
|
r = file_put_data(tf, def, sizeof(def));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = file_put_data(ef, apdu.data, apdu.nc);
|
||||||
|
}
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
return SW_MEMORY_FAILURE();
|
||||||
|
}
|
||||||
|
low_flash_available();
|
||||||
|
}
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
91
src/openpgp/cmd_reset_retry.c
Normal file
91
src/openpgp/cmd_reset_retry.c
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "otp.h"
|
||||||
|
|
||||||
|
int cmd_reset_retry() {
|
||||||
|
if (P2(apdu) != 0x81) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (P1(apdu) == 0x0 || P1(apdu) == 0x2) {
|
||||||
|
int newpin_len = 0;
|
||||||
|
file_t *pw = NULL;
|
||||||
|
has_pw1 = false;
|
||||||
|
if (!(pw = search_by_fid(EF_PW1, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (P1(apdu) == 0x0) {
|
||||||
|
file_t *rc;
|
||||||
|
if (!(rc = search_by_fid(EF_RC, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
uint8_t pin_len = file_get_data(rc)[0];
|
||||||
|
if (apdu.nc <= pin_len) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
uint16_t r = check_pin(rc, apdu.data, pin_len);
|
||||||
|
if (r != 0x9000) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
newpin_len = apdu.nc - pin_len;
|
||||||
|
has_rc = true;
|
||||||
|
hash_multi(apdu.data, pin_len, session_rc);
|
||||||
|
has_pw1 = has_pw3 = false;
|
||||||
|
isUserAuthenticated = false;
|
||||||
|
}
|
||||||
|
else if (P1(apdu) == 0x2) {
|
||||||
|
if (!has_pw3) {
|
||||||
|
return SW_CONDITIONS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
newpin_len = apdu.nc;
|
||||||
|
}
|
||||||
|
int r = 0;
|
||||||
|
if ((r = load_dek()) != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF);
|
||||||
|
if (!tf) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (otp_key_1) {
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
dek[IV_SIZE + i] ^= otp_key_1[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32];
|
||||||
|
memcpy(def, file_get_data(tf), file_get_size(tf));
|
||||||
|
hash_multi(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pw1);
|
||||||
|
memcpy(def + IV_SIZE, dek + IV_SIZE, 32);
|
||||||
|
aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32);
|
||||||
|
r = file_put_data(tf, def, sizeof(def));
|
||||||
|
|
||||||
|
uint8_t dhash[33];
|
||||||
|
dhash[0] = newpin_len;
|
||||||
|
double_hash_pin(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 1);
|
||||||
|
file_put_data(pw, dhash, sizeof(dhash));
|
||||||
|
if (pin_reset_retries(pw, true) != PICOKEY_OK) {
|
||||||
|
return SW_MEMORY_FAILURE();
|
||||||
|
}
|
||||||
|
low_flash_available();
|
||||||
|
if ((r = load_dek()) != PICOKEY_OK) {
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
|
}
|
||||||
86
src/openpgp/cmd_select.c
Normal file
86
src/openpgp/cmd_select.c
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
|
||||||
|
int cmd_select() {
|
||||||
|
uint8_t p1 = P1(apdu);
|
||||||
|
uint8_t p2 = P2(apdu);
|
||||||
|
file_t *pe = NULL;
|
||||||
|
uint16_t fid = 0x0;
|
||||||
|
|
||||||
|
if (apdu.nc >= 2) {
|
||||||
|
fid = get_uint16_t_be(apdu.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pe) {
|
||||||
|
if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent
|
||||||
|
if (apdu.nc == 0) {
|
||||||
|
pe = (file_t *) MF;
|
||||||
|
//ac_fini();
|
||||||
|
}
|
||||||
|
else if (apdu.nc == 2) {
|
||||||
|
if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p1 == 0x01) { //Select child DF - DF identifier
|
||||||
|
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p1 == 0x02) { //Select EF under the current DF - EF identifier
|
||||||
|
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p1 == 0x03) { //Select parent DF of the current DF - Absent
|
||||||
|
if (apdu.nc != 0) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier
|
||||||
|
if (!(pe = search_by_name(apdu.data, apdu.nc))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (card_terminated) {
|
||||||
|
return set_res_sw(0x62, 0x85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier
|
||||||
|
if (!(pe = search_by_path(apdu.data, apdu.nc, MF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier
|
||||||
|
if (!(pe = search_by_path(apdu.data, apdu.nc, currentDF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) {
|
||||||
|
if ((p2 & 0xfc) == 0x04) {
|
||||||
|
process_fci(pe, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
|
}
|
||||||
|
select_file(pe);
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
54
src/openpgp/cmd_select_data.c
Normal file
54
src/openpgp/cmd_select_data.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
|
||||||
|
int cmd_select_data() {
|
||||||
|
file_t *ef = NULL;
|
||||||
|
uint16_t fid = 0x0;
|
||||||
|
if (P2(apdu) != 0x4) {
|
||||||
|
return SW_WRONG_P1P2();
|
||||||
|
}
|
||||||
|
if (apdu.data[0] != 0x60) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
if (apdu.nc != apdu.data[1] + 2 || apdu.nc < 5) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
if (apdu.data[2] != 0x5C) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
if (apdu.data[3] == 2) {
|
||||||
|
fid = (apdu.data[4] << 8) | apdu.data[5];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fid = apdu.data[4];
|
||||||
|
}
|
||||||
|
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
fid &= ~0x6000; //Now get private DO
|
||||||
|
fid += P1(apdu);
|
||||||
|
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
select_file(ef);
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
37
src/openpgp/cmd_terminate_df.c
Normal file
37
src/openpgp/cmd_terminate_df.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
|
||||||
|
int cmd_terminate_df() {
|
||||||
|
if (P1(apdu) != 0x0 || P2(apdu) != 0x0) {
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
|
}
|
||||||
|
file_t *retries;
|
||||||
|
if (!(retries = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (!has_pw3 && *(file_get_data(retries) + 6) > 0) {
|
||||||
|
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||||
|
}
|
||||||
|
if (apdu.nc != 0) {
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
initialize_flash(true);
|
||||||
|
scan_files_openpgp();
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
67
src/openpgp/cmd_verify.c
Normal file
67
src/openpgp/cmd_verify.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
|
||||||
|
int cmd_verify() {
|
||||||
|
uint8_t p1 = P1(apdu);
|
||||||
|
uint8_t p2 = P2(apdu);
|
||||||
|
|
||||||
|
if (p1 == 0xFF) {
|
||||||
|
if (apdu.nc != 0) {
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
}
|
||||||
|
if (p2 == 0x81) {
|
||||||
|
has_pw1 = false;
|
||||||
|
}
|
||||||
|
else if (p2 == 0x82) {
|
||||||
|
has_pw2 = false;
|
||||||
|
}
|
||||||
|
else if (p2 == 0x83) {
|
||||||
|
has_pw3 = false;
|
||||||
|
}
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
else if (p1 != 0x0 || (p2 & 0x60) != 0x0) {
|
||||||
|
return SW_WRONG_P1P2();
|
||||||
|
}
|
||||||
|
uint16_t fid = 0x1000 | p2;
|
||||||
|
if (fid == EF_RC && apdu.nc > 0) {
|
||||||
|
fid = EF_PW1;
|
||||||
|
}
|
||||||
|
file_t *pw, *pw_status;
|
||||||
|
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (file_get_data(pw)[0] == 0) { //not initialized
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
|
}
|
||||||
|
if (apdu.nc > 0) {
|
||||||
|
return check_pin(pw, apdu.data, apdu.nc);
|
||||||
|
}
|
||||||
|
uint8_t retries = *(file_get_data(pw_status) + 3 + (fid & 0xf));
|
||||||
|
if (retries == 0) {
|
||||||
|
return SW_PIN_BLOCKED();
|
||||||
|
}
|
||||||
|
if ((p2 == 0x81 && has_pw1) || (p2 == 0x82 && has_pw2) || (p2 == 0x83 && has_pw3)) {
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
return set_res_sw(0x63, 0xc0 | retries);
|
||||||
|
}
|
||||||
26
src/openpgp/cmd_version.c
Normal file
26
src/openpgp/cmd_version.c
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
int cmd_version_openpgp() {
|
||||||
|
res_APDU[res_APDU_size++] = PIPGP_VERSION_MAJOR;
|
||||||
|
res_APDU[res_APDU_size++] = PIPGP_VERSION_MINOR;
|
||||||
|
res_APDU[res_APDU_size++] = 0x0;
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
23
src/openpgp/defs.c
Normal file
23
src/openpgp/defs.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
uint8_t PICO_PRODUCT = 3;
|
||||||
|
uint8_t PICO_VERSION_MAJOR = PIPGP_VERSION_MAJOR;
|
||||||
|
uint8_t PICO_VERSION_MINOR = PIPGP_VERSION_MINOR;
|
||||||
389
src/openpgp/do.c
Normal file
389
src/openpgp/do.c
Normal file
@@ -0,0 +1,389 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpgp.h"
|
||||||
|
#include "asn1.h"
|
||||||
|
|
||||||
|
int parse_do(uint16_t *fids, int mode) {
|
||||||
|
int len = 0;
|
||||||
|
file_t *ef;
|
||||||
|
for (int i = 0; i < fids[0]; i++) {
|
||||||
|
if ((ef = search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) {
|
||||||
|
uint16_t data_len;
|
||||||
|
if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
|
||||||
|
data_len = ((int (*)(const file_t *, int))(ef->data))((const file_t *) ef, mode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data_len = file_get_size(ef);
|
||||||
|
if (mode == 1) {
|
||||||
|
if (fids[0] > 1 && res_APDU_size > 0) {
|
||||||
|
if (fids[i + 1] < 0x0100) {
|
||||||
|
res_APDU[res_APDU_size++] = fids[i + 1] & 0xff;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_APDU[res_APDU_size++] = fids[i + 1] >> 8;
|
||||||
|
res_APDU[res_APDU_size++] = fids[i + 1] & 0xff;
|
||||||
|
}
|
||||||
|
res_APDU_size += format_tlv_len(data_len, res_APDU + res_APDU_size);
|
||||||
|
}
|
||||||
|
if (file_has_data(ef)) {
|
||||||
|
memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
|
||||||
|
}
|
||||||
|
res_APDU_size += data_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len += data_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_trium(uint16_t fid, uint8_t num, size_t size) {
|
||||||
|
for (uint8_t i = 0; i < num; i++) {
|
||||||
|
file_t *ef;
|
||||||
|
if ((ef = search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) {
|
||||||
|
uint16_t data_len = file_get_size(ef);
|
||||||
|
memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
|
||||||
|
res_APDU_size += data_len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memset(res_APDU + res_APDU_size, 0, size);
|
||||||
|
res_APDU_size += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num * size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_ch_data(const file_t *f, int mode) {
|
||||||
|
uint16_t fids[] = {
|
||||||
|
3,
|
||||||
|
EF_CH_NAME, EF_LANG_PREF, EF_SEX,
|
||||||
|
};
|
||||||
|
res_APDU[res_APDU_size++] = EF_CH_DATA & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 0x82;
|
||||||
|
uint8_t *lp = res_APDU + res_APDU_size;
|
||||||
|
res_APDU_size += 2;
|
||||||
|
parse_do(fids, mode);
|
||||||
|
uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
|
||||||
|
*lp++ = lpdif >> 8;
|
||||||
|
*lp++ = lpdif & 0xff;
|
||||||
|
return lpdif + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_sec_tpl(const file_t *f, int mode) {
|
||||||
|
res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 5;
|
||||||
|
file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
|
||||||
|
if (ef && ef->data) {
|
||||||
|
res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 3;
|
||||||
|
memcpy(res_APDU + res_APDU_size, file_get_data(ef), 3);
|
||||||
|
res_APDU_size += 3;
|
||||||
|
}
|
||||||
|
return 5 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_ch_cert(const file_t *f, int mode) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_fp(const file_t *f, int mode) {
|
||||||
|
res_APDU[res_APDU_size++] = EF_FP & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 60;
|
||||||
|
return parse_trium(EF_FP_SIG, 3, 20) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_cafp(const file_t *f, int mode) {
|
||||||
|
res_APDU[res_APDU_size++] = EF_CA_FP & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 60;
|
||||||
|
return parse_trium(EF_FP_CA1, 3, 20) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_ts(const file_t *f, int mode) {
|
||||||
|
res_APDU[res_APDU_size++] = EF_TS_ALL & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 12;
|
||||||
|
return parse_trium(EF_TS_SIG, 3, 4) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_keyinfo(const file_t *f, int mode) {
|
||||||
|
int init_len = res_APDU_size;
|
||||||
|
if (res_APDU_size > 0) {
|
||||||
|
res_APDU[res_APDU_size++] = EF_KEY_INFO & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 6;
|
||||||
|
}
|
||||||
|
file_t *ef = search_by_fid(EF_PK_SIG, NULL, SPECIFY_ANY);
|
||||||
|
res_APDU[res_APDU_size++] = 0x00;
|
||||||
|
if (ef && ef->data) {
|
||||||
|
res_APDU[res_APDU_size++] = 0x01;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_APDU[res_APDU_size++] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
ef = search_by_fid(EF_PK_DEC, NULL, SPECIFY_ANY);
|
||||||
|
res_APDU[res_APDU_size++] = 0x01;
|
||||||
|
if (ef && ef->data) {
|
||||||
|
res_APDU[res_APDU_size++] = 0x01;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_APDU[res_APDU_size++] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
ef = search_by_fid(EF_PK_AUT, NULL, SPECIFY_ANY);
|
||||||
|
res_APDU[res_APDU_size++] = 0x02;
|
||||||
|
if (ef && ef->data) {
|
||||||
|
res_APDU[res_APDU_size++] = 0x01;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_APDU[res_APDU_size++] = 0x00;
|
||||||
|
}
|
||||||
|
return res_APDU_size - init_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_pw_status(const file_t *f, int mode) {
|
||||||
|
file_t *ef;
|
||||||
|
int init_len = res_APDU_size;
|
||||||
|
if (res_APDU_size > 0) {
|
||||||
|
res_APDU[res_APDU_size++] = EF_PW_STATUS & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 7;
|
||||||
|
}
|
||||||
|
ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY);
|
||||||
|
if (ef && ef->data) {
|
||||||
|
memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7);
|
||||||
|
res_APDU_size += 7;
|
||||||
|
}
|
||||||
|
return res_APDU_size - init_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_x448[] = {
|
||||||
|
4,
|
||||||
|
ALGO_ECDH,
|
||||||
|
/* OID of X448 */
|
||||||
|
0x2b, 0x65, 0x6f
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_rsa1k[] = {
|
||||||
|
6,
|
||||||
|
ALGO_RSA,
|
||||||
|
0x04, 0x00, /* Length modulus (in bit): 1024 */
|
||||||
|
0x00, 0x20, /* Length exponent (in bit): 32 */
|
||||||
|
0x00 /* 0: Acceptable format is: P and Q */
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_rsa2k[] = {
|
||||||
|
6,
|
||||||
|
ALGO_RSA,
|
||||||
|
0x08, 0x00, /* Length modulus (in bit): 2048 */
|
||||||
|
0x00, 0x20, /* Length exponent (in bit): 32 */
|
||||||
|
0x00 /* 0: Acceptable format is: P and Q */
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_rsa3k[] = {
|
||||||
|
6,
|
||||||
|
ALGO_RSA,
|
||||||
|
0x0C, 0x00, /* Length modulus (in bit): 3072 */
|
||||||
|
0x00, 0x20, /* Length exponent (in bit): 32 */
|
||||||
|
0x00 /* 0: Acceptable format is: P and Q */
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_rsa4k[] = {
|
||||||
|
6,
|
||||||
|
ALGO_RSA,
|
||||||
|
0x10, 0x00, /* Length modulus (in bit): 4096 */
|
||||||
|
0x00, 0x20, /* Length exponent (in bit): 32 */
|
||||||
|
0x00 /* 0: Acceptable format is: P and Q */
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_p256k1[] = {
|
||||||
|
6,
|
||||||
|
ALGO_ECDSA,
|
||||||
|
0x2b, 0x81, 0x04, 0x00, 0x0a
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_p256r1[] = {
|
||||||
|
9,
|
||||||
|
ALGO_ECDSA,
|
||||||
|
0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_p384r1[] = {
|
||||||
|
6,
|
||||||
|
ALGO_ECDSA,
|
||||||
|
0x2B, 0x81, 0x04, 0x00, 0x22
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_p521r1[] = {
|
||||||
|
6,
|
||||||
|
ALGO_ECDSA,
|
||||||
|
0x2B, 0x81, 0x04, 0x00, 0x23
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_bp256r1[] = {
|
||||||
|
10,
|
||||||
|
ALGO_ECDSA,
|
||||||
|
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_bp384r1[] = {
|
||||||
|
10,
|
||||||
|
ALGO_ECDSA,
|
||||||
|
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_bp512r1[] = {
|
||||||
|
10,
|
||||||
|
ALGO_ECDSA,
|
||||||
|
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_cv25519[] = {
|
||||||
|
11,
|
||||||
|
ALGO_ECDH,
|
||||||
|
0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef MBEDTLS_EDDSA_C
|
||||||
|
const uint8_t algorithm_attr_ed25519[] = {
|
||||||
|
10,
|
||||||
|
ALGO_EDDSA,
|
||||||
|
0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t algorithm_attr_ed448[] = {
|
||||||
|
4,
|
||||||
|
ALGO_EDDSA,
|
||||||
|
0x2b, 0x65, 0x71
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int parse_algo(const uint8_t *algo, uint16_t tag) {
|
||||||
|
res_APDU[res_APDU_size++] = tag & 0xff;
|
||||||
|
memcpy(res_APDU + res_APDU_size, algo, algo[0] + 1);
|
||||||
|
res_APDU_size += algo[0] + 1;
|
||||||
|
return algo[0] + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_algoinfo(const file_t *f, int mode) {
|
||||||
|
int datalen = 0;
|
||||||
|
if (f->fid == EF_ALGO_INFO) {
|
||||||
|
res_APDU[res_APDU_size++] = EF_ALGO_INFO & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 0x82;
|
||||||
|
uint8_t *lp = res_APDU + res_APDU_size;
|
||||||
|
res_APDU_size += 2;
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_SIG);
|
||||||
|
#ifdef MBEDTLS_EDDSA_C
|
||||||
|
datalen += parse_algo(algorithm_attr_ed25519, EF_ALGO_SIG);
|
||||||
|
datalen += parse_algo(algorithm_attr_ed448, EF_ALGO_SIG);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_cv25519, EF_ALGO_DEC);
|
||||||
|
datalen += parse_algo(algorithm_attr_x448, EF_ALGO_DEC);
|
||||||
|
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_AUT);
|
||||||
|
#ifdef MBEDTLS_EDDSA_C
|
||||||
|
datalen += parse_algo(algorithm_attr_ed25519, EF_ALGO_AUT);
|
||||||
|
datalen += parse_algo(algorithm_attr_ed448, EF_ALGO_AUT);
|
||||||
|
#endif
|
||||||
|
uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
|
||||||
|
*lp++ = lpdif >> 8;
|
||||||
|
*lp++ = lpdif & 0xff;
|
||||||
|
datalen = lpdif + 4;
|
||||||
|
}
|
||||||
|
else if (f->fid == EF_ALGO_SIG || f->fid == EF_ALGO_DEC || f->fid == EF_ALGO_AUT) {
|
||||||
|
uint16_t fid = 0x1000 | f->fid;
|
||||||
|
file_t *ef;
|
||||||
|
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)) || !ef->data) {
|
||||||
|
datalen += parse_algo(algorithm_attr_rsa2k, f->fid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint16_t len = file_get_size(ef);
|
||||||
|
if (res_APDU_size > 0) {
|
||||||
|
res_APDU[res_APDU_size++] = f->fid & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = len & 0xff;
|
||||||
|
datalen += 2;
|
||||||
|
}
|
||||||
|
memcpy(res_APDU + res_APDU_size, file_get_data(ef), len);
|
||||||
|
res_APDU_size += len;
|
||||||
|
datalen += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return datalen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_app_data(const file_t *f, int mode) {
|
||||||
|
uint16_t fids[] = {
|
||||||
|
6,
|
||||||
|
EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO, EF_KEY_INFO
|
||||||
|
};
|
||||||
|
res_APDU[res_APDU_size++] = EF_APP_DATA & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 0x82;
|
||||||
|
uint8_t *lp = res_APDU + res_APDU_size;
|
||||||
|
res_APDU_size += 2;
|
||||||
|
parse_do(fids, mode);
|
||||||
|
uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
|
||||||
|
*lp++ = lpdif >> 8;
|
||||||
|
*lp++ = lpdif & 0xff;
|
||||||
|
return lpdif + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_discrete_do(const file_t *f, int mode) {
|
||||||
|
uint16_t fids[] = {
|
||||||
|
11,
|
||||||
|
EF_EXT_CAP, EF_ALGO_SIG, EF_ALGO_DEC, EF_ALGO_AUT, EF_PW_STATUS, EF_FP, EF_CA_FP, EF_TS_ALL,
|
||||||
|
EF_UIF_SIG, EF_UIF_DEC, EF_UIF_AUT
|
||||||
|
};
|
||||||
|
res_APDU[res_APDU_size++] = EF_DISCRETE_DO & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = 0x82;
|
||||||
|
uint8_t *lp = res_APDU + res_APDU_size;
|
||||||
|
res_APDU_size += 2;
|
||||||
|
parse_do(fids, mode);
|
||||||
|
uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
|
||||||
|
*lp++ = lpdif >> 8;
|
||||||
|
*lp++ = lpdif & 0xff;
|
||||||
|
return lpdif + 4;
|
||||||
|
}
|
||||||
32
src/openpgp/do.h
Normal file
32
src/openpgp/do.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern const uint8_t algorithm_attr_p256k1[];
|
||||||
|
extern const uint8_t algorithm_attr_p256r1[];
|
||||||
|
extern const uint8_t algorithm_attr_p384r1[];
|
||||||
|
extern const uint8_t algorithm_attr_p521r1[];
|
||||||
|
extern const uint8_t algorithm_attr_bp256r1[];
|
||||||
|
extern const uint8_t algorithm_attr_bp384r1[];
|
||||||
|
extern const uint8_t algorithm_attr_bp512r1[];
|
||||||
|
extern const uint8_t algorithm_attr_cv25519[];
|
||||||
|
extern const uint8_t algorithm_attr_x448[];
|
||||||
|
extern const uint8_t algorithm_attr_rsa2k[];
|
||||||
|
extern const uint8_t algorithm_attr_rsa4096[];
|
||||||
|
#ifdef MBEDTLS_EDDSA_C
|
||||||
|
extern const uint8_t algorithm_attr_ed25519[];
|
||||||
|
extern const uint8_t algorithm_attr_ed448[];
|
||||||
|
#endif
|
||||||
@@ -3,20 +3,22 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
|
|
||||||
|
bool is_gpg = true;
|
||||||
|
|
||||||
extern const uint8_t openpgp_aid[];
|
extern const uint8_t openpgp_aid[];
|
||||||
extern const uint8_t openpgp_aid_full[];
|
extern const uint8_t openpgp_aid_full[];
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -163,4 +163,6 @@
|
|||||||
|
|
||||||
#define EF_DEV_CONF 0x1122
|
#define EF_DEV_CONF 0x1122
|
||||||
|
|
||||||
|
extern bool is_gpg;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pico_keys.h"
|
#include "pico_keys.h"
|
||||||
@@ -145,6 +145,7 @@ int man_process_apdu() {
|
|||||||
}
|
}
|
||||||
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
|
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
|
||||||
if (cmd->ins == INS(apdu)) {
|
if (cmd->ins == INS(apdu)) {
|
||||||
|
is_gpg = false;
|
||||||
int r = cmd->cmd_handler();
|
int r = cmd->cmd_handler();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
|
* This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
|
||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _MANAGEMENT_H_
|
#ifndef _MANAGEMENT_H_
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __OPENPGP_H_
|
#ifndef __OPENPGP_H_
|
||||||
@@ -27,9 +27,17 @@
|
|||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "mbedtls/rsa.h"
|
#include "mbedtls/rsa.h"
|
||||||
#include "mbedtls/ecdsa.h"
|
#include "mbedtls/ecdsa.h"
|
||||||
|
#include "crypto_utils.h"
|
||||||
|
#include "files.h"
|
||||||
|
|
||||||
extern bool has_pw1;
|
extern bool has_pw1;
|
||||||
|
extern bool has_pw2;
|
||||||
extern bool has_pw3;
|
extern bool has_pw3;
|
||||||
|
extern bool has_rc;
|
||||||
|
extern uint8_t session_pw1[32];
|
||||||
|
extern uint8_t session_rc[32];
|
||||||
|
extern uint8_t session_pw3[32];
|
||||||
|
extern uint8_t dek[IV_SIZE + 32];
|
||||||
|
|
||||||
extern int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek);
|
extern int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek);
|
||||||
extern void make_rsa_response(mbedtls_rsa_context *rsa);
|
extern void make_rsa_response(mbedtls_rsa_context *rsa);
|
||||||
@@ -51,9 +59,24 @@ extern int pin_reset_retries(const file_t *pin, bool force);
|
|||||||
#define ALGO_RSA 0x01
|
#define ALGO_RSA 0x01
|
||||||
#define ALGO_ECDH 0x12
|
#define ALGO_ECDH 0x12
|
||||||
#define ALGO_ECDSA 0x13
|
#define ALGO_ECDSA 0x13
|
||||||
|
#define ALGO_EDDSA 0x16
|
||||||
#define ALGO_AES 0x70
|
#define ALGO_AES 0x70
|
||||||
#define ALGO_AES_128 0x71
|
#define ALGO_AES_128 0x71
|
||||||
#define ALGO_AES_192 0x72
|
#define ALGO_AES_192 0x72
|
||||||
#define ALGO_AES_256 0x74
|
#define ALGO_AES_256 0x74
|
||||||
|
|
||||||
|
extern void select_file(file_t *pe);
|
||||||
|
extern int parse_do(uint16_t *fids, int mode);
|
||||||
|
extern int load_dek();
|
||||||
|
extern int check_pin(const file_t *pin, const uint8_t *data, size_t len);
|
||||||
|
extern mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len);
|
||||||
|
extern int reset_sig_count();
|
||||||
|
extern uint16_t algo_dec, algo_aut, pk_dec, pk_aut;
|
||||||
|
extern bool wait_button_pressed_fid(uint16_t fid);
|
||||||
|
extern void scan_files_openpgp();
|
||||||
|
extern int load_aes_key(uint8_t *aes_key, file_t *fkey);
|
||||||
|
extern int inc_sig_count();
|
||||||
|
extern int dek_encrypt(uint8_t *data, size_t len);
|
||||||
|
extern int dek_decrypt(uint8_t *data, size_t len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
@@ -165,7 +165,7 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scan_files() {
|
static void scan_files_piv() {
|
||||||
scan_flash();
|
scan_flash();
|
||||||
file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF);
|
file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF);
|
||||||
if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) {
|
if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) {
|
||||||
@@ -218,7 +218,7 @@ static void scan_files() {
|
|||||||
uint8_t *key = (uint8_t *)"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08";
|
uint8_t *key = (uint8_t *)"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08";
|
||||||
file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY);
|
file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY);
|
||||||
file_put_data(ef, key, 24);
|
file_put_data(ef, key, 24);
|
||||||
uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED };
|
uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS };
|
||||||
meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta));
|
meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta));
|
||||||
has_pwpiv = false;
|
has_pwpiv = false;
|
||||||
memset(session_pwpiv, 0, sizeof(session_pwpiv));
|
memset(session_pwpiv, 0, sizeof(session_pwpiv));
|
||||||
@@ -264,7 +264,7 @@ static void scan_files() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void init_piv() {
|
void init_piv() {
|
||||||
scan_files();
|
scan_files_piv();
|
||||||
has_pwpiv = false;
|
has_pwpiv = false;
|
||||||
// cmd_select();
|
// cmd_select();
|
||||||
}
|
}
|
||||||
@@ -458,74 +458,76 @@ static int cmd_get_metadata() {
|
|||||||
res_APDU[res_APDU_size++] = 2;
|
res_APDU[res_APDU_size++] = 2;
|
||||||
res_APDU[res_APDU_size++] = meta[1];
|
res_APDU[res_APDU_size++] = meta[1];
|
||||||
res_APDU[res_APDU_size++] = meta[2];
|
res_APDU[res_APDU_size++] = meta[2];
|
||||||
res_APDU[res_APDU_size++] = 0x3;
|
if (key_ref != EF_PIV_KEY_CARDMGM) {
|
||||||
res_APDU[res_APDU_size++] = 1;
|
res_APDU[res_APDU_size++] = 0x3;
|
||||||
res_APDU[res_APDU_size++] = meta[3];
|
res_APDU[res_APDU_size++] = 1;
|
||||||
if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096 || meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) {
|
res_APDU[res_APDU_size++] = meta[3];
|
||||||
res_APDU[res_APDU_size++] = 0x4;
|
if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096 || meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) {
|
||||||
res_APDU[res_APDU_size++] = 0; // Filled later
|
res_APDU[res_APDU_size++] = 0x4;
|
||||||
uint8_t *pk = &res_APDU[res_APDU_size];
|
res_APDU[res_APDU_size++] = 0; // Filled later
|
||||||
if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096) {
|
uint8_t *pk = &res_APDU[res_APDU_size];
|
||||||
mbedtls_rsa_context ctx;
|
if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096) {
|
||||||
mbedtls_rsa_init(&ctx);
|
mbedtls_rsa_context ctx;
|
||||||
int r = load_private_key_rsa(&ctx, ef_key, false);
|
mbedtls_rsa_init(&ctx);
|
||||||
if (r != PICOKEY_OK) {
|
int r = load_private_key_rsa(&ctx, ef_key, false);
|
||||||
mbedtls_rsa_free(&ctx);
|
if (r != PICOKEY_OK) {
|
||||||
return SW_EXEC_ERROR();
|
mbedtls_rsa_free(&ctx);
|
||||||
}
|
return SW_EXEC_ERROR();
|
||||||
res_APDU[res_APDU_size++] = 0x81;
|
}
|
||||||
res_APDU[res_APDU_size++] = 0x82;
|
|
||||||
put_uint16_t(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); res_APDU_size += 2;
|
|
||||||
mbedtls_mpi_write_binary(&ctx.N, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.N));
|
|
||||||
res_APDU_size += mbedtls_mpi_size(&ctx.N);
|
|
||||||
res_APDU[res_APDU_size++] = 0x82;
|
|
||||||
res_APDU[res_APDU_size++] = mbedtls_mpi_size(&ctx.E) & 0xff;
|
|
||||||
mbedtls_mpi_write_binary(&ctx.E, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.E));
|
|
||||||
res_APDU_size += mbedtls_mpi_size(&ctx.E);
|
|
||||||
mbedtls_rsa_free(&ctx);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mbedtls_ecdsa_context ctx;
|
|
||||||
mbedtls_ecdsa_init(&ctx);
|
|
||||||
int r = load_private_key_ecdsa(&ctx, ef_key, false);
|
|
||||||
if (r != PICOKEY_OK) {
|
|
||||||
mbedtls_ecdsa_free(&ctx);
|
|
||||||
return SW_EXEC_ERROR();
|
|
||||||
}
|
|
||||||
uint8_t pt[MBEDTLS_ECP_MAX_PT_LEN];
|
|
||||||
size_t plen = 0;
|
|
||||||
mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &plen, pt, sizeof(pt));
|
|
||||||
mbedtls_ecdsa_free(&ctx);
|
|
||||||
res_APDU[res_APDU_size++] = 0x86;
|
|
||||||
if (plen >= 128) {
|
|
||||||
res_APDU[res_APDU_size++] = 0x81;
|
res_APDU[res_APDU_size++] = 0x81;
|
||||||
|
res_APDU[res_APDU_size++] = 0x82;
|
||||||
|
put_uint16_t_be(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); res_APDU_size += 2;
|
||||||
|
mbedtls_mpi_write_binary(&ctx.N, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.N));
|
||||||
|
res_APDU_size += mbedtls_mpi_size(&ctx.N);
|
||||||
|
res_APDU[res_APDU_size++] = 0x82;
|
||||||
|
res_APDU[res_APDU_size++] = mbedtls_mpi_size(&ctx.E) & 0xff;
|
||||||
|
mbedtls_mpi_write_binary(&ctx.E, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.E));
|
||||||
|
res_APDU_size += mbedtls_mpi_size(&ctx.E);
|
||||||
|
mbedtls_rsa_free(&ctx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mbedtls_ecdsa_context ctx;
|
||||||
|
mbedtls_ecdsa_init(&ctx);
|
||||||
|
int r = load_private_key_ecdsa(&ctx, ef_key, false);
|
||||||
|
if (r != PICOKEY_OK) {
|
||||||
|
mbedtls_ecdsa_free(&ctx);
|
||||||
|
return SW_EXEC_ERROR();
|
||||||
|
}
|
||||||
|
uint8_t pt[MBEDTLS_ECP_MAX_PT_LEN];
|
||||||
|
size_t plen = 0;
|
||||||
|
mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &plen, pt, sizeof(pt));
|
||||||
|
mbedtls_ecdsa_free(&ctx);
|
||||||
|
res_APDU[res_APDU_size++] = 0x86;
|
||||||
|
if (plen >= 128) {
|
||||||
|
res_APDU[res_APDU_size++] = 0x81;
|
||||||
|
}
|
||||||
|
res_APDU[res_APDU_size++] = plen;
|
||||||
|
memcpy(res_APDU + res_APDU_size, pt, plen);
|
||||||
|
res_APDU_size += plen;
|
||||||
|
}
|
||||||
|
uint16_t pk_len = res_APDU_size - (pk - res_APDU);
|
||||||
|
if (pk_len > 255) {
|
||||||
|
memmove(pk + 2, pk, pk_len);
|
||||||
|
pk[-1] = 0x82;
|
||||||
|
pk[0] = pk_len >> 8;
|
||||||
|
pk[1] = pk_len & 0xff;
|
||||||
|
res_APDU_size += 2;
|
||||||
|
}
|
||||||
|
else if (pk_len > 127) {
|
||||||
|
memmove(pk + 1, pk, pk_len);
|
||||||
|
pk[-1] = 0x81;
|
||||||
|
pk[0] = pk_len;
|
||||||
|
res_APDU_size += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pk[-1] = pk_len;
|
||||||
}
|
}
|
||||||
res_APDU[res_APDU_size++] = plen;
|
|
||||||
memcpy(res_APDU + res_APDU_size, pt, plen);
|
|
||||||
res_APDU_size += plen;
|
|
||||||
}
|
|
||||||
uint16_t pk_len = res_APDU_size - (pk - res_APDU);
|
|
||||||
if (pk_len > 255) {
|
|
||||||
memmove(pk + 2, pk, pk_len);
|
|
||||||
pk[-1] = 0x82;
|
|
||||||
pk[0] = pk_len >> 8;
|
|
||||||
pk[1] = pk_len & 0xff;
|
|
||||||
res_APDU_size += 2;
|
|
||||||
}
|
|
||||||
else if (pk_len > 127) {
|
|
||||||
memmove(pk + 1, pk, pk_len);
|
|
||||||
pk[-1] = 0x81;
|
|
||||||
pk[0] = pk_len;
|
|
||||||
res_APDU_size += 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pk[-1] = pk_len;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK || key_ref == EF_PIV_KEY_CARDMGM) {
|
if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK || key_ref == EF_PIV_KEY_CARDMGM) {
|
||||||
uint8_t dhash[32];
|
uint8_t dhash[32];
|
||||||
int32_t eq = false;
|
int32_t eq = 0;
|
||||||
if (key_ref == EF_PIV_PIN) {
|
if (key_ref == EF_PIV_PIN) {
|
||||||
double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\xFF\xFF", 8, dhash);
|
double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\xFF\xFF", 8, dhash);
|
||||||
eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1);
|
eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1);
|
||||||
@@ -539,7 +541,7 @@ static int cmd_get_metadata() {
|
|||||||
}
|
}
|
||||||
res_APDU[res_APDU_size++] = 0x5;
|
res_APDU[res_APDU_size++] = 0x5;
|
||||||
res_APDU[res_APDU_size++] = 1;
|
res_APDU[res_APDU_size++] = 1;
|
||||||
res_APDU[res_APDU_size++] = eq;
|
res_APDU[res_APDU_size++] = eq == 0;
|
||||||
if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK) {
|
if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK) {
|
||||||
file_t *pw_status;
|
file_t *pw_status;
|
||||||
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
|
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
|
||||||
@@ -945,7 +947,7 @@ static int cmd_asym_keygen() {
|
|||||||
return SW_OK();
|
return SW_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_put_data() {
|
static int cmd_put_data() {
|
||||||
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
|
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
|
||||||
return SW_INCORRECT_P1P2();
|
return SW_INCORRECT_P1P2();
|
||||||
}
|
}
|
||||||
@@ -983,12 +985,13 @@ static int cmd_set_mgmkey() {
|
|||||||
}
|
}
|
||||||
uint8_t touch = P2(apdu);
|
uint8_t touch = P2(apdu);
|
||||||
if (touch != 0xFF && touch != 0xFE) {
|
if (touch != 0xFF && touch != 0xFE) {
|
||||||
if (touch == 0xFF) {
|
return SW_INCORRECT_P1P2();
|
||||||
touch = TOUCHPOLICY_NEVER;
|
}
|
||||||
}
|
if (touch == 0xFF) {
|
||||||
else if (touch == 0xFE) {
|
touch = TOUCHPOLICY_NEVER;
|
||||||
touch = TOUCHPOLICY_ALWAYS;
|
}
|
||||||
}
|
else if (touch == 0xFE) {
|
||||||
|
touch = TOUCHPOLICY_ALWAYS;
|
||||||
}
|
}
|
||||||
uint8_t algo = apdu.data[0], key_ref = apdu.data[1], pinlen = apdu.data[2];
|
uint8_t algo = apdu.data[0], key_ref = apdu.data[1], pinlen = apdu.data[2];
|
||||||
if ((key_ref != EF_PIV_KEY_CARDMGM) || (!(algo == PIV_ALGO_AES128 && pinlen == 16) && !(algo == PIV_ALGO_AES192 && pinlen == 24) && !(algo == PIV_ALGO_AES256 && pinlen == 32) && !(algo == PIV_ALGO_3DES && pinlen == 24))) {
|
if ((key_ref != EF_PIV_KEY_CARDMGM) || (!(algo == PIV_ALGO_AES128 && pinlen == 16) && !(algo == PIV_ALGO_AES192 && pinlen == 24) && !(algo == PIV_ALGO_AES256 && pinlen == 32) && !(algo == PIV_ALGO_3DES && pinlen == 24))) {
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __VERSION_H_
|
#ifndef __VERSION_H_
|
||||||
@@ -23,15 +23,15 @@
|
|||||||
#define OPGP_VERSION_MAJOR ((OPGP_VERSION >> 8) & 0xff)
|
#define OPGP_VERSION_MAJOR ((OPGP_VERSION >> 8) & 0xff)
|
||||||
#define OPGP_VERSION_MINOR (OPGP_VERSION & 0xff)
|
#define OPGP_VERSION_MINOR (OPGP_VERSION & 0xff)
|
||||||
|
|
||||||
|
|
||||||
#define PIPGP_VERSION 0x0300
|
|
||||||
|
|
||||||
#define PIPGP_VERSION_MAJOR ((PIPGP_VERSION >> 8) & 0xff)
|
|
||||||
#define PIPGP_VERSION_MINOR (PIPGP_VERSION & 0xff)
|
|
||||||
|
|
||||||
#define PIV_VERSION 0x0507
|
#define PIV_VERSION 0x0507
|
||||||
|
|
||||||
#define PIV_VERSION_MAJOR ((PIV_VERSION >> 8) & 0xff)
|
#define PIV_VERSION_MAJOR ((PIV_VERSION >> 8) & 0xff)
|
||||||
#define PIV_VERSION_MINOR (PIV_VERSION & 0xff)
|
#define PIV_VERSION_MINOR (PIV_VERSION & 0xff)
|
||||||
|
|
||||||
|
|
||||||
|
#define PIPGP_VERSION 0x0400
|
||||||
|
|
||||||
|
#define PIPGP_VERSION_MAJOR ((PIPGP_VERSION >> 8) & 0xff)
|
||||||
|
#define PIPGP_VERSION_MINOR (PIPGP_VERSION & 0xff)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
source tests/docker_env.sh
|
source tests/docker_env.sh
|
||||||
#run_in_docker rm -rf CMakeFiles
|
#run_in_docker rm -rf CMakeFiles
|
||||||
run_in_docker mkdir -p build_in_docker
|
run_in_docker mkdir -p build_in_docker
|
||||||
run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 ..
|
run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 -DENABLE_EDDSA=1 ..
|
||||||
run_in_docker -w "$PWD/build_in_docker" make -j ${NUM_PROC}
|
run_in_docker -w "$PWD/build_in_docker" make -j ${NUM_PROC}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ sleep 1
|
|||||||
rm -f memory.flash
|
rm -f memory.flash
|
||||||
echo -n "Start Pico OpenPGP..."
|
echo -n "Start Pico OpenPGP..."
|
||||||
./build_in_docker/pico_openpgp > /dev/null 2>&1 &
|
./build_in_docker/pico_openpgp > /dev/null 2>&1 &
|
||||||
|
PID=$!
|
||||||
test $? -eq 0 && echo -n "." || fail
|
test $? -eq 0 && echo -n "." || fail
|
||||||
sleep 1
|
sleep 1
|
||||||
ATR="3b:da:18:ff:81:b1:fe:75:1f:03:00:31:f5:73:c0:01:60:00:90:00:1c"
|
ATR="3b:da:18:ff:81:b1:fe:75:1f:03:00:31:f5:73:c0:01:60:00:90:00:1c"
|
||||||
@@ -27,4 +28,19 @@ test $? -eq 0 && echo -e "${OK}" || fail
|
|||||||
|
|
||||||
pytest tests -W ignore::DeprecationWarning
|
pytest tests -W ignore::DeprecationWarning
|
||||||
|
|
||||||
|
echo -n "Stopping Pico OpenPGP..."
|
||||||
|
kill "$PID" 2>/dev/null || true
|
||||||
|
kill -9 "$PID" 2>/dev/null || true
|
||||||
|
test $? -eq 0 && echo -e "${OK}" || fail
|
||||||
|
sleep 1
|
||||||
|
rm -f memory.flash
|
||||||
|
echo -n "Start Pico OpenPGP..."
|
||||||
|
./build_in_docker/pico_openpgp > /dev/null 2>&1 &
|
||||||
|
PID=$!
|
||||||
|
test $? -eq 0 && echo -n "." || fail
|
||||||
|
sleep 1
|
||||||
|
e=$(opensc-tool -an 2>&1)
|
||||||
|
grep -q "${ATR}" <<< $e && echo -n "." || fail
|
||||||
|
test $? -eq 0 && echo -e "${OK}" || fail
|
||||||
|
|
||||||
./tests/scripts/cli-test.sh
|
./tests/scripts/cli-test.sh
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ if [[ $1 == "pico" ]]; then
|
|||||||
sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
|
sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
|
||||||
git clone https://github.com/raspberrypi/pico-sdk
|
git clone https://github.com/raspberrypi/pico-sdk
|
||||||
cd pico-sdk
|
cd pico-sdk
|
||||||
|
git checkout tags/2.2.0
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
cd ..
|
cd ..
|
||||||
git clone https://github.com/raspberrypi/picotool
|
git clone https://github.com/raspberrypi/picotool
|
||||||
@@ -22,15 +23,31 @@ mkdir build_pico
|
|||||||
cd build_pico
|
cd build_pico
|
||||||
cmake -DPICO_SDK_PATH=../pico-sdk ..
|
cmake -DPICO_SDK_PATH=../pico-sdk ..
|
||||||
make
|
make
|
||||||
|
cd ..
|
||||||
elif [[ $1 == "esp32" ]]; then
|
elif [[ $1 == "esp32" ]]; then
|
||||||
sudo apt install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
|
sudo apt install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
|
||||||
git clone --recursive https://github.com/espressif/esp-idf.git
|
git clone --recursive https://github.com/espressif/esp-idf.git
|
||||||
cd esp-idf
|
cd esp-idf
|
||||||
|
git checkout tags/v5.5
|
||||||
./install.sh esp32s3
|
./install.sh esp32s3
|
||||||
. ./export.sh
|
. ./export.sh
|
||||||
cd ..
|
cd ..
|
||||||
idf.py set-target esp32s3
|
idf.py set-target esp32s3
|
||||||
idf.py all
|
idf.py all
|
||||||
|
mkdir -p release
|
||||||
|
cd build
|
||||||
|
esptool.py --chip ESP32-S3 merge_bin -o ../release/pico_openpgp_esp32-s3.bin @flash_args
|
||||||
|
cd ..
|
||||||
|
cd esp-idf
|
||||||
|
./install.sh esp32s2
|
||||||
|
. ./export.sh
|
||||||
|
cd ..
|
||||||
|
idf.py set-target esp32s2
|
||||||
|
idf.py all
|
||||||
|
mkdir -p release
|
||||||
|
cd build
|
||||||
|
esptool.py --chip ESP32-S2 merge_bin -o ../release/pico_openpgp_esp32-s2.bin @flash_args
|
||||||
|
cd ..
|
||||||
else
|
else
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
|
|||||||
Reference in New Issue
Block a user