1 |
/* sign-encrypt.c - Sign & Encrypt functions |
2 |
* Copyright (C) 2001-2004 Timo Schulz |
3 |
* |
4 |
* This file is part of MyGPGME. |
5 |
* |
6 |
* MyGPGME is free software; you can redistribute it and/or modify |
7 |
* it under the terms of the GNU General Public License as published by |
8 |
* the Free Software Foundation; either version 2 of the License, or |
9 |
* (at your option) any later version. |
10 |
* |
11 |
* MyGPGME is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
19 |
*/ |
20 |
|
21 |
#include <string.h> |
22 |
#include <stdio.h> |
23 |
#include <assert.h> |
24 |
|
25 |
#include <windows.h> |
26 |
|
27 |
#include "util.h" |
28 |
#include "context.h" |
29 |
#include "ops.h" |
30 |
|
31 |
struct sign_encrypt_result_s { |
32 |
void * last_pw_handle; |
33 |
char * userid_hint; |
34 |
char * passphrase_info; |
35 |
char cardno[32+1]; |
36 |
int no_passphrase; |
37 |
int okay; |
38 |
int bad_passphrase; |
39 |
int idea_cipher; |
40 |
}; |
41 |
|
42 |
|
43 |
void |
44 |
_gpgme_release_sign_encrypt_result( _sign_encrypt_result_t res ) |
45 |
{ |
46 |
if( res ) { |
47 |
safe_free( res->userid_hint ); |
48 |
safe_free( res->passphrase_info ); |
49 |
safe_free( res ); |
50 |
} |
51 |
} |
52 |
|
53 |
|
54 |
static void |
55 |
sign_encrypt_status_handler( gpgme_ctx_t ctx, gpg_status_code_t code, char *args ) |
56 |
{ |
57 |
char * p; |
58 |
int i=0; |
59 |
|
60 |
if( ctx->out_of_core ) |
61 |
return; |
62 |
|
63 |
if( ctx->result_type == RESULT_TYPE_NONE ) { |
64 |
assert( !ctx->result.sign_enc ); |
65 |
ctx->result.sign_enc = calloc ( 1, sizeof * ctx->result.sign_enc ); |
66 |
if( !ctx->result.sign_enc ) { |
67 |
ctx->out_of_core = 1; |
68 |
return; |
69 |
} |
70 |
ctx->result_type = RESULT_TYPE_SIGN_ENCRYPT; |
71 |
} |
72 |
assert( ctx->result_type == RESULT_TYPE_SIGN_ENCRYPT ); |
73 |
|
74 |
switch( code ) { |
75 |
case STATUS_EOF: |
76 |
break; |
77 |
|
78 |
case STATUS_USERID_HINT: |
79 |
safe_free( ctx->result.sign_enc->userid_hint ); |
80 |
ctx->result.sign_enc->userid_hint = strdup( args ); |
81 |
if( !ctx->result.sign_enc->userid_hint ) { |
82 |
ctx->out_of_core = 1; |
83 |
return; |
84 |
} |
85 |
break; |
86 |
|
87 |
case STATUS_BAD_PASSPHRASE: |
88 |
DEBUG0( "Bad passphrase - once again please\n" ); |
89 |
ctx->result.sign_enc->bad_passphrase++; |
90 |
break; |
91 |
|
92 |
case STATUS_GOOD_PASSPHRASE: |
93 |
ctx->result.sign_enc->bad_passphrase = 0; |
94 |
break; |
95 |
|
96 |
case STATUS_RSA_OR_IDEA: |
97 |
ctx->result.sign_enc->idea_cipher = 1; |
98 |
break; |
99 |
|
100 |
case STATUS_NEED_PASSPHRASE: |
101 |
case STATUS_NEED_PASSPHRASE_SYM: |
102 |
safe_free( ctx->result.sign_enc->passphrase_info ); |
103 |
ctx->result.sign_enc->passphrase_info = strdup( args ); |
104 |
if( !ctx->result.sign_enc->passphrase_info ) { |
105 |
ctx->out_of_core = 1; |
106 |
return; |
107 |
} |
108 |
break; |
109 |
|
110 |
case STATUS_MISSING_PASSPHRASE: |
111 |
DEBUG0( "missing passphrase - stop\n" ); |
112 |
ctx->result.sign_enc->no_passphrase = 1; |
113 |
break; |
114 |
|
115 |
case STATUS_SIG_CREATED: |
116 |
ctx->result.sign_enc->okay = 1; |
117 |
break; |
118 |
|
119 |
case STATUS_PROGRESS: |
120 |
if( ctx->cb.progress ) |
121 |
_gpgme_progress_handler( ctx, args ); |
122 |
break; |
123 |
|
124 |
case STATUS_CARDCTRL: |
125 |
if( args[i++] != '3' ) |
126 |
break; |
127 |
i++; |
128 |
p = ctx->result.sign_enc->cardno; |
129 |
for( ; i-1 < DIM(ctx->result.sign_enc->cardno) && args[i]; i++ ) |
130 |
*p++ = args[i]; |
131 |
*p = 0; |
132 |
break; |
133 |
|
134 |
default: |
135 |
break; |
136 |
} |
137 |
} |
138 |
|
139 |
|
140 |
static const char* |
141 |
command_handler( void *opqaue, gpg_status_code_t code, const char *key ) |
142 |
{ |
143 |
gpgme_ctx_t c = opqaue; |
144 |
|
145 |
if( c->result_type == RESULT_TYPE_NONE ) { |
146 |
assert ( !c->result.sign_enc ); |
147 |
c->result.sign_enc = calloc ( 1, sizeof *c->result.sign_enc ); |
148 |
if( !c->result.sign_enc ) { |
149 |
c->out_of_core = 1; |
150 |
return NULL; |
151 |
} |
152 |
c->result_type = RESULT_TYPE_SIGN_ENCRYPT; |
153 |
} |
154 |
|
155 |
if( !key || !c->cb.passphrase ) |
156 |
return NULL; |
157 |
|
158 |
if( code == STATUS_GET_HIDDEN |
159 |
&& (!strcmp( key, "passphrase.enter" ) |
160 |
|| !strcmp( key, "passphrase.pin.ask" )) ) { |
161 |
const char * userid_hint = c->result.sign_enc->userid_hint; |
162 |
const char * passphrase_info = c->result.sign_enc->passphrase_info; |
163 |
const char * cardno = c->result.sign_enc->cardno; |
164 |
int bad_passphrase = c->result.sign_enc->bad_passphrase; |
165 |
int is_card=0; |
166 |
char * buf; |
167 |
const char * s; |
168 |
|
169 |
c->result.sign_enc->bad_passphrase = 0; |
170 |
is_card = !strcmp( key, "passphrase.pin.ask" ); |
171 |
if( !userid_hint ) |
172 |
userid_hint = "[User ID hint missing]"; |
173 |
if( !passphrase_info ) |
174 |
passphrase_info = "[passphrase info missing]"; |
175 |
buf = malloc( 20 + strlen( userid_hint ) |
176 |
+ strlen( passphrase_info ) + 3 ); |
177 |
if( !buf ) { |
178 |
c->out_of_core = 1; |
179 |
return NULL; |
180 |
} |
181 |
sprintf( buf, "%s\n%s\n%s", |
182 |
bad_passphrase? "TRY_AGAIN":"ENTER_PASSPHRASE", |
183 |
userid_hint, passphrase_info ); |
184 |
|
185 |
s = c->cb.passphrase( c->cb.passphrase_value, |
186 |
is_card? cardno : buf, |
187 |
&c->result.sign_enc->last_pw_handle ); |
188 |
safe_free( buf ); |
189 |
return s; |
190 |
} |
191 |
|
192 |
return NULL; |
193 |
} |
194 |
|
195 |
|
196 |
gpgme_error_t |
197 |
gpgme_op_sign_encrypt_start( gpgme_ctx_t ctx, gpgme_recipients_t recp, |
198 |
gpgme_data_t plain, gpgme_data_t ciph ) |
199 |
{ |
200 |
gpgme_key_t key; |
201 |
int rc = 0; |
202 |
int i; |
203 |
|
204 |
fail_on_pending_request( ctx ); |
205 |
ctx->pending = 1; |
206 |
|
207 |
if( !gpgme_recipients_count( recp ) ) { |
208 |
rc = mk_error( No_Recipients ); |
209 |
goto leave; |
210 |
} |
211 |
|
212 |
_gpgme_gpg_release( &ctx->gpg ); |
213 |
rc = _gpgme_gpg_new( &ctx->gpg ); |
214 |
if( rc ) |
215 |
goto leave; |
216 |
|
217 |
if( ctx->use_logging ) |
218 |
_gpgme_gpg_set_logging_handler( ctx->gpg, ctx ); |
219 |
_gpgme_gpg_set_status_handler( ctx->gpg, sign_encrypt_status_handler, ctx ); |
220 |
if ( ctx->cb.passphrase ) { |
221 |
rc = _gpgme_gpg_set_command_handler( ctx->gpg, command_handler, ctx ); |
222 |
if( rc ) |
223 |
goto leave; |
224 |
} |
225 |
else if( ctx->passphrase_value ) { |
226 |
rc = _gpgme_add_passphrase( ctx ); |
227 |
if( rc ) |
228 |
goto leave; |
229 |
} |
230 |
|
231 |
_gpgme_gpg_add_arg( ctx->gpg, "--encrypt" ); |
232 |
_gpgme_gpg_add_arg( ctx->gpg, "--sign" ); |
233 |
if( ctx->use_armor ) |
234 |
_gpgme_gpg_add_arg( ctx->gpg, "--armor" ); |
235 |
if( ctx->cb.progress ) |
236 |
_gpgme_gpg_add_arg (ctx->gpg, "--enable-progress-filter"); |
237 |
if( ctx->force_trust || _gpgme_recipients_all_valid( recp ) ) |
238 |
_gpgme_gpg_add_arg (ctx->gpg, "--always-trust"); |
239 |
|
240 |
for( i = 0; (key = gpgme_signers_enum (ctx, i)); i++ ) { |
241 |
const char * s; |
242 |
s = gpgme_key_get_string_attr( key, GPGME_ATTR_KEYID, NULL, 0 ); |
243 |
if (s) { |
244 |
_gpgme_gpg_add_arg (ctx->gpg, "-u"); |
245 |
_gpgme_gpg_add_arg_concat (ctx->gpg, s, "!"); |
246 |
_gpgme_gpg_add_arg (ctx->gpg, "--encrypt-to"); |
247 |
_gpgme_gpg_add_arg (ctx->gpg, s); |
248 |
} |
249 |
gpgme_key_unref (key); |
250 |
} |
251 |
|
252 |
_gpgme_append_gpg_args_from_recipients( recp, ctx->gpg ); |
253 |
if( gpgme_data_get_type( plain ) == GPGME_DATA_TYPE_NONE ) { |
254 |
rc = mk_error( No_Data ); |
255 |
goto leave; |
256 |
} |
257 |
|
258 |
_gpgme_data_set_mode( plain, GPGME_DATA_MODE_OUT ); |
259 |
|
260 |
if( !ciph || gpgme_data_get_type(ciph) != GPGME_DATA_TYPE_NONE ) { |
261 |
rc = mk_error( No_Data ); |
262 |
goto leave; |
263 |
} |
264 |
|
265 |
_gpgme_data_set_mode( ciph, GPGME_DATA_MODE_IN ); |
266 |
|
267 |
if( ctx->use_tmpfiles ) { |
268 |
_gpgme_gpg_add_arg ( ctx->gpg, "--output" ); |
269 |
_gpgme_gpg_add_arg ( ctx->gpg, _gpgme_get_tmpfile(0) ); |
270 |
_gpgme_data_write_to_tmpfile( plain ); |
271 |
_gpgme_gpg_add_arg ( ctx->gpg, _gpgme_get_tmpfile(1) ); |
272 |
} |
273 |
else { |
274 |
_gpgme_gpg_add_arg ( ctx->gpg, "--output" ); |
275 |
_gpgme_gpg_add_arg ( ctx->gpg, "-" ); |
276 |
_gpgme_gpg_add_data ( ctx->gpg, ciph, 1 ); |
277 |
_gpgme_gpg_add_arg ( ctx->gpg, "--" ); |
278 |
_gpgme_gpg_add_data ( ctx->gpg, plain, 0 ); |
279 |
} |
280 |
|
281 |
rc = _gpgme_gpg_spawn( ctx->gpg, ctx ); |
282 |
|
283 |
leave: |
284 |
if ( rc ) { |
285 |
ctx->pending = 0; |
286 |
_gpgme_gpg_release( &ctx->gpg ); |
287 |
} |
288 |
return rc; |
289 |
|
290 |
} /* gpgme_op_sign_encrypt_start */ |
291 |
|
292 |
|
293 |
gpgme_error_t |
294 |
gpgme_op_sign_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t rset, |
295 |
gpgme_data_t in, gpgme_data_t out ) |
296 |
{ |
297 |
gpgme_error_t rc; |
298 |
|
299 |
rc = gpgme_op_sign_encrypt_start( ctx, rset, in, out ); |
300 |
if( !rc ) { |
301 |
gpgme_wait( ctx, 1 ); |
302 |
ctx->pending = 0; |
303 |
if( ctx->use_tmpfiles ) { |
304 |
_gpgme_data_read_from_tmpfile( out ); |
305 |
_gpgme_del_tmpfiles( ctx->wipe_fnc ); |
306 |
} |
307 |
if( ctx->result_type != RESULT_TYPE_SIGN_ENCRYPT ) |
308 |
rc = mk_error( General_Error ); |
309 |
else if ( ctx->out_of_core ) |
310 |
rc = mk_error( Out_Of_Core ); |
311 |
else { |
312 |
assert( ctx->result.sign_enc ); |
313 |
if( ctx->result.sign_enc->no_passphrase ) |
314 |
rc = mk_error( No_Passphrase ); |
315 |
else if( ctx->result.sign_enc->bad_passphrase ) |
316 |
rc = mk_error( Bad_Passphrase ); |
317 |
else if( ctx->result.sign_enc->idea_cipher ) |
318 |
rc = mk_error( Cipher_IDEA ); |
319 |
else if( gpgme_get_process_rc( ctx ) ) |
320 |
rc = mk_error( Internal_GPG_Problem ); |
321 |
else if( !ctx->result.sign_enc->okay ) |
322 |
rc = mk_error( Signing_Failed ); |
323 |
} |
324 |
} |
325 |
return rc; |
326 |
} /* gpgme_op_sign_encrypt */ |
327 |
|
328 |
|
329 |
gpgme_error_t |
330 |
gpgme_op_clip_sign_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t rset, |
331 |
const char * keyid, int opts ) |
332 |
{ |
333 |
gpgme_error_t err; |
334 |
gpgme_data_t plain = NULL; |
335 |
gpgme_data_t ciph = NULL; |
336 |
gpgme_key_t key = NULL; |
337 |
|
338 |
if( !keyid ) |
339 |
return mk_error( General_Error ); |
340 |
|
341 |
if( opts & GPGME_CTRL_FORCETRUST ) |
342 |
gpgme_control( ctx, GPGME_CTRL_FORCETRUST, 1 ); |
343 |
if( opts & GPGME_CTRL_TMPFILES ) |
344 |
gpgme_control( ctx, GPGME_CTRL_TMPFILES, 1 ); |
345 |
gpgme_control( ctx, GPGME_CTRL_ARMOR, 1 ); |
346 |
|
347 |
key = _gpgme_key_new_fromkeyid( keyid ); |
348 |
if( !key ) |
349 |
return mk_error( General_Error ); |
350 |
|
351 |
err = gpgme_data_new_from_clipboard (&plain); |
352 |
if( !err ) |
353 |
err = gpgme_data_new( &ciph ); |
354 |
if( !err ) |
355 |
err = gpgme_signers_add( ctx, key ); |
356 |
if( !err ) |
357 |
err = gpgme_op_sign_encrypt( ctx, rset, plain, ciph ); |
358 |
if( !err ) { |
359 |
gpgme_data_change_version( &ciph ); |
360 |
gpgme_data_release_and_set_clipboard( ciph ); |
361 |
} |
362 |
gpgme_data_release( plain ); |
363 |
gpgme_key_release( key ); |
364 |
|
365 |
return err; |
366 |
} /* gpgme_op_clip_sign_encrypt */ |