Przejdź do głównej zawartości
getnextpdf.com

Enterprise edycja

Podpisywanie HSM — szczegółowa referencja

Ta strona to dogłębna dokumentacja powierzchni podpisywania HSM w NextPDF Enterprise. Obejmuje trzy publiczne typy. NextPDF\Enterprise\Security\Signature\Hsm\Pkcs11Signer podpisuje przez token PKCS#11 za pośrednictwem rozszerzenia ext-pkcs11. NextPDF\Enterprise\Security\Signature\Hsm\OpenSslCliSigner podpisuje przez binarium openssl w podprocesie, dla kluczy opartych na dostawcy lub silniku, których PHP ext-openssl nie potrafi wczytać. NextPDF\Enterprise\Security\Signature\Hsm\Provider\HsmSignerProviderAdapter udostępnia każdy z konkretnych typów jako ujednolicony SignerProviderInterface. Na każdej ścieżce klucz prywatny pozostaje wewnątrz granicy tokenu; NextPDF przekazuje bajty do podpisania i otrzymuje podpis. Ścieżka post-kwantowa (signPqs) to podgląd: jest domyślnie wyłączona, nie niesie żadnego oświadczenia o zgodności i nie ma obsługiwanej ścieżki weryfikacji w obecnych walidatorach PDF. NextPDF nie posiada żadnej certyfikacji ani żadnej nie udziela; wsparcie nie równa się zgodności, a zgodność nie równa się certyfikacji.

Ta funkcja jest dostarczana w NextPDF Enterprise (nextpdf/enterprise) i aktywuje się wraz z kopertą licencji poziomu Enterprise. Wdrożenie bez tego uprawnienia nie wczytuje klas tej funkcji. Porównaj edycje i uzyskaj licencję.

Wszystkie trzy typy znajdują się w NextPDF\Enterprise\Security\Signature\Hsm; adapter mieści się w jego podprzestrzeni nazw Provider. Oba sygnatariusze implementują kontrakt Core NextPDF\Contracts\HsmSignerInterface.

SymbolParametryZachowanie domyślneZwracaRzuca lub kończy się niepowodzeniem zUwagi
Pkcs11Signer::__construct()string $libraryPath, int $slotId, string $pin, string $certLabel, ?string $keyLabel = null, array $chainDer = [], bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = nullOtwiera bibliotekę dostawcy, loguje się do slotu i wczytuje z tokenu certyfikat oraz metadane algorytmu kluczaHsmOperationException, gdy brakuje ext-pkcs11 lub dostęp do tokenu zawodziJeden uchwyt modułu jest buforowany na ścieżkę biblioteki na proces; PIN i etykiety mają #[SensitiveParameter]
Pkcs11Signer::sign()string $data, string $algorithm = 'sha256WithRSAEncryption'Podpisuje na tokenie; surowe wyjście ECDSA jest konwertowane do DER ECDSA-Sig-Valuestring surowe bajty podpisuHsmOperationException (klucz nieznaleziony, awaria tokenu); InvalidArgumentException (niezmapowany algorytm); wyjątki bramki FIPS przed podpisaniem, gdy podłączony jest enforcerZamknięty zbiór algorytmów; zobacz Kontrakt zachowania
Pkcs11Signer::signPqs()string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = trueOdrzucane, o ile nie ustawiono $enablePostQuantum; wysyła prowizoryczny mechanizm PQ PKCS#11string surowe bajty podpisuHsmOperationException (wyłączone, awaria tokenu, niezgodność długości podpisu); InvalidArgumentException (kontekst powyżej 255 bajtów)Podgląd; brak oświadczenia o zgodności; identyfikatory mechanizmu są prowizoryczne
Pkcs11Signer::isPostQuantumEnabled()BrakZgłasza flagę opt-in z konstruktoraboolBrak
Pkcs11Signer::getCertificateDer()BrakZwraca certyfikat sygnatariusza odczytany z tokenustring (DER)BrakWczytywany raz przy konstrukcji
Pkcs11Signer::getCertificateChainDer()BrakZwraca pośrednie certyfikaty dostarczone przez konstruktorarray<string> (DER)BrakWyklucza certyfikat sygnatariusza
OpenSslCliSigner::__construct()string $keyUri, string $certPath, string $pin, array $extraCertPaths = [], OpenSslCliBackend $backend = OpenSslCliBackend::Auto, string $opensslBinary = 'openssl', int $timeoutSeconds = 30, ?string $modulePath = null, ?string $configPath = null, bool $legacyPinDelivery = false, ?FipsSignatureEnforcer $fipsEnforcer = nullWeryfikuje proc_open, sonduje binarium i wersję, rozwiązuje backend oraz wczytuje certyfikatyHsmOperationException (proc_open wyłączone, brak pliku modułu/konfiguracji/certyfikatu, awaria binarium, brak backendu); InvalidArgumentException (pin-value wewnątrz $keyUri)OpenSslCliBackend::Auto preferuje dostawcę OpenSSL 3.x, następnie silnik
OpenSslCliSigner::sign()string $data, string $algorithm = 'sha256WithRSAEncryption'Uruchamia openssl dgst w podprocesie; PIN domyślnie wędruje przez efemeryczny plik pin-source 0600string surowe bajty podpisuHsmOperationException (timeout, PIN odrzucony, klucz nieznaleziony, awaria wczytania modułu, puste wyjście, awaria pliku pin); InvalidArgumentException (niezmapowany algorytm); wyjątki bramki FIPS przed podpisaniemPodproces jest ubijany po $timeoutSeconds; stderr jest redagowany, zanim trafi do komunikatów
Powierzchnia akcesorów OpenSslCliSignerBrakTylko do odczytu wyniki konstrukcjistring / array<string> / OpenSslCliBackendBrakgetCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion
HsmSignerProviderAdapter::__construct()HsmSignerInterface $hsm, string $providerId, SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15Opakowuje konkret HSM jako SignerProviderInterfaceBrakKonwencje id dostawcy: pkcs11-{module-id}, openssl-cli
HsmSignerProviderAdapter::providerId()BrakZwraca id dostarczone przez konstruktornon-empty-stringBrak
HsmSignerProviderAdapter::supportsAlgorithm()SignatureAlgorithm $algoMapuje enum na nazwę w stylu OpenSSL, następnie przecina ze zbiorem dozwolonym backenduboolBrakOdrzuca algorytmy typu digest-only; identyfikatory openssl-engine nie rozgłaszają niczego
HsmSignerProviderAdapter::sign()string $data, ?string $keyVersion = nullWysyła przez opakowany sygnatariusz z konfigurowanym algorytmemnon-empty-stringKeyManagementException (niepuste $keyVersion); SignatureFailedException (niemapowalny algorytm, awaria sterownika, pusty podpis)Kontrakt SPI fail-closed; każdy błąd sterownika wypływa typowany
public function __construct(private readonly string $libraryPath, private readonly int $slotId, #[SensitiveParameter] private readonly string $pin, #[SensitiveParameter] private readonly string $certLabel, #[SensitiveParameter] private readonly ?string $keyLabel = null, array $chainDer = [], private readonly bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = null)
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
public function signPqs(string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true): string
public function isPostQuantumEnabled(): bool
public function getCertificateDer(): string
public function getCertificateChainDer(): array
public function __construct(private string $keyUri, string $certPath, #[SensitiveParameter] private string $pin, array $extraCertPaths = [], private OpenSslCliBackend $backend = OpenSslCliBackend::Auto, private string $opensslBinary = 'openssl', private int $timeoutSeconds = 30, private ?string $modulePath = null, private ?string $configPath = null, private bool $legacyPinDelivery = false, private ?FipsSignatureEnforcer $fipsEnforcer = null)
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
public function getCertificateDer(): string
public function getCertificateChainDer(): array
public function getPublicKeyAlgorithm(): string
public function getCertificatePem(): string
public function getResolvedBackend(): OpenSslCliBackend
public function getOpensslVersion(): string
public function __construct(private HsmSignerInterface $hsm, private string $providerId, private SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15)
public function providerId(): string
public function supportsAlgorithm(SignatureAlgorithm $algo): bool
public function sign(string $data, ?string $keyVersion = null): string
  • Piecza nad kluczem. Klucz prywatny nigdy nie opuszcza granicy tokenu. Pkcs11Signer deleguje operację do tokenu; OpenSslCliSigner przekazuje referencję klucza — URI PKCS#11 — do podprocesu openssl. Żaden z sygnatariuszy nie potrafi wyeksportować klucza.
  • Sesja i logowanie. Pkcs11Signer buforuje jeden uchwyt modułu PKCS#11 na ścieżkę biblioteki na proces, ponieważ interfejs tokenu musi zostać zainicjalizowany dokładnie raz na proces. Każda operacja otwiera sesję i loguje się PIN-em; logowanie uwierzytelnia użytkownika przed jakimkolwiek użyciem klucza prywatnego (PKCS#11 v3.1 §5.6.8). Gdy slot zgłasza istniejące logowanie, sygnatariusz wylogowuje się i loguje ponownie, aby tokeny wymagające świeżego PIN-u na operację go otrzymały.
  • Zbiór algorytmów (zamknięty). Oba sygnatariusze akceptują dokładnie: sha256WithRSAEncryption, sha384WithRSAEncryption, sha512WithRSAEncryption; RSASSA-PSS, RSASSA-PSS-SHA256, RSASSA-PSS-SHA384, RSASSA-PSS-SHA512; ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512. Pkcs11Signer dodatkowo akceptuje ecdsa-raw. Każdy inny identyfikator wywołuje InvalidArgumentException — żaden algorytm zastępczy nigdy nie jest podpisywany.
  • Wiązanie soli PSS. Dla każdego wariantu PSS długość soli równa się długości skrótu — 32, 48 lub 64 bajty — a parametry hash i MGF pasują do wybranego skrótu. Wynika to ze struktury parametrów mechanizmu PSS, gdzie długość soli to zazwyczaj długość skrótu wiadomości (PKCS#11 v3.1 §6.1.9). Oba sygnatariusze stosują to samo parowanie, więc konfiguracja poprawna na jednym backendzie jest poprawna na drugim.
  • Konwersja ECDSA. Token zwraca podpis ECDSA jako surową, dopełnioną zerami konkatenację r i s (PKCS#11 v3.1 §6.3.1). Pkcs11Signer::sign() konwertuje to wyjście do zakodowanej w DER postaci ECDSA-Sig-Value, której oczekują walidatory PDF oraz OpenSSL. Wywołujący nigdy nie ma do czynienia z postacią surową.
  • Dostarczanie PIN-u (ścieżka CLI). W bezpiecznym trybie domyślnym PIN jest zapisywany do efemerycznego pliku utworzonego wyłącznie z uprawnieniami tylko dla właściciela, wskazywany przez atrybut pin-source w URI PKCS#11 i usuwany po zakończeniu podprocesu. W tym trybie PIN nie jest umieszczany w wierszu poleceń ani eksportowany do środowiska podprocesu. Przy $legacyPinDelivery = true PIN jest osadzony jako pin-value w URI, co jest obserwowalne w wierszu poleceń procesu; ten tryb jest wyłącznie opt-in.
  • Dyscyplina podprocesu. OpenSslCliSigner uruchamia binarium z tablicą argumentów — bez interpolacji powłoki — wymusza $timeoutSeconds, ubija podproces po wygaśnięciu i klasyfikuje stderr do typowanych błędów. Sekrety są redagowane ze stderr, zanim zostanie zacytowany w komunikacie wyjątku.
  • Semantyka adaptera. Token HSM nie ma koncepcji zarządzanej wersji klucza; kluczem na tokenie jest wersja. HsmSignerProviderAdapter::sign() odrzuca zatem każde niepuste $keyVersion z KeyManagementException, zamiast je ignorować. supportsAlgorithm() przecina mapowanie enum z akceptowanym zbiorem opakowanego backendu, więc adapter nigdy nie rozgłasza mechanizmu, który backend odrzuciłby w czasie podpisu. Pusty podpis ze sterownika wywołuje SignatureFailedException.
  • Podgląd post-kwantowy. signPqs() jest bramkowane flagą konstruktora $enablePostQuantum i w innym przypadku odmawia uruchomienia. Ciąg kontekstu jest ograniczony do 255 bajtów, co odpowiada granicy kontekstu ML-DSA (FIPS 204). Zwrócony podpis musi zgadzać się z dokładną długością bajtową wybranego zestawu parametrów Pkcs11PqsAlgorithm, w przeciwnym razie wywołanie zawodzi. Identyfikatory mechanizmu podążają za prowizorycznym rozszerzeniem PQ PKCS#11 i nie są ostateczne. Profile PAdES nie rozpoznają zestawów post-kwantowych, większość walidatorów PDF odrzuca takie podpisy, a NextPDF nie zapewnia dla nich ścieżki weryfikacji. Nie jest deklarowana żadna zgodność.
  • Skonstruowanie Pkcs11Signer bez ext-pkcs11 wywołuje HsmOperationException natychmiast; to rozszerzenie nie jest dołączane do standardowych dystrybucji PHP.
  • Etykieta certyfikatu lub klucza prywatnego, która nie pasuje do żadnego obiektu na tokenie, wywołuje HsmOperationException nazywający brakującą klasę obiektu. Etykieta klucza może na niektórych tokenach zgodnie z prawem różnić się od etykiety certyfikatu.
  • Powtarzające się nieudane logowania mogą zablokować PIN na tokenie; to token egzekwuje tę politykę, nie NextPDF. Tokeny, których klucze wymagają uwierzytelnienia przy każdym użyciu, otrzymują świeże logowanie przez ścieżkę wylogowania i ponowienia (PKCS#11 v3.1, semantyka always-authenticate).
  • OpenSslCliSigner odrzuca przy konstrukcji $keyUri, który już zawiera pin-value, fail-closed, ponieważ takie dostarczenie ominęłoby bezpieczną ścieżkę PIN-u.
  • W systemie Windows bezpieczny tryb pliku pin kończy się niepowodzeniem fail-closed z HsmOperationException: bity uprawnień pliku nie mogą tam ograniczyć nadań odczytu ACL, więc sygnatariusz odmawia pozostawienia PIN-u w postaci jawnej na ACL katalogu tymczasowego. Starsze dostarczanie PIN-u jest udokumentowaną, opcjonalną alternatywą dla zaufanych hostów Windows.
  • Automatyczne wykrywanie backendu wymaga OpenSSL 3.x dla ścieżki dostawcy; LibreSSL nigdy nie rozwiązuje się do dostawcy. Gdy nie powiedzie się ani sonda dostawcy, ani silnika, konstrukcja zawodzi z HsmOperationException, zamiast odkładać awarię na czas podpisu.
  • Podproces przekraczający $timeoutSeconds jest przerywany i raportowany jako timeout; podproces, który kończy się czysto z pustym wyjściem, jest raportowany jako awaria pustego podpisu. Żaden z tych warunków nie może wytworzyć częściowo podpisanego dokumentu.
  • Podpis post-kwantowy, którego długość bajtowa nie zgadza się z wybranym zestawem parametrów, jest odrzucany, zanim może dotrzeć do kodowania CMS.
  • HsmSignerProviderAdapter z wycofanym id dostawcy openssl-engine nie rozgłasza żadnych algorytmów, więc nieaktualna konfiguracja zawodzi przy wyborze dostawcy, a nie w czasie podpisu.

Oba sygnatariusze akceptują opcjonalny FipsSignatureEnforcer. Gdy jest podłączony, tryb FIPS jest aktywny dla tego sygnatariusza: sign() odrzuca niedozwolony algorytm podpisu lub klucz poniżej progu przed jakimkolwiek podpisywaniem na tokenie lub w podprocesie. Progi podążają za tabelą generowania podpisu — moduły RSA poniżej 2048 bitów oraz rzędy ECDSA poniżej 224 bitów są niedozwolone (NIST SP 800-131A Rev.2 §3 Table 2). Bez enforcera zachowanie pozostaje niezmienione. Bramka obejmuje wyłącznie klasyczną ścieżkę sign(); signPqs() jest regulowane własną flagą podglądu. Są to oświadczenia o możliwościach dotyczące kodu NextPDF: walidacja FIPS 140-3 przywiązuje się do modułu kryptograficznego poprzez CMVP, którym w tym wdrożeniu jest HSM lub dostawca operatora — NextPDF nie jest zwalidowanym modułem, nie posiada żadnej certyfikacji i żadnej nie udziela.

OświadczenieStandardKlauzula
Logowanie uwierzytelnia użytkownika wobec tokenu przed operacjami klucza prywatnego; błędny PIN odmawia dostępu.PKCS#11 v3.1§5.6.8
Klucze always-authenticate potrzebują świeżego logowania na użycie; powtarzające się nieudane ponowne uwierzytelnienie może zablokować PIN.PKCS#11 v3.1CKA_ALWAYS_AUTHENTICATE re-authentication
Podpis ECDSA tokenu to surowa konkatenacja r‖s; sygnatariusz konwertuje ją do DER dla interoperacyjności PDF.PKCS#11 v3.1§6.3.1
Parametry PSS wiążą hash, MGF i długość soli; sygnatariusze ustawiają sól równą długości skrótu.PKCS#11 v3.1§6.1.9
Bramka FIPS odmawia generowania podpisu z RSA poniżej 2048 bitów lub rzędem ECDSA poniżej 224 bitów.NIST SP 800-131A Rev.2§3 Table 2
Ciąg kontekstu post-kwantowego jest ograniczony do 255 bajtów.FIPS 204HashML-DSA context handling
Walidacja FIPS 140-3 przywiązuje się do modułów kryptograficznych poprzez CMVP.FIPS 140-3CMVP program scope

Wszystkie klauzule są parafrazowane; nie odtworzono żadnego tekstu normatywnego. NextPDF nie składa żadnego oświadczenia o certyfikacji. Sygnatariusze dostosowują swoje zachowanie do cytowanych klauzul jako możliwość. To, czy wytworzony podpis się weryfikuje, jest decyzją weryfikatora wobec jego kotwic zaufania; bezpieczeństwo klucza zależy od tokenu, HSM i operatora — nie od samego NextPDF.

  • Mechanizm dostarczania PIN-u podąża za konwencją pin-source w URI PKCS#11 (RFC 7512); ten RFC jest poza cytowanym korpusem, więc powyższe zachowanie jest ugruntowane w źródle produktu, a nie w cytacie ze specyfikacji.

  • Potwierdź, że środowisko uruchomieniowe wczytuje ext-pkcs11 przed skonstruowaniem Pkcs11Signer; konstrukcja zawodzi szybko, gdy rozszerzenia brakuje. Sygnatariusz CLI potrzebuje włączonego proc_open oraz binarium openssl z zainstalowanym dostawcą lub silnikiem PKCS#11.

  • PIN, etykieta certyfikatu i etykieta klucza mają #[SensitiveParameter], więc są wykluczone ze śladów stosu. Dostarczaj PIN z menedżera sekretów; nigdy nie zapisuj go w źródle, konfiguracji zatwierdzonej do systemu kontroli wersji ani w logach.

  • Konstrukcja jest kosztownym krokiem na obu sygnatariuszach: ścieżka PKCS#11 loguje się i czyta certyfikat, a ścieżka CLI sonduje binarium i backend. Skonstruuj raz i używaj ponownie tej instancji; bufor modułu na bibliotekę czyni powtarzaną konstrukcję wobec tej samej biblioteki bezpieczną.

  • Opakuj sygnatariusza w HsmSignerProviderAdapter, gdy wywołujący działa przez SignerProviderInterface. Przekaż kanoniczne id dostawcy dla opakowanej klasy — pkcs11-{module-id} lub openssl-cli — aby sprawdzenia możliwości używały właściwego zbioru dozwolonego backendu.

  • Przed włączeniem podglądu post-kwantowego zweryfikuj identyfikatory mechanizmu firmware’u tokenu wobec prowizorycznych wartości, które rejestruje NextPDF; niezgodność zawodzi w czasie podpisu. Nie włączaj podglądu dla produkcyjnego wyjścia PAdES.

  • getResolvedBackend() i getOpensslVersion() istnieją do zapisywania dowodów; utrwalaj je wraz z dowodem podpisu, gdy twój program zgodności wymaga odtwarzalności.

Ta strona dokumentuje wyłącznie zewnętrznie obserwowalne zachowanie oraz obsługiwaną powierzchnię publicznego API. Wewnętrzne ścieżki przestrzeni nazw, klasy pomocnicze, tabele mechanizmów, nazwy plików runbooków oraz prefiksy zgłoszeń są poza zakresem.