"Fossies" - the Fresh Open Source Software Archive

Member "neon-0.31.2/src/ne_pkcs11.c" (20 Jun 2020, 19193 Bytes) of package /linux/www/neon-0.31.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ne_pkcs11.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.31.1_vs_0.31.2.

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