【上一篇:openssl 自签名证书 - 制作证书(二)】
用xcode创建应用工程
1. 确认头文件搜索目录
1.根据openssl编译设置目录,比如说/usr/local/openssl/include
2.我使用homebrew安装的openssl,目录一般为/usr/local/opt/openssl/include
2.工程设置头文件搜索
左边点击project -> 中间target -> 右边Build Settings选项卡 -> Header Search Paths,双击添加路径
3. 静态库设置
- 将编译出来的【libcrypto.a】【libssl.a】复制工程目录然后添加进来
- 我是homebrew安装的,复制【libcrypto.a】【libssl.a】到工程目录然后添加进来,“什么?我去哪里找?!”,一般是在/usr/local/opt/openssl/lib/目录下
4. 上代码
#include
#include
#include
#include
#include
#include
#include
#include
#define SSL_ROOT_DIR "your path here..."
#define SSL_CA_PATH SSL_ROOT_DIR "ca.crt"
#define SSL_SERVER_CER_PATH SSL_ROOT_DIR "server.crt"
#define SSL_SERVER_KEY_PATH SSL_ROOT_DIR "server.key"
#define SSL_CLIENT_CER_PATH SSL_ROOT_DIR "client.crt"
#define SSL_CLIENT_KEY_PATH SSL_ROOT_DIR "client.key"
#ifndef SSL_VERIFY
#define SSL_VERIFY 1
#endif
#if SSL_VERIFY
#define SSL_VERIFY_MODE SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
#else
#define SSL_VERIFY_MODE SSL_VERIFY_NONE
#endif
int g_ssl_connect_flag = 0;
int g_ssl_server_close = 0;
int g_ssl_client_close = 0;
void ssl_show_certs(SSL * ssl, const char *label)
{
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl);
// SSL_get_verify_result(), really verify
printf(">>> %s\n", label);
if(SSL_get_verify_result(ssl) == X509_V_OK){
printf("ssl verify ok.\n");
}
if(NULL != cert) {
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("certificate: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("ca: %s\n", line);
free(line);
X509_free(cert);
} else{
printf("no certificate info.\n");
}
}
void ssl_socket_server(void){
SSL_CTX *ctx = NULL;
int sock = 0;
ctx = SSL_CTX_new(SSLv23_server_method());
if(NULL == ctx){
fprintf(stderr, "server create ssl context fail.\n");
ERR_print_errors_fp(stderr);
return;
}
do{
SSL_CTX_set_verify(ctx, SSL_VERIFY_MODE, NULL);
if(0 >= SSL_CTX_load_verify_locations(ctx, SSL_CA_PATH, NULL)){
ERR_print_errors_fp(stderr);
fprintf(stderr, "server load ca file fail.\n");
ERR_print_errors_fp(stderr);
break;
}
if(0 >= SSL_CTX_use_certificate_chain_file(ctx, SSL_SERVER_CER_PATH)){
fprintf(stderr, "server load cer file fail.\n");
ERR_print_errors_fp(stderr);
break;
}
/// set private key password if needed
SSL_CTX_set_default_passwd_cb_userdata(ctx, "123456");
if(0 >= SSL_CTX_use_PrivateKey_file(ctx, SSL_SERVER_KEY_PATH, SSL_FILETYPE_PEM)){
fprintf(stderr, "server load private key file fail.\n");
ERR_print_errors_fp(stderr);
break;
}
if(0 >= SSL_CTX_check_private_key(ctx)){
fprintf(stderr, "check server private key fail.\n");
ERR_print_errors_fp(stderr);
break;
}
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in s_addr;
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(10086);
s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(0 != bind(sock, (const struct sockaddr*)&s_addr, sizeof(s_addr))){
fprintf(stderr, "server bind fail.\n");
break;
}
if(0 != listen(sock, 1)){
fprintf(stderr, "server lisent fail.\n");
break;
}
struct sockaddr_in s_addr_out;
int s_add_len = 0;
int new_sock = 0;
memset(&s_addr_out, 0x00, sizeof(s_addr_out));
g_ssl_connect_flag = 1;
SSL *ssl = NULL;
printf("server waiting...\n");
char msg[256] = {0};
while(1){
s_add_len = sizeof(s_addr_out);
new_sock = accept(sock, (struct sockaddr*)&s_addr_out, (socklen_t*)&s_add_len);
if(0 >= new_sock){
continue;
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl, new_sock);
if(1 != SSL_accept(ssl)){
fprintf(stderr, "server accept ssl socket fail.\n");
ERR_print_errors_fp(stderr);
SSL_free(ssl);
close(new_sock);
continue;
}
#if SSL_VERIFY
ssl_show_certs(ssl, "serever side:");
#endif
memset(msg, 0x00, 256);
int sl = sprintf(msg, "hello client<%d> from <%s:%d>\n", new_sock, inet_ntoa(s_addr_out.sin_addr), ntohs(s_addr_out.sin_port));
int wl = SSL_write(ssl, msg, sl);
printf("server send %d bytes data.\n", wl);
memset(msg, 0x00, 256);
int rl = SSL_read(ssl, msg, 256);
printf("server recv %d bytes data:\ncontent: %s\n", rl, msg);
g_ssl_client_close = 1;
while(1 != g_ssl_server_close){
usleep(200000);
}
SSL_shutdown(ssl);
SSL_free(ssl);
close(new_sock);
printf("server close...\n");
break;
}
}while(0);
shutdown(sock, 2);
close(sock);
SSL_CTX_free(ctx);
}
void* ssl_client_thread_(void *param){
int sock = 0;
SSL *ssl = NULL;
SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
if(NULL == ctx){
fprintf(stderr, "client create ssl context fail.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
do{
do{
usleep(200000);
}while(1 != g_ssl_connect_flag);
usleep(1000000);
SSL_CTX_set_verify(ctx, SSL_VERIFY_MODE, NULL);
if(0 >= SSL_CTX_load_verify_locations(ctx, SSL_CA_PATH, NULL)){
fprintf(stderr, "client load ca file fail.\n");
ERR_print_errors_fp(stderr);
break;
}
if(0 >= SSL_CTX_use_certificate_chain_file(ctx, SSL_CLIENT_CER_PATH)){
fprintf(stderr, "client load cer file fail.\n");
ERR_print_errors_fp(stderr);
break;
}
/// set private key password if needed
SSL_CTX_set_default_passwd_cb_userdata(ctx, "123456");
if(0 >= SSL_CTX_use_PrivateKey_file(ctx, SSL_CLIENT_KEY_PATH, SSL_FILETYPE_PEM)){
fprintf(stderr, "client load private key file fail.\n");
ERR_print_errors_fp(stderr);
break;
}
if(0 >= SSL_CTX_check_private_key(ctx)){
fprintf(stderr, "check client private key fail.\n");
ERR_print_errors_fp(stderr);
break;
}
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in s_addr;
memset(&s_addr, 0x00, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(10086);
s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(0 != connect(sock, (const struct sockaddr *)&s_addr, sizeof(s_addr))){
printf("client connect server fail.\n");
break;
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
if(1 != SSL_connect(ssl)){
fprintf(stderr, "client ssl connect fail.\n");
ERR_print_errors_fp(stderr);
break;
}
#if SSL_VERIFY
ssl_show_certs(ssl, "client side:");
#endif
char msg[256] = {0};
int rl = SSL_read(ssl, msg, 256);
printf("client recv %d bytes data:\ncontent: %s\n", rl, msg);
memset(msg, 0x00, 256);
const char *m = "hello ssl server!!";
int sl = (int)strlen(m);
int wl = SSL_write(ssl, m, sl);
printf("client send %d bytes data.\n", wl);
while(1 != g_ssl_client_close){
usleep(200000);
}
}while(0);
if(NULL != ssl){
SSL_shutdown(ssl);
SSL_free(ssl);
}
close(sock);
SSL_CTX_free(ctx);
g_ssl_server_close = 1;
printf("client close...\n");
return NULL;
}
void ssl_socket_client(void){
pthread_t pt;
if(0 > pthread_create(&pt, NULL, ssl_client_thread_, NULL)){
printf("client create socket thread fail.\n");
return;
}
}
void ssl_socket_test(void){
printf("ca path: %s\nser-req: %s\nser-key: %s\nclt-req: %s\nclt-key: %s\n", SSL_CA_PATH, SSL_SERVER_CER_PATH, SSL_SERVER_KEY_PATH, SSL_CLIENT_CER_PATH, SSL_CLIENT_KEY_PATH );
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ssl_socket_client();
ssl_socket_server();
}
int main(int argc, const char * argv[]) {
// insert code here...
printf("Hello, World!\n");
ssl_socket_test();
printf("press any key to exit...\n");
getchar();
return 0;
}
控制台主要信息输出,如下:
Hello, World!
...
server waiting...
...
server send 39 bytes data.
...
client recv 39 bytes data:
content: hello client<5> from <127.0.0.1:53269>client send 18 bytes data.
server recv 18 bytes data:
content: hello ssl server!!
client close...
server close...
press any key to exit...