用OpenSSL写一个简单的Server/Client程序:证书与私钥

Table of Contents

1.生成服务器证书和私钥

生成证书和私钥

生成的证书和私钥长这样

2.服务端代码

3.客户端代码

4.编译

文件结构

CMakeLists.txt

编译

运行

参考


1.生成服务器证书和私钥

openssl req -newkey rsa:2048 -nodes -keyout serverKey.pem \
    -x509 -days 365 -out serverCert.cer \
    -subj "/C=CN/ST=GD/L=GZ/O=abc/OU=defg/CN=hijk/emailAddress=132456.com"

生成证书和私钥

$ openssl req -newkey rsa:2048 -nodes -keyout serverKey.pem \
>     -x509 -days 365 -out serverCert.cer \
>     -subj "/C=CN/ST=GD/L=GZ/O=abc/OU=defg/CN=hijk/emailAddress=132456.com"
Generating a RSA private key
.........+++++
...............................................+++++
writing new private key to 'serverKey.pem'
-----

生成的证书和私钥长这样

$ more serverCert.cer
-----BEGIN CERTIFICATE-----
MIIDvTCCAqWgAwIBAgIUeQ0DpTmzD9WraL0rItBuDM3zwyYwDQYJKoZIhvcNAQEL
BQAwbjELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQswCQYDVQQHDAJHWjEMMAoG
A1UECgwDYWJjMQ0wCwYDVQQLDARkZWZnMQ0wCwYDVQQDDARoaWprMRkwFwYJKoZI
hvcNAQkBFgoxMzI0NTYuY29tMB4XDTE5MDgxMTA3MjEzNVoXDTIwMDgxMDA3MjEz
NVowbjELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQswCQYDVQQHDAJHWjEMMAoG
A1UECgwDYWJjMQ0wCwYDVQQLDARkZWZnMQ0wCwYDVQQDDARoaWprMRkwFwYJKoZI
hvcNAQkBFgoxMzI0NTYuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAx8p1WVJcY9PXW/ytv60J15VuCs1YN5Va2e2ziRX8c82cjREYp9O/evQch3WZ
hUOEgERGPPwxAtk8lrcap7MAj1wVzgQGfNhvoPjt6PocWN+F9eduIpw+k0RxuPxS
3uZh1e308z7bOmFqCfb0iV94yLbIv1TvXoe8avr8gKmYOrVswvI8ccbkm5EENTKF
dQ+ggYifiUfevsn7Jk6RzPrZIvzqMuRIojkK3Fy/g+vBPhy53j8D92PHl3caX0uF
7Bw/se+lnANltLzT0EUevQpNZhzap9opxQNdGjzFxUe5tVOpXbHocsbvbrrSqHCq
19rWTyrSLSsucu0fjO/0287dVQIDAQABo1MwUTAdBgNVHQ4EFgQUO+GEl5OsSd2B
l6BYRAW/fUJHKEgwHwYDVR0jBBgwFoAUO+GEl5OsSd2Bl6BYRAW/fUJHKEgwDwYD
VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAGa+pIBJ7PDzpSl5SycOO
knmE8A2DmuS/bBy9D4qewPgwA2Td8MOY4Jg6/rDvHA82nm5KHc4n5IGNO0MAl1+K
PtB7RJDkfpf6n631bUdQAOUSQCIyT/agLNDuqz6cRgZ26UU5gC/2eFsFp1Xvtia4
EljfOvY8SdJR0s6siYcJZt9LN402rWsMPvdxgy1ySQTkbQsfOnXXpvxqKTo29Chj
/OE9FEyeEi0k7PqAIhiG0a0uV/3HJbXptHuQTqBjMHu0n+dIBrLzTLc0nx9r1mOY
JeLkH4mdpIMdNPDVB9iuwqr3sPohQWnZ72cowFExYuotLBIFZo5mja3ZASV+KUyf
HA==
-----END CERTIFICATE-----

$ more serverKey.pem
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHynVZUlxj09db
/K2/rQnXlW4KzVg3lVrZ7bOJFfxzzZyNERin07969ByHdZmFQ4SAREY8/DEC2TyW
txqnswCPXBXOBAZ82G+g+O3o+hxY34X1524inD6TRHG4/FLe5mHV7fTzPts6YWoJ
9vSJX3jItsi/VO9eh7xq+vyAqZg6tWzC8jxxxuSbkQQ1MoV1D6CBiJ+JR96+yfsm
TpHM+tki/Ooy5EiiOQrcXL+D68E+HLnePwP3Y8eXdxpfS4XsHD+x76WcA2W0vNPQ
RR69Ck1mHNqn2inFA10aPMXFR7m1U6ldsehyxu9uutKocKrX2tZPKtItKy5y7R+M
7/Tbzt1VAgMBAAECggEBALuuoDBpo2sP7UZ3hs0CA7XmpTo2jsGgZ3lDyB1mbwJm
S8NlJRE7ZKxfN5G00qQSuh04hfbyPiRb6IP4vGx/Rm5l5gHjXCjZtXu1fOEYW5rN
V+2aG6cdudbkPCS3vC2ypIOwBySejpk4O8HioPOPoUqEEu9SHY9i2YhyANPo/Z1f
eGZPEFv2UdqT+zoS9SjqlCcioYw0A18ebBBoDdzhNKnNo+2jchhSo8tmXY8nCeVw
hiZJandmQYjRsChLHRf8f3RH5GQjl5gbQMCqJtV7Rgpcr+9otaYvcrZUXztSWj0+
mLc6MepnO0vu7OfoVtJNI647VLtVAz5754+M3cqL3EECgYEA+GjYmUQ+SxfPGq6v
vHJZHB2lQeE4u1AFjdcgakFx3/693XvxOPbDGlms2fpeeqfTQrJljxCw2deHyBRE
0mHrizTkwDUmJGxAo7kJrsrgMwrzfyRLddfDQUZ0NMUX1ICF3z1PEq9u6+Bsexa9
Tii8sH1vBXzsnDp2CO3XNi65csUCgYEAzeVMYJJUcaziAHygRSNDtXIcMGY1Gsdm
e+jTVo7aXzvdF3zGS4lTu80H8EJZMJiybb3DQcsdUzSc+xITAgztDJbcA4DA2waZ
VVPs/qtrolXLYGlv4tkw2khKunnYcRcLVMhbcf4i1fkSO1CYNcgHnU7WXMJd8DPJ
XdqT+dzAKVECgYBqo2fIc/lh9zibNb6PYW9LmJZm766RCss3ltB9jNa71/nd6OUn
FRewaiq/8LE6am1QxpC+l+Wzvsi1Za4dupeJTQ2eTbKwFCCzqC218bXJc7wQKp6S
WiuiDAK63JlcSkguC320gcdWTyOCu8JMmURXZ6GPc4+Hibk+IAwxYGGQGQKBgQDG
m2WmTeCY2owSriSnLFIWx2C7qwuUrj2ETtz1RM0OSh+FlX1txaT4pdj/f/CquNB8
nSyo3XWHGlxGr3OYacGLgEXwNxVQ8TedIFyed9pWd+27LVmY96pxFITJBdmrlPAA
M1hKSDtwLVbR0ndQgYgezLpoNbEJj9qw5rQQtEjEUQKBgEO6sBnyV1u8DigkPfSJ
cvXwW4NIm9CO7A8OIfxb2daJhjFDjRdg+mQ16sL/jbKusRCQV4huPa1f82xSXIXj
uQxqUVmHNogP5IYtadxjjSBclxHmvhtEYOrHDhY86GeEfmt18FsTZdsafmF7gynl
hu8tyA2hJpK1yqgD5uVyRU/q
-----END PRIVATE KEY-----

2.服务端代码

/** 文件名: server.c */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define CERTSERVER "serverCert.cer"
#define KEYSERVER "serverKey.pem"

#define CHK_ERR(err, s) if((err) == -1) { perror(s); return -1; }
#define CHK_RV(rv, s) if((rv) != 1) { printf("%s error\n", s); return -1; }
#define CHK_NULL(x, s) if((x) == NULL) { printf("%s error\n", s); return -1; }
#define CHK_SSL(err, s) if((err) == -1) { ERR_print_errors_fp(stderr);  return -1;}

int main()
{
        int rv, err;
        SSL_CTX *ctx = NULL;
        const SSL_METHOD *meth = NULL;
        int listen_sd;
        int accept_sd;
        struct sockaddr_in socketAddrServer;
        struct sockaddr_in socketAddrClient;
        int socketAddrClientLen;
        SSL *ssl = NULL;
        char buf[4096];

        rv = SSL_library_init();
        CHK_RV(rv, "SSL_library_init");

        meth = TLS_server_method();
        ctx = SSL_CTX_new(meth);
        CHK_NULL(ctx, "SSL_CTX_new");

        rv = SSL_CTX_use_certificate_file(ctx, CERTSERVER, SSL_FILETYPE_PEM);
        CHK_RV(rv, "SSL_CTX_use_certicificate_file");

        rv = SSL_CTX_use_PrivateKey_file(ctx, KEYSERVER, SSL_FILETYPE_PEM);
        CHK_RV(rv, "SSL_CTX_use_PrivateKey_file");

        rv = SSL_CTX_check_private_key(ctx);
        CHK_RV(rv, "SSL_CTX_check_private_key");

        listen_sd = socket(AF_INET, SOCK_STREAM, 0);
        CHK_ERR(listen_sd, "socket");
        memset(&socketAddrServer, 0, sizeof(socketAddrServer));
        socketAddrServer.sin_family = AF_INET;
        socketAddrServer.sin_port = htons(8443);
        socketAddrServer.sin_addr.s_addr = INADDR_ANY;

        err = bind(listen_sd, (struct sockaddr *)&socketAddrServer, 
                    sizeof(socketAddrServer));
        CHK_ERR(err, "bind");
        err = listen(listen_sd, 5);
        CHK_ERR(err, "listen");

        socketAddrClientLen = sizeof(socketAddrClient);
        accept_sd = accept(listen_sd, (struct sockaddr *)&socketAddrClient, 
                            &socketAddrClientLen);
        CHK_ERR(accept_sd, "accept");
        close(listen_sd);
        printf("Connect to %s, port 0x%04X(=%d)\n", 
                inet_ntoa(socketAddrClient.sin_addr), 
                (int)ntohs(socketAddrClient.sin_port), 
                (int)ntohs(socketAddrClient.sin_port));

        ssl = SSL_new(ctx);
        CHK_NULL(ssl, "SSL_new");
        rv = SSL_set_fd(ssl, accept_sd);
        CHK_RV(rv, "SSL_set_fd");
        rv = SSL_accept(ssl);
        CHK_RV(rv, "SSL_accpet");

        rv = SSL_read(ssl, buf, sizeof(buf) - 1);
        CHK_SSL(rv, "SSL_read");
        buf[rv] = '\0';
        printf("Got %d chars :%s\n", rv, buf);
        rv = SSL_write(ssl, "I accept your request", strlen("I accept your request"));
        CHK_SSL(rv, "SSL_write");

        close(accept_sd);
        SSL_free(ssl);
        SSL_CTX_free(ctx);

        return 0;
}

3.客户端代码

/** 文件名: client.c */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define CHK_ERR(err, s) if((err) == -1) { perror(s); return -1; }
#define CHK_RV(rv, s) if((rv) != 1) { printf("%s error\n", s); return -1; }
#define CHK_NULL(x, s) if((x) == NULL) { printf("%s error\n", s); return -1; }
#define CHK_SSL(err, s) if((err) == -1) { ERR_print_errors_fp(stderr);  return -1;}

int main()
{
        int rv;
        int err;
        int client_fd;
        struct sockaddr_in socketAddrClient;
        const SSL_METHOD *meth = NULL;
        SSL_CTX *ctx = NULL;
        SSL *ssl = NULL;
        char buf[4096];

        rv = SSL_library_init();
        CHK_RV(rv, "SSL_library_init");

        meth = TLS_client_method();
        ctx = SSL_CTX_new(meth);
        CHK_NULL(ctx, "SSL_CTX_new");

        client_fd = socket(AF_INET, SOCK_STREAM, 0);
        CHK_ERR(client_fd, "socket");
        memset(&socketAddrClient, 0, sizeof(socketAddrClient));
        socketAddrClient.sin_family = AF_INET;
        socketAddrClient.sin_port = htons(8443);
        socketAddrClient.sin_addr.s_addr = inet_addr("127.0.0.1");

        err = connect(client_fd, (struct sockaddr *)&socketAddrClient, 
                        sizeof(socketAddrClient));
        CHK_ERR(err, "connect");
        ssl = SSL_new(ctx);
        CHK_NULL(ssl, "SSL_new");
        rv = SSL_set_fd(ssl, client_fd);
        CHK_RV(rv, "SSL_set_fd");
        rv = SSL_connect(ssl);
        CHK_RV(rv, "SSL_connect");

        rv = SSL_write(ssl, "Hello, I am the client", strlen("Hello, I am the client"));
        CHK_SSL(rv, "SSL_write");
        rv = SSL_read(ssl, buf, sizeof(buf) - 1);
        CHK_SSL(rv, "SSL_read");
        buf[rv] = '\0';
        printf("Got %d chars :%s\n", rv, buf);

        SSL_shutdown(ssl);
        close(client_fd);
        SSL_free(ssl);
        SSL_CTX_free(ctx);

        return 0;
}

4.编译

文件结构

$ tree -d
.
└── src
    ├── client
    └── server

CMakeLists.txt

cmake_minimum_required(VERSION 3.1)
project(demo1 LANGUAGES C)

aux_source_directory(./src/client client_SOURCES)
aux_source_directory(./src/server server_SOURCES)
add_executable(client ${client_SOURCES})
add_executable(server ${server_SOURCES})
set_property(TARGET client PROPERTY C_STANDARD 11)
set_property(TARGET server PROPERTY C_STANDARD 11)

find_package(OpenSSL REQUIRED)
target_include_directories(client PRIVATE ${OPENSSL_INCLUDE_DIR})
target_include_directories(server PRIVATE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(client PRIVATE
  ${OPENSSL_LIBRARIES}
)
target_link_libraries(server PRIVATE
  ${OPENSSL_LIBRARIES}
)

编译

$ cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/Toa/openssl-demo-work20190606/ssl-demo

$ make
[ 25%] Building C object CMakeFiles/client.dir/src/client/client.c.o
[ 50%] Linking C executable client.exe
[ 50%] Built target client
[ 75%] Building C object CMakeFiles/server.dir/src/server/server.c.o
[100%] Linking C executable server.exe
[100%] Built target server

运行

窗口1:
$ ./server.exe
Connect to 127.0.0.1, port 0xD106(=53510)
Got 22 chars :Hello, I am the client


窗口2:
$ ./client.exe
Got 21 chars :I accept your request

参考

博文:https://blog.csdn.net/oj847935591/article/details/79362542

源码地址:https://github.com/liuqun/openssl-demo

感谢GitHub序友:liuqun

 

你可能感兴趣的:(计算机网络)