#include #include #include #include extern const char *__progname; #include "pp.h" #include "bpp.h" #include "str.h" #include "algs.h" #include "msgs.h" #include "cmdline.h" #include "pkt-util.h" #include "userauth.h" typedef struct authkey AUTHKEY; typedef struct pkpriv PKPRIV; struct pkpriv { AUTHKEY *k; int queried; } ; struct authkey { AUTHKEY *link; HKALG *alg; void *pubdata; int publen; void *privdata; int privlen; char *comment; } ; static AUTHKEY *authkeys; static unsigned char *build_key_query(UASTATE *s) { PKPRIV *p; unsigned char *opp; p = s->algpriv; opp = (*s->pkthead)(s); *opp++ = 0; opp = put_string(opp,hkalg_name(p->k->alg),-1); opp = put_string(opp,p->k->pubdata,p->k->publen); return(opp); } static unsigned char *build_key_sig(UASTATE *s) { PKPRIV *p; BPP *b; unsigned char *opp; STR sig; HASHALG *ha; void *hh; char *hash; p = s->algpriv; b = s->layer->b; ha = (*p->k->alg->prehash)(); hh = (*ha->init)(); opp = put_string(&s->layer->b->opkt[0],b->sessid,b->sessidlen); (*ha->process)(hh,&s->layer->b->opkt[0],opp-&s->layer->b->opkt[0]); opp = (*s->pkthead)(s); *opp++ = 1; opp = put_string(opp,hkalg_name(p->k->alg),-1); opp = put_string(opp,p->k->pubdata,p->k->publen); (*ha->process)(hh,&b->opkt[0],opp-&b->opkt[0]); hash = malloc(ha->hashlen); (*ha->done)(hh,hash); if (! (*p->k->alg->sign)(&sig,p->k->pubdata,p->k->publen,p->k->privdata,p->k->privlen,hash)) { fprintf(stderr,"%s: can't generate authentication signature\n",__progname); exit(1); } opp = put_string(opp,sig.data,sig.len); free(sig.data); return(opp); } static char *read_comment(FILE *f, const char *def) { char *cbuf; int l; int n; int c; static void savec(char c) { if (l >= n) cbuf = realloc(cbuf,n=l+16); cbuf[l++] = c; } cbuf = 0; l = 0; n = 0; while (1) { c = getc(f); switch (c) { case '\n': case EOF: if (l == 0) return(strdup(def)); savec('\0'); return(cbuf); break; case ' ': if (l == 0) break; default: savec(c); if (l >= 80) { savec('.'); savec('.'); savec('.'); savec('\0'); return(cbuf); } break; } } } static int ua_publickey_canuse(BPP *b __attribute__((__unused__))) { void *pub; int publen; void *priv; int privlen; char *comment; static void loadkey(const char *file, int gripe) { char *pubfn; FILE *pubf; char *privfn; FILE *privf; char kname[65]; HKALG *alg; AUTHKEY *ak; asprintf(&pubfn,"%s.pub",file); asprintf(&privfn,"%s.priv",file); pubf = 0; privf = 0; do <"done"> { pubf = fopen(pubfn,"r"); if (pubf == 0) { if (gripe) fprintf(stderr,"%s: can't open public key file %s: %s\n",__progname,pubfn,strerror(errno)); break <"done">; } privf = fopen(privfn,"r"); if (privf == 0) { if (gripe) fprintf(stderr,"%s: can't open private key file %s: %s\n",__progname,privfn,strerror(errno)); break <"done">; } if (fscanf(pubf,"%64s ",&kname[0]) != 1) { if (gripe) fprintf(stderr,"%s: can't use public key in %s (missing type)\n",__progname,pubfn); break <"done">; } alg = hkalg_vfind_c(&kname[0]); if (alg == 0) { if (gripe) fprintf(stderr,"%s: can't use public key in %s (unknown algorithm name)\n",__progname,pubfn); break <"done">; } if (! alg->can_sig) { if (gripe) fprintf(stderr,"%s: can't use public key in %s (algorithm not signature-capable)\n",__progname,pubfn); break <"done">; } if (! (*alg->read_pub)(pubf,&pub,&publen)) { if (gripe) fprintf(stderr,"%s: can't use public key in %s (can't read public-key blob)\n",__progname,pubfn); break <"done">; } comment = read_comment(pubf,file); if (! (*alg->read_priv)(privf,pub,publen,&priv,&privlen)) { if (gripe) fprintf(stderr,"%s: can't use private key in %s (blob unreadable or doesn't match public key)\n",__progname,privfn); free(pub); break <"done">; } ak = malloc(sizeof(AUTHKEY)); ak->link = authkeys; ak->alg = alg; ak->pubdata = pub; ak->publen = publen; ak->privdata = priv; ak->privlen = privlen; ak->comment = comment; authkeys = ak; } while (0); free(pubfn); free(privfn); if (pubf) fclose(pubf); if (privf) fclose(privf); } if (noauthkey) return(0); if (authkey) { loadkey(authkey,1); } else { static void try(const char *suf) { char *t; asprintf(&t,"%s/%s",authkeydir,suf); loadkey(t,0); free(t); } if (! authkeydir) { if (! sshdir) { fprintf(stderr,"%s: nowhere to find key files, public key authentication disabled\n",__progname); return(0); } authkeydir = sshdir; } try("identity.dsa"); try("identity.rsa"); } if (authkeys) { AUTHKEY *ak; printf("publickey authentication possible:"); for (ak=authkeys;ak;ak=ak->link) printf(" %s",ak->alg->name); printf("\n"); } else { printf("publickey authentication not possible\n"); } return(!!authkeys); } static unsigned char *ua_publickey_start(UASTATE *s) { PKPRIV *p; p = malloc(sizeof(PKPRIV)); s->algpriv = p; p->k = authkeys; p->queried = 1; return(build_key_query(s)); } static int ua_publickey_partial(UASTATE *s __attribute__((__unused__))) { abort(); } static int ua_publickey_run(UASTATE *s) { BPP *b; PKPRIV *p; STR algname; STR pkblob; b = s->layer->b; p = s->algpriv; switch (b->ipkt[0]) { case SSH_MSG_USERAUTH_PK_OK: parse_packet(b,pp_fail, PP_IGNORE(1), PP_STRING(&algname), PP_STRING(&pkblob), PP_ENDSHERE ); if (! str_equalsC(algname,p->k->alg->name)) { fprintf(stderr,"%s: publickey authorization protocol error: algorithm name changed (sent %s, got %.*s)\n",__progname,p->k->alg->name,(int)algname.len,algname.data); exit(1); } if (! str_equalsb(pkblob,p->k->pubdata,p->k->publen)) { int i; fprintf(stderr,"%s: publickey authorization protocol error: key blob changed\n",__progname); fprintf(stderr," sent:"); for (i=0;ik->publen;i++) fprintf(stderr," %02x",((const unsigned char *)p->k->pubdata)[i]); fprintf(stderr,"\n got:"); for (i=0;ioplen = build_key_sig(s) - &b->opkt[0]; return(UA_SEND); break; default: fprintf(stderr,"%s: publickey authorization error: unexpected message (type %d)\n",__progname,b->ipkt[0]); exit(1); break; } } static int ua_publickey_retry(UASTATE *s __attribute__((__unused__))) { abort(); } static void ua_publickey_done(UASTATE *s) { PKPRIV *p; p = s->algpriv; free(p); s->algpriv = 0; } UAALG uaalg_publickey = { "publickey", &ua_publickey_canuse, &ua_publickey_start, &ua_publickey_partial, &ua_publickey_run, &ua_publickey_retry, &ua_publickey_done };