openssl学习!
为了完成老师布下的实验 ,通过在网上搜集资料,一步一步了解其中的原理
我是通过蓝桥云课提供的免费课程学习的 但是其中有一步服务端与客户端的demo中的证书到2021年1月份到期了 导致没法进行实验 所以自己又查阅了一些资料
熟悉公钥加密与PKI的概念,实验包含公钥加密,数字签名,公钥认证,认证授权,基于PKI授权等内容,使用openssl 命令行工具或者写程序的方式建立基于PKI的安全信道。
实验环境:Centos 7
数字证书认证机构(CA)
简单地说是负责发放和管理数字证书的权威机构,并作为电子商务交易中受信任的第三方,承担公钥体系中公钥的合法性检验的责任。
数字证书的作用是证明证书中列出的用户合法拥有证书中列出的公开密钥。CA机构的数字签名使得攻击者不能伪造和篡改证书。它负责产生、分配并管理所有参与网上交易的个体所需的数字证书,因此是安全电子交易的核心环节。
自己成为root CA,为了不花钱!~
从商业CA获取数字证书需要向其支付一定的金钱
- 首先找到自己系统的
openssl.conf
在哪里
[root@hadoop01 tls]# pwd
/etc/pki/tls
[root@hadoop01 tls]# ls
cert.pem certs misc openssl.cnf private
- 我们只要 openssl.cnf 这个文件 把他复制到自己创建的文件夹下
[root@hadoop01 openssl]# pwd
/root/homework/openssl 这是我自己创建的文件夹 位置随意 方便找到就行
- 在该文件夹里按顺序执行以下操作
mkdir demoCA
---
cd demoCA
---
mkdir certs crl newcerts
---
touch index.txt
---
echo '1000' > serial
---
cd ..
---
执行 tree 查看目录结构(没有该命令就先安装一下 yum install -y tree)
- 对 openssl.conf 进行编辑
vim openssl.conf
- 我们需要为自己的CA生成自签名证书。这意味着该机构是被信任的,而它的证书会作为root 证书。
openssl req -new -x509 -keyout ca.key -out ca.crt -config openssl.cnf
第一阶段 完成!!
提供证书
为一个公司从CA获取数字证书需要3个步骤:
1:生成公开/私有密钥对
公司首先需要生成它自己的公开/私有密钥对。同时需要提供一个密码来保护密钥密钥会被保存在server.key 文件中。
2:生成证书签名请求
—旦公司拥有了密钥文件,它应当生成证书签名请求(CSR)。CSR将被发送给CA,CA会为该请求生成证书(通常在确认CSR中的身份信息匹配后)。 仔细检查输入的内容! 我之前写的那个红色框框文字
3:生成证书
生成证书。CSR文件需要拥有CA的签名来构成证书。在现实世界中,CSR文件常常被发送给可信任的CA签名。本实验中,我们将使用我们自己的CA来生成证书:
- 先玩一个服务端~~
openssl genrsa -des3 -out server.key 1024 之后会提示设置密码,别忘了!
openssl req -new -key server.key -out server.csr -config openssl.cnf
openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key -config openssl.cnf
- 照猫画虎 再来个客户端~ 就是把server换成了client
openssl genrsa -des3 -out client.key 1024
openssl req -new -key client.key -out client.csr -config openssl.cnf
openssl ca -in client.csr -out client.crt -cert ca.crt -keyfile ca.key -config openssl.cnf
编写服务端与客户端的c语言代码
这两份代码是从demo_openssl_api 压缩包里找的 但是这个demo提供的证书过期了 所以我们自己创建了服务端与客户端证书
服务端代码:
/* serv.cpp - Minimal ssleay server for Unix
30.9.1996, Sampo Kellomaki <sampo@iki.fi> */
/* mangled to work with SSLeay-0.9.0b and OpenSSL 0.9.2b
Simplified to be even more minimal
12/98 - 4/99 Wade Scholine <wades@mail.cybg.com> */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/rsa.h> /* SSLeay stuff */
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
/* define HOME to be dir for key and cert files... */
#define HOME "./"
/* Make these what you want for cert & key files */
#define CERTF HOME "server.crt"
#define KEYF HOME "server.key"
#define CACERT HOME "ca.crt"
#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }
int main ()
{
int err;
int listen_sd;
int sd;
struct sockaddr_in sa_serv;
struct sockaddr_in sa_cli;
size_t client_len;
SSL_CTX* ctx;
SSL* ssl;
X509* client_cert;
char* str;
char buf [4096];
SSL_METHOD *meth;
/* SSL preliminaries. We keep the certificate and key with the context. */
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
meth = SSLv23_server_method();
ctx = SSL_CTX_new (meth);
if (!ctx) {
ERR_print_errors_fp(stderr);
exit(2);
}
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /* whether verify the certificate */
SSL_CTX_load_verify_locations(ctx,CACERT,NULL);
if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(3);
}
if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(4);
}
if (!SSL_CTX_check_private_key(ctx)) {
fprintf(stderr,"Private key does not match the certificate public key\n");
exit(5);
}
/* ----------------------------------------------- */
/* Prepare TCP socket for receiving connections */
listen_sd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR(listen_sd, "socket");
memset (&sa_serv, '\0', sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons (1111); /* Server Port number */
err = bind(listen_sd, (struct sockaddr*) &sa_serv,
sizeof (sa_serv)); CHK_ERR(err, "bind");
/* Receive a TCP connection. */
err = listen (listen_sd, 5); CHK_ERR(err, "listen");
client_len = sizeof(sa_cli);
sd = accept (listen_sd, (struct sockaddr*) &sa_cli,(socklen_t *) &client_len);
CHK_ERR(sd, "accept");
close (listen_sd);
printf ("Connection from %lx, port %x\n",
sa_cli.sin_addr.s_addr, sa_cli.sin_port);
/* ----------------------------------------------- */
/* TCP connection is ready. Do server side SSL. */
ssl = SSL_new (ctx); CHK_NULL(ssl);
SSL_set_fd (ssl, sd);
err = SSL_accept (ssl); CHK_SSL(err);
/* Get the cipher - opt */
printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
/* Get client's certificate (note: beware of dynamic allocation) - opt */
client_cert = SSL_get_peer_certificate (ssl);
if (client_cert != NULL) {
printf ("Client certificate:\n");
str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
CHK_NULL(str);
printf ("\t subject: %s\n", str);
OPENSSL_free (str);
str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
CHK_NULL(str);
printf ("\t issuer: %s\n", str);
OPENSSL_free (str);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
X509_free (client_cert);
} else
printf ("Client does not have certificate.\n");
/* DATA EXCHANGE - Receive message and send reply. */
err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err);
buf[err] = '\0';
printf ("Got %d chars:'%s'\n", err, buf);
err = SSL_write (ssl, "I hear you.", strlen("I hear you.")); CHK_SSL(err);
/* Clean up. */
close (sd);
SSL_free (ssl);
SSL_CTX_free (ctx);
return 0;
}
/* EOF - serv.cpp */
客户端:
/* cli.cpp - Minimal ssleay client for Unix
30.9.1996, Sampo Kellomaki <sampo@iki.fi> */
/* mangled to work with SSLeay-0.9.0b and OpenSSL 0.9.2b
Simplified to be even more minimal
12/98 - 4/99 Wade Scholine <wades@mail.cybg.com> */
#include <unistd.h>
#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define CERTF "client.crt"
#define KEYF "client.key"
#define CACERT "ca.crt"
#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }
int main ()
{
int err;
int sd;
struct sockaddr_in sa;
SSL_CTX* ctx;
SSL* ssl;
X509* server_cert;
char* str;
char buf [4096];
SSL_METHOD *meth;
SSLeay_add_ssl_algorithms();
meth = SSLv23_client_method();
SSL_load_error_strings();
ctx = SSL_CTX_new (meth); CHK_NULL(ctx);
CHK_SSL(err);
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,CACERT,NULL);
if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(-2);
}
if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(-3);
}
if (!SSL_CTX_check_private_key(ctx)) {
printf("Private key does not match the certificate public keyn");
exit(-4);
}
/* ----------------------------------------------- */
/* Create a socket and connect to server using normal socket calls. */
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 ("127.0.0.1"); /* Server IP */
sa.sin_port = htons (1111); /* Server Port number */
err = connect(sd, (struct sockaddr*) &sa,
sizeof(sa)); CHK_ERR(err, "connect");
/* ----------------------------------------------- */
/* Now we have TCP conncetion. Start SSL negotiation. */
ssl = SSL_new (ctx); CHK_NULL(ssl);
SSL_set_fd (ssl, sd);
err = SSL_connect (ssl); CHK_SSL(err);
/* Following two steps are optional and not required for
data exchange to be successful. */
/* Get the cipher - opt */
printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
/* Get server's certificate (note: beware of dynamic allocation) - opt */
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);
OPENSSL_free (str);
str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0);
CHK_NULL(str);
printf ("\t issuer: %s\n", str);
OPENSSL_free (str);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
X509_free (server_cert);
/* --------------------------------------------------- */
/* DATA EXCHANGE - Send a message and receive a reply. */
err = SSL_write (ssl, "Hello World!", strlen("Hello World!")); 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 */
/* Clean up. */
close (sd);
SSL_free (ssl);
SSL_CTX_free (ctx);
return 0;
}
/* EOF - cli.cpp */
创建一个Makefile 文件
INC=/usr/include/openssl
LIB=/etc/ssl
all:
g++ -I$(INC) -L$(LIB) cli.cpp -o cli -lssl -lcrypto -ldl -fpermissive
g++ -I$(INC) -L$(LIB) serv.cpp -o serv -lssl -lcrypto -ldl -fpermissive
clean:
rm -rf *~ cli serv
使用 make 命令 编译出可执行文件
大功告成!
放到虚拟机目录里 我分别放入了两台虚拟机
之后分别
./serv 启动服务端 窗口别关 再开一个终端
---
./cli 启动客户端
数字签名
[root@hadoop01 sign]# echo "zhangan" > zhangan.txt
[root@hadoop01 sign]# ls
zhangan.txt
[root@hadoop01 sign]# cat zhangan.txt
zhangan
# 产生数字摘要。
[root@hadoop01 sign]# openssl genrsa -des3 -out myrsaCA.pem 1024
Generating RSA private key, 1024 bit long modulus
.....................................................++++++
.....................................................................++++++
e is 65537 (0x10001)
Enter pass phrase for myrsaCA.pem:
Verifying - Enter pass phrase for myrsaCA.pem:
# RSA 密钥对
[root@hadoop01 sign]# openssl rsa -in myrsaCA.pem -pubout -out myrsapubkey.pem
Enter pass phrase for myrsaCA.pem:
writing RSA key
# 使用 sha256 进行签名
[root@hadoop01 sign]# openssl dgst -sha256 -out zhangan.sha256 -sign myrsaCA.pem zhangan.txt
Enter pass phrase for myrsaCA.pem:
# 查看目录下文件
[root@hadoop01 sign]# ls
myrsaCA.pem myrsapubkey.pem zhangan.sha256 zhangan.txt
# 验证签名
openssl dgst -sha256 -signature zhangan.sha256 -verify myrsapubkey.pem zhangan.txt
Verified OK
#######当我修改了zhangan.txt之后 再次进行校验测试
[root@hadoop01 sign]# echo "zhangan zhenshuai" > zhangan.txt
[root@hadoop01 sign]# cat zhangan.txt
zhangan zhenshuai
[root@hadoop01 sign]# openssl dgst -sha256 -signature zhangan.sha256 -verify myrsapubkey.pem zhangan.txt
Verification Failure