Page 1 of 1

So überprüfen Sie die Signatur eines PSS (probabilistisches Signaturschema) Signature in C# (Tillo Webhooks)

Posted: 22 Feb 2025, 11:50
by Guest
Ich arbeite an einer Integration mit TIMLO und verwende signierte Webhooks, wie hier beschrieben. Ich brauche jedoch eine Implementierung in C# und ich habe daran gearbeitet, das zu produzieren. Ich habe es geschafft, den Code unten zu erreichen, aber ich kann die Signaturüberprüfung nicht zum Laufen bringen Machen Sie wenig Erfahrung mit dieser Art von Arbeit und müssen daher nach Anleitung wenden - ich bin zu dem Punkt, an dem ich nicht sicher bin, was ich tun muss, um dies jetzt zum Laufen zu bringen. Kann mir jemand etwas helfen? Vielen Dank.

Code: Select all

private const string TILLO_CA_CERT_URL = "https://ca.tillo.io/";

void Main()
{
var headers = new Dictionary() {
{ "webhook-id", "6b8aa749707b77c4be"  },
{ "webhook-signature", "v1a,fiU3Rd66lIFFqUP4F0/knu33LmhlJrlr+8LHkcVo5wKiLZ23c60Dodi+kAugvObr4sRX+rqOmYJ7+uENl/irhqb+OCBGnvC0ydP/Bo7wu7wFHF8JZFI1diW2fN9IC1jybKAvN+BNQoMMlL/hUceMV3HHWjLMVL742NiEXWHG9eAV7GHfdGFP0US8rJLfPbafwbqDtO+jnIAH/W0ve6jz821Ky2hFHPt1+W+qjYlBN8UC54cYTLpKTxF3ZkaC4WwWWpSXHClgjyxkXSXJ8NJzOx02fO/0RiJZYWSbp8yrURvBvrdTumSl9bQ/a11O6WBaqGASkZBmsyncng9+oa79/Kj2tEsQ/b2SeZEXEdfT28Vhnvlk4uWyWswC965jMfyCp66VJak8KakBBNtZ1gSiHPzUakQagz3bK0/5WBVdUukwx9I/cUzK3kFbTrqpvwW+PvB5MdYb1ove7FG47W3ZEQ2lvF+62NhiNPVyYzyw7y4DyRtHm6KBlZwpE2M6FE/cVmQNilCOYD2ttd99WrXskMYTH8wV3HEu9Xz34TmThQjCtHsRcMX2AmXMUJGEGCbYe//eU7xVvfr8WwUM7gIBnD92t5s8bVkN/y/uT4WIl/OsBvcipBzVFxZxxAb7oiGjPl6SaQ/f0aaa9j7+FIbh8/PIK/VNL7qUxQiM+gfdE80="},
{ "webhook-timestamp",  "1740137197"}
};
var payload = "{\"type\":\"brands.status.updated\",\"timestamp\":\"2025-02-21T11:26:34Z\",\"certificate\":\"-----BEGIN CERTIFICATE-----\\r\\nMIIGBzCCA++gAwIBAgIUCMkS5Ti+joHJ4U2y2x4IzqC+0nMwDQYJKoZIhvcNAQEL\\r\\nBQAwgZ0xFDASBgNVBAMMC1RpbGxvQ0FSb290MQswCQYDVQQGEwJHQjEPMA0GA1UE\\r\\nCAwGU3Vzc2V4MRgwFgYDVQQHDA9CcmlnaHRvbiAmIEhvdmUxDjAMBgNVBAoMBVRp\\r\\nbGxvMRYwFAYDVQQLDA1QbGF0Zm9ybSBUZWFtMSUwIwYJKoZIhvcNAQkBFhZwbGF0\\r\\nZm9ybS50ZWFtQHRpbGxvLmlvMB4XDTI0MTIxMDE1MDk0NloXDTI5MTIwOTE1MDk0\\r\\nNlowZzELMAkGA1UEBhMCR0IxDzANBgNVBAgMBlN1c3NleDEOMAwGA1UECgwFVGls\\r\\nbG8xFjAUBgNVBAsMDVBsYXRmb3JtIFRlYW0xHzAdBgNVBAMMFnRpbGxvLXdlYmhv\\r\\nb2tzLXN0YWdpbmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJf16N\\r\\nTnvyIgEg88tl7B+2ZoOsDnYTMTBf12zSRdNre5KhDYWgXQ5Bgd3dx412VSU1eoWN\\r\\nHV7494I\\/Vm1HQBNBj63uCAcivykOZttYayj4tPIv5qL4LzO2rZVzeRkJMe1bK6E9\\r\\nwoABGhLQDO9QUnxzQykPIBTjt0lE0PY1uGiJxzrn99jcDMKgM1p9AfQrJQIV3BzQ\\r\\nz27dS4vQzcIvVgqbVRt1ZPU8jlbo6HuEexOM47NVToll83T8hLJG1FzDkbJ4HyCm\\r\\n3UFEEp20fMnxMtRgipp5OttjOjfVKUHaUQEawf9B8LZM9WRxIIcQHV1LvQ0BYIRO\\r\\n5PoWd6dV9khakAPMlynHu68FnJPF5xbMaURW9mcp++s8r4OvVBP2d07jh9pkze45\\r\\nHo0TTza3F1vu2eMq72rETQhEwjeR0gAhT\\/87dJDTKgiI+jPfsh6NxH4PVsvqXl8h\\r\\nKa5cRpOOvFn0oI4OKMovuQ1FA5Q+Q9Ttj1QAnfUqj2mYm2PmIcH3ljUExjtsgfXG\\r\\nxf67neF\\/lum5ZYD0njeWqynkbEBr61VKXnCdNGfSfsgytbTeGPbrlAXlJ8Fa4JSp\\r\\nNGQOi99DDnyR1QRiVjESoqME+ps1GkZB7Za5f28fbcOb3clL9YHEo8PDmUwfsm5J\\r\\nt1CfrpUeQrI6xmX6HWkprp5yBXY63ZIEQcIUtQIDAQABo3QwcjAwBgNVHR8EKTAn\\r\\nMCWgI6Ahhh9odHRwczovL2NhLnRpbGxvLmlvL2NybC9jcmwucGVtMB0GA1UdDgQW\\r\\nBBQyNSvOXcnhPIdncEPJSdXJtZdcsjAfBgNVHSMEGDAWgBSkN2+VN1dBCA8ay0zz\\r\\nxK1dw8K+RjANBgkqhkiG9w0BAQsFAAOCAgEAEmn8EknSOTrH90b3ec1yKJ5EeHKY\\r\\nqY5OeoFS4NHWpVcJ4wpo80r+zzxFJjD4kdoUDi4fcsOh4XC8OnFk6QW0fVcJbrp3\\r\\nuSyInD19aom7FNz+qWpPdcIg2ZNsCJ64TR6NR8EjZtqjLMR4+J\\/H7Aqb+VL2mFTC\\r\\nvQlMQsmmTa6fC4IYAd8woyfPF+Y56z81hZPNNaWQhvby52bzO27kLKCJmN2eZN\\/Q\\r\\nmmNIwQZnEb8UdCoEuzS8iElPGGniB4x\\/uXwhkE9kIJhmjHhIFVm1hWTLWYO3hcmP\\r\\nWBnVjplhx3Un9i1gTXeCrmpetCEGtRoHuIFQ8BruS+XFja3eReqHuz4Dhwtd3L6y\\r\\nm+Ni2PkiVe4wTGKCD37h9FTTbKiNt1ImR07+Zpy5edG2i\\/LD3LzH00rs\\/e41IfcB\\r\\nlmxd5QuI7Cjp7kdHzGB6oMtYBawMOFIRYgfGeCNE\\/7EgSFsW6wExfEZz1hNO7Cm1\\r\\nvQe8pe9s\\/b3tGovvLZQf0F6CRBd6VtpyxztmWQRIsUNgXl3LMCnawP0JmnR6wQDi\\r\\nq9H0SIzeK52YoEFxQNnItqvNLLhjOFI1TEd16AaILPyvQaPOKOj0U4KqnBd+BR2s\\r\\njdabaA9YPN09PiTIFbONBkwq1ZyGcF9gHCiRkW6jISuc17tf5w49sdeERzDttmwi\\r\\n5qiGBh41yjM59Ks=\\r\\n-----END CERTIFICATE-----\",\"version\":1,\"data\":[{\"name\":\"Costa\",\"slug\":\"costa\",\"status\":{\"code\":\"DISABLED\",\"reason\":\"TEST\"}},{\"name\":\"Farmfoods\",\"slug\":\"farmfoods\",\"status\":{\"code\":\"DISABLED\",\"reason\":\"TEST\"}},{\"name\":\"HelloFresh\",\"slug\":\"hello-fresh\",\"status\":{\"code\":\"DISABLED\",\"reason\":\"TEST\"}},{\"name\":\"Nike\",\"slug\":\"nike-usa\",\"status\":{\"code\":\"DISABLED\",\"reason\":\"TEST\"}}]}";

var jo = JObject.Parse(payload);
var certificate = jo["certificate"].ToString();
var signingCert = new Org.BouncyCastle.X509.X509CertificateParser().ReadCertificate(Encoding.UTF8.GetBytes(certificate));

using (var httpClient = new HttpClient())
{
var caCertPem = httpClient.GetStringAsync(TILLO_CA_CERT_URL).Result;
var caCert = new Org.BouncyCastle.X509.X509CertificateParser().ReadCertificate(Encoding.UTF8.GetBytes(caCertPem));

signingCert.Verify(caCert.GetPublicKey());
signingCert.CheckValidity();

AsymmetricKeyParameter keyParams = signingCert.GetPublicKey();
var rsaKeyParams = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)keyParams;
var rsa=DotNetUtilities.ToRSA(rsaKeyParams);

string concatenatedData = $"{headers["webhook-id"]}.{headers["webhook-timestamp"]}.{payload}";

byte[] dataBytes = Encoding.UTF8.GetBytes(concatenatedData);
byte[] signature = Convert.FromBase64String(headers["webhook-signature"].Replace("v1a,",""));

bool isValid;
using (var rsaCng = new RSACng())
{
var rsaParameters = rsa.ExportParameters(false);
rsaCng.ImportParameters(rsaParameters);
isValid = rsaCng.VerifyData(dataBytes, signature, HashAlgorithmName.SHA256,  RSASignaturePadding.Pss);
}
if (!isValid) throw new Exception("isValid should be true");
}
}