|
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: */
|