Exemple #1
0
int
sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
{
	u_char *d;
	int r;

	if (len > SSHBUF_SIZE_MAX - 4) {
		SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
		return SSH_ERR_NO_BUFFER_SPACE;
	}
	if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
		return r;
	POKE_U32(d, len);
	if (len != 0)
		memcpy(d + 4, v, len);
	return 0;
}
int
sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
{
	u_int32_t len;
	u_char *p;
	int r;

	/*
	 * Use sshbuf_peek_string_direct() to figure out if there is
	 * a complete string in 'buf' and copy the string directly
	 * into 'v'.
	 */
	if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
	    (r = sshbuf_get_u32(buf, &len)) != 0 ||
	    (r = sshbuf_reserve(v, len, &p)) != 0 ||
	    (r = sshbuf_get(buf, p, len)) != 0)
		return r;
	return 0;
}
int
sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v)
{
	int r, len_bits = BN_num_bits(v);
	size_t len_bytes = (len_bits + 7) / 8;
	u_char d[SSHBUF_MAX_BIGNUM], *dp;

	if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM)
		return SSH_ERR_INVALID_ARGUMENT;
	if (BN_bn2bin(v, d) != (int)len_bytes)
		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
	if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) {
		bzero(d, sizeof(d));
		return r;
	}
	POKE_U16(dp, len_bits);
	memcpy(dp + 2, d, len_bytes);
	bzero(d, sizeof(d));
	return 0;
}
Exemple #4
0
int
kex_c25519_keypair(struct kex *kex)
{
	struct sshbuf *buf = NULL;
	u_char *cp = NULL;
	int r;

	if ((buf = sshbuf_new()) == NULL)
		return SSH_ERR_ALLOC_FAIL;
	if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0)
		goto out;
	kexc25519_keygen(kex->c25519_client_key, cp);
#ifdef DEBUG_KEXECDH
	dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
#endif
	kex->client_pub = buf;
	buf = NULL;
 out:
	sshbuf_free(buf);
	return r;
}
void
sshbuf_tests(void)
{
	struct sshbuf *p1;
	const u_char *cdp;
	u_char *dp;
	size_t sz;
	int r;

	TEST_START("allocate sshbuf");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	TEST_DONE();

	TEST_START("max size on fresh buffer");
	ASSERT_SIZE_T_GT(sshbuf_max_size(p1), 0);
	TEST_DONE();

	TEST_START("available on fresh buffer");
	ASSERT_SIZE_T_GT(sshbuf_avail(p1), 0);
	TEST_DONE();

	TEST_START("len = 0 on empty buffer");
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
	TEST_DONE();

	TEST_START("set valid max size");
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 65536), 0);
	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 65536);
	TEST_DONE();

	TEST_START("available on limited buffer");
	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 65536);
	TEST_DONE();

	TEST_START("free");
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("consume on empty buffer");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
	ASSERT_INT_EQ(sshbuf_consume(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("consume_end on empty buffer");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_consume_end(p1, 0), 0);
	ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("reserve space");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	r = sshbuf_reserve(p1, 1, &dp);
	ASSERT_INT_EQ(r, 0);
	ASSERT_PTR_NE(dp, NULL);
	*dp = 0x11;
	r = sshbuf_reserve(p1, 3, &dp);
	ASSERT_INT_EQ(r, 0);
	ASSERT_PTR_NE(dp, NULL);
	*dp++ = 0x22;
	*dp++ = 0x33;
	*dp++ = 0x44;
	TEST_DONE();

	TEST_START("sshbuf_len on filled buffer");
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
	TEST_DONE();

	TEST_START("sshbuf_ptr on filled buffer");
	cdp = sshbuf_ptr(p1);
	ASSERT_PTR_NE(cdp, NULL);
	ASSERT_U8_EQ(cdp[0], 0x11);
	ASSERT_U8_EQ(cdp[1], 0x22);
	ASSERT_U8_EQ(cdp[2], 0x33);
	ASSERT_U8_EQ(cdp[3], 0x44);
	TEST_DONE();

	TEST_START("consume on filled buffer");
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
	ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
	r = sshbuf_consume(p1, 64);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
	ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3);
	cdp = sshbuf_ptr(p1);
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_U8_EQ(cdp[0], 0x22);
	ASSERT_INT_EQ(sshbuf_consume(p1, 2), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
	cdp = sshbuf_ptr(p1);
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_U8_EQ(cdp[0], 0x44);
	r = sshbuf_consume(p1, 2);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
	ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
	r = sshbuf_consume(p1, 1);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("consume_end on filled buffer");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	r = sshbuf_reserve(p1, 4, &dp);
	ASSERT_INT_EQ(r, 0);
	ASSERT_PTR_NE(dp, NULL);
	*dp++ = 0x11;
	*dp++ = 0x22;
	*dp++ = 0x33;
	*dp++ = 0x44;
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
	r = sshbuf_consume_end(p1, 5);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
	ASSERT_INT_EQ(sshbuf_consume_end(p1, 3), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
	cdp = sshbuf_ptr(p1);
	ASSERT_PTR_NE(cdp, NULL);
	ASSERT_U8_EQ(*cdp, 0x11);
	r = sshbuf_consume_end(p1, 2);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("fill limited buffer");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
	r = sshbuf_reserve(p1, 1223, &dp);
	ASSERT_INT_EQ(r, 0);
	ASSERT_PTR_NE(dp, NULL);
	memset(dp, 0xd7, 1223);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0);
	r = sshbuf_reserve(p1, 1, &dp);
	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
	ASSERT_PTR_EQ(dp, NULL);
	TEST_DONE();

	TEST_START("consume and force compaction");
	ASSERT_INT_EQ(sshbuf_consume(p1, 223), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
	r = sshbuf_reserve(p1, 224, &dp);
	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
	ASSERT_PTR_EQ(dp, NULL);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
	r = sshbuf_reserve(p1, 223, &dp);
	ASSERT_INT_EQ(r, 0);
	ASSERT_PTR_NE(dp, NULL);
	memset(dp, 0x7d, 223);
	cdp = sshbuf_ptr(p1);
	ASSERT_PTR_NE(cdp, NULL);
	ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
	ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
	TEST_DONE();

	TEST_START("resize full buffer");
	r = sshbuf_set_max_size(p1, 1000);
	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
	sz = roundup(1223 + SSHBUF_SIZE_INC * 3, SSHBUF_SIZE_INC);
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sz), 0);
	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - 1223);
	ASSERT_INT_EQ(sshbuf_len(p1), 1223);
	TEST_DONE();

	/* NB. uses sshbuf internals */
	TEST_START("alloc chunking");
	r = sshbuf_reserve(p1, 1, &dp);
	ASSERT_INT_EQ(r, 0);
	ASSERT_PTR_NE(dp, NULL);
	*dp = 0xff;
	cdp = sshbuf_ptr(p1);
	ASSERT_PTR_NE(cdp, NULL);
	ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
	ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
	ASSERT_MEM_FILLED_EQ(cdp + 1223, 0xff, 1);
	ASSERT_SIZE_T_EQ(sshbuf_alloc(p1) % SSHBUF_SIZE_INC, 0);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("reset buffer");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
	r = sshbuf_reserve(p1, 1223, &dp);
	ASSERT_INT_EQ(r, 0);
	ASSERT_PTR_NE(dp, NULL);
	memset(dp, 0xd7, 1223);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
	sshbuf_reset(p1);
	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
	sshbuf_free(p1);
	TEST_DONE();
}
Exemple #6
0
/*
 * Serialises the authentication (private) key to a blob, encrypting it with
 * passphrase.  The identification of the blob (lowest 64 bits of n) will
 * precede the key to provide identification of the key without needing a
 * passphrase.
 */
static int
sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob,
    const char *passphrase, const char *comment)
{
	struct sshbuf *buffer = NULL, *encrypted = NULL;
	u_char buf[8];
	int r, cipher_num;
	struct sshcipher_ctx ciphercontext;
	const struct sshcipher *cipher;
	u_char *cp;

	/*
	 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
	 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
	 */
	cipher_num = (strcmp(passphrase, "") == 0) ?
	    SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
	if ((cipher = cipher_by_number(cipher_num)) == NULL)
		return SSH_ERR_INTERNAL_ERROR;

	/* This buffer is used to build the secret part of the private key. */
	if ((buffer = sshbuf_new()) == NULL)
		return SSH_ERR_ALLOC_FAIL;

	/* Put checkbytes for checking passphrase validity. */
	if ((r = sshbuf_reserve(buffer, 4, &cp)) != 0)
		goto out;
	arc4random_buf(cp, 2);
	memcpy(cp + 2, cp, 2);

	/*
	 * Store the private key (n and e will not be stored because they
	 * will be stored in plain text, and storing them also in encrypted
	 * format would just give known plaintext).
	 * Note: q and p are stored in reverse order to SSL.
	 */
	if ((r = sshbuf_put_bignum1(buffer, key->rsa->d)) != 0 ||
	    (r = sshbuf_put_bignum1(buffer, key->rsa->iqmp)) != 0 ||
	    (r = sshbuf_put_bignum1(buffer, key->rsa->q)) != 0 ||
	    (r = sshbuf_put_bignum1(buffer, key->rsa->p)) != 0)
		goto out;

	/* Pad the part to be encrypted to a size that is a multiple of 8. */
	bzero(buf, 8);
	if ((r = sshbuf_put(buffer, buf, 8 - (sshbuf_len(buffer) % 8))) != 0)
		goto out;

	/* This buffer will be used to contain the data in the file. */
	if ((encrypted = sshbuf_new()) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}

	/* First store keyfile id string. */
	if ((r = sshbuf_put(encrypted, authfile_id_string,
	    sizeof(authfile_id_string))) != 0)
		goto out;

	/* Store cipher type and "reserved" field. */
	if ((r = sshbuf_put_u8(encrypted, cipher_num)) != 0 ||
	    (r = sshbuf_put_u32(encrypted, 0)) != 0)
		goto out;

	/* Store public key.  This will be in plain text. */
	if ((r = sshbuf_put_u32(encrypted, BN_num_bits(key->rsa->n))) != 0 ||
	    (r = sshbuf_put_bignum1(encrypted, key->rsa->n) != 0) ||
	    (r = sshbuf_put_bignum1(encrypted, key->rsa->e) != 0) ||
	    (r = sshbuf_put_cstring(encrypted, comment) != 0))
		goto out;

	/* Allocate space for the private part of the key in the buffer. */
	if ((r = sshbuf_reserve(encrypted, sshbuf_len(buffer), &cp)) != 0)
		goto out;

	if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase,
	    CIPHER_ENCRYPT)) != 0)
		goto out;
	if ((r = cipher_crypt(&ciphercontext, cp,
	    sshbuf_ptr(buffer), sshbuf_len(buffer), 0, 0)) != 0)
		goto out;
	if ((r = cipher_cleanup(&ciphercontext)) != 0)
		goto out;

	r = sshbuf_putb(blob, encrypted);

 out:
	bzero(&ciphercontext, sizeof(ciphercontext));
	bzero(buf, sizeof(buf));
	if (buffer != NULL)
		sshbuf_free(buffer);
	if (encrypted != NULL)
		sshbuf_free(encrypted);

	return r;
}
Exemple #7
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;
}
void
sshbuf_misc_tests(void)
{
	struct sshbuf *p1;
	char tmp[512], *p;
	FILE *out;
	size_t sz;

	TEST_START("sshbuf_dump");
	out = tmpfile();
	ASSERT_PTR_NE(out, NULL);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
	sshbuf_dump(p1, out);
	fflush(out);
	rewind(out);
	sz = fread(tmp, 1, sizeof(tmp), out);
	ASSERT_INT_EQ(ferror(out), 0);
	ASSERT_INT_NE(feof(out), 0);
	ASSERT_SIZE_T_GT(sz, 0);
	tmp[sz] = '\0';
	ASSERT_PTR_NE(strstr(tmp, "12 34 56 78"), NULL);
	fclose(out);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_dtob16");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
	p = sshbuf_dtob16(p1);
	ASSERT_PTR_NE(p, NULL);
	ASSERT_STRING_EQ(p, "12345678");
	free(p);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_dtob64 len 1");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
	p = sshbuf_dtob64(p1);
	ASSERT_PTR_NE(p, NULL);
	ASSERT_STRING_EQ(p, "EQ==");
	free(p);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_dtob64 len 2");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x22), 0);
	p = sshbuf_dtob64(p1);
	ASSERT_PTR_NE(p, NULL);
	ASSERT_STRING_EQ(p, "ESI=");
	free(p);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_dtob64 len 3");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x22), 0);
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x33), 0);
	p = sshbuf_dtob64(p1);
	ASSERT_PTR_NE(p, NULL);
	ASSERT_STRING_EQ(p, "ESIz");
	free(p);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_dtob64 len 8191");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_reserve(p1, 8192, NULL), 0);
	bzero(sshbuf_mutable_ptr(p1), 8192);
	p = sshbuf_dtob64(p1);
	ASSERT_PTR_NE(p, NULL);
	ASSERT_SIZE_T_EQ(strlen(p), ((8191 + 2) / 3) * 4);
	free(p);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_b64tod len 1");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A=="), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
	ASSERT_U8_EQ(*sshbuf_ptr(p1), 0xd0);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_b64tod len 2");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A8="), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
	ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), 0xd00f);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_b64tod len 4");
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A/QDw=="), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
	ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), 0xd00fd00f);
	sshbuf_free(p1);
	TEST_DONE();
}
void
sshbuf_getput_crypto_tests(void)
{
	struct sshbuf *p1;
	const u_char *d;
	size_t s;
	BIGNUM *bn, *bn2, *bn_x, *bn_y;
	/* This one has num_bits != num_bytes * 8 to test bignum1 encoding */
	const char *hexbn1 = "0102030405060708090a0b0c0d0e0f10";
	/* This one has MSB set to test bignum2 encoding negative-avoidance */
	const char *hexbn2 = "f0e0d0c0b0a0908070605040302010007fff11";
	u_char expbn1[] = {
		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
		0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
	};
	u_char expbn2[] = {
		0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
		0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
		0x7f, 0xff, 0x11
	};
	int ec256_nid = NID_X9_62_prime256v1;
	char *ec256_x = "0C828004839D0106AA59575216191357"
		        "34B451459DADB586677EF9DF55784999";
	char *ec256_y = "4D196B50F0B4E94B3C73E3A9D4CD9DF2"
	                "C8F9A35E42BDD047550F69D80EC23CD4";
	u_char expec256[] = {
		0x04,
		0x0c, 0x82, 0x80, 0x04, 0x83, 0x9d, 0x01, 0x06,
		0xaa, 0x59, 0x57, 0x52, 0x16, 0x19, 0x13, 0x57,
		0x34, 0xb4, 0x51, 0x45, 0x9d, 0xad, 0xb5, 0x86,
		0x67, 0x7e, 0xf9, 0xdf, 0x55, 0x78, 0x49, 0x99,
		0x4d, 0x19, 0x6b, 0x50, 0xf0, 0xb4, 0xe9, 0x4b,
		0x3c, 0x73, 0xe3, 0xa9, 0xd4, 0xcd, 0x9d, 0xf2,
		0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47,
		0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4
	};
	EC_KEY *eck;
	EC_POINT *ecp;
	int r;

#define MKBN(b, bnn) \
	do { \
		bnn = NULL; \
		ASSERT_INT_GT(BN_hex2bn(&bnn, b), 0); \
	} while (0)

	TEST_START("sshbuf_put_bignum1");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 2);
	ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn));
	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn1, sizeof(expbn1));
	BN_free(bn);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_put_bignum1 limited");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0);
	r = sshbuf_put_bignum1(p1, bn);
	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
	BN_free(bn);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_put_bignum1 bn2");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 2);
	ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn));
	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn2, sizeof(expbn2));
	BN_free(bn);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_put_bignum1 bn2 limited");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0);
	r = sshbuf_put_bignum1(p1, bn);
	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
	BN_free(bn);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_put_bignum2");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 4);
	ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn));
	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 4, expbn1, sizeof(expbn1));
	BN_free(bn);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_put_bignum2 limited");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 3), 0);
	r = sshbuf_put_bignum2(p1, bn);
	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
	BN_free(bn);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_put_bignum2 bn2");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4 + 1); /* MSB */
	ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn) + 1);
	ASSERT_U8_EQ(*(sshbuf_ptr(p1) + 4), 0x00);
	ASSERT_MEM_EQ(sshbuf_ptr(p1) + 5, expbn2, sizeof(expbn2));
	BN_free(bn);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_put_bignum2 bn2 limited");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn2) + 3), 0);
	r = sshbuf_put_bignum2(p1, bn);
	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
	BN_free(bn);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum1");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1));
	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
	bn2 = BN_new();
	ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0);
	ASSERT_BIGNUM_EQ(bn, bn2);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum1 truncated");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1);
	bn2 = BN_new();
	r = sshbuf_get_bignum1(p1, bn2);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum1 giant");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xffff), 0);
	ASSERT_INT_EQ(sshbuf_reserve(p1, (0xffff + 7) / 8, NULL), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8));
	bn2 = BN_new();
	r = sshbuf_get_bignum1(p1, bn2);
	ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8));
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum1 bn2");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2));
	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
	bn2 = BN_new();
	ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0);
	ASSERT_BIGNUM_EQ(bn, bn2);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum1 bn2 truncated");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1);
	bn2 = BN_new();
	r = sshbuf_get_bignum1(p1, bn2);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum2");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + sizeof(expbn1));
	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
	bn2 = BN_new();
	ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0);
	ASSERT_BIGNUM_EQ(bn, bn2);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum2 truncated");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0);
	bn2 = BN_new();
	r = sshbuf_get_bignum2(p1, bn2);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 3);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum2 giant");
	MKBN(hexbn1, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u32(p1, 65536), 0);
	ASSERT_INT_EQ(sshbuf_reserve(p1, 65536, NULL), 0);
	bn2 = BN_new();
	r = sshbuf_get_bignum2(p1, bn2);
	ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 65536 + 4);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum2 bn2");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0); /* MSB */
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + 1 + sizeof(expbn2));
	ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
	bn2 = BN_new();
	ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0);
	ASSERT_BIGNUM_EQ(bn, bn2);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum2 bn2 truncated");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0);
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0);
	bn2 = BN_new();
	r = sshbuf_get_bignum2(p1, bn2);
	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 1 + 4 - 1);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_get_bignum2 bn2 negative");
	MKBN(hexbn2, bn);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
	ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
	bn2 = BN_new();
	r = sshbuf_get_bignum2(p1, bn2);
	ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_IS_NEGATIVE);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4);
	BN_free(bn);
	BN_free(bn2);
	sshbuf_free(p1);
	TEST_DONE();

	TEST_START("sshbuf_put_ec");
	eck = EC_KEY_new_by_curve_name(ec256_nid);
	ASSERT_PTR_NE(eck, NULL);
	ecp = EC_POINT_new(EC_KEY_get0_group(eck));
	ASSERT_PTR_NE(ecp, NULL);
	MKBN(ec256_x, bn_x);
	MKBN(ec256_y, bn_y);
	ASSERT_INT_EQ(EC_POINT_set_affine_coordinates_GFp(
	    EC_KEY_get0_group(eck), ecp, bn_x, bn_y, NULL), 1);
	ASSERT_INT_EQ(EC_KEY_set_public_key(eck, ecp), 1);
	EC_POINT_free(ecp);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_eckey(p1, eck), 0);
	ASSERT_INT_EQ(sshbuf_get_string_direct(p1, &d, &s), 0);
	ASSERT_SIZE_T_EQ(s, sizeof(expec256));
	ASSERT_MEM_EQ(d, expec256, sizeof(expec256));
	sshbuf_free(p1);
	EC_KEY_free(eck);
	TEST_DONE();

	TEST_START("sshbuf_get_ec");
	eck = EC_KEY_new_by_curve_name(ec256_nid);
	ASSERT_PTR_NE(eck, NULL);
	p1 = sshbuf_new();
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_INT_EQ(sshbuf_put_string(p1, expec256, sizeof(expec256)), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expec256) + 4);
	ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
	ASSERT_INT_EQ(sshbuf_get_eckey(p1, eck), 0);
	bn_x = BN_new();
	bn_y = BN_new();
	ASSERT_PTR_NE(bn_x, NULL);
	ASSERT_PTR_NE(bn_y, NULL);
	ASSERT_INT_EQ(EC_POINT_get_affine_coordinates_GFp(
	    EC_KEY_get0_group(eck), EC_KEY_get0_public_key(eck),
	    bn_x, bn_y, NULL), 1);
	MKBN(ec256_x, bn);
	MKBN(ec256_y, bn2);
	ASSERT_INT_EQ(BN_cmp(bn_x, bn), 0);
	ASSERT_INT_EQ(BN_cmp(bn_y, bn2), 0);
	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
	sshbuf_free(p1);
	EC_KEY_free(eck);
	BN_free(bn_x);
	BN_free(bn_y);
	BN_free(bn);
	BN_free(bn2);
	TEST_DONE();
}
Exemple #10
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;
}
Exemple #11
0
int
sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b,
   struct sshbuf **retp)
{
	struct ssh_xmss_state *state = k->xmss_state;
	struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL;
	struct sshcipher_ctx *ciphercontext = NULL;
	const struct sshcipher *cipher;
	u_char *cp, *key, *iv = NULL;
	size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen;
	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_INTERNAL_ERROR;
		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_INVALID_FORMAT;
		goto out;
	}
	key = state->enc_keyiv;
	if ((encrypted = sshbuf_new()) == NULL ||
	    (encoded = sshbuf_new()) == NULL ||
	    (padded = sshbuf_new()) == NULL ||
	    (iv = malloc(ivlen)) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
	}

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

	if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 ||
	    (r = sshbuf_put_u32(encoded, state->idx)) != 0)
		goto out;

	/* padded state will be encrypted */
	if ((r = sshbuf_putb(padded, b)) != 0)
		goto out;
	i = 0;
	while (sshbuf_len(padded) % blocksize) {
		if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0)
			goto out;
	}
	encrypted_len = sshbuf_len(padded);

	/* header including the length of state is used as AAD */
	if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0)
		goto out;
	aadlen = sshbuf_len(encoded);

	/* concat header and state */
	if ((r = sshbuf_putb(encoded, padded)) != 0)
		goto out;

	/* reserve space for encryption of encoded data plus auth tag */
	/* encrypt at offset addlen */
	if ((r = sshbuf_reserve(encrypted,
	    encrypted_len + aadlen + authlen, &cp)) != 0 ||
	    (r = cipher_init(&ciphercontext, cipher, key, keylen,
	    iv, ivlen, 1)) != 0 ||
	    (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded),
	    encrypted_len, aadlen, authlen)) != 0)
		goto out;

	/* success */
	r = 0;
 out:
	if (retp != NULL) {
		*retp = encrypted;
		encrypted = NULL;
	}
	sshbuf_free(padded);
	sshbuf_free(encoded);
	sshbuf_free(encrypted);
	cipher_free(ciphercontext);
	free(iv);
	return r;
}
Exemple #12
0
void
sshbuf_fuzz_tests(void)
{
	struct sshbuf *p1;
	u_char *dp;
	size_t sz, sz2, i;
	u_int32_t r;
	int ret;

	/* NB. uses sshbuf internals */
	TEST_START("fuzz alloc/dealloc");
	p1 = sshbuf_new();
	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0);
	ASSERT_PTR_NE(p1, NULL);
	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
	for (i = 0; i < NUM_FUZZ_TESTS; i++) {
		r = arc4random_uniform(10);
		if (r == 0) {
			/* 10% chance: small reserve */
			r = arc4random_uniform(10);
 fuzz_reserve:
			sz = sshbuf_avail(p1);
			sz2 = sshbuf_len(p1);
			ret = sshbuf_reserve(p1, r, &dp);
			if (ret < 0) {
				ASSERT_PTR_EQ(dp, NULL);
				ASSERT_SIZE_T_LT(sz, r);
				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
			} else {
				ASSERT_PTR_NE(dp, NULL);
				ASSERT_SIZE_T_GE(sz, r);
				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r);
				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r);
				memset(dp, arc4random_uniform(255) + 1, r);
			}
		} else if (r < 3) {
			/* 20% chance: big reserve */
			r = arc4random_uniform(8 * 1024);
			goto fuzz_reserve;
		} else if (r == 3) {
			/* 10% chance: small consume */
			r = arc4random_uniform(10);
 fuzz_consume:
			sz = sshbuf_avail(p1);
			sz2 = sshbuf_len(p1);
			/* 50% change consume from end, otherwise start */
			ret = ((arc4random() & 1) ?
			    sshbuf_consume : sshbuf_consume_end)(p1, r);
			if (ret < 0) {
				ASSERT_SIZE_T_LT(sz2, r);
				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
			} else {
				ASSERT_SIZE_T_GE(sz2, r);
				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r);
				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r);
			}
		} else if (r < 8) {
			/* 40% chance: big consume */
			r = arc4random_uniform(2 * 1024);
			goto fuzz_consume;
		} else if (r == 8) {
			/* 10% chance: reset max size */
			r = arc4random_uniform(16 * 1024);
			sz = sshbuf_max_size(p1);
			if (sshbuf_set_max_size(p1, r) < 0)
				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
			else
				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r);
		} else {
			if (arc4random_uniform(8192) == 0) {
				/* tiny chance: new buffer */
				ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
				ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
				sshbuf_free(p1);
				p1 = sshbuf_new();
				ASSERT_PTR_NE(p1, NULL);
				ASSERT_INT_EQ(sshbuf_set_max_size(p1,
				    16 * 1024), 0);
			} else {
				/* Almost 10%: giant reserve */
				/* use arc4random_buf for r > 2^32 on 64 bit */
				arc4random_buf(&r, sizeof(r));
				while (r < SSHBUF_SIZE_MAX / 2) {
					r <<= 1;
					r |= arc4random() & 1;
				}
				goto fuzz_reserve;
			}
		}
		ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
		ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024);
	}
	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
	sshbuf_free(p1);
	TEST_DONE();
}