diff options
Diffstat (limited to 'trust')
57 files changed, 11145 insertions, 12 deletions
diff --git a/trust/Makefile.am b/trust/Makefile.am index 6c2c7c8..582b4f5 100644 --- a/trust/Makefile.am +++ b/trust/Makefile.am @@ -13,6 +13,22 @@ AM_CPPFLAGS = \ $(LIBTASN1_CFLAGS) \ $(NULL) +noinst_LTLIBRARIES = \ + libtrust-testable.la \ + libtrust-data.la + +libtrust_data_la_SOURCES = \ + asn1.c asn1.h \ + basic.asn basic.asn.h \ + base64.c base64.h \ + pem.c pem.h \ + pkix.asn pkix.asn.h \ + oid.c oid.h \ + openssl.asn openssl.asn.h \ + utf8.c utf8.h \ + x509.c x509.h \ + $(NULL) + MODULE_SRCS = \ builder.c builder.h \ index.c index.h \ @@ -34,7 +50,7 @@ p11_kit_trust_la_CFLAGS = \ $(LIBTASN1_CFLAGS) p11_kit_trust_la_LIBADD = \ - $(top_builddir)/common/libp11-data.la \ + libtrust-data.la \ $(top_builddir)/common/libp11-library.la \ $(top_builddir)/common/libp11-common.la \ $(LIBTASN1_LIBS) \ @@ -48,17 +64,49 @@ p11_kit_trust_la_LDFLAGS = \ p11_kit_trust_la_SOURCES = $(MODULE_SRCS) -noinst_LTLIBRARIES = \ - libtrust-testable.la - libtrust_testable_la_LDFLAGS = \ -no-undefined libtrust_testable_la_SOURCES = $(MODULE_SRCS) +bin_PROGRAMS = \ + trust + +trust_LDADD = \ + libtrust-data.la \ + $(top_builddir)/p11-kit/libp11-kit.la \ + $(top_builddir)/common/libp11-common.la \ + $(top_builddir)/common/libp11-tool.la \ + $(LTLIBINTL) \ + $(LIBTASN1_LIBS) \ + $(NULL) + +trust_CFLAGS = \ + -I$(top_srcdir)/p11-kit \ + -DP11_KIT_FUTURE_UNSTABLE_API \ + $(LIBTASN1_CFLAGS) \ + $(NULL) + +trust_SOURCES = \ + extract.c extract.h \ + extract-info.c \ + extract-jks.c \ + extract-openssl.c \ + extract-pem.c \ + extract-cer.c \ + openssl.asn openssl.asn.h \ + save.c save.h \ + trust.c \ + $(NULL) + externaldir = $(privatedir) external_SCRIPTS = \ p11-kit-extract-trust EXTRA_DIST = \ p11-kit-trust.module + +asn: + asn1Parser -o pkix.asn.h pkix.asn + asn1Parser -o openssl.asn.h openssl.asn + asn1Parser -o basic.asn.h basic.asn diff --git a/trust/asn1.c b/trust/asn1.c new file mode 100644 index 0000000..29cca3a --- /dev/null +++ b/trust/asn1.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2012 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 "asn1.h" +#define P11_DEBUG_FLAG P11_DEBUG_TRUST +#include "debug.h" +#include "oid.h" + +#include "openssl.asn.h" +#include "pkix.asn.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +static void +free_asn1_def (void *data) +{ + node_asn *def = data; + asn1_delete_structure (&def); +} + +struct { + const ASN1_ARRAY_TYPE* tab; + const char *prefix; + int prefix_len; +} asn1_tabs[] = { + { pkix_asn1_tab, "PKIX1.", 6 }, + { openssl_asn1_tab, "OPENSSL.", 8 }, + { NULL, }, +}; + +p11_dict * +p11_asn1_defs_load (void) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *def; + p11_dict *defs; + int ret; + int i; + + defs = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, free_asn1_def); + + for (i = 0; asn1_tabs[i].tab != NULL; i++) { + + def = NULL; + ret = asn1_array2tree (asn1_tabs[i].tab, &def, message); + if (ret != ASN1_SUCCESS) { + p11_debug_precond ("failed to load %s* definitions: %s: %s\n", + asn1_tabs[i].prefix, asn1_strerror (ret), message); + return NULL; + } + + if (!p11_dict_set (defs, (void *)asn1_tabs[i].prefix, def)) + return_val_if_reached (NULL); + } + + return defs; +} + +static node_asn * +lookup_def (p11_dict *asn1_defs, + const char *struct_name) +{ + int i; + + for (i = 0; asn1_tabs[i].tab != NULL; i++) { + if (strncmp (struct_name, asn1_tabs[i].prefix, asn1_tabs[i].prefix_len) == 0) + return p11_dict_get (asn1_defs, asn1_tabs[i].prefix); + } + + p11_debug_precond ("unknown prefix for element: %s\n", struct_name); + return NULL; +} + +node_asn * +p11_asn1_create (p11_dict *asn1_defs, + const char *struct_name) +{ + node_asn *def; + node_asn *asn; + int ret; + + return_val_if_fail (asn1_defs != NULL, NULL); + + def = lookup_def (asn1_defs, struct_name); + return_val_if_fail (def != NULL, NULL); + + ret = asn1_create_element (def, struct_name, &asn); + if (ret != ASN1_SUCCESS) { + p11_debug_precond ("failed to create element %s: %s\n", + struct_name, asn1_strerror (ret)); + return NULL; + } + + return asn; +} + +node_asn * +p11_asn1_decode (p11_dict *asn1_defs, + const char *struct_name, + const unsigned char *der, + size_t der_len, + char *message) +{ + char msg[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; + node_asn *asn = NULL; + int ret; + + return_val_if_fail (asn1_defs != NULL, NULL); + + asn = p11_asn1_create (asn1_defs, struct_name); + return_val_if_fail (asn != NULL, NULL); + + /* asn1_der_decoding destroys the element if fails */ + ret = asn1_der_decoding (&asn, der, der_len, message ? message : msg); + + if (ret != ASN1_SUCCESS) { + /* If caller passed in a message buffer, assume they're logging */ + if (!message) { + p11_debug ("couldn't parse %s: %s: %s", + struct_name, asn1_strerror (ret), msg); + } + return NULL; + } + + return asn; +} + +unsigned char * +p11_asn1_encode (node_asn *asn, + size_t *der_len) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; + unsigned char *der; + int len; + int ret; + + return_val_if_fail (der_len != NULL, NULL); + + len = 0; + ret = asn1_der_coding (asn, "", NULL, &len, message); + return_val_if_fail (ret != ASN1_SUCCESS, NULL); + + if (ret == ASN1_MEM_ERROR) { + der = malloc (len); + return_val_if_fail (der != NULL, NULL); + + ret = asn1_der_coding (asn, "", der, &len, message); + } + + if (ret != ASN1_SUCCESS) { + p11_debug_precond ("failed to encode: %s\n", message); + return NULL; + } + + if (der_len) + *der_len = len; + return der; +} + +ssize_t +p11_asn1_tlv_length (const unsigned char *data, + size_t length) +{ + unsigned char cls; + int counter = 0; + int cb, len; + unsigned long tag; + + if (asn1_get_tag_der (data, length, &cls, &cb, &tag) == ASN1_SUCCESS) { + counter += cb; + len = asn1_get_length_der (data + cb, length - cb, &cb); + counter += cb; + if (len >= 0) { + len += counter; + if (length >= len) + return len; + } + } + + return -1; +} + +typedef struct { + node_asn *node; + char *struct_name; + size_t length; +} asn1_item; + +static void +free_asn1_item (void *data) +{ + asn1_item *item = data; + free (item->struct_name); + asn1_delete_structure (&item->node); + free (item); +} + +struct _p11_asn1_cache { + p11_dict *defs; + p11_dict *items; +}; + +p11_asn1_cache * +p11_asn1_cache_new (void) +{ + p11_asn1_cache *cache; + + cache = calloc (1, sizeof (p11_asn1_cache)); + return_val_if_fail (cache != NULL, NULL); + + cache->defs = p11_asn1_defs_load (); + return_val_if_fail (cache->defs != NULL, NULL); + + cache->items = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, + NULL, free_asn1_item); + return_val_if_fail (cache->items != NULL, NULL); + + return cache; +} + +node_asn * +p11_asn1_cache_get (p11_asn1_cache *cache, + const char *struct_name, + const unsigned char *der, + size_t der_len) +{ + asn1_item *item; + + return_val_if_fail (cache != NULL, NULL); + return_val_if_fail (struct_name != NULL, NULL); + return_val_if_fail (der != NULL, NULL); + + item = p11_dict_get (cache->items, der); + if (item != NULL) { + return_val_if_fail (item->length == der_len, NULL); + return_val_if_fail (strcmp (item->struct_name, struct_name) == 0, NULL); + return item->node; + } + + return NULL; +} + +void +p11_asn1_cache_take (p11_asn1_cache *cache, + node_asn *node, + const char *struct_name, + const unsigned char *der, + size_t der_len) +{ + asn1_item *item; + + return_if_fail (cache != NULL); + return_if_fail (struct_name != NULL); + return_if_fail (der != NULL); + return_if_fail (der_len != 0); + + item = calloc (1, sizeof (asn1_item)); + return_if_fail (item != NULL); + + item->length = der_len; + item->node = node; + item->struct_name = strdup (struct_name); + return_if_fail (item->struct_name != NULL); + + if (!p11_dict_set (cache->items, (void *)der, item)) + return_if_reached (); +} + +void +p11_asn1_cache_flush (p11_asn1_cache *cache) +{ + return_if_fail (cache != NULL); + p11_dict_clear (cache->items); +} + +p11_dict * +p11_asn1_cache_defs (p11_asn1_cache *cache) +{ + return_val_if_fail (cache != NULL, NULL); + return cache->defs; +} + +void +p11_asn1_cache_free (p11_asn1_cache *cache) +{ + if (!cache) + return; + p11_dict_free (cache->items); + p11_dict_free (cache->defs); + free (cache); +} diff --git a/trust/asn1.h b/trust/asn1.h new file mode 100644 index 0000000..1bd7dd1 --- /dev/null +++ b/trust/asn1.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2012 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 <libtasn1.h> + +#include "dict.h" + +#ifndef P11_ASN1_H_ +#define P11_ASN1_H_ + +typedef struct _p11_asn1_cache p11_asn1_cache; + +p11_dict * p11_asn1_defs_load (void); + +node_asn * p11_asn1_decode (p11_dict *asn1_defs, + const char *struct_name, + const unsigned char *der, + size_t der_len, + char *message); + +node_asn * p11_asn1_create (p11_dict *asn1_defs, + const char *struct_name); + +unsigned char * p11_asn1_encode (node_asn *asn, + size_t *der_len); + +ssize_t p11_asn1_tlv_length (const unsigned char *data, + size_t length); + +p11_asn1_cache * p11_asn1_cache_new (void); + +p11_dict * p11_asn1_cache_defs (p11_asn1_cache *cache); + +node_asn * p11_asn1_cache_get (p11_asn1_cache *cache, + const char *struct_name, + const unsigned char *der, + size_t der_len); + +void p11_asn1_cache_take (p11_asn1_cache *cache, + node_asn *node, + const char *struct_name, + const unsigned char *der, + size_t der_len); + +void p11_asn1_cache_flush (p11_asn1_cache *cache); + +void p11_asn1_cache_free (p11_asn1_cache *cache); + +#endif /* P11_ASN1_H_ */ diff --git a/trust/base64.c b/trust/base64.c new file mode 100644 index 0000000..a9eb966 --- /dev/null +++ b/trust/base64.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "config.h" + +#include "base64.h" + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const char Pad64 = '='; + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +p11_b64_pton (const char *src, + size_t length, + unsigned char *target, + size_t targsize) +{ + int tarindex, state, ch; + char *pos; + const char *end; + + state = 0; + tarindex = 0; + end = src + length; + + /* We can't rely on the null terminator */ + #define next_char(src, end) \ + (((src) == (end)) ? '\0': *(src)++) + + while ((ch = next_char (src, end)) != '\0') { + if (isspace ((unsigned char) ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr (Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if ((size_t) tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex + 1] = ((pos - Base64) & 0x0f) + << 4; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if ((size_t) tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex + 1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if ((size_t) tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = next_char (src, end); /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void) NULL; ch != '\0'; ch = next_char (src, end)) + if (!isspace((unsigned char) ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = next_char (src, end); /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; src != end; ch = next_char (src, end)) + if (!isspace((unsigned char) ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + +int +p11_b64_ntop (const unsigned char *src, + size_t srclength, + char *target, + size_t targsize, + int breakl) +{ + size_t len = 0; + unsigned char input[3]; + unsigned char output[4]; + size_t i; + + while (srclength > 0) { + if (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + } else if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + if (srclength == 1) + output[2] = 255; + else + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = 255; + + srclength = 0; + } + + for (i = 0; i < 4; i++) { + if (breakl && len % (breakl + 1) == 0) { + assert (len + 1 < targsize); + target[len++] = '\n'; + } + + assert(output[i] == 255 || output[i] < 64); + assert (len + 1 < targsize); + + if (output[i] == 255) + target[len++] = Pad64; + else + target[len++] = Base64[output[i]]; + } + } + + assert (len < targsize); + target[len] = '\0'; /* Returned value doesn't count \0. */ + return len; +} diff --git a/trust/base64.h b/trust/base64.h new file mode 100644 index 0000000..cc27afd --- /dev/null +++ b/trust/base64.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef P11_BASE64_H_ +#define P11_BASE64_H_ + +#include <sys/types.h> + +int p11_b64_pton (const char *src, + size_t length, + unsigned char *target, + size_t targsize); + +int p11_b64_ntop (const unsigned char *src, + size_t srclength, + char *target, + size_t targsize, + int breakl); + +#endif /* P11_BASE64_H_ */ diff --git a/trust/basic.asn b/trust/basic.asn new file mode 100644 index 0000000..3c79a4b --- /dev/null +++ b/trust/basic.asn @@ -0,0 +1,12 @@ + +BASIC { } + +DEFINITIONS EXPLICIT TAGS ::= + +BEGIN + +Any ::= ANY + +ObjectIdentifier ::= OBJECT IDENTIFIER + +END
\ No newline at end of file diff --git a/trust/basic.asn.h b/trust/basic.asn.h new file mode 100644 index 0000000..b63447b --- /dev/null +++ b/trust/basic.asn.h @@ -0,0 +1,13 @@ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <libtasn1.h> + +const ASN1_ARRAY_TYPE basic_asn1_tab[] = { + { "BASIC", 536872976, NULL }, + { NULL, 1073741836, NULL }, + { "Any", 1073741837, NULL }, + { "ObjectIdentifier", 12, NULL }, + { NULL, 0, NULL } +}; diff --git a/trust/extract-cer.c b/trust/extract-cer.c new file mode 100644 index 0000000..4a0d9c0 --- /dev/null +++ b/trust/extract-cer.c @@ -0,0 +1,116 @@ +/* + * 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 "compat.h" +#include "debug.h" +#include "extract.h" +#include "message.h" +#include "save.h" + +#include <stdlib.h> + +bool +p11_extract_x509_file (P11KitIter *iter, + p11_extract_info *ex) +{ + bool found = false; + p11_save_file *file; + CK_RV rv; + + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + if (found) { + p11_message ("multiple certificates found but could only write one to file"); + break; + } + + file = p11_save_open_file (ex->destination, ex->flags); + if (!p11_save_write_and_finish (file, ex->cert_der, ex->cert_len)) + return false; + + /* Wrote something */ + found = true; + } + + if (rv != CKR_OK && rv != CKR_CANCEL) { + p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); + return false; + + /* Remember that an empty DER file is not a valid file, so complain if nothing */ + } else if (!found) { + p11_message ("no certificate found"); + return false; + } + + return true; +} + +bool +p11_extract_x509_directory (P11KitIter *iter, + p11_extract_info *ex) +{ + p11_save_file *file; + p11_save_dir *dir; + char *filename; + CK_RV rv; + bool ret; + + dir = p11_save_open_directory (ex->destination, ex->flags); + if (dir == NULL) + return false; + + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + filename = p11_extract_info_filename (ex); + return_val_if_fail (filename != NULL, -1); + + file = p11_save_open_file_in (dir, filename, ".cer", NULL); + free (filename); + + if (!p11_save_write_and_finish (file, ex->cert_der, ex->cert_len)) { + p11_save_finish_directory (dir, false); + return false; + } + } + + if (rv != CKR_OK && rv != CKR_CANCEL) { + p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); + ret = false; + } else { + ret = true; + } + + p11_save_finish_directory (dir, ret); + return ret; +} diff --git a/trust/extract-info.c b/trust/extract-info.c new file mode 100644 index 0000000..133b1cd --- /dev/null +++ b/trust/extract-info.c @@ -0,0 +1,455 @@ +/* + * 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" + +#define P11_DEBUG_FLAG P11_DEBUG_TOOL + +#include "attrs.h" +#include "debug.h" +#include "oid.h" +#include "dict.h" +#include "extract.h" +#include "message.h" +#include "pkcs11.h" +#include "pkcs11x.h" +#include "x509.h" + +#include <stdlib.h> +#include <string.h> + +static p11_dict * +load_stapled_extensions (CK_FUNCTION_LIST_PTR module, + CK_SLOT_ID slot_id, + CK_ATTRIBUTE *id) +{ + CK_OBJECT_CLASS extension = CKO_X_CERTIFICATE_EXTENSION; + CK_ATTRIBUTE *attrs; + P11KitIter *iter; + CK_RV rv = CKR_OK; + p11_dict *stapled; + + CK_ATTRIBUTE match[] = { + { CKA_CLASS, &extension, sizeof (extension) }, + { CKA_ID, id->pValue, id->ulValueLen }, + }; + + CK_ATTRIBUTE template[] = { + { CKA_OBJECT_ID, }, + { CKA_X_CRITICAL, }, + { CKA_VALUE, }, + }; + + stapled = p11_dict_new (p11_attr_hash, + (p11_dict_equals)p11_attr_equal, + NULL, p11_attrs_free); + + /* No ID to use, just short circuit */ + if (!id->pValue || !id->ulValueLen) + return stapled; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_add_filter (iter, match, 2); + p11_kit_iter_begin_with (iter, module, slot_id, 0); + + while (rv == CKR_OK) { + rv = p11_kit_iter_next (iter); + if (rv == CKR_OK) { + attrs = p11_attrs_buildn (NULL, template, 3); + rv = p11_kit_iter_load_attributes (iter, attrs, 3); + if (rv == CKR_OK || rv == CKR_ATTRIBUTE_TYPE_INVALID) { + /* CKA_OBJECT_ID is the first attribute, use it as the key */ + if (!p11_dict_set (stapled, attrs, attrs)) + return_val_if_reached (NULL); + rv = CKR_OK; + } else { + p11_attrs_free (attrs); + } + } + } + + if (rv != CKR_OK && rv != CKR_CANCEL) { + p11_message ("couldn't load stapled extensions for certificate: %s", p11_kit_strerror (rv)); + p11_dict_free (stapled); + stapled = NULL; + } + + p11_kit_iter_free (iter); + return stapled; +} + +static bool +extract_purposes (p11_extract_info *ex) +{ + CK_ATTRIBUTE oid = { CKA_OBJECT_ID, + (void *)P11_OID_EXTENDED_KEY_USAGE, + sizeof (P11_OID_EXTENDED_KEY_USAGE) }; + const unsigned char *ext = NULL; + unsigned char *alloc = NULL; + CK_ATTRIBUTE *attrs; + size_t ext_len; + + if (ex->stapled) { + attrs = p11_dict_get (ex->stapled, &oid); + if (attrs != NULL) + ext = p11_attrs_find_value (attrs, CKA_VALUE, &ext_len); + } + + if (ext == NULL && ex->cert_asn) { + alloc = p11_x509_find_extension (ex->cert_asn, P11_OID_EXTENDED_KEY_USAGE, + ex->cert_der, ex->cert_len, &ext_len); + ext = alloc; + } + + /* No such extension, match anything */ + if (ext == NULL) + return true; + + ex->purposes = p11_x509_parse_extended_key_usage (ex->asn1_defs, ext, ext_len); + + free (alloc); + return ex->purposes != NULL; +} + +static bool +should_collapse_certificate (p11_extract_info *ex, + CK_ATTRIBUTE *value) +{ + CK_ATTRIBUTE *attrs; + + if (!(ex->flags & P11_EXTRACT_COLLAPSE)) + return false; + + if (!ex->already_seen) { + ex->already_seen = p11_dict_new (p11_attr_hash, p11_attr_equal, + NULL, p11_attrs_free); + return_val_if_fail (ex->already_seen != NULL, true); + } + + if (p11_dict_get (ex->already_seen, value)) + return true; + + attrs = p11_attrs_build (NULL, value, NULL); + return_val_if_fail (attrs != NULL, true); + + if (!p11_dict_set (ex->already_seen, attrs, attrs)) + return_val_if_reached (true); + + return false; +} + +static bool +check_trust_flags_match (p11_extract_info *ex) +{ + CK_BBOOL boolv; + int flags = 0; + + /* If no extract trust flags, then just continue */ + if (!(ex->flags & (P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST))) + return true; + + if (p11_attrs_find_bool (ex->attrs, CKA_TRUSTED, &boolv) && boolv) + flags |= P11_EXTRACT_ANCHORS; + if (p11_attrs_find_bool (ex->attrs, CKA_X_DISTRUSTED, &boolv) && boolv) + flags |= P11_EXTRACT_BLACKLIST; + + /* Any of the flags can match */ + if (flags & ex->flags) + return true; + + return false; +} + +static bool +extract_certificate (P11KitIter *iter, + p11_extract_info *ex) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; + CK_ATTRIBUTE *attr; + + CK_ULONG type; + + /* Don't even bother with not X.509 certificates */ + if (!p11_attrs_find_ulong (ex->attrs, CKA_CERTIFICATE_TYPE, &type)) + type = (CK_ULONG)-1; + if (type != CKC_X_509) { + p11_debug ("skipping non X.509 certificate"); + return false; + } + + attr = p11_attrs_find_valid (ex->attrs, CKA_VALUE); + if (!attr || !attr->pValue) { + p11_debug ("skipping certificate without a value"); + return false; + } + + /* + * If collapsing and have already seen this certificate, and shouldn't + * process it even again during this extract procedure. + */ + if (should_collapse_certificate (ex, attr)) { + p11_debug ("skipping certificate that has already been seen"); + return false; + } + + /* + * We do these checks after collapsing, so that blacklisted certificates + * mask out anchors even if we're not exporting blacklisted stuff. + */ + if (!check_trust_flags_match (ex)) { + p11_debug ("skipping certificate that doesn't match trust flags"); + return false; + } + + ex->cert_der = attr->pValue; + ex->cert_len = attr->ulValueLen; + ex->cert_asn = p11_asn1_decode (ex->asn1_defs, "PKIX1.Certificate", + ex->cert_der, ex->cert_len, message); + + if (!ex->cert_asn) { + p11_message ("couldn't parse certificate: %s", message); + return false; + } + + return true; +} + +static bool +extract_info (P11KitIter *iter, + p11_extract_info *ex) +{ + CK_ATTRIBUTE *attr; + CK_RV rv; + + static CK_ATTRIBUTE attr_types[] = { + { CKA_ID, }, + { CKA_CLASS, }, + { CKA_CERTIFICATE_TYPE, }, + { CKA_LABEL, }, + { CKA_VALUE, }, + { CKA_SUBJECT, }, + { CKA_ISSUER, }, + { CKA_TRUSTED, }, + { CKA_CERTIFICATE_CATEGORY }, + { CKA_X_DISTRUSTED }, + { CKA_INVALID, }, + }; + + ex->attrs = p11_attrs_dup (attr_types); + rv = p11_kit_iter_load_attributes (iter, ex->attrs, p11_attrs_count (ex->attrs)); + + /* The attributes couldn't be loaded */ + if (rv != CKR_OK && rv != CKR_ATTRIBUTE_TYPE_INVALID && rv != CKR_ATTRIBUTE_SENSITIVE) { + p11_message ("couldn't load attributes: %s", p11_kit_strerror (rv)); + return false; + } + + /* No class attribute, very strange, just skip */ + if (!p11_attrs_find_ulong (ex->attrs, CKA_CLASS, &ex->klass)) + return false; + + /* If a certificate then */ + if (ex->klass != CKO_CERTIFICATE) { + p11_message ("skipping non-certificate object"); + return false; + } + + if (!extract_certificate (iter, ex)) + return false; + + attr = p11_attrs_find_valid (ex->attrs, CKA_ID); + if (attr) { + ex->stapled = load_stapled_extensions (p11_kit_iter_get_module (iter), + p11_kit_iter_get_slot (iter), + attr); + if (!ex->stapled) + return false; + } + + if (!extract_purposes (ex)) + return false; + + return true; +} + +static void +extract_clear (p11_extract_info *ex) +{ + ex->klass = (CK_ULONG)-1; + + p11_attrs_free (ex->attrs); + ex->attrs = NULL; + + asn1_delete_structure (&ex->cert_asn); + ex->cert_der = NULL; + ex->cert_len = 0; + + p11_dict_free (ex->stapled); + ex->stapled = NULL; + + p11_array_free (ex->purposes); + ex->purposes = NULL; +} + +CK_RV +p11_extract_info_load_filter (P11KitIter *iter, + CK_BBOOL *matches, + void *data) +{ + p11_extract_info *ex = data; + int i; + + extract_clear (ex); + + /* Try to load the certificate and extensions */ + if (!extract_info (iter, ex)) { + *matches = CK_FALSE; + return CKR_OK; + } + + /* + * Limit to certain purposes. Note that the lack of purposes noted + * on the certificate means they match any purpose. This is the + * behavior of the ExtendedKeyUsage extension. + */ + if (ex->limit_to_purposes && ex->purposes) { + *matches = CK_FALSE; + for (i = 0; i < ex->purposes->num; i++) { + if (p11_dict_get (ex->limit_to_purposes, ex->purposes->elem[i])) { + *matches = CK_TRUE; + break; + } + } + } + + return CKR_OK; +} + +void +p11_extract_info_init (p11_extract_info *ex) +{ + memset (ex, 0, sizeof (p11_extract_info)); + ex->asn1_defs = p11_asn1_defs_load (); + return_if_fail (ex->asn1_defs != NULL); +} + +void +p11_extract_info_cleanup (p11_extract_info *ex) +{ + extract_clear (ex); + + p11_dict_free (ex->limit_to_purposes); + ex->limit_to_purposes = NULL; + + p11_dict_free (ex->already_seen); + ex->already_seen = NULL; + + p11_dict_free (ex->asn1_defs); + ex->asn1_defs = NULL; +} + +void +p11_extract_info_limit_purpose (p11_extract_info *ex, + const char *purpose) +{ + char *value; + + if (!ex->limit_to_purposes) { + ex->limit_to_purposes = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); + return_if_fail (ex->limit_to_purposes != NULL); + } + + value = strdup (purpose); + return_if_fail (value != NULL); + + if (!p11_dict_set (ex->limit_to_purposes, value, value)) + return_if_reached (); +} + +static char * +extract_label (p11_extract_info *extract) +{ + CK_ATTRIBUTE *attr; + + /* Look for a label and just use that */ + attr = p11_attrs_find_valid (extract->attrs, CKA_LABEL); + if (attr && attr->pValue && attr->ulValueLen) + return strndup (attr->pValue, attr->ulValueLen); + + /* For extracting certificates */ + if (extract->klass == CKO_CERTIFICATE) + return strdup ("certificate"); + + return strdup ("unknown"); +} + +#define FILENAME_CHARS \ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_" + +char * +p11_extract_info_filename (p11_extract_info *extract) +{ + char *label; + int i; + + label = extract_label (extract); + return_val_if_fail (label != NULL, NULL); + + for (i = 0; label[i] != '\0'; i++) { + if (strchr (FILENAME_CHARS, label[i]) == NULL) + label[i] = '_'; + } + + return label; +} + +char * +p11_extract_info_comment (p11_extract_info *ex, + bool first) +{ + char *comment; + char *label; + + if (!(ex->flags & P11_EXTRACT_COMMENT)) + return NULL; + + label = extract_label (ex); + if (!asprintf (&comment, "%s# %s\n", + first ? "" : "\n", + label ? label : "")) + return_val_if_reached (NULL); + + free (label); + return comment; +} diff --git a/trust/extract-jks.c b/trust/extract-jks.c new file mode 100644 index 0000000..2c78a51 --- /dev/null +++ b/trust/extract-jks.c @@ -0,0 +1,331 @@ +/* + * 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 "attrs.h" +#include "buffer.h" +#include "compat.h" +#include "debug.h" +#include "extract.h" +#include "hash.h" +#include "message.h" +#include "save.h" + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +static void +encode_msb_short (unsigned char *data, + int16_t value) +{ + uint16_t v; + + /* At this point we only support positive numbers */ + assert (value >= 0); + assert (value < INT16_MAX); + + v = (uint16_t)value; + data[0] = (v >> 8) & 0xff; + data[1] = (v >> 0) & 0xff; +} + +static void +encode_msb_int (unsigned char *data, + int32_t value) +{ + uint32_t v; + + /* At this point we only support positive numbers */ + assert (value >= 0); + assert (value < INT32_MAX); + + v = (uint32_t)value; + data[0] = (v >> 24) & 0xff; + data[1] = (v >> 16) & 0xff; + data[2] = (v >> 8) & 0xff; + data[3] = (v >> 0) & 0xff; +} + +static void +encode_msb_long (unsigned char *data, + int64_t value) +{ + uint64_t v; + + /* At this point we only support positive numbers */ + assert (value >= 0); + assert (value < INT64_MAX); + + v = (uint64_t)value; + data[0] = (v >> 56) & 0xff; + data[1] = (v >> 48) & 0xff; + data[2] = (v >> 40) & 0xff; + data[3] = (v >> 32) & 0xff; + data[4] = (v >> 24) & 0xff; + data[5] = (v >> 16) & 0xff; + data[6] = (v >> 8) & 0xff; + data[7] = (v >> 0) & 0xff; +} + +static void +add_msb_int (p11_buffer *buffer, + int32_t value) +{ + unsigned char *data = p11_buffer_append (buffer, 4); + return_if_fail (data != NULL); + encode_msb_int (data, value); +} + +static void +add_msb_long (p11_buffer *buffer, + int64_t value) +{ + unsigned char *data = p11_buffer_append (buffer, 8); + return_if_fail (data != NULL); + encode_msb_long (data, value); +} + +static void +add_string (p11_buffer *buffer, + const char *string, + size_t length) +{ + unsigned char *data; + + if (length > INT16_MAX) { + p11_message ("truncating long string"); + length = INT16_MAX; + } + + data = p11_buffer_append (buffer, 2); + return_if_fail (data != NULL); + encode_msb_short (data, length); + p11_buffer_add (buffer, string, length); +} + +static void +convert_alias (const char *input, + size_t length, + p11_buffer *buf) +{ + char ch; + size_t i; + + /* + * Java requires that the aliases are 'converted'. For the basic java + * cacerts key store this is lower case. We just do this for ASCII, since + * we don't want to have to bring in unicode case rules. Since we're + * screwing around, we also take out spaces, to make these look like + * java aliases. + */ + + for (i = 0; i < length; i++) { + ch = input[i]; + if (!isspace (ch) && (ch & 0x80) == 0) { + ch = tolower (ch); + p11_buffer_add (buf, &ch, 1); + } + } +} + +static bool +add_alias (p11_buffer *buffer, + p11_dict *aliases, + CK_ATTRIBUTE *label) +{ + const char *input; + size_t input_len; + size_t length; + p11_buffer buf; + char num[32]; + char *alias; + int i; + + p11_buffer_init_null (&buf, 64); + + if (label && label->pValue) { + input = label->pValue; + input_len = label->ulValueLen; + } else { + input = "unlabeled"; + input_len = strlen (input); + } + + convert_alias (input, input_len, &buf); + + for (i = 0; i < INT32_MAX; i++) { + if (i > 0) { + snprintf (num, sizeof (num), "-%d", i); + p11_buffer_add (&buf, num, -1); + } + + return_val_if_fail (p11_buffer_ok (&buf), false); + if (!p11_dict_get (aliases, buf.data)) { + alias = p11_buffer_steal (&buf, &length); + if (!p11_dict_set (aliases, alias, alias)) + return_val_if_reached (false); + add_string (buffer, alias, length); + return true; + } + + p11_buffer_reset (&buf, 0); + } + + return false; +} + +static bool +prepare_jks_buffer (P11KitIter *iter, + p11_extract_info *ex, + p11_buffer *buffer) +{ + const unsigned char magic[] = { 0xfe, 0xed, 0xfe, 0xed }; + const int version = 2; + size_t count_at; + unsigned char *digest; + CK_ATTRIBUTE *label; + p11_dict *aliases; + size_t length; + int64_t now; + int count; + CK_RV rv; + + enum { + private_key = 1, + trusted_cert = 2, + }; + + /* + * Documented in the java sources in the file: + * src/share/classes/sun/security/provider/JavaKeyStore.java + */ + + p11_buffer_add (buffer, magic, sizeof (magic)); + add_msb_int (buffer, version); + count_at = buffer->len; + p11_buffer_append (buffer, 4); + count = 0; + + /* + * We use the current time for each entry. Java expects the time + * when this was this certificate was added to the keystore, however + * we don't have that information. Java uses time in milliseconds + */ + now = time (NULL); + return_val_if_fail (now > 0, false); + now *= 1000; /* seconds to milliseconds */ + + /* + * The aliases in the output file need to be unique. We use a hash + * table to guarantee this. + */ + aliases = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); + return_val_if_fail (aliases != NULL, false); + + /* For every certificate */ + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + count++; + + /* The type of entry */ + add_msb_int (buffer, trusted_cert); + + /* The alias */ + label = p11_attrs_find_valid (ex->attrs, CKA_LABEL); + if (!add_alias (buffer, aliases, label)) { + p11_message ("could not generate a certificate alias name"); + p11_dict_free (aliases); + return false; + } + + /* The creation date: current time */ + add_msb_long (buffer, now); + + /* The type of the certificate */ + add_string (buffer, "X.509", 5); + + /* The DER encoding of the certificate */ + add_msb_int (buffer, ex->cert_len); + p11_buffer_add (buffer, ex->cert_der, ex->cert_len); + } + + p11_dict_free (aliases); + + if (rv != CKR_OK && rv != CKR_CANCEL) { + p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); + return false; + } + + /* Place the count in the right place */ + encode_msb_int ((unsigned char *)buffer->data + count_at, count); + + /* + * Java keystore reinvents HMAC and uses it to try and "secure" the + * cacerts. We fill this in and use the default "changeit" string + * as the password for this keyed digest. + */ + length = buffer->len; + digest = p11_buffer_append (buffer, P11_HASH_SHA1_LEN); + return_val_if_fail (digest != NULL, false); + p11_hash_sha1 (digest, + "\000c\000h\000a\000n\000g\000e\000i\000t", 16, /* default password */ + "Mighty Aphrodite", 16, /* go figure */ + buffer->data, length, + NULL); + + return_val_if_fail (p11_buffer_ok (buffer), false); + return true; +} + +bool +p11_extract_jks_cacerts (P11KitIter *iter, + p11_extract_info *ex) +{ + p11_buffer buffer; + p11_save_file *file; + bool ret; + + p11_buffer_init (&buffer, 1024 * 10); + ret = prepare_jks_buffer (iter, ex, &buffer); + if (ret) { + file = p11_save_open_file (ex->destination, ex->flags); + ret = p11_save_write_and_finish (file, buffer.data, buffer.len); + } + + p11_buffer_uninit (&buffer); + return ret; +} diff --git a/trust/extract-openssl.c b/trust/extract-openssl.c new file mode 100644 index 0000000..91a9965 --- /dev/null +++ b/trust/extract-openssl.c @@ -0,0 +1,674 @@ +/* + * 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 "asn1.h" +#include "attrs.h" +#include "buffer.h" +#include "compat.h" +#include "debug.h" +#include "dict.h" +#include "extract.h" +#include "hash.h" +#include "message.h" +#include "oid.h" +#include "pem.h" +#include "pkcs11.h" +#include "pkcs11x.h" +#include "save.h" +#include "utf8.h" +#include "x509.h" + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +/* These functions are declared with a global scope for testing */ + +void p11_openssl_canon_string (char *str, + size_t *len); + +bool p11_openssl_canon_string_der (p11_buffer *der); + +bool p11_openssl_canon_name_der (p11_dict *asn1_defs, + p11_buffer *der); + +static p11_array * +empty_usages (void) +{ + return p11_array_new (free); +} + +static bool +known_usages (p11_array *oids) +{ + char *string; + int i; + + const char *strings[] = { + P11_OID_SERVER_AUTH_STR, + P11_OID_CLIENT_AUTH_STR, + P11_OID_CODE_SIGNING_STR, + P11_OID_EMAIL_PROTECTION_STR, + P11_OID_IPSEC_END_SYSTEM_STR, + P11_OID_IPSEC_TUNNEL_STR, + P11_OID_IPSEC_USER_STR, + P11_OID_TIME_STAMPING_STR, + NULL, + }; + + for (i = 0; strings[i] != NULL; i++) { + string = strdup (strings[i]); + return_val_if_fail (string != NULL, false); + if (!p11_array_push (oids, string)) + return_val_if_reached (false); + } + + return true; +} + +static bool +load_usage_ext (p11_extract_info *ex, + const unsigned char *ext_oid, + p11_array **oids) +{ + CK_ATTRIBUTE attr = { CKA_OBJECT_ID, (void *)ext_oid, + p11_oid_length (ext_oid) }; + void *value; + size_t length; + + value = p11_attrs_find_value (p11_dict_get (ex->stapled, &attr), CKA_VALUE, &length); + if (value == NULL) { + *oids = NULL; + return true; + } + + *oids = p11_x509_parse_extended_key_usage (ex->asn1_defs, value, length); + return_val_if_fail (*oids != NULL, false); + + return true; +} + +static bool +write_usages (node_asn *asn, + const char *field, + p11_array *oids) +{ + char *last; + int ret; + int i; + + /* + * No oids? Then doing this will make the entire optional + * field go away + */ + if (oids == NULL) { + ret = asn1_write_value (asn, field, NULL, 0); + return_val_if_fail (ret == ASN1_SUCCESS, false); + + } else { + if (asprintf (&last, "%s.?LAST", field) < 0) + return_val_if_reached (false); + for (i = 0; i < oids->num; i++) { + ret = asn1_write_value (asn, field, "NEW", 1); + return_val_if_fail (ret == ASN1_SUCCESS, false); + ret = asn1_write_value (asn, last, oids->elem[i], -1); + return_val_if_fail (ret == ASN1_SUCCESS, false); + } + + free (last); + } + + return true; +} + +static bool +write_trust_and_rejects (p11_extract_info *ex, + node_asn *asn) +{ + p11_array *trusts = NULL; + p11_array *rejects = NULL; + CK_BBOOL trust; + CK_BBOOL distrust; + + if (!p11_attrs_find_bool (ex->attrs, CKA_TRUSTED, &trust)) + trust = CK_FALSE; + if (!p11_attrs_find_bool (ex->attrs, CKA_X_DISTRUSTED, &distrust)) + distrust = CK_FALSE; + + if (!load_usage_ext (ex, P11_OID_OPENSSL_REJECT, &rejects)) + return_val_if_reached (false); + + if (distrust) { + + /* + * If this is on the blacklist then, make sure we have + * an empty trusts field and add as many things to rejects + * as possible. + */ + trusts = NULL; + + if (!rejects) + rejects = empty_usages (); + if (!known_usages (rejects)) + return_val_if_reached (false); + return_val_if_fail (rejects != NULL, false); + + } else if (trust) { + + /* + * If this is an anchor, then try and guarantee that there + * are some trust anchors. + */ + + if (!load_usage_ext (ex, P11_OID_EXTENDED_KEY_USAGE, &trusts)) + return_val_if_reached (false); + + } else { + + /* + * This is not an anchor, always put an empty trusts + * section, with possible rejects, loaded above + */ + + trusts = empty_usages (); + } + + if (!write_usages (asn, "trust", trusts) || + !write_usages (asn, "reject", rejects)) + return_val_if_reached (false); + + p11_array_free (trusts); + p11_array_free (rejects); + return true; +} + +static bool +write_keyid (p11_extract_info *ex, + node_asn *asn) +{ + CK_ATTRIBUTE attr = { CKA_OBJECT_ID, + (void *)P11_OID_SUBJECT_KEY_IDENTIFIER, + sizeof (P11_OID_SUBJECT_KEY_IDENTIFIER) }; + CK_ATTRIBUTE *value; + int ret; + + value = p11_attrs_find_valid (p11_dict_get (ex->stapled, &attr), CKA_VALUE); + if (value == NULL) { + ret = asn1_write_value (asn, "keyid", NULL, 0); + return_val_if_fail (ret == ASN1_SUCCESS, false); + } else { + ret = asn1_write_value (asn, "keyid", value->pValue, value->ulValueLen); + return_val_if_fail (ret == ASN1_SUCCESS, false); + } + + return true; +} + +static bool +write_alias (p11_extract_info *ex, + node_asn *asn) +{ + CK_ATTRIBUTE *label; + int ret; + + label = p11_attrs_find_valid (ex->attrs, CKA_LABEL); + if (label == NULL) { + ret = asn1_write_value (asn, "alias", NULL, 0); + return_val_if_fail (ret == ASN1_SUCCESS, false); + } else { + ret = asn1_write_value (asn, "alias", label->pValue, label->ulValueLen); + return_val_if_fail (ret == ASN1_SUCCESS, false); + } + + return true; +} + +static bool +write_other (p11_extract_info *ex, + node_asn *asn) +{ + int ret; + + ret = asn1_write_value (asn, "other", NULL, 0); + return_val_if_fail (ret == ASN1_SUCCESS, false); + + return true; +} + +static bool +prepare_pem_contents (p11_extract_info *ex, + p11_buffer *buffer) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; + unsigned char *der; + node_asn *asn; + size_t offset; + int ret; + int len; + + p11_buffer_add (buffer, ex->cert_der, ex->cert_len); + + asn = p11_asn1_create (ex->asn1_defs, "OPENSSL.CertAux"); + return_val_if_fail (asn != NULL, false); + + if (!write_trust_and_rejects (ex, asn) || + !write_alias (ex, asn) || + !write_keyid (ex, asn) || + !write_other (ex, asn)) + return_val_if_reached (false); + + len = 0; + offset = buffer->len; + + ret = asn1_der_coding (asn, "", NULL, &len, message); + return_val_if_fail (ret == ASN1_MEM_ERROR, false); + + der = p11_buffer_append (buffer, len); + return_val_if_fail (der != NULL, false); + + ret = asn1_der_coding (asn, "", der, &len, message); + return_val_if_fail (ret == ASN1_SUCCESS, false); + + buffer->len = offset + len; + asn1_delete_structure (&asn); + return true; +} + +bool +p11_extract_openssl_bundle (P11KitIter *iter, + p11_extract_info *ex) +{ + p11_save_file *file; + p11_buffer output; + p11_buffer buf; + char *comment; + bool ret = true; + bool first; + CK_RV rv; + + file = p11_save_open_file (ex->destination, ex->flags); + if (!file) + return false; + + first = true; + p11_buffer_init (&output, 0); + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + p11_buffer_init (&buf, 1024); + if (!p11_buffer_reset (&output, 2048)) + return_val_if_reached (false); + + if (prepare_pem_contents (ex, &buf)) { + if (!p11_pem_write (buf.data, buf.len, "TRUSTED CERTIFICATE", &output)) + return_val_if_reached (false); + + comment = p11_extract_info_comment (ex, first); + first = false; + + ret = p11_save_write (file, comment, -1) && + p11_save_write (file, output.data, output.len); + + free (comment); + } + + p11_buffer_uninit (&buf); + + if (!ret) + break; + } + + p11_buffer_uninit (&output); + + if (rv != CKR_OK && rv != CKR_CANCEL) { + p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); + ret = false; + } + + /* + * This will produce an empty file (which is a valid PEM bundle) if no + * certificates were found. + */ + + p11_save_finish_file (file, ret); + return ret; +} + +void +p11_openssl_canon_string (char *str, + size_t *len) +{ + bool nsp; + bool sp; + char *in; + char *out; + char *end; + + /* + * Now that the string is UTF-8 here we convert the string to the + * OpenSSL canonical form. This is a bit odd and openssl specific. + * Basically they ignore any char over 127, do ascii tolower() stuff + * and collapse spaces based on isspace(). + */ + + for (in = out = str, end = out + *len, sp = false, nsp = false; in < end; in++) { + if (*in & 0x80 || !isspace (*in)) { + /* If there has been a space, then add one */ + if (sp) + *out++ = ' '; + *out++ = (*in & 0x80) ? *in : tolower (*in); + sp = false; + nsp = true; + /* If there has been a non-space, then note we should get one */ + } else if (nsp) { + nsp = false; + sp = true; + } + } + + if (out < end) + out[0] = 0; + *len = out - str; +} + +bool +p11_openssl_canon_string_der (p11_buffer *der) +{ + char *string; + size_t length; + int output_len; + int len_len; + bool unknown_string; + unsigned char *output; + int len; + + string = p11_x509_parse_directory_string (der->data, der->len, &unknown_string, &length); + + /* Just pass through all the non-string types */ + if (string == NULL) + return unknown_string; + + p11_openssl_canon_string (string, &length); + + asn1_length_der (length, NULL, &len_len); + output_len = 1 + len_len + length; + + if (!p11_buffer_reset (der, output_len)) + return_val_if_reached (false); + + output = der->data; + der->len = output_len; + + output[0] = 12; /* UTF8String */ + len = output_len - 1; + asn1_octet_der ((unsigned char *)string, length, output + 1, &len); + assert (len == output_len - 1); + + free (string); + return true; +} + +bool +p11_openssl_canon_name_der (p11_dict *asn1_defs, + p11_buffer *der) +{ + p11_buffer value; + char outer[64]; + char field[64]; + node_asn *name; + void *at; + int value_len; + bool failed; + size_t offset; + int ret; + int num; + int len; + int i, j; + + name = p11_asn1_decode (asn1_defs, "PKIX1.Name", der->data, der->len, NULL); + return_val_if_fail (name != NULL, false); + + ret = asn1_number_of_elements (name, "rdnSequence", &num); + return_val_if_fail (ret == ASN1_SUCCESS, false); + + p11_buffer_init (&value, 0); + p11_buffer_reset (der, 0); + + for (i = 1, failed = false; !failed && i < num + 1; i++) { + snprintf (outer, sizeof (outer), "rdnSequence.?%d", i); + for (j = 1; !failed; j++) { + snprintf (field, sizeof (field), "%s.?%d.value", outer, j); + + value_len = 0; + ret = asn1_read_value (name, field, NULL, &value_len); + if (ret == ASN1_ELEMENT_NOT_FOUND) + break; + + return_val_if_fail (ret == ASN1_MEM_ERROR, false); + + if (!p11_buffer_reset (&value, value_len)) + return_val_if_reached (false); + + ret = asn1_read_value (name, field, value.data, &value_len); + return_val_if_fail (ret == ASN1_SUCCESS, false); + value.len = value_len; + + if (p11_openssl_canon_string_der (&value)) { + ret = asn1_write_value (name, field, value.data, value.len); + return_val_if_fail (ret == ASN1_SUCCESS, false); + } else { + failed = true; + } + } + + /* + * Yes the OpenSSL canon strangeness, is a concatenation + * of all the RelativeDistinguishedName DER encodings, without + * an outside wrapper. + */ + if (!failed) { + len = -1; + ret = asn1_der_coding (name, outer, NULL, &len, NULL); + return_val_if_fail (ret == ASN1_MEM_ERROR, false); + + offset = der->len; + at = p11_buffer_append (der, len); + return_val_if_fail (at != NULL, false); + + ret = asn1_der_coding (name, outer, at, &len, NULL); + return_val_if_fail (ret == ASN1_SUCCESS, false); + der->len = offset + len; + } + } + + asn1_delete_structure (&name); + p11_buffer_uninit (&value); + return !failed; +} + +#ifdef OS_UNIX + +static char * +symlink_for_subject_hash (p11_extract_info *ex) +{ + unsigned char md[P11_HASH_SHA1_LEN]; + p11_buffer der; + CK_ATTRIBUTE *subject; + unsigned long hash; + char *linkname = NULL; + + subject = p11_attrs_find_valid (ex->attrs, CKA_SUBJECT); + if (!subject || !subject->pValue || !subject->ulValueLen) + return NULL; + + p11_buffer_init_full (&der, memdup (subject->pValue, subject->ulValueLen), + subject->ulValueLen, 0, realloc, free); + return_val_if_fail (der.data != NULL, NULL); + + if (p11_openssl_canon_name_der (ex->asn1_defs, &der)) { + p11_hash_sha1 (md, der.data, der.len, NULL); + + hash = ( + ((unsigned long)md[0] ) | ((unsigned long)md[1] << 8L) | + ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) + ) & 0xffffffffL; + + if (asprintf (&linkname, "%08lx", hash) < 0) + return_val_if_reached (NULL); + } + + p11_buffer_uninit (&der); + return linkname; +} + +static char * +symlink_for_subject_old_hash (p11_extract_info *ex) +{ + unsigned char md[P11_HASH_MD5_LEN]; + CK_ATTRIBUTE *subject; + unsigned long hash; + char *linkname; + + subject = p11_attrs_find_valid (ex->attrs, CKA_SUBJECT); + if (!subject) + return NULL; + + p11_hash_md5 (md, subject->pValue, subject->ulValueLen, NULL); + + hash = ( + ((unsigned long)md[0] ) | ((unsigned long)md[1] << 8L) | + ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) + ) & 0xffffffffL; + + if (asprintf (&linkname, "%08lx", hash) < 0) + return_val_if_reached (NULL); + + return linkname; +} + +#endif /* OS_UNIX */ + +bool +p11_extract_openssl_directory (P11KitIter *iter, + p11_extract_info *ex) +{ + const char *filename; + p11_save_file *file; + p11_save_dir *dir; + p11_buffer output; + p11_buffer buf; + bool ret = true; + char *name; + CK_RV rv; + +#ifdef OS_UNIX + char *linkname; +#endif + + dir = p11_save_open_directory (ex->destination, ex->flags); + if (dir == NULL) + return false; + + p11_buffer_init (&buf, 0); + p11_buffer_init (&output, 0); + + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + if (!p11_buffer_reset (&buf, 1024)) + return_val_if_reached (false); + if (!p11_buffer_reset (&output, 2048)) + return_val_if_reached (false); + + if (prepare_pem_contents (ex, &buf)) { + if (!p11_pem_write (buf.data, buf.len, "TRUSTED CERTIFICATE", &output)) + return_val_if_reached (false); + + name = p11_extract_info_filename (ex); + return_val_if_fail (name != NULL, false); + + file = p11_save_open_file_in (dir, name, ".pem", &filename); + + /* + * The OpenSSL style c_rehash stuff + * + * Different versions of openssl build these hashes differently + * so output both of them. Shouldn't cause confusion, because + * multiple certificates can hash to the same link anyway, + * and this is the reason for the trailing number after the dot. + * + * The trailing number is incremented p11_save_symlink_in() if it + * conflicts with something we've already written out. + * + * On Windows no symlinks. + */ + + ret = true; + +#ifdef OS_UNIX + linkname = symlink_for_subject_hash (ex); + if (file && linkname) { + ret = p11_save_symlink_in (dir, linkname, ".0", filename); + free (linkname); + } + + linkname = symlink_for_subject_old_hash (ex); + if (ret && file && linkname) { + ret = p11_save_symlink_in (dir, linkname, ".0", filename); + free (linkname); + } +#endif /* OS_UNIX */ + + if (ret) + ret = p11_save_write_and_finish (file, output.data, output.len); + else + p11_save_finish_file (file, false); + + free (name); + } + + if (!ret) + break; + } + + p11_buffer_uninit (&buf); + p11_buffer_uninit (&output); + + if (rv != CKR_OK && rv != CKR_CANCEL) { + p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); + ret = false; + } + + p11_save_finish_directory (dir, ret); + return ret; +} diff --git a/trust/extract-pem.c b/trust/extract-pem.c new file mode 100644 index 0000000..0bae3cb --- /dev/null +++ b/trust/extract-pem.c @@ -0,0 +1,143 @@ +/* + * 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" + +#define P11_DEBUG_FLAG P11_DEBUG_TOOL + +#include "compat.h" +#include "debug.h" +#include "extract.h" +#include "message.h" +#include "pem.h" +#include "save.h" + +#include <stdlib.h> + +bool +p11_extract_pem_bundle (P11KitIter *iter, + p11_extract_info *ex) +{ + char *comment; + p11_buffer buf; + p11_save_file *file; + bool ret = true; + bool first = true; + CK_RV rv; + + file = p11_save_open_file (ex->destination, ex->flags); + if (!file) + return false; + + p11_buffer_init (&buf, 0); + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + if (!p11_buffer_reset (&buf, 2048)) + return_val_if_reached (false); + + if (!p11_pem_write (ex->cert_der, ex->cert_len, "CERTIFICATE", &buf)) + return_val_if_reached (false); + + comment = p11_extract_info_comment (ex, first); + first = false; + + ret = p11_save_write (file, comment, -1) && + p11_save_write (file, buf.data, buf.len); + + free (comment); + + if (!ret) + break; + } + + p11_buffer_uninit (&buf); + + if (rv != CKR_OK && rv != CKR_CANCEL) { + p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); + ret = false; + } + + /* + * This will produce an empty file (which is a valid PEM bundle) if no + * certificates were found. + */ + + p11_save_finish_file (file, ret); + return ret; +} + +bool +p11_extract_pem_directory (P11KitIter *iter, + p11_extract_info *ex) +{ + p11_save_file *file; + p11_save_dir *dir; + p11_buffer buf; + bool ret = true; + char *filename; + CK_RV rv; + + dir = p11_save_open_directory (ex->destination, ex->flags); + if (dir == NULL) + return false; + + p11_buffer_init (&buf, 0); + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + if (!p11_buffer_reset (&buf, 2048)) + return_val_if_reached (false); + + if (!p11_pem_write (ex->cert_der, ex->cert_len, "CERTIFICATE", &buf)) + return_val_if_reached (false); + + filename = p11_extract_info_filename (ex); + return_val_if_fail (filename != NULL, false); + + file = p11_save_open_file_in (dir, filename, ".pem", NULL); + free (filename); + + ret = p11_save_write_and_finish (file, buf.data, buf.len); + + if (!ret) + break; + } + + p11_buffer_uninit (&buf); + + if (rv != CKR_OK && rv != CKR_CANCEL) { + p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); + ret = false; + } + + p11_save_finish_directory (dir, ret); + return ret; +} diff --git a/trust/extract.c b/trust/extract.c new file mode 100644 index 0000000..10f45df --- /dev/null +++ b/trust/extract.c @@ -0,0 +1,460 @@ +/* + * 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 "attrs.h" +#include "compat.h" +#include "debug.h" +#include "extract.h" +#include "iter.h" +#include "message.h" +#include "oid.h" +#include "pkcs11.h" +#include "pkcs11x.h" +#include "save.h" +#include "tool.h" + +#include <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static bool +filter_argument (const char *optarg, + P11KitUri **uri, + CK_ATTRIBUTE **match, + int *flags) +{ + CK_ATTRIBUTE *attrs; + int ret; + + CK_OBJECT_CLASS vcertificate = CKO_CERTIFICATE; + CK_ULONG vauthority = 2; + CK_CERTIFICATE_TYPE vx509 = CKC_X_509; + + CK_ATTRIBUTE certificate = { CKA_CLASS, &vcertificate, sizeof (vcertificate) }; + CK_ATTRIBUTE authority = { CKA_CERTIFICATE_CATEGORY, &vauthority, sizeof (vauthority) }; + CK_ATTRIBUTE x509 = { CKA_CERTIFICATE_TYPE, &vx509, sizeof (vx509) }; + + if (strncmp (optarg, "pkcs11:", 7) == 0) { + if (*uri != NULL) { + p11_message ("only one pkcs11 uri filter may be specified"); + return false; + } + *uri = p11_kit_uri_new (); + ret = p11_kit_uri_parse (optarg, P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE, *uri); + if (ret != P11_KIT_URI_OK) { + p11_message ("couldn't parse pkcs11 uri filter: %s", optarg); + return false; + } + return true; + } + + if (strcmp (optarg, "ca-anchors") == 0) { + attrs = p11_attrs_build (NULL, &certificate, &authority, &x509, NULL); + *flags |= P11_EXTRACT_ANCHORS | P11_EXTRACT_COLLAPSE; + + } else if (strcmp (optarg, "trust-policy") == 0) { + attrs = p11_attrs_build (NULL, &certificate, &x509, NULL); + *flags |= P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST | P11_EXTRACT_COLLAPSE; + + } else if (strcmp (optarg, "blacklist") == 0) { + attrs = p11_attrs_build (NULL, &certificate, &x509, NULL); + *flags |= P11_EXTRACT_BLACKLIST | P11_EXTRACT_COLLAPSE; + + } else if (strcmp (optarg, "certificates") == 0) { + attrs = p11_attrs_build (NULL, &certificate, &x509, NULL); + *flags |= P11_EXTRACT_COLLAPSE; + + } else { + p11_message ("unsupported or unrecognized filter: %s", optarg); + return false; + } + + if (*match != NULL) { + p11_message ("a conflicting filter has already been specified"); + p11_attrs_free (attrs); + return false; + } + + *match = attrs; + return true; +} + +static int +is_valid_oid_rough (const char *string) +{ + size_t len; + + len = strlen (string); + + /* Rough check if a valid OID */ + return (strspn (string, "0123456789.") == len && + !strstr (string, "..") && string[0] != '\0' && string[0] != '.' && + string[len - 1] != '.'); +} + +static bool +purpose_argument (const char *optarg, + p11_extract_info *ex) +{ + const char *oid; + + if (strcmp (optarg, "server-auth") == 0) { + oid = P11_OID_SERVER_AUTH_STR; + } else if (strcmp (optarg, "client-auth") == 0) { + oid = P11_OID_CLIENT_AUTH_STR; + } else if (strcmp (optarg, "email-protection") == 0 || strcmp (optarg, "email") == 0) { + oid = P11_OID_EMAIL_PROTECTION_STR; + } else if (strcmp (optarg, "code-signing") == 0) { + oid = P11_OID_CODE_SIGNING_STR; + } else if (strcmp (optarg, "ipsec-end-system") == 0) { + oid = P11_OID_IPSEC_END_SYSTEM_STR; + } else if (strcmp (optarg, "ipsec-tunnel") == 0) { + oid = P11_OID_IPSEC_TUNNEL_STR; + } else if (strcmp (optarg, "ipsec-user") == 0) { + oid = P11_OID_IPSEC_USER_STR; + } else if (strcmp (optarg, "time-stamping") == 0) { + oid = P11_OID_TIME_STAMPING_STR; + } else if (is_valid_oid_rough (optarg)) { + oid = optarg; + } else { + p11_message ("unsupported or unregonized purpose: %s", optarg); + return false; + } + + p11_extract_info_limit_purpose (ex, oid); + return true; +} + +static bool +format_argument (const char *optarg, + p11_extract_func *func) +{ + int i; + + /* + * Certain formats do not support expressive trust information. + * So the caller should limit the supported purposes when asking + * for trust information. + */ + + static const struct { + const char *format; + p11_extract_func func; + } formats[] = { + { "x509-file", p11_extract_x509_file, }, + { "x509-directory", p11_extract_x509_directory, }, + { "pem-bundle", p11_extract_pem_bundle, }, + { "pem-directory", p11_extract_pem_directory }, + { "java-cacerts", p11_extract_jks_cacerts }, + { "openssl-bundle", p11_extract_openssl_bundle }, + { "openssl-directory", p11_extract_openssl_directory }, + { NULL }, + }; + + if (*func != NULL) { + p11_message ("a format was already specified"); + return false; + } + + for (i = 0; formats[i].format != NULL; i++) { + if (strcmp (optarg, formats[i].format) == 0) { + *func = formats[i].func; + break; + } + } + + if (*func == NULL) { + p11_message ("unsupported or unrecognized format: %s", optarg); + return false; + } + + return true; +} + +static void +limit_modules_if_necessary (CK_FUNCTION_LIST_PTR *modules, + int flags) +{ + char *string; + int i, out; + + /* + * We only "believe" the CKA_TRUSTED and CKA_X_DISTRUSTED attributes + * we get from modules explicitly marked as containing trust-policy. + */ + + if ((flags & (P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST)) == 0) + return; + + /* Count the number of modules */ + for (out = 0; modules[out] != NULL; out++); + + if (out == 0) + return; + + /* TODO: This logic will move once we merge our p11-kit managed code */ + for (i = 0, out = 0; modules[i] != NULL; i++) { + string = p11_kit_config_option (modules[i], "trust-policy"); + if (string && strcmp (string, "yes") == 0) + modules[out++] = modules[i]; + else if (string && strcmp (string, "no") != 0) + p11_message ("skipping module with invalid 'trust-policy' setting: %s", string); + free (string); + } + + if (out == 0) + p11_message ("no modules containing trust policy are registered"); +} + +static bool +validate_filter_and_format (p11_extract_info *ex, + p11_extract_func func, + CK_ATTRIBUTE *match) +{ + int i; + + /* + * These are the extract functions that contain purpose information. + * If we're being asked to export anchors, and the extract function does + * not support, and the caller has not specified a purpose, then add a + * default purpose to limit to. + */ + + static p11_extract_func supports_trust_policy[] = { + p11_extract_openssl_bundle, + p11_extract_openssl_directory, + NULL + }; + + for (i = 0; supports_trust_policy[i] != NULL; i++) { + if (func == supports_trust_policy[i]) + return true; + } + + if ((ex->flags & P11_EXTRACT_ANCHORS) && + (ex->flags & P11_EXTRACT_BLACKLIST)) { + /* + * If we're extracting *both* anchors and blacklist, then we must have + * a format that can represent the different types of information. + */ + + p11_message ("format does not support trust policy"); + return false; + + } else if (ex->flags & P11_EXTRACT_ANCHORS) { + + /* + * If we're extracting anchors, then we must have either limited the + * purposes, or have a format that can represent multiple purposes. + */ + + if (!ex->limit_to_purposes) { + p11_message ("format does not support multiple purposes, defaulting to 'server-auth'"); + p11_extract_info_limit_purpose (ex, P11_OID_SERVER_AUTH_STR); + } + } + + return true; +} + +int +p11_trust_extract (int argc, + char **argv) +{ + p11_extract_func format = NULL; + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + p11_extract_info ex; + CK_ATTRIBUTE *match; + P11KitUri *uri; + int opt = 0; + int ret; + + enum { + opt_overwrite = 'f', + opt_verbose = 'v', + opt_quiet = 'q', + opt_help = 'h', + opt_filter = 1000, + opt_purpose, + opt_format, + opt_comment, + }; + + struct option options[] = { + { "filter", required_argument, NULL, opt_filter }, + { "format", required_argument, NULL, opt_format }, + { "purpose", required_argument, NULL, opt_purpose }, + { "overwrite", no_argument, NULL, opt_overwrite }, + { "comment", no_argument, NULL, opt_comment }, + { "verbose", no_argument, NULL, opt_verbose }, + { "quiet", no_argument, NULL, opt_quiet }, + { "help", no_argument, NULL, opt_help }, + { 0 }, + }; + + p11_tool_desc usages[] = { + { 0, "usage: p11-kit extract --format=<output> <destination>" }, + { opt_filter, + "filter of what to export\n" + " ca-anchors certificate anchors (default)\n" + " blacklist blacklisted certificates\n" + " trust-policy anchors and blacklist\n" + " certificates all certificates\n" + " pkcs11:object=xx a PKCS#11 URI", + "what", + }, + { opt_format, + "format to extract to\n" + " x509-file DER X.509 certificate file\n" + " x509-directory directory of X.509 certificates\n" + " pem-bundle file containing multiple PEM blocks\n" + " pem-directory directory of PEM files\n" + " openssl-bundle OpenSSL specific PEM bundle\n" + " openssl-directory directory of OpenSSL specific files\n" + " java-cacerts java keystore cacerts file", + "type" + }, + { opt_purpose, + "limit to certificates usable for the purpose\n" + " server-auth for authenticating servers\n" + " client-auth for authenticating clients\n" + " email for email protection\n" + " code-signing for authenticating signed code\n" + " 1.2.3.4.5... an arbitrary object id", + "usage" + }, + { opt_overwrite, "overwrite output file or directory" }, + { opt_comment, "add comments to bundles if possible" }, + { opt_verbose, "show verbose debug output", }, + { opt_quiet, "supress command output", }, + { 0 }, + }; + + match = NULL; + uri = NULL; + + p11_extract_info_init (&ex); + + while ((opt = p11_tool_getopt (argc, argv, options)) != -1) { + switch (opt) { + case opt_verbose: + case opt_quiet: + break; + + case opt_overwrite: + ex.flags |= P11_SAVE_OVERWRITE; + break; + case opt_comment: + ex.flags |= P11_EXTRACT_COMMENT; + break; + case opt_filter: + if (!filter_argument (optarg, &uri, &match, &ex.flags)) + return 2; + break; + case opt_purpose: + if (!purpose_argument (optarg, &ex)) + return 2; + break; + case opt_format: + if (!format_argument (optarg, &format)) + return 2; + break; + case 'h': + p11_tool_usage (usages, options); + return 0; + case '?': + return 2; + default: + assert_not_reached (); + break; + } + } while (opt != -1); + + argc -= optind; + argv += optind; + + if (argc != 1) { + p11_message ("specify one destination file or directory"); + return 2; + } + ex.destination = argv[0]; + + if (!format) { + p11_message ("no output format specified"); + return 2; + } + + /* If nothing that was useful to enumerate was specified, then bail */ + if (uri == NULL && match == NULL) { + p11_message ("no filter specified, defaulting to 'ca-anchors'"); + filter_argument ("ca-anchors", &uri, &match, &ex.flags); + } + + if (!validate_filter_and_format (&ex, format, match)) + return 1; + + if (uri && p11_kit_uri_any_unrecognized (uri)) + p11_message ("uri contained unrecognized components, nothing will be extracted"); + + modules = p11_kit_modules_load_and_initialize (0); + if (!modules) + return 1; + + limit_modules_if_necessary (modules, ex.flags); + + iter = p11_kit_iter_new (uri); + + p11_kit_iter_add_callback (iter, p11_extract_info_load_filter, &ex, NULL); + p11_kit_iter_add_filter (iter, match, p11_attrs_count (match)); + + p11_kit_iter_begin (iter, modules); + + ret = (format) (iter, &ex) ? 0 : 1; + + p11_extract_info_cleanup (&ex); + p11_kit_iter_free (iter); + p11_kit_uri_free (uri); + + p11_kit_modules_finalize (modules); + p11_kit_modules_release (modules); + + return ret; +} diff --git a/trust/extract.h b/trust/extract.h new file mode 100644 index 0000000..7db61c1 --- /dev/null +++ b/trust/extract.h @@ -0,0 +1,125 @@ +/* + * 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" + +#ifndef P11_EXTRACT_H_ +#define P11_EXTRACT_H_ + +#include "array.h" +#include "asn1.h" +#include "dict.h" +#include "iter.h" +#include "pkcs11.h" + +enum { + /* These overlap with the flags in save.h, so start higher */ + P11_EXTRACT_COMMENT = 1 << 10, + P11_EXTRACT_ANCHORS = 1 << 11, + P11_EXTRACT_BLACKLIST = 1 << 12, + P11_EXTRACT_COLLAPSE = 1 << 13, +}; + +typedef struct { + p11_dict *asn1_defs; + p11_dict *limit_to_purposes; + p11_dict *already_seen; + char *destination; + int flags; + + /* + * Stuff below is parsed info for the current iteration. + * Currently this information is generally all relevant + * just for certificates. + */ + + CK_OBJECT_CLASS klass; + CK_ATTRIBUTE *attrs; + + /* Pre-parsed data for certificates */ + node_asn *cert_asn; + const unsigned char *cert_der; + size_t cert_len; + + /* DER OID -> CK_ATTRIBUTE list */ + p11_dict *stapled; + + /* Set of OID purposes as strings */ + p11_array *purposes; +} p11_extract_info; + +void p11_extract_info_init (p11_extract_info *ex); + +CK_RV p11_extract_info_load_filter (P11KitIter *iter, + CK_BBOOL *matches, + void *data); + +void p11_extract_info_limit_purpose (p11_extract_info *ex, + const char *purpose); + +void p11_extract_info_cleanup (p11_extract_info *ex); + +char * p11_extract_info_filename (p11_extract_info *ex); + +char * p11_extract_info_comment (p11_extract_info *ex, + bool first); + +typedef bool (* p11_extract_func) (P11KitIter *iter, + p11_extract_info *ex); + +bool p11_extract_x509_file (P11KitIter *iter, + p11_extract_info *ex); + +bool p11_extract_x509_directory (P11KitIter *iter, + p11_extract_info *ex); + +bool p11_extract_pem_bundle (P11KitIter *iter, + p11_extract_info *ex); + +bool p11_extract_pem_directory (P11KitIter *iter, + p11_extract_info *ex); + +bool p11_extract_jks_cacerts (P11KitIter *iter, + p11_extract_info *ex); + +bool p11_extract_openssl_bundle (P11KitIter *iter, + p11_extract_info *ex); + +bool p11_extract_openssl_directory (P11KitIter *iter, + p11_extract_info *ex); + +int p11_trust_extract (int argc, + char **argv); + +#endif /* P11_EXTRACT_H_ */ diff --git a/trust/oid.c b/trust/oid.c new file mode 100644 index 0000000..b4b0bf6 --- /dev/null +++ b/trust/oid.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2012 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 "oid.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +/* + * We deal with OIDs a lot in their DER form. These have the + * advantage of having the length encoded in their second byte, + * at least for all the OIDs we're interested in. + * + * The goal here is to avoid carrying around extra length + * information about DER encoded OIDs. + */ + +bool +p11_oid_simple (const unsigned char *oid, + int len) +{ + return (oid != NULL && + len > 3 && /* minimum length */ + oid[0] == 0x06 && /* simple encoding */ + (oid[1] & 128) == 0 && /* short form length */ + (size_t)oid[1] == len - 2); /* matches length */ +} + +bool +p11_oid_equal (const void *oid_one, + const void *oid_two) +{ + int len_one; + int len_two; + + len_one = p11_oid_length (oid_one); + len_two = p11_oid_length (oid_two); + + return (len_one == len_two && + memcmp (oid_one, oid_two, len_one) == 0); +} + +int +p11_oid_length (const unsigned char *oid) +{ + assert (oid[0] == 0x06); + assert ((oid[1] & 128) == 0); + return (int)oid[1] + 2; +} diff --git a/trust/oid.h b/trust/oid.h new file mode 100644 index 0000000..dee6b10 --- /dev/null +++ b/trust/oid.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2012 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> + */ + +#ifndef P11_OIDS_H_ +#define P11_OIDS_H_ + +#include "compat.h" + +bool p11_oid_simple (const unsigned char *oid, + int len); + +bool p11_oid_equal (const void *oid_one, + const void *oid_two); + +int p11_oid_length (const unsigned char *oid); + +/* + * 2.5.4.3: CN or commonName + */ +static const unsigned char P11_OID_CN[] = + { 0x06, 0x03, 0x55, 0x04, 0x03, }; + +/* + * 2.5.4.10: O or organization + */ +static const unsigned char P11_OID_O[] = + { 0x06, 0x03, 0x55, 0x04, 0x0a, }; + +/* + * 2.5.4.11: OU or organizationalUnit + */ +static const unsigned char P11_OID_OU[] = + { 0x06, 0x03, 0x55, 0x04, 0x0b, }; + +/* + * Our support of certificate extensions and so on is not limited to what is + * listed here. This is simply the OIDs used by the parsing code that generates + * backwards compatible PKCS#11 objects for NSS and the like. + */ + +/* + * 2.5.29.14: SubjectKeyIdentifier + */ +static const unsigned char P11_OID_SUBJECT_KEY_IDENTIFIER[] = + { 0x06, 0x03, 0x55, 0x1d, 0x0e }; + +/* + * 2.5.29.15: KeyUsage + * + * Defined in RFC 5280 + */ +static const unsigned char P11_OID_KEY_USAGE[] = + { 0x06, 0x03, 0x55, 0x1d, 0x0f }; + +enum { + P11_KU_DIGITAL_SIGNATURE = 128, + P11_KU_NON_REPUDIATION = 64, + P11_KU_KEY_ENCIPHERMENT = 32, + P11_KU_DATA_ENCIPHERMENT = 16, + P11_KU_KEY_AGREEMENT = 8, + P11_KU_KEY_CERT_SIGN = 4, + P11_KU_CRL_SIGN = 2, + P11_KU_ENCIPHER_ONLY = 1, + P11_KU_DECIPHER_ONLY = 32768, +}; + +/* + * 2.5.29.19: BasicConstraints + * + * Defined in RFC 5280 + */ +static const unsigned char P11_OID_BASIC_CONSTRAINTS[] = + { 0x06, 0x03, 0x55, 0x1d, 0x13 }; + +/* + * 2.5.29.37: ExtendedKeyUsage + * + * Defined in RFC 5280 + */ +static const unsigned char P11_OID_EXTENDED_KEY_USAGE[] = + { 0x06, 0x03, 0x55, 0x1d, 0x25 }; + +/* + * 1.3.6.1.4.1.3319.6.10.1: OpenSSL reject extension + * + * An internally defined certificate extension. + * + * OpenSSL contains a list of OID extended key usages to reject. + * The normal X.509 model is to only *include* the extended key + * usages that are to be allowed (ie: a whitelist). It's not clear + * exactly how valid and useful the reject per extended key usage + * model is. + * + * However in order to parse openssl trust policy information and + * be able to write it back out in the same way, we define a custom + * certificate extension to store it. + * + * It is not expected (or supported) for others outside of p11-kit + * to read this information at this point. + * + * This extension is never marked critical. It is not necessary to + * respect information in this certificate extension given that the + * ExtendedKeyUsage extension carries the same information as a + * whitelist. + */ +static const unsigned char P11_OID_OPENSSL_REJECT[] = + { 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x99, 0x77, 0x06, 0x0a, 0x01 }; + +/* + * 1.3.6.1.5.5.7.3.1: Server Auth + * + * Defined in RFC 5280 + */ +static const unsigned char P11_OID_SERVER_AUTH[] = + { 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01 }; +static const char P11_OID_SERVER_AUTH_STR[] = "1.3.6.1.5.5.7.3.1"; + +/* + * 1.3.6.1.5.5.7.3.2: Client Auth + * + * Defined in RFC 5280 + */ +static const unsigned char P11_OID_CLIENT_AUTH[] = + { 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02 }; +static const char P11_OID_CLIENT_AUTH_STR[] = "1.3.6.1.5.5.7.3.2"; + +/* + * 1.3.6.1.5.5.7.3.3: Code Signing + * + * Defined in RFC 5280 + */ +static const unsigned char P11_OID_CODE_SIGNING[] = + { 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03 }; +static const char P11_OID_CODE_SIGNING_STR[] = "1.3.6.1.5.5.7.3.3"; + +/* + * 1.3.6.1.5.5.7.3.4: Email Protection + * + * Defined in RFC 5280 + */ +static const unsigned char P11_OID_EMAIL_PROTECTION[] = + { 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04 }; +static const char P11_OID_EMAIL_PROTECTION_STR[] = "1.3.6.1.5.5.7.3.4"; + +/* + * 1.3.6.1.5.5.7.3.5: IPSec End System + * + * Defined in RFC 2459 + */ +static const unsigned char P11_OID_IPSEC_END_SYSTEM[] = + { 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x05 }; +static const char P11_OID_IPSEC_END_SYSTEM_STR[] = "1.3.6.1.5.5.7.3.5"; + +/* + * 1.3.6.1.5.5.7.3.6: IPSec Tunnel + * + * Defined in RFC 2459 + */ +static const unsigned char P11_OID_IPSEC_TUNNEL[] = + { 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x06 }; +static const char P11_OID_IPSEC_TUNNEL_STR[] = "1.3.6.1.5.5.7.3.6"; + +/* + * 1.3.6.1.5.5.7.3.7: IPSec User + * + * Defined in RFC 2459 + */ +static const unsigned char P11_OID_IPSEC_USER[] = + { 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x07 }; +static const char P11_OID_IPSEC_USER_STR[] = "1.3.6.1.5.5.7.3.7"; + +/* + * 1.3.6.1.5.5.7.3.8: Time Stamping + * + * Defined in RFC 2459 + */ +static const unsigned char P11_OID_TIME_STAMPING[] = + { 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x08 }; +static const char P11_OID_TIME_STAMPING_STR[] = "1.3.6.1.5.5.7.3.8"; +/* + * 1.3.6.1.4.1.3319.6.10.16: Reserved key purpose + * + * An internally defined reserved/dummy key purpose + * + * This is used with ExtendedKeyUsage certificate extensions to + * be a place holder when no other purposes are defined. + * + * In theory such a certificate should be blacklisted. But in reality + * many implementations use such empty sets of purposes. RFC 5280 requires + * at least one purpose in an ExtendedKeyUsage. + * + * Obviously this purpose should never be checked against. + */ +static const unsigned char P11_OID_RESERVED_PURPOSE[] = + { 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x99, 0x77, 0x06, 0x0a, 0x10 }; +static const char P11_OID_RESERVED_PURPOSE_STR[] = "1.3.6.1.4.1.3319.6.10.16"; + +#endif diff --git a/trust/openssl.asn b/trust/openssl.asn new file mode 100644 index 0000000..c1f452b --- /dev/null +++ b/trust/openssl.asn @@ -0,0 +1,28 @@ + +OPENSSL { } + +DEFINITIONS IMPLICIT TAGS ::= + +BEGIN + +-- This module contains structures specific to OpenSSL + +CertAux ::= SEQUENCE { + trust SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + reject [0] SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + alias UTF8String OPTIONAL, + keyid OCTET STRING OPTIONAL, + other [1] SEQUENCE OF AlgorithmIdentifier OPTIONAL +} + +-- Dependencies brought in from other modules + +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL +} + +UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING + -- The content of this type conforms to RFC 2279. + +END diff --git a/trust/openssl.asn.h b/trust/openssl.asn.h new file mode 100644 index 0000000..4e6b240 --- /dev/null +++ b/trust/openssl.asn.h @@ -0,0 +1,28 @@ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <libtasn1.h> + +const ASN1_ARRAY_TYPE openssl_asn1_tab[] = { + { "OPENSSL", 536875024, NULL }, + { NULL, 1073741836, NULL }, + { "CertAux", 1610612741, NULL }, + { "trust", 1610629131, NULL }, + { NULL, 12, NULL }, + { "reject", 1610637323, NULL }, + { NULL, 1073745928, "0"}, + { NULL, 12, NULL }, + { "alias", 1073758210, "UTF8String"}, + { "keyid", 1073758215, NULL }, + { "other", 536895499, NULL }, + { NULL, 1073745928, "1"}, + { NULL, 2, "AlgorithmIdentifier"}, + { "AlgorithmIdentifier", 1610612741, NULL }, + { "algorithm", 1073741836, NULL }, + { "parameters", 541081613, NULL }, + { "algorithm", 1, NULL }, + { "UTF8String", 536879111, NULL }, + { NULL, 4360, "12"}, + { NULL, 0, NULL } +}; diff --git a/trust/pem.c b/trust/pem.c new file mode 100644 index 0000000..7fe0076 --- /dev/null +++ b/trust/pem.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2012 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 "compat.h" +#include "base64.h" +#include "buffer.h" +#include "debug.h" +#include "pem.h" + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#define ARMOR_SUFF "-----" +#define ARMOR_SUFF_L 5 +#define ARMOR_PREF_BEGIN "-----BEGIN " +#define ARMOR_PREF_BEGIN_L 11 +#define ARMOR_PREF_END "-----END " +#define ARMOR_PREF_END_L 9 + +enum { + NONE = 0, + TRUSTED_CERTIFICATE, + CERTIFICATE +}; + +static const char * +pem_find_begin (const char *data, + size_t n_data, + char **type) +{ + const char *pref, *suff; + + /* Look for a prefix */ + pref = strnstr ((char *)data, ARMOR_PREF_BEGIN, n_data); + if (!pref) + return NULL; + + n_data -= (pref - data) + ARMOR_PREF_BEGIN_L; + data = pref + ARMOR_PREF_BEGIN_L; + + /* Look for the end of that begin */ + suff = strnstr ((char *)data, ARMOR_SUFF, n_data); + if (!suff) + return NULL; + + /* Make sure on the same line */ + if (memchr (pref, '\n', suff - pref)) + return NULL; + + if (type) { + pref += ARMOR_PREF_BEGIN_L; + assert (suff > pref); + *type = malloc (suff - pref + 1); + return_val_if_fail (*type != NULL, NULL); + memcpy (*type, pref, suff - pref); + (*type)[suff - pref] = 0; + } + + /* The byte after this ---BEGIN--- */ + return suff + ARMOR_SUFF_L; +} + +static const char * +pem_find_end (const char *data, + size_t n_data, + const char *type) +{ + const char *pref; + size_t n_type; + + /* Look for a prefix */ + pref = strnstr (data, ARMOR_PREF_END, n_data); + if (!pref) + return NULL; + + n_data -= (pref - data) + ARMOR_PREF_END_L; + data = pref + ARMOR_PREF_END_L; + + /* Next comes the type string */ + n_type = strlen (type); + if (n_type > n_data || strncmp ((char *)data, type, n_type) != 0) + return NULL; + + n_data -= n_type; + data += n_type; + + /* Next comes the suffix */ + if (ARMOR_SUFF_L > n_data || strncmp ((char *)data, ARMOR_SUFF, ARMOR_SUFF_L) != 0) + return NULL; + + /* The end of the data */ + return pref; +} + +static unsigned char * +pem_parse_block (const char *data, + size_t n_data, + size_t *n_decoded) +{ + const char *x, *hbeg, *hend; + const char *p, *end; + unsigned char *decoded; + size_t length; + int ret; + + assert (data != NULL); + assert (n_data != 0); + assert (n_decoded != NULL); + + p = data; + end = p + n_data; + + hbeg = hend = NULL; + + /* Try and find a pair of blank lines with only white space between */ + while (hend == NULL) { + x = memchr (p, '\n', end - p); + if (!x) + break; + ++x; + while (isspace (*x)) { + /* Found a second line, with only spaces between */ + if (*x == '\n') { + hbeg = data; + hend = x; + break; + /* Found a space between two lines */ + } else { + ++x; + } + } + + /* Try next line */ + p = x; + } + + /* Headers found? */ + if (hbeg && hend) { + data = hend; + n_data = end - data; + } + + length = (n_data * 3) / 4 + 1; + decoded = malloc (length); + return_val_if_fail (decoded != NULL, 0); + + ret = p11_b64_pton (data, n_data, decoded, length); + if (ret < 0) { + free (decoded); + return NULL; + } + + /* No need to parse headers for our use cases */ + + *n_decoded = ret; + return decoded; +} + +unsigned int +p11_pem_parse (const char *data, + size_t n_data, + p11_pem_sink sink, + void *user_data) +{ + const char *beg, *end; + unsigned int nfound = 0; + unsigned char *decoded = NULL; + size_t n_decoded = 0; + char *type; + + assert (data != NULL); + + while (n_data > 0) { + + /* This returns the first character after the PEM BEGIN header */ + beg = pem_find_begin (data, n_data, &type); + if (beg == NULL) + break; + + assert (type != NULL); + + /* This returns the character position before the PEM END header */ + end = pem_find_end (beg, n_data - (beg - data), type); + if (end == NULL) { + free (type); + break; + } + + if (beg != end) { + decoded = pem_parse_block (beg, end - beg, &n_decoded); + if (decoded) { + if (sink != NULL) + (sink) (type, decoded, n_decoded, user_data); + ++nfound; + free (decoded); + } + } + + free (type); + + /* Try for another block */ + end += ARMOR_SUFF_L; + n_data -= (const char *)end - (const char *)data; + data = end; + } + + return nfound; +} + +bool +p11_pem_write (const unsigned char *contents, + size_t length, + const char *type, + p11_buffer *buf) +{ + size_t estimate; + size_t prefix; + char *target; + int len; + + return_val_if_fail (contents || !length, false); + return_val_if_fail (type, false); + return_val_if_fail (buf, false); + + /* Estimate from base64 data. Algorithm from Glib reference */ + estimate = length * 4 / 3 + 7; + estimate += estimate / 64 + 1; + + p11_buffer_add (buf, ARMOR_PREF_BEGIN, ARMOR_PREF_BEGIN_L); + p11_buffer_add (buf, type, -1); + p11_buffer_add (buf, ARMOR_SUFF, ARMOR_SUFF_L); + + prefix = buf->len; + target = p11_buffer_append (buf, estimate); + return_val_if_fail (target != NULL, NULL); + + /* + * OpenSSL is absolutely certain that it wants its PEM base64 + * lines to be 64 characters in len. + */ + + len = p11_b64_ntop (contents, length, target, estimate, 64); + + assert (len > 0); + assert (len <= estimate); + buf->len = prefix + len; + + p11_buffer_add (buf, "\n", 1); + p11_buffer_add (buf, ARMOR_PREF_END, ARMOR_PREF_END_L); + p11_buffer_add (buf, type, -1); + p11_buffer_add (buf, ARMOR_SUFF, ARMOR_SUFF_L); + p11_buffer_add (buf, "\n", 1); + + return p11_buffer_ok (buf); +} diff --git a/trust/pem.h b/trust/pem.h new file mode 100644 index 0000000..7e4ce63 --- /dev/null +++ b/trust/pem.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 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> + */ + +#ifndef P11_PEM_H_ +#define P11_PEM_H_ + +#include "buffer.h" +#include "compat.h" + +#include <sys/types.h> + +typedef void (*p11_pem_sink) (const char *type, + const unsigned char *contents, + size_t length, + void *user_data); + +unsigned int p11_pem_parse (const char *input, + size_t length, + p11_pem_sink sink, + void *user_data); + +bool p11_pem_write (const unsigned char *contents, + size_t length, + const char *type, + p11_buffer *buf); + +#endif /* P11_PEM_H_ */ diff --git a/trust/pkix.asn b/trust/pkix.asn new file mode 100644 index 0000000..38bb028 --- /dev/null +++ b/trust/pkix.asn @@ -0,0 +1,566 @@ + +PKIX1 { } + +DEFINITIONS IMPLICIT TAGS ::= + +BEGIN + +-- This contains both PKIX1Implicit88 and RFC2630 ASN.1 modules. + +id-pkix OBJECT IDENTIFIER ::= + { iso(1) identified-organization(3) dod(6) internet(1) + security(5) mechanisms(5) pkix(7) } + +-- ISO arc for standard certificate and CRL extensions + +-- authority key identifier OID and syntax + +AuthorityKeyIdentifier ::= SEQUENCE { + keyIdentifier [0] KeyIdentifier OPTIONAL, + authorityCertIssuer [1] GeneralNames OPTIONAL, + authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + -- authorityCertIssuer and authorityCertSerialNumber shall both + -- be present or both be absgent + +KeyIdentifier ::= OCTET STRING + +-- subject key identifier OID and syntax + +SubjectKeyIdentifier ::= KeyIdentifier + +-- key usage extension OID and syntax + +KeyUsage ::= BIT STRING + +-- Directory string type -- + +DirectoryString ::= CHOICE { + teletexString TeletexString (SIZE (1..MAX)), + printableString PrintableString (SIZE (1..MAX)), + universalString UniversalString (SIZE (1..MAX)), + utf8String UTF8String (SIZE (1..MAX)), + bmpString BMPString (SIZE(1..MAX)), + -- IA5String is added here to handle old UID encoded as ia5String -- + -- See tests/userid/ for more information. It shouldn't be here, -- + -- so if it causes problems, considering dropping it. -- + ia5String IA5String (SIZE(1..MAX)) } + +SubjectAltName ::= GeneralNames + +GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + +GeneralName ::= CHOICE { + otherName [0] AnotherName, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ANY, +-- Changed to work with the libtasn1 parser. + directoryName [4] EXPLICIT RDNSequence, --Name, + ediPartyName [5] ANY, --EDIPartyName replaced by ANY to save memory + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } + +-- AnotherName replaces OTHER-NAME ::= TYPE-IDENTIFIER, as +-- TYPE-IDENTIFIER is not supported in the '88 ASN.1 syntax + +AnotherName ::= SEQUENCE { + type-id OBJECT IDENTIFIER, + value [0] EXPLICIT ANY DEFINED BY type-id } + +-- issuer alternative name extension OID and syntax + +IssuerAltName ::= GeneralNames + +-- basic constraints extension OID and syntax + +BasicConstraints ::= SEQUENCE { + cA BOOLEAN DEFAULT FALSE, + pathLenConstraint INTEGER (0..MAX) OPTIONAL } + +-- CRL distribution points extension OID and syntax + +CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + +DistributionPoint ::= SEQUENCE { + distributionPoint [0] EXPLICIT DistributionPointName OPTIONAL, + reasons [1] ReasonFlags OPTIONAL, + cRLIssuer [2] GeneralNames OPTIONAL +} + +DistributionPointName ::= CHOICE { + fullName [0] GeneralNames, + nameRelativeToCRLIssuer [1] RelativeDistinguishedName +} + +ReasonFlags ::= BIT STRING + +-- extended key usage extension OID and syntax + +ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + +KeyPurposeId ::= OBJECT IDENTIFIER + +-- CRL number extension OID and syntax + +CRLNumber ::= INTEGER (0..MAX) + +-- certificate issuer CRL entry extension OID and syntax + +CertificateIssuer ::= GeneralNames + +-- -------------------------------------- +-- EXPLICIT +-- -------------------------------------- + +-- UNIVERSAL Types defined in '93 and '98 ASN.1 +-- but required by this specification + +NumericString ::= [UNIVERSAL 18] IMPLICIT OCTET STRING + +IA5String ::= [UNIVERSAL 22] IMPLICIT OCTET STRING + +TeletexString ::= [UNIVERSAL 20] IMPLICIT OCTET STRING + +PrintableString ::= [UNIVERSAL 19] IMPLICIT OCTET STRING + +UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING + -- UniversalString is defined in ASN.1:1993 + +BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING + -- BMPString is the subtype of UniversalString and models + -- the Basic Multilingual Plane of ISO/IEC/ITU 10646-1 + +UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING + -- The content of this type conforms to RFC 2279. + + +-- attribute data types -- + +Attribute ::= SEQUENCE { + type AttributeType, + values SET OF AttributeValue + -- at least one value is required -- +} + +AttributeType ::= OBJECT IDENTIFIER + +AttributeValue ::= ANY DEFINED BY type + +AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value AttributeValue } + +-- suggested naming attributes: Definition of the following +-- information object set may be augmented to meet local +-- requirements. Note that deleting members of the set may +-- prevent interoperability with conforming implementations. +-- presented in pairs: the AttributeType followed by the +-- type definition for the corresponding AttributeValue + +-- Arc for standard naming attributes +id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} + +-- Attributes of type NameDirectoryString + +-- gnutls: Note that the Object ID (id-at*) is being set just before the +-- actual definition. This is done in order for asn1_find_structure_from_oid +-- to work (locate structure from OID). +-- Maybe this is inefficient and memory consuming. Should we replace with +-- a table that maps OIDs to structures? + +PostalAddress ::= SEQUENCE OF DirectoryString + + -- Legacy attributes + +emailAddress AttributeType ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 1 } + +Pkcs9email ::= IA5String (SIZE (1..ub-emailaddress-length)) + +-- naming data types -- + +Name ::= CHOICE { -- only one possibility for now -- + rdnSequence RDNSequence } + +RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +DistinguishedName ::= RDNSequence + +RelativeDistinguishedName ::= + SET SIZE (1 .. MAX) OF AttributeTypeAndValue + + + +-- -------------------------------------------------------- +-- certificate and CRL specific structures begin here +-- -------------------------------------------------------- + +Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING } + +TBSCertificate ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + -- If present, version shall be v2 or v3 + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + -- If present, version shall be v2 or v3 + extensions [3] EXPLICIT Extensions OPTIONAL + -- If present, version shall be v3 -- +} + +Version ::= INTEGER { v1(0), v2(1), v3(2) } + +CertificateSerialNumber ::= INTEGER + +Validity ::= SEQUENCE { + notBefore Time, + notAfter Time } + +Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + +UniqueIdentifier ::= BIT STRING + +SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING } + +Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + +Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING } + + +-- ------------------------------------------ +-- CRL structures +-- ------------------------------------------ + +CertificateList ::= SEQUENCE { + tbsCertList TBSCertList, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING } + +TBSCertList ::= SEQUENCE { + version Version OPTIONAL, + -- if present, shall be v2 + signature AlgorithmIdentifier, + issuer Name, + thisUpdate Time, + nextUpdate Time OPTIONAL, + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, shall be v2 + } OPTIONAL, + crlExtensions [0] EXPLICIT Extensions OPTIONAL + -- if present, shall be v2 -- +} + +-- Version, Time, CertificateSerialNumber, and Extensions were +-- defined earlier for use in the certificate structure + +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL } + -- contains a value of the type + -- registered for use with the + -- algorithm object identifier value + +-- Algorithm OIDs and parameter structures + +Dss-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} + +DomainParameters ::= SEQUENCE { + p INTEGER, -- odd prime, p=jq +1 + g INTEGER, -- generator, g + q INTEGER, -- factor of p-1 + j INTEGER OPTIONAL, -- subgroup factor, j>= 2 + validationParms ValidationParms OPTIONAL } + +ValidationParms ::= SEQUENCE { + seed BIT STRING, + pgenCounter INTEGER } + +Dss-Parms ::= SEQUENCE { + p INTEGER, + q INTEGER, + g INTEGER } + +-- x400 address syntax starts here +-- OR Names + +CountryName ::= [APPLICATION 1] CHOICE { + x121-dcc-code NumericString + (SIZE (ub-country-name-numeric-length)), + iso-3166-alpha2-code PrintableString + (SIZE (ub-country-name-alpha-length)) } + +OrganizationName ::= PrintableString + (SIZE (1..ub-organization-name-length)) +-- see also teletex-organization-name + +NumericUserIdentifier ::= NumericString + (SIZE (1..ub-numeric-user-id-length)) + +-- see also teletex-personal-name + +OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units) + OF OrganizationalUnitName +-- see also teletex-organizational-unit-names + +OrganizationalUnitName ::= PrintableString (SIZE + (1..ub-organizational-unit-name-length)) + +-- Extension types and attribute values +-- + +CommonName ::= PrintableString + +-- END of PKIX1Implicit88 + + +-- BEGIN of RFC2630 + +-- Cryptographic Message Syntax + +pkcs-7-ContentInfo ::= SEQUENCE { + contentType pkcs-7-ContentType, + content [0] EXPLICIT ANY DEFINED BY contentType } + +pkcs-7-DigestInfo ::= SEQUENCE { + digestAlgorithm pkcs-7-DigestAlgorithmIdentifier, + digest pkcs-7-Digest +} + +pkcs-7-Digest ::= OCTET STRING + +pkcs-7-ContentType ::= OBJECT IDENTIFIER + +pkcs-7-SignedData ::= SEQUENCE { + version pkcs-7-CMSVersion, + digestAlgorithms pkcs-7-DigestAlgorithmIdentifiers, + encapContentInfo pkcs-7-EncapsulatedContentInfo, + certificates [0] IMPLICIT pkcs-7-CertificateSet OPTIONAL, + crls [1] IMPLICIT pkcs-7-CertificateRevocationLists OPTIONAL, + signerInfos pkcs-7-SignerInfos +} + +pkcs-7-CMSVersion ::= INTEGER { v0(0), v1(1), v2(2), v3(3), v4(4) } + +pkcs-7-DigestAlgorithmIdentifiers ::= SET OF pkcs-7-DigestAlgorithmIdentifier + +pkcs-7-DigestAlgorithmIdentifier ::= AlgorithmIdentifier + +pkcs-7-EncapsulatedContentInfo ::= SEQUENCE { + eContentType pkcs-7-ContentType, + eContent [0] EXPLICIT OCTET STRING OPTIONAL } + +-- We don't use CertificateList here since we only want +-- to read the raw data. +pkcs-7-CertificateRevocationLists ::= SET OF ANY + +pkcs-7-CertificateChoices ::= CHOICE { +-- Although the paper uses Certificate type, we +-- don't use it since, we don't need to parse it. +-- We only need to read and store it. + certificate ANY +} + +pkcs-7-CertificateSet ::= SET OF pkcs-7-CertificateChoices + +pkcs-7-SignerInfos ::= SET OF ANY -- this is not correct but we don't use it + -- anyway + + +-- BEGIN of RFC2986 + +-- Certificate requests +pkcs-10-CertificationRequestInfo ::= SEQUENCE { + version INTEGER { v1(0) }, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] Attributes +} + +Attributes ::= SET OF Attribute + +pkcs-10-CertificationRequest ::= SEQUENCE { + certificationRequestInfo pkcs-10-CertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +-- stuff from PKCS#9 + +pkcs-9-at-challengePassword OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 7} + +pkcs-9-challengePassword ::= CHOICE { + printableString PrintableString, + utf8String UTF8String } + +pkcs-9-localKeyId ::= OCTET STRING + +-- PKCS #8 stuff + +-- Private-key information syntax + +pkcs-8-PrivateKeyInfo ::= SEQUENCE { + version pkcs-8-Version, + privateKeyAlgorithm AlgorithmIdentifier, + privateKey pkcs-8-PrivateKey, + attributes [0] Attributes OPTIONAL } + +pkcs-8-Version ::= INTEGER {v1(0)} + +pkcs-8-PrivateKey ::= OCTET STRING + +pkcs-8-Attributes ::= SET OF Attribute + +-- Encrypted private-key information syntax + +pkcs-8-EncryptedPrivateKeyInfo ::= SEQUENCE { + encryptionAlgorithm AlgorithmIdentifier, + encryptedData pkcs-8-EncryptedData +} + +pkcs-8-EncryptedData ::= OCTET STRING + +-- PKCS #5 stuff + +pkcs-5-des-EDE3-CBC-params ::= OCTET STRING (SIZE(8)) +pkcs-5-aes128-CBC-params ::= OCTET STRING (SIZE(16)) +pkcs-5-aes192-CBC-params ::= OCTET STRING (SIZE(16)) +pkcs-5-aes256-CBC-params ::= OCTET STRING (SIZE(16)) + +pkcs-5-PBES2-params ::= SEQUENCE { + keyDerivationFunc AlgorithmIdentifier, + encryptionScheme AlgorithmIdentifier } + +-- PBKDF2 + +-- pkcs-5-algid-hmacWithSHA1 AlgorithmIdentifier ::= +-- {algorithm pkcs-5-id-hmacWithSHA1, parameters NULL : NULL} + +pkcs-5-PBKDF2-params ::= SEQUENCE { + salt CHOICE { + specified OCTET STRING, + otherSource AlgorithmIdentifier + }, + iterationCount INTEGER (1..MAX), + keyLength INTEGER (1..MAX) OPTIONAL, + prf AlgorithmIdentifier OPTIONAL -- DEFAULT pkcs-5-id-hmacWithSHA1 +} + +-- PKCS #12 stuff + +pkcs-12-PFX ::= SEQUENCE { + version INTEGER {v3(3)}, + authSafe pkcs-7-ContentInfo, + macData pkcs-12-MacData OPTIONAL +} + +pkcs-12-PbeParams ::= SEQUENCE { + salt OCTET STRING, + iterations INTEGER +} + +pkcs-12-MacData ::= SEQUENCE { + mac pkcs-7-DigestInfo, + macSalt OCTET STRING, + iterations INTEGER DEFAULT 1 +-- Note: The default is for historical reasons and its use is +-- deprecated. A higher value, like 1024 is recommended. +} + +pkcs-12-AuthenticatedSafe ::= SEQUENCE OF pkcs-7-ContentInfo + -- Data if unencrypted + -- EncryptedData if password-encrypted + -- EnvelopedData if public key-encrypted + +pkcs-12-SafeContents ::= SEQUENCE OF pkcs-12-SafeBag + +pkcs-12-SafeBag ::= SEQUENCE { + bagId OBJECT IDENTIFIER, + bagValue [0] EXPLICIT ANY DEFINED BY badId, + bagAttributes SET OF pkcs-12-PKCS12Attribute OPTIONAL +} + +-- Bag types + +pkcs-12-KeyBag ::= pkcs-8-PrivateKeyInfo + +-- Shrouded KeyBag + +pkcs-12-PKCS8ShroudedKeyBag ::= pkcs-8-EncryptedPrivateKeyInfo + +-- CertBag + +pkcs-12-CertBag ::= SEQUENCE { + certId OBJECT IDENTIFIER, + certValue [0] EXPLICIT ANY DEFINED BY certId +} + +-- x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {pkcs-9-certTypes 1}} +-- DER-encoded X.509 certificate stored in OCTET STRING + +pkcs-12-CRLBag ::= SEQUENCE { + crlId OBJECT IDENTIFIER, + crlValue [0] EXPLICIT ANY DEFINED BY crlId +} + +pkcs-12-SecretBag ::= SEQUENCE { + secretTypeId OBJECT IDENTIFIER, + secretValue [0] EXPLICIT ANY DEFINED BY secretTypeId +} + +-- x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {pkcs-9-crlTypes 1}} +-- DER-encoded X.509 CRL stored in OCTET STRING + +pkcs-12-PKCS12Attribute ::= Attribute + +-- PKCS #7 stuff (needed in PKCS 12) + +pkcs-7-Data ::= OCTET STRING + +pkcs-7-EncryptedData ::= SEQUENCE { + version pkcs-7-CMSVersion, + encryptedContentInfo pkcs-7-EncryptedContentInfo, + unprotectedAttrs [1] IMPLICIT pkcs-7-UnprotectedAttributes OPTIONAL } + +pkcs-7-EncryptedContentInfo ::= SEQUENCE { + contentType pkcs-7-ContentType, + contentEncryptionAlgorithm pkcs-7-ContentEncryptionAlgorithmIdentifier, + encryptedContent [0] IMPLICIT pkcs-7-EncryptedContent OPTIONAL } + +pkcs-7-ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + +pkcs-7-EncryptedContent ::= OCTET STRING + +pkcs-7-UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute + +-- rfc3820 + +ProxyCertInfo ::= SEQUENCE { + pCPathLenConstraint INTEGER (0..MAX) OPTIONAL, + proxyPolicy ProxyPolicy } + +ProxyPolicy ::= SEQUENCE { + policyLanguage OBJECT IDENTIFIER, + policy OCTET STRING OPTIONAL } + +END diff --git a/trust/pkix.asn.h b/trust/pkix.asn.h new file mode 100644 index 0000000..d5d5cc4 --- /dev/null +++ b/trust/pkix.asn.h @@ -0,0 +1,408 @@ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <libtasn1.h> + +const ASN1_ARRAY_TYPE pkix_asn1_tab[] = { + { "PKIX1", 536875024, NULL }, + { NULL, 1073741836, NULL }, + { "id-pkix", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "identified-organization", 1073741825, "3"}, + { "dod", 1073741825, "6"}, + { "internet", 1073741825, "1"}, + { "security", 1073741825, "5"}, + { "mechanisms", 1073741825, "5"}, + { "pkix", 1, "7"}, + { "AuthorityKeyIdentifier", 1610612741, NULL }, + { "keyIdentifier", 1610637314, "KeyIdentifier"}, + { NULL, 4104, "0"}, + { "authorityCertIssuer", 1610637314, "GeneralNames"}, + { NULL, 4104, "1"}, + { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"}, + { NULL, 4104, "2"}, + { "KeyIdentifier", 1073741831, NULL }, + { "SubjectKeyIdentifier", 1073741826, "KeyIdentifier"}, + { "KeyUsage", 1073741830, NULL }, + { "DirectoryString", 1610612754, NULL }, + { "teletexString", 1612709890, "TeletexString"}, + { "MAX", 524298, "1"}, + { "printableString", 1612709890, "PrintableString"}, + { "MAX", 524298, "1"}, + { "universalString", 1612709890, "UniversalString"}, + { "MAX", 524298, "1"}, + { "utf8String", 1612709890, "UTF8String"}, + { "MAX", 524298, "1"}, + { "bmpString", 1612709890, "BMPString"}, + { "MAX", 524298, "1"}, + { "ia5String", 538968066, "IA5String"}, + { "MAX", 524298, "1"}, + { "SubjectAltName", 1073741826, "GeneralNames"}, + { "GeneralNames", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "GeneralName"}, + { "GeneralName", 1610612754, NULL }, + { "otherName", 1610620930, "AnotherName"}, + { NULL, 4104, "0"}, + { "rfc822Name", 1610620930, "IA5String"}, + { NULL, 4104, "1"}, + { "dNSName", 1610620930, "IA5String"}, + { NULL, 4104, "2"}, + { "x400Address", 1610620941, NULL }, + { NULL, 4104, "3"}, + { "directoryName", 1610620930, "RDNSequence"}, + { NULL, 2056, "4"}, + { "ediPartyName", 1610620941, NULL }, + { NULL, 4104, "5"}, + { "uniformResourceIdentifier", 1610620930, "IA5String"}, + { NULL, 4104, "6"}, + { "iPAddress", 1610620935, NULL }, + { NULL, 4104, "7"}, + { "registeredID", 536879116, NULL }, + { NULL, 4104, "8"}, + { "AnotherName", 1610612741, NULL }, + { "type-id", 1073741836, NULL }, + { "value", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "type-id", 1, NULL }, + { "IssuerAltName", 1073741826, "GeneralNames"}, + { "BasicConstraints", 1610612741, NULL }, + { "cA", 1610645508, NULL }, + { NULL, 131081, NULL }, + { "pathLenConstraint", 537411587, NULL }, + { "0", 10, "MAX"}, + { "CRLDistributionPoints", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "DistributionPoint"}, + { "DistributionPoint", 1610612741, NULL }, + { "distributionPoint", 1610637314, "DistributionPointName"}, + { NULL, 2056, "0"}, + { "reasons", 1610637314, "ReasonFlags"}, + { NULL, 4104, "1"}, + { "cRLIssuer", 536895490, "GeneralNames"}, + { NULL, 4104, "2"}, + { "DistributionPointName", 1610612754, NULL }, + { "fullName", 1610620930, "GeneralNames"}, + { NULL, 4104, "0"}, + { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"}, + { NULL, 4104, "1"}, + { "ReasonFlags", 1073741830, NULL }, + { "ExtKeyUsageSyntax", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "KeyPurposeId"}, + { "KeyPurposeId", 1073741836, NULL }, + { "CRLNumber", 1611137027, NULL }, + { "0", 10, "MAX"}, + { "CertificateIssuer", 1073741826, "GeneralNames"}, + { "NumericString", 1610620935, NULL }, + { NULL, 4360, "18"}, + { "IA5String", 1610620935, NULL }, + { NULL, 4360, "22"}, + { "TeletexString", 1610620935, NULL }, + { NULL, 4360, "20"}, + { "PrintableString", 1610620935, NULL }, + { NULL, 4360, "19"}, + { "UniversalString", 1610620935, NULL }, + { NULL, 4360, "28"}, + { "BMPString", 1610620935, NULL }, + { NULL, 4360, "30"}, + { "UTF8String", 1610620935, NULL }, + { NULL, 4360, "12"}, + { "Attribute", 1610612741, NULL }, + { "type", 1073741826, "AttributeType"}, + { "values", 536870927, NULL }, + { NULL, 2, "AttributeValue"}, + { "AttributeType", 1073741836, NULL }, + { "AttributeValue", 1614807053, NULL }, + { "type", 1, NULL }, + { "AttributeTypeAndValue", 1610612741, NULL }, + { "type", 1073741826, "AttributeType"}, + { "value", 2, "AttributeValue"}, + { "id-at", 1879048204, NULL }, + { "joint-iso-ccitt", 1073741825, "2"}, + { "ds", 1073741825, "5"}, + { NULL, 1, "4"}, + { "PostalAddress", 1610612747, NULL }, + { NULL, 2, "DirectoryString"}, + { "emailAddress", 1880096780, "AttributeType"}, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "rsadsi", 1073741825, "113549"}, + { "pkcs", 1073741825, "1"}, + { NULL, 1073741825, "9"}, + { NULL, 1, "1"}, + { "Pkcs9email", 1612709890, "IA5String"}, + { "ub-emailaddress-length", 524298, "1"}, + { "Name", 1610612754, NULL }, + { "rdnSequence", 2, "RDNSequence"}, + { "RDNSequence", 1610612747, NULL }, + { NULL, 2, "RelativeDistinguishedName"}, + { "DistinguishedName", 1073741826, "RDNSequence"}, + { "RelativeDistinguishedName", 1612709903, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "AttributeTypeAndValue"}, + { "Certificate", 1610612741, NULL }, + { "tbsCertificate", 1073741826, "TBSCertificate"}, + { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "signature", 6, NULL }, + { "TBSCertificate", 1610612741, NULL }, + { "version", 1610653698, "Version"}, + { NULL, 1073741833, "v1"}, + { NULL, 2056, "0"}, + { "serialNumber", 1073741826, "CertificateSerialNumber"}, + { "signature", 1073741826, "AlgorithmIdentifier"}, + { "issuer", 1073741826, "Name"}, + { "validity", 1073741826, "Validity"}, + { "subject", 1073741826, "Name"}, + { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"}, + { "issuerUniqueID", 1610637314, "UniqueIdentifier"}, + { NULL, 4104, "1"}, + { "subjectUniqueID", 1610637314, "UniqueIdentifier"}, + { NULL, 4104, "2"}, + { "extensions", 536895490, "Extensions"}, + { NULL, 2056, "3"}, + { "Version", 1610874883, NULL }, + { "v1", 1073741825, "0"}, + { "v2", 1073741825, "1"}, + { "v3", 1, "2"}, + { "CertificateSerialNumber", 1073741827, NULL }, + { "Validity", 1610612741, NULL }, + { "notBefore", 1073741826, "Time"}, + { "notAfter", 2, "Time"}, + { "Time", 1610612754, NULL }, + { "utcTime", 1090519057, NULL }, + { "generalTime", 8388625, NULL }, + { "UniqueIdentifier", 1073741830, NULL }, + { "SubjectPublicKeyInfo", 1610612741, NULL }, + { "algorithm", 1073741826, "AlgorithmIdentifier"}, + { "subjectPublicKey", 6, NULL }, + { "Extensions", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "Extension"}, + { "Extension", 1610612741, NULL }, + { "extnID", 1073741836, NULL }, + { "critical", 1610645508, NULL }, + { NULL, 131081, NULL }, + { "extnValue", 7, NULL }, + { "CertificateList", 1610612741, NULL }, + { "tbsCertList", 1073741826, "TBSCertList"}, + { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "signature", 6, NULL }, + { "TBSCertList", 1610612741, NULL }, + { "version", 1073758210, "Version"}, + { "signature", 1073741826, "AlgorithmIdentifier"}, + { "issuer", 1073741826, "Name"}, + { "thisUpdate", 1073741826, "Time"}, + { "nextUpdate", 1073758210, "Time"}, + { "revokedCertificates", 1610629131, NULL }, + { NULL, 536870917, NULL }, + { "userCertificate", 1073741826, "CertificateSerialNumber"}, + { "revocationDate", 1073741826, "Time"}, + { "crlEntryExtensions", 16386, "Extensions"}, + { "crlExtensions", 536895490, "Extensions"}, + { NULL, 2056, "0"}, + { "AlgorithmIdentifier", 1610612741, NULL }, + { "algorithm", 1073741836, NULL }, + { "parameters", 541081613, NULL }, + { "algorithm", 1, NULL }, + { "Dss-Sig-Value", 1610612741, NULL }, + { "r", 1073741827, NULL }, + { "s", 3, NULL }, + { "DomainParameters", 1610612741, NULL }, + { "p", 1073741827, NULL }, + { "g", 1073741827, NULL }, + { "q", 1073741827, NULL }, + { "j", 1073758211, NULL }, + { "validationParms", 16386, "ValidationParms"}, + { "ValidationParms", 1610612741, NULL }, + { "seed", 1073741830, NULL }, + { "pgenCounter", 3, NULL }, + { "Dss-Parms", 1610612741, NULL }, + { "p", 1073741827, NULL }, + { "q", 1073741827, NULL }, + { "g", 3, NULL }, + { "CountryName", 1610620946, NULL }, + { NULL, 1073746952, "1"}, + { "x121-dcc-code", 1612709890, "NumericString"}, + { NULL, 1048586, "ub-country-name-numeric-length"}, + { "iso-3166-alpha2-code", 538968066, "PrintableString"}, + { NULL, 1048586, "ub-country-name-alpha-length"}, + { "OrganizationName", 1612709890, "PrintableString"}, + { "ub-organization-name-length", 524298, "1"}, + { "NumericUserIdentifier", 1612709890, "NumericString"}, + { "ub-numeric-user-id-length", 524298, "1"}, + { "OrganizationalUnitNames", 1612709899, NULL }, + { "ub-organizational-units", 1074266122, "1"}, + { NULL, 2, "OrganizationalUnitName"}, + { "OrganizationalUnitName", 1612709890, "PrintableString"}, + { "ub-organizational-unit-name-length", 524298, "1"}, + { "CommonName", 1073741826, "PrintableString"}, + { "pkcs-7-ContentInfo", 1610612741, NULL }, + { "contentType", 1073741826, "pkcs-7-ContentType"}, + { "content", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "contentType", 1, NULL }, + { "pkcs-7-DigestInfo", 1610612741, NULL }, + { "digestAlgorithm", 1073741826, "pkcs-7-DigestAlgorithmIdentifier"}, + { "digest", 2, "pkcs-7-Digest"}, + { "pkcs-7-Digest", 1073741831, NULL }, + { "pkcs-7-ContentType", 1073741836, NULL }, + { "pkcs-7-SignedData", 1610612741, NULL }, + { "version", 1073741826, "pkcs-7-CMSVersion"}, + { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"}, + { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"}, + { "certificates", 1610637314, "pkcs-7-CertificateSet"}, + { NULL, 4104, "0"}, + { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"}, + { NULL, 4104, "1"}, + { "signerInfos", 2, "pkcs-7-SignerInfos"}, + { "pkcs-7-CMSVersion", 1610874883, NULL }, + { "v0", 1073741825, "0"}, + { "v1", 1073741825, "1"}, + { "v2", 1073741825, "2"}, + { "v3", 1073741825, "3"}, + { "v4", 1, "4"}, + { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL }, + { NULL, 2, "pkcs-7-DigestAlgorithmIdentifier"}, + { "pkcs-7-DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, + { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL }, + { "eContentType", 1073741826, "pkcs-7-ContentType"}, + { "eContent", 536895495, NULL }, + { NULL, 2056, "0"}, + { "pkcs-7-CertificateRevocationLists", 1610612751, NULL }, + { NULL, 13, NULL }, + { "pkcs-7-CertificateChoices", 1610612754, NULL }, + { "certificate", 13, NULL }, + { "pkcs-7-CertificateSet", 1610612751, NULL }, + { NULL, 2, "pkcs-7-CertificateChoices"}, + { "pkcs-7-SignerInfos", 1610612751, NULL }, + { NULL, 13, NULL }, + { "pkcs-10-CertificationRequestInfo", 1610612741, NULL }, + { "version", 1610874883, NULL }, + { "v1", 1, "0"}, + { "subject", 1073741826, "Name"}, + { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"}, + { "attributes", 536879106, "Attributes"}, + { NULL, 4104, "0"}, + { "Attributes", 1610612751, NULL }, + { NULL, 2, "Attribute"}, + { "pkcs-10-CertificationRequest", 1610612741, NULL }, + { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"}, + { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "signature", 6, NULL }, + { "pkcs-9-at-challengePassword", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "rsadsi", 1073741825, "113549"}, + { "pkcs", 1073741825, "1"}, + { NULL, 1073741825, "9"}, + { NULL, 1, "7"}, + { "pkcs-9-challengePassword", 1610612754, NULL }, + { "printableString", 1073741826, "PrintableString"}, + { "utf8String", 2, "UTF8String"}, + { "pkcs-9-localKeyId", 1073741831, NULL }, + { "pkcs-8-PrivateKeyInfo", 1610612741, NULL }, + { "version", 1073741826, "pkcs-8-Version"}, + { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "privateKey", 1073741826, "pkcs-8-PrivateKey"}, + { "attributes", 536895490, "Attributes"}, + { NULL, 4104, "0"}, + { "pkcs-8-Version", 1610874883, NULL }, + { "v1", 1, "0"}, + { "pkcs-8-PrivateKey", 1073741831, NULL }, + { "pkcs-8-Attributes", 1610612751, NULL }, + { NULL, 2, "Attribute"}, + { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL }, + { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "encryptedData", 2, "pkcs-8-EncryptedData"}, + { "pkcs-8-EncryptedData", 1073741831, NULL }, + { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL }, + { NULL, 1048586, "8"}, + { "pkcs-5-aes128-CBC-params", 1612709895, NULL }, + { NULL, 1048586, "16"}, + { "pkcs-5-aes192-CBC-params", 1612709895, NULL }, + { NULL, 1048586, "16"}, + { "pkcs-5-aes256-CBC-params", 1612709895, NULL }, + { NULL, 1048586, "16"}, + { "pkcs-5-PBES2-params", 1610612741, NULL }, + { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"}, + { "encryptionScheme", 2, "AlgorithmIdentifier"}, + { "pkcs-5-PBKDF2-params", 1610612741, NULL }, + { "salt", 1610612754, NULL }, + { "specified", 1073741831, NULL }, + { "otherSource", 2, "AlgorithmIdentifier"}, + { "iterationCount", 1611137027, NULL }, + { "1", 10, "MAX"}, + { "keyLength", 1611153411, NULL }, + { "1", 10, "MAX"}, + { "prf", 16386, "AlgorithmIdentifier"}, + { "pkcs-12-PFX", 1610612741, NULL }, + { "version", 1610874883, NULL }, + { "v3", 1, "3"}, + { "authSafe", 1073741826, "pkcs-7-ContentInfo"}, + { "macData", 16386, "pkcs-12-MacData"}, + { "pkcs-12-PbeParams", 1610612741, NULL }, + { "salt", 1073741831, NULL }, + { "iterations", 3, NULL }, + { "pkcs-12-MacData", 1610612741, NULL }, + { "mac", 1073741826, "pkcs-7-DigestInfo"}, + { "macSalt", 1073741831, NULL }, + { "iterations", 536903683, NULL }, + { NULL, 9, "1"}, + { "pkcs-12-AuthenticatedSafe", 1610612747, NULL }, + { NULL, 2, "pkcs-7-ContentInfo"}, + { "pkcs-12-SafeContents", 1610612747, NULL }, + { NULL, 2, "pkcs-12-SafeBag"}, + { "pkcs-12-SafeBag", 1610612741, NULL }, + { "bagId", 1073741836, NULL }, + { "bagValue", 1614815245, NULL }, + { NULL, 1073743880, "0"}, + { "badId", 1, NULL }, + { "bagAttributes", 536887311, NULL }, + { NULL, 2, "pkcs-12-PKCS12Attribute"}, + { "pkcs-12-KeyBag", 1073741826, "pkcs-8-PrivateKeyInfo"}, + { "pkcs-12-PKCS8ShroudedKeyBag", 1073741826, "pkcs-8-EncryptedPrivateKeyInfo"}, + { "pkcs-12-CertBag", 1610612741, NULL }, + { "certId", 1073741836, NULL }, + { "certValue", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "certId", 1, NULL }, + { "pkcs-12-CRLBag", 1610612741, NULL }, + { "crlId", 1073741836, NULL }, + { "crlValue", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "crlId", 1, NULL }, + { "pkcs-12-SecretBag", 1610612741, NULL }, + { "secretTypeId", 1073741836, NULL }, + { "secretValue", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "secretTypeId", 1, NULL }, + { "pkcs-12-PKCS12Attribute", 1073741826, "Attribute"}, + { "pkcs-7-Data", 1073741831, NULL }, + { "pkcs-7-EncryptedData", 1610612741, NULL }, + { "version", 1073741826, "pkcs-7-CMSVersion"}, + { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"}, + { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"}, + { NULL, 4104, "1"}, + { "pkcs-7-EncryptedContentInfo", 1610612741, NULL }, + { "contentType", 1073741826, "pkcs-7-ContentType"}, + { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"}, + { "encryptedContent", 536895490, "pkcs-7-EncryptedContent"}, + { NULL, 4104, "0"}, + { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, + { "pkcs-7-EncryptedContent", 1073741831, NULL }, + { "pkcs-7-UnprotectedAttributes", 1612709903, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "Attribute"}, + { "ProxyCertInfo", 1610612741, NULL }, + { "pCPathLenConstraint", 1611153411, NULL }, + { "0", 10, "MAX"}, + { "proxyPolicy", 2, "ProxyPolicy"}, + { "ProxyPolicy", 536870917, NULL }, + { "policyLanguage", 1073741836, NULL }, + { "policy", 16391, NULL }, + { NULL, 0, NULL } +}; diff --git a/trust/save.c b/trust/save.c new file mode 100644 index 0000000..f1605a3 --- /dev/null +++ b/trust/save.c @@ -0,0 +1,537 @@ +/* + * 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 "buffer.h" +#include "debug.h" +#include "dict.h" +#include "message.h" +#include "save.h" + +#include <sys/stat.h> + +#include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct _p11_save_file { + char *path; + char *temp; + int fd; + int flags; +}; + +struct _p11_save_dir { + p11_dict *cache; + char *path; + int flags; +}; + +bool +p11_save_write_and_finish (p11_save_file *file, + const void *data, + ssize_t length) +{ + bool ret; + + if (!file) + return false; + + ret = p11_save_write (file, data, length); + if (!p11_save_finish_file (file, ret)) + ret = false; + + return ret; +} + +p11_save_file * +p11_save_open_file (const char *path, + int flags) +{ + struct stat st; + p11_save_file *file; + char *temp; + int fd; + + return_val_if_fail (path != NULL, NULL); + + /* + * This is just an early convenience check. We check again + * later when committing, in a non-racy fashion. + */ + + if (!(flags & P11_SAVE_OVERWRITE)) { + if (stat (path, &st) >= 0) { + p11_message ("file already exists: %s", path); + return NULL; + } + } + + if (asprintf (&temp, "%s.XXXXXX", path) < 0) + return_val_if_reached (NULL); + + fd = mkstemp (temp); + if (fd < 0) { + p11_message ("couldn't create file: %s: %s", + path, strerror (errno)); + free (temp); + return NULL; + } + + file = calloc (1, sizeof (p11_save_file)); + return_val_if_fail (file != NULL, NULL); + file->temp = temp; + file->path = strdup (path); + return_val_if_fail (file->path != NULL, NULL); + file->flags = flags; + file->fd = fd; + + return file; +} + +bool +p11_save_write (p11_save_file *file, + const void *data, + ssize_t length) +{ + const unsigned char *buf = data; + ssize_t written = 0; + ssize_t res; + + if (!file) + return false; + + /* Automatically calculate length */ + if (length < 0) { + if (!data) + return true; + length = strlen (data); + } + + while (written < length) { + res = write (file->fd, buf + written, length - written); + if (res <= 0) { + if (errno == EAGAIN && errno == EINTR) + continue; + p11_message ("couldn't write to file: %s: %s", + file->temp, strerror (errno)); + return false; + } else { + written += res; + } + } + + return true; +} + +static void +filo_free (p11_save_file *file) +{ + free (file->temp); + free (file->path); + free (file); +} + +bool +p11_save_finish_file (p11_save_file *file, + bool commit) +{ + bool ret = true; + + if (!file) + return false; + + if (!commit) { + close (file->fd); + unlink (file->temp); + filo_free (file); + return true; + } + + if (close (file->fd) < 0) { + p11_message ("couldn't write file: %s: %s", + file->temp, strerror (errno)); + ret = false; + +#ifdef OS_UNIX + /* Set the mode of the file, readable by everyone, but not writable */ + } else if (chmod (file->temp, S_IRUSR | S_IRGRP | S_IROTH) < 0) { + p11_message ("couldn't set file permissions: %s: %s", + file->temp, strerror (errno)); + close (file->fd); + ret = false; + + /* Atomically rename the tempfile over the filename */ + } else if (file->flags & P11_SAVE_OVERWRITE) { + if (rename (file->temp, file->path) < 0) { + p11_message ("couldn't complete writing file: %s: %s", + file->path, strerror (errno)); + ret = false; + } else { + unlink (file->temp); + } + + /* When not overwriting, link will fail if filename exists. */ + } else { + if (link (file->temp, file->path) < 0) { + p11_message ("couldn't complete writing of file: %s: %s", + file->path, strerror (errno)); + ret = false; + } + unlink (file->temp); + +#else /* OS_WIN32 */ + + /* Windows does not do atomic renames, so delete original file first */ + } else { + if (file->flags & P11_SAVE_OVERWRITE) { + if (unlink (file->path) < 0 && errno != ENOENT) { + p11_message ("couldn't remove original file: %s: %s", + file->path, strerror (errno)); + ret = false; + } + } + + if (ret == true) { + if (rename (file->temp, file->path) < 0) { + p11_message ("couldn't complete writing file: %s: %s", + file->path, strerror (errno)); + ret = false; + } + } + + unlink (file->temp); + +#endif /* OS_WIN32 */ + } + + filo_free (file); + return ret; +} + +p11_save_dir * +p11_save_open_directory (const char *path, + int flags) +{ +#ifdef OS_UNIX + struct stat sb; +#endif + p11_save_dir *dir; + + return_val_if_fail (path != NULL, NULL); + +#ifdef OS_UNIX + /* We update the permissions when we finish writing */ + if (mkdir (path, S_IRWXU) < 0) { +#else /* OS_WIN32 */ + if (mkdir (path) < 0) { +#endif + /* Some random error, report it */ + if (errno != EEXIST) { + p11_message ("couldn't create directory: %s: %s", path, strerror (errno)); + + /* The directory exists and we're not overwriting */ + } else if (!(flags & P11_SAVE_OVERWRITE)) { + p11_message ("directory already exists: %s", path); + return NULL; + } +#ifdef OS_UNIX + /* + * If the directory exists on unix, we may have restricted + * the directory permissions to read-only. We have to change + * them back to writable in order for things to work. + */ + if (stat (path, &sb) >= 0) { + if ((sb.st_mode & S_IRWXU) != S_IRWXU && + chmod (path, S_IRWXU | sb.st_mode) < 0) { + p11_message ("couldn't make directory writable: %s: %s", + path, strerror (errno)); + return NULL; + } + } +#endif /* OS_UNIX */ + } + + dir = calloc (1, sizeof (p11_save_dir)); + return_val_if_fail (dir != NULL, NULL); + + dir->path = strdup (path); + return_val_if_fail (dir->path != NULL, NULL); + + dir->cache = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); + return_val_if_fail (dir->cache != NULL, NULL); + + dir->flags = flags; + return dir; +} + +static char * +make_unique_name (p11_save_dir *dir, + const char *filename, + const char *extension) +{ + char unique[16]; + p11_buffer buf; + int i; + + p11_buffer_init_null (&buf, 0); + + for (i = 0; true; i++) { + + p11_buffer_reset (&buf, 64); + + switch (i) { + + /* + * For the first iteration, just build the filename as + * provided by the caller. + */ + case 0: + p11_buffer_add (&buf, filename, -1); + break; + + /* + * On later iterations we try to add a numeric .N suffix + * before the extension, so the resulting file might look + * like filename.1.ext. + * + * As a special case if the extension is already '.0' then + * just just keep incerementing that. + */ + case 1: + if (extension && strcmp (extension, ".0") == 0) + extension = NULL; + /* fall through */ + + default: + p11_buffer_add (&buf, filename, -1); + snprintf (unique, sizeof (unique), ".%d", i); + p11_buffer_add (&buf, unique, -1); + break; + } + + if (extension) + p11_buffer_add (&buf, extension, -1); + + return_val_if_fail (p11_buffer_ok (&buf), NULL); + + if (!p11_dict_get (dir->cache, buf.data)) + return p11_buffer_steal (&buf, NULL); + } + + assert_not_reached (); +} + +p11_save_file * +p11_save_open_file_in (p11_save_dir *dir, + const char *basename, + const char *extension, + const char **ret_name) +{ + p11_save_file *file = NULL; + char *name; + char *path; + + return_val_if_fail (dir != NULL, NULL); + return_val_if_fail (basename != NULL, NULL); + + name = make_unique_name (dir, basename, extension); + return_val_if_fail (name != NULL, NULL); + + if (asprintf (&path, "%s/%s", dir->path, name) < 0) + return_val_if_reached (NULL); + + file = p11_save_open_file (path, dir->flags); + + if (file) { + if (!p11_dict_set (dir->cache, name, name)) + return_val_if_reached (NULL); + if (ret_name) + *ret_name = name; + name = NULL; + } + + free (name); + free (path); + + return file; +} + +#ifdef OS_UNIX + +bool +p11_save_symlink_in (p11_save_dir *dir, + const char *linkname, + const char *extension, + const char *destination) +{ + char *name; + char *path; + bool ret; + + return_val_if_fail (dir != NULL, false); + return_val_if_fail (linkname != NULL, false); + return_val_if_fail (destination != NULL, false); + + name = make_unique_name (dir, linkname, extension); + return_val_if_fail (name != NULL, false); + + if (asprintf (&path, "%s/%s", dir->path, name) < 0) + return_val_if_reached (false); + + unlink (path); + + if (symlink (destination, path) < 0) { + p11_message ("couldn't create symlink: %s: %s", + path, strerror (errno)); + ret = false; + } else { + if (!p11_dict_set (dir->cache, name, name)) + return_val_if_reached (false); + name = NULL; + ret = true; + } + + free (path); + free (name); + + return ret; +} + +#endif /* OS_UNIX */ + +static bool +cleanup_directory (const char *directory, + p11_dict *cache) +{ + struct dirent *dp; + p11_dict *remove; + p11_dictiter iter; + char *path; + DIR *dir; + int skip; + bool ret; + + /* First we load all the modules */ + dir = opendir (directory); + if (!dir) { + p11_message ("couldn't list directory: %s: %s", + directory, strerror (errno)); + return false; + } + + remove = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); + + /* We're within a global mutex, so readdir is safe */ + while ((dp = readdir (dir)) != NULL) { + if (p11_dict_get (cache, dp->d_name)) + continue; + + if (asprintf (&path, "%s/%s", directory, dp->d_name) < 0) + return_val_if_reached (false); + +#ifdef HAVE_STRUCT_DIRENT_D_TYPE + if(dp->d_type != DT_UNKNOWN) { + skip = (dp->d_type == DT_DIR); + } else +#endif + { + struct stat st; + + skip = (stat (path, &st) < 0) || S_ISDIR (st.st_mode); + } + + if (!skip) { + if (!p11_dict_set (remove, path, path)) + return_val_if_reached (false); + } else { + free (path); + } + } + + closedir (dir); + + ret = true; + + /* Remove all the files still in the cache */ + p11_dict_iterate (remove, &iter); + while (p11_dict_next (&iter, (void **)&path, NULL)) { + if (unlink (path) < 0 && errno != ENOENT) { + p11_message ("couldn't remove file: %s: %s", + path, strerror (errno)); + ret = false; + break; + } + } + + p11_dict_free (remove); + + return ret; +} + +bool +p11_save_finish_directory (p11_save_dir *dir, + bool commit) +{ + bool ret = true; + + if (!dir) + return false; + + if (commit) { + if (dir->flags & P11_SAVE_OVERWRITE) + ret = cleanup_directory (dir->path, dir->cache); + +#ifdef OS_UNIX + /* Try to set the mode of the directory to readable */ + if (ret && chmod (dir->path, S_IRUSR | S_IXUSR | S_IRGRP | + S_IXGRP | S_IROTH | S_IXOTH) < 0) { + p11_message ("couldn't set directory permissions: %s: %s", + dir->path, strerror (errno)); + ret = false; + } +#endif /* OS_UNIX */ + } + + p11_dict_free (dir->cache); + free (dir->path); + free (dir); + + return ret; +} diff --git a/trust/save.h b/trust/save.h new file mode 100644 index 0000000..f68d054 --- /dev/null +++ b/trust/save.h @@ -0,0 +1,83 @@ +/* + * 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> + */ + +#ifndef P11_SAVE_H_ +#define P11_SAVE_H_ + +#include "compat.h" + +enum { + P11_SAVE_OVERWRITE = 1 << 0, +}; + +typedef struct _p11_save_file p11_save_file; +typedef struct _p11_save_dir p11_save_dir; + +p11_save_file * p11_save_open_file (const char *path, + int flags); + +bool p11_save_write (p11_save_file *file, + const void *data, + ssize_t length); + +bool p11_save_write_and_finish (p11_save_file *file, + const void *data, + ssize_t length); + +bool p11_save_finish_file (p11_save_file *file, + bool commit); + +const char * p11_save_file_name (p11_save_file *file); + +p11_save_dir * p11_save_open_directory (const char *path, + int flags); + +p11_save_file * p11_save_open_file_in (p11_save_dir *directory, + const char *basename, + const char *extension, + const char **filename); + +#ifdef OS_UNIX + +bool p11_save_symlink_in (p11_save_dir *dir, + const char *linkname, + const char *extension, + const char *destination); + +#endif /* OS_UNIX */ + +bool p11_save_finish_directory (p11_save_dir *dir, + bool commit); + +#endif /* P11_SAVE_H_ */ diff --git a/trust/tests/Makefile.am b/trust/tests/Makefile.am index abacab6..9d5b3ae 100644 --- a/trust/tests/Makefile.am +++ b/trust/tests/Makefile.am @@ -1,29 +1,36 @@ include $(top_srcdir)/build/Makefile.tests +COMMON = $(top_srcdir)/common +TRUST = $(top_srcdir)/trust + AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(srcdir)/.. \ - -I$(top_srcdir)/common \ + -I$(top_srcdir)/p11-kit \ + -I$(COMMON) \ -DDATADIR=\"$(datadir)\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ - $(TEST_CFLAGS) + -DP11_KIT_FUTURE_UNSTABLE_API \ + $(LIBTASN1_CFLAGS) \ + $(TEST_CFLAGS) \ + $(NULL) noinst_LTLIBRARIES = \ - libtestdata.la + libtrust-test.la -libtestdata_la_SOURCES = \ +libtrust_test_la_SOURCES = \ test-trust.c test-trust.h LDADD = \ $(top_builddir)/trust/libtrust-testable.la \ - $(top_builddir)/common/libp11-data.la \ + $(top_builddir)/trust/libtrust-data.la \ + $(builddir)/libtrust-test.la \ + $(top_builddir)/p11-kit/libp11-kit.la \ $(top_builddir)/common/libp11-library.la \ $(top_builddir)/common/libp11-test.la \ $(top_builddir)/common/libp11-common.la \ - $(builddir)/libtestdata.la \ $(LIBTASN1_LIBS) \ - $(CUTEST_LIBS) \ $(NULL) CHECK_PROGS = \ @@ -33,12 +40,28 @@ CHECK_PROGS = \ test-builder \ test-token \ test-module \ + test-save \ + test-extract \ + test-cer \ + test-bundle \ + test-openssl \ + test-asn1 \ + test-base64 \ + test-pem \ + test-oid \ + test-utf8 \ + test-x509 \ $(NULL) noinst_PROGRAMS = \ frob-pow \ frob-token \ frob-nss-trust \ + frob-cert \ + frob-ku \ + frob-eku \ + frob-cert \ + frob-oid \ $(CHECK_PROGS) frob_nss_trust_LDADD = \ @@ -51,3 +74,36 @@ EXTRA_DIST = \ input \ files \ $(NULL) + +TEST_RUNNER = libtool --mode=execute + +test_save_SOURCES = \ + test-save.c \ + $(TRUST)/save.c \ + $(NULL) + +test_extract_SOURCES = \ + test-extract.c \ + $(TRUST)/extract-info.c \ + $(NULL) + +test_cer_SOURCES = \ + test-cer.c \ + $(TRUST)/extract-info.c \ + $(TRUST)/extract-cer.c \ + $(TRUST)/save.c \ + $(NULL) + +test_bundle_SOURCES = \ + test-bundle.c \ + $(TRUST)/extract-info.c \ + $(TRUST)/extract-pem.c \ + $(TRUST)/save.c \ + $(NULL) + +test_openssl_SOURCES = \ + test-openssl.c \ + $(TRUST)/extract-info.c \ + $(TRUST)/extract-openssl.c \ + $(TRUST)/save.c \ + $(NULL) diff --git a/trust/tests/files/cacert3-distrust-all.pem b/trust/tests/files/cacert3-distrust-all.pem new file mode 100644 index 0000000..ce5d887 --- /dev/null +++ b/trust/tests/files/cacert3-distrust-all.pem @@ -0,0 +1,44 @@ +-----BEGIN TRUSTED CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ijBSoFAGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMG +CCsGAQUFBwMEBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQcD +CA== +-----END TRUSTED CERTIFICATE----- diff --git a/trust/tests/files/cacert3-distrusted-all.pem b/trust/tests/files/cacert3-distrusted-all.pem new file mode 100644 index 0000000..4a04a39 --- /dev/null +++ b/trust/tests/files/cacert3-distrusted-all.pem @@ -0,0 +1,43 @@ +-----BEGIN TRUSTED CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ijBIoEYGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMG +CCsGAQUFBwMFBggrBgEFBQcDBgYIKwYBBQUHAwcGCCsGAQUFBwMI +-----END TRUSTED CERTIFICATE----- diff --git a/trust/tests/files/cacert3-not-trusted.pem b/trust/tests/files/cacert3-not-trusted.pem new file mode 100644 index 0000000..eaa2e54 --- /dev/null +++ b/trust/tests/files/cacert3-not-trusted.pem @@ -0,0 +1,42 @@ +-----BEGIN TRUSTED CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ijACMAA= +-----END TRUSTED CERTIFICATE----- diff --git a/trust/tests/files/cacert3-trusted-alias.pem b/trust/tests/files/cacert3-trusted-alias.pem new file mode 100644 index 0000000..44601ea --- /dev/null +++ b/trust/tests/files/cacert3-trusted-alias.pem @@ -0,0 +1,42 @@ +-----BEGIN TRUSTED CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ijAODAxDdXN0b20gTGFiZWw= +-----END TRUSTED CERTIFICATE----- diff --git a/trust/tests/files/cacert3-trusted-keyid.pem b/trust/tests/files/cacert3-trusted-keyid.pem new file mode 100644 index 0000000..e652733 --- /dev/null +++ b/trust/tests/files/cacert3-trusted-keyid.pem @@ -0,0 +1,42 @@ +-----BEGIN TRUSTED CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ijAJBAcAAQIDBAUG +-----END TRUSTED CERTIFICATE----- diff --git a/trust/tests/files/cacert3-trusted-multiple.pem b/trust/tests/files/cacert3-trusted-multiple.pem new file mode 100644 index 0000000..e56a58f --- /dev/null +++ b/trust/tests/files/cacert3-trusted-multiple.pem @@ -0,0 +1,85 @@ +-----BEGIN TRUSTED CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ijAmMAoGCCsGAQUFBwMBoAoGCCsGAQUFBwMEDAxDdXN0b20g +TGFiZWw= +-----END TRUSTED CERTIFICATE----- +-----BEGIN TRUSTED CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ijAODAxDdXN0b20gTGFiZWw= +-----END TRUSTED CERTIFICATE----- diff --git a/trust/tests/files/cacert3-trusted-server-alias.pem b/trust/tests/files/cacert3-trusted-server-alias.pem new file mode 100644 index 0000000..55593ec --- /dev/null +++ b/trust/tests/files/cacert3-trusted-server-alias.pem @@ -0,0 +1,43 @@ +-----BEGIN TRUSTED CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ijAmMAoGCCsGAQUFBwMBoAoGCCsGAQUFBwMEDAxDdXN0b20g +TGFiZWw= +-----END TRUSTED CERTIFICATE----- diff --git a/trust/tests/files/cacert3-twice.pem b/trust/tests/files/cacert3-twice.pem new file mode 100644 index 0000000..c73202d --- /dev/null +++ b/trust/tests/files/cacert3-twice.pem @@ -0,0 +1,84 @@ +-----BEGIN CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ig== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ig== +-----END CERTIFICATE----- diff --git a/trust/tests/files/empty-file b/trust/tests/files/empty-file new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/trust/tests/files/empty-file diff --git a/trust/tests/files/simple-string b/trust/tests/files/simple-string new file mode 100644 index 0000000..be13474 --- /dev/null +++ b/trust/tests/files/simple-string @@ -0,0 +1 @@ +The simple string is hairy
\ No newline at end of file diff --git a/trust/tests/frob-cert.c b/trust/tests/frob-cert.c new file mode 100644 index 0000000..71018bd --- /dev/null +++ b/trust/tests/frob-cert.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2012 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@gnome.org> + */ + +#include "config.h" +#include "compat.h" + +#include <libtasn1.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pkix.asn.h" + +#define err_if_fail(ret, msg) \ + do { if ((ret) != ASN1_SUCCESS) { \ + fprintf (stderr, "%s: %s\n", msg, asn1_strerror (ret)); \ + exit (1); \ + } } while (0) + +static ssize_t +tlv_length (const unsigned char *data, + size_t length) +{ + unsigned char cls; + int counter = 0; + int cb, len; + unsigned long tag; + + if (asn1_get_tag_der (data, length, &cls, &cb, &tag) == ASN1_SUCCESS) { + counter += cb; + len = asn1_get_length_der (data + cb, length - cb, &cb); + counter += cb; + if (len >= 0) { + len += counter; + if (length >= len) + return len; + } + } + + return -1; +} + +int +main (int argc, + char *argv[]) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *definitions = NULL; + node_asn *cert = NULL; + p11_mmap *map; + void *data; + size_t size; + int start, end; + ssize_t len; + int ret; + + if (argc != 4) { + fprintf (stderr, "usage: frob-cert struct field filename\n"); + return 2; + } + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "definitions: %s\n", message); + return 1; + } + + ret = asn1_create_element (definitions, argv[1], &cert); + err_if_fail (ret, "Certificate"); + + map = p11_mmap_open (argv[3], &data, &size); + if (map == NULL) { + fprintf (stderr, "couldn't open file: %s\n", argv[3]); + return 1; + } + + ret = asn1_der_decoding (&cert, data, size, message); + err_if_fail (ret, message); + + ret = asn1_der_decoding_startEnd (cert, data, size, argv[2], &start, &end); + err_if_fail (ret, "asn1_der_decoding_startEnd"); + + len = tlv_length ((unsigned char *)data + start, size - start); + assert (len >= 0); + + fprintf (stderr, "%lu %d %d %ld\n", (unsigned long)size, start, end, (long)len); + fwrite ((unsigned char *)data + start, 1, len, stdout); + fflush (stdout); + + p11_mmap_close (map); + + asn1_delete_structure (&cert); + asn1_delete_structure (&definitions); + + return 0; +} diff --git a/trust/tests/frob-eku.c b/trust/tests/frob-eku.c new file mode 100644 index 0000000..42bf50b --- /dev/null +++ b/trust/tests/frob-eku.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2012 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@gnome.org> + */ + +#include "config.h" +#include "compat.h" + +#include <libtasn1.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pkix.asn.h" + +#define err_if_fail(ret, msg) \ + do { if ((ret) != ASN1_SUCCESS) { \ + fprintf (stderr, "%s: %s\n", msg, asn1_strerror (ret)); \ + exit (1); \ + } } while (0) + +int +main (int argc, + char *argv[]) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *definitions = NULL; + node_asn *ekus = NULL; + char *buf; + int len; + int ret; + int i; + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "definitions: %s\n", message); + return 1; + } + + ret = asn1_create_element (definitions, "PKIX1.ExtKeyUsageSyntax", &ekus); + err_if_fail (ret, "ExtKeyUsageSyntax"); + + for (i = 1; i < argc; i++) { + ret = asn1_write_value (ekus, "", "NEW", 1); + err_if_fail (ret, "NEW"); + + ret = asn1_write_value (ekus, "?LAST", argv[i], strlen (argv[i])); + err_if_fail (ret, "asn1_write_value"); + } + + len = 0; + ret = asn1_der_coding (ekus, "", NULL, &len, message); + assert (ret == ASN1_MEM_ERROR); + + buf = malloc (len); + assert (buf != NULL); + ret = asn1_der_coding (ekus, "", buf, &len, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "asn1_der_coding: %s\n", message); + return 1; + } + + fwrite (buf, 1, len, stdout); + fflush (stdout); + + asn1_delete_structure (&ekus); + asn1_delete_structure (&definitions); + + return 0; +} diff --git a/trust/tests/frob-ku.c b/trust/tests/frob-ku.c new file mode 100644 index 0000000..00d45c6 --- /dev/null +++ b/trust/tests/frob-ku.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012 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@gnome.org> + */ + +#include "config.h" +#include "compat.h" + +#include "oid.h" + +#include <libtasn1.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pkix.asn.h" + +#define err_if_fail(ret, msg) \ + do { if ((ret) != ASN1_SUCCESS) { \ + fprintf (stderr, "%s: %s\n", msg, asn1_strerror (ret)); \ + exit (1); \ + } } while (0) + +int +main (int argc, + char *argv[]) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *definitions = NULL; + node_asn *ku = NULL; + unsigned int usage = 0; + char bits[2]; + char *buf; + int len; + int ret; + int i; + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "digital-signature") == 0) + usage |= P11_KU_DIGITAL_SIGNATURE; + else if (strcmp (argv[i], "non-repudiation") == 0) + usage |= P11_KU_NON_REPUDIATION; + else if (strcmp (argv[i], "key-encipherment") == 0) + usage |= P11_KU_KEY_ENCIPHERMENT; + else if (strcmp (argv[i], "data-encipherment") == 0) + usage |= P11_KU_DATA_ENCIPHERMENT; + else if (strcmp (argv[i], "key-agreement") == 0) + usage |= P11_KU_KEY_AGREEMENT; + else if (strcmp (argv[i], "key-cert-sign") == 0) + usage |= P11_KU_KEY_CERT_SIGN; + else if (strcmp (argv[i], "crl-sign") == 0) + usage |= P11_KU_CRL_SIGN; + else { + fprintf (stderr, "unsupported or unknown key usage: %s\n", argv[i]); + return 2; + } + } + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "definitions: %s\n", message); + return 1; + } + + ret = asn1_create_element (definitions, "PKIX1.KeyUsage", &ku); + err_if_fail (ret, "KeyUsage"); + + bits[0] = usage & 0xff; + bits[1] = (usage >> 8) & 0xff; + + ret = asn1_write_value (ku, "", bits, 9); + err_if_fail (ret, "asn1_write_value"); + + len = 0; + ret = asn1_der_coding (ku, "", NULL, &len, message); + assert (ret == ASN1_MEM_ERROR); + + buf = malloc (len); + assert (buf != NULL); + ret = asn1_der_coding (ku, "", buf, &len, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "asn1_der_coding: %s\n", message); + return 1; + } + + fwrite (buf, 1, len, stdout); + fflush (stdout); + + asn1_delete_structure (&ku); + asn1_delete_structure (&definitions); + + return 0; +} diff --git a/trust/tests/frob-oid.c b/trust/tests/frob-oid.c new file mode 100644 index 0000000..b4c7658 --- /dev/null +++ b/trust/tests/frob-oid.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012 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@gnome.org> + */ + +#include "config.h" +#include "compat.h" + +#include <libtasn1.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pkix.asn.h" + +#define err_if_fail(ret, msg) \ + do { if ((ret) != ASN1_SUCCESS) { \ + fprintf (stderr, "%s: %s\n", msg, asn1_strerror (ret)); \ + exit (1); \ + } } while (0) +int +main (int argc, + char *argv[]) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *definitions = NULL; + node_asn *oid = NULL; + char *buf; + int len; + int ret; + + if (argc != 2) { + fprintf (stderr, "usage: frob-oid 1.1.1\n"); + return 2; + } + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "definitions: %s\n", message); + return 1; + } + + /* AttributeType is a OBJECT IDENTIFIER */ + ret = asn1_create_element (definitions, "PKIX1.AttributeType", &oid); + err_if_fail (ret, "AttributeType"); + + ret = asn1_write_value (oid, "", argv[1], strlen (argv[1])); + err_if_fail (ret, "asn1_write_value"); + + len = 0; + ret = asn1_der_coding (oid, "", NULL, &len, message); + assert (ret == ASN1_MEM_ERROR); + + buf = malloc (len); + assert (buf != NULL); + ret = asn1_der_coding (oid, "", buf, &len, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "asn1_der_coding: %s\n", message); + return 1; + } + + fwrite (buf, 1, len, stdout); + fflush (stdout); + + asn1_delete_structure (&oid); + asn1_delete_structure (&definitions); + + return 0; +} diff --git a/trust/tests/test-asn1.c b/trust/tests/test-asn1.c new file mode 100644 index 0000000..710928c --- /dev/null +++ b/trust/tests/test-asn1.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2012 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@gnome.org> + */ + +#include "config.h" +#include "test.h" + +#include "asn1.h" +#include "debug.h" +#include "oid.h" +#include "x509.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +struct { + p11_dict *asn1_defs; +} test; + +static void +setup (void *unused) +{ + test.asn1_defs = p11_asn1_defs_load (); + assert_ptr_not_null (test.asn1_defs); +} + +static void +teardown (void *unused) +{ + p11_dict_free (test.asn1_defs); + memset (&test, 0, sizeof (test)); +} + +static void +test_tlv_length (void) +{ + struct { + const char *der; + size_t der_len; + int expected; + } tlv_lengths[] = { + { "\x01\x01\x00", 3, 3 }, + { "\x01\x01\x00\x01\x02", 5, 3 }, + { "\x01\x05\x00", 3, -1 }, + { NULL } + }; + + int length; + int i; + + for (i = 0; tlv_lengths[i].der != NULL; i++) { + length = p11_asn1_tlv_length ((const unsigned char *)tlv_lengths[i].der, tlv_lengths[i].der_len); + assert_num_eq (tlv_lengths[i].expected, length); + } +} + +static const unsigned char test_eku_server_and_client[] = { + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, +}; + +static void +test_asn1_cache (void) +{ + p11_asn1_cache *cache; + p11_dict *defs; + node_asn *asn; + node_asn *check; + + cache = p11_asn1_cache_new (); + assert_ptr_not_null (cache); + + defs = p11_asn1_cache_defs (cache); + assert_ptr_not_null (defs); + + asn = p11_asn1_decode (defs, "PKIX1.ExtKeyUsageSyntax", + test_eku_server_and_client, + sizeof (test_eku_server_and_client), NULL); + assert_ptr_not_null (defs); + + /* Place the parsed data in the cache */ + p11_asn1_cache_take (cache, asn, "PKIX1.ExtKeyUsageSyntax", + test_eku_server_and_client, + sizeof (test_eku_server_and_client)); + + /* Get it back out */ + check = p11_asn1_cache_get (cache, "PKIX1.ExtKeyUsageSyntax", + test_eku_server_and_client, + sizeof (test_eku_server_and_client)); + assert_ptr_eq (asn, check); + + /* Flush should remove it */ + p11_asn1_cache_flush (cache); + check = p11_asn1_cache_get (cache, "PKIX1.ExtKeyUsageSyntax", + test_eku_server_and_client, + sizeof (test_eku_server_and_client)); + assert_ptr_eq (NULL, check); + + p11_asn1_cache_free (cache); +} + +int +main (int argc, + char *argv[]) +{ + p11_fixture (setup, teardown); + p11_test (test_tlv_length, "/asn1/tlv_length"); + + p11_fixture (NULL, NULL); + p11_test (test_asn1_cache, "/asn1/asn1_cache"); + + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-base64.c b/trust/tests/test-base64.c new file mode 100644 index 0000000..ce303e8 --- /dev/null +++ b/trust/tests/test-base64.c @@ -0,0 +1,204 @@ +/* + * 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 "test.h" + +#include "base64.h" +#include "debug.h" +#include "message.h" + +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +static void +check_decode_msg (const char *file, + int line, + const char *function, + const char *input, + ssize_t input_len, + const unsigned char *expected, + ssize_t expected_len) +{ + unsigned char decoded[8192]; + int length; + + if (input_len < 0) + input_len = strlen (input); + if (expected_len < 0) + expected_len = strlen ((char *)expected); + length = p11_b64_pton (input, input_len, decoded, sizeof (decoded)); + + if (expected == NULL) { + if (length >= 0) + p11_test_fail (file, line, function, "decoding should have failed"); + + } else { + if (length < 0) + p11_test_fail (file, line, function, "decoding failed"); + if (expected_len != length) + p11_test_fail (file, line, function, "wrong length: (%lu != %lu)", + (unsigned long)expected_len, (unsigned long)length); + if (memcmp (decoded, expected, length) != 0) + p11_test_fail (file, line, function, "decoded wrong"); + } +} + +#define check_decode_success(input, input_len, expected, expected_len) \ + check_decode_msg (__FILE__, __LINE__, __FUNCTION__, input, input_len, expected, expected_len) + +#define check_decode_failure(input, input_len) \ + check_decode_msg (__FILE__, __LINE__, __FUNCTION__, input, input_len, NULL, 0) + +static void +test_decode_simple (void) +{ + check_decode_success ("", 0, (unsigned char *)"", 0); + check_decode_success ("MQ==", 0, (unsigned char *)"1", 0); + check_decode_success ("YmxhaAo=", -1, (unsigned char *)"blah\n", -1); + check_decode_success ("bGVlbGEK", -1, (unsigned char *)"leela\n", -1); + check_decode_success ("bGVlbG9vCg==", -1, (unsigned char *)"leeloo\n", -1); +} + +static void +test_decode_thawte (void) +{ + const char *input = + "MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB" + "rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf" + "Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw" + "MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV" + "BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa" + "Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl" + "LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u" + "MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl" + "ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm" + "gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8" + "YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf" + "b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9" + "9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S" + "zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk" + "OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV" + "HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA" + "2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW" + "oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu" + "t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c" + "KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM" + "m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu" + "MdRAGmI0Nj81Aa6sY6A="; + + const unsigned char output[] = { + 0x30, 0x82, 0x04, 0x2a, 0x30, 0x82, 0x03, 0x12, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x60, + 0x01, 0x97, 0xb7, 0x46, 0xa7, 0xea, 0xb4, 0xb4, 0x9a, 0xd6, 0x4b, 0x2f, 0xf7, 0x90, 0xfb, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, + 0xae, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, + 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x31, + 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x38, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1b, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x34, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x17, 0x0d, 0x33, 0x37, 0x31, 0x32, 0x30, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, + 0x81, 0xae, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x1f, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, + 0x30, 0x30, 0x38, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x1b, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xb2, 0xbf, 0x27, 0x2c, 0xfb, 0xdb, 0xd8, 0x5b, 0xdd, 0x78, 0x7b, 0x1b, 0x9e, 0x77, 0x66, + 0x81, 0xcb, 0x3e, 0xbc, 0x7c, 0xae, 0xf3, 0xa6, 0x27, 0x9a, 0x34, 0xa3, 0x68, 0x31, 0x71, 0x38, + 0x33, 0x62, 0xe4, 0xf3, 0x71, 0x66, 0x79, 0xb1, 0xa9, 0x65, 0xa3, 0xa5, 0x8b, 0xd5, 0x8f, 0x60, + 0x2d, 0x3f, 0x42, 0xcc, 0xaa, 0x6b, 0x32, 0xc0, 0x23, 0xcb, 0x2c, 0x41, 0xdd, 0xe4, 0xdf, 0xfc, + 0x61, 0x9c, 0xe2, 0x73, 0xb2, 0x22, 0x95, 0x11, 0x43, 0x18, 0x5f, 0xc4, 0xb6, 0x1f, 0x57, 0x6c, + 0x0a, 0x05, 0x58, 0x22, 0xc8, 0x36, 0x4c, 0x3a, 0x7c, 0xa5, 0xd1, 0xcf, 0x86, 0xaf, 0x88, 0xa7, + 0x44, 0x02, 0x13, 0x74, 0x71, 0x73, 0x0a, 0x42, 0x59, 0x02, 0xf8, 0x1b, 0x14, 0x6b, 0x42, 0xdf, + 0x6f, 0x5f, 0xba, 0x6b, 0x82, 0xa2, 0x9d, 0x5b, 0xe7, 0x4a, 0xbd, 0x1e, 0x01, 0x72, 0xdb, 0x4b, + 0x74, 0xe8, 0x3b, 0x7f, 0x7f, 0x7d, 0x1f, 0x04, 0xb4, 0x26, 0x9b, 0xe0, 0xb4, 0x5a, 0xac, 0x47, + 0x3d, 0x55, 0xb8, 0xd7, 0xb0, 0x26, 0x52, 0x28, 0x01, 0x31, 0x40, 0x66, 0xd8, 0xd9, 0x24, 0xbd, + 0xf6, 0x2a, 0xd8, 0xec, 0x21, 0x49, 0x5c, 0x9b, 0xf6, 0x7a, 0xe9, 0x7f, 0x55, 0x35, 0x7e, 0x96, + 0x6b, 0x8d, 0x93, 0x93, 0x27, 0xcb, 0x92, 0xbb, 0xea, 0xac, 0x40, 0xc0, 0x9f, 0xc2, 0xf8, 0x80, + 0xcf, 0x5d, 0xf4, 0x5a, 0xdc, 0xce, 0x74, 0x86, 0xa6, 0x3e, 0x6c, 0x0b, 0x53, 0xca, 0xbd, 0x92, + 0xce, 0x19, 0x06, 0x72, 0xe6, 0x0c, 0x5c, 0x38, 0x69, 0xc7, 0x04, 0xd6, 0xbc, 0x6c, 0xce, 0x5b, + 0xf6, 0xf7, 0x68, 0x9c, 0xdc, 0x25, 0x15, 0x48, 0x88, 0xa1, 0xe9, 0xa9, 0xf8, 0x98, 0x9c, 0xe0, + 0xf3, 0xd5, 0x31, 0x28, 0x61, 0x11, 0x6c, 0x67, 0x96, 0x8d, 0x39, 0x99, 0xcb, 0xc2, 0x45, 0x24, + 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xad, 0x6c, 0xaa, 0x94, 0x60, 0x9c, 0xed, 0xe4, 0xff, 0xfa, + 0x3e, 0x0a, 0x74, 0x2b, 0x63, 0x03, 0xf7, 0xb6, 0x59, 0xbf, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x1a, 0x40, + 0xd8, 0x95, 0x65, 0xac, 0x09, 0x92, 0x89, 0xc6, 0x39, 0xf4, 0x10, 0xe5, 0xa9, 0x0e, 0x66, 0x53, + 0x5d, 0x78, 0xde, 0xfa, 0x24, 0x91, 0xbb, 0xe7, 0x44, 0x51, 0xdf, 0xc6, 0x16, 0x34, 0x0a, 0xef, + 0x6a, 0x44, 0x51, 0xea, 0x2b, 0x07, 0x8a, 0x03, 0x7a, 0xc3, 0xeb, 0x3f, 0x0a, 0x2c, 0x52, 0x16, + 0xa0, 0x2b, 0x43, 0xb9, 0x25, 0x90, 0x3f, 0x70, 0xa9, 0x33, 0x25, 0x6d, 0x45, 0x1a, 0x28, 0x3b, + 0x27, 0xcf, 0xaa, 0xc3, 0x29, 0x42, 0x1b, 0xdf, 0x3b, 0x4c, 0xc0, 0x33, 0x34, 0x5b, 0x41, 0x88, + 0xbf, 0x6b, 0x2b, 0x65, 0xaf, 0x28, 0xef, 0xb2, 0xf5, 0xc3, 0xaa, 0x66, 0xce, 0x7b, 0x56, 0xee, + 0xb7, 0xc8, 0xcb, 0x67, 0xc1, 0xc9, 0x9c, 0x1a, 0x18, 0xb8, 0xc4, 0xc3, 0x49, 0x03, 0xf1, 0x60, + 0x0e, 0x50, 0xcd, 0x46, 0xc5, 0xf3, 0x77, 0x79, 0xf7, 0xb6, 0x15, 0xe0, 0x38, 0xdb, 0xc7, 0x2f, + 0x28, 0xa0, 0x0c, 0x3f, 0x77, 0x26, 0x74, 0xd9, 0x25, 0x12, 0xda, 0x31, 0xda, 0x1a, 0x1e, 0xdc, + 0x29, 0x41, 0x91, 0x22, 0x3c, 0x69, 0xa7, 0xbb, 0x02, 0xf2, 0xb6, 0x5c, 0x27, 0x03, 0x89, 0xf4, + 0x06, 0xea, 0x9b, 0xe4, 0x72, 0x82, 0xe3, 0xa1, 0x09, 0xc1, 0xe9, 0x00, 0x19, 0xd3, 0x3e, 0xd4, + 0x70, 0x6b, 0xba, 0x71, 0xa6, 0xaa, 0x58, 0xae, 0xf4, 0xbb, 0xe9, 0x6c, 0xb6, 0xef, 0x87, 0xcc, + 0x9b, 0xbb, 0xff, 0x39, 0xe6, 0x56, 0x61, 0xd3, 0x0a, 0xa7, 0xc4, 0x5c, 0x4c, 0x60, 0x7b, 0x05, + 0x77, 0x26, 0x7a, 0xbf, 0xd8, 0x07, 0x52, 0x2c, 0x62, 0xf7, 0x70, 0x63, 0xd9, 0x39, 0xbc, 0x6f, + 0x1c, 0xc2, 0x79, 0xdc, 0x76, 0x29, 0xaf, 0xce, 0xc5, 0x2c, 0x64, 0x04, 0x5e, 0x88, 0x36, 0x6e, + 0x31, 0xd4, 0x40, 0x1a, 0x62, 0x34, 0x36, 0x3f, 0x35, 0x01, 0xae, 0xac, 0x63, 0xa0, + }; + + check_decode_success (input, -1, output, sizeof (output)); +} + +int +main (int argc, + char *argv[]) +{ + p11_test (test_decode_simple, "/base64/decode-simple"); + p11_test (test_decode_thawte, "/base64/decode-thawte"); + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-bundle.c b/trust/tests/test-bundle.c new file mode 100644 index 0000000..bff135e --- /dev/null +++ b/trust/tests/test-bundle.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2011, Collabora Ltd. + * + * 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> + */ + +#define P11_KIT_DISABLE_DEPRECATED + +#include "config.h" + +#include "test-trust.h" + +#include "attrs.h" +#include "compat.h" +#include "debug.h" +#include "dict.h" +#include "extract.h" +#include "message.h" +#include "mock.h" +#include "path.h" +#include "pkcs11.h" +#include "pkcs11x.h" +#include "oid.h" +#include "test.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct { + CK_FUNCTION_LIST module; + P11KitIter *iter; + p11_extract_info ex; + char *directory; +} test; + +static void +setup (void *unused) +{ + CK_RV rv; + + mock_module_reset (); + memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST)); + rv = test.module.C_Initialize (NULL); + assert_num_eq (CKR_OK, rv); + + test.iter = p11_kit_iter_new (NULL); + + p11_extract_info_init (&test.ex); + + test.directory = p11_path_expand ("$TEMP/test-extract.XXXXXX"); + if (!mkdtemp (test.directory)) + assert_not_reached (); +} + +static void +teardown (void *unused) +{ + CK_RV rv; + + if (rmdir (test.directory) < 0) + assert_not_reached (); + free (test.directory); + + p11_extract_info_cleanup (&test.ex); + p11_kit_iter_free (test.iter); + + rv = test.module.C_Finalize (NULL); + assert_num_eq (CKR_OK, rv); +} + +static CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE; +static CK_CERTIFICATE_TYPE x509_type = CKC_X_509; + +static CK_ATTRIBUTE cacert3_authority_attrs[] = { + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) }, + { CKA_LABEL, "Cacert3 Here", 12 }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_ID, "ID1", 3 }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE certificate_filter[] = { + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_INVALID }, +}; + +static void +test_file (void) +{ + bool ret; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_pem_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.pem", SRCDIR "/files/cacert3.pem"); + + free (test.ex.destination); +} + +static void +test_file_multiple (void) +{ + bool ret; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_pem_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.pem", SRCDIR "/files/cacert3-twice.pem"); + + free (test.ex.destination); +} + +static void +test_file_without (void) +{ + bool ret; + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_pem_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_data (test.directory, "extract.pem", "", 0); + + free (test.ex.destination); +} + +static void +test_directory (void) +{ + bool ret; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + /* Yes, this is a race, and why you shouldn't build software as root */ + if (rmdir (test.directory) < 0) + assert_not_reached (); + test.ex.destination = test.directory; + + ret = p11_extract_pem_directory (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_directory (test.directory, ("Cacert3_Here.pem", "Cacert3_Here.1.pem", NULL)); + test_check_file (test.directory, "Cacert3_Here.pem", SRCDIR "/files/cacert3.pem"); + test_check_file (test.directory, "Cacert3_Here.1.pem", SRCDIR "/files/cacert3.pem"); +} + +static void +test_directory_empty (void) +{ + bool ret; + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + /* Yes, this is a race, and why you shouldn't build software as root */ + if (rmdir (test.directory) < 0) + assert_not_reached (); + test.ex.destination = test.directory; + + ret = p11_extract_pem_directory (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_directory (test.directory, (NULL, NULL)); +} + +int +main (int argc, + char *argv[]) +{ + mock_module_init (); + + p11_fixture (setup, teardown); + p11_test (test_file, "/pem/test_file"); + p11_test (test_file_multiple, "/pem/test_file_multiple"); + p11_test (test_file_without, "/pem/test_file_without"); + p11_test (test_directory, "/pem/test_directory"); + p11_test (test_directory_empty, "/pem/test_directory_empty"); + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-cer.c b/trust/tests/test-cer.c new file mode 100644 index 0000000..c48a5ab --- /dev/null +++ b/trust/tests/test-cer.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2011, Collabora Ltd. + * + * 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> + */ + +#define P11_KIT_DISABLE_DEPRECATED + +#include "config.h" + +#include "test-trust.h" + +#include "attrs.h" +#include "compat.h" +#include "debug.h" +#include "dict.h" +#include "extract.h" +#include "message.h" +#include "mock.h" +#include "path.h" +#include "pkcs11.h" +#include "pkcs11x.h" +#include "oid.h" +#include "test.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct { + CK_FUNCTION_LIST module; + P11KitIter *iter; + p11_extract_info ex; + char *directory; +} test; + +static void +setup (void *unused) +{ + CK_RV rv; + + mock_module_reset (); + memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST)); + rv = test.module.C_Initialize (NULL); + assert_num_eq (CKR_OK, rv); + + test.iter = p11_kit_iter_new (NULL); + + p11_extract_info_init (&test.ex); + + test.directory = p11_path_expand ("$TEMP/test-extract.XXXXXX"); + if (!mkdtemp (test.directory)) + assert_fail ("mkdtemp() failed", test.directory); +} + +static void +teardown (void *unused) +{ + CK_RV rv; + + if (rmdir (test.directory) < 0) + assert_fail ("rmdir() failed", test.directory); + free (test.directory); + + p11_extract_info_cleanup (&test.ex); + p11_kit_iter_free (test.iter); + + rv = test.module.C_Finalize (NULL); + assert_num_eq (CKR_OK, rv); +} + +static CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE; +static CK_CERTIFICATE_TYPE x509_type = CKC_X_509; + +static CK_ATTRIBUTE cacert3_authority_attrs[] = { + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) }, + { CKA_LABEL, "Cacert3 Here", 12 }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_ID, "ID1", 3 }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE certificate_filter[] = { + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_INVALID }, +}; + +static void +test_file (void) +{ + bool ret; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.cer") < 0) + assert_not_reached (); + + ret = p11_extract_x509_file (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.cer", SRCDIR "/files/cacert3.der"); + + free (test.ex.destination); +} + +static void +test_file_multiple (void) +{ + bool ret; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.cer") < 0) + assert_not_reached (); + + p11_message_quiet (); + + ret = p11_extract_x509_file (test.iter, &test.ex); + assert_num_eq (true, ret); + + assert (strstr (p11_message_last (), "multiple certificates") != NULL); + + p11_message_loud (); + + test_check_file (test.directory, "extract.cer", SRCDIR "/files/cacert3.der"); + + free (test.ex.destination); +} + +static void +test_file_without (void) +{ + bool ret; + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.cer") < 0) + assert_not_reached (); + + p11_message_quiet (); + + ret = p11_extract_x509_file (test.iter, &test.ex); + assert_num_eq (false, ret); + + assert (strstr (p11_message_last (), "no certificate") != NULL); + + p11_message_loud (); + + free (test.ex.destination); +} + +static void +test_directory (void) +{ + bool ret; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + /* Yes, this is a race, and why you shouldn't build software as root */ + if (rmdir (test.directory) < 0) + assert_not_reached (); + test.ex.destination = test.directory; + + ret = p11_extract_x509_directory (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_directory (test.directory, ("Cacert3_Here.cer", "Cacert3_Here.1.cer", NULL)); + test_check_file (test.directory, "Cacert3_Here.cer", SRCDIR "/files/cacert3.der"); + test_check_file (test.directory, "Cacert3_Here.1.cer", SRCDIR "/files/cacert3.der"); +} + +static void +test_directory_empty (void) +{ + bool ret; + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + /* Yes, this is a race, and why you shouldn't build software as root */ + if (rmdir (test.directory) < 0) + assert_not_reached (); + test.ex.destination = test.directory; + + ret = p11_extract_x509_directory (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_directory (test.directory, (NULL, NULL)); +} + +int +main (int argc, + char *argv[]) +{ + mock_module_init (); + + p11_fixture (setup, teardown); + p11_test (test_file, "/x509/test_file"); + p11_test (test_file_multiple, "/x509/test_file_multiple"); + p11_test (test_file_without, "/x509/test_file_without"); + p11_test (test_directory, "/x509/test_directory"); + p11_test (test_directory_empty, "/x509/test_directory_empty"); + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-extract.c b/trust/tests/test-extract.c new file mode 100644 index 0000000..e860996 --- /dev/null +++ b/trust/tests/test-extract.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2011, Collabora Ltd. + * + * 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> + */ + +#define P11_KIT_DISABLE_DEPRECATED + +#include "config.h" + +#include "test-trust.h" + +#include "attrs.h" +#include "compat.h" +#include "debug.h" +#include "dict.h" +#include "extract.h" +#include "message.h" +#include "mock.h" +#include "pkcs11.h" +#include "pkcs11x.h" +#include "oid.h" +#include "test.h" + +#include <stdlib.h> +#include <string.h> + +static void +test_file_name_for_label (void) +{ + CK_ATTRIBUTE label = { CKA_LABEL, "The Label!", 10 }; + p11_extract_info ex; + char *name; + + p11_extract_info_init (&ex); + + ex.attrs = p11_attrs_build (NULL, &label, NULL); + + name = p11_extract_info_filename (&ex); + assert_str_eq ("The_Label_", name); + free (name); + + p11_extract_info_cleanup (&ex); +} + +static void +test_file_name_for_class (void) +{ + p11_extract_info ex; + char *name; + + p11_extract_info_init (&ex); + + ex.klass = CKO_CERTIFICATE; + + name = p11_extract_info_filename (&ex); + assert_str_eq ("certificate", name); + free (name); + + ex.klass = CKO_DATA; + + name = p11_extract_info_filename (&ex); + assert_str_eq ("unknown", name); + free (name); + + p11_extract_info_cleanup (&ex); +} + +static void +test_comment_for_label (void) +{ + CK_ATTRIBUTE label = { CKA_LABEL, "The Label!", 10 }; + p11_extract_info ex; + char *comment; + + p11_extract_info_init (&ex); + + ex.flags = P11_EXTRACT_COMMENT; + ex.attrs = p11_attrs_build (NULL, &label, NULL); + + comment = p11_extract_info_comment (&ex, true); + assert_str_eq ("# The Label!\n", comment); + free (comment); + + comment = p11_extract_info_comment (&ex, false); + assert_str_eq ("\n# The Label!\n", comment); + free (comment); + + p11_extract_info_cleanup (&ex); +} + +static void +test_comment_not_enabled (void) +{ + CK_ATTRIBUTE label = { CKA_LABEL, "The Label!", 10 }; + p11_extract_info ex; + char *comment; + + p11_extract_info_init (&ex); + + ex.attrs = p11_attrs_build (NULL, &label, NULL); + + comment = p11_extract_info_comment (&ex, true); + assert_ptr_eq (NULL, comment); + + comment = p11_extract_info_comment (&ex, false); + assert_ptr_eq (NULL, comment); + + p11_extract_info_cleanup (&ex); +} + +struct { + CK_FUNCTION_LIST module; + P11KitIter *iter; + p11_extract_info ex; +} test; + +static void +setup (void *unused) +{ + CK_RV rv; + + mock_module_reset (); + memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST)); + + rv = test.module.C_Initialize (NULL); + assert_num_eq (CKR_OK, rv); + + test.iter = p11_kit_iter_new (NULL); + + p11_extract_info_init (&test.ex); +} + +static void +teardown (void *unused) +{ + CK_RV rv; + + p11_extract_info_cleanup (&test.ex); + + p11_kit_iter_free (test.iter); + + rv = test.module.C_Finalize (NULL); + assert_num_eq (CKR_OK, rv); +} + +static CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE; +static CK_OBJECT_CLASS extension_class = CKO_X_CERTIFICATE_EXTENSION; +static CK_CERTIFICATE_TYPE x509_type = CKC_X_509; +static CK_BBOOL truev = CK_TRUE; + +static CK_ATTRIBUTE cacert3_trusted[] = { + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) }, + { CKA_LABEL, "Cacert3 Here", 11 }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_TRUSTED, &truev, sizeof (truev) }, + { CKA_ID, "ID1", 3 }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE cacert3_distrusted[] = { + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) }, + { CKA_LABEL, "Another CaCert", 11 }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_X_DISTRUSTED, &truev, sizeof (truev) }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE certificate_filter[] = { + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE extension_eku_server_client[] = { + { CKA_CLASS, &extension_class, sizeof (extension_class) }, + { CKA_ID, "ID1", 3 }, + { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, sizeof (P11_OID_EXTENDED_KEY_USAGE) }, + { CKA_VALUE, (void *)test_eku_server_and_client, sizeof (test_eku_server_and_client) }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE extension_eku_invalid[] = { + { CKA_CLASS, &extension_class, sizeof (extension_class) }, + { CKA_ID, "ID1", 3 }, + { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, sizeof (P11_OID_EXTENDED_KEY_USAGE) }, + { CKA_VALUE, "invalid", 7 }, + { CKA_INVALID }, +}; + +static void +test_info_simple_certificate (void) +{ + void *value; + size_t length; + CK_RV rv; + + assert_ptr_not_null (test.ex.asn1_defs); + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_server_client); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + assert_num_eq (CKO_CERTIFICATE, test.ex.klass); + assert_ptr_not_null (test.ex.attrs); + value = p11_attrs_find_value (test.ex.attrs, CKA_VALUE, &length); + assert_ptr_not_null (value); + assert (memcmp (value, test_cacert3_ca_der, length) == 0); + assert_ptr_not_null (test.ex.cert_der); + assert (memcmp (test.ex.cert_der, test_cacert3_ca_der, test.ex.cert_len) == 0); + assert_ptr_not_null (test.ex.cert_asn); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); +} + +static void +test_info_limit_purposes (void) +{ + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_server_client); + + /* This should not match the above, with the stapled certificat ext */ + assert_ptr_eq (NULL, test.ex.limit_to_purposes); + p11_extract_info_limit_purpose (&test.ex, "1.1.1"); + assert_ptr_not_null (test.ex.limit_to_purposes); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); +} + +static void +test_info_invalid_purposes (void) +{ + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_invalid); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + p11_kit_be_quiet (); + + /* No results due to invalid purpose on certificate */ + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); + + p11_kit_be_loud (); +} + +static void +test_info_skip_non_certificate (void) +{ + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + p11_message_quiet (); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + assert_num_eq (CKO_CERTIFICATE, test.ex.klass); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); + + p11_message_loud (); +} + +static void +test_limit_to_purpose_match (void) +{ + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_server_client); + + p11_extract_info_limit_purpose (&test.ex, P11_OID_SERVER_AUTH_STR); + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + p11_message_quiet (); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + p11_message_loud (); +} + +static void +test_limit_to_purpose_no_match (void) +{ + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_server_client); + + p11_extract_info_limit_purpose (&test.ex, "3.3.3.3"); + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + p11_message_quiet (); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); + + p11_message_loud (); +} + +static void +test_duplicate_extract (void) +{ + CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) }; + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, &certificate, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); +} + +static void +test_duplicate_collapse (void) +{ + CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) }; + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted); + + test.ex.flags = P11_EXTRACT_COLLAPSE; + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, &certificate, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); +} + +static void +test_trusted_match (void) +{ + CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) }; + CK_BBOOL boolv; + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted); + + test.ex.flags = P11_EXTRACT_ANCHORS; + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, &certificate, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + if (!p11_attrs_find_bool (test.ex.attrs, CKA_TRUSTED, &boolv)) + boolv = CK_FALSE; + assert_num_eq (CK_TRUE, boolv); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); +} + +static void +test_distrust_match (void) +{ + CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) }; + CK_BBOOL boolv; + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted); + + test.ex.flags = P11_EXTRACT_BLACKLIST; + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, &certificate, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + if (!p11_attrs_find_bool (test.ex.attrs, CKA_X_DISTRUSTED, &boolv)) + boolv = CK_FALSE; + assert_num_eq (CK_TRUE, boolv); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); +} + +static void +test_anytrust_match (void) +{ + CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) }; + CK_RV rv; + + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted); + + test.ex.flags = P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST; + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, &certificate, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_OK, rv); + + rv = p11_kit_iter_next (test.iter); + assert_num_eq (CKR_CANCEL, rv); +} + +int +main (int argc, + char *argv[]) +{ + mock_module_init (); + + p11_test (test_file_name_for_label, "/extract/test_file_name_for_label"); + p11_test (test_file_name_for_class, "/extract/test_file_name_for_class"); + p11_test (test_comment_for_label, "/extract/test_comment_for_label"); + p11_test (test_comment_not_enabled, "/extract/test_comment_not_enabled"); + + p11_fixture (setup, teardown); + p11_test (test_info_simple_certificate, "/extract/test_info_simple_certificate"); + p11_test (test_info_limit_purposes, "/extract/test_info_limit_purposes"); + p11_test (test_info_invalid_purposes, "/extract/test_info_invalid_purposes"); + p11_test (test_info_skip_non_certificate, "/extract/test_info_skip_non_certificate"); + p11_test (test_limit_to_purpose_match, "/extract/test_limit_to_purpose_match"); + p11_test (test_limit_to_purpose_no_match, "/extract/test_limit_to_purpose_no_match"); + p11_test (test_duplicate_extract, "/extract/test_duplicate_extract"); + p11_test (test_duplicate_collapse, "/extract/test_duplicate_collapse"); + p11_test (test_trusted_match, "/extract/test_trusted_match"); + p11_test (test_distrust_match, "/extract/test_distrust_match"); + p11_test (test_anytrust_match, "/extract/test_anytrust_match"); + + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-oid.c b/trust/tests/test-oid.c new file mode 100644 index 0000000..05945d9 --- /dev/null +++ b/trust/tests/test-oid.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2012 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@gnome.org> + */ + +#include "config.h" +#include "test.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "debug.h" +#include "oid.h" + +#include <libtasn1.h> + +#include "pkix.asn.h" + +static void +test_known_oids (void) +{ + char buffer[128]; + node_asn *definitions = NULL; + node_asn *node; + int ret; + int len; + int i; + + struct { + const unsigned char *oid; + size_t length; + const char *string; + } known_oids[] = { + { P11_OID_SUBJECT_KEY_IDENTIFIER, sizeof (P11_OID_SUBJECT_KEY_IDENTIFIER), "2.5.29.14", }, + { P11_OID_KEY_USAGE, sizeof (P11_OID_KEY_USAGE), "2.5.29.15", }, + { P11_OID_BASIC_CONSTRAINTS, sizeof (P11_OID_BASIC_CONSTRAINTS), "2.5.29.19" }, + { P11_OID_EXTENDED_KEY_USAGE, sizeof (P11_OID_EXTENDED_KEY_USAGE), "2.5.29.37" }, + { P11_OID_OPENSSL_REJECT, sizeof (P11_OID_OPENSSL_REJECT), "1.3.6.1.4.1.3319.6.10.1" }, + { P11_OID_SERVER_AUTH, sizeof (P11_OID_SERVER_AUTH), P11_OID_SERVER_AUTH_STR }, + { P11_OID_CLIENT_AUTH, sizeof (P11_OID_CLIENT_AUTH), P11_OID_CLIENT_AUTH_STR }, + { P11_OID_CODE_SIGNING, sizeof (P11_OID_CODE_SIGNING), P11_OID_CODE_SIGNING_STR }, + { P11_OID_EMAIL_PROTECTION, sizeof (P11_OID_EMAIL_PROTECTION), P11_OID_EMAIL_PROTECTION_STR }, + { P11_OID_IPSEC_END_SYSTEM, sizeof (P11_OID_IPSEC_END_SYSTEM), P11_OID_IPSEC_END_SYSTEM_STR }, + { P11_OID_IPSEC_TUNNEL, sizeof (P11_OID_IPSEC_TUNNEL), P11_OID_IPSEC_TUNNEL_STR }, + { P11_OID_IPSEC_USER, sizeof (P11_OID_IPSEC_USER), P11_OID_IPSEC_USER_STR }, + { P11_OID_TIME_STAMPING, sizeof (P11_OID_TIME_STAMPING), P11_OID_TIME_STAMPING_STR }, + { P11_OID_RESERVED_PURPOSE, sizeof (P11_OID_RESERVED_PURPOSE), P11_OID_RESERVED_PURPOSE_STR }, + { NULL }, + }; + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, NULL); + assert (ret == ASN1_SUCCESS); + + for (i = 0; known_oids[i].oid != NULL; i++) { + + assert (p11_oid_simple (known_oids[i].oid, known_oids[i].length)); + assert_num_eq (known_oids[i].length, p11_oid_length (known_oids[i].oid)); + assert (p11_oid_equal (known_oids[i].oid, known_oids[i].oid)); + + if (i > 0) + assert (!p11_oid_equal (known_oids[i].oid, known_oids[i - 1].oid)); + + /* AttributeType is a OBJECT IDENTIFIER */ + ret = asn1_create_element (definitions, "PKIX1.AttributeType", &node); + assert (ret == ASN1_SUCCESS); + + ret = asn1_der_decoding (&node, known_oids[i].oid, known_oids[i].length, NULL); + assert (ret == ASN1_SUCCESS); + + len = sizeof (buffer); + ret = asn1_read_value (node, "", buffer, &len); + assert (ret == ASN1_SUCCESS); + + assert_str_eq (known_oids[i].string, buffer); + + asn1_delete_structure (&node); + } + + asn1_delete_structure (&definitions); +} + +int +main (int argc, + char *argv[]) +{ + p11_test (test_known_oids, "/oids/known"); + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-openssl.c b/trust/tests/test-openssl.c new file mode 100644 index 0000000..7479812 --- /dev/null +++ b/trust/tests/test-openssl.c @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2011, Collabora Ltd. + * + * 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> + */ + +#define P11_KIT_DISABLE_DEPRECATED + +#include "config.h" + +#include "test-trust.h" + +#include "attrs.h" +#include "buffer.h" +#include "compat.h" +#include "debug.h" +#include "dict.h" +#include "extract.h" +#include "message.h" +#include "mock.h" +#include "path.h" +#include "pkcs11.h" +#include "pkcs11x.h" +#include "oid.h" +#include "test.h" + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define ELEMS(x) (sizeof (x) / sizeof (x[0])) + +struct { + CK_FUNCTION_LIST module; + P11KitIter *iter; + p11_extract_info ex; + char *directory; +} test; + +static void +setup (void *unused) +{ + CK_RV rv; + + mock_module_reset (); + memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST)); + rv = test.module.C_Initialize (NULL); + assert_num_eq (CKR_OK, rv); + + test.iter = p11_kit_iter_new (NULL); + + p11_extract_info_init (&test.ex); + + test.directory = p11_path_expand ("$TEMP/test-extract.XXXXXX"); + if (!mkdtemp (test.directory)) + assert_not_reached (); +} + +static void +teardown (void *unused) +{ + CK_RV rv; + + if (rmdir (test.directory) < 0) + assert_not_reached (); + free (test.directory); + + p11_extract_info_cleanup (&test.ex); + p11_kit_iter_free (test.iter); + + rv = test.module.C_Finalize (NULL); + assert_num_eq (CKR_OK, rv); +} + +static CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE; +static CK_OBJECT_CLASS extension_class = CKO_X_CERTIFICATE_EXTENSION; +static CK_CERTIFICATE_TYPE x509_type = CKC_X_509; +static CK_BBOOL vtrue = CK_TRUE; + +static CK_ATTRIBUTE cacert3_authority_attrs[] = { + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) }, + { CKA_LABEL, "Custom Label", 12 }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_TRUSTED, &vtrue, sizeof (vtrue) }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE extension_eku_server[] = { + { CKA_CLASS, &extension_class, sizeof (extension_class) }, + { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, sizeof (P11_OID_EXTENDED_KEY_USAGE) }, + { CKA_VALUE, (void *)test_eku_server, sizeof (test_eku_server) }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE extension_reject_email[] = { + { CKA_CLASS, &extension_class, sizeof (extension_class) }, + { CKA_OBJECT_ID, (void *)P11_OID_OPENSSL_REJECT, sizeof (P11_OID_OPENSSL_REJECT) }, + { CKA_VALUE, (void *)test_eku_email, sizeof (test_eku_email) }, + { CKA_INVALID }, +}; + +static CK_ATTRIBUTE certificate_filter[] = { + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_INVALID }, +}; + +static void +setup_objects (const CK_ATTRIBUTE *attrs, + ...) GNUC_NULL_TERMINATED; + +static void +setup_objects (const CK_ATTRIBUTE *attrs, + ...) +{ + static CK_ULONG id_value = 8888; + + CK_ATTRIBUTE id = { CKA_ID, &id_value, sizeof (id_value) }; + CK_ATTRIBUTE *copy; + va_list va; + + va_start (va, attrs); + while (attrs != NULL) { + copy = p11_attrs_build (p11_attrs_dup (attrs), &id, NULL); + assert (copy != NULL); + mock_module_take_object (MOCK_SLOT_ONE_ID, copy); + attrs = va_arg (va, const CK_ATTRIBUTE *); + } + va_end (va); + + id_value++; +} + +static void +test_file (void) +{ + bool ret; + + setup_objects (cacert3_authority_attrs, + extension_eku_server, + extension_reject_email, + NULL); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_openssl_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.pem", + SRCDIR "/files/cacert3-trusted-server-alias.pem"); + + free (test.ex.destination); +} + +static void +test_plain (void) +{ + bool ret; + + setup_objects (cacert3_authority_attrs, NULL); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_openssl_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.pem", + SRCDIR "/files/cacert3-trusted-alias.pem"); + + free (test.ex.destination); +} + +static void +test_keyid (void) +{ + bool ret; + + static CK_ATTRIBUTE cacert3_plain[] = { + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_TRUSTED, &vtrue, sizeof (vtrue) }, + { CKA_INVALID }, + }; + + static unsigned char identifier[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + + static CK_ATTRIBUTE extension_subject_key_identifier[] = { + { CKA_CLASS, &extension_class, sizeof (extension_class) }, + { CKA_OBJECT_ID, (void *)P11_OID_SUBJECT_KEY_IDENTIFIER, sizeof (P11_OID_SUBJECT_KEY_IDENTIFIER) }, + { CKA_VALUE, identifier, sizeof (identifier) }, + { CKA_INVALID }, + }; + + setup_objects (cacert3_plain, extension_subject_key_identifier, NULL); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_openssl_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.pem", + SRCDIR "/files/cacert3-trusted-keyid.pem"); + + free (test.ex.destination); +} + +static void +test_not_authority (void) +{ + bool ret; + + static CK_ATTRIBUTE cacert3_not_trusted[] = { + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_INVALID }, + }; + + setup_objects (cacert3_not_trusted, NULL); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_openssl_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.pem", + SRCDIR "/files/cacert3-not-trusted.pem"); + + free (test.ex.destination); +} + +static void +test_distrust_all (void) +{ + bool ret; + + static CK_ATTRIBUTE cacert3_blacklist[] = { + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CLASS, &certificate_class, sizeof (certificate_class) }, + { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_X_DISTRUSTED, &vtrue, sizeof (vtrue) }, + { CKA_INVALID }, + }; + + setup_objects (cacert3_blacklist, NULL); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_openssl_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.pem", + SRCDIR "/files/cacert3-distrust-all.pem"); + + free (test.ex.destination); +} + +static void +test_file_multiple (void) +{ + bool ret; + + setup_objects (cacert3_authority_attrs, + extension_eku_server, + extension_reject_email, + NULL); + + setup_objects (cacert3_authority_attrs, + NULL); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_openssl_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_file (test.directory, "extract.pem", + SRCDIR "/files/cacert3-trusted-multiple.pem"); + + free (test.ex.destination); +} + +static void +test_file_without (void) +{ + bool ret; + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + if (asprintf (&test.ex.destination, "%s/%s", test.directory, "extract.pem") < 0) + assert_not_reached (); + + ret = p11_extract_openssl_bundle (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_data (test.directory, "extract.pem", "", 0); + + free (test.ex.destination); +} + +/* From extract-openssl.c */ +void p11_openssl_canon_string (char *str, size_t *len); + +static void +test_canon_string (void) +{ + struct { + char *input; + int input_len; + char *output; + int output_len; + } fixtures[] = { + { "A test", -1, "a test", -1 }, + { " Strip spaces ", -1, "strip spaces", -1 }, + { " Collapse \n\t spaces", -1, "collapse spaces", -1 }, + { "Ignore non-ASCII \303\204", -1, "ignore non-ascii \303\204", -1 }, + { "no-space", -1, "no-space", -1 }, + }; + + char *str; + size_t len; + size_t out; + int i; + + for (i = 0; i < ELEMS (fixtures); i++) { + if (fixtures[i].input_len < 0) + len = strlen (fixtures[i].input); + else + len = fixtures[i].input_len; + str = strndup (fixtures[i].input, len); + + p11_openssl_canon_string (str, &len); + + if (fixtures[i].output_len < 0) + out = strlen (fixtures[i].output); + else + out = fixtures[i].output_len; + assert_num_eq (out, len); + assert_str_eq (fixtures[i].output, str); + + free (str); + } +} + +bool p11_openssl_canon_string_der (p11_buffer *der); + +static void +test_canon_string_der (void) +{ + struct { + unsigned char input[100]; + int input_len; + unsigned char output[100]; + int output_len; + } fixtures[] = { + /* UTF8String */ + { { 0x0c, 0x0f, 0xc3, 0x84, ' ', 'U', 'T', 'F', '8', ' ', 's', 't', 'r', 'i', 'n', 'g', ' ', }, 17, + { 0x0c, 0x0e, 0xc3, 0x84, ' ', 'u', 't', 'f', '8', ' ', 's', 't', 'r', 'i', 'n', 'g', }, 16, + }, + + /* NumericString */ + { { 0x12, 0x04, '0', '1', '2', '3', }, 6, + { 0x0c, 0x04, '0', '1', '2', '3' }, 6, + }, + + /* IA5String */ + { { 0x16, 0x04, ' ', 'A', 'B', ' ', }, 6, + { 0x0c, 0x02, 'a', 'b', }, 4, + }, + + /* TeletexString */ + { { 0x14, 0x07, 'A', ' ', ' ', 'n', 'i', 'c', 'e' }, 9, + { 0x0c, 0x06, 'a', ' ', 'n', 'i', 'c', 'e' }, 8, + }, + + /* PrintableString */ + { { 0x13, 0x07, 'A', ' ', ' ', 'n', 'i', 'c', 'e' }, 9, + { 0x0c, 0x06, 'a', ' ', 'n', 'i', 'c', 'e' }, 8, + }, + + /* No change, not a known string type */ + { { 0x05, 0x07, 'A', ' ', ' ', 'n', 'i', 'c', 'e' }, 9, + { 0x05, 0x07, 'A', ' ', ' ', 'n', 'i', 'c', 'e' }, 9 + }, + + /* UniversalString */ + { { 0x1c, 0x14, 0x00, 0x00, 0x00, 'F', 0x00, 0x00, 0x00, 'u', + 0x00, 0x00, 0x00, 'n', 0x00, 0x00, 0x00, ' ', 0x00, 0x01, 0x03, 0x19, }, 22, + { 0x0c, 0x08, 'f', 'u', 'n', ' ', 0xf0, 0x90, 0x8c, 0x99 }, 10, + }, + + /* BMPString */ + { { 0x1e, 0x0a, 0x00, 'V', 0x00, 0xF6, 0x00, 'g', 0x00, 'e', 0x00, 'l' }, 12, + { 0x0c, 0x06, 'v', 0xc3, 0xb6, 'g', 'e', 'l' }, 8, + }, + }; + + p11_buffer buf; + bool ret; + int i; + + for (i = 0; i < ELEMS (fixtures); i++) { + p11_buffer_init_full (&buf, memdup (fixtures[i].input, fixtures[i].input_len), + fixtures[i].input_len, 0, realloc, free); + + ret = p11_openssl_canon_string_der (&buf); + assert_num_eq (true, ret); + + assert_num_eq (fixtures[i].output_len, buf.len); + assert (memcmp (buf.data, fixtures[i].output, buf.len) == 0); + + p11_buffer_uninit (&buf); + } +} + +bool p11_openssl_canon_name_der (p11_dict *asn1_defs, + p11_buffer *der); + +static void +test_canon_name_der (void) +{ + struct { + unsigned char input[100]; + int input_len; + unsigned char output[100]; + int output_len; + } fixtures[] = { + { { '0', 'T', '1', 0x14, '0', 0x12, 0x06, 0x03, 'U', 0x04, 0x0a, + 0x13, 0x0b, 'C', 'A', 'c', 'e', 'r', 't', 0x20, 'I', 'n', + 'c', '.', '1', 0x1e, '0', 0x1c, 0x06, 0x03, 'U', 0x04, + 0x0b, 0x13, 0x15, 'h', 't', 't', 'p', ':', '/', '/', 'w', + 'w', 'w', '.', 'C', 'A', 'c', 'e', 'r', 't', '.', 'o', 'r', + 'g', '1', 0x1c, '0', 0x1a, 0x06, 0x03, 'U', 0x04, 0x03, 0x13, + 0x13, 'C', 'A', 'c', 'e', 'r', 't', 0x20, 'C', 'l', 'a', 's', + 's', 0x20, '3', 0x20, 'R', 'o', 'o', 't', }, 86, + { '1', 0x14, '0', 0x12, 0x06, 0x03, 'U', 0x04, 0x0a, + 0x0c, 0x0b, 'c', 'a', 'c', 'e', 'r', 't', 0x20, 'i', 'n', + 'c', '.', '1', 0x1e, '0', 0x1c, 0x06, 0x03, 'U', 0x04, + 0x0b, 0x0c, 0x15, 'h', 't', 't', 'p', ':', '/', '/', 'w', + 'w', 'w', '.', 'c', 'a', 'c', 'e', 'r', 't', '.', 'o', 'r', + 'g', '1', 0x1c, '0', 0x1a, 0x06, 0x03, 'U', 0x04, 0x03, 0x0c, + 0x13, 'c', 'a', 'c', 'e', 'r', 't', 0x20, 'c', 'l', 'a', 's', + 's', 0x20, '3', 0x20, 'r', 'o', 'o', 't', }, 84, + }, + { { '0', 0x00, }, 2, + { }, 0, + }, + }; + + p11_buffer buf; + p11_dict *asn1_defs; + bool ret; + int i; + + asn1_defs = p11_asn1_defs_load (); + + for (i = 0; i < ELEMS (fixtures); i++) { + p11_buffer_init_full (&buf, memdup (fixtures[i].input, fixtures[i].input_len), + fixtures[i].input_len, 0, realloc, free); + + ret = p11_openssl_canon_name_der (asn1_defs, &buf); + assert_num_eq (true, ret); + + assert_num_eq (fixtures[i].output_len, buf.len); + assert (memcmp (buf.data, fixtures[i].output, buf.len) == 0); + + p11_buffer_uninit (&buf); + } + + p11_dict_free (asn1_defs); +} + +static void +test_canon_string_der_fail (void) +{ + struct { + unsigned char input[100]; + int input_len; + } fixtures[] = { + { { 0x0c, 0x02, 0xc3, 0xc4 /* Invalid UTF-8 */ }, 4 }, + { { 0x1e, 0x01, 0x00 /* Invalid UCS2 */ }, 3 }, + { { 0x1c, 0x02, 0x00, 0x01 /* Invalid UCS4 */ }, 4 }, + }; + + p11_buffer buf; + bool ret; + int i; + + for (i = 0; i < ELEMS (fixtures); i++) { + p11_buffer_init_full (&buf, memdup (fixtures[i].input, fixtures[i].input_len), + fixtures[i].input_len, 0, realloc, free); + + ret = p11_openssl_canon_string_der (&buf); + assert_num_eq (false, ret); + + p11_buffer_uninit (&buf); + } +} + +static void +test_directory (void) +{ + bool ret; + + setup_objects (cacert3_authority_attrs, + extension_eku_server, + extension_reject_email, + NULL); + + setup_objects (cacert3_authority_attrs, + NULL); + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + /* Yes, this is a race, and why you shouldn't build software as root */ + if (rmdir (test.directory) < 0) + assert_not_reached (); + test.ex.destination = test.directory; + + ret = p11_extract_openssl_directory (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_directory (test.directory, ("Custom_Label.pem", "Custom_Label.1.pem", +#ifdef OS_UNIX + "e5662767.1", "e5662767.0", "590d426f.1", "590d426f.0", +#endif + NULL)); + test_check_file (test.directory, "Custom_Label.pem", + SRCDIR "/files/cacert3-trusted-server-alias.pem"); + test_check_file (test.directory, "Custom_Label.1.pem", + SRCDIR "/files/cacert3-trusted-alias.pem"); +#ifdef OS_UNIX + test_check_symlink (test.directory, "e5662767.0", "Custom_Label.pem"); + test_check_symlink (test.directory, "e5662767.1", "Custom_Label.1.pem"); + test_check_symlink (test.directory, "590d426f.0", "Custom_Label.pem"); + test_check_symlink (test.directory, "590d426f.1", "Custom_Label.1.pem"); +#endif +} + +static void +test_directory_empty (void) +{ + bool ret; + + p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); + p11_kit_iter_add_filter (test.iter, certificate_filter, 1); + p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); + + /* Yes, this is a race, and why you shouldn't build software as root */ + if (rmdir (test.directory) < 0) + assert_not_reached (); + test.ex.destination = test.directory; + + ret = p11_extract_openssl_directory (test.iter, &test.ex); + assert_num_eq (true, ret); + + test_check_directory (test.directory, (NULL, NULL)); +} + +int +main (int argc, + char *argv[]) +{ + mock_module_init (); + + p11_fixture (setup, teardown); + p11_test (test_file, "/openssl/test_file"); + p11_test (test_plain, "/openssl/test_plain"); + p11_test (test_keyid, "/openssl/test_keyid"); + p11_test (test_not_authority, "/openssl/test_not_authority"); + p11_test (test_distrust_all, "/openssl/test_distrust_all"); + p11_test (test_file_multiple, "/openssl/test_file_multiple"); + p11_test (test_file_without, "/openssl/test_file_without"); + + p11_fixture (NULL, NULL); + p11_test (test_canon_string, "/openssl/test_canon_string"); + p11_test (test_canon_string_der, "/openssl/test_canon_string_der"); + p11_test (test_canon_string_der_fail, "/openssl/test_canon_string_der_fail"); + p11_test (test_canon_name_der, "/openssl/test_canon_name_der"); + + p11_fixture (setup, teardown); + p11_test (test_directory, "/openssl/test_directory"); + p11_test (test_directory_empty, "/openssl/test_directory_empty"); + + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-pem.c b/trust/tests/test-pem.c new file mode 100644 index 0000000..0c7d60a --- /dev/null +++ b/trust/tests/test-pem.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2012 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@gnome.org> + */ + +#include "config.h" +#include "test.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "compat.h" +#include "pem.h" + +struct { + const char *input; + struct { + const char *type; + const char *data; + unsigned int length; + } output[8]; +} success_fixtures[] = { + { + /* one block */ + "-----BEGIN BLOCK1-----\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END BLOCK1-----", + { + { + "BLOCK1", + "\x69\x83\x4d\x5e\xab\x21\x95\x5c\x42\x76\x8f\x10\x7c\xa7\x97\x87" + "\x71\x94\xcd\xdf\xf2\x9f\x82\xd8\x21\x58\x10\xaf\x1e\x1a", + 30, + }, + { + NULL, + } + } + }, + + { + /* one block, with header */ + "-----BEGIN BLOCK1-----\n" + "Header1: value1 \n" + " Header2: value2\n" + "\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END BLOCK1-----", + { + { + "BLOCK1", + "\x69\x83\x4d\x5e\xab\x21\x95\x5c\x42\x76\x8f\x10\x7c\xa7\x97\x87" + "\x71\x94\xcd\xdf\xf2\x9f\x82\xd8\x21\x58\x10\xaf\x1e\x1a", + 30, + }, + { + NULL, + } + } + }, + + { + /* two blocks, junk data */ + "-----BEGIN BLOCK1-----\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END BLOCK1-----\n" + "blah blah\n" + "-----BEGIN TWO-----\n" + "oy5L157C671HyJMCf9FiK9prvPZfSch6V4EoUfylFoI1Bq6SbL53kg==\n" + "-----END TWO-----\n" + "trailing data", + { + { + "BLOCK1", + "\x69\x83\x4d\x5e\xab\x21\x95\x5c\x42\x76\x8f\x10\x7c\xa7\x97\x87" + "\x71\x94\xcd\xdf\xf2\x9f\x82\xd8\x21\x58\x10\xaf\x1e\x1a", + 30, + }, + { + "TWO", + "\xa3\x2e\x4b\xd7\x9e\xc2\xeb\xbd\x47\xc8\x93\x02\x7f\xd1\x62\x2b" + "\xda\x6b\xbc\xf6\x5f\x49\xc8\x7a\x57\x81\x28\x51\xfc\xa5\x16\x82" + "\x35\x06\xae\x92\x6c\xbe\x77\x92", + 40 + }, + { + NULL, + } + } + }, + + { + NULL, + } +}; + +typedef struct { + int input_index; + int output_index; + int parsed; +} Closure; + +static void +on_parse_pem_success (const char *type, + const unsigned char *contents, + size_t length, + void *user_data) +{ + Closure *cl = user_data; + + assert_num_eq (success_fixtures[cl->input_index].output[cl->output_index].length, length); + assert (memcmp (success_fixtures[cl->input_index].output[cl->output_index].data, contents, + success_fixtures[cl->input_index].output[cl->output_index].length) == 0); + + cl->output_index++; + cl->parsed++; +} + +static void +test_pem_success (void) +{ + Closure cl; + int ret; + int i; + int j; + + for (i = 0; success_fixtures[i].input != NULL; i++) { + cl.input_index = i; + cl.output_index = 0; + cl.parsed = 0; + + ret = p11_pem_parse (success_fixtures[i].input, strlen (success_fixtures[i].input), + on_parse_pem_success, &cl); + + assert (success_fixtures[i].output[cl.output_index].type == NULL); + + /* Count number of outputs, return from p11_pem_parse() should match */ + for (j = 0; success_fixtures[i].output[j].type != NULL; j++); + assert_num_eq (j, ret); + assert_num_eq (ret, cl.parsed); + } +} + +const char *failure_fixtures[] = { + /* too short at end of opening line */ + "-----BEGIN BLOCK1---\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END BLOCK1-----", + + /* truncated */ + "-----BEGIN BLOCK1---", + + /* no ending */ + "-----BEGIN BLOCK1-----\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n", + + /* wrong ending */ + "-----BEGIN BLOCK1-----\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END BLOCK2-----", + + /* wrong ending */ + "-----BEGIN BLOCK1-----\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END INVALID-----", + + /* too short at end of ending line */ + "-----BEGIN BLOCK1-----\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END BLOCK1---", + + /* invalid base64 data */ + "-----BEGIN BLOCK1-----\n" + "!!!!NNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END BLOCK1-----", + + NULL, +}; + +static void +on_parse_pem_failure (const char *type, + const unsigned char *contents, + size_t length, + void *user_data) +{ + assert (false && "not reached"); +} + +static void +test_pem_failure (void) +{ + int ret; + int i; + + for (i = 0; failure_fixtures[i] != NULL; i++) { + ret = p11_pem_parse (failure_fixtures[i], strlen (failure_fixtures[i]), + on_parse_pem_failure, NULL); + assert_num_eq (0, ret); + } +} + +typedef struct { + const char *input; + size_t length; + const char *type; + const char *output; +} WriteFixture; + +static WriteFixture write_fixtures[] = { + { + "\x69\x83\x4d\x5e\xab\x21\x95\x5c\x42\x76\x8f\x10\x7c\xa7\x97\x87" + "\x71\x94\xcd\xdf\xf2\x9f\x82\xd8\x21\x58\x10\xaf\x1e\x1a", + 30, "BLOCK1", + "-----BEGIN BLOCK1-----\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n" + "-----END BLOCK1-----\n", + }, + { + "\x50\x31\x31\x2d\x4b\x49\x54\x0a\x0a\x50\x72\x6f\x76\x69\x64\x65" + "\x73\x20\x61\x20\x77\x61\x79\x20\x74\x6f\x20\x6c\x6f\x61\x64\x20" + "\x61\x6e\x64\x20\x65\x6e\x75\x6d\x65\x72\x61\x74\x65\x20\x50\x4b" + "\x43\x53\x23\x31\x31\x20\x6d\x6f\x64\x75\x6c\x65\x73\x2e\x20\x50" + "\x72\x6f\x76\x69\x64\x65\x73\x20\x61\x20\x73\x74\x61\x6e\x64\x61" + "\x72\x64\x0a\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e" + "\x20\x73\x65\x74\x75\x70\x20\x66\x6f\x72\x20\x69\x6e\x73\x74\x61" + "\x6c\x6c\x69\x6e\x67\x20\x50\x4b\x43\x53\x23\x31\x31\x20\x6d\x6f" + "\x64\x75\x6c\x65\x73\x20\x69\x6e\x20\x73\x75\x63\x68\x20\x61\x20" + "\x77\x61\x79\x20\x74\x68\x61\x74\x20\x74\x68\x65\x79\x27\x72\x65" + "\x0a\x64\x69\x73\x63\x6f\x76\x65\x72\x61\x62\x6c\x65\x2e\x0a\x0a" + "\x41\x6c\x73\x6f\x20\x73\x6f\x6c\x76\x65\x73\x20\x70\x72\x6f\x62" + "\x6c\x65\x6d\x73\x20\x77\x69\x74\x68\x20\x63\x6f\x6f\x72\x64\x69" + "\x6e\x61\x74\x69\x6e\x67\x20\x74\x68\x65\x20\x75\x73\x65\x20\x6f" + "\x66\x20\x50\x4b\x43\x53\x23\x31\x31\x20\x62\x79\x20\x64\x69\x66" + "\x66\x65\x72\x65\x6e\x74\x0a\x63\x6f\x6d\x70\x6f\x6e\x65\x6e\x74" + "\x73\x20\x6f\x72\x20\x6c\x69\x62\x72\x61\x72\x69\x65\x73\x20\x6c" + "\x69\x76\x69\x6e\x67\x20\x69\x6e\x20\x74\x68\x65\x20\x73\x61\x6d" + "\x65\x20\x70\x72\x6f\x63\x65\x73\x73\x2e\x0a", + 299, "LONG TYPE WITH SPACES", + "-----BEGIN LONG TYPE WITH SPACES-----\n" + "UDExLUtJVAoKUHJvdmlkZXMgYSB3YXkgdG8gbG9hZCBhbmQgZW51bWVyYXRlIFBL\n" + "Q1MjMTEgbW9kdWxlcy4gUHJvdmlkZXMgYSBzdGFuZGFyZApjb25maWd1cmF0aW9u\n" + "IHNldHVwIGZvciBpbnN0YWxsaW5nIFBLQ1MjMTEgbW9kdWxlcyBpbiBzdWNoIGEg\n" + "d2F5IHRoYXQgdGhleSdyZQpkaXNjb3ZlcmFibGUuCgpBbHNvIHNvbHZlcyBwcm9i\n" + "bGVtcyB3aXRoIGNvb3JkaW5hdGluZyB0aGUgdXNlIG9mIFBLQ1MjMTEgYnkgZGlm\n" + "ZmVyZW50CmNvbXBvbmVudHMgb3IgbGlicmFyaWVzIGxpdmluZyBpbiB0aGUgc2Ft\n" + "ZSBwcm9jZXNzLgo=\n" + "-----END LONG TYPE WITH SPACES-----\n" + }, + { + "\x69\x83\x4d\x5e\xab\x21\x95\x5c\x42\x76\x8f\x10\x7c\xa7\x97\x87" + "\x71\x94\xcd\xdf\xf2\x9f\x82\xd8\x21\x58\x10\xaf", + 28, "BLOCK1", + "-----BEGIN BLOCK1-----\n" + "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrw==\n" + "-----END BLOCK1-----\n", + }, + { + NULL, + } +}; + +static void +on_parse_written (const char *type, + const unsigned char *contents, + size_t length, + void *user_data) +{ + WriteFixture *fixture = user_data; + + assert_str_eq (fixture->type, type); + assert_num_eq (fixture->length, length); + assert (memcmp (contents, fixture->input, length) == 0); +} + +static void +test_pem_write (void) +{ + WriteFixture *fixture; + p11_buffer buf; + unsigned int count; + int i; + + for (i = 0; write_fixtures[i].input != NULL; i++) { + fixture = write_fixtures + i; + + if (!p11_buffer_init_null (&buf, 0)) + assert_not_reached (); + + if (!p11_pem_write ((unsigned char *)fixture->input, + fixture->length, + fixture->type, &buf)) + assert_not_reached (); + assert_str_eq (fixture->output, buf.data); + assert_num_eq (strlen (fixture->output), buf.len); + + count = p11_pem_parse (buf.data, buf.len, on_parse_written, fixture); + assert_num_eq (1, count); + + p11_buffer_uninit (&buf); + } +} + +int +main (int argc, + char *argv[]) +{ + p11_test (test_pem_success, "/pem/success"); + p11_test (test_pem_failure, "/pem/failure"); + p11_test (test_pem_write, "/pem/write"); + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-save.c b/trust/tests/test-save.c new file mode 100644 index 0000000..be072f5 --- /dev/null +++ b/trust/tests/test-save.c @@ -0,0 +1,513 @@ +/* + * 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 "test-trust.h" + +#include "attrs.h" +#include "compat.h" +#include "debug.h" +#include "dict.h" +#include "message.h" +#include "path.h" +#include "save.h" +#include "test.h" + +#include <sys/stat.h> +#include <sys/types.h> + +#include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +struct { + char *directory; +} test; + +static void +setup (void *unused) +{ + test.directory = p11_path_expand ("$TEMP/test-extract.XXXXXX"); + if (!mkdtemp (test.directory)) + assert_fail ("mkdtemp() failed", strerror (errno)); +} + +static void +teardown (void *unused) +{ + if (rmdir (test.directory) < 0) + assert_fail ("rmdir() failed", strerror (errno)); + free (test.directory); +} + +static void +write_zero_file (const char *directory, + const char *name) +{ + char *filename; + int res; + int fd; + + if (asprintf (&filename, "%s/%s", directory, name) < 0) + assert_not_reached (); + + fd = open (filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + assert (fd != -1); + res = close (fd); + assert (res >= 0); + + free (filename); +} + +static void +test_file_write (void) +{ + p11_save_file *file; + char *filename; + bool ret; + + if (asprintf (&filename, "%s/%s", test.directory, "extract-file") < 0) + assert_not_reached (); + + file = p11_save_open_file (filename, 0); + assert_ptr_not_null (file); + + ret = p11_save_write_and_finish (file, test_cacert3_ca_der, sizeof (test_cacert3_ca_der)); + assert_num_eq (true, ret); + free (filename); + + test_check_file (test.directory, "extract-file", SRCDIR "/files/cacert3.der"); +} + +static void +test_file_exists (void) +{ + p11_save_file *file; + char *filename; + + if (asprintf (&filename, "%s/%s", test.directory, "extract-file") < 0) + assert_not_reached (); + + write_zero_file (test.directory, "extract-file"); + + p11_message_quiet (); + + file = p11_save_open_file (filename, 0); + assert (file == NULL); + + p11_message_loud (); + + unlink (filename); + free (filename); +} + +static void +test_file_bad_directory (void) +{ + p11_save_file *file; + char *filename; + + if (asprintf (&filename, "/non-existent/%s/%s", test.directory, "extract-file") < 0) + assert_not_reached (); + + p11_message_quiet (); + + file = p11_save_open_file (filename, 0); + assert (file == NULL); + + p11_message_loud (); + + free (filename); +} + +static void +test_file_overwrite (void) +{ + p11_save_file *file; + char *filename; + bool ret; + + if (asprintf (&filename, "%s/%s", test.directory, "extract-file") < 0) + assert_not_reached (); + + write_zero_file (test.directory, "extract-file"); + + file = p11_save_open_file (filename, P11_SAVE_OVERWRITE); + assert_ptr_not_null (file); + + ret = p11_save_write_and_finish (file, test_cacert3_ca_der, sizeof (test_cacert3_ca_der)); + assert_num_eq (true, ret); + free (filename); + + test_check_file (test.directory, "extract-file", SRCDIR "/files/cacert3.der"); +} + +static void +test_file_auto_empty (void) +{ + p11_save_file *file; + char *filename; + bool ret; + + if (asprintf (&filename, "%s/%s", test.directory, "extract-file") < 0) + assert_not_reached (); + + file = p11_save_open_file (filename, 0); + assert_ptr_not_null (file); + + ret = p11_save_write_and_finish (file, NULL, -1); + assert_num_eq (true, ret); + free (filename); + + test_check_file (test.directory, "extract-file", SRCDIR "/files/empty-file"); +} + +static void +test_file_auto_length (void) +{ + p11_save_file *file; + char *filename; + bool ret; + + if (asprintf (&filename, "%s/%s", test.directory, "extract-file") < 0) + assert_not_reached (); + + file = p11_save_open_file (filename, 0); + assert_ptr_not_null (file); + + ret = p11_save_write_and_finish (file, "The simple string is hairy", -1); + assert_num_eq (true, ret); + free (filename); + + test_check_file (test.directory, "extract-file", SRCDIR "/files/simple-string"); +} + +static void +test_write_with_null (void) +{ + bool ret; + + ret = p11_save_write (NULL, "test", 4); + assert_num_eq (false, ret); +} + +static void +test_write_and_finish_with_null (void) +{ + bool ret; + + ret = p11_save_write_and_finish (NULL, "test", 4); + assert_num_eq (false, ret); +} + +static void +test_file_abort (void) +{ + struct stat st; + p11_save_file *file; + char *filename; + bool ret; + + if (asprintf (&filename, "%s/%s", test.directory, "extract-file") < 0) + assert_not_reached (); + + file = p11_save_open_file (filename, 0); + assert_ptr_not_null (file); + + ret = p11_save_finish_file (file, false); + assert_num_eq (true, ret); + + if (stat (filename, &st) >= 0 || errno != ENOENT) + assert_fail ("file should not exist", filename); + + free (filename); +} + + +static void +test_directory_empty (void) +{ + p11_save_dir *dir; + char *subdir; + bool ret; + + if (asprintf (&subdir, "%s/%s", test.directory, "extract-dir") < 0) + assert_not_reached (); + + dir = p11_save_open_directory (subdir, 0); + assert_ptr_not_null (dir); + + ret = p11_save_finish_directory (dir, true); + assert_num_eq (true, ret); + + test_check_directory (subdir, (NULL, NULL)); + + assert (rmdir (subdir) >= 0); + free (subdir); +} + +static void +test_directory_files (void) +{ + const char *filename; + p11_save_dir *dir; + char *subdir; + bool ret; + + if (asprintf (&subdir, "%s/%s", test.directory, "extract-dir") < 0) + assert_not_reached (); + + dir = p11_save_open_directory (subdir, 0); + assert_ptr_not_null (dir); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "blah", ".cer", &filename), + test_cacert3_ca_der, sizeof (test_cacert3_ca_der)); + assert_num_eq (true, ret); + assert_str_eq ("blah.cer", filename); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "file", ".txt", &filename), + test_text, strlen (test_text)); + assert_num_eq (true, ret); + assert_str_eq ("file.txt", filename); + +#ifdef OS_UNIX + ret = p11_save_symlink_in (dir, "link", ".ext", "/the/destination"); + assert_num_eq (true, ret); +#endif + + ret = p11_save_finish_directory (dir, true); + assert_num_eq (true, ret); + + test_check_directory (subdir, ("blah.cer", "file.txt", +#ifdef OS_UNIX + "link.ext", +#endif + NULL)); + test_check_file (subdir, "blah.cer", SRCDIR "/files/cacert3.der"); + test_check_data (subdir, "file.txt", test_text, strlen (test_text)); +#ifdef OS_UNIX + test_check_symlink (subdir, "link.ext", "/the/destination"); +#endif + + assert (rmdir (subdir) >= 0); + free (subdir); +} + +static void +test_directory_dups (void) +{ + const char *filename; + p11_save_dir *dir; + char *subdir; + bool ret; + + if (asprintf (&subdir, "%s/%s", test.directory, "extract-dir") < 0) + assert_not_reached (); + + dir = p11_save_open_directory (subdir, 0); + assert_ptr_not_null (dir); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "file", ".txt", &filename), + test_text, 5); + assert_num_eq (true, ret); + assert_str_eq ("file.txt", filename); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "file", ".txt", &filename), + test_text, 10); + assert_num_eq (true, ret); + assert_str_eq ("file.1.txt", filename); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "file", ".txt", NULL), + test_text, 15); + assert_num_eq (true, ret); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "no-ext", NULL, NULL), + test_text, 8); + assert_num_eq (true, ret); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "no-ext", NULL, NULL), + test_text, 16); + assert_num_eq (true, ret); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "with-num", ".0", NULL), + test_text, 14); + assert_num_eq (true, ret); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "with-num", ".0", NULL), + test_text, 15); + assert_num_eq (true, ret); + +#ifdef OS_UNIX + ret = p11_save_symlink_in (dir, "link", ".0", "/destination1"); + assert_num_eq (true, ret); + + ret = p11_save_symlink_in (dir, "link", ".0", "/destination2"); + assert_num_eq (true, ret); +#endif + + ret = p11_save_finish_directory (dir, true); + assert_num_eq (true, ret); + + test_check_directory (subdir, ("file.txt", "file.1.txt", "file.2.txt", + "no-ext", "no-ext.1", + "with-num.0", "with-num.1", +#ifdef OS_UNIX + "link.0", "link.1", +#endif + NULL)); + test_check_data (subdir, "file.txt", test_text, 5); + test_check_data (subdir, "file.1.txt", test_text, 10); + test_check_data (subdir, "file.2.txt", test_text, 15); + test_check_data (subdir, "no-ext", test_text, 8); + test_check_data (subdir, "no-ext.1", test_text, 16); + test_check_data (subdir, "with-num.0", test_text, 14); + test_check_data (subdir, "with-num.1", test_text, 15); +#ifdef OS_UNIX + test_check_symlink (subdir, "link.0", "/destination1"); + test_check_symlink (subdir, "link.1", "/destination2"); +#endif + + assert (rmdir (subdir) >= 0); + free (subdir); +} + +static void +test_directory_exists (void) +{ + p11_save_dir *dir; + char *subdir; + + if (asprintf (&subdir, "%s/%s", test.directory, "extract-dir") < 0) + assert_not_reached (); + +#ifdef OS_UNIX + if (mkdir (subdir, S_IRWXU) < 0) +#else + if (mkdir (subdir) < 0) +#endif + assert_fail ("mkdir() failed", subdir); + + p11_message_quiet (); + + dir = p11_save_open_directory (subdir, 0); + assert_ptr_eq (NULL, dir); + + p11_message_loud (); + + rmdir (subdir); + free (subdir); +} + +static void +test_directory_overwrite (void) +{ + const char *filename; + p11_save_dir *dir; + char *subdir; + bool ret; + + if (asprintf (&subdir, "%s/%s", test.directory, "extract-dir") < 0) + assert_not_reached (); + + /* Some initial files into this directory, which get overwritten */ + dir = p11_save_open_directory (subdir, 0); + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "file", ".txt", NULL), "", 0) && + p11_save_write_and_finish (p11_save_open_file_in (dir, "another-file", NULL, NULL), "", 0) && + p11_save_write_and_finish (p11_save_open_file_in (dir, "third-file", NULL, NULL), "", 0) && + p11_save_finish_directory (dir, true); + assert (ret && dir); + + /* Now the actual test, using the same directory */ + dir = p11_save_open_directory (subdir, P11_SAVE_OVERWRITE); + assert_ptr_not_null (dir); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "blah", ".cer", &filename), + test_cacert3_ca_der, sizeof (test_cacert3_ca_der)); + assert_num_eq (true, ret); + assert_str_eq ("blah.cer", filename); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "file", ".txt", &filename), + test_text, strlen (test_text)); + assert_num_eq (true, ret); + assert_str_eq ("file.txt", filename); + + ret = p11_save_write_and_finish (p11_save_open_file_in (dir, "file", ".txt", &filename), + test_text, 10); + assert_num_eq (true, ret); + assert_str_eq ("file.1.txt", filename); + + ret = p11_save_finish_directory (dir, true); + assert_num_eq (true, ret); + + test_check_directory (subdir, ("blah.cer", "file.txt", "file.1.txt", NULL)); + test_check_data (subdir, "blah.cer", test_cacert3_ca_der, sizeof (test_cacert3_ca_der)); + test_check_data (subdir, "file.txt", test_text, strlen (test_text)); + test_check_data (subdir, "file.1.txt", test_text, 10); + + assert (rmdir (subdir) >= 0); + free (subdir); +} + +int +main (int argc, + char *argv[]) +{ + p11_fixture (setup, teardown); + p11_test (test_file_write, "/save/test_file_write"); + p11_test (test_file_exists, "/save/test_file_exists"); + p11_test (test_file_bad_directory, "/save/test_file_bad_directory"); + p11_test (test_file_overwrite, "/save/test_file_overwrite"); + p11_test (test_file_auto_empty, "/save/test_file_auto_empty"); + p11_test (test_file_auto_length, "/save/test_file_auto_length"); + + p11_fixture (NULL, NULL); + p11_test (test_write_with_null, "/save/test_write_with_null"); + p11_test (test_write_and_finish_with_null, "/save/test_write_and_finish_with_null"); + + p11_fixture (setup, teardown); + p11_test (test_file_abort, "/save/test_file_abort"); + + p11_test (test_directory_empty, "/save/test_directory_empty"); + p11_test (test_directory_files, "/save/test_directory_files"); + p11_test (test_directory_dups, "/save/test_directory_dups"); + p11_test (test_directory_exists, "/save/test_directory_exists"); + p11_test (test_directory_overwrite, "/save/test_directory_overwrite"); + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-trust.c b/trust/tests/test-trust.c index 6a22946..33ba19e 100644 --- a/trust/tests/test-trust.c +++ b/trust/tests/test-trust.c @@ -33,15 +33,24 @@ */ #include "config.h" -#include "test.h" #include "attrs.h" +#include "debug.h" +#include "test.h" + #include "test-trust.h" +#include <sys/stat.h> + #include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <unistd.h> void test_check_object_msg (const char *file, @@ -150,3 +159,168 @@ test_check_attr_msg (const char *file, attr ? p11_attr_to_string (attr, klass) : "(null)"); } } + +static char * +read_file (const char *file, + int line, + const char *function, + const char *filename, + long *len) +{ + struct stat sb; + FILE *f = NULL; + char *data; + + f = fopen (filename, "rb"); + if (f == NULL) + p11_test_fail (file, line, function, "Couldn't open file: %s", filename); + + /* Figure out size */ + if (stat (filename, &sb) < 0) + p11_test_fail (file, line, function, "Couldn't stat file: %s", filename); + + *len = sb.st_size; + data = malloc (*len ? *len : 1); + assert (data != NULL); + + /* And read in one block */ + if (fread (data, 1, *len, f) != *len) + p11_test_fail (file, line, function, "Couldn't read file: %s", filename); + + fclose (f); + + return data; +} + +void +test_check_file_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *name, + const char *reference) +{ + char *refdata; + long reflen; + + refdata = read_file (file, line, function, reference, &reflen); + test_check_data_msg (file, line, function, directory, name, refdata, reflen); + free (refdata); +} + +void +test_check_data_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *name, + const void *refdata, + long reflen) +{ + char *filedata; + char *filename; + long filelen; + + if (asprintf (&filename, "%s/%s", directory, name) < 0) + assert_not_reached (); + + filedata = read_file (file, line, function, filename, &filelen); + + if (filelen != reflen || memcmp (filedata, refdata, reflen) != 0) + p11_test_fail (file, line, function, "File contents not as expected: %s", filename); + + if (unlink (filename) < 0) + p11_test_fail (file, line, function, "Couldn't remove file: %s", filename); + free (filename); + free (filedata); +} + +#ifdef OS_UNIX + +void +test_check_symlink_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *name, + const char *destination) +{ + char buf[1024] = { 0, }; + char *filename; + + if (asprintf (&filename, "%s/%s", directory, name) < 0) + assert_not_reached (); + + if (readlink (filename, buf, sizeof (buf)) < 0) + p11_test_fail (file, line, function, "Couldn't read symlink: %s", filename); + + if (strcmp (destination, buf) != 0) + p11_test_fail (file, line, function, "Symlink contents wrong: %s != %s", destination, buf); + + if (unlink (filename) < 0) + p11_test_fail (file, line, function, "Couldn't remove symlink: %s", filename); + free (filename); +} + +#endif /* OS_UNIX */ + +p11_dict * +test_check_directory_files (const char *file, + ...) +{ + p11_dict *files; + va_list va; + + files = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL); + + va_start (va, file); + + while (file != NULL) { + if (!p11_dict_set (files, (void *)file, (void *)file)) + return_val_if_reached (NULL); + file = va_arg (va, const char *); + } + + va_end (va); + + return files; +} + +void +test_check_directory_msg (const char *file, + int line, + const char *function, + const char *directory, + p11_dict *files) +{ + p11_dictiter iter; + struct dirent *dp; + const char *name; + DIR *dir; + + dir = opendir (directory); + if (dir == NULL) + p11_test_fail (file ,line, function, "Couldn't open directory: %s", directory); + + while ((dp = readdir (dir)) != NULL) { + if (strcmp (dp->d_name, ".") == 0 || + strcmp (dp->d_name, "..") == 0) + continue; + + if (!p11_dict_remove (files, dp->d_name)) + p11_test_fail (file, line, function, "Unexpected file in directory: %s", dp->d_name); + } + + closedir (dir); + +#ifdef OS_UNIX + if (chmod (directory, S_IRWXU) < 0) + p11_test_fail (file, line, function, "couldn't chown directory: %s: %s", directory, strerror (errno)); +#endif + + p11_dict_iterate (files, &iter); + while (p11_dict_next (&iter, (void **)&name, NULL)) + p11_test_fail (file, line, function, "Couldn't find file in directory: %s", name); + + p11_dict_free (files); +} diff --git a/trust/tests/test-trust.h b/trust/tests/test-trust.h index 672ae64..18ca13c 100644 --- a/trust/tests/test-trust.h +++ b/trust/tests/test-trust.h @@ -32,9 +32,12 @@ * Author: Stef Walter <stefw@gnome.org> */ +#include "dict.h" #include "pkcs11.h" +#include "test.h" #include <sys/types.h> +#include <stdlib.h> #ifndef TEST_DATA_H_ #define TEST_DATA_H_ @@ -270,4 +273,75 @@ static const unsigned char verisign_v1_ca[] = { 0xfd, 0x76, 0x04, 0xdb, 0x62, 0xbb, 0x90, 0x6a, 0x03, 0xd9, 0x46, 0x35, 0xd9, 0xf8, 0x7c, 0x5b, }; +static const char test_text[] = "This is the file text"; + +static const char test_eku_server_and_client[] = { + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, +}; + +static const char test_eku_server[] = { + 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, +}; + +static const char test_eku_email[] = { + 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04 +}; + +static const char test_eku_none[] = { + 0x30, 0x00, +}; + +void test_check_file_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *filename, + const char *reference); + +void test_check_data_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *filename, + const void *refdata, + long reflen); + +#ifdef OS_UNIX + +void test_check_symlink_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *name, + const char *destination); + +#endif /* OS_UNIX */ + +p11_dict * test_check_directory_files (const char *file, + ...) GNUC_NULL_TERMINATED; + +void test_check_directory_msg (const char *file, + int line, + const char *function, + const char *directory, + p11_dict *files); + +#define test_check_file(directory, name, reference) \ + (test_check_file_msg (__FILE__, __LINE__, __FUNCTION__, directory, name, reference)) + +#define test_check_data(directory, name, data, length) \ + (test_check_data_msg (__FILE__, __LINE__, __FUNCTION__, directory, name, data, length)) + +#ifdef OS_UNIX + +#define test_check_symlink(directory, name, destination) \ + (test_check_symlink_msg (__FILE__, __LINE__, __FUNCTION__, directory, name, destination)) + +#endif /* OS_UNIX */ + +#define test_check_directory(directory, files) \ + (test_check_directory_msg (__FILE__, __LINE__, __FUNCTION__, directory, \ + test_check_directory_files files)) + #endif /* TEST_DATA_H_ */ diff --git a/trust/tests/test-utf8.c b/trust/tests/test-utf8.c new file mode 100644 index 0000000..9b2c3d5 --- /dev/null +++ b/trust/tests/test-utf8.c @@ -0,0 +1,244 @@ +/* + * 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 "test.h" + +#include "utf8.h" + +#include <stdio.h> +#include <stdlib.h> + +#define ELEMS(x) (sizeof (x) / sizeof (x[0])) + +static void +test_ucs2be (void) +{ + char *output; + size_t length; + int i; + + struct { + const char *output; + size_t output_len; + const unsigned char input[100]; + size_t input_len; + } fixtures[] = { + { "This is a test", 14, + { 0x00, 'T', 0x00, 'h', 0x00, 'i', 0x00, 's', 0x00, ' ', 0x00, 'i', 0x00, 's', 0x00, ' ', + 0x00, 'a', 0x00, ' ', 0x00, 't', 0x00, 'e', 0x00, 's', 0x00, 't' }, 28, + }, + { "V\303\266gel", 6, + { 0x00, 'V', 0x00, 0xF6, 0x00, 'g', 0x00, 'e', 0x00, 'l' }, 10, + }, + { "M\303\244nwich \340\264\205", 12, + { 0x00, 'M', 0x00, 0xE4, 0x00, 'n', 0x00, 'w', 0x00, 'i', 0x00, 'c', 0x00, 'h', + 0x00, ' ', 0x0D, 0x05 }, 18, + } + }; + + for (i = 0; i < ELEMS (fixtures); i++) { + output = p11_utf8_for_ucs2be (fixtures[i].input, + fixtures[i].input_len, + &length); + + assert_num_eq (fixtures[i].output_len, length); + assert_str_eq (fixtures[i].output, output); + free (output); + } +} + +static void +test_ucs2be_fail (void) +{ + char *output; + size_t length; + int i; + + struct { + const unsigned char input[100]; + size_t input_len; + } fixtures[] = { + { { 0x00, 'T', 0x00, 'h', 0x00, 'i', 0x00, }, 7 /* truncated */ } + }; + + for (i = 0; i < ELEMS (fixtures); i++) { + output = p11_utf8_for_ucs2be (fixtures[i].input, + fixtures[i].input_len, + &length); + assert_ptr_eq (NULL, output); + } +} + +static void +test_ucs4be (void) +{ + char *output; + size_t length; + int i; + + struct { + const char *output; + size_t output_len; + const unsigned char input[100]; + size_t input_len; + } fixtures[] = { + { "This is a test", 14, + { 0x00, 0x00, 0x00, 'T', + 0x00, 0x00, 0x00, 'h', + 0x00, 0x00, 0x00, 'i', + 0x00, 0x00, 0x00, 's', + 0x00, 0x00, 0x00, ' ', + 0x00, 0x00, 0x00, 'i', + 0x00, 0x00, 0x00, 's', + 0x00, 0x00, 0x00, ' ', + 0x00, 0x00, 0x00, 'a', + 0x00, 0x00, 0x00, ' ', + 0x00, 0x00, 0x00, 't', + 0x00, 0x00, 0x00, 'e', + 0x00, 0x00, 0x00, 's', + 0x00, 0x00, 0x00, 't', + }, 56, + }, + { "Fun \360\220\214\231", 8, + { 0x00, 0x00, 0x00, 'F', + 0x00, 0x00, 0x00, 'u', + 0x00, 0x00, 0x00, 'n', + 0x00, 0x00, 0x00, ' ', + 0x00, 0x01, 0x03, 0x19, /* U+10319: looks like an antenna */ + }, 20, + } + }; + + for (i = 0; i < ELEMS (fixtures); i++) { + output = p11_utf8_for_ucs4be (fixtures[i].input, + fixtures[i].input_len, + &length); + + assert_num_eq (fixtures[i].output_len, length); + assert_str_eq (fixtures[i].output, output); + + free (output); + } +} + +static void +test_ucs4be_fail (void) +{ + char *output; + size_t length; + int i; + + struct { + const unsigned char input[100]; + size_t input_len; + } fixtures[] = { + { { 0x00, 0x00, 'T', + }, 7 /* truncated */ }, + { { 0x00, 0x00, 0x00, 'F', + 0x00, 0x00, 0x00, 'u', + 0x00, 0x00, 0x00, 'n', + 0x00, 0x00, 0x00, ' ', + 0xD8, 0x00, 0xDF, 0x19, + }, 20, + } + }; + + for (i = 0; i < ELEMS (fixtures); i++) { + output = p11_utf8_for_ucs4be (fixtures[i].input, + fixtures[i].input_len, + &length); + assert_ptr_eq (NULL, output); + } +} + +static void +test_utf8 (void) +{ + bool ret; + int i; + + struct { + const char *input; + size_t input_len; + } fixtures[] = { + { "This is a test", 14 }, + { "Good news everyone", -1 }, + { "Fun \360\220\214\231", -1 }, + { "Fun invalid here: \xfe", 4 }, /* but limited length */ + { "V\303\266gel", 6, }, + }; + + for (i = 0; i < ELEMS (fixtures); i++) { + ret = p11_utf8_validate (fixtures[i].input, + fixtures[i].input_len); + assert_num_eq (true, ret); + } +} + +static void +test_utf8_fail (void) +{ + bool ret; + int i; + + struct { + const char *input; + size_t input_len; + } fixtures[] = { + { "This is a test\x80", 15 }, + { "Good news everyone\x88", -1 }, + { "Bad \xe0v following chars should be |0x80", -1 }, + { "Truncated \xe0", -1 }, + }; + + for (i = 0; i < ELEMS (fixtures); i++) { + ret = p11_utf8_validate (fixtures[i].input, + fixtures[i].input_len); + assert_num_eq (false, ret); + } +} + +int +main (int argc, + char *argv[]) +{ + p11_test (test_ucs2be, "/utf8/ucs2be"); + p11_test (test_ucs2be_fail, "/utf8/ucs2be_fail"); + p11_test (test_ucs4be, "/utf8/ucs4be"); + p11_test (test_ucs4be_fail, "/utf8/ucs4be_fail"); + p11_test (test_utf8, "/utf8/utf8"); + p11_test (test_utf8_fail, "/utf8/utf8_fail"); + return p11_test_run (argc, argv); +} diff --git a/trust/tests/test-x509.c b/trust/tests/test-x509.c new file mode 100644 index 0000000..9f7d258 --- /dev/null +++ b/trust/tests/test-x509.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2012 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@gnome.org> + */ + +#include "config.h" +#include "test.h" + +#include "asn1.h" +#include "debug.h" +#include "oid.h" +#include "x509.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define ELEMS(x) (sizeof (x) / sizeof (x[0])) + +struct { + p11_dict *asn1_defs; +} test; + +static void +setup (void *unused) +{ + test.asn1_defs = p11_asn1_defs_load (); + assert_ptr_not_null (test.asn1_defs); +} + +static void +teardown (void *unused) +{ + p11_dict_free (test.asn1_defs); + memset (&test, 0, sizeof (test)); +} + +static const char test_ku_ds_and_np[] = { + 0x03, 0x03, 0x07, 0xc0, 0x00, +}; + +static const char test_ku_none[] = { + 0x03, 0x03, 0x07, 0x00, 0x00, +}; + +static const char test_ku_cert_crl_sign[] = { + 0x03, 0x03, 0x07, 0x06, 0x00, +}; + +static const char test_eku_server_and_client[] = { + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, +}; + +static const char test_eku_none[] = { + 0x30, 0x00, +}; + +static const char test_eku_client_email_and_timestamp[] = { + 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x08, +}; + +static const unsigned char test_cacert3_ca_der[] = { + 0x30, 0x82, 0x07, 0x59, 0x30, 0x82, 0x05, 0x41, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x0a, + 0x41, 0x8a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, + 0x43, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x31, 0x30, 0x35, 0x32, 0x33, 0x31, 0x37, 0x34, 0x38, 0x30, 0x32, 0x5a, 0x17, 0x0d, 0x32, + 0x31, 0x30, 0x35, 0x32, 0x30, 0x31, 0x37, 0x34, 0x38, 0x30, 0x32, 0x5a, 0x30, 0x54, 0x31, 0x14, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x43, + 0x41, 0x63, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, + 0x02, 0x01, 0x00, 0xab, 0x49, 0x35, 0x11, 0x48, 0x7c, 0xd2, 0x26, 0x7e, 0x53, 0x94, 0xcf, 0x43, + 0xa9, 0xdd, 0x28, 0xd7, 0x42, 0x2a, 0x8b, 0xf3, 0x87, 0x78, 0x19, 0x58, 0x7c, 0x0f, 0x9e, 0xda, + 0x89, 0x7d, 0xe1, 0xfb, 0xeb, 0x72, 0x90, 0x0d, 0x74, 0xa1, 0x96, 0x64, 0xab, 0x9f, 0xa0, 0x24, + 0x99, 0x73, 0xda, 0xe2, 0x55, 0x76, 0xc7, 0x17, 0x7b, 0xf5, 0x04, 0xac, 0x46, 0xb8, 0xc3, 0xbe, + 0x7f, 0x64, 0x8d, 0x10, 0x6c, 0x24, 0xf3, 0x61, 0x9c, 0xc0, 0xf2, 0x90, 0xfa, 0x51, 0xe6, 0xf5, + 0x69, 0x01, 0x63, 0xc3, 0x0f, 0x56, 0xe2, 0x4a, 0x42, 0xcf, 0xe2, 0x44, 0x8c, 0x25, 0x28, 0xa8, + 0xc5, 0x79, 0x09, 0x7d, 0x46, 0xb9, 0x8a, 0xf3, 0xe9, 0xf3, 0x34, 0x29, 0x08, 0x45, 0xe4, 0x1c, + 0x9f, 0xcb, 0x94, 0x04, 0x1c, 0x81, 0xa8, 0x14, 0xb3, 0x98, 0x65, 0xc4, 0x43, 0xec, 0x4e, 0x82, + 0x8d, 0x09, 0xd1, 0xbd, 0xaa, 0x5b, 0x8d, 0x92, 0xd0, 0xec, 0xde, 0x90, 0xc5, 0x7f, 0x0a, 0xc2, + 0xe3, 0xeb, 0xe6, 0x31, 0x5a, 0x5e, 0x74, 0x3e, 0x97, 0x33, 0x59, 0xe8, 0xc3, 0x03, 0x3d, 0x60, + 0x33, 0xbf, 0xf7, 0xd1, 0x6f, 0x47, 0xc4, 0xcd, 0xee, 0x62, 0x83, 0x52, 0x6e, 0x2e, 0x08, 0x9a, + 0xa4, 0xd9, 0x15, 0x18, 0x91, 0xa6, 0x85, 0x92, 0x47, 0xb0, 0xae, 0x48, 0xeb, 0x6d, 0xb7, 0x21, + 0xec, 0x85, 0x1a, 0x68, 0x72, 0x35, 0xab, 0xff, 0xf0, 0x10, 0x5d, 0xc0, 0xf4, 0x94, 0xa7, 0x6a, + 0xd5, 0x3b, 0x92, 0x7e, 0x4c, 0x90, 0x05, 0x7e, 0x93, 0xc1, 0x2c, 0x8b, 0xa4, 0x8e, 0x62, 0x74, + 0x15, 0x71, 0x6e, 0x0b, 0x71, 0x03, 0xea, 0xaf, 0x15, 0x38, 0x9a, 0xd4, 0xd2, 0x05, 0x72, 0x6f, + 0x8c, 0xf9, 0x2b, 0xeb, 0x5a, 0x72, 0x25, 0xf9, 0x39, 0x46, 0xe3, 0x72, 0x1b, 0x3e, 0x04, 0xc3, + 0x64, 0x27, 0x22, 0x10, 0x2a, 0x8a, 0x4f, 0x58, 0xa7, 0x03, 0xad, 0xbe, 0xb4, 0x2e, 0x13, 0xed, + 0x5d, 0xaa, 0x48, 0xd7, 0xd5, 0x7d, 0xd4, 0x2a, 0x7b, 0x5c, 0xfa, 0x46, 0x04, 0x50, 0xe4, 0xcc, + 0x0e, 0x42, 0x5b, 0x8c, 0xed, 0xdb, 0xf2, 0xcf, 0xfc, 0x96, 0x93, 0xe0, 0xdb, 0x11, 0x36, 0x54, + 0x62, 0x34, 0x38, 0x8f, 0x0c, 0x60, 0x9b, 0x3b, 0x97, 0x56, 0x38, 0xad, 0xf3, 0xd2, 0x5b, 0x8b, + 0xa0, 0x5b, 0xea, 0x4e, 0x96, 0xb8, 0x7c, 0xd7, 0xd5, 0xa0, 0x86, 0x70, 0x40, 0xd3, 0x91, 0x29, + 0xb7, 0xa2, 0x3c, 0xad, 0xf5, 0x8c, 0xbb, 0xcf, 0x1a, 0x92, 0x8a, 0xe4, 0x34, 0x7b, 0xc0, 0xd8, + 0x6c, 0x5f, 0xe9, 0x0a, 0xc2, 0xc3, 0xa7, 0x20, 0x9a, 0x5a, 0xdf, 0x2c, 0x5d, 0x52, 0x5c, 0xba, + 0x47, 0xd5, 0x9b, 0xef, 0x24, 0x28, 0x70, 0x38, 0x20, 0x2f, 0xd5, 0x7f, 0x29, 0xc0, 0xb2, 0x41, + 0x03, 0x68, 0x92, 0xcc, 0xe0, 0x9c, 0xcc, 0x97, 0x4b, 0x45, 0xef, 0x3a, 0x10, 0x0a, 0xab, 0x70, + 0x3a, 0x98, 0x95, 0x70, 0xad, 0x35, 0xb1, 0xea, 0x85, 0x2b, 0xa4, 0x1c, 0x80, 0x21, 0x31, 0xa9, + 0xae, 0x60, 0x7a, 0x80, 0x26, 0x48, 0x00, 0xb8, 0x01, 0xc0, 0x93, 0x63, 0x55, 0x22, 0x91, 0x3c, + 0x56, 0xe7, 0xaf, 0xdb, 0x3a, 0x25, 0xf3, 0x8f, 0x31, 0x54, 0xea, 0x26, 0x8b, 0x81, 0x59, 0xf9, + 0xa1, 0xd1, 0x53, 0x11, 0xc5, 0x7b, 0x9d, 0x03, 0xf6, 0x74, 0x11, 0xe0, 0x6d, 0xb1, 0x2c, 0x3f, + 0x2c, 0x86, 0x91, 0x99, 0x71, 0x9a, 0xa6, 0x77, 0x8b, 0x34, 0x60, 0xd1, 0x14, 0xb4, 0x2c, 0xac, + 0x9d, 0xaf, 0x8c, 0x10, 0xd3, 0x9f, 0xc4, 0x6a, 0xf8, 0x6f, 0x13, 0xfc, 0x73, 0x59, 0xf7, 0x66, + 0x42, 0x74, 0x1e, 0x8a, 0xe3, 0xf8, 0xdc, 0xd2, 0x6f, 0x98, 0x9c, 0xcb, 0x47, 0x98, 0x95, 0x40, + 0x05, 0xfb, 0xe9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x0d, 0x30, 0x82, 0x02, 0x09, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x75, 0xa8, 0x71, 0x60, 0x4c, + 0x88, 0x13, 0xf0, 0x78, 0xd9, 0x89, 0x77, 0xb5, 0x6d, 0xc5, 0x89, 0xdf, 0xbc, 0xb1, 0x7a, 0x30, + 0x81, 0xa3, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0x9b, 0x30, 0x81, 0x98, 0x80, 0x14, 0x16, + 0xb5, 0x32, 0x1b, 0xd4, 0xc7, 0xf3, 0xe0, 0xe6, 0x8e, 0xf3, 0xbd, 0xd2, 0xb0, 0x3a, 0xee, 0xb2, + 0x39, 0x18, 0xd1, 0xa1, 0x7d, 0xa4, 0x7b, 0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69, + 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, + 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, + 0x72, 0x67, 0x82, 0x01, 0x00, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x5d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x51, 0x30, 0x4f, 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, + 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x63, + 0x61, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x43, 0x30, 0x41, + 0x30, 0x3f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0x90, 0x4a, 0x30, 0x33, 0x30, 0x31, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x70, 0x68, 0x70, 0x3f, 0x69, 0x64, 0x3d, 0x31, + 0x30, 0x30, 0x34, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x08, 0x04, 0x27, + 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, + 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x70, 0x68, + 0x70, 0x3f, 0x69, 0x64, 0x3d, 0x31, 0x30, 0x30, 0x50, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, + 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x43, 0x16, 0x41, 0x54, 0x6f, 0x20, 0x67, 0x65, 0x74, 0x20, 0x79, + 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x46, 0x52, 0x45, 0x45, 0x2c, 0x20, 0x67, 0x6f, + 0x20, 0x74, 0x6f, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, + 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x29, 0x28, 0x85, + 0xae, 0x44, 0xa9, 0xb9, 0xaf, 0xa4, 0x79, 0x13, 0xf0, 0xa8, 0xa3, 0x2b, 0x97, 0x60, 0xf3, 0x5c, + 0xee, 0xe3, 0x2f, 0xc1, 0xf6, 0xe2, 0x66, 0xa0, 0x11, 0xae, 0x36, 0x37, 0x3a, 0x76, 0x15, 0x04, + 0x53, 0xea, 0x42, 0xf5, 0xf9, 0xea, 0xc0, 0x15, 0xd8, 0xa6, 0x82, 0xd9, 0xe4, 0x61, 0xae, 0x72, + 0x0b, 0x29, 0x5c, 0x90, 0x43, 0xe8, 0x41, 0xb2, 0xe1, 0x77, 0xdb, 0x02, 0x13, 0x44, 0x78, 0x47, + 0x55, 0xaf, 0x58, 0xfc, 0xcc, 0x98, 0xf6, 0x45, 0xb9, 0xd1, 0x20, 0xf8, 0xd8, 0x21, 0x07, 0xfe, + 0x6d, 0xaa, 0x73, 0xd4, 0xb3, 0xc6, 0x07, 0xe9, 0x09, 0x85, 0xcc, 0x3b, 0xf2, 0xb6, 0xbe, 0x2c, + 0x1c, 0x25, 0xd5, 0x71, 0x8c, 0x39, 0xb5, 0x2e, 0xea, 0xbe, 0x18, 0x81, 0xba, 0xb0, 0x93, 0xb8, + 0x0f, 0xe3, 0xe6, 0xd7, 0x26, 0x8c, 0x31, 0x5a, 0x72, 0x03, 0x84, 0x52, 0xe6, 0xa6, 0xf5, 0x33, + 0x22, 0x45, 0x0a, 0xc8, 0x0b, 0x0d, 0x8a, 0xb8, 0x36, 0x6f, 0x90, 0x09, 0xa1, 0xab, 0xbd, 0xd7, + 0xd5, 0x4e, 0x2e, 0x71, 0xa2, 0xd4, 0xae, 0xfa, 0xa7, 0x54, 0x2b, 0xeb, 0x35, 0x8d, 0x5a, 0xb7, + 0x54, 0x88, 0x2f, 0xee, 0x74, 0x9f, 0xed, 0x48, 0x16, 0xca, 0x0d, 0x48, 0xd0, 0x94, 0xd3, 0xac, + 0xa4, 0xa2, 0xf6, 0x24, 0xdf, 0x92, 0xe3, 0xbd, 0xeb, 0x43, 0x40, 0x91, 0x6e, 0x1c, 0x18, 0x8e, + 0x56, 0xb4, 0x82, 0x12, 0xf3, 0xa9, 0x93, 0x9f, 0xd4, 0xbc, 0x9c, 0xad, 0x9c, 0x75, 0xee, 0x5a, + 0x97, 0x1b, 0x95, 0xe7, 0x74, 0x2d, 0x1c, 0x0f, 0xb0, 0x2c, 0x97, 0x9f, 0xfb, 0xa9, 0x33, 0x39, + 0x7a, 0xe7, 0x03, 0x3a, 0x92, 0x8e, 0x22, 0xf6, 0x8c, 0x0d, 0xe4, 0xd9, 0x7e, 0x0d, 0x76, 0x18, + 0xf7, 0x01, 0xf9, 0xef, 0x96, 0x96, 0xa2, 0x55, 0x73, 0xc0, 0x3c, 0x71, 0xb4, 0x1d, 0x1a, 0x56, + 0x43, 0xb7, 0xc3, 0x0a, 0x8d, 0x72, 0xfc, 0xe2, 0x10, 0x09, 0x0b, 0x41, 0xce, 0x8c, 0x94, 0xa0, + 0xf9, 0x03, 0xfd, 0x71, 0x73, 0x4b, 0x8a, 0x57, 0x33, 0xe5, 0x8e, 0x74, 0x7e, 0x15, 0x01, 0x00, + 0xe6, 0xcc, 0x4a, 0x1c, 0xe7, 0x7f, 0x95, 0x19, 0x2d, 0xc5, 0xa5, 0x0c, 0x8b, 0xbb, 0xb5, 0xed, + 0x85, 0xb3, 0x5c, 0xd3, 0xdf, 0xb8, 0xb9, 0xf2, 0xca, 0xc7, 0x0d, 0x01, 0x14, 0xac, 0x70, 0x58, + 0xc5, 0x8c, 0x8d, 0x33, 0xd4, 0x9d, 0x66, 0xa3, 0x1a, 0x50, 0x95, 0x23, 0xfc, 0x48, 0xe0, 0x06, + 0x43, 0x12, 0xd9, 0xcd, 0xa7, 0x86, 0x39, 0x2f, 0x36, 0x72, 0xa3, 0x80, 0x10, 0xe4, 0xe1, 0xf3, + 0xd1, 0xcb, 0x5b, 0x1a, 0xc0, 0xe4, 0x80, 0x9a, 0x7c, 0x13, 0x73, 0x06, 0x4f, 0xdb, 0xa3, 0x6b, + 0x24, 0x0a, 0xba, 0xb3, 0x1c, 0xbc, 0x4a, 0x78, 0xbb, 0xe5, 0xe3, 0x75, 0x38, 0xa5, 0x48, 0xa7, + 0xa2, 0x1e, 0xaf, 0x76, 0xd4, 0x5e, 0xf7, 0x38, 0x86, 0x56, 0x5a, 0x89, 0xce, 0xd6, 0xc3, 0xa7, + 0x79, 0xb2, 0x52, 0xa0, 0xc6, 0xf1, 0x85, 0xb4, 0x25, 0x8c, 0xf2, 0x3f, 0x96, 0xb3, 0x10, 0xd9, + 0x8d, 0x6c, 0x57, 0x3b, 0x9f, 0x6f, 0x86, 0x3a, 0x18, 0x82, 0x22, 0x36, 0xc8, 0xb0, 0x91, 0x38, + 0xdb, 0x2a, 0xa1, 0x93, 0xaa, 0x84, 0x3f, 0xf5, 0x27, 0x65, 0xae, 0x73, 0xd5, 0xc8, 0xd5, 0xd3, + 0x77, 0xea, 0x4b, 0x9d, 0xc7, 0x41, 0xbb, 0xc7, 0xc0, 0xe3, 0xa0, 0x3f, 0xe4, 0x7d, 0xa4, 0x8d, + 0x73, 0xe6, 0x12, 0x4b, 0xdf, 0xa1, 0x73, 0x73, 0x73, 0x3a, 0x80, 0xe8, 0xd5, 0xcb, 0x8e, 0x2f, + 0xcb, 0xea, 0x13, 0xa7, 0xd6, 0x41, 0x8b, 0xac, 0xfa, 0x3c, 0x89, 0xd7, 0x24, 0xf5, 0x4e, 0xb4, + 0xe0, 0x61, 0x92, 0xb7, 0xf3, 0x37, 0x98, 0xc4, 0xbe, 0x96, 0xa3, 0xb7, 0x8a, +}; + +struct { + const char *eku; + size_t length; + const char *expected[16]; +} extended_key_usage_fixtures[] = { + { test_eku_server_and_client, sizeof (test_eku_server_and_client), + { P11_OID_SERVER_AUTH_STR, P11_OID_CLIENT_AUTH_STR, NULL }, }, + { test_eku_none, sizeof (test_eku_none), + { NULL, }, }, + { test_eku_client_email_and_timestamp, sizeof (test_eku_client_email_and_timestamp), + { P11_OID_CLIENT_AUTH_STR, P11_OID_EMAIL_PROTECTION_STR, P11_OID_TIME_STAMPING_STR }, }, + { NULL }, +}; + +static void +test_parse_extended_key_usage (void) +{ + p11_array *ekus; + int i, j, count; + + for (i = 0; extended_key_usage_fixtures[i].eku != NULL; i++) { + ekus = p11_x509_parse_extended_key_usage (test.asn1_defs, + (const unsigned char *)extended_key_usage_fixtures[i].eku, + extended_key_usage_fixtures[i].length); + assert_ptr_not_null (ekus); + + for (count = 0; extended_key_usage_fixtures[i].expected[count] != NULL; count++); + + assert_num_eq (count, ekus->num); + for (j = 0; j < count; j++) + assert_str_eq (ekus->elem[j], extended_key_usage_fixtures[i].expected[j]); + + p11_array_free (ekus); + } +} + +struct { + const char *ku; + size_t length; + unsigned int expected; +} key_usage_fixtures[] = { + { test_ku_ds_and_np, sizeof (test_ku_ds_and_np), P11_KU_DIGITAL_SIGNATURE | P11_KU_NON_REPUDIATION }, + { test_ku_none, sizeof (test_ku_none), 0 }, + { test_ku_cert_crl_sign, sizeof (test_ku_cert_crl_sign), P11_KU_KEY_CERT_SIGN | P11_KU_CRL_SIGN }, + { NULL }, +}; + +static void +test_parse_key_usage (void) +{ + unsigned int ku; + int i; + bool ret; + + for (i = 0; key_usage_fixtures[i].ku != NULL; i++) { + ku = 0; + + ret = p11_x509_parse_key_usage (test.asn1_defs, + (const unsigned char *)key_usage_fixtures[i].ku, + key_usage_fixtures[i].length, &ku); + assert_num_eq (true, ret); + + assert_num_eq (key_usage_fixtures[i].expected, ku); + } +} + +static void +test_parse_extension (void) +{ + node_asn *cert; + unsigned char *ext; + size_t length; + bool is_ca; + + cert = p11_asn1_decode (test.asn1_defs, "PKIX1.Certificate", + test_cacert3_ca_der, sizeof (test_cacert3_ca_der), NULL); + assert_ptr_not_null (cert); + + ext = p11_x509_find_extension (cert, P11_OID_BASIC_CONSTRAINTS, + test_cacert3_ca_der, sizeof (test_cacert3_ca_der), + &length); + assert_ptr_not_null (ext); + assert (length > 0); + + asn1_delete_structure (&cert); + + if (!p11_x509_parse_basic_constraints (test.asn1_defs, ext, length, &is_ca)) + assert_fail ("failed to parse message", "basic constraints"); + + free (ext); +} +static void +test_parse_extension_not_found (void) +{ + node_asn *cert; + unsigned char *ext; + size_t length; + + cert = p11_asn1_decode (test.asn1_defs, "PKIX1.Certificate", + test_cacert3_ca_der, sizeof (test_cacert3_ca_der), NULL); + assert_ptr_not_null (cert); + + ext = p11_x509_find_extension (cert, P11_OID_OPENSSL_REJECT, + test_cacert3_ca_der, sizeof (test_cacert3_ca_der), + &length); + assert_ptr_eq (NULL, ext); + + asn1_delete_structure (&cert); +} + +static void +test_directory_string (void) +{ + struct { + unsigned char input[100]; + int input_len; + char *output; + int output_len; + } fixtures[] = { + /* UTF8String */ + { { 0x0c, 0x0f, 0xc3, 0x84, ' ', 'U', 'T', 'F', '8', ' ', 's', 't', 'r', 'i', 'n', 'g', ' ', }, 17, + "\xc3\x84 UTF8 string ", 15, + }, + + /* NumericString */ + { { 0x12, 0x04, '0', '1', '2', '3', }, 6, + "0123", 4, + }, + + /* IA5String */ + { { 0x16, 0x04, ' ', 'A', 'B', ' ', }, 6, + " AB ", 4 + }, + + /* TeletexString */ + { { 0x14, 0x07, 'A', ' ', ' ', 'n', 'i', 'c', 'e' }, 9, + "A nice", 7 + }, + + /* PrintableString */ + { { 0x13, 0x07, 'A', ' ', ' ', 'n', 'i', 'c', 'e' }, 9, + "A nice", 7, + }, + + /* UniversalString */ + { { 0x1c, 0x14, 0x00, 0x00, 0x00, 'F', 0x00, 0x00, 0x00, 'u', + 0x00, 0x00, 0x00, 'n', 0x00, 0x00, 0x00, ' ', 0x00, 0x01, 0x03, 0x19, }, 22, + "Fun \xf0\x90\x8c\x99", 8 + }, + + /* BMPString */ + { { 0x1e, 0x0a, 0x00, 'V', 0x00, 0xF6, 0x00, 'g', 0x00, 'e', 0x00, 'l' }, 12, + "V\xc3\xb6gel", 6 + }, + }; + + char *string; + bool unknown; + size_t length; + int i; + + for (i = 0; i < ELEMS (fixtures); i++) { + string = p11_x509_parse_directory_string (fixtures[i].input, + fixtures[i].input_len, + &unknown, &length); + assert_ptr_not_null (string); + assert_num_eq (false, unknown); + + assert_num_eq (fixtures[i].output_len, length); + assert_str_eq (fixtures[i].output, string); + free (string); + } +} + +static void +test_directory_string_unknown (void) +{ + /* Not a valid choice in DirectoryString */ + unsigned char input[] = { 0x05, 0x07, 'A', ' ', ' ', 'n', 'i', 'c', 'e' }; + char *string; + bool unknown = false; + size_t length; + + string = p11_x509_parse_directory_string (input, sizeof (input), &unknown, &length); + assert_ptr_eq (NULL, string); + assert_num_eq (true, unknown); +} + +int +main (int argc, + char *argv[]) +{ + p11_fixture (setup, teardown); + p11_test (test_parse_extended_key_usage, "/x509/parse-extended-key-usage"); + p11_test (test_parse_key_usage, "/x509/parse-key-usage"); + p11_test (test_parse_extension, "/x509/parse-extension"); + p11_test (test_parse_extension_not_found, "/x509/parse-extension-not-found"); + + p11_fixture (NULL, NULL); + p11_test (test_directory_string, "/x509/directory-string"); + p11_test (test_directory_string_unknown, "/x509/directory-string-unknown"); + return p11_test_run (argc, argv); +} diff --git a/trust/trust.c b/trust/trust.c new file mode 100644 index 0000000..1993951 --- /dev/null +++ b/trust/trust.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011, Collabora Ltd. + * + * 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 "extract.h" + +#include "buffer.h" +#include "compat.h" +#include "debug.h" +#include "message.h" +#include "path.h" +#include "tool.h" + +#include <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static const p11_tool_command commands[] = { + { "extract", p11_trust_extract, "Extract certificates and trust" }, + { 0, } +}; + +int +main (int argc, + char *argv[]) +{ + return p11_tool_main (argc, argv, commands); +} diff --git a/trust/utf8.c b/trust/utf8.c new file mode 100644 index 0000000..b94c3e7 --- /dev/null +++ b/trust/utf8.c @@ -0,0 +1,329 @@ +/* + * 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 "buffer.h" +#include "debug.h" +#include "utf8.h" + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +/* + * Some parts come from FreeBSD utf8.c + * + * Copyright (c) 2002-2004 Tim J. Robbins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +static ssize_t +utf8_to_uchar (const char *str, + size_t len, + uint32_t *uc) +{ + int ch, i, mask, want; + uint32_t lbound, uch; + + assert (str != NULL); + assert (len > 0); + assert (uc != NULL); + + if (((ch = (unsigned char)*str) & ~0x7f) == 0) { + /* Fast path for plain ASCII characters. */ + *uc = ch; + return 1; + } + + /* + * Determine the number of octets that make up this character + * from the first octet, and a mask that extracts the + * interesting bits of the first octet. We already know + * the character is at least two bytes long. + * + * We also specify a lower bound for the character code to + * detect redundant, non-"shortest form" encodings. For + * example, the sequence C0 80 is _not_ a legal representation + * of the null character. This enforces a 1-to-1 mapping + * between character codes and their multibyte representations. + */ + ch = (unsigned char)*str; + if ((ch & 0xe0) == 0xc0) { + mask = 0x1f; + want = 2; + lbound = 0x80; + } else if ((ch & 0xf0) == 0xe0) { + mask = 0x0f; + want = 3; + lbound = 0x800; + } else if ((ch & 0xf8) == 0xf0) { + mask = 0x07; + want = 4; + lbound = 0x10000; + } else if ((ch & 0xfc) == 0xf8) { + mask = 0x03; + want = 5; + lbound = 0x200000; + } else if ((ch & 0xfe) == 0xfc) { + mask = 0x01; + want = 6; + lbound = 0x4000000; + } else { + /* + * Malformed input; input is not UTF-8. + */ + return -1; + } + + if (want > len) { + /* Incomplete multibyte sequence. */ + return -1; + } + + /* + * Decode the octet sequence representing the character in chunks + * of 6 bits, most significant first. + */ + uch = (unsigned char)*str++ & mask; + for (i = 1; i < want; i++) { + if ((*str & 0xc0) != 0x80) { + /* + * Malformed input; bad characters in the middle + * of a character. + */ + return -1; + } + uch <<= 6; + uch |= *str++ & 0x3f; + } + if (uch < lbound) { + /* + * Malformed input; redundant encoding. + */ + return -1; + } + + *uc = uch; + return want; +} + +static size_t +utf8_for_uchar (uint32_t uc, + char *str, + size_t len) +{ + unsigned char lead; + int i, want; + + assert (str != NULL); + assert (len >= 6); + + if ((uc & ~0x7f) == 0) { + /* Fast path for plain ASCII characters. */ + *str = (char)uc; + return 1; + } + + /* + * Determine the number of octets needed to represent this character. + * We always output the shortest sequence possible. Also specify the + * first few bits of the first octet, which contains the information + * about the sequence length. + */ + if ((uc & ~0x7ff) == 0) { + lead = 0xc0; + want = 2; + } else if ((uc & ~0xffff) == 0) { + lead = 0xe0; + want = 3; + } else if ((uc & ~0x1fffff) == 0) { + lead = 0xf0; + want = 4; + } else if ((uc & ~0x3ffffff) == 0) { + lead = 0xf8; + want = 5; + } else if ((uc & ~0x7fffffff) == 0) { + lead = 0xfc; + want = 6; + } else { + return -1; + } + + assert (want <= len); + + /* + * Output the octets representing the character in chunks + * of 6 bits, least significant last. The first octet is + * a special case because it contains the sequence length + * information. + */ + for (i = want - 1; i > 0; i--) { + str[i] = (uc & 0x3f) | 0x80; + uc >>= 6; + } + *str = (uc & 0xff) | lead; + return want; +} + +static ssize_t +ucs2be_to_uchar (const unsigned char *str, + size_t len, + uint32_t *wc) +{ + assert (str != NULL); + assert (len != 0); + assert (wc != NULL); + + if (len < 2) + return -1; + + *wc = (str[0] << 8 | str[1]); + return 2; +} + +static ssize_t +ucs4be_to_uchar (const unsigned char *str, + size_t len, + uint32_t *uc) +{ + assert (str != NULL); + assert (len != 0); + assert (uc != NULL); + + if (len < 4) + return -1; + + *uc = (str[0] << 24 | str[1] << 16 | str[2] << 8 | str[3]); + return 4; +} + +bool +p11_utf8_validate (const char *str, + ssize_t len) +{ + uint32_t dummy; + ssize_t ret; + + if (len < 0) + len = strlen (str); + + while (len > 0) { + ret = utf8_to_uchar (str, len, &dummy); + if (ret < 0) + return false; + str += ret; + len -= ret; + } + + return true; +} + +static char * +utf8_for_convert (ssize_t (* convert) (const unsigned char *, size_t, uint32_t *), + const unsigned char *str, + size_t num_bytes, + size_t *ret_len) +{ + p11_buffer buf; + char block[6]; + uint32_t uc; + ssize_t ret; + + assert (convert); + + if (!p11_buffer_init_null (&buf, num_bytes)) + return_val_if_reached (NULL); + + while (num_bytes != 0) { + ret = (convert) (str, num_bytes, &uc); + if (ret < 0) { + p11_buffer_uninit (&buf); + return NULL; + } + + str += ret; + num_bytes -= ret; + + ret = utf8_for_uchar (uc, block, 6); + if (ret < 0) { + p11_buffer_uninit (&buf); + return NULL; + } + p11_buffer_add (&buf, block, ret); + } + + return_val_if_fail (p11_buffer_ok (&buf), NULL); + return p11_buffer_steal (&buf, ret_len); +} + +char * +p11_utf8_for_ucs2be (const unsigned char *str, + size_t num_bytes, + size_t *ret_len) +{ + assert (str != NULL); + return utf8_for_convert (ucs2be_to_uchar, str, num_bytes, ret_len); +} + +char * +p11_utf8_for_ucs4be (const unsigned char *str, + size_t num_bytes, + size_t *ret_len) +{ + assert (str != NULL); + return utf8_for_convert (ucs4be_to_uchar, str, num_bytes, ret_len); +} diff --git a/trust/utf8.h b/trust/utf8.h new file mode 100644 index 0000000..8efa66f --- /dev/null +++ b/trust/utf8.h @@ -0,0 +1,53 @@ +/* + * 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> + */ + +#ifndef P11_UTF8_H_ +#define P11_UTF8_H_ + +#include "compat.h" + +#include <sys/types.h> + +bool p11_utf8_validate (const char *str, + ssize_t len); + +char * p11_utf8_for_ucs2be (const unsigned char *str, + size_t num_bytes, + size_t *ret_len); + +char * p11_utf8_for_ucs4be (const unsigned char *str, + size_t num_bytes, + size_t *ret_len); + +#endif /* P11_UTF8_H_ */ diff --git a/trust/x509.c b/trust/x509.c new file mode 100644 index 0000000..aa6e171 --- /dev/null +++ b/trust/x509.c @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2012 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 "asn1.h" +#define P11_DEBUG_FLAG P11_DEBUG_TRUST +#include "debug.h" +#include "hash.h" +#include "oid.h" +#include "utf8.h" +#include "x509.h" + +#include <stdlib.h> +#include <string.h> + +unsigned char * +p11_x509_find_extension (node_asn *cert, + const unsigned char *oid, + const unsigned char *der, + size_t der_len, + size_t *ext_len) +{ + char field[128]; + char *value; + int start; + int end; + int ret; + int len; + int i; + + return_val_if_fail (cert != NULL, NULL); + return_val_if_fail (oid != NULL, NULL); + return_val_if_fail (ext_len != NULL, NULL); + + for (i = 1; ; i++) { + if (snprintf (field, sizeof (field), "tbsCertificate.extensions.?%u.extnID", i) < 0) + return_val_if_reached (NULL); + + ret = asn1_der_decoding_startEnd (cert, der, der_len, field, &start, &end); + + /* No more extensions */ + if (ret == ASN1_ELEMENT_NOT_FOUND) + break; + + return_val_if_fail (ret == ASN1_SUCCESS, NULL); + + /* Make sure it's a straightforward oid with certain assumptions */ + if (!p11_oid_simple (der + start, (end - start) + 1)) + continue; + + /* The one we're lookin for? */ + if (!p11_oid_equal (der + start, oid)) + continue; + + if (snprintf (field, sizeof (field), "tbsCertificate.extensions.?%u.extnValue", i) < 0) + return_val_if_reached (NULL); + + len = 0; + ret = asn1_read_value (cert, field, NULL, &len); + return_val_if_fail (ret == ASN1_MEM_ERROR, NULL); + + value = malloc (len); + return_val_if_fail (value != NULL, NULL); + + ret = asn1_read_value (cert, field, value, &len); + return_val_if_fail (ret == ASN1_SUCCESS, NULL); + + *ext_len = len; + return (unsigned char *)value; + } + + return NULL; +} + +bool +p11_x509_calc_keyid (node_asn *cert, + const unsigned char *der, + size_t der_len, + unsigned char *keyid) +{ + int start, end; + int ret; + + return_val_if_fail (cert != NULL, NULL); + return_val_if_fail (der != NULL, NULL); + return_val_if_fail (keyid != NULL, NULL); + + ret = asn1_der_decoding_startEnd (cert, der, der_len, "tbsCertificate.subjectPublicKeyInfo", &start, &end); + return_val_if_fail (ret == ASN1_SUCCESS, false); + return_val_if_fail (end >= start, false); + + p11_hash_sha1 (keyid, (der + start), (end - start) + 1, NULL); + return true; +} + +bool +p11_x509_parse_basic_constraints (p11_dict *asn1_defs, + const unsigned char *ext_der, + size_t ext_len, + bool *is_ca) +{ + char buffer[8]; + node_asn *ext; + int ret; + int len; + + return_val_if_fail (is_ca != NULL, false); + + ext = p11_asn1_decode (asn1_defs, "PKIX1.BasicConstraints", ext_der, ext_len, NULL); + if (ext == NULL) + return false; + + len = sizeof (buffer); + ret = asn1_read_value (ext, "cA", buffer, &len); + + /* Default value for cA is FALSE */ + if (ret == ASN1_ELEMENT_NOT_FOUND) { + *is_ca = false; + + } else { + return_val_if_fail (ret == ASN1_SUCCESS, false); + *is_ca = (strcmp (buffer, "TRUE") == 0); + } + + asn1_delete_structure (&ext); + + return true; +} + +bool +p11_x509_parse_key_usage (p11_dict *asn1_defs, + const unsigned char *ext_der, + size_t ext_len, + unsigned int *ku) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + unsigned char buf[2]; + node_asn *ext; + int len; + int ret; + + ext = p11_asn1_decode (asn1_defs, "PKIX1.KeyUsage", ext_der, ext_len, message); + if (ext == NULL) + return false; + + len = sizeof (buf); + ret = asn1_read_value (ext, "", buf, &len); + return_val_if_fail (ret == ASN1_SUCCESS, false); + + /* A bit string, so combine into one set of flags */ + *ku = buf[0] | (buf[1] << 8); + + asn1_delete_structure (&ext); + + return true; +} + +p11_array * +p11_x509_parse_extended_key_usage (p11_dict *asn1_defs, + const unsigned char *ext_der, + size_t ext_len) +{ + node_asn *asn; + char field[128]; + p11_array *ekus; + char *eku; + int ret; + int len; + int i; + + asn = p11_asn1_decode (asn1_defs, "PKIX1.ExtKeyUsageSyntax", ext_der, ext_len, NULL); + if (asn == NULL) + return NULL; + + ekus = p11_array_new (free); + + for (i = 1; ; i++) { + if (snprintf (field, sizeof (field), "?%u", i) < 0) + return_val_if_reached (NULL); + + len = 0; + ret = asn1_read_value (asn, field, NULL, &len); + if (ret == ASN1_ELEMENT_NOT_FOUND) + break; + + return_val_if_fail (ret == ASN1_MEM_ERROR, NULL); + + eku = malloc (len + 1); + return_val_if_fail (eku != NULL, NULL); + + ret = asn1_read_value (asn, field, eku, &len); + return_val_if_fail (ret == ASN1_SUCCESS, NULL); + + eku[len] = 0; + + /* If it's our reserved OID, then skip */ + if (strcmp (eku, P11_OID_RESERVED_PURPOSE_STR) == 0) { + free (eku); + continue; + } + + if (!p11_array_push (ekus, eku)) + return_val_if_reached (NULL); + } + + asn1_delete_structure (&asn); + + return ekus; +} + +char * +p11_x509_parse_directory_string (const unsigned char *input, + size_t input_len, + bool *unknown_string, + size_t *string_len) +{ + unsigned long tag; + unsigned char cls; + int tag_len; + int len_len; + const void *octets; + long octet_len; + int ret; + + ret = asn1_get_tag_der (input, input_len, &cls, &tag_len, &tag); + return_val_if_fail (ret == ASN1_SUCCESS, NULL); + + octet_len = asn1_get_length_der (input + tag_len, input_len - tag_len, &len_len); + return_val_if_fail (octet_len >= 0, false); + return_val_if_fail (tag_len + len_len + octet_len == input_len, NULL); + + octets = input + tag_len + len_len; + + if (unknown_string) + *unknown_string = false; + + /* The following strings are the ones we normalize */ + switch (tag) { + case 12: /* UTF8String */ + case 18: /* NumericString */ + case 22: /* IA5String */ + case 20: /* TeletexString */ + case 19: /* PrintableString */ + if (!p11_utf8_validate (octets, octet_len)) + return NULL; + if (string_len) + *string_len = octet_len; + return strndup (octets, octet_len); + + case 28: /* UniversalString */ + return p11_utf8_for_ucs4be (octets, octet_len, string_len); + + case 30: /* BMPString */ + return p11_utf8_for_ucs2be (octets, octet_len, string_len); + + /* Just pass through all the non-string types */ + default: + if (unknown_string) + *unknown_string = true; + return NULL; + } + +} + +char * +p11_x509_parse_dn_name (p11_dict *asn_defs, + const unsigned char *der, + size_t der_len, + const unsigned char *oid) +{ + node_asn *asn; + char *part; + + asn = p11_asn1_decode (asn_defs, "PKIX1.Name", der, der_len, NULL); + if (asn == NULL) + return NULL; + + part = p11_x509_lookup_dn_name (asn, NULL, der, der_len, oid); + asn1_delete_structure (&asn); + return part; +} + +char * +p11_x509_lookup_dn_name (node_asn *asn, + const char *dn_field, + const unsigned char *der, + size_t der_len, + const unsigned char *oid) +{ + unsigned char *value; + char field[128]; + int value_len; + char *part; + int i, j; + int start; + int end; + int ret; + + for (i = 1; true; i++) { + for (j = 1; true; j++) { + snprintf (field, sizeof (field), "%s%srdnSequence.?%d.?%d.type", + dn_field, dn_field ? "." : "", i, j); + + ret = asn1_der_decoding_startEnd (asn, der, der_len, field, &start, &end); + + /* No more dns */ + if (ret == ASN1_ELEMENT_NOT_FOUND) + break; + + return_val_if_fail (ret == ASN1_SUCCESS, NULL); + + /* Make sure it's a straightforward oid with certain assumptions */ + if (!p11_oid_simple (der + start, (end - start) + 1)) + continue; + + /* The one we're lookin for? */ + if (!p11_oid_equal (der + start, oid)) + continue; + + snprintf (field, sizeof (field), "%s%srdnSequence.?%d.?%d.value", + dn_field, dn_field ? "." : "", i, j); + + value_len = 0; + ret = asn1_read_value (asn, field, NULL, &value_len); + return_val_if_fail (ret == ASN1_MEM_ERROR, NULL); + + value = malloc (value_len + 1); + return_val_if_fail (value != NULL, NULL); + + ret = asn1_read_value (asn, field, value, &value_len); + return_val_if_fail (ret == ASN1_SUCCESS, false); + + part = p11_x509_parse_directory_string (value, value_len, NULL, NULL); + free (value); + + return part; + } + + if (j == 1) + break; + } + + return NULL; +} diff --git a/trust/x509.h b/trust/x509.h new file mode 100644 index 0000000..af91c28 --- /dev/null +++ b/trust/x509.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2012 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 <libtasn1.h> + +#include "array.h" +#include "dict.h" + +#ifndef P11_X509_H_ +#define P11_X509_H_ + +unsigned char * p11_x509_find_extension (node_asn *cert, + const unsigned char *oid, + const unsigned char *der, + size_t der_len, + size_t *ext_len); + +bool p11_x509_calc_keyid (node_asn *cert, + const unsigned char *der, + size_t der_len, + unsigned char *keyid); + +bool p11_x509_parse_basic_constraints (p11_dict *asn1_defs, + const unsigned char *ext_der, + size_t ext_len, + bool *is_ca); + +bool p11_x509_parse_key_usage (p11_dict *asn1_defs, + const unsigned char *data, + size_t length, + unsigned int *ku); + +p11_array * p11_x509_parse_extended_key_usage (p11_dict *asn1_defs, + const unsigned char *ext_der, + size_t ext_len); + +char * p11_x509_parse_dn_name (p11_dict *asn_defs, + const unsigned char *der, + size_t der_len, + const unsigned char *oid); + +char * p11_x509_lookup_dn_name (node_asn *asn, + const char *dn_field, + const unsigned char *der, + size_t der_len, + const unsigned char *oid); + +char * p11_x509_parse_directory_string (const unsigned char *input, + size_t input_len, + bool *unknown_string, + size_t *string_len); + +#endif /* P11_X509_H_ */ |