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