Fix copyright year.
[gpgme.git] / gpgme / sign.c
1 /* sign.c -  signing functions
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
4
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "util.h"
30 #include "context.h"
31 #include "ops.h"
32
33 #define SKIP_TOKEN_OR_RETURN(a) do { \
34     while (*(a) && *(a) != ' ') (a)++; \
35     while (*(a) == ' ') (a)++; \
36     if (!*(a)) \
37         return; /* oops */ \
38 } while (0)
39
40 struct sign_result_s
41 {
42   int okay;
43   GpgmeData xmlinfo;
44 };
45
46 void
47 _gpgme_release_sign_result (SignResult result)
48 {
49   if (!result)
50     return;
51   gpgme_data_release (result->xmlinfo);
52   free (result);
53 }
54
55 /* Parse the args and save the information 
56    <type> <pubkey algo> <hash algo> <class> <timestamp> <key fpr>
57    in an XML structure.  With args of NULL the xml structure is
58    closed.  */
59 static void
60 append_xml_siginfo (GpgmeData *rdh, char *args)
61 {
62   GpgmeData dh;
63   char helpbuf[100];
64   int i;
65   char *s;
66   unsigned long ul;
67
68   if (!*rdh)
69     {
70       if (gpgme_data_new (rdh))
71         {
72           return; /* fixme: We are ignoring out-of-core */
73         }
74       dh = *rdh;
75       _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
76     }
77   else
78     {
79       dh = *rdh;
80       _gpgme_data_append_string (dh, "  </signature>\n");
81     }
82
83   if (!args)
84     {
85       /* Just close the XML containter.  */
86       _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
87       return;
88     }
89
90   _gpgme_data_append_string (dh, "  <signature>\n");
91     
92   _gpgme_data_append_string (dh,
93                              *args == 'D' ? "    <detached/>\n" :
94                              *args == 'C' ? "    <cleartext/>\n" :
95                              *args == 'S' ? "    <standard/>\n" : "");
96   SKIP_TOKEN_OR_RETURN (args);
97
98   sprintf (helpbuf, "    <algo>%d</algo>\n", atoi (args));
99   _gpgme_data_append_string (dh, helpbuf);
100   SKIP_TOKEN_OR_RETURN (args);
101
102   i = atoi (args);
103   sprintf (helpbuf, "    <hashalgo>%d</hashalgo>\n", atoi (args));
104   _gpgme_data_append_string (dh, helpbuf);
105   switch (i)
106     {
107     case  1: s = "pgp-md5"; break;
108     case  2: s = "pgp-sha1"; break;
109     case  3: s = "pgp-ripemd160"; break;
110     case  5: s = "pgp-md2"; break;
111     case  6: s = "pgp-tiger192"; break;
112     case  7: s = "pgp-haval-5-160"; break;
113     case  8: s = "pgp-sha256"; break;
114     case  9: s = "pgp-sha384"; break;
115     case 10: s = "pgp-sha512"; break;
116     default: s = "pgp-unknown"; break;
117     }
118   sprintf (helpbuf, "    <micalg>%s</micalg>\n", s);
119   _gpgme_data_append_string (dh,helpbuf);
120   SKIP_TOKEN_OR_RETURN (args);
121     
122   sprintf (helpbuf, "    <sigclass>%.2s</sigclass>\n", args);
123   _gpgme_data_append_string (dh, helpbuf);
124   SKIP_TOKEN_OR_RETURN (args);
125
126   ul = strtoul (args, NULL, 10);
127   sprintf (helpbuf, "    <created>%lu</created>\n", ul);
128   _gpgme_data_append_string (dh, helpbuf);
129   SKIP_TOKEN_OR_RETURN (args);
130
131   /* Count the length of the finperprint.  */
132   for (i = 0; args[i] && args[i] != ' '; i++)
133     ;
134   _gpgme_data_append_string (dh, "    <fpr>");
135   _gpgme_data_append (dh, args, i);
136   _gpgme_data_append_string (dh, "</fpr>\n");
137 }
138
139 GpgmeError
140 _gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
141 {
142   GpgmeError err = _gpgme_passphrase_status_handler (ctx, code, args);
143   if (err)
144     return err;
145
146   test_and_allocate_result (ctx, sign);
147
148   switch (code)
149     {
150     case GPGME_STATUS_EOF:
151       if (ctx->result.sign->okay)
152         {
153           append_xml_siginfo (&ctx->result.sign->xmlinfo, NULL);
154           _gpgme_set_op_info (ctx, ctx->result.sign->xmlinfo);
155           ctx->result.sign->xmlinfo = NULL;
156         }
157       if (!ctx->result.sign->okay)
158         return GPGME_No_Data; /* Hmmm: choose a better error? */
159       break;
160
161     case GPGME_STATUS_SIG_CREATED: 
162       /* FIXME: We have no error return for multiple signatures.  */
163       append_xml_siginfo (&ctx->result.sign->xmlinfo, args);
164       ctx->result.sign->okay = 1;
165       break;
166
167     default:
168       break;
169     }
170   return 0;
171 }
172
173 static GpgmeError
174 _gpgme_op_sign_start (GpgmeCtx ctx, int synchronous,
175                       GpgmeData in, GpgmeData out,
176                       GpgmeSigMode mode)
177 {
178   GpgmeError err = 0;
179
180   if (mode != GPGME_SIG_MODE_NORMAL
181       && mode != GPGME_SIG_MODE_DETACH
182       && mode != GPGME_SIG_MODE_CLEAR)
183     return GPGME_Invalid_Value;
184
185   err = _gpgme_op_reset (ctx, synchronous);
186   if (err)
187     goto leave;
188
189   /* Check the supplied data.  */
190   if (!in)
191     {
192       err = GPGME_No_Data;
193       goto leave;
194     }
195   if (!out)
196     {
197       err = GPGME_Invalid_Value;
198       goto leave;
199     }
200
201   err = _gpgme_passphrase_start (ctx);
202   if (err)
203     goto leave;
204
205   _gpgme_engine_set_status_handler (ctx->engine, _gpgme_sign_status_handler,
206                                     ctx);
207   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
208
209   err = _gpgme_engine_op_sign (ctx->engine, in, out, mode, ctx->use_armor,
210                                ctx->use_textmode, ctx->include_certs,
211                                ctx /* FIXME */);
212
213  leave:
214   if (err)
215     {
216       ctx->pending = 0; 
217       _gpgme_engine_release (ctx->engine);
218       ctx->engine = NULL;
219     }
220   return err;
221 }
222
223 GpgmeError
224 gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
225                      GpgmeSigMode mode)
226 {
227   return _gpgme_op_sign_start (ctx, 0, in, out, mode);
228 }
229
230 /**
231  * gpgme_op_sign:
232  * @ctx: The context
233  * @in: Data to be signed
234  * @out: Detached signature
235  * @mode: Signature creation mode
236  * 
237  * Create a detached signature for @in and write it to @out.
238  * The data will be signed using either the default key or the ones
239  * defined through @ctx.
240  * The defined modes for signature create are:
241  * <literal>
242  * GPGME_SIG_MODE_NORMAL (or 0) 
243  * GPGME_SIG_MODE_DETACH
244  * GPGME_SIG_MODE_CLEAR
245  * </literal>
246  * Note that the settings done by gpgme_set_armor() and gpgme_set_textmode()
247  * are ignore for @mode GPGME_SIG_MODE_CLEAR.
248  * 
249  * Return value: 0 on success or an error code.
250  **/
251 GpgmeError
252 gpgme_op_sign (GpgmeCtx ctx, GpgmeData in, GpgmeData out, GpgmeSigMode mode)
253 {
254   GpgmeError err = _gpgme_op_sign_start (ctx, 1, in, out, mode);
255   if (!err)
256     err = _gpgme_wait_one (ctx);
257   return err;
258 }