使用openssl API编写client和server
来源:互联网 发布:mysql大神博客 编辑:程序博客网 时间:2024/05/21 19:33
使用openssl api编写的client程序和server程序,其中第一个client采用了BIO的方式,第二个client采用了ssl接口,第一个server程序基本没有使用BIO方式,第二个server程序绝大部分使用了BIO的方式。(server和client程序只是为了展示openssl api的使用,没有涉及到多进程及多线程,没有考虑程序的性能问题。对于openssl api的学习了解是一个任重而道远的过程,需要慢慢积累,积少成多,看完文档要多去实践。)
程序清单:
makefile
client.c
server.c (两个server不能同时编译)
makefile代码如下:
[cpp] view plain copy
- #gcc -o client client.c -I/openssl_gx/include -L/openssl_gx/lib -lssl -lcrypto -ldl
- #gcc -o server serv.c -I/openssl_gx/include -L/openssl_gx/lib -lssl -lcrypto -ldl
- CC = gcc
- INCLUDE = -I/openssl_gx/include
- LIBPATH = -L/openssl_gx/lib
- LIB = -lssl -lcrypto -ldl
- client:
- $(CC) -o client client.c $(INCLUDE) $(LIBPATH) $(LIB)
- server:
- $(CC) -o server server.c $(INCLUDE) $(LIBPATH) $(LIB)
- all: client server
- clean:
- rm -f client
- rm -f server
client.c代码如下:
[cpp] view plain copy
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <openssl/ssl.h>
- #include <openssl/bio.h>
- #include <openssl/err.h>
- int main() {
- int iResult = 0;
- BIO * bio = NULL;
- SSL * ssl = NULL;
- SSL_CTX * ctx = NULL;
- X509 * pX509 = NULL;
- const SSL_METHOD * sslMethod = NULL;
- char commonName[512] = { 0 };
- X509_NAME * pX509_NAME = NULL;
- char szClientMsg[] = "I am guoxu.\n";
- unsigned int uiRecBytes = 0;
- unsigned char baRecBuffer[1024];
- unsigned char * pbRecFinish = NULL;
- unsigned char * pbRecBak = NULL;
- unsigned int uiRecBakLen = 0;
- char * pMsgline = NULL;
- SSL_library_init();
- ERR_load_BIO_strings();
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
- do {
- sslMethod = TLSv1_client_method(); /* Load ssl method. */
- if(NULL == sslMethod) {
- printf("TLSv1_client_method err: %s\n",ERR_error_string(ERR_get_error(),NULL));
- iResult = -1;
- break;
- }
- ctx = SSL_CTX_new(sslMethod); /* Create a new ssl context. */
- if( NULL == ctx) {
- printf("SSL_CTX_new err: %s\n",ERR_error_string(ERR_get_error(),NULL));
- iResult = -2;
- break;
- }
- if(0 == SSL_CTX_load_verify_locations(ctx,"/openssl_gx/cers/ca.crt",NULL)) { /* Load CA certification. */
- printf("SSL_CTX_load_verify_locations err:%s\n",
- ERR_error_string(ERR_get_error(),
- NULL));
- iResult = -3;
- break;
- }
- if(0 == SSL_CTX_use_certificate_file(ctx, "/openssl_gx/cers/client.crt", /* Load client certification file. */
- SSL_FILETYPE_PEM)) {
- printf("SSL_CTX_use_certificate_file err: %s\n",
- ERR_error_string(ERR_get_error(),NULL));
- iResult = -4;
- break;
- }
- if(0 == SSL_CTX_use_PrivateKey_file(ctx,"/openssl_gx/cers/client.key", /* Load client private key. */
- SSL_FILETYPE_PEM)) {
- iResult = -5;
- break;
- }
- if(0 == SSL_CTX_check_private_key(ctx)) { /* Check whether the private key match with the certification file. */
- printf("SSL_CTX_check_private_key err: %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- iResult = -6;
- break;
- }
- bio = BIO_new_ssl_connect(ctx);
- if(NULL == bio) {
- printf("BIO_new_ssl_connect err: %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- iResult = -7;
- break;
- }
- BIO_get_ssl(bio, &ssl);
- SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
- BIO_set_conn_hostname(bio, "127.0.0.1:443");
- if(0 >= BIO_do_connect(bio)){ /* Create a socket connection and then ssl handshake.*/
- printf("BIO_do_connect err: %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- iResult = -8;
- break;
- }
- if(X509_V_OK != SSL_get_verify_result(ssl)) { /* Check whether the ssl connection is created successfully. */
- printf("SSL_get_verify_result err: %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- iResult = -9;
- break;
- }
- pX509 = SSL_get_peer_certificate(ssl); /* Get the server certification. */
- if(NULL == pX509) {
- printf("SSL_get_peer_certificate err: %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- iResult = -10;
- break;
- }
- pX509_NAME = X509_get_subject_name(pX509);
- if(NULL == pX509_NAME) {
- printf("X509_get_subject_name err: %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- iResult = -10;
- break;
- }
- X509_NAME_get_text_by_NID(pX509_NAME, NID_commonName,commonName,512);
- if(0 != strcasecmp(commonName,"guoxu")) {
- printf("Certificate`s name guoxu != %s\n",commonName);
- iResult = -11;
- break;
- }
- if(0 >= BIO_write(bio,szClientMsg, strlen(szClientMsg))) { /* Send message to the server. */
- printf("Send a string to server failed.\n");
- iResult = -12;
- break;
- }
- } while(0);
- /* Close the ssl connection and clear the context. */
- if(NULL != bio) {
- BIO_free_all(bio);
- }
- if(NULL != ctx) {
- SSL_CTX_free(ctx);
- }
- return iResult;
- }
使用ssl接口的client程序:
[cpp] view plain copy
- #include <stdio.h>
- #include <stdlib.h>
- #include <memory.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <openssl/rsa.h>
- #include <openssl/crypto.h>
- #include <openssl/x509.h>
- #include <openssl/pem.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
- #define MAXDATASIZE 1024
- #define SERVERIP "127.0.0.1"
- #define SERVERPORT 443
- /* Make these what you want for cert & key files */
- #define CERTF "/openssl_gx/cers/client.crt"
- #define KEYF "/openssl_gx/cers/client.key"
- #define CHK_NULL(x) if ((x)==NULL) exit (1)
- #define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
- #define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }
- int main(void) {
- char buf[MAXDATASIZE];
- int sockfd, numbytes;
- struct sockaddr_in server_addr;
- const SSL_METHOD *meth;
- int err;
- SSL_CTX* ctx;
- SSL* ssl;
- if((sockfd = socket(AF_INET, SOCK_STREAM,0)) == -1) {
- perror("Socket error.\n");
- return 1;
- }
- memset(&server_addr, 0, sizeof(struct sockaddr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(SERVERPORT);
- server_addr.sin_addr.s_addr = inet_addr(SERVERIP);
- if(connect(sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1) {
- perror("connect error.\n");
- return 1;
- }
- printf("Connected %d\n", sockfd);
- SSL_library_init();
- SSL_load_error_strings();
- SSLeay_add_ssl_algorithms();
- meth = TLSv1_client_method(); /* Add ssl method. */
- if(NULL == meth) {
- printf("TLSv1_client_method err: %s\n",ERR_error_string(ERR_get_error(),NULL));
- exit(-1);
- }
- ctx = SSL_CTX_new (meth); /* Create a new ssl context. */
- if (!ctx) {
- ERR_print_errors_fp(stderr);
- exit(2);
- }
- printf("111\n");
- if(0 == SSL_CTX_load_verify_locations(ctx,"/openssl_gx/cers/ca.crt",NULL)) { /* Load CA certification file. */
- ERR_print_errors_fp(stderr);
- exit(15);
- }
- printf("222\n");
- if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) { /* Load server certification file. */
- ERR_print_errors_fp(stderr);
- exit(3);
- }
- printf("333\n");
- if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) { /* Load server private key file. */
- ERR_print_errors_fp(stderr);
- exit(4);
- }
- printf("444\n");
- if (!SSL_CTX_check_private_key(ctx)) { /* Check whether the private key match with the certification file. */
- fprintf(stderr,"Private key does not match the certificate public key\n");
- exit(5);
- }
- printf("555\n");
- /* TCP connection is ready. Do server side SSL. */
- ssl = SSL_new (ctx);
- CHK_NULL(ssl);
- SSL_set_fd (ssl, sockfd);
- err = SSL_connect (ssl);
- CHK_SSL(err);
- printf("SSL connect OK.\n");
- err = SSL_write(ssl,"I am guoxu.\n",strlen("I am guoxu.\n"));
- CHK_SSL(err);
- SSL_free(ssl);
- close(sockfd);
- SSL_CTX_free(ctx);
- return 0;
- }
没有全部使用BIO的server.c代码如下:
[cpp] view plain copy
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <memory.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <openssl/rsa.h> /* SSLeay stuff */
- #include <openssl/crypto.h>
- #include <openssl/x509.h>
- #include <openssl/pem.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
- /* Make these what you want for cert & key files */
- #define CERTF "/openssl_gx/cers/server.crt"
- #define KEYF "/openssl_gx/cers/server.key"
- #define CHK_NULL(x) if ((x)==NULL) exit (1)
- #define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
- #define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }
- static int s_server_verify = SSL_VERIFY_NONE;
- int verify_callback_server(int ok, X509_STORE_CTX * ctx) {
- printf("verify_callback_server.\n");
- return ok;
- }
- void main ()
- {
- int err;
- int listen_sd;
- int sd;
- struct sockaddr_in sa_serv;
- struct sockaddr_in sa_cli;
- size_t client_len;
- SSL_CTX* ctx;
- SSL* ssl;
- X509* client_cert;
- char* str;
- char buf [4096];
- const SSL_METHOD *meth;
- SSL_load_error_strings();
- SSLeay_add_ssl_algorithms();
- meth = TLSv1_server_method(); /* Add ssl method. */
- ctx = SSL_CTX_new (meth); /* Create a new ssl context. */
- if (!ctx) {
- ERR_print_errors_fp(stderr);
- exit(2);
- }
- if(0 == SSL_CTX_load_verify_locations(ctx,"/openssl_gx/cers/ca.crt",NULL)) { /* Load CA certification file. */
- ERR_print_errors_fp(stderr);
- exit(15);
- }
- if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) { /* Load server certification file. */
- ERR_print_errors_fp(stderr);
- exit(3);
- }
- if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) { /* Load server private key file. */
- ERR_print_errors_fp(stderr);
- exit(4);
- }
- if (!SSL_CTX_check_private_key(ctx)) { /* Check whether the private key match with the certification file. */
- fprintf(stderr,"Private key does not match the certificate public key\n");
- exit(5);
- }
- /* Indicate that the server need verify the client certification file. */
- 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);
- /* Prepare TCP socket for receiving connections */
- listen_sd = socket (AF_INET, SOCK_STREAM, 0);
- CHK_ERR(listen_sd, "socket");
- memset (&sa_serv, '\0', sizeof(sa_serv));
- sa_serv.sin_family = AF_INET;
- sa_serv.sin_addr.s_addr = INADDR_ANY;
- sa_serv.sin_port = htons (443); /* Server Port number */
- /* Server listening port should set to 443, if not the wireshark can not show the
- ssl communication. */
- err = bind(listen_sd, (struct sockaddr*) &sa_serv, sizeof (sa_serv));
- CHK_ERR(err, "bind");
- /* Receive a TCP connection. */
- err = listen (listen_sd, 5);
- CHK_ERR(err, "listen");
- client_len = sizeof(sa_cli);
- sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len);
- CHK_ERR(sd, "accept");
- close (listen_sd);
- printf ("Connection from %lx, port %x\n",
- sa_cli.sin_addr.s_addr, sa_cli.sin_port);
- /* TCP connection is ready. Do server side SSL. */
- ssl = SSL_new (ctx);
- CHK_NULL(ssl);
- SSL_set_fd (ssl, sd);
- err = SSL_accept (ssl);
- CHK_SSL(err);
- /* Get the cipher - opt */
- printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
- /* Get client's certificate (note: beware of dynamic allocation) - opt */
- client_cert = SSL_get_peer_certificate (ssl);
- if (client_cert != NULL) {
- printf ("Client certificate:\n");
- str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
- CHK_NULL(str);
- printf ("\t subject: %s\n", str);
- OPENSSL_free (str);
- str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
- CHK_NULL(str);
- printf ("\t issuer: %s\n", str);
- OPENSSL_free (str);
- /* We could do all sorts of certificate verification stuff here before
- deallocating the certificate. */
- X509_free (client_cert);
- } else {
- printf ("Client does not have certificate.\n");
- }
- /* DATA EXCHANGE - Receive message and send reply. */
- err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err);
- buf[err] = '\0';
- printf ("Got %d chars:'%s'\n", err, buf);
- //err = SSL_write (ssl, "I hear you.", strlen("I hear you.")); CHK_SSL(err);
- /* Clean up. */
- close (sd);
- SSL_free (ssl);
- SSL_CTX_free (ctx);
- }
尽力使用BIO的server.c代码如下:
[cpp] view plain copy
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <memory.h>
- #include <errno.h>
- #include <openssl/bio.h>
- #include <openssl/ssl.h>
- #include <openssl/crypto.h>
- #define ERR_OK 0
- #define ERR_HAPPENED 1
- #define TRACE_ENABLED 1
- #define TRACE0(x) printf(x)
- SSL_CTX *ctx;
- BIO * sbio, * bbio, * acpt, * out;
- SSL * ssl;
- int main ()
- {
- char tmpbuf[1024];
- ERR_load_crypto_strings(); //registers the error strings for all libcrypto functions.
- ERR_load_SSL_strings(); //registers the error strings for libssl functions.
- OpenSSL_add_ssl_algorithms(); //same as SSLeay_add_ssl_algorithms();
- ctx = SSL_CTX_new(TLSv1_server_method()); //Create a ssl context.
- if(ctx == NULL) { //Must check NULL here.
- ERR_print_errors_fp(stderr);
- return ERR_HAPPENED;
- }
- if(!SSL_CTX_use_certificate_file(ctx,"/openssl_gx/cers/server.crt",SSL_FILETYPE_PEM)) {
- //ERR_print_errors_fp(stderr);
- return ERR_HAPPENED;
- } else {
- TRACE0("====> Step 1 : Load server certificate file done.\n");
- }
- if(!SSL_CTX_use_PrivateKey_file(ctx,"/openssl_gx/cers/server.key",SSL_FILETYPE_PEM)) {
- ERR_print_errors_fp(stderr);
- return ERR_HAPPENED;
- } else {
- TRACE0("====> Step 2: Load server private key done.\n");
- }
- if(!SSL_CTX_check_private_key(ctx)) {
- ERR_print_errors_fp(stderr);
- return ERR_HAPPENED;
- } else {
- TRACE0("====> Step 3: Check server private key done.\n");
- }
- sbio = BIO_new_ssl(ctx,0); //0: Run as server; non-0: Run as client.
- BIO_get_ssl(sbio, &ssl); //Retrieves the SSL pointer of BIO sbio, it can then be manipulated using the standard SSL library functions.
- if(!ssl) {
- printf("SSL pointer is NULL.\n");
- return ERR_HAPPENED;
- }
- SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); //SSL_MODE_AUTO_RETRY will cause read/write operations to only return after the handshake and successful completion.
- bbio = BIO_new(BIO_f_buffer()); //BIO_f_buffer() returns the buffering BIO method.
- //The BIO_new() function returns a new BIO using method type.
- // Add to the chain.
- sbio = BIO_push(bbio,sbio); //Data writing to bbio will be dealed with sbio.
- acpt = BIO_new_accept("443"); //Create a new accept bio.
- /*BIO_set_accept_bios() can be used to set a chain of BIOs which will be duplicated and
- prepended to the chain when an incoming connection is received.
- This is useful if, for example, a buffering or SSL BIO is required for each connection.
- The chain of BIOs must not be freed after this call,
- they will be automatically freed when the accept BIO is freed.*/
- BIO_set_accept_bios(acpt,sbio); //append sbio to acpt.
- out = BIO_new_fp(stdout,BIO_NOCLOSE);
- /*BIO_do_accept() serves two functions.
- When it is first called, after the accept BIO has been setup,
- it will attempt to create the accept socket and bind an address to it.
- Second and subsequent calls to BIO_do_accept() will await an incoming connection,
- or request a retry in non blocking mode. */
- /* The first BIO_do_accept() setup the accept BIO. */
- if(BIO_do_accept(acpt) <= 0) {
- ERR_print_errors_fp(stderr);
- return ERR_HAPPENED;
- }
- TRACE0("====>Step 4: Waiting for the incoming connection...\n");
- /* The second BIO_do_accept() wait for the incoming connection. */
- if(BIO_do_accept(acpt) <= 0) {
- ERR_print_errors_fp(stderr);
- return ERR_HAPPENED;
- }
- TRACE0("====>Step 5: An connection comes.\n");
- sbio = BIO_pop(acpt);
- BIO_free_all(acpt);
- if(BIO_do_handshake(sbio) <= 0) {
- ERR_print_errors_fp(stderr);
- return ERR_HAPPENED;
- }
- TRACE0("====>Step 6: Handshake done.\n");
- memset(tmpbuf,0,1024 * sizeof(char));
- BIO_read(sbio,tmpbuf,1024);
- printf("\t\tRead message from client is:%s\n",tmpbuf);
- BIO_free_all(sbio);
- return 0;
- }
版权声明:本文为博主原创文章,未经博主允许不得转载
原文链接:http://blog.csdn.net/gx_1983/article/details/47958323
阅读全文
0 0
- 使用openssl API编写client和server
- 使用openssl API编写client和server
- 使用Socket编写Client-Server通信总结
- 基于TCP的server和client编写。
- 使用openssl编写服务端和客户端程序
- 使用openssl编写服务端和客户端程序
- 记录 boost 中 使用 asio 编写 server和client代码片段
- 利用OpenSSL编写SSL通信程序时常使用的API
- linux c++使用libevent编写http server + http client
- VRPN学习笔记(二) 配置server和编写client
- ROS学习(二)server和client的编写总结
- php使用websocket示例 client 和 server
- Android Binder-编写client/server
- ZigBee server和 client
- 如何使用openssl创建根CA和中间CA以及签署其他client证书请求
- 使用OpenSSL API安全编程
- C++使用OpenSSL证书API
- 利用FIFO编写一个Server/Client程序
- 初识android studio项目结构
- html页面点击下载文件(共两种实现方法)
- Cesium
- 无服务器探索之路(初级):AWS Lambda服务应用场景实践之一(二)
- shell用法总结
- 使用openssl API编写client和server
- linux 查看硬盘序列号
- circualArray
- nodejs -- 使用rabbitMq
- golang基础-接口、接口嵌套、类型断言、接口与结构体_接口等转换
- Mac ssh 多账号登陆管理
- 【ML】机器学习学前准备
- 解决Maven Configuration Problem问题
- Servlet生命周期与工作原理