Azure / Industrial-IoT

Azure Industrial IoT Platform
MIT License
523 stars 214 forks source link

CRL with zero revoked certificates fails to be decoded (OPC Foundation .NET-Standard) #2214

Closed nelsonmorais closed 4 months ago

nelsonmorais commented 5 months ago

Describe the bug When a CA has a CRL without certificates revoked, the CRL fails to be decoded and throws an exception when it attempts to get the list of revoked certificates.

To Reproduce

  1. Create a self-signed CA (Ex: CA.DER + CA.PFX)
  2. Create an empty CRL for the CA (CA.CRL)
  3. Create a Certificate for the OPC Publisher from the CA (OPCPublisher.DER + OPCPublisher.PFX)
  4. Copy the Certificates and the CRL to the OPC Publisher pki directories
  5. Start the OPC Publisher (Ex: Docker run --name opcpublisher mcr.microsoft.com/iotedge/opc-publisher:2.9.6 ...)
  6. Verify that the OPC Publisher fails to decode the CRL with the exception below
 ██████╗ ██████╗  ██████╗    ██████╗ ██╗   ██╗██████╗ ██╗     ██╗███████╗██╗  ██╗███████╗██████╗
██╔═══██╗██╔══██╗██╔════╝    ██╔══██╗██║   ██║██╔══██╗██║     ██║██╔════╝██║  ██║██╔════╝██╔══██╗
██║   ██║██████╔╝██║         ██████╔╝██║   ██║██████╔╝██║     ██║███████╗███████║█████╗  ██████╔╝
██║   ██║██╔═══╝ ██║         ██╔═══╝ ██║   ██║██╔══██╗██║     ██║╚════██║██╔══██║██╔══╝  ██╔══██╗
╚██████╔╝██║     ╚██████╗    ██║     ╚██████╔╝██████╔╝███████╗██║███████║██║  ██║███████╗██║  ██║
 ╚═════╝ ╚═╝      ╚═════╝    ╚═╝      ╚═════╝ ╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝
                                   2.9.6.4+978a207cf9 (.NET 8.0.4/linux-x64/OPC Stack 1.5.374.36)

To connect to Azure IoT Hub you must run as module inside IoT Edge or specify a device connection string using EdgeHubConnectionString environment variable or command line.
[24-04-23 14:15:15.3203] warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. For more information go to https://aka.ms/aspnet/dataprotectionwarning
[24-04-23 14:15:15.3902] info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[62]
      User profile is available. Using '/root/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.
[24-04-23 14:15:16.0046] info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[58]
      Creating key {b0dc7648-c4e5-4485-a2c7-9b35f1f0ea27} with creation date 2024-04-23 14:15:15Z, activation date 2024-04-23 14:15:15Z, and expiration date 2024-07-22 14:15:15Z.
[24-04-23 14:15:16.1784] warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {b0dc7648-c4e5-4485-a2c7-9b35f1f0ea27} may be persisted to storage in unencrypted form.
[24-04-23 14:15:16.3126] info: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[39]
      Writing data to file '/root/.aspnet/DataProtection-Keys/key-b0dc7648-c4e5-4485-a2c7-9b35f1f0ea27.xml'.
[24-04-23 14:15:17.9230] warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Overriding address(es) 'http://*:8080'. Binding to endpoints defined via IConfiguration and/or UseKestrel() instead.
[24-04-23 14:15:18.0441] info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://[::]:80
[24-04-23 14:15:18.0443] info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://0.0.0.0:443
[24-04-23 14:15:18.3425] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[512]
      Imported the PFX private key for [713ED123DAD23099D530E54F24C7A8C1E55CCF7F].
[24-04-23 14:15:18.3679] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      Own certificate Subject 'CN=OPCPublisher, C=US, S=State, L=City, OU=IS-IE-PSE-MMS, O=Company' (Thumbprint: 713ED123DAD23099D530E54F24C7A8C1E55CCF7F) loaded.
[24-04-23 14:15:18.3723] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[0]
      Checking application instance certificate.
[24-04-23 14:15:18.4615] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[512]
      Imported the PFX private key for [713ED123DAD23099D530E54F24C7A8C1E55CCF7F].
[24-04-23 14:15:18.4729] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[0]
      Check certificate: [CN=OPCPublisher, C=US, S=State, L=City, OU=IS-IE-PSE-MMS, O=Company] [713ED123DAD23099D530E54F24C7A8C1E55CCF7F]
[24-04-23 14:15:18.4809] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[0]
      Check application instance certificate. [CN=OPCPublisher, C=US, S=State, L=City, OU=IS-IE-PSE-MMS, O=Company] [713ED123DAD23099D530E54F24C7A8C1E55CCF7F]
[24-04-23 14:15:18.9367] warn: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[0]
      Application Certificate Validation suppressed BadCertificateRevocationUnknown
[24-04-23 14:15:18.9371] warn: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[0]
      Validation errors suppressed:  [CN=OPCPublisher, C=US, S=State, L=City, OU=IS-IE-PSE-MMS, O=Company] [713ED123DAD23099D530E54F24C7A8C1E55CCF7F]
[24-04-23 14:15:18.9414] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[0]
      Updated the ApplicationUri: urn:76f5:f3be:7f85:b215:a1f7:ee6b:941d:96ba:OPCPublisher:microsoft: --> urn:2fe5:32b8:155d:157d:7ceb:76bb:a830:1d20:OPCPublisher:microsoft:
[24-04-23 14:15:18.9416] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaStack[0]
      Using the ApplicationUri: urn:2fe5:32b8:155d:157d:7ceb:76bb:a830:1d20:OPCPublisher:microsoft:
[24-04-23 14:15:18.9790] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      Application own certificate store contains 1 certs.
[24-04-23 14:15:18.9802] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      01: Subject 'CN=OPCPublisher, C=US, S=State, L=City, OU=IS-IE-PSE-MMS, O=Company' (Thumbprint: 713ED123DAD23099D530E54F24C7A8C1E55CCF7F)
[24-04-23 14:15:19.0255] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      Trusted issuer store contains 1 certs.
[24-04-23 14:15:19.0257] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      01: Subject 'DC=ABCDEFG, C=US, S=State, L=City, OU=IS-IE-PSE-MMS, O=Company, CN=Company Root CA TEST CERTIFICATE' (Thumbprint: 48DAAF298B252104906C52FE5D02C22D2116ED5C)
[24-04-23 14:15:19.0527] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      Trusted issuer store has 1 CRLs.
[24-04-23 14:15:19.0742] fail: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      Error while trying to read information from trusted issuer store.
      System.Security.Cryptography.CryptographicException: Failed to decode the CRL.
       ---> System.Formats.Asn1.AsnContentException: The provided data does not represent a valid tag.
         at System.Formats.Asn1.Asn1Tag.Decode(ReadOUSySpan`1 source, Int32& bytesConsumed)
         at System.Formats.Asn1.AsnReader.PeekTag()
         at Opc.Ua.Security.Certificates.X509CRL.DecodeCrl(Byte[] tbs)
         --- End of inner exception stack trace ---
         at Opc.Ua.Security.Certificates.X509CRL.DecodeCrl(Byte[] tbs)
         at Opc.Ua.Security.Certificates.X509CRL.Decode(Byte[] crl)
         at Opc.Ua.Security.Certificates.X509CRL.EnsureDecoded()
         at Opc.Ua.Security.Certificates.X509CRL.get_IssuerName()
         at Opc.Ua.Security.Certificates.X509CRL.get_Issuer()
[24-04-23 14:15:19.2368] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      Trusted peer store contains 1 certs.
[24-04-23 14:15:19.2370] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      01: Subject 'DC=ABCDEFG, C=US, S=State, L=City, OU=IS-IE-PSE-MMS, O=Company, CN=Company Root CA TEST CERTIFICATE' (Thumbprint: 48DAAF298B252104906C52FE5D02C22D2116ED5C)
[24-04-23 14:15:19.2455] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      Trusted peer store has 0 CRLs.
[24-04-23 14:15:19.2514] info: Azure.IIoT.OpcUa.Publisher.Stack.Services.OpcUaApplication[0]
      Rejected certificate store contains 0 certs.

Expected behavior When a CA has a CRL without revoked certificates, the CRL should still be decoded properly.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Additional context The issue is on the OPC Foundation .NET-Standard stack at this location: https://github.com/OPCFoundation/UA-.NETStandard/blob/6bdd741dc0869ab463974e181b82b84b16222234/Libraries/Opc.Ua.Security.Certificates/X509Crl/X509Crl.cs#L271

Possible fix:

Other info: A similar issue was opened on the OPC Foundation .NET Standard repository for cross reference at: https://github.com/OPCFoundation/UA-.NETStandard/issues/2595

mregen commented 5 months ago

Hi @nelsonmorais, I can repro the issue when neither revoked nor CRL extensions are encoded. As a workaround you can add a CRL extension or revoke a cert. Otherwise fix is available in the next release.