Bug fix for multi-stanza key use and replay attack detection
[fwknop.git] / lib / fko_funcs.c
1 /*
2  *****************************************************************************
3  *
4  * File:    fko_funcs.c
5  *
6  * Author:  Damien S. Stuart
7  *
8  * Purpose: General utility functions for libfko
9  *
10  * Copyright 2009-2010 Damien Stuart (dstuart@dstuart.org)
11  *
12  *  License (GNU Public License):
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
27  *  USA
28  *
29  *****************************************************************************
30 */
31 #include "fko_common.h"
32 #include "fko.h"
33 #include "cipher_funcs.h"
34
35 /* Initialize an fko context.
36 */
37 int
38 fko_new(fko_ctx_t *r_ctx)
39 {
40     fko_ctx_t   ctx;
41     int         res;
42     char       *ver;
43
44     ctx = calloc(1, sizeof *ctx);
45     if(ctx == NULL)
46         return(FKO_ERROR_MEMORY_ALLOCATION);
47
48     /* Set default values and state.
49      *
50      * Note: We have to explicitly set the ctx->state to initialized
51      *       just before making an fko_xxx function call, then set it
52      *       back to zero just afer.  During initialization, we need
53      *       to make these functions think they are operating on an
54      *       initialized context, or else they would fail.
55     */
56
57     /* Set the version string.
58     */
59     ctx->initval = FKO_CTX_INITIALIZED;
60     ver = strdup(FKO_PROTOCOL_VERSION);
61     ctx->initval = 0;
62     if(ver == NULL)
63     {
64         free(ctx);
65         return(FKO_ERROR_MEMORY_ALLOCATION);
66     }
67
68     ctx->version = ver;
69
70     /* Rand value.
71     */
72     ctx->initval = FKO_CTX_INITIALIZED;
73     res = fko_set_rand_value(ctx, NULL);
74     ctx->initval = 0;
75     if(res != FKO_SUCCESS)
76     {
77         fko_destroy(ctx);
78         return res;
79     }
80
81     /* Username.
82     */
83     ctx->initval = FKO_CTX_INITIALIZED;
84     res = fko_set_username(ctx, NULL);
85     ctx->initval = 0;
86     if(res != FKO_SUCCESS)
87     {
88         fko_destroy(ctx);
89         return res;
90     }
91
92     /* Timestamp.
93     */
94     ctx->initval = FKO_CTX_INITIALIZED;
95     res = fko_set_timestamp(ctx, 0);
96     ctx->initval = 0;
97     if(res != FKO_SUCCESS)
98     {
99         fko_destroy(ctx);
100         return res;
101     }
102
103     /* Default Digest Type.
104     */
105     ctx->initval = FKO_CTX_INITIALIZED;
106     res = fko_set_spa_digest_type(ctx, FKO_DEFAULT_DIGEST);
107     ctx->initval = 0;
108     if(res != FKO_SUCCESS)
109     {
110         fko_destroy(ctx);
111         return res;
112     }
113
114     /* Default Message Type.
115     */
116     ctx->initval = FKO_CTX_INITIALIZED;
117     res = fko_set_spa_message_type(ctx, FKO_DEFAULT_MSG_TYPE);
118     ctx->initval = 0;
119     if(res != FKO_SUCCESS)
120     {
121         fko_destroy(ctx);
122         return res;
123     }
124
125     /* Default Encryption Type.
126     */
127     ctx->initval = FKO_CTX_INITIALIZED;
128     res = fko_set_spa_encryption_type(ctx, FKO_DEFAULT_ENCRYPTION);
129     ctx->initval = 0;
130     if(res != FKO_SUCCESS)
131     {
132         fko_destroy(ctx);
133         return res;
134     }
135
136 #if HAVE_LIBGPGME
137     /* Set gpg signature verify on.
138     */
139     ctx->verify_gpg_sigs = 1;
140
141 #endif /* HAVE_LIBGPGME */
142
143     /* Now we mean it.
144     */
145     ctx->initval = FKO_CTX_INITIALIZED;
146
147     FKO_SET_CTX_INITIALIZED(ctx);
148
149     *r_ctx = ctx;
150
151     return(FKO_SUCCESS);
152 }
153
154 /* Initialize an fko context with external (encrypted/encoded) data.
155  * This is used to create a context with the purpose of decoding
156  * and parsing the provided data into the context data.
157 */
158 int
159 fko_new_with_data(fko_ctx_t *r_ctx, const char *enc_msg, const char *dec_key)
160 {
161     fko_ctx_t   ctx;
162     int         res = FKO_SUCCESS; /* Are we optimistic or what? */
163
164     ctx = calloc(1, sizeof *ctx);
165     if(ctx == NULL)
166         return(FKO_ERROR_MEMORY_ALLOCATION);
167
168     /* First, add the data to the context.
169     */
170     ctx->encrypted_msg = strdup(enc_msg);
171     if(ctx->encrypted_msg == NULL)
172     {
173         free(ctx);
174         return(FKO_ERROR_MEMORY_ALLOCATION);
175     }
176
177     /* Consider it initialized here.
178     */
179     ctx->initval = FKO_CTX_INITIALIZED;
180     FKO_SET_CTX_INITIALIZED(ctx);
181
182     /* If a decryption password is provided, go ahead and decrypt and
183      * decode.
184     */
185     if(dec_key != NULL)
186     {
187         res = fko_decrypt_spa_data(ctx, dec_key);
188
189         if(res != FKO_SUCCESS)
190         {
191             fko_destroy(ctx);
192             *r_ctx = NULL; /* Make sure the caller ctx is null just in case */
193             return(res);
194         }
195     }
196
197 #if HAVE_LIBGPGME
198     /* Set gpg signature verify on.
199     */
200     ctx->verify_gpg_sigs = 1;
201
202 #endif /* HAVE_LIBGPGME */
203
204     *r_ctx = ctx;
205
206     return(res);
207 }
208
209 /* Destroy a context and free its resources
210 */
211 void
212 fko_destroy(fko_ctx_t ctx)
213 {
214 #if HAVE_LIBGPGME
215     fko_gpg_sig_t   gsig, tgsig;
216 #endif
217
218     if(CTX_INITIALIZED(ctx))
219     {
220         if(ctx->rand_val != NULL)
221             free(ctx->rand_val);
222
223         if(ctx->username != NULL)
224             free(ctx->username);
225
226         if(ctx->version != NULL)
227             free(ctx->version);
228
229         if(ctx->message != NULL)
230             free(ctx->message);
231
232         if(ctx->nat_access != NULL)
233             free(ctx->nat_access);
234
235         if(ctx->server_auth != NULL)
236             free(ctx->server_auth);
237
238         if(ctx->digest != NULL)
239             free(ctx->digest);
240
241         if(ctx->raw_digest != NULL)
242             free(ctx->raw_digest);
243
244         if(ctx->encoded_msg != NULL)
245             free(ctx->encoded_msg);
246
247         if(ctx->encrypted_msg != NULL)
248             free(ctx->encrypted_msg);
249
250 #if HAVE_LIBGPGME
251         if(ctx->gpg_exe != NULL)
252             free(ctx->gpg_exe);
253
254         if(ctx->gpg_home_dir != NULL)
255             free(ctx->gpg_home_dir);
256
257         if(ctx->gpg_recipient != NULL)
258             free(ctx->gpg_recipient);
259
260         if(ctx->gpg_signer != NULL)
261             free(ctx->gpg_signer);
262
263         if(ctx->recipient_key != NULL)
264         {
265             gpgme_key_unref(ctx->recipient_key);
266         }
267
268         if(ctx->signer_key != NULL)
269         {
270             gpgme_key_unref(ctx->signer_key);
271         }
272
273         if(ctx->gpg_ctx != NULL)
274             gpgme_release(ctx->gpg_ctx);
275
276         gsig = ctx->gpg_sigs;
277         while(gsig != NULL)
278         {
279             if(gsig->fpr != NULL)
280                 free(gsig->fpr);
281
282             tgsig = gsig;
283             gsig = gsig->next;
284
285             free(tgsig);
286         }
287
288 #endif /* HAVE_LIBGPGME */
289
290         bzero(ctx, sizeof(*ctx));
291     }
292
293     free(ctx);
294 }
295
296 /* Return the fko version
297 */
298 int
299 fko_get_version(fko_ctx_t ctx, char **version)
300 {
301     /* Must be initialized
302     */
303     if(!CTX_INITIALIZED(ctx))
304         return(FKO_ERROR_CTX_NOT_INITIALIZED);
305
306     *version = ctx->version;
307
308     return(FKO_SUCCESS);
309 }
310
311 /* Final update and encoding of data in the context.
312  * This does require all requisite fields be properly
313  * set.
314 */
315 int
316 fko_spa_data_final(fko_ctx_t ctx, const char *enc_key)
317 {
318     /* Must be initialized
319     */
320     if(!CTX_INITIALIZED(ctx))
321         return(FKO_ERROR_CTX_NOT_INITIALIZED);
322
323     return(fko_encrypt_spa_data(ctx, enc_key));
324 }
325
326 /* Return the fko SPA encrypted data.
327 */
328 int
329 fko_get_spa_data(fko_ctx_t ctx, char **spa_data)
330 {
331     /* Must be initialized
332     */
333     if(!CTX_INITIALIZED(ctx))
334         return(FKO_ERROR_CTX_NOT_INITIALIZED);
335
336     /* We expect to have encrypted data to process.  If not, we bail.
337     */
338     if(ctx->encrypted_msg == NULL || (strlen(ctx->encrypted_msg) < 1))
339         return(FKO_ERROR_MISSING_ENCODED_DATA);
340
341     *spa_data = ctx->encrypted_msg;
342
343     /* Notice we omit the first 10 bytes if Rijndael encryption is
344      * used (to eliminate the consistent 'Salted__' string), and
345      * in GnuPG mode we eliminate the consistent 'hQ' base64 encoded
346      * prefix
347     */
348     if(ctx->encryption_type == FKO_ENCRYPTION_RIJNDAEL)
349         *spa_data += strlen(B64_RIJNDAEL_SALT);
350     else if(ctx->encryption_type == FKO_ENCRYPTION_GPG)
351         *spa_data += strlen(B64_GPG_PREFIX);
352
353     return(FKO_SUCCESS);
354 }
355
356 /* Set the fko SPA encrypted data.
357 */
358 int
359 fko_set_spa_data(fko_ctx_t ctx, const char *enc_msg)
360 {
361     /* Must be initialized
362     */
363     if(!CTX_INITIALIZED(ctx))
364         return FKO_ERROR_CTX_NOT_INITIALIZED;
365
366     /* First, add the data to the context.
367     */
368     ctx->encrypted_msg = strdup(enc_msg);
369     if(ctx->encrypted_msg == NULL)
370         return(FKO_ERROR_MEMORY_ALLOCATION);
371
372     return(FKO_SUCCESS);
373 }
374
375 /***EOF***/