
Some time ago I wondered if it is possible to set up a certificate factory without resorting to the openssl utility . How to bring the whole process “from the button” from key generation to authentication. Looking ahead, I will say that the System.Security.Cryptography space in this regard is completely self-sufficient. In this article, I will consider the steps of creating certificates, exporting to pem and pkcs12 formats , storing certificates in the file system, and authentication using only classes from System.Security.Cryptography .
Creature
In this article, I will consider a simple client-server interaction scheme, without a certification authority. For mutual authentication, we need the root self-signed certificate caCert and the two end clientsCert and serverCert . Clients exchange their certificates, authenticate by root, success. Creating certificates consists of the same steps as any openssl manual :
Generate an asymmetric key:
var rsaKey = RSA.Create(2048);
We describe the subject of certification:
string subject = "CN=myauthority.ru";
cn – “common name”, , , . , . MSDN "C = US/O = Microsoft/OU = WGA/CN = test".
:
var certReq = new CertificateRequest(subject, rsaKey,HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1);
Pkcs1 openssl.
:
certReq.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
certReq.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certReq.PublicKey, false));
, , SKI ( ).
5 :
var expirate = DateTimeOffset.Now.AddYears(5);
var caCert = certReq.CreateSelfSigned(DateTimeOffset.Now, expirate);
.
:
var clientKey = RSA.Create(2048);
string subject = "CN=10.10.10.*";
var clientReq = new CertificateRequest(subject, clientKey,HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1);
ip , .
:
clientReq.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
clientReq.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, false));
clientReq.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(clientReq.PublicKey, false));
:
byte[] serialNumber = BitConverter.GetBytes(DateTime.Now.ToBinary());
Serial Number – , , . , .
5 :
var clientCert = clientReq.Create(caCert, DateTimeOffset.Now, expirate, serialNumber):
, . , caCert.Subject clientCert.Issuer, , .
, , . openssl pem, public.crt private.key. X509Certificate2, . , , base64 :
StringBuilder builder = new StringBuilder();
builder.AppendLine("-----BEGIN CERTIFICATE-----");
builder.AppendLine(Convert.ToBase64String(cert.RawData, Base64FormattingOptions.InsertLineBreaks));
builder.AppendLine("-----END CERTIFICATE-----");
File.WriteAllText("public.crt", builder.ToString());
:
RSA key = (RSA)cert.PrivateKey;
string name = key.SignatureAlgorithm.ToUpper();
StringBuilder builder = new StringBuilder();
builder.AppendLine($"-----BEGIN {name} PRIVATE KEY-----");
builder.AppendLine(Convert.ToBase64String(key.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks));
builder.AppendLine($"-----END {name} PRIVATE KEY-----");
File.WriteAllText("private.key", builder.ToString());
, ExportRSAPrivateKey netcore 3.0, .
— pkcs12 pfx, . X509Certificate2 Export, X509ContentType.Pkcs12 X509ContentType.Pfx. , , cert.HasPrivateKey == false. , X509Certificate2 , , . . p12 pfx, :
var exportCert = new X509Certificate2(cert.Export(X509ContentType.Cert), (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet).CopyWithPrivateKey((RSA)cert.PrivateKey);
File.WriteAllBytes("client.pfx", exportCert.Export(X509ContentType.Pfx));
File.WriteAllBytes("client.p12", exportCert.Export(X509ContentType.Pkcs12));
Export .
.net core , X509Store. :
X509Store store = new X509Store("test");
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
OC Linux "~/.dotnet/corefx/cryptography/x509stores/ test/" "827...E3E.pfx", ( Thumbprint). - openssl , . *.pfx , . X509Store , IssueName .
. , https. , . . « », , — , .
nginx :
server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/ssl/public.crt;
ssl_certificate_key /etc/nginx/ssl/private.key;
ssl_client_certificate /etc/nginx/ssl/caCert.crt;
ssl_verify_client on;
}
HttpClient:
SocketsHttpHandler handler = new SocketsHttpHandler();
handler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
X509Chain chain = new X509Chain(false);
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
chain.ChainPolicy.ExtraStore.Add(caCert);
var serverert = new X509Certificate2(certificate);
return chain.Build(serverert);
};
handler.SslOptions.ClientCertificates = new X509CertificateCollection() { clientCert };
HttpClient client = new HttpClient(handler);
var resp = await client.GetAsync…
"" "" .
.net core Linux OpenSSL. . , BouncyCastle, , , , 10 . , , X.509.