服务器无法加载私钥文件的X509证书

43

我正在使用Google Analytics API,并遵循这个SO问题设置OAuth:https://dev59.com/Kuo6XIcBkEYKwwoYPR_f#13013265

这是我的OAuth代码:

public void SetupOAuth ()
{
    var Cert = new X509Certificate2(
        PrivateKeyPath, 
        "notasecret", 
        X509KeyStorageFlags.Exportable);
    var Provider = new AssertionFlowClient(GoogleAuthenticationServer.Description, Cert)
    {
        ServiceAccountId = ServiceAccountUser,
        Scope = ApiUrl + "analytics.readonly"
    };
    var Auth = new OAuth2Authenticator<AssertionFlowClient>(Provider, AssertionFlowClient.GetState);
    Service = new AnalyticsService(Auth);
}

PrivateKeyPath是由Google API Console提供的私钥文件路径。这在我的本地机器上运行得很完美,但当我将其上传到我们的测试服务器时,我遇到了

System.Security.Cryptography.CryptographicException: An internal error occurred.

以下是堆栈跟踪(已删除不相关部分):

System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) +33
System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromFile(String fileName, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx) +0
System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromFile(String fileName, Object password, X509KeyStorageFlags keyStorageFlags) +237
System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags) +140
Metrics.APIs.GoogleAnalytics.SetupOAuth() in <removed>\Metrics\APIs\GoogleAnalytics.cs:36
Metrics.APIs.GoogleAnalytics..ctor(String PrivateKeyPath) in <removed>\Metrics\APIs\GoogleAnalytics.cs:31

看起来好像无法加载文件。我已经检查了传递的PrivateKeyPath,它指向了正确的位置。

有什么想法吗?我不知道这是服务器、文件、代码还是其他问题。

5个回答

84

我想到的其中一件事是你应用程序池的身份,确保加载用户配置文件已开启,否则加密子系统将无法工作。


2
这是加密 API 和应用程序池的常见问题,我也是其中之一受到影响的人。 - Wiktor Zychla
1
哎呀,向您致敬。非常感谢! - Digbyswift
1
有没有关于如何在Azure WebApp中设置此属性的想法?我需要加载一个证书,但无法解决它。 - evilpilaf
1
哇,那真是一个非常简单的解决方案,对于一个不应该成为问题的问题。好答案! - Bryan Mudge
2
@JReam 是的,我们成功加载了证书,诀窍在于构造函数,必须使用 new X509Certificate2(cert, "MyAwesomePassword", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);。 - evilpilaf
显示剩余2条评论

30

我正在使用p12文件进行加载

new X509Certificate2(
HostingEnvironment.MapPath(@"~/App_Data/GoogleAnalytics-privatekey.p12"), ....

尽管File.Exists(filename)返回true,但实际上我还是遇到了FileNotFoundException。

正如@Wiktor Zychla所说,只需启用Load User Profile即可解决问题。

这里有一张需要更改的设置截图:

只需在IIS中的“应用程序池”下右键单击该应用程序池,选择“高级设置”,您需要更改的设置大约在中间位置。

进入图像描述

提示:建议使用此代码进行注释,以防止将来浪费时间,因为如果您以前从未遇到过它,那么它就会变得非常模糊。

  // If this gives FileNotFoundException see 
  // https://dev59.com/OGYq5IYBdhLWcg3wtCzO

你好!我想我有同样的问题,我应该在哪里进行这些更改?谢谢。 - WhoAmI
@KristofferAndersson 我已经更新了答案。只需在 IIS 中右键单击应用程序池,然后选择“高级设置”-然后给我点赞 :-) - Simon_Weaver
嗯,看起来我的问题一定是其他原因。所有的池都被检查为“True”。非常奇怪。我的Keypath看起来像这样:var certificate = new X509Certificate2(@“Models / GAStatistics / \ key.p12”,“notasecret”,X509KeyStorageFlags.Exportable); 不知何故,应用程序无法定位文件(key.p12),即使我已经将它放在了我的MVC应用程序中。谢谢。 - WhoAmI
除了确保您正在查看正确的池外,您是否尝试在文件上使用File.Exists(...)以确保它返回true? - Simon_Weaver
不是,"File.Exists(...)"也在高级设置中吗?我有3个应用程序池,它们都启用了"加载用户配置文件"。我认为我的问题可能与依赖项和NuGet包有关,因为代码在控制台应用程序中运行得非常好,但在MVC中却出现问题。谢谢 - WhoAmI

13

同时尝试指定X509KeyStorageFlags

    var certificate = new X509Certificate2(KeyFilePath, KeyFilePassword, 
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | 
X509KeyStorageFlags.Exportable);

2
添加X509KeyStorageFlags.MachineKeySet特别适用于我。 - John B
这是一个很好的解决方案,可以避免对IIS配置进行混乱。 - AlfonsoML
2
如果设置了X509KeyStorageFlags参数,每次实例化X509Certificate2对象时都会在C:\ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys文件夹中创建一个密钥文件,如果经常这样做,可能会填满磁盘,因此请谨慎使用。 - NahuelGQ
它需要一个文件位于C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys -- 如果您不在选项中放置MachineKeySet,该文件将不会被创建。在PowerShell中,它看起来像这样: New-Object System.Security.Cryptography.X509Certificates.X509Certificate2.Import($certPath,$certPass,"MachineKeySet,Exportable,PersistKeySet") - Jeremy

2
如上所述,您需要配置IIS,但在我们的情况下,有时需要检查以下文件夹的权限:
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
如果设置X509KeyStorageFlags参数,它将在此文件夹中创建一个密钥文件。在我的情况下,此文件夹的权限有所不同。池帐户未添加到所述文件夹中。

但是,授予权限是什么?这个权限授予给哪个用户? - Bruno Heringer
如上所述,需要添加应用程序池账户。 - Shani

-2

不是,"File.Exists(...)" 也在高级设置中吗?我有3个应用池,它们都启用了 "Load User Profile" 的 true。我认为我的问题可能与依赖项和NuGet包有关,因为这段代码在控制台应用程序中可以正常工作,但在MVC中会出现问题。


我处于完全相同的情况,你是如何解决问题的? - Muhammad Mamoor Khan
3
我不明白这个回答与问题有什么关联。 - John Saunders

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接