mirror of git://anongit.mindrot.org/openssh.git
- djm@cvs.openbsd.org 2014/04/30 05:29:56
[bufaux.c bufbn.c bufec.c buffer.c buffer.h sshbuf-getput-basic.c] [sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c sshbuf.h ssherr.c] [ssherr.h] New buffer API; the first installment of the conversion/replacement of OpenSSH's internals to make them usable as a standalone library. This includes a set of wrappers to make it compatible with the existing buffer API so replacement can occur incrementally. With and ok markus@ Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew Dempsky and Ron Bowes for a detailed review.
This commit is contained in:
parent
380948180f
commit
05e82c3b96
14
ChangeLog
14
ChangeLog
|
@ -52,6 +52,20 @@
|
|||
Don't attempt to append a nul quote char to the filename. Should prevent
|
||||
fatal'ing with "el_insertstr failed" when there's a single quote char
|
||||
somewhere in the string. bz#2238, ok markus@
|
||||
- djm@cvs.openbsd.org 2014/04/30 05:29:56
|
||||
[bufaux.c bufbn.c bufec.c buffer.c buffer.h sshbuf-getput-basic.c]
|
||||
[sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c sshbuf.h ssherr.c]
|
||||
[ssherr.h]
|
||||
New buffer API; the first installment of the conversion/replacement
|
||||
of OpenSSH's internals to make them usable as a standalone library.
|
||||
|
||||
This includes a set of wrappers to make it compatible with the
|
||||
existing buffer API so replacement can occur incrementally.
|
||||
|
||||
With and ok markus@
|
||||
|
||||
Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew
|
||||
Dempsky and Ron Bowes for a detailed review.
|
||||
|
||||
20140430
|
||||
- (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already
|
||||
|
|
330
bufaux.c
330
bufaux.c
|
@ -1,68 +1,38 @@
|
|||
/* $OpenBSD: bufaux.c,v 1.59 2014/04/29 18:01:49 markus Exp $ */
|
||||
/* $OpenBSD: bufaux.c,v 1.60 2014/04/30 05:29:56 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Auxiliary functions for storing and retrieving various data types to/from
|
||||
* Buffers.
|
||||
* Copyright (c) 2012 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* SSH2 packet format added by Markus Friedl
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
|
||||
/*
|
||||
* Returns integers from the buffer (msb first).
|
||||
*/
|
||||
#include "ssherr.h"
|
||||
|
||||
int
|
||||
buffer_get_short_ret(u_short *ret, Buffer *buffer)
|
||||
buffer_get_short_ret(u_short *v, Buffer *buffer)
|
||||
{
|
||||
u_char buf[2];
|
||||
int ret;
|
||||
|
||||
if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
|
||||
return (-1);
|
||||
*ret = get_u16(buf);
|
||||
return (0);
|
||||
if ((ret = sshbuf_get_u16(buffer, v)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_short
|
||||
|
@ -71,21 +41,21 @@ buffer_get_short(Buffer *buffer)
|
|||
u_short ret;
|
||||
|
||||
if (buffer_get_short_ret(&ret, buffer) == -1)
|
||||
fatal("buffer_get_short: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
buffer_get_int_ret(u_int *ret, Buffer *buffer)
|
||||
buffer_get_int_ret(u_int *v, Buffer *buffer)
|
||||
{
|
||||
u_char buf[4];
|
||||
int ret;
|
||||
|
||||
if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
|
||||
return (-1);
|
||||
if (ret != NULL)
|
||||
*ret = get_u32(buf);
|
||||
return (0);
|
||||
if ((ret = sshbuf_get_u32(buffer, v)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_int
|
||||
|
@ -94,21 +64,21 @@ buffer_get_int(Buffer *buffer)
|
|||
u_int ret;
|
||||
|
||||
if (buffer_get_int_ret(&ret, buffer) == -1)
|
||||
fatal("buffer_get_int: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
|
||||
buffer_get_int64_ret(u_int64_t *v, Buffer *buffer)
|
||||
{
|
||||
u_char buf[8];
|
||||
int ret;
|
||||
|
||||
if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
|
||||
return (-1);
|
||||
if (ret != NULL)
|
||||
*ret = get_u64(buf);
|
||||
return (0);
|
||||
if ((ret = sshbuf_get_u64(buffer, v)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_int64_t
|
||||
|
@ -117,78 +87,52 @@ buffer_get_int64(Buffer *buffer)
|
|||
u_int64_t ret;
|
||||
|
||||
if (buffer_get_int64_ret(&ret, buffer) == -1)
|
||||
fatal("buffer_get_int: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores integers in the buffer, msb first.
|
||||
*/
|
||||
void
|
||||
buffer_put_short(Buffer *buffer, u_short value)
|
||||
{
|
||||
char buf[2];
|
||||
int ret;
|
||||
|
||||
put_u16(buf, value);
|
||||
buffer_append(buffer, buf, 2);
|
||||
if ((ret = sshbuf_put_u16(buffer, value)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
void
|
||||
buffer_put_int(Buffer *buffer, u_int value)
|
||||
{
|
||||
char buf[4];
|
||||
int ret;
|
||||
|
||||
put_u32(buf, value);
|
||||
buffer_append(buffer, buf, 4);
|
||||
if ((ret = sshbuf_put_u32(buffer, value)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
void
|
||||
buffer_put_int64(Buffer *buffer, u_int64_t value)
|
||||
{
|
||||
char buf[8];
|
||||
int ret;
|
||||
|
||||
put_u64(buf, value);
|
||||
buffer_append(buffer, buf, 8);
|
||||
if ((ret = sshbuf_put_u64(buffer, value)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an arbitrary binary string from the buffer. The string cannot
|
||||
* be longer than 256k. The returned value points to memory allocated
|
||||
* with xmalloc; it is the responsibility of the calling function to free
|
||||
* the data. If length_ptr is non-NULL, the length of the returned data
|
||||
* will be stored there. A null character will be automatically appended
|
||||
* to the returned string, and is not counted in length.
|
||||
*/
|
||||
void *
|
||||
buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
|
||||
{
|
||||
size_t len;
|
||||
int ret;
|
||||
u_char *value;
|
||||
u_int len;
|
||||
|
||||
/* Get the length. */
|
||||
if (buffer_get_int_ret(&len, buffer) != 0) {
|
||||
error("buffer_get_string_ret: cannot extract length");
|
||||
return (NULL);
|
||||
if ((ret = sshbuf_get_string(buffer, &value, &len)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return NULL;
|
||||
}
|
||||
if (len > 256 * 1024) {
|
||||
error("buffer_get_string_ret: bad string length %u", len);
|
||||
return (NULL);
|
||||
}
|
||||
/* Allocate space for the string. Add one byte for a null character. */
|
||||
value = xmalloc(len + 1);
|
||||
/* Get the string. */
|
||||
if (buffer_get_ret(buffer, value, len) == -1) {
|
||||
error("buffer_get_string_ret: buffer_get failed");
|
||||
free(value);
|
||||
return (NULL);
|
||||
}
|
||||
/* Append a null character to make processing easier. */
|
||||
value[len] = '\0';
|
||||
/* Optionally return the length of the string. */
|
||||
if (length_ptr)
|
||||
*length_ptr = len;
|
||||
return (value);
|
||||
if (length_ptr != NULL)
|
||||
*length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
|
||||
return value;
|
||||
}
|
||||
|
||||
void *
|
||||
|
@ -197,31 +141,24 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr)
|
|||
void *ret;
|
||||
|
||||
if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
|
||||
fatal("buffer_get_string: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
char *
|
||||
buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr)
|
||||
{
|
||||
u_int length;
|
||||
char *cp, *ret = buffer_get_string_ret(buffer, &length);
|
||||
size_t len;
|
||||
int ret;
|
||||
char *value;
|
||||
|
||||
if (ret == NULL)
|
||||
if ((ret = sshbuf_get_cstring(buffer, &value, &len)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return NULL;
|
||||
if ((cp = memchr(ret, '\0', length)) != NULL) {
|
||||
/* XXX allow \0 at end-of-string for a while, remove later */
|
||||
if (cp == ret + length - 1)
|
||||
error("buffer_get_cstring_ret: string contains \\0");
|
||||
else {
|
||||
explicit_bzero(ret, length);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (length_ptr != NULL)
|
||||
*length_ptr = length;
|
||||
return ret;
|
||||
*length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
|
||||
return value;
|
||||
}
|
||||
|
||||
char *
|
||||
|
@ -230,27 +167,24 @@ buffer_get_cstring(Buffer *buffer, u_int *length_ptr)
|
|||
char *ret;
|
||||
|
||||
if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL)
|
||||
fatal("buffer_get_cstring: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const void *
|
||||
buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr)
|
||||
{
|
||||
void *ptr;
|
||||
u_int len;
|
||||
size_t len;
|
||||
int ret;
|
||||
const u_char *value;
|
||||
|
||||
if (buffer_get_int_ret(&len, buffer) != 0)
|
||||
return NULL;
|
||||
if (len > 256 * 1024) {
|
||||
error("buffer_get_string_ptr: bad string length %u", len);
|
||||
if ((ret = sshbuf_get_string_direct(buffer, &value, &len)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return NULL;
|
||||
}
|
||||
ptr = buffer_ptr(buffer);
|
||||
buffer_consume(buffer, len);
|
||||
if (length_ptr)
|
||||
*length_ptr = len;
|
||||
return (ptr);
|
||||
if (length_ptr != NULL)
|
||||
*length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
|
||||
return value;
|
||||
}
|
||||
|
||||
const void *
|
||||
|
@ -259,133 +193,65 @@ buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
|
|||
const void *ret;
|
||||
|
||||
if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL)
|
||||
fatal("buffer_get_string_ptr: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores and arbitrary binary string in the buffer.
|
||||
*/
|
||||
void
|
||||
buffer_put_string(Buffer *buffer, const void *buf, u_int len)
|
||||
{
|
||||
buffer_put_int(buffer, len);
|
||||
buffer_append(buffer, buf, len);
|
||||
int ret;
|
||||
|
||||
if ((ret = sshbuf_put_string(buffer, buf, len)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
void
|
||||
buffer_put_cstring(Buffer *buffer, const char *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
fatal("buffer_put_cstring: s == NULL");
|
||||
buffer_put_string(buffer, s, strlen(s));
|
||||
int ret;
|
||||
|
||||
if ((ret = sshbuf_put_cstring(buffer, s)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a character from the buffer (0 - 255).
|
||||
*/
|
||||
int
|
||||
buffer_get_char_ret(u_char *ret, Buffer *buffer)
|
||||
buffer_get_char_ret(char *v, Buffer *buffer)
|
||||
{
|
||||
if (buffer_get_ret(buffer, ret, 1) == -1) {
|
||||
error("buffer_get_char_ret: buffer_get_ret failed");
|
||||
return (-1);
|
||||
int ret;
|
||||
|
||||
if ((ret = sshbuf_get_u8(buffer, (u_char *)v)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
buffer_get_char(Buffer *buffer)
|
||||
{
|
||||
u_char ch;
|
||||
char ch;
|
||||
|
||||
if (buffer_get_char_ret(&ch, buffer) == -1)
|
||||
fatal("buffer_get_char: buffer error");
|
||||
return ch;
|
||||
fatal("%s: buffer error", __func__);
|
||||
return (u_char) ch;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores a character in the buffer.
|
||||
*/
|
||||
void
|
||||
buffer_put_char(Buffer *buffer, int value)
|
||||
{
|
||||
char ch = value;
|
||||
int ret;
|
||||
|
||||
buffer_append(buffer, &ch, 1);
|
||||
if ((ret = sshbuf_put_u8(buffer, value)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
/* Pseudo bignum functions */
|
||||
|
||||
void *
|
||||
buffer_get_bignum2_as_string_ret(Buffer *buffer, u_int *length_ptr)
|
||||
{
|
||||
u_int len;
|
||||
u_char *bin, *p, *ret;
|
||||
|
||||
if ((p = bin = buffer_get_string_ret(buffer, &len)) == NULL) {
|
||||
error("%s: invalid bignum", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len > 0 && (bin[0] & 0x80)) {
|
||||
error("%s: negative numbers not supported", __func__);
|
||||
free(bin);
|
||||
return NULL;
|
||||
}
|
||||
if (len > 8 * 1024) {
|
||||
error("%s: cannot handle BN of size %d", __func__, len);
|
||||
free(bin);
|
||||
return NULL;
|
||||
}
|
||||
/* Skip zero prefix on numbers with the MSB set */
|
||||
if (len > 1 && bin[0] == 0x00 && (bin[1] & 0x80) != 0) {
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
ret = xmalloc(len);
|
||||
memcpy(ret, p, len);
|
||||
explicit_bzero(p, len);
|
||||
free(bin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *
|
||||
buffer_get_bignum2_as_string(Buffer *buffer, u_int *l)
|
||||
{
|
||||
void *ret = buffer_get_bignum2_as_string_ret(buffer, l);
|
||||
|
||||
if (ret == NULL)
|
||||
fatal("%s: buffer error", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores a string using the bignum encoding rules (\0 pad if MSB set).
|
||||
*/
|
||||
void
|
||||
buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l)
|
||||
{
|
||||
u_char *buf, *p;
|
||||
int pad = 0;
|
||||
int ret;
|
||||
|
||||
if (l > 8 * 1024)
|
||||
fatal("%s: length %u too long", __func__, l);
|
||||
/* Skip leading zero bytes */
|
||||
for (; l > 0 && *s == 0; l--, s++)
|
||||
;
|
||||
p = buf = xmalloc(l + 1);
|
||||
/*
|
||||
* If most significant bit is set then prepend a zero byte to
|
||||
* avoid interpretation as a negative number.
|
||||
*/
|
||||
if (l > 0 && (s[0] & 0x80) != 0) {
|
||||
*p++ = '\0';
|
||||
pad = 1;
|
||||
}
|
||||
memcpy(p, s, l);
|
||||
buffer_put_string(buffer, buf, l + pad);
|
||||
explicit_bzero(buf, l + pad);
|
||||
free(buf);
|
||||
if ((ret = sshbuf_put_bignum2_bytes(buffer, s, l)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
|
||||
|
|
206
bufbn.c
206
bufbn.c
|
@ -1,229 +1,101 @@
|
|||
/* $OpenBSD: bufbn.c,v 1.11 2014/02/27 08:25:09 djm Exp $*/
|
||||
/* $OpenBSD: bufbn.c,v 1.12 2014/04/30 05:29:56 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Auxiliary functions for storing and retrieving various data types to/from
|
||||
* Buffers.
|
||||
* Copyright (c) 2012 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* SSH2 packet format added by Markus Friedl
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
#include "ssherr.h"
|
||||
|
||||
/*
|
||||
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
|
||||
* by (bits+7)/8 bytes of binary data, msb first.
|
||||
*/
|
||||
int
|
||||
buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
|
||||
{
|
||||
int bits = BN_num_bits(value);
|
||||
int bin_size = (bits + 7) / 8;
|
||||
u_char *buf = xmalloc(bin_size);
|
||||
int oi;
|
||||
char msg[2];
|
||||
int ret;
|
||||
|
||||
/* Get the value of in binary */
|
||||
oi = BN_bn2bin(value, buf);
|
||||
if (oi != bin_size) {
|
||||
error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
|
||||
oi, bin_size);
|
||||
free(buf);
|
||||
return (-1);
|
||||
if ((ret = sshbuf_put_bignum1(buffer, value)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Store the number of bits in the buffer in two bytes, msb first. */
|
||||
put_u16(msg, bits);
|
||||
buffer_append(buffer, msg, 2);
|
||||
/* Store the binary data. */
|
||||
buffer_append(buffer, buf, oi);
|
||||
|
||||
explicit_bzero(buf, bin_size);
|
||||
free(buf);
|
||||
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
|
||||
{
|
||||
if (buffer_put_bignum_ret(buffer, value) == -1)
|
||||
fatal("buffer_put_bignum: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves a BIGNUM from the buffer.
|
||||
*/
|
||||
int
|
||||
buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
u_int bits, bytes;
|
||||
u_char buf[2], *bin;
|
||||
int ret;
|
||||
|
||||
/* Get the number of bits. */
|
||||
if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
|
||||
error("buffer_get_bignum_ret: invalid length");
|
||||
return (-1);
|
||||
if ((ret = sshbuf_get_bignum1(buffer, value)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
bits = get_u16(buf);
|
||||
if (bits > 65535-7) {
|
||||
error("buffer_get_bignum_ret: cannot handle BN of size %d",
|
||||
bits);
|
||||
return (-1);
|
||||
}
|
||||
/* Compute the number of binary bytes that follow. */
|
||||
bytes = (bits + 7) / 8;
|
||||
if (bytes > 8 * 1024) {
|
||||
error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
|
||||
return (-1);
|
||||
}
|
||||
if (buffer_len(buffer) < bytes) {
|
||||
error("buffer_get_bignum_ret: input buffer too small");
|
||||
return (-1);
|
||||
}
|
||||
bin = buffer_ptr(buffer);
|
||||
if (BN_bin2bn(bin, bytes, value) == NULL) {
|
||||
error("buffer_get_bignum_ret: BN_bin2bn failed");
|
||||
return (-1);
|
||||
}
|
||||
if (buffer_consume_ret(buffer, bytes) == -1) {
|
||||
error("buffer_get_bignum_ret: buffer_consume failed");
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
if (buffer_get_bignum_ret(buffer, value) == -1)
|
||||
fatal("buffer_get_bignum: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores a BIGNUM in the buffer in SSH2 format.
|
||||
*/
|
||||
int
|
||||
buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
|
||||
{
|
||||
u_int bytes;
|
||||
u_char *buf;
|
||||
int oi;
|
||||
u_int hasnohigh = 0;
|
||||
int ret;
|
||||
|
||||
if (BN_is_zero(value)) {
|
||||
buffer_put_int(buffer, 0);
|
||||
return 0;
|
||||
if ((ret = sshbuf_put_bignum2(buffer, value)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
if (value->neg) {
|
||||
error("buffer_put_bignum2_ret: negative numbers not supported");
|
||||
return (-1);
|
||||
}
|
||||
bytes = BN_num_bytes(value) + 1; /* extra padding byte */
|
||||
if (bytes < 2) {
|
||||
error("buffer_put_bignum2_ret: BN too small");
|
||||
return (-1);
|
||||
}
|
||||
buf = xmalloc(bytes);
|
||||
buf[0] = 0x00;
|
||||
/* Get the value of in binary */
|
||||
oi = BN_bn2bin(value, buf+1);
|
||||
if (oi < 0 || (u_int)oi != bytes - 1) {
|
||||
error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
|
||||
"oi %d != bin_size %d", oi, bytes);
|
||||
free(buf);
|
||||
return (-1);
|
||||
}
|
||||
hasnohigh = (buf[1] & 0x80) ? 0 : 1;
|
||||
buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
|
||||
explicit_bzero(buf, bytes);
|
||||
free(buf);
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
|
||||
{
|
||||
if (buffer_put_bignum2_ret(buffer, value) == -1)
|
||||
fatal("buffer_put_bignum2: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
||||
int
|
||||
buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
u_int len;
|
||||
u_char *bin;
|
||||
int ret;
|
||||
|
||||
if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
|
||||
error("buffer_get_bignum2_ret: invalid bignum");
|
||||
return (-1);
|
||||
if ((ret = sshbuf_get_bignum2(buffer, value)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len > 0 && (bin[0] & 0x80)) {
|
||||
error("buffer_get_bignum2_ret: negative numbers not supported");
|
||||
free(bin);
|
||||
return (-1);
|
||||
}
|
||||
if (len > 8 * 1024) {
|
||||
error("buffer_get_bignum2_ret: cannot handle BN of size %d",
|
||||
len);
|
||||
free(bin);
|
||||
return (-1);
|
||||
}
|
||||
if (BN_bin2bn(bin, len, value) == NULL) {
|
||||
error("buffer_get_bignum2_ret: BN_bin2bn failed");
|
||||
free(bin);
|
||||
return (-1);
|
||||
}
|
||||
free(bin);
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
if (buffer_get_bignum2_ret(buffer, value) == -1)
|
||||
fatal("buffer_get_bignum2: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
|
107
bufec.c
107
bufec.c
|
@ -1,6 +1,7 @@
|
|||
/* $OpenBSD: bufec.c,v 1.3 2014/01/31 16:39:19 tedu Exp $ */
|
||||
/* $OpenBSD: bufec.c,v 1.4 2014/04/30 05:29:56 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Damien Miller <djm@mindrot.org>
|
||||
* Copyright (c) 2012 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -15,73 +16,25 @@
|
|||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef OPENSSL_HAS_ECC
|
||||
/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
#include "ssherr.h"
|
||||
|
||||
/*
|
||||
* Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed
|
||||
* encoding represents this as two bitstring points that should each
|
||||
* be no longer than the field length, SEC1 specifies a 1 byte
|
||||
* point type header.
|
||||
* Being paranoid here may insulate us to parsing problems in
|
||||
* EC_POINT_oct2point.
|
||||
*/
|
||||
#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1)
|
||||
|
||||
/*
|
||||
* Append an EC_POINT to the buffer as a string containing a SEC1 encoded
|
||||
* uncompressed point. Fortunately OpenSSL handles the gory details for us.
|
||||
*/
|
||||
int
|
||||
buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
|
||||
const EC_POINT *point)
|
||||
{
|
||||
u_char *buf = NULL;
|
||||
size_t len;
|
||||
BN_CTX *bnctx;
|
||||
int ret = -1;
|
||||
int ret;
|
||||
|
||||
/* Determine length */
|
||||
if ((bnctx = BN_CTX_new()) == NULL)
|
||||
fatal("%s: BN_CTX_new failed", __func__);
|
||||
len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
|
||||
NULL, 0, bnctx);
|
||||
if (len > BUFFER_MAX_ECPOINT_LEN) {
|
||||
error("%s: giant EC point: len = %lu (max %u)",
|
||||
__func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN);
|
||||
goto out;
|
||||
if ((ret = sshbuf_put_ec(buffer, point, curve)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
/* Convert */
|
||||
buf = xmalloc(len);
|
||||
if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
|
||||
buf, len, bnctx) != len) {
|
||||
error("%s: EC_POINT_point2oct length mismatch", __func__);
|
||||
goto out;
|
||||
}
|
||||
/* Append */
|
||||
buffer_put_string(buffer, buf, len);
|
||||
ret = 0;
|
||||
out:
|
||||
if (buf != NULL) {
|
||||
explicit_bzero(buf, len);
|
||||
free(buf);
|
||||
}
|
||||
BN_CTX_free(bnctx);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -96,43 +49,13 @@ int
|
|||
buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
|
||||
EC_POINT *point)
|
||||
{
|
||||
u_char *buf;
|
||||
u_int len;
|
||||
BN_CTX *bnctx;
|
||||
int ret = -1;
|
||||
int ret;
|
||||
|
||||
if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) {
|
||||
error("%s: invalid point", __func__);
|
||||
if ((ret = sshbuf_get_ec(buffer, point, curve)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
if ((bnctx = BN_CTX_new()) == NULL)
|
||||
fatal("%s: BN_CTX_new failed", __func__);
|
||||
if (len > BUFFER_MAX_ECPOINT_LEN) {
|
||||
error("%s: EC_POINT too long: %u > max %u", __func__,
|
||||
len, BUFFER_MAX_ECPOINT_LEN);
|
||||
goto out;
|
||||
}
|
||||
if (len == 0) {
|
||||
error("%s: EC_POINT buffer is empty", __func__);
|
||||
goto out;
|
||||
}
|
||||
if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) {
|
||||
error("%s: EC_POINT is in an incorrect form: "
|
||||
"0x%02x (want 0x%02x)", __func__, buf[0],
|
||||
POINT_CONVERSION_UNCOMPRESSED);
|
||||
goto out;
|
||||
}
|
||||
if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) {
|
||||
error("buffer_get_bignum2_ret: BN_bin2bn failed");
|
||||
goto out;
|
||||
}
|
||||
/* EC_POINT_oct2point verifies that the point is on the curve for us */
|
||||
ret = 0;
|
||||
out:
|
||||
BN_CTX_free(bnctx);
|
||||
explicit_bzero(buf, len);
|
||||
free(buf);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -143,4 +66,4 @@ buffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve,
|
|||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_HAS_ECC */
|
||||
|
||||
|
|
247
buffer.c
247
buffer.c
|
@ -1,253 +1,116 @@
|
|||
/* $OpenBSD: buffer.c,v 1.35 2014/02/02 03:44:31 djm Exp $ */
|
||||
/* $OpenBSD: buffer.c,v 1.36 2014/04/30 05:29:56 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for manipulating fifo buffers (that can grow if needed).
|
||||
* Copyright (c) 2012 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "log.h"
|
||||
|
||||
#define BUFFER_MAX_CHUNK 0x100000
|
||||
#define BUFFER_MAX_LEN 0xa00000
|
||||
#define BUFFER_ALLOCSZ 0x008000
|
||||
|
||||
/* Initializes the buffer structure. */
|
||||
|
||||
void
|
||||
buffer_init(Buffer *buffer)
|
||||
{
|
||||
const u_int len = 4096;
|
||||
|
||||
buffer->alloc = 0;
|
||||
buffer->buf = xmalloc(len);
|
||||
buffer->alloc = len;
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
|
||||
/* Frees any memory used for the buffer. */
|
||||
|
||||
void
|
||||
buffer_free(Buffer *buffer)
|
||||
{
|
||||
if (buffer->alloc > 0) {
|
||||
explicit_bzero(buffer->buf, buffer->alloc);
|
||||
buffer->alloc = 0;
|
||||
free(buffer->buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears any data from the buffer, making it empty. This does not actually
|
||||
* zero the memory.
|
||||
*/
|
||||
|
||||
void
|
||||
buffer_clear(Buffer *buffer)
|
||||
{
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
|
||||
/* Appends data to the buffer, expanding it if necessary. */
|
||||
#include "ssherr.h"
|
||||
|
||||
void
|
||||
buffer_append(Buffer *buffer, const void *data, u_int len)
|
||||
{
|
||||
void *p;
|
||||
p = buffer_append_space(buffer, len);
|
||||
memcpy(p, data, len);
|
||||
}
|
||||
int ret;
|
||||
|
||||
static int
|
||||
buffer_compact(Buffer *buffer)
|
||||
{
|
||||
/*
|
||||
* If the buffer is quite empty, but all data is at the end, move the
|
||||
* data to the beginning.
|
||||
*/
|
||||
if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
|
||||
memmove(buffer->buf, buffer->buf + buffer->offset,
|
||||
buffer->end - buffer->offset);
|
||||
buffer->end -= buffer->offset;
|
||||
buffer->offset = 0;
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
if ((ret = sshbuf_put(buffer, data, len)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends space to the buffer, expanding the buffer if necessary. This does
|
||||
* not actually copy the data into the buffer, but instead returns a pointer
|
||||
* to the allocated region.
|
||||
*/
|
||||
|
||||
void *
|
||||
buffer_append_space(Buffer *buffer, u_int len)
|
||||
{
|
||||
u_int newlen;
|
||||
void *p;
|
||||
int ret;
|
||||
u_char *p;
|
||||
|
||||
if (len > BUFFER_MAX_CHUNK)
|
||||
fatal("buffer_append_space: len %u not supported", len);
|
||||
|
||||
/* If the buffer is empty, start using it from the beginning. */
|
||||
if (buffer->offset == buffer->end) {
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
restart:
|
||||
/* If there is enough space to store all data, store it now. */
|
||||
if (buffer->end + len < buffer->alloc) {
|
||||
p = buffer->buf + buffer->end;
|
||||
buffer->end += len;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Compact data back to the start of the buffer if necessary */
|
||||
if (buffer_compact(buffer))
|
||||
goto restart;
|
||||
|
||||
/* Increase the size of the buffer and retry. */
|
||||
newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ);
|
||||
if (newlen > BUFFER_MAX_LEN)
|
||||
fatal("buffer_append_space: alloc %u not supported",
|
||||
newlen);
|
||||
buffer->buf = xrealloc(buffer->buf, 1, newlen);
|
||||
buffer->alloc = newlen;
|
||||
goto restart;
|
||||
/* NOTREACHED */
|
||||
if ((ret = sshbuf_reserve(buffer, len, &p)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether an allocation of 'len' will fit in the buffer
|
||||
* This must follow the same math as buffer_append_space
|
||||
*/
|
||||
int
|
||||
buffer_check_alloc(Buffer *buffer, u_int len)
|
||||
{
|
||||
if (buffer->offset == buffer->end) {
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
restart:
|
||||
if (buffer->end + len < buffer->alloc)
|
||||
return (1);
|
||||
if (buffer_compact(buffer))
|
||||
goto restart;
|
||||
if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN)
|
||||
return (1);
|
||||
return (0);
|
||||
int ret = sshbuf_check_reserve(buffer, len);
|
||||
|
||||
if (ret == 0)
|
||||
return 1;
|
||||
if (ret == SSH_ERR_NO_BUFFER_SPACE)
|
||||
return 0;
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
/* Returns the number of bytes of data in the buffer. */
|
||||
|
||||
u_int
|
||||
buffer_len(const Buffer *buffer)
|
||||
{
|
||||
return buffer->end - buffer->offset;
|
||||
}
|
||||
|
||||
/* Gets data from the beginning of the buffer. */
|
||||
|
||||
int
|
||||
buffer_get_ret(Buffer *buffer, void *buf, u_int len)
|
||||
{
|
||||
if (len > buffer->end - buffer->offset) {
|
||||
error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
|
||||
len, buffer->end - buffer->offset);
|
||||
return (-1);
|
||||
int ret;
|
||||
|
||||
if ((ret = sshbuf_get(buffer, buf, len)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
memcpy(buf, buffer->buf + buffer->offset, len);
|
||||
buffer->offset += len;
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_get(Buffer *buffer, void *buf, u_int len)
|
||||
{
|
||||
if (buffer_get_ret(buffer, buf, len) == -1)
|
||||
fatal("buffer_get: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
||||
/* Consumes the given number of bytes from the beginning of the buffer. */
|
||||
|
||||
int
|
||||
buffer_consume_ret(Buffer *buffer, u_int bytes)
|
||||
{
|
||||
if (bytes > buffer->end - buffer->offset) {
|
||||
error("buffer_consume_ret: trying to get more bytes than in buffer");
|
||||
return (-1);
|
||||
}
|
||||
buffer->offset += bytes;
|
||||
return (0);
|
||||
int ret = sshbuf_consume(buffer, bytes);
|
||||
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
if (ret == SSH_ERR_MESSAGE_INCOMPLETE)
|
||||
return -1;
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
void
|
||||
buffer_consume(Buffer *buffer, u_int bytes)
|
||||
{
|
||||
if (buffer_consume_ret(buffer, bytes) == -1)
|
||||
fatal("buffer_consume: buffer error");
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
||||
/* Consumes the given number of bytes from the end of the buffer. */
|
||||
|
||||
int
|
||||
buffer_consume_end_ret(Buffer *buffer, u_int bytes)
|
||||
{
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
return (-1);
|
||||
buffer->end -= bytes;
|
||||
return (0);
|
||||
int ret = sshbuf_consume_end(buffer, bytes);
|
||||
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
if (ret == SSH_ERR_MESSAGE_INCOMPLETE)
|
||||
return -1;
|
||||
fatal("%s: %s", __func__, ssh_err(ret));
|
||||
}
|
||||
|
||||
void
|
||||
buffer_consume_end(Buffer *buffer, u_int bytes)
|
||||
{
|
||||
if (buffer_consume_end_ret(buffer, bytes) == -1)
|
||||
fatal("buffer_consume_end: trying to get more bytes than in buffer");
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
||||
/* Returns a pointer to the first used byte in the buffer. */
|
||||
|
||||
void *
|
||||
buffer_ptr(const Buffer *buffer)
|
||||
{
|
||||
return buffer->buf + buffer->offset;
|
||||
}
|
||||
|
||||
/* Dumps the contents of the buffer to stderr. */
|
||||
|
||||
void
|
||||
buffer_dump(const Buffer *buffer)
|
||||
{
|
||||
u_int i;
|
||||
u_char *ucp = buffer->buf;
|
||||
|
||||
for (i = buffer->offset; i < buffer->end; i++) {
|
||||
fprintf(stderr, "%02x", ucp[i]);
|
||||
if ((i-buffer->offset)%16==15)
|
||||
fprintf(stderr, "\r\n");
|
||||
else if ((i-buffer->offset)%2==1)
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
fprintf(stderr, "\r\n");
|
||||
}
|
||||
|
|
64
buffer.h
64
buffer.h
|
@ -1,57 +1,58 @@
|
|||
/* $OpenBSD: buffer.h,v 1.24 2014/04/28 03:09:18 djm Exp $ */
|
||||
/* $OpenBSD: buffer.h,v 1.25 2014/04/30 05:29:56 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Code for manipulating FIFO buffers.
|
||||
* Copyright (c) 2012 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
|
||||
|
||||
#ifndef BUFFER_H
|
||||
#define BUFFER_H
|
||||
|
||||
typedef struct {
|
||||
u_char *buf; /* Buffer for data. */
|
||||
u_int alloc; /* Number of bytes allocated for data. */
|
||||
u_int offset; /* Offset of first byte containing data. */
|
||||
u_int end; /* Offset of last byte containing data. */
|
||||
} Buffer;
|
||||
#include "sshbuf.h"
|
||||
|
||||
void buffer_init(Buffer *);
|
||||
void buffer_clear(Buffer *);
|
||||
void buffer_free(Buffer *);
|
||||
typedef struct sshbuf Buffer;
|
||||
|
||||
u_int buffer_len(const Buffer *);
|
||||
void *buffer_ptr(const Buffer *);
|
||||
#define buffer_init(b) sshbuf_init(b)
|
||||
#define buffer_clear(b) sshbuf_reset(b)
|
||||
#define buffer_free(b) sshbuf_free(b)
|
||||
#define buffer_dump(b) sshbuf_dump(b, stderr)
|
||||
|
||||
/* XXX cast is safe: sshbuf never stores more than len 2^31 */
|
||||
#define buffer_len(b) ((u_int) sshbuf_len(b))
|
||||
#define buffer_ptr(b) sshbuf_mutable_ptr(b)
|
||||
|
||||
void buffer_append(Buffer *, const void *, u_int);
|
||||
void *buffer_append_space(Buffer *, u_int);
|
||||
|
||||
int buffer_check_alloc(Buffer *, u_int);
|
||||
|
||||
void buffer_get(Buffer *, void *, u_int);
|
||||
|
||||
void buffer_consume(Buffer *, u_int);
|
||||
void buffer_consume_end(Buffer *, u_int);
|
||||
|
||||
void buffer_dump(const Buffer *);
|
||||
|
||||
int buffer_get_ret(Buffer *, void *, u_int);
|
||||
int buffer_consume_ret(Buffer *, u_int);
|
||||
int buffer_consume_end_ret(Buffer *, u_int);
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
void buffer_put_bignum(Buffer *, const BIGNUM *);
|
||||
void buffer_put_bignum2(Buffer *, const BIGNUM *);
|
||||
void buffer_get_bignum(Buffer *, BIGNUM *);
|
||||
void buffer_get_bignum2(Buffer *, BIGNUM *);
|
||||
void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
|
||||
|
||||
u_short buffer_get_short(Buffer *);
|
||||
void buffer_put_short(Buffer *, u_short);
|
||||
|
@ -71,8 +72,7 @@ void buffer_put_string(Buffer *, const void *, u_int);
|
|||
char *buffer_get_cstring(Buffer *, u_int *);
|
||||
void buffer_put_cstring(Buffer *, const char *);
|
||||
|
||||
#define buffer_skip_string(b) \
|
||||
do { u_int l = buffer_get_int(b); buffer_consume(b, l); } while (0)
|
||||
#define buffer_skip_string(b) (void)buffer_get_string_ptr(b, NULL);
|
||||
|
||||
int buffer_put_bignum_ret(Buffer *, const BIGNUM *);
|
||||
int buffer_get_bignum_ret(Buffer *, BIGNUM *);
|
||||
|
@ -84,19 +84,15 @@ int buffer_get_int64_ret(u_int64_t *, Buffer *);
|
|||
void *buffer_get_string_ret(Buffer *, u_int *);
|
||||
char *buffer_get_cstring_ret(Buffer *, u_int *);
|
||||
const void *buffer_get_string_ptr_ret(Buffer *, u_int *);
|
||||
int buffer_get_char_ret(u_char *, Buffer *);
|
||||
|
||||
void *buffer_get_bignum2_as_string_ret(Buffer *, u_int *);
|
||||
void *buffer_get_bignum2_as_string(Buffer *, u_int *);
|
||||
void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
|
||||
int buffer_get_char_ret(char *, Buffer *);
|
||||
|
||||
#ifdef OPENSSL_HAS_ECC
|
||||
#include <openssl/ec.h>
|
||||
|
||||
int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *);
|
||||
void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *);
|
||||
int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *);
|
||||
void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *);
|
||||
#endif
|
||||
|
||||
#endif /* BUFFER_H */
|
||||
#endif /* BUFFER_H */
|
||||
|
||||
|
|
|
@ -0,0 +1,421 @@
|
|||
/* $OpenBSD: sshbuf-getput-basic.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ssherr.h"
|
||||
#define SSHBUF_INTERNAL
|
||||
#include "sshbuf.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
|
||||
{
|
||||
const u_char *p = sshbuf_ptr(buf);
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_consume(buf, 8)) < 0)
|
||||
return r;
|
||||
if (valp != NULL)
|
||||
*valp = PEEK_U64(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
|
||||
{
|
||||
const u_char *p = sshbuf_ptr(buf);
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_consume(buf, 4)) < 0)
|
||||
return r;
|
||||
if (valp != NULL)
|
||||
*valp = PEEK_U32(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_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_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
|
||||
{
|
||||
const u_char *val;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
if (valp != NULL)
|
||||
*valp = NULL;
|
||||
if (lenp != NULL)
|
||||
*lenp = 0;
|
||||
if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
|
||||
return r;
|
||||
if (valp != NULL) {
|
||||
if ((*valp = malloc(len + 1)) == NULL) {
|
||||
SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
}
|
||||
memcpy(*valp, val, len);
|
||||
(*valp)[len] = '\0';
|
||||
}
|
||||
if (lenp != NULL)
|
||||
*lenp = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
|
||||
{
|
||||
size_t len;
|
||||
const u_char *p;
|
||||
int r;
|
||||
|
||||
if (valp != NULL)
|
||||
*valp = NULL;
|
||||
if (lenp != NULL)
|
||||
*lenp = 0;
|
||||
if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
|
||||
return r;
|
||||
if (valp != 0)
|
||||
*valp = p;
|
||||
if (lenp != NULL)
|
||||
*lenp = len;
|
||||
if (sshbuf_consume(buf, len + 4) != 0) {
|
||||
/* Shouldn't happen */
|
||||
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
|
||||
SSHBUF_ABORT();
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
size_t len;
|
||||
const u_char *p, *z;
|
||||
int r;
|
||||
|
||||
if (valp != NULL)
|
||||
*valp = NULL;
|
||||
if (lenp != NULL)
|
||||
*lenp = 0;
|
||||
if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
|
||||
return r;
|
||||
/* Allow a \0 only at the end of the string */
|
||||
if (len > 0 &&
|
||||
(z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
|
||||
SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
}
|
||||
if ((r = sshbuf_skip_string(buf)) != 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, len);
|
||||
(*valp)[len] = '\0';
|
||||
}
|
||||
if (lenp != NULL)
|
||||
*lenp = (size_t)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(struct sshbuf *buf, const void *v, size_t len)
|
||||
{
|
||||
u_char *p;
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_reserve(buf, len, &p)) < 0)
|
||||
return r;
|
||||
memcpy(p, v, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
|
||||
{
|
||||
return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, fmt);
|
||||
r = sshbuf_putfv(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
|
||||
{
|
||||
va_list ap2;
|
||||
int r, len;
|
||||
u_char *p;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
if (len == 0) {
|
||||
r = 0;
|
||||
goto out; /* Nothing to do */
|
||||
}
|
||||
va_end(ap2);
|
||||
va_copy(ap2, ap);
|
||||
if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
|
||||
goto out;
|
||||
if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
|
||||
r = SSH_ERR_INTERNAL_ERROR;
|
||||
goto out; /* Shouldn't happen */
|
||||
}
|
||||
/* Consume terminating \0 */
|
||||
if ((r = sshbuf_consume_end(buf, 1)) != 0)
|
||||
goto out;
|
||||
r = 0;
|
||||
out:
|
||||
va_end(ap2);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
|
||||
{
|
||||
u_char *p;
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
|
||||
return r;
|
||||
POKE_U64(p, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
|
||||
{
|
||||
u_char *p;
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
|
||||
return r;
|
||||
POKE_U32(p, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
|
||||
{
|
||||
u_char *p;
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
|
||||
return r;
|
||||
POKE_U16(p, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_put_u8(struct sshbuf *buf, u_char val)
|
||||
{
|
||||
u_char *p;
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
|
||||
return r;
|
||||
p[0] = val;
|
||||
return 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);
|
||||
memcpy(d + 4, v, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_put_cstring(struct sshbuf *buf, const char *v)
|
||||
{
|
||||
return sshbuf_put_string(buf, (u_char *)v, strlen(v));
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
|
||||
{
|
||||
return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
|
||||
{
|
||||
const u_char *p;
|
||||
size_t len;
|
||||
struct sshbuf *ret;
|
||||
int r;
|
||||
|
||||
if (buf == NULL || bufp == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
*bufp = NULL;
|
||||
if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
|
||||
return r;
|
||||
if ((ret = sshbuf_from(p, len)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
|
||||
(r = sshbuf_set_parent(ret, buf)) != 0) {
|
||||
sshbuf_free(ret);
|
||||
return r;
|
||||
}
|
||||
*bufp = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
|
||||
{
|
||||
u_char *d;
|
||||
const u_char *s = (const u_char *)v;
|
||||
int r, prepend;
|
||||
|
||||
if (len > SSHBUF_SIZE_MAX - 5) {
|
||||
SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
|
||||
return SSH_ERR_NO_BUFFER_SPACE;
|
||||
}
|
||||
/* Skip leading zero bytes */
|
||||
for (; len > 0 && *s == 0; len--, s++)
|
||||
;
|
||||
/*
|
||||
* If most significant bit is set then prepend a zero byte to
|
||||
* avoid interpretation as a negative number.
|
||||
*/
|
||||
prepend = len > 0 && (s[0] & 0x80) != 0;
|
||||
if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
|
||||
return r;
|
||||
POKE_U32(d, len + prepend);
|
||||
if (prepend)
|
||||
d[4] = 0;
|
||||
memcpy(d + 4 + prepend, s, len);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
/* $OpenBSD: sshbuf-getput-crypto.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
|
||||
#include "ssherr.h"
|
||||
#define SSHBUF_INTERNAL
|
||||
#include "sshbuf.h"
|
||||
|
||||
int
|
||||
sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v)
|
||||
{
|
||||
const u_char *d;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
|
||||
return r;
|
||||
/* Refuse negative (MSB set) and overlong bignums */
|
||||
if ((len != 0 && (*d & 0x80) != 0))
|
||||
return SSH_ERR_BIGNUM_IS_NEGATIVE;
|
||||
if (len > SSHBUF_MAX_BIGNUM)
|
||||
return SSH_ERR_BIGNUM_TOO_LARGE;
|
||||
if (v != NULL && BN_bin2bn(d, len, v) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
/* Consume the string */
|
||||
if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
|
||||
/* Shouldn't happen */
|
||||
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
|
||||
SSHBUF_ABORT();
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 + 1)
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_HAS_ECC
|
||||
static int
|
||||
get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
|
||||
{
|
||||
/* Refuse overlong bignums */
|
||||
if (len == 0 || len > SSHBUF_MAX_ECPOINT)
|
||||
return SSH_ERR_ECPOINT_TOO_LARGE;
|
||||
/* Only handle uncompressed points */
|
||||
if (*d != POINT_CONVERSION_UNCOMPRESSED)
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
|
||||
return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
|
||||
{
|
||||
const u_char *d;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
|
||||
return r;
|
||||
if ((r = get_ec(d, len, v, g)) != 0)
|
||||
return r;
|
||||
/* Skip string */
|
||||
if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
|
||||
/* Shouldn't happen */
|
||||
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
|
||||
SSHBUF_ABORT();
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
|
||||
{
|
||||
EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
|
||||
int r;
|
||||
const u_char *d;
|
||||
size_t len;
|
||||
|
||||
if (pt == NULL) {
|
||||
SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
}
|
||||
if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
|
||||
EC_POINT_free(pt);
|
||||
return r;
|
||||
}
|
||||
if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
|
||||
EC_POINT_free(pt);
|
||||
return r;
|
||||
}
|
||||
if (EC_KEY_set_public_key(v, pt) != 1) {
|
||||
EC_POINT_free(pt);
|
||||
return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
|
||||
}
|
||||
EC_POINT_free(pt);
|
||||
/* Skip string */
|
||||
if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
|
||||
/* Shouldn't happen */
|
||||
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
|
||||
SSHBUF_ABORT();
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* OPENSSL_HAS_ECC */
|
||||
|
||||
int
|
||||
sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
|
||||
{
|
||||
u_char d[SSHBUF_MAX_BIGNUM + 1];
|
||||
int len = BN_num_bytes(v), prepend = 0, r;
|
||||
|
||||
if (len < 0 || len > SSHBUF_MAX_BIGNUM)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
*d = '\0';
|
||||
if (BN_bn2bin(v, d + 1) != len)
|
||||
return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
|
||||
/* If MSB is set, prepend a \0 */
|
||||
if (len > 0 && (d[1] & 0x80) != 0)
|
||||
prepend = 1;
|
||||
if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
|
||||
bzero(d, sizeof(d));
|
||||
return r;
|
||||
}
|
||||
bzero(d, sizeof(d));
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_HAS_ECC
|
||||
int
|
||||
sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
|
||||
{
|
||||
u_char d[SSHBUF_MAX_ECPOINT];
|
||||
BN_CTX *bn_ctx;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if ((bn_ctx = BN_CTX_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
|
||||
NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) {
|
||||
BN_CTX_free(bn_ctx);
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
|
||||
d, len, bn_ctx) != len) {
|
||||
BN_CTX_free(bn_ctx);
|
||||
return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
|
||||
}
|
||||
BN_CTX_free(bn_ctx);
|
||||
ret = sshbuf_put_string(buf, d, len);
|
||||
bzero(d, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
|
||||
{
|
||||
return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
|
||||
EC_KEY_get0_group(v));
|
||||
}
|
||||
#endif /* OPENSSL_HAS_ECC */
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/* $OpenBSD: sshbuf-misc.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <resolv.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ssherr.h"
|
||||
#define SSHBUF_INTERNAL
|
||||
#include "sshbuf.h"
|
||||
|
||||
void
|
||||
sshbuf_dump(struct sshbuf *buf, FILE *f)
|
||||
{
|
||||
const u_char *p = sshbuf_ptr(buf);
|
||||
size_t i, j, len = sshbuf_len(buf);
|
||||
|
||||
fprintf(f, "buffer %p len = %zu\n", buf, len);
|
||||
for (i = 0; i < len; i += 16) {
|
||||
fprintf(f, "%.4zd: ", i);
|
||||
for (j = i; j < i + 16; j++) {
|
||||
if (j < len)
|
||||
fprintf(f, "%02x ", p[j]);
|
||||
else
|
||||
fprintf(f, " ");
|
||||
}
|
||||
fprintf(f, " ");
|
||||
for (j = i; j < i + 16; j++) {
|
||||
if (j < len) {
|
||||
if (isascii(p[j]) && isprint(p[j]))
|
||||
fprintf(f, "%c", p[j]);
|
||||
else
|
||||
fprintf(f, ".");
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
sshbuf_dtob16(struct sshbuf *buf)
|
||||
{
|
||||
size_t i, j, len = sshbuf_len(buf);
|
||||
const u_char *p = sshbuf_ptr(buf);
|
||||
char *ret;
|
||||
const char hex[] = "0123456789abcdef";
|
||||
|
||||
if (len == 0)
|
||||
return strdup("");
|
||||
if (SIZE_MAX / 2 <= len || (ret = malloc(len * 2 + 1)) == NULL)
|
||||
return NULL;
|
||||
for (i = j = 0; i < len; i++) {
|
||||
ret[j++] = hex[(p[i] >> 4) & 0xf];
|
||||
ret[j++] = hex[p[i] & 0xf];
|
||||
}
|
||||
ret[j] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
sshbuf_dtob64(struct sshbuf *buf)
|
||||
{
|
||||
size_t len = sshbuf_len(buf), plen;
|
||||
const u_char *p = sshbuf_ptr(buf);
|
||||
char *ret;
|
||||
int r;
|
||||
|
||||
if (len == 0)
|
||||
return strdup("");
|
||||
plen = ((len + 2) / 3) * 4 + 1;
|
||||
if (SIZE_MAX / 2 <= len || (ret = malloc(plen)) == NULL)
|
||||
return NULL;
|
||||
if ((r = b64_ntop(p, len, ret, plen)) == -1) {
|
||||
bzero(ret, plen);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_b64tod(struct sshbuf *buf, const char *b64)
|
||||
{
|
||||
size_t plen = strlen(b64);
|
||||
int nlen, r;
|
||||
u_char *p;
|
||||
|
||||
if (plen == 0)
|
||||
return 0;
|
||||
if ((p = malloc(plen)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((nlen = b64_pton(b64, p, plen)) < 0) {
|
||||
bzero(p, plen);
|
||||
free(p);
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
}
|
||||
if ((r = sshbuf_put(buf, p, nlen)) < 0) {
|
||||
bzero(p, plen);
|
||||
free(p);
|
||||
return r;
|
||||
}
|
||||
bzero(p, plen);
|
||||
free(p);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
/* $OpenBSD: sshbuf.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ssherr.h"
|
||||
#define SSHBUF_INTERNAL
|
||||
#include "sshbuf.h"
|
||||
|
||||
static inline int
|
||||
sshbuf_check_sanity(const struct sshbuf *buf)
|
||||
{
|
||||
SSHBUF_TELL("sanity");
|
||||
if (__predict_false(buf == NULL ||
|
||||
(!buf->readonly && buf->d != buf->cd) ||
|
||||
buf->refcount < 1 || buf->refcount > SSHBUF_REFS_MAX ||
|
||||
buf->cd == NULL ||
|
||||
(buf->dont_free && (buf->readonly || buf->parent != NULL)) ||
|
||||
buf->max_size > SSHBUF_SIZE_MAX ||
|
||||
buf->alloc > buf->max_size ||
|
||||
buf->size > buf->alloc ||
|
||||
buf->off > buf->size)) {
|
||||
/* Do not try to recover from corrupted buffer internals */
|
||||
SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
|
||||
raise(SIGSEGV);
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sshbuf_maybe_pack(struct sshbuf *buf, int force)
|
||||
{
|
||||
SSHBUF_DBG(("force %d", force));
|
||||
SSHBUF_TELL("pre-pack");
|
||||
if (buf->off == 0 || buf->readonly || buf->refcount > 1)
|
||||
return;
|
||||
if (force ||
|
||||
(buf->off >= SSHBUF_PACK_MIN && buf->off >= buf->size / 2)) {
|
||||
memmove(buf->d, buf->d + buf->off, buf->size - buf->off);
|
||||
buf->size -= buf->off;
|
||||
buf->off = 0;
|
||||
SSHBUF_TELL("packed");
|
||||
}
|
||||
}
|
||||
|
||||
struct sshbuf *
|
||||
sshbuf_new(void)
|
||||
{
|
||||
struct sshbuf *ret;
|
||||
|
||||
if ((ret = calloc(sizeof(*ret), 1)) == NULL)
|
||||
return NULL;
|
||||
ret->alloc = SSHBUF_SIZE_INIT;
|
||||
ret->max_size = SSHBUF_SIZE_MAX;
|
||||
ret->readonly = 0;
|
||||
ret->refcount = 1;
|
||||
ret->parent = NULL;
|
||||
if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sshbuf *
|
||||
sshbuf_from(const void *blob, size_t len)
|
||||
{
|
||||
struct sshbuf *ret;
|
||||
|
||||
if (blob == NULL || len > SSHBUF_SIZE_MAX ||
|
||||
(ret = calloc(sizeof(*ret), 1)) == NULL)
|
||||
return NULL;
|
||||
ret->alloc = ret->size = ret->max_size = len;
|
||||
ret->readonly = 1;
|
||||
ret->refcount = 1;
|
||||
ret->parent = NULL;
|
||||
ret->cd = blob;
|
||||
ret->d = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_check_sanity(child)) != 0 ||
|
||||
(r = sshbuf_check_sanity(parent)) != 0)
|
||||
return r;
|
||||
child->parent = parent;
|
||||
child->parent->refcount++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
sshbuf_init(struct sshbuf *ret)
|
||||
{
|
||||
bzero(ret, sizeof(*ret));
|
||||
ret->alloc = SSHBUF_SIZE_INIT;
|
||||
ret->max_size = SSHBUF_SIZE_MAX;
|
||||
ret->readonly = 0;
|
||||
ret->dont_free = 1;
|
||||
ret->refcount = 1;
|
||||
if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL)
|
||||
ret->alloc = 0;
|
||||
}
|
||||
|
||||
void
|
||||
sshbuf_free(struct sshbuf *buf)
|
||||
{
|
||||
int dont_free = 0;
|
||||
|
||||
if (buf == NULL)
|
||||
return;
|
||||
/*
|
||||
* The following will leak on insane buffers, but this is the safest
|
||||
* course of action - an invalid pointer or already-freed pointer may
|
||||
* have been passed to us and continuing to scribble over memory would
|
||||
* be bad.
|
||||
*/
|
||||
if (sshbuf_check_sanity(buf) != 0)
|
||||
return;
|
||||
/*
|
||||
* If we are a child, the free our parent to decrement its reference
|
||||
* count and possibly free it.
|
||||
*/
|
||||
if (buf->parent != NULL) {
|
||||
sshbuf_free(buf->parent);
|
||||
buf->parent = NULL;
|
||||
}
|
||||
/*
|
||||
* If we are a parent with still-extant children, then don't free just
|
||||
* yet. The last child's call to sshbuf_free should decrement our
|
||||
* refcount to 0 and trigger the actual free.
|
||||
*/
|
||||
buf->refcount--;
|
||||
if (buf->refcount > 0)
|
||||
return;
|
||||
dont_free = buf->dont_free;
|
||||
if (!buf->readonly) {
|
||||
bzero(buf->d, buf->alloc);
|
||||
free(buf->d);
|
||||
}
|
||||
bzero(buf, sizeof(*buf));
|
||||
if (!dont_free)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void
|
||||
sshbuf_reset(struct sshbuf *buf)
|
||||
{
|
||||
u_char *d;
|
||||
|
||||
if (buf->readonly || buf->refcount > 1) {
|
||||
/* Nonsensical. Just make buffer appear empty */
|
||||
buf->off = buf->size;
|
||||
return;
|
||||
}
|
||||
if (sshbuf_check_sanity(buf) == 0)
|
||||
bzero(buf->d, buf->alloc);
|
||||
buf->off = buf->size = 0;
|
||||
if (buf->alloc != SSHBUF_SIZE_INIT) {
|
||||
if ((d = realloc(buf->d, SSHBUF_SIZE_INIT)) != NULL) {
|
||||
buf->cd = buf->d = d;
|
||||
buf->alloc = SSHBUF_SIZE_INIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
sshbuf_max_size(const struct sshbuf *buf)
|
||||
{
|
||||
return buf->max_size;
|
||||
}
|
||||
|
||||
size_t
|
||||
sshbuf_alloc(const struct sshbuf *buf)
|
||||
{
|
||||
return buf->alloc;
|
||||
}
|
||||
|
||||
const struct sshbuf *
|
||||
sshbuf_parent(const struct sshbuf *buf)
|
||||
{
|
||||
return buf->parent;
|
||||
}
|
||||
|
||||
u_int
|
||||
sshbuf_refcount(const struct sshbuf *buf)
|
||||
{
|
||||
return buf->refcount;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_set_max_size(struct sshbuf *buf, size_t max_size)
|
||||
{
|
||||
size_t rlen;
|
||||
u_char *dp;
|
||||
int r;
|
||||
|
||||
SSHBUF_DBG(("set max buf = %p len = %zu", buf, max_size));
|
||||
if ((r = sshbuf_check_sanity(buf)) != 0)
|
||||
return r;
|
||||
if (max_size == buf->max_size)
|
||||
return 0;
|
||||
if (buf->readonly || buf->refcount > 1)
|
||||
return SSH_ERR_BUFFER_READ_ONLY;
|
||||
if (max_size > SSHBUF_SIZE_MAX)
|
||||
return SSH_ERR_NO_BUFFER_SPACE;
|
||||
/* pack and realloc if necessary */
|
||||
sshbuf_maybe_pack(buf, max_size < buf->size);
|
||||
if (max_size < buf->alloc && max_size > buf->size) {
|
||||
if (buf->size < SSHBUF_SIZE_INIT)
|
||||
rlen = SSHBUF_SIZE_INIT;
|
||||
else
|
||||
rlen = roundup(buf->size, SSHBUF_SIZE_INC);
|
||||
if (rlen > max_size)
|
||||
rlen = max_size;
|
||||
bzero(buf->d + buf->size, buf->alloc - buf->size);
|
||||
SSHBUF_DBG(("new alloc = %zu", rlen));
|
||||
if ((dp = realloc(buf->d, rlen)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
buf->cd = buf->d = dp;
|
||||
buf->alloc = rlen;
|
||||
}
|
||||
SSHBUF_TELL("new-max");
|
||||
if (max_size < buf->alloc)
|
||||
return SSH_ERR_NO_BUFFER_SPACE;
|
||||
buf->max_size = max_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
sshbuf_len(const struct sshbuf *buf)
|
||||
{
|
||||
if (sshbuf_check_sanity(buf) != 0)
|
||||
return 0;
|
||||
return buf->size - buf->off;
|
||||
}
|
||||
|
||||
size_t
|
||||
sshbuf_avail(const struct sshbuf *buf)
|
||||
{
|
||||
if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
|
||||
return 0;
|
||||
return buf->max_size - (buf->size - buf->off);
|
||||
}
|
||||
|
||||
const u_char *
|
||||
sshbuf_ptr(const struct sshbuf *buf)
|
||||
{
|
||||
if (sshbuf_check_sanity(buf) != 0)
|
||||
return NULL;
|
||||
return buf->cd + buf->off;
|
||||
}
|
||||
|
||||
u_char *
|
||||
sshbuf_mutable_ptr(const struct sshbuf *buf)
|
||||
{
|
||||
if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
|
||||
return NULL;
|
||||
return buf->d + buf->off;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_check_reserve(const struct sshbuf *buf, size_t len)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_check_sanity(buf)) != 0)
|
||||
return r;
|
||||
if (buf->readonly || buf->refcount > 1)
|
||||
return SSH_ERR_BUFFER_READ_ONLY;
|
||||
SSHBUF_TELL("check");
|
||||
/* Check that len is reasonable and that max_size + available < len */
|
||||
if (len > buf->max_size || buf->max_size - len < buf->size - buf->off)
|
||||
return SSH_ERR_NO_BUFFER_SPACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp)
|
||||
{
|
||||
size_t rlen, need;
|
||||
u_char *dp;
|
||||
int r;
|
||||
|
||||
if (dpp != NULL)
|
||||
*dpp = NULL;
|
||||
|
||||
SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len));
|
||||
if ((r = sshbuf_check_reserve(buf, len)) != 0)
|
||||
return r;
|
||||
/*
|
||||
* If the requested allocation appended would push us past max_size
|
||||
* then pack the buffer, zeroing buf->off.
|
||||
*/
|
||||
sshbuf_maybe_pack(buf, buf->size + len > buf->max_size);
|
||||
SSHBUF_TELL("reserve");
|
||||
if (len + buf->size > buf->alloc) {
|
||||
/*
|
||||
* Prefer to alloc in SSHBUF_SIZE_INC units, but
|
||||
* allocate less if doing so would overflow max_size.
|
||||
*/
|
||||
need = len + buf->size - buf->alloc;
|
||||
rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC);
|
||||
SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen));
|
||||
if (rlen > buf->max_size)
|
||||
rlen = buf->alloc + need;
|
||||
SSHBUF_DBG(("adjusted rlen %zu", rlen));
|
||||
if ((dp = realloc(buf->d, rlen)) == NULL) {
|
||||
SSHBUF_DBG(("realloc fail"));
|
||||
if (dpp != NULL)
|
||||
*dpp = NULL;
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
}
|
||||
buf->alloc = rlen;
|
||||
buf->cd = buf->d = dp;
|
||||
if ((r = sshbuf_check_reserve(buf, len)) < 0) {
|
||||
/* shouldn't fail */
|
||||
if (dpp != NULL)
|
||||
*dpp = NULL;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
dp = buf->d + buf->size;
|
||||
buf->size += len;
|
||||
SSHBUF_TELL("done");
|
||||
if (dpp != NULL)
|
||||
*dpp = dp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_consume(struct sshbuf *buf, size_t len)
|
||||
{
|
||||
int r;
|
||||
|
||||
SSHBUF_DBG(("len = %zu", len));
|
||||
if ((r = sshbuf_check_sanity(buf)) != 0)
|
||||
return r;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (len > sshbuf_len(buf))
|
||||
return SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
buf->off += len;
|
||||
SSHBUF_TELL("done");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshbuf_consume_end(struct sshbuf *buf, size_t len)
|
||||
{
|
||||
int r;
|
||||
|
||||
SSHBUF_DBG(("len = %zu", len));
|
||||
if ((r = sshbuf_check_sanity(buf)) != 0)
|
||||
return r;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (len > sshbuf_len(buf))
|
||||
return SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
buf->size -= len;
|
||||
SSHBUF_TELL("done");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
/* $OpenBSD: sshbuf.h,v 1.1 2014/04/30 05:29:56 djm Exp $ */
|
||||
/*
|
||||
* 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>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
|
||||
#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 */
|
||||
};
|
||||
|
||||
#ifndef SSHBUF_NO_DEPREACTED
|
||||
/*
|
||||
* NB. Please do not use sshbuf_init() in new code. Please use sshbuf_new()
|
||||
* instead. sshbuf_init() is deprectated and will go away soon (it is
|
||||
* only included to allow compat with buffer_* in OpenSSH)
|
||||
*/
|
||||
void sshbuf_init(struct sshbuf *buf);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Returns a read-only pointer to the start of the the data in buf
|
||||
*/
|
||||
const u_char *sshbuf_ptr(const struct sshbuf *buf);
|
||||
|
||||
/*
|
||||
* Returns a mutable pointer to the start of the the data in buf, or
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Functions to extract or store SSH wire encoded bignums and elliptic
|
||||
* curve points.
|
||||
*/
|
||||
int sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v);
|
||||
int sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v);
|
||||
int sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g);
|
||||
int sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v);
|
||||
int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v);
|
||||
int sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v);
|
||||
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);
|
||||
int sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len);
|
||||
|
||||
/* Dump the contents of the buffer to stderr in a human-readable format */
|
||||
void sshbuf_dump(struct sshbuf *buf, FILE *f);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Macros for decoding/encoding integers */
|
||||
#define PEEK_U64(p) \
|
||||
(((u_int64_t)(((u_char *)(p))[0]) << 56) | \
|
||||
((u_int64_t)(((u_char *)(p))[1]) << 48) | \
|
||||
((u_int64_t)(((u_char *)(p))[2]) << 40) | \
|
||||
((u_int64_t)(((u_char *)(p))[3]) << 32) | \
|
||||
((u_int64_t)(((u_char *)(p))[4]) << 24) | \
|
||||
((u_int64_t)(((u_char *)(p))[5]) << 16) | \
|
||||
((u_int64_t)(((u_char *)(p))[6]) << 8) | \
|
||||
(u_int64_t)(((u_char *)(p))[7]))
|
||||
#define PEEK_U32(p) \
|
||||
(((u_int32_t)(((u_char *)(p))[0]) << 24) | \
|
||||
((u_int32_t)(((u_char *)(p))[1]) << 16) | \
|
||||
((u_int32_t)(((u_char *)(p))[2]) << 8) | \
|
||||
(u_int32_t)(((u_char *)(p))[3]))
|
||||
#define PEEK_U16(p) \
|
||||
(((u_int16_t)(((u_char *)(p))[0]) << 8) | \
|
||||
(u_int16_t)(((u_char *)(p))[1]))
|
||||
|
||||
#define POKE_U64(p, v) \
|
||||
do { \
|
||||
((u_char *)(p))[0] = (((u_int64_t)(v)) >> 56) & 0xff; \
|
||||
((u_char *)(p))[1] = (((u_int64_t)(v)) >> 48) & 0xff; \
|
||||
((u_char *)(p))[2] = (((u_int64_t)(v)) >> 40) & 0xff; \
|
||||
((u_char *)(p))[3] = (((u_int64_t)(v)) >> 32) & 0xff; \
|
||||
((u_char *)(p))[4] = (((u_int64_t)(v)) >> 24) & 0xff; \
|
||||
((u_char *)(p))[5] = (((u_int64_t)(v)) >> 16) & 0xff; \
|
||||
((u_char *)(p))[6] = (((u_int64_t)(v)) >> 8) & 0xff; \
|
||||
((u_char *)(p))[7] = ((u_int64_t)(v)) & 0xff; \
|
||||
} while (0)
|
||||
#define POKE_U32(p, v) \
|
||||
do { \
|
||||
((u_char *)(p))[0] = (((u_int64_t)(v)) >> 24) & 0xff; \
|
||||
((u_char *)(p))[1] = (((u_int64_t)(v)) >> 16) & 0xff; \
|
||||
((u_char *)(p))[2] = (((u_int64_t)(v)) >> 8) & 0xff; \
|
||||
((u_char *)(p))[3] = ((u_int64_t)(v)) & 0xff; \
|
||||
} while (0)
|
||||
#define POKE_U16(p, v) \
|
||||
do { \
|
||||
((u_char *)(p))[0] = (((u_int64_t)(v)) >> 8) & 0xff; \
|
||||
((u_char *)(p))[1] = ((u_int64_t)(v)) & 0xff; \
|
||||
} 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 */
|
|
@ -0,0 +1,131 @@
|
|||
/* $OpenBSD: ssherr.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "ssherr.h"
|
||||
|
||||
const char *
|
||||
ssh_err(int n)
|
||||
{
|
||||
switch (n) {
|
||||
case SSH_ERR_SUCCESS:
|
||||
return "success";
|
||||
case SSH_ERR_INTERNAL_ERROR:
|
||||
return "unexpected internal error";
|
||||
case SSH_ERR_ALLOC_FAIL:
|
||||
return "memory allocation failed";
|
||||
case SSH_ERR_MESSAGE_INCOMPLETE:
|
||||
return "incomplete message";
|
||||
case SSH_ERR_INVALID_FORMAT:
|
||||
return "invalid format";
|
||||
case SSH_ERR_BIGNUM_IS_NEGATIVE:
|
||||
return "bignum is negative";
|
||||
case SSH_ERR_STRING_TOO_LARGE:
|
||||
return "string is too large";
|
||||
case SSH_ERR_BIGNUM_TOO_LARGE:
|
||||
return "bignum is too large";
|
||||
case SSH_ERR_ECPOINT_TOO_LARGE:
|
||||
return "elliptic curve point is too large";
|
||||
case SSH_ERR_NO_BUFFER_SPACE:
|
||||
return "insufficient buffer space";
|
||||
case SSH_ERR_INVALID_ARGUMENT:
|
||||
return "invalid argument";
|
||||
case SSH_ERR_KEY_BITS_MISMATCH:
|
||||
return "key bits do not match";
|
||||
case SSH_ERR_EC_CURVE_INVALID:
|
||||
return "invalid elliptic curve";
|
||||
case SSH_ERR_KEY_TYPE_MISMATCH:
|
||||
return "key type does not match";
|
||||
case SSH_ERR_KEY_TYPE_UNKNOWN:
|
||||
return "unknown or unsupported key type";
|
||||
case SSH_ERR_EC_CURVE_MISMATCH:
|
||||
return "elliptic curve does not match";
|
||||
case SSH_ERR_EXPECTED_CERT:
|
||||
return "plain key provided where certificate required";
|
||||
case SSH_ERR_KEY_LACKS_CERTBLOB:
|
||||
return "key lacks certificate data";
|
||||
case SSH_ERR_KEY_CERT_UNKNOWN_TYPE:
|
||||
return "unknown/unsupported certificate type";
|
||||
case SSH_ERR_KEY_CERT_INVALID_SIGN_KEY:
|
||||
return "invalid certificate signing key";
|
||||
case SSH_ERR_KEY_INVALID_EC_VALUE:
|
||||
return "invalid elliptic curve value";
|
||||
case SSH_ERR_SIGNATURE_INVALID:
|
||||
return "incorrect signature";
|
||||
case SSH_ERR_LIBCRYPTO_ERROR:
|
||||
return "error in libcrypto"; /* XXX fetch and return */
|
||||
case SSH_ERR_UNEXPECTED_TRAILING_DATA:
|
||||
return "unexpected bytes remain after decoding";
|
||||
case SSH_ERR_SYSTEM_ERROR:
|
||||
return strerror(errno);
|
||||
case SSH_ERR_KEY_CERT_INVALID:
|
||||
return "invalid certificate";
|
||||
case SSH_ERR_AGENT_COMMUNICATION:
|
||||
return "communication with agent failed";
|
||||
case SSH_ERR_AGENT_FAILURE:
|
||||
return "agent refused operation";
|
||||
case SSH_ERR_DH_GEX_OUT_OF_RANGE:
|
||||
return "DH GEX group out of range";
|
||||
case SSH_ERR_DISCONNECTED:
|
||||
return "disconnected";
|
||||
case SSH_ERR_MAC_INVALID:
|
||||
return "message authentication code incorrect";
|
||||
case SSH_ERR_NO_CIPHER_ALG_MATCH:
|
||||
return "no matching cipher found";
|
||||
case SSH_ERR_NO_MAC_ALG_MATCH:
|
||||
return "no matching MAC found";
|
||||
case SSH_ERR_NO_COMPRESS_ALG_MATCH:
|
||||
return "no matching compression method found";
|
||||
case SSH_ERR_NO_KEX_ALG_MATCH:
|
||||
return "no matching key exchange method found";
|
||||
case SSH_ERR_NO_HOSTKEY_ALG_MATCH:
|
||||
return "no matching host key type found";
|
||||
case SSH_ERR_PROTOCOL_MISMATCH:
|
||||
return "protocol version mismatch";
|
||||
case SSH_ERR_NO_PROTOCOL_VERSION:
|
||||
return "could not read protocol version";
|
||||
case SSH_ERR_NO_HOSTKEY_LOADED:
|
||||
return "could not load host key";
|
||||
case SSH_ERR_NEED_REKEY:
|
||||
return "rekeying not supported by peer";
|
||||
case SSH_ERR_PASSPHRASE_TOO_SHORT:
|
||||
return "passphrase is too short (minimum four characters)";
|
||||
case SSH_ERR_FILE_CHANGED:
|
||||
return "file changed while reading";
|
||||
case SSH_ERR_KEY_UNKNOWN_CIPHER:
|
||||
return "key encrypted using unsupported cipher";
|
||||
case SSH_ERR_KEY_WRONG_PASSPHRASE:
|
||||
return "incorrect passphrase supplied to decrypt private key";
|
||||
case SSH_ERR_KEY_BAD_PERMISSIONS:
|
||||
return "bad permissions";
|
||||
case SSH_ERR_KEY_CERT_MISMATCH:
|
||||
return "certificate does not match key";
|
||||
case SSH_ERR_KEY_NOT_FOUND:
|
||||
return "key not found";
|
||||
case SSH_ERR_AGENT_NOT_PRESENT:
|
||||
return "agent not present";
|
||||
case SSH_ERR_AGENT_NO_IDENTITIES:
|
||||
return "agent contains no identities";
|
||||
case SSH_ERR_KRL_BAD_MAGIC:
|
||||
return "KRL file has invalid magic number";
|
||||
case SSH_ERR_KEY_REVOKED:
|
||||
return "Key is revoked";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/* $OpenBSD: ssherr.h,v 1.1 2014/04/30 05:29:56 djm Exp $ */
|
||||
/*
|
||||
* 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 _SSHERR_H
|
||||
#define _SSHERR_H
|
||||
|
||||
/* XXX are these too granular? not granular enough? I can't decide - djm */
|
||||
|
||||
/* Error codes */
|
||||
#define SSH_ERR_SUCCESS 0
|
||||
#define SSH_ERR_INTERNAL_ERROR -1
|
||||
#define SSH_ERR_ALLOC_FAIL -2
|
||||
#define SSH_ERR_MESSAGE_INCOMPLETE -3
|
||||
#define SSH_ERR_INVALID_FORMAT -4
|
||||
#define SSH_ERR_BIGNUM_IS_NEGATIVE -5
|
||||
#define SSH_ERR_STRING_TOO_LARGE -6
|
||||
#define SSH_ERR_BIGNUM_TOO_LARGE -7
|
||||
#define SSH_ERR_ECPOINT_TOO_LARGE -8
|
||||
#define SSH_ERR_NO_BUFFER_SPACE -9
|
||||
#define SSH_ERR_INVALID_ARGUMENT -10
|
||||
#define SSH_ERR_KEY_BITS_MISMATCH -11
|
||||
#define SSH_ERR_EC_CURVE_INVALID -12
|
||||
#define SSH_ERR_KEY_TYPE_MISMATCH -13
|
||||
#define SSH_ERR_KEY_TYPE_UNKNOWN -14 /* XXX UNSUPPORTED? */
|
||||
#define SSH_ERR_EC_CURVE_MISMATCH -15
|
||||
#define SSH_ERR_EXPECTED_CERT -16
|
||||
#define SSH_ERR_KEY_LACKS_CERTBLOB -17
|
||||
#define SSH_ERR_KEY_CERT_UNKNOWN_TYPE -18
|
||||
#define SSH_ERR_KEY_CERT_INVALID_SIGN_KEY -19
|
||||
#define SSH_ERR_KEY_INVALID_EC_VALUE -20
|
||||
#define SSH_ERR_SIGNATURE_INVALID -21
|
||||
#define SSH_ERR_LIBCRYPTO_ERROR -22
|
||||
#define SSH_ERR_UNEXPECTED_TRAILING_DATA -23
|
||||
#define SSH_ERR_SYSTEM_ERROR -24
|
||||
#define SSH_ERR_KEY_CERT_INVALID -25
|
||||
#define SSH_ERR_AGENT_COMMUNICATION -26
|
||||
#define SSH_ERR_AGENT_FAILURE -27
|
||||
#define SSH_ERR_DH_GEX_OUT_OF_RANGE -28
|
||||
#define SSH_ERR_DISCONNECTED -29
|
||||
#define SSH_ERR_MAC_INVALID -30
|
||||
#define SSH_ERR_NO_CIPHER_ALG_MATCH -31
|
||||
#define SSH_ERR_NO_MAC_ALG_MATCH -32
|
||||
#define SSH_ERR_NO_COMPRESS_ALG_MATCH -33
|
||||
#define SSH_ERR_NO_KEX_ALG_MATCH -34
|
||||
#define SSH_ERR_NO_HOSTKEY_ALG_MATCH -35
|
||||
#define SSH_ERR_NO_HOSTKEY_LOADED -36
|
||||
#define SSH_ERR_PROTOCOL_MISMATCH -37
|
||||
#define SSH_ERR_NO_PROTOCOL_VERSION -38
|
||||
#define SSH_ERR_NEED_REKEY -39
|
||||
#define SSH_ERR_PASSPHRASE_TOO_SHORT -40
|
||||
#define SSH_ERR_FILE_CHANGED -41
|
||||
#define SSH_ERR_KEY_UNKNOWN_CIPHER -42
|
||||
#define SSH_ERR_KEY_WRONG_PASSPHRASE -43
|
||||
#define SSH_ERR_KEY_BAD_PERMISSIONS -44
|
||||
#define SSH_ERR_KEY_CERT_MISMATCH -45
|
||||
#define SSH_ERR_KEY_NOT_FOUND -46
|
||||
#define SSH_ERR_AGENT_NOT_PRESENT -47
|
||||
#define SSH_ERR_AGENT_NO_IDENTITIES -48
|
||||
#define SSH_ERR_BUFFER_READ_ONLY -49
|
||||
#define SSH_ERR_KRL_BAD_MAGIC -50
|
||||
#define SSH_ERR_KEY_REVOKED -51
|
||||
|
||||
/* Translate a numeric error code to a human-readable error string */
|
||||
const char *ssh_err(int n);
|
||||
|
||||
#endif /* _SSHERR_H */
|
Loading…
Reference in New Issue