#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <strings.h>
#include <libgen.h>
#include <pthread.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>
#include <cryptoutil.h>
#define PK11_URI_PREFIX "pkcs11:"
#define PK11_TOKEN "token"
#define PK11_MANUF "manufacturer"
#define PK11_SERIAL "serial"
#define PK11_MODEL "model"
#define PK11_OBJECT "object"
#define PK11_OBJECTTYPE "objecttype"
#define PK11_ID "id"
#define PK11_PINFILE "pinfile"
static int
read_id(char *str, unsigned char *output, int out_len)
{
int i, len, n;
unsigned int x1, x2;
len = strlen(str);
(void) memset(output, 0, out_len);
i = 0;
n = 0;
while (i < len) {
if (sscanf(str + i, "%1x", &x1) != 1)
return (0);
++i;
if (sscanf(str + i, "%1x", &x2) == 1) {
x1 = x1 * 16 + x2;
++i;
}
if ((n + 1) > out_len)
return (0);
output[n] = (unsigned char)x1;
if (i < len) {
if (str[i] != ':')
return (0);
++i;
}
++n;
}
return (n);
}
int
pkcs11_parse_uri(const char *str, pkcs11_uri_t *uri)
{
char *str2, *l1, *l2, *tok, *name;
(void) memset(uri, 0, sizeof (pkcs11_uri_t));
uri->objecttype_present = B_FALSE;
if (strncmp(str, PK11_URI_PREFIX, strlen(PK11_URI_PREFIX)) != 0)
return (PK11_NOT_PKCS11_URI);
if ((str2 = strdup(str + strlen(PK11_URI_PREFIX))) == NULL)
return (PK11_MALLOC_ERROR);
if (strstr(str2, ";;") != NULL || str2[0] == ';' ||
(strlen(str2) > 0 && str2[strlen(str2) - 1] == ';'))
goto bad_uri;
tok = strtok_r(str2, ";", &l1);
for (; tok != NULL; tok = strtok_r(NULL, ";", &l1)) {
name = strtok_r(tok, "=", &l2);
if (l2 == NULL)
goto bad_uri;
if (strcmp(name, PK11_TOKEN) == 0) {
if (uri->token != NULL)
goto bad_uri;
if (strlen(l2) > 32)
goto value_overflow;
if ((uri->token = (unsigned char *)strdup(l2)) == NULL)
goto malloc_failed;
} else if (strcmp(name, PK11_MANUF) == 0) {
if (uri->manuf != NULL)
goto bad_uri;
if (strlen(l2) > 32)
goto value_overflow;
if ((uri->manuf = (unsigned char *)strdup(l2)) == NULL)
goto malloc_failed;
} else if (strcmp(name, PK11_SERIAL) == 0) {
if (uri->serial != NULL)
goto bad_uri;
if (strlen(l2) > 16)
goto value_overflow;
if ((uri->serial = (unsigned char *)strdup(l2)) == NULL)
goto malloc_failed;
} else if (strcmp(name, PK11_MODEL) == 0) {
if (uri->model != NULL)
goto bad_uri;
if (strlen(l2) > 16)
goto value_overflow;
if ((uri->model = (unsigned char *)strdup(l2)) == NULL)
goto malloc_failed;
} else if (strcmp(name, PK11_ID) == 0) {
if (uri->id_len != 0)
goto bad_uri;
if (strlen(l2) > PK11_MAX_ID_LEN * 2 +
PK11_MAX_ID_LEN - 1) {
goto value_overflow;
}
if ((uri->id = malloc(PK11_MAX_ID_LEN)) == NULL)
goto malloc_failed;
uri->id_len = read_id(l2, uri->id,
PK11_MAX_ID_LEN);
if (uri->id_len == 0)
goto bad_uri;
} else if (strcmp(name, PK11_OBJECT) == 0) {
if (uri->object != NULL)
goto bad_uri;
if (strlen(l2) > PK11_MAX_OBJECT_LEN)
goto value_overflow;
if ((uri->object = (unsigned char *)strdup(l2)) == NULL)
goto malloc_failed;
} else if (strcmp(name, PK11_OBJECTTYPE) == 0) {
if (uri->objecttype_present == CK_TRUE)
goto bad_uri;
if (strcmp(l2, "public") == 0)
uri->objecttype = CKO_PUBLIC_KEY;
else if (strcmp(l2, "private") == 0)
uri->objecttype = CKO_PRIVATE_KEY;
else if (strcmp(l2, "cert") == 0)
uri->objecttype = CKO_CERTIFICATE;
else if (strcmp(l2, "secretkey") == 0)
uri->objecttype = CKO_SECRET_KEY;
else if (strcmp(l2, "data") == 0)
uri->objecttype = CKO_DATA;
else
goto bad_uri;
uri->objecttype_present = CK_TRUE;
} else if (strcmp(name, PK11_PINFILE) == 0)
if (uri->pinfile == NULL) {
if (strlen(l2) > MAXPATHLEN)
goto value_overflow;
if ((uri->pinfile = strdup(l2)) == NULL)
goto malloc_failed;
if (uri->pinfile[0] == '\0')
goto bad_uri;
} else
goto bad_uri;
else
goto bad_uri;
}
free(str2);
return (PK11_URI_OK);
malloc_failed:
free(str2);
pkcs11_free_uri(uri);
return (PK11_MALLOC_ERROR);
bad_uri:
free(str2);
pkcs11_free_uri(uri);
return (PK11_URI_INVALID);
value_overflow:
free(str2);
pkcs11_free_uri(uri);
return (PK11_URI_VALUE_OVERFLOW);
}
void
pkcs11_free_uri(pkcs11_uri_t *uri)
{
if (uri->object != NULL)
free(uri->object);
if (uri->token != NULL)
free(uri->token);
if (uri->manuf != NULL)
free(uri->manuf);
if (uri->serial != NULL)
free(uri->serial);
if (uri->model != NULL)
free(uri->model);
if (uri->id != NULL)
free(uri->id);
if (uri->pinfile != NULL)
free(uri->pinfile);
}