I. Create an OpenSSL Certificate:
1. Create the directory./democa/./democa/newcerts/and create the file./democa/index.txt./democa/serial.
2. Run echo 01>./democa/serial.
3. Create your own CA certificate
$ OpenSSL req-New-X509-keyout ca. Key-out ca. CRT
4. Generate the private key (key file) and CSR file of the server.
$ OpenSSL genrsa-des3-out server. Key 1024
$ OpenSSL req-New-key server. Key-out server. CSR
5. Generate the client's private key (key file) and CSR File
$ OpenSSL Gen RSA-des3-out client. Key 1024
$ OpenSSL req-New-key client. Key-out client. CSR
6. Use the generated CA certificate to sign the generated server. CSR and client. CSR files.
$ OpenSSL ca-in server. CSR-out server. CRT-Cert CA. CRT-Keyfile ca. Key
$ OpenSSL ca-in client. CSR-out client. CRT-Cert CA. CRT-Keyfile ca. Key
7. Generate a pem Certificate
Certificates in PEM format are sometimes used. You can combine the Certificate file (CRT) and private key file (key) to generate
$ Cat client. CRT client. Key> client. pem
$ Cat server. CRT server. Key> server. pem
Ii. OpenSSL Programming
OpenSSL programming has two styles: Original Ecology and layer-by-layer encapsulation.
2.1 Original Ecological OpenSSL Programming
The underlying APIs in BSD socket and OpenSSL must be used. The original OpenSSL has two important structures: SSL and ssl_ctx.
The ssl_ctx data structure is a structure used to establish an SSL/TSL connection. It can be used to specify communication protocols (sslv23/tslv1), certificates, keys, and other related information.
The SSL data structure is the structure associated with a specific session.
Common functions:
Ssl_library_init (): initializes an OpenSSL library.
Ssl_ctx_new (const ssl_method * method): Creates a CTX structure.
Ssl_new (ssl_ctx * CTX): creates an SSL structure.
Ssl_set_fd (SSL * SSL, int FD): Associate the SSL structure with a specific session.
Ssl_accept (SSL * SSL) and ssl_connect (SSL * SSL): used for SSL session handshake.
Ssl_read (SSL * SSL, void * Buf, int num) and ssl_write (SSL * SSL, void * Buf, int num) are used for SSL read/write.
Ssl_shutdown (SSL * SSL) is used to close an SSL/TSL session.
You can use these functions to perform the most basic OpenSSL programming. The OpenSSL programming framework is as follows.
Sample Code: https server and client
Server:
# Include <sys/types. h> # include <sys/socket. h> # include <sys/UN. h> # include <unistd. h> # include <stdio. h> # include <ARPA/inet. h> # include <OpenSSL/Bio. h> # include <OpenSSL/SSL. h> # include <OpenSSL/err. h> # define server_pem ".. /digitcert/server. PEM "# define server_kry ".. /digitcert/server. key "int password_callback (char * Buf, int size, int rwflag, void * userdata) {/* For the purposes of this demonstration, Password is "ibmdw" */printf ("*** callback function called/N"); strcpy (BUF, "123456"); Return strlen (BUF );} int main () {int serv_sock, cli_sock; socklen_t client_len; struct sockaddr_in server_address; struct sockaddr_in client_address; ssl_ctx * CTX; SSL * SSL; int (* callback) (char *, int, int, void *) = & password_callback; printf ("serving it up in a secure manner/n"); ssl_library_init (); ssl_loa D_error_strings (); err_load_bio_strings (); err_load_ssl_strings (); openssl_add_all_algorithms (); printf ("attempting to create SSL context... "); CTX = ssl_ctx_new (sslv23_server_method (); If (CTX = NULL) {printf (" failed. aborting. /n "); Return 0;} printf ("/nloading certificates... /n "); ssl_ctx_set_default_passwd_cb (CTX, callback); If (! Convert (CTX, server_pem, ssl_filetype_pem) {err_print_errors_fp (stdout); ssl_ctx_free (CTX); Return 0;} else printf ("load server. CSR successful! /N "); If (ssl_ctx_use_privatekey_file (CTX, server_kry, ssl_filetype_pem) <= 0) {printf (" use private key failed! /N "); err_print_errors_fp (stdout); ssl_ctx_free (CTX); Return 0;} serv_sock = socket (af_inet, sock_stream, 0); If (-1 = serv_sock) {perror ("socket");} server_address.sin_family = af_inet; region = htons (443); region = htonl (inaddr_any); int ret = BIND (serv_sock, (struct sockaddr *) & server_address, sizeof (struct sockaddr); If (-1 = RET) {perror ("bind");} List En (serv_sock, 5); While (1) {cli_sock = accept (serv_sock, (struct sockaddr *) & client_address, (socklen_t *) & client_len ); SSL = ssl_new (CTX); ssl_set_fd (SSL, cli_sock); ssl_accept (SSL); // read char line [4096]; ssl_read (SSL, line, sizeof (line )); // normally process HTTP protocol // write and return packets. Ssl_write (SSL, "HTTP/1.0 200 OK/R/n/R/N", 19); ssl_write (SSL, "<HTML> <peader> </peader> <body> <P1> Hello World <P1> </body> </ptml>", 62); close (cli_sock ); ssl_shutdown (SSL); ssl_free (SSL);} ssl_ctx_free (CTX );}
Client:
# Include <stdio. h> # include <stdlib. h> # include <string. h> # include <sys/types. h> # include <sys/socket. h> # include <errno. h> # include <unistd. h> # include <netinet/in. h> # include <limits. h> # include <netdb. h> # include <ARPA/inet. h> # include <ctype. h> # include <OpenSSL/crypto. h> # include <OpenSSL/SSL. h> # include <OpenSSL/err. h> # include <OpenSSL/Rand. h> # define debug 1 /*********************************: Search for the first matched character ******************************* * ***********/char * rstrchr (char * s, char X) {int I = strlen (s); If (! (* S) return 0; while (s [I-1]) if (strchr (S + (I-1), x )) return (S + (I-1); else I --; return 0 ;} /*************************************** * *********************** function: analyze the website address and port from the string SRC, then you can get the file you want to download ********************************* * ****************************/void gethost (char * SRC, char * web, char * file, int * port) {char * pA; char * pb; memset (Web, 0, sizeof (Web); memset (file, 0, sizeof (File )); * Port = 0; If (! (* SRC) return; Pa = SRC; If (! Strncmp (Pa, "http: //", strlen ("http: //") pA = SRC + strlen ("http: //"); else if (! Strncmp (Pa, "https: //", strlen ("https: //") pA = SRC + strlen ("https ://"); PB = strchr (Pa, '/'); If (PB) {memcpy (Web, Pa, strlen (PA)-strlen (PB); If (Pb + 1) {memcpy (file, Pb + 1, strlen (Pb)-1); file [strlen (Pb)-1] = 0 ;}} else memcpy (Web, Pa, strlen (PA); If (PB) Web [strlen (PA)-strlen (PB)] = 0; else web [strlen (PA)] = 0; pa = strchr (Web, ':'); If (PA) * Port = atoi (PA + 1); else * Port = 4 43 ;} ************************ * ********************* filename: https-client.c * purpose: demonstrate HTTPS client Programming Method * wrote by: zhoulifa (zhoulifa@163.com) Zhou Lifa (http://zhoulifa.bokee.com) Linux enthusiast Linux knowledge transmitter soho developers are best at C Language * Date Time: * Note: Anyone can copy the code and use the documentation at will, of course, for your commercial purposes * but follow the GPL * thanks to: Google * hope: I hope more and more people will contribute to the development of science and technology. * technology stands on the shoulders of giants to make progress faster! Thank you for your contributions to the open source team! **************************************** * ***************************/INT main (INT argc, char * argv []) {int sockfd, RET; char buffer [1024]; struct sockaddr_in server_addr; struct hostent * Host; int portnumber, nbytes; char host_addr [256]; char host_file [1024]; char local_file [256]; file * FP; char request [1024]; int send, totalsend; int I; char * PT; SSL * SSL; ssl_ctx * CTX; If (argc! = 2) {If (Debug) fprintf (stderr, "Usage: % s webpage-address/A/N", argv [0]); exit (1 );} if (Debug) printf ("parameter.1 is: % s/n", argv [1]); gethost (argv [1], host_addr, host_file, & portnumber ); /* analyze URL, port, file name, etc. */If (Debug) printf ("webhost: % s/n", host_addr); If (Debug) printf ("hostfile: % s/n ", host_file); If (Debug) printf (" portnumber: % d/n ", portnumber); If (host = gethostbyname (host_addr )) = NULL) {/* Obtain the Host IP Address */If (Debug) fprintf (stderr, "gethostname error, % s/n", strerror (errno); exit (1 );} /* The client program starts to establish the sockfd descriptor */If (sockfd = socket (af_inet, sock_stream, 0) =-1) {/* establish socket connection */If (Debug) fprintf (stderr, "socket error: % S/A/N", strerror (errno); exit (1 );} /* fill the client program with server information */bzero (& server_addr, sizeof (server_addr); server_addr.sin_family = af_inet; server_addr.sin_port = htons (Portnumber); server_addr.sin_addr = * (struct in_addr *) Host-> h_addr);/* The client program initiates a connection request */If (connect (sockfd, (struct sockaddr *) (& server_addr), sizeof (struct sockaddr) =-1) {/* connect to the website */If (Debug) fprintf (stderr, "Connect error: % S/A/N ", strerror (errno); exit (1);}/* SSL initialization */ssl_library_init (); ssl_load_error_strings (); CTX = ssl_ctx_new (sslv23_client_method (); If (CTX = NULL) {err_print _ Errors_fp (stderr); exit (1);} SSL = ssl_new (CTX); If (SSL = NULL) {err_print_errors_fp (stderr); exit (1 );} /* Associate socket and SSL */ret = ssl_set_fd (SSL, sockfd); If (ret = 0) {err_print_errors_fp (stderr); exit (1 );} rand_poll (); While (rand_status () = 0) {unsigned short rand_ret = rand () % 65536; rand_seed (& rand_ret, sizeof (rand_ret ));} ret = ssl_connect (SSL); If (Ret! = 1) {err_print_errors_fp (stderr); exit (1);} sprintf (request, "Get/% s HTTP/1.1/R/naccept: */R/naccept-language: ZH-CN/R/n/User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) /R/n/Host: % s: % d/R/nconnection: Close/R/n/R/N ", host_file, host_addr, portnumber); If (Debug) printf ("% s", request);/* prepare the request and send it to the Host * // * obtain the actual file name */If (host_file & * host_file) PT = rstrchr (host_file ,'/'); Else Pt = 0; memset (local_file, 0, sizeof (local_file); If (PT & * PT) {If (Pt + 1) & * (Pt + 1) strcpy (local_file, Pt + 1); else memcpy (local_file, host_file, strlen (host_file)-1 );} else if (host_file & * host_file) strcpy (local_file, host_file); else strcpy (local_file, "index.html"); If (Debug) printf ("local filename to write: % s/n ", local_file);/* Send HTTPS Request */send = 0; totalsen D = 0; nbytes = strlen (request); While (totalsend <nbytes) {send = ssl_write (SSL, request + totalsend, nbytes-totalsend ); if (send =-1) {If (Debug) err_print_errors_fp (stderr); exit (0) ;}totalsend + = Send; If (Debug) printf ("% d bytes send OK! /N ", totalsend);} fp = fopen (" index.html "," A "); If (! FP) {If (Debug) printf ("Create File error! % S/n ", strerror (errno); Return 0;} If (Debug) printf ("/nthe following is the response header:/N "); I = 0; /* the connection is successful and the HTTPS response is received. response */while (nbytes = ssl_read (SSL, buffer, 1) = 1) {if (I <4) {If (buffer [0] = '/R' | buffer [0] ='/N') I ++; else I = 0; If (Debug) printf ("% C", buffer [0]);/* print the HTTPS header information on the screen */} else {fwrite (buffer, 1, 1, FP ); /* write HTTPS subject information to the file */I ++; if (I % 1024 = 0) Fflush (FP);/* save disk every 1 K */} fclose (FP);/* end communication */ret = ssl_shutdown (SSL); If (Ret! = 1) {err_print_errors_fp (stderr); exit (1);} Close (sockfd); ssl_free (SSL); ssl_ctx_free (CTX); err_free_strings (); exit (0 );}
2.2 layer-by-layer OpenSSL programming.
Here, the basic operations of BSD socket are invisible to the upper layer. OpenSSL encapsulates its underlying operations.
In addition, you need to understand the concept of bio.
Bio is an abstract encapsulation of the IO type by OpenSSL, including memory, files, logs, standard input and output, socket, encryption/decryption, digest, and SSL channels.
Bio is divided into two types: source/sink Type Bio is a data source or input data source (I do not know how to translate the sink), such as sokect bio and file bio. Filter Bio is to convert data from one bio to another bio or application interface. During the conversion process, the data can be not modified (such as information abstract bio) or converted.
Bio chain, you can pre-set the links between multiple bio. When data comes in from the Source Type Bio, the data is automatically transferred between bio chains. This should be attractive to bio. For example, three bio, mbio (memory type), sbio (SSL type), and abio (accept type) are connected into bio chains: mbio-> sbio-> abio.
Therefore, mbio read operations include receiving data from accept, performing SSL decryption on encrypted data, and finally reading data into memory; mbio write operations include SSL encryption of data and sending encrypted data from the socket.
Bio common functions:
Bio * bio_new (bio_method * type): Generate bio
Bio_set (Bio * a, bio_method * type): Set bio
Bio_free (Bio * A): delete bio
Bio_free_all (Bio * A): deletes a bio chain.
Bio_read (Bio * B, void * Buf, int Len)
Bio_gets (Bio * B, char * Buf, int size)
Bio_write (Bio * B, const void * Buf, int Len)
Bio_puts (Bio * B, const char * BUF)
Bio * bio_push (Bio * B, bio * append): This function attaches bio named append to bio named B and returns B.
Bio * bio_pop (Bio * B): Remove bio from a bio chain of B and return the next bio.
Sample Code (ECHO ):
Server:
#include <stdio.h>#include <string.h>#include <openssl/bio.h>#include <openssl/ssl.h>#include <openssl/err.h>#include <unistd.h>#define SERVER_PEM "../digitCert/server.pem"#define SERVER_KRY "../digitCert/server.key"int password_callback(char *buf, int size, int rwflag, void *userdata){ /* For the purposes of this demonstration, the password is "ibmdw" */ printf("*** Callback function called/n"); strcpy(buf,"123456"); return strlen(buf);}int main(){ SSL_CTX *ctx; SSL *ssl; BIO *sslbio, *acptbio, *out; pid_t pid; int len; char buf[1024]; int (*callback)(char *, int, int, void *) = &password_callback; printf("Secure Programming with the OpenSSL API, Part 4:/n"); printf("Serving it up in a secure manner/n/n"); SSL_library_init(); SSL_load_error_strings(); ERR_load_BIO_strings(); ERR_load_SSL_strings(); OpenSSL_add_all_algorithms(); printf("Attempting to create SSL context... "); ctx = SSL_CTX_new(SSLv23_server_method()); if(ctx == NULL) { printf("Failed. Aborting./n"); return 0; } printf("/nLoading certificates.../n"); SSL_CTX_set_default_passwd_cb(ctx, callback); if(!SSL_CTX_use_certificate_file(ctx, SERVER_PEM, SSL_FILETYPE_PEM)) { ERR_print_errors_fp(stdout); SSL_CTX_free(ctx); return 0; } else printf("load server.csr successful!/n"); if((SSL_CTX_use_PrivateKey_file(ctx, SERVER_KRY, SSL_FILETYPE_PEM))<=0) { printf("use private key failed!/n/n"); ERR_print_errors_fp(stdout); SSL_CTX_free(ctx); return 0; } printf("Attempting to create BIO object... "); sslbio = BIO_new_ssl(ctx, 0);//0 indicate using server mode if(sslbio == NULL) { printf("Failed. Aborting./n"); ERR_print_errors_fp(stdout); SSL_CTX_free(ctx); return 0; } printf("/nAttempting to set up BIO for SSL.../n"); BIO_get_ssl(sslbio, &ssl); printf("Waiting for incoming connection.../n"); /*Begin to listen the port*/ if(BIO_do_accept(acptbio) <= 0) { ERR_print_errors_fp(stdout); SSL_CTX_free(ctx); BIO_free_all(sslbio); BIO_free_all(acptbio); return 1; } while(1) { /*Waiting for a new connection to establish*/ if(BIO_do_accept(acptbio) <= 0) { ERR_print_errors_fp(stdout); SSL_CTX_free(ctx); BIO_free_all(sslbio); BIO_free_all(acptbio); return 1; } out = BIO_pop(acptbio); if((pid=fork()))//parent process { BIO_free(out); }else { if(BIO_do_handshake(out) <= 0) { printf("Handshake failed./n"); ERR_print_errors_fp(stdout); SSL_CTX_free(ctx); BIO_free_all(sslbio); BIO_free_all(acptbio); return 1; } for(;;) { memset(buf,0,1023); len = BIO_read(out,buf,1023); switch(SSL_get_error(ssl,len)) { case SSL_ERROR_NONE: break; default: printf("Read Problem!/n"); exit(0); } if(!strcmp(buf,"/r/n")||!strcmp(buf,"/n")) break; if(buf[0]=='q') break; BIO_write(out,buf,len); printf("%s/n",buf); } BIO_free(out); BIO_ssl_shutdown(sslbio); exit(0); }//end else } BIO_ssl_shutdown(sslbio); BIO_free_all(sslbio); BIO_free_all(acptbio); SSL_CTX_free(ctx);}
Client:
# Include <OpenSSL/SSL. h> # include <errno. h> # include <OpenSSL/Bio. h> # include <OpenSSL/err. h> # include <stdio. h> # include <string. h> int main () {bio * sslbio; SSL * SSL; ssl_ctx * CTX; int P;/* set up the library */ssl_library_init (); // yes, initialize SSL library err_load_bio_strings (); ssl_load_error_strings (); openssl_add_all_algorithms ();/* set up the SSL context */CTX = ssl_ctx_new (sslv23_method ();/* Load Trust store */If (! Ssl_ctx_load_verify_locations (CTX ,".. /digitcert/CA. CRT ", 0) // read the CA root certificate. Use this certificate to verify whether the certificate of the other party is trusted. {fprintf (stderr," error loading trust store/N "); ssl_ctx_free (CTX); Return 0;}/* setup the connection */sslbio = bio_new_ssl_connect (CTX ); // create an SSL bio/* set the ssl_mode_auto_retry flag */bio_get_ssl (sslbio, & SSL ); // obtain the SSL variable ssl_set_mode (SSL, ssl_mode_auto_retry) from the established SSL Type Bio sslbio; // set the SSL mode to ssl_mode _ Auto_retry: use this option to set. If the server suddenly wants a new handshake, OpenSSL can process it in the background. /* Create and setup the connection */bio_set_conn_hostname (sslbio, "127.0.0.1: 4433"); If (bio_do_connect (sslbio) <= 0) // initiate a handshake request {fprintf (stderr, "Error attempting to connect/N"); err_print_errors_fp (stderr); bio_free_all (sslbio); ssl_ctx_free (CTX); Return 0;} else printf ("connent to server successful! /N ");/* Check the certificate */If (ssl_get_verify_result (SSL )! = X509_v_ OK) // verify whether the certificate of the other party is valid (the time has not expired, and so on ...) {Fprintf (stderr, "certificate verification error: % LD/N", ssl_get_verify_result (SSL); bio_free_all (sslbio); ssl_ctx_free (CTX); Return 0 ;} else printf ("verify server Cert successful/N"); char Buf [1024]; for (;) {printf ("/ninput :"); scanf ("% s", & Buf [0]); bio_write (sslbio, Buf, strlen (BUF); P = bio_read (sslbio, Buf, 1023 ); if (P <= 0) break; Buf [p] = 0; printf ("% s/n", Buf); memset (BUF, 0,1024 );} /* close the connection and free the context */bio_ssl_shutdown (sslbio); bio_free_all (sslbio); ssl_ctx_free (CTX); Return 0 ;}