在阅读X509Certificate2时如何解决访问被拒绝的问题

时间:2019-08-09 10:07:47

标签: c# asp.net-web-api dynamics-crm x509certificate2 xero-api

我正在创建一个API,以通过私有应用程序登录Xero,因此我按照他们的说明和Xero API文档查看其工作原理。链接here

因此,我创建了一个应用程序,并使用OpenSSL生成了公共证书(.cer文件),还为其创建了“ .pfx文件”,并将该文件附加到Notes实体中的Dynamics CRM中。

现在,当我运行C#代码以使用同一对公钥/私钥对登录时,它可以按预期工作。 (从CRM中检索到私钥/公钥对),并按预期方式将其传递给登录代码(代码已粘贴在下面)

下一步是使用C#以编程方式创建这些公钥/私钥对,然后使用下面的代码创建它。

// Generate a RSA Key
RSA RSAKey = RSA.Create(1024);

// Creating Certificate Request with relevant parameters
var req = new CertificateRequest(subjectNameDN, RSAKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

// Creating self-signed certificate with an expiry defined in app settings
X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(expiryDurationInYears));

subjectNameDN变量以字符串格式包含我的OrganizationName,OrganizationUnitName和CommonName。

此步骤之后,我要做的是创建一个.pfx文件和一个.zip文件(zip文件中包含.cert文件),并将这两个文件都附加到Dynamics CRM中的注释记录中。

下面是代码

创建.pfx文件并附加到CRM中的注释:

Entity annotationPfx = new Entity("annotation");
annotationPfx.Attributes["subject"] = "public_privatekey pfx";
annotationPfx.Attributes["filename"] = "public_privatekey.pfx";
annotationPfx.Attributes["documentbody"] = Convert.ToBase64String(cert .Export(X509ContentType.Pfx, myPassword));
annotationPfx.Attributes["mimetype"] = "application/x-pkcs12";
annotationPfx.Attributes["isdocument"] = true;
_crmServiceClient.Create(annotationPfx);

使用.pfx文件创建zip文件,并附加到CRM中的注释:

 var certVal = "-----BEGIN CERTIFICATE-----" + Environment.NewLine + Convert.ToBase64String(cert .Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) + Environment.NewLine + "-----END CERTIFICATE-----";
 byte[] certificateInBytes = System.Text.Encoding.UTF8.GetBytes(certVal);
 byte[] compressedCertInBytes;
 string certFileName = "MyCertificate.cer";
 using (var outStream = new MemoryStream())
    {
       using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
       {
           var fileInArchive = archive.CreateEntry(certFileName, CompressionLevel.Optimal);
           using (var entryStream = fileInArchive.Open())
           using (var fileToCompressStream = new MemoryStream(certificateInBytes))
            {
                fileToCompressStream.CopyTo(entryStream);
            }
        }
            compressedCertInBytes = outStream.ToArray();
    }

 Entity annotationZip = new Entity("annotation");
 annotationZip.Attributes["subject"] = "publickey zip";
 annotationZip.Attributes["filename"] = "publickey.zip";                       
 annotationZip.Attributes["documentbody"] = Convert.ToBase64String(compressedCertInBytes);
 annotationZip.Attributes["mimetype"] = "application/zip";
 annotationZip.Attributes["isdocument"] = true;

然后,我要做的是,下载zip文件,解压缩,然后将其粘贴到Xero的Private Application中。

然后,我运行我的代码以登录Xero(粘贴在下面)

var baseApiUrl = "https://api.xero.com";
var consumerKey = myConsumerKey;
var privateConsumer = new Consumer(consumerKey, consumerSecret);

certificate = new X509Certificate2(Convert.FromBase64String(retrieveBase64FromCRM), 
             myPassword, 
             X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);

var privateAuthenticator = new PrivateAuthenticator(certificate);

var privateApplicationSettings = new ApplicationSettings
{
   BaseApiUrl = baseApiUrl,
   Consumer = privateConsumer,
   Authenticator = privateAuthenticator
 };

ApplicationSettings applicationSettings = privateApplicationSettings;

if (applicationSettings.Authenticator is IAuthenticator)
{
                IXeroCoreApi myXeroApi = new XeroCoreApi(applicationSettings.BaseApiUrl, applicationSettings.Authenticator as IAuthenticator,
                applicationSettings.Consumer, User(), new DefaultMapper(), new DefaultMapper());
}

string getXeroOrgName = myXeroApi != null && !string.IsNullOrEmpty(myXeroApi.Organisation.Name.ToString()) ? myXeroApi.Organisation.Name.ToString() : string.Empty;

此代码是发生故障的地方。我收到以下错误。

我传递参数'X509KeyStorageFlags.MachineKeySet |时出错。 X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable”以获取证书

Access Denied

我收到错误访问拒绝消息。

堆栈跟踪:-

    System.Security.Cryptography.CryptographicException: Access denied.

   at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
   at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
   at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)
   at myFunctionName(Dictionary`2 myParameters)

没有这些参数,我得到的错误是

Invalid provider type specified

堆栈跟踪:

System.Security.Cryptography.CryptographicException: Invalid provider type specified.

      at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
at Xero.Api.Infrastructure.ThirdParty.Dust.RsaSha1.Sign(SHA1CryptoServiceProvider hash)
at Xero.Api.Infrastructure.ThirdParty.Dust.RsaSha1.SignCore(String baseString)
at Xero.Api.Infrastructure.OAuth.Signing.RsaSha1Signer.CreateSignature(X509Certificate2 certificate, IToken token, Uri uri, String verb, String verifier, Boolean renewToken, String callback)
at Xero.Api.Example.Applications.Private.PrivateAuthenticator.GetSignature(IConsumer consumer, IUser user, Uri uri, String verb, IConsumer consumer1)
at Xero.Api.Infrastructure.Http.HttpClient.CreateRequest(String endPoint, String method, String accept, String query)
at Xero.Api.Infrastructure.Http.HttpClient.Get(String endpoint, String query)
at Xero.Api.Infrastructure.Http.XeroHttpClient.Get[TResult,TResponse](String endPoint)
at Xero.Api.Common.XeroReadEndpoint`3.Get(String endpoint, String child)
at Xero.Api.Common.XeroReadEndpoint`3.Find()
at Xero.Api.Core.XeroCoreApi.get_Organisation()
at myFunctionName(Dictionary`2 myParameters)

但是令我惊讶的是,当我在Azure上托管此API时,它可以按预期运行,没有任何问题,并且能够登录Xero,但无法在本地计算机上对其进行调试。

如果我使用通过OpenSSL创建的证书的值,则可以调试代码,但是如果我使用以编程方式创建的证书的值,则会出错。

任何帮助,将不胜感激。

2 个答案:

答案 0 :(得分:1)

拒绝访问是因为您试图将私钥保存到计算机密钥库(MachineKeySet)中,并且不是管理员。

无效的提供程序类型是因为PFX中的私钥没有表示密钥存储提供程序,因此打开它时,将其保存在CNG(vs CAPI)中,并且Xero库使用cert.PrivateKey而不是cert.GetRSAPrivateKey()。

如果您使用的是Windows,则可以通过在CAPI中生成原始密钥来解决此问题:

CspParameters cspParams = new CspParameters
{
    KeyContainerName = Guid.NewGuid().ToString(),
};

using (var rsaCsp = new RSACryptoServiceProvider(2048, cspParams))
{
    rsaCsp.PersistKeyInCsp = false;

    // CertificateRequest stuff here
}

(或类似的方式,通过电话提交答案)

答案 1 :(得分:-1)

ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };   

以上行将帮助您解决问题

在“尝试捕获”块中,我按如下方式使用了它

try
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
                WebProxy proxy = new WebProxy("proxy.xyz.local", 81) { UseDefaultCredentials = true };
                WebRequest request = WebRequest.Create(globaConfigStatciValues.Url);
                request.Proxy = proxy;
                request.Method = "GET";
                request.Credentials = new NetworkCredential(globaConfigStatciValues.username,
                    globaConfigStatciValues.password);


                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    try
                    {
                        if (response.StatusCode == HttpStatusCode.OK)
                        {
                            isConnectionSucessfull = true;
                            tracing.Trace($" Resposne is correct  {response.StatusCode}");
                            TracingMessage += $"Resposne is correct  {response.StatusCode} \n";
                        }
                        else
                        {
                            TracingMessage += $"Response from connecting to API {response.StatusCode} \n";
                            tracing.Trace($"Response from connecting to API {response.StatusCode}");
                        }

                    }
                    catch (Exception e)
                    {
                        TracingMessage += $" In catch block {e} \n";
                        tracing.Trace($" In catch block {e}");
                        createLogRecord( e.StackTrace,TracingMessage);
                       // throw new Exception($"There was an issue with connecting to API {e.Message}");
                    }
                }



            }
            catch (Exception e)
            {
                TracingMessage += $" In catch block of PerformGetMethodtoApi {e} \n";
                tracing.Trace($" In catch block of PerformGetMethodtoApi {e}");
                createLogRecord( e.StackTrace, TracingMessage);
               // throw new Exception($"There was an issue with connecting to API {e.Message}");
            }