DDS Security built-in Access Control plugin

This commit adds the build-in Access Control plugin that is part of the
DDS Security implementation for Cyclone.

The Access Control Plugin API defines the types and operations necessary
to support an access control mechanism for DDS Domain Participants.

Similar to other builtin plugins, the DDS Security access control plugin
is built as a shared library to allow dynamic library loading on runtime.
This enables DDS participants to use specific plugin implementations with
different configurations.

This commit includes some basic tests for the access control functions.
This initial version of the plugin does not support permissions expiry
(not-valid-after date in permissions configuration).

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

Process review comments for access control plugin

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

Part 2 of processing review changes for access control

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

Add test for topicname dcps, add comment for xml date parser

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

Fixed an bug in leap year count for year 2200, changed the rounding for sub-ns fraction and added an additional overflow test in DDS_Security_parse_xml_date

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>
This commit is contained in:
Dennis Potman 2019-11-21 12:01:34 +01:00 committed by eboasson
parent 68f789d77b
commit 3b4facbd45
101 changed files with 19154 additions and 52 deletions

View file

@ -13,10 +13,12 @@
#ifndef DSCMN_SECURITY_UTILS_H_
#define DSCMN_SECURITY_UTILS_H_
#include "dds/export.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "dds/export.h"
#include "dds/ddsrt/strtol.h"
#include "dds/ddsrt/time.h"
#include "dds/security/core/dds_security_types.h"
#include "dds/security/dds_security_api.h"
@ -339,6 +341,10 @@ ddssec_strchrs (
const char *chrs,
bool inc);
DDS_EXPORT dds_time_t
DDS_Security_parse_xml_date(
char *buf);
#define DDS_Security_ParticipantCryptoTokenSeq_alloc() \
DDS_Security_DataHolderSeq_alloc())

View file

@ -807,47 +807,34 @@ DDS_Security_Exception_set(
#if DDSI_INCLUDE_SSL
DDS_EXPORT void
DDS_Security_Exception_set_with_openssl_error(
DDS_Security_SecurityException *ex,
const char *context,
int code,
int minor_code,
const char *error_area
)
DDS_Security_SecurityException *ex,
const char *context,
int code,
int minor_code,
const char *error_area)
{
BIO *bio;
assert(context);
assert(error_area);
assert(ex);
DDSRT_UNUSED_ARG(context);
BIO *bio;
char *buf = NULL;
char *str;
size_t len; /*BIO_get_mem_data requires long int */
assert(context);
assert(error_area);
assert(ex);
DDSRT_UNUSED_ARG( context );
bio = BIO_new(BIO_s_mem());
if (bio) {
size_t exception_msg_len;
ERR_print_errors(bio);
len = (size_t)BIO_get_mem_data (bio, &buf);
exception_msg_len = len + strlen(error_area) + 1;
str = ddsrt_malloc( exception_msg_len );
ddsrt_strlcpy(str, error_area, exception_msg_len);
memcpy(str + strlen(error_area), buf, len );
str [ exception_msg_len -1 ] = '\0';
//snprintf( str, exception_msg_len, "%s%s", error_area, buf );
ex->message = str;
ex->code = code;
ex->minor_code = minor_code;
BIO_free(bio);
} else {
DDS_Security_Exception_set(ex, context, code, minor_code, "BIO_new failed");
}
if ((bio = BIO_new(BIO_s_mem()))) {
ERR_print_errors(bio);
char *buf = NULL;
size_t len = (size_t)BIO_get_mem_data(bio, &buf);
size_t exception_msg_len = len + strlen(error_area) + 1;
char *str = ddsrt_malloc(exception_msg_len);
ddsrt_strlcpy(str, error_area, exception_msg_len);
memcpy(str + strlen(error_area), buf, len);
str[exception_msg_len - 1] = '\0';
ex->message = str;
ex->code = code;
ex->minor_code = minor_code;
BIO_free(bio);
} else {
DDS_Security_Exception_set(ex, context, code, minor_code, "BIO_new failed");
}
}
#endif
@ -1104,6 +1091,203 @@ DDS_Security_normalize_file(
}
#undef __FILESEPCHAR
return norm;
}
/**
* Parses an XML date string and returns this as a dds_time_t value. As leap seconds are not permitted
* in the XML date format (as stated in the XML Schema specification), this parser function does not
* accept leap seconds in its input string. This complies with the dds_time_t representation on posix,
* which is a unix timestamp (that also ignores leap seconds).
*
* As a dds_time_t is expressed as nanoseconds, the fractional seconds part of the input string will
* be rounded in case the fractional part has more than 9 digits.
*/
dds_time_t
DDS_Security_parse_xml_date(
char *buf)
{
int32_t year = -1;
int32_t month = -1;
int32_t day = -1;
int32_t hour = -1;
int32_t minute = -1;
int32_t second = -1;
int32_t hour_offset = -1;
int32_t minute_offset = -1;
int64_t frac_ns = 0;
size_t cnt = 0;
size_t cnt_frac_sec = 0;
assert(buf != NULL);
/* Make an integrity check of the string before the conversion*/
while (buf[cnt] != '\0')
{
if (cnt == 4 || cnt == 7)
{
if (buf[cnt] != '-')
return DDS_TIME_INVALID;
}
else if (cnt == 10)
{
if (buf[cnt] != 'T')
return DDS_TIME_INVALID;
}
else if (cnt == 13 || cnt == 16)
{
if (buf[cnt] != ':')
return DDS_TIME_INVALID;
}
else if (cnt == 19)
{
if (buf[cnt] != 'Z' && buf[cnt] != '+' && buf[cnt] != '-' && buf[cnt] != '.')
return DDS_TIME_INVALID;
/* If a dot is found then a variable number of fractional seconds is present.
A second integrity loop to account for the variability is used */
if (buf[cnt] == '.' && !cnt_frac_sec)
{
cnt_frac_sec = 1;
while (buf[cnt + 1] != '\0' && buf[cnt + 1] >= '0' && buf[cnt + 1] <= '9')
{
cnt_frac_sec++;
cnt++;
}
}
}
else if (cnt == 19 + cnt_frac_sec)
{
if (buf[cnt] != 'Z' && buf[cnt] != '+' && buf[cnt] != '-')
return DDS_TIME_INVALID;
}
else if (cnt == 22 + cnt_frac_sec)
{
if (buf[cnt] != ':')
return DDS_TIME_INVALID;
}
else
{
if (buf[cnt] < '0' || buf[cnt] > '9')
return DDS_TIME_INVALID;
}
cnt++;
}
/* Do not allow more than 12 (13 including the dot) and less than 1 fractional second digits if they are used */
if (cnt_frac_sec && (cnt_frac_sec < 2 || cnt_frac_sec > 13))
return DDS_TIME_INVALID;
/* Valid string length value at this stage are 19, 20 and 25 plus the fractional seconds part */
if (cnt != 19 + cnt_frac_sec && cnt != 20 + cnt_frac_sec && cnt != 25 + cnt_frac_sec)
return DDS_TIME_INVALID;
year = ddsrt_todigit(buf[0]) * 1000 + ddsrt_todigit(buf[1]) * 100 + ddsrt_todigit(buf[2]) * 10 + ddsrt_todigit(buf[3]);
month = ddsrt_todigit(buf[5]) * 10 + ddsrt_todigit(buf[6]);
day = ddsrt_todigit(buf[8]) * 10 + ddsrt_todigit(buf[9]);
hour = ddsrt_todigit(buf[11]) * 10 + ddsrt_todigit(buf[12]);
minute = ddsrt_todigit(buf[14]) * 10 + ddsrt_todigit(buf[15]);
second = ddsrt_todigit(buf[17]) * 10 + ddsrt_todigit(buf[18]);
{
int64_t frac_ns_pow = DDS_NSECS_IN_SEC / 10;
size_t n = 0;
for (n = 0; cnt_frac_sec && n < cnt_frac_sec - 1; n++)
{
/* Maximum granularity is nanosecond so round to maximum 9 digits */
if (n == 9)
{
if (ddsrt_todigit(buf[20 + n]) >= 5)
frac_ns++;
break;
}
frac_ns += ddsrt_todigit(buf[20 + n]) * frac_ns_pow;
frac_ns_pow = frac_ns_pow / 10;
}
}
/* If the length is 20 the last character must be a Z representing UTC time zone */
if (cnt == 19 + cnt_frac_sec || (cnt == 20 + cnt_frac_sec && buf[19 + cnt_frac_sec] == 'Z'))
{
hour_offset = 0;
minute_offset = 0;
}
else if (cnt == 25 + cnt_frac_sec)
{
hour_offset = ddsrt_todigit(buf[20 + cnt_frac_sec]) * 10 + ddsrt_todigit(buf[21 + cnt_frac_sec]);
minute_offset = ddsrt_todigit(buf[23 + cnt_frac_sec]) * 10 + ddsrt_todigit(buf[24 + cnt_frac_sec]);
}
else
return DDS_TIME_INVALID;
/* Make a limit check to make sure that all the numbers are within absolute boundaries.
Note that leap seconds are not allowed in XML dates and therefore not supported. */
if (year < 1970 || year > 2262 || month < 1 || month > 12 || day < 1 || day > 31 ||
hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59 ||
((hour_offset < 0 || hour_offset > 11 || minute_offset < 0 || minute_offset > 59) && (hour_offset != 12 || minute_offset != 0)))
{
return DDS_TIME_INVALID;
}
/* Boundary check including consideration for month and leap years */
if (!(((month == 4 || month == 6 || month == 9 || month == 11) && (day >= 1 && day <= 30)) ||
((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && (day >= 1 && day <= 31)) ||
(month == 2 && ((year % 100 != 0 && year % 4 == 0) || (year % 400 == 0)) && (day >= 1 && day <= 29)) ||
(month == 2 && (day >= 1 && day <= 28))))
{
return DDS_TIME_INVALID;
}
/* Convert the year-month-day to total number of days */
int32_t total_leap_years = (year - 1970 + 1) / 4;
/* Leap year count decreased by the number of xx00 years before current year because these are not leap years,
except for 2000. The year 2400 is not in the valid year range so we don't take that into account. */
if (year > 2100)
total_leap_years -= year / 100 - 20;
if (year == 2200)
total_leap_years++;
int32_t total_reg_years = year - 1970 - total_leap_years;
int32_t total_num_days = total_leap_years * 366 + total_reg_years * 365;
int32_t month_cnt;
for (month_cnt = 1; month_cnt < month; month_cnt++)
{
if (month_cnt == 4 || month_cnt == 6 || month_cnt == 9 || month_cnt == 11)
total_num_days += 30;
else if (month_cnt == 2)
{
if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
total_num_days += 29;
else
total_num_days += 28;
}
else
total_num_days += 31;
}
total_num_days += day - 1;
/* Correct the offset sign if negative */
if (buf[19 + cnt_frac_sec] == '-')
{
hour_offset = -hour_offset;
minute_offset = -minute_offset;
}
/* Convert the total number of days to seconds */
int64_t ts_days = (int64_t)total_num_days * 24 * 60 * 60;
int64_t ts_hms = hour * 60 * 60 + minute * 60 + second;
if (ts_days + ts_hms > INT64_MAX / DDS_NSECS_IN_SEC)
return DDS_TIME_INVALID;
int64_t ts = DDS_SECS(ts_days + ts_hms);
/* Apply the hour and minute offset */
int64_t ts_offset = DDS_SECS((int64_t)hour_offset * 60 * 60 + minute_offset * 60);
/* Prevent the offset from making the timestamp negative or overflow it */
if ((ts_offset <= 0 || (ts_offset > 0 && ts_offset < ts)) && INT64_MAX - ts - frac_ns >= -ts_offset)
return ts - ts_offset + frac_ns;
return DDS_TIME_INVALID;
}

View file

@ -15,6 +15,7 @@ include (CUnit)
set(security_core_test_sources
"tc_fsm.c"
"dds_security_core.c"
"security_utils.c"
)
add_definitions(-DDDSI_INCLUDE_SECURITY)

View file

@ -0,0 +1,62 @@
/*
* Copyright(c) 2006 to 2019 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "CUnit/CUnit.h"
#include "CUnit/Test.h"
#include "dds/ddsrt/time.h"
#include "dds/security/core/dds_security_utils.h"
CU_Test(ddssec_security_utils, parse_xml_date)
{
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date(""), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("abc"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01D01:01:01Z"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2019-02-29T01:01:01Z"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2100-02-29T01:01:01Z"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1969-01-01T01:01:01Z"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2010-01-01T23:59:60Z"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1969-01-01T01:01:01+01"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1969-01-01T01:01:01+0100"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1969-01-01T01:01:01+0:00"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1970-01-01T00:00:00+01:00"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.0000000000001+01:00"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.0.1+01:00"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.+01:00"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1970-01-01T00:00:00Z"), 0);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2000-02-29T00:00:00Z"), DDS_SECS(951782400));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01Z"), DDS_SECS(1577840461));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01+00:30"), DDS_SECS(1577840461 - 30 * 60));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01+01:00"), DDS_SECS(1577840461 - 60 * 60));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01+12:00"), DDS_SECS(1577840461 - 12 * 60 * 60));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01-01:00"), DDS_SECS(1577840461 + 60 * 60));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-12-31T23:59:59Z"), DDS_SECS(1609459199));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-02-29T01:01:01Z"), DDS_SECS(1582938061));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2038-01-19T03:14:07Z"), DDS_SECS(INT32_MAX));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2038-01-19T03:14:08Z"), DDS_SECS(INT64_C(INT32_MAX + 1)));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2100-01-01T00:00:00Z"), DDS_SECS(4102444800));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2120-01-01T00:00:00Z"), DDS_SECS(4733510400));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2200-01-01T00:00:00Z"), DDS_SECS(7258118400));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2220-01-01T00:00:00Z"), DDS_SECS(7889184000));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2262-04-11T23:47:16.854775807Z"), INT64_MAX);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2262-04-11T23:47:16.854775808Z"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2262-04-11T23:47:16.854775807+00:01"), INT64_MAX - DDS_SECS(60));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2262-04-11T23:47:16.854775807-00:01"), DDS_TIME_INVALID);
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.000000001+01:00"), INT64_C(1577836861000000001));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.0000000004+01:00"), INT64_C(1577836861000000000));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.0000000005+01:00"), INT64_C(1577836861000000001));
CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.987654321+01:00"), INT64_C(1577836861987654321));
}