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 = ssh_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 = ssh_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; }
/** * @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 = ssh_buffer_get_ssh_string(buffer); if (type_s == NULL) { ssh_buffer_free(buffer); return SSH_ERROR; } ssh_string_free(type_s); if (type == SSH_KEYTYPE_RSA_CERT01 || type == SSH_KEYTYPE_DSS_CERT01) { rc = pki_import_cert_buffer(buffer, type, pkey); } else { rc = pki_import_pubkey_buffer(buffer, type, pkey); } ssh_buffer_free(buffer); return rc; }
/** @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 = ssh_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 = ssh_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 = ssh_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 (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { goto error; } rc=ssh_packet_send(session); SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; error: return SSH_ERROR; }
/** * @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_LOG(SSH_LOG_WARN, "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_LOG(SSH_LOG_WARN, "Out of memory!"); goto fail; } type_s = ssh_buffer_get_ssh_string(buffer); if (type_s == NULL) { SSH_LOG(SSH_LOG_WARN, "Out of memory!"); goto fail; } type = ssh_key_type_from_name(ssh_string_get_char(type_s)); if (type == SSH_KEYTYPE_UNKNOWN) { SSH_LOG(SSH_LOG_WARN, "Unknown key type found!"); goto fail; } ssh_string_free(type_s); if (type == SSH_KEYTYPE_RSA_CERT01 || type == SSH_KEYTYPE_DSS_CERT01) { rc = pki_import_cert_buffer(buffer, type, pkey); } else { 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 = ssh_buffer_get_ssh_string(packet); if (e == NULL) { ssh_set_error(session, SSH_FATAL, "No e number in client request"); return -1; } if (ssh_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; }
/* * Test the behavior of ssh_buffer_get_ssh_string with invalid data */ static void *thread_ssh_buffer_get_ssh_string(void *threadid) { ssh_buffer buffer = NULL; size_t i, j, k, l; int rc; /* some values that can go wrong */ uint32_t values[] = { 0xffffffff, 0xfffffffe, 0xfffffffc, 0xffffff00, 0x80000000, 0x80000004, 0x7fffffff}; char data[128] = {0}; /* Unused */ (void)threadid; memset(data, 'X', sizeof(data)); for (i = 0; i < ARRAY_SIZE(values); ++i) { for (j = 0; j < (int)sizeof(data); ++j) { for (k = 1; k < 5; ++k) { buffer = ssh_buffer_new(); assert_non_null(buffer); for (l = 0; l < k; ++l) { rc = ssh_buffer_add_u32(buffer, htonl(values[i])); assert_int_equal(rc, 0); } rc = ssh_buffer_add_data(buffer,data,j); assert_int_equal(rc, 0); for (l = 0; l < k; ++l) { ssh_string str = ssh_buffer_get_ssh_string(buffer); assert_null(str); SSH_STRING_FREE(str); } SSH_BUFFER_FREE(buffer); } } } pthread_exit(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 = ssh_buffer_get_ssh_string(buffer); if (p == NULL) { goto fail; } q = ssh_buffer_get_ssh_string(buffer); if (q == NULL) { ssh_string_burn(p); ssh_string_free(p); goto fail; } g = ssh_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 = ssh_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 = ssh_buffer_get_ssh_string(buffer); if (e == NULL) { goto fail; } n = ssh_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 = ssh_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 = ssh_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 = ssh_buffer_get_ssh_string(buffer); if (ssh_string_len(pubkey) != ED25519_PK_LEN) { SSH_LOG(SSH_LOG_WARN, "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_DSS_CERT01: case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_UNKNOWN: default: SSH_LOG(SSH_LOG_WARN, "Unknown public key protocol %d", type); goto fail; } *pkey = key; return SSH_OK; fail: ssh_key_free(key); return SSH_ERROR; }
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ /* ECDH keys */ ssh_string q_c_string; ssh_string q_s_string; EC_KEY *ecdh_key; const EC_GROUP *group; const EC_POINT *ecdh_pubkey; bignum_CTX ctx; /* SSH host keys (rsa,dsa,ecdsa) */ ssh_key privkey; ssh_string sig_blob = NULL; int len; int rc; /* Extract the client pubkey from the init packet */ q_c_string = ssh_buffer_get_ssh_string(packet); if (q_c_string == NULL) { ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet"); return SSH_ERROR; } session->next_crypto->ecdh_client_pubkey = q_c_string; /* Build server's keypair */ ctx = BN_CTX_new(); ecdh_key = EC_KEY_new_by_curve_name(NISTP256); if (ecdh_key == NULL) { ssh_set_error_oom(session); BN_CTX_free(ctx); return SSH_ERROR; } group = EC_KEY_get0_group(ecdh_key); EC_KEY_generate_key(ecdh_key); ecdh_pubkey = EC_KEY_get0_public_key(ecdh_key); len = EC_POINT_point2oct(group, ecdh_pubkey, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, ctx); q_s_string = ssh_string_new(len); if (q_s_string == NULL) { EC_KEY_free(ecdh_key); BN_CTX_free(ctx); return SSH_ERROR; } EC_POINT_point2oct(group, ecdh_pubkey, POINT_CONVERSION_UNCOMPRESSED, ssh_string_data(q_s_string), len, ctx); BN_CTX_free(ctx); session->next_crypto->ecdh_privkey = ecdh_key; session->next_crypto->ecdh_server_pubkey = q_s_string; /* build k and session_id */ rc = ecdh_build_k(session); if (rc < 0) { ssh_set_error(session, SSH_FATAL, "Cannot build k number"); return SSH_ERROR; } /* privkey is not allocated */ rc = ssh_get_key_params(session, &privkey); if (rc == SSH_ERROR) { return SSH_ERROR; } rc = ssh_make_sessionid(session); if (rc != SSH_OK) { ssh_set_error(session, SSH_FATAL, "Could not create a session id"); return SSH_ERROR; } sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey); if (sig_blob == NULL) { ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); return SSH_ERROR; } rc = ssh_buffer_pack(session->out_buffer, "bSSS", SSH2_MSG_KEXDH_REPLY, session->next_crypto->server_pubkey, /* host's pubkey */ q_s_string, /* ecdh public key */ sig_blob); /* signature blob */ ssh_string_free(sig_blob); if (rc != SSH_OK) { ssh_set_error_oom(session); return SSH_ERROR; } SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent"); rc = ssh_packet_send(session); if (rc == SSH_ERROR) { return SSH_ERROR; } /* Send the MSG_NEWKEYS */ rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); if (rc < 0) { return SSH_ERROR;; } session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; rc = ssh_packet_send(session); SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; }
sftp_client_message sftp_get_client_message(sftp_session sftp) { ssh_session session = sftp->session; sftp_packet packet; sftp_client_message msg; ssh_buffer payload; int rc; msg = malloc(sizeof (struct sftp_client_message_struct)); if (msg == NULL) { ssh_set_error_oom(session); return NULL; } ZERO_STRUCTP(msg); packet = sftp_packet_read(sftp); if (packet == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } payload = packet->payload; msg->type = packet->type; msg->sftp = sftp; /* take a copy of the whole packet */ msg->complete_message = ssh_buffer_new(); ssh_buffer_add_data(msg->complete_message, ssh_buffer_get(payload), ssh_buffer_get_len(payload)); ssh_buffer_get_u32(payload, &msg->id); switch(msg->type) { case SSH_FXP_CLOSE: case SSH_FXP_READDIR: msg->handle = ssh_buffer_get_ssh_string(payload); if (msg->handle == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_READ: rc = ssh_buffer_unpack(payload, "Sqd", &msg->handle, &msg->offset, &msg->len); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_WRITE: rc = ssh_buffer_unpack(payload, "SqS", &msg->handle, &msg->offset, &msg->data); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_REMOVE: case SSH_FXP_RMDIR: case SSH_FXP_OPENDIR: case SSH_FXP_READLINK: case SSH_FXP_REALPATH: rc = ssh_buffer_unpack(payload, "s", &msg->filename); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_RENAME: case SSH_FXP_SYMLINK: rc = ssh_buffer_unpack(payload, "sS", &msg->filename, &msg->data); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_MKDIR: case SSH_FXP_SETSTAT: rc = ssh_buffer_unpack(payload, "s", &msg->filename); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_FSETSTAT: msg->handle = ssh_buffer_get_ssh_string(payload); if (msg->handle == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_LSTAT: case SSH_FXP_STAT: rc = ssh_buffer_unpack(payload, "s", &msg->filename); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } if(sftp->version > 3) { ssh_buffer_unpack(payload, "d", &msg->flags); } break; case SSH_FXP_OPEN: rc = ssh_buffer_unpack(payload, "sd", &msg->filename, &msg->flags); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; case SSH_FXP_FSTAT: rc = ssh_buffer_unpack(payload, "S", &msg->handle); if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } break; default: ssh_set_error(sftp->session, SSH_FATAL, "Received unhandled sftp message %d", msg->type); sftp_client_message_free(msg); return NULL; } sftp_packet_free(packet); return msg; }