diff options
| author | Ian Moffett <ian@osmora.org> | 2024-09-29 18:26:07 -0400 | 
|---|---|---|
| committer | Ian Moffett <ian@osmora.org> | 2024-09-29 18:26:07 -0400 | 
| commit | 6107a37ae0f8ad89ab6d2d36f93cc0d47f8bb47a (patch) | |
| tree | f9172d51fb8a36b934843610cdc9a38cbbfc52da | |
| parent | 8e470bc3663da4a5bbb771a4a6fbaf8a4cae224d (diff) | |
project: Move server/client code into library
Signed-off-by: Ian Moffett <ian@osmora.org>
| -rw-r--r-- | client/main.c | 190 | ||||
| -rw-r--r-- | lib/include/libostp/server.h (renamed from ostp.d/include/net/listen.h) | 27 | ||||
| -rw-r--r-- | lib/include/libostp/session.h | 75 | ||||
| -rw-r--r-- | lib/include/net/auth.h (renamed from ostp.d/include/net/auth.h) | 7 | ||||
| -rw-r--r-- | lib/include/otconfig.h (renamed from ostp.d/include/otconfig.h) | 0 | ||||
| -rw-r--r-- | lib/libostp/auth.c (renamed from ostp.d/net/otd_auth.c) | 120 | ||||
| -rw-r--r-- | lib/libostp/param.c (renamed from ostp.d/net/otd_param.c) | 25 | ||||
| -rw-r--r-- | lib/libostp/server.c (renamed from ostp.d/net/otd_listen.c) | 173 | ||||
| -rw-r--r-- | lib/libostp/session.c | 299 | ||||
| -rw-r--r-- | ostp.d/init/main.c (renamed from ostp.d/init/otd_init.c) | 27 | 
10 files changed, 600 insertions, 343 deletions
| diff --git a/client/main.c b/client/main.c index 6bc5a5e..0f87639 100644 --- a/client/main.c +++ b/client/main.c @@ -27,186 +27,38 @@   * POSSIBILITY OF SUCH DAMAGE.   */ -#include <net/stpsession.h> -#include <net/param.h> -#include <crypto/ecdh.h> -#include <arpa/inet.h> -#include <defs.h> +#include <libostp/session.h>  #include <stdio.h> -#include <stdint.h> -#include <unistd.h> -#include <string.h>  #define CENTRAL_SERVER "149.248.6.149" -#define OSTP_PORT 5352 +// #define CENTRAL_SERVER "127.0.0.1" -static const char *pap_codestr[] = { -    [PAP_SUCCESS]   = "success", -    [PAP_BAD_SPW]   = "bad SPW", -    [PAP_BAD_PERMS] = "insufficient permissions", -    [PAP_RESOURCE]  = "server out of resources" -}; - -static void -log_pubkey(uint8_t pubkey[]) +int +main(int argc, char **argv)  { -    for (size_t i = 0; i < 32; ++i) { -        printf("%02X ", pubkey[i] & 0xFF); -        if (i != 0 && i % 4 == 0) { -            printf("\n"); -        } +    char buf[] = "Hello, World!\n"; +    char recv_buf[4096]; +    struct ostp_session s; +    int err; + +    if ((err = session_new(CENTRAL_SERVER, &s)) < 0) { +        fprintf(stderr, "Failed to create new session!\n"); +        return err;      } -    printf("\n"); -} - -static int -negotiate_spw(int sockfd, const unsigned char *session_key) -{ -    struct aes_message am; -    struct msg_frame msg_frame; -    struct pap pap; -    unsigned char *tmp; -    int error; - -    /* Create a PAP and encrypt it */ -    pap.spw = 0x8000; -    pap.code = 0; - -    while (1) { -        if ((error = send_frame(sockfd, &pap, sizeof(pap), session_key)) < 0) { -            return error; -        } - -        /* Receive the PAP the server replies with */ -        if ((error = recv_frame(sockfd, sizeof(pap), session_key, &pap)) < 0) { -            return error; -        } -        /* -         * If the server echos our PAP with code 0 then it has -         * applied our session parameters! However, there is -         * a chance arbitration will be needed and we need -         * to look out for that too... -         */ -        if (pap.code == 0) { -            printf("** Negotiation success\n"); -            break; +    if (argc >= 2) { +        if (session_send(buf, sizeof(buf), &s) < 0) { +            fprintf(stderr, "Failed to send data to server!\n"); +            return -1;          } - -        printf("** Arbitration needed, server says: %s\n", pap_codestr[pap.code]); -        printf("** Server proposes SPW of 0x%0X, accepting\n", pap.spw); -        pap.spw |= PAP_SPW_QSR; -        pap.code = 0; -    } - -    return 0; -} - -static void -recv_motd(int sockfd, const unsigned char *session_key) -{ -    char buf[4096]; -    int len; - -    /* Receive the PAP the server replies with */ -    if ((len = recv_frame(sockfd, sizeof(buf), session_key, buf)) < 0) { -        printf("Failed to recv MOTD...\n"); -        return; -    } - -    buf[len] = '\0'; -    printf("%s\n", buf); -} - -static int -request_session(void) -{ -    struct sockaddr_in addr; -    struct session_request stp_sq; -    struct x25519_keypair keypair; -    unsigned char serv_pubkey[32]; -    unsigned char *session_key; -    int error, sockfd; - -    addr.sin_family = AF_INET; -    addr.sin_addr.s_addr = inet_addr(CENTRAL_SERVER); -    addr.sin_port = htons(OSTP_PORT); - -    sockfd = socket(AF_INET, SOCK_STREAM, 0); -    if (sockfd < 0) { -        return sockfd; -    } - -    error = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); -    if (error < 0) { -        printf("Failed to connect!\n"); -        close(sockfd); -        return error; -    } - -    printf("Generating keys...\n"); - -    /* Generate an ephemeral keypair */ -    if ((error = gen_x25519_keypair(&keypair)) < 0) { -        printf("Key generation failed!\n"); -        close(sockfd); -        return error; -    } - -    /* -     * Setup the session request and add our public -     * key to it. -     * -     * TODO: Use the 'U' bit in options. -     */ -    memset(stp_sq.hash, 0, sizeof(stp_sq.hash)); -    stp_sq.options = 0; -    memcpy(stp_sq.pubkey, keypair.pubkey, sizeof(stp_sq.pubkey)); -    log_pubkey(keypair.pubkey); - -    printf("Sending session request...\n"); -    error = send(sockfd, &stp_sq, sizeof(stp_sq), 0); -    if (error < 0) { -        perror("Failed to send session request"); -        close(sockfd); -        return error; -    } - -    error = recv(sockfd, serv_pubkey, sizeof(serv_pubkey), 0); -    if (error < 0) { -        perror("Failed to get public key from peer\n"); -        close(sockfd); -        return error;      } -    if (error == 0) { -        printf("Connection closed by peer\n"); -        close(sockfd); -        return 0; +    if (session_recv(recv_buf, sizeof(recv_buf), &s) < 0) { +        fprintf(stderr, "Failed to recv data from server!\n"); +        return -1;      } -    printf("Got public key from server\n"); -    log_pubkey(serv_pubkey); - -    printf("Deriving session key...\n"); -    gen_session_key(keypair.privkey, serv_pubkey, &session_key); - -    /* Send server SPW bits */ -    if ((error = negotiate_spw(sockfd, session_key)) < 0) { -        printf("Session Parameter Negotiation failed\n"); -        free_session_key(session_key); -        close(sockfd); -        return error; -    } - -    recv_motd(sockfd, session_key); -    free_session_key(session_key); -    close(sockfd); +    printf("%s\n", recv_buf); +    session_close(&s);      return 0;  } - -int -main(void) -{ -    return request_session(); -} diff --git a/ostp.d/include/net/listen.h b/lib/include/libostp/server.h index 03ba7a4..a7a737b 100644 --- a/ostp.d/include/net/listen.h +++ b/lib/include/libostp/server.h @@ -27,9 +27,28 @@   * POSSIBILITY OF SUCH DAMAGE.   */ -#ifndef NET_LISTEN_H_ -#define NET_LISTEN_H_ +#ifndef LIBOSTP_SERVER_H_ +#define LIBOSTP_SERVER_H_ -int net_listen(void); +#include <sys/select.h> +#include <libostp/session.h> +#include <stddef.h> -#endif  /* NET_LISTEN_H_ */ +#define MAX_CLIENTS 32 + +struct ostp_listener { +    int(*on_recv)(struct ostp_session *session, const char *buf, size_t len); +    int port; + +    /* -- Private -- */ +    int clients[MAX_CLIENTS]; +    int serv_sockfd; +    fd_set client_fds; +}; + +void listener_init(struct ostp_listener *lp); +int listener_bind(struct ostp_session *sp, struct ostp_listener *lp); +int listener_poll(struct ostp_session *sp, struct ostp_listener *lp); +void listener_cleanup(struct ostp_listener *lp); + +#endif  /* !LIBOSTP_SERVER_H_ */ diff --git a/lib/include/libostp/session.h b/lib/include/libostp/session.h new file mode 100644 index 0000000..591ac0e --- /dev/null +++ b/lib/include/libostp/session.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + *    contributors may be used to endorse or promote products derived from + *    this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LIBOSTP_SESSION_H_ +#define LIBOSTP_SESSION_H_ + +#include <stdint.h> + +#define LIBOSTP_DEBUG 1 + +struct ostp_session { +    unsigned char *session_key; +    int sockfd; +}; + +/* + * Create a new ostp ostp_session. + * + * @host: IPv4 address of OST host. + * @res: Output for new ostp_session structure. + */ +int session_new(const char *host, struct ostp_session *res); + +/* + * Close an existing/running ostp_session. + * + * @ostp_session: Session to close. + */ +int session_close(struct ostp_session *session); + +/* + * Encrypt and send data to server. + * + * @data: Data to send. + * @len: Length of data. + * @ostp_session: Running ostp_session. + */ +int session_send(void *data, uint16_t len, const struct ostp_session *session); + +/* + * Receive data from the server. + * + * @buf: Buffer for received data. + * @len: Length of buffer. + * @ostp_session: Running ostp_session. + */ +int session_recv(void *buf, uint16_t len, const struct ostp_session *session); + +#endif      /* LIBOSTP_SESSION_H_ */ diff --git a/ostp.d/include/net/auth.h b/lib/include/net/auth.h index 76567c3..d672231 100644 --- a/ostp.d/include/net/auth.h +++ b/lib/include/net/auth.h @@ -31,8 +31,11 @@  #define NET_AUTH_H_  #include <net/stpsession.h> +#include <libostp/session.h> +#include <libostp/server.h> -int handle_srq(int client_fd, struct session_request *srq); -int negotiate_spw(int client_fd, unsigned char *session_key); +int handle_srq(struct ostp_session *sp, struct ostp_listener *lp, +    struct session_request *srq); +int negotiate_spw(struct ostp_session *sp, unsigned char *session_key);  #endif  /* NET_AUTH_H_ */ diff --git a/ostp.d/include/otconfig.h b/lib/include/otconfig.h index 9487556..9487556 100644 --- a/ostp.d/include/otconfig.h +++ b/lib/include/otconfig.h diff --git a/ostp.d/net/otd_auth.c b/lib/libostp/auth.c index 67b4885..d32c06a 100644 --- a/ostp.d/net/otd_auth.c +++ b/lib/libostp/auth.c @@ -28,41 +28,13 @@   */  #include <sys/wait.h> -#include <arpa/inet.h>  #include <net/auth.h> -#include <net/listen.h> -#include <net/param.h> -#include <net/stpsession.h>  #include <crypto/ecdh.h>  #include <otconfig.h> +#include <arpa/inet.h>  #include <stdio.h>  #include <unistd.h> - -#define KEY_BYTE_WIDTH 32 - -static void -log_pubkey(uint8_t pubkey[KEY_BYTE_WIDTH]) -{ -    for (size_t i = 0; i < KEY_BYTE_WIDTH; ++i) { -        printf("%02X ", pubkey[i] & 0xFF); -        if (i != 0 && i % 4 == 0) { -            printf("\n"); -        } -    } - -    printf("\n"); -} - -static void -send_motd(int client_fd, const unsigned char *session_key) -{ -    char motd[] = MOTD; - -    printf("Sending MOTD...\n"); -    if (send_frame(client_fd, motd, sizeof(motd), session_key) < 0) { -        printf("Failed to session MOTD\n"); -    } -} +#include <stdlib.h>  /*   * Check a password to see if it matches with @@ -95,7 +67,7 @@ pwcheck(char *username, char *pw)  }  static int -passwd_auth(int client_fd, const unsigned char *session_key) +passwd_auth(struct ostp_session *sp, const unsigned char *session_key)  {      int error;      struct session_auth auth; @@ -105,7 +77,7 @@ passwd_auth(int client_fd, const unsigned char *session_key)          return 0;      } -    error = recv_frame(client_fd, sizeof(auth), session_key, &auth); +    error = recv_frame(sp->sockfd, sizeof(auth), session_key, &auth);      if (error < 0) {          return error;      } @@ -113,7 +85,7 @@ passwd_auth(int client_fd, const unsigned char *session_key)      if (pwcheck(auth.username, auth.password) != 0) {          printf("Got bad password for %s\n", auth.username);          auth.code = AUTH_BAD_PW; -        error = send_frame(client_fd, &auth, sizeof(auth), session_key); +        error = send_frame(sp->sockfd, &auth, sizeof(auth), session_key);          if (error < 0) {              printf("Failed to ACK user authentication with frame\n");          } @@ -121,7 +93,7 @@ passwd_auth(int client_fd, const unsigned char *session_key)      }      auth.code = AUTH_SUCCESS; -    error = send_frame(client_fd, &auth, sizeof(auth), session_key); +    error = send_frame(sp->sockfd, &auth, sizeof(auth), session_key);      if (error < 0) {          printf("Failed to ACK user authentication with frame\n");          return error; @@ -129,39 +101,52 @@ passwd_auth(int client_fd, const unsigned char *session_key)      return 0;  } -static int -client_echo(int client_fd, const unsigned char *session_key) +static void +send_motd(struct ostp_session *sp, const unsigned char *session_key)  { -    char buf[4096]; -    int error; +    char motd[] = MOTD; -    error = recv_frame(client_fd, sizeof(buf) - 1, session_key, buf); -    if (error < 0) { -        return error; +    printf("Sending MOTD...\n"); +    if (send_frame(sp->sockfd, motd, sizeof(motd), session_key) < 0) { +        printf("Failed to session MOTD\n");      } +} -    /* Echo frame to all clients */ -    for (size_t i = 1; i < MAX_CLIENTS; ++i) { -        if (clients[i] <= 0) -            continue; - -        send_frame(clients[i], buf, sizeof(buf), session_key); +static int +session_run(struct ostp_session *sp, struct ostp_listener *lp, +    const unsigned char *session_key) +{ +    char buf[4096]; +    size_t len; + +    while (1) { +        for (int i = 1; i < MAX_CLIENTS; ++i) { +            if (lp->clients[i] <= 0) +                continue; +            if (FD_ISSET(lp->clients[i], &lp->client_fds) <= 0) +                continue; + +            len = recv_frame(lp->clients[i], sizeof(buf) - 1, session_key, buf); +            if (len < 0) { +                printf("recv_frame() failure, packet lost\n"); +                continue; +            } +            if (len == 0) { +                return 0; +            } +            if (lp->on_recv != NULL) { +                lp->on_recv(sp, buf, len); +            } +        }      } - -    return 0;  } -/* - * Verify the session request packet and handle - * the rest. - * - * @client_fd: File descriptor for client socket. - * @srq: Session request packet. - */ +  int -handle_srq(int client_fd, struct session_request *srq) +handle_srq(struct ostp_session *sp, struct ostp_listener *lp, struct session_request *srq)  {      struct x25519_keypair keypair;      unsigned char *session_key; +    pid_t child;      int error;      if (REQUIRE_USER_AUTH && !ISSET(srq->options, SESSION_REQ_USER)) { @@ -171,8 +156,6 @@ handle_srq(int client_fd, struct session_request *srq)          return -1;      } -    printf("Got public key from peer: \n"); -    log_pubkey(srq->pubkey);      printf("Generating keys...\n");      if (gen_x25519_keypair(&keypair) < 0) { @@ -181,7 +164,7 @@ handle_srq(int client_fd, struct session_request *srq)      }      /* Send back our our public key */ -    error = send(client_fd, keypair.pubkey, keypair.pubkey_len, 0); +    error = send(sp->sockfd, keypair.pubkey, keypair.pubkey_len, 0);      if (error < 0) {          perror("Failed to send public key");          return error; @@ -193,13 +176,24 @@ handle_srq(int client_fd, struct session_request *srq)          return error;      } +    /* Try user auth, not needed if REQUIRE_USER_AUTH is 0 */ +    if (passwd_auth(sp, session_key) != 0) { +        return -1; +    } +      /* Handle any requested session parameters */ -    if ((error = negotiate_spw(client_fd, session_key)) < 0) { +    if ((error = negotiate_spw(sp, session_key)) < 0) {          free_session_key(session_key);          return error;      } -    send_motd(client_fd, session_key); -    free_session_key(session_key); +    send_motd(sp, session_key); + +    /* Dispatch a thread and handle this session */ +    child = fork(); +    if (child == 0) { +        session_run(sp, lp, session_key); +        exit(0); +    }      return 0;  } diff --git a/ostp.d/net/otd_param.c b/lib/libostp/param.c index fe33bd8..4c14733 100644 --- a/ostp.d/net/otd_param.c +++ b/lib/libostp/param.c @@ -28,18 +28,17 @@   */  #include <net/stpsession.h> -#include <net/param.h> +#include <libostp/session.h>  #include <crypto/aes.h> +#include <net/param.h> +#include <net/auth.h>  #include <otconfig.h> -#include <defs.h> -#include <string.h> -#include <stdlib.h>  #include <stdio.h>  static int -handle_pap(int client_fd, const struct pap *pap, const unsigned char *session_key) +handle_pap(struct ostp_session *sp, const struct pap *pap, const unsigned char *session_key)  { -    int error = 0; +    int error = -1;      uint8_t attempts = 0;      struct pap tmp_pap = *pap;      const size_t LEN = sizeof(struct pap); @@ -49,7 +48,7 @@ handle_pap(int client_fd, const struct pap *pap, const unsigned char *session_ke          /* Quick session request, jump right in! */          if (ISSET(tmp_pap.spw, PAP_SPW_QSR)) {              printf("Got QSR, starting session...\n"); -            send_frame(client_fd, &tmp_pap, LEN, session_key); +            send_frame(sp->sockfd, &tmp_pap, LEN, session_key);              return 0;          } @@ -62,15 +61,15 @@ handle_pap(int client_fd, const struct pap *pap, const unsigned char *session_ke          printf("Got bad SPW from client\n");          printf("Attempting arbitration...\n"); -        tmp_pap.spw = 0x0; +        tmp_pap.spw = 0;          tmp_pap.code = PAP_BAD_SPW;          /* Send in PAP and wait for response */ -        if ((error = send_frame(client_fd, &tmp_pap, LEN, session_key)) < 0) { +        if ((error = send_frame(sp->sockfd, &tmp_pap, LEN, session_key)) < -1) {              printf("Failed to send PAP frame\n");              return -1;          } -        if ((error = recv_frame(client_fd, LEN, session_key, &tmp_pap)) < 0) { +        if ((error = recv_frame(sp->sockfd, LEN, session_key, &tmp_pap)) < -1) {              printf("Failed to recv PAP frame\n");              return error;          } @@ -82,16 +81,16 @@ handle_pap(int client_fd, const struct pap *pap, const unsigned char *session_ke  }  int -negotiate_spw(int client_fd, unsigned char *session_key) +negotiate_spw(struct ostp_session *sp, unsigned char *session_key)  {      const size_t LEN = sizeof(struct pap);      struct pap pap;      int error;      /* Get PAP from the network */ -    if ((error = recv_frame(client_fd, LEN, session_key, &pap)) < 0) { +    if ((error = recv_frame(sp->sockfd, LEN, session_key, &pap)) < -1) {          return error;      } -    return handle_pap(client_fd, &pap, session_key); +    return handle_pap(sp, &pap, session_key);  } diff --git a/ostp.d/net/otd_listen.c b/lib/libostp/server.c index 216db33..0013ce2 100644 --- a/ostp.d/net/otd_listen.c +++ b/lib/libostp/server.c @@ -27,109 +27,128 @@   * POSSIBILITY OF SUCH DAMAGE.   */ -#include <sys/select.h> -#include <arpa/inet.h> +#include <libostp/server.h>  #include <net/auth.h>  #include <net/stpsession.h> -#include <defs.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <signal.h> -#include <errno.h> +#include <arpa/inet.h>  #include <string.h> +#include <unistd.h> +#include <stdio.h> -#define LISTEN_PORT 5352  #define MAX_BACKLOG 4 -#define MAX_CLIENTS 32 - -static int serv_sock; -static int clients[MAX_CLIENTS] = {0}; - -static void -signal_handle(int sig) -{ -    printf("Cleaning up... goodbye!\n"); - -    for (int i = 0; i < MAX_CLIENTS; ++i) { -        close(clients[i]); -    } - -    close(serv_sock); -    exit(0); -} +#define LISTEN_PORT 5352  static int -handle_client(struct sockaddr_in *caddr, int clientno) +handle_client(struct sockaddr_in *caddr, struct ostp_session *sp, struct ostp_listener *lp, +    int clientno)  {      struct session_request srq;      ssize_t nread; -    int client_fd; -    client_fd = clients[clientno]; +    sp->sockfd = lp->clients[clientno];      /* Try to read in the session request */ -    if ((nread = read(client_fd, &srq, sizeof(srq))) < 0) { +    if ((nread = read(sp->sockfd, &srq, sizeof(srq))) < 0) {          printf("Read failure...\n"); -        close(client_fd); -        clients[clientno] = -1; +        close(sp->sockfd); +        lp->clients[clientno] = -1;          return -1;      }      if (nread == 0) {          printf("Connection closed by peer\n"); -        close(client_fd); -        clients[clientno] = -1; +        close(sp->sockfd); +        lp->clients[clientno] = -1;          return -1;      }      /* Is this even a session request? */      if (nread != sizeof(srq)) {          printf("Rejecting data - not a session request...\n"); -        close(client_fd); -        clients[clientno] = -1; +        close(sp->sockfd); +        lp->clients[clientno] = -1;          return -1;      }      /* Handle the session request */ -    if (handle_srq(client_fd, &srq) < 0) { -        close(client_fd); -        clients[clientno] = -1; +    if (handle_srq(sp, lp, &srq) < 0) { +        close(sp->sockfd); +        lp->clients[clientno] = -1;          return -1;      }      return 0;  } -static void -read_clients(void) +/* + * Put a listener in a known state during + * initialization. + */ +void +listener_init(struct ostp_listener *lp) +{ +    lp->port = LISTEN_PORT; +    lp->on_recv = NULL; +} + +int +listener_bind(struct ostp_session *sp, struct ostp_listener *lp) +{ +    struct sockaddr_in saddr; +    int error; + +    lp->serv_sockfd = socket(AF_INET, SOCK_STREAM, 0); +    if (sp->sockfd < 0) { +        perror("Failed to create socket\n"); +        return -1; +    } + +    saddr.sin_family = AF_INET; +    saddr.sin_addr.s_addr = INADDR_ANY; +    saddr.sin_port = htons(LISTEN_PORT); +    error = bind(lp->serv_sockfd, (struct sockaddr *)&saddr, sizeof(saddr)); +    if (error < 0) { +        perror("Failed to bind socket\n"); +        close(lp->serv_sockfd); +        return error; +    } + +    if ((error = listen(lp->serv_sockfd, MAX_BACKLOG)) < 0) { +        perror("Failed to listen"); +        return error; +    } + +    return 0; +} + +int +listener_poll(struct ostp_session *sp, struct ostp_listener *lp)  {      struct sockaddr_in caddr; -    fd_set fds;      socklen_t caddr_len;      int client_sock, error = 0;      char *ip; -    memset(clients, -1, sizeof(clients)); -    clients[0] = serv_sock; +    memset(lp->clients, -1, sizeof(lp->clients)); +    lp->clients[0] = lp->serv_sockfd;      while (1) { -        FD_ZERO(&fds); +        FD_ZERO(&lp->client_fds);          for (int i = 0; i < MAX_CLIENTS; ++i) { -            if (clients[i] >= 0) -                FD_SET(clients[i], &fds); +            if (lp->clients[i] >= 0) +                FD_SET(lp->clients[i], &lp->client_fds);          } -        if (select(1024, &fds, NULL, NULL, NULL) < 0) { +        if (select(1024, &lp->client_fds, NULL, NULL, NULL) < 0) {              perror("select");              continue;          }          /* Check if the servers socket has new connections */ -        if (FD_ISSET(serv_sock, &fds)) { +        if (FD_ISSET(lp->serv_sockfd, &lp->client_fds)) {              caddr_len = sizeof(caddr); -            client_sock = accept(serv_sock, (struct sockaddr *)&caddr, +            client_sock = accept(lp->serv_sockfd, (struct sockaddr *)&caddr,                  &caddr_len);              if (client_sock < 0) { @@ -138,8 +157,8 @@ read_clients(void)              }              for (int i = 0; i < MAX_CLIENTS; ++i) { -                if (clients[i] < 0) { -                    clients[i] = client_sock; +                if (lp->clients[i] < 0) { +                    lp->clients[i] = client_sock;                      ip = inet_ntoa(caddr.sin_addr);                      printf("Incoming connection from %s\n", ip);                      break; @@ -147,56 +166,30 @@ read_clients(void)              }          } -        /* Handle from data from clients */ +        /* Handle from data from lp->clients */          for (int i = 1; i < MAX_CLIENTS; ++i) { -            if (clients[i] <= 0) +            if (lp->clients[i] <= 0)                  continue; -            if (FD_ISSET(clients[i], &fds) <= 0) +            if (FD_ISSET(lp->clients[i], &lp->client_fds) <= 0)                  continue; -            handle_client(&caddr, i); +            handle_client(&caddr, sp, lp, i);              break;          }      }      close(client_sock); -    close(serv_sock); +    close(lp->serv_sockfd);  } -/* - * Begin listening for incoming connections - * and handle them. - */ -int -net_listen(void) +void +listener_cleanup(struct ostp_listener *lp)  { -    struct sockaddr_in saddr; -    int error; - -    signal(SIGTERM, signal_handle); -    signal(SIGINT, signal_handle); - -    serv_sock = socket(AF_INET, SOCK_STREAM, 0); -    if (serv_sock < 0) { -        perror("Failed to create socket\n"); -        return -1; -    } - -    saddr.sin_family = AF_INET; -    saddr.sin_addr.s_addr = INADDR_ANY; -    saddr.sin_port = htons(LISTEN_PORT); -    error = bind(serv_sock, (struct sockaddr *)&saddr, sizeof(saddr)); -    if (error < 0) { -        perror("Failed to bind socket\n"); -        close(serv_sock); -        return error; -    } - -    if ((error = listen(serv_sock, MAX_BACKLOG)) < 0) { -        perror("Failed to listen"); -        return error; +    for (int i = 0; i < MAX_CLIENTS; ++i) { +        if (lp->clients[i] > 0) { +            close(lp->clients[i]); +        }      } -    read_clients(); -    __builtin_unreachable(); +    close(lp->serv_sockfd);  } diff --git a/lib/libostp/session.c b/lib/libostp/session.c new file mode 100644 index 0000000..4bc6fb4 --- /dev/null +++ b/lib/libostp/session.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + *    contributors may be used to endorse or promote products derived from + *    this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <libostp/session.h> +#include <net/stpsession.h> +#include <net/param.h> +#include <crypto/ecdh.h> +#include <defs.h> +#include <arpa/inet.h> +#include <termios.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#define OSTP_PORT 5352 + +#if LIBOSTP_DEBUG +#define LOG(...) printf("libostp: %s", __VA_ARGS__) +#else +#define LOG(...) (void)0 +#endif + +static const char *pap_codestr[] = { +    [PAP_SUCCESS]   = "success", +    [PAP_BAD_SPW]   = "bad SPW", +    [PAP_BAD_PERMS] = "insufficient permissions", +    [PAP_RESOURCE]  = "server out of resources" +}; + +static const char *auth_codestr[] = { +    [AUTH_SUCCESS] = "successful auth", +    [AUTH_BAD_PW] = "bad username or password" +}; + +static int +send_auth(int sockfd, const unsigned char *session_key) +{ +    struct session_auth auth; +    struct termios oldt, newt; +    int c, index = 0; +    int error; + +    printf("** Please authenticate yourself **\n"); +    printf("Username: "); + +    /* Fetch username and clean it up */ +    fgets(auth.username, sizeof(auth.username), stdin); +    auth.username[strcspn(auth.username, "\n")] = '\0'; + +    /* Hide input */ +    tcgetattr(STDIN_FILENO, &oldt); +    newt = oldt; +    newt.c_lflag &= ~(ECHO | ICANON); +    tcsetattr(STDIN_FILENO, TCSANOW, &newt); + +    printf("Password: "); +    while (index < (sizeof(auth.password) - 1)) { +        c = getchar(); + +        if (c == '\n') { +            printf("\n"); +            break; +        } + +        if (c == 127 || c == '\b') { +            if (index > 0) { +                auth.password[index] = '\0'; +                index--; +                printf("\b \b"); +            } +        } else { +            auth.password[index++] = c; +            printf("*"); +        } +    } + +    auth.code = 0; +    auth.password[index] = '\0'; +    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + +    /* Send frame with session auth */ +    error = send_frame(sockfd, &auth, sizeof(auth), session_key); +    if (error < 0) { +        printf("Failed to send user authentication\n"); +        return error; +    } + +    /* Try to get server reply */ +    error = recv_frame(sockfd, sizeof(auth), session_key, &auth); +    if (error < 0) { +        LOG("Failed to get user authentication ACK from server\n"); +        return error; +    } + +    /* Did it fail? */ +    if (auth.code != AUTH_SUCCESS) { +        LOG("Failed to authenticate, server says: %s\n", +            auth_codestr[auth.code]); +        return -1; +    } + +    return 0; +} + +static int +client_negotiate_spw(int sockfd, const unsigned char *session_key) +{ +    struct aes_message am; +    struct msg_frame msg_frame; +    struct pap pap; +    unsigned char *tmp; +    int error; + +    /* Create a PAP and encrypt it */ +    pap.spw = 0x8000; +    pap.code = 0; + +    while (1) { +        if ((error = send_frame(sockfd, &pap, sizeof(pap), session_key)) < 0) { +            return error; +        } + +        /* Receive the PAP the server replies with */ +        if ((error = recv_frame(sockfd, sizeof(pap), session_key, &pap)) < 0) { +            return error; +        } + +        /* +         * If the server echos our PAP with code 0 then it has +         * applied our session parameters! However, there is +         * a chance arbitration will be needed and we need +         * to look out for that too... +         */ +        if (pap.code == 0) { +            LOG("** Negotiation success\n"); +            break; +        } + +        LOG("** Arbitration needed, server says: %s\n", pap_codestr[pap.code]); +        LOG("** Server proposes SPW of 0x%0X, accepting\n", pap.spw); +        pap.spw |= PAP_SPW_QSR; +        pap.code = 0; +    } + +    return 0; +} + +static void +recv_motd(int sockfd, const unsigned char *session_key) +{ +    char buf[4096]; +    int len; + +    /* Receive the PAP the server replies with */ +    if ((len = recv_frame(sockfd, sizeof(buf) - 1, session_key, buf)) < 0) { +        printf("Failed to recv MOTD...\n"); +        return; +    } + +    buf[len] = '\0'; +    printf("%s\n", buf); +} + +int +session_new(const char *host, struct ostp_session *res) +{ +    struct sockaddr_in addr; +    struct session_request stp_sq; +    struct x25519_keypair keypair; +    unsigned char serv_pubkey[32]; +    unsigned char *session_key; +    int error, sockfd; + +    res->session_key = NULL; +    addr.sin_family = AF_INET; +    addr.sin_addr.s_addr = inet_addr(host); +    addr.sin_port = htons(OSTP_PORT); + +    sockfd = socket(AF_INET, SOCK_STREAM, 0); +    if (sockfd < 0) { +        return sockfd; +    } + +    error = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); +    if (error < 0) { +        LOG("Failed to connect!\n"); +        close(sockfd); +        return error; +    } + +    LOG("Generating keys...\n"); + +    /* Generate an ephemeral keypair */ +    if ((error = gen_x25519_keypair(&keypair)) < 0) { +        LOG("Key generation failed!\n"); +        close(sockfd); +        return error; +    } + +    /* +     * Setup the session request and add our public +     * key to it. We also assume user authentication. +     */ +    memset(stp_sq.hash, 0, sizeof(stp_sq.hash)); +    stp_sq.options = SESSION_REQ_USER; +    memcpy(stp_sq.pubkey, keypair.pubkey, sizeof(stp_sq.pubkey)); + +    LOG("Sending session request...\n"); +    error = send(sockfd, &stp_sq, sizeof(stp_sq), 0); +    if (error < 0) { +        perror("Failed to send session request"); +        close(sockfd); +        return error; +    } + +    error = recv(sockfd, serv_pubkey, sizeof(serv_pubkey), 0); +    if (error < 0) { +        perror("Failed to get public key from peer\n"); +        close(sockfd); +        return error; +    } + +    if (error == 0) { +        LOG("Connection closed by peer\n"); +        close(sockfd); +        return 0; +    } + +    LOG("Got public key from server\n"); +    LOG("Deriving session key...\n"); +    gen_session_key(keypair.privkey, serv_pubkey, &session_key); + +    /* User authentication occurs before sending SPWs */ +    if ((error = send_auth(sockfd, session_key)) < 0) { +        return error; +    } + +    /* Send server SPW bits */ +    if ((error = client_negotiate_spw(sockfd, session_key)) < 0) { +        LOG("Session Parameter Negotiation failed\n"); +        free_session_key(session_key); +        close(sockfd); +        return error; +    } + +    recv_motd(sockfd, session_key); +    res->sockfd = sockfd; +    res->session_key = session_key; +    return 0; +} + +int +session_close(struct ostp_session *session) +{ +    if (session->session_key == NULL) { +        free_session_key(session->session_key); +    } +    close(session->sockfd); +    return 0; +} + +int +session_send(void *data, uint16_t len, const struct ostp_session *session) +{ +    return send_frame(session->sockfd, data, len, session->session_key); +} + +int +session_recv(void *buf, uint16_t len, const struct ostp_session *session) +{ +    return recv_frame(session->sockfd, len, session->session_key, buf); +} diff --git a/ostp.d/init/otd_init.c b/ostp.d/init/main.c index 4b899b4..08e020e 100644 --- a/ostp.d/init/otd_init.c +++ b/ostp.d/init/main.c @@ -27,11 +27,34 @@   * POSSIBILITY OF SUCH DAMAGE.   */ -#include <net/listen.h> +#include <libostp/session.h> +#include <libostp/server.h> +#include <string.h>  #include <stdio.h> +static int +blah(struct ostp_session *s, const char *buf, size_t len) +{ +    printf("Got data!\n"); +    return 0; +} +  int  main(void)  { -    return net_listen(); +    struct ostp_listener l; +    struct ostp_session s; +    int error; + +    listener_init(&l); +    l.on_recv = blah; + +    if ((error = listener_bind(&s, &l)) < 0) { +        return error; +    } +    if ((error = listener_poll(&s, &l)) < 0) { +        return error; +    } + +    return 0;  } | 
