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库文件,如下图:

2、服务器端

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

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

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

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

代码:

工程文件:

#-------------------------------------------------
#
# Project created by QtCreator 2014-05-11T22:28:07
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = MyPolarSSLToolSrv
TEMPLATE = app

INCLUDEPATH += /home/chenlong12580/develop/polarTool/polarssl/include
LIBS += -L "/home/chenlong12580/develop/polarTool/polarssl/lib/" -lpolarssl

SOURCES += main.cpp        widget.cpp     workthread.cpp

HEADERS  += widget.h     workthread.h

FORMS    += widget.ui

线程类:

void WorkThread::run()
{
    qDebug() << "I am a thread!";

    int listen_fd = 0;
    int client_fd =0;
    int ret= 0;
    havege_state hs;
    ssl_context ssl;
    ssl_session ssn;
    x509_cert srvcert;
    rsa_context rsa;
    unsigned char buf[1024];
    int len = 0;

    memset( &srvcert, 0, sizeof( x509_cert ) );

    ret = x509parse_crt( &srvcert, (unsigned char *) test_srv_crt,
                         strlen( test_srv_crt ) );
    if( ret != 0 )
    {
        printf( " failed\n  !  x509parse_crt returned %d\n\n", ret );
        return;
    }

    ret = x509parse_crt( &srvcert, (unsigned char *) test_ca_crt,
                         strlen( test_ca_crt ) );
    if( ret != 0 )
    {
        printf( " failed\n  !  x509parse_crt returned %d\n\n", ret );
        return;
    }

    ret =  x509parse_key( &rsa, (unsigned char *) test_srv_key,
                          strlen( test_srv_key ), NULL, 0 );
    if( ret != 0 )
    {
        printf( " failed\n  !  x509parse_key returned %d\n\n", ret );
        return;
    }

    ret = net_bind( &listen_fd, NULL, 8443 );
    if (0 != ret)
    {
        qDebug() << ret;
        return;
    }

    qDebug() << "bind ok";

    /* socket is block */
    ret = net_accept( listen_fd, &client_fd, NULL );
    if (0 != ret)
    {
        return;
    }

    qDebug() << "accept ok";

    havege_init( &hs );

    ret = ssl_init( &ssl );
    if (0 != ret)
    {
        return;
    }

    ssl_set_endpoint( &ssl, SSL_IS_SERVER );
    ssl_set_authmode( &ssl, SSL_VERIFY_NONE );

    ssl_set_rng( &ssl, havege_rand, &hs );
    ssl_set_dbg( &ssl, my_debug, stdout );
    ssl_set_bio( &ssl, net_recv, &client_fd,
                 net_send, &client_fd );
    ssl_set_scb( &ssl, my_get_session,
                 my_set_session );

    ssl_set_ciphers( &ssl, my_ciphers );
    ssl_set_session( &ssl, 1, 0, &ssn );

    memset( &ssn, 0, sizeof( ssl_session ) );

    ssl_set_ca_chain( &ssl, srvcert.next, NULL );
    ssl_set_own_cert( &ssl, &srvcert, &rsa );
    ssl_set_dh_param( &ssl, my_dhm_P, my_dhm_G );

    qDebug() << "before ssl_handshake ok";

    while( ( ret = ssl_handshake( &ssl ) ) != 0 )
    {
        ;
    }

    qDebug() << "ssl_handshake ok";

    do
    {
        len = sizeof( buf ) - 1;
        memset( buf, 0, sizeof( buf ) );
        ret = ssl_read( &ssl, buf, len );

        if( ret == POLARSSL_ERR_NET_TRY_AGAIN )
            continue;

        if( ret <= 0 )
        {
            switch( ret )
            {
            case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
                printf( " connection was closed gracefully\n" );
                break;

            case POLARSSL_ERR_NET_CONN_RESET:
                printf( " connection was reset by peer\n" );
                break;

            default:
                printf( " ssl_read returned %d\n", ret );
                break;
            }

            break;
        }

        len = ret;
        printf( " %d bytes read\n\n%s", len, (char *) buf );
    }while( 0 );

    char *cc = (char *)buf;
    QString ss(cc);

    qDebug() << ss;

    (void)sprintf( (char *) buf, HTTP_RESPONSE,
                       ssl_get_cipher( &ssl ) );

    while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
    {
        if( ret == POLARSSL_ERR_NET_CONN_RESET )
        {
            printf( " failed\n  ! peer closed the connection\n\n" );
            return;
        }

        if( ret != POLARSSL_ERR_NET_TRY_AGAIN )
        {
            printf( " failed\n  ! ssl_write returned %d\n\n", ret );
            return;
        }
    }

    ssl_close_notify( &ssl );

    net_close( client_fd );
    x509_free( &srvcert );
    rsa_free( &rsa );
    ssl_free( &ssl );

    cur = s_list_1st;
    while( cur != NULL )
    {
        prv = cur;
        cur = cur->next;
        memset( prv, 0, sizeof( ssl_session ) );
        free( prv );
    }

    memset( &ssl, 0, sizeof( ssl_context ) );
}

主窗口类:

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QDebug>
#include <QMessageBox>
#include "workthread.h"
#include "polarssl/havege.h"
#include "polarssl/certs.h"
#include "polarssl/x509.h"
#include "polarssl/ssl.h"
#include "polarssl/net.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    qDebug() << "server";

    connect(this, SIGNAL(emit_parse_cer()), this, SLOT(slot_parse_cer()));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_BrowseBtn_clicked()
{
    QString pathStr = QFileDialog::getOpenFileName(this, QString("选择证书文件"), QString("C:\\Users\\Administrator\\Desktop"), QString("*.*"));
    if (pathStr.length() == 0)
    {
        qDebug() << "please select a cer file!";
        return;
    }

    ui->PathEdit->setText(pathStr);

    emit emit_parse_cer();
}

void Widget::slot_parse_cer()
{
    x509_cert crt;
    memset(&crt, 0, sizeof(crt));

    int res = x509parse_crtfile( &crt, ui->PathEdit->text().toLatin1().data());
    if (0 != res)
    {
        QMessageBox::warning(this, "警告", "解析证书失败,请选择正确的证书文件", QMessageBox::Ok);
        return;
    }

    ui->CrtInfo->setText(QString("是否为根证书:") + QString::number(crt.ca_istrue));
    ui->CrtInfo->append(QString("证书版本号:") + QString::number(crt.version));
    ui->CrtInfo->append(QString("有效期:") + QString::number(crt.valid_from.year) + "-" + QString::number(crt.valid_from.mon)
    + QString("  到:") + QString::number(crt.valid_to.year) + "-" + QString::number(crt.valid_to.mon));

    qDebug() << crt.ca_istrue;
    qDebug() << crt.valid_from.year;
}

void Widget::on_pushButton_clicked()
{
    WorkThread *workThread = new WorkThread;
    workThread->start();
}

3、客户端

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

工程文件:

#-------------------------------------------------
#
# Project created by QtCreator 2014-05-11T22:28:07
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = MyPolarSSLToolCli
TEMPLATE = app

INCLUDEPATH += /home/chenlong12580/develop/polarTool/polarssl/include
LIBS += -L "/home/chenlong12580/develop/polarTool/polarssl/lib/" -lpolarssl

SOURCES += main.cpp        widget.cpp

HEADERS  += widget.h

FORMS    += widget.ui

主窗口类:

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QDebug>
#include <QMessageBox>
#include "polarssl/havege.h"
#include "polarssl/certs.h"
#include "polarssl/x509.h"
#include "polarssl/ssl.h"
#include "polarssl/net.h"

#define SERVER_PORT 8443
/*
#define SERVER_NAME "localhost"
#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
*/
#define SERVER_NAME "polarssl.org"
#define GET_REQUEST     "GET /hello/ HTTP/1.1\r\n"     "Host: polarssl.org\r\n\r\n"

#define DEBUG_LEVEL 0

void my_debug( void *ctx, int level, char *str )
{
    if( level < DEBUG_LEVEL )
    {
        fprintf( (FILE *) ctx, "%s", str );
        fflush(  (FILE *) ctx  );
    }
}

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    qDebug() << "client";

    connect(this, SIGNAL(emit_parse_cer()), this, SLOT(slot_parse_cer()));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_BrowseBtn_clicked()
{
    QString pathStr = QFileDialog::getOpenFileName(this, QString("选择证书文件"), QString("C:\\Users\\Administrator\\Desktop"), QString("*.*"));
    if (pathStr.length() == 0)
    {
        qDebug() << "please select a cer file!";
        return;
    }

    ui->PathEdit->setText(pathStr);

    emit emit_parse_cer();
}

void Widget::slot_parse_cer()
{
    x509_cert crt;
    memset(&crt, 0, sizeof(crt));

    int res = x509parse_crtfile( &crt, ui->PathEdit->text().toLatin1().data());
    if (0 != res)
    {
        QMessageBox::warning(this, "警告", "解析证书失败,请选择正确的证书文件", QMessageBox::Ok);
        return;
    }

    ui->CrtInfo->setText(QString("是否为根证书:") + QString::number(crt.ca_istrue));
    ui->CrtInfo->append(QString("证书版本号:") + QString::number(crt.version));
    ui->CrtInfo->append(QString("有效期:") + QString::number(crt.valid_from.year) + "-" + QString::number(crt.valid_from.mon)
    + QString("  到:") + QString::number(crt.valid_to.year) + "-" + QString::number(crt.valid_to.mon));

    qDebug() << crt.ca_istrue;
    qDebug() << crt.valid_from.year;
}

void Widget::on_pushButton_clicked()
{
    int ret, len, server_fd;
    unsigned char buf[1024];
    havege_state hs;
    ssl_context ssl;
    ssl_session ssn;

    /*
         * 0. Initialize the RNG and the session data
         */
    havege_init( &hs );
    memset( &ssn, 0, sizeof( ssl_session ) );

    /*
         * 1. Start the connection
         */
    printf( "\n  . Connecting to tcp/%s/%4d...", SERVER_NAME,
            SERVER_PORT );
    fflush( stdout );

    if( ( ret = net_connect( &server_fd, "127.0.0.1",
                             SERVER_PORT ) ) != 0 )
    {
        printf( " failed\n  ! net_connect returned %d\n\n", ret );
        return;
    }

    printf( " ok\n" );

    /*
         * 2. Setup stuff
         */
    printf( "  . Setting up the SSL/TLS structure..." );
    fflush( stdout );

    if( ( ret = ssl_init( &ssl ) ) != 0 )
    {
        printf( " failed\n  ! ssl_init returned %d\n\n", ret );
        return;
    }

    printf( " ok\n" );

    ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
    ssl_set_authmode( &ssl, SSL_VERIFY_NONE );

    ssl_set_rng( &ssl, havege_rand, &hs );
    ssl_set_dbg( &ssl, my_debug, stdout );
    ssl_set_bio( &ssl, net_recv, &server_fd,
                 net_send, &server_fd );

    ssl_set_ciphers( &ssl, ssl_default_ciphers );
    ssl_set_session( &ssl, 1, 600, &ssn );

    /*
         * 3. Write the GET request
         */
    printf( "  > Write to server:" );
    fflush( stdout );

    len = sprintf( (char *) buf, GET_REQUEST );

    while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
    {
        if( ret != POLARSSL_ERR_NET_TRY_AGAIN )
        {
            printf( " failed\n  ! ssl_write returned %d\n\n", ret );
            return;
        }
    }

    len = ret;
    printf( " %d bytes written\n\n%s", len, (char *) buf );

    /*
         * 7. Read the HTTP response
         */
    printf( "  < Read from server:" );
    fflush( stdout );

    do
    {
        len = sizeof( buf ) - 1;
        memset( buf, 0, sizeof( buf ) );
        ret = ssl_read( &ssl, buf, len );

        if( ret == POLARSSL_ERR_NET_TRY_AGAIN )
            continue;

        if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY )
            break;

        if( ret <= 0 )
        {
            printf( "failed\n  ! ssl_read returned %d\n\n", ret );
            break;
        }

        len = ret;
        printf( " %d bytes read\n\n%s", len, (char *) buf );
    }
    while( 0 );

   char *cc= (char *)buf;
   QString ss(cc);

    qDebug() << ss;

    ssl_close_notify( &ssl );

    return;
}

4、运行效果

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

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

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

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

Qt中调用PolarSSL库(一)

时间: 2024-11-03 22:28:45

Qt中调用PolarSSL库(一)的相关文章

Qt调用PolarSSL库(一个)

最近一直在学习SSL相关知识,也明白了理论相关知识,主要SSL基本概念和连接建立.主要依据PolarSSL开源库学习.学习完了之后就希望能给有所运用,就想用Qt写一个简单的程序,添加对SSL相关概念的把握和对PolarSSL库的运用.当然,终于希望是能够使用Qt做一个比較完好的工具,帮助大家更好的理解和学习SSL相关知识.这都是后话,在第一篇里面,我们就简单用样例展示怎样在Qt里面调用PolarSSL库. 这篇博客主要是解说Qt里面调用PolarSSL库,至于SSL相关概念在后面的博客再具体介绍

Qt中添加OpenCV库

配置在Qt中的OpenCV,看了很多“教程”,最终成功.记一下过程. 本机配置: window7 32位系统: qt-opensource-windows-x86-mingw492-5.5.1: OpenCV2.4.10. 对于我来说配置过程比较难,因为目前我没用过Qt和Cmake,之前一直用VS编译C++,也没有用过MinGW,所以看教程中的各种命令或者执行文件都比较费时.这次各种尝试后成功.参考资料的连接在最后,其中帮助我最大的就是那一篇纯英文的,很详细. 前期准备 Qt5的opensour

QT中使用Glut库

用Qt中的QGLWidget窗体类中是不包括glut工具库的,难怪在myGLWidget(在我的程序中是QGLWidget的派生类)中绘制实心球体是说“glutSolidSphere”: 找不到标识符,就是说没有这个函数的声明.接下来就来安装glut库: 1.先下载glut库 http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip. 2.将下载下来的文件解压,将glut32.lib和glut.lib两个lib文件移到qt

qt中调用shell脚本并监控返回的方法

在QT中经常要调用外部命令或者是执行shell脚本,并且要对执行结果进行分析. QProcess runShellProcess =new QProcess(this); //调用过程输出的监控 connect(runShellProcess, SIGNAL(readyRead()), this, SLOT(readProcess())); connect(runShellProcess, SIGNAL(finished(int)), this, SLOT(finishedProcess()))

iOS开发:在Swift中调用oc库

先列举这个工程中用到的oc源码库: MBProgressHUD:半透明提示器,Loading动画等 SDWebImage:图片下载和缓存的库 MJRefresh: 下拉刷新,上拉加载 Alamofire.xcodeproj和SwiftyJSON.xcodeproj是Swift的库,这篇博客主要记录调用上面4个oc的库. 第一步:将oc的源码库拖入到我们的projec,如下图. 第二步:新建一个头文件,用于引用oc的库.如下图,选择 object library 中的 头文件,拖拽到project

【转】QT中添加 动态库(.so) 和 静态库 (.a) 的方法

http://blog.csdn.net/yzj19870824/article/details/6933737 在QT 的Makefile文件中: 1 添加动态库,如lipcap.so 则,在LIBS一行中添加“-L/usr/local/lib -lpcap”,依据自己的情况修改libpcap.so的路径 2 添加静态库,如libtinyxml.a 则,在LIBS一行添加“/home/yzj/tinyxml/libtinyxml.a”: 在INCPATH一行添加“ -I /home/yzj/t

在Android中调用KSOAP2库访问webservice服务出现的服务端返回AnyType{}

最近在做毕业设计的时候,涉及到了安卓端访问web service服务端数据库,并返回一个值,当我把web service测试通过后,想写一个简单的安卓测试程序,来实现服务端数据库访问,通过web service中的一个serch()方法,然后发现,每次的返回值都是一个AnyType{},Logcat如图所示: 网上搜集了很多资料,产生的原因其实很简答,是因为服务端返回值为null,Logcat中显示的就职anyType{},找到了原因,解决起来也就好说了,其中包括这些方法: {解决方法引用自博客

算法第四版 在Eclipse中调用Algs4库

首先下载Eclipse,我选择的是Eclipse IDE for Java Developers64位版本,下载下来之后解压缩到喜欢的位置然后双击Eclipse.exe启动 然后开始新建项目,File -> New Java Project,项目名随便写,如下图 右键src文件夹,Add -> New Java Class,这里需要注意Name一栏里填写的内容就是类名,这里我写了TestAlgs4,为了测试「算法 第四版」作者给的那个测试样例 代码如下: import edu.princeto

在QT中使用FFmpeg库的部分报错问题

win32: LIBS += -L$$PWD/../ffmpeg-win32-dev/lib/ -lavutil win32: LIBS += -L$$PWD/../ffmpeg-win32-dev/lib/ -lavformat win32: LIBS += -L$$PWD/../ffmpeg-win32-dev/lib/ -lswresample win32: LIBS += -L$$PWD/../ffmpeg-win32-dev/lib/ -lswscale INCLUDEPATH +=