summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES4
-rw-r--r--crypto/build.info2
-rw-r--r--crypto/err/err_all.c4
-rw-r--r--crypto/err/openssl.ec1
-rw-r--r--crypto/lhash/lhash.c12
-rw-r--r--crypto/property/README87
-rw-r--r--crypto/property/build.info3
-rw-r--r--crypto/property/defn_cache.c105
-rw-r--r--crypto/property/properties.ebnf17
-rw-r--r--crypto/property/properties.xhtml685
-rw-r--r--crypto/property/property.c508
-rw-r--r--crypto/property/property_lcl.h51
-rw-r--r--crypto/property/property_parse.c545
-rw-r--r--crypto/property/property_string.c137
-rw-r--r--crypto/sparse_array.c2
-rw-r--r--doc/internal/man3/OSSL_METHOD_STORE.pod103
-rw-r--r--doc/man3/OPENSSL_LH_COMPFUNC.pod11
-rw-r--r--include/internal/property.h35
-rw-r--r--include/openssl/err.h2
-rw-r--r--include/openssl/lhash.h5
-rw-r--r--include/openssl/stack.h2
-rw-r--r--test/build.info6
-rw-r--r--test/property_test.c374
-rw-r--r--test/recipes/03-test_property.t12
-rw-r--r--test/sparse_array_test.c2
25 files changed, 2705 insertions, 10 deletions
diff --git a/CHANGES b/CHANGES
index cca9ed9b80..5fcf667736 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,10 @@
Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
+ *) Added property based algorithm implementation selection framework to
+ the core.
+ [Paul Dale]
+
*) Added SCA hardening for modular field inversion in EC_GROUP through
a new dedicated field_inv() pointer in EC_METHOD.
This also addresses a leakage affecting conversions from projective
diff --git a/crypto/build.info b/crypto/build.info
index fc0050ea4e..94ed06e65f 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -1,7 +1,7 @@
# Note that these directories are filtered in Configure. Look for %skipdir
# there for further explanations.
SUBDIRS=objects buffer bio stack lhash rand evp asn1 pem x509 x509v3 conf \
- txt_db pkcs7 pkcs12 ui kdf store \
+ txt_db pkcs7 pkcs12 ui kdf store property \
md2 md4 md5 sha mdc2 gmac hmac ripemd whrlpool poly1305 blake2 \
siphash sm3 des aes rc2 rc4 rc5 idea aria bf cast camellia \
seed sm4 chacha modes bn ec rsa dsa dh sm2 dso engine \
diff --git a/crypto/err/err_all.c b/crypto/err/err_all.c
index 3911ecc5c9..4bf020c281 100644
--- a/crypto/err/err_all.c
+++ b/crypto/err/err_all.c
@@ -39,6 +39,7 @@
#include <openssl/kdferr.h>
#include <openssl/storeerr.h>
#include <openssl/esserr.h>
+#include "internal/propertyerr.h"
int err_load_crypto_strings_int(void)
{
@@ -96,7 +97,8 @@ int err_load_crypto_strings_int(void)
ERR_load_ASYNC_strings() == 0 ||
#endif
ERR_load_KDF_strings() == 0 ||
- ERR_load_OSSL_STORE_strings() == 0)
+ ERR_load_OSSL_STORE_strings() == 0 ||
+ ERR_load_PROP_strings() == 0)
return 0;
return 1;
diff --git a/crypto/err/openssl.ec b/crypto/err/openssl.ec
index 94d46d067b..901a847d29 100644
--- a/crypto/err/openssl.ec
+++ b/crypto/err/openssl.ec
@@ -35,6 +35,7 @@ L KDF include/openssl/kdf.h crypto/kdf/kdf_err.c
L SM2 crypto/include/internal/sm2.h crypto/sm2/sm2_err.c
L OSSL_STORE include/openssl/store.h crypto/store/store_err.c
L ESS include/openssl/ess.h crypto/ess/ess_err.c
+L PROP include/internal/property.h crypto/property/property_err.c
# additional header files to be scanned for function names
L NONE include/openssl/x509_vfy.h NONE
diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c
index c826039807..aa0ca1c957 100644
--- a/crypto/lhash/lhash.c
+++ b/crypto/lhash/lhash.c
@@ -75,6 +75,16 @@ err:
void OPENSSL_LH_free(OPENSSL_LHASH *lh)
{
+ if (lh == NULL)
+ return;
+
+ OPENSSL_LH_flush(lh);
+ OPENSSL_free(lh->b);
+ OPENSSL_free(lh);
+}
+
+void OPENSSL_LH_flush(OPENSSL_LHASH *lh)
+{
unsigned int i;
OPENSSL_LH_NODE *n, *nn;
@@ -89,8 +99,6 @@ void OPENSSL_LH_free(OPENSSL_LHASH *lh)
n = nn;
}
}
- OPENSSL_free(lh->b);
- OPENSSL_free(lh);
}
void *OPENSSL_LH_insert(OPENSSL_LHASH *lh, void *data)
diff --git a/crypto/property/README b/crypto/property/README
new file mode 100644
index 0000000000..b3f56cfa2f
--- /dev/null
+++ b/crypto/property/README
@@ -0,0 +1,87 @@
+Properties are associated with algorithms and are used to select between different implementations dynamically.
+
+This implementation is based on a number of assumptions:
+
+* Property definition is uncommon. I.e. providers will be loaded and
+ unloaded relatively infrequently, if at all.
+
+* The number of distinct property names will be small.
+
+* Providers will often give the same implementation properties to most or
+ all of their implemented algorithms. E.g. the FIPS property would be set
+ across an entire provider. Likewise for, hardware, accelerated, software,
+ HSM and, perhaps, constant_time.
+
+* There are a lot of algorithm implementations, therefore property
+ definitions should be space efficient. However...
+
+* ... property queries are very common. These must be fast.
+
+* Property queries come from a small set and are reused many times typically.
+ I.e. an application tends to use the same set of queries over and over,
+ rather than spanning a wide variety of queries.
+
+* Property queries can never add new property definitions.
+
+
+Some consequences of these assumptions are:
+
+* That definition is uncommon and queries are very common, we can treat
+ the property definitions as almost immutable. Specifically, a query can
+ never change the state of the definitions.
+
+* That definition is uncommon and needs to be space efficient, it will
+ be feasible to use a hash table to contain the names (and possibly also
+ values) of all properties and to reference these instead of duplicating
+ strings. Moreover, such a data structure need not be garbage collected.
+ By converting strings to integers using a structure such as this, string
+ comparison degenerates to integer comparison. Additionally, lists of
+ properties can be sorted by the string index which makes comparisons linear
+ time rather than quadratic time - the O(n log n) sort cost being amortised.
+
+* A cache for property definitions is also viable, if only implementation
+ properties are used and not algorithm properties, or at least these are
+ maintained separately. This cache would be a hash table, indexed by
+ the property definition string, and algorithms with the same properties
+ would share their definition structure. Again, reducing space use.
+
+* A query cache is desirable. This would be a hash table keyed by the
+ algorithm identifier and the entire query string and it would map to
+ the chosen algorithm. When a provider is loaded or unloaded, this cache
+ must be invalidated. The cache will also be invalidated when the global
+ properties are changed as doing so removes the need to index on both the
+ global and requested property strings.
+
+
+The implementation:
+
+* property_lock.c contains some wrapper functions to handle the global
+ lock more easily. The global lock is held for short periods of time with
+ per algorithm locking being used for longer intervals.
+
+* property_string.c contains the string cache which converts property
+ names and values to small integer indices. Names and values are stored in
+ separate hash tables. The two Boolean values, the strings "yes" and "no",
+ are populated as the first two members of the value table. All property
+ names reserved by OpenSSL are also populated here. No functions are
+ provided to convert from an index back to the original string (this can be
+ done by maintaining parallel stacks of strings if required).
+
+* property_parse.c contains the property definition and query parsers.
+ These convert ASCII strings into lists of properties. The resulting
+ lists are sorted by the name index. Some additional utility functions
+ for dealing with property lists are also included: comparison of a query
+ against a definition and merging two queries into a single larger query.
+
+* property.c contains the main APIs for defining and using properties.
+ Algorithms are discovered from their NID and a query string.
+ The results are cached.
+
+ The caching of query results has to be efficient but it must also be robust
+ against a denial of service attack. The cache cannot be permitted to grow
+ without bounds and must garbage collect under-used entries. The garbage
+ collection does not have to be exact.
+
+* defn_cache.c contains a cache that maps property definition strings to
+ parsed properties. It is used by property.c to improve performance when
+ the same definition appears multiple times.
diff --git a/crypto/property/build.info b/crypto/property/build.info
new file mode 100644
index 0000000000..3a86b6e141
--- /dev/null
+++ b/crypto/property/build.info
@@ -0,0 +1,3 @@
+LIBS=../../libcrypto
+SOURCE[../../libcrypto]=property_string.c property_parse.c property.c \
+ property_err.c defn_cache.c
diff --git a/crypto/property/defn_cache.c b/crypto/property/defn_cache.c
new file mode 100644
index 0000000000..df87c19f55
--- /dev/null
+++ b/crypto/property/defn_cache.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include "internal/propertyerr.h"
+#include "internal/property.h"
+#include "property_lcl.h"
+
+/*
+ * Implement a property definition cache.
+ * These functions assume that they are called under a write lock.
+ * No attempt is made to clean out the cache, except when it is shut down.
+ */
+
+typedef struct {
+ const char *prop;
+ OSSL_PROPERTY_LIST *defn;
+ char body[1];
+} PROPERTY_DEFN_ELEM;
+
+DEFINE_LHASH_OF(PROPERTY_DEFN_ELEM);
+
+static LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns = NULL;
+
+static unsigned long property_defn_hash(const PROPERTY_DEFN_ELEM *a)
+{
+ return OPENSSL_LH_strhash(a->prop);
+}
+
+static int property_defn_cmp(const PROPERTY_DEFN_ELEM *a,
+ const PROPERTY_DEFN_ELEM *b)
+{
+ return strcmp(a->prop, b->prop);
+}
+
+static void property_defn_free(PROPERTY_DEFN_ELEM *elem)
+{
+ ossl_property_free(elem->defn);
+ OPENSSL_free(elem);
+}
+
+int ossl_prop_defn_init(void)
+{
+ property_defns = lh_PROPERTY_DEFN_ELEM_new(&property_defn_hash,
+ &property_defn_cmp);
+ return property_defns != NULL;
+}
+
+void ossl_prop_defn_cleanup(void)
+{
+ if (property_defns != NULL) {
+ lh_PROPERTY_DEFN_ELEM_doall(property_defns, &property_defn_free);
+ lh_PROPERTY_DEFN_ELEM_free(property_defns);
+ property_defns = NULL;
+ }
+}
+
+OSSL_PROPERTY_LIST *ossl_prop_defn_get(const char *prop)
+{
+ PROPERTY_DEFN_ELEM elem, *r;
+
+ elem.prop = prop;
+ r = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem);
+ return r != NULL ? r->defn : NULL;
+}
+
+int ossl_prop_defn_set(const char *prop, OSSL_PROPERTY_LIST *pl)
+{
+ PROPERTY_DEFN_ELEM elem, *old, *p = NULL;
+ size_t len;
+
+ if (prop == NULL)
+ return 1;
+
+ if (pl == NULL) {
+ elem.prop = prop;
+ lh_PROPERTY_DEFN_ELEM_delete(property_defns, &elem);
+ return 1;
+ }
+ len = strlen(prop);
+ p = OPENSSL_malloc(sizeof(*p) + len);
+ if (p != NULL) {
+ p->prop = p->body;
+ p->defn = pl;
+ memcpy(p->body, prop, len + 1);
+ old = lh_PROPERTY_DEFN_ELEM_insert(property_defns, p);
+ if (old != NULL) {
+ property_defn_free(old);
+ return 1;
+ }
+ if (!lh_PROPERTY_DEFN_ELEM_error(property_defns))
+ return 1;
+ }
+ OPENSSL_free(p);
+ return 0;
+}
diff --git a/crypto/property/properties.ebnf b/crypto/property/properties.ebnf
new file mode 100644
index 0000000000..9a6857f751
--- /dev/null
+++ b/crypto/property/properties.ebnf
@@ -0,0 +1,17 @@
+(* https://bottlecaps.de/rr/ui *)
+
+Definition
+ ::= PropertyName ( '=' Value )? ( ',' PropertyName ( '=' Value )? )*
+Query ::= ( '-'? PropertyName | PropertyName ( '=' | '!=' ) Value )
+ ( ',' ( '-'? PropertyName | PropertyName ( '=' | '!=' ) Value ) )*
+Value ::= NumberLiteral
+ | StringLiteral
+StringLiteral ::= QuotedString | UnquotedString
+QuotedString ::= '"' [^"]* '"'
+ | "'" [^']* "'"
+UnquotedString ::= [^{space},]+
+NumberLiteral
+ ::= '0' ( [0-7]* | 'x' [0-9A-Fa-f]+ )
+ | '-'? [1-9] [0-9]+
+PropertyName
+ ::= [A-Z] [A-Z0-9_]* ( '.' [A-Z] [A-Z0-9_]* )*
diff --git a/crypto/property/properties.xhtml b/crypto/property/properties.xhtml
new file mode 100644
index 0000000000..33827226c0
--- /dev/null
+++ b/crypto/property/properties.xhtml
@@ -0,0 +1,685 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+ <meta name="generator" content="Railroad Diagram Generator 1.56.1774" />
+ <style type="text/css">
+ ::-moz-selection
+ {
+ color: #FFFCF0;
+ background: #0F0C00;
+ }
+ ::selection
+ {
+ color: #FFFCF0;
+ background: #0F0C00;
+ }
+ .ebnf a, .grammar a
+ {
+ text-decoration: none;
+ }
+ .ebnf a:hover, .grammar a:hover
+ {
+ color: #050400;
+ text-decoration: underline;
+ }
+ .signature
+ {
+ color: #806600;
+ font-size: 11px;
+ text-align: right;
+ }
+ body
+ {
+ font: normal 12px Verdana, sans-serif;
+ color: #0F0C00;
+ background: #FFFCF0;
+ }
+ a:link, a:visited
+ {
+ color: #0F0C00;
+ }
+ a:link.signature, a:visited.signature
+ {
+ color: #806600;
+ }
+ a.button, #tabs li a
+ {
+ padding: 0.25em 0.5em;
+ border: 1px solid #806600;
+ background: #F1E8C6;
+ color: #806600;
+ text-decoration: none;
+ font-weight: bold;
+ }
+ a.button:hover, #tabs li a:hover
+ {
+ color: #050400;
+ background: #FFF6D1;
+ border-color: #050400;
+ }
+ #tabs
+ {
+ padding: 3px 10px;
+ margin-left: 0;
+ margin-top: 58px;
+ border-bottom: 1px solid #0F0C00;
+ }
+ #tabs li
+ {
+ list-style: none;
+ margin-left: 5px;
+ display: inline;
+ }
+ #tabs li a
+ {
+ border-bottom: 1px solid #0F0C00;
+ }
+ #tabs li a.active
+ {
+ color: #0F0C00;
+ background: #FFFCF0;
+ border-color: #0F0C00;
+ border-bottom: 1px solid #FFFCF0;
+ outline: none;
+ }
+ #divs div
+ {
+ display: none;
+ overflow:auto;
+ }
+ #divs div.active
+ {
+ display: block;
+ }
+ #text
+ {
+ border-color: #806600;
+ background: #FFFEFA;
+ color: #050400;
+ }
+ .small
+ {
+ vertical-align: top;
+ text-align: right;
+ font-size: 9px;
+ font-weight: normal;
+ line-height: 120%;
+ }
+ td.small
+ {
+ padding-top: 0px;
+ }
+ .hidden
+ {
+ visibility: hidden;
+ }
+ td:hover .hidden
+ {
+ visibility: visible;
+ }
+ div.download
+ {
+ display: none;
+ background: #FFFCF0;
+ position: absolute;
+ right: 34px;
+ top: 94px;
+ padding: 10px;
+ border: 1px dotted #0F0C00;
+ }
+ #divs div.ebnf, .ebnf code
+ {
+ display: block;
+ padding: 10px;
+ background: #FFF6D1;
+ width: 1000px;
+ }
+ #divs div.grammar
+ {
+ display: block;
+ padding-left: 16px;
+ padding-top: 2px;
+ padding-bottom: 2px;
+ background: #FFF6D1;
+ }
+ pre
+ {
+ margin: 0px;
+ }
+ .ebnf div
+ {
+ padding-left: 13ch;
+ text-indent: -13ch;
+ }
+ .ebnf code, .grammar code, textarea, pre
+ {
+ font:12px SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace;
+ }
+ tr.option-line td:first-child
+ {
+ text-align: right
+ }
+ tr.option-text td
+ {
+ padding-bottom: 10px
+ }
+ table.palette
+ {
+ border-top: 1px solid #050400;
+ border-right: 1px solid #050400;
+ margin-bottom: 4px
+ }
+ td.palette
+ {
+ border-bottom: 1px solid #050400;
+ border-left: 1px solid #050400;
+ }
+ a.palette
+ {
+ padding: 2px 3px 2px 10px;
+ text-decoration: none;
+ }
+ .palette
+ {
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ -ms-user-select: none;
+ }
+ </style><svg xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <style type="text/css">
+ @namespace "http://www.w3.org/2000/svg";
+ .line {fill: none; stroke: #332900;}
+ .bold-line {stroke: #141000; shape-rendering: crispEdges; stroke-width: 2; }
+ .thin-line {stroke: #1F1800; shape-rendering: crispEdges}
+ .filled {fill: #332900; stroke: none;}
+ text.terminal {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #141000;
+ font-weight: bold;
+ }
+ text.nonterminal {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #1A1400;
+ font-weight: normal;
+ }
+ text.regexp {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #1F1800;
+ font-weight: normal;
+ }
+ rect, circle, polygon {fill: #332900; stroke: #332900;}
+ rect.terminal {fill: #FFDB4D; stroke: #332900;}
+ rect.nonterminal {fill: #FFEC9E; stroke: #332900;}
+ rect.text {fill: none; stroke: none;}
+ polygon.regexp {fill: #FFF4C7; stroke: #332900;}
+ </style>
+ </defs></svg></head>
+ <body>
+ <xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><xhtml:a name="Definition">Definition:</xhtml:a></xhtml:p><svg xmlns="http://www.w3.org/2000/svg" width="375" height="113">
+ <defs>
+ <style type="text/css">
+ @namespace "http://www.w3.org/2000/svg";
+ .line {fill: none; stroke: #332900;}
+ .bold-line {stroke: #141000; shape-rendering: crispEdges; stroke-width: 2; }
+ .thin-line {stroke: #1F1800; shape-rendering: crispEdges}
+ .filled {fill: #332900; stroke: none;}
+ text.terminal {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #141000;
+ font-weight: bold;
+ }
+ text.nonterminal {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #1A1400;
+ font-weight: normal;
+ }
+ text.regexp {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #1F1800;
+ font-weight: normal;
+ }
+ rect, circle, polygon {fill: #332900; stroke: #332900;}
+ rect.terminal {fill: #FFDB4D; stroke: #332900;}
+ rect.nonterminal {fill: #FFEC9E; stroke: #332900;}
+ rect.text {fill: none; stroke: none;}
+ polygon.regexp {fill: #FFF4C7; stroke: #332900;}
+ </style>
+ </defs>
+ <polygon points="9 61 1 57 1 65"/>
+ <polygon points="17 61 9 57 9 65"/><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#PropertyName" xlink:title="PropertyName">
+ <rect x="51" y="47" width="110" height="32"/>
+ <rect x="49" y="45" width="110" height="32" class="nonterminal"/>
+ <text class="nonterminal" x="59" y="65">PropertyName</text></a><rect x="201" y="79" width="30" height="32" rx="10"/>
+ <rect x="199" y="77" width="30" height="32" class="terminal" rx="10"/>
+ <text class="terminal" x="209" y="97">=</text><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Value" xlink:title="Value">
+ <rect x="251" y="79" width="56" height="32"/>
+ <rect x="249" y="77" width="56" height="32" class="nonterminal"/>
+ <text class="nonterminal" x="259" y="97">Value</text></a><rect x="51" y="3" width="24" height="32" rx="10"/>
+ <rect x="49" y="1" width="24" height="32" class="terminal" rx="10"/>
+ <text class="terminal" x="59" y="21">,</text>
+ <svg:path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 61 h2 m20 0 h10 m110 0 h10 m20 0 h10 m0 0 h116 m-146 0 h20 m126 0 h20 m-166 0 q10 0 10 10 m146 0 q0 -10 10 -10 m-156 10 v12 m146 0 v-12 m-146 12 q0 10 10 10 m126 0 q10 0 10 -10 m-136 10 h10 m30 0 h10 m0 0 h10 m56 0 h10 m-296 -32 l20 0 m-1 0 q-9 0 -9 -10 l0 -24 q0 -10 10 -10 m296 44 l20 0 m-20 0 q10 0 10 -10 l0 -24 q0 -10 -10 -10 m-296 0 h10 m24 0 h10 m0 0 h252 m23 44 h-3"/>
+ <polygon points="365 61 373 57 373 65"/>
+ <polygon points="365 61 357 57 357 65"/></svg><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
+ <xhtml:div class="ebnf"><xhtml:code>
+ <div><a href="#Definition" title="Definition">Definition</a></div>
+ <div>         ::= <a href="#PropertyName" title="PropertyName">PropertyName</a> ( '=' <a href="#Value" title="Value">Value</a> )? ( ',' <a href="#PropertyName" title="PropertyName">PropertyName</a> ( '=' <a href="#Value" title="Value">Value</a> )? )*</div></xhtml:code></xhtml:div>
+ </xhtml:p>
+ <xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">no references</xhtml:p><xhtml:br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><xhtml:a name="Query">Query:</xhtml:a></xhtml:p><svg xmlns="http://www.w3.org/2000/svg" width="419" height="201">
+ <defs>
+ <style type="text/css">
+ @namespace "http://www.w3.org/2000/svg";
+ .line {fill: none; stroke: #332900;}
+ .bold-line {stroke: #141000; shape-rendering: crispEdges; stroke-width: 2; }
+ .thin-line {stroke: #1F1800; shape-rendering: crispEdges}
+ .filled {fill: #332900; stroke: none;}
+ text.terminal {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #141000;
+ font-weight: bold;
+ }
+ text.nonterminal {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #1A1400;
+ font-weight: normal;
+ }
+ text.regexp {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #1F1800;
+ font-weight: normal;
+ }
+ rect, circle, polygon {fill: #332900; stroke: #332900;}
+ rect.terminal {fill: #FFDB4D; stroke: #332900;}
+ rect.nonterminal {fill: #FFEC9E; stroke: #332900;}
+ rect.text {fill: none; stroke: none;}
+ polygon.regexp {fill: #FFF4C7; stroke: #332900;}
+ </style>
+ </defs>
+ <polygon points="9 61 1 57 1 65"/>
+ <polygon points="17 61 9 57 9 65"/>
+ <rect x="91" y="79" width="26" height="32" rx="10"/>
+ <rect x="89" y="77" width="26" height="32" class="terminal" rx="10"/>
+ <text class="terminal" x="99" y="97">-</text><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#PropertyName" xlink:title="PropertyName">
+ <rect x="157" y="47" width="110" height="32"/>
+ <rect x="155" y="45" width="110" height="32" class="nonterminal"/>
+ <text class="nonterminal" x="165" y="65">PropertyName</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#PropertyName" xlink:title="PropertyName">
+ <rect x="71" y="123" width="110" height="32"/>
+ <rect x="69" y="121" width="110" height="32" class="nonterminal"/>
+ <text class="nonterminal" x="79" y="141">PropertyName</text></a><rect x="221" y="123" width="30" height="32" rx="10"/>
+ <rect x="219" y="121" width="30" height="32" class="terminal" rx="10"/>
+ <text class="terminal" x="229" y="141">=</text>
+ <rect x="221" y="167" width="34" height="32" rx="10"/>
+ <rect x="219" y="165" width="34" height="32" class="terminal" rx="10"/>
+ <text class="terminal" x="229" y="185">!=</text><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Value" xlink:title="Value">
+ <rect x="295" y="123" width="56" height="32"/>
+ <rect x="293" y="121" width="56" height="32" class="nonterminal"/>
+ <text class="nonterminal" x="303" y="141">Value</text></a><rect x="51" y="3" width="24" height="32" rx="10"/>
+ <rect x="49" y="1" width="24" height="32" class="terminal" rx="10"/>
+ <text class="terminal" x="59" y="21">,</text>
+ <svg:path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 61 h2 m60 0 h10 m0 0 h36 m-66 0 h20 m46 0 h20 m-86 0 q10 0 10 10 m66 0 q0 -10 10 -10 m-76 10 v12 m66 0 v-12 m-66 12 q0 10 10 10 m46 0 q10 0 10 -10 m-56 10 h10 m26 0 h10 m20 -32 h10 m110 0 h10 m0 0 h84 m-320 0 h20 m300 0 h20 m-340 0 q10 0 10 10 m320 0 q0 -10 10 -10 m-330 10 v56 m320 0 v-56 m-320 56 q0 10 10 10 m300 0 q10 0 10 -10 m-310 10 h10 m110 0 h10 m20 0 h10 m30 0 h10 m0 0 h4 m-74 0 h20 m54 0 h20 m-94 0 q10 0 10 10 m74 0 q0 -10 10 -10 m-84 10 v24 m74 0 v-24 m-74 24 q0 10 10 10 m54 0 q10 0 10 -10 m-64 10 h10 m34 0 h10 m20 -44 h10 m56 0 h10 m-340 -76 l20 0 m-1 0 q-9 0 -9 -10 l0 -24 q0 -10 10 -10 m340 44 l20 0 m-20 0 q10 0 10 -10 l0 -24 q0 -10 -10 -10 m-340 0 h10 m24 0 h10 m0 0 h296 m23 44 h-3"/>
+ <polygon points="409 61 417 57 417 65"/>
+ <polygon points="409 61 401 57 401 65"/></svg><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
+ <xhtml:div class="ebnf"><xhtml:code>
+ <div><a href="#Query" title="Query">Query</a>    ::= ( '-'? <a href="#PropertyName" title="PropertyName">PropertyName</a> | <a href="#PropertyName" title="PropertyName">PropertyName</a> ( '=' | '!=' ) <a href="#Value" title="Value">Value</a> ) ( ',' ( '-'? <a href="#PropertyName" title="PropertyName">PropertyName</a> | <a href="#PropertyName" title="PropertyName">PropertyName</a> ( '=' | '!=' ) <a href="#Value" title="Value">Value</a> ) )*</div></xhtml:code></xhtml:div>
+ </xhtml:p>
+ <xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">no references</xhtml:p><xhtml:br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><xhtml:a name="Value">Value:</xhtml:a></xhtml:p><svg xmlns="http://www.w3.org/2000/svg" width="207" height="81">
+ <defs>
+ <style type="text/css">
+ @namespace "http://www.w3.org/2000/svg";
+ .line {fill: none; stroke: #332900;}
+ .bold-line {stroke: #141000; shape-rendering: crispEdges; stroke-width: 2; }
+ .thin-line {stroke: #1F1800; shape-rendering: crispEdges}
+ .filled {fill: #332900; stroke: none;}
+ text.terminal {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #141000;
+ font-weight: bold;
+ }
+ text.nonterminal {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #1A1400;
+ font-weight: normal;
+ }
+ text.regexp {font-family: Verdana, Sans-serif;
+ font-size: 12px;
+ fill: #1F1800;
+ font-weight: normal;
+ }
+ rect, circle, polygon {fill: #332900; stroke: #332900;}
+ rect.terminal {fill: #FFDB4D; stroke: #332900;}
+ rect.nonterminal {fill: #FFEC9E; stroke: #332900;}
+ rect.text {fill: none; stroke: none;}
+ polygon.regexp {fill: #FFF4C7; stroke: #332900;}
+ </style>
+ </defs>
+ <polygon points="9 17 1 13 1 21"/>
+ <polygon points="17 17 9 13 9 21"/><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#NumberLiteral" xlink:title="NumberLiteral">
+ <rect x="51" y="3" width="108" height="32"/>
+ <rect x="49" y="1" width="108" height="32" class="nonterminal"/>
+ <text class="nonterminal" x="59" y="21">NumberLiteral</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#StringLiteral" xlink:title="StringLiteral">
+ <rect x="51" y="47" width="96" height="32"/>
+ <rect x="49" y="45" width="96" height="32" class="nonterminal"/>
+ <text class="nonterminal" x="59" y="65">StringLiteral</text></a><svg:path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 17 h2 m20 0 h10 m108 0 h10 m-148 0 h20 m128 0 h20 m-168 0 q10 0 10 10 m148 0 q0 -10 10 -10 m-158 10 v24 m148 0 v-24 m-148 24 q0 10 10 10 m128 0 q10 0 10 -10 m-138 10 h10 m96 0 h10 m0 0 h12 m23 -44 h-3"/>
+ <polygon points="197 17 205 13 205 21"/>
+ <polygon points="197 17 189 13 189 21"/></svg><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
+ <xhtml:div class="ebnf"><xhtml:code>
+ <div><a href="#Value" title="Value">Value</a>    ::= <a href="#NumberLiteral" title="NumberLiteral">NumberLiteral</a></div>
+ <div>           | <a href="#StringLiteral" title="StringLiteral">StringLiteral</a></div></xhtml:code></xhtml:div>
+ </xhtml:p>
+ <xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">referenced by:
+ <xhtml:ul>
+ <xhtml:li><xhtml:a href="#Definition" title="Definition">Definition</xhtml:a></xhtml:li>
+ <xhtml:li><xhtml:a href="#Query" title="Query">Query</xhtml:a></xhtml:li>
+ </xhtml:ul>
+ </xhtml:p><xhtml:br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><xhtml:a name="StringLiteral">StringLiteral:</xhtml:a></xhtml:p><svg xmlns="http://www.w3.org/2000/svg" width="219" height="81">
+ <defs>
+ <style type="text/css">
<