int main(int argc, char **argv) { struct s2n_connection *conn; uint8_t mac_key[] = "sample mac key"; uint8_t des3_key[] = "12345678901234567890123"; struct s2n_blob des3 = {.data = des3_key,.size = sizeof(des3_key) }; uint8_t random_data[S2N_DEFAULT_FRAGMENT_LENGTH + 1]; struct s2n_blob r = {.data = random_data, .size = sizeof(random_data)}; BEGIN_TEST(); EXPECT_SUCCESS(s2n_init()); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_get_urandom_data(&r)); /* Peer and we are in sync */ conn->server = &conn->active; conn->client = &conn->active; /* test the 3des cipher with a SHA1 hash */ conn->active.cipher_suite->cipher = &s2n_3des; conn->active.cipher_suite->hmac_alg = S2N_HMAC_SHA1; EXPECT_SUCCESS(conn->active.cipher_suite->cipher->get_encryption_key(&conn->active.server_key, &des3)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->get_decryption_key(&conn->active.client_key, &des3)); EXPECT_SUCCESS(s2n_hmac_init(&conn->active.client_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); EXPECT_SUCCESS(s2n_hmac_init(&conn->active.server_record_mac, S2N_HMAC_SHA1, mac_key, sizeof(mac_key))); conn->actual_protocol_version = S2N_TLS11; int max_aligned_fragment = S2N_DEFAULT_FRAGMENT_LENGTH - (S2N_DEFAULT_FRAGMENT_LENGTH % 8); for (int i = 0; i <= max_aligned_fragment + 1; i++) { struct s2n_blob in = {.data = random_data,.size = i }; int bytes_written; EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->out)); EXPECT_SUCCESS(bytes_written = s2n_record_write(conn, TLS_APPLICATION_DATA, &in)); if (i < max_aligned_fragment - 20 - 8 - 1) { EXPECT_EQUAL(bytes_written, i); } else { EXPECT_EQUAL(bytes_written, max_aligned_fragment - 20 - 8 - 1); } uint16_t predicted_length = bytes_written + 1 + 20 + 8; if (predicted_length % 8) { predicted_length += (8 - (predicted_length % 8)); } EXPECT_EQUAL(conn->out.blob.data[0], TLS_APPLICATION_DATA); EXPECT_EQUAL(conn->out.blob.data[1], 3); EXPECT_EQUAL(conn->out.blob.data[2], 2); EXPECT_EQUAL(conn->out.blob.data[3], (predicted_length >> 8) & 0xff); EXPECT_EQUAL(conn->out.blob.data[4], predicted_length & 0xff); /* The data should be encrypted */ if (bytes_written > 10) { EXPECT_NOT_EQUAL(memcmp(conn->out.blob.data + 5, random_data, bytes_written), 0); } /* Copy the encrypted out data to the in data */ EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->header_in, 5)) EXPECT_SUCCESS(s2n_stuffer_copy(&conn->out, &conn->in, s2n_stuffer_data_available(&conn->out))) /* Let's decrypt it */ uint8_t content_type; uint16_t fragment_length; EXPECT_SUCCESS(s2n_record_header_parse(conn, &content_type, &fragment_length)); EXPECT_SUCCESS(s2n_record_parse(conn)); EXPECT_EQUAL(content_type, TLS_APPLICATION_DATA); EXPECT_EQUAL(fragment_length, predicted_length); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->header_in)); EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->in)); } EXPECT_SUCCESS(conn->active.cipher_suite->cipher->destroy_key(&conn->active.server_key)); EXPECT_SUCCESS(conn->active.cipher_suite->cipher->destroy_key(&conn->active.client_key)); EXPECT_SUCCESS(s2n_connection_free(conn)); END_TEST(); }
int main(int argc, char *const *argv) { struct addrinfo hints, *ai_list, *ai; int r, sockfd = 0; ssize_t session_state_length = 0; uint8_t *session_state = NULL; /* Optional args */ const char *alpn_protocols = NULL; const char *server_name = NULL; const char *ca_file = NULL; const char *ca_dir = NULL; uint16_t mfl_value = 0; uint8_t insecure = 0; int reconnect = 0; uint8_t session_ticket = 1; s2n_status_request_type type = S2N_STATUS_REQUEST_NONE; uint32_t dyn_rec_threshold = 0; uint8_t dyn_rec_timeout = 0; /* required args */ const char *cipher_prefs = "default"; const char *host = NULL; struct verify_data unsafe_verify_data; const char *port = "443"; int echo_input = 0; int use_corked_io = 0; static struct option long_options[] = { {"alpn", required_argument, 0, 'a'}, {"ciphers", required_argument, 0, 'c'}, {"echo", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"name", required_argument, 0, 'n'}, {"status", no_argument, 0, 's'}, {"mfl", required_argument, 0, 'm'}, {"ca-file", required_argument, 0, 'f'}, {"ca-dir", required_argument, 0, 'd'}, {"insecure", no_argument, 0, 'i'}, {"reconnect", no_argument, 0, 'r'}, {"no-session-ticket", no_argument, 0, 'T'}, {"dynamic", required_argument, 0, 'D'}, {"timeout", required_argument, 0, 't'}, {"corked-io", no_argument, 0, 'C'}, }; while (1) { int option_index = 0; int c = getopt_long(argc, argv, "a:c:ehn:sf:d:D:t:irTC", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'a': alpn_protocols = optarg; break; case 'C': use_corked_io = 1; break; case 'c': cipher_prefs = optarg; break; case 'e': echo_input = 1; break; case 'h': usage(); break; case 'n': server_name = optarg; break; case 's': type = S2N_STATUS_REQUEST_OCSP; break; case 'm': mfl_value = (uint16_t) atoi(optarg); break; case 'f': ca_file = optarg; break; case 'd': ca_dir = optarg; break; case 'i': insecure = 1; break; case 'r': reconnect = 5; break; case 'T': session_ticket = 0; break; case 't': dyn_rec_timeout = (uint8_t) MIN(255, atoi(optarg)); break; case 'D': dyn_rec_threshold = strtoul(optarg, 0, 10); if (errno == ERANGE) { dyn_rec_threshold = 0; } break; case '?': default: usage(); break; } } if (optind < argc) { host = argv[optind++]; } if (optind < argc) { port = argv[optind++]; } if (!host) { usage(); } if (!server_name) { server_name = host; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { fprintf(stderr, "Error disabling SIGPIPE\n"); exit(1); } GUARD_EXIT(s2n_init(), "Error running s2n_init()"); if ((r = getaddrinfo(host, port, &hints, &ai_list)) != 0) { fprintf(stderr, "error: %s\n", gai_strerror(r)); exit(1); } do { int connected = 0; for (ai = ai_list; ai != NULL; ai = ai->ai_next) { if ((sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) { continue; } if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == -1) { close(sockfd); continue; } connected = 1; /* connect() succeeded */ break; } if (connected == 0) { fprintf(stderr, "Failed to connect to %s:%s\n", host, port); exit(1); } struct s2n_config *config = s2n_config_new(); setup_s2n_config(config, cipher_prefs, type, &unsafe_verify_data, host, alpn_protocols, mfl_value); if (ca_file || ca_dir) { if (s2n_config_set_verification_ca_location(config, ca_file, ca_dir) < 0) { print_s2n_error("Error setting CA file for trust store."); } } else if (insecure) { GUARD_EXIT(s2n_config_disable_x509_verification(config), "Error disabling X.509 validation"); } if (session_ticket) { GUARD_EXIT(s2n_config_set_session_tickets_onoff(config, 1), "Error enabling session tickets"); } struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT); if (conn == NULL) { print_s2n_error("Error getting new connection"); exit(1); } GUARD_EXIT(s2n_connection_set_config(conn, config), "Error setting configuration"); GUARD_EXIT(s2n_set_server_name(conn, server_name), "Error setting server name"); GUARD_EXIT(s2n_connection_set_fd(conn, sockfd) , "Error setting file descriptor"); if (use_corked_io) { GUARD_EXIT(s2n_connection_use_corked_io(conn), "Error setting corked io"); } /* Update session state in connection if exists */ if (session_state_length > 0) { GUARD_EXIT(s2n_connection_set_session(conn, session_state, session_state_length), "Error setting session state in connection"); } /* See echo.c */ int ret = negotiate(conn); if (ret != 0) { /* Error is printed in negotiate */ return -1; } printf("Connected to %s:%s\n", host, port); /* Save session state from connection if reconnect is enabled */ if (reconnect > 0) { if (!session_ticket && s2n_connection_get_session_id_length(conn) <= 0) { printf("Endpoint sent empty session id so cannot resume session\n"); exit(1); } free(session_state); session_state_length = s2n_connection_get_session_length(conn); session_state = calloc(session_state_length, sizeof(uint8_t)); if (s2n_connection_get_session(conn, session_state, session_state_length) != session_state_length) { print_s2n_error("Error getting serialized session state"); exit(1); } } if (dyn_rec_threshold > 0 && dyn_rec_timeout > 0) { s2n_connection_set_dynamic_record_threshold(conn, dyn_rec_threshold, dyn_rec_timeout); } if (echo_input == 1) { echo(conn, sockfd); } s2n_blocked_status blocked; s2n_shutdown(conn, &blocked); GUARD_EXIT(s2n_connection_free(conn), "Error freeing connection"); GUARD_EXIT(s2n_config_free(config), "Error freeing configuration"); close(sockfd); reconnect--; } while (reconnect >= 0); GUARD_EXIT(s2n_cleanup(), "Error running s2n_cleanup()"); free(session_state); freeaddrinfo(ai_list); return 0; }
int main(int argc, char **argv) { struct s2n_connection *conn; struct s2n_config *config; int status; pid_t pid; int server_to_client[2]; int client_to_server[2]; BEGIN_TEST(); EXPECT_SUCCESS(setenv("S2N_ENABLE_CLIENT_MODE", "1", 0)); /* Create a pipe */ EXPECT_SUCCESS(s2n_init()); for (int is_dh_key_exchange = 0; is_dh_key_exchange <= 1; is_dh_key_exchange++) { EXPECT_SUCCESS(pipe(server_to_client)); EXPECT_SUCCESS(pipe(client_to_server)); /* Create a child process */ pid = fork(); if (pid == 0) { /* This is the child process, close the read end of the pipe */ EXPECT_SUCCESS(close(client_to_server[0])); EXPECT_SUCCESS(close(server_to_client[1])); /* Write the fragmented hello message */ mock_client(client_to_server[1], server_to_client[0]); } /* This is the parent */ EXPECT_SUCCESS(close(client_to_server[1])); EXPECT_SUCCESS(close(server_to_client[0])); EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_NOT_NULL(config = s2n_config_new()); EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key(config, certificate, private_key)); if (is_dh_key_exchange) { EXPECT_SUCCESS(s2n_config_add_dhparams(config, dhparams)); } EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); /* Set up the connection to read from the fd */ EXPECT_SUCCESS(s2n_connection_set_read_fd(conn, client_to_server[0])); EXPECT_SUCCESS(s2n_connection_set_write_fd(conn, server_to_client[1])); /* Negotiate the handshake. */ EXPECT_SUCCESS(s2n_negotiate(conn, &status)); char buffer[0xffff]; for (int i = 1; i < 0xffff; i += 100) { char * ptr = buffer; int bytes_read = 0; int size = i; do { EXPECT_SUCCESS(bytes_read = s2n_recv(conn, ptr, size, &status)); size -= bytes_read; ptr += bytes_read; } while(size); for (int j = 0; j < i; j++) { EXPECT_EQUAL(buffer[j], 33); } } /* Verify that read() returns EOF */ EXPECT_SUCCESS(s2n_recv(conn, buffer, 1, &status)); EXPECT_SUCCESS(s2n_shutdown(conn, &status)); EXPECT_SUCCESS(s2n_connection_free(conn)); EXPECT_SUCCESS(s2n_config_free(config)); /* Clean up */ EXPECT_EQUAL(waitpid(-1, &status, 0), pid); EXPECT_EQUAL(status, 0); } END_TEST(); return 0; }
int main(int argc, char * const *argv) { struct addrinfo hints, *ai_list, *ai; int r, sockfd = 0; /* Optional args */ const char *alpn_protocols = NULL; const char *server_name = NULL; s2n_status_request_type type = S2N_STATUS_REQUEST_NONE; /* required args */ const char *host = NULL; const char *port = "443"; static struct option long_options[] = { { "alpn", required_argument, 0, 'a' }, { "help", no_argument, 0, 'h' }, { "name", required_argument, 0, 'n' }, { "status", no_argument, 0, 's' }, }; while (1) { int option_index = 0; int c = getopt_long (argc, argv, "a:hn:s", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'a': alpn_protocols = optarg; break; case 'h': usage(); break; case 'n': server_name = optarg; break; case 's': type = S2N_STATUS_REQUEST_OCSP; break; case '?': default: usage(); break; } } if (optind < argc) { host = argv[optind++]; } if (optind < argc) { port = argv[optind++]; } if (!host) { usage(); } if (!server_name) { server_name = host; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { fprintf(stderr, "Error disabling SIGPIPE\n"); exit(1); } if ((r = getaddrinfo(host, port, &hints, &ai_list)) != 0) { fprintf(stderr, "error: %s\n", gai_strerror(r)); exit(1); } int connected = 0; for (ai = ai_list; ai != NULL; ai = ai->ai_next) { if ((sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) { continue; } if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == -1) { close(sockfd); continue; } connected = 1; /* connect() succeeded */ break; } freeaddrinfo(ai_list); if (connected == 0) { fprintf(stderr, "Failed to connect to %s:%s\n", argv[1], port); close(sockfd); exit(1); } if (s2n_init() < 0) { fprintf(stderr, "Error running s2n_init(): '%s'\n", s2n_strerror(s2n_errno, "EN")); } struct s2n_config *config = s2n_config_new(); if (config == NULL) { fprintf(stderr, "Error getting new config: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } if (s2n_config_set_status_request_type(config, type) < 0) { fprintf(stderr, "Error setting status request type: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } if (alpn_protocols) { /* Count the number of commas, this tells us how many protocols there are in the list */ const char *ptr = alpn_protocols; int protocol_count = 1; while (*ptr) { if (*ptr == ',') { protocol_count++; } ptr++; } char **protocols = malloc(sizeof(char *) * protocol_count); if (!protocols) { fprintf(stderr, "Error allocating memory\n"); exit(1); } const char *next = alpn_protocols; int index = 0; int length = 0; ptr = alpn_protocols; while (*ptr) { if (*ptr == ',') { protocols[index] = malloc(length + 1); if (!protocols[index]) { fprintf(stderr, "Error allocating memory\n"); exit(1); } memcpy(protocols[index], next, length); protocols[index][length] = '\0'; length = 0; index++; ptr++; next = ptr; } else { length++; ptr++; } } if (ptr != next) { protocols[index] = malloc(length + 1); if (!protocols[index]) { fprintf(stderr, "Error allocating memory\n"); exit(1); } memcpy(protocols[index], next, length); protocols[index][length] = '\0'; } if (s2n_config_set_protocol_preferences(config, (const char * const *)protocols, protocol_count) < 0) { fprintf(stderr, "Failed to set protocol preferences: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } while(protocol_count) { protocol_count--; free(protocols[protocol_count]); } free(protocols); } struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT); if (conn == NULL) { fprintf(stderr, "Error getting new connection: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } printf("Connected to %s:%s\n", host, port); if (s2n_connection_set_config(conn, config) < 0) { fprintf(stderr, "Error setting configuration: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } if (s2n_set_server_name(conn, server_name) < 0) { fprintf(stderr, "Error setting server name: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } if (s2n_connection_set_fd(conn, sockfd) < 0) { fprintf(stderr, "Error setting file descriptor: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } /* See echo.c */ negotiate(conn); echo(conn, sockfd); s2n_blocked_status blocked; if (s2n_shutdown(conn, &blocked) < 0) { fprintf(stderr, "Error calling s2n_shutdown: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } if (s2n_connection_free(conn) < 0) { fprintf(stderr, "Error freeing connection: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } if (s2n_config_free(config) < 0) { fprintf(stderr, "Error freeing configuration: '%s'\n", s2n_strerror(s2n_errno, "EN")); exit(1); } if (s2n_cleanup() < 0) { fprintf(stderr, "Error running s2n_cleanup(): '%s'\n", s2n_strerror(s2n_errno, "EN")); } return 0; }
int main(int argc, char **argv) { if(argc != 2) { fprintf(stderr,"usage: %s hostname\n", argv[0]); return 1; } signal(SIGINT, sigint_handler); printf("Looking up addresses for %s ...\n", argv[1]); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version hints.ai_socktype = SOCK_STREAM; struct addrinfo *dnsres; int status_1 = getaddrinfo(argv[1], PORT, &hints, &dnsres); if(status_1 != 0) { fprintf(stderr, "dns lookup failed: %s\n", gai_strerror(status_1)); return 2; } print_addrinfo(dnsres); printf("Connecting to %s ...\n", "the server"); int sockfd = socket(dnsres->ai_family, dnsres->ai_socktype, dnsres->ai_protocol); if(connect(sockfd, dnsres->ai_addr, dnsres->ai_addrlen) != 0) { perror("connect"); return 3; } printf("Connected.\n"); freeaddrinfo(dnsres); // frees the memory that was dynamically allocated for the linked lists by getaddrinfo s2n_init(); struct s2n_config *config = s2n_config_new(); s2n_status_request_type type = S2N_STATUS_REQUEST_NONE; s2n_config_set_status_request_type(config, type); struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT); s2n_connection_set_config(conn, config); s2n_connection_set_fd(conn, sockfd); s2n_blocked_status blocked; do { if (s2n_negotiate(conn, &blocked) < 0) { fprintf(stderr, "Failed to negotiate: '%s' %d\n", s2n_strerror(s2n_errno, "EN"), s2n_connection_get_alert(conn)); exit(1); } } while (blocked); int client_hello_version; int client_protocol_version; int server_protocol_version; int actual_protocol_version; if ((client_hello_version = s2n_connection_get_client_hello_version(conn)) < 0) { fprintf(stderr, "Could not get client hello version\n"); exit(1); } if ((client_protocol_version = s2n_connection_get_client_protocol_version(conn)) < 0) { fprintf(stderr, "Could not get client protocol version\n"); exit(1); } if ((server_protocol_version = s2n_connection_get_server_protocol_version(conn)) < 0) { fprintf(stderr, "Could not get server protocol version\n"); exit(1); } if ((actual_protocol_version = s2n_connection_get_actual_protocol_version(conn)) < 0) { fprintf(stderr, "Could not get actual protocol version\n"); exit(1); } printf("Client hello version: %d\n", client_hello_version); printf("Client protocol version: %d\n", client_protocol_version); printf("Server protocol version: %d\n", server_protocol_version); printf("Actual protocol version: %d\n", actual_protocol_version); if (s2n_get_server_name(conn)) { printf("Server name: %s\n", s2n_get_server_name(conn)); } if (s2n_get_application_protocol(conn)) { printf("Application protocol: %s\n", s2n_get_application_protocol(conn)); } uint32_t length; const uint8_t *status = s2n_connection_get_ocsp_response(conn, &length); if (status && length > 0) { fprintf(stderr, "OCSP response received, length %d\n", length); } printf("Cipher negotiated: %s\n", s2n_connection_get_cipher(conn)); char buf[BUFFERSIZE + 1]; int bytes_read, bytes_written; // Make sure stdin is a terminal. if (!isatty(STDIN_FILENO)) { fprintf(stderr, "Not a terminal.\n"); exit(EXIT_FAILURE); } // Save the terminal attributes so we can restore them later. tcgetattr(STDIN_FILENO, &saved_attributes); atexit(reset_input_mode); // Set the funny terminal modes. struct termios tattr; tcgetattr(STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON | ECHO); // Clear ICANON and ECHO. tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr); fd_set master, readfds; FD_ZERO(&master); FD_SET(STDIN_FILENO, &master); FD_SET(sockfd, &master); for(;;) { readfds = master; select(sockfd + 1, &readfds, NULL, NULL, NULL); if(FD_ISSET(STDIN_FILENO, &readfds)) { bytes_read = read(STDIN_FILENO, buf, BUFFERSIZE); if(bytes_read < 1) break; char *buf_ptr = buf; int bytes_available = bytes_read; do { bytes_written = s2n_send(conn, buf_ptr, bytes_available, &blocked); if(bytes_written < 0) break; bytes_available -= bytes_written; buf_ptr += bytes_written; } while(bytes_available || blocked); } if(FD_ISSET(sockfd, &readfds)) { do { bytes_read = s2n_recv(conn, buf, BUFFERSIZE, &blocked); if(bytes_read < 1) break; write(STDOUT_FILENO, buf, bytes_read); } while(blocked); } //if(nbytes != mbytes) printf("nbytes [%d] != mbytes [%d] \n", nbytes, mbytes); } close(sockfd); s2n_connection_free(conn); s2n_config_free(config); s2n_cleanup(); printf("\nBYE!\n"); return 0; }