1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Administration for metaslot
  28  *
  29  * All the "list" operations will call functions in libpkcs11.so
  30  * Normally, it doesn't make sense to call functions in libpkcs11.so directly
  31  * because libpkcs11.so depends on the configuration file (pkcs11.conf) the
  32  * cryptoadm command is trying to administer.  However, since metaslot
  33  * is part of the framework, it is not possible to get information about
  34  * it without actually calling functions in libpkcs11.so.
  35  *
  36  * So, for the listing operation, which won't modify the value of pkcs11.conf
  37  * it is safe to call libpkcs11.so.
  38  *
  39  * For other operations that modifies the pkcs11.conf file, libpkcs11.so
  40  * will not be called.
  41  *
  42  */
  43 
  44 #include <cryptoutil.h>
  45 #include <stdio.h>
  46 #include <libintl.h>
  47 #include <dlfcn.h>
  48 #include <link.h>
  49 #include <strings.h>
  50 #include <security/cryptoki.h>
  51 #include <cryptoutil.h>
  52 #include "cryptoadm.h"
  53 
  54 #define METASLOT_ID     0
  55 
  56 int
  57 list_metaslot_info(boolean_t show_mechs, boolean_t verbose,
  58     mechlist_t *mechlist)
  59 {
  60         int rc = SUCCESS;
  61         CK_RV rv;
  62         CK_SLOT_INFO slot_info;
  63         CK_TOKEN_INFO token_info;
  64         CK_MECHANISM_TYPE_PTR pmech_list = NULL;
  65         CK_ULONG mech_count;
  66         int i;
  67         CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR);
  68         CK_FUNCTION_LIST_PTR    funcs;
  69         void *dldesc = NULL;
  70         boolean_t lib_initialized = B_FALSE;
  71         uentry_t *puent;
  72         char buf[128];
  73 
  74 
  75         /*
  76          * Display the system-wide metaslot settings as specified
  77          * in pkcs11.conf file.
  78          */
  79         if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
  80                 cryptoerror(LOG_STDERR,
  81                     gettext("metaslot entry doesn't exist."));
  82                 return (FAILURE);
  83         }
  84 
  85         (void) printf(gettext("System-wide Meta Slot Configuration:\n"));
  86         /*
  87          * TRANSLATION_NOTE:
  88          * Strictly for appearance's sake, this line should be as long as
  89          * the length of the translated text above.
  90          */
  91         (void) printf(gettext("------------------------------------\n"));
  92         (void) printf(gettext("Status: %s\n"), puent->flag_metaslot_enabled ?
  93             gettext("enabled") : gettext("disabled"));
  94         (void) printf(gettext("Sensitive Token Object Automatic Migrate: %s\n"),
  95             puent->flag_metaslot_auto_key_migrate ? gettext("enabled") :
  96             gettext("disabled"));
  97 
  98         bzero(buf, sizeof (buf));
  99         if (memcmp(puent->metaslot_ks_slot, buf, SLOT_DESCRIPTION_SIZE) != 0) {
 100                 (void) printf(gettext("Persistent object store slot: %s\n"),
 101                     puent->metaslot_ks_slot);
 102         }
 103 
 104         if (memcmp(puent->metaslot_ks_token, buf, TOKEN_LABEL_SIZE) != 0) {
 105                 (void) printf(gettext("Persistent object store token: %s\n"),
 106                     puent->metaslot_ks_token);
 107         }
 108 
 109         if ((!verbose) && (!show_mechs)) {
 110                 return (SUCCESS);
 111         }
 112 
 113         if (verbose) {
 114                 (void) printf(gettext("\nDetailed Meta Slot Information:\n"));
 115                 /*
 116                  * TRANSLATION_NOTE:
 117                  * Strictly for appearance's sake, this line should be as
 118                  * long as the length of the translated text above.
 119                  */
 120                 (void) printf(gettext("-------------------------------\n"));
 121         }
 122 
 123         /*
 124          * Need to actually make calls to libpkcs11.so to get
 125          * information about metaslot.
 126          */
 127 
 128         dldesc = dlopen(UEF_FRAME_LIB, RTLD_NOW);
 129         if (dldesc == NULL) {
 130                 char *dl_error;
 131                 dl_error = dlerror();
 132                 cryptodebug("Cannot load PKCS#11 framework library. "
 133                     "dlerror:%s", dl_error);
 134                 return (FAILURE);
 135         }
 136 
 137         /* Get the pointer to library's C_GetFunctionList() */
 138         Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList");
 139         if (Tmp_C_GetFunctionList == NULL) {
 140                 cryptodebug("Cannot get the address of the C_GetFunctionList "
 141                     "from framework");
 142                 rc = FAILURE;
 143                 goto finish;
 144         }
 145 
 146 
 147         /* Get the provider's function list */
 148         rv = Tmp_C_GetFunctionList(&funcs);
 149         if (rv != CKR_OK) {
 150                 cryptodebug("failed to call C_GetFunctionList in "
 151                     "framework library");
 152                 rc = FAILURE;
 153                 goto finish;
 154         }
 155 
 156         /* Initialize this provider */
 157         rv = funcs->C_Initialize(NULL_PTR);
 158         if (rv != CKR_OK) {
 159                 cryptodebug("C_Initialize failed with error code 0x%x\n", rv);
 160                 rc = FAILURE;
 161                 goto finish;
 162         } else {
 163                 lib_initialized = B_TRUE;
 164         }
 165 
 166         /*
 167          * We know for sure that metaslot is slot 0 in the framework,
 168          * so, we will do a C_GetSlotInfo() trying to see if it works.
 169          * If it fails with CKR_SLOT_ID_INVALID, we know that metaslot
 170          * is not really enabled.
 171          */
 172         rv = funcs->C_GetSlotInfo(METASLOT_ID, &slot_info);
 173         if (rv == CKR_SLOT_ID_INVALID) {
 174                 (void) printf(gettext("actual status: disabled.\n"));
 175                 /*
 176                  * Even if the -m and -v flag is supplied, there's nothing
 177                  * interesting to display about metaslot since it is disabled,
 178                  * so, just stop right here.
 179                  */
 180                 goto finish;
 181         }
 182 
 183         if (rv != CKR_OK) {
 184                 cryptodebug("C_GetSlotInfo failed with error "
 185                     "code 0x%x\n", rv);
 186                 rc = FAILURE;
 187                 goto finish;
 188         }
 189 
 190         if (!verbose) {
 191                 goto display_mechs;
 192         }
 193 
 194         (void) printf(gettext("actual status: enabled.\n"));
 195 
 196         (void) printf(gettext("Description: %.64s\n"),
 197             slot_info.slotDescription);
 198 
 199         (void) printf(gettext("Token Present: %s\n"),
 200             (slot_info.flags & CKF_TOKEN_PRESENT ?
 201             gettext("True") : gettext("False")));
 202 
 203         rv = funcs->C_GetTokenInfo(METASLOT_ID, &token_info);
 204         if (rv != CKR_OK) {
 205                 cryptodebug("C_GetTokenInfo failed with error "
 206                     "code 0x%x\n", rv);
 207                 rc = FAILURE;
 208                 goto finish;
 209         }
 210 
 211         (void) printf(gettext("Token Label: %.32s\n"
 212             "Manufacturer ID: %.32s\n"
 213             "Model: %.16s\n"
 214             "Serial Number: %.16s\n"
 215             "Hardware Version: %d.%d\n"
 216             "Firmware Version: %d.%d\n"
 217             "UTC Time: %.16s\n"
 218             "PIN Min Length: %d\n"
 219             "PIN Max Length: %d\n"),
 220             token_info.label,
 221             token_info.manufacturerID,
 222             token_info.model,
 223             token_info.serialNumber,
 224             token_info.hardwareVersion.major,
 225             token_info.hardwareVersion.minor,
 226             token_info.firmwareVersion.major,
 227             token_info.firmwareVersion.minor,
 228             token_info.utcTime,
 229             token_info.ulMinPinLen,
 230             token_info.ulMaxPinLen);
 231 
 232         display_token_flags(token_info.flags);
 233 
 234         if (!show_mechs) {
 235                 goto finish;
 236         }
 237 
 238 display_mechs:
 239 
 240         if (mechlist == NULL) {
 241                 rv = funcs->C_GetMechanismList(METASLOT_ID, NULL_PTR,
 242                     &mech_count);
 243                 if (rv != CKR_OK) {
 244                         cryptodebug("C_GetMechanismList failed with error "
 245                             "code 0x%x\n", rv);
 246                         rc = FAILURE;
 247                         goto finish;
 248                 }
 249 
 250                 if (mech_count > 0) {
 251                         pmech_list = malloc(mech_count *
 252                             sizeof (CK_MECHANISM_TYPE));
 253                         if (pmech_list == NULL) {
 254                                 cryptodebug("out of memory");
 255                                 rc = FAILURE;
 256                                 goto finish;
 257                         }
 258                         rv = funcs->C_GetMechanismList(METASLOT_ID, pmech_list,
 259                             &mech_count);
 260                         if (rv != CKR_OK) {
 261                                 cryptodebug("C_GetMechanismList failed with "
 262                                     "error code 0x%x\n", rv);
 263                                 rc = FAILURE;
 264                                 goto finish;
 265                         }
 266                 }
 267         } else {
 268                 rc = convert_mechlist(&pmech_list, &mech_count, mechlist);
 269                 if (rc != SUCCESS) {
 270                         goto finish;
 271                 }
 272         }
 273 
 274         (void) printf(gettext("Mechanisms:\n"));
 275         if (mech_count == 0) {
 276                 /* should never be this case */
 277                 (void) printf(gettext("No mechanisms\n"));
 278                 goto finish;
 279         }
 280         if (verbose) {
 281                 display_verbose_mech_header();
 282         }
 283 
 284         for (i = 0; i < mech_count; i++) {
 285                 CK_MECHANISM_TYPE       mech = pmech_list[i];
 286 
 287                 if (mech >= CKM_VENDOR_DEFINED) {
 288                         (void) printf("%#lx", mech);
 289                 } else {
 290                         (void) printf("%-29s", pkcs11_mech2str(mech));
 291                 }
 292 
 293                 if (verbose) {
 294                         CK_MECHANISM_INFO mech_info;
 295                         rv = funcs->C_GetMechanismInfo(METASLOT_ID,
 296                             mech, &mech_info);
 297                         if (rv != CKR_OK) {
 298                                 cryptodebug("C_GetMechanismInfo failed with "
 299                                     "error code 0x%x\n", rv);
 300                                 rc = FAILURE;
 301                                 goto finish;
 302                         }
 303                         display_mech_info(&mech_info);
 304                 }
 305                 (void) printf("\n");
 306         }
 307 
 308 finish:
 309 
 310         if ((rc == FAILURE) && (show_mechs)) {
 311                 (void) printf(gettext(
 312                     "metaslot: failed to retrieve the mechanism list.\n"));
 313         }
 314 
 315         if (lib_initialized) {
 316                 (void) funcs->C_Finalize(NULL_PTR);
 317         }
 318 
 319         if (dldesc != NULL) {
 320                 (void) dlclose(dldesc);
 321         }
 322 
 323         if (pmech_list != NULL) {
 324                 (void) free(pmech_list);
 325         }
 326 
 327         return (rc);
 328 }
 329 
 330 int
 331 list_metaslot_policy()
 332 {
 333 
 334         uentry_t *puent;
 335         int rc;
 336 
 337         if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
 338                 cryptoerror(LOG_STDERR,
 339                     gettext("metaslot entry doesn't exist."));
 340                 return (FAILURE);
 341         }
 342 
 343         rc = display_policy(puent);
 344         (void) printf("\n");
 345         free_uentry(puent);
 346         return (rc);
 347 }
 348 
 349 /*
 350  * disable metaslot and some of its configuration options
 351  *
 352  * If mechlist==NULL, and the other 2 flags are false, just disabled
 353  * the metaslot feature.
 354  *
 355  * mechlist: list of mechanisms to disable
 356  * allflag: if true, indicates all mechanisms should be disabled.
 357  * auto_key_migrate_flag: if true, indicates auto key migrate should be disabled
 358  */
 359 int
 360 disable_metaslot(mechlist_t *mechlist, boolean_t allflag,
 361     boolean_t auto_key_migrate_flag)
 362 {
 363         uentry_t *puent;
 364         int rc = SUCCESS;
 365 
 366         if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
 367                 cryptoerror(LOG_STDERR,
 368                     gettext("metaslot entry doesn't exist."));
 369                 return (FAILURE);
 370         }
 371 
 372 
 373         if ((mechlist == NULL) && (!auto_key_migrate_flag) && (!allflag)) {
 374                 /* disable metaslot */
 375                 puent->flag_metaslot_enabled = B_FALSE;
 376                 goto write_to_file;
 377         }
 378 
 379         if (auto_key_migrate_flag) {
 380                 /* need to disable auto_key_migrate */
 381                 puent->flag_metaslot_auto_key_migrate = B_FALSE;
 382         }
 383 
 384         if ((mechlist == NULL) && (!allflag)) {
 385                 goto write_to_file;
 386         }
 387 
 388         /* disable specified mechanisms */
 389         if (allflag) {
 390                 free_umechlist(puent->policylist);
 391                 puent->policylist = NULL;
 392                 puent->count = 0;
 393                 puent->flag_enabledlist = B_TRUE;
 394                 rc = SUCCESS;
 395         } else {
 396                 if (puent->flag_enabledlist == B_TRUE) {
 397                         /*
 398                          * The current default policy mode
 399                          * is "all are disabled, except ...", so if a
 400                          * specified mechanism is in the exception list
 401                          * (the policylist), delete it from the policylist.
 402                          */
 403                         rc = update_policylist(puent, mechlist, DELETE_MODE);
 404                 } else {
 405                         /*
 406                          * The current default policy mode of this library
 407                          * is "all are enabled", so if a specified mechanism
 408                          * is not in the exception list (policylist), add
 409                          * it into the policylist.
 410                          */
 411                         rc = update_policylist(puent, mechlist, ADD_MODE);
 412                 }
 413         }
 414 
 415         if (rc != SUCCESS) {
 416                 goto finish;
 417         }
 418 
 419         /* If all mechanisms are disabled, metaslot will be disabled as well */
 420         if ((puent->flag_enabledlist) && (puent->count == 0)) {
 421                 puent->flag_metaslot_enabled = B_FALSE;
 422         }
 423 
 424 write_to_file:
 425 
 426         rc = update_pkcs11conf(puent);
 427 
 428 finish:
 429         free_uentry(puent);
 430         return (rc);
 431 }
 432 
 433 /*
 434  * enable metaslot and some of its configuration options
 435  *
 436  * If mechlist==NULL, and the other flags are false, or not specified,
 437  * just enable the metaslot feature.
 438  *
 439  * token: if specified, indicate label of token to be used as keystore.
 440  * slot: if specified, indicate slot to be used as keystore.
 441  * use_default: if true, indicate to use the default keystore.  It should
 442  *              not be specified if either token or slot is specified.
 443  * mechlist: list of mechanisms to enable
 444  * allflag: if true, indicates all mechanisms should be enabled.
 445  * auto_key_migrate_flag: if true, indicates auto key migrate should be enabled
 446  */
 447 int
 448 enable_metaslot(char *token, char *slot, boolean_t use_default,
 449     mechlist_t *mechlist,  boolean_t allflag, boolean_t auto_key_migrate_flag)
 450 {
 451         uentry_t *puent;
 452         int rc = SUCCESS;
 453 
 454         if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
 455                 cryptoerror(LOG_STDERR,
 456                     gettext("metaslot entry doesn't exist."));
 457                 return (FAILURE);
 458         }
 459 
 460         puent->flag_metaslot_enabled = B_TRUE;
 461 
 462         if (auto_key_migrate_flag) {
 463                 /* need to enable auto_key_migrate */
 464                 puent->flag_metaslot_auto_key_migrate = B_TRUE;
 465         }
 466 
 467         if (allflag) {
 468                 /*
 469                  * If enabling all, what needs to be done are cleaning up the
 470                  * policylist and setting the "flag_enabledlist" flag to
 471                  * B_FALSE.
 472                  */
 473                 free_umechlist(puent->policylist);
 474                 puent->policylist = NULL;
 475                 puent->count = 0;
 476                 puent->flag_enabledlist = B_FALSE;
 477                 rc = SUCCESS;
 478         } else {
 479                 if (mechlist) {
 480                         if (puent->flag_enabledlist == B_TRUE) {
 481                                 /*
 482                                  * The current default policy mode of this
 483                                  * library is "all are disabled, except ...",
 484                                  * so if a specified mechanism is not in the
 485                                  * exception list (policylist), add it.
 486                                  */
 487                                 rc = update_policylist(puent, mechlist,
 488                                     ADD_MODE);
 489                         } else {
 490                                 /*
 491                                  * The current default policy mode of this
 492                                  * library is "all are enabled, except", so if
 493                                  * a specified  mechanism is in the exception
 494                                  * list (policylist), delete it.
 495                                  */
 496                                 rc = update_policylist(puent, mechlist,
 497                                     DELETE_MODE);
 498                         }
 499                 }
 500         }
 501 
 502         if (rc != SUCCESS) {
 503                 goto finish;
 504         }
 505 
 506         if (!use_default && !token && !slot) {
 507                 /* no need to change metaslot keystore */
 508                 goto write_to_file;
 509         }
 510 
 511         (void) bzero((char *)puent->metaslot_ks_token, TOKEN_LABEL_SIZE);
 512         (void) bzero((char *)puent->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE);
 513 
 514         if (use_default) {
 515                 (void) strlcpy((char *)puent->metaslot_ks_token,
 516                     SOFT_TOKEN_LABEL, TOKEN_LABEL_SIZE);
 517                 (void) strlcpy((char *)puent->metaslot_ks_slot,
 518                     SOFT_SLOT_DESCRIPTION, SLOT_DESCRIPTION_SIZE);
 519         } else {
 520 
 521                 if (token) {
 522                         (void) strlcpy((char *)puent->metaslot_ks_token, token,
 523                             TOKEN_LABEL_SIZE);
 524                 }
 525 
 526                 if (slot) {
 527                         (void) strlcpy((char *)puent->metaslot_ks_slot, slot,
 528                             SLOT_DESCRIPTION_SIZE);
 529                 }
 530         }
 531 
 532 
 533 write_to_file:
 534 
 535         rc = update_pkcs11conf(puent);
 536 
 537 finish:
 538         free_uentry(puent);
 539         return (rc);
 540 }