merged usage() information from master
[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     /* Default Encryption Mode (Rijndael in EBC mode for backwards
137      * compatibility - it recommended to change this to CBC mode)
138     */
139     ctx->initval = FKO_CTX_INITIALIZED;
140     res = fko_set_spa_encryption_mode(ctx, FKO_DEFAULT_ENC_MODE);
141     ctx->initval = 0;
142     if(res != FKO_SUCCESS)
143     {
144         fko_destroy(ctx);
145         return res;
146     }
147
148 #if HAVE_LIBGPGME
149     /* Set gpg signature verify on.
150     */
151     ctx->verify_gpg_sigs = 1;
152
153 #endif /* HAVE_LIBGPGME */
154
155     /* Now we mean it.
156     */
157     ctx->initval = FKO_CTX_INITIALIZED;
158
159     FKO_SET_CTX_INITIALIZED(ctx);
160
161     *r_ctx = ctx;
162
163     return(FKO_SUCCESS);
164 }
165
166 /* Initialize an fko context with external (encrypted/encoded) data.
167  * This is used to create a context with the purpose of decoding
168  * and parsing the provided data into the context data.
169 */
170 int
171 fko_new_with_data(fko_ctx_t *r_ctx, const char *enc_msg,
172     const char *dec_key, int encryption_mode)
173 {
174     fko_ctx_t   ctx;
175     int         res = FKO_SUCCESS; /* Are we optimistic or what? */
176
177     ctx = calloc(1, sizeof *ctx);
178     if(ctx == NULL)
179         return(FKO_ERROR_MEMORY_ALLOCATION);
180
181     /* First, add the data to the context.
182     */
183     ctx->encrypted_msg = strdup(enc_msg);
184     if(ctx->encrypted_msg == NULL)
185     {
186         free(ctx);
187         return(FKO_ERROR_MEMORY_ALLOCATION);
188     }
189
190     /* Default Encryption Mode (Rijndael in CBC mode)
191     */
192     ctx->initval = FKO_CTX_INITIALIZED;
193     res = fko_set_spa_encryption_mode(ctx, encryption_mode);
194     ctx->initval = 0;
195     if(res != FKO_SUCCESS)
196     {
197         fko_destroy(ctx);
198         return res;
199     }
200
201     /* Consider it initialized here.
202     */
203     ctx->initval = FKO_CTX_INITIALIZED;
204     FKO_SET_CTX_INITIALIZED(ctx);
205
206     /* If a decryption key is provided, go ahead and decrypt and decode.
207     */
208     if(dec_key != NULL)
209     {
210         res = fko_decrypt_spa_data(ctx, dec_key);
211
212         if(res != FKO_SUCCESS)
213         {
214             fko_destroy(ctx);
215             *r_ctx = NULL; /* Make sure the caller ctx is null just in case */
216             return(res);
217         }
218     }
219
220 #if HAVE_LIBGPGME
221     /* Set gpg signature verify on.
222     */
223     ctx->verify_gpg_sigs = 1;
224
225 #endif /* HAVE_LIBGPGME */
226
227     *r_ctx = ctx;
228
229     return(res);
230 }
231
232 /* Destroy a context and free its resources
233 */
234 void
235 fko_destroy(fko_ctx_t ctx)
236 {
237 #if HAVE_LIBGPGME
238     fko_gpg_sig_t   gsig, tgsig;
239 #endif
240
241     if(CTX_INITIALIZED(ctx))
242     {
243         if(ctx->rand_val != NULL)
244             free(ctx->rand_val);
245
246         if(ctx->username != NULL)
247             free(ctx->username);
248
249         if(ctx->version != NULL)
250             free(ctx->version);
251
252         if(ctx->message != NULL)
253             free(ctx->message);
254
255         if(ctx->nat_access != NULL)
256             free(ctx->nat_access);
257
258         if(ctx->server_auth != NULL)
259             free(ctx->server_auth);
260
261         if(ctx->digest != NULL)
262             free(ctx->digest);
263
264         if(ctx->raw_digest != NULL)
265             free(ctx->raw_digest);
266
267         if(ctx->encoded_msg != NULL)
268             free(ctx->encoded_msg);
269
270         if(ctx->encrypted_msg != NULL)
271             free(ctx->encrypted_msg);
272
273 #if HAVE_LIBGPGME
274         if(ctx->gpg_exe != NULL)
275             free(ctx->gpg_exe);
276
277         if(ctx->gpg_home_dir != NULL)
278             free(ctx->gpg_home_dir);
279
280         if(ctx->gpg_recipient != NULL)
281             free(ctx->gpg_recipient);
282
283         if(ctx->gpg_signer != NULL)
284             free(ctx->gpg_signer);
285
286         if(ctx->recipient_key != NULL)
287         {
288             gpgme_key_unref(ctx->recipient_key);
289         }
290
291         if(ctx->signer_key != NULL)
292         {
293             gpgme_key_unref(ctx->signer_key);
294         }
295
296         if(ctx->gpg_ctx != NULL)
297             gpgme_release(ctx->gpg_ctx);
298
299         gsig = ctx->gpg_sigs;
300         while(gsig != NULL)
301         {
302             if(gsig->fpr != NULL)
303                 free(gsig->fpr);
304
305             tgsig = gsig;
306             gsig = gsig->next;
307
308             free(tgsig);
309         }
310
311 #endif /* HAVE_LIBGPGME */
312
313         bzero(ctx, sizeof(*ctx));
314     }
315
316     free(ctx);
317 }
318
319 /* Return the fko version
320 */
321 int
322 fko_get_version(fko_ctx_t ctx, char **version)
323 {
324     /* Must be initialized
325     */
326     if(!CTX_INITIALIZED(ctx))
327         return(FKO_ERROR_CTX_NOT_INITIALIZED);
328
329     *version = ctx->version;
330
331     return(FKO_SUCCESS);
332 }
333
334 /* Final update and encoding of data in the context.
335  * This does require all requisite fields be properly
336  * set.
337 */
338 int
339 fko_spa_data_final(fko_ctx_t ctx, const char *enc_key)
340 {
341     /* Must be initialized
342     */
343     if(!CTX_INITIALIZED(ctx))
344         return(FKO_ERROR_CTX_NOT_INITIALIZED);
345
346     return(fko_encrypt_spa_data(ctx, enc_key));
347 }
348
349 /* Return the fko SPA encrypted data.
350 */
351 int
352 fko_get_spa_data(fko_ctx_t ctx, char **spa_data)
353 {
354     /* Must be initialized
355     */
356     if(!CTX_INITIALIZED(ctx))
357         return(FKO_ERROR_CTX_NOT_INITIALIZED);
358
359     /* We expect to have encrypted data to process.  If not, we bail.
360     */
361     if(ctx->encrypted_msg == NULL || (strlen(ctx->encrypted_msg) < 1))
362         return(FKO_ERROR_MISSING_ENCODED_DATA);
363
364     *spa_data = ctx->encrypted_msg;
365
366     /* Notice we omit the first 10 bytes if Rijndael encryption is
367      * used (to eliminate the consistent 'Salted__' string), and
368      * in GnuPG mode we eliminate the consistent 'hQ' base64 encoded
369      * prefix
370     */
371     if(ctx->encryption_type == FKO_ENCRYPTION_RIJNDAEL)
372         *spa_data += strlen(B64_RIJNDAEL_SALT);
373     else if(ctx->encryption_type == FKO_ENCRYPTION_GPG)
374         *spa_data += strlen(B64_GPG_PREFIX);
375
376     return(FKO_SUCCESS);
377 }
378
379 /* Set the fko SPA encrypted data.
380 */
381 int
382 fko_set_spa_data(fko_ctx_t ctx, const char *enc_msg)
383 {
384     /* Must be initialized
385     */
386     if(!CTX_INITIALIZED(ctx))
387         return FKO_ERROR_CTX_NOT_INITIALIZED;
388
389     /* First, add the data to the context.
390     */
391     ctx->encrypted_msg = strdup(enc_msg);
392     if(ctx->encrypted_msg == NULL)
393         return(FKO_ERROR_MEMORY_ALLOCATION);
394
395     return(FKO_SUCCESS);
396 }
397
398 /***EOF***/