💡 Kompletní funkční příklad je k dispozici na GitHubu:
digital-signing-certificate-validity-dotnet

Problém souladu, který nikdo nevidí, dokud ho neodhalí auditor

Podpisová služba běží tři roky bez chyby. Dokumenty jsou odesílány, příjemci je přijímají a v protokolech se neobjevuje žádná známka problému. Pak validátor protistrany označí dávku jako neplatnou a vyšetřování odhalí dva důvody: podpisy byly vytvořeny pomocí SHA‑1 a během posledních čtyř měsíců byl certifikát již prošlý.

Obě selhání byla při podpisu tichá. To je to, co mění GroupDocs.Signature 26.9.

Vynucení platnosti certifikátu je novým výchozím chováním pro digitální podepisování v .NET: certifikát mimo své platnostní období je odmítnut místo toho, aby byl použit. Přichází s dvěma doprovodnými prvky – SHA‑256 jako výchozí PDF digest a LogLevel, který konečně filtruje – a společně přesouvají tři třídy selhání od příjemce zpět k odesílateli, kde je stále možné je opravit.

Proč je tichý úspěch nákladný výsledek

Podepisování je neobvyklé tím, že strana, která udělá chybu, není ta, která ji objeví. Poškozená faktura selže ve vašem vlastním systému; neplatný podpis selže v systému někoho jiného o několik týdnů později, bez jakéhokoli diagnostického výstupu, který byste mohli přečíst.

Tato asymetrie je důvod, proč „API vrátilo úspěch“ není zde užitečnou zárukou. Staré výchozí nastavení bylo optimalizováno tak, aby nerušilo volajícího, a náklady dopadly na příjemce a nakonec na toho, kdo musel znovu podepsat a znovu odeslat několik stovek dokumentů.

Změna 1: Prošlé certifikáty jsou odmítány

Hlavní změna. Sign nyní vyhodí GroupDocsSignatureException, pokud platnost certifikátu skončila nebo ještě nezačala, a nic se neukládá na disk.

try
{
    signature.Sign(outputPath, options);
    return true;
}
catch (GroupDocsSignatureException ex)
{
    Console.WriteLine($"   Rejected: {ex.Message}");
    return false;
}

Zpráva uvádí název certifikátu a vlastnost, která by to umožnila, takže operátor čtoucí řádek v logu může jednat bez otevírání dokumentace. Pro pipeline, která přechází na 26.9 a začíná selhávat, je to téměř vždy důvod – a správná reakce je obnovení, nikoli potlačení.

Když skutečně potřebujete staré chování, jde o jedinou vlastnost:

var options = new DigitalSignOptions(certificate)
{
    Password = certificatePassword,
    AllowExpired = true
};

Dokument je podepsán a varování je odesláno do loggeru. Validátory stále výsledek odmítají, protože AllowExpired řídí, co knihovna povolí, nikoli hodnotu certifikátu. Doprovodná vlajka AllowNotYetValid pokrývá druhý konec okna a je úmyslně nezávislá: povolení prošlého certifikátu tiše neumožňuje také certifikát s budoucí platností.

Změna 2: SHA‑256 jako výchozí

Digitální PDF podpisy jsou nyní zapisovány pomocí SHA‑256 ve formátu adbe.pkcs7.detached, který očekávají současní validátory. Starší verze používaly SHA‑1.

var options = new DigitalSignOptions(certificate)
{
    Password = certificatePassword,
    HashAlgorithm = HashAlgorithm.Sha256,
    Reason = "Approved",
    Location = "Head office"
};

Explicitní nastavení vlastnosti je potřeba jen tehdy, když chcete jít dál – Sha384 nebo Sha512, pokud to politika vyžaduje – nebo když chcete zůstat u Sha1 pro validátor, který nedokáže zpracovat nic jiného. Časové razítko přidané k podpisu používá stejný digest.

Ověřování se změnilo ve stejném vydání a stejným směrem: DigitalVerifyOptions bez kritérií byl dříve téměř nečinný, nyní provádí úplnou kryptografickou kontrolu, takže dokument upravený po podpisu je hlášen jako neplatný.

Změna 3: LogLevel skutečně filtruje

SignatureSettings již dlouho přijímá logger. Před verzí 26.9 byl úroveň ignorována, takže každá zpráva dorazila bez ohledu na nastavení a většina služeb vypnula logování místo toho, aby se topila ve stopách.

Ukázka umožňuje měřitý rozdíl tím, že podepíše stejný dokument třikrát pomocí počítacího loggeru:

var levels = new Dictionary<string, LogLevel>
{
    ["None"] = LogLevel.None,
    ["Warning | Error"] = LogLevel.Warning | LogLevel.Error,
    ["All"] = LogLevel.All
};

None generuje nulové zprávy, Warning | Error zachová jedinou výstrahu vyvolanou povoleným prošlým certifikátem a All přidá stopu pro každý krok. Samotný počítací logger je integrační bod pro váš vlastní stack:

public void Warning(string message)
{
    Warnings++;
    WarningMessages.Add(message);
}

Implementujte tyto tři metody pro Serilog, NLog nebo Application Insights a diagnostika knihovny bude zaznamenána tam, kde logujete zbytek své služby.

Mění úroveň logování, jaké výjimky dostanu?

Ne, a stojí za to to explicitně uvést, protože se to může zdát související. LogLevel filtruje, co se dostane k ILogger. Výjimky jsou vyhazovány do vašeho kódu bez ohledu na úroveň: prošlý certifikát bez AllowExpired stále vyhodí výjimku i při LogLevel.None a váš blok catch se chová identicky. Diagnostika a řízení toku jsou oddělené kanály, což umožňuje bezpečně provozovat produkci na Warning | Error.

Odmítnutí je levnější, než se zdá

Námitka proti tvrdému zastavení je provozní: noční dávka, která dříve skončila, nyní selže v 02:00 a někdo je povolán. To je skutečný náklad, ale stále menší. Odmítnutá dávka představuje jedno upozornění, jedno obnovení a jedno opětovné spuštění, vše v rámci vašich vlastních systémů. Dávka podepsaná prošlým certifikátem je objevena příjemcem, což znamená vlákno podpory, opětovné vydání každého postiženého dokumentu a nepříjemnou konverzaci o tom, jak dlouho to probíhalo.

Ukázka dělá selhání konkrétním místo teoretickým: úmyslně podepíše s prošlým certifikátem, zachytí výjimku a vytiskne zprávu, takže můžete přesně vidět, co budou vaše logy obsahovat, než aktualizace dorazí do produkce. Doporučuji spustit tuto metodu proti vašemu vlastnímu úložišti certifikátů před naplánováním zvýšení verze.

Co udělat před aktualizací

Tři kontroly, řazené podle pravděpodobnosti, že vás potrápí.

Prozkoumejte expiraci certifikátů ve všech podepisovacích cestách, včetně těch, které běží měsíčně nebo čtvrtletně – tam se prošlý certifikát nejdéle skrývá. Pak vyhledejte HashAlgorithm: pokud nic nenastavuje, vaše digesty se při aktualizaci změní ze SHA‑1 na SHA‑256, což je vylepšení, které by mělo být uvedeno v poznámkách k vydání. Nakonec záměrně zvolte úroveň logování. Poctivý výchozí stav pro službu je Warning | Error; All slouží k reprodukci konkrétního problému a None znamená vzdát se jediného signálu, který vám říká, že podpis byl vytvořen pod výjimkou.

Ověřování se změnilo stejným směrem

Je snadné to přehlédnout, protože v kódu volajícího se nic nemění. DigitalVerifyOptions bez nastavených kritérií byl dříve téměř nečinný: porovnával poskytnutá kritéria a pokud žádná nebyla, neměl co říci. Od verze 26.9 stejná volání provádějí úplnou kryptografickou kontrolu každého digitálního PDF podpisu.

Pro službu, která ověřuje příchozí dokumenty, je to tichý upgrade z „tady je podpis“ na „tento podpis odpovídá tomuto obsahu“. Stojí za to vědět, než uvidíte, že dokument začíná selhávat při ověřování, které prošlo minulý měsíc: dokument byl pravděpodobně upraven a starší kontrola ho prostě neodhalila.

Certifikáty ve vzorku

Jedna podrobnost, kterou je vhodné zkopírovat místo kódu: ukázka neobsahuje žádný soukromý klíč. TestCertificates.cs vytváří ve výpočetní paměti tři samopodepsané PFX soubory – platný, prošlý minulý rok, platný od příštího roku – takže demonstrace funguje bez ohledu na aktuální datum a v repozitáři není nic citlivého.

Tento vzor stojí za přijetí ve vašich vlastních testovacích sadách. Závazný testovací certifikát časem vyprší a když k tomu dojde, selhání vypadá přesně jako chyba, kterou tato verze měla odhalit.

Závěr

Tři změny, jeden směr: selhání, která se dříve objevovala u příjemce, se nyní objevují u odesílatele. Obnovte certifikát místo použití AllowExpired, nechte SHA‑256 jako výchozí, kryptograficky ověřujte příchozí dokumenty a zvolte úroveň logování dříve, než ji budete potřebovat. Ukázka spouští všech šest chování v jednom průchodu, včetně odmítnutí, takže aktualizaci lze natrénovat během několika minut.

Další zdroje