root/openpgpsdk/trunk/src/app/openpgp.c

Revision 612 (checked in by rachel, 5 years ago)

This (and previous commit) adds extra doxygen documentation.

Line 
1 /*
2  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
3  * All rights reserved.
4  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
5  * their moral rights under the UK Copyright Design and Patents Act 1988 to
6  * be recorded as the authors of this copyright work.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
9  * use this file except in compliance with the License.
10  *
11  * You may obtain a copy of the License at
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 /**
23  \file Command line program to perform openpgp operations
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <getopt.h>
30 #include <assert.h>
31 #include <libgen.h>
32
33 #include "openpgpsdk/keyring.h"
34 #include "../src/lib/keyring_local.h"
35 #include "openpgpsdk/crypto.h"
36 #include "openpgpsdk/signature.h"
37 #include "openpgpsdk/validate.h"
38 #include "openpgpsdk/readerwriter.h"
39 #include "openpgpsdk/std_print.h"
40
41 #define DEFAULT_NUMBITS 1024
42
43 static const char* usage="%s --list-keys | --encrypt | --decrypt | --sign | --clearsign | --verify [--keyring=<keyring>] [--userid=<userid>] [--filename=<filename>] [--armour] [--homedir=<homedir>]\n";
44 static const char* usage_list_keys="%s --list-keys [--keyring=<keyring>]\n";
45 // \todo static const char* usage_list_packets="%s --list-packets \n";
46 static const char* usage_find_key="%s --find-key --userid=<userid> [--keyring=<keyring>] \n";
47 static const char* usage_export_key="%s --export-key --userid=<userid> [--keyring=<keyring>] \n";
48 static const char* usage_import_key="%s --import-key --filename=<filename> --keyring=<keyring> \n";
49 static const char* usage_generate_key="%s --generate-key --userid=<userid> [--numbits=<numbits>] [--passphrase=<passphrase>]\n";
50 static const char* usage_encrypt="%s --encrypt --userid=<userid> --filename=<filename> [--armour] [--homedir=<homedir>]\n";
51 static const char* usage_decrypt="%s --decrypt --filename=<filename> [--armour] [--homedir=<homedir>]\n";
52 static const char* usage_sign="%s --sign --userid=<userid> --filename=<filename> [--armour] [--homedir=<homedir>]\n";
53 static const char* usage_clearsign="%s --clearsign --userid=<userid> --filename=<filename> [--homedir=<homedir>]\n";
54 static const char* usage_verify="%s --verify --filename=<filename> [--homedir=<homedir>] [--armour]\n";
55 static const char* usage_list_packets="%s --list-packets --filename=<filename> [--homedir=<homedir>] [--armour]\n";
56
57 static char* pname;
58
59 enum optdefs {
60 // commands
61 LIST_KEYS=1,
62 // \todo LIST_PACKETS,
63 FIND_KEY,
64 EXPORT_KEY,
65 IMPORT_KEY,
66 GENERATE_KEY,
67 ENCRYPT,
68 DECRYPT,
69 SIGN,
70 CLEARSIGN,
71 VERIFY,
72 LIST_PACKETS,
73
74 // options
75 KEYRING,
76 USERID,
77 PASSPHRASE,
78 FILENAME,
79 ARMOUR,
80 HOMEDIR,
81 NUMBITS
82 };
83
84 static struct option long_options[]=
85     {
86     // commands
87     { "list-keys", no_argument, NULL, LIST_KEYS },
88     //\todo    { "list-packets", no_argument, NULL, LIST_PACKETS },
89     { "find-key", no_argument, NULL, FIND_KEY },
90     { "export-key", no_argument, NULL, EXPORT_KEY },
91     { "import-key", no_argument, NULL, IMPORT_KEY },
92     { "generate-key", no_argument, NULL, GENERATE_KEY },
93
94     { "encrypt", no_argument, NULL, ENCRYPT },
95     { "decrypt", no_argument, NULL, DECRYPT },
96     { "sign", no_argument, NULL, SIGN },
97     { "clearsign", no_argument, NULL, CLEARSIGN },
98     { "verify", no_argument, NULL, VERIFY },
99
100     { "list-packets", no_argument, NULL, LIST_PACKETS },
101
102     // options
103     { "keyring", required_argument, NULL, KEYRING },
104     { "userid", required_argument, NULL, USERID },
105     { "passphrase", required_argument, NULL, PASSPHRASE },
106     { "filename", required_argument, NULL, FILENAME },
107     { "homedir", required_argument, NULL, HOMEDIR },
108     { "armour", no_argument, NULL, ARMOUR },
109     { "numbits", required_argument, NULL, NUMBITS },
110     { 0,0,0,0},
111     };
112
113 void print_usage(const char* usage, char* pname)
114     {
115     fprintf(stderr, "\nUsage: ");
116     fprintf(stderr, usage, basename(pname));
117     }
118
119 int main(int argc, char **argv)
120     {
121     int optindex=0;
122     int ch=0;
123     int cmd=0;
124     int armour=0;
125     int fd=0;
126
127     pname=argv[0];
128     const int maxbuf=1024;
129     char opt_keyring[maxbuf+1];
130     char opt_userid[maxbuf+1];
131     char opt_passphrase[maxbuf+1];
132     char opt_filename[maxbuf+1];
133     char opt_homedir[maxbuf+1];
134     //    char opt_numbits[maxbuf+1];
135     int got_homedir=0;
136     int got_keyring=0;
137     int got_userid=0;
138     int got_passphrase=0;
139     int got_filename=0;
140     int got_numbits=0;
141     int numbits=DEFAULT_NUMBITS;
142     char outputfilename[maxbuf+1];
143     ops_keyring_t* myring=NULL;
144     char myring_name[maxbuf+1];
145     ops_keyring_t* pubring=NULL;
146     char pubring_name[maxbuf+1];
147     ops_keyring_t* secring=NULL;
148     char secring_name[maxbuf+1];
149     const ops_keydata_t* keydata=NULL;
150     char *suffix=NULL;
151     char *dir=NULL;
152     char default_homedir[maxbuf+1];
153     //    char full_keyringname[maxbuf+1];
154     ops_boolean_t overwrite=ops_true;
155     ops_keydata_t* mykeydata=NULL;
156     ops_create_info_t * cinfo=NULL;
157     ops_memory_t* mem=NULL;
158     ops_validate_result_t *validate_result=NULL;
159     ops_user_id_t uid;
160     //char line[maxbuf+1];
161     //int i=0;
162     ops_secret_key_t* skey=NULL;
163
164     memset(opt_keyring,'\0',sizeof(opt_keyring));
165     memset(opt_userid,'\0',sizeof(opt_userid));
166     memset(opt_passphrase,'\0',sizeof(opt_passphrase));
167     memset(opt_filename,'\0',sizeof(opt_filename));
168     memset(opt_homedir,'\0',sizeof(opt_homedir));
169
170     memset(outputfilename,'\0',sizeof(outputfilename));
171
172     if (argc<2)
173         {
174         print_usage(usage,pname);
175         exit(-1);
176         }
177    
178     // what does the user want to do?
179
180     while((ch=getopt_long(argc,argv,"",long_options,&optindex   )) != -1)
181         {
182        
183         // read options and commands
184         
185         switch(long_options[optindex].val)
186             {
187             // commands
188
189         case LIST_KEYS:
190             cmd=LIST_KEYS;
191             break;
192            
193             /* \todo
194         case LIST_PACKETS:
195             cmd=LIST_PACKETS;
196             break;
197             */
198
199         case FIND_KEY:
200             cmd=FIND_KEY;
201             break;
202            
203         case EXPORT_KEY:
204             cmd=EXPORT_KEY;
205             break;
206
207         case IMPORT_KEY:
208             cmd=IMPORT_KEY;
209             break;
210
211         case GENERATE_KEY:
212             cmd=GENERATE_KEY;
213             break;
214
215
216         case ENCRYPT:
217             cmd=ENCRYPT;
218             break;
219
220         case DECRYPT:
221             cmd=DECRYPT;
222             break;
223
224         case SIGN:
225             cmd=SIGN;
226             break;
227
228         case CLEARSIGN:
229             cmd=CLEARSIGN;
230             break;
231
232         case VERIFY:
233             cmd=VERIFY;
234             break;
235
236         case LIST_PACKETS:
237             cmd=LIST_PACKETS;
238             break;
239
240             // option
241
242         case KEYRING:
243             assert(optarg);
244             snprintf(opt_keyring,maxbuf,"%s",optarg);
245             got_keyring=1;
246             break;
247            
248         case USERID:
249             assert(optarg);
250             snprintf(opt_userid,maxbuf,"%s",optarg);
251             got_userid=1;
252             break;
253            
254         case PASSPHRASE:
255             assert(optarg);
256             snprintf(opt_passphrase,maxbuf,"%s",optarg);
257             got_passphrase=1;
258             break;
259            
260         case FILENAME:
261             assert(optarg);
262             snprintf(opt_filename,maxbuf,"%s",optarg);
263             got_filename=1;
264             break;
265            
266         case ARMOUR:
267             armour=1;
268             break;
269            
270         case HOMEDIR:
271             assert(optarg);
272             snprintf(opt_homedir, maxbuf, "%s", optarg);
273             got_homedir=1;
274             break;
275
276
277         case NUMBITS:
278             assert(optarg);
279             sscanf(optarg, "%d", &numbits);
280             got_numbits=1;
281             break;
282
283         default:
284             printf("shouldn't be here: option=%d\n", long_options[optindex].val);
285             break;
286             }
287         }
288
289     /*
290      * Read keyrings.
291      * read public and secret from homedir.
292      * (assumed names are pubring.gpg and secring.gpg).
293      * Also read named keyring, if given.
294      *
295      * We will then have variables pubring, secring and myring.
296      */
297
298     if (got_homedir)
299         dir=opt_homedir;
300     else
301         {
302         snprintf(default_homedir,maxbuf,"%s/.gnupg",getenv("HOME"));
303         printf("dir: %s\n", default_homedir);
304         dir=default_homedir;
305         }
306
307     snprintf(pubring_name, maxbuf, "%s/pubring.gpg", dir);
308     pubring=ops_mallocz(sizeof *pubring);
309     if (!ops_keyring_read_from_file(pubring,ops_false,pubring_name))
310         {
311         fprintf(stderr, "Cannot read keyring %s\n", pubring_name);
312         exit(-1);
313         }
314     snprintf(secring_name, maxbuf, "%s/secring.gpg", dir);
315     secring=ops_mallocz(sizeof *secring);
316     if (!ops_keyring_read_from_file(secring,ops_false,secring_name))
317         {
318         fprintf(stderr, "Cannot read keyring %s\n", secring_name);
319         exit(-1);
320         }
321
322     if (got_keyring)
323         {
324         snprintf(myring_name, maxbuf, "%s/%s", opt_homedir, opt_keyring);
325         myring=ops_mallocz(sizeof *myring);
326         if (!ops_keyring_read_from_file(myring,ops_false,myring_name))
327             {
328             fprintf(stderr, "Cannot read keyring %s\n", myring_name);
329             exit(-1);
330             }
331         }
332
333     // now do the required action
334     
335     switch(cmd)
336         {
337     case LIST_KEYS:
338         if (!got_keyring)
339             {
340             print_usage(usage_list_keys,pname);
341             exit(-1);
342             }
343        
344         ops_keyring_list(myring);
345         //        ops_keyring_free(&kering);
346         break;
347        
348         //case LIST_PACKETS:
349
350     case FIND_KEY:
351         if (!got_userid)
352             {
353             print_usage(usage_find_key,pname);
354             exit(-1);
355             }
356        
357         //        fprintf(stderr,"userid: %s\n", opt_userid);
358         //keydata=ops_keydata_new();
359         if (!got_keyring)
360             keydata=ops_keyring_find_key_by_userid(pubring, opt_userid);
361         else
362             keydata=ops_keyring_find_key_by_userid(myring, opt_userid);
363         //        ops_keyring_free(&keyring);
364         if (keydata)
365             {
366             exit (1);
367             }
368         else
369             {
370             exit(0);
371             }
372         break;
373
374     case EXPORT_KEY:
375         if (!got_keyring || !got_userid)
376             {
377             print_usage(usage_export_key,pname);
378             exit(-1);
379             }
380        
381         if (got_keyring)
382             keydata=ops_keyring_find_key_by_userid(myring, opt_userid);
383         else
384             keydata=ops_keyring_find_key_by_userid(pubring, opt_userid);
385         if (!keydata)
386             {
387             fprintf(stderr,"Cannot find key in keyring\n");
388             exit(-1);
389             }
390
391         ops_setup_memory_write(&cinfo, &mem, 128);
392         if (keydata->type==OPS_PTAG_CT_PUBLIC_KEY)
393             ops_write_transferable_public_key(keydata, ops_true, cinfo);
394         else
395             ops_write_transferable_secret_key(keydata, (unsigned char *)opt_passphrase, strlen(opt_passphrase), ops_true, cinfo);
396         fprintf(stdout,"%s",(char *)ops_memory_get_data(mem));
397         ops_teardown_memory_write(cinfo,mem);
398
399         break;
400
401     case IMPORT_KEY:
402         if (!got_filename || !got_keyring)
403             {
404             print_usage(usage_import_key, pname);
405             exit(-1);
406             }
407         fprintf(stderr,"before:\n");
408         ops_keyring_list(myring);
409
410         // read new key
411         if (!ops_keyring_read_from_file(myring, armour, opt_filename))
412             {
413             fprintf(stderr,"Cannot import key from file %s\n", opt_filename);
414             exit(-1);
415             }
416
417         fprintf(stderr,"after:\n");
418         ops_keyring_list(myring);
419        
420         break;
421
422     case GENERATE_KEY:
423         if (!got_userid)
424             {
425             print_usage(usage_generate_key,pname);
426             exit(-1);
427             }
428        
429         uid.user_id=(unsigned char *)opt_userid;
430         mykeydata=ops_rsa_create_selfsigned_keypair(numbits,65537,&uid);
431         if (!mykeydata)
432             {
433             fprintf(stderr,"Cannot generate key\n");
434             exit(-1);
435             }
436
437         // write public key
438         // append to keyrings
439         fd=ops_setup_file_append(&cinfo, pubring_name);
440         ops_write_transferable_public_key(mykeydata, ops_false, cinfo);
441         ops_teardown_file_write(cinfo,fd);
442
443         ops_keyring_free(pubring);
444         if (!ops_keyring_read_from_file(pubring,ops_false,pubring_name))
445             {
446             fprintf(stderr, "Cannot re-read keyring %s\n", pubring_name);
447             exit(-1);
448             }
449
450         fd=ops_setup_file_append(&cinfo, secring_name);
451         ops_write_transferable_secret_key(mykeydata, NULL, 0, ops_false, cinfo);
452         ops_teardown_file_write(cinfo,fd);
453         ops_keyring_free(secring);
454         if (!ops_keyring_read_from_file(secring,ops_false,secring_name))
455             {
456             fprintf(stderr, "Cannot re-read keyring %s\n", secring_name);
457             exit(-1);
458             }
459
460         ops_keydata_free(mykeydata);
461         break;
462
463     case ENCRYPT:
464         if (!got_filename)
465             {
466             print_usage(usage_encrypt,pname);
467             exit(-1);
468             }
469
470         if (!got_userid)
471             {
472             print_usage(usage_encrypt,pname);
473             exit(-1);
474             }
475
476         suffix=armour ? ".asc" : ".gpg";
477         keydata=ops_keyring_find_key_by_userid(pubring,opt_userid);
478         if (!keydata)
479             {
480             fprintf(stderr,"Userid '%s' not found in keyring\n",
481                     opt_userid);
482             exit(-1);
483             }
484
485         // outputfilename
486         snprintf(outputfilename,maxbuf,"%s%s", opt_filename,suffix);
487
488         overwrite=ops_true;
489         ops_encrypt_file(opt_filename, outputfilename, keydata, armour,overwrite);
490         break;
491
492     case DECRYPT:
493         if (!got_filename)
494             {
495             print_usage(usage_decrypt,pname);
496             exit(-1);
497             }
498
499         overwrite=ops_true;
500         ops_decrypt_file(opt_filename, NULL, secring, armour,overwrite,callback_cmd_get_passphrase_from_cmdline);
501         break;
502
503     case SIGN:
504         if (!got_filename || !got_userid)
505             {
506             print_usage(usage_sign, pname);
507             exit(-1);
508             }
509
510         // get key with which to sign
511         keydata=ops_keyring_find_key_by_userid(secring,opt_userid);
512         if (!keydata)
513             {
514             fprintf(stderr,"Userid '%s' not found in keyring\n",
515                     opt_userid);
516             exit(-1);
517             }
518         // now decrypt key
519         // \todo
520         //fprintf(stdout, "Enter passphrase: ");
521         skey=ops_decrypt_secret_key_from_data(keydata,opt_passphrase);
522         assert(skey);
523
524         // sign file
525         overwrite=ops_true;
526         ops_sign_file(opt_filename, NULL, skey, armour, overwrite);
527         break;
528
529     case CLEARSIGN:
530         if (!got_filename || !got_userid)
531             {
532             print_usage(usage_clearsign, pname);
533             exit(-1);
534             }
535
536         // get key with which to sign
537         keydata=ops_keyring_find_key_by_userid(secring,opt_userid);
538         if (!keydata)
539             {
540             fprintf(stderr,"Userid '%s' not found in keyring\n",
541                     opt_userid);
542             exit(-1);
543             }
544         skey=ops_decrypt_secret_key_from_data(keydata,opt_passphrase);
545         assert(skey);
546
547         // sign file
548         overwrite=ops_true;
549         ops_sign_file_as_cleartext(opt_filename, skey, overwrite);
550         break;
551
552     case VERIFY:
553         if (!got_filename)
554             {
555             print_usage(usage_verify, pname);
556             exit(-1);
557             }
558
559         validate_result=ops_mallocz(sizeof (ops_validate_result_t));
560
561         if (ops_validate_file(validate_result, opt_filename, armour, pubring)==ops_true)
562             {
563             fprintf(stdout, "Verified OK\n");
564             }
565         else
566             {
567             fprintf(stdout, "Not verified OK: %d invalid signatures, %d unknown signatures\n", validate_result->invalid_count, validate_result->unknown_signer_count);
568             }
569         ops_validate_result_free(validate_result);
570         break;
571
572     case LIST_PACKETS:
573         if (!got_filename)
574             {
575             print_usage(usage_list_packets, pname);
576             exit(-1);
577             }
578         ops_list_packets(opt_filename, armour, pubring, callback_cmd_get_passphrase_from_cmdline);
579         break;
580
581     default:
582         print_usage(usage,pname);
583         exit(-1);
584         ;
585         }
586    
587     if (pubring)
588         {
589         ops_keyring_free(pubring);
590         pubring=NULL;
591         }
592     if (secring)
593         {
594         ops_keyring_free(secring);
595         secring=NULL;
596         }
597     if (myring)
598         {
599         ops_keyring_free(myring);
600         myring=NULL;
601         }
602
603     exit(0);
604     }
Note: See TracBrowser for help on using the browser.