终端采用WINCE5.0作为开发平台,服务器端采用LINUX,由于需要做到安全连接,用普通的SOCKET进行TCP无法达到安全级别,于是使用SSL进行连接通讯,经过测试,在WINCE端采用WININET库的函数,LINUX端采用OPENSSL。
在WINCE端主动发起连接,其流程是:
1. 用InternetOpen函数打开一个连接hOpen。
HINTERNET
hOpen = NULL;
hOpen = InternetOpen(L
"MY SSL",
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
0,
0);
2. 用InternetConnect,对打开的连接hOpen进行参数配置,设置IP,端口,连接方式,得到hConnect。
HINTERNET
hConnect = NULL;
hConnect = InternetConnect(hOpen,
L”192.168.0.1”,
//服务器
IP地址
L”5396”,
//服务器端口
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
0);
3. 用HttpOpenRequest开辟一个REQUEST内容句柄hReq,将需要传递的信息放 入该句柄内容。其中向服务器发送helloworld的消息。
HINTERNET
hReq = NULL;
hReq = HttpOpenRequest(hConnect,
L"GET",
L”helloworld”,
L"HTTP/1.0",
NULL,
(LPCTSTR*)AcceptTypes,
INTERNET_FLAG_SECURE|
INTERNET_FLAG_IGNORE_CERT_CN_INVALID|
INTERNET_FLAG_IGNORE_CERT_DATE_INVALID,
0);
4. 用HttpSendRequest,向服务器发送REQUEST,并通过返回值,判断证书,最后连接上服务器,如果失败,可继续发送,如果超过3次,直接返回失败。
while(!HttpSendRequest(hReq, NULL, 0, 0, 0))
{
printf("sendrequest error/n");
dwError = GetLastError();
if ( dwError == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED)
{
printf("error_internet_client_auth_cert_needed/n");
LPVOID dwCert = NULL;
InternetErrorDlg( (HWND)GetDesktopWindow(),
hReq,
ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA |
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,
&dwCert);
InternetSetOption(hReq, INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT,
dwCert, sizeof(dwCert));
HttpSendRequest(hReq, NULL, 0, 0, 0);
break;
}else if(dwError == ERROR_INTERNET_INVALID_CA)
{
DWORD dwFlags;
DWORD dwBuffLen = sizeof(dwFlags);
InternetQueryOption (hReq, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID
| SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS,
&dwFlags, sizeof (dwFlags) );
if(HttpSendRequest(hReq,NULL,0, 0, 0))
{
printf("sendrequest success/n");
}else
{
printf("sendrequest error/n");
}
break;
}
n++;
if(n == 3)
{
SSLerr = 1;
//KillTimer(NULL,checktime);
return 0;
}
}
5. 然后用阻塞方式等待服务器返回的数据,用InternetReadFile接受数据。
if(InternetReadFile(hReq,buf,100,&dwSize))
{
buf[dwSize] = '/0';
printf("read success %s/n",buf);
}else
{
printf("read error/n");
}
这时
buf收到的服务器发回的dwsize个字节的消息。
LINUX端的过程就是使用OPENSSL创建一个SSL服务器的过程,首先要在linux上安装好OPENSSL组件,否则无法调用SSL,然后要创建证书,当客户端发起连接时,发送给客户端提供身份认证,这些在这里都不详细叙述,都有详细的制作方法,创建服务器的过程也就是打开一个TCP连接,然后监听客户端发起的连接,并响应连接,由于为了说明SSL原理,对服务器程序并不重点介绍,这里使用开辟线程去处理连接,并在线程中进行SSL通讯。
1. 首先是前期的准备工作,
#define CERTF
"/opt/Mac/server.crt"
#define KEYF
"/opt/Mac/server.key"
SSL_METHOD *meth;
X509
*client_cert;
OpenSSL_add_ssl_algorithms();
meth = SSLv23_server_method();
ctx = SSL_CTX_new(meth);
然后加载证书
if(SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) == -1)
{
printf("load the card error/n");
exit(1);
}else
{
printf("load the card success/n");
}
if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) == -1)
{
printf("load the privatekey error/n");
exit(1);
}else
{
printf("load the privatekey success/n");
}
if (!SSL_CTX_check_private_key(ctx))
{
printf("Private key does not match the certificate public key/n");
exit(1);
}else
{
printf("Private key match the certificate public key success/n");
}
2. 用TCP连接方式建立一个服务器程序然后建立循环等待连接,这里核心代码是
while(1)
{
temp_sock_descriptor = accept(Sock_Descriptor,(struct sockaddr*)&sin,&len);
pthread_create(&id,NULL,(void*)thread,&temp_sock_descriptor);
}
这里当连接到来时,立刻开辟一个线程thread去处理,然后进入线程。
进行SSL处理:
SSL
*ssl = SSL_new(ctx); SSL_set_fd(ssl,temp_sock_descriptor);
SSL_set_accept_state(ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
SSL_accept(ssl); 相当于接受客户端的
SSL连接
Num = sizeof(buf);
SSL_read(ssl, buf, num); 读取客户端发送的信息到
buf
Printf(“%s”,buf);查看收到的信息,其中包括客户端的所有信息。
Memset(buf,’/0’,num);
Strcpy(buf,”hello”);
Num = strlen(buf);
SSL_write(ssl,buf,num); 向客户端发送消息
SSL_free(ssl);
close(temp_sock_descriptor);
这样整个
SSL通讯的基本过程就是这样,可以在这个基础上使用SSL发送需要保密的信息。
可以使用普通的浏览器访问刚刚建立的
SSL服务器,如果服务器IP是
192.168.0.1,绑定的端口是
5396;
那么,在浏览器地址输入栏输入
按确定后,会弹出警告框,因为证书不是浏览器默认的安全证书,这时继续操作,
就会看到窗口显示hello。
如果用
wince访问服务器,打印收到的字符串,显示也是hello,这样SSL通讯基本实现。