27e5036c8729159c208d880e78524c59e1f4ef76
[scute.git] / src / gpgsm.c
1 /* gpgsm.c - Talking to gpgsm.
2    Copyright (C) 2006, 2008 g10 Code GmbH
3
4    This file is part of Scute.
5
6    Scute is free software; you can redistribute it and/or modify it
7    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    Scute is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with Scute; if not, write to the Free Software Foundation,
18    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20    In addition, as a special exception, g10 Code GmbH gives permission
21    to link this library: with the Mozilla Foundation's code for
22    Mozilla (or with modified versions of it that use the same license
23    as the "Mozilla" code), and distribute the linked executables.  You
24    must obey the GNU General Public License in all respects for all of
25    the code used other than "Mozilla".  If you modify this file, you
26    may extend this exception to your version of the file, but you are
27    not obligated to do so.  If you do not wish to do so, delete this
28    exception statement from your version.  */
29
30 #if HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <assert.h>
35 #include <locale.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdbool.h>
39 #include <time.h>
40
41 #include <assuan.h>
42 #include <gpg-error.h>
43
44 #include "cryptoki.h"
45 #include "support.h"
46 #include "cert.h"
47 #include "agent.h"
48 #include "gpgsm.h"
49 #include "debug.h"
50
51 \f
52 /* Communication object for search_cb.  */
53 struct search_cb_parm
54 {
55   bool found;    /* Set to true if a private key object was found.  */
56   cert_get_cb_t cert_get_cb;
57   void *hook;
58   bool with_chain;
59   const char *grip;
60 };
61
62
63 static gpg_error_t
64 search_cb (void *hook, struct cert *cert)
65 {
66   struct search_cb_parm *ctx = hook;
67   gpg_error_t err = 0;
68
69   CK_ATTRIBUTE_PTR attrp;
70   CK_ULONG attr_countp;
71
72   /* Add the private key object only once.  */
73   if (!ctx->found)
74     {
75       err = scute_attr_prv (cert, ctx->grip, &attrp, &attr_countp);
76       if (err)
77         return err;
78
79       err = (*ctx->cert_get_cb) (ctx->hook, attrp, attr_countp);
80       if (err)
81         {
82           scute_attr_free (attrp, attr_countp);
83           return err;
84         }
85
86       ctx->found = true;
87     }
88
89   /* Add the certificate chain recursively before adding the
90      certificate.  But ignore errors.  If the chain is incomplete, we
91      might still be able to proceed, for example with client
92      authentication.  */
93   if (ctx->with_chain && strcmp (cert->chain_id, cert->fpr))
94     scute_gpgsm_search_certs_by_fpr (cert->chain_id, search_cb, ctx);
95
96   /* Turn this certificate into a certificate object.  */
97   err = scute_attr_cert (cert, ctx->grip, &attrp, &attr_countp);
98   if (err)
99     return err;
100
101   err = (*ctx->cert_get_cb) (ctx->hook, attrp, attr_countp);
102   if (err)
103     {
104       scute_attr_free (attrp, attr_countp);
105       return err;
106     }
107
108   return err;
109 }
110
111
112 /* Create the attributes required for a new certificate object.  If
113  * CERTREF is not NULL it is used to locate the cert directly from the
114  * card; if CERTREF is NULL or a cert was not found on the card, GRIP
115  * is used to find the certificate in the local key store of gpgsm.
116  *
117  * FIXME: This is all pretty questionable because our input data
118  * always comes from the card.
119  *
120  * Returns allocated attributes for the certificate object in ATTRP
121  * and ATTR_COUNTP, and for the private key object in PRV_ATTRP and
122  * PRV_ATTR_COUNTP.  */
123 gpg_error_t
124 scute_gpgsm_get_cert (char *grip, const char *certref,
125                       cert_get_cb_t cert_get_cb, void *hook)
126 {
127   gpg_error_t err;
128   struct search_cb_parm search;
129
130   search.found = false;
131   search.cert_get_cb = cert_get_cb;
132   search.hook = hook;
133   search.with_chain = false;
134   search.grip = grip;
135
136   DEBUG (DBG_INFO, "scute_gpgsm_get_cert: certref='%s'", certref);
137
138   /* If the cert is requested from the card, we try to get it from
139    * the card as well.  */
140   if (certref)
141     {
142       struct cert cert;
143
144       memset (&cert, '\0', sizeof (cert));
145       err = scute_agent_get_cert (certref, &cert);
146       if (! err)
147         {
148 #if 0
149           /* For now, we don't need no stinking chain.  */
150
151           /* As we only have the DER certificate from the card, we need to
152              parse that and fill out the missing info and try to get the
153              certificate chain from gpgsm.  */
154           err = scute_cert_from_der (&cert);
155 #endif
156           if (! err)
157             err = search_cb (&search, &cert);
158           return err;
159         }
160     }
161
162   DEBUG (DBG_INFO, "scute_gpgsm_get_cert: falling back to gpgsm");
163   search.with_chain = true;
164   err = scute_gpgsm_search_certs_by_grip (grip, search_cb, &search);
165   return err;
166 }