diff --git a/Server/Controllers/AccessController.cs b/Server/Controllers/AccessController.cs index d02ca14..d6fd5c5 100644 --- a/Server/Controllers/AccessController.cs +++ b/Server/Controllers/AccessController.cs @@ -92,8 +92,8 @@ public Task RequestAccessTokenAuthCode( } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); - + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var tokenRequestBuilder = AccessTokenRequestForAuthorizationCodeBuilder.Create( tokenRequestModel.ClientId, tokenRequestModel.TokenEndpointUrl, @@ -124,7 +124,7 @@ public Task RequestAccessTokenClientCredentials( } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var tokenRequestBuilder = AccessTokenRequestForClientCredentialsBuilder.Create( tokenRequestModel.ClientId, diff --git a/Server/Controllers/CertificationsController.cs b/Server/Controllers/CertificationsController.cs index 5411246..07aa93c 100644 --- a/Server/Controllers/CertificationsController.cs +++ b/Server/Controllers/CertificationsController.cs @@ -53,7 +53,7 @@ public IActionResult LoadTestCertificate([FromBody] string testClientCert) try { - var certificate = new X509Certificate2(testClientCert, "udap-test", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12FromFile(testClientCert, "udap-test", X509KeyStorageFlags.Exportable); var subjectName = certificate.SubjectName.Name; var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); @@ -114,7 +114,7 @@ public IActionResult ValidateCertificate([FromBody] string password) var certBytes = Convert.FromBase64String(clientCertSession); try { - var certificate = new X509Certificate2(certBytes, password, X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, password, X509KeyStorageFlags.Exportable); var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); HttpContext.Session.SetString(UdapEdConstants.CERTIFICATION_CERTIFICATE_WITH_KEY, Convert.ToBase64String(clientCertWithKeyBytes)); result.DistinguishedName = certificate.SubjectName.Name; @@ -185,7 +185,7 @@ public IActionResult IsClientCertificateLoaded() if (certBytesWithKey != null) { var certBytes = Convert.FromBase64String(certBytesWithKey); - var certificate = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -230,7 +230,7 @@ public IActionResult BuildSoftwareStatementWithHeaderForClientCredentials( } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var certificationBuilder = UdapCertificationsAndEndorsementBuilder.Create(request.CertificationName, clientCert); @@ -289,7 +289,7 @@ public IActionResult BuildRequestBodyForClientCredentials( } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var document = JsonSerializer .Deserialize(request.SoftwareStatement)!; diff --git a/Server/Controllers/MetadataController.cs b/Server/Controllers/MetadataController.cs index e4b8942..ad6aeed 100644 --- a/Server/Controllers/MetadataController.cs +++ b/Server/Controllers/MetadataController.cs @@ -24,6 +24,7 @@ using Udap.Util.Extensions; using UdapEd.Server.Extensions; using UdapEd.Shared; +using UdapEd.Shared.Extensions; using UdapEd.Shared.Model; using UdapEd.Shared.Model.Discovery; @@ -57,7 +58,7 @@ public async Task Get([FromQuery] string metadataUrl, [FromQuery] var result = new MetadataVerificationModel(); var certBytes = Convert.FromBase64String(anchorString); - var anchorCert = new X509Certificate2(certBytes); + var anchorCert = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); var trustAnchorStore = new TrustAnchorMemoryStore() { AnchorCertificates = new HashSet @@ -178,7 +179,7 @@ public IActionResult UploadAnchorCertificate([FromBody] string base64String) try { var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -207,7 +208,7 @@ public async Task LoadUdapOrgAnchor([FromBody] string anchorCerti var response = await _httpClient.GetAsync(new Uri(anchorCertificate)); response.EnsureSuccessStatusCode(); var certBytes = await response.Content.ReadAsByteArrayAsync(); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -241,7 +242,7 @@ public IActionResult IsAnchorCertificateLoaded() if (base64String != null) { var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -318,7 +319,7 @@ public async Task GetFhirLabsCommunityList() public IActionResult BuildCertificateDisplay([FromBody] List certificates) { var certBytes = Convert.FromBase64String(certificates.First()); - var cert = new X509Certificate2(certBytes); + var cert = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); var result = new CertificateDisplayBuilder(cert).BuildCertificateDisplayData(); return Ok(result); @@ -328,7 +329,7 @@ public IActionResult BuildCertificateDisplay([FromBody] List certificate public IActionResult BuildCertificateDisplay([FromBody] string certificate) { var certBytes = Convert.FromBase64String(certificate); - var cert = new X509Certificate2(certBytes); + var cert = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); var result = new CertificateDisplayBuilder(cert).BuildCertificateDisplayData(); return Ok(result); diff --git a/Server/Controllers/MutualTlsController.cs b/Server/Controllers/MutualTlsController.cs index 6228ab8..6286d44 100644 --- a/Server/Controllers/MutualTlsController.cs +++ b/Server/Controllers/MutualTlsController.cs @@ -45,7 +45,7 @@ public IActionResult UploadTestClientCertificate([FromBody] string testClientCer try { - var certificate = new X509Certificate2(testClientCert, "udap-test", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12FromFile(testClientCert, "udap-test", X509KeyStorageFlags.Exportable); var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); HttpContext.Session.SetString(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WITH_KEY, Convert.ToBase64String(clientCertWithKeyBytes)); @@ -99,7 +99,7 @@ public IActionResult ValidateCertificate([FromBody] string password) var certBytes = Convert.FromBase64String(clientCertSession); try { - var certificate = new X509Certificate2(certBytes, password, X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, password, X509KeyStorageFlags.Exportable); var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); HttpContext.Session.SetString(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WITH_KEY, @@ -157,7 +157,7 @@ public IActionResult IsClientCertificateLoaded() if (certBytesWithKey != null) { var certBytes = Convert.FromBase64String(certBytesWithKey); - var certificate = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -195,7 +195,7 @@ public IActionResult UploadAnchorCertificate([FromBody] string base64String) try { var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -224,7 +224,7 @@ public async Task LoadUdapOrgAnchor([FromBody] string anchorCerti var response = await _httpClient.GetAsync(new Uri(anchorCertificate)); response.EnsureSuccessStatusCode(); var certBytes = await response.Content.ReadAsByteArrayAsync(); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -258,7 +258,7 @@ public IActionResult IsAnchorCertificateLoaded() if (base64String != null) { var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -284,7 +284,7 @@ public IActionResult IsAnchorCertificateLoaded() public IActionResult VerifyMtlsTrust([FromBody] string publicCertificate) { var clientCertBytes = Convert.FromBase64String(publicCertificate); - var clientCertificate = new X509Certificate2(clientCertBytes); + var clientCertificate = X509CertificateLoader.LoadCertificate(clientCertBytes); var base64String = HttpContext.Session.GetString(UdapEdConstants.MTLS_ANCHOR_CERTIFICATE); @@ -294,7 +294,7 @@ public IActionResult VerifyMtlsTrust([FromBody] string publicCertificate) } var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); var notifications = new List(); _trustChainValidator.Problem += element => notifications.Add($"Validation Problem: {element.ChainElementStatus.Summarize(TrustChainValidator.DefaultProblemFlags)}"); diff --git a/Server/Controllers/RegisterController.cs b/Server/Controllers/RegisterController.cs index dc273fc..2382886 100644 --- a/Server/Controllers/RegisterController.cs +++ b/Server/Controllers/RegisterController.cs @@ -60,11 +60,12 @@ public IActionResult UploadTestClientCertificate([FromBody] string testClientCer try { - certificate = new X509Certificate2(testClientCert, "udap-test", X509KeyStorageFlags.Exportable); + certificate = X509CertificateLoader.LoadPkcs12FromFile(testClientCert, "udap-test", X509KeyStorageFlags.Exportable); } catch { - certificate = new X509Certificate2(testClientCert, _configuration["sampleKeyC"], X509KeyStorageFlags.Exportable); + + certificate = X509CertificateLoader.LoadPkcs12FromFile(testClientCert, _configuration["sampleKeyC"], X509KeyStorageFlags.Exportable); } var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); @@ -122,7 +123,7 @@ public IActionResult ValidateCertificate([FromBody] string password) var certBytes = Convert.FromBase64String(clientCertSession); try { - var certificate = new X509Certificate2(certBytes, password, X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, password, X509KeyStorageFlags.Exportable); var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); HttpContext.Session.SetString(UdapEdConstants.UDAP_CLIENT_CERTIFICATE_WITH_KEY, Convert.ToBase64String(clientCertWithKeyBytes)); @@ -181,7 +182,7 @@ public IActionResult IsClientCertificateLoaded() if (certBytesWithKey != null) { var certBytes = Convert.FromBase64String(certBytesWithKey); - var certificate = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -223,7 +224,7 @@ public IActionResult BuildSoftwareStatementWithHeaderForClientCredentials( } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); UdapDcrBuilderForClientCredentialsUnchecked dcrBuilder; @@ -296,7 +297,7 @@ public IActionResult BuildSoftwareStatementWithHeaderForAuthorizationCode( } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); UdapDcrBuilderForAuthorizationCodeUnchecked dcrBuilder; @@ -371,7 +372,7 @@ public IActionResult BuildRequestBodyForClientCredentials( } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var document = JsonSerializer .Deserialize(request.SoftwareStatement)!; @@ -436,7 +437,7 @@ public IActionResult BuildRequestBodyForAuthorizationCode( } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var document = JsonSerializer .Deserialize(request.SoftwareStatement)!; diff --git a/Server/Program.cs b/Server/Program.cs index 53cc790..2fb16c6 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -234,7 +234,7 @@ } app.UseBlazorFrameworkFiles(); -app.UseStaticFiles(); +app.MapStaticAssets(); app.UseRouting(); app.UseRateLimiter(); //after routing diff --git a/Server/Services/Authentication/ClientCertificateProvider.cs b/Server/Services/Authentication/ClientCertificateProvider.cs index a0accd3..f2fdb5c 100644 --- a/Server/Services/Authentication/ClientCertificateProvider.cs +++ b/Server/Services/Authentication/ClientCertificateProvider.cs @@ -22,7 +22,7 @@ public ClientCertificateProvider(IHttpContextAccessor httpContextAccessor, ILogg if (certBytesWithKey != null) { var certBytes = Convert.FromBase64String(certBytesWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); return clientCert; } @@ -36,7 +36,7 @@ public ClientCertificateProvider(IHttpContextAccessor httpContextAccessor, ILogg if (anchorBytes != null) { var certBytes = Convert.FromBase64String(anchorBytes); - var anchorCerts = new X509Certificate2Collection() { new(certBytes) }; + var anchorCerts = new X509Certificate2Collection(X509CertificateLoader.LoadCertificate(certBytes)); return anchorCerts; } diff --git a/Server/UdapEd - Backup.Server.csproj b/Server/UdapEd - Backup.Server.csproj deleted file mode 100644 index 4f0b48c..0000000 --- a/Server/UdapEd - Backup.Server.csproj +++ /dev/null @@ -1,63 +0,0 @@ - - - - net8.0 - enable - enable - Linux - FhriLabs.UdapEd - -p "5171:8080" -p "7041:443" -e ASPNETCORE_HTTPS_PORT=7041 - .. - e17eb5d1-fcd6-4149-b420-26b7e7d50e28 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Always - - - Always - - - Always - - - Always - - - - - - - - diff --git a/Shared/Extensions/CertificateExtensions.cs b/Shared/Extensions/CertificateExtensions.cs index c8ca3a4..cfc5b54 100644 --- a/Shared/Extensions/CertificateExtensions.cs +++ b/Shared/Extensions/CertificateExtensions.cs @@ -9,6 +9,7 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; +using System.Text; namespace UdapEd.Shared.Extensions { @@ -31,5 +32,54 @@ public static string GetPublicKeyAlgorithm(this X509Certificate2 certificate) return ""; } + + public static string ToPemFormat(this byte[]? rawData, bool lineBreaks = false) + { + if (rawData == null) + { + return string.Empty; + } + + const string pemHeader = "-----BEGIN CERTIFICATE-----"; + var rawDataString = Encoding.UTF8.GetString(rawData); + + if (rawDataString.StartsWith(pemHeader)) + { + return rawDataString; + } + + var pem = new StringBuilder(); + pem.AppendLine("-----BEGIN CERTIFICATE-----"); + pem.AppendLine(Convert.ToBase64String(rawData, lineBreaks ? Base64FormattingOptions.None : Base64FormattingOptions.InsertLineBreaks)); + pem.AppendLine("-----END CERTIFICATE-----"); + + return pem.ToString(); + } + + public static string ExportToPem(this X509Certificate2 cert, bool lineBreaks = false) + { + var builder = new StringBuilder(); + builder.AppendLine("-----BEGIN CERTIFICATE-----"); + builder.AppendLine(Convert.ToBase64String(cert.Export(X509ContentType.Cert), + lineBreaks ? Base64FormattingOptions.None : Base64FormattingOptions.InsertLineBreaks)); + builder.AppendLine("-----END CERTIFICATE-----"); + return builder.ToString(); + } + + public static string ExportPrivateKeyToPem(this X509Certificate2 cert, bool lineBreaks = false) + { + var builder = new StringBuilder(); + var privateKey = cert.GetRSAPrivateKey(); + if (privateKey != null) + { + var keyBytes = privateKey.ExportPkcs8PrivateKey(); + builder.AppendLine("-----BEGIN PRIVATE KEY-----"); + builder.AppendLine(Convert.ToBase64String(keyBytes, + lineBreaks ? Base64FormattingOptions.None : Base64FormattingOptions.InsertLineBreaks)); + builder.AppendLine("-----END PRIVATE KEY-----"); + } + return builder.ToString(); + } + } } diff --git a/Shared/Services/Infrastructure.cs b/Shared/Services/Infrastructure.cs index a2e133d..801a848 100644 --- a/Shared/Services/Infrastructure.cs +++ b/Shared/Services/Infrastructure.cs @@ -45,8 +45,8 @@ public async Task BuildMyTestCertificatePackage(List subjAltName var (caData, intermediateData) = await GetSigningCertificates(); - using var rootCa = new X509Certificate2(caData, "udap-test"); - using var subCa = new X509Certificate2(intermediateData, "udap-test"); + using var rootCa = X509CertificateLoader.LoadPkcs12(caData, "udap-test"); + using var subCa = X509CertificateLoader.LoadPkcs12(intermediateData, "udap-test"); var certTooling = new CertificateTooling(); @@ -109,8 +109,8 @@ public async Task JitFhirlabsCommunityCertificate(List subjAltNa { var (caData, intermediateData) = await GetSigningCertificates(); - using var rootCa = new X509Certificate2(caData, "udap-test"); - using var subCa = new X509Certificate2(intermediateData, "udap-test"); + using var rootCa = X509CertificateLoader.LoadPkcs12(caData, "udap-test"); + using var subCa = X509CertificateLoader.LoadPkcs12(intermediateData, "udap-test"); var certTooling = new CertificateTooling(); @@ -144,7 +144,7 @@ public async Task JitFhirlabsCommunityCertificate(List subjAltNa { var bytes = await _httpClient.GetByteArrayAsync(url); - var cert = new X509Certificate2(bytes); + var cert = X509CertificateLoader.LoadCertificate(bytes); return new CertificateDisplayBuilder(cert).BuildCertificateDisplayData(); } catch (Exception ex) diff --git a/Shared/Services/x509/CertificateTooling.cs b/Shared/Services/x509/CertificateTooling.cs index 322217a..d364a60 100644 --- a/Shared/Services/x509/CertificateTooling.cs +++ b/Shared/Services/x509/CertificateTooling.cs @@ -14,7 +14,7 @@ namespace UdapEd.Shared.Services.x509; public class CertificateTooling { - public byte[] BuildUdapClientCertificate( + public byte[]? BuildUdapClientCertificate( X509Certificate2 intermediateCert, X509Certificate2 caCert, RSA intermediateKey, @@ -95,15 +95,17 @@ public byte[] BuildUdapClientCertificate( var clientCertWithKey = clientCert.CopyWithPrivateKey(rsaKey); - var certPackage = new X509Certificate2Collection(); - certPackage.Add(clientCertWithKey); - certPackage.Add(new X509Certificate2(intermediateCert.Export(X509ContentType.Cert))); - certPackage.Add(new X509Certificate2(caCert.Export(X509ContentType.Cert))); + var certPackage = new X509Certificate2Collection + { + clientCertWithKey, + X509CertificateLoader.LoadCertificate(intermediateCert.Export(X509ContentType.Cert)), + X509CertificateLoader.LoadCertificate(caCert.Export(X509ContentType.Cert)) + }; return certPackage.Export(X509ContentType.Pkcs12, password); } - public byte[] BuildClientCertificateECDSA( + public byte[]? BuildClientCertificateECDSA( X509Certificate2 intermediateCert, X509Certificate2 caCert, RSA intermediateKey, @@ -184,10 +186,12 @@ public byte[] BuildClientCertificateECDSA( var clientCertWithKey = clientCert.CopyWithPrivateKey(ecdsa); - var certPackage = new X509Certificate2Collection(); - certPackage.Add(clientCertWithKey); - certPackage.Add(new X509Certificate2(intermediateCert.Export(X509ContentType.Cert))); - certPackage.Add(new X509Certificate2(caCert.Export(X509ContentType.Cert))); + var certPackage = new X509Certificate2Collection + { + clientCertWithKey, + X509CertificateLoader.LoadCertificate(intermediateCert.Export(X509ContentType.Cert)), + X509CertificateLoader.LoadCertificate(caCert.Export(X509ContentType.Cert)) + }; return certPackage.Export(X509ContentType.Pkcs12, password); diff --git a/UdapEdAppMaui/App.xaml.cs b/UdapEdAppMaui/App.xaml.cs index c707525..f3f0874 100644 --- a/UdapEdAppMaui/App.xaml.cs +++ b/UdapEdAppMaui/App.xaml.cs @@ -10,8 +10,13 @@ public App(CrlCacheService crlCacheService) { _crlCacheService = crlCacheService; InitializeComponent(); + } - MainPage = new MainPage(); + protected override Window CreateWindow(IActivationState? activationState) + { + var window = base.CreateWindow(activationState); + window.Page = new MainPage(); + return window; } protected override void OnStart() diff --git a/UdapEdAppMaui/Services/AccessService.cs b/UdapEdAppMaui/Services/AccessService.cs index e539d40..12794d8 100644 --- a/UdapEdAppMaui/Services/AccessService.cs +++ b/UdapEdAppMaui/Services/AccessService.cs @@ -87,7 +87,7 @@ public AccessService(HttpClient httpClient, ILogger logger) } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var tokenRequestBuilder = AccessTokenRequestForAuthorizationCodeBuilder.Create( tokenRequestModel.ClientId, @@ -118,7 +118,7 @@ public AccessService(HttpClient httpClient, ILogger logger) } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var tokenRequestBuilder = AccessTokenRequestForClientCredentialsBuilder.Create( tokenRequestModel.ClientId, diff --git a/UdapEdAppMaui/Services/Authentication/ClientCertificateProvider.cs b/UdapEdAppMaui/Services/Authentication/ClientCertificateProvider.cs index 4304cbf..9d89670 100644 --- a/UdapEdAppMaui/Services/Authentication/ClientCertificateProvider.cs +++ b/UdapEdAppMaui/Services/Authentication/ClientCertificateProvider.cs @@ -32,7 +32,7 @@ public ClientCertificateProvider(ILogger logger) if (certBytesWithKey != null) { var certBytes = Convert.FromBase64String(certBytesWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); return clientCert; } @@ -48,7 +48,7 @@ public ClientCertificateProvider(ILogger logger) if (anchorBytes != null) { var certBytes = Convert.FromBase64String(anchorBytes); - var anchorCerts = new X509Certificate2Collection() { new(certBytes) }; + var anchorCerts = new X509Certificate2Collection(X509CertificateLoader.LoadCertificate(certBytes)); return anchorCerts; } diff --git a/UdapEdAppMaui/Services/CertificationService.cs b/UdapEdAppMaui/Services/CertificationService.cs index 64a86d4..59ced99 100644 --- a/UdapEdAppMaui/Services/CertificationService.cs +++ b/UdapEdAppMaui/Services/CertificationService.cs @@ -50,7 +50,7 @@ public CertificationService(HttpClient httpClient, ILogger await fileStream.ReadAsync(certBytes, 0, certBytes.Length); - var certificate = new X509Certificate2(certBytes, "udap-test", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, "udap-test", X509KeyStorageFlags.Exportable); var subjectName = certificate.SubjectName.Name; var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); @@ -106,7 +106,7 @@ public async Task UploadCertificate(string base64EncodedBytes) var certBytes = Convert.FromBase64String(clientCertSession); try { - var certificate = new X509Certificate2(certBytes, password, X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, password, X509KeyStorageFlags.Exportable); var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); await StoreInChunks(UdapEdConstants.CERTIFICATION_CERTIFICATE_WITH_KEY, clientCertWithKeyBytes); result.DistinguishedName = certificate.SubjectName.Name; @@ -165,7 +165,7 @@ public async Task UploadCertificate(string base64EncodedBytes) if (certBytesWithKey != null) { var certBytes = Convert.FromBase64String(certBytesWithKey); - var certificate = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -215,7 +215,7 @@ public async Task RemoveCertificate() } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var certificationBuilder = UdapCertificationsAndEndorsementBuilder.Create(request.CertificationName, clientCert); @@ -271,7 +271,7 @@ public async Task RemoveCertificate() } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var document = JsonSerializer .Deserialize(request.SoftwareStatement)!; diff --git a/UdapEdAppMaui/Services/DiscoveryService.cs b/UdapEdAppMaui/Services/DiscoveryService.cs index 2656d67..d84fdbf 100644 --- a/UdapEdAppMaui/Services/DiscoveryService.cs +++ b/UdapEdAppMaui/Services/DiscoveryService.cs @@ -28,6 +28,7 @@ using UdapEd.Shared.Services; using Task = System.Threading.Tasks.Task; using Microsoft.Maui.Storage; +using UdapEd.Shared.Extensions; namespace UdapEdAppMaui.Services; internal class DiscoveryService : IDiscoveryService @@ -61,7 +62,7 @@ public DiscoveryService(IUdapClient udapClient, HttpClient httpClient, IOptionsM var result = new MetadataVerificationModel(); var certBytes = Convert.FromBase64String(anchorString); - var anchorCert = new X509Certificate2(certBytes); + var anchorCert = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); var trustAnchorStore = new TrustAnchorMemoryStore() { AnchorCertificates = new HashSet @@ -167,7 +168,7 @@ void OnTokenError(string message) => try { var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -196,7 +197,7 @@ void OnTokenError(string message) => var response = await _httpClient.GetAsync(new Uri(anchorCertificate)); response.EnsureSuccessStatusCode(); var certBytes = await response.Content.ReadAsByteArrayAsync(); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -226,7 +227,7 @@ void OnTokenError(string message) => var response = await _httpClient.GetAsync(new Uri(anchorCertificate)); response.EnsureSuccessStatusCode(); var certBytes = await response.Content.ReadAsByteArrayAsync(); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -260,7 +261,7 @@ void OnTokenError(string message) => if (base64String != null) { var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -311,7 +312,7 @@ public Task SetClientHeaders(Dictionary headers) { await Task.Delay(1, token); var certBytes = Convert.FromBase64String(base64EncodedCertificate!.First()); - var cert = new X509Certificate2(certBytes); + var cert = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); var result = new CertificateDisplayBuilder(cert).BuildCertificateDisplayData(); return result; @@ -329,7 +330,7 @@ public Task SetClientHeaders(Dictionary headers) { await Task.Delay(1, token); var certBytes = Convert.FromBase64String(base64EncodedCertificate!); - var cert = new X509Certificate2(certBytes); + var cert = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); var result = new CertificateDisplayBuilder(cert).BuildCertificateDisplayData(); return result; diff --git a/UdapEdAppMaui/Services/MutualTlsService.cs b/UdapEdAppMaui/Services/MutualTlsService.cs index e76a97b..194c545 100644 --- a/UdapEdAppMaui/Services/MutualTlsService.cs +++ b/UdapEdAppMaui/Services/MutualTlsService.cs @@ -52,7 +52,7 @@ public async Task UploadClientCertificate(string certBytes) var certBytes = new byte[fileStream.Length]; await fileStream.ReadAsync(certBytes, 0, certBytes.Length); - var certificate = new X509Certificate2(certBytes, "udap-test", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, "udap-test", X509KeyStorageFlags.Exportable); var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WITH_KEY, Convert.ToBase64String(clientCertWithKeyBytes)); @@ -100,7 +100,7 @@ await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WIT var certBytes = Convert.FromBase64String(clientCertSession); try { - var certificate = new X509Certificate2(certBytes, password, X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, password, X509KeyStorageFlags.Exportable); var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WITH_KEY, Convert.ToBase64String(clientCertWithKeyBytes)); @@ -153,7 +153,7 @@ await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WIT if (certBytesWithKey != null) { var certBytes = Convert.FromBase64String(certBytesWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); result.DistinguishedName = clientCert.SubjectName.Name; result.Thumbprint = clientCert.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -186,7 +186,7 @@ await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WIT try { var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -215,7 +215,7 @@ await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WIT var response = await _httpClient.GetAsync(new Uri(anchorCertificate)); response.EnsureSuccessStatusCode(); var certBytes = await response.Content.ReadAsByteArrayAsync(); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -247,7 +247,7 @@ await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WIT if (base64String != null) { var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -270,7 +270,7 @@ await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WIT public async Task?> VerifyMtlsTrust(string publicCertificate) { var clientCertBytes = Convert.FromBase64String(publicCertificate); - var clientCertificate = new X509Certificate2(clientCertBytes); + var clientCertificate = X509CertificateLoader.LoadCertificate(clientCertBytes); var base64String = await SecureStorage.Default.GetAsync(UdapEdConstants.MTLS_ANCHOR_CERTIFICATE); @@ -280,7 +280,7 @@ await SecureStorage.Default.SetAsync(UdapEdConstants.MTLS_CLIENT_CERTIFICATE_WIT } var certBytes = Convert.FromBase64String(base64String); - var certificate = new X509Certificate2(certBytes); + var certificate = X509Certificate2.CreateFromPem(certBytes.ToPemFormat()); var notifications = new List(); _trustChainValidator.Problem += element => notifications.Add($"Validation Problem: {element.ChainElementStatus.Summarize(TrustChainValidator.DefaultProblemFlags)}"); diff --git a/UdapEdAppMaui/Services/RegisterService.cs b/UdapEdAppMaui/Services/RegisterService.cs index 8a3d9fc..481c395 100644 --- a/UdapEdAppMaui/Services/RegisterService.cs +++ b/UdapEdAppMaui/Services/RegisterService.cs @@ -61,7 +61,7 @@ public async Task UploadClientCertificate(string base64EncodedBytes) } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); UdapDcrBuilderForClientCredentialsUnchecked dcrBuilder; @@ -129,7 +129,7 @@ public async Task UploadClientCertificate(string base64EncodedBytes) } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); UdapDcrBuilderForAuthorizationCodeUnchecked dcrBuilder; @@ -200,7 +200,7 @@ public async Task UploadClientCertificate(string base64EncodedBytes) } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var document = JsonSerializer .Deserialize(request.SoftwareStatement)!; @@ -262,7 +262,7 @@ public async Task UploadClientCertificate(string base64EncodedBytes) } var certBytes = Convert.FromBase64String(clientCertWithKey); - var clientCert = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); var document = JsonSerializer .Deserialize(request.SoftwareStatement)!; @@ -383,7 +383,7 @@ await response.Content.ReadAsStringAsync(), var certBytes = Convert.FromBase64String(clientCertSession); try { - var certificate = new X509Certificate2(certBytes, password, X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, password, X509KeyStorageFlags.Exportable); var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); await StoreInChunks(UdapEdConstants.UDAP_CLIENT_CERTIFICATE_WITH_KEY, clientCertWithKeyBytes); @@ -440,7 +440,7 @@ await response.Content.ReadAsStringAsync(), if (certBytesWithKey != null) { var certBytes = Convert.FromBase64String(certBytesWithKey); - var certificate = new X509Certificate2(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); + var certificate = X509CertificateLoader.LoadPkcs12(certBytes, "ILikePasswords", X509KeyStorageFlags.Exportable); result.DistinguishedName = certificate.SubjectName.Name; result.Thumbprint = certificate.Thumbprint; result.CertLoaded = CertLoadedEnum.Positive; @@ -488,11 +488,11 @@ await response.Content.ReadAsStringAsync(), try { - certificate = new X509Certificate2(certBytes, "udap-test", X509KeyStorageFlags.Exportable); + certificate = X509CertificateLoader.LoadPkcs12(certBytes, "udap-test", X509KeyStorageFlags.Exportable); } catch { - certificate = new X509Certificate2(certBytes, _configuration["sampleKeyC"], X509KeyStorageFlags.Exportable); + certificate = X509CertificateLoader.LoadPkcs12(certBytes, _configuration["sampleKeyC"], X509KeyStorageFlags.Exportable); } var clientCertWithKeyBytes = certificate.Export(X509ContentType.Pkcs12, "ILikePasswords"); diff --git a/_tests/UtilityTests/FhirUtilityTests.cs b/_tests/UtilityTests/FhirUtilityTests.cs index 582dfff..a2734e1 100644 --- a/_tests/UtilityTests/FhirUtilityTests.cs +++ b/_tests/UtilityTests/FhirUtilityTests.cs @@ -206,7 +206,7 @@ public async T.Task ExpandValueSets() public async T.Task mTLS_Call() { using var httpClientHandler = new HttpClientHandler(); - var clientCert = new X509Certificate2("FhirLabs_mTLS_Client.pfx", "udap-test", X509KeyStorageFlags.Exportable); + var clientCert = X509CertificateLoader.LoadPkcs12FromFile("FhirLabs_mTLS_Client.pfx", "udap-test", X509KeyStorageFlags.Exportable); httpClientHandler.ClientCertificates.Add(clientCert); var httpClient = new HttpClient(httpClientHandler); var weather = await httpClient.GetStringAsync("https://localhost:7057/weatherforecast"); diff --git a/_tests/UtilityTests/InfrastructureControllerTests.cs b/_tests/UtilityTests/InfrastructureControllerTests.cs index 8421351..1b54e13 100644 --- a/_tests/UtilityTests/InfrastructureControllerTests.cs +++ b/_tests/UtilityTests/InfrastructureControllerTests.cs @@ -40,7 +40,7 @@ public async Task BuildAUdapClientCertFromWebService() var contentBase64 = await response.Content.ReadAsStringAsync(); var bytes = Convert.FromBase64String(contentBase64); - var certificate = new X509Certificate2(bytes, "udap-test"); + var certificate = X509CertificateLoader.LoadPkcs12(bytes, "udap-test"); var subjectAltNames = certificate.GetSubjectAltNames() .Where(s => s.Item1 == "URI") @@ -62,7 +62,7 @@ public async Task BuildAUdapClientCert() Substitute.For>()); var bytes = await infrastructure.JitFhirlabsCommunityCertificate(subjAltNames, "udap-test"); - var certificate = new X509Certificate2(bytes, "udap-test"); + var certificate = X509CertificateLoader.LoadPkcs12(bytes, "udap-test"); var subjectAltNames = certificate.GetSubjectAltNames() .Where(s => s.Item1 == "URI")