root/openpgpsdk/trunk/src/keyring.c

Revision 353 (checked in by ben, 7 years ago)

Allow stdin to be redirected.

Line 
1 /** \file
2  */
3
4 #include <openpgpsdk/keyring.h>
5 #include <openpgpsdk/packet-parse.h>
6 #include <openpgpsdk/util.h>
7 #include <openpgpsdk/accumulate.h>
8 #include <openpgpsdk/validate.h>
9 #include "keyring_local.h"
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <assert.h>
15 #include <termios.h>
16
17 ops_key_data_t *
18 ops_keyring_find_key_by_id(const ops_keyring_t *keyring,
19                            const unsigned char keyid[OPS_KEY_ID_SIZE])
20     {
21     int n;
22
23     for(n=0 ; n < keyring->nkeys ; ++n)
24         if(!memcmp(keyring->keys[n].keyid,keyid,OPS_KEY_ID_SIZE))
25             return &keyring->keys[n];
26
27     return NULL;
28     }
29
30 void ops_key_data_free(ops_key_data_t *key)
31     {
32     unsigned n;
33
34     for(n=0 ; n < key->nuids ; ++n)
35         ops_user_id_free(&key->uids[n]);
36     free(key->uids);
37     key->uids=NULL;
38
39     for(n=0 ; n < key->npackets ; ++n)
40         ops_packet_free(&key->packets[n]);
41     free(key->packets);
42     key->packets=NULL;
43
44     if(key->type == OPS_PTAG_CT_PUBLIC_KEY)
45         ops_public_key_free(&key->key.pkey);
46     else
47         ops_secret_key_free(&key->key.skey);
48     }
49
50 /**
51  * \ingroup Memory
52  *
53  * ops_keyring_free() frees the memory used in one ops_keyring_t structure
54  * \param keyring Keyring to be freed.
55  */
56 void ops_keyring_free(ops_keyring_t *keyring)
57     {
58     int n;
59
60     for(n=0 ; n < keyring->nkeys ; ++n)
61         ops_key_data_free(&keyring->keys[n]);
62     free(keyring->keys);
63     keyring->keys=NULL;
64     }
65
66 const ops_public_key_t *
67 ops_get_public_key_from_data(const ops_key_data_t *data)
68     {
69     if(data->type == OPS_PTAG_CT_PUBLIC_KEY)
70         return &data->key.pkey;
71     return &data->key.skey.public_key;
72     }
73
74 ops_boolean_t ops_key_is_secret(const ops_key_data_t *data)
75     { return data->type != OPS_PTAG_CT_PUBLIC_KEY; }
76
77 const ops_secret_key_t *
78 ops_get_secret_key_from_data(const ops_key_data_t *data)
79     {
80     if(data->type != OPS_PTAG_CT_SECRET_KEY)
81         return NULL;
82     return &data->key.skey;
83     }
84
85 static ops_parse_cb_return_t
86 cb_keyring_read(const ops_parser_content_t *content_,
87                 ops_parse_cb_info_t *cbinfo)
88     {
89     //    const ops_parser_content_union_t *content=&content_->content;
90     //    char buffer[1024];
91     //    size_t n;
92
93     OPS_USED(cbinfo);
94
95     switch(content_->tag)
96         {
97     case OPS_PARSER_PTAG:
98     case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY: // we get these because we didn't prompt
99     case OPS_PTAG_CT_SIGNATURE_HEADER:
100     case OPS_PTAG_CT_SIGNATURE_FOOTER:
101     case OPS_PTAG_CT_SIGNATURE:
102     case OPS_PTAG_CT_TRUST:
103     case OPS_PARSER_ERRCODE:
104         break;
105
106     case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
107         // we don't want to prompt when reading the keyring
108         break;
109
110     default:
111         fprintf(stderr,"Unexpected packet tag=%d (0x%x)\n",content_->tag,
112                 content_->tag);
113         assert(0);
114         exit(1);
115         }
116
117     return OPS_RELEASE_MEMORY;
118     }
119
120 /* Read a keyring from a file (either public or secret) */
121 void ops_keyring_read(ops_keyring_t *keyring,const char *file)
122     {
123     ops_parse_info_t *pinfo;
124     int fd;
125
126     memset(keyring,'\0',sizeof *keyring);
127
128     pinfo=ops_parse_info_new();
129
130     fd=open(file,O_RDONLY);
131     if(fd < 0)
132         {
133         perror(file);
134         exit(1);
135         }
136
137     ops_reader_set_fd(pinfo,fd);
138
139     ops_parse_cb_set(pinfo,cb_keyring_read,NULL);
140
141     ops_parse_and_accumulate(keyring,pinfo);
142
143     close(fd);
144
145     ops_parse_info_delete(pinfo);
146     }
147
148 static void echo_off()
149     {
150     struct termios term;
151     int r;
152
153     r=tcgetattr(0,&term);
154     if(r < 0 && errno == ENOTTY)
155         return;
156     assert(r >= 0);
157
158     term.c_lflag &= ~ECHO;
159
160     r=tcsetattr(0,TCSANOW,&term);
161     assert(r >= 0);
162     }
163        
164 static void echo_on()
165     {
166     struct termios term;
167     int r;
168
169     r=tcgetattr(0,&term);
170     if(r < 0 && errno == ENOTTY)
171         return;
172     assert(r >= 0);
173
174     term.c_lflag |= ECHO;
175
176     r=tcsetattr(0,TCSANOW,&term);
177     assert(r >= 0);
178     }
179
180 char *ops_get_passphrase(void)
181     {
182     char buffer[1024];
183     char *passphrase;
184     size_t n;
185
186     printf("Passphrase: ");
187
188     echo_off();
189     fgets(buffer,sizeof buffer,stdin);
190     echo_on();
191
192     putchar('\n');
193
194     n=strlen(buffer);
195     if(n && buffer[n-1] == '\n')
196         buffer[--n]='\0';
197     passphrase=malloc(n+1);
198     strcpy(passphrase,buffer);
199
200     return passphrase;
201     }
202
203 typedef struct
204     {
205     ops_key_data_t *key;
206     char *pphrase;
207     ops_secret_key_t *skey;
208     } decrypt_arg_t;
209
210 static ops_parse_cb_return_t decrypt_cb(const ops_parser_content_t *content_,
211                                         ops_parse_cb_info_t *cbinfo)
212     {
213     const ops_parser_content_union_t *content=&content_->content;
214     decrypt_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
215
216     OPS_USED(cbinfo);
217
218     switch(content_->tag)
219         {
220     case OPS_PARSER_PTAG:
221     case OPS_PTAG_CT_USER_ID:
222     case OPS_PTAG_CT_SIGNATURE:
223     case OPS_PTAG_CT_TRUST:
224         break;
225
226     case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
227         *content->secret_key_passphrase.passphrase=arg->pphrase;
228         return OPS_KEEP_MEMORY;
229
230     case OPS_PARSER_ERRCODE:
231         switch(content->errcode.errcode)
232             {
233         case OPS_E_P_MPI_FORMAT_ERROR:
234             /* Generally this means a bad passphrase */
235             fprintf(stderr,"Bad passphrase!\n");
236             goto done;
237
238         case OPS_E_P_PACKET_CONSUMED:
239             /* And this is because of an error we've accepted */
240             goto done;
241
242         default:
243             fprintf(stderr,"parse error: %s\n",
244                     ops_errcode(content->errcode.errcode));
245             assert(0);
246             break;
247             }
248
249         break;
250
251     case OPS_PARSER_ERROR:
252         printf("parse error: %s\n",content->error.error);
253         assert(0);
254         break;
255
256     default:
257         fprintf(stderr,"Unexpected tag %d (0x%x)\n",content_->tag,
258                 content_->tag);
259         assert(0);
260         }
261
262  done:
263     return OPS_RELEASE_MEMORY;
264     }
265
266 ops_secret_key_t *ops_decrypt_secret_key_from_data(ops_key_data_t *key,
267                                                    const char *pphrase)
268     {
269     ops_parse_info_t *pinfo;
270     decrypt_arg_t arg;
271
272     memset(&arg,'\0',sizeof arg);
273     arg.key=key;
274     arg.pphrase=strdup(pphrase);
275
276     pinfo=ops_parse_info_new();
277
278     ops_key_data_reader_set(pinfo,key);
279     ops_parse_cb_set(pinfo,decrypt_cb,&arg);
280
281     ops_parse(pinfo);
282
283     return arg.skey;
284     }
285
Note: See TracBrowser for help on using the browser.