Digitale ondertekening IMKL-pakket
Om het risico op verlies van integriteit van plannen te beperken, kan je optioneel een digitale handtekening plaatsen op je IMKL-bestanden. Dit is een mature en wijdverspreide state-of-the-art technologie. Het plaatsen van een digitale handtekening op het IMKL-bestand is optioneel.
Een digitale handtekening garandeert integriteit en authenticiteit van de IMKL-bestanden
IMKL-bestanden zijn zip-bestanden en worden als geheel ondertekend.
De aanwezigheid én controle van een digitale handtekening op het IMKL-bestand garandeert de non-repudiation (niet-weerlegbaarheid) van de KLB met betrekking tot de correct afgeleverde plannen.
Deze controle werkt end-to-end: van bij de KLB tot in het IMKL-archief. Ze is onafhankelijk van de onderliggende transporttechnologie (zoals HTTPS) en compenseert dus ook mogelijke – al dan niet nog onbekende – kwetsbaarheden in het transportprotocol volgens het defense-in-depth-principe.
Ontvangstbevestiging door Athumi
De aanwezigheid van een digitale handtekening levert op zich nog geen bewijs dat Athumi de doorgestuurde plannen effectief correct heeft ontvangen.
Om de ketting sluitend te maken, is een door Athumi digitaal ondertekende ontvangstbevestiging nodig. Daarom ondertekent Athumi het validatierapport van een digitaal ondertekend IMKL-bestand op zijn beurt digitaal.
Een positief validatierapport wordt zo een cryptografisch “ontvangstbewijs” (ook wel message disposition notification genoemd).
Dit ontvangstbewijs:
Bevat de datum en het exacte tijdstip van ontvangst (UTC)
Vormt een bijkomende garantie dat het IMKL-bestand niet achteraf werd vervangen
Biedt extra bescherming tegen antedateren
In feite wordt hiermee het principe van een aangetekend schrijven in digitale vorm toegepast.
Athumi neemt in het validatierapport op:
De cryptografische hash (SHA-256) van het IMKL-bestand
Het tijdstip (UTC) van ontvangst
Een digitale handtekening op het validatierapport
Controle door de KLB
Wil je als KLB cryptografische zekerheid over:
de integriteit van het transport, en
het opgeslagen IMKL-document,
dan kan je:
De hash vergelijken met de hash die je zelf berekende vóór verzending
De digitale handtekening van Athumi valideren
Heb je het IMKL-bestand zelf digitaal ondertekend? Dan hoef je in principe de hash niet meer te vergelijken. De ondertekende bevestiging dat Athumi jouw handtekening heeft gevalideerd, kan dan volstaan.
Digitale ondertekening van het IMKL-pakket
Digitale ondertekening is optioneel. De digitale ondertekening van het IMKL-pakket gebeurt volgens het RSA-algoritme en de SHA-256-hashfunctie. Cfr http://en.wikipedia.org/wiki/RSA_(cryptosystem) .
Een digitaal ondertekend IMKL-pakket bestaat uit een zip-bestand met daarin:
Eén tekstbestand met de signature (base64-gecodeerde geëncrypteerde hash) (*.txt)
Eén X.509-certificaat met de publieke sleutel van het certificaat dat gebruikt werd om de hash te encrypteren (*.cer).
Eén IMKL-pakket (*.zip)
De naam van de bestanden (met uitzondering van de bestandsextensie) is vrij te kiezen.
Voorbeeld van een digitaal ondertekend IMKL-pakket:

Controle van het certificaat
Athumi controleert de geldigheid van het gebruikte certificaat.
Daarvoor bezorg je als KLB de publieke sleutels van het root-certificaat en van eventuele tussenliggende certificaten aan Athumi. Dat kan via e-mail naar klip@athumi.eu.
Self-signed certificaten zijn niet toegelaten.
Daarnaast vergelijkt Athumi het subject van het gebruikte certificaat met het subject dat je invult op de profielpagina.
Ontbreekt het subject op de profielpagina?
Of wijkt het subject af van het subject in het IMKL-pakket?
Dan zal het IMKL-pakket niet valideren.

Je vindt het subject van het certificaat in de gedetailleerde eigenschappen van het certificaat.

Voorbeeld code (C#)
Voor het berekenen van de base64-gecodeerde gesignde SHA-256-hash van een IMKL-pakket. Deze waarde komt in het *.txt bestand:
public class ImklSigner
{
public string Sign(byte[] zip, X509Certificate2 cert)
{
using (var rsa = (RSACryptoServiceProvider)cert.PrivateKey)
{
return Convert.ToBase64String(rsa.SignData(zip, "SHA256"));
}
}
}
Digitale ondertekening van het validatierapport
De validatierapporten van IMKL-pakketten worden door Athumi digitaal ondertekend.
Zo’n validatierapport bevat:
Het tijdstip van ontvangst (UTC)
De cryptografische hash van het opgeladen IMKL-pakket
Een KLB kan een validatierapport opvragen via volgende URI: ws/klip/v2/Imkl/Report/MapRequest/{mapRequestId}/UnaZone/{unaZoneId}
Ondertekening van XML-rapporten
Een validatierapport in XML wordt digitaal ondertekend volgens het XML-DSig-principe. Cfr. http://en.wikipedia.org/wiki/XML_Signature.
Er bestaat momenteel nog geen internationale standaard voor het digitaal ondertekenen van JSON-berichten. Daarom heeft Athumi hiervoor een eigen formaat gedefinieerd.
Voorbeeld van een digitaal ondertekend validatierapport in XML:
<ImklReport xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://api.agiv.be/ws/klip/v1">
<DateReceived>2015-10-26T08:43:20.107Z</DateReceived>
<SignatureValue>XtOnuzGYsVmqUFmXbRg3zKXs6/6lkivNERBNfEB3MrMi0iUE97xB+KwDcA1DaCmV7f9XfOWQkyBVKyyYuf2BhHoe2y8gNW8rQlr42VpuCBlnHZ/oYDWvD/rbkYbosc3sPVikh83a9qhy+BaNuRDB53TmK1C4y6kCaoVNe1Ip0qjn2tUY5TvuzePoif91qxT+VLaVxS7TAuwT97bf0iljHi6naVCt22KPCD/VfQjM5Z2lNCFaLAWYpXz6Xgwg6xnduhQCjOW11H2mNgvt1Ou/gFm1b/cw7VvCDNkIIwwRZ+tRTCDiJU1Sbjh+jpKUOdsJI9h1Ig+E3eDv+9ZloZbe8A==</SignatureValue>
<CertificateThumbprint>2081c1d735b2f224d61c13f7e29e3b056afa2529</CertificateThumbprint>
<MapRequestId>1a540b0f-8536-47d2-90af-28333be7ab66</MapRequestId>
<ZoneId>e444932b-4a04-4aed-bdf7-2e1f70d47cab</ZoneId>
<Status>https://klip.vlaanderen.be/api/cl/klip/v2/ImklStatus/datavalid</Status>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>qVmokZ+v9HWvkti/NABuQpwsIj3nf1mNsc9ymCDRjjc=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>YMH3hEPHL8sH1sgyjsjmxeCGOJhJW0kyNxAFyK8kOQSS9WBeDi7Oa7GNgY2dEGhaWf3ijrYJzKNzOTki+0CCbc2OHNSSmlRmcTJrlgmjqUzjhY6+pFJt3gTEh1d+fKwVW3tv0bTNKb4eMg1WO3XGf/hTEh6pqvkqaoIjAoput/GDts69iGvhuTI6cWC2rmJlJOMkYTU2rEPGLwuypRAomobmgp1TrS1vRvYG9Q/sRIGLJDmAegyGgmxEfjDRd0DDvRKCQuXtcRZNvGyZ5S3wyvdC3yR/5RAIFsk5XW9fo9/NkDSgHyK/EKA99oRZidXwcTxZfD8ZycFhquSPlLKT4Q==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</ImklReport>
Voorbeeld van een digitaal ondertekend validatierapport in JSON:
{
"DateReceived" : "2015-10-26T08:43:20.107Z",
"SignatureValue" : "XtOnuzGYsVmqUFmXbRg3zKXs6/6lkivNERBNfEB3MrMi0iUE97xB+KwDcA1DaCmV7f9XfOWQkyBVKyyYuf2BhHoe2y8gNW8rQlr42VpuCBlnHZ/oYDWvD/rbkYbosc3sPVikh83a9qhy+BaNuRDB53TmK1C4y6kCaoVNe1Ip0qjn2tUY5TvuzePoif91qxT+VLaVxS7TAuwT97bf0iljHi6naVCt22KPCD/VfQjM5Z2lNCFaLAWYpXz6Xgwg6xnduhQCjOW11H2mNgvt1Ou/gFm1b/cw7VvCDNkIIwwRZ+tRTCDiJU1Sbjh+jpKUOdsJI9h1Ig+E3eDv+9ZloZbe8A==",
"CertificateThumbprint" : "2081c1d735b2f224d61c13f7e29e3b056afa2529",
"MapRequestId" : "1a540b0f-8536-47d2-90af-28333be7ab66",
"ZoneId" : "e444932b-4a04-4aed-bdf7-2e1f70d47cab",
"Status" : "https://klip.vlaanderen.be/api/cl/klip/v2/ImklStatus/datavalid",
"Signature" : {
"SignedInfo" : {
"SignatureMethod" : {
"Algorithm" : "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
}
},
"SignatureValue" : "DbaSpEWOoestxKrZXcyX1r8WRd/yUnBy3ltPiwcJbAZT9Xt9abHlI/MKha8dCTJs7mATfiEED8LpIbAjGoRqtyLE5ASAGjR6bJKCGqkgmlD1B7A6tPJ+xkP3gt/doASjAFdKeEpFNTAFXdL5ZTn6rzmRQWW3Xmt0ZDeECVGUQnge7p9SRiOM/2yieRp3NJCSfG/JzhYv5JorY0Tgoaowfa5Hqsyw+8Nv+q7F7wwzdatovELZwfdOm9yuU9FUj8hoA5qevKAt8dP5wtmWoNjEXYwQgHw+/BXDcGlOJHnG9QctwtqEw+j+lsbLXWy3MoWQ0HP5iH6qlN2OgqwzH/7brw==",
"KeyInfo" : {
"X509Data" : {
"X509Certificate" : "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"
}
}
}
}
Voorbeeld code (C#) voor het verifiëren van een digitaal ondertekend XML-bericht:
namespace Gisvl.Klipdf.ImklReportSignatureVerifier
{
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Xml;
using System.Xml.Linq;
public class XmlSignatureVerifier
{
public bool IsValid(string xml)
{
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
var xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = false;
xmlDocument.LoadXml(xml);
var signedXml = new SignedXml(xmlDocument);
var nodeList = xmlDocument.GetElementsByTagName("Signature");
// assert that there is only one Signature element
if (nodeList.Count != 1)
{
return false;
}
// Load the signature node.
var element = (XmlElement)nodeList[0];
signedXml.LoadXml(element);
// get the public key
var xelement = XElement.Parse(element.OuterXml);
XNamespace ns = "http://www.w3.org/2000/09/xmldsig#";
var certificate = xelement.Descendants(ns + "X509Certificate").Single();
var binaryCertData = Convert.FromBase64String(certificate.Value);
var cert = new X509Certificate2(binaryCertData);
// assert that the reference uri is an empty string
var uri = xelement.Descendants(ns + "Reference").Single().Attribute("URI");
if (!string.IsNullOrEmpty(uri.Value))
{
return false;
}
// assert that the certificate is not expired
var notBefore = cert.NotBefore;
var notAfter = cert.NotAfter;
if (DateTime.Now < notBefore || DateTime.Now > notAfter)
{
return false;
}
// assert that the certificate is an Informatie Vlaanderen certificate (beta: 2081C1D735B2F224D61C13F7E29E3B056AFA2529 ; production: D5D39A8C82FD1D68B5D86FBE94ED96AC8F8F9953)
if (cert.Thumbprint != "2081C1D735B2F224D61C13F7E29E3B056AFA2529")
{
return false;
}
// Verify the signature and if certificate is valid and not revoked and return the result
return signedXml.CheckSignature(cert, true);
}
}
}
namespace Gisvl.Klipdf.ImklReportSignatureVerifier
{
using System;
using System.Security.Cryptography;
public sealed class RSAPKCS1SHA256SignatureDescription : SignatureDescription
{
public RSAPKCS1SHA256SignatureDescription()
{
KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
DigestAlgorithm = typeof(SHA256Managed).FullName;
FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName;
DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName;
}
public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
var deformatter = new RSAPKCS1SignatureDeformatter(key);
deformatter.SetHashAlgorithm("SHA256");
return deformatter;
}
public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
var formatter = new RSAPKCS1SignatureFormatter(key);
formatter.SetHashAlgorithm("SHA256");
return formatter;
}
}
}
namespace Gisvl.Klipdf.ImklReportSignatureVerifier
{
using NUnit.Framework;
public class XmlSignatureVerifierTest
{
[Test]
public void Test()
{
const string xml = "<imklreport xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://api.agiv.be/ws/klip/v1\"><datereceived>2015-10-26T08:43:20.107Z</datereceived><signaturevalue>XtOnuzGYsVmqUFmXbRg3zKXs6/6lkivNERBNfEB3MrMi0iUE97xB+KwDcA1DaCmV7f9XfOWQkyBVKyyYuf2BhHoe2y8gNW8rQlr42VpuCBlnHZ/oYDWvD/rbkYbosc3sPVikh83a9qhy+BaNuRDB53TmK1C4y6kCaoVNe1Ip0qjn2tUY5TvuzePoif91qxT+VLaVxS7TAuwT97bf0iljHi6naVCt22KPCD/VfQjM5Z2lNCFaLAWYpXz6Xgwg6xnduhQCjOW11H2mNgvt1Ou/gFm1b/cw7VvCDNkIIwwRZ+tRTCDiJU1Sbjh+jpKUOdsJI9h1Ig+E3eDv+9ZloZbe8A==</signaturevalue><certificatethumbprint>2081c1d735b2f224d61c13f7e29e3b056afa2529</certificatethumbprint><maprequestid>1a540b0f-8536-47d2-90af-28333be7ab66</maprequestid><zoneid>e444932b-4a04-4aed-bdf7-2e1f70d47cab</zoneid><status>https://klip.vlaanderen.be/api/cl/klip/v2/ImklStatus/datavalid</status><signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><signedinfo><canonicalizationmethod algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\" /><signaturemethod algorithm=\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\" /><reference uri=\"\"><transforms><transform algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\" /></transforms><digestmethod algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\" /><digestvalue>qVmokZ+v9HWvkti/NABuQpwsIj3nf1mNsc9ymCDRjjc=</digestvalue></reference></signedinfo><signaturevalue>YMH3hEPHL8sH1sgyjsjmxeCGOJhJW0kyNxAFyK8kOQSS9WBeDi7Oa7GNgY2dEGhaWf3ijrYJzKNzOTki+0CCbc2OHNSSmlRmcTJrlgmjqUzjhY6+pFJt3gTEh1d+fKwVW3tv0bTNKb4eMg1WO3XGf/hTEh6pqvkqaoIjAoput/GDts69iGvhuTI6cWC2rmJlJOMkYTU2rEPGLwuypRAomobmgp1TrS1vRvYG9Q/sRIGLJDmAegyGgmxEfjDRd0DDvRKCQuXtcRZNvGyZ5S3wyvdC3yR/5RAIFsk5XW9fo9/NkDSgHyK/EKA99oRZidXwcTxZfD8ZycFhquSPlLKT4Q==</signaturevalue><keyinfo><x509data><x509certificate>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</x509certificate></x509data></keyinfo></signature></imklreport>";
var verifier = new XmlSignatureVerifier();
Assert.IsTrue(verifier.IsValid(xml));
}
}
}
Voorbeeld code (C#) voor het verifiëren van een digitaal ondertekend JSON-bericht:
namespace Gisvl.Klipdf.ImklReportSignatureVerifier
{
using Newtonsoft.Json.Linq;
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
public class JsonSignatureVerifier
{
public bool IsValid(string json)
{
var jObject = JObject.Parse(json);
// get the public key
var certToken = jObject.SelectToken("Signature.KeyInfo.X509Data.X509Certificate");
var binaryCertData = Convert.FromBase64String(certToken.Value<string>());
var cert = new X509Certificate2(binaryCertData);
// assert that the certificate is not expired
var notBefore = cert.NotBefore;
var notAfter = cert.NotAfter;
if (DateTime.Now < notBefore || DateTime.Now > notAfter)
{
return false;
}
// assert that the certificate is an AIV certificate (beta: 2081C1D735B2F224D61C13F7E29E3B056AFA2529 ; production: D5D39A8C82FD1D68B5D86FBE94ED96AC8F8F9953)
if (cert.Thumbprint != "2081C1D735B2F224D61C13F7E29E3B056AFA2529")
{
return false;
}
// verify if the certificate is valid and not revoked
if (!cert.Verify())
{
return false;
}
// get the signature
var signatureToken = jObject.SelectToken("Signature.SignatureValue");
var signature = signatureToken.Value<string>();
// remove the signature element
jObject.Remove("Signature");
var strippedjson = jObject.ToString(Newtonsoft.Json.Formatting.None);
// verify
using (var rsa = (RSACryptoServiceProvider)cert.PublicKey.Key)
{
return rsa.VerifyData(Encoding.UTF8.GetBytes(strippedjson), "SHA256", Convert.FromBase64String(signature));
}
}
}
}
namespace Gisvl.Klipdf.ImklReportSignatureVerifier
{
using NUnit.Framework;
public class JsonSignatureVerifierTest
{
[Test]
public void Test()
{
const string json = "{\"DateReceived\":\"2015-10-26T08:43:20.107Z\",\"SignatureValue\":\"XtOnuzGYsVmqUFmXbRg3zKXs6/6lkivNERBNfEB3MrMi0iUE97xB+KwDcA1DaCmV7f9XfOWQkyBVKyyYuf2BhHoe2y8gNW8rQlr42VpuCBlnHZ/oYDWvD/rbkYbosc3sPVikh83a9qhy+BaNuRDB53TmK1C4y6kCaoVNe1Ip0qjn2tUY5TvuzePoif91qxT+VLaVxS7TAuwT97bf0iljHi6naVCt22KPCD/VfQjM5Z2lNCFaLAWYpXz6Xgwg6xnduhQCjOW11H2mNgvt1Ou/gFm1b/cw7VvCDNkIIwwRZ+tRTCDiJU1Sbjh+jpKUOdsJI9h1Ig+E3eDv+9ZloZbe8A==\",\"CertificateThumbprint\":\"2081c1d735b2f224d61c13f7e29e3b056afa2529\",\"MapRequestId\":\"1a540b0f-8536-47d2-90af-28333be7ab66\",\"ZoneId\":\"e444932b-4a04-4aed-bdf7-2e1f70d47cab\",\"Status\":\"https://klip.vlaanderen.be/api/cl/klip/v2/ImklStatus/datavalid\",\"Signature\":{\"SignedInfo\":{\"SignatureMethod\":{\"Algorithm\":\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\"}},\"SignatureValue\":\"DbaSpEWOoestxKrZXcyX1r8WRd/yUnBy3ltPiwcJbAZT9Xt9abHlI/MKha8dCTJs7mATfiEED8LpIbAjGoRqtyLE5ASAGjR6bJKCGqkgmlD1B7A6tPJ+xkP3gt/doASjAFdKeEpFNTAFXdL5ZTn6rzmRQWW3Xmt0ZDeECVGUQnge7p9SRiOM/2yieRp3NJCSfG/JzhYv5JorY0Tgoaowfa5Hqsyw+8Nv+q7F7wwzdatovELZwfdOm9yuU9FUj8hoA5qevKAt8dP5wtmWoNjEXYwQgHw+/BXDcGlOJHnG9QctwtqEw+j+lsbLXWy3MoWQ0HP5iH6qlN2OgqwzH/7brw==\",\"KeyInfo\":{\"X509Data\":{\"X509Certificate\":\"MIIF+TCCA+GgAwIBAgIOAQAAAAABSR5mwERBAI0wDQYJKoZIhvcNAQELBQAwNjELMAkGA1UEBhMCQkUxFjAUBgNVBAMTDUdvdmVybm1lbnQgQ0ExDzANBgNVBAUTBjIwMTQwMjAeFw0xNDEwMTcxMzU4MTBaFw0yMDAxMTcxMzU4MTBaMIGkMSIwIAYDVQQDDBlrbGlwLnNpZ25pbmcuYWdpdi5iZS9iZXRhMQswCQYDVQQGEwJCRTEfMB0GCSqGSIb3DQEJARYQc2VjdXJpdHlAYWdpdi5iZTENMAsGA1UEBwwER2VudDEYMBYGA1UECAwPT29zdC1WbGFhbmRlcmVuMRIwEAYDVQQLDAlJVC1EaWVuc3QxEzARBgNVBAoMCjA4ODE3NDY1MjkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMR4iZqa/ba/ljL5hYdDgh2d682yEVy1zb2WP0MAkM5bTWvnmNagtT5B3ZWsayyCmmfL6vhbQ/Koa6rP2O+3K83Ng3uCb389HdAaspPXM6QukLhbCuF73HEqMBFs5wGBpzwcTC4XDKpSLi9CD3S96sLknXj0r8RbMw3WxZPGuOhhZoQb9WUs9aNYXV3oxBY3QvEdmajEMgmeEb/8w4WMt2fN5JBRCCeovhL5NbmmkfKCfQsx7uocXA+qvD7J5P8Vp+NSOz3T3HSv3XF+znpk5fe4UrqJMf06k63v4hPQ24/SAvmI74egZshy5ye1rDL04Z1X+0o2XcJLtnBdQ8rx5jAgMBAAGjggGUMIIBkDAfBgNVHSMEGDAWgBSO6Dkuol6Mul/B7QIppc9Aw7mbujBwBggrBgEFBQcBAQRkMGIwNgYIKwYBBQUHMAKGKmh0dHA6Ly9jZXJ0cy5wa2kuYmVsZ2l1bS5iZS9iZWxnaXVtcnM0LmNydDAoBggrBgEFBQcwAYYcaHR0cDovL29jc3AucGtpLmJlbGdpdW0uYmUvMjAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYHYDgMAQEDAzAuMCwGCCsGAQUFBwIBFiBodHRwOi8vcmVwb3NpdG9yeS5wa2kuYmVsZ2l1bS5iZTA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLnBraS5iZWxnaXVtLmJlL2dvdmVybm1lbnQyMDE0MDIuY3JsMA4GA1UdDwEB/wQEAwIE8DARBglghkgBhvhCAQEEBAMCBLAwHQYDVR0OBBYEFAJAEZ2JWVM1qboizHpo7jAqzyuEMCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQwDQYJKoZIhvcNAQELBQADggIBAB5aQzbgSTIH7zoPOI/JTNhSIXj7UHWs1dmow2AXgtoPToJR4/qq++/mMoHFM0R79xPrQuWrnkMKcuhsemrc21XzmSvA1FYYcCjrXHrSnffesCF1yb2g/2JiPlOYjWYeNCD279brnL0vEoMFXwGyGMvTh0lKiB3uO1R0MLhmdMkavi6iQ2XDTO/RC1lgC4x8gcPituldM7mrbxwNbnYV3VP063AmeA9vgwrgqbhbTLrE5rVZ1PbS0EBtoiTLIhUSLIsY+CQf2MNMHR00gwnv8cUSErO4te5oJEWjKiGd0aiSW6wbbVJSzn97kafmk/lB7/ZiEKyl0xYHJ+8cegSRxPkQN1VvHIj8WhO5zLpMxRh0xfW5XIo0yPLCMBz1PDMlWQOk7LHE81DqpzJgwifuHSGlnuLNwmSmYr6ntBA9Y/9gKkBHtmrLa5c3UYJ3QdGEE3aXQ+WKwZT6B+YkPAKH+LPH0MSeI6Gu7YeSHbe3Znczl2e88unlWt4uy/kGURaG5bPwlv3g4lU2R62kSK/EyrNG3wSItfODEocgjJwoP62RydOhqrugRMDulPVREyXWVyWWQng3V0vxbeXyeeOfonXzFaDSQh7Yx1H+44FukCbhtDH/fqYuy52QprllinNaSTjC7aA0CKKWmDaCOdeaQZ/TBCwJJt/XCJoTfDUVgOdU\"}}}}";
var verifier = new JsonSignatureVerifier();
Assert.IsTrue(verifier.IsValid(json));
}
}
}