To prevent man-in-the-middle attacks (a server pretending to be someone else), I would like to verify that the SMTP server I connect too over SSL has a valid SSL certificate which proves it is who I think it is.

For example, after connecting to an SMTP server on port 25, I can switch to a secure connection like so: 

```
<?php

$smtp = fsockopen( "tcp://mail.example.com", 25, $errno, $errstr ); 
fread( $smtp, 512 ); 

fwrite($smtp,"HELO mail.example.me\r\n"); // .me is client, .com is server
fread($smtp, 512); 

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

stream_socket_enable_crypto( $smtp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT ); 

fwrite($smtp,"HELO mail.example.me\r\n");

```

However, there is no mention of where PHP is checking the SSL certificate against. Does PHP have a built-in list of root CA's? Is it just accepting anything?

**What is the proper way to verify the certificate is valid and that the SMTP server really is who I think it is?**

Update
======

Based on [this comment on PHP.net](http://www.php.net/manual/en/function.stream-socket-client.php#85345) it seems I can do SSL checks using some stream options. The best part is that the [stream\_context\_set\_option](http://php.net/manual/en/function.stream-context-set-option.php) accepts a context *or a stream resource*. Therefore, at some point in your TCP connection you can switch to SSL using a [CA cert bundle](http://curl.haxx.se/docs/caextract.html).

```
$resource = fsockopen( "tcp://mail.example.com", 25, $errno, $errstr ); 

...

stream_set_blocking($resource, true);

stream_context_set_option($resource, 'ssl', 'verify_host', true);
stream_context_set_option($resource, 'ssl', 'verify_peer', true);
stream_context_set_option($resource, 'ssl', 'allow_self_signed', false);

stream_context_set_option($resource, 'ssl', 'cafile', __DIR__ . '/cacert.pem');

$secure = stream_socket_enable_crypto($resource, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
stream_set_blocking($resource, false);

if( ! $secure)
{
    die("failed to connect securely\n");
}

```

Also, see [Context options and parameters](http://us1.php.net/manual/en/context.php) which expands on the [SSL options](http://us1.php.net/manual/en/context.ssl.php).

**However, while this now solves the main problem - how do I verify that the *valid* certificate actually belongs to the domain/IP I'm connecting to?**

In other words, the cert the server I'm connecting too may have a valid cert - but how do I know it's valid for "example.com" and not another server using a valid cert to act like "example.com"?

Update 2
========

It seems that you can [capture the SSL certificate](https://stackoverflow.com/a/3081093/99923) using the steam context params and parse it with [openssl\_x509\_parse](http://php.net/manual/en/function.openssl-x509-parse.php).

```
$cont = stream_context_get_params($r);
print_r(openssl_x509_parse($cont["options"]["ssl"]["peer_certificate"]));

```