如何为套接字连接添加SSL证书?Python3与PHP客户端连接失败排查
Let's break down the key issues in your setup that are blocking the SSL handshake, starting with the red flags in your Python server code:
1. Incorrect SSL Context Configuration & Missing Server Flag
Your server uses ssl.Purpose.CLIENT_AUTH for the context—this tells the server to require a valid client certificate from the PHP side to complete the handshake. If your PHP client isn't configured to send a client certificate, the server will immediately reject the connection.
On top of that, you forgot to pass server_side=True to wrap_socket(). By default, wrap_socket() assumes you're creating a client-side SSL socket. For a server, this flag is mandatory to initiate the SSL handshake correctly.
Quick Fix for the Server:
If you don't need client certificate authentication (most basic setups don't), adjust your code like this:
#!/usr/bin/env python3 import ssl import socket # Create a server-side context (no forced client auth) ssl_context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH) ssl_context.verify_mode = ssl.CERT_NONE # Disable client certificate check sock = socket.socket() # Mark this as a server-side SSL socket sock = ssl_context.wrap_socket(sock, server_side=True) sock.bind(('0.0.0.0', 9000)) sock.listen(5) csock, address = sock.accept() # Rest of your server logic...
2. CA Certificate Loading Problem
You're using capath='.' in load_verify_locations(), but capath requires the directory to contain hash-named symlinks to your CA certificates (generated with the c_rehash tool). If you just placed a regular CA file like ca.crt in the current folder, the server can't find it.
Fix This:
Use cafile instead of capath to point directly to your CA certificate file:
ssl_context.load_verify_locations(cafile='./ca.crt') # Replace with your actual CA file path
If you must use capath, run c_rehash . in your server directory first to generate the required symlinks.
3. PHP Client SSL Configuration Mismatches
Even with a fixed server, your PHP client needs to match the SSL settings:
- Use the
ssl://protocol when connecting:$socket = stream_socket_client('ssl://your-server-ip:9000', $errno, $errstr, 30); - If you enabled client certificate authentication on the server, configure the client to send its cert:
$context = stream_context_create([ 'ssl' => [ 'local_cert' => '/path/to/client-cert-and-key.pem', // Combined cert/key file 'verify_peer' => true, 'cafile' => '/path/to/ca.crt' ] ]); $socket = stream_socket_client('ssl://your-server-ip:9000', $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context); - If using a self-signed server cert (common in testing), temporarily disable peer verification (never do this in production!):
$context = stream_context_create(['ssl' => ['verify_peer' => false]]); $socket = stream_socket_client('ssl://your-server-ip:9000', $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
Start with fixing the server's server_side=True and verify mode first—those are the most likely culprits here.
内容的提问来源于stack exchange,提问作者BPS

