#define DTLS_SH_LENGTH (2 + DTLS_RANDOM_LENGTH + 1 + 2 + 1)
#define DTLS_CE_LENGTH (3 + 3 + 27 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE)
#define DTLS_SKEXEC_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE + 1 + 1 + 2 + 70)
+#define DTLS_SKEXEC_ECDH_ANON_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE)
#define DTLS_SKEXECPSK_LENGTH_MIN 2
#define DTLS_SKEXECPSK_LENGTH_MAX 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN
#define DTLS_CKXPSK_LENGTH_MIN 2
peer_init();
}
+ void
+ dtls_enables_anon_ecdh(dtls_context_t* ctx, dtls_cipher_enable_t is_enable)
+{
+ if(ctx)
+ {
+ ctx->is_anon_ecdh_eabled = is_enable;
+ }
+}
+
+void
+dtls_select_cipher(dtls_context_t* ctx, const dtls_cipher_t cipher)
+{
+ if(ctx)
+ {
+ ctx->selected_cipher = cipher;
+ }
+}
+
/* Calls cb_alert() with given arguments if defined, otherwise an
* error message is logged and the result is -1. This is just an
* internal helper.
/** returns true if the cipher matches TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */
static inline int is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(dtls_cipher_t cipher)
{
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
return cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
#else
return 0;
#endif /* DTLS_PSK */
}
+/** returns true if the cipher matches TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 */
+static inline int is_tls_ecdh_anon_with_aes_128_cbc_sha_256(dtls_cipher_t cipher)
+{
+#ifdef DTLS_ECC
+ return cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256;
+#else
+ return 0;
+#endif
+}
+
+/** returns true if the cipher matches TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 */
+static inline int is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(dtls_cipher_t cipher)
+{
+#if defined(DTLS_ECC) && defined(DTLS_PSK)
+ return cipher == TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256;
+#else
+ return 0;
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
+}
+
+
+
/** returns true if the application is configured for psk */
static inline int is_psk_supported(dtls_context_t *ctx)
{
static inline int is_ecdsa_supported(dtls_context_t *ctx, int is_client)
{
#ifdef DTLS_ECC
- return ctx && ctx->h && ((!is_client && ctx->h->get_ecdsa_key) ||
+ return ctx && ctx->h && ((!is_client && ctx->h->get_ecdsa_key) ||
(is_client && ctx->h->verify_ecdsa_key));
#else
return 0;
#endif /* DTLS_ECC */
}
+/** returns true if the application is configured for x509 */
+static inline int is_x509_supported(dtls_context_t *ctx, int is_client)
+{
+#ifdef DTLS_X509
+ return ctx && ctx->h && ((!is_client && ctx->h->get_x509_cert) ||
+ (is_client && ctx->h->verify_x509_cert));
+#else
+ return 0;
+#endif /* DTLS_X509 */
+}
+
/** Returns true if the application is configured for ecdhe_ecdsa with
* client authentication */
static inline int is_ecdsa_client_auth_supported(dtls_context_t *ctx)
#endif /* DTLS_ECC */
}
+/** Returns true if the application is configured for x509 with
+ * client authentication */
+static inline int is_x509_client_auth_supported(dtls_context_t *ctx)
+{
+#ifdef DTLS_X509
+ return ctx && ctx->h && ctx->h->get_x509_cert && ctx->h->verify_x509_cert;
+#else
+ return 0;
+#endif /* DTLS_X509 */
+}
+
+/** returns true if ecdh_anon_with_aes_128_cbc_sha is supported */
+static inline int is_ecdh_anon_supported(dtls_context_t *ctx)
+{
+#ifdef DTLS_ECC
+ return ctx && (ctx->is_anon_ecdh_eabled == DTLS_CIPHER_ENABLE);
+#else
+ return 0;
+#endif
+}
+
+/** returns true if ecdhe_psk_with_aes_128_cbc_sha_256 is supported */
+static inline int is_ecdhe_psk_supported(dtls_context_t *ctx)
+{
+#if defined(DTLS_ECC) && defined(DTLS_PSK)
+ return is_psk_supported(ctx);
+#else
+ return 0;
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
+}
+
+
/**
* Returns @c 1 if @p code is a cipher suite other than @c
* TLS_NULL_WITH_NULL_NULL that we recognize.
known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) {
int psk;
int ecdsa;
+ int ecdh_anon;
+ int ecdhe_psk;
+ int x509;
psk = is_psk_supported(ctx);
ecdsa = is_ecdsa_supported(ctx, is_client);
+ ecdh_anon = is_ecdh_anon_supported(ctx);
+ ecdhe_psk = is_ecdhe_psk_supported(ctx);
+ x509 = is_x509_supported(ctx, is_client);
+
return (psk && is_tls_psk_with_aes_128_ccm_8(code)) ||
- (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code));
+ (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code)) ||
+ (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha_256(code)) ||
+ (ecdhe_psk && is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(code)) ||
+ (x509 && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code));
}
/**
dtls_debug("key_block (%d bytes):\n", dtls_kb_size(config, peer->role));
dtls_debug_dump(" client_MAC_secret",
dtls_kb_client_mac_secret(config, peer->role),
- dtls_kb_mac_secret_size(config, peer->role));
+ dtls_kb_mac_secret_size(config->cipher));
dtls_debug_dump(" server_MAC_secret",
dtls_kb_server_mac_secret(config, peer->role),
- dtls_kb_mac_secret_size(config, peer->role));
+ dtls_kb_mac_secret_size(config->cipher));
dtls_debug_dump(" client_write_key",
dtls_kb_client_write_key(config, peer->role),
dtls_debug_dump(" client_IV",
dtls_kb_client_iv(config, peer->role),
- dtls_kb_iv_size(config, peer->role));
+ dtls_kb_iv_size(config->cipher));
dtls_debug_dump(" server_IV",
dtls_kb_server_iv(config, peer->role),
- dtls_kb_iv_size(config, peer->role));
+ dtls_kb_iv_size(config->cipher));
}
/** returns the name of the goven handshake type number.
dtls_peer_t *peer,
session_t *session,
dtls_peer_type role) {
- unsigned char *pre_master_secret;
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+ unsigned char pre_master_secret[MAX_KEYBLOCK_LENGTH + uECC_BYTES];
+#else
+ unsigned char pre_master_secret[MAX_KEYBLOCK_LENGTH];
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
int pre_master_len = 0;
dtls_security_parameters_t *security = dtls_security_params_next(peer);
uint8 master_secret[DTLS_MASTER_SECRET_LENGTH];
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
}
- pre_master_secret = security->key_block;
-
switch (handshake->cipher) {
#ifdef DTLS_PSK
case TLS_PSK_WITH_AES_128_CCM_8: {
break;
}
#endif /* DTLS_PSK */
-#ifdef DTLS_ECC
- case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: {
- pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecdsa.own_eph_priv,
- handshake->keyx.ecdsa.other_eph_pub_x,
- handshake->keyx.ecdsa.other_eph_pub_y,
- sizeof(handshake->keyx.ecdsa.own_eph_priv),
+#if defined(DTLS_ECC) || defined(DTLS_X509)
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: {
+ pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecc.own_eph_priv,
+ handshake->keyx.ecc.other_eph_pub_x,
+ handshake->keyx.ecc.other_eph_pub_y,
+ sizeof(handshake->keyx.ecc.own_eph_priv),
pre_master_secret,
MAX_KEYBLOCK_LENGTH);
if (pre_master_len < 0) {
break;
}
#endif /* DTLS_ECC */
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+ case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: {
+ unsigned char psk[DTLS_PSK_MAX_KEY_LEN];
+ int psklen;
+
+ psklen = CALL(ctx, get_psk_info, session, DTLS_PSK_KEY,
+ handshake->keyx.psk.identity,
+ handshake->keyx.psk.id_length,
+ psk, DTLS_PSK_MAX_KEY_LEN);
+ if (psklen < 0) {
+ dtls_crit("no psk key for session available\n");
+ return psklen;
+ }
+
+ pre_master_len = dtls_ecdhe_psk_pre_master_secret(psk, psklen,
+ handshake->keyx.ecc.own_eph_priv,
+ handshake->keyx.ecc.other_eph_pub_x,
+ handshake->keyx.ecc.other_eph_pub_y,
+ sizeof(handshake->keyx.ecc.own_eph_priv),
+ pre_master_secret,
+ MAX_KEYBLOCK_LENGTH + uECC_BYTES);
+
+ if (pre_master_len < 0) {
+ dtls_crit("the curve was too long, for the pre master secret\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
+ }
+ break;
+ }
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
default:
dtls_crit("calculate_key_block: unknown cipher\n");
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
/* create key_block from master_secret
* key_block = PRF(master_secret,
"key expansion" + tmp.random.server + tmp.random.client) */
+ security->cipher = handshake->cipher;
+ security->compression = handshake->compression;
+ security->rseq = 0;
dtls_prf(master_secret,
DTLS_MASTER_SECRET_LENGTH,
memcpy(handshake->tmp.master_secret, master_secret, DTLS_MASTER_SECRET_LENGTH);
dtls_debug_keyblock(security);
- security->cipher = handshake->cipher;
- security->compression = handshake->compression;
- security->rseq = 0;
return 0;
}
cert_type = dtls_uint8_to_int(data);
data += sizeof(uint8);
+
if (cert_type == TLS_CERT_TYPE_RAW_PUBLIC_KEY)
- return 0;
+ return 0;
+#ifdef DTLS_X509
+ if (cert_type == TLS_CERT_TYPE_X509)
+ return 0;
+#endif
}
dtls_warn("no supported certificate type found\n");
if (verify_ext_cert_type(data, j))
goto error;
} else {
+#ifndef DTLS_X509
if (dtls_uint8_to_int(data) != TLS_CERT_TYPE_RAW_PUBLIC_KEY)
+#else
+ if ((dtls_uint8_to_int(data) != TLS_CERT_TYPE_RAW_PUBLIC_KEY) &&
+ (dtls_uint8_to_int(data) != TLS_CERT_TYPE_X509))
+#endif
goto error;
}
break;
if (verify_ext_cert_type(data, j))
goto error;
} else {
+#ifndef DTLS_X509
if (dtls_uint8_to_int(data) != TLS_CERT_TYPE_RAW_PUBLIC_KEY)
+#else
+ if ((dtls_uint8_to_int(data) != TLS_CERT_TYPE_RAW_PUBLIC_KEY) &&
+ (dtls_uint8_to_int(data) != TLS_CERT_TYPE_X509))
+#endif
goto error;
}
break;
dtls_handshake_parameters_t *handshake,
uint8 *data, size_t length) {
-#ifdef DTLS_ECC
- if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher)) {
+#if defined(DTLS_ECC) || defined(DTLS_X509)
+ if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) ||
+ is_tls_ecdh_anon_with_aes_128_cbc_sha_256(handshake->cipher) ) {
if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) {
dtls_debug("The client key exchange is too short\n");
}
data += sizeof(uint8);
- memcpy(handshake->keyx.ecdsa.other_eph_pub_x, data,
- sizeof(handshake->keyx.ecdsa.other_eph_pub_x));
- data += sizeof(handshake->keyx.ecdsa.other_eph_pub_x);
+ memcpy(handshake->keyx.ecc.other_eph_pub_x, data,
+ sizeof(handshake->keyx.ecc.other_eph_pub_x));
+ data += sizeof(handshake->keyx.ecc.other_eph_pub_x);
- memcpy(handshake->keyx.ecdsa.other_eph_pub_y, data,
- sizeof(handshake->keyx.ecdsa.other_eph_pub_y));
- data += sizeof(handshake->keyx.ecdsa.other_eph_pub_y);
+ memcpy(handshake->keyx.ecc.other_eph_pub_y, data,
+ sizeof(handshake->keyx.ecc.other_eph_pub_y));
+ data += sizeof(handshake->keyx.ecc.other_eph_pub_y);
}
#endif /* DTLS_ECC */
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+ if (is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(handshake->cipher)) {
+ int id_length;
+
+ if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) {
+ dtls_debug("The client key exchange is too short\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += DTLS_HS_LENGTH;
+
+ //PSK hint
+ id_length = dtls_uint16_to_int(data);
+ data += sizeof(uint16);
+
+ if (DTLS_HS_LENGTH + DTLS_CKXPSK_LENGTH_MIN + DTLS_CKXEC_LENGTH + id_length != length) {
+ dtls_debug("The identity has a wrong length\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+
+ if (id_length > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) {
+ dtls_warn("please use a smaller client identity\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
+ }
+
+ handshake->keyx.psk.id_length = id_length;
+ memcpy(handshake->keyx.psk.identity, data, id_length);
+ data += id_length;
+
+ //ECDH public
+ if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) {
+ dtls_alert("expected 65 bytes long public point\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += sizeof(uint8);
+
+ if (dtls_uint8_to_int(data) != 4) {
+ dtls_alert("expected uncompressed public point\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += sizeof(uint8);
+
+ memcpy(handshake->keyx.ecc.other_eph_pub_x, data,
+ sizeof(handshake->keyx.ecc.other_eph_pub_x));
+ data += sizeof(handshake->keyx.ecc.other_eph_pub_x);
+
+ memcpy(handshake->keyx.ecc.other_eph_pub_y, data,
+ sizeof(handshake->keyx.ecc.other_eph_pub_y));
+ data += sizeof(handshake->keyx.ecc.other_eph_pub_y);
+ }
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
#ifdef DTLS_PSK
if (is_tls_psk_with_aes_128_ccm_8(handshake->cipher)) {
int id_length;
p += data_len_array[i];
res += data_len_array[i];
}
+ } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher) ||
+ is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(security->cipher)) {
+
+ unsigned char nonce[DTLS_CBC_IV_LENGTH];
+
+ /** Add IV into body of packet in case of AES CBC mode according to RFC 5246, Section 6.2.3.2
+ *
+ * opaque IV[SecurityParameters.record_iv_length];
+ * block-ciphered struct {
+ * opaque content[TLSCompressed.length];
+ * opaque MAC[SecurityParameters.mac_length];
+ * uint8 padding[GenericBlockCipher.padding_length];
+ * uint8 padding_length;
+ * };
+ *
+ */
+
+ res = 0;
+ dtls_prng(nonce, DTLS_CBC_IV_LENGTH);
+ memcpy(p , nonce, DTLS_CBC_IV_LENGTH);
+ p += DTLS_CBC_IV_LENGTH;
+ res += DTLS_CBC_IV_LENGTH;
+
+ for (i = 0; i < data_array_len; i++) {
+ /* check the minimum that we need for packets that are not encrypted */
+ if (*rlen < res + DTLS_RH_LENGTH + data_len_array[i]) {
+ dtls_debug("dtls_prepare_record: send buffer too small\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
+ }
+
+ memcpy(p, data_array[i], data_len_array[i]);
+ p += data_len_array[i];
+ res += data_len_array[i];
+ }
+
+ res = dtls_encrypt(start + DTLS_CBC_IV_LENGTH, res - DTLS_CBC_IV_LENGTH,
+ start + DTLS_CBC_IV_LENGTH, nonce,
+ dtls_kb_local_write_key(security, peer->role),
+ dtls_kb_key_size(security, peer->role),
+ dtls_kb_local_mac_secret(security, peer->role),
+ dtls_kb_mac_secret_size(security->cipher),
+ NULL, 0,
+ security->cipher);
+ if (res < 0)
+ return res;
+
+ res += DTLS_CBC_IV_LENGTH;
+
} else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */
/**
* length of additional_data for the AEAD cipher which consists of
memset(nonce, 0, DTLS_CCM_BLOCKSIZE);
memcpy(nonce, dtls_kb_local_iv(security, peer->role),
- dtls_kb_iv_size(security, peer->role));
- memcpy(nonce + dtls_kb_iv_size(security, peer->role), start, 8); /* epoch + seq_num */
+ dtls_kb_iv_size(security->cipher));
+ memcpy(nonce + dtls_kb_iv_size(security->cipher), start, 8); /* epoch + seq_num */
dtls_debug_dump("nonce:", nonce, DTLS_CCM_BLOCKSIZE);
dtls_debug_dump("key:", dtls_kb_local_write_key(security, peer->role),
memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */
memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */
dtls_int_to_uint16(A_DATA + 11, res - 8); /* length */
-
+
res = dtls_encrypt(start + 8, res - 8, start + 8, nonce,
- dtls_kb_local_write_key(security, peer->role),
- dtls_kb_key_size(security, peer->role),
- A_DATA, A_DATA_LEN);
+ dtls_kb_local_write_key(security, peer->role),
+ dtls_kb_key_size(security, peer->role),
+ dtls_kb_local_mac_secret(security, peer->role),
+ dtls_kb_mac_secret_size(security->cipher),
+ A_DATA, A_DATA_LEN,
+ security->cipher);
if (res < 0)
return res;
- res += 8; /* increment res by size of nonce_explicit */
+ res += 8; /* increment res by size of nonce_explicit */
dtls_debug_dump("message:", start, res);
}
#undef mycookie
}
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
static int
dtls_check_ecdsa_signature_elem(uint8 *data, size_t data_length,
unsigned char **result_r,
dtls_hash_finalize(sha256hash, &hs_hash);
- ret = dtls_ecdsa_verify_sig_hash(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y,
- sizeof(config->keyx.ecdsa.other_pub_x),
- sha256hash, sizeof(sha256hash),
- result_r, result_s);
+ ret = dtls_ecdsa_verify_sig_hash(config->keyx.ecc.other_pub_x, config->keyx.ecc.other_pub_y,
+ sizeof(config->keyx.ecc.other_pub_x),
+ sha256hash, sizeof(sha256hash),
+ result_r, result_s);
- if (ret < 0) {
+ if (ret <= 0) {
dtls_alert("wrong signature err: %i\n", ret);
return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
}
/* length of this extension type */
dtls_int_to_uint16(p, 1);
p += sizeof(uint16);
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ dtls_int_to_uint8(p, TLS_CERT_TYPE_X509);
+ else
+#endif /* DTLS_X509 */
+ dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY);
- dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY);
p += sizeof(uint8);
/* client certificate type extension */
dtls_int_to_uint16(p, 1);
p += sizeof(uint16);
- dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY);
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ dtls_int_to_uint8(p, TLS_CERT_TYPE_X509);
+ else
+#endif /* DTLS_X509 */
+ dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY);
+
p += sizeof(uint8);
/* ec_point_formats */
}
#ifdef DTLS_ECC
+#define DTLS_EC_SUBJECTPUBLICKEY_SIZE (2 * DTLS_EC_KEY_SIZE + sizeof(cert_asn1_header))
+
static int
dtls_send_certificate_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer,
- const dtls_ecdsa_key_t *key)
+ const dtls_ecc_key_t *key)
{
uint8 buf[DTLS_CE_LENGTH];
uint8 *p;
- /* Certificate
+ /* Certificate
*
* Start message construction at beginning of buffer. */
p = buf;
- dtls_int_to_uint24(p, 94); /* certificates length */
+ /* length of this certificate */
+ dtls_int_to_uint24(p, DTLS_EC_SUBJECTPUBLICKEY_SIZE);
p += sizeof(uint24);
- dtls_int_to_uint24(p, 91); /* length of this certificate */
- p += sizeof(uint24);
-
memcpy(p, &cert_asn1_header, sizeof(cert_asn1_header));
p += sizeof(cert_asn1_header);
return dtls_send_handshake_msg(ctx, peer, DTLS_HT_CERTIFICATE,
buf, p - buf);
}
+#endif /* DTLS_ECC */
+
+#ifdef DTLS_X509
+static int
+dtls_send_certificate_x509(dtls_context_t *ctx, dtls_peer_t *peer)
+{
+ uint8 buf[DTLS_MAX_CERT_SIZE];
+ uint8 *p;
+ int ret;
+ unsigned char *cert;
+ size_t cert_size;
+
+ dtls_info("\n dtls_send_certificate_ecdsa\n");
+ ret = CALL(ctx, get_x509_cert, &peer->session,
+ (const unsigned char **)&cert, &cert_size);
+
+ if (ret < 0) {
+ dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ return ret;
+ }
+
+ /* Certificate
+ *
+ * Start message construction at beginning of buffer. */
+ p = buf;
+
+ dtls_int_to_uint24(p, cert_size); /* certificates length */
+ p += sizeof(uint24);
+
+ memcpy(p, cert, cert_size);
+ p += cert_size;
+
+ assert(p - buf <= sizeof(buf));
+
+ return dtls_send_handshake_msg(ctx, peer, DTLS_HT_CERTIFICATE,
+ buf, p - buf);
+}
+#endif /* DTLS_X509 */
+#if defined(DTLS_X509) || defined(DTLS_ECC)
static uint8 *
dtls_add_ecdsa_signature_elem(uint8 *p, uint32_t *point_r, uint32_t *point_s)
{
static int
dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer,
- const dtls_ecdsa_key_t *key)
+ const dtls_ecc_key_t *key)
{
/* The ASN.1 Integer representation of an 32 byte unsigned int could be
* 33 bytes long add space for that */
uint8 *ephemeral_pub_y;
uint32_t point_r[9];
uint32_t point_s[9];
+ int ecdsa;
dtls_handshake_parameters_t *config = peer->handshake_params;
- /* ServerKeyExchange
+ ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher);
+ /* ServerKeyExchange
*
* Start message construction at beginning of buffer. */
p = buf;
ephemeral_pub_y = p;
p += DTLS_EC_KEY_SIZE;
- dtls_ecdsa_generate_key(config->keyx.ecdsa.own_eph_priv,
- ephemeral_pub_x, ephemeral_pub_y,
- DTLS_EC_KEY_SIZE);
+ dtls_ecdsa_generate_key(config->keyx.ecc.own_eph_priv,
+ ephemeral_pub_x, ephemeral_pub_y,
+ DTLS_EC_KEY_SIZE);
+ if(ecdsa) {
+ /* sign the ephemeral and its paramaters */
+ dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE,
+ config->tmp.random.client, DTLS_RANDOM_LENGTH,
+ config->tmp.random.server, DTLS_RANDOM_LENGTH,
+ key_params, p - key_params,
+ point_r, point_s);
- /* sign the ephemeral and its paramaters */
- dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE,
- config->tmp.random.client, DTLS_RANDOM_LENGTH,
- config->tmp.random.server, DTLS_RANDOM_LENGTH,
- key_params, p - key_params,
- point_r, point_s);
+ p = dtls_add_ecdsa_signature_elem(p, point_r, point_s);
+ }
- p = dtls_add_ecdsa_signature_elem(p, point_r, point_s);
+ assert(p - buf <= sizeof(buf));
+
+ return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE,
+ buf, p - buf);
+}
+#endif /* defined(DTLS_X509) || defined(DTLS_ECC) */
+
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+static int dtls_send_server_key_exchange_ecdhe_psk(dtls_context_t *ctx, dtls_peer_t *peer,
+ const unsigned char *psk_hint, size_t psk_hint_len)
+{
+ /* The ASN.1 Integer representation of an 32 byte unsigned int could be
+ * 33 bytes long add space for that */
+ uint8 buf[DTLS_SKEXEC_LENGTH + DTLS_SKEXECPSK_LENGTH_MAX + 2];
+ uint8 *p;
+ uint8 *ephemeral_pub_x;
+ uint8 *ephemeral_pub_y;
+ dtls_handshake_parameters_t *config = peer->handshake_params;
+
+ /* ServerKeyExchange
+ * Please see Session 2, RFC 5489.
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ //other cases for rsa, diffie_hellman, etc.
+ case ec_diffie_hellman_psk: // NEW
+ opaque psk_identity_hint<0..2^16-1>;
+ ServerECDHParams params;
+ };
+ } ServerKeyExchange; */
+ p = buf;
+
+ assert(psk_hint_len <= DTLS_PSK_MAX_CLIENT_IDENTITY_LEN);
+ if (psk_hint_len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) {
+ // should never happen
+ dtls_warn("psk identity hint is too long\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
+ }
+
+ // psk_identity_hint
+ dtls_int_to_uint16(p, psk_hint_len);
+ p += sizeof(uint16);
+
+ memcpy(p, psk_hint, psk_hint_len);
+ p += psk_hint_len;
+
+ /* ServerECDHParams. */
+ /* ECCurveType curve_type: named_curve */
+ dtls_int_to_uint8(p, TLS_EC_CURVE_TYPE_NAMED_CURVE);
+ p += sizeof(uint8);
+
+ /* NamedCurve namedcurve: secp256r1 */
+ dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES_SECP256R1);
+ p += sizeof(uint16);
+
+ dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE);
+ p += sizeof(uint8);
+
+ /* This should be an uncompressed point, but I do not have access to the spec. */
+ dtls_int_to_uint8(p, 4);
+ p += sizeof(uint8);
+
+ /* store the pointer to the x component of the pub key and make space */
+ ephemeral_pub_x = p;
+ p += DTLS_EC_KEY_SIZE;
+
+ /* store the pointer to the y component of the pub key and make space */
+ ephemeral_pub_y = p;
+ p += DTLS_EC_KEY_SIZE;
+
+ dtls_ecdsa_generate_key(config->keyx.ecc.own_eph_priv,
+ ephemeral_pub_x, ephemeral_pub_y,
+ DTLS_EC_KEY_SIZE);
assert(p - buf <= sizeof(buf));
return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE,
buf, p - buf);
}
-#endif /* DTLS_ECC */
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
#ifdef DTLS_PSK
static int
}
#endif /* DTLS_PSK */
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
static int
dtls_send_server_certificate_request(dtls_context_t *ctx, dtls_peer_t *peer)
{
dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer)
{
int res;
+ int ecdsa;
+ int ecdh_anon;
+ int ecdhe_psk;
res = dtls_send_server_hello(ctx, peer);
return res;
}
-#ifdef DTLS_ECC
- if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) {
- const dtls_ecdsa_key_t *ecdsa_key;
+ ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher);
+ ecdh_anon = is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher);
+ ecdhe_psk = is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher);
+
+#if defined(DTLS_ECC) || defined(DTLS_X509)
+ if(ecdh_anon) {
+ res = dtls_send_server_key_exchange_ecdh(ctx, peer, NULL);
+
+ if (res < 0) {
+ dtls_debug("dtls_server_hello(with ECDH): cannot prepare Server Key Exchange record\n");
+ return res;
+ }
+ }
+ else if (ecdsa) {
+ const dtls_ecc_key_t *ecdsa_key;
+
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ res = CALL(ctx, get_x509_key, &peer->session, &ecdsa_key);
+ else
+#endif /* DTLS_X509 */
+ res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key);
- res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key);
if (res < 0) {
- dtls_crit("no ecdsa certificate to send in certificate\n");
+ dtls_debug("no ecdsa key to send\n");
return res;
}
- res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key);
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ res = dtls_send_certificate_x509(ctx, peer);
+ else
+#endif /* DTLS_X509 */
+ res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key);
if (res < 0) {
dtls_debug("dtls_server_hello: cannot prepare Certificate record\n");
}
if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) &&
- is_ecdsa_client_auth_supported(ctx)) {
+ (is_ecdsa_client_auth_supported(ctx) || (is_x509_client_auth_supported(ctx)))) {
res = dtls_send_server_certificate_request(ctx, peer);
-
if (res < 0) {
- dtls_debug("dtls_server_hello: cannot prepare certificate Request record\n");
+ dtls_debug("dtls_server_hello(with ECDSA): cannot prepare certificate Request record\n");
return res;
}
}
}
#endif /* DTLS_ECC */
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+ else if(ecdhe_psk) {
+ unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN];
+ int psk_len;
+
+ /* The identity hint is optional, therefore we ignore the result
+ * and check psk only. */
+ psk_len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_HINT,
+ NULL, 0, psk_hint, DTLS_PSK_MAX_CLIENT_IDENTITY_LEN);
+ if (psk_len < 0) {
+ dtls_debug("dtls_server_hello: cannot create ServerKeyExchange\n");
+ return psk_len;
+ }
+
+ if (psk_len > 0) {
+ res = dtls_send_server_key_exchange_ecdhe_psk(ctx, peer, psk_hint, (size_t)psk_len);
+
+ if (res < 0) {
+ dtls_debug("dtls_server_hello(with ECDHE): cannot prepare Server Key Exchange record\n");
+ return res;
+ }
+ }
+ }
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
#ifdef DTLS_PSK
if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) {
unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN];
static int
dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer)
{
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+ uint8 buf[DTLS_CKXEC_LENGTH + 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN];
+#else
uint8 buf[DTLS_CKXEC_LENGTH];
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
uint8 client_id[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN];
uint8 *p;
dtls_handshake_parameters_t *handshake = peer->handshake_params;
break;
}
#endif /* DTLS_PSK */
-#ifdef DTLS_ECC
- case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: {
+#if defined(DTLS_ECC) || defined(DTLS_X509)
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: {
uint8 *ephemeral_pub_x;
uint8 *ephemeral_pub_y;
ephemeral_pub_y = p;
p += DTLS_EC_KEY_SIZE;
- dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecdsa.own_eph_priv,
+ dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecc.own_eph_priv,
ephemeral_pub_x, ephemeral_pub_y,
DTLS_EC_KEY_SIZE);
break;
}
#endif /* DTLS_ECC */
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+ case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: {
+ int psk_len;
+ uint8 *ephemeral_pub_x;
+ uint8 *ephemeral_pub_y;
+
+ /* Please see Session 2, RFC 5489.
+ struct {
+ select (KeyExchangeAlgorithm) {
+ // other cases for rsa, diffie_hellman, etc.
+ case ec_diffie_hellman_psk:
+ opaque psk_identity<0..2^16-1>;
+ ClientECDiffieHellmanPublic public;
+ } exchange_keys;
+ } ClientKeyExchange;
+ */
+
+ psk_len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_IDENTITY,
+ NULL, 0,
+ client_id,
+ sizeof(client_id));
+ if (psk_len < 0) {
+ dtls_crit("no psk identity set in kx\n");
+ return psk_len;
+ }
+
+ if (psk_len + sizeof(uint16) > DTLS_CKXEC_LENGTH) {
+ dtls_warn("the psk identity is too long\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
+ }
+
+ dtls_int_to_uint16(p, psk_len);
+ p += sizeof(uint16);
+
+ memcpy(p, client_id, psk_len);
+ p += psk_len;
+
+ dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE);
+ p += sizeof(uint8);
+
+ dtls_int_to_uint8(p, 4);
+ p += sizeof(uint8);
+
+ ephemeral_pub_x = p;
+ p += DTLS_EC_KEY_SIZE;
+ ephemeral_pub_y = p;
+ p += DTLS_EC_KEY_SIZE;
+
+ dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecc.own_eph_priv,
+ ephemeral_pub_x, ephemeral_pub_y,
+ DTLS_EC_KEY_SIZE);
+ break;
+ }
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
default:
dtls_crit("cipher not supported\n");
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
buf, p - buf);
}
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
static int
dtls_send_certificate_verify_ecdh(dtls_context_t *ctx, dtls_peer_t *peer,
- const dtls_ecdsa_key_t *key)
+ const dtls_ecc_key_t *key)
{
/* The ASN.1 Integer representation of an 32 byte unsigned int could be
* 33 bytes long add space for that */
uint8 cookie[], size_t cookie_length) {
uint8 buf[DTLS_CH_LENGTH_MAX];
uint8 *p = buf;
- uint8_t cipher_size;
- uint8_t extension_size;
- int psk;
- int ecdsa;
+ uint8_t cipher_size = 0;
+ uint8_t extension_size = 0;
+ int psk = 0;
+ int ecdsa = 0;
+ int ecdh_anon = 0;
+ int ecdhe_psk = 0;
+ int x509 = 0;
dtls_handshake_parameters_t *handshake = peer->handshake_params;
dtls_tick_t now;
- psk = is_psk_supported(ctx);
- ecdsa = is_ecdsa_supported(ctx, 1);
+ switch(ctx->selected_cipher)
+ {
+ case TLS_PSK_WITH_AES_128_CCM_8:
+ psk = is_psk_supported(ctx);
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ ecdsa = is_ecdsa_supported(ctx, 1);
+ x509 = is_x509_supported(ctx, 1);
+ break;
+ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256:
+ ecdh_anon = is_ecdh_anon_supported(ctx);
+ break;
+ case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256:
+ ecdhe_psk = is_ecdhe_psk_supported(ctx);
+ break;
+ default:
+ psk = is_psk_supported(ctx);
+ ecdsa = is_ecdsa_supported(ctx, 1);
+ ecdh_anon = is_ecdh_anon_supported(ctx);
+ ecdhe_psk = is_ecdhe_psk_supported(ctx);
+ x509 = is_x509_supported(ctx, 1);
+ break;
+ }
- cipher_size = 2 + ((ecdsa) ? 2 : 0) + ((psk) ? 2 : 0);
- extension_size = (ecdsa) ? 2 + 6 + 6 + 8 + 6: 0;
+ cipher_size = 2 + ((ecdsa || x509) ? 2 : 0) + (psk ? 2 : 0) + (ecdh_anon ? 2 : 0) + (ecdhe_psk ? 2 : 0);
+
+ /* Is extension needed? */
+ extension_size = (ecdsa || x509 || ecdhe_psk || ecdh_anon) ? 2 : 0;
+ /* Supported EC and Supported Point Formats */
+ extension_size += (ecdsa || x509 || ecdhe_psk | ecdh_anon) ? ( 8 + 6) : 0;
+ /* Supported Client and Server Cert Types */
+ extension_size += (ecdsa || x509) ? ( 6 + 6) : 0;
if (cipher_size == 0) {
dtls_crit("no cipher callbacks implemented\n");
dtls_int_to_uint16(p, cipher_size - 2);
p += sizeof(uint16);
- if (ecdsa) {
- dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
+ if (ecdh_anon) {
+ dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256);
p += sizeof(uint16);
}
if (psk) {
dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8);
p += sizeof(uint16);
}
+ if (ecdsa || x509) {
+ dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
+ p += sizeof(uint16);
+ }
+ if (ecdhe_psk) {
+ dtls_int_to_uint16(p, TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256);
+ p += sizeof(uint16);
+ }
/* compression method */
dtls_int_to_uint8(p, 1);
p += sizeof(uint16);
}
- if (ecdsa) {
+ if (ecdsa || x509) {
/* client certificate type extension */
dtls_int_to_uint16(p, TLS_EXT_CLIENT_CERTIFICATE_TYPE);
p += sizeof(uint16);
dtls_int_to_uint8(p, 1);
p += sizeof(uint8);
- dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY);
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ dtls_int_to_uint8(p, TLS_CERT_TYPE_X509);
+ else
+#endif /* DTLS_X509 */
+ dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY);
+
p += sizeof(uint8);
- /* client certificate type extension */
+ /* server certificate type extension */
dtls_int_to_uint16(p, TLS_EXT_SERVER_CERTIFICATE_TYPE);
p += sizeof(uint16);
dtls_int_to_uint8(p, 1);
p += sizeof(uint8);
- dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY);
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ dtls_int_to_uint8(p, TLS_CERT_TYPE_X509);
+ else
+#endif /* DTLS_X509 */
+ dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY);
+
p += sizeof(uint8);
+ }
+ if (ecdsa || x509 || ecdhe_psk || ecdh_anon ) {
/* elliptic_curves */
dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES);
p += sizeof(uint16);
}
#ifdef DTLS_ECC
+
static int
-check_server_certificate(dtls_context_t *ctx,
+check_peer_certificate(dtls_context_t *ctx,
dtls_peer_t *peer,
uint8 *data, size_t data_length)
{
data += DTLS_HS_LENGTH;
- if (dtls_uint24_to_int(data) != 94) {
- dtls_alert("expect length of 94 bytes for server certificate message\n");
- return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
- }
- data += sizeof(uint24);
-
- if (dtls_uint24_to_int(data) != 91) {
- dtls_alert("expect length of 91 bytes for certificate\n");
+ if (dtls_uint24_to_int(data) != DTLS_EC_SUBJECTPUBLICKEY_SIZE) {
+ dtls_alert("expect length of %d bytes for certificate\n",
+ DTLS_EC_SUBJECTPUBLICKEY_SIZE);
return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
}
data += sizeof(uint24);
}
data += sizeof(cert_asn1_header);
- memcpy(config->keyx.ecdsa.other_pub_x, data,
- sizeof(config->keyx.ecdsa.other_pub_x));
- data += sizeof(config->keyx.ecdsa.other_pub_x);
+ memcpy(config->keyx.ecc.other_pub_x, data,
+ sizeof(config->keyx.ecc.other_pub_x));
+ data += sizeof(config->keyx.ecc.other_pub_x);
- memcpy(config->keyx.ecdsa.other_pub_y, data,
- sizeof(config->keyx.ecdsa.other_pub_y));
- data += sizeof(config->keyx.ecdsa.other_pub_y);
+ memcpy(config->keyx.ecc.other_pub_y, data,
+ sizeof(config->keyx.ecc.other_pub_y));
+ data += sizeof(config->keyx.ecc.other_pub_y);
err = CALL(ctx, verify_ecdsa_key, &peer->session,
- config->keyx.ecdsa.other_pub_x,
- config->keyx.ecdsa.other_pub_y,
- sizeof(config->keyx.ecdsa.other_pub_x));
+ config->keyx.ecc.other_pub_x,
+ config->keyx.ecc.other_pub_y,
+ sizeof(config->keyx.ecc.other_pub_x));
if (err < 0) {
dtls_warn("The certificate was not accepted\n");
return err;
return 0;
}
+#endif /* DTLS_ECC */
+
+#ifdef DTLS_X509
+static int
+check_peer_certificate_x509(dtls_context_t *ctx,
+ dtls_peer_t *peer,
+ uint8 *data, size_t data_length)
+{
+ int ret;
+ dtls_handshake_parameters_t *config = peer->handshake_params;
+ int cert_length;
+
+ dtls_info("\n check_peer_certificate_x509\n");
+ update_hs_hash(peer, data, data_length);
+
+ assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(config->cipher));
+
+ data += DTLS_HS_LENGTH;
+
+ cert_length = dtls_uint24_to_int(data);
+ data += sizeof(uint24);
+
+ ret = CALL(ctx, verify_x509_cert, &peer->session, data, cert_length,
+ config->keyx.ecc.other_pub_x, sizeof(config->keyx.ecc.other_pub_x),
+ config->keyx.ecc.other_pub_y, sizeof(config->keyx.ecc.other_pub_y));
+ if (ret < 0) {
+ dtls_warn("The certificate was not accepted\n");
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* DTLS_X509 */
+#if defined(DTLS_X509) || defined(DTLS_ECC)
static int
check_server_key_exchange_ecdsa(dtls_context_t *ctx,
dtls_peer_t *peer,
data += sizeof(uint8);
data_length -= sizeof(uint8);
- memcpy(config->keyx.ecdsa.other_eph_pub_x, data, sizeof(config->keyx.ecdsa.other_eph_pub_y));
- data += sizeof(config->keyx.ecdsa.other_eph_pub_y);
- data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y);
+ memcpy(config->keyx.ecc.other_eph_pub_x, data, sizeof(config->keyx.ecc.other_eph_pub_y));
+ data += sizeof(config->keyx.ecc.other_eph_pub_y);
+ data_length -= sizeof(config->keyx.ecc.other_eph_pub_y);
- memcpy(config->keyx.ecdsa.other_eph_pub_y, data, sizeof(config->keyx.ecdsa.other_eph_pub_y));
- data += sizeof(config->keyx.ecdsa.other_eph_pub_y);
- data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y);
+ memcpy(config->keyx.ecc.other_eph_pub_y, data, sizeof(config->keyx.ecc.other_eph_pub_y));
+ data += sizeof(config->keyx.ecc.other_eph_pub_y);
+ data_length -= sizeof(config->keyx.ecc.other_eph_pub_y);
ret = dtls_check_ecdsa_signature_elem(data, data_length, &result_r, &result_s);
if (ret < 0) {
data += ret;
data_length -= ret;
- ret = dtls_ecdsa_verify_sig(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y,
- sizeof(config->keyx.ecdsa.other_pub_x),
- config->tmp.random.client, DTLS_RANDOM_LENGTH,
- config->tmp.random.server, DTLS_RANDOM_LENGTH,
- key_params,
- 1 + 2 + 1 + 1 + (2 * DTLS_EC_KEY_SIZE),
- result_r, result_s);
+ ret = dtls_ecdsa_verify_sig(config->keyx.ecc.other_pub_x, config->keyx.ecc.other_pub_y,
+ sizeof(config->keyx.ecc.other_pub_x),
+ config->tmp.random.client, DTLS_RANDOM_LENGTH,
+ config->tmp.random.server, DTLS_RANDOM_LENGTH,
+ key_params,
+ 1 + 2 + 1 + 1 + (2 * DTLS_EC_KEY_SIZE),
+ result_r, result_s);
- if (ret < 0) {
+ if (ret <= 0) {
dtls_alert("wrong signature\n");
return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
}
return 0;
}
+
+static int
+check_server_key_exchange_ecdh(dtls_context_t *ctx,
+ dtls_peer_t *peer,
+ uint8 *data, size_t data_length)
+{
+ dtls_handshake_parameters_t *config = peer->handshake_params;
+
+ update_hs_hash(peer, data, data_length);
+
+ assert(is_tls_ecdh_anon_with_aes_128_cbc_sha_256(config->cipher));
+
+ data += DTLS_HS_LENGTH;
+
+ if (data_length < DTLS_HS_LENGTH + DTLS_SKEXEC_ECDH_ANON_LENGTH) {
+ dtls_alert("the packet length does not match the expected\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
+ }
+
+ if (dtls_uint8_to_int(data) != TLS_EC_CURVE_TYPE_NAMED_CURVE) {
+ dtls_alert("Only named curves supported\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += sizeof(uint8);
+ data_length -= sizeof(uint8);
+
+ if (dtls_uint16_to_int(data) != TLS_EXT_ELLIPTIC_CURVES_SECP256R1) {
+ dtls_alert("secp256r1 supported\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += sizeof(uint16);
+ data_length -= sizeof(uint16);
+
+ if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) {
+ dtls_alert("expected 65 bytes long public point\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += sizeof(uint8);
+ data_length -= sizeof(uint8);
+
+ if (dtls_uint8_to_int(data) != 4) {
+ dtls_alert("expected uncompressed public point\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
+ }
+ data += sizeof(uint8);
+ data_length -= sizeof(uint8);
+
+ memcpy(config->keyx.ecc.other_eph_pub_x, data, sizeof(config->keyx.ecc.other_eph_pub_x));
+ data += sizeof(config->keyx.ecc.other_eph_pub_x);
+ data_length -= sizeof(config->keyx.ecc.other_eph_pub_x);
+
+ memcpy(config->keyx.ecc.other_eph_pub_y, data, sizeof(config->keyx.ecc.other_eph_pub_y));
+ data += sizeof(config->keyx.ecc.other_eph_pub_y);
+ data_length -= sizeof(config->keyx.ecc.other_eph_pub_y);
+
+ return 0;
+}
#endif /* DTLS_ECC */
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+check_server_key_exchange_ecdhe_psk(dtls_context_t *ctx,
+ dtls_peer_t *peer,
+ uint8 *data, size_t data_length)
+{
+ dtls_handshake_parameters_t *config = peer->handshake_params;
+ uint16_t psk_len = 0;
+
+ /* ServerKeyExchange
+ * Please see Session 2, RFC 5489.
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ //other cases for rsa, diffie_hellman, etc.
+ case ec_diffie_hellman_psk: // NEW
+ opaque psk_identity_hint<0..2^16-1>;
+ ServerECDHParams params;
+ };
+ } ServerKeyExchange; */
+
+ update_hs_hash(peer, data, data_length);
+
+ assert(is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(config->cipher));
+
+ data += DTLS_HS_LENGTH;
+
+ psk_len = dtls_uint16_to_int(data);
+ data += sizeof(uint16);
+
+ if (psk_len != data_length - DTLS_HS_LENGTH - DTLS_SKEXEC_ECDH_ANON_LENGTH - sizeof(uint16)) {
+ dtls_warn("the length of the server identity hint is worng\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
+ }
+
+ if (psk_len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) {
+ dtls_warn("please use a smaller server identity hint\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
+ }
+
+ // store the psk_identity_hint in config->keyx.psk for later use
+ config->keyx.psk.id_length = psk_len;
+ memcpy(config->keyx.psk.identity, data, psk_len);
+
+ data += psk_len;
+ data_length -= psk_len;
+
+ if (data_length < DTLS_HS_LENGTH + DTLS_SKEXEC_ECDH_ANON_LENGTH) {
+ dtls_alert("the packet length does not match the expected\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
+ }
+
+ if (dtls_uint8_to_int(data) != TLS_EC_CURVE_TYPE_NAMED_CURVE) {
+ dtls_alert("Only named curves supported\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += sizeof(uint8);
+ data_length -= sizeof(uint8);
+
+ if (dtls_uint16_to_int(data) != TLS_EXT_ELLIPTIC_CURVES_SECP256R1) {
+ dtls_alert("secp256r1 supported\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += sizeof(uint16);
+ data_length -= sizeof(uint16);
+
+ if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) {
+ dtls_alert("expected 65 bytes long public point\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
+ }
+ data += sizeof(uint8);
+ data_length -= sizeof(uint8);
+
+ if (dtls_uint8_to_int(data) != 4) {
+ dtls_alert("expected uncompressed public point\n");
+ return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
+ }
+ data += sizeof(uint8);
+ data_length -= sizeof(uint8);
+
+ memcpy(config->keyx.ecc.other_eph_pub_x, data, sizeof(config->keyx.ecc.other_eph_pub_x));
+ data += sizeof(config->keyx.ecc.other_eph_pub_x);
+ data_length -= sizeof(config->keyx.ecc.other_eph_pub_x);
+
+ memcpy(config->keyx.ecc.other_eph_pub_y, data, sizeof(config->keyx.ecc.other_eph_pub_y));
+ data += sizeof(config->keyx.ecc.other_eph_pub_y);
+ data_length -= sizeof(config->keyx.ecc.other_eph_pub_y);
+
+ return 0;
+}
+#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */
#ifdef DTLS_PSK
static int
}
static int
-check_server_hellodone(dtls_context_t *ctx,
+check_server_hellodone(dtls_context_t *ctx,
dtls_peer_t *peer,
uint8 *data, size_t data_length)
{
- int res;
+ int res = 0;
#ifdef DTLS_ECC
- const dtls_ecdsa_key_t *ecdsa_key;
+ const dtls_ecc_key_t *ecdsa_key;
+#ifdef DTLS_X509
+ unsigned char *cert;
+ size_t cert_size;
+#endif /* DTLS_X509 */
#endif /* DTLS_ECC */
dtls_handshake_parameters_t *handshake = peer->handshake_params;
update_hs_hash(peer, data, data_length);
-#ifdef DTLS_ECC
- if (handshake->do_client_auth) {
-
- res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key);
+#if defined(DTLS_ECC) || defined(DTLS_X509)
+ if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) {
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ res = CALL(ctx, get_x509_key, &peer->session, &ecdsa_key);
+ else
+#endif /* DTLS_X509 */
+ res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key);
if (res < 0) {
- dtls_crit("no ecdsa certificate to send in certificate\n");
+ dtls_crit("no ecdsa key to use\n");
return res;
}
- res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key);
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ res = dtls_send_certificate_x509(ctx, peer);
+ else
+#endif /* DTLS_X509 */
+ res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key);
if (res < 0) {
dtls_debug("dtls_server_hello: cannot prepare Certificate record\n");
}
#ifdef DTLS_ECC
- if (handshake->do_client_auth) {
-
+ if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) {
res = dtls_send_certificate_verify_ecdh(ctx, peer, ecdsa_key);
if (res < 0) {
if (security->cipher == TLS_NULL_WITH_NULL_NULL) {
/* no cipher suite selected */
return clen;
+ } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher) ||
+ is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(security->cipher)) {
+
+ unsigned char nonce[DTLS_CBC_IV_LENGTH];
+
+ if (clen < (DTLS_CBC_IV_LENGTH + DTLS_HMAC_DIGEST_SIZE)) /* need at least IV and MAC */
+ return -1;
+
+ memcpy(nonce, *cleartext , DTLS_CBC_IV_LENGTH);
+ clen -= DTLS_CBC_IV_LENGTH;
+ *cleartext += DTLS_CBC_IV_LENGTH ;
+
+ clen = dtls_decrypt(*cleartext, clen, *cleartext, nonce,
+ dtls_kb_remote_write_key(security, peer->role),
+ dtls_kb_key_size(security, peer->role),
+ dtls_kb_remote_mac_secret(security, peer->role),
+ dtls_kb_mac_secret_size(security->cipher),
+ NULL, 0,
+ security->cipher);
+
} else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */
/**
* length of additional_data for the AEAD cipher which consists of
memset(nonce, 0, DTLS_CCM_BLOCKSIZE);
memcpy(nonce, dtls_kb_remote_iv(security, peer->role),
- dtls_kb_iv_size(security, peer->role));
+ dtls_kb_iv_size(security->cipher));
/* read epoch and seq_num from message */
- memcpy(nonce + dtls_kb_iv_size(security, peer->role), *cleartext, 8);
+ memcpy(nonce + dtls_kb_iv_size(security->cipher), *cleartext, 8);
*cleartext += 8;
clen -= 8;
clen = dtls_decrypt(*cleartext, clen, *cleartext, nonce,
dtls_kb_remote_write_key(security, peer->role),
dtls_kb_key_size(security, peer->role),
- A_DATA, A_DATA_LEN);
- if (clen < 0)
- dtls_warn("decryption failed\n");
- else {
+ dtls_kb_remote_mac_secret(security, peer->role),
+ dtls_kb_mac_secret_size(security->cipher),
+ A_DATA, A_DATA_LEN,
+ security->cipher);
+ }
+
+ if (clen < 0)
+ dtls_warn("decryption failed\n");
+ else {
#ifndef NDEBUG
- printf("decrypt_verify(): found %i bytes cleartext\n", clen);
+ dtls_debug("decrypt_verify(): found %i bytes cleartext\n", clen);
#endif
- dtls_security_params_free_other(peer);
- dtls_debug_dump("cleartext", *cleartext, clen);
- }
+ dtls_security_params_free_other(peer);
+ dtls_debug_dump("cleartext", *cleartext, clen);
}
+
return clen;
}
return err;
}
if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher))
- peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE;
+ peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; //ecdsa
+ else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher) ||
+ is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher))
+ peer->state = DTLS_STATE_WAIT_SERVERKEYEXCHANGE; //ecdh
else
- peer->state = DTLS_STATE_WAIT_SERVERHELLODONE;
+ peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; //psk
/* update_hs_hash(peer, data, data_length); */
break;
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
case DTLS_HT_CERTIFICATE:
if ((role == DTLS_CLIENT && state != DTLS_STATE_WAIT_SERVERCERTIFICATE) ||
(role == DTLS_SERVER && state != DTLS_STATE_WAIT_CLIENTCERTIFICATE)) {
return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE);
}
- err = check_server_certificate(ctx, peer, data, data_length);
+#ifdef DTLS_X509
+ if (CALL(ctx, is_x509_active) == 0)
+ err = check_peer_certificate_x509(ctx, peer, data, data_length);
+ else
+#endif /* DTLS_X509 */
+ err = check_peer_certificate(ctx, peer, data, data_length);
if (err < 0) {
- dtls_warn("error in check_server_certificate err: %i\n", err);
+ dtls_warn("error in check_peer_certificate err: %i\n", err);
return err;
}
if (role == DTLS_CLIENT) {
case DTLS_HT_SERVER_KEY_EXCHANGE:
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) {
if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) {
return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE);
}
err = check_server_key_exchange_ecdsa(ctx, peer, data, data_length);
}
+
+ if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) {
+ if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) {
+ return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE);
+ }
+ err = check_server_key_exchange_ecdh(ctx, peer, data, data_length);
+ }
#endif /* DTLS_ECC */
+
+#if defined(DTLS_PSK) && defined(DTLS_ECC)
+ if (is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) {
+ if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) {
+ return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE);
+ }
+ err = check_server_key_exchange_ecdhe_psk(ctx, peer, data, data_length);
+ }
+#endif defined(DTLS_PSK) && defined(DTLS_ECC)
+
#ifdef DTLS_PSK
if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) {
if (state != DTLS_STATE_WAIT_SERVERHELLODONE) {
update_hs_hash(peer, data, data_length);
if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) &&
- is_ecdsa_client_auth_supported(ctx))
- peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY;
+ (is_ecdsa_client_auth_supported(ctx) || (is_x509_client_auth_supported(ctx))))
+ peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; //ecdsa
else
- peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC;
+ peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC; //psk || ecdh_anon
break;
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
case DTLS_HT_CERTIFICATE_VERIFY:
if (state != DTLS_STATE_WAIT_CERTIFICATEVERIFY) {
return err;
}
if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) &&
- is_ecdsa_client_auth_supported(ctx))
- peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE;
+ (is_ecdsa_client_auth_supported(ctx) || (is_x509_client_auth_supported(ctx))))
+ peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; //ecdhe
else
- peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE;
+ peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; //psk, ecdh_anon
/* after sending the ServerHelloDone, we expect the
* ClientKeyExchange (possibly containing the PSK id),
uint8 *record_header, uint8 *data, size_t data_length)
{
int err;
- dtls_handshake_parameters_t *handshake = peer->handshake_params;
/* A CCS message is handled after a KeyExchange message was
* received from the client. When security parameters have been
if (data_length < 1 || data[0] != 1)
return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
+ dtls_handshake_parameters_t *handshake = peer->handshake_params;
/* Just change the cipher when we are on the same epoch */
if (peer->role == DTLS_SERVER) {
err = calculate_key_block(ctx, handshake, peer,
data = msg + DTLS_RH_LENGTH;
data_length = rlen - DTLS_RH_LENGTH;
state = DTLS_STATE_WAIT_CLIENTHELLO;
- role = DTLS_SERVER;
+ role = DTLS_SERVER;
} else {
int err = dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
dtls_info("decrypt_verify() failed\n");
if (peer->state < DTLS_STATE_CONNECTED) {
dtls_alert_send_from_err(ctx, peer, &peer->session, err);
+
+ (void)CALL(ctx, event, &peer->session,
+ DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_HANDSHAKE_FAILURE);
+
peer->state = DTLS_STATE_CLOSED;
/* dtls_stop_retransmission(ctx, peer); */
dtls_destroy_peer(ctx, peer, 1);
if (err < 0) {
dtls_warn("error while handling ChangeCipherSpec message\n");
dtls_alert_send_from_err(ctx, peer, session, err);
+ if (peer) {
+ (void)CALL(ctx, event, &peer->session,
+ DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_HANDSHAKE_FAILURE);
- /* invalidate peer */
- dtls_destroy_peer(ctx, peer, 1);
- peer = NULL;
-
+ /* invalidate peer */
+ dtls_destroy_peer(ctx, peer, 1);
+ peer = NULL;
+ }
return err;
}
break;
if (err < 0) {
dtls_warn("error while handling handshake packet\n");
dtls_alert_send_from_err(ctx, peer, session, err);
+
+ if (peer) {
+ (void)CALL(ctx, event, &peer->session,
+ DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_HANDSHAKE_FAILURE);
+ dtls_destroy_peer(ctx, peer, 1);
+ }
+
return err;
}
if (peer && peer->state == DTLS_STATE_CONNECTED) {
if (fread(buf, 1, sizeof(buf), urandom) != sizeof(buf)) {
dtls_emerg("cannot initialize PRNG\n");
+ fclose(urandom);
return NULL;
}
res = dtls_send_client_hello(ctx, peer, NULL, 0);
if (res < 0)
dtls_warn("cannot send ClientHello\n");
- else
+ else
peer->state = DTLS_STATE_CLIENTHELLO;
return res;
*next = node->t;
}
+size_t
+dtls_prf_with_current_keyblock(dtls_context_t *ctx, session_t *session,
+ const uint8_t* label, const uint32_t labellen,
+ const uint8_t* random1, const uint32_t random1len,
+ const uint8_t* random2, const uint32_t random2len,
+ uint8_t* buf, const uint32_t buflen) {
+ dtls_peer_t *peer = NULL;
+ dtls_security_parameters_t *security = NULL;
+ size_t keysize = 0;
+
+ if(!ctx || !session || !label || !buf || labellen == 0 || buflen == 0) {
+ dtls_warn("dtls_prf_with_current_keyblock(): invalid parameter\n");
+ return 0;
+ }
+
+ peer = dtls_get_peer(ctx, session);
+ if (!peer) {
+ dtls_warn("dtls_prf_with_current_keyblock(): cannot find peer\n");
+ return 0;
+ }
+
+ security = dtls_security_params(peer);
+ if (!security) {
+ dtls_crit("dtls_prf_with_current_keyblock(): peer has empty security parameters\n");
+ return 0;
+ }
+
+ /* note that keysize should never be zero as bad things will happen */
+ keysize = dtls_kb_size(security, peer->role);
+ assert(keysize > 0);
+
+ return dtls_prf(security->key_block, keysize,
+ label, labellen,
+ random1, random1len,
+ random2, random2len,
+ buf, buflen);
+}
+
#ifdef WITH_CONTIKI
/*---------------------------------------------------------------------------*/
/* message retransmission */