我正在尝试在 Graph API 中创建订阅,并且正在考虑尝试包含资源数据。我一直在阅读这个 Microsoft 文档,尝试在代码中创建密钥,并提出了以下代码,该代码是在 这个堆栈溢出答案的帮助下创建的:
using var rsa = RSA.Create(4096);
var certificateRequest = new CertificateRequest("CN=testCertificate", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
// Make sure the key can only be used for encryption purposes
certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.EncipherOnly, true));
var selfSignedCertificate = certificateRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1));
using var exportedCertificate = new X509Certificate2(selfSignedCertificate.Export(X509ContentType.Pfx));
var x509PublicKey = Convert.ToBase64String(exportedCertificate.GetPublicKey());
var rsaPrivateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey());
我已经尝试过:
X509KeyUsageExtension
X509ContentType.Cert
并将其用作公钥创建此证书后,我将使用以下代码尝试创建订阅:
var requestBody = new Subscription
{
ChangeType = "created,updated",
NotificationUrl = _notificationUrl,
LifecycleNotificationUrl = _lifecycleUrl,
Resource = resource,
ExpirationDateTime = DateTime.UtcNow.AddDays(3),
ClientState = _clientState,
IncludeResourceData = true,
EncryptionCertificate = x509PublicKey,
EncryptionCertificateId = certificateId
};
graphClient.Subscriptions.PostAsync(requestBody, cancellationToken: cancellationToken);
如果我删除
includeResourceData
、EncryptionCertificate
和 EncryptionCertificateId
,则此方法有效,但如果没有,我将收到 HTTP 400 响应:
证书验证错误:找不到请求的对象。
如果有人有任何关于如何解决此错误的想法或示例,我们将不胜感激。
我找到了问题的关键以及为什么这不起作用。在对如何执行此操作进行了更多研究之后,我在一些示例代码中找到了 README 文件,其中更详细地介绍了 Microsoft 的期望。本自述文件的关键部分在最后指出:
复制-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----之间的内容。这将是 appsettings.json 文件中 Base64EncodedCertificate 的值。Microsoft 文档以 Base64 编码的 X.509 格式导出证书,并仅包含公钥在深入研究代码和返回的内容后,我注意到证书中的公钥是与证书本身不同的 base64 字符串,证书本身包含公钥。回顾
我误解了他们的要求,并假设他们只想要证书制作过程中的公钥。
此后唯一的问题是如何提取证书的 base64 内容,并且我在
X509Certificate2
类中没有找到任何有用的方法来执行此操作,因此我编写了一个小辅助方法来对此进行排序:
private const string _beginCertificate = "-----BEGIN CERTIFICATE-----\n";
private const string _endCertificate = "\n-----END CERTIFICATE-----";
/// <summary>
/// Extract the base64 certificate without the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- strings.
/// </summary>
/// <returns>
/// The base64 contents of the X509 certificate provided
/// </returns>
private static string ExtractBase64Certificate(string x509CertificatePemString)
{
var indexFrom = x509CertificatePemString.IndexOf(_beginCertificate, StringComparison.OrdinalIgnoreCase) + _beginCertificate.Length;
var indexTo = x509CertificatePemString.LastIndexOf(_endCertificate, StringComparison.OrdinalIgnoreCase);
return x509CertificatePemString.Substring(indexFrom, indexTo - indexFrom);
}
使用它来提取证书,我已经能够通过“证书验证错误”并创建订阅。我已经整理了原始问题中的代码,以确保证书只能执行所需的操作,因此代码现在如下所示:
using var rsa = RSA.Create(4096);
var certificateRequest = new CertificateRequest("CN=testCertificate", rsa, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
// Make sure the key can only be used for encryption purposes
certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.EncipherOnly, true));
var selfSignedCertificate = certificateRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1));
using var exportedCertificate = new X509Certificate2(selfSignedCertificate.Export(X509ContentType.Cert));
var x509PublicKey = Convert.ToBase64String(exportedCertificate.GetPublicKey());
var rsaPrivateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey());
此更新后的代码有两个关键事项需要注意:
微软接受使用SHA512作为哈希算法,所以最好使用这个。我不确定他们是否会使用 SHA3_512,但我的机器无法使用此哈希算法,所以我坚持使用 SHA_512。
X509ContentType.Cert