New initial commit

This commit is contained in:
Olaf Bergmann 2016-02-02 18:39:21 +01:00
commit e1388b3980
58 changed files with 13922 additions and 0 deletions

64
.gitignore vendored Normal file
View 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
View 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 Redistributors
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 Redistributors 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

184
doc/DoxygenLayout.xml Normal file
View 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
View 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)

4076
dtls.c Normal file

File diff suppressed because it is too large Load Diff

740
dtls.h Normal file
View 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
View 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
View 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
View File

@ -0,0 +1,7 @@
CONTIKI=../../..
APPS += ecc
CFLAGS += -DTEST_INCLUDE
include $(CONTIKI)/Makefile.include

3
ecc/Makefile.ecc Normal file
View File

@ -0,0 +1,3 @@
# This is a -*- Makefile -*-
ecc_src = ecc.c test_helper.c

81
ecc/Makefile.in Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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_ */

View 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:
:

View File

@ -0,0 +1,2 @@
#define BYTE_ORDER 1234
#define HAVE_ASSERT_H 1

View File

@ -0,0 +1,2 @@
#define BYTE_ORDER 1234
#define HAVE_ASSERT_H 1

View File

@ -0,0 +1 @@
#define HAVE_ASSERT_H 1

View File

@ -0,0 +1,3 @@
#define BYTE_ORDER 1234
#define HAVE_ASSERT_H 1
typedef int ssize_t;

View File

@ -0,0 +1 @@
#define HAVE_ASSERT_H 1

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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_ */