简体   繁体   English

将 PEM 格式的公钥传递给 openssl_pkey_get_public 会给出错误:0906D06C:PEM 例程:PEM_read_bio:no start line

[英]Passing public key in PEM format to openssl_pkey_get_public gives error:0906D06C:PEM routines:PEM_read_bio:no start line

The following public RSA key in PEM format was provided to openssl_pkey_get_public.以下 PEM 格式的公共 RSA 密钥已提供给 openssl_pkey_get_public。

-----BEGIN PUBLIC KEY-----
MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQCIZouo/rL5IkIIGrke/qkY
Nsb9JDXUw2MfutYdwIVjPiEbAcLiVxK6tOVXy7dq+hU0zyNd68bUi7VJjXWoiepS
+Mm6v76GCGvVvno48m7ofWIq6VLEaMQjIM/pzkF0TW7CmtjKvgg722Hx87AI/KCM
sWuHjhcQZsMgV4ibC8EAY6GYwHYAPWfUq+LI2wfRsQHumFC2IuT4guO/Vs5FJGXw
Arrvv7VPyKwZ8cpcZn9ka1K0N7su7QiGnzOhS3n2THaj25alE6TMXnrKmt6yIiXh
amsKVEKPPzHpw9ldTao1aG7vVNC9QXC8i9uQTWhhokxvSNw5OYFFkDZC5jD7McvB
AgMBAAE=
-----END PUBLIC KEY-----

However, the method call fails, returning false, with the error string error:0906D06C:PEM routines:PEM_read_bio:no start line但是,方法调用失败,返回 false,错误字符串error:0906D06C:PEM routines:PEM_read_bio:no start line

Is the public key invalid?公钥无效吗? For the record, my code is starting with a public key modulus and exponent and converting it to PEM format using the algorithm posted here .作为记录,我的代码从公钥模数和指数开始,并使用此处发布的算法将其转换为 PEM 格式。

Here's the full script:这是完整的脚本:

<?php

function createPemFromModulusAndExponent($n, $e)
{
    $modulus = urlsafeB64Decode($n);
    $publicExponent = urlsafeB64Decode($e);
    $components = array(
        'modulus' => pack('Ca*a*', 2, encodeLength(strlen($modulus)), $modulus),
        'publicExponent' => pack('Ca*a*', 2, encodeLength(strlen($publicExponent)), $publicExponent)
    );

    $RSAPublicKey = pack('Ca*a*a*', 48, encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), $components['modulus'], $components['publicExponent']);

    $rsaOID = pack('H*', '300d06092a864886f70d0101010500');
    $RSAPublicKey = chr(0) . $RSAPublicKey;
    $RSAPublicKey = chr(3) . encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
    $RSAPublicKey = pack('Ca*a*', 48, encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey);

    $RSAPublicKey = "-----BEGIN PUBLIC KEY-----" . chunk_split(base64_encode($RSAPublicKey), 64) . '-----END PUBLIC KEY-----';
    return $RSAPublicKey;
}

function urlsafeB64Decode($input)
{
    $remainder = strlen($input) % 4;
    if ($remainder)
    {
        $padlen = 4 - $remainder;
        $input .= str_repeat('=', $padlen);
    }
    return base64_decode(strtr($input, '-_', '+/'));
}

function encodeLength($length)
{
    if ($length <= 0x7F)
    {
        return chr($length);
    }

    $temp = ltrim(pack('N', $length), chr(0));
    return pack('Ca*', 0x80 | strlen($temp), $temp);
}

$key = createPemFromModulusAndExponent('iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ', 'AQAB');

print_r($key);

print_r(openssl_pkey_get_public($key));

print_r(openssl_error_string());

First: openssl_pkey_get_public is intended to either load the public key directly or extract it from a certificate, as described in the documentation of the certificate parameter of openssl_pkey_get_public .首先: openssl_pkey_get_public旨在直接加载公钥或从证书中提取公钥,如openssl_pkey_get_publiccertificate参数文档中所述。

There has already been a bug filed for this issue, #75643 from Dec 2017 (version 7.1.12), which has the status No Feedback and is currently suspended (note that #75643 actually refers to openssl_public_encrypt , which however uses the same logic regarding the key as openssl_pkey_get_public , here ):已经为此问题提交了一个错误,即 2017 年 12 月(版本 7.1.12)的#75643 ,其状态为No Feedback ,目前已暂停(请注意,#75643 实际上是指openssl_public_encrypt ,但它使用相同的逻辑关于密钥为openssl_pkey_get_public在这里):

The error in the queue is expected.队列中的错误是预期的。 If you supply string as a PEM (string not prefixed by "file://" which would be a file path), then certificate is tried first (using PEM_ASN1_read_bio).如果您将字符串作为 PEM 提供(字符串不以“file://”为前缀,这将是一个文件路径),则首先尝试证书(使用 PEM_ASN1_read_bio)。 It means that it fails and the error is saved to the queue.这意味着它失败并且错误被保存到队列中。 However this queue is just a copy of the OpenSSL which is emptied.然而,这个队列只是被清空的 OpenSSL 的副本。 After that the key is loaded using PEM_read_bio_PUBKEY which is successful in your case so you get back the result.之后,使用 PEM_read_bio_PUBKEY 加载密钥,这在您的情况下是成功的,因此您可以取回结果。 To sum it up openssl_error_string does not mean that the operation failed but just that some error was emitted...总而言之,openssl_error_string 并不意味着操作失败,而只是发出了一些错误......

According to this, the error message is caused by the failure to extract the key from the certificate.据此,错误消息是由于未能从证书中提取密钥引起的。 However, processing is continued and the key is loaded directly.但是,继续处理并直接加载密钥。 In other words, the error message occurs as expected when loading the key directly and can be ignored in this context (at least if the direct loading is successful).换句话说,错误消息在直接加载密钥时按预期出现,并且在这种情况下可以忽略(至少在直接加载成功的情况下)。

For the records: As of 7.2(.17), a slightly different error message is displayed: error:0909006C:PEM routines:get_name:no start line .对于记录:从 7.2(.17) 开始,显示的错误消息略有不同: error:0909006C:PEMroutines:get_name:no start line


Update:更新:

As @President James Moveon Polk noted in his comment, createPemFromModulusAndExponent doesn't generate the key correctly.正如@President James Moveon Polk 在他的评论中指出的那样, createPemFromModulusAndExponent没有正确生成密钥。 If the first / most significant byte is greater than 0x7F , the modulus must be preceded by a 0x00 byte, which does currently not happen.如果第一个/最高有效字节大于0x7F ,则模数前面必须有一个0x00字节,这目前不会发生。 Eg in the posted code the modulus starts (Base64url decoded) with 0x88 , which means that the generated (= the posted) key is invalid.例如,在发布的代码中,模数以0x88开头(Base64url 解码),这意味着生成的(= 发布的)密钥无效。 If a 0x00 is prepended manually and the so corrected value is (Base64url encoded) passed to createPemFromModulusAndExponent , the following, now valid key results:如果手动添加0x00并且如此更正的值(Base64url 编码)传递给createPemFromModulusAndExponent ,则以下现在有效的密钥结果:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiGaLqP6y+SJCCBq5Hv6p
GDbG/SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInq
UvjJur++hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPyg
jLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk+ILjv1bORSRl
8AK677+1T8isGfHKXGZ/ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl
4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw+zHL
wQIDAQAB
-----END PUBLIC KEY-----

Of course it would be better if createPemFromModulusAndExponent would do this correction automatically.当然,如果createPemFromModulusAndExponent会自动进行此校正会更好。 @President James Moveon Polk has filed an issue for this, here . @President James Moveon Polk 已为此提出问题,请点击此处

Allow me to propose an alternative way that's quite a bit simpler and more succinct.请允许我提出一种更简单、更简洁的替代方法。 Using phpseclib,使用 phpseclib,

require __DIR__ . '/vendor/autoload.php';

use phpseclib\Math\BigInteger;
use phpseclib\Crypt\RSA;

$rsa = new RSA;
$rsa->loadKey([
    'e' => new BigInteger(base64_decode('AQAB'), 256),
    'n' => new BigInteger(base64_decode('iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ'), 256)
]);

print_r(openssl_pkey_get_public($rsa));

The code you're using is, in fact, using code that was lifted from phpseclib 2.0.实际上,您使用的代码是使用从 phpseclib 2.0 中提取的代码。 See https://github.com/dragosgaftoneanu/okta-simple-jwt-verifier/issues/1#issuecomment-612503921 for more info.有关更多信息,请参阅https://github.com/dragosgaftoneanu/okta-simple-jwt-verifier/issues/1#issuecomment-612503921

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 openssl_verify和“错误:0906D06C:PEM例程:PEM_read_bio:无起始行” - openssl_verify and “error:0906D06C:PEM routines:PEM_read_bio:no start line” Firebase PHP JWT“OpenSSL无法验证数据:错误:0906D06C:PEM例程:PEM_read_bio:无启动行” - Firebase PHP JWT “OpenSSL unable to verify data: error:0906D06C:PEM routines:PEM_read_bio:no start line” openssl_pkey_get_public没有打开公钥,“没有起始行”错误 - openssl_pkey_get_public not open public key, “no start line” error PHP OpenSSL 无法读取 PEM 格式的公钥 - PHP OpenSSL cannot read public key in PEM format openssl_pkey_get_public返回false,但是密钥确实存在 - openssl_pkey_get_public returning false, but key does exist openssl_pkey_get_public返回0 - openssl_pkey_get_public return 0 lombucci/jwt 无法解析您的密钥,原因:error:0909006C:PEMroutines:get_name:no start line - lombucci/jwt It was not possible to parse your key, reason: error:0909006C:PEM routines:get_name:no start line ECDSA:将 60 字节的二进制公钥转换为 PEM 格式,以便与 PHP openssl_verify() 一起使用 - ECDSA: Convert a binary public key of 60 bytes into PEM format for using it with PHP openssl_verify() PHP rsa 从 pem 文件中获取公钥 - PHP rsa get public key from pem file openssl_verify():不能将提供的密钥参数强制转换为 .pem 文件的公钥 - openssl_verify(): supplied key param cannot be coerced into a public key for a .pem file
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM