Closed sennz closed 2 years ago
Hi! sorry but the sdk only works with European Digital Certificate specification. The NZ cert starts with a different string scheme (NZCP:/ instead of HC1:), uses a different base (base32 instead of base45) and has a different payload structure. You can check your CoseSign1 error with the CBOR library (here an example https://github.com/Spomky-Labs/cbor-php/issues/32).
i did some check with the NZ specs. the problem was that the NZ certificate is not compressed, if you use that code it works and extract the data (I tested the first qrcode on the detail page):
composer require christian-riesen/base32
composer require spomky-labs/cbor-php
<?php
use CBOR\ByteStringObject;
use CBOR\CBORObject;
use CBOR\Decoder;
use CBOR\ListObject;
use CBOR\OtherObject\OtherObjectManager;
use CBOR\StringStream;
use CBOR\Tag\TagObjectManager;
use CBOR\TagObject as Base;
use Base32\Base32;
require_once 'vendor/autoload.php';
$data = 'NZCP:/1/2KCEVIQEIVVWK6JNGEASNICZAEP2KALYDZSGSZB2O5SWEOTOPJRXALTDN53GSZBRHEXGQZLBNR2GQLTOPICRUYMBTIFAIGTUKBAAUYTWMOSGQQDDN5XHIZLYOSBHQJTIOR2HA4Z2F4XXO53XFZ3TGLTPOJTS6MRQGE4C6Y3SMVSGK3TUNFQWY4ZPOYYXQKTIOR2HA4Z2F4XW46TDOAXGG33WNFSDCOJONBSWC3DUNAXG46RPMNXW45DFPB2HGL3WGFTXMZLSONUW63TFGEXDALRQMR2HS4DFQJ2FMZLSNFTGSYLCNRSUG4TFMRSW45DJMFWG6UDVMJWGSY2DN53GSZCQMFZXG4LDOJSWIZLOORUWC3CTOVRGUZLDOSRWSZ3JOZSW4TTBNVSWISTBMNVWUZTBNVUWY6KOMFWWKZ2TOBQXE4TPO5RWI33CNIYTSNRQFUYDILJRGYDVAYFE6VGU4MCDGK7DHLLYWHVPUS2YIDJOA6Y524TD3AZRM263WTY2BE4DPKIF27WKF3UDNNVSVWRDYIYVJ65IRJJJ6Z25M2DO4YZLBHWFQGVQR5ZLIWEQJOZTS3IQ7JTNCFDX';
$decoded = Base32::decode(mb_substr($data, 8)); // We remove the NZCP: prefix and the version /1/
$stream = new StringStream($decoded);
final class CoseSign1Tag extends Base // Specific tag for the example
{
public static function getTagId(): int
{
return 18;
}
public static function createFromLoadedData(int $additionalInformation, ?string $data, CBORObject $object): Base
{
return new self($additionalInformation, $data, $object);
}
public function getNormalizedData(bool $ignoreTags = false)
{
return $this->getValue()->getNormalizedData($ignoreTags);
}
}
$tagObjectManager = new TagObjectManager();
$tagObjectManager->add(CoseSign1Tag::class);
$cborDecoder = new Decoder($tagObjectManager, new OtherObjectManager());
$cbor = $cborDecoder->decode($stream); //We decode the data
if (!$cbor instanceof CoseSign1Tag) {
throw new InvalidArgumentException('Not a valid certificate. Not a CoseSign1 type.');
}
$list = $cbor->getValue();
if (!$list instanceof ListObject) {
throw new InvalidArgumentException('Not a valid certificate. No list.');
}
if ($list->count() !==4) {
throw new InvalidArgumentException('Not a valid certificate. The list size is not correct.');
}
$firstItem = $list->get(0); // The first item corresponds to the protected header
$headerStream = new StringStream($firstItem->getValue()); // The first item is also a CBOR encoded byte string
dump('Protected header', $cborDecoder->decode($headerStream)->getNormalizedData()); // The array [1 => "-7"] = ["alg" => "ES256"]
$secondItem = $list->get(1); // The second item corresponds to unprotected header
dump('Unprotected header', $secondItem->getNormalizedData()); // The index 4 refers to the 'kid' (key ID) parameter (see https://www.iana.org/assignments/cose/cose.xhtml)
$thirdItem = $list->get(2); // The third item corresponds to the data we want to load
if (!$thirdItem instanceof ByteStringObject) {
throw new InvalidArgumentException('Not a valid certificate. The payload is not a byte string.');
}
$infoStream = new StringStream($thirdItem->getValue()); // The third item is a CBOR encoded byte string
dump('The payload', $cborDecoder->decode($infoStream)->getNormalizedData()); // The data we are looking for
$fourthItem = $list->get(3); // The fourth item is the signature.
// It can be verified using the protected header (first item) and the data (third item)
// And the public key
if (!$fourthItem instanceof ByteStringObject) {
throw new InvalidArgumentException('Not a valid certificate. The signature is not a byte string.');
}
dump('Digital signature', $fourthItem->getNormalizedData()); // The digital signature
function dump($title, $list)
{
echo "<h1>$title</h1><pre>" . print_r($list, true) . "</pre>";
}
?>
Thank you for the quick update.
I know this is closed but @sennz, have you worked out how to verify the signature?
I know this is closed but @sennz, have you worked out how to verify the signature?
Not yet, I couldn't verify the digital signature with the public key.
I know this is closed but @sennz, have you worked out how to verify the signature?
Not yet, I couldn't verify the digital signature with the public key.
All the methods I've seen require a PEM but the libraries I found only support converting RSA public keys from JWK to PEM.
I know this is closed but @sennz, have you worked out how to verify the signature?
Not yet, I couldn't verify the digital signature with the public key.
All the methods I've seen require a PEM but the libraries I found only support converting RSA public keys from JWK to PEM.
Yes, I found a library, but I didn't have time to check https://web-token.spomky-labs.com/
Hi Thanks for the SDK, I try to use your code to NZ verification, but i am getting "Not a valid certificate. Not a CoseSign1 type" error. Details are below https://nzcp.covid19.health.nz/#example-resolving-an-issuers-identifier-to-their-public-keys I have decoded the string to hex, next step fails "Not a valid certificate. Not a CoseSign1 type" What am I doing wrong? Thanks