生成自己的自签名证书

16 篇文章 2 订阅

因为在测试wss (WebSocket Secure)的时候,需要证书。因此参考网上的文章做了一个自己的server的证书。具体步骤如下,参考文章

制作用于CA签名的证书

生成CA证书的私钥

$ openssl genrsa -des3 -passout pass:123456 -out ca.key 2048
Generating RSA private key, 2048 bit long modulus
................+++
..............................................................................................................+++
e is 65537 (0x10001)

-passout pass:123456 表示加密私钥文件时,传递密码是123456
genrsa 的详细说明见此文章

生成一个证书请求文件:

$ openssl req -new -out ca.csr -key ca.key -passin pass:123456 -keyform PEM -subj "/C=CN/ST=SC/L=CD/O=CTP/OU=DEV/CN=0.0.0.0"

其中参数:

  • -new 表示新生成一个新的证书请求文件
  • -out ca.csr 指定输出文件 ca.csr,此处输出文件即为证书请求文件
  • -key ca.key指定私钥文件ca.key
  • -passin pass:123456 是用户私钥的保护口令 123456
  • -keyform PEM 表示编码格式为 PEM,可选 DER
  • -subj 用于指定生成的证书请求的用户信息

注意:
CA证书的 subj 中的 CN 不要与后面签发的其他证书的 CN 内容相同,否则 OpenSSL 验证证书时无法通过

更多参数详情见此文章此文章

接下来生成CA 证书:

$ openssl x509 -req -days 3650 -in ca.csr -signkey ca.key -passin pass:123456 -CAcreateserial -out ca.crt
Signature ok
subject=/C=CN/ST=SC/L=CD/O=CTP/OU=DEV/CN=0.0.0.0
Getting Private key

参数说明:

  • -req 表示输入文件为证书请求文件
  • -days 3650 表示证书有效期为3650天,根证书的有效期一般为10年,普通证书有效期一般为1年
  • -in ca.csr 输入文件ca.csr可以是证书请求文件(-req指定为证书请求文件),也可以是已签署过的证书
  • -signkey ca.key 用于提供自签署时的私钥文件ca.key
  • -CAcreateserial 当使用该选项时,如果CA使用的序列号文件不存在将自动创建:该文件将包含序列号值"02"并且此次签名后证书文件序列号为1。

更多参数说明见此文章

更多:
上述步骤其实也可以浓缩成下面一步:

$ openssl req -newkey rsa:2048 -nodes -keyout ca.key -x509 -days 3650 -out ca.crt -subj "/C=CN/ST=SC/L=CD/O=CTP/OU=DEV/CN=0.0.0.0"
Generating a 2048 bit RSA private key
..............+++
......................+++
writing new private key to 'ca.key'
-----

参数说明:

  • -nodes 选项-nodes不是英文单词“nodes”,而是“no DES”。 当作为参数给出时,这意味着OpenSSL不会对 PKCS#12文件中的私钥做密码保护。
    如果需要对密钥进行密码保护,可以将-nodes用上面第一条命令的-passout pass:123456代替。

参考这篇文章

用CA签名产生服务器证书

生成用于服务器证书的私钥

$ openssl genrsa -des3 -passout pass:123456 -out server.key 2048
Generating RSA private key, 2048 bit long modulus
......................+++
...............+++
e is 65537 (0x10001)

生成服务器使用的证书请求文件:

$ openssl req -new -key server.key -passin pass:123456 -out server.csr -subj "/C=CN/ST=SC/L=CD/O=CTP/OU=DEV/CN=127.0.0.1"

生成服务器使用的自签名SSL证书

$ openssl x509 -req -in server.csr -passin pass:123456 -out server.crt -signkey server.key -CA ca.crt -CAkey ca.key -days 365 -CAcreateserial
Signature ok
subject=/C=CN/ST=SC/L=CD/O=CTP/OU=DEV/CN=127.0.0.1
Getting Private key
Getting CA Private Key

参数说明:

  • -CA ca.crt 指定签署时所使用的CA证书ca.crt
  • -CAkey ca.key 设置CA签署时使用的私钥文件ca.key。如果该选项没有指定,将假定CA私钥已经存在于CA自签名的证书文件中。

OpenSSL API 实现SSL连接代码

用于测试证书上述证书的代码如下:

ssl_common.h

//ssl_common.h

#include <stdio.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>


inline
const char* SSL_error_string()
{
    return ERR_error_string(ERR_get_error(), NULL);
}

inline
void ssl_init_lib()
{
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();
}

inline
SSL* ssl_new(SSL_CTX* ctx, int socket)
{
    SSL* ssl = SSL_new(ctx);
    if(NULL == ssl)
        printf("SSL_new return %s\n", SSL_error_string());
    else
        SSL_set_fd(ssl, socket);
    return ssl;
}

inline
void ssl_free(SSL*& ssl)
{
    SSL_shutdown(ssl);
    SSL_free(ssl);
    ssl = NULL;
}

inline
int ssl_set_verify(SSL_CTX* ctx, const char* root_certificate_path, const char* root_certificate_dir = NULL)
{
    int r = 1;
    if(root_certificate_path || root_certificate_dir)
    {
        if((r = SSL_CTX_load_verify_locations(ctx, root_certificate_path, root_certificate_dir)) <= 0)
        {
            printf("SSL_CTX_load_verify_locations return = %d %s\n", r, SSL_error_string());
            return r;
        }
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    }
    else
    {
        SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
    }
        return r;
}

inline
int ssl_set_certificate_resource(SSL_CTX* ctx, const char* certificate_path, const char* private_key_path, const char* private_key_passwd)
{
    int r;
    if((r = SSL_CTX_use_certificate_file(ctx, certificate_path, SSL_FILETYPE_PEM)) <= 0)
    {
        printf("SSL_CTX_use_certificate_file return = %d %s\n", r, SSL_error_string());
        return r;
    }
    SSL_CTX_set_default_passwd_cb_userdata(ctx, (void*)private_key_passwd);
    if((r = SSL_CTX_use_PrivateKey_file(ctx, private_key_path, SSL_FILETYPE_PEM)) <= 0)
    {
        printf("SSL_CTX_use_PrivateKey_file return = %d %s\n", r, SSL_error_string());
        return r;
    }

    if((r = SSL_CTX_check_private_key(ctx)) <= 0)
    {
        printf("SSL_CTX_check_private_key return = %d %s\n", r, SSL_error_string());
        return r;
    }
    SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
    SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
    return r;
}

server.cpp

//server.cpp
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include "ssl_common.h"

const unsigned short port = 10001;
const char* const certificate_path = "./server.crt";
const char* const private_key_path = "./server.key";
const char* const private_key_passwd = "123456";
const char* const ca_path = "./ca.crt";

const char* const ret_str = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";


int main(int argc, char* argv[])
{
    ssl_init_lib();

    const SSL_METHOD* method = TLSv1_2_method();
    SSL_CTX* ctx = NULL;
    SSL* ssl = NULL;

    int r = -1;
    int listen_socket = -1;
    int client_socket = -1;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    char buf[1024] = {0};
    int client_len = 0;

    do
    {
        ctx =  SSL_CTX_new(method);
        if(NULL == ctx)
        {
            printf("SSL_CTX_new return = NULL %s\n", SSL_error_string());
            break;
        }

        ssl_set_verify(ctx, NULL, NULL);
        ssl_set_certificate_resource(ctx, certificate_path, private_key_path, private_key_passwd);


        //listen
        listen_socket = socket(AF_INET, SOCK_STREAM, 0);
        if(listen_socket < 0)
        {
            printf("socket error = %d\n", errno);
            break;
        }
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(port);
        if(bind(listen_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
        {
            printf("bind error = %d\n", errno);
            break;
        }
        if(listen(listen_socket, 5) < 0)
        {
            printf("listen error = %d\n", errno);
            break;
        }

        while(1)
        {
            //socket accept
            client_len = sizeof(client_addr);
            socklen_t len = client_len;
            printf("start listen\n");
            client_socket = accept(listen_socket, (struct sockaddr*)&client_addr, &len);
            if(client_socket < 0)
            {
                printf("accept error = %d\n", errno);
                break;
            }


            //SSL accept
            ssl = ssl_new(ctx, client_socket);
            if((r = SSL_accept(ssl)) <= 0)
            {
                printf("SSL_accept return %d, %s\n", r, SSL_error_string());
                break;
            }


            //communication
            r = SSL_read(ssl, buf, sizeof(buf));
            if(r > 0)
            {
                printf("server recv text: %s\n", buf);
            }
            else
            {
                printf("SSL_read return %d, %s\n", r, SSL_error_string());
            }

            r = SSL_write(ssl, ret_str, strlen(ret_str));
            if(r <= 0)
            {
                printf("SSL_write return %d, %s\n", r, SSL_error_string());
            }


            //shutdown
            printf("close client socket\n");
            ssl_free(ssl);
            close(client_socket);
            client_socket = 0;
        }
    }while(0);

    printf("destroy resources\n");

    if(ssl)    {    SSL_free(ssl);    ssl = NULL;    }
    if(ctx)    {    SSL_CTX_free(ctx);    ctx = NULL;    }
    if(listen_socket > 0)   {   close(listen_socket);   listen_socket = 0;  }
    if(client_socket > 0)   {   close(client_socket);   client_socket = 0;  }

    printf("server done\n");

    return 0;
}

client.cpp

//client.cpp

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include "ssl_common.h"

const char* const host_addr = "127.0.0.1";
const unsigned short port = 10001;
const char* const ca_path = "./ca.crt";

#define VIRIFY_SERVER_CA 1

int main(int argc, char* argv[])
{
    ssl_init_lib();

    const SSL_METHOD* method = SSLv23_method();
    SSL_CTX* ctx = NULL;
    SSL* ssl = NULL;

    int r = -1;
    int remote_socket = -1;
    struct sockaddr_in remote_addr;
    X509* x509_cert = NULL;
    X509_NAME* x509_subject = NULL;
    X509_NAME* x509_issuer = NULL;
    char buf[1024] = {0};
    char subject[1024] = {0};
    char issuer[256] = {0};
    int client_len = 0;

    do
    {
        ctx =  SSL_CTX_new(method);
        if(NULL == ctx)
        {
            printf("SSL_CTX_new return = NULL %s\n", SSL_error_string());
            break;
        }
#if VIRIFY_SERVER_CA
        ssl_set_verify(ctx, ca_path, NULL);
#endif


        //socket connection
        remote_socket = socket(AF_INET, SOCK_STREAM, 0);
        if(remote_socket < 0)
        {
            printf("socket error = %d\n", errno);
            break;
        }
        memset(&remote_addr, 0, sizeof(remote_addr));
        remote_addr.sin_addr.s_addr = INADDR_ANY;
        remote_addr.sin_family = AF_INET;
        remote_addr.sin_port = htons(port);
        if(connect(remote_socket, (struct sockaddr*)&remote_addr, sizeof(remote_addr)) < 0)
        {
            printf("connect error = %d\n", errno);
            break;
        }

        {
            char ret_str[256] = {0};


            //SSL connection
            ssl = ssl_new(ctx, remote_socket);
            if((r = SSL_connect(ssl)) <= 0)
            {
                printf("SSL_connect return %d, %s\n", r, SSL_error_string());
                break;
            }


            //check cerificate by application (not SSL handshake)
            //not neccesary
#if VIRIFY_SERVER_CA
            if(X509_V_OK != (r = SSL_get_verify_result(ssl)))
            {
                printf("SSL_get_verify_result return %d, %s\n", r, SSL_error_string());
                break;
            }
            x509_cert = SSL_get_peer_certificate(ssl);
            if(x509_cert == NULL)
            {
                printf("SSL_get_peer_certificate return NULL, %s\n", SSL_error_string());
                break;
            }
            x509_subject = X509_get_subject_name(x509_cert);
            if(x509_subject == NULL)
            {
                printf("X509_get_subject_name return NULL, %s\n", SSL_error_string());
                break;
            }
            X509_NAME_oneline(x509_subject, subject, sizeof(subject)-1);

            x509_issuer = X509_get_issuer_name(x509_cert);
            if(x509_issuer == NULL)
            {
                printf("X509_get_issuer_name return NULL, %s\n", SSL_error_string());
                break;
            }
            X509_NAME_oneline(x509_issuer, issuer, sizeof(issuer)-1);
            X509_NAME_get_text_by_NID(x509_subject, NID_commonName, buf, sizeof(buf)-1);
            printf("subject =%s \nissuer =%s\n  commonName =%s\n",subject,issuer,buf);
#endif


            //communication
            strcpy(ret_str, "hello ssl");
            SSL_write(ssl, ret_str, strlen(ret_str));


            //shutdown
            ssl_free(ssl);
            close(remote_socket);
            remote_socket = 0;
        }
    }while(0);


    printf("destroy resources\n");
#if VIRIFY_SERVER_CA
    if(x509_cert)   {   X509_free(x509_cert);   x509_cert = NULL;   }
#endif

    if(ssl)    {    SSL_free(ssl);    ssl = NULL;    }
    if(ctx)    {    SSL_CTX_free(ctx);    ctx = NULL;    }
    if(remote_socket > 0)   {   close(remote_socket);   remote_socket = 0;  }

    printf("done\n");
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
set(project_name test)
project(${project_name})

SET(CMAKE_SKIP_BUILD_RPATH  TRUE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
SET(CMAKE_INSTALL_RPATH "./")
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(WIN32)
    set(SYS_LIBS ws2_32.lib CACHE INTERNAL "")
    set(SSL_LIBS openssl32.lib libcrypto.lib CACHE INTERNAL "")
    set(LIB_PARAM  CACHE INTERNAL "")
else()
    add_definitions(-std=c++11 -pipe -g -ggdb -fPIC)
    include_directories(/usr/include)
    set(SYS_LIBS pthread dl rt CACHE INTERNAL "")
    set(SSL_LIBS ssl crypto CACHE INTERNAL "")
    set(LIB_PARAM "-Wl," CACHE INTERNAL "")
endif()

add_executable(server  server.cpp)
target_link_libraries(server
    ${SSL_LIBS}
    ${SYS_LIBS}
)

add_executable(client client.cpp)
target_link_libraries(client
    ${SSL_LIBS}
    ${SYS_LIBS}
)

测试通过。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值