diff --git a/CHANGELOG.md b/CHANGELOG.md index aad2f1a..388784b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Certificate Manager change log + +## 2020-01-27 version 1.0.2 +* Small fixes for RSA certificates KeySize +* IdentityServer4 example certificates + ## 2020-01-24 version 1.0.1 * Support RSA certificates diff --git a/README.md b/README.md index 7a50d29..c31c6cd 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Add the NuGet package to the your project file ``` - + ``` The NuGet packages uses dependency injection to setup. In a console application initialize the package as follows: diff --git a/src/CertificateManager.sln b/src/CertificateManager.sln index dfbac2c..a8293ae 100644 --- a/src/CertificateManager.sln +++ b/src/CertificateManager.sln @@ -28,6 +28,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IoTHubCreateDeviceCertifica EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreateAngularVueJsDevelopmentCertificates", "CreateAngularVueJsDevelopmentCertificates\CreateAngularVueJsDevelopmentCertificates.csproj", "{4761AF09-95B5-4632-92D6-872652C354C7}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CreateIdentityServer4Certificates", "CreateIdentityServer4Certificates\CreateIdentityServer4Certificates.csproj", "{C22EB3CB-0F6F-4F64-847B-63E0A75AA999}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -66,6 +68,10 @@ Global {4761AF09-95B5-4632-92D6-872652C354C7}.Debug|Any CPU.Build.0 = Debug|Any CPU {4761AF09-95B5-4632-92D6-872652C354C7}.Release|Any CPU.ActiveCfg = Release|Any CPU {4761AF09-95B5-4632-92D6-872652C354C7}.Release|Any CPU.Build.0 = Release|Any CPU + {C22EB3CB-0F6F-4F64-847B-63E0A75AA999}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C22EB3CB-0F6F-4F64-847B-63E0A75AA999}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C22EB3CB-0F6F-4F64-847B-63E0A75AA999}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C22EB3CB-0F6F-4F64-847B-63E0A75AA999}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/CertificateManager/CertificateManager.csproj b/src/CertificateManager/CertificateManager.csproj index 0bada53..f572da2 100644 --- a/src/CertificateManager/CertificateManager.csproj +++ b/src/CertificateManager/CertificateManager.csproj @@ -11,11 +11,11 @@ Certificate Manager is a package which makes it easy to create certificates (chained and self signed) which can be used to in client server authentication and IoT Devices like Azure IoT Hub certificate authentication mtls pfx cer pem cert crt - first release, certificate creation, export certificates chained and self signed + small fixes for RSA certificates 2020 damienbod true damienbod - 1.0.1 + 1.0.2 diff --git a/src/CertificateManager/CreateCertificates.cs b/src/CertificateManager/CreateCertificates.cs index 05daf0b..98ea056 100644 --- a/src/CertificateManager/CreateCertificates.cs +++ b/src/CertificateManager/CreateCertificates.cs @@ -75,8 +75,7 @@ public X509Certificate2 NewRsaSelfSignedCertificate( X509KeyUsageFlags x509KeyUsageFlags, RsaConfiguration rsaConfiguration) { - using var rsa = RSA.Create("RSA"); - rsa.KeySize = rsaConfiguration.KeySize; // 1024, 2048 or 4096 + using var rsa = RSA.Create(rsaConfiguration.KeySize); // 1024, 2048 or 4096 var request = new CertificateRequest( _certificateUtility.CreateIssuerOrSubject(distinguishedName), rsa, @@ -113,8 +112,7 @@ public X509Certificate2 NewRsaChainedCertificate( throw new Exception("Signing cert must have private key"); } - using var rsa = RSA.Create("rsa"); - rsa.KeySize = rsaConfiguration.KeySize; + using var rsa = RSA.Create(rsaConfiguration.KeySize); var request = new CertificateRequest( _certificateUtility.CreateIssuerOrSubject(distinguishedName), rsa, diff --git a/src/CertificateManager/CreateCertificatesRsa.cs b/src/CertificateManager/CreateCertificatesRsa.cs index 85eaeb8..042395d 100644 --- a/src/CertificateManager/CreateCertificatesRsa.cs +++ b/src/CertificateManager/CreateCertificatesRsa.cs @@ -15,7 +15,14 @@ public CreateCertificatesRsa(CreateCertificates createCertificates) _createCertificates = createCertificates; } - public X509Certificate2 CreateDevelopmentCertificate(string dnsName, int validityPeriodInYears) + /// + /// creates a development certificate + /// + /// DNS name ie localhost etc + /// valid time in years + /// 1024 2048 4096 + /// + public X509Certificate2 CreateDevelopmentCertificate(string dnsName, int validityPeriodInYears, int keySize = 1024) { var basicConstraints = new BasicConstraints { @@ -57,7 +64,10 @@ public X509Certificate2 CreateDevelopmentCertificate(string dnsName, int validit subjectAlternativeName, enhancedKeyUsages, x509KeyUsageFlags, - new RsaConfiguration()); + new RsaConfiguration + { + KeySize = keySize + }); return certificate; } diff --git a/src/CertificateManagerTests/RsaKeySizeTests.cs b/src/CertificateManagerTests/RsaKeySizeTests.cs new file mode 100644 index 0000000..9fd6c6d --- /dev/null +++ b/src/CertificateManagerTests/RsaKeySizeTests.cs @@ -0,0 +1,169 @@ +using CertificateManager; +using CertificateManager.Models; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using Xunit; + +namespace CertificateManagerTests +{ + public class RsaKeySizeTests + { + [Fact] + public void CreateChainedCertificatesRsaKeySizeTest() + { + var serviceProvider = new ServiceCollection() + .AddCertificateManager() + .BuildServiceProvider(); + + var cc = serviceProvider.GetService(); + var cert2048 = CreateRsaCertificate(cc, 2048); + var cert4096 = CreateRsaCertificate(cc, 4096); + + var chained1024 = CreateRsaCertificateChained(cc, 1024, cert2048); + var chained4096 = CreateRsaCertificateChained(cc, 4096, cert2048); + Assert.Equal(1024, chained1024.PrivateKey.KeySize); + Assert.Equal(4096, chained4096.PrivateKey.KeySize); + } + + [Fact] + public void CreateCertificatesRsaKeySizeTest() + { + var serviceProvider = new ServiceCollection() + .AddCertificateManager() + .BuildServiceProvider(); + + var ccRsa = serviceProvider.GetService(); + var cert2048 = ccRsa.CreateDevelopmentCertificate("localhost", 2, 2048); + Assert.Equal(2048, cert2048.PrivateKey.KeySize); + + var cert1024 = ccRsa.CreateDevelopmentCertificate("localhost", 2); + Assert.Equal(1024, cert1024.PrivateKey.KeySize); + } + + [Fact] + public void RsaKeySizeTest() + { + var serviceProvider = new ServiceCollection() + .AddCertificateManager() + .BuildServiceProvider(); + + var cc = serviceProvider.GetService(); + + var cert2048 = CreateRsaCertificate(cc, 2048); + Assert.Equal(2048, cert2048.PrivateKey.KeySize); + + var cert4096= CreateRsaCertificate(cc, 4096); + Assert.Equal(4096, cert4096.PrivateKey.KeySize); + } + + public static X509Certificate2 CreateRsaCertificate(CreateCertificates createCertificates, int keySize) + { + var basicConstraints = new BasicConstraints + { + CertificateAuthority = true, + HasPathLengthConstraint = true, + PathLengthConstraint = 2, + Critical = false + }; + + var subjectAlternativeName = new SubjectAlternativeName + { + DnsName = new List + { + "localhost", + } + }; + + var x509KeyUsageFlags = X509KeyUsageFlags.KeyCertSign + | X509KeyUsageFlags.DigitalSignature + | X509KeyUsageFlags.KeyEncipherment + | X509KeyUsageFlags.CrlSign + | X509KeyUsageFlags.DataEncipherment + | X509KeyUsageFlags.NonRepudiation + | X509KeyUsageFlags.KeyAgreement; + + // only if mtls is used + var enhancedKeyUsages = new OidCollection + { + new Oid("1.3.6.1.5.5.7.3.1"), // TLS Server auth + new Oid("1.3.6.1.5.5.7.3.2"), // TLS Client auth + //new Oid("1.3.6.1.5.5.7.3.3"), // Code signing + //new Oid("1.3.6.1.5.5.7.3.4"), // Email + //new Oid("1.3.6.1.5.5.7.3.8") // Timestamping + }; + + var certificate = createCertificates.NewRsaSelfSignedCertificate( + new DistinguishedName { CommonName = "localhost" }, + basicConstraints, + new ValidityPeriod + { + ValidFrom = DateTimeOffset.UtcNow, + ValidTo = DateTimeOffset.UtcNow.AddYears(1) + }, + subjectAlternativeName, + enhancedKeyUsages, + x509KeyUsageFlags, + new RsaConfiguration + { + KeySize = keySize + }); + + return certificate; + } + + public static X509Certificate2 CreateRsaCertificateChained(CreateCertificates createCertificates, int keySize, X509Certificate2 parentCert) + { + var basicConstraints = new BasicConstraints + { + CertificateAuthority = false, + HasPathLengthConstraint = false, + PathLengthConstraint = 0, + Critical = false + }; + + var subjectAlternativeName = new SubjectAlternativeName + { + DnsName = new List + { + "localhost", + } + }; + + var x509KeyUsageFlags = X509KeyUsageFlags.DigitalSignature; + + // only if mtls is used + var enhancedKeyUsages = new OidCollection + { + new Oid("1.3.6.1.5.5.7.3.1"), // TLS Server auth + new Oid("1.3.6.1.5.5.7.3.2"), // TLS Client auth + //new Oid("1.3.6.1.5.5.7.3.3"), // Code signing + //new Oid("1.3.6.1.5.5.7.3.4"), // Email + //new Oid("1.3.6.1.5.5.7.3.8") // Timestamping + }; + + var certificate = createCertificates.NewRsaChainedCertificate( + new DistinguishedName { CommonName = "localhost" }, + basicConstraints, + new ValidityPeriod + { + ValidFrom = DateTimeOffset.UtcNow, + ValidTo = DateTimeOffset.UtcNow.AddYears(1) + }, + subjectAlternativeName, + parentCert, + enhancedKeyUsages, + x509KeyUsageFlags, + new RsaConfiguration + { + KeySize = keySize + }); + + return certificate; + } + + } +} diff --git a/src/CreateAngularVueJsDevelopmentCertificates/Program.cs b/src/CreateAngularVueJsDevelopmentCertificates/Program.cs index 900e1c5..c0ae862 100644 --- a/src/CreateAngularVueJsDevelopmentCertificates/Program.cs +++ b/src/CreateAngularVueJsDevelopmentCertificates/Program.cs @@ -1,11 +1,6 @@ using CertificateManager; -using CertificateManager.Models; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; using System.IO; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; namespace CreateAngularVueJsDevelopmentCertificates { diff --git a/src/CreateIdentityServer4Certificates/CreateIdentityServer4Certificates.csproj b/src/CreateIdentityServer4Certificates/CreateIdentityServer4Certificates.csproj new file mode 100644 index 0000000..369da10 --- /dev/null +++ b/src/CreateIdentityServer4Certificates/CreateIdentityServer4Certificates.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + diff --git a/src/CreateIdentityServer4Certificates/Program.cs b/src/CreateIdentityServer4Certificates/Program.cs new file mode 100644 index 0000000..87b6c47 --- /dev/null +++ b/src/CreateIdentityServer4Certificates/Program.cs @@ -0,0 +1,135 @@ +using CertificateManager; +using CertificateManager.Models; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +namespace CreateIdentityServer4Certificates +{ + class Program + { + static CreateCertificates _cc; + static void Main(string[] args) + { + var sp = new ServiceCollection() + .AddCertificateManager() + .BuildServiceProvider(); + + _cc = sp.GetService(); + + var rsaCert = CreateRsaCertificate("locahost", 10); + var ecdsaCert = CreateECDsaCertificate("locahost", 10); + + string password = "1234"; + var iec = sp.GetService(); + + var rsaCertPfxBytes = iec.ExportSelfSignedCertificatePfx(password, rsaCert); + File.WriteAllBytes("rsaCert.pfx", rsaCertPfxBytes); + + var ecdsaCertPfxBytes = iec.ExportSelfSignedCertificatePfx(password, ecdsaCert); + File.WriteAllBytes("ecdsaCert.pfx", ecdsaCertPfxBytes); + + Console.WriteLine(""); + } + + public static X509Certificate2 CreateRsaCertificate(string dnsName, int validityPeriodInYears) + { + var basicConstraints = new BasicConstraints + { + CertificateAuthority = false, + HasPathLengthConstraint = false, + PathLengthConstraint = 0, + Critical = false + }; + + var subjectAlternativeName = new SubjectAlternativeName + { + DnsName = new List + { + dnsName, + } + }; + + var x509KeyUsageFlags = X509KeyUsageFlags.DigitalSignature; + + // only if mtls is used + var enhancedKeyUsages = new OidCollection + { + new Oid("1.3.6.1.5.5.7.3.1"), // TLS Server auth + new Oid("1.3.6.1.5.5.7.3.2"), // TLS Client auth + //new Oid("1.3.6.1.5.5.7.3.3"), // Code signing + //new Oid("1.3.6.1.5.5.7.3.4"), // Email + //new Oid("1.3.6.1.5.5.7.3.8") // Timestamping + }; + + var certificate = _cc.NewRsaSelfSignedCertificate( + new DistinguishedName { CommonName = dnsName }, + basicConstraints, + new ValidityPeriod + { + ValidFrom = DateTimeOffset.UtcNow, + ValidTo = DateTimeOffset.UtcNow.AddYears(validityPeriodInYears) + }, + subjectAlternativeName, + enhancedKeyUsages, + x509KeyUsageFlags, + new RsaConfiguration + { + KeySize = 2048 + }); + + return certificate; + } + + public static X509Certificate2 CreateECDsaCertificate(string dnsName, int validityPeriodInYears) + { + var basicConstraints = new BasicConstraints + { + CertificateAuthority = false, + HasPathLengthConstraint = false, + PathLengthConstraint = 0, + Critical = false + }; + + var subjectAlternativeName = new SubjectAlternativeName + { + DnsName = new List + { + dnsName, + } + }; + + var x509KeyUsageFlags = X509KeyUsageFlags.DigitalSignature; + + // only if mtls is used + var enhancedKeyUsages = new OidCollection { + new Oid("1.3.6.1.5.5.7.3.1"), // TLS Server auth + new Oid("1.3.6.1.5.5.7.3.2"), // TLS Client auth + //new Oid("1.3.6.1.5.5.7.3.3"), // Code signing + //new Oid("1.3.6.1.5.5.7.3.4"), // Email + //new Oid("1.3.6.1.5.5.7.3.8") // Timestamping + }; + + var certificate = _cc.NewECDsaSelfSignedCertificate( + new DistinguishedName { CommonName = dnsName }, + basicConstraints, + new ValidityPeriod + { + ValidFrom = DateTimeOffset.UtcNow, + ValidTo = DateTimeOffset.UtcNow.AddYears(validityPeriodInYears) + }, + subjectAlternativeName, + enhancedKeyUsages, + x509KeyUsageFlags, + new ECDsaConfiguration + { + //KeySize = 256 + }); + + return certificate; + } + } +}