4

在命令行中,我可以通过键入验证证书是否由受信任的 CA 颁发

openssl 验证 mycert.pem

我如何对 PHP 的 OpenSSL 库做同样的事情?PHP 有一个带有openssl_verify许多额外参数的函数:

data , string $signature , mixed $pub_key_id

如何使用相应的 PHP 函数重复该简单的命令行操作?

4

4 回答 4

4

使用phpseclib,一个纯 PHP X509 实现,这很容易。例如。

<?php
include('File/X509.php');

$x509 = new File_X509();
$x509->loadCA('...');
$x509->loadX509('...');
echo $x509->validateSignature() ? 'valid' : 'invalid';
?>

有关更多信息,请参见http://phpseclib.sourceforge.net/x509/compare.html#verify

于 2013-11-14T17:43:14.383 回答
1

我不确定你的证书是什么,但我发现了这个函数 openssl_x509_check purpose。

http://php.net/manual/en/function.openssl-x509-check purpose.php http://www.php.net/manual/en/openssl.cert.verification.php

openssl_x509_check purpose($cert, $ purpose, $cainfo, $untrustedfile);

$cainfo 是带有 CA 文件路径的数组。

于 2018-09-10T15:06:40.573 回答
-1

看看这个: 在 PHP 中验证 SMTP

<?php
$server   = "smtp.gmail.com";        // Who I connect to
$myself   = "my_server.example.com"; // Who I am
$cabundle = '/etc/ssl/cacert.pem';   // Where my root certificates are

// Verify server. There's not much we can do, if we suppose that an attacker
// has taken control of the DNS. The most we can hope for is that there will
// be discrepancies between the expected responses to the following code and
// the answers from the subverted DNS server.

// To detect these discrepancies though, implies we knew the proper response
// and saved it in the code. At that point we might as well save the IP, and
// decouple from the DNS altogether.

$match1   = false;
$addrs    = gethostbynamel($server);
foreach($addrs as $addr)
{
    $name = gethostbyaddr($addr);
    if ($name == $server)
    {
        $match1 = true;
        break;
    }
}
// Here we must decide what to do if $match1 is false.
// Which may happen often and for legitimate reasons.
print "Test 1: " . ($match1 ? "PASSED" : "FAILED") . "\n";

$match2   = false;
$domain   = explode('.', $server);
array_shift($domain);
$domain = implode('.', $domain);
getmxrr($domain, $mxhosts);
foreach($mxhosts as $mxhost)
{
    $tests = gethostbynamel($mxhost);
    if (0 != count(array_intersect($addrs, $tests)))
    {
        // One of the instances of $server is a MX for its domain
        $match2 = true;
        break;
    }
}
// Again here we must decide what to do if $match2 is false.
// Most small ISP pass test 2; very large ISPs and Google fail.
print "Test 2: " . ($match2 ? "PASSED" : "FAILED") . "\n";
// On the other hand, if you have a PASS on a server you use,
// it's unlikely to become a FAIL anytime soon.

// End of maybe-they-help-maybe-they-don't checks.

// Establish the connection
$smtp = fsockopen( "tcp://$server", 25, $errno, $errstr );
fread( $smtp, 512 );

// Here you can check the usual banner from $server (or in general,
// check whether it contains $server's domain name, or whether the
// domain it advertises has $server among its MX's.
// But yet again, Google fails both these tests.

fwrite($smtp,"HELO $myself\r\n");
fread($smtp, 512);

// Switch to TLS
fwrite($smtp,"STARTTLS\r\n");
fread($smtp, 512);
stream_set_blocking($smtp, true);
stream_context_set_option($smtp, 'ssl', 'verify_peer', true);
stream_context_set_option($smtp, 'ssl', 'allow_self_signed', false);
stream_context_set_option($smtp, 'ssl', 'capture_peer_cert', true);
stream_context_set_option($smtp, 'ssl', 'cafile', $cabundle);
$secure = stream_socket_enable_crypto($smtp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
stream_set_blocking($smtp, false);
$opts = stream_context_get_options($smtp);
if (!isset($opts["ssl"]["peer_certificate"]))
    $secure = false;
else
{
    $cert = openssl_x509_parse($opts["ssl"]["peer_certificate"]);
    $names = '';
    if ('' != $cert)
    {
        if (isset($cert['extensions']))
            $names = $cert['extensions']['subjectAltName'];
        elseif (isset($cert['subject']))
        {
            if (isset($cert['subject']['CN']))
                $names = 'DNS:' . $cert['subject']['CN'];
            else
                $secure = false; // No exts, subject without CN
        }
        else
            $secure = false; // No exts, no subject
    }
    $checks = explode(',', $names);

    // At least one $check must match $server
    $tmp    = explode('.', $server);
    $fles   = array_reverse($tmp);
    $okay   = false;
    foreach($checks as $check)
    {
        $tmp = explode(':', $check);
        if ('DNS' != $tmp[0])    continue;  // candidates must start with DNS:
        if (!isset($tmp[1]))     continue;  // and have something afterwards
        $tmp  = explode('.', $tmp[1]);
        if (count($tmp) < 3)     continue;  // "*.com" is not a valid match
        $cand = array_reverse($tmp);
        $okay = true;
        foreach($cand as $i => $item)
        {
            if (!isset($fles[$i]))
            {
                // We connected to www.example.com and certificate is for *.www.example.com -- bad.
                $okay = false;
                break;
            }
            if ($fles[$i] == $item)
                continue;
            if ($item == '*')
                break;
        }
        if ($okay)
            break;
    }
    if (!$okay)
        $secure = false; // No hosts matched our server.
}

if (!$secure)
        die("failed to connect securely\n");
print "Success!\n";
// Continue with connection...
?>
于 2013-12-06T01:24:36.690 回答
-1

在 PHP 中,openssl_verify 函数不用于验证证书是否由受信任的 CA 颁发,而是用于验证签名是否适合某些数据...

编辑:如何使用 PHP 验证 CA:您不仅可以验证主题和颁发者名称是否匹配,因此仅在 Php 中使用 OpenSSL 似乎不太可能

于 2013-11-13T15:22:48.580 回答