1 /*
2  * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
3  * Use is subject to license terms specified in the COPYING file
4  * distributed with the Net-SNMP package.
5  */
6 
7 /*
8  * pkcs.c
9  */
10 
11 #include <net-snmp/net-snmp-config.h>
12 #ifdef NETSNMP_USE_PKCS11
13 #include <net-snmp/types.h>
14 #include <net-snmp/output_api.h>
15 #include <net-snmp/config_api.h>
16 #include <net-snmp/library/snmp_api.h>
17 #include <net-snmp/library/tools.h>
18 #include <net-snmp/library/keytools.h>
19 #include <net-snmp/library/scapi.h>
20 #include <net-snmp/library/callback.h>
21 #include <security/cryptoki.h>
22 
23 typedef struct netsnmp_pkcs_slot_session_s {
24     CK_SLOT_ID        sid;
25     CK_SESSION_HANDLE hdl;
26 } netsnmp_pkcs_slot_session;
27 
28 typedef struct netsnmp_pkcs_slot_info_s {
29     int count;
30     netsnmp_pkcs_slot_session *pSession;
31 } netsnmp_pkcs_slot_info;
32 
33 static CK_RV get_session_handle(CK_MECHANISM_TYPE, CK_FLAGS,\
34                                 CK_SESSION_HANDLE_PTR);
35 static CK_RV get_slot_session_handle(netsnmp_pkcs_slot_session *,\
36                                      CK_SESSION_HANDLE_PTR);
37 static char *pkcserr_string(CK_RV);
38 static int free_slots(int, int, void *, void *);
39 
40 static netsnmp_pkcs_slot_info *pSlot = NULL;
41 
42 /*
43  * initialize the Cryptoki library.
44  */
45 int
pkcs_init(void)46 pkcs_init(void)
47 {
48     CK_RV          rv;
49     CK_ULONG       slotcount;
50     CK_SLOT_ID_PTR pSlotList = NULL;
51     netsnmp_pkcs_slot_session    *tmp;
52     int            i, rval = SNMPERR_SUCCESS;
53     /* Initialize pkcs */
54     if ((rv = C_Initialize(NULL)) != CKR_OK) {
55         DEBUGMSGTL(("pkcs_init", "C_Initialize failed: %s",
56                 pkcserr_string(rv)));
57         return SNMPERR_SC_NOT_CONFIGURED;
58     }
59 
60     /* Get slot count */
61     rv = C_GetSlotList(1, NULL_PTR, &slotcount);
62     if (rv != CKR_OK || slotcount == 0) {
63         DEBUGMSGTL(("pkcs_init", "C_GetSlotList failed: %s",
64                 pkcserr_string(rv)));
65         QUITFUN(SNMPERR_GENERR, pkcs_init_quit);
66     }
67 
68     /* Found at least one slot, allocate memory for slot list */
69     pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID));
70     pSlot = malloc(sizeof (netsnmp_pkcs_slot_info));
71     pSlot->pSession = malloc(slotcount * sizeof (netsnmp_pkcs_slot_session));
72 
73     if (pSlotList == NULL_PTR ||
74         pSlot == NULL_PTR ||
75         pSlot->pSession == NULL_PTR) {
76         DEBUGMSGTL(("pkcs_init","malloc failed."));
77         QUITFUN(SNMPERR_GENERR, pkcs_init_quit);
78     }
79 
80     /* Get the list of slots */
81     if ((rv = C_GetSlotList(1, pSlotList, &slotcount)) != CKR_OK) {
82         DEBUGMSGTL(("pkcs_init", "C_GetSlotList failed: %s",
83                 pkcserr_string(rv)));
84         QUITFUN(SNMPERR_GENERR, pkcs_init_quit);
85     }
86 
87     /* initialize Slots structure */
88     pSlot->count = slotcount;
89     for (i = 0, tmp = pSlot->pSession; i < slotcount; i++, tmp++) {
90         tmp->sid = pSlotList[i];
91         tmp->hdl = NULL;
92     }
93 
94     snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
95                         free_slots, NULL);
96 
97   pkcs_init_quit:
98     SNMP_FREE(pSlotList);
99     return rval;
100 }
101 
102 /*
103  * close all the opened sessions when finished with Cryptoki library.
104  */
105 static int
free_slots(int majorID,int minorID,void * serverarg,void * clientarg)106 free_slots(int majorID, int minorID, void *serverarg, void *clientarg)
107 {
108     int            slotcount, i;
109 
110     if (pSlot != NULL) {
111         slotcount = pSlot->count;
112         for (i = 0; i < slotcount; i++) {
113             if (pSlot->pSession->hdl != NULL) {
114                 free(pSlot->pSession->hdl);
115             }
116         }
117         free(pSlot);
118     }
119 
120     (void) C_Finalize(NULL);
121     return 0;
122 }
123 
124 /*
125  * generate random data
126  */
127 int
pkcs_random(u_char * buf,size_t buflen)128 pkcs_random(u_char * buf, size_t buflen)
129 {
130     CK_SESSION_HANDLE hSession;
131 
132     if (pSlot != NULL &&
133         get_slot_session_handle(pSlot->pSession, &hSession) == CKR_OK &&
134         C_GenerateRandom(hSession, buf, buflen) == CKR_OK) {
135         return SNMPERR_SUCCESS;
136     }
137 
138     return SNMPERR_GENERR;
139 }
140 
141 /*
142  * retrieve the session handle from the first slot that supports the specified
143  * mechanism.
144  */
145 static CK_RV
get_session_handle(CK_MECHANISM_TYPE mech_type,CK_FLAGS flag,CK_SESSION_HANDLE_PTR sess)146 get_session_handle(CK_MECHANISM_TYPE mech_type, CK_FLAGS flag,
147                 CK_SESSION_HANDLE_PTR sess)
148 {
149     CK_RV             rv = CKR_OK;
150     CK_MECHANISM_INFO info;
151     netsnmp_pkcs_slot_session       *p = NULL;
152     int               i, slotcount = 0;
153 
154     if (pSlot) {
155         slotcount = pSlot->count;
156         p = pSlot->pSession;
157     }
158 
159     /* Find a slot with matching mechanism */
160     for (i = 0; i < slotcount; i++, p++) {
161         rv = C_GetMechanismInfo(p->sid, mech_type, &info);
162 
163         if (rv != CKR_OK) {
164             continue; /* to the next slot */
165         } else {
166             if (info.flags & flag) {
167                 rv = get_slot_session_handle(p, sess);
168                 break; /* found */
169             }
170         }
171     }
172 
173     /* Show error if no matching mechanism found */
174     if (i == slotcount) {
175         DEBUGMSGTL(("pkcs_init","No cryptographic provider for %s",
176                 mech_type));
177         return CKR_SESSION_HANDLE_INVALID;
178     }
179 
180     return rv;
181 }
182 
183 /*
184  * retrieve the session handle from the specified slot.
185  */
186 static CK_RV
get_slot_session_handle(netsnmp_pkcs_slot_session * p,CK_SESSION_HANDLE_PTR sess)187 get_slot_session_handle(netsnmp_pkcs_slot_session *p,
188                         CK_SESSION_HANDLE_PTR sess)
189 {
190     CK_RV rv = CKR_OK;
191     if (p == NULL) {
192         *sess = NULL;
193         return CKR_SESSION_HANDLE_INVALID;
194     }
195 
196     if (p->hdl == NULL) {
197         /* Open a session */
198         rv = C_OpenSession(p->sid, CKF_SERIAL_SESSION,
199                 NULL_PTR, NULL, &p->hdl);
200 
201         if (rv != CKR_OK) {
202             DEBUGMSGTL(("get_slot_session_handle","can not open PKCS #11 session: %s",
203                         pkcserr_string(rv)));
204         }
205     }
206     *sess = p->hdl;
207 
208     return rv;
209 }
210 
211 /*
212  * perform a signature operation to generate MAC.
213  */
214 int
pkcs_sign(CK_MECHANISM_TYPE mech_type,u_char * key,u_int keylen,u_char * msg,u_int msglen,u_char * mac,size_t * maclen)215 pkcs_sign(CK_MECHANISM_TYPE mech_type, u_char * key, u_int keylen,
216           u_char * msg, u_int msglen, u_char * mac, size_t * maclen)
217 {
218     /*
219      * Key template
220      */
221     CK_OBJECT_CLASS class = CKO_SECRET_KEY;
222     CK_KEY_TYPE keytype = CKK_GENERIC_SECRET;
223     CK_BBOOL truevalue = TRUE;
224     CK_BBOOL falsevalue= FALSE;
225     CK_ATTRIBUTE template[] = {
226         {CKA_CLASS, &class, sizeof (class)},
227         {CKA_KEY_TYPE, &keytype, sizeof (keytype)},
228         {CKA_SIGN, &truevalue, sizeof (truevalue)},
229         {CKA_TOKEN, &falsevalue, sizeof (falsevalue)},
230         {CKA_VALUE, key, keylen}
231     };
232     CK_SESSION_HANDLE hSession;
233     CK_MECHANISM mech;
234     CK_OBJECT_HANDLE hkey = (CK_OBJECT_HANDLE) 0;
235     int                rval = SNMPERR_SUCCESS;
236     if (get_session_handle(mech_type, CKF_SIGN, &hSession) != CKR_OK ||
237         hSession == NULL) {
238         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
239     }
240 
241     /* create a key object */
242     if (C_CreateObject(hSession, template,
243         (sizeof (template) / sizeof (CK_ATTRIBUTE)), &hkey) != CKR_OK) {
244         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
245     }
246 
247     mech.mechanism = mech_type;
248     mech.pParameter = NULL_PTR;
249     mech.ulParameterLen = 0;
250 
251     /* initialize a signature operation */
252     if (C_SignInit(hSession, &mech, hkey) != CKR_OK ) {
253         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
254     }
255     /* continue a multiple-part signature operation */
256     if (C_SignUpdate(hSession, msg, msglen) != CKR_OK) {
257         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
258     }
259     /* finish a multiple-part signature operation */
260     if (C_SignFinal(hSession, mac, maclen) != CKR_OK) {
261         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
262     }
263 
264   pkcs_sign_quit:
265 
266     if (key != (CK_OBJECT_HANDLE) 0) {
267         (void) C_DestroyObject(hSession, hkey);
268     }
269     return rval;
270 }
271 
272 /*
273  * perform a message-digesting operation.
274  */
275 int
pkcs_digest(CK_MECHANISM_TYPE mech_type,u_char * msg,u_int msglen,u_char * digest,size_t * digestlen)276 pkcs_digest(CK_MECHANISM_TYPE mech_type, u_char * msg, u_int msglen,
277             u_char * digest, size_t * digestlen)
278 {
279     int               rval = SNMPERR_SUCCESS;
280     CK_SESSION_HANDLE hSession;
281     CK_MECHANISM      mech;
282     if (get_session_handle(mech_type, CKF_DIGEST, &hSession) != CKR_OK ||
283         hSession == NULL) {
284         QUITFUN(SNMPERR_GENERR, pkcs_digest_quit);
285     }
286 
287     mech.mechanism = mech_type;
288     mech.pParameter = NULL_PTR;
289     mech.ulParameterLen = 0;
290 
291     /* initialize a message-digesting operation */
292     if (C_DigestInit(hSession, &mech)!= CKR_OK ) {
293         QUITFUN(SNMPERR_GENERR, pkcs_digest_quit);
294     }
295     /* continue a multiple-part message-digesting operation */
296     if (C_DigestUpdate(hSession, msg, msglen) != CKR_OK ) {
297         QUITFUN(SNMPERR_GENERR, pkcs_digest_quit);
298     }
299     /* finish a multiple-part message-digesting operation */
300     if (C_DigestFinal(hSession, digest, digestlen) != CKR_OK) {
301         QUITFUN(SNMPERR_GENERR, pkcs_digest_quit);
302     }
303 
304   pkcs_digest_quit:
305     return rval;
306 }
307 
308 /*
309  * encrypt plaintext into ciphertext using key and iv.
310  */
311 int
pkcs_encrpyt(CK_MECHANISM_TYPE mech_type,u_char * key,u_int keylen,u_char * iv,u_int ivlen,u_char * plaintext,u_int ptlen,u_char * ciphertext,size_t * ctlen)312 pkcs_encrpyt(CK_MECHANISM_TYPE mech_type, u_char * key, u_int keylen,
313              u_char * iv, u_int ivlen,
314              u_char * plaintext, u_int ptlen,
315              u_char * ciphertext, size_t * ctlen)
316 {
317     int                rval = SNMPERR_SUCCESS;
318     int                pad_size, offset;
319     /*
320      * Key template
321      */
322     CK_OBJECT_CLASS class = CKO_SECRET_KEY;
323     CK_KEY_TYPE keytype = CKK_DES;
324     /* CK_KEY_TYPE AESkeytype = CKK_AES; */
325     CK_BBOOL truevalue = TRUE;
326     CK_BBOOL falsevalue = FALSE;
327 
328     CK_ATTRIBUTE template[] = {
329         {CKA_CLASS, &class, sizeof (class)},
330         {CKA_KEY_TYPE, &keytype, sizeof (keytype)},
331         {CKA_ENCRYPT, &truevalue, sizeof (truevalue)},
332         {CKA_TOKEN, &falsevalue, sizeof (falsevalue)},
333         {CKA_VALUE, key, keylen}
334     };
335 
336     CK_SESSION_HANDLE hSession;
337     CK_MECHANISM mech;
338     CK_OBJECT_HANDLE hkey = (CK_OBJECT_HANDLE) 0;
339 
340     if (get_session_handle(mech_type, CKF_ENCRYPT,
341                            &hSession) != CKR_OK ||
342         hSession == NULL) {
343         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
344     }
345 
346     if (C_CreateObject(hSession, template,
347         (sizeof (template) / sizeof (CK_ATTRIBUTE)),
348                                 &hkey) != CKR_OK) {
349         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
350     }
351 
352     mech.mechanism = mech_type;
353     mech.pParameter = iv;
354     mech.ulParameterLen = ivlen;
355 
356     /* initialize an encryption operation */
357     if (C_EncryptInit(hSession, &mech, hkey) != CKR_OK ) {
358         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
359     }
360 
361     /* for DES */
362     pad_size = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
363 
364     if (ptlen + pad_size - ptlen % pad_size > *ctlen) {
365         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
366     }
367 
368     for (offset = 0; offset < ptlen; offset += pad_size) {
369         /* continue a multiple-part encryption operation */
370         if (C_EncryptUpdate(hSession, plaintext + offset, pad_size,
371                             ciphertext + offset, ctlen) != CKR_OK) {
372             QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
373         }
374     }
375 
376     /* finish a multiple-part encryption operation */
377     if (C_EncryptFinal(hSession, ciphertext + offset, ctlen) != CKR_OK) {
378         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
379     }
380     *ctlen = offset;
381 
382   pkcs_encrypt_quit:
383     if (key != (CK_OBJECT_HANDLE) 0) {
384         (void) C_DestroyObject(hSession, hkey);
385     }
386     return rval;
387 }
388 
389 /*
390  * decrypt ciphertext into plaintext using key and iv.
391  */
392 int
pkcs_decrpyt(CK_MECHANISM_TYPE mech_type,u_char * key,u_int keylen,u_char * iv,u_int ivlen,u_char * ciphertext,u_int ctlen,u_char * plaintext,size_t * ptlen)393 pkcs_decrpyt(CK_MECHANISM_TYPE mech_type, u_char * key, u_int keylen,
394              u_char * iv, u_int ivlen,
395              u_char * ciphertext, u_int ctlen,
396              u_char * plaintext, size_t * ptlen)
397 {
398     int            rval = SNMPERR_SUCCESS;
399     /*
400      * Key template
401      */
402     CK_OBJECT_CLASS class = CKO_SECRET_KEY;
403     CK_KEY_TYPE keytype = CKK_DES;
404     /* CK_KEY_TYPE AESkeytype = CKK_AES; */
405     CK_BBOOL truevalue = TRUE;
406     CK_BBOOL falsevalue= FALSE;
407     CK_ATTRIBUTE template[] = {
408         {CKA_CLASS, &class, sizeof (class)},
409         {CKA_KEY_TYPE, &keytype, sizeof (keytype)},
410         {CKA_DECRYPT, &truevalue, sizeof (truevalue)},
411         {CKA_TOKEN, &falsevalue, sizeof (falsevalue)},
412         {CKA_VALUE, key, keylen}
413     };
414     CK_SESSION_HANDLE hSession;
415     CK_MECHANISM mech;
416     CK_OBJECT_HANDLE hkey = (CK_OBJECT_HANDLE) 0;
417 
418     if (get_session_handle(mech_type, CKF_DECRYPT, &hSession) != CKR_OK ||
419         hSession == NULL) {
420         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
421     }
422 
423     if (C_CreateObject(hSession, template,
424         (sizeof (template) / sizeof (CK_ATTRIBUTE)), &hkey) != CKR_OK) {
425         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
426     }
427 
428     mech.mechanism = mech_type;
429     mech.pParameter = iv;
430     mech.ulParameterLen = ivlen;
431 
432     /* initialize a decryption operation */
433     if (C_DecryptInit(hSession, &mech, hkey) != CKR_OK ) {
434         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
435     }
436     /* continue a multiple-part decryption operation */
437     if (C_DecryptUpdate(hSession, ciphertext, ctlen, plaintext,
438                                         ptlen) != CKR_OK) {
439         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
440     }
441     /* finish a multiple-part decryption operation */
442     if (C_DecryptFinal(hSession, plaintext, ptlen) != CKR_OK) {
443         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
444     }
445 
446   pkcs_decrypt_quit:
447     if (key != (CK_OBJECT_HANDLE) 0) {
448         (void) C_DestroyObject(hSession, hkey);
449     }
450     return rval;
451 }
452 
453 /*
454  * Convert a passphrase into a master user key, Ku, according to the
455  * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM)
456  */
457 int
pkcs_generate_Ku(CK_MECHANISM_TYPE mech_type,u_char * passphrase,u_int pplen,u_char * Ku,size_t * kulen)458 pkcs_generate_Ku(CK_MECHANISM_TYPE mech_type, u_char * passphrase, u_int pplen,
459                  u_char * Ku, size_t * kulen)
460 {
461     int                rval = SNMPERR_SUCCESS, nbytes = USM_LENGTH_EXPANDED_PASSPHRASE;
462     CK_SESSION_HANDLE hSession;
463     CK_MECHANISM mech;
464     u_int        i, pindex = 0;
465     u_char        buf[USM_LENGTH_KU_HASHBLOCK], *bufp;
466 
467     if (get_session_handle(mech_type, CKF_DIGEST, &hSession) != CKR_OK ||
468         hSession == NULL) {
469         QUITFUN(SNMPERR_GENERR, pkcs_generate_Ku_quit);
470     }
471 
472     mech.mechanism = mech_type;
473     mech.pParameter = NULL_PTR;
474     mech.ulParameterLen = 0;
475 
476     /* initialize a message-digesting operation */
477     if (C_DigestInit(hSession, &mech)!= CKR_OK ) {
478         QUITFUN(SNMPERR_GENERR, pkcs_generate_Ku_quit);
479     }
480 
481     while (nbytes > 0) {
482         bufp = buf;
483         for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) {
484            /*
485 	    * fill a buffer with the supplied passphrase.  When the end
486             * of the passphrase is reachedcycle back to the beginning.
487             */
488             *bufp++ = passphrase[pindex++ % pplen];
489         }
490         /* continue a multiple-part message-digesting operation */
491         if (C_DigestUpdate(hSession, buf, USM_LENGTH_KU_HASHBLOCK) != CKR_OK ) {
492             QUITFUN(SNMPERR_GENERR, pkcs_generate_Ku_quit);
493         }
494         nbytes -= USM_LENGTH_KU_HASHBLOCK;
495     }
496     /* finish a multiple-part message-digesting operation */
497     if (C_DigestFinal(hSession, Ku, kulen) != CKR_OK) {
498         QUITFUN(SNMPERR_GENERR, pkcs_generate_Ku_quit);
499     }
500 
501   pkcs_generate_Ku_quit:
502     return rval;
503 }
504 
505 /*
506  * pkcserr_stringor: returns a string representation of the given
507  * return code.
508  */
509 static char *
pkcserr_string(CK_RV rv)510 pkcserr_string(CK_RV rv)
511 {
512     static char errstr[128];
513     switch (rv) {
514     case CKR_OK:
515         return ("CKR_OK");
516         break;
517     case CKR_CANCEL:
518         return ("CKR_CANCEL");
519         break;
520     case CKR_HOST_MEMORY:
521         return ("CKR_HOST_MEMORY");
522         break;
523     case CKR_SLOT_ID_INVALID:
524         return ("CKR_SLOT_ID_INVALID");
525         break;
526     case CKR_GENERAL_ERROR:
527         return ("CKR_GENERAL_ERROR");
528         break;
529     case CKR_FUNCTION_FAILED:
530         return ("CKR_FUNCTION_FAILED");
531         break;
532     case CKR_ARGUMENTS_BAD:
533         return ("CKR_ARGUMENTS_BAD");
534         break;
535     case CKR_NO_EVENT:
536         return ("CKR_NO_EVENT");
537         break;
538     case CKR_NEED_TO_CREATE_THREADS:
539         return ("CKR_NEED_TO_CREATE_THREADS");
540         break;
541     case CKR_CANT_LOCK:
542         return ("CKR_CANT_LOCK");
543         break;
544     case CKR_ATTRIBUTE_READ_ONLY:
545         return ("CKR_ATTRIBUTE_READ_ONLY");
546         break;
547     case CKR_ATTRIBUTE_SENSITIVE:
548         return ("CKR_ATTRIBUTE_SENSITIVE");
549         break;
550     case CKR_ATTRIBUTE_TYPE_INVALID:
551         return ("CKR_ATTRIBUTE_TYPE_INVALID");
552         break;
553     case CKR_ATTRIBUTE_VALUE_INVALID:
554         return ("CKR_ATTRIBUTE_VALUE_INVALID");
555         break;
556     case CKR_DATA_INVALID:
557         return ("CKR_DATA_INVALID");
558         break;
559     case CKR_DATA_LEN_RANGE:
560         return ("CKR_DATA_LEN_RANGE");
561         break;
562     case CKR_DEVICE_ERROR:
563         return ("CKR_DEVICE_ERROR");
564         break;
565     case CKR_DEVICE_MEMORY:
566         return ("CKR_DEVICE_MEMORY");
567         break;
568     case CKR_DEVICE_REMOVED:
569         return ("CKR_DEVICE_REMOVED");
570         break;
571     case CKR_ENCRYPTED_DATA_INVALID:
572         return ("CKR_ENCRYPTED_DATA_INVALID");
573         break;
574     case CKR_ENCRYPTED_DATA_LEN_RANGE:
575         return ("CKR_ENCRYPTED_DATA_LEN_RANGE");
576         break;
577     case CKR_FUNCTION_CANCELED:
578         return ("CKR_FUNCTION_CANCELED");
579         break;
580     case CKR_FUNCTION_NOT_PARALLEL:
581         return ("CKR_FUNCTION_NOT_PARALLEL");
582         break;
583     case CKR_FUNCTION_NOT_SUPPORTED:
584         return ("CKR_FUNCTION_NOT_SUPPORTED");
585         break;
586     case CKR_KEY_HANDLE_INVALID:
587         return ("CKR_KEY_HANDLE_INVALID");
588         break;
589     case CKR_KEY_SIZE_RANGE:
590         return ("CKR_KEY_SIZE_RANGE");
591         break;
592     case CKR_KEY_TYPE_INCONSISTENT:
593         return ("CKR_KEY_TYPE_INCONSISTENT");
594         break;
595     case CKR_KEY_NOT_NEEDED:
596         return ("CKR_KEY_NOT_NEEDED");
597         break;
598     case CKR_KEY_CHANGED:
599         return ("CKR_KEY_CHANGED");
600         break;
601     case CKR_KEY_NEEDED:
602         return ("CKR_KEY_NEEDED");
603         break;
604     case CKR_KEY_INDIGESTIBLE:
605         return ("CKR_KEY_INDIGESTIBLE");
606         break;
607     case CKR_KEY_FUNCTION_NOT_PERMITTED:
608         return ("CKR_KEY_FUNCTION_NOT_PERMITTED");
609         break;
610     case CKR_KEY_NOT_WRAPPABLE:
611         return ("CKR_KEY_NOT_WRAPPABLE");
612         break;
613     case CKR_KEY_UNEXTRACTABLE:
614         return ("CKR_KEY_UNEXTRACTABLE");
615         break;
616     case CKR_MECHANISM_INVALID:
617         return ("CKR_MECHANISM_INVALID");
618         break;
619     case CKR_MECHANISM_PARAM_INVALID:
620         return ("CKR_MECHANISM_PARAM_INVALID");
621         break;
622     case CKR_OBJECT_HANDLE_INVALID:
623         return ("CKR_OBJECT_HANDLE_INVALID");
624         break;
625     case CKR_OPERATION_ACTIVE:
626         return ("CKR_OPERATION_ACTIVE");
627         break;
628     case CKR_OPERATION_NOT_INITIALIZED:
629         return ("CKR_OPERATION_NOT_INITIALIZED");
630         break;
631     case CKR_PIN_INCORRECT:
632         return ("CKR_PIN_INCORRECT");
633         break;
634     case CKR_PIN_INVALID:
635         return ("CKR_PIN_INVALID");
636         break;
637     case CKR_PIN_LEN_RANGE:
638         return ("CKR_PIN_LEN_RANGE");
639         break;
640     case CKR_PIN_EXPIRED:
641         return ("CKR_PIN_EXPIRED");
642         break;
643     case CKR_PIN_LOCKED:
644         return ("CKR_PIN_LOCKED");
645         break;
646     case CKR_SESSION_CLOSED:
647         return ("CKR_SESSION_CLOSED");
648         break;
649     case CKR_SESSION_COUNT:
650         return ("CKR_SESSION_COUNT");
651         break;
652     case CKR_SESSION_HANDLE_INVALID:
653         return ("CKR_SESSION_HANDLE_INVALID");
654         break;
655     case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
656         return ("CKR_SESSION_PARALLEL_NOT_SUPPORTED");
657         break;
658     case CKR_SESSION_READ_ONLY:
659         return ("CKR_SESSION_READ_ONLY");
660         break;
661     case CKR_SESSION_EXISTS:
662         return ("CKR_SESSION_EXISTS");
663         break;
664     case CKR_SESSION_READ_ONLY_EXISTS:
665         return ("CKR_SESSION_READ_ONLY_EXISTS");
666         break;
667     case CKR_SESSION_READ_WRITE_SO_EXISTS:
668         return ("CKR_SESSION_READ_WRITE_SO_EXISTS");
669         break;
670     case CKR_SIGNATURE_INVALID:
671         return ("CKR_SIGNATURE_INVALID");
672         break;
673     case CKR_SIGNATURE_LEN_RANGE:
674         return ("CKR_SIGNATURE_LEN_RANGE");
675         break;
676     case CKR_TEMPLATE_INCOMPLETE:
677         return ("CKR_TEMPLATE_INCOMPLETE");
678         break;
679     case CKR_TEMPLATE_INCONSISTENT:
680         return ("CKR_TEMPLATE_INCONSISTENT");
681         break;
682     case CKR_TOKEN_NOT_PRESENT:
683         return ("CKR_TOKEN_NOT_PRESENT");
684         break;
685     case CKR_TOKEN_NOT_RECOGNIZED:
686         return ("CKR_TOKEN_NOT_RECOGNIZED");
687         break;
688     case CKR_TOKEN_WRITE_PROTECTED:
689         return ("CKR_TOKEN_WRITE_PROTECTED");
690         break;
691     case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
692         return ("CKR_UNWRAPPING_KEY_HANDLE_INVALID");
693         break;
694     case CKR_UNWRAPPING_KEY_SIZE_RANGE:
695         return ("CKR_UNWRAPPING_KEY_SIZE_RANGE");
696         break;
697     case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
698         return ("CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT");
699         break;
700     case CKR_USER_ALREADY_LOGGED_IN:
701         return ("CKR_USER_ALREADY_LOGGED_IN");
702         break;
703     case CKR_USER_NOT_LOGGED_IN:
704         return ("CKR_USER_NOT_LOGGED_IN");
705         break;
706     case CKR_USER_PIN_NOT_INITIALIZED:
707         return ("CKR_USER_PIN_NOT_INITIALIZED");
708         break;
709     case CKR_USER_TYPE_INVALID:
710         return ("CKR_USER_TYPE_INVALID");
711         break;
712     case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
713         return ("CKR_USER_ANOTHER_ALREADY_LOGGED_IN");
714         break;
715     case CKR_USER_TOO_MANY_TYPES:
716         return ("CKR_USER_TOO_MANY_TYPES");
717         break;
718     case CKR_WRAPPED_KEY_INVALID:
719         return ("CKR_WRAPPED_KEY_INVALID");
720         break;
721     case CKR_WRAPPED_KEY_LEN_RANGE:
722         return ("CKR_WRAPPED_KEY_LEN_RANGE");
723         break;
724     case CKR_WRAPPING_KEY_HANDLE_INVALID:
725         return ("CKR_WRAPPING_KEY_HANDLE_INVALID");
726         break;
727     case CKR_WRAPPING_KEY_SIZE_RANGE:
728         return ("CKR_WRAPPING_KEY_SIZE_RANGE");
729         break;
730     case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
731         return ("CKR_WRAPPING_KEY_TYPE_INCONSISTENT");
732         break;
733     case CKR_RANDOM_SEED_NOT_SUPPORTED:
734         return ("CKR_RANDOM_SEED_NOT_SUPPORTED");
735         break;
736     case CKR_RANDOM_NO_RNG:
737         return ("CKR_RANDOM_NO_RNG");
738         break;
739     case CKR_DOMAIN_PARAMS_INVALID:
740         return ("CKR_DOMAIN_PARAMS_INVALID");
741         break;
742     case CKR_BUFFER_TOO_SMALL:
743         return ("CKR_BUFFER_TOO_SMALL");
744         break;
745     case CKR_SAVED_STATE_INVALID:
746         return ("CKR_SAVED_STATE_INVALID");
747         break;
748     case CKR_INFORMATION_SENSITIVE:
749         return ("CKR_INFORMATION_SENSITIVE");
750         break;
751     case CKR_STATE_UNSAVEABLE:
752         return ("CKR_STATE_UNSAVEABLE");
753         break;
754     case CKR_CRYPTOKI_NOT_INITIALIZED:
755         return ("CKR_CRYPTOKI_NOT_INITIALIZED");
756         break;
757     case CKR_CRYPTOKI_ALREADY_INITIALIZED:
758         return ("CKR_CRYPTOKI_ALREADY_INITIALIZED");
759         break;
760     case CKR_MUTEX_BAD:
761         return ("CKR_MUTEX_BAD");
762         break;
763     case CKR_MUTEX_NOT_LOCKED:
764         return ("CKR_MUTEX_NOT_LOCKED");
765         break;
766     case CKR_VENDOR_DEFINED:
767         return ("CKR_VENDOR_DEFINED");
768         break;
769     default:
770         /* rv not found */
771         snprintf(errstr, sizeof (errstr),
772             "Unknown return code: 0x%x", rv);
773         return (errstr);
774         break;
775     }
776 }
777 #else
778 int pkcs_unused;	/* Suppress "empty translation unit" warning */
779 #endif
780