Lots of similar questions, but I don't see a good answer.
I have a cloud-based application with an agent installed on customer sites in the field. I want to have the agent, upon installation, generate a CSR and upload the request over HTTPS to the cloud service, where I will sign it with the cloud service certificate (that the agent will trust) and return the signed certificate. This certificate will be used for agent authentication, encryption, and file signatures.
I'm able to make the CSR pretty easily:
public string GenerateAgentCsr(Guid customerId)
{
var domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
var domainDistinguishedName = string.Join(",DC=", domain.Split("."));
var distinguishedName = $"DC={Environment.MachineName},DC={domainDistinguishedName},O={customerId}";
var rsa = RSA.Create(1024);
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
request.CertificateExtensions.Add(new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.DataEncipherment |
X509KeyUsageFlags.NonRepudiation, false));
var armored = request.AsCsr();
return armored;
}
public static string AsCsr(this CertificateRequest request)
{
var encoded = request.CreateSigningRequest();
var payload = Convert.ToBase64String(encoded);
using var stream = new MemoryStream();
using (var writer = new StreamWriter(stream, Encoding.UTF8, 512, true))
{
writer.WriteLine("-----BEGIN CERTIFICATE REQUEST-----");
writer.WriteLine(payload.Slice());
writer.WriteLine("-----END CERTIFICATE REQUEST-----");
writer.Flush();
}
stream.Position = 0;
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
...so I can send this up to the cloud server, but then I immediately run into a problem. My plan was to have a method like so:
public X509Certificate2 SignCertificate(CertificateRequest csr)
{
var signedCert = csr.Create(GetCertificateAuthorityCertificate(), DateTimeOffset.Now, DateTimeOffset.Now.AddYears(10),
new byte[] { 1, 2, 3, 4 });
return signedCert;
}
...but I can't actually convert the CSR into a CertificateRequest. There's no Parse mechanism or constructor that will allow this.
So... once I have the CSR, how do I properly parse and sign it with my cloud service certificate so that I can send it back to the agent?