Skip to content

Instantly share code, notes, and snippets.

@MysteryDash
Created March 7, 2019 10:43
Show Gist options
  • Save MysteryDash/f26f4abb2915557720e8ef3535634e9d to your computer and use it in GitHub Desktop.
Save MysteryDash/f26f4abb2915557720e8ef3535634e9d to your computer and use it in GitHub Desktop.
Install root certificates for the current user without confirmation
//
// This file is licensed under the terms of the Simple Non Code License (SNCL) 2.3.0.
// The full license text can be found in the file named License.txt.
// Written originally by Alexandre Quoniou in 2019.
//
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
namespace Dash.Win32
{
public static class CertificateStore
{
// ReSharper disable once InconsistentNaming
private const int BM_CLICK = 0x00F5;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
/// <summary>
/// Installs a certificate (in CurrentUser's Root store) and bypasses the confirmation window.
/// </summary>
/// <param name="certificate"></param>
/// <param name="token"></param>
/// <returns></returns>
public static Task<bool> InstallAsync(X509Certificate2 certificate, CancellationToken token = default)
{
var installationTask = Task.Run(() =>
{
using (var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
}
}, token);
var validationTask = Task.Run(async () =>
{
var success = ConfirmSecurityWindow(installationTask, token);
await installationTask;
return success;
}, token);
return validationTask;
}
/// <summary>
/// Removes a certificate (in CurrentUser's Root store) and bypasses the confirmation window.
/// </summary>
/// <param name="certificate"></param>
/// <param name="token"></param>
/// <returns></returns>
public static Task<bool> UninstallAsync(X509Certificate2 certificate, CancellationToken token = default)
{
var deletionTask = Task.Run(() =>
{
using (var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadWrite);
store.Remove(certificate);
}
}, token);
var validationTask = Task.Run(async () =>
{
var success = ConfirmSecurityWindow(deletionTask, token);
await deletionTask;
return success;
}, token);
return validationTask;
}
private static bool ConfirmSecurityWindow(Task securityWindowTask, CancellationToken token = default)
{
while (!securityWindowTask.IsFaulted &&
!securityWindowTask.IsCanceled &&
!securityWindowTask.IsCompleted)
{
token.ThrowIfCancellationRequested();
foreach (var process in Process.GetProcessesByName("csrss").Where(p => p.MainWindowHandle != IntPtr.Zero))
{
var windowHandle = process.MainWindowHandle;
var buttonHandle = FindWindowEx(windowHandle, IntPtr.Zero, "Button", null);
return PostMessage(buttonHandle, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
}
}
return false;
}
}
}
@MysteryDash
Copy link
Author

Simple Non Code License (SNCL)

Version 2.3.0
Copyright © 2016-2019 Alexandre Quoniou

The original creator(s) of the data or text under this license is thereby called the licensor.
The physical or juridical person obtaining a copy of the data or text under this license is thereby called the licensee.
The data, source code or text under this license is therefore called the object.

  1. The licensee's rights and obligations

    1.1. The licensee has the right to obtain a free copy of the object.
    1.2. It is the right of the licensee to redistribute unaltered copies of the object although commercial use is utterly forbidden (except with the original licensor's express written consent).
    1.3. The licensee is given the right to adapt or modify the object to suit their needs and to redistribute the modified version subject to the following conditions:

     1.3.1. You must add the following notice in any copy of the object that you may create: Originally written by {Licensor} in {Year of Creation}.
     1.3.2. You must not remove the license information (e.g., a header in source code) present in the object.
     1.3.3. The modified version of the object is subjected to the clauses 1.1 and 1.2 of this license.
     1.3.3. You must include the following notice in any object-modified copies you redistribute: This document or data is a derivative of {Name of the object} and the information contained here may or may not represent the original document or data.
     1.3.4. You must include this license along with any object-modified copies you redistribute.
     1.3.5. In case of juridical issues that may arise from licensee edits the licensee is liable instead of the licensor.
    
  2. Liability of the licensor and of the licensee

    2.1. The licensor offers the object as-is and as-available, and makes no representations or warranties of any kind concerning the object. Thus, the licensor is not liable for any use made of the object.
    2.2. The licensee only is liable for any juridical issue related to the use of the object, edited by third parties or not.

  3. Termination

    3.1. All of the clauses stated in section 1 are void if the licensee fails to accomplish their obligations established in section 1.
    3.2. If the clause 3.1 becomes true the licensee must pay for any costs the licensor may have with juridical actions against him.

  4. Other terms and conditions

    4.1. The licensor shall not be bound by any additional or different terms or conditions communicated by the licensee unless expressly agreed.
    4.2. The licensor has the right to edit at any time the content of this license, however, its effects will not be retroactive.
    4.3. Any modification made by the licensor shall not affect the already published versions of the object, only the future ones.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment