public static void ArgumentValidation() { SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder(); Assert.Throws <ArgumentOutOfRangeException>("dnsName", () => builder.AddDnsName(null)); Assert.Throws <ArgumentOutOfRangeException>("dnsName", () => builder.AddDnsName(string.Empty)); Assert.Throws <ArgumentOutOfRangeException>("emailAddress", () => builder.AddEmailAddress(null)); Assert.Throws <ArgumentOutOfRangeException>("emailAddress", () => builder.AddEmailAddress(string.Empty)); Assert.Throws <ArgumentNullException>("uri", () => builder.AddUri(null)); Assert.Throws <ArgumentNullException>("ipAddress", () => builder.AddIpAddress(null)); Assert.Throws <ArgumentOutOfRangeException>("upn", () => builder.AddUserPrincipalName(null)); Assert.Throws <ArgumentOutOfRangeException>("upn", () => builder.AddUserPrincipalName(string.Empty)); }
public static void DnsNameMatchIgnoresTrailingPeriodFromParameter() { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=10.0.0.1", key, HashAlgorithmName.SHA256); SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName("fruit.EXAMPLE"); sanBuilder.AddDnsName("*.FrUIt.eXaMpLE"); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { AssertMatch(true, cert, "aPPlE.fruit.example."); AssertMatch(true, cert, "tOmaTO.FRUIT.example."); AssertMatch(false, cert, "tOmaTO.vegetable.example."); AssertMatch(true, cert, "FRUit.example."); AssertMatch(false, cert, "VEGetaBlE.example."); } } }
private static CertificateRequest CreateCertificateRequest(RSA key, string emailAddress, string commonName, string countryCode) { if (emailAddress is null) { emailAddress = Prompt.Input <string>("Email address:"); } if (commonName is null) { commonName = Prompt.Input <string>("Common name:"); } if (countryCode is null) { countryCode = Prompt.Input <string>("Country code:"); } var request = new CertificateRequest($"CN={commonName}, C={countryCode}", key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); //The email address needs to be added to the request as an alternative name var alternativeNameBuilder = new SubjectAlternativeNameBuilder(); alternativeNameBuilder.AddEmailAddress(emailAddress); request.CertificateExtensions.Add(alternativeNameBuilder.Build()); return(request); }
public static void SanDoesNotMatchIPAddressInDnsName() { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=10.0.0.1", key, HashAlgorithmName.SHA256); SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName("127.0.0.1"); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { // 127.0.0.1 is an IP Address, but the SAN calls it a dNSName, so it won't match. AssertMatch(false, cert, "127.0.0.1"); // Since the SAN contains no iPAddress values, we fall back to the CN. AssertMatch(true, cert, "10.0.0.1"); } } }
public static void IPv6InCommonNameIsTextMatch() { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=[fe80::1]", key, HashAlgorithmName.SHA256); SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName("huckleberry.fruit.example"); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { // Various text forms of fe80::1. These would all match under IP-ID, but // only the first couple match under CN-ID (case-insensitive exact) AssertMatch(true, cert, "[fe80::1]"); AssertMatch(true, cert, "[fE80::1]"); AssertMatch(true, cert, "[FE80::1]"); AssertMatch(true, cert, "[Fe80::1]"); AssertMatch(false, cert, "fe80::1"); AssertMatch(false, cert, "[fe80:0000::1]"); AssertMatch(false, cert, "[fe80:0000::01]"); } } }
public static void WildcardRequiresSuffixToMatch() { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=potato.vegetable.example", key, HashAlgorithmName.SHA256); SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName("*"); sanBuilder.AddDnsName("*."); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { AssertMatch(false, cert, "example"); AssertMatch(false, cert, "example."); } } }
public void AddSubjectAlternativeName(CertificateRequest request, SubjectAlternativeName subjectAlternativeName) { foreach (var dnsName in subjectAlternativeName.DnsName) { if (UriHostNameType.Unknown == Uri.CheckHostName(dnsName)) { throw new ArgumentException("Must be a valid DNS name", nameof(dnsName)); } } var sanBuilder = new SubjectAlternativeNameBuilder(); foreach (var dnsName in subjectAlternativeName.DnsName) { sanBuilder.AddDnsName(dnsName); } if (!string.IsNullOrEmpty(subjectAlternativeName.Email)) { sanBuilder.AddEmailAddress(subjectAlternativeName.Email); } var sanExtension = sanBuilder.Build(); request.CertificateExtensions.Add(sanExtension); }
public static void NoPartialWildcards() { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=10.0.0.1", key, HashAlgorithmName.SHA256); SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName("*berry.fruit.example"); sanBuilder.AddDnsName("cran*.fruit.example"); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { AssertMatch(false, cert, "cranberry.fruit.example"); AssertMatch(false, cert, "cranapple.fruit.example"); AssertMatch(false, cert, "strawberry.fruit.example"); } } }
public static void SanWithNoDnsMeansDoCommonNameFallback() { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=zalzalak.fruit.example", key, HashAlgorithmName.SHA256); SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddIpAddress(IPAddress.Loopback); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { AssertMatch(false, cert, "yumberry.fruit.example"); AssertMatch(true, cert, "127.0.0.1"); // Since the SAN contains no dNSName values, we fall back to the CN. AssertMatch(true, cert, "zalzalak.fruit.example"); AssertMatch(false, cert, "zalzalak.fruit.example", allowCommonName: false); } } }
public static void MultiValue() { // This produces the same value as the "ComplexGetNameInfo" certificate/test suite. // Subject Alternative Names: // DNS Name=dns1.subject.example.org // DNS Name=dns2.subject.example.org // RFC822 [email protected] // RFC822 [email protected] // Other Name: // Principal [email protected] // Other Name: // Principal [email protected] // URL=http://uri1.subject.example.org/ // URL=http://uri2.subject.example.org/ const string expectedHex = "3081F88218646E73312E7375626A6563742E6578616D706C652E6F7267821864" + "6E73322E7375626A6563742E6578616D706C652E6F7267811573616E656D6169" + "6C31406578616D706C652E6F7267811573616E656D61696C32406578616D706C" + "652E6F7267A027060A2B060104018237140203A0190C177375626A6563747570" + "6E31406578616D706C652E6F7267A027060A2B060104018237140203A0190C17" + "7375626A65637475706E32406578616D706C652E6F72678620687474703A2F2F" + "757269312E7375626A6563742E6578616D706C652E6F72672F8620687474703A" + "2F2F757269322E7375626A6563742E6578616D706C652E6F72672F"; SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder(); builder.AddDnsName("dns1.subject.example.org"); builder.AddDnsName("dns2.subject.example.org"); builder.AddEmailAddress("*****@*****.**"); builder.AddEmailAddress("*****@*****.**"); builder.AddUserPrincipalName("*****@*****.**"); builder.AddUserPrincipalName("*****@*****.**"); builder.AddUri(new Uri("http://uri1.subject.example.org/")); builder.AddUri(new Uri("http://uri2.subject.example.org/")); X509Extension extension = builder.Build(); Assert.Equal(SubjectAltNameOid, extension.Oid.Value); Assert.Equal( expectedHex, extension.RawData.ByteArrayToHex()); }
public static void SingleValue_EmailAddress_Unicode() { // There's not a good example of what an IDNA-converted email address // looks like, so this isn't easy to verify. For now let it be restricted to IA5. SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder(); // [nihongo]@[nihongo].example.org Assert.Throws <CryptographicException>( () => builder.AddEmailAddress("\u65E5\u672C\u8A8E@\u65E5\u672C\u8A8E.example.org")); }
public static void CreateBrokerTlsCert(this X509Certificate2 CACertificate, string domainname, IPAddress iP, string pubfile, string pivfile, string email) { var build = new SubjectAlternativeNameBuilder(); build.AddDnsName(domainname); build.AddIpAddress(iP); build.AddEmailAddress(email ?? "*****@*****.**"); string name = $"C=CN,CN={iP.ToString()},ST=IoTSharp,O={Dns.GetHostName()},OU= CA_{MethodBase.GetCurrentMethod().Module.Assembly.GetName().Name}"; var broker = CACertificate.CreateTlsClientRSA(name, build); broker.SavePem(pubfile, pivfile); }
public static void SingleValue_EmailAddress_Ascii() { SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder(); builder.AddEmailAddress("*****@*****.**"); X509Extension extension = builder.Build(); Assert.Equal(SubjectAltNameOid, extension.Oid.Value); Assert.Equal("3012811075736572406578616D706C652E6F7267", extension.RawData.ByteArrayToHex()); }
public static void NameConstraintViolation_InvalidGeneralNames() { SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder(); builder.AddEmailAddress("///"); // permitted RFC822 name constraint with GeneralName of ///. string nameConstraints = "3009A007300581032F2F2F"; TestNameConstrainedChain(nameConstraints, builder, (bool result, X509Chain chain) => { Assert.False(result, "chain.Build"); Assert.Equal(PlatformNameConstraints(X509ChainStatusFlags.InvalidNameConstraints), chain.AllStatusFlags()); }); }
public static void SanWithIPAddressMeansNoCommonNameFallback() { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=10.0.0.1", key, HashAlgorithmName.SHA256); SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddIpAddress(IPAddress.Loopback); sanBuilder.AddIpAddress(IPAddress.IPv6Loopback); sanBuilder.AddIpAddress(IPAddress.Parse("[fe80::1]")); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { AssertMatch(true, cert, "127.0.0.1"); // Various text forms of IPv6Loopback AssertMatch(true, cert, "[::1]"); AssertMatch(true, cert, "::1"); AssertMatch(true, cert, "[::01]"); AssertMatch(true, cert, "[0000::1]"); // Various text forms of fe80::1 AssertMatch(true, cert, "[fe80::1]"); AssertMatch(true, cert, "[FE80::1]"); AssertMatch(true, cert, "fe80::1"); AssertMatch(true, cert, "[fe80:0000::1]"); AssertMatch(true, cert, "[fe80:0000::01]"); // Various text forms of fe80:: AssertMatch(false, cert, "[fe80::]"); AssertMatch(false, cert, "fe80::"); AssertMatch(false, cert, "[fe80::0]"); AssertMatch(false, cert, "[fe80:0000::]"); // Since the SAN has an iPAddress value, we do not fall back to the CN. AssertMatch(false, cert, "10.0.0.1"); } } }
public static void WildcardsDoNotMatchAfterFirstPosition() { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=10.0.0.1", key, HashAlgorithmName.SHA256); SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName("fruit.example"); sanBuilder.AddDnsName("*.fruit.example"); sanBuilder.AddDnsName("*.*.fruit.example"); sanBuilder.AddDnsName("apple.*.fruit.example"); sanBuilder.AddDnsName("rambutan.fruit.example"); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { AssertMatch(true, cert, "apple.fruit.example"); AssertMatch(true, cert, "blackberry.fruit.example"); AssertMatch(true, cert, "pome.fruit.example"); AssertMatch(true, cert, "pomme.fruit.example"); AssertMatch(true, cert, "rambutan.fruit.example"); AssertMatch(false, cert, "apple.pome.fruit.example"); AssertMatch(false, cert, "apple.pomme.fruit.example"); AssertMatch(false, cert, "apple.fruit.example", allowWildcards: false); AssertMatch(false, cert, "blackberry.fruit.example", allowWildcards: false); AssertMatch(false, cert, "pome.fruit.example", allowWildcards: false); AssertMatch(false, cert, "pomme.fruit.example", allowWildcards: false); // This one has a redundant dNSName after the wildcard AssertMatch(true, cert, "rambutan.fruit.example", allowWildcards: false); AssertMatch(true, cert, "fruit.example"); AssertMatch(true, cert, "fruit.example", allowWildcards: false); } } }
public void SetUp() { SetUpProvider(); _context = new DefaultHttpContext(); X509Certificate2 certificate; using (RSA rsa = RSA.Create()) { var certReq = new CertificateRequest("CN=eventstoredb-node", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); var sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddEmailAddress("*****@*****.**"); sanBuilder.AddUserPrincipalName("*****@*****.**"); sanBuilder.AddUri(new Uri("http://localhost")); certReq.CertificateExtensions.Add(sanBuilder.Build()); certificate = certReq.CreateSelfSigned(DateTimeOffset.UtcNow.AddMonths(-1), DateTimeOffset.UtcNow.AddMonths(1)); } _context.Connection.ClientCertificate = certificate; _authenticateResult = _provider.Authenticate(_context, out _authenticateRequest); }
public static void OnlyValidHostnamesAccepted(bool addSanExt) { using (ECDsa key = ECDsa.Create()) { CertificateRequest req = new CertificateRequest( "CN=John Smith", key, HashAlgorithmName.SHA256); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset notBefore = now.AddMinutes(-1); DateTimeOffset notAfter = now.AddMinutes(1); if (addSanExt) { SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName("fruit.example"); sanBuilder.AddDnsName("*.fruit.example"); sanBuilder.AddDnsName("*.*.fruit.example"); sanBuilder.AddDnsName("apple.*.fruit.example"); sanBuilder.AddDnsName("rambutan.fruit.example"); sanBuilder.AddEmailAddress("*****@*****.**"); req.CertificateExtensions.Add(sanBuilder.Build()); } using (X509Certificate2 cert = req.CreateSelfSigned(notBefore, notAfter)) { Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname("John Smith")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname("*.pomme.fruit.example")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname(".pomme.fruit.example")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname("*berry.fruit.example")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname("cran*.fruit.example")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname("cran*.fruit.example")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname("")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname(".")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname("*.")); Assert.Throws <ArgumentException>("hostname", () => cert.MatchesHostname("*")); } } }
public IActionResult InstallCertificate([FromBody] CertificateDot dot) { IActionResult actionResult = NoContent(); try { if (_options.CACertificate == null || _options.BrokerCertificate == null) { StringBuilder builder = new StringBuilder(); if (!string.IsNullOrEmpty(dot.C)) { builder.Append($"C={dot.C},"); } builder.Append($"CN={dot.CN},"); if (!string.IsNullOrEmpty(dot.ST)) { builder.Append($"ST={dot.ST},"); } if (!string.IsNullOrEmpty(dot.O)) { builder.Append($"O={dot.O},"); } if (!string.IsNullOrEmpty(dot.OU)) { builder.Append($"OU={dot.OU},"); } var ca = new X509Certificate2().CreateCA(builder.ToString().TrimEnd(',')); ca.SavePem(_options.CACertificateFile, _options.CAPrivateKeyFile); var build = new SubjectAlternativeNameBuilder(); build.AddDnsName(dot.ServerName); if (!string.IsNullOrEmpty(dot.IPAddress)) { build.AddIpAddress(IPAddress.Parse(dot.IPAddress)); } if (!string.IsNullOrEmpty(dot.Email)) { build.AddEmailAddress(dot.Email); } StringBuilder builderserver = new StringBuilder(); if (!string.IsNullOrEmpty(dot.C)) { builderserver.Append($"C={dot.C},"); } builderserver.Append($"CN={dot.ServerName},"); if (!string.IsNullOrEmpty(dot.ST)) { builderserver.Append($"ST={dot.ST},"); } if (!string.IsNullOrEmpty(dot.O)) { builderserver.Append($"O={dot.O},"); } if (!string.IsNullOrEmpty(dot.OU)) { builderserver.Append($"OU={dot.OU},"); } var broker = ca.CreateTlsClientRSA(builderserver.ToString().TrimEnd(','), build); broker.SavePem(_options.CertificateFile, _options.PrivateKeyFile); actionResult = Ok(new { code = 0, msg = "OK", data = new { CAName = ca.GetNameInfo(X509NameType.SimpleName, true), BrokerName = broker.GetNameInfo(X509NameType.SimpleName, false) } }); } else { actionResult = Ok(new { code = -1, msg = Resources.TheCertificateIsInstalled, data = new { CAName = _options.CACertificate.GetNameInfo(X509NameType.SimpleName, true), BrokerName = _options.BrokerCertificate.GetNameInfo(X509NameType.SimpleName, false) } }); } } catch (System.Exception ex) { actionResult = BadRequest(new { code = -2, msg = ex.Message }); _logger.LogError(ex, "InstallCertificate:" + ex.Message); } return(actionResult); }
public async Task <IActionResult> Register([FromBody] RegisterDto model) { IActionResult actionResult = NoContent(); try { if (_options.CACertificate == null && model.TLS) { actionResult = BadRequest(new { code = -1, msg = "There is no root certificate, please initialize the server first" }); } else { var user = new IdentityUser { UserName = model.UserName, Email = model.Email }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { await _signInManager.SignInAsync(user, false); await _signInManager.UserManager.AddClaimAsync(user, new Claim(ClaimTypes.GivenName, model.ClientId)); await _signInManager.UserManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, model.Email)); int _StoreCertPem = 0; if (model.TLS) { SubjectAlternativeNameBuilder altNames = new SubjectAlternativeNameBuilder(); altNames.AddDnsName(model.ClientId); altNames.AddEmailAddress(model.Email); altNames.AddUserPrincipalName(model.UserName); altNames.AddUri(new Uri($"mqtt://{_options.BrokerCertificate.GetNameInfo(X509NameType.DnsName, false)}:{_options.SSLPort}")); string name = $"CN={model.ClientId},C=CN, O={_options.BrokerCertificate.GetNameInfo(X509NameType.SimpleName, false)},OU={model.ClientId}"; var tlsclient = _options.CACertificate.CreateTlsClientRSA(name, altNames); tlsclient.SavePem(out string x509CRT, out string x509Key); _context.StoreCertPem.Add(new StoreCertPem() { Id = user.Id, ClientCert = x509CRT, ClientKey = x509Key }); _StoreCertPem = _context.SaveChanges(); await _signInManager.UserManager.AddClaimAsync(user, new Claim(ClaimTypes.Thumbprint, tlsclient.Thumbprint)); } actionResult = Ok(new { code = 0, msg = "OK", data = GenerateJwtToken(model.UserName, user), model.TLS, StoreTLS = _StoreCertPem > 0 }); } else { var msg = from e in result.Errors select $"{e.Code}:{e.Description}\r\n"; actionResult = BadRequest(new { code = -3, msg = string.Join(';', msg.ToArray()) }); } } } catch (Exception ex) { actionResult = BadRequest(new { code = -2, msg = ex.Message, data = ex }); _logger.LogError(ex, ex.Message); } return(actionResult); }
public FileContentResult get_ssl_certificate(DistinguishedName dName) { var rootCA = CertUtil.getInstance().getRootCA(); var rsa = RSA.Create(); var request = new CertificateRequest(dName.getX509DistinguishedName(), rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); var subjectANB = new SubjectAlternativeNameBuilder(); subjectANB.AddDnsName(dName.DNS); subjectANB.AddEmailAddress(dName.E); request.CertificateExtensions.Add(subjectANB.Build()); request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false)); request.CertificateExtensions.Add(new X509KeyUsageExtension( X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.NonRepudiation, false) ); // set the AuthorityKeyIdentifier. There is no built-in // support, so it needs to be copied from the Subject Key // Identifier of the signing certificate and massaged slightly. // AuthorityKeyIdentifier is "KeyID=" var issuerSubjectKey = rootCA.Extensions["Subject Key Identifier"].RawData; var segment = new byte[issuerSubjectKey.Length - 2]; Buffer.BlockCopy(issuerSubjectKey, 2, segment, 0, issuerSubjectKey.Length - 2); var authorityKeyIdentifer = new byte[segment.Length + 4]; // these bytes define the "KeyID" part of the AuthorityKeyIdentifer var KeyID = new byte[] { 0x30, 0x16, 0x80, 0x14 }; KeyID.CopyTo(authorityKeyIdentifer, 0); segment.CopyTo(authorityKeyIdentifer, 4); request.CertificateExtensions.Add(new X509Extension("2.5.29.35", authorityKeyIdentifer, false)); request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension( new OidCollection { new Oid("1.3.6.1.5.5.7.3.8"), // Timestamping new Oid("1.3.6.1.5.5.7.3.2"), // TLS Client auth new Oid("1.3.6.1.5.5.7.3.1") // TLS Server auth }, false) ); request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false)); // Add Time and Key X509Certificate2 sslCert = request.Create(rootCA, DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1), BitConverter.GetBytes(DateTimeOffset.Now.Ticks)); sslCert = sslCert.CopyWithPrivateKey(rsa); // Create PFX (PKCS #12) with private key byte[] p12Cert = sslCert.Export(X509ContentType.Pkcs12, "password"); // Create Base 64 encoded CER (public key only) string cerCert = "-----BEGIN CERTIFICATE-----\r\n" + Convert.ToBase64String(sslCert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) + "\r\n-----END CERTIFICATE-----"; byte[] pfxCert = sslCert.Export(X509ContentType.Pfx, "password"); String CertID = DateTimeOffset.Now.Ticks.ToString(); // Write to disk System.IO.File.WriteAllBytes(AppContext.BaseDirectory + "/" + CertID + ".p12", p12Cert); System.IO.File.WriteAllText(AppContext.BaseDirectory + "/" + CertID + ".cer", cerCert); System.IO.File.WriteAllBytes(AppContext.BaseDirectory + "/" + CertID + ".pfx", pfxCert); FileContentResult fcResult = File(p12Cert, "application/octet-stream", CertID + ".p12"); //FileContentResult fcResult = File(System.Text.Encoding.ASCII.GetBytes(cerCert), "application/octet-stream", "176743490865.cer"); return(fcResult); }
public IActionResult IssueCertificate(CertRequest certRequest) { if (certRequest.CertPassphrase.Length < Constants.MinPassphraseLength) { _logger.LogWarning( string.Format( "User {} tried to issue new certificate with too short passphrase.", certRequest.Uid ) ); return(BadRequest("Too short passphrase")); } CipherSuite cipherSuite = certRequest.RequestedCipherSuite; if (!cipherSuite.IsValidCipherSuite()) { _logger.LogWarning("Invalid cipher suite:\n" + cipherSuite); return(BadRequest("Invalid cipher suite.")); } User user = _userDBAuthenticator.AuthenticateAndGetUser(certRequest.Uid, certRequest.Password); if (user != null) { // Load the certificate X509Certificate2 coreCACert = new X509Certificate2(CAConfig.CoreCACertPath); HashAlgorithmName hashAlg = new HashAlgorithmName(cipherSuite.HashAlg); AsymmetricAlgorithm privKey = null; string privKeyExport = null; CertificateRequest req = null; if (cipherSuite.Alg.Equals(EncryptionAlgorithms.RSA)) { privKey = RSA.Create(cipherSuite.KeySize); privKeyExport = ((RSA)privKey).ToPem(); req = new CertificateRequest( "CN=" + user.Id, (RSA)privKey, hashAlg, RSASignaturePadding.Pss ); } else if (cipherSuite.Alg.Equals(EncryptionAlgorithms.ECDSA)) { privKey = ECDsa.Create(); privKeyExport = ((ECDsa)privKey).ToPem(); req = new CertificateRequest( "CN=" + user.Id, (ECDsa)privKey, hashAlg ); } else { _logger.LogError( string.Format( "Unknown encryption algorithm '{0}'.", cipherSuite.Alg ) ); throw new CryptographicUnexpectedOperationException(); } // Add email as SAN SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddEmailAddress(user.Email); req.CertificateExtensions.Add(sanBuilder.Build()); // Arguments: Is no CA, no restricted nr of path levels, (nr of path levels), is not critical req.CertificateExtensions.Add( new X509BasicConstraintsExtension(false, false, 0, false) ); req.CertificateExtensions.Add( new X509SubjectKeyIdentifierExtension(req.PublicKey, false) ); req.CertificateExtensions.Add( new X509KeyUsageExtension( X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, false ) ); OidCollection oidCollection = new OidCollection(); // Set Client Authentication Oid oidCollection.Add(new Oid("1.3.6.1.5.5.7.3.2")); // Set Secure Email / Email protection Oid oidCollection.Add(new Oid("1.3.6.1.5.5.7.3.4")); req.CertificateExtensions.Add( new X509EnhancedKeyUsageExtension( oidCollection, false ) ); // Add CRL Distribution Point (CDP) req.CertificateExtensions.Add( new System.Security.Cryptography.X509Certificates.X509Extension( new Oid(X509Extensions.CrlDistributionPoints.Id), new CrlDistPoint( new[] { new DistributionPoint( new DistributionPointName( new GeneralNames( new GeneralName( GeneralName.UniformResourceIdentifier, CAConfig.CrlDistributionPoint ) ) ), null, null ) } ).GetDerEncoded(), false ) ); X509Certificate2 coreCaPublicCert = new X509Certificate2(coreCACert.Export(X509ContentType.Cert)); if (coreCaPublicCert.HasPrivateKey) { _logger.LogError("Core CA public certificate exported with private key!"); throw new CryptographicUnexpectedOperationException(); } // Use transaction to prevent race conditions on the serial number X509Certificate2 userCert; using ( IDbContextTransaction scope = _caDBModifier.GetScope() ) { SerialNumber serialNr = _caDBModifier.GetMaxSerialNr(); // It is necessary to use this constructor to be able to sign keys // that use different algorithms than the one for the core CA's key userCert = req.Create( coreCACert.SubjectName, X509SignatureGenerator.CreateForRSA( (RSA)coreCACert.PrivateKey, RSASignaturePadding.Pss ), DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(CAConfig.UserCertValidityPeriod), serialNr.SerialNrBytes ); _caDBModifier.RevokeAllCertificatesOfUser(user); // Add certificate to DB _caDBModifier.AddCertificate( new PublicCertificate { SerialNr = serialNr.SerialNr, Uid = user.Id, Certificate = Convert.ToBase64String( userCert.Export(X509ContentType.Cert) ), IsRevoked = false } ); scope.Commit(); } var collection = new X509Certificate2Collection(); X509Certificate2 userCertWithPrivKey; if (privKey is RSA rsa) { userCertWithPrivKey = userCert.CopyWithPrivateKey(rsa); } else if (privKey is ECDsa dsa) { userCertWithPrivKey = userCert.CopyWithPrivateKey(dsa); } else { throw new CryptographicUnexpectedOperationException(); } collection.Add(userCertWithPrivKey); collection.Add(coreCaPublicCert); BackupPrivateKey(privKeyExport, user.Id + '_' + userCert.Thumbprint + ".pem.enc"); byte[] certBytes = collection.Export(X509ContentType.Pkcs12, certRequest.CertPassphrase); string pkcs12ArchiveB64 = Convert.ToBase64String(certBytes); // Add encrypted private key to DB _caDBModifier.AddPrivateKey( new PrivateKey { Uid = user.Id, KeyPkcs12 = pkcs12ArchiveB64 } ); _logger.LogInformation("Successfully issued new certificate for user " + user.Id); return(Ok( new UserCertificate { Pkcs12Archive = pkcs12ArchiveB64 } )); } else { _logger.LogWarning( "Unauthorized attempt to issue certificate for user " + certRequest.Uid ); return(Unauthorized()); } }