binary FEATURE accept base64 values with newlines
Fixes #1793
diff --git a/src/plugins_types/binary.c b/src/plugins_types/binary.c
index 114a17d..5317e01 100644
--- a/src/plugins_types/binary.c
+++ b/src/plugins_types/binary.c
@@ -211,6 +211,51 @@
return LY_SUCCESS;
}
+/**
+ * @brief Remove all newlines from a base64 string if present.
+ *
+ * @param[in,out] value Value, may be dynamic and modified.
+ * @param[in,out] value_len Length of @p value, is updated.
+ * @param[in,out] options Type options, are updated.
+ * @param[out] err Error information.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+binary_base64_newlines(char **value, size_t *value_len, uint32_t *options, struct ly_err_item **err)
+{
+ char *val;
+ size_t len;
+
+ if ((*value_len < 65) || ((*value)[64] != '\n')) {
+ /* no newlines */
+ return LY_SUCCESS;
+ }
+
+ if (!(*options & LYPLG_TYPE_STORE_DYNAMIC)) {
+ /* make the value dynamic so we can modify it */
+ *value = strndup(*value, *value_len);
+ LY_CHECK_RET(!*value, LY_EMEM);
+ *options |= LYPLG_TYPE_STORE_DYNAMIC;
+ }
+
+ val = *value;
+ len = *value_len;
+ while (len > 64) {
+ if (val[64] != '\n') {
+ /* missing, error */
+ return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Newlines are expected every 64 Base64 characters.");
+ }
+
+ /* remove the newline */
+ memmove(val + 64, val + 65, len - 64);
+ --(*value_len);
+ val += 64;
+ len -= 65;
+ }
+
+ return LY_SUCCESS;
+}
+
LIBYANG_API_DEF LY_ERR
lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
@@ -252,8 +297,12 @@
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);
- /* validate */
if (format != LY_VALUE_CANON) {
+ /* accept newline every 64 characters (PEM data) */
+ ret = binary_base64_newlines((char **)&value, &value_len, &options, err);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* validate */
ret = binary_base64_validate(value, value_len, type_bin, err);
LY_CHECK_GOTO(ret, cleanup);
}
diff --git a/tests/utests/types/binary.c b/tests/utests/types/binary.c
index 2df1cc9..e96efab 100644
--- a/tests/utests/types/binary.c
+++ b/tests/utests/types/binary.c
@@ -125,6 +125,34 @@
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
+ /* newlines after every 64 chars */
+ val = "MIIEAzCCAuugAwIBAgIURc4sipHvJSlNrQIhRhZilBvV4RowDQYJKoZIhvcNAQEL\n"
+ "BQAwgZAxCzAJBgNVBAYTAkNaMRYwFAYDVQQIDA1Tb3V0aCBNb3JhdmlhMQ0wCwYD\n"
+ "VQQHDARCcm5vMRgwFgYDVQQKDA9DRVNORVQgei5zLnAuby4xDDAKBgNVBAsMA1RN\n"
+ "QzETMBEGA1UEAwwKZXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBs\n"
+ "ZS5vcmcwHhcNMjEwOTAzMTAyMTAxWhcNMzEwOTAxMTAyMTAxWjCBkDELMAkGA1UE\n"
+ "BhMCQ1oxFjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xGDAW\n"
+ "BgNVBAoMD0NFU05FVCB6LnMucC5vLjEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApl\n"
+ "eGFtcGxlIENBMR0wGwYJKoZIhvcNAQkBFg5jYUBleGFtcGxlLm9yZzCCASIwDQYJ\n"
+ "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN4Ld3JDDocyy9KXNJhEUPeZpQW3UdUN\n"
+ "Xloeh5n/bxasgThkBuQ7oF/nKyVUe517U1CJA993ZIc0jhIWThAnqXkz70DX5EZ7\n"
+ "ancPd01MidA6T8k1RYYJWr+vyIRYYBYzK7LSnU6wMWqPTgzZB+KMWwb065ooLEB5\n"
+ "XwqAeTIMPLRqM1Galewl4ZSuRJnrXxRjfF3AWNyC9dZw6wIg8cppvoLdBGQiFJQf\n"
+ "9SgiVy+HyedAytFEixqKAAIgQUJwhCgbEd6jGFbeaL8HT4MFp1VmaaUBQMkZj/Gn\n"
+ "KBwCk5BEMu76EN1pzHc4Dd6DabQNGCnsqOPe31yhQGmNFy9R6zNnWZMCAwEAAaNT\n"
+ "MFEwHQYDVR0OBBYEFM7w/pO8vk5oowvWPoCKo0RW/JcnMB8GA1UdIwQYMBaAFM7w\n"
+ "/pO8vk5oowvWPoCKo0RW/JcnMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\n"
+ "BQADggEBAG/xfYuRKnCyiwYC/K7kAjHmCNnLCr1mx8P1ECsSJPme3OThDTNeGf8i\n"
+ "N2952tGmMFDa+DaAwPc6Gt3cWTb/NYMTLWlt2yj5rJAcLXxIU0SMafBf+F7E/R8A\n"
+ "b/HDDjs0pQaJ0EJhQJVkMdfj3Wq9l0dJT5iEBUrUQflDufiMdEJEIGKZh86MgzEL\n"
+ "bcn1QX8dlLc91M2OifWStqLzXPicG+jjuoPUceC0flMQDb2qx03sxvJKfYfS5ArA\n"
+ "CqvdWyXLoP7DI9THJrMI/vBHJKpl4Wtmsh2OLn9VHauFMzPSGke5GwjXCpbXGepj\n"
+ "9qWN8Gd/FWgSDH2OBvZ6aHdB1pPjN9k=";
+ assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
+ 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
+ assert_ptr_equal(value.realtype, lysc_type);
+ type->free(UTEST_LYCTX, &value);
+
/* empty value */
val = "";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),