1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4e1051a39Sopenharmony_ci * 5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 6e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 9e1051a39Sopenharmony_ci */ 10e1051a39Sopenharmony_ci 11e1051a39Sopenharmony_ci#include <string.h> 12e1051a39Sopenharmony_ci#include <stdio.h> 13e1051a39Sopenharmony_ci#include <stdarg.h> 14e1051a39Sopenharmony_ci#include <openssl/err.h> 15e1051a39Sopenharmony_ci#include "internal/propertyerr.h" 16e1051a39Sopenharmony_ci#include "internal/property.h" 17e1051a39Sopenharmony_ci#include "crypto/ctype.h" 18e1051a39Sopenharmony_ci#include "internal/nelem.h" 19e1051a39Sopenharmony_ci#include "property_local.h" 20e1051a39Sopenharmony_ci#include "e_os.h" 21e1051a39Sopenharmony_ci 22e1051a39Sopenharmony_ciDEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION) 23e1051a39Sopenharmony_ci 24e1051a39Sopenharmony_cistatic const char *skip_space(const char *s) 25e1051a39Sopenharmony_ci{ 26e1051a39Sopenharmony_ci while (ossl_isspace(*s)) 27e1051a39Sopenharmony_ci s++; 28e1051a39Sopenharmony_ci return s; 29e1051a39Sopenharmony_ci} 30e1051a39Sopenharmony_ci 31e1051a39Sopenharmony_cistatic int match_ch(const char *t[], char m) 32e1051a39Sopenharmony_ci{ 33e1051a39Sopenharmony_ci const char *s = *t; 34e1051a39Sopenharmony_ci 35e1051a39Sopenharmony_ci if (*s == m) { 36e1051a39Sopenharmony_ci *t = skip_space(s + 1); 37e1051a39Sopenharmony_ci return 1; 38e1051a39Sopenharmony_ci } 39e1051a39Sopenharmony_ci return 0; 40e1051a39Sopenharmony_ci} 41e1051a39Sopenharmony_ci 42e1051a39Sopenharmony_ci#define MATCH(s, m) match(s, m, sizeof(m) - 1) 43e1051a39Sopenharmony_ci 44e1051a39Sopenharmony_cistatic int match(const char *t[], const char m[], size_t m_len) 45e1051a39Sopenharmony_ci{ 46e1051a39Sopenharmony_ci const char *s = *t; 47e1051a39Sopenharmony_ci 48e1051a39Sopenharmony_ci if (OPENSSL_strncasecmp(s, m, m_len) == 0) { 49e1051a39Sopenharmony_ci *t = skip_space(s + m_len); 50e1051a39Sopenharmony_ci return 1; 51e1051a39Sopenharmony_ci } 52e1051a39Sopenharmony_ci return 0; 53e1051a39Sopenharmony_ci} 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_cistatic int parse_name(OSSL_LIB_CTX *ctx, const char *t[], int create, 56e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX *idx) 57e1051a39Sopenharmony_ci{ 58e1051a39Sopenharmony_ci char name[100]; 59e1051a39Sopenharmony_ci int err = 0; 60e1051a39Sopenharmony_ci size_t i = 0; 61e1051a39Sopenharmony_ci const char *s = *t; 62e1051a39Sopenharmony_ci int user_name = 0; 63e1051a39Sopenharmony_ci 64e1051a39Sopenharmony_ci for (;;) { 65e1051a39Sopenharmony_ci if (!ossl_isalpha(*s)) { 66e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER, 67e1051a39Sopenharmony_ci "HERE-->%s", *t); 68e1051a39Sopenharmony_ci return 0; 69e1051a39Sopenharmony_ci } 70e1051a39Sopenharmony_ci do { 71e1051a39Sopenharmony_ci if (i < sizeof(name) - 1) 72e1051a39Sopenharmony_ci name[i++] = ossl_tolower(*s); 73e1051a39Sopenharmony_ci else 74e1051a39Sopenharmony_ci err = 1; 75e1051a39Sopenharmony_ci } while (*++s == '_' || ossl_isalnum(*s)); 76e1051a39Sopenharmony_ci if (*s != '.') 77e1051a39Sopenharmony_ci break; 78e1051a39Sopenharmony_ci user_name = 1; 79e1051a39Sopenharmony_ci if (i < sizeof(name) - 1) 80e1051a39Sopenharmony_ci name[i++] = *s; 81e1051a39Sopenharmony_ci else 82e1051a39Sopenharmony_ci err = 1; 83e1051a39Sopenharmony_ci s++; 84e1051a39Sopenharmony_ci } 85e1051a39Sopenharmony_ci name[i] = '\0'; 86e1051a39Sopenharmony_ci if (err) { 87e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t); 88e1051a39Sopenharmony_ci return 0; 89e1051a39Sopenharmony_ci } 90e1051a39Sopenharmony_ci *t = skip_space(s); 91e1051a39Sopenharmony_ci *idx = ossl_property_name(ctx, name, user_name && create); 92e1051a39Sopenharmony_ci return 1; 93e1051a39Sopenharmony_ci} 94e1051a39Sopenharmony_ci 95e1051a39Sopenharmony_cistatic int parse_number(const char *t[], OSSL_PROPERTY_DEFINITION *res) 96e1051a39Sopenharmony_ci{ 97e1051a39Sopenharmony_ci const char *s = *t; 98e1051a39Sopenharmony_ci int64_t v = 0; 99e1051a39Sopenharmony_ci 100e1051a39Sopenharmony_ci if (!ossl_isdigit(*s)) 101e1051a39Sopenharmony_ci return 0; 102e1051a39Sopenharmony_ci do { 103e1051a39Sopenharmony_ci v = v * 10 + (*s++ - '0'); 104e1051a39Sopenharmony_ci } while (ossl_isdigit(*s)); 105e1051a39Sopenharmony_ci if (!ossl_isspace(*s) && *s != '\0' && *s != ',') { 106e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT, 107e1051a39Sopenharmony_ci "HERE-->%s", *t); 108e1051a39Sopenharmony_ci return 0; 109e1051a39Sopenharmony_ci } 110e1051a39Sopenharmony_ci *t = skip_space(s); 111e1051a39Sopenharmony_ci res->type = OSSL_PROPERTY_TYPE_NUMBER; 112e1051a39Sopenharmony_ci res->v.int_val = v; 113e1051a39Sopenharmony_ci return 1; 114e1051a39Sopenharmony_ci} 115e1051a39Sopenharmony_ci 116e1051a39Sopenharmony_cistatic int parse_hex(const char *t[], OSSL_PROPERTY_DEFINITION *res) 117e1051a39Sopenharmony_ci{ 118e1051a39Sopenharmony_ci const char *s = *t; 119e1051a39Sopenharmony_ci int64_t v = 0; 120e1051a39Sopenharmony_ci 121e1051a39Sopenharmony_ci if (!ossl_isxdigit(*s)) 122e1051a39Sopenharmony_ci return 0; 123e1051a39Sopenharmony_ci do { 124e1051a39Sopenharmony_ci v <<= 4; 125e1051a39Sopenharmony_ci if (ossl_isdigit(*s)) 126e1051a39Sopenharmony_ci v += *s - '0'; 127e1051a39Sopenharmony_ci else 128e1051a39Sopenharmony_ci v += ossl_tolower(*s) - 'a'; 129e1051a39Sopenharmony_ci } while (ossl_isxdigit(*++s)); 130e1051a39Sopenharmony_ci if (!ossl_isspace(*s) && *s != '\0' && *s != ',') { 131e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT, 132e1051a39Sopenharmony_ci "HERE-->%s", *t); 133e1051a39Sopenharmony_ci return 0; 134e1051a39Sopenharmony_ci } 135e1051a39Sopenharmony_ci *t = skip_space(s); 136e1051a39Sopenharmony_ci res->type = OSSL_PROPERTY_TYPE_NUMBER; 137e1051a39Sopenharmony_ci res->v.int_val = v; 138e1051a39Sopenharmony_ci return 1; 139e1051a39Sopenharmony_ci} 140e1051a39Sopenharmony_ci 141e1051a39Sopenharmony_cistatic int parse_oct(const char *t[], OSSL_PROPERTY_DEFINITION *res) 142e1051a39Sopenharmony_ci{ 143e1051a39Sopenharmony_ci const char *s = *t; 144e1051a39Sopenharmony_ci int64_t v = 0; 145e1051a39Sopenharmony_ci 146e1051a39Sopenharmony_ci if (*s == '9' || *s == '8' || !ossl_isdigit(*s)) 147e1051a39Sopenharmony_ci return 0; 148e1051a39Sopenharmony_ci do { 149e1051a39Sopenharmony_ci v = (v << 3) + (*s - '0'); 150e1051a39Sopenharmony_ci } while (ossl_isdigit(*++s) && *s != '9' && *s != '8'); 151e1051a39Sopenharmony_ci if (!ossl_isspace(*s) && *s != '\0' && *s != ',') { 152e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT, 153e1051a39Sopenharmony_ci "HERE-->%s", *t); 154e1051a39Sopenharmony_ci return 0; 155e1051a39Sopenharmony_ci } 156e1051a39Sopenharmony_ci *t = skip_space(s); 157e1051a39Sopenharmony_ci res->type = OSSL_PROPERTY_TYPE_NUMBER; 158e1051a39Sopenharmony_ci res->v.int_val = v; 159e1051a39Sopenharmony_ci return 1; 160e1051a39Sopenharmony_ci} 161e1051a39Sopenharmony_ci 162e1051a39Sopenharmony_cistatic int parse_string(OSSL_LIB_CTX *ctx, const char *t[], char delim, 163e1051a39Sopenharmony_ci OSSL_PROPERTY_DEFINITION *res, const int create) 164e1051a39Sopenharmony_ci{ 165e1051a39Sopenharmony_ci char v[1000]; 166e1051a39Sopenharmony_ci const char *s = *t; 167e1051a39Sopenharmony_ci size_t i = 0; 168e1051a39Sopenharmony_ci int err = 0; 169e1051a39Sopenharmony_ci 170e1051a39Sopenharmony_ci while (*s != '\0' && *s != delim) { 171e1051a39Sopenharmony_ci if (i < sizeof(v) - 1) 172e1051a39Sopenharmony_ci v[i++] = *s; 173e1051a39Sopenharmony_ci else 174e1051a39Sopenharmony_ci err = 1; 175e1051a39Sopenharmony_ci s++; 176e1051a39Sopenharmony_ci } 177e1051a39Sopenharmony_ci if (*s == '\0') { 178e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER, 179e1051a39Sopenharmony_ci "HERE-->%c%s", delim, *t); 180e1051a39Sopenharmony_ci return 0; 181e1051a39Sopenharmony_ci } 182e1051a39Sopenharmony_ci v[i] = '\0'; 183e1051a39Sopenharmony_ci if (err) { 184e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t); 185e1051a39Sopenharmony_ci } else { 186e1051a39Sopenharmony_ci res->v.str_val = ossl_property_value(ctx, v, create); 187e1051a39Sopenharmony_ci } 188e1051a39Sopenharmony_ci *t = skip_space(s + 1); 189e1051a39Sopenharmony_ci res->type = OSSL_PROPERTY_TYPE_STRING; 190e1051a39Sopenharmony_ci return !err; 191e1051a39Sopenharmony_ci} 192e1051a39Sopenharmony_ci 193e1051a39Sopenharmony_cistatic int parse_unquoted(OSSL_LIB_CTX *ctx, const char *t[], 194e1051a39Sopenharmony_ci OSSL_PROPERTY_DEFINITION *res, const int create) 195e1051a39Sopenharmony_ci{ 196e1051a39Sopenharmony_ci char v[1000]; 197e1051a39Sopenharmony_ci const char *s = *t; 198e1051a39Sopenharmony_ci size_t i = 0; 199e1051a39Sopenharmony_ci int err = 0; 200e1051a39Sopenharmony_ci 201e1051a39Sopenharmony_ci if (*s == '\0' || *s == ',') 202e1051a39Sopenharmony_ci return 0; 203e1051a39Sopenharmony_ci while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') { 204e1051a39Sopenharmony_ci if (i < sizeof(v) - 1) 205e1051a39Sopenharmony_ci v[i++] = ossl_tolower(*s); 206e1051a39Sopenharmony_ci else 207e1051a39Sopenharmony_ci err = 1; 208e1051a39Sopenharmony_ci s++; 209e1051a39Sopenharmony_ci } 210e1051a39Sopenharmony_ci if (!ossl_isspace(*s) && *s != '\0' && *s != ',') { 211e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER, 212e1051a39Sopenharmony_ci "HERE-->%s", s); 213e1051a39Sopenharmony_ci return 0; 214e1051a39Sopenharmony_ci } 215e1051a39Sopenharmony_ci v[i] = 0; 216e1051a39Sopenharmony_ci if (err) 217e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t); 218e1051a39Sopenharmony_ci else if ((res->v.str_val = ossl_property_value(ctx, v, create)) == 0) 219e1051a39Sopenharmony_ci err = 1; 220e1051a39Sopenharmony_ci *t = skip_space(s); 221e1051a39Sopenharmony_ci res->type = OSSL_PROPERTY_TYPE_STRING; 222e1051a39Sopenharmony_ci return !err; 223e1051a39Sopenharmony_ci} 224e1051a39Sopenharmony_ci 225e1051a39Sopenharmony_cistatic int parse_value(OSSL_LIB_CTX *ctx, const char *t[], 226e1051a39Sopenharmony_ci OSSL_PROPERTY_DEFINITION *res, int create) 227e1051a39Sopenharmony_ci{ 228e1051a39Sopenharmony_ci const char *s = *t; 229e1051a39Sopenharmony_ci int r = 0; 230e1051a39Sopenharmony_ci 231e1051a39Sopenharmony_ci if (*s == '"' || *s == '\'') { 232e1051a39Sopenharmony_ci s++; 233e1051a39Sopenharmony_ci r = parse_string(ctx, &s, s[-1], res, create); 234e1051a39Sopenharmony_ci } else if (*s == '+') { 235e1051a39Sopenharmony_ci s++; 236e1051a39Sopenharmony_ci r = parse_number(&s, res); 237e1051a39Sopenharmony_ci } else if (*s == '-') { 238e1051a39Sopenharmony_ci s++; 239e1051a39Sopenharmony_ci r = parse_number(&s, res); 240e1051a39Sopenharmony_ci res->v.int_val = -res->v.int_val; 241e1051a39Sopenharmony_ci } else if (*s == '0' && s[1] == 'x') { 242e1051a39Sopenharmony_ci s += 2; 243e1051a39Sopenharmony_ci r = parse_hex(&s, res); 244e1051a39Sopenharmony_ci } else if (*s == '0' && ossl_isdigit(s[1])) { 245e1051a39Sopenharmony_ci s++; 246e1051a39Sopenharmony_ci r = parse_oct(&s, res); 247e1051a39Sopenharmony_ci } else if (ossl_isdigit(*s)) { 248e1051a39Sopenharmony_ci return parse_number(t, res); 249e1051a39Sopenharmony_ci } else if (ossl_isalpha(*s)) 250e1051a39Sopenharmony_ci return parse_unquoted(ctx, t, res, create); 251e1051a39Sopenharmony_ci if (r) 252e1051a39Sopenharmony_ci *t = s; 253e1051a39Sopenharmony_ci return r; 254e1051a39Sopenharmony_ci} 255e1051a39Sopenharmony_ci 256e1051a39Sopenharmony_cistatic int pd_compare(const OSSL_PROPERTY_DEFINITION *const *p1, 257e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *const *p2) 258e1051a39Sopenharmony_ci{ 259e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *pd1 = *p1; 260e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *pd2 = *p2; 261e1051a39Sopenharmony_ci 262e1051a39Sopenharmony_ci if (pd1->name_idx < pd2->name_idx) 263e1051a39Sopenharmony_ci return -1; 264e1051a39Sopenharmony_ci if (pd1->name_idx > pd2->name_idx) 265e1051a39Sopenharmony_ci return 1; 266e1051a39Sopenharmony_ci return 0; 267e1051a39Sopenharmony_ci} 268e1051a39Sopenharmony_ci 269e1051a39Sopenharmony_cistatic void pd_free(OSSL_PROPERTY_DEFINITION *pd) 270e1051a39Sopenharmony_ci{ 271e1051a39Sopenharmony_ci OPENSSL_free(pd); 272e1051a39Sopenharmony_ci} 273e1051a39Sopenharmony_ci 274e1051a39Sopenharmony_ci/* 275e1051a39Sopenharmony_ci * Convert a stack of property definitions and queries into a fixed array. 276e1051a39Sopenharmony_ci * The items are sorted for efficient query. The stack is not freed. 277e1051a39Sopenharmony_ci * This function also checks for duplicated names and returns an error if 278e1051a39Sopenharmony_ci * any exist. 279e1051a39Sopenharmony_ci */ 280e1051a39Sopenharmony_cistatic OSSL_PROPERTY_LIST * 281e1051a39Sopenharmony_cistack_to_property_list(OSSL_LIB_CTX *ctx, 282e1051a39Sopenharmony_ci STACK_OF(OSSL_PROPERTY_DEFINITION) *sk) 283e1051a39Sopenharmony_ci{ 284e1051a39Sopenharmony_ci const int n = sk_OSSL_PROPERTY_DEFINITION_num(sk); 285e1051a39Sopenharmony_ci OSSL_PROPERTY_LIST *r; 286e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX prev_name_idx = 0; 287e1051a39Sopenharmony_ci int i; 288e1051a39Sopenharmony_ci 289e1051a39Sopenharmony_ci r = OPENSSL_malloc(sizeof(*r) 290e1051a39Sopenharmony_ci + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0])); 291e1051a39Sopenharmony_ci if (r != NULL) { 292e1051a39Sopenharmony_ci sk_OSSL_PROPERTY_DEFINITION_sort(sk); 293e1051a39Sopenharmony_ci 294e1051a39Sopenharmony_ci r->has_optional = 0; 295e1051a39Sopenharmony_ci for (i = 0; i < n; i++) { 296e1051a39Sopenharmony_ci r->properties[i] = *sk_OSSL_PROPERTY_DEFINITION_value(sk, i); 297e1051a39Sopenharmony_ci r->has_optional |= r->properties[i].optional; 298e1051a39Sopenharmony_ci 299e1051a39Sopenharmony_ci /* Check for duplicated names */ 300e1051a39Sopenharmony_ci if (i > 0 && r->properties[i].name_idx == prev_name_idx) { 301e1051a39Sopenharmony_ci OPENSSL_free(r); 302e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED, 303e1051a39Sopenharmony_ci "Duplicated name `%s'", 304e1051a39Sopenharmony_ci ossl_property_name_str(ctx, prev_name_idx)); 305e1051a39Sopenharmony_ci return NULL; 306e1051a39Sopenharmony_ci } 307e1051a39Sopenharmony_ci prev_name_idx = r->properties[i].name_idx; 308e1051a39Sopenharmony_ci } 309e1051a39Sopenharmony_ci r->num_properties = n; 310e1051a39Sopenharmony_ci } 311e1051a39Sopenharmony_ci return r; 312e1051a39Sopenharmony_ci} 313e1051a39Sopenharmony_ci 314e1051a39Sopenharmony_ciOSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn) 315e1051a39Sopenharmony_ci{ 316e1051a39Sopenharmony_ci OSSL_PROPERTY_DEFINITION *prop = NULL; 317e1051a39Sopenharmony_ci OSSL_PROPERTY_LIST *res = NULL; 318e1051a39Sopenharmony_ci STACK_OF(OSSL_PROPERTY_DEFINITION) *sk; 319e1051a39Sopenharmony_ci const char *s = defn; 320e1051a39Sopenharmony_ci int done; 321e1051a39Sopenharmony_ci 322e1051a39Sopenharmony_ci if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL) 323e1051a39Sopenharmony_ci return NULL; 324e1051a39Sopenharmony_ci 325e1051a39Sopenharmony_ci s = skip_space(s); 326e1051a39Sopenharmony_ci done = *s == '\0'; 327e1051a39Sopenharmony_ci while (!done) { 328e1051a39Sopenharmony_ci const char *start = s; 329e1051a39Sopenharmony_ci 330e1051a39Sopenharmony_ci prop = OPENSSL_malloc(sizeof(*prop)); 331e1051a39Sopenharmony_ci if (prop == NULL) 332e1051a39Sopenharmony_ci goto err; 333e1051a39Sopenharmony_ci memset(&prop->v, 0, sizeof(prop->v)); 334e1051a39Sopenharmony_ci prop->optional = 0; 335e1051a39Sopenharmony_ci if (!parse_name(ctx, &s, 1, &prop->name_idx)) 336e1051a39Sopenharmony_ci goto err; 337e1051a39Sopenharmony_ci prop->oper = OSSL_PROPERTY_OPER_EQ; 338e1051a39Sopenharmony_ci if (prop->name_idx == 0) { 339e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED, 340e1051a39Sopenharmony_ci "Unknown name HERE-->%s", start); 341e1051a39Sopenharmony_ci goto err; 342e1051a39Sopenharmony_ci } 343e1051a39Sopenharmony_ci if (match_ch(&s, '=')) { 344e1051a39Sopenharmony_ci if (!parse_value(ctx, &s, prop, 1)) { 345e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE, 346e1051a39Sopenharmony_ci "HERE-->%s", start); 347e1051a39Sopenharmony_ci goto err; 348e1051a39Sopenharmony_ci } 349e1051a39Sopenharmony_ci } else { 350e1051a39Sopenharmony_ci /* A name alone means a true Boolean */ 351e1051a39Sopenharmony_ci prop->type = OSSL_PROPERTY_TYPE_STRING; 352e1051a39Sopenharmony_ci prop->v.str_val = OSSL_PROPERTY_TRUE; 353e1051a39Sopenharmony_ci } 354e1051a39Sopenharmony_ci 355e1051a39Sopenharmony_ci if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop)) 356e1051a39Sopenharmony_ci goto err; 357e1051a39Sopenharmony_ci prop = NULL; 358e1051a39Sopenharmony_ci done = !match_ch(&s, ','); 359e1051a39Sopenharmony_ci } 360e1051a39Sopenharmony_ci if (*s != '\0') { 361e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS, 362e1051a39Sopenharmony_ci "HERE-->%s", s); 363e1051a39Sopenharmony_ci goto err; 364e1051a39Sopenharmony_ci } 365e1051a39Sopenharmony_ci res = stack_to_property_list(ctx, sk); 366e1051a39Sopenharmony_ci 367e1051a39Sopenharmony_cierr: 368e1051a39Sopenharmony_ci OPENSSL_free(prop); 369e1051a39Sopenharmony_ci sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free); 370e1051a39Sopenharmony_ci return res; 371e1051a39Sopenharmony_ci} 372e1051a39Sopenharmony_ci 373e1051a39Sopenharmony_ciOSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s, 374e1051a39Sopenharmony_ci int create_values) 375e1051a39Sopenharmony_ci{ 376e1051a39Sopenharmony_ci STACK_OF(OSSL_PROPERTY_DEFINITION) *sk; 377e1051a39Sopenharmony_ci OSSL_PROPERTY_LIST *res = NULL; 378e1051a39Sopenharmony_ci OSSL_PROPERTY_DEFINITION *prop = NULL; 379e1051a39Sopenharmony_ci int done; 380e1051a39Sopenharmony_ci 381e1051a39Sopenharmony_ci if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL) 382e1051a39Sopenharmony_ci return NULL; 383e1051a39Sopenharmony_ci 384e1051a39Sopenharmony_ci s = skip_space(s); 385e1051a39Sopenharmony_ci done = *s == '\0'; 386e1051a39Sopenharmony_ci while (!done) { 387e1051a39Sopenharmony_ci prop = OPENSSL_malloc(sizeof(*prop)); 388e1051a39Sopenharmony_ci if (prop == NULL) 389e1051a39Sopenharmony_ci goto err; 390e1051a39Sopenharmony_ci memset(&prop->v, 0, sizeof(prop->v)); 391e1051a39Sopenharmony_ci 392e1051a39Sopenharmony_ci if (match_ch(&s, '-')) { 393e1051a39Sopenharmony_ci prop->oper = OSSL_PROPERTY_OVERRIDE; 394e1051a39Sopenharmony_ci prop->optional = 0; 395e1051a39Sopenharmony_ci if (!parse_name(ctx, &s, 1, &prop->name_idx)) 396e1051a39Sopenharmony_ci goto err; 397e1051a39Sopenharmony_ci goto skip_value; 398e1051a39Sopenharmony_ci } 399e1051a39Sopenharmony_ci prop->optional = match_ch(&s, '?'); 400e1051a39Sopenharmony_ci if (!parse_name(ctx, &s, 1, &prop->name_idx)) 401e1051a39Sopenharmony_ci goto err; 402e1051a39Sopenharmony_ci 403e1051a39Sopenharmony_ci if (match_ch(&s, '=')) { 404e1051a39Sopenharmony_ci prop->oper = OSSL_PROPERTY_OPER_EQ; 405e1051a39Sopenharmony_ci } else if (MATCH(&s, "!=")) { 406e1051a39Sopenharmony_ci prop->oper = OSSL_PROPERTY_OPER_NE; 407e1051a39Sopenharmony_ci } else { 408e1051a39Sopenharmony_ci /* A name alone is a Boolean comparison for true */ 409e1051a39Sopenharmony_ci prop->oper = OSSL_PROPERTY_OPER_EQ; 410e1051a39Sopenharmony_ci prop->type = OSSL_PROPERTY_TYPE_STRING; 411e1051a39Sopenharmony_ci prop->v.str_val = OSSL_PROPERTY_TRUE; 412e1051a39Sopenharmony_ci goto skip_value; 413e1051a39Sopenharmony_ci } 414e1051a39Sopenharmony_ci if (!parse_value(ctx, &s, prop, create_values)) 415e1051a39Sopenharmony_ci prop->type = OSSL_PROPERTY_TYPE_VALUE_UNDEFINED; 416e1051a39Sopenharmony_ci 417e1051a39Sopenharmony_ciskip_value: 418e1051a39Sopenharmony_ci if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop)) 419e1051a39Sopenharmony_ci goto err; 420e1051a39Sopenharmony_ci prop = NULL; 421e1051a39Sopenharmony_ci done = !match_ch(&s, ','); 422e1051a39Sopenharmony_ci } 423e1051a39Sopenharmony_ci if (*s != '\0') { 424e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS, 425e1051a39Sopenharmony_ci "HERE-->%s", s); 426e1051a39Sopenharmony_ci goto err; 427e1051a39Sopenharmony_ci } 428e1051a39Sopenharmony_ci res = stack_to_property_list(ctx, sk); 429e1051a39Sopenharmony_ci 430e1051a39Sopenharmony_cierr: 431e1051a39Sopenharmony_ci OPENSSL_free(prop); 432e1051a39Sopenharmony_ci sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free); 433e1051a39Sopenharmony_ci return res; 434e1051a39Sopenharmony_ci} 435e1051a39Sopenharmony_ci 436e1051a39Sopenharmony_ci/* 437e1051a39Sopenharmony_ci * Compare a query against a definition. 438e1051a39Sopenharmony_ci * Return the number of clauses matched or -1 if a mandatory clause is false. 439e1051a39Sopenharmony_ci */ 440e1051a39Sopenharmony_ciint ossl_property_match_count(const OSSL_PROPERTY_LIST *query, 441e1051a39Sopenharmony_ci const OSSL_PROPERTY_LIST *defn) 442e1051a39Sopenharmony_ci{ 443e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *const q = query->properties; 444e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *const d = defn->properties; 445e1051a39Sopenharmony_ci int i = 0, j = 0, matches = 0; 446e1051a39Sopenharmony_ci OSSL_PROPERTY_OPER oper; 447e1051a39Sopenharmony_ci 448e1051a39Sopenharmony_ci while (i < query->num_properties) { 449e1051a39Sopenharmony_ci if ((oper = q[i].oper) == OSSL_PROPERTY_OVERRIDE) { 450e1051a39Sopenharmony_ci i++; 451e1051a39Sopenharmony_ci continue; 452e1051a39Sopenharmony_ci } 453e1051a39Sopenharmony_ci if (j < defn->num_properties) { 454e1051a39Sopenharmony_ci if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */ 455e1051a39Sopenharmony_ci j++; 456e1051a39Sopenharmony_ci continue; 457e1051a39Sopenharmony_ci } 458e1051a39Sopenharmony_ci if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */ 459e1051a39Sopenharmony_ci const int eq = q[i].type == d[j].type 460e1051a39Sopenharmony_ci && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0; 461e1051a39Sopenharmony_ci 462e1051a39Sopenharmony_ci if ((eq && oper == OSSL_PROPERTY_OPER_EQ) 463e1051a39Sopenharmony_ci || (!eq && oper == OSSL_PROPERTY_OPER_NE)) 464e1051a39Sopenharmony_ci matches++; 465e1051a39Sopenharmony_ci else if (!q[i].optional) 466e1051a39Sopenharmony_ci return -1; 467e1051a39Sopenharmony_ci i++; 468e1051a39Sopenharmony_ci j++; 469e1051a39Sopenharmony_ci continue; 470e1051a39Sopenharmony_ci } 471e1051a39Sopenharmony_ci } 472e1051a39Sopenharmony_ci 473e1051a39Sopenharmony_ci /* 474e1051a39Sopenharmony_ci * Handle the cases of a missing value and a query with no corresponding 475e1051a39Sopenharmony_ci * definition. The former fails for any comparison except inequality, 476e1051a39Sopenharmony_ci * the latter is treated as a comparison against the Boolean false. 477e1051a39Sopenharmony_ci */ 478e1051a39Sopenharmony_ci if (q[i].type == OSSL_PROPERTY_TYPE_VALUE_UNDEFINED) { 479e1051a39Sopenharmony_ci if (oper == OSSL_PROPERTY_OPER_NE) 480e1051a39Sopenharmony_ci matches++; 481e1051a39Sopenharmony_ci else if (!q[i].optional) 482e1051a39Sopenharmony_ci return -1; 483e1051a39Sopenharmony_ci } else if (q[i].type != OSSL_PROPERTY_TYPE_STRING 484e1051a39Sopenharmony_ci || (oper == OSSL_PROPERTY_OPER_EQ 485e1051a39Sopenharmony_ci && q[i].v.str_val != OSSL_PROPERTY_FALSE) 486e1051a39Sopenharmony_ci || (oper == OSSL_PROPERTY_OPER_NE 487e1051a39Sopenharmony_ci && q[i].v.str_val == OSSL_PROPERTY_FALSE)) { 488e1051a39Sopenharmony_ci if (!q[i].optional) 489e1051a39Sopenharmony_ci return -1; 490e1051a39Sopenharmony_ci } else { 491e1051a39Sopenharmony_ci matches++; 492e1051a39Sopenharmony_ci } 493e1051a39Sopenharmony_ci i++; 494e1051a39Sopenharmony_ci } 495e1051a39Sopenharmony_ci return matches; 496e1051a39Sopenharmony_ci} 497e1051a39Sopenharmony_ci 498e1051a39Sopenharmony_civoid ossl_property_free(OSSL_PROPERTY_LIST *p) 499e1051a39Sopenharmony_ci{ 500e1051a39Sopenharmony_ci OPENSSL_free(p); 501e1051a39Sopenharmony_ci} 502e1051a39Sopenharmony_ci 503e1051a39Sopenharmony_ci/* 504e1051a39Sopenharmony_ci * Merge two property lists. 505e1051a39Sopenharmony_ci * If there is a common name, the one from the first list is used. 506e1051a39Sopenharmony_ci */ 507e1051a39Sopenharmony_ciOSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a, 508e1051a39Sopenharmony_ci const OSSL_PROPERTY_LIST *b) 509e1051a39Sopenharmony_ci{ 510e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *const ap = a->properties; 511e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *const bp = b->properties; 512e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *copy; 513e1051a39Sopenharmony_ci OSSL_PROPERTY_LIST *r; 514e1051a39Sopenharmony_ci int i, j, n; 515e1051a39Sopenharmony_ci const int t = a->num_properties + b->num_properties; 516e1051a39Sopenharmony_ci 517e1051a39Sopenharmony_ci r = OPENSSL_malloc(sizeof(*r) 518e1051a39Sopenharmony_ci + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0])); 519e1051a39Sopenharmony_ci if (r == NULL) 520e1051a39Sopenharmony_ci return NULL; 521e1051a39Sopenharmony_ci 522e1051a39Sopenharmony_ci r->has_optional = 0; 523e1051a39Sopenharmony_ci for (i = j = n = 0; i < a->num_properties || j < b->num_properties; n++) { 524e1051a39Sopenharmony_ci if (i >= a->num_properties) { 525e1051a39Sopenharmony_ci copy = &bp[j++]; 526e1051a39Sopenharmony_ci } else if (j >= b->num_properties) { 527e1051a39Sopenharmony_ci copy = &ap[i++]; 528e1051a39Sopenharmony_ci } else if (ap[i].name_idx <= bp[j].name_idx) { 529e1051a39Sopenharmony_ci if (ap[i].name_idx == bp[j].name_idx) 530e1051a39Sopenharmony_ci j++; 531e1051a39Sopenharmony_ci copy = &ap[i++]; 532e1051a39Sopenharmony_ci } else { 533e1051a39Sopenharmony_ci copy = &bp[j++]; 534e1051a39Sopenharmony_ci } 535e1051a39Sopenharmony_ci memcpy(r->properties + n, copy, sizeof(r->properties[0])); 536e1051a39Sopenharmony_ci r->has_optional |= copy->optional; 537e1051a39Sopenharmony_ci } 538e1051a39Sopenharmony_ci r->num_properties = n; 539e1051a39Sopenharmony_ci if (n != t) 540e1051a39Sopenharmony_ci r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0])); 541e1051a39Sopenharmony_ci return r; 542e1051a39Sopenharmony_ci} 543e1051a39Sopenharmony_ci 544e1051a39Sopenharmony_ciint ossl_property_parse_init(OSSL_LIB_CTX *ctx) 545e1051a39Sopenharmony_ci{ 546e1051a39Sopenharmony_ci static const char *const predefined_names[] = { 547e1051a39Sopenharmony_ci "provider", /* Name of provider (default, legacy, fips) */ 548e1051a39Sopenharmony_ci "version", /* Version number of this provider */ 549e1051a39Sopenharmony_ci "fips", /* FIPS validated or FIPS supporting algorithm */ 550e1051a39Sopenharmony_ci "output", /* Output type for encoders */ 551e1051a39Sopenharmony_ci "input", /* Input type for decoders */ 552e1051a39Sopenharmony_ci "structure", /* Structure name for encoders and decoders */ 553e1051a39Sopenharmony_ci }; 554e1051a39Sopenharmony_ci size_t i; 555e1051a39Sopenharmony_ci 556e1051a39Sopenharmony_ci for (i = 0; i < OSSL_NELEM(predefined_names); i++) 557e1051a39Sopenharmony_ci if (ossl_property_name(ctx, predefined_names[i], 1) == 0) 558e1051a39Sopenharmony_ci goto err; 559e1051a39Sopenharmony_ci 560e1051a39Sopenharmony_ci /* 561e1051a39Sopenharmony_ci * Pre-populate the two Boolean values. We must do them before any other 562e1051a39Sopenharmony_ci * values and in this order so that we get the same index as the global 563e1051a39Sopenharmony_ci * OSSL_PROPERTY_TRUE and OSSL_PROPERTY_FALSE values 564e1051a39Sopenharmony_ci */ 565e1051a39Sopenharmony_ci if ((ossl_property_value(ctx, "yes", 1) != OSSL_PROPERTY_TRUE) 566e1051a39Sopenharmony_ci || (ossl_property_value(ctx, "no", 1) != OSSL_PROPERTY_FALSE)) 567e1051a39Sopenharmony_ci goto err; 568e1051a39Sopenharmony_ci 569e1051a39Sopenharmony_ci return 1; 570e1051a39Sopenharmony_cierr: 571e1051a39Sopenharmony_ci return 0; 572e1051a39Sopenharmony_ci} 573e1051a39Sopenharmony_ci 574e1051a39Sopenharmony_cistatic void put_char(char ch, char **buf, size_t *remain, size_t *needed) 575e1051a39Sopenharmony_ci{ 576e1051a39Sopenharmony_ci if (*remain == 0) { 577e1051a39Sopenharmony_ci ++*needed; 578e1051a39Sopenharmony_ci return; 579e1051a39Sopenharmony_ci } 580e1051a39Sopenharmony_ci if (*remain == 1) 581e1051a39Sopenharmony_ci **buf = '\0'; 582e1051a39Sopenharmony_ci else 583e1051a39Sopenharmony_ci **buf = ch; 584e1051a39Sopenharmony_ci ++*buf; 585e1051a39Sopenharmony_ci ++*needed; 586e1051a39Sopenharmony_ci --*remain; 587e1051a39Sopenharmony_ci} 588e1051a39Sopenharmony_ci 589e1051a39Sopenharmony_cistatic void put_str(const char *str, char **buf, size_t *remain, size_t *needed) 590e1051a39Sopenharmony_ci{ 591e1051a39Sopenharmony_ci size_t olen, len; 592e1051a39Sopenharmony_ci 593e1051a39Sopenharmony_ci len = olen = strlen(str); 594e1051a39Sopenharmony_ci *needed += len; 595e1051a39Sopenharmony_ci 596e1051a39Sopenharmony_ci if (*remain == 0) 597e1051a39Sopenharmony_ci return; 598e1051a39Sopenharmony_ci 599e1051a39Sopenharmony_ci if (*remain < len + 1) 600e1051a39Sopenharmony_ci len = *remain - 1; 601e1051a39Sopenharmony_ci 602e1051a39Sopenharmony_ci if (len > 0) { 603e1051a39Sopenharmony_ci memcpy(*buf, str, len); 604e1051a39Sopenharmony_ci *buf += len; 605e1051a39Sopenharmony_ci *remain -= len; 606e1051a39Sopenharmony_ci } 607e1051a39Sopenharmony_ci 608e1051a39Sopenharmony_ci if (len < olen && *remain == 1) { 609e1051a39Sopenharmony_ci **buf = '\0'; 610e1051a39Sopenharmony_ci ++*buf; 611e1051a39Sopenharmony_ci --*remain; 612e1051a39Sopenharmony_ci } 613e1051a39Sopenharmony_ci} 614e1051a39Sopenharmony_ci 615e1051a39Sopenharmony_cistatic void put_num(int64_t val, char **buf, size_t *remain, size_t *needed) 616e1051a39Sopenharmony_ci{ 617e1051a39Sopenharmony_ci int64_t tmpval = val; 618e1051a39Sopenharmony_ci size_t len = 1; 619e1051a39Sopenharmony_ci 620e1051a39Sopenharmony_ci if (tmpval < 0) { 621e1051a39Sopenharmony_ci len++; 622e1051a39Sopenharmony_ci tmpval = -tmpval; 623e1051a39Sopenharmony_ci } 624e1051a39Sopenharmony_ci for (; tmpval > 9; len++, tmpval /= 10); 625e1051a39Sopenharmony_ci 626e1051a39Sopenharmony_ci *needed += len; 627e1051a39Sopenharmony_ci 628e1051a39Sopenharmony_ci if (*remain == 0) 629e1051a39Sopenharmony_ci return; 630e1051a39Sopenharmony_ci 631e1051a39Sopenharmony_ci BIO_snprintf(*buf, *remain, "%lld", (long long int)val); 632e1051a39Sopenharmony_ci if (*remain < len) { 633e1051a39Sopenharmony_ci *buf += *remain; 634e1051a39Sopenharmony_ci *remain = 0; 635e1051a39Sopenharmony_ci } else { 636e1051a39Sopenharmony_ci *buf += len; 637e1051a39Sopenharmony_ci *remain -= len; 638e1051a39Sopenharmony_ci } 639e1051a39Sopenharmony_ci} 640e1051a39Sopenharmony_ci 641e1051a39Sopenharmony_cisize_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx, 642e1051a39Sopenharmony_ci const OSSL_PROPERTY_LIST *list, char *buf, 643e1051a39Sopenharmony_ci size_t bufsize) 644e1051a39Sopenharmony_ci{ 645e1051a39Sopenharmony_ci int i; 646e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *prop = NULL; 647e1051a39Sopenharmony_ci size_t needed = 0; 648e1051a39Sopenharmony_ci const char *val; 649e1051a39Sopenharmony_ci 650e1051a39Sopenharmony_ci if (list == NULL) { 651e1051a39Sopenharmony_ci if (bufsize > 0) 652e1051a39Sopenharmony_ci *buf = '\0'; 653e1051a39Sopenharmony_ci return 1; 654e1051a39Sopenharmony_ci } 655e1051a39Sopenharmony_ci if (list->num_properties != 0) 656e1051a39Sopenharmony_ci prop = &list->properties[list->num_properties - 1]; 657e1051a39Sopenharmony_ci for (i = 0; i < list->num_properties; i++, prop--) { 658e1051a39Sopenharmony_ci /* Skip invalid names */ 659e1051a39Sopenharmony_ci if (prop->name_idx == 0) 660e1051a39Sopenharmony_ci continue; 661e1051a39Sopenharmony_ci 662e1051a39Sopenharmony_ci if (needed > 0) 663e1051a39Sopenharmony_ci put_char(',', &buf, &bufsize, &needed); 664e1051a39Sopenharmony_ci 665e1051a39Sopenharmony_ci if (prop->optional) 666e1051a39Sopenharmony_ci put_char('?', &buf, &bufsize, &needed); 667e1051a39Sopenharmony_ci else if (prop->oper == OSSL_PROPERTY_OVERRIDE) 668e1051a39Sopenharmony_ci put_char('-', &buf, &bufsize, &needed); 669e1051a39Sopenharmony_ci 670e1051a39Sopenharmony_ci val = ossl_property_name_str(ctx, prop->name_idx); 671e1051a39Sopenharmony_ci if (val == NULL) 672e1051a39Sopenharmony_ci return 0; 673e1051a39Sopenharmony_ci put_str(val, &buf, &bufsize, &needed); 674e1051a39Sopenharmony_ci 675e1051a39Sopenharmony_ci switch (prop->oper) { 676e1051a39Sopenharmony_ci case OSSL_PROPERTY_OPER_NE: 677e1051a39Sopenharmony_ci put_char('!', &buf, &bufsize, &needed); 678e1051a39Sopenharmony_ci /* fall through */ 679e1051a39Sopenharmony_ci case OSSL_PROPERTY_OPER_EQ: 680e1051a39Sopenharmony_ci put_char('=', &buf, &bufsize, &needed); 681e1051a39Sopenharmony_ci /* put value */ 682e1051a39Sopenharmony_ci switch (prop->type) { 683e1051a39Sopenharmony_ci case OSSL_PROPERTY_TYPE_STRING: 684e1051a39Sopenharmony_ci val = ossl_property_value_str(ctx, prop->v.str_val); 685e1051a39Sopenharmony_ci if (val == NULL) 686e1051a39Sopenharmony_ci return 0; 687e1051a39Sopenharmony_ci put_str(val, &buf, &bufsize, &needed); 688e1051a39Sopenharmony_ci break; 689e1051a39Sopenharmony_ci 690e1051a39Sopenharmony_ci case OSSL_PROPERTY_TYPE_NUMBER: 691e1051a39Sopenharmony_ci put_num(prop->v.int_val, &buf, &bufsize, &needed); 692e1051a39Sopenharmony_ci break; 693e1051a39Sopenharmony_ci 694e1051a39Sopenharmony_ci default: 695e1051a39Sopenharmony_ci return 0; 696e1051a39Sopenharmony_ci } 697e1051a39Sopenharmony_ci break; 698e1051a39Sopenharmony_ci default: 699e1051a39Sopenharmony_ci /* do nothing */ 700e1051a39Sopenharmony_ci break; 701e1051a39Sopenharmony_ci } 702e1051a39Sopenharmony_ci } 703e1051a39Sopenharmony_ci 704e1051a39Sopenharmony_ci put_char('\0', &buf, &bufsize, &needed); 705e1051a39Sopenharmony_ci return needed; 706e1051a39Sopenharmony_ci} 707