c语言web服务实现https证书存储在字符串中

一、背景

公司有一个需求需要在windows平台上实现一个web小程序,对该web小程序有如下要求:
1. 体积小,10M以下
2. 无需安装,下载下来,鼠标双击即可使用
3. 实现https加密和浏览器进行通信

二、技术选型

为了实现这个小程序,公司对技术做了如下选型:
1. 使用C语言编写
2. 使用mongoose框架
3. 使用openssl库实现https加密
4. ssl证书保存在字符串中,不存储在文件中。

注: ssl证书不存储在文件中,而存储在字符串中,是因为该小程序不需要安装,只有一个exe文件,不能有其他额外的文件。

三、技术实现

公司使用mongoose框架做webserver,mongoose非常轻量,github地址是:https://github.com/cesanta/mongoose,目前有5k多个星,比较稳定。

实现上比较麻烦的是ssl证书不存储在文件中,而是存储在字符串中。mongoose关于https的实现,都是基于证书为文件实现的,所以需要对相关代码进行修改。

下面直接上干货,修改的函数主要是mongoose.c文件中的mg_use_cert函数。

3.1 mg_user_cert函数默认加载ssl文件代码

static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
                                         const char *key,
                                         const char **err_msg) {
  if (key == NULL) key = cert;
  if (cert == NULL || cert[0] == '
static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
const char *key,
const char **err_msg) {
if (key == NULL) key = cert;
if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
return MG_SSL_OK;
} else if (SSL_CTX_use_certificate_file(ctx, cert, 1) == 0) {
MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
return MG_SSL_ERROR;
} else if (SSL_CTX_use_PrivateKey_file(ctx, key, 1) == 0) {
MG_SET_PTRPTR(err_msg, "Invalid SSL key");
return MG_SSL_ERROR;
} else if (SSL_CTX_use_certificate_chain_file(ctx, cert) == 0) {
MG_SET_PTRPTR(err_msg, "Invalid CA bundle");
return MG_SSL_ERROR;
} else {
SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#if !MG_DISABLE_PFS && !defined(KR_VERSION)
BIO *bio = NULL;
DH *dh = NULL;
/* Try to read DH parameters from the cert/key file. */
bio = BIO_new_file(cert, "r");
if (bio != NULL) {
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
}
/*
* If there are no DH params in the file, fall back to hard-coded ones.
* Not ideal, but better than nothing.
*/
if (dh == NULL) {
bio = BIO_new_mem_buf((void *) mg_s_default_dh_params, -1);
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
}
if (dh != NULL) {
SSL_CTX_set_tmp_dh(ctx, dh);
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
DH_free(dh);
}
#if OPENSSL_VERSION_NUMBER > 0x10002000L
SSL_CTX_set_ecdh_auto(ctx, 1);
#endif
#endif
}
return MG_SSL_OK;
}
' || key == NULL || key[0] == '
static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
const char *key,
const char **err_msg) {
if (key == NULL) key = cert;
if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
return MG_SSL_OK;
} else if (SSL_CTX_use_certificate_file(ctx, cert, 1) == 0) {
MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
return MG_SSL_ERROR;
} else if (SSL_CTX_use_PrivateKey_file(ctx, key, 1) == 0) {
MG_SET_PTRPTR(err_msg, "Invalid SSL key");
return MG_SSL_ERROR;
} else if (SSL_CTX_use_certificate_chain_file(ctx, cert) == 0) {
MG_SET_PTRPTR(err_msg, "Invalid CA bundle");
return MG_SSL_ERROR;
} else {
SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#if !MG_DISABLE_PFS && !defined(KR_VERSION)
BIO *bio = NULL;
DH *dh = NULL;
/* Try to read DH parameters from the cert/key file. */
bio = BIO_new_file(cert, "r");
if (bio != NULL) {
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
}
/*
* If there are no DH params in the file, fall back to hard-coded ones.
* Not ideal, but better than nothing.
*/
if (dh == NULL) {
bio = BIO_new_mem_buf((void *) mg_s_default_dh_params, -1);
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
}
if (dh != NULL) {
SSL_CTX_set_tmp_dh(ctx, dh);
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
DH_free(dh);
}
#if OPENSSL_VERSION_NUMBER > 0x10002000L
SSL_CTX_set_ecdh_auto(ctx, 1);
#endif
#endif
}
return MG_SSL_OK;
}
') { return MG_SSL_OK; } else if (SSL_CTX_use_certificate_file(ctx, cert, 1) == 0) { MG_SET_PTRPTR(err_msg, "Invalid SSL cert"); return MG_SSL_ERROR; } else if (SSL_CTX_use_PrivateKey_file(ctx, key, 1) == 0) { MG_SET_PTRPTR(err_msg, "Invalid SSL key"); return MG_SSL_ERROR; } else if (SSL_CTX_use_certificate_chain_file(ctx, cert) == 0) { MG_SET_PTRPTR(err_msg, "Invalid CA bundle"); return MG_SSL_ERROR; } else { SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #if !MG_DISABLE_PFS && !defined(KR_VERSION) BIO *bio = NULL; DH *dh = NULL; /* Try to read DH parameters from the cert/key file. */ bio = BIO_new_file(cert, "r"); if (bio != NULL) { dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); } /* * If there are no DH params in the file, fall back to hard-coded ones. * Not ideal, but better than nothing. */ if (dh == NULL) { bio = BIO_new_mem_buf((void *) mg_s_default_dh_params, -1); dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); } if (dh != NULL) { SSL_CTX_set_tmp_dh(ctx, dh); SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); DH_free(dh); } #if OPENSSL_VERSION_NUMBER > 0x10002000L SSL_CTX_set_ecdh_auto(ctx, 1); #endif #endif } return MG_SSL_OK; }

3.2 修改mg_user_cert函数从字符串中加载ssl证书

直接上修改好的代码,主要思路是:
1. 使用函数SSL_CTX_use_certificate 替换SSL_CTX_use_certificate_file
2. 使用PEM_read_bio_RSAPrivateKey 替换SSL_CTX_use_PrivateKey_file.
3. 使用X509_STORE_add_cert函数替换SSL_CTX_use_certificate_chain_file来添加cert证书

具体代码如下:

3.3 字符串存储ssl证书

本文只给出了ssl证书的一部分,详情如下

3.3.1 字符存储key

3.3.2 字符存储key

四、参考文件

curlx.c
gistfile1.txt
OpenSSL API

本文来自网络,不代表云小秘立场,转载请注明出处:https://www.cloudmmu.com/684.html

作者: 欧邦

折腾不休,奋斗不止

发表评论

联系我们

联系我们

15877997995

在线咨询: QQ交谈

邮箱: oubang@live.cn

工作时间:周一至周五,9:00-21:00,节假日休息
关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部