通过openssl命令来建立一个SSL测试环境
环境背景:Ubuntu 16.04.1 & OpenSSL-1.0.2g
1. 在openssl安装目录/usr/lib/ssl/的misc目录下,运行脚本 ./CA.sh –newca
随后会生成一个demonCA的目录,里面包含了ca证书及其私钥。
2. 生成客户端和服务端证书申请
$ openssl req -newkey rsa:1024 -out req1.pem -keyout sslclientkey.pem
$ openssl req -newkey rsa:1024 -out req2.pem -keyout sslserverkey.pem
3. 签发客户端和服务端证书
$ openssl ca -in req1.pem -out sslclientcert.pem
$ openssl ca -in req2.pem -out sslservercert.pem
4. 运行ssl 服务端
$ openssl s_server -cert sslservercert.pem -key sslserverkey.pem -CAfile demoCA/cacert.pem
Enter pass phrase for sslserverkey.pem:
Using default temp DH parameters
ACCEPT
-----BEGIN SSL SESSION PARAMETERS-----
MFUCAQECAgMDBALAMAQABDBZ6RLUgd5qBfj3oeCfRzD/1sdK9aQcpbmvFVRLBJ66
roEscQm1tHBUOrYWX9UYjNehBgIEX/U+rqIEAgIBLKQGBAQBAAAA
-----END SSL SESSION PARAMETERS-----
Shared ciphers:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA
Signature Algorithms: RSA+SHA512:DSA+SHA512:ECDSA+SHA512:RSA+SHA384:DSA+SHA384:ECDSA+SHA384:RSA+SHA256:DSA+SHA256:ECDSA+SHA256:RSA+SHA224:DSA+SHA224:ECDSA+SHA224:RSA+SHA1:DSA+SHA1:ECDSA+SHA1
Shared Signature Algorithms: RSA+SHA512:DSA+SHA512:ECDSA+SHA512:RSA+SHA384:DSA+SHA384:ECDSA+SHA384:RSA+SHA256:DSA+SHA256:ECDSA+SHA256:RSA+SHA224:DSA+SHA224:ECDSA+SHA224:RSA+SHA1:DSA+SHA1:ECDSA+SHA1
Supported Elliptic Curve Point Formats: uncompressed:ansiX962_compressed_prime:ansiX962_compressed_char2
Supported Elliptic Curves: P-256:P-521:brainpoolP512r1:brainpoolP384r1:P-384:brainpoolP256r1:secp256k1:B-571:K-571:K-409:B-409:K-283:B-283
Shared Elliptic curves: P-256:P-521:brainpoolP512r1:brainpoolP384r1:P-384:brainpoolP256r1:secp256k1:B-571:K-571:K-409:B-409:K-283:B-283
CIPHER is ECDHE-RSA-AES256-GCM-SHA384
Secure Renegotiation IS supported
5. 运行客户端
$ openssl s_client -CAfile demoCA/cacert.pem
CONNECTED(00000003)
depth=1 C = CN, ST = JiangSu, O = Tech, OU = Software Development, CN = wq, emailAddress = wq897387@126.com
verify return:1
depth=0 C = CN, ST = JiangSu, O = Tech, OU = Software Development, CN = wq, emailAddress = wq897387@126.com
verify return:1
---
Certificate chain
0 s:/C=CN/ST=JiangSu/O=Tech/OU=Software Development/CN=wq/emailAddress=wq897387@126.com
i:/C=CN/ST=JiangSu/O=Tech/OU=Software Development/CN=wq/emailAddress=wq897387@126.com
1 s:/C=CN/ST=JiangSu/O=Tech/OU=Software Development/CN=wq/emailAddress=wq897387@126.com
i:/C=CN/ST=JiangSu/O=Tech/OU=Software Development/CN=wq/emailAddress=wq897387@126.com
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDdjCCAl6gAwIBAgIJAMW4y04XPrUDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
BAYTAkNOMRAwDgYDVQQIDAdKaWFuZ1N1MQ0wCwYDVQQKDARUZWNoMR0wGwYDVQQL
DBRTb2Z0d2FyZSBEZXZlbG9wbWVudDELMAkGA1UEAwwCd3ExIjAgBgkqhkiG9w0B
CQEWE3dxODk3Mzg3NjNAeWVhaC5uZXQwHhcNMjEwMTA2MDQzMDEyWhcNMjIwMTA2
MDQzMDEyWjB+MQswCQYDVQQGEwJDTjEQMA4GA1UECAwHSmlhbmdTdTENMAsGA1UE
CgwEVGVjaDEdMBsGA1UECwwUU29mdHdhcmUgRGV2ZWxvcG1lbnQxCzAJBgNVBAMM
AndxMSIwIAYJKoZIhvcNAQkBFhN3cTg5NzM4NzYzQHllYWgubmV0MIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQDAO8Y56uwwL1FQtNGvfLJhaAp5898SWaenYOAl
w906uY6gLEZQ2+PbndPSOwHxrTH4tOYdAdan7dXHA0V5a2w20qn9zn5RbyXpX/Cp
eVaRmI8rgq3kafPTeQMoCXfcaKjydy+oywlDPkbS7q1h5iOTVHsEJLKIg46oaJLl
gLFOswIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM
IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU2QySKT5mNzgFVk2cOxk6
JdDBIIgwHwYDVR0jBBgwFoAUozwxNsifkC4u51ET6KQpuht1z8AwDQYJKoZIhvcN
AQELBQADggEBAK70RFqguCwO7ebmiI2pFWvrbilm2LHBsFPWXedOKWJ1l84OVGOO
FGrAmG69Kd1BFpMk/16a9EHwecbS+5CcfqxdtKWvWXpvpq1oVlqcxcJxXu7bqR5v
v9MONZj0LFfo30JUXMjJ8Nq0NiAHMi8PEXhGXgYtWBWKHbPpS+k/bs+fW1V6zUl6
/xFbgw8/c6UsPdDpQtMrmwZqmbQULqObEBB0tU7ggisdYfIFZ3dfLvw2sB+oDmGt
pzdDtjzPCSqOkT4S1/twgu8sYAx7EXKM0UkrATDp6Is1nuQNzcV8TmC53hMapP52
1fd0JOu6IXBbIFtXZ1x7vjkit1g+u2cTT3g=
-----END CERTIFICATE-----
subject=/C=CN/ST=JiangSu/O=Tech/OU=Software Development/CN=wq/emailAddress=wq897387@126.com
issuer=/C=CN/ST=JiangSu/O=Tech/OU=Software Development/CN=wq/emailAddress=wq897387@126.com
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 2403 bytes and written 391 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 131EC22EF3270199458720A32F7C626FD9C177EDEBABD4D2CBFC38A69A0A536A
Session-ID-ctx:
Master-Key: 59E912D481DE6A05F8F7A1E09F4730FFD6C74AF5A41CA5B9AF15544B049EBAAE812C7109B5B470543AB6165FD5188CD7
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 49 f5 d2 ed 95 0b 9b c7-a9 1e 5d ab bc 54 2c 4e I.........]..T,N
0010 - 13 68 d9 60 92 57 f8 0d-cd f6 75 f7 67 a3 21 27 .h.`.W....u.g.!'
0020 - cb 5b ed c1 db 11 17 dd-99 fb 57 b3 ff 83 64 f7 .[........W...d.
0030 - 18 31 89 9a 99 5c 6c f6-1e 87 2e 03 ec b9 50 cb .1...\l.......P.
0040 - fe 1e 7a fb 95 86 ab 8c-f4 c6 a2 84 77 70 d4 76 ..z.........wp.v
0050 - ec f0 f8 48 a3 c5 29 7c-d6 4b 7d 67 8e a8 01 46 ...H..)|.K}g...F
0060 - 17 01 fd f4 b3 b6 11 28-05 3e b8 dd aa 25 a7 f8 .......(.>...%..
0070 - 47 05 96 c1 1f 18 e7 8b-a9 81 ca dd e2 2e f4 8d G...............
0080 - 25 9e e5 be a9 ed 61 2b-0a d4 61 50 92 ff fe b9 %.....a+..aP....
0090 - 1d bb 42 09 7f ce be 65-f1 73 16 72 a3 07 4a cf ..B....e.s.r..J.
Start Time: 1609907886
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
通过openssl编程接口建立一个SSL测试环境
Server端
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <linux/in.h>
#include <errno.h>
#include <openssl/ssl.h>
int err;
#define CERTF "certs/sslservercert.pem"
#define KEYF "certs/sslserverkey.pem"
#define CAFILE "certs/cacert.pem"
int verify_callback_server(int ok, X509_STORE_CTX *ctx)
{
printf("verify_callback_server.\n");
return ok;
}
int SSL_CTX_use_PrivateKey_file_pass(SSL_CTX *ctx, char *filename, char *pass)
{
EVP_PKEY *pkey = NULL;
BIO *key = NULL;
key = BIO_new(BIO_s_file());
BIO_read_filename(key, filename);
pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, pass);
if (pkey==NULL)
{
printf("PEM_read_bio_PrivateKey failed");
return -1;
}
if (SSL_CTX_use_PrivateKey(ctx, pkey)<=0)
{
printf("SSL_CTX_use_PrivateKey err.\n");
return -1;
}
BIO_free(key);
return 1;
}
int main()
{
int ret;
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
const SSL_METHOD *meth = SSLv3_server_method();
SSL_CTX *ctx = SSL_CTX_new(meth);
if (!ctx)
{
printf("SSL_CTX_new failed. ctx=%d\n", ctx);
return -1;
}
if ((!SSL_CTX_load_verify_locations(ctx, CAFILE, NULL))||(!SSL_CTX_set_default_verify_paths(ctx)))
{
printf("error.\n");
return -1;
}
if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM)<=0)
{
printf("SSL_CTX_use_certificate_file failed.\n");
return -1;
}
if (SSL_CTX_use_PrivateKey_file_pass(ctx,KEYF,NULL)<=0)
{
printf("SSL_CTX_use_PrivateKey_file_pass failed.\n");
return -1;
}
if (!SSL_CTX_check_private_key(ctx))
{
printf("SSL_CTX_check_private_key failed.\n");
return -1;
}
int s_server_verify = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_CLIENT_ONCE;
SSL_CTX_set_verify(ctx, s_server_verify, verify_callback_server);
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAFILE));
int s_handle = socket(AF_INET, SOCK_STREAM, 6);
if (s_handle<0)
{
printf("create socket failed.\n");
return -1;
}
struct sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("192.168.44.99");
service.sin_port = htons(1111);
if (bind(s_handle, (const struct sockaddr *)&service, sizeof(service))==-1)
{
printf("bind failed.\n");
close(s_handle);
return -1;
}
if (listen(s_handle, 1)==-1)
{
printf("listen failed.\n");
return -1;
}
while(1)
{
int session_socket = accept(s_handle, NULL, NULL);
if(session_socket < 0)
{
printf("accept failed.\n");
return -1;
}
SSL *ssl = SSL_new(ctx);
err = SSL_set_fd(ssl, session_socket);
if (err < 0)
{
printf("SSL_set_fd failed.\n");
return -1;
}
err = SSL_accept(ssl);
if (err < 0)
{
printf("SSL_accept failed. errstr=%s\n", SSL_state_string_long(ssl));
return -1;
}
printf("SSL_connection using %s\n", SSL_get_cipher(ssl));
X509 *client_cert = SSL_get_peer_certificate(ssl);
if (client_cert != NULL)
{
printf("client cerificate:\n");
char *str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
if (str&&(*str))
printf("\tsubject:%s\n", str);
OPENSSL_free(str);
str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
if(str&&(*str))
printf("\t issuer:%s\n", str);
OPENSSL_free(str);
X509_free(client_cert);
}else
printf("Client does not have certificate.\n");
const char *cipher_name = SSL_get_cipher_name(ssl);
if (cipher_name && *cipher_name)
{
printf("SSL_get_cipher_name %s.\n", cipher_name);
return -1;
}
char buf[1024];
memset(buf, 0, 1024);
err = SSL_read(ssl, buf, sizeof(buf)-1);
if (err<0)
{
printf("SSL_read failed.\n");
close(ssl);
return err;
}
printf("get: %s\n", buf);
SSL_free(ssl);
close(s_handle);
}
SSL_CTX_free(ctx);
return 0;
}
Client端
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define MAX_T 1000
#define CLIENTCERT "certs/sslclientcert.pem"
#define CLIENTKEY "certs/sslclientkey.pem"
#define CAFILE "certs/cacert.pem"
int verify_callback(int ok, X509_STORE_CTX *ctx)
{
printf("verify_callback.\n");
return ok;
}
int SSL_CTX_use_PrivateKey_file_pass(SSL_CTX *ctx, char *filename, char *pass)
{
EVP_PKEY *pkey = NULL;
BIO *key = NULL;
key = BIO_new(BIO_s_file());
BIO_read_filename(key, filename);
pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, pass);
if (pkey==NULL)
{
printf("PEM_read_bio_PrivateKey failed");
return -1;
}
if (SSL_CTX_use_PrivateKey(ctx, pkey)<=0)
{
printf("SSL_CTX_use_PrivateKey err.\n");
return -1;
}
BIO_free(key);
return 1;
}
int main()
{
int ret;
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
const SSL_METHOD *meth = SSLv3_client_method();
SSL_CTX *ctx = SSL_CTX_new(meth);
if (!ctx)
{
printf("SSL_CTX_new failed.\n");
return -1;
}
if (SSL_CTX_use_certificate_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM)<=0)
{
printf("SSL_CTX_use_certificate failed.\n");
return -1;
}
if (SSL_CTX_use_PrivateKey_file_pass(ctx, CLIENTKEY, NULL)<=0)
{
printf("SSL_CTX_use_PrivateKey_file_pass failed.\n");
return -1;
}
int s_handle = socket(AF_INET, SOCK_STREAM, 0);
if (s_handle <= 0)
{
printf("create socket handle failed.\n");
return -1;
}
struct sockaddr_in dest_sin;
dest_sin.sin_family = AF_INET;
dest_sin.sin_addr.s_addr = inet_addr("192.168.44.99");
dest_sin.sin_port = htons(1111);
ret = connect(s_handle, (struct sockaddr *)&dest_sin, sizeof(dest_sin));
if (ret < 0)
{
printf("connect failed.\n");
return -1;
}
SSL *ssl = SSL_new(ctx);
if (ssl==NULL)
{
printf("SSL_new failed.\n");
return -1;
}
SSL_set_fd(ssl, s_handle);
ret = SSL_connect(ssl);
if (ret<0)
{
printf("SSL_connect failed.\n");
return -1;
}
printf("SSL_ connection using %s\n", SSL_get_cipher(ssl));
X509 * server_cert = SSL_get_peer_certificate(ssl);
printf("Server certificate:");
char *str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
printf("\t subject: %s\n", str);
OPENSSL_free(str);
str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0);
printf("\tissuer:%s\n",str);
OPENSSL_free(str);
X509_free(server_cert);
ret = SSL_write(ssl, "Hello World!",strlen("Hello World!"));
if (ret<0)
{
printf("SSL_Write failed.\n");
return ret;
}
SSL_CTX_free(ctx);
return 0;
}
Makefile
all: ssl_server ssl_client
ssl_server:
gcc -g ssl_server.c libssl.a libcrypto.a -o ssl_server -ldl
ssl_client:
gcc -g ssl_client.c libssl.a libcrypto.a -o ssl_client -ldl
clean:
rm ssl_server ssl_client
在当前目录创建certs文件夹,塞入如下证书
cacert.pem sslclientcert.pem sslclientkey.pem sslservercert.pem sslserverkey.pem