年前写了一些关于windows 下c++通过openssl访问https站点的东西,有兴趣的可以看看http://blog.youkuaiyun.com/shangwei97/archive/2011/01/30/6170258.aspx。
其实我的目的最终是在windows mobile 上实现访问https的功能。
通过openssl可以访问https的站点后,其实移植到wm上是很简单的事,知道重新编译openssl在evc下生成可以在wm下使用的dll就行。我没有编译而是从网上找来一个可以使用的dll,其实为了更好的控制程序,dll最好还是把源码把握在自己手里,这样方便查明问题的所在。
废话不多说了,把程序代码贴出来,和相关的下载地址也贴出来。
下面是wm下可以使用的openssl的程序http://u.115.com/file/f3396b0792#Openssl0.98g_lib_ARMV4_dll.zip
在程序正常调试还需要一个include文件包,其中包含了openssl要用到的头文件
下载地址http://u.115.com/file/f3996c187a#include.rar
wm下的代码基本上和windows下没有区别只是个别的头文件名称不一致下面是程序的源码,是在mfc程序下的,这里只列出头文件和具体的访问事件里的内容。
/**************************************************************/
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <Winbase.h>
//#include <sys/types.h>
#include <winsock.h>
#include <winsock2.h>
#include "openssl/rsa.h"
#include "openssl/crypto.h"
#include "openssl/x509.h"
#include "openssl/pem.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rand.h"
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")
#pragma comment(lib, "ws2.lib")
//#pragma comment(lib, "ws2_32.lib")
//ws2_32.lib libeay32.lib ssleay32.lib
/*所有需要的参数信息都在此处以#define的形式提供*/
#define PORT 5555 /*服务端的端口*/
#define SERVER_ADDR "172.16.140.216" /*服务段的IP地址*/
#define CHK_NULL(x) if ((x)==NULL) exit (-1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(-2); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(-3); }
using namespace std;
//具体的事件,GetByte是为了发送多数据而设计的这里没有用到
long GetByte(byte* byData)
{
HANDLE hfile = INVALID_HANDLE_VALUE;
//BYTE pByte[4096] = {0};
unsigned long bytesRead = 0;
char pByte[4096];
LPCWSTR szFileName = L"//Program Files//HttpsTest//test.txt";
DWORD lowerFileSize = 0;
hfile = CreateFile(szFileName, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (INVALID_HANDLE_VALUE == hfile)
return 0;
lowerFileSize = GetFileSize (hfile, NULL);
ReadFile(hfile , (LPVOID)pByte, lowerFileSize+1, &bytesRead ,NULL );
memcpy(byData,pByte,lowerFileSize);
byData[lowerFileSize] = 0;
return lowerFileSize;
}
void CHttpsTestDlg::OnBnClickedBtGo()
{
int err;
int sd;
struct sockaddr_in sa;
SSL_CTX* ctx;
SSL* ssl;
X509* server_cert;
char* str;
char buf [4096];
SSL_METHOD *meth;
int seed_int[100]; /*存放随机序列*/
byte byData[4096];
memset(byData,0,4096);
int iLen = GetByte(byData);
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
{
printf("WSAStartup()fail:%d/n",GetLastError());
return ;
}
OpenSSL_add_ssl_algorithms(); /*初始化*/
SSL_load_error_strings(); /*为打印调试信息作准备*/
meth = TLSv1_client_method(); /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/
ctx = SSL_CTX_new (meth);
CHK_NULL(ctx);
/*构建随机数生成机制,WIN32平台必需*/
//srand( (unsigned)time( NULL ) );
for( int i = 0; i < 100;i++ )
seed_int[i] = rand();
RAND_seed(seed_int, sizeof(seed_int));
/*以下是正常的TCP socket建立过程 .............................. */
printf("Begin tcp socket.../n");
sd = socket (AF_INET, SOCK_STREAM, 0);
//CHK_ERR(sd, "socket");
memset (&sa, '/0', sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr (SERVER_ADDR); /* Server IP */
sa.sin_port = htons (PORT); /* Server Port number */
err = connect(sd, (struct sockaddr*) &sa,sizeof(sa));
//CHK_ERR(err, "connect");
/* TCP 链接已建立.开始 SSL 握手过程.......................... */
printf("Begin SSL negotiation /n");
//system("pasue");
ssl = SSL_new (ctx);
CHK_NULL(ssl);
SSL_set_fd (ssl, sd);
err = SSL_connect (ssl);
CHK_SSL(err);
/*打印所有加密算法的信息(可选)*/
printf ("SSL connection using %s/n", SSL_get_cipher (ssl));
/*得到服务端的证书并打印些信息(可选) */
server_cert = SSL_get_peer_certificate (ssl);
CHK_NULL(server_cert);
printf ("Server certificate:/n");
str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
CHK_NULL(str);
printf ("/t subject: %s/n", str);
//free (str);
str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0);
CHK_NULL(str);
printf ("/t issuer: %s/n", str);
//free (str);
X509_free (server_cert); /*如不再需要,需将证书释放 */
/* 数据交换开始,用SSL_write,SSL_read代替write,read */
printf("Begin SSL data exchange/n");
err = SSL_write (ssl, "Knock/r/n", strlen("Knock/r/n"));
//err = SSL_write (ssl, (LPVOID)byData,iLen);
CHK_SSL(err);
err = SSL_read (ssl, buf, sizeof(buf) - 1);
CHK_SSL(err);
buf[err] = '/0';
printf ("Got %d chars:'%s'/n", err, buf);
SSL_shutdown (ssl); /* send SSL/TLS close_notify */
/* 收尾工作 */
shutdown (sd,2);
SSL_free (ssl);
SSL_CTX_free (ctx);
}
/**********************************************************/
// 下面是server端的程序,是用java写的证书的生成过程,可以参考以前我先前写的那个贴子。是结合keytool和openssl来生成的
//java服务 代码
import java.io. * ;
import java.net. * ;
import com.sun.net.ssl.KeyManagerFactory;
import com.sun.net.ssl.KeyManager;
import com.sun.net.ssl.TrustManagerFactory;
import com.sun.net.ssl.TrustManager;
import com.sun.net.ssl.SSLContext;
import javax.net.ServerSocketFactory;
import java.security.KeyStore;
public class svr implements Runnable {
public static final int PORT = 5555 ;
public static final String HOST = "localhost";
public static final String QUESTION ="Knock";
public static final String ANSWER = "I am 140.129,Who's there?";
// The new constants that are used during setup.
public static final String KEYSTORE_FILE = "mycerts"; //"server_keystore";
public static final String ALGORITHM = "sunx509";
public static final String PASSWORD = "111111";
public static void main(String[] args) {
new Thread( new svr()).start();
}
public void run() {
ServerSocket ss = null ;
try {
// Local references used for clarity. Their presence
// here is part of the reason we need to import
// so many classes.
KeyManagerFactory kmf;
KeyManager[] km;
KeyStore ks;
TrustManagerFactory tmf;
TrustManager[] tm;
SSLContext sslc;
// Create a keystore that will read the JKS (Java KeyStore)
// file format which was created by the keytool utility.
ks = KeyStore.getInstance("JKS");
// Load the keystore object with the binary keystore file and
// a byte array representing its password.
ks.load( new FileInputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
// Gives us a factory for key managers that will let
// us handle the asymetric keys we created earlier.
kmf = KeyManagerFactory.getInstance(ALGORITHM);
// Initialize the key manager factory with the keystore object,
// again using the same password for security since it is going to
// access the private key.
kmf.init(ks, PASSWORD.toCharArray());
// Now we can get the key managers from the factory, since it knows
// what type we are using now.
km = kmf.getKeyManagers();
// Next, create a trust manager factory using the same algorithm.
// This is to avoid using the certificates in cacerts that
// represent an authentication security risk.
tmf = TrustManagerFactory.getInstance(ALGORITHM);
// then initialize it with the keystore object. This time we don't
// need the keystore password. This is because trusted certificates
// are not a sensitive element in the keystore, unlike the
// private keys.
tmf.init(ks);
// Once that's initialized, get the trust managers from the factory.
tm = tmf.getTrustManagers();
// Almost done, we need a context object that will get our
// server socket factory. We specify TLS to indicate that we will
// need a server socket factory that supports SSL.
sslc = SSLContext.getInstance("TLS");
// Initialize the context object with the key managers and trust
// managers we got earlier. The third parameter is an optional
// SecureRandom object. By passing in null, we are letting the
// context object create its own.
sslc.init(km, tm, null );
// Finally, we get the ordinary-looking server socket factory
// from the context object.
ServerSocketFactory ssf = sslc.getServerSocketFactory();
// From the factory, we simply ask for an ordinary-looking
// server socket on the port we wish.
ss = ssf.createServerSocket(PORT);
listen(ss);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (ss != null ) {
try {
ss.close();
}
catch (IOException e) {
// oh, well
}
}
System.exit( 0 );
}
}
static void listen(ServerSocket ss) throws Exception {
System.out.println("Ready for connections.");
while ( true ) {
Socket s = ss.accept();
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
BufferedReader br = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String q = br.readLine();
while ( ! QUESTION.equals(q)) {
//throw new RuntimeException("Wrong question: /"" + q + "/"");
System.out.println("Wrong question: /"" + q + "/"");
}
System.out.println("Question: /"" + q + "/"");
bw.write(ANSWER +"/n");
bw.flush();
s.close();
}
}
}
/*******************************************************************/
希望能给正在做https或者正在用openssl的朋友一点帮助
如果下载过期了,可以发邮件到shangwei97@163.com