зеркало из https://github.com/github/putty.git
240 строки
7.7 KiB
C
240 строки
7.7 KiB
C
/*
|
|
* Header connecting the pieces of the SSH-2 transport layer.
|
|
*/
|
|
|
|
#ifndef PUTTY_SSH2TRANSPORT_H
|
|
#define PUTTY_SSH2TRANSPORT_H
|
|
|
|
#ifndef NO_GSSAPI
|
|
#include "sshgssc.h"
|
|
#include "sshgss.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
|
|
|
|
#define MAXKEXLIST 16
|
|
struct kexinit_algorithm {
|
|
const char *name;
|
|
union {
|
|
struct {
|
|
const ssh_kex *kex;
|
|
bool warn;
|
|
} kex;
|
|
struct {
|
|
const ssh_keyalg *hostkey;
|
|
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;
|
|
};
|
|
|
|
#define HOSTKEY_ALGORITHMS(X) \
|
|
X(HK_ED25519, ssh_ecdsa_ed25519) \
|
|
X(HK_ECDSA, ssh_ecdsa_nistp256) \
|
|
X(HK_ECDSA, ssh_ecdsa_nistp384) \
|
|
X(HK_ECDSA, ssh_ecdsa_nistp521) \
|
|
X(HK_DSA, ssh_dss) \
|
|
X(HK_RSA, 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;
|
|
char *hostkey_str; /* string representation, for easy checking in rekeys */
|
|
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;
|
|
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;
|
|
|
|
int nbits, pbits;
|
|
bool warn_kex, warn_hk, warn_cscipher, warn_sccipher;
|
|
mp_int *p, *g, *e, *f, *K;
|
|
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;
|
|
char *keystr, *fingerprint;
|
|
ssh_key *hkey; /* actual host key */
|
|
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;
|
|
int dlgret;
|
|
bool guessok;
|
|
bool ignorepkt;
|
|
struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST];
|
|
#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 *, int);
|
|
|
|
/* 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 */
|