diff --git a/src/libp11-int.h b/src/libp11-int.h index aee4cbb4..a49088ba 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -77,6 +77,7 @@ struct pkcs11_ctx_private { void *handle; char *init_args; CK_VERSION cryptoki_version; + CK_VERSION library_version; UI_METHOD *ui_method; /* UI_METHOD for CKU_CONTEXT_SPECIFIC PINs */ void *ui_user_data; pthread_mutex_t fork_lock; diff --git a/src/p11_load.c b/src/p11_load.c index 512abfce..25f3a5bf 100644 --- a/src/p11_load.c +++ b/src/p11_load.c @@ -195,6 +195,8 @@ int pkcs11_CTX_load(PKCS11_CTX *ctx, const char *name) ctx->description = PKCS11_DUP(ck_info.libraryDescription); cpriv->cryptoki_version.major = ck_info.cryptokiVersion.major; cpriv->cryptoki_version.minor = ck_info.cryptokiVersion.minor; + cpriv->library_version.major = ck_info.libraryVersion.major; + cpriv->library_version.minor = ck_info.libraryVersion.minor; #if OPENSSL_VERSION_NUMBER >= 0x30000000L register_falcon_oids(); #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ diff --git a/src/util.h b/src/util.h index d14fd2cf..5556f6d4 100644 --- a/src/util.h +++ b/src/util.h @@ -50,6 +50,29 @@ #define strcasecmp _stricmp #endif +typedef struct { + int slot_nr; + char *obj_id; + size_t obj_id_len; + char *obj_label; + PKCS11_SLOT **matched_slots; + size_t matched_count; + PKCS11_TOKEN *match_tok; + char *pin; + size_t pin_len; + char *pin_value; + char *pin_source; + char *type; + char *slot_description; + char *slot_manufacturer; + int slot_id; + char *library_description; + char *library_manufacturer; + char *library_version; + char *module_name; + char *module_path; +} PARSED; + /* defined in util_uri.c */ typedef struct util_ctx_st UTIL_CTX; /* opaque */ @@ -74,6 +97,11 @@ void UTIL_CTX_log(UTIL_CTX *ctx, int level, const char *format, ...) int UTIL_CTX_set_pin(UTIL_CTX *ctx, const char *pin); void UTIL_CTX_set_force_login(UTIL_CTX *ctx, int force_login); +char *dump_hex(unsigned char *val, const size_t len); +int util_ctx_parse_uri(UTIL_CTX *ctx, PARSED *parsed, + const char *object_typestr, const char *object_uri); +void util_parsed_free(PARSED *parsed); + X509 *UTIL_CTX_get_cert_from_uri(UTIL_CTX *ctx, const char *uri, UI_METHOD *ui_method, void *ui_data); EVP_PKEY *UTIL_CTX_get_pubkey_from_uri(UTIL_CTX *ctx, const char *uri, diff --git a/src/util_uri.c b/src/util_uri.c index 311a2006..3aa21d06 100644 --- a/src/util_uri.c +++ b/src/util_uri.c @@ -27,8 +27,11 @@ */ #include "util.h" -#include "p11_pthread.h" +#include "libp11-int.h" #include +#include +#include +#include #include #include @@ -288,7 +291,7 @@ void UTIL_CTX_log(UTIL_CTX *ctx, int level, const char *format, ...) va_end(args); } -static char *dump_hex(unsigned char *val, const size_t len) +char *dump_hex(unsigned char *val, const size_t len) { int j = 0; size_t i, size = 2 * len + 1; @@ -681,7 +684,7 @@ static int parse_slot_id_string(UTIL_CTX *ctx, } static int parse_uri_attr_len(UTIL_CTX *ctx, - const char *attr, int attrlen, char *field, + const char *attr, size_t attrlen, char *field, size_t *field_len) { size_t max = *field_len, outlen = 0; @@ -728,6 +731,11 @@ static int parse_uri_attr(UTIL_CTX *ctx, size_t outlen = attrlen; char *out; + if (*field != NULL) { + /* Duplicate attributes not allowed */ + return 0; + } + out = OPENSSL_malloc(outlen + 1); /* reserve 1 byte for NUL terminator */ if (out == NULL) return 0; @@ -781,7 +789,7 @@ static int parse_pin_source(UTIL_CTX *ctx, const char *attr, size_t attrlen, char *field, size_t *field_len) { - char *val; + char *val = NULL; int ret = 1; if (!parse_uri_attr(ctx, attr, attrlen, &val)) { @@ -803,14 +811,15 @@ static int parse_pin_source(UTIL_CTX *ctx, } static int parse_pkcs11_uri(UTIL_CTX *ctx, - const char *uri, PKCS11_TOKEN **p_tok, - char *id, size_t *id_len, char *pin, size_t *pin_len, - char **label) + const char *uri, PARSED *parsed, + char *pin, size_t *pin_len) { PKCS11_TOKEN *tok; - char *newlabel = NULL; const char *end, *p; int rv = 1, id_set = 0, pin_set = 0; + char tmp_id[MAX_PIN_LENGTH]; + size_t tmp_id_len = sizeof(tmp_id); + char *tmp_str = NULL; tok = OPENSSL_malloc(sizeof(PKCS11_TOKEN)); if (!tok) { @@ -818,6 +827,7 @@ static int parse_pkcs11_uri(UTIL_CTX *ctx, return 0; } memset(tok, 0, sizeof(PKCS11_TOKEN)); + parsed->match_tok = tok; /* We are only ever invoked if the string starts with 'pkcs11:' */ end = uri + 6; @@ -839,28 +849,95 @@ static int parse_pkcs11_uri(UTIL_CTX *ctx, } else if (!strncmp(p, "serial=", 7)) { p += 7; rv = parse_uri_attr(ctx, p, (size_t)(end - p), &tok->serialnr); + } else if (!strncmp(p, "slot-description=", 17)) { + p += 17; + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->slot_description); + } else if (!strncmp(p, "slot-manufacturer=", 18)) { + p += 18; + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->slot_manufacturer); + } else if (!strncmp(p, "slot-id=", 8)) { + p += 8; + if (parsed->slot_id != -1) { + /* Duplicate attributes not allowed */ + rv = 0; + } else { + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &tmp_str); + if (rv) { + char *endptr = NULL; + long val; + + errno = 0; + val = strtol(tmp_str, &endptr, 10); + if (!isdigit((unsigned char)*tmp_str) || *endptr != '\0' || + errno != 0 || val < 0 || val > INT_MAX) { + UTIL_CTX_log(ctx, LOG_ERR, "Invalid slot-id in PKCS#11 URI: %s\n", tmp_str); + rv = 0; + } else { + parsed->slot_id = (int)val; + } + } + OPENSSL_free(tmp_str); + tmp_str = NULL; + } + } else if (!strncmp(p, "library-description=", 20)) { + p += 20; + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->library_description); + } else if (!strncmp(p, "library-manufacturer=", 21)) { + p += 21; + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->library_manufacturer); + } else if (!strncmp(p, "library-version=", 16)) { + p += 16; + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->library_version); } else if (!strncmp(p, "object=", 7)) { p += 7; - rv = parse_uri_attr(ctx, p, (size_t)(end - p), &newlabel); + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->obj_label); } else if (!strncmp(p, "id=", 3)) { p += 3; - rv = parse_uri_attr_len(ctx, p, (size_t)(end - p), id, id_len); + if (parsed->obj_id) { + /* Duplicate attributes not allowed */ + rv = 0; + } else { + tmp_id_len = sizeof(tmp_id); + rv = parse_uri_attr_len(ctx, p, (size_t)(end - p), tmp_id, &tmp_id_len); + } + if (rv && tmp_id_len > 0) { + parsed->obj_id = OPENSSL_malloc(tmp_id_len); + if (parsed->obj_id) { + memcpy(parsed->obj_id, tmp_id, tmp_id_len); + parsed->obj_id_len = tmp_id_len; + } else { + rv = 0; + } + } id_set = 1; } else if (!strncmp(p, "pin-value=", 10)) { p += 10; rv = pin_set ? 0 : parse_uri_attr_len(ctx, p, (size_t)(end - p), pin, pin_len); + if (rv) { + parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->pin_value); + } pin_set = 1; } else if (!strncmp(p, "pin-source=", 11)) { p += 11; rv = pin_set ? 0 : parse_pin_source(ctx, p, (size_t)(end - p), pin, pin_len); + if (rv) { + parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->pin_source); + } pin_set = 1; + } else if (!strncmp(p, "module-name=", 12)) { + p += 12; + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->module_name); + } else if (!strncmp(p, "module-path=", 12)) { + p += 12; + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->module_path); } else if (!strncmp(p, "type=", 5) || !strncmp(p, "object-type=", 12)) { p = strchr(p, '=') + 1; - if ((end - p == 4 && !strncmp(p, "cert", 4)) || - (end - p == 6 && !strncmp(p, "public", 6)) || - (end - p == 7 && !strncmp(p, "private", 7))) { - /* Actually, just ignore it */ + rv = parse_uri_attr(ctx, p, (size_t)(end - p), &parsed->type); + if (rv && parsed->type && (!strcmp(parsed->type, "cert") || + !strcmp(parsed->type, "public") || + !strcmp(parsed->type, "private"))) { + /* valid object type */ } else { UTIL_CTX_log(ctx, LOG_ERR, "Unknown object type\n"); rv = 0; @@ -870,41 +947,53 @@ static int parse_pkcs11_uri(UTIL_CTX *ctx, } } - if (!id_set) - *id_len = 0; + if (!id_set && !parsed->obj_id) + parsed->obj_id_len = 0; if (!pin_set) *pin_len = 0; - if (rv) { - *label = newlabel; - *p_tok = tok; - } else { - OPENSSL_free(tok->model); - OPENSSL_free(tok->manufacturer); - OPENSSL_free(tok->serialnr); - OPENSSL_free(tok->label); - OPENSSL_free(tok); - tok = NULL; - OPENSSL_free(newlabel); - } - return rv; } +void util_parsed_free(PARSED *parsed) +{ + if (!parsed) + return; + OPENSSL_free(parsed->obj_id); + OPENSSL_free(parsed->obj_label); + if (parsed->pin_len) { + OPENSSL_cleanse(parsed->pin, parsed->pin_len); + OPENSSL_free(parsed->pin); + } + if (parsed->pin_value) { + OPENSSL_cleanse(parsed->pin_value, strlen(parsed->pin_value)); + OPENSSL_free(parsed->pin_value); + } + OPENSSL_free(parsed->pin_source); + OPENSSL_free(parsed->type); + OPENSSL_free(parsed->slot_description); + OPENSSL_free(parsed->slot_manufacturer); + OPENSSL_free(parsed->library_description); + OPENSSL_free(parsed->library_manufacturer); + OPENSSL_free(parsed->library_version); + OPENSSL_free(parsed->module_name); + OPENSSL_free(parsed->module_path); + OPENSSL_free(parsed->matched_slots); + if (parsed->match_tok) { + OPENSSL_free(parsed->match_tok->model); + OPENSSL_free(parsed->match_tok->manufacturer); + OPENSSL_free(parsed->match_tok->serialnr); + OPENSSL_free(parsed->match_tok->label); + OPENSSL_free(parsed->match_tok); + } + memset(parsed, 0, sizeof(PARSED)); +} + /******************************************************************************/ /* Utilities common to public, private key and certificate handling */ /******************************************************************************/ -typedef struct { - int slot_nr; - char *obj_id; - size_t obj_id_len; - char *obj_label; - PKCS11_SLOT **matched_slots; - size_t matched_count; -} PARSED; - -static int util_ctx_parse_uri(UTIL_CTX *ctx, PARSED *parsed, +int util_ctx_parse_uri(UTIL_CTX *ctx, PARSED *parsed, const char *object_typestr, const char *object_uri) { PKCS11_SLOT *slot; @@ -915,19 +1004,13 @@ static int util_ctx_parse_uri(UTIL_CTX *ctx, PARSED *parsed, int rv = 0; parsed->slot_nr = -1; + parsed->slot_id = -1; if (object_uri && *object_uri) { - parsed->obj_id_len = strlen(object_uri) + 1; - parsed->obj_id = OPENSSL_malloc(parsed->obj_id_len); - if (!parsed->obj_id) { - UTIL_CTX_log(ctx, LOG_ERR, "Could not allocate memory for ID\n"); - goto cleanup; - } if (!strncasecmp(object_uri, "pkcs11:", 7)) { char tmp_pin[MAX_PIN_LENGTH+1]; size_t tmp_pin_len = MAX_PIN_LENGTH; - n = parse_pkcs11_uri(ctx, object_uri, &match_tok, - parsed->obj_id, &parsed->obj_id_len, tmp_pin, &tmp_pin_len, &parsed->obj_label); + n = parse_pkcs11_uri(ctx, object_uri, parsed, tmp_pin, &tmp_pin_len); if (!n) { OPENSSL_cleanse(tmp_pin, sizeof(tmp_pin)); UTIL_CTX_log(ctx, LOG_ERR, @@ -936,15 +1019,50 @@ static int util_ctx_parse_uri(UTIL_CTX *ctx, PARSED *parsed, object_typestr); goto cleanup; } + match_tok = parsed->match_tok; if (tmp_pin_len > 0 && tmp_pin[0] != 0) { tmp_pin[tmp_pin_len] = 0; + parsed->pin = OPENSSL_strdup(tmp_pin); + parsed->pin_len = tmp_pin_len; if (!UTIL_CTX_set_pin(ctx, tmp_pin)) { OPENSSL_cleanse(tmp_pin, sizeof(tmp_pin)); goto cleanup; } } OPENSSL_cleanse(tmp_pin, sizeof(tmp_pin)); + if (parsed->type) { + if (!strcmp(parsed->type, "cert")) { + if (strcmp(object_typestr, "certificate") != 0 && + strcmp(object_typestr, "public key") != 0) { + UTIL_CTX_log(ctx, LOG_NOTICE, + "Requested object type '%s' does not match URI type '%s'\n", + object_typestr, parsed->type); + goto cleanup; + } + } else if (!strcmp(parsed->type, "public")) { + if (strcmp(object_typestr, "public key") != 0) { + UTIL_CTX_log(ctx, LOG_NOTICE, + "Requested object type '%s' does not match URI type '%s'\n", + object_typestr, parsed->type); + goto cleanup; + } + } else if (!strcmp(parsed->type, "private")) { + if (strcmp(object_typestr, "private key") != 0 && + strcmp(object_typestr, "key") != 0) { + UTIL_CTX_log(ctx, LOG_NOTICE, + "Requested object type '%s' does not match URI type '%s'\n", + object_typestr, parsed->type); + goto cleanup; + } + } + } } else { + parsed->obj_id_len = strlen(object_uri) + 1; + parsed->obj_id = OPENSSL_malloc(parsed->obj_id_len); + if (!parsed->obj_id) { + UTIL_CTX_log(ctx, LOG_ERR, "Could not allocate memory for ID\n"); + goto cleanup; + } n = parse_slot_id_string(ctx, object_uri, &parsed->slot_nr, parsed->obj_id, &parsed->obj_id_len, &parsed->obj_label); if (!n) { @@ -959,6 +1077,11 @@ static int util_ctx_parse_uri(UTIL_CTX *ctx, PARSED *parsed, } } + if (!ctx || !ctx->slot_list || ctx->slot_count == 0) { + /* Slot list not initialized / no slots; parsing succeeded */ + return 1; + } + parsed->matched_slots = (PKCS11_SLOT **)OPENSSL_malloc(ctx->slot_count * sizeof(PKCS11_SLOT *)); if (!parsed->matched_slots) { UTIL_CTX_log(ctx, LOG_ERR, "Could not allocate memory for slots\n"); @@ -984,21 +1107,82 @@ static int util_ctx_parse_uri(UTIL_CTX *ctx, PARSED *parsed, flags[m - 2] = '\0'; } - if (parsed->slot_nr != -1 && - parsed->slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) { - found_slot = slot; - } + if (match_tok || parsed->slot_nr != -1) { + int match = 1; - if (match_tok && slot->token && - (!match_tok->label || - !strcmp(match_tok->label, slot->token->label)) && - (!match_tok->manufacturer || - !strcmp(match_tok->manufacturer, slot->token->manufacturer)) && - (!match_tok->serialnr || - !strcmp(match_tok->serialnr, slot->token->serialnr)) && - (!match_tok->model || - !strcmp(match_tok->model, slot->token->model))) { - found_slot = slot; + if (parsed->slot_nr != -1 && + parsed->slot_nr != (int)PKCS11_get_slotid_from_slot(slot)) { + match = 0; + } + if (match_tok) { + if (parsed->slot_id != -1 && + parsed->slot_id != (int)PKCS11_get_slotid_from_slot(slot)) { + match = 0; + } + if (parsed->slot_description && + (!slot->description || + strcmp(parsed->slot_description, slot->description) != 0)) { + match = 0; + } + if (parsed->slot_manufacturer && + (!slot->manufacturer || + strcmp(parsed->slot_manufacturer, slot->manufacturer) != 0)) { + match = 0; + } + if (parsed->library_description && + (!ctx->pkcs11_ctx || !ctx->pkcs11_ctx->description || + strcmp(parsed->library_description, ctx->pkcs11_ctx->description) != 0)) { + match = 0; + } + if (parsed->library_manufacturer && + (!ctx->pkcs11_ctx || !ctx->pkcs11_ctx->manufacturer || + strcmp(parsed->library_manufacturer, ctx->pkcs11_ctx->manufacturer) != 0)) { + match = 0; + } + if (parsed->library_version) { + if (!ctx->pkcs11_ctx || !ctx->pkcs11_ctx->_private) { + match = 0; + } else { + PKCS11_CTX_private *cpriv = ctx->pkcs11_ctx->_private; + unsigned int maj = 0, min = 0; + int count = sscanf(parsed->library_version, "%u.%u", &maj, &min); + + if (count == 2) { + if ((unsigned int)cpriv->library_version.major != maj || + (unsigned int)cpriv->library_version.minor != min) + match = 0; + } else if (count == 1) { + if ((unsigned int)cpriv->library_version.major != maj) + match = 0; + } else { + match = 0; + } + } + } + if (match_tok->label && + (!slot->token || !slot->token->label || + strcmp(match_tok->label, slot->token->label) != 0)) { + match = 0; + } + if (match_tok->manufacturer && + (!slot->token || !slot->token->manufacturer || + strcmp(match_tok->manufacturer, slot->token->manufacturer) != 0)) { + match = 0; + } + if (match_tok->serialnr && + (!slot->token || !slot->token->serialnr || + strcmp(match_tok->serialnr, slot->token->serialnr) != 0)) { + match = 0; + } + if (match_tok->model && + (!slot->token || !slot->token->model || + strcmp(match_tok->model, slot->token->model) != 0)) { + match = 0; + } + } + if (match) { + found_slot = slot; + } } UTIL_CTX_log(ctx, LOG_NOTICE, "- [%lu] %-25.25s %-36s (%s)\n", PKCS11_get_slotid_from_slot(slot), @@ -1042,17 +1226,10 @@ static int util_ctx_parse_uri(UTIL_CTX *ctx, PARSED *parsed, } rv = 1; /* Success */ + return rv; cleanup: - /* Free the searched token data */ - if (match_tok) { - OPENSSL_free(match_tok->model); - OPENSSL_free(match_tok->manufacturer); - OPENSSL_free(match_tok->serialnr); - OPENSSL_free(match_tok->label); - OPENSSL_free(match_tok); - } - return rv; + return 0; } /* In several tokens, certificates are marked as private */ @@ -1231,9 +1408,7 @@ static void *util_ctx_load_object(UTIL_CTX *ctx, pthread_mutex_unlock(&ctx->lock); - OPENSSL_free(parsed.obj_label); - OPENSSL_free(parsed.matched_slots); - OPENSSL_free(parsed.obj_id); + util_parsed_free(&parsed); if (!obj) { UTIL_CTX_log(ctx, LOG_ERR, "The %s was not found at: %s\n", @@ -1702,9 +1877,7 @@ EVP_PKEY *UTIL_CTX_generate_key(UTIL_CTX *ctx, const char *uri, int algorithm, end: pthread_mutex_unlock(&ctx->lock); - OPENSSL_free(parsed.obj_label); - OPENSSL_free(parsed.matched_slots); - OPENSSL_free(parsed.obj_id); + util_parsed_free(&parsed); return key; } diff --git a/tests/Makefile.am b/tests/Makefile.am index d29065b5..7379a47e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,7 +39,8 @@ check_PROGRAMS = \ mldsa87-keygen-prov \ mlkem768-keygen-prov \ session-pool-test \ - session-pool-stress + session-pool-stress \ + parse-uri dist_check_SCRIPTS = \ rsa-testpkcs11.softhsm \ rsa-testfork.softhsm \ @@ -119,6 +120,7 @@ check_all_prov_SOURCES = check-all-prov.c helpers_prov.c ec_derive_prov_SOURCES = ec-derive-prov.c helpers_prov.c session_pool_test_SOURCES = session-pool-test.c session-pool-under-test.c session_pool_test_LDADD = $(OPENSSL_LIBS) +parse_uri_SOURCES = parse-uri.c ../src/util_uri.c TESTS = $(dist_check_SCRIPTS) diff --git a/tests/parse-uri.c b/tests/parse-uri.c new file mode 100644 index 00000000..c7a36be0 --- /dev/null +++ b/tests/parse-uri.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2026 Jakub Jelen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "util.h" + +static void print_hex(const char *label, char *value, int length) +{ + char *hex = NULL; + if (length == 0) { + printf("%s=\n", label); + return; + } + + hex = dump_hex((unsigned char *)value, length); + if (hex) { + printf("%s=%s\n", label, hex); + OPENSSL_free(hex); + } +} + +static void print_hex_str(const char *label, char *value) +{ + if (value != NULL) { + print_hex(label, value, strlen(value)); + } +} + +int main(int argc, char **argv) +{ + UTIL_CTX *ctx; + PARSED parsed; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + ctx = UTIL_CTX_new(0); + if (!ctx) { + fprintf(stderr, "Failed to create UTIL_CTX\n"); + return 1; + } + + memset(&parsed, 0, sizeof(parsed)); + if (!util_ctx_parse_uri(ctx, &parsed, "object", argv[1])) { + fprintf(stderr, "Failed to parse URI: %s\n", argv[1]); + util_parsed_free(&parsed); + UTIL_CTX_free(ctx); + return 1; + } + + print_hex_str("library-description", parsed.library_description); + print_hex_str("library-manufacturer", parsed.library_manufacturer); + if (parsed.library_version) + printf("library-version=%s\n", parsed.library_version); + if (parsed.match_tok) { + print_hex_str("token", parsed.match_tok->label); + print_hex_str("manufacturer", parsed.match_tok->manufacturer); + print_hex_str("serial", parsed.match_tok->serialnr); + print_hex_str("model", parsed.match_tok->model); + } + print_hex_str("slot-description", parsed.slot_description); + print_hex_str("slot-manufacturer", parsed.slot_manufacturer); + if (parsed.slot_id != -1) + printf("slot-id=%d\n", parsed.slot_id); + print_hex_str("object", parsed.obj_label); + if (parsed.type) + printf("type=%s\n", parsed.type); + if (parsed.obj_id) + print_hex("id", parsed.obj_id, parsed.obj_id_len); + if (parsed.pin_value) + printf("pin-value=%s\n", parsed.pin_value); + else if (parsed.pin) + printf("pin-value=%s\n", parsed.pin); + if (parsed.pin_source) + printf("pin-source=%s\n", parsed.pin_source); + if (parsed.module_name) + printf("module-name=%s\n", parsed.module_name); + if (parsed.module_path) + printf("module-path=%s\n", parsed.module_path); + + util_parsed_free(&parsed); + UTIL_CTX_free(ctx); + return 0; +}