]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/heimdal/lib/hx509/softp11.c
heimdal: Fix multiple security vulnerabilities
[FreeBSD/FreeBSD.git] / crypto / heimdal / lib / hx509 / softp11.c
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 #define CRYPTOKI_EXPORTS 1
35
36 #include "hx_locl.h"
37 #include "pkcs11.h"
38
39 #define OBJECT_ID_MASK          0xfff
40 #define HANDLE_OBJECT_ID(h)     ((h) & OBJECT_ID_MASK)
41 #define OBJECT_ID(obj)          HANDLE_OBJECT_ID((obj)->object_handle)
42
43 #ifndef HAVE_RANDOM
44 #define random() rand()
45 #define srandom(s) srand(s)
46 #endif
47
48 #ifdef _WIN32
49 #include <shlobj.h>
50 #endif
51
52 struct st_attr {
53     CK_ATTRIBUTE attribute;
54     int secret;
55 };
56
57 struct st_object {
58     CK_OBJECT_HANDLE object_handle;
59     struct st_attr *attrs;
60     int num_attributes;
61     hx509_cert cert;
62 };
63
64 static struct soft_token {
65     CK_VOID_PTR application;
66     CK_NOTIFY notify;
67     char *config_file;
68     hx509_certs certs;
69     struct {
70         struct st_object **objs;
71         int num_objs;
72     } object;
73     struct {
74         int hardware_slot;
75         int app_error_fatal;
76         int login_done;
77     } flags;
78     int open_sessions;
79     struct session_state {
80         CK_SESSION_HANDLE session_handle;
81
82         struct {
83             CK_ATTRIBUTE *attributes;
84             CK_ULONG num_attributes;
85             int next_object;
86         } find;
87
88         int sign_object;
89         CK_MECHANISM_PTR sign_mechanism;
90         int verify_object;
91         CK_MECHANISM_PTR verify_mechanism;
92     } state[10];
93 #define MAX_NUM_SESSION (sizeof(soft_token.state)/sizeof(soft_token.state[0]))
94     FILE *logfile;
95 } soft_token;
96
97 static hx509_context context;
98
99 static void
100 application_error(const char *fmt, ...)
101 {
102     va_list ap;
103     va_start(ap, fmt);
104     vprintf(fmt, ap);
105     va_end(ap);
106     if (soft_token.flags.app_error_fatal)
107         abort();
108 }
109
110 static void
111 st_logf(const char *fmt, ...)
112 {
113     va_list ap;
114     if (soft_token.logfile == NULL)
115         return;
116     va_start(ap, fmt);
117     vfprintf(soft_token.logfile, fmt, ap);
118     va_end(ap);
119     fflush(soft_token.logfile);
120 }
121
122 static CK_RV
123 init_context(void)
124 {
125     if (context == NULL) {
126         int ret = hx509_context_init(&context);
127         if (ret)
128             return CKR_GENERAL_ERROR;
129     }
130     return CKR_OK;
131 }
132
133 #define INIT_CONTEXT() { CK_RV icret = init_context(); if (icret) return icret; }
134
135 static void
136 snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...)
137 {
138     int len;
139     va_list ap;
140     va_start(ap, fmt);
141     len = vsnprintf(str, size, fmt, ap);
142     va_end(ap);
143     if (len < 0 || (size_t)len > size)
144         return;
145     while ((size_t)len < size)
146         str[len++] = fillchar;
147 }
148
149 #ifndef TEST_APP
150 #define printf error_use_st_logf
151 #endif
152
153 #define VERIFY_SESSION_HANDLE(s, state)                 \
154 {                                                       \
155     CK_RV xret;                                         \
156     xret = verify_session_handle(s, state);             \
157     if (xret != CKR_OK) {                               \
158         /* return CKR_OK */;                            \
159     }                                                   \
160 }
161
162 static CK_RV
163 verify_session_handle(CK_SESSION_HANDLE hSession,
164                       struct session_state **state)
165 {
166     size_t i;
167
168     for (i = 0; i < MAX_NUM_SESSION; i++){
169         if (soft_token.state[i].session_handle == hSession)
170             break;
171     }
172     if (i == MAX_NUM_SESSION) {
173         application_error("use of invalid handle: 0x%08lx\n",
174                           (unsigned long)hSession);
175         return CKR_SESSION_HANDLE_INVALID;
176     }
177     if (state)
178         *state = &soft_token.state[i];
179     return CKR_OK;
180 }
181
182 static CK_RV
183 object_handle_to_object(CK_OBJECT_HANDLE handle,
184                         struct st_object **object)
185 {
186     int i = HANDLE_OBJECT_ID(handle);
187
188     *object = NULL;
189     if (i >= soft_token.object.num_objs)
190         return CKR_ARGUMENTS_BAD;
191     if (soft_token.object.objs[i] == NULL)
192         return CKR_ARGUMENTS_BAD;
193     if (soft_token.object.objs[i]->object_handle != handle)
194         return CKR_ARGUMENTS_BAD;
195     *object = soft_token.object.objs[i];
196     return CKR_OK;
197 }
198
199 static int
200 attributes_match(const struct st_object *obj,
201                  const CK_ATTRIBUTE *attributes,
202                  CK_ULONG num_attributes)
203 {
204     CK_ULONG i;
205     int j;
206
207     st_logf("attributes_match: %ld\n", (unsigned long)OBJECT_ID(obj));
208
209     for (i = 0; i < num_attributes; i++) {
210         int match = 0;
211         for (j = 0; j < obj->num_attributes; j++) {
212             if (attributes[i].type == obj->attrs[j].attribute.type &&
213                 attributes[i].ulValueLen == obj->attrs[j].attribute.ulValueLen &&
214                 memcmp(attributes[i].pValue, obj->attrs[j].attribute.pValue,
215                        attributes[i].ulValueLen) == 0) {
216                 match = 1;
217                 break;
218             }
219         }
220         if (match == 0) {
221             st_logf("type %d attribute have no match\n", attributes[i].type);
222             return 0;
223         }
224     }
225     st_logf("attribute matches\n");
226     return 1;
227 }
228
229 static void
230 print_attributes(const CK_ATTRIBUTE *attributes,
231                  CK_ULONG num_attributes)
232 {
233     CK_ULONG i;
234
235     st_logf("find objects: attrs: %lu\n", (unsigned long)num_attributes);
236
237     for (i = 0; i < num_attributes; i++) {
238         st_logf("  type: ");
239         switch (attributes[i].type) {
240         case CKA_TOKEN: {
241             CK_BBOOL *ck_true;
242             if (attributes[i].ulValueLen != sizeof(CK_BBOOL)) {
243                 application_error("token attribute wrong length\n");
244                 break;
245             }
246             ck_true = attributes[i].pValue;
247             st_logf("token: %s", *ck_true ? "TRUE" : "FALSE");
248             break;
249         }
250         case CKA_CLASS: {
251             CK_OBJECT_CLASS *class;
252             if (attributes[i].ulValueLen != sizeof(CK_ULONG)) {
253                 application_error("class attribute wrong length\n");
254                 break;
255             }
256             class = attributes[i].pValue;
257             st_logf("class ");
258             switch (*class) {
259             case CKO_CERTIFICATE:
260                 st_logf("certificate");
261                 break;
262             case CKO_PUBLIC_KEY:
263                 st_logf("public key");
264                 break;
265             case CKO_PRIVATE_KEY:
266                 st_logf("private key");
267                 break;
268             case CKO_SECRET_KEY:
269                 st_logf("secret key");
270                 break;
271             case CKO_DOMAIN_PARAMETERS:
272                 st_logf("domain parameters");
273                 break;
274             default:
275                 st_logf("[class %lx]", (long unsigned)*class);
276                 break;
277             }
278             break;
279         }
280         case CKA_PRIVATE:
281             st_logf("private");
282             break;
283         case CKA_LABEL:
284             st_logf("label");
285             break;
286         case CKA_APPLICATION:
287             st_logf("application");
288             break;
289         case CKA_VALUE:
290             st_logf("value");
291             break;
292         case CKA_ID:
293             st_logf("id");
294             break;
295         default:
296             st_logf("[unknown 0x%08lx]", (unsigned long)attributes[i].type);
297             break;
298         }
299         st_logf("\n");
300     }
301 }
302
303 static struct st_object *
304 add_st_object(void)
305 {
306     struct st_object *o, **objs;
307     int i;
308
309     o = calloc(1, sizeof(*o));
310     if (o == NULL)
311         return NULL;
312
313     for (i = 0; i < soft_token.object.num_objs; i++) {
314         if (soft_token.object.objs == NULL) {
315             soft_token.object.objs[i] = o;
316             break;
317         }
318     }
319     if (i == soft_token.object.num_objs) {
320         objs = realloc(soft_token.object.objs,
321                        (soft_token.object.num_objs + 1) * sizeof(soft_token.object.objs[0]));
322         if (objs == NULL) {
323             free(o);
324             return NULL;
325         }
326         soft_token.object.objs = objs;
327         soft_token.object.objs[soft_token.object.num_objs++] = o;
328     }
329     soft_token.object.objs[i]->object_handle =
330         (random() & (~OBJECT_ID_MASK)) | i;
331
332     return o;
333 }
334
335 static CK_RV
336 add_object_attribute(struct st_object *o,
337                      int secret,
338                      CK_ATTRIBUTE_TYPE type,
339                      CK_VOID_PTR pValue,
340                      CK_ULONG ulValueLen)
341 {
342     struct st_attr *a;
343     int i;
344
345     if (pValue == NULL && ulValueLen)
346         return CKR_ARGUMENTS_BAD;
347
348     i = o->num_attributes;
349     a = realloc(o->attrs, (i + 1) * sizeof(o->attrs[0]));
350     if (a == NULL)
351         return CKR_DEVICE_MEMORY;
352     o->attrs = a;
353     o->attrs[i].secret = secret;
354     o->attrs[i].attribute.type = type;
355     o->attrs[i].attribute.pValue = malloc(ulValueLen);
356     if (o->attrs[i].attribute.pValue == NULL && ulValueLen != 0)
357         return CKR_DEVICE_MEMORY;
358     if (ulValueLen)
359         memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen);
360     o->attrs[i].attribute.ulValueLen = ulValueLen;
361     o->num_attributes++;
362
363     return CKR_OK;
364 }
365
366 static CK_RV
367 add_pubkey_info(hx509_context hxctx, struct st_object *o,
368                 CK_KEY_TYPE key_type, hx509_cert cert)
369 {
370     BIGNUM *num;
371     CK_BYTE *modulus = NULL;
372     size_t modulus_len = 0;
373     CK_ULONG modulus_bits = 0;
374     CK_BYTE *exponent = NULL;
375     size_t exponent_len = 0;
376
377     if (key_type != CKK_RSA)
378         return CKR_OK;
379     if (_hx509_cert_private_key(cert) == NULL)
380         return CKR_OK;
381
382     num = _hx509_private_key_get_internal(context,
383                                           _hx509_cert_private_key(cert),
384                                           "rsa-modulus");
385     if (num == NULL)
386         return CKR_GENERAL_ERROR;
387     modulus_bits = BN_num_bits(num);
388
389     modulus_len = BN_num_bytes(num);
390     modulus = malloc(modulus_len);
391     BN_bn2bin(num, modulus);
392     BN_free(num);
393
394     add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
395     add_object_attribute(o, 0, CKA_MODULUS_BITS,
396                          &modulus_bits, sizeof(modulus_bits));
397
398     free(modulus);
399
400     num = _hx509_private_key_get_internal(context,
401                                           _hx509_cert_private_key(cert),
402                                           "rsa-exponent");
403     if (num == NULL)
404         return CKR_GENERAL_ERROR;
405
406     exponent_len = BN_num_bytes(num);
407     exponent = malloc(exponent_len);
408     BN_bn2bin(num, exponent);
409     BN_free(num);
410
411     add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
412                          exponent, exponent_len);
413
414     free(exponent);
415
416     return CKR_OK;
417 }
418
419
420 struct foo {
421     char *label;
422     char *id;
423 };
424
425 static int
426 add_cert(hx509_context hxctx, void *ctx, hx509_cert cert)
427 {
428     static char empty[] = "";
429     struct foo *foo = (struct foo *)ctx;
430     struct st_object *o = NULL;
431     CK_OBJECT_CLASS type;
432     CK_BBOOL bool_true = CK_TRUE;
433     CK_BBOOL bool_false = CK_FALSE;
434     CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
435     CK_KEY_TYPE key_type;
436     CK_MECHANISM_TYPE mech_type;
437     CK_RV ret = CKR_GENERAL_ERROR;
438     int hret;
439     heim_octet_string cert_data, subject_data, issuer_data, serial_data;
440
441     st_logf("adding certificate\n");
442
443     serial_data.data = NULL;
444     serial_data.length = 0;
445     cert_data = subject_data = issuer_data = serial_data;
446
447     hret = hx509_cert_binary(hxctx, cert, &cert_data);
448     if (hret)
449         goto out;
450
451     {
452             hx509_name name;
453
454             hret = hx509_cert_get_issuer(cert, &name);
455             if (hret)
456                 goto out;
457             hret = hx509_name_binary(name, &issuer_data);
458             hx509_name_free(&name);
459             if (hret)
460                 goto out;
461
462             hret = hx509_cert_get_subject(cert, &name);
463             if (hret)
464                 goto out;
465             hret = hx509_name_binary(name, &subject_data);
466             hx509_name_free(&name);
467             if (hret)
468                 goto out;
469     }
470
471     {
472         AlgorithmIdentifier alg;
473
474         hret = hx509_cert_get_SPKI_AlgorithmIdentifier(context, cert, &alg);
475         if (hret) {
476             ret = CKR_DEVICE_MEMORY;
477             goto out;
478         }
479
480         key_type = CKK_RSA; /* XXX */
481
482         free_AlgorithmIdentifier(&alg);
483     }
484
485
486     type = CKO_CERTIFICATE;
487     o = add_st_object();
488     if (o == NULL) {
489         ret = CKR_DEVICE_MEMORY;
490         goto out;
491     }
492
493     o->cert = hx509_cert_ref(cert);
494
495     add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
496     add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
497     add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
498     add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
499     add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
500
501     add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type));
502     add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
503
504     add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
505     add_object_attribute(o, 0, CKA_ISSUER, issuer_data.data, issuer_data.length);
506     add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data.data, serial_data.length);
507     add_object_attribute(o, 0, CKA_VALUE, cert_data.data, cert_data.length);
508     add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false));
509
510     st_logf("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o));
511
512     type = CKO_PUBLIC_KEY;
513     o = add_st_object();
514     if (o == NULL) {
515         ret = CKR_DEVICE_MEMORY;
516         goto out;
517     }
518     o->cert = hx509_cert_ref(cert);
519
520     add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
521     add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
522     add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
523     add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
524     add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
525
526     add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
527     add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
528     add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */
529     add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */
530     add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
531     add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
532     mech_type = CKM_RSA_X_509;
533     add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
534
535     add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
536     add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true));
537     add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true));
538     add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false));
539     add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true));
540     add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));
541
542     add_pubkey_info(hxctx, o, key_type, cert);
543
544     st_logf("add key ok: %lx\n", (unsigned long)OBJECT_ID(o));
545
546     if (hx509_cert_have_private_key(cert)) {
547         CK_FLAGS flags;
548
549         type = CKO_PRIVATE_KEY;
550         o = add_st_object();
551         if (o == NULL) {
552             ret = CKR_DEVICE_MEMORY;
553             goto out;
554         }
555         o->cert = hx509_cert_ref(cert);
556
557         add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
558         add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
559         add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false));
560         add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
561         add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));
562
563         add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
564         add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
565         add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */
566         add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */
567         add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
568         add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
569         mech_type = CKM_RSA_X_509;
570         add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
571
572         add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
573         add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true));
574         add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true));
575         flags = 0;
576         add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags));
577
578         add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true));
579         add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true));
580         add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false));
581         add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true));
582         add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true));
583         add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false));
584
585         add_pubkey_info(hxctx, o, key_type, cert);
586     }
587
588     ret = CKR_OK;
589  out:
590     if (ret != CKR_OK) {
591         st_logf("something went wrong when adding cert!\n");
592
593         /* XXX wack o */;
594     }
595     hx509_xfree(cert_data.data);
596     hx509_xfree(serial_data.data);
597     hx509_xfree(issuer_data.data);
598     hx509_xfree(subject_data.data);
599
600     return 0;
601 }
602
603 static CK_RV
604 add_certificate(const char *cert_file,
605                 const char *pin,
606                 char *id,
607                 char *label)
608 {
609     hx509_certs certs;
610     hx509_lock lock = NULL;
611     int ret, flags = 0;
612
613     struct foo foo;
614     foo.id = id;
615     foo.label = label;
616
617     if (pin == NULL)
618         flags |= HX509_CERTS_UNPROTECT_ALL;
619
620     if (pin) {
621         char *str;
622         asprintf(&str, "PASS:%s", pin);
623
624         hx509_lock_init(context, &lock);
625         hx509_lock_command_string(lock, str);
626
627         memset(str, 0, strlen(str));
628         free(str);
629     }
630
631     ret = hx509_certs_init(context, cert_file, flags, lock, &certs);
632     if (ret) {
633         st_logf("failed to open file %s\n", cert_file);
634         return CKR_GENERAL_ERROR;
635     }
636
637     ret = hx509_certs_iter_f(context, certs, add_cert, &foo);
638     hx509_certs_free(&certs);
639     if (ret) {
640         st_logf("failed adding certs from file %s\n", cert_file);
641         return CKR_GENERAL_ERROR;
642     }
643
644     return CKR_OK;
645 }
646
647 static void
648 find_object_final(struct session_state *state)
649 {
650     if (state->find.attributes) {
651         CK_ULONG i;
652
653         for (i = 0; i < state->find.num_attributes; i++) {
654             if (state->find.attributes[i].pValue)
655                 free(state->find.attributes[i].pValue);
656         }
657         free(state->find.attributes);
658         state->find.attributes = NULL;
659         state->find.num_attributes = 0;
660         state->find.next_object = -1;
661     }
662 }
663
664 static void
665 reset_crypto_state(struct session_state *state)
666 {
667     state->sign_object = -1;
668     if (state->sign_mechanism)
669         free(state->sign_mechanism);
670     state->sign_mechanism = NULL_PTR;
671     state->verify_object = -1;
672     if (state->verify_mechanism)
673         free(state->verify_mechanism);
674     state->verify_mechanism = NULL_PTR;
675 }
676
677 static void
678 close_session(struct session_state *state)
679 {
680     if (state->find.attributes) {
681         application_error("application didn't do C_FindObjectsFinal\n");
682         find_object_final(state);
683     }
684
685     state->session_handle = CK_INVALID_HANDLE;
686     soft_token.application = NULL_PTR;
687     soft_token.notify = NULL_PTR;
688     reset_crypto_state(state);
689 }
690
691 static const char *
692 has_session(void)
693 {
694     return soft_token.open_sessions > 0 ? "yes" : "no";
695 }
696
697 static CK_RV
698 read_conf_file(const char *fn, CK_USER_TYPE userType, const char *pin)
699 {
700     char buf[1024], *type, *s, *p;
701     FILE *f;
702     CK_RV ret = CKR_OK;
703     CK_RV failed = CKR_OK;
704
705     if (fn == NULL) {
706         st_logf("Can't open configuration file.  No file specified\n");
707         return CKR_GENERAL_ERROR;
708     }
709
710     f = fopen(fn, "r");
711     if (f == NULL) {
712         st_logf("can't open configuration file %s\n", fn);
713         return CKR_GENERAL_ERROR;
714     }
715     rk_cloexec_file(f);
716
717     while(fgets(buf, sizeof(buf), f) != NULL) {
718         buf[strcspn(buf, "\n")] = '\0';
719
720         st_logf("line: %s\n", buf);
721
722         p = buf;
723         while (isspace((unsigned char)*p))
724             p++;
725         if (*p == '#')
726             continue;
727         while (isspace((unsigned char)*p))
728             p++;
729
730         s = NULL;
731         type = strtok_r(p, "\t", &s);
732         if (type == NULL)
733             continue;
734
735         if (strcasecmp("certificate", type) == 0) {
736             char *cert, *id, *label;
737
738             id = strtok_r(NULL, "\t", &s);
739             if (id == NULL) {
740                 st_logf("no id\n");
741                 continue;
742             }
743             st_logf("id: %s\n", id);
744             label = strtok_r(NULL, "\t", &s);
745             if (label == NULL) {
746                 st_logf("no label\n");
747                 continue;
748             }
749             cert = strtok_r(NULL, "\t", &s);
750             if (cert == NULL) {
751                 st_logf("no certfiicate store\n");
752                 continue;
753             }
754
755             st_logf("adding: %s: %s in file %s\n", id, label, cert);
756
757             ret = add_certificate(cert, pin, id, label);
758             if (ret)
759                 failed = ret;
760         } else if (strcasecmp("debug", type) == 0) {
761             char *name;
762
763             name = strtok_r(NULL, "\t", &s);
764             if (name == NULL) {
765                 st_logf("no filename\n");
766                 continue;
767             }
768
769             if (soft_token.logfile)
770                 fclose(soft_token.logfile);
771
772             if (strcasecmp(name, "stdout") == 0)
773                 soft_token.logfile = stdout;
774             else {
775                 soft_token.logfile = fopen(name, "a");
776                 if (soft_token.logfile)
777                     rk_cloexec_file(soft_token.logfile);
778             }
779             if (soft_token.logfile == NULL)
780                 st_logf("failed to open file: %s\n", name);
781
782         } else if (strcasecmp("app-fatal", type) == 0) {
783             char *name;
784
785             name = strtok_r(NULL, "\t", &s);
786             if (name == NULL) {
787                 st_logf("argument to app-fatal\n");
788                 continue;
789             }
790
791             if (strcmp(name, "true") == 0 || strcmp(name, "on") == 0)
792                 soft_token.flags.app_error_fatal = 1;
793             else if (strcmp(name, "false") == 0 || strcmp(name, "off") == 0)
794                 soft_token.flags.app_error_fatal = 0;
795             else
796                 st_logf("unknown app-fatal: %s\n", name);
797
798         } else {
799             st_logf("unknown type: %s\n", type);
800         }
801     }
802
803     fclose(f);
804
805     return failed;
806 }
807
808 static CK_RV
809 func_not_supported(void)
810 {
811     st_logf("function not supported\n");
812     return CKR_FUNCTION_NOT_SUPPORTED;
813 }
814
815 static char *
816 get_config_file_for_user(void)
817 {
818     char *fn = NULL;
819
820 #ifndef _WIN32
821     char *home = NULL;
822
823     if (!issuid()) {
824         fn = getenv("SOFTPKCS11RC");
825         if (fn)
826             fn = strdup(fn);
827         home = getenv("HOME");
828     }
829     if (fn == NULL && home == NULL) {
830         struct passwd *pw = getpwuid(getuid());
831         if(pw != NULL)
832             home = pw->pw_dir;
833     }
834     if (fn == NULL) {
835         if (home)
836             asprintf(&fn, "%s/.soft-token.rc", home);
837         else
838             fn = strdup("/etc/soft-token.rc");
839     }
840 #else  /* Windows */
841
842     char appdatafolder[MAX_PATH];
843
844     fn = getenv("SOFTPKCS11RC");
845
846     /* Retrieve the roaming AppData folder for the current user.  The
847        current user is the user account represented by the current
848        thread token. */
849
850     if (fn == NULL &&
851         SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatafolder))) {
852
853         asprintf(&fn, "%s\\.soft-token.rc", appdatafolder);
854     }
855
856 #endif  /* _WIN32 */
857
858     return fn;
859 }
860
861
862 CK_RV CK_SPEC
863 C_Initialize(CK_VOID_PTR a)
864 {
865     CK_C_INITIALIZE_ARGS_PTR args = a;
866     CK_RV ret;
867     size_t i;
868
869     st_logf("Initialize\n");
870
871     INIT_CONTEXT();
872
873     OpenSSL_add_all_algorithms();
874
875     srandom(getpid() ^ (int) time(NULL));
876
877     for (i = 0; i < MAX_NUM_SESSION; i++) {
878         soft_token.state[i].session_handle = CK_INVALID_HANDLE;
879         soft_token.state[i].find.attributes = NULL;
880         soft_token.state[i].find.num_attributes = 0;
881         soft_token.state[i].find.next_object = -1;
882         reset_crypto_state(&soft_token.state[i]);
883     }
884
885     soft_token.flags.hardware_slot = 1;
886     soft_token.flags.app_error_fatal = 0;
887     soft_token.flags.login_done = 0;
888
889     soft_token.object.objs = NULL;
890     soft_token.object.num_objs = 0;
891
892     soft_token.logfile = NULL;
893 #if 0
894     soft_token.logfile = stdout;
895 #endif
896 #if 0
897     soft_token.logfile = fopen("/tmp/log-pkcs11.txt", "a");
898 #endif
899
900     if (a != NULL_PTR) {
901         st_logf("\tCreateMutex:\t%p\n", args->CreateMutex);
902         st_logf("\tDestroyMutext\t%p\n", args->DestroyMutex);
903         st_logf("\tLockMutext\t%p\n", args->LockMutex);
904         st_logf("\tUnlockMutext\t%p\n", args->UnlockMutex);
905         st_logf("\tFlags\t%04x\n", (unsigned int)args->flags);
906     }
907
908     soft_token.config_file = get_config_file_for_user();
909
910     /*
911      * This operations doesn't return CKR_OK if any of the
912      * certificates failes to be unparsed (ie password protected).
913      */
914     ret = read_conf_file(soft_token.config_file, CKU_USER, NULL);
915     if (ret == CKR_OK)
916         soft_token.flags.login_done = 1;
917
918     return CKR_OK;
919 }
920
921 CK_RV
922 C_Finalize(CK_VOID_PTR args)
923 {
924     size_t i;
925
926     INIT_CONTEXT();
927
928     st_logf("Finalize\n");
929
930     for (i = 0; i < MAX_NUM_SESSION; i++) {
931         if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) {
932             application_error("application finalized without "
933                               "closing session\n");
934             close_session(&soft_token.state[i]);
935         }
936     }
937
938     return CKR_OK;
939 }
940
941 CK_RV
942 C_GetInfo(CK_INFO_PTR args)
943 {
944     INIT_CONTEXT();
945
946     st_logf("GetInfo\n");
947
948     memset(args, 17, sizeof(*args));
949     args->cryptokiVersion.major = 2;
950     args->cryptokiVersion.minor = 10;
951     snprintf_fill((char *)args->manufacturerID,
952                   sizeof(args->manufacturerID),
953                   ' ',
954                   "Heimdal hx509 SoftToken");
955     snprintf_fill((char *)args->libraryDescription,
956                   sizeof(args->libraryDescription), ' ',
957                   "Heimdal hx509 SoftToken");
958     args->libraryVersion.major = 2;
959     args->libraryVersion.minor = 0;
960
961     return CKR_OK;
962 }
963
964 extern CK_FUNCTION_LIST funcs;
965
966 CK_RV
967 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
968 {
969     INIT_CONTEXT();
970
971     *ppFunctionList = &funcs;
972     return CKR_OK;
973 }
974
975 CK_RV
976 C_GetSlotList(CK_BBOOL tokenPresent,
977               CK_SLOT_ID_PTR pSlotList,
978               CK_ULONG_PTR   pulCount)
979 {
980     INIT_CONTEXT();
981     st_logf("GetSlotList: %s\n",
982             tokenPresent ? "tokenPresent" : "token not Present");
983     if (pSlotList)
984         pSlotList[0] = 1;
985     *pulCount = 1;
986     return CKR_OK;
987 }
988
989 CK_RV
990 C_GetSlotInfo(CK_SLOT_ID slotID,
991               CK_SLOT_INFO_PTR pInfo)
992 {
993     INIT_CONTEXT();
994     st_logf("GetSlotInfo: slot: %d : %s\n", (int)slotID, has_session());
995
996     memset(pInfo, 18, sizeof(*pInfo));
997
998     if (slotID != 1)
999         return CKR_ARGUMENTS_BAD;
1000
1001     snprintf_fill((char *)pInfo->slotDescription,
1002                   sizeof(pInfo->slotDescription),
1003                   ' ',
1004                   "Heimdal hx509 SoftToken (slot)");
1005     snprintf_fill((char *)pInfo->manufacturerID,
1006                   sizeof(pInfo->manufacturerID),
1007                   ' ',
1008                   "Heimdal hx509 SoftToken (slot)");
1009     pInfo->flags = CKF_TOKEN_PRESENT;
1010     if (soft_token.flags.hardware_slot)
1011         pInfo->flags |= CKF_HW_SLOT;
1012     pInfo->hardwareVersion.major = 1;
1013     pInfo->hardwareVersion.minor = 0;
1014     pInfo->firmwareVersion.major = 1;
1015     pInfo->firmwareVersion.minor = 0;
1016
1017     return CKR_OK;
1018 }
1019
1020 CK_RV
1021 C_GetTokenInfo(CK_SLOT_ID slotID,
1022                CK_TOKEN_INFO_PTR pInfo)
1023 {
1024     INIT_CONTEXT();
1025     st_logf("GetTokenInfo: %s\n", has_session());
1026
1027     memset(pInfo, 19, sizeof(*pInfo));
1028
1029     snprintf_fill((char *)pInfo->label,
1030                   sizeof(pInfo->label),
1031                   ' ',
1032                   "Heimdal hx509 SoftToken (token)");
1033     snprintf_fill((char *)pInfo->manufacturerID,
1034                   sizeof(pInfo->manufacturerID),
1035                   ' ',
1036                   "Heimdal hx509 SoftToken (token)");
1037     snprintf_fill((char *)pInfo->model,
1038                   sizeof(pInfo->model),
1039                   ' ',
1040                   "Heimdal hx509 SoftToken (token)");
1041     snprintf_fill((char *)pInfo->serialNumber,
1042                   sizeof(pInfo->serialNumber),
1043                   ' ',
1044                   "4711");
1045     pInfo->flags =
1046         CKF_TOKEN_INITIALIZED |
1047         CKF_USER_PIN_INITIALIZED;
1048
1049     if (soft_token.flags.login_done == 0)
1050         pInfo->flags |= CKF_LOGIN_REQUIRED;
1051
1052     /* CFK_RNG |
1053        CKF_RESTORE_KEY_NOT_NEEDED |
1054     */
1055     pInfo->ulMaxSessionCount = MAX_NUM_SESSION;
1056     pInfo->ulSessionCount = soft_token.open_sessions;
1057     pInfo->ulMaxRwSessionCount = MAX_NUM_SESSION;
1058     pInfo->ulRwSessionCount = soft_token.open_sessions;
1059     pInfo->ulMaxPinLen = 1024;
1060     pInfo->ulMinPinLen = 0;
1061     pInfo->ulTotalPublicMemory = 4711;
1062     pInfo->ulFreePublicMemory = 4712;
1063     pInfo->ulTotalPrivateMemory = 4713;
1064     pInfo->ulFreePrivateMemory = 4714;
1065     pInfo->hardwareVersion.major = 2;
1066     pInfo->hardwareVersion.minor = 0;
1067     pInfo->firmwareVersion.major = 2;
1068     pInfo->firmwareVersion.minor = 0;
1069
1070     return CKR_OK;
1071 }
1072
1073 CK_RV
1074 C_GetMechanismList(CK_SLOT_ID slotID,
1075                    CK_MECHANISM_TYPE_PTR pMechanismList,
1076                    CK_ULONG_PTR pulCount)
1077 {
1078     INIT_CONTEXT();
1079     st_logf("GetMechanismList\n");
1080
1081     *pulCount = 1;
1082     if (pMechanismList == NULL_PTR)
1083         return CKR_OK;
1084     pMechanismList[1] = CKM_RSA_PKCS;
1085
1086     return CKR_OK;
1087 }
1088
1089 CK_RV
1090 C_GetMechanismInfo(CK_SLOT_ID slotID,
1091                    CK_MECHANISM_TYPE type,
1092                    CK_MECHANISM_INFO_PTR pInfo)
1093 {
1094     INIT_CONTEXT();
1095     st_logf("GetMechanismInfo: slot %d type: %d\n",
1096             (int)slotID, (int)type);
1097     memset(pInfo, 0, sizeof(*pInfo));
1098
1099     return CKR_OK;
1100 }
1101
1102 CK_RV
1103 C_InitToken(CK_SLOT_ID slotID,
1104             CK_UTF8CHAR_PTR pPin,
1105             CK_ULONG ulPinLen,
1106             CK_UTF8CHAR_PTR pLabel)
1107 {
1108     INIT_CONTEXT();
1109     st_logf("InitToken: slot %d\n", (int)slotID);
1110     return CKR_FUNCTION_NOT_SUPPORTED;
1111 }
1112
1113 CK_RV
1114 C_OpenSession(CK_SLOT_ID slotID,
1115               CK_FLAGS flags,
1116               CK_VOID_PTR pApplication,
1117               CK_NOTIFY Notify,
1118               CK_SESSION_HANDLE_PTR phSession)
1119 {
1120     size_t i;
1121     INIT_CONTEXT();
1122     st_logf("OpenSession: slot: %d\n", (int)slotID);
1123
1124     if (soft_token.open_sessions == MAX_NUM_SESSION)
1125         return CKR_SESSION_COUNT;
1126
1127     soft_token.application = pApplication;
1128     soft_token.notify = Notify;
1129
1130     for (i = 0; i < MAX_NUM_SESSION; i++)
1131         if (soft_token.state[i].session_handle == CK_INVALID_HANDLE)
1132             break;
1133     if (i == MAX_NUM_SESSION)
1134         abort();
1135
1136     soft_token.open_sessions++;
1137
1138     soft_token.state[i].session_handle =
1139         (CK_SESSION_HANDLE)(random() & 0xfffff);
1140     *phSession = soft_token.state[i].session_handle;
1141
1142     return CKR_OK;
1143 }
1144
1145 CK_RV
1146 C_CloseSession(CK_SESSION_HANDLE hSession)
1147 {
1148     struct session_state *state;
1149     INIT_CONTEXT();
1150     st_logf("CloseSession\n");
1151
1152     if (verify_session_handle(hSession, &state) != CKR_OK)
1153         application_error("closed session not open");
1154     else
1155         close_session(state);
1156
1157     return CKR_OK;
1158 }
1159
1160 CK_RV
1161 C_CloseAllSessions(CK_SLOT_ID slotID)
1162 {
1163     size_t i;
1164     INIT_CONTEXT();
1165
1166     st_logf("CloseAllSessions\n");
1167
1168     for (i = 0; i < MAX_NUM_SESSION; i++)
1169         if (soft_token.state[i].session_handle != CK_INVALID_HANDLE)
1170             close_session(&soft_token.state[i]);
1171
1172     return CKR_OK;
1173 }
1174
1175 CK_RV
1176 C_GetSessionInfo(CK_SESSION_HANDLE hSession,
1177                  CK_SESSION_INFO_PTR pInfo)
1178 {
1179     st_logf("GetSessionInfo\n");
1180     INIT_CONTEXT();
1181
1182     VERIFY_SESSION_HANDLE(hSession, NULL);
1183
1184     memset(pInfo, 20, sizeof(*pInfo));
1185
1186     pInfo->slotID = 1;
1187     if (soft_token.flags.login_done)
1188         pInfo->state = CKS_RO_USER_FUNCTIONS;
1189     else
1190         pInfo->state = CKS_RO_PUBLIC_SESSION;
1191     pInfo->flags = CKF_SERIAL_SESSION;
1192     pInfo->ulDeviceError = 0;
1193
1194     return CKR_OK;
1195 }
1196
1197 CK_RV
1198 C_Login(CK_SESSION_HANDLE hSession,
1199         CK_USER_TYPE userType,
1200         CK_UTF8CHAR_PTR pPin,
1201         CK_ULONG ulPinLen)
1202 {
1203     char *pin = NULL;
1204     CK_RV ret;
1205     INIT_CONTEXT();
1206
1207     st_logf("Login\n");
1208
1209     VERIFY_SESSION_HANDLE(hSession, NULL);
1210
1211     if (pPin != NULL_PTR) {
1212         asprintf(&pin, "%.*s", (int)ulPinLen, pPin);
1213         st_logf("type: %d password: %s\n", (int)userType, pin);
1214     }
1215
1216     /*
1217      * Login
1218      */
1219
1220     ret = read_conf_file(soft_token.config_file, userType, pin);
1221     if (ret == CKR_OK)
1222         soft_token.flags.login_done = 1;
1223
1224     free(pin);
1225
1226     return soft_token.flags.login_done ? CKR_OK : CKR_PIN_INCORRECT;
1227 }
1228
1229 CK_RV
1230 C_Logout(CK_SESSION_HANDLE hSession)
1231 {
1232     st_logf("Logout\n");
1233     INIT_CONTEXT();
1234
1235     VERIFY_SESSION_HANDLE(hSession, NULL);
1236     return CKR_FUNCTION_NOT_SUPPORTED;
1237 }
1238
1239 CK_RV
1240 C_GetObjectSize(CK_SESSION_HANDLE hSession,
1241                 CK_OBJECT_HANDLE hObject,
1242                 CK_ULONG_PTR pulSize)
1243 {
1244     st_logf("GetObjectSize\n");
1245     INIT_CONTEXT();
1246
1247     VERIFY_SESSION_HANDLE(hSession, NULL);
1248     return CKR_FUNCTION_NOT_SUPPORTED;
1249 }
1250
1251 CK_RV
1252 C_GetAttributeValue(CK_SESSION_HANDLE hSession,
1253                     CK_OBJECT_HANDLE hObject,
1254                     CK_ATTRIBUTE_PTR pTemplate,
1255                     CK_ULONG ulCount)
1256 {
1257     struct session_state *state;
1258     struct st_object *obj;
1259     CK_ULONG i;
1260     CK_RV ret;
1261     int j;
1262
1263     INIT_CONTEXT();
1264
1265     st_logf("GetAttributeValue: %lx\n",
1266             (unsigned long)HANDLE_OBJECT_ID(hObject));
1267     VERIFY_SESSION_HANDLE(hSession, &state);
1268
1269     if ((ret = object_handle_to_object(hObject, &obj)) != CKR_OK) {
1270         st_logf("object not found: %lx\n",
1271                 (unsigned long)HANDLE_OBJECT_ID(hObject));
1272         return ret;
1273     }
1274
1275     for (i = 0; i < ulCount; i++) {
1276         st_logf("       getting 0x%08lx\n", (unsigned long)pTemplate[i].type);
1277         for (j = 0; j < obj->num_attributes; j++) {
1278             if (obj->attrs[j].secret) {
1279                 pTemplate[i].ulValueLen = (CK_ULONG)-1;
1280                 break;
1281             }
1282             if (pTemplate[i].type == obj->attrs[j].attribute.type) {
1283                 if (pTemplate[i].pValue != NULL_PTR && obj->attrs[j].secret == 0) {
1284                     if (pTemplate[i].ulValueLen >= obj->attrs[j].attribute.ulValueLen)
1285                         memcpy(pTemplate[i].pValue, obj->attrs[j].attribute.pValue,
1286                                obj->attrs[j].attribute.ulValueLen);
1287                 }
1288                 pTemplate[i].ulValueLen = obj->attrs[j].attribute.ulValueLen;
1289                 break;
1290             }
1291         }
1292         if (j == obj->num_attributes) {
1293             st_logf("key type: 0x%08lx not found\n", (unsigned long)pTemplate[i].type);
1294             pTemplate[i].ulValueLen = (CK_ULONG)-1;
1295         }
1296
1297     }
1298     return CKR_OK;
1299 }
1300
1301 CK_RV
1302 C_FindObjectsInit(CK_SESSION_HANDLE hSession,
1303                   CK_ATTRIBUTE_PTR pTemplate,
1304                   CK_ULONG ulCount)
1305 {
1306     struct session_state *state;
1307
1308     st_logf("FindObjectsInit\n");
1309
1310     INIT_CONTEXT();
1311
1312     VERIFY_SESSION_HANDLE(hSession, &state);
1313
1314     if (state->find.next_object != -1) {
1315         application_error("application didn't do C_FindObjectsFinal\n");
1316         find_object_final(state);
1317     }
1318     if (ulCount) {
1319         CK_ULONG i;
1320
1321         print_attributes(pTemplate, ulCount);
1322
1323         state->find.attributes =
1324             calloc(1, ulCount * sizeof(state->find.attributes[0]));
1325         if (state->find.attributes == NULL)
1326             return CKR_DEVICE_MEMORY;
1327         for (i = 0; i < ulCount; i++) {
1328             state->find.attributes[i].pValue =
1329                 malloc(pTemplate[i].ulValueLen);
1330             if (state->find.attributes[i].pValue == NULL) {
1331                 find_object_final(state);
1332                 return CKR_DEVICE_MEMORY;
1333             }
1334             memcpy(state->find.attributes[i].pValue,
1335                    pTemplate[i].pValue, pTemplate[i].ulValueLen);
1336             state->find.attributes[i].type = pTemplate[i].type;
1337             state->find.attributes[i].ulValueLen = pTemplate[i].ulValueLen;
1338         }
1339         state->find.num_attributes = ulCount;
1340         state->find.next_object = 0;
1341     } else {
1342         st_logf("find all objects\n");
1343         state->find.attributes = NULL;
1344         state->find.num_attributes = 0;
1345         state->find.next_object = 0;
1346     }
1347
1348     return CKR_OK;
1349 }
1350
1351 CK_RV
1352 C_FindObjects(CK_SESSION_HANDLE hSession,
1353               CK_OBJECT_HANDLE_PTR phObject,
1354               CK_ULONG ulMaxObjectCount,
1355               CK_ULONG_PTR pulObjectCount)
1356 {
1357     struct session_state *state;
1358     int i;
1359
1360     INIT_CONTEXT();
1361
1362     st_logf("FindObjects\n");
1363
1364     VERIFY_SESSION_HANDLE(hSession, &state);
1365
1366     if (state->find.next_object == -1) {
1367         application_error("application didn't do C_FindObjectsInit\n");
1368         return CKR_ARGUMENTS_BAD;
1369     }
1370     if (ulMaxObjectCount == 0) {
1371         application_error("application asked for 0 objects\n");
1372         return CKR_ARGUMENTS_BAD;
1373     }
1374     *pulObjectCount = 0;
1375     for (i = state->find.next_object; i < soft_token.object.num_objs; i++) {
1376         st_logf("FindObjects: %d\n", i);
1377         state->find.next_object = i + 1;
1378         if (attributes_match(soft_token.object.objs[i],
1379                              state->find.attributes,
1380                              state->find.num_attributes)) {
1381             *phObject++ = soft_token.object.objs[i]->object_handle;
1382             ulMaxObjectCount--;
1383             (*pulObjectCount)++;
1384             if (ulMaxObjectCount == 0)
1385                 break;
1386         }
1387     }
1388     return CKR_OK;
1389 }
1390
1391 CK_RV
1392 C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
1393 {
1394     struct session_state *state;
1395
1396     INIT_CONTEXT();
1397
1398     st_logf("FindObjectsFinal\n");
1399     VERIFY_SESSION_HANDLE(hSession, &state);
1400     find_object_final(state);
1401     return CKR_OK;
1402 }
1403
1404 static CK_RV
1405 commonInit(CK_ATTRIBUTE *attr_match, int attr_match_len,
1406            const CK_MECHANISM_TYPE *mechs, int mechs_len,
1407            const CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey,
1408            struct st_object **o)
1409 {
1410     CK_RV ret;
1411     int i;
1412
1413     *o = NULL;
1414     if ((ret = object_handle_to_object(hKey, o)) != CKR_OK)
1415         return ret;
1416
1417     ret = attributes_match(*o, attr_match, attr_match_len);
1418     if (!ret) {
1419         application_error("called commonInit on key that doesn't "
1420                           "support required attr");
1421         return CKR_ARGUMENTS_BAD;
1422     }
1423
1424     for (i = 0; i < mechs_len; i++)
1425         if (mechs[i] == pMechanism->mechanism)
1426             break;
1427     if (i == mechs_len) {
1428         application_error("called mech (%08lx) not supported\n",
1429                           pMechanism->mechanism);
1430         return CKR_ARGUMENTS_BAD;
1431     }
1432     return CKR_OK;
1433 }
1434
1435
1436 static CK_RV
1437 dup_mechanism(CK_MECHANISM_PTR *dp, const CK_MECHANISM_PTR pMechanism)
1438 {
1439     CK_MECHANISM_PTR p;
1440
1441     p = malloc(sizeof(*p));
1442     if (p == NULL)
1443         return CKR_DEVICE_MEMORY;
1444
1445     if (*dp)
1446         free(*dp);
1447     *dp = p;
1448     memcpy(p, pMechanism, sizeof(*p));
1449
1450     return CKR_OK;
1451 }
1452
1453 CK_RV
1454 C_DigestInit(CK_SESSION_HANDLE hSession,
1455              CK_MECHANISM_PTR pMechanism)
1456 {
1457     st_logf("DigestInit\n");
1458     INIT_CONTEXT();
1459     VERIFY_SESSION_HANDLE(hSession, NULL);
1460     return CKR_FUNCTION_NOT_SUPPORTED;
1461 }
1462
1463 CK_RV
1464 C_SignInit(CK_SESSION_HANDLE hSession,
1465            CK_MECHANISM_PTR pMechanism,
1466            CK_OBJECT_HANDLE hKey)
1467 {
1468     struct session_state *state;
1469     CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS };
1470     CK_BBOOL bool_true = CK_TRUE;
1471     CK_ATTRIBUTE attr[] = {
1472         { CKA_SIGN, &bool_true, sizeof(bool_true) }
1473     };
1474     struct st_object *o;
1475     CK_RV ret;
1476
1477     INIT_CONTEXT();
1478     st_logf("SignInit\n");
1479     VERIFY_SESSION_HANDLE(hSession, &state);
1480
1481     ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
1482                      mechs, sizeof(mechs)/sizeof(mechs[0]),
1483                      pMechanism, hKey, &o);
1484     if (ret)
1485         return ret;
1486
1487     ret = dup_mechanism(&state->sign_mechanism, pMechanism);
1488     if (ret == CKR_OK)
1489         state->sign_object = OBJECT_ID(o);
1490
1491     return CKR_OK;
1492 }
1493
1494 CK_RV
1495 C_Sign(CK_SESSION_HANDLE hSession,
1496        CK_BYTE_PTR pData,
1497        CK_ULONG ulDataLen,
1498        CK_BYTE_PTR pSignature,
1499        CK_ULONG_PTR pulSignatureLen)
1500 {
1501     struct session_state *state;
1502     struct st_object *o;
1503     CK_RV ret;
1504     int hret;
1505     const AlgorithmIdentifier *alg;
1506     heim_octet_string sig, data;
1507
1508     INIT_CONTEXT();
1509     st_logf("Sign\n");
1510     VERIFY_SESSION_HANDLE(hSession, &state);
1511
1512     sig.data = NULL;
1513     sig.length = 0;
1514
1515     if (state->sign_object == -1)
1516         return CKR_ARGUMENTS_BAD;
1517
1518     if (pulSignatureLen == NULL) {
1519         st_logf("signature len NULL\n");
1520         ret = CKR_ARGUMENTS_BAD;
1521         goto out;
1522     }
1523
1524     if (pData == NULL_PTR) {
1525         st_logf("data NULL\n");
1526         ret = CKR_ARGUMENTS_BAD;
1527         goto out;
1528     }
1529
1530     o = soft_token.object.objs[state->sign_object];
1531
1532     if (hx509_cert_have_private_key(o->cert) == 0) {
1533         st_logf("private key NULL\n");
1534         return CKR_ARGUMENTS_BAD;
1535     }
1536
1537     switch(state->sign_mechanism->mechanism) {
1538     case CKM_RSA_PKCS:
1539         alg = hx509_signature_rsa_pkcs1_x509();
1540         break;
1541     default:
1542         ret = CKR_FUNCTION_NOT_SUPPORTED;
1543         goto out;
1544     }
1545
1546     data.data = pData;
1547     data.length = ulDataLen;
1548
1549     hret = _hx509_create_signature(context,
1550                                    _hx509_cert_private_key(o->cert),
1551                                    alg,
1552                                    &data,
1553                                    NULL,
1554                                    &sig);
1555     if (hret) {
1556         ret = CKR_DEVICE_ERROR;
1557         goto out;
1558     }
1559     *pulSignatureLen = sig.length;
1560
1561     if (pSignature != NULL_PTR)
1562         memcpy(pSignature, sig.data, sig.length);
1563
1564     ret = CKR_OK;
1565  out:
1566     if (sig.data) {
1567         memset(sig.data, 0, sig.length);
1568         der_free_octet_string(&sig);
1569     }
1570     return ret;
1571 }
1572
1573 CK_RV
1574 C_SignUpdate(CK_SESSION_HANDLE hSession,
1575              CK_BYTE_PTR pPart,
1576              CK_ULONG ulPartLen)
1577 {
1578     INIT_CONTEXT();
1579     st_logf("SignUpdate\n");
1580     VERIFY_SESSION_HANDLE(hSession, NULL);
1581     return CKR_FUNCTION_NOT_SUPPORTED;
1582 }
1583
1584
1585 CK_RV
1586 C_SignFinal(CK_SESSION_HANDLE hSession,
1587             CK_BYTE_PTR pSignature,
1588             CK_ULONG_PTR pulSignatureLen)
1589 {
1590     INIT_CONTEXT();
1591     st_logf("SignUpdate\n");
1592     VERIFY_SESSION_HANDLE(hSession, NULL);
1593     return CKR_FUNCTION_NOT_SUPPORTED;
1594 }
1595
1596 CK_RV
1597 C_VerifyInit(CK_SESSION_HANDLE hSession,
1598              CK_MECHANISM_PTR pMechanism,
1599              CK_OBJECT_HANDLE hKey)
1600 {
1601     struct session_state *state;
1602     CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS };
1603     CK_BBOOL bool_true = CK_TRUE;
1604     CK_ATTRIBUTE attr[] = {
1605         { CKA_VERIFY, &bool_true, sizeof(bool_true) }
1606     };
1607     struct st_object *o;
1608     CK_RV ret;
1609
1610     INIT_CONTEXT();
1611     st_logf("VerifyInit\n");
1612     VERIFY_SESSION_HANDLE(hSession, &state);
1613
1614     ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
1615                      mechs, sizeof(mechs)/sizeof(mechs[0]),
1616                      pMechanism, hKey, &o);
1617     if (ret)
1618         return ret;
1619
1620     ret = dup_mechanism(&state->verify_mechanism, pMechanism);
1621     if (ret == CKR_OK)
1622         state->verify_object = OBJECT_ID(o);
1623
1624     return ret;
1625 }
1626
1627 CK_RV
1628 C_Verify(CK_SESSION_HANDLE hSession,
1629          CK_BYTE_PTR pData,
1630          CK_ULONG ulDataLen,
1631          CK_BYTE_PTR pSignature,
1632          CK_ULONG ulSignatureLen)
1633 {
1634     struct session_state *state;
1635     struct st_object *o;
1636     const AlgorithmIdentifier *alg;
1637     CK_RV ret;
1638     int hret;
1639     heim_octet_string data, sig;
1640
1641     INIT_CONTEXT();
1642     st_logf("Verify\n");
1643     VERIFY_SESSION_HANDLE(hSession, &state);
1644
1645     if (state->verify_object == -1)
1646         return CKR_ARGUMENTS_BAD;
1647
1648     o = soft_token.object.objs[state->verify_object];
1649
1650     switch(state->verify_mechanism->mechanism) {
1651     case CKM_RSA_PKCS:
1652         alg = hx509_signature_rsa_pkcs1_x509();
1653         break;
1654     default:
1655         ret = CKR_FUNCTION_NOT_SUPPORTED;
1656         goto out;
1657     }
1658
1659     sig.data = pData;
1660     sig.length = ulDataLen;
1661     data.data = pSignature;
1662     data.length = ulSignatureLen;
1663
1664     hret = _hx509_verify_signature(context,
1665                                    o->cert,
1666                                    alg,
1667                                    &data,
1668                                    &sig);
1669     if (hret) {
1670         ret = CKR_GENERAL_ERROR;
1671         goto out;
1672     }
1673     ret = CKR_OK;
1674
1675  out:
1676     return ret;
1677 }
1678
1679
1680 CK_RV
1681 C_VerifyUpdate(CK_SESSION_HANDLE hSession,
1682                CK_BYTE_PTR pPart,
1683                CK_ULONG ulPartLen)
1684 {
1685     INIT_CONTEXT();
1686     st_logf("VerifyUpdate\n");
1687     VERIFY_SESSION_HANDLE(hSession, NULL);
1688     return CKR_FUNCTION_NOT_SUPPORTED;
1689 }
1690
1691 CK_RV
1692 C_VerifyFinal(CK_SESSION_HANDLE hSession,
1693               CK_BYTE_PTR pSignature,
1694               CK_ULONG ulSignatureLen)
1695 {
1696     INIT_CONTEXT();
1697     st_logf("VerifyFinal\n");
1698     VERIFY_SESSION_HANDLE(hSession, NULL);
1699     return CKR_FUNCTION_NOT_SUPPORTED;
1700 }
1701
1702 CK_RV
1703 C_GenerateRandom(CK_SESSION_HANDLE hSession,
1704                  CK_BYTE_PTR RandomData,
1705                  CK_ULONG ulRandomLen)
1706 {
1707     INIT_CONTEXT();
1708     st_logf("GenerateRandom\n");
1709     VERIFY_SESSION_HANDLE(hSession, NULL);
1710     return CKR_FUNCTION_NOT_SUPPORTED;
1711 }
1712
1713
1714 CK_FUNCTION_LIST funcs = {
1715     { 2, 11 },
1716     C_Initialize,
1717     C_Finalize,
1718     C_GetInfo,
1719     C_GetFunctionList,
1720     C_GetSlotList,
1721     C_GetSlotInfo,
1722     C_GetTokenInfo,
1723     C_GetMechanismList,
1724     C_GetMechanismInfo,
1725     C_InitToken,
1726     (void *)func_not_supported, /* C_InitPIN */
1727     (void *)func_not_supported, /* C_SetPIN */
1728     C_OpenSession,
1729     C_CloseSession,
1730     C_CloseAllSessions,
1731     C_GetSessionInfo,
1732     (void *)func_not_supported, /* C_GetOperationState */
1733     (void *)func_not_supported, /* C_SetOperationState */
1734     C_Login,
1735     C_Logout,
1736     (void *)func_not_supported, /* C_CreateObject */
1737     (void *)func_not_supported, /* C_CopyObject */
1738     (void *)func_not_supported, /* C_DestroyObject */
1739     (void *)func_not_supported, /* C_GetObjectSize */
1740     C_GetAttributeValue,
1741     (void *)func_not_supported, /* C_SetAttributeValue */
1742     C_FindObjectsInit,
1743     C_FindObjects,
1744     C_FindObjectsFinal,
1745     (void *)func_not_supported, /* C_EncryptInit, */
1746     (void *)func_not_supported, /* C_Encrypt, */
1747     (void *)func_not_supported, /* C_EncryptUpdate, */
1748     (void *)func_not_supported, /* C_EncryptFinal, */
1749     (void *)func_not_supported, /* C_DecryptInit, */
1750     (void *)func_not_supported, /* C_Decrypt, */
1751     (void *)func_not_supported, /* C_DecryptUpdate, */
1752     (void *)func_not_supported, /* C_DecryptFinal, */
1753     C_DigestInit,
1754     (void *)func_not_supported, /* C_Digest */
1755     (void *)func_not_supported, /* C_DigestUpdate */
1756     (void *)func_not_supported, /* C_DigestKey */
1757     (void *)func_not_supported, /* C_DigestFinal */
1758     C_SignInit,
1759     C_Sign,
1760     C_SignUpdate,
1761     C_SignFinal,
1762     (void *)func_not_supported, /* C_SignRecoverInit */
1763     (void *)func_not_supported, /* C_SignRecover */
1764     C_VerifyInit,
1765     C_Verify,
1766     C_VerifyUpdate,
1767     C_VerifyFinal,
1768     (void *)func_not_supported, /* C_VerifyRecoverInit */
1769     (void *)func_not_supported, /* C_VerifyRecover */
1770     (void *)func_not_supported, /* C_DigestEncryptUpdate */
1771     (void *)func_not_supported, /* C_DecryptDigestUpdate */
1772     (void *)func_not_supported, /* C_SignEncryptUpdate */
1773     (void *)func_not_supported, /* C_DecryptVerifyUpdate */
1774     (void *)func_not_supported, /* C_GenerateKey */
1775     (void *)func_not_supported, /* C_GenerateKeyPair */
1776     (void *)func_not_supported, /* C_WrapKey */
1777     (void *)func_not_supported, /* C_UnwrapKey */
1778     (void *)func_not_supported, /* C_DeriveKey */
1779     (void *)func_not_supported, /* C_SeedRandom */
1780     C_GenerateRandom,
1781     (void *)func_not_supported, /* C_GetFunctionStatus */
1782     (void *)func_not_supported, /* C_CancelFunction */
1783     (void *)func_not_supported  /* C_WaitForSlotEvent */
1784 };