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