网络安全综合课程设计指导书要点.docx
《网络安全综合课程设计指导书要点.docx》由会员分享,可在线阅读,更多相关《网络安全综合课程设计指导书要点.docx(32页珍藏版)》请在冰点文库上搜索。
网络安全综合课程设计指导书要点
网络安全综合课程设计
基于SSL的C/S安全通信程序的实现
实验指导书
专业实验中心
2013-7
目录
第一章、设计环境及目的
1、实验环境
Windowsxp,visualC++,UltraEdit,ActivePerl-5.8.6.811-MSWin32-x86-122208等工具软件,并结合了openssl-0.9.7b等工具。
2、实验目的
1)熟悉计算机的加密和应用,熟悉Socket通信编程函数,掌握TCP/IP协议的客服端、服务器模式的网络编程。
2)了解openssl的编译过程。
3)了解CA如何申请、下载和安装。
以及如何进行公私钥分割。
4)ActivePerl工具软件的安装及运用。
5)编译,搭建Openssl开发环境。
6)综合运用Socket编程和Openssl安全套接字编程建立安全通信通道。
第二章、相关技术介绍
1.CA
CA:
CA是PKI系统中通信双方都信任的实体,被称为可信第三方(TrustedThirdParty,简称TTP)。
CA作为可信第三方的重要条件之一就是CA的行为具有非否认性。
作为第三方而不是简单的上级,就必须能让信任者有追究自己责任的能力。
CA通过证书证实他人的公钥信息,证书上有CA的签名。
用户如果因为信任证书而导致了损失,证书可以作为有效的证据用于追究CA的法律责任。
正是因为CA愿意给出承担责任的承诺,所以也被称为可信第三方。
在很多情况下,CA与用户是相互独立的实体,CA作为服务提供方,有可能因为服务质量问题(例如,发布的公钥数据有错误)而给用户带来损失。
证书中绑定了公钥数据、和相应私钥拥有者的身份信息,并带有CA的数字签名。
证书中也包含了CA的名称,以便于依赖方找到CA的公钥、验证证书上的数字签名。
1)CA的层级结构:
CA建立自上而下的信任链,下级CA信任上级CA,下级CA由上级CA颁发证书并认证。
2)CA提供的服务:
颁发证书、废除证书、更新证书、验证证书、管理密钥。
2.OpenSSL
OpenSSL:
为网络通信提供安全及数据完整性的一种安全协议,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。
利用OpenSSL开发包编写建立在SSL上的C/S程序,包含客户端和服务器端程序。
OpenSSL采用C语言作为开发语言,这使得OpenSSL具有优秀的跨平台性能,这对于广大技术人员来说是一件非常美妙的事情,可以在不同的平台使用同样熟悉的东西。
OpenSSL支持Linux、Windows、BSD、Mac、VMS等平台,这使得OpenSSL具有广泛的适用性。
3.Winsocket编译原理
WindowsSockets接口是TCP/IP网络最为通用API(应用程序接口),已成为Windows网络编程的事实上的标准。
它以Unix中流行的Socket接口为范例定义了一套MicrosoftWindows下网络编程接口函数库。
它不仅包含了人们所熟悉的BerkeleySocket风格的库函数;也包含了一组针对Windows的扩展库函数,以使程序员能充分地利用Windows消息驱动机制进行编程。
SOCKET实际在计算机中提供了一个通信端口,可以通过这个端口与任何一个具有SOCKET接口的计算机通信。
应用程序在网络上传输,接收的信息都通过这个SOCKET接口来实现。
在应用开发中就像使用文件句柄一样,可以对SOCKET句柄进行读,写操作。
VC++对原来的WindowsSockets库函数进行了一系列封装,继而产生了CAsynSocket、CSocket、CSocketFile等类,它们封装着有关Socket的各种功能。
在VC中进行WINSOCK的API编程开发,需要使用到下面三个文件:
1)WINSOCK.H:
这是WINSOCKAPI的头文件。
2)WSOCK32.LIB:
WINSOCKAPI连接库文件。
在使用中,一点要把它作为项目的非缺省的连接库包含到项目文件中去。
3)WINSOCK.DLL:
WINSOCK的动态连接库。
总的来说,使用SOCKET接口(面向连接或无连接)进行网络通信时,必须按下面简单的四步进行处理:
1)程序必须建立一个SOCKET。
2)程序必须按要求配置此SOCKET。
也就是说,程序要么将此SOCKET连接到远方的主机上,要么给此SOCKET指定一个本地协议端口。
3)程序必须按要求通过此SOCKET发送和接收数据。
4)程序必须关闭此SOCKET。
程序分为两部分:
客户端和服务器端,我们的目的是利用SSL/TLS的特性保证通信双方能够互相验证对方身份(真实性),并保证数据的完整性,私密性.服务器和客服端程序框架的建立,另外重点是证书文件的生成。
本次编程基本上是改造的openssl自带的demos目录下的cli.cpp,serv.cpp文件,做了一些修改,并增加了一些功能。
第三章、设计步骤与开发平台的搭建
1、环境搭建
1)安装ActivePerl-5.6.1.629-MSWin32-x86-multi-thread.
2)打开控制台程序,在openssl解压后的目录下执行PerlConfigureVC-WIN32命令,注意,一定要在这个目录下执行该命令,否则找不到Configure文件,当然,你也可以指定完整的Configure文件路径。
顺利通过。
3)根据openssl的帮助说明,在解压目录下执行ms\do_masm(和ms_\do_ms)命令,成功通过。
4)配置VC环境变量,我在相同的控制台程序下转到VC所在目录下的vc98\bin目录,执行vcvars32批处理命令,设置VC的环境变量,然后再转到openssl解压包的根目录下。
5)在openssl解压目录下执行nmake-fms\ntdll.mak,如果没有错误,就完成编译了。
输出的文件在out32dll里面,包括应用程序的可执行文件、两个Lib文件和两个dll文件。
2、证书下载
1)访问http:
//172.16.110.5/certsrv申请证书、导出包含公私钥的pfx文件。
申请证书-->高级-->使用表格CA-->标记为密钥可导出(导出到文件--不要选择)-->安装证书。
2)IE-->internet选项-->内容-->证书-->选中刚才安装的证书,导出-->是,导出私钥-->(缺省)下一步-->密码(1234)-->文件名(mykey.pfx).
3、公私钥分割
注:
红色字体为系统提示,黑色字体为输入或输入的说明。
1)运行openssl
E:
\openss\out32dll>openssl
2)在openssl环境下运行。
Openssl>pkcs12–ind:
\ok\mykey.pfx–outd:
\ok\mypem.pem
EnterImportPassword:
此处输入mykey.pfx的密码“1234”
MACverifiedok
EnterPEMpassphrase:
此处输入保护私钥的密码(注:
也就是服务器端加载私钥时要输入的密码)
Verifying-EnterPEMpassphrase:
验证输入
Openssl>quit
3)经过第2步所生成的mypem.pem文件即包含公钥又包含私钥,但和mykey.pfx比较编码格式发生了变化。
分割过程:
(1)Ultraedit打开mypem.pem。
(2)找到
-----BEGINRSAPRIVATEKEY-----
…….
-----ENDRSAPRIVATEKEY-----
将这一部分(如图1的阴影部分)内容复制并另存为chkey.pem,即私钥文件。
图1
4)找到-----BEGINCERTIFICATE-----
……….
-----ENDCERTIFICATE-----将这一部分(如下图的阴影部分)内容复制并另存为chcert.pem,即公钥钥文件。
第四章、系统结构
通信系统需要由以下几个部分组成:
SSL加密通信、身份认证、证书管理。
安全通信系统结构
1、身份认证模块设计方法
1)证书与密钥交换算法的选择
在SSL协议中证书的一个重要作用就是参与通信双方对密钥交换算法的选择。
在通信双方开始进行算法协商时,SSL客户端在它发给SSL服务端的客户问候消息中列出了所有客户端支持的加密算法套件,每个加密套件中有一项标识了该加密套件支持的密钥交换算法,选择什么的密钥交换算法由SSL服务端所拥有的证书决定。
SSL服务端在对客户端发来的加密套件进行选择时,要通过它拥有的证书类型来决定是否该选择该加密套件。
我们使用两种方法来划分证书的类型,第一种是依据证书的用途,证书从其用途可以分为加密证书和签名证书等,它们分别指定证书在使用中的不同用途,加密证书用来加密数据,保证数据的保密性,签名证书用来对数据进行签名,保证数据的不可抵赖性。
第二种划分方法是依据证书绑定的公钥类型,目前我们的证书中可以绑定下列公钥加密算法的公钥:
RSA、DH、ECC和DSS。
在SSL中这两种证书类型的划分方法都要考虑到,因为它们从不同的方面影响着SSL对密钥交换算法的选择,进而决定了SSL的握手过程。
下面我们介绍一下在SSL握手过程中进行算法协商时证书所起的作用。
当SSL客户端发起SSL连接请求时,它向SSL服务端发送客户问候消息,客户问候消息中包含有客户端支持的所有加密套件,加密套件中包含有该套件支持的密钥交换算法。
SSL服务端在接收到客户端发来的客户问候消息后,它要从客户端支持的加密套件组中选择一个加密套件,其中一个重要依据就是服务端拥有的证书。
如果待选择的加密套件中有SSLRSAWITHIDEACBCSHA,它要求服务端必须提供RSA证书用于鉴别身份和交换密钥,此时如果SSL服务端有RSA证书,它就可以选择该加密套件,由于RSA证书中已经包含了密钥交换算法的参数,服务端就不需要在向客户端发送密钥交换消息。
客户端在与服务端进行密钥交换时,就是利用该证书中绑定的公钥来加密预加密密钥。
如果服务端没有RSA证书,而只有支持DSS算法的签名证书,它就有可能选择另一个待选择的加密套件SSLDHDSSWITH3DESEDECBCSHA,该加密套件要求密钥交换采用DH算法,同时必须对服务端进行身份鉴别,因为服务端证书消息中的DSS证书只能供客户端进行身份认证,所以DH算法的参数需要通过服务端密钥交换消息传给客户端。
2)证书与身份认证
证书的另一个重要作用就是身份认证。
基于证书的身份认证过程如下:
①SSL服务端向SSL客户端发送证书消息,随后,SSL服务端再向客户端发送证书请求消息,该消息由两部分组成,第一部分是请求的证书类型,第二部分是请求证书的发证者CA的名字,也就是服务端信任的CA的名字。
②SSL客户端在接收到SSL服务端发来的证书消息后,首先认证服务端证书,如果认证通过,则继续接收后面的消息,否则将向服务端发送警告消息,并终止连接。
当SSL客户端接收到服务端发来的证书请求消息后,需要向服务端发送客户证书消息,客户证书消息中包含有客户端证书,该证书必须满足服务端在证书请求中列出的条件,即该证书必须是服务端信任的CA签发的。
在上面我们提到在SSL服务端证书和客户端证书都分别包含在证书消息中,实际上在证书消息中不只是一个证书,而是~个证书链。
证书链由最终实体证书到根以证书的一系列顺序排列的证书组成,对证书的认证上就是对该证书链进行认证。
在SSL协议中并没有规定具体的认证证书的方法,因此在我们对SSL协议进行实现的过程中必须从可行的认证方法中选择一种有效和安全的认证方法。
我们对证书链的认证主要是认证证书链中每个证书是否是被其上一级以所签发的,这个过程可以沿着证书链从实体证书一直到证书链的末端(即根证书)来顺序进行。
2、传输加密模块设计方法
采用SSL协议的公开实现OpemSSL提供安全的传输机制,应用程序数据的传输过程为:
1)程序把应用数据提交给本地的SSL。
2)发送端的SSL先用对应连接的散列算法对应用数据进行散列,得到一个应用数据的散列值。
3)散列值和应用数据一起用加密算法加密。
4)密文通过网络传给对方。
5)接收方的SSL用相同的算法对密文解密,得到明文。
6)接收方的SSL用相同的散列算法对明文中的应用数据散列。
7)计算得到的散列值与明文中的散列值比较,如果一致,明文中的应用数据有效,SSL把应用数据上交给接收方的应用层;否则就丢弃数据,并向对方发出报警信息。
严重的错误有可能引起再次的协商或连接中断。
SSL通信模型为标准的C/S结构,除了在TCP层之上进行传输之外,与一
般的通信没有明显区别,其服务器端的基本程序结构如下:
1)在使用OpemSSL前,必须先对OpenSSL进行初始化。
2)一次SSL连接会话一般要先申请一个SSL环境,创建本次会话所使用的
协议:
需要注意的是客户端和服务器需要使用相同的协议,然后申请SSL会话
的环境,使用不同的协议进行会话,其环境也不同。
根据自己的需要设置SSL
握手阶段证书的验证方式和加载自己的证书。
3)SSL使用TCP协议,需要把SSL绑定到已经连接的套接字上。
4)接下来是SSL握手。
5)握手成功之后,就可以进行通信了,使用SSL.read和SSL.write读写SSL套接字代替传统的read和write,使用SSL.accept代替传统的accept调用。
6)通信结束,需要释放前面申请的SSL资源。
第五章、程序设计提示与测试
1、初始化SSL证书
1)初始化Openssl算法库及协议算法
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
SSL_METHOD*meth;
meth=SSLv23_server_method();//使用SSLV2或V3协议
ctx=SSL_CTX_new(meth);//初始化SSL上下文
2)验证证书(此为验证客户端)
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,verify_callback_server);//验证客户端
SSL_CTX_set_verify(ctx,SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);//不验证客户端
SSL_CTX_load_verify_locations(ctx,ROOTCERTF,NULL);//若验证,则放置CA证书
SSL_CTX_set_verify_depth(ctx,1);
SSL_CTX_set_cipher_list(ctx,"RC4-MD5");
3)设置证书、私钥及验证(此为设置服务端)
if(SSL_CTX_use_certificate_file(ctx,CERTF,SSL_FILETYPE_PEM)<=0)
{
returnFALSE;
}//设子服务器证书
if(SSL_CTX_use_PrivateKey_file(ctx,KEYF,SSL_FILETYPE_PEM)<=0)
{
returnFALSE;
}//设置服务器私钥
if(!
SSL_CTX_check_private_key(ctx))
{
returnFALSE;
}//检查服务器私钥和证书是否匹配
2、启动线程处理函数
1)初始化WindowsSocket
if(WSAStartup(MAKEWORD(2,2),&wsaData))
{
char*msg=(char*)malloc(128);
strcpy(msg,"初始化Socket失败!
");
SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_STATE_MSG,0,(long)msg);
return;
}
2)初始化sockaddr_in结构体
memset(&sa_serv,'\0',sizeof(sa_serv));
sa_serv.sin_family=AF_INET;
sa_serv.sin_addr.s_addr=INADDR_ANY;
sa_serv.sin_port=htons(port);
3)启动接收连接线程
for(;;)
{
hd=CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE)AcceptThreadProc,
(void*)listen_sd,0,&idThread);
//等待该线程执行完毕,开启下一个线程,继续等待接收连接。
WaitForSingleObject(hd,INFINITE);
}
3、接收消息线程处理函数
1)调用select异步等待消息
for(;;)
{
FD_ZERO(&writeFds);
FD_ZERO(&readFds);
FD_ZERO(&excFds);
FD_SET(clientFd,&readFds);
//异步的方式等待客户端数据
intnfd=select(maxFd+1,&readFds,&writeFds,&excFds,NULL);
2)接收服务器消息
if(FD_ISSET(sd,&readFds))
{
//接收服务器消息
intlen=SSL_read(ssl,buffer,sizeof(buffer));
if(len<=0)
{
char*msg=(char*)malloc(128);
strcpy(msg,"服务器退出!
");
SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_STATE_MSG,sd,(long)msg);
return;
}
提取客户端数据
if(FD_ISSET(clientFd,&readFds))//有客户端数据需要读取
{
//接收客户端数据
len=SSL_read(clientDesc.ssl,buffer,sizeof(buffer));
if(len<=0)
{
//char*msg=(char*)malloc(128);
strcpy(msg,"客户端退出!
");
SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_STATE_MSG,clientFd,(long)msg);
return;
}
buffer[len]='\0';
char*msg1=(char*)malloc(len+1);
strcpy(msg1,buffer);
//发送WM_CLIENT_MSG消息到主窗体,把接收到的消息显示到列表框
SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_CLIENT_MSG,clientFd,(long)msg1);
}
4、发送消息函数
1)服务器发送消息
voidCServerDlg:
:
OnSend()
{
UpdateData();
//遍续所有已经链接客户端,发送消息
for(inti=0;i{
if(Clients[i].fd!
=0)
{
//发送消息
SSL_write(Clients[i].ssl,m_str.GetBuffer(0),m_str.GetLength());
m_str.ReleaseBuffer();
}
}
m_list.InsertString(0,m_str);
m_str.Empty();
UpdateData(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT1))->SetActiveWindow();
}
2)服务端发送消息
voidCClientDlg:
:
OnSend()
{
UpdateData();
if(client.fd!
=0)
{
//发送消息
SSL_write(client.ssl,m_str.GetBuffer(0),m_str.GetLength());
m_str.ReleaseBuffer();
}
else
{
return;
}
}
5、服务端程序的框架
/*生成一个SSL结构并初始化*/
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
meth=SSLv23_server_method();
ctx=SSL_CTX_new(meth);
/*正常的socket过程*/
//为接收客户端连接准备服务器端TCPsocket连接.
listen_sd=socket(AF_INET,SOCK_STREAM,0);
CHK_ERR(err,"socket");
memset(&sa_serv,'\0',sizeof(sa_serv));
//设置通信协议为TCP/IP协议
sa_serv.sin_family=AF_INET;
//设置接收IP地址为任意IPADDR
sa_serv.sin_addr.s_addr=INADDR_ANY;
//设置server的端口号
sa_serv.sin_port=htons(serverport);
//绑定端口号
err=bind(listen_sd,(structsockaddr*)&sa_serv,
sizeof(sa_serv));CHK_ERR(err,"bind");
//开始监听TCP连接
err=listen(listen_sd,5);CHK_ERR(err,"listen");
client_len=sizeof(sa_cli);
//接收到一个客户端的连接
sd=accept(listen_sd,(structsockaddr*)&sa_cli,&client_len);CHK_ERR(sd,"accept");
//关闭TCP连接
closesocket(listen_sd);
printf("Connectionfrom%lx,port%x\n",
sa_cli.sin_addr.s_addr,sa_cli.sin_port);
/*把建立好的socket和SSL结构联系起来*/
TCP连接已经准备好,开始启用server端的SSL.
ssl=