Skip to content

Commit

Permalink
Finding and removing cached CRLs and Intermediates on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeShook committed Oct 3, 2024
1 parent 787108d commit 01fa494
Show file tree
Hide file tree
Showing 28 changed files with 1,335 additions and 249 deletions.
84 changes: 76 additions & 8 deletions Client/Services/Infrastructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@
// */
#endregion

using System.IO.Compression;
using System.Net.Http.Json;
using System.Security.Cryptography.X509Certificates;
using BlazorMonaco;
using Org.BouncyCastle.X509;
using UdapEd.Shared.Model;
using UdapEd.Shared.Services;
using static Google.Apis.Requests.BatchRequest;

namespace UdapEd.Client.Services;

public class Infrastructure : IInfrastructure
{
private HttpClient _httpClient;
public Infrastructure(HttpClient httpClient)
private readonly ILogger<Infrastructure> _logger;

public Infrastructure(HttpClient httpClient, ILogger<Infrastructure> logger)
{
_httpClient = httpClient;
_logger = logger;
}

public async Task<string> GetMyIp()
Expand Down Expand Up @@ -74,7 +72,7 @@ public Task<byte[]> JitFhirlabsCommunityCertificate(List<string> subjAltNames, s
}
catch (Exception ex)
{
//_logger.LogError(ex, "Failed GetCertificateData from list");
_logger.LogError(ex, "Failed GetCertificateData from list");
return null;
}
}
Expand All @@ -89,8 +87,78 @@ public Task<byte[]> JitFhirlabsCommunityCertificate(List<string> subjAltNames, s
}
catch (Exception ex)
{
//_logger.LogError(ex, "Failed GetCertificateData from list");
_logger.LogError(ex, "Failed GetCertificateData from list");
return null;
}
}

public async Task<X509CacheSettings?> GetX509StoreCache(string thumbprint)
{
try
{
var response = await _httpClient.GetAsync($"Infrastructure/GetX509StoreCache?thumbprint={thumbprint}");

return await response.Content.ReadFromJsonAsync<X509CacheSettings>();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get X509 store cache");
return null;
}
}
public async Task<CrlFileCacheSettings?> GetCryptNetUrlCache(string location)
{
try
{
_logger.LogDebug($"Calling GetCryptNetUrlCache");
var response = await _httpClient.GetAsync($"Infrastructure/GetCryptNetUrlCache?crlUrl={location}");

return await response.Content.ReadFromJsonAsync<CrlFileCacheSettings>();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get file cache");
return null;
}
}

public async Task RemoveFromX509Store(X509CacheSettings? settings)
{
if (settings == null)
{
throw new ArgumentNullException(nameof(settings));
}

try
{
var response = await _httpClient.PostAsJsonAsync("Infrastructure/RemoveFromX509Store", settings);

response.EnsureSuccessStatusCode();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to remove from X509 store");
throw;
}
}

public async Task RemoveFromFileCache(CrlFileCacheSettings? settings)
{
if (settings == null)
{
throw new ArgumentNullException(nameof(settings));
}

try
{
var response = await _httpClient.PostAsJsonAsync("Infrastructure/RemoveFromFileCache", settings);

response.EnsureSuccessStatusCode();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to remove from file cache");
throw;
}
}
}
129 changes: 117 additions & 12 deletions Server/Controllers/InfrastructureController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,43 +20,148 @@ namespace UdapEd.Server.Controllers;
public class InfrastructureController : Controller
{
private readonly IInfrastructure _infrastructure;
private readonly ILogger<InfrastructureController> _logger;

public InfrastructureController(IInfrastructure infrastructure)
public InfrastructureController(IInfrastructure infrastructure, ILogger<InfrastructureController> logger)
{
_infrastructure = infrastructure;
_logger = logger;
}

[HttpGet("BuildMyTestCertificatePackage")]
public async Task<IActionResult> BuildMyTestCertificatePackage(List<string> subjAltNames, CancellationToken token)
{
var zip = await _infrastructure.BuildMyTestCertificatePackage(subjAltNames);
var base64String = Convert.ToBase64String(zip);
try
{
var zip = await _infrastructure.BuildMyTestCertificatePackage(subjAltNames);
var base64String = Convert.ToBase64String(zip);

return Ok(base64String);
return Ok(base64String);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to build test certificate package");
return StatusCode(500, "Internal server error");
}
}

[HttpGet("JitFhirlabsCommunityCertificate")]
public async Task<IActionResult> JitFhirlabsCommunityCertificate(List<string> subjAltNames, string password, CancellationToken token)
{
var clientCertBytes = await _infrastructure.JitFhirlabsCommunityCertificate(subjAltNames, password);
var base64String = Convert.ToBase64String(clientCertBytes);
try
{
var clientCertBytes = await _infrastructure.JitFhirlabsCommunityCertificate(subjAltNames, password);
var base64String = Convert.ToBase64String(clientCertBytes);

return Ok(base64String);
return Ok(base64String);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get JitFhirlabs community certificate");
return StatusCode(500, "Internal server error");
}
}

[HttpGet("GetX509data")]
public async Task<IActionResult> GetX509data(string url, CancellationToken token)
{
var viewModel = await _infrastructure.GetX509data(url);

return Ok(viewModel);
try
{
var viewModel = await _infrastructure.GetX509data(url);
return Ok(viewModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get X509 data");
return StatusCode(500, "Internal server error");
}
}

[HttpGet("GetCrldata")]
public async Task<IActionResult> GetCrldata(string url, CancellationToken token)
{
var viewModel = await _infrastructure.GetCrldata(url);
try
{
var viewModel = await _infrastructure.GetCrldata(url);
return Ok(viewModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get CRL data");
return StatusCode(500, "Internal server error");
}
}

[HttpGet("GetX509StoreCache")]
public async Task<ActionResult<X509CacheSettings?>> GetX509StoreCache([FromQuery] string thumbprint)
{
try
{
var result = await _infrastructure.GetX509StoreCache(thumbprint);

return Ok(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get X509 store cache");
return StatusCode(500, "Internal server error");
}
}

[HttpPost("RemoveFromX509Store")]
public async Task<IActionResult> RemoveFromX509Store([FromBody] X509CacheSettings? settings)
{
if (settings == null)
{
return BadRequest("Settings cannot be null");
}

try
{
await _infrastructure.RemoveFromX509Store(settings);
return NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to remove from X509 store");
return StatusCode(500, "Internal server error");
}
}

[HttpGet("GetCryptNetUrlCache")]
public async Task<ActionResult<X509CacheSettings?>> GetCryptNetUrlCache([FromQuery] string crlUrl)
{
try
{
var result = await _infrastructure.GetCryptNetUrlCache(crlUrl);

return Ok(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get X509 store cache");
return StatusCode(500, "Internal server error");
}
}


[HttpPost("RemoveFromFileCache")]
public async Task<IActionResult> RemoveFromFileCache([FromBody] CrlFileCacheSettings? settings)
{
if (settings == null)
{
return BadRequest("Settings cannot be null");
}

return Ok(viewModel);
try
{
await _infrastructure.RemoveFromFileCache(settings);
return NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to remove from X509 store");
return StatusCode(500, "Internal server error");
}
}
}
4 changes: 3 additions & 1 deletion Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

// Add services to the container.
builder.Host.UseSerilog((ctx, lc) => lc
.MinimumLevel.Information()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information)
Expand All @@ -49,6 +49,8 @@
// Mount Cloud Secrets
builder.Configuration.AddJsonFile("/secret/udapEdAppsettings", true, false);

builder.Services.AddSingleton<CrlCacheService>();

builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(60);
Expand Down
39 changes: 25 additions & 14 deletions Shared/Components/CertificatePKIViewer.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@
<CertificateViewer Class="mt-2"
Title="@Title"
JwtHeader="@JwtHeaderWithx5c"
EncodeCertificate="@EncodeCertificate"

IntermediateResolved = "(x509Encoded) => {
IntermediateCertificate = x509Encoded;
}"

CrlResolved = "(x509Encoded) => {
CRL = x509Encoded;
}"
/>


@if (CRL != null)
EncodeCertificate="@EncodeCertificate"
IntermediateResolvedEvent = "(x509Encoded) => { IntermediateCertificate = x509Encoded; }"
CrlResolvedEvent="(crlDescription) => { Crl = crlDescription; }"
CrlCachedEvent="(crlFileCacheSettings) => { CrlUrlCache = crlFileCacheSettings; StateHasChanged();}"
/>

@if (Crl != null)
{
<MudExpansionPanels Class="mt-2">
<MudExpansionPanel Expanded="true" Style="background-color: #EDE7F6">
Expand All @@ -25,7 +19,24 @@
<ChildContent>
<MudCard Class="mt-4">
<MudCardContent>
<pre>@CRL</pre>
@if (CrlUrlCache != null && CrlUrlCache.Cached)
{
<MudGrid>
<MudItem Style="display: flex; align-items: center;">
<MudIcon Icon="@Icons.Material.Filled.Cached" Color="Color.Warning" Size="Size.Small" />
<MudText Class="mr-2" Color="Color.Warning">Cached with Windows CryptnetUrlCache on File System</MudText>
</MudItem>
</MudGrid>

<MudButton
IconColor="Color.Info"
StartIcon=@Icons.Material.Filled.Remove
Size="Size.Small"
OnClick="@(() => RemoveCrlFromCache(CrlUrlCache))">
<MudText Color="Color.Info">Remove</MudText>
</MudButton>
}
<pre>@Crl</pre>
</MudCardContent>
</MudCard>
</ChildContent>
Expand Down
Loading

0 comments on commit 01fa494

Please sign in to comment.