Strict version.
#include <assert.h>
#include <errno.h>
+#include "alloc.h"
+#include "common.h"
#include "asn1/asn1c/asn_codecs_prim.h"
#include "asn1/asn1c/asn_internal.h"
#include "json_util.h"
return ASN_STRTOX_ERROR_INVAL;
}
+char *
+asn_INTEGER2str(INTEGER_t const *bi)
+{
+ return bi ? hex2str(bi->buf, bi->size) : NULL;
+}
+
+int
+asn_str2INTEGER(char const *str, INTEGER_t *bigint)
+{
+ size_t slen;
+ int error;
+
+ if (str == NULL) {
+ bigint->buf = NULL;
+ bigint->size = 0;
+ return 0;
+ }
+
+ slen = strlen(str);
+ if (slen > 40)
+ return EOVERFLOW;
+ if (slen & 1)
+ return EINVAL;
+
+ bigint->size = slen / 2;
+ bigint->buf = pmalloc(bigint->size);
+
+ error = str2hex(str, bigint->buf);
+ if (error) {
+ free(bigint->buf);
+ bigint->buf = NULL;
+ bigint->size = 0;
+ return error;
+ }
+
+ return 0;
+}
+
int
INTEGER_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
const void *bptr) {
}
}
+
+int
+INTEGER_cmp(INTEGER_t const *a, INTEGER_t const *b)
+{
+ return INTEGER_compare(&asn_DEF_INTEGER, a, b);
+}
+
+/* Transfers ownership */
+void
+INTEGER_move(INTEGER_t *to, INTEGER_t *from)
+{
+ *to = *from;
+ memset(from, 0, sizeof(*from));
+}
+
+void
+INTEGER_cleanup(INTEGER_t *st)
+{
+ INTEGER_free(&asn_DEF_INTEGER, st, ASFM_FREE_UNDERLYING);
+}
enum asn_strtox_result_e asn_strtoumax_lim(const char *str, const char **end,
uintmax_t *l);
+char *asn_INTEGER2str(INTEGER_t const *);
+int asn_str2INTEGER(char const *, INTEGER_t *);
+
/*
* Convert the integer value into the corresponding enumeration map entry.
*/
const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(
const asn_INTEGER_specifics_t *specs, long value);
+int INTEGER_cmp(INTEGER_t const *, INTEGER_t const *);
+void INTEGER_move(INTEGER_t *, INTEGER_t *);
+void INTEGER_cleanup(INTEGER_t *);
+
#endif /* _INTEGER_H_ */
error = json_get_ts(json, "success", &node->success_ts);
if (error != 0 && error != ENOENT)
goto fail;
+ error = json_get_bigint(json, "mftNum", &node->mft.num);
+ if (error < 0)
+ goto fail;
error = json_get_ts(json, "mftUpdate", &node->mft.update);
if (error < 0)
goto fail;
goto fail;
if (node->success_ts && json_add_ts(json, "success", node->success_ts))
goto fail;
+ if (node->mft.num.size && json_add_bigint(json, "mftNum", &node->mft.num))
+ goto fail;
if (node->mft.update && json_add_ts(json, "mftUpdate", node->mft.update))
goto fail;
if (node->rrdp)
}
/*
- * Steals ownership of @rpp->files and @rpp->nfiles, but they're not going to be
- * modified nor deleted until the cache cleanup.
+ * Steals ownership of @rpp->files, @rpp->nfiles and @rpp->mft.num, but they're
+ * not going to be modified nor deleted until the cache cleanup.
*/
void
cache_commit_rpp(char const *rpkiNotify, char const *caRepository,
commit->caRepository = pstrdup(caRepository);
commit->files = rpp->files;
commit->nfiles = rpp->nfiles;
- commit->mft = rpp->mft;
+ INTEGER_move(&commit->mft.num, &rpp->mft.num);
+ commit->mft.update = rpp->mft.update;
mutex_lock(&commits_lock);
STAILQ_INSERT_TAIL(&commits, commit, lh);
commit->files[0].url = pstrdup(map->url);
commit->files[0].path = pstrdup(map->path);
commit->nfiles = 1;
+ memset(&commit->mft, 0, sizeof(commit->mft));
mutex_lock(&commits_lock);
STAILQ_INSERT_TAIL(&commits, commit, lh);
char const *dst;
array_index i;
- fb->mft = commit->mft;
+ INTEGER_move(&fb->mft.num, &commit->mft.num);
+ fb->mft.update = commit->mft.update;
for (i = 0; i < commit->nfiles; i++) {
src = commit->files + i;
free(commit->files[i].path);
}
free(commit->files);
+ mftm_cleanup(&commit->mft);
free(commit);
}
}
*tt = time;
return 0;
}
+
+char *hex2str(uint8_t const *hex, size_t hexlen)
+{
+ static const char * const H2C = "0123456789ABCDEF";
+ char *str;
+ size_t i;
+
+ if (hex == NULL || hexlen == 0)
+ return NULL;
+
+ str = pmalloc(2 * hexlen + 1);
+ for (i = 0; i < hexlen; i++) {
+ str[2 * i ] = H2C[hex[i] >> 4];
+ str[2 * i + 1] = H2C[hex[i] & 0xF];
+ }
+ str[2 * i] = 0;
+
+ return str;
+}
+
+static int
+c2h(char c)
+{
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+/* @hex needs to be already allocated. */
+int str2hex(char const *str, uint8_t *hex)
+{
+ size_t h;
+ int digit;
+
+ if (str[0] == 0)
+ return EINVAL; /* Not a number */
+
+ for (h = 0; str[2 * h] != 0; h++) {
+ digit = c2h(str[2 * h]);
+ if (digit < 0)
+ return EINVAL; /* Not hexadecimal */
+ hex[h] = digit << 4;
+
+ if (str[2 * h + 1] == 0)
+ return EINVAL; /* Need an even length */
+ digit = c2h(str[2 * h + 1]);
+ if (digit < 0)
+ return EINVAL; /* Not hexadecimal */
+ hex[h] |= digit;
+ }
+
+ return 0;
+}
#include <pthread.h>
#include <stdbool.h>
+#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
int time2str(time_t, char *);
int str2time(char const *, time_t *);
+char *hex2str(uint8_t const *, size_t);
+int str2hex(char const *, uint8_t *);
+
#endif /* SRC_RTR_COMMON_H_ */
return 0;
}
+int
+json_get_bigint(json_t *parent, char const *name, INTEGER_t *result)
+{
+ char const *str;
+ int error;
+
+ error = json_get_str(parent, name, &str);
+ if (error)
+ return error;
+
+ error = asn_str2INTEGER(str, result);
+ if (error)
+ pr_op_err("Tag '%s' (%s) cannot be parsed into an integer: %s",
+ name, str, strerror(error));
+
+ return error;
+}
+
int
json_get_ts(json_t *parent, char const *name, time_t *result)
{
return 0;
}
+int
+json_add_bigint(json_t *parent, char const *name, INTEGER_t *value)
+{
+ char *str;
+ int error;
+
+ str = asn_INTEGER2str(value);
+ if (!str)
+ return pr_op_err("Cannot convert %s to string.", name);
+
+ error = json_add_str(parent, name, str);
+
+ free(str);
+ return error;
+}
+
int
json_add_str(json_t *parent, char const *name, char const *value)
{
#include <sys/types.h>
#include <unistd.h>
+#include "asn1/asn1c/INTEGER.h"
+
/*
* Contract of get functions:
*
int json_get_int(json_t *, char const *, int *);
int json_get_u32(json_t *, char const *, uint32_t *);
int json_get_ulong(json_t *, char const *, unsigned long *);
+int json_get_bigint(json_t *, char const *, INTEGER_t *);
int json_get_ts(json_t *, char const *, time_t *);
int json_get_str(json_t *, char const *, char const **);
int json_get_array(json_t *, char const *, json_t **);
int json_add_int(json_t *, char const *, int);
int json_add_ulong(json_t *, char const *, unsigned long);
+int json_add_bigint(json_t *, char const *, INTEGER_t *);
int json_add_str(json_t *, char const *, char const *);
int json_add_ts(json_t *, char const *, time_t);
if (!prev)
return 0;
+ if (prev->num.size && INTEGER_cmp(&prev->num, ¤t->num) > 0)
+ return pr_val_err("The fallback manifest has a higher manifestNumber than the downloaded one.");
if (prev->update && difftime(prev->update, current->update) > 0)
return pr_val_err("The fallback manifest is newer than the downloaded one.");
*/
if (mft->manifestNumber.size > 20)
return pr_val_err("Manifest number is larger than 20 octets");
+ INTEGER_move(&meta->num, &mft->manifestNumber);
/* rfc6486#section-4.4.3 */
error = validate_dates(&mft->thisUpdate, &mft->nextUpdate, meta);
return NULL;
}
-static char
-hash_c2b(char chara)
-{
- if ('a' <= chara && chara <= 'f')
- return chara - 'a' + 10;
- if ('A' <= chara && chara <= 'F')
- return chara - 'A' + 10;
- if ('0' <= chara && chara <= '9')
- return chara - '0';
- return -1;
-}
-
static int
-json2dh(json_t *json, struct rrdp_hash **result)
+json2dh(json_t *json, struct rrdp_hash **dh)
{
- char const *src;
- size_t srclen;
- struct rrdp_hash *dst;
- char digit;
- size_t i;
+ char const *str;
+ struct rrdp_hash *hash;
- src = json_string_value(json);
- if (src == NULL)
+ str = json_string_value(json);
+ if (str == NULL)
return pr_op_err("Hash is not a string.");
- srclen = strlen(src);
- if (srclen != 2 * RRDP_HASH_LEN)
- return pr_op_err("Hash is not %d characters long.", 2 * RRDP_HASH_LEN);
+ if (strlen(str) != 2 * RRDP_HASH_LEN)
+ return pr_op_err("Hash is not %d characters long.",
+ 2 * RRDP_HASH_LEN);
- dst = pmalloc(sizeof(struct rrdp_hash));
- for (i = 0; i < RRDP_HASH_LEN; i++) {
- digit = hash_c2b(src[2 * i]);
- if (digit == -1)
- goto bad_char;
- dst->bytes[i] = digit << 4;
- digit = hash_c2b(src[2 * i + 1]);
- if (digit == -1)
- goto bad_char;
- dst->bytes[i] |= digit;
+ hash = pmalloc(sizeof(struct rrdp_hash));
+ if (str2hex(str, hash->bytes) != 0) {
+ free(hash);
+ return pr_op_err("Malformed hash: %s", str);
}
- *result = dst;
+ *dh = hash;
return 0;
-
-bad_char:
- free(dst);
- return pr_op_err("Invalid characters in hash: %c%c", src[2 * i], src[2 * i] + 1);
}
static void
X509_CRL_free(rpp->crl.obj);
rpp->crl.obj = NULL;
}
+
+ mftm_cleanup(&rpp->mft);
}
#include <openssl/x509.h>
#include <time.h>
+#include "asn1/asn1c/INTEGER.h"
#include "types/map.h"
struct mft_meta {
+ INTEGER_t num; /* Manifest's manifestNumber */
time_t update; /* Manifest's thisUpdate */
};
struct mft_meta mft;
};
+#define mftm_cleanup(m) INTEGER_cleanup(&(m)->num);
void rpp_cleanup(struct rpp *);
#endif /* SRC_RPP_H_ */
address_test_SOURCES = types/address_test.c
address_test_LDADD = ${CHECK_LIBS}
+check_PROGRAMS += asn1_int.test
+asn1_int_test_SOURCES = asn1/asn1c/INTEGER_t_test.c
+asn1_int_test_LDADD = ${CHECK_LIBS}
+
check_PROGRAMS += base64.test
base64_test_SOURCES = base64_test.c
base64_test_LDADD = ${CHECK_LIBS}
--- /dev/null
+#include <check.h>
+
+#include "alloc.c"
+#include "common.c"
+#include "asn1/asn1c/asn_codecs_prim.c"
+#include "asn1/asn1c/INTEGER.c"
+#include "mock.c"
+
+__MOCK_ABORT(asn__format_to_callback, ssize_t, 0,
+ int (*cb)(const void *, size_t, void *key), void *key, const char *fmt, ...)
+MOCK_ABORT_INT(asn_generic_no_constraint,
+ const asn_TYPE_descriptor_t *td, const void *ptr,
+ asn_app_constraint_failed_f *cb, void *key)
+static asn_dec_rval_t dummy;
+__MOCK_ABORT(ber_check_tags, asn_dec_rval_t, dummy,
+ const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td,
+ asn_struct_ctx_t *opt_ctx, const void *ptr, size_t size, int tag_mode,
+ int last_tag_form, ber_tlv_len_t *last_length, int *opt_tlv_form)
+__MOCK_ABORT(der_write_tags, ssize_t, 0,
+ const asn_TYPE_descriptor_t *sd, size_t struct_length, int tag_mode,
+ int last_tag_form, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb,
+ void *app_key)
+__MOCK_ABORT(json_int_new, json_t *, NULL, json_int_t value)
+
+START_TEST(test_serde)
+{
+ INTEGER_t bi;
+ char *str;
+
+ ck_assert_int_eq(0, asn_str2INTEGER(NULL, &bi));
+ ck_assert_ptr_eq(NULL, bi.buf);
+ ck_assert_int_eq(0, bi.size);
+ ck_assert_ptr_eq(NULL, asn_INTEGER2str(NULL));
+
+ ck_assert_int_eq(EINVAL, asn_str2INTEGER("", &bi));
+ ck_assert_int_eq(EINVAL, asn_str2INTEGER("a", &bi));
+ ck_assert_int_eq(EINVAL, asn_str2INTEGER("abc", &bi));
+
+ ck_assert_int_eq(0, asn_str2INTEGER("ab", &bi));
+ ck_assert_int_eq(1, bi.size);
+ ck_assert_int_eq(0xAB, bi.buf[0]);
+ str = asn_INTEGER2str(&bi);
+ ck_assert_str_eq("AB", str);
+ INTEGER_cleanup(&bi);
+ free(str);
+
+ ck_assert_int_eq(0, asn_str2INTEGER("abc5", &bi));
+ ck_assert_int_eq(2, bi.size);
+ ck_assert_int_eq(0xAB, bi.buf[0]);
+ ck_assert_int_eq(0xC5, bi.buf[1]);
+ str = asn_INTEGER2str(&bi);
+ ck_assert_str_eq("ABC5", str);
+ INTEGER_cleanup(&bi);
+ free(str);
+
+ ck_assert_int_eq(EINVAL, asn_str2INTEGER("abc59", &bi));
+
+ ck_assert_int_eq(0, asn_str2INTEGER("abcdef0123456789ABCDEFabcdef012345678901", &bi));
+ ck_assert_int_eq(20, bi.size);
+ ck_assert_int_eq(0xAB, bi.buf[0]);
+ ck_assert_int_eq(0xCD, bi.buf[1]);
+ ck_assert_int_eq(0x89, bi.buf[18]);
+ ck_assert_int_eq(0x01, bi.buf[19]);
+ str = asn_INTEGER2str(&bi);
+ ck_assert_str_eq("ABCDEF0123456789ABCDEFABCDEF012345678901", str);
+ INTEGER_cleanup(&bi);
+ free(str);
+
+ ck_assert_int_eq(EOVERFLOW, asn_str2INTEGER("abcdef0123456789ABCDEFabcdef0123456789012", &bi));
+ ck_assert_int_eq(EOVERFLOW, asn_str2INTEGER("abcdef0123456789ABCDEFabcdef0123456789013", &bi));
+ ck_assert_int_eq(EINVAL, asn_str2INTEGER("z", &bi));
+ ck_assert_int_eq(EINVAL, asn_str2INTEGER("abmd", &bi));
+}
+END_TEST
+
+static Suite *create_suite(void)
+{
+ Suite *suite;
+ TCase *serde;
+
+ serde = tcase_create("serde");
+ tcase_add_test(serde, test_serde);
+
+ suite = suite_create("INTEGER_t");
+ suite_add_tcase(suite, serde);
+
+ return suite;
+}
+
+int main(void)
+{
+ Suite *suite;
+ SRunner *runner;
+ int tests_failed;
+
+ suite = create_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;
+}
MOCK_VOID(__delete_node_cb, struct cache_node const *node)
MOCK_VOID(task_wakeup_busy, void)
+__MOCK_ABORT(asn_INTEGER2str, char *, NULL, INTEGER_t const *bi)
+MOCK_VOID(INTEGER_move, INTEGER_t *to, INTEGER_t *from)
+MOCK_VOID(INTEGER_cleanup, INTEGER_t *i)
/* Helpers */