/** 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;
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)
{
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_256(code)) ||
- (ecdhe_psk && is_tls_ecdhe_psk_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));
}
/**
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_256: {
pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecc.own_eph_priv,
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 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) ) {
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),
#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,
/* 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 */
uint8 buf[DTLS_CE_LENGTH];
uint8 *p;
- /* Certificate
+ /* Certificate
*
* Start message construction at beginning of buffer. */
p = buf;
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)
{
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,
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,
}
#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)
{
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);
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");
}
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;
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_256: {
uint8 *ephemeral_pub_x;
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)
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;
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);
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) + (ecdhe_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);
+ extension_size = (ecdsa || x509) ? (2 + 6 + 6 + 8 + 6) : 0;
if (cipher_size == 0) {
dtls_crit("no cipher callbacks implemented\n");
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);
}
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 */
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);
/* elliptic_curves */
}
#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)
{
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,
}
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;
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");
#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) {
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);
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) {
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
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");
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;