Compare commits
1 Commits
feat/serve
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 6dfcc1b2be |
@@ -23,5 +23,5 @@ public record DocumentDto : DocumentDetailsDto
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the binary data of the document, if available.
|
/// Gets or sets the binary data of the document, if available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[]? ByteData { get; init; }
|
public byte[]? ByteData { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Pkcs11Interop" Version="5.3.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,83 +1,67 @@
|
|||||||
# EnvelopeGenerator.Infrastructure.Crypt
|
# EnvelopeGenerator.Infrastructure.Crypt
|
||||||
|
|
||||||
PKCS#11-based cryptographic infrastructure for FES (Advanced Electronic Signature) workflows.
|
This project provides PKCS#11-based cryptographic infrastructure for FES (Advanced Electronic Signature) workflows.
|
||||||
|
|
||||||
Official references:
|
If you are new to HSM/SoftHSM: this README is written to let you start from zero and still understand the full path from setup to testing.
|
||||||
|
|
||||||
- SoftHSMv2 (official): `https://github.com/softhsm/SoftHSMv2`
|
|
||||||
- OpenSC `pkcs11-tool` docs: `https://github.com/OpenSC/OpenSC/wiki/Using-pkcs11-tool-and-OpenSSL`
|
|
||||||
- PKCS#11 standard overview (OASIS): `https://www.oasis-open.org/committees/pkcs11/`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1) Scope
|
## 1) What this project is (and what it is not)
|
||||||
|
|
||||||
This project is the crypto layer only.
|
This project is the cryptography layer only.
|
||||||
|
|
||||||
- Signs hashes via keys in HSM/SoftHSM.
|
- It signs hashes using private keys stored in HSM/SoftHSM.
|
||||||
- Reads certificates from HSM/SoftHSM.
|
- It reads certificates from HSM/SoftHSM.
|
||||||
- Verifies signatures.
|
- It verifies signatures.
|
||||||
- Exposes abstractions for Application/Server integration.
|
- It exposes service abstractions for Application/Server integration.
|
||||||
|
|
||||||
This project is not:
|
It is **not**:
|
||||||
|
|
||||||
- a REST API,
|
- a REST API by itself,
|
||||||
- a UI module,
|
- a UI component,
|
||||||
- a full document orchestration workflow.
|
- a full document workflow orchestrator.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2) SoftHSM and PKCS#11 basics
|
## 2) SoftHSM and PKCS#11 in one minute
|
||||||
|
|
||||||
- SoftHSM is a software implementation of an HSM.
|
- `SoftHSMv2` is a software HSM implementation.
|
||||||
- It does not expose REST endpoints.
|
- It does **not** provide a REST endpoint.
|
||||||
- Access is via PKCS#11 shared library (`.so`/`.dll`).
|
- You access it through a PKCS#11 library/module (`.so`/`.dll`).
|
||||||
- App loads module path and performs PKCS#11 operations.
|
- Your app loads that library and calls PKCS#11 functions.
|
||||||
|
|
||||||
Supported deployment patterns:
|
Two deployment patterns are possible:
|
||||||
|
|
||||||
1. Direct module (`libsofthsm2.so`, `softhsm2-x64.dll`, etc.)
|
1. **Direct local module**
|
||||||
2. PKCS#11 proxy module (remote HSM/SoftHSM backend)
|
- Example library path: `libsofthsm2.so`
|
||||||
|
2. **PKCS#11 proxy module (remote HSM/SoftHSM)**
|
||||||
|
- Example library path: `libpkcs11-proxy.so` or proxy DLL
|
||||||
|
|
||||||
Critical platform rule:
|
Both are valid for this project.
|
||||||
|
|
||||||
- A Windows process cannot load a Linux `.so` directly.
|
|
||||||
- `Crypt:Pkcs11:LibraryPath` must always point to a native library compatible with the host OS of `EnvelopeGenerator.Server`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2.1) Windows Server + Linux SoftHSM architecture (decision TODO)
|
## 3) How this maps to the FES diagram (Ablauf SignFlow Unternehmenszertifikat)
|
||||||
|
|
||||||
Current business requirement: `EnvelopeGenerator.Server` runs on Windows, SoftHSM runs on Linux.
|
From the shared draw.io/PDF process:
|
||||||
|
|
||||||
This repository must use one of the following three paths:
|
- Step 6: Backend computes document hash and sends it with PIN context to HSM.
|
||||||
|
- Implemented by: `ISignatureProvider` / `Pkcs11SignatureProvider`
|
||||||
|
- Step 7: HSM returns digital signature (and cert context can be resolved).
|
||||||
|
- Implemented by: `Pkcs11SignatureProvider` + `ICertificateProvider`
|
||||||
|
- Step 8: Backend embeds signature + certificate into PDF and creates audit trail.
|
||||||
|
- This project provides crypto primitives for this step.
|
||||||
|
- PDF embedding and audit document composition are integrated in later layers.
|
||||||
|
|
||||||
1. Linux signing service (recommended)
|
So this project is the cryptographic core for diagram steps 6-8.
|
||||||
- Windows `EnvelopeGenerator.Server` calls HTTPS signing API.
|
|
||||||
- Linux service performs PKCS#11 operations against SoftHSM.
|
|
||||||
- Private keys stay on Linux.
|
|
||||||
2. PKCS#11 proxy bridge
|
|
||||||
- Windows app loads a Windows PKCS#11 proxy client DLL.
|
|
||||||
- Proxy forwards operations to Linux-side PKCS#11 endpoint connected to SoftHSM.
|
|
||||||
3. Local Windows SoftHSM (dev/test only, optional)
|
|
||||||
- SoftHSM is also installed on Windows.
|
|
||||||
- App talks to local Windows PKCS#11 module.
|
|
||||||
|
|
||||||
TODO - architecture lock-in:
|
Actor mapping from the diagram:
|
||||||
|
|
||||||
- [ ] Select one path as production standard (`1` is recommended).
|
- `Ersteller` (sender): creates envelope and defines recipients.
|
||||||
- [ ] Document final runtime topology (hosts, ports, TLS, auth).
|
- `Signierer` (recipient/signer): completes 2FA and signs.
|
||||||
- [ ] Define where audit metadata (IP/email/phone/device) is stored and signed/linked.
|
- `Backend` (our stack): computes hash, requests HSM signature, embeds proof in PDF.
|
||||||
- [ ] Update `SignatureController.Submit` integration contract for FES branch.
|
- `HSM/SoftHSM`: stores private keys and performs cryptographic signing.
|
||||||
- [ ] Add environment-specific runbook for Windows host + Linux HSM operations.
|
- `CA`: issues/renews certificates.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3) FES flow mapping
|
|
||||||
|
|
||||||
- Step 6: hash is sent to HSM signing operation -> `ISignatureProvider`
|
|
||||||
- Step 7: signature and certificate context are resolved -> `Pkcs11SignatureProvider`, `ICertificateProvider`
|
|
||||||
- Step 8: PDF embedding + audit trail are completed by upper layers; this project provides crypto primitives
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -96,17 +80,19 @@ DI entry point:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5) Runtime configuration
|
## 5) Required configuration
|
||||||
|
|
||||||
Configuration section: `Crypt:Pkcs11`
|
Configuration section: `Crypt:Pkcs11`
|
||||||
|
|
||||||
|
Typical keys:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"Crypt": {
|
"Crypt": {
|
||||||
"Pkcs11": {
|
"Pkcs11": {
|
||||||
"LibraryPath": "/usr/lib/softhsm/libsofthsm2.so",
|
"LibraryPath": "/usr/lib/softhsm/libsofthsm2.so",
|
||||||
"SlotId": 1720207650,
|
"SlotId": 0,
|
||||||
"TokenLabel": "DevToken",
|
"TokenLabel": null,
|
||||||
"UserPin": "***",
|
"UserPin": "***",
|
||||||
"PrivateKeyLabel": "sign-key",
|
"PrivateKeyLabel": "sign-key",
|
||||||
"PrivateKeyIdHex": null,
|
"PrivateKeyIdHex": null,
|
||||||
@@ -117,273 +103,297 @@ Configuration section: `Crypt:Pkcs11`
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Security rules:
|
Security rule:
|
||||||
|
|
||||||
- Never commit real PINs.
|
- Do not commit real PINs to source control.
|
||||||
- Use environment variables or secret vault.
|
- Use environment variables / secret vault for production.
|
||||||
- Use test-only tokens for development.
|
|
||||||
|
|
||||||
Production naming convention used in this repository:
|
|
||||||
|
|
||||||
- Token label: `CompanyProdToken`
|
|
||||||
- Private key label: `company-sign-key-v1`
|
|
||||||
- Certificate label: `company-sign-cert-v1`
|
|
||||||
|
|
||||||
These names are also exposed as constants in `EnvelopeGenerator.Infrastructure.Crypt/Options/Pkcs11ProviderOptions.cs`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Test configuration source
|
## 6) The 5 test values you must provide
|
||||||
|
|
||||||
Crypt tests read PKCS#11 values from `EnvelopeGenerator.Tests/appsettings.json` under `Crypt:Pkcs11`.
|
Integration tests need these environment variables:
|
||||||
|
|
||||||
Required keys:
|
- `FES_TEST_PKCS11_LIBRARY_PATH`
|
||||||
|
- `FES_TEST_PKCS11_SLOT_ID`
|
||||||
|
- `FES_TEST_PKCS11_USER_PIN`
|
||||||
|
- `FES_TEST_PKCS11_PRIVATE_KEY_LABEL`
|
||||||
|
- `FES_TEST_PKCS11_CERTIFICATE_LABEL`
|
||||||
|
|
||||||
- `Crypt:Pkcs11:LibraryPath`
|
Without these values, integration tests are skipped by design.
|
||||||
- `Crypt:Pkcs11:SlotId` (or `Crypt:Pkcs11:TokenLabel`)
|
|
||||||
- `Crypt:Pkcs11:UserPin`
|
|
||||||
- `Crypt:Pkcs11:PrivateKeyLabel`
|
|
||||||
- `Crypt:Pkcs11:CertificateLabel`
|
|
||||||
|
|
||||||
No environment variable is required for crypt tests in this repository anymore.
|
## 6.1 Which certificate/key should be created?
|
||||||
|
|
||||||
|
This is the most important business decision for IT and architecture.
|
||||||
|
|
||||||
|
Based on your shared diagram, the **primary model** is:
|
||||||
|
|
||||||
|
- one **company certificate + company key pair** in HSM,
|
||||||
|
- reused for all signers,
|
||||||
|
- signer identity proven by audit-trail + 2FA evidence.
|
||||||
|
|
||||||
|
What this means in practical terms:
|
||||||
|
|
||||||
|
- Not one key per sender.
|
||||||
|
- Not one key per recipient by default.
|
||||||
|
- One company signing identity, many signing events.
|
||||||
|
|
||||||
|
Alternative model (future/optional):
|
||||||
|
|
||||||
|
- per-signer certificate/key pair (more complex CA lifecycle).
|
||||||
|
|
||||||
|
For current fast validation and your FES flow, use the **company-level key/certificate** model.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Full SoftHSM lifecycle runbook (project scope)
|
## 7) How to obtain these values (IT-friendly)
|
||||||
|
|
||||||
### 7.1 Discover module path
|
## 7.1 If you use direct SoftHSM module
|
||||||
|
|
||||||
|
### A) Find module path
|
||||||
|
|
||||||
|
What it is:
|
||||||
|
|
||||||
|
- PKCS#11 shared library file used by the app to talk to SoftHSM.
|
||||||
|
|
||||||
|
Why needed:
|
||||||
|
|
||||||
|
- Without this exact file path, PKCS#11 cannot be loaded.
|
||||||
|
|
||||||
|
Linux examples:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ldconfig -p | grep softhsm
|
ldconfig -p | grep softhsm
|
||||||
find /usr -name "libsofthsm2.so" 2>/dev/null
|
find /usr -name "libsofthsm2.so" 2>/dev/null
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.2 List slots/tokens
|
Use the resolved full path as `FES_TEST_PKCS11_LIBRARY_PATH`.
|
||||||
|
|
||||||
|
### B) List slots/tokens
|
||||||
|
|
||||||
|
What it is:
|
||||||
|
|
||||||
|
- Slot: logical container position in PKCS#11.
|
||||||
|
- Token: initialized security container in a slot.
|
||||||
|
|
||||||
|
Why needed:
|
||||||
|
|
||||||
|
- The app must know which slot/token contains the company key and certificate.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
softhsm2-util --show-slots
|
softhsm2-util --show-slots
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.3 Create new token (recommended for new company/test tenant)
|
Pick your slot as `FES_TEST_PKCS11_SLOT_ID`.
|
||||||
|
|
||||||
|
### C) Identify key and certificate labels
|
||||||
|
|
||||||
|
What it is:
|
||||||
|
|
||||||
|
- `Private key label`: name of the signing private key object.
|
||||||
|
- `Certificate label`: name of the matching X.509 certificate object.
|
||||||
|
|
||||||
|
Why needed:
|
||||||
|
|
||||||
|
- Tests and runtime use labels to select correct objects in HSM.
|
||||||
|
|
||||||
|
Use `pkcs11-tool` against your module:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
softhsm2-util --init-token --slot <uninitialized-slot> --label <token-label> --so-pin <so-pin> --pin <user-pin>
|
pkcs11-tool --module /path/to/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> --list-objects
|
||||||
```
|
```
|
||||||
|
|
||||||
Important:
|
From output:
|
||||||
|
|
||||||
- After init, token is reassigned to a new slot id.
|
- private key label -> `FES_TEST_PKCS11_PRIVATE_KEY_LABEL`
|
||||||
- Re-run `--show-slots` and use the new slot id.
|
- certificate label -> `FES_TEST_PKCS11_CERTIFICATE_LABEL`
|
||||||
|
|
||||||
### 7.4 Login and inspect objects
|
### D) User PIN
|
||||||
|
|
||||||
|
What it is:
|
||||||
|
|
||||||
|
- User authorization secret to open authenticated session on token.
|
||||||
|
|
||||||
|
Why needed:
|
||||||
|
|
||||||
|
- HSM will not allow signing with private key without login.
|
||||||
|
|
||||||
|
PIN is assigned during token initialization and must be provided by IT/security team.
|
||||||
|
|
||||||
|
### E) Optional: Initialize token and create objects (Linux quick bootstrap)
|
||||||
|
|
||||||
|
Only if token/keys are not already provisioned by IT PKI team.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> --list-objects
|
# 1) Initialize token in slot 0 (example)
|
||||||
```
|
softhsm2-util --init-token --slot 0 --label "CompanySignToken"
|
||||||
|
|
||||||
### 7.5 Generate company signing key pair
|
# 2) Verify slot/token
|
||||||
|
softhsm2-util --show-slots
|
||||||
|
|
||||||
```bash
|
# 3) Generate RSA key pair inside token (example)
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> \
|
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot 0 --login --pin <USER_PIN> \
|
||||||
--keypairgen --key-type rsa:3072 --label sign-key --id 01
|
--keypairgen --key-type rsa:3072 --label sign-key --id 01
|
||||||
```
|
|
||||||
|
|
||||||
### 7.6 Import company certificate
|
# 4) Import certificate (already issued by CA)
|
||||||
|
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot 0 --login --pin <USER_PIN> \
|
||||||
```bash
|
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> \
|
|
||||||
--write-object company-sign-cert.der --type cert --label sign-cert --id 01
|
--write-object company-sign-cert.der --type cert --label sign-cert --id 01
|
||||||
|
|
||||||
|
# 5) List objects and confirm labels
|
||||||
|
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot 0 --login --pin <USER_PIN> --list-objects
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.7 Read object metadata (for diagnostics)
|
Notes:
|
||||||
|
|
||||||
```bash
|
- Use this only in non-production unless approved.
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> --list-objects
|
- In production, key generation/import should follow company security policy.
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> --list-mechanisms
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7.8 Update operations
|
## 7.2 If you use PKCS#11 proxy module
|
||||||
|
|
||||||
PKCS#11 objects are usually immutable for key/cert payload; updates are done by rotation:
|
What it is:
|
||||||
|
|
||||||
1. Create/import new key/cert with new label or id.
|
- A local PKCS#11 bridge library that forwards calls to remote HSM/SoftHSM service.
|
||||||
2. Update app config/env labels.
|
|
||||||
3. Validate with integration tests.
|
|
||||||
4. Delete old objects when safe.
|
|
||||||
|
|
||||||
PIN operations:
|
Why needed:
|
||||||
|
|
||||||
- User PIN change (while logged in):
|
- App still loads a local module path, but crypto operations happen remotely.
|
||||||
|
|
||||||
```bash
|
Ask IT for:
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <old-user-pin> --change-pin --new-pin <new-user-pin>
|
|
||||||
```
|
|
||||||
|
|
||||||
- User PIN reset via SO credentials:
|
- proxy module path (`libpkcs11-proxy.*`)
|
||||||
|
- slot id or token label
|
||||||
|
- user pin
|
||||||
|
- private key label
|
||||||
|
- certificate label
|
||||||
|
|
||||||
```bash
|
In proxy mode, values come from proxy-backed token, not local SoftHSM token files.
|
||||||
softhsm2-util --init-pin --slot <slot-id> --so-pin <so-pin> --pin <new-user-pin>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7.9 Delete operations
|
|
||||||
|
|
||||||
Delete by label/id/type:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <slot-id> --login --pin <user-pin> \
|
|
||||||
--delete-object --type cert --label sign-cert
|
|
||||||
```
|
|
||||||
|
|
||||||
Token-level destructive reset (do not use unless approved):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
softhsm2-util --delete-token --token <token-label>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8) New company onboarding checklist
|
## 7.3 Linux handover checklist for IT (copy/paste friendly)
|
||||||
|
|
||||||
For company-level signing model (one company key/cert pair):
|
1. Confirm module path exists (`libsofthsm2.so` or proxy module).
|
||||||
|
2. Confirm token exists and slot id is known.
|
||||||
1. Create token with company label (or assign dedicated token in remote HSM).
|
3. Confirm company private key label and certificate label.
|
||||||
2. Generate key pair in token.
|
4. Confirm user PIN for test environment.
|
||||||
3. Obtain CA certificate and import into token.
|
5. Share these five values securely with development team.
|
||||||
4. Record secure runtime values:
|
|
||||||
- module path
|
|
||||||
- slot id or token label
|
|
||||||
- user pin
|
|
||||||
- private key label
|
|
||||||
- certificate label
|
|
||||||
5. Run crypt integration tests.
|
|
||||||
6. Store values in vault and wire app environment.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Rotation/update checklist
|
## 8) Test execution checklist (single command flow)
|
||||||
|
|
||||||
1. Create new key/cert (`sign-key-v2`, `sign-cert-v2`).
|
## 8.1 Set environment variables
|
||||||
2. Configure app env to new labels.
|
|
||||||
3. Run integration tests.
|
|
||||||
4. Deploy.
|
|
||||||
5. Keep old key/cert during grace period.
|
|
||||||
6. Remove old key/cert after legal/operational confirmation.
|
|
||||||
|
|
||||||
---
|
PowerShell example:
|
||||||
|
|
||||||
## 10) Running tests
|
```powershell
|
||||||
|
$env:FES_TEST_PKCS11_LIBRARY_PATH = "<module-path>"
|
||||||
|
$env:FES_TEST_PKCS11_SLOT_ID = "<slot-id>"
|
||||||
|
$env:FES_TEST_PKCS11_USER_PIN = "<user-pin>"
|
||||||
|
$env:FES_TEST_PKCS11_PRIVATE_KEY_LABEL = "<private-key-label>"
|
||||||
|
$env:FES_TEST_PKCS11_CERTIFICATE_LABEL = "<certificate-label>"
|
||||||
|
```
|
||||||
|
|
||||||
Before running, configure `EnvelopeGenerator.Tests/appsettings.json` -> `Crypt:Pkcs11` with real Linux SoftHSM values.
|
Linux (bash) example:
|
||||||
|
|
||||||
Run crypt tests:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
export FES_TEST_PKCS11_LIBRARY_PATH="/usr/lib/softhsm/libsofthsm2.so"
|
||||||
|
export FES_TEST_PKCS11_SLOT_ID="0"
|
||||||
|
export FES_TEST_PKCS11_USER_PIN="<user-pin>"
|
||||||
|
export FES_TEST_PKCS11_PRIVATE_KEY_LABEL="sign-key"
|
||||||
|
export FES_TEST_PKCS11_CERTIFICATE_LABEL="sign-cert"
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify env values quickly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "$FES_TEST_PKCS11_LIBRARY_PATH"
|
||||||
|
echo "$FES_TEST_PKCS11_SLOT_ID"
|
||||||
|
echo "$FES_TEST_PKCS11_PRIVATE_KEY_LABEL"
|
||||||
|
echo "$FES_TEST_PKCS11_CERTIFICATE_LABEL"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8.2 Run only crypt tests
|
||||||
|
|
||||||
|
```powershell
|
||||||
dotnet test "EnvelopeGenerator.Tests/EnvelopeGenerator.Tests.csproj" -f net8.0 --filter "FullyQualifiedName~EnvelopeGenerator.Tests.Application.Crypt"
|
dotnet test "EnvelopeGenerator.Tests/EnvelopeGenerator.Tests.csproj" -f net8.0 --filter "FullyQualifiedName~EnvelopeGenerator.Tests.Application.Crypt"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
Expected:
|
||||||
|
|
||||||
## 11) Common failures
|
- Unit tests pass always.
|
||||||
|
- Integration tests pass when env values are correct.
|
||||||
|
- Integration tests skip when env values are missing.
|
||||||
|
|
||||||
- `CKR_PIN_INCORRECT`: wrong user pin for that token.
|
If all five values are correct:
|
||||||
- `CRYPT_PROVIDER_UNAVAILABLE`: bad module path or native load issue.
|
|
||||||
- `CRYPT_SLOT_NOT_FOUND`: wrong slot id or token label.
|
- integration tests run automatically,
|
||||||
- `CRYPT_LOGIN_FAILED`: login failed (pin/token mismatch).
|
- no code change is required,
|
||||||
- `CRYPT_KEY_NOT_FOUND`: key label/id mismatch.
|
- only environment setup is required.
|
||||||
- `CRYPT_CERT_NOT_FOUND`: certificate label/id mismatch.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12) Integration note
|
## 9) Common failure meanings
|
||||||
|
|
||||||
Current implementation uses `CKM_SHA256_RSA_PKCS` while caller provides hash bytes. Validate mechanism semantics in your provider/HSM policy. If provider expects raw payload instead of digest for selected mechanism, signing flow must be adjusted.
|
- `CRYPT_PROVIDER_UNAVAILABLE`
|
||||||
|
- invalid library path, missing native dependency, provider cannot load
|
||||||
|
- `CRYPT_SLOT_NOT_FOUND`
|
||||||
|
- wrong slot id or token label
|
||||||
|
- `CRYPT_LOGIN_FAILED`
|
||||||
|
- wrong PIN
|
||||||
|
- `CRYPT_KEY_NOT_FOUND`
|
||||||
|
- private key label/id mismatch
|
||||||
|
- `CRYPT_CERT_NOT_FOUND`
|
||||||
|
- certificate label/id mismatch
|
||||||
|
|
||||||
|
This is exactly what IT needs for first-level diagnostics.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13) Production-first onboarding (single-line checkpoints)
|
## 10) Integration in the full stack architecture
|
||||||
|
|
||||||
This section is the authoritative path for production-style setup (critical documents, FES).
|
Current role by layer:
|
||||||
|
|
||||||
### 13.1 Step 1 - Initialize dedicated company token
|
- `Infrastructure.Crypt` (this project): PKCS#11 crypto operations
|
||||||
|
- `Application`: orchestration use-cases and business process steps
|
||||||
|
- `Server`: API endpoints and presentation concerns
|
||||||
|
|
||||||
One-line command:
|
Recommended integration path:
|
||||||
|
|
||||||
```bash
|
1. Stabilize crypt tests and environment setup (this stage).
|
||||||
mkdir -p ./fes-prod && cd ./fes-prod && export SO_PIN="$(openssl rand -hex 16)" USER_PIN="$(openssl rand -hex 12)" && softhsm2-util --init-token --slot <uninitialized-slot> --label CompanyProdToken --so-pin "$SO_PIN" --pin "$USER_PIN" && softhsm2-util --show-slots
|
2. Integrate `ISignatureProvider` + `ICertificateProvider` into Application command flow.
|
||||||
```
|
3. Connect Application flow to Server endpoints.
|
||||||
|
4. Add PDF embedding and audit-trail generation for full step-8 compliance.
|
||||||
|
5. Add archiving/distribution orchestration for steps 9-10.
|
||||||
|
|
||||||
Checkpoint:
|
---
|
||||||
|
|
||||||
- Token appears as initialized with label `CompanyProdToken`.
|
## 11) Important note about signing semantics
|
||||||
- SoftHSM reassigns token to a new slot ID; use that slot ID in all next commands.
|
|
||||||
|
|
||||||
Security note:
|
PKCS#11 mechanisms differ in whether they expect raw data or a precomputed digest.
|
||||||
|
|
||||||
- Do not print/store PINs in shell history in real production operations.
|
Current implementation signs with `CKM_SHA256_RSA_PKCS` and receives hash bytes from caller.
|
||||||
- Persist secrets in a vault or protected secret store.
|
This must be validated in your real provider environment.
|
||||||
|
|
||||||
### 13.2 Step 2 - Generate company signing key pair inside HSM
|
If provider expects raw data for this mechanism, integration may require adjustment.
|
||||||
|
This is why integration tests are critical.
|
||||||
|
|
||||||
One-line command:
|
---
|
||||||
|
|
||||||
```bash
|
## 12) Quick FAQ
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <company-slot-id> --login --pin "$USER_PIN" --keypairgen --key-type rsa:3072 --label company-sign-key-v1 --id 01 && pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <company-slot-id> --login --pin "$USER_PIN" --list-objects
|
|
||||||
```
|
|
||||||
|
|
||||||
Checkpoint:
|
**Q: Do I need REST calls to SoftHSM?**
|
||||||
|
|
||||||
- `Private Key Object` and `Public Key Object` exist for label `company-sign-key-v1`, id `01`.
|
No. SoftHSM is not a REST server. Use PKCS#11 library calls.
|
||||||
- Private key remains non-extractable in token.
|
|
||||||
|
|
||||||
### 13.3 Step 3 - Obtain CA-issued certificate for HSM key
|
**Q: Can I use proxy and still call it SoftHSM setup?**
|
||||||
|
|
||||||
Required policy:
|
Yes. Proxy can forward to SoftHSM-backed token infrastructure.
|
||||||
|
|
||||||
- Certificate must be issued by enterprise CA for the key generated in token.
|
**Q: Once I provide the 5 values, can tests run directly?**
|
||||||
- Do not use self-signed cert for production signing identity.
|
|
||||||
|
|
||||||
Operational note:
|
Yes. Set env vars and run the single `dotnet test` command above.
|
||||||
|
|
||||||
- CSR generation method depends on installed PKCS#11 OpenSSL integration (`engine_pkcs11` / provider).
|
**Q: Will one company cert/key be enough for this phase?**
|
||||||
- After CA issues certificate, import certificate DER into token with matching id/label family.
|
|
||||||
|
|
||||||
OpenSSL 3 prerequisite check:
|
Yes, for the diagram-aligned company-signing model, one company key/certificate is enough for initial implementation and validation.
|
||||||
|
|
||||||
```bash
|
|
||||||
openssl version && openssl engine -t -c 2>/dev/null | grep -i pkcs11 || true
|
|
||||||
```
|
|
||||||
|
|
||||||
If no PKCS#11 engine/provider is listed, install integration packages first (distribution specific), then continue.
|
|
||||||
|
|
||||||
### 13.4 Step 4 - Import CA certificate into token
|
|
||||||
|
|
||||||
One-line command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <company-slot-id> --login --pin "$USER_PIN" --write-object ./company-sign-cert-v1.der --type cert --id 01 --label company-sign-cert-v1 && pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot <company-slot-id> --login --pin "$USER_PIN" --list-objects
|
|
||||||
```
|
|
||||||
|
|
||||||
Checkpoint:
|
|
||||||
|
|
||||||
- `Certificate Object` exists with id `01` and expected label.
|
|
||||||
|
|
||||||
### 13.5 Step 5 - Wire runtime/test configuration
|
|
||||||
|
|
||||||
Server runtime (`EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json`) must include:
|
|
||||||
|
|
||||||
- `Crypt:Pkcs11:LibraryPath` = native PKCS#11 library path for the server host OS
|
|
||||||
- Windows host: Windows DLL path (vendor DLL or proxy client DLL)
|
|
||||||
- Linux host: Linux `.so` path
|
|
||||||
- `Crypt:Pkcs11:SlotId` = `2021549410` (or current company slot)
|
|
||||||
- `Crypt:Pkcs11:TokenLabel` = `CompanyProdToken`
|
|
||||||
- `Crypt:Pkcs11:UserPin` = real user pin
|
|
||||||
- `Crypt:Pkcs11:PrivateKeyLabel` = `company-sign-key-v1`
|
|
||||||
- `Crypt:Pkcs11:CertificateLabel` = `company-sign-cert-v1`
|
|
||||||
|
|
||||||
Test runtime (`EnvelopeGenerator.Tests/appsettings.json`) must mirror the same `Crypt:Pkcs11` values.
|
|
||||||
|
|
||||||
Then run tests:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
dotnet test "EnvelopeGenerator.Tests/EnvelopeGenerator.Tests.csproj" -f net8.0 --filter "FullyQualifiedName~EnvelopeGenerator.Tests.Application.Crypt"
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,301 +0,0 @@
|
|||||||
# FES Signature Infrastructure Plan
|
|
||||||
|
|
||||||
## 1. Goal
|
|
||||||
|
|
||||||
Build a reusable and modular cryptography infrastructure in `EnvelopeGenerator.Infrastructure.Crypt` to support FES (Advanced Electronic Signature) workflows.
|
|
||||||
|
|
||||||
This module must:
|
|
||||||
|
|
||||||
- use PKCS#11 providers (SoftHSMv2 first, real HSM later),
|
|
||||||
- stay independent from UI/API concerns,
|
|
||||||
- expose clean interfaces to `Application` layer use-cases,
|
|
||||||
- support future extensions (timestamping, certificate chain validation, multiple key algorithms).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Context and Constraints
|
|
||||||
|
|
||||||
1. SoftHSMv2 is **not** a REST service. It is a PKCS#11 module loaded as a native library.
|
|
||||||
2. `EnvelopeGenerator.Server` is presentation only; cryptographic implementation belongs to infrastructure.
|
|
||||||
3. Clean Architecture boundaries must be respected:
|
|
||||||
- `Application` depends on abstractions.
|
|
||||||
- `Infrastructure.Crypt` implements abstractions.
|
|
||||||
4. Initial target framework is `net8.0`.
|
|
||||||
5. We need production-ready behavior, not only PoC signing.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. High-Level Design
|
|
||||||
|
|
||||||
## 3.1 Architecture slice
|
|
||||||
|
|
||||||
- **Application layer (contracts/use-cases):**
|
|
||||||
- request signing hash/document,
|
|
||||||
- request certificate/public key material,
|
|
||||||
- request verification,
|
|
||||||
- consume signature evidence result.
|
|
||||||
|
|
||||||
- **Infrastructure.Crypt layer (this project):**
|
|
||||||
- PKCS#11 session handling,
|
|
||||||
- key/certificate object discovery,
|
|
||||||
- hash signing operations,
|
|
||||||
- local cryptographic verification,
|
|
||||||
- certificate parsing helpers,
|
|
||||||
- error normalization.
|
|
||||||
|
|
||||||
## 3.2 Provider model
|
|
||||||
|
|
||||||
Define provider-agnostic APIs and add one concrete provider first:
|
|
||||||
|
|
||||||
- `Pkcs11SignatureProvider` (primary)
|
|
||||||
- future providers:
|
|
||||||
- `RemoteSigningProvider` (if a dedicated signing gateway is introduced)
|
|
||||||
- `MockSignatureProvider` (for deterministic test scenarios)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Deliverables (Phase by Phase)
|
|
||||||
|
|
||||||
## Phase 0 - Contracts and Domain Language
|
|
||||||
|
|
||||||
Create neutral models and interfaces in `Infrastructure.Crypt` (or shared abstractions if needed later):
|
|
||||||
|
|
||||||
- `SigningAlgorithm` (enum/value object)
|
|
||||||
- `Pkcs11ProviderOptions`
|
|
||||||
- `KeyLocator` (label/id/slot/token selectors)
|
|
||||||
- `SignHashRequest`
|
|
||||||
- `SignHashResult`
|
|
||||||
- `VerifySignatureRequest`
|
|
||||||
- `VerifySignatureResult`
|
|
||||||
- `CertificateDescriptor`
|
|
||||||
- `SignatureEvidence` (technical evidence payload)
|
|
||||||
|
|
||||||
Interfaces:
|
|
||||||
|
|
||||||
- `ISignatureProvider`
|
|
||||||
- `ICertificateProvider`
|
|
||||||
- `ISignatureVerifier`
|
|
||||||
- `ICryptographicHealthCheck`
|
|
||||||
|
|
||||||
Acceptance criteria:
|
|
||||||
|
|
||||||
- no dependency on ASP.NET types,
|
|
||||||
- no UI/API naming leakage,
|
|
||||||
- all model names are business-neutral.
|
|
||||||
|
|
||||||
## Phase 1 - PKCS#11 Core Adapter (SoftHSM-ready)
|
|
||||||
|
|
||||||
Implement:
|
|
||||||
|
|
||||||
- `Pkcs11LibraryLoader`
|
|
||||||
- `Pkcs11SessionFactory`
|
|
||||||
- `Pkcs11ObjectFinder`
|
|
||||||
- `Pkcs11SignatureProvider`
|
|
||||||
- `Pkcs11CertificateProvider`
|
|
||||||
|
|
||||||
Capabilities:
|
|
||||||
|
|
||||||
1. load module path from options (`libsofthsm2.so` or proxy module when required),
|
|
||||||
2. enumerate slots/tokens,
|
|
||||||
3. open read-write session,
|
|
||||||
4. login with user pin,
|
|
||||||
5. find private key by label/id,
|
|
||||||
6. sign digest with selected mechanism,
|
|
||||||
7. read certificate object by label/id.
|
|
||||||
|
|
||||||
Acceptance criteria:
|
|
||||||
|
|
||||||
- deterministic disposal of sessions,
|
|
||||||
- no leaked native handles,
|
|
||||||
- detailed typed errors (not raw exception strings only).
|
|
||||||
|
|
||||||
## Phase 2 - Verification and Certificate Utilities
|
|
||||||
|
|
||||||
Implement:
|
|
||||||
|
|
||||||
- `DefaultSignatureVerifier`
|
|
||||||
- `X509CertificateParser`
|
|
||||||
- optional `CertificateChainValidator` (toggleable)
|
|
||||||
|
|
||||||
Capabilities:
|
|
||||||
|
|
||||||
1. verify signature using returned certificate/public key,
|
|
||||||
2. expose certificate metadata (`thumbprint`, `subject`, `issuer`, `notBefore`, `notAfter`),
|
|
||||||
3. map validation failures into stable error codes.
|
|
||||||
|
|
||||||
Acceptance criteria:
|
|
||||||
|
|
||||||
- same request yields same verification outcome,
|
|
||||||
- invalid signature returns structured negative result.
|
|
||||||
|
|
||||||
## Phase 3 - Evidence Builder
|
|
||||||
|
|
||||||
Implement:
|
|
||||||
|
|
||||||
- `SignatureEvidenceBuilder`
|
|
||||||
|
|
||||||
Evidence payload should contain:
|
|
||||||
|
|
||||||
- transaction/correlation id,
|
|
||||||
- algorithm,
|
|
||||||
- hash metadata,
|
|
||||||
- key locator snapshot (safe subset),
|
|
||||||
- certificate fingerprint and subject,
|
|
||||||
- sign timestamp (UTC),
|
|
||||||
- verification outcome,
|
|
||||||
- provider type (`PKCS11`).
|
|
||||||
|
|
||||||
Acceptance criteria:
|
|
||||||
|
|
||||||
- no secret values in evidence (pin, private key id internals),
|
|
||||||
- evidence serializable for storage/audit.
|
|
||||||
|
|
||||||
## Phase 4 - Dependency Injection Module
|
|
||||||
|
|
||||||
Implement:
|
|
||||||
|
|
||||||
- `CryptInfrastructureDependencyInjection` extension methods
|
|
||||||
|
|
||||||
Methods:
|
|
||||||
|
|
||||||
- `AddCryptInfrastructure(...)`
|
|
||||||
- `AddPkcs11Provider(...)`
|
|
||||||
|
|
||||||
Acceptance criteria:
|
|
||||||
|
|
||||||
- one-line registration from composition root,
|
|
||||||
- options validation on startup.
|
|
||||||
|
|
||||||
## Phase 5 - Test Suite (`EnvelopeGenerator.Tests`)
|
|
||||||
|
|
||||||
Add test categories for `net8.0`:
|
|
||||||
|
|
||||||
1. `Unit`:
|
|
||||||
- request validation,
|
|
||||||
- algorithm mapping,
|
|
||||||
- evidence building,
|
|
||||||
- error mapping.
|
|
||||||
2. `Integration` (conditional/manual profile):
|
|
||||||
- SoftHSM slot listing,
|
|
||||||
- login,
|
|
||||||
- sign hash,
|
|
||||||
- verify,
|
|
||||||
- certificate read.
|
|
||||||
|
|
||||||
Acceptance criteria:
|
|
||||||
|
|
||||||
- unit tests run in CI without native SoftHSM,
|
|
||||||
- integration tests run when module path + pins are provided via environment variables.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Proposed Project Structure
|
|
||||||
|
|
||||||
```text
|
|
||||||
EnvelopeGenerator.Infrastructure.Crypt/
|
|
||||||
Abstractions/
|
|
||||||
ISignatureProvider.cs
|
|
||||||
ICertificateProvider.cs
|
|
||||||
ISignatureVerifier.cs
|
|
||||||
ICryptographicHealthCheck.cs
|
|
||||||
Models/
|
|
||||||
SigningAlgorithm.cs
|
|
||||||
SignHashRequest.cs
|
|
||||||
SignHashResult.cs
|
|
||||||
VerifySignatureRequest.cs
|
|
||||||
VerifySignatureResult.cs
|
|
||||||
SignatureEvidence.cs
|
|
||||||
CertificateDescriptor.cs
|
|
||||||
KeyLocator.cs
|
|
||||||
Options/
|
|
||||||
Pkcs11ProviderOptions.cs
|
|
||||||
Pkcs11/
|
|
||||||
Pkcs11LibraryLoader.cs
|
|
||||||
Pkcs11SessionFactory.cs
|
|
||||||
Pkcs11ObjectFinder.cs
|
|
||||||
Pkcs11SignatureProvider.cs
|
|
||||||
Pkcs11CertificateProvider.cs
|
|
||||||
Verification/
|
|
||||||
DefaultSignatureVerifier.cs
|
|
||||||
X509CertificateParser.cs
|
|
||||||
Evidence/
|
|
||||||
SignatureEvidenceBuilder.cs
|
|
||||||
DependencyInjection/
|
|
||||||
CryptInfrastructureDependencyInjection.cs
|
|
||||||
Exceptions/
|
|
||||||
CryptographicOperationException.cs
|
|
||||||
Pkcs11ProviderException.cs
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Configuration Strategy
|
|
||||||
|
|
||||||
Use options (bound from host config) with environment override support:
|
|
||||||
|
|
||||||
- `Crypt:Provider = PKCS11`
|
|
||||||
- `Crypt:Pkcs11:LibraryPath`
|
|
||||||
- `Crypt:Pkcs11:SlotId` or token selectors
|
|
||||||
- `Crypt:Pkcs11:UserPin` (from secret store/env, not plain committed value)
|
|
||||||
- `Crypt:Pkcs11:PrivateKeyLabel`
|
|
||||||
- `Crypt:Pkcs11:CertificateLabel`
|
|
||||||
- `Crypt:Pkcs11:LoginType`
|
|
||||||
|
|
||||||
Validation rules:
|
|
||||||
|
|
||||||
- library path required,
|
|
||||||
- at least one key locator required,
|
|
||||||
- pin required for signing operations.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Error Model
|
|
||||||
|
|
||||||
Define stable error codes to prevent provider-specific leakage:
|
|
||||||
|
|
||||||
- `CRYPT_PROVIDER_UNAVAILABLE`
|
|
||||||
- `CRYPT_SLOT_NOT_FOUND`
|
|
||||||
- `CRYPT_LOGIN_FAILED`
|
|
||||||
- `CRYPT_KEY_NOT_FOUND`
|
|
||||||
- `CRYPT_CERT_NOT_FOUND`
|
|
||||||
- `CRYPT_SIGN_FAILED`
|
|
||||||
- `CRYPT_VERIFY_FAILED`
|
|
||||||
|
|
||||||
Map low-level exceptions to these codes with safe diagnostics.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Non-Functional Requirements
|
|
||||||
|
|
||||||
1. **Security:** never log pins or raw private key handles.
|
|
||||||
2. **Reliability:** deterministic cleanup (`IDisposable`/`IAsyncDisposable`).
|
|
||||||
3. **Observability:** structured logs with correlation id.
|
|
||||||
4. **Performance:** avoid repeated login per operation when a safe session strategy is available.
|
|
||||||
5. **Extensibility:** algorithm/provider mapping must be open for extension.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Implementation Order (Small Tasks)
|
|
||||||
|
|
||||||
1. Add models + interfaces.
|
|
||||||
2. Add options + validators.
|
|
||||||
3. Add PKCS#11 low-level loader/session wrappers.
|
|
||||||
4. Implement `Pkcs11SignatureProvider` for hash signing.
|
|
||||||
5. Implement certificate retrieval.
|
|
||||||
6. Implement verifier.
|
|
||||||
7. Implement evidence builder.
|
|
||||||
8. Add DI registration extension.
|
|
||||||
9. Add unit tests.
|
|
||||||
10. Add optional integration tests (SoftHSM profile).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. Definition of Done
|
|
||||||
|
|
||||||
Done means:
|
|
||||||
|
|
||||||
1. `Infrastructure.Crypt` exposes generic cryptographic services usable by Application use-cases.
|
|
||||||
2. SoftHSM-backed PKCS#11 sign/verify path works in integration tests.
|
|
||||||
3. All sensitive configuration is externalized.
|
|
||||||
4. Structured error codes are returned for expected failure scenarios.
|
|
||||||
5. Documentation exists for host registration and required settings.
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
# FES (Advanced Electronic Signature) Summary and Integration Plan - EN
|
|
||||||
|
|
||||||
This document summarizes the shared diagram flow (`Ablauf SignFlow Unternehmenszertifikat`) and provides a small-step integration plan for the `EnvelopeGenerator` solution.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1) Simplified flow summary
|
|
||||||
|
|
||||||
Flow logic:
|
|
||||||
|
|
||||||
1. The sender uploads a document and defines signers.
|
|
||||||
2. If a valid company certificate already exists in HSM, it is used with the company key pair.
|
|
||||||
3. If no valid company certificate exists, CA issuance/renewal flow is required.
|
|
||||||
4. The signer receives an e-mail with a signing link.
|
|
||||||
5. The signer completes SMS OTP (2FA) and performs UI signature interaction.
|
|
||||||
6. Backend computes the hash for the current signing stage and sends it to HSM.
|
|
||||||
7. HSM signs the hash with the private key and returns signature + certificate context.
|
|
||||||
8. Backend embeds digital signature and certificate into PDF and writes audit trail.
|
|
||||||
9. After all signers complete, the final artifact is archived.
|
|
||||||
10. The final signed document is distributed to signers.
|
|
||||||
|
|
||||||
Important: The visible UI signature is not yet the legal electronic signature. The legal signature is produced in backend+HSM steps.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2) Relation to current codebase (as-is)
|
|
||||||
|
|
||||||
- `EnvelopeGenerator.Server` is the presentation layer host (Blazor + API hosting).
|
|
||||||
- Business flow is handled in `Application` via MediatR pipelines.
|
|
||||||
- Current receiver flow is centered around UI overlay/signature capture.
|
|
||||||
- Missing FES core: PKCS#11 hash-sign-verify + certificate-based PDF embedding pipeline.
|
|
||||||
|
|
||||||
Critical deployment fact:
|
|
||||||
|
|
||||||
- `EnvelopeGenerator.Server` is planned to run on Windows.
|
|
||||||
- SoftHSM is currently planned to run on Linux.
|
|
||||||
- A Windows process cannot directly load Linux PKCS#11 module (`libsofthsm2.so`).
|
|
||||||
- Therefore, architecture must include a compatibility bridge (service or proxy) unless HSM/SoftHSM is local to Windows.
|
|
||||||
|
|
||||||
Conclusion: FES is not a replacement of the current flow; it is a cryptographic hardening layer behind it.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3) Why SoftHSM tests are foundational
|
|
||||||
|
|
||||||
The tests defined in `SOFTHSM_TEST_KILAVUZU_TR.md` are the technical prerequisite for FES:
|
|
||||||
|
|
||||||
- `slots/login` -> HSM connectivity and authentication
|
|
||||||
- `certificate` -> certificate retrieval path
|
|
||||||
- `sign` -> hash signing with private key
|
|
||||||
- `verify` -> signature and certificate consistency validation
|
|
||||||
|
|
||||||
Without these tests passing, diagram steps 6-8 should not go live.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4) Target architecture (clean architecture aligned)
|
|
||||||
|
|
||||||
### Deployment topology options (must choose one)
|
|
||||||
|
|
||||||
1. **Linux signing service (recommended)**
|
|
||||||
- Windows `EnvelopeGenerator.Server` calls Linux signing API over HTTPS.
|
|
||||||
- Linux signing service performs PKCS#11 operations against SoftHSM.
|
|
||||||
- Private keys never leave Linux/HSM boundary.
|
|
||||||
|
|
||||||
2. **PKCS#11 proxy bridge**
|
|
||||||
- Windows host loads a Windows PKCS#11 proxy client DLL.
|
|
||||||
- Proxy forwards PKCS#11 operations to Linux side connected to SoftHSM.
|
|
||||||
|
|
||||||
3. **Windows-local SoftHSM (dev/test)**
|
|
||||||
- SoftHSM also installed on Windows and used locally.
|
|
||||||
- Useful for local testing, not preferred production topology.
|
|
||||||
|
|
||||||
Decision note:
|
|
||||||
|
|
||||||
- For production-critical FES, choose option 1 by default unless enterprise HSM policy requires option 2.
|
|
||||||
- Keep option 3 for development convenience only.
|
|
||||||
|
|
||||||
### Layer responsibilities
|
|
||||||
|
|
||||||
- `EnvelopeGenerator.Server`:
|
|
||||||
- API endpoints, auth orchestration, input validation.
|
|
||||||
- FES branch routing: standard-sign path vs external signing-service/proxy path.
|
|
||||||
- No private-key material handling.
|
|
||||||
|
|
||||||
- `EnvelopeGenerator.Application`:
|
|
||||||
- Use cases such as `SignWithHsmCommand`.
|
|
||||||
- MediatR pipeline orchestration for status/history/audit.
|
|
||||||
- FES evidence model aggregation (ip/email/phone/user-agent/otp proof/timestamps).
|
|
||||||
|
|
||||||
- `EnvelopeGenerator.Infrastructure`:
|
|
||||||
- Implementations for `IPkcs11Service`, `IPdfSignatureService`, `ITimestampService`.
|
|
||||||
- Pkcs11Interop integration and cryptographic operations.
|
|
||||||
- Optional client for Linux signing service if topology option 1 is selected.
|
|
||||||
|
|
||||||
- `Domain`:
|
|
||||||
- Signature evidence and audit-trail models.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5) Small-step integration plan
|
|
||||||
|
|
||||||
## Phase 0 - Scope and contracts
|
|
||||||
|
|
||||||
1. Finalize signing algorithms (for example `SHA256_RSA_PKCS`).
|
|
||||||
2. Confirm strategy: company certificate vs signer-specific certificate.
|
|
||||||
3. Freeze mandatory audit fields:
|
|
||||||
- identity, OTP proof, IP, user-agent, transaction id, timestamps, hash metadata.
|
|
||||||
4. Freeze deployment topology decision:
|
|
||||||
- option 1 (Linux signing service), option 2 (PKCS#11 proxy), or option 3 (Windows-local SoftHSM).
|
|
||||||
5. Define production host mapping:
|
|
||||||
- where `EnvelopeGenerator.Server` runs,
|
|
||||||
- where HSM/SoftHSM runs,
|
|
||||||
- where certificate lifecycle is managed.
|
|
||||||
|
|
||||||
Deliverable: Technical decision record (ADR-style markdown).
|
|
||||||
|
|
||||||
## Phase 1 - PKCS#11 connector (infrastructure)
|
|
||||||
|
|
||||||
1. Define `IPkcs11Service` interface.
|
|
||||||
2. Add `Pkcs11Interop` implementation.
|
|
||||||
3. Add config model:
|
|
||||||
- library path, slot, token label, key label, certificate label.
|
|
||||||
4. Ensure secure secret handling for PIN.
|
|
||||||
5. Ensure host-compatible module loading:
|
|
||||||
- Windows server must load Windows DLL,
|
|
||||||
- Linux server must load Linux `.so`.
|
|
||||||
|
|
||||||
Deliverable: Testable PKCS#11 service with health/slot/login/sign/verify capabilities.
|
|
||||||
|
|
||||||
## Phase 1.5 - Cross-host bridge implementation
|
|
||||||
|
|
||||||
1. If option 1 selected:
|
|
||||||
- implement Linux signing service API contract (`/sign`, `/certificate`, `/health`),
|
|
||||||
- implement authenticated HTTP client in `EnvelopeGenerator.Server`.
|
|
||||||
2. If option 2 selected:
|
|
||||||
- install/configure PKCS#11 proxy client DLL on Windows,
|
|
||||||
- install/configure proxy server on Linux and bind to SoftHSM.
|
|
||||||
|
|
||||||
Deliverable: Windows-to-Linux signing communication path proven end-to-end.
|
|
||||||
|
|
||||||
## Phase 2 - Application use case
|
|
||||||
|
|
||||||
1. Add `SignDocumentHashCommand` (or equivalent).
|
|
||||||
2. Pipeline flow:
|
|
||||||
- compute/receive hash,
|
|
||||||
- sign with HSM,
|
|
||||||
- attach certificate context,
|
|
||||||
- verify,
|
|
||||||
- produce evidence object.
|
|
||||||
3. Add resilient error mapping and retry strategy.
|
|
||||||
|
|
||||||
Deliverable: HSM signing use case in Application layer.
|
|
||||||
|
|
||||||
## Phase 3 - PDF signature embedding
|
|
||||||
|
|
||||||
1. Implement PDF signature embedding via `IPdfSignatureService`.
|
|
||||||
2. Build signer-specific audit-trail pages.
|
|
||||||
3. Append all audit pages to final PDF artifact.
|
|
||||||
|
|
||||||
Deliverable: Signed PDF with certificate context and audit trail pages.
|
|
||||||
|
|
||||||
## Phase 4 - Presentation/API integration
|
|
||||||
|
|
||||||
1. Integrate FES option into submit flow (feature flag guarded).
|
|
||||||
2. Add operational endpoints:
|
|
||||||
- HSM health/check
|
|
||||||
- signature evidence query (restricted roles)
|
|
||||||
3. Keep DTOs safe; avoid exposing sensitive cryptographic material.
|
|
||||||
4. In `SignatureController.Submit`, add FES branch that sends signing payload + audit context to selected signing backend.
|
|
||||||
|
|
||||||
Deliverable: API-level orchestration with minimal UI disruption.
|
|
||||||
|
|
||||||
## Phase 5 - Audit, archive, distribution
|
|
||||||
|
|
||||||
1. Persist signature evidence records.
|
|
||||||
2. Include hash/cert metadata in archival package.
|
|
||||||
3. Add signed artifact reference to distribution e-mails.
|
|
||||||
|
|
||||||
Deliverable: Alignment with diagram steps 9-10.
|
|
||||||
|
|
||||||
## Phase 6 - Testing and operations
|
|
||||||
|
|
||||||
1. Postman collection + Newman automation.
|
|
||||||
2. Positive/negative matrix:
|
|
||||||
- wrong pin, wrong slot, missing cert, expired cert, HSM timeout.
|
|
||||||
3. Observability:
|
|
||||||
- structured logs, correlation id, latency metrics.
|
|
||||||
|
|
||||||
Deliverable: Production readiness checklist.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6) Transition strategy from test API to production flow
|
|
||||||
|
|
||||||
1. Keep `/api/pkcs11-test/*` only for non-production.
|
|
||||||
2. In production, use the same internal services through business endpoints only.
|
|
||||||
3. Roll out by feature flag:
|
|
||||||
- `FesEnabled=false` initially
|
|
||||||
- pilot sender group
|
|
||||||
- full rollout
|
|
||||||
|
|
||||||
4. Keep explicit environment matrix:
|
|
||||||
- local dev (option 3),
|
|
||||||
- integration/staging (option 1 or 2),
|
|
||||||
- production (option 1 or 2 only).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7) Risks and mitigations
|
|
||||||
|
|
||||||
- Certificate expiry risk -> proactive monitoring and renewal alerting.
|
|
||||||
- HSM connectivity risk -> retry policy, circuit breaker, fallback queue.
|
|
||||||
- PIN/secret exposure risk -> vault-backed secrets and rotation policy.
|
|
||||||
- Verification failure risk -> block PDF sealing and move envelope to technical hold state.
|
|
||||||
- Cross-host connectivity risk -> mTLS/JWT auth + timeout/retry/circuit breaker + health probe.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8) Short done checklist
|
|
||||||
|
|
||||||
- [ ] PKCS#11 service interface + implementation
|
|
||||||
- [ ] Application command + pipeline behaviors
|
|
||||||
- [ ] PDF signature embedding
|
|
||||||
- [ ] Audit-trail generation
|
|
||||||
- [ ] API integration + feature flag
|
|
||||||
- [ ] Postman/Newman regression suite
|
|
||||||
- [ ] Operational runbook and alerting rules
|
|
||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,84 +0,0 @@
|
|||||||
10/6/26, 10:46 PM
|
|
||||||
|
|
||||||
Test SoftHSM : SWINFRA-54
|
|
||||||
|
|
||||||
Projects / Infrastruktur Software / Issues /
|
|
||||||
|
|
||||||
Enter search…
|
|
||||||
|
|
||||||
SWINFRA-54
|
|
||||||
|
|
||||||
All…
|
|
||||||
|
|
||||||
Created by Marvin Kamm 3 months ago
|
|
||||||
|
|
||||||
Visible to issue readers 1
|
|
||||||
|
|
||||||
Updated by Matthias Dewald about 1 month ago
|
|
||||||
|
|
||||||
# **Test SoftHSM**
|
|
||||||
|
|
||||||
Project Priorität Status **SWI** Infrastruktur Softwa H Hoch O Offen re… Bearbeiter Fälligkeit Projekteinfluss MD _ ? ? Matthias Dewald Kein fälligkeit Kein projektbezug Boards No visible boards
|
|
||||||
|
|
||||||
Bitte eine Test-VM mit der Software SoftHSM bereitstellen.
|
|
||||||
|
|
||||||
Laut Info von @Henning Emrich soll die Installation unter Debian Linux deutlich einfacher sein, als unter Windows. Bitte prüfen.
|
|
||||||
|
|
||||||
@Hakan Tek & @OlgunR
|
|
||||||
|
|
||||||
Sollen bitte die API Ansteuerung testen
|
|
||||||
|
|
||||||
FYI
|
|
||||||
|
|
||||||
@Marlon Schreiber @Jan-Ulrich Hoss @Henning Emrich @Hakan Tek @OlgunR
|
|
||||||
|
|
||||||
**Attachments** 1
|
|
||||||
|
|
||||||
Files Attached to Comments
|
|
||||||
|
|
||||||
**PDF**
|
|
||||||
|
|
||||||
Ablauf SignFlow Un ternehme… 83 kB
|
|
||||||
|
|
||||||
MD _ **Matthias Dewald** Commented 3 months ago Ist für Dienstag 30.6 10:00 Uhr Eingeplant
|
|
||||||
|
|
||||||
HT **Hakan Tek** Commented 3 months ago
|
|
||||||
|
|
||||||
Für die Integration auf der .NET-Seite können wir die Pkcs11Interop-Bibliothek und die entsprechende DevExpress-Infrastruktur verwenden. @OlgunR, falls du noch weitere Vorschläge hast, füge sie bitte hinzu. @Marvin Kamm, @Henning Emrich, @Matthias Dewald, um mit den Tests beginnen zu können, benötigen wir die entsprechenden Verbindungsdaten für SoftHSM (Slot-ID, PIN, Bibliothekspfad usw.).
|
|
||||||
|
|
||||||
FYI
|
|
||||||
|
|
||||||
@Marlon Schreiber @Jan-Ulrich Hoss
|
|
||||||
|
|
||||||
bugtracker.dd:8080/issue/SWINFRA-54/Test-SoftHSM
|
|
||||||
|
|
||||||
1/2
|
|
||||||
|
|
||||||
10/6/26, 10:46 PM
|
|
||||||
|
|
||||||
Test SoftHSM : SWINFRA-54
|
|
||||||
|
|
||||||
MD
|
|
||||||
|
|
||||||
## **Matthias Dewald** Commented 3 months ago
|
|
||||||
|
|
||||||
Hallo zusammen, SoftHSM ist auf der 172.24.12.64 installiert:
|
|
||||||
|
|
||||||
Der Proxy läuft auf Port 5657 und erwartet Verbindungen über die Proxy-Bibliothek (libpkcs11-proxy.so)
|
|
||||||
|
|
||||||
@Hakan Tek Bitte testen
|
|
||||||
|
|
||||||
MD
|
|
||||||
|
|
||||||
## **Matthias Dewald** Commented about 1 month ago
|
|
||||||
|
|
||||||
Ablauf SignFlow Unternehmenszertifikat.drawio.pdf
|
|
||||||
|
|
||||||
**PDF**
|
|
||||||
|
|
||||||
Ablauf SignFlow Un ternehme… 83 kB
|
|
||||||
|
|
||||||
bugtracker.dd:8080/issue/SWINFRA-54/Test-SoftHSM
|
|
||||||
|
|
||||||
2/2
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
|
<ItemGroup>
|
||||||
<PackageReference Include="Bogus" Version="35.6.3" />
|
<PackageReference Include="Bogus" Version="35.6.3" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.6.0" />
|
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.6.0" />
|
||||||
@@ -28,60 +28,21 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.20" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.20" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.20" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.20" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.82.1" />
|
<PackageReference Include="Microsoft.Identity.Client" Version="4.82.1" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.14.0" />
|
<PackageReference Include="NUnit" Version="3.14.0" />
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
|
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.5" />
|
||||||
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
|
||||||
<PackageReference Include="Bogus" Version="35.6.3" />
|
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
|
||||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.6.0" />
|
|
||||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="4.3.0" />
|
|
||||||
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
|
||||||
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
|
|
||||||
<PackageReference Include="HtmlSanitizer" Version="9.0.892" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.17" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.17" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.17" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.17">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.17" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.82.1" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
|
||||||
<PackageReference Include="NUnit" Version="3.14.0" />
|
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
|
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
||||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
|
||||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure.Crypt\EnvelopeGenerator.Infrastructure.Crypt.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
|
|
||||||
<Compile Remove="Application\Crypt\**\*.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.6" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.6" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Using Include="NUnit.Framework" />
|
<Using Include="NUnit.Framework" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -54,8 +54,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Service",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Infrastructure.Doc", "EnvelopeGenerator.Infrastructure.Doc\EnvelopeGenerator.Infrastructure.Doc.csproj", "{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Infrastructure.Doc", "EnvelopeGenerator.Infrastructure.Doc\EnvelopeGenerator.Infrastructure.Doc.csproj", "{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Infrastructure.Crypt", "EnvelopeGenerator.Infrastructure.Crypt\EnvelopeGenerator.Infrastructure.Crypt.csproj", "{B33A3B17-A4F8-4307-9C51-DDFE1B292DE7}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -122,10 +120,6 @@ Global
|
|||||||
{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{B33A3B17-A4F8-4307-9C51-DDFE1B292DE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{B33A3B17-A4F8-4307-9C51-DDFE1B292DE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B33A3B17-A4F8-4307-9C51-DDFE1B292DE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B33A3B17-A4F8-4307-9C51-DDFE1B292DE7}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -150,7 +144,6 @@ Global
|
|||||||
{83ED2617-B398-4859-8F59-B38F8807E83E} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
|
{83ED2617-B398-4859-8F59-B38F8807E83E} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
|
||||||
{6B87FB5F-F4EA-45BE-A218-385DC2CE8E80} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
|
{6B87FB5F-F4EA-45BE-A218-385DC2CE8E80} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
|
||||||
{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
{3B6EFE8D-F1EE-4666-87A0-9F90149CC61A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
{B33A3B17-A4F8-4307-9C51-DDFE1B292DE7} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {73E60370-756D-45AD-A19A-C40A02DACCC7}
|
SolutionGuid = {73E60370-756D-45AD-A19A-C40A02DACCC7}
|
||||||
|
|||||||
Reference in New Issue
Block a user