|
在Windows CE上实现网络安全功能
王珂
(转载自计算机世界日报
2000/07/18)
一、概述
---- 现在掌上电脑越来越普及,Windows
CE上的程序也随之流行,其中网络应用程序尤其受到欢迎,而网络安全和加密传输是其中的一个重要方面。本文介绍如何使用Visual
C++实现Windows CE上的网络安全功能。
---- Windows CE支持PCT 1.0以及SSL
2.0和3.0。这些协议可以通过WinINET或者直接通过Winsock来访问。本文将分别介绍这两种方法。
二、使用WinINET访问加密协议
---- 使用WinINET访问加密协议是使用加密协议最简单的方法。
---- 使用WinINET访问加密协议的步骤
---- 1.
使用InternetConnect函数连接,将dwFlags参数设置为INTERNET_FLAG_SECURE。
----
InternetConnect函数用于打开一个FTP、Gopher或HTTP站点。如果成功,将返回该FTP、Gopher或HTTP会话的句柄;如果不成功,返回NULL。InternetConnect的函数原型为:
HINTERNET InternetConnect( IN HINTERNET hInternetSession, IN LPCSTR
lpszServerName, IN INTERNET_PORT nServerPort, IN LPCSTR lpszUsername,
IN LPCSTR lpszPassword, IN DWORD dwService, IN DWORD dwFlags, IN DWORD
dwContext ); ---- 这里需要设置8个参数,其中:
- hInternetSession为目前会话的句柄。该句柄必须是上一个InternetOpen函数的返回值;
- lpszServerName指向包含Internet服务器的主机名称(如http://www.mit.edu)或IP地址(如202.102.13.141)的字符串;
- nServerPort是将要连结到的TCP/IP的端口号,可以使用一些预定的常量,详见表1;
---- 表1:预定义的TCP/IP端口值
| 名称 |
端口值 |
| INTERNET_DEFAULT_FTP_PORT |
21 |
| INTERNET_DEFAULT_GOPHER_PORT |
70 |
| INTERNET_DEFAULT_HTTP_PORT |
80 |
| INTERNET_DEFAULT_HTTPS_PORT |
443 |
| INTERNET_DEFAULT_SOCKS_PORT |
1080 |
| INTERNET_INVALID_PORT_NUMBER |
使用由dwService指定的服务的默认端口值
|
---- lpszUsername指向包含用户用于登录的名字的字符串。其默认值详见表2;
---- lpszPassword指向包含用户登录密码的字符串,其默认值详见表2;
---- 表2:lpszUsername和lpszPassword的默认值
| lpszUsername的值 |
lpszPassword的值 |
lpszUsername的默认值 |
lpszPassword的默认值 |
| NULL |
NULL |
"anonymous" |
用户的电子邮件名称 |
| NULL |
非空字符串 |
错误 |
错误 |
| 非空字符串 |
NULL |
lpszUsername的值 |
"" |
| 非空字符串 |
非空字符串 |
lpszUsername的值 |
lpszPassword的值 |
---- l dwService是要访问的服务类型,其值详见表3;
---- 表3:Internet服务的预定义值
| 预定义名称 |
意义 |
| INTERNET_SERVICE_FTP |
FTP服务 |
| INTERNET_SERVICE_GOPHER |
Gopher服务 |
| INTERNET_SERVICE_HTTP |
HTTP服务 |
----
dwFlags为可选标记,此处设置为INTERNET_FLAG_SECURE,表示使用SSL/PCT协议完成事务;
---- dwContext为应用程序定义的值,用来为返回的句柄标识应用程序设备场境。
---- 2. 对于HTTP,需要调用HttpOpenRequest函数。
----
HttpOpenRequest函数用于打开HTTP申请,如果成功则返回该申请的句柄,否则返回NULL。该函数原型为: HINTERNET HttpOpenRequest( IN HINTERNET hHttpSession, IN LPCSTR lpszVerb,
IN LPCSTR lpszObjectName, IN LPCSTR lpszVersion, IN LPCSTR lpszReferer,
IN LPCSTR FAR * lpszAcceptTypes, IN DWORD dwFlags, IN DWORD dwContext
); ---- 该函数有8个参数需要设置,其中:
- hHttpSession是由InternetConnect返回的HTTP会话句柄;
- lpszVerb指向在申请中使用的"动词"的字符串,如果设置为NULL,则使用"GET";
- lpszObjectName指向包含动词的目标对象名称的字符串,通常是文件名称、可执行模块或搜索说明符;
- lpszVersion指向包含HTTP版本的字符串,如果为NULL,则默认为"HTTP/1.0";
- lpszReferer指向包含文档地址(URL)的字符串,申请的URL必须是从该文档获取的;
- lpszAcceptTypes指向客户接收的内容的类型;
- dwFlags、dwContext与InternetConnect函数中的同名参数意义相同,
---- 3. 按通常使用WinINET的方法完成对HTTP的访问。
三、使用Winsock访问加密协议
---- 3-1 证书验证
----
验证(Authentication)是确定远程主机是否可信的过程。远程主机只有从认证中心(Certificate
Authority,以下简称CA)获得了基于公钥加密的鉴定证书,才能够被看作可信的。认证中心可以从级别更高的认证中心获得证书,依此类推。这样就形成了一个认证链。要验证一个证书的真伪,应用程序必须确定基层CA的一致性。Windows
CE支持X.509型证书。
---- Windows
CE维护了一个可以信赖的CA的数据库。当应用程序试图启动加密连结时,Windows
CE从认证链的底层提取CA并检查它是否在自己的CA数据库中。应用程序最终承担判断证书值否可以接受的责任。它们可以自由的决定接受或拒绝证书,这取决于它们判断的标准和要求保密性的高低。如果证书被拒绝了,那么连结将不能完成。至少,证书应当满足下列需求:(1)他们应当是当前的;(2)证书的基层CA应当在Windows
CE的CA数据库中。
----
证书的确认回叫函数必须被所有使用加密套接字的客户应用所实现。他们的返回值决定了连结是否能够通过Winsock完成,语法如下: int SslValidate ( DWORD dwType, LPVOID pvArg, DWORD dwChainLen, LPBLOB
pCertChain, DWORD dwFlags, ); ---- 返回值详见表4:
---- 表4:SslValidate函数的返回值
| 返回值 |
意义 |
| SSL_ERR_BAD_DATA |
证书格式不正确 |
| SSL_ERR_BAD_SIG |
签名检验失败 |
| SSL_ERR_CERT_EXPIRED |
证书到期 |
| SSL_ERR_CERT_REVOKED |
证书被自己的发行商撤销 |
| SSL_ERR_CERT_UNKNOWN |
发行尚未知,或者一些未知问题出现在验证过程中
|
---- SslValidate的5个参数意义如下:
- dwType制定了被pCertChain指定的数据类型,它必须为SSL_CERT_X.509,表示pCertChain是一个指向X.509型证书的指针;
- pvArg是应用程序定义的设备场境,被SSLVALIDATECERTHOOK结构传递;
- dwChainLen参数是pCertChain指向的证书数量。它必须为1;
- pCertChain是一个指向底层证书的指针;
- 证书发行商没有在CA数据库中找到,dwFlags应当包含SSL_CERT_FLAG_ISSUER_UNKNOWN。应用程序可以使者验证发行商自己,或返回SSL_ERR_CERT_UNKNOWN。
---- 3-2 实现加密套接字
---- 下面介绍如何建立加密套接字连结。
---- 实现加密套接字的步骤
---- 1. 使用socket函数建立一个套接字。
---- socket函数用于建立绑定到指定服务提供商的套接字。其函数原型如下:
---- SOCKET socket (int af, int type, int
protocol);
---- 其中:
- af是地址规范,Windows CE支持PF_INET和AF_IRDA APAR Internet地址格式;
---- type是新套接字的类型规范,其值见表5:
---- 表5:套接字类型
| 类型 |
说明 |
| SOCK_STREAM |
使用带外数据传输机制提供连续的、可信的、双向的、基于连结的字节流。
|
| SOCK_DGRAM |
支持非连结的、限定最大长度的不可靠缓冲的数据报。
|
---- l protocol是在socket中使用的协议,以指定地址家族。
---- 2. 使用setsockopt函数将套接字设置为加密模式。该函数原型如下:
---- int setsockopt (SOCKET s, int level,
int optname, const char FAR * optval, int optlen);
---- 其中:
- s是一个套接字的描述符;
- level是选项被定义的级别,其值可以是SOL_SOCKET或IPPROTO_TCP。这里设置为SOL_SOCKET,此时,将有如下选项;
- optname是将要设置的套接字选项名称,这里设置为SO_SECURE;
- optval指向存储被申请套接字选项的值的缓冲区,这里设置为指向DWORD的值为SO_SEC_SSL的指针;
- optlen是optival缓冲区的大小;
---- 3.
通过调用WSAIoctl指定认证验证回叫函数,函数原型如下: int
WSAIoctl ( SOCKET s, DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
LPVOID lpvOUTBuffer, DWORD cbOUTBuffer, LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED
lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE );
---- 其中:
- s是一个套接字的描述符;
- dwIoControlCode是待执行操作的控制代码,这里为SO_SSL_SET_VALIDATE_CERT_HOOK,表示将指针设置为证书验证指令;
- lpvInBuffer是一个指向输入缓冲区的指针;
- cbInBuffer是输入缓冲区大小;
- lpvOutBuffer是指向输出缓冲区的指针;
- cbOutBuffer是输出缓冲区大小;
- lpcbBytesReturned是指向真实的输出字节的数值;
- lpOverlapped和lpCompletionROUTINE这里必须为NULL。
---- 4.
要指定特定的安全协议,调用WSAIoctl,并将dwIoControlCode设置为SO_SSL_GETPROTOCOLS来决定默认协议。然后调用WSAIoctl,将dwIoControlCode设置为SO_SSL_SET_PROTOCOLS来选择将被使用的协议。
---- 5. 使用connect建立连结。
---- connect函数用于建立一个到指定套接字的连接。其函数原型为:
---- int connect (SOCKET s, const struct
sockaddr FAR* name, int namelen);
---- 其中:
- s为一个套接字的描述符;
- name时要连结到的套接字名称;
- namelen是name参数的长度。
---- 6.
正常传输和接受信息。使用send和recv函数自动加密和解密数据。
---- recv用来从连结的套接字中接受数据。
---- int recv (SOCKET s, char FAR* buf, int
len, int flags);
---- 其中:
- s为一个套接字的描述符;
- buf是输入数据的缓冲;
- len是buf的长度;
- flags指定访问建立的方式。
---- 7.
完成后,使用closesocket函数关闭套接字。closesocket的函数原型为:
---- int closesocket (SOCKET s); ---- l s是将被关闭的套接字的描述符。
---- 3-3 使用延时握手
----
延时握手允许应用程序建立一个不加密连结,以后将其转换为加密连结。使用延时握手实现加密套接字
- 同"实现加密套接字"步骤的1~3步。
- Set the socket in deferred handshake mode with WSAIoctl. The control
code should be set to SO_SSL_SET_FLAGS and the flag set to
SSL_FLAG_DEFER_HANDSHAKE.
使用WSAIoctl将套接字设置为握手模式。dwIoControlCode为SO_SSL_SET_FLAGS并将标记设置为SSL_FLAG_DEFER_HANDSHAKE。
- 使用connect函数建立非加密到远程客户的连结。
- 正常传输和解收费加密数据。
- 要切换到加密模式,调用WSAIoctl函数,将dwIoControlCode设置为SO_SSL_PERFORM_HANDSHAKE。证书回叫函数将被自动调用。
- 正常传输数据。使用send和recv函数自动加密和解密数据。
- 使用closesocket关闭套接字。
四、小结
- Windows CE是一个兼容性强、结构紧凑的操作系统,又由于它通常被安装在掌上电脑中,有着便于携带的优势,因此Windows
CE客户机(瘦客户机)在网络中的地位以及Windows CE应用程序都将成为一个很有潜力的发展领域。
- Windows CE资源有限,因此使用编码效率高、速度快的Visual C++编写应用程序当属首选。编写Windows
CE应用程序应当安装Windows CE Toolkit。编写程序时应尤其注意代码的效率。
- Windows CE应用程序一般不接在掌上电脑上调试,Windows CE Toolkit for Visual
C++提供了一套虚拟工具,让你在PC机上模拟运行Windows CE应用程序并监测其运行效果。
- 使用WinINET和Winsock编写加密传输程序各有其优势,应当根据应用程序的其它部分使用什么协议来具体确定所选方案,最大化提高效率。
|