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