Securitatea semnăturilor electronice DigiOHS
Documentație tehnică și criptografică pentru semnătura electronică avansată (AES) implementată în DigiOHS, conformă cu Regulamentul UE 910/2014 (eIDAS) art. 26 și cu Legea 455/2001 din România.
Versiune document: 2026.04 · Operator: SC Moneta Digi SRL · CUI: 53243922 · Sediu: București · Contact: office@digiohs.com
1. Cadru legal & nivel AES
Toate fișele de instruire generate prin DigiOHS poartă o semnătură electronică avansată (AES) conform definiției din Regulamentul UE 910/2014 (eIDAS) art. 26. Concret, fiecare semnătură satisface simultan cele patru condiții:
- Linkată unic la semnatar — certificatul X.509 are în câmpul
subject.serialNumber(RFC 5280) un identificator personal verificabil (telefon din dosarul de personal, validat prin SMS OTP). - Identifică semnatarul —
commonNameconține numele complet,organizationNamefirma,organizationalUnitNameconține CUI-ul. - Sub controlul exclusiv al semnatarului — cheia privată RSA se generează ephemeral în memoria serverului doar după ce utilizatorul introduce un cod OTP cu 6 cifre primit prin SMS pe telefonul lui. Cheia nu se stochează niciodată nici pe disc, nici în baza de date.
- Detectează modificările ulterioare — semnătura PAdES Baseline B-B se calculează peste
ByteRange(toate octeții PDF-ului mai puțin signature dictionary). Orice byte schimbat invalidează verificarea criptografică.
2. Ierarhie PKI
DigiOHS operează o autoritate de certificare internă cu trei niveluri, izolată de CA-uri publice (nu este cross-signed). Toate certificatele utilizator sunt emise de Intermediate CA, niciodată direct de Root CA.
┌──────────────────────────────────────┐
│ DigiOHS Root CA │
│ RSA 4096 · valabil 20 ani │
│ Self-signed · keyUsage=keyCertSign │
│ Basic Constraints: CA=TRUE │
└──────────────────────────────────────┘
│ semnează
▼
┌──────────────────────────────────────┐
│ DigiOHS Issuing Intermediate CA │
│ RSA 4096 · valabil 5 ani │
│ keyUsage=keyCertSign + cRLSign │
│ pathLenConstraint=0 │
└──────────────────────────────────────┘
│ semnează
▼
┌──────────────────────────────────────┐
│ User Certificate (per semnătură) │
│ RSA 2048 · valabil 48 ore │
│ keyUsage=digitalSignature + │
│ nonRepudiation │
│ extKeyUsage=id-kp-documentSigning │
│ (OID 1.3.6.1.5.5.7.3.36) │
│ subject.serialNumber=<phone> │
└──────────────────────────────────────┘Un PDF semnat conține întreaga chain (User cert + Intermediate + Root) într-o structură CMS SignedData conformă PKCS#7. La validare, orice viewer compatibil PAdES (Adobe Reader, Foxit, pdfsig) poate verifica chain-ul fără apel la rețea, atât timp cât are Root CA în trust store.
3. Algoritmi criptografici
| Componentă | Algoritm | Mod / parametri |
|---|---|---|
| Cheia Root CA | RSA | 4096 biți · e=65537 · semnare SHA-256-RSA |
| Cheia Intermediate CA | RSA | 4096 biți · semnare SHA-256-RSA |
| Cheia utilizator (per semnătură) | RSA | 2048 biți · ephemeral |
| Hash semnătură | SHA-256 | FIPS 180-4 / RFC 6234 |
| Format semnătură | PAdES B-B | PKCS#7 detached · ETSI EN 319 142-1 |
| Criptare cheia Intermediate la-rest | AES-256-GCM | IV random 12 biți · authTag 128 biți · NIST SP 800-38D |
| PRNG | CSPRNG OS | /dev/urandom (Linux) via node:crypto |
| OTP | 6 cifre | stocat ca SHA-256 hash · TTL 5 minute · max 5 încercări |
| Marcă temporală | RFC 3161 TSA | FreeTSA / DigiCert TSA · best-effort |
Roadmap criptografic: ECDSA P-256 ca alternativă la RSA-2048 (gain de performanță), RSA-PSS în loc de PKCS#1 v1.5 padding (rezistență la atacuri Bleichenbacher), Post-Quantum (CRYSTALS-Dilithium) când NIST publică standardele finale.
4. Emiterea certificatelor
Niciun certificat utilizator nu este pre-emis sau cached. Fiecare semnătură generează un certificat nou, valabil 48 ore (durata standard pentru a permite reluarea fluxului în caz de erori temporare ale rețelei).
Pași la emitere (server-side):
- Validare OTP (6 cifre) introdus de utilizator vs hash SHA-256 stocat.
- Generare keypair RSA-2048 în memoria procesului Node (forge.pki.rsa.generateKeyPair).
- Construire CSR cu subject DN populat din dosarul de personal (CommonName, organizationName, OID 2.5.4.5 = telefon E.164).
- Adăugare extensii:
basicConstraints CA=false,keyUsage digitalSignature + nonRepudiation,extKeyUsage id-kp-documentSigning. - Decriptare cheie privată Intermediate CA (AES-256-GCM cu master key) și semnare CSR.
- Persistare în
digiohs_issued_certificates: serial, certPem (publicul), publicKeyHash, validity. Niciodată cheia privată. - Returnare în RAM a certificatului + cheii private către funcția de semnare PAdES.
- După aplicarea semnăturii, cheia privată iese din scope-ul funcției → garbage-collected.
5. Fluxul complet de semnare
Salariat (telefon) DigiOHS (server) MariaDB / Storage
───────────────────── ─────────────────── ──────────────────
1. WhatsApp link ────────▶
Verifică token OTP-link
Returnează formular semnătură
2. Trasează semnătura ────▶
Stochează signature image
───────▶ digiohs_stored_signatures
(imagine PNG)
3. Cere OTP ────────▶
Generează 6 cifre random
SHA-256(OTP) → DB
───────▶ digiohs_training_events
(otpHash, otpSentAt)
Trimite SMS Infobip ────▶ telefon E.164
4. Introduce OTP ────────▶
SHA-256(input) == DB hash?
↓ DA + max 5min trecute
Setează otpVerifiedAt
Setează completedAt
───────▶ digiohs_training_events
5. Cere PDF ────────▶
Verifică completedAt set
↓ DA
buildFisaPdf() → PDF nesem.
applyOrganizationWatermark()
─────────────────────────
issueUserCertificate():
- Generează RSA-2048 (RAM)
- Decriptează Intermediate
CA cu CA_MASTER_KEY
- Semnează cert utilizator
- Persistă DOAR certPem
───────▶ digiohs_issued_certificates
─────────────────────────
signPdfWithPades():
- normalizeToLegacyXref()
- plainAddPlaceholder()
- PKCS#7 detached signature
cu cheia ephemeral
─────────────────────────
Cere TSA timestamp (RFC 3161)
Embedează timestampToken
─────────────────────────
Cheia privată iese din scope
→ GC distruge octeții
Returnează PDF semnat ◀──── browser
audit log:
PADES_SIGNATURE_APPLIED
───────▶ digiohs_audit_eventsÎntregul ciclu de la prezentarea OTP-ului la PDF semnat: tipic 800-1500ms. Cheia privată trăiește efectiv ~50ms în memoria procesului Node.
6. Protecția cheilor private
Cheia utilizator (per semnătură)
Strategia: ephemeral, never-stored. Generată în memoria procesului, folosită pentru o singură operație de semnătură, distrusă la ieșirea din scope. Nu există persistență, nu există recuperabilitate. Aceasta e o postură mai puternică decât modelul KEK (Key Encryption Key) folosit de DocuSign, fiindcă nu există nimic de decriptat.
Cheia Intermediate CA
Singura cheie privată persistentă din sistem. Stocare:
- Tabela
digiohs_certificate_authorities, câmpencryptedKeyPem. - Format:
v1:<iv>:<authTag>:<ciphertext_b64> - Cifrare: AES-256-GCM. IV unic per cheie (12 octeți random). AuthTag 128 biți.
- Master key: 32 octeți (256 biți) stocată în
/etc/digiohs/ca-master.keycu permisiuni0440 root:digiohs— owner root (revocare instantă), citibil doar de procesul de aplicație care rulează sub user-uldigiohs, niciun alt user de shell nu îl poate accesa. Nu apare în.env.production, nu se loghează în deploy scripts, nu e listat deprintenvpe sistem.
Atacul ipotetic care recuperează intermediate CA ar necesita simultan: (a) acces root la serverul aplicației, (b) acces la DB dump. Cu ambele, atacatorul ar putea decriptaoricine Intermediate CA și emite el însuși certificate. Pentru a închide și această zonă, oferim un upgrade opțional cu HSM hardware (FIPS 140-2 Level 3) la cerere pentru clienți enterprise — cheia nu părăsește niciodată cipul, semnarea se face prin PKCS#11 API.
Root CA
Generată o singură dată la bootstrap, ținută offline sau pe HSM (după cerință). Folosită exclusiv pentru semnarea certificatelor Intermediate (operație rară, ~o dată la 5 ani). Nu e accesibilă proceselor aplicației în funcționarea normală.
7. Validarea semnăturii
O semnătură DigiOHS poate fi verificată în mai multe moduri:
a) Adobe Acrobat Reader (gratuit)
- Deschide PDF-ul semnat → tab Signatures (panou stânga).
- Click pe semnătură → Validity Status.
- La prima verificare: import Root CA în trust store (DigiOHS publică fingerprint-ul Root CA pe această pagină — vezi mai jos).
- Adobe verifică: integritatea bytes, lanțul de certificate, timestamp-ul TSA, dacă certificatele nu au fost revocate (CRL/OCSP).
b) Linie de comandă (pdfsig / openssl)
# pdfsig (poppler-utils) pdfsig -nocert fisa.pdf # extragere semnătură + verificare openssl pdfsig -dump-sig fisa.pdf openssl pkcs7 -inform DER -in signature.bin -print_certs
c-bis) Forensic monitoring continuu
Pe lângă semnătura propriu-zisă, un cron orar verifică integritatea audit log-ului:
- Pentru fiecare
TrainingEventfinalizat în ultimele 25h, verifică existența unuiAuditEventcorespunzător cu acțiuneaTRAINING_OTP_VERIFIED. Dacă lipsește → posibil bypass prin SQL direct → alertă email laoffice@digiohs.com. - Pentru fiecare semnătură instructor/verificator atașată recent, verifică audit corespondent (
TRAINING_BATCH_*_SIGNEDsauPADES_SIGNATURE_APPLIED). - Recalculează SHA-256 hash chain pentru ultimele 5.000 evenimente audit. Orice divergență față de valoarea stocată (
hashChain) detectează tampering pe tabela de audit însăși.
Toate anomaliile generează alertă email la office@digiohs.com + ping Slack. Cron-ul rulează cu lock distribuit (MariaDB GET_LOCK) → o singură execuție / oră, indiferent câte hosturi sunt active. Răspunde la întrebarea Q4 din checklist-ul de due diligence: chiar dacă un atacator cu acces SQL direct ar bypass OTP-ul, modificarea ar fi detectată în maxim 1 oră.
c) eIDAS proof bundle (pentru audit ITM)
DigiOHS oferă, prin endpoint-ul GET /api/training/eidas-proof?event=..., un PDF de probă care include: hash-ul fișei semnate, timestamp TSA, lanțul complet de certificate, log-ul de audit cu IP + user agent + timestamp OTP, plus referințele legale eIDAS art. 26 + Legea 455/2001.
d) DigiOHS Root CA — fingerprint public
Pentru a evita afișarea „semnătură de la emitent necunoscut" în Adobe Reader, importă Root CA-ul nostru în trust store-ul tău (Tools → Trust Manager → Trusted Certificates).
SHA-256 fingerprint Root CA: disponibil la cerere viaoffice@digiohs.com(publicăm fingerprint-ul exact după bootstrap-ul producției — momentan în staging).
8. Conformitate și standarde
- Regulament UE 910/2014 (eIDAS) art. 26 — definiția AES. Toate cele patru condiții satisfăcute (vezi secțiunea 1).
- Legea 455/2001 (RO) — privind semnătura electronică. Articolele 4 + 5 — semnătura electronică extinsă (echivalent AES) are aceeași valoare juridică ca semnătura olografă.
- Codul Muncii (RO) art. 16 și HG 1425/2006 — cadrul pentru fișele individuale de instruire SSM/SU semnate digital.
- ETSI EN 319 142-1 — formatul PAdES Baseline B-B implementat.
- RFC 5280 — X.509 v3 certificate profile. Toate certificatele noastre respectă profilul.
- RFC 3161 — Time-Stamp Protocol. Timestamp-uri din TSA externe (FreeTSA / DigiCert).
- NIST SP 800-38D — modul GCM pentru AES-256.
- FIPS 180-4 / RFC 6234 — SHA-256.
- GDPR (UE 2016/679) — datele personale ale semnatarului (telefon, nume) sunt stocate exclusiv în certificat și DB-ul intern; nu sunt expuse public sau transmise către terți. Retenție: 5 ani conform legislației RO pentru documente SSM, apoi anonimizare.
9. Contact security & vulnerability disclosure
Pentru întrebări de due diligence, audit criptografic, sau raportare de vulnerabilități:
Răspundem la rapoarte de vulnerabilitate în maxim 5 zile lucrătoare. Pentru contracte enterprise oferim NDA-uri standard, audit acces la cod, și asistență la integrare HSM la cerere.
