xref: /titanic_50/usr/src/cmd/cmd-crypto/pktool/setpin.c (revision 47e946e784719ae402ace34695f67b0e6e76ae5c)
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 /*
22*47e946e7SWyllys Ingersoll  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * This file implements the setpin operation for this tool.
287c478bd9Sstevel@tonic-gate  * The basic flow of the process is to load the PKCS#11 module,
297711facfSdinak  * finds the soft token, prompt the user for the old PIN (if
307711facfSdinak  * any) and the new PIN, change the token's PIN, and clean up.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357711facfSdinak #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
387c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
397c478bd9Sstevel@tonic-gate #include "common.h"
407c478bd9Sstevel@tonic-gate 
4199ebb4caSwyllys static int
4299ebb4caSwyllys setpin_nss(KMF_HANDLE_T handle,
4399ebb4caSwyllys 	char *token_spec, char *dir, char *prefix)
447c478bd9Sstevel@tonic-gate {
4599ebb4caSwyllys 	int rv = 0;
4630a5e8faSwyllys 	KMF_CREDENTIAL		oldcred = {NULL, 0};
4799ebb4caSwyllys 	KMF_CREDENTIAL		newpincred = {NULL, 0};
4899ebb4caSwyllys 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
4999ebb4caSwyllys 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
5030a5e8faSwyllys 	KMF_ATTRIBUTE		setpinattrs[6];
5130a5e8faSwyllys 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_NSS;
5230a5e8faSwyllys 	int			numattrs = 0;
5399ebb4caSwyllys 
5499ebb4caSwyllys 	rv = configure_nss(handle, dir, prefix);
5599ebb4caSwyllys 	if (rv != KMF_OK)
5699ebb4caSwyllys 		return (rv);
5799ebb4caSwyllys 
5830a5e8faSwyllys 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_KEYSTORE_TYPE_ATTR,
5930a5e8faSwyllys 	    &kstype, sizeof (kstype));
6030a5e8faSwyllys 	numattrs++;
6130a5e8faSwyllys 	if (token_spec != NULL) {
6230a5e8faSwyllys 		kmf_set_attr_at_index(setpinattrs, numattrs,
6330a5e8faSwyllys 		    KMF_TOKEN_LABEL_ATTR,
6430a5e8faSwyllys 		    token_spec, strlen(token_spec));
6530a5e8faSwyllys 		numattrs++;
6630a5e8faSwyllys 	}
6799ebb4caSwyllys 
6899ebb4caSwyllys 	if ((rv = get_pin(gettext("Enter current token passphrase "
6930a5e8faSwyllys 	    "(<CR> if not set):"), NULL, &old_pin, &old_pinlen)) != CKR_OK) {
7099ebb4caSwyllys 		cryptoerror(LOG_STDERR,
7199ebb4caSwyllys 		    gettext("Unable to get token passphrase."));
7299ebb4caSwyllys 		return (PK_ERR_NSS);
7399ebb4caSwyllys 	}
7499ebb4caSwyllys 	/* Get the user's new PIN. */
7599ebb4caSwyllys 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
7699ebb4caSwyllys 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
7799ebb4caSwyllys 		if (rv == CKR_PIN_INCORRECT)
7899ebb4caSwyllys 			cryptoerror(LOG_STDERR, gettext(
7999ebb4caSwyllys 			    "Passphrases do not match."));
8099ebb4caSwyllys 		else
8199ebb4caSwyllys 			cryptoerror(LOG_STDERR, gettext(
8299ebb4caSwyllys 			    "Unable to get and confirm new passphrase."));
8399ebb4caSwyllys 		if (old_pin != NULL)
8499ebb4caSwyllys 			free(old_pin);
8599ebb4caSwyllys 		return (PK_ERR_NSS);
8699ebb4caSwyllys 	}
8799ebb4caSwyllys 
8830a5e8faSwyllys 	oldcred.cred = (char *)old_pin;
8930a5e8faSwyllys 	oldcred.credlen = old_pinlen;
9030a5e8faSwyllys 
9130a5e8faSwyllys 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_CREDENTIAL_ATTR,
9230a5e8faSwyllys 	    &oldcred, sizeof (oldcred));
9330a5e8faSwyllys 	numattrs++;
9499ebb4caSwyllys 
9599ebb4caSwyllys 	newpincred.cred = (char *)new_pin;
9699ebb4caSwyllys 	newpincred.credlen = new_pinlen;
9730a5e8faSwyllys 	kmf_set_attr_at_index(setpinattrs, numattrs, KMF_NEWPIN_ATTR,
9830a5e8faSwyllys 	    &newpincred, sizeof (newpincred));
9930a5e8faSwyllys 	numattrs++;
10099ebb4caSwyllys 
10130a5e8faSwyllys 	rv = kmf_set_token_pin(handle, numattrs, setpinattrs);
10299ebb4caSwyllys 
10399ebb4caSwyllys 	if (new_pin)
10499ebb4caSwyllys 		free(new_pin);
10599ebb4caSwyllys 	if (old_pin)
10699ebb4caSwyllys 		free(old_pin);
10799ebb4caSwyllys 
10899ebb4caSwyllys 	return (rv);
10999ebb4caSwyllys }
11099ebb4caSwyllys 
11199ebb4caSwyllys static int
112*47e946e7SWyllys Ingersoll setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec, boolean_t souser)
11399ebb4caSwyllys {
1147c478bd9Sstevel@tonic-gate 	CK_SLOT_ID		slot_id;
1157c478bd9Sstevel@tonic-gate 	CK_FLAGS		pin_state;
1167711facfSdinak 	CK_UTF8CHAR_PTR		old_pin = NULL, new_pin = NULL;
1177711facfSdinak 	CK_ULONG		old_pinlen = 0, new_pinlen = 0;
1187711facfSdinak 	CK_RV			rv = CKR_OK;
11999ebb4caSwyllys 	char			*token_name = NULL;
12099ebb4caSwyllys 	CK_TOKEN_INFO		token_info;
12199ebb4caSwyllys 	KMF_CREDENTIAL		newpincred = {NULL, 0};
12230a5e8faSwyllys 	KMF_CREDENTIAL		oldcred = {NULL, 0};
12330a5e8faSwyllys 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_PK11TOKEN;
12430a5e8faSwyllys 	KMF_ATTRIBUTE		attrlist[6];
125*47e946e7SWyllys Ingersoll 	CK_USER_TYPE		user = CKU_USER;
12630a5e8faSwyllys 	int			numattr = 0;
12749e21299Sdinak 
12849e21299Sdinak 	/* If nothing is specified, default is to use softtoken. */
12949e21299Sdinak 	if (token_spec == NULL) {
13099ebb4caSwyllys 		token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID;
13149e21299Sdinak 		token_name = SOFT_TOKEN_LABEL;
13249e21299Sdinak 	}
1337711facfSdinak 
13430a5e8faSwyllys 	rv = kmf_pk11_token_lookup(NULL, token_spec, &slot_id);
13599ebb4caSwyllys 	if (rv == KMF_OK) {
13699ebb4caSwyllys 		/* find the pin state for the selected token */
13799ebb4caSwyllys 		if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK)
1387711facfSdinak 			return (PK_ERR_PK11);
13999ebb4caSwyllys 
14099ebb4caSwyllys 		pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED;
14199ebb4caSwyllys 		if (token_name == NULL)
14299ebb4caSwyllys 			token_name = (char *)token_info.label;
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	/*
1467711facfSdinak 	 * If the token is the softtoken, check if the token flags show the
1477711facfSdinak 	 * PIN has not been set yet.  If not then set the old PIN to the
1487711facfSdinak 	 * default "changeme".  Otherwise, let user type in the correct old
1497711facfSdinak 	 * PIN to unlock token.
1507c478bd9Sstevel@tonic-gate 	 */
1517711facfSdinak 	if (pin_state == CKF_USER_PIN_TO_BE_CHANGED &&
1527711facfSdinak 	    strcmp(token_name, SOFT_TOKEN_LABEL) == 0) {
1537711facfSdinak 		if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) ==
1547711facfSdinak 		    NULL) {
1557711facfSdinak 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
1567711facfSdinak 			final_pk11(NULL);
1577711facfSdinak 			return (PK_ERR_PK11);
1587711facfSdinak 		}
1597711facfSdinak 		old_pinlen = strlen(SOFT_DEFAULT_PIN);
1607711facfSdinak 	} else {
1617711facfSdinak 		if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
1627711facfSdinak 		    &old_pin, &old_pinlen)) != CKR_OK) {
1637711facfSdinak 			cryptoerror(LOG_STDERR,
1647711facfSdinak 			    gettext("Unable to get token passphrase (%s)."),
1657711facfSdinak 			    pkcs11_strerror(rv));
1667711facfSdinak 			final_pk11(NULL);
1677711facfSdinak 			return (PK_ERR_PK11);
1687711facfSdinak 		}
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 
1717711facfSdinak 	/* Get the user's new PIN. */
1727711facfSdinak 	if ((rv = get_pin(gettext("Create new passphrase:"), gettext(
1737711facfSdinak 	    "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) {
1747711facfSdinak 		if (rv == CKR_PIN_INCORRECT)
1757711facfSdinak 			cryptoerror(LOG_STDERR, gettext(
1767711facfSdinak 			    "Passphrases do not match."));
1777711facfSdinak 		else
1787711facfSdinak 			cryptoerror(LOG_STDERR, gettext(
1797711facfSdinak 			    "Unable to get and confirm new passphrase (%s)."),
1807711facfSdinak 			    pkcs11_strerror(rv));
1817711facfSdinak 		free(old_pin);
1827711facfSdinak 		final_pk11(NULL);
1837711facfSdinak 		return (PK_ERR_PK11);
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
18630a5e8faSwyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
18730a5e8faSwyllys 	    &kstype, sizeof (kstype));
18830a5e8faSwyllys 	numattr++;
18930a5e8faSwyllys 	if (token_name != NULL) {
19030a5e8faSwyllys 		kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR,
19130a5e8faSwyllys 		    token_name, strlen(token_name));
19230a5e8faSwyllys 		numattr++;
19330a5e8faSwyllys 	}
19430a5e8faSwyllys 	oldcred.cred = (char *)old_pin;
19530a5e8faSwyllys 	oldcred.credlen = old_pinlen;
19630a5e8faSwyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR,
19730a5e8faSwyllys 	    &oldcred, sizeof (oldcred));
19830a5e8faSwyllys 	numattr++;
19930a5e8faSwyllys 
20030a5e8faSwyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_SLOT_ID_ATTR,
20130a5e8faSwyllys 	    &slot_id, sizeof (slot_id));
20230a5e8faSwyllys 	numattr++;
2037711facfSdinak 
20499ebb4caSwyllys 	newpincred.cred = (char *)new_pin;
20599ebb4caSwyllys 	newpincred.credlen = new_pinlen;
20630a5e8faSwyllys 	kmf_set_attr_at_index(attrlist, numattr, KMF_NEWPIN_ATTR,
20730a5e8faSwyllys 	    &newpincred, sizeof (newpincred));
20830a5e8faSwyllys 	numattr++;
20999ebb4caSwyllys 
210*47e946e7SWyllys Ingersoll 	if (souser) {
211*47e946e7SWyllys Ingersoll 		user = CKU_SO;
212*47e946e7SWyllys Ingersoll 		kmf_set_attr_at_index(attrlist, numattr,
213*47e946e7SWyllys Ingersoll 		    KMF_PK11_USER_TYPE_ATTR,
214*47e946e7SWyllys Ingersoll 		    &user, sizeof (user));
215*47e946e7SWyllys Ingersoll 		numattr++;
216*47e946e7SWyllys Ingersoll 	}
217*47e946e7SWyllys Ingersoll 
21830a5e8faSwyllys 	rv = kmf_set_token_pin(handle, numattr, attrlist);
2197711facfSdinak 
2207711facfSdinak 	/* Clean up. */
22199ebb4caSwyllys 	if (old_pin != NULL)
2227711facfSdinak 		free(old_pin);
22399ebb4caSwyllys 	if (new_pin != NULL)
2247711facfSdinak 		free(new_pin);
2257711facfSdinak 
22699ebb4caSwyllys 	return (rv);
2277711facfSdinak }
2287711facfSdinak 
22999ebb4caSwyllys /*
23099ebb4caSwyllys  * Changes the token's PIN.
23199ebb4caSwyllys  */
23299ebb4caSwyllys int
23399ebb4caSwyllys pk_setpin(int argc, char *argv[])
23499ebb4caSwyllys /* ARGSUSED */
23599ebb4caSwyllys {
23699ebb4caSwyllys 	int		opt;
23799ebb4caSwyllys 	int		rv;
23899ebb4caSwyllys 	extern int	optind_av;
23999ebb4caSwyllys 	extern char	*optarg_av;
24099ebb4caSwyllys 	char		*token_spec = NULL;
24199ebb4caSwyllys 	char		*dir = NULL;
24299ebb4caSwyllys 	char		*prefix = NULL;
243*47e946e7SWyllys Ingersoll 	char		*utype = NULL;
24499ebb4caSwyllys 	KMF_HANDLE_T	handle;
24599ebb4caSwyllys 	KMF_KEYSTORE_TYPE	kstype = KMF_KEYSTORE_PK11TOKEN;
246*47e946e7SWyllys Ingersoll 	boolean_t	souser = 0;
24799ebb4caSwyllys 
24899ebb4caSwyllys 	/* Parse command line options.  Do NOT i18n/l10n. */
24999ebb4caSwyllys 	while ((opt = getopt_av(argc, argv,
25099ebb4caSwyllys 		"T:(token)k:(keystore)d:(dir)"
251*47e946e7SWyllys Ingersoll 		"p:(prefix)u:(usertype)")) != EOF) {
25299ebb4caSwyllys 		switch (opt) {
25399ebb4caSwyllys 			case 'k':
25499ebb4caSwyllys 				kstype = KS2Int(optarg_av);
25599ebb4caSwyllys 				if (kstype == 0)
25699ebb4caSwyllys 					return (PK_ERR_USAGE);
25799ebb4caSwyllys 				break;
25899ebb4caSwyllys 			case 'T':	/* token specifier */
25999ebb4caSwyllys 				if (token_spec)
26099ebb4caSwyllys 					return (PK_ERR_USAGE);
26199ebb4caSwyllys 				token_spec = optarg_av;
26299ebb4caSwyllys 				break;
26399ebb4caSwyllys 			case 'd':
26499ebb4caSwyllys 				if (dir)
26599ebb4caSwyllys 					return (PK_ERR_USAGE);
26699ebb4caSwyllys 				dir = optarg_av;
26799ebb4caSwyllys 				break;
26899ebb4caSwyllys 			case 'p':
26999ebb4caSwyllys 				if (prefix)
27099ebb4caSwyllys 					return (PK_ERR_USAGE);
27199ebb4caSwyllys 				prefix = optarg_av;
27299ebb4caSwyllys 				break;
273*47e946e7SWyllys Ingersoll 			case 'u':
274*47e946e7SWyllys Ingersoll 				utype = optarg_av;
275*47e946e7SWyllys Ingersoll 				break;
27699ebb4caSwyllys 			default:
27799ebb4caSwyllys 				return (PK_ERR_USAGE);
27899ebb4caSwyllys 				break;
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 
299*47e946e7SWyllys Ingersoll 	if (utype != NULL) {
300*47e946e7SWyllys Ingersoll 		if (strcmp(utype, "so") == 0)
301*47e946e7SWyllys Ingersoll 			souser = 1;
302*47e946e7SWyllys Ingersoll 		else if (strcmp(utype, "user") == 0)
303*47e946e7SWyllys Ingersoll 			souser = 0;
304*47e946e7SWyllys Ingersoll 		else /* Wrong option string */
305*47e946e7SWyllys Ingersoll 			return (PK_ERR_USAGE);
306*47e946e7SWyllys Ingersoll 	}
307*47e946e7SWyllys Ingersoll 
30899ebb4caSwyllys 	switch (kstype) {
30999ebb4caSwyllys 		case KMF_KEYSTORE_PK11TOKEN:
310*47e946e7SWyllys 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