HEIMDAL: move code from source4/heimdal* to third_party/heimdal*
[samba.git] / third_party / 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 "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 HX509_LIB_CALL
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;
822     int ret;
823
824     fn = secure_getenv("SOFTPKCS11RC");
825     if (fn)
826         fn = strdup(fn);
827     if (fn == NULL) {
828         char homebuf[MAX_PATH];
829         const char *home = roken_get_appdatadir(homebuf, sizeof(homebuf));
830
831         if (home) {
832             ret = asprintf(&fn, "%s/.soft-token.rc", home);
833             if (ret == -1)
834                 fn = NULL;
835         } else {
836 #ifndef WIN32
837             fn = strdup("/etc/soft-token.rc");
838 #endif
839         }
840     }
841
842     return fn;
843 }
844
845
846 CK_RV CK_SPEC
847 C_Initialize(CK_VOID_PTR a)
848 {
849     CK_C_INITIALIZE_ARGS_PTR args = a;
850     CK_RV ret;
851     size_t i;
852
853     st_logf("Initialize\n");
854
855     INIT_CONTEXT();
856
857     OpenSSL_add_all_algorithms();
858
859     srandom(getpid() ^ (int) time(NULL));
860
861     for (i = 0; i < MAX_NUM_SESSION; i++) {
862         soft_token.state[i].session_handle = CK_INVALID_HANDLE;
863         soft_token.state[i].find.attributes = NULL;
864         soft_token.state[i].find.num_attributes = 0;
865         soft_token.state[i].find.next_object = -1;
866         reset_crypto_state(&soft_token.state[i]);
867     }
868
869     soft_token.flags.hardware_slot = 1;
870     soft_token.flags.app_error_fatal = 0;
871     soft_token.flags.login_done = 0;
872
873     soft_token.object.objs = NULL;
874     soft_token.object.num_objs = 0;
875
876     soft_token.logfile = NULL;
877 #if 0
878     soft_token.logfile = stdout;
879 #endif
880 #if 0
881     soft_token.logfile = fopen("/tmp/log-pkcs11.txt", "a");
882 #endif
883
884     if (a != NULL_PTR) {
885         st_logf("\tCreateMutex:\t%p\n", args->CreateMutex);
886         st_logf("\tDestroyMutext\t%p\n", args->DestroyMutex);
887         st_logf("\tLockMutext\t%p\n", args->LockMutex);
888         st_logf("\tUnlockMutext\t%p\n", args->UnlockMutex);
889         st_logf("\tFlags\t%04x\n", (unsigned int)args->flags);
890     }
891
892     soft_token.config_file = get_config_file_for_user();
893
894     /*
895      * This operations doesn't return CKR_OK if any of the
896      * certificates failes to be unparsed (ie password protected).
897      */
898     ret = read_conf_file(soft_token.config_file, CKU_USER, NULL);
899     if (ret == CKR_OK)
900         soft_token.flags.login_done = 1;
901
902     return CKR_OK;
903 }
904
905 CK_RV
906 C_Finalize(CK_VOID_PTR args)
907 {
908     size_t i;
909
910     INIT_CONTEXT();
911
912     st_logf("Finalize\n");
913
914     for (i = 0; i < MAX_NUM_SESSION; i++) {
915         if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) {
916             application_error("application finalized without "
917                               "closing session\n");
918             close_session(&soft_token.state[i]);
919         }
920     }
921
922     return CKR_OK;
923 }
924
925 CK_RV
926 C_GetInfo(CK_INFO_PTR args)
927 {
928     INIT_CONTEXT();
929
930     st_logf("GetInfo\n");
931
932     memset(args, 17, sizeof(*args));
933     args->cryptokiVersion.major = 2;
934     args->cryptokiVersion.minor = 10;
935     snprintf_fill((char *)args->manufacturerID,
936                   sizeof(args->manufacturerID),
937                   ' ',
938                   "Heimdal hx509 SoftToken");
939     snprintf_fill((char *)args->libraryDescription,
940                   sizeof(args->libraryDescription), ' ',
941                   "Heimdal hx509 SoftToken");
942     args->libraryVersion.major = 2;
943     args->libraryVersion.minor = 0;
944
945     return CKR_OK;
946 }
947
948 extern CK_FUNCTION_LIST funcs;
949
950 CK_RV
951 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
952 {
953     INIT_CONTEXT();
954
955     *ppFunctionList = &funcs;
956     return CKR_OK;
957 }
958
959 CK_RV
960 C_GetSlotList(CK_BBOOL tokenPresent,
961               CK_SLOT_ID_PTR pSlotList,
962               CK_ULONG_PTR   pulCount)
963 {
964     INIT_CONTEXT();
965     st_logf("GetSlotList: %s\n",
966             tokenPresent ? "tokenPresent" : "token not Present");
967     if (pSlotList)
968         pSlotList[0] = 1;
969     *pulCount = 1;
970     return CKR_OK;
971 }
972
973 CK_RV
974 C_GetSlotInfo(CK_SLOT_ID slotID,
975               CK_SLOT_INFO_PTR pInfo)
976 {
977     INIT_CONTEXT();
978     st_logf("GetSlotInfo: slot: %d : %s\n", (int)slotID, has_session());
979
980     memset(pInfo, 18, sizeof(*pInfo));
981
982     if (slotID != 1)
983         return CKR_ARGUMENTS_BAD;
984
985     snprintf_fill((char *)pInfo->slotDescription,
986                   sizeof(pInfo->slotDescription),
987                   ' ',
988                   "Heimdal hx509 SoftToken (slot)");
989     snprintf_fill((char *)pInfo->manufacturerID,
990                   sizeof(pInfo->manufacturerID),
991                   ' ',
992                   "Heimdal hx509 SoftToken (slot)");
993     pInfo->flags = CKF_TOKEN_PRESENT;
994     if (soft_token.flags.hardware_slot)
995         pInfo->flags |= CKF_HW_SLOT;
996     pInfo->hardwareVersion.major = 1;
997     pInfo->hardwareVersion.minor = 0;
998     pInfo->firmwareVersion.major = 1;
999     pInfo->firmwareVersion.minor = 0;
1000
1001     return CKR_OK;
1002 }
1003
1004 CK_RV
1005 C_GetTokenInfo(CK_SLOT_ID slotID,
1006                CK_TOKEN_INFO_PTR pInfo)
1007 {
1008     INIT_CONTEXT();
1009     st_logf("GetTokenInfo: %s\n", has_session());
1010
1011     memset(pInfo, 19, sizeof(*pInfo));
1012
1013     snprintf_fill((char *)pInfo->label,
1014                   sizeof(pInfo->label),
1015                   ' ',
1016                   "Heimdal hx509 SoftToken (token)");
1017     snprintf_fill((char *)pInfo->manufacturerID,
1018                   sizeof(pInfo->manufacturerID),
1019                   ' ',
1020                   "Heimdal hx509 SoftToken (token)");
1021     snprintf_fill((char *)pInfo->model,
1022                   sizeof(pInfo->model),
1023                   ' ',
1024                   "Heimdal hx509 SoftToken (token)");
1025     snprintf_fill((char *)pInfo->serialNumber,
1026                   sizeof(pInfo->serialNumber),
1027                   ' ',
1028                   "4711");
1029     pInfo->flags =
1030         CKF_TOKEN_INITIALIZED |
1031         CKF_USER_PIN_INITIALIZED;
1032
1033     if (soft_token.flags.login_done == 0)
1034         pInfo->flags |= CKF_LOGIN_REQUIRED;
1035
1036     /* CFK_RNG |
1037        CKF_RESTORE_KEY_NOT_NEEDED |
1038     */
1039     pInfo->ulMaxSessionCount = MAX_NUM_SESSION;
1040     pInfo->ulSessionCount = soft_token.open_sessions;
1041     pInfo->ulMaxRwSessionCount = MAX_NUM_SESSION;
1042     pInfo->ulRwSessionCount = soft_token.open_sessions;
1043     pInfo->ulMaxPinLen = 1024;
1044     pInfo->ulMinPinLen = 0;
1045     pInfo->ulTotalPublicMemory = 4711;
1046     pInfo->ulFreePublicMemory = 4712;
1047     pInfo->ulTotalPrivateMemory = 4713;
1048     pInfo->ulFreePrivateMemory = 4714;
1049     pInfo->hardwareVersion.major = 2;
1050     pInfo->hardwareVersion.minor = 0;
1051     pInfo->firmwareVersion.major = 2;
1052     pInfo->firmwareVersion.minor = 0;
1053
1054     return CKR_OK;
1055 }
1056
1057 CK_RV
1058 C_GetMechanismList(CK_SLOT_ID slotID,
1059                    CK_MECHANISM_TYPE_PTR pMechanismList,
1060                    CK_ULONG_PTR pulCount)
1061 {
1062     INIT_CONTEXT();
1063     st_logf("GetMechanismList\n");
1064
1065     *pulCount = 1;
1066     if (pMechanismList == NULL_PTR)
1067         return CKR_OK;
1068     pMechanismList[0] = CKM_RSA_PKCS;
1069
1070     return CKR_OK;
1071 }
1072
1073 CK_RV
1074 C_GetMechanismInfo(CK_SLOT_ID slotID,
1075                    CK_MECHANISM_TYPE type,
1076                    CK_MECHANISM_INFO_PTR pInfo)
1077 {
1078     INIT_CONTEXT();
1079     st_logf("GetMechanismInfo: slot %d type: %d\n",
1080             (int)slotID, (int)type);
1081     memset(pInfo, 0, sizeof(*pInfo));
1082
1083     return CKR_OK;
1084 }
1085
1086 CK_RV
1087 C_InitToken(CK_SLOT_ID slotID,
1088             CK_UTF8CHAR_PTR pPin,
1089             CK_ULONG ulPinLen,
1090             CK_UTF8CHAR_PTR pLabel)
1091 {
1092     INIT_CONTEXT();
1093     st_logf("InitToken: slot %d\n", (int)slotID);
1094     return CKR_FUNCTION_NOT_SUPPORTED;
1095 }
1096
1097 CK_RV
1098 C_OpenSession(CK_SLOT_ID slotID,
1099               CK_FLAGS flags,
1100               CK_VOID_PTR pApplication,
1101               CK_NOTIFY Notify,
1102               CK_SESSION_HANDLE_PTR phSession)
1103 {
1104     size_t i;
1105     INIT_CONTEXT();
1106     st_logf("OpenSession: slot: %d\n", (int)slotID);
1107
1108     if (soft_token.open_sessions == MAX_NUM_SESSION)
1109         return CKR_SESSION_COUNT;
1110
1111     soft_token.application = pApplication;
1112     soft_token.notify = Notify;
1113
1114     for (i = 0; i < MAX_NUM_SESSION; i++)
1115         if (soft_token.state[i].session_handle == CK_INVALID_HANDLE)
1116             break;
1117     if (i == MAX_NUM_SESSION)
1118         abort();
1119
1120     soft_token.open_sessions++;
1121
1122     soft_token.state[i].session_handle =
1123         (CK_SESSION_HANDLE)(random() & 0xfffff);
1124     *phSession = soft_token.state[i].session_handle;
1125
1126     return CKR_OK;
1127 }
1128
1129 CK_RV
1130 C_CloseSession(CK_SESSION_HANDLE hSession)
1131 {
1132     struct session_state *state;
1133     INIT_CONTEXT();
1134     st_logf("CloseSession\n");
1135
1136     if (verify_session_handle(hSession, &state) != CKR_OK)
1137         application_error("closed session not open");
1138     else
1139         close_session(state);
1140
1141     return CKR_OK;
1142 }
1143
1144 CK_RV
1145 C_CloseAllSessions(CK_SLOT_ID slotID)
1146 {
1147     size_t i;
1148     INIT_CONTEXT();
1149
1150     st_logf("CloseAllSessions\n");
1151
1152     for (i = 0; i < MAX_NUM_SESSION; i++)
1153         if (soft_token.state[i].session_handle != CK_INVALID_HANDLE)
1154             close_session(&soft_token.state[i]);
1155
1156     return CKR_OK;
1157 }
1158
1159 CK_RV
1160 C_GetSessionInfo(CK_SESSION_HANDLE hSession,
1161                  CK_SESSION_INFO_PTR pInfo)
1162 {
1163     st_logf("GetSessionInfo\n");
1164     INIT_CONTEXT();
1165
1166     VERIFY_SESSION_HANDLE(hSession, NULL);
1167
1168     memset(pInfo, 20, sizeof(*pInfo));
1169
1170     pInfo->slotID = 1;
1171     if (soft_token.flags.login_done)
1172         pInfo->state = CKS_RO_USER_FUNCTIONS;
1173     else
1174         pInfo->state = CKS_RO_PUBLIC_SESSION;
1175     pInfo->flags = CKF_SERIAL_SESSION;
1176     pInfo->ulDeviceError = 0;
1177
1178     return CKR_OK;
1179 }
1180
1181 CK_RV
1182 C_Login(CK_SESSION_HANDLE hSession,
1183         CK_USER_TYPE userType,
1184         CK_UTF8CHAR_PTR pPin,
1185         CK_ULONG ulPinLen)
1186 {
1187     char *pin = NULL;
1188     CK_RV ret;
1189     INIT_CONTEXT();
1190
1191     st_logf("Login\n");
1192
1193     VERIFY_SESSION_HANDLE(hSession, NULL);
1194
1195     if (pPin != NULL_PTR) {
1196         int aret;
1197
1198         aret = asprintf(&pin, "%.*s", (int)ulPinLen, pPin);
1199         if (aret != -1 && pin)
1200                 st_logf("type: %d password: %s\n", (int)userType, pin);
1201         else
1202                 st_logf("memory error: asprintf failed\n");
1203     }
1204
1205     /*
1206      * Login
1207      */
1208
1209     ret = read_conf_file(soft_token.config_file, userType, pin);
1210     if (ret == CKR_OK)
1211         soft_token.flags.login_done = 1;
1212
1213     free(pin);
1214
1215     return soft_token.flags.login_done ? CKR_OK : CKR_PIN_INCORRECT;
1216 }
1217
1218 CK_RV
1219 C_Logout(CK_SESSION_HANDLE hSession)
1220 {
1221     st_logf("Logout\n");
1222     INIT_CONTEXT();
1223
1224     VERIFY_SESSION_HANDLE(hSession, NULL);
1225     return CKR_FUNCTION_NOT_SUPPORTED;
1226 }
1227
1228 CK_RV
1229 C_GetObjectSize(CK_SESSION_HANDLE hSession,
1230                 CK_OBJECT_HANDLE hObject,
1231                 CK_ULONG_PTR pulSize)
1232 {
1233     st_logf("GetObjectSize\n");
1234     INIT_CONTEXT();
1235
1236     VERIFY_SESSION_HANDLE(hSession, NULL);
1237     return CKR_FUNCTION_NOT_SUPPORTED;
1238 }
1239
1240 CK_RV
1241 C_GetAttributeValue(CK_SESSION_HANDLE hSession,
1242                     CK_OBJECT_HANDLE hObject,
1243                     CK_ATTRIBUTE_PTR pTemplate,
1244                     CK_ULONG ulCount)
1245 {
1246     struct session_state *state;
1247     struct st_object *obj;
1248     CK_ULONG i;
1249     CK_RV ret;
1250     int j;
1251
1252     INIT_CONTEXT();
1253
1254     st_logf("GetAttributeValue: %lx\n",
1255             (unsigned long)HANDLE_OBJECT_ID(hObject));
1256     VERIFY_SESSION_HANDLE(hSession, &state);
1257
1258     if ((ret = object_handle_to_object(hObject, &obj)) != CKR_OK) {
1259         st_logf("object not found: %lx\n",
1260                 (unsigned long)HANDLE_OBJECT_ID(hObject));
1261         return ret;
1262     }
1263
1264     for (i = 0; i < ulCount; i++) {
1265         st_logf("       getting 0x%08lx\n", (unsigned long)pTemplate[i].type);
1266         for (j = 0; j < obj->num_attributes; j++) {
1267             if (obj->attrs[j].secret) {
1268                 pTemplate[i].ulValueLen = (CK_ULONG)-1;
1269                 break;
1270             }
1271             if (pTemplate[i].type == obj->attrs[j].attribute.type) {
1272                 if (pTemplate[i].pValue != NULL_PTR && obj->attrs[j].secret == 0) {
1273                     if (pTemplate[i].ulValueLen >= obj->attrs[j].attribute.ulValueLen)
1274                         memcpy(pTemplate[i].pValue, obj->attrs[j].attribute.pValue,
1275                                obj->attrs[j].attribute.ulValueLen);
1276                 }
1277                 pTemplate[i].ulValueLen = obj->attrs[j].attribute.ulValueLen;
1278                 break;
1279             }
1280         }
1281         if (j == obj->num_attributes) {
1282             st_logf("key type: 0x%08lx not found\n", (unsigned long)pTemplate[i].type);
1283             pTemplate[i].ulValueLen = (CK_ULONG)-1;
1284         }
1285
1286     }
1287     return CKR_OK;
1288 }
1289
1290 CK_RV
1291 C_FindObjectsInit(CK_SESSION_HANDLE hSession,
1292                   CK_ATTRIBUTE_PTR pTemplate,
1293                   CK_ULONG ulCount)
1294 {
1295     struct session_state *state;
1296
1297     st_logf("FindObjectsInit\n");
1298
1299     INIT_CONTEXT();
1300
1301     VERIFY_SESSION_HANDLE(hSession, &state);
1302
1303     if (state->find.next_object != -1) {
1304         application_error("application didn't do C_FindObjectsFinal\n");
1305         find_object_final(state);
1306     }
1307     if (ulCount) {
1308         CK_ULONG i;
1309
1310         print_attributes(pTemplate, ulCount);
1311
1312         state->find.attributes =
1313             calloc(1, ulCount * sizeof(state->find.attributes[0]));
1314         if (state->find.attributes == NULL)
1315             return CKR_DEVICE_MEMORY;
1316         for (i = 0; i < ulCount; i++) {
1317             state->find.attributes[i].pValue =
1318                 malloc(pTemplate[i].ulValueLen);
1319             if (state->find.attributes[i].pValue == NULL) {
1320                 find_object_final(state);
1321                 return CKR_DEVICE_MEMORY;
1322             }
1323             memcpy(state->find.attributes[i].pValue,
1324                    pTemplate[i].pValue, pTemplate[i].ulValueLen);
1325             state->find.attributes[i].type = pTemplate[i].type;
1326             state->find.attributes[i].ulValueLen = pTemplate[i].ulValueLen;
1327         }
1328         state->find.num_attributes = ulCount;
1329         state->find.next_object = 0;
1330     } else {
1331         st_logf("find all objects\n");
1332         state->find.attributes = NULL;
1333         state->find.num_attributes = 0;
1334         state->find.next_object = 0;
1335     }
1336
1337     return CKR_OK;
1338 }
1339
1340 CK_RV
1341 C_FindObjects(CK_SESSION_HANDLE hSession,
1342               CK_OBJECT_HANDLE_PTR phObject,
1343               CK_ULONG ulMaxObjectCount,
1344               CK_ULONG_PTR pulObjectCount)
1345 {
1346     struct session_state *state;
1347     int i;
1348
1349     INIT_CONTEXT();
1350
1351     st_logf("FindObjects\n");
1352
1353     VERIFY_SESSION_HANDLE(hSession, &state);
1354
1355     if (state->find.next_object == -1) {
1356         application_error("application didn't do C_FindObjectsInit\n");
1357         return CKR_ARGUMENTS_BAD;
1358     }
1359     if (ulMaxObjectCount == 0) {
1360         application_error("application asked for 0 objects\n");
1361         return CKR_ARGUMENTS_BAD;
1362     }
1363     *pulObjectCount = 0;
1364     for (i = state->find.next_object; i < soft_token.object.num_objs; i++) {
1365         st_logf("FindObjects: %d\n", i);
1366         state->find.next_object = i + 1;
1367         if (attributes_match(soft_token.object.objs[i],
1368                              state->find.attributes,
1369                              state->find.num_attributes)) {
1370             *phObject++ = soft_token.object.objs[i]->object_handle;
1371             ulMaxObjectCount--;
1372             (*pulObjectCount)++;
1373             if (ulMaxObjectCount == 0)
1374                 break;
1375         }
1376     }
1377     return CKR_OK;
1378 }
1379
1380 CK_RV
1381 C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
1382 {
1383     struct session_state *state;
1384
1385     INIT_CONTEXT();
1386
1387     st_logf("FindObjectsFinal\n");
1388     VERIFY_SESSION_HANDLE(hSession, &state);
1389     find_object_final(state);
1390     return CKR_OK;
1391 }
1392
1393 static CK_RV
1394 commonInit(CK_ATTRIBUTE *attr_match, int attr_match_len,
1395            const CK_MECHANISM_TYPE *mechs, int mechs_len,
1396            const CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey,
1397            struct st_object **o)
1398 {
1399     CK_RV ret;
1400     int i;
1401
1402     *o = NULL;
1403     if ((ret = object_handle_to_object(hKey, o)) != CKR_OK)
1404         return ret;
1405
1406     ret = attributes_match(*o, attr_match, attr_match_len);
1407     if (!ret) {
1408         application_error("called commonInit on key that doesn't "
1409                           "support required attr");
1410         return CKR_ARGUMENTS_BAD;
1411     }
1412
1413     for (i = 0; i < mechs_len; i++)
1414         if (mechs[i] == pMechanism->mechanism)
1415             break;
1416     if (i == mechs_len) {
1417         application_error("called mech (%08lx) not supported\n",
1418                           pMechanism->mechanism);
1419         return CKR_ARGUMENTS_BAD;
1420     }
1421     return CKR_OK;
1422 }
1423
1424
1425 static CK_RV
1426 dup_mechanism(CK_MECHANISM_PTR *dp, const CK_MECHANISM_PTR pMechanism)
1427 {
1428     CK_MECHANISM_PTR p;
1429
1430     p = malloc(sizeof(*p));
1431     if (p == NULL)
1432         return CKR_DEVICE_MEMORY;
1433
1434     if (*dp)
1435         free(*dp);
1436     *dp = p;
1437     memcpy(p, pMechanism, sizeof(*p));
1438
1439     return CKR_OK;
1440 }
1441
1442 CK_RV
1443 C_DigestInit(CK_SESSION_HANDLE hSession,
1444              CK_MECHANISM_PTR pMechanism)
1445 {
1446     st_logf("DigestInit\n");
1447     INIT_CONTEXT();
1448     VERIFY_SESSION_HANDLE(hSession, NULL);
1449     return CKR_FUNCTION_NOT_SUPPORTED;
1450 }
1451
1452 CK_RV
1453 C_SignInit(CK_SESSION_HANDLE hSession,
1454            CK_MECHANISM_PTR pMechanism,
1455            CK_OBJECT_HANDLE hKey)
1456 {
1457     struct session_state *state;
1458     CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS };
1459     CK_BBOOL bool_true = CK_TRUE;
1460     CK_ATTRIBUTE attr[] = {
1461         { CKA_SIGN, &bool_true, sizeof(bool_true) }
1462     };
1463     struct st_object *o;
1464     CK_RV ret;
1465
1466     INIT_CONTEXT();
1467     st_logf("SignInit\n");
1468     VERIFY_SESSION_HANDLE(hSession, &state);
1469
1470     ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
1471                      mechs, sizeof(mechs)/sizeof(mechs[0]),
1472                      pMechanism, hKey, &o);
1473     if (ret)
1474         return ret;
1475
1476     ret = dup_mechanism(&state->sign_mechanism, pMechanism);
1477     if (ret == CKR_OK)
1478         state->sign_object = OBJECT_ID(o);
1479
1480     return CKR_OK;
1481 }
1482
1483 CK_RV
1484 C_Sign(CK_SESSION_HANDLE hSession,
1485        CK_BYTE_PTR pData,
1486        CK_ULONG ulDataLen,
1487        CK_BYTE_PTR pSignature,
1488        CK_ULONG_PTR pulSignatureLen)
1489 {
1490     struct session_state *state;
1491     struct st_object *o;
1492     CK_RV ret;
1493     int hret;
1494     const AlgorithmIdentifier *alg;
1495     heim_octet_string sig, data;
1496
1497     INIT_CONTEXT();
1498     st_logf("Sign\n");
1499     VERIFY_SESSION_HANDLE(hSession, &state);
1500
1501     sig.data = NULL;
1502     sig.length = 0;
1503
1504     if (state->sign_object == -1)
1505         return CKR_ARGUMENTS_BAD;
1506
1507     if (pulSignatureLen == NULL) {
1508         st_logf("signature len NULL\n");
1509         ret = CKR_ARGUMENTS_BAD;
1510         goto out;
1511     }
1512
1513     if (pData == NULL_PTR) {
1514         st_logf("data NULL\n");
1515         ret = CKR_ARGUMENTS_BAD;
1516         goto out;
1517     }
1518
1519     o = soft_token.object.objs[state->sign_object];
1520
1521     if (hx509_cert_have_private_key(o->cert) == 0) {
1522         st_logf("private key NULL\n");
1523         return CKR_ARGUMENTS_BAD;
1524     }
1525
1526     switch(state->sign_mechanism->mechanism) {
1527     case CKM_RSA_PKCS:
1528         alg = hx509_signature_rsa_pkcs1_x509();
1529         break;
1530     default:
1531         ret = CKR_FUNCTION_NOT_SUPPORTED;
1532         goto out;
1533     }
1534
1535     data.data = pData;
1536     data.length = ulDataLen;
1537
1538     hret = _hx509_create_signature(context,
1539                                    _hx509_cert_private_key(o->cert),
1540                                    alg,
1541                                    &data,
1542                                    NULL,
1543                                    &sig);
1544     if (hret) {
1545         ret = CKR_DEVICE_ERROR;
1546         goto out;
1547     }
1548     *pulSignatureLen = sig.length;
1549
1550     if (pSignature != NULL_PTR)
1551         memcpy(pSignature, sig.data, sig.length);
1552
1553     ret = CKR_OK;
1554  out:
1555     if (sig.data) {
1556         memset(sig.data, 0, sig.length);
1557         der_free_octet_string(&sig);
1558     }
1559     return ret;
1560 }
1561
1562 CK_RV
1563 C_SignUpdate(CK_SESSION_HANDLE hSession,
1564              CK_BYTE_PTR pPart,
1565              CK_ULONG ulPartLen)
1566 {
1567     INIT_CONTEXT();
1568     st_logf("SignUpdate\n");
1569     VERIFY_SESSION_HANDLE(hSession, NULL);
1570     return CKR_FUNCTION_NOT_SUPPORTED;
1571 }
1572
1573
1574 CK_RV
1575 C_SignFinal(CK_SESSION_HANDLE hSession,
1576             CK_BYTE_PTR pSignature,
1577             CK_ULONG_PTR pulSignatureLen)
1578 {
1579     INIT_CONTEXT();
1580     st_logf("SignUpdate\n");
1581     VERIFY_SESSION_HANDLE(hSession, NULL);
1582     return CKR_FUNCTION_NOT_SUPPORTED;
1583 }
1584
1585 CK_RV
1586 C_VerifyInit(CK_SESSION_HANDLE hSession,
1587              CK_MECHANISM_PTR pMechanism,
1588              CK_OBJECT_HANDLE hKey)
1589 {
1590     struct session_state *state;
1591     CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS };
1592     CK_BBOOL bool_true = CK_TRUE;
1593     CK_ATTRIBUTE attr[] = {
1594         { CKA_VERIFY, &bool_true, sizeof(bool_true) }
1595     };
1596     struct st_object *o;
1597     CK_RV ret;
1598
1599     INIT_CONTEXT();
1600     st_logf("VerifyInit\n");
1601     VERIFY_SESSION_HANDLE(hSession, &state);
1602
1603     ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
1604                      mechs, sizeof(mechs)/sizeof(mechs[0]),
1605                      pMechanism, hKey, &o);
1606     if (ret)
1607         return ret;
1608
1609     ret = dup_mechanism(&state->verify_mechanism, pMechanism);
1610     if (ret == CKR_OK)
1611         state->verify_object = OBJECT_ID(o);
1612
1613     return ret;
1614 }
1615
1616 CK_RV
1617 C_Verify(CK_SESSION_HANDLE hSession,
1618          CK_BYTE_PTR pData,
1619          CK_ULONG ulDataLen,
1620          CK_BYTE_PTR pSignature,
1621          CK_ULONG ulSignatureLen)
1622 {
1623     struct session_state *state;
1624     struct st_object *o;
1625     const AlgorithmIdentifier *alg;
1626     CK_RV ret;
1627     int hret;
1628     heim_octet_string data, sig;
1629
1630     INIT_CONTEXT();
1631     st_logf("Verify\n");
1632     VERIFY_SESSION_HANDLE(hSession, &state);
1633
1634     if (state->verify_object == -1)
1635         return CKR_ARGUMENTS_BAD;
1636
1637     o = soft_token.object.objs[state->verify_object];
1638
1639     switch(state->verify_mechanism->mechanism) {
1640     case CKM_RSA_PKCS:
1641         alg = hx509_signature_rsa_pkcs1_x509();
1642         break;
1643     default:
1644         ret = CKR_FUNCTION_NOT_SUPPORTED;
1645         goto out;
1646     }
1647
1648     sig.data = pData;
1649     sig.length = ulDataLen;
1650     data.data = pSignature;
1651     data.length = ulSignatureLen;
1652
1653     hret = _hx509_verify_signature(context,
1654                                    o->cert,
1655                                    alg,
1656                                    &data,
1657                                    &sig);
1658     if (hret) {
1659         ret = CKR_GENERAL_ERROR;
1660         goto out;
1661     }
1662     ret = CKR_OK;
1663
1664  out:
1665     return ret;
1666 }
1667
1668
1669 CK_RV
1670 C_VerifyUpdate(CK_SESSION_HANDLE hSession,
1671                CK_BYTE_PTR pPart,
1672                CK_ULONG ulPartLen)
1673 {
1674     INIT_CONTEXT();
1675     st_logf("VerifyUpdate\n");
1676     VERIFY_SESSION_HANDLE(hSession, NULL);
1677     return CKR_FUNCTION_NOT_SUPPORTED;
1678 }
1679
1680 CK_RV
1681 C_VerifyFinal(CK_SESSION_HANDLE hSession,
1682               CK_BYTE_PTR pSignature,
1683               CK_ULONG ulSignatureLen)
1684 {
1685     INIT_CONTEXT();
1686     st_logf("VerifyFinal\n");
1687     VERIFY_SESSION_HANDLE(hSession, NULL);
1688     return CKR_FUNCTION_NOT_SUPPORTED;
1689 }
1690
1691 CK_RV
1692 C_GenerateRandom(CK_SESSION_HANDLE hSession,
1693                  CK_BYTE_PTR RandomData,
1694                  CK_ULONG ulRandomLen)
1695 {
1696     INIT_CONTEXT();
1697     st_logf("GenerateRandom\n");
1698     VERIFY_SESSION_HANDLE(hSession, NULL);
1699     return CKR_FUNCTION_NOT_SUPPORTED;
1700 }
1701
1702
1703 CK_FUNCTION_LIST funcs = {
1704     { 2, 11 },
1705     C_Initialize,
1706     C_Finalize,
1707     C_GetInfo,
1708     C_GetFunctionList,
1709     C_GetSlotList,
1710     C_GetSlotInfo,
1711     C_GetTokenInfo,
1712     C_GetMechanismList,
1713     C_GetMechanismInfo,
1714     C_InitToken,
1715     (void *)func_not_supported, /* C_InitPIN */
1716     (void *)func_not_supported, /* C_SetPIN */
1717     C_OpenSession,
1718     C_CloseSession,
1719     C_CloseAllSessions,
1720     C_GetSessionInfo,
1721     (void *)func_not_supported, /* C_GetOperationState */
1722     (void *)func_not_supported, /* C_SetOperationState */
1723     C_Login,
1724     C_Logout,
1725     (void *)func_not_supported, /* C_CreateObject */
1726     (void *)func_not_supported, /* C_CopyObject */
1727     (void *)func_not_supported, /* C_DestroyObject */
1728     (void *)func_not_supported, /* C_GetObjectSize */
1729     C_GetAttributeValue,
1730     (void *)func_not_supported, /* C_SetAttributeValue */
1731     C_FindObjectsInit,
1732     C_FindObjects,
1733     C_FindObjectsFinal,
1734     (void *)func_not_supported, /* C_EncryptInit, */
1735     (void *)func_not_supported, /* C_Encrypt, */
1736     (void *)func_not_supported, /* C_EncryptUpdate, */
1737     (void *)func_not_supported, /* C_EncryptFinal, */
1738     (void *)func_not_supported, /* C_DecryptInit, */
1739     (void *)func_not_supported, /* C_Decrypt, */
1740     (void *)func_not_supported, /* C_DecryptUpdate, */
1741     (void *)func_not_supported, /* C_DecryptFinal, */
1742     C_DigestInit,
1743     (void *)func_not_supported, /* C_Digest */
1744     (void *)func_not_supported, /* C_DigestUpdate */
1745     (void *)func_not_supported, /* C_DigestKey */
1746     (void *)func_not_supported, /* C_DigestFinal */
1747     C_SignInit,
1748     C_Sign,
1749     C_SignUpdate,
1750     C_SignFinal,
1751     (void *)func_not_supported, /* C_SignRecoverInit */
1752     (void *)func_not_supported, /* C_SignRecover */
1753     C_VerifyInit,
1754     C_Verify,
1755     C_VerifyUpdate,
1756     C_VerifyFinal,
1757     (void *)func_not_supported, /* C_VerifyRecoverInit */
1758     (void *)func_not_supported, /* C_VerifyRecover */
1759     (void *)func_not_supported, /* C_DigestEncryptUpdate */
1760     (void *)func_not_supported, /* C_DecryptDigestUpdate */
1761     (void *)func_not_supported, /* C_SignEncryptUpdate */
1762     (void *)func_not_supported, /* C_DecryptVerifyUpdate */
1763     (void *)func_not_supported, /* C_GenerateKey */
1764     (void *)func_not_supported, /* C_GenerateKeyPair */
1765     (void *)func_not_supported, /* C_WrapKey */
1766     (void *)func_not_supported, /* C_UnwrapKey */
1767     (void *)func_not_supported, /* C_DeriveKey */
1768     (void *)func_not_supported, /* C_SeedRandom */
1769     C_GenerateRandom,
1770     (void *)func_not_supported, /* C_GetFunctionStatus */
1771     (void *)func_not_supported, /* C_CancelFunction */
1772     (void *)func_not_supported  /* C_WaitForSlotEvent */
1773 };