1/*
2   neon PKCS#11 support
3   Copyright (C) 2008, Joe Orton <joe@manyfish.co.uk>
4
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Library General Public
7   License as published by the Free Software Foundation; either
8   version 2 of the License, or (at your option) any later version.
9
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Library General Public License for more details.
14
15   You should have received a copy of the GNU Library General Public
16   License along with this library; if not, write to the Free
17   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18   MA 02111-1307, USA
19*/
20
21#include "config.h"
22
23#include "ne_pkcs11.h"
24
25#ifdef HAVE_PAKCHOIS
26#include <string.h>
27
28#include <pakchois.h>
29
30#include "ne_internal.h"
31#include "ne_alloc.h"
32#include "ne_private.h"
33#include "ne_privssl.h"
34
35struct ne_ssl_pkcs11_provider_s {
36    pakchois_module_t *module;
37    ne_ssl_pkcs11_pin_fn pin_fn;
38    void *pin_data;
39    pakchois_session_t *session;
40    ne_ssl_client_cert *clicert;
41    ck_object_handle_t privkey;
42    ck_key_type_t keytype;
43};
44
45/* To do list for PKCS#11 support:
46
47   - propagate error strings back to ne_session; use new
48   pakchois_error() for pakchois API 0.2
49   - add API to specify a particular slot number to use for clicert
50   - add API to specify a particular cert ID for clicert
51   - find a certificate which has an issuer matching the
52     CA dnames given by GnuTLS
53   - make sure subject name matches between pubkey and privkey
54   - check error handling & fail gracefully if the token is
55   ejected mid-session
56   - add API to enumerate/search provided certs and allow
57     direct choice? (or just punt)
58   - the session<->provider interface requires that
59   one clicert is used for all sessions.  remove this limitation
60   - add API to import all CA certs as trusted
61   (CKA_CERTIFICATE_CATEGORY seems to be unused unfortunately;
62    just add all X509 certs with CKA_TRUSTED set to true))
63   - make DSA work
64
65*/
66
67#ifdef HAVE_OPENSSL
68
69#include <openssl/rsa.h>
70#include <openssl/err.h>
71
72#define PK11_RSA_ERR (RSA_F_RSA_EAY_PRIVATE_ENCRYPT)
73
74/* RSA_METHOD ->rsa_sign calback. */
75static int pk11_rsa_sign(int type,
76                         const unsigned char *m, unsigned int mlen,
77                         unsigned char *sigret, unsigned int *siglen,
78                         const RSA *r)
79{
80    ne_ssl_pkcs11_provider *prov = (ne_ssl_pkcs11_provider *)r->meth->app_data;
81    ck_rv_t rv;
82    struct ck_mechanism mech;
83    unsigned long len;
84
85    if (!prov->session || prov->privkey == CK_INVALID_HANDLE) {
86        NE_DEBUG(NE_DBG_SSL, "pk11: Cannot sign, no session/key.\n");
87        RSAerr(PK11_RSA_ERR,ERR_R_RSA_LIB);
88        return 0;
89    }
90
91    mech.mechanism = CKM_RSA_PKCS;
92    mech.parameter = NULL;
93    mech.parameter_len = 0;
94
95    /* Initialize signing operation; using the private key discovered
96     * earlier. */
97    rv = pakchois_sign_init(prov->session, &mech, prov->privkey);
98    if (rv != CKR_OK) {
99        NE_DEBUG(NE_DBG_SSL, "pk11: SignInit failed: %lx.\n", rv);
100        RSAerr(PK11_RSA_ERR, ERR_R_RSA_LIB);
101        return 0;
102    }
103
104    len = *siglen = RSA_size(r);
105    rv = pakchois_sign(prov->session, (unsigned char *)m, mlen, sigret, &len);
106    if (rv != CKR_OK) {
107        NE_DEBUG(NE_DBG_SSL, "pk11: Sign failed.\n");
108        RSAerr(PK11_RSA_ERR, ERR_R_RSA_LIB);
109        return 0;
110    }
111
112    NE_DEBUG(NE_DBG_SSL, "pk11: Signed successfully.\n");
113    return 1;
114}
115
116/* RSA_METHOD ->rsa_init implementation; called during RSA_new(rsa). */
117static int pk11_rsa_init(RSA *rsa)
118{
119    /* Ensures that RSA_sign() uses meth->rsa_sign: */
120    rsa->flags |= RSA_FLAG_SIGN_VER;
121    return 1;
122}
123
124/* RSA_METHOD ->rsa_finish implementation; called during
125 * RSA_free(rsa). */
126static int pk11_rsa_finish(RSA *rsa)
127{
128    RSA_METHOD *meth = (RSA_METHOD *)rsa->meth;
129
130    /* Freeing the dynamically allocated method here works as well as
131     * doing anything else: */
132    ne_free(meth);
133    /* Does not appear that rsa->meth will be used after this, but in
134     * case it is, ensure a NULL pointer dereference rather than a
135     * random pointer dereference. */
136    rsa->meth = NULL;
137
138    return 0;
139}
140
141/* Return an RSA_METHOD which will use the PKCS#11 provider to
142 * implement the signing operation. */
143static RSA_METHOD *pk11_rsa_method(ne_ssl_pkcs11_provider *prov)
144{
145    RSA_METHOD *m = ne_calloc(sizeof *m);
146
147    m->name = "neon PKCS#11";
148    m->rsa_sign = pk11_rsa_sign;
149
150    m->init = pk11_rsa_init;
151    m->finish = pk11_rsa_finish;
152
153    /* This is hopefully under complete control of the RSA_METHOD,
154     * otherwise there is nowhere to put this. */
155    m->app_data = (char *)prov;
156
157    m->flags = RSA_METHOD_FLAG_NO_CHECK;
158
159    return m;
160}
161#endif
162
163static int pk11_find_x509(ne_ssl_pkcs11_provider *prov,
164                          pakchois_session_t *pks,
165                          unsigned char *certid, unsigned long *cid_len)
166{
167    struct ck_attribute a[3];
168    ck_object_class_t class;
169    ck_certificate_type_t type;
170    ck_rv_t rv;
171    ck_object_handle_t obj;
172    unsigned long count;
173    int found = 0;
174
175    /* Find objects with cert class and X.509 cert type. */
176    class = CKO_CERTIFICATE;
177    type = CKC_X_509;
178
179    a[0].type = CKA_CLASS;
180    a[0].value = &class;
181    a[0].value_len = sizeof class;
182    a[1].type = CKA_CERTIFICATE_TYPE;
183    a[1].value = &type;
184    a[1].value_len = sizeof type;
185
186    rv = pakchois_find_objects_init(pks, a, 2);
187    if (rv != CKR_OK) {
188        NE_DEBUG(NE_DBG_SSL, "pk11: FindObjectsInit failed.\n");
189        return 0;
190    }
191
192    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
193           && count == 1) {
194        unsigned char value[8192], subject[8192];
195
196        a[0].type = CKA_VALUE;
197        a[0].value = value;
198        a[0].value_len = sizeof value;
199        a[1].type = CKA_ID;
200        a[1].value = certid;
201        a[1].value_len = *cid_len;
202        a[2].type = CKA_SUBJECT;
203        a[2].value = subject;
204        a[2].value_len = sizeof subject;
205
206        if (pakchois_get_attribute_value(pks, obj, a, 3) == CKR_OK) {
207            ne_ssl_client_cert *cc;
208
209#ifdef HAVE_GNUTLS
210            cc = ne__ssl_clicert_exkey_import(value, a[0].value_len);
211#else
212            cc = ne__ssl_clicert_exkey_import(value, a[0].value_len, pk11_rsa_method(prov));
213#endif
214            if (cc) {
215                NE_DEBUG(NE_DBG_SSL, "pk11: Imported X.509 cert.\n");
216                prov->clicert = cc;
217                found = 1;
218                *cid_len = a[1].value_len;
219                break;
220            }
221        }
222        else {
223            NE_DEBUG(NE_DBG_SSL, "pk11: Skipped cert, missing attrs.\n");
224        }
225    }
226
227    pakchois_find_objects_final(pks);
228    return found;
229}
230
231#ifdef HAVE_OPENSSL
232/* No DSA support for OpenSSL (yet, anyway). */
233#define KEYTYPE_IS_DSA(kt) (0)
234#else
235#define KEYTYPE_IS_DSA(kt) (kt == CKK_DSA)
236#endif
237
238static int pk11_find_pkey(ne_ssl_pkcs11_provider *prov,
239                          pakchois_session_t *pks,
240                          unsigned char *certid, unsigned long cid_len)
241{
242    struct ck_attribute a[3];
243    ck_object_class_t class;
244    ck_rv_t rv;
245    ck_object_handle_t obj;
246    unsigned long count;
247    int found = 0;
248
249    class = CKO_PRIVATE_KEY;
250
251    /* Find an object with private key class and a certificate ID
252     * which matches the certificate. */
253    /* FIXME: also match the cert subject. */
254    a[0].type = CKA_CLASS;
255    a[0].value = &class;
256    a[0].value_len = sizeof class;
257    a[1].type = CKA_ID;
258    a[1].value = certid;
259    a[1].value_len = cid_len;
260
261    rv = pakchois_find_objects_init(pks, a, 2);
262    if (rv != CKR_OK) {
263        NE_DEBUG(NE_DBG_SSL, "pk11: FindObjectsInit failed.\n");
264        /* TODO: error propagation */
265        return 0;
266    }
267
268    rv = pakchois_find_objects(pks, &obj, 1, &count);
269    if (rv == CKR_OK && count == 1) {
270        NE_DEBUG(NE_DBG_SSL, "pk11: Found private key.\n");
271
272        a[0].type = CKA_KEY_TYPE;
273        a[0].value = &prov->keytype;
274        a[0].value_len = sizeof prov->keytype;
275
276        if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK
277            && (prov->keytype == CKK_RSA || KEYTYPE_IS_DSA(prov->keytype))) {
278            found = 1;
279            prov->privkey = obj;
280        }
281        else {
282            NE_DEBUG(NE_DBG_SSL, "pk11: Could not determine key type.\n");
283        }
284    }
285
286    pakchois_find_objects_final(pks);
287
288    return found;
289}
290
291static int find_client_cert(ne_ssl_pkcs11_provider *prov,
292                            pakchois_session_t *pks)
293{
294    unsigned char certid[8192];
295    unsigned long cid_len = sizeof certid;
296
297    /* TODO: match cert subject too. */
298    return pk11_find_x509(prov, pks, certid, &cid_len)
299        && pk11_find_pkey(prov, pks, certid, cid_len);
300}
301
302#ifdef HAVE_GNUTLS
303/* Callback invoked by GnuTLS to provide the signature.  The signature
304 * operation is handled here by the PKCS#11 provider.  */
305static int pk11_sign_callback(gnutls_session_t session,
306                              void *userdata,
307                              gnutls_certificate_type_t cert_type,
308                              const gnutls_datum_t *cert,
309                              const gnutls_datum_t *hash,
310                              gnutls_datum_t *signature)
311{
312    ne_ssl_pkcs11_provider *prov = userdata;
313    ck_rv_t rv;
314    struct ck_mechanism mech;
315    unsigned long siglen;
316
317    if (!prov->session || prov->privkey == CK_INVALID_HANDLE) {
318        NE_DEBUG(NE_DBG_SSL, "pk11: Cannot sign, no session/key.\n");
319        return GNUTLS_E_NO_CERTIFICATE_FOUND;
320    }
321
322    mech.mechanism = prov->keytype == CKK_DSA ? CKM_DSA : CKM_RSA_PKCS;
323    mech.parameter = NULL;
324    mech.parameter_len = 0;
325
326    /* Initialize signing operation; using the private key discovered
327     * earlier. */
328    rv = pakchois_sign_init(prov->session, &mech, prov->privkey);
329    if (rv != CKR_OK) {
330        NE_DEBUG(NE_DBG_SSL, "pk11: SignInit failed: %lx.\n", rv);
331        return GNUTLS_E_PK_SIGN_FAILED;
332    }
333
334    /* Work out how long the signature must be: */
335    rv = pakchois_sign(prov->session, hash->data, hash->size, NULL, &siglen);
336    if (rv != CKR_OK) {
337        NE_DEBUG(NE_DBG_SSL, "pk11: Sign1 failed.\n");
338        return GNUTLS_E_PK_SIGN_FAILED;
339    }
340
341    signature->data = gnutls_malloc(siglen);
342    signature->size = siglen;
343
344    rv = pakchois_sign(prov->session, hash->data, hash->size,
345                       signature->data, &siglen);
346    if (rv != CKR_OK) {
347        NE_DEBUG(NE_DBG_SSL, "pk11: Sign2 failed.\n");
348        return GNUTLS_E_PK_SIGN_FAILED;
349    }
350
351    NE_DEBUG(NE_DBG_SSL, "pk11: Signed successfully.\n");
352
353    return 0;
354}
355#endif
356
357static void terminate_string(unsigned char *str, size_t len)
358{
359    unsigned char *ptr = str + len - 1;
360
361    while ((*ptr == ' ' || *ptr == '\t' || *ptr == '\0') && ptr >= str)
362        ptr--;
363
364    if (ptr == str - 1)
365        str[0] = '\0';
366    else if (ptr == str + len - 1)
367        str[len-1] = '\0';
368    else
369        ptr[1] = '\0';
370}
371
372static int pk11_login(ne_ssl_pkcs11_provider *prov, ck_slot_id_t slot_id,
373                      pakchois_session_t *pks, struct ck_slot_info *sinfo)
374{
375    struct ck_token_info tinfo;
376    int attempt = 0;
377    ck_rv_t rv;
378
379    if (pakchois_get_token_info(prov->module, slot_id, &tinfo) != CKR_OK) {
380        NE_DEBUG(NE_DBG_SSL, "pk11: GetTokenInfo failed\n");
381        /* TODO: propagate error. */
382        return -1;
383    }
384
385    if ((tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
386        NE_DEBUG(NE_DBG_SSL, "pk11: No login required.\n");
387        return 0;
388    }
389
390    /* For a token with a "protected" (out-of-band) authentication
391     * path, calling login with a NULL username is all that is
392     * required. */
393    if (tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
394        if (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) {
395            return 0;
396        }
397        else {
398            NE_DEBUG(NE_DBG_SSL, "pk11: Protected login failed.\n");
399            /* TODO: error propagation. */
400            return -1;
401        }
402    }
403
404    /* Otherwise, PIN entry is necessary for login, so fail if there's
405     * no callback. */
406    if (!prov->pin_fn) {
407        NE_DEBUG(NE_DBG_SSL, "pk11: No pin callback but login required.\n");
408        /* TODO: propagate error. */
409        return -1;
410    }
411
412    terminate_string(sinfo->slot_description, sizeof sinfo->slot_description);
413
414    do {
415        char pin[NE_SSL_P11PINLEN];
416        unsigned int flags = 0;
417
418        /* If login has been attempted once already, check the token
419         * status again, the flags might change. */
420        if (attempt) {
421            if (pakchois_get_token_info(prov->module, slot_id,
422                                        &tinfo) != CKR_OK) {
423                NE_DEBUG(NE_DBG_SSL, "pk11: GetTokenInfo failed\n");
424                /* TODO: propagate error. */
425                return -1;
426            }
427        }
428
429        if (tinfo.flags & CKF_USER_PIN_COUNT_LOW)
430            flags |= NE_SSL_P11PIN_COUNT_LOW;
431        if (tinfo.flags & CKF_USER_PIN_FINAL_TRY)
432            flags |= NE_SSL_P11PIN_FINAL_TRY;
433
434        terminate_string(tinfo.label, sizeof tinfo.label);
435
436        if (prov->pin_fn(prov->pin_data, attempt++,
437                         (char *)sinfo->slot_description,
438                         (char *)tinfo.label, flags, pin)) {
439            return -1;
440        }
441
442        rv = pakchois_login(pks, CKU_USER, (unsigned char *)pin, strlen(pin));
443
444        /* Try to scrub the pin off the stack.  Clever compilers will
445         * probably optimize this away, oh well. */
446        memset(pin, 0, sizeof pin);
447    } while (rv == CKR_PIN_INCORRECT);
448
449    NE_DEBUG(NE_DBG_SSL, "pk11: Login result = %lu\n", rv);
450
451    return (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : -1;
452}
453
454static void pk11_provide(void *userdata, ne_session *sess,
455                         const ne_ssl_dname *const *dnames,
456                         int dncount)
457{
458    ne_ssl_pkcs11_provider *prov = userdata;
459    ck_slot_id_t *slots;
460    unsigned long scount, n;
461
462    if (prov->clicert) {
463        NE_DEBUG(NE_DBG_SSL, "pk11: Using existing clicert.\n");
464        ne_ssl_set_clicert(sess, prov->clicert);
465        return;
466    }
467
468    if (pakchois_get_slot_list(prov->module, 1, NULL, &scount) != CKR_OK
469        || scount == 0) {
470        NE_DEBUG(NE_DBG_SSL, "pk11: No slots.\n");
471        /* TODO: propagate error. */
472        return;
473    }
474
475    slots = ne_malloc(scount * sizeof *slots);
476    if (pakchois_get_slot_list(prov->module, 1, slots, &scount) != CKR_OK)  {
477        ne_free(slots);
478        NE_DEBUG(NE_DBG_SSL, "pk11: Really, no slots?\n");
479        /* TODO: propagate error. */
480        return;
481    }
482
483    NE_DEBUG(NE_DBG_SSL, "pk11: Found %ld slots.\n", scount);
484
485    for (n = 0; n < scount; n++) {
486        pakchois_session_t *pks;
487        ck_rv_t rv;
488        struct ck_slot_info sinfo;
489
490        if (pakchois_get_slot_info(prov->module, slots[n], &sinfo) != CKR_OK) {
491            NE_DEBUG(NE_DBG_SSL, "pk11: GetSlotInfo failed\n");
492            continue;
493        }
494
495        if ((sinfo.flags & CKF_TOKEN_PRESENT) == 0) {
496            NE_DEBUG(NE_DBG_SSL, "pk11: slot empty, ignoring\n");
497            continue;
498        }
499
500        rv = pakchois_open_session(prov->module, slots[n],
501                                   CKF_SERIAL_SESSION,
502                                   NULL, NULL, &pks);
503        if (rv != CKR_OK) {
504            NE_DEBUG(NE_DBG_SSL, "pk11: could not open slot, %ld (%ld: %ld)\n",
505                     rv, n, slots[n]);
506            continue;
507        }
508
509        if (pk11_login(prov, slots[n], pks, &sinfo) == 0) {
510            if (find_client_cert(prov, pks)) {
511                NE_DEBUG(NE_DBG_SSL, "pk11: Setup complete.\n");
512                prov->session = pks;
513                ne_ssl_set_clicert(sess, prov->clicert);
514                ne_free(slots);
515                return;
516            }
517        }
518
519        pakchois_close_session(pks);
520    }
521
522    ne_free(slots);
523}
524
525static int pk11_init(ne_ssl_pkcs11_provider **provider,
526                     pakchois_module_t *module)
527{
528    ne_ssl_pkcs11_provider *prov;
529
530    prov = *provider = ne_calloc(sizeof *prov);
531    prov->module = module;
532    prov->privkey = CK_INVALID_HANDLE;
533
534    return NE_PK11_OK;
535}
536
537int ne_ssl_pkcs11_provider_init(ne_ssl_pkcs11_provider **provider,
538                                const char *name)
539{
540    pakchois_module_t *pm;
541
542    if (pakchois_module_load(&pm, name) == CKR_OK) {
543        return pk11_init(provider, pm);
544    }
545    else {
546        return NE_PK11_FAILED;
547    }
548}
549
550int ne_ssl_pkcs11_nss_provider_init(ne_ssl_pkcs11_provider **provider,
551                                    const char *name, const char *directory,
552                                    const char *cert_prefix,
553                                    const char *key_prefix,
554                                    const char *secmod_db)
555{
556    pakchois_module_t *pm;
557
558    if (pakchois_module_nssload(&pm, name, directory, cert_prefix,
559                                key_prefix, secmod_db) == CKR_OK) {
560        return pk11_init(provider, pm);
561    }
562    else {
563        return NE_PK11_FAILED;
564    }
565}
566
567void ne_ssl_pkcs11_provider_pin(ne_ssl_pkcs11_provider *provider,
568                                ne_ssl_pkcs11_pin_fn fn,
569                                void *userdata)
570{
571    provider->pin_fn = fn;
572    provider->pin_data = userdata;
573}
574
575void ne_ssl_set_pkcs11_provider(ne_session *sess,
576                                ne_ssl_pkcs11_provider *provider)
577{
578#ifdef HAVE_GNUTLS
579    sess->ssl_context->sign_func = pk11_sign_callback;
580    sess->ssl_context->sign_data = provider;
581#endif
582
583    ne_ssl_provide_clicert(sess, pk11_provide, provider);
584}
585
586void ne_ssl_pkcs11_provider_destroy(ne_ssl_pkcs11_provider *prov)
587{
588    if (prov->session) {
589        pakchois_close_session(prov->session);
590    }
591    if (prov->clicert) {
592        ne_ssl_clicert_free(prov->clicert);
593    }
594    pakchois_module_destroy(prov->module);
595    ne_free(prov);
596}
597
598#else /* !HAVE_PAKCHOIS */
599
600int ne_ssl_pkcs11_provider_init(ne_ssl_pkcs11_provider **provider,
601                                const char *name)
602{
603    return NE_PK11_NOTIMPL;
604}
605
606int ne_ssl_pkcs11_nss_provider_init(ne_ssl_pkcs11_provider **provider,
607                                    const char *name, const char *directory,
608                                    const char *cert_prefix,
609                                    const char *key_prefix,
610                                    const char *secmod_db)
611{
612    return NE_PK11_NOTIMPL;
613}
614
615void ne_ssl_pkcs11_provider_destroy(ne_ssl_pkcs11_provider *provider) { }
616
617void ne_ssl_pkcs11_provider_pin(ne_ssl_pkcs11_provider *provider,
618                                ne_ssl_pkcs11_pin_fn fn,
619                                void *userdata) { }
620
621void ne_ssl_set_pkcs11_provider(ne_session *sess,
622                                ne_ssl_pkcs11_provider *provider) { }
623
624#endif /* HAVE_PAKCHOIS */
625
626