blob: a928057ddc014b25d8289a9d52c16be6f68d620b [file] [log] [blame]
Bryan Duxburycd9aea12011-02-22 18:12:06 +00001Notes on Thrift/SSL
2
3Author: Ping Li <pingli@facebook.com>
4
51. Scope
6
7 This SSL only supports blocking mode socket I/O. It can only be used with
8 TSimpleServer, TThreadedServer, and TThreadPoolServer.
9
102. Implementation
11
12 There're two main classes TSSLSocketFactory and TSSLSocket. Instances of
13 TSSLSocket are always created from TSSLSocketFactory.
14
15 PosixSSLThreadFactory creates PosixSSLThread. The only difference from the
16 PthreadThread type is that it cleanups OpenSSL error queue upon exiting
17 the thread. Ideally, OpenSSL APIs should only be called from PosixSSLThread.
18
193. How to use SSL APIs
20
21 // This is for demo. In real code, typically only one TSSLSocketFactory
22 // instance is needed.
23 shared_ptr<TSSLSocketFactory> getSSLSocketFactory() {
24 shared_ptr<TSSLSocketFactory> factory(new TSSLSocketFactory());
25 // client: load trusted certificates
26 factory->loadTrustedCertificates("my-trusted-ca-certificates.pem");
27 // client: optionally set your own access manager, otherwise,
28 // the default client access manager will be loaded.
29
30 factory->loadCertificate("my-certificate-signed-by-ca.pem");
31 factory->loadPrivateKey("my-private-key.pem");
32 // server: optionally setup access manager
33 // shared_ptr<AccessManager> accessManager(new MyAccessManager);
Roger Meier3f067a82011-03-04 13:35:05 +000034 // factory->access(accessManager);
Bryan Duxburycd9aea12011-02-22 18:12:06 +000035 ...
36 }
37
38 // client code sample
Roger Meier3f067a82011-03-04 13:35:05 +000039 shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
Bryan Duxburycd9aea12011-02-22 18:12:06 +000040 shared_ptr<TSocket> socket = factory.createSocket(host, port);
41 shared_ptr<TBufferedTransport> transport(new TBufferedTransport(socket));
42 ...
43
44 // server code sample
45 shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
46 shared_ptr<TSSLServerSocket> socket(new TSSLServerSocket(port, factory));
47 shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory));
48 ...
49
504. AccessManager
51
52 AccessManager defines a callback interface. It has three callback methods:
53
54 (a) Decision verify(const sockaddr_storage& sa);
55 (b) Decision verify(const string& host, const char* name, int size);
56 (c) Decision verify(const sockaddr_storage& sa, const char* data, int size);
57
58 After SSL handshake completes, additional checks are conducted. Application
59 is given the chance to decide whether or not to continue the conversation
Roger Meier3f067a82011-03-04 13:35:05 +000060 with the remote. Application is queried through the above three "verify"
Bryan Duxburycd9aea12011-02-22 18:12:06 +000061 method. They are called at different points of the verification process.
62
63 Decisions can be one of ALLOW, DENY, and SKIP. ALLOW and DENY means the
64 conversation should be continued or disconnected, respectively. ALLOW and
65 DENY decision stops the verification process. SKIP means there's no decision
66 based on the given input, continue the verification process.
67
68 First, (a) is called with the remote IP. It is called once at the beginning.
69 "sa" is the IP address of the remote peer.
70
71 Then, the certificate of remote peer is loaded. SubjectAltName extensions
72 are extracted and sent to application for verification. When a DNS
73 subjectAltName field is extracted, (b) is called. When an IP subjectAltName
74 field is extracted, (c) is called.
75
76 The "host" in (b) is the value from TSocket::getHost() if this is a client
Roger Meier3f067a82011-03-04 13:35:05 +000077 side socket, or TSocket::getPeerHost() if this is a server side socket. The
Bryan Duxburycd9aea12011-02-22 18:12:06 +000078 reason is client side socket initiates the connection. TSocket::getHost()
79 is the remote host name. On server side, the remote host name is unknown
80 unless it's retrieved through TSocket::getPeerHost(). Either way, "host"
81 should be the remote host name. Keep in mind, if TSocket::getPeerHost()
82 failed, it would return the remote host name in numeric format.
83
84 If all subjectAltName extensions were "skipped", the common name field would
85 be checked. It is sent to application through (c), where "sa" is the remote
86 IP address. "data" is the IP address extracted from subjectAltName IP
87 extension, and "size" is the length of the extension data.
88
89 If any of the above "verify" methods returned a decision ALLOW or DENY, the
90 verification process would be stopped.
91
92 If any of the above "verify" methods returned SKIP, that decision would be
93 ignored and the verification process would move on till the last item is
94 examined. At that point, if there's still no decision, the connection is
95 terminated.
96
97 Thread safety, an access manager should not store state information if it's
98 to be used by many SSL sockets.
99
1005. SIGPIPE signal
101
102 Applications running OpenSSL over network connections may crash if SIGPIPE
103 is not ignored. This happens when they receive a connection reset by remote
104 peer exception, which somehow triggers a SIGPIPE signal. If not handled,
105 this signal would kill the application.
106
1076. How to run test client/server in SSL mode
108
109 The server expects the followings from the current working directory,
110 - "server-certificate.pem"
111 - "server-private-key.pem"
112
113 The client loads "trusted-ca-certificate.pem" from current directory.
114
115 The file names are hard coded in the source code. You need to create these
116 certificates before you can run the test code in SSL mode. Make sure at least
117 one of the followings is included in "server-certificate.pem",
118 - subjectAltName, DNS localhost
119 - subjectAltName, IP 127.0.0.1
120 - common name, localhost
121
122 Run,
123 - "./test_server --ssl" to start server
124 - "./test_client --ssl" to run client
125
126 If "-h <host>" is used to run client, the above "localhost" in the above
127 server-certificate.pem has to be replaced with that host name.
128
1297. TSSLSocketFactory::randomize()
130
131 The default implementation of OpenSSLSocketFactory::randomize() simply calls
132 OpenSSL's RAND_poll() when OpenSSL library is first initialized.
133
134 The PRNG seed is key to the application security. This method should be
Roger Meier3f067a82011-03-04 13:35:05 +0000135 overridden if it's not strong enough for you.