root/source4/heimdal/lib/hx509/ks_p11.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. p11_rsa_public_encrypt
  2. p11_rsa_public_decrypt
  3. p11_rsa_private_encrypt
  4. p11_rsa_private_decrypt
  5. p11_rsa_init
  6. p11_rsa_finish
  7. p11_mech_info
  8. p11_init_slot
  9. p11_get_session
  10. p11_put_session
  11. iterate_entries
  12. getattr_bn
  13. collect_private_key
  14. p11_cert_release
  15. collect_cert
  16. p11_list_keys
  17. p11_init
  18. p11_release_module
  19. p11_free
  20. p11_iter_start
  21. p11_iter
  22. p11_iter_end
  23. p11_printinfo
  24. _hx509_ks_pkcs11_register

   1 /*
   2  * Copyright (c) 2004 - 2008 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #include "hx_locl.h"
  35 RCSID("$Id$");
  36 #ifdef HAVE_DLFCN_H
  37 #include <dlfcn.h>
  38 #endif
  39 
  40 #ifdef HAVE_DLOPEN
  41 
  42 #include "pkcs11.h"
  43 
  44 struct p11_slot {
  45     int flags;
  46 #define P11_SESSION             1
  47 #define P11_SESSION_IN_USE      2
  48 #define P11_LOGIN_REQ           4
  49 #define P11_LOGIN_DONE          8
  50 #define P11_TOKEN_PRESENT       16
  51     CK_SESSION_HANDLE session;
  52     CK_SLOT_ID id;
  53     CK_BBOOL token;
  54     char *name;
  55     hx509_certs certs;
  56     char *pin;
  57     struct {
  58         CK_MECHANISM_TYPE_PTR list;
  59         CK_ULONG num;
  60         CK_MECHANISM_INFO_PTR *infos;
  61     } mechs;
  62 };
  63 
  64 struct p11_module {
  65     void *dl_handle;
  66     CK_FUNCTION_LIST_PTR funcs;
  67     CK_ULONG num_slots;
  68     unsigned int ref;
  69     struct p11_slot *slot;
  70 };
  71 
  72 #define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args
  73 
  74 static int p11_get_session(hx509_context,
  75                            struct p11_module *,
  76                            struct p11_slot *,
  77                            hx509_lock,
  78                            CK_SESSION_HANDLE *);
  79 static int p11_put_session(struct p11_module *,
  80                            struct p11_slot *,
  81                            CK_SESSION_HANDLE);
  82 static void p11_release_module(struct p11_module *);
  83 
  84 static int p11_list_keys(hx509_context,
  85                          struct p11_module *,
  86                          struct p11_slot *,
  87                          CK_SESSION_HANDLE,
  88                          hx509_lock,
  89                          hx509_certs *);
  90 
  91 /*
  92  *
  93  */
  94 
  95 struct p11_rsa {
  96     struct p11_module *p;
  97     struct p11_slot *slot;
  98     CK_OBJECT_HANDLE private_key;
  99     CK_OBJECT_HANDLE public_key;
 100 };
 101 
 102 static int
 103 p11_rsa_public_encrypt(int flen,
     /* [<][>][^][v][top][bottom][index][help] */
 104                        const unsigned char *from,
 105                        unsigned char *to,
 106                        RSA *rsa,
 107                        int padding)
 108 {
 109     return -1;
 110 }
 111 
 112 static int
 113 p11_rsa_public_decrypt(int flen,
     /* [<][>][^][v][top][bottom][index][help] */
 114                        const unsigned char *from,
 115                        unsigned char *to,
 116                        RSA *rsa,
 117                        int padding)
 118 {
 119     return -1;
 120 }
 121 
 122 
 123 static int
 124 p11_rsa_private_encrypt(int flen,
     /* [<][>][^][v][top][bottom][index][help] */
 125                         const unsigned char *from,
 126                         unsigned char *to,
 127                         RSA *rsa,
 128                         int padding)
 129 {
 130     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
 131     CK_OBJECT_HANDLE key = p11rsa->private_key;
 132     CK_SESSION_HANDLE session;
 133     CK_MECHANISM mechanism;
 134     CK_ULONG ck_sigsize;
 135     int ret;
 136 
 137     if (padding != RSA_PKCS1_PADDING)
 138         return -1;
 139 
 140     memset(&mechanism, 0, sizeof(mechanism));
 141     mechanism.mechanism = CKM_RSA_PKCS;
 142 
 143     ck_sigsize = RSA_size(rsa);
 144 
 145     ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
 146     if (ret)
 147         return -1;
 148 
 149     ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key));
 150     if (ret != CKR_OK) {
 151         p11_put_session(p11rsa->p, p11rsa->slot, session);
 152         return -1;
 153     }
 154 
 155     ret = P11FUNC(p11rsa->p, Sign,
 156                   (session, (CK_BYTE *)from, flen, to, &ck_sigsize));
 157     p11_put_session(p11rsa->p, p11rsa->slot, session);
 158     if (ret != CKR_OK)
 159         return -1;
 160 
 161     return ck_sigsize;
 162 }
 163 
 164 static int
 165 p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
     /* [<][>][^][v][top][bottom][index][help] */
 166                         RSA * rsa, int padding)
 167 {
 168     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
 169     CK_OBJECT_HANDLE key = p11rsa->private_key;
 170     CK_SESSION_HANDLE session;
 171     CK_MECHANISM mechanism;
 172     CK_ULONG ck_sigsize;
 173     int ret;
 174 
 175     if (padding != RSA_PKCS1_PADDING)
 176         return -1;
 177 
 178     memset(&mechanism, 0, sizeof(mechanism));
 179     mechanism.mechanism = CKM_RSA_PKCS;
 180 
 181     ck_sigsize = RSA_size(rsa);
 182 
 183     ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session);
 184     if (ret)
 185         return -1;
 186 
 187     ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key));
 188     if (ret != CKR_OK) {
 189         p11_put_session(p11rsa->p, p11rsa->slot, session);
 190         return -1;
 191     }
 192 
 193     ret = P11FUNC(p11rsa->p, Decrypt,
 194                   (session, (CK_BYTE *)from, flen, to, &ck_sigsize));
 195     p11_put_session(p11rsa->p, p11rsa->slot, session);
 196     if (ret != CKR_OK)
 197         return -1;
 198 
 199     return ck_sigsize;
 200 }
 201 
 202 static int
 203 p11_rsa_init(RSA *rsa)
     /* [<][>][^][v][top][bottom][index][help] */
 204 {
 205     return 1;
 206 }
 207 
 208 static int
 209 p11_rsa_finish(RSA *rsa)
     /* [<][>][^][v][top][bottom][index][help] */
 210 {
 211     struct p11_rsa *p11rsa = RSA_get_app_data(rsa);
 212     p11_release_module(p11rsa->p);
 213     free(p11rsa);
 214     return 1;
 215 }
 216 
 217 static const RSA_METHOD p11_rsa_pkcs1_method = {
 218     "hx509 PKCS11 PKCS#1 RSA",
 219     p11_rsa_public_encrypt,
 220     p11_rsa_public_decrypt,
 221     p11_rsa_private_encrypt,
 222     p11_rsa_private_decrypt,
 223     NULL,
 224     NULL,
 225     p11_rsa_init,
 226     p11_rsa_finish,
 227     0,
 228     NULL,
 229     NULL,
 230     NULL
 231 };
 232 
 233 /*
 234  *
 235  */
 236 
 237 static int
 238 p11_mech_info(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 239               struct p11_module *p,
 240               struct p11_slot *slot,
 241               int num)
 242 {
 243     CK_ULONG i;
 244     int ret;
 245 
 246     ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i));
 247     if (ret) {
 248         hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
 249                                "Failed to get mech list count for slot %d",
 250                                num);
 251         return HX509_PKCS11_NO_MECH;
 252     }
 253     if (i == 0) {
 254         hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
 255                                "no mech supported for slot %d", num);
 256         return HX509_PKCS11_NO_MECH;
 257     }
 258     slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0]));
 259     if (slot->mechs.list == NULL) {
 260         hx509_set_error_string(context, 0, ENOMEM,
 261                                "out of memory");
 262         return ENOMEM;
 263     }
 264     slot->mechs.num = i;
 265     ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i));
 266     if (ret) {
 267         hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
 268                                "Failed to get mech list for slot %d",
 269                                num);
 270         return HX509_PKCS11_NO_MECH;
 271     }
 272     assert(i == slot->mechs.num);
 273 
 274     slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos));
 275     if (slot->mechs.list == NULL) {
 276         hx509_set_error_string(context, 0, ENOMEM,
 277                                "out of memory");
 278         return ENOMEM;
 279     }
 280 
 281     for (i = 0; i < slot->mechs.num; i++) {
 282         slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0])));
 283         if (slot->mechs.infos[i] == NULL) {
 284             hx509_set_error_string(context, 0, ENOMEM,
 285                                    "out of memory");
 286             return ENOMEM;
 287         }
 288         ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i],
 289                                             slot->mechs.infos[i]));
 290         if (ret) {
 291             hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH,
 292                                    "Failed to get mech info for slot %d",
 293                                    num);
 294             return HX509_PKCS11_NO_MECH;
 295         }
 296     }
 297 
 298     return 0;
 299 }
 300 
 301 static int
 302 p11_init_slot(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 303               struct p11_module *p,
 304               hx509_lock lock,
 305               CK_SLOT_ID id,
 306               int num,
 307               struct p11_slot *slot)
 308 {
 309     CK_SESSION_HANDLE session;
 310     CK_SLOT_INFO slot_info;
 311     CK_TOKEN_INFO token_info;
 312     size_t i;
 313     int ret;
 314 
 315     slot->certs = NULL;
 316     slot->id = id;
 317 
 318     ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info));
 319     if (ret) {
 320         hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
 321                                "Failed to init PKCS11 slot %d",
 322                                num);
 323         return HX509_PKCS11_TOKEN_CONFUSED;
 324     }
 325 
 326     for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) {
 327         char c = slot_info.slotDescription[i];
 328         if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0')
 329             continue;
 330         i++;
 331         break;
 332     }
 333 
 334     asprintf(&slot->name, "%.*s",
 335              i, slot_info.slotDescription);
 336 
 337     if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0)
 338         return 0;
 339 
 340     ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info));
 341     if (ret) {
 342         hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN,
 343                                "Failed to init PKCS11 slot %d "
 344                                "with error 0x08x",
 345                                num, ret);
 346         return HX509_PKCS11_NO_TOKEN;
 347     }
 348     slot->flags |= P11_TOKEN_PRESENT;
 349 
 350     if (token_info.flags & CKF_LOGIN_REQUIRED)
 351         slot->flags |= P11_LOGIN_REQ;
 352 
 353     ret = p11_get_session(context, p, slot, lock, &session);
 354     if (ret)
 355         return ret;
 356 
 357     ret = p11_mech_info(context, p, slot, num);
 358     if (ret)
 359         goto out;
 360 
 361     ret = p11_list_keys(context, p, slot, session, lock, &slot->certs);
 362  out:
 363     p11_put_session(p, slot, session);
 364 
 365     return ret;
 366 }
 367 
 368 static int
 369 p11_get_session(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 370                 struct p11_module *p,
 371                 struct p11_slot *slot,
 372                 hx509_lock lock,
 373                 CK_SESSION_HANDLE *psession)
 374 {
 375     CK_RV ret;
 376 
 377     if (slot->flags & P11_SESSION_IN_USE)
 378         _hx509_abort("slot already in session");
 379 
 380     if (slot->flags & P11_SESSION) {
 381         slot->flags |= P11_SESSION_IN_USE;
 382         *psession = slot->session;
 383         return 0;
 384     }
 385 
 386     ret = P11FUNC(p, OpenSession, (slot->id,
 387                                    CKF_SERIAL_SESSION,
 388                                    NULL,
 389                                    NULL,
 390                                    &slot->session));
 391     if (ret != CKR_OK) {
 392         if (context)
 393             hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION,
 394                                    "Failed to OpenSession for slot id %d "
 395                                    "with error: 0x%08x",
 396                                    (int)slot->id, ret);
 397         return HX509_PKCS11_OPEN_SESSION;
 398     }
 399 
 400     slot->flags |= P11_SESSION;
 401 
 402     /*
 403      * If we have have to login, and haven't tried before and have a
 404      * prompter or known to work pin code.
 405      *
 406      * This code is very conversative and only uses the prompter in
 407      * the hx509_lock, the reason is that it's bad to try many
 408      * passwords on a pkcs11 token, it might lock up and have to be
 409      * unlocked by a administrator.
 410      *
 411      * XXX try harder to not use pin several times on the same card.
 412      */
 413 
 414     if (   (slot->flags & P11_LOGIN_REQ)
 415         && (slot->flags & P11_LOGIN_DONE) == 0
 416         && (lock || slot->pin))
 417     {
 418         hx509_prompt prompt;
 419         char pin[20];
 420         char *str;
 421 
 422         if (slot->pin == NULL) {
 423 
 424             memset(&prompt, 0, sizeof(prompt));
 425 
 426             asprintf(&str, "PIN code for %s: ", slot->name);
 427             prompt.prompt = str;
 428             prompt.type = HX509_PROMPT_TYPE_PASSWORD;
 429             prompt.reply.data = pin;
 430             prompt.reply.length = sizeof(pin);
 431         
 432             ret = hx509_lock_prompt(lock, &prompt);
 433             if (ret) {
 434                 free(str);
 435                 if (context)
 436                     hx509_set_error_string(context, 0, ret,
 437                                            "Failed to get pin code for slot "
 438                                            "id %d with error: %d",
 439                                            (int)slot->id, ret);
 440                 return ret;
 441             }
 442             free(str);
 443         } else {
 444             strlcpy(pin, slot->pin, sizeof(pin));
 445         }
 446 
 447         ret = P11FUNC(p, Login, (slot->session, CKU_USER,
 448                                  (unsigned char*)pin, strlen(pin)));
 449         if (ret != CKR_OK) {
 450             if (context)
 451                 hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN,
 452                                        "Failed to login on slot id %d "
 453                                        "with error: 0x%08x",
 454                                        (int)slot->id, ret);
 455             return HX509_PKCS11_LOGIN;
 456         } else
 457             slot->flags |= P11_LOGIN_DONE;
 458 
 459         if (slot->pin == NULL) {
 460             slot->pin = strdup(pin);
 461             if (slot->pin == NULL) {
 462                 if (context)
 463                     hx509_set_error_string(context, 0, ENOMEM,
 464                                            "out of memory");
 465                 return ENOMEM;
 466             }
 467         }
 468     } else
 469         slot->flags |= P11_LOGIN_DONE;
 470 
 471     slot->flags |= P11_SESSION_IN_USE;
 472 
 473     *psession = slot->session;
 474 
 475     return 0;
 476 }
 477 
 478 static int
 479 p11_put_session(struct p11_module *p,
     /* [<][>][^][v][top][bottom][index][help] */
 480                 struct p11_slot *slot,
 481                 CK_SESSION_HANDLE session)
 482 {
 483     if ((slot->flags & P11_SESSION_IN_USE) == 0)
 484         _hx509_abort("slot not in session");
 485     slot->flags &= ~P11_SESSION_IN_USE;
 486 
 487     return 0;
 488 }
 489 
 490 static int
 491 iterate_entries(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 492                 struct p11_module *p, struct p11_slot *slot,
 493                 CK_SESSION_HANDLE session,
 494                 CK_ATTRIBUTE *search_data, int num_search_data,
 495                 CK_ATTRIBUTE *query, int num_query,
 496                 int (*func)(hx509_context,
 497                             struct p11_module *, struct p11_slot *,
 498                             CK_SESSION_HANDLE session,
 499                             CK_OBJECT_HANDLE object,
 500                             void *, CK_ATTRIBUTE *, int), void *ptr)
 501 {
 502     CK_OBJECT_HANDLE object;
 503     CK_ULONG object_count;
 504     int ret, ret2, i;
 505 
 506     ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data));
 507     if (ret != CKR_OK) {
 508         return -1;
 509     }
 510     while (1) {
 511         ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count));
 512         if (ret != CKR_OK) {
 513             return -1;
 514         }
 515         if (object_count == 0)
 516             break;
 517         
 518         for (i = 0; i < num_query; i++)
 519             query[i].pValue = NULL;
 520 
 521         ret = P11FUNC(p, GetAttributeValue,
 522                       (session, object, query, num_query));
 523         if (ret != CKR_OK) {
 524             return -1;
 525         }
 526         for (i = 0; i < num_query; i++) {
 527             query[i].pValue = malloc(query[i].ulValueLen);
 528             if (query[i].pValue == NULL) {
 529                 ret = ENOMEM;
 530                 goto out;
 531             }
 532         }
 533         ret = P11FUNC(p, GetAttributeValue,
 534                       (session, object, query, num_query));
 535         if (ret != CKR_OK) {
 536             ret = -1;
 537             goto out;
 538         }
 539         
 540         ret = (*func)(context, p, slot, session, object, ptr, query, num_query);
 541         if (ret)
 542             goto out;
 543 
 544         for (i = 0; i < num_query; i++) {
 545             if (query[i].pValue)
 546                 free(query[i].pValue);
 547             query[i].pValue = NULL;
 548         }
 549     }
 550  out:
 551 
 552     for (i = 0; i < num_query; i++) {
 553         if (query[i].pValue)
 554             free(query[i].pValue);
 555         query[i].pValue = NULL;
 556     }
 557 
 558     ret2 = P11FUNC(p, FindObjectsFinal, (session));
 559     if (ret2 != CKR_OK) {
 560         return ret2;
 561     }
 562 
 563     return ret;
 564 }
 565                 
 566 static BIGNUM *
 567 getattr_bn(struct p11_module *p,
     /* [<][>][^][v][top][bottom][index][help] */
 568            struct p11_slot *slot,
 569            CK_SESSION_HANDLE session,
 570            CK_OBJECT_HANDLE object,
 571            unsigned int type)
 572 {
 573     CK_ATTRIBUTE query;
 574     BIGNUM *bn;
 575     int ret;
 576 
 577     query.type = type;
 578     query.pValue = NULL;
 579     query.ulValueLen = 0;
 580 
 581     ret = P11FUNC(p, GetAttributeValue,
 582                   (session, object, &query, 1));
 583     if (ret != CKR_OK)
 584         return NULL;
 585 
 586     query.pValue = malloc(query.ulValueLen);
 587 
 588     ret = P11FUNC(p, GetAttributeValue,
 589                   (session, object, &query, 1));
 590     if (ret != CKR_OK) {
 591         free(query.pValue);
 592         return NULL;
 593     }
 594     bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL);
 595     free(query.pValue);
 596 
 597     return bn;
 598 }
 599 
 600 static int
 601 collect_private_key(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 602                     struct p11_module *p, struct p11_slot *slot,
 603                     CK_SESSION_HANDLE session,
 604                     CK_OBJECT_HANDLE object,
 605                     void *ptr, CK_ATTRIBUTE *query, int num_query)
 606 {
 607     struct hx509_collector *collector = ptr;
 608     hx509_private_key key;
 609     heim_octet_string localKeyId;
 610     int ret;
 611     RSA *rsa;
 612     struct p11_rsa *p11rsa;
 613 
 614     localKeyId.data = query[0].pValue;
 615     localKeyId.length = query[0].ulValueLen;
 616 
 617     ret = _hx509_private_key_init(&key, NULL, NULL);
 618     if (ret)
 619         return ret;
 620 
 621     rsa = RSA_new();
 622     if (rsa == NULL)
 623         _hx509_abort("out of memory");
 624 
 625     /*
 626      * The exponent and modulus should always be present according to
 627      * the pkcs11 specification, but some smartcards leaves it out,
 628      * let ignore any failure to fetch it.
 629      */
 630     rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS);
 631     rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT);
 632 
 633     p11rsa = calloc(1, sizeof(*p11rsa));
 634     if (p11rsa == NULL)
 635         _hx509_abort("out of memory");
 636 
 637     p11rsa->p = p;
 638     p11rsa->slot = slot;
 639     p11rsa->private_key = object;
 640 
 641     if (p->ref == 0)
 642         _hx509_abort("pkcs11 ref == 0 on alloc");
 643     p->ref++;
 644     if (p->ref == UINT_MAX)
 645         _hx509_abort("pkcs11 ref == UINT_MAX on alloc");
 646 
 647     RSA_set_method(rsa, &p11_rsa_pkcs1_method);
 648     ret = RSA_set_app_data(rsa, p11rsa);
 649     if (ret != 1)
 650         _hx509_abort("RSA_set_app_data");
 651 
 652     _hx509_private_key_assign_rsa(key, rsa);
 653 
 654     ret = _hx509_collector_private_key_add(context,
 655                                            collector,
 656                                            hx509_signature_rsa(),
 657                                            key,
 658                                            NULL,
 659                                            &localKeyId);
 660 
 661     if (ret) {
 662         _hx509_private_key_free(&key);
 663         return ret;
 664     }
 665     return 0;
 666 }
 667 
 668 static void
 669 p11_cert_release(hx509_cert cert, void *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 670 {
 671     struct p11_module *p = ctx;
 672     p11_release_module(p);
 673 }
 674 
 675 
 676 static int
 677 collect_cert(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 678              struct p11_module *p, struct p11_slot *slot,
 679              CK_SESSION_HANDLE session,
 680              CK_OBJECT_HANDLE object,
 681              void *ptr, CK_ATTRIBUTE *query, int num_query)
 682 {
 683     struct hx509_collector *collector = ptr;
 684     hx509_cert cert;
 685     int ret;
 686 
 687     if ((CK_LONG)query[0].ulValueLen == -1 ||
 688         (CK_LONG)query[1].ulValueLen == -1)
 689     {
 690         return 0;
 691     }
 692 
 693     ret = hx509_cert_init_data(context, query[1].pValue,
 694                                query[1].ulValueLen, &cert);
 695     if (ret)
 696         return ret;
 697 
 698     if (p->ref == 0)
 699         _hx509_abort("pkcs11 ref == 0 on alloc");
 700     p->ref++;
 701     if (p->ref == UINT_MAX)
 702         _hx509_abort("pkcs11 ref to high");
 703 
 704     _hx509_cert_set_release(cert, p11_cert_release, p);
 705 
 706     {
 707         heim_octet_string data;
 708         
 709         data.data = query[0].pValue;
 710         data.length = query[0].ulValueLen;
 711         
 712         _hx509_set_cert_attribute(context,
 713                                   cert,
 714                                   oid_id_pkcs_9_at_localKeyId(),
 715                                   &data);
 716     }
 717 
 718     if ((CK_LONG)query[2].ulValueLen != -1) {
 719         char *str;
 720 
 721         asprintf(&str, "%.*s",
 722                  (int)query[2].ulValueLen, (char *)query[2].pValue);
 723         if (str) {
 724             hx509_cert_set_friendly_name(cert, str);
 725             free(str);
 726         }
 727     }
 728 
 729     ret = _hx509_collector_certs_add(context, collector, cert);
 730     hx509_cert_free(cert);
 731 
 732     return ret;
 733 }
 734 
 735 
 736 static int
 737 p11_list_keys(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 738               struct p11_module *p,
 739               struct p11_slot *slot,
 740               CK_SESSION_HANDLE session,
 741               hx509_lock lock,
 742               hx509_certs *certs)
 743 {
 744     struct hx509_collector *collector;
 745     CK_OBJECT_CLASS key_class;
 746     CK_ATTRIBUTE search_data[] = {
 747         {CKA_CLASS, NULL, 0},
 748     };
 749     CK_ATTRIBUTE query_data[3] = {
 750         {CKA_ID, NULL, 0},
 751         {CKA_VALUE, NULL, 0},
 752         {CKA_LABEL, NULL, 0}
 753     };
 754     int ret;
 755 
 756     search_data[0].pValue = &key_class;
 757     search_data[0].ulValueLen = sizeof(key_class);
 758 
 759     if (lock == NULL)
 760         lock = _hx509_empty_lock;
 761 
 762     ret = _hx509_collector_alloc(context, lock, &collector);
 763     if (ret)
 764         return ret;
 765 
 766     key_class = CKO_PRIVATE_KEY;
 767     ret = iterate_entries(context, p, slot, session,
 768                           search_data, 1,
 769                           query_data, 1,
 770                           collect_private_key, collector);
 771     if (ret)
 772         goto out;
 773 
 774     key_class = CKO_CERTIFICATE;
 775     ret = iterate_entries(context, p, slot, session,
 776                           search_data, 1,
 777                           query_data, 3,
 778                           collect_cert, collector);
 779     if (ret)
 780         goto out;
 781 
 782     ret = _hx509_collector_collect_certs(context, collector, &slot->certs);
 783 
 784 out:
 785     _hx509_collector_free(collector);
 786 
 787     return ret;
 788 }
 789 
 790 
 791 static int
 792 p11_init(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 793          hx509_certs certs, void **data, int flags,
 794          const char *residue, hx509_lock lock)
 795 {
 796     CK_C_GetFunctionList getFuncs;
 797     struct p11_module *p;
 798     char *list, *str;
 799     int ret;
 800 
 801     *data = NULL;
 802 
 803     list = strdup(residue);
 804     if (list == NULL)
 805         return ENOMEM;
 806 
 807     p = calloc(1, sizeof(*p));
 808     if (p == NULL) {
 809         free(list);
 810         return ENOMEM;
 811     }
 812 
 813     p->ref = 1;
 814 
 815     str = strchr(list, ',');
 816     if (str)
 817         *str++ = '\0';
 818     while (str) {
 819         char *strnext;
 820         strnext = strchr(str, ',');
 821         if (strnext)
 822             *strnext++ = '\0';
 823 #if 0
 824         if (strncasecmp(str, "slot=", 5) == 0)
 825             p->selected_slot = atoi(str + 5);
 826 #endif
 827         str = strnext;
 828     }
 829 
 830     p->dl_handle = dlopen(list, RTLD_NOW);
 831     free(list);
 832     if (p->dl_handle == NULL) {
 833         ret = HX509_PKCS11_LOAD;
 834         hx509_set_error_string(context, 0, ret,
 835                                "Failed to open %s: %s", list, dlerror());
 836         goto out;
 837     }
 838 
 839     getFuncs = dlsym(p->dl_handle, "C_GetFunctionList");
 840     if (getFuncs == NULL) {
 841         ret = HX509_PKCS11_LOAD;
 842         hx509_set_error_string(context, 0, ret,
 843                                "C_GetFunctionList missing in %s: %s",
 844                                list, dlerror());
 845         goto out;
 846     }
 847 
 848     ret = (*getFuncs)(&p->funcs);
 849     if (ret) {
 850         ret = HX509_PKCS11_LOAD;
 851         hx509_set_error_string(context, 0, ret,
 852                                "C_GetFunctionList failed in %s", list);
 853         goto out;
 854     }
 855 
 856     ret = P11FUNC(p, Initialize, (NULL_PTR));
 857     if (ret != CKR_OK) {
 858         ret = HX509_PKCS11_TOKEN_CONFUSED;
 859         hx509_set_error_string(context, 0, ret,
 860                                "Failed initialize the PKCS11 module");
 861         goto out;
 862     }
 863 
 864     ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots));
 865     if (ret) {
 866         ret = HX509_PKCS11_TOKEN_CONFUSED;
 867         hx509_set_error_string(context, 0, ret,
 868                                "Failed to get number of PKCS11 slots");
 869         goto out;
 870     }
 871 
 872    if (p->num_slots == 0) {
 873         ret = HX509_PKCS11_NO_SLOT;
 874         hx509_set_error_string(context, 0, ret,
 875                                "Selected PKCS11 module have no slots");
 876         goto out;
 877    }
 878 
 879 
 880     {
 881         CK_SLOT_ID_PTR slot_ids;
 882         int i, num_tokens = 0;
 883 
 884         slot_ids = malloc(p->num_slots * sizeof(*slot_ids));
 885         if (slot_ids == NULL) {
 886             hx509_clear_error_string(context);
 887             ret = ENOMEM;
 888             goto out;
 889         }
 890 
 891         ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots));
 892         if (ret) {
 893             free(slot_ids);
 894             hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED,
 895                                    "Failed getting slot-list from "
 896                                    "PKCS11 module");
 897             ret = HX509_PKCS11_TOKEN_CONFUSED;
 898             goto out;
 899         }
 900 
 901         p->slot = calloc(p->num_slots, sizeof(p->slot[0]));
 902         if (p->slot == NULL) {
 903             free(slot_ids);
 904             hx509_set_error_string(context, 0, ENOMEM,
 905                                    "Failed to get memory for slot-list");
 906             ret = ENOMEM;
 907             goto out;
 908         }
 909                         
 910         for (i = 0; i < p->num_slots; i++) {
 911             ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]);
 912             if (ret)
 913                 break;
 914             if (p->slot[i].flags & P11_TOKEN_PRESENT)
 915                 num_tokens++;
 916         }
 917         free(slot_ids);
 918         if (ret)
 919             goto out;
 920         if (num_tokens == 0) {
 921             ret = HX509_PKCS11_NO_TOKEN;
 922             goto out;
 923         }
 924     }
 925 
 926     *data = p;
 927 
 928     return 0;
 929  out:
 930     p11_release_module(p);
 931     return ret;
 932 }
 933 
 934 static void
 935 p11_release_module(struct p11_module *p)
     /* [<][>][^][v][top][bottom][index][help] */
 936 {
 937     int i;
 938 
 939     if (p->ref == 0)
 940         _hx509_abort("pkcs11 ref to low");
 941     if (--p->ref > 0)
 942         return;
 943 
 944     for (i = 0; i < p->num_slots; i++) {
 945         if (p->slot[i].flags & P11_SESSION_IN_USE)
 946             _hx509_abort("pkcs11 module release while session in use");
 947         if (p->slot[i].flags & P11_SESSION) {
 948             int ret;
 949 
 950             ret = P11FUNC(p, CloseSession, (p->slot[i].session));
 951             if (ret != CKR_OK)
 952                 ;
 953         }
 954 
 955         if (p->slot[i].name)
 956             free(p->slot[i].name);
 957         if (p->slot[i].pin) {
 958             memset(p->slot[i].pin, 0, strlen(p->slot[i].pin));
 959             free(p->slot[i].pin);
 960         }
 961         if (p->slot[i].mechs.num) {
 962             free(p->slot[i].mechs.list);
 963 
 964             if (p->slot[i].mechs.infos) {
 965                 int j;
 966 
 967                 for (j = 0 ; j < p->slot[i].mechs.num ; j++)
 968                     free(p->slot[i].mechs.infos[j]);
 969                 free(p->slot[i].mechs.infos);
 970             }
 971         }
 972     }
 973     free(p->slot);
 974 
 975     if (p->funcs)
 976         P11FUNC(p, Finalize, (NULL));
 977 
 978     if (p->dl_handle)
 979         dlclose(p->dl_handle);
 980 
 981     memset(p, 0, sizeof(*p));
 982     free(p);
 983 }
 984 
 985 static int
 986 p11_free(hx509_certs certs, void *data)
     /* [<][>][^][v][top][bottom][index][help] */
 987 {
 988     struct p11_module *p = data;
 989     int i;
 990 
 991     for (i = 0; i < p->num_slots; i++) {
 992         if (p->slot[i].certs)
 993             hx509_certs_free(&p->slot[i].certs);
 994     }
 995     p11_release_module(p);
 996     return 0;
 997 }
 998 
 999 struct p11_cursor {
1000     hx509_certs certs;
1001     void *cursor;
1002 };
1003 
1004 static int
1005 p11_iter_start(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1006                hx509_certs certs, void *data, void **cursor)
1007 {
1008     struct p11_module *p = data;
1009     struct p11_cursor *c;
1010     int ret, i;
1011 
1012     c = malloc(sizeof(*c));
1013     if (c == NULL) {
1014         hx509_clear_error_string(context);
1015         return ENOMEM;
1016     }
1017     ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs);
1018     if (ret) {
1019         free(c);
1020         return ret;
1021     }
1022 
1023     for (i = 0 ; i < p->num_slots; i++) {
1024         if (p->slot[i].certs == NULL)
1025             continue;
1026         ret = hx509_certs_merge(context, c->certs, p->slot[i].certs);
1027         if (ret) {
1028             hx509_certs_free(&c->certs);
1029             free(c);
1030             return ret;
1031         }
1032     }
1033 
1034     ret = hx509_certs_start_seq(context, c->certs, &c->cursor);
1035     if (ret) {
1036         hx509_certs_free(&c->certs);
1037         free(c);
1038         return 0;
1039     }
1040     *cursor = c;
1041 
1042     return 0;
1043 }
1044 
1045 static int
1046 p11_iter(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1047          hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
1048 {
1049     struct p11_cursor *c = cursor;
1050     return hx509_certs_next_cert(context, c->certs, c->cursor, cert);
1051 }
1052 
1053 static int
1054 p11_iter_end(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1055              hx509_certs certs, void *data, void *cursor)
1056 {
1057     struct p11_cursor *c = cursor;
1058     int ret;
1059     ret = hx509_certs_end_seq(context, c->certs, c->cursor);
1060     hx509_certs_free(&c->certs);
1061     free(c);
1062     return ret;
1063 }
1064 
1065 #define MECHFLAG(x) { "unknown-flag-" #x, x }
1066 static struct units mechflags[] = {
1067         MECHFLAG(0x80000000),
1068         MECHFLAG(0x40000000),
1069         MECHFLAG(0x20000000),
1070         MECHFLAG(0x10000000),
1071         MECHFLAG(0x08000000),
1072         MECHFLAG(0x04000000),
1073         {"ec-compress",         0x2000000 },
1074         {"ec-uncompress",       0x1000000 },
1075         {"ec-namedcurve",       0x0800000 },
1076         {"ec-ecparameters",     0x0400000 },
1077         {"ec-f-2m",             0x0200000 },
1078         {"ec-f-p",              0x0100000 },
1079         {"derive",              0x0080000 },
1080         {"unwrap",              0x0040000 },
1081         {"wrap",                0x0020000 },
1082         {"genereate-key-pair",  0x0010000 },
1083         {"generate",            0x0008000 },
1084         {"verify-recover",      0x0004000 },
1085         {"verify",              0x0002000 },
1086         {"sign-recover",        0x0001000 },
1087         {"sign",                0x0000800 },
1088         {"digest",              0x0000400 },
1089         {"decrypt",             0x0000200 },
1090         {"encrypt",             0x0000100 },
1091         MECHFLAG(0x00080),
1092         MECHFLAG(0x00040),
1093         MECHFLAG(0x00020),
1094         MECHFLAG(0x00010),
1095         MECHFLAG(0x00008),
1096         MECHFLAG(0x00004),
1097         MECHFLAG(0x00002),
1098         {"hw",                  0x0000001 },
1099         { NULL,                 0x0000000 }
1100 };
1101 #undef MECHFLAG
1102 
1103 static int
1104 p11_printinfo(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1105               hx509_certs certs,
1106               void *data,
1107               int (*func)(void *, const char *),
1108               void *ctx)
1109 {
1110     struct p11_module *p = data;
1111     int i, j;
1112 
1113     _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s",
1114                      p->num_slots, p->num_slots > 1 ? "s" : "");
1115 
1116     for (i = 0; i < p->num_slots; i++) {
1117         struct p11_slot *s = &p->slot[i];
1118 
1119         _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x",
1120                          i, (int)s->id, s->name, s->flags);
1121 
1122         _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu",
1123                          (unsigned long)s->mechs.num);
1124         for (j = 0; j < s->mechs.num; j++) {
1125             const char *mechname = "unknown";
1126             char flags[256], unknownname[40];
1127 #define MECHNAME(s,n) case s: mechname = n; break
1128             switch(s->mechs.list[j]) {
1129                 MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen");
1130                 MECHNAME(CKM_RSA_PKCS, "rsa-pkcs");
1131                 MECHNAME(CKM_RSA_X_509, "rsa-x-509");
1132                 MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs");
1133                 MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs");
1134                 MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs");
1135                 MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs");
1136                 MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs");
1137                 MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs");
1138                 MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep");
1139                 MECHNAME(CKM_SHA512_HMAC, "sha512-hmac");
1140                 MECHNAME(CKM_SHA512, "sha512");
1141                 MECHNAME(CKM_SHA384_HMAC, "sha384-hmac");
1142                 MECHNAME(CKM_SHA384, "sha384");
1143                 MECHNAME(CKM_SHA256_HMAC, "sha256-hmac");
1144                 MECHNAME(CKM_SHA256, "sha256");
1145                 MECHNAME(CKM_SHA_1, "sha1");
1146                 MECHNAME(CKM_MD5, "md5");
1147                 MECHNAME(CKM_MD2, "md2");
1148                 MECHNAME(CKM_RIPEMD160, "ripemd-160");
1149                 MECHNAME(CKM_DES_ECB, "des-ecb");
1150                 MECHNAME(CKM_DES_CBC, "des-cbc");
1151                 MECHNAME(CKM_AES_ECB, "aes-ecb");
1152                 MECHNAME(CKM_AES_CBC, "aes-cbc");
1153                 MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen");
1154             default:
1155                 snprintf(unknownname, sizeof(unknownname),
1156                          "unknown-mech-%lu",
1157                          (unsigned long)s->mechs.list[j]);
1158                 mechname = unknownname;
1159                 break;
1160             }
1161 #undef MECHNAME
1162             unparse_flags(s->mechs.infos[j]->flags, mechflags,
1163                           flags, sizeof(flags));
1164 
1165             _hx509_pi_printf(func, ctx, "  %s: %s", mechname, flags);
1166         }
1167     }
1168 
1169     return 0;
1170 }
1171 
1172 static struct hx509_keyset_ops keyset_pkcs11 = {
1173     "PKCS11",
1174     0,
1175     p11_init,
1176     NULL,
1177     p11_free,
1178     NULL,
1179     NULL,
1180     p11_iter_start,
1181     p11_iter,
1182     p11_iter_end,
1183     p11_printinfo
1184 };
1185 
1186 #endif /* HAVE_DLOPEN */
1187 
1188 void
1189 _hx509_ks_pkcs11_register(hx509_context context)
     /* [<][>][^][v][top][bottom][index][help] */
1190 {
1191 #ifdef HAVE_DLOPEN
1192     _hx509_ks_register(context, &keyset_pkcs11);
1193 #endif
1194 }

/* [<][>][^][v][top][bottom][index][help] */