mirror of
https://github.com/eclipse/tinydtls.git
synced 2025-05-08 11:27:36 +08:00
New initial commit
This commit is contained in:
commit
e1388b3980
64
.gitignore
vendored
Normal file
64
.gitignore
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
core
|
||||
*~
|
||||
*.[oa]
|
||||
*.gz
|
||||
*.cap
|
||||
*.pcap
|
||||
Makefile
|
||||
autom4te.cache/
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
configure
|
||||
doc/Doxyfile
|
||||
doc/doxygen.out
|
||||
doc/html/
|
||||
libtinydtls.a
|
||||
tests/ccm-test
|
||||
tests/dtls-client
|
||||
tests/dtls-server
|
||||
tests/prf-test
|
||||
tinydtls-0.6.0
|
||||
./tinydtls-0.6.0/
|
||||
TAGS
|
||||
*.patch
|
||||
.gitignore
|
||||
ecc/testecc
|
||||
ecc/testfield
|
||||
*.d
|
||||
*.hex
|
||||
*.elf
|
||||
*.map
|
||||
obj_*
|
||||
tinydtls.h
|
||||
dtls_config.h
|
||||
*.apple2enh
|
||||
*.atarixl
|
||||
*.avr-atmega128rfa1
|
||||
*.avr-raven
|
||||
*.avr-ravenlcd
|
||||
*.avr-ravenusb
|
||||
*.avr-rcb
|
||||
*.avr-zigbit
|
||||
*.c128
|
||||
*.c64
|
||||
*.cc2530dk
|
||||
*.cc2538dk
|
||||
*.cooja
|
||||
*.econotag
|
||||
*.eval-adf7xxxmb4z
|
||||
*.exp5438
|
||||
*.iris
|
||||
*.mbxxx
|
||||
*.micaz
|
||||
*.minimal-net
|
||||
*.native
|
||||
*.seedeye
|
||||
*.sensinode
|
||||
*.sky
|
||||
*.stm32test
|
||||
*.win32
|
||||
*.wismote
|
||||
*.z1
|
||||
*.z1sp
|
||||
.project
|
60
ABOUT.md
Normal file
60
ABOUT.md
Normal file
@ -0,0 +1,60 @@
|
||||
# About This Content
|
||||
|
||||
2015-12-18
|
||||
|
||||
# License
|
||||
|
||||
The Eclipse Foundation makes available all content in this plug-in
|
||||
("Content"). Unless otherwise indicated below, the Content is provided
|
||||
to you under the terms and conditions of the Eclipse Public License
|
||||
Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0
|
||||
(“EDL”). A copy of the EPL is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html and a copy of the EDL is
|
||||
available at http://www.eclipse.org/org/documents/edl-v10.php. For
|
||||
purposes of the EPL, "Program" will mean the Content.
|
||||
|
||||
If you did not receive this Content directly from the Eclipse
|
||||
Foundation, the Content is being redistributed by another party
|
||||
("Redistributor") and different terms and conditions may apply to your
|
||||
use of any object code in the Content. Check the Redistributor’s
|
||||
license that was provided with the Content. If no such license exists,
|
||||
contact the Redistributor. Unless otherwise indicated below, the terms
|
||||
and conditions of the EPL and EDL still apply to any source code in
|
||||
the Content and such source code may be obtained at
|
||||
http://www.eclipse.org.
|
||||
|
||||
# Third Party Content
|
||||
|
||||
The Content includes items that have been sourced from third parties
|
||||
as set out below. If you did not receive this Content directly from
|
||||
the Eclipse Foundation, the following is provided for informational
|
||||
purposes only, and you should look to the Redistributor’s license for
|
||||
terms and conditions of use.
|
||||
|
||||
## Uthash 1.9.9
|
||||
|
||||
[Uthash](https://troydhanson.github.io/uthash/) is an implementation
|
||||
of hash tables and linked lists for C structures by Troy D. Hanson.
|
||||
Uthash is licensed under the BSD revised license, see
|
||||
https://troydhanson.github.io/uthash/license.html,
|
||||
|
||||
## rijndael 3.0
|
||||
|
||||
The library uses an implementation of the Rijndael algorithm (AES)
|
||||
from [OpenBSD](http://www.openbsd.org/) by Vincent Rijmen, Antoon
|
||||
Bosselaers, and Paulo Barreto. The authors have placed the code in the
|
||||
public domain under the license included in the file rijndael.h (see
|
||||
http://www.openbsd.org/cgi-bin/cvsweb).
|
||||
|
||||
## SHA-256 1.0
|
||||
|
||||
The SHA-256 implementation from Aaron D. Gifford is available at
|
||||
http://www.aarongifford.com/computers/sha2-1.0.1.tgz under a
|
||||
3-clause BSD license.
|
||||
|
||||
## ECC 1.0
|
||||
|
||||
The implementation of the ECC curve secp256r1 was originally developed
|
||||
by Chris K Cockrum and has been put under MIT license for inclusion
|
||||
with tinydtls. The original source is made available in
|
||||
https://cockrum.net/Implementation_of_ECC_on_an_8-bit_microcontroller.pdf
|
12
LICENSE
Normal file
12
LICENSE
Normal file
@ -0,0 +1,12 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*******************************************************************************/
|
128
Makefile.in
Normal file
128
Makefile.in
Normal file
@ -0,0 +1,128 @@
|
||||
# Makefile for tinydtls
|
||||
#
|
||||
#
|
||||
# Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Olaf Bergmann - initial API and implementation
|
||||
#
|
||||
|
||||
# the library's version
|
||||
VERSION:=@PACKAGE_VERSION@
|
||||
|
||||
# tools
|
||||
@SET_MAKE@
|
||||
SHELL = /bin/sh
|
||||
MKDIR = mkdir
|
||||
ETAGS = @ETAGS@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
abs_builddir = @abs_builddir@
|
||||
top_builddir = @top_builddir@
|
||||
libdir = @libdir@
|
||||
includedir = @includedir@/@PACKAGE_NAME@
|
||||
package = @PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
|
||||
install := cp
|
||||
|
||||
# files and flags
|
||||
SOURCES:= dtls.c crypto.c ccm.c hmac.c netq.c peer.c dtls_time.c session.c debug.c
|
||||
SUB_OBJECTS:=aes/rijndael.o @OPT_OBJS@
|
||||
OBJECTS:= $(patsubst %.c, %.o, $(SOURCES)) $(SUB_OBJECTS)
|
||||
HEADERS:=dtls.h hmac.h debug.h dtls_config.h uthash.h numeric.h crypto.h global.h ccm.h \
|
||||
netq.h alert.h utlist.h prng.h peer.h state.h dtls_time.h session.h \
|
||||
tinydtls.h
|
||||
CFLAGS:=-Wall -pedantic -std=c99 @CFLAGS@
|
||||
CPPFLAGS:=@CPPFLAGS@ -DDTLS_CHECK_CONTENTTYPE
|
||||
SUBDIRS:=tests doc platform-specific sha2 aes ecc
|
||||
DISTSUBDIRS:=$(SUBDIRS)
|
||||
DISTDIR=$(top_builddir)/$(package)
|
||||
FILES:=Makefile.in configure configure.in dtls_config.h.in tinydtls.h.in \
|
||||
Makefile.tinydtls $(SOURCES) $(HEADERS)
|
||||
LIB:=libtinydtls.a
|
||||
LDFLAGS:=@LIBS@
|
||||
ARFLAGS:=cru
|
||||
doc:=doc
|
||||
|
||||
.PHONY: all dirs clean install dist distclean .gitignore doc TAGS
|
||||
|
||||
ifneq ("@WITH_CONTIKI@", "1")
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
all: $(LIB) dirs
|
||||
|
||||
check:
|
||||
echo DISTDIR: $(DISTDIR)
|
||||
echo top_builddir: $(top_builddir)
|
||||
$(MAKE) -C tests check
|
||||
|
||||
dirs: $(SUBDIRS)
|
||||
for dir in $^; do \
|
||||
$(MAKE) -C $$dir ; \
|
||||
done
|
||||
|
||||
$(SUB_OBJECTS)::
|
||||
$(MAKE) -C $(@D) $(@F)
|
||||
|
||||
$(LIB): $(OBJECTS)
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
ranlib $@
|
||||
|
||||
clean:
|
||||
@rm -f $(PROGRAM) main.o $(LIB) $(OBJECTS)
|
||||
for dir in $(SUBDIRS); do \
|
||||
$(MAKE) -C $$dir clean ; \
|
||||
done
|
||||
endif # WITH_CONTIKI
|
||||
|
||||
doc:
|
||||
$(MAKE) -C doc
|
||||
|
||||
distclean: clean
|
||||
@rm -rf $(DISTDIR)
|
||||
@rm -f *~ $(DISTDIR).tar.gz
|
||||
|
||||
dist: $(FILES) $(DISTSUBDIRS)
|
||||
test -d $(DISTDIR) || mkdir $(DISTDIR)
|
||||
cp $(FILES) $(DISTDIR)
|
||||
for dir in $(DISTSUBDIRS); do \
|
||||
$(MAKE) -C $$dir dist; \
|
||||
done
|
||||
tar czf $(package).tar.gz $(DISTDIR)
|
||||
|
||||
install: $(LIB) $(HEADERS) $(SUBDIRS)
|
||||
test -d $(libdir) || mkdir -p $(libdir)
|
||||
test -d $(includedir) || mkdir -p $(includedir)
|
||||
$(install) $(LIB) $(libdir)/
|
||||
$(install) $(HEADERS) $(includedir)/
|
||||
for dir in $(SUBDIRS); do \
|
||||
$(MAKE) -C $$dir install="$(install)" includedir=$(includedir) install; \
|
||||
done
|
||||
|
||||
TAGS:
|
||||
$(ETAGS) -o $@.new $(SOURCES)
|
||||
$(ETAGS) -a -o $@.new $(HEADERS)
|
||||
mv $@.new $@
|
||||
|
||||
# files that should be ignored by git
|
||||
GITIGNOREDS:= core \*~ \*.[oa] \*.gz \*.cap \*.pcap Makefile \
|
||||
autom4te.cache/ config.h config.log config.status configure \
|
||||
doc/Doxyfile doc/doxygen.out doc/html/ $(LIB) tests/ccm-test \
|
||||
tests/dtls-client tests/dtls-server tests/prf-test $(package) \
|
||||
$(DISTDIR)/ TAGS \*.patch .gitignore ecc/testecc ecc/testfield \
|
||||
\*.d \*.hex \*.elf \*.map obj_\* tinydtls.h dtls_config.h \
|
||||
$(addprefix \*., $(notdir $(wildcard ../../platform/*))) \
|
||||
.project
|
||||
|
||||
.gitignore:
|
||||
echo $(GITIGNOREDS) | sed 's/ /\n/g' > $@
|
||||
|
36
Makefile.tinydtls
Normal file
36
Makefile.tinydtls
Normal file
@ -0,0 +1,36 @@
|
||||
# This is a -*- Makefile -*-
|
||||
|
||||
ifeq ($(TARGET), redbee-econotag)
|
||||
CFLAGS += -DSHA2_USE_INTTYPES_H=1 -DLITTLE_ENDIAN=3412 -DBYTE_ORDER=LITTLE_ENDIAN
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET), wismote)
|
||||
CFLAGS += -DSHA2_USE_INTTYPES_H=1 -DLITTLE_ENDIAN=3412 -DBYTE_ORDER=LITTLE_ENDIAN
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET), exp5438)
|
||||
CFLAGS += -DSHA2_USE_INTTYPES_H=1 -DLITTLE_ENDIAN=3412 -DBYTE_ORDER=LITTLE_ENDIAN
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET), native)
|
||||
CFLAGS += -DSHA2_USE_INTTYPES_H=1
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET), minimal-net)
|
||||
CFLAGS += -DSHA2_USE_INTTYPES_H=1
|
||||
endif
|
||||
|
||||
CFLAGS += -DDTLSv12 -DWITH_SHA256
|
||||
tinydtls_src = dtls.c crypto.c hmac.c rijndael.c sha2.c ccm.c netq.c ecc.c dtls_time.c peer.c session.c
|
||||
|
||||
# This adds support for TLS_PSK_WITH_AES_128_CCM_8
|
||||
CFLAGS += -DDTLS_PSK
|
||||
|
||||
# This adds support for TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
|
||||
CFLAGS += -DDTLS_ECC
|
||||
tinydtls_src += ecc.c
|
||||
|
||||
# This activates debugging support
|
||||
# CFLAGS += -DNDEBUG
|
||||
tinydtls_src += debug.c
|
||||
|
26
README
Normal file
26
README
Normal file
@ -0,0 +1,26 @@
|
||||
CONTENTS
|
||||
|
||||
This library contains functions and structures that can help
|
||||
constructing a single-threaded UDP server with DTLS support in
|
||||
C99. The following components are available:
|
||||
|
||||
* dtls
|
||||
Basic support for DTLS with pre-shared key mode.
|
||||
|
||||
* tests
|
||||
The subdirectory tests contains test programs that show how each
|
||||
component is used.
|
||||
|
||||
BUILDING
|
||||
|
||||
When using the code from the git repository at sourceforge, invoke
|
||||
'autoreconf' to re-create the configure script. To build for Contiki,
|
||||
place tinydtls into Contiki's apps directory and call
|
||||
./configure --with-contiki.
|
||||
|
||||
After configuration, invoke make to build the library and associated
|
||||
test programs. To add tinydtls as Contiki application, drop it into
|
||||
the apps directory and add the following line to your Makefile:
|
||||
|
||||
APPS += tinydtls/aes tinydtls/sha2 tinydtls/ecc tinydtls
|
||||
|
67
aes/Makefile.in
Normal file
67
aes/Makefile.in
Normal file
@ -0,0 +1,67 @@
|
||||
# Makefile for tinydtls
|
||||
#
|
||||
# Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Olaf Bergmann - initial API and implementation
|
||||
#
|
||||
|
||||
# the library's version
|
||||
VERSION:=@PACKAGE_VERSION@
|
||||
|
||||
# tools
|
||||
@SET_MAKE@
|
||||
SHELL = /bin/sh
|
||||
MKDIR = mkdir
|
||||
|
||||
abs_builddir = @abs_builddir@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir:= @top_srcdir@
|
||||
|
||||
SOURCES:= rijndael.c
|
||||
HEADERS:= rijndael.h
|
||||
OBJECTS:= $(patsubst %.c, %.o, $(SOURCES))
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
CFLAGS=-Wall -std=c99 -pedantic @CFLAGS@
|
||||
LDLIBS=@LIBS@
|
||||
FILES:=Makefile.in $(SOURCES) $(HEADERS)
|
||||
DISTDIR=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
|
||||
.PHONY: all dirs clean install dist distclean .gitignore doc
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
all:
|
||||
|
||||
check:
|
||||
echo DISTDIR: $(DISTDIR)
|
||||
echo top_builddir: $(top_builddir)
|
||||
|
||||
clean:
|
||||
@rm -f $(PROGRAMS) main.o $(LIB) $(OBJECTS)
|
||||
for dir in $(SUBDIRS); do \
|
||||
$(MAKE) -C $$dir clean ; \
|
||||
done
|
||||
|
||||
distclean: clean
|
||||
@rm -rf $(DISTDIR)
|
||||
@rm -f *~ $(DISTDIR).tar.gz
|
||||
|
||||
dist: $(FILES)
|
||||
test -d $(DISTDIR)/aes || mkdir $(DISTDIR)/aes
|
||||
cp -p $(FILES) $(DISTDIR)/aes
|
||||
|
||||
install: $(HEADERS)
|
||||
test -d $(includedir)/aes || mkdir -p $(includedir)/aes
|
||||
$(install) $(HEADERS) $(includedir)/aes
|
||||
|
||||
.gitignore:
|
||||
echo "core\n*~\n*.[oa]\n*.gz\n*.cap\n$(PROGRAM)\n$(DISTDIR)\n.gitignore" >$@
|
73
alert.h
Normal file
73
alert.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file alert.h
|
||||
* @brief DTLS alert protocol
|
||||
*/
|
||||
|
||||
#ifndef _DTLS_ALERT_H_
|
||||
#define _DTLS_ALERT_H_
|
||||
|
||||
typedef enum {
|
||||
DTLS_ALERT_LEVEL_WARNING=1,
|
||||
DTLS_ALERT_LEVEL_FATAL=2
|
||||
} dtls_alert_level_t;
|
||||
|
||||
typedef enum {
|
||||
DTLS_ALERT_CLOSE_NOTIFY = 0, /* close_notify */
|
||||
DTLS_ALERT_UNEXPECTED_MESSAGE = 10, /* unexpected_message */
|
||||
DTLS_ALERT_BAD_RECORD_MAC = 20, /* bad_record_mac */
|
||||
DTLS_ALERT_RECORD_OVERFLOW = 22, /* record_overflow */
|
||||
DTLS_ALERT_DECOMPRESSION_FAILURE = 30, /* decompression_failure */
|
||||
DTLS_ALERT_HANDSHAKE_FAILURE = 40, /* handshake_failure */
|
||||
DTLS_ALERT_BAD_CERTIFICATE = 42, /* bad_certificate */
|
||||
DTLS_ALERT_UNSUPPORTED_CERTIFICATE = 43, /* unsupported_certificate */
|
||||
DTLS_ALERT_CERTIFICATE_REVOKED = 44, /* certificate_revoked */
|
||||
DTLS_ALERT_CERTIFICATE_EXPIRED = 45, /* certificate_expired */
|
||||
DTLS_ALERT_CERTIFICATE_UNKNOWN = 46, /* certificate_unknown */
|
||||
DTLS_ALERT_ILLEGAL_PARAMETER = 47, /* illegal_parameter */
|
||||
DTLS_ALERT_UNKNOWN_CA = 48, /* unknown_ca */
|
||||
DTLS_ALERT_ACCESS_DENIED = 49, /* access_denied */
|
||||
DTLS_ALERT_DECODE_ERROR = 50, /* decode_error */
|
||||
DTLS_ALERT_DECRYPT_ERROR = 51, /* decrypt_error */
|
||||
DTLS_ALERT_PROTOCOL_VERSION = 70, /* protocol_version */
|
||||
DTLS_ALERT_INSUFFICIENT_SECURITY = 71, /* insufficient_security */
|
||||
DTLS_ALERT_INTERNAL_ERROR = 80, /* internal_error */
|
||||
DTLS_ALERT_USER_CANCELED = 90, /* user_canceled */
|
||||
DTLS_ALERT_NO_RENEGOTIATION = 100, /* no_renegotiation */
|
||||
DTLS_ALERT_UNSUPPORTED_EXTENSION = 110 /* unsupported_extension */
|
||||
} dtls_alert_t;
|
||||
|
||||
#define DTLS_EVENT_CONNECT 0x01DC /**< initiated handshake */
|
||||
#define DTLS_EVENT_CONNECTED 0x01DE /**< handshake or re-negotiation
|
||||
* has finished */
|
||||
#define DTLS_EVENT_RENEGOTIATE 0x01DF /**< re-negotiation has started */
|
||||
|
||||
static inline int
|
||||
dtls_alert_create(dtls_alert_level_t level, dtls_alert_t desc)
|
||||
{
|
||||
return -((level << 8) | desc);
|
||||
}
|
||||
|
||||
static inline int
|
||||
dtls_alert_fatal_create(dtls_alert_t desc)
|
||||
{
|
||||
return dtls_alert_create(DTLS_ALERT_LEVEL_FATAL, desc);
|
||||
}
|
||||
|
||||
#endif /* _DTLS_ALERT_H_ */
|
303
ccm.c
Normal file
303
ccm.c
Normal file
@ -0,0 +1,303 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "dtls_config.h"
|
||||
#include "global.h"
|
||||
#include "numeric.h"
|
||||
#include "ccm.h"
|
||||
|
||||
#ifdef HAVE_ASSERT_H
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#define CCM_FLAGS(A,M,L) (((A > 0) << 6) | (((M - 2)/2) << 3) | (L - 1))
|
||||
|
||||
#define MASK_L(_L) ((1 << 8 * _L) - 1)
|
||||
|
||||
#define SET_COUNTER(A,L,cnt,C) { \
|
||||
int i; \
|
||||
memset((A) + DTLS_CCM_BLOCKSIZE - (L), 0, (L)); \
|
||||
(C) = (cnt) & MASK_L(L); \
|
||||
for (i = DTLS_CCM_BLOCKSIZE - 1; (C) && (i > (L)); --i, (C) >>= 8) \
|
||||
(A)[i] |= (C) & 0xFF; \
|
||||
}
|
||||
|
||||
static inline void
|
||||
block0(size_t M, /* number of auth bytes */
|
||||
size_t L, /* number of bytes to encode message length */
|
||||
size_t la, /* l(a) octets additional authenticated data */
|
||||
size_t lm, /* l(m) message length */
|
||||
unsigned char nonce[DTLS_CCM_BLOCKSIZE],
|
||||
unsigned char *result) {
|
||||
int i;
|
||||
|
||||
result[0] = CCM_FLAGS(la, M, L);
|
||||
|
||||
/* copy the nonce */
|
||||
memcpy(result + 1, nonce, DTLS_CCM_BLOCKSIZE - L - 1);
|
||||
|
||||
for (i=0; i < L; i++) {
|
||||
result[15-i] = lm & 0xff;
|
||||
lm >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the CBC-MAC for the additional authentication data that
|
||||
* is sent in cleartext.
|
||||
*
|
||||
* \param ctx The crypto context for the AES encryption.
|
||||
* \param msg The message starting with the additional authentication data.
|
||||
* \param la The number of additional authentication bytes in \p msg.
|
||||
* \param B The input buffer for crypto operations. When this function
|
||||
* is called, \p B must be initialized with \c B0 (the first
|
||||
* authentication block.
|
||||
* \param X The output buffer where the result of the CBC calculation
|
||||
* is placed.
|
||||
* \return The result is written to \p X.
|
||||
*/
|
||||
static void
|
||||
add_auth_data(rijndael_ctx *ctx, const unsigned char *msg, size_t la,
|
||||
unsigned char B[DTLS_CCM_BLOCKSIZE],
|
||||
unsigned char X[DTLS_CCM_BLOCKSIZE]) {
|
||||
size_t i,j;
|
||||
|
||||
rijndael_encrypt(ctx, B, X);
|
||||
|
||||
memset(B, 0, DTLS_CCM_BLOCKSIZE);
|
||||
|
||||
if (!la)
|
||||
return;
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
if (la < 0xFF00) { /* 2^16 - 2^8 */
|
||||
j = 2;
|
||||
dtls_int_to_uint16(B, la);
|
||||
} else if (la <= UINT32_MAX) {
|
||||
j = 6;
|
||||
dtls_int_to_uint16(B, 0xFFFE);
|
||||
dtls_int_to_uint32(B+2, la);
|
||||
} else {
|
||||
j = 10;
|
||||
dtls_int_to_uint16(B, 0xFFFF);
|
||||
dtls_int_to_uint64(B+2, la);
|
||||
}
|
||||
#else /* WITH_CONTIKI */
|
||||
/* With Contiki, we are building for small devices and thus
|
||||
* anticipate that the number of additional authentication bytes
|
||||
* will not exceed 65280 bytes (0xFF00) and we can skip the
|
||||
* workarounds required for j=6 and j=10 on devices with a word size
|
||||
* of 32 bits or 64 bits, respectively.
|
||||
*/
|
||||
|
||||
assert(la < 0xFF00);
|
||||
j = 2;
|
||||
dtls_int_to_uint16(B, la);
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
i = min(DTLS_CCM_BLOCKSIZE - j, la);
|
||||
memcpy(B + j, msg, i);
|
||||
la -= i;
|
||||
msg += i;
|
||||
|
||||
memxor(B, X, DTLS_CCM_BLOCKSIZE);
|
||||
|
||||
rijndael_encrypt(ctx, B, X);
|
||||
|
||||
while (la > DTLS_CCM_BLOCKSIZE) {
|
||||
for (i = 0; i < DTLS_CCM_BLOCKSIZE; ++i)
|
||||
B[i] = X[i] ^ *msg++;
|
||||
la -= DTLS_CCM_BLOCKSIZE;
|
||||
|
||||
rijndael_encrypt(ctx, B, X);
|
||||
}
|
||||
|
||||
if (la) {
|
||||
memset(B, 0, DTLS_CCM_BLOCKSIZE);
|
||||
memcpy(B, msg, la);
|
||||
memxor(B, X, DTLS_CCM_BLOCKSIZE);
|
||||
|
||||
rijndael_encrypt(ctx, B, X);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
encrypt(rijndael_ctx *ctx, size_t L, unsigned long counter,
|
||||
unsigned char *msg, size_t len,
|
||||
unsigned char A[DTLS_CCM_BLOCKSIZE],
|
||||
unsigned char S[DTLS_CCM_BLOCKSIZE]) {
|
||||
|
||||
static unsigned long counter_tmp;
|
||||
|
||||
SET_COUNTER(A, L, counter, counter_tmp);
|
||||
rijndael_encrypt(ctx, A, S);
|
||||
memxor(msg, S, len);
|
||||
}
|
||||
|
||||
static inline void
|
||||
mac(rijndael_ctx *ctx,
|
||||
unsigned char *msg, size_t len,
|
||||
unsigned char B[DTLS_CCM_BLOCKSIZE],
|
||||
unsigned char X[DTLS_CCM_BLOCKSIZE]) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
B[i] = X[i] ^ msg[i];
|
||||
|
||||
rijndael_encrypt(ctx, B, X);
|
||||
|
||||
}
|
||||
|
||||
long int
|
||||
dtls_ccm_encrypt_message(rijndael_ctx *ctx, size_t M, size_t L,
|
||||
unsigned char nonce[DTLS_CCM_BLOCKSIZE],
|
||||
unsigned char *msg, size_t lm,
|
||||
const unsigned char *aad, size_t la) {
|
||||
size_t i, len;
|
||||
unsigned long counter_tmp;
|
||||
unsigned long counter = 1; /* \bug does not work correctly on ia32 when
|
||||
lm >= 2^16 */
|
||||
unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */
|
||||
unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */
|
||||
unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */
|
||||
unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */
|
||||
|
||||
len = lm; /* save original length */
|
||||
/* create the initial authentication block B0 */
|
||||
block0(M, L, la, lm, nonce, B);
|
||||
add_auth_data(ctx, aad, la, B, X);
|
||||
|
||||
/* initialize block template */
|
||||
A[0] = L-1;
|
||||
|
||||
/* copy the nonce */
|
||||
memcpy(A + 1, nonce, DTLS_CCM_BLOCKSIZE - L - 1);
|
||||
|
||||
while (lm >= DTLS_CCM_BLOCKSIZE) {
|
||||
/* calculate MAC */
|
||||
mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X);
|
||||
|
||||
/* encrypt */
|
||||
encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S);
|
||||
|
||||
/* update local pointers */
|
||||
lm -= DTLS_CCM_BLOCKSIZE;
|
||||
msg += DTLS_CCM_BLOCKSIZE;
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (lm) {
|
||||
/* Calculate MAC. The remainder of B must be padded with zeroes, so
|
||||
* B is constructed to contain X ^ msg for the first lm bytes (done in
|
||||
* mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes
|
||||
* (i.e., we can use memcpy() here).
|
||||
*/
|
||||
memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm);
|
||||
mac(ctx, msg, lm, B, X);
|
||||
|
||||
/* encrypt */
|
||||
encrypt(ctx, L, counter, msg, lm, A, S);
|
||||
|
||||
/* update local pointers */
|
||||
msg += lm;
|
||||
}
|
||||
|
||||
/* calculate S_0 */
|
||||
SET_COUNTER(A, L, 0, counter_tmp);
|
||||
rijndael_encrypt(ctx, A, S);
|
||||
|
||||
for (i = 0; i < M; ++i)
|
||||
*msg++ = X[i] ^ S[i];
|
||||
|
||||
return len + M;
|
||||
}
|
||||
|
||||
long int
|
||||
dtls_ccm_decrypt_message(rijndael_ctx *ctx, size_t M, size_t L,
|
||||
unsigned char nonce[DTLS_CCM_BLOCKSIZE],
|
||||
unsigned char *msg, size_t lm,
|
||||
const unsigned char *aad, size_t la) {
|
||||
|
||||
size_t len;
|
||||
unsigned long counter_tmp;
|
||||
unsigned long counter = 1; /* \bug does not work correctly on ia32 when
|
||||
lm >= 2^16 */
|
||||
unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */
|
||||
unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */
|
||||
unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */
|
||||
unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */
|
||||
|
||||
if (lm < M)
|
||||
goto error;
|
||||
|
||||
len = lm; /* save original length */
|
||||
lm -= M; /* detract MAC size*/
|
||||
|
||||
/* create the initial authentication block B0 */
|
||||
block0(M, L, la, lm, nonce, B);
|
||||
add_auth_data(ctx, aad, la, B, X);
|
||||
|
||||
/* initialize block template */
|
||||
A[0] = L-1;
|
||||
|
||||
/* copy the nonce */
|
||||
memcpy(A + 1, nonce, DTLS_CCM_BLOCKSIZE - L - 1);
|
||||
|
||||
while (lm >= DTLS_CCM_BLOCKSIZE) {
|
||||
/* decrypt */
|
||||
encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S);
|
||||
|
||||
/* calculate MAC */
|
||||
mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X);
|
||||
|
||||
/* update local pointers */
|
||||
lm -= DTLS_CCM_BLOCKSIZE;
|
||||
msg += DTLS_CCM_BLOCKSIZE;
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (lm) {
|
||||
/* decrypt */
|
||||
encrypt(ctx, L, counter, msg, lm, A, S);
|
||||
|
||||
/* Calculate MAC. Note that msg ends in the MAC so we must
|
||||
* construct B to contain X ^ msg for the first lm bytes (done in
|
||||
* mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes
|
||||
* (i.e., we can use memcpy() here).
|
||||
*/
|
||||
memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm);
|
||||
mac(ctx, msg, lm, B, X);
|
||||
|
||||
/* update local pointers */
|
||||
msg += lm;
|
||||
}
|
||||
|
||||
/* calculate S_0 */
|
||||
SET_COUNTER(A, L, 0, counter_tmp);
|
||||
rijndael_encrypt(ctx, A, S);
|
||||
|
||||
memxor(msg, S, M);
|
||||
|
||||
/* return length if MAC is valid, otherwise continue with error handling */
|
||||
if (equals(X, msg, M))
|
||||
return len - M;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
61
ccm.h
Normal file
61
ccm.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _DTLS_CCM_H_
|
||||
#define _DTLS_CCM_H_
|
||||
|
||||
#include "aes/rijndael.h"
|
||||
|
||||
/* implementation of Counter Mode CBC-MAC, RFC 3610 */
|
||||
|
||||
#define DTLS_CCM_BLOCKSIZE 16 /**< size of hmac blocks */
|
||||
#define DTLS_CCM_MAX 16 /**< max number of bytes in digest */
|
||||
#define DTLS_CCM_NONCE_SIZE 12 /**< size of nonce */
|
||||
|
||||
/**
|
||||
* Authenticates and encrypts a message using AES in CCM mode. Please
|
||||
* see also RFC 3610 for the meaning of \p M, \p L, \p lm and \p la.
|
||||
*
|
||||
* \param ctx The initialized rijndael_ctx object to be used for AES operations.
|
||||
* \param M The number of authentication octets.
|
||||
* \param L The number of bytes used to encode the message length.
|
||||
* \param N The nonce value to use. You must provide \c DTLS_CCM_BLOCKSIZE
|
||||
* nonce octets, although only the first \c 16 - \p L - 1 are used.
|
||||
* \param msg The message to encrypt. The first \p la octets are additional
|
||||
* authentication data that will be cleartext. Note that the
|
||||
* encryption operation modifies the contents of \p msg and adds
|
||||
* \p M bytes MAC. Therefore, the buffer must be at least
|
||||
* \p lm + \p M bytes large.
|
||||
* \param lm The actual length of \p msg.
|
||||
* \param aad A pointer to the additional authentication data (can be \c NULL if
|
||||
* \p la is zero).
|
||||
* \param la The number of additional authentication octets (may be zero).
|
||||
* \return FIXME
|
||||
*/
|
||||
long int
|
||||
dtls_ccm_encrypt_message(rijndael_ctx *ctx, size_t M, size_t L,
|
||||
unsigned char nonce[DTLS_CCM_BLOCKSIZE],
|
||||
unsigned char *msg, size_t lm,
|
||||
const unsigned char *aad, size_t la);
|
||||
|
||||
long int
|
||||
dtls_ccm_decrypt_message(rijndael_ctx *ctx, size_t M, size_t L,
|
||||
unsigned char nonce[DTLS_CCM_BLOCKSIZE],
|
||||
unsigned char *msg, size_t lm,
|
||||
const unsigned char *aad, size_t la);
|
||||
|
||||
#endif /* _DTLS_CCM_H_ */
|
111
configure.in
Normal file
111
configure.in
Normal file
@ -0,0 +1,111 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
#
|
||||
# Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Olaf Bergmann - initial API and implementation
|
||||
# Hauke Mehrtens - memory optimization, ECC integration
|
||||
|
||||
AC_PREREQ([2.65])
|
||||
AC_INIT([tinydtls], [0.8.2])
|
||||
AC_CONFIG_SRCDIR([dtls.c])
|
||||
dnl AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AC_ARG_WITH(contiki,
|
||||
[AS_HELP_STRING([--with-contiki],[build libtinydtls for the Contiki OS])],
|
||||
[AC_DEFINE(WITH_CONTIKI,1,[Define to 1 if building for Contiki.])
|
||||
WITH_CONTIKI=1],
|
||||
[])
|
||||
|
||||
AC_PATH_PROG(DOXYGEN, doxygen, [:])
|
||||
AC_PATH_PROG(ETAGS, etags, [/bin/false])
|
||||
|
||||
if test "${with_contiki}" != "yes" ; then
|
||||
# Checks for programs.
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_CC
|
||||
AC_PROG_RANLIB
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
# Checks for libraries.
|
||||
AC_SEARCH_LIBS([gethostbyname], [nsl])
|
||||
AC_SEARCH_LIBS([socket], [socket])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(debug,
|
||||
[AS_HELP_STRING([--without-debug],[disable all debug output and assertions])],
|
||||
[CPPFLAGS="${CPPFLAGS} -DNDEBUG"
|
||||
NDEBUG=1],
|
||||
[])
|
||||
|
||||
AC_ARG_WITH(ecc,
|
||||
[AS_HELP_STRING([--without-ecc],[disable support for TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8])],
|
||||
[],
|
||||
[AC_DEFINE(DTLS_ECC, 1, [Define to 1 if building with ECC support.])
|
||||
OPT_OBJS="${OPT_OBJS} ecc/ecc.o"
|
||||
DTLS_ECC=1])
|
||||
|
||||
AC_ARG_WITH(psk,
|
||||
[AS_HELP_STRING([--without-psk],[disable support for TLS_PSK_WITH_AES_128_CCM_8])],
|
||||
[],
|
||||
[AC_DEFINE(DTLS_PSK, 1, [Define to 1 if building with PSK support])
|
||||
DTLS_PSK=1])
|
||||
|
||||
CPPFLAGS="${CPPFLAGS} -DDTLSv12 -DWITH_SHA256"
|
||||
OPT_OBJS="${OPT_OBJS} sha2/sha2.o"
|
||||
|
||||
AC_SUBST(OPT_OBJS)
|
||||
AC_SUBST(NDEBUG)
|
||||
AC_SUBST(WITH_CONTIKI)
|
||||
AC_SUBST(DTLS_ECC)
|
||||
AC_SUBST(DTLS_PSK)
|
||||
|
||||
if test "${with_contiki}" = "yes" ; then
|
||||
AC_MSG_NOTICE([skipping header checks for Contiki])
|
||||
else
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([assert.h arpa/inet.h fcntl.h inttypes.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h strings.h sys/param.h sys/socket.h unistd.h])
|
||||
|
||||
AC_CHECK_HEADERS([sys/time.h time.h])
|
||||
AC_CHECK_HEADERS([sys/types.h sys/stat.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_INLINE
|
||||
AC_TYPE_SIZE_T
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_in6.sin6_len],
|
||||
[AC_DEFINE(HAVE_SOCKADDR_IN6_SIN6_LEN, [1],
|
||||
[Define to 1 if struct sockaddr_in6 has a member sin6_len.])], [],
|
||||
[#include <netinet/in.h>])
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_MALLOC
|
||||
AC_CHECK_FUNCS([memset select socket strdup strerror strnlen fls vprintf])
|
||||
fi
|
||||
|
||||
AC_CONFIG_HEADERS([dtls_config.h tinydtls.h])
|
||||
|
||||
# Adds Contiki-specific definitions to the end of dtls_config.h
|
||||
AH_BOTTOM([
|
||||
#ifdef WITH_CONTIKI
|
||||
#include "platform-specific/platform.h"
|
||||
#endif])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
doc/Makefile
|
||||
doc/Doxyfile
|
||||
tests/Makefile
|
||||
platform-specific/Makefile
|
||||
sha2/Makefile
|
||||
aes/Makefile
|
||||
ecc/Makefile])
|
||||
AC_OUTPUT
|
565
crypto.c
Normal file
565
crypto.c
Normal file
@ -0,0 +1,565 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "dtls_config.h"
|
||||
|
||||
#ifdef HAVE_ASSERT_H
|
||||
#include <assert.h>
|
||||
#else
|
||||
#define assert(x)
|
||||
#endif
|
||||
|
||||
#include "global.h"
|
||||
#include "debug.h"
|
||||
#include "numeric.h"
|
||||
#include "dtls.h"
|
||||
#include "crypto.h"
|
||||
#include "ccm.h"
|
||||
#include "ecc/ecc.h"
|
||||
#include "prng.h"
|
||||
#include "netq.h"
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#define HMAC_UPDATE_SEED(Context,Seed,Length) \
|
||||
if (Seed) dtls_hmac_update(Context, (Seed), (Length))
|
||||
|
||||
static struct dtls_cipher_context_t cipher_context;
|
||||
#ifndef WITH_CONTIKI
|
||||
static pthread_mutex_t cipher_context_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
static struct dtls_cipher_context_t *dtls_cipher_context_get(void)
|
||||
{
|
||||
#ifndef WITH_CONTIKI
|
||||
pthread_mutex_lock(&cipher_context_mutex);
|
||||
#endif
|
||||
return &cipher_context;
|
||||
}
|
||||
|
||||
static void dtls_cipher_context_release(void)
|
||||
{
|
||||
#ifndef WITH_CONTIKI
|
||||
pthread_mutex_unlock(&cipher_context_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
void crypto_init()
|
||||
{
|
||||
}
|
||||
|
||||
static dtls_handshake_parameters_t *dtls_handshake_malloc() {
|
||||
return malloc(sizeof(dtls_handshake_parameters_t));
|
||||
}
|
||||
|
||||
static void dtls_handshake_dealloc(dtls_handshake_parameters_t *handshake) {
|
||||
free(handshake);
|
||||
}
|
||||
|
||||
static dtls_security_parameters_t *dtls_security_malloc() {
|
||||
return malloc(sizeof(dtls_security_parameters_t));
|
||||
}
|
||||
|
||||
static void dtls_security_dealloc(dtls_security_parameters_t *security) {
|
||||
free(security);
|
||||
}
|
||||
#else /* WITH_CONTIKI */
|
||||
|
||||
#include "memb.h"
|
||||
MEMB(handshake_storage, dtls_handshake_parameters_t, DTLS_HANDSHAKE_MAX);
|
||||
MEMB(security_storage, dtls_security_parameters_t, DTLS_SECURITY_MAX);
|
||||
|
||||
void crypto_init() {
|
||||
memb_init(&handshake_storage);
|
||||
memb_init(&security_storage);
|
||||
}
|
||||
|
||||
static dtls_handshake_parameters_t *dtls_handshake_malloc() {
|
||||
return memb_alloc(&handshake_storage);
|
||||
}
|
||||
|
||||
static void dtls_handshake_dealloc(dtls_handshake_parameters_t *handshake) {
|
||||
memb_free(&handshake_storage, handshake);
|
||||
}
|
||||
|
||||
static dtls_security_parameters_t *dtls_security_malloc() {
|
||||
return memb_alloc(&security_storage);
|
||||
}
|
||||
|
||||
static void dtls_security_dealloc(dtls_security_parameters_t *security) {
|
||||
memb_free(&security_storage, security);
|
||||
}
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
dtls_handshake_parameters_t *dtls_handshake_new()
|
||||
{
|
||||
dtls_handshake_parameters_t *handshake;
|
||||
|
||||
handshake = dtls_handshake_malloc();
|
||||
if (!handshake) {
|
||||
dtls_crit("can not allocate a handshake struct\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(handshake, 0, sizeof(*handshake));
|
||||
|
||||
if (handshake) {
|
||||
/* initialize the handshake hash wrt. the hard-coded DTLS version */
|
||||
dtls_debug("DTLSv12: initialize HASH_SHA256\n");
|
||||
/* TLS 1.2: PRF(secret, label, seed) = P_<hash>(secret, label + seed) */
|
||||
/* FIXME: we use the default SHA256 here, might need to support other
|
||||
hash functions as well */
|
||||
dtls_hash_init(&handshake->hs_state.hs_hash);
|
||||
}
|
||||
return handshake;
|
||||
}
|
||||
|
||||
void dtls_handshake_free(dtls_handshake_parameters_t *handshake)
|
||||
{
|
||||
if (!handshake)
|
||||
return;
|
||||
|
||||
netq_delete_all(&handshake->reorder_queue);
|
||||
dtls_handshake_dealloc(handshake);
|
||||
}
|
||||
|
||||
dtls_security_parameters_t *dtls_security_new()
|
||||
{
|
||||
dtls_security_parameters_t *security;
|
||||
|
||||
security = dtls_security_malloc();
|
||||
if (!security) {
|
||||
dtls_crit("can not allocate a security struct\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(security, 0, sizeof(*security));
|
||||
|
||||
if (security) {
|
||||
security->cipher = TLS_NULL_WITH_NULL_NULL;
|
||||
security->compression = TLS_COMPRESSION_NULL;
|
||||
}
|
||||
return security;
|
||||
}
|
||||
|
||||
void dtls_security_free(dtls_security_parameters_t *security)
|
||||
{
|
||||
if (!security)
|
||||
return;
|
||||
|
||||
dtls_security_dealloc(security);
|
||||
}
|
||||
|
||||
size_t
|
||||
dtls_p_hash(dtls_hashfunc_t h,
|
||||
const unsigned char *key, size_t keylen,
|
||||
const unsigned char *label, size_t labellen,
|
||||
const unsigned char *random1, size_t random1len,
|
||||
const unsigned char *random2, size_t random2len,
|
||||
unsigned char *buf, size_t buflen) {
|
||||
dtls_hmac_context_t *hmac_a, *hmac_p;
|
||||
|
||||
unsigned char A[DTLS_HMAC_DIGEST_SIZE];
|
||||
unsigned char tmp[DTLS_HMAC_DIGEST_SIZE];
|
||||
size_t dlen; /* digest length */
|
||||
size_t len = 0; /* result length */
|
||||
|
||||
hmac_a = dtls_hmac_new(key, keylen);
|
||||
if (!hmac_a)
|
||||
return 0;
|
||||
|
||||
/* calculate A(1) from A(0) == seed */
|
||||
HMAC_UPDATE_SEED(hmac_a, label, labellen);
|
||||
HMAC_UPDATE_SEED(hmac_a, random1, random1len);
|
||||
HMAC_UPDATE_SEED(hmac_a, random2, random2len);
|
||||
|
||||
dlen = dtls_hmac_finalize(hmac_a, A);
|
||||
|
||||
hmac_p = dtls_hmac_new(key, keylen);
|
||||
if (!hmac_p)
|
||||
goto error;
|
||||
|
||||
while (len + dlen < buflen) {
|
||||
|
||||
/* FIXME: rewrite loop to avoid superflous call to dtls_hmac_init() */
|
||||
dtls_hmac_init(hmac_p, key, keylen);
|
||||
dtls_hmac_update(hmac_p, A, dlen);
|
||||
|
||||
HMAC_UPDATE_SEED(hmac_p, label, labellen);
|
||||
HMAC_UPDATE_SEED(hmac_p, random1, random1len);
|
||||
HMAC_UPDATE_SEED(hmac_p, random2, random2len);
|
||||
|
||||
len += dtls_hmac_finalize(hmac_p, tmp);
|
||||
memcpy(buf, tmp, dlen);
|
||||
buf += dlen;
|
||||
|
||||
/* calculate A(i+1) */
|
||||
dtls_hmac_init(hmac_a, key, keylen);
|
||||
dtls_hmac_update(hmac_a, A, dlen);
|
||||
dtls_hmac_finalize(hmac_a, A);
|
||||
}
|
||||
|
||||
dtls_hmac_init(hmac_p, key, keylen);
|
||||
dtls_hmac_update(hmac_p, A, dlen);
|
||||
|
||||
HMAC_UPDATE_SEED(hmac_p, label, labellen);
|
||||
HMAC_UPDATE_SEED(hmac_p, random1, random1len);
|
||||
HMAC_UPDATE_SEED(hmac_p, random2, random2len);
|
||||
|
||||
dtls_hmac_finalize(hmac_p, tmp);
|
||||
memcpy(buf, tmp, buflen - len);
|
||||
|
||||
error:
|
||||
dtls_hmac_free(hmac_a);
|
||||
dtls_hmac_free(hmac_p);
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
size_t
|
||||
dtls_prf(const unsigned char *key, size_t keylen,
|
||||
const unsigned char *label, size_t labellen,
|
||||
const unsigned char *random1, size_t random1len,
|
||||
const unsigned char *random2, size_t random2len,
|
||||
unsigned char *buf, size_t buflen) {
|
||||
|
||||
/* Clear the result buffer */
|
||||
memset(buf, 0, buflen);
|
||||
return dtls_p_hash(HASH_SHA256,
|
||||
key, keylen,
|
||||
label, labellen,
|
||||
random1, random1len,
|
||||
random2, random2len,
|
||||
buf, buflen);
|
||||
}
|
||||
|
||||
void
|
||||
dtls_mac(dtls_hmac_context_t *hmac_ctx,
|
||||
const unsigned char *record,
|
||||
const unsigned char *packet, size_t length,
|
||||
unsigned char *buf) {
|
||||
uint16 L;
|
||||
dtls_int_to_uint16(L, length);
|
||||
|
||||
assert(hmac_ctx);
|
||||
dtls_hmac_update(hmac_ctx, record +3, sizeof(uint16) + sizeof(uint48));
|
||||
dtls_hmac_update(hmac_ctx, record, sizeof(uint8) + sizeof(uint16));
|
||||
dtls_hmac_update(hmac_ctx, L, sizeof(uint16));
|
||||
dtls_hmac_update(hmac_ctx, packet, length);
|
||||
|
||||
dtls_hmac_finalize(hmac_ctx, buf);
|
||||
}
|
||||
|
||||
static size_t
|
||||
dtls_ccm_encrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, size_t srclen,
|
||||
unsigned char *buf,
|
||||
unsigned char *nounce,
|
||||
const unsigned char *aad, size_t la) {
|
||||
long int len;
|
||||
|
||||
assert(ccm_ctx);
|
||||
|
||||
len = dtls_ccm_encrypt_message(&ccm_ctx->ctx, 8 /* M */,
|
||||
max(2, 15 - DTLS_CCM_NONCE_SIZE),
|
||||
nounce,
|
||||
buf, srclen,
|
||||
aad, la);
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t
|
||||
dtls_ccm_decrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src,
|
||||
size_t srclen, unsigned char *buf,
|
||||
unsigned char *nounce,
|
||||
const unsigned char *aad, size_t la) {
|
||||
long int len;
|
||||
|
||||
assert(ccm_ctx);
|
||||
|
||||
len = dtls_ccm_decrypt_message(&ccm_ctx->ctx, 8 /* M */,
|
||||
max(2, 15 - DTLS_CCM_NONCE_SIZE),
|
||||
nounce,
|
||||
buf, srclen,
|
||||
aad, la);
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
int
|
||||
dtls_psk_pre_master_secret(unsigned char *key, size_t keylen,
|
||||
unsigned char *result, size_t result_len) {
|
||||
unsigned char *p = result;
|
||||
|
||||
if (result_len < (2 * (sizeof(uint16) + keylen))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dtls_int_to_uint16(p, keylen);
|
||||
p += sizeof(uint16);
|
||||
|
||||
memset(p, 0, keylen);
|
||||
p += keylen;
|
||||
|
||||
memcpy(p, result, sizeof(uint16));
|
||||
p += sizeof(uint16);
|
||||
|
||||
memcpy(p, key, keylen);
|
||||
|
||||
return 2 * (sizeof(uint16) + keylen);
|
||||
}
|
||||
#endif /* DTLS_PSK */
|
||||
|
||||
#ifdef DTLS_ECC
|
||||
static void dtls_ec_key_to_uint32(const unsigned char *key, size_t key_size,
|
||||
uint32_t *result) {
|
||||
int i;
|
||||
|
||||
for (i = (key_size / sizeof(uint32_t)) - 1; i >= 0 ; i--) {
|
||||
*result = dtls_uint32_to_int(&key[i * sizeof(uint32_t)]);
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
static void dtls_ec_key_from_uint32(const uint32_t *key, size_t key_size,
|
||||
unsigned char *result) {
|
||||
int i;
|
||||
|
||||
for (i = (key_size / sizeof(uint32_t)) - 1; i >= 0 ; i--) {
|
||||
dtls_int_to_uint32(result, key[i]);
|
||||
result += 4;
|
||||
}
|
||||
}
|
||||
|
||||
int dtls_ec_key_from_uint32_asn1(const uint32_t *key, size_t key_size,
|
||||
unsigned char *buf) {
|
||||
int i;
|
||||
unsigned char *buf_orig = buf;
|
||||
int first = 1;
|
||||
|
||||
for (i = (key_size / sizeof(uint32_t)) - 1; i >= 0 ; i--) {
|
||||
if (key[i] == 0)
|
||||
continue;
|
||||
/* the first bit has to be set to zero, to indicate a poritive integer */
|
||||
if (first && key[i] & 0x80000000) {
|
||||
*buf = 0;
|
||||
buf++;
|
||||
dtls_int_to_uint32(buf, key[i]);
|
||||
buf += 4;
|
||||
} else if (first && !(key[i] & 0xFF800000)) {
|
||||
buf[0] = (key[i] >> 16) & 0xff;
|
||||
buf[1] = (key[i] >> 8) & 0xff;
|
||||
buf[2] = key[i] & 0xff;
|
||||
buf += 3;
|
||||
} else if (first && !(key[i] & 0xFFFF8000)) {
|
||||
buf[0] = (key[i] >> 8) & 0xff;
|
||||
buf[1] = key[i] & 0xff;
|
||||
buf += 2;
|
||||
} else if (first && !(key[i] & 0xFFFFFF80)) {
|
||||
buf[0] = key[i] & 0xff;
|
||||
buf += 1;
|
||||
} else {
|
||||
dtls_int_to_uint32(buf, key[i]);
|
||||
buf += 4;
|
||||
}
|
||||
first = 0;
|
||||
}
|
||||
return buf - buf_orig;
|
||||
}
|
||||
|
||||
int dtls_ecdh_pre_master_secret(unsigned char *priv_key,
|
||||
unsigned char *pub_key_x,
|
||||
unsigned char *pub_key_y,
|
||||
size_t key_size,
|
||||
unsigned char *result,
|
||||
size_t result_len) {
|
||||
uint32_t priv[8];
|
||||
uint32_t pub_x[8];
|
||||
uint32_t pub_y[8];
|
||||
uint32_t result_x[8];
|
||||
uint32_t result_y[8];
|
||||
|
||||
if (result_len < key_size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dtls_ec_key_to_uint32(priv_key, key_size, priv);
|
||||
dtls_ec_key_to_uint32(pub_key_x, key_size, pub_x);
|
||||
dtls_ec_key_to_uint32(pub_key_y, key_size, pub_y);
|
||||
|
||||
ecc_ecdh(pub_x, pub_y, priv, result_x, result_y);
|
||||
|
||||
dtls_ec_key_from_uint32(result_x, key_size, result);
|
||||
return key_size;
|
||||
}
|
||||
|
||||
void
|
||||
dtls_ecdsa_generate_key(unsigned char *priv_key,
|
||||
unsigned char *pub_key_x,
|
||||
unsigned char *pub_key_y,
|
||||
size_t key_size) {
|
||||
uint32_t priv[8];
|
||||
uint32_t pub_x[8];
|
||||
uint32_t pub_y[8];
|
||||
|
||||
do {
|
||||
dtls_prng((unsigned char *)priv, key_size);
|
||||
} while (!ecc_is_valid_key(priv));
|
||||
|
||||
ecc_gen_pub_key(priv, pub_x, pub_y);
|
||||
|
||||
dtls_ec_key_from_uint32(priv, key_size, priv_key);
|
||||
dtls_ec_key_from_uint32(pub_x, key_size, pub_key_x);
|
||||
dtls_ec_key_from_uint32(pub_y, key_size, pub_key_y);
|
||||
}
|
||||
|
||||
/* rfc4492#section-5.4 */
|
||||
void
|
||||
dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size,
|
||||
const unsigned char *sign_hash, size_t sign_hash_size,
|
||||
uint32_t point_r[9], uint32_t point_s[9]) {
|
||||
int ret;
|
||||
uint32_t priv[8];
|
||||
uint32_t hash[8];
|
||||
uint32_t rand[8];
|
||||
|
||||
dtls_ec_key_to_uint32(priv_key, key_size, priv);
|
||||
dtls_ec_key_to_uint32(sign_hash, sign_hash_size, hash);
|
||||
do {
|
||||
dtls_prng((unsigned char *)rand, key_size);
|
||||
ret = ecc_ecdsa_sign(priv, hash, rand, point_r, point_s);
|
||||
} while (ret);
|
||||
}
|
||||
|
||||
void
|
||||
dtls_ecdsa_create_sig(const unsigned char *priv_key, size_t key_size,
|
||||
const unsigned char *client_random, size_t client_random_size,
|
||||
const unsigned char *server_random, size_t server_random_size,
|
||||
const unsigned char *keyx_params, size_t keyx_params_size,
|
||||
uint32_t point_r[9], uint32_t point_s[9]) {
|
||||
dtls_hash_ctx data;
|
||||
unsigned char sha256hash[DTLS_HMAC_DIGEST_SIZE];
|
||||
|
||||
dtls_hash_init(&data);
|
||||
dtls_hash_update(&data, client_random, client_random_size);
|
||||
dtls_hash_update(&data, server_random, server_random_size);
|
||||
dtls_hash_update(&data, keyx_params, keyx_params_size);
|
||||
dtls_hash_finalize(sha256hash, &data);
|
||||
|
||||
dtls_ecdsa_create_sig_hash(priv_key, key_size, sha256hash,
|
||||
sizeof(sha256hash), point_r, point_s);
|
||||
}
|
||||
|
||||
/* rfc4492#section-5.4 */
|
||||
int
|
||||
dtls_ecdsa_verify_sig_hash(const unsigned char *pub_key_x,
|
||||
const unsigned char *pub_key_y, size_t key_size,
|
||||
const unsigned char *sign_hash, size_t sign_hash_size,
|
||||
unsigned char *result_r, unsigned char *result_s) {
|
||||
uint32_t pub_x[8];
|
||||
uint32_t pub_y[8];
|
||||
uint32_t hash[8];
|
||||
uint32_t point_r[8];
|
||||
uint32_t point_s[8];
|
||||
|
||||
dtls_ec_key_to_uint32(pub_key_x, key_size, pub_x);
|
||||
dtls_ec_key_to_uint32(pub_key_y, key_size, pub_y);
|
||||
dtls_ec_key_to_uint32(result_r, key_size, point_r);
|
||||
dtls_ec_key_to_uint32(result_s, key_size, point_s);
|
||||
dtls_ec_key_to_uint32(sign_hash, sign_hash_size, hash);
|
||||
|
||||
return ecc_ecdsa_validate(pub_x, pub_y, hash, point_r, point_s);
|
||||
}
|
||||
|
||||
int
|
||||
dtls_ecdsa_verify_sig(const unsigned char *pub_key_x,
|
||||
const unsigned char *pub_key_y, size_t key_size,
|
||||
const unsigned char *client_random, size_t client_random_size,
|
||||
const unsigned char *server_random, size_t server_random_size,
|
||||
const unsigned char *keyx_params, size_t keyx_params_size,
|
||||
unsigned char *result_r, unsigned char *result_s) {
|
||||
dtls_hash_ctx data;
|
||||
unsigned char sha256hash[DTLS_HMAC_DIGEST_SIZE];
|
||||
|
||||
dtls_hash_init(&data);
|
||||
dtls_hash_update(&data, client_random, client_random_size);
|
||||
dtls_hash_update(&data, server_random, server_random_size);
|
||||
dtls_hash_update(&data, keyx_params, keyx_params_size);
|
||||
dtls_hash_finalize(sha256hash, &data);
|
||||
|
||||
return dtls_ecdsa_verify_sig_hash(pub_key_x, pub_key_y, key_size, sha256hash,
|
||||
sizeof(sha256hash), result_r, result_s);
|
||||
}
|
||||
#endif /* DTLS_ECC */
|
||||
|
||||
int
|
||||
dtls_encrypt(const unsigned char *src, size_t length,
|
||||
unsigned char *buf,
|
||||
unsigned char *nounce,
|
||||
unsigned char *key, size_t keylen,
|
||||
const unsigned char *aad, size_t la)
|
||||
{
|
||||
int ret;
|
||||
struct dtls_cipher_context_t *ctx = dtls_cipher_context_get();
|
||||
|
||||
ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen);
|
||||
if (ret < 0) {
|
||||
/* cleanup everything in case the key has the wrong size */
|
||||
dtls_warn("cannot set rijndael key\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (src != buf)
|
||||
memmove(buf, src, length);
|
||||
ret = dtls_ccm_encrypt(&ctx->data, src, length, buf, nounce, aad, la);
|
||||
|
||||
error:
|
||||
dtls_cipher_context_release();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
dtls_decrypt(const unsigned char *src, size_t length,
|
||||
unsigned char *buf,
|
||||
unsigned char *nounce,
|
||||
unsigned char *key, size_t keylen,
|
||||
const unsigned char *aad, size_t la)
|
||||
{
|
||||
int ret;
|
||||
struct dtls_cipher_context_t *ctx = dtls_cipher_context_get();
|
||||
|
||||
ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen);
|
||||
if (ret < 0) {
|
||||
/* cleanup everything in case the key has the wrong size */
|
||||
dtls_warn("cannot set rijndael key\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (src != buf)
|
||||
memmove(buf, src, length);
|
||||
ret = dtls_ccm_decrypt(&ctx->data, src, length, buf, nounce, aad, la);
|
||||
|
||||
error:
|
||||
dtls_cipher_context_release();
|
||||
return ret;
|
||||
}
|
||||
|
350
crypto.h
Normal file
350
crypto.h
Normal file
@ -0,0 +1,350 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _DTLS_CRYPTO_H_
|
||||
#define _DTLS_CRYPTO_H_
|
||||
|
||||
#include <stdlib.h> /* for rand() and srand() */
|
||||
#include <stdint.h>
|
||||
|
||||
#include "aes/rijndael.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "state.h"
|
||||
#include "numeric.h"
|
||||
#include "hmac.h"
|
||||
#include "ccm.h"
|
||||
|
||||
/* TLS_PSK_WITH_AES_128_CCM_8 */
|
||||
#define DTLS_MAC_KEY_LENGTH 0
|
||||
#define DTLS_KEY_LENGTH 16 /* AES-128 */
|
||||
#define DTLS_BLK_LENGTH 16 /* AES-128 */
|
||||
#define DTLS_MAC_LENGTH DTLS_HMAC_DIGEST_SIZE
|
||||
#define DTLS_IV_LENGTH 4 /* length of nonce_explicit */
|
||||
|
||||
/**
|
||||
* Maximum size of the generated keyblock. Note that MAX_KEYBLOCK_LENGTH must
|
||||
* be large enough to hold the pre_master_secret, i.e. twice the length of the
|
||||
* pre-shared key + 1.
|
||||
*/
|
||||
#define MAX_KEYBLOCK_LENGTH \
|
||||
(2 * DTLS_MAC_KEY_LENGTH + 2 * DTLS_KEY_LENGTH + 2 * DTLS_IV_LENGTH)
|
||||
|
||||
/** Length of DTLS master_secret */
|
||||
#define DTLS_MASTER_SECRET_LENGTH 48
|
||||
#define DTLS_RANDOM_LENGTH 32
|
||||
|
||||
typedef enum { AES128=0
|
||||
} dtls_crypto_alg;
|
||||
|
||||
typedef enum {
|
||||
DTLS_ECDH_CURVE_SECP256R1
|
||||
} dtls_ecdh_curve;
|
||||
|
||||
/** Crypto context for TLS_PSK_WITH_AES_128_CCM_8 cipher suite. */
|
||||
typedef struct {
|
||||
rijndael_ctx ctx; /**< AES-128 encryption context */
|
||||
} aes128_ccm_t;
|
||||
|
||||
typedef struct dtls_cipher_context_t {
|
||||
/** numeric identifier of this cipher suite in host byte order. */
|
||||
aes128_ccm_t data; /**< The crypto context */
|
||||
} dtls_cipher_context_t;
|
||||
|
||||
typedef struct {
|
||||
uint8 own_eph_priv[32];
|
||||
uint8 other_eph_pub_x[32];
|
||||
uint8 other_eph_pub_y[32];
|
||||
uint8 other_pub_x[32];
|
||||
uint8 other_pub_y[32];
|
||||
} dtls_handshake_parameters_ecdsa_t;
|
||||
|
||||
/* This is the maximal supported length of the psk client identity and psk
|
||||
* server identity hint */
|
||||
#define DTLS_PSK_MAX_CLIENT_IDENTITY_LEN 32
|
||||
|
||||
/* This is the maximal supported length of the pre-shared key. */
|
||||
#define DTLS_PSK_MAX_KEY_LEN DTLS_KEY_LENGTH
|
||||
|
||||
typedef struct {
|
||||
uint16_t id_length;
|
||||
unsigned char identity[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN];
|
||||
} dtls_handshake_parameters_psk_t;
|
||||
|
||||
typedef struct {
|
||||
dtls_compression_t compression; /**< compression method */
|
||||
|
||||
dtls_cipher_t cipher; /**< cipher type */
|
||||
uint16_t epoch; /**< counter for cipher state changes*/
|
||||
uint64_t rseq; /**< sequence number of last record sent */
|
||||
|
||||
/**
|
||||
* The key block generated from PRF applied to client and server
|
||||
* random bytes. The actual size is given by the selected cipher and
|
||||
* can be calculated using dtls_kb_size(). Use \c dtls_kb_ macros to
|
||||
* access the components of the key block.
|
||||
*/
|
||||
uint8 key_block[MAX_KEYBLOCK_LENGTH];
|
||||
} dtls_security_parameters_t;
|
||||
|
||||
struct netq_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct random_t {
|
||||
uint8 client[DTLS_RANDOM_LENGTH]; /**< client random gmt and bytes */
|
||||
uint8 server[DTLS_RANDOM_LENGTH]; /**< server random gmt and bytes */
|
||||
} random;
|
||||
/** the session's master secret */
|
||||
uint8 master_secret[DTLS_MASTER_SECRET_LENGTH];
|
||||
} tmp;
|
||||
struct netq_t *reorder_queue; /**< the packets to reorder */
|
||||
dtls_hs_state_t hs_state; /**< handshake protocol status */
|
||||
|
||||
dtls_compression_t compression; /**< compression method */
|
||||
dtls_cipher_t cipher; /**< cipher type */
|
||||
unsigned int do_client_auth:1;
|
||||
union {
|
||||
#ifdef DTLS_ECC
|
||||
dtls_handshake_parameters_ecdsa_t ecdsa;
|
||||
#endif /* DTLS_ECC */
|
||||
#ifdef DTLS_PSK
|
||||
dtls_handshake_parameters_psk_t psk;
|
||||
#endif /* DTLS_PSK */
|
||||
} keyx;
|
||||
} dtls_handshake_parameters_t;
|
||||
|
||||
/* The following macros provide access to the components of the
|
||||
* key_block in the security parameters. */
|
||||
|
||||
#define dtls_kb_client_mac_secret(Param, Role) ((Param)->key_block)
|
||||
#define dtls_kb_server_mac_secret(Param, Role) \
|
||||
(dtls_kb_client_mac_secret(Param, Role) + DTLS_MAC_KEY_LENGTH)
|
||||
#define dtls_kb_remote_mac_secret(Param, Role) \
|
||||
((Role) == DTLS_SERVER \
|
||||
? dtls_kb_client_mac_secret(Param, Role) \
|
||||
: dtls_kb_server_mac_secret(Param, Role))
|
||||
#define dtls_kb_local_mac_secret(Param, Role) \
|
||||
((Role) == DTLS_CLIENT \
|
||||
? dtls_kb_client_mac_secret(Param, Role) \
|
||||
: dtls_kb_server_mac_secret(Param, Role))
|
||||
#define dtls_kb_mac_secret_size(Param, Role) DTLS_MAC_KEY_LENGTH
|
||||
#define dtls_kb_client_write_key(Param, Role) \
|
||||
(dtls_kb_server_mac_secret(Param, Role) + DTLS_MAC_KEY_LENGTH)
|
||||
#define dtls_kb_server_write_key(Param, Role) \
|
||||
(dtls_kb_client_write_key(Param, Role) + DTLS_KEY_LENGTH)
|
||||
#define dtls_kb_remote_write_key(Param, Role) \
|
||||
((Role) == DTLS_SERVER \
|
||||
? dtls_kb_client_write_key(Param, Role) \
|
||||
: dtls_kb_server_write_key(Param, Role))
|
||||
#define dtls_kb_local_write_key(Param, Role) \
|
||||
((Role) == DTLS_CLIENT \
|
||||
? dtls_kb_client_write_key(Param, Role) \
|
||||
: dtls_kb_server_write_key(Param, Role))
|
||||
#define dtls_kb_key_size(Param, Role) DTLS_KEY_LENGTH
|
||||
#define dtls_kb_client_iv(Param, Role) \
|
||||
(dtls_kb_server_write_key(Param, Role) + DTLS_KEY_LENGTH)
|
||||
#define dtls_kb_server_iv(Param, Role) \
|
||||
(dtls_kb_client_iv(Param, Role) + DTLS_IV_LENGTH)
|
||||
#define dtls_kb_remote_iv(Param, Role) \
|
||||
((Role) == DTLS_SERVER \
|
||||
? dtls_kb_client_iv(Param, Role) \
|
||||
: dtls_kb_server_iv(Param, Role))
|
||||
#define dtls_kb_local_iv(Param, Role) \
|
||||
((Role) == DTLS_CLIENT \
|
||||
? dtls_kb_client_iv(Param, Role) \
|
||||
: dtls_kb_server_iv(Param, Role))
|
||||
#define dtls_kb_iv_size(Param, Role) DTLS_IV_LENGTH
|
||||
|
||||
#define dtls_kb_size(Param, Role) \
|
||||
(2 * (dtls_kb_mac_secret_size(Param, Role) + \
|
||||
dtls_kb_key_size(Param, Role) + dtls_kb_iv_size(Param, Role)))
|
||||
|
||||
/* just for consistency */
|
||||
#define dtls_kb_digest_size(Param, Role) DTLS_MAC_LENGTH
|
||||
|
||||
/**
|
||||
* Expands the secret and key to a block of DTLS_HMAC_MAX
|
||||
* size according to the algorithm specified in section 5 of
|
||||
* RFC 4346.
|
||||
*
|
||||
* \param h Identifier of the hash function to use.
|
||||
* \param key The secret.
|
||||
* \param keylen Length of \p key.
|
||||
* \param seed The seed.
|
||||
* \param seedlen Length of \p seed.
|
||||
* \param buf Output buffer where the result is XORed into
|
||||
* The buffe must be capable to hold at least
|
||||
* \p buflen bytes.
|
||||
* \return The actual number of bytes written to \p buf or 0
|
||||
* on error.
|
||||
*/
|
||||
size_t dtls_p_hash(dtls_hashfunc_t h,
|
||||
const unsigned char *key, size_t keylen,
|
||||
const unsigned char *label, size_t labellen,
|
||||
const unsigned char *random1, size_t random1len,
|
||||
const unsigned char *random2, size_t random2len,
|
||||
unsigned char *buf, size_t buflen);
|
||||
|
||||
/**
|
||||
* This function implements the TLS PRF for DTLS_VERSION. For version
|
||||
* 1.0, the PRF is P_MD5 ^ P_SHA1 while version 1.2 uses
|
||||
* P_SHA256. Currently, the actual PRF is selected at compile time.
|
||||
*/
|
||||
size_t dtls_prf(const unsigned char *key, size_t keylen,
|
||||
const unsigned char *label, size_t labellen,
|
||||
const unsigned char *random1, size_t random1len,
|
||||
const unsigned char *random2, size_t random2len,
|
||||
unsigned char *buf, size_t buflen);
|
||||
|
||||
/**
|
||||
* Calculates MAC for record + cleartext packet and places the result
|
||||
* in \p buf. The given \p hmac_ctx must be initialized with the HMAC
|
||||
* function to use and the proper secret. As the DTLS mac calculation
|
||||
* requires data from the record header, \p record must point to a
|
||||
* buffer of at least \c sizeof(dtls_record_header_t) bytes. Usually,
|
||||
* the remaining packet will be encrypted, therefore, the cleartext
|
||||
* is passed separately in \p packet.
|
||||
*
|
||||
* \param hmac_ctx The HMAC context to use for MAC calculation.
|
||||
* \param record The record header.
|
||||
* \param packet Cleartext payload to apply the MAC to.
|
||||
* \param length Size of \p packet.
|
||||
* \param buf A result buffer that is large enough to hold
|
||||
* the generated digest.
|
||||
*/
|
||||
void dtls_mac(dtls_hmac_context_t *hmac_ctx,
|
||||
const unsigned char *record,
|
||||
const unsigned char *packet, size_t length,
|
||||
unsigned char *buf);
|
||||
|
||||
/**
|
||||
* Encrypts the specified \p src of given \p length, writing the
|
||||
* result to \p buf. The cipher implementation may add more data to
|
||||
* the result buffer such as an initialization vector or padding
|
||||
* (e.g. for block cipers in CBC mode). The caller therefore must
|
||||
* ensure that \p buf provides sufficient storage to hold the result.
|
||||
* Usually this means ( 2 + \p length / blocksize ) * blocksize. The
|
||||
* function returns a value less than zero on error or otherwise the
|
||||
* number of bytes written.
|
||||
*
|
||||
* \param ctx The cipher context to use.
|
||||
* \param src The data to encrypt.
|
||||
* \param length The actual size of of \p src.
|
||||
* \param buf The result buffer. \p src and \p buf must not
|
||||
* overlap.
|
||||
* \param aad additional data for AEAD ciphers
|
||||
* \param aad_length actual size of @p aad
|
||||
* \return The number of encrypted bytes on success, less than zero
|
||||
* otherwise.
|
||||
*/
|
||||
int dtls_encrypt(const unsigned char *src, size_t length,
|
||||
unsigned char *buf,
|
||||
unsigned char *nounce,
|
||||
unsigned char *key, size_t keylen,
|
||||
const unsigned char *aad, size_t aad_length);
|
||||
|
||||
/**
|
||||
* Decrypts the given buffer \p src of given \p length, writing the
|
||||
* result to \p buf. The function returns \c -1 in case of an error,
|
||||
* or the number of bytes written. Note that for block ciphers, \p
|
||||
* length must be a multiple of the cipher's block size. A return
|
||||
* value between \c 0 and the actual length indicates that only \c n-1
|
||||
* block have been processed. Unlike dtls_encrypt(), the source
|
||||
* and destination of dtls_decrypt() may overlap.
|
||||
*
|
||||
* \param ctx The cipher context to use.
|
||||
* \param src The buffer to decrypt.
|
||||
* \param length The length of the input buffer.
|
||||
* \param buf The result buffer.
|
||||
* \param aad additional authentication data for AEAD ciphers
|
||||
* \param aad_length actual size of @p aad
|
||||
* \return Less than zero on error, the number of decrypted bytes
|
||||
* otherwise.
|
||||
*/
|
||||
int dtls_decrypt(const unsigned char *src, size_t length,
|
||||
unsigned char *buf,
|
||||
unsigned char *nounce,
|
||||
unsigned char *key, size_t keylen,
|
||||
const unsigned char *a_data, size_t a_data_length);
|
||||
|
||||
/* helper functions */
|
||||
|
||||
/**
|
||||
* Generates pre_master_sercet from given PSK and fills the result
|
||||
* according to the "plain PSK" case in section 2 of RFC 4279.
|
||||
* Diffie-Hellman and RSA key exchange are currently not supported.
|
||||
*
|
||||
* @param key The shared key.
|
||||
* @param keylen Length of @p key in bytes.
|
||||
* @param result The derived pre master secret.
|
||||
* @return The actual length of @p result.
|
||||
*/
|
||||
int dtls_psk_pre_master_secret(unsigned char *key, size_t keylen,
|
||||
unsigned char *result, size_t result_len);
|
||||
|
||||
#define DTLS_EC_KEY_SIZE 32
|
||||
|
||||
int dtls_ecdh_pre_master_secret(unsigned char *priv_key,
|
||||
unsigned char *pub_key_x,
|
||||
unsigned char *pub_key_y,
|
||||
size_t key_size,
|
||||
unsigned char *result,
|
||||
size_t result_len);
|
||||
|
||||
void dtls_ecdsa_generate_key(unsigned char *priv_key,
|
||||
unsigned char *pub_key_x,
|
||||
unsigned char *pub_key_y,
|
||||
size_t key_size);
|
||||
|
||||
void dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size,
|
||||
const unsigned char *sign_hash, size_t sign_hash_size,
|
||||
uint32_t point_r[9], uint32_t point_s[9]);
|
||||
|
||||
void dtls_ecdsa_create_sig(const unsigned char *priv_key, size_t key_size,
|
||||
const unsigned char *client_random, size_t client_random_size,
|
||||
const unsigned char *server_random, size_t server_random_size,
|
||||
const unsigned char *keyx_params, size_t keyx_params_size,
|
||||
uint32_t point_r[9], uint32_t point_s[9]);
|
||||
|
||||
int dtls_ecdsa_verify_sig_hash(const unsigned char *pub_key_x,
|
||||
const unsigned char *pub_key_y, size_t key_size,
|
||||
const unsigned char *sign_hash, size_t sign_hash_size,
|
||||
unsigned char *result_r, unsigned char *result_s);
|
||||
|
||||
int dtls_ecdsa_verify_sig(const unsigned char *pub_key_x,
|
||||
const unsigned char *pub_key_y, size_t key_size,
|
||||
const unsigned char *client_random, size_t client_random_size,
|
||||
const unsigned char *server_random, size_t server_random_size,
|
||||
const unsigned char *keyx_params, size_t keyx_params_size,
|
||||
unsigned char *result_r, unsigned char *result_s);
|
||||
|
||||
int dtls_ec_key_from_uint32_asn1(const uint32_t *key, size_t key_size,
|
||||
unsigned char *buf);
|
||||
|
||||
|
||||
dtls_handshake_parameters_t *dtls_handshake_new();
|
||||
|
||||
void dtls_handshake_free(dtls_handshake_parameters_t *handshake);
|
||||
|
||||
dtls_security_parameters_t *dtls_security_new();
|
||||
|
||||
void dtls_security_free(dtls_security_parameters_t *security);
|
||||
void crypto_init();
|
||||
|
||||
#endif /* _DTLS_CRYPTO_H_ */
|
||||
|
373
debug.c
Normal file
373
debug.c
Normal file
@ -0,0 +1,373 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "dtls_config.h"
|
||||
|
||||
#if defined(HAVE_ASSERT_H) && !defined(assert)
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "global.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
static int maxlog = DTLS_LOG_WARN; /* default maximum log level */
|
||||
|
||||
const char *dtls_package_name() {
|
||||
return PACKAGE_NAME;
|
||||
}
|
||||
|
||||
const char *dtls_package_version() {
|
||||
return PACKAGE_VERSION;
|
||||
}
|
||||
|
||||
log_t
|
||||
dtls_get_log_level() {
|
||||
return maxlog;
|
||||
}
|
||||
|
||||
void
|
||||
dtls_set_log_level(log_t level) {
|
||||
#ifdef NDEBUG
|
||||
maxlog = min(level, DTLS_LOG_INFO);
|
||||
#else /* !NDEBUG */
|
||||
maxlog = level;
|
||||
#endif /* NDEBUG */
|
||||
}
|
||||
|
||||
/* this array has the same order as the type log_t */
|
||||
static char *loglevels[] = {
|
||||
"EMRG", "ALRT", "CRIT", "WARN", "NOTE", "INFO", "DEBG"
|
||||
};
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
|
||||
static inline size_t
|
||||
print_timestamp(char *s, size_t len, time_t t) {
|
||||
struct tm *tmp;
|
||||
tmp = localtime(&t);
|
||||
return strftime(s, len, "%b %d %H:%M:%S", tmp);
|
||||
}
|
||||
|
||||
#else /* alternative implementation: just print the timestamp */
|
||||
|
||||
static inline size_t
|
||||
print_timestamp(char *s, size_t len, clock_time_t t) {
|
||||
#ifdef HAVE_SNPRINTF
|
||||
return snprintf(s, len, "%u.%03u",
|
||||
(unsigned int)(t / CLOCK_SECOND),
|
||||
(unsigned int)(t % CLOCK_SECOND));
|
||||
#else /* HAVE_SNPRINTF */
|
||||
/* @todo do manual conversion of timestamp */
|
||||
return 0;
|
||||
#endif /* HAVE_SNPRINTF */
|
||||
}
|
||||
|
||||
#endif /* HAVE_TIME_H */
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/**
|
||||
* A length-safe strlen() fake.
|
||||
*
|
||||
* @param s The string to count characters != 0.
|
||||
* @param maxlen The maximum length of @p s.
|
||||
*
|
||||
* @return The length of @p s.
|
||||
*/
|
||||
static inline size_t
|
||||
dtls_strnlen(const char *s, size_t maxlen) {
|
||||
size_t n = 0;
|
||||
while(*s++ && n < maxlen)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static size_t
|
||||
dsrv_print_addr(const session_t *addr, char *buf, size_t len) {
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
const void *addrptr = NULL;
|
||||
in_port_t port;
|
||||
char *p = buf;
|
||||
|
||||
switch (addr->addr.sa.sa_family) {
|
||||
case AF_INET:
|
||||
if (len < INET_ADDRSTRLEN)
|
||||
return 0;
|
||||
|
||||
addrptr = &addr->addr.sin.sin_addr;
|
||||
port = ntohs(addr->addr.sin.sin_port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (len < INET6_ADDRSTRLEN + 2)
|
||||
return 0;
|
||||
|
||||
*p++ = '[';
|
||||
|
||||
addrptr = &addr->addr.sin6.sin6_addr;
|
||||
port = ntohs(addr->addr.sin6.sin6_port);
|
||||
|
||||
break;
|
||||
default:
|
||||
memcpy(buf, "(unknown address type)", min(22, len));
|
||||
return min(22, len);
|
||||
}
|
||||
|
||||
if (inet_ntop(addr->addr.sa.sa_family, addrptr, p, len) == 0) {
|
||||
perror("dsrv_print_addr");
|
||||
return 0;
|
||||
}
|
||||
|
||||
p += dtls_strnlen(p, len);
|
||||
|
||||
if (addr->addr.sa.sa_family == AF_INET6) {
|
||||
if (p < buf + len) {
|
||||
*p++ = ']';
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
p += snprintf(p, buf + len - p + 1, ":%d", port);
|
||||
|
||||
return p - buf;
|
||||
#else /* HAVE_ARPA_INET_H */
|
||||
# if WITH_CONTIKI
|
||||
char *p = buf;
|
||||
# ifdef UIP_CONF_IPV6
|
||||
uint8_t i;
|
||||
const char hex[] = "0123456789ABCDEF";
|
||||
|
||||
if (len < 41)
|
||||
return 0;
|
||||
|
||||
*p++ = '[';
|
||||
|
||||
for (i=0; i < 16; i += 2) {
|
||||
if (i) {
|
||||
*p++ = ':';
|
||||
}
|
||||
*p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
|
||||
*p++ = hex[(addr->addr.u8[i] & 0x0f)];
|
||||
*p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
|
||||
*p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
|
||||
}
|
||||
*p++ = ']';
|
||||
# else /* UIP_CONF_IPV6 */
|
||||
# warning "IPv4 network addresses will not be included in debug output"
|
||||
|
||||
if (len < 21)
|
||||
return 0;
|
||||
# endif /* UIP_CONF_IPV6 */
|
||||
if (buf + len - p < 6)
|
||||
return 0;
|
||||
|
||||
p += sprintf(p, ":%d", uip_htons(addr->port));
|
||||
|
||||
return p - buf;
|
||||
# else /* WITH_CONTIKI */
|
||||
/* TODO: output addresses manually */
|
||||
# warning "inet_ntop() not available, network addresses will not be included in debug output"
|
||||
# endif /* WITH_CONTIKI */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* NDEBUG */
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
void
|
||||
dsrv_log(log_t level, char *format, ...) {
|
||||
static char timebuf[32];
|
||||
va_list ap;
|
||||
FILE *log_fd;
|
||||
|
||||
if (maxlog < level)
|
||||
return;
|
||||
|
||||
log_fd = level <= DTLS_LOG_CRIT ? stderr : stdout;
|
||||
|
||||
if (print_timestamp(timebuf,sizeof(timebuf), time(NULL)))
|
||||
fprintf(log_fd, "%s ", timebuf);
|
||||
|
||||
if (level <= DTLS_LOG_DEBUG)
|
||||
fprintf(log_fd, "%s ", loglevels[level]);
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(log_fd, format, ap);
|
||||
va_end(ap);
|
||||
fflush(log_fd);
|
||||
}
|
||||
#elif defined (HAVE_VPRINTF) /* WITH_CONTIKI */
|
||||
void
|
||||
dsrv_log(log_t level, char *format, ...) {
|
||||
static char timebuf[32];
|
||||
va_list ap;
|
||||
|
||||
if (maxlog < level)
|
||||
return;
|
||||
|
||||
if (print_timestamp(timebuf,sizeof(timebuf), clock_time()))
|
||||
PRINTF("%s ", timebuf);
|
||||
|
||||
if (level <= DTLS_LOG_DEBUG)
|
||||
PRINTF("%s ", loglevels[level]);
|
||||
|
||||
va_start(ap, format);
|
||||
vprintf(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
#ifndef NDEBUG
|
||||
/** dumps packets in usual hexdump format */
|
||||
void hexdump(const unsigned char *packet, int length) {
|
||||
int n = 0;
|
||||
|
||||
while (length--) {
|
||||
if (n % 16 == 0)
|
||||
printf("%08X ",n);
|
||||
|
||||
printf("%02X ", *packet++);
|
||||
|
||||
n++;
|
||||
if (n % 8 == 0) {
|
||||
if (n % 16 == 0)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** dump as narrow string of hex digits */
|
||||
void dump(unsigned char *buf, size_t len) {
|
||||
while (len--)
|
||||
printf("%02x", *buf++);
|
||||
}
|
||||
|
||||
void dtls_dsrv_log_addr(log_t level, const char *name, const session_t *addr)
|
||||
{
|
||||
char addrbuf[73];
|
||||
int len;
|
||||
|
||||
len = dsrv_print_addr(addr, addrbuf, sizeof(addrbuf));
|
||||
if (!len)
|
||||
return;
|
||||
dsrv_log(level, "%s: %s\n", name, addrbuf);
|
||||
}
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
void
|
||||
dtls_dsrv_hexdump_log(log_t level, const char *name, const unsigned char *buf, size_t length, int extend) {
|
||||
static char timebuf[32];
|
||||
FILE *log_fd;
|
||||
int n = 0;
|
||||
|
||||
if (maxlog < level)
|
||||
return;
|
||||
|
||||
log_fd = level <= DTLS_LOG_CRIT ? stderr : stdout;
|
||||
|
||||
if (print_timestamp(timebuf, sizeof(timebuf), time(NULL)))
|
||||
fprintf(log_fd, "%s ", timebuf);
|
||||
|
||||
if (level <= DTLS_LOG_DEBUG)
|
||||
fprintf(log_fd, "%s ", loglevels[level]);
|
||||
|
||||
if (extend) {
|
||||
fprintf(log_fd, "%s: (%zu bytes):\n", name, length);
|
||||
|
||||
while (length--) {
|
||||
if (n % 16 == 0)
|
||||
fprintf(log_fd, "%08X ", n);
|
||||
|
||||
fprintf(log_fd, "%02X ", *buf++);
|
||||
|
||||
n++;
|
||||
if (n % 8 == 0) {
|
||||
if (n % 16 == 0)
|
||||
fprintf(log_fd, "\n");
|
||||
else
|
||||
fprintf(log_fd, " ");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(log_fd, "%s: (%zu bytes): ", name, length);
|
||||
while (length--)
|
||||
fprintf(log_fd, "%02X", *buf++);
|
||||
}
|
||||
fprintf(log_fd, "\n");
|
||||
|
||||
fflush(log_fd);
|
||||
}
|
||||
#else /* WITH_CONTIKI */
|
||||
void
|
||||
dtls_dsrv_hexdump_log(log_t level, const char *name, const unsigned char *buf, size_t length, int extend) {
|
||||
static char timebuf[32];
|
||||
int n = 0;
|
||||
|
||||
if (maxlog < level)
|
||||
return;
|
||||
|
||||
if (print_timestamp(timebuf,sizeof(timebuf), clock_time()))
|
||||
PRINTF("%s ", timebuf);
|
||||
|
||||
if (level >= 0 && level <= DTLS_LOG_DEBUG)
|
||||
PRINTF("%s ", loglevels[level]);
|
||||
|
||||
if (extend) {
|
||||
PRINTF("%s: (%zu bytes):\n", name, length);
|
||||
|
||||
while (length--) {
|
||||
if (n % 16 == 0)
|
||||
PRINTF("%08X ", n);
|
||||
|
||||
PRINTF("%02X ", *buf++);
|
||||
|
||||
n++;
|
||||
if (n % 8 == 0) {
|
||||
if (n % 16 == 0)
|
||||
PRINTF("\n");
|
||||
else
|
||||
PRINTF(" ");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PRINTF("%s: (%zu bytes): ", name, length);
|
||||
while (length--)
|
||||
PRINTF("%02X", *buf++);
|
||||
}
|
||||
PRINTF("\n");
|
||||
}
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
#endif /* NDEBUG */
|
122
debug.h
Normal file
122
debug.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _DTLS_DEBUG_H_
|
||||
#define _DTLS_DEBUG_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dtls_config.h"
|
||||
#include "global.h"
|
||||
#include "session.h"
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
# ifndef DEBUG
|
||||
# define DEBUG DEBUG_PRINT
|
||||
# endif /* DEBUG */
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
#ifdef CONTIKI_TARGET_MBXXX
|
||||
extern char __Stack_Init, _estack;
|
||||
|
||||
static inline void check_stack() {
|
||||
const char *p = &__Stack_Init;
|
||||
while (p < &_estack && *p == 0x38) {
|
||||
p++;
|
||||
}
|
||||
|
||||
PRINTF("Stack: %d bytes used (%d free)\n", &_estack - p, p - &__Stack_Init);
|
||||
}
|
||||
#else /* CONTIKI_TARGET_MBXXX */
|
||||
static inline void check_stack() {
|
||||
}
|
||||
#endif /* CONTIKI_TARGET_MBXXX */
|
||||
#else /* WITH_CONTKI */
|
||||
#define PRINTF(...)
|
||||
|
||||
static inline void check_stack() {
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Pre-defined log levels akin to what is used in \b syslog. */
|
||||
typedef enum { DTLS_LOG_EMERG=0, DTLS_LOG_ALERT, DTLS_LOG_CRIT, DTLS_LOG_WARN,
|
||||
DTLS_LOG_NOTICE, DTLS_LOG_INFO, DTLS_LOG_DEBUG
|
||||
} log_t;
|
||||
|
||||
/** Returns a zero-terminated string with the name of this library. */
|
||||
const char *dtls_package_name();
|
||||
|
||||
/** Returns a zero-terminated string with the library version. */
|
||||
const char *dtls_package_version();
|
||||
|
||||
/** Returns the current log level. */
|
||||
log_t dtls_get_log_level();
|
||||
|
||||
/** Sets the log level to the specified value. */
|
||||
void dtls_set_log_level(log_t level);
|
||||
|
||||
/**
|
||||
* Writes the given text to \c stdout. The text is output only when \p
|
||||
* level is below or equal to the log level that set by
|
||||
* set_log_level(). */
|
||||
#ifdef HAVE_VPRINTF
|
||||
void dsrv_log(log_t level, char *format, ...);
|
||||
#else
|
||||
#define dsrv_log(level, format, ...) PRINTF(format, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
/** dumps packets in usual hexdump format */
|
||||
void hexdump(const unsigned char *packet, int length);
|
||||
|
||||
/** dump as narrow string of hex digits */
|
||||
void dump(unsigned char *buf, size_t len);
|
||||
|
||||
void dtls_dsrv_hexdump_log(log_t level, const char *name, const unsigned char *buf, size_t length, int extend);
|
||||
|
||||
void dtls_dsrv_log_addr(log_t level, const char *name, const session_t *addr);
|
||||
|
||||
#else /* NDEBUG */
|
||||
|
||||
static inline void hexdump(const unsigned char *packet, int length)
|
||||
{}
|
||||
|
||||
static inline void dump(unsigned char *buf, size_t len)
|
||||
{}
|
||||
|
||||
static inline void
|
||||
dtls_dsrv_hexdump_log(log_t level, const char *name, const unsigned char *buf, size_t length, int extend)
|
||||
{}
|
||||
|
||||
static inline void
|
||||
dtls_dsrv_log_addr(log_t level, const char *name, const session_t *addr)
|
||||
{}
|
||||
|
||||
#endif /* NDEBUG */
|
||||
|
||||
/* A set of convenience macros for common log levels. */
|
||||
#define dtls_emerg(...) dsrv_log(DTLS_LOG_EMERG, __VA_ARGS__)
|
||||
#define dtls_alert(...) dsrv_log(DTLS_LOG_ALERT, __VA_ARGS__)
|
||||
#define dtls_crit(...) dsrv_log(DTLS_LOG_CRIT, __VA_ARGS__)
|
||||
#define dtls_warn(...) dsrv_log(DTLS_LOG_WARN, __VA_ARGS__)
|
||||
#define dtls_notice(...) dsrv_log(DTLS_LOG_NOTICE, __VA_ARGS__)
|
||||
#define dtls_info(...) dsrv_log(DTLS_LOG_INFO, __VA_ARGS__)
|
||||
#define dtls_debug(...) dsrv_log(DTLS_LOG_DEBUG, __VA_ARGS__)
|
||||
#define dtls_debug_hexdump(name, buf, length) dtls_dsrv_hexdump_log(DTLS_LOG_DEBUG, name, buf, length, 1)
|
||||
#define dtls_debug_dump(name, buf, length) dtls_dsrv_hexdump_log(DTLS_LOG_DEBUG, name, buf, length, 0)
|
||||
|
||||
#endif /* _DTLS_DEBUG_H_ */
|
1551
doc/Doxyfile.in
Normal file
1551
doc/Doxyfile.in
Normal file
File diff suppressed because it is too large
Load Diff
184
doc/DoxygenLayout.xml
Normal file
184
doc/DoxygenLayout.xml
Normal file
@ -0,0 +1,184 @@
|
||||
<doxygenlayout version="1.0">
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title=""/>
|
||||
<tab type="pages" visible="yes" title=""/>
|
||||
<tab type="modules" visible="yes" title=""/>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespaces" visible="yes" title=""/>
|
||||
<tab type="namespacemembers" visible="yes" title=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="yes" title="">
|
||||
<tab type="classes" visible="yes" title=""/>
|
||||
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
<tab type="hierarchy" visible="yes" title=""/>
|
||||
<tab type="classmembers" visible="yes" title=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="yes" title="">
|
||||
<tab type="files" visible="yes" title=""/>
|
||||
<tab type="globals" visible="yes" title=""/>
|
||||
</tab>
|
||||
<tab type="dirs" visible="yes" title=""/>
|
||||
<tab type="examples" visible="yes" title=""/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<allmemberslink visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<memberdecl>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<memberdecl>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
36
doc/Makefile.in
Normal file
36
doc/Makefile.in
Normal file
@ -0,0 +1,36 @@
|
||||
# the library's version
|
||||
VERSION:=@PACKAGE_VERSION@
|
||||
PACKAGE_TARNAME:=@PACKAGE_TARNAME@
|
||||
|
||||
# tools
|
||||
@SET_MAKE@
|
||||
SHELL = /bin/sh
|
||||
MKDIR = mkdir
|
||||
DOXYGEN= @DOXYGEN@
|
||||
|
||||
top_builddir = @top_builddir@
|
||||
prefix = @prefix@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
htmldir = @htmldir@
|
||||
|
||||
DISTDIR?=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
FILES:=Makefile.in Doxyfile.in html
|
||||
|
||||
doc: Doxyfile
|
||||
$(DOXYGEN) $< >./doxygen.out 2>&1
|
||||
|
||||
clean:
|
||||
@rm -rf html
|
||||
|
||||
distclean: clean
|
||||
@rm -rf $(DISTDIR)
|
||||
@rm -f *~
|
||||
|
||||
dist: doc
|
||||
test -d $(DISTDIR)/doc || mkdir $(DISTDIR)/doc
|
||||
cp -r $(FILES) $(DISTDIR)/doc
|
||||
|
||||
install: $(doc) html
|
||||
test -d $(htmldir) || mkdir -p $(htmldir)
|
||||
cp -r html/* $(htmldir)
|
740
dtls.h
Normal file
740
dtls.h
Normal file
@ -0,0 +1,740 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
* Achim Kraus - session recovery
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file dtls.h
|
||||
* @brief High level DTLS API and visible structures.
|
||||
*/
|
||||
|
||||
#ifndef _DTLS_DTLS_H_
|
||||
#define _DTLS_DTLS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "state.h"
|
||||
#include "peer.h"
|
||||
|
||||
#include "uthash.h"
|
||||
|
||||
#include "alert.h"
|
||||
#include "crypto.h"
|
||||
#include "hmac.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "dtls_time.h"
|
||||
|
||||
#ifndef DTLSv12
|
||||
#define DTLS_VERSION 0xfeff /* DTLS v1.1 */
|
||||
#else
|
||||
#define DTLS_VERSION 0xfefd /* DTLS v1.2 */
|
||||
#endif
|
||||
|
||||
typedef enum dtls_credentials_type_t {
|
||||
DTLS_PSK_HINT, DTLS_PSK_IDENTITY, DTLS_PSK_KEY
|
||||
} dtls_credentials_type_t;
|
||||
|
||||
typedef struct dtls_ecdsa_key_t {
|
||||
dtls_ecdh_curve curve;
|
||||
const unsigned char *priv_key; /** < private key as bytes > */
|
||||
const unsigned char *pub_key_x; /** < x part of the public key for the given private key > */
|
||||
const unsigned char *pub_key_y; /** < y part of the public key for the given private key > */
|
||||
} dtls_ecdsa_key_t;
|
||||
|
||||
/** Length of the secret that is used for generating Hello Verify cookies. */
|
||||
#define DTLS_COOKIE_SECRET_LENGTH 12
|
||||
|
||||
struct dtls_context_t;
|
||||
|
||||
/**
|
||||
* This structure contains callback functions used by tinydtls to
|
||||
* communicate with the application. At least the write function must
|
||||
* be provided. It is called by the DTLS state machine to send packets
|
||||
* over the network. The read function is invoked to deliver decrypted
|
||||
* and verfified application data. The third callback is an event
|
||||
* handler function that is called when alert messages are encountered
|
||||
* or events generated by the library have occured.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* Called from dtls_handle_message() to send DTLS packets over the
|
||||
* network. The callback function must use the network interface
|
||||
* denoted by session->ifindex to send the data.
|
||||
*
|
||||
* @param ctx The current DTLS context.
|
||||
* @param session The session object, including the address of the
|
||||
* remote peer where the data shall be sent.
|
||||
* @param buf The data to send.
|
||||
* @param len The actual length of @p buf.
|
||||
* @return The callback function must return the number of bytes
|
||||
* that were sent, or a value less than zero to indicate an
|
||||
* error.
|
||||
*/
|
||||
int (*write)(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Called from dtls_handle_message() deliver application data that was
|
||||
* received on the given session. The data is delivered only after
|
||||
* decryption and verification have succeeded.
|
||||
*
|
||||
* @param ctx The current DTLS context.
|
||||
* @param session The session object, including the address of the
|
||||
* data's origin.
|
||||
* @param buf The received data packet.
|
||||
* @param len The actual length of @p buf.
|
||||
* @return ignored
|
||||
*/
|
||||
int (*read)(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* The event handler is called when a message from the alert
|
||||
* protocol is received or the state of the DTLS session changes.
|
||||
*
|
||||
* @param ctx The current dtls context.
|
||||
* @param session The session object that was affected.
|
||||
* @param level The alert level or @c 0 when an event ocurred that
|
||||
* is not an alert.
|
||||
* @param code Values less than @c 256 indicate alerts, while
|
||||
* @c 256 or greater indicate internal DTLS session changes.
|
||||
* @return ignored
|
||||
*/
|
||||
int (*event)(struct dtls_context_t *ctx, session_t *session,
|
||||
dtls_alert_level_t level, unsigned short code);
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
/**
|
||||
* Called during handshake to get information related to the
|
||||
* psk key exchange. The type of information requested is
|
||||
* indicated by @p type which will be one of DTLS_PSK_HINT,
|
||||
* DTLS_PSK_IDENTITY, or DTLS_PSK_KEY. The called function
|
||||
* must store the requested item in the buffer @p result of
|
||||
* size @p result_length. On success, the function must return
|
||||
* the actual number of bytes written to @p result, of a
|
||||
* value less than zero on error. The parameter @p desc may
|
||||
* contain additional request information (e.g. the psk_identity
|
||||
* for which a key is requested when @p type == @c DTLS_PSK_KEY.
|
||||
*
|
||||
* @param ctx The current dtls context.
|
||||
* @param session The session where the key will be used.
|
||||
* @param type The type of the requested information.
|
||||
* @param desc Additional request information
|
||||
* @param desc_len The actual length of desc.
|
||||
* @param result Must be filled with the requested information.
|
||||
* @param result_length Maximum size of @p result.
|
||||
* @return The number of bytes written to @p result or a value
|
||||
* less than zero on error.
|
||||
*/
|
||||
int (*get_psk_info)(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
dtls_credentials_type_t type,
|
||||
const unsigned char *desc, size_t desc_len,
|
||||
unsigned char *result, size_t result_length);
|
||||
|
||||
#endif /* DTLS_PSK */
|
||||
|
||||
#ifdef DTLS_ECC
|
||||
/**
|
||||
* Called during handshake to get the server's or client's ecdsa
|
||||
* key used to authenticate this server or client in this
|
||||
* session. If found, the key must be stored in @p result and
|
||||
* the return value must be @c 0. If not found, @p result is
|
||||
* undefined and the return value must be less than zero.
|
||||
*
|
||||
* If ECDSA should not be supported, set this pointer to NULL.
|
||||
*
|
||||
* Implement this if you want to provide your own certificate to
|
||||
* the other peer. This is mandatory for a server providing ECDSA
|
||||
* support and optional for a client. A client doing DTLS client
|
||||
* authentication has to implementing this callback.
|
||||
*
|
||||
* @param ctx The current dtls context.
|
||||
* @param session The session where the key will be used.
|
||||
* @param result Must be set to the key object to used for the given
|
||||
* session.
|
||||
* @return @c 0 if result is set, or less than zero on error.
|
||||
*/
|
||||
int (*get_ecdsa_key)(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const dtls_ecdsa_key_t **result);
|
||||
|
||||
/**
|
||||
* Called during handshake to check the peer's pubic key in this
|
||||
* session. If the public key matches the session and should be
|
||||
* considerated valid the return value must be @c 0. If not valid,
|
||||
* the return value must be less than zero.
|
||||
*
|
||||
* If ECDSA should not be supported, set this pointer to NULL.
|
||||
*
|
||||
* Implement this if you want to verify the other peers public key.
|
||||
* This is mandatory for a DTLS client doing based ECDSA
|
||||
* authentication. A server implementing this will request the
|
||||
* client to do DTLS client authentication.
|
||||
*
|
||||
* @param ctx The current dtls context.
|
||||
* @param session The session where the key will be used.
|
||||
* @param other_pub_x x component of the public key.
|
||||
* @param other_pub_y y component of the public key.
|
||||
* @return @c 0 if public key matches, or less than zero on error.
|
||||
* error codes:
|
||||
* return dtls_alert_fatal_create(DTLS_ALERT_BAD_CERTIFICATE);
|
||||
* return dtls_alert_fatal_create(DTLS_ALERT_UNSUPPORTED_CERTIFICATE);
|
||||
* return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_REVOKED);
|
||||
* return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_EXPIRED);
|
||||
* return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_UNKNOWN);
|
||||
* return dtls_alert_fatal_create(DTLS_ALERT_UNKNOWN_CA);
|
||||
*/
|
||||
int (*verify_ecdsa_key)(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const unsigned char *other_pub_x,
|
||||
const unsigned char *other_pub_y,
|
||||
size_t key_size);
|
||||
#endif /* DTLS_ECC */
|
||||
} dtls_handler_t;
|
||||
|
||||
struct netq_t;
|
||||
|
||||
/** Holds global information of the DTLS engine. */
|
||||
typedef struct dtls_context_t {
|
||||
unsigned char cookie_secret[DTLS_COOKIE_SECRET_LENGTH];
|
||||
clock_time_t cookie_secret_age; /**< the time the secret has been generated */
|
||||
|
||||
dtls_peer_t *peers; /**< peer hash map */
|
||||
#ifdef WITH_CONTIKI
|
||||
struct etimer retransmit_timer; /**< fires when the next packet must be sent */
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
struct netq_t *sendqueue; /**< the packets to send */
|
||||
|
||||
void *app; /**< application-specific data */
|
||||
|
||||
dtls_handler_t *h; /**< callback handlers */
|
||||
|
||||
unsigned char readbuf[DTLS_MAX_BUF];
|
||||
} dtls_context_t;
|
||||
|
||||
/**
|
||||
* This function initializes the tinyDTLS memory management and must
|
||||
* be called first.
|
||||
*/
|
||||
void dtls_init();
|
||||
|
||||
/**
|
||||
* Creates a new context object. The storage allocated for the new
|
||||
* object must be released with dtls_free_context(). */
|
||||
dtls_context_t *dtls_new_context(void *app_data);
|
||||
|
||||
/** Releases any storage that has been allocated for \p ctx. */
|
||||
void dtls_free_context(dtls_context_t *ctx);
|
||||
|
||||
#define dtls_set_app_data(CTX,DATA) ((CTX)->app = (DATA))
|
||||
#define dtls_get_app_data(CTX) ((CTX)->app)
|
||||
|
||||
/** Sets the callback handler object for @p ctx to @p h. */
|
||||
static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) {
|
||||
ctx->h = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a DTLS channel with the specified remote peer @p dst.
|
||||
* This function returns @c 0 if that channel already exists, a value
|
||||
* greater than zero when a new ClientHello message was sent, and
|
||||
* a value less than zero on error.
|
||||
*
|
||||
* @param ctx The DTLS context to use.
|
||||
* @param dst The remote party to connect to.
|
||||
* @return A value less than zero on error, greater or equal otherwise.
|
||||
*/
|
||||
int dtls_connect(dtls_context_t *ctx, const session_t *dst);
|
||||
|
||||
/**
|
||||
* Establishes a DTLS channel with the specified remote peer.
|
||||
* This function returns @c 0 if that channel already exists, a value
|
||||
* greater than zero when a new ClientHello message was sent, and
|
||||
* a value less than zero on error.
|
||||
*
|
||||
* @param ctx The DTLS context to use.
|
||||
* @param peer The peer object that describes the session.
|
||||
* @return A value less than zero on error, greater or equal otherwise.
|
||||
*/
|
||||
int dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer);
|
||||
|
||||
/**
|
||||
* Closes the DTLS connection associated with @p remote. This function
|
||||
* returns zero on success, and a value less than zero on error.
|
||||
*/
|
||||
int dtls_close(dtls_context_t *ctx, const session_t *remote);
|
||||
|
||||
int dtls_renegotiate(dtls_context_t *ctx, const session_t *dst);
|
||||
|
||||
/**
|
||||
* Writes the application data given in @p buf to the peer specified
|
||||
* by @p session.
|
||||
*
|
||||
* @param ctx The DTLS context to use.
|
||||
* @param session The remote transport address and local interface.
|
||||
* @param buf The data to write.
|
||||
* @param len The actual length of @p data.
|
||||
*
|
||||
* @return The number of bytes written or @c -1 on error.
|
||||
*/
|
||||
int dtls_write(struct dtls_context_t *ctx, session_t *session,
|
||||
uint8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Checks sendqueue of given DTLS context object for any outstanding
|
||||
* packets to be transmitted.
|
||||
*
|
||||
* @param context The DTLS context object to use.
|
||||
* @param next If not NULL, @p next is filled with the timestamp
|
||||
* of the next scheduled retransmission, or @c 0 when no packets are
|
||||
* waiting.
|
||||
*/
|
||||
void dtls_check_retransmit(dtls_context_t *context, clock_time_t *next);
|
||||
|
||||
#define DTLS_COOKIE_LENGTH 16
|
||||
|
||||
#define DTLS_CT_CHANGE_CIPHER_SPEC 20
|
||||
#define DTLS_CT_ALERT 21
|
||||
#define DTLS_CT_HANDSHAKE 22
|
||||
#define DTLS_CT_APPLICATION_DATA 23
|
||||
|
||||
/** Generic header structure of the DTLS record layer. */
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8 content_type; /**< content type of the included message */
|
||||
uint16 version; /**< Protocol version */
|
||||
uint16 epoch; /**< counter for cipher state changes */
|
||||
uint48 sequence_number; /**< sequence number */
|
||||
uint16 length; /**< length of the following fragment */
|
||||
/* fragment */
|
||||
} dtls_record_header_t;
|
||||
|
||||
/* Handshake types */
|
||||
|
||||
#define DTLS_HT_HELLO_REQUEST 0
|
||||
#define DTLS_HT_CLIENT_HELLO 1
|
||||
#define DTLS_HT_SERVER_HELLO 2
|
||||
#define DTLS_HT_HELLO_VERIFY_REQUEST 3
|
||||
#define DTLS_HT_CERTIFICATE 11
|
||||
#define DTLS_HT_SERVER_KEY_EXCHANGE 12
|
||||
#define DTLS_HT_CERTIFICATE_REQUEST 13
|
||||
#define DTLS_HT_SERVER_HELLO_DONE 14
|
||||
#define DTLS_HT_CERTIFICATE_VERIFY 15
|
||||
#define DTLS_HT_CLIENT_KEY_EXCHANGE 16
|
||||
#define DTLS_HT_FINISHED 20
|
||||
|
||||
/** Header structure for the DTLS handshake protocol. */
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8 msg_type; /**< Type of handshake message (one of DTLS_HT_) */
|
||||
uint24 length; /**< length of this message */
|
||||
uint16 message_seq; /**< Message sequence number */
|
||||
uint24 fragment_offset; /**< Fragment offset. */
|
||||
uint24 fragment_length; /**< Fragment length. */
|
||||
/* body */
|
||||
} dtls_handshake_header_t;
|
||||
|
||||
/** Structure of the Client Hello message. */
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint16 version; /**< Client version */
|
||||
uint32 gmt_random; /**< GMT time of the random byte creation */
|
||||
unsigned char random[28]; /**< Client random bytes */
|
||||
/* session id (up to 32 bytes) */
|
||||
/* cookie (up to 32 bytes) */
|
||||
/* cipher suite (2 to 2^16 -1 bytes) */
|
||||
/* compression method */
|
||||
} dtls_client_hello_t;
|
||||
|
||||
/** Structure of the Hello Verify Request. */
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint16 version; /**< Server version */
|
||||
uint8 cookie_length; /**< Length of the included cookie */
|
||||
uint8 cookie[]; /**< up to 32 bytes making up the cookie */
|
||||
} dtls_hello_verify_t;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Checks a received DTLS record for consistency and eventually decrypt,
|
||||
* verify, decompress and reassemble the contained fragment for
|
||||
* delivery to high-lever clients.
|
||||
*
|
||||
* \param state The DTLS record state for the current session.
|
||||
* \param
|
||||
*/
|
||||
int dtls_record_read(dtls_state_t *state, uint8 *msg, int msglen);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Handles incoming data as DTLS message from given peer.
|
||||
*
|
||||
* @param ctx The dtls context to use.
|
||||
* @param session The current session
|
||||
* @param msg The received data
|
||||
* @param msglen The actual length of @p msg.
|
||||
* @return A value less than zero on error, zero on success.
|
||||
*/
|
||||
int dtls_handle_message(dtls_context_t *ctx, session_t *session,
|
||||
uint8 *msg, int msglen);
|
||||
|
||||
/**
|
||||
* Check if @p session is associated with a peer object in @p context.
|
||||
* This function returns a pointer to the peer if found, NULL otherwise.
|
||||
*
|
||||
* @param context The DTLS context to search.
|
||||
* @param session The remote address and local interface
|
||||
* @return A pointer to the peer associated with @p session or NULL if
|
||||
* none exists.
|
||||
*/
|
||||
dtls_peer_t *dtls_get_peer(const dtls_context_t *context,
|
||||
const session_t *session);
|
||||
|
||||
/**
|
||||
* Resets all connections with @p peer.
|
||||
*
|
||||
* @param context The active DTLS context.
|
||||
* @param peer The peer to reset.
|
||||
*/
|
||||
void dtls_reset_peer(dtls_context_t *context, dtls_peer_t *peer);
|
||||
|
||||
#endif /* _DTLS_DTLS_H_ */
|
||||
|
||||
/**
|
||||
* @mainpage
|
||||
*
|
||||
* @author Olaf Bergmann, TZI Uni Bremen
|
||||
*
|
||||
* This library provides a very simple datagram server with DTLS
|
||||
* support. It is designed to support session multiplexing in
|
||||
* single-threaded applications and thus targets specifically on
|
||||
* embedded systems.
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* This software is under the <a
|
||||
* href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>.
|
||||
*
|
||||
* @subsection uthash UTHash
|
||||
*
|
||||
* This library uses <a href="http://uthash.sourceforge.net/">uthash</a> to manage
|
||||
* its peers (not used for Contiki). @b uthash uses the <b>BSD revised license</b>, see
|
||||
* <a href="http://uthash.sourceforge.net/license.html">http://uthash.sourceforge.net/license.html</a>.
|
||||
*
|
||||
* @subsection sha256 Aaron D. Gifford's SHA256 Implementation
|
||||
*
|
||||
* tinyDTLS provides HMAC-SHA256 with BSD-licensed code from Aaron D. Gifford,
|
||||
* see <a href="http://www.aarongifford.com/">www.aarongifford.com</a>.
|
||||
*
|
||||
* @subsection aes Rijndael Implementation From OpenBSD
|
||||
*
|
||||
* The AES implementation is taken from rijndael.{c,h} contained in the crypto
|
||||
* sub-system of the OpenBSD operating system. It is copyright by Vincent Rijmen, *
|
||||
* Antoon Bosselaers and Paulo Barreto. See <a
|
||||
* href="http://www.openbsd.org/cgi-bin/cvsweb/src/sys/crypto/rijndael.c">rijndael.c</a>
|
||||
* for License info.
|
||||
*
|
||||
* @section download Getting the Files
|
||||
*
|
||||
* You can get the sources either from the <a
|
||||
* href="http://sourceforge.net/projects/tinydtls/files">downloads</a> section or
|
||||
* through git from the <a
|
||||
* href="http://sourceforge.net/projects/tinydtls/develop">project develop page</a>.
|
||||
*
|
||||
* @section config Configuration
|
||||
*
|
||||
* Use @c configure to set up everything for a successful build. For Contiki, use the
|
||||
* option @c --with-contiki.
|
||||
*
|
||||
* @section build Building
|
||||
*
|
||||
* After configuration, just type
|
||||
* @code
|
||||
make
|
||||
* @endcode
|
||||
* optionally followed by
|
||||
* @code
|
||||
make install
|
||||
* @endcode
|
||||
* The Contiki version is integrated with the Contiki build system, hence you do not
|
||||
* need to invoke @c make explicitely. Just add @c tinydtls to the variable @c APPS
|
||||
* in your @c Makefile.
|
||||
*
|
||||
* @addtogroup dtls_usage DTLS Usage
|
||||
*
|
||||
* @section dtls_server_example DTLS Server Example
|
||||
*
|
||||
* This section shows how to use the DTLS library functions to setup a
|
||||
* simple secure UDP echo server. The application is responsible for the
|
||||
* entire network communication and thus will look like a usual UDP
|
||||
* server with socket creation and binding and a typical select-loop as
|
||||
* shown below. The minimum configuration required for DTLS is the
|
||||
* creation of the dtls_context_t using dtls_new_context(), and a callback
|
||||
* for sending data. Received packets are read by the application and
|
||||
* passed to dtls_handle_message() as shown in @ref dtls_read_cb.
|
||||
* For any useful communication to happen, read and write call backs
|
||||
* and a key management function should be registered as well.
|
||||
*
|
||||
* @code
|
||||
dtls_context_t *the_context = NULL;
|
||||
int fd, result;
|
||||
|
||||
static dtls_handler_t cb = {
|
||||
.write = send_to_peer,
|
||||
.read = read_from_peer,
|
||||
.event = NULL,
|
||||
.get_psk_key = get_psk_key
|
||||
};
|
||||
|
||||
fd = socket(...);
|
||||
if (fd < 0 || bind(fd, ...) < 0)
|
||||
exit(-1);
|
||||
|
||||
the_context = dtls_new_context(&fd);
|
||||
dtls_set_handler(the_context, &cb);
|
||||
|
||||
while (1) {
|
||||
...initialize fd_set rfds and timeout ...
|
||||
result = select(fd+1, &rfds, NULL, 0, NULL);
|
||||
|
||||
if (FD_ISSET(fd, &rfds))
|
||||
dtls_handle_read(the_context);
|
||||
}
|
||||
|
||||
dtls_free_context(the_context);
|
||||
* @endcode
|
||||
*
|
||||
* @subsection dtls_read_cb The Read Callback
|
||||
*
|
||||
* The DTLS library expects received raw data to be passed to
|
||||
* dtls_handle_message(). The application is responsible for
|
||||
* filling a session_t structure with the address data of the
|
||||
* remote peer as illustrated by the following example:
|
||||
*
|
||||
* @code
|
||||
int dtls_handle_read(struct dtls_context_t *ctx) {
|
||||
int *fd;
|
||||
session_t session;
|
||||
static uint8 buf[DTLS_MAX_BUF];
|
||||
int len;
|
||||
|
||||
fd = dtls_get_app_data(ctx);
|
||||
|
||||
assert(fd);
|
||||
|
||||
session.size = sizeof(session.addr);
|
||||
len = recvfrom(*fd, buf, sizeof(buf), 0, &session.addr.sa, &session.size);
|
||||
|
||||
return len < 0 ? len : dtls_handle_message(ctx, &session, buf, len);
|
||||
}
|
||||
* @endcode
|
||||
*
|
||||
* Once a new DTLS session was established and DTLS ApplicationData has been
|
||||
* received, the DTLS server invokes the read callback with the MAC-verified
|
||||
* cleartext data as its argument. A read callback for a simple echo server
|
||||
* could look like this:
|
||||
* @code
|
||||
int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
|
||||
return dtls_write(ctx, session, data, len);
|
||||
}
|
||||
* @endcode
|
||||
*
|
||||
* @subsection dtls_send_cb The Send Callback
|
||||
*
|
||||
* The callback function send_to_peer() is called whenever data must be
|
||||
* sent over the network. Here, the sendto() system call is used to
|
||||
* transmit data within the given session. The socket descriptor required
|
||||
* by sendto() has been registered as application data when the DTLS context
|
||||
* was created with dtls_new_context().
|
||||
* Note that it is on the application to buffer the data when it cannot be
|
||||
* sent at the time this callback is invoked. The following example thus
|
||||
* is incomplete as it would have to deal with EAGAIN somehow.
|
||||
* @code
|
||||
int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
|
||||
int fd = *(int *)dtls_get_app_data(ctx);
|
||||
return sendto(fd, data, len, MSG_DONTWAIT, &session->addr.sa, session->size);
|
||||
}
|
||||
* @endcode
|
||||
*
|
||||
* @subsection dtls_get_psk_info The Key Storage
|
||||
*
|
||||
* When a new DTLS session is created, the library must ask the application
|
||||
* for keying material. To do so, it invokes the registered call-back function
|
||||
* get_psk_info() with the current context and session information as parameter.
|
||||
* When the call-back function is invoked with the parameter @p type set to
|
||||
* @c DTLS_PSK_IDENTITY, the result parameter @p result must be filled with
|
||||
* the psk_identity_hint in case of a server, or the actual psk_identity in
|
||||
* case of a client. When @p type is @c DTLS_PSK_KEY, the result parameter
|
||||
* must be filled with a key for the given identity @p id. The function must
|
||||
* return the number of bytes written to @p result which must not exceed
|
||||
* @p result_length.
|
||||
* In case of an error, the function must return a negative value that
|
||||
* corresponds to a valid error code defined in alert.h.
|
||||
*
|
||||
* @code
|
||||
int get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
|
||||
const session_t *session UNUSED_PARAM,
|
||||
dtls_credentials_type_t type,
|
||||
const unsigned char *id, size_t id_len,
|
||||
unsigned char *result, size_t result_length) {
|
||||
|
||||
switch (type) {
|
||||
case DTLS_PSK_IDENTITY:
|
||||
if (result_length < psk_id_length) {
|
||||
dtls_warn("cannot set psk_identity -- buffer too small\n");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
memcpy(result, psk_id, psk_id_length);
|
||||
return psk_id_length;
|
||||
case DTLS_PSK_KEY:
|
||||
if (id_len != psk_id_length || memcmp(psk_id, id, id_len) != 0) {
|
||||
dtls_warn("PSK for unknown id requested, exiting\n");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_ILLEGAL_PARAMETER);
|
||||
} else if (result_length < psk_key_length) {
|
||||
dtls_warn("cannot set psk -- buffer too small\n");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
memcpy(result, psk_key, psk_key_length);
|
||||
return psk_key_length;
|
||||
default:
|
||||
dtls_warn("unsupported request type: %d\n", type);
|
||||
}
|
||||
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
* @endcode
|
||||
*
|
||||
* @subsection dtls_events The Event Notifier
|
||||
*
|
||||
* Applications that want to be notified whenever the status of a DTLS session
|
||||
* has changed can register an event handling function with the field @c event
|
||||
* in the dtls_handler_t structure (see \ref dtls_server_example). The call-back
|
||||
* function is called for alert messages and internal state changes. For alert
|
||||
* messages, the argument @p level will be set to a value greater than zero, and
|
||||
* @p code will indicate the notification code. For internal events, @p level
|
||||
* is @c 0, and @p code a value greater than @c 255.
|
||||
*
|
||||
* Internal events are DTLS_EVENT_CONNECTED, @c DTLS_EVENT_CONNECT, and
|
||||
* @c DTLS_EVENT_RENEGOTIATE.
|
||||
*
|
||||
* @code
|
||||
int handle_event(struct dtls_context_t *ctx, session_t *session,
|
||||
dtls_alert_level_t level, unsigned short code) {
|
||||
... do something with event ...
|
||||
return 0;
|
||||
}
|
||||
* @endcode
|
||||
*
|
||||
* @section dtls_client_example DTLS Client Example
|
||||
*
|
||||
* A DTLS client is constructed like a server but needs to actively setup
|
||||
* a new session by calling dtls_connect() at some point. As this function
|
||||
* usually returns before the new DTLS channel is established, the application
|
||||
* must register an event handler and wait for @c DTLS_EVENT_CONNECT before
|
||||
* it can send data over the DTLS channel.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup contiki Contiki
|
||||
*
|
||||
* To use tinyDTLS as Contiki application, place the source code in the directory
|
||||
* @c apps/tinydtls in the Contiki source tree and invoke configure with the option
|
||||
* @c --with-contiki. This will define WITH_CONTIKI in tinydtls.h and include
|
||||
* @c Makefile.contiki in the main Makefile. To cross-compile for another platform
|
||||
* you will need to set your host and build system accordingly. For example,
|
||||
* when configuring for ARM, you would invoke
|
||||
* @code
|
||||
./configure --with-contiki --build=x86_64-linux-gnu --host=arm-none-eabi
|
||||
* @endcode
|
||||
* on an x86_64 linux host.
|
||||
*
|
||||
* Then, create a Contiki project with @c APPS += tinydtls in its Makefile. A sample
|
||||
* server could look like this (with read_from_peer() and get_psk_key() as shown above).
|
||||
*
|
||||
* @code
|
||||
#include "contiki.h"
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "dtls.h"
|
||||
|
||||
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||
#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
|
||||
|
||||
int send_to_peer(struct dtls_context_t *, session_t *, uint8 *, size_t);
|
||||
|
||||
static struct uip_udp_conn *server_conn;
|
||||
static dtls_context_t *dtls_context;
|
||||
|
||||
static dtls_handler_t cb = {
|
||||
.write = send_to_peer,
|
||||
.read = read_from_peer,
|
||||
.event = NULL,
|
||||
.get_psk_key = get_psk_key
|
||||
};
|
||||
|
||||
PROCESS(server_process, "DTLS server process");
|
||||
AUTOSTART_PROCESSES(&server_process);
|
||||
|
||||
PROCESS_THREAD(server_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
|
||||
dtls_init();
|
||||
|
||||
server_conn = udp_new(NULL, 0, NULL);
|
||||
udp_bind(server_conn, UIP_HTONS(5684));
|
||||
|
||||
dtls_context = dtls_new_context(server_conn);
|
||||
if (!dtls_context) {
|
||||
dtls_emerg("cannot create context\n");
|
||||
PROCESS_EXIT();
|
||||
}
|
||||
|
||||
dtls_set_handler(dtls_context, &cb);
|
||||
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT();
|
||||
if(ev == tcpip_event && uip_newdata()) {
|
||||
session_t session;
|
||||
|
||||
uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr);
|
||||
session.port = UIP_UDP_BUF->srcport;
|
||||
session.size = sizeof(session.addr) + sizeof(session.port);
|
||||
|
||||
dtls_handle_message(ctx, &session, uip_appdata, uip_datalen());
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
|
||||
int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
|
||||
struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx);
|
||||
|
||||
uip_ipaddr_copy(&conn->ripaddr, &session->addr);
|
||||
conn->rport = session->port;
|
||||
|
||||
uip_udp_packet_send(conn, data, len);
|
||||
|
||||
memset(&conn->ripaddr, 0, sizeof(server_conn->ripaddr));
|
||||
memset(&conn->rport, 0, sizeof(conn->rport));
|
||||
|
||||
return len;
|
||||
}
|
||||
* @endcode
|
||||
*/
|
71
dtls_time.c
Normal file
71
dtls_time.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file dtls_time.c
|
||||
* @brief Clock Handling
|
||||
*/
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "dtls_config.h"
|
||||
#include "dtls_time.h"
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
clock_time_t dtls_clock_offset;
|
||||
|
||||
void
|
||||
dtls_clock_init(void) {
|
||||
clock_init();
|
||||
dtls_clock_offset = clock_time();
|
||||
}
|
||||
|
||||
void
|
||||
dtls_ticks(dtls_tick_t *t) {
|
||||
*t = clock_time();
|
||||
}
|
||||
|
||||
#else /* WITH_CONTIKI */
|
||||
|
||||
time_t dtls_clock_offset;
|
||||
|
||||
void
|
||||
dtls_clock_init(void) {
|
||||
#ifdef HAVE_TIME_H
|
||||
dtls_clock_offset = time(NULL);
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
/* Issue a warning when using gcc. Other prepropressors do
|
||||
* not seem to have a similar feature. */
|
||||
# warning "cannot initialize clock"
|
||||
# endif
|
||||
dtls_clock_offset = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void dtls_ticks(dtls_tick_t *t) {
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
*t = (tv.tv_sec - dtls_clock_offset) * DTLS_TICKS_PER_SECOND
|
||||
+ (tv.tv_usec * DTLS_TICKS_PER_SECOND / 1000000);
|
||||
#else
|
||||
#error "clock not implemented"
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
|
60
dtls_time.h
Normal file
60
dtls_time.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file dtls_time.h
|
||||
* @brief Clock Handling
|
||||
*/
|
||||
|
||||
#ifndef _DTLS_DTLS_TIME_H_
|
||||
#define _DTLS_DTLS_TIME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "tinydtls.h"
|
||||
|
||||
/**
|
||||
* @defgroup clock Clock Handling
|
||||
* Default implementation of internal clock. You should redefine this if
|
||||
* you do not have time() and gettimeofday().
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
#include "clock.h"
|
||||
#else /* WITH_CONTIKI */
|
||||
#include <time.h>
|
||||
|
||||
#ifndef CLOCK_SECOND
|
||||
# define CLOCK_SECOND 1000
|
||||
#endif
|
||||
|
||||
typedef uint32_t clock_time_t;
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
typedef clock_time_t dtls_tick_t;
|
||||
|
||||
#ifndef DTLS_TICKS_PER_SECOND
|
||||
#define DTLS_TICKS_PER_SECOND CLOCK_SECOND
|
||||
#endif /* DTLS_TICKS_PER_SECOND */
|
||||
|
||||
void dtls_clock_init(void);
|
||||
void dtls_ticks(dtls_tick_t *t);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* _DTLS_DTLS_TIME_H_ */
|
7
ecc/Makefile.contiki
Normal file
7
ecc/Makefile.contiki
Normal file
@ -0,0 +1,7 @@
|
||||
CONTIKI=../../..
|
||||
|
||||
APPS += ecc
|
||||
|
||||
CFLAGS += -DTEST_INCLUDE
|
||||
|
||||
include $(CONTIKI)/Makefile.include
|
3
ecc/Makefile.ecc
Normal file
3
ecc/Makefile.ecc
Normal file
@ -0,0 +1,3 @@
|
||||
# This is a -*- Makefile -*-
|
||||
|
||||
ecc_src = ecc.c test_helper.c
|
81
ecc/Makefile.in
Normal file
81
ecc/Makefile.in
Normal file
@ -0,0 +1,81 @@
|
||||
# Makefile for tinydtls
|
||||
#
|
||||
# Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Olaf Bergmann - initial API and implementation
|
||||
# Hauke Mehrtens - memory optimization, ECC integration
|
||||
#
|
||||
|
||||
# the library's version
|
||||
VERSION:=@PACKAGE_VERSION@
|
||||
|
||||
# tools
|
||||
@SET_MAKE@
|
||||
SHELL = /bin/sh
|
||||
MKDIR = mkdir
|
||||
|
||||
abs_builddir = @abs_builddir@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir:= @top_srcdir@
|
||||
|
||||
ECC_SOURCES:= ecc.c testecc.c testfield.c test_helper.c
|
||||
ECC_HEADERS:= ecc.h test_helper.h
|
||||
FILES:=Makefile.in Makefile.contiki $(ECC_SOURCES) $(ECC_HEADERS)
|
||||
DISTDIR=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
|
||||
ifeq ("@WITH_CONTIKI@", "1")
|
||||
include Makefile.contiki
|
||||
else
|
||||
ECC_OBJECTS:= $(patsubst %.c, %.o, $(ECC_SOURCES)) ecc_test.o
|
||||
PROGRAMS:= testecc testfield
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
CFLAGS=-Wall -std=c99 -pedantic @CFLAGS@ -DTEST_INCLUDE
|
||||
LDLIBS=@LIBS@
|
||||
|
||||
.PHONY: all dirs clean install distclean .gitignore doc
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
ecc_test.o: ecc.c ecc.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
testecc: ecc_test.o test_helper.o
|
||||
|
||||
testfield: ecc_test.o test_helper.o
|
||||
|
||||
check:
|
||||
echo DISTDIR: $(DISTDIR)
|
||||
echo top_builddir: $(top_builddir)
|
||||
|
||||
clean:
|
||||
@rm -f $(PROGRAMS) main.o $(LIB) $(OBJECTS)
|
||||
for dir in $(SUBDIRS); do \
|
||||
$(MAKE) -C $$dir clean ; \
|
||||
done
|
||||
|
||||
distclean: clean
|
||||
@rm -rf $(DISTDIR)
|
||||
@rm -f *~ $(DISTDIR).tar.gz
|
||||
endif # WITH_CONTIKI
|
||||
|
||||
dist: $(FILES)
|
||||
test -d $(DISTDIR)/ecc || mkdir $(DISTDIR)/ecc
|
||||
cp -p $(FILES) $(DISTDIR)/ecc
|
||||
|
||||
install: $(ECC_HEADERS)
|
||||
test -d $(includedir)/ecc || mkdir -p $(includedir)/ecc
|
||||
$(install) $(ECC_HEADERS) $(includedir)/ecc
|
||||
|
||||
.gitignore:
|
||||
echo "core\n*~\n*.[oa]\n*.gz\n*.cap\n$(PROGRAM)\n$(DISTDIR)\n.gitignore" >$@
|
141
global.h
Normal file
141
global.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _DTLS_GLOBAL_H_
|
||||
#define _DTLS_GLOBAL_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "tinydtls.h"
|
||||
|
||||
#ifndef DTLSv12
|
||||
/* The current version of tinyDTLS supports DTLSv1.2 only. */
|
||||
#define DTLSv12 1
|
||||
#endif
|
||||
|
||||
#ifndef WITH_SHA256
|
||||
/* The current version of tinyDTLS supports DTLSv1.2 with SHA256 PRF
|
||||
only. */
|
||||
#define WITH_SHA256 1
|
||||
#endif
|
||||
|
||||
/* Define our own types as at least uint32_t does not work on my amd64. */
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned char uint16[2];
|
||||
typedef unsigned char uint24[3];
|
||||
typedef unsigned char uint32[4];
|
||||
typedef unsigned char uint48[6];
|
||||
|
||||
#ifndef DTLS_MAX_BUF
|
||||
/** Maximum size of DTLS message.
|
||||
When Peers are sending bigger messages this causes problems. Californium
|
||||
with ECDSA needs at least 220 */
|
||||
#ifdef WITH_CONTIKI
|
||||
#ifdef DTLS_ECC
|
||||
#define DTLS_MAX_BUF 200
|
||||
#else /* DTLS_ECC */
|
||||
#define DTLS_MAX_BUF 100
|
||||
#endif /* DTLS_ECC */
|
||||
#else /* WITH_CONTIKI */
|
||||
#define DTLS_MAX_BUF 1400
|
||||
#endif /* WITH_CONTIKI */
|
||||
#endif
|
||||
|
||||
#ifndef DTLS_DEFAULT_MAX_RETRANSMIT
|
||||
/** Number of message retransmissions. */
|
||||
#define DTLS_DEFAULT_MAX_RETRANSMIT 7
|
||||
#endif
|
||||
|
||||
/** Known cipher suites.*/
|
||||
typedef enum {
|
||||
TLS_NULL_WITH_NULL_NULL = 0x0000, /**< NULL cipher */
|
||||
TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8, /**< see RFC 6655 */
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE /**< see RFC 7251 */
|
||||
} dtls_cipher_t;
|
||||
|
||||
/** Known compression suites.*/
|
||||
typedef enum {
|
||||
TLS_COMPRESSION_NULL = 0x0000 /* NULL compression */
|
||||
} dtls_compression_t;
|
||||
|
||||
#define TLS_EXT_ELLIPTIC_CURVES 10 /* see RFC 4492 */
|
||||
#define TLS_EXT_EC_POINT_FORMATS 11 /* see RFC 4492 */
|
||||
#define TLS_EXT_SIG_HASH_ALGO 13 /* see RFC 5246 */
|
||||
#define TLS_EXT_CLIENT_CERTIFICATE_TYPE 19 /* see RFC 7250 */
|
||||
#define TLS_EXT_SERVER_CERTIFICATE_TYPE 20 /* see RFC 7250 */
|
||||
#define TLS_EXT_ENCRYPT_THEN_MAC 22 /* see RFC 7366 */
|
||||
|
||||
#define TLS_CERT_TYPE_RAW_PUBLIC_KEY 2 /* see RFC 7250 */
|
||||
|
||||
#define TLS_EXT_ELLIPTIC_CURVES_SECP256R1 23 /* see RFC 4492 */
|
||||
|
||||
#define TLS_EXT_EC_POINT_FORMATS_UNCOMPRESSED 0 /* see RFC 4492 */
|
||||
|
||||
#define TLS_EC_CURVE_TYPE_NAMED_CURVE 3 /* see RFC 4492 */
|
||||
|
||||
#define TLS_CLIENT_CERTIFICATE_TYPE_ECDSA_SIGN 64 /* see RFC 4492 */
|
||||
|
||||
#define TLS_EXT_SIG_HASH_ALGO_SHA256 4 /* see RFC 5246 */
|
||||
#define TLS_EXT_SIG_HASH_ALGO_ECDSA 3 /* see RFC 5246 */
|
||||
|
||||
/**
|
||||
* XORs \p n bytes byte-by-byte starting at \p y to the memory area
|
||||
* starting at \p x. */
|
||||
static inline void
|
||||
memxor(unsigned char *x, const unsigned char *y, size_t n) {
|
||||
while(n--) {
|
||||
*x ^= *y;
|
||||
x++; y++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares \p len bytes from @p a with @p b in constant time. This
|
||||
* functions always traverses the entire length to prevent timing
|
||||
* attacks.
|
||||
*
|
||||
* \param a Byte sequence to compare
|
||||
* \param b Byte sequence to compare
|
||||
* \param len Number of bytes to compare.
|
||||
* \return \c 1 if \p a and \p b are equal, \c 0 otherwise.
|
||||
*/
|
||||
static inline int
|
||||
equals(unsigned char *a, unsigned char *b, size_t len) {
|
||||
int result = 1;
|
||||
while (len--) {
|
||||
result &= (*a++ == *b++);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FLS
|
||||
#define dtls_fls(i) fls(i)
|
||||
#else
|
||||
static inline int
|
||||
dtls_fls(unsigned int i) {
|
||||
int n;
|
||||
for (n = 0; i; n++)
|
||||
i >>= 1;
|
||||
return n;
|
||||
}
|
||||
#endif /* HAVE_FLS */
|
||||
|
||||
#define uthash_fatal(msg) return(-1) /* fatal error in uthash */
|
||||
|
||||
#endif /* _DTLS_GLOBAL_H_ */
|
165
hmac.c
Normal file
165
hmac.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dtls_config.h"
|
||||
|
||||
#ifdef HAVE_ASSERT_H
|
||||
#include <assert.h>
|
||||
#else
|
||||
#define assert(x)
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "hmac.h"
|
||||
|
||||
/* use malloc()/free() on platforms other than Contiki */
|
||||
#ifndef WITH_CONTIKI
|
||||
#include <stdlib.h>
|
||||
|
||||
static inline dtls_hmac_context_t *
|
||||
dtls_hmac_context_new() {
|
||||
return (dtls_hmac_context_t *)malloc(sizeof(dtls_hmac_context_t));
|
||||
}
|
||||
|
||||
static inline void
|
||||
dtls_hmac_context_free(dtls_hmac_context_t *ctx) {
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
#else /* WITH_CONTIKI */
|
||||
#include "memb.h"
|
||||
MEMB(hmac_context_storage, dtls_hmac_context_t, DTLS_HASH_MAX);
|
||||
|
||||
static inline dtls_hmac_context_t *
|
||||
dtls_hmac_context_new() {
|
||||
return (dtls_hmac_context_t *)memb_alloc(&hmac_context_storage);
|
||||
}
|
||||
|
||||
static inline void
|
||||
dtls_hmac_context_free(dtls_hmac_context_t *ctx) {
|
||||
memb_free(&hmac_context_storage, ctx);
|
||||
}
|
||||
|
||||
void
|
||||
dtls_hmac_storage_init() {
|
||||
memb_init(&hmac_context_storage);
|
||||
}
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
void
|
||||
dtls_hmac_update(dtls_hmac_context_t *ctx,
|
||||
const unsigned char *input, size_t ilen) {
|
||||
assert(ctx);
|
||||
dtls_hash_update(&ctx->data, input, ilen);
|
||||
}
|
||||
|
||||
dtls_hmac_context_t *
|
||||
dtls_hmac_new(const unsigned char *key, size_t klen) {
|
||||
dtls_hmac_context_t *ctx;
|
||||
|
||||
ctx = dtls_hmac_context_new();
|
||||
if (ctx)
|
||||
dtls_hmac_init(ctx, key, klen);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void
|
||||
dtls_hmac_init(dtls_hmac_context_t *ctx, const unsigned char *key, size_t klen) {
|
||||
int i;
|
||||
|
||||
assert(ctx);
|
||||
|
||||
memset(ctx, 0, sizeof(dtls_hmac_context_t));
|
||||
|
||||
if (klen > DTLS_HMAC_BLOCKSIZE) {
|
||||
dtls_hash_init(&ctx->data);
|
||||
dtls_hash_update(&ctx->data, key, klen);
|
||||
dtls_hash_finalize(ctx->pad, &ctx->data);
|
||||
} else
|
||||
memcpy(ctx->pad, key, klen);
|
||||
|
||||
/* create ipad: */
|
||||
for (i=0; i < DTLS_HMAC_BLOCKSIZE; ++i)
|
||||
ctx->pad[i] ^= 0x36;
|
||||
|
||||
dtls_hash_init(&ctx->data);
|
||||
dtls_hmac_update(ctx, ctx->pad, DTLS_HMAC_BLOCKSIZE);
|
||||
|
||||
/* create opad by xor-ing pad[i] with 0x36 ^ 0x5C: */
|
||||
for (i=0; i < DTLS_HMAC_BLOCKSIZE; ++i)
|
||||
ctx->pad[i] ^= 0x6A;
|
||||
}
|
||||
|
||||
void
|
||||
dtls_hmac_free(dtls_hmac_context_t *ctx) {
|
||||
if (ctx)
|
||||
dtls_hmac_context_free(ctx);
|
||||
}
|
||||
|
||||
int
|
||||
dtls_hmac_finalize(dtls_hmac_context_t *ctx, unsigned char *result) {
|
||||
unsigned char buf[DTLS_HMAC_DIGEST_SIZE];
|
||||
size_t len;
|
||||
|
||||
assert(ctx);
|
||||
assert(result);
|
||||
|
||||
len = dtls_hash_finalize(buf, &ctx->data);
|
||||
|
||||
dtls_hash_init(&ctx->data);
|
||||
dtls_hash_update(&ctx->data, ctx->pad, DTLS_HMAC_BLOCKSIZE);
|
||||
dtls_hash_update(&ctx->data, buf, len);
|
||||
|
||||
len = dtls_hash_finalize(result, &ctx->data);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef HMAC_TEST
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
static unsigned char buf[DTLS_HMAC_DIGEST_SIZE];
|
||||
size_t len, i;
|
||||
dtls_hmac_context_t *ctx;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: %s key text", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dtls_hmac_storage_init();
|
||||
ctx = dtls_hmac_new(argv[1], strlen(argv[1]));
|
||||
assert(ctx);
|
||||
dtls_hmac_update(ctx, argv[2], strlen(argv[2]));
|
||||
|
||||
len = dtls_hmac_finalize(ctx, buf);
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
printf("%02x", buf[i]);
|
||||
printf("\n");
|
||||
|
||||
dtls_hmac_free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
146
hmac.h
Normal file
146
hmac.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _DTLS_HMAC_H_
|
||||
#define _DTLS_HMAC_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "global.h"
|
||||
|
||||
#ifdef WITH_SHA256
|
||||
/** Aaron D. Gifford's implementation of SHA256
|
||||
* see http://www.aarongifford.com/ */
|
||||
#include "sha2/sha2.h"
|
||||
|
||||
typedef SHA256_CTX dtls_hash_ctx;
|
||||
typedef dtls_hash_ctx *dtls_hash_t;
|
||||
#define DTLS_HASH_CTX_SIZE sizeof(SHA256_CTX)
|
||||
|
||||
static inline void
|
||||
dtls_hash_init(dtls_hash_t ctx) {
|
||||
SHA256_Init((SHA256_CTX *)ctx);
|
||||
}
|
||||
|
||||
static inline void
|
||||
dtls_hash_update(dtls_hash_t ctx, const unsigned char *input, size_t len) {
|
||||
SHA256_Update((SHA256_CTX *)ctx, input, len);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
dtls_hash_finalize(unsigned char *buf, dtls_hash_t ctx) {
|
||||
SHA256_Final(buf, (SHA256_CTX *)ctx);
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
}
|
||||
#endif /* WITH_SHA256 */
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
static inline void dtls_hmac_storage_init()
|
||||
{ }
|
||||
#else
|
||||
void dtls_hmac_storage_init();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup HMAC Keyed-Hash Message Authentication Code (HMAC)
|
||||
* NIST Standard FIPS 198 describes the Keyed-Hash Message Authentication
|
||||
* Code (HMAC) which is used as hash function for the DTLS PRF.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define DTLS_HMAC_BLOCKSIZE 64 /**< size of hmac blocks */
|
||||
#define DTLS_HMAC_DIGEST_SIZE 32 /**< digest size (for SHA-256) */
|
||||
#define DTLS_HMAC_MAX 64 /**< max number of bytes in digest */
|
||||
|
||||
/**
|
||||
* List of known hash functions for use in dtls_hmac_init(). The
|
||||
* identifiers are the same as the HashAlgorithm defined in
|
||||
* <a href="http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1"
|
||||
* >Section 7.4.1.4.1 of RFC 5246</a>.
|
||||
*/
|
||||
typedef enum {
|
||||
HASH_NONE=0, HASH_MD5=1, HASH_SHA1=2, HASH_SHA224=3,
|
||||
HASH_SHA256=4, HASH_SHA384=5, HASH_SHA512=6
|
||||
} dtls_hashfunc_t;
|
||||
|
||||
/**
|
||||
* Context for HMAC generation. This object is initialized with
|
||||
* dtls_hmac_init() and must be passed to dtls_hmac_update() and
|
||||
* dtls_hmac_finalize(). Once, finalized, the component \c H is
|
||||
* invalid and must be initialized again with dtls_hmac_init() before
|
||||
* the structure can be used again.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char pad[DTLS_HMAC_BLOCKSIZE]; /**< ipad and opad storage */
|
||||
dtls_hash_ctx data; /**< context for hash function */
|
||||
} dtls_hmac_context_t;
|
||||
|
||||
/**
|
||||
* Initializes an existing HMAC context.
|
||||
*
|
||||
* @param ctx The HMAC context to initialize.
|
||||
* @param key The secret key.
|
||||
* @param klen The length of @p key.
|
||||
*/
|
||||
void dtls_hmac_init(dtls_hmac_context_t *ctx, const unsigned char *key, size_t klen);
|
||||
|
||||
/**
|
||||
* Allocates a new HMAC context \p ctx with the given secret key.
|
||||
* This function returns \c 1 if \c ctx has been set correctly, or \c
|
||||
* 0 or \c -1 otherwise. Note that this function allocates new storage
|
||||
* that must be released by dtls_hmac_free().
|
||||
*
|
||||
* \param key The secret key.
|
||||
* \param klen The length of \p key.
|
||||
* \return A new dtls_hmac_context_t object or @c NULL on error
|
||||
*/
|
||||
dtls_hmac_context_t *dtls_hmac_new(const unsigned char *key, size_t klen);
|
||||
|
||||
/**
|
||||
* Releases the storage for @p ctx that has been allocated by
|
||||
* dtls_hmac_new().
|
||||
*
|
||||
* @param ctx The dtls_hmac_context_t to free.
|
||||
*/
|
||||
void dtls_hmac_free(dtls_hmac_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Updates the HMAC context with data from \p input.
|
||||
*
|
||||
* \param ctx The HMAC context.
|
||||
* \param input The input data.
|
||||
* \param ilen Size of \p input.
|
||||
*/
|
||||
void dtls_hmac_update(dtls_hmac_context_t *ctx,
|
||||
const unsigned char *input, size_t ilen);
|
||||
|
||||
/**
|
||||
* Completes the HMAC generation and writes the result to the given
|
||||
* output parameter \c result. The buffer must be large enough to hold
|
||||
* the message digest created by the actual hash function. If in
|
||||
* doubt, use \c DTLS_HMAC_MAX. The function returns the number of
|
||||
* bytes written to \c result.
|
||||
*
|
||||
* \param ctx The HMAC context.
|
||||
* \param result Output parameter where the MAC is written to.
|
||||
* \return Length of the MAC written to \p result.
|
||||
*/
|
||||
int dtls_hmac_finalize(dtls_hmac_context_t *ctx, unsigned char *result);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif /* _DTLS_HMAC_H_ */
|
147
netq.c
Normal file
147
netq.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "dtls_config.h"
|
||||
#include "debug.h"
|
||||
#include "netq.h"
|
||||
#include "utlist.h"
|
||||
|
||||
#ifdef HAVE_ASSERT_H
|
||||
#include <assert.h>
|
||||
#else
|
||||
#ifndef assert
|
||||
#warning "assertions are disabled"
|
||||
# define assert(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
#include <stdlib.h>
|
||||
|
||||
static inline netq_t *
|
||||
netq_malloc_node(size_t size) {
|
||||
return (netq_t *)malloc(sizeof(netq_t) + size);
|
||||
}
|
||||
|
||||
static inline void
|
||||
netq_free_node(netq_t *node) {
|
||||
free(node);
|
||||
}
|
||||
|
||||
#else /* WITH_CONTIKI */
|
||||
#include "memb.h"
|
||||
|
||||
MEMB(netq_storage, netq_t, NETQ_MAXCNT);
|
||||
|
||||
static inline netq_t *
|
||||
netq_malloc_node(size_t size) {
|
||||
return (netq_t *)memb_alloc(&netq_storage);
|
||||
}
|
||||
|
||||
static inline void
|
||||
netq_free_node(netq_t *node) {
|
||||
memb_free(&netq_storage, node);
|
||||
}
|
||||
|
||||
void
|
||||
netq_init() {
|
||||
memb_init(&netq_storage);
|
||||
}
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
int
|
||||
netq_insert_node(netq_t **queue, netq_t *node) {
|
||||
netq_t *p;
|
||||
|
||||
assert(queue);
|
||||
assert(node);
|
||||
|
||||
p = *queue;
|
||||
while(p && p->t <= node->t)
|
||||
p = p->next;
|
||||
|
||||
if (p)
|
||||
LL_PREPEND_ELEM(*queue, p, node);
|
||||
else
|
||||
LL_APPEND(*queue, node);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
netq_t *
|
||||
netq_head(netq_t **queue) {
|
||||
return queue ? *queue : NULL;
|
||||
}
|
||||
|
||||
netq_t *
|
||||
netq_next(netq_t *p) {
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
return p->next;
|
||||
}
|
||||
|
||||
void
|
||||
netq_remove(netq_t **queue, netq_t *p) {
|
||||
if (!queue || !p)
|
||||
return;
|
||||
|
||||
LL_DELETE(*queue, p);
|
||||
}
|
||||
|
||||
netq_t *netq_pop_first(netq_t **queue) {
|
||||
netq_t *p = netq_head(queue);
|
||||
|
||||
if (p)
|
||||
LL_DELETE(*queue, p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
netq_t *
|
||||
netq_node_new(size_t size) {
|
||||
netq_t *node;
|
||||
node = netq_malloc_node(size);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!node)
|
||||
dtls_warn("netq_node_new: malloc\n");
|
||||
#endif
|
||||
|
||||
if (node)
|
||||
memset(node, 0, sizeof(netq_t));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void
|
||||
netq_node_free(netq_t *node) {
|
||||
if (node)
|
||||
netq_free_node(node);
|
||||
}
|
||||
|
||||
void
|
||||
netq_delete_all(netq_t **queue) {
|
||||
netq_t *p, *tmp;
|
||||
if (queue) {
|
||||
LL_FOREACH_SAFE(*queue,p,tmp) {
|
||||
netq_free_node(p);
|
||||
}
|
||||
|
||||
*queue = NULL;
|
||||
}
|
||||
}
|
112
netq.h
Normal file
112
netq.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _DTLS_NETQ_H_
|
||||
#define _DTLS_NETQ_H_
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "global.h"
|
||||
#include "dtls.h"
|
||||
#include "dtls_time.h"
|
||||
|
||||
/**
|
||||
* \defgroup netq Network Packet Queue
|
||||
* The netq utility functions implement an ordered queue of data packets
|
||||
* to send over the network and can also be used to queue received packets
|
||||
* from the network.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef NETQ_MAXCNT
|
||||
#ifdef DTLS_ECC
|
||||
#define NETQ_MAXCNT 5 /**< maximum number of elements in netq structure */
|
||||
#elif defined(DTLS_PSK)
|
||||
#define NETQ_MAXCNT 3 /**< maximum number of elements in netq structure */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Datagrams in the netq_t structure have a fixed maximum size of
|
||||
* DTLS_MAX_BUF to simplify memory management on constrained nodes. */
|
||||
typedef unsigned char netq_packet_t[DTLS_MAX_BUF];
|
||||
|
||||
typedef struct netq_t {
|
||||
struct netq_t *next;
|
||||
|
||||
clock_time_t t; /**< when to send PDU for the next time */
|
||||
unsigned int timeout; /**< randomized timeout value */
|
||||
|
||||
dtls_peer_t *peer; /**< remote address */
|
||||
uint16_t epoch;
|
||||
uint8_t type;
|
||||
unsigned char retransmit_cnt; /**< retransmission counter, will be removed when zero */
|
||||
|
||||
size_t length; /**< actual length of data */
|
||||
#ifndef WITH_CONTIKI
|
||||
unsigned char data[]; /**< the datagram to send */
|
||||
#else
|
||||
netq_packet_t data; /**< the datagram to send */
|
||||
#endif
|
||||
} netq_t;
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
static inline void netq_init()
|
||||
{ }
|
||||
#else
|
||||
void netq_init();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Adds a node to the given queue, ordered by their time-stamp t.
|
||||
* This function returns @c 0 on error, or non-zero if @p node has
|
||||
* been added successfully.
|
||||
*
|
||||
* @param queue A pointer to the queue head where @p node will be added.
|
||||
* @param node The new item to add.
|
||||
* @return @c 0 on error, or non-zero if the new item was added.
|
||||
*/
|
||||
int netq_insert_node(netq_t **queue, netq_t *node);
|
||||
|
||||
/** Destroys specified node and releases any memory that was allocated
|
||||
* for the associated datagram. */
|
||||
void netq_node_free(netq_t *node);
|
||||
|
||||
/** Removes all items from given queue and frees the allocated storage */
|
||||
void netq_delete_all(netq_t **queue);
|
||||
|
||||
/** Creates a new node suitable for adding to a netq_t queue. */
|
||||
netq_t *netq_node_new(size_t size);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the first item in given queue or NULL if
|
||||
* empty.
|
||||
*/
|
||||
netq_t *netq_head(netq_t **queue);
|
||||
|
||||
netq_t *netq_next(netq_t *p);
|
||||
void netq_remove(netq_t **queue, netq_t *p);
|
||||
|
||||
/**
|
||||
* Removes the first item in given queue and returns a pointer to the
|
||||
* removed element. If queue is empty when netq_pop_first() is called,
|
||||
* this function returns NULL.
|
||||
*/
|
||||
netq_t *netq_pop_first(netq_t **queue);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif /* _DTLS_NETQ_H_ */
|
134
numeric.h
Normal file
134
numeric.h
Normal file
@ -0,0 +1,134 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _DTLS_NUMERIC_H_
|
||||
#define _DTLS_NUMERIC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef min
|
||||
#define min(A,B) ((A) <= (B) ? (A) : (B))
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(A,B) ((A) < (B) ? (B) : (A))
|
||||
#endif
|
||||
|
||||
/* this one is for consistency... */
|
||||
static inline int dtls_int_to_uint8(unsigned char *field, uint8_t value)
|
||||
{
|
||||
field[0] = value & 0xff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int dtls_int_to_uint16(unsigned char *field, uint16_t value)
|
||||
{
|
||||
field[0] = (value >> 8) & 0xff;
|
||||
field[1] = value & 0xff;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static inline int dtls_int_to_uint24(unsigned char *field, uint32_t value)
|
||||
{
|
||||
field[0] = (value >> 16) & 0xff;
|
||||
field[1] = (value >> 8) & 0xff;
|
||||
field[2] = value & 0xff;
|
||||
return 3;
|
||||
}
|
||||
|
||||
static inline int dtls_int_to_uint32(unsigned char *field, uint32_t value)
|
||||
{
|
||||
field[0] = (value >> 24) & 0xff;
|
||||
field[1] = (value >> 16) & 0xff;
|
||||
field[2] = (value >> 8) & 0xff;
|
||||
field[3] = value & 0xff;
|
||||
return 4;
|
||||
}
|
||||
|
||||
static inline int dtls_int_to_uint48(unsigned char *field, uint64_t value)
|
||||
{
|
||||
field[0] = (value >> 40) & 0xff;
|
||||
field[1] = (value >> 32) & 0xff;
|
||||
field[2] = (value >> 24) & 0xff;
|
||||
field[3] = (value >> 16) & 0xff;
|
||||
field[4] = (value >> 8) & 0xff;
|
||||
field[5] = value & 0xff;
|
||||
return 6;
|
||||
}
|
||||
|
||||
static inline int dtls_int_to_uint64(unsigned char *field, uint64_t value)
|
||||
{
|
||||
field[0] = (value >> 56) & 0xff;
|
||||
field[1] = (value >> 48) & 0xff;
|
||||
field[2] = (value >> 40) & 0xff;
|
||||
field[3] = (value >> 32) & 0xff;
|
||||
field[4] = (value >> 24) & 0xff;
|
||||
field[5] = (value >> 16) & 0xff;
|
||||
field[6] = (value >> 8) & 0xff;
|
||||
field[7] = value & 0xff;
|
||||
return 8;
|
||||
}
|
||||
|
||||
static inline uint8_t dtls_uint8_to_int(const unsigned char *field)
|
||||
{
|
||||
return (uint8_t)field[0];
|
||||
}
|
||||
|
||||
static inline uint16_t dtls_uint16_to_int(const unsigned char *field)
|
||||
{
|
||||
return ((uint16_t)field[0] << 8)
|
||||
| (uint16_t)field[1];
|
||||
}
|
||||
|
||||
static inline uint32_t dtls_uint24_to_int(const unsigned char *field)
|
||||
{
|
||||
return ((uint32_t)field[0] << 16)
|
||||
| ((uint32_t)field[1] << 8)
|
||||
| (uint32_t)field[2];
|
||||
}
|
||||
|
||||
static inline uint32_t dtls_uint32_to_int(const unsigned char *field)
|
||||
{
|
||||
return ((uint32_t)field[0] << 24)
|
||||
| ((uint32_t)field[1] << 16)
|
||||
| ((uint32_t)field[2] << 8)
|
||||
| (uint32_t)field[3];
|
||||
}
|
||||
|
||||
static inline uint64_t dtls_uint48_to_int(const unsigned char *field)
|
||||
{
|
||||
return ((uint64_t)field[0] << 40)
|
||||
| ((uint64_t)field[1] << 32)
|
||||
| ((uint64_t)field[2] << 24)
|
||||
| ((uint64_t)field[3] << 16)
|
||||
| ((uint64_t)field[4] << 8)
|
||||
| (uint64_t)field[5];
|
||||
}
|
||||
|
||||
static inline uint64_t dtls_uint64_to_int(const unsigned char *field)
|
||||
{
|
||||
return ((uint64_t)field[0] << 56)
|
||||
| ((uint64_t)field[1] << 48)
|
||||
| ((uint64_t)field[2] << 40)
|
||||
| ((uint64_t)field[3] << 32)
|
||||
| ((uint64_t)field[4] << 24)
|
||||
| ((uint64_t)field[5] << 16)
|
||||
| ((uint64_t)field[6] << 8)
|
||||
| (uint64_t)field[7];
|
||||
}
|
||||
|
||||
#endif /* _DTLS_NUMERIC_H_ */
|
82
peer.c
Normal file
82
peer.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "global.h"
|
||||
#include "peer.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
void peer_init()
|
||||
{
|
||||
}
|
||||
|
||||
static inline dtls_peer_t *
|
||||
dtls_malloc_peer() {
|
||||
return (dtls_peer_t *)malloc(sizeof(dtls_peer_t));
|
||||
}
|
||||
|
||||
void
|
||||
dtls_free_peer(dtls_peer_t *peer) {
|
||||
dtls_handshake_free(peer->handshake_params);
|
||||
dtls_security_free(peer->security_params[0]);
|
||||
dtls_security_free(peer->security_params[1]);
|
||||
free(peer);
|
||||
}
|
||||
#else /* WITH_CONTIKI */
|
||||
|
||||
#include "memb.h"
|
||||
MEMB(peer_storage, dtls_peer_t, DTLS_PEER_MAX);
|
||||
|
||||
void
|
||||
peer_init() {
|
||||
memb_init(&peer_storage);
|
||||
}
|
||||
|
||||
static inline dtls_peer_t *
|
||||
dtls_malloc_peer() {
|
||||
return memb_alloc(&peer_storage);
|
||||
}
|
||||
|
||||
void
|
||||
dtls_free_peer(dtls_peer_t *peer) {
|
||||
dtls_handshake_free(peer->handshake_params);
|
||||
dtls_security_free(peer->security_params[0]);
|
||||
dtls_security_free(peer->security_params[1]);
|
||||
memb_free(&peer_storage, peer);
|
||||
}
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
dtls_peer_t *
|
||||
dtls_new_peer(const session_t *session) {
|
||||
dtls_peer_t *peer;
|
||||
|
||||
peer = dtls_malloc_peer();
|
||||
if (peer) {
|
||||
memset(peer, 0, sizeof(dtls_peer_t));
|
||||
memcpy(&peer->session, session, sizeof(session_t));
|
||||
peer->security_params[0] = dtls_security_new();
|
||||
|
||||
if (!peer->security_params[0]) {
|
||||
dtls_free_peer(peer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dtls_dsrv_log_addr(DTLS_LOG_DEBUG, "dtls_new_peer", session);
|
||||
}
|
||||
|
||||
return peer;
|
||||
}
|
140
peer.h
Normal file
140
peer.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file peer.h
|
||||
* @brief information about peers in a DTLS session
|
||||
*/
|
||||
|
||||
#ifndef _DTLS_PEER_H_
|
||||
#define _DTLS_PEER_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "global.h"
|
||||
#include "session.h"
|
||||
|
||||
#include "state.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#ifndef DTLS_PEERS_NOHASH
|
||||
#include "uthash.h"
|
||||
#endif /* DTLS_PEERS_NOHASH */
|
||||
|
||||
typedef enum { DTLS_CLIENT=0, DTLS_SERVER } dtls_peer_type;
|
||||
|
||||
/**
|
||||
* Holds security parameters, local state and the transport address
|
||||
* for each peer. */
|
||||
typedef struct dtls_peer_t {
|
||||
#ifdef DTLS_PEERS_NOHASH
|
||||
struct dtls_peer_t *next;
|
||||
#else /* DTLS_PEERS_NOHASH */
|
||||
UT_hash_handle hh;
|
||||
#endif /* DTLS_PEERS_NOHASH */
|
||||
|
||||
session_t session; /**< peer address and local interface */
|
||||
|
||||
dtls_peer_type role; /**< denotes if this host is DTLS_CLIENT or DTLS_SERVER */
|
||||
dtls_state_t state; /**< DTLS engine state */
|
||||
|
||||
dtls_security_parameters_t *security_params[2];
|
||||
dtls_handshake_parameters_t *handshake_params;
|
||||
} dtls_peer_t;
|
||||
|
||||
static inline dtls_security_parameters_t *dtls_security_params_epoch(dtls_peer_t *peer, uint16_t epoch)
|
||||
{
|
||||
if (peer->security_params[0] && peer->security_params[0]->epoch == epoch) {
|
||||
return peer->security_params[0];
|
||||
} else if (peer->security_params[1] && peer->security_params[1]->epoch == epoch) {
|
||||
return peer->security_params[1];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline dtls_security_parameters_t *dtls_security_params(dtls_peer_t *peer)
|
||||
{
|
||||
return peer->security_params[0];
|
||||
}
|
||||
|
||||
static inline dtls_security_parameters_t *dtls_security_params_next(dtls_peer_t *peer)
|
||||
{
|
||||
if (peer->security_params[1])
|
||||
dtls_security_free(peer->security_params[1]);
|
||||
|
||||
peer->security_params[1] = dtls_security_new();
|
||||
if (!peer->security_params[1]) {
|
||||
return NULL;
|
||||
}
|
||||
peer->security_params[1]->epoch = peer->security_params[0]->epoch + 1;
|
||||
return peer->security_params[1];
|
||||
}
|
||||
|
||||
static inline void dtls_security_params_free_other(dtls_peer_t *peer)
|
||||
{
|
||||
dtls_security_parameters_t * security0 = peer->security_params[0];
|
||||
dtls_security_parameters_t * security1 = peer->security_params[1];
|
||||
|
||||
if (!security0 || !security1 || security0->epoch < security1->epoch)
|
||||
return;
|
||||
|
||||
dtls_security_free(security1);
|
||||
peer->security_params[1] = NULL;
|
||||
}
|
||||
|
||||
static inline void dtls_security_params_switch(dtls_peer_t *peer)
|
||||
{
|
||||
dtls_security_parameters_t * security = peer->security_params[1];
|
||||
|
||||
peer->security_params[1] = peer->security_params[0];
|
||||
peer->security_params[0] = security;
|
||||
}
|
||||
|
||||
void peer_init();
|
||||
|
||||
/**
|
||||
* Creates a new peer for given @p session. The current configuration
|
||||
* is initialized with the cipher suite TLS_NULL_WITH_NULL_NULL (i.e.
|
||||
* no security at all). This function returns a pointer to the new
|
||||
* peer or NULL on error. The caller is responsible for releasing the
|
||||
* storage allocated for this peer using dtls_free_peer().
|
||||
*
|
||||
* @param session The remote peer's address and local interface index.
|
||||
* @return A pointer to a newly created and initialized peer object
|
||||
* or NULL on error.
|
||||
*/
|
||||
dtls_peer_t *dtls_new_peer(const session_t *session);
|
||||
|
||||
/** Releases the storage allocated to @p peer. */
|
||||
void dtls_free_peer(dtls_peer_t *peer);
|
||||
|
||||
/** Returns the current state of @p peer. */
|
||||
static inline dtls_state_t dtls_peer_state(const dtls_peer_t *peer) {
|
||||
return peer->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given @p peer is connected. This function returns
|
||||
* @c 1 if connected, or @c 0 otherwise.
|
||||
*/
|
||||
static inline int dtls_peer_is_connected(const dtls_peer_t *peer) {
|
||||
return peer->state == DTLS_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
#endif /* _DTLS_PEER_H_ */
|
27
platform-specific/Makefile.in
Normal file
27
platform-specific/Makefile.in
Normal file
@ -0,0 +1,27 @@
|
||||
# the library's version
|
||||
VERSION:=@PACKAGE_VERSION@
|
||||
|
||||
# tools
|
||||
@SET_MAKE@
|
||||
SHELL = /bin/sh
|
||||
MKDIR = mkdir
|
||||
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
THIS=platform-specific
|
||||
DISTDIR?=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
FILES:=Makefile.in $(wildcard *.h)
|
||||
|
||||
clean:
|
||||
|
||||
distclean: clean
|
||||
@rm -rf $(DISTDIR)
|
||||
@rm -f *~
|
||||
|
||||
dist:
|
||||
test -d $(DISTDIR)/$(THIS) || mkdir $(DISTDIR)/$(THIS)
|
||||
cp -r $(FILES) $(DISTDIR)/$(THIS)
|
||||
|
||||
# this directory contains no installation candidates
|
||||
install:
|
||||
:
|
2
platform-specific/config-cc2538dk.h
Normal file
2
platform-specific/config-cc2538dk.h
Normal file
@ -0,0 +1,2 @@
|
||||
#define BYTE_ORDER 1234
|
||||
#define HAVE_ASSERT_H 1
|
2
platform-specific/config-econotag.h
Normal file
2
platform-specific/config-econotag.h
Normal file
@ -0,0 +1,2 @@
|
||||
#define BYTE_ORDER 1234
|
||||
#define HAVE_ASSERT_H 1
|
1
platform-specific/config-minimal-net.h
Normal file
1
platform-specific/config-minimal-net.h
Normal file
@ -0,0 +1 @@
|
||||
#define HAVE_ASSERT_H 1
|
3
platform-specific/config-sky.h
Normal file
3
platform-specific/config-sky.h
Normal file
@ -0,0 +1,3 @@
|
||||
#define BYTE_ORDER 1234
|
||||
#define HAVE_ASSERT_H 1
|
||||
typedef int ssize_t;
|
1
platform-specific/config-wismote.h
Normal file
1
platform-specific/config-wismote.h
Normal file
@ -0,0 +1 @@
|
||||
#define HAVE_ASSERT_H 1
|
65
platform-specific/platform.h
Normal file
65
platform-specific/platform.h
Normal file
@ -0,0 +1,65 @@
|
||||
/************************************************************************/
|
||||
/* Contiki-specific parameters */
|
||||
/************************************************************************/
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#define _PLATFORM_H_ 1
|
||||
|
||||
#ifdef CONTIKI
|
||||
#include "contiki.h"
|
||||
#include "contiki-lib.h"
|
||||
#include "contiki-net.h"
|
||||
|
||||
#include "contiki-conf.h"
|
||||
|
||||
/* global constants for constrained devices running Contiki */
|
||||
#ifndef DTLS_PEER_MAX
|
||||
/** The maximum number DTLS peers (i.e. sessions). */
|
||||
# define DTLS_PEER_MAX 1
|
||||
#endif
|
||||
|
||||
#ifndef DTLS_HANDSHAKE_MAX
|
||||
/** The maximum number of concurrent DTLS handshakes. */
|
||||
# define DTLS_HANDSHAKE_MAX 1
|
||||
#endif
|
||||
|
||||
#ifndef DTLS_SECURITY_MAX
|
||||
/** The maximum number of concurrently used cipher keys */
|
||||
# define DTLS_SECURITY_MAX (DTLS_PEER_MAX + DTLS_HANDSHAKE_MAX)
|
||||
#endif
|
||||
|
||||
#ifndef DTLS_HASH_MAX
|
||||
/** The maximum number of hash functions that can be used in parallel. */
|
||||
# define DTLS_HASH_MAX (3 * DTLS_PEER_MAX)
|
||||
#endif
|
||||
|
||||
/** do not use uthash hash tables */
|
||||
#define DTLS_PEERS_NOHASH 1
|
||||
|
||||
/************************************************************************/
|
||||
/* Specific Contiki platforms */
|
||||
/************************************************************************/
|
||||
|
||||
#if CONTIKI_TARGET_ECONOTAG
|
||||
# include "platform-specific/config-econotag.h"
|
||||
#endif /* CONTIKI_TARGET_ECONOTAG */
|
||||
|
||||
#ifdef CONTIKI_TARGET_CC2538DK
|
||||
# include "platform-specific/config-cc2538dk.h"
|
||||
#endif /* CONTIKI_TARGET_CC2538DK */
|
||||
|
||||
#ifdef CONTIKI_TARGET_WISMOTE
|
||||
# include "platform-specific/config-wismote.h"
|
||||
#endif /* CONTIKI_TARGET_WISMOTE */
|
||||
|
||||
#ifdef CONTIKI_TARGET_SKY
|
||||
# include "platform-specific/config-sky.h"
|
||||
#endif /* CONTIKI_TARGET_SKY */
|
||||
|
||||
#ifdef CONTIKI_TARGET_MINIMAL_NET
|
||||
# include "platform-specific/config-minimal-net.h"
|
||||
#endif /* CONTIKI_TARGET_MINIMAL_NET */
|
||||
|
||||
#endif /* CONTIKI */
|
||||
|
||||
#endif /* _PLATFORM_H_ */
|
96
prng.h
Normal file
96
prng.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file prng.h
|
||||
* @brief Pseudo Random Numbers
|
||||
*/
|
||||
|
||||
#ifndef _DTLS_PRNG_H_
|
||||
#define _DTLS_PRNG_H_
|
||||
|
||||
#include "tinydtls.h"
|
||||
|
||||
/**
|
||||
* @defgroup prng Pseudo Random Numbers
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef WITH_CONTIKI
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Fills \p buf with \p len random bytes. This is the default
|
||||
* implementation for prng(). You might want to change prng() to use
|
||||
* a better PRNG on your specific platform.
|
||||
*/
|
||||
static inline int
|
||||
dtls_prng(unsigned char *buf, size_t len) {
|
||||
while (len--)
|
||||
*buf++ = rand() & 0xFF;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
dtls_prng_init(unsigned short seed) {
|
||||
srand(seed);
|
||||
}
|
||||
#else /* WITH_CONTIKI */
|
||||
#include <string.h>
|
||||
#include "random.h"
|
||||
|
||||
#ifdef HAVE_PRNG
|
||||
static inline int
|
||||
dtls_prng(unsigned char *buf, size_t len)
|
||||
{
|
||||
return contiki_prng_impl(buf, len);
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* Fills \p buf with \p len random bytes. This is the default
|
||||
* implementation for prng(). You might want to change prng() to use
|
||||
* a better PRNG on your specific platform.
|
||||
*/
|
||||
static inline int
|
||||
dtls_prng(unsigned char *buf, size_t len) {
|
||||
unsigned short v = random_rand();
|
||||
while (len > sizeof(v)) {
|
||||
memcpy(buf, &v, sizeof(v));
|
||||
len -= sizeof(v);
|
||||
buf += sizeof(v);
|
||||
v = random_rand();
|
||||
}
|
||||
|
||||
memcpy(buf, &v, len);
|
||||
return 1;
|
||||
}
|
||||
#endif /* HAVE_PRNG */
|
||||
|
||||
static inline void
|
||||
dtls_prng_init(unsigned short seed) {
|
||||
/* random_init() messes with the radio interface of the CC2538 and
|
||||
* therefore must not be called after the radio has been
|
||||
* initialized. */
|
||||
#ifndef CONTIKI_TARGET_CC2538DK
|
||||
random_init(seed);
|
||||
#endif
|
||||
}
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* _DTLS_PRNG_H_ */
|
74
session.c
Normal file
74
session.c
Normal file
@ -0,0 +1,74 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "dtls_config.h"
|
||||
#include "session.h"
|
||||
|
||||
#ifdef HAVE_ASSERT_H
|
||||
#include <assert.h>
|
||||
#else
|
||||
#ifndef assert
|
||||
#warning "assertions are disabled"
|
||||
# define assert(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
#define _dtls_address_equals_impl(A,B) \
|
||||
((A)->size == (B)->size \
|
||||
&& (A)->port == (B)->port \
|
||||
&& uip_ipaddr_cmp(&((A)->addr),&((B)->addr)) \
|
||||
&& (A)->ifindex == (B)->ifindex)
|
||||
|
||||
#else /* WITH_CONTIKI */
|
||||
|
||||
static inline int
|
||||
_dtls_address_equals_impl(const session_t *a,
|
||||
const session_t *b) {
|
||||
if (a->ifindex != b->ifindex ||
|
||||
a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family)
|
||||
return 0;
|
||||
|
||||
/* need to compare only relevant parts of sockaddr_in6 */
|
||||
switch (a->addr.sa.sa_family) {
|
||||
case AF_INET:
|
||||
return
|
||||
a->addr.sin.sin_port == b->addr.sin.sin_port &&
|
||||
memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr,
|
||||
sizeof(struct in_addr)) == 0;
|
||||
case AF_INET6:
|
||||
return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port &&
|
||||
memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr,
|
||||
sizeof(struct in6_addr)) == 0;
|
||||
default: /* fall through and signal error */
|
||||
;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
void
|
||||
dtls_session_init(session_t *sess) {
|
||||
assert(sess);
|
||||
memset(sess, 0, sizeof(session_t));
|
||||
sess->size = sizeof(sess->addr);
|
||||
}
|
||||
|
||||
int
|
||||
dtls_session_equals(const session_t *a, const session_t *b) {
|
||||
assert(a); assert(b);
|
||||
return _dtls_address_equals_impl(a, b);
|
||||
}
|
67
session.h
Normal file
67
session.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _DTLS_SESSION_H_
|
||||
#define _DTLS_SESSION_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "global.h"
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
#include "ip/uip.h"
|
||||
typedef struct {
|
||||
unsigned char size;
|
||||
uip_ipaddr_t addr;
|
||||
unsigned short port;
|
||||
int ifindex;
|
||||
} session_t;
|
||||
|
||||
#else /* WITH_CONTIKI */
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
typedef struct {
|
||||
socklen_t size; /**< size of addr */
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_storage st;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
} addr;
|
||||
uint8_t ifindex;
|
||||
} session_t;
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
/**
|
||||
* Resets the given session_t object @p sess to its default
|
||||
* values. In particular, the member rlen must be initialized to the
|
||||
* available size for storing addresses.
|
||||
*
|
||||
* @param sess The session_t object to initialize.
|
||||
*/
|
||||
void dtls_session_init(session_t *sess);
|
||||
|
||||
/**
|
||||
* Compares the given session objects. This function returns @c 0
|
||||
* when @p a and @p b differ, @c 1 otherwise.
|
||||
*/
|
||||
int dtls_session_equals(const session_t *a, const session_t *b);
|
||||
|
||||
#endif /* _DTLS_SESSION_H_ */
|
69
sha2/Makefile.in
Normal file
69
sha2/Makefile.in
Normal file
@ -0,0 +1,69 @@
|
||||
# Makefile for tinydtls
|
||||
#
|
||||
# Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Olaf Bergmann - initial API and implementation
|
||||
#
|
||||
|
||||
# the library's version
|
||||
VERSION:=@PACKAGE_VERSION@
|
||||
|
||||
# tools
|
||||
@SET_MAKE@
|
||||
SHELL = /bin/sh
|
||||
MKDIR = mkdir
|
||||
|
||||
abs_builddir = @abs_builddir@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir:= @top_srcdir@
|
||||
|
||||
SOURCES:= sha2.c
|
||||
HEADERS:=sha2.h
|
||||
OBJECTS:= $(patsubst %.c, %.o, $(SOURCES))
|
||||
CPPFLAGS=@CPPFLAGS@ -I$(top_srcdir)
|
||||
CFLAGS=-Wall -std=c99 -pedantic @CFLAGS@
|
||||
LDLIBS=@LIBS@
|
||||
FILES:=Makefile.in $(SOURCES) $(HEADERS) README sha2prog.c sha2speed.c sha2test.pl
|
||||
DISTDIR=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
|
||||
.PHONY: all dirs clean install dist distclean .gitignore doc
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
all:
|
||||
|
||||
check:
|
||||
echo DISTDIR: $(DISTDIR)
|
||||
echo top_builddir: $(top_builddir)
|
||||
|
||||
clean:
|
||||
@rm -f $(PROGRAMS) main.o $(LIB) $(OBJECTS)
|
||||
for dir in $(SUBDIRS); do \
|
||||
$(MAKE) -C $$dir clean ; \
|
||||
done
|
||||
|
||||
distclean: clean
|
||||
@rm -rf $(DISTDIR)
|
||||
@rm -f *~ $(DISTDIR).tar.gz
|
||||
|
||||
dist: $(FILES)
|
||||
test -d $(DISTDIR)/sha2 || mkdir $(DISTDIR)/sha2
|
||||
cp -p $(FILES) $(DISTDIR)/sha2
|
||||
test -d $(DISTDIR)/sha2/testvectors || mkdir $(DISTDIR)/sha2/testvectors
|
||||
cp -pr testvectors $(DISTDIR)/sha2/testvectors
|
||||
|
||||
install: $(HEADERS)
|
||||
test -d $(includedir)/sha2 || mkdir -p $(includedir)/sha2
|
||||
$(install) $(HEADERS) $(includedir)/sha2
|
||||
|
||||
.gitignore:
|
||||
echo "core\n*~\n*.[oa]\n*.gz\n*.cap\n$(PROGRAM)\n$(DISTDIR)\n.gitignore" >$@
|
56
state.h
Normal file
56
state.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file state.h
|
||||
* @brief state information for DTLS FSM
|
||||
*/
|
||||
|
||||
#ifndef _DTLS_STATE_H_
|
||||
#define _DTLS_STATE_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "hmac.h"
|
||||
|
||||
typedef enum {
|
||||
DTLS_STATE_INIT = 0, DTLS_STATE_WAIT_CLIENTHELLO, DTLS_STATE_WAIT_CLIENTCERTIFICATE,
|
||||
DTLS_STATE_WAIT_CLIENTKEYEXCHANGE, DTLS_STATE_WAIT_CERTIFICATEVERIFY,
|
||||
DTLS_STATE_WAIT_CHANGECIPHERSPEC,
|
||||
DTLS_STATE_WAIT_FINISHED, DTLS_STATE_FINISHED,
|
||||
/* client states */
|
||||
DTLS_STATE_CLIENTHELLO, DTLS_STATE_WAIT_SERVERCERTIFICATE, DTLS_STATE_WAIT_SERVERKEYEXCHANGE,
|
||||
DTLS_STATE_WAIT_SERVERHELLODONE,
|
||||
|
||||
DTLS_STATE_CONNECTED,
|
||||
DTLS_STATE_CLOSING,
|
||||
DTLS_STATE_CLOSED
|
||||
} dtls_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t mseq_s; /**< send handshake message sequence number counter */
|
||||
uint16_t mseq_r; /**< received handshake message sequence number counter */
|
||||
|
||||
/** pending config that is updated during handshake */
|
||||
/* FIXME: dtls_security_parameters_t pending_config; */
|
||||
|
||||
/* temporary storage for the final handshake hash */
|
||||
dtls_hash_ctx hs_hash;
|
||||
} dtls_hs_state_t;
|
||||
#endif /* _DTLS_STATE_H_ */
|
75
tests/Makefile.in
Normal file
75
tests/Makefile.in
Normal file
@ -0,0 +1,75 @@
|
||||
# Makefile for tinydtls
|
||||
#
|
||||
# Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
#
|
||||
# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
# and the Eclipse Distribution License is available at
|
||||
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
#
|
||||
# Contributors:
|
||||
# Olaf Bergmann - initial API and implementation
|
||||
#
|
||||
|
||||
# the library's version
|
||||
VERSION:=@PACKAGE_VERSION@
|
||||
|
||||
# tools
|
||||
@SET_MAKE@
|
||||
SHELL = /bin/sh
|
||||
MKDIR = mkdir
|
||||
|
||||
abs_builddir = @abs_builddir@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir:= @top_srcdir@
|
||||
|
||||
# files and flags
|
||||
SOURCES:= dtls-server.c ccm-test.c prf-test.c \
|
||||
dtls-client.c
|
||||
#cbc_aes128-test.c #dsrv-test.c
|
||||
OBJECTS:= $(patsubst %.c, %.o, $(SOURCES))
|
||||
PROGRAMS:= $(patsubst %.c, %, $(SOURCES))
|
||||
HEADERS:=
|
||||
CFLAGS:=-Wall @CFLAGS@
|
||||
CPPFLAGS:=-I$(top_srcdir) @CPPFLAGS@
|
||||
LDFLAGS:=-L$(top_builddir)
|
||||
LDLIBS:=-ltinydtls @LIBS@
|
||||
DISTDIR=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
FILES:=Makefile.in $(SOURCES) ccm-testdata.c #cbc_aes128-testdata.c
|
||||
|
||||
.PHONY: all dirs clean distclean .gitignore doc
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
check:
|
||||
echo DISTDIR: $(DISTDIR)
|
||||
echo top_builddir: $(top_builddir)
|
||||
|
||||
clean:
|
||||
@rm -f $(PROGRAMS) main.o $(LIB) $(OBJECTS)
|
||||
for dir in $(SUBDIRS); do \
|
||||
$(MAKE) -C $$dir clean ; \
|
||||
done
|
||||
|
||||
doc:
|
||||
$(MAKE) -C doc
|
||||
|
||||
distclean: clean
|
||||
@rm -rf $(DISTDIR)
|
||||
@rm -f *~ $(DISTDIR).tar.gz
|
||||
|
||||
dist: $(FILES)
|
||||
test -d $(DISTDIR)/tests || mkdir $(DISTDIR)/tests
|
||||
cp $(FILES) $(DISTDIR)/tests
|
||||
|
||||
# this directory contains no installation candidates
|
||||
install:
|
||||
:
|
||||
|
||||
.gitignore:
|
||||
echo "core\n*~\n*.[oa]\n*.gz\n*.cap\n$(PROGRAM)\n$(DISTDIR)\n.gitignore" >$@
|
60
tests/cbc_aes128-test.c
Normal file
60
tests/cbc_aes128-test.c
Normal file
@ -0,0 +1,60 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "numeric.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#include "cbc_aes128-testdata.c"
|
||||
|
||||
void
|
||||
dump(unsigned char *buf, size_t len) {
|
||||
size_t i = 0;
|
||||
while (i < len) {
|
||||
printf("%02x ", buf[i++]);
|
||||
if (i % 4 == 0)
|
||||
printf(" ");
|
||||
if (i % 16 == 0)
|
||||
printf("\n\t");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int len, n;
|
||||
|
||||
for (n = 0; n < sizeof(data)/sizeof(struct test_vector); ++n) {
|
||||
dtls_cipher_context_t *cipher;
|
||||
|
||||
cipher = dtls_new_cipher(&ciphers[AES128],
|
||||
data[n].key,
|
||||
sizeof(data[n].key));
|
||||
|
||||
if (!cipher) {
|
||||
fprintf(stderr, "cannot set key\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
dtls_init_cipher(cipher, data[n].nonce, sizeof(data[n].nonce));
|
||||
|
||||
if (data[n].M == 0)
|
||||
len = dtls_encrypt(cipher, data[n].msg, data[n].lm);
|
||||
else
|
||||
len = dtls_decrypt(cipher, data[n].msg, data[n].lm);
|
||||
|
||||
printf("Packet Vector #%d ", n+1);
|
||||
if (len != data[n].r_lm
|
||||
|| memcmp(data[n].msg, data[n].result, len))
|
||||
printf("FAILED, ");
|
||||
else
|
||||
printf("OK, ");
|
||||
|
||||
printf("result is (total length = %d):\n\t", (int)len);
|
||||
dump(data[n].msg, len);
|
||||
|
||||
free(cipher);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
72
tests/cbc_aes128-testdata.c
Normal file
72
tests/cbc_aes128-testdata.c
Normal file
@ -0,0 +1,72 @@
|
||||
/* dtls -- a very basic DTLS implementation
|
||||
*
|
||||
* Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* test vectors from Appendix F.2.{1,2} of NIST SP 800-38A, ed. 2001 */
|
||||
|
||||
struct test_vector {
|
||||
size_t M; /* mode: 0 == encrypt, 1 == decrypt */
|
||||
size_t lm; /* overall message length */
|
||||
size_t la; /* not used */
|
||||
unsigned char key[AES_BLKLEN];
|
||||
unsigned char nonce[AES_BLKLEN];
|
||||
unsigned char msg[2000];
|
||||
size_t r_lm; /* overall result length */
|
||||
unsigned char result[2000]; /* result */
|
||||
};
|
||||
|
||||
struct test_vector data[] = {
|
||||
/* F.2.1 (encrypt) */
|
||||
{ 0, 4 * AES_BLKLEN, 0,
|
||||
{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, /* AES key */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, /* Nonce */
|
||||
{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
|
||||
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, /* msg */
|
||||
4 * AES_BLKLEN, /* length of result */
|
||||
{ 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
|
||||
0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
|
||||
0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
|
||||
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7
|
||||
} /* result */
|
||||
},
|
||||
|
||||
/* F.2.2 (decrypt) */
|
||||
{ 1, 4 * AES_BLKLEN, 0,
|
||||
{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, /* AES key */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, /* Nonce */
|
||||
{ 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
|
||||
0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
|
||||
0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
|
||||
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7
|
||||
}, /* msg */
|
||||
4 * AES_BLKLEN, /* length of result */
|
||||
{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
|
||||
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
|
||||
} /* result */
|
||||
}
|
||||
};
|
97
tests/ccm-test.c
Normal file
97
tests/ccm-test.c
Normal file
@ -0,0 +1,97 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
#include "contiki.h"
|
||||
#include "contiki-lib.h"
|
||||
#include "contiki-net.h"
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
//#include "debug.h"
|
||||
#include "dtls_config.h"
|
||||
#include "numeric.h"
|
||||
#include "ccm.h"
|
||||
|
||||
#include "ccm-testdata.c"
|
||||
|
||||
#ifndef HAVE_FLS
|
||||
int fls(unsigned int i) {
|
||||
int n;
|
||||
for (n = 0; i; n++)
|
||||
i >>= 1;
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
dump(unsigned char *buf, size_t len) {
|
||||
size_t i = 0;
|
||||
while (i < len) {
|
||||
printf("%02x ", buf[i++]);
|
||||
if (i % 4 == 0)
|
||||
printf(" ");
|
||||
if (i % 16 == 0)
|
||||
printf("\n\t");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
PROCESS(ccm_test_process, "CCM test process");
|
||||
AUTOSTART_PROCESSES(&ccm_test_process);
|
||||
PROCESS_THREAD(ccm_test_process, ev, d)
|
||||
{
|
||||
#else /* WITH_CONTIKI */
|
||||
int main(int argc, char **argv) {
|
||||
#endif /* WITH_CONTIKI */
|
||||
long int len;
|
||||
int n;
|
||||
|
||||
rijndael_ctx ctx;
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
PROCESS_BEGIN();
|
||||
#endif /* WITH_CONTIKI */
|
||||
|
||||
for (n = 0; n < sizeof(data)/sizeof(struct test_vector); ++n) {
|
||||
|
||||
if (rijndael_set_key_enc_only(&ctx, data[n].key, 8*sizeof(data[n].key)) < 0) {
|
||||
fprintf(stderr, "cannot set key\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = dtls_ccm_encrypt_message(&ctx, data[n].M, data[n].L, data[n].nonce,
|
||||
data[n].msg + data[n].la,
|
||||
data[n].lm - data[n].la,
|
||||
data[n].msg, data[n].la);
|
||||
|
||||
len += + data[n].la;
|
||||
printf("Packet Vector #%d ", n+1);
|
||||
if (len != data[n].r_lm || memcmp(data[n].msg, data[n].result, len))
|
||||
printf("FAILED, ");
|
||||
else
|
||||
printf("OK, ");
|
||||
|
||||
printf("result is (total length = %lu):\n\t", len);
|
||||
dump(data[n].msg, len);
|
||||
|
||||
len = dtls_ccm_decrypt_message(&ctx, data[n].M, data[n].L, data[n].nonce,
|
||||
data[n].msg + data[n].la, len - data[n].la,
|
||||
data[n].msg, data[n].la);
|
||||
|
||||
if (len < 0)
|
||||
printf("Packet Vector #%d: cannot decrypt message\n", n+1);
|
||||
else
|
||||
printf("\t*** MAC verified (total length = %lu) ***\n", len + data[n].la);
|
||||
}
|
||||
|
||||
#ifdef WITH_CONTIKI
|
||||
PROCESS_END();
|
||||
#else /* WITH_CONTIKI */
|
||||
return 0;
|
||||
#endif /* WITH_CONTIKI */
|
||||
}
|
395
tests/ccm-testdata.c
Normal file
395
tests/ccm-testdata.c
Normal file
@ -0,0 +1,395 @@
|
||||
/* dtls -- a very basic DTLS implementation
|
||||
*
|
||||
* Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* test vectors from RFC 3610 */
|
||||
|
||||
struct test_vector {
|
||||
size_t M, L;
|
||||
size_t lm; /* overall message length */
|
||||
size_t la; /* number of bytes additional data */
|
||||
unsigned char key[DTLS_CCM_BLOCKSIZE];
|
||||
unsigned char nonce[DTLS_CCM_BLOCKSIZE];
|
||||
unsigned char msg[200];
|
||||
size_t r_lm; /* overall result length */
|
||||
unsigned char result[200]; /* result */
|
||||
};
|
||||
|
||||
struct test_vector data[] = {
|
||||
/* #1 */
|
||||
{ 8, 2, 31, 8,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E}, /* msg */
|
||||
39, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x58, 0x8C, 0x97, 0x9A, 0x61, 0xC6, 0x63, 0xD2, 0xF0, 0x66, 0xD0, 0xC2, 0xC0, 0xF9, 0x89, 0x80, 0x6D, 0x5F, 0x6B, 0x61, 0xDA, 0xC3, 0x84, 0x17, 0xE8, 0xD1, 0x2C, 0xFD, 0xF9, 0x26, 0xE0} /* result */
|
||||
},
|
||||
|
||||
/* #2 */
|
||||
{ 8, 2, 32, 8,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}, /* msg */
|
||||
40, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x72, 0xC9, 0x1A, 0x36, 0xE1, 0x35, 0xF8, 0xCF, 0x29, 0x1C, 0xA8, 0x94, 0x08, 0x5C, 0x87, 0xE3, 0xCC, 0x15, 0xC4, 0x39, 0xC9, 0xE4, 0x3A, 0x3B, 0xA0, 0x91, 0xD5, 0x6E, 0x10, 0x40, 0x09, 0x16} /* result */
|
||||
},
|
||||
|
||||
/* #3 */
|
||||
{ 8, 2, 33, 8,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x02, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20}, /* msg */
|
||||
41, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x51, 0xB1, 0xE5, 0xF4, 0x4A, 0x19, 0x7D, 0x1D, 0xA4, 0x6B, 0x0F, 0x8E, 0x2D, 0x28, 0x2A, 0xE8, 0x71, 0xE8, 0x38, 0xBB, 0x64, 0xDA, 0x85, 0x96, 0x57, 0x4A, 0xDA, 0xA7, 0x6F, 0xBD, 0x9F, 0xB0, 0xC5} /* result */
|
||||
},
|
||||
|
||||
/* #4 */
|
||||
{ 8, 2, 31, 12,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x06, 0x05, 0x04, 0x03, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E}, /* msg */
|
||||
39, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xA2, 0x8C, 0x68, 0x65, 0x93, 0x9A, 0x9A, 0x79, 0xFA, 0xAA, 0x5C, 0x4C, 0x2A, 0x9D, 0x4A, 0x91, 0xCD, 0xAC, 0x8C, 0x96, 0xC8, 0x61, 0xB9, 0xC9, 0xE6, 0x1E, 0xF1} /* result */
|
||||
},
|
||||
|
||||
/* #5 */
|
||||
{ 8, 2, 32, 12,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x07, 0x06, 0x05, 0x04, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}, /* msg */
|
||||
40, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xDC, 0xF1, 0xFB, 0x7B, 0x5D, 0x9E, 0x23, 0xFB, 0x9D, 0x4E, 0x13, 0x12, 0x53, 0x65, 0x8A, 0xD8, 0x6E, 0xBD, 0xCA, 0x3E, 0x51, 0xE8, 0x3F, 0x07, 0x7D, 0x9C, 0x2D, 0x93} /* result */
|
||||
},
|
||||
|
||||
/* #6 */
|
||||
{ 8, 2, 33, 12,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x08, 0x07, 0x06, 0x05, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20}, /* msg */
|
||||
41, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x6F, 0xC1, 0xB0, 0x11, 0xF0, 0x06, 0x56, 0x8B, 0x51, 0x71, 0xA4, 0x2D, 0x95, 0x3D, 0x46, 0x9B, 0x25, 0x70, 0xA4, 0xBD, 0x87, 0x40, 0x5A, 0x04, 0x43, 0xAC, 0x91, 0xCB, 0x94} /* result */
|
||||
},
|
||||
|
||||
/* #7 */
|
||||
{ 10, 2, 31, 8,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x09, 0x08, 0x07, 0x06, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E}, /* msg */
|
||||
41, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x35, 0xD1, 0xB2, 0xC9, 0x5F, 0x41, 0xD5, 0xD1, 0xD4, 0xFE, 0xC1, 0x85, 0xD1, 0x66, 0xB8, 0x09, 0x4E, 0x99, 0x9D, 0xFE, 0xD9, 0x6C, 0x04, 0x8C, 0x56, 0x60, 0x2C, 0x97, 0xAC, 0xBB, 0x74, 0x90} /* result */
|
||||
},
|
||||
|
||||
/* #8 */
|
||||
{ 10, 2, 32, 8,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x0A, 0x09, 0x08, 0x07, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}, /* msg */
|
||||
42, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x7B, 0x75, 0x39, 0x9A, 0xC0, 0x83, 0x1D, 0xD2, 0xF0, 0xBB, 0xD7, 0x58, 0x79, 0xA2, 0xFD, 0x8F, 0x6C, 0xAE, 0x6B, 0x6C, 0xD9, 0xB7, 0xDB, 0x24, 0xC1, 0x7B, 0x44, 0x33, 0xF4, 0x34, 0x96, 0x3F, 0x34, 0xB4} /* result */
|
||||
},
|
||||
|
||||
/* #9 */
|
||||
{ 10, 2, 33, 8,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x0B, 0x0A, 0x09, 0x08, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20}, /* msg */
|
||||
43, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x82, 0x53, 0x1A, 0x60, 0xCC, 0x24, 0x94, 0x5A, 0x4B, 0x82, 0x79, 0x18, 0x1A, 0xB5, 0xC8, 0x4D, 0xF2, 0x1C, 0xE7, 0xF9, 0xB7, 0x3F, 0x42, 0xE1, 0x97, 0xEA, 0x9C, 0x07, 0xE5, 0x6B, 0x5E, 0xB1, 0x7E, 0x5F, 0x4E} /* result */
|
||||
},
|
||||
|
||||
/* #10 */
|
||||
{ 10, 2, 31, 12,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x0C, 0x0B, 0x0A, 0x09, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E}, /* msg */
|
||||
41, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x07, 0x34, 0x25, 0x94, 0x15, 0x77, 0x85, 0x15, 0x2B, 0x07, 0x40, 0x98, 0x33, 0x0A, 0xBB, 0x14, 0x1B, 0x94, 0x7B, 0x56, 0x6A, 0xA9, 0x40, 0x6B, 0x4D, 0x99, 0x99, 0x88, 0xDD} /* result */
|
||||
},
|
||||
|
||||
/* #11 */
|
||||
{ 10, 2, 32, 12,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x0D, 0x0C, 0x0B, 0x0A, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}, /* msg */
|
||||
42, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x67, 0x6B, 0xB2, 0x03, 0x80, 0xB0, 0xE3, 0x01, 0xE8, 0xAB, 0x79, 0x59, 0x0A, 0x39, 0x6D, 0xA7, 0x8B, 0x83, 0x49, 0x34, 0xF5, 0x3A, 0xA2, 0xE9, 0x10, 0x7A, 0x8B, 0x6C, 0x02, 0x2C} /* result */
|
||||
},
|
||||
|
||||
/* #12 */
|
||||
{ 10, 2, 33, 12,
|
||||
{ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x0E, 0x0D, 0x0C, 0x0B, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, /* Nonce */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20}, /* msg */
|
||||
43, /* length of result */
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xC0, 0xFF, 0xA0, 0xD6, 0xF0, 0x5B, 0xDB, 0x67, 0xF2, 0x4D, 0x43, 0xA4, 0x33, 0x8D, 0x2A, 0xA4, 0xBE, 0xD7, 0xB2, 0x0E, 0x43, 0xCD, 0x1A, 0xA3, 0x16, 0x62, 0xE7, 0xAD, 0x65, 0xD6, 0xDB} /* result */
|
||||
},
|
||||
|
||||
/* #13 */
|
||||
{ 8, 2, 31, 8,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x41, 0x2B, 0x4E, 0xA9, 0xCD, 0xBE, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0x0B, 0xE1, 0xA8, 0x8B, 0xAC, 0xE0, 0x18, 0xB1, 0x08, 0xE8, 0xCF, 0x97, 0xD8, 0x20, 0xEA, 0x25, 0x84, 0x60, 0xE9, 0x6A, 0xD9, 0xCF, 0x52, 0x89, 0x05, 0x4D, 0x89, 0x5C, 0xEA, 0xC4, 0x7C}, /* msg */
|
||||
39, /* length of result */
|
||||
{ 0x0B, 0xE1, 0xA8, 0x8B, 0xAC, 0xE0, 0x18, 0xB1, 0x4C, 0xB9, 0x7F, 0x86, 0xA2, 0xA4, 0x68, 0x9A, 0x87, 0x79, 0x47, 0xAB, 0x80, 0x91, 0xEF, 0x53, 0x86, 0xA6, 0xFF, 0xBD, 0xD0, 0x80, 0xF8, 0xE7, 0x8C, 0xF7, 0xCB, 0x0C, 0xDD, 0xD7, 0xB3} /* result */
|
||||
},
|
||||
|
||||
/* #14 */
|
||||
{ 8, 2, 32, 8,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x33, 0x56, 0x8E, 0xF7, 0xB2, 0x63, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0x63, 0x01, 0x8F, 0x76, 0xDC, 0x8A, 0x1B, 0xCB, 0x90, 0x20, 0xEA, 0x6F, 0x91, 0xBD, 0xD8, 0x5A, 0xFA, 0x00, 0x39, 0xBA, 0x4B, 0xAF, 0xF9, 0xBF, 0xB7, 0x9C, 0x70, 0x28, 0x94, 0x9C, 0xD0, 0xEC}, /* msg */
|
||||
40, /* length of result */
|
||||
{ 0x63, 0x01, 0x8F, 0x76, 0xDC, 0x8A, 0x1B, 0xCB, 0x4C, 0xCB, 0x1E, 0x7C, 0xA9, 0x81, 0xBE, 0xFA, 0xA0, 0x72, 0x6C, 0x55, 0xD3, 0x78, 0x06, 0x12, 0x98, 0xC8, 0x5C, 0x92, 0x81, 0x4A, 0xBC, 0x33, 0xC5, 0x2E, 0xE8, 0x1D, 0x7D, 0x77, 0xC0, 0x8A} /* result */
|
||||
},
|
||||
|
||||
/* #15 */
|
||||
{ 8, 2, 33, 8,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x10, 0x3F, 0xE4, 0x13, 0x36, 0x71, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0xAA, 0x6C, 0xFA, 0x36, 0xCA, 0xE8, 0x6B, 0x40, 0xB9, 0x16, 0xE0, 0xEA, 0xCC, 0x1C, 0x00, 0xD7, 0xDC, 0xEC, 0x68, 0xEC, 0x0B, 0x3B, 0xBB, 0x1A, 0x02, 0xDE, 0x8A, 0x2D, 0x1A, 0xA3, 0x46, 0x13, 0x2E}, /* msg */
|
||||
41, /* length of result */
|
||||
{ 0xAA, 0x6C, 0xFA, 0x36, 0xCA, 0xE8, 0x6B, 0x40, 0xB1, 0xD2, 0x3A, 0x22, 0x20, 0xDD, 0xC0, 0xAC, 0x90, 0x0D, 0x9A, 0xA0, 0x3C, 0x61, 0xFC, 0xF4, 0xA5, 0x59, 0xA4, 0x41, 0x77, 0x67, 0x08, 0x97, 0x08, 0xA7, 0x76, 0x79, 0x6E, 0xDB, 0x72, 0x35, 0x06} /* result */
|
||||
},
|
||||
|
||||
/* #16 */
|
||||
{ 8, 2, 31, 12,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x76, 0x4C, 0x63, 0xB8, 0x05, 0x8E, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0xD0, 0xD0, 0x73, 0x5C, 0x53, 0x1E, 0x1B, 0xEC, 0xF0, 0x49, 0xC2, 0x44, 0x12, 0xDA, 0xAC, 0x56, 0x30, 0xEF, 0xA5, 0x39, 0x6F, 0x77, 0x0C, 0xE1, 0xA6, 0x6B, 0x21, 0xF7, 0xB2, 0x10, 0x1C}, /* msg */
|
||||
39, /* length of result */
|
||||
{ 0xD0, 0xD0, 0x73, 0x5C, 0x53, 0x1E, 0x1B, 0xEC, 0xF0, 0x49, 0xC2, 0x44, 0x14, 0xD2, 0x53, 0xC3, 0x96, 0x7B, 0x70, 0x60, 0x9B, 0x7C, 0xBB, 0x7C, 0x49, 0x91, 0x60, 0x28, 0x32, 0x45, 0x26, 0x9A, 0x6F, 0x49, 0x97, 0x5B, 0xCA, 0xDE, 0xAF} /* result */
|
||||
},
|
||||
|
||||
/* #17 */
|
||||
{ 8, 2, 32, 12,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0xF8, 0xB6, 0x78, 0x09, 0x4E, 0x3B, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0x77, 0xB6, 0x0F, 0x01, 0x1C, 0x03, 0xE1, 0x52, 0x58, 0x99, 0xBC, 0xAE, 0xE8, 0x8B, 0x6A, 0x46, 0xC7, 0x8D, 0x63, 0xE5, 0x2E, 0xB8, 0xC5, 0x46, 0xEF, 0xB5, 0xDE, 0x6F, 0x75, 0xE9, 0xCC, 0x0D}, /* msg */
|
||||
40, /* length of result */
|
||||
{ 0x77, 0xB6, 0x0F, 0x01, 0x1C, 0x03, 0xE1, 0x52, 0x58, 0x99, 0xBC, 0xAE, 0x55, 0x45, 0xFF, 0x1A, 0x08, 0x5E, 0xE2, 0xEF, 0xBF, 0x52, 0xB2, 0xE0, 0x4B, 0xEE, 0x1E, 0x23, 0x36, 0xC7, 0x3E, 0x3F, 0x76, 0x2C, 0x0C, 0x77, 0x44, 0xFE, 0x7E, 0x3C} /* result */
|
||||
},
|
||||
|
||||
/* #18 */
|
||||
{ 8, 2, 33, 12,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0xD5, 0x60, 0x91, 0x2D, 0x3F, 0x70, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0xCD, 0x90, 0x44, 0xD2, 0xB7, 0x1F, 0xDB, 0x81, 0x20, 0xEA, 0x60, 0xC0, 0x64, 0x35, 0xAC, 0xBA, 0xFB, 0x11, 0xA8, 0x2E, 0x2F, 0x07, 0x1D, 0x7C, 0xA4, 0xA5, 0xEB, 0xD9, 0x3A, 0x80, 0x3B, 0xA8, 0x7F}, /* msg */
|
||||
41, /* length of result */
|
||||
{ 0xCD, 0x90, 0x44, 0xD2, 0xB7, 0x1F, 0xDB, 0x81, 0x20, 0xEA, 0x60, 0xC0, 0x00, 0x97, 0x69, 0xEC, 0xAB, 0xDF, 0x48, 0x62, 0x55, 0x94, 0xC5, 0x92, 0x51, 0xE6, 0x03, 0x57, 0x22, 0x67, 0x5E, 0x04, 0xC8, 0x47, 0x09, 0x9E, 0x5A, 0xE0, 0x70, 0x45, 0x51} /* result */
|
||||
},
|
||||
|
||||
/* #19 */
|
||||
{ 10, 2, 31, 8,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x42, 0xFF, 0xF8, 0xF1, 0x95, 0x1C, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0xD8, 0x5B, 0xC7, 0xE6, 0x9F, 0x94, 0x4F, 0xB8, 0x8A, 0x19, 0xB9, 0x50, 0xBC, 0xF7, 0x1A, 0x01, 0x8E, 0x5E, 0x67, 0x01, 0xC9, 0x17, 0x87, 0x65, 0x98, 0x09, 0xD6, 0x7D, 0xBE, 0xDD, 0x18}, /* msg */
|
||||
41, /* length of result */
|
||||
{ 0xD8, 0x5B, 0xC7, 0xE6, 0x9F, 0x94, 0x4F, 0xB8, 0xBC, 0x21, 0x8D, 0xAA, 0x94, 0x74, 0x27, 0xB6, 0xDB, 0x38, 0x6A, 0x99, 0xAC, 0x1A, 0xEF, 0x23, 0xAD, 0xE0, 0xB5, 0x29, 0x39, 0xCB, 0x6A, 0x63, 0x7C, 0xF9, 0xBE, 0xC2, 0x40, 0x88, 0x97, 0xC6, 0xBA} /* result */
|
||||
},
|
||||
|
||||
/* #20 */
|
||||
{ 10, 2, 32, 8,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x92, 0x0F, 0x40, 0xE5, 0x6C, 0xDC, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0x74, 0xA0, 0xEB, 0xC9, 0x06, 0x9F, 0x5B, 0x37, 0x17, 0x61, 0x43, 0x3C, 0x37, 0xC5, 0xA3, 0x5F, 0xC1, 0xF3, 0x9F, 0x40, 0x63, 0x02, 0xEB, 0x90, 0x7C, 0x61, 0x63, 0xBE, 0x38, 0xC9, 0x84, 0x37}, /* msg */
|
||||
42, /* length of result */
|
||||
{ 0x74, 0xA0, 0xEB, 0xC9, 0x06, 0x9F, 0x5B, 0x37, 0x58, 0x10, 0xE6, 0xFD, 0x25, 0x87, 0x40, 0x22, 0xE8, 0x03, 0x61, 0xA4, 0x78, 0xE3, 0xE9, 0xCF, 0x48, 0x4A, 0xB0, 0x4F, 0x44, 0x7E, 0xFF, 0xF6, 0xF0, 0xA4, 0x77, 0xCC, 0x2F, 0xC9, 0xBF, 0x54, 0x89, 0x44} /* result */
|
||||
},
|
||||
|
||||
/* #21 */
|
||||
{ 10, 2, 33, 8,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x27, 0xCA, 0x0C, 0x71, 0x20, 0xBC, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0x44, 0xA3, 0xAA, 0x3A, 0xAE, 0x64, 0x75, 0xCA, 0xA4, 0x34, 0xA8, 0xE5, 0x85, 0x00, 0xC6, 0xE4, 0x15, 0x30, 0x53, 0x88, 0x62, 0xD6, 0x86, 0xEA, 0x9E, 0x81, 0x30, 0x1B, 0x5A, 0xE4, 0x22, 0x6B, 0xFA}, /* msg */
|
||||
43, /* length of result */
|
||||
{ 0x44, 0xA3, 0xAA, 0x3A, 0xAE, 0x64, 0x75, 0xCA, 0xF2, 0xBE, 0xED, 0x7B, 0xC5, 0x09, 0x8E, 0x83, 0xFE, 0xB5, 0xB3, 0x16, 0x08, 0xF8, 0xE2, 0x9C, 0x38, 0x81, 0x9A, 0x89, 0xC8, 0xE7, 0x76, 0xF1, 0x54, 0x4D, 0x41, 0x51, 0xA4, 0xED, 0x3A, 0x8B, 0x87, 0xB9, 0xCE} /* result */
|
||||
},
|
||||
|
||||
/* #22 */
|
||||
{ 10, 2, 31, 12,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x5B, 0x8C, 0xCB, 0xCD, 0x9A, 0xF8, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70, 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41, 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43, 0xD2, 0xD7, 0xC2}, /* msg */
|
||||
41, /* length of result */
|
||||
{ 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70, 0x31, 0xD7, 0x50, 0xA0, 0x9D, 0xA3, 0xED, 0x7F, 0xDD, 0xD4, 0x9A, 0x20, 0x32, 0xAA, 0xBF, 0x17, 0xEC, 0x8E, 0xBF, 0x7D, 0x22, 0xC8, 0x08, 0x8C, 0x66, 0x6B, 0xE5, 0xC1, 0x97} /* result */
|
||||
},
|
||||
|
||||
/* #23 */
|
||||
{ 10, 2, 32, 12,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x3E, 0xBE, 0x94, 0x04, 0x4B, 0x9A, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0x47, 0xA6, 0x5A, 0xC7, 0x8B, 0x3D, 0x59, 0x42, 0x27, 0xE8, 0x5E, 0x71, 0xE2, 0xFC, 0xFB, 0xB8, 0x80, 0x44, 0x2C, 0x73, 0x1B, 0xF9, 0x51, 0x67, 0xC8, 0xFF, 0xD7, 0x89, 0x5E, 0x33, 0x70, 0x76}, /* msg */
|
||||
42, /* length of result */
|
||||
{ 0x47, 0xA6, 0x5A, 0xC7, 0x8B, 0x3D, 0x59, 0x42, 0x27, 0xE8, 0x5E, 0x71, 0xE8, 0x82, 0xF1, 0xDB, 0xD3, 0x8C, 0xE3, 0xED, 0xA7, 0xC2, 0x3F, 0x04, 0xDD, 0x65, 0x07, 0x1E, 0xB4, 0x13, 0x42, 0xAC, 0xDF, 0x7E, 0x00, 0xDC, 0xCE, 0xC7, 0xAE, 0x52, 0x98, 0x7D} /* result */
|
||||
},
|
||||
|
||||
/* #24 */
|
||||
{ 10, 2, 33, 12,
|
||||
{ 0xD7, 0x82, 0x8D, 0x13, 0xB2, 0xB0, 0xBD, 0xC3, 0x25, 0xA7, 0x62, 0x36, 0xDF, 0x93, 0xCC, 0x6B}, /* AES key */
|
||||
{ 0x00, 0x8D, 0x49, 0x3B, 0x30, 0xAE, 0x8B, 0x3C, 0x96, 0x96, 0x76, 0x6C, 0xFA}, /* Nonce */
|
||||
{ 0x6E, 0x37, 0xA6, 0xEF, 0x54, 0x6D, 0x95, 0x5D, 0x34, 0xAB, 0x60, 0x59, 0xAB, 0xF2, 0x1C, 0x0B, 0x02, 0xFE, 0xB8, 0x8F, 0x85, 0x6D, 0xF4, 0xA3, 0x73, 0x81, 0xBC, 0xE3, 0xCC, 0x12, 0x85, 0x17, 0xD4}, /* msg */
|
||||
43, /* length of result */
|
||||
{ 0x6E, 0x37, 0xA6, 0xEF, 0x54, 0x6D, 0x95, 0x5D, 0x34, 0xAB, 0x60, 0x59, 0xF3, 0x29, 0x05, 0xB8, 0x8A, 0x64, 0x1B, 0x04, 0xB9, 0xC9, 0xFF, 0xB5, 0x8C, 0xC3, 0x90, 0x90, 0x0F, 0x3D, 0xA1, 0x2A, 0xB1, 0x6D, 0xCE, 0x9E, 0x82, 0xEF, 0xA1, 0x6D, 0xA6, 0x20, 0x59} /* result */
|
||||
},
|
||||
|
||||
/* #25 */
|
||||
/* Cipher: AES-128 M=16 L=2 K_LEN=1 N_LEN=13 K=0x00 N=0x00000000000000000000000000 */
|
||||
{ 16, 2, 0, 0,
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* Nonce */
|
||||
{ }, /* msg */
|
||||
16, /* length of result */
|
||||
{ 0x8b, 0x60, 0xab, 0xcd, 0x60, 0x43, 0x81, 0x0b,
|
||||
0xa3, 0x78, 0xa0, 0x1d, 0x4a, 0x29, 0x83, 0x0b
|
||||
} /* result */
|
||||
},
|
||||
|
||||
/* #26 */
|
||||
/* Cipher: AES-128 M=16 L=2 K_LEN=1 N_LEN=13 K=0x00 N=0x00000000000000000000000000 */
|
||||
{ 16, 2, 37, 0,
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* AES key */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00 }, /* Nonce */
|
||||
{ 0x45, 0x69, 0x6e, 0x20, 0x6b, 0x6c, 0x65, 0x69,
|
||||
0x6e, 0x65, 0x72, 0x20, 0x54, 0x65, 0x78, 0x74,
|
||||
0x0a, 0x7a, 0x75, 0x6d, 0x20, 0x54, 0x65, 0x73,
|
||||
0x74, 0x65, 0x6e, 0x20, 0x76, 0x6f, 0x6e, 0x20,
|
||||
0x43, 0x43, 0x4d, 0x2e, 0x0a
|
||||
}, /* msg */
|
||||
53, /* length of result */
|
||||
{ 0x90, 0x11, 0x9c, 0x2d, 0x6b, 0xf9, 0xe9, 0x05,
|
||||
0x3e, 0x0b, 0x44, 0x56, 0xca, 0xc8, 0xb6, 0x1a,
|
||||
0x00, 0x57, 0xa9, 0x8b, 0x6b, 0x69, 0x09, 0x7e,
|
||||
0x8e, 0x50, 0x50, 0x63, 0x50, 0x58, 0x0f, 0x78,
|
||||
0x75, 0x69, 0x6e, 0x9f, 0x3d, 0x63, 0x93, 0xe7,
|
||||
0x7a, 0x84, 0xe9, 0x9f, 0x11, 0x93, 0x95, 0xa0,
|
||||
0x9a, 0xef, 0x0d, 0xa0, 0xed
|
||||
} /* result */
|
||||
},
|
||||
|
||||
/* #27 */
|
||||
/* Cipher: AES-128 M=8 L=5 K_LEN=16 N_LEN=10 K=0x001234567890abcdefdcaffeed3921ee N=0x00112233445566778899 */
|
||||
{ 8, 5, 0, 0,
|
||||
{ 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd,
|
||||
0xef, 0xdc, 0xaf, 0xfe, 0xed, 0x39, 0x21, 0xee }, /* AES key */
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99 }, /* Nonce */
|
||||
{ }, /* msg */
|
||||
8, /* length of result */
|
||||
{ 0xb1, 0x33, 0x51, 0xc8, 0xb3, 0xd5, 0x10, 0xa7 } /* result */
|
||||
},
|
||||
|
||||
/* #28 */
|
||||
/* Cipher: AES-128 M=8 L=5 K_LEN=16 N_LEN=10 K=0x001234567890abcdefdcaffeed3921ee N=0x00112233445566778899 */
|
||||
{ 8, 5, 37, 0,
|
||||
{ 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd,
|
||||
0xef, 0xdc, 0xaf, 0xfe, 0xed, 0x39, 0x21, 0xee }, /* AES key */
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99 }, /* Nonce */
|
||||
{ 0x45, 0x69, 0x6e, 0x20, 0x6b, 0x6c, 0x65, 0x69,
|
||||
0x6e, 0x65, 0x72, 0x20, 0x54, 0x65, 0x78, 0x74,
|
||||
0x0a, 0x7a, 0x75, 0x6d, 0x20, 0x54, 0x65, 0x73,
|
||||
0x74, 0x65, 0x6e, 0x20, 0x76, 0x6f, 0x6e, 0x20,
|
||||
0x43, 0x43, 0x4d, 0x2e, 0x0a
|
||||
}, /* msg */
|
||||
45, /* length of result */
|
||||
{ 0x44, 0x7a, 0x82, 0x70, 0x1d, 0xd0, 0x35, 0x7b,
|
||||
0x68, 0xf7, 0x35, 0x4d, 0xbf, 0xd9, 0x16, 0x15,
|
||||
0x97, 0x41, 0x3d, 0x1e, 0x89, 0xc1, 0x25, 0xe7,
|
||||
0xd6, 0xa7, 0xde, 0x90, 0x1e, 0xf1, 0x69, 0x69,
|
||||
0x9f, 0xce, 0x40, 0xdc, 0xf0, 0xd1, 0x74, 0x53,
|
||||
0x2c, 0xa3, 0xb0, 0xcf, 0xb9
|
||||
} /* result */
|
||||
},
|
||||
|
||||
/* #29 */
|
||||
/* Cipher: AES-128 M=14 L=3 K_LEN=16 N_LEN=12 K=0x001234567890abcdefdcaffeed3921ee N=0x001122334455667788990000 */
|
||||
{ 14, 3, 0, 0,
|
||||
{ 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd,
|
||||
0xef, 0xdc, 0xaf, 0xfe, 0xed, 0x39, 0x21, 0xee }, /* AES key */
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0x00, 0x00 }, /* Nonce */
|
||||
{ }, /* msg */
|
||||
14, /* length of result */
|
||||
{ 0xa4, 0x06, 0xa4, 0x23, 0x93, 0x3d, 0xa0, 0xca,
|
||||
0xb5, 0x90, 0xdb, 0x69, 0x69, 0x33 } /* result */
|
||||
},
|
||||
|
||||
/* #30 */
|
||||
/* Cipher: AES-128 M=14 L=3 K_LEN=16 N_LEN=12 K=0x001234567890abcdefdcaffeed3921ee N=0x001122334455667788990000 */
|
||||
{ 14, 3, 37, 0,
|
||||
{ 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd,
|
||||
0xef, 0xdc, 0xaf, 0xfe, 0xed, 0x39, 0x21, 0xee }, /* AES key */
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0x00, 0x00 }, /* Nonce */
|
||||
{ 0x45, 0x69, 0x6e, 0x20, 0x6b, 0x6c, 0x65, 0x69,
|
||||
0x6e, 0x65, 0x72, 0x20, 0x54, 0x65, 0x78, 0x74,
|
||||
0x0a, 0x7a, 0x75, 0x6d, 0x20, 0x54, 0x65, 0x73,
|
||||
0x74, 0x65, 0x6e, 0x20, 0x76, 0x6f, 0x6e, 0x20,
|
||||
0x43, 0x43, 0x4d, 0x2e, 0x0a
|
||||
}, /* msg */
|
||||
51,
|
||||
{ 0x60, 0xaf, 0x87, 0x67, 0x4d, 0x9d, 0x54, 0x17,
|
||||
0x16, 0xc0, 0x29, 0x10, 0x7e, 0x3e, 0x34, 0x93,
|
||||
0x78, 0xe8, 0xd3, 0xc8, 0xc1, 0x03, 0x4f, 0xd6,
|
||||
0xf5, 0x3b, 0xaf, 0xd3, 0xf0, 0xd7, 0x0b, 0xdd,
|
||||
0x63, 0x93, 0xed, 0xf2, 0xb2, 0x72, 0xdc, 0xae,
|
||||
0x7c, 0xa0, 0x01, 0xdb, 0x56, 0x2a, 0x06, 0xb6,
|
||||
0xe9, 0xcf, 0x3c } /* result */
|
||||
},
|
||||
|
||||
/* #31 */
|
||||
/* Cipher: AES-128 M=8 L=5 K_LEN=6 N_LEN=10 K=0x11223344aabb N=0x00112233445566778899 */
|
||||
{ 8, 5, 0, 0,
|
||||
{ 0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb }, /* AES key */
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99 }, /* Nonce */
|
||||
{ }, /* msg */
|
||||
8,
|
||||
{ 0x28, 0x15, 0xfe, 0x81, 0xdd, 0xc3, 0x79, 0x04 } /* result */
|
||||
},
|
||||
|
||||
/* #32 */
|
||||
/* Cipher: AES-128 M=8 L=5 K_LEN=6 N_LEN=10 K=0x11223344aabb N=0x00112233445566778899 */
|
||||
|
||||
{ 8, 5, 37, 0,
|
||||
{ 0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb }, /* AES key */
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99 }, /* Nonce */
|
||||
{ 0x45, 0x69, 0x6e, 0x20, 0x6b, 0x6c, 0x65, 0x69,
|
||||
0x6e, 0x65, 0x72, 0x20, 0x54, 0x65, 0x78, 0x74,
|
||||
0x0a, 0x7a, 0x75, 0x6d, 0x20, 0x54, 0x65, 0x73,
|
||||
0x74, 0x65, 0x6e, 0x20, 0x76, 0x6f, 0x6e, 0x20,
|
||||
0x43, 0x43, 0x4d, 0x2e, 0x0a
|
||||
}, /* msg */
|
||||
45,
|
||||
{ 0xdb, 0x31, 0x55, 0x9d, 0xab, 0x70, 0xdc, 0x62,
|
||||
0xd7, 0x76, 0x41, 0xb2, 0x14, 0x9e, 0x9c, 0x26,
|
||||
0x70, 0x61, 0xea, 0x36, 0xf8, 0x0e, 0xdf, 0x19,
|
||||
0xa6, 0xc7, 0x46, 0x3d, 0x5a, 0xc3, 0x0a, 0x73,
|
||||
0x14, 0x96, 0xa4, 0x84, 0x7f, 0x37, 0x55, 0x42,
|
||||
0xce, 0x7e, 0xf9, 0x3b, 0xe5 } /* result */
|
||||
}
|
||||
};
|
108
tests/dsrv-test.c
Normal file
108
tests/dsrv-test.c
Normal file
@ -0,0 +1,108 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "dsrv.h"
|
||||
|
||||
void
|
||||
handle_read(struct dsrv_context_t *ctx) {
|
||||
int len;
|
||||
static char buf[200];
|
||||
struct sockaddr_storage src;
|
||||
socklen_t srclen = sizeof(src);
|
||||
int fd = dsrv_get_fd(ctx, DSRV_READ);
|
||||
|
||||
len = recvfrom(fd, buf, sizeof(buf), 0,
|
||||
(struct sockaddr *)&src, &srclen);
|
||||
|
||||
if (len < 0) {
|
||||
perror("recvfrom");
|
||||
} else {
|
||||
printf("read %d bytes: '%*s'\n", len, len, buf);
|
||||
if (dsrv_sendto(ctx, (struct sockaddr *)&src, srclen, 0, buf, len)
|
||||
== NULL) {
|
||||
fprintf(stderr, "cannot add packet to sendqueue\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
handle_write(struct dsrv_context_t *ctx) {
|
||||
struct packet_t *p;
|
||||
int fd = dsrv_get_fd(ctx, DSRV_WRITE);
|
||||
int len;
|
||||
|
||||
p = ctx->rq ? nq_peek(ctx->wq) : NULL;
|
||||
|
||||
if (!p)
|
||||
return -1;
|
||||
|
||||
len = sendto(fd, p->buf, p->len, 0, p->raddr, p->rlen);
|
||||
|
||||
if (len < 0)
|
||||
perror("sendto");
|
||||
else
|
||||
nq_pop(ctx->wq);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
#if 1
|
||||
struct sockaddr_in6 listen_addr = { AF_INET6, htons(20220), 0, IN6ADDR_ANY_INIT, 0 };
|
||||
#else
|
||||
struct sockaddr_in listen_addr = { AF_INET, htons(20220), { htonl(0x7f000001) } };
|
||||
#endif
|
||||
fd_set rfds, wfds;
|
||||
struct timeval timeout;
|
||||
struct dsrv_context_t *ctx;
|
||||
int result;
|
||||
|
||||
ctx = dsrv_new_context((struct sockaddr *)&listen_addr, sizeof(listen_addr),
|
||||
200,200);
|
||||
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "E: cannot create server context\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
|
||||
dsrv_prepare(ctx, &rfds, DSRV_READ);
|
||||
dsrv_prepare(ctx, &wfds, DSRV_WRITE);
|
||||
|
||||
#if 0
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = dsrv_get_timeout(ctx);
|
||||
#else
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
#endif
|
||||
|
||||
result = select( FD_SETSIZE, &rfds, &wfds, 0, &timeout);
|
||||
|
||||
if (result < 0) { /* error */
|
||||
if (errno != EINTR)
|
||||
perror("select");
|
||||
} else if (result == 0) { /* timeout */
|
||||
printf(".");
|
||||
} else { /* ok */
|
||||
if (dsrv_check(ctx, &wfds, DSRV_WRITE))
|
||||
handle_write(ctx);
|
||||
else if (dsrv_check(ctx, &rfds, DSRV_READ))
|
||||
handle_read(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
dsrv_close(ctx);
|
||||
dsrv_free_context(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
530
tests/dtls-client.c
Normal file
530
tests/dtls-client.c
Normal file
@ -0,0 +1,530 @@
|
||||
#include "tinydtls.h"
|
||||
|
||||
/* This is needed for apple */
|
||||
#define __APPLE_USE_RFC_3542
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "debug.h"
|
||||
#include "dtls.h"
|
||||
|
||||
#define DEFAULT_PORT 20220
|
||||
|
||||
#define PSK_DEFAULT_IDENTITY "Client_identity"
|
||||
#define PSK_DEFAULT_KEY "secretPSK"
|
||||
#define PSK_OPTIONS "i:k:"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UNUSED_PARAM __attribute__((unused))
|
||||
#else
|
||||
#define UNUSED_PARAM
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
static char buf[200];
|
||||
static size_t len = 0;
|
||||
|
||||
typedef struct {
|
||||
size_t length; /* length of string */
|
||||
unsigned char *s; /* string data */
|
||||
} dtls_str;
|
||||
|
||||
static dtls_str output_file = { 0, NULL }; /* output file name */
|
||||
|
||||
static dtls_context_t *dtls_context = NULL;
|
||||
static dtls_context_t *orig_dtls_context = NULL;
|
||||
|
||||
|
||||
static const unsigned char ecdsa_priv_key[] = {
|
||||
0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
|
||||
0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
|
||||
0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
|
||||
0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA};
|
||||
|
||||
static const unsigned char ecdsa_pub_key_x[] = {
|
||||
0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
|
||||
0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
|
||||
0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
|
||||
0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52};
|
||||
|
||||
static const unsigned char ecdsa_pub_key_y[] = {
|
||||
0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
|
||||
0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
|
||||
0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
|
||||
0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29};
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
ssize_t
|
||||
read_from_file(char *arg, unsigned char *buf, size_t max_buf_len) {
|
||||
FILE *f;
|
||||
ssize_t result = 0;
|
||||
|
||||
f = fopen(arg, "r");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
while (!feof(f)) {
|
||||
size_t bytes_read;
|
||||
bytes_read = fread(buf, 1, max_buf_len, f);
|
||||
if (ferror(f)) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
buf += bytes_read;
|
||||
result += bytes_read;
|
||||
max_buf_len -= bytes_read;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* The PSK information for DTLS */
|
||||
#define PSK_ID_MAXLEN 256
|
||||
#define PSK_MAXLEN 256
|
||||
static unsigned char psk_id[PSK_ID_MAXLEN];
|
||||
static size_t psk_id_length = 0;
|
||||
static unsigned char psk_key[PSK_MAXLEN];
|
||||
static size_t psk_key_length = 0;
|
||||
|
||||
/* This function is the "key store" for tinyDTLS. It is called to
|
||||
* retrieve a key for the given identity within this particular
|
||||
* session. */
|
||||
static int
|
||||
get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
|
||||
const session_t *session UNUSED_PARAM,
|
||||
dtls_credentials_type_t type,
|
||||
const unsigned char *id, size_t id_len,
|
||||
unsigned char *result, size_t result_length) {
|
||||
|
||||
switch (type) {
|
||||
case DTLS_PSK_IDENTITY:
|
||||
if (id_len) {
|
||||
dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id);
|
||||
}
|
||||
|
||||
if (result_length < psk_id_length) {
|
||||
dtls_warn("cannot set psk_identity -- buffer too small\n");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
memcpy(result, psk_id, psk_id_length);
|
||||
return psk_id_length;
|
||||
case DTLS_PSK_KEY:
|
||||
if (id_len != psk_id_length || memcmp(psk_id, id, id_len) != 0) {
|
||||
dtls_warn("PSK for unknown id requested, exiting\n");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_ILLEGAL_PARAMETER);
|
||||
} else if (result_length < psk_key_length) {
|
||||
dtls_warn("cannot set psk -- buffer too small\n");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
memcpy(result, psk_key, psk_key_length);
|
||||
return psk_key_length;
|
||||
default:
|
||||
dtls_warn("unsupported request type: %d\n", type);
|
||||
}
|
||||
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
#endif /* DTLS_PSK */
|
||||
|
||||
#ifdef DTLS_ECC
|
||||
static int
|
||||
get_ecdsa_key(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const dtls_ecdsa_key_t **result) {
|
||||
static const dtls_ecdsa_key_t ecdsa_key = {
|
||||
.curve = DTLS_ECDH_CURVE_SECP256R1,
|
||||
.priv_key = ecdsa_priv_key,
|
||||
.pub_key_x = ecdsa_pub_key_x,
|
||||
.pub_key_y = ecdsa_pub_key_y
|
||||
};
|
||||
|
||||
*result = &ecdsa_key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
verify_ecdsa_key(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const unsigned char *other_pub_x,
|
||||
const unsigned char *other_pub_y,
|
||||
size_t key_size) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* DTLS_ECC */
|
||||
|
||||
static void
|
||||
try_send(struct dtls_context_t *ctx, session_t *dst) {
|
||||
int res;
|
||||
res = dtls_write(ctx, dst, (uint8 *)buf, len);
|
||||
if (res >= 0) {
|
||||
memmove(buf, buf + res, len - res);
|
||||
len -= res;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_stdin() {
|
||||
if (fgets(buf + len, sizeof(buf) - len, stdin))
|
||||
len += strlen(buf + len);
|
||||
}
|
||||
|
||||
static int
|
||||
read_from_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%c", data[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
send_to_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len) {
|
||||
|
||||
int fd = *(int *)dtls_get_app_data(ctx);
|
||||
return sendto(fd, data, len, MSG_DONTWAIT,
|
||||
&session->addr.sa, session->size);
|
||||
}
|
||||
|
||||
static int
|
||||
dtls_handle_read(struct dtls_context_t *ctx) {
|
||||
int fd;
|
||||
session_t session;
|
||||
#define MAX_READ_BUF 2000
|
||||
static uint8 buf[MAX_READ_BUF];
|
||||
int len;
|
||||
|
||||
fd = *(int *)dtls_get_app_data(ctx);
|
||||
|
||||
if (!fd)
|
||||
return -1;
|
||||
|
||||
memset(&session, 0, sizeof(session_t));
|
||||
session.size = sizeof(session.addr);
|
||||
len = recvfrom(fd, buf, MAX_READ_BUF, 0,
|
||||
&session.addr.sa, &session.size);
|
||||
|
||||
if (len < 0) {
|
||||
perror("recvfrom");
|
||||
return -1;
|
||||
} else {
|
||||
dtls_dsrv_log_addr(DTLS_LOG_DEBUG, "peer", &session);
|
||||
dtls_debug_dump("bytes from peer", buf, len);
|
||||
}
|
||||
|
||||
return dtls_handle_message(ctx, &session, buf, len);
|
||||
}
|
||||
|
||||
static void dtls_handle_signal(int sig)
|
||||
{
|
||||
dtls_free_context(dtls_context);
|
||||
dtls_free_context(orig_dtls_context);
|
||||
signal(sig, SIG_DFL);
|
||||
kill(getpid(), sig);
|
||||
}
|
||||
|
||||
/* stolen from libcoap: */
|
||||
static int
|
||||
resolve_address(const char *server, struct sockaddr *dst) {
|
||||
|
||||
struct addrinfo *res, *ainfo;
|
||||
struct addrinfo hints;
|
||||
static char addrstr[256];
|
||||
int error;
|
||||
|
||||
memset(addrstr, 0, sizeof(addrstr));
|
||||
if (server && strlen(server) > 0)
|
||||
memcpy(addrstr, server, strlen(server));
|
||||
else
|
||||
memcpy(addrstr, "localhost", 9);
|
||||
|
||||
memset ((char *)&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
error = getaddrinfo(addrstr, "", &hints, &res);
|
||||
|
||||
if (error != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
|
||||
|
||||
switch (ainfo->ai_family) {
|
||||
case AF_INET6:
|
||||
case AF_INET:
|
||||
|
||||
memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
return ainfo->ai_addrlen;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
usage( const char *program, const char *version) {
|
||||
const char *p;
|
||||
|
||||
p = strrchr( program, '/' );
|
||||
if ( p )
|
||||
program = ++p;
|
||||
|
||||
fprintf(stderr, "%s v%s -- DTLS client implementation\n"
|
||||
"(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
|
||||
#ifdef DTLS_PSK
|
||||
"usage: %s [-i file] [-k file] [-o file] [-p port] [-v num] addr [port]\n"
|
||||
#else /* DTLS_PSK */
|
||||
"usage: %s [-o file] [-p port] [-v num] addr [port]\n"
|
||||
#endif /* DTLS_PSK */
|
||||
#ifdef DTLS_PSK
|
||||
"\t-i file\t\tread PSK identity from file\n"
|
||||
"\t-k file\t\tread pre-shared key from file\n"
|
||||
#endif /* DTLS_PSK */
|
||||
"\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n"
|
||||
"\t-p port\t\tlisten on specified port (default is %d)\n"
|
||||
"\t-v num\t\tverbosity level (default: 3)\n",
|
||||
program, version, program, DEFAULT_PORT);
|
||||
}
|
||||
|
||||
static dtls_handler_t cb = {
|
||||
.write = send_to_peer,
|
||||
.read = read_from_peer,
|
||||
.event = NULL,
|
||||
#ifdef DTLS_PSK
|
||||
.get_psk_info = get_psk_info,
|
||||
#endif /* DTLS_PSK */
|
||||
#ifdef DTLS_ECC
|
||||
.get_ecdsa_key = get_ecdsa_key,
|
||||
.verify_ecdsa_key = verify_ecdsa_key
|
||||
#endif /* DTLS_ECC */
|
||||
};
|
||||
|
||||
#define DTLS_CLIENT_CMD_CLOSE "client:close"
|
||||
#define DTLS_CLIENT_CMD_RENEGOTIATE "client:renegotiate"
|
||||
|
||||
/* As per RFC 6347 section 4.2.8, DTLS Server should support requests
|
||||
* from clients who have silently abandoned the existing association
|
||||
* and initiated a new handshake request by sending a ClientHello.
|
||||
* Below command tests this feature.
|
||||
*/
|
||||
#define DTLS_CLIENT_CMD_REHANDSHAKE "client:rehandshake"
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
fd_set rfds, wfds;
|
||||
struct timeval timeout;
|
||||
unsigned short port = DEFAULT_PORT;
|
||||
char port_str[NI_MAXSERV] = "0";
|
||||
log_t log_level = DTLS_LOG_WARN;
|
||||
int fd, result;
|
||||
int on = 1;
|
||||
int opt, res;
|
||||
session_t dst;
|
||||
|
||||
dtls_init();
|
||||
snprintf(port_str, sizeof(port_str), "%d", port);
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
psk_id_length = strlen(PSK_DEFAULT_IDENTITY);
|
||||
psk_key_length = strlen(PSK_DEFAULT_KEY);
|
||||
memcpy(psk_id, PSK_DEFAULT_IDENTITY, psk_id_length);
|
||||
memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length);
|
||||
#endif /* DTLS_PSK */
|
||||
|
||||
while ((opt = getopt(argc, argv, "p:o:v:" PSK_OPTIONS)) != -1) {
|
||||
switch (opt) {
|
||||
#ifdef DTLS_PSK
|
||||
case 'i' : {
|
||||
ssize_t result = read_from_file(optarg, psk_id, PSK_ID_MAXLEN);
|
||||
if (result < 0) {
|
||||
dtls_warn("cannot read PSK identity\n");
|
||||
} else {
|
||||
psk_id_length = result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'k' : {
|
||||
ssize_t result = read_from_file(optarg, psk_key, PSK_MAXLEN);
|
||||
if (result < 0) {
|
||||
dtls_warn("cannot read PSK\n");
|
||||
} else {
|
||||
psk_key_length = result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* DTLS_PSK */
|
||||
case 'p' :
|
||||
strncpy(port_str, optarg, NI_MAXSERV-1);
|
||||
port_str[NI_MAXSERV - 1] = '\0';
|
||||
break;
|
||||
case 'o' :
|
||||
output_file.length = strlen(optarg);
|
||||
output_file.s = (unsigned char *)malloc(output_file.length + 1);
|
||||
|
||||
if (!output_file.s) {
|
||||
dtls_crit("cannot set output file: insufficient memory\n");
|
||||
exit(-1);
|
||||
} else {
|
||||
/* copy filename including trailing zero */
|
||||
memcpy(output_file.s, optarg, output_file.length + 1);
|
||||
}
|
||||
break;
|
||||
case 'v' :
|
||||
log_level = strtol(optarg, NULL, 10);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], dtls_package_version());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
dtls_set_log_level(log_level);
|
||||
|
||||
if (argc <= optind) {
|
||||
usage(argv[0], dtls_package_version());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(&dst, 0, sizeof(session_t));
|
||||
/* resolve destination address where server should be sent */
|
||||
res = resolve_address(argv[optind++], &dst.addr.sa);
|
||||
if (res < 0) {
|
||||
dtls_emerg("failed to resolve address\n");
|
||||
exit(-1);
|
||||
}
|
||||
dst.size = res;
|
||||
|
||||
/* use port number from command line when specified or the listen
|
||||
port, otherwise */
|
||||
dst.addr.sin.sin_port = htons(atoi(optind < argc ? argv[optind++] : port_str));
|
||||
|
||||
|
||||
/* init socket and set it to non-blocking */
|
||||
fd = socket(dst.addr.sa.sa_family, SOCK_DGRAM, 0);
|
||||
|
||||
if (fd < 0) {
|
||||
dtls_alert("socket: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
|
||||
dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
|
||||
}
|
||||
#if 0
|
||||
flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
dtls_alert("fcntl: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
on = 1;
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
|
||||
#else /* IPV6_RECVPKTINFO */
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
|
||||
#endif /* IPV6_RECVPKTINFO */
|
||||
dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
if (signal(SIGINT, dtls_handle_signal) == SIG_ERR) {
|
||||
dtls_alert("An error occurred while setting a signal handler.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dtls_context = dtls_new_context(&fd);
|
||||
if (!dtls_context) {
|
||||
dtls_emerg("cannot create context\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
dtls_set_handler(dtls_context, &cb);
|
||||
|
||||
dtls_connect(dtls_context, &dst);
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
|
||||
FD_SET(fileno(stdin), &rfds);
|
||||
FD_SET(fd, &rfds);
|
||||
/* FD_SET(fd, &wfds); */
|
||||
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
result = select(fd+1, &rfds, &wfds, 0, &timeout);
|
||||
|
||||
if (result < 0) { /* error */
|
||||
if (errno != EINTR)
|
||||
perror("select");
|
||||
} else if (result == 0) { /* timeout */
|
||||
} else { /* ok */
|
||||
if (FD_ISSET(fd, &wfds))
|
||||
/* FIXME */;
|
||||
else if (FD_ISSET(fd, &rfds))
|
||||
dtls_handle_read(dtls_context);
|
||||
else if (FD_ISSET(fileno(stdin), &rfds))
|
||||
handle_stdin();
|
||||
}
|
||||
|
||||
if (len) {
|
||||
if (len >= strlen(DTLS_CLIENT_CMD_CLOSE) &&
|
||||
!memcmp(buf, DTLS_CLIENT_CMD_CLOSE, strlen(DTLS_CLIENT_CMD_CLOSE))) {
|
||||
printf("client: closing connection\n");
|
||||
dtls_close(dtls_context, &dst);
|
||||
len = 0;
|
||||
} else if (len >= strlen(DTLS_CLIENT_CMD_RENEGOTIATE) &&
|
||||
!memcmp(buf, DTLS_CLIENT_CMD_RENEGOTIATE, strlen(DTLS_CLIENT_CMD_RENEGOTIATE))) {
|
||||
printf("client: renegotiate connection\n");
|
||||
dtls_renegotiate(dtls_context, &dst);
|
||||
len = 0;
|
||||
} else if (len >= strlen(DTLS_CLIENT_CMD_REHANDSHAKE) &&
|
||||
!memcmp(buf, DTLS_CLIENT_CMD_REHANDSHAKE, strlen(DTLS_CLIENT_CMD_REHANDSHAKE))) {
|
||||
printf("client: rehandshake connection\n");
|
||||
if (orig_dtls_context == NULL) {
|
||||
/* Cache the current context. We cannot free the current context as it will notify
|
||||
* the Server to close the connection (which we do not want).
|
||||
*/
|
||||
orig_dtls_context = dtls_context;
|
||||
/* Now, Create a new context and attempt to initiate a handshake. */
|
||||
dtls_context = dtls_new_context(&fd);
|
||||
if (!dtls_context) {
|
||||
dtls_emerg("cannot create context\n");
|
||||
exit(-1);
|
||||
}
|
||||
dtls_set_handler(dtls_context, &cb);
|
||||
dtls_connect(dtls_context, &dst);
|
||||
}
|
||||
len = 0;
|
||||
} else {
|
||||
try_send(dtls_context, &dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dtls_free_context(dtls_context);
|
||||
dtls_free_context(orig_dtls_context);
|
||||
exit(0);
|
||||
}
|
||||
|
366
tests/dtls-server.c
Normal file
366
tests/dtls-server.c
Normal file
@ -0,0 +1,366 @@
|
||||
|
||||
/* This is needed for apple */
|
||||
#define __APPLE_USE_RFC_3542
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "dtls.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define DEFAULT_PORT 20220
|
||||
|
||||
static const unsigned char ecdsa_priv_key[] = {
|
||||
0xD9, 0xE2, 0x70, 0x7A, 0x72, 0xDA, 0x6A, 0x05,
|
||||
0x04, 0x99, 0x5C, 0x86, 0xED, 0xDB, 0xE3, 0xEF,
|
||||
0xC7, 0xF1, 0xCD, 0x74, 0x83, 0x8F, 0x75, 0x70,
|
||||
0xC8, 0x07, 0x2D, 0x0A, 0x76, 0x26, 0x1B, 0xD4};
|
||||
|
||||
static const unsigned char ecdsa_pub_key_x[] = {
|
||||
0xD0, 0x55, 0xEE, 0x14, 0x08, 0x4D, 0x6E, 0x06,
|
||||
0x15, 0x59, 0x9D, 0xB5, 0x83, 0x91, 0x3E, 0x4A,
|
||||
0x3E, 0x45, 0x26, 0xA2, 0x70, 0x4D, 0x61, 0xF2,
|
||||
0x7A, 0x4C, 0xCF, 0xBA, 0x97, 0x58, 0xEF, 0x9A};
|
||||
|
||||
static const unsigned char ecdsa_pub_key_y[] = {
|
||||
0xB4, 0x18, 0xB6, 0x4A, 0xFE, 0x80, 0x30, 0xDA,
|
||||
0x1D, 0xDC, 0xF4, 0xF4, 0x2E, 0x2F, 0x26, 0x31,
|
||||
0xD0, 0x43, 0xB1, 0xFB, 0x03, 0xE2, 0x2F, 0x4D,
|
||||
0x17, 0xDE, 0x43, 0xF9, 0xF9, 0xAD, 0xEE, 0x70};
|
||||
|
||||
#if 0
|
||||
/* SIGINT handler: set quit to 1 for graceful termination */
|
||||
void
|
||||
handle_sigint(int signum) {
|
||||
dsrv_stop(dsrv_get_context());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
/* This function is the "key store" for tinyDTLS. It is called to
|
||||
* retrieve a key for the given identity within this particular
|
||||
* session. */
|
||||
static int
|
||||
get_psk_info(struct dtls_context_t *ctx, const session_t *session,
|
||||
dtls_credentials_type_t type,
|
||||
const unsigned char *id, size_t id_len,
|
||||
unsigned char *result, size_t result_length) {
|
||||
|
||||
struct keymap_t {
|
||||
unsigned char *id;
|
||||
size_t id_length;
|
||||
unsigned char *key;
|
||||
size_t key_length;
|
||||
} psk[3] = {
|
||||
{ (unsigned char *)"Client_identity", 15,
|
||||
(unsigned char *)"secretPSK", 9 },
|
||||
{ (unsigned char *)"default identity", 16,
|
||||
(unsigned char *)"\x11\x22\x33", 3 },
|
||||
{ (unsigned char *)"\0", 2,
|
||||
(unsigned char *)"", 1 }
|
||||
};
|
||||
|
||||
if (type != DTLS_PSK_KEY) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id) {
|
||||
int i;
|
||||
for (i = 0; i < sizeof(psk)/sizeof(struct keymap_t); i++) {
|
||||
if (id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) {
|
||||
if (result_length < psk[i].key_length) {
|
||||
dtls_warn("buffer too small for PSK");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
memcpy(result, psk[i].key, psk[i].key_length);
|
||||
return psk[i].key_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
|
||||
}
|
||||
|
||||
#endif /* DTLS_PSK */
|
||||
|
||||
#ifdef DTLS_ECC
|
||||
static int
|
||||
get_ecdsa_key(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const dtls_ecdsa_key_t **result) {
|
||||
static const dtls_ecdsa_key_t ecdsa_key = {
|
||||
.curve = DTLS_ECDH_CURVE_SECP256R1,
|
||||
.priv_key = ecdsa_priv_key,
|
||||
.pub_key_x = ecdsa_pub_key_x,
|
||||
.pub_key_y = ecdsa_pub_key_y
|
||||
};
|
||||
|
||||
*result = &ecdsa_key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
verify_ecdsa_key(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const unsigned char *other_pub_x,
|
||||
const unsigned char *other_pub_y,
|
||||
size_t key_size) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* DTLS_ECC */
|
||||
|
||||
#define DTLS_SERVER_CMD_CLOSE "server:close"
|
||||
#define DTLS_SERVER_CMD_RENEGOTIATE "server:renegotiate"
|
||||
|
||||
static int
|
||||
read_from_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%c", data[i]);
|
||||
if (len >= strlen(DTLS_SERVER_CMD_CLOSE) &&
|
||||
!memcmp(data, DTLS_SERVER_CMD_CLOSE, strlen(DTLS_SERVER_CMD_CLOSE))) {
|
||||
printf("server: closing connection\n");
|
||||
dtls_close(ctx, session);
|
||||
return len;
|
||||
} else if (len >= strlen(DTLS_SERVER_CMD_RENEGOTIATE) &&
|
||||
!memcmp(data, DTLS_SERVER_CMD_RENEGOTIATE, strlen(DTLS_SERVER_CMD_RENEGOTIATE))) {
|
||||
printf("server: renegotiate connection\n");
|
||||
dtls_renegotiate(ctx, session);
|
||||
return len;
|
||||
}
|
||||
|
||||
return dtls_write(ctx, session, data, len);
|
||||
}
|
||||
|
||||
static int
|
||||
send_to_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len) {
|
||||
|
||||
int fd = *(int *)dtls_get_app_data(ctx);
|
||||
return sendto(fd, data, len, MSG_DONTWAIT,
|
||||
&session->addr.sa, session->size);
|
||||
}
|
||||
|
||||
static int
|
||||
dtls_handle_read(struct dtls_context_t *ctx) {
|
||||
int *fd;
|
||||
session_t session;
|
||||
static uint8 buf[DTLS_MAX_BUF];
|
||||
int len;
|
||||
|
||||
fd = dtls_get_app_data(ctx);
|
||||
|
||||
assert(fd);
|
||||
|
||||
memset(&session, 0, sizeof(session_t));
|
||||
session.size = sizeof(session.addr);
|
||||
len = recvfrom(*fd, buf, sizeof(buf), MSG_TRUNC,
|
||||
&session.addr.sa, &session.size);
|
||||
|
||||
if (len < 0) {
|
||||
perror("recvfrom");
|
||||
return -1;
|
||||
} else {
|
||||
dtls_debug("got %d bytes from port %d\n", len,
|
||||
ntohs(session.addr.sin6.sin6_port));
|
||||
if (sizeof(buf) < len) {
|
||||
dtls_warn("packet was truncated (%d bytes lost)\n", len - sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
return dtls_handle_message(ctx, &session, buf, len);
|
||||
}
|
||||
|
||||
static int
|
||||
resolve_address(const char *server, struct sockaddr *dst) {
|
||||
|
||||
struct addrinfo *res, *ainfo;
|
||||
struct addrinfo hints;
|
||||
static char addrstr[256];
|
||||
int error;
|
||||
|
||||
memset(addrstr, 0, sizeof(addrstr));
|
||||
if (server && strlen(server) > 0)
|
||||
memcpy(addrstr, server, strlen(server));
|
||||
else
|
||||
memcpy(addrstr, "localhost", 9);
|
||||
|
||||
memset ((char *)&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
error = getaddrinfo(addrstr, "", &hints, &res);
|
||||
|
||||
if (error != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
|
||||
|
||||
switch (ainfo->ai_family) {
|
||||
case AF_INET6:
|
||||
|
||||
memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
return ainfo->ai_addrlen;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(const char *program, const char *version) {
|
||||
const char *p;
|
||||
|
||||
p = strrchr( program, '/' );
|
||||
if ( p )
|
||||
program = ++p;
|
||||
|
||||
fprintf(stderr, "%s v%s -- DTLS server implementation\n"
|
||||
"(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
|
||||
"usage: %s [-A address] [-p port] [-v num]\n"
|
||||
"\t-A address\t\tlisten on specified address (default is ::)\n"
|
||||
"\t-p port\t\tlisten on specified port (default is %d)\n"
|
||||
"\t-v num\t\tverbosity level (default: 3)\n",
|
||||
program, version, program, DEFAULT_PORT);
|
||||
}
|
||||
|
||||
static dtls_handler_t cb = {
|
||||
.write = send_to_peer,
|
||||
.read = read_from_peer,
|
||||
.event = NULL,
|
||||
#ifdef DTLS_PSK
|
||||
.get_psk_info = get_psk_info,
|
||||
#endif /* DTLS_PSK */
|
||||
#ifdef DTLS_ECC
|
||||
.get_ecdsa_key = get_ecdsa_key,
|
||||
.verify_ecdsa_key = verify_ecdsa_key
|
||||
#endif /* DTLS_ECC */
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
dtls_context_t *the_context = NULL;
|
||||
log_t log_level = DTLS_LOG_WARN;
|
||||
fd_set rfds, wfds;
|
||||
struct timeval timeout;
|
||||
int fd, opt, result;
|
||||
int on = 1;
|
||||
struct sockaddr_in6 listen_addr;
|
||||
|
||||
memset(&listen_addr, 0, sizeof(struct sockaddr_in6));
|
||||
|
||||
/* fill extra field for 4.4BSD-based systems (see RFC 3493, section 3.4) */
|
||||
#if defined(SIN6_LEN) || defined(HAVE_SOCKADDR_IN6_SIN6_LEN)
|
||||
listen_addr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
|
||||
listen_addr.sin6_family = AF_INET6;
|
||||
listen_addr.sin6_port = htons(DEFAULT_PORT);
|
||||
listen_addr.sin6_addr = in6addr_any;
|
||||
|
||||
while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'A' :
|
||||
if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) {
|
||||
fprintf(stderr, "cannot resolve address\n");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'p' :
|
||||
listen_addr.sin6_port = htons(atoi(optarg));
|
||||
break;
|
||||
case 'v' :
|
||||
log_level = strtol(optarg, NULL, 10);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], dtls_package_version());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
dtls_set_log_level(log_level);
|
||||
|
||||
/* init socket and set it to non-blocking */
|
||||
fd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
|
||||
|
||||
if (fd < 0) {
|
||||
dtls_alert("socket: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
|
||||
dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
|
||||
}
|
||||
#if 0
|
||||
flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
dtls_alert("fcntl: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
on = 1;
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
|
||||
#else /* IPV6_RECVPKTINFO */
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
|
||||
#endif /* IPV6_RECVPKTINFO */
|
||||
dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
|
||||
dtls_alert("bind: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
dtls_init();
|
||||
|
||||
the_context = dtls_new_context(&fd);
|
||||
|
||||
dtls_set_handler(the_context, &cb);
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
|
||||
FD_SET(fd, &rfds);
|
||||
/* FD_SET(fd, &wfds); */
|
||||
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
result = select( fd+1, &rfds, &wfds, 0, &timeout);
|
||||
|
||||
if (result < 0) { /* error */
|
||||
if (errno != EINTR)
|
||||
perror("select");
|
||||
} else if (result == 0) { /* timeout */
|
||||
} else { /* ok */
|
||||
if (FD_ISSET(fd, &wfds))
|
||||
;
|
||||
else if (FD_ISSET(fd, &rfds)) {
|
||||
dtls_handle_read(the_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
dtls_free_context(the_context);
|
||||
exit(0);
|
||||
}
|
123
tests/netq-test.c
Normal file
123
tests/netq-test.c
Normal file
@ -0,0 +1,123 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utlist.h"
|
||||
#include "netq.h"
|
||||
|
||||
void
|
||||
dump_queue(struct netq_t *queue) {
|
||||
struct netq_t *p;
|
||||
int i = 0;
|
||||
|
||||
if (!queue) {
|
||||
printf("(null)\n");
|
||||
} else {
|
||||
LL_FOREACH(queue, p) {
|
||||
printf("node #%d, timeout: %d\n", i++, p->t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct netq_t *nq = NULL, *node;
|
||||
int i;
|
||||
|
||||
clock_time_t timestamps[] = { 300, 100, 200, 400, 500 };
|
||||
|
||||
for (i = 0; i < sizeof(timestamps)/sizeof(clock_time_t); i++) {
|
||||
node = netq_node_new(0);
|
||||
|
||||
if (!node) {
|
||||
fprintf(stderr, "E: cannot create node #%d\n", i);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
node->t = timestamps[i];
|
||||
|
||||
if (!netq_insert_node(&nq, node)) {
|
||||
fprintf(stderr, "E: cannot add node to nodelist #%d\n", i);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("initial queue:\n");
|
||||
dump_queue(nq);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("pop first element:\n");
|
||||
node = netq_pop_first(&nq);
|
||||
|
||||
assert(node);
|
||||
printf("first node's timeout is %d\n", node->t);
|
||||
dump_queue(nq);
|
||||
|
||||
netq_node_free(node);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("queue head:\n");
|
||||
node = netq_head(&nq);
|
||||
|
||||
printf("head's timeout is %d\n", node->t);
|
||||
dump_queue(nq);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("next timeout:\n");
|
||||
|
||||
node = netq_next(node);
|
||||
|
||||
printf("next node's timeout is %d\n", node->t);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("remove next:\n");
|
||||
|
||||
netq_remove(&nq, node);
|
||||
dump_queue(nq);
|
||||
|
||||
netq_node_free(node);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("insert new item (timeout 50):\n");
|
||||
node = netq_node_new(0);
|
||||
|
||||
assert(node);
|
||||
node->t = 50;
|
||||
|
||||
netq_insert_node(&nq, node);
|
||||
dump_queue(nq);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("insert new item (timeout 350):\n");
|
||||
node = netq_node_new(0);
|
||||
|
||||
assert(node);
|
||||
node->t = 350;
|
||||
|
||||
netq_insert_node(&nq, node);
|
||||
dump_queue(nq);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("insert new item (timeout 1000):\n");
|
||||
node = netq_node_new(0);
|
||||
|
||||
assert(node);
|
||||
node->t = 1000;
|
||||
|
||||
netq_insert_node(&nq, node);
|
||||
dump_queue(nq);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("remove all:\n");
|
||||
|
||||
netq_delete_all(&nq);
|
||||
dump_queue(nq);
|
||||
|
||||
printf("------------------------------------------------------------------------\n");
|
||||
printf("pop first element of empty queue:\n");
|
||||
node = netq_pop_first(&nq);
|
||||
|
||||
assert(node == NULL);
|
||||
dump_queue(nq);
|
||||
|
||||
return 0;
|
||||
}
|
478
tests/pcap.c
Normal file
478
tests/pcap.c
Normal file
@ -0,0 +1,478 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <pcap/pcap.h>
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "debug.h"
|
||||
#include "dtls.h"
|
||||
|
||||
#define TRANSPORT_HEADER_SIZE (14+20+8) /* Ethernet + IP + UDP */
|
||||
|
||||
/* the pre_master_secret is generated from the PSK at startup */
|
||||
unsigned char pre_master_secret[60];
|
||||
size_t pre_master_len = 0;
|
||||
|
||||
unsigned char master_secret[DTLS_MASTER_SECRET_LENGTH];
|
||||
size_t master_secret_len = 0;
|
||||
|
||||
dtls_security_parameters_t security_params[2];
|
||||
int config = 0;
|
||||
unsigned int epoch[2] = { 0, 0 };
|
||||
|
||||
#if DTLS_VERSION == 0xfeff
|
||||
dtls_hash_t hs_hash[2];
|
||||
#elif DTLS_VERSION == 0xfefd
|
||||
dtls_hash_t hs_hash[1];
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
update_hash(uint8 *record, size_t rlength,
|
||||
uint8 *data, size_t data_length) {
|
||||
int i;
|
||||
|
||||
if (!hs_hash[0])
|
||||
return;
|
||||
|
||||
for (i = 0; i < sizeof(hs_hash) / sizeof(dtls_hash_t *); ++i) {
|
||||
dtls_hash_update(hs_hash[i], data, data_length);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
finalize_hash(uint8 *buf) {
|
||||
#if DTLS_VERSION == 0xfeff
|
||||
unsigned char statebuf[sizeof(md5_state_t) + sizeof(SHA_CTX)];
|
||||
#elif DTLS_VERSION == 0xfefd
|
||||
unsigned char statebuf[sizeof(SHA256_CTX)];
|
||||
#endif
|
||||
|
||||
if (!hs_hash[0])
|
||||
return;
|
||||
|
||||
/* temporarily store hash status for roll-back after finalize */
|
||||
#if DTLS_VERSION == 0xfeff
|
||||
memcpy(statebuf, hs_hash[0], sizeof(md5_state_t));
|
||||
memcpy(statebuf + sizeof(md5_state_t),
|
||||
hs_hash[1],
|
||||
sizeof(SHA_CTX));
|
||||
#elif DTLS_VERSION == 0xfefd
|
||||
memcpy(statebuf, hs_hash[0], sizeof(statebuf));
|
||||
#endif
|
||||
|
||||
dtls_hash_finalize(buf, hs_hash[0]);
|
||||
#if DTLS_VERSION == 0xfeff
|
||||
dtls_hash_finalize(buf + 16, hs_hash[1]);
|
||||
#endif
|
||||
|
||||
/* restore hash status */
|
||||
#if DTLS_VERSION == 0xfeff
|
||||
memcpy(hs_hash[0], statebuf, sizeof(md5_state_t));
|
||||
memcpy(hs_hash[1],
|
||||
statebuf + sizeof(md5_state_t),
|
||||
sizeof(SHA_CTX));
|
||||
#elif DTLS_VERSION == 0xfefd
|
||||
memcpy(hs_hash[0], statebuf, sizeof(statebuf));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
clear_hash() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(hs_hash) / sizeof(dtls_hash_t *); ++i)
|
||||
free(hs_hash[i]);
|
||||
memset(hs_hash, 0, sizeof(hs_hash));
|
||||
}
|
||||
|
||||
#undef CURRENT_CONFIG
|
||||
#undef OTHER_CONFIG
|
||||
#undef SWITCH_CONFIG
|
||||
#define CURRENT_CONFIG (&security_params[config])
|
||||
#define OTHER_CONFIG (&security_params[!(config & 0x01)])
|
||||
#define SWITCH_CONFIG (config = !(config & 0x01))
|
||||
|
||||
int
|
||||
pcap_verify(dtls_security_parameters_t *sec,
|
||||
int is_client,
|
||||
const unsigned char *record, size_t record_length,
|
||||
const unsigned char *cleartext, size_t cleartext_length) {
|
||||
|
||||
unsigned char mac[DTLS_HMAC_MAX];
|
||||
dtls_hmac_context_t hmac_ctx;
|
||||
int ok;
|
||||
|
||||
if (cleartext_length < dtls_kb_digest_size(sec))
|
||||
return 0;
|
||||
|
||||
dtls_hmac_init(&hmac_ctx,
|
||||
is_client
|
||||
? dtls_kb_client_mac_secret(sec)
|
||||
: dtls_kb_server_mac_secret(sec),
|
||||
dtls_kb_mac_secret_size(sec));
|
||||
|
||||
cleartext_length -= dtls_kb_digest_size(sec);
|
||||
|
||||
/* calculate MAC even if padding is wrong */
|
||||
dtls_mac(&hmac_ctx,
|
||||
record, /* the pre-filled record header */
|
||||
cleartext, cleartext_length,
|
||||
mac);
|
||||
|
||||
ok = memcmp(mac, cleartext + cleartext_length,
|
||||
dtls_kb_digest_size(sec)) == 0;
|
||||
#ifndef NDEBUG
|
||||
printf("MAC (%s): ", ok ? "valid" : "invalid");
|
||||
dump(mac, dtls_kb_digest_size(sec));
|
||||
printf("\n");
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
int
|
||||
decrypt_verify(int is_client, const uint8 *packet, size_t length,
|
||||
uint8 **cleartext, size_t *clen) {
|
||||
int res, ok = 0;
|
||||
dtls_cipher_context_t *cipher;
|
||||
|
||||
static unsigned char buf[1000];
|
||||
|
||||
switch (CURRENT_CONFIG->cipher) {
|
||||
case AES128: /* TLS_PSK_WITH_AES128_CBC_SHA */
|
||||
*cleartext = buf;
|
||||
*clen = length - sizeof(dtls_record_header_t);
|
||||
|
||||
if (is_client)
|
||||
cipher = CURRENT_CONFIG->read_cipher;
|
||||
else
|
||||
cipher = CURRENT_CONFIG->write_cipher;
|
||||
|
||||
res = dtls_decrypt(cipher,
|
||||
(uint8 *)packet + sizeof(dtls_record_header_t), *clen,
|
||||
buf, NULL, 0);
|
||||
|
||||
if (res < 0) {
|
||||
warn("decryption failed!\n");
|
||||
} else {
|
||||
ok = pcap_verify(CURRENT_CONFIG, is_client, (uint8 *)packet, length,
|
||||
*cleartext, res);
|
||||
|
||||
if (ok)
|
||||
*clen = res - dtls_kb_digest_size(CURRENT_CONFIG);
|
||||
}
|
||||
break;
|
||||
default: /* no cipher suite selected */
|
||||
*cleartext = (uint8 *)packet + sizeof(dtls_record_header_t);
|
||||
*clen = length - sizeof(dtls_record_header_t);
|
||||
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
printf("verify OK\n");
|
||||
else
|
||||
printf("verification failed!\n");
|
||||
return ok;
|
||||
}
|
||||
|
||||
#define SKIP_ETH_HEADER(M,L) \
|
||||
if ((L) < 14) \
|
||||
return; \
|
||||
else { \
|
||||
(M) += 14; \
|
||||
(L) -= 14; \
|
||||
}
|
||||
|
||||
#define SKIP_IP_HEADER(M,L) \
|
||||
if (((M)[0] & 0xF0) == 0x40) { /* IPv4 */ \
|
||||
(M) += (M[0] & 0x0F) * 4; \
|
||||
(L) -= (M[0] & 0x0F) * 4; \
|
||||
} else \
|
||||
if (((M)[0] & 0xF0) == 0x60) { /* IPv6 */ \
|
||||
(M) += 40; \
|
||||
(L) -= 40; \
|
||||
}
|
||||
|
||||
#define SKIP_UDP_HEADER(M,L) { \
|
||||
(M) += 8; \
|
||||
(L) -= 8; \
|
||||
}
|
||||
|
||||
void
|
||||
handle_packet(const u_char *packet, int length) {
|
||||
static int n = 0;
|
||||
static unsigned char initial_hello[] = {
|
||||
0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
uint8 *data;
|
||||
size_t data_length, rlen;
|
||||
int i, res;
|
||||
#if DTLS_VERSION == 0xfeff
|
||||
#ifndef SHA1_DIGEST_LENGTH
|
||||
#define SHA1_DIGEST_LENGTH 20
|
||||
#endif
|
||||
uint8 hash_buf[16 + SHA1_DIGEST_LENGTH];
|
||||
#elif DTLS_VERSION == 0xfefd
|
||||
uint8 hash_buf[SHA256_DIGEST_LENGTH];
|
||||
#endif
|
||||
#define verify_data_length 12
|
||||
int is_client;
|
||||
n++;
|
||||
|
||||
SKIP_ETH_HEADER(packet, length);
|
||||
SKIP_IP_HEADER(packet, length);
|
||||
|
||||
/* determine from port if this is a client */
|
||||
is_client = dtls_uint16_to_int(packet) != 20220;
|
||||
|
||||
SKIP_UDP_HEADER(packet, length);
|
||||
|
||||
while (length) {
|
||||
rlen = dtls_uint16_to_int(packet + 11) + sizeof(dtls_record_header_t);
|
||||
|
||||
if (!rlen) {
|
||||
fprintf(stderr, "invalid length!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* skip packet if it is from a different epoch */
|
||||
if (dtls_uint16_to_int(packet + 3) != epoch[is_client])
|
||||
goto next;
|
||||
|
||||
res = decrypt_verify(is_client, packet, rlen,
|
||||
&data, &data_length);
|
||||
|
||||
if (res <= 0)
|
||||
goto next;
|
||||
|
||||
printf("packet %d (from %s):\n", n, is_client ? "client" : "server");
|
||||
hexdump(packet, sizeof(dtls_record_header_t));
|
||||
printf("\n");
|
||||
hexdump(data, data_length);
|
||||
printf("\n");
|
||||
|
||||
if (packet[0] == 22 && data[0] == 1) { /* ClientHello */
|
||||
if (memcmp(packet, initial_hello, sizeof(initial_hello)) == 0)
|
||||
goto next;
|
||||
|
||||
memcpy(dtls_kb_client_iv(OTHER_CONFIG), data + 14, 32);
|
||||
|
||||
clear_hash();
|
||||
#if DTLS_VERSION == 0xfeff
|
||||
hs_hash[0] = dtls_new_hash(HASH_MD5);
|
||||
hs_hash[1] = dtls_new_hash(HASH_SHA1);
|
||||
|
||||
hs_hash[0]->init(hs_hash[0]->data);
|
||||
hs_hash[1]->init(hs_hash[1]->data);
|
||||
#elif DTLS_VERSION == 0xfefd
|
||||
dtls_hash_init(hs_hash[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (packet[0] == 22 && data[0] == 2) { /* ServerHello */
|
||||
memcpy(dtls_kb_server_iv(OTHER_CONFIG), data + 14, 32);
|
||||
/* FIXME: search in ciphers */
|
||||
OTHER_CONFIG->cipher = TLS_PSK_WITH_AES_128_CCM_8;
|
||||
}
|
||||
|
||||
if (packet[0] == 20 && data[0] == 1) { /* ChangeCipherSpec */
|
||||
printf("client random: ");
|
||||
dump(dtls_kb_client_iv(OTHER_CONFIG), 32);
|
||||
printf("\nserver random: ");
|
||||
dump(dtls_kb_server_iv(OTHER_CONFIG), 32);
|
||||
printf("\n");
|
||||
master_secret_len =
|
||||
dtls_prf(pre_master_secret, pre_master_len,
|
||||
(unsigned char *)"master secret", 13,
|
||||
dtls_kb_client_iv(OTHER_CONFIG), 32,
|
||||
dtls_kb_server_iv(OTHER_CONFIG), 32,
|
||||
master_secret, DTLS_MASTER_SECRET_LENGTH);
|
||||
|
||||
printf("master_secret:\n ");
|
||||
for(i = 0; i < master_secret_len; i++)
|
||||
printf("%02x", master_secret[i]);
|
||||
printf("\n");
|
||||
|
||||
/* create key_block from master_secret
|
||||
* key_block = PRF(master_secret,
|
||||
"key expansion" + server_random + client_random) */
|
||||
dtls_prf(master_secret, master_secret_len,
|
||||
(unsigned char *)"key expansion", 13,
|
||||
dtls_kb_server_iv(OTHER_CONFIG), 32,
|
||||
dtls_kb_client_iv(OTHER_CONFIG), 32,
|
||||
OTHER_CONFIG->key_block,
|
||||
dtls_kb_size(OTHER_CONFIG));
|
||||
|
||||
OTHER_CONFIG->read_cipher =
|
||||
dtls_cipher_new(OTHER_CONFIG->cipher,
|
||||
dtls_kb_client_write_key(OTHER_CONFIG),
|
||||
dtls_kb_key_size(OTHER_CONFIG));
|
||||
|
||||
if (!OTHER_CONFIG->read_cipher) {
|
||||
warn("cannot create read cipher\n");
|
||||
} else {
|
||||
dtls_cipher_set_iv(OTHER_CONFIG->read_cipher,
|
||||
dtls_kb_client_iv(OTHER_CONFIG),
|
||||
dtls_kb_iv_size(OTHER_CONFIG));
|
||||
}
|
||||
|
||||
OTHER_CONFIG->write_cipher =
|
||||
dtls_cipher_new(OTHER_CONFIG->cipher,
|
||||
dtls_kb_server_write_key(OTHER_CONFIG),
|
||||
dtls_kb_key_size(OTHER_CONFIG));
|
||||
|
||||
if (!OTHER_CONFIG->write_cipher) {
|
||||
warn("cannot create write cipher\n");
|
||||
} else {
|
||||
dtls_cipher_set_iv(OTHER_CONFIG->write_cipher,
|
||||
dtls_kb_server_iv(OTHER_CONFIG),
|
||||
dtls_kb_iv_size(OTHER_CONFIG));
|
||||
}
|
||||
|
||||
/* if (is_client) */
|
||||
SWITCH_CONFIG;
|
||||
epoch[is_client]++;
|
||||
|
||||
printf("key_block:\n");
|
||||
printf(" client_MAC_secret:\t");
|
||||
dump(dtls_kb_client_mac_secret(CURRENT_CONFIG),
|
||||
dtls_kb_mac_secret_size(CURRENT_CONFIG));
|
||||
printf("\n");
|
||||
|
||||
printf(" server_MAC_secret:\t");
|
||||
dump(dtls_kb_server_mac_secret(CURRENT_CONFIG),
|
||||
dtls_kb_mac_secret_size(CURRENT_CONFIG));
|
||||
printf("\n");
|
||||
|
||||
printf(" client_write_key:\t");
|
||||
dump(dtls_kb_client_write_key(CURRENT_CONFIG),
|
||||
dtls_kb_key_size(CURRENT_CONFIG));
|
||||
printf("\n");
|
||||
|
||||
printf(" server_write_key:\t");
|
||||
dump(dtls_kb_server_write_key(CURRENT_CONFIG),
|
||||
dtls_kb_key_size(CURRENT_CONFIG));
|
||||
printf("\n");
|
||||
|
||||
printf(" client_IV:\t\t");
|
||||
dump(dtls_kb_client_iv(CURRENT_CONFIG),
|
||||
dtls_kb_iv_size(CURRENT_CONFIG));
|
||||
printf("\n");
|
||||
|
||||
printf(" server_IV:\t\t");
|
||||
dump(dtls_kb_server_iv(CURRENT_CONFIG),
|
||||
dtls_kb_iv_size(CURRENT_CONFIG));
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
if (packet[0] == 22) {
|
||||
if (data[0] == 20) { /* Finished */
|
||||
finalize_hash(hash_buf);
|
||||
/* clear_hash(); */
|
||||
|
||||
update_hash((unsigned char *)packet, sizeof(dtls_record_header_t),
|
||||
data, data_length);
|
||||
|
||||
dtls_prf(master_secret, master_secret_len,
|
||||
is_client
|
||||
? (unsigned char *)"client finished"
|
||||
: (unsigned char *)"server finished"
|
||||
, 15,
|
||||
hash_buf, sizeof(hash_buf),
|
||||
NULL, 0,
|
||||
data + sizeof(dtls_handshake_header_t),
|
||||
verify_data_length);
|
||||
printf("verify_data:\n");
|
||||
dump(data, data_length);
|
||||
printf("\n");
|
||||
} else {
|
||||
update_hash((unsigned char *)packet, sizeof(dtls_record_header_t),
|
||||
data, data_length);
|
||||
}
|
||||
}
|
||||
|
||||
if (packet[0] == 23) { /* Application Data */
|
||||
printf("Application Data:\n");
|
||||
dump(data, data_length);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
next:
|
||||
length -= rlen;
|
||||
packet += rlen;
|
||||
}
|
||||
}
|
||||
|
||||
void init() {
|
||||
memset(security_params, 0, sizeof(security_params));
|
||||
CURRENT_CONFIG->cipher = -1;
|
||||
|
||||
memset(hs_hash, 0, sizeof(hs_hash));
|
||||
|
||||
/* set pre_master_secret to default if no PSK was given */
|
||||
if (!pre_master_len) {
|
||||
/* unsigned char psk[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; */
|
||||
pre_master_len =
|
||||
dtls_pre_master_secret((unsigned char *)"secretPSK", 9,
|
||||
pre_master_secret);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pcap_t *pcap;
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
struct pcap_pkthdr *pkthdr;
|
||||
const u_char *packet;
|
||||
int res = 0;
|
||||
int c, option_index = 0;
|
||||
|
||||
static struct option opts[] = {
|
||||
{ "psk", 1, 0, 'p' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* handle command line options */
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, "p:", opts, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'p':
|
||||
pre_master_len = dtls_pre_master_secret((unsigned char *)optarg,
|
||||
strlen(optarg), pre_master_secret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc <= optind) {
|
||||
fprintf(stderr, "usage: %s [-p|--psk PSK] pcapfile\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
pcap = pcap_open_offline(argv[optind], errbuf);
|
||||
if (!pcap) {
|
||||
fprintf(stderr, "pcap_open_offline: %s\n", errbuf);
|
||||
return -2;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
res = pcap_next_ex(pcap, &pkthdr, &packet);
|
||||
|
||||
switch(res) {
|
||||
case -2: goto done;
|
||||
case -1: pcap_perror(pcap, "read packet"); break;
|
||||
case 1: handle_packet(packet, pkthdr->caplen); break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
done:
|
||||
|
||||
pcap_close(pcap);
|
||||
|
||||
return 0;
|
||||
}
|
31
tests/prf-test.c
Normal file
31
tests/prf-test.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tinydtls.h"
|
||||
#include "debug.h"
|
||||
#include "global.h"
|
||||
#include "crypto.h"
|
||||
|
||||
int
|
||||
main() {
|
||||
/* see http://www.ietf.org/mail-archive/web/tls/current/msg03416.html */
|
||||
unsigned char key[] = { 0x9b, 0xbe, 0x43, 0x6b, 0xa9, 0x40, 0xf0, 0x17,
|
||||
0xb1, 0x76, 0x52, 0x84, 0x9a, 0x71, 0xdb, 0x35 };
|
||||
unsigned char label[] = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x61, 0x62,
|
||||
0x65, 0x6c};
|
||||
unsigned char random1[] = { 0xa0, 0xba, 0x9f, 0x93, 0x6c, 0xda, 0x31, 0x18};
|
||||
unsigned char random2[] = {0x27, 0xa6, 0xf7, 0x96, 0xff, 0xd5, 0x19, 0x8c
|
||||
};
|
||||
unsigned char buf[200];
|
||||
size_t result;
|
||||
|
||||
result = dtls_prf(key, sizeof(key),
|
||||
label, sizeof(label),
|
||||
random1, sizeof(random1),
|
||||
random2, sizeof(random2),
|
||||
buf, 100);
|
||||
|
||||
printf("PRF yields %zu bytes of random data:\n", result);
|
||||
hexdump(buf, result);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
862
tests/secure-server.c
Normal file
862
tests/secure-server.c
Normal file
@ -0,0 +1,862 @@
|
||||
/* secure-server -- A (broken) DTLS server example
|
||||
*
|
||||
* Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org>
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#ifdef WITH_DTLS
|
||||
#define SERVER_CERT_PEM "./server-cert.pem"
|
||||
#define SERVER_KEY_PEM "./server-key.pem"
|
||||
#define CA_CERT_PEM "./ca-cert.pem"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ASSERT_H
|
||||
# include <assert.h>
|
||||
#else
|
||||
# define assert(x)
|
||||
#endif /* HAVE_ASSERT_H */
|
||||
|
||||
static int quit=0;
|
||||
|
||||
/* SIGINT handler: set quit to 1 for graceful termination */
|
||||
void
|
||||
handle_sigint(int signum) {
|
||||
quit = 1;
|
||||
}
|
||||
|
||||
int
|
||||
check_connect(int sockfd, char *buf, int buflen,
|
||||
struct sockaddr *src, int *ifindex) {
|
||||
|
||||
/* for some reason, the definition in netinet/in.h is not exported */
|
||||
#ifndef IN6_PKTINFO
|
||||
struct in6_pktinfo
|
||||
{
|
||||
struct in6_addr ipi6_addr; /* src/dst IPv6 address */
|
||||
unsigned int ipi6_ifindex; /* send/recv interface index */
|
||||
};
|
||||
#endif
|
||||
|
||||
size_t bytes;
|
||||
|
||||
struct iovec iov[1] = { {buf, buflen} };
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
struct in6_pktinfo *p = NULL;
|
||||
|
||||
struct msghdr msg = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
msg.msg_name = src;
|
||||
msg.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
|
||||
bytes = recvmsg(sockfd, &msg, MSG_DONTWAIT | MSG_PEEK);
|
||||
if (bytes < 0) {
|
||||
perror("recvmsg");
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* TODO: handle msg.msg_flags & MSG_TRUNC */
|
||||
if (msg.msg_flags & MSG_CTRUNC) {
|
||||
fprintf(stderr, "control was truncated!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ifindex) {
|
||||
/* Here we try to retrieve the interface index where the packet was received */
|
||||
*ifindex = 0;
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
|
||||
p = (struct in6_pktinfo *)(CMSG_DATA(cmsg));
|
||||
*ifindex = p->ipi6_ifindex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
typedef enum { UNKNOWN=0, DTLS=1 } protocol_t;
|
||||
|
||||
protocol_t
|
||||
demux_protocol(const char *buf, int len) {
|
||||
return DTLS;
|
||||
}
|
||||
|
||||
#ifdef WITH_DTLS
|
||||
typedef enum {
|
||||
PEER_ST_ESTABLISHED, PEER_ST_PENDING, PEER_ST_CLOSED
|
||||
} peer_state_t;
|
||||
typedef struct {
|
||||
peer_state_t state;
|
||||
unsigned long h;
|
||||
SSL *ssl;
|
||||
} ssl_peer_t;
|
||||
|
||||
#define MAX_SSL_PENDING 2 /* must be less than MAX_SSL_PEERS */
|
||||
#define MAX_SSL_PEERS 10 /* MAX_SSL_PENDING of these might be pending */
|
||||
ssl_peer_t *ssl_peer_storage[MAX_SSL_PEERS];
|
||||
static int pending = 0;
|
||||
|
||||
void
|
||||
check_peers() {
|
||||
typedef struct bio_dgram_data_st
|
||||
{
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sa_in;
|
||||
struct sockaddr_in6 sa_in6;
|
||||
} peer;
|
||||
unsigned int connected;
|
||||
unsigned int _errno;
|
||||
unsigned int mtu;
|
||||
struct timeval next_timeout;
|
||||
struct timeval socket_timeout;
|
||||
} bio_dgram_data;
|
||||
|
||||
struct sockaddr_in6 peer;
|
||||
int i;
|
||||
BIO *bio;
|
||||
for (i = 0; i < MAX_SSL_PEERS; i++) {
|
||||
if (ssl_peer_storage[i]) {
|
||||
if (!ssl_peer_storage[i]->ssl)
|
||||
fprintf(stderr, "invalid SSL object for peer %d!\n",i);
|
||||
else {
|
||||
bio = SSL_get_rbio(ssl_peer_storage[i]->ssl);
|
||||
if (bio) {
|
||||
(void) BIO_dgram_get_peer(bio, (struct sockaddr *)&peer);
|
||||
if (peer.sin6_port && ssl_peer_storage[i]->h != ntohs(peer.sin6_port)) {
|
||||
fprintf(stderr, " bio %p: port differs from hash: %d != %d! (%sconnected)\n", bio,
|
||||
ssl_peer_storage[i]->h,
|
||||
ntohs(((struct sockaddr_in6 *)&peer)->sin6_port),
|
||||
((bio_dgram_data *)bio->ptr)->connected ? "" : "not ");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a hash value from the first num bytes of s, taking init as
|
||||
* initialization value. */
|
||||
static inline unsigned long
|
||||
_hash(unsigned long init, const char *s, int num) {
|
||||
int c;
|
||||
|
||||
while (num--)
|
||||
while ( (c = *s++) ) {
|
||||
init = ((init << 7) + init) + c;
|
||||
}
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
hash_peer(const struct sockaddr *peer, int ifindex) {
|
||||
unsigned long h;
|
||||
|
||||
/* initialize hash value to interface index */
|
||||
h = _hash(0, (char *)&ifindex, sizeof(int));
|
||||
|
||||
#define CAST(TYPE,VAR) ((TYPE)VAR)
|
||||
|
||||
assert(peer);
|
||||
switch (peer->sa_family) {
|
||||
case AF_INET:
|
||||
return ntohs(CAST(const struct sockaddr_in *, peer)->sin_port);
|
||||
h = _hash(h, (char *) &CAST(const struct sockaddr_in *, peer)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
h = _hash(h, (char *) &CAST(const struct sockaddr_in *, peer)->sin_port,
|
||||
sizeof(in_port_t));
|
||||
break;
|
||||
case AF_INET6:
|
||||
return ntohs(CAST(const struct sockaddr_in6 *, peer)->sin6_port);
|
||||
h = _hash(h,
|
||||
(char *) &CAST(const struct sockaddr_in6 *, peer)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
h = _hash(h,
|
||||
(char *) &CAST(const struct sockaddr_in6 *, peer)->sin6_port,
|
||||
sizeof(in_port_t));
|
||||
break;
|
||||
default:
|
||||
/* last resort */
|
||||
h = _hash(h, (char *)peer, sizeof(struct sockaddr));
|
||||
}
|
||||
|
||||
return 42;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Returns index of peer object for specified address/ifindex pair. */
|
||||
int
|
||||
get_index_of_peer(const struct sockaddr *peer, int ifindex) {
|
||||
unsigned long h;
|
||||
int idx;
|
||||
#ifndef NDEBUG
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
char port[6];
|
||||
#endif
|
||||
|
||||
if (!peer)
|
||||
return -1;
|
||||
|
||||
h = hash_peer(peer,ifindex);
|
||||
|
||||
for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
|
||||
if (ssl_peer_storage[idx] && ssl_peer_storage[idx]->h == h) {
|
||||
#ifndef NDEBUG
|
||||
getnameinfo((struct sockaddr *)peer, sizeof(struct sockaddr_in6),
|
||||
addr, sizeof(addr), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
fprintf(stderr, "get_index_of_peer: [%s]:%s => %lu\n",
|
||||
addr, port, h);
|
||||
#endif
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL *
|
||||
get_ssl(SSL_CTX *ctx, int sockfd, struct sockaddr *src, int ifindex) {
|
||||
int idx;
|
||||
BIO *bio;
|
||||
SSL *ssl;
|
||||
#ifndef NDEBUG
|
||||
struct sockaddr_storage peer;
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
char port[6];
|
||||
int i;
|
||||
#endif
|
||||
|
||||
idx = get_index_of_peer(src,ifindex);
|
||||
if (idx >= 0) {
|
||||
fprintf(stderr,"found peer %d ",idx);
|
||||
switch (ssl_peer_storage[idx]->state) {
|
||||
case PEER_ST_ESTABLISHED: fprintf(stderr,"established\n"); break;
|
||||
case PEER_ST_PENDING: fprintf(stderr,"pending\n"); break;
|
||||
case PEER_ST_CLOSED: fprintf(stderr,"closed\n"); break;
|
||||
default:
|
||||
OPENSSL_assert(0);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
memset(&peer, 0, sizeof(peer));
|
||||
(void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[idx]->ssl), &peer);
|
||||
|
||||
getnameinfo((struct sockaddr *)&peer, sizeof(peer),
|
||||
addr, sizeof(addr), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
fprintf(stderr," [%s]:%s \n", addr, port);
|
||||
#endif
|
||||
return ssl_peer_storage[idx]->ssl;
|
||||
}
|
||||
|
||||
/* none found, create new if sufficient space available */
|
||||
if (pending < MAX_SSL_PENDING) {
|
||||
for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
|
||||
if (ssl_peer_storage[idx] == NULL) { /* found space */
|
||||
ssl = SSL_new(ctx);
|
||||
|
||||
if (ssl) {
|
||||
bio = BIO_new_dgram(sockfd, BIO_NOCLOSE);
|
||||
if (!bio) {
|
||||
SSL_free(ssl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL_set_bio(ssl, bio, bio);
|
||||
SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
|
||||
|
||||
SSL_set_accept_state(ssl);
|
||||
ssl_peer_storage[idx] = (ssl_peer_t *) malloc(sizeof(ssl_peer_t));
|
||||
if (!ssl_peer_storage[idx]) {
|
||||
SSL_free(ssl);
|
||||
return NULL;
|
||||
}
|
||||
ssl_peer_storage[idx]->state = PEER_ST_PENDING;
|
||||
ssl_peer_storage[idx]->h = hash_peer(src,ifindex);
|
||||
ssl_peer_storage[idx]->ssl = ssl;
|
||||
|
||||
pending++;
|
||||
|
||||
fprintf(stderr,
|
||||
"created new SSL peer %d for ssl object %p (storage: %p)\n",
|
||||
idx, ssl, ssl_peer_storage[idx]);
|
||||
#ifndef NDEBUG
|
||||
if (getnameinfo((struct sockaddr *)&src, sizeof(src),
|
||||
addr, sizeof(addr), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
|
||||
perror("getnameinfo");
|
||||
fprintf(stderr, "port was %u\n", ntohs(((struct sockaddr_in6 *)src)->sin6_port));
|
||||
} else {
|
||||
fprintf(stderr," [%s]:%s \n", addr, port);
|
||||
}
|
||||
#endif
|
||||
OPENSSL_assert(ssl_peer_storage[idx]->ssl == ssl);
|
||||
fprintf(stderr,"%d objects pending\n", pending);
|
||||
check_peers();
|
||||
return ssl;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "too many pending SSL objects\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fprintf(stderr, "too many peers\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Deletes peer stored at index idx and frees allocated memory. */
|
||||
static inline void
|
||||
delete_peer(int idx) {
|
||||
if (idx < 0 || !ssl_peer_storage[idx])
|
||||
return;
|
||||
|
||||
if (ssl_peer_storage[idx]->state == PEER_ST_PENDING)
|
||||
pending--;
|
||||
|
||||
OPENSSL_assert(ssl_peer_storage[idx]->ssl);
|
||||
SSL_free(ssl_peer_storage[idx]->ssl);
|
||||
|
||||
free(ssl_peer_storage[idx]);
|
||||
ssl_peer_storage[idx] = NULL;
|
||||
|
||||
printf("deleted peer %d\n",idx);
|
||||
}
|
||||
|
||||
/** Deletes all closed objects from ssl_peer_storage. */
|
||||
void
|
||||
remove_closed() {
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < MAX_SSL_PEERS; idx++)
|
||||
if (ssl_peer_storage[idx]
|
||||
&& ssl_peer_storage[idx]->state == PEER_ST_CLOSED)
|
||||
delete_peer(idx);
|
||||
}
|
||||
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
unsigned int
|
||||
psk_server_callback(SSL *ssl, const char *identity,
|
||||
unsigned char *psk, unsigned int max_psk_len) {
|
||||
static char keybuf[] = "secretPSK";
|
||||
|
||||
printf("psk_server_callback: check identity of client %s\n", identity);
|
||||
memcpy(psk, keybuf, min(strlen(keybuf), max_psk_len));
|
||||
|
||||
return min(strlen(keybuf), max_psk_len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WITH_DTLS
|
||||
/**
|
||||
* This function tracks the status changes from libssl to manage local
|
||||
* object state.
|
||||
*/
|
||||
void
|
||||
info_callback(const SSL *ssl, int where, int ret) {
|
||||
int idx, i;
|
||||
struct sockaddr_storage peer;
|
||||
struct sockaddr_storage peer2;
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
char port[6];
|
||||
|
||||
if (where & SSL_CB_LOOP) /* do not care for intermediary states */
|
||||
return;
|
||||
|
||||
memset(&peer, 0, sizeof(peer));
|
||||
(void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
|
||||
|
||||
/* lookup SSL object */ /* FIXME: need to get the ifindex */
|
||||
idx = get_index_of_peer((struct sockaddr *)&peer, 0);
|
||||
|
||||
if (idx >= 0)
|
||||
fprintf(stderr, "info_callback: assert: %d < 0 || %p == %p (storage: %p)\n",
|
||||
idx, ssl, ssl_peer_storage[idx]->ssl, ssl_peer_storage[idx]);
|
||||
if (idx >= 0 && ssl != ssl_peer_storage[idx]->ssl) {
|
||||
getnameinfo((struct sockaddr *)&peer, sizeof(peer),
|
||||
addr, sizeof(addr), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
fprintf(stderr," ssl: [%s]:%s ", addr, port);
|
||||
|
||||
(void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[idx]->ssl), &peer2);
|
||||
getnameinfo((struct sockaddr *)&peer2, sizeof(peer2),
|
||||
addr, sizeof(addr), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
fprintf(stderr," ssl_peer_storage[idx]->ssl: [%s]:%s\n", addr, port);
|
||||
|
||||
fprintf(stderr, " hash:%lu h: %lu\n",
|
||||
hash_peer((const struct sockaddr *)&peer, 0),
|
||||
ssl_peer_storage[idx]->h);
|
||||
|
||||
for (i = 0; i < MAX_SSL_PEERS; i++) {
|
||||
if (ssl_peer_storage[i]) {
|
||||
fprintf(stderr, "%02d: %p ssl: %p ",
|
||||
i, ssl_peer_storage[i] ,ssl_peer_storage[i]->ssl);
|
||||
|
||||
(void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[i]->ssl), &peer2);
|
||||
getnameinfo((struct sockaddr *)&peer2, sizeof(peer2),
|
||||
addr, sizeof(addr), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
fprintf(stderr," peer: [%s]:%s h: %lu\n", addr, port, ssl_peer_storage[i]->h);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "***** ASSERT FAILED ******\n");
|
||||
|
||||
memset(&peer, 0, sizeof(peer));
|
||||
(void) BIO_dgram_get_peer(SSL_get_wbio(ssl), &peer);
|
||||
|
||||
idx = get_index_of_peer((struct sockaddr *)&peer, 0);
|
||||
fprintf(stderr, " get_index_of_peer for wbio returns %d, type is %04x\n",
|
||||
idx, where);
|
||||
}
|
||||
#if 1
|
||||
check_peers();
|
||||
OPENSSL_assert((idx < 0) || (ssl == ssl_peer_storage[idx]->ssl));
|
||||
#endif
|
||||
|
||||
if (where & SSL_CB_ALERT) {
|
||||
#ifndef NDEBUG
|
||||
if (ret != 0)
|
||||
fprintf(stderr,"%s:%s:%s\n", SSL_alert_type_string(ret),
|
||||
SSL_alert_desc_string(ret), SSL_alert_desc_string_long(ret));
|
||||
#endif
|
||||
|
||||
/* examine alert type */
|
||||
switch (*SSL_alert_type_string(ret)) {
|
||||
case 'F':
|
||||
/* move SSL object from pending to close */
|
||||
if (idx >= 0) {
|
||||
ssl_peer_storage[idx]->state = PEER_ST_CLOSED;
|
||||
pending--;
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
if ((ret & 0xff) == SSL_AD_CLOSE_NOTIFY) {
|
||||
if (where == SSL_CB_WRITE_ALERT)
|
||||
fprintf(stderr,"sent CLOSE_NOTIFY\n");
|
||||
else /* received CN */
|
||||
fprintf(stderr,"received CLOSE_NOTIFY\n");
|
||||
}
|
||||
break;
|
||||
default: /* handle unknown alert types */
|
||||
#ifndef NDEBUG
|
||||
printf("not handled!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (where & SSL_CB_HANDSHAKE_DONE) {
|
||||
/* move SSL object from pending to established */
|
||||
printf("HANDSHAKE_DONE ");
|
||||
if (idx >= 0) {
|
||||
|
||||
if (ssl_peer_storage[idx]->state == PEER_ST_PENDING) {
|
||||
ssl_peer_storage[idx]->state = PEER_ST_ESTABLISHED;
|
||||
pending--;
|
||||
printf("moved SSL object %d to ESTABLISHED\n", idx);
|
||||
printf("%d objects pending\n", pending);
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
printf("huh, object %d was not pending? (%d)\n", idx,
|
||||
ssl_peer_storage[idx]->state);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_DTLS
|
||||
/* checks if ssl object was closed and can be removed */
|
||||
int
|
||||
check_close(SSL *ssl) {
|
||||
int res, err, idx;
|
||||
struct sockaddr_storage peer;
|
||||
|
||||
memset(&peer, 0, sizeof(peer));
|
||||
(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
|
||||
|
||||
res = 0;
|
||||
if (SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) {
|
||||
printf("SSL_RECEIVED_SHUTDOWN\n");
|
||||
res = SSL_shutdown(ssl);
|
||||
if (res == 0) {
|
||||
printf("must call SSL_shutdown again\n");
|
||||
res = SSL_shutdown(ssl);
|
||||
}
|
||||
if (res < 0) {
|
||||
err = SSL_get_error(ssl,res);
|
||||
fprintf(stderr, "shutdown: SSL error %d: %s\n", err,
|
||||
ERR_error_string(err, NULL));
|
||||
}
|
||||
|
||||
/* we can close the SSL object anyway */
|
||||
/* FIXME: need to get ifindex from somewhere */
|
||||
idx = get_index_of_peer((struct sockaddr *)&peer, 0);
|
||||
OPENSSL_assert(idx < 0 || ssl == ssl_peer_storage[idx]->ssl);
|
||||
if (idx >= 0) {
|
||||
ssl_peer_storage[idx]->state = PEER_ST_CLOSED;
|
||||
printf("moved SSL object %d to CLOSED\n",idx);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
check_timeout() {
|
||||
int i, result, err;
|
||||
|
||||
for (i = 0; i < MAX_SSL_PEERS; i++) {
|
||||
if (ssl_peer_storage[i]) {
|
||||
OPENSSL_assert(ssl_peer_storage[i]->ssl);
|
||||
result = DTLSv1_handle_timeout(ssl_peer_storage[i]->ssl);
|
||||
if (result < 0) {
|
||||
err = SSL_get_error(ssl_peer_storage[i]->ssl,result);
|
||||
fprintf(stderr, "dtls1_handle_timeout (%d): %s\n",
|
||||
err, ERR_error_string(err, NULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* remove outdated obbjects? */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_DTLS */
|
||||
|
||||
int
|
||||
_read(SSL_CTX *ctx, int sockfd) {
|
||||
char buf[2000];
|
||||
struct sockaddr_in6 src;
|
||||
int len, ifindex, i;
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
char port[6];
|
||||
socklen_t sz = sizeof(struct sockaddr_in6);
|
||||
#ifdef WITH_DTLS
|
||||
SSL *ssl;
|
||||
int err;
|
||||
#endif
|
||||
|
||||
/* Retrieve remote address and interface index as well as the first
|
||||
few bytes of the message to demultiplex protocols. */
|
||||
memset(&src, 0, sizeof(struct sockaddr_in6));
|
||||
len = check_connect(sockfd, buf, 4, (struct sockaddr *)&src, &ifindex);
|
||||
|
||||
if (len < 0) /* error */
|
||||
return len;
|
||||
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr,"received packet");
|
||||
|
||||
if (getnameinfo((struct sockaddr *)&src, sizeof(src),
|
||||
addr, sizeof(addr), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV) == 0)
|
||||
fprintf(stderr," from [%s]:%s", addr, port);
|
||||
|
||||
fprintf(stderr," on interface %d\n", ifindex);
|
||||
#endif
|
||||
|
||||
switch (demux_protocol(buf, len)) {
|
||||
#ifdef WITH_DTLS
|
||||
case DTLS :
|
||||
ssl = get_ssl(ctx, sockfd, (struct sockaddr *)&src, ifindex);
|
||||
if (!ssl) {
|
||||
fprintf(stderr, "cannot create new SSL object\n");
|
||||
/* return recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT);*/
|
||||
len = recvfrom(sockfd, buf, sizeof(buf), MSG_DONTWAIT,
|
||||
(struct sockaddr *)&src, &sz);
|
||||
getnameinfo((struct sockaddr *)&src, sz,
|
||||
addr, sizeof(addr), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
printf("discarded %d bytes from [%s]:%s\n", len, addr, port);
|
||||
return len;
|
||||
}
|
||||
len = SSL_read(ssl, buf, sizeof(buf));
|
||||
break;
|
||||
#endif
|
||||
case UNKNOWN:
|
||||
default :
|
||||
len = recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
printf("here is the data:\n");
|
||||
for (i=0; i<len; i++)
|
||||
printf("%c",buf[i]);
|
||||
} if (len == 0) { /* session closed? */
|
||||
#ifdef WITH_DTLS
|
||||
if (check_close(ssl) <= 0) {
|
||||
fprintf(stderr, "not closed\n");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#ifdef WITH_DTLS
|
||||
err = SSL_get_error(ssl,len);
|
||||
switch (err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
fprintf(stderr, "SSL_ERROR_WANT_READ\n");
|
||||
return 0;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
fprintf(stderr, "SSL_ERROR_WANT_WRITE\n");
|
||||
return 0;
|
||||
default:
|
||||
fprintf(stderr, "read: SSL error %d: %s\n", err,
|
||||
ERR_error_string(err, NULL));
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
perror("recv");
|
||||
#endif
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
_write(SSL_CTX *ctx, int sockfd) {
|
||||
int res = 0;
|
||||
#ifdef WITH_DTLS
|
||||
SSL *ssl;
|
||||
int err;
|
||||
|
||||
ssl = get_ssl(ctx, sockfd, NULL, 1);
|
||||
if (!ssl) {
|
||||
fprintf(stderr, "no SSL object for writing");
|
||||
return 0;
|
||||
}
|
||||
res = SSL_write(ssl, NULL, 0);
|
||||
if (res < 0) {
|
||||
/*
|
||||
if (SSL_want_write(ssl))
|
||||
return 0;
|
||||
*/
|
||||
/* FIXME: check SSL_want_read(ssl) */
|
||||
|
||||
err = SSL_get_error(ssl,res);
|
||||
fprintf(stderr,"SSL_write returned %d (%s)\n", err, ERR_error_string(err, NULL));
|
||||
} else {
|
||||
printf("SSL_write successful\n");
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len) {
|
||||
/* FIXME: generate secure client-specific cookie */
|
||||
#define DUMMYSTR "ABCDEFGHIJKLMNOP"
|
||||
*cookie_len = strlen(DUMMYSTR);
|
||||
memcpy(cookie, DUMMYSTR, *cookie_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
verify_cookie(SSL *ssl, unsigned char *cookie, unsigned int cookie_len) {
|
||||
/* FIXME */
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum { READ, WRITE };
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
int sockfd = 0;
|
||||
int on = 1;
|
||||
struct sockaddr_in6 listen_addr = { AF_INET6, htons(20220), 0, IN6ADDR_ANY_INIT, 0 };
|
||||
size_t addr_size = sizeof(struct sockaddr_in6);
|
||||
fd_set fds[2];
|
||||
int result, flags;
|
||||
int idx, res = 0;
|
||||
struct timeval timeout;
|
||||
struct sigaction act, oact;
|
||||
|
||||
#ifdef WITH_DTLS
|
||||
SSL_CTX *ctx;
|
||||
|
||||
memset(ssl_peer_storage, 0, sizeof(ssl_peer_storage));
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
ctx = SSL_CTX_new(DTLSv1_server_method());
|
||||
|
||||
SSL_CTX_set_cipher_list(ctx, "ALL");
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
||||
|
||||
res = SSL_CTX_use_certificate_file(ctx, SERVER_CERT_PEM, SSL_FILETYPE_PEM);
|
||||
if (res != 1) {
|
||||
fprintf(stderr, "cannot read server certificate from file '%s' (%s)\n",
|
||||
SERVER_CERT_PEM, ERR_error_string(res,NULL));
|
||||
goto end;
|
||||
}
|
||||
|
||||
res = SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY_PEM, SSL_FILETYPE_PEM);
|
||||
if (res != 1) {
|
||||
fprintf(stderr, "cannot read server key from file '%s' (%s)\n",
|
||||
SERVER_KEY_PEM, ERR_error_string(res,NULL));
|
||||
goto end;
|
||||
}
|
||||
|
||||
res = SSL_CTX_check_private_key (ctx);
|
||||
if (res != 1) {
|
||||
fprintf(stderr, "invalid private key\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
res = SSL_CTX_load_verify_locations(ctx, CA_CERT_PEM, NULL);
|
||||
if (res != 1) {
|
||||
fprintf(stderr, "cannot read ca file '%s'\n", CA_CERT_PEM);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Client has to authenticate */
|
||||
|
||||
/* Client has to authenticate */
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
|
||||
|
||||
SSL_CTX_set_read_ahead(ctx, 1); /* disable read-ahead */
|
||||
SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
|
||||
SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie);
|
||||
|
||||
SSL_CTX_use_psk_identity_hint(ctx, "Enter password for CoAP-Gateway");
|
||||
SSL_CTX_set_psk_server_callback(ctx, psk_server_callback);
|
||||
|
||||
SSL_CTX_set_info_callback(ctx, info_callback);
|
||||
#endif
|
||||
|
||||
sockfd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
|
||||
if ( sockfd < 0 ) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0)
|
||||
perror("setsockopt SO_REUSEADDR");
|
||||
|
||||
flags = fcntl(sockfd, F_GETFL, 0);
|
||||
if (flags < 0 || fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
perror("fcntl");
|
||||
return -1;
|
||||
}
|
||||
|
||||
on = 1;
|
||||
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
|
||||
perror("setsockopt IPV6_PKTINFO");
|
||||
}
|
||||
|
||||
if (bind (sockfd, (const struct sockaddr *)&listen_addr, addr_size) < 0) {
|
||||
perror("bind");
|
||||
res = -2;
|
||||
goto end;
|
||||
}
|
||||
|
||||
act.sa_handler = handle_sigint;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGINT, &act, &oact);
|
||||
|
||||
while (!quit) {
|
||||
FD_ZERO(&fds[READ]);
|
||||
FD_ZERO(&fds[WRITE]);
|
||||
FD_SET(sockfd, &fds[READ]);
|
||||
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
result = select( FD_SETSIZE, &fds[READ], &fds[WRITE], 0, &timeout);
|
||||
|
||||
if (result < 0) { /* error */
|
||||
if (errno != EINTR)
|
||||
perror("select");
|
||||
} else if (result > 0) { /* read from socket */
|
||||
if ( FD_ISSET( sockfd, &fds[READ]) ) {
|
||||
_read(ctx, sockfd); /* read received data */
|
||||
} else if ( FD_ISSET( sockfd, &fds[WRITE]) ) { /* write to socket */
|
||||
_write(ctx, sockfd); /* write data */
|
||||
}
|
||||
} else { /* timeout */
|
||||
check_timeout();
|
||||
}
|
||||
remove_closed();
|
||||
}
|
||||
|
||||
end:
|
||||
#ifdef WITH_DTLS
|
||||
for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
|
||||
if (ssl_peer_storage[idx] && ssl_peer_storage[idx]->ssl) {
|
||||
if (ssl_peer_storage[idx]->state == PEER_ST_ESTABLISHED)
|
||||
SSL_shutdown(ssl_peer_storage[idx]->ssl);
|
||||
SSL_free(ssl_peer_storage[idx]->ssl);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX_free(ctx);
|
||||
#endif
|
||||
close(sockfd); /* don't care if we close stdin at this point */
|
||||
return res;
|
||||
}
|
35
tinydtls.h.in
Normal file
35
tinydtls.h.in
Normal file
@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Olaf Bergmann - initial API and implementation
|
||||
* Hauke Mehrtens - memory optimization, ECC integration
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file tinydtls.h
|
||||
* @brief public tinydtls API
|
||||
*/
|
||||
|
||||
#ifndef _DTLS_TINYDTLS_H_
|
||||
#define _DTLS_TINYDTLS_H_
|
||||
|
||||
/** Defined to 1 if tinydtls is built with support for ECC */
|
||||
#undef DTLS_ECC
|
||||
|
||||
/** Defined to 1 if tinydtls is built with support for PSK */
|
||||
#undef DTLS_PSK
|
||||
|
||||
/** Defined to 1 if tinydtls is built for Contiki OS */
|
||||
#undef WITH_CONTIKI
|
||||
|
||||
#endif /* _DTLS_TINYDTLS_H_ */
|
Loading…
x
Reference in New Issue
Block a user