Properties for implementation selection.
Properties are a sequence of comma separated name=value pairs. A name without a corresponding value is assumed to be a Boolean and have the true value 'yes'. Values are either strings or numbers. Strings can be quoted either _"_ or _'_ or unquoted (with restrictions). There are no escape characters inside strings. Number are either decimal digits or '0x' followed by hexidecimal digits. Numbers are represented internally as signed sixty four bit values. Queries on properties are a sequence comma separated conditional tests. These take the form of name=value (equality test), name!=value (inequality test) or name (Boolean test for truth). Queries can be parsed, compared against a definition or merged pairwise. Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tim Hudson <tjh@openssl.org> (Merged from https://github.com/openssl/openssl/pull/8224)master
parent
e3ac365489
commit
1bdbdaffdc
4
CHANGES
4
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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -74,6 +74,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)
|
||||
|
|
|
@ -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.
|
|
@ -0,0 +1,3 @@
|
|||
LIBS=../../libcrypto
|
||||
SOURCE[../../libcrypto]=property_string.c property_parse.c property.c \
|
||||
property_err.c 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;
|
||||
}
|
|
@ -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_]* )*
|
|
@ -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">
|
||||
@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="#QuotedString" xlink:title="QuotedString">
|
||||
<rect x="51" y="3" width="104" height="32"/>
|
||||
<rect x="49" y="1" width="104" height="32" class="nonterminal"/>
|
||||
<text class="nonterminal" x="59" y="21">QuotedString</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#UnquotedString" xlink:title="UnquotedString">
|
||||
<rect x="51" y="47" width="120" height="32"/>
|
||||
<rect x="49" y="45" width="120" height="32" class="nonterminal"/>
|
||||
<text class="nonterminal" x="59" y="65">UnquotedString</text></a><svg:path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 17 h2 m20 0 h10 m104 0 h10 m0 0 h16 m-160 0 h20 m140 0 h20 m-180 0 q10 0 10 10 m160 0 q0 -10 10 -10 m-170 10 v24 m160 0 v-24 m-160 24 q0 10 10 10 m140 0 q10 0 10 -10 m-150 10 h10 m120 0 h10 m23 -44 h-3"/>
|
||||
<polygon points="209 17 217 13 217 21"/>
|
||||
<polygon points="209 17 201 13 201 21"/></svg><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<xhtml:div class="ebnf"><xhtml:code>
|
||||
<div><a href="#StringLiteral" title="StringLiteral">StringLiteral</a></div>
|
||||
<div> ::= <a href="#QuotedString" title="QuotedString">QuotedString</a></div>
|
||||
<div> | <a href="#UnquotedString" title="UnquotedString">UnquotedString</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="#Value" title="Value">Value</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="QuotedString">QuotedString:</xhtml:a></xhtml:p><svg xmlns="http://www.w3.org/2000/svg" width="327" height="151">
|
||||
<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 33 1 29 1 37"/>
|
||||
<polygon points="17 33 9 29 9 37"/>
|
||||
<rect x="51" y="19" width="26" height="32" rx="10"/>
|
||||
<rect x="49" y="17" width="26" height="32" class="terminal" rx="10"/>
|
||||
<text class="terminal" x="59" y="37">"</text>
|
||||
<polygon points="137 35 144 19 186 19 193 35 186 51 144 51"/>
|
||||
<polygon points="135 33 142 17 184 17 191 33 184 49 142 49" class="regexp"/>
|
||||
<text class="regexp" x="150" y="37">[^"]</text>
|
||||
<rect x="253" y="19" width="26" height="32" rx="10"/>
|
||||
<rect x="251" y="17" width="26" height="32" class="terminal" rx="10"/>
|
||||
<text class="terminal" x="261" y="37">"</text>
|
||||
<rect x="51" y="101" width="24" height="32" rx="10"/>
|
||||
<rect x="49" y="99" width="24" height="32" class="terminal" rx="10"/>
|
||||
<text class="terminal" x="59" y="119">'</text>
|
||||
<polygon points="135 117 142 101 182 101 189 117 182 133 142 133"/>
|
||||
<polygon points="133 115 140 99 180 99 187 115 180 131 140 131" class="regexp"/>
|
||||
<text class="regexp" x="148" y="119">[^']</text>
|
||||
<rect x="249" y="101" width="24" height="32" rx="10"/>
|
||||
<rect x="247" y="99" width="24" height="32" class="terminal" rx="10"/>
|
||||
<text class="terminal" x="257" y="119">'</text>
|
||||
<svg:path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 33 h2 m20 0 h10 m26 0 h10 m40 0 h10 m56 0 h10 m-96 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -12 q0 -10 10 -10 m76 32 l20 0 m-20 0 q10 0 10 -10 l0 -12 q0 -10 -10 -10 m-76 0 h10 m0 0 h66 m-116 32 h20 m116 0 h20 m-156 0 q10 0 10 10 m136 0 q0 -10 10 -10 m-146 10 v14 m136 0 v-14 m-136 14 q0 10 10 10 m116 0 q10 0 10 -10 m-126 10 h10 m0 0 h106 m20 -34 h10 m26 0 h10 m-268 0 h20 m248 0 h20 m-288 0 q10 0 10 10 m268 0 q0 -10 10 -10 m-278 10 v62 m268 0 v-62 m-268 62 q0 10 10 10 m248 0 q10 0 10 -10 m-258 10 h10 m24 0 h10 m40 0 h10 m54 0 h10 m-94 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -12 q0 -10 10 -10 m74 32 l20 0 m-20 0 q10 0 10 -10 l0 -12 q0 -10 -10 -10 m-74 0 h10 m0 0 h64 m-114 32 h20 m114 0 h20 m-154 0 q10 0 10 10 m134 0 q0 -10 10 -10 m-144 10 v14 m134 0 v-14 m-134 14 q0 10 10 10 m114 0 q10 0 10 -10 m-124 10 h10 m0 0 h104 m20 -34 h10 m24 0 h10 m0 0 h6 m23 -82 h-3"/>
|
||||
<polygon points="317 33 325 29 325 37"/>
|
||||
<polygon points="317 33 309 29 309 37"/></svg><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<xhtml:div class="ebnf"><xhtml:code>
|
||||
<div><a href="#QuotedString" title="QuotedString">QuotedString</a></div>
|
||||
<div> ::= '"' [^"]* '"'</div>
|
||||
<div> | "'" [^']* "'"</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="#StringLiteral" title="StringLiteral">StringLiteral</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="UnquotedString">UnquotedString:</xhtml:a></xhtml:p><svg xmlns="http://www.w3.org/2000/svg" width="207" height="53">
|
||||
<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 33 1 29 1 37"/>
|
||||
<polygon points="17 33 9 29 9 37"/>
|
||||
<polygon points="51 35 58 19 152 19 159 35 152 51 58 51"/>
|
||||
<polygon points="49 33 56 17 150 17 157 33 150 49 56 49" class="regexp"/>
|
||||
<text class="regexp" x="64" y="37">[^{space},]</text>
|
||||
<svg:path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 33 h2 m20 0 h10 m108 0 h10 m-148 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -12 q0 -10 10 -10 m128 32 l20 0 m-20 0 q10 0 10 -10 l0 -12 q0 -10 -10 -10 m-128 0 h10 m0 0 h118 m23 32 h-3"/>
|
||||
<polygon points="197 33 205 29 205 37"/>
|
||||
<polygon points="197 33 189 29 189 37"/></svg><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<xhtml:div class="ebnf"><xhtml:code>
|
||||
<div><a href="#UnquotedString" title="UnquotedString">UnquotedString</a></div>
|
||||
<div> ::= [^{space},]+</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="#StringLiteral" title="StringLiteral">StringLiteral</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="NumberLiteral">NumberLiteral:</xhtml:a></xhtml:p><svg xmlns="http://www.w3.org/2000/svg" width="377" height="305">
|
||||
<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 51 1 47 1 55"/>
|
||||
<polygon points="17 51 9 47 9 55"/>
|
||||
<rect x="51" y="37" width="28" height="32" rx="10"/>
|
||||
<rect x="49" y="35" width="28" height="32" class="terminal" rx="10"/>
|
||||
<text class="terminal" x="59" y="55">0</text>
|
||||
<polygon points="139 19 146 3 194 3 201 19 194 35 146 35"/>
|
||||
<polygon points="137 17 144 1 192 1 199 17 192 33 144 33" class="regexp"/>
|
||||
<text class="regexp" x="152" y="21">[0-7]</text>
|
||||
<rect x="119" y="85" width="28" height="32" rx="10"/>
|
||||
<rect x="117" y="83" width="28" height="32" class="terminal" rx="10"/>
|
||||
<text class="terminal" x="127" y="103">x</text>
|
||||
<polygon points="207 101 214 85 262 85 269 101 262 117 214 117"/>
|
||||
<polygon points="205 99 212 83 260 83 267 99 260 115 212 115" class="regexp"/>
|
||||
<text class="regexp" x="220" y="103">[0-9]</text>
|
||||
<polygon points="207 145 214 129 260 129 267 145 260 161 214 161"/>
|
||||
<polygon points="205 143 212 127 258 127 265 143 258 159 212 159" class="regexp"/>
|
||||
<text class="regexp" x="220" y="147">[A-F]</text>
|
||||
<polygon points="207 189 214 173 258 173 265 189 258 205 214 205"/>
|
||||
<polygon points="205 187 212 171 256 171 263 187 256 203 212 203" class="regexp"/>
|
||||
<text class="regexp" x="220" y="191">[a-f]</text>
|
||||
<rect x="71" y="271" width="26" height="32" rx="10"/>
|
||||
<rect x="69" y="269" width="26" height="32" class="terminal" rx="10"/>
|
||||
<text class="terminal" x="79" y="289">-</text>
|
||||
<polygon points="137 255 144 239 192 239 199 255 192 271 144 271"/>
|
||||
<polygon points="135 253 142 237 190 237 197 253 190 269 142 269" class="regexp"/>
|
||||
<text class="regexp" x="150" y="257">[1-9]</text>
|
||||
<polygon points="239 255 246 239 294 239 301 255 294 271 246 271"/>
|
||||
<polygon points="237 253 244 237 292 237 299 253 292 269 244 269" class="regexp"/>
|
||||
<text class="regexp" x="252" y="257">[0-9]</text>
|
||||
<svg:path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 51 h2 m20 0 h10 m28 0 h10 m40 0 h10 m0 0 h72 m-102 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -14 q0 -10 10 -10 m82 34 l20 0 m-20 0 q10 0 10 -10 l0 -14 q0 -10 -10 -10 m-82 0 h10 m62 0 h10 m20 34 h88 m-230 0 h20 m210 0 h20 m-250 0 q10 0 10 10 m230 0 q0 -10 10 -10 m-240 10 v28 m230 0 v-28 m-230 28 q0 10 10 10 m210 0 q10 0 10 -10 m-220 10 h10 m28 0 h10 m40 0 h10 m62 0 h10 m-102 0 h20 m82 0 h20 m-122 0 q10 0 10 10 m102 0 q0 -10 10 -10 m-112 10 v24 m102 0 v-24 m-102 24 q0 10 10 10 m82 0 q10 0 10 -10 m-92 10 h10 m60 0 h10 m0 0 h2 m-92 -10 v20 m102 0 v-20 m-102 20 v24 m102 0 v-24 m-102 24 q0 10 10 10 m82 0 q10 0 10 -10 m-92 10 h10 m58 0 h10 m0 0 h4 m-122 -88 l20 0 m-1 0 q-9 0 -9 -10 l0 -12 q0 -10 10 -10 m122 32 l20 0 m-20 0 q10 0 10 -10 l0 -12 q0 -10 -10 -10 m-122 0 h10 m0 0 h112 m-278 -16 h20 m298 0 h20 m-338 0 q10 0 10 10 m318 0 q0 -10 10 -10 m-328 10 v182 m318 0 v-182 m-318 182 q0 10 10 10 m298 0 q10 0 10 -10 m-288 10 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 m62 0 h10 m20 0 h10 m62 0 h10 m-102 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -12 q0 -10 10 -10 m82 32 l20 0 m-20 0 q10 0 10 -10 l0 -12 q0 -10 -10 -10 m-82 0 h10 m0 0 h72 m20 32 h8 m23 -202 h-3"/>
|
||||
<polygon points="367 51 375 47 375 55"/>
|
||||
<polygon points="367 51 359 47 359 55"/></svg><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<xhtml:div class="ebnf"><xhtml:code>
|
||||
<div><a href="#NumberLiteral" title="NumberLiteral">NumberLiteral</a></div>
|
||||
<div> ::= '0' ( [0-7]* | 'x' [0-9A-Fa-f]+ )</div>
|
||||
<div> | '-'? [1-9] [0-9]+</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="#Value" title="Value">Value</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="PropertyName">PropertyName:</xhtml:a></xhtml:p><svg xmlns="http://www.w3.org/2000/svg" width="283" height="203">
|
||||
<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 183 1 179 1 187"/>
|
||||
<polygon points="17 183 9 179 9 187"/>
|
||||
<polygon points="51 185 58 169 106 169 113 185 106 201 58 201"/>
|
||||
<polygon points="49 183 56 167 104 167 111 183 104 199 56 199" class="regexp"/>
|
||||
<text class="regexp" x="64" y="187">[A-Z]</text>
|
||||
<polygon points="153 151 160 135 208 135 215 151 208 167 160 167"/>
|
||||
<polygon points="151 149 158 133 206 133 213 149 206 165 158 165" class="regexp"/>
|
||||
<text class="regexp" x="166" y="153">[A-Z]</text>
|
||||
<polygon points="153 107 160 91 208 91 215 107 208 123 160 123"/>
|
||||
<polygon points="151 105 158 89 206 89 213 105 206 121 158 121" class="regexp"/>
|
||||
<text class="regexp" x="166" y="109">[0-9]</text>
|
||||
<rect x="153" y="47" width="28" height="32" rx="10"/>
|
||||
<rect x="151" y="45" width="28" height="32" class="terminal" rx="10"/>
|
||||
<text class="terminal" x="161" y="65">_</text>
|
||||
<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 183 h2 m20 0 h10 m62 0 h10 m20 0 h10 m0 0 h72 m-102 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -14 q0 -10 10 -10 m82 34 l20 0 m-20 0 q10 0 10 -10 l0 -14 q0 -10 -10 -10 m-82 0 h10 m62 0 h10 m-92 10 l0 -44 q0 -10 10 -10 m92 54 l0 -44 q0 -10 -10 -10 m-82 0 h10 m62 0 h10 m-92 10 l0 -44 q0 -10 10 -10 m92 54 l0 -44 q0 -10 -10 -10 m-82 0 h10 m28 0 h10 m0 0 h34 m-204 122 l20 0 m-1 0 q-9 0 -9 -10 l0 -146 q0 -10 10 -10 m204 166 l20 0 m-20 0 q10 0 10 -10 l0 -146 q0 -10 -10 -10 m-204 0 h10 m24 0 h10 m0 0 h160 m23 166 h-3"/>
|
||||
<polygon points="273 183 281 179 281 187"/>
|
||||
<polygon points="273 183 265 179 265 187"/></svg><xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<xhtml:div class="ebnf"><xhtml:code>
|
||||
<div><a href="#PropertyName" title="PropertyName">PropertyName</a></div>
|
||||
<div> ::= [A-Z] [A-Z0-9_]* ( '.' [A-Z] [A-Z0-9_]* )*</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:hr xmlns:xhtml="http://www.w3.org/1999/xhtml" />
|
||||
<xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<xhtml:table class="signature" border="0">
|
||||
<xhtml:tr>
|
||||
<xhtml:td style="width: 100%"> </xhtml:td>
|
||||
<xhtml:td valign="top">
|
||||
<xhtml:nobr class="signature">... generated by <xhtml:a name="Railroad-Diagram-Generator" class="signature" title="https://www.bottlecaps.de/rr/ui" href="https://www.bottlecaps.de/rr/ui" target="_blank">Railroad Diagram Generator</xhtml:a></xhtml:nobr>
|
||||
</xhtml:td>
|
||||
<xhtml:td><xhtml:a name="Railroad-Diagram-Generator" title="https://www.bottlecaps.de/rr/ui" href="https://www.bottlecaps.de/rr/ui" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
|
||||
<g transform="scale(0.178)">
|
||||
<circle cx="45" cy="45" r="45" style="stroke:none; fill:#FFCC00"/>
|
||||
<circle cx="45" cy="45" r="42" style="stroke:#332900; stroke-width:2px; fill:#FFCC00"/>
|
||||
<line x1="15" y1="15" x2="75" y2="75" stroke="#332900" style="stroke-width:9px;"/>
|
||||
<line x1="15" y1="75" x2="75" y2="15" stroke="#332900" style="stroke-width:9px;"/>
|
||||
<text x="7" y="54" style="font-size:26px; font-family:Arial, Sans-serif; font-weight:bold; fill: #332900">R</text>
|
||||
<text x="64" y="54" style="font-size:26px; font-family:Arial, Sans-serif; font-weight:bold; fill: #332900">R</text>
|
||||
</g></svg></xhtml:a></xhtml:td>
|
||||
</xhtml:tr>
|
||||
</xhtml:table>
|
||||
</xhtml:p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include "internal/property.h"
|
||||
#include "internal/ctype.h"
|
||||
#include <openssl/lhash.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "internal/thread_once.h"
|
||||
#include "internal/lhash.h"
|
||||
#include "internal/sparse_array.h"
|
||||
#include "property_lcl.h"
|
||||
|
||||
/* The number of elements in the query cache before we initiate a flush */
|
||||
#define IMPL_CACHE_FLUSH_THRESHOLD 500
|
||||
|
||||
typedef struct {
|
||||
OSSL_PROPERTY_LIST *properties;
|
||||
void *implementation;
|
||||
void (*implementation_destruct)(void *);
|
||||
} IMPLEMENTATION;
|
||||
|
||||
DEFINE_STACK_OF(IMPLEMENTATION)
|
||||
|
||||
typedef struct {
|
||||
const char *query;
|
||||
void *result;
|
||||
char body[1];
|
||||
} QUERY;
|
||||
|
||||
DEFINE_LHASH_OF(QUERY);
|
||||
|
||||
typedef struct {
|
||||
int nid;
|
||||
STACK_OF(IMPLEMENTATION) *impls;
|
||||
LHASH_OF(QUERY) *cache;
|
||||
} ALGORITHM;
|
||||
|
||||
struct ossl_method_store_st {
|
||||
size_t nelem;
|
||||
SPARSE_ARRAY_OF(ALGORITHM) *algs;
|
||||
OSSL_PROPERTY_LIST *global_properties;
|
||||
int need_flush;
|
||||
unsigned int nbits;
|
||||
unsigned char rand_bits[(IMPL_CACHE_FLUSH_THRESHOLD + 7) / 8];
|
||||
CRYPTO_RWLOCK *lock;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
OSSL_METHOD_STORE *store;
|
||||
LHASH_OF(QUERY) *cache;
|
||||
size_t nelem;
|
||||
} IMPL_CACHE_FLUSH;
|
||||
|
||||
DEFINE_SPARSE_ARRAY_OF(ALGORITHM);
|
||||
|
||||
static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid);
|
||||
static void ossl_method_cache_flush_all(OSSL_METHOD_STORE *c);
|
||||
|
||||
int ossl_property_read_lock(OSSL_METHOD_STORE *p)
|
||||
{
|
||||
return p != NULL ? CRYPTO_THREAD_read_lock(p->lock) : 0;
|
||||
}
|
||||
|
||||
int ossl_property_write_lock(OSSL_METHOD_STORE *p)
|
||||
{
|
||||
return p != NULL ? CRYPTO_THREAD_write_lock(p->lock) : 0;
|
||||
}
|
||||
|
||||
int ossl_property_unlock(OSSL_METHOD_STORE *p)
|
||||
{
|
||||
return p != 0 ? CRYPTO_THREAD_unlock(p->lock) : 0;
|
||||
}
|
||||
|
||||
int ossl_method_store_init(void)
|
||||
{
|
||||
if (ossl_property_string_init()
|
||||
&& ossl_prop_defn_init()
|
||||
&& ossl_property_parse_init())
|
||||
return 1;
|
||||
|
||||
ossl_method_store_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ossl_method_store_cleanup(void)
|
||||
{
|
||||
ossl_property_string_cleanup();
|
||||
ossl_prop_defn_cleanup();
|
||||
}
|
||||
|
||||
static CRYPTO_ONCE method_store_init_flag = CRYPTO_ONCE_STATIC_INIT;
|
||||
DEFINE_RUN_ONCE_STATIC(do_method_store_init)
|
||||
{
|
||||
return OPENSSL_init_crypto(0, NULL)
|
||||
&& ossl_method_store_init()
|
||||
&& OPENSSL_atexit(&ossl_method_store_cleanup);
|
||||
}
|
||||
|
||||
static unsigned long query_hash(const QUERY *a)
|
||||
{
|
||||
return OPENSSL_LH_strhash(a->query);
|
||||
}
|
||||
|
||||
static int query_cmp(const QUERY *a, const QUERY *b)
|
||||
{
|
||||
return strcmp(a->query, b->query);
|
||||
}
|
||||
|
||||
static void impl_free(IMPLEMENTATION *impl)
|
||||
{
|
||||
if (impl != NULL) {
|
||||
if (impl->implementation_destruct)
|
||||
impl->implementation_destruct(impl->implementation);
|
||||
OPENSSL_free(impl);
|
||||
}
|
||||
}
|
||||
|
||||
static void impl_cache_free(QUERY *elem)
|
||||
{
|
||||
OPENSSL_free(elem);
|
||||
}
|
||||
|
||||
static void alg_cleanup(size_t idx, ALGORITHM *a)
|
||||
{
|
||||
if (a != NULL) {
|
||||
sk_IMPLEMENTATION_pop_free(a->impls, &impl_free);
|
||||
lh_QUERY_doall(a->cache, &impl_cache_free);
|
||||
lh_QUERY_free(a->cache);
|
||||
OPENSSL_free(a);
|
||||
}
|
||||
}
|
||||
|
||||
OSSL_METHOD_STORE *ossl_method_store_new(void)
|
||||
{
|
||||
OSSL_METHOD_STORE *res = OPENSSL_zalloc(sizeof(*res));
|
||||
|
||||
if (!RUN_ONCE(&method_store_init_flag, do_method_store_init))
|
||||
return 0;
|
||||
|
||||
if (res != NULL) {
|
||||
if ((res->algs = ossl_sa_ALGORITHM_new()) == NULL) {
|
||||
OPENSSL_free(res);
|
||||
return NULL;
|
||||
}
|
||||
if ((res->lock = CRYPTO_THREAD_lock_new()) == NULL) {
|
||||
OPENSSL_free(res->algs);
|
||||
OPENSSL_free(res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ossl_method_store_free(OSSL_METHOD_STORE *store)
|
||||
{
|
||||
if (store != NULL) {
|
||||
ossl_sa_ALGORITHM_doall(store->algs, &alg_cleanup);
|
||||
ossl_sa_ALGORITHM_free(store->algs);
|
||||
ossl_property_free(store->global_properties);
|
||||
CRYPTO_THREAD_lock_free(store->lock);
|
||||
OPENSSL_free(store);
|
||||
}
|
||||
}
|
||||
|
||||
static ALGORITHM *ossl_method_store_retrieve(OSSL_METHOD_STORE *store, int nid)
|
||||
{
|
||||
return ossl_sa_ALGORITHM_get(store->algs, nid);
|
||||
}
|
||||
|
||||
static int ossl_method_store_insert(OSSL_METHOD_STORE *store, ALGORITHM *alg)
|
||||
{
|
||||
return ossl_sa_ALGORITHM_set(store->algs, alg->nid, alg);
|
||||
}
|
||||
|
||||
int ossl_method_store_add(OSSL_METHOD_STORE *store,
|
||||
int nid, const char *properties,
|
||||
void *implementation,
|
||||
void (*implementation_destruct)(void *))
|
||||
{
|
||||
ALGORITHM *alg = NULL;
|
||||
IMPLEMENTATION *impl;
|
||||
int ret = 0;
|
||||
|
||||
if (nid <= 0 || implementation == NULL || store == NULL)
|
||||
return 0;
|
||||
if (properties == NULL)
|
||||
properties = "";
|
||||
|
||||
/* Create new entry */
|
||||
impl = OPENSSL_malloc(sizeof(*impl));
|
||||
if (impl == NULL)
|
||||
return 0;
|
||||
impl->implementation = implementation;
|
||||
impl->implementation_destruct = implementation_destruct;
|
||||
|
||||
/*
|
||||
* Insert into the hash table if required.
|
||||
*
|
||||
* A write lock is used unconditionally because we wend our way down to the
|
||||
* property string code which isn't locking friendly.
|
||||
*/
|
||||
ossl_property_write_lock(store);
|
||||
ossl_method_cache_flush(store, nid);
|
||||
if ((impl->properties = ossl_prop_defn_get(properties)) == NULL) {
|
||||
if ((impl->properties = ossl_parse_property(properties)) == NULL)
|
||||
goto err;
|
||||
ossl_prop_defn_set(properties, impl->properties);
|
||||
}
|
||||
|
||||
alg = ossl_method_store_retrieve(store, nid);
|
||||
if (alg == NULL) {
|
||||
if ((alg = OPENSSL_zalloc(sizeof(*alg))) == NULL
|
||||
|| (alg->impls = sk_IMPLEMENTATION_new_null()) == NULL
|
||||
|| (alg->cache = lh_QUERY_new(&query_hash, &query_cmp)) == NULL)
|
||||
goto err;
|
||||
alg->nid = nid;
|
||||
if (!ossl_method_store_insert(store, alg))
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Push onto stack */
|
||||
if (sk_IMPLEMENTATION_push(alg->impls, impl))
|
||||
ret = 1;
|
||||
ossl_property_unlock(store);
|
||||
if (ret == 0)
|
||||
impl_free(impl);
|
||||
return ret;
|
||||
|
||||
err:
|
||||
ossl_property_unlock(store);
|
||||
alg_cleanup(0, alg);
|
||||
impl_free(impl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ossl_method_store_remove(OSSL_METHOD_STORE *store, int nid,
|
||||
const void *implementation)
|
||||
{
|
||||
ALGORITHM *alg = NULL;
|
||||
int i;
|
||||
|
||||
if (nid <= 0 || implementation == NULL || store == NULL)
|
||||
return 0;
|
||||
|
||||
ossl_property_write_lock(store);
|
||||
ossl_method_cache_flush(store, nid);
|
||||
alg = ossl_method_store_retrieve(store, nid);
|
||||
if (alg == NULL) {
|
||||
ossl_property_unlock(store);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A sorting find then a delete could be faster but these stacks should be
|
||||
* relatively small, so we avoid the overhead. Sorting could also surprise
|
||||
* users when result orderings change (even though they are not guaranteed).
|
||||
*/
|
||||
for (i = 0; i < sk_IMPLEMENTATION_num(alg->impls); i++) {
|
||||
IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i);
|
||||
|
||||
if (impl->implementation == implementation) {
|
||||
sk_IMPLEMENTATION_delete(alg->impls, i);
|
||||
ossl_property_unlock(store);
|
||||
impl_free(impl);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
ossl_property_unlock(store);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ossl_method_store_fetch(OSSL_METHOD_STORE *store, int nid,
|
||||
const char *prop_query, void **result)
|
||||
{
|
||||
ALGORITHM *alg;
|
||||
IMPLEMENTATION *impl;
|
||||
OSSL_PROPERTY_LIST *pq = NULL, *p2;
|
||||
int ret = 0;
|
||||
int j;
|
||||
|
||||
if (nid <= 0 || result == NULL || store == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* This only needs to be a read lock, because queries never create property
|
||||
* names or value and thus don't modify any of the property string layer.
|
||||
*/
|
||||
ossl_property_read_lock(store);
|
||||
alg = ossl_method_store_retrieve(store, nid);
|
||||
if (alg == NULL) {
|
||||
ossl_property_unlock(store);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (prop_query == NULL) {
|
||||
if ((impl = sk_IMPLEMENTATION_value(alg->impls, 0)) != NULL) {
|
||||
*result = impl->implementation;
|
||||
ret = 1;
|
||||
}
|
||||
goto fin;
|
||||
}
|
||||
pq = ossl_parse_query(prop_query);
|
||||
if (pq == NULL)
|
||||
goto fin;
|
||||
if (store->global_properties != NULL) {
|
||||
p2 = ossl_property_merge(pq, store->global_properties);
|
||||
if (p2 == NULL)
|
||||
goto fin;
|
||||
ossl_property_free(pq);
|
||||
pq = p2;
|
||||
}
|
||||
for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) {
|
||||
impl = sk_IMPLEMENTATION_value(alg->impls, j);
|
||||
|
||||
if (ossl_property_match(pq, impl->properties)) {
|
||||
*result = impl->implementation;
|
||||
ret = 1;
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
fin:
|
||||
ossl_property_unlock(store);
|
||||
ossl_property_free(pq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ossl_method_store_set_global_properties(OSSL_METHOD_STORE *store,
|
||||
const char *prop_query) {
|
||||
int ret = 0;
|
||||
|
||||
if (store == NULL)
|
||||
return 1;
|
||||
|
||||
ossl_property_write_lock(store);
|
||||
ossl_method_cache_flush_all(store);
|
||||
if (prop_query == NULL) {
|
||||
ossl_property_free(store->global_properties);
|
||||
store->global_properties = NULL;
|
||||
ossl_property_unlock(store);
|
||||
return 1;
|
||||
}
|
||||
store->global_properties = ossl_parse_query(prop_query);
|
||||
ret = store->global_properties != NULL;
|
||||
ossl_property_unlock(store);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void impl_cache_flush_alg(size_t idx, ALGORITHM *alg)
|
||||
{
|
||||
lh_QUERY_doall(alg->cache, &impl_cache_free);
|
||||
lh_QUERY_flush(alg->cache);
|
||||
}
|
||||
|
||||
static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid)
|
||||
{
|
||||
ALGORITHM *alg = ossl_method_store_retrieve(store, nid);
|
||||
|
||||
if (alg != NULL) {
|
||||
store->nelem -= lh_QUERY_num_items(alg->cache);
|
||||
impl_cache_flush_alg(0, alg);
|
||||
}
|
||||
}
|
||||
|
||||
static void ossl_method_cache_flush_all(OSSL_METHOD_STORE *store)
|
||||
{
|
||||
ossl_sa_ALGORITHM_doall(store->algs, &impl_cache_flush_alg);
|
||||
store->nelem = 0;
|
||||
}
|
||||
|
||||
IMPLEMENT_LHASH_DOALL_ARG(QUERY, IMPL_CACHE_FLUSH);
|
||||
|
||||
/*
|
||||
* Flush an element from the query cache (perhaps).
|
||||
*
|
||||
* In order to avoid taking a write lock to keep accurate LRU information or
|
||||
* using atomic operations to approximate similar, the procedure used here
|
||||
* is to stochastically flush approximately half the cache. Since generating
|
||||
* random numbers is relatively expensive, we produce them in blocks and
|
||||
* consume them as we go, saving generated bits between generations of flushes.
|
||||
*
|
||||
* This procedure isn't ideal, LRU would be better. However, in normal
|
||||
* operation, reaching a full cache would be quite unexpected. It means
|
||||
* that no steady state of algorithm queries has been reached. I.e. it is most
|
||||
* likely an attack of some form. A suboptimal clearance strategy that doesn't
|
||||
* degrade performance of the normal case is preferable to a more refined
|
||||
* approach that imposes a performance impact.
|
||||
*/
|
||||
static void impl_cache_flush_cache(QUERY *c, IMPL_CACHE_FLUSH *state)
|
||||
{
|
||||
OSSL_METHOD_STORE *store = state->store;
|
||||
unsigned int n;
|
||||
|
||||
if (store->nbits == 0) {
|
||||
if (!RAND_bytes(store->rand_bits, sizeof(store->rand_bits)))
|
||||
return;
|
||||
store->nbits = sizeof(store->rand_bits) * 8;
|
||||
}
|
||||
n = --store->nbits;
|
||||
if ((store->rand_bits[n >> 3] & (1 << (n & 7))) != 0)
|
||||
OPENSSL_free(lh_QUERY_delete(state->cache, c));
|
||||
else
|
||||
state->nelem++;
|
||||
}
|
||||
|
||||
static void impl_cache_flush_one_alg(size_t idx, ALGORITHM *alg, void *v)
|
||||
{
|
||||
IMPL_CACHE_FLUSH *state = (IMPL_CACHE_FLUSH *)v;
|
||||
|
||||
state->cache = alg->cache;
|
||||
lh_QUERY_doall_IMPL_CACHE_FLUSH(state->cache, &impl_cache_flush_cache,
|
||||
state);
|
||||
}
|
||||
|
||||
static void ossl_method_cache_flush_some(OSSL_METHOD_STORE *store)
|
||||
{
|
||||
IMPL_CACHE_FLUSH state;
|
||||
|
||||
state.nelem = 0;
|
||||
state.store = store;
|
||||
ossl_sa_ALGORITHM_doall_arg(store->algs, &impl_cache_flush_one_alg, &state);
|
||||
store->need_flush = 0;
|
||||
store->nelem = state.nelem;
|
||||
}
|
||||
|
||||
int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, int nid,
|
||||
const char *prop_query, void **result)
|
||||
{
|
||||
ALGORITHM *alg;
|
||||
QUERY elem, *r;
|
||||
|
||||
if (nid <= 0 || store == NULL)
|
||||
return 0;
|
||||
|
||||
ossl_property_read_lock(store);
|
||||
alg = ossl_method_store_retrieve(store, nid |