AL icon indicating copy to clipboard operation
AL copied to clipboard

.NET cryptography handling

Open marekjz opened this issue 7 years ago • 8 comments

I'm using System.Security.Cryptography.MD5 for files integrity check - also large ones (ZIP files over 100MB - probably too large to use Azure micro service effectively). The files are then exported with their MD5 hash appended as files postfix. The files are stored as BLOBs, then passed further to file distribution agent that is running on another server (talking to NAV via web service). The principle is to "stamp" the file with integrity checksum right after it's generated (and before it is passed further).

I can also imagine need to use other cryptographic functions (like SHA256, SHA512, maybe AES, RSA, ECC, and high quality random functions etc)... This kind of functionality is in general good to have locally, not as an external (micro) service.

Are you planning to implement equivalent of .NET cryptographic functions as a part of AL?

By the way, are you planning to still support the .NET functionality used by standard objects, e.g. Codeunit 419 (File Management), for example used for ZIP compression?

Code examples (i.e. how I use the .NET's MD5 function now): SysSecCryptMD5 := SysSecCryptMD5.Create; ZipFileHash := DELCHR(SysBitConvrtr.ToString(SysSecCryptMD5.ComputeHash(SysIOFile.OpenRead(ServerFilePath))), '=', '-');

I am using a bit more .NET libraries:

  • System.Security.Cryptography.MD5.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
  • System.BitConverter.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
  • System.IO.File.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

Currently I am using temporary server files (used also by Codeunit #419 / "File Management") but with "AL"/Tenerife will not use files/System.IO.File, which should be replaced by equivalent streams.

marekjz avatar Apr 26 '17 09:04 marekjz

.NET connection would be very fine. My customers do not want to submit data to Azure so Azure Functions is out of the question. I also need something like Newtonsoft.JSON or MimeKit or System.Threading.Tasks.

Gallimathias avatar May 08 '17 06:05 Gallimathias

Is there any status update on this? In general, if there is no intention of providing .NET Interop capability, you will have to add a lot of base .NET functionality. I love the fact that we have now the ability for Xml and Json, but especially when communicating with web services/REST APIs, we will need MD5 implementation.

pzentner avatar Jul 27 '17 15:07 pzentner

Since you mentioned MD5, check out https://security.stackexchange.com/questions/19906/is-md5-considered-insecure

doivosevic avatar Jul 31 '17 09:07 doivosevic

You are correct, MD5 is not necessarily the best choice, but as you can see, I at least mentioned "communication with REST APIs" and I don't have control over the APIs. This is what a lot of developers still use. It also doesn't matter necessarily, even if we could use SHA-2, it would be great. The biggest issue is that we don't have access to any .NET Interop anymore and therefore cannot even "choose" what algorithms we want to use.

pzentner avatar Jul 31 '17 11:07 pzentner

Please see if the new methods added to C/AL Open Library satisfy your requirement: https://github.com/Microsoft/cal-open-library/pull/10

StanislawStempin avatar Oct 05 '17 09:10 StanislawStempin

Hash-suite in Microsoft/AL looks very good 👍 Some would find also very convenient to have System.Security.Cryptography.Xml.SignedXml & related classes ported to AL, to process W3C XmlDigSig (2000-2013) compliant signatures. First wish is signature verification. For only verification we could actually not necessarily load a certificate from BLOB/file/store (that only for signing), but take trusted authority thumbprint + IANA cert. chain policy OID(s) as parameters to check (eventually + some extra parameters). Maybe also some some generic X.509 certificate and signature operations would be nice to have (e.g. certificate and signature verification).

marekjz avatar Nov 25 '17 11:11 marekjz

That's what this library is for. develop the required functionality in a generic way and create a pull request and everyone can benefit from it


Peter Zentner NAV-X, LLC Phone: +1 877.779.6289 Email: [email protected] Website: www.nav-x.com Address: 670 N Beers Street, Bldg 4 - 2nd Floor, Holmdel, NJ 07733 From: MarekJZ [email protected] Sent: Saturday, November 25, 2017 6:00:19 AM To: Microsoft/AL Cc: Peter Zentner; Comment Subject: Re: [Microsoft/AL] .NET cryptography handling (#171)

Hash-suite in Microsoft/AL looks very good 👍 Some would find also very convenient to have System.Security.Cryptography.Xml.SignedXml & related classes ported to AL, to process W3C XmlDigSig (2000-2013) compliant signatures. First wish is signature verification. For only verification we could actually not necessarily load a certificate from BLOB/file/store (that only for signing), but take trusted authority thumbprint + IANA cert. chain policy OID(s) as parameters to check (eventually + some extra parameters). Maybe also some some generic X.509 certificate and signature operations would be nice to have (e.g. certificate and signature verification).

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/Microsoft/AL/issues/171#issuecomment-346933565, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AdEY0vU2HQEhRWRt2eRwmYuoZakHqKBvks5s5_NDgaJpZM4NIk_6.

pzentner avatar Nov 25 '17 14:11 pzentner

@StanislawStempin We currently have the following 2 functions that work for certificate loading from BLOB (via Stream) and XML Digital Signature verification. XML signature verification is used against confidential and often heavy or numerous documents, so it would be really great to have that opportunity to do it internally (without need to use web service integration - i.e. sending that XML out of NAV).

PROCEDURE LoadX509CertFromStream@1101107016(CertStream@1101107000 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.IO.Stream";VAR X509Cert2@1101107001 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.X509Certificates.X509Certificate2" SUPPRESSDISPOSE);
VAR
  MemStream@1101107002 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.IO.MemoryStream";
  X509CertStoreFlags@1101107003 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.X509Certificates.X509KeyStorageFlags";
BEGIN
  IF CertStream.Length = 0 THEN
    ERROR('Missing cert content');

  // Copying stream:
  MemStream := MemStream.MemoryStream();
  CertStream.Position := 0;
  CertStream.CopyTo(MemStream);

  // Loading cert:
  X509CertStoreFlags := X509CertStoreFlags.DefaultKeySet;
  X509Cert2 := X509Cert2.X509Certificate2();
  X509Cert2.Import(MemStream.ToArray(), '', X509CertStoreFlags);
END;

PROCEDURE VerifyXmlDigSig@1101107014(XmlDigSigStream@1101107000 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.IO.Stream";X509Cert2@1101107004 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.X509Certificates.X509Certificate2";AuthorityCertThumbprint@1101107008 : Text[100];CertChainPolicyOid@1101107014 : Text[1024]) IsValidSignature : Boolean;
VAR
  Oid@1101107015 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.Oid";
  X509Chain@1101107003 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.X509Certificates.X509Chain";
  X509ChainElement@1101107009 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.X509Certificates.X509ChainElement";
  X509VerificationFlags@1101107011 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.X509Certificates.X509VerificationFlags";
  X509RevocationMode@1101107013 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.X509Certificates.X509RevocationMode";
  X509RevocationFlag@1101107010 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Security.Cryptography.X509Certificates.X509RevocationFlag";
  UrlRetrievalTimeoutDuration@1101107016 : Duration;
  IsChainValid@1101107012 : Boolean;
  XmlDocument@1101107002 : DotNet "'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Xml.XmlDocument";
  XmlNodeList@1101107006 : DotNet "'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Xml.XmlNodeList";
  XmlElement@1101107005 : DotNet "'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Xml.XmlElement";
  SignedXml@1101107001 : DotNet "'System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.System.Security.Cryptography.Xml.SignedXml";
BEGIN
  IF XmlDigSigStream.Length = 0 THEN
    ERROR('Missing signature content');
  IF ISNULL(X509Cert2) THEN
    ERROR('Missing certificate');

  X509Chain := X509Chain.X509Chain();

  // Perform only basic check here:
  X509RevocationMode := X509RevocationMode.Online; // (or Offline/NoCheck) TODO: Make configurable
  X509RevocationFlag := X509RevocationFlag.EntireChain;  // (or ExcludeRoot) TODO: Make configurable
  X509VerificationFlags := X509VerificationFlags.NoFlag; // TODO: Make configurable

  X509Chain.ChainPolicy.RevocationMode := X509RevocationMode;
  X509Chain.ChainPolicy.RevocationFlag := X509RevocationFlag;
  X509Chain.ChainPolicy.VerificationFlags := X509VerificationFlags;

  // Policy OID:
  IF CertChainPolicyOid <> '' THEN BEGIN
    Oid := Oid.Oid(CertChainPolicyOid);
    X509Chain.ChainPolicy.CertificatePolicy.Add(Oid);
  END;
  X509Chain.ChainPolicy.VerificationTime := CURRENTDATETIME;
  UrlRetrievalTimeoutDuration := 30000; // TODO: Make configurable
  X509Chain.ChainPolicy.UrlRetrievalTimeout := UrlRetrievalTimeoutDuration;

  // Building chain:
  IsChainValid := X509Chain.Build(X509Cert2);
  IF NOT IsChainValid THEN
    EXIT(FALSE);

  // Authority requirement:
  IF AuthorityCertThumbprint <> '' THEN BEGIN
    // Searching the cert chain to find element with AuthorityCertThumbprint:
    IsChainValid := FALSE;
    FOREACH X509ChainElement IN X509Chain.ChainElements DO BEGIN
      IF X509ChainElement.Certificate.Thumbprint = AuthorityCertThumbprint THEN BEGIN
        IsChainValid := TRUE;
        BREAK;
      END;
    END;
    IF NOT IsChainValid THEN
      EXIT(FALSE);
  END;

  // Loading XML doc:
  XmlDocument := XmlDocument.XmlDocument();
  XmlDocument.PreserveWhitespace := TRUE;
  XmlDocument.Load(XmlDigSigStream);

  // Loading SignedXml:
  SignedXml := SignedXml.SignedXml(XmlDocument);
  XmlNodeList := XmlDocument.GetElementsByTagName('Signature');
  XmlElement := XmlNodeList.Item(0);
  SignedXml.LoadXml(XmlElement);

  // Verifying only XML signature
  // (chain already checked before):
  EXIT(SignedXml.CheckSignature(X509Cert2, TRUE));
END;

There can be also a situation when signature verification is done against custom/internal root CA, with certificate installed in Windows store. Then we may also need to be able to install custom certificate in the NAV running environment, or specify it explicitly (i.e. pass the root CA certificate's stream as extra parameter). Verification against single certificate (just SignedXml.CheckSignature(X509Cert2, TRUE)) would also be useful.

marekjz avatar Nov 28 '17 21:11 marekjz

This is a fairly old suggestion, and these should be tracked in https://aka.ms/bcideas, and not on the AL GitHub, which is for bugs in AL language and VC Code VSIX only.

In general, for cryptography requests, these should go into the System apps Cryptography Management module. See https://github.com/microsoft/BCApps/tree/main/src/System%20Application/App/Cryptography%20Management

Closing this issue

pborring avatar Dec 05 '23 11:12 pborring