diff --git a/lib/hx509/ChangeLog b/lib/hx509/ChangeLog index 9e22f9e5b..24a75ea08 100644 --- a/lib/hx509/ChangeLog +++ b/lib/hx509/ChangeLog @@ -1,5 +1,7 @@ 2008-02-26 Love Hörnquist Åstrand + * version-script.map: add hx509_pem_read + * hxtool-commands.in: Add --pem to cms-verify-sd. * test_cms.in: Test verifying PEM signature files. diff --git a/lib/hx509/Makefile.am b/lib/hx509/Makefile.am index c61918f46..dcaee7744 100644 --- a/lib/hx509/Makefile.am +++ b/lib/hx509/Makefile.am @@ -6,6 +6,7 @@ lib_LTLIBRARIES = libhx509.la libhx509_la_LDFLAGS = -version-info 3:0:0 BUILT_SOURCES = \ + sel-gram.h \ $(gen_files_ocsp:.x=.c) \ $(gen_files_pkcs10:.x=.c) \ hx509_err.c \ @@ -50,6 +51,8 @@ gen_files_crmf = \ asn1_ProofOfPossession.x \ asn1_SubsequentMessage.x +AM_YFLAGS = -d + dist_libhx509_la_SOURCES = \ ca.c \ cert.c \ @@ -64,6 +67,10 @@ dist_libhx509_la_SOURCES = \ hx509-protos.h \ hx509.h \ hx_locl.h \ + sel.c \ + sel.h \ + sel-gram.y \ + sel-lex.l \ keyset.c \ ks_dir.c \ ks_file.c \ @@ -81,6 +88,8 @@ dist_libhx509_la_SOURCES = \ req.c \ revoke.c +sel-lex.c: sel-gram.h + libhx509_la_LIBADD = \ $(LIB_com_err) \ $(LIB_hcrypto) \ @@ -184,7 +193,8 @@ test_soft_pkcs11_CPPFLAGS = -I$(srcdir)/ref TESTS = $(SCRIPT_TESTS) $(PROGRAM_TESTS) PROGRAM_TESTS = \ - test_name + test_name \ + test_expr SCRIPT_TESTS = \ test_ca \ diff --git a/lib/hx509/cert.c b/lib/hx509/cert.c index b16e515f0..589215c57 100644 --- a/lib/hx509/cert.c +++ b/lib/hx509/cert.c @@ -2355,7 +2355,7 @@ hx509_verify_hostname(hx509_context context, } while (1); { - Name *name = &cert->data->tbsCertificate.subject; + const Name *name = &cert->data->tbsCertificate.subject; /* match if first component is a CN= */ if (name->u.rdnSequence.len > 0 @@ -2548,6 +2548,7 @@ hx509_query_alloc(hx509_context context, hx509_query **q) return 0; } + /** * Set match options for the hx509 query controller. * @@ -2697,6 +2698,25 @@ hx509_query_match_eku(hx509_query *q, const heim_oid *eku) return 0; } +int +hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr) +{ + if (q->expr) { + _hx509_expr_free(q->expr); + q->expr = NULL; + } + + if (expr == NULL) { + q->match &= ~HX509_QUERY_MATCH_EXPR; + } else { + q->expr = _hx509_expr_parse(expr); + if (q->expr) + q->match |= HX509_QUERY_MATCH_EXPR; + } + + return 0; +} + /** * Set the query controller to match using a specific match function. * @@ -2753,6 +2773,9 @@ hx509_query_free(hx509_context context, hx509_query *q) } if (q->friendlyname) free(q->friendlyname); + if (q->expr) + _hx509_expr_free(q->expr); + memset(q, 0, sizeof(*q)); free(q); } @@ -2890,6 +2913,19 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert hx509_cert_check_eku(context, cert, q->eku, 0)) return 0; + if ((q->match & HX509_QUERY_MATCH_EXPR)) { + hx509_env env = NULL; + + ret = _hx509_cert_to_env(context, cert, &env); + if (ret) + return 0; + + ret = _hx509_eval_expr(context, env, q->expr); + hx509_env_free(&env); + if (ret == 0) + return 0; + } + if (q->match & ~HX509_QUERY_MASK) return 0; @@ -3206,3 +3242,103 @@ hx509_xfree(void *ptr) { free(ptr); } + +/** + * + */ + +int +_hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env) +{ + ExtKeyUsage eku; + hx509_name name; + char *buf; + int ret; + hx509_env envcert = NULL; + + *env = NULL; + + /* version */ + asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert))); + ret = hx509_env_add(context, &envcert, "version", buf); + free(buf); + if (ret) + goto out; + + /* subject */ + ret = hx509_cert_get_subject(cert, &name); + if (ret) + goto out; + + ret = hx509_name_to_string(name, &buf); + if (ret) { + hx509_name_free(&name); + goto out; + } + + ret = hx509_env_add(context, &envcert, "subject", buf); + hx509_name_free(&name); + if (ret) + goto out; + + /* issuer */ + ret = hx509_cert_get_issuer(cert, &name); + if (ret) + goto out; + + ret = hx509_name_to_string(name, &buf); + hx509_name_free(&name); + if (ret) + goto out; + + ret = hx509_env_add(context, &envcert, "issuer", buf); + hx509_xfree(buf); + if (ret) + goto out; + + /* eku */ + + ret = _hx509_cert_get_eku(context, cert, &eku); + if (ret == HX509_EXTENSION_NOT_FOUND) + ; + else if (ret != 0) + goto out; + else { + int i; + hx509_env enveku = NULL; + + for (i = 0; i < eku.len; i++) { + + ret = der_print_heim_oid(&eku.val[i], '.', &buf); + if (ret) { + free_ExtKeyUsage(&eku); + hx509_env_free(&enveku); + goto out; + } + ret = hx509_env_add(context, &enveku, buf, "oid-name-here"); + free(buf); + if (ret) { + free_ExtKeyUsage(&eku); + hx509_env_free(&enveku); + goto out; + } + } + free_ExtKeyUsage(&eku); + + ret = hx509_env_add_binding(context, &envcert, "eku", enveku); + if (ret) { + hx509_env_free(&enveku); + goto out; + } + } + + ret = hx509_env_add_binding(context, env, "certificate", envcert); + if (ret) + goto out; + + return 0; + +out: + hx509_env_free(&envcert); + return ret; +} diff --git a/lib/hx509/env.c b/lib/hx509/env.c index 4d3877d4d..9d771c506 100644 --- a/lib/hx509/env.c +++ b/lib/hx509/env.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 Kungliga Tekniska Högskolan + * Copyright (c) 2007 - 2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -40,36 +40,6 @@ RCSID("$Id$"); * See the library functions here: @ref hx509_env */ -struct hx509_env { - struct { - char *key; - char *value; - } *val; - size_t len; -}; - -/** - * Allocate a new hx509_env container object. - * - * @param context A hx509 context. - * @param env return a hx509_env structure, free with hx509_env_free(). - * - * @return An hx509 error code, see hx509_get_error_string(). - * - * @ingroup hx509_env - */ - -int -hx509_env_init(hx509_context context, hx509_env *env) -{ - *env = calloc(1, sizeof(**env)); - if (*env == NULL) { - hx509_set_error_string(context, 0, ENOMEM, "out of memory"); - return ENOMEM; - } - return 0; -} - /** * Add a new key/value pair to the hx509_env. * @@ -84,34 +54,92 @@ hx509_env_init(hx509_context context, hx509_env *env) */ int -hx509_env_add(hx509_context context, hx509_env env, +hx509_env_add(hx509_context context, hx509_env *env, const char *key, const char *value) { - void *ptr; + hx509_env n; - ptr = realloc(env->val, sizeof(env->val[0]) * (env->len + 1)); - if (ptr == NULL) { + n = malloc(sizeof(*n)); + if (n == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; } - env->val = ptr; - env->val[env->len].key = strdup(key); - if (env->val[env->len].key == NULL) { - hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + + n->type = env_string; + n->next = NULL; + n->name = strdup(key); + if (n->name == NULL) { + free(n); return ENOMEM; } - env->val[env->len].value = strdup(value); - if (env->val[env->len].value == NULL) { - free(env->val[env->len].key); - hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + n->u.string = strdup(value); + if (n->u.string == NULL) { + free(n->name); + free(n); return ENOMEM; } - env->len++; + + /* add to tail */ + if (*env) { + hx509_env e = *env; + while (e->next) + e = e->next; + e->next = n; + } else + *env = n; + return 0; } /** - * Search the hx509_env for a key. + * Add a new key/binding pair to the hx509_env. + * + * @param context A hx509 context. + * @param env enviroment to add the enviroment variable too. + * @param key key to add + * @param list binding list to add + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_env + */ + +int +hx509_env_add_binding(hx509_context context, hx509_env *env, + const char *key, hx509_env list) +{ + hx509_env n; + + n = malloc(sizeof(*n)); + if (n == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + n->type = env_list; + n->next = NULL; + n->name = strdup(key); + if (n->name == NULL) { + free(n); + return ENOMEM; + } + n->u.list = list; + + /* add to tail */ + if (*env) { + hx509_env e = *env; + while (e->next) + e = e->next; + e->next = n; + } else + *env = n; + + return 0; +} + + +/** + * Search the hx509_env for a length based key. * * @param context A hx509 context. * @param env enviroment to add the enviroment variable too. @@ -127,16 +155,80 @@ const char * hx509_env_lfind(hx509_context context, hx509_env env, const char *key, size_t len) { - size_t i; - - for (i = 0; i < env->len; i++) { - char *s = env->val[i].key; - if (strncmp(key, s, len) == 0 && s[len] == '\0') - return env->val[i].value; + while(env) { + if (strncmp(key, env->name ,len) == 0 + && env->name[len] == '\0' && env->type == env_string) + return env->u.string; + env = env->next; } return NULL; } +/** + * Search the hx509_env for a key. + * + * @param context A hx509 context. + * @param env enviroment to add the enviroment variable too. + * @param key key to search for. + * + * @return the value if the key is found, NULL otherwise. + * + * @ingroup hx509_env + */ + +const char * +hx509_env_find(hx509_context context, hx509_env env, const char *key) +{ + while(env) { + if (strcmp(key, env->name) == 0 && env->type == env_string) + return env->u.string; + env = env->next; + } + return NULL; +} + +/** + * Search the hx509_env for a binding. + * + * @param context A hx509 context. + * @param env enviroment to add the enviroment variable too. + * @param key key to search for. + * + * @return the binding if the key is found, NULL if not found. + * + * @ingroup hx509_env + */ + +hx509_env +hx509_env_find_binding(hx509_context context, + hx509_env env, + const char *key) +{ + while(env) { + if (strcmp(key, env->name) == 0 && env->type == env_list) + return env->u.list; + env = env->next; + } + return NULL; +} + +static void +env_free(hx509_env b) +{ + while(b) { + hx509_env next = b->next; + + if (b->type == env_string) + free(b->u.string); + else if (b->type == env_list) + env_free(b->u.list); + + free(b->name); + free(b); + b = next; + } +} + /** * Free an hx509_env enviroment context. * @@ -148,14 +240,7 @@ hx509_env_lfind(hx509_context context, hx509_env env, void hx509_env_free(hx509_env *env) { - size_t i; - - for (i = 0; i < (*env)->len; i++) { - free((*env)->val[i].key); - free((*env)->val[i].value); - } - free((*env)->val); - free(*env); + if (*env) + env_free(*env); *env = NULL; } - diff --git a/lib/hx509/hx509.h b/lib/hx509/hx509.h index d579be05b..e9d7131c6 100644 --- a/lib/hx509/hx509.h +++ b/lib/hx509/hx509.h @@ -50,7 +50,7 @@ typedef struct hx509_request_data *hx509_request; typedef struct hx509_error_data *hx509_error; typedef struct hx509_peer_info *hx509_peer_info; typedef struct hx509_ca_tbs *hx509_ca_tbs; -typedef struct hx509_env *hx509_env; +typedef struct hx509_env_data *hx509_env; typedef struct hx509_crl *hx509_crl; typedef void (*hx509_vprint_func)(void *, const char *, va_list); diff --git a/lib/hx509/hx_locl.h b/lib/hx509/hx_locl.h index 3bafc9bdb..adf5215a0 100644 --- a/lib/hx509/hx_locl.h +++ b/lib/hx509/hx_locl.h @@ -80,6 +80,8 @@ typedef void (*_hx509_cert_release_func)(struct hx509_cert_data *, void *); typedef struct hx509_private_key_ops hx509_private_key_ops; +#include "sel.h" + #include #include @@ -129,7 +131,8 @@ struct hx509_query_data { #define HX509_QUERY_MATCH_KEY_HASH_SHA1 0x100000 #define HX509_QUERY_MATCH_TIME 0x200000 #define HX509_QUERY_MATCH_EKU 0x400000 -#define HX509_QUERY_MASK 0x7fffff +#define HX509_QUERY_MATCH_EXPR 0x800000 +#define HX509_QUERY_MASK 0xffffff Certificate *subject; Certificate *certificate; heim_integer *serial; @@ -144,6 +147,7 @@ struct hx509_query_data { heim_octet_string *keyhash_sha1; time_t timenow; heim_oid *eku; + struct hx_expr *expr; }; struct hx509_keyset_ops { @@ -188,6 +192,18 @@ struct hx509_context_data { /* _hx509_calculate_path flag field */ #define HX509_CALCULATE_PATH_NO_ANCHOR 1 +/* environment */ +struct hx509_env_data { + enum { env_string, env_list } type; + char *name; + struct hx509_env_data *next; + union { + char *string; + struct hx509_env_data *list; + } u; +}; + + extern const AlgorithmIdentifier * _hx509_crypto_default_sig_alg; extern const AlgorithmIdentifier * _hx509_crypto_default_digest_alg; extern const AlgorithmIdentifier * _hx509_crypto_default_secret_alg; diff --git a/lib/hx509/hxtool-commands.in b/lib/hx509/hxtool-commands.in index 703952f85..6d105d686 100644 --- a/lib/hx509/hxtool-commands.in +++ b/lib/hx509/hxtool-commands.in @@ -448,6 +448,12 @@ command = { argument = "oid-string" help = "match on EKU" } + option = { + long = "expr" + type = "string" + argument = "expression" + help = "match on expression" + } option = { long = "keyEncipherment" type = "flag" diff --git a/lib/hx509/hxtool.c b/lib/hx509/hxtool.c index 4fc2fa11f..8c5e1b6ed 100644 --- a/lib/hx509/hxtool.c +++ b/lib/hx509/hxtool.c @@ -942,6 +942,9 @@ query(struct query_options *opt, int argc, char **argv) if (opt->digitalSignature_flag) hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + if (opt->expr_string) + hx509_query_match_expr(context, q, opt->expr_string); + ret = hx509_certs_find(context, certs, q, &c); hx509_query_free(context, q); if (ret) diff --git a/lib/hx509/name.c b/lib/hx509/name.c index 3c0b256ce..a34e09e84 100644 --- a/lib/hx509/name.c +++ b/lib/hx509/name.c @@ -897,7 +897,7 @@ hx509_name_is_null_p(const hx509_name name) * @param name the name to print * @param str an allocated string returns the name in string form * - * @return An hx509 error code, see krb5_get_error_string(). + * @return An hx509 error code, see hx509_get_error_string(). * * @ingroup hx509_name */ diff --git a/lib/hx509/sel-gram.y b/lib/hx509/sel-gram.y new file mode 100644 index 000000000..ca34a1975 --- /dev/null +++ b/lib/hx509/sel-gram.y @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * 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. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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. + */ + +%{ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include + +RCSID("$Id$"); + +%} + +%union { + char *string; + struct hx_expr *expr; +} + +%token kw_TRUE +%token kw_FALSE +%token kw_AND +%token kw_OR +%token kw_IN +%token kw_TAILMATCH + +%type expr +%type comp +%type word words +%type number +%type string +%type function +%type variable variables + +%token NUMBER +%token STRING +%token IDENTIFIER + +%start start + +%% + +start: expr { _hx509_expr_input.expr = $1; } + +expr : kw_TRUE { $$ = _hx509_make_expr(op_TRUE, NULL, NULL); } + | kw_FALSE { $$ = _hx509_make_expr(op_FALSE, NULL, NULL); } + | '!' expr { $$ = _hx509_make_expr(op_NOT, $2, NULL); } + | expr kw_AND expr { $$ = _hx509_make_expr(op_AND, $1, $3); } + | expr kw_OR expr { $$ = _hx509_make_expr(op_OR, $1, $3); } + | '(' expr ')' { $$ = $2; } + | comp { $$ = _hx509_make_expr(op_COMP, $1, NULL); } + ; + +words : word { $$ = _hx509_make_expr(expr_WORDS, $1, NULL); } + | word ',' words { $$ = _hx509_make_expr(expr_WORDS, $1, $3); } + ; + +comp : word '=' '=' word { $$ = _hx509_make_expr(comp_EQ, $1, $4); } + | word '!' '=' word { $$ = _hx509_make_expr(comp_NE, $1, $4); } + | word kw_TAILMATCH word { $$ = _hx509_make_expr(comp_TAILEQ, $1, $3); } + | word kw_IN '(' words ')' { $$ = _hx509_make_expr(comp_IN, $1, $4); } + | word kw_IN variable { $$ = _hx509_make_expr(comp_IN, $1, $3); } + ; + +word : number { $$ = $1; } + | string { $$ = $1; } + | function { $$ = $1; } + | variable { $$ = $1; } + ; + +number : NUMBER { $$ = _hx509_make_expr(expr_NUMBER, $1, NULL); }; +string : STRING { $$ = _hx509_make_expr(expr_STRING, $1, NULL); }; + +function: IDENTIFIER '(' words ')' { + $$ = _hx509_make_expr(expr_FUNCTION, $1, $3); } + ; +variable: '%' '{' variables '}' { $$ = $3; } + ; + +variables: IDENTIFIER '.' variables { + $$ = _hx509_make_expr(expr_VAR, $1, $3); } + | IDENTIFIER { + $$ = _hx509_make_expr(expr_VAR, $1, NULL); } + ; diff --git a/lib/hx509/sel-lex.l b/lib/hx509/sel-lex.l new file mode 100644 index 000000000..ce3ea9913 --- /dev/null +++ b/lib/hx509/sel-lex.l @@ -0,0 +1,152 @@ +%{ +/* + * Copyright (c) 2004, 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * 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. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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. + */ + +/* $Id$ */ + +#undef ECHO + +#include +#include +#include +#include +#include "sel.h" +#include "sel-gram.h" +unsigned lineno = 1; + +static char * handle_string(void); +static int lex_input(char *, int); +static void error_message (const char *format, ...); +void yyerror (char *); + +struct hx_expr_input _hx509_expr_input; + +#define YY_NO_UNPUT 1 + +#undef YY_INPUT +#define YY_INPUT(buf,res,maxsize) (res = lex_input(buf, maxsize)) + +#undef ECHO + +%} +%% + +TRUE { return kw_TRUE; } +FALSE { return kw_FALSE; } +AND { return kw_AND; } +OR { return kw_OR; } +IN { return kw_IN; } +TAILMATCH { return kw_TAILMATCH; } + +[A-Za-z][-A-Za-z0-9_]* { + yylval.string = strdup ((const char *)yytext); + return IDENTIFIER; + } +"\"" { yylval.string = handle_string(); return STRING; } +\n { ++lineno; } +[,.!={}()%] { return *yytext; } +[ \t] ; +%% + +void +error_message (const char *format, ...) +{ + va_list args; + + if (_hx509_expr_input.error) + free(_hx509_expr_input.error); + + va_start (args, format); + vasprintf(&_hx509_expr_input.error, format, args); + va_end (args); +} + +void +yyerror (char *s) +{ + error_message("%s", s); +} + +static char * +handle_string(void) +{ + char x[1024]; + int i = 0; + int c; + int quote = 0; + while((c = input()) != EOF){ + if(quote) { + x[i++] = '\\'; + x[i++] = c; + quote = 0; + continue; + } + if(c == '\n'){ + error_message("unterminated string"); + lineno++; + break; + } + if(c == '\\'){ + quote++; + continue; + } + if(c == '\"') + break; + x[i++] = c; + } + x[i] = '\0'; + return strdup(x); +} + +int +yywrap () +{ + return 1; +} + +static int +lex_input(char *buf, int max_size) +{ + int n; + + n = _hx509_expr_input.length - _hx509_expr_input.offset; + if (max_size < n) + n = max_size; + if (n <= 0) + return YY_NULL; + + memcpy(buf, _hx509_expr_input.buf + _hx509_expr_input.offset, n); + _hx509_expr_input.offset += n; + + return n; +} diff --git a/lib/hx509/sel.c b/lib/hx509/sel.c new file mode 100644 index 000000000..86a5eca7a --- /dev/null +++ b/lib/hx509/sel.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * 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. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 "hx_locl.h" + +struct hx_expr * +_hx509_make_expr(enum hx_expr_op op, void *arg1, void *arg2) +{ + struct hx_expr *expr; + + expr = malloc(sizeof(*expr)); + if (expr == NULL) + return NULL; + expr->op = op; + expr->arg1 = arg1; + expr->arg2 = arg2; + + return expr; +} + +static const char * +eval_word(hx509_context context, hx509_env env, struct hx_expr *word) +{ + switch (word->op) { + case expr_STRING: + return word->arg1; + case expr_VAR: + if (word->arg2 == NULL) + return hx509_env_find(context, env, word->arg1); + + env = hx509_env_find_binding(context, env, word->arg1); + if (env == NULL) + return NULL; + + return eval_word(context, env, word->arg2); + default: + return NULL; + } +} + +static hx509_env +find_variable(hx509_context context, hx509_env env, struct hx_expr *word) +{ + assert(word->op == expr_VAR); + + if (word->arg2 == NULL) + return hx509_env_find_binding(context, env, word->arg1); + + env = hx509_env_find_binding(context, env, word->arg1); + if (env == NULL) + return NULL; + return find_variable(context, env, word->arg2); +} + +static int +eval_comp(hx509_context context, hx509_env env, struct hx_expr *expr) +{ + switch (expr->op) { + case comp_NE: + case comp_EQ: + case comp_TAILEQ: { + const char *s1, *s2; + int ret; + + s1 = eval_word(context, env, expr->arg1); + s2 = eval_word(context, env, expr->arg2); + + if (s1 == NULL || s2 == NULL) + return FALSE; + + if (expr->op == comp_TAILEQ) { + size_t len1 = strlen(s1); + size_t len2 = strlen(s2); + + if (len1 < len2) + return 0; + ret = strcmp(s1 + (len1 - len2), s2) == 0; + } else { + ret = strcmp(s1, s2) == 0; + if (expr->op == comp_NE) + ret = !ret; + } + return ret; + } + case comp_IN: { + struct hx_expr *subexpr; + const char *w, *s1; + + w = eval_word(context, env, expr->arg1); + + subexpr = expr->arg2; + + if (subexpr->op == expr_WORDS) { + while (subexpr) { + s1 = eval_word(context, env, subexpr->arg1); + if (strcmp(w, s1) == 0) + return TRUE; + subexpr = subexpr->arg2; + } + } else if (subexpr->op == expr_VAR) { + hx509_env subenv; + + subenv = find_variable(context, env, subexpr); + if (subenv == NULL) + return FALSE; + + while (subenv) { + if (subenv->type != env_string) + continue; + if (strcmp(w, subenv->name) == 0) + return TRUE; + if (strcmp(w, subenv->u.string) == 0) + return TRUE; + subenv = subenv->next; + } + + } else + _hx509_abort("hx509 eval IN unknown op: %d", (int)subexpr->op); + + return FALSE; + } + default: + _hx509_abort("hx509 eval expr with unknown op: %d", (int)expr->op); + } + return FALSE; +} + +int +_hx509_eval_expr(hx509_context context, hx509_env env, struct hx_expr *expr) +{ + switch (expr->op) { + case op_TRUE: + return 1; + case op_FALSE: + return 0; + case op_NOT: + return ! _hx509_eval_expr(context, env, expr->arg1); + case op_AND: + return _hx509_eval_expr(context, env, expr->arg1) && + _hx509_eval_expr(context, env, expr->arg2); + case op_OR: + return _hx509_eval_expr(context, env, expr->arg1) || + _hx509_eval_expr(context, env, expr->arg2); + case op_COMP: + return eval_comp(context, env, expr->arg1); + default: + _hx509_abort("hx509 eval expr with unknown op: %d", (int)expr->op); + } +} + +void +_hx509_expr_free(struct hx_expr *expr) +{ + switch (expr->op) { + case expr_STRING: + case expr_NUMBER: + free(expr->arg1); + break; + case expr_WORDS: + case expr_FUNCTION: + case expr_VAR: + free(expr->arg1); + if (expr->arg2) + _hx509_expr_free(expr->arg2); + break; + default: + if (expr->arg1) + _hx509_expr_free(expr->arg1); + if (expr->arg2) + _hx509_expr_free(expr->arg2); + break; + } + free(expr); +} + +struct hx_expr * +_hx509_expr_parse(const char *buf) +{ + _hx509_expr_input.buf = buf; + _hx509_expr_input.length = strlen(buf); + _hx509_expr_input.offset = 0; + _hx509_expr_input.expr = NULL; + + if (_hx509_expr_input.error) { + free(_hx509_expr_input.error); + _hx509_expr_input.error = NULL; + } + + yyparse(); + + return _hx509_expr_input.expr; +} diff --git a/lib/hx509/sel.h b/lib/hx509/sel.h new file mode 100644 index 000000000..782d266fa --- /dev/null +++ b/lib/hx509/sel.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * 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. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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. + */ + +enum hx_expr_op { + op_TRUE, + op_FALSE, + op_NOT, + op_AND, + op_OR, + op_COMP, + + comp_EQ, + comp_NE, + comp_IN, + comp_TAILEQ, + + expr_NUMBER, + expr_STRING, + expr_FUNCTION, + expr_VAR, + expr_WORDS +}; + +struct hx_expr { + enum hx_expr_op op; + void *arg1; + void *arg2; +}; + +struct hx_expr_input { + const char *buf; + size_t length; + size_t offset; + struct hx_expr *expr; + char *error; +}; + +extern struct hx_expr_input _hx509_expr_input; + +int yyparse(void); diff --git a/lib/hx509/test_expr.c b/lib/hx509/test_expr.c new file mode 100644 index 000000000..52e93c13f --- /dev/null +++ b/lib/hx509/test_expr.c @@ -0,0 +1,85 @@ + +#include "hx_locl.h" +#include + +struct foo { + int val; + char *str; +} foo[] = { + { 0, "FALSE" }, + { 1, "TRUE" }, + { 0, "!TRUE" }, + { 0, "! TRUE" }, + { 0, "!\tTRUE" }, + { 0, "( FALSE AND FALSE )" }, + { 0, "( TRUE AND FALSE )" }, + { 1, "( TRUE AND TRUE )" }, + { 1, "( TRUE OR TRUE )" }, + { 1, "( TRUE OR FALSE )" }, + { 0, "( FALSE OR FALSE )" }, + { 1, "! ( FALSE OR FALSE )" }, + + { 1, "\"foo\" TAILMATCH \"foo\"" }, + { 1, "\"foobar\" TAILMATCH \"bar\"" }, + { 0, "\"foobar\" TAILMATCH \"foo\"" }, + + { 1, "\"foo\" == \"foo\"" }, + { 0, "\"foo\" == \"bar\"" }, + { 0, "\"foo\" != \"foo\"" }, + { 1, "\"foo\" != \"bar\"" }, + { 1, "%{variable} == \"foo\"" }, + { 0, "%{variable} == \"bar\"" }, + { 1, "%{context.variable} == \"foo\"" }, + { 0, "%{context.variable} == \"bar\"" }, + { 1, "\"foo\" IN ( \"bar\", \"foo\")" }, + { 0, "\"foo\" IN ( \"bar\", \"baz\")" }, + { 0, "\"bar\" IN %{context}" }, + { 1, "\"foo\" IN %{context}" }, + { 1, "\"variable\" IN %{context}" }, + + { 1, "\"foo\" IN %{context} AND %{context.variable} == \"foo\"" } +}; + +int +main(int argc, char **argv) +{ + struct hx_expr *expr; + hx509_context context; + hx509_env env = NULL, env2 = NULL; + int val, i, ret; + +#if 0 + extern int yydebug; + yydebug = 1; +#endif + + ret = hx509_context_init(&context); + if (ret) + errx(1, "hx509_context_init failed with %d", ret); + + hx509_env_add(context, &env, "variable", "foo"); + hx509_env_add(context, &env2, "variable", "foo"); + hx509_env_add_binding(context, &env, "context", env2); + + for (i = 0; i < sizeof(foo)/sizeof(foo[0]); i++) { + + expr = _hx509_expr_parse(foo[i].str); + if (expr == NULL) + errx(1, "_hx509_expr_parse failed for %d: %s", i, foo[i].str); + + val = _hx509_eval_expr(context, env, expr); + if (foo[i].val) { + if (val == 0) + errx(1, "_hx509_eval_expr not true when it should: %d: %s", + i, foo[i].str); + } else { + if (val) + errx(1, "_hx509_eval_expr true when it should not: %d: %s", + i, foo[i].str); + } + } + + hx509_env_free(&env); + + return 0; +} diff --git a/lib/hx509/test_name.c b/lib/hx509/test_name.c index 1e21e3692..7326fe632 100644 --- a/lib/hx509/test_name.c +++ b/lib/hx509/test_name.c @@ -72,13 +72,12 @@ test_name_fail(hx509_context context, const char *name) static int test_expand(hx509_context context, const char *name, const char *expected) { - hx509_env env; + hx509_env env = NULL; hx509_name n; char *s; int ret; - hx509_env_init(context, &env); - hx509_env_add(context, env, "uid", "lha"); + hx509_env_add(context, &env, "uid", "lha"); ret = hx509_parse_name(context, name, &n); if (ret) diff --git a/lib/hx509/test_query.in b/lib/hx509/test_query.in index 74acd459a..0ead760a1 100644 --- a/lib/hx509/test_query.in +++ b/lib/hx509/test_query.in @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan +# Copyright (c) 2005 - 2008 Kungliga Tekniska Högskolan # (Royal Institute of Technology, Stockholm, Sweden). # All rights reserved. # @@ -51,7 +51,7 @@ echo "try printing" ${hxtool} print \ --pass=PASS:foobar \ --info --content \ - FILE:$srcdir/data/kdc.crt || exit 1 + FILE:$srcdir/data/kdc.crt >/dev/null 2>/dev/null || exit 1 ${hxtool} print \ --pass=PASS:foobar \ @@ -159,5 +159,39 @@ ${hxtool} query \ --keyEncipherment \ FILE:$srcdir/data/test-ke-only.crt >/dev/null 2>/dev/null && exit 1 -exit 0 +echo "make sure entry is found (eku) in query language" +${hxtool} query \ + --expr='"1.3.6.1.5.2.3.5" IN %{certificate.eku}' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 +echo "make sure entry is not found (eku) in query language" +${hxtool} query \ + --expr='"1.3.6.1.5.2.3.6" IN %{certificate.eku}' \ + FILE:$srcdir/data/kdc.crt > /dev/null && exit 1 + +echo "make sure entry is found (subject) in query language" +${hxtool} query \ + --expr='%{certificate.subject} == "CN=kdc,C=SE"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +echo "make sure entry is found using TAILMATCH (subject) in query language" +${hxtool} query \ + --expr='%{certificate.subject} TAILMATCH "C=SE"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +echo "make sure entry is not found using TAILMATCH (subject) in query language" +${hxtool} query \ + --expr='%{certificate.subject} TAILMATCH "C=FI"' \ + FILE:$srcdir/data/kdc.crt > /dev/null && exit 1 + +echo "make sure entry is found (issuer) in query language" +${hxtool} query \ + --expr='%{certificate.issuer} == "C=SE,CN=hx509 Test Root CA"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +echo "make sure entry match with EKU and TAILMATCH in query language" +${hxtool} query \ + --expr='"1.3.6.1.5.2.3.5" IN %{certificate.eku} AND %{certificate.subject} TAILMATCH "C=SE"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +exit 0