net-snmp 5.7
pkcs.c
00001 /*
00002  * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
00003  * Use is subject to license terms specified in the COPYING file
00004  * distributed with the Net-SNMP package.
00005  */
00006 
00007 /*
00008  * pkcs.c
00009  */
00010 
00011 #include <net-snmp/net-snmp-config.h>
00012 #ifdef NETSNMP_USE_PKCS11
00013 #include <net-snmp/types.h>
00014 #include <net-snmp/output_api.h>
00015 #include <net-snmp/config_api.h>
00016 #include <net-snmp/library/snmp_api.h>
00017 #include <net-snmp/library/tools.h>
00018 #include <net-snmp/library/keytools.h>
00019 #include <net-snmp/library/scapi.h>
00020 #include <net-snmp/library/callback.h>
00021 #include <security/cryptoki.h>
00022 
00023 typedef struct netsnmp_pkcs_slot_session_s {
00024     CK_SLOT_ID        sid;
00025     CK_SESSION_HANDLE hdl;
00026 } netsnmp_pkcs_slot_session; 
00027 
00028 typedef struct netsnmp_pkcs_slot_info_s {
00029     int count;
00030     netsnmp_pkcs_slot_session *pSession; 
00031 } netsnmp_pkcs_slot_info;
00032 
00033 static CK_RV get_session_handle(CK_MECHANISM_TYPE, CK_FLAGS,\
00034                                 CK_SESSION_HANDLE_PTR);
00035 static CK_RV get_slot_session_handle(netsnmp_pkcs_slot_session *,\
00036                                      CK_SESSION_HANDLE_PTR);
00037 static char *pkcserr_string(CK_RV);
00038 static int free_slots(int, int, void *, void *);
00039 
00040 static netsnmp_pkcs_slot_info *pSlot = NULL;
00041 
00042 /*
00043  * initialize the Cryptoki library.
00044  */
00045 int
00046 pkcs_init(void)
00047 {
00048     CK_RV          rv;
00049     CK_ULONG       slotcount;
00050     CK_SLOT_ID_PTR pSlotList = NULL;
00051     netsnmp_pkcs_slot_session    *tmp;
00052     int            i, rval = SNMPERR_SUCCESS;
00053     /* Initialize pkcs */
00054     if ((rv = C_Initialize(NULL)) != CKR_OK) {
00055         DEBUGMSGTL(("pkcs_init", "C_Initialize failed: %s",
00056                 pkcserr_string(rv)));
00057         return SNMPERR_SC_NOT_CONFIGURED;
00058     }
00059 
00060     /* Get slot count */
00061     rv = C_GetSlotList(1, NULL_PTR, &slotcount);
00062     if (rv != CKR_OK || slotcount == 0) {
00063         DEBUGMSGTL(("pkcs_init", "C_GetSlotList failed: %s", 
00064                 pkcserr_string(rv)));
00065         QUITFUN(SNMPERR_GENERR, pkcs_init_quit);
00066     }
00067 
00068     /* Found at least one slot, allocate memory for slot list */
00069     pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID));
00070     pSlot = malloc(sizeof (netsnmp_pkcs_slot_info));
00071     pSlot->pSession = malloc(slotcount * sizeof (netsnmp_pkcs_slot_session));
00072 
00073     if (pSlotList == NULL_PTR ||
00074         pSlot == NULL_PTR ||
00075         pSlot->pSession == NULL_PTR) {
00076         DEBUGMSGTL(("pkcs_init","malloc failed.")); 
00077         QUITFUN(SNMPERR_GENERR, pkcs_init_quit);
00078     }
00079 
00080     /* Get the list of slots */
00081     if ((rv = C_GetSlotList(1, pSlotList, &slotcount)) != CKR_OK) {
00082         DEBUGMSGTL(("pkcs_init", "C_GetSlotList failed: %s", 
00083                 pkcserr_string(rv)));
00084         QUITFUN(SNMPERR_GENERR, pkcs_init_quit);
00085     }
00086 
00087     /* initialize Slots structure */
00088     pSlot->count = slotcount;
00089     for (i = 0, tmp = pSlot->pSession; i < slotcount; i++, tmp++) {
00090         tmp->sid = pSlotList[i]; 
00091         tmp->hdl = NULL;
00092     }
00093 
00094     snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
00095                         free_slots, NULL);
00096 
00097   pkcs_init_quit:
00098     SNMP_FREE(pSlotList);
00099     return rval;
00100 }
00101 
00102 /*
00103  * close all the opened sessions when finished with Cryptoki library.
00104  */
00105 static int
00106 free_slots(int majorID, int minorID, void *serverarg, void *clientarg)
00107 {
00108     int            slotcount, i;
00109 
00110     if (pSlot != NULL) {
00111         slotcount = pSlot->count;
00112         for (i = 0; i < slotcount; i++) {
00113             if (pSlot->pSession->hdl != NULL) {
00114                 free(pSlot->pSession->hdl);
00115             }
00116         }
00117         free(pSlot);
00118     }
00119 
00120     (void) C_Finalize(NULL);
00121     return 0;
00122 }
00123 
00124 /*
00125  * generate random data
00126  */
00127 int
00128 pkcs_random(u_char * buf, size_t buflen)
00129 {
00130     CK_SESSION_HANDLE hSession;
00131 
00132     if (pSlot != NULL &&
00133         get_slot_session_handle(pSlot->pSession, &hSession) == CKR_OK &&
00134         C_GenerateRandom(hSession, buf, buflen) == CKR_OK) {
00135         return SNMPERR_SUCCESS;
00136     }
00137 
00138     return SNMPERR_GENERR;
00139 }
00140 
00141 /*
00142  * retrieve the session handle from the first slot that supports the specified
00143  * mechanism.
00144  */
00145 static CK_RV
00146 get_session_handle(CK_MECHANISM_TYPE mech_type, CK_FLAGS flag,
00147                 CK_SESSION_HANDLE_PTR sess)
00148 {
00149     CK_RV             rv = CKR_OK;
00150     CK_MECHANISM_INFO info;
00151     netsnmp_pkcs_slot_session       *p = NULL;
00152     int               i, slotcount = 0;
00153             
00154     if (pSlot) {
00155         slotcount = pSlot->count;
00156         p = pSlot->pSession;
00157     }
00158 
00159     /* Find a slot with matching mechanism */
00160     for (i = 0; i < slotcount; i++, p++) {
00161         rv = C_GetMechanismInfo(p->sid, mech_type, &info);
00162 
00163         if (rv != CKR_OK) {
00164             continue; /* to the next slot */
00165         } else {
00166             if (info.flags & flag) {
00167                 rv = get_slot_session_handle(p, sess);
00168                 break; /* found */
00169             }
00170         }
00171     }
00172 
00173     /* Show error if no matching mechanism found */
00174     if (i == slotcount) {
00175         DEBUGMSGTL(("pkcs_init","No cryptographic provider for %s",
00176                 mech_type)); 
00177         return CKR_SESSION_HANDLE_INVALID;
00178     }
00179 
00180     return rv;
00181 }
00182 
00183 /*
00184  * retrieve the session handle from the specified slot.
00185  */
00186 static CK_RV
00187 get_slot_session_handle(netsnmp_pkcs_slot_session *p,
00188                         CK_SESSION_HANDLE_PTR sess)
00189 {
00190     CK_RV rv = CKR_OK;
00191     if (p == NULL) {
00192         *sess = NULL;
00193         return CKR_SESSION_HANDLE_INVALID;
00194     }
00195 
00196     if (p->hdl == NULL) {
00197         /* Open a session */
00198         rv = C_OpenSession(p->sid, CKF_SERIAL_SESSION,
00199                 NULL_PTR, NULL, &p->hdl);
00200 
00201         if (rv != CKR_OK) {
00202             DEBUGMSGTL(("get_slot_session_handle","can not open PKCS #11 session: %s",
00203                         pkcserr_string(rv)));
00204         }
00205     }
00206     *sess = p->hdl;
00207 
00208     return rv;
00209 }
00210 
00211 /*
00212  * perform a signature operation to generate MAC.
00213  */
00214 int
00215 pkcs_sign(CK_MECHANISM_TYPE mech_type, u_char * key, u_int keylen,
00216           u_char * msg, u_int msglen, u_char * mac, size_t * maclen)
00217 {
00218     /*
00219      * Key template 
00220      */
00221     CK_OBJECT_CLASS class = CKO_SECRET_KEY;
00222     CK_KEY_TYPE keytype = CKK_GENERIC_SECRET;
00223     CK_BBOOL truevalue = TRUE;
00224     CK_BBOOL falsevalue= FALSE;
00225     CK_ATTRIBUTE template[] = {
00226         {CKA_CLASS, &class, sizeof (class)},
00227         {CKA_KEY_TYPE, &keytype, sizeof (keytype)},
00228         {CKA_SIGN, &truevalue, sizeof (truevalue)},
00229         {CKA_TOKEN, &falsevalue, sizeof (falsevalue)},
00230         {CKA_VALUE, key, keylen}
00231     };
00232     CK_SESSION_HANDLE hSession;
00233     CK_MECHANISM mech;
00234     CK_OBJECT_HANDLE hkey = (CK_OBJECT_HANDLE) 0;
00235     int                rval = SNMPERR_SUCCESS;
00236     if (get_session_handle(mech_type, CKF_SIGN, &hSession) != CKR_OK ||
00237         hSession == NULL) {
00238         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
00239     }
00240 
00241     /* create a key object */
00242     if (C_CreateObject(hSession, template,
00243         (sizeof (template) / sizeof (CK_ATTRIBUTE)), &hkey) != CKR_OK) {
00244         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
00245     }
00246 
00247     mech.mechanism = mech_type;
00248     mech.pParameter = NULL_PTR;
00249     mech.ulParameterLen = 0;
00250 
00251     /* initialize a signature operation */
00252     if (C_SignInit(hSession, &mech, hkey) != CKR_OK ) {
00253         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
00254     }
00255     /* continue a multiple-part signature operation */
00256     if (C_SignUpdate(hSession, msg, msglen) != CKR_OK) {
00257         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
00258     }
00259     /* finish a multiple-part signature operation */
00260     if (C_SignFinal(hSession, mac, maclen) != CKR_OK) {
00261         QUITFUN(SNMPERR_GENERR, pkcs_sign_quit);
00262     }
00263 
00264   pkcs_sign_quit:
00265 
00266     if (key != (CK_OBJECT_HANDLE) 0) {
00267         (void) C_DestroyObject(hSession, hkey);
00268     }
00269     return rval;
00270 }
00271 
00272 /*
00273  * perform a message-digesting operation.
00274  */
00275 int
00276 pkcs_digest(CK_MECHANISM_TYPE mech_type, u_char * msg, u_int msglen,
00277             u_char * digest, size_t * digestlen)
00278 {
00279     int               rval = SNMPERR_SUCCESS;
00280     CK_SESSION_HANDLE hSession;
00281     CK_MECHANISM      mech;
00282     if (get_session_handle(mech_type, CKF_DIGEST, &hSession) != CKR_OK ||
00283         hSession == NULL) {
00284         QUITFUN(SNMPERR_GENERR, pkcs_digest_quit);
00285     }
00286 
00287     mech.mechanism = mech_type;
00288     mech.pParameter = NULL_PTR;
00289     mech.ulParameterLen = 0;
00290 
00291     /* initialize a message-digesting operation */
00292     if (C_DigestInit(hSession, &mech)!= CKR_OK ) {
00293         QUITFUN(SNMPERR_GENERR, pkcs_digest_quit);
00294     }
00295     /* continue a multiple-part message-digesting operation */
00296     if (C_DigestUpdate(hSession, msg, msglen) != CKR_OK ) {
00297         QUITFUN(SNMPERR_GENERR, pkcs_digest_quit);
00298     }
00299     /* finish a multiple-part message-digesting operation */
00300     if (C_DigestFinal(hSession, digest, digestlen) != CKR_OK) {
00301         QUITFUN(SNMPERR_GENERR, pkcs_digest_quit);
00302     }
00303 
00304   pkcs_digest_quit:
00305     return rval;
00306 }
00307 
00308 /*
00309  * encrypt plaintext into ciphertext using key and iv.   
00310  */
00311 int
00312 pkcs_encrpyt(CK_MECHANISM_TYPE mech_type, u_char * key, u_int keylen,
00313              u_char * iv, u_int ivlen,
00314              u_char * plaintext, u_int ptlen,
00315              u_char * ciphertext, size_t * ctlen)
00316 {
00317     int                rval = SNMPERR_SUCCESS;
00318     int                pad_size, offset;
00319     /*
00320      * Key template 
00321      */
00322     CK_OBJECT_CLASS class = CKO_SECRET_KEY;
00323     CK_KEY_TYPE keytype = CKK_DES;
00324     /* CK_KEY_TYPE AESkeytype = CKK_AES; */
00325     CK_BBOOL truevalue = TRUE;
00326     CK_BBOOL falsevalue = FALSE;
00327 
00328     CK_ATTRIBUTE template[] = {
00329         {CKA_CLASS, &class, sizeof (class)},
00330         {CKA_KEY_TYPE, &keytype, sizeof (keytype)},
00331         {CKA_ENCRYPT, &truevalue, sizeof (truevalue)},
00332         {CKA_TOKEN, &falsevalue, sizeof (falsevalue)},
00333         {CKA_VALUE, key, keylen} 
00334     };
00335 
00336     CK_SESSION_HANDLE hSession;
00337     CK_MECHANISM mech;
00338     CK_OBJECT_HANDLE hkey = (CK_OBJECT_HANDLE) 0;
00339 
00340     if (get_session_handle(mech_type, CKF_ENCRYPT,
00341                            &hSession) != CKR_OK ||
00342         hSession == NULL) {
00343         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
00344     }
00345 
00346     if (C_CreateObject(hSession, template,
00347         (sizeof (template) / sizeof (CK_ATTRIBUTE)),
00348                                 &hkey) != CKR_OK) {
00349         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
00350     }
00351 
00352     mech.mechanism = mech_type;
00353     mech.pParameter = iv;
00354     mech.ulParameterLen = ivlen;
00355 
00356     /* initialize an encryption operation */
00357     if (C_EncryptInit(hSession, &mech, hkey) != CKR_OK ) {
00358         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
00359     }
00360 
00361     /* for DES */
00362     pad_size = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
00363 
00364     if (ptlen + pad_size - ptlen % pad_size > *ctlen) {
00365         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);    
00366     }
00367 
00368     for (offset = 0; offset < ptlen; offset += pad_size) {
00369         /* continue a multiple-part encryption operation */
00370         if (C_EncryptUpdate(hSession, plaintext + offset, pad_size,
00371                             ciphertext + offset, ctlen) != CKR_OK) {
00372             QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
00373         }
00374     }
00375 
00376     /* finish a multiple-part encryption operation */
00377     if (C_EncryptFinal(hSession, ciphertext + offset, ctlen) != CKR_OK) {
00378         QUITFUN(SNMPERR_GENERR, pkcs_encrypt_quit);
00379     }
00380     *ctlen = offset;
00381 
00382   pkcs_encrypt_quit:
00383     if (key != (CK_OBJECT_HANDLE) 0) {
00384         (void) C_DestroyObject(hSession, hkey);
00385     }
00386     return rval;
00387 }
00388 
00389 /* 
00390  * decrypt ciphertext into plaintext using key and iv.
00391  */
00392 int
00393 pkcs_decrpyt(CK_MECHANISM_TYPE mech_type, u_char * key, u_int keylen,
00394              u_char * iv, u_int ivlen,
00395              u_char * ciphertext, u_int ctlen,
00396              u_char * plaintext, size_t * ptlen)
00397 {
00398     int            rval = SNMPERR_SUCCESS;
00399     /*
00400      * Key template 
00401      */
00402     CK_OBJECT_CLASS class = CKO_SECRET_KEY;
00403     CK_KEY_TYPE keytype = CKK_DES;
00404     /* CK_KEY_TYPE AESkeytype = CKK_AES; */
00405     CK_BBOOL truevalue = TRUE;
00406     CK_BBOOL falsevalue= FALSE;
00407     CK_ATTRIBUTE template[] = {
00408         {CKA_CLASS, &class, sizeof (class)},
00409         {CKA_KEY_TYPE, &keytype, sizeof (keytype)},
00410         {CKA_DECRYPT, &truevalue, sizeof (truevalue)},
00411         {CKA_TOKEN, &falsevalue, sizeof (falsevalue)},
00412         {CKA_VALUE, key, keylen}
00413     };
00414     CK_SESSION_HANDLE hSession;
00415     CK_MECHANISM mech;
00416     CK_OBJECT_HANDLE hkey = (CK_OBJECT_HANDLE) 0;
00417 
00418     if (get_session_handle(mech_type, CKF_DECRYPT, &hSession) != CKR_OK ||
00419         hSession == NULL) {
00420         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
00421     }
00422 
00423     if (C_CreateObject(hSession, template,
00424         (sizeof (template) / sizeof (CK_ATTRIBUTE)), &hkey) != CKR_OK) {
00425         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
00426     }
00427 
00428     mech.mechanism = mech_type;
00429     mech.pParameter = iv;
00430     mech.ulParameterLen = ivlen;
00431 
00432     /* initialize a decryption operation */
00433     if (C_DecryptInit(hSession, &mech, hkey) != CKR_OK ) {
00434         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
00435     }
00436     /* continue a multiple-part decryption operation */
00437     if (C_DecryptUpdate(hSession, ciphertext, ctlen, plaintext,
00438                                         ptlen) != CKR_OK) {
00439         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
00440     }
00441     /* finish a multiple-part decryption operation */
00442     if (C_DecryptFinal(hSession, plaintext, ptlen) != CKR_OK) {
00443         QUITFUN(SNMPERR_GENERR, pkcs_decrypt_quit);
00444     }
00445 
00446   pkcs_decrypt_quit:
00447     if (key != (CK_OBJECT_HANDLE) 0) {
00448         (void) C_DestroyObject(hSession, hkey);
00449     }
00450     return rval;
00451 }
00452 
00453 /*
00454  * Convert a passphrase into a master user key, Ku, according to the
00455  * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM)
00456  */
00457 int
00458 pkcs_generate_Ku(CK_MECHANISM_TYPE mech_type, u_char * passphrase, u_int pplen,
00459                  u_char * Ku, size_t * kulen)
00460 {
00461     int                rval = SNMPERR_SUCCESS, nbytes = USM_LENGTH_EXPANDED_PASSPHRASE;
00462     CK_SESSION_HANDLE hSession;
00463     CK_MECHANISM mech;
00464     u_int        i, pindex = 0;
00465     u_char        buf[USM_LENGTH_KU_HASHBLOCK], *bufp;
00466 
00467     if (get_session_handle(mech_type, CKF_DIGEST, &hSession) != CKR_OK ||
00468         hSession == NULL) {
00469         QUITFUN(SNMPERR_GENERR, pkcs_generate_Ku_quit);
00470     }
00471 
00472     mech.mechanism = mech_type;
00473     mech.pParameter = NULL_PTR;
00474     mech.ulParameterLen = 0;
00475 
00476     /* initialize a message-digesting operation */
00477     if (C_DigestInit(hSession, &mech)!= CKR_OK ) {
00478         QUITFUN(SNMPERR_GENERR, pkcs_generate_Ku_quit);
00479     }
00480 
00481     while (nbytes > 0) {
00482         bufp = buf;
00483         for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) {
00484            /*
00485             * fill a buffer with the supplied passphrase.  When the end
00486             * of the passphrase is reachedcycle back to the beginning.
00487             */
00488             *bufp++ = passphrase[pindex++ % pplen];
00489         }
00490         /* continue a multiple-part message-digesting operation */
00491         if (C_DigestUpdate(hSession, buf, USM_LENGTH_KU_HASHBLOCK) != CKR_OK ) {
00492             QUITFUN(SNMPERR_GENERR, pkcs_generate_Ku_quit);
00493         }
00494         nbytes -= USM_LENGTH_KU_HASHBLOCK;
00495     }
00496     /* finish a multiple-part message-digesting operation */
00497     if (C_DigestFinal(hSession, Ku, kulen) != CKR_OK) {
00498         QUITFUN(SNMPERR_GENERR, pkcs_generate_Ku_quit);
00499     }
00500 
00501   pkcs_generate_Ku_quit:
00502     return rval;
00503 }
00504    
00505 /*
00506  * pkcserr_stringor: returns a string representation of the given 
00507  * return code.
00508  */
00509 static char *
00510 pkcserr_string(CK_RV rv)
00511 {
00512     static char errstr[128];
00513     switch (rv) {
00514     case CKR_OK:
00515         return ("CKR_OK");
00516         break;
00517     case CKR_CANCEL:
00518         return ("CKR_CANCEL");
00519         break;
00520     case CKR_HOST_MEMORY:
00521         return ("CKR_HOST_MEMORY");
00522         break;
00523     case CKR_SLOT_ID_INVALID:
00524         return ("CKR_SLOT_ID_INVALID");
00525         break;
00526     case CKR_GENERAL_ERROR:
00527         return ("CKR_GENERAL_ERROR");
00528         break;
00529     case CKR_FUNCTION_FAILED:
00530         return ("CKR_FUNCTION_FAILED");
00531         break;
00532     case CKR_ARGUMENTS_BAD:
00533         return ("CKR_ARGUMENTS_BAD");
00534         break;
00535     case CKR_NO_EVENT:
00536         return ("CKR_NO_EVENT");
00537         break;
00538     case CKR_NEED_TO_CREATE_THREADS:
00539         return ("CKR_NEED_TO_CREATE_THREADS");
00540         break;
00541     case CKR_CANT_LOCK:
00542         return ("CKR_CANT_LOCK");
00543         break;
00544     case CKR_ATTRIBUTE_READ_ONLY:
00545         return ("CKR_ATTRIBUTE_READ_ONLY");
00546         break;
00547     case CKR_ATTRIBUTE_SENSITIVE:
00548         return ("CKR_ATTRIBUTE_SENSITIVE");
00549         break;
00550     case CKR_ATTRIBUTE_TYPE_INVALID:
00551         return ("CKR_ATTRIBUTE_TYPE_INVALID");
00552         break;
00553     case CKR_ATTRIBUTE_VALUE_INVALID:
00554         return ("CKR_ATTRIBUTE_VALUE_INVALID");
00555         break;
00556     case CKR_DATA_INVALID:
00557         return ("CKR_DATA_INVALID");
00558         break;
00559     case CKR_DATA_LEN_RANGE:
00560         return ("CKR_DATA_LEN_RANGE");
00561         break;
00562     case CKR_DEVICE_ERROR:
00563         return ("CKR_DEVICE_ERROR");
00564         break;
00565     case CKR_DEVICE_MEMORY:
00566         return ("CKR_DEVICE_MEMORY");
00567         break;
00568     case CKR_DEVICE_REMOVED:
00569         return ("CKR_DEVICE_REMOVED");
00570         break;
00571     case CKR_ENCRYPTED_DATA_INVALID:
00572         return ("CKR_ENCRYPTED_DATA_INVALID");
00573         break;
00574     case CKR_ENCRYPTED_DATA_LEN_RANGE:
00575         return ("CKR_ENCRYPTED_DATA_LEN_RANGE");
00576         break;
00577     case CKR_FUNCTION_CANCELED:
00578         return ("CKR_FUNCTION_CANCELED");
00579         break;
00580     case CKR_FUNCTION_NOT_PARALLEL:
00581         return ("CKR_FUNCTION_NOT_PARALLEL");
00582         break;
00583     case CKR_FUNCTION_NOT_SUPPORTED:
00584         return ("CKR_FUNCTION_NOT_SUPPORTED");
00585         break;
00586     case CKR_KEY_HANDLE_INVALID:
00587         return ("CKR_KEY_HANDLE_INVALID");
00588         break;
00589     case CKR_KEY_SIZE_RANGE:
00590         return ("CKR_KEY_SIZE_RANGE");
00591         break;
00592     case CKR_KEY_TYPE_INCONSISTENT:
00593         return ("CKR_KEY_TYPE_INCONSISTENT");
00594         break;
00595     case CKR_KEY_NOT_NEEDED:
00596         return ("CKR_KEY_NOT_NEEDED");
00597         break;
00598     case CKR_KEY_CHANGED:
00599         return ("CKR_KEY_CHANGED");
00600         break;
00601     case CKR_KEY_NEEDED:
00602         return ("CKR_KEY_NEEDED");
00603         break;
00604     case CKR_KEY_INDIGESTIBLE:
00605         return ("CKR_KEY_INDIGESTIBLE");
00606         break;
00607     case CKR_KEY_FUNCTION_NOT_PERMITTED:
00608         return ("CKR_KEY_FUNCTION_NOT_PERMITTED");
00609         break;
00610     case CKR_KEY_NOT_WRAPPABLE:
00611         return ("CKR_KEY_NOT_WRAPPABLE");
00612         break;
00613     case CKR_KEY_UNEXTRACTABLE:
00614         return ("CKR_KEY_UNEXTRACTABLE");
00615         break;
00616     case CKR_MECHANISM_INVALID:
00617         return ("CKR_MECHANISM_INVALID");
00618         break;
00619     case CKR_MECHANISM_PARAM_INVALID:
00620         return ("CKR_MECHANISM_PARAM_INVALID");
00621         break;
00622     case CKR_OBJECT_HANDLE_INVALID:
00623         return ("CKR_OBJECT_HANDLE_INVALID");
00624         break;
00625     case CKR_OPERATION_ACTIVE:
00626         return ("CKR_OPERATION_ACTIVE");
00627         break;
00628     case CKR_OPERATION_NOT_INITIALIZED:
00629         return ("CKR_OPERATION_NOT_INITIALIZED");
00630         break;
00631     case CKR_PIN_INCORRECT:
00632         return ("CKR_PIN_INCORRECT");
00633         break;
00634     case CKR_PIN_INVALID:
00635         return ("CKR_PIN_INVALID");
00636         break;
00637     case CKR_PIN_LEN_RANGE:
00638         return ("CKR_PIN_LEN_RANGE");
00639         break;
00640     case CKR_PIN_EXPIRED:
00641         return ("CKR_PIN_EXPIRED");
00642         break;
00643     case CKR_PIN_LOCKED:
00644         return ("CKR_PIN_LOCKED");
00645         break;
00646     case CKR_SESSION_CLOSED:
00647         return ("CKR_SESSION_CLOSED");
00648         break;
00649     case CKR_SESSION_COUNT:
00650         return ("CKR_SESSION_COUNT");
00651         break;
00652     case CKR_SESSION_HANDLE_INVALID:
00653         return ("CKR_SESSION_HANDLE_INVALID");
00654         break;
00655     case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
00656         return ("CKR_SESSION_PARALLEL_NOT_SUPPORTED");
00657         break;
00658     case CKR_SESSION_READ_ONLY:
00659         return ("CKR_SESSION_READ_ONLY");
00660         break;
00661     case CKR_SESSION_EXISTS:
00662         return ("CKR_SESSION_EXISTS");
00663         break;
00664     case CKR_SESSION_READ_ONLY_EXISTS:
00665         return ("CKR_SESSION_READ_ONLY_EXISTS");
00666         break;
00667     case CKR_SESSION_READ_WRITE_SO_EXISTS:
00668         return ("CKR_SESSION_READ_WRITE_SO_EXISTS");
00669         break;
00670     case CKR_SIGNATURE_INVALID:
00671         return ("CKR_SIGNATURE_INVALID");
00672         break;
00673     case CKR_SIGNATURE_LEN_RANGE:
00674         return ("CKR_SIGNATURE_LEN_RANGE");
00675         break;
00676     case CKR_TEMPLATE_INCOMPLETE:
00677         return ("CKR_TEMPLATE_INCOMPLETE");
00678         break;
00679     case CKR_TEMPLATE_INCONSISTENT:
00680         return ("CKR_TEMPLATE_INCONSISTENT");
00681         break;
00682     case CKR_TOKEN_NOT_PRESENT:
00683         return ("CKR_TOKEN_NOT_PRESENT");
00684         break;
00685     case CKR_TOKEN_NOT_RECOGNIZED:
00686         return ("CKR_TOKEN_NOT_RECOGNIZED");
00687         break;
00688     case CKR_TOKEN_WRITE_PROTECTED:
00689         return ("CKR_TOKEN_WRITE_PROTECTED");
00690         break;
00691     case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
00692         return ("CKR_UNWRAPPING_KEY_HANDLE_INVALID");
00693         break;
00694     case CKR_UNWRAPPING_KEY_SIZE_RANGE:
00695         return ("CKR_UNWRAPPING_KEY_SIZE_RANGE");
00696         break;
00697     case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
00698         return ("CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT");
00699         break;
00700     case CKR_USER_ALREADY_LOGGED_IN:
00701         return ("CKR_USER_ALREADY_LOGGED_IN");
00702         break;
00703     case CKR_USER_NOT_LOGGED_IN:
00704         return ("CKR_USER_NOT_LOGGED_IN");
00705         break;
00706     case CKR_USER_PIN_NOT_INITIALIZED:
00707         return ("CKR_USER_PIN_NOT_INITIALIZED");
00708         break;
00709     case CKR_USER_TYPE_INVALID:
00710         return ("CKR_USER_TYPE_INVALID");
00711         break;
00712     case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
00713         return ("CKR_USER_ANOTHER_ALREADY_LOGGED_IN");
00714         break;
00715     case CKR_USER_TOO_MANY_TYPES:
00716         return ("CKR_USER_TOO_MANY_TYPES");
00717         break;
00718     case CKR_WRAPPED_KEY_INVALID:
00719         return ("CKR_WRAPPED_KEY_INVALID");
00720         break;
00721     case CKR_WRAPPED_KEY_LEN_RANGE:
00722         return ("CKR_WRAPPED_KEY_LEN_RANGE");
00723         break;
00724     case CKR_WRAPPING_KEY_HANDLE_INVALID:
00725         return ("CKR_WRAPPING_KEY_HANDLE_INVALID");
00726         break;
00727     case CKR_WRAPPING_KEY_SIZE_RANGE:
00728         return ("CKR_WRAPPING_KEY_SIZE_RANGE");
00729         break;
00730     case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
00731         return ("CKR_WRAPPING_KEY_TYPE_INCONSISTENT");
00732         break;
00733     case CKR_RANDOM_SEED_NOT_SUPPORTED:
00734         return ("CKR_RANDOM_SEED_NOT_SUPPORTED");
00735         break;
00736     case CKR_RANDOM_NO_RNG:
00737         return ("CKR_RANDOM_NO_RNG");
00738         break;
00739     case CKR_DOMAIN_PARAMS_INVALID:
00740         return ("CKR_DOMAIN_PARAMS_INVALID");
00741         break;
00742     case CKR_BUFFER_TOO_SMALL:
00743         return ("CKR_BUFFER_TOO_SMALL");
00744         break;
00745     case CKR_SAVED_STATE_INVALID:
00746         return ("CKR_SAVED_STATE_INVALID");
00747         break;
00748     case CKR_INFORMATION_SENSITIVE:
00749         return ("CKR_INFORMATION_SENSITIVE");
00750         break;
00751     case CKR_STATE_UNSAVEABLE:
00752         return ("CKR_STATE_UNSAVEABLE");
00753         break;
00754     case CKR_CRYPTOKI_NOT_INITIALIZED:
00755         return ("CKR_CRYPTOKI_NOT_INITIALIZED");
00756         break;
00757     case CKR_CRYPTOKI_ALREADY_INITIALIZED:
00758         return ("CKR_CRYPTOKI_ALREADY_INITIALIZED");
00759         break;
00760     case CKR_MUTEX_BAD:
00761         return ("CKR_MUTEX_BAD");
00762         break;
00763     case CKR_MUTEX_NOT_LOCKED:
00764         return ("CKR_MUTEX_NOT_LOCKED");
00765         break;
00766     case CKR_VENDOR_DEFINED:
00767         return ("CKR_VENDOR_DEFINED");
00768         break;
00769     default:
00770         /* rv not found */
00771         snprintf(errstr, sizeof (errstr),
00772             "Unknown return code: 0x%x", rv);
00773         return (errstr);
00774         break;
00775     }
00776 }
00777 #else
00778 int pkcs_unused;        /* Suppress "empty translation unit" warning */
00779 #endif