static int deserialise_array(struct sshbuf *m, char ***ap, size_t *np) { char **a = NULL; size_t i, n = 0; struct sshbuf *b = NULL; u_int tmp; int r = SSH_ERR_INTERNAL_ERROR; if ((r = sshbuf_get_u32(m, &tmp)) != 0 || (r = sshbuf_froms(m, &b)) != 0) goto out; if (tmp > INT_MAX) { r = SSH_ERR_INVALID_FORMAT; goto out; } n = tmp; if (n > 0 && (a = calloc(n, sizeof(*a))) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } for (i = 0; i < n; i++) { if ((r = sshbuf_get_cstring(b, &a[i], NULL)) != 0) goto out; } /* success */ r = 0; *ap = a; a = NULL; *np = n; n = 0; out: for (i = 0; i < n; i++) free(a[i]); free(a); sshbuf_free(b); return r; }
static int parse_option_list(struct sshbuf *oblob, struct passwd *pw, u_int which, int crit, int *cert_no_port_forwarding_flag, int *cert_no_agent_forwarding_flag, int *cert_no_x11_forwarding_flag, int *cert_no_pty_flag, int *cert_no_user_rc, char **cert_forced_command, int *cert_source_address_done) { struct ssh *ssh = active_state; /* XXX */ char *command, *allowed; const char *remote_ip; char *name = NULL; struct sshbuf *c = NULL, *data = NULL; int r, ret = -1, result, found; if ((c = sshbuf_fromb(oblob)) == NULL) { error("%s: sshbuf_fromb failed", __func__); goto out; } while (sshbuf_len(c) > 0) { sshbuf_free(data); data = NULL; if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 || (r = sshbuf_froms(c, &data)) != 0) { error("Unable to parse certificate options: %s", ssh_err(r)); goto out; } debug3("found certificate option \"%.100s\" len %zu", name, sshbuf_len(data)); found = 0; if ((which & OPTIONS_EXTENSIONS) != 0) { if (strcmp(name, "permit-X11-forwarding") == 0) { *cert_no_x11_forwarding_flag = 0; found = 1; } else if (strcmp(name, "permit-agent-forwarding") == 0) { *cert_no_agent_forwarding_flag = 0; found = 1; } else if (strcmp(name, "permit-port-forwarding") == 0) { *cert_no_port_forwarding_flag = 0; found = 1; } else if (strcmp(name, "permit-pty") == 0) { *cert_no_pty_flag = 0; found = 1; } else if (strcmp(name, "permit-user-rc") == 0) { *cert_no_user_rc = 0; found = 1; } } if (!found && (which & OPTIONS_CRITICAL) != 0) { if (strcmp(name, "force-command") == 0) { if ((r = sshbuf_get_cstring(data, &command, NULL)) != 0) { error("Unable to parse \"%s\" " "section: %s", name, ssh_err(r)); goto out; } if (*cert_forced_command != NULL) { error("Certificate has multiple " "force-command options"); free(command); goto out; } *cert_forced_command = command; found = 1; } if (strcmp(name, "source-address") == 0) { if ((r = sshbuf_get_cstring(data, &allowed, NULL)) != 0) { error("Unable to parse \"%s\" " "section: %s", name, ssh_err(r)); goto out; } if ((*cert_source_address_done)++) { error("Certificate has multiple " "source-address options"); free(allowed); goto out; } remote_ip = ssh_remote_ipaddr(ssh); result = addr_match_cidr_list(remote_ip, allowed); free(allowed); switch (result) { case 1: /* accepted */ break; case 0: /* no match */ logit("Authentication tried for %.100s " "with valid certificate but not " "from a permitted host " "(ip=%.200s).", pw->pw_name, remote_ip); auth_debug_add("Your address '%.200s' " "is not permitted to use this " "certificate for login.", remote_ip); goto out; case -1: default: error("Certificate source-address " "contents invalid"); goto out; } found = 1; } } if (!found) { if (crit) { error("Certificate critical option \"%s\" " "is not supported", name); goto out; } else { logit("Certificate extension \"%s\" " "is not supported", name); } } else if (sshbuf_len(data) != 0) { error("Certificate option \"%s\" corrupt " "(extra data)", name); goto out; } free(name); name = NULL; } /* successfully parsed all options */ ret = 0; out: if (ret != 0 && cert_forced_command != NULL && *cert_forced_command != NULL) { free(*cert_forced_command); *cert_forced_command = NULL; } free(name); sshbuf_free(data); sshbuf_free(c); return ret; }
/* ARGSUSED */ int ssh_ecdsa_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, u_int compat) { ECDSA_SIG *sig = NULL; int hash_alg; u_char digest[SSH_DIGEST_MAX_LENGTH]; size_t dlen; int ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL, *sigbuf = NULL; char *ktype = NULL; if (key == NULL || key->ecdsa == NULL || sshkey_type_plain(key->type) != KEY_ECDSA) return SSH_ERR_INVALID_ARGUMENT; if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || (dlen = ssh_digest_bytes(hash_alg)) == 0) return SSH_ERR_INTERNAL_ERROR; /* fetch signature */ if ((b = sshbuf_from(signature, signaturelen)) == NULL) return SSH_ERR_ALLOC_FAIL; if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || sshbuf_froms(b, &sigbuf) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) { ret = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } if (sshbuf_len(b) != 0) { ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; goto out; } /* parse signature */ if ((sig = ECDSA_SIG_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 || sshbuf_get_bignum2(sigbuf, sig->s) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if (sshbuf_len(sigbuf) != 0) { ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; goto out; } if ((ret = ssh_digest_memory(hash_alg, data, datalen, digest, sizeof(digest))) != 0) goto out; switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) { case 1: ret = 0; break; case 0: ret = SSH_ERR_SIGNATURE_INVALID; goto out; default: ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } out: explicit_bzero(digest, sizeof(digest)); if (sigbuf != NULL) sshbuf_free(sigbuf); if (b != NULL) sshbuf_free(b); if (sig != NULL) ECDSA_SIG_free(sig); free(ktype); return ret; }
static int cert_option_list(struct sshauthopt *opts, struct sshbuf *oblob, u_int which, int crit) { char *command, *allowed; char *name = NULL; struct sshbuf *c = NULL, *data = NULL; int r, ret = -1, found; if ((c = sshbuf_fromb(oblob)) == NULL) { error("%s: sshbuf_fromb failed", __func__); goto out; } while (sshbuf_len(c) > 0) { sshbuf_free(data); data = NULL; if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 || (r = sshbuf_froms(c, &data)) != 0) { error("Unable to parse certificate options: %s", ssh_err(r)); goto out; } debug3("found certificate option \"%.100s\" len %zu", name, sshbuf_len(data)); found = 0; if ((which & OPTIONS_EXTENSIONS) != 0) { if (strcmp(name, "permit-X11-forwarding") == 0) { opts->permit_x11_forwarding_flag = 1; found = 1; } else if (strcmp(name, "permit-agent-forwarding") == 0) { opts->permit_agent_forwarding_flag = 1; found = 1; } else if (strcmp(name, "permit-port-forwarding") == 0) { opts->permit_port_forwarding_flag = 1; found = 1; } else if (strcmp(name, "permit-pty") == 0) { opts->permit_pty_flag = 1; found = 1; } else if (strcmp(name, "permit-user-rc") == 0) { opts->permit_user_rc = 1; found = 1; } } if (!found && (which & OPTIONS_CRITICAL) != 0) { if (strcmp(name, "force-command") == 0) { if ((r = sshbuf_get_cstring(data, &command, NULL)) != 0) { error("Unable to parse \"%s\" " "section: %s", name, ssh_err(r)); goto out; } if (opts->force_command != NULL) { error("Certificate has multiple " "force-command options"); free(command); goto out; } opts->force_command = command; found = 1; } if (strcmp(name, "source-address") == 0) { if ((r = sshbuf_get_cstring(data, &allowed, NULL)) != 0) { error("Unable to parse \"%s\" " "section: %s", name, ssh_err(r)); goto out; } if (opts->required_from_host_cert != NULL) { error("Certificate has multiple " "source-address options"); free(allowed); goto out; } /* Check syntax */ if (addr_match_cidr_list(NULL, allowed) == -1) { error("Certificate source-address " "contents invalid"); goto out; } opts->required_from_host_cert = allowed; found = 1; } } if (!found) { if (crit) { error("Certificate critical option \"%s\" " "is not supported", name); goto out; } else { logit("Certificate extension \"%s\" " "is not supported", name); } } else if (sshbuf_len(data) != 0) { error("Certificate option \"%s\" corrupt " "(extra data)", name); goto out; } free(name); name = NULL; } /* successfully parsed all options */ ret = 0; out: free(name); sshbuf_free(data); sshbuf_free(c); return ret; }