Skip to content

Commit b3e0621

Browse files
committed
Documentation and tests for encrypted private keys
1 parent 1c16a5a commit b3e0621

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ incoming connection initializes its TLS context.
111111
This implies that any invalid certificate file paths or contents will only cause
112112
an `error` event at a later time.
113113

114+
If your private key is encrypted with a passphrase, you have to specify it
115+
like this:
116+
117+
```php
118+
$server = new SecureServer($server, $loop, array(
119+
'local_cert' => 'server.pem',
120+
'passphrase' => 'secret'
121+
));
122+
```
123+
114124
Whenever a client completes the TLS handshake, it will emit a `connection` event
115125
with a connection instance implementing [`ConnectionInterface`](#connectioninterface):
116126

examples/localhost_swordfish.pem

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBZMRIwEAYDVQQDDAkxMjcu
3+
MC4wLjExCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK
4+
DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMwMTQxMDQzWhcNMjYx
5+
MjI4MTQxMDQzWjBZMRIwEAYDVQQDDAkxMjcuMC4wLjExCzAJBgNVBAYTAkFVMRMw
6+
EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0
7+
eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRXt83SrKIHr/i
8+
3lc8O8pz6NHE1DNHJa4xg2xalXWzCEV6m1qLd9VdaLT9cJD1afNmEMBgY6RblNL/
9+
paJWVoR9MOUeIoYl2PrhUCxsf7h6MRtezQQe3e+n+/0XunF0JUQIZuJqbxfRk5WT
10+
XmYnphqOZKEcistAYvFBjzl/D+Cl/nYsreADc+t9l5Vni89oTWEuqIrsM4WUZqqB
11+
VMAakd2nZJLWIrMxq9hbW1XNukOQfcmZVFTC6CUnLq8qzGbtfZYBuMBACnL1k/E/
12+
yPaAgR46l14VAcndDUJBtMeL2qYuNwvXQhg3KuBmpTUpH+yzxU+4T3lmv0xXmPqu
13+
ySH3xvW3AgMBAAGjUDBOMB0GA1UdDgQWBBRu68WTI4pVeTB7wuG9QGI3Ie441TAf
14+
BgNVHSMEGDAWgBRu68WTI4pVeTB7wuG9QGI3Ie441TAMBgNVHRMEBTADAQH/MA0G
15+
CSqGSIb3DQEBBQUAA4IBAQCc4pEjEHO47VRJkbHgC+c2gAVgxekkaA1czBA1uAvh
16+
ILRda0NLlvyftbjaG0zZp2ABUCfRfksl/Pf/PzWLUMEuH/9kEW2rgP43z6YgiL6k
17+
kBPlmAU607UjD726RPGkw8QPSXS/dWiNJ5CBpPWLpxC45pokqItYbY0ijQ5Piq09
18+
TchYlCX044oSRnPiP394PQ3HVdaGhJB2DnjDq3in5dVivFf8EdgzQSvp/wXy3WQs
19+
uFSVonSnrZGY/4AgT3psGaQ6fqKb4SBoqtf5bFQvp1XNNRkuEJnS/0dygEya0c+c
20+
aCe/1gXC2wDjx0/TekY5m1Nyw5SY6z7stOqL/ekwgejt
21+
-----END CERTIFICATE-----
22+
-----BEGIN ENCRYPTED PRIVATE KEY-----
23+
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIG7idPRLgiHkCAggA
24+
MBQGCCqGSIb3DQMHBAg+MLPdepHWSwSCBMgVW9LseCjfTAmF9U1qRnKsq3kIwEnW
25+
6aERBqs/mnmEhrXgZYgcvRRK7kD12TdHt/Nz46Ymu0h+Lrvuwtl1fHQUARTk/gFh
26+
onLhc9kjMUhLRIR007vJe3HvWOb/v+SBSDB38OpUxUwJmBVBuSaYLWVuPR6J5kUj
27+
xOgBS049lN3E9cfrHvb3bF/epIQrU0OgfyyxEvIi5n30y+tlRn3y68PY6Qd46t4Y
28+
UN5VZUwvJBgoRy9TGxSkiSRjhxC2PWpLYq/HMzDbcRcFF5dVAIioUd/VZ7fdgBfA
29+
uMW4SFfpFLDUX0aaYe+ZdA5tM0Bc0cOtG8Z0sc9JYDNNcvjmSiGCi646h8F0D3O6
30+
JKAQMMxQGWiyQeJ979LVjtq4lJESXA8VEKz9rV03y5xunmFCLy6dGt+6GJwXgabn
31+
OH7nvEv4GqAOqKc6E9je4JM+AF/oUazrfPse1KEEtsPKarazjCB/SKYtHyDJaavD
32+
GGjtiU9zWwGMOgIDyNmXe3ga7/TWoGOAg5YlTr6Hbq2Y/5ycgjAgPFjuXtvnoT0+
33+
mF5TnNfMAqTgQsE2gjhonK1pdlOen0lN5FtoUXp3CXU0dOq0J70GiX+1YA7VDn30
34+
n5WNAgfOXX3l3E95jGN370pHXyli5RUNW0NZVHV+22jlNWCVtQHUh+DVswQZg+i5
35+
+DqaIHz2jUetMo7gWtqGn/wwSopOs87VM1rcALhZL4EsJ+Zy81I/hA32RNnGbuol
36+
NAiZh+0KrtTcc/fPunpd8vRtOwGphM11dKucozUufuiPG2inR3aEqt5yNx54ec/f
37+
J6nryWRYiHEA/rCU9MSBM9cqKFtEmy9/8oxV41/SPxhXjHwDlABWTtFuJ3pf2sOF
38+
ILSYYFwB0ZGvdjE5yAJFBr9efno/L9fafmGk7a3vmVgK2AmUC9VNB5XHw1GjF8OP
39+
aQAXe4md9Bh0jk/D/iyp7e7IWNssul/7XejhabidWgFj6EXc9YxE59+FlhDqyMhn
40+
V6houc+QeUXuwsAKgRJJhJtpv/QSZ5BI3esxHHUt3ayGnvhFElpAc0t7C/EiXKIv
41+
DAFYP2jksBqijM8YtEgPWYzEP5buYxZnf/LK7FDocLsNcdF38UaKBbeF90e7bR8j
42+
SHspG9aJWICu8Yawnh8zuy/vQv+h9gWyGodd2p9lQzlbRXrutbwfmPf7xP6nzT9i
43+
9GcugJxTaZgkCfhhHxFk/nRHS2NAzagKVib1xkUlZJg2hX0fIFUdYteL1GGTvOx5
44+
m3mTOino4T19z9SEdZYb2OHYh29e/T74bJiLCYdXwevSYHxfZc8pYAf0jp4UnMT2
45+
f7B0ctX1iXuQ2uZVuxh+U1Mcu+v0gDla1jWh7AhcePSi4xBNUCak0kQip6r5e6Oi
46+
r4MIyMRk/Pc5pzEKo8G6nk26rNvX3aRvECoVfmK7IVdsqZ6IXlt9kOmWx3IeKzrO
47+
J5DxpzW+9oIRZJgPTkc4/XRb0tFmFQYTiChiQ1AJUEiCX0GpkFf7cq61aLGYtWyn
48+
vL2lmQhljzjrDo15hKErvk7eBZW7GW/6j/m/PfRdcBI4ceuP9zWQXnDOd9zmaE4b
49+
q3bJ+IbbyVZA2WwyzN7umCKWghsiPMAolxEnYM9JRf8BcqeqQiwVZlfO5KFuN6Ze
50+
le4=
51+
-----END ENCRYPTED PRIVATE KEY-----

src/SecureServer.php

+15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@
2323
* );
2424
* ```
2525
*
26+
* If your private key is encrypted with a passphrase, you have to specify it
27+
* like this:
28+
*
29+
* ```php
30+
* $context = array(
31+
* 'local_cert' => 'server.pem',
32+
* 'passphrase' => 'secret'
33+
* );
34+
* ```
35+
*
2636
* @see Server
2737
* @link http://php.net/manual/en/context.ssl.php for TLS context options
2838
*/
@@ -35,6 +45,11 @@ class SecureServer extends EventEmitter implements ServerInterface
3545

3646
public function __construct(Server $tcp, LoopInterface $loop, array $context)
3747
{
48+
// default to empty passphrase to surpress blocking passphrase prompt
49+
$context += array(
50+
'passphrase' => ''
51+
);
52+
3853
$this->tcp = $tcp;
3954
$this->context = $context;
4055
$this->loop = $loop;

tests/FunctionalSecureServerTest.php

+71
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,30 @@ public function testEmitsConnectionForNewConnection()
2727
$server = new SecureServer($server, $loop, array(
2828
'local_cert' => __DIR__ . '/../examples/localhost.pem'
2929
));
30+
$server->on('error', 'var_dump');
31+
$server->on('connection', $this->expectCallableOnce());
32+
$server->listen(0);
33+
$port = $server->getPort();
34+
35+
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
36+
'verify_peer' => false
37+
));
38+
$promise = $connector->create('127.0.0.1', $port);
39+
40+
$promise->then($this->expectCallableOnce());
41+
42+
Block\sleep(0.1, $loop);
43+
}
44+
45+
public function testEmitsConnectionForNewConnectionWithEncryptedCertificate()
46+
{
47+
$loop = Factory::create();
48+
49+
$server = new Server($loop);
50+
$server = new SecureServer($server, $loop, array(
51+
'local_cert' => __DIR__ . '/../examples/localhost_swordfish.pem',
52+
'passphrase' => 'swordfish'
53+
));
3054
$server->on('connection', $this->expectCallableOnce());
3155
$server->listen(0);
3256
$port = $server->getPort();
@@ -64,6 +88,53 @@ public function testEmitsErrorForServerWithInvalidCertificate()
6488
Block\sleep(0.1, $loop);
6589
}
6690

91+
public function testEmitsErrorForServerWithEncryptedCertificateMissingPassphrase()
92+
{
93+
$loop = Factory::create();
94+
95+
$server = new Server($loop);
96+
$server = new SecureServer($server, $loop, array(
97+
'local_cert' => __DIR__ . '/../examples/localhost_swordfish.pem'
98+
));
99+
$server->on('connection', $this->expectCallableNever());
100+
$server->on('error', $this->expectCallableOnce());
101+
$server->listen(0);
102+
$port = $server->getPort();
103+
104+
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
105+
'verify_peer' => false
106+
));
107+
$promise = $connector->create('127.0.0.1', $port);
108+
109+
$promise->then(null, $this->expectCallableOnce());
110+
111+
Block\sleep(0.1, $loop);
112+
}
113+
114+
public function testEmitsErrorForServerWithEncryptedCertificateWithInvalidPassphrase()
115+
{
116+
$loop = Factory::create();
117+
118+
$server = new Server($loop);
119+
$server = new SecureServer($server, $loop, array(
120+
'local_cert' => __DIR__ . '/../examples/localhost_swordfish.pem',
121+
'passphrase' => 'nope'
122+
));
123+
$server->on('connection', $this->expectCallableNever());
124+
$server->on('error', $this->expectCallableOnce());
125+
$server->listen(0);
126+
$port = $server->getPort();
127+
128+
$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
129+
'verify_peer' => false
130+
));
131+
$promise = $connector->create('127.0.0.1', $port);
132+
133+
$promise->then(null, $this->expectCallableOnce());
134+
135+
Block\sleep(0.1, $loop);
136+
}
137+
67138
public function testEmitsErrorForConnectionWithPeerVerification()
68139
{
69140
$loop = Factory::create();

0 commit comments

Comments
 (0)