自签名证书创建,c代码验证

事前准备

相关:
pem、key:私钥文件,对数据进行加密解密
csr:证书签名请求文件,将其提交给证书颁发机构(ca、CA)对证书签名
crt:由证书颁发机构(ca、CA)签名后的证书或者自签名证书,该证书包含证书持有人的信息、持有人的公钥以及签署者的签名等信息
关于证书相关格式转换本文不做介绍


终端输入命令:vim /usr/local/openssl/ssl/openssl.cnf,根据自己具体的安装路径查找openssl的默认配置文件即可,部分内容如下图显示:

openssl默认配置部分截图

dir:默认的ssl工作目录,可以修改默认目录,这里是安装完默认的
certs:存放已经签发的证书
newcerts:存放CA新生成的证书
private:存放私钥
crl:存放已经吊销的证书
index.txt:已签发证书的文本数据库文件
serial:序列号存储文件,序列号为16进制数存储供证书签发使用序列号做参考
.rand:私有随机文件,
生成随机数命令:openssl rand -out xxx/.rand 1024
1024表示随机数长度
在生成证书的临时目录里创建默认配置目录文件命令,一键梭哈:
mkdir -p ./demoCA/certs; mkdir -p ./demoCA/crl; mkdir ./democA/newcerts; mkdir -p ./demoCA/private; touch ./demoCA/index.txt; touch ./demoCA/serial; echo 01 > ./demoCA/serial;


创建自己生成证书的临时文件夹:mkdir ~/Desktop/openssl_ssl
进入文件夹:cd ~/Desktop/openssl_ssl,然后将之前提到过得【openssl.cnf】文件复制到此,开始制作证书用于之后的socket编程里

1. 制作ca根证书

1.1 生成ca根证书私钥

openssl genrsa -aes256 -out ca.key 2048

genrsa:使用RSA算法生成私钥
-aes256:使用256位密钥的AES算法对私钥进行加密
-out:输出文件路径
2048:私钥长度
输入完命令会让你输入两遍私钥文件的密码

1.2 生成ca根证书请求文件

openssl req -new -key ca.key -out ca.csr

req:执行证书签发命令
-new:新的证书签发请求
-key:指定私钥文件的路径
-out:csr文件的输出路径
输入完命令会让你输入ca根证书私钥的密码并填写一些信息,如下所示:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.


Country Name (2 letter code) [AU]:cn 【国家代码两个字母可为空,ca、server、client要一致】
State or Province Name (full name) [Some-State]:【省份,ca、server、client要一致】
Locality Name (eg, city) []:【城市】
Organization Name (eg, company) [Internet Widgits Pty Ltd]:【公司名,ca、server、client要一致】
Organizational Unit Name (eg, section) []:【组织名】
Common Name (e.g. server FQDN or YOUR name) []:【不可为空,全限定域名或名字】
Email Address []:【邮箱】

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:【输入密码】
An optional company name []:【可选的公司名】

上面输入的ca请求信息在后续申请使用该ca证书签名的请求证书要保证一致。

1.3自己作为ca机构签发根证书(自签发证书)

openssl x509 -req -days 365 -signkey ca.key -in ca.csr -out ca.crt

x509:用于自签名证书,生成x509格式的证书
-req:请求签名
-days:证书有效期
-signkey:证书签发的私钥
-in:证书请求文件,有效的文件路径
-out:ca签名后的证书输出路径

2. 制作server端证书

用刚才的ca证书为使用端签发证书

2.1 生成server端私钥

openssl genrsa -aes256 -out server.key 2048
连续输入两次密码

2.2 生成server端证书请求文件

openssl req -new -key server.key -out server.csr
同样的会让你输入刚才私钥的密码,并填写和ca根证书请求文件一样的信息,两者要保持一样

2.3 使用ca根证书为server端签发证书

openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key -config openssl.cnf

-in:输入证书签名请求文件
-out:签名后的证书输出路径
-cert:ca根证书
-keyfile:ca根证书私钥文件
-config:配置文件

3 制作client端证书

套路和server端基本是一样的,下面就直接上命令了

3.1 生成client端私钥

openssl genrsa -aes256 -out client.key 2048

3.2 生成client端证书请求文件

openssl req -new -key client.key-out client.csr

3.3 使用ca根证书为client端签发证书

openssl ca -in client.csr -out client.crt -cert ca.crt -keyfile ca.key -config openssl.cnf

文件变化:1. index.txt本地数据库文本文件多了两条信息、2. serial序列号文件的序列号递增了、3. newcerts文件夹多了两个证书、4. 其它...

到这里我们就可以结束了,我们已经得到了ca.crt、server.key、server.crt、client.key、client.crt,我们就可以开始编程了。
双向认证要保证server、client端证书签名的ca要一样或者期限没有过期否则会认证失败

【下一篇:openssl 自签名证书 - socket编程应用(三)】


4. 导出证书

4.1 导出server端证书

导出时会让你输入server端私钥的密码,即server-key.pem的密码,验证通过后再输入两次证书导出的密码
openssl pkcs12 -export -clcerts -name server-p12 -inkey server.key -in server.crt -out server-p12.keystore

4.2 导出client端证书

导出同server操作是一样的,先输入client-key.pem的密码,在输入两次证书导出的密码
openssl pkcs12 -export -clcerts -name client-p12 -inkey client.key -in client.crt -out client-p12.keystore

4.3 导出受信任的证书

keytool -importcert -trustcacerts -alias localhost -file ca-crt.cer -keystore ca-trust.keystore

终端显示:

输入密钥库口令:
再次输入新口令:
所有者: EMAILADDRESS=【邮箱地址】, CN=127.0.0.1, OU=【组织名】, O=【公司】, L=【市】, ST=【省份】, C=cn【国家代码】
发布者: EMAILADDRESS=【邮箱地址】, CN=127.0.0.1, OU=【组织名】, O=【公司名】, L=【市】, ST=【省份】, C=cn【国家代码】
序列号: 4272b0ce733*************316f20cfe5f6a182
生效时间: Mon Jan 28 11:12:17 CST 2019, 失效时间: Tue Jan 28 11:12:17 CST 2020
证书指纹:
SHA1: C1:B6:C6:B3:95:8F:3C:12:B8:C4:AB:5E:8B:0D:03:6B:6D:B2:1E:D3
SHA256: 31:BF:B7:EA:F3:72:E9:28:95:55:41:76:F0:7B:24:19:2B:FF:C7:C4:AA:AE:63:EF:6C:98:69:5A:49:37:56:3F
签名算法名称: SHA256withRSA
主体公共密钥算法: 2048 位 RSA 密钥
版本: 1
是否信任此证书? [否]: y【终端输入y/n】
证书已添加到密钥库中

现在就可以使用ca证书,server端证书和私钥,client端证书和私钥开始socket编程了...



作者:码掺和_夏尼
链接:https://www.jianshu.com/p/37ded4da1095
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

用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. 静态库设置

  1. 将编译出来的【libcrypto.a】【libssl.a】复制工程目录然后添加进来
  2. 我是homebrew安装的,复制【libcrypto.a】【libssl.a】到工程目录然后添加进来,“什么?我去哪里找?!”,一般是在/usr/local/opt/openssl/lib/目录下

4. 上代码

#include <stdio.h>

#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

#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...



作者:码掺和_夏尼
链接:https://www.jianshu.com/p/bba9c47a0515
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

以下是使用 OpenSSL 库进行签名验证的示例代码。假设您已经有了签名和公钥证书的文件。 ```c #include <stdio.h> #include <stdlib.h> #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/pem.h> int main() { // 读取签名文件 FILE* f = fopen("signature.bin", "rb"); if (!f) { perror("Failed to open signature file"); return EXIT_FAILURE; } fseek(f, 0, SEEK_END); long siglen = ftell(f); rewind(f); unsigned char* sig = (unsigned char*)malloc(siglen); fread(sig, 1, siglen, f); fclose(f); // 读取公钥文件 BIO* bio = BIO_new_file("public.crt", "r"); if (!bio) { perror("Failed to open public key file"); return EXIT_FAILURE; } X509* cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); EVP_PKEY* pubkey = X509_get_pubkey(cert); // 读取要验证的文件 f = fopen("file_to_verify.bin", "rb"); if (!f) { perror("Failed to open file to verify"); return EXIT_FAILURE; } fseek(f, 0, SEEK_END); long datalen = ftell(f); rewind(f); unsigned char* data = (unsigned char*)malloc(datalen); fread(data, 1, datalen, f); fclose(f); // 创建签名上下文并验证签名 EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); EVP_VerifyInit(mdctx, EVP_sha256()); EVP_VerifyUpdate(mdctx, data, datalen); int result = EVP_VerifyFinal(mdctx, sig, siglen, pubkey); // 清理资源 EVP_MD_CTX_free(mdctx); EVP_PKEY_free(pubkey); X509_free(cert); BIO_free(bio); free(sig); free(data); // 输出验证结果 if (result == 1) { printf("Signature verification succeeded!\n"); return EXIT_SUCCESS; } else if (result == 0) { printf("Signature verification failed!\n"); return EXIT_FAILURE; } else { printf("Error occurred during signature verification!\n"); return EXIT_FAILURE; } } ``` 这是一个简单的示例,您需要根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值