| 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 | }
|
|---|