如何使用包含主题类型为 CA 的基本约束扩展的 CA 证书创建自签名证书

How to create a self signed certificate with a CA certificate containing the basic constraint extension with subject type as CA

我正在尝试使用 azure rest 创建应用程序网关 api。我使用的是使用以下文档生成的自签名证书:

https://docs.microsoft.com/en-us/azure/application-gateway/self-signed-certificates

当我发送创建应用程序网关的请求时,出现以下错误:

不包含任何 CA 证书。 CA 证书包含主题类型为 CA 的基本约束扩展。

我曾尝试将根证书与客户端证书结合使用,但这似乎没有帮助。

该解决方案需要自动化,将 运行 来自 Windows 机器,这里是与文档相匹配的相关源代码 (C#):

        Process process = null;
        var processInfo = new ProcessStartInfo();
        processInfo.FileName = AzureNames.OpenSSLBinaryLocation;
        processInfo.CreateNoWindow = true;
        processInfo.UseShellExecute = false;
        processInfo.RedirectStandardError = true;
        processInfo.RedirectStandardOutput = true;
        processInfo.WorkingDirectory = workingDirectory;
        
        processInfo.Arguments = string.Format("ecparam -out {0}.key -name prime256v1 -genkey", AzureNames.CertificateRoot);
        process = Process.Start(processInfo);
        process.WaitForExit();

        processInfo.Arguments = string.Format("req -new -sha256 -key {0}.key -out {0}.csr -subj \"/C=US/ST=Denver/L=Denver/O=Enterprise Architecture/OU=Enterprise Architecture/CN=site.com/emailAddress=sample@sample.com\"", AzureNames.CertificateRoot);
        process = Process.Start(processInfo);
        process.WaitForExit();

        processInfo.Arguments = string.Format("x509 -req -sha256 -days 365 --extensions v3_ca -in {0}.csr -signkey contoso.key -out {0}.crt", AzureNames.CertificateRoot);
        process = Process.Start(processInfo);
        process.WaitForExit();

        processInfo.Arguments = string.Format("ecparam -out {0}.key -name prime256v1 -genkey", AzureNames.CertificateClient);
        process = Process.Start(processInfo);
        process.WaitForExit();

        processInfo.Arguments = string.Format("req -new -sha256 -key {0}.key -out {0}.csr -subj \"/C=US/ST=Denver/L=Denver/O=Enterprise Architecture/OU=Enterprise Architecture/CN=site.com/emailAddress=sample@sample.com\"", AzureNames.CertificateClient);
        process = Process.Start(processInfo);
        process.WaitForExit();

        processInfo.Arguments = string.Format("x509 -req -in {0}.csr -CA  {1}.crt -CAkey {1}.key -CAcreateserial -out {0}.crt -days 365 --extensions v3_ca -sha256", AzureNames.CertificateClient, AzureNames.CertificateRoot);
        process = Process.Start(processInfo);
        process.WaitForExit();
        
        process.Close();

        //combine root cert into client certificate
        var rootContents = File.ReadAllText(AzureNames.CertificatesStorageLocation + @"\" + AzureNames.CertificateRoot + ".crt");           
        File.AppendAllText(AzureNames.CertificatesStorageLocation + @"\" + AzureNames.CertificateClient + ".crt", Environment.NewLine + rootContents);

        //perform manual step
        File.Copy(AzureNames.CertificatesStorageLocation + @"\" + AzureNames.CertificateClient + ".crt", AzureNames.CertificatesStorageLocation + @"\" + AzureNames.CertificateClient + ".cer");
        var userCommand = string.Format("openssl pkcs12 –export –in {0}.cer –inkey {0}.key –out {0}.pfx -passout pass:{1}", AzureNames.CertificateClient, AzureNames.CertificatePassword);
        Console.WriteLine("Open command prompt, then run the following two statements as seperate commands(copy paste)");
        Console.WriteLine("--------------------------");
        Console.WriteLine("cd \"" + workingDirectory + "\"");
        Console.WriteLine(userCommand);
        Console.WriteLine("--------------------------");
        Console.WriteLine("After you have successfully run the commands above:");
        Console.WriteLine("       1. Close the command prompt you just opened(not this one)");
        Console.WriteLine("       2. Press any key to continue");
        Console.ReadKey();
        Console.WriteLine();
        Console.WriteLine("Continuing on...");

你所有的 C# 代码都在为 运行 "x509" 和朋友生成 shell 进程。

建议:由于您的环境是 MS Windows/MS Azure,请试试这个:

PS PKI: New-SelfSignedCertificate

New-SelfSignedCertificate -DnsName "www.fabrikam.com", "www.contoso.com" -CertStoreLocation "cert:\LocalMachine\My"

您可以指定任意数量的扩展名(通过 OID),包括:

The object identifiers of some common extensions are as follows:

Application Policy. 1.3.6.1.4.1.311.21.10
Application Policy Mappings. 1.3.6.1.4.1.311.21.11
Basic Constraints. 2.5.29.19
Certificate Policies. 2.5.29.32
Enhanced Key Usage. 2.5.29.37
Name Constraints. 2.5.29.30
Policy Mappings. 2.5.29.33
Subject Alternative Name. 2.5.29.17

另请参阅:


附录:

也可以直接在C#中生成自签名证书:

https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.certificaterequest?view=net-6.0

这完全支持证书扩展:

X509Extension Class

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

public class CertSelect
{
    public static void Main()
    {
        try
        {
            X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

            X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
            for (int i = 0; i < collection.Count; i++)
            {
                foreach (X509Extension extension in collection[i].Extensions)
                {
                    Console.WriteLine(extension.Oid.FriendlyName + "(" + extension.Oid.Value + ")");

                    if (extension.Oid.FriendlyName == "Key Usage")
                    {
                        X509KeyUsageExtension ext = (X509KeyUsageExtension)extension;
                        Console.WriteLine(ext.KeyUsages);
                    }

                    if (extension.Oid.FriendlyName == "Basic Constraints")
                    {
                        X509BasicConstraintsExtension ext = (X509BasicConstraintsExtension)extension;
                        Console.WriteLine(ext.CertificateAuthority);
                        Console.WriteLine(ext.HasPathLengthConstraint);
                        Console.WriteLine(ext.PathLengthConstraint);
                    }

                    if (extension.Oid.FriendlyName == "Subject Key Identifier")
                    {
                        X509SubjectKeyIdentifierExtension ext = (X509SubjectKeyIdentifierExtension)extension;
                        Console.WriteLine(ext.SubjectKeyIdentifier);
                    }

                    if (extension.Oid.FriendlyName == "Enhanced Key Usage")
                    {
                        X509EnhancedKeyUsageExtension ext = (X509EnhancedKeyUsageExtension)extension;
                        OidCollection oids = ext.EnhancedKeyUsages;
                        foreach (Oid oid in oids)
                        {
                            Console.WriteLine(oid.FriendlyName + "(" + oid.Value + ")");
                        }
                    }
                }
            }
            store.Close();
        }
        catch (CryptographicException)
        {
            Console.WriteLine("Information could not be written out for this certificate.");
        }
    }
}

现代 openSSL 使用必需的 .cnf 文件来实现原始教程中提到的功能:https://docs.microsoft.com/en-us/azure/application-gateway/self-signed-certificates

更改第二个openSSL进程

processInfo.Arguments = string.Format("req -config {1} -new -sha256 -key {0}.key -out {0}.csr -subj \"/C=US/ST=Denver/L=Denver/O=Enterprise Architecture/OU=Enterprise Architecture/CN=site.com/emailAddress=sample@sample.com\"", AzureNames.CertificateRoot, configFile);

添加所需的configFile.cnf

[要求]

req_extensions = v3_req

distinguished_name = dn

[dn]

[v3_req]

基本约束 = CA:TRUE

然后更改第三个openSSL进程

processInfo.Arguments = string.Format("x509 -req -sha256 -days 365 -extensions v3_ca -extfile {1} -in {0}.csr -signkey contoso.key -out {0}.crt", AzureNames.CertificateRoot, configCAFile);

添加所需的configFileCA.cnf

[v3_ca]

基本约束 = CA:TRUE