sshbuf.h 11.6 KB
Newer Older
1
/*	$OpenBSD: sshbuf.h,v 1.11 2018/07/09 21:56:06 markus Exp $	*/
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright (c) 2011 Damien Miller
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _SSHBUF_H
#define _SSHBUF_H

#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
24 25 26 27 28 29
#ifdef WITH_OPENSSL
# include <openssl/bn.h>
# ifdef OPENSSL_HAS_ECC
#  include <openssl/ec.h>
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

#define SSHBUF_SIZE_MAX		0x8000000	/* Hard maximum size */
#define SSHBUF_REFS_MAX		0x100000	/* Max child buffers */
#define SSHBUF_MAX_BIGNUM	(16384 / 8)	/* Max bignum *bytes* */
#define SSHBUF_MAX_ECPOINT	((528 * 2 / 8) + 1) /* Max EC point *bytes* */

/*
 * NB. do not depend on the internals of this. It will be made opaque
 * one day.
 */
struct sshbuf {
	u_char *d;		/* Data */
	const u_char *cd;	/* Const data */
	size_t off;		/* First available byte is buf->d + buf->off */
	size_t size;		/* Last byte is buf->d + buf->size - 1 */
	size_t max_size;	/* Maximum size of buffer */
	size_t alloc;		/* Total bytes allocated to buf->d */
	int readonly;		/* Refers to external, const data */
	int dont_free;		/* Kludge to support sshbuf_init */
	u_int refcount;		/* Tracks self and number of child buffers */
	struct sshbuf *parent;	/* If child, pointer to parent */
};

/*
 * Create a new sshbuf buffer.
 * Returns pointer to buffer on success, or NULL on allocation failure.
 */
struct sshbuf *sshbuf_new(void);

/*
 * Create a new, read-only sshbuf buffer from existing data.
 * Returns pointer to buffer on success, or NULL on allocation failure.
 */
struct sshbuf *sshbuf_from(const void *blob, size_t len);

/*
 * Create a new, read-only sshbuf buffer from the contents of an existing
 * buffer. The contents of "buf" must not change in the lifetime of the
 * resultant buffer.
 * Returns pointer to buffer on success, or NULL on allocation failure.
 */
struct sshbuf *sshbuf_fromb(struct sshbuf *buf);

/*
 * Create a new, read-only sshbuf buffer from the contents of a string in
 * an existing buffer (the string is consumed in the process).
 * The contents of "buf" must not change in the lifetime of the resultant
 * buffer.
 * Returns pointer to buffer on success, or NULL on allocation failure.
 */
int	sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp);

/*
 * Clear and free buf
 */
void	sshbuf_free(struct sshbuf *buf);

/*
 * Reset buf, clearing its contents. NB. max_size is preserved.
 */
void	sshbuf_reset(struct sshbuf *buf);

/*
 * Return the maximum size of buf
 */
size_t	sshbuf_max_size(const struct sshbuf *buf);

/*
 * Set the maximum size of buf
 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
 */
int	sshbuf_set_max_size(struct sshbuf *buf, size_t max_size);

/*
 * Returns the length of data in buf
 */
size_t	sshbuf_len(const struct sshbuf *buf);

/*
 * Returns number of bytes left in buffer before hitting max_size.
 */
size_t	sshbuf_avail(const struct sshbuf *buf);

/*
mmcc@openbsd.org's avatar
mmcc@openbsd.org committed
114
 * Returns a read-only pointer to the start of the data in buf
115 116 117 118
 */
const u_char *sshbuf_ptr(const struct sshbuf *buf);

/*
mmcc@openbsd.org's avatar
mmcc@openbsd.org committed
119
 * Returns a mutable pointer to the start of the data in buf, or
120 121 122 123 124 125 126 127 128 129 130 131
 * NULL if the buffer is read-only.
 */
u_char *sshbuf_mutable_ptr(const struct sshbuf *buf);

/*
 * Check whether a reservation of size len will succeed in buf
 * Safer to use than direct comparisons again sshbuf_avail as it copes
 * with unsigned overflows correctly.
 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
 */
int	sshbuf_check_reserve(const struct sshbuf *buf, size_t len);

djm@openbsd.org's avatar
djm@openbsd.org committed
132 133 134 135 136 137 138 139
/*
 * Preallocates len additional bytes in buf.
 * Useful for cases where the caller knows how many bytes will ultimately be
 * required to avoid realloc in the buffer code.
 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
 */
int	sshbuf_allocate(struct sshbuf *buf, size_t len);

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
/*
 * Reserve len bytes in buf.
 * Returns 0 on success and a pointer to the first reserved byte via the
 * optional dpp parameter or a negative * SSH_ERR_* error code on failure.
 */
int	sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp);

/*
 * Consume len bytes from the start of buf
 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
 */
int	sshbuf_consume(struct sshbuf *buf, size_t len);

/*
 * Consume len bytes from the end of buf
 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
 */
int	sshbuf_consume_end(struct sshbuf *buf, size_t len);

/* Extract or deposit some bytes */
int	sshbuf_get(struct sshbuf *buf, void *v, size_t len);
int	sshbuf_put(struct sshbuf *buf, const void *v, size_t len);
int	sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v);

/* Append using a printf(3) format */
int	sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
	    __attribute__((format(printf, 2, 3)));
int	sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap);

/* Functions to extract or store big-endian words of various sizes */
int	sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp);
int	sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp);
int	sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp);
int	sshbuf_get_u8(struct sshbuf *buf, u_char *valp);
int	sshbuf_put_u64(struct sshbuf *buf, u_int64_t val);
int	sshbuf_put_u32(struct sshbuf *buf, u_int32_t val);
int	sshbuf_put_u16(struct sshbuf *buf, u_int16_t val);
int	sshbuf_put_u8(struct sshbuf *buf, u_char val);

/*
 * Functions to extract or store SSH wire encoded strings (u32 len || data)
 * The "cstring" variants admit no \0 characters in the string contents.
 * Caller must free *valp.
 */
int	sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp);
int	sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp);
int	sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v);
int	sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len);
int	sshbuf_put_cstring(struct sshbuf *buf, const char *v);
int	sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v);

/*
 * "Direct" variant of sshbuf_get_string, returns pointer into the sshbuf to
 * avoid an malloc+memcpy. The pointer is guaranteed to be valid until the
 * next sshbuf-modifying function call. Caller does not free.
 */
int	sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp,
	    size_t *lenp);

/* Skip past a string */
#define sshbuf_skip_string(buf) sshbuf_get_string_direct(buf, NULL, NULL)

/* Another variant: "peeks" into the buffer without modifying it */
int	sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
	    size_t *lenp);
djm@openbsd.org's avatar
djm@openbsd.org committed
205
/* XXX peek_u8 / peek_u32 */
206 207 208 209 210

/*
 * Functions to extract or store SSH wire encoded bignums and elliptic
 * curve points.
 */
211
int	sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len);
Damien Miller's avatar
Damien Miller committed
212 213
int	sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
	    const u_char **valp, size_t *lenp);
214
#ifdef WITH_OPENSSL
215 216 217 218
int	sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v);
int	sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v);
int	sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v);
int	sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v);
219
# ifdef OPENSSL_HAS_ECC
220 221
int	sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g);
int	sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v);
222 223
int	sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g);
int	sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v);
224 225
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
226

227
/* Dump the contents of the buffer in a human-readable format */
228 229
void	sshbuf_dump(struct sshbuf *buf, FILE *f);

230 231 232
/* Dump specified memory in a human-readable format */
void	sshbuf_dump_data(const void *s, size_t len, FILE *f);

233 234 235 236 237 238 239 240 241
/* Return the hexadecimal representation of the contents of the buffer */
char	*sshbuf_dtob16(struct sshbuf *buf);

/* Encode the contents of the buffer as base64 */
char	*sshbuf_dtob64(struct sshbuf *buf);

/* Decode base64 data and append it to the buffer */
int	sshbuf_b64tod(struct sshbuf *buf, const char *b64);

djm@openbsd.org's avatar
djm@openbsd.org committed
242 243 244 245 246 247 248
/*
 * Duplicate the contents of a buffer to a string (caller to free).
 * Returns NULL on buffer error, or if the buffer contains a premature
 * nul character.
 */
char *sshbuf_dup_string(struct sshbuf *buf);

249 250
/* Macros for decoding/encoding integers */
#define PEEK_U64(p) \
djm@openbsd.org's avatar
djm@openbsd.org committed
251 252 253 254 255 256 257 258
	(((u_int64_t)(((const u_char *)(p))[0]) << 56) | \
	 ((u_int64_t)(((const u_char *)(p))[1]) << 48) | \
	 ((u_int64_t)(((const u_char *)(p))[2]) << 40) | \
	 ((u_int64_t)(((const u_char *)(p))[3]) << 32) | \
	 ((u_int64_t)(((const u_char *)(p))[4]) << 24) | \
	 ((u_int64_t)(((const u_char *)(p))[5]) << 16) | \
	 ((u_int64_t)(((const u_char *)(p))[6]) << 8) | \
	  (u_int64_t)(((const u_char *)(p))[7]))
259
#define PEEK_U32(p) \
djm@openbsd.org's avatar
djm@openbsd.org committed
260 261 262 263
	(((u_int32_t)(((const u_char *)(p))[0]) << 24) | \
	 ((u_int32_t)(((const u_char *)(p))[1]) << 16) | \
	 ((u_int32_t)(((const u_char *)(p))[2]) << 8) | \
	  (u_int32_t)(((const u_char *)(p))[3]))
264
#define PEEK_U16(p) \
djm@openbsd.org's avatar
djm@openbsd.org committed
265 266
	(((u_int16_t)(((const u_char *)(p))[0]) << 8) | \
	  (u_int16_t)(((const u_char *)(p))[1]))
267 268 269

#define POKE_U64(p, v) \
	do { \
djm@openbsd.org's avatar
djm@openbsd.org committed
270 271 272 273 274 275 276 277 278
		const u_int64_t __v = (v); \
		((u_char *)(p))[0] = (__v >> 56) & 0xff; \
		((u_char *)(p))[1] = (__v >> 48) & 0xff; \
		((u_char *)(p))[2] = (__v >> 40) & 0xff; \
		((u_char *)(p))[3] = (__v >> 32) & 0xff; \
		((u_char *)(p))[4] = (__v >> 24) & 0xff; \
		((u_char *)(p))[5] = (__v >> 16) & 0xff; \
		((u_char *)(p))[6] = (__v >> 8) & 0xff; \
		((u_char *)(p))[7] = __v & 0xff; \
279 280 281
	} while (0)
#define POKE_U32(p, v) \
	do { \
djm@openbsd.org's avatar
djm@openbsd.org committed
282 283 284 285 286
		const u_int32_t __v = (v); \
		((u_char *)(p))[0] = (__v >> 24) & 0xff; \
		((u_char *)(p))[1] = (__v >> 16) & 0xff; \
		((u_char *)(p))[2] = (__v >> 8) & 0xff; \
		((u_char *)(p))[3] = __v & 0xff; \
287 288 289
	} while (0)
#define POKE_U16(p, v) \
	do { \
djm@openbsd.org's avatar
djm@openbsd.org committed
290 291 292
		const u_int16_t __v = (v); \
		((u_char *)(p))[0] = (__v >> 8) & 0xff; \
		((u_char *)(p))[1] = __v & 0xff; \
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
	} while (0)

/* Internal definitions follow. Exposed for regress tests */
#ifdef SSHBUF_INTERNAL

/*
 * Return the allocation size of buf
 */
size_t	sshbuf_alloc(const struct sshbuf *buf);

/*
 * Increment the reference count of buf.
 */
int	sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent);

/*
 * Return the parent buffer of buf, or NULL if it has no parent.
 */
const struct sshbuf *sshbuf_parent(const struct sshbuf *buf);

/*
 * Return the reference count of buf
 */
u_int	sshbuf_refcount(const struct sshbuf *buf);

# define SSHBUF_SIZE_INIT	256		/* Initial allocation */
# define SSHBUF_SIZE_INC	256		/* Preferred increment length */
# define SSHBUF_PACK_MIN	8192		/* Minimim packable offset */

/* # define SSHBUF_ABORT abort */
/* # define SSHBUF_DEBUG */

# ifndef SSHBUF_ABORT
#  define SSHBUF_ABORT()
# endif

# ifdef SSHBUF_DEBUG
#  define SSHBUF_TELL(what) do { \
		printf("%s:%d %s: %s size %zu alloc %zu off %zu max %zu\n", \
		    __FILE__, __LINE__, __func__, what, \
		    buf->size, buf->alloc, buf->off, buf->max_size); \
		fflush(stdout); \
	} while (0)
#  define SSHBUF_DBG(x) do { \
		printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \
		printf x; \
		printf("\n"); \
		fflush(stdout); \
	} while (0)
# else
#  define SSHBUF_TELL(what)
#  define SSHBUF_DBG(x)
# endif
#endif /* SSHBUF_INTERNAL */

#endif /* _SSHBUF_H */