4a74438d5aaa2b53964de8244cb22f18f2853b07
[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->encoded_msg != NULL)
242             free(ctx->encoded_msg);
243
244         if(ctx->encrypted_msg != NULL)
245             free(ctx->encrypted_msg);
246
247 #if HAVE_LIBGPGME
248         if(ctx->gpg_exe != NULL)
249             free(ctx->gpg_exe);
250
251         if(ctx->gpg_home_dir != NULL)
252             free(ctx->gpg_home_dir);
253
254         if(ctx->gpg_recipient != NULL)
255             free(ctx->gpg_recipient);
256
257         if(ctx->gpg_signer != NULL)
258             free(ctx->gpg_signer);
259
260         if(ctx->recipient_key != NULL)
261         {
262             gpgme_key_unref(ctx->recipient_key);
263         }
264
265         if(ctx->signer_key != NULL)
266         {
267             gpgme_key_unref(ctx->signer_key);
268         }
269
270         if(ctx->gpg_ctx != NULL)
271             gpgme_release(ctx->gpg_ctx);
272
273         gsig = ctx->gpg_sigs;
274         while(gsig != NULL)
275         {
276             if(gsig->fpr != NULL)
277                 free(gsig->fpr);
278
279             tgsig = gsig;
280             gsig = gsig->next;
281
282             free(tgsig);
283         }
284
285 #endif /* HAVE_LIBGPGME */
286
287         bzero(ctx, sizeof(*ctx));
288     }
289
290     free(ctx);
291 }
292
293 /* Return the fko version
294 */
295 int
296 fko_get_version(fko_ctx_t ctx, char **version)
297 {
298     /* Must be initialized
299     */
300     if(!CTX_INITIALIZED(ctx))
301         return(FKO_ERROR_CTX_NOT_INITIALIZED);
302
303     *version = ctx->version;
304
305     return(FKO_SUCCESS);
306 }
307
308 /* Final update and encoding of data in the context.
309  * This does require all requisite fields be properly
310  * set.
311 */
312 int
313 fko_spa_data_final(fko_ctx_t ctx, const char *enc_key)
314 {
315     /* Must be initialized
316     */
317     if(!CTX_INITIALIZED(ctx))
318         return(FKO_ERROR_CTX_NOT_INITIALIZED);
319
320     return(fko_encrypt_spa_data(ctx, enc_key));
321 }
322
323 /* Return the fko SPA encrypted data.
324 */
325 int
326 fko_get_spa_data(fko_ctx_t ctx, char **spa_data)
327 {
328     /* Must be initialized
329     */
330     if(!CTX_INITIALIZED(ctx))
331         return(FKO_ERROR_CTX_NOT_INITIALIZED);
332
333     /* We expect to have encrypted data to process.  If not, we bail.
334     */
335     if(ctx->encrypted_msg == NULL || (strlen(ctx->encrypted_msg) < 1))
336         return(FKO_ERROR_MISSING_ENCODED_DATA);
337
338     *spa_data = ctx->encrypted_msg;
339
340     /* Notice we omit the first 10 bytes if Rijndael encryption is
341      * used (to eliminate the consistent 'Salted__' string), and
342      * in GnuPG mode we eliminate the consistent 'hQ' base64 encoded
343      * prefix
344     */
345     if(ctx->encryption_type == FKO_ENCRYPTION_RIJNDAEL)
346         *spa_data += strlen(B64_RIJNDAEL_SALT);
347     else if(ctx->encryption_type == FKO_ENCRYPTION_GPG)
348         *spa_data += strlen(B64_GPG_PREFIX);
349
350     return(FKO_SUCCESS);
351 }
352
353 /* Set the fko SPA encrypted data.
354 */
355 int
356 fko_set_spa_data(fko_ctx_t ctx, const char *enc_msg)
357 {
358     /* Must be initialized
359     */
360     if(!CTX_INITIALIZED(ctx))
361         return FKO_ERROR_CTX_NOT_INITIALIZED;
362
363     /* First, add the data to the context.
364     */
365     ctx->encrypted_msg = strdup(enc_msg);
366     if(ctx->encrypted_msg == NULL)
367         return(FKO_ERROR_MEMORY_ALLOCATION);
368
369     return(FKO_SUCCESS);
370 }
371
372 /***EOF***/