使用c语言实现在linux下的openssl客户端和服务器端编程
使用c语言实现在linux下的openssl客户端和服务器端编程
摘自:https://www.cnblogs.com/etangyushan/p/3679457.html
前几天组长让我实现一个使用openssl的c语言编写的客户端和java编写的服务器实现字符流的通信,给了段代码。在自己的ubuntu上跑服务器和客户端收发信息都没有问题,但是就是和java的通信不了。后来发现组长给的客户端代码有问题,于是网上找到了比较正确的客户端和服务器代码,自己做了稍微的改动。有一点要说一下,我的c客户端使用的证书格式是.pem的,而java那边使用kittool生成的证书格式是.cer的所以需要进行cer到pem格式的转换才可以使用。
我使用的是这个网址下进行证书格式转换:https://www.sslshopper.com/ssl-converter.html
操作是:
1.选择要转换的文件。
2.选择文件的格式,里面没有cer格式选项,可以使用der就可以。
3.选择要转换成为什么格式我是选择standard pem。生成的是。crt文件,这个在ubuntu下面导入到我的客户端中即可。
以下是我编程的具体的操作步骤,大部分是从网上整理的,小部分的做了改动,加了注释。
安装openssl安装包
在以下网站下载openssl:
http://www.openssl.org/source/openssl-1.0.0a.tar.gz
tar -zxvf openssl-1.0.0a.tar.gz
mv openssl-1.0.1a openssl
cd openssl
如果需要zlib压缩模块的话,还需要先安装zlib
./config --prefix=/usr/local/ssl shared zlib-dynamic enable-camellia
不需要就直接用:
./config --prefix=/usr/local/ssl shared no-zlib
更多详细帮助请运行
./config –help
./config –t
make depend
make
make test
sudo make install
设置环境变量:在/etc/profile的PATH中增加如下内容
PATH=/usr/local/ssl/bin:/sbin/:$PATH:/usr/sbin
export PATH
cat /etc/ssl/openssl.cnf
//查看路径
which openssl
//查看版本
openssl version
openssl安装完毕
如果计算机联网的话可以使用如下命令安装比较简便
Ubuntu系统下安装openssl
sudo apt-get install openssl
//安装openssl-devel
//由于ubuntu下无法安装openssl-devel 所以使用libssl-dev代替openssl-devel
sudo apt-get install libssl-dev
CentOS系统下安装openssl
//解压openssl安装包
[root@localhost opt]# tar xvzf openssl-1.0.0d.tar.gz
//进入解压后的目录
[root@localhost opt]# cd openssl-1.0.0d
//修改openssl配置文件
[root@localhost openssl-1.0.0d]# ./configure --prefix=/usr/local/openssl
//编译代码
[root@localhost openssl-1.0.0d]# make
//安装
[root@localhost openssl-1.0.0d]# make install
//安装curses.h头文件的库
sudo apt-get install libncurses5-dev
//所需软件安装完毕:openssl、openssl-devel、libncurses5-dev 三个软件
生成工作目录产生CA凭证
ca.crt 为自签名证书;
server.crt,server.key 为服务器端的证书和私钥文件;
proxy.crt,proxy.key 为代理服务器端的证书和私钥文件;
client.crt,client.key 为客户端的证书和私钥文件。
//把openssl安装目录下的misc拷贝到用户目录下
cd
mkdir sslca
cd sslca
sudo cp /usr/local/ssl/ssl/misc -r ./
sudo cp /usr/local/ssl/ssl/openssl.cnf ./misc
Cd misc
CA.sh –newca
//产生一个demoCA文件夹
cd demoCA
//复制安装目录下面的openssl.cnf文件到demoCA下
sudo cp /usr/local/ssl/ssl/openssl.cnf ./
//产生CA自签名证书
openssl genrsa -out ./private/ca.key -rand ./private/.rnd -des 2048
openssl req -new -x509 -days 3650 -key ./private/ca.key -out ./private/ca.crt -config openssl.cnf
openssl x509 -in ./private/ca.crt -noout -text
//产生server的证书过程
openssl genrsa -out ./private/server.key 1024
openssl req -new -key ./private/server.key -out ./newcerts/server.csr -config openssl.cnf
//这一步如果产生错误,请看后面的解决方法
openssl ca -in ./newcerts/server.csr -cert ./private/ca.crt -keyfile ./private/ca.key -config openssl.cnf -policy policy_anything -out ./certs/server.crt
openssl x509 -in ./certs/server.crt -noout -text
//产生proxy的证书过程
openssl genrsa -out ./private/proxy.key 1024
//这步要是产生错误,请看后面的解决方法
openssl req -new -key ./private/proxy.key -out ./newcerts/proxy.csr -config openssl.cnf
openssl ca -in ./newcerts/proxy.csr -cert ./private/ca.crt -keyfile./private/ca.key -config openssl.cnf -policy policy_anything -out ./certs/proxy.crt
openssl x509 -in ./certs/proxy.crt -noout -text
//产生client的证书过程
openssl genrsa -out ./private/client.key 1024
openssl req -new -key ./private/client.key -out ./newcerts/client.csr -config openssl.cnf
openssl ca -in ./newcerts/client.csr -cert ./private/ca.crt -keyfile ./private/ca.key -config openssl.cnf -policy policy_anything -out ./certs/client.crt
openssl x509 -in ./certs/client.crt -noout -text
产生一般错误的解决方法
//出现:I am unable to access the ./demoCA/newcerts directory
./demoCA/newcerts:Nosuch file or directory
解决:修改openssl.cnf
在42行:dir = ./demoCA修改为 dir = ./
//出现:failed to update database
TXT_DB error number 2
解决:修改index.txt.attr
将unique_subject = yes修改为 unique_subject = no
#客户端的代码
vim client.c
//client
#include <openssl/rand.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <errno.h>
#include <curses.h>
#define PORT 7979
#define SERVER "127.0.0.1"
#define CACERT "./private/ca.crt"
/* 如果需要与不是本机的服务器通信,在这个地方的证书导入对应服务器的证书,我的是和java通信,所以就导入了java端的服务器证书
注意,java端的证书需要进行格式转换,具体操作方法请参见开头的说明。*/
#define MYCERTF "./certs/proxy.crt"
#define MYKEYF "./private/proxy.key"
#define MSGLENGTH 1024
int
main ()
{
struct sockaddr_in sin;
int seed_int[100];
SSL *ssl;
SSL_METHOD *meth;
SSL_CTX *ctx;
int i; /* 初始化OpenSSL */
SSL_library_init();
/*加载算法库 */
OpenSSL_add_ssl_algorithms ();
/*加载错误处理信息 */
SSL_load_error_strings ();
/* 选择会话协议 */
meth = (SSL_METHOD *) TLSv1_client_method ();
/* 创建会话环境 */
ctx = SSL_CTX_new (meth);
if (NULL == ctx)
exit (1);
/* 制定证书验证方式 */
SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, NULL); /* 为SSL会话加载CA证书*/
SSL_CTX_load_verify_locations (ctx, CACERT, NULL); /* 为SSL会话加载用户证书 */
if (0 == SSL_CTX_use_certificate_file (ctx, MYCERTF, SSL_FILETYPE_PEM))
{
ERR_print_errors_fp (stderr);
exit (1);
}
/* 为SSL会话加载用户私钥 */
if (0 == SSL_CTX_use_PrivateKey_file (ctx, MYKEYF, SSL_FILETYPE_PEM))
{
ERR_print_errors_fp (stderr);
exit (1);
}
/* 验证私钥和证书是否相符 */
if (!SSL_CTX_check_private_key (ctx))
{
printf ("Private key does not match the certificate public key\n");
exit (1);
}
/* 设置随机数 */
srand ((unsigned) time (NULL));
for (i = 0; i < 100; i++)
seed_int[i] = rand ();
RAND_seed (seed_int, sizeof (seed_int));
/* 指定加密器类型 */
SSL_CTX_set_cipher_list (ctx, "RC4-MD5");
SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY);
int sock;
printf ("Begin tcp socket...\n");
/* 创建socket描述符 */
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
printf ("SOCKET error. \n");
}
memset (&sin, '\0', sizeof (sin)); /* 准备通信地址和端口号 */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr (SERVER); /* Server IP */
sin.sin_port = htons (PORT); /* Server Port number */
int icnn = connect (sock, (struct sockaddr *) &sin, sizeof (sin));
if (icnn == -1)
{
printf ("can not connect to server,%s\n", strerror (errno));
exit (1);
} /* 创建一个SSL套接字*/
ssl = SSL_new (ctx);
if (NULL == ssl)
exit (1); /* 申请一个ssl套接字 */
if (0 >= SSL_set_fd (ssl, sock))
{
printf ("Attach to Line fail!\n");
exit (1);
}
//建立SSL连接
int k = SSL_connect (ssl);
if (0 == k)
{
printf ("%d\n", k);
printf ("SSL connect fail!\n");
exit (1);
}
printf ("connect to server\n");
char sendmsg[MSGLENGTH] = "\0";
char revmsg[MSGLENGTH] = "\0";
//接收服务器消息
int err = SSL_read (ssl, revmsg, sizeof (revmsg));
revmsg[err] = '\0';
printf ("%s\n", revmsg);
while (1)
{
printf ("please input the data to send:\n");
scanf ("%s", sendmsg);
//向服务器发送消息
SSL_write (ssl, sendmsg, strlen (sendmsg));
printf ("send message ' %s ' success\n", sendmsg);
}
//关闭连接
SSL_shutdown (ssl);
SSL_free (ssl);
SSL_CTX_free (ctx);
close (sock);
getch ();
return 0;
}
#服务端的代码
vim server.c
//server
#include <stdio.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <curses.h>
#define MSGLENGTH 1024
#define PORT 7979
#define CACERT "./private/ca.crt"
#define SVRCERTF "./certs/server.crt"
#define SVRKEYF "./private/server.key"
#define ADDRESS “127.0.0.1”
int main ()
{
int sock;
SSL_METHOD *meth;
SSL_CTX *ctx;
SSL *ssl;
//SSL初库始化
SSL_library_init();
//载入所有SSL算法
OpenSSL_add_ssl_algorithms ();
//载入所有错误信息
SSL_load_error_strings ();
meth = (SSL_METHOD *) TLSv1_server_method ();
ctx = SSL_CTX_new (meth);
if (NULL == ctx)
exit (1);
SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations (ctx, CACERT, NULL);
//加载证书和私钥
if (0 == SSL_CTX_use_certificate_file (ctx, SVRCERTF, SSL_FILETYPE_PEM))
{
ERR_print_errors_fp (stderr);
exit (1);
}
if (0 == SSL_CTX_use_PrivateKey_file (ctx, SVRKEYF, SSL_FILETYPE_PEM))
{
ERR_print_errors_fp (stderr);
exit (1);
}
if (!SSL_CTX_check_private_key (ctx))
{
printf ("Private key does not match the certificate public key\n");
exit (1);
}
SSL_CTX_set_cipher_list (ctx, "RC4-MD5");
SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY);
printf ("Begin tcp socket...\n");
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
printf ("SOCKET error! \n");
return 0;
}
//准备通信地址和端口号
struct sockaddr_in addr;
memset (&addr, '\0', sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons (PORT); /* Server Port number */
//addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_addr.s_addr = inet_addr(ADDRESS);
//绑定地址和端口号
int nResult = bind (sock, (struct sockaddr *) &addr, sizeof (addr));
if (nResult == -1)
{
printf ("bind socket error\n");
return 0;
}
printf ("server start successfully,port:%d\nwaiting for connections\n",
PORT);
struct sockaddr_in sa_cli;
//设置最大连接数
int err = listen (sock, 5);
if (-1 == err)
exit (1);
int client_len = sizeof (sa_cli);
//等待客户端连接
int ss = accept (sock, (struct sockaddr *) &sa_cli, &client_len);
if (ss == -1)
{
exit (1);
}
close (sock);
printf ("Connection from %d, port %d\n", sa_cli.sin_addr.s_addr,
sa_cli.sin_port);
ssl = SSL_new (ctx);
if (NULL == ssl)
exit (1);
if (0 == SSL_set_fd (ssl, ss))
{
printf ("Attach to Line fail!\n");
exit (1);
}
int k = SSL_accept (ssl);
if (0 == k)
{
printf ("%d/n", k);
printf ("SSL connect fail!\n");
exit (1);
}
X509 *client_cert;
client_cert = SSL_get_peer_certificate (ssl);
printf ("find a customer to try to connect\n");
if (client_cert != NULL)
{
printf ("Client certificate:\n");
char *str =
X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
if (NULL == str)
{
printf ("auth error!\n");
exit (1);
}
printf ("subject: %s\n", str);
str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
if (NULL == str)
{
printf ("certificate name is null\n");
exit (1);
}
printf ("issuer: %s\n", str);
printf ("connect successfully\n");
X509_free (client_cert);
OPENSSL_free (str);
}
else
{
printf ("can not find the customer's certificate\n");
exit (1);
}
char buf[MSGLENGTH];
SSL_write (ssl, "Server is connect to you!\n",
strlen ("Server is connect to you!\n"));
printf ("Listen to the client: \n");
while (1)
{
err = SSL_read (ssl, buf, sizeof (buf));
buf[err] = '\0';
printf ("%s\n", buf);
}
SSL_shutdown (ssl);
SSL_free (ssl);
SSL_CTX_free (ctx);
getch ();
return 0;
}
#makefile的代码:
vim makefile
all:client.c server.c
gcc –o clientclient.c –Wall –lssl –ldl -lcurses
gcc –o serverserver.c –Wall –lssl –ldl –lcurses
#如果是自定义安装路径的,可以使用下面的
#gcc -Wall -o clientclient.c -I/usr/openssl-1.0.0c/include/usr/openssl-1.0.0c/libssl.a /usr/openssl-1.0.0c/libcrypto.a –ldl
#gcc -Wall -o serverserver.c -I/usr/openssl-1.0.0c/include/usr/openssl-1.0.0c/libssl.a /usr/openssl-1.0.0c/libcrypto.a -ldl
clean::
rm -f client server
使用c语言实现在linux下的openssl客户端和服务器端编程的更多相关文章
- linux下利用openssl来实现证书的颁发(详细步骤)--转载和修改
原文地址:http://www.cnblogs.com/firtree/p/4028354.html linux下利用openssl来实现证书的颁发(详细步骤) 1.首先需要安装openssl,一个开 ...
- Linux下更改oracle客户端字符集和服务端字符集
from:http://blog.csdn.net/chid/article/details/6166506 Linux 下更改 oracle 客户端字符集和服务端字符集 1.Linux 下更改 or ...
- linux下Tomcat+OpenSSL配置单向&双向认证(自制证书)
背景 由于ios将在2017年1月1日起强制实施ATS安全策略,所有通讯必须使用https传输,本文只针对自制证书,但目前尚不确定自制证书是否能通过appstore审核. 1.必须支持传输层安全(TL ...
- 为什么360、百度、腾讯出的Mac端云盘客户端都只有同步盘?(用户量小,同步盘开发成本低,Linux下都没有客户端)
如题,顾名思义,同步盘是用来同步的,不具备增量的功能,像这三家在Windows端出的客户端都是即有同步也有增量的. 陆续出来的,可能大家更多的是跟随策略,不得不提dropbox是这样的形式.mac电脑 ...
- 百度文库,linux下安装oracle客户端
linux单独安装oracle client(oracle客户端) 更新:2013-10-17 18:30 | 标签:linux oracle 1.要远程使用oracle,先下载下面三个文件,注意 ...
- Linux下编译OpenSSL
编译环境 操作系统: Red Hat Enterprise Linux Server release 5.4 64-bit 编译工具: gcc (GCC) 4.1.2 20080704 (Red Ha ...
- Linux下C与Mysql的混合编程(转)
1 概述 MySQL 是一个关系型数据库管理系统.由瑞典MySQL AB公司开发,眼下属于Oracle公司.MySQL是最流行的关系型数据库管理系统. 支持AIX.FreeBSD.HP-UX.Linu ...
- Linux下实现 OpenSSL 简单加密与解密字符串
场景 shell脚本中存在明文密码 客户要求禁止使用明文密码,密码做加密处理. 方案 在网上了解到了Linux OpenSSL加密解密工具 可以指定各种加密算法为字符,文件做加密处理. 加密的案例比较 ...
- Linux下管道重定向使用以及Shell编程(操作系统)
实验名称:Linux的基本操作 实验目的: 1.了解管道和重定向 2.熟悉基本的Linux脚本的编写 实验环境:Ubuntu 12.4(32位,简体中文) 实验内容: 1.将当前用户目录下的文件清单输 ...
随机推荐
- C#对象的三种序列化
要让一个对象支持.Net序列化服务,用户必须为每一个关联的类加上[Serializable]特性.如果类中有些成员不适合参与序列化(比如:密码字段),可以在这些域前加上[NonSerialized]特 ...
- Servlet技术基础
由于Servlet部分涉及较多的类,要想尽快掌握Servlet基础,必须熟悉使用这些类之间的关系以及其常用的方法. 主要讲解部分包括: 1)通过实现Servelt接口来编写Servlet 2)熟悉Se ...
- jQuqery append 和 after 区别
jQuqery append 和 after 区别 append 是在被选元素内的结尾插入内容. 比如以下选中了 ol 元素,使用 append 后会在 <li> List Item 2 ...
- lvds cable信号
http://forums.bit-tech.net/showthread.php?t=208616
- dell R730 安装windwos 2008 R2在windows loading files...完成后屏幕无信号(iDrac绿屏)
dell R730 安装windwos 2008 R2在windows loading files...完成后,Starting Windows时屏幕无信号(iDrac绿屏) 解决方法: F2 进行 ...
- dig命令使用大全
https://www.cnblogs.com/daxian2012/archive/2013/01/10/2854126.html 译者序:可以这样说,翻译本篇文档的过程就是我重新学习DNS的过程, ...
- Run-time Settings 运行时设置
1.执行顺序设置和执行概率设置 2.迭代之间的等待时间设置 3.日志设置 4.思考时间 5.杂项 线程进程选择: 一般服务器没有安全机制选择线程执行 但是有安全机制的话 比如第一个进程50个线程 第二 ...
- 笔记本制作centos qcow2格式文件
笔记本win7先通过vbox安装好centos6.5 然后打开cmd命令行在c:\Program Files\Oracle\VirtualBox下执行 vboxmanage clonehd --for ...
- python xlwt操作excel
- Linux测试环境搭建apache+mysql+php
Linux Red Hat Enterprise Linux Server release 5.4 (Tikanga) Kernel \r on an \m Apache +Mysql+php 搭建准 ...