#include <libknot/descriptor.h>
#include <ucw/mempool.h>
#include <sys/socket.h>
+#include <gnutls/x509.h>
#include "lib/resolve.h"
#include "lib/layer.h"
#include "lib/rplan.h"
return kr_ok();
}
+void certs_free(gnutls_x509_crt_t *array, size_t count)
+{
+ if (!array)
+ return;
+ for (int i = 0; i < count; i++)
+ gnutls_free(array[i]);
+ gnutls_free(array);
+}
+
+void whitelist_free(struct issuer_whitelist *iss)
+{
+ if (!iss || !iss->names)
+ return;
+ // WARNING: assume count is initialized?
+ for (int i = 0; i < iss->count; i++)
+ free(iss->names[i]);
+ free(iss->names);
+ free(iss);
+}
+
+
+int read_certs(const char *filepath, char **out)
+{
+ size_t size;
+ char *certs = NULL;
+ int fd = open(filepath, O_RDONLY);
+ if (fd == -1)
+ goto fail;
+
+ if ((size = lseek(fd, 0, SEEK_END)) == -1 || lseek(fd, 0, SEEK_SET) == -1)
+ goto fail;
+
+ certs = calloc(1, size);
+ if (!certs)
+ goto fail;
+
+ int ret = read(fd, certs, size);
+ if (ret != size)
+ goto fail;
+
+ close(fd);
+ *out = certs;
+ return kr_ok();
+
+fail:
+ kr_log_warning(TLS, "failed to read %s (%s)\n", filepath, strerror(errno));
+ if (certs)
+ free(certs);
+
+ if (fd != -1)
+ close(fd);
+
+ return EXIT_FAILURE;
+}
+
+gnutls_x509_crt_t *parse_certificates(char *raw_certs, size_t size, int *count)
+{
+ *count = 0;
+
+ gnutls_datum_t cert_datum = { (unsigned char *)raw_certs, size };
+ gnutls_x509_crt_t *cert_list = NULL;
+ unsigned int cert_count = 0;
+ int ret = gnutls_x509_crt_list_import2(&cert_list, &cert_count,
+ &cert_datum, GNUTLS_X509_FMT_PEM, 0);
+
+ if (ret < 0) {
+ kr_log_warning(TLS, "failed to import certificates (%s)\n",
+ gnutls_strerror(ret));
+ certs_free(cert_list, cert_count);
+ return NULL;
+ }
+
+ *count = cert_count;
+ return cert_list;
+}
+
+int get_auth_name_array(struct issuer_whitelist *iss, const char *filepath)
+{
+ int rv = EXIT_FAILURE;
+ char *raw_certs = NULL;
+ if (read_certs(filepath, &raw_certs) != kr_ok())
+ goto cleanup;
+
+ int count = 0;
+ gnutls_x509_crt_t *certs = parse_certificates(raw_certs, strlen(raw_certs), &count);
+ if (count <= 0)
+ goto cleanup;
+
+ char iss_org_name[256] = { 0 };
+ size_t iss_org_name_size = sizeof(iss_org_name);
+ iss->count = 0;
+ iss->names = calloc(count, sizeof(char *));
+ if (!iss->names)
+ goto cleanup;
+
+ for (int i = 0; i < count; i++) {
+ iss_org_name_size = sizeof(iss_org_name);
+ int ret = gnutls_x509_crt_get_issuer_dn_by_oid(
+ certs[i], GNUTLS_OID_X520_ORGANIZATION_NAME,
+ 0, 0, iss_org_name, &iss_org_name_size);
+
+ if (ret == GNUTLS_E_SUCCESS) {
+ iss->names[iss->count] = strndup(iss_org_name, iss_org_name_size);
+ if (!iss->names[iss->count])
+ kr_error(ENOMEM);
+ // TODO: deal with ENOMEM
+ // ;
+
+ // TODO: Delete
+ kr_log_warning(TLS, "whitelisted %s\n", iss->names[iss->count]);
+ iss->count++;
+ }
+ }
+
+ iss->count = iss->count;
+ rv = kr_ok();
+
+cleanup:
+ if (raw_certs)
+ free(raw_certs);
+
+ certs_free(certs, count);
+ return rv;
+}
+
+int kr_init_whitelist(const char *whitelistpath)
+{
+ the_resolver->issuers = calloc(sizeof(struct issuer_whitelist), 1);
+ if (!the_resolver->issuers)
+ return ENOMEM;
+
+ int ret = get_auth_name_array(the_resolver->issuers, whitelistpath);
+ if (ret != kr_ok()) {
+ whitelist_free(the_resolver->issuers);
+ the_resolver->issuers = NULL;
+ }
+
+ return ret;
+}
+
int kr_resolver_init(module_array_t *modules, knot_mm_t *pool)
{
the_resolver = &the_resolver_value;
trie_free(the_resolver->trust_anchors);
kr_ta_clear(the_resolver->negative_anchors);
trie_free(the_resolver->negative_anchors);
+ whitelist_free(the_resolver->issuers);
the_resolver = NULL;
}