agent/
[gnupg.git] / sm / qualified.c
blob4a9c81ddbd992f5aa7de9df2e7414aa8e7e2c5f3
1 /* qualified.c - Routines related to qualified signatures
2 * Copyright (C) 2005, 2007 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <assert.h>
28 #include <errno.h>
29 #ifdef HAVE_LOCALE_H
30 #include <locale.h>
31 #endif
32 #ifdef HAVE_LANGINFO_CODESET
33 #include <langinfo.h>
34 #endif
36 #include "gpgsm.h"
37 #include "i18n.h"
38 #include <ksba.h>
41 /* We open the file only once and keep the open file pointer as well
42 as the name of the file here. Note that, a listname not equal to
43 NULL indicates that this module has been intialized and if the
44 LISTFP is also NULL, no list of qualified signatures exists. */
45 static char *listname;
46 static FILE *listfp;
49 /* Read the trustlist and return entry by entry. KEY must point to a
50 buffer of at least 41 characters. COUNTRY shall be a buffer of at
51 least 3 characters to receive the country code of that qualified
52 signature (i.e. "de" for German and "be" for Belgium).
54 Reading a valid entry returns 0, EOF is indicated by GPG_ERR_EOF
55 and any other error condition is indicated by the appropriate error
56 code. */
57 static gpg_error_t
58 read_list (char *key, char *country, int *lnr)
60 gpg_error_t err;
61 int c, i, j;
62 char *p, line[256];
64 *key = 0;
65 *country = 0;
67 if (!listname)
69 listname = make_filename (GNUPG_DATADIR, "qualified.txt", NULL);
70 listfp = fopen (listname, "r");
71 if (!listfp && errno != ENOENT)
73 err = gpg_error_from_syserror ();
74 log_error (_("can't open `%s': %s\n"), listname, gpg_strerror (err));
75 return err;
79 if (!listfp)
80 return gpg_error (GPG_ERR_EOF);
84 if (!fgets (line, DIM(line)-1, listfp) )
86 if (feof (listfp))
87 return gpg_error (GPG_ERR_EOF);
88 return gpg_error_from_syserror ();
91 if (!*line || line[strlen(line)-1] != '\n')
93 /* Eat until end of line. */
94 while ( (c=getc (listfp)) != EOF && c != '\n')
96 return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
97 : GPG_ERR_INCOMPLETE_LINE);
99 ++*lnr;
101 /* Allow for empty lines and spaces */
102 for (p=line; spacep (p); p++)
105 while (!*p || *p == '\n' || *p == '#');
107 for (i=j=0; (p[i] == ':' || hexdigitp (p+i)) && j < 40; i++)
108 if ( p[i] != ':' )
109 key[j++] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
110 key[j] = 0;
111 if (j != 40 || !(spacep (p+i) || p[i] == '\n'))
113 log_error (_("invalid formatted fingerprint in `%s', line %d\n"),
114 listname, *lnr);
115 return gpg_error (GPG_ERR_BAD_DATA);
117 assert (p[i]);
118 i++;
119 while (spacep (p+i))
120 i++;
121 if ( p[i] >= 'a' && p[i] <= 'z'
122 && p[i+1] >= 'a' && p[i+1] <= 'z'
123 && (spacep (p+i+2) || p[i+2] == '\n'))
125 country[0] = p[i];
126 country[1] = p[i+1];
127 country[2] = 0;
129 else
131 log_error (_("invalid country code in `%s', line %d\n"), listname, *lnr);
132 return gpg_error (GPG_ERR_BAD_DATA);
135 return 0;
141 /* Check whether the certificate CERT is included in the list of
142 qualified certificates. This list is similar to the "trustlist.txt"
143 as maintained by gpg-agent and includes fingerprints of root
144 certificates to be used for qualified (legally binding like
145 handwritten) signatures. We keep this list system wide and not
146 per user because it is not a decision of the user.
148 Returns: 0 if the certificate is included. GPG_ERR_NOT_FOUND if it
149 is not in the list or any other error (e.g. if no list of
150 qualified signatures is available. If COUNTRY has not been passed
151 as NULL a string witha maximum length of 2 will be copied into it;
152 thus the caller needs to provide a buffer of length 3. */
153 gpg_error_t
154 gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert, char *country)
156 gpg_error_t err;
157 char *fpr;
158 char key[41];
159 char mycountry[3];
160 int lnr = 0;
162 if (country)
163 *country = 0;
165 fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
166 if (!fpr)
167 return gpg_error (GPG_ERR_GENERAL);
169 if (listfp)
170 rewind (listfp);
171 while (!(err = read_list (key, mycountry, &lnr)))
173 if (!strcmp (key, fpr))
174 break;
176 if (gpg_err_code (err) == GPG_ERR_EOF)
177 err = gpg_error (GPG_ERR_NOT_FOUND);
179 if (!err && country)
180 strcpy (country, mycountry);
182 xfree (fpr);
183 return err;
187 /* We know that CERT is a qualified certificate. Ask the user for
188 consent to actually create a signature using this certificate.
189 Returns: 0 for yes, GPG_ERR_CANCEL for no or any otehr error
190 code. */
191 gpg_error_t
192 gpgsm_qualified_consent (ctrl_t ctrl, ksba_cert_t cert)
194 gpg_error_t err;
195 char *name, *subject, *buffer, *p;
196 const char *s;
197 char *orig_codeset = NULL;
199 name = ksba_cert_get_subject (cert, 0);
200 if (!name)
201 return gpg_error (GPG_ERR_GENERAL);
202 subject = gpgsm_format_name2 (name, 0);
203 ksba_free (name); name = NULL;
205 #ifdef ENABLE_NLS
206 /* The Assuan agent protocol requires us to transmit utf-8 strings */
207 orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
208 #ifdef HAVE_LANGINFO_CODESET
209 if (!orig_codeset)
210 orig_codeset = nl_langinfo (CODESET);
211 #endif
212 if (orig_codeset)
213 { /* We only switch when we are able to restore the codeset later.
214 Note that bind_textdomain_codeset does only return on memory
215 errors but not if a codeset is not available. Thus we don't
216 bother printing a diagnostic here. */
217 orig_codeset = xstrdup (orig_codeset);
218 if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
220 xfree (orig_codeset);
221 orig_codeset = NULL;
224 #endif
226 if (asprintf (&name,
227 _("You are about to create a signature using your "
228 "certificate:\n"
229 "\"%s\"\n"
230 "This will create a qualified signature by law "
231 "equated to a handwritten signature.\n\n%s%s"
232 "Are you really sure that you want to do this?"),
233 subject? subject:"?",
234 opt.qualsig_approval?
236 _("Note, that this software is not officially approved "
237 "to create or verify such signatures.\n"),
238 opt.qualsig_approval? "":"\n"
239 ) < 0 )
240 err = gpg_error_from_syserror ();
241 else
242 err = 0;
244 #ifdef ENABLE_NLS
245 if (orig_codeset)
246 bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
247 #endif
248 xfree (orig_codeset);
249 xfree (subject);
251 if (err)
252 return err;
254 buffer = p = xtrymalloc (strlen (name) * 3 + 1);
255 if (!buffer)
257 err = gpg_error_from_syserror ();
258 free (name);
259 return err;
261 for (s=name; *s; s++)
263 if (*s < ' ' || *s == '+')
265 sprintf (p, "%%%02X", *(unsigned char *)s);
266 p += 3;
268 else if (*s == ' ')
269 *p++ = '+';
270 else
271 *p++ = *s;
273 *p = 0;
274 free (name);
277 err = gpgsm_agent_get_confirmation (ctrl, buffer);
279 xfree (buffer);
280 return err;
284 /* Popup a prompt to inform the user that the signature created is not
285 a qualified one. This is of course only done if we know that we
286 have been approved. */
287 gpg_error_t
288 gpgsm_not_qualified_warning (ctrl_t ctrl, ksba_cert_t cert)
290 gpg_error_t err;
291 char *name, *subject, *buffer, *p;
292 const char *s;
293 char *orig_codeset = NULL;
295 if (!opt.qualsig_approval)
296 return 0;
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;
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"))
320 xfree (orig_codeset);
321 orig_codeset = NULL;
324 #endif
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;
337 #ifdef ENABLE_NLS
338 if (orig_codeset)
340 bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
341 xfree (orig_codeset);
343 #endif
344 xfree (subject);
346 if (err)
347 return err;
349 buffer = p = xtrymalloc (strlen (name) * 3 + 1);
350 if (!buffer)
352 err = gpg_error_from_syserror ();
353 free (name);
354 return err;
356 for (s=name; *s; s++)
358 if (*s < ' ' || *s == '+')
360 sprintf (p, "%%%02X", *(unsigned char *)s);
361 p += 3;
363 else if (*s == ' ')
364 *p++ = '+';
365 else
366 *p++ = *s;
368 *p = 0;
369 free (name);
372 err = gpgsm_agent_get_confirmation (ctrl, buffer);
374 xfree (buffer);
375 return err;