コード例 #1
0
ファイル: script.c プロジェクト: jma127/bitc-rpc
static int script_sign_hash(struct wallet *wallet, const uint160 *keyHash,
                            const uint256 *hash, enum script_hash_type hashType,
                            struct buff *script) {
  struct key *k;
  size_t siglen;
  uint8 *sig;
  bool s;

  k = wallet_lookup_pubkey(wallet, keyHash);
  if (k == NULL) {
    return 1;
  }

  s = key_sign(k, hash, sizeof *hash, &sig, &siglen);
  if (!s) {
    return 1;
  }
  Log(LGPFX " siglen=%zu\n", siglen);

  /*
   * Verify the signature is good. This code is new..
   */
  s = key_verify(k, hash, sizeof *hash, sig, siglen);
  ASSERT(s == 1);

  uint8 push_data[siglen + 1];

  memcpy(push_data, sig, siglen);
  free(sig);
  push_data[siglen] = (uint8)hashType;

  script_push_data(script, push_data, siglen + 1);

  return 0;
}
コード例 #2
0
int
mm_answer_sign(int sock, Buffer *m)
{
	Key *key;
	u_char *p;
	u_char *signature;
	u_int siglen, datlen;
	int keyid;

	debug3("%s", __func__);

	keyid = buffer_get_int(m);
	p = buffer_get_string(m, &datlen);

	/*
	 * Supported KEX types will only return SHA1 (20 byte) or
	 * SHA256 (32 byte) hashes
	 */
	if (datlen != 20 && datlen != 32)
		fatal("%s: data length incorrect: %u", __func__, datlen);

	/* save session id, it will be passed on the first call */
	if (session_id2_len == 0) {
		session_id2_len = datlen;
		session_id2 = xmalloc(session_id2_len);
		memcpy(session_id2, p, session_id2_len);
	}

	if ((key = get_hostkey_by_index(keyid)) == NULL)
		fatal("%s: no hostkey from index %d", __func__, keyid);
	if (key_sign(key, &signature, &siglen, p, datlen) < 0)
		fatal("%s: key_sign failed", __func__);

	debug3("%s: signature %p(%u)", __func__, signature, siglen);

	buffer_clear(m);
	buffer_put_string(m, signature, siglen);

	xfree(p);
	xfree(signature);

	mm_request_send(sock, MONITOR_ANS_SIGN, m);

	/* Turn on permissions for getpwnam */
	monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);

	return (0);
}
コード例 #3
0
ファイル: ssh-keysign.c プロジェクト: UNGLinux/Obase
int
main(int argc, char **argv)
{
	Buffer b;
	Options options;
#define NUM_KEYTYPES 3
	Key *keys[NUM_KEYTYPES], *key = NULL;
	struct passwd *pw;
	int key_fd[NUM_KEYTYPES], i, found, version = 2, fd;
	u_char *signature, *data;
	char *host;
	u_int slen, dlen;
	u_int32_t rnd[256];

	/* Ensure that stdin and stdout are connected */
	if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2)
		exit(1);
	/* Leave /dev/null fd iff it is attached to stderr */
	if (fd > 2)
		close(fd);

	i = 0;
	key_fd[i++] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY);
	key_fd[i++] = open(_PATH_HOST_ECDSA_KEY_FILE, O_RDONLY);
	key_fd[i++] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY);

	original_real_uid = getuid();	/* XXX readconf.c needs this */
	if ((pw = getpwuid(original_real_uid)) == NULL)
		fatal("getpwuid failed");
	pw = pwcopy(pw);

	permanently_set_uid(pw);

#ifdef DEBUG_SSH_KEYSIGN
	log_init("ssh-keysign", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
#endif

	/* verify that ssh-keysign is enabled by the admin */
	initialize_options(&options);
	(void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0);
	fill_default_options(&options);
	if (options.enable_ssh_keysign != 1)
		fatal("ssh-keysign not enabled in %s",
		    _PATH_HOST_CONFIG_FILE);

	for (i = found = 0; i < NUM_KEYTYPES; i++) {
		if (key_fd[i] != -1)
			found = 1;
	}
	if (found == 0)
		fatal("could not open any host key");

	OpenSSL_add_all_algorithms();
	for (i = 0; i < 256; i++)
		rnd[i] = arc4random();
	RAND_seed(rnd, sizeof(rnd));

	found = 0;
	for (i = 0; i < NUM_KEYTYPES; i++) {
		keys[i] = NULL;
		if (key_fd[i] == -1)
			continue;
		keys[i] = key_load_private_pem(key_fd[i], KEY_UNSPEC,
		    NULL, NULL);
		close(key_fd[i]);
		if (keys[i] != NULL)
			found = 1;
	}
	if (!found)
		fatal("no hostkey found");

	buffer_init(&b);
	if (ssh_msg_recv(STDIN_FILENO, &b) < 0)
		fatal("ssh_msg_recv failed");
	if (buffer_get_char(&b) != version)
		fatal("bad version");
	fd = buffer_get_int(&b);
	if ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO))
		fatal("bad fd");
	if ((host = get_local_name(fd)) == NULL)
		fatal("cannot get local name for fd");

	data = buffer_get_string(&b, &dlen);
	if (valid_request(pw, host, &key, data, dlen) < 0)
		fatal("not a valid request");
	xfree(host);

	found = 0;
	for (i = 0; i < NUM_KEYTYPES; i++) {
		if (keys[i] != NULL &&
		    key_equal_public(key, keys[i])) {
			found = 1;
			break;
		}
	}
	if (!found)
		fatal("no matching hostkey found");

	if (key_sign(keys[i], &signature, &slen, data, dlen) != 0)
		fatal("key_sign failed");
	xfree(data);

	/* send reply */
	buffer_clear(&b);
	buffer_put_string(&b, signature, slen);
	if (ssh_msg_send(STDOUT_FILENO, version, &b) == -1)
		fatal("ssh_msg_send failed");

	return (0);
}
コード例 #4
0
ファイル: kexgexs.c プロジェクト: crazyleen/openssh
void
kexgex_server(Kex *kex)
{
	BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
	Key *server_host_public, *server_host_private;
	DH *dh;
	u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
	u_int sbloblen, klen, slen, hashlen;
	int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1;
	int type, kout;

	if (kex->load_host_public_key == NULL ||
	    kex->load_host_private_key == NULL)
		fatal("Cannot load hostkey");
	server_host_public = kex->load_host_public_key(kex->hostkey_type);
	if (server_host_public == NULL)
		fatal("Unsupported hostkey type %d", kex->hostkey_type);
	server_host_private = kex->load_host_private_key(kex->hostkey_type);
	if (server_host_private == NULL)
		fatal("Missing private key for hostkey type %d",
		    kex->hostkey_type);


	type = packet_read();
	switch (type) {
	case SSH2_MSG_KEX_DH_GEX_REQUEST:
		debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
		omin = min = packet_get_int();
		onbits = nbits = packet_get_int();
		omax = max = packet_get_int();
		min = MAX(DH_GRP_MIN, min);
		max = MIN(DH_GRP_MAX, max);
		nbits = MAX(DH_GRP_MIN, nbits);
		nbits = MIN(DH_GRP_MAX, nbits);
		break;
	case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
		debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
		onbits = nbits = packet_get_int();
		/* unused for old GEX */
		omin = min = DH_GRP_MIN;
		omax = max = DH_GRP_MAX;
		break;
	default:
		fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
	}
	packet_check_eom();

	if (omax < omin || onbits < omin || omax < onbits)
		fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
		    omin, onbits, omax);

	/* Contact privileged parent */
	dh = PRIVSEP(choose_dh(min, nbits, max));
	if (dh == NULL)
		packet_disconnect("Protocol error: no matching DH grp found");

	debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
	packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
	packet_put_bignum2(dh->p);
	packet_put_bignum2(dh->g);
	packet_send();

	/* flush */
	packet_write_wait();

	/* Compute our exchange value in parallel with the client */
	dh_gen_key(dh, kex->we_need * 8);

	debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
	packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT);

	/* key, cert */
	if ((dh_client_pub = BN_new()) == NULL)
		fatal("dh_client_pub == NULL");
	packet_get_bignum2(dh_client_pub);
	packet_check_eom();

#ifdef DEBUG_KEXDH
	fprintf(stderr, "dh_client_pub= ");
	BN_print_fp(stderr, dh_client_pub);
	fprintf(stderr, "\n");
	debug("bits %d", BN_num_bits(dh_client_pub));
#endif

#ifdef DEBUG_KEXDH
	DHparams_print_fp(stderr, dh);
	fprintf(stderr, "pub= ");
	BN_print_fp(stderr, dh->pub_key);
	fprintf(stderr, "\n");
#endif
	if (!dh_pub_is_valid(dh, dh_client_pub))
		packet_disconnect("bad client public DH value");

	klen = DH_size(dh);
	kbuf = xmalloc(klen);
	if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0)
		fatal("DH_compute_key: failed");
#ifdef DEBUG_KEXDH
	dump_digest("shared secret", kbuf, kout);
#endif
	if ((shared_secret = BN_new()) == NULL)
		fatal("kexgex_server: BN_new failed");
	if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
		fatal("kexgex_server: BN_bin2bn failed");
	memset(kbuf, 0, klen);
	free(kbuf);

	key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);

	if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
		omin = min = omax = max = -1;

	/* calc H */
	kexgex_hash(
	    kex->evp_md,
	    kex->client_version_string,
	    kex->server_version_string,
	    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
	    buffer_ptr(&kex->my), buffer_len(&kex->my),
	    server_host_key_blob, sbloblen,
	    omin, onbits, omax,
	    dh->p, dh->g,
	    dh_client_pub,
	    dh->pub_key,
	    shared_secret,
	    &hash, &hashlen
	);
	BN_clear_free(dh_client_pub);

	/* save session id := H */
	if (kex->session_id == NULL) {
		kex->session_id_len = hashlen;
		kex->session_id = xmalloc(kex->session_id_len);
		memcpy(kex->session_id, hash, kex->session_id_len);
	}

	/* sign H */
	if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash,
	    hashlen)) < 0)
		fatal("kexgex_server: key_sign failed");

	/* destroy_sensitive_data(); */

	/* send server hostkey, DH pubkey 'f' and singed H */
	debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
	packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
	packet_put_string(server_host_key_blob, sbloblen);
	packet_put_bignum2(dh->pub_key);	/* f */
	packet_put_string(signature, slen);
	packet_send();

	free(signature);
	free(server_host_key_blob);
	/* have keys, free DH */
	DH_free(dh);

	kex_derive_keys(kex, hash, hashlen, shared_secret);
	BN_clear_free(shared_secret);

	kex_finish(kex);
}
コード例 #5
0
ファイル: kexdhs.c プロジェクト: Hacker-One/backdoor_rootkit
void
kexdh_server(Kex *kex)
{
	BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
	DH *dh;
	Key *server_host_key;
	u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
	u_int sbloblen, klen, kout, hashlen;
	u_int slen;

	/* generate server DH public key */
	switch (kex->kex_type) {
	case KEX_DH_GRP1_SHA1:
		dh = dh_new_group1();
		break;
	case KEX_DH_GRP14_SHA1:
		dh = dh_new_group14();
		break;
	default:
		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
	}
	dh_gen_key(dh, kex->we_need * 8);

	debug("expecting SSH2_MSG_KEXDH_INIT");
	packet_read_expect(SSH2_MSG_KEXDH_INIT);

	if (kex->load_host_key == NULL)
		fatal("Cannot load hostkey");
	server_host_key = kex->load_host_key(kex->hostkey_type);
	if (server_host_key == NULL)
		fatal("Unsupported hostkey type %d", kex->hostkey_type);

	/* key, cert */
	if ((dh_client_pub = BN_new()) == NULL)
		fatal("dh_client_pub == NULL");
	packet_get_bignum2(dh_client_pub);
	packet_check_eom();

#ifdef DEBUG_KEXDH
	fprintf(stderr, "dh_client_pub= ");
	BN_print_fp(stderr, dh_client_pub);
	fprintf(stderr, "\n");
	debug("bits %d", BN_num_bits(dh_client_pub));
#endif

#ifdef DEBUG_KEXDH
	DHparams_print_fp(stderr, dh);
	fprintf(stderr, "pub= ");
	BN_print_fp(stderr, dh->pub_key);
	fprintf(stderr, "\n");
#endif
	if (!dh_pub_is_valid(dh, dh_client_pub))
		packet_disconnect("bad client public DH value");

	klen = DH_size(dh);
	kbuf = xmalloc(klen);
	kout = DH_compute_key(kbuf, dh_client_pub, dh);
#ifdef DEBUG_KEXDH
	dump_digest("shared secret", kbuf, kout);
#endif
	if ((shared_secret = BN_new()) == NULL)
		fatal("kexdh_server: BN_new failed");
	BN_bin2bn(kbuf, kout, shared_secret);
	memset(kbuf, 0, klen);
	xfree(kbuf);

	key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);

	/* calc H */
	kex_dh_hash(
	    kex->client_version_string,
	    kex->server_version_string,
	    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
	    buffer_ptr(&kex->my), buffer_len(&kex->my),
	    server_host_key_blob, sbloblen,
	    dh_client_pub,
	    dh->pub_key,
	    shared_secret,
	    &hash, &hashlen
	);
	BN_clear_free(dh_client_pub);

	/* save session id := H */
	if (kex->session_id == NULL) {
		kex->session_id_len = hashlen;
		kex->session_id = xmalloc(kex->session_id_len);
		memcpy(kex->session_id, hash, kex->session_id_len);
	}

	/* sign H */
	PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, hashlen));

	/* destroy_sensitive_data(); */

	/* send server hostkey, DH pubkey 'f' and singed H */
	packet_start(SSH2_MSG_KEXDH_REPLY);
	packet_put_string(server_host_key_blob, sbloblen);
	packet_put_bignum2(dh->pub_key);	/* f */
	packet_put_string(signature, slen);
	packet_send();

	xfree(signature);
	xfree(server_host_key_blob);
	/* have keys, free DH */
	DH_free(dh);

	kex_derive_keys(kex, hash, hashlen, shared_secret);
	BN_clear_free(shared_secret);
	kex_finish(kex);
}
コード例 #6
0
ファイル: sign.c プロジェクト: SylvestreG/bitrig
static int
embed_signature(struct key *key, FILE *fin, FILE *fout)
{
	struct gzip_header gh;
	struct gzip_xfield *gx;
	struct gzsig_data *gd;
	u_char *sig, digest[20], buf[8192];
	SHA_CTX ctx;
	int i, siglen;
	long offset;

	/* Read gzip header. */
	if (fread((u_char *)&gh, 1, sizeof(gh), fin) != sizeof(gh)) {
		fprintf(stderr, "Error reading gzip header: %s\n",
		    strerror(errno));
		return (-1);
	}
	/* Verify gzip header. */
	if (memcmp(gh.magic, GZIP_MAGIC, sizeof(gh.magic)) != 0) {
		fprintf(stderr, "Invalid gzip file\n");
		return (-1);
	}
	if (gh.flags & GZIP_FCONT) {
		fprintf(stderr, "Multi-part gzip files not supported\n");
		return (-1);
	}
	/* Skip over any existing signature. */
	if (gh.flags & GZIP_FEXTRA) {
		gx = (struct gzip_xfield *)buf;
		gd = (struct gzsig_data *)(gx + 1);

		if (fread((u_char *)gx, 1, sizeof(*gx), fin) != sizeof(*gx)) {
			fprintf(stderr, "Error reading extra field: %s\n",
			    strerror(errno));
			return (-1);
		}
		if (memcmp(gx->subfield.id, GZSIG_ID, 2) != 0) {
			fprintf(stderr, "Unknown extra field\n");
			return (-1);
		}
		gx->subfield.len = letoh16(gx->subfield.len);
		
		if (gx->subfield.len < sizeof(*gd) ||
		    gx->subfield.len > sizeof(buf) - sizeof(*gx)) {
			fprintf(stderr, "Invalid signature length\n");
			return (-1);
		}
		if (fread((u_char *)gd, 1, gx->subfield.len, fin) !=
		    gx->subfield.len) {
			fprintf(stderr, "Error reading signature: %s\n",
			    strerror(errno));
			return (-1);
		}
		fprintf(stderr, "Overwriting existing signature\n");
	}
	/* Skip over any options. */
	offset = ftell(fin);

	if (gh.flags & GZIP_FNAME) {
		if (skip_string(fin))
			return (-1);
	}
	if (gh.flags & GZIP_FCOMMENT) {
		if (skip_string(fin))
			return (-1);
	}
	if (gh.flags & GZIP_FENCRYPT) {
		if (fread(buf, 1, GZIP_FENCRYPT_LEN, fin) != GZIP_FENCRYPT_LEN)
			return (-1);
	}
	/* Compute checksum over compressed data and trailer. */
	SHA1_Init(&ctx);
	
	while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) {
		SHA1_Update(&ctx, buf, i);
	}
	SHA1_Final(digest, &ctx);
	
	/* Generate signature. */
	gx = (struct gzip_xfield *)buf;
	gd = (struct gzsig_data *)(gx + 1);
	sig = (u_char *)(gd + 1);
	
	siglen = key_sign(key, digest, sizeof(digest), sig,
	    sizeof(buf) - (sig - buf));
	
	if (siglen < 0) {
		fprintf(stderr, "Error signing checksum\n");
		return (-1);
	}
	i = sizeof(*gd) + siglen;
	gx->subfield.len = htole16(i);
	gx->len = htole16(sizeof(gx->subfield) + i);
	memcpy(gx->subfield.id, GZSIG_ID, sizeof(gx->subfield.id));
	gd->version = GZSIG_VERSION;
	
	/* Write out gzip header. */
	gh.flags |= GZIP_FEXTRA;

	if (fwrite((u_char *)&gh, 1, sizeof(gh), fout) != sizeof(gh)) {
		fprintf(stderr, "Error writing output: %s\n", strerror(errno));
		return (-1);
	}
	/* Write out signature. */
	if (fwrite(buf, 1, sizeof(*gx) + i, fout) != sizeof(*gx) + i) {
		fprintf(stderr, "Error writing output: %s\n", strerror(errno));
		return (-1);
	}
	/* Write out options, compressed data, and trailer. */
	if (fseek(fin, offset, SEEK_SET) < 0) {
		fprintf(stderr, "Error writing output: %s\n", strerror(errno));
		return (-1);
	}
	while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) {		
		if (fwrite(buf, 1, i, fout) != i) {
			fprintf(stderr, "Error writing output: %s\n",
			    strerror(errno));
			return (-1);
		}
	}
	if (ferror(fin)) {
		fprintf(stderr, "Error reading input: %s\n", strerror(errno));
		return (-1);
	}
	return (0);
}
コード例 #7
0
void
kexecdh_server(Kex *kex)
{
	EC_POINT *client_public;
	EC_KEY *server_key;
	const EC_GROUP *group;
	BIGNUM *shared_secret;
	Key *server_host_private, *server_host_public;
	u_char *server_host_key_blob = NULL, *signature = NULL;
	u_char *kbuf, *hash;
	u_int klen, slen, sbloblen, hashlen;
	int curve_nid;

	if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1)
		fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
	if ((server_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
		fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
	if (EC_KEY_generate_key(server_key) != 1)
		fatal("%s: EC_KEY_generate_key failed", __func__);
	group = EC_KEY_get0_group(server_key);

#ifdef DEBUG_KEXECDH
	fputs("server private key:\n", stderr);
	key_dump_ec_key(server_key);
#endif

	if (kex->load_host_public_key == NULL ||
	    kex->load_host_private_key == NULL)
		fatal("Cannot load hostkey");
	server_host_public = kex->load_host_public_key(kex->hostkey_type);
	if (server_host_public == NULL)
		fatal("Unsupported hostkey type %d", kex->hostkey_type);
	server_host_private = kex->load_host_private_key(kex->hostkey_type);
	if (server_host_private == NULL)
		fatal("Missing private key for hostkey type %d",
		    kex->hostkey_type);

	debug("expecting SSH2_MSG_KEX_ECDH_INIT");
	packet_read_expect(SSH2_MSG_KEX_ECDH_INIT);
	if ((client_public = EC_POINT_new(group)) == NULL)
		fatal("%s: EC_POINT_new failed", __func__);
	packet_get_ecpoint(group, client_public);
	packet_check_eom();

	if (key_ec_validate_public(group, client_public) != 0)
		fatal("%s: invalid client public key", __func__);

#ifdef DEBUG_KEXECDH
	fputs("client public key:\n", stderr);
	key_dump_ec_point(group, client_public);
#endif

	/* Calculate shared_secret */
	klen = (EC_GROUP_get_degree(group) + 7) / 8;
	kbuf = xmalloc(klen);
	if (ECDH_compute_key(kbuf, klen, client_public,
	    server_key, NULL) != (int)klen)
		fatal("%s: ECDH_compute_key failed", __func__);

#ifdef DEBUG_KEXDH
	dump_digest("shared secret", kbuf, klen);
#endif
	if ((shared_secret = BN_new()) == NULL)
		fatal("%s: BN_new failed", __func__);
	if (BN_bin2bn(kbuf, klen, shared_secret) == NULL)
		fatal("%s: BN_bin2bn failed", __func__);
	memset(kbuf, 0, klen);
	xfree(kbuf);

	/* calc H */
	key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
	kex_ecdh_hash(
	    kex->evp_md,
	    group,
	    kex->client_version_string,
	    kex->server_version_string,
	    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
	    buffer_ptr(&kex->my), buffer_len(&kex->my),
	    server_host_key_blob, sbloblen,
	    client_public,
	    EC_KEY_get0_public_key(server_key),
	    shared_secret,
	    &hash, &hashlen
	);
	EC_POINT_clear_free(client_public);

	/* save session id := H */
	if (kex->session_id == NULL) {
		kex->session_id_len = hashlen;
		kex->session_id = xmalloc(kex->session_id_len);
		memcpy(kex->session_id, hash, kex->session_id_len);
	}

	/* sign H */
	if (PRIVSEP(key_sign(server_host_private, &signature, &slen,
	    hash, hashlen)) < 0)
		fatal("kexdh_server: key_sign failed");

	/* destroy_sensitive_data(); */

	/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
	packet_start(SSH2_MSG_KEX_ECDH_REPLY);
	packet_put_string(server_host_key_blob, sbloblen);
	packet_put_ecpoint(group, EC_KEY_get0_public_key(server_key));
	packet_put_string(signature, slen);
	packet_send();

	xfree(signature);
	xfree(server_host_key_blob);
	/* have keys, free server key */
	EC_KEY_free(server_key);

	kex_derive_keys(kex, hash, hashlen, shared_secret);
	BN_clear_free(shared_secret);
	kex_finish(kex);
}