/* This is needed for apple */
#define __APPLE_USE_RFC_3542
+#include "iotivity_config.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
+#endif
#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
+#ifdef HAVE_NETDB_H
#include <netdb.h>
+#endif
#include <signal.h>
+#include <getopt.h>
+#include "platform_features.h"
-#include "tinydtls.h"
-#include "dtls.h"
-#include "debug.h"
+#include "tinydtls.h"
+#include "dtls.h"
+#include "debug.h"
+
+#ifdef DTLS_X509
+#define DTLS_PRIVATE_KEY_SIZE (32)
+#define DTLS_PUBLIC_KEY_SIZE (64)
+#endif
#define DEFAULT_PORT 20220
+/**
+ * @struct byte_array
+ *
+ * General purpose byte array structure.
+ *
+ * Contains pointer to array of bytes and it's length.
+ */
+
+typedef struct
+{
+ uint8_t *data; /**< Pointer to the byte array */
+ size_t len; /**< Data size */
+} byte_array;
+
+
+/**@def BYTE_ARRAY_INITIALIZER
+ *
+ * Initializes of existing byte array pointer to \a NULL.
+ */
+#undef BYTE_ARRAY_INITIALIZER
+#define BYTE_ARRAY_INITIALIZER {NULL, 0}
+
+#ifdef DTLS_X509
+#define X509_OPTIONS "x:r:u:"
+#define SERVER_CRT_LEN 295
+static const unsigned char g_server_certificate[SERVER_CRT_LEN] = {
+ 0x00, 0x01, 0x24,
+ 0x30, 0x82, 0x01, 0x20, 0x30, 0x81, 0xc4, 0xa0,
+ 0x03, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x37,
+ 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
+ 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x17,
+ 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x0c, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x20, 0x49, 0x53, 0x53, 0x55, 0x45, 0x52, 0x30,
+ 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x31, 0x30,
+ 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
+ 0x17, 0x0d, 0x34, 0x39, 0x30, 0x31, 0x30, 0x31,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30,
+ 0x17, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x0c, 0x0c, 0x4c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x20, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52,
+ 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
+ 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+ 0x42, 0x00, 0x04, 0x07, 0x88, 0x10, 0xdc, 0x62,
+ 0xd7, 0xe6, 0x9b, 0x7c, 0xad, 0x6e, 0x78, 0xb0,
+ 0x5f, 0x9a, 0x00, 0x11, 0x74, 0x2c, 0x8b, 0xaf,
+ 0x09, 0x65, 0x7c, 0x86, 0x8e, 0x55, 0xcb, 0x39,
+ 0x55, 0x72, 0xc6, 0x65, 0x71, 0xcd, 0x03, 0xdc,
+ 0x2a, 0x4f, 0x46, 0x5b, 0x14, 0xc8, 0x27, 0x74,
+ 0xab, 0xf4, 0x1f, 0xc1, 0x35, 0x0d, 0x42, 0xbc,
+ 0xc2, 0x9f, 0xb5, 0xc1, 0x79, 0xb6, 0x8b, 0xca,
+ 0xdb, 0xff, 0x82, 0x30, 0x0c, 0x06, 0x08, 0x2a,
+ 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05,
+ 0x00, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21,
+ 0x00, 0xb1, 0x81, 0x81, 0x92, 0x0e, 0x76, 0x7c,
+ 0xeb, 0xf5, 0x37, 0xde, 0x27, 0xc4, 0x01, 0xc8,
+ 0x96, 0xc3, 0xe5, 0x9f, 0x47, 0x7e, 0x25, 0x92,
+ 0xa4, 0xba, 0x22, 0x25, 0xa3, 0x81, 0x19, 0xcf,
+ 0x0d, 0x02, 0x21, 0x00, 0xca, 0x92, 0xbe, 0x79,
+ 0xc7, 0x82, 0x84, 0x64, 0xc4, 0xc4, 0xf4, 0x3d,
+ 0x69, 0x79, 0x68, 0xc0, 0xf1, 0xba, 0xaf, 0x6c,
+ 0xbb, 0xdd, 0x54, 0x7d, 0x07, 0xe7, 0x53, 0x3b,
+ 0xc3, 0x1b, 0x87, 0x04};
+
+//default server's key pair
+static const unsigned char x509_priv_key[] = {
+ 0xaa, 0xa3, 0x46, 0xf1, 0x3c, 0x56, 0x5d, 0x08,
+ 0x5e, 0x59, 0xba, 0x7f, 0xd2, 0x21, 0x62, 0xc6,
+ 0xcc, 0x5d, 0xfa, 0x3f, 0xb5, 0x25, 0xa9, 0x89,
+ 0x4f, 0x32, 0xe8, 0x2a, 0xe0, 0xee, 0x9b, 0x4c};
+
+static const unsigned char x509_pub_key_x[] = {
+ 0x07, 0x88, 0x10, 0xdc, 0x62, 0xd7, 0xe6, 0x9b,
+ 0x7c, 0xad, 0x6e, 0x78, 0xb0, 0x5f, 0x9a, 0x00,
+ 0x11, 0x74, 0x2c, 0x8b, 0xaf, 0x09, 0x65, 0x7c,
+ 0x86, 0x8e, 0x55, 0xcb, 0x39, 0x55, 0x72, 0xc6};
+
+static const unsigned char x509_pub_key_y[] = {
+ 0x65, 0x71, 0xcd, 0x03, 0xdc, 0x2a, 0x4f, 0x46,
+ 0x5b, 0x14, 0xc8, 0x27, 0x74, 0xab, 0xf4, 0x1f,
+ 0xc1, 0x35, 0x0d, 0x42, 0xbc, 0xc2, 0x9f, 0xb5,
+ 0xc1, 0x79, 0xb6, 0x8b, 0xca, 0xdb, 0xff, 0x82};
+
+//default CA pub key
+static const unsigned char x509_ca_pub_x[] = {
+ 0x57, 0x94, 0x7f, 0x98, 0x7a, 0x02, 0x67, 0x09,
+ 0x25, 0xc1, 0xcb, 0x5a, 0xf5, 0x46, 0xfb, 0xad,
+ 0xf7, 0x68, 0x94, 0x8c, 0xa7, 0xe3, 0xf0, 0x5b,
+ 0xc3, 0x6b, 0x5c, 0x9b, 0xd3, 0x7d, 0x74, 0x12
+};
+
+static const unsigned char x509_ca_pub_y[] = {
+ 0xce, 0x68, 0xbc, 0x55, 0xf5, 0xf8, 0x1b, 0x3d,
+ 0xef, 0xed, 0x1f, 0x2b, 0xd2, 0x69, 0x5d, 0xcf,
+ 0x79, 0x16, 0xa6, 0xbd, 0x97, 0x96, 0x27, 0x60,
+ 0x5d, 0xd1, 0xb7, 0x93, 0xa2, 0x4a, 0x62, 0x4d
+};
+
+static const unsigned char client_pub_key_x[] = {
+ 0xe3, 0xd1, 0x67, 0x1e, 0xdc, 0x46, 0xf4, 0x19,
+ 0x50, 0x15, 0x2e, 0x3a, 0x2f, 0xd8, 0x68, 0x6b,
+ 0x37, 0x32, 0x84, 0x9e, 0x83, 0x81, 0xbf, 0x25,
+ 0x5d, 0xbb, 0x18, 0x07, 0x3c, 0xbd, 0xf3, 0xab};
+
+static const unsigned char client_pub_key_y[] = {
+ 0xd3, 0xbf, 0x53, 0x59, 0xc9, 0x1e, 0xce, 0x5b,
+ 0x39, 0x6a, 0xe5, 0x60, 0xf3, 0x70, 0xdb, 0x66,
+ 0xb6, 0x80, 0xcb, 0x65, 0x0b, 0x35, 0x2a, 0x62,
+ 0x44, 0x89, 0x63, 0x64, 0x6f, 0x6f, 0xbd, 0xf0};
+
+static unsigned char x509_server_cert[DTLS_MAX_CERT_SIZE];
+static size_t x509_server_cert_len = 0;
+static unsigned char x509_server_priv[DTLS_PRIVATE_KEY_SIZE+1];
+static size_t x509_server_priv_is_set = 0;
+static unsigned char x509_ca_pub[DTLS_PUBLIC_KEY_SIZE+1];
+static size_t x509_ca_pub_is_set = 0;
+
+static int x509_info_from_file = 0;
+#endif /*DTLS_X509*/
+#ifdef DTLS_ECC
static const unsigned char ecdsa_priv_key[] = {
0xD9, 0xE2, 0x70, 0x7A, 0x72, 0xDA, 0x6A, 0x05,
0x04, 0x99, 0x5C, 0x86, 0xED, 0xDB, 0xE3, 0xEF,
0x1D, 0xDC, 0xF4, 0xF4, 0x2E, 0x2F, 0x26, 0x31,
0xD0, 0x43, 0xB1, 0xFB, 0x03, 0xE2, 0x2F, 0x4D,
0x17, 0xDE, 0x43, 0xF9, 0xF9, 0xAD, 0xEE, 0x70};
-
+#endif /*DTLS_ECC*/
#if 0
/* SIGINT handler: set quit to 1 for graceful termination */
void
}
#endif
+#ifdef DTLS_X509
+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;
+}
+#endif /*DTLS_X509*/
+
#ifdef DTLS_PSK
#define PSK_SERVER_HINT "Server_identity"
const unsigned char *id, size_t id_len,
unsigned char *result, size_t result_length) {
+ (void)ctx;
+ (void)session;
struct keymap_t {
unsigned char *id;
size_t id_length;
case DTLS_PSK_KEY:
if (id) {
int i;
- for (i = 0; i < sizeof(psk)/sizeof(struct keymap_t); i++) {
+ for (i = 0; i < (int)(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");
get_ecdsa_key(struct dtls_context_t *ctx,
const session_t *session,
const dtls_ecc_key_t **result) {
+ (void)ctx;
+ (void)session;
static const dtls_ecc_key_t ecdsa_key = {
.curve = DTLS_ECDH_CURVE_SECP256R1,
.priv_key = ecdsa_priv_key,
const unsigned char *other_pub_x,
const unsigned char *other_pub_y,
size_t key_size) {
+ (void)ctx;
+ (void)session;
+ (void)other_pub_x;
+ (void)other_pub_y;
+ (void)key_size;
return 0;
}
#endif /* DTLS_ECC */
+#ifdef DTLS_X509
+static int
+get_x509_key(struct dtls_context_t *ctx,
+ const session_t *session,
+ const dtls_ecc_key_t **result) {
+ (void)ctx;
+ (void)session;
+ static dtls_ecc_key_t ecdsa_key = {
+ .curve = DTLS_ECDH_CURVE_SECP256R1,
+ .priv_key = x509_priv_key,
+ .pub_key_x = x509_pub_key_x,
+ .pub_key_y = x509_pub_key_y
+ };
+ if (x509_info_from_file)
+ ecdsa_key.priv_key = x509_server_priv;
+
+ *result = &ecdsa_key;
+ return 0;
+}
+
+static int
+get_x509_cert(struct dtls_context_t *ctx,
+ const session_t *session,
+ const unsigned char **cert,
+ size_t *cert_size)
+{
+ (void)ctx;
+ (void)session;
+ if (x509_info_from_file)
+ {
+ *cert = x509_server_cert;
+ *cert_size = x509_server_cert_len;
+ }
+ else
+ {
+ *cert = g_server_certificate;
+ *cert_size = SERVER_CRT_LEN;
+ }
+
+ return 0;
+}
+
+static int check_certificate(byte_array cert_der_code, byte_array ca_public_key)
+{
+ (void)cert_der_code;
+ (void)ca_public_key;
+ return 0;
+}
+
+static int verify_x509_cert(struct dtls_context_t *ctx, const session_t *session,
+ const unsigned char *cert, size_t cert_size,
+ unsigned char *x,
+ size_t x_size,
+ unsigned char *y,
+ size_t y_size)
+{
+ int ret;
+ const unsigned char *ca_pub_x;
+ const unsigned char *ca_pub_y;
+ byte_array cert_der_code = BYTE_ARRAY_INITIALIZER;
+ byte_array ca_public_key = BYTE_ARRAY_INITIALIZER;
+ unsigned char ca_pub_key[DTLS_PUBLIC_KEY_SIZE];
+ (void)ctx;
+ (void)session;
+
+ if (x509_info_from_file)
+ {
+ ca_pub_x = x509_ca_pub;
+ ca_pub_y = x509_ca_pub + DTLS_PUBLIC_KEY_SIZE/2;
+ }
+ else
+ {
+ ca_pub_x = x509_ca_pub_x;
+ ca_pub_y = x509_ca_pub_y;
+ }
+
+ cert_der_code.data = (uint8_t *)cert;
+ cert_der_code.len = cert_size;
+
+ ca_public_key.len = DTLS_PUBLIC_KEY_SIZE;
+ ca_public_key.data = ca_pub_key;
+ memcpy(ca_public_key.data, ca_pub_x, DTLS_PUBLIC_KEY_SIZE/2);
+ memcpy(ca_public_key.data + DTLS_PUBLIC_KEY_SIZE/2, ca_pub_y, DTLS_PUBLIC_KEY_SIZE/2);
+
+ memcpy(x, client_pub_key_x, x_size);
+ memcpy(y, client_pub_key_y, y_size);
+
+ ret = (int) check_certificate(cert_der_code, ca_public_key);
+
+ return -ret;
+}
+
+static int is_x509_active(struct dtls_context_t *ctx)
+{
+ (void)ctx;
+ return 0;
+}
+#endif /* DTLS_X509 */
+
+
#define DTLS_SERVER_CMD_CLOSE "server:close"
#define DTLS_SERVER_CMD_RENEGOTIATE "server:renegotiate"
static int
-read_from_peer(struct dtls_context_t *ctx,
+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++)
} else {
dtls_debug("got %d bytes from port %d\n", len,
ntohs(session.addr.sin6.sin6_port));
- if (sizeof(buf) < len) {
+ if ((int)(sizeof(buf)) < len) {
dtls_warn("packet was truncated (%d bytes lost)\n", len - sizeof(buf));
}
}
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] [-a enable|disable]\n"
+#ifdef DTLS_X509
+ " [-x file] [-r file] [-u file]"
+#endif /* DTLS_X509 */
"\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"
"\t-a enable|disable\t(default: disable)\n"
- "\t\t\t\tenable:enable TLS_ECDH_anon_with_AES_128_CBC_SHA\n"
- "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA\n",
- program, version, program, DEFAULT_PORT);
+ "\t\t\t\tenable:enable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n"
+ "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n"
+#ifdef DTLS_X509
+ "\t-x file\tread Server certificate from file\n"
+ "\t-r file\tread Server private key from file\n"
+ "\t-u file\tread CA public key from file\n"
+#endif /* DTLS_X509 */
+ ,program, version, program, DEFAULT_PORT);
}
static dtls_handler_t cb = {
#endif /* DTLS_PSK */
#ifdef DTLS_ECC
.get_ecdsa_key = get_ecdsa_key,
- .verify_ecdsa_key = verify_ecdsa_key
+ .verify_ecdsa_key = verify_ecdsa_key,
#endif /* DTLS_ECC */
+#ifdef DTLS_X509
+ .get_x509_key = get_x509_key,
+ .verify_x509_cert = verify_x509_cert,
+ .get_x509_cert = get_x509_cert,
+ .is_x509_active = is_x509_active,
+#endif
+
};
-int
+int
main(int argc, char **argv) {
dtls_context_t *the_context = NULL;
log_t log_level = DTLS_LOG_WARN;
struct timeval timeout;
int fd, opt, result;
int on = 1;
- int ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
+ dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
struct sockaddr_in6 listen_addr;
memset(&listen_addr, 0, sizeof(struct sockaddr_in6));
if( strcmp(optarg, "enable") == 0)
ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
break;
+#ifdef DTLS_X509
+ case 'x' :
+ {
+ ssize_t result = read_from_file(optarg, x509_server_cert, DTLS_MAX_CERT_SIZE);
+ if (result < 0)
+ {
+ dtls_warn("Cannot read Server certificate. Using default\n");
+ }
+ else
+ {
+ x509_server_cert_len = result;
+ }
+ break;
+ }
+ case 'r' :
+ {
+ ssize_t result = read_from_file(optarg, x509_server_priv, DTLS_PRIVATE_KEY_SIZE+1);
+ if (result < 0)
+ {
+ dtls_warn("Cannot read Server private key. Using default\n");
+ }
+ else
+ {
+ x509_server_priv_is_set = result;
+ }
+ break;
+ }
+ case 'u' :
+ {
+ ssize_t result = read_from_file(optarg, x509_ca_pub, DTLS_PUBLIC_KEY_SIZE+1);
+ if (result < 0)
+ {
+ dtls_warn("Cannot read CA public key. Using default\n");
+ }
+ else
+ {
+ x509_ca_pub_is_set = result;
+ }
+ break;
+ }
+#endif /* DTLS_X509 */
default:
usage(argv[0], dtls_package_version());
exit(1);
dtls_set_log_level(log_level);
+#ifdef DTLS_X509
+ if (x509_server_cert_len && x509_server_priv_is_set && x509_ca_pub_is_set)
+ {
+ x509_info_from_file = 1;
+ }
+ else if(!(x509_server_cert_len || x509_server_priv_is_set || x509_ca_pub_is_set))
+ {
+ x509_info_from_file = 0;
+ }
+ else
+ {
+ fprintf(stderr,"please set -x, -r, -u options simultaneously");
+ usage(argv[0], dtls_package_version());
+ exit(1);
+ }
+#endif /* DTLS_X509 */
+
/* init socket and set it to non-blocking */
fd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
return 0;
}
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on) ) < 0) {
dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
}
#if 0
#endif
on = 1;
#ifdef IPV6_RECVPKTINFO
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, OPTVAL_T(&on), sizeof(on) ) < 0) {
#else /* IPV6_RECVPKTINFO */
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, OPTVAL_T(&on), sizeof(on) ) < 0) {
#endif /* IPV6_RECVPKTINFO */
dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
}
the_context = dtls_new_context(&fd);
- /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */
+ /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */
dtls_enables_anon_ecdh(the_context, ecdh_anon_enalbe);
dtls_set_handler(the_context, &cb);