openssl engine rsa引擎进行tls认证 (9)
openssl引擎在tls通信的应用,实现tls的客户端和服务端,进行tls双休认证
我们通过rsa引擎可以替换openssl中得rsa算法,使用我们自己得算法,那么在tls(c/s)通信过程中,在handshark握手阶段有证书认证,使用rsa证书得话会涉及rsa签名,验签得过程,同时还会调用rsa公钥加密接口。
rangine.h
#ifndef __RANG_ENG_H__
#define __RANG_ENG_H__
#include <openssl/engine.h>
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/ecdh.h>
#include <openssl/crypto.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
const char *eng_id="randeng";
const char *eng_name="rand engines for OpenSSL";
/*需要声明一下结构体*/
struct evp_md_st {
int type;
int pkey_type;
int md_size;
unsigned long flags;
int (*init) (EVP_MD_CTX *ctx);
int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
int (*final) (EVP_MD_CTX *ctx, unsigned char *md);
int (*copy) (EVP_MD_CTX *to, const EVP_MD_CTX *from);
int (*cleanup) (EVP_MD_CTX *ctx);
int block_size;
int ctx_size; /* how big does the ctx->md_data need to be */
/* control function */
int (*md_ctrl) (EVP_MD_CTX *ctx, int cmd, int p1, void *p2);
} /* EVP_MD */ ;
struct evp_md_ctx_st {
const EVP_MD *digest;
ENGINE *engine; /* functional reference if 'digest' is
* ENGINE-provided */
unsigned long flags;
void *md_data;
/* Public key context for sign/verify */
EVP_PKEY_CTX *pctx;
/* Update function: usually copied from EVP_MD */
int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
} /* EVP_MD_CTX */ ;
typedef volatile int CRYPTO_REF_COUNT;
struct rsa_st {
/*
* The first parameter is used to pickup errors where this is passed
* instead of an EVP_PKEY, it is set to 0
*/
int pad;
int32_t version;
const RSA_METHOD *meth;
/* functional reference if 'meth' is ENGINE-provided */
ENGINE *engine;
BIGNUM *n;
BIGNUM *e;
BIGNUM *d;
BIGNUM *p;
BIGNUM *q;
BIGNUM *dmp1;
BIGNUM *dmq1;
BIGNUM *iqmp;
/* for multi-prime RSA, defined in RFC 8017 */
STACK_OF(RSA_PRIME_INFO) *prime_infos;
/* If a PSS only key this contains the parameter restrictions */
RSA_PSS_PARAMS *pss;
/* be careful using this if the RSA structure is shared */
CRYPTO_EX_DATA ex_data;
CRYPTO_REF_COUNT references;
int flags;
/* Used to cache montgomery values */
BN_MONT_CTX *_method_mod_n;
BN_MONT_CTX *_method_mod_p;
BN_MONT_CTX *_method_mod_q;
/*
* all BIGNUM values are actually in the following data, if it is not
* NULL
*/
char *bignum_data;
BN_BLINDING *blinding;
BN_BLINDING *mt_blinding;
CRYPTO_RWLOCK *lock;
};
struct rsa_meth_st {
char *name;
int (*rsa_pub_enc) (int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
int (*rsa_pub_dec) (int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
int (*rsa_priv_enc) (int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
int (*rsa_priv_dec) (int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
/* Can be null */
int (*rsa_mod_exp) (BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx);
/* Can be null */
int (*bn_mod_exp) (BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
/* called at new */
int (*init) (RSA *rsa);
/* called at free */
int (*finish) (RSA *rsa);
/* RSA_METHOD_FLAG_* things */
int flags;
/* may be needed! */
char *app_data;
/*
* New sign and verify functions: some libraries don't allow arbitrary
* data to be signed/verified: this allows them to be used. Note: for
* this to work the RSA_public_decrypt() and RSA_private_encrypt() should
* *NOT* be used RSA_sign(), RSA_verify() should be used instead.
*/
int (*rsa_sign) (int type,
const unsigned char *m, unsigned int m_length,
unsigned char *sigret, unsigned int *siglen,
const RSA *rsa);
int (*rsa_verify) (int dtype, const unsigned char *m,
unsigned int m_length, const unsigned char *sigbuf,
unsigned int siglen, const RSA *rsa);
/*
* If this callback is NULL, the builtin software RSA key-gen will be
* used. This is for behavioural compatibility whilst the code gets
* rewired, but one day it would be nice to assume there are no such
* things as "builtin software" implementations.
*/
int (*rsa_keygen) (RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
int (*rsa_multi_prime_keygen) (RSA *rsa, int bits, int primes,
BIGNUM *e, BN_GENCB *cb);
};
#endif // DEBUG
rangine.c
实现tls客户端
#include "rangeng.h"
static int myrand_init(ENGINE *e)
{
printf("myrand_init\n");
return 1;
}
static int myrand_finish(ENGINE *e)
{
printf("myrand_finish\n");
return 1;
}
static int myrand_destroy(ENGINE *e)
{
printf("myrand_destroy\n");
return 1;
}
static int myrand_status(void)
{
printf("myrand_status\n");
return 1;
}
static int myrand_bytes(unsigned char *buf, size_t num)
{
printf("myrand_bytes 产生随机数%d个\n",num);
memset(buf,0,num);
return 1;
}
const RAND_METHOD rand_method=
{
NULL,
myrand_bytes,
NULL,
NULL,
NULL,
myrand_status
};
static int my_engine_sha256_update(EVP_MD_CTX *ctx, const void *data, size_t count);
static int my_engine_sha256_init (EVP_MD_CTX *ctx)
{
ctx->update = &my_engine_sha256_update;
printf("initialized! SHA256\n");
return 1;
}
static int my_engine_sha256_update(EVP_MD_CTX *ctx, const void *data, size_t count)
{
printf("SHA256 update \n");
unsigned char * digest256 = (unsigned char*) malloc(sizeof(unsigned char)*32);
memset(digest256,1,32);
count = 32;
ctx->md_data = digest256;
return 1;
}
static int my_engine_sha256_final (EVP_MD_CTX *ctx, unsigned char *md)
{
printf("SHA256 final size of EVP_MD: %d\n", sizeof(EVP_MD));
memcpy(md, ctx->md_data, ctx->digest->md_size);
return 1;
}
int my_engine_sha256_cope(EVP_MD_CTX *to, const EVP_MD_CTX *from)
{
printf("Copy SHA256\n");
if (to->md_data && from->md_data) {
memcpy(to->md_data, from->md_data,sizeof(from->md_data));
}
return 1;
}
static int my_engine_sha256_clean(EVP_MD_CTX *ctx) {
printf("SHA256 cleanup\n");
if (ctx->md_data)
memset(ctx->md_data, 0, 32);
return 1;
}
// 摘要算法 digest
static EVP_MD my_sha256_engine={
NID_sha256,
0,
32,
EVP_MD_FLAG_DIGALGID_ABSENT,
my_engine_sha256_init,
my_engine_sha256_update,
my_engine_sha256_final,
my_engine_sha256_cope,
my_engine_sha256_clean,
64,
32
};
static int my_rsa_pub_enc(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
printf("my_rsa_pub_enc\n");
for (int i = 0; i < flen; i++)
{
to[i]=from[i]+10;
}
return flen;
}
static int my_rsa_pub_dec(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
printf("my_rsa_pub_dec\n");
for (int i = 0; i < flen; i++)
{
to[i]=from[i]-10;
}
return flen;
}
static int my_rsa_priv_enc(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
printf("my_rsa_priv_enc\n");
return 1;
}
static int my_rsa_priv_dec(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
printf("my_rsa_priv_dec\n");
return 1;
}
static int my_rsa_sign (int type,const unsigned char *m, unsigned int m_length,
unsigned char *sigret, unsigned int *siglen,const RSA *rsa)
{
printf("my_rsa_sign\n");
return 1;
}
static int my_rsa_verify (int type,const unsigned char *m, unsigned int m_length,
unsigned char *sigret, unsigned int *siglen,const RSA *rsa)
{
printf("my_rsa_verify\n");
return 1;
}
static int my_rsa_init(RSA *rsa)
{
printf("my_rsa_init\n");
return 1;
}
static int my_rsa_finish(RSA *rsa)
{
printf("my_rsa_finish\n");
return 1;
}
const RSA_METHOD rsa_method = {
"rsa_engine_test",
my_rsa_pub_enc,
my_rsa_pub_dec,
NULL,
NULL,
NULL,
NULL,
my_rsa_init,
my_rsa_finish,
ENGINE_METHOD_RSA,
NULL,
my_rsa_sign,
my_rsa_verify,
NULL,
NULL
};
static int my_digest_ids[] = {NID_sha256};
static int my_engine_digest_selector(ENGINE *e, const EVP_MD **digest,
const int **nids, int nid) {
int ok = 1;
if (!digest) {
*nids = my_digest_ids;
printf("\n Digest is empty! Nid:%d\n", nid);
return 2;
}
printf("Digest no %d requested\n",nid);
if (nid == NID_sha256) {
*digest = &my_sha256_engine;
}
else {
ok = 0;
*digest = NULL;
}
return ok;
}
/*绑定函数*/
static int bind_pp(ENGINE *e)
{
if(!ENGINE_set_id(e,eng_id)||
!ENGINE_set_name(e,eng_name)||
!ENGINE_set_RAND(e,&rand_method)||
!ENGINE_set_destroy_function(e,myrand_destroy)||
!ENGINE_set_init_function(e,myrand_init)||
!ENGINE_set_finish_function(e,myrand_finish)||
!ENGINE_set_RSA(e,&rsa_method)||
!ENGINE_set_digests(e, &my_engine_digest_selector)) //设置摘要选择器函数
return 0;
//RAND_set_rand_method(&rand_method);
printf("ERR_load_rsa success\n");
return 1;
}
static ENGINE *enging_range(void)
{
ENGINE*e =ENGINE_new();
if(!e)
return NULL;
if(!bind_pp(e))
{
ENGINE_free(e);
return NULL;
}
return e;
}
void ENGINE_load_rand()
{
ENGINE* e=enging_range();
if(!e)
return ;
ENGINE_add(e);
ENGINE_free(e);
//ERR_add_error(e);
}
static void display_engine_list()
{
ENGINE *h;
int loop;
h = ENGINE_get_first();
loop = 0;
printf("start:\n");
while(h)
{
printf("engine %i, id = \"%s\", name = \"%s\"\n",
loop++, ENGINE_get_id(h), ENGINE_get_name(h));
h = ENGINE_get_next(h);
}
printf("end of list\n");
ENGINE_free(h);
}
#define CACERT "../cert/ca.crt"
#define CLIENT_CRT "../cert/client.crt"
#define CLIENT_KEY "../cert/client.key"
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(-2); }
#define SERVER_ADDR "172.16.39.197" //输入自己的IP地址
#define PORT 20001
#define SERVER_mode 1
#define CLIENT_mode 0
SSL_CTX* InitSSL(char *ca_path,char *client_crt_path,char *client_key_path,int mothflag)
{
SSL_CTX* ctx=NULL;
SSL_METHOD *meth;
int status;
/* * 算法初始化 * */
SSL_library_init();
// 加载SSL错误信息
SSL_load_error_strings();
// 添加SSL的加密/HASH算法
SSLeay_add_ssl_algorithms();
/*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/
if(mothflag)
meth = (SSL_METHOD *)TLSv1_2_server_method();
else
meth = (SSL_METHOD *)TLSv1_2_client_method();
/* 创建SSL会话环境 */
ctx = SSL_CTX_new (meth);
if(ctx == NULL)
{
printf ("SSL_CTX_new error\n");
return NULL;
}
// /*验证与否,是否要验证对方*/
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
// /*若验证对方,则放置CA证书*/
SSL_CTX_load_verify_locations(ctx,ca_path,NULL);
/*加载自己的证书*/
if (SSL_CTX_use_certificate_file(ctx, client_crt_path, SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_CTX_use_certificate_file error\n");
goto exit;
}
/*加载自己的私钥,以用于签名*/
if (SSL_CTX_use_PrivateKey_file(ctx, client_key_path, SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_CTX_use_PrivateKey_file error\n");
goto exit;
}
// 设置证书私钥文件的密码
//SSL_CTX_set_default_passwd_cb_userdata(ctx, pw);
/*调用了以上两个函数后,检验一下自己的证书与私钥是否配对*/
if (!SSL_CTX_check_private_key(ctx))
{
printf("SSL_CTX_check_private_key error\n");
goto exit;
}
return ctx;
exit:
if(ctx) SSL_CTX_free (ctx);
return NULL;
}
int main()
{
// 初始化 OpenSSL 引擎系统
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
//加载引擎
ENGINE_load_rand();
display_engine_list();
ENGINE *e=NULL;
e=ENGINE_by_id(eng_id);
if(!e)
{
printf("err load engine failed\n");
return 0;
}
ENGINE_init(e);
printf("RAND-----BEGIN---END\n");
// 调用引擎中的随机数生成方法
//ENGINE_set_default_RAND(e);
unsigned char rand_buf[6]={0};
int err = RAND_bytes(rand_buf,5);
for(int i= 0; i < 5; i++) {
printf("%x",rand_buf[i]);
}
printf("\n");
char * str1 = "Fraunhofer FKIE Wachtberg!";
int str_len = 26;
int er;
er = ENGINE_set_default_digests(e);
printf("ENGINE SETTING DEFAULT DIGESTS %d\n",er);
unsigned char digest[32] = {0};
unsigned int digestSize = -1;
EVP_MD_CTX *evp_ctx=NULL;
printf("SHA256-----BEGIN---END\n");
evp_ctx = EVP_MD_CTX_create();
er = EVP_DigestInit_ex(evp_ctx, EVP_sha256(),e);
printf("Digest INIT %d\n",er);
er = EVP_DigestUpdate(evp_ctx, (unsigned char*)str1, str_len);
printf("Digest Update %d\n",er);
er = EVP_DigestFinal(evp_ctx, digest, &digestSize);
printf("Digest Final %d Digest size:%d\n",er,digestSize);
for(int i= 0; i< digestSize; i++) {
printf("%x", digest[i]);
}
printf("\n");
EVP_MD_CTX_destroy(evp_ctx);
printf("RSA-----BEGIN---END\n");
ENGINE_register_RSA(e); //
RSA *rsa = RSA_new();
BIGNUM *bn = BN_new();
BN_set_word(bn, RSA_F4);
RSA_generate_key_ex(rsa, 2048, bn, NULL);
printf("RSA Key Pair:\n");
RSA_print_fp(stdout, rsa, 0);
// 使用引擎进行 RSA 加密
unsigned char plaintext[] = "Hello, World!";
unsigned char ciphertext[256]={0}; // 注意,缓冲区大小可能需要根据您的密钥长度进行调整
unsigned char plaintext1[256]={0};
int len = RSA_public_encrypt(sizeof(plaintext), plaintext, ciphertext, rsa, RSA_PKCS1_PADDING);
len=RSA_public_decrypt(len, ciphertext, plaintext1, rsa, RSA_PKCS1_PADDING);
// 打印加密后的数据
printf("Encrypted data: ");
for (int i = 0; i < len; i++) {
printf("%02x ", ciphertext[i]);
}
printf("\n");
printf("ciphertext=%s\n",ciphertext);
// 打印加密后的数据
printf("decrypted data: ");
for (int i = 0; i < len; i++) {
printf("%02x ", plaintext1[i]);
}
printf("\n");
printf("ciphertext=%s\n",plaintext1);
int sd=0;
int confd=0;
SSL* ssl=NULL;
SSL_CTX* ctx=NULL;
struct sockaddr_in sa={0};
ctx=InitSSL(CACERT,CLIENT_CRT,CLIENT_KEY,CLIENT_mode);
if(ctx==NULL) return -1;
/* 指定加密器类型 */
//SSL_CTX_set_cipher_list (ctx, "ECDHE-RSA-AES256-SHA");
SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY);
/*以下是正常的TCP socket建立过程 .............................. */
printf("Begin tcp socket...\n");
sd= socket (AF_INET, SOCK_STREAM, 0);
if(sd <= 0)
{
perror("socket");
goto exit;
}
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(SERVER_ADDR); /* Server IP */
sa.sin_port = htons(PORT); /* Server Port number */
confd = connect(sd, (struct sockaddr*)&sa, sizeof(sa));
if(confd < 0)
{
printf("connect error=%d\n",confd);
goto exit;
}
/* TCP 链接已建立.开始 SSL 握手过程.......................... */
printf("Begin SSL negotiation \n");
/*申请一个SSL套接字*/
ssl = SSL_new (ctx);
if(ssl <= 0)
{
printf("Error creating SSL new \n");
goto exit;
}
/*绑定读写套接字*/
SSL_set_fd (ssl, sd);
SSL_connect (ssl);
printf("链接已建立.开始 SSL 握手过程 \n");
/*打印所有加密算法的信息(可选)*/
printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
/*得到服务端的证书并打印些信息(可选) */
X509* server_cert = SSL_get_peer_certificate (ssl);
printf ("Server certificate:\n");
char *str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
printf ("/t subject: %s\n", str);
free (str);
str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0);
printf ("/t issuer: %s\n", str);
free (str);
X509_free (server_cert); /*如不再需要,需将证书释放 */
/* 数据交换开始,用SSL_write,SSL_read代替write,read */
printf("Begin SSL data exchange\n");
unsigned char buf[300]={0};
while(1)
{
gets(buf);
int ret = SSL_write (ssl, buf, sizeof(buf));
memset (buf, 0, sizeof(buf));
}
SSL_shutdown (ssl); /* send SSL/TLS close_notify */
/* 收尾工作 */
shutdown (sd,2);
exit:
if(sd > 0) close (sd);
if(confd > 0) close (confd);
if(ctx) SSL_CTX_free(ctx);
if(ssl) SSL_free (ssl);
return 0;
// 清理引擎资源
ENGINE_finish(e);
ENGINE_free(e);
}
tls服务端
OPENSSL TLS认证
研究openssl 加密套件协商过程
在一台 uBuntu 上执行以下命令建立 TLS/SSL Server
openssl s_server -CAfile ca.crt -cert server.crt -key server.key -port 20001 -verify 1 -tls1_2
切记证书相同保证一致
结果查看
我自己写的简单rsa算法并不满足openssl的tls验证,但是通过客户端打印可以发现,openssl 在进行tls认证的时候使用的是我们rsa引擎的算法!