Remove unused pkg dependancy
[platform/upstream/iotivity.git] / extlibs / tinydtls / dtls.c
index 41e68a5..5f2e400 100644 (file)
@@ -138,23 +138,23 @@ PROCESS(dtls_retransmit_process, "DTLS retransmit process");
 
 static dtls_context_t the_dtls_context;
 
-static inline dtls_context_t *
+INLINE_API dtls_context_t *
 malloc_context() {
   return &the_dtls_context;
 }
 
-static inline void
+INLINE_API void
 free_context(dtls_context_t *context) {
 }
 
 #else /* WITH_CONTIKI */
 
-static inline dtls_context_t *
+INLINE_API dtls_context_t *
 malloc_context() {
   return (dtls_context_t *)malloc(sizeof(dtls_context_t));
 }
 
-static inline void
+INLINE_API void
 free_context(dtls_context_t *context) {
   free(context);
 }
@@ -227,6 +227,16 @@ dtls_send(dtls_context_t *ctx, dtls_peer_t *peer, unsigned char type,
  */
 static void dtls_stop_retransmission(dtls_context_t *context, dtls_peer_t *peer);
 
+/**
+ * Starts retransmissions of handshake messages for @p peer.
+ */
+static void dtls_start_retransmission(dtls_context_t *context, dtls_peer_t *peer);
+
+/**
+ * Clears retransmissions of handshake messages for @p peer.
+ */
+static void dtls_clear_retransmission(dtls_context_t *context, dtls_peer_t *peer);
+
 dtls_peer_t *
 dtls_get_peer(const dtls_context_t *ctx, const session_t *session) {
   dtls_peer_t *p = NULL;
@@ -307,7 +317,8 @@ dtls_create_cookie(dtls_context_t *ctx,
                   uint8 *msg, size_t msglen,
                   uint8 *cookie, int *clen) {
   unsigned char buf[DTLS_HMAC_MAX];
-  size_t len, e;
+  int len;
+  size_t e;
 
   /* create cookie with HMAC-SHA256 over:
    * - SECRET
@@ -405,7 +416,7 @@ is_record(uint8 *msg, size_t msglen) {
  * \return pointer to the next byte after the written header.
  * The length will be set to 0 and has to be changed before sending.
  */ 
-static inline uint8 *
+INLINE_API uint8 *
 dtls_set_record_header(uint8 type, dtls_security_parameters_t *security,
                       uint8 *buf) {
   
@@ -439,7 +450,7 @@ dtls_set_record_header(uint8 type, dtls_security_parameters_t *security,
  * bytes. Increments message sequence number counter of \p peer.
  * \return pointer to the next byte after \p buf
  */ 
-static inline uint8 *
+INLINE_API uint8 *
 dtls_set_handshake_header(uint8 type, dtls_peer_t *peer, 
                          int length, 
                          int frag_offset, int frag_length, 
@@ -477,9 +488,9 @@ static uint8 compression_methods[] = {
 };
 
 /** 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)
+INLINE_API 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;
@@ -487,7 +498,7 @@ static inline int is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(dtls_cipher_t cipher)
 }
 
 /** returns true if the cipher matches TLS_PSK_WITH_AES_128_CCM_8 */
-static inline int is_tls_psk_with_aes_128_ccm_8(dtls_cipher_t cipher)
+INLINE_API int is_tls_psk_with_aes_128_ccm_8(dtls_cipher_t cipher)
 {
 #ifdef DTLS_PSK
   return cipher == TLS_PSK_WITH_AES_128_CCM_8;
@@ -496,19 +507,30 @@ static inline int is_tls_psk_with_aes_128_ccm_8(dtls_cipher_t cipher)
 #endif /* DTLS_PSK */
 }
 
-/** returns true if the cipher matches TLS_ECDH_anon_WITH_AES_128_CBC_SHA */
-static inline int is_tls_ecdh_anon_with_aes_128_cbc_sha(dtls_cipher_t cipher)
+/** returns true if the cipher matches TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 */
+INLINE_API 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;
+    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 */
+INLINE_API 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)
+INLINE_API int is_psk_supported(dtls_context_t *ctx)
 {
 #ifdef DTLS_PSK
   return ctx && ctx->h && ctx->h->get_psk_info;
@@ -518,19 +540,30 @@ static inline int is_psk_supported(dtls_context_t *ctx)
 }
 
 /** returns true if the application is configured for ecdhe_ecdsa */
-static inline int is_ecdsa_supported(dtls_context_t *ctx, int is_client)
+INLINE_API 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 */
+INLINE_API 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)
+INLINE_API int is_ecdsa_client_auth_supported(dtls_context_t *ctx)
 {
 #ifdef DTLS_ECC
   return ctx && ctx->h && ctx->h->get_ecdsa_key && ctx->h->verify_ecdsa_key;
@@ -539,8 +572,19 @@ 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 */
+INLINE_API 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)
+INLINE_API int is_ecdh_anon_supported(dtls_context_t *ctx)
 {
 #ifdef DTLS_ECC
     return ctx &&  (ctx->is_anon_ecdh_eabled == DTLS_CIPHER_ENABLE);
@@ -549,6 +593,17 @@ static inline int is_ecdh_anon_supported(dtls_context_t *ctx)
 #endif
 }
 
+/** returns true if ecdhe_psk_with_aes_128_cbc_sha_256 is supported */
+INLINE_API 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.
@@ -563,14 +618,20 @@ 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)) ||
-        (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha(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));
 }
 
 /**
@@ -610,11 +671,11 @@ static void dtls_debug_keyblock(dtls_security_parameters_t *config)
   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),
@@ -626,11 +687,11 @@ static void dtls_debug_keyblock(dtls_security_parameters_t *config)
 
   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.
@@ -676,7 +737,11 @@ calculate_key_block(dtls_context_t *ctx,
                    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];
@@ -685,8 +750,6 @@ calculate_key_block(dtls_context_t *ctx,
     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: {
@@ -717,9 +780,9 @@ calculate_key_block(dtls_context_t *ctx,
     break;
   }
 #endif /* DTLS_PSK */
-#ifdef DTLS_ECC
+#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: {
+  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,
@@ -733,6 +796,35 @@ calculate_key_block(dtls_context_t *ctx,
     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);
@@ -754,6 +846,9 @@ calculate_key_block(dtls_context_t *ctx,
   /* 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,
@@ -766,9 +861,6 @@ calculate_key_block(dtls_context_t *ctx,
   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;
 }
@@ -814,8 +906,13 @@ static int verify_ext_cert_type(uint8 *data, size_t data_length) {
     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");
@@ -906,7 +1003,12 @@ dtls_check_tls_extension(dtls_peer_t *peer,
          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;
@@ -916,7 +1018,12 @@ dtls_check_tls_extension(dtls_peer_t *peer,
          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;
@@ -976,7 +1083,8 @@ static int
 dtls_update_parameters(dtls_context_t *ctx, 
                       dtls_peer_t *peer,
                       uint8 *data, size_t data_length) {
-  int i, j;
+  int i;
+  unsigned int j;
   int ok;
   dtls_handshake_parameters_t *config = peer->handshake_params;
   dtls_security_parameters_t *security = dtls_security_params(peer);
@@ -1077,14 +1185,14 @@ error:
  * Parse the ClientKeyExchange and update the internal handshake state with
  * the new data.
  */
-static inline int
+INLINE_API int
 check_client_keyexchange(dtls_context_t *ctx, 
                         dtls_handshake_parameters_t *handshake,
                         uint8 *data, size_t length) {
 
-#ifdef DTLS_ECC
+#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(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");
@@ -1113,6 +1221,56 @@ check_client_keyexchange(dtls_context_t *ctx,
     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;
@@ -1143,7 +1301,7 @@ check_client_keyexchange(dtls_context_t *ctx,
   return 0;
 }
 
-static inline void
+INLINE_API void
 update_hs_hash(dtls_peer_t *peer, uint8 *data, size_t length) {
   dtls_debug_dump("add MAC data", data, length);
   dtls_hash_update(&peer->handshake_params->hs_state.hs_hash, data, length);
@@ -1155,12 +1313,12 @@ copy_hs_hash(dtls_peer_t *peer, dtls_hash_ctx *hs_hash) {
         sizeof(peer->handshake_params->hs_state.hs_hash));
 }
 
-static inline size_t
+INLINE_API size_t
 finalize_hs_hash(dtls_peer_t *peer, uint8 *buf) {
   return dtls_hash_finalize(buf, &peer->handshake_params->hs_state.hs_hash);
 }
 
-static inline void
+INLINE_API void
 clear_hs_hash(dtls_peer_t *peer) {
   assert(peer);
   dtls_debug("clear MAC\n");
@@ -1286,6 +1444,54 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security,
       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
@@ -1299,8 +1505,6 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security,
       dtls_debug("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_8\n");
     } else if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(security->cipher)) {
       dtls_debug("dtls_prepare_record(): encrypt using TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n");
-    } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha(security->cipher)) {
-        dtls_debug("dtls_prepare_record() : encrypt using TLS_ECDH_anon_WITH_AES_128_CBC_SHA\n");
     } else {
       dtls_debug("dtls_prepare_record(): encrypt using unknown cipher\n");
     }
@@ -1363,8 +1567,8 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security,
 
     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),
@@ -1378,17 +1582,19 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security,
     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),
+               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);
   }
 
@@ -1561,7 +1767,7 @@ dtls_send_multi(dtls_context_t *ctx, dtls_peer_t *peer,
   return res <= 0 ? res : overall_len - (len - res);
 }
 
-static inline int
+INLINE_API int
 dtls_send_alert(dtls_context_t *ctx, dtls_peer_t *peer, dtls_alert_level_t level,
                dtls_alert_t description) {
   uint8_t msg[] = { level, description };
@@ -1690,7 +1896,7 @@ dtls_verify_peer(dtls_context_t *ctx,
 #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,
@@ -1804,11 +2010,11 @@ check_client_certificate_verify(dtls_context_t *ctx,
   dtls_hash_finalize(sha256hash, &hs_hash);
 
   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);
+                                   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);
   }
@@ -1874,8 +2080,13 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer)
     /* 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 */
@@ -1886,7 +2097,13 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer)
     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 */
@@ -1914,6 +2131,8 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer)
 }
 
 #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_ecc_key_t *key)
@@ -1921,17 +2140,15 @@ dtls_send_certificate_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer,
   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);
 
@@ -1946,7 +2163,46 @@ dtls_send_certificate_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer,
   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)
 {
@@ -2053,7 +2309,6 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer,
   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,
@@ -2070,7 +2325,81 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer,
   return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE,
                                 buf, p - buf);
 }
-#endif /* DTLS_ECC */
+#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 /* defined(DTLS_PSK) && defined(DTLS_ECC) */
 
 #ifdef DTLS_PSK
 static int
@@ -2102,7 +2431,7 @@ dtls_send_server_key_exchange_psk(dtls_context_t *ctx, dtls_peer_t *peer,
 }
 #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)
 {
@@ -2163,6 +2492,7 @@ 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);
 
@@ -2172,9 +2502,10 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer)
   }
 
   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(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);
 
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
   if(ecdh_anon) {
       res = dtls_send_server_key_exchange_ecdh(ctx, peer, NULL);
 
@@ -2186,13 +2517,24 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer)
   else if (ecdsa) {
     const dtls_ecc_key_t *ecdsa_key;
 
-    res = CALL(ctx, get_ecdsa_key, &peer->session, &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);
+
     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");
@@ -2207,9 +2549,8 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer)
     }
 
     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(with ECDSA): cannot prepare certificate Request record\n");
         return res;
@@ -2217,7 +2558,31 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer)
     }
   }
 #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];
@@ -2253,7 +2618,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer)
   return 0;
 }
 
-static inline int 
+INLINE_API int 
 dtls_send_ccs(dtls_context_t *ctx, dtls_peer_t *peer) {
   uint8 buf[1] = {1};
 
@@ -2264,7 +2629,11 @@ dtls_send_ccs(dtls_context_t *ctx, dtls_peer_t *peer) {
 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;
@@ -2299,9 +2668,9 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer)
     break;
   }
 #endif /* DTLS_PSK */
-#ifdef DTLS_ECC
+#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: {
+  case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: {
     uint8 *ephemeral_pub_x;
     uint8 *ephemeral_pub_y;
 
@@ -2324,6 +2693,60 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer)
     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);
@@ -2335,7 +2758,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer)
                                 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_ecc_key_t *key)
@@ -2408,11 +2831,13 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer,
                        uint8 cookie[], size_t cookie_length) {
   uint8 buf[DTLS_CH_LENGTH_MAX];
   uint8 *p = buf;
-  uint8_t cipher_size;
-  uint8_t extension_size;
+  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;
 
@@ -2423,19 +2848,31 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer,
         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:
+      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) + (ecdh_anon ? 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");
@@ -2478,17 +2915,21 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer,
   p += sizeof(uint16);
 
   if (ecdh_anon) {
-    dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA);
+    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) {
+  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);
@@ -2503,7 +2944,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer,
     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);
@@ -2516,10 +2957,16 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer,
     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);
 
@@ -2531,9 +2978,17 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer,
     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);
@@ -2667,8 +3122,9 @@ check_server_hello_verify_request(dtls_context_t *ctx,
 }
 
 #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)
 {
@@ -2681,14 +3137,9 @@ check_server_certificate(dtls_context_t *ctx,
 
   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);
@@ -2718,7 +3169,41 @@ check_server_certificate(dtls_context_t *ctx,
 
   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,
@@ -2786,14 +3271,14 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx,
   data_length -= ret;
 
   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) {
+                              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) {
     dtls_alert("wrong signature\n");
     return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
   }
@@ -2809,7 +3294,7 @@ check_server_key_exchange_ecdh(dtls_context_t *ctx,
 
   update_hs_hash(peer, data, data_length);
 
-  assert(is_tls_ecdh_anon_with_aes_128_cbc_sha(config->cipher));
+  assert(is_tls_ecdh_anon_with_aes_128_cbc_sha_256(config->cipher));
 
   data += DTLS_HS_LENGTH;
 
@@ -2856,8 +3341,97 @@ check_server_key_exchange_ecdh(dtls_context_t *ctx,
 
   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
@@ -2978,13 +3552,17 @@ check_certificate_request(dtls_context_t *ctx,
 }
 
 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_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;
@@ -2993,16 +3571,25 @@ check_server_hellodone(dtls_context_t *ctx,
 
   update_hs_hash(peer, data, data_length);
 
-#ifdef DTLS_ECC
+#if defined(DTLS_ECC) || defined(DTLS_X509)
   if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) {
-
-    res = CALL(ctx, get_ecdsa_key, &peer->session, &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);
     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");
@@ -3021,7 +3608,6 @@ check_server_hellodone(dtls_context_t *ctx,
 
 #ifdef DTLS_ECC
   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) {
@@ -3069,6 +3655,26 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length,
   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
@@ -3083,10 +3689,10 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length,
 
     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;
 
@@ -3107,18 +3713,22 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t 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),
                       A_DATA, A_DATA_LEN,
-               security->cipher);
-    if (clen < 0)
-      dtls_warn("decryption failed\n");
-    else {
+                      security->cipher);
+  }
+
+  if (clen < 0)
+    dtls_warn("decryption failed\n");
+  else {
 #ifndef NDEBUG
-      dtls_debug("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;
 }
 
@@ -3179,7 +3789,11 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
    * we do everything accordingly to the DTLS 1.2 standard this should
    * not be a problem. */
   if (peer) {
-    dtls_stop_retransmission(ctx, peer);
+    dtls_handshake_header_t *hs_header = DTLS_HANDSHAKE_HEADER(data);
+    if (state == DTLS_STATE_WAIT_CHANGECIPHERSPEC && hs_header->msg_type ==  DTLS_HT_FINISHED) {
+      return 0;
+    }
+    dtls_clear_retransmission(ctx, peer);
   }
 
   /* The following switch construct handles the given message with
@@ -3219,7 +3833,8 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
     }
     if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher))
       peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; //ecdsa
-    else if (is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher))
+    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; //psk
@@ -3227,16 +3842,21 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
 
     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) {
@@ -3251,7 +3871,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
 
   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);
@@ -3259,13 +3879,23 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
       err = check_server_key_exchange_ecdsa(ctx, peer, data, data_length);
     }
 
-    if (is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher)) {
+    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) {
@@ -3373,13 +4003,13 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
     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))
+            (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; //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) {
@@ -3496,7 +4126,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
       return err;
     }
     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))))
       peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; //ecdhe
     else
       peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; //psk, ecdh_anon
@@ -3580,6 +4210,18 @@ handle_handshake(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
       return 0;
     }
   }
+  /* This is a ClientHello send when doing retransmission */
+  if (peer && hs_header->msg_type == DTLS_HT_CLIENT_HELLO &&
+              dtls_uint16_to_int(hs_header->message_seq) == 0) {
+     res = dtls_verify_peer(ctx, peer, session, state, data, data_length);
+     if (res < 0) {
+       dtls_warn("error in dtls_verify_peer err: %i\n", res);
+     }
+     if (res > 0) {
+       dtls_debug("server hello verify was sent\n");
+     }
+     return res;
+  }
 
   if (dtls_uint16_to_int(hs_header->message_seq) < peer->handshake_params->hs_state.mseq_r) {
     dtls_warn("The message sequence number is too small, expected %i, got: %i\n",
@@ -3661,7 +4303,7 @@ handle_ccs(dtls_context_t *ctx, dtls_peer_t *peer,
           uint8 *record_header, uint8 *data, size_t data_length)
 {
   int err;
-  dtls_handshake_parameters_t *handshake = peer->handshake_params;
+  dtls_handshake_parameters_t *handshake;
 
   /* A CCS message is handled after a KeyExchange message was
    * received from the client. When security parameters have been
@@ -3677,6 +4319,7 @@ handle_ccs(dtls_context_t *ctx, dtls_peer_t *peer,
   if (data_length < 1 || data[0] != 1)
     return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
 
+  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,
@@ -3752,7 +4395,7 @@ handle_alert(dtls_context_t *ctx, dtls_peer_t *peer,
   }
   
   if (free_peer) {
-    dtls_stop_retransmission(ctx, peer);
+    dtls_clear_retransmission(ctx, peer);
     dtls_destroy_peer(ctx, peer, 0);
   }
 
@@ -3823,21 +4466,30 @@ dtls_handle_message(dtls_context_t *ctx,
           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) {
+         if (DTLS_CT_HANDSHAKE == msg[0] && DTLS_STATE_WAIT_FINISHED == peer->state) {
+           int err =  dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
+           dtls_info("decrypt_verify() failed\n");
+
            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_clear_retransmission(ctx, peer); */
            dtls_destroy_peer(ctx, peer, 1);
+           return err;
+         } else {
+           data = msg + DTLS_RH_LENGTH;
+           data_length = rlen - DTLS_RH_LENGTH;
+           role = peer->role;
+           state = peer->state;
          }
-          return err;
-        }
+       }
       } else {
-        role = peer->role;
-        state = peer->state;
+       role = peer->role;
+       state = peer->state;
       }
     } else {
       /* is_record() ensures that msg contains at least a record header */
@@ -3858,25 +4510,26 @@ dtls_handle_message(dtls_context_t *ctx,
     switch (msg[0]) {
 
     case DTLS_CT_CHANGE_CIPHER_SPEC:
-      if (peer) {
-        dtls_stop_retransmission(ctx, peer);
-      }
       err = handle_ccs(ctx, peer, msg, data, data_length);
       if (err < 0) {
        dtls_warn("error while handling ChangeCipherSpec message\n");
        dtls_alert_send_from_err(ctx, peer, session, err);
-
-       /* invalidate peer */
-       dtls_destroy_peer(ctx, peer, 1);
-       peer = NULL;
-
+        if (peer) {
+         (void)CALL(ctx, event, &peer->session,
+                DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_HANDSHAKE_FAILURE);
+
+         /* invalidate peer */
+         dtls_clear_retransmission(ctx, peer);
+         dtls_destroy_peer(ctx, peer, 1);
+         peer = NULL;
+        }
        return err;
       }
       break;
 
     case DTLS_CT_ALERT:
       if (peer) {
-        dtls_stop_retransmission(ctx, peer);
+        dtls_clear_retransmission(ctx, peer);
       }
       err = handle_alert(ctx, peer, msg, data, data_length);
       if (err < 0 || err == 1) {
@@ -3888,10 +4541,18 @@ dtls_handle_message(dtls_context_t *ctx,
       break;
 
     case DTLS_CT_HANDSHAKE:
+
       /* Handshake messages other than Finish must use the current
        * epoch, Finish has epoch + 1. */
 
       if (peer) {
+
+             /* Handle the client's last flight retransmission when the server's
+              * Finished message is lost. This avoids deadlock. */
+       if (DTLS_SERVER == role && DTLS_STATE_CONNECTED == state) {
+         dtls_start_retransmission(ctx, peer);
+         break;
+       }
        uint16_t expected_epoch = dtls_security_params(peer)->epoch;
        uint16_t msg_epoch = 
          dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->epoch);
@@ -3921,6 +4582,14 @@ dtls_handle_message(dtls_context_t *ctx,
       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_clear_retransmission(ctx, peer);
+        dtls_destroy_peer(ctx, peer, 1);
+      }
+
        return err;
       }
       if (peer && peer->state == DTLS_STATE_CONNECTED) {
@@ -3937,7 +4606,7 @@ dtls_handle_message(dtls_context_t *ctx,
         // TODO: should we send a alert here?
         return -1;
       }
-      dtls_stop_retransmission(ctx, peer);
+      dtls_clear_retransmission(ctx, peer);
       CALL(ctx, read, &peer->session, data, data_length);
       break;
     default:
@@ -3956,7 +4625,11 @@ dtls_context_t *
 dtls_new_context(void *app_data) {
   dtls_context_t *c;
   dtls_tick_t now;
-#ifndef WITH_CONTIKI
+#if defined(_WIN32)
+  unsigned int randValue;
+  errno_t err;
+#endif
+#if !defined(WITH_CONTIKI) && !defined(_WIN32)
   FILE *urandom = fopen("/dev/urandom", "r");
   unsigned char buf[sizeof(unsigned long)];
 #endif /* WITH_CONTIKI */
@@ -3965,6 +4638,14 @@ dtls_new_context(void *app_data) {
 #ifdef WITH_CONTIKI
   /* FIXME: need something better to init PRNG here */
   dtls_prng_init(now);
+#elif defined(_WIN32)
+  err = rand_s(&randValue);
+  if (err != 0)
+  {
+    dtls_emerg("cannot initialize PRNG\n");
+    return NULL;
+  }
+  dtls_prng_init(randValue);
 #else /* WITH_CONTIKI */
   if (!urandom) {
     dtls_emerg("cannot initialize PRNG\n");
@@ -3973,6 +4654,7 @@ dtls_new_context(void *app_data) {
 
   if (fread(buf, 1, sizeof(buf), urandom) != sizeof(buf)) {
     dtls_emerg("cannot initialize PRNG\n");
+    fclose(urandom);
     return NULL;
   }
 
@@ -4027,6 +4709,7 @@ dtls_free_context(dtls_context_t *ctx) {
 
   if (ctx->peers) {
     HASH_ITER(hh, ctx->peers, p, tmp) {
+      dtls_clear_retransmission(ctx, p);
       dtls_destroy_peer(ctx, p, 1);
     }
   }
@@ -4068,7 +4751,7 @@ dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer) {
   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;
@@ -4119,7 +4802,11 @@ dtls_retransmit(dtls_context_t *context, netq_t *node) {
 
       dtls_ticks(&now);
       node->retransmit_cnt++;
-      node->t = now + (node->timeout << node->retransmit_cnt);
+      if (node->t == 1) {
+        node->t = 0;
+      } else {
+        node->t = now + (node->timeout << node->retransmit_cnt);
+      }
       netq_insert_node(context->sendqueue, node);
       
       if (node->type == DTLS_CT_HANDSHAKE) {
@@ -4160,12 +4847,40 @@ dtls_stop_retransmission(dtls_context_t *context, dtls_peer_t *peer) {
 
   while (node) {
     if (dtls_session_equals(&node->peer->session, &peer->session)) {
+      node->t = 0;
+    }
+    node = list_item_next(node);
+  }
+}
+
+static void
+dtls_start_retransmission(dtls_context_t *context, dtls_peer_t *peer) {
+  netq_t *node;
+  node = list_head(context->sendqueue);
+
+  while (node) {
+    if (dtls_session_equals(&node->peer->session, &peer->session)) {
+      node->retransmit_cnt = 0;
+      node->t = 1;
+    }
+    node = list_item_next(node);
+  }
+}
+
+static void
+dtls_clear_retransmission(dtls_context_t *context, dtls_peer_t *peer) {
+  netq_t *node;
+  node = list_head(context->sendqueue);
+
+  while (node) {
+    if (dtls_session_equals(&node->peer->session, &peer->session)) {
       netq_t *tmp = node;
       node = list_item_next(node);
       list_remove(context->sendqueue, tmp);
       netq_node_free(tmp);
-    } else
-      node = list_item_next(node);    
+    } else {
+      node = list_item_next(node);
+    }
   }
 }
 
@@ -4175,14 +4890,16 @@ dtls_check_retransmit(dtls_context_t *context, clock_time_t *next) {
   netq_t *node = netq_head(context->sendqueue);
 
   dtls_ticks(&now);
-  while (node && node->t <= now) {
-    netq_pop_first(context->sendqueue);
-    dtls_retransmit(context, node);
-    node = netq_head(context->sendqueue);
-  }
 
-  if (next && node)
-    *next = node->t;
+  while (node) {
+    if (node->t && node->t <= now){
+      netq_pop_first(context->sendqueue);
+      dtls_retransmit(context, node);
+      node = netq_head(context->sendqueue);
+    } else {
+      node = list_item_next(node);
+    }
+  }
 }
 
 size_t