From: pcarana Date: Tue, 9 Apr 2019 20:20:55 +0000 (-0500) Subject: Relocate some code, and add decoded strings length X-Git-Tag: v0.0.2~49^2~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=dfa4030aeef2c67fb42816cf6b5e61f4d66370b6;p=thirdparty%2FFORT-validator.git Relocate some code, and add decoded strings length --- diff --git a/src/Makefile.am b/src/Makefile.am index 2d6b627f..45c6127a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,6 +24,7 @@ rtr_server_SOURCES += rtr/primitive_reader.c rtr/primitive_reader.h rtr_server_SOURCES += rtr/primitive_writer.c rtr/primitive_writer.h rtr_server_SOURCES += rtr/rtr.c rtr/rtr.h +rtr_server_SOURCES += slurm/json_parser.c slurm/json_parser.h rtr_server_SOURCES += slurm/slurm_parser.c slurm/slurm_parser.h rtr_server_SOURCES += crypto/base64.c crypto/base64.h diff --git a/src/crypto/base64.c b/src/crypto/base64.c index 15535594..7e893fc3 100644 --- a/src/crypto/base64.c +++ b/src/crypto/base64.c @@ -3,11 +3,15 @@ #include #include #include +#include +#include /* - * TODO This is a copy of fort-validator/src/crypto/base64.c with a small - * modification at 'base64_decode' (new parameter 'has_nl' to indicate if the - * encoded string has newlines in it) + * TODO This is a copy of fort-validator/src/crypto/base64.c with a few + * modifications: + * - At 'base64_decode': new parameter 'has_nl' to indicate if the encoded + * string has newlines in it. + * - New function 'base64url_decode'. */ /** @@ -120,3 +124,81 @@ end: return error ? error_ul2i(error) : 0; } + +int +base64url_decode(char const *str_encoded, unsigned char **result, + size_t *result_len) +{ + BIO *encoded; /* base64 encoded. */ + char *str_copy; + size_t encoded_len, alloc_size, dec_len; + int error, pad, i; + + /* + * Apparently there isn't a base64url decoder, and there isn't + * much difference between base64 codification and base64url, just as + * stated in RFC 4648 section 5: "This encoding is technically + * identical to the previous one, except for the 62:nd and 63:rd + * alphabet character, as indicated in Table 2". + * + * The existing base64 can be used if the 62:nd and 63:rd base64url + * alphabet chars are replaced with the corresponding base64 chars, and + * also if we add the optional padding that the member should have. + */ + encoded_len = strlen(str_encoded); + pad = (encoded_len % 4) > 0 ? 4 - (encoded_len % 4) : 0; + + str_copy = malloc(encoded_len + pad + 1); + if (str_copy == NULL) + return -ENOMEM; + /* Set all with pad char, then replace with the original string */ + memset(str_copy, '=', encoded_len + pad); + memcpy(str_copy, str_encoded, encoded_len); + str_copy[encoded_len + pad] = '\0'; + + for (i = 0; i < encoded_len; i++) { + if (str_copy[i] == '-') + str_copy[i] = '+'; + else if (str_copy[i] == '_') + str_copy[i] = '/'; + } + + /* Now decode as regular base64 */ + encoded = BIO_new_mem_buf(str_copy, -1); + if (encoded == NULL) { + warnx("BIO_new() returned NULL"); + error = -EINVAL; + goto free_copy; + } + + alloc_size = EVP_DECODE_LENGTH(strlen(str_copy)); + *result = malloc(alloc_size + 1); + if (*result == NULL) { + error = -ENOMEM; + goto free_enc; + } + memset(*result, 0, alloc_size); + (*result)[alloc_size] = '\0'; + + error = base64_decode(encoded, result, false, alloc_size, &dec_len); + if (error) + goto free_all; + + if (dec_len == 0) { + warnx("'%s' couldn't be decoded", str_encoded); + error = -EINVAL; + goto free_all; + } + *result_len = dec_len; + + free(str_copy); + BIO_free(encoded); + return 0; +free_all: + free(*result); +free_enc: + BIO_free(encoded); +free_copy: + free(str_copy); + return error; +} diff --git a/src/crypto/base64.h b/src/crypto/base64.h index 5aebce22..fb8210d7 100644 --- a/src/crypto/base64.h +++ b/src/crypto/base64.h @@ -6,5 +6,6 @@ #include int base64_decode(BIO *, unsigned char **, bool, size_t, size_t *); +int base64url_decode(char const *, unsigned char **, size_t *); #endif /* SRC_BASE64_H_ */ diff --git a/src/slurm/json_parser.c b/src/slurm/json_parser.c new file mode 100644 index 00000000..40241c4b --- /dev/null +++ b/src/slurm/json_parser.c @@ -0,0 +1,79 @@ +#include "json_parser.h" + +#include +#include + +int +json_get_string(json_t *parent, char const *name, char const **result) +{ + json_t *child; + + child = json_object_get(parent, name); + if (child == NULL) { + *result = NULL; + return 0; + } + + if (!json_is_string(child)) { + warnx("The '%s' element is not a JSON string.", name); + return -EINVAL; + } + + *result = json_string_value(child); + return 0; +} + +int +json_get_int(json_t *parent, char const *name, json_int_t *result) +{ + json_t *child; + + child = json_object_get(parent, name); + if (child == NULL) { + *result = 0; + return 0; + } + + if (!json_is_integer(child)) { + warnx("The '%s' element is not a JSON integer.", name); + return -EINVAL; + } + + *result = json_integer_value(child); + return 0; +} + +json_t * +json_get_array(json_t *parent, char const *name) +{ + json_t *child; + + child = json_object_get(parent, name); + if (child == NULL) { + return NULL; + } + + if (!json_is_array(child)) { + warnx("The '%s' element is not a JSON array.", name); + return NULL; + } + + return child; +} + +json_t * +json_get_object(json_t *parent, char const *name) +{ + json_t *child; + + child = json_object_get(parent, name); + if (child == NULL) + return NULL; + + if (!json_is_object(child)) { + warnx("The '%s' element is not a JSON object.", name); + return NULL; + } + + return child; +} diff --git a/src/slurm/json_parser.h b/src/slurm/json_parser.h new file mode 100644 index 00000000..2b33d623 --- /dev/null +++ b/src/slurm/json_parser.h @@ -0,0 +1,11 @@ +#ifndef SRC_SLURM_JSON_PARSER_H_ +#define SRC_SLURM_JSON_PARSER_H_ + +#include + +int json_get_string(json_t *, char const *, char const **); +int json_get_int(json_t *, char const *, json_int_t *); +json_t *json_get_array(json_t *, char const *); +json_t *json_get_object(json_t *, char const *); + +#endif /* SRC_SLURM_JSON_PARSER_H_ */ diff --git a/src/slurm/slurm_parser.c b/src/slurm/slurm_parser.c index 71b7ee10..bfebf362 100644 --- a/src/slurm/slurm_parser.c +++ b/src/slurm/slurm_parser.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -11,6 +10,7 @@ #include "../address.h" #include "../configuration.h" #include "../crypto/base64.h" +#include "json_parser.h" /* JSON members */ #define SLURM_VERSION "slurmVersion" @@ -52,15 +52,13 @@ struct slurm_bgpsec { u_int8_t data_flag; u_int32_t asn; unsigned char *ski; + size_t ski_len; unsigned char *routerPublicKey; + size_t routerPublicKey_len; char const *comment; }; static int handle_json(json_t *); -static int json_get_string(json_t *, char const *, char const **); -static int json_get_int(json_t *, char const *, json_int_t *); -static json_t *json_get_array(json_t *, char const *); -static json_t *json_get_object(json_t *, char const *); int slurm_load(void) @@ -270,19 +268,14 @@ set_max_prefix_length(json_t *object, bool is_assertion, u_int8_t addr_fam, } static int -decode_base64url(char const *str_encoded, unsigned char **result) +validate_encoded(const char *encoded) { - BIO *encoded; /* base64 encoded. */ - char *str_copy; - size_t encoded_len, alloc_size, dec_len; - int error, pad, i; - /* * RFC 8416, sections 3.3.2 (SKI member), and 3.4.2 (SKI and * routerPublicKey members): "{..} whose value is the Base64 encoding * without trailing '=' (Section 5 of [RFC4648])" */ - if (strrchr(str_encoded, '=') != NULL) { + if (strrchr(encoded, '=') != NULL) { warnx("The base64 encoded value has trailing '='"); return -EINVAL; } @@ -301,73 +294,7 @@ decode_base64url(char const *str_encoded, unsigned char **result) * "{..} whose value is the Base64url encoding without trailing '=' * (Section 5 of [RFC4648])" */ - - /* - * Apparently there isn't a base64url decoder, and there isn't - * much difference between base64 codification and base64url, just as - * stated in RFC 4648 section 5: "This encoding is technically - * identical to the previous one, except for the 62:nd and 63:rd - * alphabet character, as indicated in Table 2". - * - * The existing base64 can be used if the 62:nd and 63:rd base64url - * alphabet chars are replaced with the corresponding base64 chars, and - * also if we add the optional padding that the member should have. - */ - encoded_len = strlen(str_encoded); - pad = (encoded_len % 4) > 0 ? 4 - (encoded_len % 4) : 0; - - str_copy = malloc(encoded_len + pad + 1); - if (str_copy == NULL) - return -ENOMEM; - /* Set all with pad char, then replace with the original string */ - memset(str_copy, '=', encoded_len + pad); - memcpy(str_copy, str_encoded, encoded_len); - str_copy[encoded_len + pad] = '\0'; - - for (i = 0; i < encoded_len; i++) { - if (str_copy[i] == '-') - str_copy[i] = '+'; - else if (str_copy[i] == '_') - str_copy[i] = '/'; - } - - /* Now decode as regular base64 */ - encoded = BIO_new_mem_buf(str_copy, -1); - if (encoded == NULL) { - warnx("BIO_new() returned NULL"); - error = -EINVAL; - goto free_copy; - } - - alloc_size = EVP_DECODE_LENGTH(strlen(str_copy)); - *result = malloc(alloc_size + 1); - if (*result == NULL) { - error = -ENOMEM; - goto free_enc; - } - memset(*result, 0, alloc_size); - (*result)[alloc_size] = '\0'; - - error = base64_decode(encoded, result, false, alloc_size, &dec_len); - if (error) - goto free_all; - - if (dec_len == 0) { - warnx("'%s' couldn't be decoded", str_encoded); - error = -EINVAL; - goto free_all; - } - - free(str_copy); - BIO_free(encoded); return 0; -free_all: - free(*result); -free_enc: - BIO_free(encoded); -free_copy: - free(str_copy); - return error; } static int @@ -389,7 +316,11 @@ set_ski(json_t *object, bool is_assertion, struct slurm_bgpsec *result) return 0; } - error = decode_base64url(str_encoded, &result->ski); + error = validate_encoded(str_encoded); + if (error) + return error; + + error = base64url_decode(str_encoded, &result->ski, &result->ski_len); if (error) return error; @@ -421,8 +352,13 @@ set_router_pub_key(json_t *object, bool is_assertion, return -EINVAL; } + error = validate_encoded(str_encoded); + if (error) + return error; + /* TODO The public key may contain NULL chars as part of the string */ - error = decode_base64url(str_encoded, &result->routerPublicKey); + error = base64url_decode(str_encoded, &result->routerPublicKey, + &result->routerPublicKey_len); if (error) return error; @@ -433,6 +369,15 @@ set_router_pub_key(json_t *object, bool is_assertion, * the subjectPublicKeyInfo, including the ASN.1 tag and length values * of the subjectPublicKeyInfo SEQUENCE. */ + /* + * TODO When the merge is done, reuse the functions at fort-validator + * + * #include + * #include "asn1/decode.h" + * struct SubjectPublicKeyInfo *router_pki; + * error = asn1_decode(result->routerPublicKey, result->routerPublicKey_len, + * &asn_DEF_SubjectPublicKeyInfo, (void **) &router_pki); + */ /* TODO persist, free later */ free(result->routerPublicKey); @@ -649,78 +594,3 @@ handle_json(json_t *root) return 0; } - -static int -json_get_string(json_t *parent, char const *name, char const **result) -{ - json_t *child; - - child = json_object_get(parent, name); - if (child == NULL) { - *result = NULL; - return 0; - } - - if (!json_is_string(child)) { - warnx("The '%s' element is not a JSON string.", name); - return -EINVAL; - } - - *result = json_string_value(child); - return 0; -} - -static int -json_get_int(json_t *parent, char const *name, json_int_t *result) -{ - json_t *child; - - child = json_object_get(parent, name); - if (child == NULL) { - *result = 0; - return 0; - } - - if (!json_is_integer(child)) { - warnx("The '%s' element is not a JSON integer.", name); - return -EINVAL; - } - - *result = json_integer_value(child); - return 0; -} - -static json_t * -json_get_array(json_t *parent, char const *name) -{ - json_t *child; - - child = json_object_get(parent, name); - if (child == NULL) { - return NULL; - } - - if (!json_is_array(child)) { - warnx("The '%s' element is not a JSON array.", name); - return NULL; - } - - return child; -} - -static json_t * -json_get_object(json_t *parent, char const *name) -{ - json_t *child; - - child = json_object_get(parent, name); - if (child == NULL) - return NULL; - - if (!json_is_object(child)) { - warnx("The '%s' element is not a JSON object.", name); - return NULL; - } - - return child; -}