/*
 * libwebsockets - small server side websockets and web server implementation
 *
 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#if !defined(__LWS_SSH_H__)
#define __LWS_SSH_H__

#if defined(LWS_WITH_MBEDTLS)
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
#include "mbedtls/rsa.h"
#endif

#include "lws-plugin-ssh.h"

#define LWS_SIZE_EC25519	32
#define LWS_SIZE_EC25519_PUBKEY 32
#define LWS_SIZE_EC25519_PRIKEY 64

#define LWS_SIZE_SHA256		32
#define LWS_SIZE_SHA512		64

#define LWS_SIZE_AES256_KEY	32
#define LWS_SIZE_AES256_IV	12
#define LWS_SIZE_AES256_MAC	16
#define LWS_SIZE_AES256_BLOCK	16

#define LWS_SIZE_CHACHA256_KEY	(2 * 32)
#define POLY1305_TAGLEN		16
#define POLY1305_KEYLEN		32

#define crypto_hash_sha512_BYTES 64U

#define PEEK_U64(p) \
        (((uint64_t)(((const uint8_t *)(p))[0]) << 56) | \
         ((uint64_t)(((const uint8_t *)(p))[1]) << 48) | \
         ((uint64_t)(((const uint8_t *)(p))[2]) << 40) | \
         ((uint64_t)(((const uint8_t *)(p))[3]) << 32) | \
         ((uint64_t)(((const uint8_t *)(p))[4]) << 24) | \
         ((uint64_t)(((const uint8_t *)(p))[5]) << 16) | \
         ((uint64_t)(((const uint8_t *)(p))[6]) << 8) | \
          (uint64_t)(((const uint8_t *)(p))[7]))
#define PEEK_U32(p) \
        (((uint32_t)(((const uint8_t *)(p))[0]) << 24) | \
         ((uint32_t)(((const uint8_t *)(p))[1]) << 16) | \
         ((uint32_t)(((const uint8_t *)(p))[2]) << 8) | \
          (uint32_t)(((const uint8_t *)(p))[3]))
#define PEEK_U16(p) \
        (((uint16_t)(((const uint8_t *)(p))[0]) << 8) | \
          (uint16_t)(((const uint8_t *)(p))[1]))

#define POKE_U64(p, v) \
        do { \
                const uint64_t __v = (v); \
                ((uint8_t *)(p))[0] = (__v >> 56) & 0xff; \
                ((uint8_t *)(p))[1] = (__v >> 48) & 0xff; \
                ((uint8_t *)(p))[2] = (__v >> 40) & 0xff; \
                ((uint8_t *)(p))[3] = (__v >> 32) & 0xff; \
                ((uint8_t *)(p))[4] = (__v >> 24) & 0xff; \
                ((uint8_t *)(p))[5] = (__v >> 16) & 0xff; \
                ((uint8_t *)(p))[6] = (__v >> 8) & 0xff; \
                ((uint8_t *)(p))[7] = __v & 0xff; \
        } while (0)
#define POKE_U32(p, v) \
        do { \
                const uint32_t __v = (v); \
                ((uint8_t *)(p))[0] = (__v >> 24) & 0xff; \
                ((uint8_t *)(p))[1] = (__v >> 16) & 0xff; \
                ((uint8_t *)(p))[2] = (__v >> 8) & 0xff; \
                ((uint8_t *)(p))[3] = __v & 0xff; \
        } while (0)
#define POKE_U16(p, v) \
        do { \
                const uint16_t __v = (v); \
                ((uint8_t *)(p))[0] = (__v >> 8) & 0xff; \
                ((uint8_t *)(p))[1] = __v & 0xff; \
        } while (0)


enum {
	SSH_MSG_DISCONNECT					= 1,
	SSH_MSG_IGNORE						= 2,
	SSH_MSG_UNIMPLEMENTED					= 3,
	SSH_MSG_DEBUG						= 4,
	SSH_MSG_SERVICE_REQUEST					= 5,
	SSH_MSG_SERVICE_ACCEPT					= 6,
	SSH_MSG_KEXINIT						= 20,
	SSH_MSG_NEWKEYS						= 21,

	/* 30 .. 49: KEX messages specific to KEX protocol */
	SSH_MSG_KEX_ECDH_INIT					= 30,
	SSH_MSG_KEX_ECDH_REPLY					= 31,

	/* 50... userauth */

	SSH_MSG_USERAUTH_REQUEST				= 50,
	SSH_MSG_USERAUTH_FAILURE				= 51,
	SSH_MSG_USERAUTH_SUCCESS				= 52,
	SSH_MSG_USERAUTH_BANNER					= 53,

	/* 60... publickey */

	SSH_MSG_USERAUTH_PK_OK					= 60,

	/* 80... connection */

	SSH_MSG_GLOBAL_REQUEST					= 80,
	SSH_MSG_REQUEST_SUCCESS					= 81,
	SSH_MSG_REQUEST_FAILURE					= 82,

	SSH_MSG_CHANNEL_OPEN					= 90,
	SSH_MSG_CHANNEL_OPEN_CONFIRMATION			= 91,
	SSH_MSG_CHANNEL_OPEN_FAILURE				= 92,
	SSH_MSG_CHANNEL_WINDOW_ADJUST				= 93,
	SSH_MSG_CHANNEL_DATA					= 94,
	SSH_MSG_CHANNEL_EXTENDED_DATA				= 95,
	SSH_MSG_CHANNEL_EOF					= 96,
	SSH_MSG_CHANNEL_CLOSE					= 97,
	SSH_MSG_CHANNEL_REQUEST					= 98,
	SSH_MSG_CHANNEL_SUCCESS					= 99,
	SSH_MSG_CHANNEL_FAILURE					= 100,

	SSH_EXTENDED_DATA_STDERR				= 1,

	SSH_CH_TYPE_SESSION					= 1,
	SSH_CH_TYPE_SCP						= 2,
	SSH_CH_TYPE_SFTP					= 3,

	SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT		= 1,
	SSH_DISCONNECT_PROTOCOL_ERROR				= 2,
	SSH_DISCONNECT_KEY_EXCHANGE_FAILED			= 3,
	SSH_DISCONNECT_RESERVED					= 4,
	SSH_DISCONNECT_MAC_ERROR				= 5,
	SSH_DISCONNECT_COMPRESSION_ERROR			= 6,
	SSH_DISCONNECT_SERVICE_NOT_AVAILABLE			= 7,
	SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED		= 8,
	SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE			= 9,
	SSH_DISCONNECT_CONNECTION_LOST				= 10,
	SSH_DISCONNECT_BY_APPLICATION				= 11,
	SSH_DISCONNECT_TOO_MANY_CONNECTIONS			= 12,
	SSH_DISCONNECT_AUTH_CANCELLED_BY_USER			= 13,
	SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE		= 14,
	SSH_DISCONNECT_ILLEGAL_USER_NAME			= 15,
	
	SSH_OPEN_ADMINISTRATIVELY_PROHIBITED			= 1,
	SSH_OPEN_CONNECT_FAILED					= 2,
	SSH_OPEN_UNKNOWN_CHANNEL_TYPE				= 3,
	SSH_OPEN_RESOURCE_SHORTAGE				= 4,

	KEX_STATE_EXPECTING_CLIENT_OFFER			= 0,
	KEX_STATE_REPLIED_TO_OFFER,
	KEX_STATE_CRYPTO_INITIALIZED,

	SSH_KEYIDX_IV						= 0,
	SSH_KEYIDX_ENC,
	SSH_KEYIDX_INTEG,

	/* things we may write on the connection */

	SSH_WT_NONE						= 0,
	SSH_WT_VERSION,
	SSH_WT_OFFER,
	SSH_WT_OFFER_REPLY,
	SSH_WT_SEND_NEWKEYS,
	SSH_WT_UA_ACCEPT,
	SSH_WT_UA_FAILURE,
	SSH_WT_UA_BANNER,
	SSH_WT_UA_PK_OK,
	SSH_WT_UA_SUCCESS,
	SSH_WT_CH_OPEN_CONF,
	SSH_WT_CH_FAILURE,
	SSH_WT_CHRQ_SUCC,
	SSH_WT_CHRQ_FAILURE,
	SSH_WT_SCP_ACK_OKAY,
	SSH_WT_SCP_ACK_ERROR,
	SSH_WT_CH_CLOSE,
	SSH_WT_CH_EOF,
	SSH_WT_WINDOW_ADJUST,
	SSH_WT_EXIT_STATUS,

	/* RX parser states */

	SSH_INITIALIZE_TRANSIENT				= 0,
	SSHS_IDSTRING,
	SSHS_IDSTRING_CR,
	SSHS_MSG_LEN,
	SSHS_MSG_PADDING,
	SSHS_MSG_ID,
	SSH_KEX_STATE_COOKIE,
	SSH_KEX_NL_KEX_ALGS_LEN,
	SSH_KEX_NL_KEX_ALGS,
	SSH_KEX_NL_SHK_ALGS_LEN,
	SSH_KEX_NL_SHK_ALGS,
	SSH_KEX_NL_EACTS_ALGS_LEN,
	SSH_KEX_NL_EACTS_ALGS,
	SSH_KEX_NL_EASTC_ALGS_LEN,
	SSH_KEX_NL_EASTC_ALGS,
	SSH_KEX_NL_MACTS_ALGS_LEN,
	SSH_KEX_NL_MACTS_ALGS,
	SSH_KEX_NL_MASTC_ALGS_LEN,
	SSH_KEX_NL_MASTC_ALGS,
	SSH_KEX_NL_CACTS_ALGS_LEN,
	SSH_KEX_NL_CACTS_ALGS,
	SSH_KEX_NL_CASTC_ALGS_LEN,
	SSH_KEX_NL_CASTC_ALGS,
	SSH_KEX_NL_LCTS_ALGS_LEN,
	SSH_KEX_NL_LCTS_ALGS,
	SSH_KEX_NL_LSTC_ALGS_LEN,
	SSH_KEX_NL_LSTC_ALGS,
	SSH_KEX_FIRST_PKT,
	SSH_KEX_RESERVED,

	SSH_KEX_STATE_ECDH_KEYLEN,
	SSH_KEX_STATE_ECDH_Q_C,

	SSHS_MSG_EAT_PADDING,
	SSH_KEX_STATE_SKIP,

	SSHS_GET_STRING_LEN,
	SSHS_GET_STRING,
	SSHS_GET_STRING_LEN_ALLOC,
	SSHS_GET_STRING_ALLOC,
	SSHS_DO_SERVICE_REQUEST,

	SSHS_DO_UAR_SVC,
	SSHS_DO_UAR_PUBLICKEY,
	SSHS_NVC_DO_UAR_CHECK_PUBLICKEY,
	SSHS_DO_UAR_SIG_PRESENT,
	SSHS_NVC_DO_UAR_ALG,
	SSHS_NVC_DO_UAR_PUBKEY_BLOB,
	SSHS_NVC_DO_UAR_SIG,

	SSHS_GET_U32,

	SSHS_NVC_CHOPEN_TYPE,
	SSHS_NVC_CHOPEN_SENDER_CH,
	SSHS_NVC_CHOPEN_WINSIZE,
	SSHS_NVC_CHOPEN_PKTSIZE,

	SSHS_NVC_CHRQ_RECIP,
	SSHS_NVC_CHRQ_TYPE,
	SSHS_CHRQ_WANT_REPLY,
        SSHS_NVC_CHRQ_TERM,
        SSHS_NVC_CHRQ_TW,
        SSHS_NVC_CHRQ_TH,
	SSHS_NVC_CHRQ_TWP,
        SSHS_NVC_CHRQ_THP,
        SSHS_NVC_CHRQ_MODES,

	SSHS_NVC_CHRQ_ENV_NAME,
	SSHS_NVC_CHRQ_ENV_VALUE,

	SSHS_NVC_CHRQ_EXEC_CMD,

	SSHS_NVC_CHRQ_SUBSYSTEM,

	SSHS_NVC_CH_EOF,
	SSHS_NVC_CH_CLOSE,

	SSHS_NVC_CD_RECIP,
	SSHS_NVC_CD_DATA,
	SSHS_NVC_CD_DATA_ALLOC,

	SSHS_NVC_WA_RECIP,
	SSHS_NVC_WA_ADD,

	SSHS_NVC_DISCONNECT_REASON,
	SSHS_NVC_DISCONNECT_DESC,
	SSHS_NVC_DISCONNECT_LANG,

	SSHS_SCP_COLLECTSTR			= 0,
	SSHS_SCP_PAYLOADIN			= 1,


	/* from https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13 */

	SECSH_FILEXFER_VERSION			= 6,

	/* sftp packet types */

	SSH_FXP_INIT				= 1,
	SSH_FXP_VERSION				= 2,
	SSH_FXP_OPEN				= 3,
	SSH_FXP_CLOSE				= 4,
	SSH_FXP_READ				= 5,
	SSH_FXP_WRITE				= 6,
	SSH_FXP_LSTAT				= 7,
	SSH_FXP_FSTAT				= 8,
	SSH_FXP_SETSTAT				= 9,
	SSH_FXP_FSETSTAT			= 10,
	SSH_FXP_OPENDIR				= 11,
	SSH_FXP_READDIR				= 12,
	SSH_FXP_REMOVE				= 13,
	SSH_FXP_MKDIR				= 14,
	SSH_FXP_RMDIR				= 15,
	SSH_FXP_REALPATH			= 16,
	SSH_FXP_STAT				= 17,
	SSH_FXP_RENAME				= 18,
	SSH_FXP_READLINK			= 19,
	SSH_FXP_LINK				= 21,
	SSH_FXP_BLOCK				= 22,
	SSH_FXP_UNBLOCK				= 23,
	SSH_FXP_STATUS				= 101,
	SSH_FXP_HANDLE				= 102,
	SSH_FXP_DATA				= 103,
	SSH_FXP_NAME				= 104,
	SSH_FXP_ATTRS				= 105,
	SSH_FXP_EXTENDED			= 200,
	SSH_FXP_EXTENDED_REPLY			= 201,

	/* sftp return codes */

	SSH_FX_OK				= 0,
	SSH_FX_EOF				= 1,
	SSH_FX_NO_SUCH_FILE			= 2,
	SSH_FX_PERMISSION_DENIED		= 3,
	SSH_FX_FAILURE				= 4,
	SSH_FX_BAD_MESSAGE			= 5,
	SSH_FX_NO_CONNECTION			= 6,
	SSH_FX_CONNECTION_LOST			= 7,
	SSH_FX_OP_UNSUPPORTED			= 8,
	SSH_FX_INVALID_HANDLE			= 9,
	SSH_FX_NO_SUCH_PATH			= 10,
	SSH_FX_FILE_ALREADY_EXISTS		= 11,
	SSH_FX_WRITE_PROTECT			= 12,
	SSH_FX_NO_MEDIA				= 13,
	SSH_FX_NO_SPACE_ON_FILESYSTEM		= 14,
	SSH_FX_QUOTA_EXCEEDED			= 15,
	SSH_FX_UNKNOWN_PRINCIPAL		= 16,
	SSH_FX_LOCK_CONFLICT			= 17,
	SSH_FX_DIR_NOT_EMPTY			= 18,
	SSH_FX_NOT_A_DIRECTORY			= 19,
	SSH_FX_INVALID_FILENAME			= 20,
	SSH_FX_LINK_LOOP			= 21,
	SSH_FX_CANNOT_DELETE			= 22,
	SSH_FX_INVALID_PARAMETER		= 23,
	SSH_FX_FILE_IS_A_DIRECTORY		= 24,
	SSH_FX_BYTE_RANGE_LOCK_CONFLICT		= 25,
	SSH_FX_BYTE_RANGE_LOCK_REFUSED		= 26,
	SSH_FX_DELETE_PENDING			= 27,
	SSH_FX_FILE_CORRUPT			= 28,
	SSH_FX_OWNER_INVALID			= 29,
	SSH_FX_GROUP_INVALID			= 30,
	SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK	= 31,


	SSH_PENDING_TIMEOUT_CONNECT_TO_SUCCESSFUL_AUTH =
			PENDING_TIMEOUT_USER_REASON_BASE + 0,

	SSH_AUTH_STATE_NO_AUTH			= 0,
	SSH_AUTH_STATE_GAVE_AUTH_IGNORE_REQS	= 1,
};

#define LWS_SSH_INITIAL_WINDOW 16384

struct lws_ssh_userauth {
	struct lws_genhash_ctx hash_ctx;
	char *username;
	char *service;
	char *alg;
	uint8_t *pubkey;
	uint32_t pubkey_len;
	uint8_t *sig;
	uint32_t sig_len;
	char sig_present;
};

struct lws_ssh_keys {
	/* 3 == SSH_KEYIDX_IV (len=4), SSH_KEYIDX_ENC, SSH_KEYIDX_INTEG */
	uint8_t key[3][LWS_SIZE_CHACHA256_KEY];

	/* opaque allocation made when cipher activated */
	void *cipher;

	uint8_t MAC_length;
	uint8_t padding_alignment; /* block size */
	uint8_t valid:1;
	uint8_t full_length:1;
};

struct lws_kex {
	uint8_t kex_r[256];
	uint8_t Q_C[LWS_SIZE_EC25519]; /* client eph public key aka 'e' */
	uint8_t eph_pri_key[LWS_SIZE_EC25519]; /* server eph private key */
	uint8_t Q_S[LWS_SIZE_EC25519]; /* server ephemeral public key */
	uint8_t kex_cookie[16];
	uint8_t *I_C; /* malloc'd copy of client KEXINIT payload */
	uint8_t *I_S; /* malloc'd copy of server KEXINIT payload */
	uint32_t I_C_payload_len;
	uint32_t I_C_alloc_len;
	uint32_t I_S_payload_len;
	uint32_t kex_r_len;
	uint8_t match_bitfield;
	uint8_t newkeys; /* which sides newkeys have been applied */

	struct lws_ssh_keys keys_next_cts;
	struct lws_ssh_keys keys_next_stc;
};

struct lws_subprotocol_scp {
	char fp[128];
	uint64_t len;
	uint32_t attr;
	char cmd;
	char ips;
};

typedef union {
	struct lws_subprotocol_scp scp;
} lws_subprotocol;

struct per_session_data__sshd;

struct lws_ssh_channel {
	struct lws_ssh_channel *next;

	struct per_session_data__sshd *pss;

	lws_subprotocol *sub; /* NULL, or allocated subprotocol state */
	void *priv; /* owned by user code */
	int type;
	uint32_t server_ch;
	uint32_t sender_ch;
	int32_t window;
	int32_t peer_window_est;
	uint32_t max_pkt;

	uint32_t spawn_pid;
	int retcode;

	uint8_t scheduled_close:1;
	uint8_t sent_close:1;
	uint8_t received_close:1;
};

struct per_vhost_data__sshd;

struct per_session_data__sshd {
	struct per_session_data__sshd *next;
	struct per_vhost_data__sshd *vhd;
	struct lws *wsi;

	struct lws_kex *kex;
	char *disconnect_desc;

	uint8_t K[LWS_SIZE_EC25519]; /* shared secret */
	uint8_t session_id[LWS_SIZE_SHA256]; /* H from first working KEX */
	char name[64];
	char last_auth_req_username[32];
	char last_auth_req_service[32];

	struct lws_ssh_keys active_keys_cts;
	struct lws_ssh_keys active_keys_stc;
	struct lws_ssh_userauth *ua;
	struct lws_ssh_channel *ch_list;
	struct lws_ssh_channel *ch_temp;

	uint8_t *last_alloc;

	union {
		struct lws_ssh_pty pty;
		char aux[64];
	} args;

	uint32_t ssh_sequence_ctr_cts;
	uint32_t ssh_sequence_ctr_stc;

	uint64_t payload_bytes_cts;
	uint64_t payload_bytes_stc;

	uint32_t disconnect_reason;

	char V_C[64]; /* Client version String */
	uint8_t packet_assembly[2048];
	uint32_t pa_pos;

	uint32_t msg_len;
	uint32_t pos;
	uint32_t len;
	uint32_t ctr;
	uint32_t npos;
	uint32_t reason;
	uint32_t channel_doing_spawn;
	int next_ch_num;

	uint8_t K_S[LWS_SIZE_EC25519]; /* server public key */

	uint32_t copy_to_I_C:1;
	uint32_t okayed_userauth:1;
	uint32_t sent_banner:1;
	uint32_t seen_auth_req_before:1;
	uint32_t serviced_stderr_last:1;
	uint32_t kex_state;
	uint32_t chrq_server_port;
	uint32_t ch_recip;
	uint32_t count_auth_attempts;

	char parser_state;
	char state_after_string;
	char first_coming;
	uint8_t rq_want_reply;
	uint8_t ssh_auth_state;

	uint8_t msg_id;
	uint8_t msg_padding;
	uint8_t write_task[8];
	struct lws_ssh_channel *write_channel[8];
	uint8_t wt_head, wt_tail;
};

struct per_vhost_data__sshd {
	struct lws_context *context;
	struct lws_vhost *vhost;
	const struct lws_protocols *protocol;
	struct per_session_data__sshd *live_pss_list;
	const struct lws_ssh_ops *ops;
};


struct host_keys {
	uint8_t *data;
	uint32_t len;
};

extern struct host_keys host_keys[];

extern int
crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n,
			     const unsigned char *p);

extern int
ed25519_key_parse(uint8_t *p, size_t len, char *type, size_t type_len,
                  uint8_t *pub, uint8_t *pri);

extern int
kex_ecdh(struct per_session_data__sshd *pss, uint8_t *result, uint32_t *plen);

extern uint32_t
lws_g32(uint8_t **p);

extern uint32_t
lws_p32(uint8_t *p, uint32_t v);

extern int
lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len);

extern const char *lws_V_S;

extern int
lws_chacha_activate(struct lws_ssh_keys *keys);

extern void
lws_chacha_destroy(struct lws_ssh_keys *keys);

extern uint32_t
lws_chachapoly_get_length(struct lws_ssh_keys *keys, uint32_t seq,
			  const uint8_t *in4);

extern void
poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen,
    const u_char key[POLY1305_KEYLEN]);

extern int
lws_chacha_decrypt(struct lws_ssh_keys *keys, uint32_t seq,
		   const uint8_t *ct, uint32_t len, uint8_t *pt);
extern int
lws_chacha_encrypt(struct lws_ssh_keys *keys, uint32_t seq,
		   const uint8_t *ct, uint32_t len, uint8_t *pt);

extern void
lws_pad_set_length(struct per_session_data__sshd *pss, void *start, uint8_t **p,
		   struct lws_ssh_keys *keys);

extern size_t
get_gen_server_key_25519(struct per_session_data__sshd *pss, uint8_t *b, size_t len);

extern int
crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen,
		    const unsigned char *m, size_t mlen,
		    const unsigned char *sk);

extern int
crypto_sign_ed25519_keypair(struct lws_context *context, uint8_t *pk,
			    uint8_t *sk);

#endif
