Last active
February 4, 2025 22:24
-
-
Save richard-ramos/e01c9ec091a67e2e6042a86bf7359c26 to your computer and use it in GitHub Desktop.
PicoTLS Handshake
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // client.c | |
| #include <picotls.h> | |
| #include "picotls/openssl.h" | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <sys/socket.h> | |
| #include <arpa/inet.h> | |
| #include <unistd.h> | |
| #define PORT 8443 | |
| #define BUFFER_SIZE 1024 | |
| // In the same dir of picotls, after doing a `cmake .` and a `make`. | |
| // gcc client.c -o client libpicotls-core.a libpicotls-openssl.a -Iinclude -lcrypto | |
| int main(void) | |
| { | |
| int sock = 0; | |
| struct sockaddr_in serv_addr; | |
| char buffer[BUFFER_SIZE] = {0}; | |
| ptls_context_t ctx = { | |
| .random_bytes = ptls_openssl_random_bytes, | |
| .get_time = &ptls_get_time, | |
| .key_exchanges = ptls_openssl_key_exchanges, | |
| .cipher_suites = ptls_openssl_cipher_suites, | |
| }; | |
| if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
| perror("Socket creation failed"); | |
| return -1; | |
| } | |
| serv_addr.sin_family = AF_INET; | |
| serv_addr.sin_port = htons(PORT); | |
| if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { | |
| perror("Invalid address"); | |
| return -1; | |
| } | |
| if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { | |
| perror("Connection failed"); | |
| return -1; | |
| } | |
| printf("Connected to server\n"); | |
| // Create TLS connection | |
| ptls_t *tls = ptls_new(&ctx, 0); // 0 for client | |
| if (tls == NULL) { | |
| fprintf(stderr, "Failed to create TLS context\n"); | |
| return -1; | |
| } | |
| ptls_buffer_t sendbuf, recvbuf; | |
| ptls_buffer_init(&sendbuf, "", 0); | |
| ptls_buffer_init(&recvbuf, "", 0); | |
| // Perform handshake | |
| int ret; | |
| ptls_handshake_properties_t props = {}; | |
| // Start handshake | |
| ret = ptls_handshake(tls, &sendbuf, NULL, 0, &props); | |
| if (ret != PTLS_ERROR_IN_PROGRESS) { | |
| fprintf(stderr, "Failed to initiate handshake: %d\n", ret); | |
| return -1; | |
| } | |
| // Send initial handshake data | |
| if (sendbuf.off > 0) { | |
| send(sock, sendbuf.base, sendbuf.off, 0); | |
| ptls_buffer_dispose(&sendbuf); | |
| ptls_buffer_init(&sendbuf, "", 0); | |
| } | |
| // Continue handshake until complete | |
| while (ptls_handshake_is_complete(tls) == 0) { | |
| size_t received = recv(sock, buffer, BUFFER_SIZE, 0); | |
| if (received == 0) { | |
| fprintf(stderr, "Connection closed during handshake\n"); | |
| goto Exit; | |
| } | |
| ret = ptls_handshake(tls, &sendbuf, buffer, &received, &props); | |
| if (ret != 0 && ret != PTLS_ERROR_IN_PROGRESS) { | |
| fprintf(stderr, "Handshake failed: %d %d\n", ret, PTLS_ERROR_IN_PROGRESS); | |
| goto Exit; | |
| } | |
| if (sendbuf.off > 0) { | |
| send(sock, sendbuf.base, sendbuf.off, 0); | |
| ptls_buffer_dispose(&sendbuf); | |
| ptls_buffer_init(&sendbuf, "", 0); | |
| } | |
| } | |
| printf("Handshake completed successfully\n"); | |
| // Send encrypted message | |
| const char *message = "Hello, Server!"; | |
| ptls_buffer_t encbuf; | |
| ptls_buffer_init(&encbuf, "", 0); | |
| ret = ptls_send(tls, &encbuf, message, strlen(message)); | |
| if (ret != 0) { | |
| fprintf(stderr, "Failed to encrypt message: %d\n", ret); | |
| goto Exit; | |
| } | |
| send(sock, encbuf.base, encbuf.off, 0); | |
| printf("Sent encrypted message: %s\n", message); | |
| Exit: | |
| ptls_buffer_dispose(&encbuf); | |
| ptls_buffer_dispose(&sendbuf); | |
| ptls_buffer_dispose(&recvbuf); | |
| ptls_free(tls); | |
| close(sock); | |
| return 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // server.c | |
| #include <picotls.h> | |
| #include <picotls/openssl.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <sys/socket.h> | |
| #include <netinet/in.h> | |
| #include <unistd.h> | |
| #include <openssl/pem.h> | |
| // generate key | |
| // openssl ecparam -name prime256v1 -genkey -noout -out server.key | |
| // generate cert | |
| // openssl req -new -x509 -key server.key -out server.crt -days 365 -subj "/CN=localhost" | |
| // gcc server.c -o server libpicotls-core.a libpicotls-openssl.a -Iinclude -lcrypto | |
| #define PORT 8443 | |
| #define BUFFER_SIZE 1024 | |
| int main(void) | |
| { | |
| int server_fd, client_fd; | |
| struct sockaddr_in address; | |
| int opt = 1; | |
| int addrlen = sizeof(address); | |
| char buffer[BUFFER_SIZE] = {0}; | |
| ptls_openssl_sign_certificate_t sign_cert; | |
| // Load the private key | |
| FILE *fp = fopen("server.key", "rb"); | |
| if (!fp) { | |
| perror("Failed to open private key file"); | |
| return -1; | |
| } | |
| EVP_PKEY *pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); | |
| fclose(fp); | |
| if (!pkey) { | |
| perror("Failed to read private key"); | |
| return -1; | |
| } | |
| // Initialize the certificate signing structure | |
| ptls_openssl_init_sign_certificate(&sign_cert, pkey); | |
| EVP_PKEY_free(pkey); // Free the key, as it's now managed by sign_cert | |
| ptls_context_t ctx = { | |
| .random_bytes = ptls_openssl_random_bytes, | |
| .get_time = &ptls_get_time, | |
| .key_exchanges = ptls_openssl_key_exchanges, | |
| .cipher_suites = ptls_openssl_cipher_suites, | |
| .sign_certificate = &sign_cert.super, | |
| }; | |
| // Load server certificate and key | |
| ptls_load_certificates(&ctx, "server.crt"); | |
| if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { | |
| perror("Socket creation failed"); | |
| return -1; | |
| } | |
| if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { | |
| perror("Setsockopt failed"); | |
| return -1; | |
| } | |
| address.sin_family = AF_INET; | |
| address.sin_addr.s_addr = INADDR_ANY; | |
| address.sin_port = htons(PORT); | |
| if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { | |
| perror("Bind failed"); | |
| return -1; | |
| } | |
| if (listen(server_fd, 3) < 0) { | |
| perror("Listen failed"); | |
| return -1; | |
| } | |
| printf("Server listening on port %d...\n", PORT); | |
| if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { | |
| perror("Accept failed"); | |
| return -1; | |
| } | |
| printf("Client connected\n"); | |
| // Create TLS connection | |
| ptls_t *tls = ptls_new(&ctx, 1); // 1 for server | |
| if (tls == NULL) { | |
| fprintf(stderr, "Failed to create TLS context\n"); | |
| return -1; | |
| } | |
| ptls_buffer_t sendbuf, recvbuf; | |
| ptls_buffer_init(&sendbuf, "", 0); | |
| ptls_buffer_init(&recvbuf, "", 0); | |
| // Handle handshake | |
| int ret; | |
| ptls_handshake_properties_t props = {}; | |
| int handshake_complete = 0; | |
| while (!handshake_complete) { | |
| size_t received = recv(client_fd, buffer, BUFFER_SIZE, 0); | |
| if (received == 0) { | |
| fprintf(stderr, "Connection closed during handshake\n"); | |
| goto Exit; | |
| } | |
| ret = ptls_handshake(tls, &sendbuf, buffer, &received, &props); | |
| if (ret == 0) { | |
| handshake_complete = 1; | |
| } else if (ret != PTLS_ERROR_IN_PROGRESS) { | |
| fprintf(stderr, "Handshake failed: %d\n", ret); | |
| goto Exit; | |
| } | |
| if (sendbuf.off > 0) { | |
| send(client_fd, sendbuf.base, sendbuf.off, 0); | |
| ptls_buffer_dispose(&sendbuf); | |
| ptls_buffer_init(&sendbuf, "", 0); | |
| } | |
| } | |
| printf("Handshake completed successfully\n"); | |
| // Receive and decrypt data | |
| while (1) { | |
| size_t received = recv(client_fd, buffer, BUFFER_SIZE, 0); | |
| if (received == 0) { | |
| printf("Connection closed by client\n"); | |
| break; | |
| } | |
| ret = ptls_receive(tls, &recvbuf, buffer, received); | |
| if (ret == 0) { | |
| printf("Received: %.*s\n", (int)recvbuf.off, (char *)recvbuf.base); | |
| ptls_buffer_dispose(&recvbuf); | |
| ptls_buffer_init(&recvbuf, "", 0); | |
| } | |
| } | |
| Exit: | |
| ptls_buffer_dispose(&sendbuf); | |
| ptls_buffer_dispose(&recvbuf); | |
| ptls_free(tls); | |
| close(client_fd); | |
| close(server_fd); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment