2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A *
2N/A * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <sys/types.h>
2N/A#include <sys/wait.h>
2N/A#include <unistd.h>
2N/A#include <strings.h>
2N/A#include <libgen.h>
2N/A#include <pthread.h>
2N/A#include <ctype.h>
2N/A
2N/A#include <security/cryptoki.h>
2N/A#include <security/pkcs11.h>
2N/A
2N/A#include <cryptoutil.h>
2N/A
2N/A/* PKCS#11 URI prefix and attributes. */
2N/A#define PK11_URI_PREFIX "pkcs11:"
2N/A#define PK11_TOKEN "token"
2N/A#define PK11_MANUF "manufacturer"
2N/A#define PK11_SERIAL "serial"
2N/A#define PK11_MODEL "model"
2N/A#define PK11_OBJECT "object"
2N/A#define PK11_OBJECTTYPE "objecttype"
2N/A#define PK11_ID "id"
2N/A#define PK11_PINFILE "pinfile"
2N/A
2N/A/*
2N/A * Gets a hexadecimal string of the xx:xx:xx-like format and fills the output
2N/A * buffer with bytes representing each of the hexadecimal numbers. Returns 0 on
2N/A * error (missing ':', not a hexadecimal character (eg. 'z'), output buffer
2N/A * overflow, etc.), or the number of hexadecimal numbers processed.
2N/A *
2N/A * Returns:
2N/A * 0
2N/A * on failure
2N/A * >0
2N/A * number of bytes returned via the output parameter
2N/A */
2N/Astatic int
2N/Aread_id(char *str, unsigned char *output, int out_len)
2N/A{
2N/A int i, len, n;
2N/A unsigned int x1, x2;
2N/A
2N/A len = strlen(str);
2N/A (void) memset(output, 0, out_len);
2N/A /* Counter of the processed bytes. */
2N/A i = 0;
2N/A /* Counter for the used output bytes. */
2N/A n = 0;
2N/A
2N/A while (i < len) {
2N/A /* We require at least one hexadecimal character. */
2N/A if (sscanf(str + i, "%1x", &x1) != 1)
2N/A return (0);
2N/A ++i;
2N/A /* And we accept the 2nd one if it is there. */
2N/A if (sscanf(str + i, "%1x", &x2) == 1) {
2N/A x1 = x1 * 16 + x2;
2N/A ++i;
2N/A }
2N/A
2N/A /* Output buffer overflow? */
2N/A if ((n + 1) > out_len)
2N/A return (0);
2N/A output[n] = (unsigned char)x1;
2N/A /* Still some bytes to process? */
2N/A if (i < len) {
2N/A /* ':' is the only acceptable delimiter. */
2N/A if (str[i] != ':')
2N/A return (0);
2N/A /* Skip ':' */
2N/A ++i;
2N/A }
2N/A ++n;
2N/A }
2N/A
2N/A return (n);
2N/A}
2N/A
2N/Astatic char hex_table[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2N/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2N/A 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11,
2N/A 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2N/A 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2N/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2N/A
2N/A#define X2CHAR(x) (hex_table[x])
2N/A
2N/A/*
2N/A * Performs inline percent-decoding of string str.
2N/A * String must be zero-terminated! Implies, that str must not be NULL either.
2N/A * Returns: length of the resulting string
2N/A */
2N/Asize_t
2N/Apct_decode(char *str)
2N/A{
2N/A char *p, *q;
2N/A p = q = str;
2N/A
2N/A while (*p != '\0') {
2N/A /* cannot overflow - zero-termination constraint on str */
2N/A if ((*p == '%') && isxdigit(p[1]) && isxdigit(p[2])) {
2N/A *q = (X2CHAR(p[1]) << 4) + X2CHAR(p[2]);
2N/A p += 3;
2N/A } else {
2N/A /* not copying common unescaped prefix */
2N/A if (q != p) {
2N/A *q = *p;
2N/A }
2N/A p++;
2N/A }
2N/A q++;
2N/A }
2N/A *q = '\0';
2N/A return (q - str);
2N/A}
2N/A
2N/A/*
2N/A * Process the PKCS#11 URI. The function expects an allocated URI structure. The
2N/A * caller is later expected to call pkcs11_free_uri() when the parsed URI is no
2N/A * longer needed.
2N/A *
2N/A * Note that the caller needs to call pkcs11_free_uri() on the 'uri' structure
2N/A * only if PK11_URI_OK is returned but it is always safe to do that since
2N/A * pkcs11_free_uri() checks for NULLs and the structure is zeroized here before
2N/A * it is used.
2N/A *
2N/A * Returns:
2N/A * PK11_URI_OK
2N/A * success
2N/A * PK11_URI_INVALID
2N/A * invalid PKCS#11 URI (one that has the "pkcs11:" prefix but is
2N/A * otherwise incorrectly specified)
2N/A * PK11_MALLOC_ERROR
2N/A * malloc(3C) failed when allocating one of the internal buffers.
2N/A * This error can be returned only after the correct "pkcs11:"
2N/A * prefix was found but it does not give any information about the
2N/A * syntax correctness of the URI body.
2N/A * PK11_URI_VALUE_OVERFLOW
2N/A * some attributes in the URI are of the fixed length according to
2N/A * the spec. If any of those attributes overflows we report an
2N/A * error
2N/A * PK11_NOT_PKCS11_URI
2N/A * the URI supplied is not the PKCS#11 URI at all (does not have
2N/A * the "pkcs11:" prefix)
2N/A */
2N/Aint
2N/Apkcs11_parse_uri(const char *str, pkcs11_uri_t *uri)
2N/A{
2N/A char *str2, *l1, *l2, *tok, *name;
2N/A size_t len;
2N/A
2N/A /* Initialize the structure. */
2N/A (void) memset(uri, 0, sizeof (pkcs11_uri_t));
2N/A /* Be really safe. */
2N/A uri->objecttype_present = B_FALSE;
2N/A
2N/A /* Check that we have the correct PKCS#11 URI prefix. */
2N/A if (strncmp(str, PK11_URI_PREFIX, strlen(PK11_URI_PREFIX)) != 0)
2N/A return (PK11_NOT_PKCS11_URI);
2N/A /* Dup the string and skip over the prefix then. */
2N/A if ((str2 = strdup(str + strlen(PK11_URI_PREFIX))) == NULL)
2N/A return (PK11_MALLOC_ERROR);
2N/A
2N/A /*
2N/A * Using strtok_r() would silently skip over multiple semicolons. We
2N/A * must check such situation before moving on. We must also avoid ';' as
2N/A * the first and the last character of the URI.
2N/A */
2N/A if (strstr(str2, ";;") != NULL || str2[0] == ';' ||
2N/A (strlen(str2) > 0 && str2[strlen(str2) - 1] == ';'))
2N/A goto bad_uri;
2N/A
2N/A /* Now parse the URI. */
2N/A tok = strtok_r(str2, ";", &l1);
2N/A for (; tok != NULL; tok = strtok_r(NULL, ";", &l1)) {
2N/A /* "tok" is not empty so there will be something in "name". */
2N/A name = strtok_r(tok, "=", &l2);
2N/A /* Check whether there is '=' at all. */
2N/A if (l2 == NULL)
2N/A goto bad_uri;
2N/A
2N/A /*
2N/A * Fill out the URI structure. We do not accept duplicate
2N/A * attributes.
2N/A */
2N/A if (strcmp(name, PK11_TOKEN) == 0) {
2N/A /* Check for duplicity. */
2N/A if (uri->token != NULL)
2N/A goto bad_uri;
2N/A len = pct_decode(l2);
2N/A if (len > 32)
2N/A goto value_overflow;
2N/A if ((uri->token = (unsigned char *)strdup(l2)) == NULL)
2N/A goto malloc_failed;
2N/A } else if (strcmp(name, PK11_MANUF) == 0) {
2N/A /* Check for duplicity. */
2N/A if (uri->manuf != NULL)
2N/A goto bad_uri;
2N/A len = pct_decode(l2);
2N/A if (len > 32)
2N/A goto value_overflow;
2N/A if ((uri->manuf = (unsigned char *)strdup(l2)) == NULL)
2N/A goto malloc_failed;
2N/A } else if (strcmp(name, PK11_SERIAL) == 0) {
2N/A /* Check for duplicity. */
2N/A if (uri->serial != NULL)
2N/A goto bad_uri;
2N/A len = pct_decode(l2);
2N/A if (len > 16)
2N/A goto value_overflow;
2N/A if ((uri->serial = (unsigned char *)strdup(l2)) == NULL)
2N/A goto malloc_failed;
2N/A } else if (strcmp(name, PK11_MODEL) == 0) {
2N/A /* Check for duplicity. */
2N/A if (uri->model != NULL)
2N/A goto bad_uri;
2N/A len = pct_decode(l2);
2N/A if (len > 16)
2N/A goto value_overflow;
2N/A if ((uri->model = (unsigned char *)strdup(l2)) == NULL)
2N/A goto malloc_failed;
2N/A } else if (strcmp(name, PK11_ID) == 0) {
2N/A /* Check for duplicity. */
2N/A if (uri->id_len != 0)
2N/A goto bad_uri;
2N/A /*
2N/A * We can have maximum of PK11_MAX_ID_LEN 2-byte
2N/A * numbers separated by ':'s, like
2N/A * 01:02:0A:FF:...
2N/A */
2N/A if (strlen(l2) > PK11_MAX_ID_LEN * 2 +
2N/A PK11_MAX_ID_LEN - 1) {
2N/A goto value_overflow;
2N/A }
2N/A if ((uri->id = malloc(PK11_MAX_ID_LEN)) == NULL)
2N/A goto malloc_failed;
2N/A uri->id_len = read_id(l2, uri->id,
2N/A PK11_MAX_ID_LEN);
2N/A if (uri->id_len == 0)
2N/A goto bad_uri;
2N/A } else if (strcmp(name, PK11_OBJECT) == 0) {
2N/A /* Check for duplicity. */
2N/A if (uri->object != NULL)
2N/A goto bad_uri;
2N/A len = pct_decode(l2);
2N/A if (len > PK11_MAX_OBJECT_LEN)
2N/A goto value_overflow;
2N/A if ((uri->object = (unsigned char *)strdup(l2)) == NULL)
2N/A goto malloc_failed;
2N/A } else if (strcmp(name, PK11_OBJECTTYPE) == 0) {
2N/A /*
2N/A * Check for duplicity. objecttype can not be empty, it
2N/A * would not make sense.
2N/A */
2N/A if (uri->objecttype_present == CK_TRUE)
2N/A goto bad_uri;
2N/A if (strcmp(l2, "public") == 0)
2N/A uri->objecttype = CKO_PUBLIC_KEY;
2N/A else if (strcmp(l2, "private") == 0)
2N/A uri->objecttype = CKO_PRIVATE_KEY;
2N/A else if (strcmp(l2, "cert") == 0)
2N/A uri->objecttype = CKO_CERTIFICATE;
2N/A else if (strcmp(l2, "secretkey") == 0)
2N/A uri->objecttype = CKO_SECRET_KEY;
2N/A else if (strcmp(l2, "data") == 0)
2N/A uri->objecttype = CKO_DATA;
2N/A else
2N/A goto bad_uri;
2N/A uri->objecttype_present = CK_TRUE;
2N/A } else if (strcmp(name, PK11_PINFILE) == 0)
2N/A /* Check for duplicity. */
2N/A if (uri->pinfile == NULL) {
2N/A len = pct_decode(l2);
2N/A if (len > MAXPATHLEN)
2N/A goto value_overflow;
2N/A if ((uri->pinfile = strdup(l2)) == NULL)
2N/A goto malloc_failed;
2N/A /* Empty pinfile makes no sense. */
2N/A if (uri->pinfile[0] == '\0')
2N/A goto bad_uri;
2N/A } else
2N/A goto bad_uri;
2N/A else
2N/A /* Unknown attribute name. */
2N/A goto bad_uri;
2N/A }
2N/A
2N/A free(str2);
2N/A return (PK11_URI_OK);
2N/Amalloc_failed:
2N/A free(str2);
2N/A pkcs11_free_uri(uri);
2N/A return (PK11_MALLOC_ERROR);
2N/Abad_uri:
2N/A free(str2);
2N/A pkcs11_free_uri(uri);
2N/A return (PK11_URI_INVALID);
2N/Avalue_overflow:
2N/A free(str2);
2N/A pkcs11_free_uri(uri);
2N/A return (PK11_URI_VALUE_OVERFLOW);
2N/A}
2N/A
2N/A/*
2N/A * Free the PKCS#11 URI structure attributes but do not free the structure
2N/A * itself. The caller needs to call this function only if pkcs11_parse_uri()
2N/A * returned PK11_URI_OK. However, it is always safe to do that for other return
2N/A * codes as well since the structure is zeroized at the beginning of
2N/A * pkcs11_parse_uri() and we check for NULLs here.
2N/A */
2N/Avoid
2N/Apkcs11_free_uri(pkcs11_uri_t *uri)
2N/A{
2N/A if (uri->object != NULL)
2N/A free(uri->object);
2N/A if (uri->token != NULL)
2N/A free(uri->token);
2N/A if (uri->manuf != NULL)
2N/A free(uri->manuf);
2N/A if (uri->serial != NULL)
2N/A free(uri->serial);
2N/A if (uri->model != NULL)
2N/A free(uri->model);
2N/A if (uri->id != NULL)
2N/A free(uri->id);
2N/A if (uri->pinfile != NULL)
2N/A free(uri->pinfile);
2N/A}