为Identity Server 4生成自签名证书时,“ X509证书没有私钥”

时间:2018-11-27 16:25:32

标签: docker ssl-certificate identityserver4 x509

这就是我要实现的目标。我们正在Kubernetes上开发一个微服务应用程序。微服务之一是IdentityServer实例。最初,我想在Docker上本地测试该解决方案以确保其有效。为此,我想将证书粘贴到appsettings.json。最终,该值将被Kubernetes机密替换。在我的启动课程中,这是我尝试加载证书的方式:

 services.AddIdentityServer()
         .AddSigningCredential(GetIdentityServerCertificate())
         .AddConfigurationStore(...

    private X509Certificate2 GetIdentityServerCertificate()
    {
        var clientSecret = Configuration["Certificate"];
        var pfxBytes = Convert.FromBase64String(clientSecret);
        var certificate = new X509Certificate2(pfxBytes);
        return certificate;
    }

证书是由我使用openssl生成的:

openssl req –newkey rsa:2048 –nodes –keyout XXXXX.key –x509 –days 365 –out XXXXX.cer

openssl pkcs12 –export –in XXXX.cer –inkey XXXX.key –out XXXX.pfx

然后我通过使用以下方式获得证书:

openssl pkcs12 -in XXXX.pfx -info -nokeys

-----BEGIN CERTIFICATE-----
i take this content and paste into appconfig.json
-----END CERTIFICATE-----

当我调试它时,结果是: System.InvalidOperationException:'X509证书没有私钥。'

1 个答案:

答案 0 :(得分:1)

以下是在.net core中工作的示例:

使用openssl工具。打开终端并输入以下命令:

openssl genrsa -out private.pem 2048 
openssl rsa -in private.pem -outform PEM -pubout -out public.pem

这将导致创建2个文件。

在.NET Core应用程序中实际使用RSA密钥之前,还有另外一件事。我们需要将它们转换为XML。使用“ RSA PEM到XML转换器”。 可以在这里完成:Online rsa key converter 将XML复制到private-rsa-key.xml和public-rsa-key.xml文件之前,请使用以下格式设置它们:XML Formatter

只有负责生成令牌的服务才需要私钥。不得在该项目外部共享。

Startup.cs:

public class Startup
{
    public IConfiguration Configuration { get; }
    private SigningCredentials _signingCredentials;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        // other code
        services
                .AddIdentityServer()
                .AddSigningCredential(_signingCredentials)
                .AddInMemoryApiResources(_identityConfig.GetApiResources())
                .AddInMemoryClients(_identityConfig.GetClients());
        // other code
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseMvc();
        app.UseIdentityServer();
    }

    private void InitializeRsaKey()
    {
        try
        {
            RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(2048);
            var rsaParametersPrivate = RSAExtensions.RSAParametersFromXmlFile(Configuration.GetSection("JwtSettings:rsaPrivateKeyXml").Value);
            rsaProvider.ImportParameters(rsaParametersPrivate);
            var securityKey = new RsaSecurityKey(rsaProvider);
            _signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256);
        }
        catch(Exception ex)
        {
            throw new Exception("Identity Server RSA Key initialization failed. " + ex.ToString());
        }
    }
}

RSAExtensions类:

public static class RSAExtensions
{
    /// <summary>
    /// Gets RSA Parameters from XML file.
    /// </summary>
    /// <param name="xmlFilePath">The XML file path.</param>
    /// <returns>RSAParameters.</returns>
    /// <exception cref="Exception">Invalid XML RSA key.</exception>
    public static RSAParameters RSAParametersFromXmlFile(string xmlFilePath)
    {
        RSAParameters parameters = new RSAParameters();

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(File.ReadAllText(xmlFilePath));

        if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
        {
            foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
            {
                switch (node.Name)
                {
                    case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                }
            }
        }
        else
        {
            throw new Exception("Invalid XML RSA key.");
        }

        return parameters;
    }
}

在appsettings.json中添加以下内容:

"JwtSettings": {
    "rsaPrivateKeyXml": "RSAKeys/private-rsa-key.xml",
},

我不知道您是否可以将原始XML存储在appsettings.json中。如果不是,您可以编写一个辅助方法,将pem转换为xml并将原始pem内容存储在配置变量中。

我在GitHub上找到了一个示例项目,可能会帮助您进行转换:Rsa-Dotnet-Core