7

I'm trying to do a RRSIG validation, I'm trying to use the openssl lib in PHP. But I'm having a problem to pass the public key to the openssl_verify function.

This is a base code, using the Net/DNS2 library to do a DNS query with DNSSEC option. and get the DNSKEY and RRSIG.

<?php

require_once 'Net/DNS2.php';

$r = new Net_DNS2_Resolver(array('nameservers' => array('127.0.0.1')));
$r->dnssec = true;

try {
        $result = $r->query('ip4afrika.nl', 'DNSKEY');

} catch(Net_DNS2_Exception $e) {

        echo "::query() failed: ", $e->getMessage(), "\n";
        die(); // 
}

// print_r($result->answer);

$public_key_bin = base64_decode( $result->answer[0]->key ) ;
$public_key_str = $result->answer[0]->key; //echo $public_key_str; die();
// $public_key_res = openssl_x509_parse($public_key_bin);
$public_key_res = openssl_x509_read($public_key_str);
// $public_key_res = openssl_pkey_get_public($public_key_str);

while ($msg = openssl_error_string()) echo $msg . PHP_EOL;

I get this error messages,

when using:

$public_key_res = openssl_x509_read($public_key_str);

 PHP Warning:  openssl_x509_read(): supplied parameter cannot be
 coerced into an X509 certificate! in /src/Net_DNS2-1.4.3/i.php on line
 34 PHP Stack trace: PHP   1. {main}() /src/Net_DNS2-1.4.3/i.php:0 PHP 
 2. openssl_x509_read() /src/Net_DNS2-1.4.3/i.php:34 error:0906D06C:PEM routines:PEM_read_bio:no start line

so i tried adding the BEGIN/END headers

$public_key_str = '-----BEGIN CERTIFICATE-----' . PHP_EOL . $result->answer[0]->key . PHP_EOL . '-----END CERTIFICATE-----' ;

And got this error messages,

error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag
error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error
error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib

So it seems I'm feeding the function the wrong format, I'm still googling but any help would be welcome.

Eventually I like to validate the signature with:

openssl_verify($data, $signature, $public_key_res, 'RSA-SHA256');
Rabin
  • 826
  • 10
  • 21
  • Did you look @ http://php.net/manual/en/function.openssl-verify.php. They have nice examples – E_p May 15 '17 at 23:08
  • Yes I did @E_p, my problem is how to pass the key which I get from the DNS query to the function, no matter which format I try, I get error about the key format being incorrect in some way. – Rabin May 16 '17 at 06:17
  • Is it possible, that when you get key it has extra white-space or something in it that can create that issue? – E_p May 16 '17 at 16:23
  • @E_p, no extra spaces that I can see, verified by printing the key and pipe via `xxd` , look the same. Another option is that the key need to be processed before handing it to the function (maybe remove some bytes). – Rabin May 17 '17 at 08:36

2 Answers2

2

Short answer:

If you just need the capability in PHP, you can just use https://github.com/metaregistrar/php-dnssec-validator .

Long Answer:

The reason you can't load the KEY data is because it's in a slightly different format. According to rfc3110:

Field             Size
-----             ----
exponent length   1 or 3 octets (see text)
exponent          as specified by length field
modulus           remaining space

Whereas RSA public keys are a bit more complex -- aside from the exponent and modulus, you need to prefix it with the correct OID as such (2nd answer).

After that the process is a bit gnarly:

  1. Get the RRSIG record to get the signature and key tag (to determine which key to use)

  2. Use the public keys from the correct DNSKEY RR to verify the signature against.

There's also a process described here (in python)

Community
  • 1
  • 1
aljo f
  • 2,430
  • 20
  • 22
  • Thanks the 3rd link to the other SO post was very informative. also I came across the python implementation, but I didn't understand it, the last bit which define how you can determinate if it was a valid signature is very vague, also PHP have problem working with such long numbers, so that is the reason I wanted to used the build in openssl lib, which should be able to do the job. Can you help me to understand how to dissect the returned RRSIG and who it composed? – Rabin May 21 '17 at 13:39
0

PHP_EOL is platform specific, not sure what platform you're testing this code on but try replacing the constant with '\n' explicitly. See if that helps.

Jeremy Giberson
  • 1,063
  • 8
  • 15