0

I have a code which runs under IIS as a web service. So, on message receipt, I load certificate from database, check it(to make sure cert is valid and with a private key) and call following function. Obviously all of that works using test cases, but doesn't work under IIS in production. I was able to find some information online which point to the fact that IIS runs under NETWORK credentials and doesn't have permissions needed.

But error message is misleading and there is no files involved in this process.

Getting cert and checking it's good:

    this.ServerCertificate = new X509Certificate2(options.As2ServerCertificate);
    if (!this.ServerCertificate.HasPrivateKey || this.ServerCertificate.NotAfter < DateTime.Now.Date)
    {                    
        return false;
    }

When calling this function:

    public static byte[] Decrypt(byte[] encodedEncryptedMessage, X509Certificate2 certificate)
    {
        var envelopedCms = new EnvelopedCms();
        envelopedCms.Decode(encodedEncryptedMessage);
        envelopedCms.Decrypt(new X509Certificate2Collection(certificate));
        return envelopedCms.Encode();
    }

In production we receive following error:

The system cannot find the file specified.

System.Security at System.Security.Cryptography.Pkcs.EnvelopedCms.DecryptContent(RecipientInfoCollection recipientInfos, X509Certificate2Collection extraStore) at Edi.CommunicationProtocols.AS2.Cryptography.Decrypt(Byte[] encodedEncryptedMessage, X509Certificate2 certificate) in ClientServerCode\trunk\Edi\CommunicationProtocols\AS2\Cryptography.cs:line 44 at Edi.CommunicationProtocols.AS2.As2Server.ReceiveMessage(List`1 headers, Byte[] content) in Edi\CommunicationProtocols\AS2\As2Server.cs:line 41 at Web.Services.Rest.AS2ListenerService.ProcessMessage(String accountId, Stream data) in ClientServerCode\trunk\Web.Services\Rest\AS2ListenerService.cs:line 91

So, it looks like framework trying to read something off the disk even though all data (certificate) provided by code. How do I work around this?

katit
  • 17,375
  • 35
  • 128
  • 256

2 Answers2

1

Faced same issue and switched to bouncy castle:

public static byte[] Decrypt(byte[] data, byte[] certbytes, string password)
    {
        Pkcs12Store pkcs12 = new Pkcs12Store(new MemoryStream(certbytes), password.ToArray());

        string keyAlias = pkcs12.Aliases.Cast<string>().First(x => pkcs12.IsKeyEntry(x));

        AsymmetricKeyParameter key = pkcs12.GetKey(keyAlias).Key;
        Org.BouncyCastle.X509.X509Certificate cert = pkcs12.GetCertificate(keyAlias).Certificate;

        var envelopedData = new CmsEnvelopedData(data);
        var recepientInfos = envelopedData.GetRecipientInfos();

        var recepientId = new RecipientID()
        {
            Issuer = cert.IssuerDN,
            SerialNumber = cert.SerialNumber
        };
        var recepient = recepientInfos[recepientId];
        return recepient.GetContent(key);
    }

As you are doing As2 and dealing with multipart content, just use Mimekit and you'll end up with something like:

 public static MimeEntity Decrypt(ApplicationPkcs7Mime data, byte[] certbytes, string password)
    {
        using (var ctx = (SecureMimeContext)CryptographyContext.Create("application/pkcs7-mime"))
        {
            ctx.Import(new MemoryStream(certbytes), password);
            return data.Decrypt(ctx);
        }
    }

As a side note, on Azure you don't have this issue

bgman
  • 309
  • 1
  • 5
  • Thanks! Also I solved issue, I have follow up question on MimeKit. I want to stay independent from other libs, we implemented all MIME stuff. All pretty much works, but I hit a snag with compressed AS2 messages. Does MimeKit handle it automatically? (compressed-data) – katit Aug 23 '22 at 20:23
  • Didn't handle compressing/decompresing, but there must be a way . I see ApplicationPkcs7Mime has Decompress method. – bgman Aug 24 '22 at 06:39
0

So, what happens here, is that even though I do pass certificate to my method call, framework still tries to lookup other certificates from user profile and fails.

Solution to this problem (also not ideal) is to do following: CryptographicException was unhandled: System cannot find the specified file

After setting "Load user profile: true" all is working

katit
  • 17,375
  • 35
  • 128
  • 256