public static void ECDSA_Signing_RSA() { using (RSA rsa = RSA.Create()) using (ECDsa ecdsa = ECDsa.Create()) { var request = new CertificateRequest( new X500DistinguishedName("CN=Test"), ecdsa, HashAlgorithmName.SHA256); request.CertificateExtensions.Add( new X509BasicConstraintsExtension(true, false, 0, true)); DateTimeOffset now = DateTimeOffset.UtcNow; using (X509Certificate2 cert = request.CreateSelfSigned(now, now.AddDays(1))) { X509SignatureGenerator generator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1); request = new CertificateRequest( new X500DistinguishedName("CN=Leaf"), rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); byte[] serialNumber = { 1, 1, 2, 3, 5, 8, 13 }; AssertExtensions.Throws <ArgumentException>("issuerCertificate", () => request.Create(cert, now, now.AddHours(3), serialNumber)); // Passes with the generator using (request.Create(cert.SubjectName, generator, now, now.AddHours(3), serialNumber)) { } } } }
public static void PublicKeyEncoding() { using (RSA rsa = RSA.Create()) { rsa.ImportParameters(TestData.RsaBigExponentParams); X509SignatureGenerator signatureGenerator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1); PublicKey publicKey = signatureGenerator.PublicKey; // Irrespective of what the current key thinks, the PublicKey value we encode for RSA will always write // DER-NULL parameters, by the guidance of RFC 3447: // // The object identifier rsaEncryption identifies RSA public and private // keys as defined in Appendices A.1.1 and A.1.2. The parameters field // associated with this OID in a value of type AlgorithmIdentifier shall // have a value of type NULL. Assert.Equal(new byte[] { 5, 0 }, publicKey.EncodedParameters.RawData); string expectedKeyHex = // SEQUENCE "3082010C" + // INTEGER (modulus) "0282010100" + TestData.RsaBigExponentParams.Modulus.ByteArrayToHex() + // INTEGER (exponent) "0205" + TestData.RsaBigExponentParams.Exponent.ByteArrayToHex(); Assert.Equal(expectedKeyHex, publicKey.EncodedKeyValue.RawData.ByteArrayToHex()); const string rsaEncryptionOid = "1.2.840.113549.1.1.1"; Assert.Equal(rsaEncryptionOid, publicKey.Oid.Value); Assert.Equal(rsaEncryptionOid, publicKey.EncodedParameters.Oid.Value); Assert.Equal(rsaEncryptionOid, publicKey.EncodedKeyValue.Oid.Value); PublicKey publicKey2 = signatureGenerator.PublicKey; Assert.Same(publicKey, publicKey2); } }
public void CreateIssuerRSACngWithSuppliedKeyPair() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Assert.Ignore("Cng provider only available on windows"); } X509Certificate2 issuer = null; CngKey cngKey = CngKey.Create(CngAlgorithm.Rsa); using (RSA rsaKeyPair = new RSACng(cngKey)) { // create cert with supplied keys var generator = X509SignatureGenerator.CreateForRSA(rsaKeyPair, RSASignaturePadding.Pkcs1); using (var cert = CertificateBuilder.Create("CN=Root Cert") .SetCAConstraint(-1) .SetRSAPublicKey(rsaKeyPair) .CreateForRSA(generator)) { Assert.NotNull(cert); issuer = new X509Certificate2(cert.RawData); WriteCertificate(cert, "Default root cert with supplied RSA cert"); CheckPEMWriter(cert); } // now sign a cert with supplied private key using (var appCert = CertificateBuilder.Create("CN=App Cert") .SetIssuer(issuer) .CreateForRSA(generator)) { Assert.NotNull(appCert); Assert.AreEqual(issuer.SubjectName.Name, appCert.IssuerName.Name); Assert.AreEqual(issuer.SubjectName.RawData, appCert.IssuerName.RawData); WriteCertificate(appCert, "Signed RSA app cert"); CheckPEMWriter(appCert); } } }
public static void ReproduceBigExponentCsr() { X509Extension sanExtension = new X509Extension( "2.5.29.17", "302387047F00000187100000000000000000000000000000000182096C6F63616C686F7374".HexToByteArray(), false); byte[] autoCsr; byte[] csr; string csrPem; string autoCsrPem; using (RSA rsa = RSA.Create()) { rsa.ImportParameters(TestData.RsaBigExponentParams); CertificateRequest request = new CertificateRequest( "CN=localhost, OU=.NET Framework (CoreFX), O=Microsoft Corporation, L=Redmond, S=Washington, C=US", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); request.CertificateExtensions.Add(sanExtension); autoCsr = request.CreateSigningRequest(); autoCsrPem = request.CreateSigningRequestPem(); X509SignatureGenerator generator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1); csr = request.CreateSigningRequest(generator); csrPem = request.CreateSigningRequestPem(generator); } AssertExtensions.SequenceEqual(TestData.BigExponentPkcs10Bytes, autoCsr); AssertExtensions.SequenceEqual(TestData.BigExponentPkcs10Bytes, csr); Assert.Equal(TestData.BigExponentPkcs10Pem, autoCsrPem); Assert.Equal(TestData.BigExponentPkcs10Pem, csrPem); }
public static void RsaPkcsSignatureGeneratorCtor_Exceptions() { AssertExtensions.Throws <ArgumentNullException>( "key", () => X509SignatureGenerator.CreateForRSA(null, RSASignaturePadding.Pkcs1)); }
public static void ReproduceBigExponentCert() { DateTimeOffset notBefore = new DateTimeOffset(2016, 3, 2, 1, 48, 0, TimeSpan.Zero); DateTimeOffset notAfter = new DateTimeOffset(2017, 3, 2, 1, 48, 0, TimeSpan.Zero); byte[] serialNumber = "9B5DE6C15126A58B".HexToByteArray(); var subject = new X500DistinguishedName( "CN=localhost, OU=.NET Framework (CoreFX), O=Microsoft Corporation, L=Redmond, S=Washington, C=US"); X509Extension skidExtension = new X509SubjectKeyIdentifierExtension( "78A5C75D51667331D5A96924114C9B5FA00D7BCB", false); X509Extension akidExtension = new X509Extension( "2.5.29.35", "3016801478A5C75D51667331D5A96924114C9B5FA00D7BCB".HexToByteArray(), false); X509Extension basicConstraints = new X509BasicConstraintsExtension(true, false, 0, false); X509Certificate2 cert; using (RSA rsa = RSA.Create()) { rsa.ImportParameters(TestData.RsaBigExponentParams); CertificateRequest request = new CertificateRequest(subject, rsa, HashAlgorithmName.SHA256); request.CertificateExtensions.Add(skidExtension); request.CertificateExtensions.Add(akidExtension); request.CertificateExtensions.Add(basicConstraints); var signatureGenerator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1); cert = request.Create(subject, signatureGenerator, notBefore, notAfter, serialNumber); } const string expectedHex = "308203EB308202D3A0030201020209009B5DE6C15126A58B300D06092A864886" + "F70D01010B050030818A310B3009060355040613025553311330110603550408" + "130A57617368696E67746F6E3110300E060355040713075265646D6F6E64311E" + "301C060355040A13154D6963726F736F667420436F72706F726174696F6E3120" + "301E060355040B13172E4E4554204672616D65776F726B2028436F7265465829" + "31123010060355040313096C6F63616C686F7374301E170D3136303330323031" + "343830305A170D3137303330323031343830305A30818A310B30090603550406" + "13025553311330110603550408130A57617368696E67746F6E3110300E060355" + "040713075265646D6F6E64311E301C060355040A13154D6963726F736F667420" + "436F72706F726174696F6E3120301E060355040B13172E4E4554204672616D65" + "776F726B2028436F726546582931123010060355040313096C6F63616C686F73" + "7430820124300D06092A864886F70D010101050003820111003082010C028201" + "0100AF81C1CBD8203F624A539ED6608175372393A2837D4890E48A19DED36973" + "115620968D6BE0D3DAA38AA777BE02EE0B6B93B724E8DCC12B632B4FA80BBC92" + "5BCE624F4CA7CC606306B39403E28C932D24DD546FFE4EF6A37F10770B2215EA" + "8CBB5BF427E8C4D89B79EB338375100C5F83E55DE9B4466DDFBEEE42539AEF33" + "EF187B7760C3B1A1B2103C2D8144564A0C1039A09C85CF6B5974EB516FC8D662" + "3C94AE3A5A0BB3B4C792957D432391566CF3E2A52AFB0C142B9E0681B8972671" + "AF2B82DD390A39B939CF719568687E4990A63050CA7768DCD6B378842F18FDB1" + "F6D9FF096BAF7BEB98DCF930D66FCFD503F58D41BFF46212E24E3AFC45EA42BD" + "884702050200000441A350304E301D0603551D0E0416041478A5C75D51667331" + "D5A96924114C9B5FA00D7BCB301F0603551D2304183016801478A5C75D516673" + "31D5A96924114C9B5FA00D7BCB300C0603551D13040530030101FF300D06092A" + "864886F70D01010B0500038201010077756D05FFA6ADFED5B6D4AFB540840C6D" + "01CF6B3FA6C973DFD61FCAA0A814FA1E2469019D94B1D856D07DD2B95B8550DF" + "D2085953A494B99EFCBAA7982CE771984F9D4A445FFEE062E8A049736A39FD99" + "4E1FDA0A5DC2B5B0E57A0B10C41BC7FE6A40B24F85977302593E60B98DD4811D" + "47D948EDF8D6E6B5AF80A1827496E20BFD240E467674504D4E4703331D64705C" + "36FB6E14BABFD9CBEEC44B33A8D7B36479900F3C5BBAB69C5E453D180783E250" + "8051B998C038E4622571D2AB891D898E5458828CF18679517D28DBCABF72E813" + "07BFD721B73DDB1751123F99D8FC0D533798C4DBD14719D5D8A85B00A144A367" + "677B48891A9B56F045334811BACB7A"; Assert.Equal(expectedHex, cert.RawData.ByteArrayToHex()); }
public static PSD2Certificate createRSAKeysAndCertificate(PSD2CertificateParameters parameters) { var context = new ValidationContext(parameters, null, null); var validationResults = new List <ValidationResult>(); bool valid = Validator.TryValidateObject(parameters, context, validationResults, true); if (!valid) { throw new ValidationException("Invalid Request", new AggregateException(validationResults.Select(validationResult => new ValidationException(validationResult.ErrorMessage)))); } var subjectDN = CreateDistinguishedName(new Dictionary <string, string> { { "O", parameters.Subject.Organization }, { "CN", parameters.Subject.CommonName }, { "C", parameters.Subject.Country }, { OID_organizationIdentifier, parameters.Subject.OrganizationIdentifier }, }); var issuerDN = CreateDistinguishedName(new Dictionary <string, string> { { OID_emailAddress, parameters.Issuer.EmailAddress }, { "CN", parameters.Issuer.CommonName }, { "OU", parameters.Issuer.OrganizationUnit }, { "O", parameters.Issuer.Organization }, { "L", parameters.Issuer.Locality }, { "ST", parameters.Issuer.State }, { "C", parameters.Issuer.Country }, }); var issuerDnsName = parameters.IssuerDnsName; using (RSA rsa = RSA.Create(2048)) { var request = new CertificateRequest(subjectDN, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation | X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign, false)); if (parameters.CertificateType == PSD2CertificateType.QWAC) // only for qwac { request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid(OID_serverAuth), new Oid(OID_clientAuth) }, false)); } request.CertificateExtensions.Add(new X509QcStatmentExtension(parameters.Roles, parameters.CertificateType, parameters.RetentionPeriod, parameters.NcaName, parameters.NcaId, false)); var sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName(issuerDnsName); request.CertificateExtensions.Add(sanBuilder.Build()); using (RSA issuerRSA = RSA.Create(4096)) { var certificate = request.Create(issuerDN, X509SignatureGenerator.CreateForRSA(issuerRSA, RSASignaturePadding.Pkcs1), DateTimeOffset.Now, DateTimeOffset.Now.AddMonths(39), new byte[] { 1, 2, 3, 4 }); return(new PSD2Certificate { PublicKey = PemExporter.ExportPublicKeyPKCS1(rsa), PrivateKey = PemExporter.ExportPrivateKeyPKCS8(rsa), Certificate = PemExporter.ToPem("CERTIFICATE", certificate.Export(X509ContentType.Cert)) }); } } }
internal RSASha1Pkcs1SignatureGenerator(RSA rsa) { _realRsaGenerator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1); }
public static void SignatureAlgorithm_Encoding(string hashAlgorithmName) { // PSS-MGF1-with-SHA-2-* end up differing in only three bytes: // 1) hashAlgorithm.algorithmId's last byte // 2) mgf.parameters.algorithmId's last byte // 3) saltLen. byte lastOidByte; byte saltLenByte; switch (hashAlgorithmName) { case "SHA256": lastOidByte = 0x01; saltLenByte = 256 / 8; break; case "SHA384": lastOidByte = 0x02; saltLenByte = 384 / 8; break; case "SHA512": lastOidByte = 0x03; saltLenByte = 512 / 8; break; default: throw new ArgumentOutOfRangeException(nameof(hashAlgorithmName)); } string expectedHex = // SEQUENCE (AlgorithmIdentifier) "303D" + // OBJECT IDENTIFIER (AlgorithmIdentifier.algorithm == Oids.RsaPss) "06092A864886F70D01010A" + // SEQUENCE (AlgorithmIdentifier.params == RSASSA-PSS-params) "3030" + // CONSTRUCTED CONTEXT SPECIFIC 0 (params.hashAlgorithm) "A00D" + // SEQUENCE (AlgorithmIdentifier) "300B" + // OBJECT IDENTIFIER (params.hashAlgorithm.algorithm) "06096086480165030402" + lastOidByte.ToString("X2") + // CONSTRUCTED CONTEXT SPECIFIC 1 (params.maskGenAlgorithm) "A11A" + // SEQUENCE (MaskGenAlgorithm) "3018" + // OBJECT IDENTIFIER (MaskGenAlgorithm.algorithm == Oids.Mgf1) "06092A864886F70D010108" + // SEQUENCE (MaskGenAlgorithm.params) "300B" + // OBJECT IDENTIFIER (MGF PRF == same hash algorithm as above) "06096086480165030402" + lastOidByte.ToString("X2") + // CONSTRUCTED CONTEXT SPECIFIC 2 (params.saltLength) "A203" + // INTEGER (saltLength == size of hash) "0201" + saltLenByte.ToString("X2"); using (RSA rsa = RSA.Create()) { RSAParameters parameters = TestData.RsaBigExponentParams; rsa.ImportParameters(parameters); HashAlgorithmName hashAlgorithm = new HashAlgorithmName(hashAlgorithmName); var signatureGenerator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pss); byte[] sigAlg = signatureGenerator.GetSignatureAlgorithmIdentifier(hashAlgorithm); Assert.Equal(expectedHex, sigAlg.ByteArrayToHex()); } }
public static void FractionalSecondsNotWritten(bool selfSigned) { using (X509Certificate2 savedCert = new X509Certificate2(TestData.PfxData, TestData.PfxDataPassword)) using (RSA rsa = savedCert.GetRSAPrivateKey()) { X500DistinguishedName subjectName = new X500DistinguishedName("CN=Test"); var request = new CertificateRequest( subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // notBefore is a date before 2050 UTC (encoded using UTC TIME), // notAfter is a date after 2050 UTC (encoded using GENERALIZED TIME). DateTimeOffset notBefore = new DateTimeOffset(2049, 3, 4, 5, 6, 7, 89, TimeSpan.Zero); DateTimeOffset notAfter = notBefore.AddYears(2); Assert.NotEqual(0, notAfter.Millisecond); DateTimeOffset normalizedBefore = notBefore.AddMilliseconds(-notBefore.Millisecond); DateTimeOffset normalizedAfter = notAfter.AddMilliseconds(-notAfter.Millisecond); byte[] manualSerialNumber = { 3, 2, 1 }; X509Certificate2 cert; if (selfSigned) { cert = request.CreateSelfSigned(notBefore, notAfter); } else { cert = request.Create( subjectName, X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1), notBefore, notAfter, manualSerialNumber); } using (cert) { Assert.Equal(normalizedBefore.DateTime.ToLocalTime(), cert.NotBefore); Assert.Equal(normalizedAfter.DateTime.ToLocalTime(), cert.NotAfter); if (selfSigned) { // The serial number used in CreateSelfSigned is random, so find the issuer name, // and the validity period is the next 34 bytes. Verify it was encoded as expected. // // Since the random serial number is at most 9 bytes and the subjectName encoded // value is 17 bytes, there's no chance of an early false match. byte[] encodedCert = cert.RawData; byte[] needle = subjectName.RawData; int index = encodedCert.AsSpan().IndexOf(needle); Assert.Equal( "3020170D3439303330343035303630375A180F32303531303330343035303630375A", encodedCert.AsSpan(index + needle.Length, 34).ByteArrayToHex()); } else { // The entire encoding is deterministic in this mode. Assert.Equal( "308201953081FFA0030201020203030201300D06092A864886F70D01010B0500" + "300F310D300B06035504031304546573743020170D3439303330343035303630" + "375A180F32303531303330343035303630375A300F310D300B06035504031304" + "5465737430819F300D06092A864886F70D010101050003818D00308189028181" + "00B11E30EA87424A371E30227E933CE6BE0E65FF1C189D0D888EC8FF13AA7B42" + "B68056128322B21F2B6976609B62B6BC4CF2E55FF5AE64E9B68C78A3C2DACC91" + "6A1BC7322DD353B32898675CFB5B298B176D978B1F12313E3D865BC53465A11C" + "CA106870A4B5D50A2C410938240E92B64902BAEA23EB093D9599E9E372E48336" + "730203010001300D06092A864886F70D01010B0500038181000095ABC7CC7B01" + "9C2A88A7891165B6ACCDBC5137D80C0A5151B11FD4D789CCE808412ABF05FFB1" + "D9BE097776147A6D4C3EE177E5F9C2C9E8C005D72A6473F9904185B95634BFB4" + "EA80B232B271DC1BF20A2FDC46FC93771636B618F29417C31D5F602236FDB414" + "CDC1BEDE700E31E80DC5E7BB7D3F367420B72925605C916BDA", cert.RawData.ByteArrayToHex()); } } } }
public void CreateForRSAWithGeneratorTest( KeyHashPair keyHashPair ) { // default signing cert with custom key using (X509Certificate2 signingCert = CertificateBuilder.Create(Subject) .SetCAConstraint() .SetHashAlgorithm(HashAlgorithmName.SHA512) .SetRSAKeySize(2048) .CreateForRSA()) { WriteCertificate(signingCert, $"Signing RSA {signingCert.GetRSAPublicKey().KeySize} cert"); using (RSA rsaPrivateKey = signingCert.GetRSAPrivateKey()) { var generator = X509SignatureGenerator.CreateForRSA(rsaPrivateKey, RSASignaturePadding.Pkcs1); using (var issuer = new X509Certificate2(signingCert.RawData)) using (var cert = CertificateBuilder.Create("CN=App Cert") .SetIssuer(issuer) .CreateForRSA(generator)) { Assert.NotNull(cert); WriteCertificate(cert, $"Default signed RSA cert"); } } using (RSA rsaPrivateKey = signingCert.GetRSAPrivateKey()) using (RSA rsaPublicKey = signingCert.GetRSAPublicKey()) { var generator = X509SignatureGenerator.CreateForRSA(rsaPrivateKey, RSASignaturePadding.Pkcs1); using (var issuer = new X509Certificate2(signingCert.RawData)) using (var cert = CertificateBuilder.Create("CN=App Cert") .SetHashAlgorithm(keyHashPair.HashAlgorithmName) .SetIssuer(issuer) .SetRSAPublicKey(rsaPublicKey) .CreateForRSA(generator)) { Assert.NotNull(cert); WriteCertificate(cert, $"Default signed RSA cert with Public Key"); } } using (RSA rsaPrivateKey = signingCert.GetRSAPrivateKey()) { var generator = X509SignatureGenerator.CreateForRSA(rsaPrivateKey, RSASignaturePadding.Pkcs1); using (var issuer = new X509Certificate2(signingCert.RawData)) using (var cert = CertificateBuilder.Create("CN=App Cert") .SetHashAlgorithm(keyHashPair.HashAlgorithmName) .SetIssuer(issuer) .SetRSAKeySize(keyHashPair.KeySize) .CreateForRSA(generator)) { Assert.NotNull(cert); WriteCertificate(cert, $"Default signed RSA cert"); } } // ensure invalid path throws argument exception Assert.Throws <NotSupportedException>(() => { using (RSA rsaPrivateKey = signingCert.GetRSAPrivateKey()) { var generator = X509SignatureGenerator.CreateForRSA(rsaPrivateKey, RSASignaturePadding.Pkcs1); _ = CertificateBuilder.Create("CN=App Cert") .SetHashAlgorithm(keyHashPair.HashAlgorithmName) .SetRSAKeySize(keyHashPair.KeySize) .CreateForRSA(generator); } }); } }
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()); } }
internal static void MakeTestChain( ReadOnlySpan <RSA> keys, Span <X509Certificate2> certs, IEnumerable <X509Extension> endEntityExtensions, IEnumerable <X509Extension> intermediateExtensions, IEnumerable <X509Extension> rootExtensions) { if (keys.Length < 2) { throw new ArgumentException(nameof(keys)); } if (keys.Length != certs.Length) { throw new ArgumentException(nameof(certs)); } rootExtensions ??= new X509Extension[] { new X509BasicConstraintsExtension(true, false, 0, true), new X509KeyUsageExtension( X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.DigitalSignature, false) }; intermediateExtensions ??= new X509Extension[] { new X509BasicConstraintsExtension(true, false, 0, true), new X509KeyUsageExtension( X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.DigitalSignature, false) }; endEntityExtensions ??= new X509Extension[] { new X509BasicConstraintsExtension(false, false, 0, true), new X509KeyUsageExtension( X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation | X509KeyUsageFlags.KeyEncipherment, false) }; TimeSpan notBeforeInterval = TimeSpan.FromDays(30); TimeSpan notAfterInterval = TimeSpan.FromDays(90); DateTimeOffset eeStart = DateTimeOffset.UtcNow.AddDays(-7); DateTimeOffset eeEnd = eeStart.AddDays(45); byte[] serialBuf = new byte[16]; int rootIndex = keys.Length - 1; HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256; RSASignaturePadding signaturePadding = RSASignaturePadding.Pkcs1; CertificateRequest rootReq = new CertificateRequest( "CN=Test Root", keys[rootIndex], hashAlgorithm, signaturePadding); foreach (X509Extension extension in rootExtensions) { rootReq.CertificateExtensions.Add(extension); } X509SignatureGenerator lastGenerator = X509SignatureGenerator.CreateForRSA(keys[rootIndex], RSASignaturePadding.Pkcs1); X500DistinguishedName lastSubject = rootReq.SubjectName; certs[rootIndex] = rootReq.Create( lastSubject, lastGenerator, eeStart - (notBeforeInterval * rootIndex), eeEnd + (notAfterInterval * rootIndex), CreateSerial()); int presentationNumber = 0; for (int i = rootIndex - 1; i > 0; i--) { presentationNumber++; CertificateRequest intermediateReq = new CertificateRequest( $"CN=Intermediate Layer {presentationNumber}", keys[i], hashAlgorithm, signaturePadding); foreach (X509Extension extension in intermediateExtensions) { intermediateReq.CertificateExtensions.Add(extension); } certs[i] = intermediateReq.Create( lastSubject, lastGenerator, eeStart - (notBeforeInterval * i), eeEnd + (notAfterInterval * i), CreateSerial()); lastSubject = intermediateReq.SubjectName; lastGenerator = X509SignatureGenerator.CreateForRSA(keys[i], RSASignaturePadding.Pkcs1); } CertificateRequest eeReq = new CertificateRequest( "CN=End-Entity", keys[0], hashAlgorithm, signaturePadding); foreach (X509Extension extension in endEntityExtensions) { eeReq.CertificateExtensions.Add(extension); } certs[0] = eeReq.Create(lastSubject, lastGenerator, eeStart, eeEnd, CreateSerial()); }