Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make X509CertificateStore support CRLs on Windows #2571

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
4 changes: 4 additions & 0 deletions Docs/Certificates.md
Expand Up @@ -31,6 +31,10 @@ The UA .NET Standard stack supports the following certificate stores:

- The **Trusted Https** store `<root>/trustedHttps` which contains https certificates which are trusted by an application. To establish trust, the same rules apply as explained for the *Trusted* and the *Issuer* store.

### X509Store on Windows
Starting with Version 1.5.xx of the UA .NET Standard Stack the X509Store supports the storage and retrieval of CRLS, if used on the **Windows OS**.
This enables the usage of the X509Store instead of the Directory Store for stores requiring the use of crls, e.g. the issuer or the directory Store.

### Windows .NET applications
By default the self signed certificates are stored in a **X509Store** called **CurrentUser\\UA_MachineDefault**. The certificates can be viewed or deleted with the Windows Certificate Management Console (certmgr.msc). The *trusted*, *issuer* and *rejected* stores remain in a folder called **OPC Foundation\pki** with a root folder which is specified by the `SpecialFolder` variable **%CommonApplicationData%**. On Windows 7/8/8.1/10 this is usually the invisible folder **C:\ProgramData**.

Expand Down
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -29,6 +29,9 @@ More samples based on the official [Nuget](https://www.nuget.org/packages/OPCFou
* Sessions and Subscriptions.
* A [PubSub](Docs/PubSub.md) library with samples.

#### **New in 1.05.xxx**
* CRL Support for the X509Store on Windows

#### **New in 1.05.373**
* 1.05 Nodeset
* Support for [WellKnownRoles & RoleBasedUserManagement](Docs/RoleBasedUserManagement.md).
Expand Down
1 change: 1 addition & 0 deletions Stack/Opc.Ua.Core/Opc.Ua.Core.csproj
Expand Up @@ -92,6 +92,7 @@
<PropertyGroup>
<ZipTmp>$(BaseIntermediateOutputPath)/zipnodeset2</ZipTmp>
<ZipNodeSet2XML>Schema/Opc.Ua.NodeSet2.xml</ZipNodeSet2XML>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
romanett marked this conversation as resolved.
Show resolved Hide resolved

<Target Name="ZipNodeSet2" BeforeTargets="PrepareForBuild" Inputs="$(ZipNodeSet2XML)" Outputs="$(ZipNodeSet2XML).zip">
Expand Down
@@ -0,0 +1,198 @@
/* ========================================================================
* Copyright (c) 2005-2024 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/

// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------

#pragma warning disable CS1591,CS1573,CS0465,CS0649,CS8019,CS1570,CS1584,CS1658,CS0436,CS8981
using global::System;
using global::System.Diagnostics;
using global::System.Diagnostics.CodeAnalysis;
using global::System.Runtime.CompilerServices;
using global::System.Runtime.InteropServices;
using global::System.Runtime.Versioning;
using winmdroot = global::Windows.Win32;
namespace Windows.Win32
{

/// <content>
/// Contains extern methods from "CRYPT32.dll".
/// </content>
[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Windows.CsWin32", "0.3.49-beta+91f5c15987")]
internal static partial class PInvokeHelper
{
/// <summary>The CertEnumCRLsInStore function retrieves the first or next certificate revocation list (CRL) context in a certificate store. Used in a loop, this function can retrieve in sequence all CRL contexts in a certificate store.</summary>
/// <param name="hCertStore">Handle of a certificate store.</param>
/// <param name="pPrevCrlContext">
/// <para>A pointer to the previous <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/ns-wincrypt-crl_context">CRL_CONTEXT</a> structure found. The <i>pPrevCrlContext</i> parameter must be <b>NULL</b> to get the first CRL in the store. Successive CRLs are enumerated by setting <i>pPrevCrlContext</i> to the pointer returned by a previous call to the function. This function frees the <b>CRL_CONTEXT</b> referenced by non-<b>NULL</b> values of this parameter. The enumeration skips any CRLs previously deleted by <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/nf-wincrypt-certdeletecrlfromstore">CertDeleteCRLFromStore</a>.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certenumcrlsinstore#parameters">Read more on docs.microsoft.com</see>.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is a pointer to the next <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/ns-wincrypt-crl_context">CRL_CONTEXT</a> in the store. <b>NULL</b> is returned if the function fails. For extended error information, call <a href="https://docs.microsoft.com/windows/desktop/api/errhandlingapi/nf-errhandlingapi-getlasterror">GetLastError</a>. Some possible error codes follow. </para>
/// <para>This doc was truncated.</para>
/// </returns>
/// <remarks>
/// <para>The returned pointer is freed when it is passed as the <i>pPrevCrlContext</i> on a subsequent call to the function. Otherwise, the pointer must explicitly be freed by calling <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/nf-wincrypt-certfreecrlcontext">CertFreeCRLContext</a>. A <i>pPrevCrlContext</i> that is not <b>NULL</b> is always freed when passed to this function through a call to <b>CertFreeCRLContext</b>, even if the function itself returns an error. A duplicate of the CRL <a href="https://docs.microsoft.com/windows/desktop/SecGloss/c-gly">context</a> returned by this function can be made by calling <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/nf-wincrypt-certduplicatecrlcontext">CertDuplicateCRLContext</a>.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certenumcrlsinstore#">Read more on docs.microsoft.com</see>.</para>
/// </remarks>
[DllImport("CRYPT32.dll", ExactSpelling = true, SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern unsafe winmdroot.Security.Cryptography.CRL_CONTEXT* CertEnumCRLsInStore(winmdroot.Security.Cryptography.HCERTSTORE hCertStore, [Optional] winmdroot.Security.Cryptography.CRL_CONTEXT* pPrevCrlContext);

/// <summary>Creates a certificate revocation list (CRL) context from an encoded CRL and adds it to the certificate store.</summary>
/// <param name="hCertStore">Handle of a certificate store.</param>
/// <param name="dwCertEncodingType">
/// <para>Specifies the type of encoding used. It is always acceptable to specify both the certificate and <a href="https://docs.microsoft.com/windows/desktop/SecGloss/m-gly">message encoding types</a> by combining them with a bitwise-<b>OR</b> operation as shown in the following example: X509_ASN_ENCODING | PKCS_7_ASN_ENCODING Currently defined encoding types are: </para>
/// <para>This doc was truncated.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certaddencodedcrltostore#parameters">Read more on docs.microsoft.com</see>.</para>
/// </param>
/// <param name="pbCrlEncoded">A pointer to a buffer containing the encoded CRL to be added to the <a href="https://docs.microsoft.com/windows/desktop/SecGloss/c-gly">certificate store</a>.</param>
/// <param name="cbCrlEncoded">The size, in bytes, of the <i>pbCrlEncoded</i> buffer.</param>
/// <param name="dwAddDisposition">
/// <para>Specifies the action to take if a matching CRL or a link to a matching CRL already exists in the store. Currently defined disposition values and their uses are as follows. </para>
/// <para>This doc was truncated.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certaddencodedcrltostore#parameters">Read more on docs.microsoft.com</see>.</para>
/// </param>
/// <param name="ppCrlContext">
/// <para>A pointer to a pointer to the decoded <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/ns-wincrypt-crl_context">CRL_CONTEXT</a> structure. This is an optional parameter that can be <b>NULL</b>, indicating that the calling application does not require a copy of the new or existing CRL. If a copy is made, that context must be freed using <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/nf-wincrypt-certfreecrlcontext">CertFreeCRLContext</a>.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certaddencodedcrltostore#parameters">Read more on docs.microsoft.com</see>.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is <b>TRUE</b>. If the function fails, the return value is <b>FALSE</b>. For extended error information, call <a href="https://docs.microsoft.com/windows/desktop/api/errhandlingapi/nf-errhandlingapi-getlasterror">GetLastError</a>. Some possible error codes follow. </para>
/// <para>This doc was truncated.</para>
/// </returns>
/// <remarks>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certaddencodedcrltostore">Learn more about this API from docs.microsoft.com</see>.</para>
/// </remarks>
[DllImport("CRYPT32.dll", ExactSpelling = true, SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern unsafe winmdroot.Foundation.BOOL CertAddEncodedCRLToStore(winmdroot.Security.Cryptography.HCERTSTORE hCertStore, winmdroot.Security.Cryptography.CERT_QUERY_ENCODING_TYPE dwCertEncodingType, byte* pbCrlEncoded, uint cbCrlEncoded, uint dwAddDisposition, [Optional] winmdroot.Security.Cryptography.CRL_CONTEXT** ppCrlContext);

/// <summary>The CertDeleteCRLFromStore function deletes the specified certificate revocation list (CRL) context from the certificate store.</summary>
/// <param name="pCrlContext">
/// <para>A pointer to the <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/ns-wincrypt-crl_context">CRL_CONTEXT</a> structure to be deleted.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certdeletecrlfromstore#parameters">Read more on docs.microsoft.com</see>.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is <b>TRUE</b>. If the function fails, the return value is <b>FALSE</b>. For extended error information, call <a href="https://docs.microsoft.com/windows/desktop/api/errhandlingapi/nf-errhandlingapi-getlasterror">GetLastError</a>. One possible error code is the following. </para>
/// <para>This doc was truncated.</para>
/// </returns>
/// <remarks>
/// <para>All subsequent get or find operations for the CRL in this store fail. However, memory allocated for the CRL is not freed until all duplicated contexts have also been freed. The <i>pCrlContext</i> parameter is always freed by this function by using <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/nf-wincrypt-certfreecrlcontext">CertFreeCRLContext</a>, even for an error.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certdeletecrlfromstore#">Read more on docs.microsoft.com</see>.</para>
/// </remarks>
[DllImport("CRYPT32.dll", ExactSpelling = true, SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern unsafe winmdroot.Foundation.BOOL CertDeleteCRLFromStore(winmdroot.Security.Cryptography.CRL_CONTEXT* pCrlContext);
}

namespace Security.Cryptography
{
/// <summary>The CRL_CONTEXT structure contains both the encoded and decoded representations of a certificate revocation list (CRL). CRL contexts returned by any CryptoAPI function must be freed by calling the CertFreeCRLContext function.</summary>
/// <remarks>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/ns-wincrypt-crl_context">Learn more about this API from docs.microsoft.com</see>.</para>
/// </remarks>
[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Windows.CsWin32", "0.3.49-beta+91f5c15987")]
internal partial struct CRL_CONTEXT
{
/// <summary>
/// <para>Type of encoding used. It is always acceptable to specify both the certificate and <a href="https://docs.microsoft.com/windows/desktop/SecGloss/m-gly">message encoding types</a> by combining them with a bitwise-<b>OR</b> operation as shown in the following example: X509_ASN_ENCODING | PKCS_7_ASN_ENCODING Currently defined encoding types are: </para>
/// <para>This doc was truncated.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/ns-wincrypt-crl_context#members">Read more on docs.microsoft.com</see>.</para>
/// </summary>
internal winmdroot.Security.Cryptography.CERT_QUERY_ENCODING_TYPE dwCertEncodingType;

/// <summary>A pointer to the encoded CRL information.</summary>
internal unsafe byte* pbCrlEncoded;

/// <summary>The size, in bytes, of the encoded CRL information.</summary>
internal uint cbCrlEncoded;

/// <summary>
/// <para>A pointer to <a href="https://docs.microsoft.com/windows/desktop/api/wincrypt/ns-wincrypt-crl_info">CRL_INFO</a> structure containing the CRL information.</para>
/// <para><see href="https://learn.microsoft.com/windows/win32/api/wincrypt/ns-wincrypt-crl_context#members">Read more on docs.microsoft.com</see>.</para>
/// </summary>
internal unsafe Byte* pCrlInfo;

/// <summary>A handle to the <a href="https://docs.microsoft.com/windows/desktop/SecGloss/c-gly">certificate store</a>.</summary>
internal winmdroot.Security.Cryptography.HCERTSTORE hCertStore;
}



[DebuggerDisplay("{Value}")]
[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Windows.CsWin32", "0.3.49-beta+91f5c15987")]
internal unsafe readonly partial struct HCERTSTORE
{
internal readonly void* Value;

internal HCERTSTORE(void* value) => this.Value = value;

public static implicit operator void*(HCERTSTORE value) => value.Value;

Check warning on line 163 in Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs

View check run for this annotation

Codecov / codecov/patch

Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs#L163

Added line #L163 was not covered by tests

public static explicit operator HCERTSTORE(void* value) => new HCERTSTORE(value);

}

[Flags]
[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Windows.CsWin32", "0.3.49-beta+91f5c15987")]
internal enum CERT_QUERY_ENCODING_TYPE : uint
{
X509_ASN_ENCODING = 0x00000001,
PKCS_7_ASN_ENCODING = 0x00010000,
}
}

namespace Foundation
{
[DebuggerDisplay("{Value}")]
[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Windows.CsWin32", "0.3.49-beta+91f5c15987")]
internal readonly partial struct BOOL
{
internal readonly int Value;

internal BOOL(int value) => this.Value = value;

Check warning on line 186 in Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs

View check run for this annotation

Codecov / codecov/patch

Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs#L186

Added line #L186 was not covered by tests

public static implicit operator int(BOOL value) => value.Value;

Check warning on line 188 in Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs

View check run for this annotation

Codecov / codecov/patch

Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs#L188

Added line #L188 was not covered by tests

public static explicit operator BOOL(int value) => new BOOL(value);
internal BOOL(bool value) => this.Value = value ? 1 : 0;

Check warning on line 191 in Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs

View check run for this annotation

Codecov / codecov/patch

Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs#L190-L191

Added lines #L190 - L191 were not covered by tests

public static implicit operator bool(BOOL value) => value.Value != 0;

public static implicit operator BOOL(bool value) => new BOOL(value);

Check warning on line 195 in Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs

View check run for this annotation

Codecov / codecov/patch

Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore/Extensions/Internal/PInvokeHelper.cs#L195

Added line #L195 was not covered by tests
}
}
}