]> granicus.if.org Git - p11-kit/commitdiff
url: Split out the URL encoding and decoding functions
authorStef Walter <stefw@gnome.org>
Mon, 11 Mar 2013 16:17:15 +0000 (17:17 +0100)
committerStef Walter <stefw@gnome.org>
Fri, 15 Mar 2013 17:18:47 +0000 (18:18 +0100)
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

common/Makefile.am
common/tests/Makefile.am
common/tests/test-url.c [new file with mode: 0644]
common/url.c [new file with mode: 0644]
common/url.h [new file with mode: 0644]
p11-kit/uri.c

index 3522acbdc60d417dc812030a820776ed8e4bc69d..a132984f997eac315f4cb75e0141fa04f7cb45c9 100644 (file)
@@ -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 = \
index f31cebb38895b8a2c02a459d151166bd990049c0..e14fddd7d9759c37f92c763c01b7c3158ab351ec 100644 (file)
@@ -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 (file)
index 0000000..096563b
--- /dev/null
@@ -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 (file)
index 0000000..6ccf74d
--- /dev/null
@@ -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 (file)
index 0000000..fa7938a
--- /dev/null
@@ -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 */
index e8cb4c868452a64e8aa0590d0d2c139e141c06cd..0bb35db60a37a40f1d3d6f89c37ba54591e72e5d 100644 (file)
@@ -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;