xref: /minix3/crypto/external/bsd/libsaslc/dist/src/buffer.c (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
1*ebfedea0SLionel Sambuc /* $NetBSD: buffer.c,v 1.2 2011/02/12 23:21:32 christos Exp $ */
2*ebfedea0SLionel Sambuc 
3*ebfedea0SLionel Sambuc /* Copyright (c) 2010 The NetBSD Foundation, Inc.
4*ebfedea0SLionel Sambuc  * All rights reserved.
5*ebfedea0SLionel Sambuc  *
6*ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
7*ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
8*ebfedea0SLionel Sambuc  * are met:
9*ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
10*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
11*ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
12*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
13*ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
14*ebfedea0SLionel Sambuc  * 3. All advertising materials mentioning features or use of this software
15*ebfedea0SLionel Sambuc  *    must display the following acknowledgement:
16*ebfedea0SLionel Sambuc  *        This product includes software developed by the NetBSD
17*ebfedea0SLionel Sambuc  *        Foundation, Inc. and its contributors.
18*ebfedea0SLionel Sambuc  * 4. Neither the name of The NetBSD Foundation nor the names of its
19*ebfedea0SLionel Sambuc  *    contributors may be used to endorse or promote products derived
20*ebfedea0SLionel Sambuc  *    from this software without specific prior written permission.
21*ebfedea0SLionel Sambuc  *
22*ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23*ebfedea0SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24*ebfedea0SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25*ebfedea0SLionel Sambuc  * PURPOSE ARE DISCLAIMED.	IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26*ebfedea0SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27*ebfedea0SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28*ebfedea0SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29*ebfedea0SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30*ebfedea0SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31*ebfedea0SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32*ebfedea0SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
33*ebfedea0SLionel Sambuc  */
34*ebfedea0SLionel Sambuc #include <sys/cdefs.h>
35*ebfedea0SLionel Sambuc __RCSID("$NetBSD: buffer.c,v 1.2 2011/02/12 23:21:32 christos Exp $");
36*ebfedea0SLionel Sambuc 
37*ebfedea0SLionel Sambuc #include <sys/param.h>		/* for MIN() */
38*ebfedea0SLionel Sambuc 
39*ebfedea0SLionel Sambuc #include <assert.h>
40*ebfedea0SLionel Sambuc #include <saslc.h>
41*ebfedea0SLionel Sambuc #include <stdio.h>
42*ebfedea0SLionel Sambuc #include <stdlib.h>
43*ebfedea0SLionel Sambuc #include <string.h>
44*ebfedea0SLionel Sambuc 
45*ebfedea0SLionel Sambuc #include "buffer.h"
46*ebfedea0SLionel Sambuc #include "error.h"
47*ebfedea0SLionel Sambuc #include "saslc_private.h"
48*ebfedea0SLionel Sambuc 
49*ebfedea0SLionel Sambuc /*
50*ebfedea0SLionel Sambuc  * XXX: Should we rename saslc__buffer_* and saslc__buffer32_* to
51*ebfedea0SLionel Sambuc  * something reflecting their encode and decode, resp, context?
52*ebfedea0SLionel Sambuc  */
53*ebfedea0SLionel Sambuc 
54*ebfedea0SLionel Sambuc /**
55*ebfedea0SLionel Sambuc  * encode buffer context
56*ebfedea0SLionel Sambuc  */
57*ebfedea0SLionel Sambuc struct saslc__buffer_context_t {
58*ebfedea0SLionel Sambuc 	saslc_sess_t *sess;	/* session pointer (for error messages) */
59*ebfedea0SLionel Sambuc 	size_t maxbuf;		/* allocated length of payload buffer (maxbuf) */
60*ebfedea0SLionel Sambuc 	size_t bufneed;		/* bytes needed in payload buffer */
61*ebfedea0SLionel Sambuc 
62*ebfedea0SLionel Sambuc 	/* XXX: must be at end */
63*ebfedea0SLionel Sambuc 	uint8_t buf[1];		/* payload buffer */
64*ebfedea0SLionel Sambuc };
65*ebfedea0SLionel Sambuc 
66*ebfedea0SLionel Sambuc /**
67*ebfedea0SLionel Sambuc  * decode buffer context
68*ebfedea0SLionel Sambuc  *
69*ebfedea0SLionel Sambuc  * the actual packet looks like:
70*ebfedea0SLionel Sambuc  *
71*ebfedea0SLionel Sambuc  * struct {
72*ebfedea0SLionel Sambuc  *    uint8_t size[4];	// length of packet following this (big endian order)
73*ebfedea0SLionel Sambuc  *    uint8_t payload[];	// variable length payload area
74*ebfedea0SLionel Sambuc  *    struct {
75*ebfedea0SLionel Sambuc  *      uint8_t mac_0_9[10];	// truncated MD5_HMAC hash of size and payload
76*ebfedea0SLionel Sambuc  *      uint8_t version[2];	// always 1 (big endian order)
77*ebfedea0SLionel Sambuc  *      uint8_t seqnum[4];      // sequence number (big endian order)
78*ebfedea0SLionel Sambuc  *    } mac __packed;
79*ebfedea0SLionel Sambuc  * } __packed
80*ebfedea0SLionel Sambuc  */
81*ebfedea0SLionel Sambuc struct saslc__buffer32_context_t {
82*ebfedea0SLionel Sambuc 	saslc_sess_t *sess;	/* session pointer (for error messages) */
83*ebfedea0SLionel Sambuc 	size_t szneed;		/* bytes needed in size buffer */
84*ebfedea0SLionel Sambuc 	size_t bufsize;		/* size of payload buffer */
85*ebfedea0SLionel Sambuc 	size_t maxbuf;		/* allocated length of payload buffer */
86*ebfedea0SLionel Sambuc 	size_t bufneed;		/* bytes needed in payload buffer */
87*ebfedea0SLionel Sambuc 
88*ebfedea0SLionel Sambuc 	/* XXX: these must be sequential and at the end! */
89*ebfedea0SLionel Sambuc 	uint8_t szbuf[4];	/* size buffer */
90*ebfedea0SLionel Sambuc 	uint8_t buf[1];		/* payload buffer */
91*ebfedea0SLionel Sambuc } __packed;
92*ebfedea0SLionel Sambuc 
93*ebfedea0SLionel Sambuc /****************************************
94*ebfedea0SLionel Sambuc  * saslc__buffer_* routines.
95*ebfedea0SLionel Sambuc  * For fetching unencoded data.
96*ebfedea0SLionel Sambuc  */
97*ebfedea0SLionel Sambuc 
98*ebfedea0SLionel Sambuc /**
99*ebfedea0SLionel Sambuc  * @brief destroy a buffer context
100*ebfedea0SLionel Sambuc  * @param ctx context to destroy
101*ebfedea0SLionel Sambuc  * @return nothing
102*ebfedea0SLionel Sambuc  */
103*ebfedea0SLionel Sambuc void
saslc__buffer_destroy(saslc__buffer_context_t * ctx)104*ebfedea0SLionel Sambuc saslc__buffer_destroy(saslc__buffer_context_t *ctx)
105*ebfedea0SLionel Sambuc {
106*ebfedea0SLionel Sambuc 
107*ebfedea0SLionel Sambuc 	free(ctx);
108*ebfedea0SLionel Sambuc }
109*ebfedea0SLionel Sambuc 
110*ebfedea0SLionel Sambuc /**
111*ebfedea0SLionel Sambuc  * @brief create a buffer context
112*ebfedea0SLionel Sambuc  * @param sess saslc session
113*ebfedea0SLionel Sambuc  * @param maxbuf maximum buffer size
114*ebfedea0SLionel Sambuc  * @return buffer context
115*ebfedea0SLionel Sambuc  */
116*ebfedea0SLionel Sambuc saslc__buffer_context_t *
saslc__buffer_create(saslc_sess_t * sess,size_t maxbuf)117*ebfedea0SLionel Sambuc saslc__buffer_create(saslc_sess_t *sess, size_t maxbuf)
118*ebfedea0SLionel Sambuc {
119*ebfedea0SLionel Sambuc 	saslc__buffer_context_t *ctx;
120*ebfedea0SLionel Sambuc 	size_t buflen;
121*ebfedea0SLionel Sambuc 
122*ebfedea0SLionel Sambuc 	buflen = sizeof(*ctx) - sizeof(ctx->buf) + maxbuf;
123*ebfedea0SLionel Sambuc 	ctx = malloc(buflen);
124*ebfedea0SLionel Sambuc 	if (ctx == NULL) {
125*ebfedea0SLionel Sambuc 		saslc__error_set_errno(ERR(sess), ERROR_NOMEM);
126*ebfedea0SLionel Sambuc 		return NULL;
127*ebfedea0SLionel Sambuc 	}
128*ebfedea0SLionel Sambuc 	memset(ctx, 0, sizeof(*ctx) - sizeof(ctx->buf));
129*ebfedea0SLionel Sambuc 
130*ebfedea0SLionel Sambuc 	ctx->maxbuf = maxbuf;
131*ebfedea0SLionel Sambuc 	ctx->bufneed = ctx->maxbuf;
132*ebfedea0SLionel Sambuc 	ctx->sess = sess;
133*ebfedea0SLionel Sambuc 	return ctx;
134*ebfedea0SLionel Sambuc }
135*ebfedea0SLionel Sambuc 
136*ebfedea0SLionel Sambuc /**
137*ebfedea0SLionel Sambuc  * @brief fetch a block of data from the input stream.
138*ebfedea0SLionel Sambuc  * @param ctx context
139*ebfedea0SLionel Sambuc  * @param in input buffer
140*ebfedea0SLionel Sambuc  * @param inlen input buffer length
141*ebfedea0SLionel Sambuc  * @param out pointer to output buffer
142*ebfedea0SLionel Sambuc  * @param outlen pointer to output buffer length
143*ebfedea0SLionel Sambuc  * @return number of bytes consumed by the current call, or -1 on
144*ebfedea0SLionel Sambuc  * failure.
145*ebfedea0SLionel Sambuc  *
146*ebfedea0SLionel Sambuc  * NOTE: Output is buffered, so if the return is success and outlen is
147*ebfedea0SLionel Sambuc  * zero, then more data is needed to fill the packet.  The internal
148*ebfedea0SLionel Sambuc  * buffer can be flushed by calling with inlen = 0.
149*ebfedea0SLionel Sambuc  */
150*ebfedea0SLionel Sambuc ssize_t
saslc__buffer_fetch(saslc__buffer_context_t * ctx,const uint8_t * in,size_t inlen,uint8_t ** out,size_t * outlen)151*ebfedea0SLionel Sambuc saslc__buffer_fetch(saslc__buffer_context_t *ctx, const uint8_t *in,
152*ebfedea0SLionel Sambuc     size_t inlen, uint8_t **out, size_t *outlen)
153*ebfedea0SLionel Sambuc {
154*ebfedea0SLionel Sambuc 	uint8_t *p;
155*ebfedea0SLionel Sambuc 	size_t len;
156*ebfedea0SLionel Sambuc 
157*ebfedea0SLionel Sambuc 	if (inlen == 0) {  /* flush internal buffer */
158*ebfedea0SLionel Sambuc 		*outlen = ctx->maxbuf - ctx->bufneed;
159*ebfedea0SLionel Sambuc 		*out = *outlen != 0 ? ctx->buf : NULL;
160*ebfedea0SLionel Sambuc 		ctx->bufneed = ctx->maxbuf;	/* for next call */
161*ebfedea0SLionel Sambuc 		return 0;
162*ebfedea0SLionel Sambuc 	}
163*ebfedea0SLionel Sambuc 
164*ebfedea0SLionel Sambuc 	len = 0;
165*ebfedea0SLionel Sambuc 	if (ctx->bufneed > 0) {
166*ebfedea0SLionel Sambuc 		p = ctx->buf + ctx->maxbuf - ctx->bufneed;
167*ebfedea0SLionel Sambuc 		len = MIN(inlen, ctx->bufneed);
168*ebfedea0SLionel Sambuc 		memcpy(p, in, len);
169*ebfedea0SLionel Sambuc 		ctx->bufneed -= len;
170*ebfedea0SLionel Sambuc 		if (ctx->bufneed > 0) {
171*ebfedea0SLionel Sambuc 			*out = NULL;
172*ebfedea0SLionel Sambuc 			*outlen = 0;
173*ebfedea0SLionel Sambuc 			return len;
174*ebfedea0SLionel Sambuc 		}
175*ebfedea0SLionel Sambuc 		*out = ctx->buf;
176*ebfedea0SLionel Sambuc 		*outlen = ctx->maxbuf;
177*ebfedea0SLionel Sambuc 		ctx->bufneed = ctx->maxbuf;	/* for next call */
178*ebfedea0SLionel Sambuc 		return len;
179*ebfedea0SLionel Sambuc 	}
180*ebfedea0SLionel Sambuc 	assert(/*CONSTCOND*/0);		/* should not happen! */
181*ebfedea0SLionel Sambuc 	saslc__error_set(ERR(ctx->sess), ERROR_MECH, "buffer coding error");
182*ebfedea0SLionel Sambuc 	*out = NULL;
183*ebfedea0SLionel Sambuc 	*outlen = 0;
184*ebfedea0SLionel Sambuc 	ctx->bufneed = ctx->maxbuf;	/* for next call */
185*ebfedea0SLionel Sambuc 	return -1;
186*ebfedea0SLionel Sambuc }
187*ebfedea0SLionel Sambuc 
188*ebfedea0SLionel Sambuc /****************************************
189*ebfedea0SLionel Sambuc  * saslc__buffer32_* routines.
190*ebfedea0SLionel Sambuc  * For fetching an encoded packet.
191*ebfedea0SLionel Sambuc  * The packet is of the form:
192*ebfedea0SLionel Sambuc  * struct {
193*ebfedea0SLionel Sambuc  *     uint8_t size[4];		// bytes in payload
194*ebfedea0SLionel Sambuc  *     uint8_t payload[];	// packet payload (including any trailing HMAC)
195*ebfedea0SLionel Sambuc  * } __packed;
196*ebfedea0SLionel Sambuc  */
197*ebfedea0SLionel Sambuc 
198*ebfedea0SLionel Sambuc /**
199*ebfedea0SLionel Sambuc  * @brief destroy a buffer32 context
200*ebfedea0SLionel Sambuc  * @param ctx context to destroy
201*ebfedea0SLionel Sambuc  * @return nothing
202*ebfedea0SLionel Sambuc  */
203*ebfedea0SLionel Sambuc void
saslc__buffer32_destroy(saslc__buffer32_context_t * ctx)204*ebfedea0SLionel Sambuc saslc__buffer32_destroy(saslc__buffer32_context_t *ctx)
205*ebfedea0SLionel Sambuc {
206*ebfedea0SLionel Sambuc 
207*ebfedea0SLionel Sambuc 	free(ctx);
208*ebfedea0SLionel Sambuc }
209*ebfedea0SLionel Sambuc 
210*ebfedea0SLionel Sambuc /**
211*ebfedea0SLionel Sambuc  * @brief create a buffer32 context
212*ebfedea0SLionel Sambuc  * @param sess saslc session
213*ebfedea0SLionel Sambuc  * @param maxbuf maximum buffer size
214*ebfedea0SLionel Sambuc  * @return buffer context
215*ebfedea0SLionel Sambuc  */
216*ebfedea0SLionel Sambuc saslc__buffer32_context_t *
saslc__buffer32_create(saslc_sess_t * sess,size_t maxbuf)217*ebfedea0SLionel Sambuc saslc__buffer32_create(saslc_sess_t *sess, size_t maxbuf)
218*ebfedea0SLionel Sambuc {
219*ebfedea0SLionel Sambuc 	saslc__buffer32_context_t *ctx;
220*ebfedea0SLionel Sambuc 	size_t buflen;
221*ebfedea0SLionel Sambuc 
222*ebfedea0SLionel Sambuc 	buflen = sizeof(*ctx) - sizeof(ctx->buf) + maxbuf;
223*ebfedea0SLionel Sambuc 	ctx = malloc(buflen);
224*ebfedea0SLionel Sambuc 	if (ctx == NULL) {
225*ebfedea0SLionel Sambuc 		saslc__error_set_errno(ERR(sess), ERROR_NOMEM);
226*ebfedea0SLionel Sambuc 		return NULL;
227*ebfedea0SLionel Sambuc 	}
228*ebfedea0SLionel Sambuc 	memset(ctx, 0, sizeof(*ctx) - sizeof(ctx->buf));
229*ebfedea0SLionel Sambuc 
230*ebfedea0SLionel Sambuc 	ctx->maxbuf = maxbuf;
231*ebfedea0SLionel Sambuc 	ctx->szneed = sizeof(ctx->szbuf);
232*ebfedea0SLionel Sambuc 	ctx->sess = sess;
233*ebfedea0SLionel Sambuc 	return ctx;
234*ebfedea0SLionel Sambuc }
235*ebfedea0SLionel Sambuc 
236*ebfedea0SLionel Sambuc /**
237*ebfedea0SLionel Sambuc  * @brief fetch a block of data from the input stream.  The block is
238*ebfedea0SLionel Sambuc  * prefixed in the stream by a 4 byte length field (in network byte
239*ebfedea0SLionel Sambuc  * order).
240*ebfedea0SLionel Sambuc  * @param ctx context
241*ebfedea0SLionel Sambuc  * @param in input buffer
242*ebfedea0SLionel Sambuc  * @param inlen input buffer length
243*ebfedea0SLionel Sambuc  * @param out pointer to output buffer
244*ebfedea0SLionel Sambuc  * @param outlen pointer to output buffer length
245*ebfedea0SLionel Sambuc  * @return number of bytes consumed by the current call on success, 0
246*ebfedea0SLionel Sambuc  * if more data is needed, or -1 on failure.
247*ebfedea0SLionel Sambuc  */
248*ebfedea0SLionel Sambuc ssize_t
saslc__buffer32_fetch(saslc__buffer32_context_t * ctx,const uint8_t * in,size_t inlen,uint8_t ** out,size_t * outlen)249*ebfedea0SLionel Sambuc saslc__buffer32_fetch(saslc__buffer32_context_t *ctx, const uint8_t *in,
250*ebfedea0SLionel Sambuc     size_t inlen, uint8_t **out, size_t *outlen)
251*ebfedea0SLionel Sambuc {
252*ebfedea0SLionel Sambuc 	uint8_t *p;
253*ebfedea0SLionel Sambuc 	size_t ate, len;
254*ebfedea0SLionel Sambuc 
255*ebfedea0SLionel Sambuc 	if (inlen == 0) { /* we cannot flush the decode buffer */
256*ebfedea0SLionel Sambuc 		saslc__error_set(ERR(ctx->sess), ERROR_BADARG,
257*ebfedea0SLionel Sambuc 		    "bad inlen: cannot flush decode buffer");
258*ebfedea0SLionel Sambuc 		return -1;
259*ebfedea0SLionel Sambuc 	}
260*ebfedea0SLionel Sambuc 	ate = 0;
261*ebfedea0SLionel Sambuc 	if (ctx->szneed) {
262*ebfedea0SLionel Sambuc 		p = ctx->szbuf + sizeof(ctx->szbuf) - ctx->szneed;
263*ebfedea0SLionel Sambuc 		len = MIN(inlen, ctx->szneed);
264*ebfedea0SLionel Sambuc 		memcpy(p, in, len);
265*ebfedea0SLionel Sambuc 		ctx->szneed -= len;
266*ebfedea0SLionel Sambuc 		ate += len;
267*ebfedea0SLionel Sambuc 		if (ctx->szneed > 0)
268*ebfedea0SLionel Sambuc 			goto need_more;
269*ebfedea0SLionel Sambuc 
270*ebfedea0SLionel Sambuc 		ctx->bufsize = be32dec(ctx->szbuf);
271*ebfedea0SLionel Sambuc 		if (ctx->bufsize == 0) {
272*ebfedea0SLionel Sambuc 			saslc__error_set(ERR(ctx->sess), ERROR_MECH,
273*ebfedea0SLionel Sambuc 			    "pack with no payload");
274*ebfedea0SLionel Sambuc 			return -1;
275*ebfedea0SLionel Sambuc 		}
276*ebfedea0SLionel Sambuc 		if (ctx->bufsize > ctx->maxbuf) {
277*ebfedea0SLionel Sambuc 			saslc__error_set(ERR(ctx->sess), ERROR_MECH,
278*ebfedea0SLionel Sambuc 			    "payload longer than maxbuf");
279*ebfedea0SLionel Sambuc 			return -1;
280*ebfedea0SLionel Sambuc 		}
281*ebfedea0SLionel Sambuc 		in += len;
282*ebfedea0SLionel Sambuc 		inlen -= len;
283*ebfedea0SLionel Sambuc 		ctx->bufneed = ctx->bufsize;
284*ebfedea0SLionel Sambuc 	}
285*ebfedea0SLionel Sambuc 	if (ctx->bufneed) {
286*ebfedea0SLionel Sambuc 		p = ctx->buf + ctx->bufsize - ctx->bufneed;
287*ebfedea0SLionel Sambuc 		len = MIN(inlen, ctx->bufneed);
288*ebfedea0SLionel Sambuc 		memcpy(p, in, len);
289*ebfedea0SLionel Sambuc 		ctx->bufneed -= len;
290*ebfedea0SLionel Sambuc 		ate += len;
291*ebfedea0SLionel Sambuc 		if (ctx->bufneed > 0)
292*ebfedea0SLionel Sambuc 			goto need_more;
293*ebfedea0SLionel Sambuc 	}
294*ebfedea0SLionel Sambuc 	ctx->szneed = sizeof(ctx->szbuf);	/* for next call */
295*ebfedea0SLionel Sambuc 	*out = ctx->szbuf;
296*ebfedea0SLionel Sambuc 	*outlen = sizeof(ctx->szbuf) + ctx->bufsize;
297*ebfedea0SLionel Sambuc 	return ate;
298*ebfedea0SLionel Sambuc  need_more:
299*ebfedea0SLionel Sambuc 	*out = NULL;
300*ebfedea0SLionel Sambuc 	*outlen = 0;
301*ebfedea0SLionel Sambuc 	return ate;
302*ebfedea0SLionel Sambuc }
303