[rs-commit] r415 - in /mod_sign/trunk: README mod_sign.c
rs-commit at redwax.eu
rs-commit at redwax.eu
Sun Aug 2 13:53:34 CEST 2020
Author: dirkx at redwax.eu
Date: Sun Aug 2 13:53:34 2020
New Revision: 415
Log:
First functional version; cursory tested against google/apple GAEN
Modified:
mod_sign/trunk/README
mod_sign/trunk/mod_sign.c
Modified: mod_sign/trunk/README
==============================================================================
--- mod_sign/trunk/README (original)
+++ mod_sign/trunk/README Sun Aug 2 13:53:34 2020
@@ -15,16 +15,35 @@
</Location>
</IfModule>
-3) Test by doing
+3) Test by doing:
+ # Generate a payload and calculat the digest.
echo my payload > payload.txt
openssl sha256 payload.txt
- curl http://localhost/sign?digest=0d2a2ba99cb99e1ecc60154c49a1a56c1e67d43473709ff8e89cea6ac3d01010
-Or more properly
+ # Offer this digest for signing - request a binary blob back.
+ #
+ curl 'http://localhost/signdigest?digest=0d2a2ba99cb99e1ecc60154c49a1a56c1e67d43473709ff8e89cea6ac3d01010&digest_encoding=hex&signature_encoding=binary' > sig.bin
- curl 'http://localhost/sign?digest=0d2a2ba99cb99e1ecc60154c49a1a56c1e67d43473709ff8e89cea6ac3d01010&digest_type=SHA256&digest_encoding=HEX'
+ # Verify that the signature is correct. You should see 'Verified OK'
+ openssl dgst -sha256 -verify ec.pub -hex -signature sig.bin payload.txt
+
+Parameters
+ digest
+ digest itself. Accepts HEX and Base64.
+ Hex can be of the 0d2a or the 02:2a and '02 2a ..' variety.
+ digest_encoding
+ HEX or base64
+ signature_encoding
+ HEX or base64 or Binary
+ digest_type
+ any type openssl support. See
+
+ openssl list -digest-algorithms
+
+ for a few list.
+
Modified: mod_sign/trunk/mod_sign.c
==============================================================================
--- mod_sign/trunk/mod_sign.c (original)
+++ mod_sign/trunk/mod_sign.c Sun Aug 2 13:53:34 2020
@@ -16,8 +16,8 @@
/*
* Sign a digest passed as a base64 value with a
- * private key. Originaly created as part of the
- * Dutch CoronaApp effort to deal with the very
+ * private key. Originaly created as part of the
+ * Dutch CoronaApp effort to deal with the very
* peculiar google/apple unmanaged X9.62 DER blob.
*
*/
@@ -27,6 +27,7 @@
#include <apr_hash.h>
#include <apr_uuid.h>
#include <apr_base64.h>
+#include <assert.h>
#include <openssl/err.h>
#include <openssl/evp.h>
@@ -43,7 +44,7 @@
#define HANDLER "sign"
#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
+#define TOSTRING(x) STRINGIFY(x)
module AP_MODULE_DECLARE_DATA sign_module;
@@ -53,14 +54,22 @@
} encoding_t;
typedef struct {
- const char * location;
+ const char *location;
encoding_t encoding;
+ encoding_t outencoding;
+ const EVP_MD *md_type;
EVP_PKEY *key;
-} sign_config_rec;
+} sign_config_rec;
static apr_status_t sign_EVP_PKEY_cleanup(void *data)
{
EVP_PKEY_free((EVP_PKEY *) data);
+ return APR_SUCCESS;
+}
+
+static apr_status_t sign_ctx_cleanup(void *data)
+{
+ EVP_PKEY_CTX_free((EVP_PKEY_CTX *) data);
return APR_SUCCESS;
}
@@ -69,6 +78,8 @@
sign_config_rec *conf = apr_pcalloc(p, sizeof(sign_config_rec));
conf->location = d;
conf->encoding = ENCODING_UNSET;
+ conf->outencoding = ENCODING_UNSET;
+ conf->md_type = NULL;
conf->key = NULL;
return conf;
@@ -82,26 +93,64 @@
sign_config_rec *base = (sign_config_rec *) basev;
new->encoding = (add->encoding == ENCODING_UNSET) ? base->encoding : add->encoding;
+ new->outencoding = (add->outencoding == ENCODING_UNSET) ? base->outencoding : add->outencoding;
+ new->md_type = (add->md_type == 0) ? base->md_type : add->md_type;
new->key = (add->key == 0) ? base->key : add->key;
return new;
+}
+
+static encoding_t str2enc(const char *arg)
+{
+ if (!strcasecmp(arg, "base64"))
+ return ENCODING_BASE64;
+
+ if (!strcasecmp(arg, "hex"))
+ return ENCODING_HEX;
+
+ if (!strcasecmp(arg, "binary"))
+ return ENCODING_BINARY;
+
+ return ENCODING_UNSET;
}
static const char *set_sign_encoding(cmd_parms *cmd, void *dconf,
const char *arg)
{
sign_config_rec *conf = dconf;
-
- if (!strcmp(arg, "base64")) {
- conf->encoding = ENCODING_BASE64;
- }
- else if (!strcmp(arg, "hex")) {
- conf->encoding = ENCODING_HEX;
- }
- else {
+ conf->encoding = str2enc(arg);
+
+ if (conf->encoding == ENCODING_UNSET)
return apr_psprintf(cmd->pool,
- "The encoding '%s' wasn't 'hex', or 'base64'.", arg);
- }
+ "The encoding '%s' wasn't 'hex', 'binary' or 'base64'.", arg);
+
+ return NULL;
+}
+
+static const char *set_sign_digest_encoding(cmd_parms *cmd, void *dconf,
+ const char *arg)
+{
+ sign_config_rec *conf = dconf;
+ conf->outencoding = str2enc(arg);
+
+ if (conf->outencoding == ENCODING_BINARY)
+ return "Binary encoding not supported on input (we've not yet implemented POST)";
+
+ if (conf->outencoding == ENCODING_UNSET)
+ return apr_psprintf(cmd->pool,
+ "The encoding '%s' wasn't 'hex' or 'base64'.", arg);
+
+ return NULL;
+}
+
+static const char *set_sign_digest(cmd_parms *cmd, void *dconf,
+ const char *arg)
+{
+ sign_config_rec *conf = dconf;
+
+ if ((conf->md_type = EVP_get_digestbyname(arg)) == NULL)
+ return "Unknown digest";
+
return NULL;
}
@@ -140,15 +189,6 @@
return NULL;
}
-static const command_rec sign_cmds[] =
-{
- AP_INIT_TAKE1("SignEncoding",
- set_sign_encoding, NULL, RSRC_CONF | ACCESS_CONF,
- "Set to the default encoding to be returned if not specified. Must be \"hex\", or \"base64\". Defaults to \"base64\"."),
- AP_INIT_TAKE1("SignKey",
- set_sign_key, NULL, RSRC_CONF | ACCESS_CONF,
- "Set the key to use to sign (mandatory, no default)"),
-{NULL}};
static void log_message(request_rec *r, apr_status_t status,
const char *message)
@@ -200,7 +240,8 @@
query_string = apr_pstrdup(r->pool, input);
- while ((key = apr_strtok(query_string, "&", &strtok_state))) {
+ key = apr_strtok(query_string, "&", &strtok_state);
+ while (key) {
value = strchr(key, '=');
if (value) {
*value = '\0'; /* Split the string in two */
@@ -211,7 +252,10 @@
}
ap_unescape_url(key);
ap_unescape_url(value);
+
apr_table_set(params, key, value);
+
+ key = apr_strtok(NULL, "&", &strtok_state);
}
return params;
}
@@ -224,19 +268,19 @@
register unsigned char digit;
#if !APR_CHARSET_EBCDIC
- digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
+ digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
digit *= 16;
digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
-#else /*APR_CHARSET_EBCDIC*/
+#else /* APR_CHARSET_EBCDIC */
char xstr[5];
- xstr[0]='0';
- xstr[1]='x';
- xstr[2]=what[0];
- xstr[3]=what[1];
- xstr[4]='\0';
+ xstr[0] = '0';
+ xstr[1] = 'x';
+ xstr[2] = what[0];
+ xstr[3] = what[1];
+ xstr[4] = '\0';
digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16
-));
-#endif /*APR_CHARSET_EBCDIC*/
+ ));
+#endif /* APR_CHARSET_EBCDIC */
return (digit);
}
@@ -256,13 +300,14 @@
return p - hexstr;
}
-static encoding_t str2encoding(const char * str) {
- if (strcasecmp(str,"hex") == 0)
- return ENCODING_HEX;
- if (strcasecmp(str,"base64") == 0)
- return ENCODING_BASE64;
- if (strcasecmp(str,"binary") == 0)
- return ENCODING_BINARY;
+static encoding_t str2encoding(const char *str)
+{
+ if (strcasecmp(str, "hex") == 0)
+ return ENCODING_HEX;
+ if (strcasecmp(str, "base64") == 0)
+ return ENCODING_BASE64;
+ if (strcasecmp(str, "binary") == 0)
+ return ENCODING_BINARY;
return ENCODING_UNSET;
}
@@ -271,7 +316,7 @@
apr_size_t len;
apr_off_t offset;
const unsigned char *der;
- encoding_t encoding = conf->encoding == ENCODING_UNSET ? ENCODING_BASE64 : conf->encoding;
+ encoding_t encoding = conf->encoding;
encoding_t outencoding = encoding;
int rv;
apr_bucket_brigade *bb = apr_brigade_create(r->pool,
@@ -279,9 +324,9 @@
apr_bucket *e;
apr_status_t status;
const char *q, *qq;
- apr_byte_t * digest;
+ apr_byte_t *digest;
apr_size_t digest_len = 0;
- const EVP_MD * md = NULL;
+ const EVP_MD *md;
const char *accept_encoding = apr_table_get(r->headers_in,
"Accept-Encoding");
@@ -292,68 +337,97 @@
return rv;
}
- if (r->args == NULL || strlen(r->args) == 0 || strlen(r->args) > 256) {
+ if (r->args == NULL || strlen(r->args) == 0 || strlen(r->args) > 510) {
ap_log_rerror(
- APLOG_MARK, APLOG_NOTICE, status, r, "sign_handler: digest argument missing or wrong size");
+ APLOG_MARK, APLOG_NOTICE, 0, r, "sign_handler: digest argument missing or odd sized arguments");
return HTTP_BAD_REQUEST;
};
apr_table_t *args = apr_querystring_to_table(r);
- q = apr_table_get(args, "digest");
-
- if (q == NULL || strlen(q) < 25) {
- ap_log_rerror(
- APLOG_MARK, APLOG_NOTICE, status, r, "sign_handler: digest argument wrong size");
- return HTTP_BAD_REQUEST;
- };
-
- if (encoding == ENCODING_HEX) {
- digest = (apr_byte_t *)apr_pstrdup(r->pool, q); /* replacing in situ */
- digest_len = apr_hex2bin((char *)digest);
- }
- else {
- digest_len = apr_base64_decode_len(q);
- digest = (apr_byte_t *)ap_pbase64decode(r->pool, q);
- }
-
- if ((q = apr_table_get(args, "digest_type")) == NULL) {
- if (digest_len == 20)
- q = "SHA1";
- else if (digest_len == 224 / 8)
- q = "SHA224";
- else if (digest_len == 256 / 8)
- q = "SHA256";
- else if (digest_len == 384 / 8)
- q = "SHA384";
- else if (digest_len == 512 / 8)
- q = "SHA512";
- else {
+
+ q = apr_table_get(args, "digest_encoding");
+ if (q) {
+ encoding_t e = str2encoding(q);
+ if (encoding != ENCODING_UNSET && e != encoding) {
ap_log_rerror(
- APLOG_MARK, APLOG_NOTICE, status, r, "sign_handler: cannot guess digest from length.");
+ APLOG_MARK, APLOG_NOTICE, 0, r, "sign_handler: specified digest encoding not permitted by server configuration.");
return HTTP_BAD_REQUEST;
};
- };
-
- if ((md = EVP_get_digestbyname(q)) == NULL) {
+ encoding = e;
+ };
+
+ if (encoding == ENCODING_UNSET) {
ap_log_rerror(
- APLOG_MARK, APLOG_NOTICE, status, r, "sign_handler: unknown digest type");
+ APLOG_MARK, APLOG_DEBUG, 0, r, "sign_handler: falling back to default base64 input encoding.");
+ encoding = ENCODING_BASE64;
+ };
+
+ q = apr_table_get(args, "digest");
+ if (q == NULL || strlen(q) < 25 || strlen(q) > 256) {
+ ap_log_rerror(
+ APLOG_MARK, APLOG_NOTICE, 0, r, "sign_handler: digest missing or far too small/large.");
return HTTP_BAD_REQUEST;
};
- // If the server has not set an encoding; ok to
- // to override it.
- //
+ if (encoding == ENCODING_HEX) {
+ digest = (apr_byte_t *) apr_pstrdup(r->pool, q); /* replacing in situ */
+ digest_len = apr_hex2bin((char *)digest);
+ }
+ else {
+ digest = apr_palloc(r->pool, apr_base64_decode_len(q));
+ digest_len = apr_base64_decode_binary(digest, q);
+ }
+
+ if (conf->md_type == NULL) {
+ if ((q = apr_table_get(args, "digest_type")) == NULL) {
+ if (digest_len == 20)
+ q = "SHA1";
+ else if (digest_len == 224 / 8)
+ q = "SHA224";
+ else if (digest_len == 256 / 8)
+ q = "SHA256";
+ else if (digest_len == 384 / 8)
+ q = "SHA384";
+ else if (digest_len == 512 / 8)
+ q = "SHA512";
+ else {
+ ap_log_rerror(
+ APLOG_MARK, APLOG_NOTICE, status, r, "sign_handler: cannot guess digest from length");
+ return HTTP_BAD_REQUEST;
+ };
+ };
+
+ if ((md = EVP_get_digestbyname(q)) == NULL) {
+ ap_log_rerror(
+ APLOG_MARK, APLOG_NOTICE, status, r, "sign_handler: unknown digest type");
+ return HTTP_BAD_REQUEST;
+ };
+ };
+
+ if (EVP_MD_size(md) != digest_len) {
+ ap_log_rerror(
+ APLOG_MARK, APLOG_NOTICE, status, r, "sign_handler: %s digest needs %d bytes, recieved %d",
+ OBJ_nid2ln(EVP_MD_type(md)), EVP_MD_size(md), (int)digest_len);
+ return HTTP_BAD_REQUEST;
+ };
+
+ /*
+ * If the server has not set an encoding; ok to override it.
+ */
if ((q = apr_table_get(args, "signature_encoding"))) {
- encoding_t e = str2encoding(q);
- if (e != outencoding && outencoding != ENCODING_UNSET) {
- ap_log_rerror(APLOG_MARK, APLOG_NOTICE, status, r,
- "sign_handler: signature encoding type not allowed by server config");
+ encoding_t e = str2encoding(q);
+ if (e != outencoding && outencoding != ENCODING_UNSET) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOTICE, status, r,
+ "sign_handler: signature encoding type not allowed by server config");
return HTTP_BAD_REQUEST;
- };
- outencoding = e;
- };
-
- /* what content encoding have we been asked for? */
+ };
+ outencoding = e;
+ };
+
+ /*
+ * what content encoding have we been asked for? Only looked at if none
+ * is set.
+ */
if (accept_encoding && outencoding == ENCODING_UNSET) {
char *last, *token, *value;
if (!vary) {
@@ -377,32 +451,41 @@
else {
value = token;
}
- encoding_t e = str2encoding(value);
- if (e != ENCODING_UNSET)
+ encoding_t e = str2encoding(value);
+ if (e != ENCODING_UNSET)
outencoding = e;
token = apr_strtok(NULL, ",", &last);
}
}
+ if (outencoding == ENCODING_UNSET) {
+ outencoding = ENCODING_BASE64;
+ ap_log_rerror(
+ APLOG_MARK, APLOG_DEBUG, 0, r, "sign_handler: falling back to default base64 output encoding.");
+ };
+
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(conf->key, NULL /* no engine */ );
+ apr_pool_cleanup_register(r->pool, NULL, sign_ctx_cleanup, apr_pool_cleanup_null);
+
size_t siglen;
if ((ctx == NULL) ||
- (EVP_PKEY_sign_init(ctx) != 1) ||
- (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) != 1) ||
- (EVP_PKEY_CTX_set_signature_md(ctx, md)) ||
- ((siglen = EVP_PKEY_sign(ctx, NULL, &siglen, digest, digest_len)) <= 0)
+ (EVP_PKEY_sign_init(ctx) <= 0) ||
+ /* (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <=0 ) || */
+ (EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0)
) {
- EVP_PKEY_CTX_free(ctx);
log_message(r, APR_SUCCESS, "EVP Signing context could not me initialized");
return HTTP_INTERNAL_SERVER_ERROR;
};
+ if ((EVP_PKEY_sign(ctx, NULL, &siglen, digest, digest_len) <= 0)) {
+ log_message(r, APR_SUCCESS, "EVP Signature length check failed.");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ };
unsigned char *sig = apr_pcalloc(r->pool, siglen);
int err = EVP_PKEY_sign(ctx, sig, &siglen, digest, digest_len);
- EVP_PKEY_CTX_free(ctx);
if (err != 1) {
log_message(r, APR_SUCCESS, "EVP Signing failed");
@@ -421,19 +504,19 @@
if (outencoding == ENCODING_BASE64) {
len = apr_base64_encode_len(siglen);
q = (char *)apr_palloc(r->pool, 1 + len);
- len = apr_base64_encode((char *)q, (const char *)sig, siglen);
+ len = apr_base64_encode_binary((char *)q, sig, siglen);
apr_brigade_write(bb, NULL, NULL, q, len);
//add a CR ? ?
}
else if (outencoding == ENCODING_HEX) {
- q = apr_palloc(r->pool,2 * siglen + 1);
+ q = apr_palloc(r->pool, 2 * siglen + 1);
ap_bin2hex(sig, siglen, (char *)q);
- len = 2*siglen;
- apr_brigade_write(bb, NULL, NULL, q,len);
+ len = 2 * siglen;
+ apr_brigade_write(bb, NULL, NULL, q, len);
//add a CR ? ?
}
else {
- len = siglen;
+ len = siglen;
apr_brigade_write(bb, NULL, NULL, (const char *)sig, len);
};
ap_set_content_length(r, len);
@@ -454,7 +537,7 @@
static int options_wadl(request_rec *r, sign_config_rec * conf)
{
-static const char str[] = "XXXX " TOSTRING(MODULE_MAGIC_COOKIE) " XXXX";
+ static const char str[] = "XXXX " TOSTRING(MODULE_MAGIC_COOKIE) " XXXX";
int rv;
@@ -465,10 +548,10 @@
ap_set_content_type(r, "application/vnd.sun.wadl+xml");
- ap_rprintf(r,"%s",str);
+ ap_rprintf(r, "%s", str);
ap_rprintf(r,
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<wadl:application xmlns:wadl=\"http://wadl.dev.java.net/2009/02\"\n"
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
" xsi:schemaLocation=\"http://wadl.dev.java.net/2009/02 file:wadl.xsd\">\n"
@@ -476,23 +559,23 @@
" <wadl:resource path=\"/\">\n"
" <wadl:method name=\"GET\" id=\"sign\">\n"
" <wadl:request>\n"
- " <param name=\"digest\" type=\"xsd:string\" style=\"query\" required=\"true\"/>\n"
- " <param name=\"digest_type\" style=\"query\" default=\"SHA256\">\n"
- " <option value=\"SHA1\"/>\n"
- " <option value=\"SHA224\"/>\n"
- " <option value=\"SHA256\"/>\n"
- " <option value=\"SHA384\"/>\n"
- " <option value=\"SHA512\"/>\n"
- " </param>\n"
- " <param name=\"digest_encoding\" style=\"query\" default=\"base64\">\n"
- " <option value=\"hex\"/>\n"
- " <option value=\"base64\"/>\n"
- " </param>\n"
- " <param name=\"signature_encoding\" style=\"query\" default=\"base64\">\n"
- " <option value=\"hex\"/>\n"
- " <option value=\"base64\"/>\n"
- " </param>\n"
- " </wadl:request>\n"
+ " <param name=\"digest\" type=\"xsd:string\" style=\"query\" required=\"true\"/>\n"
+ " <param name=\"digest_type\" style=\"query\" default=\"SHA256\">\n"
+ " <option value=\"SHA1\"/>\n"
+ " <option value=\"SHA224\"/>\n"
+ " <option value=\"SHA256\"/>\n"
+ " <option value=\"SHA384\"/>\n"
+ " <option value=\"SHA512\"/>\n"
+ " </param>\n"
+ " <param name=\"digest_encoding\" style=\"query\" default=\"base64\">\n"
+ " <option value=\"hex\"/>\n"
+ " <option value=\"base64\"/>\n"
+ " </param>\n"
+ " <param name=\"signature_encoding\" style=\"query\" default=\"base64\">\n"
+ " <option value=\"hex\"/>\n"
+ " <option value=\"base64\"/>\n"
+ " </param>\n"
+ " </wadl:request>\n"
" <wadl:response status=\"500\">\n"
" <wadl:representation mediaType=\"text/html\">\n"
" <wadl:doc>On a configuration error, 500 Internal Server Error will be returned,\n"
@@ -500,14 +583,8 @@
" error.</wadl:doc>\n"
" </wadl:representation>\n"
" </wadl:response>\n"
- " <wadl:response status=\"304\">\n"
- " <wadl:representation mediaType=\"application/pkix-crl\">\n"
- " <wadl:doc>If the ETag specified within the If-None-Match header is unmodified\n"
- " compared to the current ETag, 304 Not Modified is returned with no body..</wadl:doc>\n"
- " </wadl:representation>\n"
- " </wadl:response>\n"
" <wadl:response status=\"200\">\n"
- " <wadl:representation mediaType=\"application/pkix-crl\">\n"
+ " <wadl:representation mediaType=\"text/plain\">\n"
" <wadl:doc>After a successful signing of the digest, 200 OK will be returned\n"
" with the body containing the ASN.1 DER-encoded signature as hex, binary or base64.</wadl:doc>\n"
" </wadl:representation>\n"
@@ -516,7 +593,7 @@
" </wadl:resource>\n"
" </wadl:resources>\n"
"</wadl:application>\n",
- conf->location ? conf->location :
+ conf->location ? conf->location :
apr_pstrcat(r->pool, ap_http_scheme(r), "://",
r->server->server_hostname, r->uri, NULL));
@@ -574,7 +651,23 @@
ap_hook_handler(sign_handler, NULL, NULL, APR_HOOK_MIDDLE);
}
-AP_DECLARE_MODULE(crl) =
+static const command_rec sign_cmds[] =
+{
+ AP_INIT_TAKE1("SignEncoding",
+ set_sign_encoding, NULL, RSRC_CONF | ACCESS_CONF,
+ "Set to the default encoding to be returned if not specified. Must be \"hex\", or \"base64\". Defaults to \"base64\"."),
+ AP_INIT_TAKE1("SignDigestEncoding",
+ set_sign_digest_encoding, NULL, RSRC_CONF | ACCESS_CONF,
+ "Set to the encoding for the digest supplied. Must be \"hex\", or \"base64\". Defaults to \"base64\"."),
+ AP_INIT_TAKE1("SignDigest",
+ set_sign_digest, NULL, RSRC_CONF | ACCESS_CONF,
+ "Set to the digest type used. Can be any digeste supported by openssl, defaults to SHA256"),
+ AP_INIT_TAKE1("SignKey",
+ set_sign_key, NULL, RSRC_CONF | ACCESS_CONF,
+ "Set the key to use to sign (mandatory, no default)"),
+{NULL}};
+
+AP_DECLARE_MODULE(sign) =
{
STANDARD20_MODULE_STUFF,
create_sign_dir_config, /* dir config creater */
More information about the rs-commit
mailing list