summaryrefslogtreecommitdiff
path: root/regress/lib
diff options
context:
space:
mode:
authorYASUOKA Masahiko <yasuoka@cvs.openbsd.org>2015-07-20 23:52:30 +0000
committerYASUOKA Masahiko <yasuoka@cvs.openbsd.org>2015-07-20 23:52:30 +0000
commit00320dad4cc1a77d9b0f33fc801d3928e0076dac (patch)
tree0905f9b1b01ceaa64a6f11f7e63a98aff976f802 /regress/lib
parent484a61a40f69196a63b292c3c497a1d536571ef7 (diff)
Add radius(3) library. This will be used by RADIUS server and client
programs to manipulate RADIUS packets. Mainly written by UMEZAWA Takeshi. fix and suggestion deraadt ok deraadt
Diffstat (limited to 'regress/lib')
-rw-r--r--regress/lib/libradius/Makefile22
-rw-r--r--regress/lib/libradius/incs.h28
-rw-r--r--regress/lib/libradius/main.c45
-rw-r--r--regress/lib/libradius/test00.c32
-rw-r--r--regress/lib/libradius/test01.c97
-rw-r--r--regress/lib/libradius/test02.c56
-rw-r--r--regress/lib/libradius/test03.c45
-rw-r--r--regress/lib/libradius/test04.c77
-rw-r--r--regress/lib/libradius/test05.c23
-rw-r--r--regress/lib/libradius/test06.c22
-rw-r--r--regress/lib/libradius/test10.c42
-rw-r--r--regress/lib/libradius/test11.c38
-rw-r--r--regress/lib/libradius/test20.c51
-rw-r--r--regress/lib/libradius/test21.c79
-rw-r--r--regress/lib/libradius/test22.c75
-rw-r--r--regress/lib/libradius/test23.c70
-rw-r--r--regress/lib/libradius/test24.c50
-rw-r--r--regress/lib/libradius/test25.c84
18 files changed, 936 insertions, 0 deletions
diff --git a/regress/lib/libradius/Makefile b/regress/lib/libradius/Makefile
new file mode 100644
index 00000000000..60dde7b1e11
--- /dev/null
+++ b/regress/lib/libradius/Makefile
@@ -0,0 +1,22 @@
+# $OpenBSD: Makefile,v 1.1 2015/07/20 23:52:29 yasuoka Exp $
+
+PROG= radius_test
+REGRESS_TARGETS= run-radius_test
+
+SRCS= main.c
+SRCS+= test00.c test01.c test02.c test03.c test04.c test05.c test06.c
+SRCS+= test10.c test11.c
+SRCS+= test20.c test21.c test22.c test23.c test24.c test25.c
+
+CFLAGS+= -std=gnu99 -Wall -g -O0
+LDFLAGS+= -g
+
+DPADD+= ${LIBRADIUS} ${LIBCRYPTO}
+LDADD+= -lradius -lcrypto
+
+NOMAN= #defined
+
+run-radius_test: radius_test
+ ./radius_test
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libradius/incs.h b/regress/lib/libradius/incs.h
new file mode 100644
index 00000000000..01a9b9e83bb
--- /dev/null
+++ b/regress/lib/libradius/incs.h
@@ -0,0 +1,28 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <radius.h>
+
+typedef void (*testfunc)(void);
+
+void check_failed(const char *expr, const char *file, int line);
+void add_test(testfunc fn, const char *name);
+
+#define CHECK(x) \
+ do { if (!(x)) check_failed(#x, __FILE__, __LINE__); } while(0)
+
+#define ADD_TEST(fn) \
+extern void fn(void); \
+__attribute__((__constructor__)) \
+void fn ## _add(void) \
+{ \
+ add_test(fn, #fn); \
+}
diff --git a/regress/lib/libradius/main.c b/regress/lib/libradius/main.c
new file mode 100644
index 00000000000..3a35ff63e62
--- /dev/null
+++ b/regress/lib/libradius/main.c
@@ -0,0 +1,45 @@
+#include "incs.h"
+
+#define TEST_MAX 100
+
+struct test_entry {
+ testfunc func;
+ const char *name;
+} entries[TEST_MAX];
+
+int ntests = 0;
+
+int test_entry_cmp(const void *a, const void *b)
+{
+ return strcmp(
+ ((struct test_entry *)a)->name,
+ ((struct test_entry *)b)->name);
+}
+
+int main(void)
+{
+ srandom(time(NULL));
+
+ qsort(entries, ntests, sizeof(struct test_entry), test_entry_cmp);
+
+ for (int i = 0; i < ntests; i++) {
+ fprintf(stderr, "running test %s\n", entries[i].name);
+ entries[i].func();
+ }
+
+ fprintf(stderr, "tests are successfully completed.\n");
+ return 0;
+}
+
+void check_failed(const char *expr, const char *file, int line)
+{
+ fprintf(stderr, "CHECK FAILED: %s at file %s line %d\n", expr, file, line);
+ exit(1);
+}
+
+void add_test(testfunc fn, const char *name)
+{
+ entries[ntests].func = fn;
+ entries[ntests].name = name;
+ ntests++;
+}
diff --git a/regress/lib/libradius/test00.c b/regress/lib/libradius/test00.c
new file mode 100644
index 00000000000..69133553da9
--- /dev/null
+++ b/regress/lib/libradius/test00.c
@@ -0,0 +1,32 @@
+#include "incs.h"
+
+/*
+ * basic header operation
+ */
+
+void test00(void)
+{
+ RADIUS_PACKET *packet;
+ uint8_t code;
+ uint8_t id;
+ const uint8_t *pdata;
+ uint8_t authenticator[16];
+
+ code = random();
+ id = random();
+ packet = radius_new_request_packet(code);
+ radius_set_id(packet, id);
+ pdata = (const uint8_t *)radius_get_data(packet);
+ CHECK(pdata[0] == code);
+ CHECK(radius_get_code(packet) == code);
+ CHECK(pdata[1] == id);
+ CHECK(radius_get_id(packet) == id);
+ CHECK(((pdata[2] << 8) | pdata[3]) == 20);
+ CHECK(radius_get_length(packet) == 20);
+
+ CHECK(radius_get_authenticator_retval(packet) == pdata + 4);
+ radius_get_authenticator(packet, authenticator);
+ CHECK(memcmp(authenticator, radius_get_authenticator_retval(packet), 16) == 0);
+}
+
+ADD_TEST(test00)
diff --git a/regress/lib/libradius/test01.c b/regress/lib/libradius/test01.c
new file mode 100644
index 00000000000..1365429dc96
--- /dev/null
+++ b/regress/lib/libradius/test01.c
@@ -0,0 +1,97 @@
+#include "incs.h"
+
+/*
+ * put/get/has attributes
+ */
+
+void test01(void)
+{
+ RADIUS_PACKET *packet;
+ uint8_t buf[256];
+ size_t len;
+ const void *ptr;
+
+ static const uint8_t data0[] = { 0xfe, 0xdc, 0xba, 0x98 };
+ static const uint8_t data1[] = { 0x76, 0x54, 0x32 };
+ static const uint8_t data2[] = { 0x0f, 0x1e, 0x2d, 0x3c };
+ static const uint8_t data3[] = { 0x4b, 0x5a, 0x69 };
+ static const uint8_t attrs[] = {
+ 10, 6, 0xfe, 0xdc, 0xba, 0x98,
+ 20, 5, 0x76, 0x54, 0x32,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 300/256, 300%256, 40, 6, 0x0f, 0x1e, 0x2d, 0x3c,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 11, 0, 0, 500/256, 500%256, 60, 5, 0x4b, 0x5a, 0x69,
+ 20, 6, 0x0f, 0x1e, 0x2d, 0x3c,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 11, 0, 0, 300/256, 300%256, 40, 5, 0x76, 0x54, 0x32,
+ };
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ radius_put_raw_attr(packet, 10, data0, sizeof(data0));
+ radius_put_raw_attr(packet, 20, data1, sizeof(data1));
+ radius_put_vs_raw_attr(packet, 300, 40, data2, sizeof(data2));
+ radius_put_vs_raw_attr(packet, 500, 60, data3, sizeof(data3));
+ radius_put_raw_attr(packet, 20, data2, sizeof(data2));
+ radius_put_vs_raw_attr(packet, 300, 40, data1, sizeof(data1));
+
+ CHECK(radius_get_length(packet) == sizeof(attrs) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs, sizeof(attrs)) == 0);
+
+ len = sizeof(buf);
+ CHECK(radius_get_raw_attr(packet, 10, buf, &len) == 0);
+ CHECK(len == sizeof(data0));
+ CHECK(memcmp(buf, data0, len) == 0);
+
+ len = sizeof(buf);
+ CHECK(radius_get_raw_attr(packet, 20, buf, &len) == 0);
+ CHECK(len == sizeof(data1));
+ CHECK(memcmp(buf, data1, len) == 0);
+
+ len = sizeof(buf);
+ CHECK(radius_get_vs_raw_attr(packet, 300, 40, buf, &len) == 0);
+ CHECK(len == sizeof(data2));
+ CHECK(memcmp(buf, data2, len) == 0);
+
+ len = sizeof(buf);
+ CHECK(radius_get_vs_raw_attr(packet, 500, 60, buf, &len) == 0);
+ CHECK(len == sizeof(data3));
+ CHECK(memcmp(buf, data3, len) == 0);
+
+ len = 2;
+ CHECK(radius_get_raw_attr(packet, 10, buf, &len) == 0);
+ CHECK(len == 2);
+ CHECK(memcmp(buf, data0, len) == 0);
+
+ len = 2;
+ CHECK(radius_get_vs_raw_attr(packet, 300, 40, buf, &len) == 0);
+ CHECK(len == 2);
+ CHECK(memcmp(buf, data2, len) == 0);
+
+ len = sizeof(buf);
+ CHECK(radius_get_raw_attr(packet, 90, buf, &len) != 0);
+ CHECK(radius_get_vs_raw_attr(packet, 300, 90, buf, &len) != 0);
+ CHECK(radius_get_vs_raw_attr(packet, 900, 40, buf, &len) != 0);
+
+ len = 0;
+ CHECK(radius_get_raw_attr_ptr(packet, 10, &ptr, &len) == 0);
+ CHECK(len == 4);
+ CHECK(ptr == radius_get_data(packet) + 20 + 0 + 2);
+
+ len = 0;
+ CHECK(radius_get_vs_raw_attr_ptr(packet, 500, 60, &ptr, &len) == 0);
+ CHECK(len == 3);
+ CHECK(ptr == radius_get_data(packet) + 20 + 23 + 8);
+
+ CHECK(radius_get_raw_attr_ptr(packet, 90, &ptr, &len) != 0);
+ CHECK(radius_get_vs_raw_attr_ptr(packet, 300, 90, &ptr, &len) != 0);
+ CHECK(radius_get_vs_raw_attr_ptr(packet, 900, 40, &ptr, &len) != 0);
+
+ CHECK(radius_has_attr(packet, 10));
+ CHECK(radius_has_attr(packet, 20));
+ CHECK(radius_has_vs_attr(packet, 300, 40));
+ CHECK(radius_has_vs_attr(packet, 500, 60));
+ CHECK(!radius_has_attr(packet, 90));
+ CHECK(!radius_has_vs_attr(packet, 300, 90));
+ CHECK(!radius_has_vs_attr(packet, 900, 40));
+}
+
+ADD_TEST(test01)
diff --git a/regress/lib/libradius/test02.c b/regress/lib/libradius/test02.c
new file mode 100644
index 00000000000..c09276d2c27
--- /dev/null
+++ b/regress/lib/libradius/test02.c
@@ -0,0 +1,56 @@
+#include "incs.h"
+
+/*
+ * set attributes
+ */
+
+void test02(void)
+{
+ RADIUS_PACKET *packet;
+
+ static const uint8_t data0[] = { 0xfe, 0xdc, 0xba, 0x98 };
+ static const uint8_t data1[] = { 0x76, 0x54, 0x32, 0x10 };
+ static const uint8_t data2[] = { 0x0f, 0x1e, 0x2d, 0x3c };
+ static const uint8_t data3[] = { 0x4b, 0x5a, 0x69, 0x78, 0xff };
+ static const uint8_t attrs_beforeset[] = {
+ 10, 6, 0xfe, 0xdc, 0xba, 0x98,
+ 10, 6, 0x76, 0x54, 0x32, 0x10,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 20, 30, 6, 0x76, 0x54, 0x32, 0x10,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 20, 30, 6, 0xfe, 0xdc, 0xba, 0x98,
+ };
+ static const uint8_t attrs_afterset[] = {
+ 10, 6, 0x0f, 0x1e, 0x2d, 0x3c,
+ 10, 6, 0x76, 0x54, 0x32, 0x10,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 20, 30, 6, 0x0f, 0x1e, 0x2d, 0x3c,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 20, 30, 6, 0xfe, 0xdc, 0xba, 0x98,
+ };
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ radius_put_raw_attr(packet, 10, data0, sizeof(data0));
+ radius_put_raw_attr(packet, 10, data1, sizeof(data1));
+ radius_put_vs_raw_attr(packet, 20, 30, data1, sizeof(data1));
+ radius_put_vs_raw_attr(packet, 20, 30, data0, sizeof(data0));
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_beforeset) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_beforeset, sizeof(attrs_beforeset)) == 0);
+
+ CHECK(radius_set_raw_attr(packet, 10, data2, sizeof(data2)) == 0);
+ CHECK(radius_set_vs_raw_attr(packet, 20, 30, data2, sizeof(data2)) == 0);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_afterset) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_afterset, sizeof(attrs_afterset)) == 0);
+
+ CHECK(radius_set_raw_attr(packet, 10, data3, sizeof(data2) - 1) != 0);
+ CHECK(radius_set_raw_attr(packet, 10, data3, sizeof(data2) + 1) != 0);
+ CHECK(radius_set_vs_raw_attr(packet, 20, 30, data3, sizeof(data2) - 1) != 0);
+ CHECK(radius_set_vs_raw_attr(packet, 20, 30, data3, sizeof(data2) + 1) != 0);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_afterset) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_afterset, sizeof(attrs_afterset)) == 0);
+
+ CHECK(radius_set_raw_attr(packet, 90, data3, sizeof(data3)) != 0);
+ CHECK(radius_set_vs_raw_attr(packet, 900, 90, data3, sizeof(data3)) != 0);
+}
+
+ADD_TEST(test02)
diff --git a/regress/lib/libradius/test03.c b/regress/lib/libradius/test03.c
new file mode 100644
index 00000000000..576d2ef825c
--- /dev/null
+++ b/regress/lib/libradius/test03.c
@@ -0,0 +1,45 @@
+#include "incs.h"
+
+/*
+ * del attributes
+ */
+
+void test03(void)
+{
+ RADIUS_PACKET *packet;
+
+ static const uint8_t data0[] = { 0xfe, 0xdc, 0xba, 0x98 };
+ static const uint8_t data1[] = { 0x76, 0x54, 0x32, 0x10 };
+ static const uint8_t data2[] = { 0x0f, 0x1e, 0x2d, 0x3c };
+ static const uint8_t data3[] = { 0x4b, 0x5a, 0x69, 0x67 };
+ static const uint8_t attrs_afterdel[] = {
+ 80, 6, 0x0f, 0x1e, 0x2d, 0x3c,
+ 80, 6, 0x0f, 0x1e, 0x2d, 0x3c,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 70, 60, 6, 0x0f, 0x1e, 0x2d, 0x3c,
+ };
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ radius_put_raw_attr(packet, 10, data0, sizeof(data0));
+ radius_put_raw_attr(packet, 80, data2, sizeof(data2));
+ radius_put_raw_attr(packet, 10, data1, sizeof(data1));
+ radius_put_raw_attr(packet, 80, data2, sizeof(data2));
+ radius_put_vs_raw_attr(packet, 20, 30, data1, sizeof(data1));
+ radius_put_vs_raw_attr(packet, 20, 30, data0, sizeof(data0));
+ radius_put_vs_raw_attr(packet, 70, 60, data2, sizeof(data2));
+ radius_put_vs_raw_attr(packet, 20, 30, data3, sizeof(data3));
+
+ CHECK(radius_del_attr_all(packet, 10) == 0);
+ CHECK(radius_del_vs_attr_all(packet, 20, 30) == 0);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_afterdel) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_afterdel, sizeof(attrs_afterdel)) == 0);
+
+ CHECK(radius_del_attr_all(packet, 90) == 0);
+ CHECK(radius_del_vs_attr_all(packet, 90, 90) == 0);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_afterdel) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_afterdel, sizeof(attrs_afterdel)) == 0);
+}
+
+ADD_TEST(test03)
diff --git a/regress/lib/libradius/test04.c b/regress/lib/libradius/test04.c
new file mode 100644
index 00000000000..d868a226404
--- /dev/null
+++ b/regress/lib/libradius/test04.c
@@ -0,0 +1,77 @@
+#include "incs.h"
+
+/*
+ * put/get cat attributes
+ */
+
+void test04(void)
+{
+ RADIUS_PACKET *packet;
+ uint8_t buf[1024];
+ size_t len;
+ uint8_t *p;
+
+#define ATTRLEN (256 + 256 + 103)
+ uint8_t data0[ATTRLEN];
+ uint8_t data1[ATTRLEN];
+ uint8_t data2[] = { 0x10, 0x20, 0x30, 0x40 };
+ uint8_t data3[] = { 0x10, 0x20, 0x30, 0x40, 0x10, 0x20, 0x30, 0x40 };
+ uint8_t attrs[2048];
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ for (int i = 0; i < ATTRLEN; i++)
+ data0[i] = random();
+ for (int i = 0; i < ATTRLEN; i++)
+ data1[i] = random();
+
+ p = attrs;
+ *p++ = 20; *p++ = 6;
+ memcpy(p, data2, 4); p += 4;
+
+ *p++ = 10; *p++ = 255;
+ memcpy(p, data0, 253); p += 253;
+ *p++ = 10; *p++ = 255;
+ memcpy(p, data0 + 253, 253); p += 253;
+ *p++ = 10; *p++ = ATTRLEN-253*2+2;
+ memcpy(p, data0 + 253*2, ATTRLEN-253*2); p += ATTRLEN-253*2;
+
+ *p++ = RADIUS_TYPE_VENDOR_SPECIFIC; *p++ = 255;
+ *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 20; *p++ = 30; *p++ = 249;
+ memcpy(p, data1, 247); p += 247;
+ *p++ = RADIUS_TYPE_VENDOR_SPECIFIC; *p++ = 255;
+ *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 20; *p++ = 30; *p++ = 249;
+ memcpy(p, data1 + 247, 247); p += 247;
+ *p++ = RADIUS_TYPE_VENDOR_SPECIFIC; *p++ = ATTRLEN-247*2+8;
+ *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 20; *p++ = 30; *p++ = ATTRLEN-247*2+2;
+ memcpy(p, data1 + 247*2, ATTRLEN-247*2); p += ATTRLEN-247*2;
+
+ *p++ = 20; *p++ = 6;
+ memcpy(p, data2, 4); p += 4;
+
+
+ radius_put_raw_attr(packet, 20, data2, sizeof(data2));
+ radius_put_raw_attr_cat(packet, 10, data0, ATTRLEN);
+ radius_put_vs_raw_attr_cat(packet, 20, 30, data1, ATTRLEN);
+ radius_put_raw_attr(packet, 20, data2, sizeof(data2));
+
+ CHECK(radius_get_length(packet) == 20 + (p-attrs));
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs, p-attrs) == 0);
+
+ len = sizeof(buf);
+ CHECK(radius_get_raw_attr_cat(packet, 10, buf, &len) == 0);
+ CHECK(len == ATTRLEN);
+ CHECK(memcmp(buf, data0, len) == 0);
+
+ len = sizeof(buf);
+ CHECK(radius_get_vs_raw_attr_cat(packet, 20, 30, buf, &len) == 0);
+ CHECK(len == ATTRLEN);
+ CHECK(memcmp(buf, data1, len) == 0);
+
+ len = sizeof(buf);
+ CHECK(radius_get_raw_attr_cat(packet, 20,buf, &len) == 0);
+ CHECK(len == sizeof(data3));
+ CHECK(memcmp(buf, data3, len) == 0);
+}
+
+ADD_TEST(test04)
diff --git a/regress/lib/libradius/test05.c b/regress/lib/libradius/test05.c
new file mode 100644
index 00000000000..b5e9173af6d
--- /dev/null
+++ b/regress/lib/libradius/test05.c
@@ -0,0 +1,23 @@
+#include "incs.h"
+
+/*
+ * request/response association
+ */
+
+void test05(void)
+{
+ RADIUS_PACKET *req0, *req1, *resp;
+
+ req0 = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+ req1 = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+ CHECK(radius_get_request_packet(req0) == NULL);
+ CHECK(radius_get_request_packet(req1) == NULL);
+
+ resp = radius_new_response_packet(RADIUS_CODE_ACCESS_ACCEPT, req0);
+ CHECK(radius_get_request_packet(resp) == req0);
+
+ radius_set_request_packet(resp, req1);
+ CHECK(radius_get_request_packet(resp) == req1);
+}
+
+ADD_TEST(test05)
diff --git a/regress/lib/libradius/test06.c b/regress/lib/libradius/test06.c
new file mode 100644
index 00000000000..e947e8c0ce6
--- /dev/null
+++ b/regress/lib/libradius/test06.c
@@ -0,0 +1,22 @@
+#include "incs.h"
+
+/*
+ *
+ */
+
+void test06(void)
+{
+ RADIUS_PACKET *pkt;
+ u_char data[] = {
+ RADIUS_CODE_ACCESS_ACCEPT, 0x01, 0, 20,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ };
+ pkt = radius_convert_packet(data, sizeof(data));
+ CHECK(pkt != NULL);
+ CHECK(!radius_has_attr(pkt, RADIUS_TYPE_MESSAGE_AUTHENTICATOR));
+ CHECK(!radius_put_uint32_attr(pkt, RADIUS_TYPE_MESSAGE_AUTHENTICATOR, 1));
+ //CHECK(memcmp(radius_get_data(pkt), data, sizeof(data)) == 0);
+ radius_delete_packet(pkt);
+}
+
+ADD_TEST(test06)
diff --git a/regress/lib/libradius/test10.c b/regress/lib/libradius/test10.c
new file mode 100644
index 00000000000..34727d93288
--- /dev/null
+++ b/regress/lib/libradius/test10.c
@@ -0,0 +1,42 @@
+#include "incs.h"
+
+#include <openssl/md5.h>
+
+/*
+ * response authenticator
+ */
+
+void test10(void)
+{
+ RADIUS_PACKET *request;
+ RADIUS_PACKET *response;
+ MD5_CTX ctx;
+
+ uint8_t responsedata[] = {
+ RADIUS_CODE_ACCESS_ACCEPT, 0x7f, 0, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* auth */
+ 10, 11, 'f', 'o', 'o', 'b', 'a', 'r', 'b', 'a', 'z',
+ };
+
+ request = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+ radius_set_id(request, 0x7f);
+ response = radius_new_response_packet(RADIUS_CODE_ACCESS_ACCEPT, request);
+ radius_put_string_attr(response, 10, "foobarbaz");
+ radius_set_response_authenticator(response, "sharedsecret");
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, responsedata, 4);
+ MD5_Update(&ctx, radius_get_authenticator_retval(request), 16);
+ MD5_Update(&ctx, responsedata + 20, sizeof(responsedata) - 20);
+ MD5_Update(&ctx, "sharedsecret", 12);
+ MD5_Final(responsedata + 4, &ctx);
+
+ CHECK(radius_get_length(response) == sizeof(responsedata));
+ CHECK(memcmp(radius_get_data(response), responsedata, sizeof(responsedata)) == 0);
+ CHECK(radius_check_response_authenticator(response, "sharedsecret") == 0);
+
+ radius_set_raw_attr(response, 10, "zapzapzap", 9);
+ CHECK(radius_check_response_authenticator(response, "sharedsecret") != 0);
+}
+
+ADD_TEST(test10)
diff --git a/regress/lib/libradius/test11.c b/regress/lib/libradius/test11.c
new file mode 100644
index 00000000000..0317a696363
--- /dev/null
+++ b/regress/lib/libradius/test11.c
@@ -0,0 +1,38 @@
+#include "incs.h"
+
+#include <openssl/md5.h>
+
+/*
+ * accounting request authenticator
+ */
+
+void test11(void)
+{
+ RADIUS_PACKET *packet;
+ MD5_CTX ctx;
+
+ uint8_t packetdata[] = {
+ RADIUS_CODE_ACCOUNTING_REQUEST, 0x7f, 0, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* auth */
+ 10, 11, 'f', 'o', 'o', 'b', 'a', 'r', 'b', 'a', 'z',
+ };
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST);
+ radius_set_id(packet, 0x7f);
+ radius_put_string_attr(packet, 10, "foobarbaz");
+ radius_set_accounting_request_authenticator(packet, "sharedsecret");
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, packetdata, sizeof(packetdata));
+ MD5_Update(&ctx, "sharedsecret", 12);
+ MD5_Final(packetdata + 4, &ctx);
+
+ CHECK(radius_get_length(packet) == sizeof(packetdata));
+ CHECK(memcmp(radius_get_data(packet), packetdata, sizeof(packetdata)) == 0);
+ CHECK(radius_check_accounting_request_authenticator(packet, "sharedsecret") == 0);
+
+ radius_set_raw_attr(packet, 10, "zapzapzap", 9);
+ CHECK(radius_check_accounting_request_authenticator(packet, "sharedsecret") != 0);
+}
+
+ADD_TEST(test11)
diff --git a/regress/lib/libradius/test20.c b/regress/lib/libradius/test20.c
new file mode 100644
index 00000000000..592a9d1e1a3
--- /dev/null
+++ b/regress/lib/libradius/test20.c
@@ -0,0 +1,51 @@
+#include "incs.h"
+
+/*
+ * string attributes
+ */
+
+void test20(void)
+{
+ RADIUS_PACKET *packet;
+ char buf[256];
+
+ static const uint8_t attrs[] = {
+ 10, 12, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
+ RADIUS_TYPE_VENDOR_SPECIFIC, 17, 0, 0, 0, 20, 30, 11, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
+ 40, 7, 'z', 'x', 'c', 'v', 0,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 50, 60, 6, 'b', 'n', 0, 'm',
+ };
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ radius_put_string_attr(packet, 10, "qwertyuiop");
+ radius_put_vs_string_attr(packet, 20, 30, "asdfghjkl");
+ radius_put_raw_attr(packet, 40, "zxcv\0", 5);
+ radius_put_vs_raw_attr(packet, 50, 60, "bn\0m", 4);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs, sizeof(attrs)) == 0);
+
+ CHECK(radius_get_string_attr(packet, 10, buf, sizeof(buf)) == 0);
+ CHECK(strcmp(buf, "qwertyuiop") == 0);
+
+ CHECK(radius_get_vs_string_attr(packet, 20, 30, buf, sizeof(buf)) == 0);
+ CHECK(strcmp(buf, "asdfghjkl") == 0);
+
+ CHECK(radius_get_string_attr(packet, 40, buf, sizeof(buf)) != 0);
+ CHECK(radius_get_vs_string_attr(packet, 50, 60, buf, sizeof(buf)) != 0);
+
+ CHECK(radius_get_string_attr(packet, 10, buf, 4) == 0);
+ CHECK(strcmp(buf, "qwe") == 0);
+
+ CHECK(radius_get_vs_string_attr(packet, 20, 30, buf, 5) == 0);
+ CHECK(strcmp(buf, "asdf") == 0);
+
+ CHECK(radius_get_string_attr(packet, 10, buf, 0) == 0);
+ CHECK(buf[0] != 0);
+
+ CHECK(radius_get_vs_string_attr(packet, 20, 30, buf, 0) == 0);
+ CHECK(buf[0] != 0);
+}
+
+ADD_TEST(test20)
diff --git a/regress/lib/libradius/test21.c b/regress/lib/libradius/test21.c
new file mode 100644
index 00000000000..10b7e2f5fc9
--- /dev/null
+++ b/regress/lib/libradius/test21.c
@@ -0,0 +1,79 @@
+#include "incs.h"
+
+/*
+ * integer (uint16_t, uint32_t, uint64_t) attributes
+ */
+
+void test21(void)
+{
+ RADIUS_PACKET *packet;
+ uint16_t v16;
+ uint32_t v32;
+ uint64_t v64;
+
+ static const uint8_t attrs_beforeset[] = {
+ 1, 3, 0,
+ 10, 4, 0x12, 0x34,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 10, 0, 0, 0, 20, 30, 4, 0x43, 0x21,
+ 40, 6, 0x13, 0x57, 0x9b, 0xdf,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 50, 60, 6, 0x24, 0x68, 0xac, 0xe0,
+ 70, 10, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 16, 0, 0, 0, 80, 90, 10, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ };
+ static const uint8_t attrs_afterset[] = {
+ 1, 3, 0,
+ 10, 4, 0x43, 0x21,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 10, 0, 0, 0, 20, 30, 4, 0x12, 0x34,
+ 40, 6, 0x24, 0x68, 0xac, 0xe0,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 50, 60, 6, 0x13, 0x57, 0x9b, 0xdf,
+ 70, 10, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 16, 0, 0, 0, 80, 90, 10, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ };
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ radius_put_raw_attr(packet, 1, "", 1); /* padding for UNalignment */
+ radius_put_uint16_attr(packet, 10, 0x1234);
+ radius_put_vs_uint16_attr(packet, 20, 30, 0x4321);
+ radius_put_uint32_attr(packet, 40, 0x13579bdfU);
+ radius_put_vs_uint32_attr(packet, 50, 60, 0x2468ace0U);
+ radius_put_uint64_attr(packet, 70, 0x0123456789abcdefULL);
+ radius_put_vs_uint64_attr(packet, 80, 90, 0xfedcba9876543210ULL);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_beforeset) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_beforeset, sizeof(attrs_beforeset)) == 0);
+
+ CHECK(radius_get_uint16_attr(packet, 10, &v16) == 0);
+ CHECK(v16 == 0x1234);
+ CHECK(radius_get_vs_uint16_attr(packet, 20, 30, &v16) == 0);
+ CHECK(v16 == 0x4321);
+
+ CHECK(radius_get_uint32_attr(packet, 40, &v32) == 0);
+ CHECK(v32 == 0x13579bdfU);
+ CHECK(radius_get_vs_uint32_attr(packet, 50, 60, &v32) == 0);
+ CHECK(v32 == 0x2468ace0U);
+
+ CHECK(radius_get_uint64_attr(packet, 70, &v64) == 0);
+ CHECK(v64 == 0x0123456789abcdefULL);
+ CHECK(radius_get_vs_uint64_attr(packet, 80, 90, &v64) == 0);
+ CHECK(v64 == 0xfedcba9876543210ULL);
+
+ CHECK(radius_set_uint16_attr(packet, 10, 0x4321) == 0);
+ CHECK(radius_set_vs_uint16_attr(packet, 20, 30, 0x1234) == 0);
+ CHECK(radius_set_uint32_attr(packet, 40, 0x2468ace0U) == 0);
+ CHECK(radius_set_vs_uint32_attr(packet, 50, 60, 0x13579bdfU) == 0);
+ CHECK(radius_set_uint64_attr(packet, 70, 0xfedcba9876543210ULL) == 0);
+ CHECK(radius_set_vs_uint64_attr(packet, 80, 90, 0x0123456789abcdefULL) == 0);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_afterset) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_afterset, sizeof(attrs_afterset)) == 0);
+
+ CHECK(radius_get_uint16_attr(packet, 40, &v16) != 0);
+ CHECK(radius_get_vs_uint16_attr(packet, 50, 60, &v16) != 0);
+ CHECK(radius_get_uint32_attr(packet, 70, &v32) != 0);
+ CHECK(radius_get_vs_uint32_attr(packet, 80, 90, &v32) != 0);
+ CHECK(radius_get_uint64_attr(packet, 10, &v64) != 0);
+ CHECK(radius_get_vs_uint64_attr(packet, 20, 30, &v64) != 0);
+}
+
+ADD_TEST(test21)
diff --git a/regress/lib/libradius/test22.c b/regress/lib/libradius/test22.c
new file mode 100644
index 00000000000..75f78f78cc0
--- /dev/null
+++ b/regress/lib/libradius/test22.c
@@ -0,0 +1,75 @@
+#include "incs.h"
+
+#include <arpa/inet.h>
+
+/*
+ * inernet address (struct in_addr, struct in6_addr) attributes
+ */
+
+void test22(void)
+{
+ RADIUS_PACKET *packet;
+ struct in_addr in4a;
+ struct in6_addr in6a, in6b;
+
+ static const uint8_t attrs_beforeset[] = {
+ 1, 3, 0,
+ 10, 6, 192, 168, 0, 1,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 20, 30, 6, 10, 20, 30, 40,
+ 40, 18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 24, 0, 0, 0, 50, 60, 18, 0x3f, 0xff, 0x0e, 0xca, 0x86, 0x42, 0xfd, 0xb9, 0x75, 0x31, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
+ };
+ static const uint8_t attrs_afterset[] = {
+ 1, 3, 0,
+ 10, 6, 10, 20, 30, 40,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 12, 0, 0, 0, 20, 30, 6, 192, 168, 0, 1,
+ 40, 18, 0x3f, 0xff, 0x0e, 0xca, 0x86, 0x42, 0xfd, 0xb9, 0x75, 0x31, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
+ RADIUS_TYPE_VENDOR_SPECIFIC, 24, 0, 0, 0, 50, 60, 18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+ };
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ radius_put_raw_attr(packet, 1, "", 1); /* padding for UNalignment */
+ in4a.s_addr = inet_addr("192.168.0.1");
+ radius_put_ipv4_attr(packet, 10, in4a);
+ in4a.s_addr = inet_addr("10.20.30.40");
+ radius_put_vs_ipv4_attr(packet, 20, 30, in4a);
+ inet_pton(AF_INET6, "2001:0db8:dead:beef:1234:5678:9abc:def0", &in6a);
+ radius_put_ipv6_attr(packet, 40, &in6a);
+ inet_pton(AF_INET6, "3fff:0eca:8642:fdb9:7531:fedc:ba98:7654", &in6a);
+ radius_put_vs_ipv6_attr(packet, 50, 60, &in6a);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_beforeset) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_beforeset, sizeof(attrs_beforeset)) == 0);
+
+ CHECK(radius_get_ipv4_attr(packet, 10, &in4a) == 0);
+ CHECK(in4a.s_addr == inet_addr("192.168.0.1"));
+ CHECK(radius_get_vs_ipv4_attr(packet, 20, 30, &in4a) == 0);
+ CHECK(in4a.s_addr == inet_addr("10.20.30.40"));
+
+ CHECK(radius_get_ipv6_attr(packet, 40, &in6b) == 0);
+ inet_pton(AF_INET6, "2001:0db8:dead:beef:1234:5678:9abc:def0", &in6a);
+ CHECK(memcmp(&in6b, &in6a, sizeof(struct in6_addr)) == 0);
+ CHECK(radius_get_vs_ipv6_attr(packet, 50, 60, &in6b) == 0);
+ inet_pton(AF_INET6, "3fff:0eca:8642:fdb9:7531:fedc:ba98:7654", &in6a);
+ CHECK(memcmp(&in6b, &in6a, sizeof(struct in6_addr)) == 0);
+
+ in4a.s_addr = inet_addr("10.20.30.40");
+ radius_set_ipv4_attr(packet, 10, in4a);
+ in4a.s_addr = inet_addr("192.168.0.1");
+ radius_set_vs_ipv4_attr(packet, 20, 30, in4a);
+ inet_pton(AF_INET6, "3fff:0eca:8642:fdb9:7531:fedc:ba98:7654", &in6a);
+ radius_set_ipv6_attr(packet, 40, &in6a);
+ inet_pton(AF_INET6, "2001:0db8:dead:beef:1234:5678:9abc:def0", &in6a);
+ radius_set_vs_ipv6_attr(packet, 50, 60, &in6a);
+
+ CHECK(radius_get_length(packet) == sizeof(attrs_afterset) + 20);
+ CHECK(memcmp(radius_get_data(packet) + 20, attrs_afterset, sizeof(attrs_afterset)) == 0);
+
+ CHECK(radius_get_ipv4_attr(packet, 40, &in4a) != 0);
+ CHECK(radius_get_vs_ipv4_attr(packet, 50, 60, &in4a) != 0);
+ CHECK(radius_get_ipv6_attr(packet, 10, &in6b) != 0);
+ CHECK(radius_get_vs_ipv6_attr(packet, 20, 30, &in6b) != 0);
+}
+
+ADD_TEST(test22)
diff --git a/regress/lib/libradius/test23.c b/regress/lib/libradius/test23.c
new file mode 100644
index 00000000000..3085a581237
--- /dev/null
+++ b/regress/lib/libradius/test23.c
@@ -0,0 +1,70 @@
+#include "incs.h"
+
+#include <openssl/hmac.h>
+
+/*
+ * Message-Authenticator attribute
+ */
+
+void test23(void)
+{
+ RADIUS_PACKET *packet;
+ RADIUS_PACKET *response;
+ HMAC_CTX ctx;
+
+ uint8_t packetdata[] = {
+ RADIUS_CODE_ACCESS_REQUEST, 0x7f, 0, 48,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* auth */
+ 10, 10, 'h', 'o', 'g', 'e', 'f', 'u', 'g', 'a',
+ RADIUS_TYPE_MESSAGE_AUTHENTICATOR, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ uint8_t responsedata[] = {
+ RADIUS_CODE_ACCESS_ACCEPT, 0x7f, 0, 49,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* auth */
+ 10, 11, 'f', 'o', 'o', 'b', 'a', 'r', 'b', 'a', 'z',
+ RADIUS_TYPE_MESSAGE_AUTHENTICATOR, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+ radius_set_id(packet, 0x7f);
+ radius_put_string_attr(packet, 10, "hogefuga");
+ radius_put_message_authenticator(packet, "sharedsecret");
+
+ radius_get_authenticator(packet, packetdata + 4);
+ HMAC(EVP_md5(), "sharedsecret", 12, packetdata, sizeof(packetdata), packetdata + sizeof(packetdata) - 16, NULL);
+
+ CHECK(radius_get_length(packet) == sizeof(packetdata));
+ CHECK(memcmp(radius_get_data(packet), packetdata, sizeof(packetdata)) == 0);
+ CHECK(radius_check_message_authenticator(packet, "sharedsecret") == 0);
+
+ response = radius_new_response_packet(RADIUS_CODE_ACCESS_ACCEPT, packet);
+ radius_put_string_attr(response, 10, "foobarbaz");
+ radius_put_message_authenticator(response, "sharedsecret");
+
+ radius_get_authenticator(response, responsedata + 4);
+ HMAC_Init(&ctx, "sharedsecret", 12, EVP_md5());
+ HMAC_Update(&ctx, responsedata, 4);
+ HMAC_Update(&ctx, packetdata + 4, 16);
+ HMAC_Update(&ctx, responsedata + 20, sizeof(responsedata) - 20);
+ HMAC_Final(&ctx, responsedata + sizeof(responsedata) - 16, NULL);
+ HMAC_cleanup(&ctx);
+
+ CHECK(radius_get_length(response) == sizeof(responsedata));
+ CHECK(memcmp(radius_get_data(response), responsedata, sizeof(responsedata)) == 0);
+ CHECK(radius_check_message_authenticator(response, "sharedsecret") == 0);
+
+ radius_set_raw_attr(packet, 10, "hogefuge", 8);
+ CHECK(radius_check_message_authenticator(packet, "sharedsecret") != 0);
+ radius_set_raw_attr(response, 10, "zapzapzap", 9);
+ CHECK(radius_check_message_authenticator(response, "sharedsecret") != 0);
+
+ radius_set_raw_attr(packet, 10, "hogefuga", 8);
+ radius_set_id(packet, 0xff);
+ radius_set_message_authenticator(packet, "sharedsecret");
+ packetdata[1] = 0xff;
+ memset(packetdata + sizeof(packetdata) - 16, 0, 16);
+ HMAC(EVP_md5(), "sharedsecret", 12, packetdata, sizeof(packetdata), packetdata + sizeof(packetdata) - 16, NULL);
+ CHECK(memcmp(radius_get_data(packet), packetdata, sizeof(packetdata)) == 0);
+}
+
+ADD_TEST(test23)
diff --git a/regress/lib/libradius/test24.c b/regress/lib/libradius/test24.c
new file mode 100644
index 00000000000..c85391b5f9e
--- /dev/null
+++ b/regress/lib/libradius/test24.c
@@ -0,0 +1,50 @@
+#include "incs.h"
+
+#include <openssl/hmac.h>
+
+/*
+ * User-Password attribute
+ */
+
+void test24(void)
+{
+ uint8_t cipher[256],cipher1[256];
+ size_t clen;
+ char plain[256];
+ RADIUS_PACKET *packet;
+
+ uint8_t ra[16] = {
+ 0xf3, 0xa4, 0x7a, 0x1f, 0x6a, 0x6d, 0x76, 0x71, 0x0b, 0x94, 0x7a, 0xb9, 0x30, 0x41, 0xa0, 0x39,
+ };
+
+ uint8_t encryptedpass[16] = {
+ 0x33, 0x65, 0x75, 0x73, 0x77, 0x82, 0x89, 0xb5, 0x70, 0x88, 0x5e, 0x15, 0x08, 0x48, 0x25, 0xc5,
+ };
+
+ clen = sizeof(cipher);
+ CHECK(radius_encrypt_user_password_attr(cipher, &clen, "challenge", ra, "xyzzy5461") == 0);
+ CHECK(clen == 16);
+ CHECK(memcmp(cipher, encryptedpass, 16) == 0);
+
+ CHECK(radius_decrypt_user_password_attr(plain, sizeof(plain), cipher, clen, ra, "xyzzy5461") == 0);
+ CHECK(strcmp(plain, "challenge") == 0);
+
+ clen = 15;
+ CHECK(radius_encrypt_user_password_attr(cipher, &clen, "challenge", ra, "xyzzy5461") != 0);
+ CHECK(radius_decrypt_user_password_attr(plain, 16, cipher, 16, ra, "xyzzy5461") != 0);
+ CHECK(radius_decrypt_user_password_attr(plain, 256, cipher, 17, ra, "xyzzy5461") != 0);
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ CHECK(radius_put_user_password_attr(packet, "foobarbaz", "sharedsecret") == 0);
+ clen = sizeof(cipher1);
+ CHECK(radius_get_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher1, &clen) == 0);
+ CHECK(clen == 16);
+ radius_encrypt_user_password_attr(cipher, &clen, "foobarbaz", radius_get_authenticator_retval(packet), "sharedsecret");
+ CHECK(memcmp(cipher1, cipher, 16) == 0);
+
+ CHECK(radius_get_user_password_attr(packet, plain, sizeof(plain), "sharedsecret") == 0);
+ CHECK(strcmp(plain, "foobarbaz") == 0);
+}
+
+ADD_TEST(test24)
diff --git a/regress/lib/libradius/test25.c b/regress/lib/libradius/test25.c
new file mode 100644
index 00000000000..0e9a57324b6
--- /dev/null
+++ b/regress/lib/libradius/test25.c
@@ -0,0 +1,84 @@
+#include "incs.h"
+
+/*
+ * MS-MPPE-{Send,Recv}-Key attribute
+ */
+
+void test25(void)
+{
+ uint8_t ra[] = {
+ 0x67, 0x8a, 0xe6, 0xed, 0x69, 0x6e, 0x1b, 0xd1, 0x0a, 0xe2, 0xfe, 0xa1, 0x05, 0xd4, 0x6a, 0x56,
+ };
+ uint8_t encrypted[] = {
+ 0x80, 0x36,
+ 0xf4, 0xab, 0xbe, 0x21, 0x17, 0xfb, 0x3e, 0x4a, 0x78, 0x74, 0xdc, 0xe9, 0x1c, 0x5b, 0x04, 0x49,
+ 0x8e, 0xc7, 0x72, 0x0f, 0x16, 0x86, 0x88, 0x56, 0x2d, 0xbc, 0x88, 0xe2, 0x1c, 0xab, 0x62, 0x71,
+ };
+ uint8_t plainkey[] = {
+ 0xfc, 0x6e, 0xa4, 0x18, 0x37, 0x3d, 0x8e, 0x90, 0xc1, 0x36, 0xfa, 0xe3, 0x73, 0x5e, 0x37, 0xd1,
+ };
+ uint8_t plainkey2[] = {
+ 0x86, 0xfe, 0x22, 0x0e, 0x76, 0x24, 0xba, 0x2a, 0x10, 0x05, 0xf6, 0xbf, 0x9b, 0x55, 0xe0, 0xb2,
+ };
+
+ uint8_t plain[256];
+ size_t plen;
+ uint8_t cipher[256];
+ size_t clen;
+ RADIUS_PACKET *packet, *response;
+
+ plen = sizeof(plain);
+ CHECK(radius_decrypt_mppe_key_attr(plain, &plen, encrypted, sizeof(encrypted), ra, "hogehogefugafuga") == 0);
+ CHECK(plen == 16);
+ CHECK(memcmp(plain, plainkey, 16) == 0);
+
+ clen = sizeof(cipher);
+ CHECK(radius_encrypt_mppe_key_attr(cipher, &clen, plainkey, 16, ra, "hogehogefugafuga") == 0);
+ CHECK(clen == 34);
+ memset(plain, 0, sizeof(plain));
+ plen = sizeof(plain);
+ CHECK(radius_decrypt_mppe_key_attr(plain, &plen, cipher, clen, ra, "hogehogefugafuga") == 0);
+ CHECK(plen == 16);
+ CHECK(memcmp(plain, plainkey, 16) == 0);
+
+ clen = 33;
+ CHECK(radius_encrypt_mppe_key_attr(cipher, &clen, plainkey, 16, ra, "hogehogefugafuga") != 0);
+ plen = 15;
+ CHECK(radius_decrypt_mppe_key_attr(plain, &plen, cipher, 34, ra, "hogehogefugafuga") != 0);
+ plen = 16;
+ CHECK(radius_decrypt_mppe_key_attr(plain, &plen, cipher, 33, ra, "hogehogefugafuga") != 0);
+
+ packet = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
+
+ CHECK(radius_put_mppe_send_key_attr(packet, plainkey, sizeof(plainkey), "sharedsecret") == 0);
+ clen = sizeof(cipher);
+ CHECK(radius_get_vs_raw_attr(packet, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MPPE_SEND_KEY, cipher, &clen) == 0);
+ CHECK(clen == 34);
+ plen = sizeof(plain);
+ CHECK(radius_decrypt_mppe_key_attr(plain, &plen, cipher, clen, radius_get_authenticator_retval(packet), "sharedsecret") == 0);
+ CHECK(plen == 16);
+ CHECK(memcmp(plain, plainkey, plen) == 0);
+ memset(plain, 0, sizeof(plain));
+ plen = sizeof(plain);
+ CHECK(radius_get_mppe_send_key_attr(packet, plain, &plen, "sharedsecret") == 0);
+ CHECK(plen == 16);
+ CHECK(memcmp(plain, plainkey, plen) == 0);
+
+ response = radius_new_response_packet(RADIUS_CODE_ACCESS_ACCEPT, packet);
+
+ CHECK(radius_put_mppe_recv_key_attr(response, plainkey2, sizeof(plainkey2), "sharedsecret") == 0);
+ clen = sizeof(cipher);
+ CHECK(radius_get_vs_raw_attr(response, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MPPE_RECV_KEY, cipher, &clen) == 0);
+ CHECK(clen == 34);
+ plen = sizeof(plain);
+ CHECK(radius_decrypt_mppe_key_attr(plain, &plen, cipher, clen, radius_get_authenticator_retval(packet), "sharedsecret") == 0);
+ CHECK(plen == 16);
+ CHECK(memcmp(plain, plainkey2, plen) == 0);
+ memset(plain, 0, sizeof(plain));
+ plen = sizeof(plain);
+ CHECK(radius_get_mppe_recv_key_attr(response, plain, &plen, "sharedsecret") == 0);
+ CHECK(plen == 16);
+ CHECK(memcmp(plain, plainkey2, plen) == 0);
+}
+
+ADD_TEST(test25)