.NET a PKCS#7 struktura
V současné době experimentuju s PKCS#7 strukturou pro práci s elektronicky podepsanými lékařskými zprávami. Náš firemní produkt používá velmi dobrou knihovnu od firmy AEC, ale potřebujeme mít jistotu, že se k záznamům a možnosti ověření podpisů zprávy dostaneme i jiným způsobem, než-li pomocí knihovny Trustport PKI SDK.
V PKCS#7 struktuře je možné uložit libovolný soubor a následně jej opatřit jedním a více elektronickými podpisy, časovými razítky a podle potřeby připojit i CRL. Nebudu se zabývat vytvořením struktury, přidáváním podpisů, razítek a CRL, ale pouze validací dat z této struktury.
Klasický .NET má poměrně dobrou podporu pro práci s touto strukturou. Velmi elegantně a jednoduše se lze dostat k informacím o tom, kdo zprávu podepsal, bohužel k časovému razítku TSA se již tak elegantně dostat nelze.
public void DotNETCMSTest(byte[] buffer) { ContentInfo content = new ContentInfo(buffer); SignedCms cms = new SignedCms(); cms.Decode(buffer); try { cms.CheckSignature(true); } catch (CryptographicException ex) { Console.WriteLine(ex); } ShowDotNETParameters(cms); } private void ShowDotNETParameters(SignedCms cms) { for (int i = 0; i < cms.SignerInfos.Count; i++) { Console.WriteLine("Subject name of signer #{0}:\t{1}", i + 1, cms.SignerInfos[i].Certificate.SubjectName.Name); // Podepsané atributy podpisu for (int j = 0; j < cms.SignerInfos[i].SignedAttributes.Count; j++) { Console.WriteLine("SignedAttributes #{0}:\tTyp: {1}\tOID: {2}", j + 1, cms.SignerInfos[i].SignedAttributes[j].Oid.FriendlyName, cms.SignerInfos[i].SignedAttributes[j].Oid.Value); for (int k = 0; k < cms.SignerInfos[i].SignedAttributes[j].Values.Count; k++) { switch (cms.SignerInfos[i].SignedAttributes[j].Oid.Value) { // Typ obsahu - PKCS 7 - data case "1.2.840.113549.1.9.3": Pkcs9ContentType contentType = cms.SignerInfos[i].SignedAttributes[j].Values[k] as Pkcs9ContentType; break; // Výtah zprávy case "1.2.840.113549.1.9.4": Pkcs9MessageDigest messageDigest = cms.SignerInfos[i].SignedAttributes[j].Values[k] as Pkcs9MessageDigest; break; // Čas podpisu z počítače, nikoliv z TSA case "1.2.840.113549.1.9.5": Pkcs9SigningTime signTime = cms.SignerInfos[i].SignedAttributes[j].Values[k] as Pkcs9SigningTime; break; default: break; } } } // Nepodepsané atributy podpisu - TSA razítko apod. for (int j = 0; j < cms.SignerInfos[i].UnsignedAttributes.Count; j++) { Console.WriteLine("UnsignedAttributes #{0}:\tTyp: {1}\tOID {2}", j + 1, cms.SignerInfos[i].UnsignedAttributes[j].Oid.FriendlyName, cms.SignerInfos[i].UnsignedAttributes[j].Oid.Value); for (int k = 0; k < cms.SignerInfos[i].UnsignedAttributes[j].Values.Count; k++) { switch (cms.SignerInfos[i].UnsignedAttributes[j].Oid.Value) { // Časové razítko z TSA case "1.2.840.113549.1.9.16.2.14": // signTime bude null, protože se nejedná o timestamp podle .NETu Pkcs9SigningTime signTime = cms.SignerInfos[i].UnsignedAttributes[j].Values[k] as Pkcs9SigningTime; // Jediné co tedy máme je attributeObject, ale .NET nemá prostředky, co s tím, nebo jsem na ně zatím nenarazil Pkcs9AttributeObject attributeObject = cms.SignerInfos[i].UnsignedAttributes[j].Values[k] as Pkcs9AttributeObject; // Takže ho zatím jen zapíšu na disk string filetimestamp = string.Format("c:\\Devel\\Razitko_{0}_{1}", i, j); System.IO.File.WriteAllBytes(filetimestamp, attributeObject.RawData); break; default: break; } } } } }
A cože metoda DotNETCMSTest(byte[] buffer)
vlastně dělá? Nic užitečného, jen otestuje, nedošlo-li k narušení struktury a vypíše seznam podepisovaných a nepodepisovaných atributů.
buffer je pole bytů, načtené ze souboru např. pomocí System.IO.File.ReadAllBytes
Proměnná content je typu System.Security.Cryptography.Pkcs.ContentInfo
a ve své podstatě ji nijak nepoužívám, jen mi pomohla zjistit, že se skutečně jedná o PKCS 7 - data.
ContentInfo
má dvě property:
Content
- typ
byte[]
, obsahuje vlastní CMS/PKCS #7 strukturu ContentType
- typ
System.Security.Cryptography.Oid
, obsahuje OID informaci o jaký typ obsahu se vlastně jedná
Třída System.Security.Cryptography.Oid
je určena pro práci s OID
a podle mého skromného názoru přehlednější (nikoliv lepší), než-li její obdoba Org.BouncyCastle.Asn1.DerObjectIdentifier
z projektu Bouncy Castle.
Katalog jednotlivých OID je k nalezení např. na www.alvestrand.no nebo www.oid-info.com.
Tato třída obsahuje property následující property:
FriendlyName
- typ
string
, uživatelsky čitelná reprezentace OID objektu, pokud je schopen systém přeložit OID na nějaký text, vrací v této property její název, např Typ obsahu, Čas podpisu nebo Výtah ze zprávy, jinak vrací null. Value
- typ
string
, vlastní textová reprezentace OID objektu, např 1.2.840.113549.1.9.5.
Dále je použita proměnná cms, která je typu System.Security.Cryptography.Pkcs.SignedCms
.
Bude ještě dopracováno ...
Poslat nový komentář