Ejemplo n.º 1
0
/*
 * 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;
}
Ejemplo n.º 2
0
/* parse buffer and return algorithm proposal */
int
kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
{
	struct sshbuf *b = NULL;
	u_char v;
	u_int i;
	char **proposal = NULL;
	int r;

	*propp = NULL;
	if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL)
		return SSH_ERR_ALLOC_FAIL;
	if ((b = sshbuf_fromb(raw)) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}
	if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */
		goto out;
	/* extract kex init proposal strings */
	for (i = 0; i < PROPOSAL_MAX; i++) {
		if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
			goto out;
		debug2("%s: %s", proposal_names[i], proposal[i]);
	}
	/* first kex follows / reserved */
	if ((r = sshbuf_get_u8(b, &v)) != 0 ||	/* first_kex_follows */
	    (r = sshbuf_get_u32(b, &i)) != 0)	/* reserved */
		goto out;
	if (first_kex_follows != NULL)
		*first_kex_follows = v;
	debug2("first_kex_follows %d ", v);
	debug2("reserved %u ", i);
	r = 0;
	*propp = proposal;
 out:
	if (r != 0 && proposal != NULL)
		kex_prop_free(proposal);
	sshbuf_free(b);
	return r;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
static int
sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase,
    struct sshkey **keyp, char **commentp)
{
	int r;
	u_int16_t check1, check2;
	u_int8_t cipher_type;
	struct sshbuf *decrypted = NULL, *copy = NULL;
	u_char *cp;
	char *comment = NULL;
	struct sshcipher_ctx ciphercontext;
	const struct sshcipher *cipher;
	struct sshkey *prv = 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;

	if ((prv = sshkey_new_private(KEY_RSA1)) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}
	if ((copy = sshbuf_fromb(blob)) == NULL ||
	    (decrypted = sshbuf_new()) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}
	if ((r = sshbuf_consume(copy, sizeof(authfile_id_string))) != 0)
		goto out;

	/* Read cipher type. */
	if ((r = sshbuf_get_u8(copy, &cipher_type)) != 0 ||
	    (r = sshbuf_get_u32(copy, NULL)) != 0)	/* reserved */
		goto out;

	/* Read the public key and comment from the buffer. */
	if ((r = sshbuf_get_u32(copy, NULL)) != 0 ||	/* key bits */
	    (r = sshbuf_get_bignum1(copy, prv->rsa->n)) != 0 ||
	    (r = sshbuf_get_bignum1(copy, prv->rsa->e)) != 0 ||
	    (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0)
		goto out;

	/* Check that it is a supported cipher. */
	cipher = cipher_by_number(cipher_type);
	if (cipher == NULL) {
		r = SSH_ERR_KEY_UNKNOWN_CIPHER;
		goto out;
	}
	/* Initialize space for decrypted data. */
	if ((r = sshbuf_reserve(decrypted, sshbuf_len(copy), &cp)) != 0)
		goto out;

	/* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
	if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase,
	    CIPHER_DECRYPT)) != 0)
		goto out;
	if ((r = cipher_crypt(&ciphercontext, cp,
	    sshbuf_ptr(copy), sshbuf_len(copy), 0, 0)) != 0) {
		cipher_cleanup(&ciphercontext);
		goto out;
	}
	if ((r = cipher_cleanup(&ciphercontext)) != 0)
		goto out;

	if ((r = sshbuf_get_u16(decrypted, &check1)) != 0 ||
	    (r = sshbuf_get_u16(decrypted, &check2)) != 0)
		goto out;
	if (check1 != check2) {
		r = SSH_ERR_KEY_WRONG_PASSPHRASE;
		goto out;
	}

	/* Read the rest of the private key. */
	if ((r = sshbuf_get_bignum1(decrypted, prv->rsa->d)) != 0 ||
	    (r = sshbuf_get_bignum1(decrypted, prv->rsa->iqmp)) != 0 ||
	    (r = sshbuf_get_bignum1(decrypted, prv->rsa->q)) != 0 ||
	    (r = sshbuf_get_bignum1(decrypted, prv->rsa->p)) != 0)
		goto out;

	/* calculate p-1 and q-1 */
	if ((r = rsa_generate_additional_parameters(prv->rsa)) != 0)
		goto out;

	/* enable blinding */
	if (RSA_blinding_on(prv->rsa, NULL) != 1) {
		r = SSH_ERR_LIBCRYPTO_ERROR;
		goto out;
	}
	r = 0;
	*keyp = prv;
	prv = NULL;
	if (commentp != NULL) {
		*commentp = comment;
		comment = NULL;
	}
 out:
	bzero(&ciphercontext, sizeof(ciphercontext));
	if (comment != NULL)
		free(comment);
	if (prv != NULL)
		sshkey_free(prv);
	if (copy != NULL)
		sshbuf_free(copy);
	if (decrypted != NULL)
		sshbuf_free(decrypted);
	return r;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
int
sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded,
   struct sshbuf **retp)
{
	struct ssh_xmss_state *state = k->xmss_state;
	struct sshbuf *copy = NULL, *decrypted = NULL;
	struct sshcipher_ctx *ciphercontext = NULL;
	const struct sshcipher *cipher = NULL;
	u_char *key, *iv = NULL, *dp;
	size_t keylen, ivlen, authlen, aadlen;
	u_int blocksize, encrypted_len, index;
	int r = SSH_ERR_INTERNAL_ERROR;

	if (retp != NULL)
		*retp = NULL;
	if (state == NULL ||
	    state->enc_keyiv == NULL ||
	    state->enc_ciphername == NULL)
		return SSH_ERR_INTERNAL_ERROR;
	if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	blocksize = cipher_blocksize(cipher);
	keylen = cipher_keylen(cipher);
	ivlen = cipher_ivlen(cipher);
	authlen = cipher_authlen(cipher);
	if (state->enc_keyiv_len != keylen + ivlen) {
		r = SSH_ERR_INTERNAL_ERROR;
		goto out;
	}
	key = state->enc_keyiv;

	if ((copy = sshbuf_fromb(encoded)) == NULL ||
	    (decrypted = sshbuf_new()) == NULL ||
	    (iv = malloc(ivlen)) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}

	/* check magic */
	if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) ||
	    memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	/* parse public portion */
	if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 ||
	    (r = sshbuf_get_u32(encoded, &index)) != 0 ||
	    (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0)
		goto out;

	/* check size of encrypted key blob */
	if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}
	/* check that an appropriate amount of auth data is present */
	if (sshbuf_len(encoded) < encrypted_len + authlen) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}

	aadlen = sshbuf_len(copy) - sshbuf_len(encoded);

	/* replace first 4 bytes of IV with index to ensure uniqueness */
	memcpy(iv, key + keylen, ivlen);
	POKE_U32(iv, index);

	/* decrypt private state of key */
	if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 ||
	    (r = cipher_init(&ciphercontext, cipher, key, keylen,
	    iv, ivlen, 0)) != 0 ||
	    (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy),
	    encrypted_len, aadlen, authlen)) != 0)
		goto out;

	/* there should be no trailing data */
	if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0)
		goto out;
	if (sshbuf_len(encoded) != 0) {
		r = SSH_ERR_INVALID_FORMAT;
		goto out;
	}

	/* remove AAD */
	if ((r = sshbuf_consume(decrypted, aadlen)) != 0)
		goto out;
	/* XXX encrypted includes unchecked padding */

	/* success */
	r = 0;
	if (retp != NULL) {
		*retp = decrypted;
		decrypted = NULL;
	}
 out:
	cipher_free(ciphercontext);
	sshbuf_free(copy);
	sshbuf_free(decrypted);
	free(iv);
	return r;
}