summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryasuoka <yasuoka@openbsd.org>2015-07-20 23:52:29 +0000
committeryasuoka <yasuoka@openbsd.org>2015-07-20 23:52:29 +0000
commit0eaf192d8f98a1706afb2186171b5fb45b160397 (patch)
treecbda52d82b81136f1e5c92160880b7e1d9be3262
parentMove `ticks' declaration to sys/kernel.h. (diff)
downloadwireguard-openbsd-0eaf192d8f98a1706afb2186171b5fb45b160397.tar.xz
wireguard-openbsd-0eaf192d8f98a1706afb2186171b5fb45b160397.zip
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
-rw-r--r--lib/libradius/Makefile21
-rw-r--r--lib/libradius/radius.3283
-rw-r--r--lib/libradius/radius.c418
-rw-r--r--lib/libradius/radius.h515
-rw-r--r--lib/libradius/radius_attr.c533
-rw-r--r--lib/libradius/radius_eapmsk.c78
-rw-r--r--lib/libradius/radius_local.h81
-rw-r--r--lib/libradius/radius_mppe.c188
-rw-r--r--lib/libradius/radius_msgauth.c132
-rw-r--r--lib/libradius/radius_userpass.c153
-rw-r--r--lib/libradius/shlib_version2
-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
-rw-r--r--share/mk/bsd.README3
-rw-r--r--share/mk/bsd.prog.mk3
31 files changed, 3344 insertions, 2 deletions
diff --git a/lib/libradius/Makefile b/lib/libradius/Makefile
new file mode 100644
index 00000000000..a5dc26e9eab
--- /dev/null
+++ b/lib/libradius/Makefile
@@ -0,0 +1,21 @@
+# $OpenBSD: Makefile,v 1.1 2015/07/20 23:52:29 yasuoka Exp $
+
+LIB= radius
+SRCS= radius.c radius_attr.c radius_msgauth.c radius_userpass.c \
+ radius_mppe.c radius_eapmsk.c
+INCS= radius.h
+
+CFLAGS+= -Wall
+
+MAN= radius.3
+
+.include <bsd.lib.mk>
+
+includes:
+ @cd ${.CURDIR}; for i in $(INCS); do \
+ j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \
+ ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} \
+ -m 444 $$i ${DESTDIR}/usr/include"; \
+ echo $$j; \
+ eval "$$j"; \
+ done
diff --git a/lib/libradius/radius.3 b/lib/libradius/radius.3
new file mode 100644
index 00000000000..da189e425db
--- /dev/null
+++ b/lib/libradius/radius.3
@@ -0,0 +1,283 @@
+.\" $OpenBSD: radius.3,v 1.1 2015/07/20 23:52:29 yasuoka Exp $
+.\"
+.\" Copyright (c) 2009 Internet Initiative Japan Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd $Mdocdate: July 20 2015 $
+.Dt NRADIUS 3
+.Os
+.Sh NAME
+.Nm radius
+.Nd manipulate RADIUS packets for RADIUS clients/servers
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/in.h
+.In stdbool.h
+.In radius.h
+.Sh DESCRIPTION
+.Nm radius
+provides a facility to manipulate RADIUS packets and some helper functions.
+.Sh CREATING AND DESTROYING PACKETS
+RADIUS packet objects are created by
+.Fn radius_new_request_packet ,
+.Fn radius_new_response_packet
+or
+.Fn radius_convert_packet .
+Authenticator field of the packet that is returned by
+.Fn radius_new_request_packet
+and
+.Fn radius_new_response_packet
+is filled with random bytes.
+.Pp
+You must call
+.Fn radius_delete_packet
+to free memory associated with the packet object.
+.Sh HEADER ACCESSOR
+.Fn radius_get_id ,
+.Fn radius_get_code ,
+.Fn radius_get_authenticator ,
+.Fn radius_get_authenticator_retval
+and
+.Fn radius_get_length
+retreives specified property of the packet.
+.Fn radius_update_id
+update packet's ID field with internal id counter.
+.Fn radius_set_id
+sets packet's ID field.
+.Pp
+.Fn radius_set_request_packet
+associate request packet to response packet.
+Associated request packet can be retrieved by
+.Fn radius_get_request_packet .
+.Pp
+.Fn radius_set_response_authenticator
+sets response authenticator to response packet.
+.Fn radius_check_response_authenticator
+checks response authenticator of response packet.
+The request packet must be associated with response packet by
+.Fn radius_new_response_packet
+or
+.Fn radius_set_request_packet .
+.Pp
+.Fn radius_set_accounting_request_authenticator
+sets request authenticator to accounting request packet.
+.Fn radius_check_accounting_request_authenticator
+checks request authenticator of accounting request packet.
+.Pp
+.Fn radius_get_request_authenticator_retval
+returns authenticator field of the packet if the argument is
+a request packet, and returns that of the associated request packet
+if the argument is a response packet.
+.Pp
+.Fn radius_get_data
+returns packet data itself.
+.Sh RAW ATTRIBUTE ACCESSOR
+.Fn radius_get_raw_attr
+retrieves attribute value.
+.Fa length
+is a value-result parameter, initially containing the size of the buffer
+and modified on return to indicate the size of the value returned.
+If buffer size is not sufficient, returned value is truncated.
+.Pp
+.Fn radius_put_raw_attr
+appends attribute data to the last of the packet.
+If buffer size is larger than maximum size of single attribute, this
+function returns error.
+.Pp
+.Fn radius_get_raw_attr_cat
+retrieves attrbute value.
+Unlike
+.Fn radius_get_raw_attr ,
+.Fn radius_get_raw_attr_cat
+retreives concatenated ALL attrbiute value that have specified attribute type.
+If buffer size is not sufficient, this function returns error.
+If
+.Fa buf
+is
+.Dv NULL ,
+the initial value of
+.Fa length
+is not cared and the actual size of concatenated values is returned.
+.Pp
+.Fn radius_put_raw_attr_cat
+appends attribute data to the last of the packet.
+Unlike
+.Fn radius_put_raw_attr ,
+.Fn radius_put_raw_attr_cat
+divides data into multiple attributes and append them if buffer size is
+larger than maximum size of single attribute.
+Note that packet object may be broken (but can be deleted normally by
+.Fn radius_delete_packet )
+if this function have returned error.
+.Pp
+.Fn radius_get_raw_attr_ptr
+retreives pointer and length of specified attribute.
+returned buffer must not be modified.
+.Pp
+.Fn radius_set_raw_attr
+overwrite existing attribute value.
+If specified attribute does not exist, this function returns error.
+If
+.Fa length
+is different from length of the specified attribute, this function returns error.
+.Pp
+.Fn radius_del_attr_all
+deletes all attributes matching its arguments.
+.Pp
+.Fn radius_has_attr
+returns whether packet has specified attribute.
+.Pp
+.Fn radius_get_vs_raw_attr ,
+.Fn radius_put_vs_raw_attr ,
+.Fn radius_get_vs_raw_attr_cat ,
+.Fn radius_put_vs_raw_attr_cat ,
+.Fn radius_get_vs_raw_attr_ptr ,
+.Fn radius_set_vs_raw_attr ,
+.Fn radius_del_vs_attr_all
+and
+.Fn radius_has_vs_attr
+are vendor-specific version of raw attribute accessors.
+.Sh TYPED ATTRIBUTE ACCESSOR
+To make code simple, there are many typed attribute accessors.
+.Nm radius
+provides typed accessors for
+.Li uint16_t ,
+.Li uint32_t ,
+.Li uint64_t ,
+.Li struct in_addr
+and
+.Li struct in6_addr .
+Byte endian may be appropriately swapped for
+.Li uint16_t ,
+.Li uint32_t
+and
+.Li uint64_t .
+.Pp
+These typed accessors do not requires
+.Fa length
+parameters because length is implied by the type.
+For "get" functions, if actual attribute size is different from the size of
+the type, the functions return error.
+.Pp
+There are also typed accessors for string (
+.Li char * ).
+For "get" function for string, returned string is always NUL-terminated
+even if buffer size is smaller than actual attribute size.
+This behavior is similar to
+.Fn strlcpy .
+.Sh MESSAGE AUTHENTICATOR
+There exist helper functions for Message-Authenticator attribute.
+.Pp
+.Fn radius_put_message_authenticator
+and
+.Fn radius_set_message_authenticator
+calculate Message-Authenticator and put or set it to packet, respectively.
+.Pp
+.Fn radius_check_message_authenticator
+checks Message-Authenticator.
+.Pp
+The request packet must be associated with response packet by
+.Fn radius_new_response_packet
+or
+.Fn radius_set_request_packet ,
+otherwise packet is treated as request packet.
+.Sh ENCRYPTED ATTRIBUTE
+There exist helper functions for encrypted attributes.
+.Pp
+.Fn radius_encrypt_user_password_attr ,
+.Fn radius_decrypt_user_password_attr ,
+.Fn radius_encrypt_mppe_key_attr
+and
+.Fn radius_decrypt_mppe_key_attr
+encrypt or decrypt User-Password attribute or MS-MPPE-{Send,Recv}-Key
+attributes respectively.
+.Pp
+.Fn radius_get_user_password_attr ,
+.Fn radius_put_user_password_attr ,
+.Fn radius_get_mppe_send_key_attr ,
+.Fn radius_put_mppe_send_key_attr ,
+.Fn radius_get_mppe_recv_key_attr
+and
+.Fn radius_put_mppe_recv_key_attr
+are shortcuts of combination of encrypt/decrypt functions
+and get/put functions.
+.Sh SENDING AND RECEIVING PACKETS
+There exist helper functions to sending and receiving packets.
+.Pp
+.Fn radius_send ,
+.Fn radius_sendto ,
+.Fn radius_sendmsg ,
+.Fn radius_recv ,
+.Fn radius_recvfrom
+and
+.Fn radius_recvmsg
+are helper version of
+.Fn send ,
+.Fn sendto ,
+.Fn sendmsg ,
+.Fn recv ,
+.Fn recvfrom
+and
+.Fn recvmsg ,
+respectively.
+.Pp
+.Fn radius_send ,
+.Fn radius_sendto
+and
+.Fn radius_sendmsg
+return 0 on success and nonzero on failure.
+.Pp
+.Fn radius_recv
+.Fn radius_recvfrom
+and
+.Fn radius_recvmsg
+return received packet on success and return NULL on failure.
+.Pp
+Note that
+.Li msg_iov
+must be
+.Li NULL
+and
+.Li msg_iovlen
+must be zero in case of
+.Fn radius_sendmsg
+and
+.Fn radius_recvmsg .
+.Sh RETURN VALUES
+Functions that return int return 0 on success and nonzero on failure.
+Functions that return pointer return non-NULL pointer on success and
+NULL on failure.
+.\" .Sh SEE ALSO
+.Sh HISTORY
+.Nm radius+
+library is first written by UMEZAWA Takeshi in 2002 for ID gateway service
+of Internet Initiative Japan.
+YASUOKA Masahiko added support for Message-Authentication attribute in 2008.
+OpenBSD project rewrite C++ code to pure C code in 2010.
+.Nm radius+
+library is renamed
+.Nm radius
+library and moved to under lib/ in 2013.
+.\" .Sh AUTHROS
diff --git a/lib/libradius/radius.c b/lib/libradius/radius.c
new file mode 100644
index 00000000000..45a9efc0871
--- /dev/null
+++ b/lib/libradius/radius.c
@@ -0,0 +1,418 @@
+/* $OpenBSD: radius.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
+
+/*-
+ * Copyright (c) 2009 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sys/uio.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/md5.h>
+
+#include "radius.h"
+
+#include "radius_local.h"
+
+static uint8_t radius_id_counter = 0;
+
+static int
+radius_check_packet_data(const RADIUS_PACKET_DATA * pdata,
+ size_t length)
+{
+ const RADIUS_ATTRIBUTE *attr;
+ const RADIUS_ATTRIBUTE *end;
+
+ if (length < sizeof(RADIUS_PACKET_DATA))
+ return (-1);
+ if (length > 0xffff)
+ return (-1);
+ if (length != (size_t) ntohs(pdata->length))
+ return (-1);
+
+ attr = ATTRS_BEGIN(pdata);
+ end = ATTRS_END(pdata);
+ for (; attr < end; ATTRS_ADVANCE(attr)) {
+ if (attr->length < 2)
+ return (-1);
+ if (attr->type == RADIUS_TYPE_VENDOR_SPECIFIC) {
+ if (attr->length < 8)
+ return (-1);
+ if ((attr->vendor & htonl(0xff000000U)) != 0)
+ return (-1);
+ if (attr->length != attr->vlength + 6)
+ return (-1);
+ }
+ }
+
+ if (attr != end)
+ return (-1);
+
+ return (0);
+}
+
+int
+radius_ensure_add_capacity(RADIUS_PACKET * packet, size_t capacity)
+{
+ size_t newsize;
+ void *newptr;
+
+ /*
+ * The maximum size is 64KB.
+ * We use little bit smaller value for our safety(?).
+ */
+ if (ntohs(packet->pdata->length) + capacity > 0xfe00)
+ return (-1);
+
+ if (ntohs(packet->pdata->length) + capacity > packet->capacity) {
+ newsize = ntohs(packet->pdata->length) + capacity +
+ RADIUS_PACKET_CAPACITY_INCREMENT;
+ newptr = realloc(packet->pdata, newsize);
+ if (newptr == NULL)
+ return (-1);
+ packet->capacity = newsize;
+ packet->pdata = (RADIUS_PACKET_DATA *)newptr;
+ }
+ return (0);
+}
+
+RADIUS_PACKET *
+radius_new_request_packet(uint8_t code)
+{
+ RADIUS_PACKET *packet;
+
+ packet = (RADIUS_PACKET *)malloc(sizeof(RADIUS_PACKET));
+ if (packet == NULL)
+ return (NULL);
+ packet->pdata =
+ (RADIUS_PACKET_DATA *)malloc(RADIUS_PACKET_CAPACITY_INITIAL);
+ if (packet->pdata == NULL) {
+ free(packet);
+ return (NULL);
+ }
+ packet->capacity = RADIUS_PACKET_CAPACITY_INITIAL;
+ packet->request = NULL;
+ packet->pdata->code = code;
+ packet->pdata->id = radius_id_counter++;
+ packet->pdata->length = htons(sizeof(RADIUS_PACKET_DATA));
+ arc4random_buf(packet->pdata->authenticator,
+ sizeof(packet->pdata->authenticator));
+
+ return (packet);
+}
+
+RADIUS_PACKET *
+radius_new_response_packet(uint8_t code, const RADIUS_PACKET * request)
+{
+ RADIUS_PACKET *packet;
+
+ packet = radius_new_request_packet(code);
+ if (packet == NULL)
+ return (NULL);
+ packet->request = request;
+ packet->pdata->id = request->pdata->id;
+
+ return (packet);
+}
+
+RADIUS_PACKET *
+radius_convert_packet(const void *pdata, size_t length)
+{
+ RADIUS_PACKET *packet;
+
+ if (radius_check_packet_data((const RADIUS_PACKET_DATA *)pdata,
+ length) != 0)
+ return (NULL);
+ packet = (RADIUS_PACKET *)malloc(sizeof(RADIUS_PACKET));
+ if (packet == NULL)
+ return (NULL);
+ packet->pdata = (RADIUS_PACKET_DATA *)malloc(length);
+ packet->capacity = length;
+ packet->request = NULL;
+ if (packet->pdata == NULL) {
+ free(packet);
+ return (NULL);
+ }
+ memcpy(packet->pdata, pdata, length);
+
+ return (packet);
+}
+
+int
+radius_delete_packet(RADIUS_PACKET * packet)
+{
+ free(packet->pdata);
+ free(packet);
+ return (0);
+}
+
+uint8_t
+radius_get_code(const RADIUS_PACKET * packet)
+{
+ return (packet->pdata->code);
+}
+
+uint8_t
+radius_get_id(const RADIUS_PACKET * packet)
+{
+ return (packet->pdata->id);
+}
+
+void
+radius_update_id(RADIUS_PACKET * packet)
+{
+ packet->pdata->id = radius_id_counter++;
+}
+
+void
+radius_set_id(RADIUS_PACKET * packet, uint8_t id)
+{
+ packet->pdata->id = id;
+}
+
+void
+radius_get_authenticator(const RADIUS_PACKET * packet, void *authenticator)
+{
+ memcpy(authenticator, packet->pdata->authenticator, 16);
+}
+
+uint8_t *
+radius_get_authenticator_retval(const RADIUS_PACKET * packet)
+{
+ return (packet->pdata->authenticator);
+}
+
+uint8_t *
+radius_get_request_authenticator_retval(const RADIUS_PACKET * packet)
+{
+ if (packet->request == NULL)
+ return (packet->pdata->authenticator);
+ else
+ return (packet->request->pdata->authenticator);
+}
+
+void
+radius_set_request_packet(RADIUS_PACKET * packet,
+ const RADIUS_PACKET * request)
+{
+ packet->request = request;
+}
+
+const RADIUS_PACKET *
+radius_get_request_packet(const RADIUS_PACKET * packet)
+{
+ return (packet->request);
+}
+
+static void
+radius_calc_authenticator(uint8_t * authenticator_dst,
+ const RADIUS_PACKET * packet, const uint8_t * authenticator_src,
+ const char *secret)
+{
+ MD5_CTX ctx;
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, (unsigned char *)packet->pdata, 4);
+ MD5_Update(&ctx, (unsigned char *)authenticator_src, 16);
+ MD5_Update(&ctx,
+ (unsigned char *)packet->pdata->attributes,
+ radius_get_length(packet) - 20);
+ MD5_Update(&ctx, (unsigned char *)secret, strlen(secret));
+ MD5_Final((unsigned char *)authenticator_dst, &ctx);
+}
+
+static void
+radius_calc_response_authenticator(uint8_t * authenticator_dst,
+ const RADIUS_PACKET * packet, const char *secret)
+{
+ radius_calc_authenticator(authenticator_dst,
+ packet, packet->request->pdata->authenticator, secret);
+}
+
+int
+radius_check_response_authenticator(const RADIUS_PACKET * packet,
+ const char *secret)
+{
+ uint8_t authenticator[16];
+
+ radius_calc_response_authenticator(authenticator, packet, secret);
+ return (memcmp(authenticator, packet->pdata->authenticator, 16));
+}
+
+void
+radius_set_response_authenticator(RADIUS_PACKET * packet,
+ const char *secret)
+{
+ radius_calc_response_authenticator(packet->pdata->authenticator,
+ packet, secret);
+}
+
+static void
+radius_calc_accounting_request_authenticator(uint8_t * authenticator_dst,
+ const RADIUS_PACKET * packet, const char *secret)
+{
+ uint8_t zero[16];
+
+ memset(zero, 0, sizeof(zero));
+ radius_calc_authenticator(authenticator_dst,
+ packet, zero, secret);
+}
+
+void
+radius_set_accounting_request_authenticator(RADIUS_PACKET * packet,
+ const char *secret)
+{
+ radius_calc_accounting_request_authenticator(
+ packet->pdata->authenticator, packet, secret);
+}
+
+int
+radius_check_accounting_request_authenticator(const RADIUS_PACKET * packet,
+ const char *secret)
+{
+ uint8_t authenticator[16];
+
+ radius_calc_accounting_request_authenticator(authenticator, packet,
+ secret);
+ return (memcmp(authenticator, packet->pdata->authenticator, 16));
+}
+
+
+uint16_t
+radius_get_length(const RADIUS_PACKET * packet)
+{
+ return (ntohs(packet->pdata->length));
+}
+
+
+const void *
+radius_get_data(const RADIUS_PACKET * packet)
+{
+ return (packet->pdata);
+}
+
+RADIUS_PACKET *
+radius_recvfrom(int s, int flags, struct sockaddr * sa, socklen_t * slen)
+{
+ char buf[0x10000];
+ ssize_t n;
+
+ n = recvfrom(s, buf, sizeof(buf), flags, sa, slen);
+ if (n <= 0)
+ return (NULL);
+
+ return (radius_convert_packet(buf, (size_t) n));
+}
+
+int
+radius_sendto(int s, const RADIUS_PACKET * packet,
+ int flags, const struct sockaddr * sa, socklen_t slen)
+{
+ ssize_t n;
+
+ n = sendto(s, packet->pdata, radius_get_length(packet), flags, sa,
+ slen);
+ if (n != radius_get_length(packet))
+ return (-1);
+
+ return (0);
+}
+
+RADIUS_PACKET *
+radius_recv(int s, int flags)
+{
+ char buf[0x10000];
+ ssize_t n;
+
+ n = recv(s, buf, sizeof(buf), flags);
+ if (n <= 0)
+ return (NULL);
+
+ return (radius_convert_packet(buf, (size_t) n));
+}
+
+int
+radius_send(int s, const RADIUS_PACKET * packet, int flags)
+{
+ ssize_t n;
+
+ n = send(s, packet->pdata, radius_get_length(packet), flags);
+ if (n != radius_get_length(packet))
+ return (-1);
+
+ return (0);
+}
+
+RADIUS_PACKET *
+radius_recvmsg(int s, struct msghdr * msg, int flags)
+{
+ struct iovec iov;
+ char buf[0x10000];
+ ssize_t n;
+
+ if (msg->msg_iov != NULL || msg->msg_iovlen != 0)
+ return (NULL);
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+ msg->msg_iov = &iov;
+ msg->msg_iovlen = 1;
+ n = recvmsg(s, msg, flags);
+ msg->msg_iov = NULL;
+ msg->msg_iovlen = 0;
+ if (n <= 0)
+ return (NULL);
+
+ return (radius_convert_packet(buf, (size_t) n));
+}
+
+int
+radius_sendmsg(int s, const RADIUS_PACKET * packet,
+ const struct msghdr * msg, int flags)
+{
+ struct msghdr msg0;
+ struct iovec iov;
+ ssize_t n;
+
+ if (msg->msg_iov != NULL || msg->msg_iovlen != 0)
+ return (-1);
+
+ iov.iov_base = packet->pdata;
+ iov.iov_len = radius_get_length(packet);
+ msg0 = *msg;
+ msg0.msg_iov = &iov;
+ msg0.msg_iovlen = 1;
+ n = sendmsg(s, &msg0, flags);
+ if (n != radius_get_length(packet))
+ return (-1);
+
+ return (0);
+}
diff --git a/lib/libradius/radius.h b/lib/libradius/radius.h
new file mode 100644
index 00000000000..98c5ee61fe9
--- /dev/null
+++ b/lib/libradius/radius.h
@@ -0,0 +1,515 @@
+/* $OpenBSD: radius.h,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
+
+/*-
+ * Copyright (c) 2009 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _RADIUS_H
+#define _RADIUS_H
+
+#define RADIUS_DEFAULT_PORT 1812
+#define RADIUS_ACCT_DEFAULT_PORT 1813
+
+/* RADIUS codes */
+#define RADIUS_CODE_ACCESS_REQUEST 1
+#define RADIUS_CODE_ACCESS_ACCEPT 2
+#define RADIUS_CODE_ACCESS_REJECT 3
+#define RADIUS_CODE_ACCOUNTING_REQUEST 4
+#define RADIUS_CODE_ACCOUNTING_RESPONSE 5
+#define RADIUS_CODE_ACCESS_CHALLENGE 11
+#define RADIUS_CODE_STATUS_SERVER 12
+#define RADIUS_CODE_STATUS_CLIENT 13
+
+
+/* RADIUS attributes */
+#define RADIUS_TYPE_USER_NAME 1
+#define RADIUS_TYPE_USER_PASSWORD 2
+#define RADIUS_TYPE_CHAP_PASSWORD 3
+#define RADIUS_TYPE_NAS_IP_ADDRESS 4
+#define RADIUS_TYPE_NAS_PORT 5
+#define RADIUS_TYPE_SERVICE_TYPE 6
+#define RADIUS_TYPE_FRAMED_PROTOCOL 7
+#define RADIUS_TYPE_FRAMED_IP_ADDRESS 8
+#define RADIUS_TYPE_FRAMED_IP_NETMASK 9
+#define RADIUS_TYPE_FRAMED_ROUTING 10
+#define RADIUS_TYPE_FILTER_ID 11
+#define RADIUS_TYPE_FRAMED_MTU 12
+#define RADIUS_TYPE_FRAMED_COMPRESSION 13
+#define RADIUS_TYPE_LOGIN_IP_HOST 14
+#define RADIUS_TYPE_LOGIN_SERVICE 15
+#define RADIUS_TYPE_LOGIN_TCP_PORT 16
+/* unassigned 17 */
+#define RADIUS_TYPE_REPLY_MESSAGE 18
+#define RADIUS_TYPE_CALLBACK_NUMBER 19
+#define RADIUS_TYPE_CALLBACK_ID 20
+/* unassigned 21 */
+#define RADIUS_TYPE_FRAMED_ROUTE 22
+#define RADIUS_TYPE_FRAMED_IPX_NETWORK 23
+#define RADIUS_TYPE_STATE 24
+#define RADIUS_TYPE_CLASS 25
+#define RADIUS_TYPE_VENDOR_SPECIFIC 26
+#define RADIUS_TYPE_SESSION_TIMEOUT 27
+#define RADIUS_TYPE_IDLE_TIMEOUT 28
+#define RADIUS_TYPE_TERMINATION_ACTION 29
+#define RADIUS_TYPE_CALLED_STATION_ID 30
+#define RADIUS_TYPE_CALLING_STATION_ID 31
+#define RADIUS_TYPE_NAS_IDENTIFIER 32
+#define RADIUS_TYPE_PROXY_STATE 33
+#define RADIUS_TYPE_LOGIN_LAT_SERVICE 34
+#define RADIUS_TYPE_LOGIN_LAT_NODE 35
+#define RADIUS_TYPE_LOGIN_LAT_GROUP 36
+#define RADIUS_TYPE_FRAMED_APPLETALK_LINK 37
+#define RADIUS_TYPE_FRAMED_APPLETALK_NETWORK 38
+#define RADIUS_TYPE_FRAMED_APPLETALK_ZONE 39
+#define RADIUS_TYPE_ACCT_STATUS_TYPE 40
+#define RADIUS_TYPE_ACCT_DELAY_TIME 41
+#define RADIUS_TYPE_ACCT_INPUT_OCTETS 42
+#define RADIUS_TYPE_ACCT_OUTPUT_OCTETS 43
+#define RADIUS_TYPE_ACCT_SESSION_ID 44
+#define RADIUS_TYPE_ACCT_AUTHENTIC 45
+#define RADIUS_TYPE_ACCT_SESSION_TIME 46
+#define RADIUS_TYPE_ACCT_INPUT_PACKETS 47
+#define RADIUS_TYPE_ACCT_OUTPUT_PACKETS 48
+#define RADIUS_TYPE_ACCT_TERMINATE_CAUSE 49
+#define RADIUS_TYPE_ACCT_MULTI_SESSION_ID 50
+#define RADIUS_TYPE_ACCT_LINK_COUNT 51
+#define RADIUS_TYPE_ACCT_INPUT_GIGAWORDS 52
+#define RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS 53
+/* unassigned (for accounting) 54 */
+#define RADIUS_TYPE_EVENT_TIMESTAMP 55
+/* unassigned (for accounting) 56 */
+/* unassigned (for accounting) 57 */
+/* unassigned (for accounting) 58 */
+/* unassigned (for accounting) 59 */
+#define RADIUS_TYPE_CHAP_CHALLENGE 60
+#define RADIUS_TYPE_NAS_PORT_TYPE 61
+#define RADIUS_TYPE_PORT_LIMIT 62
+#define RADIUS_TYPE_LOGIN_LAT_PORT 63
+#define RADIUS_TYPE_TUNNEL_TYPE 64
+#define RADIUS_TYPE_TUNNEL_MEDIUM_TYPE 65
+#define RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT 66
+#define RADIUS_TYPE_TUNNEL_SERVER_ENDPOINT 67
+#define RADIUS_TYPE_ACCT_TUNNEL_CONNECTION 68
+#define RADIUS_TYPE_TUNNEL_PASSWORD 69
+#define RADIUS_TYPE_ARAP_PASSWORD 70
+#define RADIUS_TYPE_ARAP_FEATURES 71
+#define RADIUS_TYPE_ARAP_ZONE_ACCESS 72
+#define RADIUS_TYPE_ARAP_SECURITY 73
+#define RADIUS_TYPE_ARAP_SECURITY_DATA 74
+#define RADIUS_TYPE_PASSWORD_RETRY 75
+#define RADIUS_TYPE_PROMPT 76
+#define RADIUS_TYPE_CONNECT_INFO 77
+#define RADIUS_TYPE_CONFIGURATION_TOKEN 78
+#define RADIUS_TYPE_EAP_MESSAGE 79
+#define RADIUS_TYPE_MESSAGE_AUTHENTICATOR 80
+#define RADIUS_TYPE_TUNNEL_PRIVATE_GROUP_ID 81
+#define RADIUS_TYPE_TUNNEL_ASSIGNMENT_ID 82
+#define RADIUS_TYPE_TUNNEL_PREFERENCE 83
+#define RADIUS_TYPE_ARAP_CHALLENGE_RESPONSE 84
+#define RADIUS_TYPE_ACCT_INTERIM_INTERVAL 85
+#define RADIUS_TYPE_ACCT_TUNNEL_PACKETS_LOST 86
+#define RADIUS_TYPE_NAS_PORT_ID 87
+#define RADIUS_TYPE_FRAMED_POOL 88
+/* unassigned 89 */
+#define RADIUS_TYPE_TUNNEL_CLIENT_AUTH_ID 90
+#define RADIUS_TYPE_TUNNEL_SERVER_AUTH_ID 91
+/* unassigned 92-94 */
+#define RADIUS_TYPE_NAS_IPV6_ADDRESS 95
+#define RADIUS_TYPE_FRAMED_INTERFACE_ID 96
+#define RADIUS_TYPE_FRAMED_IPV6_PREFIX 97
+#define RADIUS_TYPE_LOGIN_IPV6_HOST 98
+#define RADIUS_TYPE_FRAMED_IPV6_ROUTE 99
+#define RADIUS_TYPE_FRAMED_IPV6_POOL 100
+
+
+/* RFC 2865 5.7. Framed-Protocol */
+#define RADIUS_FRAMED_PROTOCOL_PPP 1 /* PPP */
+#define RADIUS_FRAMED_PROTOCOL_SLIP 2 /* SLIP */
+#define RADIUS_FRAMED_PROTOCOL_ARAP 3 /* AppleTalk Remote Access
+ * Protocol (ARAP) */
+#define RADIUS_FRAMED_PROTOCOL_GANDALF 4 /* Gandalf proprietary
+ * SingleLink/MultiLink
+ * protocol */
+#define RADIUS_FRAMED_PROTOCOL_XYLOGICS 5 /* Xylogics proprietary
+ * IPX/SLIP */
+#define RADIUS_FRAMED_PROTOCOL_X75 6 /* X.75 Synchronous */
+
+
+/* RFC 2865 5.6. Service-Type */
+#define RADIUS_SERVICE_TYPE_LOGIN 1
+#define RADIUS_SERVICE_TYPE_FRAMED 2
+#define RADIUS_SERVICE_TYPE_CB_LOGIN 3
+#define RADIUS_SERVICE_TYPE_CB_FRAMED 4
+#define RADIUS_SERVICE_TYPE_OUTBOUND 5
+#define RADIUS_SERVICE_TYPE_ADMINISTRATIVE 6
+#define RADIUS_SERVICE_TYPE_NAS_PROMPT 7
+#define RADIUS_SERVICE_TYPE_AUTHENTICAT_ONLY 8
+#define RADIUS_SERVICE_TYPE_CB_NAS_PROMPTi 9
+#define RADIUS_SERVICE_TYPE_CALL_CHECK 10
+#define RADIUS_SERVICE_TYPE_CB_ADMINISTRATIVE 11
+
+
+/* Microsoft vendor specific attributes: see RFC2548*/
+#define RADIUS_VENDOR_MICROSOFT 311
+#define RADIUS_VTYPE_MS_CHAP_RESPONSE 1
+#define RADIUS_VTYPE_MS_CHAP_ERROR 2
+#define RADIUS_VTYPE_MS_CHAP_PW_1 3
+#define RADIUS_VTYPE_MS_CHAP_PW_2 4
+#define RADIUS_VTYPE_MS_CHAP_LM_ENC_PW 5
+#define RADIUS_VTYPE_MS_CHAP_NT_ENC_PW 6
+#define RADIUS_VTYPE_MPPE_ENCRYPTION_POLICY 7
+#define RADIUS_VTYPE_MPPE_ENCRYPTION_TYPES 8
+#define RADIUS_VTYPE_MS_RAS_VENDOR 9
+#define RADIUS_VTYPE_MS_CHAP_CHALLENGE 11
+#define RADIUS_VTYPE_MS_CHAP_MPPE_KEYS 12
+#define RADIUS_VTYPE_MS_BAP_USAGE 13
+#define RADIUS_VTYPE_MS_LINK_UTILIZATION_THRESHOLD 14
+#define RADIUS_VTYPE_MS_LINK_DROP_TIME_LIMIT 15
+#define RADIUS_VTYPE_MPPE_SEND_KEY 16
+#define RADIUS_VTYPE_MPPE_RECV_KEY 17
+#define RADIUS_VTYPE_MS_RAS_VERSION 18
+#define RADIUS_VTYPE_MS_OLD_ARAP_PASSWORD 19
+#define RADIUS_VTYPE_MS_NEW_ARAP_PASSWORD 20
+#define RADIUS_VTYPE_MS_ARAP_PASSWORD_CHANGE_REASON 21
+#define RADIUS_VTYPE_MS_FILTER 22
+#define RADIUS_VTYPE_MS_ACCT_AUTH_TYPE 23
+#define RADIUS_VTYPE_MS_ACCT_EAP_TYPE 24
+#define RADIUS_VTYPE_MS_CHAP2_RESPONSE 25
+#define RADIUS_VTYPE_MS_CHAP2_SUCCESS 26
+#define RADIUS_VTYPE_MS_CHAP2_PW 27
+#define RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER 28
+#define RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER 29
+#define RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER 30
+#define RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER 31
+/* unassigned? 32 */
+#define RADIUS_VTYPE_MS_ARAP_CHALLENGE 33
+
+
+/* RFC 2865 5.41. NAS-Port-Type */
+#define RADIUS_NAS_PORT_TYPE_ASYNC 0 /* Async */
+#define RADIUS_NAS_PORT_TYPE_SYNC 1 /* Sync */
+#define RADIUS_NAS_PORT_TYPE_ISDN_SYNC 2 /* ISDN Sync */
+#define RADIUS_NAS_PORT_TYPE_ISDN_ASYNC_V120 3 /* ISDN Async V.120 */
+#define RADIUS_NAS_PORT_TYPE_ISDN_ASYNC_V110 4 /* ISDN Async V.110 */
+#define RADIUS_NAS_PORT_TYPE_VIRTUAL 5 /* Virtual */
+#define RADIUS_NAS_PORT_TYPE_PIAFS 6 /* PIAFS */
+#define RADIUS_NAS_PORT_TYPE_HDLC_CLEAR_CHANNEL 7 /* HDLC Clear Channel */
+#define RADIUS_NAS_PORT_TYPE_X_25 8 /* X.25 */
+#define RADIUS_NAS_PORT_TYPE_X_75 9 /* X.75 */
+#define RADIUS_NAS_PORT_TYPE_G3_FAX 10 /* G.3 Fax */
+#define RADIUS_NAS_PORT_TYPE_SDSL 11 /* SDSL - Symmetric DSL */
+#define RADIUS_NAS_PORT_TYPE_ADSL_CAP 12 /* ADSL-CAP - Asymmetric
+ * DSL, Carrierless
+ * Amplitude Phase
+ * Modulation */
+#define RADIUS_NAS_PORT_TYPE_ADSL_DMT 13 /* ADSL-DMT - Asymmetric
+ * DSL, Discrete
+ * Multi-Tone */
+#define RADIUS_NAS_PORT_TYPE_IDSL 14 /* IDSL - ISDN Digital
+ * Subscriber Line */
+#define RADIUS_NAS_PORT_TYPE_ETHERNET 15 /* Ethernet */
+#define RADIUS_NAS_PORT_TYPE_XDSL 16 /* xDSL - Digital
+ * Subscriber Line of
+ * unknown type */
+#define RADIUS_NAS_PORT_TYPE_CABLE 17 /* Cable */
+#define RADIUS_NAS_PORT_TYPE_WIRELESS 18 /* Wireless - Other */
+#define RADIUS_NAS_PORT_TYPE_WIRELESS_802_11 19 /* Wireless - IEEE
+ * 802.11 */
+
+
+/* RFC 2866 5.1. Acct-Status-Type */
+#define RADIUS_ACCT_STATUS_TYPE_START 1 /* Start */
+#define RADIUS_ACCT_STATUS_TYPE_STOP 2 /* Stop */
+#define RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE 3 /* Interim-Update */
+#define RADIUS_ACCT_STATUS_TYPE_ACCT_ON 7 /* Accounting-On */
+#define RADIUS_ACCT_STATUS_TYPE_ACCT_OFF 8 /* Accounting-Off */
+
+
+/* RFC 2866 5.6. Acct-Authentic */
+#define RADIUS_ACCT_AUTHENTIC_RADIUS 1 /* RADIUS */
+#define RADIUS_ACCT_AUTHENTIC_LOCAL 2 /* Local */
+#define RADIUS_ACCT_AUTHENTIC_REMOTE 3 /* Remote */
+
+
+/* RFC 2866 5.10. Acct-Terminate-Cause */
+#define RADIUS_TERMNATE_CAUSE_USER_REQUEST 1 /* User Request */
+#define RADIUS_TERMNATE_CAUSE_LOST_CARRIER 2 /* Lost Carrier */
+#define RADIUS_TERMNATE_CAUSE_LOST_SERVICE 3 /* Lost Service */
+#define RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT 4 /* Idle Timeout */
+#define RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT 5 /* Session Timeout */
+#define RADIUS_TERMNATE_CAUSE_ADMIN_RESET 6 /* Admin Reset */
+#define RADIUS_TERMNATE_CAUSE_ADMIN_REBOOT 7 /* Admin Reboot */
+#define RADIUS_TERMNATE_CAUSE_PORT_ERROR 8 /* Port Error */
+#define RADIUS_TERMNATE_CAUSE_NAS_ERROR 9 /* NAS Error */
+#define RADIUS_TERMNATE_CAUSE_NAS_RESET 10 /* NAS Request */
+#define RADIUS_TERMNATE_CAUSE_NAS_REBOOT 11 /* NAS Reboot */
+#define RADIUS_TERMNATE_CAUSE_PORT_UNNEEDED 12 /* Port Unneeded */
+#define RADIUS_TERMNATE_CAUSE_PORT_PREEMPTED 13 /* Port Preempted */
+#define RADIUS_TERMNATE_CAUSE_PORT_SUSPENDED 14 /* Port Suspended */
+#define RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL 15 /* Service Unavailable */
+#define RADIUS_TERMNATE_CAUSE_CALLBACK 16 /* Callback */
+#define RADIUS_TERMNATE_CAUSE_USER_ERROR 17 /* User Error */
+#define RADIUS_TERMNATE_CAUSE_HOST_REQUEST 18 /* Host Request */
+
+
+/* RFC 2868 3.1. Tunnel-Type */
+#define RADIUS_TUNNEL_TYPE_PPTP 1 /* Point-to-Point Tunneling
+ * Protocol (PPTP) */
+#define RADIUS_TUNNEL_TYPE_L2F 2 /* Layer Two Forwarding (L2F) */
+#define RADIUS_TUNNEL_TYPE_L2TP 3 /* Layer Two Tunneling
+ * Protocol (L2TP) */
+#define RADIUS_TUNNEL_TYPE_ATMP 4 /* Ascend Tunnel Management
+ * Protocol (ATMP) */
+#define RADIUS_TUNNEL_TYPE_VTP 5 /* Virtual Tunneling Protocol
+ * (VTP) */
+#define RADIUS_TUNNEL_TYPE_AH 6 /* IP Authentication Header in
+ * the Tunnel-mode (AH) */
+#define RADIUS_TUNNEL_TYPE_IP 7 /* IP-in-IP Encapsulation
+ * (IP-IP) */
+#define RADIUS_TUNNEL_TYPE_MOBILE 8 /* Minimal IP-in-IP
+ * Encapsulation (MIN-IP-IP) */
+#define RADIUS_TUNNEL_TYPE_ESP 9 /* IP Encapsulating Security
+ * Payload in the Tunnel-mode
+ * (ESP) */
+#define RADIUS_TUNNEL_TYPE_GRE 10 /* Generic Route Encapsulation
+ * (GRE) */
+#define RADIUS_TUNNEL_TYPE_VDS 11 /* Bay Dial Virtual Services
+ * (DVS) */
+#define RADIUS_TUNNEL_TYPE_IPIP 12 /* IP-in-IP Tunneling */
+
+
+/* RFC 2868 3.2. Tunnel-Medium-Type */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1 /* IPv4 (IP version 4) */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2 /* IPv6 (IP version 6) */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_NSAP 3 /* NSAP */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_HDLC 4 /* HDLC (8-bit
+ * multidrop) */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_BBN1822 5 /* BBN 1822 */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6 /* 802 (includes all 802
+ * media plus Ethernet
+ * "canonical format")*/
+#define RADIUS_TUNNEL_MEDIUM_TYPE_E163 7 /* E.163 (POTS) */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_E164 8 /* E.164 (SMDS, Frame
+ * Relay, ATM) */
+
+
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/******* packet manipulation support *******/
+
+typedef struct _RADIUS_PACKET RADIUS_PACKET;
+
+/* constructors */
+RADIUS_PACKET *radius_new_request_packet(uint8_t);
+RADIUS_PACKET *radius_new_response_packet(uint8_t, const RADIUS_PACKET *);
+RADIUS_PACKET *radius_convert_packet(const void *, size_t);
+
+/* destructor */
+int radius_delete_packet(RADIUS_PACKET *);
+
+/* accessors - header values */
+uint8_t radius_get_id(const RADIUS_PACKET *);
+void radius_update_id(RADIUS_PACKET * packet);
+void radius_set_id(RADIUS_PACKET *, uint8_t);
+uint8_t radius_get_code(const RADIUS_PACKET *);
+void radius_get_authenticator(const RADIUS_PACKET *, void *);
+void radius_set_request_packet(RADIUS_PACKET *,
+ const RADIUS_PACKET *);
+const RADIUS_PACKET *
+ radius_get_request_packet(const RADIUS_PACKET *);
+int radius_check_response_authenticator(const RADIUS_PACKET *,
+ const char *);
+int radius_check_accounting_request_authenticator(
+ const RADIUS_PACKET *, const char *);
+uint8_t *radius_get_authenticator_retval(const RADIUS_PACKET *);
+uint8_t *radius_get_request_authenticator_retval(const RADIUS_PACKET *);
+void radius_set_accounting_request_authenticator(RADIUS_PACKET *,
+ const char *);
+void radius_set_response_authenticator(RADIUS_PACKET *,
+ const char *);
+uint16_t radius_get_length(const RADIUS_PACKET *);
+const void *radius_get_data(const RADIUS_PACKET *);
+
+int radius_get_raw_attr(const RADIUS_PACKET *, uint8_t, void *,
+ size_t *);
+int radius_get_vs_raw_attr(const RADIUS_PACKET *, uint32_t,
+ uint8_t, void *, size_t *);
+int radius_put_raw_attr(RADIUS_PACKET *, uint8_t, const void *,
+ size_t);
+int radius_put_vs_raw_attr(RADIUS_PACKET *, uint32_t, uint8_t,
+ const void *, size_t);
+int radius_get_raw_attr_ptr(const RADIUS_PACKET *, uint8_t,
+ const void **, size_t *);
+int radius_get_vs_raw_attr_ptr(const RADIUS_PACKET *, uint32_t,
+ uint8_t, const void **, size_t *);
+int radius_get_raw_attr_cat(const RADIUS_PACKET *, uint8_t,
+ void *, size_t *);
+int radius_get_vs_raw_attr_cat(const RADIUS_PACKET *, uint32_t,
+ uint8_t, void *, size_t *);
+int radius_put_raw_attr_cat(RADIUS_PACKET *, uint8_t,
+ const void *, size_t);
+int radius_put_vs_raw_attr_cat(RADIUS_PACKET *, uint32_t, uint8_t,
+ const void *, size_t);
+int radius_set_raw_attr(RADIUS_PACKET *, uint8_t, const void *,
+ size_t);
+int radius_set_vs_raw_attr(RADIUS_PACKET *, uint32_t, uint8_t,
+ const void *, size_t);
+
+int radius_del_attr_all(RADIUS_PACKET *, uint8_t);
+int radius_del_vs_attr_all(RADIUS_PACKET *, uint32_t, uint8_t);
+
+bool radius_has_attr(const RADIUS_PACKET *, uint8_t);
+bool radius_has_vs_attr(const RADIUS_PACKET *, uint32_t, uint8_t);
+
+/* typed attribute accessor (string) */
+int radius_get_string_attr(const RADIUS_PACKET *, uint8_t, char *,
+ size_t);
+int radius_get_vs_string_attr(const RADIUS_PACKET *, uint32_t,
+ uint8_t, char *, size_t);
+int radius_put_string_attr(RADIUS_PACKET *, uint8_t, const char *);
+int radius_put_vs_string_attr(RADIUS_PACKET *, uint32_t, uint8_t,
+ const char *);
+
+/* typed attribute accessor (uint16_t) */
+int radius_get_uint16_attr(const RADIUS_PACKET *,
+ uint8_t, uint16_t *);
+int radius_get_vs_uint16_attr(const RADIUS_PACKET *,
+ uint32_t, uint8_t, uint16_t *);
+int radius_put_uint16_attr(RADIUS_PACKET *,
+ uint8_t, const uint16_t);
+int radius_put_vs_uint16_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const uint16_t);
+int radius_set_uint16_attr(RADIUS_PACKET *,
+ uint8_t, const uint16_t);
+int radius_set_vs_uint16_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const uint16_t);
+
+/* typed attribute accessor (uint32_t) */
+int radius_get_uint32_attr(const RADIUS_PACKET *,
+ uint8_t, uint32_t *);
+int radius_get_vs_uint32_attr(const RADIUS_PACKET *,
+ uint32_t, uint8_t, uint32_t *);
+int radius_put_uint32_attr(RADIUS_PACKET *,
+ uint8_t, const uint32_t);
+int radius_put_vs_uint32_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const uint32_t);
+int radius_set_uint32_attr(RADIUS_PACKET *,
+ uint8_t, const uint32_t);
+int radius_set_vs_uint32_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const uint32_t);
+
+/* typed attribute accessor (uint64_t) */
+int radius_get_uint64_attr(const RADIUS_PACKET *,
+ uint8_t, uint64_t *);
+int radius_get_vs_uint64_attr(const RADIUS_PACKET *,
+ uint32_t, uint8_t, uint64_t *);
+int radius_put_uint64_attr(RADIUS_PACKET *,
+ uint8_t, const uint64_t);
+int radius_put_vs_uint64_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const uint64_t);
+int radius_set_uint64_attr(RADIUS_PACKET *,
+ uint8_t, const uint64_t);
+int radius_set_vs_uint64_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const uint64_t);
+
+/* typed attribute accessor (ipv4) */
+int radius_get_ipv4_attr(const RADIUS_PACKET *,
+ uint8_t, struct in_addr *);
+int radius_get_vs_ipv4_attr(const RADIUS_PACKET *,
+ uint32_t, uint8_t, struct in_addr *);
+int radius_put_ipv4_attr(RADIUS_PACKET *,
+ uint8_t, const struct in_addr);
+int radius_put_vs_ipv4_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const struct in_addr);
+int radius_set_ipv4_attr(RADIUS_PACKET *,
+ uint8_t, const struct in_addr);
+int radius_set_vs_ipv4_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const struct in_addr);
+
+/* typed attribute accessor (ipv6) */
+int radius_get_ipv6_attr(const RADIUS_PACKET *,
+ uint8_t, struct in6_addr *);
+int radius_get_vs_ipv6_attr(const RADIUS_PACKET *,
+ uint32_t, uint8_t, struct in6_addr *);
+int radius_put_ipv6_attr(RADIUS_PACKET *,
+ uint8_t, const struct in6_addr *);
+int radius_put_vs_ipv6_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const struct in6_addr *);
+int radius_set_ipv6_attr(RADIUS_PACKET *,
+ uint8_t, const struct in6_addr *);
+int radius_set_vs_ipv6_attr(RADIUS_PACKET *,
+ uint32_t, uint8_t, const struct in6_addr *);
+
+/* message authenticator */
+int radius_put_message_authenticator(RADIUS_PACKET *,
+ const char *);
+int radius_set_message_authenticator(RADIUS_PACKET *,
+ const char *);
+int radius_check_message_authenticator(RADIUS_PACKET *,
+ const char *);
+
+/* encryption */
+int radius_encrypt_user_password_attr(void *, size_t *,
+ const char *, const void *, const char *);
+int radius_decrypt_user_password_attr(char *, size_t,
+ const void *, size_t, const void *, const char *);
+int radius_encrypt_mppe_key_attr(void *, size_t *,
+ const void *, size_t, const void *, const char *);
+int radius_decrypt_mppe_key_attr(void *, size_t *, const void *,
+ size_t, const void *, const char *);
+
+/* encrypted attribute */
+int radius_get_user_password_attr(const RADIUS_PACKET *,
+ char *, size_t, const char *);
+int radius_put_user_password_attr(RADIUS_PACKET *,
+ const char *, const char *);
+int radius_get_mppe_send_key_attr(const RADIUS_PACKET *, void *,
+ size_t *, const char *);
+int radius_put_mppe_send_key_attr(RADIUS_PACKET *,
+ const void *, size_t, const char *);
+int radius_get_mppe_recv_key_attr(const RADIUS_PACKET *,
+ void *, size_t *, const char *);
+int radius_put_mppe_recv_key_attr(RADIUS_PACKET *, const void *,
+ size_t, const char *);
+
+int radius_get_eap_msk(const RADIUS_PACKET *, void *, size_t *,
+ const char *);
+
+/* helpers */
+RADIUS_PACKET *radius_recvfrom(int, int, struct sockaddr *, socklen_t *);
+int radius_sendto(int, const RADIUS_PACKET *, int flags,
+ const struct sockaddr *, socklen_t);
+RADIUS_PACKET *radius_recv(int, int);
+int radius_send(int, const RADIUS_PACKET *, int);
+RADIUS_PACKET *radius_recvmsg(int, struct msghdr *, int);
+int radius_sendmsg(int, const RADIUS_PACKET *,
+ const struct msghdr *, int);
+
+__END_DECLS
+
+#endif
diff --git a/lib/libradius/radius_attr.c b/lib/libradius/radius_attr.c
new file mode 100644
index 00000000000..e07985ed98b
--- /dev/null
+++ b/lib/libradius/radius_attr.c
@@ -0,0 +1,533 @@
+/* $OpenBSD: radius_attr.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
+
+/*-
+ * Copyright (c) 2009 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <md5.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "radius.h"
+
+#include "radius_local.h"
+
+#define FIND_ATTRIBUTE_BEGIN(constness, redolabel) \
+ constness RADIUS_ATTRIBUTE* attr; \
+ constness RADIUS_ATTRIBUTE* end; \
+ \
+ attr = ATTRS_BEGIN(packet->pdata); \
+ end = ATTRS_END(packet->pdata); \
+ \
+ for (;; ATTRS_ADVANCE(attr)) \
+ { \
+ redolabel \
+ if (attr >= end) \
+ break; \
+ if (attr->type != type) \
+ continue; \
+ {
+
+#define FIND_ATTRIBUTE_END \
+ } }
+
+#define FIND_VS_ATTRIBUTE_BEGIN(constness, redolabel) \
+ constness RADIUS_ATTRIBUTE* attr; \
+ constness RADIUS_ATTRIBUTE* end; \
+ \
+ attr = ATTRS_BEGIN(packet->pdata); \
+ end = ATTRS_END(packet->pdata); \
+ \
+ for (;; ATTRS_ADVANCE(attr)) \
+ { \
+ redolabel \
+ if (attr >= end) \
+ break; \
+ if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC) \
+ continue; \
+ if (attr->vendor != htonl(vendor)) \
+ continue; \
+ if (attr->vtype != vtype) \
+ continue; \
+ {
+
+#define FIND_VS_ATTRIBUTE_END \
+ } }
+
+
+int
+radius_get_raw_attr_ptr(const RADIUS_PACKET * packet, uint8_t type,
+ const void **ptr, size_t * length)
+{
+ FIND_ATTRIBUTE_BEGIN(const,) {
+ *length = attr->length - 2;
+ *ptr = attr->data;
+ return (0);
+ } FIND_ATTRIBUTE_END;
+
+ return (-1);
+}
+
+int
+radius_get_vs_raw_attr_ptr(const RADIUS_PACKET * packet, uint32_t vendor,
+ uint8_t vtype, const void **ptr, size_t * length)
+{
+ FIND_VS_ATTRIBUTE_BEGIN(const,) {
+ *length = attr->vlength - 2;
+ *ptr = attr->vdata;
+ return (0);
+ } FIND_VS_ATTRIBUTE_END;
+
+ return (-1);
+}
+
+int
+radius_get_raw_attr(const RADIUS_PACKET * packet, uint8_t type, void *buf,
+ size_t * length)
+{
+ FIND_ATTRIBUTE_BEGIN(const,) {
+ *length = MINIMUM(attr->length - 2, *length);
+ memcpy(buf, attr->data, *length);
+ return (0);
+ } FIND_ATTRIBUTE_END;
+
+ return (-1);
+}
+
+int
+radius_get_vs_raw_attr(const RADIUS_PACKET * packet, uint32_t vendor,
+ uint8_t vtype, void *buf, size_t * length)
+{
+ FIND_VS_ATTRIBUTE_BEGIN(const,) {
+ *length = MINIMUM(attr->vlength - 2, *length);
+ memcpy(buf, attr->vdata, *length);
+ return (0);
+ } FIND_VS_ATTRIBUTE_END;
+
+ return (-1);
+}
+
+int
+radius_get_raw_attr_cat(const RADIUS_PACKET * packet, uint8_t type, void *buf,
+ size_t * length)
+{
+ size_t off = 0;
+
+ FIND_ATTRIBUTE_BEGIN(const,) {
+ if (buf != NULL) {
+ if (off + attr->length - 2 <= *length)
+ memcpy((char *)buf + off, attr->data,
+ attr->length - 2);
+ else
+ return (-1);
+ }
+ off += attr->length - 2;
+ } FIND_ATTRIBUTE_END;
+
+ *length = off;
+
+ return (0);
+}
+
+int
+radius_get_vs_raw_attr_cat(const RADIUS_PACKET * packet, uint32_t vendor,
+ uint8_t vtype, void *buf, size_t * length)
+{
+ size_t off = 0;
+
+ FIND_VS_ATTRIBUTE_BEGIN(const,) {
+ if (buf != NULL) {
+ if (off + attr->vlength - 2 <= *length)
+ memcpy((char *)buf + off, attr->vdata,
+ attr->vlength - 2);
+ else
+ return (-1);
+ }
+ off += attr->vlength - 2;
+ } FIND_VS_ATTRIBUTE_END;
+
+ *length = off;
+
+ return (0);
+}
+
+int
+radius_put_raw_attr(RADIUS_PACKET * packet, uint8_t type, const void *buf,
+ size_t length)
+{
+ RADIUS_ATTRIBUTE *newattr;
+
+ if (length > 255 - 2)
+ return (-1);
+
+ if (radius_ensure_add_capacity(packet, length + 2) != 0)
+ return (-1);
+
+ newattr = ATTRS_END(packet->pdata);
+ newattr->type = type;
+ newattr->length = length + 2;
+ memcpy(newattr->data, buf, length);
+ packet->pdata->length = htons(radius_get_length(packet) + length + 2);
+
+ return (0);
+}
+
+int
+radius_put_vs_raw_attr(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype,
+ const void *buf, size_t length)
+{
+ RADIUS_ATTRIBUTE *newattr;
+
+ if (length > 255 - 8)
+ return (-1);
+ if ((vendor & 0xff000000U) != 0)
+ return (-1);
+
+ if (radius_ensure_add_capacity(packet, length + 8) != 0)
+ return (-1);
+
+ newattr = ATTRS_END(packet->pdata);
+ newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC;
+ newattr->length = length + 8;
+ newattr->vendor = htonl(vendor);
+ newattr->vtype = vtype;
+ newattr->vlength = length + 2;
+ memcpy(newattr->vdata, buf, length);
+ packet->pdata->length = htons(radius_get_length(packet) + length + 8);
+
+ return (0);
+}
+
+int
+radius_put_raw_attr_cat(RADIUS_PACKET * packet, uint8_t type, const void *buf,
+ size_t length)
+{
+ int off, len0;
+
+ off = 0;
+ while (off < length) {
+ len0 = MINIMUM(length - off, 255 - 2);
+
+ if (radius_put_raw_attr(packet, type, (const char *)buf + off,
+ len0) != 0)
+ return (-1);
+
+ off += len0;
+ }
+
+ return (0);
+}
+
+int
+radius_put_vs_raw_attr_cat(RADIUS_PACKET * packet, uint32_t vendor,
+ uint8_t vtype, const void *buf, size_t length)
+{
+ int off, len0;
+
+ off = 0;
+ while (off < length) {
+ len0 = MINIMUM(length - off, 255 - 8);
+
+ if (radius_put_vs_raw_attr(packet, vendor, vtype,
+ (const char *)buf + off, len0) != 0)
+ return (-1);
+
+ off += len0;
+ }
+
+ return (0);
+}
+
+int
+radius_set_raw_attr(RADIUS_PACKET * packet,
+ uint8_t type, const void *buf, size_t length)
+{
+ FIND_ATTRIBUTE_BEGIN(,) {
+ if (length != attr->length - 2)
+ return (-1);
+ memcpy(attr->data, buf, length);
+ return (0);
+ } FIND_ATTRIBUTE_END;
+
+ return (-1);
+}
+
+int
+radius_set_vs_raw_attr(RADIUS_PACKET * packet,
+ uint32_t vendor, uint8_t vtype, const void *buf, size_t length)
+{
+ FIND_VS_ATTRIBUTE_BEGIN(,) {
+ if (length != attr->vlength - 2)
+ return (-1);
+ memcpy(attr->vdata, buf, length);
+ return (0);
+ } FIND_VS_ATTRIBUTE_END;
+
+ return (-1);
+}
+
+int
+radius_del_attr_all(RADIUS_PACKET * packet, uint8_t type)
+{
+ FIND_ATTRIBUTE_BEGIN(, redo:) {
+ RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
+ packet->pdata->length =
+ htons(ntohs(packet->pdata->length) - attr->length);
+ memmove(attr, next, ((char *)end) - ((char *)next));
+ end = ATTRS_END(packet->pdata);
+ goto redo;
+ } FIND_ATTRIBUTE_END;
+
+ return (0);
+}
+
+int
+radius_del_vs_attr_all(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
+{
+ FIND_VS_ATTRIBUTE_BEGIN(, redo:) {
+ RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
+ packet->pdata->length =
+ htons(ntohs(packet->pdata->length) - attr->length);
+ memmove(attr, next, ((char *)end) - ((char *)next));
+ end = ATTRS_END(packet->pdata);
+ goto redo;
+ } FIND_VS_ATTRIBUTE_END;
+
+ return (0);
+}
+
+bool
+radius_has_attr(const RADIUS_PACKET * packet, uint8_t type)
+{
+ FIND_ATTRIBUTE_BEGIN(const,) {
+ return (true);
+ } FIND_VS_ATTRIBUTE_END;
+
+ return (false);
+}
+
+bool
+radius_has_vs_attr(const RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
+{
+ FIND_VS_ATTRIBUTE_BEGIN(const,) {
+ return (true);
+ } FIND_VS_ATTRIBUTE_END;
+
+ return (false);
+}
+
+int
+radius_get_string_attr(const RADIUS_PACKET * packet, uint8_t type, char *str,
+ size_t len)
+{
+ const void *p;
+ size_t origlen;
+
+ if (radius_get_raw_attr_ptr(packet, type, &p, &origlen) != 0)
+ return (-1);
+ if (memchr(p, 0, origlen) != NULL)
+ return (-1);
+ if (len >= 1) {
+ len = MINIMUM(origlen, len - 1);
+ memcpy(str, (const char *)p, len);
+ str[len] = '\0';
+ }
+ return (0);
+}
+
+int
+radius_get_vs_string_attr(const RADIUS_PACKET * packet,
+ uint32_t vendor, uint8_t vtype, char *str, size_t len)
+{
+ const void *p;
+ size_t origlen;
+
+ if (radius_get_vs_raw_attr_ptr(packet,
+ vendor, vtype, &p, &origlen) != 0)
+ return (-1);
+ if (memchr(p, 0, origlen) != NULL)
+ return (-1);
+ if (len >= 1) {
+ len = MINIMUM(origlen, len - 1);
+ memcpy(str, (const char *)p, len);
+ str[len] = '\0';
+ }
+
+ return (0);
+}
+
+int
+radius_put_string_attr(RADIUS_PACKET * packet, uint8_t type, const char *str)
+{
+ return radius_put_raw_attr(packet, type, str, strlen(str));
+}
+
+int
+radius_put_vs_string_attr(RADIUS_PACKET * packet,
+ uint32_t vendor, uint8_t vtype, const char *str)
+{
+ return radius_put_vs_raw_attr(packet, vendor, vtype, str, strlen(str));
+}
+
+
+#define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ftname, tname, hton, ntoh) \
+int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet, \
+ uint8_t type, tname *val) \
+{ \
+ const void *p; \
+ tname nval; \
+ size_t len; \
+ \
+ if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0) \
+ return (-1); \
+ if (len != sizeof(tname)) \
+ return (-1); \
+ memcpy(&nval, p, sizeof(tname)); \
+ *val = ntoh(nval); \
+ return (0); \
+} \
+ \
+int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet, \
+ uint32_t vendor, uint8_t vtype, tname *val) \
+{ \
+ const void *p; \
+ tname nval; \
+ size_t len; \
+ \
+ if (radius_get_vs_raw_attr_ptr(packet, \
+ vendor, vtype, &p, &len) != 0) \
+ return (-1); \
+ if (len != sizeof(tname)) \
+ return (-1); \
+ memcpy(&nval, p, sizeof(tname)); \
+ *val = ntoh(nval); \
+ return (0); \
+} \
+ \
+int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet, \
+ uint8_t type, tname val) \
+{ \
+ tname nval; \
+ \
+ nval = hton(val); \
+ return radius_put_raw_attr(packet, type, &nval, sizeof(tname)); \
+} \
+ \
+int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet, \
+ uint32_t vendor, uint8_t vtype, tname val) \
+{ \
+ tname nval; \
+ \
+ nval = hton(val); \
+ return radius_put_vs_raw_attr(packet, vendor, vtype, \
+ &nval, sizeof(tname)); \
+} \
+ \
+int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet, \
+ uint8_t type, tname val) \
+{ \
+ tname nval; \
+ \
+ nval = hton(val); \
+ return radius_set_raw_attr(packet, type, &nval, sizeof(tname)); \
+} \
+ \
+int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet, \
+ uint32_t vendor, uint8_t vtype, tname val) \
+{ \
+ tname nval; \
+ \
+ nval = hton(val); \
+ return radius_set_vs_raw_attr(packet, vendor, vtype, \
+ &nval, sizeof(tname)); \
+}
+
+#define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ftname, tname) \
+int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet, \
+ uint8_t type, tname *val) \
+{ \
+ const void *p; \
+ size_t len; \
+ \
+ if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0) \
+ return (-1); \
+ if (len != sizeof(tname)) \
+ return (-1); \
+ memcpy(val, p, sizeof(tname)); \
+ return (0); \
+} \
+ \
+int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet, \
+ uint32_t vendor, uint8_t vtype, tname *val) \
+{ \
+ const void *p; \
+ size_t len; \
+ \
+ if (radius_get_vs_raw_attr_ptr(packet, \
+ vendor, vtype, &p, &len) != 0) \
+ return (-1); \
+ if (len != sizeof(tname)) \
+ return (-1); \
+ memcpy(val, p, sizeof(tname)); \
+ return (0); \
+} \
+ \
+int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet, \
+ uint8_t type, const tname *val) \
+{ \
+ return radius_put_raw_attr(packet, type, val, sizeof(tname)); \
+} \
+ \
+int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet, \
+ uint32_t vendor, uint8_t vtype, const tname *val) \
+{ \
+ return radius_put_vs_raw_attr(packet, vendor, vtype, \
+ val, sizeof(tname)); \
+} \
+ \
+int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet, \
+ uint8_t type, const tname *val) \
+{ \
+ return radius_set_raw_attr(packet, type, val, sizeof(tname)); \
+} \
+ \
+int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet, \
+ uint32_t vendor, uint8_t vtype, const tname *val) \
+{ \
+ return radius_set_vs_raw_attr(packet, vendor, vtype, \
+ val, sizeof(tname)); \
+}
+
+DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint16, uint16_t, htons, ntohs)
+DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint32, uint32_t, htonl, ntohl)
+DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint64, uint64_t, htobe64, betoh64)
+DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ipv4, struct in_addr,,)
+DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ipv6, struct in6_addr)
diff --git a/lib/libradius/radius_eapmsk.c b/lib/libradius/radius_eapmsk.c
new file mode 100644
index 00000000000..0cb69ddaee4
--- /dev/null
+++ b/lib/libradius/radius_eapmsk.c
@@ -0,0 +1,78 @@
+/* $OpenBSD: radius_eapmsk.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
+
+/*-
+ * Copyright (c) 2013 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/md5.h>
+
+#include "radius.h"
+
+#include "radius_local.h"
+
+int
+radius_get_eap_msk(const RADIUS_PACKET * packet, void *buf, size_t * len,
+ const char *secret)
+{
+ /*
+ * Unfortunately, the way to pass EAP MSK/EMSK over RADIUS
+ * is not standardized.
+ */
+ uint8_t buf0[256];
+ uint8_t buf1[256];
+ size_t len0, len1;
+
+ /*
+ * EAP MSK via MPPE keys
+ *
+ * MSK = MPPE-Recv-Key + MPPE-Send-Key + 32byte zeros
+ * http://msdn.microsoft.com/en-us/library/cc224635.aspx
+ */
+ len0 = sizeof(buf0);
+ len1 = sizeof(buf1);
+ if (radius_get_mppe_recv_key_attr(packet, buf0, &len0, secret) == 0 &&
+ radius_get_mppe_send_key_attr(packet, buf1, &len1, secret) == 0) {
+ if (len0 < 16 || len1 < 16)
+ return (-1);
+ if (*len < 64)
+ return (-1);
+ memcpy(buf, buf0, 16);
+ memcpy(((char *)buf) + 16, buf1, 16);
+ memset(((char *)buf) + 32, 0, 32);
+ *len = 64;
+ return (0);
+ }
+
+ return (-1);
+}
diff --git a/lib/libradius/radius_local.h b/lib/libradius/radius_local.h
new file mode 100644
index 00000000000..cd2dfe4af77
--- /dev/null
+++ b/lib/libradius/radius_local.h
@@ -0,0 +1,81 @@
+/* $OpenBSD: radius_local.h,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
+
+/*-
+ * Copyright (c) 2009 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef RADIUS_LOCAL_H
+#define RADIUS_LOCAL_H
+
+#ifndef countof
+#define countof(x) (sizeof(x)/sizeof((x)[0]))
+#endif
+
+typedef struct _RADIUS_PACKET_DATA {
+ uint8_t code;
+ uint8_t id;
+ uint16_t length;
+ uint8_t authenticator[16];
+ char attributes[0];
+} RADIUS_PACKET_DATA;
+#pragma pack(1)
+typedef struct _RADIUS_ATTRIBUTE {
+ uint8_t type;
+ uint8_t length;
+ char data[0];
+ uint32_t vendor;
+ uint8_t vtype;
+ uint8_t vlength;
+ char vdata[0];
+} RADIUS_ATTRIBUTE;
+#pragma pack()
+
+struct _RADIUS_PACKET {
+ RADIUS_PACKET_DATA *pdata;
+ size_t capacity;
+ const RADIUS_PACKET *request;
+};
+#define RADIUS_PACKET_CAPACITY_INITIAL 64
+#define RADIUS_PACKET_CAPACITY_INCREMENT 64
+
+#define ATTRS_BEGIN(pdata) ((RADIUS_ATTRIBUTE*)pdata->attributes)
+
+#define ATTRS_END(pdata) \
+ ((RADIUS_ATTRIBUTE*)(((char*)pdata) + ntohs(pdata->length)))
+
+#define ATTRS_NEXT(x) ((RADIUS_ATTRIBUTE*)(((char*)x) + x->length))
+
+/*
+ * must be expression rather than statement
+ * to be used in third expression of for statement.
+ */
+#define ATTRS_ADVANCE(x) (x = ATTRS_NEXT(x))
+
+int radius_ensure_add_capacity(RADIUS_PACKET * packet, size_t capacity);
+
+#define ROUNDUP(a, b) ((((a) + (b) - 1) / (b)) * (b))
+#define MINIMUM(a, b) (((a) < (b))? (a) : (b))
+
+#endif /* RADIUS_LOCAL_H */
diff --git a/lib/libradius/radius_mppe.c b/lib/libradius/radius_mppe.c
new file mode 100644
index 00000000000..cee79a9a482
--- /dev/null
+++ b/lib/libradius/radius_mppe.c
@@ -0,0 +1,188 @@
+/* $OpenBSD: radius_mppe.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
+
+/*-
+ * Copyright (c) 2013 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/md5.h>
+
+#include "radius.h"
+
+#include "radius_local.h"
+
+int
+radius_encrypt_mppe_key_attr(void *cipher, size_t * clen, const void *plain,
+ size_t plen, const void *ra, const char *secret)
+{
+ size_t slen = strlen(secret);
+ uint8_t b[16], plain0[256], *p, *c;
+ size_t off;
+ MD5_CTX ctx;
+ unsigned int i;
+ uint16_t salt;
+
+ if (plen > 239)
+ return (-1);
+ if (*clen < ROUNDUP(plen + 1, 16) + 2)
+ return (-1);
+
+ salt = arc4random();
+ plain0[0] = plen;
+ memcpy(plain0 + 1, plain, plen);
+ memset(plain0 + 1 + plen, 0, ROUNDUP(plen + 1, 16) - (plen + 1));
+
+ *clen = ROUNDUP(plen + 1, 16) + 2;
+ memcpy(cipher, &salt, 2);
+ for (off = 0; off < *clen - 2; off += 16) {
+ c = ((uint8_t *)cipher) + 2 + off;
+ p = ((uint8_t *)plain0) + off;
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, secret, slen);
+ if (off == 0) {
+ MD5_Update(&ctx, ra, 16);
+ MD5_Update(&ctx, cipher, 2);
+ } else
+ MD5_Update(&ctx, c - 16, 16);
+ MD5_Final(b, &ctx);
+ for (i = 0; i < 16; i++)
+ c[i] = p[i] ^ b[i];
+ }
+
+ return (0);
+}
+
+int
+radius_decrypt_mppe_key_attr(void *plain, size_t * plen, const void *cipher,
+ size_t clen, const void *ra, const char *secret)
+{
+ size_t slen = strlen(secret);
+ uint8_t b[16], plain0[256], *p, *c;
+ size_t off;
+ MD5_CTX ctx;
+ unsigned int i;
+
+ if (clen < 18 || clen > 255)
+ return (-1);
+ if ((clen - 2) % 16 != 0)
+ return (-1);
+ if (*plen < clen - 3)
+ return (-1);
+
+ for (off = 0; off < clen - 2; off += 16) {
+ c = ((uint8_t *)cipher) + 2 + off;
+ p = ((uint8_t *)plain0) + off;
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, secret, slen);
+ if (off == 0) {
+ MD5_Update(&ctx, ra, 16);
+ MD5_Update(&ctx, cipher, 2);
+ } else
+ MD5_Update(&ctx, c - 16, 16);
+ MD5_Final(b, &ctx);
+ for (i = 0; i < 16; i++)
+ p[i] = c[i] ^ b[i];
+ }
+
+ if (plain0[0] > clen - 3)
+ return (-1);
+ *plen = plain0[0];
+ memcpy(plain, plain0 + 1, *plen);
+
+ return (0);
+}
+
+static int
+radius_get_mppe_key_attr(const RADIUS_PACKET * packet, uint8_t vtype,
+ void *buf, size_t * len, const char *secret)
+{
+ uint8_t cipher[256];
+ size_t clen = sizeof(cipher);
+
+ if (radius_get_vs_raw_attr(packet, RADIUS_VENDOR_MICROSOFT, vtype,
+ cipher, &clen) != 0)
+ return (-1);
+ if (radius_decrypt_mppe_key_attr(buf, len, cipher, clen,
+ radius_get_request_authenticator_retval(packet), secret) != 0)
+ return (-1);
+ return (0);
+}
+
+static int
+radius_put_mppe_key_attr(RADIUS_PACKET * packet, uint8_t vtype,
+ const void *buf, size_t len, const char *secret)
+{
+ uint8_t cipher[256];
+ size_t clen = sizeof(cipher);
+
+ if (radius_encrypt_mppe_key_attr(cipher, &clen, buf, len,
+ radius_get_request_authenticator_retval(packet), secret) != 0)
+ return (-1);
+ if (radius_put_vs_raw_attr(packet, RADIUS_VENDOR_MICROSOFT, vtype,
+ cipher, clen) != 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+radius_get_mppe_send_key_attr(const RADIUS_PACKET * packet, void *buf,
+ size_t * len, const char *secret)
+{
+ return (radius_get_mppe_key_attr(packet, RADIUS_VTYPE_MPPE_SEND_KEY,
+ buf, len, secret));
+}
+
+int
+radius_put_mppe_send_key_attr(RADIUS_PACKET * packet, const void *buf,
+ size_t len, const char *secret)
+{
+ return (radius_put_mppe_key_attr(packet, RADIUS_VTYPE_MPPE_SEND_KEY,
+ buf, len, secret));
+}
+
+int
+radius_get_mppe_recv_key_attr(const RADIUS_PACKET * packet, void *buf,
+ size_t * len, const char *secret)
+{
+ return (radius_get_mppe_key_attr(packet, RADIUS_VTYPE_MPPE_RECV_KEY,
+ buf, len, secret));
+}
+
+int
+radius_put_mppe_recv_key_attr(RADIUS_PACKET * packet, const void *buf,
+ size_t len, const char *secret)
+{
+ return (radius_put_mppe_key_attr(packet, RADIUS_VTYPE_MPPE_RECV_KEY,
+ buf, len, secret));
+}
diff --git a/lib/libradius/radius_msgauth.c b/lib/libradius/radius_msgauth.c
new file mode 100644
index 00000000000..68123f9e1a2
--- /dev/null
+++ b/lib/libradius/radius_msgauth.c
@@ -0,0 +1,132 @@
+/* $OpenBSD: radius_msgauth.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
+
+/*-
+ * Copyright (c) 2009 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/hmac.h>
+
+#include "radius.h"
+
+#include "radius_local.h"
+
+static void
+radius_calc_message_authenticator(RADIUS_PACKET * packet, const char *secret,
+ void *ma)
+{
+ const RADIUS_ATTRIBUTE *attr;
+ const RADIUS_ATTRIBUTE *end;
+ u_char zero16[16];
+ HMAC_CTX ctx;
+ int mdlen;
+
+ memset(zero16, 0, sizeof(zero16));
+
+ HMAC_Init(&ctx, secret, strlen(secret), EVP_md5());
+
+ /*
+ * Traverse the radius packet.
+ */
+ if (packet->request != NULL) {
+ HMAC_Update(&ctx, (const u_char *)packet->pdata, 4);
+ HMAC_Update(&ctx, (unsigned char *)packet->request->pdata
+ ->authenticator, 16);
+ } else {
+ HMAC_Update(&ctx, (const u_char *)packet->pdata,
+ sizeof(RADIUS_PACKET_DATA));
+ }
+
+ attr = ATTRS_BEGIN(packet->pdata);
+ end = ATTRS_END(packet->pdata);
+
+ for (; attr < end; ATTRS_ADVANCE(attr)) {
+ if (attr->type == RADIUS_TYPE_MESSAGE_AUTHENTICATOR) {
+ HMAC_Update(&ctx, (u_char *)attr, 2);
+ HMAC_Update(&ctx, (u_char *)zero16, sizeof(zero16));
+ } else
+ HMAC_Update(&ctx, (u_char *)attr, (int) attr->length);
+ }
+
+ HMAC_Final(&ctx, (u_char *)ma, &mdlen);
+
+ HMAC_cleanup(&ctx);
+}
+
+int
+radius_put_message_authenticator(RADIUS_PACKET * packet, const char *secret)
+{
+ u_char ma[16];
+
+ /*
+ * It is not required to initialize ma
+ * because content of Message-Authenticator attribute is assumed zero
+ * during calculation.
+ */
+ if (radius_put_raw_attr(packet, RADIUS_TYPE_MESSAGE_AUTHENTICATOR,
+ ma, sizeof(ma)) != 0)
+ return (-1);
+
+ return (radius_set_message_authenticator(packet, secret));
+}
+
+int
+radius_set_message_authenticator(RADIUS_PACKET * packet, const char *secret)
+{
+ u_char ma[16];
+
+ radius_calc_message_authenticator(packet, secret, ma);
+
+ return (radius_set_raw_attr(packet, RADIUS_TYPE_MESSAGE_AUTHENTICATOR,
+ ma, sizeof(ma)));
+}
+
+int
+radius_check_message_authenticator(RADIUS_PACKET * packet, const char *secret)
+{
+ int rval;
+ size_t len;
+ u_char ma0[16], ma1[16];
+
+ radius_calc_message_authenticator(packet, secret, ma0);
+
+ len = sizeof(ma1);
+ if ((rval = radius_get_raw_attr(packet,
+ RADIUS_TYPE_MESSAGE_AUTHENTICATOR, ma1, &len)) != 0)
+ return (rval);
+
+ if (len != sizeof(ma1))
+ return (-1);
+
+ return (memcmp(ma0, ma1, sizeof(ma1)));
+}
diff --git a/lib/libradius/radius_userpass.c b/lib/libradius/radius_userpass.c
new file mode 100644
index 00000000000..08bbc3d1a71
--- /dev/null
+++ b/lib/libradius/radius_userpass.c
@@ -0,0 +1,153 @@
+/* $OpenBSD: radius_userpass.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
+
+/*-
+ * Copyright (c) 2013 Internet Initiative Japan Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/md5.h>
+
+#include "radius.h"
+
+#include "radius_local.h"
+
+int
+radius_encrypt_user_password_attr(void *cipher, size_t * clen,
+ const char *plain, const void *ra, const char *secret)
+{
+ size_t plen = strlen(plain);
+ size_t slen = strlen(secret);
+ char b[16], p[16], *c;
+ size_t off;
+ MD5_CTX ctx;
+ unsigned int i;
+
+ if (*clen < ROUNDUP(plen, 16))
+ return (-1);
+
+ for (off = 0; off < plen; off += sizeof(p)) {
+ c = ((char *)cipher) + off;
+ memset(p, 0, sizeof(p));
+ strncpy(p, plain + off, sizeof(p)); /* not strlcpy() */
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, secret, slen);
+ if (off == 0)
+ MD5_Update(&ctx, ra, 16);
+ else
+ MD5_Update(&ctx, c - 16, 16);
+ MD5_Final(b, &ctx);
+ for (i = 0; i < 16; i++)
+ c[i] = p[i] ^ b[i];
+ }
+
+ *clen = off;
+ return (0);
+}
+
+int
+radius_decrypt_user_password_attr(char *plain, size_t plen, const void *cipher,
+ size_t clen, const void *ra, const char *secret)
+{
+ size_t slen = strlen(secret);
+ char b[16];
+ size_t off;
+ char *p, *c;
+ MD5_CTX ctx;
+ unsigned int i;
+
+ if (clen % 16 != 0)
+ return (-1);
+ if (plen < clen + 1)
+ return (-1);
+
+ for (off = 0; off < clen; off += 16) {
+ c = ((char *)cipher) + off;
+ p = plain + off;
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, secret, slen);
+ if (off == 0)
+ MD5_Update(&ctx, ra, 16);
+ else
+ MD5_Update(&ctx, c - 16, 16);
+ MD5_Final(b, &ctx);
+ for (i = 0; i < 16; i++)
+ p[i] = c[i] ^ b[i];
+ }
+
+ p = memchr(plain, '\0', off);
+ if (p == NULL)
+ plain[off] = '\0';
+ else {
+ /* memcspn() does not exist... */
+ for (p++; p < plain + off; p++) {
+ if (*p != '\0')
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int
+radius_get_user_password_attr(const RADIUS_PACKET * packet, char *buf,
+ size_t len, const char *secret)
+{
+ char cipher[256];
+ size_t clen = sizeof(cipher);
+
+ if (radius_get_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher,
+ &clen) != 0)
+ return (-1);
+ if (radius_decrypt_user_password_attr(buf, len, cipher, clen,
+ radius_get_authenticator_retval(packet), secret) != 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+radius_put_user_password_attr(RADIUS_PACKET * packet, const char *buf,
+ const char *secret)
+{
+ char cipher[256];
+ size_t clen = sizeof(cipher);
+
+ if (radius_encrypt_user_password_attr(cipher, &clen, buf,
+ radius_get_authenticator_retval(packet), secret) != 0)
+ return (-1);
+ if (radius_put_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher,
+ clen) != 0)
+ return (-1);
+
+ return (0);
+}
diff --git a/lib/libradius/shlib_version b/lib/libradius/shlib_version
new file mode 100644
index 00000000000..1edea46de91
--- /dev/null
+++ b/lib/libradius/shlib_version
@@ -0,0 +1,2 @@
+major=1
+minor=0
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)
diff --git a/share/mk/bsd.README b/share/mk/bsd.README
index 5f3444f4fbe..10b91e91f4a 100644
--- a/share/mk/bsd.README
+++ b/share/mk/bsd.README
@@ -1,4 +1,4 @@
-# $OpenBSD: bsd.README,v 1.59 2014/10/31 13:46:17 jsing Exp $
+# $OpenBSD: bsd.README,v 1.60 2015/07/20 23:52:29 yasuoka Exp $
# $NetBSD: bsd.README,v 1.17 1996/04/13 02:08:08 thorpej Exp $
# @(#)bsd.README 5.1 (Berkeley) 5/11/90
@@ -348,6 +348,7 @@ DPADD Additional dependencies for the program. Usually used for
LIBM /usr/lib/libm.a
LIBMENU /usr/lib/libmenu.a
LIBMENUW /usr/lib/libmenuw.a
+ LIBRADIUS /usr/lib/libradius.a
LIBOLDCURSES /usr/lib/libocurses.a
LIBOSSAUDIO /usr/lib/libossaudio.a
LIBPANEL /usr/lib/libpanel.a
diff --git a/share/mk/bsd.prog.mk b/share/mk/bsd.prog.mk
index 835e032b102..d36787ae6ca 100644
--- a/share/mk/bsd.prog.mk
+++ b/share/mk/bsd.prog.mk
@@ -1,4 +1,4 @@
-# $OpenBSD: bsd.prog.mk,v 1.67 2015/05/14 02:56:01 jsg Exp $
+# $OpenBSD: bsd.prog.mk,v 1.68 2015/07/20 23:52:29 yasuoka Exp $
# $NetBSD: bsd.prog.mk,v 1.55 1996/04/08 21:19:26 jtc Exp $
# @(#)bsd.prog.mk 5.26 (Berkeley) 6/25/91
@@ -42,6 +42,7 @@ LIBL?= ${DESTDIR}/usr/lib/libl.a
LIBM?= ${DESTDIR}/usr/lib/libm.a
LIBMENU?= ${DESTDIR}/usr/lib/libmenu.a
LIBMENUW?= ${DESTDIR}/usr/lib/libmenuw.a
+LIBRADIUS?= ${DESTDIR}/usr/lib/libradius.a
LIBOLDCURSES?= ${DESTDIR}/usr/lib/libocurses.a
LIBOSSAUDIO?= ${DESTDIR}/usr/lib/libossaudio.a
LIBPANEL?= ${DESTDIR}/usr/lib/libpanel.a