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