Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: fko_encode.c
5 : : *
6 : : * Purpose: Encodes some pieces of the spa data then puts together all of
7 : : * the necessary pieces to gether to create the single encoded
8 : : * message string.
9 : : *
10 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
11 : : * Copyright (C) 2009-2014 fwknop developers and contributors. For a full
12 : : * list of contributors, see the file 'CREDITS'.
13 : : *
14 : : * License (GNU General Public License):
15 : : *
16 : : * This program is free software; you can redistribute it and/or
17 : : * modify it under the terms of the GNU General Public License
18 : : * as published by the Free Software Foundation; either version 2
19 : : * of the License, or (at your option) any later version.
20 : : *
21 : : * This program is distributed in the hope that it will be useful,
22 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 : : * GNU General Public License for more details.
25 : : *
26 : : * You should have received a copy of the GNU General Public License
27 : : * along with this program; if not, write to the Free Software
28 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 : : * USA
30 : : *
31 : : *****************************************************************************
32 : : */
33 : : #include "fko_common.h"
34 : : #include "fko.h"
35 : : #include "base64.h"
36 : : #include "digest.h"
37 : :
38 : : /* Take a given string, base64-encode it and append it to the given
39 : : * buffer.
40 : : */
41 : : static int
42 : 858 : append_b64(char* tbuf, char *str)
43 : : {
44 : 858 : int len = strnlen(str, MAX_SPA_ENCODED_MSG_SIZE);
45 : : char *bs;
46 : :
47 : : #if HAVE_LIBFIU
48 : : fiu_return_on("append_b64_toobig",
49 : : FKO_ERROR_INVALID_DATA_ENCODE_MESSAGE_TOOBIG);
50 : : #endif
51 : :
52 [ + - ]: 858 : if(len >= MAX_SPA_ENCODED_MSG_SIZE)
53 : : return(FKO_ERROR_INVALID_DATA_ENCODE_MESSAGE_TOOBIG);
54 : :
55 : : #if HAVE_LIBFIU
56 : : fiu_return_on("append_b64_calloc", FKO_ERROR_MEMORY_ALLOCATION);
57 : : #endif
58 : :
59 : 858 : bs = calloc(1, ((len/3)*4)+8);
60 [ + - ]: 858 : if(bs == NULL)
61 : : return(FKO_ERROR_MEMORY_ALLOCATION);
62 : :
63 : 858 : b64_encode((unsigned char*)str, bs, len);
64 : :
65 : : /* --DSS XXX: make sure to check here if later decoding
66 : : * becomes a problem.
67 : : */
68 : 858 : strip_b64_eq(bs);
69 : :
70 : 858 : strlcat(tbuf, bs, FKO_ENCODE_TMP_BUF_SIZE);
71 : :
72 : 858 : free(bs);
73 : :
74 : 858 : return(FKO_SUCCESS);
75 : : }
76 : :
77 : : /* Set the SPA encryption type.
78 : : */
79 : : int
80 : 429 : fko_encode_spa_data(fko_ctx_t ctx)
81 : : {
82 : 429 : int res, offset = 0;
83 : : char *tbuf;
84 : :
85 : : #if HAVE_LIBFIU
86 : : fiu_return_on("fko_encode_spa_data_init", FKO_ERROR_CTX_NOT_INITIALIZED);
87 : : #endif
88 : : /* Must be initialized
89 : : */
90 [ + - ][ + - ]: 429 : if(!CTX_INITIALIZED(ctx))
91 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
92 : :
93 : : /* Check prerequisites.
94 : : * --DSS XXX: Needs review. Also, we could make this more robust (or
95 : : * (at leaset expand the error reporting for the missing
96 : : * data).
97 : : */
98 : : #if HAVE_LIBFIU
99 : : fiu_return_on("fko_encode_spa_data_valid", FKO_ERROR_INCOMPLETE_SPA_DATA);
100 : : #endif
101 [ + - ]: 429 : if( validate_username(ctx->username) != FKO_SUCCESS
102 [ + - ][ + - ]: 429 : || ctx->version == NULL || strnlen(ctx->version, MAX_SPA_VERSION_SIZE) == 0
103 [ + - ][ + - ]: 429 : || ctx->message == NULL || strnlen(ctx->message, MAX_SPA_MESSAGE_SIZE) == 0)
104 : : {
105 : : return(FKO_ERROR_INCOMPLETE_SPA_DATA);
106 : : }
107 : :
108 [ - + ]: 429 : if(ctx->message_type == FKO_NAT_ACCESS_MSG)
109 : : {
110 [ # # ][ # # ]: 0 : if(ctx->nat_access == NULL || strnlen(ctx->nat_access, MAX_SPA_MESSAGE_SIZE) == 0)
111 : : return(FKO_ERROR_INCOMPLETE_SPA_DATA);
112 : : }
113 : :
114 : : #if HAVE_LIBFIU
115 : : fiu_return_on("fko_encode_spa_data_calloc", FKO_ERROR_MEMORY_ALLOCATION);
116 : : #endif
117 : : /* Allocate our initial tmp buffer.
118 : : */
119 : 429 : tbuf = calloc(1, FKO_ENCODE_TMP_BUF_SIZE);
120 [ + - ]: 429 : if(tbuf == NULL)
121 : : return(FKO_ERROR_MEMORY_ALLOCATION);
122 : :
123 : : /* Put it together a piece at a time, starting with the rand val.
124 : : */
125 : 429 : strlcpy(tbuf, ctx->rand_val, FKO_ENCODE_TMP_BUF_SIZE);
126 : :
127 : : /* Add the base64-encoded username.
128 : : */
129 : 429 : strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
130 [ - + ]: 429 : if((res = append_b64(tbuf, ctx->username)) != FKO_SUCCESS)
131 : : {
132 : 0 : free(tbuf);
133 : 0 : return(res);
134 : : }
135 : :
136 : : /* Add the timestamp.
137 : : */
138 : 429 : offset = strlen(tbuf);
139 : 429 : snprintf(((char*)tbuf+offset), FKO_ENCODE_TMP_BUF_SIZE - offset,
140 : 429 : ":%u:", (unsigned int) ctx->timestamp);
141 : :
142 : : /* Add the version string.
143 : : */
144 : 429 : strlcat(tbuf, ctx->version, FKO_ENCODE_TMP_BUF_SIZE);
145 : :
146 : : /* Before we add the message type value, we will once again
147 : : * check for whether or not a client_timeout was specified
148 : : * since the message_type was set. If this is the case, then
149 : : * we want to adjust the message_type first. The easy way
150 : : * to do this is simply call fko_set_spa_client_timeout and set
151 : : * it to its current value. This will force a re-check and
152 : : * possible reset of the message type.
153 : : *
154 : : */
155 : 429 : fko_set_spa_client_timeout(ctx, ctx->client_timeout);
156 : :
157 : : /* Add the message type value.
158 : : */
159 : 429 : offset = strlen(tbuf);
160 : 429 : snprintf(((char*)tbuf+offset), FKO_ENCODE_TMP_BUF_SIZE - offset,
161 : 429 : ":%i:", ctx->message_type);
162 : :
163 : : /* Add the base64-encoded SPA message.
164 : : */
165 [ - + ]: 429 : if((res = append_b64(tbuf, ctx->message)) != FKO_SUCCESS)
166 : : {
167 : 0 : free(tbuf);
168 : 0 : return(res);
169 : : }
170 : :
171 : : /* If a nat_access message was given, add it to the SPA
172 : : * message.
173 : : */
174 [ - + ]: 429 : if(ctx->nat_access != NULL)
175 : : {
176 : 0 : strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
177 [ # # ]: 0 : if((res = append_b64(tbuf, ctx->nat_access)) != FKO_SUCCESS)
178 : : {
179 : 0 : free(tbuf);
180 : 0 : return(res);
181 : : }
182 : : }
183 : :
184 : : /* If we have a server_auth field set. Add it here.
185 : : *
186 : : */
187 [ - + ]: 429 : if(ctx->server_auth != NULL)
188 : : {
189 : 0 : strlcat(tbuf, ":", FKO_ENCODE_TMP_BUF_SIZE);
190 [ # # ]: 0 : if((res = append_b64(tbuf, ctx->server_auth)) != FKO_SUCCESS)
191 : : {
192 : 0 : free(tbuf);
193 : 0 : return(res);
194 : : }
195 : : }
196 : :
197 : : /* If a client timeout is specified and we are not dealing with a
198 : : * SPA command message, add the timeout here.
199 : : */
200 [ + + ][ + - ]: 429 : if(ctx->client_timeout > 0 && ctx->message_type != FKO_COMMAND_MSG)
201 : : {
202 : 1 : offset = strlen(tbuf);
203 : 1 : snprintf(((char*)tbuf+offset), FKO_ENCODE_TMP_BUF_SIZE - offset,
204 : : ":%i", ctx->client_timeout);
205 : : }
206 : :
207 : : /* If encoded_msg is not null, then we assume it needs to
208 : : * be freed before re-assignment.
209 : : */
210 [ - + ]: 429 : if(ctx->encoded_msg != NULL)
211 : 0 : free(ctx->encoded_msg);
212 : :
213 : : /* Copy our encoded data into the context.
214 : : */
215 : 429 : ctx->encoded_msg = strdup(tbuf);
216 : 429 : free(tbuf);
217 : :
218 [ + - ]: 429 : if(ctx->encoded_msg == NULL)
219 : : return(FKO_ERROR_MEMORY_ALLOCATION);
220 : :
221 : 429 : ctx->encoded_msg_len = strnlen(ctx->encoded_msg, MAX_SPA_ENCODED_MSG_SIZE);
222 : :
223 [ + - ]: 429 : if(! is_valid_encoded_msg_len(ctx->encoded_msg_len))
224 : : return(FKO_ERROR_INVALID_DATA_ENCODE_MSGLEN_VALIDFAIL);
225 : :
226 : : /* At this point we can compute the digest for this SPA data.
227 : : */
228 [ + - ]: 429 : if((res = fko_set_spa_digest(ctx)) != FKO_SUCCESS)
229 : : return(res);
230 : :
231 : : /* Here we can clear the modified flags on the SPA data fields.
232 : : */
233 : 429 : FKO_CLEAR_SPA_DATA_MODIFIED(ctx);
234 : :
235 : 429 : return(FKO_SUCCESS);
236 : : }
237 : :
238 : : /* Return the fko SPA encrypted data.
239 : : */
240 : : int
241 : 449 : fko_get_encoded_data(fko_ctx_t ctx, char **enc_msg)
242 : : {
243 : : /* Must be initialized
244 : : */
245 [ + - ][ + - ]: 449 : if(!CTX_INITIALIZED(ctx))
246 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
247 : :
248 [ + - ]: 449 : if(enc_msg == NULL)
249 : : return(FKO_ERROR_INVALID_DATA);
250 : :
251 : 449 : *enc_msg = ctx->encoded_msg;
252 : :
253 : 449 : return(FKO_SUCCESS);
254 : : }
255 : :
256 : : /* Set the fko SPA encoded data (this is a convenience
257 : : * function mostly used for tests that involve fuzzing).
258 : : */
259 : : #if FUZZING_INTERFACES
260 : : int
261 : 448 : fko_set_encoded_data(fko_ctx_t ctx,
262 : : const char * const encoded_msg, const int msg_len,
263 : : const int require_digest, const int digest_type)
264 : : {
265 : 448 : char *tbuf = NULL;
266 : 448 : int res = FKO_SUCCESS, mlen;
267 : :
268 : : /* Must be initialized
269 : : */
270 [ + - ][ + - ]: 448 : if(!CTX_INITIALIZED(ctx))
271 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
272 : :
273 [ + - ]: 448 : if(encoded_msg == NULL)
274 : : return(FKO_ERROR_INVALID_DATA);
275 : :
276 : 448 : ctx->encoded_msg = strdup(encoded_msg);
277 : :
278 : 448 : ctx->state |= FKO_DATA_MODIFIED;
279 : :
280 [ + - ]: 448 : if(ctx->encoded_msg == NULL)
281 : : return(FKO_ERROR_MEMORY_ALLOCATION);
282 : :
283 : : /* allow arbitrary length (i.e. let the decode routines validate
284 : : * SPA message length).
285 : : */
286 : 448 : ctx->encoded_msg_len = msg_len;
287 : :
288 [ - + ]: 448 : if(require_digest)
289 : : {
290 : 0 : fko_set_spa_digest_type(ctx, digest_type);
291 [ # # ]: 0 : if((res = fko_set_spa_digest(ctx)) != FKO_SUCCESS)
292 : : {
293 : : return res;
294 : : }
295 : :
296 : : /* append the digest to the encoded message buffer
297 : : */
298 : 0 : mlen = ctx->encoded_msg_len + ctx->digest_len + 2;
299 : 0 : tbuf = calloc(1, mlen);
300 [ # # ]: 0 : if(tbuf == NULL)
301 : : return(FKO_ERROR_MEMORY_ALLOCATION);
302 : :
303 : : /* memcpy since the provided encoded buffer might
304 : : * have an embedded NULL?
305 : : */
306 : 0 : mlen = snprintf(tbuf, mlen, "%s:%s", ctx->encoded_msg, ctx->digest);
307 : :
308 [ # # ]: 0 : if(ctx->encoded_msg != NULL)
309 : 0 : free(ctx->encoded_msg);
310 : :
311 : 0 : ctx->encoded_msg = strdup(tbuf);
312 : 0 : free(tbuf);
313 : :
314 [ # # ]: 0 : if(ctx->encoded_msg == NULL)
315 : : return(FKO_ERROR_MEMORY_ALLOCATION);
316 : :
317 : 0 : ctx->encoded_msg_len = mlen;
318 : : }
319 : :
320 : 448 : FKO_CLEAR_SPA_DATA_MODIFIED(ctx);
321 : :
322 : 448 : return(FKO_SUCCESS);
323 : : }
324 : : #endif
325 : :
326 : : /***EOF***/
|