#include #include #include #include #include extern const char *__progname; #include "pp.h" #include "bpp.h" #include "str.h" #include "rnd.h" #include "algs.h" #include "msgs.h" #include "hkdb.h" #include "pkt-util.h" typedef struct dhge_sha1_state DHGE_SHA1_STATE; struct dhge_sha1_state { int (*nextstep)(LAYER *, DHGE_SHA1_STATE *); MP_INT p; MP_INT g; MP_INT x; MP_INT e; } ; static int min = 1024; static int n = 2048; static int max = 8192; #if 0 static void *kex_d_h_g_e_sha1_run(BPP *b, void *sv) { DHGE_SHA1_STATE *s; int xbits; int xbytes; unsigned char xhbmask; char *xtmp; unsigned char *xbin; int i; MP_INT q; MP_INT f; MP_INT K; MP_INT tmp1; STR Hsig; void *hash; s = sv; switch (s->step) { case STEP_GEX_REQUEST: step_gex_request(b,s); return(0); break; case STEP_GEX_INIT: if (b->ipkt[0] != SSH_MSG_KEX_DH_GEX_REPLY) { fprintf(stderr,"%s: MSG_KEX_DH_GEX_REPLY packet isn't\n",__progname); exit(1); } parse_packet(b,pp_fail, PP_IGNORE(1), PP_STRING(&b->K_S), PP_MPINT(&f), PP_STRING(&Hsig), PP_ENDSHERE ); if ((mpz_cmp(&f,&p) >= 0) || (mpz_cmp_ui(&f,1) < 0)) { fprintf(stderr,"%s: server's f value is out of range\n",__progname); exit(1); } check_host_key(b->hk,b->K_S.data,b->K_S.len); mpz_powm(&K,&f,&x,&p); b->kex_hlen = 20; b->kex_h = malloc(20); hash = sha1_init(); opp = put_string(&b->opkt[0],&b->c_version[0],b->c_vlen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],&b->s_version[0],b->s_vlen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->c_kexinit_payload,b->c_kexinit_paylen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->s_kexinit_payload,b->s_kexinit_paylen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->K_S.data,b->K_S.len); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_uint32(&b->opkt[0],min); opp = put_uint32(opp,n); opp = put_uint32(opp,max); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&p); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&g); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&e); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&f); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&K); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); b->kex_klen = opp - &b->opkt[0]; b->kex_k = malloc(b->kex_klen); bcopy(&b->opkt[0],b->kex_k,b->kex_klen); sha1_result(hash,b->kex_h); if (! (*b->hk->checksig)(b,b->kex_h,b->kex_hlen,Hsig.data,Hsig.len)) { fprintf(stderr,"%s: kex hash signature wrong\n",__progname); exit(1); } mpz_clear(&p); mpz_clear(&g); mpz_clear(&q); mpz_clear(&x); mpz_clear(&e); mpz_clear(&f); mpz_clear(&K); mpz_clear(&tmp1); { extern HASHALG hashalg_sha1; b->kex_hash = &hashalg_sha1; } free(s); return(1); break; } } #endif #if 0 static int kex_d_h_g_e_sha1_run(BPP *b) { int xbits; int xbytes; unsigned char xhbmask; char *xtmp; unsigned char *xbin; int i; unsigned char *opp; MP_INT p; MP_INT g; MP_INT q; MP_INT x; MP_INT e; MP_INT f; MP_INT K; MP_INT tmp1; STR Hsig; void *hash; if (! b->hk->can_sig) { fprintf(stderr,"%s: kex %s: server host key algorithm (%s) can't do signatures!\n",__progname,b->kex->name,b->hk->name); exit(1); } mpz_init(&p); mpz_init(&g); mpz_init(&q); mpz_init(&x); mpz_init(&e); mpz_init(&f); mpz_init(&K); mpz_init(&tmp1); mpz_tdiv_q_ui(&q,&p,2); opp = &b->opkt[0]; *opp++ = SSH_MSG_KEX_DH_GEX_REQUEST; opp = put_uint32(opp,min); opp = put_uint32(opp,n); opp = put_uint32(opp,max); b->oplen = opp - &b->opkt[0]; bpp_w_pkt(b); bpp_r_pkt(b); if (b->ipkt[0] != SSH_MSG_KEX_DH_GEX_GROUP) { fprintf(stderr,"%s: MSG_KEX_DH_GEX_GROUP packet isn't\n",__progname); exit(1); } parse_packet(b,pp_fail, PP_IGNORE(1), PP_MPINT(&p), PP_MPINT(&g), PP_ENDSHERE ); mpz_tdiv_q_2exp(&tmp1,&p,1); xbits = mpz_sizeinbase(&tmp1,2); xbytes = (xbits + 7) >> 3; xtmp = malloc((xbytes*2)+1); xbin = malloc(xbytes); xhbmask = "\377\001\003\007\017\037\077\177"[xbits&7]; while (1) { random_data(xbin,xbytes); xbin[0] &= xhbmask; for (i=0;i= 0) || (mpz_cmp_ui(&x,1) <= 0)) continue; break; } mpz_powm(&e,&g,&x,&p); b->opkt[0] = SSH_MSG_KEX_DH_GEX_INIT; opp = put_mpint(&b->opkt[1],&e); b->oplen = opp - &b->opkt[0]; bpp_w_pkt(b); bpp_r_pkt(b); if (b->ipkt[0] != SSH_MSG_KEX_DH_GEX_REPLY) { fprintf(stderr,"%s: MSG_KEX_DH_GEX_REPLY packet isn't\n",__progname); exit(1); } parse_packet(b,pp_fail, PP_IGNORE(1), PP_STRING(&b->K_S), PP_MPINT(&f), PP_STRING(&Hsig), PP_ENDSHERE ); if ((mpz_cmp(&f,&p) >= 0) || (mpz_cmp_ui(&f,1) < 0)) { fprintf(stderr,"%s: server's f value is out of range\n",__progname); exit(1); } /* XXX verify that b->K_S really is the right host key */ { int i; printf("host key:"); for (i=0;iK_S.len;i++) printf(" %02x",b->K_S.data[i]); printf("\n"); } mpz_powm(&K,&f,&x,&p); b->kex_hlen = 20; b->kex_h = malloc(20); hash = sha1_init(); opp = put_string(&b->opkt[0],&b->c_version[0],b->c_vlen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],&b->s_version[0],b->s_vlen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->c_kexinit_payload,b->c_kexinit_paylen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->s_kexinit_payload,b->s_kexinit_paylen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->K_S.data,b->K_S.len); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_uint32(&b->opkt[0],min); opp = put_uint32(opp,n); opp = put_uint32(opp,max); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&p); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&g); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&e); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&f); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&K); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); b->kex_klen = opp - &b->opkt[0]; b->kex_k = malloc(b->kex_klen); bcopy(&b->opkt[0],b->kex_k,b->kex_klen); sha1_result(hash,b->kex_h); if (! (*b->hk->checksig)(b,b->kex_h,b->kex_hlen,Hsig.data,Hsig.len)) { fprintf(stderr,"%s: kex hash signature wrong\n",__progname); exit(1); } mpz_clear(&p); mpz_clear(&g); mpz_clear(&q); mpz_clear(&x); mpz_clear(&e); mpz_clear(&f); mpz_clear(&K); mpz_clear(&tmp1); { extern HASHALG hashalg_sha1; b->kex_hash = &hashalg_sha1; } return(1); } #endif #if 0 static int kex_d_h_g_e_sha1_run(BPP *b) { int xbits; int xbytes; unsigned char xhbmask; char *xtmp; unsigned char *xbin; int i; unsigned char *opp; MP_INT p; MP_INT g; MP_INT q; MP_INT x; MP_INT e; MP_INT f; MP_INT K; MP_INT tmp1; STR Hsig; void *hash; if (! b->hk->can_sig) { fprintf(stderr,"%s: kex %s: server host key algorithm (%s) can't do signatures!\n",__progname,b->kex->name,b->hk->name); exit(1); } mpz_init(&p); mpz_init(&g); mpz_init(&q); mpz_init(&x); mpz_init(&e); mpz_init(&f); mpz_init(&K); mpz_init(&tmp1); mpz_tdiv_q_ui(&q,&p,2); opp = &b->opkt[0]; *opp++ = SSH_MSG_KEX_DH_GEX_REQUEST; opp = put_uint32(opp,min); opp = put_uint32(opp,n); opp = put_uint32(opp,max); b->oplen = opp - &b->opkt[0]; bpp_w_pkt(b); bpp_r_pkt(b); if (b->ipkt[0] != SSH_MSG_KEX_DH_GEX_GROUP) { fprintf(stderr,"%s: MSG_KEX_DH_GEX_GROUP packet isn't\n",__progname); exit(1); } parse_packet(b,pp_fail, PP_IGNORE(1), PP_MPINT(&p), PP_MPINT(&g), PP_ENDSHERE ); mpz_tdiv_q_2exp(&tmp1,&p,1); xbits = mpz_sizeinbase(&tmp1,2); xbytes = (xbits + 7) >> 3; xtmp = malloc((xbytes*2)+1); xbin = malloc(xbytes); xhbmask = "\377\001\003\007\017\037\077\177"[xbits&7]; while (1) { random_data(xbin,xbytes); xbin[0] &= xhbmask; for (i=0;i= 0) || (mpz_cmp_ui(&x,1) <= 0)) continue; break; } mpz_powm(&e,&g,&x,&p); b->opkt[0] = SSH_MSG_KEX_DH_GEX_INIT; opp = put_mpint(&b->opkt[1],&e); b->oplen = opp - &b->opkt[0]; bpp_w_pkt(b); bpp_r_pkt(b); if (b->ipkt[0] != SSH_MSG_KEX_DH_GEX_REPLY) { fprintf(stderr,"%s: MSG_KEX_DH_GEX_REPLY packet isn't\n",__progname); exit(1); } parse_packet(b,pp_fail, PP_IGNORE(1), PP_STRING(&b->K_S), PP_MPINT(&f), PP_STRING(&Hsig), PP_ENDSHERE ); if ((mpz_cmp(&f,&p) >= 0) || (mpz_cmp_ui(&f,1) < 0)) { fprintf(stderr,"%s: server's f value is out of range\n",__progname); exit(1); } /* XXX verify that b->K_S really is the right host key */ { int i; printf("host key:"); for (i=0;iK_S.len;i++) printf(" %02x",b->K_S.data[i]); printf("\n"); } mpz_powm(&K,&f,&x,&p); b->kex_hlen = 20; b->kex_h = malloc(20); hash = sha1_init(); opp = put_string(&b->opkt[0],&b->c_version[0],b->c_vlen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],&b->s_version[0],b->s_vlen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->c_kexinit_payload,b->c_kexinit_paylen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->s_kexinit_payload,b->s_kexinit_paylen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->K_S.data,b->K_S.len); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_uint32(&b->opkt[0],min); opp = put_uint32(opp,n); opp = put_uint32(opp,max); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&p); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&g); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&e); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&f); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&K); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); b->kex_klen = opp - &b->opkt[0]; b->kex_k = malloc(b->kex_klen); bcopy(&b->opkt[0],b->kex_k,b->kex_klen); sha1_result(hash,b->kex_h); if (! (*b->hk->checksig)(b,b->kex_h,b->kex_hlen,Hsig.data,Hsig.len)) { fprintf(stderr,"%s: kex hash signature wrong\n",__progname); exit(1); } mpz_clear(&p); mpz_clear(&g); mpz_clear(&q); mpz_clear(&x); mpz_clear(&e); mpz_clear(&f); mpz_clear(&K); mpz_clear(&tmp1); { extern HASHALG hashalg_sha1; b->kex_hash = &hashalg_sha1; } return(1); } #endif static int step_gex_init(LAYER *l, DHGE_SHA1_STATE *s) { BPP *b; MP_INT f; MP_INT K; STR Hsig; HASHALG *ha; void *hash; unsigned char sigbuf[20]; unsigned char *opp; b = l->b; if (b->ipkt[0] != SSH_MSG_KEX_DH_GEX_REPLY) { fprintf(stderr,"%s: MSG_KEX_DH_GEX_REPLY packet isn't\n",__progname); exit(1); } mpz_init(&f); mpz_init(&K); parse_packet(b,pp_fail, PP_IGNORE(1), PP_STRING(&b->K_S), PP_MPINT(&f), PP_STRING(&Hsig), PP_ENDSHERE ); if ((mpz_cmp(&f,&s->p) >= 0) || (mpz_cmp_ui(&f,1) < 0)) { fprintf(stderr,"%s: server's f value is out of range\n",__progname); exit(1); } /* XXX verify that K_S really is the right host key */ { int i; printf("host key:"); for (i=0;iK_S.len;i++) printf(" %02x",b->K_S.data[i]); printf("\n"); } mpz_powm(&K,&f,&s->x,&s->p); b->kex_hlen = 20; b->kex_h = malloc(20); hash = sha1_init(); opp = put_string(&b->opkt[0],&b->c_version[0],b->c_vlen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],&b->s_version[0],b->s_vlen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->c_kexinit_payload,b->c_kexinit_paylen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->s_kexinit_payload,b->s_kexinit_paylen); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_string(&b->opkt[0],b->K_S.data,b->K_S.len); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_uint32(&b->opkt[0],min); opp = put_uint32(opp,n); opp = put_uint32(opp,max); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&s->p); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&s->g); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&s->e); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&f); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); opp = put_mpint(&b->opkt[0],&K); sha1_process_bytes(hash,&b->opkt[0],opp-&b->opkt[0]); b->kex_klen = opp - &b->opkt[0]; b->kex_k = malloc(b->kex_klen); bcopy(&b->opkt[0],b->kex_k,b->kex_klen); sha1_result(hash,b->kex_h); ha = (*b->hk->prehash)(); if (sizeof(sigbuf) != ha->hashlen) abort(); hash = (*ha->init)(); (*ha->process)(hash,b->kex_h,20); (*ha->done)(hash,&sigbuf[0]); if (! (*b->hk->checksig)(b->K_S.data,b->K_S.len,&sigbuf[0],Hsig.data,Hsig.len)) { fprintf(stderr,"%s: kex hash signature wrong\n",__progname); exit(1); } mpz_clear(&s->p); mpz_clear(&s->g); mpz_clear(&s->e); mpz_clear(&s->x); mpz_clear(&f); mpz_clear(&K); free_str(Hsig); { extern HASHALG hashalg_sha1; b->kex_hash = &hashalg_sha1; } free(s); return(1); } static int step_gex_request(LAYER *l, DHGE_SHA1_STATE *s) { int xbits; int xbytes; char *xtmp; unsigned char *xbin; unsigned char xhbmask; int i; unsigned char *opp; MP_INT t; if (l->b->ipkt[0] != SSH_MSG_KEX_DH_GEX_GROUP) { fprintf(stderr,"%s: MSG_KEX_DH_GEX_GROUP packet isn't\n",__progname); exit(1); } mpz_init(&t); parse_packet(l->b,pp_fail, PP_IGNORE(1), PP_MPINT(&s->p), PP_MPINT(&s->g), PP_ENDSHERE ); mpz_tdiv_q_2exp(&t,&s->p,1); xbits = mpz_sizeinbase(&t,2); xbytes = (xbits + 7) >> 3; xtmp = malloc((xbytes*2)+1); xbin = malloc(xbytes); xhbmask = "\377\001\003\007\017\037\077\177"[xbits&7]; while (1) { random_data(xbin,xbytes); xbin[0] &= xhbmask; for (i=0;i>4)&15]; xtmp[i+i+1] = "0123456789ABCDEF"[xbin[i]&15]; } xtmp[i+i] = '\0'; mpz_set_str(&s->x,xtmp,16); if ((mpz_cmp(&s->x,&t) >= 0) || (mpz_cmp_ui(&s->x,1) <= 0)) continue; break; } free(xtmp); free(xbin); mpz_powm(&s->e,&s->g,&s->x,&s->p); l->b->opkt[0] = SSH_MSG_KEX_DH_GEX_INIT; opp = put_mpint(&l->b->opkt[1],&s->e); l->b->oplen = opp - &l->b->opkt[0]; below_opkt(l); s->nextstep = &step_gex_init; mpz_clear(&t); return(0); } static void *kex_d_h_g_e_sha1_init(LAYER *l) { DHGE_SHA1_STATE *s; unsigned char *opp; s = malloc(sizeof(DHGE_SHA1_STATE)); if (! l->b->hk->can_sig) { fprintf(stderr,"%s: kex %s: server host key algorithm (%s) can't do signatures!\n",__progname,l->b->kex->name,l->b->hk->name); exit(1); } mpz_init(&s->p); mpz_init(&s->g); mpz_init(&s->e); mpz_init(&s->x); opp = &l->b->opkt[0]; *opp++ = SSH_MSG_KEX_DH_GEX_REQUEST; opp = put_uint32(opp,min); opp = put_uint32(opp,n); opp = put_uint32(opp,max); l->b->oplen = opp - &l->b->opkt[0]; below_opkt(l); s->nextstep = &step_gex_request; return(s); } static int kex_d_h_g_e_sha1_run(LAYER *l, void *sv) { DHGE_SHA1_STATE *s; s = sv; return((*s->nextstep)(l,s)); } KEXALG kexalg_diffie_hellman_group_exchange_sha1 = { "diffie-hellman-group-exchange-sha1", 0, 1, kex_d_h_g_e_sha1_init, kex_d_h_g_e_sha1_run };