blob: 47288fae61d086243513c6dec927c32d4cdbed18 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pj/ssl_sock.h>
20#include <pj/compat/socket.h>
21#include <pj/assert.h>
22#include <pj/errno.h>
23#include <pj/math.h>
24#include <pj/pool.h>
25#include <pj/sock.h>
26#include <pj/string.h>
27
28#include "os_symbian.h"
29#include <securesocket.h>
30#include <x509cert.h>
31#include <e32des8.h>
32
33#define THIS_FILE "ssl_sock_symbian.cpp"
34
35
36/* Cipher name structure */
37typedef struct cipher_name_t {
38 pj_ssl_cipher cipher;
39 const char *name;
40} cipher_name_t;
41
42/* Cipher name constants */
43static cipher_name_t cipher_names[] =
44{
45 {PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
46
47 /* TLS/SSLv3 */
48 {PJ_TLS_RSA_WITH_NULL_MD5, "TLS_RSA_WITH_NULL_MD5"},
49 {PJ_TLS_RSA_WITH_NULL_SHA, "TLS_RSA_WITH_NULL_SHA"},
50 {PJ_TLS_RSA_WITH_NULL_SHA256, "TLS_RSA_WITH_NULL_SHA256"},
51 {PJ_TLS_RSA_WITH_RC4_128_MD5, "TLS_RSA_WITH_RC4_128_MD5"},
52 {PJ_TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA"},
53 {PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
54 {PJ_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
55 {PJ_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
56 {PJ_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
57 {PJ_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
58 {PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
59 {PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
60 {PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
61 {PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
62 {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
63 {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
64 {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
65 {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
66 {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
67 {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
68 {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
69 {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
70 {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
71 {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
72 {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
73 {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
74 {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
75 {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
76 {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
77 {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
78 {PJ_TLS_DH_anon_WITH_RC4_128_MD5, "TLS_DH_anon_WITH_RC4_128_MD5"},
79 {PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
80 {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
81 {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
82 {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
83 {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
84
85 /* TLS (deprecated) */
86 {PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
87 {PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
88 {PJ_TLS_RSA_WITH_IDEA_CBC_SHA, "TLS_RSA_WITH_IDEA_CBC_SHA"},
89 {PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
90 {PJ_TLS_RSA_WITH_DES_CBC_SHA, "TLS_RSA_WITH_DES_CBC_SHA"},
91 {PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
92 {PJ_TLS_DH_DSS_WITH_DES_CBC_SHA, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
93 {PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
94 {PJ_TLS_DH_RSA_WITH_DES_CBC_SHA, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
95 {PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
96 {PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
97 {PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
98 {PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
99 {PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
100 {PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
101 {PJ_TLS_DH_anon_WITH_DES_CBC_SHA, "TLS_DH_anon_WITH_DES_CBC_SHA"},
102
103 /* SSLv3 */
104 {PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA, "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
105 {PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
106 {PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
107
108 /* SSLv2 */
109 {PJ_SSL_CK_RC4_128_WITH_MD5, "SSL_CK_RC4_128_WITH_MD5"},
110 {PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
111 {PJ_SSL_CK_RC2_128_CBC_WITH_MD5, "SSL_CK_RC2_128_CBC_WITH_MD5"},
112 {PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
113 {PJ_SSL_CK_IDEA_128_CBC_WITH_MD5, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
114 {PJ_SSL_CK_DES_64_CBC_WITH_MD5, "SSL_CK_DES_64_CBC_WITH_MD5"},
115 {PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
116};
117
118
119/* Get cipher name string */
120static const char* get_cipher_name(pj_ssl_cipher cipher)
121{
122 unsigned i, n;
123
124 n = PJ_ARRAY_SIZE(cipher_names);
125 for (i = 0; i < n; ++i) {
126 if (cipher == cipher_names[i].cipher)
127 return cipher_names[i].name;
128 }
129
130 return "CIPHER_UNKNOWN";
131}
132
133typedef void (*CPjSSLSocket_cb)(int err, void *key);
134
135class CPjSSLSocketReader : public CActive
136{
137public:
138 static CPjSSLSocketReader *NewL(CSecureSocket &sock)
139 {
140 CPjSSLSocketReader *self = new (ELeave)
141 CPjSSLSocketReader(sock);
142 CleanupStack::PushL(self);
143 self->ConstructL();
144 CleanupStack::Pop(self);
145 return self;
146 }
147
148 ~CPjSSLSocketReader() {
149 Cancel();
150 }
151
152 /* Asynchronous read from the socket. */
153 int Read(CPjSSLSocket_cb cb, void *key, TPtr8 &data, TUint flags)
154 {
155 PJ_ASSERT_RETURN(!IsActive(), PJ_EBUSY);
156
157 cb_ = cb;
158 key_ = key;
159 sock_.RecvOneOrMore(data, iStatus, len_received_);
160 SetActive();
161
162 return PJ_EPENDING;
163 }
164
165private:
166 CSecureSocket &sock_;
167 CPjSSLSocket_cb cb_;
168 void *key_;
169 TSockXfrLength len_received_; /* not really useful? */
170
171 void DoCancel() {
172 sock_.CancelAll();
173 }
174
175 void RunL() {
176 (*cb_)(iStatus.Int(), key_);
177 }
178
179 CPjSSLSocketReader(CSecureSocket &sock) :
180 CActive(0), sock_(sock), cb_(NULL), key_(NULL)
181 {}
182
183 void ConstructL() {
184 CActiveScheduler::Add(this);
185 }
186};
187
188class CPjSSLSocket : public CActive
189{
190public:
191 enum ssl_state {
192 SSL_STATE_NULL,
193 SSL_STATE_CONNECTING,
194 SSL_STATE_HANDSHAKING,
195 SSL_STATE_ESTABLISHED
196 };
197
198 static CPjSSLSocket *NewL(const TDesC8 &ssl_proto,
199 pj_qos_type qos_type,
200 const pj_qos_params &qos_params)
201 {
202 CPjSSLSocket *self = new (ELeave) CPjSSLSocket(qos_type, qos_params);
203 CleanupStack::PushL(self);
204 self->ConstructL(ssl_proto);
205 CleanupStack::Pop(self);
206 return self;
207 }
208
209 ~CPjSSLSocket() {
210 Cancel();
211 CleanupSubObjects();
212 }
213
214 int Connect(CPjSSLSocket_cb cb, void *key, const TInetAddr &local_addr,
215 const TInetAddr &rem_addr,
216 const TDesC8 &servername = TPtrC8(NULL,0),
217 const TDesC8 &ciphers = TPtrC8(NULL,0));
218 int Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc, TUint flags);
219 int SendSync(const TDesC8 &aDesc, TUint flags);
220
221 CPjSSLSocketReader* GetReader();
222 enum ssl_state GetState() const { return state_; }
223 const TInetAddr* GetLocalAddr() const { return &local_addr_; }
224 int GetCipher(TDes8 &cipher) const {
225 if (securesock_)
226 return securesock_->CurrentCipherSuite(cipher);
227 return KErrNotFound;
228 }
229 const CX509Certificate *GetPeerCert() {
230 if (securesock_)
231 return securesock_->ServerCert();
232 return NULL;
233 }
234
235private:
236 enum ssl_state state_;
237 pj_sock_t sock_;
238 CSecureSocket *securesock_;
239 bool is_connected_;
240
241 pj_qos_type qos_type_;
242 pj_qos_params qos_params_;
243
244 CPjSSLSocketReader *reader_;
245 TBuf<32> ssl_proto_;
246 TInetAddr rem_addr_;
247 TPtrC8 servername_;
248 TPtrC8 ciphers_;
249 TInetAddr local_addr_;
250 TSockXfrLength sent_len_;
251
252 CPjSSLSocket_cb cb_;
253 void *key_;
254
255 void DoCancel();
256 void RunL();
257
258 CPjSSLSocket(pj_qos_type qos_type, const pj_qos_params &qos_params) :
259 CActive(0), state_(SSL_STATE_NULL), sock_(PJ_INVALID_SOCKET),
260 securesock_(NULL), is_connected_(false),
261 qos_type_(qos_type), qos_params_(qos_params),
262 reader_(NULL), cb_(NULL), key_(NULL)
263 {}
264
265 void ConstructL(const TDesC8 &ssl_proto) {
266 ssl_proto_.Copy(ssl_proto);
267 CActiveScheduler::Add(this);
268 }
269
270 void CleanupSubObjects() {
271 delete reader_;
272 reader_ = NULL;
273 if (securesock_) {
274 if (state_ == SSL_STATE_ESTABLISHED)
275 securesock_->Close();
276 delete securesock_;
277 securesock_ = NULL;
278 }
279 if (sock_ != PJ_INVALID_SOCKET) {
280 pj_sock_close(sock_);
281 sock_ = PJ_INVALID_SOCKET;
282 }
283 }
284};
285
286int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
287 const TInetAddr &local_addr,
288 const TInetAddr &rem_addr,
289 const TDesC8 &servername,
290 const TDesC8 &ciphers)
291{
292 pj_status_t status;
293
294 PJ_ASSERT_RETURN(state_ == SSL_STATE_NULL, PJ_EINVALIDOP);
295
296 status = pj_sock_socket(rem_addr.Family(), pj_SOCK_STREAM(), 0, &sock_);
297 if (status != PJ_SUCCESS)
298 return status;
299
300 // Apply QoS
301 status = pj_sock_apply_qos2(sock_, qos_type_, &qos_params_,
302 2, THIS_FILE, NULL);
303
304 RSocket &rSock = ((CPjSocket*)sock_)->Socket();
305
306 local_addr_ = local_addr;
307
308 if (!local_addr_.IsUnspecified()) {
309 TInt err = rSock.Bind(local_addr_);
310 if (err != KErrNone)
311 return PJ_RETURN_OS_ERROR(err);
312 }
313
314 cb_ = cb;
315 key_ = key;
316 rem_addr_ = rem_addr;
317
318 /* Note: the following members only keep the pointer, not the data */
319 servername_.Set(servername);
320 ciphers_.Set(ciphers);
321
322 rSock.Connect(rem_addr_, iStatus);
323 SetActive();
324 state_ = SSL_STATE_CONNECTING;
325
326 rSock.LocalName(local_addr_);
327
328 return PJ_EPENDING;
329}
330
331int CPjSSLSocket::Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc,
332 TUint flags)
333{
334 PJ_UNUSED_ARG(flags);
335
336 PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
337
338 if (IsActive())
339 return PJ_EBUSY;
340
341 cb_ = cb;
342 key_ = key;
343
344 securesock_->Send(aDesc, iStatus, sent_len_);
345 SetActive();
346
347 return PJ_EPENDING;
348}
349
350int CPjSSLSocket::SendSync(const TDesC8 &aDesc, TUint flags)
351{
352 PJ_UNUSED_ARG(flags);
353
354 PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
355
356 TRequestStatus reqStatus;
357 securesock_->Send(aDesc, reqStatus, sent_len_);
358 User::WaitForRequest(reqStatus);
359
360 return PJ_RETURN_OS_ERROR(reqStatus.Int());
361}
362
363CPjSSLSocketReader* CPjSSLSocket::GetReader()
364{
365 PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, NULL);
366
367 if (reader_)
368 return reader_;
369
370 TRAPD(err, reader_ = CPjSSLSocketReader::NewL(*securesock_));
371 if (err != KErrNone)
372 return NULL;
373
374 return reader_;
375}
376
377void CPjSSLSocket::DoCancel()
378{
379 /* Operation to be cancelled depends on current state */
380 switch (state_) {
381 case SSL_STATE_CONNECTING:
382 {
383 RSocket &rSock = ((CPjSocket*)sock_)->Socket();
384
385 rSock.CancelConnect();
386 CleanupSubObjects();
387 state_ = SSL_STATE_NULL;
388 }
389 break;
390 case SSL_STATE_HANDSHAKING:
391 {
392 securesock_->CancelHandshake();
393 CleanupSubObjects();
394 state_ = SSL_STATE_NULL;
395 }
396 break;
397 case SSL_STATE_ESTABLISHED:
398 securesock_->CancelSend();
399 break;
400 default:
401 break;
402 }
403}
404
405void CPjSSLSocket::RunL()
406{
407 switch (state_) {
408 case SSL_STATE_CONNECTING:
409 if (iStatus != KErrNone) {
410 CleanupSubObjects();
411 state_ = SSL_STATE_NULL;
412 /* Dispatch connect failure notification */
413 if (cb_) (*cb_)(iStatus.Int(), key_);
414 } else {
415 RSocket &rSock = ((CPjSocket*)sock_)->Socket();
416
417 /* Get local addr */
418 rSock.LocalName(local_addr_);
419
420 /* Prepare and start handshake */
421 securesock_ = CSecureSocket::NewL(rSock, ssl_proto_);
422 securesock_->SetDialogMode(EDialogModeAttended);
423 if (servername_.Length() > 0)
424 securesock_->SetOpt(KSoSSLDomainName, KSolInetSSL,
425 servername_);
426 if (ciphers_.Length() > 0)
427 securesock_->SetAvailableCipherSuites(ciphers_);
428
429 // FlushSessionCache() seems to also fire signals to all
430 // completed AOs (something like CActiveScheduler::RunIfReady())
431 // which may cause problem, e.g: we've experienced that when
432 // SSL timeout is set to 1s, the SSL timeout timer fires up
433 // at this point and securesock_ instance gets deleted here!
434 // So be careful using this. And we don't think we need it here.
435 //securesock_->FlushSessionCache();
436
437 securesock_->StartClientHandshake(iStatus);
438 SetActive();
439 state_ = SSL_STATE_HANDSHAKING;
440 }
441 break;
442 case SSL_STATE_HANDSHAKING:
443 if (iStatus == KErrNone) {
444 state_ = SSL_STATE_ESTABLISHED;
445 } else {
446 state_ = SSL_STATE_NULL;
447 CleanupSubObjects();
448 }
449 /* Dispatch connect status notification */
450 if (cb_) (*cb_)(iStatus.Int(), key_);
451 break;
452 case SSL_STATE_ESTABLISHED:
453 /* Dispatch data sent notification */
454 if (cb_) (*cb_)(iStatus.Int(), key_);
455 break;
456 default:
457 pj_assert(0);
458 break;
459 }
460}
461
462typedef void (*CPjTimer_cb)(void *user_data);
463
464class CPjTimer : public CActive
465{
466public:
467 CPjTimer(const pj_time_val *delay, CPjTimer_cb cb, void *user_data) :
468 CActive(0), cb_(cb), user_data_(user_data)
469 {
470 CActiveScheduler::Add(this);
471
472 rtimer_.CreateLocal();
473 pj_int32_t interval = PJ_TIME_VAL_MSEC(*delay) * 1000;
474 if (interval < 0) {
475 interval = 0;
476 }
477 rtimer_.After(iStatus, interval);
478 SetActive();
479 }
480
481 ~CPjTimer() { Cancel(); }
482
483private:
484 RTimer rtimer_;
485 CPjTimer_cb cb_;
486 void *user_data_;
487
488 void RunL() { if (cb_) (*cb_)(user_data_); }
489 void DoCancel() { rtimer_.Cancel(); }
490};
491
492/*
493 * Structure of recv/read state.
494 */
495typedef struct read_state_t {
496 TPtr8 *read_buf;
497 TPtr8 *orig_buf;
498 pj_uint32_t flags;
499} read_state_t;
500
501/*
502 * Structure of send/write data.
503 */
504typedef struct write_data_t {
505 pj_size_t len;
506 pj_ioqueue_op_key_t *key;
507 pj_size_t data_len;
508 char data[1];
509} write_data_t;
510
511/*
512 * Structure of send/write state.
513 */
514typedef struct write_state_t {
515 char *buf;
516 pj_size_t max_len;
517 char *start;
518 pj_size_t len;
519 write_data_t *current_data;
520 TPtrC8 send_ptr;
521} write_state_t;
522
523/*
524 * Secure socket structure definition.
525 */
526struct pj_ssl_sock_t
527{
528 pj_pool_t *pool;
529 pj_ssl_sock_cb cb;
530 void *user_data;
531
532 pj_bool_t established;
533 write_state_t write_state;
534 read_state_t read_state;
535 CPjTimer *connect_timer;
536
537 CPjSSLSocket *sock;
538 int sock_af;
539 int sock_type;
540 pj_sockaddr local_addr;
541 pj_sockaddr rem_addr;
542
543 /* QoS settings */
544 pj_qos_type qos_type;
545 pj_qos_params qos_params;
546 pj_bool_t qos_ignore_error;
547
548
549 pj_ssl_sock_proto proto;
550 pj_time_val timeout;
551 pj_str_t servername;
552 pj_str_t ciphers;
553 pj_ssl_cert_info remote_cert_info;
554};
555
556
557static pj_str_t get_cert_name(char *buf, unsigned buf_len,
558 const CX500DistinguishedName &name)
559{
560 TInt i;
561 TUint8 *p;
562 TInt l = buf_len;
563
564 p = (TUint8*)buf;
565 for(i = 0; i < name.Count(); ++i) {
566 const CX520AttributeTypeAndValue &attr = name.Element(i);
567
568 /* Print element separator */
569 *p++ = '/';
570 if (0 == --l) break;
571
572 /* Print the type. */
573 TPtr8 type(p, l);
574 type.Copy(attr.Type());
575 p += type.Length();
576 l -= type.Length();
577 if (0 >= --l) break;
578
579 /* Print equal sign */
580 *p++ = '=';
581 if (0 == --l) break;
582
583 /* Print the value. Let's just get the raw data here */
584 TPtr8 value(p, l);
585 value.Copy(attr.EncodedValue().Mid(2));
586 p += value.Length();
587 l -= value.Length();
588 if (0 >= --l) break;
589 }
590
591 pj_str_t src;
592 pj_strset(&src, buf, buf_len - l);
593
594 return src;
595}
596
597/* Get certificate info from CX509Certificate.
598 */
599static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci,
600 const CX509Certificate *x)
601{
602 enum { tmp_buf_len = 512 };
603 char *tmp_buf;
604 unsigned len;
605
606 pj_assert(pool && ci && x);
607
608 /* Init */
609 tmp_buf = new char[tmp_buf_len];
610 pj_bzero(ci, sizeof(*ci));
611
612 /* Version */
613 ci->version = x->Version();
614
615 /* Serial number */
616 len = x->SerialNumber().Length();
617 if (len > sizeof(ci->serial_no))
618 len = sizeof(ci->serial_no);
619 pj_memcpy(ci->serial_no + sizeof(ci->serial_no) - len,
620 x->SerialNumber().Ptr(), len);
621
622 /* Subject */
623 {
624 HBufC *subject = NULL;
625 TRAPD(err, subject = x->SubjectL());
626 if (err == KErrNone) {
627 TPtr16 ptr16(subject->Des());
628 len = ptr16.Length();
629 TPtr8 ptr8((TUint8*)pj_pool_alloc(pool, len), len);
630 ptr8.Copy(ptr16);
631 pj_strset(&ci->subject.cn, (char*)ptr8.Ptr(), ptr8.Length());
632 }
633 pj_str_t tmp = get_cert_name(tmp_buf, tmp_buf_len,
634 x->SubjectName());
635 pj_strdup(pool, &ci->subject.info, &tmp);
636 }
637
638 /* Issuer */
639 {
640 HBufC *issuer = NULL;
641 TRAPD(err, issuer = x->IssuerL());
642 if (err == KErrNone) {
643 TPtr16 ptr16(issuer->Des());
644 len = ptr16.Length();
645 TPtr8 ptr8((TUint8*)pj_pool_alloc(pool, len), len);
646 ptr8.Copy(ptr16);
647 pj_strset(&ci->issuer.cn, (char*)ptr8.Ptr(), ptr8.Length());
648 }
649 pj_str_t tmp = get_cert_name(tmp_buf, tmp_buf_len,
650 x->IssuerName());
651 pj_strdup(pool, &ci->issuer.info, &tmp);
652 }
653
654 /* Validity */
655 const CValidityPeriod &valid_period = x->ValidityPeriod();
656 TTime base_time(TDateTime(1970, EJanuary, 0, 0, 0, 0, 0));
657 TTimeIntervalSeconds tmp_sec;
658 valid_period.Start().SecondsFrom(base_time, tmp_sec);
659 ci->validity.start.sec = tmp_sec.Int();
660 valid_period.Finish().SecondsFrom(base_time, tmp_sec);
661 ci->validity.end.sec = tmp_sec.Int();
662
663 /* Deinit */
664 delete [] tmp_buf;
665}
666
667
668/* Update certificates info. This function should be called after handshake
669 * or renegotiation successfully completed.
670 */
671static void update_certs_info(pj_ssl_sock_t *ssock)
672{
673 const CX509Certificate *x;
674
675 pj_assert(ssock && ssock->sock &&
676 ssock->sock->GetState() == CPjSSLSocket::SSL_STATE_ESTABLISHED);
677
678 /* Active remote certificate */
679 x = ssock->sock->GetPeerCert();
680 if (x) {
681 get_cert_info(ssock->pool, &ssock->remote_cert_info, x);
682 } else {
683 pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
684 }
685}
686
687
688/* Available ciphers */
689static unsigned ciphers_num_ = 0;
690static struct ciphers_t
691{
692 pj_ssl_cipher id;
693 const char *name;
694} ciphers_[64];
695
696/*
697 * Get cipher list supported by SSL/TLS backend.
698 */
699PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
700 unsigned *cipher_num)
701{
702 unsigned i;
703
704 PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
705
706 if (ciphers_num_ == 0) {
707 RSocket sock;
708 CSecureSocket *secure_sock;
709 TPtrC16 proto(_L16("TLS1.0"));
710
711 secure_sock = CSecureSocket::NewL(sock, proto);
712 if (secure_sock) {
713 TBuf8<128> ciphers_buf(0);
714 secure_sock->AvailableCipherSuites(ciphers_buf);
715
716 ciphers_num_ = ciphers_buf.Length() / 2;
717 if (ciphers_num_ > PJ_ARRAY_SIZE(ciphers_))
718 ciphers_num_ = PJ_ARRAY_SIZE(ciphers_);
719 for (i = 0; i < ciphers_num_; ++i) {
720 ciphers_[i].id = (pj_ssl_cipher)(ciphers_buf[i*2]*10 +
721 ciphers_buf[i*2+1]);
722 ciphers_[i].name = get_cipher_name(ciphers_[i].id);
723 }
724 }
725
726 delete secure_sock;
727 }
728
729 if (ciphers_num_ == 0) {
730 *cipher_num = 0;
731 return PJ_ENOTFOUND;
732 }
733
734 *cipher_num = PJ_MIN(*cipher_num, ciphers_num_);
735 for (i = 0; i < *cipher_num; ++i)
736 ciphers[i] = ciphers_[i].id;
737
738 return PJ_SUCCESS;
739}
740
741
742/* Get cipher name string */
743PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
744{
745 unsigned i;
746
747 if (ciphers_num_ == 0) {
748 pj_ssl_cipher c[1];
749 i = 0;
750 pj_ssl_cipher_get_availables(c, &i);
751 }
752
753 for (i = 0; i < ciphers_num_; ++i) {
754 if (cipher == ciphers_[i].id)
755 return ciphers_[i].name;
756 }
757
758 return NULL;
759}
760
761
762/* Check if the specified cipher is supported by SSL/TLS backend. */
763PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
764{
765 unsigned i;
766
767 if (ciphers_num_ == 0) {
768 pj_ssl_cipher c[1];
769 i = 0;
770 pj_ssl_cipher_get_availables(c, &i);
771 }
772
773 for (i = 0; i < ciphers_num_; ++i) {
774 if (cipher == ciphers_[i].id)
775 return PJ_TRUE;
776 }
777
778 return PJ_FALSE;
779}
780
781
782/*
783 * Create SSL socket instance.
784 */
785PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
786 const pj_ssl_sock_param *param,
787 pj_ssl_sock_t **p_ssock)
788{
789 pj_ssl_sock_t *ssock;
790
791 PJ_ASSERT_RETURN(param->async_cnt == 1, PJ_EINVAL);
792 PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
793
794 /* Allocate secure socket */
795 ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
796
797 /* Allocate write buffer */
798 ssock->write_state.buf = (char*)pj_pool_alloc(pool,
799 param->send_buffer_size);
800 ssock->write_state.max_len = param->send_buffer_size;
801 ssock->write_state.start = ssock->write_state.buf;
802
803 /* Init secure socket */
804 ssock->pool = pool;
805 ssock->sock_af = param->sock_af;
806 ssock->sock_type = param->sock_type;
807 ssock->cb = param->cb;
808 ssock->user_data = param->user_data;
809 ssock->timeout = param->timeout;
810 if (param->ciphers_num > 0) {
811 /* Cipher list in Symbian is represented as array of two-octets. */
812 ssock->ciphers.slen = param->ciphers_num*2;
813 ssock->ciphers.ptr = (char*)pj_pool_alloc(pool, ssock->ciphers.slen);
814 pj_uint8_t *c = (pj_uint8_t*)ssock->ciphers.ptr;
815 for (unsigned i = 0; i < param->ciphers_num; ++i) {
816 *c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF00) >> 8;
817 *c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF);
818 }
819 }
820 pj_strdup_with_null(pool, &ssock->servername, &param->server_name);
821
822 ssock->qos_type = param->qos_type;
823 ssock->qos_ignore_error = param->qos_ignore_error;
824 pj_memcpy(&ssock->qos_params, &param->qos_params,
825 sizeof(param->qos_params));
826
827 /* Finally */
828 *p_ssock = ssock;
829
830 return PJ_SUCCESS;
831}
832
833
834PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files(pj_pool_t *pool,
835 const pj_str_t *CA_file,
836 const pj_str_t *cert_file,
837 const pj_str_t *privkey_file,
838 const pj_str_t *privkey_pass,
839 pj_ssl_cert_t **p_cert)
840{
841 PJ_UNUSED_ARG(pool);
842 PJ_UNUSED_ARG(CA_file);
843 PJ_UNUSED_ARG(cert_file);
844 PJ_UNUSED_ARG(privkey_file);
845 PJ_UNUSED_ARG(privkey_pass);
846 PJ_UNUSED_ARG(p_cert);
847 return PJ_ENOTSUP;
848}
849
850/*
851 * Set SSL socket credential.
852 */
853PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
854 pj_ssl_sock_t *ssock,
855 pj_pool_t *pool,
856 const pj_ssl_cert_t *cert)
857{
858 PJ_UNUSED_ARG(ssock);
859 PJ_UNUSED_ARG(pool);
860 PJ_UNUSED_ARG(cert);
861 return PJ_ENOTSUP;
862}
863
864/*
865 * Close the SSL socket.
866 */
867PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
868{
869 PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
870
871 delete ssock->connect_timer;
872 ssock->connect_timer = NULL;
873
874 delete ssock->sock;
875 ssock->sock = NULL;
876
877 delete ssock->read_state.read_buf;
878 delete ssock->read_state.orig_buf;
879 ssock->read_state.read_buf = NULL;
880 ssock->read_state.orig_buf = NULL;
881
882 return PJ_SUCCESS;
883}
884
885
886/*
887 * Associate arbitrary data with the SSL socket.
888 */
889PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data (pj_ssl_sock_t *ssock,
890 void *user_data)
891{
892 PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
893
894 ssock->user_data = user_data;
895
896 return PJ_SUCCESS;
897}
898
899
900/*
901 * Retrieve the user data previously associated with this SSL
902 * socket.
903 */
904PJ_DEF(void*) pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
905{
906 PJ_ASSERT_RETURN(ssock, NULL);
907
908 return ssock->user_data;
909}
910
911
912/*
913 * Retrieve the local address and port used by specified SSL socket.
914 */
915PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
916 pj_ssl_sock_info *info)
917{
918 PJ_ASSERT_RETURN(ssock && info, PJ_EINVAL);
919
920 pj_bzero(info, sizeof(*info));
921
922 info->established = ssock->established;
923
924 /* Local address */
925 if (ssock->sock) {
926 const TInetAddr* local_addr_ = ssock->sock->GetLocalAddr();
927 int addrlen = sizeof(pj_sockaddr);
928 pj_status_t status;
929
930 status = PjSymbianOS::Addr2pj(*local_addr_, info->local_addr, &addrlen);
931 if (status != PJ_SUCCESS)
932 return status;
933 } else {
934 pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
935 }
936
937 if (info->established) {
938 /* Cipher suite */
939 TBuf8<4> cipher;
940 if (ssock->sock->GetCipher(cipher) == KErrNone) {
941 info->cipher = (pj_ssl_cipher)cipher[1];
942 }
943
944 /* Remote address */
945 pj_sockaddr_cp((pj_sockaddr_t*)&info->remote_addr,
946 (pj_sockaddr_t*)&ssock->rem_addr);
947
948 /* Certificates info */
949 info->remote_cert_info = &ssock->remote_cert_info;
950 }
951
952 /* Protocol */
953 info->proto = ssock->proto;
954
955 return PJ_SUCCESS;
956}
957
958
959/*
960 * Starts read operation on this SSL socket.
961 */
962PJ_DEF(pj_status_t) pj_ssl_sock_start_read (pj_ssl_sock_t *ssock,
963 pj_pool_t *pool,
964 unsigned buff_size,
965 pj_uint32_t flags)
966{
967 PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
968 PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
969
970 /* Reading is already started */
971 if (ssock->read_state.orig_buf) {
972 return PJ_SUCCESS;
973 }
974
975 void *readbuf[1];
976 readbuf[0] = pj_pool_alloc(pool, buff_size);
977 return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
978}
979
980static void read_cb(int err, void *key)
981{
982 pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
983 pj_status_t status;
984
985 status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
986
987 /* Check connection status */
988 if (err == KErrEof || !PjSymbianOS::Instance()->IsConnectionUp() ||
989 !ssock->established)
990 {
991 status = PJ_EEOF;
992 }
993
994 /* Notify data arrival */
995 if (ssock->cb.on_data_read) {
996 pj_size_t remainder = 0;
997 char *data = (char*)ssock->read_state.orig_buf->Ptr();
998 pj_size_t data_len = ssock->read_state.read_buf->Length() +
999 ssock->read_state.read_buf->Ptr() -
1000 ssock->read_state.orig_buf->Ptr();
1001
1002 if (data_len > 0) {
1003 /* Notify received data */
1004 pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, data, data_len,
1005 status, &remainder);
1006 if (!ret) {
1007 /* We've been destroyed */
1008 return;
1009 }
1010
1011 /* Calculate available data for next READ operation */
1012 if (remainder > 0) {
1013 pj_size_t data_maxlen = ssock->read_state.orig_buf->MaxLength();
1014
1015 /* There is some data left unconsumed by application, we give
1016 * smaller buffer for next READ operation.
1017 */
1018 ssock->read_state.read_buf->Set((TUint8*)data+remainder, 0,
1019 data_maxlen - remainder);
1020 } else {
1021 /* Give all buffer for next READ operation.
1022 */
1023 ssock->read_state.read_buf->Set(*ssock->read_state.orig_buf);
1024 }
1025 }
1026 }
1027
1028 if (status == PJ_SUCCESS) {
1029 /* Perform the "next" READ operation */
1030 CPjSSLSocketReader *reader = ssock->sock->GetReader();
1031 ssock->read_state.read_buf->SetLength(0);
1032 status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf,
1033 ssock->read_state.flags);
1034 }
1035
1036 /* Connection closed or something goes wrong */
1037 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
1038 /* Notify error */
1039 if (ssock->cb.on_data_read) {
1040 pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, NULL, 0,
1041 status, NULL);
1042 if (!ret) {
1043 /* We've been destroyed */
1044 return;
1045 }
1046 }
1047
1048 delete ssock->read_state.read_buf;
1049 delete ssock->read_state.orig_buf;
1050 ssock->read_state.read_buf = NULL;
1051 ssock->read_state.orig_buf = NULL;
1052 ssock->established = PJ_FALSE;
1053 }
1054}
1055
1056/*
1057 * Same as #pj_ssl_sock_start_read(), except that the application
1058 * supplies the buffers for the read operation so that the acive socket
1059 * does not have to allocate the buffers.
1060 */
1061PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
1062 pj_pool_t *pool,
1063 unsigned buff_size,
1064 void *readbuf[],
1065 pj_uint32_t flags)
1066{
1067 PJ_ASSERT_RETURN(ssock && buff_size && readbuf, PJ_EINVAL);
1068 PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
1069
1070 /* Return failure if access point is marked as down by app. */
1071 PJ_SYMBIAN_CHECK_CONNECTION();
1072
1073 /* Reading is already started */
1074 if (ssock->read_state.orig_buf) {
1075 return PJ_SUCCESS;
1076 }
1077
1078 PJ_UNUSED_ARG(pool);
1079
1080 /* Get reader instance */
1081 CPjSSLSocketReader *reader = ssock->sock->GetReader();
1082 if (!reader)
1083 return PJ_ENOMEM;
1084
1085 /* We manage two buffer pointers here:
1086 * 1. orig_buf keeps the orginal buffer address (and its max length).
1087 * 2. read_buf provides buffer for READ operation, mind that there may be
1088 * some remainder data left by application.
1089 */
1090 ssock->read_state.read_buf = new TPtr8((TUint8*)readbuf[0], 0, buff_size);
1091 ssock->read_state.orig_buf = new TPtr8((TUint8*)readbuf[0], 0, buff_size);
1092 ssock->read_state.flags = flags;
1093
1094 pj_status_t status;
1095 status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf,
1096 ssock->read_state.flags);
1097
1098 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
1099 delete ssock->read_state.read_buf;
1100 delete ssock->read_state.orig_buf;
1101 ssock->read_state.read_buf = NULL;
1102 ssock->read_state.orig_buf = NULL;
1103
1104 return status;
1105 }
1106
1107 return PJ_SUCCESS;
1108}
1109
1110/*
1111 * Same as pj_ssl_sock_start_read(), except that this function is used
1112 * only for datagram sockets, and it will trigger \a on_data_recvfrom()
1113 * callback instead.
1114 */
1115PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
1116 pj_pool_t *pool,
1117 unsigned buff_size,
1118 pj_uint32_t flags)
1119{
1120 PJ_UNUSED_ARG(ssock);
1121 PJ_UNUSED_ARG(pool);
1122 PJ_UNUSED_ARG(buff_size);
1123 PJ_UNUSED_ARG(flags);
1124 return PJ_ENOTSUP;
1125}
1126
1127/*
1128 * Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom()
1129 * operation takes the buffer from the argument rather than creating
1130 * new ones.
1131 */
1132PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
1133 pj_pool_t *pool,
1134 unsigned buff_size,
1135 void *readbuf[],
1136 pj_uint32_t flags)
1137{
1138 PJ_UNUSED_ARG(ssock);
1139 PJ_UNUSED_ARG(pool);
1140 PJ_UNUSED_ARG(buff_size);
1141 PJ_UNUSED_ARG(readbuf);
1142 PJ_UNUSED_ARG(flags);
1143 return PJ_ENOTSUP;
1144}
1145
1146static void send_cb(int err, void *key)
1147{
1148 pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
1149 write_state_t *st = &ssock->write_state;
1150
1151 /* Check connection status */
1152 if (err != KErrNone || !PjSymbianOS::Instance()->IsConnectionUp() ||
1153 !ssock->established)
1154 {
1155 ssock->established = PJ_FALSE;
1156 return;
1157 }
1158
1159 /* Remove sent data from buffer */
1160 st->start += st->current_data->len;
1161 st->len -= st->current_data->len;
1162
1163 /* Reset current outstanding send */
1164 st->current_data = NULL;
1165
1166 /* Let's check if there is pending data to send */
1167 if (st->len) {
1168 write_data_t *wdata = (write_data_t*)st->start;
1169 pj_status_t status;
1170
1171 st->send_ptr.Set((TUint8*)wdata->data, (TInt)wdata->data_len);
1172 st->current_data = wdata;
1173 status = ssock->sock->Send(&send_cb, ssock, st->send_ptr, 0);
1174 if (status != PJ_EPENDING) {
1175 ssock->established = PJ_FALSE;
1176 st->len = 0;
1177 return;
1178 }
1179 } else {
1180 /* Buffer empty, reset the start position */
1181 st->start = st->buf;
1182 }
1183}
1184
1185/*
1186 * Send data using the socket.
1187 */
1188PJ_DEF(pj_status_t) pj_ssl_sock_send (pj_ssl_sock_t *ssock,
1189 pj_ioqueue_op_key_t *send_key,
1190 const void *data,
1191 pj_ssize_t *size,
1192 unsigned flags)
1193{
1194 PJ_CHECK_STACK();
1195 PJ_ASSERT_RETURN(ssock && data && size, PJ_EINVAL);
1196 PJ_ASSERT_RETURN(ssock->write_state.max_len == 0 ||
1197 ssock->write_state.max_len >= (pj_size_t)*size,
1198 PJ_ETOOSMALL);
1199
1200 /* Check connection status */
1201 if (!PjSymbianOS::Instance()->IsConnectionUp() || !ssock->established)
1202 {
1203 ssock->established = PJ_FALSE;
1204 return PJ_ECANCELLED;
1205 }
1206
1207 write_state_t *st = &ssock->write_state;
1208
1209 /* Synchronous mode */
1210 if (st->max_len == 0) {
1211 st->send_ptr.Set((TUint8*)data, (TInt)*size);
1212 return ssock->sock->SendSync(st->send_ptr, flags);
1213 }
1214
1215 /* CSecureSocket only allows one outstanding send operation, so
1216 * we use buffering mechanism to allow application to perform send
1217 * operations at any time.
1218 */
1219
1220 pj_size_t needed_len = *size + sizeof(write_data_t) - 1;
1221
1222 /* Align needed_len to be multiplication of 4 */
1223 needed_len = ((needed_len + 3) >> 2) << 2;
1224
1225 /* Block until there is buffer slot available and contiguous! */
1226 while (st->start + st->len + needed_len > st->buf + st->max_len) {
1227 pj_symbianos_poll(-1, -1);
1228 }
1229
1230 /* Push back the send data into the buffer */
1231 write_data_t *wdata = (write_data_t*)(st->start + st->len);
1232
1233 wdata->len = needed_len;
1234 wdata->key = send_key;
1235 wdata->data_len = (pj_size_t)*size;
1236 pj_memcpy(wdata->data, data, *size);
1237 st->len += needed_len;
1238
1239 /* If no outstanding send, send it */
1240 if (st->current_data == NULL) {
1241 pj_status_t status;
1242
1243 wdata = (write_data_t*)st->start;
1244 st->current_data = wdata;
1245 st->send_ptr.Set((TUint8*)wdata->data, (TInt)wdata->data_len);
1246 status = ssock->sock->Send(&send_cb, ssock, st->send_ptr, flags);
1247
1248 if (status != PJ_EPENDING) {
1249 *size = -status;
1250 return status;
1251 }
1252 }
1253
1254 return PJ_SUCCESS;
1255}
1256
1257/*
1258 * Send datagram using the socket.
1259 */
1260PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
1261 pj_ioqueue_op_key_t *send_key,
1262 const void *data,
1263 pj_ssize_t *size,
1264 unsigned flags,
1265 const pj_sockaddr_t *addr,
1266 int addr_len)
1267{
1268 PJ_UNUSED_ARG(ssock);
1269 PJ_UNUSED_ARG(send_key);
1270 PJ_UNUSED_ARG(data);
1271 PJ_UNUSED_ARG(size);
1272 PJ_UNUSED_ARG(flags);
1273 PJ_UNUSED_ARG(addr);
1274 PJ_UNUSED_ARG(addr_len);
1275 return PJ_ENOTSUP;
1276}
1277
1278/*
1279 * Starts asynchronous socket accept() operations on this SSL socket.
1280 */
1281PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
1282 pj_pool_t *pool,
1283 const pj_sockaddr_t *local_addr,
1284 int addr_len)
1285{
1286 PJ_UNUSED_ARG(ssock);
1287 PJ_UNUSED_ARG(pool);
1288 PJ_UNUSED_ARG(local_addr);
1289 PJ_UNUSED_ARG(addr_len);
1290
1291 return PJ_ENOTSUP;
1292}
1293
1294static void connect_cb(int err, void *key)
1295{
1296 pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
1297 pj_status_t status;
1298
1299 if (ssock->connect_timer) {
1300 delete ssock->connect_timer;
1301 ssock->connect_timer = NULL;
1302 }
1303
1304 status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
1305 if (status == PJ_SUCCESS) {
1306 ssock->established = PJ_TRUE;
1307 update_certs_info(ssock);
1308 } else {
1309 delete ssock->sock;
1310 ssock->sock = NULL;
1311 if (err == KErrTimedOut) status = PJ_ETIMEDOUT;
1312 }
1313
1314 if (ssock->cb.on_connect_complete) {
1315 pj_bool_t ret = (*ssock->cb.on_connect_complete)(ssock, status);
1316 if (!ret) {
1317 /* We've been destroyed */
1318 return;
1319 }
1320 }
1321}
1322
1323static void connect_timer_cb(void *key)
1324{
1325 connect_cb(KErrTimedOut, key);
1326}
1327
1328/*
1329 * Starts asynchronous socket connect() operation and SSL/TLS handshaking
1330 * for this socket. Once the connection is done (either successfully or not),
1331 * the \a on_connect_complete() callback will be called.
1332 */
1333PJ_DEF(pj_status_t) pj_ssl_sock_start_connect (pj_ssl_sock_t *ssock,
1334 pj_pool_t *pool,
1335 const pj_sockaddr_t *localaddr,
1336 const pj_sockaddr_t *remaddr,
1337 int addr_len)
1338{
1339 CPjSSLSocket *sock = NULL;
1340 pj_status_t status;
1341
1342 PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
1343 PJ_EINVAL);
1344
1345 /* Check connection status */
1346 PJ_SYMBIAN_CHECK_CONNECTION();
1347
1348 if (ssock->sock != NULL) {
1349 CPjSSLSocket::ssl_state state = ssock->sock->GetState();
1350 switch (state) {
1351 case CPjSSLSocket::SSL_STATE_ESTABLISHED:
1352 return PJ_SUCCESS;
1353 default:
1354 return PJ_EPENDING;
1355 }
1356 }
1357
1358 /* Set SSL protocol */
1359 TPtrC8 proto;
1360
1361 if (ssock->proto == PJ_SSL_SOCK_PROTO_DEFAULT)
1362 ssock->proto = PJ_SSL_SOCK_PROTO_TLS1;
1363
1364 /* CSecureSocket only support TLS1.0 and SSL3.0 */
1365 switch(ssock->proto) {
1366 case PJ_SSL_SOCK_PROTO_TLS1:
1367 proto.Set((const TUint8*)"TLS1.0", 6);
1368 break;
1369 case PJ_SSL_SOCK_PROTO_SSL3:
1370 proto.Set((const TUint8*)"SSL3.0", 6);
1371 break;
1372 default:
1373 return PJ_ENOTSUP;
1374 }
1375
1376 /* Prepare addresses */
1377 TInetAddr localaddr_, remaddr_;
1378 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)localaddr, addr_len,
1379 localaddr_);
1380 if (status != PJ_SUCCESS)
1381 return status;
1382
1383 status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)remaddr, addr_len,
1384 remaddr_);
1385 if (status != PJ_SUCCESS)
1386 return status;
1387
1388 pj_sockaddr_cp((pj_sockaddr_t*)&ssock->rem_addr, remaddr);
1389
1390 /* Init SSL engine */
1391 TRAPD(err, sock = CPjSSLSocket::NewL(proto, ssock->qos_type,
1392 ssock->qos_params));
1393 if (err != KErrNone)
1394 return PJ_ENOMEM;
1395
1396 if (ssock->timeout.sec != 0 || ssock->timeout.msec != 0) {
1397 ssock->connect_timer = new CPjTimer(&ssock->timeout,
1398 &connect_timer_cb, ssock);
1399 }
1400
1401 /* Convert server name to Symbian descriptor */
1402 TPtrC8 servername_((TUint8*)ssock->servername.ptr,
1403 ssock->servername.slen);
1404
1405 /* Convert cipher list to Symbian descriptor */
1406 TPtrC8 ciphers_((TUint8*)ssock->ciphers.ptr,
1407 ssock->ciphers.slen);
1408
1409 /* Try to connect */
1410 status = sock->Connect(&connect_cb, ssock, localaddr_, remaddr_,
1411 servername_, ciphers_);
1412 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
1413 delete sock;
1414 return status;
1415 }
1416
1417 ssock->sock = sock;
1418 return status;
1419}
1420
1421
1422PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
1423{
1424 PJ_UNUSED_ARG(ssock);
1425 return PJ_ENOTSUP;
1426}