Blame src/eng_parse.c

Packit 6b81fa
/*
Packit 6b81fa
 * Copyright (c) 2001 Markus Friedl
Packit 6b81fa
 * Copyright (c) 2002 Juha Yrjölä
Packit 6b81fa
 * Copyright (c) 2002 Olaf Kirch
Packit 6b81fa
 * Copyright (c) 2003 Kevin Stefanik
Packit 6b81fa
 * Copyright (c) 2016-2017 Michał Trojnara <Michal.Trojnara@stunnel.org>
Packit 6b81fa
 *
Packit 6b81fa
 * Redistribution and use in source and binary forms, with or without
Packit 6b81fa
 * modification, are permitted provided that the following conditions
Packit 6b81fa
 * are met:
Packit 6b81fa
 * 1. Redistributions of source code must retain the above copyright
Packit 6b81fa
 *    notice, this list of conditions and the following disclaimer.
Packit 6b81fa
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 6b81fa
 *    notice, this list of conditions and the following disclaimer in the
Packit 6b81fa
 *    documentation and/or other materials provided with the distribution.
Packit 6b81fa
 *
Packit 6b81fa
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
Packit 6b81fa
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit 6b81fa
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit 6b81fa
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 6b81fa
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit 6b81fa
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 6b81fa
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 6b81fa
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 6b81fa
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit 6b81fa
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 6b81fa
 */
Packit 6b81fa
Packit 6b81fa
#include "engine.h"
Packit 6b81fa
#include <stdio.h>
Packit 6b81fa
#include <string.h>
Packit 6b81fa
Packit 6b81fa
static int hex_to_bin(ENGINE_CTX *ctx,
Packit 6b81fa
		const char *in, unsigned char *out, size_t *outlen)
Packit 6b81fa
{
Packit 6b81fa
	size_t left, count = 0;
Packit 6b81fa
Packit 6b81fa
	if (in == NULL || *in == '\0') {
Packit 6b81fa
		*outlen = 0;
Packit 6b81fa
		return 1;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	left = *outlen;
Packit 6b81fa
Packit 6b81fa
	while (*in != '\0') {
Packit 6b81fa
		int byte = 0, nybbles = 2;
Packit 6b81fa
Packit 6b81fa
		while (nybbles-- && *in && *in != ':') {
Packit 6b81fa
			char c;
Packit 6b81fa
			byte <<= 4;
Packit 6b81fa
			c = *in++;
Packit 6b81fa
			if ('0' <= c && c <= '9')
Packit 6b81fa
				c -= '0';
Packit 6b81fa
			else if ('a' <= c && c <= 'f')
Packit 6b81fa
				c = c - 'a' + 10;
Packit 6b81fa
			else if ('A' <= c && c <= 'F')
Packit 6b81fa
				c = c - 'A' + 10;
Packit 6b81fa
			else {
Packit 6b81fa
				ctx_log(ctx, 0,
Packit 6b81fa
					"hex_to_bin(): invalid char '%c' in hex string\n",
Packit 6b81fa
					c);
Packit 6b81fa
				*outlen = 0;
Packit 6b81fa
				return 0;
Packit 6b81fa
			}
Packit 6b81fa
			byte |= c;
Packit 6b81fa
		}
Packit 6b81fa
		if (*in == ':')
Packit 6b81fa
			in++;
Packit 6b81fa
		if (left == 0) {
Packit 6b81fa
			ctx_log(ctx, 0, "hex_to_bin(): hex string too long\n");
Packit 6b81fa
			*outlen = 0;
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		out[count++] = (unsigned char)byte;
Packit 6b81fa
		left--;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	*outlen = count;
Packit 6b81fa
	return 1;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/* parse string containing slot and id information */
Packit 6b81fa
int parse_slot_id_string(ENGINE_CTX *ctx,
Packit 6b81fa
		const char *slot_id, int *slot,
Packit 6b81fa
		unsigned char *id, size_t *id_len, char **label)
Packit 6b81fa
{
Packit 6b81fa
	int n, i;
Packit 6b81fa
Packit 6b81fa
	/* support for several formats */
Packit 6b81fa
#define HEXDIGITS "01234567890ABCDEFabcdef"
Packit 6b81fa
#define DIGITS "0123456789"
Packit 6b81fa
Packit 6b81fa
	/* first: pure hex number (id, slot is undefined) */
Packit 6b81fa
	if (strspn(slot_id, HEXDIGITS) == strlen(slot_id)) {
Packit 6b81fa
		/* ah, easiest case: only hex. */
Packit 6b81fa
		if ((strlen(slot_id) + 1) / 2 > *id_len) {
Packit 6b81fa
			ctx_log(ctx, 0, "ID string too long!\n");
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		*slot = -1;
Packit 6b81fa
		return hex_to_bin(ctx, slot_id, id, id_len);
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* second: slot:id. slot is an digital int. */
Packit 6b81fa
	if (sscanf(slot_id, "%d", &n) == 1) {
Packit 6b81fa
		i = strspn(slot_id, DIGITS);
Packit 6b81fa
Packit 6b81fa
		if (slot_id[i] != ':') {
Packit 6b81fa
			ctx_log(ctx, 0, "Could not parse string!\n");
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		i++;
Packit 6b81fa
		if (slot_id[i] == 0) {
Packit 6b81fa
			*slot = n;
Packit 6b81fa
			*id_len = 0;
Packit 6b81fa
			return 1;
Packit 6b81fa
		}
Packit 6b81fa
		if (strspn(slot_id + i, HEXDIGITS) + i != strlen(slot_id)) {
Packit 6b81fa
			ctx_log(ctx, 0, "Could not parse string!\n");
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		/* ah, rest is hex */
Packit 6b81fa
		if ((strlen(slot_id) - i + 1) / 2 > *id_len) {
Packit 6b81fa
			ctx_log(ctx, 0, "ID string too long!\n");
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		*slot = n;
Packit 6b81fa
		return hex_to_bin(ctx, slot_id + i, id, id_len);
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* third: id_<id>, slot is undefined */
Packit 6b81fa
	if (strncmp(slot_id, "id_", 3) == 0) {
Packit 6b81fa
		if (strspn(slot_id + 3, HEXDIGITS) + 3 != strlen(slot_id)) {
Packit 6b81fa
			ctx_log(ctx, 0, "Could not parse string!\n");
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		/* ah, rest is hex */
Packit 6b81fa
		if ((strlen(slot_id) - 3 + 1) / 2 > *id_len) {
Packit 6b81fa
			ctx_log(ctx, 0, "ID string too long!\n");
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		*slot = -1;
Packit 6b81fa
		return hex_to_bin(ctx, slot_id + 3, id, id_len);
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* label_<label>, slot is undefined */
Packit 6b81fa
	if (strncmp(slot_id, "label_", 6) == 0) {
Packit 6b81fa
		*slot = -1;
Packit 6b81fa
		*label = OPENSSL_strdup(slot_id + 6);
Packit 6b81fa
		*id_len = 0;
Packit 6b81fa
		return *label != NULL;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* last try: it has to be slot_<slot> and then "-id_<cert>" */
Packit 6b81fa
Packit 6b81fa
	if (strncmp(slot_id, "slot_", 5) != 0) {
Packit 6b81fa
		ctx_log(ctx, 0, "Format not recognized!\n");
Packit 6b81fa
		return 0;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* slot is an digital int. */
Packit 6b81fa
	if (sscanf(slot_id + 5, "%d", &n) != 1) {
Packit 6b81fa
		ctx_log(ctx, 0, "Could not decode slot number!\n");
Packit 6b81fa
		return 0;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	i = strspn(slot_id + 5, DIGITS);
Packit 6b81fa
Packit 6b81fa
	if (slot_id[i + 5] == 0) {
Packit 6b81fa
		*slot = n;
Packit 6b81fa
		*id_len = 0;
Packit 6b81fa
		return 1;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	if (slot_id[i + 5] != '-') {
Packit 6b81fa
		ctx_log(ctx, 0, "Could not parse string!\n");
Packit 6b81fa
		return 0;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	i = 5 + i + 1;
Packit 6b81fa
Packit 6b81fa
	/* now followed by "id_" */
Packit 6b81fa
	if (strncmp(slot_id + i, "id_", 3) == 0) {
Packit 6b81fa
		if (strspn(slot_id + i + 3, HEXDIGITS) + 3 + i != strlen(slot_id)) {
Packit 6b81fa
			ctx_log(ctx, 0, "Could not parse string!\n");
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		/* ah, rest is hex */
Packit 6b81fa
		if ((strlen(slot_id) - i - 3 + 1) / 2 > *id_len) {
Packit 6b81fa
			ctx_log(ctx, 0, "ID string too long!\n");
Packit 6b81fa
			return 0;
Packit 6b81fa
		}
Packit 6b81fa
		*slot = n;
Packit 6b81fa
		return hex_to_bin(ctx, slot_id + i + 3, id, id_len);
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* ... or "label_" */
Packit 6b81fa
	if (strncmp(slot_id + i, "label_", 6) == 0) {
Packit 6b81fa
		*slot = n;
Packit 6b81fa
		*label = OPENSSL_strdup(slot_id + i + 6);
Packit 6b81fa
		*id_len = 0;
Packit 6b81fa
		return *label != NULL;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	ctx_log(ctx, 0, "Could not parse string!\n");
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
static int parse_uri_attr(ENGINE_CTX *ctx,
Packit 6b81fa
		const char *attr, int attrlen, unsigned char **field,
Packit 6b81fa
		size_t *field_len)
Packit 6b81fa
{
Packit 6b81fa
	size_t max, outlen = 0;
Packit 6b81fa
	unsigned char *out;
Packit 6b81fa
	int ret = 1;
Packit 6b81fa
Packit 6b81fa
	if (field_len) {
Packit 6b81fa
		out = *field;
Packit 6b81fa
		max = *field_len;
Packit 6b81fa
	} else {
Packit 6b81fa
		out = OPENSSL_malloc(attrlen + 1);
Packit 6b81fa
		if (out == NULL)
Packit 6b81fa
			return 0;
Packit 6b81fa
		max = attrlen + 1;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	while (ret && attrlen && outlen < max) {
Packit 6b81fa
		if (*attr == '%') {
Packit 6b81fa
			if (attrlen < 3) {
Packit 6b81fa
				ret = 0;
Packit 6b81fa
			} else {
Packit 6b81fa
				char tmp[3];
Packit 6b81fa
				size_t l = 1;
Packit 6b81fa
Packit 6b81fa
				tmp[0] = attr[1];
Packit 6b81fa
				tmp[1] = attr[2];
Packit 6b81fa
				tmp[2] = 0;
Packit 6b81fa
				ret = hex_to_bin(ctx, tmp, &out[outlen++], &l);
Packit 6b81fa
				attrlen -= 3;
Packit 6b81fa
				attr += 3;
Packit 6b81fa
			}
Packit 6b81fa
Packit 6b81fa
		} else {
Packit 6b81fa
			out[outlen++] = *(attr++);
Packit 6b81fa
			attrlen--;
Packit 6b81fa
		}
Packit 6b81fa
	}
Packit 6b81fa
	if (attrlen && outlen == max)
Packit 6b81fa
		ret = 0;
Packit 6b81fa
Packit 6b81fa
	if (ret) {
Packit 6b81fa
		if (field_len) {
Packit 6b81fa
			*field_len = outlen;
Packit 6b81fa
		} else {
Packit 6b81fa
			out[outlen] = 0;
Packit 6b81fa
			*field = out;
Packit 6b81fa
		}
Packit 6b81fa
	} else {
Packit 6b81fa
		if (field_len == NULL)
Packit 6b81fa
			OPENSSL_free(out);
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	return ret;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
int parse_pkcs11_uri(ENGINE_CTX *ctx,
Packit 6b81fa
		const char *uri, PKCS11_TOKEN **p_tok,
Packit 6b81fa
		unsigned char *id, size_t *id_len, char *pin, size_t *pin_len,
Packit 6b81fa
		char **label)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_TOKEN *tok;
Packit 6b81fa
	char *newlabel = NULL;
Packit 6b81fa
	const char *end, *p;
Packit 6b81fa
	int rv = 1, id_set = 0, pin_set = 0;
Packit 6b81fa
Packit 6b81fa
	tok = OPENSSL_malloc(sizeof(PKCS11_TOKEN));
Packit 6b81fa
	if (tok == NULL) {
Packit 6b81fa
		ctx_log(ctx, 0, "Could not allocate memory for token info\n");
Packit 6b81fa
		return 0;
Packit 6b81fa
	}
Packit 6b81fa
	memset(tok, 0, sizeof(PKCS11_TOKEN));
Packit 6b81fa
Packit 6b81fa
	/* We are only ever invoked if the string starts with 'pkcs11:' */
Packit 6b81fa
	end = uri + 6;
Packit 6b81fa
	while (rv && end[0] && end[1]) {
Packit 6b81fa
		p = end + 1;
Packit 6b81fa
		end = strpbrk(p, ";?&";;
Packit 6b81fa
		if (end == NULL)
Packit 6b81fa
			end = p + strlen(p);
Packit 6b81fa
Packit 6b81fa
		if (!strncmp(p, "model=", 6)) {
Packit 6b81fa
			p += 6;
Packit 6b81fa
			rv = parse_uri_attr(ctx, p, end - p, (void *)&tok->model, NULL);
Packit 6b81fa
		} else if (!strncmp(p, "manufacturer=", 13)) {
Packit 6b81fa
			p += 13;
Packit 6b81fa
			rv = parse_uri_attr(ctx, p, end - p, (void *)&tok->manufacturer, NULL);
Packit 6b81fa
		} else if (!strncmp(p, "token=", 6)) {
Packit 6b81fa
			p += 6;
Packit 6b81fa
			rv = parse_uri_attr(ctx, p, end - p, (void *)&tok->label, NULL);
Packit 6b81fa
		} else if (!strncmp(p, "serial=", 7)) {
Packit 6b81fa
			p += 7;
Packit 6b81fa
			rv = parse_uri_attr(ctx, p, end - p, (void *)&tok->serialnr, NULL);
Packit 6b81fa
		} else if (!strncmp(p, "object=", 7)) {
Packit 6b81fa
			p += 7;
Packit 6b81fa
			rv = parse_uri_attr(ctx, p, end - p, (void *)&newlabel, NULL);
Packit 6b81fa
		} else if (!strncmp(p, "id=", 3)) {
Packit 6b81fa
			p += 3;
Packit 6b81fa
			rv = parse_uri_attr(ctx, p, end - p, (void *)&id, id_len);
Packit 6b81fa
			id_set = 1;
Packit 6b81fa
		} else if (!strncmp(p, "pin-value=", 10)) {
Packit 6b81fa
			p += 10;
Packit 6b81fa
			rv = parse_uri_attr(ctx, p, end - p, (void *)&pin, pin_len);
Packit 6b81fa
			pin_set = 1;
Packit 6b81fa
		} else if (!strncmp(p, "type=", 5) || !strncmp(p, "object-type=", 12)) {
Packit 6b81fa
			p = strchr(p, '=') + 1;
Packit 6b81fa
Packit 6b81fa
			if ((end - p == 4 && !strncmp(p, "cert", 4)) ||
Packit 6b81fa
					(end - p == 6 && !strncmp(p, "public", 6)) ||
Packit 6b81fa
					(end - p == 7 && !strncmp(p, "private", 7))) {
Packit 6b81fa
				/* Actually, just ignore it */
Packit 6b81fa
			} else {
Packit 6b81fa
				ctx_log(ctx, 0, "Unknown object type\n");
Packit 6b81fa
				rv = 0;
Packit 6b81fa
			}
Packit 6b81fa
		} else {
Packit 6b81fa
			rv = 0;
Packit 6b81fa
		}
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	if (!id_set)
Packit 6b81fa
		*id_len = 0;
Packit 6b81fa
	if (!pin_set)
Packit 6b81fa
		*pin_len = 0;
Packit 6b81fa
Packit 6b81fa
	if (rv) {
Packit 6b81fa
		*label = newlabel;
Packit 6b81fa
		*p_tok = tok;
Packit 6b81fa
	} else {
Packit 6b81fa
		OPENSSL_free(tok);
Packit 6b81fa
		tok = NULL;
Packit 6b81fa
		OPENSSL_free(newlabel);
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	return rv;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/* vim: set noexpandtab: */