#ifndef _ALGS_H_1292ae2c_ #define _ALGS_H_1292ae2c_ /* This file is in the public domain. */ #include /* * Definitions for algorithms. * * What an algorithm constitutes depends on which algorithm type it * belongs to; see the ALGTYPE struct for a description of a type and * the individual algorithm structs for the various types. * * ENCALG, COMPALG, MACALG, KEXALG, and HKALG represent encoding, * compression, MAC, key-exchange, and public-key algorithms. (The * HKALG name is historical and means "host-key algorithm".) HASHALG * is similar but is used for hashing algorithms, though the protocol * does not define any such thing (we are merely leveraging the * algorithm support machinery); UAALG likewise represents a user * authentication algorithm (these exist in the protocol, but in a * very different way from most of the algorithm types). * * An ALGLIST represents a list of algorithms. This can be a default * list or an explicit list. An ALE is an element in an explicit list * (ALE stands for Alg List Element). * * An ALGTYPE represents an algorithm type. This consists of a string * tag (for debugging) and a number of functions for doing things with * algorithms of that type, such as enumerating them or returning an * algorithm's name. */ typedef struct encalg ENCALG; typedef struct compalg COMPALG; typedef struct macalg MACALG; typedef struct kexalg KEXALG; typedef struct hkalg HKALG; typedef struct hashalg HASHALG; typedef struct uaalg UAALG; typedef struct alglist ALGLIST; typedef struct ale ALE; typedef struct algtype ALGTYPE; #include "bpp.h" #include "str.h" #include "userauth.h" /* * An encryption algorithm. An encryption algorithm has: * * name: the algorithm's name. * comment: a brief text description of the algorithm. * blksize: the block size (1 for stream ciphers). * ivsize: the IV size (0 if none, eg stream ciphers). * keysize: the key size, in bytes. * hide: true iff this algorithm should not be in the default list. * init_enc(key,iv), init_dec(key,iv): routine to initialize for * encryption (init_enc) or decryption (init_dec). Sizes of the key * and IV data blocks are fixed per-algorithm (keysize and ivsize). * These routines return opaque handles. * process(handle,indata,outdata,len): routine to do en-/de-cryption. * len is in bytes and will always be a multiple of blksize. indata * and outdata may be equal but must not otherwise overlap. * done(handle): routine to clean up and free the handle. */ struct encalg { const char *name; const char *comment; int blksize; int ivsize; int keysize; int hide; void *(*init_enc)(const void *, const void *); void *(*init_dec)(const void *, const void *); void (*process)(void *, const void *, void *, int); void (*done)(void *); } ; /* * A compression algorithm. A compression algorithm has: * * name: the algorithm's name. * comment: a brief text description of the algorithm. * init_comp(), init_decomp(): initialize for compression (init_comp) * or decompression (init_decomp), returning a handle. * process(handle,indata,inlen,callback): do compression or * decompression, according to how the handle was created. * flush(handle,callback): flush any partial output. * done: tear down the handle and free stuff. * * The semantics of compression/decompression are that (*process)() is * called one or more times for a data block; at the end of the block, * (*flush)() is called to push out any remaining partial block. The * callbacks for these calls should all be functionally the same. */ struct compalg { const char *name; const char *comment; void *(*init_comp)(void); void *(*init_decomp)(void); void (*process)(void *, const void *, int, void (*)(const void *, int)); void (*flush)(void *, void (*)(const void *, int)); void (*done)(void *); } ; /* * A MAC algorithm. These are what are called keyed MACs; that is, * they take some secret key data as well as the data to be protected. * A MAC algorithm has: * * name: the algorithm's name. * comment: a brief text description of the algorithm. * maclen: the length, in bytes, of MACs from this algorithm. * keylen: the length, in bytes, of keys to this algorithm. * hide: true iff this algorithm should not be in the default list. * init(key): initialize an instance of the algorithm, returning a * handle. * check(handle,inmac,nb,...): check the MAC on a data stream against a * received MAC, inmac. The data stream is made up of nb data blocks; * the variable part of the arglist is nb repetitions of a * const void * pointer and an int length. Return value is true for a * match and false for a mismatch. * gen(handle,mac,nb,...): generate the MAC for a data stream. Args * are as for check, except that the second arg receives the generated * MAC rather than supplying one to be compared against. * done(handle): clean up any data associated with handle. */ struct macalg { const char *name; const char *comment; int maclen; int keylen; int hide; void *(*init)(const void *); int (*check)(void *, const void *, int, ...); void (*gen)(void *, void *, int, ...); void (*done)(void *); } ; /* * A key-exchange (kex) algorithm. A kex algorithm has: * * name: the algorithm's name. * comment: a brief text description of the algorithm. * need_enc: true if this kex algorithm requires an encryption-capable * host key algorithm. * need_sig: true if this kex algorithm requires a signature-capable * host key algorithm. * disabled(): returns 0, if the algorithm is not disabled, or a string * describing the reason why, if it is. * init_c(layer), init_s(layer): initialize for operation as the client * (init_c) or server (init_s), returning a handle. The argument is * the LAYER pointer for transport-layer messages. * run(layer,handle): run the key-exchange algorithm. layer is the * LAYER pointer for transport-layer messages. * servinit(alg), servidle(alg), servproc(alg), servpriv: support for * doing precomputation with leftover cycles in the server. servinit * is called to initialize this for an algorithm, servidle is called * as a block function (in particular, its return value is that of a * block function), and servproc is called to shut down the idle-time * precomputation when a process switches from being the global server * process to being the server for a specific connection (under normal * circumstances, very soon after forking). servpriv is provided for * the other three functions to store private data (usually, a pointer * to a private data block) in; its use is completely up to them. */ struct kexalg { const char *name; const char *comment; int need_enc; int need_sig; const char *(*disabled)(void); void *(*init_c)(LAYER *); void *(*init_s)(LAYER *); int (*run)(LAYER *, void *); void (*servinit)(KEXALG *); int (*servidle)(KEXALG *); void (*servproc)(KEXALG *); void *servpriv; } ; /* * A public-key algorithm. A public-key algorithm has: * * name: the algorithm's name. * comment: a brief text description of the algorithm. * can_enc: true iff this algorithm can do encryption. * can_sig: true iff this algorithm can do signatures. * canuse(serverp): true iff this algorithm can be used for host keys. * Argument is a boolean, true if the call is for server mode and * false for client mode. In server mode, this routine is responsible * for disabling algorithms for which no host key is available. * host_key(bpp,privdata,privlen): called to retrieve the host key for * an algorithm. The host key's public data is stored into the K_S * member of the BPP; the private data, through privdata and privlen. * match(a_ptr,a_len,b_ptr,b_len): determines whether two public data * blobs represent the same key. (This may be little more than a * bcmp; it exists for algorithms that include random nonce data in * their key blobs.) * prehash(): Not used if can_sig is false. If can_sig is true, called * to return a HASHALG for hashing data before signing it. Note that * there is code that assumes that a given algorithm's prehash * function always returns the same algorithm. * checksig(pubdata,publen,hash,sigdata,siglen): Not used if can_sig is * false. If can_sig is true, called to check a signature. * pubdata/publen provide the key's public data blob; sigdata and * siglen the signature to compare against. hash is the data to sign * (ie, a hash from the algorithm prehash returned). Return value is * true if the signature is valid, false if not. * sign(sig,pubdata,publen,privdata,privlen,hash): Not used if can_sig * is false. If can_sig is true, called to sign data. pubdata/publen * provide the key's public data, privdata/privlen the private data. * hash to be signed (from the algorithm prehash returned); sig * receives the resulting signature data blob (it is the caller's * responsibility to free this when it is no longer needed). Return * value is true on success, false on failure. * genkey(pubf,privf,bits,flags): generate a key. The public data is * written to pubf, the private to privf. bits is the size in bits of * the key desired. flags contains flag bits: * - GEN_F_VERBOSE * If set, the generation procedure writes * progress indications (to stdout). * - GEN_F_VALUES * If set, the resulting key parameters are * printed (to stdout). * The details of the output from either flag are algorithm-specific * and are not documented; this output is intended for human * consumption and it is a mistake to depend on its format. * checkpub(data,len): check whether a public-key data blob purportedly * being for this algorithm actually is. This is for sanity-checking; * it is acceptable for it to miss relatively subtle defects (eg, an * RSA key whose exponent is greater than its modulus). * private(op,...): an algorithm-specific escape hatch. Conceptually, * this corresponds roughly to ioctl(2). The first argument is a C * string indicating what operation is being performed, with further * arguments being whatever the algorithm wants; the details can be * anything agreed upon by the algorithm and its caller(s). * altnames: a vector of alternative names for this algorithm (eg, * "dsa" and "dss" for "ssh-dss"). * deffile: a default key file name for this algorithm. * hkfile: a host-key file name for this algorithm. */ struct hkalg { const char *name; const char *comment; int can_enc; int can_sig; int (*canuse)(int); void (*host_key)(BPP *, void **, int *); int (*match)(const void *, int, const void *, int); /* BEGIN if can_sig */ HASHALG *(*prehash)(void); int (*checksig)(const void *, int, const void *, const void *, int); int (*sign)(STR *, const void *, int, const void *, int, const void *); /* END if can_sig */ void (*genkey)(FILE *, FILE *, int, unsigned int); #define GEN_F_VERBOSE 0x00000001 #define GEN_F_VALUES 0x00000002 int (*checkpub)(const void *, int); void (*private)(const char *, ...); const char * const *altnames; const char *deffile; const char *hkfile; } ; /* * A hashing algorithm. A hashing algorithm has: * * name: the algorithm's name. * comment: a brief text description of the algorithm. * hashlen: the length (in bytes) of a hash generated by this * algorithm. * init(): create an instance of this algorithm and return a handle. * process(handle,data,len): process the data. * clone(handle): return a new handle having the same state as the * argument handle (but independent once created). * done(handle,hash): finish a hash operation, generating the hash. * drop(handle): summarily discard a hash-in-progress. */ struct hashalg { const char *name; const char *comment; int hashlen; void *(*init)(void); void (*process)(void *, const void *, int); void *(*clone)(void *); void (*done)(void *, void *); void (*drop)(void *); } ; /* * A user authentication algorithm. A user authentication algorithm * has: * * name: the algorithm's name. * comment: a brief text description of the algorithm. * c: client-side stuff: * c.canuse(bpp): returns true iff this algorithm can be used with bpp. * (This can, eg, disable an authentication algorithm if the * encryption algorithm in use on the connection is too weak.) * c.start(state): starts the algorithm for a given CUASTATE, setting * up any private data necessary in its algpriv member. Return value * is a pointer just past the end of the initial packet. * c.partial(state): called when the server indicates partial success * for an authentication attempt using this algorithm, and this * algorithm is named in the "can continue" list. Returns one of the * UA_* values. * c.run(state): called when a packet in the algorithm-specific range * is receved. Returns one of the UA_* values. * c.retry(state): called when the server indicates failure for an * authentication attempt using this algorithm, and this algorithm is * named in the "can continue" list. Returns one of the UA_* values. * c.done(state): called when an authentication attempt using this algorithm * terminates. * s: server-side stuff: * s.canuse(state): returns true iff this algorithm can be used for the * given authentication attempt. * s.request(state,data,len): called when a client request is received * for this authentication method. * s.attempts: a count of authentication attempts using this method. */ struct uaalg { const char *name; const char *comment; struct { int (*canuse)(BPP *); unsigned char *(*start)(CUASTATE *); int (*partial)(CUASTATE *); int (*run)(CUASTATE *); int (*retry)(CUASTATE *); void (*done)(CUASTATE *); } c; struct { int (*canuse)(SUASTATE *); int (*request)(SUASTATE *, const void *, int); int attempts; } s; } ; /* * Return values from c.partial and c.run calls. * * Semantics: * * UA_READ means to go back and read another packet; any output needed * has already been generated. * * UA_SEND means to send the packet currently pending output, then go * back and read another packet. * * UA_NEXT means to give up on this authentication method and try the * next one. */ #define UA_READ 1 #define UA_SEND 2 #define UA_NEXT 3 /* * A list of algorithms. * * type is the kind of algorithm. * * flags holds flag bits. ALF_DEFAULT means that the remaining members * are meaningless and the list consists of the default algorithms for * its type. * * head and tail are a tconc of the ALEs holding the list itself. * * ALGLIST_DEFINIT constructs an initializer that gives a type and sets * ALF_DEFAULT. */ struct alglist { const ALGTYPE *type; unsigned int flags; #define ALF_DEFAULT 0x00000001 ALE *head; ALE **tail; } ; #define ALGLIST_DEFINIT(type) {(type),ALF_DEFAULT,0,0} /* * An ALE is an AlgList Element, an algorithm in an ALGLIST. They are * linked together by the link field; alg is the algorithm itself, * which is a void * so we can use the same structure regardless of * the algorithm type. (The other alternative is to make alg a union * of all the algorithm types, but that complicates the code * significantly.) */ struct ale { ALE *link; void *alg; } ; /* * An ALGTYPE is an algorithm type, such as "key exchange" or * "compression". * * tag: a string name for this type, used for debugging. * find_c(name): look up an algorithm by name, where the name is a C * string. * find_rostr(name): look up an algorithm by name, where the name is a * ROSTR. * name(alg): return an algorithm's name. * comment(alg): return an algorithm's comment string. * disabled(alg): return nil if the algorithm can be used, or a reason * string if not. * list(inx): enumerates the algorithms. To list the algorithms of * this type, start with an argument of zero and increment it until * you get a nil pointer back. * deflist(inx): enumerates the algorithms on the default list for this * type. The semantics are as for list, except that the list of * algorithms contains just the default algorithms of this type * instead of all algorithms. * servidle_init(alg), servidle(alg), servproc(alg): these are the * interface allowing algorithms to do precomputation with spare * cycles in the server. alg is always the particular algorithm. * servidle_init is called to initialize the system; then servidle is * called when the server has spare cycles. Its return semantics are * those of a block function. Finally, servproc is called to shut * down precomputation when a process switches from being the global * server process to being the server process for a specific * connection. */ struct algtype { const char *tag; void *(*find_c)(const char *); void *(*find_rostr)(ROSTR); const char *(*name)(void *); const char *(*comment)(void *); const char *(*disabled)(void *); void *(*list)(int); void *(*deflist)(int); void (*servidle_init)(void *); int (*servidle)(void *); void (*servproc)(void *); } ; /* * The individual algorithm types. Each declaration is accompanied by * any idiosyncratic routine declarations for that type. */ /* * Encryption. * * encalg_init(alg,key,iv,dir) initializes an encryption algorithm for * operation. dir is a character which specifies the direction: 'r' * for read (decryption) operation and 'w' for write (encryption) * operation. The return value is a state handle. * encalg_i(alg,state,out,indata,inlen,wanted) runs decryption on * input. out is called as output is generated. indata/inlen are the * ciphertext data; wanted is the number of cleartext bytes desired * (once this many bytes have been generated, decryption will stop at * the next convenient boundary). * encalg_o(alg,state,out,indata,inlen) runs encryption on output. * Args are the same as encalg_i, except that there is no * byte-count-desired argument (and cleartext and ciphertext swap * roles). * encalg_done(alg,state) shuts down the algorithm instance. * * These routines exist in order to wrap the ENCALG's encryption calls * in buffering and logging layers. Otherwise, we'd use the * algorithm's methods directly, as is done for most algorithm * actions. */ extern const ALGTYPE at_enc; extern void *encalg_init(ENCALG *, const void *, const void *, char); extern int encalg_i(ENCALG *, void *, void (*)(const void *, int), const void *, int, int); extern void encalg_o(ENCALG *, void *, void (*)(const void *, int), const void *, int); extern void encalg_done(ENCALG *, void *); /* * Compression. * * compalg_init(alg,dir): calls the init method from the algorithm for * the direction (compress if dir is 'w', decokmpress if 'r') and * returns the resulting handle. */ extern const ALGTYPE at_comp; extern void *compalg_init(COMPALG *, char); /* * MAC. * * macalg_init(alg,key) simply calls the algorithm's init method. It * exists largely for historical reasons; it could be replaced with a * direct call. */ extern const ALGTYPE at_mac; extern void *macalg_init(MACALG *, const void *); /* * Key exchange (kex). */ extern const ALGTYPE at_kex; /* * Public-key crypto (the "hk" name is historical and stands for "host * key".) */ extern const ALGTYPE at_hk; /* * User authentication. */ extern const ALGTYPE at_ua; /* * The number of different algorithm types, and an extern declaration * of the array of types. */ #define AT__N 6 /* enc, comp, mac, kex, hk, ua */ extern const ALGTYPE *at__list[]; /* * Algorithm-list calls. Except as noted, these must not be called on * default lists. * * alglist_init(list,type) initializes an ALGLIST, given the ALGTYPE * for it. The list is initialized as non-default and empty. It * completely ignores the current state of the ALGLIST. * alglist_clear(list) discards everything in the ALGLIST. It leaves * the list in a consistent state where it can be freed, but without * any particular invariant on its contents or lack thereof. It works * on default lists. * alglist_map(list,cb) calls cb for each algorithm in its list, in * order. If any callback call returns a negative value, alglist_map * returns that value without checking the rest of the list; * otherwise, the return value is the sum of all the callback return * values. * alglist_dropalg(list,alg) removes alg from list list. If alg is not * present, nothing happens; if alg is present multiple times, all * occurrences are removed. * alglist_append1(list,alg) adds alg to the tail of list. It does not * check to see whether alg is already present. * alglist_prepend1(list,alg) adds alg to the head of list. It does * not check to see whether the algorithm is already present. * alglist_expand_default(list) converts a default list into a * non-default containing the default list of algorithms for its type. * It does nothing when called on a non-default list. * alglist_filter(list,test) passes a list through a filter. test is * called on each element of list. Those elements for which test * returns nonzero remain in the list; those for which test returns * zero are dropped. No promises are made about the order in which * entries are tested, though retained entries are in the same order * among themselves as they were in the original list. * alglist_first(list) returns the first algorithm in a list. If the * list is empty, it returns a nil pointer. * alglist_present(list,alg) tests whether alg is in list (return value * nonzero) or not (return value zero). * alglist_empty(list) tests whether list is empty (return value * nonzero) or not (return value zero). * alglist_dump(list,outf) prints list's algorithm names to outf, in * order, with a space preceding each one (including the first). * alglists_identical(list1,list2) tests whether two lists contain * exactly the same algorithms in the same order (return value * nonzero) or not (return value zero). * alglist_replace(list1,list2) throws away everything in list1, then * replaces it with a copy of list2. */ extern void alglist_init(ALGLIST *, const ALGTYPE *); extern void alglist_clear(ALGLIST *); extern int alglist_map(ALGLIST *, int (*)(void *)); extern void alglist_dropalg(ALGLIST *, void *); extern void alglist_append1(ALGLIST *, void *); extern void alglist_prepend1(ALGLIST *, void *); extern void alglist_expand_default(ALGLIST *); extern void alglist_filter(ALGLIST *, int (*)(void *)); extern void *alglist_first(ALGLIST *); extern int alglist_present(ALGLIST *, void *); extern int alglist_empty(ALGLIST *); extern void alglist_dump(ALGLIST *, FILE *); extern int alglists_identical(ALGLIST *, ALGLIST *); extern void alglist_replace(ALGLIST *, ALGLIST *); /* * The lists of algorithms. The actual lists are generated by Makefile * machinery at build time. */ extern ENCALG *alglist_enc[]; extern COMPALG *alglist_comp[]; extern MACALG *alglist_mac[]; extern KEXALG *alglist_kex[]; extern HKALG *alglist_hk[]; extern HASHALG *alglist_hash[]; extern UAALG *alglist_ua[]; #endif