1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "libwebsockets.h" 26d4afb5ceSopenharmony_ci#include "lws-ssh.h" 27d4afb5ceSopenharmony_ci 28d4afb5ceSopenharmony_ci#include <string.h> 29d4afb5ceSopenharmony_ci 30d4afb5ceSopenharmony_ci/* 31d4afb5ceSopenharmony_ci * ssh-keygen -t ed25519 32d4afb5ceSopenharmony_ci * head -n-1 srv-key-25519 | tail -n +2 | base64 -d | hexdump -C 33d4afb5ceSopenharmony_ci */ 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_cistatic void 36d4afb5ceSopenharmony_cilws_sized_blob(uint8_t **p, void *blob, uint32_t len) 37d4afb5ceSopenharmony_ci{ 38d4afb5ceSopenharmony_ci lws_p32((*p), len); 39d4afb5ceSopenharmony_ci *p += 4; 40d4afb5ceSopenharmony_ci memcpy(*p, blob, len); 41d4afb5ceSopenharmony_ci *p += len; 42d4afb5ceSopenharmony_ci} 43d4afb5ceSopenharmony_ci 44d4afb5ceSopenharmony_cistatic const char key_leadin[] = "openssh-key-v1\x00\x00\x00\x00\x04none" 45d4afb5ceSopenharmony_ci "\x00\x00\x00\x04none\x00" 46d4afb5ceSopenharmony_ci "\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x33" 47d4afb5ceSopenharmony_ci "\x00\x00\x00\x0bssh-ed25519\x00\x00\x00\x20", 48d4afb5ceSopenharmony_ci key_sep[] = "\x00\x00\x00\x90\xb1\x4f\xa7\x28" 49d4afb5ceSopenharmony_ci "\xb1\x4f\xa7\x28\x00\x00\x00\x0bssh-ed25519" 50d4afb5ceSopenharmony_ci "\x00\x00\x00\x20", 51d4afb5ceSopenharmony_ci key_privl[] = "\x00\x00\x00\x40", 52d4afb5ceSopenharmony_ci key_trail[] = "\x00\x00\x00\x0cself-gen@cbl\x01"; 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_cistatic size_t 55d4afb5ceSopenharmony_cilws_gen_server_key_ed25519(struct lws_context *context, uint8_t *buf256, 56d4afb5ceSopenharmony_ci size_t max_len) 57d4afb5ceSopenharmony_ci{ 58d4afb5ceSopenharmony_ci uint8_t *p = buf256 + sizeof(key_leadin) - 1; 59d4afb5ceSopenharmony_ci 60d4afb5ceSopenharmony_ci if (max_len < sizeof(key_leadin) - 1 + 32 + sizeof(key_sep) - 1 + 32 + 61d4afb5ceSopenharmony_ci sizeof(key_privl) - 1 + 64 + sizeof(key_trail) - 1) 62d4afb5ceSopenharmony_ci return 0; 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_ci memcpy(buf256, key_leadin, sizeof(key_leadin) - 1); 65d4afb5ceSopenharmony_ci crypto_sign_ed25519_keypair(context, p, p + 32 + sizeof(key_sep) - 1 + 66d4afb5ceSopenharmony_ci 32 + sizeof(key_privl) - 1); 67d4afb5ceSopenharmony_ci memcpy(p + 32 + sizeof(key_sep) - 1, p, 32); 68d4afb5ceSopenharmony_ci p += 32; 69d4afb5ceSopenharmony_ci memcpy(p, key_sep, sizeof(key_sep) - 1); 70d4afb5ceSopenharmony_ci p += sizeof(key_sep) - 1 + 32; 71d4afb5ceSopenharmony_ci memcpy(p, key_privl, sizeof(key_privl) - 1); 72d4afb5ceSopenharmony_ci p += sizeof(key_privl) - 1 + 64; 73d4afb5ceSopenharmony_ci memcpy(p, key_trail, sizeof(key_trail) - 1); 74d4afb5ceSopenharmony_ci p += sizeof(key_trail) - 1; 75d4afb5ceSopenharmony_ci 76d4afb5ceSopenharmony_ci lwsl_notice("%s: Generated key len %ld\n", __func__, (long)(p - buf256)); 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci return (size_t)(p - buf256); 79d4afb5ceSopenharmony_ci} 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_cistatic int 82d4afb5ceSopenharmony_cilws_mpint_rfc4251(uint8_t *dest, const uint8_t *src, int bytes, int uns) 83d4afb5ceSopenharmony_ci{ 84d4afb5ceSopenharmony_ci uint8_t *odest = dest; 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_ci while (!*src && bytes > 1) { 87d4afb5ceSopenharmony_ci src++; 88d4afb5ceSopenharmony_ci bytes--; 89d4afb5ceSopenharmony_ci } 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_ci if (!*src) { 92d4afb5ceSopenharmony_ci *dest++ = 0; 93d4afb5ceSopenharmony_ci *dest++ = 0; 94d4afb5ceSopenharmony_ci *dest++ = 0; 95d4afb5ceSopenharmony_ci *dest++ = 0; 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_ci return 4; 98d4afb5ceSopenharmony_ci } 99d4afb5ceSopenharmony_ci 100d4afb5ceSopenharmony_ci if (uns && (*src) & 0x80) 101d4afb5ceSopenharmony_ci bytes++; 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci *dest++ = (uint8_t)(bytes >> 24); 104d4afb5ceSopenharmony_ci *dest++ = (uint8_t)(bytes >> 16); 105d4afb5ceSopenharmony_ci *dest++ = (uint8_t)(bytes >> 8); 106d4afb5ceSopenharmony_ci *dest++ = (uint8_t)(bytes); 107d4afb5ceSopenharmony_ci 108d4afb5ceSopenharmony_ci if (uns && (*src) & 0x80) { 109d4afb5ceSopenharmony_ci *dest++ = 0; 110d4afb5ceSopenharmony_ci bytes--; 111d4afb5ceSopenharmony_ci } 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci while (bytes--) 114d4afb5ceSopenharmony_ci *dest++ = *src++; 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci return lws_ptr_diff(dest, odest); 117d4afb5ceSopenharmony_ci} 118d4afb5ceSopenharmony_ci 119d4afb5ceSopenharmony_ciint 120d4afb5ceSopenharmony_cied25519_key_parse(uint8_t *p, size_t len, char *type, size_t type_len, 121d4afb5ceSopenharmony_ci uint8_t *pub, uint8_t *pri) 122d4afb5ceSopenharmony_ci{ 123d4afb5ceSopenharmony_ci uint32_t l, publ, m; 124d4afb5ceSopenharmony_ci uint8_t *op = p; 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ci if (len < 180) 127d4afb5ceSopenharmony_ci return 1; 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_ci if (memcmp(p, "openssh-key-v1", 14)) 130d4afb5ceSopenharmony_ci return 2; 131d4afb5ceSopenharmony_ci 132d4afb5ceSopenharmony_ci p += 15; 133d4afb5ceSopenharmony_ci 134d4afb5ceSopenharmony_ci l = lws_g32(&p); /* ciphername */ 135d4afb5ceSopenharmony_ci if (l != 4 || memcmp(p, "none", 4)) 136d4afb5ceSopenharmony_ci return 3; 137d4afb5ceSopenharmony_ci p += l; 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_ci l = lws_g32(&p); /* kdfname */ 140d4afb5ceSopenharmony_ci if (l != 4 || memcmp(p, "none", 4)) 141d4afb5ceSopenharmony_ci return 4; 142d4afb5ceSopenharmony_ci p += l; 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci l = lws_g32(&p); /* kdfoptions */ 145d4afb5ceSopenharmony_ci if (l) 146d4afb5ceSopenharmony_ci return 5; 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci l = lws_g32(&p); /* number of keys */ 149d4afb5ceSopenharmony_ci if (l != 1) 150d4afb5ceSopenharmony_ci return 6; 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_ci publ = lws_g32(&p); /* length of pubkey block */ 153d4afb5ceSopenharmony_ci if ((size_t)((uint32_t)(p - op) + publ) >= len) 154d4afb5ceSopenharmony_ci return 7; 155d4afb5ceSopenharmony_ci 156d4afb5ceSopenharmony_ci l = lws_g32(&p); /* key type length */ 157d4afb5ceSopenharmony_ci if (l > 31) 158d4afb5ceSopenharmony_ci return 8; 159d4afb5ceSopenharmony_ci m = l; 160d4afb5ceSopenharmony_ci if (m >= type_len) 161d4afb5ceSopenharmony_ci m = (uint32_t)type_len -1 ; 162d4afb5ceSopenharmony_ci lws_strncpy(type, (const char *)p, m + 1); 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci p += l; 165d4afb5ceSopenharmony_ci l = lws_g32(&p); /* pub key length */ 166d4afb5ceSopenharmony_ci if (l != 32) 167d4afb5ceSopenharmony_ci return 10; 168d4afb5ceSopenharmony_ci 169d4afb5ceSopenharmony_ci p += l; 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_ci publ = lws_g32(&p); /* length of private key block */ 172d4afb5ceSopenharmony_ci if ((size_t)((uint32_t)(p - op) + publ) != len) 173d4afb5ceSopenharmony_ci return 11; 174d4afb5ceSopenharmony_ci 175d4afb5ceSopenharmony_ci l = lws_g32(&p); /* checkint 1 */ 176d4afb5ceSopenharmony_ci if (lws_g32(&p) != l) /* must match checkint 2 */ 177d4afb5ceSopenharmony_ci return 12; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci l = lws_g32(&p); /* key type length */ 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci p += l; 182d4afb5ceSopenharmony_ci l = lws_g32(&p); /* public key part length */ 183d4afb5ceSopenharmony_ci if (l != LWS_SIZE_EC25519_PUBKEY) 184d4afb5ceSopenharmony_ci return 15; 185d4afb5ceSopenharmony_ci 186d4afb5ceSopenharmony_ci if (pub) 187d4afb5ceSopenharmony_ci memcpy(pub, p, LWS_SIZE_EC25519_PUBKEY); 188d4afb5ceSopenharmony_ci p += l; 189d4afb5ceSopenharmony_ci l = lws_g32(&p); /* private key part length */ 190d4afb5ceSopenharmony_ci if (l != LWS_SIZE_EC25519_PRIKEY) 191d4afb5ceSopenharmony_ci return 16; 192d4afb5ceSopenharmony_ci 193d4afb5ceSopenharmony_ci if (pri) 194d4afb5ceSopenharmony_ci memcpy(pri, p, LWS_SIZE_EC25519_PRIKEY); 195d4afb5ceSopenharmony_ci 196d4afb5ceSopenharmony_ci return 0; 197d4afb5ceSopenharmony_ci} 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_cistatic int 200d4afb5ceSopenharmony_ci_genhash_update_len(struct lws_genhash_ctx *ctx, const void *input, size_t ilen) 201d4afb5ceSopenharmony_ci{ 202d4afb5ceSopenharmony_ci uint32_t be; 203d4afb5ceSopenharmony_ci 204d4afb5ceSopenharmony_ci lws_p32((uint8_t *)&be, (uint32_t)ilen); 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci if (lws_genhash_update(ctx, (uint8_t *)&be, 4)) 207d4afb5ceSopenharmony_ci return 1; 208d4afb5ceSopenharmony_ci if (lws_genhash_update(ctx, input, ilen)) 209d4afb5ceSopenharmony_ci return 1; 210d4afb5ceSopenharmony_ci 211d4afb5ceSopenharmony_ci return 0; 212d4afb5ceSopenharmony_ci} 213d4afb5ceSopenharmony_ci 214d4afb5ceSopenharmony_cistatic int 215d4afb5ceSopenharmony_cikex_ecdh_dv(uint8_t *dest, int dest_len, const uint8_t *kbi, int kbi_len, 216d4afb5ceSopenharmony_ci const uint8_t *H, char c, const uint8_t *session_id) 217d4afb5ceSopenharmony_ci{ 218d4afb5ceSopenharmony_ci uint8_t pool[LWS_SIZE_SHA256]; 219d4afb5ceSopenharmony_ci struct lws_genhash_ctx ctx; 220d4afb5ceSopenharmony_ci int n = 0, m; 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci /* 223d4afb5ceSopenharmony_ci * Key data MUST be taken from the beginning of the hash output. 224d4afb5ceSopenharmony_ci * As many bytes as needed are taken from the beginning of the hash 225d4afb5ceSopenharmony_ci * value. 226d4afb5ceSopenharmony_ci * 227d4afb5ceSopenharmony_ci * If the key length needed is longer than the output of the HASH, 228d4afb5ceSopenharmony_ci * the key is extended by computing HASH of the concatenation of K 229d4afb5ceSopenharmony_ci * and H and the entire key so far, and appending the resulting 230d4afb5ceSopenharmony_ci * bytes (as many as HASH generates) to the key. This process is 231d4afb5ceSopenharmony_ci * repeated until enough key material is available; the key is taken 232d4afb5ceSopenharmony_ci * from the beginning of this value. In other words: 233d4afb5ceSopenharmony_ci * 234d4afb5ceSopenharmony_ci * K1 = HASH(K || H || X || session_id) (X is e.g., "A") 235d4afb5ceSopenharmony_ci * K2 = HASH(K || H || K1) 236d4afb5ceSopenharmony_ci * K3 = HASH(K || H || K1 || K2) 237d4afb5ceSopenharmony_ci * ... 238d4afb5ceSopenharmony_ci * key = K1 || K2 || K3 || ... 239d4afb5ceSopenharmony_ci */ 240d4afb5ceSopenharmony_ci 241d4afb5ceSopenharmony_ci while (n < dest_len) { 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci if (lws_genhash_init(&ctx, LWS_GENHASH_TYPE_SHA256)) 244d4afb5ceSopenharmony_ci return 1; 245d4afb5ceSopenharmony_ci 246d4afb5ceSopenharmony_ci if (lws_genhash_update(&ctx, kbi, (unsigned int)kbi_len)) 247d4afb5ceSopenharmony_ci goto hash_failed; 248d4afb5ceSopenharmony_ci if (lws_genhash_update(&ctx, H, LWS_SIZE_SHA256)) 249d4afb5ceSopenharmony_ci goto hash_failed; 250d4afb5ceSopenharmony_ci 251d4afb5ceSopenharmony_ci if (!n) { 252d4afb5ceSopenharmony_ci if (lws_genhash_update(&ctx, (void *)&c, 1)) 253d4afb5ceSopenharmony_ci goto hash_failed; 254d4afb5ceSopenharmony_ci if (lws_genhash_update(&ctx, session_id, 255d4afb5ceSopenharmony_ci LWS_SIZE_EC25519)) 256d4afb5ceSopenharmony_ci goto hash_failed; 257d4afb5ceSopenharmony_ci } else 258d4afb5ceSopenharmony_ci if (lws_genhash_update(&ctx, pool, LWS_SIZE_EC25519)) 259d4afb5ceSopenharmony_ci goto hash_failed; 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci lws_genhash_destroy(&ctx, pool); 262d4afb5ceSopenharmony_ci 263d4afb5ceSopenharmony_ci m = LWS_SIZE_EC25519; 264d4afb5ceSopenharmony_ci if (m > (dest_len - n)) 265d4afb5ceSopenharmony_ci m = dest_len - n; 266d4afb5ceSopenharmony_ci 267d4afb5ceSopenharmony_ci memcpy(dest, pool, (unsigned int)m); 268d4afb5ceSopenharmony_ci n += m; 269d4afb5ceSopenharmony_ci dest += m; 270d4afb5ceSopenharmony_ci } 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci return 0; 273d4afb5ceSopenharmony_ci 274d4afb5ceSopenharmony_cihash_failed: 275d4afb5ceSopenharmony_ci lws_genhash_destroy(&ctx, NULL); 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_ci return 1; 278d4afb5ceSopenharmony_ci} 279d4afb5ceSopenharmony_ci 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_cistatic const unsigned char basepoint[32] = { 9 }; 282d4afb5ceSopenharmony_ci 283d4afb5ceSopenharmony_cisize_t 284d4afb5ceSopenharmony_ciget_gen_server_key_25519(struct per_session_data__sshd *pss, uint8_t *b, 285d4afb5ceSopenharmony_ci size_t len) 286d4afb5ceSopenharmony_ci{ 287d4afb5ceSopenharmony_ci size_t s, mylen; 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci mylen = pss->vhd->ops->get_server_key(pss->wsi, b, len); 290d4afb5ceSopenharmony_ci if (mylen) 291d4afb5ceSopenharmony_ci return mylen; 292d4afb5ceSopenharmony_ci 293d4afb5ceSopenharmony_ci /* create one then */ 294d4afb5ceSopenharmony_ci lwsl_notice("Generating server hostkey\n"); 295d4afb5ceSopenharmony_ci s = lws_gen_server_key_ed25519(pss->vhd->context, b, len); 296d4afb5ceSopenharmony_ci lwsl_notice(" gen key len %ld\n", (long)s); 297d4afb5ceSopenharmony_ci if (!s) 298d4afb5ceSopenharmony_ci return 0; 299d4afb5ceSopenharmony_ci /* set the key */ 300d4afb5ceSopenharmony_ci if (!pss->vhd->ops->set_server_key(pss->wsi, b, s)) 301d4afb5ceSopenharmony_ci return 0; 302d4afb5ceSopenharmony_ci 303d4afb5ceSopenharmony_ci /* new key stored OK */ 304d4afb5ceSopenharmony_ci 305d4afb5ceSopenharmony_ci return s; 306d4afb5ceSopenharmony_ci} 307d4afb5ceSopenharmony_ci 308d4afb5ceSopenharmony_ciint 309d4afb5ceSopenharmony_cikex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen) 310d4afb5ceSopenharmony_ci{ 311d4afb5ceSopenharmony_ci uint8_t pri_key[64], temp[64], payload_sig[64 + 32], a, *lp, kbi[64]; 312d4afb5ceSopenharmony_ci struct lws_kex *kex = pss->kex; 313d4afb5ceSopenharmony_ci struct lws_genhash_ctx ctx; 314d4afb5ceSopenharmony_ci unsigned long long smlen; 315d4afb5ceSopenharmony_ci uint8_t *p = reply + 5; 316d4afb5ceSopenharmony_ci uint32_t be, kbi_len; 317d4afb5ceSopenharmony_ci uint8_t servkey[256]; 318d4afb5ceSopenharmony_ci char keyt[33]; 319d4afb5ceSopenharmony_ci int r, c; 320d4afb5ceSopenharmony_ci 321d4afb5ceSopenharmony_ci r = (int)get_gen_server_key_25519(pss, servkey, (int)sizeof(servkey)); 322d4afb5ceSopenharmony_ci if (!r) { 323d4afb5ceSopenharmony_ci lwsl_err("%s: Failed to get or gen server key\n", __func__); 324d4afb5ceSopenharmony_ci 325d4afb5ceSopenharmony_ci return 1; 326d4afb5ceSopenharmony_ci } 327d4afb5ceSopenharmony_ci 328d4afb5ceSopenharmony_ci r = ed25519_key_parse(servkey, (unsigned int)r, keyt, sizeof(keyt), 329d4afb5ceSopenharmony_ci pss->K_S /* public key */, pri_key); 330d4afb5ceSopenharmony_ci if (r) { 331d4afb5ceSopenharmony_ci lwsl_notice("%s: server key parse failed: %d\n", __func__, r); 332d4afb5ceSopenharmony_ci 333d4afb5ceSopenharmony_ci return 1; 334d4afb5ceSopenharmony_ci } 335d4afb5ceSopenharmony_ci keyt[32] = '\0'; 336d4afb5ceSopenharmony_ci 337d4afb5ceSopenharmony_ci lwsl_info("Server key type: %s\n", keyt); 338d4afb5ceSopenharmony_ci 339d4afb5ceSopenharmony_ci /* 340d4afb5ceSopenharmony_ci * 1) Generate ephemeral key pair [ eph_pri_key | kex->Q_S ] 341d4afb5ceSopenharmony_ci * 2) Compute shared secret. 342d4afb5ceSopenharmony_ci * 3) Generate and sign exchange hash. 343d4afb5ceSopenharmony_ci * 344d4afb5ceSopenharmony_ci * 1) A 32 bytes private key should be generated for each new 345d4afb5ceSopenharmony_ci * connection, using a secure PRNG. The following actions 346d4afb5ceSopenharmony_ci * must be done on the private key: 347d4afb5ceSopenharmony_ci * 348d4afb5ceSopenharmony_ci * mysecret[0] &= 248; 349d4afb5ceSopenharmony_ci * mysecret[31] &= 127; 350d4afb5ceSopenharmony_ci * mysecret[31] |= 64; 351d4afb5ceSopenharmony_ci */ 352d4afb5ceSopenharmony_ci lws_get_random(pss->vhd->context, kex->eph_pri_key, LWS_SIZE_EC25519); 353d4afb5ceSopenharmony_ci kex->eph_pri_key[0] &= 248; 354d4afb5ceSopenharmony_ci kex->eph_pri_key[31] &= 127; 355d4afb5ceSopenharmony_ci kex->eph_pri_key[31] |= 64; 356d4afb5ceSopenharmony_ci 357d4afb5ceSopenharmony_ci /* 358d4afb5ceSopenharmony_ci * 2) The public key is calculated using the cryptographic scalar 359d4afb5ceSopenharmony_ci * multiplication: 360d4afb5ceSopenharmony_ci * 361d4afb5ceSopenharmony_ci * const unsigned char privkey[32]; 362d4afb5ceSopenharmony_ci * unsigned char pubkey[32]; 363d4afb5ceSopenharmony_ci * 364d4afb5ceSopenharmony_ci * crypto_scalarmult (pubkey, privkey, basepoint); 365d4afb5ceSopenharmony_ci */ 366d4afb5ceSopenharmony_ci crypto_scalarmult_curve25519(kex->Q_S, kex->eph_pri_key, basepoint); 367d4afb5ceSopenharmony_ci 368d4afb5ceSopenharmony_ci a = 0; 369d4afb5ceSopenharmony_ci for (r = 0; r < (int)sizeof(kex->Q_S); r++) 370d4afb5ceSopenharmony_ci a |= kex->Q_S[r]; 371d4afb5ceSopenharmony_ci if (!a) { 372d4afb5ceSopenharmony_ci lwsl_notice("all zero pubkey\n"); 373d4afb5ceSopenharmony_ci return SSH_DISCONNECT_KEY_EXCHANGE_FAILED; 374d4afb5ceSopenharmony_ci } 375d4afb5ceSopenharmony_ci 376d4afb5ceSopenharmony_ci /* 377d4afb5ceSopenharmony_ci * The shared secret, k, is defined in SSH specifications to be a big 378d4afb5ceSopenharmony_ci * integer. This number is calculated using the following procedure: 379d4afb5ceSopenharmony_ci * 380d4afb5ceSopenharmony_ci * X is the 32 bytes point obtained by the scalar multiplication of 381d4afb5ceSopenharmony_ci * the other side's public key and the local private key scalar. 382d4afb5ceSopenharmony_ci */ 383d4afb5ceSopenharmony_ci crypto_scalarmult_curve25519(pss->K, kex->eph_pri_key, kex->Q_C); 384d4afb5ceSopenharmony_ci 385d4afb5ceSopenharmony_ci /* 386d4afb5ceSopenharmony_ci * The whole 32 bytes of the number X are then converted into a big 387d4afb5ceSopenharmony_ci * integer k. This conversion follows the network byte order. This 388d4afb5ceSopenharmony_ci * step differs from RFC5656. 389d4afb5ceSopenharmony_ci */ 390d4afb5ceSopenharmony_ci kbi_len = (uint32_t)lws_mpint_rfc4251(kbi, pss->K, LWS_SIZE_EC25519, 1); 391d4afb5ceSopenharmony_ci 392d4afb5ceSopenharmony_ci /* 393d4afb5ceSopenharmony_ci * The exchange hash H is computed as the hash of the concatenation of 394d4afb5ceSopenharmony_ci * the following: 395d4afb5ceSopenharmony_ci * 396d4afb5ceSopenharmony_ci * string V_C, the client's identification string (CR and LF 397d4afb5ceSopenharmony_ci * excluded) 398d4afb5ceSopenharmony_ci * string V_S, the server's identification string (CR and LF 399d4afb5ceSopenharmony_ci * excluded) 400d4afb5ceSopenharmony_ci * string I_C, the payload of the client's SSH_MSG_KEXINIT 401d4afb5ceSopenharmony_ci * string I_S, the payload of the server's SSH_MSG_KEXINIT 402d4afb5ceSopenharmony_ci * string K_S, the host key 403d4afb5ceSopenharmony_ci * mpint Q_C, exchange value sent by the client 404d4afb5ceSopenharmony_ci * mpint Q_S, exchange value sent by the server 405d4afb5ceSopenharmony_ci * mpint K, the shared secret 406d4afb5ceSopenharmony_ci * 407d4afb5ceSopenharmony_ci * However there are a lot of unwritten details in the hash 408d4afb5ceSopenharmony_ci * definition... 409d4afb5ceSopenharmony_ci */ 410d4afb5ceSopenharmony_ci 411d4afb5ceSopenharmony_ci if (lws_genhash_init(&ctx, LWS_GENHASH_TYPE_SHA256)) { 412d4afb5ceSopenharmony_ci lwsl_notice("genhash init failed\n"); 413d4afb5ceSopenharmony_ci return 1; 414d4afb5ceSopenharmony_ci } 415d4afb5ceSopenharmony_ci 416d4afb5ceSopenharmony_ci if (_genhash_update_len(&ctx, pss->V_C, strlen(pss->V_C))) 417d4afb5ceSopenharmony_ci goto hash_probs; 418d4afb5ceSopenharmony_ci if (_genhash_update_len(&ctx, pss->vhd->ops->server_string, /* aka V_S */ 419d4afb5ceSopenharmony_ci strlen(pss->vhd->ops->server_string))) 420d4afb5ceSopenharmony_ci goto hash_probs; 421d4afb5ceSopenharmony_ci if (_genhash_update_len(&ctx, kex->I_C, kex->I_C_payload_len)) 422d4afb5ceSopenharmony_ci goto hash_probs; 423d4afb5ceSopenharmony_ci if (_genhash_update_len(&ctx, kex->I_S, kex->I_S_payload_len)) 424d4afb5ceSopenharmony_ci goto hash_probs; 425d4afb5ceSopenharmony_ci /* 426d4afb5ceSopenharmony_ci * K_S (host public key) 427d4afb5ceSopenharmony_ci * 428d4afb5ceSopenharmony_ci * sum of name + key lengths and headers 429d4afb5ceSopenharmony_ci * name length: name 430d4afb5ceSopenharmony_ci * key length: key 431d4afb5ceSopenharmony_ci * ---> */ 432d4afb5ceSopenharmony_ci lws_p32((uint8_t *)&be, (uint32_t)(8 + (int)strlen(keyt) + LWS_SIZE_EC25519)); 433d4afb5ceSopenharmony_ci if (lws_genhash_update(&ctx, (void *)&be, 4)) 434d4afb5ceSopenharmony_ci goto hash_probs; 435d4afb5ceSopenharmony_ci 436d4afb5ceSopenharmony_ci if (_genhash_update_len(&ctx, keyt, strlen(keyt))) 437d4afb5ceSopenharmony_ci goto hash_probs; 438d4afb5ceSopenharmony_ci if (_genhash_update_len(&ctx, pss->K_S, LWS_SIZE_EC25519)) 439d4afb5ceSopenharmony_ci goto hash_probs; 440d4afb5ceSopenharmony_ci /* <---- */ 441d4afb5ceSopenharmony_ci 442d4afb5ceSopenharmony_ci if (_genhash_update_len(&ctx, kex->Q_C, LWS_SIZE_EC25519)) 443d4afb5ceSopenharmony_ci goto hash_probs; 444d4afb5ceSopenharmony_ci if (_genhash_update_len(&ctx, kex->Q_S, LWS_SIZE_EC25519)) 445d4afb5ceSopenharmony_ci goto hash_probs; 446d4afb5ceSopenharmony_ci 447d4afb5ceSopenharmony_ci if (lws_genhash_update(&ctx, kbi, kbi_len)) 448d4afb5ceSopenharmony_ci goto hash_probs; 449d4afb5ceSopenharmony_ci 450d4afb5ceSopenharmony_ci if (lws_genhash_destroy(&ctx, temp)) 451d4afb5ceSopenharmony_ci goto hash_probs; 452d4afb5ceSopenharmony_ci 453d4afb5ceSopenharmony_ci /* 454d4afb5ceSopenharmony_ci * Sign the 32-byte SHA256 "exchange hash" in temp 455d4afb5ceSopenharmony_ci * The signature is itself 64 bytes 456d4afb5ceSopenharmony_ci */ 457d4afb5ceSopenharmony_ci smlen = LWS_SIZE_EC25519 + 64; 458d4afb5ceSopenharmony_ci if (crypto_sign_ed25519(payload_sig, &smlen, temp, LWS_SIZE_EC25519, 459d4afb5ceSopenharmony_ci pri_key)) 460d4afb5ceSopenharmony_ci return 1; 461d4afb5ceSopenharmony_ci 462d4afb5ceSopenharmony_ci#if 0 463d4afb5ceSopenharmony_ci l = LWS_SIZE_EC25519; 464d4afb5ceSopenharmony_ci n = crypto_sign_ed25519_open(temp, &l, payload_sig, smlen, pss->K_S); 465d4afb5ceSopenharmony_ci 466d4afb5ceSopenharmony_ci lwsl_notice("own sig sanity check says %d\n", n); 467d4afb5ceSopenharmony_ci#endif 468d4afb5ceSopenharmony_ci 469d4afb5ceSopenharmony_ci /* sig [64] and payload [32] concatenated in payload_sig 470d4afb5ceSopenharmony_ci * 471d4afb5ceSopenharmony_ci * The server then responds with the following 472d4afb5ceSopenharmony_ci * 473d4afb5ceSopenharmony_ci * uint32 packet length (exl self + mac) 474d4afb5ceSopenharmony_ci * byte padding len 475d4afb5ceSopenharmony_ci * byte SSH_MSG_KEX_ECDH_REPLY 476d4afb5ceSopenharmony_ci * string server public host key and certificates (K_S) 477d4afb5ceSopenharmony_ci * string Q_S (exchange value sent by the server) 478d4afb5ceSopenharmony_ci * string signature of H 479d4afb5ceSopenharmony_ci * padding 480d4afb5ceSopenharmony_ci */ 481d4afb5ceSopenharmony_ci *p++ = SSH_MSG_KEX_ECDH_REPLY; 482d4afb5ceSopenharmony_ci 483d4afb5ceSopenharmony_ci /* server public host key and certificates (K_S) */ 484d4afb5ceSopenharmony_ci 485d4afb5ceSopenharmony_ci lp = p; 486d4afb5ceSopenharmony_ci p +=4; 487d4afb5ceSopenharmony_ci lws_sized_blob(&p, keyt, (uint32_t)strlen(keyt)); 488d4afb5ceSopenharmony_ci lws_sized_blob(&p, pss->K_S, LWS_SIZE_EC25519); 489d4afb5ceSopenharmony_ci lws_p32(lp, (uint32_t)(lws_ptr_diff(p, lp) - 4)); 490d4afb5ceSopenharmony_ci 491d4afb5ceSopenharmony_ci /* Q_S (exchange value sent by the server) */ 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci lws_sized_blob(&p, kex->Q_S, LWS_SIZE_EC25519); 494d4afb5ceSopenharmony_ci 495d4afb5ceSopenharmony_ci /* signature of H */ 496d4afb5ceSopenharmony_ci 497d4afb5ceSopenharmony_ci lp = p; 498d4afb5ceSopenharmony_ci p +=4; 499d4afb5ceSopenharmony_ci lws_sized_blob(&p, keyt, (uint32_t)strlen(keyt)); 500d4afb5ceSopenharmony_ci lws_sized_blob(&p, payload_sig, 64); 501d4afb5ceSopenharmony_ci lws_p32(lp, (uint32_t)(lws_ptr_diff(p, lp) - 4)); 502d4afb5ceSopenharmony_ci 503d4afb5ceSopenharmony_ci /* end of message */ 504d4afb5ceSopenharmony_ci 505d4afb5ceSopenharmony_ci lws_pad_set_length(pss, reply, &p, &pss->active_keys_stc); 506d4afb5ceSopenharmony_ci *plen = (uint32_t)lws_ptr_diff(p, reply); 507d4afb5ceSopenharmony_ci 508d4afb5ceSopenharmony_ci if (!pss->active_keys_stc.valid) 509d4afb5ceSopenharmony_ci memcpy(pss->session_id, temp, LWS_SIZE_EC25519); 510d4afb5ceSopenharmony_ci 511d4afb5ceSopenharmony_ci /* RFC4253 7.2: 512d4afb5ceSopenharmony_ci * 513d4afb5ceSopenharmony_ci * The key exchange produces two values: a shared secret K, 514d4afb5ceSopenharmony_ci * and an exchange hash H. Encryption and authentication 515d4afb5ceSopenharmony_ci * keys are derived from these. The exchange hash H from the 516d4afb5ceSopenharmony_ci * first key exchange is additionally used as the session 517d4afb5ceSopenharmony_ci * identifier, which is a unique identifier for this connection. 518d4afb5ceSopenharmony_ci * It is used by authentication methods as a part of the data 519d4afb5ceSopenharmony_ci * that is signed as a proof of possession of a private key. 520d4afb5ceSopenharmony_ci * Once computed, the session identifier is not changed, 521d4afb5ceSopenharmony_ci * even if keys are later re-exchanged. 522d4afb5ceSopenharmony_ci * 523d4afb5ceSopenharmony_ci * The hash alg used in the KEX must be used for key derivation. 524d4afb5ceSopenharmony_ci * 525d4afb5ceSopenharmony_ci * 1) Initial IV client to server: 526d4afb5ceSopenharmony_ci * 527d4afb5ceSopenharmony_ci * HASH(K || H || "A" || session_id) 528d4afb5ceSopenharmony_ci * 529d4afb5ceSopenharmony_ci * (Here K is encoded as mpint and "A" as byte and session_id 530d4afb5ceSopenharmony_ci * as raw data. "A" means the single character A, ASCII 65). 531d4afb5ceSopenharmony_ci * 532d4afb5ceSopenharmony_ci * 533d4afb5ceSopenharmony_ci */ 534d4afb5ceSopenharmony_ci for (c = 0; c < 3; c++) { 535d4afb5ceSopenharmony_ci kex_ecdh_dv(kex->keys_next_cts.key[c], LWS_SIZE_CHACHA256_KEY, 536d4afb5ceSopenharmony_ci kbi, (int)kbi_len, temp, (char)('A' + (c * 2)), 537d4afb5ceSopenharmony_ci pss->session_id); 538d4afb5ceSopenharmony_ci kex_ecdh_dv(kex->keys_next_stc.key[c], LWS_SIZE_CHACHA256_KEY, 539d4afb5ceSopenharmony_ci kbi, (int)kbi_len, temp, (char)('B' + (c * 2)), 540d4afb5ceSopenharmony_ci pss->session_id); 541d4afb5ceSopenharmony_ci } 542d4afb5ceSopenharmony_ci 543d4afb5ceSopenharmony_ci lws_explicit_bzero(temp, sizeof(temp)); 544d4afb5ceSopenharmony_ci 545d4afb5ceSopenharmony_ci return 0; 546d4afb5ceSopenharmony_ci 547d4afb5ceSopenharmony_cihash_probs: 548d4afb5ceSopenharmony_ci lws_genhash_destroy(&ctx, NULL); 549d4afb5ceSopenharmony_ci 550d4afb5ceSopenharmony_ci return 1; 551d4afb5ceSopenharmony_ci} 552