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
setpin_nss(KMF_HANDLE_T handle,char * token_spec,char * dir,char * prefix)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
setpin_pkcs11(KMF_HANDLE_T handle,char * token_spec,boolean_t souser)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
pk_setpin(int argc,char * argv[])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