publickey_crypto.c 15.1 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1 2
/* publickey_crypto.c
 *
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Niels Möller's avatar
Niels Möller committed
24 25
 */

Niels Möller's avatar
Niels Möller committed
26 27
#include "publickey_crypto.h"

Niels Möller's avatar
Niels Möller committed
28
#include "atoms.h"
29 30 31 32
#include "bignum.h"
#include "crypto.h"
#include "format.h"
#include "parse.h"
Niels Möller's avatar
Niels Möller committed
33
#include "publickey_crypto.h"
34 35 36 37
#include "sha.h"
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"
Niels Möller's avatar
Niels Möller committed
38

39 40 41 42 43
#define CLASS_DEFINE
#include "publickey_crypto.h.x"
#undef CLASS_DEFINE

#include "publickey_crypto.c.x"
Niels Möller's avatar
Niels Möller committed
44

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/* DSS signatures */
/* CLASS:
   (class
     (name dss_signer)
     (super signer)
     (vars
       (random object randomness)
       (public struct dss_public)
       (a bignum)))
*/

/* CLASS:
   (class
     (name dss_verifier)
     (super verifier)
     (vars
       (public struct dss_public)))
*/
Niels Möller's avatar
Niels Möller committed
63

64 65 66 67 68 69 70
/* CLASS:
   (class
     (name dss_algorithm)
     (super signature_algorithm)
     (vars
       (random object randomness)))
*/
Niels Möller's avatar
Niels Möller committed
71

Niels Möller's avatar
Niels Möller committed
72
static void dss_hash(mpz_t h, UINT32 length, UINT8 *msg)
73 74
{
  /* Compute hash */
75 76 77
  struct hash_instance *hash = MAKE_HASH(&sha_algorithm);
  UINT8 *digest = alloca(hash->hash_size);
  HASH_UPDATE(hash, length, msg);
78
  HASH_DIGEST(hash, digest);
Niels Möller's avatar
Niels Möller committed
79

80
  bignum_parse_u(h, hash->hash_size, digest);
81

82 83 84 85
  debug("DSS hash: ");
  debug_mpz(h);
  debug("\n");
  
86
  KILL(hash);
87 88
}

89
static struct lsh_string *do_dss_sign(struct signer *c,
90 91
				      UINT32 length,
				      UINT8 *msg)
Niels Möller's avatar
Niels Möller committed
92
{
93
  CAST(dss_signer, closure, c);
Niels Möller's avatar
Niels Möller committed
94
  mpz_t k, r, s, tmp;
Niels Möller's avatar
Niels Möller committed
95
  struct lsh_string *signature;
Niels Möller's avatar
Niels Möller committed
96

Niels Möller's avatar
Niels Möller committed
97 98 99 100 101
  /* Select k, 0<k<q, randomly */
  mpz_init_set(tmp, closure->public.q);
  mpz_sub_ui(tmp, tmp, 1);

  mpz_init(k);
102
  bignum_random(k, closure->random, tmp);
Niels Möller's avatar
Niels Möller committed
103 104
  mpz_add_ui(k, k, 1);

105 106 107 108
  debug("do_dss_sign, k: ");
  debug_mpz(k);
  debug("\n");
  
109
  /* Compute r = (g^k (mod p)) (mod q) */
Niels Möller's avatar
Niels Möller committed
110
  mpz_init(r);
111
  mpz_powm(r, closure->public.g, k, closure->public.p);
112 113 114 115

  debug("do_dss_sign, group element: ");
  debug_mpz(r);
  debug("\n");
Niels Möller's avatar
Niels Möller committed
116
  
117
  mpz_fdiv_r(r, r, closure->public.q);
118 119 120 121 122

  debug("do_dss_sign, r: ");
  debug_mpz(r);
  debug("\n");

Niels Möller's avatar
Niels Möller committed
123
  /* Compute hash */
124
  dss_hash(tmp, length, msg);
125
  
Niels Möller's avatar
Niels Möller committed
126
  /* Compute k^-1 (mod q) */
127 128 129 130 131 132 133 134
  if (!mpz_invert(k, k, closure->public.q))
    {
      werror("do_dss_sign: k non-invertible\n");
      mpz_clear(tmp);
      mpz_clear(k);
      mpz_clear(r);
      return NULL;
    }
Niels Möller's avatar
Niels Möller committed
135 136 137

  /* Compute signature s = k^-1(h + ar) (mod q) */
  mpz_init(s);
138
  mpz_mul(s, r, closure->a);
139
  mpz_fdiv_r(s, s, closure->public.q);
Niels Möller's avatar
Niels Möller committed
140 141
  mpz_add(s, s, tmp);
  mpz_mul(s, s, k);
142
  mpz_fdiv_r(s, s, closure->public.q);
143 144 145 146

  debug("do_dss_sign, s: ");
  debug_mpz(s);
  debug("\n");
Niels Möller's avatar
Niels Möller committed
147 148 149 150 151 152 153 154 155 156 157 158
  
  /* Build signature */
  signature = ssh_format("%a%n%n", ATOM_SSH_DSS, r, s);

  mpz_clear(k);
  mpz_clear(r);
  mpz_clear(s);
  mpz_clear(tmp);

  return signature;
}

Niels Möller's avatar
Niels Möller committed
159
#if 0
Niels Möller's avatar
Niels Möller committed
160 161
static struct lsh_string *dss_public_key(struct signer *dss)
{
Niels Möller's avatar
Niels Möller committed
162 163
  return ssh_format("%a%n%n%n%n",
		    ATOM_SSH_DSS, dss->p, dss->q, dss->g, dss->y);
Niels Möller's avatar
Niels Möller committed
164
}
Niels Möller's avatar
Niels Möller committed
165
#endif
Niels Möller's avatar
Niels Möller committed
166

Niels Möller's avatar
Niels Möller committed
167 168 169 170 171
static int do_dss_verify(struct verifier *c,
			 UINT32 length,
			 UINT8 *msg,
			 UINT32 signature_length,
			 UINT8 * signature_data)
Niels Möller's avatar
Niels Möller committed
172
{
173
  CAST(dss_verifier, closure, c);
Niels Möller's avatar
Niels Möller committed
174 175
  struct simple_buffer buffer;

176 177
  int res;
  
Niels Möller's avatar
Niels Möller committed
178
  int atom;
Niels Möller's avatar
Niels Möller committed
179
  mpz_t r, s;
180

181
  mpz_t w, tmp, v;
Niels Möller's avatar
Niels Möller committed
182

Niels Möller's avatar
Niels Möller committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
  simple_buffer_init(&buffer, signature_length, signature_data);
  if (!parse_atom(&buffer, &atom)
      || (atom != ATOM_SSH_DSS) )
    return 0;

  mpz_init(r);
  mpz_init(s);
  if (! (parse_bignum(&buffer, r)
	 && parse_bignum(&buffer, s)
	 && parse_eod(&buffer)
	 && (mpz_sgn(r) == 1)
	 && (mpz_sgn(s) == 1)
	 && (mpz_cmp(r, closure->public.q) < 0)
	 && (mpz_cmp(s, closure->public.q) < 0) ))
    {
      mpz_clear(r);
      mpz_clear(s);
      return 0;
    }
202 203 204 205 206 207 208 209
  
  debug("do_dss_verify, r: ");
  debug_mpz(r);
  debug("\n");
  
  debug("do_dss_verify, s: ");
  debug_mpz(s);
  debug("\n");
Niels Möller's avatar
Niels Möller committed
210

211 212
  /* Compute w = s^-1 (mod q) */
  mpz_init(w);
213 214

  /* FIXME: mpz_invert generates negative inverses. Is this a problem? */
215
  if (!mpz_invert(w, s, closure->public.q))
216 217 218 219 220 221 222 223
    {
      werror("do_dss_verify: s non-invertible.\n");
      mpz_clear(r);
      mpz_clear(s);
      mpz_clear(w);
      return 0;
    }

224 225 226 227
  debug("do_dss_verify, w: ");
  debug_mpz(w);
  debug("\n");

228 229 230 231 232 233 234 235 236
  /* Compute hash */
  mpz_init(tmp);
  dss_hash(tmp, length, msg);

  /* g^{w * h (mod q)} (mod p)  */

  mpz_init(v);

  mpz_mul(tmp, tmp, w);
237
  mpz_fdiv_r(tmp, tmp, closure->public.q);
238

239 240 241 242
  debug("u1: ");
  debug_mpz(tmp);
  debug("\n");
  
243 244 245 246
  mpz_powm(v, closure->public.g, tmp, closure->public.p);

  /* y^{w * r (mod q) } (mod p) */
  mpz_mul(tmp, r, w);
247 248 249 250 251
  mpz_fdiv_r(tmp, tmp, closure->public.q);

  debug("u2: ");
  debug_mpz(tmp);
  debug("\n");
252

253 254
  mpz_powm(tmp, closure->public.y, tmp, closure->public.p);
  
255 256
  /* (g^{w * h} * y^{w * r} (mod p) ) (mod q) */
  mpz_mul(v, v, tmp);
257
  mpz_fdiv_r(v, v, closure->public.p);
258 259 260 261 262

  debug("do_dss_verify, group element: ");
  debug_mpz(v);
  debug("\n");
  
263
  mpz_fdiv_r(v, v, closure->public.q);
264

265 266 267 268
  debug("do_dss_verify, v: ");
  debug_mpz(v);
  debug("\n");

269 270 271 272 273 274 275 276 277 278 279
  res = mpz_cmp(v, r);

  mpz_clear(r);
  mpz_clear(s);
  mpz_clear(w);
  mpz_clear(tmp);
  mpz_clear(v);

  return !res;
}

280 281
static int parse_dss_public(struct simple_buffer *buffer,
			    struct dss_public *public)
282
{
283
  return (parse_bignum(buffer, public->p)
284
	  && (mpz_sgn(public->p) == 1)
285
	  && parse_bignum(buffer, public->q)
286 287
	  && (mpz_sgn(public->q) == 1)
	  && (mpz_cmp(public->q, public->p) < 0) /* q < p */ 
288
	  && parse_bignum(buffer, public->g)
289 290
	  && (mpz_sgn(public->g) == 1)
	  && (mpz_cmp(public->g, public->p) < 0) /* g < p */ 
291
	  && parse_bignum(buffer, public->y) 
292 293 294 295 296 297
	  && (mpz_sgn(public->y) == 1)
	  && (mpz_cmp(public->y, public->p) < 0) /* y < p */  );
}

/* FIXME: Outside of the protocol transactions, keys should be stored
 * in SPKI-style S-expressions. */
Niels Möller's avatar
Niels Möller committed
298 299 300 301 302
static struct signer *make_dss_signer(struct signature_algorithm *c,
				      UINT32 public_length,
				      UINT8 *public,
				      UINT32 private_length,
				      UINT8 *private)
303
{
304 305
  CAST(dss_algorithm, closure, c);
  NEW(dss_signer, res);
Niels Möller's avatar
Niels Möller committed
306
  
307 308
  struct simple_buffer public_buffer;
  struct simple_buffer private_buffer;  
309 310
  int atom;

311 312
  /* FIXME: The allocator could do this kind of initialization
   * automatically. */
313 314 315 316
  mpz_init(res->public.p);
  mpz_init(res->public.q);
  mpz_init(res->public.g);
  mpz_init(res->public.y);
317
  mpz_init(res->a);
318
  
319 320 321 322 323 324 325 326 327
  simple_buffer_init(&public_buffer, public_length, public);
  if (!parse_atom(&public_buffer, &atom)
      || (atom != ATOM_SSH_DSS) )
    {
      KILL(res);
      return 0;
    }
  simple_buffer_init(&private_buffer, private_length, private);

328 329
  if (! (parse_dss_public(&public_buffer, &res->public)
  	 && parse_bignum(&private_buffer, res->a)
330
	 /* FIXME: Perhaps do some more sanity checks? */
331 332
	 && (mpz_sgn(res->a) == 1)
	 && parse_eod(&private_buffer) ))
333
    {
334
      KILL(res);
335 336
      return NULL;
    }
Niels Möller's avatar
Niels Möller committed
337
  
338
  res->super.sign = do_dss_sign;
Niels Möller's avatar
Niels Möller committed
339 340
  res->random = closure->random;

341 342 343
  return &res->super;
}

344 345 346 347
static struct verifier *
make_dss_verifier(struct signature_algorithm *closure UNUSED,
		  UINT32 public_length,
		  UINT8 *public)
348
{
349
  NEW(dss_verifier, res);
350 351 352
  struct simple_buffer buffer;
  int atom;

353 354
  /* FIXME: The allocator could do this kind of initialization
   * automatically. */
355 356 357 358 359
  mpz_init(res->public.p);
  mpz_init(res->public.q);
  mpz_init(res->public.g);
  mpz_init(res->public.y);
  
360 361 362 363 364 365 366 367
  simple_buffer_init(&buffer, public_length, public);
  if (!parse_atom(&buffer, &atom)
      || (atom != ATOM_SSH_DSS) )
    {
      KILL(res);
      return 0;
    }
  
368 369 370
  if (!parse_dss_public(&buffer, &res->public))
    /* FIXME: Perhaps do some more sanity checks? */
    {
371
      KILL(res);
372 373 374 375 376 377 378
      return NULL;
    }

  res->super.verify = do_dss_verify;
  return &res->super;
}

379
struct signature_algorithm *make_dss_algorithm(struct randomness *random)
380
{
381
  NEW(dss_algorithm, dss);
382 383 384 385 386 387 388 389

  dss->super.make_signer = make_dss_signer;
  dss->super.make_verifier = make_dss_verifier;
  dss->random = random;

  return &dss->super;
}
    
Niels Möller's avatar
Niels Möller committed
390
/* Groups */
391 392 393 394 395 396 397
/* CLASS:
   (class
     (name group_zn)
     (super group)
     (vars
       (modulo bignum)))
*/
Niels Möller's avatar
Niels Möller committed
398 399 400

static int zn_member(struct group *c, mpz_t x)
{
401
  CAST(group_zn, closure, c);
Niels Möller's avatar
Niels Möller committed
402 403 404 405 406 407

  return ( (mpz_sgn(x) == 1) && (mpz_cmp(x, closure->modulo) < 0) );
}

static void zn_invert(struct group *c, mpz_t res, mpz_t x)
{
408
  CAST(group_zn, closure, c);
Niels Möller's avatar
Niels Möller committed
409 410 411

  if (!mpz_invert(res, x, closure->modulo))
    fatal("zn_invert: element is non-invertible\n");
412

413
  mpz_fdiv_r(res, res, closure->modulo);
Niels Möller's avatar
Niels Möller committed
414 415 416 417
}

static void zn_combine(struct group *c, mpz_t res, mpz_t a, mpz_t b)
{
418
  CAST(group_zn, closure, c);
Niels Möller's avatar
Niels Möller committed
419 420

  mpz_mul(res, a, b);
421
  mpz_fdiv_r(res, res, closure->modulo);
Niels Möller's avatar
Niels Möller committed
422 423 424 425
}

static void zn_power(struct group *c, mpz_t res, mpz_t g, mpz_t e)
{
426
  CAST(group_zn, closure, c);
Niels Möller's avatar
Niels Möller committed
427 428 429 430 431 432 433

  mpz_powm(res, g, e, closure->modulo);
}

/* Assumes p is a prime number */
struct group *make_zn(mpz_t p)
{
434
  NEW(group_zn, res);
Niels Möller's avatar
Niels Möller committed
435 436 437 438 439 440

  res->super.member = zn_member;
  res->super.invert = zn_invert;
  res->super.combine = zn_combine;
  res->super.power = zn_power;     /* Pretty Mutation! Magical Recall! */
  
441 442 443
  mpz_init_set(res->modulo, p);
  mpz_init_set(res->super.order, p);
  mpz_sub_ui(res->super.order, res->super.order, 1);
Niels Möller's avatar
Niels Möller committed
444 445 446 447 448
  return &res->super;
}

/* diffie-hellman */

449 450 451 452
void init_diffie_hellman_instance(struct diffie_hellman_method *m,
				  struct diffie_hellman_instance *self,
				  struct ssh_connection *c)
{
453 454
  /* FIXME: The allocator could do this kind of initialization
   * automatically. */
455 456 457 458 459 460 461
  mpz_init(self->e);
  mpz_init(self->f);
  mpz_init(self->secret);
  mpz_init(self->K);
  
  self->method = m;
  self->hash = MAKE_HASH(m->H);
462
  self->exchange_hash = NULL;
463 464 465

  debug("init_diffie_hellman_instance()\n V_C: ");

466
  /* FIXME: Length field should be included when hashing. */
467 468
  debug_safe(c->client_version->length,
	     c->client_version->data);
469 470 471
  HASH_UPDATE(self->hash,
	      c->client_version->length,
	      c->client_version->data);
472 473 474
  debug("\n V_S: ");
  debug_safe(c->server_version->length,
	     c->server_version->data);
475 476 477
  HASH_UPDATE(self->hash,
	      c->server_version->length,
	      c->server_version->data);
478 479 480
  debug("\n I_C: ");
  debug_safe(c->literal_kexinits[CONNECTION_CLIENT]->length,
	     c->literal_kexinits[CONNECTION_CLIENT]->data);
481 482 483
  HASH_UPDATE(self->hash,
	      c->literal_kexinits[CONNECTION_CLIENT]->length,
	      c->literal_kexinits[CONNECTION_CLIENT]->data);
484 485 486
  debug("\n I_C: ");
  debug_safe(c->literal_kexinits[CONNECTION_SERVER]->length,
	     c->literal_kexinits[CONNECTION_SERVER]->data);
487 488 489
  HASH_UPDATE(self->hash,
	      c->literal_kexinits[CONNECTION_SERVER]->length,
	      c->literal_kexinits[CONNECTION_SERVER]->data);
490
  debug("\n");
491 492 493 494 495 496 497 498
  
  lsh_string_free(c->literal_kexinits[CONNECTION_CLIENT]);
  lsh_string_free(c->literal_kexinits[CONNECTION_SERVER]);

  c->literal_kexinits[CONNECTION_SERVER] = NULL;
  c->literal_kexinits[CONNECTION_CLIENT] = NULL;
}

499
struct diffie_hellman_method *make_dh1(struct randomness *r)
Niels Möller's avatar
Niels Möller committed
500
{
501
  NEW(diffie_hellman_method, res);
Niels Möller's avatar
Niels Möller committed
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
  mpz_t p;
  
  mpz_init_set_str(p,
		   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
		   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
		   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
		   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
		   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
		   "FFFFFFFFFFFFFFFF", 16);

  res->G = make_zn(p);
  mpz_clear(p);

  mpz_init_set_ui(res->generator, 2);

517
  res->H = &sha_algorithm;
Niels Möller's avatar
Niels Möller committed
518 519 520 521 522 523 524 525 526 527
  res->random = r;
  
  return res;
}

void dh_generate_secret(struct diffie_hellman_instance *self,
			mpz_t r)
{
  mpz_t tmp;

528 529 530 531 532
  /* Generate a random number, 1 < x <= p-1 = O(G) */
  mpz_init_set(tmp, self->method->G->order);  
  mpz_sub_ui(tmp, tmp, 1);
  bignum_random(self->secret, self->method->random, tmp);
  mpz_add_ui(self->secret, self->secret, 1);
Niels Möller's avatar
Niels Möller committed
533 534
  mpz_clear(tmp);

535
  GROUP_POWER(self->method->G, r, self->method->generator, self->secret);
Niels Möller's avatar
Niels Möller committed
536 537 538 539 540 541 542 543 544 545 546 547
}

struct lsh_string *dh_make_client_msg(struct diffie_hellman_instance *self)
{
  dh_generate_secret(self, self->e);
  return ssh_format("%c%n", SSH_MSG_KEXDH_INIT, self->e);
}

int dh_process_client_msg(struct diffie_hellman_instance *self,
			  struct lsh_string *packet)
{
  struct simple_buffer buffer;
548
  int msg_number;
Niels Möller's avatar
Niels Möller committed
549 550 551
  
  simple_buffer_init(&buffer, packet->length, packet->data);

552 553 554 555 556 557 558 559 560 561
  if (! (parse_uint8(&buffer, &msg_number)
	 && (msg_number == SSH_MSG_KEXDH_INIT)
	 && parse_bignum(&buffer, self->e)
	 && (mpz_cmp_ui(self->e, 1) > 0)
	 && (mpz_cmp(self->e, self->method->G->order) <= 0)
	 && parse_eod(&buffer) ))
    return 0;

  GROUP_POWER(self->method->G, self->K, self->e, self->secret);
  return 1;
Niels Möller's avatar
Niels Möller committed
562 563
}

564
#if 0
Niels Möller's avatar
Niels Möller committed
565 566 567
void dh_hash_update(struct diffie_hellman_instance *self,
		    struct lsh_string *packet)
{
568 569 570 571
  debug("dh_hash_update, length = %d, data:\n", packet->length);
  debug_safe(packet->length, packet->data);
  debug("\n");
  
Niels Möller's avatar
Niels Möller committed
572 573
  HASH_UPDATE(self->hash, packet->length, packet->data);
}
574
#endif
Niels Möller's avatar
Niels Möller committed
575 576 577 578

/* Hashes server key, e and f */
void dh_hash_digest(struct diffie_hellman_instance *self, UINT8 *digest)
{
579 580 581 582
  struct lsh_string *s = ssh_format("%S%n%n%n",
				    self->server_key,
				    self->e, self->f,
				    self->K);
583
  debug("dh_hash_digest()\n '");
584 585
  debug_safe(s->length,
	     s->data);
586
  debug("'\n");
587
  
Niels Möller's avatar
Niels Möller committed
588 589 590
  HASH_UPDATE(self->hash, s->length, s->data);
  lsh_string_free(s);

591
  HASH_DIGEST(self->hash, digest);
Niels Möller's avatar
Niels Möller committed
592 593
}

594
void dh_make_server_secret(struct diffie_hellman_instance *self)
Niels Möller's avatar
Niels Möller committed
595 596
{
  dh_generate_secret(self, self->f);
597
}
Niels Möller's avatar
Niels Möller committed
598

599 600 601
struct lsh_string *dh_make_server_msg(struct diffie_hellman_instance *self,
				      struct signer *s)
{
602 603
  self->exchange_hash = lsh_string_alloc(self->hash->hash_size);
  
Niels Möller's avatar
Niels Möller committed
604
  dh_hash_digest(self, self->exchange_hash->data);
Niels Möller's avatar
Niels Möller committed
605 606 607 608

  return ssh_format("%c%S%n%fS",
		    SSH_MSG_KEXDH_REPLY,
		    self->server_key,
609 610 611
		    self->f, SIGN(s,
				  self->exchange_hash->length,
				  self->exchange_hash->data));
Niels Möller's avatar
Niels Möller committed
612 613 614 615 616 617
}

int dh_process_server_msg(struct diffie_hellman_instance *self,
			  struct lsh_string *packet)
{
  struct simple_buffer buffer;
618
  int msg_number;
Niels Möller's avatar
Niels Möller committed
619 620 621
  
  simple_buffer_init(&buffer, packet->length, packet->data);

622 623 624 625 626 627 628 629 630 631 632 633
  if (!(parse_uint8(&buffer, &msg_number)
	&& (msg_number == SSH_MSG_KEXDH_REPLY)
	&& (self->server_key = parse_string_copy(&buffer))
	&& (parse_bignum(&buffer, self->f))
	&& (mpz_cmp_ui(self->f, 1) > 0)
	&& (mpz_cmp(self->f, self->method->G->order) <= 0)
	&& (self->signature = parse_string_copy(&buffer))
	&& parse_eod(&buffer)))
    return 0;

  GROUP_POWER(self->method->G, self->K, self->f, self->secret);
  return 1;
Niels Möller's avatar
Niels Möller committed
634 635 636 637 638
}
	  
int dh_verify_server_msg(struct diffie_hellman_instance *self,
			 struct verifier *v)
{
639
  self->exchange_hash = lsh_string_alloc(self->hash->hash_size);
Niels Möller's avatar
Niels Möller committed
640
  
641
  dh_hash_digest(self, self->exchange_hash->data);
Niels Möller's avatar
Niels Möller committed
642

643 644
  return VERIFY(v,
		self->hash->hash_size, self->exchange_hash->data,
Niels Möller's avatar
Niels Möller committed
645 646
		self->signature->length, self->signature->data);
}
Niels Möller's avatar
Niels Möller committed
647