--- /dev/null
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = src test
--- /dev/null
+#!/bin/bash
+
+# Hello.
+# Run this file to generate the configure script.
+# You'll need Autoconf and Automake installed!
+
+aclocal && automake --add-missing --copy && autoconf
--- /dev/null
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.69])
+# TODO change the bug report address
+AC_INIT([rpki-validator], [0.0.1], [ydahhrk@gmail.com])
+AC_CONFIG_SRCDIR([src/main.c])
+AM_INIT_AUTOMAKE([subdir-objects])
+
+# Checks for programs.
+AC_PROG_CC
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_CHECK_HEADERS([netinet/in.h stdlib.h string.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+AC_CHECK_HEADER_STDBOOL
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_CHECK_FUNCS([memset socket])
+AC_SEARCH_LIBS([pthread_create], [pthread])
+
+# Check dependencies.
+PKG_CHECK_MODULES([CHECK], [check])
+PKG_CHECK_MODULES([GLIB], [glib-2.0])
+
+# Spit out the makefiles.
+AC_OUTPUT(Makefile src/Makefile test/Makefile)
--- /dev/null
+make distclean
+rm -frv \
+ Makefile.in \
+ aclocal.m4 \
+ autom4te.cache \
+ compile \
+ configure \
+ depcomp \
+ install-sh \
+ missing \
+ man/Makefile.in \
+ src/Makefile.in
+
--- /dev/null
+bin_PROGRAMS = rpki_validator
+
+rpki_validator_SOURCES = main.c
+rpki_validator_SOURCES += common.h
+rpki_validator_SOURCES += line_file.h
+rpki_validator_SOURCES += line_file.c
+rpki_validator_SOURCES += tal.h
+rpki_validator_SOURCES += tal.c
+
+rpki_validator_CFLAGS = -pedantic -Wall -std=gnu11 -O3 ${GLIB_CFLAGS}
+rpki_validator_LDADD = ${GLIB_LIBS}
--- /dev/null
+#ifndef SRC_RTR_COMMON_H_
+#define SRC_RTR_COMMON_H_
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+
+#endif /* SRC_RTR_COMMON_H_ */
--- /dev/null
+#include "line_file.h"
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct line_file {
+ FILE *file;
+ const char *file_name;
+ size_t offset;
+};
+
+/*
+ * @file_name is expected to outlive the lfile.
+ */
+int
+lfile_open(const char *file_name, struct line_file **result)
+{
+ struct line_file *lfile;
+ int err;
+
+ lfile = malloc(sizeof(struct line_file));
+ if (lfile == NULL)
+ return -ENOMEM;
+
+ lfile->file = fopen(file_name, "r");
+ if (lfile->file == NULL) {
+ err = errno;
+ free(lfile);
+ return err;
+ }
+ lfile->file_name = file_name;
+ lfile->offset = 0;
+
+ *result = lfile;
+ return 0;
+}
+
+void
+lfile_close(struct line_file *lf)
+{
+ fclose(lf->file);
+ free(lf);
+}
+
+/*
+ * On success, places the string in *result.
+ * On failure, returns error code.
+ * On EOF reached, returns zero but nullifies result.
+ *
+ * @result is allocated in the heap.
+ */
+int
+lfile_read(struct line_file *lfile, char **result)
+{
+ char *string;
+ size_t alloc_len;
+ ssize_t len;
+ ssize_t i;
+ int err;
+
+ /*
+ * Note to myself:
+ *
+ * getline() is very convoluted. I really don't like it. I'm actually
+ * considering getting rid of it and pulling off something that doesn't
+ * seem like it was designed by an alien, but it doesn't warrant going
+ * that far yet. Do not read its Linux man page; it didn't answer my
+ * questions. Go straight to POSIX instead.
+ *
+ * - If the file is empty, or all that's left is an empty line, it
+ * (confusingly) returns -1. errno will be 0, feof() should return
+ * 1, ferror() should return 0.
+ * - The fact that it returns the newline in the buffer is puzzling,
+ * because who the fuck wants that nonsense. You will want to remove
+ * it, BUT DON'T SWEAT IT IF IT'S NOT THERE, because the last line of
+ * the file might not be newline-terminated.
+ * - The string WILL be NULL-terminated, but the NULL chara will not be
+ * included in the returned length. BUT IT'S THERE. Don't worry about
+ * writing past the allocated space on the last line.
+ * - Newline is `\n` according to POSIX, which is good, because RFC 7730
+ * agrees. You will have to worry about `\r`, though.
+ *
+ * Also, the Linux man page claims the following:
+ *
+ * [The out] buffer should be freed by the user program even if
+ * getline() failed.
+ *
+ * This... does not exist in the POSIX spec. But it does make sense
+ * because getline is normally meant to be used repeatedly with a
+ * recycled buffer. (free() is a no-op if its argument is NULL so go
+ * nuts.)
+ */
+
+ string = NULL;
+ alloc_len = 0;
+ len = getline(&string, &alloc_len, lfile->file);
+
+ if (len == -1) {
+ err = errno;
+ free(string);
+ *result = NULL;
+ if (ferror(lfile->file))
+ return err;
+ if (feof(lfile->file))
+ return 0;
+ warnx("Supposedly unreachable code reached. ferror:%d feof:%d",
+ ferror(lfile->file), feof(lfile->file));
+ return -EINVAL;
+ }
+
+ lfile->offset += len;
+
+ /*
+ * Make sure that strlen() matches len.
+ * We should make the best out of the fact that we didn't use fgets(),
+ * after all.
+ */
+ for (i = 0; i < len; i++) {
+ if (string[i] == '\0') {
+ warnx("File %s has an illegal null character in its body. Please remove it.",
+ lfile_name(lfile));
+ free(string);
+ return -EINVAL;
+ }
+ }
+
+ if (len >= 2) {
+ if (string[len - 2] == '\r' && string[len - 1] == '\n')
+ string[len - 2] = '\0';
+ }
+ if (len >= 1) {
+ if (string[len - 1] == '\n')
+ string[len - 1] = '\0';
+ }
+
+ *result = string;
+ return 0;
+}
+
+const char *
+lfile_name(struct line_file *lfile)
+{
+ return lfile->file_name;
+}
+
+size_t
+lfile_offset(struct line_file *lfile)
+{
+ return lfile->offset;
+}
--- /dev/null
+#ifndef LINE_FILE_H_
+#define LINE_FILE_H_
+
+/*
+ * A "line file" is a text file that you want to read line-by-line.
+ *
+ * As defined by RFC7730 (the only current user of this code), lines are
+ * terminated by either CRLF or LF.
+ * (...which is the same as saying "lines are terminated by LF.")
+ */
+
+#include <stddef.h>
+
+struct line_file;
+
+int lfile_open(const char *, struct line_file **);
+void lfile_close();
+
+int lfile_read(struct line_file *, char **);
+
+const char *lfile_name(struct line_file *);
+size_t lfile_offset(struct line_file *);
+
+#endif /* LINE_FILE_H_ */
--- /dev/null
+#include <stdlib.h>
+
+int
+main(void)
+{
+ return EXIT_SUCCESS;
+}
--- /dev/null
+#include "tal.h"
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdio.h>
+
+#include "common.h"
+#include "line_file.h"
+
+struct uri {
+ char *string;
+ SLIST_ENTRY(uri) next;
+};
+
+SLIST_HEAD(uri_list, uri);
+
+struct tal {
+ struct uri_list uris;
+ /* Decoded; not base64. */
+ guchar *spki;
+ size_t spki_size;
+};
+
+static void
+uri_destroy(struct uri *uri)
+{
+ free(uri->string);
+ free(uri);
+}
+
+static void
+uris_destroy(struct uri_list *uris)
+{
+ struct uri *uri;
+
+ while (!SLIST_EMPTY(uris)) {
+ uri = SLIST_FIRST(uris);
+ SLIST_REMOVE_HEAD(uris, next);
+ uri_destroy(uri);
+ }
+}
+
+static int
+read_uri(struct line_file *lfile, struct uri **result)
+{
+ struct uri *uri;
+ int err;
+
+ uri = malloc(sizeof(struct uri));
+ if (uri == NULL) {
+ warnx("Out of memory");
+ return -ENOMEM;
+ }
+
+ err = lfile_read(lfile, &uri->string);
+ if (err) {
+ /* TODO have lfile_read print error msg */
+ free(uri);
+ return err;
+ }
+
+ *result = uri;
+ return 0;
+}
+
+static int
+read_uris(struct line_file *lfile, struct uri_list *uris)
+{
+ struct uri *previous, *uri;
+ int err;
+
+ err = read_uri(lfile, &uri);
+ if (err)
+ return err;
+
+ if (strcmp(uri->string, "") == 0) {
+ uri_destroy(uri);
+ warnx("TAL file %s contains no URIs", lfile_name(lfile));
+ return -EINVAL;
+ }
+
+ SLIST_INIT(uris);
+ SLIST_INSERT_HEAD(uris, uri, next);
+
+ do {
+ previous = uri;
+
+ err = read_uri(lfile, &uri);
+ if (err)
+ return err;
+
+ if (strcmp(uri->string, "") == 0) {
+ uri_destroy(uri);
+ return 0; /* Happy path */
+ }
+
+ SLIST_INSERT_AFTER(previous, uri, next);
+ } while (true);
+}
+
+/*
+ * Will usually allocate slightly more because of the newlines, but I'm fine
+ * with it.
+ */
+static size_t
+get_spki_alloc_size(struct line_file *lfile)
+{
+ struct stat st;
+ size_t result;
+
+ stat(lfile_name(lfile), &st);
+ result = st.st_size - lfile_offset(lfile);
+
+ /*
+ * See the documentation for g_base64_decode_step().
+ * I added `+ 1`. It's because `result / 4` truncates, and I'm not sure
+ * if the original equation meant to round up.
+ */
+ return (result / 4 + 1) * 3 + 3;
+}
+
+static int
+read_spki(struct line_file *lfile, struct tal *tal)
+{
+ char *line;
+ gint state = 0;
+ guint save = 0;
+ int err;
+
+ tal->spki = malloc(get_spki_alloc_size(lfile));
+ if (tal->spki == NULL)
+ return -ENOMEM;
+ tal->spki_size = 0;
+
+ do {
+ err = lfile_read(lfile, &line);
+ if (err) {
+ free(tal->spki);
+ return err;
+ }
+
+ if (line == NULL)
+ return 0;
+
+ tal->spki_size += g_base64_decode_step(line, strlen(line),
+ tal->spki + tal->spki_size, &state, &save);
+ free(line);
+ } while (true);
+}
+
+int
+tal_load(const char *file_name, struct tal **result)
+{
+ struct line_file *lfile;
+ struct tal *tal;
+ int err;
+
+ err = lfile_open(file_name, &lfile);
+ if (err)
+ return err;
+
+ tal = malloc(sizeof(struct tal));
+ if (tal == NULL) {
+ lfile_close(lfile);
+ return -ENOMEM;
+ }
+
+ err = read_uris(lfile, &tal->uris);
+ if (err) {
+ free(tal);
+ lfile_close(lfile);
+ return err;
+ }
+
+ err = read_spki(lfile, tal);
+ if (err) {
+ uris_destroy(&tal->uris);
+ free(tal);
+ lfile_close(lfile);
+ return err;
+ }
+
+ lfile_close(lfile);
+ *result = tal;
+ return 0;
+}
+
+void tal_destroy(struct tal *tal)
+{
+ if (tal == NULL)
+ return;
+
+ uris_destroy(&tal->uris);
+ free(tal->spki);
+ free(tal);
+}
--- /dev/null
+#ifndef TAL_H_
+#define TAL_H_
+
+struct tal;
+
+int tal_load(const char *, struct tal **);
+void tal_destroy(struct tal *);
+
+#endif /* TAL_H_ */
--- /dev/null
+AM_CFLAGS = -pedantic -Wall -std=gnu11 -I../src ${CHECK_CFLAGS}
+MY_LDADD = ${CHECK_LIBS}
+
+check_PROGRAMS = line_file.test tal.test
+TESTS = ${check_PROGRAMS}
+
+line_file_test_SOURCES = line_file_test.c ../src/line_file.c ../src/line_file.h
+line_file_test_LDADD = ${MY_LDADD}
+
+tal_test_SOURCES = tal_test.c ../src/line_file.c ../src/line_file.h
+tal_test_CFLAGS = ${AM_CFLAGS} ${GLIB_CFLAGS}
+tal_test_LDADD = ${MY_LDADD} ${GLIB_LIBS}
--- /dev/null
+This is a normal line.
+This is also a normal line, but the following one is empty.
+
+This one ends with \r\n.\r
+This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line. This is a very long line.
+This line does not end with a newline.
\ No newline at end of file
--- /dev/null
+#include "line_file.h"
+
+#include <check.h>
+#include <errno.h>
+#include <stdlib.h>
+
+START_TEST(file_line_normal)
+{
+ struct line_file *lfile;
+ char *string, *long_string;
+ char *SENTENCE;
+ size_t SENTENCE_LEN;
+ unsigned int i;
+
+ ck_assert_int_eq(lfile_open("line_file/core.txt", &lfile), 0);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert_str_eq(string, "This is a normal line.");
+ free(string);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert_str_eq(string, "This is also a normal line, but the following one is empty.");
+ free(string);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert_str_eq(string, "");
+ free(string);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert_str_eq(string, "This one ends with \\r\\n.");
+ free(string);
+
+ SENTENCE = "This is a very long line. ";
+ SENTENCE_LEN = strlen(SENTENCE);
+ long_string = malloc(316 * SENTENCE_LEN + 1);
+ ck_assert(long_string);
+ for (i = 0; i < 316; i++)
+ strcpy(long_string + i * SENTENCE_LEN, SENTENCE);
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert_str_eq(string, long_string);
+ free(long_string);
+ free(string);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert_str_eq(string, "This line does not end with a newline.");
+ free(string);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert(string == NULL);
+
+ lfile_close(lfile);
+}
+END_TEST
+
+START_TEST(file_line_empty)
+{
+ struct line_file *lfile;
+ char *string;
+
+ ck_assert_int_eq(lfile_open("line_file/empty.txt", &lfile), 0);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert(string == NULL);
+
+ lfile_close(lfile);
+}
+END_TEST
+
+START_TEST(file_line_null_chara)
+{
+ struct line_file *lfile;
+ char *string;
+
+ ck_assert_int_eq(lfile_open("line_file/error.txt", &lfile), 0);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), 0);
+ ck_assert_str_eq(string, "This is a normal line.");
+ free(string);
+
+ ck_assert_int_eq(lfile_read(lfile, &string), -EINVAL);
+
+ lfile_close(lfile);
+}
+END_TEST
+
+Suite *lfile_read_suite(void)
+{
+ Suite *suite;
+ TCase *core, *limits, *errors;
+
+ core = tcase_create("Core");
+ tcase_add_test(core, file_line_normal);
+
+ limits = tcase_create("Limits");
+ tcase_add_test(limits, file_line_empty);
+
+ errors = tcase_create("Errors");
+ tcase_add_test(errors, file_line_null_chara);
+
+ suite = suite_create("lfile_read()");
+ suite_add_tcase(suite, core);
+ suite_add_tcase(suite, limits);
+ suite_add_tcase(suite, errors);
+ return suite;
+}
+
+int main(void)
+{
+ Suite *suite;
+ SRunner *runner;
+ int tests_failed;
+
+ suite = lfile_read_suite();
+
+ runner = srunner_create(suite);
+ srunner_run_all(runner, CK_NORMAL);
+ tests_failed = srunner_ntests_failed(runner);
+ srunner_free(runner);
+
+ return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
--- /dev/null
+rsync://repository.lacnic.net/rpki/lacnic/rta-lacnic-rpki.cer
+http://potato
+rsync://potato
+
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqZEzhYK0+PtDOPfub/KR
+c3MeWx3neXx4/wbnJWGbNAtbYqXg3uU5J4HFzPgk/VIppgSKAhlO0H60DRP48by9
+gr5/yDHu2KXhOmnMg46sYsUIpfgtBS9+VtrqWziJfb+pkGtuOWeTnj6zBmBNZKK+
+5AlMCW1WPhrylIcB+XSZx8tk9GS/3SMQ+YfMVwwAyYjsex14Uzto4GjONALE5oh1
+M3+glRQduD6vzSwOD+WahMbc9vCOTED+2McLHRKgNaQf0YJ9a1jG9oJIvDkKXEqd
+fqDRktwyoD74cV57bW3tBAexB7GglITbInyQAsmdngtfg2LUMrcROHHP86QPZINj
+DQIDAQAB
--- /dev/null
+#include "tal.c"
+
+#include <check.h>
+#include <errno.h>
+#include <stdlib.h>
+
+START_TEST(tal_load_normal)
+{
+ struct tal *tal;
+ struct uri *uri;
+ unsigned int i;
+ /* Got this by feeding the subjectPublicKeyInfo to `base64 -d`. */
+ unsigned char decoded[] = {
+ 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,
+ 0xA9, 0x91, 0x33, 0x85, 0x82, 0xB4, 0xF8, 0xFB, 0x43, 0x38, 0xF7,
+ 0xEE, 0x6F, 0xF2, 0x91, 0x73, 0x73, 0x1E, 0x5B, 0x1D, 0xE7, 0x79,
+ 0x7C, 0x78, 0xFF, 0x06, 0xE7, 0x25, 0x61, 0x9B, 0x34, 0x0B, 0x5B,
+ 0x62, 0xA5, 0xE0, 0xDE, 0xE5, 0x39, 0x27, 0x81, 0xC5, 0xCC, 0xF8,
+ 0x24, 0xFD, 0x52, 0x29, 0xA6, 0x04, 0x8A, 0x02, 0x19, 0x4E, 0xD0,
+ 0x7E, 0xB4, 0x0D, 0x13, 0xF8, 0xF1, 0xBC, 0xBD, 0x82, 0xBE, 0x7F,
+ 0xC8, 0x31, 0xEE, 0xD8, 0xA5, 0xE1, 0x3A, 0x69, 0xCC, 0x83, 0x8E,
+ 0xAC, 0x62, 0xC5, 0x08, 0xA5, 0xF8, 0x2D, 0x05, 0x2F, 0x7E, 0x56,
+ 0xDA, 0xEA, 0x5B, 0x38, 0x89, 0x7D, 0xBF, 0xA9, 0x90, 0x6B, 0x6E,
+ 0x39, 0x67, 0x93, 0x9E, 0x3E, 0xB3, 0x06, 0x60, 0x4D, 0x64, 0xA2,
+ 0xBE, 0xE4, 0x09, 0x4C, 0x09, 0x6D, 0x56, 0x3E, 0x1A, 0xF2, 0x94,
+ 0x87, 0x01, 0xF9, 0x74, 0x99, 0xC7, 0xCB, 0x64, 0xF4, 0x64, 0xBF,
+ 0xDD, 0x23, 0x10, 0xF9, 0x87, 0xCC, 0x57, 0x0C, 0x00, 0xC9, 0x88,
+ 0xEC, 0x7B, 0x1D, 0x78, 0x53, 0x3B, 0x68, 0xE0, 0x68, 0xCE, 0x34,
+ 0x02, 0xC4, 0xE6, 0x88, 0x75, 0x33, 0x7F, 0xA0, 0x95, 0x14, 0x1D,
+ 0xB8, 0x3E, 0xAF, 0xCD, 0x2C, 0x0E, 0x0F, 0xE5, 0x9A, 0x84, 0xC6,
+ 0xDC, 0xF6, 0xF0, 0x8E, 0x4C, 0x40, 0xFE, 0xD8, 0xC7, 0x0B, 0x1D,
+ 0x12, 0xA0, 0x35, 0xA4, 0x1F, 0xD1, 0x82, 0x7D, 0x6B, 0x58, 0xC6,
+ 0xF6, 0x82, 0x48, 0xBC, 0x39, 0x0A, 0x5C, 0x4A, 0x9D, 0x7E, 0xA0,
+ 0xD1, 0x92, 0xDC, 0x32, 0xA0, 0x3E, 0xF8, 0x71, 0x5E, 0x7B, 0x6D,
+ 0x6D, 0xED, 0x04, 0x07, 0xB1, 0x07, 0xB1, 0xA0, 0x94, 0x84, 0xDB,
+ 0x22, 0x7C, 0x90, 0x02, 0xC9, 0x9D, 0x9E, 0x0B, 0x5F, 0x83, 0x62,
+ 0xD4, 0x32, 0xB7, 0x11, 0x38, 0x71, 0xCF, 0xF3, 0xA4, 0x0F, 0x64,
+ 0x83, 0x63, 0x0D, 0x02, 0x03, 0x01, 0x00, 0x01
+ };
+
+ ck_assert_int_eq(tal_load("tal/lacnic.tal", &tal), 0);
+
+ uri = SLIST_FIRST(&tal->uris);
+ ck_assert_str_eq(uri->string, "rsync://repository.lacnic.net/rpki/lacnic/rta-lacnic-rpki.cer");
+ uri = SLIST_NEXT(uri, next);
+ ck_assert_str_eq(uri->string, "http://potato");
+ uri = SLIST_NEXT(uri, next);
+ ck_assert_str_eq(uri->string, "rsync://potato");
+ uri = SLIST_NEXT(uri, next);
+ ck_assert(uri == NULL);
+
+ ck_assert_uint_eq(ARRAY_SIZE(decoded), tal->spki_size);
+ for (i = 0; i < ARRAY_SIZE(decoded); i++)
+ ck_assert_uint_eq(tal->spki[i], decoded[i]);
+
+ tal_destroy(tal);
+}
+END_TEST
+
+Suite *tal_load_suite(void)
+{
+ Suite *suite;
+ TCase *core;
+
+ core = tcase_create("Core");
+ tcase_add_test(core, tal_load_normal);
+
+ suite = suite_create("lfile_read()");
+ suite_add_tcase(suite, core);
+ return suite;
+}
+
+int main(void)
+{
+ Suite *suite;
+ SRunner *runner;
+ int tests_failed;
+
+ suite = tal_load_suite();
+
+ runner = srunner_create(suite);
+ srunner_run_all(runner, CK_NORMAL);
+ tests_failed = srunner_ntests_failed(runner);
+ srunner_free(runner);
+
+ return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}