Added qualified signature features.
[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"
220                   "Are you really sure that you want to do this?"),
221                 subject? subject:"?"
222                 ) < 0 )
223     err = gpg_error_from_errno (errno);
224   else
225     err = 0;
226
227 #ifdef ENABLE_NLS
228   if (orig_codeset)
229     bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
230 #endif
231   xfree (orig_codeset);
232   xfree (subject);
233
234   if (err)
235     return err;
236
237   buffer = p = xtrymalloc (strlen (name) * 3 + 1);
238   if (!buffer)
239     {
240       err = gpg_error_from_errno (errno);
241       free (name);
242       return err;
243     }
244   for (s=name; *s; s++)
245     {
246       if (*s < ' ' || *s == '+')
247         {
248           sprintf (p, "%%%02X", *(unsigned char *)s);
249           p += 3;
250         }
251       else if (*s == ' ')
252         *p++ = '+';
253       else
254         *p++ = *s;
255     }
256   *p = 0;
257   free (name); 
258
259
260   err = gpgsm_agent_get_confirmation (ctrl, buffer);
261
262   xfree (buffer);
263   return err;
264 }