1a0f5279025655ea03fd81a3be742c803e0b3e80
[gnupg.git] / sm / qualified.c
1 /* qualified.c - Routines related to qualified signatures
2  * Copyright (C) 2005, 2007 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG 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 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <assert.h>
26 #include <errno.h>
27 #ifdef HAVE_LOCALE_H
28 #include <locale.h>
29 #endif
30 #ifdef HAVE_LANGINFO_CODESET
31 #include <langinfo.h>
32 #endif
33
34 #include "gpgsm.h"
35 #include "i18n.h"
36 #include <ksba.h>
37
38
39 /* We open the file only once and keep the open file pointer as well
40    as the name of the file here.  Note that, a listname not equal to
41    NULL indicates that this module has been intialized and if the
42    LISTFP is also NULL, no list of qualified signatures exists. */
43 static char *listname;
44 static FILE *listfp;
45
46
47 /* Read the trustlist and return entry by entry.  KEY must point to a
48    buffer of at least 41 characters. COUNTRY shall be a buffer of at
49    least 3 characters to receive the country code of that qualified
50    signature (i.e. "de" for German and "be" for Belgium).
51
52    Reading a valid entry returns 0, EOF is indicated by GPG_ERR_EOF
53    and any other error condition is indicated by the appropriate error
54    code. */
55 static gpg_error_t
56 read_list (char *key, char *country, int *lnr)
57 {
58   gpg_error_t err;
59   int c, i, j;
60   char *p, line[256];
61
62   *key = 0;
63   *country = 0;
64
65   if (!listname)
66     {
67       listname = make_filename (gnupg_datadir (), "qualified.txt", NULL);
68       listfp = fopen (listname, "r");
69       if (!listfp && errno != ENOENT)
70         {
71           err = gpg_error_from_syserror ();
72           log_error (_("can't open `%s': %s\n"), listname, gpg_strerror (err));
73           return err;
74         }
75     }
76
77   if (!listfp)
78     return gpg_error (GPG_ERR_EOF);
79
80   do
81     {
82       if (!fgets (line, DIM(line)-1, listfp) )
83         {
84           if (feof (listfp))
85             return gpg_error (GPG_ERR_EOF);
86           return gpg_error_from_syserror ();
87         }
88
89       if (!*line || line[strlen(line)-1] != '\n')
90         {
91           /* Eat until end of line. */
92           while ( (c=getc (listfp)) != EOF && c != '\n')
93             ;
94           return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
95                                  : GPG_ERR_INCOMPLETE_LINE);
96         }
97       ++*lnr;
98       
99       /* Allow for empty lines and spaces */
100       for (p=line; spacep (p); p++)
101         ;
102     }
103   while (!*p || *p == '\n' || *p == '#');
104   
105   for (i=j=0; (p[i] == ':' || hexdigitp (p+i)) && j < 40; i++)
106     if ( p[i] != ':' )
107       key[j++] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
108   key[j] = 0;
109   if (j != 40 || !(spacep (p+i) || p[i] == '\n'))
110     {
111       log_error (_("invalid formatted fingerprint in `%s', line %d\n"),
112                  listname, *lnr);
113       return gpg_error (GPG_ERR_BAD_DATA);
114     }
115   assert (p[i]);
116   i++;
117   while (spacep (p+i))
118     i++;
119   if ( p[i] >= 'a' && p[i] <= 'z' 
120        && p[i+1] >= 'a' && p[i+1] <= 'z' 
121        && (spacep (p+i+2) || p[i+2] == '\n'))
122     {
123       country[0] = p[i];
124       country[1] = p[i+1];
125       country[2] = 0;
126     }
127   else
128     {
129       log_error (_("invalid country code in `%s', line %d\n"), listname, *lnr);
130       return gpg_error (GPG_ERR_BAD_DATA);
131     }
132
133   return 0;
134 }
135
136
137
138
139 /* Check whether the certificate CERT is included in the list of
140    qualified certificates.  This list is similar to the "trustlist.txt"
141    as maintained by gpg-agent and includes fingerprints of root
142    certificates to be used for qualified (legally binding like
143    handwritten) signatures.  We keep this list system wide and not
144    per user because it is not a decision of the user. 
145
146    Returns: 0 if the certificate is included.  GPG_ERR_NOT_FOUND if it
147    is not in the list or any other error (e.g. if no list of
148    qualified signatures is available.  If COUNTRY has not been passed
149    as NULL a string witha maximum length of 2 will be copied into it;
150    thus the caller needs to provide a buffer of length 3. */
151 gpg_error_t
152 gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert, char *country)
153 {
154   gpg_error_t err;
155   char *fpr;
156   char key[41];
157   char mycountry[3];
158   int lnr = 0;
159
160   if (country)
161     *country = 0;
162
163   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
164   if (!fpr)
165     return gpg_error (GPG_ERR_GENERAL);
166
167   if (listfp)
168     rewind (listfp);
169   while (!(err = read_list (key, mycountry, &lnr)))
170     {
171       if (!strcmp (key, fpr))
172         break;
173     }
174   if (gpg_err_code (err) == GPG_ERR_EOF)
175     err = gpg_error (GPG_ERR_NOT_FOUND);
176
177   if (!err && country)
178     strcpy (country, mycountry);
179
180   xfree (fpr);
181   return err;
182 }
183
184
185 /* We know that CERT is a qualified certificate.  Ask the user for
186    consent to actually create a signature using this certificate.
187    Returns: 0 for yes, GPG_ERR_CANCEL for no or any otehr error
188    code. */
189 gpg_error_t
190 gpgsm_qualified_consent (ctrl_t ctrl, ksba_cert_t cert)
191 {
192   gpg_error_t err;
193   char *name, *subject, *buffer, *p;
194   const char *s;
195   char *orig_codeset = NULL;
196
197   name = ksba_cert_get_subject (cert, 0);
198   if (!name)
199     return gpg_error (GPG_ERR_GENERAL);
200   subject = gpgsm_format_name2 (name, 0);
201   ksba_free (name); name = NULL;
202
203 #ifdef ENABLE_NLS
204   /* The Assuan agent protocol requires us to transmit utf-8 strings */
205   orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
206 #ifdef HAVE_LANGINFO_CODESET
207   if (!orig_codeset)
208     orig_codeset = nl_langinfo (CODESET);
209 #endif
210   if (orig_codeset)
211     { /* We only switch when we are able to restore the codeset later.
212          Note that bind_textdomain_codeset does only return on memory
213          errors but not if a codeset is not available.  Thus we don't
214          bother printing a diagnostic here. */
215       orig_codeset = xstrdup (orig_codeset);
216       if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
217         {
218           xfree (orig_codeset);
219           orig_codeset = NULL; 
220         }
221     }
222 #endif
223
224   if (asprintf (&name,
225                 _("You are about to create a signature using your "
226                   "certificate:\n"
227                   "\"%s\"\n"
228                   "This will create a qualified signature by law "
229                   "equated to a handwritten signature.\n\n%s%s"
230                   "Are you really sure that you want to do this?"),
231                 subject? subject:"?",
232                 opt.qualsig_approval? 
233                 "":
234                 _("Note, that this software is not officially approved "
235                   "to create or verify such signatures.\n"),
236                 opt.qualsig_approval? "":"\n"
237                 ) < 0 )
238     err = gpg_error_from_syserror ();
239   else
240     err = 0;
241
242 #ifdef ENABLE_NLS
243   if (orig_codeset)
244     bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
245 #endif
246   xfree (orig_codeset);
247   xfree (subject);
248
249   if (err)
250     return err;
251
252   buffer = p = xtrymalloc (strlen (name) * 3 + 1);
253   if (!buffer)
254     {
255       err = gpg_error_from_syserror ();
256       free (name);
257       return err;
258     }
259   for (s=name; *s; s++)
260     {
261       if (*s < ' ' || *s == '+')
262         {
263           sprintf (p, "%%%02X", *(unsigned char *)s);
264           p += 3;
265         }
266       else if (*s == ' ')
267         *p++ = '+';
268       else
269         *p++ = *s;
270     }
271   *p = 0;
272   free (name); 
273
274
275   err = gpgsm_agent_get_confirmation (ctrl, buffer);
276
277   xfree (buffer);
278   return err;
279 }
280
281
282 /* Popup a prompt to inform the user that the signature created is not
283    a qualified one.  This is of course only done if we know that we
284    have been approved. */
285 gpg_error_t
286 gpgsm_not_qualified_warning (ctrl_t ctrl, ksba_cert_t cert)
287 {
288   gpg_error_t err;
289   char *name, *subject, *buffer, *p;
290   const char *s;
291 #ifdef ENABLE_NLS
292   char *orig_codeset = NULL;
293 #endif
294
295   if (!opt.qualsig_approval)
296     return 0;
297
298   name = ksba_cert_get_subject (cert, 0);
299   if (!name)
300     return gpg_error (GPG_ERR_GENERAL);
301   subject = gpgsm_format_name2 (name, 0);
302   ksba_free (name); name = NULL;
303
304
305 #ifdef ENABLE_NLS
306   /* The Assuan agent protocol requires us to transmit utf-8 strings */
307   orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
308 #ifdef HAVE_LANGINFO_CODESET
309   if (!orig_codeset)
310     orig_codeset = nl_langinfo (CODESET);
311 #endif
312   if (orig_codeset)
313     { /* We only switch when we are able to restore the codeset later.
314          Note that bind_textdomain_codeset does only return on memory
315          errors but not if a codeset is not available.  Thus we don't
316          bother printing a diagnostic here. */
317       orig_codeset = xstrdup (orig_codeset);
318       if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
319         {
320           xfree (orig_codeset);
321           orig_codeset = NULL; 
322         }
323     }
324 #endif
325
326   if (asprintf (&name,
327                 _("You are about to create a signature using your "
328                   "certificate:\n"
329                   "\"%s\"\n"
330                   "Note, that this certificate will NOT create a "
331                   "qualified signature!"),
332                 subject? subject:"?") < 0 )
333     err = gpg_error_from_syserror ();
334   else
335     err = 0;
336
337 #ifdef ENABLE_NLS
338   if (orig_codeset)
339     {
340       bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
341       xfree (orig_codeset);
342     }
343 #endif
344   xfree (subject);
345
346   if (err)
347     return err;
348
349   buffer = p = xtrymalloc (strlen (name) * 3 + 1);
350   if (!buffer)
351     {
352       err = gpg_error_from_syserror ();
353       free (name);
354       return err;
355     }
356   for (s=name; *s; s++)
357     {
358       if (*s < ' ' || *s == '+')
359         {
360           sprintf (p, "%%%02X", *(unsigned char *)s);
361           p += 3;
362         }
363       else if (*s == ' ')
364         *p++ = '+';
365       else
366         *p++ = *s;
367     }
368   *p = 0;
369   free (name); 
370
371
372   err = gpgsm_agent_get_confirmation (ctrl, buffer);
373
374   xfree (buffer);
375   return err;
376 }