.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.

  1. public void DotNETCMSTest(byte[] buffer)
  2. {
  3. ContentInfo content = new ContentInfo(buffer);
  4. SignedCms cms = new SignedCms();
  5. cms.Decode(buffer);
  6. try
  7. {
  8. cms.CheckSignature(true);
  9. }
  10. catch (CryptographicException ex)
  11. {
  12. Console.WriteLine(ex);
  13. }
  14. ShowDotNETParameters(cms);
  15. }
  16.  
  17. private void ShowDotNETParameters(SignedCms cms)
  18. {
  19. for (int i = 0; i < cms.SignerInfos.Count; i++)
  20. {
  21. Console.WriteLine("Subject name of signer #{0}:\t{1}", i + 1, cms.SignerInfos[i].Certificate.SubjectName.Name);
  22. // Podepsané atributy podpisu
  23. for (int j = 0; j < cms.SignerInfos[i].SignedAttributes.Count; j++)
  24. {
  25. Console.WriteLine("SignedAttributes #{0}:\tTyp: {1}\tOID: {2}", j + 1, cms.SignerInfos[i].SignedAttributes[j].Oid.FriendlyName, cms.SignerInfos[i].SignedAttributes[j].Oid.Value);
  26. for (int k = 0; k < cms.SignerInfos[i].SignedAttributes[j].Values.Count; k++)
  27. {
  28. switch (cms.SignerInfos[i].SignedAttributes[j].Oid.Value)
  29. {
  30. // Typ obsahu - PKCS 7 - data
  31. case "1.2.840.113549.1.9.3":
  32. Pkcs9ContentType contentType = cms.SignerInfos[i].SignedAttributes[j].Values[k] as Pkcs9ContentType;
  33. break;
  34. // Výtah zprávy
  35. case "1.2.840.113549.1.9.4":
  36. Pkcs9MessageDigest messageDigest = cms.SignerInfos[i].SignedAttributes[j].Values[k] as Pkcs9MessageDigest;
  37. break;
  38. // Čas podpisu z počítače, nikoliv z TSA
  39. case "1.2.840.113549.1.9.5":
  40. Pkcs9SigningTime signTime = cms.SignerInfos[i].SignedAttributes[j].Values[k] as Pkcs9SigningTime;
  41. break;
  42. default:
  43. break;
  44. }
  45. }
  46. }
  47.  
  48. // Nepodepsané atributy podpisu - TSA razítko apod.
  49. for (int j = 0; j < cms.SignerInfos[i].UnsignedAttributes.Count; j++)
  50. {
  51. Console.WriteLine("UnsignedAttributes #{0}:\tTyp: {1}\tOID {2}", j + 1, cms.SignerInfos[i].UnsignedAttributes[j].Oid.FriendlyName, cms.SignerInfos[i].UnsignedAttributes[j].Oid.Value);
  52. for (int k = 0; k < cms.SignerInfos[i].UnsignedAttributes[j].Values.Count; k++)
  53. {
  54. switch (cms.SignerInfos[i].UnsignedAttributes[j].Oid.Value)
  55. {
  56. // Časové razítko z TSA
  57. case "1.2.840.113549.1.9.16.2.14":
  58. // signTime bude null, protože se nejedná o timestamp podle .NETu
  59. Pkcs9SigningTime signTime = cms.SignerInfos[i].UnsignedAttributes[j].Values[k] as Pkcs9SigningTime;
  60. // Jediné co tedy máme je attributeObject, ale .NET nemá prostředky, co s tím, nebo jsem na ně zatím nenarazil
  61. Pkcs9AttributeObject attributeObject = cms.SignerInfos[i].UnsignedAttributes[j].Values[k] as Pkcs9AttributeObject;
  62. // Takže ho zatím jen zapíšu na disk
  63. string filetimestamp = string.Format("c:\\Devel\\Razitko_{0}_{1}", i, j);
  64. System.IO.File.WriteAllBytes(filetimestamp, attributeObject.RawData);
  65. break;
  66. default:
  67. break;
  68. }
  69. }
  70. }
  71. }
  72. }

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ář

Obsah tohoto pole je soukromý a nebude veřejně zobrazen.
  • Allowed HTML tags: <img> <a> <em> <strong> <cite> <code> <var> <abbr> <acronym> <kbd> <ul> <ol> <li> <dl> <dt> <dd> <blockcode> <h1> <h2> <h3> <h4> <h5> <table> <tbody> <thead> <tfoot> <tr> <td> <th> <p>
  • Řádky a odstavce se zalomí automaticky.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>.
  • You may link to Gallery2 items on this site using a special syntax.

Více informací o možnostech formátování

CAPTCHA
Je mi to moc líto, ale kvůli spamovacím robotům jsem musel zavést toto nepopulární opatření
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.