PUBLIC_KEY *publickey_make_rsa(SSH_SESSION *session, BUFFER *buffer, char *type){ STRING *e,*n; PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY)); if(!strcmp(type,"ssh-rsa")) key->type=TYPE_RSA; else key->type=TYPE_RSA1; key->type_c=type; e=buffer_get_ssh_string(buffer); n=buffer_get_ssh_string(buffer); buffer_free(buffer); /* we don't need it anymore */ if(!e || !n){ ssh_set_error(session,SSH_FATAL,"Invalid RSA public key"); if(e) free(e); if(n) free(n); free(key); return NULL; } #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&key->rsa_pub,NULL,"(public-key(rsa(n %b)(e %b)))",string_len(n),n->string,string_len(e),e->string); #elif HAVE_LIBCRYPTO key->rsa_pub=RSA_new(); key->rsa_pub->e=make_string_bn(e); key->rsa_pub->n=make_string_bn(n); #endif #ifdef DEBUG_CRYPTO ssh_print_hexa("e",e->string,string_len(e)); ssh_print_hexa("n",n->string,string_len(n)); #endif free(e); free(n); return key; }
static int kbdauth_info_get(SSH_SESSION *session){ STRING *name; /* name of the "asking" window showed to client */ STRING *instruction; STRING *tmp; u32 nprompts; u32 i; enter_function(); name=buffer_get_ssh_string(session->in_buffer); instruction=buffer_get_ssh_string(session->in_buffer); tmp=buffer_get_ssh_string(session->in_buffer); buffer_get_u32(session->in_buffer,&nprompts); if(!name || !instruction || !tmp){ if(name) free(name); if(instruction) free(instruction); // tmp must be empty if we got here ssh_set_error(session,SSH_FATAL,"Invalid USERAUTH_INFO_REQUEST msg"); leave_function(); return SSH_AUTH_ERROR; } if(tmp) free(tmp); // no use if(!session->kbdint) session->kbdint=kbdint_new(); else kbdint_clean(session->kbdint); session->kbdint->name=string_to_char(name); free(name); session->kbdint->instruction=string_to_char(instruction); free(instruction); nprompts=ntohl(nprompts); if(nprompts>KBDINT_MAX_PROMPT){ ssh_set_error(session,SSH_FATAL,"Too much prompt asked from server: %lu(0x%.8lx)",nprompts,nprompts); leave_function(); return SSH_AUTH_ERROR; } session->kbdint->nprompts=nprompts; session->kbdint->prompts=malloc(nprompts*sizeof(char *)); memset(session->kbdint->prompts,0,nprompts*sizeof(char *)); session->kbdint->echo=malloc(nprompts); memset(session->kbdint->echo,0,nprompts); for(i=0;i<nprompts;++i){ tmp=buffer_get_ssh_string(session->in_buffer); buffer_get_u8(session->in_buffer,&session->kbdint->echo[i]); if(!tmp){ ssh_set_error(session,SSH_FATAL,"Short INFO_REQUEST packet"); leave_function(); return SSH_AUTH_ERROR; } session->kbdint->prompts[i]=string_to_char(tmp); free(tmp); } leave_function(); return SSH_AUTH_INFO; /* we are not auth. but we parsed the packet */ }
/* caller has to free commment */ ssh_key ssh_agent_get_next_ident(struct ssh_session_struct *session, char **comment) { struct ssh_key_struct *key; struct ssh_string_struct *blob = NULL; struct ssh_string_struct *tmp = NULL; int rc; if (session->agent->count == 0) { return NULL; } switch(session->version) { case 1: return NULL; case 2: /* get the blob */ blob = buffer_get_ssh_string(session->agent->ident); if (blob == NULL) { return NULL; } /* get the comment */ tmp = buffer_get_ssh_string(session->agent->ident); if (tmp == NULL) { ssh_string_free(blob); return NULL; } if (comment) { *comment = ssh_string_to_char(tmp); } else { ssh_string_free(blob); ssh_string_free(tmp); return NULL; } ssh_string_free(tmp); /* get key from blob */ rc = ssh_pki_import_pubkey_blob(blob, &key); ssh_string_free(blob); if (rc == SSH_ERROR) { return NULL; } break; default: return NULL; } return key; }
/** @internal * @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back * a SSH_MSG_NEWKEYS */ int ssh_client_curve25519_reply(ssh_session_t * session, ssh_buffer_t * packet){ ssh_string_t * q_s_string = NULL; ssh_string_t * pubkey = NULL; ssh_string_t * signature = NULL; int rc; pubkey = buffer_get_ssh_string(packet); if (pubkey == NULL){ ssh_set_error(session,SSH_FATAL, "No public key in packet"); goto error; } /* this is the server host key */ session->next_crypto->server_pubkey = pubkey; pubkey = NULL; q_s_string = buffer_get_ssh_string(packet); if (q_s_string == NULL) { ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet"); goto error; } if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE){ ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d", (int)ssh_string_len(q_s_string)); ssh_string_free(q_s_string); goto error; } memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE); ssh_string_free(q_s_string); signature = buffer_get_ssh_string(packet); if (signature == NULL) { ssh_set_error(session, SSH_FATAL, "No signature in packet"); goto error; } session->next_crypto->dh_server_signature = signature; signature=NULL; /* ownership changed */ /* TODO: verify signature now instead of waiting for NEWKEYS */ if (ssh_curve25519_build_k(session) < 0) { ssh_set_error(session, SSH_FATAL, "Cannot build k number"); goto error; } /* Send the MSG_NEWKEYS */ if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { goto error; } rc=packet_send(session); SSH_INFO(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; error: return SSH_ERROR; }
int ssh_pki_import_signature_blob(const ssh_string sig_blob, const ssh_key pubkey, ssh_signature *psig) { ssh_signature sig; enum ssh_keytypes_e type; ssh_string str; ssh_buffer buf; int rc; if (sig_blob == NULL || psig == NULL) { return SSH_ERROR; } buf = ssh_buffer_new(); if (buf == NULL) { return SSH_ERROR; } rc = ssh_buffer_add_data(buf, ssh_string_data(sig_blob), ssh_string_len(sig_blob)); if (rc < 0) { ssh_buffer_free(buf); return SSH_ERROR; } str = buffer_get_ssh_string(buf); if (str == NULL) { ssh_buffer_free(buf); return SSH_ERROR; } type = ssh_key_type_from_name(ssh_string_get_char(str)); ssh_string_free(str); str = buffer_get_ssh_string(buf); ssh_buffer_free(buf); if (str == NULL) { return SSH_ERROR; } sig = pki_signature_from_blob(pubkey, str, type); ssh_string_free(str); if (sig == NULL) { return SSH_ERROR; } *psig = sig; return SSH_OK; }
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){ ssh_string f; ssh_string pubkey = NULL; ssh_string signature = NULL; int rc; pubkey = buffer_get_ssh_string(packet); if (pubkey == NULL){ ssh_set_error(session,SSH_FATAL, "No public key in packet"); goto error; } dh_import_pubkey(session, pubkey); f = buffer_get_ssh_string(packet); if (f == NULL) { ssh_set_error(session,SSH_FATAL, "No F number in packet"); goto error; } rc = dh_import_f(session, f); ssh_string_burn(f); ssh_string_free(f); if (rc < 0) { ssh_set_error(session, SSH_FATAL, "Cannot import f number"); goto error; } signature = buffer_get_ssh_string(packet); if (signature == NULL) { ssh_set_error(session, SSH_FATAL, "No signature in packet"); goto error; } session->next_crypto->dh_server_signature = signature; signature=NULL; /* ownership changed */ if (dh_build_k(session) < 0) { ssh_set_error(session, SSH_FATAL, "Cannot build k number"); goto error; } /* Send the MSG_NEWKEYS */ if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { goto error; } rc=packet_send(session); SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; error: return SSH_ERROR; }
/* caller has to free commment */ struct ssh_public_key_struct *agent_get_next_ident(struct ssh_session_struct *session, char **comment) { struct ssh_public_key_struct *pubkey = NULL; struct ssh_string_struct *blob = NULL; struct ssh_string_struct *tmp = NULL; if (session->agent->count == 0) { return NULL; } switch(session->version) { case 1: return NULL; case 2: /* get the blob */ blob = buffer_get_ssh_string(session->agent->ident); if (blob == NULL) { return NULL; } /* get the comment */ tmp = buffer_get_ssh_string(session->agent->ident); if (tmp == NULL) { string_free(blob); return NULL; } if (comment) { *comment = string_to_char(tmp); } else { string_free(blob); string_free(tmp); return NULL; } string_free(tmp); /* get key from blob */ pubkey = publickey_from_string(session, blob); string_free(blob); break; default: return NULL; } return pubkey; }
/** * @brief Import a base64 formated public key from a memory c-string. * * @param[in] b64_key The base64 key to format. * * @param[in] type The type of the key to format. * * @param[out] pkey A pointer where the allocated key can be stored. You * need to free the memory. * * @return SSH_OK on success, SSH_ERROR on error. * * @see ssh_key_free() */ int ssh_pki_import_pubkey_base64(const char *b64_key, enum ssh_keytypes_e type, ssh_key *pkey) { ssh_buffer buffer; ssh_string type_s; int rc; if (b64_key == NULL || pkey == NULL) { return SSH_ERROR; } buffer = base64_to_bin(b64_key); if (buffer == NULL) { return SSH_ERROR; } type_s = buffer_get_ssh_string(buffer); if (type_s == NULL) { ssh_buffer_free(buffer); return SSH_ERROR; } ssh_string_free(type_s); rc = pki_import_pubkey_buffer(buffer, type, pkey); ssh_buffer_free(buffer); return rc; }
PUBLIC_KEY *publickey_from_string(SSH_SESSION *session, STRING *pubkey_s){ BUFFER *tmpbuf=buffer_new(); STRING *type_s; char *type; buffer_add_data(tmpbuf,pubkey_s->string,string_len(pubkey_s)); type_s=buffer_get_ssh_string(tmpbuf); if(!type_s){ buffer_free(tmpbuf); ssh_set_error(session,SSH_FATAL,"Invalid public key format"); return NULL; } type=string_to_char(type_s); free(type_s); if(!strcmp(type,"ssh-dss")){ free(type); return publickey_make_dss(session, tmpbuf); } if(!strcmp(type,"ssh-rsa")){ free(type); return publickey_make_rsa(session, tmpbuf,"ssh-rsa"); } if(!strcmp(type,"ssh-rsa1")){ free(type); return publickey_make_rsa(session, tmpbuf,"ssh-rsa1"); } ssh_set_error(session,SSH_FATAL,"unknown public key protocol %s",type); buffer_free(tmpbuf); free(type); return NULL; }
int ssh_get_kex(SSH_SESSION *session,int server_kex ){ STRING *str; char *strings[10]; int i; if(packet_wait(session,SSH2_MSG_KEXINIT,1)) return -1; if(buffer_get_data(session->in_buffer,session->server_kex.cookie,16)!=16){ ssh_set_error(session,SSH_FATAL,"get_kex(): no cookie in packet"); return -1; } hashbufin_add_cookie(session,session->server_kex.cookie); memset(strings,0,sizeof(char *)*10); for(i=0;i<10;++i){ str=buffer_get_ssh_string(session->in_buffer); if(!str) break; if(str){ buffer_add_ssh_string(session->in_hashbuf,str); strings[i]=string_to_char(str); free(str); } else strings[i]=NULL; } /* copy the server kex info into an array of strings */ if(server_kex){ session->client_kex.methods=malloc( 10 * sizeof(char **)); for(i=0;i<10;++i) session->client_kex.methods[i]=strings[i]; } else { // client session->server_kex.methods=malloc( 10 * sizeof(char **)); for(i=0;i<10;++i) session->server_kex.methods[i]=strings[i]; } return 0; }
/** @internal * @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back * a SSH_MSG_NEWKEYS */ int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){ ssh_string q_s_string = NULL; ssh_string pubkey = NULL; ssh_string signature = NULL; int rc; pubkey = buffer_get_ssh_string(packet); if (pubkey == NULL){ ssh_set_error(session,SSH_FATAL, "No public key in packet"); goto error; } ecdh_import_pubkey(session, pubkey); q_s_string = buffer_get_ssh_string(packet); if (q_s_string == NULL) { ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet"); goto error; } session->next_crypto->ecdh_server_pubkey = q_s_string; signature = buffer_get_ssh_string(packet); if (signature == NULL) { ssh_set_error(session, SSH_FATAL, "No signature in packet"); goto error; } session->next_crypto->dh_server_signature = signature; signature=NULL; /* ownership changed */ /* TODO: verify signature now instead of waiting for NEWKEYS */ if (ecdh_build_k(session) < 0) { ssh_set_error(session, SSH_FATAL, "Cannot build k number"); goto error; } /* Send the MSG_NEWKEYS */ if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { goto error; } rc=packet_send(session); ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; error: return SSH_ERROR; }
PUBLIC_KEY *publickey_make_dss(SSH_SESSION *session, BUFFER *buffer){ STRING *p,*q,*g,*pubkey; PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY)); key->type=TYPE_DSS; key->type_c="ssh-dss"; p=buffer_get_ssh_string(buffer); q=buffer_get_ssh_string(buffer); g=buffer_get_ssh_string(buffer); pubkey=buffer_get_ssh_string(buffer); buffer_free(buffer); /* we don't need it anymore */ if(!p || !q || !g || !pubkey){ ssh_set_error(session,SSH_FATAL,"Invalid DSA public key"); if(p) free(p); if(q) free(q); if(g) free(g); if(pubkey) free(pubkey); free(key); return NULL; } #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&key->dsa_pub,NULL,"(public-key(dsa(p %b)(q %b)(g %b)(y %b)))",string_len(p),p->string,string_len(q),q->string,string_len(g),g->string,string_len(pubkey),pubkey->string); #elif defined HAVE_LIBCRYPTO key->dsa_pub=DSA_new(); key->dsa_pub->p=make_string_bn(p); key->dsa_pub->q=make_string_bn(q); key->dsa_pub->g=make_string_bn(g); key->dsa_pub->pub_key=make_string_bn(pubkey); #endif free(p); free(q); free(g); free(pubkey); return key; }
/** * @internal * * @brief Import a public key from a ssh string. * * @param[in] key_blob The key blob to import as specified in RFC 4253 section * 6.6 "Public Key Algorithms". * * @param[out] pkey A pointer where the allocated key can be stored. You * need to free the memory. * * @return SSH_OK on success, SSH_ERROR on error. * * @see ssh_key_free() */ int ssh_pki_import_pubkey_blob(const ssh_string key_blob, ssh_key *pkey) { ssh_buffer buffer; ssh_string type_s = NULL; enum ssh_keytypes_e type; int rc; if (key_blob == NULL || pkey == NULL) { return SSH_ERROR; } buffer = ssh_buffer_new(); if (buffer == NULL) { ssh_pki_log("Out of memory!"); return SSH_ERROR; } rc = ssh_buffer_add_data(buffer, ssh_string_data(key_blob), ssh_string_len(key_blob)); if (rc < 0) { ssh_pki_log("Out of memory!"); goto fail; } type_s = buffer_get_ssh_string(buffer); if (type_s == NULL) { ssh_pki_log("Out of memory!"); goto fail; } type = ssh_key_type_from_name(ssh_string_get_char(type_s)); if (type == SSH_KEYTYPE_UNKNOWN) { ssh_pki_log("Unknown key type found!"); goto fail; } ssh_string_free(type_s); rc = pki_import_pubkey_buffer(buffer, type, pkey); ssh_buffer_free(buffer); return rc; fail: ssh_buffer_free(buffer); ssh_string_free(type_s); return SSH_ERROR; }
/** @internal * @brief parse an incoming SSH_MSG_KEXDH_INIT packet and complete * key exchange **/ static int ssh_server_kexdh_init(ssh_session session, ssh_buffer packet){ ssh_string e; e = buffer_get_ssh_string(packet); if (e == NULL) { ssh_set_error(session, SSH_FATAL, "No e number in client request"); return -1; } if (dh_import_e(session, e) < 0) { ssh_set_error(session, SSH_FATAL, "Cannot import e number"); session->session_state=SSH_SESSION_STATE_ERROR; } else { session->dh_handshake_state=DH_STATE_INIT_SENT; dh_handshake_server(session); } ssh_string_free(e); return SSH_OK; }
PUBLIC_KEY *publickey_from_string(SSH_SESSION *session, STRING *pubkey_s) { BUFFER *tmpbuf = NULL; STRING *type_s = NULL; char *type_c = NULL; int type; tmpbuf = buffer_new(); if (tmpbuf == NULL) { return NULL; } if (buffer_add_data(tmpbuf, pubkey_s->string, string_len(pubkey_s)) < 0) { goto error; } type_s = buffer_get_ssh_string(tmpbuf); if (type_s == NULL) { ssh_set_error(session,SSH_FATAL,"Invalid public key format"); goto error; } type_c = string_to_char(type_s); string_free(type_s); if (type_c == NULL) { goto error; } type = ssh_type_from_name(type_c); SAFE_FREE(type_c); switch (type) { case TYPE_DSS: return publickey_make_dss(session, tmpbuf); case TYPE_RSA: case TYPE_RSA1: return publickey_make_rsa(session, tmpbuf, type); } ssh_set_error(session, SSH_FATAL, "Unknown public key protocol %s", ssh_type_to_char(type)); error: buffer_free(tmpbuf); return NULL; }
ssh_public_key publickey_from_string(ssh_session session, ssh_string pubkey_s) { ssh_buffer tmpbuf = NULL; ssh_string type_s = NULL; char *type_c = NULL; int type; tmpbuf = ssh_buffer_new(); if (tmpbuf == NULL) { return NULL; } if (buffer_add_data(tmpbuf, ssh_string_data(pubkey_s), ssh_string_len(pubkey_s)) < 0) { goto error; } type_s = buffer_get_ssh_string(tmpbuf); if (type_s == NULL) { ssh_set_error(session,SSH_FATAL,"Invalid public key format"); goto error; } type_c = ssh_string_to_char(type_s); ssh_string_free(type_s); if (type_c == NULL) { goto error; } type = ssh_type_from_name(type_c); SAFE_FREE(type_c); switch (type) { case SSH_KEYTYPE_DSS: return publickey_make_dss(session, tmpbuf); case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: return publickey_make_rsa(session, tmpbuf, type); } ssh_set_error(session, SSH_FATAL, "Unknown public key protocol %s", ssh_type_to_char(type)); error: ssh_buffer_free(tmpbuf); return NULL; }
static int channel_rcv_data1(ssh_session session, int is_stderr) { ssh_channel channel = session->channels; ssh_string str = NULL; str = buffer_get_ssh_string(session->in_buffer); if (str == NULL) { ssh_log(session, SSH_LOG_FUNCTIONS, "Invalid data packet !\n"); return -1; } ssh_log(session, SSH_LOG_RARE, "Adding %zu bytes data in %d", string_len(str), is_stderr); if (channel_default_bufferize(channel, string_data(str), string_len(str), is_stderr) < 0) { string_free(str); return -1; } string_free(str); return 0; }
static int channel_open(CHANNEL *channel, const char *type_c, int window, int maxpacket, BUFFER *payload) { SSH_SESSION *session = channel->session; STRING *type = NULL; u32 tmp = 0; enter_function(); channel->local_channel = ssh_channel_new_id(session); channel->local_maxpacket = maxpacket; channel->local_window = window; ssh_log(session, SSH_LOG_RARE, "Creating a channel %d with %d window and %d max packet", channel->local_channel, window, maxpacket); type = string_from_char(type_c); if (type == NULL) { leave_function(); return -1; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN) < 0 || buffer_add_ssh_string(session->out_buffer,type) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->local_channel)) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->local_window)) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) { string_free(type); leave_function(); return -1; } string_free(type); if (payload != NULL) { if (buffer_add_buffer(session->out_buffer, payload) < 0) { leave_function(); return -1; } } if (packet_send(session) != SSH_OK) { leave_function(); return -1; } ssh_log(session, SSH_LOG_RARE, "Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d", type_c, channel->local_channel); if (packet_wait(session, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, 1) != SSH_OK) { leave_function(); return -1; } switch(session->in_packet.type) { case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: buffer_get_u32(session->in_buffer, &tmp); if (channel->local_channel != ntohl(tmp)) { ssh_set_error(session, SSH_FATAL, "Server answered with sender channel number %lu instead of given %u", (long unsigned int) ntohl(tmp), channel->local_channel); leave_function(); return -1; } buffer_get_u32(session->in_buffer, &tmp); channel->remote_channel = ntohl(tmp); buffer_get_u32(session->in_buffer, &tmp); channel->remote_window = ntohl(tmp); buffer_get_u32(session->in_buffer,&tmp); channel->remote_maxpacket=ntohl(tmp); ssh_log(session, SSH_LOG_PROTOCOL, "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", channel->local_channel, channel->remote_channel); ssh_log(session, SSH_LOG_PROTOCOL, "Remote window : %lu, maxpacket : %lu", (long unsigned int) channel->remote_window, (long unsigned int) channel->remote_maxpacket); channel->open = 1; leave_function(); return 0; case SSH2_MSG_CHANNEL_OPEN_FAILURE: { STRING *error_s; char *error; u32 code; buffer_get_u32(session->in_buffer, &tmp); buffer_get_u32(session->in_buffer, &code); error_s = buffer_get_ssh_string(session->in_buffer); error = string_to_char(error_s); string_free(error_s); if (error == NULL) { leave_function(); return -1; } ssh_set_error(session, SSH_REQUEST_DENIED, "Channel opening failure: channel %u error (%lu) %s", channel->local_channel, (long unsigned int) ntohl(code), error); SAFE_FREE(error); leave_function(); return -1; } default: ssh_set_error(session, SSH_FATAL, "Received unknown packet %d\n", session->in_packet.type); leave_function(); return -1; } leave_function(); return -1; }
ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer, int type) { ssh_string e = NULL; ssh_string n = NULL; ssh_public_key key = NULL; key = malloc(sizeof(struct ssh_public_key_struct)); if (key == NULL) { ssh_buffer_free(buffer); return NULL; } ZERO_STRUCTP(key); key->type = type; key->type_c = ssh_type_to_char(key->type); e = buffer_get_ssh_string(buffer); n = buffer_get_ssh_string(buffer); ssh_buffer_free(buffer); /* we don't need it anymore */ if(e == NULL || n == NULL) { ssh_set_error(session, SSH_FATAL, "Invalid RSA public key"); goto error; } #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&key->rsa_pub, NULL, "(public-key(rsa(n %b)(e %b)))", ssh_string_len(n), ssh_string_data(n), ssh_string_len(e),ssh_string_data(e)); if (key->rsa_pub == NULL) { goto error; } #elif HAVE_LIBCRYPTO key->rsa_pub = RSA_new(); if (key->rsa_pub == NULL) { goto error; } key->rsa_pub->e = make_string_bn(e); key->rsa_pub->n = make_string_bn(n); if (key->rsa_pub->e == NULL || key->rsa_pub->n == NULL) { goto error; } #endif #ifdef DEBUG_CRYPTO ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e)); ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n)); #endif ssh_string_burn(e); ssh_string_free(e); ssh_string_burn(n); ssh_string_free(n); return key; error: ssh_string_burn(e); ssh_string_free(e); ssh_string_burn(n); ssh_string_free(n); publickey_free(key); return NULL; }
/* TODO : split this function in two so it becomes smaller */ SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,PUBLIC_KEY *pubkey,int needed_type){ #ifdef HAVE_LIBGCRYPT gcry_sexp_t sig; #elif defined HAVE_LIBCRYPTO DSA_SIG *sig; STRING *r,*s; #endif SIGNATURE *sign=malloc(sizeof(SIGNATURE)); BUFFER *tmpbuf=buffer_new(); STRING *rs; STRING *type_s,*e; int len,rsalen; char *type; buffer_add_data(tmpbuf,signature->string,string_len(signature)); type_s=buffer_get_ssh_string(tmpbuf); if(!type_s){ ssh_set_error(session,SSH_FATAL,"Invalid signature packet"); buffer_free(tmpbuf); return NULL; } type=string_to_char(type_s); free(type_s); switch(needed_type){ case TYPE_DSS: if(strcmp(type,"ssh-dss")){ ssh_set_error(session,SSH_FATAL,"Invalid signature type : %s",type); buffer_free(tmpbuf); free(type); return NULL; } break; case TYPE_RSA: if(strcmp(type,"ssh-rsa")){ ssh_set_error(session,SSH_FATAL,"Invalid signature type : %s",type); buffer_free(tmpbuf); free(type); return NULL; } break; default: ssh_set_error(session,SSH_FATAL,"Invalid signature type : %s",type); free(type); buffer_free(tmpbuf); return NULL; } free(type); switch(needed_type){ case TYPE_DSS: rs=buffer_get_ssh_string(tmpbuf); buffer_free(tmpbuf); if(!rs || string_len(rs)!=40){ /* 40 is the dual signature blob len. */ if(rs) free(rs); return NULL; } /* we make use of strings (because we have all-made functions to convert them to bignums (ou pas ;)*/ #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&sig,NULL,"(sig-val(dsa(r %b)(s %b)))",20,rs->string,20,rs->string+20); #elif defined HAVE_LIBCRYPTO r=string_new(20); s=string_new(20); string_fill(r,rs->string,20); string_fill(s,rs->string+20,20); sig=DSA_SIG_new(); sig->r=make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */ sig->s=make_string_bn(s); free(r); free(s); #endif #ifdef DEBUG_CRYPTO ssh_print_hexa("r",rs->string,20); ssh_print_hexa("s",rs->string+20,20); #endif free(rs); sign->type=TYPE_DSS; sign->dsa_sign=sig; return sign; case TYPE_RSA: e=buffer_get_ssh_string(tmpbuf); buffer_free(tmpbuf); if(!e){ return NULL; } len=string_len(e); #ifdef HAVE_LIBGCRYPT rsalen=(gcry_pk_get_nbits(pubkey->rsa_pub)+7)/8; #elif defined HAVE_LIBCRYPTO rsalen=RSA_size(pubkey->rsa_pub); #endif if(len>rsalen){ free(e); free(sign); ssh_set_error(session,SSH_FATAL,"signature too big ! %d instead of %d",len,rsalen); return NULL; } if(len<rsalen) ssh_log(session,SSH_LOG_RARE,"RSA signature len %d < %d",len,rsalen); sign->type=TYPE_RSA; #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&sig,NULL,"(sig-val(rsa(s %b)))",string_len(e),e->string); sign->rsa_sign=sig; #elif defined HAVE_LIBCRYPTO sign->rsa_sign=e; #endif #ifdef DEBUG_CRYPTO ssh_say(0,"Len : %d\n",len); ssh_print_hexa("rsa signature",e->string,len); #endif #ifdef HAVE_LIBGCRYPT free(e); #endif return sign; default: return NULL; } }
static int wait_auth_status(SSH_SESSION *session,int kbdint){ int err=SSH_AUTH_ERROR; int cont=1; STRING *auth; u8 partial=0; int todo = 0; char *auth_methods = NULL; enter_function(); while(cont){ if(packet_read(session)) break; if(packet_translate(session)) break; switch(session->in_packet.type){ case SSH2_MSG_USERAUTH_FAILURE: auth = buffer_get_ssh_string(session->in_buffer); if(!auth || buffer_get_u8(session->in_buffer,&partial)!=1 ){ ssh_set_error(session,SSH_FATAL, "invalid SSH_MSG_USERAUTH_FAILURE message"); leave_function(); return SSH_AUTH_ERROR; } auth_methods = string_to_char(auth); if(partial) { err=SSH_AUTH_PARTIAL; ssh_set_error(session,SSH_NO_ERROR,"partial success, authentications that can continue : %s", auth_methods); } else { err=SSH_AUTH_DENIED; ssh_set_error(session,SSH_REQUEST_DENIED,"Access denied. authentications that can continue : %s", auth_methods); session->auth_methods = 0; if (strstr(auth_methods, "password") != NULL) { session->auth_methods |= SSH_AUTH_METHOD_PASSWORD; } if (strstr(auth_methods, "keyboard-interactive") != NULL) { session->auth_methods |= SSH_AUTH_METHOD_INTERACTIVE; } if (strstr(auth_methods, "publickey") != NULL) { session->auth_methods |= SSH_AUTH_METHOD_PUBLICKEY; } if (strstr(auth_methods, "hostbased") != NULL) { session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED; } } free(auth); free(auth_methods); cont=0; break; case SSH2_MSG_USERAUTH_PK_OK: /* SSH monkeys have defined the same number for both */ /* SSH_MSG_USERAUTH_PK_OK and SSH_MSG_USERAUTH_INFO_REQUEST */ /* which is not really smart; */ /*case SSH2_MSG_USERAUTH_INFO_REQUEST: */ if(kbdint){ err=SSH_AUTH_INFO; cont=0; break; } /* continue through success */ case SSH2_MSG_USERAUTH_SUCCESS: err=SSH_AUTH_SUCCESS; cont=0; break; case SSH2_MSG_USERAUTH_BANNER: { STRING *banner=buffer_get_ssh_string(session->in_buffer); if(!banner){ ssh_say(1,"The banner message was invalid. continuing though\n"); break; } ssh_say(2,"Received a message banner\n"); if(session->banner) free(session->banner); /* erase the older one */ session->banner=banner; break; } default: packet_parse(session); break; } } leave_function(); return err; }
ssh_string ssh_agent_sign_data(ssh_session session, const ssh_key pubkey, struct ssh_buffer_struct *data) { ssh_buffer request; ssh_buffer reply; ssh_string key_blob; ssh_string sig_blob; int type = SSH2_AGENT_FAILURE; int flags = 0; uint32_t dlen; int rc; request = ssh_buffer_new(); if (request == NULL) { return NULL; } /* create request */ if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) { return NULL; } rc = ssh_pki_export_pubkey_blob(pubkey, &key_blob); if (rc < 0) { ssh_buffer_free(request); return NULL; } /* adds len + blob */ rc = buffer_add_ssh_string(request, key_blob); ssh_string_free(key_blob); if (rc < 0) { ssh_buffer_free(request); return NULL; } /* Add data */ dlen = buffer_get_rest_len(data); if (buffer_add_u32(request, htonl(dlen)) < 0) { ssh_buffer_free(request); return NULL; } if (buffer_add_data(request, buffer_get_rest(data), dlen) < 0) { ssh_buffer_free(request); return NULL; } if (buffer_add_u32(request, htonl(flags)) < 0) { ssh_buffer_free(request); return NULL; } reply = ssh_buffer_new(); if (reply == NULL) { ssh_buffer_free(request); return NULL; } /* send the request */ if (agent_talk(session, request, reply) < 0) { ssh_buffer_free(request); return NULL; } ssh_buffer_free(request); /* check if reply is valid */ if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) { ssh_buffer_free(reply); return NULL; } if (agent_failed(type)) { SSH_LOG(session, SSH_LOG_WARN, "Agent reports failure in signing the key"); ssh_buffer_free(reply); return NULL; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type); ssh_buffer_free(reply); return NULL; } sig_blob = buffer_get_ssh_string(reply); ssh_buffer_free(reply); return sig_blob; }
ssh_string agent_sign_data(struct ssh_session_struct *session, struct ssh_buffer_struct *data, struct ssh_public_key_struct *pubkey) { struct ssh_string_struct *blob = NULL; struct ssh_string_struct *sig = NULL; struct ssh_buffer_struct *request = NULL; struct ssh_buffer_struct *reply = NULL; int type = SSH2_AGENT_FAILURE; int flags = 0; uint32_t dlen = 0; /* create blob from the pubkey */ blob = publickey_to_string(pubkey); request = buffer_new(); if (request == NULL) { goto error; } /* create request */ if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) { goto error; } /* adds len + blob */ if (buffer_add_ssh_string(request, blob) < 0) { goto error; } /* Add data */ dlen = buffer_get_len(data); if (buffer_add_u32(request, htonl(dlen)) < 0) { goto error; } if (buffer_add_data(request, buffer_get(data), dlen) < 0) { goto error; } if (buffer_add_u32(request, htonl(flags)) < 0) { goto error; } string_free(blob); reply = buffer_new(); if (reply == NULL) { goto error; } /* send the request */ if (agent_talk(session, request, reply) < 0) { buffer_free(request); return NULL; } buffer_free(request); /* check if reply is valid */ if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) { goto error; } if (agent_failed(type)) { ssh_log(session, SSH_LOG_RARE, "Agent reports failure in signing the key"); buffer_free(reply); return NULL; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type); buffer_free(reply); return NULL; } sig = buffer_get_ssh_string(reply); buffer_free(reply); return sig; error: ssh_set_error(session, SSH_FATAL, "Not enough memory"); string_free(blob); buffer_free(request); buffer_free(reply); return NULL; }
static int pki_import_pubkey_buffer(ssh_buffer buffer, enum ssh_keytypes_e type, ssh_key *pkey) { ssh_key key; int rc; key = ssh_key_new(); if (key == NULL) { return SSH_ERROR; } key->type = type; key->type_c = ssh_key_type_to_char(type); key->flags = SSH_KEY_FLAG_PUBLIC; switch (type) { case SSH_KEYTYPE_DSS: { ssh_string p; ssh_string q; ssh_string g; ssh_string pubkey; p = buffer_get_ssh_string(buffer); if (p == NULL) { goto fail; } q = buffer_get_ssh_string(buffer); if (q == NULL) { ssh_string_burn(p); ssh_string_free(p); goto fail; } g = buffer_get_ssh_string(buffer); if (g == NULL) { ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); goto fail; } pubkey = buffer_get_ssh_string(buffer); if (pubkey == NULL) { ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); ssh_string_burn(g); ssh_string_free(g); goto fail; } rc = pki_pubkey_build_dss(key, p, q, g, pubkey); #ifdef DEBUG_CRYPTO ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p)); ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q)); ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g)); #endif ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); ssh_string_burn(g); ssh_string_free(g); ssh_string_burn(pubkey); ssh_string_free(pubkey); if (rc == SSH_ERROR) { goto fail; } } break; case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: { ssh_string e; ssh_string n; e = buffer_get_ssh_string(buffer); if (e == NULL) { goto fail; } n = buffer_get_ssh_string(buffer); if (n == NULL) { ssh_string_burn(e); ssh_string_free(e); goto fail; } rc = pki_pubkey_build_rsa(key, e, n); #ifdef DEBUG_CRYPTO ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e)); ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n)); #endif ssh_string_burn(e); ssh_string_free(e); ssh_string_burn(n); ssh_string_free(n); if (rc == SSH_ERROR) { goto fail; } } break; case SSH_KEYTYPE_ECDSA: #ifdef HAVE_ECC { ssh_string e; ssh_string i; int nid; i = buffer_get_ssh_string(buffer); if (i == NULL) { goto fail; } nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i)); ssh_string_free(i); if (nid == -1) { goto fail; } e = buffer_get_ssh_string(buffer); if (e == NULL) { goto fail; } rc = pki_pubkey_build_ecdsa(key, nid, e); ssh_string_burn(e); ssh_string_free(e); if (rc < 0) { goto fail; } /* Update key type */ key->type_c = ssh_pki_key_ecdsa_name(key); } break; #endif case SSH_KEYTYPE_ED25519: { ssh_string pubkey = buffer_get_ssh_string(buffer); if (ssh_string_len(pubkey) != ED25519_PK_LEN) { ssh_pki_log("Invalid public key length"); ssh_string_burn(pubkey); ssh_string_free(pubkey); goto fail; } key->ed25519_pubkey = malloc(ED25519_PK_LEN); if (key->ed25519_pubkey == NULL) { ssh_string_burn(pubkey); ssh_string_free(pubkey); goto fail; } memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN); ssh_string_burn(pubkey); ssh_string_free(pubkey); } break; case SSH_KEYTYPE_UNKNOWN: default: ssh_pki_log("Unknown public key protocol %d", type); goto fail; } *pkey = key; return SSH_OK; fail: ssh_key_free(key); return SSH_ERROR; }
ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer) { ssh_string p = NULL; ssh_string q = NULL; ssh_string g = NULL; ssh_string pubkey = NULL; ssh_public_key key = NULL; key = malloc(sizeof(struct ssh_public_key_struct)); if (key == NULL) { ssh_buffer_free(buffer); return NULL; } ZERO_STRUCTP(key); key->type = SSH_KEYTYPE_DSS; key->type_c = ssh_type_to_char(key->type); p = buffer_get_ssh_string(buffer); q = buffer_get_ssh_string(buffer); g = buffer_get_ssh_string(buffer); pubkey = buffer_get_ssh_string(buffer); ssh_buffer_free(buffer); /* we don't need it anymore */ if (p == NULL || q == NULL || g == NULL || pubkey == NULL) { ssh_set_error(session, SSH_FATAL, "Invalid DSA public key"); goto error; } #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&key->dsa_pub, NULL, "(public-key(dsa(p %b)(q %b)(g %b)(y %b)))", ssh_string_len(p), ssh_string_data(p), ssh_string_len(q), ssh_string_data(q), ssh_string_len(g), ssh_string_data(g), ssh_string_len(pubkey), ssh_string_data(pubkey)); if (key->dsa_pub == NULL) { goto error; } #elif defined HAVE_LIBCRYPTO key->dsa_pub = DSA_new(); if (key->dsa_pub == NULL) { goto error; } key->dsa_pub->p = make_string_bn(p); key->dsa_pub->q = make_string_bn(q); key->dsa_pub->g = make_string_bn(g); key->dsa_pub->pub_key = make_string_bn(pubkey); if (key->dsa_pub->p == NULL || key->dsa_pub->q == NULL || key->dsa_pub->g == NULL || key->dsa_pub->pub_key == NULL) { goto error; } #endif /* HAVE_LIBCRYPTO */ #ifdef DEBUG_CRYPTO ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p)); ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q)); ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g)); #endif ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); ssh_string_burn(g); ssh_string_free(g); ssh_string_burn(pubkey); ssh_string_free(pubkey); return key; error: ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); ssh_string_burn(g); ssh_string_free(g); ssh_string_burn(pubkey); ssh_string_free(pubkey); publickey_free(key); return NULL; }
/** * @internal * * @brief This function parses the last end of a channel request packet. * * This is normally converted to a SSH message and placed in the queue. * * @param[in] session The SSH session. * * @param[in] channel The channel the request is made on. * * @param[in] packet The rest of the packet to be parsed. * * @param[in] request The type of request. * * @param[in] want_reply The want_reply field from the request. * * @returns SSH_OK on success, SSH_ERROR if an error occured. */ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet, const char *request, uint8_t want_reply) { ssh_message msg = NULL; enter_function(); msg = ssh_message_new(session); if (msg == NULL) { ssh_set_error_oom(session); goto error; } ssh_log(session, SSH_LOG_PACKET, "Received a %s channel_request for channel (%d:%d) (want_reply=%hhd)", request, channel->local_channel, channel->remote_channel, want_reply); msg->type = SSH_REQUEST_CHANNEL; msg->channel_request.channel = channel; msg->channel_request.want_reply = want_reply; if (strcmp(request, "pty-req") == 0) { ssh_string term = NULL; char *term_c = NULL; term = buffer_get_ssh_string(packet); if (term == NULL) { ssh_set_error_oom(session); goto error; } term_c = ssh_string_to_char(term); if (term_c == NULL) { ssh_set_error_oom(session); ssh_string_free(term); goto error; } ssh_string_free(term); msg->channel_request.type = SSH_CHANNEL_REQUEST_PTY; msg->channel_request.TERM = term_c; buffer_get_u32(packet, &msg->channel_request.width); buffer_get_u32(packet, &msg->channel_request.height); buffer_get_u32(packet, &msg->channel_request.pxwidth); buffer_get_u32(packet, &msg->channel_request.pxheight); msg->channel_request.width = ntohl(msg->channel_request.width); msg->channel_request.height = ntohl(msg->channel_request.height); msg->channel_request.pxwidth = ntohl(msg->channel_request.pxwidth); msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight); msg->channel_request.modes = buffer_get_ssh_string(packet); if (msg->channel_request.modes == NULL) { SAFE_FREE(term_c); goto error; } goto end; } if (strcmp(request, "window-change") == 0) { msg->channel_request.type = SSH_CHANNEL_REQUEST_WINDOW_CHANGE; buffer_get_u32(packet, &msg->channel_request.width); buffer_get_u32(packet, &msg->channel_request.height); buffer_get_u32(packet, &msg->channel_request.pxwidth); buffer_get_u32(packet, &msg->channel_request.pxheight); msg->channel_request.width = ntohl(msg->channel_request.width); msg->channel_request.height = ntohl(msg->channel_request.height); msg->channel_request.pxwidth = ntohl(msg->channel_request.pxwidth); msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight); goto end; } if (strcmp(request, "subsystem") == 0) { ssh_string subsys = NULL; char *subsys_c = NULL; subsys = buffer_get_ssh_string(packet); if (subsys == NULL) { ssh_set_error_oom(session); goto error; } subsys_c = ssh_string_to_char(subsys); if (subsys_c == NULL) { ssh_set_error_oom(session); ssh_string_free(subsys); goto error; } ssh_string_free(subsys); msg->channel_request.type = SSH_CHANNEL_REQUEST_SUBSYSTEM; msg->channel_request.subsystem = subsys_c; goto end; } if (strcmp(request, "shell") == 0) { msg->channel_request.type = SSH_CHANNEL_REQUEST_SHELL; goto end; } if (strcmp(request, "exec") == 0) { ssh_string cmd = NULL; cmd = buffer_get_ssh_string(packet); if (cmd == NULL) { ssh_set_error_oom(session); goto error; } msg->channel_request.type = SSH_CHANNEL_REQUEST_EXEC; msg->channel_request.command = ssh_string_to_char(cmd); ssh_string_free(cmd); if (msg->channel_request.command == NULL) { goto error; } goto end; } if (strcmp(request, "env") == 0) { ssh_string name = NULL; ssh_string value = NULL; name = buffer_get_ssh_string(packet); if (name == NULL) { ssh_set_error_oom(session); goto error; } value = buffer_get_ssh_string(packet); if (value == NULL) { ssh_set_error_oom(session); ssh_string_free(name); goto error; } msg->channel_request.type = SSH_CHANNEL_REQUEST_ENV; msg->channel_request.var_name = ssh_string_to_char(name); msg->channel_request.var_value = ssh_string_to_char(value); if (msg->channel_request.var_name == NULL || msg->channel_request.var_value == NULL) { ssh_string_free(name); ssh_string_free(value); goto error; } ssh_string_free(name); ssh_string_free(value); goto end; } if (strcmp(request, "x11-req") == 0) { ssh_string auth_protocol = NULL; ssh_string auth_cookie = NULL; buffer_get_u8(packet, &msg->channel_request.x11_single_connection); auth_protocol = buffer_get_ssh_string(packet); if (auth_protocol == NULL) { ssh_set_error_oom(session); goto error; } auth_cookie = buffer_get_ssh_string(packet); if (auth_cookie == NULL) { ssh_set_error_oom(session); ssh_string_free(auth_protocol); goto error; } msg->channel_request.type = SSH_CHANNEL_REQUEST_X11; msg->channel_request.x11_auth_protocol = ssh_string_to_char(auth_protocol); msg->channel_request.x11_auth_cookie = ssh_string_to_char(auth_cookie); if (msg->channel_request.x11_auth_protocol == NULL || msg->channel_request.x11_auth_cookie == NULL) { ssh_string_free(auth_protocol); ssh_string_free(auth_cookie); goto error; } ssh_string_free(auth_protocol); ssh_string_free(auth_cookie); buffer_get_u32(packet, &msg->channel_request.x11_screen_number); goto end; } msg->channel_request.type = SSH_CHANNEL_UNKNOWN; end: ssh_message_queue(session,msg); leave_function(); return SSH_OK; error: ssh_message_free(msg); leave_function(); return SSH_ERROR; }
int ssh_get_kex(SSH_SESSION *session, int server_kex) { STRING *str = NULL; char *strings[10]; int i; enter_function(); if (packet_wait(session, SSH2_MSG_KEXINIT, 1) != SSH_OK) { leave_function(); return -1; } if (buffer_get_data(session->in_buffer,session->server_kex.cookie,16) != 16) { ssh_set_error(session, SSH_FATAL, "get_kex(): no cookie in packet"); leave_function(); return -1; } if (hashbufin_add_cookie(session, session->server_kex.cookie) < 0) { ssh_set_error(session, SSH_FATAL, "get_kex(): adding cookie failed"); leave_function(); return -1; } memset(strings, 0, sizeof(char *) * 10); for (i = 0; i < 10; i++) { str = buffer_get_ssh_string(session->in_buffer); if (str == NULL) { break; } if (buffer_add_ssh_string(session->in_hashbuf, str) < 0) { goto error; } strings[i] = string_to_char(str); if (strings[i] == NULL) { goto error; } string_free(str); str = NULL; } /* copy the server kex info into an array of strings */ if (server_kex) { session->client_kex.methods = malloc(10 * sizeof(char **)); if (session->client_kex.methods == NULL) { leave_function(); return -1; } for (i = 0; i < 10; i++) { session->client_kex.methods[i] = strings[i]; } } else { /* client */ session->server_kex.methods = malloc(10 * sizeof(char **)); if (session->server_kex.methods == NULL) { leave_function(); return -1; } for (i = 0; i < 10; i++) { session->server_kex.methods[i] = strings[i]; } } leave_function(); return 0; error: string_free(str); for (i = 0; i < 10; i++) { SAFE_FREE(strings[i]); } leave_function(); return -1; }
static void channel_rcv_request(SSH_SESSION *session) { CHANNEL *channel; STRING *request_s; char *request; u32 status; enter_function(); channel = channel_from_msg(session); if (channel == NULL) { ssh_log(session, SSH_LOG_FUNCTIONS, ssh_get_error(session)); leave_function(); return; } request_s = buffer_get_ssh_string(session->in_buffer); if (request_s == NULL) { ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); leave_function(); return; } request = string_to_char(request_s); string_free(request_s); if (request == NULL) { leave_function(); return; } buffer_get_u8(session->in_buffer, (u8 *) &status); if (strcmp(request,"exit-status") == 0) { SAFE_FREE(request); ssh_log(session, SSH_LOG_PACKET, "received exit-status"); buffer_get_u32(session->in_buffer, &status); channel->exit_status = ntohl(status); leave_function(); return ; } if (strcmp(request, "exit-signal") == 0) { const char *core = "(core dumped)"; STRING *signal_s; char *signal; u8 i; SAFE_FREE(request); signal_s = buffer_get_ssh_string(session->in_buffer); if (signal_s == NULL) { ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); leave_function(); return; } signal = string_to_char(signal_s); string_free(signal_s); if (signal == NULL) { leave_function(); return; } buffer_get_u8(session->in_buffer, &i); if (i == 0) { core = ""; } ssh_log(session, SSH_LOG_PACKET, "Remote connection closed by signal SIG %s %s", signal, core); SAFE_FREE(signal); leave_function(); return; } ssh_log(session, SSH_LOG_PACKET, "Unknown request %s", request); SAFE_FREE(request); leave_function(); }
/* TODO : split this function in two so it becomes smaller */ SIGNATURE *signature_from_string(ssh_session session, ssh_string signature, ssh_public_key pubkey, int needed_type) { SIGNATURE *sign = NULL; ssh_buffer tmpbuf = NULL; ssh_string rs = NULL; ssh_string type_s = NULL; ssh_string e = NULL; char *type_c = NULL; int type; int len; int rsalen; #ifdef HAVE_LIBGCRYPT gcry_sexp_t sig; #elif defined HAVE_LIBCRYPTO DSA_SIG *sig = NULL; ssh_string r = NULL; ssh_string s = NULL; #endif sign = malloc(sizeof(SIGNATURE)); if (sign == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); return NULL; } ZERO_STRUCTP(sign); tmpbuf = ssh_buffer_new(); if (tmpbuf == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); signature_free(sign); return NULL; } if (buffer_add_data(tmpbuf, ssh_string_data(signature), ssh_string_len(signature)) < 0) { signature_free(sign); ssh_buffer_free(tmpbuf); return NULL; } type_s = buffer_get_ssh_string(tmpbuf); if (type_s == NULL) { ssh_set_error(session, SSH_FATAL, "Invalid signature packet"); signature_free(sign); ssh_buffer_free(tmpbuf); return NULL; } type_c = ssh_string_to_char(type_s); ssh_string_free(type_s); if (type_c == NULL) { signature_free(sign); ssh_buffer_free(tmpbuf); return NULL; } type = ssh_type_from_name(type_c); SAFE_FREE(type_c); if (needed_type != type) { ssh_set_error(session, SSH_FATAL, "Invalid signature type: %s", ssh_type_to_char(type)); signature_free(sign); ssh_buffer_free(tmpbuf); return NULL; } switch(needed_type) { case SSH_KEYTYPE_DSS: rs = buffer_get_ssh_string(tmpbuf); ssh_buffer_free(tmpbuf); /* 40 is the dual signature blob len. */ if (rs == NULL || ssh_string_len(rs) != 40) { ssh_string_free(rs); signature_free(sign); return NULL; } /* we make use of strings (because we have all-made functions to convert * them to bignums (ou pas ;) */ #ifdef HAVE_LIBGCRYPT if (gcry_sexp_build(&sig, NULL, "(sig-val(dsa(r %b)(s %b)))", 20 ,ssh_string_data(rs), 20,(unsigned char *)ssh_string_data(rs) + 20)) { ssh_string_free(rs); signature_free(sign); return NULL; } #elif defined HAVE_LIBCRYPTO r = ssh_string_new(20); s = ssh_string_new(20); if (r == NULL || s == NULL) { ssh_string_free(r); ssh_string_free(s); ssh_string_free(rs); signature_free(sign); return NULL; } ssh_string_fill(r, ssh_string_data(rs), 20); ssh_string_fill(s, (char *)ssh_string_data(rs) + 20, 20); sig = DSA_SIG_new(); if (sig == NULL) { ssh_string_free(r); ssh_string_free(s); ssh_string_free(rs); signature_free(sign); return NULL; } sig->r = make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */ sig->s = make_string_bn(s); ssh_string_free(r); ssh_string_free(s); if (sig->r == NULL || sig->s == NULL) { ssh_string_free(rs); DSA_SIG_free(sig); signature_free(sign); return NULL; } #endif #ifdef DEBUG_CRYPTO ssh_print_hexa("r", ssh_string_data(rs), 20); ssh_print_hexa("s", (const unsigned char *)ssh_string_data(rs) + 20, 20); #endif ssh_string_free(rs); sign->type = SSH_KEYTYPE_DSS; sign->dsa_sign = sig; return sign; case SSH_KEYTYPE_RSA: e = buffer_get_ssh_string(tmpbuf); ssh_buffer_free(tmpbuf); if (e == NULL) { signature_free(sign); return NULL; } len = ssh_string_len(e); #ifdef HAVE_LIBGCRYPT rsalen = (gcry_pk_get_nbits(pubkey->rsa_pub) + 7) / 8; #elif defined HAVE_LIBCRYPTO rsalen = RSA_size(pubkey->rsa_pub); #endif if (len > rsalen) { ssh_string_free(e); signature_free(sign); ssh_set_error(session, SSH_FATAL, "Signature too big! %d instead of %d", len, rsalen); return NULL; } if (len < rsalen) { ssh_log(session, SSH_LOG_RARE, "RSA signature len %d < %d", len, rsalen); } sign->type = SSH_KEYTYPE_RSA; #ifdef HAVE_LIBGCRYPT if (gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))", ssh_string_len(e), ssh_string_data(e))) { signature_free(sign); ssh_string_free(e); return NULL; } sign->rsa_sign = sig; #elif defined HAVE_LIBCRYPTO sign->rsa_sign = e; #endif #ifdef DEBUG_CRYPTO ssh_log(session, SSH_LOG_FUNCTIONS, "len e: %d", len); ssh_print_hexa("RSA signature", ssh_string_data(e), len); #endif #ifdef HAVE_LIBGCRYPT ssh_string_free(e); #endif return sign; default: return NULL; } return NULL; }
/* is_stderr is set to 1 if the data are extended, ie stderr */ static void channel_rcv_data(SSH_SESSION *session,int is_stderr) { CHANNEL *channel; STRING *str; size_t len; enter_function(); channel = channel_from_msg(session); if (channel == NULL) { ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); leave_function(); return; } if (is_stderr) { u32 ignore; /* uint32 data type code. we can ignore it */ buffer_get_u32(session->in_buffer, &ignore); } str = buffer_get_ssh_string(session->in_buffer); if (str == NULL) { ssh_log(session, SSH_LOG_PACKET, "Invalid data packet!"); leave_function(); return; } len = string_len(str); ssh_log(session, SSH_LOG_PROTOCOL, "Channel receiving %zu bytes data in %d (local win=%d remote win=%d)", len, is_stderr, channel->local_window, channel->remote_window); /* What shall we do in this case? Let's accept it anyway */ if (len > channel->local_window) { ssh_log(session, SSH_LOG_RARE, "Data packet too big for our window(%zu vs %d)", len, channel->local_window); } if (channel_default_bufferize(channel, str->string, len, is_stderr) < 0) { string_free(str); leave_function(); return; } if (len <= channel->local_window) { channel->local_window -= len; } else { channel->local_window = 0; /* buggy remote */ } ssh_log(session, SSH_LOG_PROTOCOL, "Channel windows are now (local win=%d remote win=%d)", channel->local_window, channel->remote_window); string_free(str); leave_function(); }