cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

ssh_agent.c (5774B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#include "config.h"
     21
     22#include "client.h"
     23#include "ssh_agent.h"
     24#include "ssh_buffer.h"
     25
     26#include <guacamole/client.h>
     27#include <guacamole/mem.h>
     28#include <libssh2.h>
     29#include <openssl/err.h>
     30#include <openssl/evp.h>
     31#include <openssl/pem.h>
     32#include <openssl/rsa.h>
     33
     34#include <stdio.h>
     35#include <stdint.h>
     36#include <stdlib.h>
     37#include <unistd.h>
     38
     39void ssh_auth_agent_sign(ssh_auth_agent* agent, char* data, int data_length) {
     40
     41    LIBSSH2_CHANNEL* channel = agent->channel;
     42    ssh_key* key = agent->identity;
     43
     44    char sig[4096];
     45    int sig_len;
     46
     47    char buffer[4096];
     48    char* pos = buffer;
     49
     50    /* Sign with key */
     51    sig_len = ssh_key_sign(key, data, data_length, (u_char*) sig);
     52    if (sig_len < 0)
     53        return;
     54
     55    buffer_write_uint32(&pos, 1+4 + 4+7 + 4+sig_len);
     56
     57    buffer_write_byte(&pos, SSH2_AGENT_SIGN_RESPONSE);
     58    buffer_write_uint32(&pos, 4+7 + 4+sig_len);
     59
     60    /* Write key type */
     61    if (key->type == SSH_KEY_RSA)
     62        buffer_write_string(&pos, "ssh-rsa", 7);
     63    else if (key->type == SSH_KEY_DSA)
     64        buffer_write_string(&pos, "ssh-dss", 7);
     65    else
     66        return;
     67
     68    /* Write signature */
     69    buffer_write_string(&pos, sig, sig_len);
     70
     71    libssh2_channel_write(channel, buffer, pos-buffer);
     72    libssh2_channel_flush(channel);
     73
     74}
     75
     76void ssh_auth_agent_list_identities(ssh_auth_agent* auth_agent) {
     77
     78    LIBSSH2_CHANNEL* channel = auth_agent->channel;
     79    ssh_key* key = auth_agent->identity;
     80
     81    char buffer[4096];
     82    char* pos = buffer;
     83
     84    buffer_write_uint32(&pos, 1+4
     85                              + key->public_key_length+4
     86                              + sizeof(SSH_AGENT_COMMENT)+3);
     87
     88    buffer_write_byte(&pos, SSH2_AGENT_IDENTITIES_ANSWER);
     89    buffer_write_uint32(&pos, 1);
     90
     91    buffer_write_string(&pos, key->public_key, key->public_key_length);
     92    buffer_write_string(&pos, SSH_AGENT_COMMENT, sizeof(SSH_AGENT_COMMENT)-1);
     93
     94    libssh2_channel_write(channel, buffer, pos-buffer);
     95    libssh2_channel_flush(channel);
     96
     97}
     98
     99void ssh_auth_agent_handle_packet(ssh_auth_agent* auth_agent, uint8_t type,
    100        char* data, int data_length) {
    101
    102    switch (type) {
    103
    104        /* List identities */
    105        case SSH2_AGENT_REQUEST_IDENTITIES:
    106            ssh_auth_agent_list_identities(auth_agent);
    107            break;
    108
    109        /* Sign request */
    110        case SSH2_AGENT_SIGN_REQUEST: {
    111
    112            char* pos = data;
    113
    114            int key_blob_length;
    115            int sign_data_length;
    116            char* sign_data;
    117
    118            /* Skip past key, read data, ignore flags */
    119            buffer_read_string(&pos, &key_blob_length);
    120            sign_data = buffer_read_string(&pos, &sign_data_length);
    121
    122            /* Sign given data */
    123            ssh_auth_agent_sign(auth_agent, sign_data, sign_data_length);
    124            break;
    125        }
    126
    127        /* Otherwise, return failure */
    128        default:
    129            libssh2_channel_write(auth_agent->channel,
    130                    UNSUPPORTED, sizeof(UNSUPPORTED)-1);
    131
    132    }
    133
    134}
    135
    136int ssh_auth_agent_read(ssh_auth_agent* auth_agent) {
    137
    138    LIBSSH2_CHANNEL* channel = auth_agent->channel;
    139
    140    int bytes_read;
    141
    142    if (libssh2_channel_eof(channel))
    143        return -1;
    144
    145    /* Read header if available */
    146    if (auth_agent->buffer_length >= 5) {
    147
    148        uint32_t length =
    149              (((unsigned char*) auth_agent->buffer)[0] << 24)
    150            | (((unsigned char*) auth_agent->buffer)[1] << 16)
    151            | (((unsigned char*) auth_agent->buffer)[2] <<  8)
    152            |  ((unsigned char*) auth_agent->buffer)[3];
    153
    154        uint8_t type = ((unsigned char*) auth_agent->buffer)[4];
    155
    156        /* If enough data read, call handler, shift data */
    157        if (auth_agent->buffer_length >= length+4) {
    158
    159            ssh_auth_agent_handle_packet(auth_agent, type,
    160                    auth_agent->buffer+5, length-1);
    161
    162            auth_agent->buffer_length -= length+4;
    163            memmove(auth_agent->buffer,
    164                    auth_agent->buffer+length+4, auth_agent->buffer_length);
    165            return length+4;
    166        }
    167
    168    }
    169
    170    /* Read data into buffer */
    171    bytes_read = libssh2_channel_read(channel,
    172            auth_agent->buffer+auth_agent->buffer_length,
    173            sizeof(auth_agent->buffer)-auth_agent->buffer_length);
    174
    175    /* If unsuccessful, return error */
    176    if (bytes_read < 0)
    177        return bytes_read;
    178
    179    /* Update buffer length */
    180    auth_agent->buffer_length += bytes_read;
    181    return bytes_read;
    182
    183}
    184
    185void ssh_auth_agent_callback(LIBSSH2_SESSION *session,
    186        LIBSSH2_CHANNEL *channel, void **abstract) {
    187
    188    /* Get client data */
    189    guac_client* client = (guac_client*) *abstract;
    190    ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
    191
    192    /* Init auth agent */
    193    ssh_auth_agent* auth_agent = guac_mem_alloc(sizeof(ssh_auth_agent));
    194    auth_agent->channel = channel;
    195    auth_agent->identity = client_data->key;
    196    auth_agent->buffer_length = 0;
    197
    198    /* Store auth agent */
    199    client_data->auth_agent = auth_agent;
    200
    201}
    202