1
/* $Id: ssl_sock_symbian.cpp 3999 2012-03-30 07:10:13Z bennylp $ */
3
* Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
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.
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.
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
19
#include <pj/ssl_sock.h>
20
#include <pj/compat/socket.h>
21
#include <pj/assert.h>
26
#include <pj/string.h>
28
#include "os_symbian.h"
29
#include <securesocket.h>
33
#define THIS_FILE "ssl_sock_symbian.cpp"
36
/* Cipher name structure */
37
typedef struct cipher_name_t {
42
/* Cipher name constants */
43
static cipher_name_t cipher_names[] =
45
{PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
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"},
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"},
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"},
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"}
119
/* Get cipher name string */
120
static const char* get_cipher_name(pj_ssl_cipher cipher)
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;
130
return "CIPHER_UNKNOWN";
133
typedef void (*CPjSSLSocket_cb)(int err, void *key);
135
class CPjSSLSocketReader : public CActive
138
static CPjSSLSocketReader *NewL(CSecureSocket &sock)
140
CPjSSLSocketReader *self = new (ELeave)
141
CPjSSLSocketReader(sock);
142
CleanupStack::PushL(self);
144
CleanupStack::Pop(self);
148
~CPjSSLSocketReader() {
152
/* Asynchronous read from the socket. */
153
int Read(CPjSSLSocket_cb cb, void *key, TPtr8 &data, TUint flags)
155
PJ_ASSERT_RETURN(!IsActive(), PJ_EBUSY);
159
sock_.RecvOneOrMore(data, iStatus, len_received_);
166
CSecureSocket &sock_;
169
TSockXfrLength len_received_; /* not really useful? */
176
(*cb_)(iStatus.Int(), key_);
179
CPjSSLSocketReader(CSecureSocket &sock) :
180
CActive(0), sock_(sock), cb_(NULL), key_(NULL)
184
CActiveScheduler::Add(this);
188
class CPjSSLSocket : public CActive
193
SSL_STATE_CONNECTING,
194
SSL_STATE_HANDSHAKING,
195
SSL_STATE_ESTABLISHED
198
static CPjSSLSocket *NewL(const TDesC8 &ssl_proto,
199
pj_qos_type qos_type,
200
const pj_qos_params &qos_params)
202
CPjSSLSocket *self = new (ELeave) CPjSSLSocket(qos_type, qos_params);
203
CleanupStack::PushL(self);
204
self->ConstructL(ssl_proto);
205
CleanupStack::Pop(self);
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);
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 {
226
return securesock_->CurrentCipherSuite(cipher);
229
const CX509Certificate *GetPeerCert() {
231
return securesock_->ServerCert();
236
enum ssl_state state_;
238
CSecureSocket *securesock_;
241
pj_qos_type qos_type_;
242
pj_qos_params qos_params_;
244
CPjSSLSocketReader *reader_;
249
TInetAddr local_addr_;
250
TSockXfrLength sent_len_;
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)
265
void ConstructL(const TDesC8 &ssl_proto) {
266
ssl_proto_.Copy(ssl_proto);
267
CActiveScheduler::Add(this);
270
void CleanupSubObjects() {
274
if (state_ == SSL_STATE_ESTABLISHED)
275
securesock_->Close();
279
if (sock_ != PJ_INVALID_SOCKET) {
280
pj_sock_close(sock_);
281
sock_ = PJ_INVALID_SOCKET;
286
int 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)
294
PJ_ASSERT_RETURN(state_ == SSL_STATE_NULL, PJ_EINVALIDOP);
296
status = pj_sock_socket(rem_addr.Family(), pj_SOCK_STREAM(), 0, &sock_);
297
if (status != PJ_SUCCESS)
301
status = pj_sock_apply_qos2(sock_, qos_type_, &qos_params_,
304
RSocket &rSock = ((CPjSocket*)sock_)->Socket();
306
local_addr_ = local_addr;
308
if (!local_addr_.IsUnspecified()) {
309
TInt err = rSock.Bind(local_addr_);
311
return PJ_RETURN_OS_ERROR(err);
316
rem_addr_ = rem_addr;
318
/* Note: the following members only keep the pointer, not the data */
319
servername_.Set(servername);
320
ciphers_.Set(ciphers);
322
rSock.Connect(rem_addr_, iStatus);
324
state_ = SSL_STATE_CONNECTING;
326
rSock.LocalName(local_addr_);
331
int CPjSSLSocket::Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc,
334
PJ_UNUSED_ARG(flags);
336
PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
344
securesock_->Send(aDesc, iStatus, sent_len_);
350
int CPjSSLSocket::SendSync(const TDesC8 &aDesc, TUint flags)
352
PJ_UNUSED_ARG(flags);
354
PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
356
TRequestStatus reqStatus;
357
securesock_->Send(aDesc, reqStatus, sent_len_);
358
User::WaitForRequest(reqStatus);
360
return PJ_RETURN_OS_ERROR(reqStatus.Int());
363
CPjSSLSocketReader* CPjSSLSocket::GetReader()
365
PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, NULL);
370
TRAPD(err, reader_ = CPjSSLSocketReader::NewL(*securesock_));
377
void CPjSSLSocket::DoCancel()
379
/* Operation to be cancelled depends on current state */
381
case SSL_STATE_CONNECTING:
383
RSocket &rSock = ((CPjSocket*)sock_)->Socket();
385
rSock.CancelConnect();
387
state_ = SSL_STATE_NULL;
390
case SSL_STATE_HANDSHAKING:
392
securesock_->CancelHandshake();
394
state_ = SSL_STATE_NULL;
397
case SSL_STATE_ESTABLISHED:
398
securesock_->CancelSend();
405
void CPjSSLSocket::RunL()
408
case SSL_STATE_CONNECTING:
409
if (iStatus != KErrNone) {
411
state_ = SSL_STATE_NULL;
412
/* Dispatch connect failure notification */
413
if (cb_) (*cb_)(iStatus.Int(), key_);
415
RSocket &rSock = ((CPjSocket*)sock_)->Socket();
418
rSock.LocalName(local_addr_);
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,
426
if (ciphers_.Length() > 0)
427
securesock_->SetAvailableCipherSuites(ciphers_);
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();
437
securesock_->StartClientHandshake(iStatus);
439
state_ = SSL_STATE_HANDSHAKING;
442
case SSL_STATE_HANDSHAKING:
443
if (iStatus == KErrNone) {
444
state_ = SSL_STATE_ESTABLISHED;
446
state_ = SSL_STATE_NULL;
449
/* Dispatch connect status notification */
450
if (cb_) (*cb_)(iStatus.Int(), key_);
452
case SSL_STATE_ESTABLISHED:
453
/* Dispatch data sent notification */
454
if (cb_) (*cb_)(iStatus.Int(), key_);
462
typedef void (*CPjTimer_cb)(void *user_data);
464
class CPjTimer : public CActive
467
CPjTimer(const pj_time_val *delay, CPjTimer_cb cb, void *user_data) :
468
CActive(0), cb_(cb), user_data_(user_data)
470
CActiveScheduler::Add(this);
472
rtimer_.CreateLocal();
473
pj_int32_t interval = PJ_TIME_VAL_MSEC(*delay) * 1000;
477
rtimer_.After(iStatus, interval);
481
~CPjTimer() { Cancel(); }
488
void RunL() { if (cb_) (*cb_)(user_data_); }
489
void DoCancel() { rtimer_.Cancel(); }
493
* Structure of recv/read state.
495
typedef struct read_state_t {
502
* Structure of send/write data.
504
typedef struct write_data_t {
506
pj_ioqueue_op_key_t *key;
512
* Structure of send/write state.
514
typedef struct write_state_t {
519
write_data_t *current_data;
524
* Secure socket structure definition.
532
pj_bool_t established;
533
write_state_t write_state;
534
read_state_t read_state;
535
CPjTimer *connect_timer;
540
pj_sockaddr local_addr;
541
pj_sockaddr rem_addr;
544
pj_qos_type qos_type;
545
pj_qos_params qos_params;
546
pj_bool_t qos_ignore_error;
549
pj_ssl_sock_proto proto;
553
pj_ssl_cert_info remote_cert_info;
557
static pj_str_t get_cert_name(char *buf, unsigned buf_len,
558
const CX500DistinguishedName &name)
565
for(i = 0; i < name.Count(); ++i) {
566
const CX520AttributeTypeAndValue &attr = name.Element(i);
568
/* Print element separator */
572
/* Print the type. */
574
type.Copy(attr.Type());
579
/* Print equal sign */
583
/* Print the value. Let's just get the raw data here */
585
value.Copy(attr.EncodedValue().Mid(2));
592
pj_strset(&src, buf, buf_len - l);
597
/* Get certificate info from CX509Certificate.
599
static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci,
600
const CX509Certificate *x)
602
enum { tmp_buf_len = 512 };
606
pj_assert(pool && ci && x);
609
tmp_buf = new char[tmp_buf_len];
610
pj_bzero(ci, sizeof(*ci));
613
ci->version = x->Version();
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);
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);
631
pj_strset(&ci->subject.cn, (char*)ptr8.Ptr(), ptr8.Length());
633
pj_str_t tmp = get_cert_name(tmp_buf, tmp_buf_len,
635
pj_strdup(pool, &ci->subject.info, &tmp);
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);
647
pj_strset(&ci->issuer.cn, (char*)ptr8.Ptr(), ptr8.Length());
649
pj_str_t tmp = get_cert_name(tmp_buf, tmp_buf_len,
651
pj_strdup(pool, &ci->issuer.info, &tmp);
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();
668
/* Update certificates info. This function should be called after handshake
669
* or renegotiation successfully completed.
671
static void update_certs_info(pj_ssl_sock_t *ssock)
673
const CX509Certificate *x;
675
pj_assert(ssock && ssock->sock &&
676
ssock->sock->GetState() == CPjSSLSocket::SSL_STATE_ESTABLISHED);
678
/* Active remote certificate */
679
x = ssock->sock->GetPeerCert();
681
get_cert_info(ssock->pool, &ssock->remote_cert_info, x);
683
pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
688
/* Available ciphers */
689
static unsigned ciphers_num_ = 0;
690
static struct ciphers_t
697
* Get cipher list supported by SSL/TLS backend.
699
PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
700
unsigned *cipher_num)
704
PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
706
if (ciphers_num_ == 0) {
708
CSecureSocket *secure_sock;
709
TPtrC16 proto(_L16("TLS1.0"));
711
secure_sock = CSecureSocket::NewL(sock, proto);
713
TBuf8<128> ciphers_buf(0);
714
secure_sock->AvailableCipherSuites(ciphers_buf);
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 +
722
ciphers_[i].name = get_cipher_name(ciphers_[i].id);
729
if (ciphers_num_ == 0) {
734
*cipher_num = PJ_MIN(*cipher_num, ciphers_num_);
735
for (i = 0; i < *cipher_num; ++i)
736
ciphers[i] = ciphers_[i].id;
742
/* Get cipher name string */
743
PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
747
if (ciphers_num_ == 0) {
750
pj_ssl_cipher_get_availables(c, &i);
753
for (i = 0; i < ciphers_num_; ++i) {
754
if (cipher == ciphers_[i].id)
755
return ciphers_[i].name;
762
/* Check if the specified cipher is supported by SSL/TLS backend. */
763
PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
767
if (ciphers_num_ == 0) {
770
pj_ssl_cipher_get_availables(c, &i);
773
for (i = 0; i < ciphers_num_; ++i) {
774
if (cipher == ciphers_[i].id)
783
* Create SSL socket instance.
785
PJ_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)
789
pj_ssl_sock_t *ssock;
791
PJ_ASSERT_RETURN(param->async_cnt == 1, PJ_EINVAL);
792
PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
794
/* Allocate secure socket */
795
ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
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;
803
/* Init secure socket */
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);
820
pj_strdup_with_null(pool, &ssock->servername, ¶m->server_name);
822
ssock->qos_type = param->qos_type;
823
ssock->qos_ignore_error = param->qos_ignore_error;
824
pj_memcpy(&ssock->qos_params, ¶m->qos_params,
825
sizeof(param->qos_params));
834
PJ_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)
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);
851
* Set SSL socket credential.
853
PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
854
pj_ssl_sock_t *ssock,
856
const pj_ssl_cert_t *cert)
858
PJ_UNUSED_ARG(ssock);
865
* Close the SSL socket.
867
PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
869
PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
871
delete ssock->connect_timer;
872
ssock->connect_timer = NULL;
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;
887
* Associate arbitrary data with the SSL socket.
889
PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data (pj_ssl_sock_t *ssock,
892
PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
894
ssock->user_data = user_data;
901
* Retrieve the user data previously associated with this SSL
904
PJ_DEF(void*) pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
906
PJ_ASSERT_RETURN(ssock, NULL);
908
return ssock->user_data;
913
* Retrieve the local address and port used by specified SSL socket.
915
PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
916
pj_ssl_sock_info *info)
918
PJ_ASSERT_RETURN(ssock && info, PJ_EINVAL);
920
pj_bzero(info, sizeof(*info));
922
info->established = ssock->established;
926
const TInetAddr* local_addr_ = ssock->sock->GetLocalAddr();
927
int addrlen = sizeof(pj_sockaddr);
930
status = PjSymbianOS::Addr2pj(*local_addr_, info->local_addr, &addrlen);
931
if (status != PJ_SUCCESS)
934
pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
937
if (info->established) {
940
if (ssock->sock->GetCipher(cipher) == KErrNone) {
941
info->cipher = (pj_ssl_cipher)cipher[1];
945
pj_sockaddr_cp((pj_sockaddr_t*)&info->remote_addr,
946
(pj_sockaddr_t*)&ssock->rem_addr);
948
/* Certificates info */
949
info->remote_cert_info = &ssock->remote_cert_info;
953
info->proto = ssock->proto;
960
* Starts read operation on this SSL socket.
962
PJ_DEF(pj_status_t) pj_ssl_sock_start_read (pj_ssl_sock_t *ssock,
967
PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
968
PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
970
/* Reading is already started */
971
if (ssock->read_state.orig_buf) {
976
readbuf[0] = pj_pool_alloc(pool, buff_size);
977
return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
980
static void read_cb(int err, void *key)
982
pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
985
status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
987
/* Check connection status */
988
if (err == KErrEof || !PjSymbianOS::Instance()->IsConnectionUp() ||
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();
1003
/* Notify received data */
1004
pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, data, data_len,
1005
status, &remainder);
1007
/* We've been destroyed */
1011
/* Calculate available data for next READ operation */
1012
if (remainder > 0) {
1013
pj_size_t data_maxlen = ssock->read_state.orig_buf->MaxLength();
1015
/* There is some data left unconsumed by application, we give
1016
* smaller buffer for next READ operation.
1018
ssock->read_state.read_buf->Set((TUint8*)data+remainder, 0,
1019
data_maxlen - remainder);
1021
/* Give all buffer for next READ operation.
1023
ssock->read_state.read_buf->Set(*ssock->read_state.orig_buf);
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);
1036
/* Connection closed or something goes wrong */
1037
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
1039
if (ssock->cb.on_data_read) {
1040
pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, NULL, 0,
1043
/* We've been destroyed */
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;
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.
1061
PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
1067
PJ_ASSERT_RETURN(ssock && buff_size && readbuf, PJ_EINVAL);
1068
PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
1070
/* Return failure if access point is marked as down by app. */
1071
PJ_SYMBIAN_CHECK_CONNECTION();
1073
/* Reading is already started */
1074
if (ssock->read_state.orig_buf) {
1078
PJ_UNUSED_ARG(pool);
1080
/* Get reader instance */
1081
CPjSSLSocketReader *reader = ssock->sock->GetReader();
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.
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;
1095
status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf,
1096
ssock->read_state.flags);
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;
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()
1115
PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
1120
PJ_UNUSED_ARG(ssock);
1121
PJ_UNUSED_ARG(pool);
1122
PJ_UNUSED_ARG(buff_size);
1123
PJ_UNUSED_ARG(flags);
1128
* Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom()
1129
* operation takes the buffer from the argument rather than creating
1132
PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
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);
1146
static void send_cb(int err, void *key)
1148
pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
1149
write_state_t *st = &ssock->write_state;
1151
/* Check connection status */
1152
if (err != KErrNone || !PjSymbianOS::Instance()->IsConnectionUp() ||
1153
!ssock->established)
1155
ssock->established = PJ_FALSE;
1159
/* Remove sent data from buffer */
1160
st->start += st->current_data->len;
1161
st->len -= st->current_data->len;
1163
/* Reset current outstanding send */
1164
st->current_data = NULL;
1166
/* Let's check if there is pending data to send */
1168
write_data_t *wdata = (write_data_t*)st->start;
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;
1180
/* Buffer empty, reset the start position */
1181
st->start = st->buf;
1186
* Send data using the socket.
1188
PJ_DEF(pj_status_t) pj_ssl_sock_send (pj_ssl_sock_t *ssock,
1189
pj_ioqueue_op_key_t *send_key,
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,
1200
/* Check connection status */
1201
if (!PjSymbianOS::Instance()->IsConnectionUp() || !ssock->established)
1203
ssock->established = PJ_FALSE;
1204
return PJ_ECANCELLED;
1207
write_state_t *st = &ssock->write_state;
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);
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.
1220
pj_size_t needed_len = *size + sizeof(write_data_t) - 1;
1222
/* Align needed_len to be multiplication of 4 */
1223
needed_len = ((needed_len + 3) >> 2) << 2;
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);
1230
/* Push back the send data into the buffer */
1231
write_data_t *wdata = (write_data_t*)(st->start + st->len);
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;
1239
/* If no outstanding send, send it */
1240
if (st->current_data == NULL) {
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);
1248
if (status != PJ_EPENDING) {
1258
* Send datagram using the socket.
1260
PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
1261
pj_ioqueue_op_key_t *send_key,
1265
const pj_sockaddr_t *addr,
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);
1279
* Starts asynchronous socket accept() operations on this SSL socket.
1281
PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
1283
const pj_sockaddr_t *local_addr,
1286
PJ_UNUSED_ARG(ssock);
1287
PJ_UNUSED_ARG(pool);
1288
PJ_UNUSED_ARG(local_addr);
1289
PJ_UNUSED_ARG(addr_len);
1294
static void connect_cb(int err, void *key)
1296
pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
1299
if (ssock->connect_timer) {
1300
delete ssock->connect_timer;
1301
ssock->connect_timer = NULL;
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);
1311
if (err == KErrTimedOut) status = PJ_ETIMEDOUT;
1314
if (ssock->cb.on_connect_complete) {
1315
pj_bool_t ret = (*ssock->cb.on_connect_complete)(ssock, status);
1317
/* We've been destroyed */
1323
static void connect_timer_cb(void *key)
1325
connect_cb(KErrTimedOut, key);
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.
1333
PJ_DEF(pj_status_t) pj_ssl_sock_start_connect (pj_ssl_sock_t *ssock,
1335
const pj_sockaddr_t *localaddr,
1336
const pj_sockaddr_t *remaddr,
1339
CPjSSLSocket *sock = NULL;
1342
PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
1345
/* Check connection status */
1346
PJ_SYMBIAN_CHECK_CONNECTION();
1348
if (ssock->sock != NULL) {
1349
CPjSSLSocket::ssl_state state = ssock->sock->GetState();
1351
case CPjSSLSocket::SSL_STATE_ESTABLISHED:
1358
/* Set SSL protocol */
1361
if (ssock->proto == PJ_SSL_SOCK_PROTO_DEFAULT)
1362
ssock->proto = PJ_SSL_SOCK_PROTO_TLS1;
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);
1369
case PJ_SSL_SOCK_PROTO_SSL3:
1370
proto.Set((const TUint8*)"SSL3.0", 6);
1376
/* Prepare addresses */
1377
TInetAddr localaddr_, remaddr_;
1378
status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)localaddr, addr_len,
1380
if (status != PJ_SUCCESS)
1383
status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)remaddr, addr_len,
1385
if (status != PJ_SUCCESS)
1388
pj_sockaddr_cp((pj_sockaddr_t*)&ssock->rem_addr, remaddr);
1390
/* Init SSL engine */
1391
TRAPD(err, sock = CPjSSLSocket::NewL(proto, ssock->qos_type,
1392
ssock->qos_params));
1393
if (err != KErrNone)
1396
if (ssock->timeout.sec != 0 || ssock->timeout.msec != 0) {
1397
ssock->connect_timer = new CPjTimer(&ssock->timeout,
1398
&connect_timer_cb, ssock);
1401
/* Convert server name to Symbian descriptor */
1402
TPtrC8 servername_((TUint8*)ssock->servername.ptr,
1403
ssock->servername.slen);
1405
/* Convert cipher list to Symbian descriptor */
1406
TPtrC8 ciphers_((TUint8*)ssock->ciphers.ptr,
1407
ssock->ciphers.slen);
1409
/* Try to connect */
1410
status = sock->Connect(&connect_cb, ssock, localaddr_, remaddr_,
1411
servername_, ciphers_);
1412
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
1422
PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
1424
PJ_UNUSED_ARG(ssock);