2022-11-13 23:17:18 +08:00
|
|
|
using System;
|
2024-02-06 11:23:04 +08:00
|
|
|
using System.Threading;
|
|
|
|
using System.Threading.Tasks;
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
|
|
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
|
|
|
{
|
2024-02-05 10:53:59 +08:00
|
|
|
using SKIT.FlurlHttpClient.Primitives;
|
2024-02-06 11:23:04 +08:00
|
|
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Constants;
|
2023-03-30 21:40:48 +08:00
|
|
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
|
|
|
|
|
2024-01-29 23:12:37 +08:00
|
|
|
internal static class WechatTenpayClientSigningExtensions
|
2022-05-09 19:28:47 +08:00
|
|
|
{
|
2024-02-05 15:58:42 +08:00
|
|
|
public static ErroredResult VerifySignature(this WechatTenpayClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber)
|
2022-05-09 19:28:47 +08:00
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
if (client is null) throw new ArgumentNullException(nameof(client));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
2024-02-06 11:23:04 +08:00
|
|
|
CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(strSerialNumber);
|
|
|
|
if (!entry.HasValue)
|
|
|
|
{
|
|
|
|
return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate with serial number \"{strSerialNumber}\"."));
|
|
|
|
}
|
|
|
|
|
|
|
|
return GenerateSignatureResultByCertificate(
|
|
|
|
scheme: strSignScheme,
|
|
|
|
certificate: entry.Value.Certificate,
|
|
|
|
message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
|
|
|
signature: strSignature
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static async Task<ErroredResult> VerifySignatureAsync(this WechatTenpayClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber, CancellationToken cancellationToken = default)
|
|
|
|
{
|
|
|
|
if (client is null) throw new ArgumentNullException(nameof(client));
|
|
|
|
|
|
|
|
if (client.PlatformCertificateManager is not ICertificateManagerAsync)
|
|
|
|
{
|
|
|
|
// 降级为同步调用
|
|
|
|
return VerifySignature(client, strTimestamp, strNonce, strContent, strSignature, strSignScheme, strSerialNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
CertificateEntry? entry = await ((ICertificateManagerAsync)client.PlatformCertificateManager).GetEntryAsync(strSerialNumber, cancellationToken).ConfigureAwait(false);
|
|
|
|
if (!entry.HasValue)
|
|
|
|
{
|
|
|
|
return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate with serial number \"{strSerialNumber}\"."));
|
|
|
|
}
|
|
|
|
|
|
|
|
return GenerateSignatureResultByCertificate(
|
|
|
|
scheme: strSignScheme,
|
|
|
|
certificate: entry.Value.Certificate,
|
|
|
|
message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
|
|
|
signature: strSignature
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static string GenerateMessageForSignature(string timestamp, string nonce, string body)
|
|
|
|
{
|
|
|
|
return $"{timestamp}\n{nonce}\n{body}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
private static ErroredResult GenerateSignatureResultByCertificate(string scheme, string certificate, string message, string signature)
|
|
|
|
{
|
2024-02-05 15:58:42 +08:00
|
|
|
ErroredResult result;
|
|
|
|
|
2024-02-06 11:23:04 +08:00
|
|
|
switch (scheme)
|
2022-11-13 23:17:18 +08:00
|
|
|
{
|
2024-02-06 11:23:04 +08:00
|
|
|
case SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256:
|
2022-11-13 23:17:18 +08:00
|
|
|
{
|
2024-02-05 15:58:42 +08:00
|
|
|
try
|
2022-11-13 23:17:18 +08:00
|
|
|
{
|
2024-05-21 16:01:20 +08:00
|
|
|
bool valid = Utilities.RSAUtility.VerifyWithSHA256ByCertificate(
|
2024-02-06 11:23:04 +08:00
|
|
|
certificatePem: certificate,
|
|
|
|
messageData: message,
|
|
|
|
encodingSignature: new EncodedString(signature, EncodingKinds.Base64)
|
2022-11-13 23:17:18 +08:00
|
|
|
);
|
2024-02-05 15:58:42 +08:00
|
|
|
if (valid)
|
|
|
|
result = ErroredResult.Ok();
|
|
|
|
else
|
2024-02-06 11:23:04 +08:00
|
|
|
result = ErroredResult.Fail(new Exception($"Signature does not match. Maybe \"{signature}\" is an illegal signature."));
|
2022-11-13 23:17:18 +08:00
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
2024-02-05 15:58:42 +08:00
|
|
|
result = ErroredResult.Fail(ex);
|
2022-11-13 23:17:18 +08:00
|
|
|
}
|
|
|
|
}
|
2024-02-05 15:58:42 +08:00
|
|
|
break;
|
2022-11-13 23:17:18 +08:00
|
|
|
|
2024-02-06 11:23:04 +08:00
|
|
|
case SignSchemes.WECHATPAY2_SM2_WITH_SM3:
|
2022-05-09 19:28:47 +08:00
|
|
|
{
|
2024-02-05 15:58:42 +08:00
|
|
|
try
|
2022-05-09 19:28:47 +08:00
|
|
|
{
|
2024-02-05 15:58:42 +08:00
|
|
|
bool valid = Utilities.SM2Utility.VerifyWithSM3ByCertificate(
|
2024-02-06 11:23:04 +08:00
|
|
|
certificatePem: certificate,
|
|
|
|
messageData: message,
|
|
|
|
encodingSignature: new EncodedString(signature, EncodingKinds.Base64)
|
2022-11-13 23:17:18 +08:00
|
|
|
);
|
2024-02-05 15:58:42 +08:00
|
|
|
if (valid)
|
|
|
|
result = ErroredResult.Ok();
|
|
|
|
else
|
2024-02-06 11:23:04 +08:00
|
|
|
result = ErroredResult.Fail(new Exception($"Signature does not match. Maybe \"{signature}\" is an illegal signature."));
|
2022-11-13 23:17:18 +08:00
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
2024-02-05 15:58:42 +08:00
|
|
|
result = ErroredResult.Fail(ex);
|
2022-11-13 23:17:18 +08:00
|
|
|
}
|
2022-05-09 19:28:47 +08:00
|
|
|
}
|
2024-02-05 15:58:42 +08:00
|
|
|
break;
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2024-02-06 11:23:04 +08:00
|
|
|
result = ErroredResult.Fail(new Exception($"Unsupported signing scheme: \"{scheme}\"."));
|
2022-05-09 19:28:47 +08:00
|
|
|
}
|
2024-02-05 15:58:42 +08:00
|
|
|
break;
|
2022-05-09 19:28:47 +08:00
|
|
|
}
|
2024-02-05 15:58:42 +08:00
|
|
|
|
|
|
|
return result;
|
2022-05-09 19:28:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|