#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" static const char *p_hex = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" "FFFFFFFFFFFFFFFF"; typedef struct dhg1_sha1_state DHG1_SHA1_STATE; struct dhg1_sha1_state { MP_INT p; MP_INT x; MP_INT e; } ; static void *kex_d_h_g1_sha1_init(LAYER *l) { DHG1_SHA1_STATE *s; int ptlen; int pblen; char *xtmp; unsigned char *xbin; unsigned char *opp; MP_INT q; s = malloc(sizeof(DHG1_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_set_str(&s->p,p_hex,16); mpz_init(&q); mpz_init(&s->x); mpz_init_set_ui(&s->e,2); mpz_tdiv_q_ui(&q,&s->p,2); ptlen = strlen(p_hex); pblen = (ptlen + 1) / 2; xtmp = malloc(ptlen+3); xbin = malloc(pblen); while (1) { random_data(xbin,pblen); xbin[0] &= (ptlen & 1) ? 0x07 : 0x7f; data_to_mpint(&s->x,&xbin[0],pblen); mpz_set_str(&s->x,xtmp,16); if ((mpz_cmp(&s->x,&q) >= 0) || (mpz_cmp_ui(&s->x,1) <= 0)) continue; break; } mpz_powm(&s->e,&s->e,&s->x,&s->p); l->b->opkt[0] = SSH_MSG_KEXDH_INIT; opp = put_mpint(&l->b->opkt[1],&s->e); l->b->oplen = opp - &l->b->opkt[0]; below_opkt(l); mpz_clear(&q); return(s); } static int kex_d_h_g1_sha1_run(LAYER *l, void *sv) { BPP *b; DHG1_SHA1_STATE *s; MP_INT f; MP_INT K; STR Hsig; HASHALG *ha; void *hash; unsigned char sigbuf[20]; unsigned char *opp; s = sv; b = l->b; mpz_init(&f); mpz_init(&K); if (b->ipkt[0] != SSH_MSG_KEXDH_REPLY) { fprintf(stderr,"%s: KEXDH_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,&s->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,&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_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->x); mpz_clear(&s->e); mpz_clear(&f); mpz_clear(&K); { extern HASHALG hashalg_sha1; b->kex_hash = &hashalg_sha1; } free(s); return(1); } KEXALG kexalg_diffie_hellman_group1_sha1 = { "diffie-hellman-group1-sha1", 0, 1, kex_d_h_g1_sha1_init, kex_d_h_g1_sha1_run };