Merge branch 'master' into development-eddsa
This commit is contained in:
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.
|
||||||
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.
|
||||||
26
README.md
26
README.md
@@ -366,12 +366,32 @@ This project is available under two editions:
|
|||||||
- run this in production with multiple users/devices,
|
- run this in production with multiple users/devices,
|
||||||
- integrate it into their own product/appliance,
|
- integrate it into their own product/appliance,
|
||||||
- enforce corporate policies (PIN policy, admin/user roles, revocation),
|
- 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.
|
- and *not* be required to publish derivative source code.
|
||||||
- Includes access to enterprise-only features (bulk provisioning, multi-user policy controls, device inventory & revocation, custom attestation/identity), official signed builds, and an onboarding call.
|
- 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:
|
Typical licensing models:
|
||||||
- Internal use (within one legal entity).
|
- Internal use (single legal entity, including internal private cloud / virtualized deployments).
|
||||||
- Redistribution / OEM (shipping this as part of your product).
|
- 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
|
For commercial licensing and enterprise features, email pol@henarejos.me
|
||||||
Subject: `ENTERPRISE LICENSE <your company name>`
|
Subject: `ENTERPRISE LICENSE <your company name>`
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
VERSION_MAJOR="5"
|
VERSION_MAJOR="6"
|
||||||
VERSION_MINOR="6"
|
VERSION_MINOR="0"
|
||||||
NO_EDDSA=0
|
NO_EDDSA=0
|
||||||
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
|
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
|
||||||
#if ! [[ -z "${GITHUB_SHA}" ]]; then
|
#if ! [[ -z "${GITHUB_SHA}" ]]; then
|
||||||
|
|||||||
Submodule pico-keys-sdk updated: 8f907b25ba...c1cc33fd9d
@@ -10,6 +10,8 @@ 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"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "pico_keys.h"
|
#include "pico_keys.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
const uint8_t sc_hsm_aid[] = {
|
const uint8_t sc_hsm_aid[] = {
|
||||||
11,
|
11,
|
||||||
@@ -44,6 +45,8 @@ const uint8_t *dev_name = NULL;
|
|||||||
uint16_t dev_name_len = 0;
|
uint16_t dev_name_len = 0;
|
||||||
|
|
||||||
uint8_t PICO_PRODUCT = 1;
|
uint8_t PICO_PRODUCT = 1;
|
||||||
|
uint8_t PICO_VERSION_MAJOR = HSM_VERSION_MAJOR;
|
||||||
|
uint8_t PICO_VERSION_MINOR = HSM_VERSION_MINOR;
|
||||||
|
|
||||||
static int sc_hsm_process_apdu();
|
static int sc_hsm_process_apdu();
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#ifndef __VERSION_H_
|
#ifndef __VERSION_H_
|
||||||
#define __VERSION_H_
|
#define __VERSION_H_
|
||||||
|
|
||||||
#define HSM_VERSION 0x0506
|
#define HSM_VERSION 0x0600
|
||||||
|
|
||||||
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
||||||
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ from binascii import unhexlify
|
|||||||
|
|
||||||
DEFAULT_DKEK = [0x1] * 32
|
DEFAULT_DKEK = [0x1] * 32
|
||||||
|
|
||||||
TERM_CERT = unhexlify('7F2181E57F4E819E5F290100421045535049434F48534D445630303030317F494F060A04007F00070202020203864104F571E53AA8E75C929D925081CF0F893CB5991D48BD546C1A3F22199F037E4B12D601ACD91C67C88D3C5B3D04C08EC0A372485F7A248E080EE0C6237C1B075E1C5F201045535049434F48534D54525A474E50327F4C0E060904007F0007030102025301005F25060203000300055F24060204000300045F374041BF5E970739135770DBCC5DDA81FFD8B13419A9257D44CAF8404267C644E8F435B43F5E57EB2A8CF4B198045ACD094E0CB34E6217D9C8922CFB9BBEFD4088AD')
|
TERM_CERT = unhexlify('7f2181e57f4e819e5f290100421045535049434f48534d445630303030327f494f060a04007f000702020202038641043400e4f42ea8b78b2ab58d24c8297a4b1c13a73a631b531e58d0efb60d70dd6666c8fce4130e9b15ffa4ad29708d32764ac4b0cc0e5301898522f4c735f5a90d5f201045535049434f48534d54524c524134437f4c0e060904007f0007030102025301005f25060205010102085f24060206010102085f3740569f6fe91796f95fa77ecdb680468417eed7b4e00ccc2e091a6b56389213f913c4cf91da96fbcb12d363fead30a5598f737975d58b5170b7f45e9e87ec546883')
|
||||||
DICA_CERT = unhexlify('7F2181E97F4E81A25F290100421045535049434F48534D434130303030317F494F060A04007F0007020202020386410421EE4A21C16A10F737F12E78E5091B266612038CDABEBB722B15BF6D41B877FBF64D9AB69C39B9831B1AE00BEF2A4E81976F7688D45189BB232A24703D8A96A55F201045535049434F48534D445630303030317F4C12060904007F000703010202530580000000005F25060202000801085F24060203000601045F37403F75C08FFFC9186B56E6147199E82BFC327CEEF72495BC567961CD54D702F13E3C2766FCD1D11BD6A9D1F4A229B76B248CEB9AF88D59A74D0AB149448705159B')
|
DICA_CERT = unhexlify('7f2181e97f4e81a25f290100421045535049434f48534d434130303030327f494f060a04007f00070202020203864104e66b473ec328caf39eaed840f9c7a4ba237e1dd19004861fa3f4f134bd2d5ea5f71c6c2e6321add4c8a7793ba41119c5783f48a5d9dfc0898d9ae9e7b14da8d65f201045535049434f48534d445630303030327f4c12060904007f000703010202530580000000045f25060205000400065f24060206000400065f3740a645594c6c338cd6bda6cad039cee54fd822b1011c0af1e4e3a2a6d03d43bdbb8be68a66a8757e7b1f963589bdd80d8e65de5055b722609041ec63f0498ddc8b')
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ RUN apt install -y libccid \
|
|||||||
cmake \
|
cmake \
|
||||||
vsmartcard-vpcd \
|
vsmartcard-vpcd \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
RUN pip3 install pytest pycvc cryptography pyscard==2.2.1 base58
|
RUN pip3 install pytest pycvc cryptography base58
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
RUN git clone https://github.com/OpenSC/OpenSC
|
RUN git clone https://github.com/OpenSC/OpenSC
|
||||||
WORKDIR /OpenSC
|
WORKDIR /OpenSC
|
||||||
RUN git checkout tags/0.25.1
|
RUN git checkout tags/0.26.1
|
||||||
RUN ./bootstrap
|
RUN ./bootstrap
|
||||||
RUN ./configure --enable-openssl
|
RUN ./configure --enable-openssl
|
||||||
RUN make -j `nproc`
|
RUN make -j `nproc`
|
||||||
@@ -37,7 +37,9 @@ RUN make clean
|
|||||||
RUN ldconfig
|
RUN ldconfig
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
RUN git clone https://github.com/polhenarejos/pypicohsm.git
|
RUN git clone https://github.com/polhenarejos/pypicohsm.git
|
||||||
RUN pip3 install -e pypicohsm
|
WORKDIR /pypicohsm
|
||||||
|
RUN pip3 install .
|
||||||
|
WORKDIR /
|
||||||
RUN git clone https://github.com/CardContact/sc-hsm-embedded
|
RUN git clone https://github.com/CardContact/sc-hsm-embedded
|
||||||
WORKDIR /sc-hsm-embedded
|
WORKDIR /sc-hsm-embedded
|
||||||
RUN autoreconf -fi
|
RUN autoreconf -fi
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def test_select(device):
|
|||||||
device.select_applet()
|
device.select_applet()
|
||||||
|
|
||||||
def test_initialization(device):
|
def test_initialization(device):
|
||||||
device.initialize()
|
device.initialize(no_dev_cert=True)
|
||||||
|
|
||||||
def test_termca(device):
|
def test_termca(device):
|
||||||
data = device.get_termca()
|
data = device.get_termca()
|
||||||
|
|||||||
@@ -20,14 +20,14 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import hashlib
|
import hashlib
|
||||||
from const import DEFAULT_DKEK
|
from const import DEFAULT_DKEK
|
||||||
from picohsm import APDUResponse, SWCodes
|
from picokey import APDUResponse, SWCodes
|
||||||
from picohsm.const import DEFAULT_DKEK_SHARES
|
from picohsm.const import DEFAULT_DKEK_SHARES
|
||||||
|
|
||||||
KEY_DOMAINS = 3
|
KEY_DOMAINS = 3
|
||||||
TEST_KEY_DOMAIN = 1
|
TEST_KEY_DOMAIN = 1
|
||||||
|
|
||||||
def test_key_domains(device):
|
def test_key_domains(device):
|
||||||
device.initialize(key_domains=KEY_DOMAINS)
|
device.initialize(key_domains=KEY_DOMAINS, no_dev_cert=True)
|
||||||
for k in range(KEY_DOMAINS):
|
for k in range(KEY_DOMAINS):
|
||||||
kd = device.get_key_domain(key_domain=k)
|
kd = device.get_key_domain(key_domain=k)
|
||||||
assert('error' in kd)
|
assert('error' in kd)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from picohsm.const import DEFAULT_DKEK_SHARES, DEFAULT_PIN, DEFAULT_RETRIES
|
|||||||
from const import DEFAULT_DKEK
|
from const import DEFAULT_DKEK
|
||||||
|
|
||||||
def test_dkek(device):
|
def test_dkek(device):
|
||||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
device.login(DEFAULT_PIN)
|
device.login(DEFAULT_PIN)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
assert('dkek' in resp)
|
assert('dkek' in resp)
|
||||||
|
|||||||
@@ -18,22 +18,22 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from picohsm import APDUResponse, SWCodes
|
from picokey import APDUResponse, SWCodes
|
||||||
from picohsm.const import DEFAULT_PIN, DEFAULT_RETRIES
|
from picohsm.const import DEFAULT_PIN, DEFAULT_RETRIES
|
||||||
|
|
||||||
WRONG_PIN = '112233'
|
WRONG_PIN = '112233'
|
||||||
|
|
||||||
def test_pin_init_retries(device):
|
def test_pin_init_retries(device):
|
||||||
device.initialize(retries=DEFAULT_RETRIES)
|
device.initialize(retries=DEFAULT_RETRIES, no_dev_cert=True)
|
||||||
retries = device.get_login_retries()
|
retries = device.get_login_retries()
|
||||||
assert(retries == DEFAULT_RETRIES)
|
assert(retries == DEFAULT_RETRIES)
|
||||||
|
|
||||||
def test_pin_login(device):
|
def test_pin_login(device):
|
||||||
device.initialize(retries=DEFAULT_RETRIES)
|
device.initialize(retries=DEFAULT_RETRIES, no_dev_cert=True)
|
||||||
device.login(DEFAULT_PIN)
|
device.login(DEFAULT_PIN)
|
||||||
|
|
||||||
def test_pin_retries(device):
|
def test_pin_retries(device):
|
||||||
device.initialize(retries=DEFAULT_RETRIES)
|
device.initialize(retries=DEFAULT_RETRIES, no_dev_cert=True)
|
||||||
device.login(DEFAULT_PIN)
|
device.login(DEFAULT_PIN)
|
||||||
|
|
||||||
for ret in range(DEFAULT_RETRIES-1):
|
for ret in range(DEFAULT_RETRIES-1):
|
||||||
@@ -45,7 +45,7 @@ def test_pin_retries(device):
|
|||||||
device.login(WRONG_PIN)
|
device.login(WRONG_PIN)
|
||||||
assert(e.value.sw == SWCodes.SW_PIN_BLOCKED)
|
assert(e.value.sw == SWCodes.SW_PIN_BLOCKED)
|
||||||
|
|
||||||
device.initialize(retries=DEFAULT_RETRIES)
|
device.initialize(retries=DEFAULT_RETRIES, no_dev_cert=True)
|
||||||
retries = device.get_login_retries()
|
retries = device.get_login_retries()
|
||||||
assert(retries == DEFAULT_RETRIES)
|
assert(retries == DEFAULT_RETRIES)
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import pytest
|
|||||||
from picohsm import KeyType, DOPrefixes
|
from picohsm import KeyType, DOPrefixes
|
||||||
|
|
||||||
def test_gen_initialize(device):
|
def test_gen_initialize(device):
|
||||||
device.initialize()
|
device.initialize(no_dev_cert=True)
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"curve", ['secp192r1', 'secp256r1', 'secp384r1', 'secp521r1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp192k1', 'secp256k1', 'curve25519', 'curve448', 'ed25519', 'ed448']
|
"curve", ['secp192r1', 'secp256r1', 'secp384r1', 'secp521r1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp192k1', 'secp256k1', 'curve25519', 'curve448', 'ed25519', 'ed448']
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from picohsm.const import DEFAULT_RETRIES, DEFAULT_DKEK_SHARES
|
|||||||
from const import DEFAULT_DKEK
|
from const import DEFAULT_DKEK
|
||||||
|
|
||||||
def test_prepare_dkek(device):
|
def test_prepare_dkek(device):
|
||||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
kcv = hashlib.sha256(b'\x00'*32).digest()[:8]
|
kcv = hashlib.sha256(b'\x00'*32).digest()[:8]
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from picohsm.const import DEFAULT_RETRIES, DEFAULT_DKEK_SHARES
|
|||||||
from const import DEFAULT_DKEK
|
from const import DEFAULT_DKEK
|
||||||
|
|
||||||
def test_prepare_dkek(device):
|
def test_prepare_dkek(device):
|
||||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
kcv = hashlib.sha256(b'\x00'*32).digest()[:8]
|
kcv = hashlib.sha256(b'\x00'*32).digest()[:8]
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from picohsm import KeyType, DOPrefixes, APDUResponse, SWCodes
|
from picohsm import KeyType, DOPrefixes
|
||||||
|
from picokey import APDUResponse, SWCodes
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
import hashlib
|
import hashlib
|
||||||
from const import DEFAULT_DKEK
|
from const import DEFAULT_DKEK
|
||||||
@@ -28,7 +29,7 @@ from cryptography.hazmat.primitives.asymmetric import ec
|
|||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
|
||||||
def test_initialize(device):
|
def test_initialize(device):
|
||||||
device.initialize(key_domains=1)
|
device.initialize(key_domains=1, no_dev_cert=True)
|
||||||
assert(device.get_key_domains() == 1)
|
assert(device.get_key_domains() == 1)
|
||||||
|
|
||||||
device.set_key_domain(key_domain=0, total=2)
|
device.set_key_domain(key_domain=0, total=2)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from const import DEFAULT_DKEK
|
|||||||
MESSAGE = b'a secret message'
|
MESSAGE = b'a secret message'
|
||||||
|
|
||||||
def test_prepare_aes(device):
|
def test_prepare_aes(device):
|
||||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ import pytest
|
|||||||
import os
|
import os
|
||||||
from cryptography.hazmat.primitives.ciphers import aead
|
from cryptography.hazmat.primitives.ciphers import aead
|
||||||
import cryptography.exceptions
|
import cryptography.exceptions
|
||||||
from picohsm import APDUResponse, DOPrefixes, EncryptionMode, SWCodes
|
from picohsm import DOPrefixes, EncryptionMode
|
||||||
|
from picokey import APDUResponse, SWCodes
|
||||||
from picohsm.const import DEFAULT_DKEK_SHARES
|
from picohsm.const import DEFAULT_DKEK_SHARES
|
||||||
from const import DEFAULT_DKEK
|
from const import DEFAULT_DKEK
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
@@ -30,7 +31,7 @@ MESSAGE = b'a secret message'
|
|||||||
AAD = b'this is a tag for AAD'
|
AAD = b'this is a tag for AAD'
|
||||||
|
|
||||||
def test_prepare_chachapoly(device):
|
def test_prepare_chachapoly(device):
|
||||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import os
|
import os
|
||||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes, aead
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes, aead
|
||||||
import cryptography.exceptions
|
from picohsm import EncryptionMode, AES
|
||||||
from picohsm import APDUResponse, DOPrefixes, EncryptionMode, SWCodes, AES
|
|
||||||
from picohsm.const import DEFAULT_DKEK_SHARES
|
from picohsm.const import DEFAULT_DKEK_SHARES
|
||||||
from const import DEFAULT_DKEK
|
from const import DEFAULT_DKEK
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
@@ -30,7 +29,7 @@ MESSAGE = b'a secret message'
|
|||||||
AAD = b'this is a tag for AAD'
|
AAD = b'this is a tag for AAD'
|
||||||
|
|
||||||
def test_prepare_aes(device):
|
def test_prepare_aes(device):
|
||||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ from const import DEFAULT_DKEK
|
|||||||
MESSAGE = b'a secret message'
|
MESSAGE = b'a secret message'
|
||||||
|
|
||||||
def test_prepare_aes(device):
|
def test_prepare_aes(device):
|
||||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from picohsm import DOPrefixes
|
|||||||
INFO = b'info message'
|
INFO = b'info message'
|
||||||
|
|
||||||
def test_prepare_kd(device):
|
def test_prepare_kd(device):
|
||||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from picohsm import DOPrefixes
|
|||||||
INFO = b'info message'
|
INFO = b'info message'
|
||||||
|
|
||||||
def test_prepare_kd(device):
|
def test_prepare_kd(device):
|
||||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from picohsm import DOPrefixes
|
|||||||
INFO = b'shared message'
|
INFO = b'shared message'
|
||||||
|
|
||||||
def test_prepare_kd(device):
|
def test_prepare_kd(device):
|
||||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
|
|
||||||
|
|||||||
@@ -21,20 +21,20 @@ import pytest
|
|||||||
from binascii import unhexlify, hexlify
|
from binascii import unhexlify, hexlify
|
||||||
from cvc.certificates import CVC
|
from cvc.certificates import CVC
|
||||||
from picohsm.utils import int_to_bytes
|
from picohsm.utils import int_to_bytes
|
||||||
from picohsm import APDUResponse, SWCodes
|
from picokey import APDUResponse, SWCodes
|
||||||
from const import TERM_CERT, DICA_CERT
|
from const import TERM_CERT, DICA_CERT
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec, utils
|
from cryptography.hazmat.primitives.asymmetric import ec, utils
|
||||||
from cryptography.hazmat.primitives import hashes
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
|
||||||
AUT_KEY = unhexlify('0A40E11E672C28C558B72C25D93BCF28C08D39AFDD5A1A2FD3BAF7A6B27F0C2E')
|
AUT_KEY = unhexlify('579A995BD7BA35AD3D3968940FA4CDA34116E121A8AC01396234DAFB132B3FD7')
|
||||||
aut_pk = ec.derive_private_key(int.from_bytes(AUT_KEY, 'big'), ec.BrainpoolP256R1())
|
aut_pk = ec.derive_private_key(int.from_bytes(AUT_KEY, 'big'), ec.BrainpoolP256R1())
|
||||||
AUT_PUK = unhexlify('678201ed7f218201937f4e82014b5f290100421045535049434f48534d54525a474e50327f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641040cc18ce246da678239af0913a1579dda58c07be404da4a65327794fac93f57a333267979905b5d046da7020226cc4e5fc477e8fc651a0cf87095259aafa88e648701015f201045535049434f48534d54525a474e50325f37401fc90bdab2a58c3cd25f18a90baa2c21d3d087002ba240fb274ff066759297f79e130053d902d637a448c8cdcd0670fe8ebcc06d8a3ee82079f08d1ff8660393421045535049434f48534d54525a474e50325f3740e24e7e23eae3c78f9fa88391004369a293c43ef99e2279170983e1dbe707fbf0382d09de3e60ef1addd2f055947c3efcef17926065ddb7a031f4905da474ed1d')
|
AUT_PUK = unhexlify('678201ed7f218201937f4e82014b5f290100421045535049434f48534d54524c524134437f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7864104a8217de2cec275cdf9dcda68128aff6061199291532545ab394e2554015962e16d568012a9d01b3da60d062aeed11356467fa3af9ebf9aad3d2933ebb9d86e0f8701015f201045535049434f48534d54524c524134435f374022d9f4480995e8370f8377e8bd4a63547be7740f7836456de5196839c6689540889acd573338d68bdea3db2e31c8dd00e670a4bcccdef497a156c39170d3c837421045535049434f48534d54524c524134435f374014445d219facb3bb745867d945e46526a2a6d03441dba52911d8f9483abbe4272a0beee7cecc69c661f3459c9b5431719ebf7e11f93d903a2cf705899eb4b631')
|
||||||
|
|
||||||
|
|
||||||
term_chr = CVC().decode(TERM_CERT).chr()
|
term_chr = CVC().decode(TERM_CERT).chr()
|
||||||
|
|
||||||
def test_initialize(device):
|
def test_initialize(device):
|
||||||
device.initialize(puk_auts=1, puk_min_auts=1)
|
device.initialize(puk_auts=1, puk_min_auts=1, no_dev_cert=False)
|
||||||
device.logout()
|
device.logout()
|
||||||
|
|
||||||
def test_register_puk(device):
|
def test_register_puk(device):
|
||||||
@@ -102,7 +102,7 @@ def test_enumerate_puk_1(device):
|
|||||||
assert(puks[0]['status'] == 0)
|
assert(puks[0]['status'] == 0)
|
||||||
|
|
||||||
def test_enumerate_puk_2(device):
|
def test_enumerate_puk_2(device):
|
||||||
device.initialize(puk_auts=2, puk_min_auts=1)
|
device.initialize(puk_auts=2, puk_min_auts=1, no_dev_cert=True)
|
||||||
puks = device.enumerate_puk()
|
puks = device.enumerate_puk()
|
||||||
assert(len(puks) == 2)
|
assert(len(puks) == 2)
|
||||||
assert(puks[0]['status'] == -1)
|
assert(puks[0]['status'] == -1)
|
||||||
@@ -115,7 +115,7 @@ def test_enumerate_puk_2(device):
|
|||||||
assert(puks[1]['status'] == -1)
|
assert(puks[1]['status'] == -1)
|
||||||
|
|
||||||
def test_register_more_puks(device):
|
def test_register_more_puks(device):
|
||||||
device.initialize(puk_auts=2, puk_min_auts=1)
|
device.initialize(puk_auts=2, puk_min_auts=1, no_dev_cert=True)
|
||||||
status = device.get_puk_status()
|
status = device.get_puk_status()
|
||||||
assert(status == bytes([2,2,1,0]))
|
assert(status == bytes([2,2,1,0]))
|
||||||
|
|
||||||
@@ -123,14 +123,14 @@ def test_register_more_puks(device):
|
|||||||
assert(status == bytes([2,1,1,0]))
|
assert(status == bytes([2,1,1,0]))
|
||||||
|
|
||||||
def test_is_pku(device):
|
def test_is_pku(device):
|
||||||
device.initialize(puk_auts=1, puk_min_auts=1)
|
device.initialize(puk_auts=1, puk_min_auts=1, no_dev_cert=True)
|
||||||
assert(device.is_puk() == True)
|
assert(device.is_puk() == True)
|
||||||
|
|
||||||
device.initialize()
|
device.initialize(no_dev_cert=True)
|
||||||
assert(device.is_puk() == False)
|
assert(device.is_puk() == False)
|
||||||
|
|
||||||
def test_check_puk_key(device):
|
def test_check_puk_key(device):
|
||||||
device.initialize(puk_auts=1, puk_min_auts=1)
|
device.initialize(puk_auts=1, puk_min_auts=1, no_dev_cert=True)
|
||||||
status = device.check_puk_key(term_chr)
|
status = device.check_puk_key(term_chr)
|
||||||
assert(status == -1)
|
assert(status == -1)
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ def test_check_puk_key(device):
|
|||||||
|
|
||||||
|
|
||||||
def test_register_puk_with_no_puk(device):
|
def test_register_puk_with_no_puk(device):
|
||||||
device.initialize()
|
device.initialize(no_dev_cert=True)
|
||||||
with pytest.raises(APDUResponse) as e:
|
with pytest.raises(APDUResponse) as e:
|
||||||
device.register_puk(AUT_PUK, TERM_CERT, DICA_CERT)
|
device.register_puk(AUT_PUK, TERM_CERT, DICA_CERT)
|
||||||
assert(e.value.sw == SWCodes.SW_FILE_NOT_FOUND)
|
assert(e.value.sw == SWCodes.SW_FILE_NOT_FOUND)
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ from cvc.asn1 import ASN1
|
|||||||
from cvc.certificates import CVC
|
from cvc.certificates import CVC
|
||||||
from cvc import oid
|
from cvc import oid
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
from picohsm import DOPrefixes, APDUResponse, SWCodes
|
from picohsm import DOPrefixes
|
||||||
|
from picokey import APDUResponse, SWCodes
|
||||||
|
|
||||||
KDM = unhexlify(b'30820420060B2B0601040181C31F0402016181ED7F2181E97F4E81A25F290100421045535049434F48534D434130303030317F494F060A04007F0007020202020386410421EE4A21C16A10F737F12E78E5091B266612038CDABEBB722B15BF6D41B877FBF64D9AB69C39B9831B1AE00BEF2A4E81976F7688D45189BB232A24703D8A96A55F201045535049434F48534D445630303030317F4C12060904007F000703010202530580000000005F25060202000801085F24060203000601045F37403F75C08FFFC9186B56E6147199E82BFC327CEEF72495BC567961CD54D702F13E3C2766FCD1D11BD6A9D1F4A229B76B248CEB9AF88D59A74D0AB149448705159B6281E97F2181E57F4E819E5F290100421045535049434F48534D445630303030317F494F060A04007F000702020202038641043359F5234CE62E0EB80460046D8FD1AAE018CC8B9E687B40AA2C047E352409B45153D1AD888E4E7E780A3B1FA8C69CA8998BD271C8849137149142E96816A5A45F201045535049434F48534D54524A5A58314A7F4C0E060904007F0007030102025301005F25060205000100085F24060206000100085F374016F155B01CDE7FB902C8A631FCB6938458CB570EAB088DEFE1FFACD3AEFF069020256EECCF8E962461534ED682DB87BB9801E25556F87BF524385C536D19A7D1638201F1678201ED7F218201937F4E82014B5F290100421045535049434F48534D54524A5A58314A7F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410443F0BAB3EB271E1B762BDB81C2CC10C21CF9E8A73241B86C9552614A8842DA00A556C20BC4250C275981FE196F8D2E8766DE06C609BA07AC3E6E1468EAC451408701015F201045535049434F48534D54524A5A58314A5F37402E79A552EA5ABE1B4244841CC55515F31CACFE9B3E0A3FC3FC178DFD5ED6ADC67E03FCC65C24A8A65658768A1A522F372E9897B87058E453A647FC58E089D30D421045535049434F48534D54524A5A58314A5F37400B54434EF57C6DD55D26B44F63940E9F15C10FBC8FC013528F76ACF917D74EF41D635D630F778862ADBD3EE8574F4ABC28B9A6044DFCB9C30D83C1A4DBE6437054400964DBAED86825DBA4E5BCEFF66DAF5739A71D4B2677FB1F53ABA23B3D1D1A686A06478C3CF7FF797FE7C8A4D090D881319BD15AABE709D3EA74A48C88E4387F')
|
KDM = unhexlify(b'30820420060b2b0601040181c31f0402016181ed7f2181e97f4e81a25f290100421045535049434f48534d434130303030327f494f060a04007f00070202020203864104e66b473ec328caf39eaed840f9c7a4ba237e1dd19004861fa3f4f134bd2d5ea5f71c6c2e6321add4c8a7793ba41119c5783f48a5d9dfc0898d9ae9e7b14da8d65f201045535049434f48534d445630303030327f4c12060904007f000703010202530580000000045f25060205000400065f24060206000400065f3740a645594c6c338cd6bda6cad039cee54fd822b1011c0af1e4e3a2a6d03d43bdbb8be68a66a8757e7b1f963589bdd80d8e65de5055b722609041ec63f0498ddc8b6281e97f2181e57f4e819e5f290100421045535049434f48534d445630303030327f494f060a04007f000702020202038641043359f5234ce62e0eb80460046d8fd1aae018cc8b9e687b40aa2c047e352409b45153d1ad888e4e7e780a3b1fa8c69ca8998bd271c8849137149142e96816a5a45f201045535049434f48534d54524a5a58314a7f4c0e060904007f0007030102025301005f25060205010102085f24060206010102085f37409add1c1c8a05e7bc56a8bd846c9122d9214cc43c86b6952a961dce525d830a58130cbb275e9408af38dc16160f958d2b9ac6ac4f0f1b9b863284f00121d447ce638201f1678201ed7f218201937f4e82014b5f290100421045535049434f48534d54524a5a58314a7f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641049de55b50b921de72bbf740d3518905ff893e8208cfe8d144de34d79da3645d1c0cb551a19d6e6a5fee050e479a65d36fdf638af741e52dad4df9960b8ed443d18701015f201045535049434f48534d54524a5a58314a5f374099dede270b9a2def89a4d12dc0314e6289bd565808683f362e9f9ac9554ec5113bf7e412ecc386af12d2a9b43f27e54e10dfc6d8f2d6b618b1776459c13c0bec421045535049434f48534d54524a5a58314a5f3740459f6385f28a84f1c57f421a7f6cb4f1177084497321be94c87998c2e01af0202bab6984411cde1aab34e4e59cc27961b85855bae6340305281ff838253b0f3554404b6a2fe6947faa91f6ffa0d707cd4cbb43192935f561be137f4b3680304fc28b41210b671b8b033e06b4ad720010bcd36b92282844616261f944f3c4f67bfda5')
|
||||||
|
|
||||||
def test_initialize(device):
|
def test_initialize(device):
|
||||||
device.initialize(key_domains=1)
|
device.initialize(key_domains=1, no_dev_cert=True)
|
||||||
device.logout()
|
device.logout()
|
||||||
|
|
||||||
def test_create_xkek(device):
|
def test_create_xkek(device):
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ from cvc.certificates import CVC
|
|||||||
from cvc import oid
|
from cvc import oid
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
from cryptography.hazmat.primitives import hashes
|
from cryptography.hazmat.primitives import hashes
|
||||||
from picohsm import EncryptionMode, APDUResponse, SWCodes, PicoHSM
|
from picohsm import EncryptionMode, PicoHSM
|
||||||
|
from picokey import APDUResponse, SWCodes
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
TEST_STRING = b'Pico Keys are awesome!'
|
TEST_STRING = b'Pico Keys are awesome!'
|
||||||
@@ -36,7 +37,7 @@ def sha256_sha256(data):
|
|||||||
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
|
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
|
||||||
|
|
||||||
def test_initialize(device):
|
def test_initialize(device):
|
||||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
resp = device.import_dkek(DEFAULT_DKEK)
|
resp = device.import_dkek(DEFAULT_DKEK)
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ test $? -eq 0 || exit $?
|
|||||||
rsa_encrypt_decrypt() {
|
rsa_encrypt_decrypt() {
|
||||||
openssl pkeyutl -encrypt -pubin -inkey 1.pub $2 -in $1 -out data.crypt
|
openssl pkeyutl -encrypt -pubin -inkey 1.pub $2 -in $1 -out data.crypt
|
||||||
test $? -eq 0 && echo -n "." || exit $?
|
test $? -eq 0 && echo -n "." || exit $?
|
||||||
TDATA=$(tr -d '\0' < <(pkcs11-tool --id 1 --pin 648219 --decrypt $3 -i data.crypt 2>/dev/null))
|
TDATA=$(pkcs11-tool --id 1 --pin 648219 --decrypt $3 -i data.crypt 2>/dev/null | sed '/^OAEP parameters:/d' | tr -d '\0')
|
||||||
test $? -eq 0 && echo -n "." || exit $?
|
test $? -eq 0 && echo -n "." || exit $?
|
||||||
if [[ ${TEST_STRING} != "$TDATA" ]]; then
|
if [[ "$TEST_STRING" != "$TDATA" ]]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
test $? -eq 0 && echo -n "." || exit $?
|
test $? -eq 0 && echo -n "." || exit $?
|
||||||
@@ -36,7 +36,7 @@ rsa_encrypt_decrypt data_pad "-pkeyopt rsa_padding_mode:none" "--mechanism RSA-X
|
|||||||
test $? -eq 0 && echo -e ".\t${OK}" || exit $?
|
test $? -eq 0 && echo -e ".\t${OK}" || exit $?
|
||||||
|
|
||||||
echo -n " Test RSA-PKCS-OAEP ciphering..."
|
echo -n " Test RSA-PKCS-OAEP ciphering..."
|
||||||
rsa_encrypt_decrypt data "-pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256" "--mechanism RSA-PKCS-OAEP"
|
rsa_encrypt_decrypt data "-pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256" "--mechanism RSA-PKCS-OAEP --hash-algorithm SHA256 --mgf MGF1-SHA256"
|
||||||
test $? -eq 0 && echo -e ".\t${OK}" || exit $?
|
test $? -eq 0 && echo -e ".\t${OK}" || exit $?
|
||||||
|
|
||||||
rm -rf data* 1.*
|
rm -rf data* 1.*
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ except ModuleNotFoundError:
|
|||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from picohsm import PicoHSM, PinType, DOPrefixes, KeyType, EncryptionMode, utils, APDUResponse, SWCodes, AES, Platform
|
from picohsm import PicoHSM, PinType, DOPrefixes, KeyType, EncryptionMode, AES
|
||||||
|
from picohsm.utils import get_pki_data
|
||||||
|
from picokey import APDUResponse, Platform
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
print('ERROR: picohsm module not found! Install picohsm package.\nTry with `pip install pypicohsm`')
|
print('ERROR: picohsm module not found! Install picohsm package.\nTry with `pip install pypicohsm`')
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
import json
|
|
||||||
import urllib.request
|
|
||||||
import base64
|
import base64
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
import sys
|
import sys
|
||||||
@@ -175,21 +175,6 @@ def parse_args():
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def get_pki_data(url, data=None, method='GET'):
|
|
||||||
user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; '
|
|
||||||
'rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'
|
|
||||||
method = 'GET'
|
|
||||||
if (data is not None):
|
|
||||||
method = 'POST'
|
|
||||||
req = urllib.request.Request(f"https://www.picokeys.com/pico/pico-hsm/{url}/",
|
|
||||||
method=method,
|
|
||||||
data=data,
|
|
||||||
headers={'User-Agent': user_agent, })
|
|
||||||
response = urllib.request.urlopen(req)
|
|
||||||
resp = response.read().decode('utf-8')
|
|
||||||
j = json.loads(resp)
|
|
||||||
return j
|
|
||||||
|
|
||||||
def get_pki_certs(certs_dir='certs', force=False):
|
def get_pki_certs(certs_dir='certs', force=False):
|
||||||
certs = get_pki_data('certs')
|
certs = get_pki_data('certs')
|
||||||
if (os.path.exists(certs_dir) is False):
|
if (os.path.exists(certs_dir) is False):
|
||||||
@@ -222,45 +207,9 @@ def initialize(picohsm, args):
|
|||||||
print('Are you sure?')
|
print('Are you sure?')
|
||||||
_ = input('[Press enter to confirm]')
|
_ = input('[Press enter to confirm]')
|
||||||
|
|
||||||
if (args.pin):
|
picohsm.initialize(pin=args.pin, sopin=args.so_pin, no_dev_cert=args.no_dev_cert)
|
||||||
try:
|
|
||||||
picohsm.login(args.pin)
|
|
||||||
except APDUResponse:
|
|
||||||
pass
|
|
||||||
pin = args.pin
|
|
||||||
else:
|
|
||||||
pin = '648219'
|
|
||||||
|
|
||||||
if (args.so_pin):
|
|
||||||
try:
|
|
||||||
picohsm.login(args.so_pin, who=PinType.SO_PIN)
|
|
||||||
except APDUResponse:
|
|
||||||
pass
|
|
||||||
so_pin = args.so_pin
|
|
||||||
else:
|
|
||||||
so_pin = '57621880'
|
|
||||||
|
|
||||||
picohsm.initialize(pin=pin, sopin=so_pin)
|
|
||||||
if (not args.no_dev_cert):
|
if (not args.no_dev_cert):
|
||||||
response = picohsm.get_contents(DOPrefixes.EE_CERTIFICATE_PREFIX, 0x00)
|
|
||||||
|
|
||||||
cert = bytearray(response)
|
|
||||||
Y = CVC().decode(cert).pubkey().find(0x86).data()
|
|
||||||
print(f'Public Point: {hexlify(Y).decode()}')
|
|
||||||
|
|
||||||
pbk = base64.urlsafe_b64encode(Y)
|
|
||||||
params = {'pubkey': pbk}
|
|
||||||
if (picohsm.platform in (Platform.RP2350, Platform.ESP32, Platform.EMULATION)):
|
|
||||||
params['curve'] = 'secp256k1'
|
|
||||||
data = urllib.parse.urlencode(params).encode()
|
|
||||||
j = get_pki_data('cvc', data=data)
|
|
||||||
print('Device name: '+j['devname'])
|
|
||||||
dataef = base64.urlsafe_b64decode(
|
|
||||||
j['cvcert']) + base64.urlsafe_b64decode(j['dvcert']) + base64.urlsafe_b64decode(j['cacert'])
|
|
||||||
|
|
||||||
picohsm.select_file(0x2f02)
|
|
||||||
response = picohsm.put_contents(0x0000, data=dataef)
|
|
||||||
|
|
||||||
print('Certificate uploaded successfully!')
|
print('Certificate uploaded successfully!')
|
||||||
print('')
|
print('')
|
||||||
print('Note that the device is initialized with a default PIN and '
|
print('Note that the device is initialized with a default PIN and '
|
||||||
|
|||||||
Reference in New Issue
Block a user