openssl_verify and "error:0906D06C:PEM routines:PEM_read_bio:no start line"

23,566

Solution 1

Have you tried to call openssl_verify() with a (maybe self-signed) certificate containing your public key instead of a pure public key ?

As far as I know, some PHP OpenSSL functions do not properly support naked public keys although it seems strange that it does verify correctly in spite of the error.

<?php
$private = openssl_pkey_get_private(file_get_contents('private'), 'passphrase');

// This causes the "no start line" error when using a naked public key:
$public  = openssl_pkey_get_public(file_get_contents('public')); // <-- this should be cert

echo openssl_error_string()."\n";

openssl_sign('Test', $sig, $private);
var_dump(openssl_verify('Test', $sig, $public));

echo openssl_error_string()."\n";
?>

Example for converting a public key to a simple certificate in a Linux/UNIX shell such as bash (refer to the OpenSSL documentation or some tutorials for more):

# Create certificate request
openssl req -new -days 3600 -key [PRIVATE-KEY-FILE] -out [REQUEST-TMP-FILE]

# Create certificate from request
RANDFILE=[RANDOM-TMP-FILE] openssl x509 -req -in [REQUEST-TMP-FILE] -signkey [PRIVATE-KEY-FILE] -out [CERTIFICATE-OUT-FILE]

This will also create temporary files you might want to delete afterwards, namely [REQUEST-TMP-FILE] and [RANDOM-TMP-FILE].

PHP sample code can be found at http://de.php.net/manual/en/function.openssl-csr-new.php.

Solution 2

Where everyone else has an errno that is reset to zero automatically by successful operations, OpenSSL has an "error stack", that you need to empty manually. See function openssl_error_string which is implemented in terms of ERR_get_error. Chances are that the error message that you are seeing has nothing to do with your code; try adding this before your code:

while ($msg = openssl_error_string()) {};

and in between each line:

while ($msg = openssl_error_string())
    echo "OpenSSL error when doing foo:" . $msg . "<br />\n";

Solution 3

You might have an easier time using phpseclib for signature creation / verification:

http://phpseclib.sourceforge.net/documentation/misc_crypt.html#misc_crypt_rsa_examples

Share:
23,566
BarsMonster
Author by

BarsMonster

Software/Hardware geek, Microelectronics, Optics, Lasers and Holography. My personal blog is at 3.14.by I do some microchip photography at zeptobars.com

Updated on March 07, 2020

Comments

  • BarsMonster
    BarsMonster about 4 years

    I am trying to use OpenSSL function for RSA sign/verify in PHP. When I try to do openssl_verify using my public key, I am getting this error: error:0906D06C:PEM routines:PEM_read_bio:no start line, but the function itself works correctly (returns 0 if messages was modified, and 1 if intact). openssl_sign works fine.

    How can I fix it?

    Currently, I use public key generated by openssl:

    define("SC_MSG_PUBLIC", <<<EOD
    -----BEGIN PUBLIC KEY-----
    MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALjPcOckMHDVLiUstcRwwx8kF5PzsiEs
    rskyndWisbXMLU9BHomXwL7Qg2L91jE+sNSobkzBDF41CbwDiNlofZUCAwEAAQ==
    -----END PUBLIC KEY-----
    EOD
    );
    

    Any ideas why this error triggers, but things works fine?

    Tried to generate public key out of private, and use it, but it appeared to be exactly the same, same error message :-S

    $pkey = openssl_pkey_get_private(SC_MSG_PRIVATE);
    $keyDetails = openssl_pkey_get_details($pkey);
    file_put_contents('c:\publickey', $keyDetails['key']);
    

    Also, I've tried to install newer versions of everything (PHP 5.3.1, OpenSSL 1.0.0a) - same result. And, I am on windows.

    • jww
      jww about 8 years
      You have to preserve the CR/LF at the encapsulation boundaries (-----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY-----). Note that this is a CR/LF pair; and not a CR (OS X) and not a LF (Linux). OpenSSL fails to parse PEM without them. You also need to ensure the length of a line is less than 1000 characters. Also see RFC 1421, Section 4.3.1, Constraints.
  • BarsMonster
    BarsMonster over 13 years
    Didn't helped, it cannot parse key in 1 line. It parses it only if it's in these 4 lines.
  • BarsMonster
    BarsMonster over 13 years
    This might work, but this is kinda wierd... Instead widely used native and very optimized library, we have to use slow byte-code-based one....
  • Admin
    Admin over 13 years
    The slow part of RSA is the math and since phpseclib's Crypt_RSA uses gmp, if it's available, speed isn't much of an issue. Actually, the really slow part is key generation. Everything else, even if phpseclib's native PHP BigInteger implementation is being used, is pretty fast. Try it out if your skeptical. The thing about OpenSSL is that it's intended for C developers. The PHP bindings are subpar and the API isn't, imho, intuitive for PHP developers.
  • BarsMonster
    BarsMonster over 13 years
    This would work in the worst case, but I would rather prefer to work with OpenSSL, it's defacto standard and the message I am working with in PHP is going to be signed/verified by C++ part too using OpenSSL, so extra consistency would be a plus.
  • BarsMonster
    BarsMonster over 13 years
    That's a perfect solution. Thanks for steps to generate certificate out of my key. You've got a nice rep up :-)
  • John
    John over 9 years
    PHP solved this horrible, a naked PUB would make usage for many people so much easier. The joke is that you can point the openssl funktion to a naked pub file on disk but not to the same content as string literal! As literal you need the certificate. Thanks a lot for pointing this out, saved me quite a lot of time.
  • olidem
    olidem almost 6 years
    No, what John says does not work for me. I had to create a (self signed) certificate in order to get read the public key.