summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2013-03-11 17:17:15 +0100
committerStef Walter <stefw@gnome.org>2013-03-15 18:18:47 +0100
commit48004b92d4c65080ac71f6a48297abd4d83dfdcb (patch)
tree09c1f5051e5ca59d5465344e532e2e3b85b48648
parent06bf3da80eb780621e0f1eb0ab8d4716ed7b3478 (diff)
downloadp11-kit-48004b92d4c65080ac71f6a48297abd4d83dfdcb.tar.gz
url: Split out the URL encoding and decoding functions
We want to use these as the format for encoding binary data in our PKCS#11 attribute persistence https://bugs.freedesktop.org/show_bug.cgi?id=62156
-rw-r--r--common/Makefile.am1
-rw-r--r--common/tests/Makefile.am1
-rw-r--r--common/tests/test-url.c166
-rw-r--r--common/url.c142
-rw-r--r--common/url.h59
-rw-r--r--p11-kit/uri.c120
6 files changed, 381 insertions, 108 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index 3522acb..a132984 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -28,6 +28,7 @@ libp11_library_la_SOURCES = \
lexer.c lexer.h \
library.c library.h \
pkcs11.h pkcs11x.h \
+ url.c url.h \
$(NULL)
libp11_mock_la_SOURCES = \
diff --git a/common/tests/Makefile.am b/common/tests/Makefile.am
index f31cebb..e14fddd 100644
--- a/common/tests/Makefile.am
+++ b/common/tests/Makefile.am
@@ -21,6 +21,7 @@ CHECK_PROGS = \
test-attrs \
test-buffer \
test-lexer \
+ test-url \
$(NULL)
noinst_PROGRAMS = \
diff --git a/common/tests/test-url.c b/common/tests/test-url.c
new file mode 100644
index 0000000..096563b
--- /dev/null
+++ b/common/tests/test-url.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include "library.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "url.h"
+
+static void
+check_decode_msg (CuTest *tc,
+ const char *file,
+ int line,
+ const char *input,
+ ssize_t input_len,
+ const char *expected,
+ size_t expected_len)
+{
+ unsigned char *decoded;
+ size_t length;
+
+ if (input_len < 0)
+ input_len = strlen (input);
+ decoded = p11_url_decode (input, input + input_len, "", &length);
+
+ if (expected == NULL) {
+ CuAssert_Line (tc, file, line, "decoding should have failed", decoded == NULL);
+
+ } else {
+ CuAssert_Line (tc, file, line, "decoding failed", decoded != NULL);
+ CuAssertIntEquals_LineMsg (tc, file, line, "wrong length", expected_len, length);
+ CuAssert_Line (tc, file, line, "decoded wrong", memcmp (decoded, expected, length) == 0);
+ free (decoded);
+ }
+}
+
+#define check_decode_success(tc, input, input_len, expected, expected_len) \
+ check_decode_msg (tc, __FILE__, __LINE__, input, input_len, expected, expected_len)
+
+#define check_decode_failure(tc, input, input_len) \
+ check_decode_msg (tc, __FILE__, __LINE__, input, input_len, NULL, 0)
+
+static void
+test_decode_success (CuTest *tc)
+{
+ check_decode_success (tc, "%54%45%53%54%00", -1, "TEST", 5);
+ check_decode_success (tc, "%54%45%53%54%00", 6, "TE", 2);
+ check_decode_success (tc, "%54est%00", -1, "Test", 5);
+}
+
+static void
+test_decode_skip (CuTest *tc)
+{
+ const char *input = "%54 %45 %53 %54 %00";
+ unsigned char *decoded;
+ size_t length;
+
+ decoded = p11_url_decode (input, input + strlen (input), P11_URL_WHITESPACE, &length);
+ CuAssertStrEquals (tc, "TEST", (char *)decoded);
+ CuAssertIntEquals (tc, 5, length);
+
+ free (decoded);
+}
+
+static void
+test_decode_failure (CuTest *tc)
+{
+ /* Early termination */
+ check_decode_failure (tc, "%54%45%53%5", -1);
+ check_decode_failure (tc, "%54%45%53%", -1);
+
+ /* Not hex characters */
+ check_decode_failure (tc, "%54%XX%53%54%00", -1);
+}
+
+static void
+test_encode (CuTest *tc)
+{
+ const unsigned char *input = (unsigned char *)"TEST";
+ char *encoded;
+ size_t length;
+
+ encoded = p11_url_encode (input, input + 5, "", &length);
+ CuAssertStrEquals (tc, "%54%45%53%54%00", (char *)encoded);
+ CuAssertIntEquals (tc, 15, length);
+
+ free (encoded);
+}
+
+static void
+test_encode_verbatim (CuTest *tc)
+{
+ const unsigned char *input = (unsigned char *)"TEST";
+ char *encoded;
+ size_t length;
+
+ encoded = p11_url_encode (input, input + 5, "ES", &length);
+ CuAssertStrEquals (tc, "%54ES%54%00", (char *)encoded);
+ CuAssertIntEquals (tc, 11, length);
+
+ free (encoded);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ putenv ("P11_KIT_STRICT=1");
+ p11_library_init ();
+
+ SUITE_ADD_TEST (suite, test_decode_success);
+ SUITE_ADD_TEST (suite, test_decode_skip);
+ SUITE_ADD_TEST (suite, test_decode_failure);
+
+ SUITE_ADD_TEST (suite, test_encode);
+ SUITE_ADD_TEST (suite, test_encode_verbatim);
+
+ CuSuiteRun (suite);
+ CuSuiteSummary (suite, output);
+ CuSuiteDetails (suite, output);
+ printf ("%s\n", output->buffer);
+ ret = suite->failCount;
+ CuSuiteDelete (suite);
+ CuStringDelete (output);
+ return ret;
+}
diff --git a/common/url.c b/common/url.c
new file mode 100644
index 0000000..6ccf74d
--- /dev/null
+++ b/common/url.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "debug.h"
+#include "url.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+const static char HEX_CHARS[] = "0123456789abcdef";
+
+unsigned char *
+p11_url_decode (const char *value,
+ const char *end,
+ const char *skip,
+ size_t *length)
+{
+ char *a, *b;
+ unsigned char *result, *p;
+
+ assert (value <= end);
+ assert (skip != NULL);
+
+ /* String can only get shorter */
+ result = malloc ((end - value) + 1);
+ return_val_if_fail (result != NULL, NULL);
+
+ /* Now loop through looking for escapes */
+ p = result;
+ while (value != end) {
+ /*
+ * A percent sign followed by two hex digits means
+ * that the digits represent an escaped character.
+ */
+ if (*value == '%') {
+ value++;
+ if (value + 2 > end) {
+ free (result);
+ return NULL;
+ }
+ a = strchr (HEX_CHARS, tolower (value[0]));
+ b = strchr (HEX_CHARS, tolower (value[1]));
+ if (!a || !b) {
+ free (result);
+ return NULL;
+ }
+ *p = (a - HEX_CHARS) << 4;
+ *(p++) |= (b - HEX_CHARS);
+ value += 2;
+
+ /* Ignore whitespace characters */
+ } else if (strchr (skip, *value)) {
+ value++;
+
+ /* A different character */
+ } else {
+ *(p++) = *(value++);
+ }
+ }
+
+ /* Null terminate string, in case its a string */
+ *p = 0;
+
+ if (length)
+ *length = p - result;
+ return result;
+}
+
+char *
+p11_url_encode (const unsigned char *value,
+ const unsigned char *end,
+ const char *verbatim,
+ size_t *length)
+{
+ char *p;
+ char *result;
+
+ assert (value <= end);
+
+ /* Just allocate for worst case */
+ result = malloc (((end - value) * 3) + 1);
+ return_val_if_fail (result != NULL, NULL);
+
+ /* Now loop through looking for escapes */
+ p = result;
+ while (value != end) {
+
+ /* These characters we let through verbatim */
+ if (*value && strchr (verbatim, *value) != NULL) {
+ *(p++) = *(value++);
+
+ /* All others get encoded */
+ } else {
+ *(p++) = '%';
+ *(p++) = HEX_CHARS[((unsigned char)*value) >> 4];
+ *(p++) = HEX_CHARS[((unsigned char)*value) & 0x0F];
+ ++value;
+ }
+ }
+
+ *p = 0;
+ if (length)
+ *length = p - result;
+ return result;
+}
diff --git a/common/url.h b/common/url.h
new file mode 100644
index 0000000..fa7938a
--- /dev/null
+++ b/common/url.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Collabora Ltd.
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#ifndef P11_URL_H
+#define P11_URL_H
+
+#include "compat.h"
+
+#include <stdlib.h>
+
+#define P11_URL_WHITESPACE " \n\r\v"
+
+#define P11_URL_VERBATIM "abcdefghijklmnopqrstuvwxyz" \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+ "012345789_-."
+
+unsigned char * p11_url_decode (const char *value,
+ const char *end,
+ const char *skip,
+ size_t *length);
+
+char * p11_url_encode (const unsigned char *value,
+ const unsigned char *end,
+ const char *verbatim,
+ size_t *length);
+
+#endif /* P11_URL_H */
diff --git a/p11-kit/uri.c b/p11-kit/uri.c
index e8cb4c8..0bb35db 100644
--- a/p11-kit/uri.c
+++ b/p11-kit/uri.c
@@ -43,6 +43,7 @@
#include "private.h"
#include "p11-kit.h"
#include "uri.h"
+#include "url.h"
#include <assert.h>
#include <ctype.h>
@@ -145,103 +146,8 @@ struct p11_kit_uri {
char *pin_source;
};
-const static char HEX_CHARS[] = "0123456789abcdef";
const static char WHITESPACE[] = " \n\r\v";
-static int
-url_decode (const char *value, const char *end,
- unsigned char** output, size_t *length)
-{
- char *a, *b;
- unsigned char *result, *p;
-
- assert (output);
- assert (value <= end);
-
- /* String can only get shorter */
- result = malloc ((end - value) + 1);
- return_val_if_fail (result != NULL, P11_KIT_URI_UNEXPECTED);
-
- /* Now loop through looking for escapes */
- p = result;
- while (value != end) {
- /*
- * A percent sign followed by two hex digits means
- * that the digits represent an escaped character.
- */
- if (*value == '%') {
- value++;
- if (value + 2 > end) {
- free (result);
- return P11_KIT_URI_BAD_ENCODING;
- }
- a = strchr (HEX_CHARS, tolower (value[0]));
- b = strchr (HEX_CHARS, tolower (value[1]));
- if (!a || !b) {
- free (result);
- return P11_KIT_URI_BAD_ENCODING;
- }
- *p = (a - HEX_CHARS) << 4;
- *(p++) |= (b - HEX_CHARS);
- value += 2;
-
- /* Ignore whitespace characters */
- } else if (strchr (WHITESPACE, *value)) {
- value++;
-
- /* A different character */
- } else {
- *(p++) = *(value++);
- }
- }
-
- /* Null terminate string, in case its a string */
- *p = 0;
-
- if (length)
- *length = p - result;
- *output = result;
- return P11_KIT_URI_OK;
-}
-
-static char *
-url_encode (const unsigned char *value,
- const unsigned char *end,
- size_t *length,
- bool force)
-{
- char *p;
- char *result;
-
- assert (value <= end);
-
- /* Just allocate for worst case */
- result = malloc (((end - value) * 3) + 1);
- return_val_if_fail (result != NULL, NULL);
-
- /* Now loop through looking for escapes */
- p = result;
- while (value != end) {
-
- /* These characters we let through verbatim */
- if (*value && !force && (isalnum (*value) || strchr ("_-.", *value) != NULL)) {
- *(p++) = *(value++);
-
- /* All others get encoded */
- } else {
- *(p++) = '%';
- *(p++) = HEX_CHARS[((unsigned char)*value) >> 4];
- *(p++) = HEX_CHARS[((unsigned char)*value) & 0x0F];
- ++value;
- }
- }
-
- *p = 0;
- if (length)
- *length = p - result;
- return result;
-}
-
static char *
key_decode (const char *value, const char *end)
{
@@ -750,7 +656,8 @@ format_encode_string (p11_buffer *buffer,
char *encoded;
bool ret;
- encoded = url_encode (value, value + n_value, NULL, force);
+ encoded = p11_url_encode (value, value + n_value,
+ force ? "" : P11_URL_VERBATIM, NULL);
return_val_if_fail (encoded != NULL, false);
ret = format_raw_string (buffer, is_first, name, encoded);
@@ -960,7 +867,6 @@ parse_string_attribute (const char *name, const char *start, const char *end,
unsigned char *value;
CK_ATTRIBUTE_TYPE type;
size_t length;
- int ret;
assert (start <= end);
@@ -971,9 +877,9 @@ parse_string_attribute (const char *name, const char *start, const char *end,
else
return 0;
- ret = url_decode (start, end, &value, &length);
- if (ret < 0)
- return ret;
+ value = p11_url_decode (start, end, P11_URL_WHITESPACE, &length);
+ if (value == NULL)
+ return P11_KIT_URI_BAD_ENCODING;
uri->attrs = p11_attrs_take (uri->attrs, type, value, length);
return 1;
@@ -1033,13 +939,12 @@ parse_struct_info (unsigned char *where, size_t length, const char *start,
{
unsigned char *value;
size_t value_length;
- int ret;
assert (start <= end);
- ret = url_decode (start, end, &value, &value_length);
- if (ret < 0)
- return ret;
+ value = p11_url_decode (start, end, P11_URL_WHITESPACE, &value_length);
+ if (value == NULL)
+ return P11_KIT_URI_BAD_ENCODING;
/* Too long, shouldn't match anything */
if (value_length > length) {
@@ -1173,15 +1078,14 @@ parse_extra_info (const char *name, const char *start, const char *end,
P11KitUri *uri)
{
unsigned char *pin_source;
- int ret;
assert (start <= end);
if (strcmp (name, "pinfile") == 0 ||
strcmp (name, "pin-source") == 0) {
- ret = url_decode (start, end, &pin_source, NULL);
- if (ret < 0)
- return ret;
+ pin_source = p11_url_decode (start, end, P11_URL_WHITESPACE, NULL);
+ if (pin_source == NULL)
+ return P11_KIT_URI_BAD_ENCODING;
free (uri->pin_source);
uri->pin_source = (char*)pin_source;
return 1;