diff options
Diffstat (limited to 'ssh/transport2.h')
-rw-r--r-- | ssh/transport2.h | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/ssh/transport2.h b/ssh/transport2.h new file mode 100644 index 00000000..204573fb --- /dev/null +++ b/ssh/transport2.h @@ -0,0 +1,261 @@ +/* + * Header connecting the pieces of the SSH-2 transport layer. + */ + +#ifndef PUTTY_SSH2TRANSPORT_H +#define PUTTY_SSH2TRANSPORT_H + +#ifndef NO_GSSAPI +#include "gssc.h" +#include "gss.h" +#define MIN_CTXT_LIFETIME 5 /* Avoid rekey with short lifetime (seconds) */ +#define GSS_KEX_CAPABLE (1<<0) /* Can do GSS KEX */ +#define GSS_CRED_UPDATED (1<<1) /* Cred updated since previous delegation */ +#define GSS_CTXT_EXPIRES (1<<2) /* Context expires before next timer */ +#define GSS_CTXT_MAYFAIL (1<<3) /* Context may expire during handshake */ +#endif + +#define DH_MIN_SIZE 1024 +#define DH_MAX_SIZE 8192 + +struct kexinit_algorithm { + ptrlen name; + union { + struct { + const ssh_kex *kex; + bool warn; + } kex; + struct { + const ssh_keyalg *hostkey; + unsigned hkflags; + bool warn; + } hk; + struct { + const ssh_cipheralg *cipher; + bool warn; + } cipher; + struct { + const ssh2_macalg *mac; + bool etm; + } mac; + struct { + const ssh_compression_alg *comp; + bool delayed; + } comp; + } u; +}; +struct kexinit_algorithm_list { + struct kexinit_algorithm *algs; + size_t nalgs, algsize; +}; + +#define HOSTKEY_ALGORITHMS(X) \ + X(HK_ED25519, ssh_ecdsa_ed25519) \ + X(HK_ED448, ssh_ecdsa_ed448) \ + X(HK_ECDSA, ssh_ecdsa_nistp256) \ + X(HK_ECDSA, ssh_ecdsa_nistp384) \ + X(HK_ECDSA, ssh_ecdsa_nistp521) \ + X(HK_DSA, ssh_dsa) \ + X(HK_RSA, ssh_rsa_sha512) \ + X(HK_RSA, ssh_rsa_sha256) \ + X(HK_RSA, ssh_rsa) \ + X(HK_ED25519, opensshcert_ssh_ecdsa_ed25519) \ + /* OpenSSH defines no certified version of Ed448 */ \ + X(HK_ECDSA, opensshcert_ssh_ecdsa_nistp256) \ + X(HK_ECDSA, opensshcert_ssh_ecdsa_nistp384) \ + X(HK_ECDSA, opensshcert_ssh_ecdsa_nistp521) \ + X(HK_DSA, opensshcert_ssh_dsa) \ + X(HK_RSA, opensshcert_ssh_rsa_sha512) \ + X(HK_RSA, opensshcert_ssh_rsa_sha256) \ + X(HK_RSA, opensshcert_ssh_rsa) \ + /* end of list */ +#define COUNT_HOSTKEY_ALGORITHM(type, alg) +1 +#define N_HOSTKEY_ALGORITHMS (0 HOSTKEY_ALGORITHMS(COUNT_HOSTKEY_ALGORITHM)) + +struct ssh_signkey_with_user_pref_id { + const ssh_keyalg *alg; + int id; +}; +extern const struct ssh_signkey_with_user_pref_id + ssh2_hostkey_algs[N_HOSTKEY_ALGORITHMS]; + +/* + * Enumeration of high-level classes of reason why we might need to do + * a repeat key exchange. A full detailed reason in human-readable + * string form for the Event Log is also provided, but this enum type + * is used to discriminate between classes of reason that the code + * needs to treat differently. + * + * RK_NONE == 0 is the value indicating that no rekey is currently + * needed at all. RK_INITIAL indicates that we haven't even done the + * _first_ key exchange yet. RK_SERVER indicates that we're rekeying + * because the server asked for it, not because we decided it + * ourselves. RK_NORMAL is the usual case. RK_GSS_UPDATE indicates + * that we're rekeying because we've just got new GSSAPI credentials + * (hence there's no point in doing a preliminary check for new GSS + * creds, because we already know the answer); RK_POST_USERAUTH + * indicates that _if_ we're going to need a post-userauth immediate + * rekey for any reason, this is the moment to do it. + * + * So RK_POST_USERAUTH only tells the transport layer to _consider_ + * rekeying, not to definitely do it. Also, that one enum value is + * special in that the user-readable reason text is passed in to the + * transport layer as NULL, whereas fills in the reason text after it + * decides whether it needs a rekey at all. In the other cases, + * rekey_reason is passed in to the at the same time as rekey_class. + */ +typedef enum RekeyClass { + RK_NONE = 0, + RK_INITIAL, + RK_SERVER, + RK_NORMAL, + RK_POST_USERAUTH, + RK_GSS_UPDATE +} RekeyClass; + +typedef struct transport_direction { + const ssh_cipheralg *cipher; + const ssh2_macalg *mac; + bool etm_mode; + const ssh_compression_alg *comp; + bool comp_delayed; + int mkkey_adjust; +} transport_direction; + +struct ssh2_transport_state { + int crState, crStateKex; + + PacketProtocolLayer *higher_layer; + PktInQueue pq_in_higher; + PktOutQueue pq_out_higher; + IdempotentCallback ic_pq_out_higher; + + Conf *conf; + char *savedhost; + int savedport; + const char *rekey_reason; + enum RekeyClass rekey_class; + + unsigned long max_data_size; + + const ssh_kex *kex_alg; + const ssh_keyalg *hostkey_alg; + unsigned char session_id[MAX_HASH_LEN]; + int session_id_len; + int dh_min_size, dh_max_size; + bool dh_got_size_bounds; + dh_ctx *dh_ctx; + ssh_hash *exhash; + + struct DataTransferStats *stats; + + const SshServerConfig *ssc; + + char *client_greeting, *server_greeting; + + bool kex_in_progress, kexinit_delayed; + unsigned long next_rekey, last_rekey; + const char *deferred_rekey_reason; + bool higher_layer_ok; + + /* + * Fully qualified host name, which we need if doing GSSAPI. + */ + char *fullhostname; + + /* shgss is outside the ifdef on purpose to keep APIs simple. If + * NO_GSSAPI is not defined, then it's just an opaque structure + * tag and the pointer will be NULL. */ + struct ssh_connection_shared_gss_state *shgss; +#ifndef NO_GSSAPI + int gss_status; + time_t gss_cred_expiry; /* Re-delegate if newer */ + unsigned long gss_ctxt_lifetime; /* Re-delegate when short */ +#endif + ssh_transient_hostkey_cache *thc; + + bool gss_kex_used; + + tree234 *host_cas; + + int nbits, pbits; + bool warn_kex, warn_hk, warn_cscipher, warn_sccipher; + mp_int *p, *g, *e, *f; + strbuf *ebuf, *fbuf; + strbuf *kex_shared_secret; + strbuf *outgoing_kexinit, *incoming_kexinit; + strbuf *client_kexinit, *server_kexinit; /* aliases to the above */ + int kex_init_value, kex_reply_value; + transport_direction in, out, *cstrans, *sctrans; + ptrlen hostkeydata, sigdata; + strbuf *hostkeyblob; /* used in server to construct host key to + * send to client; in client to check in rekeys */ + char *keystr; + ssh_key *hkey; /* actual host key */ + unsigned hkflags; /* signing flags, used in server */ + RSAKey *rsa_kex_key; /* for RSA kex */ + bool rsa_kex_key_needs_freeing; + ecdh_key *ecdh_key; /* for ECDH kex */ + unsigned char exchange_hash[MAX_HASH_LEN]; + bool can_gssapi_keyex; + bool need_gss_transient_hostkey; + bool warned_about_no_gss_transient_hostkey; + bool got_session_id; + bool can_send_ext_info, post_newkeys_ext_info; + SeatPromptResult spr; + bool guessok; + bool ignorepkt; + struct kexinit_algorithm_list kexlists[NKEXLIST]; +#ifndef NO_GSSAPI + Ssh_gss_buf gss_buf; + Ssh_gss_buf gss_rcvtok, gss_sndtok; + Ssh_gss_stat gss_stat; + Ssh_gss_buf mic; + bool init_token_sent; + bool complete_rcvd; + bool gss_delegate; +#endif + + /* List of crypto primitives below the warning threshold that the + * user has already clicked OK to, so that we don't keep asking + * about them again during rekeys. This directly stores pointers + * to the algorithm vtables, compared by pointer value (which is + * not a determinism hazard, because we're only using it as a + * set). */ + tree234 *weak_algorithms_consented_to; + + /* + * List of host key algorithms for which we _don't_ have a stored + * host key. These are indices into the main hostkey_algs[] array + */ + int uncert_hostkeys[N_HOSTKEY_ALGORITHMS]; + int n_uncert_hostkeys; + + /* + * Indicate that the current rekey is intended to finish with a + * newly cross-certified host key. To double-check that we + * certified the right one, we set this to point to the host key + * algorithm we expect it to be. + */ + const ssh_keyalg *cross_certifying; + + ssh_key *const *hostkeys; + int nhostkeys; + + PacketProtocolLayer ppl; +}; + +/* Helpers shared between transport and kex */ +PktIn *ssh2_transport_pop(struct ssh2_transport_state *s); +void ssh2_transport_dialog_callback(void *, SeatPromptResult); + +/* Provided by transport for use in kex */ +void ssh2transport_finalise_exhash(struct ssh2_transport_state *s); + +/* Provided by kex for use in transport. Must set the 'aborted' flag + * if it throws a connection-terminating error, so that the caller + * won't have to check that by looking inside its state parameter + * which might already have been freed. */ +void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted); + +#endif /* PUTTY_SSH2TRANSPORT_H */ |