17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 599ebb4caSwyllys * Common Development and Distribution License (the "License"). 699ebb4caSwyllys * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2247e946e7SWyllys Ingersoll * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*33f5ff17SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * This file implements the setpin operation for this tool. 297c478bd9Sstevel@tonic-gate * The basic flow of the process is to load the PKCS#11 module, 307711facfSdinak * finds the soft token, prompt the user for the old PIN (if 317711facfSdinak * any) and the new PIN, change the token's PIN, and clean up. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <stdio.h> 357c478bd9Sstevel@tonic-gate #include <stdlib.h> 367711facfSdinak #include <errno.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <cryptoutil.h> 397c478bd9Sstevel@tonic-gate #include <security/cryptoki.h> 407c478bd9Sstevel@tonic-gate #include "common.h" 417c478bd9Sstevel@tonic-gate 4299ebb4caSwyllys static int 4399ebb4caSwyllys setpin_nss(KMF_HANDLE_T handle, 4499ebb4caSwyllys char *token_spec, char *dir, char *prefix) 457c478bd9Sstevel@tonic-gate { 4699ebb4caSwyllys int rv = 0; 4730a5e8faSwyllys KMF_CREDENTIAL oldcred = {NULL, 0}; 4899ebb4caSwyllys KMF_CREDENTIAL newpincred = {NULL, 0}; 4999ebb4caSwyllys CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL; 5099ebb4caSwyllys CK_ULONG old_pinlen = 0, new_pinlen = 0; 5130a5e8faSwyllys KMF_ATTRIBUTE setpinattrs[6]; 5230a5e8faSwyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS; 5330a5e8faSwyllys int numattrs = 0; 5499ebb4caSwyllys 5599ebb4caSwyllys rv = configure_nss(handle, dir, prefix); 5699ebb4caSwyllys if (rv != KMF_OK) 5799ebb4caSwyllys return (rv); 5899ebb4caSwyllys 5930a5e8faSwyllys kmf_set_attr_at_index(setpinattrs, numattrs, KMF_KEYSTORE_TYPE_ATTR, 6030a5e8faSwyllys &kstype, sizeof (kstype)); 6130a5e8faSwyllys numattrs++; 6230a5e8faSwyllys if (token_spec != NULL) { 6330a5e8faSwyllys kmf_set_attr_at_index(setpinattrs, numattrs, 6430a5e8faSwyllys KMF_TOKEN_LABEL_ATTR, 6530a5e8faSwyllys token_spec, strlen(token_spec)); 6630a5e8faSwyllys numattrs++; 6730a5e8faSwyllys } 6899ebb4caSwyllys 6999ebb4caSwyllys if ((rv = get_pin(gettext("Enter current token passphrase " 7030a5e8faSwyllys "(<CR> if not set):"), NULL, &old_pin, &old_pinlen)) != CKR_OK) { 7199ebb4caSwyllys cryptoerror(LOG_STDERR, 7299ebb4caSwyllys gettext("Unable to get token passphrase.")); 7399ebb4caSwyllys return (PK_ERR_NSS); 7499ebb4caSwyllys } 7599ebb4caSwyllys /* Get the user's new PIN. */ 7699ebb4caSwyllys if ((rv = get_pin(gettext("Create new passphrase:"), gettext( 7799ebb4caSwyllys "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) { 7899ebb4caSwyllys if (rv == CKR_PIN_INCORRECT) 7999ebb4caSwyllys cryptoerror(LOG_STDERR, gettext( 8099ebb4caSwyllys "Passphrases do not match.")); 8199ebb4caSwyllys else 8299ebb4caSwyllys cryptoerror(LOG_STDERR, gettext( 8399ebb4caSwyllys "Unable to get and confirm new passphrase.")); 8499ebb4caSwyllys if (old_pin != NULL) 8599ebb4caSwyllys free(old_pin); 8699ebb4caSwyllys return (PK_ERR_NSS); 8799ebb4caSwyllys } 8899ebb4caSwyllys 8930a5e8faSwyllys oldcred.cred = (char *)old_pin; 9030a5e8faSwyllys oldcred.credlen = old_pinlen; 9130a5e8faSwyllys 9230a5e8faSwyllys kmf_set_attr_at_index(setpinattrs, numattrs, KMF_CREDENTIAL_ATTR, 9330a5e8faSwyllys &oldcred, sizeof (oldcred)); 9430a5e8faSwyllys numattrs++; 9599ebb4caSwyllys 9699ebb4caSwyllys newpincred.cred = (char *)new_pin; 9799ebb4caSwyllys newpincred.credlen = new_pinlen; 9830a5e8faSwyllys kmf_set_attr_at_index(setpinattrs, numattrs, KMF_NEWPIN_ATTR, 9930a5e8faSwyllys &newpincred, sizeof (newpincred)); 10030a5e8faSwyllys numattrs++; 10199ebb4caSwyllys 10230a5e8faSwyllys rv = kmf_set_token_pin(handle, numattrs, setpinattrs); 10399ebb4caSwyllys 10499ebb4caSwyllys if (new_pin) 10599ebb4caSwyllys free(new_pin); 10699ebb4caSwyllys if (old_pin) 10799ebb4caSwyllys free(old_pin); 10899ebb4caSwyllys 10999ebb4caSwyllys return (rv); 11099ebb4caSwyllys } 11199ebb4caSwyllys 11299ebb4caSwyllys static int 11347e946e7SWyllys Ingersoll setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec, boolean_t souser) 11499ebb4caSwyllys { 1157c478bd9Sstevel@tonic-gate CK_SLOT_ID slot_id; 1167c478bd9Sstevel@tonic-gate CK_FLAGS pin_state; 1177711facfSdinak CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL; 1187711facfSdinak CK_ULONG old_pinlen = 0, new_pinlen = 0; 1197711facfSdinak CK_RV rv = CKR_OK; 12099ebb4caSwyllys char *token_name = NULL; 12199ebb4caSwyllys CK_TOKEN_INFO token_info; 12299ebb4caSwyllys KMF_CREDENTIAL newpincred = {NULL, 0}; 12330a5e8faSwyllys KMF_CREDENTIAL oldcred = {NULL, 0}; 12430a5e8faSwyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; 12530a5e8faSwyllys KMF_ATTRIBUTE attrlist[6]; 12647e946e7SWyllys Ingersoll CK_USER_TYPE user = CKU_USER; 12730a5e8faSwyllys int numattr = 0; 12849e21299Sdinak 12949e21299Sdinak /* If nothing is specified, default is to use softtoken. */ 13049e21299Sdinak if (token_spec == NULL) { 13199ebb4caSwyllys token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID; 13249e21299Sdinak token_name = SOFT_TOKEN_LABEL; 13349e21299Sdinak } 1347711facfSdinak 13530a5e8faSwyllys rv = kmf_pk11_token_lookup(NULL, token_spec, &slot_id); 13699ebb4caSwyllys if (rv == KMF_OK) { 13799ebb4caSwyllys /* find the pin state for the selected token */ 13899ebb4caSwyllys if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK) 1397711facfSdinak return (PK_ERR_PK11); 14099ebb4caSwyllys 14199ebb4caSwyllys pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED; 14299ebb4caSwyllys if (token_name == NULL) 14399ebb4caSwyllys token_name = (char *)token_info.label; 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* 1477711facfSdinak * If the token is the softtoken, check if the token flags show the 1487711facfSdinak * PIN has not been set yet. If not then set the old PIN to the 1497711facfSdinak * default "changeme". Otherwise, let user type in the correct old 1507711facfSdinak * PIN to unlock token. 1517c478bd9Sstevel@tonic-gate */ 1527711facfSdinak if (pin_state == CKF_USER_PIN_TO_BE_CHANGED && 1537711facfSdinak strcmp(token_name, SOFT_TOKEN_LABEL) == 0) { 1547711facfSdinak if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) == 1557711facfSdinak NULL) { 1567711facfSdinak cryptoerror(LOG_STDERR, "%s.", strerror(errno)); 1577711facfSdinak final_pk11(NULL); 1587711facfSdinak return (PK_ERR_PK11); 1597711facfSdinak } 1607711facfSdinak old_pinlen = strlen(SOFT_DEFAULT_PIN); 1617711facfSdinak } else { 1627711facfSdinak if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, 1637711facfSdinak &old_pin, &old_pinlen)) != CKR_OK) { 1647711facfSdinak cryptoerror(LOG_STDERR, 1657711facfSdinak gettext("Unable to get token passphrase (%s)."), 1667711facfSdinak pkcs11_strerror(rv)); 1677711facfSdinak final_pk11(NULL); 1687711facfSdinak return (PK_ERR_PK11); 1697711facfSdinak } 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727711facfSdinak /* Get the user's new PIN. */ 1737711facfSdinak if ((rv = get_pin(gettext("Create new passphrase:"), gettext( 1747711facfSdinak "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) { 1757711facfSdinak if (rv == CKR_PIN_INCORRECT) 1767711facfSdinak cryptoerror(LOG_STDERR, gettext( 1777711facfSdinak "Passphrases do not match.")); 1787711facfSdinak else 1797711facfSdinak cryptoerror(LOG_STDERR, gettext( 1807711facfSdinak "Unable to get and confirm new passphrase (%s)."), 1817711facfSdinak pkcs11_strerror(rv)); 1827711facfSdinak free(old_pin); 1837711facfSdinak final_pk11(NULL); 1847711facfSdinak return (PK_ERR_PK11); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 18730a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, 18830a5e8faSwyllys &kstype, sizeof (kstype)); 18930a5e8faSwyllys numattr++; 19030a5e8faSwyllys if (token_name != NULL) { 19130a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, 19230a5e8faSwyllys token_name, strlen(token_name)); 19330a5e8faSwyllys numattr++; 19430a5e8faSwyllys } 19530a5e8faSwyllys oldcred.cred = (char *)old_pin; 19630a5e8faSwyllys oldcred.credlen = old_pinlen; 19730a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, 19830a5e8faSwyllys &oldcred, sizeof (oldcred)); 19930a5e8faSwyllys numattr++; 20030a5e8faSwyllys 20130a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_SLOT_ID_ATTR, 20230a5e8faSwyllys &slot_id, sizeof (slot_id)); 20330a5e8faSwyllys numattr++; 2047711facfSdinak 20599ebb4caSwyllys newpincred.cred = (char *)new_pin; 20699ebb4caSwyllys newpincred.credlen = new_pinlen; 20730a5e8faSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_NEWPIN_ATTR, 20830a5e8faSwyllys &newpincred, sizeof (newpincred)); 20930a5e8faSwyllys numattr++; 21099ebb4caSwyllys 21147e946e7SWyllys Ingersoll if (souser) { 21247e946e7SWyllys Ingersoll user = CKU_SO; 21347e946e7SWyllys Ingersoll kmf_set_attr_at_index(attrlist, numattr, 21447e946e7SWyllys Ingersoll KMF_PK11_USER_TYPE_ATTR, 21547e946e7SWyllys Ingersoll &user, sizeof (user)); 21647e946e7SWyllys Ingersoll numattr++; 21747e946e7SWyllys Ingersoll } 21847e946e7SWyllys Ingersoll 21930a5e8faSwyllys rv = kmf_set_token_pin(handle, numattr, attrlist); 2207711facfSdinak 2217711facfSdinak /* Clean up. */ 22299ebb4caSwyllys if (old_pin != NULL) 2237711facfSdinak free(old_pin); 22499ebb4caSwyllys if (new_pin != NULL) 2257711facfSdinak free(new_pin); 2267711facfSdinak 22799ebb4caSwyllys return (rv); 2287711facfSdinak } 2297711facfSdinak 23099ebb4caSwyllys /* 23199ebb4caSwyllys * Changes the token's PIN. 23299ebb4caSwyllys */ 23399ebb4caSwyllys int 23499ebb4caSwyllys pk_setpin(int argc, char *argv[]) 23599ebb4caSwyllys /* ARGSUSED */ 23699ebb4caSwyllys { 23799ebb4caSwyllys int opt; 23899ebb4caSwyllys int rv; 23999ebb4caSwyllys extern int optind_av; 24099ebb4caSwyllys extern char *optarg_av; 24199ebb4caSwyllys char *token_spec = NULL; 24299ebb4caSwyllys char *dir = NULL; 24399ebb4caSwyllys char *prefix = NULL; 24447e946e7SWyllys Ingersoll char *utype = NULL; 24599ebb4caSwyllys KMF_HANDLE_T handle; 24699ebb4caSwyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; 24747e946e7SWyllys Ingersoll boolean_t souser = 0; 24899ebb4caSwyllys 24999ebb4caSwyllys /* Parse command line options. Do NOT i18n/l10n. */ 25099ebb4caSwyllys while ((opt = getopt_av(argc, argv, 25199ebb4caSwyllys "T:(token)k:(keystore)d:(dir)" 25247e946e7SWyllys Ingersoll "p:(prefix)u:(usertype)")) != EOF) { 25399ebb4caSwyllys switch (opt) { 25499ebb4caSwyllys case 'k': 25599ebb4caSwyllys kstype = KS2Int(optarg_av); 25699ebb4caSwyllys if (kstype == 0) 25799ebb4caSwyllys return (PK_ERR_USAGE); 25899ebb4caSwyllys break; 25999ebb4caSwyllys case 'T': /* token specifier */ 26099ebb4caSwyllys if (token_spec) 26199ebb4caSwyllys return (PK_ERR_USAGE); 26299ebb4caSwyllys token_spec = optarg_av; 26399ebb4caSwyllys break; 26499ebb4caSwyllys case 'd': 26599ebb4caSwyllys if (dir) 26699ebb4caSwyllys return (PK_ERR_USAGE); 26799ebb4caSwyllys dir = optarg_av; 26899ebb4caSwyllys break; 26999ebb4caSwyllys case 'p': 27099ebb4caSwyllys if (prefix) 27199ebb4caSwyllys return (PK_ERR_USAGE); 27299ebb4caSwyllys prefix = optarg_av; 27399ebb4caSwyllys break; 27447e946e7SWyllys Ingersoll case 'u': 27547e946e7SWyllys Ingersoll utype = optarg_av; 27647e946e7SWyllys Ingersoll break; 27799ebb4caSwyllys default: 27899ebb4caSwyllys return (PK_ERR_USAGE); 27999ebb4caSwyllys } 28099ebb4caSwyllys } 28199ebb4caSwyllys 28299ebb4caSwyllys 28399ebb4caSwyllys /* No additional args allowed. */ 28499ebb4caSwyllys argc -= optind_av; 28599ebb4caSwyllys argv += optind_av; 28699ebb4caSwyllys if (argc != 0) 28799ebb4caSwyllys return (PK_ERR_USAGE); 28899ebb4caSwyllys 28999ebb4caSwyllys /* Done parsing command line options. */ 29099ebb4caSwyllys if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { 29199ebb4caSwyllys token_spec = PK_DEFAULT_PK11TOKEN; 29299ebb4caSwyllys } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { 29399ebb4caSwyllys token_spec = DEFAULT_NSS_TOKEN; 29499ebb4caSwyllys } 29599ebb4caSwyllys 29630a5e8faSwyllys if ((rv = kmf_initialize(&handle, NULL, NULL)) != KMF_OK) 29799ebb4caSwyllys return (rv); 29899ebb4caSwyllys 29947e946e7SWyllys Ingersoll if (utype != NULL) { 30047e946e7SWyllys Ingersoll if (strcmp(utype, "so") == 0) 30147e946e7SWyllys Ingersoll souser = 1; 30247e946e7SWyllys Ingersoll else if (strcmp(utype, "user") == 0) 30347e946e7SWyllys Ingersoll souser = 0; 30447e946e7SWyllys Ingersoll else /* Wrong option string */ 30547e946e7SWyllys Ingersoll return (PK_ERR_USAGE); 30647e946e7SWyllys Ingersoll } 30747e946e7SWyllys Ingersoll 30899ebb4caSwyllys switch (kstype) { 30999ebb4caSwyllys case KMF_KEYSTORE_PK11TOKEN: 31047e946e7SWyllys Ingersoll rv = setpin_pkcs11(handle, token_spec, souser); 31199ebb4caSwyllys break; 31299ebb4caSwyllys case KMF_KEYSTORE_NSS: 31399ebb4caSwyllys rv = setpin_nss(handle, token_spec, dir, prefix); 31499ebb4caSwyllys break; 31599ebb4caSwyllys default: 31699ebb4caSwyllys cryptoerror(LOG_STDERR, 31799ebb4caSwyllys gettext("incorrect keystore.")); 31899ebb4caSwyllys return (PK_ERR_USAGE); 31999ebb4caSwyllys } 32099ebb4caSwyllys 32130a5e8faSwyllys (void) kmf_finalize(handle); 32299ebb4caSwyllys 32399ebb4caSwyllys if (rv == KMF_ERR_AUTH_FAILED) { 32499ebb4caSwyllys cryptoerror(LOG_STDERR, 32599ebb4caSwyllys gettext("Incorrect passphrase.")); 32699ebb4caSwyllys return (PK_ERR_SYSTEM); 32799ebb4caSwyllys } else if (rv != CKR_OK) { 32899ebb4caSwyllys cryptoerror(LOG_STDERR, 32999ebb4caSwyllys gettext("Unable to change passphrase.")); 33099ebb4caSwyllys return (PK_ERR_SYSTEM); 33199ebb4caSwyllys } else { 3327711facfSdinak (void) fprintf(stdout, gettext("Passphrase changed.\n")); 33399ebb4caSwyllys } 3347711facfSdinak return (0); 3357c478bd9Sstevel@tonic-gate } 336