2 * Copyright (c) 2007, Cameron Rich
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * * Neither the name of the axTLS project nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * Demonstrate the use of the axTLS library in C with a set of
33 * command-line parameters similar to openssl. In fact, openssl clients
34 * should be able to communicate with axTLS servers and visa-versa.
36 * This code has various bits enabled depending on the configuration. To enable
37 * the most interesting version, compile with the 'full mode' enabled.
39 * To see what options you have, run the following:
43 * The axtls shared library must be in the same directory or be found
51 /* define standard input */
53 #define STDIN_FILENO 0
56 static void do_server(int argc, char *argv[]);
57 static void print_options(char *option);
58 static void print_server_options(char *option);
59 static void do_client(int argc, char *argv[]);
60 static void print_client_options(char *option);
61 static void display_cipher(SSL *ssl);
62 static void display_session_id(SSL *ssl);
65 * Main entry point. Doesn't do much except works out whether we are a client
68 int main(int argc, char *argv[])
72 WORD wVersionRequested = MAKEWORD(2, 2);
73 WSAStartup(wVersionRequested, &wsaData);
74 #elif !defined(CONFIG_PLATFORM_SOLARIS)
75 signal(SIGPIPE, SIG_IGN); /* ignore pipe errors */
78 if (argc == 2 && strcmp(argv[1], "version") == 0)
80 printf("axssl %s %s\n", ssl_version(), __DATE__);
85 strcmp(argv[1], "s_server") && strcmp(argv[1], "s_client")))
86 print_options(argc > 1 ? argv[1] : "");
88 strcmp(argv[1], "s_server") ?
89 do_client(argc, argv) : do_server(argc, argv);
94 * Implement the SSL server logic.
96 static void do_server(int argc, char *argv[])
100 uint32_t options = SSL_DISPLAY_CERTS;
103 int server_fd, res = 0;
104 socklen_t client_len;
105 #ifndef CONFIG_SSL_SKELETON_MODE
106 char *private_key_file = NULL;
107 const char *password = NULL;
110 int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
117 struct sockaddr_in serv_addr;
118 struct sockaddr_in client_addr;
120 #ifdef CONFIG_SSL_CERT_VERIFICATION
121 int ca_cert_index = 0;
122 int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
123 char **ca_cert = (char **)calloc(1, sizeof(char *)*ca_cert_size);
127 #ifndef CONFIG_SSL_SKELETON_MODE
128 cert = (char **)calloc(1, sizeof(char *)*cert_size);
133 if (strcmp(argv[i], "-accept") == 0)
137 print_server_options(argv[i]);
140 port = atoi(argv[++i]);
142 #ifndef CONFIG_SSL_SKELETON_MODE
143 else if (strcmp(argv[i], "-cert") == 0)
145 if (i >= argc-1 || cert_index >= cert_size)
147 print_server_options(argv[i]);
150 cert[cert_index++] = argv[++i];
152 else if (strcmp(argv[i], "-key") == 0)
156 print_server_options(argv[i]);
159 private_key_file = argv[++i];
160 options |= SSL_NO_DEFAULT_KEY;
162 else if (strcmp(argv[i], "-pass") == 0)
166 print_server_options(argv[i]);
169 password = argv[++i];
172 else if (strcmp(argv[i], "-quiet") == 0)
175 options &= ~SSL_DISPLAY_CERTS;
177 #ifdef CONFIG_SSL_CERT_VERIFICATION
178 else if (strcmp(argv[i], "-verify") == 0)
180 options |= SSL_CLIENT_AUTHENTICATION;
182 else if (strcmp(argv[i], "-CAfile") == 0)
184 if (i >= argc-1 || ca_cert_index >= ca_cert_size)
186 print_server_options(argv[i]);
189 ca_cert[ca_cert_index++] = argv[++i];
192 #ifdef CONFIG_SSL_FULL_MODE
193 else if (strcmp(argv[i], "-debug") == 0)
195 options |= SSL_DISPLAY_BYTES;
197 else if (strcmp(argv[i], "-state") == 0)
199 options |= SSL_DISPLAY_STATES;
201 else if (strcmp(argv[i], "-show-rsa") == 0)
203 options |= SSL_DISPLAY_RSA;
206 else /* don't know what this is */
208 print_server_options(argv[i]);
214 if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_SVR_SESS)) == NULL)
216 fprintf(stderr, "Error: Server context is invalid\n");
220 #ifndef CONFIG_SSL_SKELETON_MODE
221 if (private_key_file)
223 int obj_type = SSL_OBJ_RSA_KEY;
225 /* auto-detect the key type from the file extension */
226 if (strstr(private_key_file, ".p8"))
227 obj_type = SSL_OBJ_PKCS8;
228 else if (strstr(private_key_file, ".p12"))
229 obj_type = SSL_OBJ_PKCS12;
231 if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password))
233 fprintf(stderr, "Error: Private key '%s' is undefined.\n",
239 for (i = 0; i < cert_index; i++)
241 if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL))
243 printf("Certificate '%s' is undefined.\n", cert[i]);
249 #ifdef CONFIG_SSL_CERT_VERIFICATION
250 for (i = 0; i < ca_cert_index; i++)
252 if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL))
254 printf("Certificate '%s' is undefined.\n", ca_cert[i]);
261 #ifndef CONFIG_SSL_SKELETON_MODE
265 /* Create socket for incoming connections */
266 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
272 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
274 /* Construct local address structure */
275 memset(&serv_addr, 0, sizeof(serv_addr)); /* Zero out structure */
276 serv_addr.sin_family = AF_INET; /* Internet address family */
277 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
278 serv_addr.sin_port = htons(port); /* Local port */
280 /* Bind to the local address */
281 if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
287 if (listen(server_fd, 5) < 0)
293 client_len = sizeof(client_addr);
295 /*************************************************************************
296 * This is where the interesting stuff happens. Up until now we've
297 * just been setting up sockets etc. Now we do the SSL handshake.
298 *************************************************************************/
310 if ((client_fd = accept(server_fd,
311 (struct sockaddr *)&client_addr, &client_len)) < 0)
317 ssl = ssl_server_new(ssl_ctx, client_fd);
319 /* now read (and display) whatever the client sends us */
322 /* allow parallel reading of client and standard input */
324 FD_SET(client_fd, &read_set);
327 /* win32 doesn't like mixing up stdin and sockets */
328 if (isatty(STDIN_FILENO))/* but only if we are in an active shell */
330 FD_SET(STDIN_FILENO, &read_set);
333 if ((res = select(client_fd+1, &read_set, NULL, NULL, NULL)) > 0)
337 /* read standard input? */
338 if (FD_ISSET(STDIN_FILENO, &read_set))
340 if (fgets((char *)buf, sizeof(buf), stdin) == NULL)
342 res = SSL_ERROR_CONN_LOST;
346 /* small hack to check renegotiation */
347 if (buf[0] == 'r' && (buf[1] == '\n' || buf[1] == '\r'))
349 res = ssl_renegotiate(ssl);
351 else /* write our ramblings to the client */
353 res = ssl_write(ssl, buf, strlen((char *)buf)+1);
357 else /* a socket read */
360 /* keep reading until we get something interesting */
363 if ((res = ssl_read(ssl, &read_buf)) == SSL_OK)
365 /* are we in the middle of doing a handshake? */
366 if (ssl_handshake_status(ssl) != SSL_OK)
370 else if (!reconnected)
372 /* we are connected/reconnected */
375 display_session_id(ssl);
383 if (res > SSL_OK) /* display our interesting output */
385 printf("%s", read_buf);
388 else if (res < SSL_OK && !quiet)
390 ssl_display_error(res);
401 printf("CONNECTION CLOSED\n");
409 /* client was disconnected or the handshake failed. */
411 SOCKET_CLOSE(client_fd);
414 ssl_ctx_free(ssl_ctx);
418 * Implement the SSL client logic.
420 static void do_client(int argc, char *argv[])
422 #ifdef CONFIG_SSL_ENABLE_CLIENT
424 uint16_t port = 4433;
425 uint32_t options = SSL_SERVER_VERIFY_LATER|SSL_DISPLAY_CERTS;
427 char *private_key_file = NULL;
428 struct sockaddr_in client_addr;
429 struct hostent *hostent;
435 int cert_index = 0, ca_cert_index = 0;
436 int cert_size, ca_cert_size;
437 char **ca_cert, **cert;
438 uint8_t session_id[SSL_SESSION_ID_SIZE];
440 const char *password = NULL;
443 sin_addr = inet_addr("127.0.0.1");
444 cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
445 ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
446 ca_cert = (char **)calloc(1, sizeof(char *)*ca_cert_size);
447 cert = (char **)calloc(1, sizeof(char *)*cert_size);
451 if (strcmp(argv[i], "-connect") == 0)
457 print_client_options(argv[i]);
461 if ((ptr = strchr(host, ':')) == NULL)
463 print_client_options(argv[i]);
468 hostent = gethostbyname(host);
472 print_client_options(argv[i]);
475 sin_addr = *((uint32_t **)hostent->h_addr_list)[0];
477 else if (strcmp(argv[i], "-cert") == 0)
479 if (i >= argc-1 || cert_index >= cert_size)
481 print_client_options(argv[i]);
484 cert[cert_index++] = argv[++i];
486 else if (strcmp(argv[i], "-key") == 0)
490 print_client_options(argv[i]);
493 private_key_file = argv[++i];
494 options |= SSL_NO_DEFAULT_KEY;
496 else if (strcmp(argv[i], "-CAfile") == 0)
498 if (i >= argc-1 || ca_cert_index >= ca_cert_size)
500 print_client_options(argv[i]);
503 ca_cert[ca_cert_index++] = argv[++i];
505 else if (strcmp(argv[i], "-verify") == 0)
507 options &= ~SSL_SERVER_VERIFY_LATER;
509 else if (strcmp(argv[i], "-reconnect") == 0)
513 else if (strcmp(argv[i], "-quiet") == 0)
516 options &= ~SSL_DISPLAY_CERTS;
518 else if (strcmp(argv[i], "-pass") == 0)
522 print_client_options(argv[i]);
525 password = argv[++i];
527 #ifdef CONFIG_SSL_FULL_MODE
528 else if (strcmp(argv[i], "-debug") == 0)
530 options |= SSL_DISPLAY_BYTES;
532 else if (strcmp(argv[i], "-state") == 0)
534 options |= SSL_DISPLAY_STATES;
536 else if (strcmp(argv[i], "-show-rsa") == 0)
538 options |= SSL_DISPLAY_RSA;
541 else /* don't know what this is */
543 print_client_options(argv[i]);
549 if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL)
551 fprintf(stderr, "Error: Client context is invalid\n");
555 if (private_key_file)
557 int obj_type = SSL_OBJ_RSA_KEY;
559 /* auto-detect the key type from the file extension */
560 if (strstr(private_key_file, ".p8"))
561 obj_type = SSL_OBJ_PKCS8;
562 else if (strstr(private_key_file, ".p12"))
563 obj_type = SSL_OBJ_PKCS12;
565 if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password))
567 fprintf(stderr, "Error: Private key '%s' is undefined.\n",
573 for (i = 0; i < cert_index; i++)
575 if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL))
577 printf("Certificate '%s' is undefined.\n", cert[i]);
582 for (i = 0; i < ca_cert_index; i++)
584 if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL))
586 printf("Certificate '%s' is undefined.\n", ca_cert[i]);
594 /*************************************************************************
595 * This is where the interesting stuff happens. Up until now we've
596 * just been setting up sockets etc. Now we do the SSL handshake.
597 *************************************************************************/
598 client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
599 memset(&client_addr, 0, sizeof(client_addr));
600 client_addr.sin_family = AF_INET;
601 client_addr.sin_port = htons(port);
602 client_addr.sin_addr.s_addr = sin_addr;
604 if (connect(client_fd, (struct sockaddr *)&client_addr,
605 sizeof(client_addr)) < 0)
613 printf("CONNECTED\n");
617 /* Try session resumption? */
622 ssl = ssl_client_new(ssl_ctx, client_fd, session_id,
624 if ((res = ssl_handshake_status(ssl)) != SSL_OK)
628 ssl_display_error(res);
635 display_session_id(ssl);
636 memcpy(session_id, ssl_get_session_id(ssl), SSL_SESSION_ID_SIZE);
641 SOCKET_CLOSE(client_fd);
643 client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
644 connect(client_fd, (struct sockaddr *)&client_addr,
645 sizeof(client_addr));
651 ssl = ssl_client_new(ssl_ctx, client_fd, NULL, 0);
654 /* check the return status */
655 if ((res = ssl_handshake_status(ssl)) != SSL_OK)
659 ssl_display_error(res);
667 const char *common_name = ssl_get_cert_dn(ssl,
668 SSL_X509_CERT_COMMON_NAME);
671 printf("Common Name:\t\t\t%s\n", common_name);
674 display_session_id(ssl);
683 /* allow parallel reading of server and standard input */
684 FD_SET(client_fd, &read_set);
686 /* win32 doesn't like mixing up stdin and sockets */
687 FD_SET(STDIN_FILENO, &read_set);
689 if ((res = select(client_fd+1, &read_set, NULL, NULL, NULL)) > 0)
691 /* read standard input? */
692 if (FD_ISSET(STDIN_FILENO, &read_set))
695 if (fgets((char *)buf, sizeof(buf), stdin) == NULL)
697 /* bomb out of here */
703 /* small hack to check renegotiation */
704 if (buf[0] == 'R' && (buf[1] == '\n' || buf[1] == '\r'))
706 res = ssl_renegotiate(ssl);
710 res = ssl_write(ssl, buf, strlen((char *)buf)+1);
715 else /* a socket read */
719 res = ssl_read(ssl, &read_buf);
721 if (res > 0) /* display our interesting output */
723 printf("%s", read_buf);
734 ssl_display_error(res);
737 break; /* get outta here */
741 ssl_ctx_free(ssl_ctx);
742 SOCKET_CLOSE(client_fd);
744 print_client_options(argv[1]);
749 * We've had some sort of command-line error. Print out the basic options.
751 static void print_options(char *option)
753 printf("axssl: Error: '%s' is an invalid command.\n", option);
754 printf("usage: axssl [s_server|s_client|version] [args ...]\n");
759 * We've had some sort of command-line error. Print out the server options.
761 static void print_server_options(char *option)
763 #ifndef CONFIG_SSL_SKELETON_MODE
764 int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
766 #ifdef CONFIG_SSL_CERT_VERIFICATION
767 int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
770 printf("unknown option %s\n", option);
771 printf("usage: s_server [args ...]\n");
772 printf(" -accept arg\t- port to accept on (default is 4433)\n");
773 #ifndef CONFIG_SSL_SKELETON_MODE
774 printf(" -cert arg\t- certificate file to add (in addition to default)"
776 "\t\t Can repeat up to %d times\n", cert_size);
777 printf(" -key arg\t- Private key file to use\n");
778 printf(" -pass\t\t- private key file pass phrase source\n");
780 printf(" -quiet\t\t- No server output\n");
781 #ifdef CONFIG_SSL_CERT_VERIFICATION
782 printf(" -verify\t- turn on peer certificate verification\n");
783 printf(" -CAfile arg\t- Certificate authority\n");
784 printf("\t\t Can repeat up to %d times\n", ca_cert_size);
786 #ifdef CONFIG_SSL_FULL_MODE
787 printf(" -debug\t\t- Print more output\n");
788 printf(" -state\t\t- Show state messages\n");
789 printf(" -show-rsa\t- Show RSA state\n");
795 * We've had some sort of command-line error. Print out the client options.
797 static void print_client_options(char *option)
799 #ifdef CONFIG_SSL_ENABLE_CLIENT
800 int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
801 int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
804 printf("unknown option %s\n", option);
805 #ifdef CONFIG_SSL_ENABLE_CLIENT
806 printf("usage: s_client [args ...]\n");
807 printf(" -connect host:port - who to connect to (default "
808 "is localhost:4433)\n");
809 printf(" -verify\t- turn on peer certificate verification\n");
810 printf(" -cert arg\t- certificate file to use\n");
811 printf("\t\t Can repeat up to %d times\n", cert_size);
812 printf(" -key arg\t- Private key file to use\n");
813 printf(" -CAfile arg\t- Certificate authority\n");
814 printf("\t\t Can repeat up to %d times\n", ca_cert_size);
815 printf(" -quiet\t\t- No client output\n");
816 printf(" -reconnect\t- Drop and re-make the connection "
817 "with the same Session-ID\n");
818 printf(" -pass\t\t- private key file pass phrase source\n");
819 #ifdef CONFIG_SSL_FULL_MODE
820 printf(" -debug\t\t- Print more output\n");
821 printf(" -state\t\t- Show state messages\n");
822 printf(" -show-rsa\t- Show RSA state\n");
825 printf("Change configuration to allow this feature\n");
831 * Display what cipher we are using
833 static void display_cipher(SSL *ssl)
835 printf("CIPHER is ");
836 switch (ssl_get_cipher_id(ssl))
839 printf("AES128-SHA");
843 printf("AES256-SHA");
846 case SSL_RC4_128_SHA:
850 case SSL_RC4_128_MD5:
855 printf("Unknown - %d", ssl_get_cipher_id(ssl));
864 * Display what session id we have.
866 static void display_session_id(SSL *ssl)
869 const uint8_t *session_id = ssl_get_session_id(ssl);
870 int sess_id_size = ssl_get_session_id_size(ssl);
872 if (sess_id_size > 0)
874 printf("-----BEGIN SSL SESSION PARAMETERS-----\n");
875 for (i = 0; i < sess_id_size; i++)
877 printf("%02x", session_id[i]);
880 printf("\n-----END SSL SESSION PARAMETERS-----\n");