This commit is contained in:
J Harper
2016-10-10 21:59:05 +01:00
parent aa4ef719cc
commit b8dcfd8759
97 changed files with 6724 additions and 3137 deletions

View File

@@ -10,6 +10,7 @@ include $(MATRIXSSL_ROOT)/common.mk
SRC:=\
memset_s.c \
corelib.c \
psbuf.c \
$(OSDEP)/osdep.c
ASM:=memset_s.s
@@ -33,10 +34,13 @@ $(ASM): memset_s.c
$(OBJS): $(MATRIXSSL_ROOT)/common.mk Makefile *.h
# Build the static library
# Redirect stderr to null so we don't see the 'empty file' warnings
$(STATIC): $(OBJS)
$(AR) -rcuv $@ $^ 2>/dev/null
$(AR) -rcu $@ $^
clean:
rm -f $(STATIC) $(OBJS) $(ASM)
# Allows to check configuration options.
parse-config:
echo '#include "coreConfig.h"' | $(CC) $(CFLAGS) -dM -E -x c -

View File

@@ -273,22 +273,20 @@ int32_t psCreateMutex(psMutex_t *mutex, uint32_t flags)
return PS_SUCCESS;
}
int32_t psLockMutex(psMutex_t *mutex)
void psLockMutex(psMutex_t *mutex)
{
if (pthread_mutex_lock(mutex) != 0) {
psTraceCore("pthread_mutex_lock failed\n");
return PS_PLATFORM_FAIL;
abort(); /* Catastrophic error: mutex does not work correctly. */
}
return PS_SUCCESS;
}
int32_t psUnlockMutex(psMutex_t *mutex)
void psUnlockMutex(psMutex_t *mutex)
{
if (pthread_mutex_unlock(mutex) != 0) {
psTraceCore("pthread_mutex_unlock failed\n");
return PS_PLATFORM_FAIL;
abort(); /* Catastrophic error: mutex does not work correctly. */
}
return PS_SUCCESS;
}
void psDestroyMutex(psMutex_t *mutex)

View File

@@ -118,16 +118,14 @@ int32_t psCreateMutex(psMutex_t *mutex, uint32_t flags)
return PS_SUCCESS;
}
int32_t psLockMutex(psMutex_t *mutex)
void psLockMutex(psMutex_t *mutex)
{
EnterCriticalSection(mutex);
return PS_SUCCESS;
}
int32_t psUnlockMutex(psMutex_t *mutex)
void psUnlockMutex(psMutex_t *mutex)
{
LeaveCriticalSection(mutex);
return PS_SUCCESS;
}
void psDestroyMutex(psMutex_t *mutex)

View File

@@ -44,6 +44,29 @@ extern "C" {
#include "list.h"
#include "psmalloc.h"
/******************************************************************************/
/*
psCore helper macros: for communicating with compiler
These macros allow to remove spurious warnings.
*/
/* Tell compiler a variable is intended that it can be set, but not used.
(The variable is for debugging, future extension or used in some
conditionally disabled/unifdeffed branches of execution). */
#define PS_VARIABLE_SET_BUT_UNUSED(x) do { (void)(x); } while(0)
/* Tell compiler a variable is intended that it can be unused.
This is for compilers which detect variables that are not set.
(The variable is for debugging, future extension or used in some
conditionally disabled/unifdeffed branches of execution). */
#define PS_VARIABLE_UNUSED(x) do { (void)(x); } while(0)
/* Tell compiler a function parameter is intended that it can be unused.
This is for compilers which detect parameters that are not used.
(The parameter is for debugging, future extension or used in some
conditionally disabled/unifdeffed branches of execution). */
#define PS_PARAMETER_UNUSED(x) do { (void)(x); } while(0)
/******************************************************************************/
/*
psCore return codes
@@ -71,7 +94,10 @@ extern "C" {
#define PS_INTERRUPT_FAIL -14 /* An interrupt occurred and MAY be an error */
#define PS_PENDING -15 /* In process. Not necessarily an error */
#define PS_EAGAIN -16 /* Try again later. Not necessarily an error */
#define PS_OUTPUT_LENGTH -17 /* Output length negotiation:
output buffer is too small. */
#define PS_HOSTNAME_RESOLUTION -18 /* Cannot resolve host name. */
#define PS_CONNECT -19 /* Cannot connect to remote host. */
#define PS_TRUE 1
#define PS_FALSE 0
@@ -112,6 +138,36 @@ typedef struct {
int32 size; /* Size of buffer in bytes */
} psBuf_t;
/* Dynamically allocated automatically resizing psBuf_t. */
struct psDynBuf;
typedef struct psDynBuf psDynBuf_t;
struct psDynBuf {
psBuf_t buf;
psPool_t *pool;
int err;
psDynBuf_t *master;
};
#define PS_DYNBUF_GROW 256 /* Usual grow amount. */
/* Buffer for parsing input. */
struct psParseBuf;
typedef struct psParseBuf psParseBuf_t;
/* The contents of parsebuf are exactly the same than psDynBuf_t.
this allows them to share some of implementation. */
struct psParseBuf {
psBuf_t buf;
psPool_t *pool;
int err;
psParseBuf_t *master;
};
/* psDynBuf or psParseBuf allocated from this pool
is never freed automatically. */
extern psPool_t * const psStaticAllocationsPool;
/* Function definitions for Static and Dynamic Buffer API. */
#include "psbuf.h"
/******************************************************************************/
#ifdef MATRIX_USE_FILE_SYSTEM
@@ -165,15 +221,15 @@ PSPUBLIC int32 psGetFileBuf(psPool_t *pool, const char *fileName,
#ifdef USE_MULTITHREADING
#define PS_SHARED 0x1
PSPUBLIC int32_t psCreateMutex(psMutex_t *mutex, uint32_t flags);
PSPUBLIC int32_t psLockMutex(psMutex_t *mutex);
PSPUBLIC int32_t psUnlockMutex(psMutex_t *mutex);
PSPUBLIC void psLockMutex(psMutex_t *mutex);
PSPUBLIC void psUnlockMutex(psMutex_t *mutex);
PSPUBLIC void psDestroyMutex(psMutex_t *mutex);
#else
/** @note These are defines rather than inline functions because it allows
the caller to not allocate a mutex that will never be used. */
#define psCreateMutex(A, B) (PS_SUCCESS)
#define psLockMutex(A) (PS_SUCCESS)
#define psUnlockMutex(A) (PS_SUCCESS)
#define psLockMutex(A) do { } while(0)
#define psUnlockMutex(A) do { } while(0)
#define psDestroyMutex(A)
#endif /* USE_MULTITHREADING */

View File

@@ -1,70 +0,0 @@
/**
* @file coreConfig.h
* @version $Format:%h%d$
*
* Configuration settings for Matrix core module.
*/
/*
* Copyright (c) 2013-2016 INSIDE Secure Corporation
* Copyright (c) PeerSec Networks, 2002-2011
* All Rights Reserved
*
* The latest version of this code is available at http://www.matrixssl.org
*
* This software is open source; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This General Public License does NOT permit incorporating this software
* into proprietary programs. If you are unable to comply with the GPL, a
* commercial license for this software may be purchased from INSIDE at
* http://www.insidesecure.com/
*
* This program is distributed in WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* http://www.gnu.org/copyleft/gpl.html
*/
/******************************************************************************/
#ifndef _h_PS_CORECONFIG
#define _h_PS_CORECONFIG
/******************************************************************************/
/* Configurable features */
/******************************************************************************/
/**
Enable various levels of trace.
When these option is turned off, messages are silently
discarded and their text does not take space in the binary image.
*/
//#define USE_CORE_TRACE
#ifndef NO_CORE_ERROR
#define USE_CORE_ERROR
#endif
#ifndef NO_CORE_ASSERT
#define USE_CORE_ASSERT
#endif
/**
If enabled, calls to the psError set of APIs will perform a platform
abort on the exeutable to aid in debugging.
*/
#ifdef DEBUG
//#define HALT_ON_PS_ERROR /* NOT RECOMMENDED FOR PRODUCTION BUILDS */
#endif
/**
Include the psCoreOsdepMutex family of APIs
*/
//#define USE_MULTITHREADING
#endif /* _h_PS_CORECONFIG */
/******************************************************************************/

View File

@@ -83,6 +83,8 @@
#else
#define PSTM_MIPS /* MIPS assembly supported on 32 bit only */
#endif
#elif defined(__aarch64__)
#define PSTM_64BIT /* Supported by architecture */
#endif
#endif /* GNUC/CLANG */
@@ -235,13 +237,15 @@ extern void osdepEntropyClose(void);
typedef signed long long int64_t;
#endif
#elif defined(METAL)
typedef signed long int32;
typedef unsigned long uint32;
typedef signed short int16;
typedef unsigned short uint16;
#include <stdint.h>
typedef int32_t int32;
typedef uint32_t uint32;
typedef int16_t int16;
typedef uint16_t uint16;
typedef uint8_t uint8;
#ifdef HAVE_NATIVE_INT64
typedef unsigned long long uint64;
typedef signed long long int64;
typedef int64_t int64;
typedef uint64_t uint64;
#endif
#elif defined (NUCLEUS)
#include <stdint.h>

742
core/psbuf.c Normal file
View File

@@ -0,0 +1,742 @@
/**
* @file psbuf.c
* @version $Format:%h%d$
*
* Implementation of API for handling buffers containing binary data.
*/
/*
* Copyright (c) 2016 INSIDE Secure Corporation
* All Rights Reserved
*
* The latest version of this code is available at http://www.matrixssl.org
*
* This software is open source; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This General Public License does NOT permit incorporating this software
* into proprietary programs. If you are unable to comply with the GPL, a
* commercial license for this software may be purchased from INSIDE at
* http://www.insidesecure.com/
*
* This program is distributed in WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* http://www.gnu.org/copyleft/gpl.html
*/
/******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include "coreApi.h"
/* Omit debug printouts. */
#define debugf(...) do { } while(0)
/* This address is indicator for static allocations pool, and does not
need to point to any valid pool. The pool cannot be NULL, because
NULL is reserved for "default memory pool". */
psPool_t * const psStaticAllocationsPool =
(psPool_t *)&psStaticAllocationsPool;
void *psBufInit(psPool_t *pool, psBuf_t *buf, size_t capacity)
{
buf->buf = psMalloc(pool, capacity);
buf->start = buf->buf;
buf->end = buf->start;
buf->size = buf->buf ? capacity : 0;
return buf->buf;
}
void psBufUninit(psPool_t *pool, psBuf_t *buf) {
if (pool != psStaticAllocationsPool)
psFree(buf->buf, pool);
buf->buf = NULL;
buf->start = NULL;
buf->end = NULL;
buf->size = 0;
}
void *psBufDetach(psPool_t *pool, psBuf_t *buf, size_t *len_p) {
void * new;
size_t len = buf->end - buf->start;
new = psMalloc(pool, len ? len : 1);
if (new) {
memcpy(new, buf->start, len);
*len_p = len;
}
psBufUninit(pool, buf);
return new;
}
int32_t psBufFromData(psPool_t *pool, psBuf_t *buf, const void *data, size_t len)
{
void *new = NULL;
buf->buf = buf->start = buf->end = NULL;
buf->size = 0;
if (data != NULL) {
new = psMalloc(pool, len ? len : 1);
if (new != NULL) {
buf->buf = buf->start = buf->end = new;
buf->size = len;
buf->end += len;
memcpy(new, data, len);
}
}
return new ? PS_SUCCESS : PS_MEM_FAIL;
}
static int32_t psBufFromStaticData(psBuf_t *buf, const void *data, size_t len)
{
if (!data)
len = 0;
buf->buf = buf->start = buf->end = (void *) data;
buf->size = len;
buf->end += len;
return data ? PS_SUCCESS : PS_ARG_FAIL;
}
char *psBufAsHex(psPool_t *pool, const psBuf_t *buf)
{
char * hexstr;
size_t len = buf->end - buf->start;
hexstr = psMalloc(pool, len * 2 + 1);
if (hexstr) {
size_t i;
hexstr[0] = 0;
for(i = 0; i < len; i++)
sprintf(hexstr + i * 2, "%02x", buf->start[i]);
}
return hexstr;
}
void *psBufAppendSize(psBuf_t *buf, size_t sz)
{
unsigned char *loc = buf->end;
unsigned char *bufend = buf->buf + buf->size;
if (loc + sz <= bufend) {
buf->end += sz;
} else {
loc = NULL;
}
return loc;
}
void psBufReservePrepend(psBuf_t *buf, size_t sz)
{
unsigned char *bufend = buf->buf + buf->size;
unsigned char *loc = buf->end;
assert(buf->start == buf->end); /* Must be done at the beginning. */
if (loc + sz <= bufend) {
buf->start += sz;
buf->end += sz;
}
}
void *psBufPrependSize(psBuf_t *buf, size_t sz)
{
if (buf->buf <= buf->start && buf->buf + sz <= buf->start) {
buf->start -= sz;
return buf->start;
}
return NULL;
}
void *psDynBufInit(psPool_t *pool, psDynBuf_t *db, size_t capacity)
{
void *mem = psBufInit(pool, &db->buf, capacity);
db->pool = pool;
db->err = (mem == NULL);
db->master = NULL;
return mem;
}
void psDynBufUninit(psDynBuf_t *db)
{
psBufUninit(db->pool, &db->buf);
db->err = 0;
db->pool = NULL;
db->master = NULL;
}
void *psDynBufDetach(psDynBuf_t *db, size_t *len_p)
{
void *new;
if (db->err) {
psDynBufUninit(db);
return NULL;
}
new = psBufDetach(db->pool, &db->buf, len_p);
db->pool = NULL;
return new;
}
void assert_subbuf(psDynBuf_t *sub)
{
const psDynBuf_t *db;
/* Has master. */
assert(sub->master != NULL);
db = sub->master;
/* Does not have pool */
assert(sub->pool == NULL);
/* The buf begin and is within master allocated data area. */
assert(sub->buf.buf >= db->buf.start && sub->buf.buf <= db->buf.end);
assert(sub->buf.buf + sub->buf.size >= db->buf.start &&
sub->buf.buf + sub->buf.size <= db->buf.end);
/* For debugging: Mark head and tail visually. */
memset(sub->buf.buf, '(', sub->buf.start - sub->buf.buf);
memset(sub->buf.end, ')', sub->buf.buf + sub->buf.size - sub->buf.end);
}
static void *psDynBufGrow(psDynBuf_t *db, size_t head_sz, size_t tail_sz)
{
void *alloc;
void *loc;
psBuf_t new;
size_t headroom = db->buf.start - db->buf.buf;
size_t tailroom = (db->buf.buf + db->buf.size) - db->buf.end;
size_t filled = db->buf.end - db->buf.start;
size_t offset;
size_t offset_tail;
if (db->err)
return NULL;
if (head_sz != 0 && head_sz < PS_DYNBUF_GROW)
head_sz = PS_DYNBUF_GROW;
if (tail_sz < PS_DYNBUF_GROW)
tail_sz = PS_DYNBUF_GROW;
if (db->master) {
offset = db->buf.buf - db->master->buf.start;
offset_tail = db->master->buf.end - (db->buf.buf + db->buf.size);
debugf("Sub Grow: %zu+%zu+%zu => %zu+%zu+%zu; sub @ pos=%zd...-%zd\n",
headroom, filled, tailroom, headroom + head_sz, filled, tailroom + tail_sz, offset, offset_tail);
assert_subbuf(db);
/* For debugging: */
memset(db->buf.buf, '{', headroom);
memset(db->buf.end, '}', tailroom);
loc = psDynBufGrow(db->master, 0, head_sz + tail_sz);
if (loc) {
db->master->buf.end += head_sz + tail_sz;
if (offset_tail)
memmove(db->master->buf.end - offset_tail,
db->master->buf.end - offset_tail - head_sz - tail_sz,
offset_tail);
db->buf.buf = db->master->buf.start + offset;
db->buf.start = db->buf.buf + headroom + head_sz;
if (head_sz > 0)
memmove(db->buf.start,
db->buf.start - head_sz,
filled);
db->buf.end = db->buf.start + filled;
db->buf.size = head_sz + headroom + filled +
tailroom + tail_sz;
debugf("Sub Grown: sub @ pos=%d, %zd bytes (%zd+%zd+%zd)\n",
(int) (db->buf.buf - db->master->buf.start),
db->buf.size, db->buf.start - db->buf.buf,
db->buf.end - db->buf.start, db->buf.buf + db->buf.size - db->buf.end);
/* For debugging: */
memset(db->buf.buf, '<', head_sz + headroom);
memset(db->buf.end, '>', tail_sz + tailroom);
} else {
db->err++;
}
assert_subbuf(db);
return loc;
}
head_sz += headroom;
tail_sz += tailroom;
debugf("Grow: %zu+%zu+%zu => %zu+%zu+%zu\n",
headroom, filled, tailroom, head_sz, filled, tail_sz);
alloc = psBufInit(db->pool, &new, head_sz + filled + tail_sz);
if (alloc) {
psBufReservePrepend(&new, head_sz);
loc = psBufAppendSize(&new, filled);
/* Just allocated so there is space. */
assert(loc != NULL);
memcpy(loc, db->buf.start, filled);
psBufUninit(db->pool, &db->buf);
db->buf.buf = new.buf;
db->buf.start = new.start;
db->buf.end = new.end;
db->buf.size = new.size;
} else {
db->err++;
loc = NULL;
}
return loc;
}
void *psDynBufAppendSize(psDynBuf_t *db, size_t sz)
{
unsigned char *loc = psBufAppendSize(&db->buf, sz);
if (loc == NULL)
if (psDynBufGrow(db, 0, sz)) {
loc = psBufAppendSize(&db->buf, sz);
assert(loc != NULL);
}
return loc;
}
void psDynBufReservePrepend(psDynBuf_t *db, size_t sz)
{
/* This function only performs action if nothing has been pushed.
The logic for prepending will make sure prepend succeeds even
if there is no head room. */
if (db->buf.start == db->buf.end)
psBufReservePrepend(&db->buf, sz);
}
void *psDynBufPrependSize(psDynBuf_t *db, size_t sz)
{
unsigned char *loc = psBufPrependSize(&db->buf, sz);
if (loc == NULL)
if (psDynBufGrow(db, sz, 0)) {
loc = psBufPrependSize(&db->buf, sz);
assert(loc != NULL);
}
return loc;
}
void *psDynBufSubInit(psDynBuf_t *db, psDynBuf_t *sub, size_t capacity)
{
void *mem = psDynBufAppendSize(db, capacity);
if (mem) {
sub->buf.buf = db->buf.end - capacity;
sub->buf.start = sub->buf.buf;
sub->buf.end = sub->buf.buf;
sub->buf.size = capacity;
sub->pool = NULL;
sub->master = db;
sub->err = 0;
memset(sub->buf.buf, '#', capacity);
assert_subbuf(sub);
} else {
sub->buf.buf = sub->buf.start = sub->buf.end = NULL;
sub->buf.size = 0;
sub->pool = NULL;
sub->err = 1;
db->err++;
sub->master = db;
}
return mem;
}
void *psDynBufSubInitAt(psDynBuf_t *db, psDynBuf_t *sub, size_t at,
size_t length)
{
size_t len = db->buf.end - db->buf.start;
if (db->err == 0 && at + length <= len) {
sub->buf.buf = db->buf.start + at;
sub->buf.start = sub->buf.buf;
sub->buf.end = sub->buf.buf;
sub->buf.size = length;
sub->pool = NULL;
sub->master = db;
sub->err = 0;
memset(sub->buf.buf, '#', length);
assert_subbuf(sub);
} else {
sub->buf.buf = sub->buf.start = sub->buf.end = NULL;
sub->buf.size = 0;
sub->pool = NULL;
sub->err++;
db->err++;
sub->master = db;
}
return sub->buf.buf;
}
void *psDynBufSubFinish(psDynBuf_t *sub)
{
void *loc = NULL;
psDynBuf_t *db = sub->master;
if (sub->err) {
db->err += sub->err;
} else {
size_t total = sub->buf.size;
size_t filled = sub->buf.end - sub->buf.start;
size_t offset_tail;
offset_tail = db->buf.end - (sub->buf.buf + sub->buf.size);
assert_subbuf(sub);
if (sub->buf.buf != sub->buf.start && filled > 0) {
memmove(sub->buf.buf, sub->buf.start, filled);
}
if (offset_tail > 0) {
memmove(db->buf.end - total + filled - offset_tail,
db->buf.end - offset_tail, offset_tail);
}
db->buf.end -= total;
db->buf.end += filled;
loc = sub->buf.buf;
}
sub->buf.buf = NULL;
psDynBufUninit(sub);
return loc;
}
static size_t len_of_tag_and_len(size_t len)
{
size_t lentaglen;
if (len < 128)
lentaglen = 2;
else if (len < 256)
lentaglen = 3;
else if (len < 65536)
lentaglen = 4;
else if (len < 16777216)
lentaglen = 5;
else
lentaglen = 6; /* Supports up-to 32-bit sizes. */
return lentaglen;
}
static void output_len(size_t len, unsigned char *target)
{
if (len < 128)
target[1] = (unsigned char) len;
else if (len < 256) {
target[1] = 0x81;
target[2] = (unsigned char) len;
} else if (len < 65536) {
target[1] = 0x82;
target[2] = (unsigned char) (len >> 8);
target[3] = (unsigned char) len;
} else if (len < 16777216) {
target[1] = 0x83;
target[2] = (unsigned char) (len >> 16);
target[3] = (unsigned char) (len >> 8);
target[4] = (unsigned char) len;
} else {
target[1] = 0x84;
target[2] = (unsigned char) (len >> 24);
target[3] = (unsigned char) (len >> 16);
target[4] = (unsigned char) (len >> 8);
target[5] = (unsigned char) len;
}
}
char *psDynBufAppendAsn1TagGen(psDynBuf_t *db, unsigned char tag,
const unsigned char *bytes, size_t len)
{
size_t extralen = len_of_tag_and_len(len);
unsigned char *target = psDynBufAppendSize(db, len + extralen);
if (target) {
target[0] = tag;
output_len(len, target);
memcpy(target + extralen, bytes, len);
}
return (char *)target;
}
char *psDynBufBeginConstructedTag(psDynBuf_t *db, psDynBuf_t *sub)
{
char *target = psDynBufSubInit(db, sub, 20);
if (target) {
psDynBufReservePrepend(sub, 4);
}
return target;
}
char *psDynBufEndConstructedTag(psDynBuf_t *sub, unsigned char tag)
{
size_t len = sub->buf.end - sub->buf.start;
size_t extralen = len_of_tag_and_len(len);
unsigned char *target = psDynBufPrependSize(sub, extralen);
if (target) {
target[0] = tag;
output_len(len, target);
}
psDynBufSubFinish(sub);
return (char*)target;
}
int32_t psParseBufFromStaticData(psParseBuf_t *pb, const void *data, size_t len)
{
int32_t rc = psBufFromStaticData(&pb->buf, data, len);
pb->pool = psStaticAllocationsPool;
pb->err = rc != PS_SUCCESS;
pb->master = NULL;
return rc;
}
/* The maximum supported PS_PARSE_MAXIMUM_TAG_CONTENT: */
#define PS_PARSE_MAXIMUM_TAG_CONTENT 0x40000000U /* 1 gigabyte. */
/* Note: If the value needs to be extended, the limit for function
psParseBufGetTagLen() on 32-bit hosts is 0xFFFFFFFFU - 5. */
size_t psParseBufGetTagLen(const psParseBuf_t *pb,
unsigned char tag,
size_t *hdrLen_p)
{
unsigned char lenlen;
size_t len_at = 1;
size_t len_hdr = 2;
size_t len_content;
size_t len_out;
const unsigned char *ptr = pb->buf.start;
size_t bytes = pb->buf.end - pb->buf.start;
if (bytes < 2)
return 0;
if (tag != 0 && ptr[0] != tag)
return 0;
/* Check size tag: long input lengths. */
lenlen = ptr[1]; /* Use lenlen temporarily to parse length field. */
if (lenlen >= 0x80) {
if (bytes < 0x83)
return 0;
if (lenlen == 0x81 && ptr[2] < 0x80)
return 0;
if (lenlen == 0x82 && ptr[2] == 0x00)
return 0;
if (lenlen == 0x83 && ptr[2] == 0x00)
return 0;
if (lenlen == 0x84 && ptr[2] == 0x00)
return 0;
if (lenlen == 0x80 || lenlen > 0x84)
return 0; /* Too large or indefinite len. */
len_at++;
lenlen -= 0x80;
len_hdr += lenlen;
} else {
lenlen = 1;
}
/* len_at and lenlen now express length and of the len. */
/* additionally, its known that all the length bytes are accessible. */
len_content = 0;
while(lenlen) {
len_content <<= 8;
len_content += ptr[len_at];
len_at++;
lenlen--;
}
if (len_content > PS_PARSE_MAXIMUM_TAG_CONTENT)
return 0;
len_out = len_content + len_hdr;
if (len_out > bytes)
return 0;
if (hdrLen_p)
*hdrLen_p = len_hdr;
return len_out;
}
int psParseBufCanGetTag(const psParseBuf_t *pb, unsigned char tag)
{
return psParseBufGetTagLen(pb, tag, NULL) > 0;
}
size_t psParseBufTrySkipBytes(psParseBuf_t *pb,
const unsigned char *bytes,
size_t numbytes)
{
size_t skip_bytes = 0;
if (psParseCanRead(pb, numbytes) &&
memcmp(bytes, pb->buf.start, numbytes) == 0)
skip_bytes = numbytes;
pb->buf.start += skip_bytes;
return skip_bytes;
}
size_t psParseBufSkipBytes(psParseBuf_t *pb, const unsigned char *bytes,
size_t numbytes)
{
size_t sz = psParseBufTrySkipBytes(pb, bytes, numbytes);
if (sz == 0)
pb->err ++;
return sz;
}
size_t psParseBufTryReadTagSub(const psParseBuf_t *pb,
psParseBuf_t *content, unsigned char tag)
{
size_t hdrlen;
size_t len = psParseBufGetTagLen(pb, tag, &hdrlen);
size_t len_content;
psParseBuf_t content_tmp; /* Allows calling the function with
content == NULL to skip the tag. */
if (!content)
content = & content_tmp;
if (!len) {
content->buf.buf = content->buf.start = content->buf.end = NULL;
content->buf.size = 0;
content->pool = NULL;
/* Mark state of content as error. */
content->err = 1;
/* Do not raise error status of main pb. */
content->master = (psParseBuf_t *)pb;
return 0;
}
len_content = len - hdrlen;
content->buf.start = content->buf.buf = pb->buf.start + hdrlen;
content->buf.size = len_content;
content->buf.end = content->buf.start + len_content;
content->pool = NULL;
content->master = (psParseBuf_t *)pb;
content->err = 0;
return len;
}
size_t psParseBufReadTagSub(psParseBuf_t *pb,
psParseBuf_t *content, unsigned char tag)
{
size_t len = psParseBufTryReadTagSub(pb, content, tag);
if (len == 0) {
/* Mark this also as an error in main parse buffer. */
pb->err++;
/* Initialize sub as the same memory than main parse buffer,
to allow parsing using it (typically unsuccessfully)
in following parsing operations. */
memcpy(&(content->buf), &(pb->buf), sizeof content->buf);
}
return len;
}
size_t psParseBufReadTagRef(psParseBuf_t *pb,
psBuf_t *ref, unsigned char tag)
{
psParseBuf_t content;
size_t len = psParseBufReadTagSub(pb, &content, tag);
if (len) {
memcpy(ref, &content.buf, sizeof(psBuf_t));
pb->buf.start += len;
}
return len;
}
size_t psParseBufTrySkipTag(psParseBuf_t *pb, unsigned char tag)
{
psParseBuf_t sub;
size_t sz = psParseBufTryReadTagSub(pb, &sub, tag);
if (sz)
(void) psParseBufFinish(&sub);
return sz;
}
size_t psParseBufSkipTag(psParseBuf_t *pb, unsigned char tag)
{
psParseBuf_t sub;
size_t sz = psParseBufReadTagSub(pb, &sub, tag);
if (sz)
(void) psParseBufFinish(&sub);
return sz;
}
int32_t psParseBufCopyAll(const psParseBuf_t *pb, unsigned char *target,
size_t *targetlen)
{
size_t len = pb->buf.end - pb->buf.start;
if (pb->err != 0)
return PS_FAILURE;
if (target == NULL) {
*targetlen = len;
return PS_OUTPUT_LENGTH;
}
if (len > *targetlen) {
*targetlen = len;
return PS_OUTPUT_LENGTH;
}
memcpy(target, pb->buf.start, len);
return PS_SUCCESS;
}
int psParseBufEq(const psParseBuf_t *pb1, const psParseBuf_t *pb2)
{
if (pb1->err || pb2->err)
return 0;
return psBufEq(&pb1->buf, &pb2->buf);
}
int32_t psParseBufCheckState(const psParseBuf_t *pb)
{
return pb->err == 0 ? PS_SUCCESS : PS_FAILURE;
}
int32_t psParseBufFinish(psParseBuf_t *pb)
{
int32_t rc;
if (pb->master) {
if (pb->err)
/* Signal master on error. */
pb->master->err++;
else
/* Advance master. */
pb->master->buf.start = pb->buf.buf + pb->buf.size;
pb->buf.buf = NULL; /* Do not free any data. */
}
/* Free state. */
rc = psParseBufCheckState(pb);
psBufUninit(pb->pool, &pb->buf);
pb->master = NULL;
pb->err = 0;
pb->pool = NULL;
return rc;
}
void psParseBufCancel(psParseBuf_t *pb)
{
/* Free state. */
if (pb->master)
pb->buf.buf = NULL; /* Do not free any data. */
psBufUninit(pb->pool, &pb->buf);
pb->master = NULL;
pb->err = 0;
pb->pool = NULL;
}
/* end of file psbuf.c */

297
core/psbuf.h Normal file
View File

@@ -0,0 +1,297 @@
/**
* @file psbuf.h
* @version $Format:%h%d$
*
* API for handling buffers containing binary data.
*/
/*
* Copyright (c) 2016 INSIDE Secure Corporation
* All Rights Reserved
*
* The latest version of this code is available at http://www.matrixssl.org
*
* This software is open source; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This General Public License does NOT permit incorporating this software
* into proprietary programs. If you are unable to comply with the GPL, a
* commercial license for this software may be purchased from INSIDE at
* http://www.insidesecure.com/
*
* This program is distributed in WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* http://www.gnu.org/copyleft/gpl.html
*/
/******************************************************************************/
#ifndef _h_PS_BUF
#define _h_PS_BUF
#include "coreApi.h"
#include <string.h>
/* API for psBuf initialization and basic usage.*/
void *psBufInit(psPool_t *pool, psBuf_t *buf, size_t capacity);
void psBufUninit(psPool_t *pool, psBuf_t *buf);
void *psBufDetach(psPool_t *pool, psBuf_t *buf, size_t *len_p);
void *psBufAppendSize(psBuf_t *buf, size_t sz);
void psBufReservePrepend(psBuf_t *buf, size_t sz);
void *psBufPrependSize(psBuf_t *buf, size_t sz);
char *psBufAsHex(psPool_t *pool, const psBuf_t *buf);
int32_t psBufFromData(psPool_t *pool, psBuf_t *buf,
const void *data, size_t len);
static __inline int psBufEq(const psBuf_t *buf1, const psBuf_t *buf2)
{
return (buf1->end - buf1->start) == (buf2->end - buf2->start) &&
buf1->start != NULL &&
buf2->start != NULL &&
memcmp(buf1->start, buf2->start, (buf1->end - buf1->start))
== 0;
}
static __inline void *psBufAppendChar(psBuf_t *buf, char ch)
{
void *loc = psBufAppendSize(buf, 1);
if (loc)
*(char*)loc = ch;
return loc;
}
static __inline void *psBufPrependChar(psBuf_t *buf, char ch)
{
void *loc = psBufPrependSize(buf, 1);
if (loc)
*(char*)loc = ch;
return loc;
}
/* API for Dynamic Buffers initialization and basic usage. */
void *psDynBufInit(psPool_t *pool, psDynBuf_t *db, size_t capacity);
void psDynBufUninit(psDynBuf_t *db);
void *psDynBufDetach(psDynBuf_t *db, size_t *len_p);
void *psDynBufAppendSize(psDynBuf_t *db, size_t sz);
void psDynBufReservePrepend(psDynBuf_t *db, size_t sz);
void *psDynBufPrependSize(psDynBuf_t *db, size_t sz);
static __inline void *psDynBufAppendChar(psDynBuf_t *db, char ch)
{
void *loc = psDynBufAppendSize(db, 1);
if (loc)
*(char*)loc = ch;
return loc;
}
static __inline void *psDynBufPrependChar(psDynBuf_t *db, char ch)
{
void *loc = psDynBufPrependSize(db, 1);
if (loc)
*(char*)loc = ch;
return loc;
}
static __inline void *psDynBufAppendStr(psDynBuf_t *db, const char *s)
{
size_t len = s ? strlen(s) : 0;
void *loc = psDynBufAppendSize(db, len);
if (loc)
memcpy(loc, s, len);
return loc;
}
static __inline void *psDynBufPrependStr(psDynBuf_t *db, const char *s)
{
size_t len = s ? strlen(s) : 0;
void *loc = psDynBufPrependSize(db, len);
if (loc)
memcpy(loc, s, len);
return loc;
}
static __inline void *psDynBufAppendOctets(psDynBuf_t *db, const void *data,
size_t len)
{
void *loc = psDynBufAppendSize(db, len);
if (loc)
memcpy(loc, data, len);
return loc;
}
static __inline void *psDynBufAppendBuf(psDynBuf_t *db, const psBuf_t *b)
{
return psDynBufAppendOctets(db, b->start, b->end - b->start);
}
static __inline void *psDynBufIncorporateDynBuf(psDynBuf_t *db, psDynBuf_t *db2)
{
size_t len;
void *data = psDynBufDetach(db2, &len);
if (data) {
return psDynBufAppendOctets(db, data, len);
} else {
db->err++;
return NULL;
}
}
/* Dynamic buffer subbuffers. */
void *psDynBufSubInit(psDynBuf_t *db, psDynBuf_t *sub, size_t capacity);
void *psDynBufSubInitAt(psDynBuf_t *db, psDynBuf_t *sub, size_t at,
size_t length);
void *psDynBufSubFinish(psDynBuf_t *sub);
/* Note: This variable argument function is currently implemented as a macro. */
#define psDynBufAppendStrf(ps_dyn_buf_p, ...) \
do { \
char tmp; \
size_t len = 1 + snprintf(&tmp, 1, __VA_ARGS__); \
char *target = psDynBufAppendSize((ps_dyn_buf_p), len); \
if (target) { \
snprintf(target, len, __VA_ARGS__); \
(ps_dyn_buf_p)->buf.end -= 1; \
} \
} while(0)
/* Subset of ASN.1 via psDynBuf. */
char *psDynBufAppendAsn1TagGen(psDynBuf_t *db, unsigned char tag,
const unsigned char *bytes, size_t len);
char *psDynBufBeginConstructedTag(psDynBuf_t *db, psDynBuf_t *sub);
char *psDynBufEndConstructedTag(psDynBuf_t *sub, unsigned char tag);
static __inline char *psDynBufBeginSequence(psDynBuf_t *db, psDynBuf_t *sub)
{
return psDynBufBeginConstructedTag(db, sub);
}
static __inline char *psDynBufEndSequence(psDynBuf_t *sub)
{
return psDynBufEndConstructedTag(sub, 0x30);
}
static __inline int32_t psDynBufDetachBuf(psDynBuf_t *db, psBuf_t *target)
{
size_t sz;
void *buf;
target->start = target->buf = buf = psDynBufDetach(db, &sz);
if (!buf) {
/* Exception path: memory allocation failure. */
target->size = 0;
target->end = buf;
return PS_MEM_FAIL;
}
target->size = sz;
target->end = ((unsigned char *) buf) + sz;
return PS_SUCCESS;
}
/* Start parsing static data using psParseBuf_t. */
int32_t psParseBufFromStaticData(psParseBuf_t *pb,
const void *data, size_t len);
/* Check if there is sufficient data to parse left. */
static __inline int psParseCanRead(const psParseBuf_t *pb, size_t nbytes)
{
size_t bytes_readable;
if (pb->err)
return 0;
bytes_readable = pb->buf.end - pb->buf.start;
return bytes_readable >= nbytes;
}
/* Get length of following ASN.1 tag
(specify tag as unsigned char or 0 for ANY).
This is for parsing content of parsebuf as ASN.1 DER data.
If hdrLen_p is non-null, the function also returns the length of tag header.
*/
size_t psParseBufGetTagLen(const psParseBuf_t *pb, unsigned char tag,
size_t *hdrLen_p);
/* Test if there is specific (tag > 0) or any (tag == 0) ASN.1 der
encoding at current parsing location.
return 0 no, 1 yes */
int psParseBufCanGetTag(const psParseBuf_t *pb, unsigned char tag);
/* Try read ASN.1 DER specific (tag > 0) or any (tag == 0) at the
current parsing location. Reading will return sub parsebuf,
which allows reading constructed tags.
Returns length of tag read (including header) or 0 if no tag was read.
Parsing location will advance once finished with content.
*/
size_t psParseBufTryReadTagSub(const psParseBuf_t *pb,
psParseBuf_t *content, unsigned char tag);
/* Read specified (or any) ASN.1 tag at the current parsing location.
it is considered error if read fails.
Parsing location will advance once finished with content. */
size_t psParseBufReadTagSub(psParseBuf_t *pb,
psParseBuf_t *content, unsigned char tag);
/* Copy all data from parse buffer. Supports length negotiations.
Fails if parsing errors have been seen. */
int32_t psParseBufCopyAll(const psParseBuf_t *pb, unsigned char *target,
size_t *targetlen);
/* Return true only if buffers have encountered no parsing errors and
the contents are equal. */
int psParseBufEq(const psParseBuf_t *pb1, const psParseBuf_t *pb2);
/* return PS_SUCCESS if pb has not encountered parsing errors. */
int32_t psParseBufCheckState(const psParseBuf_t *pb);
/* Alias (implemented as a macro) for psParseBufTryReadTagSub used on sequence.
*/
#define psParseBufTryReadSequenceSub(pb, content) \
psParseBufTryReadTagSub(pb, content, 0x30)
/* Alias (implemented as a macro) for psParseBufReadTagSub used on sequence. */
#define psParseBufReadSequenceSub(pb, content) \
psParseBufReadTagSub(pb, content, 0x30)
/* Skip tag with specified tag id (or 0 for any) if possible.
If tag was skipped, return length in bytes that was skipped. */
size_t psParseBufTrySkipTag(psParseBuf_t *pb, unsigned char tag);
/* Skip tag with specified tag id (or 0 for any) if possible.
Tag not existing is considered error and error is set in pb. */
size_t psParseBufSkipTag(psParseBuf_t *pb, unsigned char tag);
/* Signal errors from sub to master buffer.
If invoked on allocated main parse buffer, the memory will be freed.
If invoked on subbuffer, the position on main buffer is advanced.
The return value will only be PS_SUCCESS is no errors have been observed. */
int32_t psParseBufFinish(psParseBuf_t *buf);
/* Cancel processing of subbuffer.
Errors are not propagated to the master buffer, and master buffer is not
advanced.
If invoked on allocated main parse buffer, any memory allocated will
still be freed. */
void psParseBufCancel(psParseBuf_t *buf);
/* Skip specified bytes (such as tag with specific contents or non-ASN.1 data)*/
size_t psParseBufTrySkipBytes(psParseBuf_t *pb,
const unsigned char *bytes,
size_t numbytes);
/* Skip specified bytes. Not finding the bytes is an error. */
size_t psParseBufSkipBytes(psParseBuf_t *pb, const unsigned char *bytes,
size_t numbytes);
/* Read given tag and fill-in reference with the content.
Parse buffer is moved to point to the next parsing location. */
size_t psParseBufReadTagRef(psParseBuf_t *pb,
psBuf_t *ref, unsigned char tag);
#endif /* _h_PS_BUF */
/* end of file psbuf.h */

View File

@@ -49,6 +49,11 @@
#define MATRIX_NO_POOL (void *)0x0
/* Introduce variables used for memory pooling, so that the compiler does not
give spurious warnings even when memory pools are not supported by the
target operating system. */
#define PS_POOL_USED(poolVar) PS_VARIABLE_SET_BUT_UNUSED(poolVar)
/******************************************************************************/
/*
Native memory routines
@@ -68,14 +73,7 @@
#define psMemset memset
#define psMemcpy memcpy
/*
Support for memory allocation in order to avoid applications that redefine
malloc/free (see Perl)
*/
__inline static void *psMallocNative(size_t size) { return malloc(size); }
__inline static void psFreeNative(void *ptr) { free(ptr); }
typedef int32_t psPool_t;
typedef int32 psPool_t;
/******************************************************************************/