Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • rist/librist
  • alejagapatrick-spec/librist
  • Frolicking/librist
  • gpeskens/librist
  • alexpokotilo/librist
  • jgh-/librist
  • salaopen/librist
  • dholroyd/librist
  • kjnk/librist
  • davemevans/librist
  • ian.hall2/librist
  • dprestegard/librist
  • ferrantelucas1997/librist
  • dslobodskoy/librist
  • Gyan/librist
  • bkeane/librist
  • quink/librist
  • aconverse/librist
  • longervision/librist
  • Sikabo/librist
  • jonasohland/librist
  • kevmo314/librist
  • lelegard/librist
  • tmatth/librist
  • pkviet/librist
  • altanai/librist
  • alexandre-janniaux/librist
  • seannamiller19/librist
  • oviano2/librist
  • sthibaul/librist
  • robUx4/librist
  • jcnelson0126/librist
  • al1/librist
  • 1480c1/librist
  • edgehew/librist
  • manueldev/librist
  • fennewald/librist
  • 1div0/librist
  • qyliss/librist
  • Yannick_Le_Roux/librist
  • paparodeo/librist
41 results
Show changes
Commits on Source (188)
Showing
with 820 additions and 1467 deletions
......@@ -57,4 +57,4 @@ compile_commands.json
.ionide
# End of https://www.toptal.com/developers/gitignore/api/c,meson,visualstudiocode
.cache
......@@ -2,7 +2,6 @@ stages:
- build
- analyze
- test
- test2
.ubuntu-amd64-bionic:
image: registry.videolan.org/librist-ubuntu-bionic:20200501213126
......@@ -11,6 +10,13 @@ stages:
- docker
- amd64
.ubuntu-amd64-jammy:
image: registry.videolan.org/libplacebo-ubuntu-jammy:20230730213642
stage: build
tags:
- docker
- amd64
.debian-amd64-common:
image: registry.videolan.org/dav1d-debian-unstable:20200306210534
stage: build
......@@ -27,10 +33,6 @@ build-ubuntu:
script:
- meson build --buildtype release --werror -Duse_tun=true
- ninja -C build
artifacts:
paths:
- build
expire_in: 24 hours
build-win64:
extends: .debian-amd64-common
......@@ -49,33 +51,6 @@ build-win64:
- build
expire_in: 24 hours
build-macos:
stage: build
tags:
- macos
script:
- meson build --buildtype release
--werror
-Ddefault_library=both
-Duse_mbedtls=false
- ninja -C build
build-freebsd:
stage: build
only: [branches@rist/librist]
tags:
- freebsd
script:
- LDFLAGS="-L/usr/local/lib" CFLAGS="-I/usr/local/include" meson build --buildtype release --werror
- ninja -C build
artifacts:
paths:
- build
expire_in: 24 hours
analyze-ubuntu:
stage: analyze
extends:
......@@ -89,9 +64,10 @@ analyze-ubuntu:
test-ubuntu:
stage: test
extends:
- .ubuntu-amd64-bionic
- .ubuntu-amd64-jammy
needs: ["build-ubuntu"]
script:
- meson build --buildtype release -Db_sanitize=address,undefined
- cd build && meson test --print-errorlogs
dependencies:
- build-ubuntu
......@@ -100,51 +76,3 @@ test-ubuntu:
paths:
- build/meson-logs/testlog.txt
test-win64:
stage: test2
extends: .debian-amd64-common
needs: ["build-win64", "test-ubuntu"]
script:
- cd build && meson test --suite unicast --print-errorlogs
dependencies:
- build-win64
artifacts:
when: on_failure
paths:
- build/meson-logs/testlog.txt
test-macos:
stage: test
tags:
- macos
needs: ["build-macos"]
script:
- meson build --buildtype release
--werror
-Ddefault_library=both
-Duse_mbedtls=false
- cd build && MESON_TESTTHREADS=4 meson test --suite unicast --print-errorlogs --timeout-multiplier=10
dependencies:
- build-macos
artifacts:
when: on_failure
paths:
- build/meson-logs/testlog.txt
test-freebsd:
stage: test
only: [branches@rist/librist]
tags:
- freebsd
needs: ["build-freebsd"]
script:
- cd build && meson test --suite unicast --print-errorlogs
dependencies:
- build-freebsd
artifacts:
when: on_failure
paths:
- build/meson-logs/testlog.txt
![librist logo](docs/librist_logo.png)
# librist
# libRIST
A library that can be used to easily add the RIST protocol to your application.
......@@ -12,7 +12,7 @@ This project is partially funded by the SipRadius LLC.
## Goal and Features
The goal of this project is to provide a rist library for **most platforms**.
The goal of this project is to provide a RIST library for **most platforms**.
It supports all features from the TR-06-1 and most of the features of TR-06-2.
......@@ -22,7 +22,7 @@ None. This library has no external runtime dependencies on any OS other than nor
## License
**librist** is released under a very liberal license, a contrario from the other VideoLAN projects, so that it can be embedded anywhere, including non-open-source software; or even drivers, to allow the creation of hybrid decoders.
**libRIST** is released under a very liberal license, a contrario from the other VideoLAN projects, so that it can be embedded anywhere, including non-open-source software; or even drivers, to allow the creation of hybrid decoders.
The reasoning behind this decision is the same as for libvorbis, see [RMS on vorbis](https://lwn.net/2001/0301/a/rms-ov-license.php3).
......@@ -97,6 +97,11 @@ The [VideoLAN Code of Conduct](https://wiki.videolan.org/CoC) applies to this pr
1. Simply do a `docker build` on the Dockerfile in the 'common' subdirectory
# Install with HomeBrew on MacOS
1. Assuming HomeBrew is already setup, enter "brew install librist" in a terminal.
2. libRIST will be installed in /usr/local, except on Arm64-based Macs, where the root is /opt/homebrew. Make sure to have the bin folder (/usr/local/bin or /opt/homebrew/bin, respectively) in your PATH.
# Support
This project is partially funded by SipRadius LLC.
......@@ -106,11 +111,15 @@ This company can provide support and integration help, should you need it.
# FAQ
## Why do you not improve srt rather than starting a new project?
## Why do you not improve SRT rather than starting a new project?
- Although SRT provides a similar solution, it is the result of the vision and design of a single company, Haivision, and it is maintained almost exclusively by Haivision paid developers. RIST on the other hand, was the collective design work of a large group of experts (companies) that have been providing packet recovery services for many years. From its conception, RIST has been based on clear and open standards. Just from SipRadius installations alone, top tier broadcasters have over 4000 RIST point-to-point links running 24/7h.
Here is a table of comparison of the two protocols:
- Although SRT provides a similar solution, it is the result of the vision and design of a single company. librist on the other hand, was the collective design work of a large group of experts (companies) that have been providing packet recovery services for many years. From its conception, rist has been based on clear and open standards.
![librist logo](docs/RIST_vs_SRT.png)
## Is librist an acronym?
## Is libRIST an acronym?
- Yes, libRIST stands for Library - Reliable Internet Stream Transport
......
......@@ -18,6 +18,7 @@ RUN git clone https://code.videolan.org/rist/librist.git && \
FROM ubuntu:focal as release
COPY --from=builder /librist/build/tools/rist2rist /usr/bin/
COPY --from=builder /librist/build/tools/udp2udp /usr/bin/
COPY --from=builder /librist/build/tools/ristreceiver /usr/bin/
COPY --from=builder /librist/build/tools/ristsender /usr/bin/
COPY --from=builder /librist/build/tools/ristsrppasswd /usr/bin/
[binaries]
c = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang'
cpp = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++'
ar = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar'
as = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-as'
ranlib = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib'
ld = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-link'
strip = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip'
pkgconfig = 'false'
[properties]
sys_root = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot'
[host_machine]
system = 'android'
cpu_family = 'arm'
cpu = 'aarch64'
endian = 'little'
[binaries]
c = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-android21-clang'
cpp = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-android21-clang++'
ar = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar'
as = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-as'
ranlib = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib'
ld = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-link'
strip = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip'
pkgconfig = 'false'
[properties]
sys_root = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot'
[host_machine]
system = 'android'
cpu_family = 'arm'
cpu = 'armv7a'
endian = 'little'
[binaries]
c = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android21-clang'
cpp = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android21-clang++'
ar = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar'
as = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-as'
ranlib = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib'
ld = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-link'
strip = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip'
pkgconfig = 'false'
[properties]
sys_root = '/usr/lib/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot'
[host_machine]
system = 'android'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
/*
Copyright (c) 2013, Kenneth MacKay
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 "ifaddrs.h"
#include <errno.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
typedef struct NetlinkList {
struct NetlinkList *m_next;
struct nlmsghdr *m_data;
unsigned int m_size;
} NetlinkList;
static int netlink_socket(void) {
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (l_socket < 0) {
return -1;
}
struct sockaddr_nl l_addr;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
if (bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) {
close(l_socket);
return -1;
}
return l_socket;
}
static int netlink_send(int p_socket, int p_request) {
struct {
struct nlmsghdr m_hdr;
struct rtgenmsg m_msg;
} l_data;
memset(&l_data, 0, sizeof(l_data));
l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
l_data.m_hdr.nlmsg_type = p_request;
l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
l_data.m_hdr.nlmsg_pid = 0;
l_data.m_hdr.nlmsg_seq = p_socket;
l_data.m_msg.rtgen_family = AF_UNSPEC;
struct sockaddr_nl l_addr;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0,
(struct sockaddr *)&l_addr, sizeof(l_addr)));
}
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) {
struct msghdr l_msg;
struct iovec l_iov = {p_buffer, p_len};
struct sockaddr_nl l_addr;
for (;;) {
l_msg.msg_name = (void *)&l_addr;
l_msg.msg_namelen = sizeof(l_addr);
l_msg.msg_iov = &l_iov;
l_msg.msg_iovlen = 1;
l_msg.msg_control = NULL;
l_msg.msg_controllen = 0;
l_msg.msg_flags = 0;
int l_result = recvmsg(p_socket, &l_msg, 0);
if (l_result < 0) {
if (errno == EINTR) {
continue;
}
return -2;
}
if (l_msg.msg_flags & MSG_TRUNC) { // buffer was too small
return -1;
}
return l_result;
}
}
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size,
int *p_done) {
size_t l_size = 4096;
void *l_buffer = NULL;
for (;;) {
free(l_buffer);
l_buffer = malloc(l_size);
if (l_buffer == NULL) {
return NULL;
}
int l_read = netlink_recv(p_socket, l_buffer, l_size);
*p_size = l_read;
if (l_read == -2) {
free(l_buffer);
return NULL;
}
if (l_read >= 0) {
pid_t l_pid = getpid();
struct nlmsghdr *l_hdr;
for (l_hdr = (struct nlmsghdr *)l_buffer;
NLMSG_OK(l_hdr, (unsigned int)l_read);
l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) {
if ((pid_t)l_hdr->nlmsg_pid != l_pid ||
(int)l_hdr->nlmsg_seq != p_socket) {
continue;
}
if (l_hdr->nlmsg_type == NLMSG_DONE) {
*p_done = 1;
break;
}
if (l_hdr->nlmsg_type == NLMSG_ERROR) {
free(l_buffer);
return NULL;
}
}
return l_buffer;
}
l_size *= 2;
}
}
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) {
NetlinkList *l_item = malloc(sizeof(NetlinkList));
if (l_item == NULL) {
return NULL;
}
l_item->m_next = NULL;
l_item->m_data = p_data;
l_item->m_size = p_size;
return l_item;
}
static void freeResultList(NetlinkList *p_list) {
NetlinkList *l_cur;
while (p_list) {
l_cur = p_list;
p_list = p_list->m_next;
free(l_cur->m_data);
free(l_cur);
}
}
static NetlinkList *getResultList(int p_socket, int p_request) {
if (netlink_send(p_socket, p_request) < 0) {
return NULL;
}
NetlinkList *l_list = NULL;
NetlinkList *l_end = NULL;
int l_size;
int l_done = 0;
while (!l_done) {
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
if (!l_hdr) { // error
freeResultList(l_list);
return NULL;
}
NetlinkList *l_item = newListItem(l_hdr, l_size);
if (!l_item) {
freeResultList(l_list);
return NULL;
}
if (!l_list) {
l_list = l_item;
} else {
l_end->m_next = l_item;
}
l_end = l_item;
}
return l_list;
}
static size_t maxSize(size_t a, size_t b) { return (a > b ? a : b); }
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) {
switch (p_family) {
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_PACKET:
return maxSize(sizeof(struct sockaddr_ll),
offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
default:
return maxSize(sizeof(struct sockaddr),
offsetof(struct sockaddr, sa_data) + p_dataSize);
}
}
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest,
void *p_data, size_t p_size) {
switch (p_family) {
case AF_INET:
memcpy(&((struct sockaddr_in *)p_dest)->sin_addr, p_data, p_size);
break;
case AF_INET6:
memcpy(&((struct sockaddr_in6 *)p_dest)->sin6_addr, p_data, p_size);
break;
case AF_PACKET:
memcpy(((struct sockaddr_ll *)p_dest)->sll_addr, p_data, p_size);
((struct sockaddr_ll *)p_dest)->sll_halen = p_size;
break;
default:
memcpy(p_dest->sa_data, p_data, p_size);
break;
}
p_dest->sa_family = p_family;
}
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) {
if (!*p_resultList) {
*p_resultList = p_entry;
} else {
struct ifaddrs *l_cur = *p_resultList;
while (l_cur->ifa_next) {
l_cur = l_cur->ifa_next;
}
l_cur->ifa_next = p_entry;
}
}
static int interpretLink(struct nlmsghdr *p_hdr,
struct ifaddrs **p_resultList) {
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
size_t l_dataSize = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
struct rtattr *l_rta;
for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch (l_rta->rta_type) {
case IFLA_ADDRESS:
case IFLA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
break;
case IFLA_IFNAME:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
case IFLA_STATS:
l_dataSize += NLMSG_ALIGN(l_rtaSize);
break;
default:
break;
}
}
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) +
l_nameSize + l_addrSize + l_dataSize);
if (l_entry == NULL) {
return -1;
}
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = "";
char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
char *l_name = l_index + sizeof(int);
char *l_addr = l_name + l_nameSize;
char *l_data = l_addr + l_addrSize;
// save the interface index so we can look it up when handling the addresses.
memcpy(l_index, &l_info->ifi_index, sizeof(int));
l_entry->ifa_flags = l_info->ifi_flags;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch (l_rta->rta_type) {
case IFLA_ADDRESS:
case IFLA_BROADCAST: {
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData,
l_rtaDataSize);
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
if (l_rta->rta_type == IFLA_ADDRESS) {
l_entry->ifa_addr = (struct sockaddr *)l_addr;
} else {
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFLA_IFNAME:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
case IFLA_STATS:
memcpy(l_data, l_rtaData, l_rtaDataSize);
l_entry->ifa_data = l_data;
break;
default:
break;
}
}
addToEnd(p_resultList, l_entry);
return 0;
}
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links,
int p_numLinks) {
int l_num = 0;
struct ifaddrs *l_cur = *p_links;
while (l_cur && l_num < p_numLinks) {
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
int l_index;
memcpy(&l_index, l_indexPtr, sizeof(int));
if (l_index == p_index) {
return l_cur;
}
l_cur = l_cur->ifa_next;
++l_num;
}
return NULL;
}
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
int p_numLinks) {
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
struct ifaddrs *l_interface =
findInterface(l_info->ifa_index, p_resultList, p_numLinks);
if (l_info->ifa_family == AF_PACKET) {
return 0;
}
size_t l_nameSize = 0;
size_t l_addrSize = 0;
int l_addedNetmask = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
struct rtattr *l_rta;
for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch (l_rta->rta_type) {
case IFA_ADDRESS:
case IFA_LOCAL:
if ((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) &&
!l_addedNetmask) { // make room for netmask
l_addrSize +=
NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
l_addedNetmask = 1;
}
case IFA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
break;
case IFA_LABEL:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
default:
break;
}
}
struct ifaddrs *l_entry =
malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
if (l_entry == NULL) {
return -1;
}
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
char *l_addr = l_name + l_nameSize;
l_entry->ifa_flags = l_info->ifa_flags;
if (l_interface) {
l_entry->ifa_flags |= l_interface->ifa_flags;
}
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch (l_rta->rta_type) {
case IFA_ADDRESS:
case IFA_BROADCAST:
case IFA_LOCAL: {
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData,
l_rtaDataSize);
if (l_info->ifa_family == AF_INET6) {
if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) ||
IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) {
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
}
}
if (l_rta->rta_type ==
IFA_ADDRESS) { // apparently in a point-to-point network IFA_ADDRESS
// contains the dest address and IFA_LOCAL contains the
// local address
if (l_entry->ifa_addr) {
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
} else {
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
} else if (l_rta->rta_type == IFA_LOCAL) {
if (l_entry->ifa_addr) {
l_entry->ifa_dstaddr = l_entry->ifa_addr;
}
l_entry->ifa_addr = (struct sockaddr *)l_addr;
} else {
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFA_LABEL:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
default:
break;
}
}
if (l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET ||
l_entry->ifa_addr->sa_family == AF_INET6)) {
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
unsigned l_prefix =
(l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix
: l_info->ifa_prefixlen);
char l_mask[16] = {0};
unsigned i;
for (i = 0; i < (l_prefix / 8); ++i) {
l_mask[i] = 0xff;
}
if (l_prefix % 8) {
l_mask[i] = 0xff << (8 - (l_prefix % 8));
}
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr,
l_mask, l_maxPrefix / 8);
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
}
addToEnd(p_resultList, l_entry);
return 0;
}
static int interpretLinks(int p_socket, NetlinkList *p_netlinkList,
struct ifaddrs **p_resultList) {
int l_numLinks = 0;
pid_t l_pid = getpid();
for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next) {
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);
l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) {
if ((pid_t)l_hdr->nlmsg_pid != l_pid ||
(int)l_hdr->nlmsg_seq != p_socket) {
continue;
}
if (l_hdr->nlmsg_type == NLMSG_DONE) {
break;
}
if (l_hdr->nlmsg_type == RTM_NEWLINK) {
if (interpretLink(l_hdr, p_resultList) == -1) {
return -1;
}
++l_numLinks;
}
}
}
return l_numLinks;
}
static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList,
struct ifaddrs **p_resultList, int p_numLinks) {
pid_t l_pid = getpid();
for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next) {
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);
l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) {
if ((pid_t)l_hdr->nlmsg_pid != l_pid ||
(int)l_hdr->nlmsg_seq != p_socket) {
continue;
}
if (l_hdr->nlmsg_type == NLMSG_DONE) {
break;
}
if (l_hdr->nlmsg_type == RTM_NEWADDR) {
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) {
return -1;
}
}
}
}
return 0;
}
int getifaddrs(struct ifaddrs **ifap) {
if (!ifap) {
return -1;
}
*ifap = NULL;
int l_socket = netlink_socket();
if (l_socket < 0) {
return -1;
}
NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
if (!l_linkResults) {
close(l_socket);
return -1;
}
NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
if (!l_addrResults) {
close(l_socket);
freeResultList(l_linkResults);
return -1;
}
int l_result = 0;
int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
if (l_numLinks == -1 ||
interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) {
l_result = -1;
}
freeResultList(l_linkResults);
freeResultList(l_addrResults);
close(l_socket);
return l_result;
}
void freeifaddrs(struct ifaddrs *ifa) {
struct ifaddrs *l_cur;
while (ifa) {
l_cur = ifa;
ifa = ifa->ifa_next;
free(l_cur);
}
}
/*
* Copyright (c) 1995, 1999
* Berkeley Software Design, 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.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
*
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
*/
#ifndef _IFADDRS_H_
#define _IFADDRS_H_
struct ifaddrs {
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
struct sockaddr *ifa_dstaddr;
void *ifa_data;
};
/*
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
* to be included it must be included before this header file.
*/
#ifndef ifa_broadaddr
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
#endif
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int getifaddrs(struct ifaddrs **ifap);
extern void freeifaddrs(struct ifaddrs *ifa);
__END_DECLS
#endif
......@@ -8,7 +8,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#ifdef __linux
#ifdef __linux__
#include "linux-crypto.h"
struct linux_crypto {
......@@ -218,10 +218,10 @@ int linux_crypto_set_key(const uint8_t *key, int keylen, struct linux_crypto *ct
return 0;
}
int linux_crypto_decrypt(uint8_t inbuf[], uint8_t outbuf[], int buflen, uint8_t iv[], struct linux_crypto *ctx) {
int linux_crypto_decrypt(const uint8_t inbuf[], uint8_t outbuf[], int buflen, uint8_t iv[], struct linux_crypto *ctx) {
return _linux_crypto_process(ctx, inbuf, buflen, outbuf, buflen, 0, iv, 0);
}
int linux_crypto_encrypt(uint8_t inbuf[], uint8_t outbuf[], int buflen, uint8_t iv[], struct linux_crypto *ctx) {
int linux_crypto_encrypt(const uint8_t inbuf[], uint8_t outbuf[], int buflen, uint8_t iv[], struct linux_crypto *ctx) {
return _linux_crypto_process(ctx, inbuf, buflen, outbuf, buflen, 1, iv, 0);
}
......
......@@ -13,7 +13,7 @@
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
......@@ -34,7 +34,7 @@ struct linux_crypto;
int linux_crypto_init(struct linux_crypto **ctx);
int linux_crypto_set_key(const uint8_t *key, int keylen,struct linux_crypto *ctx);
int linux_crypto_decrypt(uint8_t inbuf[], uint8_t outbuf[], int buflen, uint8_t iv[], struct linux_crypto *ctx);
int linux_crypto_encrypt(uint8_t inbuf[], uint8_t outbuf[], int buflen, uint8_t iv[], struct linux_crypto *ctx);
int linux_crypto_decrypt(const uint8_t inbuf[], uint8_t outbuf[], int buflen, uint8_t iv[], struct linux_crypto *ctx);
int linux_crypto_encrypt(const uint8_t inbuf[], uint8_t outbuf[], int buflen, uint8_t iv[], struct linux_crypto *ctx);
void linux_crypto_free(struct linux_crypto **ctx);
#endif
......@@ -12,6 +12,11 @@ if not builtin_mbedtls
endif
if mbedcrypto_lib.found()
mbedcrypto_lib_found = true
mpi_random_test = '''
#include <mbedtls/bignum.h>
void test_has_func() { mbedtls_mpi_random(NULL, 0, NULL, NULL, NULL); }
'''
cdata.set10('MBEDTLS_HAS_MPI_RANDOM', cc.compiles(mpi_random_test, name: 'MbedTLS has mbedtls_mpi_random()', dependencies: mbedcrypto_lib))
endif
endif
if builtin_mbedtls and not mbedcrypto_lib_found
......@@ -93,13 +98,9 @@ if builtin_mbedtls and not mbedcrypto_lib_found
)
inc += mbedcrypto_lib_includes
mbedcrypto_lib_found = true
cdata.set10('MBEDTLS_HAS_MPI_RANDOM', false)
# We could compile libmbedcrypto.a using make on contrib/mbedtls and copy to the build folder instead
#my_mbedcrypto_inc = mbedcrypto_lib_includes
#my_mbedcrypto_lib = static_library('mbedcrypto')
#mbedcrypto_lib = declare_dependency(link_with : my_mbedcrypto_lib, include_directories : my_mbedcrypto_inc)
endif
if mbedcrypto_lib_found
deps += mbedcrypto_lib
platform_files += 'contrib/srp.c'
platform_files += 'src/eap.c'
endif
\ No newline at end of file
......@@ -27,6 +27,10 @@ typedef int socklen_t;
#define write(fd, buf, size) _write(fd, buf, size)
#endif
#ifndef SHUT_RDWR
#define SHUT_RDWR SD_BOTH
#endif
#else /* Unix like OSes */
#include <sys/types.h>
......
/*
* Secure Remote Password 6a implementation based on mbedtls.
*
* Copyright (c) 2017 Johannes Schriewer
* https://github.com/dunkelstern/mbedtls-csrp
*
* Copyright (c) 2015 Dieter Wimberger
* https://github.com/dwimberger/mbedtls-csrp
*
* Derived from:
* Copyright (c) 2010 Tom Cocagne. All rights reserved.
* https://github.com/cocagne/csrp
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Tom Cocagne, Dieter Wimberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "mbedtls/bignum.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
#include "mbedtls/version.h"
#if MBEDTLS_VERSION_NUMBER > 0x02070000
#define USE_SHA_RET 1
#else
#define USE_SHA_RET 0
#endif
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
#include <mbedtls/compat-2.x.h>
#endif
#include "srp.h"
static int g_initialized = 0;
static mbedtls_entropy_context entropy_ctx;
static mbedtls_ctr_drbg_context ctr_drbg_ctx;
static mbedtls_mpi * RR;
typedef struct
{
BIGNUM *N;
BIGNUM *g;
} NGConstant;
struct NGHex
{
const char * n_hex;
const char * g_hex;
};
/* All constants here were pulled from Appendix A of RFC 5054 */
static struct NGHex global_Ng_constants[] = {
{ /* 512 */
"D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B"
"1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3",
"2"
},
{ /* 768 */
"B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F402653BE7147F"
"00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF737D9BE9713CEF8D837ADA"
"6380B1093E94B6A529A8C6C2BE33E0867C60C3262B",
"2"
},
{ /* 1024 */
"EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496"
"EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E"
"F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA"
"9AFD5138FE8376435B9FC61D2FC0EB06E3",
"2"
},
{ /* 2048 */
"AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4"
"A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60"
"95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF"
"747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907"
"8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861"
"60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB"
"FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73",
"2"
},
{ /* 4096 */
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
"49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
"FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
"180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
"04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
"B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
"1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
"E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
"99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
"04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
"233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
"D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
"FFFFFFFFFFFFFFFF",
"5"
},
{ /* 8192 */
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
"49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
"FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
"180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
"04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
"B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
"1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
"E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
"99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
"04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
"233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
"D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
"AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
"DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
"2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
"F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
"BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
"B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
"387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
"6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA"
"3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C"
"5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
"22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886"
"2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6"
"6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5"
"0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268"
"359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6"
"FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
"60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
"13"
},
{0,0} /* null sentinel */
};
static NGConstant * new_ng( SRP_NGType ng_type, const char * n_hex, const char * g_hex )
{
NGConstant * ng = (NGConstant *) malloc( sizeof(NGConstant) );
ng->N = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
ng->g = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(ng->N);
mbedtls_mpi_init(ng->g);
if( !ng || !ng->N || !ng->g )
{
if (ng->N)
mbedtls_mpi_free(ng->N);
if (ng->g)
mbedtls_mpi_free(ng->g);
free(ng);
return 0;
}
if ( ng_type != SRP_NG_CUSTOM )
{
n_hex = global_Ng_constants[ ng_type ].n_hex;
g_hex = global_Ng_constants[ ng_type ].g_hex;
}
mbedtls_mpi_read_string( ng->N, 16, n_hex);
mbedtls_mpi_read_string( ng->g, 16, g_hex);
return ng;
}
static void delete_ng( NGConstant * ng )
{
if (ng)
{
mbedtls_mpi_free( ng->N );
mbedtls_mpi_free( ng->g );
free(ng->N);
free(ng->g);
free(ng);
}
}
typedef union
{
mbedtls_sha1_context sha;
mbedtls_sha256_context sha256;
mbedtls_sha512_context sha512;
} HashCTX;
struct SRPSession
{
SRP_HashAlgorithm hash_alg;
NGConstant *ng;
};
struct SRPVerifier
{
SRP_HashAlgorithm hash_alg;
NGConstant *ng;
const char * username;
const unsigned char * bytes_B;
int authenticated;
unsigned char M [SHA512_DIGEST_LENGTH];
unsigned char H_AMK [SHA512_DIGEST_LENGTH];
unsigned char session_key [SHA512_DIGEST_LENGTH];
};
struct SRPUser
{
SRP_HashAlgorithm hash_alg;
NGConstant *ng;
BIGNUM *a;
BIGNUM *A;
BIGNUM *S;
const unsigned char * bytes_A;
int authenticated;
const char * username;
const unsigned char * password;
size_t password_len;
unsigned char M [SHA512_DIGEST_LENGTH];
unsigned char H_AMK [SHA512_DIGEST_LENGTH];
unsigned char session_key [SHA512_DIGEST_LENGTH];
};
static void hash_init( SRP_HashAlgorithm alg, HashCTX *c )
{
switch (alg)
{
case SRP_SHA1 :
mbedtls_sha1_init( &c->sha );
break;
case SRP_SHA256:
mbedtls_sha256_init( &c->sha256 );
break;
case SRP_SHA512:
mbedtls_sha512_init( &c->sha512 );
break;
default:
return;
};
}
/*
static void hash_start( SRP_HashAlgorithm alg, HashCTX *c )
{
switch (alg)
{
case SRP_SHA1 : mbedtls_sha1_starts( &c->sha );
case SRP_SHA224: mbedtls_sha256_starts( &c->sha256, 1 );
case SRP_SHA256: mbedtls_sha256_starts( &c->sha256, 0 );
case SRP_SHA384: mbedtls_sha512_starts( &c->sha512, 1 );
case SRP_SHA512: mbedtls_sha512_starts( &c->sha512, 0 );
default:
return;
};
}*/
static int hash_update( SRP_HashAlgorithm alg, HashCTX *c, const void *data, size_t len )
{
#if !USE_SHA_RET
switch (alg)
{
case SRP_SHA1 : mbedtls_sha1_update( &c->sha, data, len ); break;
case SRP_SHA224: mbedtls_sha256_update( &c->sha256, data, len ); break;
case SRP_SHA256: mbedtls_sha256_update( &c->sha256, data, len ); break;
case SRP_SHA384: mbedtls_sha512_update( &c->sha512, data, len ); break;
case SRP_SHA512: mbedtls_sha512_update( &c->sha512, data, len ); break;
default:
return -1;
};
return 0;
#else
switch (alg)
{
case SRP_SHA1:
return mbedtls_sha1_update_ret( &c->sha, data, len );
case SRP_SHA224:
return mbedtls_sha256_update_ret( &c->sha256, data, len );
case SRP_SHA256:
return mbedtls_sha256_update_ret( &c->sha256, data, len );
case SRP_SHA384:
return mbedtls_sha512_update_ret( &c->sha512, data, len );
case SRP_SHA512:
return mbedtls_sha512_update_ret( &c->sha512, data, len );
default:
return -1;
};
#endif
}
static int hash_final( SRP_HashAlgorithm alg, HashCTX *c, unsigned char *md )
{
#if !USE_SHA_RET
switch (alg)
{
case SRP_SHA1 : mbedtls_sha1_finish( &c->sha, md ); break;
case SRP_SHA224: mbedtls_sha256_finish( &c->sha256, md ); break;
case SRP_SHA256: mbedtls_sha256_finish( &c->sha256, md ); break;
case SRP_SHA384: mbedtls_sha512_finish( &c->sha512, md ); break;
case SRP_SHA512: mbedtls_sha512_finish( &c->sha512, md ); break;
default:
return -1;
};
return 0;
#else
switch (alg)
{
case SRP_SHA1 :
return mbedtls_sha1_finish_ret( &c->sha, md );
case SRP_SHA224:
return mbedtls_sha256_finish_ret( &c->sha256, md );
case SRP_SHA256:
return mbedtls_sha256_finish_ret( &c->sha256, md );
case SRP_SHA384:
return mbedtls_sha512_finish_ret( &c->sha512, md );
case SRP_SHA512:
return mbedtls_sha512_finish_ret( &c->sha512, md );
default:
return -1;
};
#endif
}
static int hash( SRP_HashAlgorithm alg, const unsigned char *d, size_t n, unsigned char *md )
{
#if !USE_SHA_RET
switch (alg)
{
case SRP_SHA1 : mbedtls_sha1( d, n, md ); break;
case SRP_SHA224: mbedtls_sha256( d, n, md, 1); break;
case SRP_SHA256: mbedtls_sha256( d, n, md, 0); break;
case SRP_SHA384: mbedtls_sha512( d, n, md, 1 ); break;
case SRP_SHA512: mbedtls_sha512( d, n, md, 0 ); break;
default:
return -1;
};
return 0;
#else
switch (alg)
{
case SRP_SHA1 :
return mbedtls_sha1_ret( d, n, md );
case SRP_SHA224:
return mbedtls_sha256_ret( d, n, md, 1);
case SRP_SHA256:
return mbedtls_sha256_ret( d, n, md, 0);
case SRP_SHA384:
return mbedtls_sha512_ret( d, n, md, 1 );
case SRP_SHA512:
return mbedtls_sha512_ret( d, n, md, 0 );
default:
return -1;
};
#endif
}
static int hash_length( SRP_HashAlgorithm alg )
{
switch (alg)
{
case SRP_SHA1 : return SHA1_DIGEST_LENGTH;
case SRP_SHA224: return SHA224_DIGEST_LENGTH;
case SRP_SHA256: return SHA256_DIGEST_LENGTH;
case SRP_SHA384: return SHA384_DIGEST_LENGTH;
case SRP_SHA512: return SHA512_DIGEST_LENGTH;
default:
return -1;
};
}
static BIGNUM * H_nn( SRP_HashAlgorithm alg, const BIGNUM * n1, const BIGNUM * n2 )
{
unsigned char buff[ SHA512_DIGEST_LENGTH ];
size_t len_n1 = mbedtls_mpi_size(n1);
size_t len_n2 = mbedtls_mpi_size(n2);
size_t nbytes = len_n1 + len_n2;
unsigned char * bin = (unsigned char *) malloc( nbytes );
if (!bin)
return 0;
mbedtls_mpi_write_binary( n1, bin, len_n1 );
mbedtls_mpi_write_binary( n2, bin+len_n1, len_n2 );
hash( alg, bin, nbytes, buff );
free(bin);
BIGNUM * bn;
bn = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(bn);
mbedtls_mpi_read_binary( bn, buff, hash_length(alg) );
return bn;
}
static BIGNUM * H_ns( SRP_HashAlgorithm alg, const BIGNUM * n, const unsigned char * bytes, size_t len_bytes )
{
unsigned char buff[ SHA512_DIGEST_LENGTH ];
size_t len_n = mbedtls_mpi_size(n);
size_t nbytes = len_n + len_bytes;
unsigned char * bin = (unsigned char *) malloc( nbytes );
if (!bin)
return 0;
mbedtls_mpi_write_binary( n, bin, len_n );
memcpy( bin + len_n, bytes, len_bytes );
hash( alg, bin, nbytes, buff );
free(bin);
BIGNUM * bn;
bn = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(bn);
mbedtls_mpi_read_binary( bn, buff, hash_length(alg) );
return bn;
}
static BIGNUM * calculate_x( SRP_HashAlgorithm alg, const BIGNUM * salt, const char * username, const unsigned char * password, size_t password_len )
{
unsigned char ucp_hash[SHA512_DIGEST_LENGTH];
HashCTX ctx;
hash_init( alg, &ctx );
if (hash_update( alg, &ctx, username, strlen(username) ) != 0)
return NULL;
if (hash_update( alg, &ctx, ":", 1 ) != 0)
return NULL;
if (hash_update( alg, &ctx, password, password_len ) != 0)
return NULL;
if (hash_final( alg, &ctx, ucp_hash ) != 0)
return NULL;
return H_ns( alg, salt, ucp_hash, hash_length(alg) );
}
static void update_hash_n( SRP_HashAlgorithm alg, HashCTX *ctx, const BIGNUM * n )
{
unsigned long len = mbedtls_mpi_size(n);
unsigned char * n_bytes = (unsigned char *) malloc( len );
if (!n_bytes)
return;
mbedtls_mpi_write_binary( n, n_bytes, len );
hash_update(alg, ctx, n_bytes, len);
free(n_bytes);
}
static void hash_num( SRP_HashAlgorithm alg, const BIGNUM * n, unsigned char * dest )
{
size_t nbytes = mbedtls_mpi_size(n);
unsigned char * bin = (unsigned char *) malloc( nbytes );
if(!bin)
return;
mbedtls_mpi_write_binary( n, bin, nbytes );
hash( alg, bin, nbytes, dest );
free(bin);
}
static void calculate_M( SRP_HashAlgorithm alg, NGConstant *ng, unsigned char * dest, const char * I, const BIGNUM * s,
const BIGNUM * A, const BIGNUM * B, const unsigned char * K )
{
unsigned char H_N[ SHA512_DIGEST_LENGTH ] = { '\0' };
unsigned char H_g[ SHA512_DIGEST_LENGTH ] = { '\0' };
unsigned char H_I[ SHA512_DIGEST_LENGTH ] = { '\0' };
unsigned char H_xor[ SHA512_DIGEST_LENGTH ] = { '\0' };
HashCTX ctx;
int i = 0;
int hash_len = hash_length(alg);
hash_num( alg, ng->N, H_N );
hash_num( alg, ng->g, H_g );
hash(alg, (const unsigned char *)I, strlen(I), H_I);
for (i=0; i < hash_len; i++ )
H_xor[i] = H_N[i] ^ H_g[i];
hash_init( alg, &ctx );
hash_update( alg, &ctx, H_xor, hash_len );
hash_update( alg, &ctx, H_I, hash_len );
update_hash_n( alg, &ctx, s );
update_hash_n( alg, &ctx, A );
update_hash_n( alg, &ctx, B );
hash_update( alg, &ctx, K, hash_len );
hash_final( alg, &ctx, dest );
}
static void calculate_H_AMK( SRP_HashAlgorithm alg, unsigned char *dest, const BIGNUM * A, const unsigned char * M, const unsigned char * K )
{
HashCTX ctx;
hash_init( alg, &ctx );
update_hash_n( alg, &ctx, A );
hash_update( alg, &ctx, M, hash_length(alg) );
hash_update( alg, &ctx, K, hash_length(alg) );
hash_final( alg, &ctx, dest );
}
static void init_random()
{
if (g_initialized)
return;
mbedtls_entropy_init( &entropy_ctx );
mbedtls_ctr_drbg_init( &ctr_drbg_ctx );
unsigned char hotBits[128] = {
82, 42, 71, 87, 124, 241, 30, 1, 54, 239, 240, 121, 89, 9, 151, 11, 60,
226, 142, 47, 115, 157, 100, 126, 242, 132, 46, 12, 56, 197, 194, 76,
198, 122, 90, 241, 255, 43, 120, 209, 69, 21, 195, 212, 100, 251, 18,
111, 30, 238, 24, 199, 238, 236, 138, 225, 45, 15, 42, 83, 114, 132,
165, 141, 32, 185, 167, 100, 131, 23, 236, 9, 11, 51, 130, 136, 97, 161,
36, 174, 129, 234, 2, 54, 119, 184, 70, 103, 118, 109, 122, 15, 24, 23,
166, 203, 102, 160, 77, 100, 17, 4, 132, 138, 215, 204, 109, 245, 122,
9, 184, 89, 70, 247, 125, 97, 213, 240, 85, 243, 91, 226, 127, 64, 136,
37, 154, 232
};
mbedtls_ctr_drbg_seed(
&ctr_drbg_ctx,
mbedtls_entropy_func,
&entropy_ctx,
hotBits,
128
);
RR = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(RR);
g_initialized = 1;
}
/***********************************************************************************************************
*
* Exported Functions
*
***********************************************************************************************************/
struct SRPSession * srp_session_new( SRP_HashAlgorithm alg,
SRP_NGType ng_type,
const char * n_hex, const char * g_hex)
{
struct SRPSession * session;
session = (struct SRPSession *)malloc(sizeof(struct SRPSession));
memset(session, 0, sizeof(struct SRPSession));
session->hash_alg = alg;
session->ng = new_ng( ng_type, n_hex, g_hex );
return session;
}
void srp_session_delete(struct SRPSession *session)
{
delete_ng( session->ng );
free(session);
}
void srp_random_seed( const unsigned char * random_data, size_t data_length )
{
g_initialized = 1;
if( mbedtls_ctr_drbg_seed( &ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx,
(const unsigned char *) random_data,
data_length ) != 0 )
{
return;
}
}
void srp_create_salted_verification_key( struct SRPSession *session,
const char * username,
const unsigned char * password, size_t len_password,
const unsigned char ** bytes_s, size_t * len_s,
const unsigned char ** bytes_v, size_t * len_v)
{
BIGNUM * s;
BIGNUM * v;
BIGNUM * x = 0;
s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(s);
v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(v);
if( !session || !s || !v )
goto cleanup_and_exit;
init_random(); /* Only happens once */
mbedtls_mpi_fill_random( s, 32,
&mbedtls_ctr_drbg_random,
&ctr_drbg_ctx );
x = calculate_x( session->hash_alg, s, username, password, len_password );
if( !x )
goto cleanup_and_exit;
mbedtls_mpi_exp_mod(v, session->ng->g, x, session->ng->N, RR);
*len_s = mbedtls_mpi_size(s);
*len_v = mbedtls_mpi_size(v);
*bytes_s = (const unsigned char *) malloc( *len_s );
*bytes_v = (const unsigned char *) malloc( *len_v );
if (!bytes_s || !bytes_v)
goto cleanup_and_exit;
mbedtls_mpi_write_binary( s, (unsigned char *)*bytes_s, *len_s );
mbedtls_mpi_write_binary( v, (unsigned char *)*bytes_v, *len_v );
cleanup_and_exit:
mbedtls_mpi_free(s);
free(s);
mbedtls_mpi_free(v);
free(v);
mbedtls_mpi_free(x);
free(x);
//TODO: BN_CTX_free(ctx);
}
/* Out: bytes_B, len_B.
*
* On failure, bytes_B will be set to NULL and len_B will be set to 0
*/
struct SRPVerifier * srp_verifier_new( struct SRPSession *session,
const char *username,
const unsigned char * bytes_s, size_t len_s,
const unsigned char * bytes_v, size_t len_v,
const unsigned char * bytes_A, size_t len_A,
const unsigned char ** bytes_B, size_t * len_B)
{
BIGNUM *s;
s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(s);
mbedtls_mpi_read_binary(s, bytes_s, len_s);
BIGNUM *v;
v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(v);
mbedtls_mpi_read_binary(v, bytes_v, len_v);
BIGNUM *A;
A = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(A);
mbedtls_mpi_read_binary(A, bytes_A, len_A);
BIGNUM *u = 0;
BIGNUM *B;
B = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(B);
BIGNUM *S;
S = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(S);
BIGNUM *b;
b = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(b);
BIGNUM *k = 0;
BIGNUM *tmp1;
tmp1 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(tmp1);
BIGNUM *tmp2;
tmp2 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(tmp2);
size_t ulen = strlen(username) + 1;
struct SRPVerifier *ver = 0;
ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) );
*len_B = 0;
*bytes_B = 0;
if( !session || !B || !S || !b || !tmp1 || !tmp2 || !ver ) {
goto cleanup_and_exit;
}
init_random(); /* Only happens once */
ver->hash_alg = session->hash_alg;
ver->ng = session->ng;
ver->username = (char *) malloc( ulen ); // FIXME
if (!ver->username)
{
free(ver);
ver = 0;
goto cleanup_and_exit;
}
memcpy( (char*)ver->username, username, ulen );
ver->authenticated = 0;
/* SRP-6a safety check */
mbedtls_mpi_mod_mpi( tmp1, A, session->ng->N );
if ( mbedtls_mpi_cmp_int( tmp1, 0 ) != 0)
{
mbedtls_mpi_fill_random( b, 32,
&mbedtls_ctr_drbg_random,
&ctr_drbg_ctx );
k = H_nn(session->hash_alg, session->ng->N, session->ng->g);
/* B = kv + g^b */
mbedtls_mpi_mul_mpi( tmp1, k, v);
mbedtls_mpi_exp_mod( tmp2, session->ng->g, b, session->ng->N, RR );
mbedtls_mpi_add_mpi( tmp1, tmp1, tmp2 );
mbedtls_mpi_mod_mpi( B, tmp1, session->ng->N );
u = H_nn(session->hash_alg, A, B);
/* S = (A *(v^u)) ^ b */
mbedtls_mpi_exp_mod(tmp1, v, u, session->ng->N, RR);
mbedtls_mpi_mul_mpi(tmp2, A, tmp1);
mbedtls_mpi_exp_mod(S, tmp2, b, session->ng->N, RR);
hash_num(session->hash_alg, S, ver->session_key);
calculate_M( session->hash_alg, session->ng, ver->M, username, s, A, B, ver->session_key );
calculate_H_AMK( session->hash_alg, ver->H_AMK, A, ver->M, ver->session_key );
*len_B = mbedtls_mpi_size(B);
*bytes_B = malloc( *len_B );
if( !*bytes_B )
{
free( (void*) ver->username );
free( ver );
ver = 0;
*len_B = 0;
goto cleanup_and_exit;
}
mbedtls_mpi_write_binary( B, (unsigned char *)*bytes_B, *len_B );
ver->bytes_B = *bytes_B;
}
cleanup_and_exit:
mbedtls_mpi_free(s);
free(s);
mbedtls_mpi_free(v);
free(v);
mbedtls_mpi_free(A);
free(A);
if (u) {mbedtls_mpi_free(u); free(u);}
if (k) {mbedtls_mpi_free(k); free(k);}
mbedtls_mpi_free(B);
free(B);
mbedtls_mpi_free(S);
free(S);
mbedtls_mpi_free(b);
free(b);
mbedtls_mpi_free(tmp1);
free(tmp1);
mbedtls_mpi_free(tmp2);
free(tmp2);
return ver;
}
void srp_verifier_delete( struct SRPVerifier * ver )
{
if (ver)
{
//delete_ng( ver->ng );
free( (char *) ver->username );
if(ver->bytes_B !=0) {
free( (unsigned char *) ver->bytes_B );
}
memset(ver, 0, sizeof(*ver));
free( ver );
}
}
int srp_verifier_is_authenticated( struct SRPVerifier * ver )
{
return ver->authenticated;
}
const char * srp_verifier_get_username( struct SRPVerifier * ver )
{
return ver->username;
}
const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, size_t * key_length )
{
if (key_length)
*key_length = hash_length( ver->hash_alg );
return ver->session_key;
}
int srp_verifier_get_session_key_length( struct SRPVerifier * ver )
{
return hash_length( ver->hash_alg );
}
/* user_M must be exactly SHA512_DIGEST_LENGTH bytes in size */
void srp_verifier_verify_session( struct SRPVerifier * ver, const unsigned char * user_M, const unsigned char ** bytes_HAMK )
{
if ( memcmp( ver->M, user_M, hash_length(ver->hash_alg) ) == 0 )
{
ver->authenticated = 1;
*bytes_HAMK = ver->H_AMK;
}
else
*bytes_HAMK = NULL;
}
/*******************************************************************************/
struct SRPUser * srp_user_new( struct SRPSession *session, const char * username,
const unsigned char * bytes_password, size_t len_password)
{
struct SRPUser *usr = (struct SRPUser *) calloc(1, sizeof(struct SRPUser) );
size_t ulen = strlen(username) + 1;
if (!usr)
goto err_exit;
init_random(); /* Only happens once */
usr->hash_alg = session->hash_alg;
usr->ng = session->ng;
usr->a = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
usr->A = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
usr->S = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(usr->a);
mbedtls_mpi_init(usr->A);
mbedtls_mpi_init(usr->S);
if (!usr->ng || !usr->a || !usr->A || !usr->S)
goto err_exit;
usr->username = (const char *) malloc(ulen);
usr->password = (const unsigned char *) malloc(len_password);
usr->password_len = len_password;
if (!usr->username || !usr->password)
goto err_exit;
memcpy((char *)usr->username, username, ulen);
memcpy((char *)usr->password, bytes_password, len_password);
usr->authenticated = 0;
usr->bytes_A = 0;
return usr;
err_exit:
if (usr)
{
mbedtls_mpi_free(usr->a);
mbedtls_mpi_free(usr->A);
mbedtls_mpi_free(usr->S);
if (usr->username)
free((void*)usr->username);
if (usr->password)
{
memset((void*)usr->password, 0, usr->password_len);
free((void*)usr->password);
}
free(usr);
}
return 0;
}
void srp_user_delete( struct SRPUser * usr )
{
if( usr )
{
mbedtls_mpi_free( usr->a );
mbedtls_mpi_free( usr->A );
mbedtls_mpi_free( usr->S );
free(usr->a);
free(usr->A);
free(usr->S);
//delete_ng( usr->ng );
memset((void*)usr->password, 0, usr->password_len);
free((char *)usr->username);
free((char *)usr->password);
if (usr->bytes_A)
free( (char *)usr->bytes_A );
memset(usr, 0, sizeof(*usr));
free( usr );
}
}
int srp_user_is_authenticated( struct SRPUser * usr)
{
return usr->authenticated;
}
const char * srp_user_get_username( struct SRPUser * usr )
{
return usr->username;
}
const unsigned char * srp_user_get_session_key( struct SRPUser * usr, size_t * key_length )
{
if (key_length)
*key_length = hash_length( usr->hash_alg );
return usr->session_key;
}
int srp_user_get_session_key_length( struct SRPUser * usr )
{
return hash_length( usr->hash_alg );
}
/* Output: username, bytes_A, len_A */
void srp_user_start_authentication( struct SRPUser * usr, const char ** username,
const unsigned char ** bytes_A, size_t * len_A )
{
mbedtls_mpi_fill_random( usr->a, 32, &mbedtls_ctr_drbg_random, &ctr_drbg_ctx);
mbedtls_mpi_exp_mod(usr->A, usr->ng->g, usr->a, usr->ng->N, RR);
*len_A = mbedtls_mpi_size(usr->A);
*bytes_A = malloc( *len_A );
if (!*bytes_A)
{
*len_A = 0;
*bytes_A = 0;
*username = 0;
return;
}
mbedtls_mpi_write_binary( usr->A, (unsigned char *) *bytes_A, *len_A );
usr->bytes_A = *bytes_A;
*username = usr->username;
}
/* Output: bytes_M. Buffer length is SHA512_DIGEST_LENGTH */
void srp_user_process_challenge( struct SRPUser * usr,
const unsigned char * bytes_s, size_t len_s,
const unsigned char * bytes_B, size_t len_B,
const unsigned char ** bytes_M, size_t * len_M )
{
BIGNUM *u = 0;
BIGNUM *x = 0;
BIGNUM *k = 0;
BIGNUM *s;
s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(s);
mbedtls_mpi_read_binary(s, bytes_s, len_s);
BIGNUM *B;
B = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(B);
mbedtls_mpi_read_binary(B, bytes_B, len_B);
BIGNUM *v;
v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(v);
BIGNUM *tmp1;
tmp1 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(tmp1);
BIGNUM *tmp2;
tmp2 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(tmp2);
BIGNUM *tmp3;
tmp3 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi));
mbedtls_mpi_init(tmp3);
*len_M = 0;
*bytes_M = 0;
if( !s || !B || !v || !tmp1 || !tmp2 || !tmp3 )
goto cleanup_and_exit;
u = H_nn(usr->hash_alg, usr->A, B);
if (!u)
goto cleanup_and_exit;
x = calculate_x( usr->hash_alg, s, usr->username, usr->password, usr->password_len );
if (!x)
goto cleanup_and_exit;
k = H_nn(usr->hash_alg, usr->ng->N, usr->ng->g);
if (!k)
goto cleanup_and_exit;
/* SRP-6a safety check */
if( mbedtls_mpi_cmp_int( B, 0 ) != 0 && mbedtls_mpi_cmp_int( u, 0 ) !=0 )
{
mbedtls_mpi_exp_mod(v, usr->ng->g, x, usr->ng->N, RR);
/* S = (B - k*(g^x)) ^ (a + ux) */
mbedtls_mpi_mul_mpi( tmp1, u, x );
mbedtls_mpi_mod_mpi( tmp1, tmp1, usr->ng->N);
mbedtls_mpi_add_mpi( tmp2, usr->a, tmp1);
mbedtls_mpi_mod_mpi( tmp2, tmp2, usr->ng->N);
/* tmp2 = (a + ux) */
mbedtls_mpi_exp_mod( tmp1, usr->ng->g, x, usr->ng->N, RR);
mbedtls_mpi_mul_mpi( tmp3, k, tmp1 );
mbedtls_mpi_mod_mpi( tmp3, tmp3, usr->ng->N);
/* tmp3 = k*(g^x) */
mbedtls_mpi_sub_mpi(tmp1, B, tmp3);
/* tmp1 = (B - K*(g^x)) */
mbedtls_mpi_exp_mod( usr->S, tmp1, tmp2, usr->ng->N, RR);
hash_num(usr->hash_alg, usr->S, usr->session_key);
calculate_M( usr->hash_alg, usr->ng, usr->M, usr->username, s, usr->A, B, usr->session_key );
calculate_H_AMK( usr->hash_alg, usr->H_AMK, usr->A, usr->M, usr->session_key );
*bytes_M = usr->M;
if (len_M) {
*len_M = hash_length( usr->hash_alg );
}
}
else
{
*bytes_M = NULL;
if (len_M)
*len_M = 0;
}
cleanup_and_exit:
mbedtls_mpi_free(s);
mbedtls_mpi_free(B);
mbedtls_mpi_free(u);
mbedtls_mpi_free(x);
mbedtls_mpi_free(k);
mbedtls_mpi_free(v);
mbedtls_mpi_free(tmp1);
mbedtls_mpi_free(tmp2);
mbedtls_mpi_free(tmp3);
free(s);
free(B);
free(u);
free(x);
free(k);
free(v);
free(tmp1);
free(tmp2);
free(tmp3);
}
void srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK )
{
if ( memcmp( usr->H_AMK, bytes_HAMK, hash_length(usr->hash_alg) ) == 0 )
usr->authenticated = 1;
}
/*
* Secure Remote Password 6a implementation based on mbedtls.
*
* Copyright (c) 2017 Johannes Schriewer
* https://github.com/dunkelstern/mbedtls-csrp
*
* Copyright (c) 2015 Dieter Wimberger
* https://github.com/dwimberger/mbedtls-csrp
*
* Derived from:
* Copyright (c) 2010 Tom Cocagne. All rights reserved.
* https://github.com/cocagne/csrp
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Tom Cocagne, Dieter Wimberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
/*
*
* Purpose: This is a direct implementation of the Secure Remote Password
* Protocol version 6a as described by
* http://srp.stanford.edu/design.html
*
* Author: tom.cocagne@gmail.com (Tom Cocagne), Dieter Wimberger
*
* Dependencies: mbedtls
*
* Usage: Refer to test_srp.c for a demonstration
*
* Notes:
* This library allows multiple combinations of hashing algorithms and
* prime number constants. For authentication to succeed, the hash and
* prime number constants must match between
* srp_create_salted_verification_key(), srp_user_new(),
* and srp_verifier_new(). A recommended approach is to determine the
* desired level of security for an application and globally define the
* hash and prime number constants to the predetermined values.
*
* As one might suspect, more bits means more security. As one might also
* suspect, more bits also means more processing time. The test_srp.c
* program can be easily modified to profile various combinations of
* hash & prime number pairings.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#ifndef SRP_H
#define SRP_H
#define SHA1_DIGEST_LENGTH 20
#define SHA224_DIGEST_LENGTH 28
#define SHA256_DIGEST_LENGTH 32
#define SHA384_DIGEST_LENGTH 48
#define SHA512_DIGEST_LENGTH 64
#define BIGNUM mbedtls_mpi
struct SRPSession;
struct SRPVerifier;
struct SRPUser;
typedef enum
{
SRP_NG_512,
SRP_NG_768,
SRP_NG_1024,
SRP_NG_2048,
SRP_NG_4096,
SRP_NG_8192,
SRP_NG_CUSTOM
} SRP_NGType;
typedef enum
{
SRP_SHA1,
SRP_SHA224,
SRP_SHA256,
SRP_SHA384,
SRP_SHA512
} SRP_HashAlgorithm;
/* This library will automatically seed the mbedtls random number generator.
*
* The random data should include at least as many bits of entropy as the
* largest hash function used by the application. So, for example, if a
* 512-bit hash function is used, the random data requies at least 512
* bits of entropy.
*
* Passing a null pointer to this function will cause this library to skip
* seeding the random number generator.
*
* Notes:
* * This function is optional on Windows & Linux and mandatory on all
* other platforms.
*/
void srp_random_seed( const unsigned char * random_data, size_t data_length );
/*
* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type.
* If provided, they must contain ASCII text of the hexidecimal notation.
*/
struct SRPSession * srp_session_new( SRP_HashAlgorithm alg,
SRP_NGType ng_type,
const char * n_hex, const char * g_hex);
void srp_session_delete(struct SRPSession *session);
/* Out: bytes_s, len_s, bytes_v, len_v
*
* The caller is responsible for freeing the memory allocated for bytes_s and bytes_v
*/
void srp_create_salted_verification_key( struct SRPSession * session,
const char * username,
const unsigned char * password, size_t len_password,
const unsigned char ** bytes_s, size_t * len_s,
const unsigned char ** bytes_v, size_t * len_v);
/* Out: bytes_B, len_B.
*
* On failure, bytes_B will be set to NULL and len_B will be set to 0
*/
struct SRPVerifier * srp_verifier_new( struct SRPSession * session,
const char * username,
const unsigned char * bytes_s, size_t len_s,
const unsigned char * bytes_v, size_t len_v,
const unsigned char * bytes_A, size_t len_A,
const unsigned char ** bytes_B, size_t * len_B);
void srp_verifier_delete( struct SRPVerifier * ver );
int srp_verifier_is_authenticated( struct SRPVerifier * ver );
const char * srp_verifier_get_username( struct SRPVerifier * ver );
/* key_length may be null */
const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, size_t * key_length );
int srp_verifier_get_session_key_length( struct SRPVerifier * ver );
/* user_M must be exactly srp_verifier_get_session_key_length() bytes in size */
void srp_verifier_verify_session( struct SRPVerifier * ver,
const unsigned char * user_M,
const unsigned char ** bytes_HAMK );
/*******************************************************************************/
/* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type */
struct SRPUser * srp_user_new( struct SRPSession *session,
const char * username,
const unsigned char * bytes_password, size_t len_password);
void srp_user_delete( struct SRPUser * usr );
int srp_user_is_authenticated( struct SRPUser * usr);
const char * srp_user_get_username( struct SRPUser * usr );
/* key_length may be null */
const unsigned char * srp_user_get_session_key( struct SRPUser * usr, size_t * key_length );
int srp_user_get_session_key_length( struct SRPUser * usr );
/* Output: username, bytes_A, len_A */
void srp_user_start_authentication( struct SRPUser * usr, const char ** username,
const unsigned char ** bytes_A, size_t * len_A );
/* Output: bytes_M, len_M (len_M may be null and will always be
* srp_user_get_session_key_length() bytes in size) */
void srp_user_process_challenge( struct SRPUser * usr,
const unsigned char * bytes_s, size_t len_s,
const unsigned char * bytes_B, size_t len_B,
const unsigned char ** bytes_M, size_t * len_M );
/* bytes_HAMK must be exactly srp_user_get_session_key_length() bytes in size */
void srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK );
#endif /* Include Guard */
#ifdef __cplusplus
}
#endif
docs/RIST_vs_SRT.png

206 KiB

......@@ -90,4 +90,7 @@ typedef signed int ssize_t;
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define SET_BIT(value, pos) (value |= (1U << pos))
#define UNSET_BIT(value, pos) (value &= (1U << pos))
#endif
......@@ -8,6 +8,6 @@
#ifndef LIBRIST_CONFIG_H
#define LIBRIST_CONFIG_H
#define HAVE_MBEDTLS @HAVE_MBEDTLS@
#define HAVE_SRP_SUPPORT @HAVE_SRP_SUPPORT@
#endif /* LIBRIST_CONFIG_H */
......@@ -9,10 +9,11 @@
#ifndef _LIBRIST_SRP_H_
#define _LIBRIST_SRP_H_
#include "librist_config.h"
#if HAVE_MBEDTLS
#if HAVE_SRP_SUPPORT
#include "librist.h"
#include <stddef.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
......@@ -47,6 +48,55 @@ typedef void (*user_verifier_lookup_t)(char * username,
char **generator_ascii,
void *user_data);
typedef struct {
size_t verifier_len; /* len in bytes of the verifier. */
uint8_t *verifier; /* verifier bytes, MUST be heap allocated. */
size_t salt_len; /* len in bytes of the salt.*/
uint8_t *salt; /* salt bytes, MUST be heap allocated. */
bool default_ng; /* Use the default 2048 bit modulus, when true N Prime modulus & generator MUST be NULL. */
char *n_modulus_ascii; /* N Prime modulus in hex as a zero terminated C string, MUST be heap allocated or NULL. */
char *generator_ascii; /* Generator in hex as a zero terminated C string, MUST be heap allocated or NULL. */
} librist_verifier_lookup_data_t;
/**
* @brief SRP User lookup function
*
* The SRP User lookup function is called inside the process of authentication
* the calling application MUST implement this function if it desires to so run
* as a RIST MAIN profile server with SRP authentication enabled.
* Userlookup is assumed to have been successful if both verifier params and both salt
* params are set by the lookup function.
* If the verifier function sets a non-zero generation number libRIST will periodically
* poll it to see if salt/verifier has changed, it will do this with lookup_data set to
* NULL. On changes it will request the client to re-authenticate itself.
* Leave generation number at 0 to keep the old behaviour of unconditionally periodically
* reauthenticating clients.
* libRIST will take ownership of all heap allocated data.
*
* @bug Previous releases of libRIST had an error in combined hashing of multiple data
sources. The error produced reproducable hashes that are not matching with
correctly hashed data. This reflects in the SRP file and also results in
incompatibilty with the newly created nettle+gmp crypto backend.
To ensure compatibilty with previous libRIST releases it's recommended to have
both old and new verifier/salt pairs availabe and in the lookup function return
the maximum requested version. Where 0 is the legacy compatible version and 1
is the new correct version.
Compatibility with the broken hashing will be removed in a future release.
*
* @param username IN the username attempting authentication
* @param lookup_data OUT: when non-null the calling application should fill this with the requested data.
* @param hashversion IN/OUT IN: the maximum supported hashversion that should be looked up. OUT: the hashversion of the found salt/verifier pair.
* @param generation IN/OUT IN: generation number the library has cached for the requested user. OUT: generation number of the returned data.
* @param user_data IN pointer to user data.
*
**/
typedef void (*user_verifier_lookup_2_t)(char * username,
librist_verifier_lookup_data_t *lookup_data,
int *hashversion,
uint64_t *generation,
void *user_data);
/**
* @brief Enable SRP authentication
*
......@@ -61,7 +111,8 @@ typedef void (*user_verifier_lookup_t)(char * username,
* @param userdata IN optional user data to be supplied to lookup function.
*
**/
RIST_API int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata);
RIST_API RIST_DEPRECATED int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata);
RIST_API int rist_enable_eap_srp_2(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_2_t lookup_func, void *userdata);
#ifdef __cplusplus
}
......
......@@ -41,14 +41,25 @@ enum rist_log_level
* when using UDP logging to prevent fd's leaking.
**/
#if !defined(__cplusplus) || __cplusplus >= 202002L
#define LOGGING_SETTINGS_INITIALIZER \
{ \
.log_level = RIST_LOG_DISABLE, \
{ \
.log_level = RIST_LOG_DISABLE, \
.log_cb = NULL, \
.log_cb_arg = NULL, \
.log_cb_arg = NULL, \
.log_socket = -1, \
.log_stream = NULL, \
}
}
#else
#define LOGGING_SETTINGS_INITIALIZER \
{ \
RIST_LOG_DISABLE, \
NULL, \
NULL, \
-1, \
NULL, \
}
#endif
struct rist_logging_settings {
enum rist_log_level log_level;///<minimum log level
......