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