int kex_send_kexinit(struct ssh *ssh) { u_char *cookie; Kex *kex = ssh->kex; int r; if (kex == NULL) return SSH_ERR_INTERNAL_ERROR; if (kex->flags & KEX_INIT_SENT) return 0; kex->done = 0; /* generate a random cookie */ if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) return SSH_ERR_INVALID_FORMAT; if ((cookie = sshbuf_ptr(kex->my)) == NULL) return SSH_ERR_INTERNAL_ERROR; arc4random_buf(cookie, KEX_COOKIE_LEN); if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0) return r; if ((r = sshpkt_put(ssh, sshbuf_ptr(kex->my), sshbuf_len(kex->my))) != 0) return r; if ((r = sshpkt_send(ssh)) != 0) return r; debug("SSH2_MSG_KEXINIT sent"); kex->flags |= KEX_INIT_SENT; return 0; }
/* * Wait until all buffered output has been sent to the client. * This is used when the program terminates. */ static void drain_output(struct ssh *ssh) { int r; /* Send any buffered stdout data to the client. */ if (sshbuf_len(stdout_buffer) > 0) { if ((r = sshpkt_start(ssh, SSH_SMSG_STDOUT_DATA)) != 0 || (r = sshpkt_put_string(ssh, sshbuf_ptr(stdout_buffer), sshbuf_len(stdout_buffer))) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); /* Update the count of sent bytes. */ stdout_bytes += sshbuf_len(stdout_buffer); } /* Send any buffered stderr data to the client. */ if (sshbuf_len(stderr_buffer) > 0) { if ((r = sshpkt_start(ssh, SSH_SMSG_STDERR_DATA)) != 0 || (r = sshpkt_put_string(ssh, sshbuf_ptr(stderr_buffer), sshbuf_len(stderr_buffer))) != 0 || (r = sshpkt_send(ssh)) != 0) /* Update the count of sent bytes. */ stderr_bytes += sshbuf_len(stderr_buffer); } /* Wait until all buffered data has been written to the client. */ ssh_packet_write_wait(ssh); }
int kex_c25519_dec(struct kex *kex, const struct sshbuf *server_blob, struct sshbuf **shared_secretp) { struct sshbuf *buf = NULL; const u_char *server_pub; int r; *shared_secretp = NULL; if (sshbuf_len(server_blob) != CURVE25519_SIZE) { r = SSH_ERR_SIGNATURE_INVALID; goto out; } server_pub = sshbuf_ptr(server_blob); #ifdef DEBUG_KEXECDH dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE); #endif /* shared secret */ if ((buf = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub, buf, 0)) < 0) goto out; #ifdef DEBUG_KEXECDH dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); #endif *shared_secretp = buf; buf = NULL; out: sshbuf_free(buf); return r; }
int kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob, struct sshbuf **server_blobp, struct sshbuf **shared_secretp) { struct sshbuf *server_blob = NULL; struct sshbuf *buf = NULL; const u_char *client_pub; u_char *server_pub; u_char server_key[CURVE25519_SIZE]; int r; *server_blobp = NULL; *shared_secretp = NULL; if (sshbuf_len(client_blob) != CURVE25519_SIZE) { r = SSH_ERR_SIGNATURE_INVALID; goto out; } client_pub = sshbuf_ptr(client_blob); #ifdef DEBUG_KEXECDH dump_digest("client public key 25519:", client_pub, CURVE25519_SIZE); #endif /* allocate space for encrypted KEM key and ECDH pub key */ if ((server_blob = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0) goto out; kexc25519_keygen(server_key, server_pub); /* allocate shared secret */ if ((buf = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 0)) < 0) goto out; #ifdef DEBUG_KEXECDH dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE); dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); #endif *server_blobp = server_blob; *shared_secretp = buf; server_blob = NULL; buf = NULL; out: explicit_bzero(server_key, sizeof(server_key)); sshbuf_free(server_blob); sshbuf_free(buf); return r; }
int sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp, size_t *lenp) { u_int32_t len; const u_char *p = sshbuf_ptr(buf); if (valp != NULL) *valp = NULL; if (lenp != NULL) *lenp = 0; if (sshbuf_len(buf) < 4) { SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE")); return SSH_ERR_MESSAGE_INCOMPLETE; } len = PEEK_U32(p); if (len > SSHBUF_SIZE_MAX - 4) { SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE")); return SSH_ERR_STRING_TOO_LARGE; } if (sshbuf_len(buf) - 4 < len) { SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE")); return SSH_ERR_MESSAGE_INCOMPLETE; } if (valp != 0) *valp = p + 4; if (lenp != NULL) *lenp = len; return 0; }
int sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp) { u_int32_t len; const u_char *p = sshbuf_ptr(buf), *z; int r; if (sshbuf_len(buf) < 4) { SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE")); return SSH_ERR_MESSAGE_INCOMPLETE; } len = PEEK_U32(p); if (sshbuf_len(buf) < (size_t)len + 4) { SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE")); return SSH_ERR_MESSAGE_INCOMPLETE; } /* Allow a \0 only at the end of the string */ if ((z = memchr(p + 4, '\0', len)) != NULL && z < p + 4 + len - 1) { SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT")); return SSH_ERR_INVALID_FORMAT; } if ((r = sshbuf_consume(buf, 4 + (size_t)len)) < 0) return -1; if (valp != NULL) { if ((*valp = malloc(len + 1)) == NULL) { SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); return SSH_ERR_ALLOC_FAIL; } memcpy(*valp, p + 4, len); (*valp)[len] = '\0'; } if (lenp != NULL) *lenp = (size_t)len; return 0; }
static char * authmethods_get(struct authctxt *authctxt) { struct sshbuf *b; char *list; int i, r; if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); for (i = 0; authmethods[i] != NULL; i++) { if (strcmp(authmethods[i]->name, "none") == 0) continue; if (authmethods[i]->enabled == NULL || *(authmethods[i]->enabled) == 0) continue; if (!auth2_method_allowed(authctxt, authmethods[i]->name, NULL)) continue; if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) ? "," : "", authmethods[i]->name)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } if ((r = sshbuf_put_u8(b, 0)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); list = xstrdup((const char *)sshbuf_ptr(b)); sshbuf_free(b); return list; }
int sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v) { const u_char *d = sshbuf_ptr(buf); u_int16_t len_bits; size_t len_bytes; /* Length in bits */ if (sshbuf_len(buf) < 2) return SSH_ERR_MESSAGE_INCOMPLETE; len_bits = PEEK_U16(d); len_bytes = (len_bits + 7) >> 3; if (len_bytes > SSHBUF_MAX_BIGNUM) return SSH_ERR_BIGNUM_TOO_LARGE; if (sshbuf_len(buf) < 2 + len_bytes) return SSH_ERR_MESSAGE_INCOMPLETE; if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL) return SSH_ERR_ALLOC_FAIL; if (sshbuf_consume(buf, 2 + len_bytes) != 0) { SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); SSHBUF_ABORT(); return SSH_ERR_INTERNAL_ERROR; } return 0; }
static void public_fuzz(struct sshkey *k) { struct sshkey *k1; struct sshbuf *buf; struct fuzz *fuzz; u_int fuzzers = FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP | FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END; if (test_is_fast()) fuzzers &= ~FUZZ_1_BIT_FLIP; if (test_is_slow()) fuzzers |= FUZZ_2_BIT_FLIP | FUZZ_2_BYTE_FLIP; ASSERT_PTR_NE(buf = sshbuf_new(), NULL); ASSERT_INT_EQ(sshkey_putb(k, buf), 0); fuzz = fuzz_begin(fuzzers, sshbuf_mutable_ptr(buf), sshbuf_len(buf)); ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(buf), sshbuf_len(buf), &k1), 0); sshkey_free(k1); sshbuf_free(buf); TEST_ONERROR(onerror, fuzz); for(; !fuzz_done(fuzz); fuzz_next(fuzz)) { if (sshkey_from_blob(fuzz_ptr(fuzz), fuzz_len(fuzz), &k1) == 0) sshkey_free(k1); } fuzz_cleanup(fuzz); }
static struct kbdintctxt * kbdint_alloc(const char *devs) { struct kbdintctxt *kbdintctxt; struct sshbuf *b; int i, r; kbdintctxt = xcalloc(1, sizeof(struct kbdintctxt)); if (strcmp(devs, "") == 0) { if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); for (i = 0; devices[i]; i++) { if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) ? "," : "", devices[i]->name)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } if ((r = sshbuf_put_u8(b, 0)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); kbdintctxt->devices = xstrdup((const char *)sshbuf_ptr(b)); sshbuf_free(b); } else { kbdintctxt->devices = xstrdup(devs); } debug("kbdint_alloc: devices '%s'", kbdintctxt->devices); kbdintctxt->ctxt = NULL; kbdintctxt->device = NULL; kbdintctxt->nreq = 0; return kbdintctxt; }
static void build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, const struct sshkey *sign_key, const struct sshkey *ca_key, const char *sig_alg) { struct sshbuf *ca_buf, *pk, *principals, *critopts, *exts; u_char *sigblob; size_t siglen; ca_buf = sshbuf_new(); ASSERT_PTR_NE(ca_buf, NULL); ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0); /* * Get the public key serialisation by rendering the key and skipping * the type string. This is a bit of a hack :/ */ pk = sshbuf_new(); ASSERT_PTR_NE(pk, NULL); ASSERT_INT_EQ(sshkey_putb_plain(k, pk), 0); ASSERT_INT_EQ(sshbuf_skip_string(pk), 0); principals = sshbuf_new(); ASSERT_PTR_NE(principals, NULL); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0); critopts = sshbuf_new(); ASSERT_PTR_NE(critopts, NULL); put_opt(critopts, "force-command", "/usr/local/bin/nethack"); put_opt(critopts, "source-address", "192.168.0.0/24,127.0.0.1,::1"); exts = sshbuf_new(); ASSERT_PTR_NE(exts, NULL); put_opt(critopts, "permit-X11-forwarding", NULL); ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0); ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */ ASSERT_INT_EQ(sshbuf_putb(b, pk), 0); /* public key serialisation */ ASSERT_INT_EQ(sshbuf_put_u64(b, 1234), 0); /* serial */ ASSERT_INT_EQ(sshbuf_put_u32(b, SSH2_CERT_TYPE_USER), 0); /* type */ ASSERT_INT_EQ(sshbuf_put_cstring(b, "gregor"), 0); /* key ID */ ASSERT_INT_EQ(sshbuf_put_stringb(b, principals), 0); /* principals */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0), 0); /* start */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0xffffffffffffffffULL), 0); /* end */ ASSERT_INT_EQ(sshbuf_put_stringb(b, critopts), 0); /* options */ ASSERT_INT_EQ(sshbuf_put_stringb(b, exts), 0); /* extensions */ ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, sshbuf_ptr(b), sshbuf_len(b), sig_alg, 0), 0); ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ free(sigblob); sshbuf_free(ca_buf); sshbuf_free(exts); sshbuf_free(critopts); sshbuf_free(principals); sshbuf_free(pk); }
/* * Make packets from buffered stdout data, and buffer it for sending to the * client. */ static void make_packets_from_stdout_data(struct ssh *ssh) { size_t len; int r; /* Send buffered stdout data to the client. */ while (sshbuf_len(stdout_buffer) > 0 && ssh_packet_not_very_much_data_to_write(ssh)) { len = sshbuf_len(stdout_buffer); if (ssh_packet_is_interactive(ssh)) { if (len > 512) len = 512; } else { /* Keep the packets at reasonable size. */ if (len > ssh_packet_get_maxsize(ssh)) len = ssh_packet_get_maxsize(ssh); } if ((r = sshpkt_start(ssh, SSH_SMSG_STDOUT_DATA)) != 0 || (r = sshpkt_put_string(ssh, sshbuf_ptr(stdout_buffer), len)) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); if ((r = sshbuf_consume(stdout_buffer, len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); stdout_bytes += len; } }
/* Confirmation hash calculation */ void jpake_confirm_hash(const BIGNUM *k, const u_char *endpoint_id, u_int endpoint_id_len, const u_char *sess_id, u_int sess_id_len, u_char **confirm_hash, u_int *confirm_hash_len) { struct sshbuf *b; int r; /* * Calculate confirmation proof: * client: H(k || client_id || session_id) * server: H(k || server_id || session_id) */ if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_bignum2(b, k)) != 0 || (r = sshbuf_put_string(b, endpoint_id, endpoint_id_len)) != 0 || (r = sshbuf_put_string(b, sess_id, sess_id_len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (hash_buffer(sshbuf_ptr(b), sshbuf_len(b), EVP_sha256(), confirm_hash, confirm_hash_len) != 0) fatal("%s: hash_buffer", __func__); sshbuf_free(b); }
static void public_fuzz(struct sshkey *k) { struct sshkey *k1; struct sshbuf *buf; struct fuzz *fuzz; ASSERT_PTR_NE(buf = sshbuf_new(), NULL); ASSERT_INT_EQ(sshkey_to_blob_buf(k, buf), 0); /* XXX need a way to run the tests in "slow, but complete" mode */ fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | /* XXX too slow FUZZ_2_BIT_FLIP | */ FUZZ_1_BYTE_FLIP | /* XXX too slow FUZZ_2_BYTE_FLIP | */ FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, sshbuf_mutable_ptr(buf), sshbuf_len(buf)); ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(buf), sshbuf_len(buf), &k1), 0); sshkey_free(k1); sshbuf_free(buf); TEST_ONERROR(onerror, fuzz); for(; !fuzz_done(fuzz); fuzz_next(fuzz)) { if (sshkey_from_blob(fuzz_ptr(fuzz), fuzz_len(fuzz), &k1) == 0) sshkey_free(k1); } fuzz_cleanup(fuzz); }
/* * Caclulate a new key after a reconnect */ void calculate_new_key(u_int64_t *key, u_int64_t cookie, u_int64_t challenge) { int r; const EVP_MD *md = EVP_sha1(); EVP_MD_CTX ctx; char hash[EVP_MAX_MD_SIZE]; struct sshbuf *b; if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u64(b, *key)) != 0 || (r = sshbuf_put_u64(b, cookie)) != 0 || (r = sshbuf_put_u64(b, challenge)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, sshbuf_ptr(b), sshbuf_len(b)); EVP_DigestFinal(&ctx, hash, NULL); sshbuf_reset(b); if ((r = sshbuf_put(b, hash, EVP_MD_size(md))) != 0 || (r = sshbuf_get_u64(b, key)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); sshbuf_free(b); }
/* * Parse the public, unencrypted portion of a RSA1 key. */ int sshkey_parse_public_rsa1(struct sshbuf *blob, struct sshkey **keyp, char **commentp) { int r; struct sshkey *pub = NULL; struct sshbuf *copy = NULL; *keyp = NULL; if (commentp != NULL) *commentp = NULL; /* Check that it is at least big enough to contain the ID string. */ if (sshbuf_len(blob) < sizeof(authfile_id_string)) return SSH_ERR_INVALID_FORMAT; /* * Make sure it begins with the id string. Consume the id string * from the buffer. */ if (memcmp(sshbuf_ptr(blob), authfile_id_string, sizeof(authfile_id_string)) != 0) return SSH_ERR_INVALID_FORMAT; /* Make a working copy of the keyblob and skip past the magic */ if ((copy = sshbuf_fromb(blob)) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_consume(copy, sizeof(authfile_id_string))) != 0) goto out; /* Skip cipher type, reserved data and key bits. */ if ((r = sshbuf_get_u8(copy, NULL)) != 0 || /* cipher type */ (r = sshbuf_get_u32(copy, NULL)) != 0 || /* reserved */ (r = sshbuf_get_u32(copy, NULL)) != 0) /* key bits */ goto out; /* Read the public key from the buffer. */ if ((pub = sshkey_new(KEY_RSA1)) == NULL || (r = sshbuf_get_bignum1(copy, pub->rsa->n)) != 0 || (r = sshbuf_get_bignum1(copy, pub->rsa->e)) != 0) goto out; /* Finally, the comment */ if ((r = sshbuf_get_string(copy, (u_char**)commentp, NULL)) != 0) goto out; /* The encrypted private part is not parsed by this function. */ r = 0; *keyp = pub; pub = NULL; out: if (copy != NULL) sshbuf_free(copy); if (pub != NULL) sshkey_free(pub); return r; }
int ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { u_char *sig = NULL; size_t slen = 0, len; unsigned long long smlen; int r, ret; struct sshbuf *b = NULL; if (lenp != NULL) *lenp = 0; if (sigp != NULL) *sigp = NULL; if (key == NULL || sshkey_type_plain(key->type) != KEY_ED25519 || key->ed25519_sk == NULL || datalen >= INT_MAX - crypto_sign_ed25519_BYTES) return SSH_ERR_INVALID_ARGUMENT; smlen = slen = datalen + crypto_sign_ed25519_BYTES; if ((sig = malloc(slen)) == NULL) return SSH_ERR_ALLOC_FAIL; if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, key->ed25519_sk)) != 0 || smlen <= datalen) { r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ goto out; } /* encode signature */ if ((b = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) goto out; len = sshbuf_len(b); if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sshbuf_ptr(b), len); } if (lenp != NULL) *lenp = len; /* success */ r = 0; out: sshbuf_free(b); if (sig != NULL) { explicit_bzero(sig, slen); free(sig); } return r; }
static int do_send_and_receive(struct ssh *from, struct ssh *to, int mydirection, int *packet_count, int trigger_direction, int packet_index, const char *dump_path, struct sshbuf *replace_data) { u_char type; size_t len, olen; const u_char *buf; int r; FILE *dumpfile; for (;;) { if ((r = ssh_packet_next(from, &type)) != 0) { fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r)); return r; } if (type != 0) return 0; buf = ssh_output_ptr(from, &len); olen = len; if (do_debug) { printf("%s packet %d type %u len %zu:\n", mydirection == S2C ? "s2c" : "c2s", *packet_count, type, len); sshbuf_dump_data(buf, len, stdout); } if (mydirection == trigger_direction && packet_index == *packet_count) { if (replace_data != NULL) { buf = sshbuf_ptr(replace_data); len = sshbuf_len(replace_data); if (do_debug) { printf("***** replaced packet " "len %zu\n", len); sshbuf_dump_data(buf, len, stdout); } } else if (dump_path != NULL) { if ((dumpfile = fopen(dump_path, "w+")) == NULL) err(1, "fopen %s", dump_path); if (len != 0 && fwrite(buf, len, 1, dumpfile) != 1) err(1, "fwrite %s", dump_path); if (do_debug) printf("***** dumped packet " "len %zu\n", len); fclose(dumpfile); exit(0); } } (*packet_count)++; if (len == 0) return 0; if ((r = ssh_input_append(to, buf, len)) != 0 || (r = ssh_output_consume(from, olen)) != 0) return r; } }
int kex_ecdh_hash( const EVP_MD *evp_md, const EC_GROUP *ec_group, const char *client_version_string, const char *server_version_string, const u_char *ckexinit, size_t ckexinitlen, const u_char *skexinit, size_t skexinitlen, const u_char *serverhostkeyblob, size_t sbloblen, const EC_POINT *client_dh_pub, const EC_POINT *server_dh_pub, const BIGNUM *shared_secret, u_char **hash, size_t *hashlen) { struct sshbuf *b; EVP_MD_CTX md; static u_char digest[EVP_MAX_MD_SIZE]; int r; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 || (r = sshbuf_put_cstring(b, server_version_string)) != 0 || /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 || (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || (r = sshbuf_put_ec(b, client_dh_pub, ec_group)) != 0 || (r = sshbuf_put_ec(b, server_dh_pub, ec_group)) != 0 || (r = sshbuf_put_bignum2(b, shared_secret)) != 0) { sshbuf_free(b); return r; } #ifdef DEBUG_KEX sshbuf_dump(b, stderr); #endif if (EVP_DigestInit(&md, evp_md) != 1 || EVP_DigestUpdate(&md, sshbuf_ptr(b), sshbuf_len(b)) != 1 || EVP_DigestFinal(&md, digest, NULL) != 1) { sshbuf_free(b); return SSH_ERR_LIBCRYPTO_ERROR; } sshbuf_free(b); #ifdef DEBUG_KEX dump_digest("hash", digest, EVP_MD_size(evp_md)); #endif *hash = digest; *hashlen = EVP_MD_size(evp_md); return 0; }
BIGNUM * load_bignum(const char *name) { BIGNUM *ret = NULL; struct sshbuf *buf; buf = load_text_file(name); ASSERT_INT_NE(BN_hex2bn(&ret, (const char *)sshbuf_ptr(buf)), 0); sshbuf_free(buf); return ret; }
static void build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, const struct sshkey *sign_key, const struct sshkey *ca_key) { struct sshbuf *ca_buf, *pk, *principals, *critopts, *exts; u_char *sigblob; size_t siglen; ca_buf = sshbuf_new(); ASSERT_INT_EQ(sshkey_to_blob_buf(ca_key, ca_buf), 0); /* * Get the public key serialisation by rendering the key and skipping * the type string. This is a bit of a hack :/ */ pk = sshbuf_new(); ASSERT_INT_EQ(sshkey_plain_to_blob_buf(k, pk), 0); ASSERT_INT_EQ(sshbuf_skip_string(pk), 0); principals = sshbuf_new(); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0); critopts = sshbuf_new(); /* XXX fill this in */ exts = sshbuf_new(); /* XXX fill this in */ ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0); ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */ ASSERT_INT_EQ(sshbuf_putb(b, pk), 0); /* public key serialisation */ ASSERT_INT_EQ(sshbuf_put_u64(b, 1234), 0); /* serial */ ASSERT_INT_EQ(sshbuf_put_u32(b, SSH2_CERT_TYPE_USER), 0); /* type */ ASSERT_INT_EQ(sshbuf_put_cstring(b, "gregor"), 0); /* key ID */ ASSERT_INT_EQ(sshbuf_put_stringb(b, principals), 0); /* principals */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0), 0); /* start */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0xffffffffffffffffULL), 0); /* end */ ASSERT_INT_EQ(sshbuf_put_stringb(b, critopts), 0); /* options */ ASSERT_INT_EQ(sshbuf_put_stringb(b, exts), 0); /* extensions */ ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, sshbuf_ptr(b), sshbuf_len(b), 0), 0); ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ free(sigblob); sshbuf_free(ca_buf); sshbuf_free(exts); sshbuf_free(critopts); sshbuf_free(principals); sshbuf_free(pk); }
int sshbuf_get_u8(struct sshbuf *buf, u_char *valp) { const u_char *p = sshbuf_ptr(buf); int r; if ((r = sshbuf_consume(buf, 1)) < 0) return r; if (valp != NULL) *valp = (u_int8_t)*p; return 0; }
int sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp) { const u_char *p = sshbuf_ptr(buf); int r; if ((r = sshbuf_consume(buf, 2)) < 0) return r; if (valp != NULL) *valp = PEEK_U16(p); return 0; }
int sshbuf_get(struct sshbuf *buf, void *v, size_t len) { const u_char *p = sshbuf_ptr(buf); int r; if ((r = sshbuf_consume(buf, len)) < 0) return r; if (v != NULL) memcpy(v, p, len); return 0; }
/* * Derive fake salt as H(username || first_private_host_key) * This provides relatively stable fake salts for non-existent * users and avoids the jpake method becoming an account validity * oracle. */ static void derive_rawsalt(const char *username, u_char *rawsalt, u_int len) { u_char *digest; u_int digest_len; struct sshbuf *b; struct sshkey *k; int r; if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_cstring(b, username)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if ((k = get_hostkey_by_index(0)) == NULL || (k->flags & SSHKEY_FLAG_EXT)) fatal("%s: no hostkeys", __func__); switch (k->type) { case KEY_RSA1: case KEY_RSA: if (k->rsa->p == NULL || k->rsa->q == NULL) fatal("%s: RSA key missing p and/or q", __func__); if ((r = sshbuf_put_bignum2(b, k->rsa->p)) != 0 || (r = sshbuf_put_bignum2(b, k->rsa->q)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); break; case KEY_DSA: if (k->dsa->priv_key == NULL) fatal("%s: DSA key missing priv_key", __func__); if ((r = sshbuf_put_bignum2(b, k->dsa->priv_key)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); break; case KEY_ECDSA: if (EC_KEY_get0_private_key(k->ecdsa) == NULL) fatal("%s: ECDSA key missing priv_key", __func__); if ((r = sshbuf_put_bignum2(b, EC_KEY_get0_private_key(k->ecdsa))) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); break; default: fatal("%s: unknown key type %d", __func__, k->type); } if (hash_buffer(sshbuf_ptr(b), sshbuf_len(b), EVP_sha256(), &digest, &digest_len) != 0) fatal("%s: hash_buffer", __func__); sshbuf_free(b); if (len > digest_len) fatal("%s: not enough bytes for rawsalt (want %u have %u)", __func__, len, digest_len); memcpy(rawsalt, digest, len); bzero(digest, digest_len); xfree(digest); }
char * ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status, OM_uint32 *minor_status) { OM_uint32 lmin; gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; OM_uint32 ctx; struct sshbuf *b; char *ret; int r; if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if (major_status != NULL) *major_status = ctxt->major; if (minor_status != NULL) *minor_status = ctxt->minor; ctx = 0; /* The GSSAPI error */ do { gss_display_status(&lmin, ctxt->major, GSS_C_GSS_CODE, ctxt->oid, &ctx, &msg); if ((r = sshbuf_put(b, msg.value, msg.length)) != 0 || (r = sshbuf_put_u8(b, '\n')) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); gss_release_buffer(&lmin, &msg); } while (ctx != 0); /* The mechanism specific error */ do { gss_display_status(&lmin, ctxt->minor, GSS_C_MECH_CODE, ctxt->oid, &ctx, &msg); if ((r = sshbuf_put(b, msg.value, msg.length)) != 0 || (r = sshbuf_put_u8(b, '\n')) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); gss_release_buffer(&lmin, &msg); } while (ctx != 0); if ((r = sshbuf_put_u8(b, '\n')) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); ret = xstrdup((const char *)sshbuf_ptr(b)); sshbuf_free(b); return (ret); }
/* * Reassemble an argument vector into a string, quoting and escaping as * necessary. Caller must free returned string. */ static char * assemble_argv(int argc, char **argv) { int i, j, ws, r; char c, *ret; struct sshbuf *buf, *arg; if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); for (i = 0; i < argc; i++) { ws = 0; sshbuf_reset(arg); for (j = 0; argv[i][j] != '\0'; j++) { r = 0; c = argv[i][j]; switch (c) { case ' ': case '\t': ws = 1; r = sshbuf_put_u8(arg, c); break; case '\\': case '\'': case '"': if ((r = sshbuf_put_u8(arg, '\\')) != 0) break; /* FALLTHROUGH */ default: r = sshbuf_put_u8(arg, c); break; } if (r != 0) fatal("%s: sshbuf_put_u8: %s", __func__, ssh_err(r)); } if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) || (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) || (r = sshbuf_putb(buf, arg)) != 0 || (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0)) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL) fatal("%s: malloc failed", __func__); memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf)); ret[sshbuf_len(buf)] = '\0'; sshbuf_free(buf); sshbuf_free(arg); return ret; }
static void send_msg(struct sshbuf *m) { u_char buf[4]; size_t mlen = sshbuf_len(m); int r; POKE_U32(buf, mlen); if (atomicio(vwrite, fd, buf, 4) != 4 || atomicio(vwrite, fd, (u_char *)sshbuf_ptr(m), sshbuf_len(m)) != sshbuf_len(m)) error("write to helper failed"); if ((r = sshbuf_consume(m, mlen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); }
struct sshbuf * sshbuf_fromb(struct sshbuf *buf) { struct sshbuf *ret; if (sshbuf_check_sanity(buf) != 0) return NULL; if ((ret = sshbuf_from(sshbuf_ptr(buf), sshbuf_len(buf))) == NULL) return NULL; if (sshbuf_set_parent(ret, buf) != 0) { sshbuf_free(ret); return NULL; } return ret; }
int kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, const BIGNUM *secret) { struct sshbuf *shared_secret; int r; if ((shared_secret = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) { r = kex_derive_keys(ssh, hash, hashlen, sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)); } sshbuf_free(shared_secret); return r; }