Qt中调用PolarSSL库(一)

时间:2023-03-09 00:17:45
Qt中调用PolarSSL库(一)

最近一直在学习SSL相关的知识,也是先了解理论相关的知识,主要是SSL相关的基本概念和连接建立过程,主要是基于PolarSSL开源库进行学习。学习完了之后就希望能给有所运用,就想用Qt写一个简单的程序,增加对SSL相关概念的把握和对PolarSSL库的运用。当然,最终希望是可以使用Qt做一个比较完善的工具,帮助大家更好的理解和学习SSL相关知识。这都是后话,在第一篇里面,我们就简单用例子展示如何在Qt里面调用PolarSSL库。

这篇博客主要是讲解Qt里面调用PolarSSL库,至于SSL相关概念在后面的博客再详细介绍。

SSL握手需要客户端和服务器端交互,这里我们分别介绍。

1、编译PolarSSL库

我们准备使用的方式就是编译PolarSSL为.a静态库,然后在Qt中连接,使用的PolarSSL的版本是0.10.1。

下载对应的软件版本,解压缩后在library目录下执行make即可生成libpolarssl.a库文件,如下图:

Qt中调用PolarSSL库(一)

2、服务器端

使用Qt设计一个简单的界面,在按钮的槽函数中进行相关的操作,也就是调用PolarSSL库函数进行编程,初始化ssl相关结构体,监听端口,等等。

SSL中最重要的就是执行握手操作。这里需要注意一点,由于涉及到socket编程,像accept函数都是阻塞的,如果在gui主线程中调用会造成界面冻结,也就是我们常说的ANR。解决方法就是将这些操作放在一个线程中,Qt中创建一个线程比较容易,创建一个类,继承自QThread,实现run函数,即可,最后启动线程也比较简单,调用该类的start()

函数即可。好了,不多说了,上代码,首先看看服务器端的代码结构:workThread即是线程,实现SSL相关的功能,监听套接字,实现SSL握手,读取客户端发来的消息,向客户端发送消息。

mianwindow即是主窗口界面,有个按钮,在按钮的槽函数中启动线程

代码:

工程文件:

  1. #-------------------------------------------------
  2. #
  3. # Project created by QtCreator 2014-05-11T22:28:07
  4. #
  5. #-------------------------------------------------
  6. QT       += core gui
  7. greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  8. TARGET = MyPolarSSLToolSrv
  9. TEMPLATE = app
  10. INCLUDEPATH += /home/chenlong12580/develop/polarTool/polarssl/include
  11. LIBS += -L "/home/chenlong12580/develop/polarTool/polarssl/lib/" -lpolarssl
  12. SOURCES += main.cpp\
  13. widget.cpp \
  14. workthread.cpp
  15. HEADERS  += widget.h \
  16. workthread.h
  17. FORMS    += widget.ui

线程类:

  1. void WorkThread::run()
  2. {
  3. qDebug() << "I am a thread!";
  4. int listen_fd = 0;
  5. int client_fd =0;
  6. int ret= 0;
  7. havege_state hs;
  8. ssl_context ssl;
  9. ssl_session ssn;
  10. x509_cert srvcert;
  11. rsa_context rsa;
  12. unsigned char buf[1024];
  13. int len = 0;
  14. memset( &srvcert, 0, sizeof( x509_cert ) );
  15. ret = x509parse_crt( &srvcert, (unsigned char *) test_srv_crt,
  16. strlen( test_srv_crt ) );
  17. if( ret != 0 )
  18. {
  19. printf( " failed\n  !  x509parse_crt returned %d\n\n", ret );
  20. return;
  21. }
  22. ret = x509parse_crt( &srvcert, (unsigned char *) test_ca_crt,
  23. strlen( test_ca_crt ) );
  24. if( ret != 0 )
  25. {
  26. printf( " failed\n  !  x509parse_crt returned %d\n\n", ret );
  27. return;
  28. }
  29. ret =  x509parse_key( &rsa, (unsigned char *) test_srv_key,
  30. strlen( test_srv_key ), NULL, 0 );
  31. if( ret != 0 )
  32. {
  33. printf( " failed\n  !  x509parse_key returned %d\n\n", ret );
  34. return;
  35. }
  36. ret = net_bind( &listen_fd, NULL, 8443 );
  37. if (0 != ret)
  38. {
  39. qDebug() << ret;
  40. return;
  41. }
  42. qDebug() << "bind ok";
  43. /* socket is block */
  44. ret = net_accept( listen_fd, &client_fd, NULL );
  45. if (0 != ret)
  46. {
  47. return;
  48. }
  49. qDebug() << "accept ok";
  50. havege_init( &hs );
  51. ret = ssl_init( &ssl );
  52. if (0 != ret)
  53. {
  54. return;
  55. }
  56. ssl_set_endpoint( &ssl, SSL_IS_SERVER );
  57. ssl_set_authmode( &ssl, SSL_VERIFY_NONE );
  58. ssl_set_rng( &ssl, havege_rand, &hs );
  59. ssl_set_dbg( &ssl, my_debug, stdout );
  60. ssl_set_bio( &ssl, net_recv, &client_fd,
  61. net_send, &client_fd );
  62. ssl_set_scb( &ssl, my_get_session,
  63. my_set_session );
  64. ssl_set_ciphers( &ssl, my_ciphers );
  65. ssl_set_session( &ssl, 1, 0, &ssn );
  66. memset( &ssn, 0, sizeof( ssl_session ) );
  67. ssl_set_ca_chain( &ssl, srvcert.next, NULL );
  68. ssl_set_own_cert( &ssl, &srvcert, &rsa );
  69. ssl_set_dh_param( &ssl, my_dhm_P, my_dhm_G );
  70. qDebug() << "before ssl_handshake ok";
  71. while( ( ret = ssl_handshake( &ssl ) ) != 0 )
  72. {
  73. ;
  74. }
  75. qDebug() << "ssl_handshake ok";
  76. do
  77. {
  78. len = sizeof( buf ) - 1;
  79. memset( buf, 0, sizeof( buf ) );
  80. ret = ssl_read( &ssl, buf, len );
  81. if( ret == POLARSSL_ERR_NET_TRY_AGAIN )
  82. continue;
  83. if( ret <= 0 )
  84. {
  85. switch( ret )
  86. {
  87. case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
  88. printf( " connection was closed gracefully\n" );
  89. break;
  90. case POLARSSL_ERR_NET_CONN_RESET:
  91. printf( " connection was reset by peer\n" );
  92. break;
  93. default:
  94. printf( " ssl_read returned %d\n", ret );
  95. break;
  96. }
  97. break;
  98. }
  99. len = ret;
  100. printf( " %d bytes read\n\n%s", len, (char *) buf );
  101. }while( 0 );
  102. char *cc = (char *)buf;
  103. QString ss(cc);
  104. qDebug() << ss;
  105. (void)sprintf( (char *) buf, HTTP_RESPONSE,
  106. ssl_get_cipher( &ssl ) );
  107. while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
  108. {
  109. if( ret == POLARSSL_ERR_NET_CONN_RESET )
  110. {
  111. printf( " failed\n  ! peer closed the connection\n\n" );
  112. return;
  113. }
  114. if( ret != POLARSSL_ERR_NET_TRY_AGAIN )
  115. {
  116. printf( " failed\n  ! ssl_write returned %d\n\n", ret );
  117. return;
  118. }
  119. }
  120. ssl_close_notify( &ssl );
  121. net_close( client_fd );
  122. x509_free( &srvcert );
  123. rsa_free( &rsa );
  124. ssl_free( &ssl );
  125. cur = s_list_1st;
  126. while( cur != NULL )
  127. {
  128. prv = cur;
  129. cur = cur->next;
  130. memset( prv, 0, sizeof( ssl_session ) );
  131. free( prv );
  132. }
  133. memset( &ssl, 0, sizeof( ssl_context ) );
  134. }

主窗口类:

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. #include <QFileDialog>
  4. #include <QDebug>
  5. #include <QMessageBox>
  6. #include "workthread.h"
  7. #include "polarssl/havege.h"
  8. #include "polarssl/certs.h"
  9. #include "polarssl/x509.h"
  10. #include "polarssl/ssl.h"
  11. #include "polarssl/net.h"
  12. Widget::Widget(QWidget *parent) :
  13. QWidget(parent),
  14. ui(new Ui::Widget)
  15. {
  16. ui->setupUi(this);
  17. qDebug() << "server";
  18. connect(this, SIGNAL(emit_parse_cer()), this, SLOT(slot_parse_cer()));
  19. }
  20. Widget::~Widget()
  21. {
  22. delete ui;
  23. }
  24. void Widget::on_BrowseBtn_clicked()
  25. {
  26. QString pathStr = QFileDialog::getOpenFileName(this, QString("选择证书文件"), QString("C:\\Users\\Administrator\\Desktop"), QString("*.*"));
  27. if (pathStr.length() == 0)
  28. {
  29. qDebug() << "please select a cer file!";
  30. return;
  31. }
  32. ui->PathEdit->setText(pathStr);
  33. emit emit_parse_cer();
  34. }
  35. void Widget::slot_parse_cer()
  36. {
  37. x509_cert crt;
  38. memset(&crt, 0, sizeof(crt));
  39. int res = x509parse_crtfile( &crt, ui->PathEdit->text().toLatin1().data());
  40. if (0 != res)
  41. {
  42. QMessageBox::warning(this, "警告", "解析证书失败,请选择正确的证书文件", QMessageBox::Ok);
  43. return;
  44. }
  45. ui->CrtInfo->setText(QString("是否为根证书:") + QString::number(crt.ca_istrue));
  46. ui->CrtInfo->append(QString("证书版本号:") + QString::number(crt.version));
  47. ui->CrtInfo->append(QString("有效期:") + QString::number(crt.valid_from.year) + "-" + QString::number(crt.valid_from.mon)
  48. + QString("  到:") + QString::number(crt.valid_to.year) + "-" + QString::number(crt.valid_to.mon));
  49. qDebug() << crt.ca_istrue;
  50. qDebug() << crt.valid_from.year;
  51. }
  52. void Widget::on_pushButton_clicked()
  53. {
  54. WorkThread *workThread = new WorkThread;
  55. workThread->start();
  56. }

3、客户端

客户端比较简单,直接在界面类进行的SSL功能相关的实现,就是创建套接字,链接服务器,进行SSL握手,向服务器发消息,读取服务器发来的消息。

工程文件:

  1. #-------------------------------------------------
  2. #
  3. # Project created by QtCreator 2014-05-11T22:28:07
  4. #
  5. #-------------------------------------------------
  6. QT       += core gui
  7. greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  8. TARGET = MyPolarSSLToolCli
  9. TEMPLATE = app
  10. INCLUDEPATH += /home/chenlong12580/develop/polarTool/polarssl/include
  11. LIBS += -L "/home/chenlong12580/develop/polarTool/polarssl/lib/" -lpolarssl
  12. SOURCES += main.cpp\
  13. widget.cpp
  14. HEADERS  += widget.h
  15. FORMS    += widget.ui

主窗口类:

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. #include <QFileDialog>
  4. #include <QDebug>
  5. #include <QMessageBox>
  6. #include "polarssl/havege.h"
  7. #include "polarssl/certs.h"
  8. #include "polarssl/x509.h"
  9. #include "polarssl/ssl.h"
  10. #include "polarssl/net.h"
  11. #define SERVER_PORT 8443
  12. /*
  13. #define SERVER_NAME "localhost"
  14. #define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
  15. */
  16. #define SERVER_NAME "polarssl.org"
  17. #define GET_REQUEST \
  18. "GET /hello/ HTTP/1.1\r\n" \
  19. "Host: polarssl.org\r\n\r\n"
  20. #define DEBUG_LEVEL 0
  21. void my_debug( void *ctx, int level, char *str )
  22. {
  23. if( level < DEBUG_LEVEL )
  24. {
  25. fprintf( (FILE *) ctx, "%s", str );
  26. fflush(  (FILE *) ctx  );
  27. }
  28. }
  29. Widget::Widget(QWidget *parent) :
  30. QWidget(parent),
  31. ui(new Ui::Widget)
  32. {
  33. ui->setupUi(this);
  34. qDebug() << "client";
  35. connect(this, SIGNAL(emit_parse_cer()), this, SLOT(slot_parse_cer()));
  36. }
  37. Widget::~Widget()
  38. {
  39. delete ui;
  40. }
  41. void Widget::on_BrowseBtn_clicked()
  42. {
  43. QString pathStr = QFileDialog::getOpenFileName(this, QString("选择证书文件"), QString("C:\\Users\\Administrator\\Desktop"), QString("*.*"));
  44. if (pathStr.length() == 0)
  45. {
  46. qDebug() << "please select a cer file!";
  47. return;
  48. }
  49. ui->PathEdit->setText(pathStr);
  50. emit emit_parse_cer();
  51. }
  52. void Widget::slot_parse_cer()
  53. {
  54. x509_cert crt;
  55. memset(&crt, 0, sizeof(crt));
  56. int res = x509parse_crtfile( &crt, ui->PathEdit->text().toLatin1().data());
  57. if (0 != res)
  58. {
  59. QMessageBox::warning(this, "警告", "解析证书失败,请选择正确的证书文件", QMessageBox::Ok);
  60. return;
  61. }
  62. ui->CrtInfo->setText(QString("是否为根证书:") + QString::number(crt.ca_istrue));
  63. ui->CrtInfo->append(QString("证书版本号:") + QString::number(crt.version));
  64. ui->CrtInfo->append(QString("有效期:") + QString::number(crt.valid_from.year) + "-" + QString::number(crt.valid_from.mon)
  65. + QString("  到:") + QString::number(crt.valid_to.year) + "-" + QString::number(crt.valid_to.mon));
  66. qDebug() << crt.ca_istrue;
  67. qDebug() << crt.valid_from.year;
  68. }
  69. void Widget::on_pushButton_clicked()
  70. {
  71. int ret, len, server_fd;
  72. unsigned char buf[1024];
  73. havege_state hs;
  74. ssl_context ssl;
  75. ssl_session ssn;
  76. /*
  77. * 0. Initialize the RNG and the session data
  78. */
  79. havege_init( &hs );
  80. memset( &ssn, 0, sizeof( ssl_session ) );
  81. /*
  82. * 1. Start the connection
  83. */
  84. printf( "\n  . Connecting to tcp/%s/%4d...", SERVER_NAME,
  85. SERVER_PORT );
  86. fflush( stdout );
  87. if( ( ret = net_connect( &server_fd, "127.0.0.1",
  88. SERVER_PORT ) ) != 0 )
  89. {
  90. printf( " failed\n  ! net_connect returned %d\n\n", ret );
  91. return;
  92. }
  93. printf( " ok\n" );
  94. /*
  95. * 2. Setup stuff
  96. */
  97. printf( "  . Setting up the SSL/TLS structure..." );
  98. fflush( stdout );
  99. if( ( ret = ssl_init( &ssl ) ) != 0 )
  100. {
  101. printf( " failed\n  ! ssl_init returned %d\n\n", ret );
  102. return;
  103. }
  104. printf( " ok\n" );
  105. ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
  106. ssl_set_authmode( &ssl, SSL_VERIFY_NONE );
  107. ssl_set_rng( &ssl, havege_rand, &hs );
  108. ssl_set_dbg( &ssl, my_debug, stdout );
  109. ssl_set_bio( &ssl, net_recv, &server_fd,
  110. net_send, &server_fd );
  111. ssl_set_ciphers( &ssl, ssl_default_ciphers );
  112. ssl_set_session( &ssl, 1, 600, &ssn );
  113. /*
  114. * 3. Write the GET request
  115. */
  116. printf( "  > Write to server:" );
  117. fflush( stdout );
  118. len = sprintf( (char *) buf, GET_REQUEST );
  119. while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
  120. {
  121. if( ret != POLARSSL_ERR_NET_TRY_AGAIN )
  122. {
  123. printf( " failed\n  ! ssl_write returned %d\n\n", ret );
  124. return;
  125. }
  126. }
  127. len = ret;
  128. printf( " %d bytes written\n\n%s", len, (char *) buf );
  129. /*
  130. * 7. Read the HTTP response
  131. */
  132. printf( "  < Read from server:" );
  133. fflush( stdout );
  134. do
  135. {
  136. len = sizeof( buf ) - 1;
  137. memset( buf, 0, sizeof( buf ) );
  138. ret = ssl_read( &ssl, buf, len );
  139. if( ret == POLARSSL_ERR_NET_TRY_AGAIN )
  140. continue;
  141. if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY )
  142. break;
  143. if( ret <= 0 )
  144. {
  145. printf( "failed\n  ! ssl_read returned %d\n\n", ret );
  146. break;
  147. }
  148. len = ret;
  149. printf( " %d bytes read\n\n%s", len, (char *) buf );
  150. }
  151. while( 0 );
  152. char *cc= (char *)buf;
  153. QString ss(cc);
  154. qDebug() << ss;
  155. ssl_close_notify( &ssl );
  156. return;
  157. }

4、运行效果

下面说说运行的效果,首先启动服务器端,服务器端启动线程,监听套接字:

Qt中调用PolarSSL库(一)

接着启动客户端,客户端链接服务器端,写入消息,读取服务器端的响应:

Qt中调用PolarSSL库(一)

最后根据打印可以看出服务器端和客户端握手成功,写入读取消息成功:

Qt中调用PolarSSL库(一)

Qt中调用PolarSSL库(一)

我们可以根据抓包来看看SSL握手的过程,如下:

Qt中调用PolarSSL库(一)

通过抓包可以看到服务器端和客户端的握手过程,以及在不同的握手阶段中做得事情:

服务器端:

  1. /*
  2. * SSL handshake -- server side
  3. */
  4. int ssl_handshake_server( ssl_context *ssl )
  5. {
  6. int ret = 0;
  7. SSL_DEBUG_MSG( 2, ( "=> handshake server" ) );
  8. while( ssl->state != SSL_HANDSHAKE_OVER )
  9. {
  10. SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) );
  11. if( ( ret = ssl_flush_output( ssl ) ) != 0 )
  12. break;
  13. switch( ssl->state )
  14. {
  15. case SSL_HELLO_REQUEST:
  16. ssl->state = SSL_CLIENT_HELLO;
  17. break;
  18. /*
  19. *  <==   ClientHello
  20. */
  21. case SSL_CLIENT_HELLO:
  22. ret = ssl_parse_client_hello( ssl );
  23. break;
  24. /*
  25. *  ==>   ServerHello
  26. *        Certificate
  27. *      ( ServerKeyExchange  )
  28. *      ( CertificateRequest )
  29. *        ServerHelloDone
  30. */
  31. case SSL_SERVER_HELLO:
  32. ret = ssl_write_server_hello( ssl );
  33. break;
  34. case SSL_SERVER_CERTIFICATE:
  35. ret = ssl_write_certificate( ssl );
  36. break;
  37. case SSL_SERVER_KEY_EXCHANGE:
  38. ret = ssl_write_server_key_exchange( ssl );
  39. break;
  40. case SSL_CERTIFICATE_REQUEST:
  41. ret = ssl_write_certificate_request( ssl );
  42. break;
  43. case SSL_SERVER_HELLO_DONE:
  44. ret = ssl_write_server_hello_done( ssl );
  45. break;
  46. /*
  47. *  <== ( Certificate/Alert  )
  48. *        ClientKeyExchange
  49. *      ( CertificateVerify  )
  50. *        ChangeCipherSpec
  51. *        Finished
  52. */
  53. case SSL_CLIENT_CERTIFICATE:
  54. ret = ssl_parse_certificate( ssl );
  55. break;
  56. case SSL_CLIENT_KEY_EXCHANGE:
  57. ret = ssl_parse_client_key_exchange( ssl );
  58. break;
  59. case SSL_CERTIFICATE_VERIFY:
  60. ret = ssl_parse_certificate_verify( ssl );
  61. break;
  62. case SSL_CLIENT_CHANGE_CIPHER_SPEC:
  63. ret = ssl_parse_change_cipher_spec( ssl );
  64. break;
  65. case SSL_CLIENT_FINISHED:
  66. ret = ssl_parse_finished( ssl );
  67. break;
  68. /*
  69. *  ==>   ChangeCipherSpec
  70. *        Finished
  71. */
  72. case SSL_SERVER_CHANGE_CIPHER_SPEC:
  73. ret = ssl_write_change_cipher_spec( ssl );
  74. break;
  75. case SSL_SERVER_FINISHED:
  76. ret = ssl_write_finished( ssl );
  77. break;
  78. case SSL_FLUSH_BUFFERS:
  79. SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
  80. ssl->state = SSL_HANDSHAKE_OVER;
  81. break;
  82. default:
  83. SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
  84. return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
  85. }
  86. if( ret != 0 )
  87. break;
  88. }
  89. SSL_DEBUG_MSG( 2, ( "<= handshake server" ) );
  90. return( ret );
  91. }

客户端:

    1. /*
    2. * SSL handshake -- client side
    3. */
    4. int ssl_handshake_client( ssl_context *ssl )
    5. {
    6. int ret = 0;
    7. SSL_DEBUG_MSG( 2, ( "=> handshake client" ) );
    8. while( ssl->state != SSL_HANDSHAKE_OVER )
    9. {
    10. SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) );
    11. if( ( ret = ssl_flush_output( ssl ) ) != 0 )
    12. break;
    13. switch( ssl->state )
    14. {
    15. case SSL_HELLO_REQUEST:
    16. ssl->state = SSL_CLIENT_HELLO;
    17. break;
    18. /*
    19. *  ==>   ClientHello
    20. */
    21. case SSL_CLIENT_HELLO:
    22. ret = ssl_write_client_hello( ssl );
    23. break;
    24. /*
    25. *  <==   ServerHello
    26. *        Certificate
    27. *      ( ServerKeyExchange  )
    28. *      ( CertificateRequest )
    29. *        ServerHelloDone
    30. */
    31. case SSL_SERVER_HELLO:
    32. ret = ssl_parse_server_hello( ssl );
    33. break;
    34. case SSL_SERVER_CERTIFICATE:
    35. ret = ssl_parse_certificate( ssl );
    36. break;
    37. case SSL_SERVER_KEY_EXCHANGE:
    38. ret = ssl_parse_server_key_exchange( ssl );
    39. break;
    40. case SSL_CERTIFICATE_REQUEST:
    41. ret = ssl_parse_certificate_request( ssl );
    42. break;
    43. case SSL_SERVER_HELLO_DONE:
    44. ret = ssl_parse_server_hello_done( ssl );
    45. break;
    46. /*
    47. *  ==> ( Certificate/Alert  )
    48. *        ClientKeyExchange
    49. *      ( CertificateVerify  )
    50. *        ChangeCipherSpec
    51. *        Finished
    52. */
    53. case SSL_CLIENT_CERTIFICATE:
    54. ret = ssl_write_certificate( ssl );
    55. break;
    56. case SSL_CLIENT_KEY_EXCHANGE:
    57. ret = ssl_write_client_key_exchange( ssl );
    58. break;
    59. case SSL_CERTIFICATE_VERIFY:
    60. ret = ssl_write_certificate_verify( ssl );
    61. break;
    62. case SSL_CLIENT_CHANGE_CIPHER_SPEC:
    63. ret = ssl_write_change_cipher_spec( ssl );
    64. break;
    65. case SSL_CLIENT_FINISHED:
    66. ret = ssl_write_finished( ssl );
    67. break;
    68. /*
    69. *  <==   ChangeCipherSpec
    70. *        Finished
    71. */
    72. case SSL_SERVER_CHANGE_CIPHER_SPEC:
    73. ret = ssl_parse_change_cipher_spec( ssl );
    74. break;
    75. case SSL_SERVER_FINISHED:
    76. ret = ssl_parse_finished( ssl );
    77. break;
    78. case SSL_FLUSH_BUFFERS:
    79. SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
    80. ssl->state = SSL_HANDSHAKE_OVER;
    81. break;
    82. default:
    83. SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
    84. return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
    85. }
    86. if( ret != 0 )
    87. break;
    88. }
    89. SSL_DEBUG_MSG( 2, ( "<= handshake client" ) );
    90. return( ret );
    91. }

http://blog.****.net/chenlong12580/article/details/30556955