2002-04-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / agent / learncard.c
blobfe3e9eff321a44afac3d400b80bf73430ced6416
1 /* learncard.c - Handle the LEARN command
2 * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
31 #include "agent.h"
32 #include "../assuan/assuan.h"
34 struct keypair_info_s {
35 struct keypair_info_s *next;
36 int no_cert;
37 char *id; /* points into grip */
38 char hexgrip[1];
40 typedef struct keypair_info_s *KEYPAIR_INFO;
42 struct kpinfo_cb_parm_s {
43 int error;
44 KEYPAIR_INFO info;
48 static void
49 release_keypair_info (KEYPAIR_INFO info)
51 while (info)
53 KEYPAIR_INFO tmp = info->next;
54 xfree (info);
55 info = tmp;
61 /* This callback is used by agent_card_leanr and passed the content of
62 all KEYPAIRINFO lines. It merely store this data away */
63 static void
64 kpinfo_cb (void *opaque, const char *line)
66 struct kpinfo_cb_parm_s *parm = opaque;
67 KEYPAIR_INFO item;
68 char *p;
70 if (parm->error)
71 return; /* no need to gather data after an error coccured */
72 item = xtrycalloc (1, sizeof *item + strlen (line));
73 if (!item)
75 parm->error = GNUPG_Out_Of_Core;
76 return;
78 strcpy (item->hexgrip, line);
79 for (p = item->hexgrip; hexdigitp (p); p++)
81 if (p == item->hexgrip && *p == 'X' && spacep (p+1))
83 item->no_cert = 1;
84 p++;
86 else if ((p - item->hexgrip) != 40 || !spacep (p))
87 { /* not a 20 byte hex keygrip or not followed by a space */
88 parm->error = GNUPG_Invalid_Response;
89 xfree (item);
90 return;
92 *p++ = 0;
93 while (spacep (p))
94 p++;
95 item->id = p;
96 while (*p && !spacep (p))
97 p++;
98 if (p == item->id)
99 { /* invalid ID string */
100 parm->error = GNUPG_Invalid_Response;
101 xfree (item);
102 return;
104 *p = 0; /* ignore trailing stuff */
106 /* store it */
107 item->next = parm->info;
108 parm->info = item;
112 /* Create an S-expression with the shadow info. */
113 static unsigned char *
114 make_shadow_info (const char *serialno, const char *idstring)
116 const char *s;
117 unsigned char *info, *p;
118 char numbuf[21];
119 int n;
121 for (s=serialno, n=0; *s && s[1]; s += 2)
122 n++;
124 info = p = xtrymalloc (1 + 21 + n
125 + 21 + strlen (idstring) + 1 + 1);
126 *p++ = '(';
127 sprintf (numbuf, "%d:", n);
128 p = stpcpy (p, numbuf);
129 for (s=serialno; *s && s[1]; s += 2)
130 *p++ = xtoi_2 (s);
131 sprintf (numbuf, "%d:", strlen (idstring));
132 p = stpcpy (p, numbuf);
133 p = stpcpy (p, idstring);
134 *p++ = ')';
135 *p = 0;
136 return info;
140 /* Perform the learn operation. If ASSUAN_CONTEXT is not NULL all new
141 certificates are send via Assuan */
143 agent_handle_learn (void *assuan_context)
145 int rc;
146 struct kpinfo_cb_parm_s parm;
147 char *serialno = NULL;
148 KEYPAIR_INFO item;
149 unsigned char grip[20];
150 char *p;
151 int i;
153 memset (&parm, 0, sizeof parm);
155 /* Check whether a card is present and get the serial number */
156 rc = agent_card_serialno (&serialno);
157 if (rc)
158 goto leave;
160 /* now gather all the availabe info */
161 rc = agent_card_learn (kpinfo_cb, &parm);
162 if (!rc && parm.error)
163 rc = parm.error;
164 if (rc)
166 log_debug ("agent_card_learn failed: %s\n", gnupg_strerror (rc));
167 goto leave;
170 log_info ("card has S/N: %s\n", serialno);
171 for (item = parm.info; item; item = item->next)
173 unsigned char *pubkey, *shdkey;
174 size_t n;
176 if (opt.verbose)
177 log_info (" id: %s (grip=%s)\n", item->id, item->hexgrip);
179 if (item->no_cert)
180 continue; /* no public key yet available */
182 for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
183 grip[i] = xtoi_2 (p);
185 if (!agent_key_available (grip))
186 continue;
188 /* unknown - store it */
189 rc = agent_card_readkey (item->id, &pubkey);
190 if (rc)
192 log_debug ("agent_card_readkey failed: %s\n", gnupg_strerror (rc));
193 goto leave;
197 unsigned char *shadow_info = make_shadow_info (serialno, item->id);
198 if (!shadow_info)
200 rc = GNUPG_Out_Of_Core;
201 xfree (pubkey);
202 goto leave;
204 rc = agent_shadow_key (pubkey, shadow_info, &shdkey);
205 xfree (shadow_info);
207 xfree (pubkey);
208 if (rc)
210 log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc));
211 goto leave;
213 n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
214 assert (n);
216 rc = agent_write_private_key (grip, shdkey, n, 0);
217 xfree (shdkey);
218 if (rc)
220 log_error ("error writing key: %s\n", gnupg_strerror (rc));
221 goto leave;
224 if (opt.verbose)
225 log_info ("stored\n");
227 if (assuan_context)
229 char *derbuf;
230 size_t derbuflen;
232 rc = agent_card_readcert (item->id, &derbuf, &derbuflen);
233 if (rc)
235 log_error ("error reading certificate: %s\n",
236 gnupg_strerror (rc));
237 goto leave;
240 rc = assuan_send_data (assuan_context, derbuf, derbuflen);
241 xfree (derbuf);
242 if (!rc)
243 rc = assuan_send_data (assuan_context, NULL, 0);
244 if (!rc)
245 rc = assuan_write_line (assuan_context, "END");
246 if (rc)
248 log_error ("sending certificate failed: %s\n",
249 assuan_strerror (rc));
250 rc = map_assuan_err (rc);
251 goto leave;
257 leave:
258 xfree (serialno);
259 release_keypair_info (parm.info);
260 return rc;