1 | #include<qapplication.h>
|
---|
2 | #include<qfile.h>
|
---|
3 | #include<qsocket.h>
|
---|
4 | #include<qserversocket.h>
|
---|
5 | #include<qvaluelist.h>
|
---|
6 | #include<qtimer.h>
|
---|
7 | #include"qca.h"
|
---|
8 |
|
---|
9 | char pemdata_cert[] =
|
---|
10 | "-----BEGIN CERTIFICATE-----\n"
|
---|
11 | "MIIDbjCCAtegAwIBAgIBADANBgkqhkiG9w0BAQQFADCBhzELMAkGA1UEBhMCVVMx\n"
|
---|
12 | "EzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNVBAcTBklydmluZTEYMBYGA1UEChMP\n"
|
---|
13 | "RXhhbXBsZSBDb21wYW55MRQwEgYDVQQDEwtleGFtcGxlLmNvbTEiMCAGCSqGSIb3\n"
|
---|
14 | "DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbTAeFw0wMzA3MjQwNzMwMDBaFw0wMzA4\n"
|
---|
15 | "MjMwNzMwMDBaMIGHMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEP\n"
|
---|
16 | "MA0GA1UEBxMGSXJ2aW5lMRgwFgYDVQQKEw9FeGFtcGxlIENvbXBhbnkxFDASBgNV\n"
|
---|
17 | "BAMTC2V4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu\n"
|
---|
18 | "Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCobzCF268K2sRp473gvBTT\n"
|
---|
19 | "4AgSL1kjeF8N57vxS1P8zWrWMXNs4LuH0NRZmKTajeboy0br8xw+smIy3AbaKAwW\n"
|
---|
20 | "WZToesxebu3m9VeA8dqWyOaUMjoxAcgVYesgVaMpjRe7fcWdJnX1wJoVVPuIcO8m\n"
|
---|
21 | "a+AAPByfTORbzpSTmXAQAwIDAQABo4HnMIHkMB0GA1UdDgQWBBTvFierzLmmYMq0\n"
|
---|
22 | "cB/+5rK1bNR56zCBtAYDVR0jBIGsMIGpgBTvFierzLmmYMq0cB/+5rK1bNR566GB\n"
|
---|
23 | "jaSBijCBhzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNV\n"
|
---|
24 | "BAcTBklydmluZTEYMBYGA1UEChMPRXhhbXBsZSBDb21wYW55MRQwEgYDVQQDEwtl\n"
|
---|
25 | "eGFtcGxlLmNvbTEiMCAGCSqGSIb3DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbYIB\n"
|
---|
26 | "ADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAGqGhXf7xNOnYNtFO7gz\n"
|
---|
27 | "K6RdZGHFI5q1DAEz4hhNBC9uElh32XGX4wN7giz3zLC8v9icL/W4ff/K5NDfv3Gf\n"
|
---|
28 | "gQe/+Wo9Be3H3ul6uwPPFnx4+PIOF2a5TW99H9smyxWdNjnFtcUte4al3RszcMWG\n"
|
---|
29 | "x3iqsWosGtj6F+ridmKoqKLu\n"
|
---|
30 | "-----END CERTIFICATE-----\n";
|
---|
31 |
|
---|
32 | char pemdata_privkey[] =
|
---|
33 | "-----BEGIN RSA PRIVATE KEY-----\n"
|
---|
34 | "MIICXAIBAAKBgQCobzCF268K2sRp473gvBTT4AgSL1kjeF8N57vxS1P8zWrWMXNs\n"
|
---|
35 | "4LuH0NRZmKTajeboy0br8xw+smIy3AbaKAwWWZToesxebu3m9VeA8dqWyOaUMjox\n"
|
---|
36 | "AcgVYesgVaMpjRe7fcWdJnX1wJoVVPuIcO8ma+AAPByfTORbzpSTmXAQAwIDAQAB\n"
|
---|
37 | "AoGAP83u+aYghuIcaWhmM03MLf69z/WztKYSi/fu0BcS977w67bL3MC9CVPoPRB/\n"
|
---|
38 | "0nLSt/jZIuRzHKUCYfXLerSU7v0oXDTy6GPzWMh/oXIrpF0tYNbwWF7LSq2O2gGZ\n"
|
---|
39 | "XtA9MSmUNNJaKzQQeXjqdVFOY8A0Pho+k2KByBiCi+ChkcECQQDRUuyX0+PKJtA2\n"
|
---|
40 | "M36BOTFpy61BAv+JRlXUnHuevOfQWl6NR6YGygqCyH1sWtP1sa9S4wWys3DFH+5A\n"
|
---|
41 | "DkuAqk7zAkEAzf4eUH2hp5CIMsXH+WpIzKj09oY1it2CAKjVq4rUELf8iXvmGoFl\n"
|
---|
42 | "000spua4MjHNUYm7LR0QaKesKrMyGZUesQJAL8aLdYPJI+SD9Tr/jqLtIkZ4frQe\n"
|
---|
43 | "eshw4pvsoyheiHF3zyshO791crAr4EVCx3sMlxB1xnmqLXPCPyCEHxO//QJBAIBY\n"
|
---|
44 | "IYkjDZJ6ofGIe1UyXJNvfdkPu9J+ut4wU5jjEcgs6mK62J6RGuFxhy2iOQfFMdjo\n"
|
---|
45 | "yL+OCUg7mDCun7uCxrECQAtSvnLOFMjO5qExRjFtwi+b1rcSekd3Osk/izyRFSzg\n"
|
---|
46 | "Or+AL56/EKfiogNnFipgaXIbb/xj785Cob6v96XoW1I=\n"
|
---|
47 | "-----END RSA PRIVATE KEY-----\n";
|
---|
48 |
|
---|
49 | class LayerTracker
|
---|
50 | {
|
---|
51 | public:
|
---|
52 | struct Item
|
---|
53 | {
|
---|
54 | int plain;
|
---|
55 | int encoded;
|
---|
56 | };
|
---|
57 |
|
---|
58 | LayerTracker()
|
---|
59 | {
|
---|
60 | p = 0;
|
---|
61 | }
|
---|
62 |
|
---|
63 | void reset()
|
---|
64 | {
|
---|
65 | p = 0;
|
---|
66 | list.clear();
|
---|
67 | }
|
---|
68 |
|
---|
69 | void addPlain(int plain)
|
---|
70 | {
|
---|
71 | p += plain;
|
---|
72 | }
|
---|
73 |
|
---|
74 | void specifyEncoded(int encoded, int plain)
|
---|
75 | {
|
---|
76 | // can't specify more bytes than we have
|
---|
77 | if(plain > p)
|
---|
78 | plain = p;
|
---|
79 | p -= plain;
|
---|
80 | Item i;
|
---|
81 | i.plain = plain;
|
---|
82 | i.encoded = encoded;
|
---|
83 | list += i;
|
---|
84 | }
|
---|
85 |
|
---|
86 | int finished(int encoded)
|
---|
87 | {
|
---|
88 | int plain = 0;
|
---|
89 | for(QValueList<Item>::Iterator it = list.begin(); it != list.end();) {
|
---|
90 | Item &i = *it;
|
---|
91 |
|
---|
92 | // not enough?
|
---|
93 | if(encoded < i.encoded) {
|
---|
94 | i.encoded -= encoded;
|
---|
95 | break;
|
---|
96 | }
|
---|
97 |
|
---|
98 | encoded -= i.encoded;
|
---|
99 | plain += i.plain;
|
---|
100 | it = list.remove(it);
|
---|
101 | }
|
---|
102 | return plain;
|
---|
103 | }
|
---|
104 |
|
---|
105 | int p;
|
---|
106 | QValueList<Item> list;
|
---|
107 | };
|
---|
108 |
|
---|
109 | class SecureServerTest : public QServerSocket
|
---|
110 | {
|
---|
111 | Q_OBJECT
|
---|
112 | public:
|
---|
113 | enum { Idle, Handshaking, Active, Closing };
|
---|
114 |
|
---|
115 | SecureServerTest(int _port) : QServerSocket(_port), port(_port)
|
---|
116 | {
|
---|
117 | sock = new QSocket;
|
---|
118 | connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
|
---|
119 | connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
|
---|
120 | connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
|
---|
121 | connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int)));
|
---|
122 |
|
---|
123 | ssl = new QCA::TLS;
|
---|
124 | connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken()));
|
---|
125 | connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead()));
|
---|
126 | connect(ssl, SIGNAL(readyReadOutgoing(int)), SLOT(ssl_readyReadOutgoing(int)));
|
---|
127 | connect(ssl, SIGNAL(closed()), SLOT(ssl_closed()));
|
---|
128 | connect(ssl, SIGNAL(error(int)), SLOT(ssl_error(int)));
|
---|
129 |
|
---|
130 | cert.fromPEM(pemdata_cert);
|
---|
131 | privkey.fromPEM(pemdata_privkey);
|
---|
132 |
|
---|
133 | mode = Idle;
|
---|
134 | }
|
---|
135 |
|
---|
136 | ~SecureServerTest()
|
---|
137 | {
|
---|
138 | delete ssl;
|
---|
139 | delete sock;
|
---|
140 | }
|
---|
141 |
|
---|
142 | void start()
|
---|
143 | {
|
---|
144 | if(cert.isNull() || privkey.isNull()) {
|
---|
145 | printf("Error loading cert and/or private key!\n");
|
---|
146 | QTimer::singleShot(0, this, SIGNAL(quit()));
|
---|
147 | return;
|
---|
148 | }
|
---|
149 | if(!ok()) {
|
---|
150 | printf("Error binding to port %d!\n", port);
|
---|
151 | QTimer::singleShot(0, this, SIGNAL(quit()));
|
---|
152 | return;
|
---|
153 | }
|
---|
154 | printf("Listening on port %d ...\n", port);
|
---|
155 | }
|
---|
156 |
|
---|
157 | void newConnection(int s)
|
---|
158 | {
|
---|
159 | // Note: only 1 connection supported at a time in this example!
|
---|
160 | if(sock->isOpen()) {
|
---|
161 | QSocket tmp;
|
---|
162 | tmp.setSocket(s);
|
---|
163 | printf("throwing away extra connection\n");
|
---|
164 | return;
|
---|
165 | }
|
---|
166 | mode = Handshaking;
|
---|
167 | sock->setSocket(s);
|
---|
168 | printf("Connection received! Starting TLS handshake...\n");
|
---|
169 | ssl->setCertificate(cert, privkey);
|
---|
170 | ssl->startServer();
|
---|
171 | }
|
---|
172 |
|
---|
173 | signals:
|
---|
174 | void quit();
|
---|
175 |
|
---|
176 | private slots:
|
---|
177 | void sock_readyRead()
|
---|
178 | {
|
---|
179 | QByteArray buf(sock->bytesAvailable());
|
---|
180 | int num = sock->readBlock(buf.data(), buf.size());
|
---|
181 | if(num < (int)buf.size())
|
---|
182 | buf.resize(num);
|
---|
183 | ssl->writeIncoming(buf);
|
---|
184 | }
|
---|
185 |
|
---|
186 | void sock_connectionClosed()
|
---|
187 | {
|
---|
188 | printf("Connection closed.\n");
|
---|
189 | }
|
---|
190 |
|
---|
191 | void sock_bytesWritten(int x)
|
---|
192 | {
|
---|
193 | if(mode == Active && sent) {
|
---|
194 | int bytes = layer.finished(x);
|
---|
195 | bytesLeft -= bytes;
|
---|
196 |
|
---|
197 | if(bytesLeft == 0) {
|
---|
198 | mode = Closing;
|
---|
199 | printf("SSL shutdown\n");
|
---|
200 | ssl->close();
|
---|
201 | }
|
---|
202 | }
|
---|
203 | }
|
---|
204 |
|
---|
205 | void sock_error(int)
|
---|
206 | {
|
---|
207 | printf("Socket error.\n");
|
---|
208 | }
|
---|
209 |
|
---|
210 | void ssl_handshaken()
|
---|
211 | {
|
---|
212 | printf("Successful SSL handshake. Waiting for newline.\n");
|
---|
213 | layer.reset();
|
---|
214 | bytesLeft = 0;
|
---|
215 | sent = false;
|
---|
216 | mode = Active;
|
---|
217 | }
|
---|
218 |
|
---|
219 | void ssl_readyRead()
|
---|
220 | {
|
---|
221 | QByteArray a = ssl->read();
|
---|
222 | QString str =
|
---|
223 | "<html>\n"
|
---|
224 | "<head><title>Test</title></head>\n"
|
---|
225 | "<body>this is only a test</body>\n"
|
---|
226 | "</html>\n";
|
---|
227 | QCString cs = str.latin1();
|
---|
228 | QByteArray b(cs.length());
|
---|
229 | memcpy(b.data(), cs.data(), b.size());
|
---|
230 |
|
---|
231 | printf("Sending test response...\n");
|
---|
232 | sent = true;
|
---|
233 | layer.addPlain(b.size());
|
---|
234 | ssl->write(b);
|
---|
235 | }
|
---|
236 |
|
---|
237 | void ssl_readyReadOutgoing(int plainBytes)
|
---|
238 | {
|
---|
239 | QByteArray a = ssl->readOutgoing();
|
---|
240 | layer.specifyEncoded(a.size(), plainBytes);
|
---|
241 | sock->writeBlock(a.data(), a.size());
|
---|
242 | }
|
---|
243 |
|
---|
244 | void ssl_closed()
|
---|
245 | {
|
---|
246 | printf("Closing.\n");
|
---|
247 | sock->close();
|
---|
248 | }
|
---|
249 |
|
---|
250 | void ssl_error(int x)
|
---|
251 | {
|
---|
252 | if(x == QCA::TLS::ErrHandshake) {
|
---|
253 | printf("SSL Handshake Error! Closing.\n");
|
---|
254 | sock->close();
|
---|
255 | }
|
---|
256 | else {
|
---|
257 | printf("SSL Error! Closing.\n");
|
---|
258 | sock->close();
|
---|
259 | }
|
---|
260 | }
|
---|
261 |
|
---|
262 | private:
|
---|
263 | int port;
|
---|
264 | QSocket *sock;
|
---|
265 | QCA::TLS *ssl;
|
---|
266 | QCA::Cert cert;
|
---|
267 | QCA::RSAKey privkey;
|
---|
268 |
|
---|
269 | bool sent;
|
---|
270 | int mode;
|
---|
271 | int bytesLeft;
|
---|
272 | LayerTracker layer;
|
---|
273 | };
|
---|
274 |
|
---|
275 | #include"sslservtest.moc"
|
---|
276 |
|
---|
277 | int main(int argc, char **argv)
|
---|
278 | {
|
---|
279 | QApplication app(argc, argv, false);
|
---|
280 | int port = argc > 1 ? QString(argv[1]).toInt() : 8000;
|
---|
281 |
|
---|
282 | if(!QCA::isSupported(QCA::CAP_TLS)) {
|
---|
283 | printf("TLS not supported!\n");
|
---|
284 | return 1;
|
---|
285 | }
|
---|
286 |
|
---|
287 | SecureServerTest *s = new SecureServerTest(port);
|
---|
288 | QObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
|
---|
289 | s->start();
|
---|
290 | app.exec();
|
---|
291 | delete s;
|
---|
292 |
|
---|
293 | return 0;
|
---|
294 | }
|
---|