Version 0.5.0 of tinydtls
Dependents: tinydtls_test_cellular tinydtls_test_ethernet tiny-dtls
dtls.c@1:598a56fe116e, 2014-02-12 (annotated)
- Committer:
- ashleymills
- Date:
- Wed Feb 12 09:30:16 2014 +0000
- Revision:
- 1:598a56fe116e
- Parent:
- 0:ff9ebe0cf0e9
Explicitly removed something instead of relying on MACRO to disable it. Mbed can't use it.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ashleymills | 0:ff9ebe0cf0e9 | 1 | /* dtls -- a very basic DTLS implementation |
ashleymills | 0:ff9ebe0cf0e9 | 2 | * |
ashleymills | 0:ff9ebe0cf0e9 | 3 | * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> |
ashleymills | 0:ff9ebe0cf0e9 | 4 | * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de> |
ashleymills | 0:ff9ebe0cf0e9 | 5 | * |
ashleymills | 0:ff9ebe0cf0e9 | 6 | * Permission is hereby granted, free of charge, to any person |
ashleymills | 0:ff9ebe0cf0e9 | 7 | * obtaining a copy of this software and associated documentation |
ashleymills | 0:ff9ebe0cf0e9 | 8 | * files (the "Software"), to deal in the Software without |
ashleymills | 0:ff9ebe0cf0e9 | 9 | * restriction, including without limitation the rights to use, copy, |
ashleymills | 0:ff9ebe0cf0e9 | 10 | * modify, merge, publish, distribute, sublicense, and/or sell copies |
ashleymills | 0:ff9ebe0cf0e9 | 11 | * of the Software, and to permit persons to whom the Software is |
ashleymills | 0:ff9ebe0cf0e9 | 12 | * furnished to do so, subject to the following conditions: |
ashleymills | 0:ff9ebe0cf0e9 | 13 | * |
ashleymills | 0:ff9ebe0cf0e9 | 14 | * The above copyright notice and this permission notice shall be |
ashleymills | 0:ff9ebe0cf0e9 | 15 | * included in all copies or substantial portions of the Software. |
ashleymills | 0:ff9ebe0cf0e9 | 16 | * |
ashleymills | 0:ff9ebe0cf0e9 | 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
ashleymills | 0:ff9ebe0cf0e9 | 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
ashleymills | 0:ff9ebe0cf0e9 | 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
ashleymills | 0:ff9ebe0cf0e9 | 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
ashleymills | 0:ff9ebe0cf0e9 | 21 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
ashleymills | 0:ff9ebe0cf0e9 | 22 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
ashleymills | 0:ff9ebe0cf0e9 | 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
ashleymills | 0:ff9ebe0cf0e9 | 24 | * SOFTWARE. |
ashleymills | 0:ff9ebe0cf0e9 | 25 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 26 | |
ashleymills | 0:ff9ebe0cf0e9 | 27 | #include "config.h" |
ashleymills | 0:ff9ebe0cf0e9 | 28 | #include "dtls_time.h" |
ashleymills | 0:ff9ebe0cf0e9 | 29 | |
ashleymills | 0:ff9ebe0cf0e9 | 30 | #define __DEBUG__ 0 |
ashleymills | 0:ff9ebe0cf0e9 | 31 | #ifndef __MODULE__ |
ashleymills | 0:ff9ebe0cf0e9 | 32 | #define __MODULE__ "dtls.c" |
ashleymills | 0:ff9ebe0cf0e9 | 33 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 34 | |
ashleymills | 0:ff9ebe0cf0e9 | 35 | #include "dbg.h" |
ashleymills | 0:ff9ebe0cf0e9 | 36 | |
ashleymills | 0:ff9ebe0cf0e9 | 37 | #include <stdio.h> |
ashleymills | 0:ff9ebe0cf0e9 | 38 | #include <stdlib.h> |
ashleymills | 0:ff9ebe0cf0e9 | 39 | #ifdef HAVE_ASSERT_H |
ashleymills | 0:ff9ebe0cf0e9 | 40 | #include <assert.h> |
ashleymills | 0:ff9ebe0cf0e9 | 41 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 42 | #ifndef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 43 | #include <stdlib.h> |
ashleymills | 0:ff9ebe0cf0e9 | 44 | #include "uthash.h" |
ashleymills | 0:ff9ebe0cf0e9 | 45 | #else /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 46 | # ifndef NDEBUG |
ashleymills | 0:ff9ebe0cf0e9 | 47 | # define DEBUG DEBUG_PRINT |
ashleymills | 0:ff9ebe0cf0e9 | 48 | # include "net/uip-debug.h" |
ashleymills | 0:ff9ebe0cf0e9 | 49 | # endif /* NDEBUG */ |
ashleymills | 0:ff9ebe0cf0e9 | 50 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 51 | |
ashleymills | 0:ff9ebe0cf0e9 | 52 | #include "debug.h" |
ashleymills | 0:ff9ebe0cf0e9 | 53 | #include "numeric.h" |
ashleymills | 0:ff9ebe0cf0e9 | 54 | #include "netq.h" |
ashleymills | 0:ff9ebe0cf0e9 | 55 | #include "dtls.h" |
ashleymills | 0:ff9ebe0cf0e9 | 56 | |
ashleymills | 0:ff9ebe0cf0e9 | 57 | #ifdef WITH_SHA256 |
ashleymills | 0:ff9ebe0cf0e9 | 58 | # include "sha2/sha2.h" |
ashleymills | 0:ff9ebe0cf0e9 | 59 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 60 | |
ashleymills | 0:ff9ebe0cf0e9 | 61 | #define dtls_set_version(H,V) dtls_int_to_uint16(&(H)->version, (V)) |
ashleymills | 0:ff9ebe0cf0e9 | 62 | #define dtls_set_content_type(H,V) ((H)->content_type = (V) & 0xff) |
ashleymills | 0:ff9ebe0cf0e9 | 63 | #define dtls_set_length(H,V) ((H)->length = (V)) |
ashleymills | 0:ff9ebe0cf0e9 | 64 | |
ashleymills | 0:ff9ebe0cf0e9 | 65 | #define dtls_get_content_type(H) ((H)->content_type & 0xff) |
ashleymills | 0:ff9ebe0cf0e9 | 66 | #define dtls_get_version(H) dtls_uint16_to_int(&(H)->version) |
ashleymills | 0:ff9ebe0cf0e9 | 67 | #define dtls_get_epoch(H) dtls_uint16_to_int(&(H)->epoch) |
ashleymills | 0:ff9ebe0cf0e9 | 68 | #define dtls_get_sequence_number(H) dtls_uint48_to_ulong(&(H)->sequence_number) |
ashleymills | 0:ff9ebe0cf0e9 | 69 | #define dtls_get_fragment_length(H) dtls_uint24_to_int(&(H)->fragment_length) |
ashleymills | 0:ff9ebe0cf0e9 | 70 | |
ashleymills | 0:ff9ebe0cf0e9 | 71 | #ifndef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 72 | #define HASH_FIND_PEER(head,sess,out) \ |
ashleymills | 0:ff9ebe0cf0e9 | 73 | HASH_FIND(hh,head,sess,sizeof(session_t),out) |
ashleymills | 0:ff9ebe0cf0e9 | 74 | #define HASH_ADD_PEER(head,sess,add) \ |
ashleymills | 0:ff9ebe0cf0e9 | 75 | HASH_ADD(hh,head,sess,sizeof(session_t),add) |
ashleymills | 0:ff9ebe0cf0e9 | 76 | #define HASH_DEL_PEER(head,delptr) \ |
ashleymills | 0:ff9ebe0cf0e9 | 77 | HASH_DELETE(hh,head,delptr) |
ashleymills | 0:ff9ebe0cf0e9 | 78 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 79 | |
ashleymills | 0:ff9ebe0cf0e9 | 80 | #define DTLS_RH_LENGTH sizeof(dtls_record_header_t) |
ashleymills | 0:ff9ebe0cf0e9 | 81 | #define DTLS_HS_LENGTH sizeof(dtls_handshake_header_t) |
ashleymills | 0:ff9ebe0cf0e9 | 82 | #define DTLS_CH_LENGTH sizeof(dtls_client_hello_t) /* no variable length fields! */ |
ashleymills | 0:ff9ebe0cf0e9 | 83 | #define DTLS_COOKIE_LENGTH_MAX 32 |
ashleymills | 0:ff9ebe0cf0e9 | 84 | #define DTLS_CH_LENGTH_MAX sizeof(dtls_client_hello_t) + DTLS_COOKIE_LENGTH_MAX + 12 + 26 |
ashleymills | 0:ff9ebe0cf0e9 | 85 | #define DTLS_HV_LENGTH sizeof(dtls_hello_verify_t) |
ashleymills | 0:ff9ebe0cf0e9 | 86 | #define DTLS_SH_LENGTH (2 + DTLS_RANDOM_LENGTH + 1 + 2 + 1) |
ashleymills | 0:ff9ebe0cf0e9 | 87 | #define DTLS_CE_LENGTH (3 + 3 + 27 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE) |
ashleymills | 0:ff9ebe0cf0e9 | 88 | #define DTLS_SKEXEC_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE + 2 + 70) |
ashleymills | 0:ff9ebe0cf0e9 | 89 | #define DTLS_SKEXECPSK_LENGTH_MIN 2 |
ashleymills | 0:ff9ebe0cf0e9 | 90 | #define DTLS_SKEXECPSK_LENGTH_MAX 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN |
ashleymills | 0:ff9ebe0cf0e9 | 91 | #define DTLS_CKXPSK_LENGTH_MIN 2 |
ashleymills | 0:ff9ebe0cf0e9 | 92 | #define DTLS_CKXEC_LENGTH (1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE) |
ashleymills | 0:ff9ebe0cf0e9 | 93 | #define DTLS_CV_LENGTH (1 + 1 + 2 + 1 + 1 + 1 + 1 + DTLS_EC_KEY_SIZE + 1 + 1 + DTLS_EC_KEY_SIZE) |
ashleymills | 0:ff9ebe0cf0e9 | 94 | #define DTLS_FIN_LENGTH 12 |
ashleymills | 0:ff9ebe0cf0e9 | 95 | |
ashleymills | 0:ff9ebe0cf0e9 | 96 | #define HS_HDR_LENGTH DTLS_RH_LENGTH + DTLS_HS_LENGTH |
ashleymills | 0:ff9ebe0cf0e9 | 97 | #define HV_HDR_LENGTH HS_HDR_LENGTH + DTLS_HV_LENGTH |
ashleymills | 0:ff9ebe0cf0e9 | 98 | |
ashleymills | 0:ff9ebe0cf0e9 | 99 | #define HIGH(V) (((V) >> 8) & 0xff) |
ashleymills | 0:ff9ebe0cf0e9 | 100 | #define LOW(V) ((V) & 0xff) |
ashleymills | 0:ff9ebe0cf0e9 | 101 | |
ashleymills | 0:ff9ebe0cf0e9 | 102 | #define DTLS_RECORD_HEADER(M) ((dtls_record_header_t *)(M)) |
ashleymills | 0:ff9ebe0cf0e9 | 103 | #define DTLS_HANDSHAKE_HEADER(M) ((dtls_handshake_header_t *)(M)) |
ashleymills | 0:ff9ebe0cf0e9 | 104 | |
ashleymills | 0:ff9ebe0cf0e9 | 105 | #define HANDSHAKE(M) ((dtls_handshake_header_t *)((M) + DTLS_RH_LENGTH)) |
ashleymills | 0:ff9ebe0cf0e9 | 106 | #define CLIENTHELLO(M) ((dtls_client_hello_t *)((M) + HS_HDR_LENGTH)) |
ashleymills | 0:ff9ebe0cf0e9 | 107 | |
ashleymills | 0:ff9ebe0cf0e9 | 108 | /* The length check here should work because dtls_*_to_int() works on |
ashleymills | 0:ff9ebe0cf0e9 | 109 | * unsigned char. Otherwise, broken messages could cause severe |
ashleymills | 0:ff9ebe0cf0e9 | 110 | * trouble. Note that this macro jumps out of the current program flow |
ashleymills | 0:ff9ebe0cf0e9 | 111 | * when the message is too short. Beware! |
ashleymills | 0:ff9ebe0cf0e9 | 112 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 113 | #define SKIP_VAR_FIELD(P,L,T) { \ |
ashleymills | 0:ff9ebe0cf0e9 | 114 | if (L < dtls_ ## T ## _to_int(P) + sizeof(T)) \ |
ashleymills | 0:ff9ebe0cf0e9 | 115 | goto error; \ |
ashleymills | 0:ff9ebe0cf0e9 | 116 | L -= dtls_ ## T ## _to_int(P) + sizeof(T); \ |
ashleymills | 0:ff9ebe0cf0e9 | 117 | P += dtls_ ## T ## _to_int(P) + sizeof(T); \ |
ashleymills | 0:ff9ebe0cf0e9 | 118 | } |
ashleymills | 0:ff9ebe0cf0e9 | 119 | |
ashleymills | 0:ff9ebe0cf0e9 | 120 | /* some constants for the PRF */ |
ashleymills | 0:ff9ebe0cf0e9 | 121 | #define PRF_LABEL(Label) prf_label_##Label |
ashleymills | 0:ff9ebe0cf0e9 | 122 | #define PRF_LABEL_SIZE(Label) (sizeof(PRF_LABEL(Label)) - 1) |
ashleymills | 0:ff9ebe0cf0e9 | 123 | |
ashleymills | 0:ff9ebe0cf0e9 | 124 | static const unsigned char prf_label_master[] = "master secret"; |
ashleymills | 0:ff9ebe0cf0e9 | 125 | static const unsigned char prf_label_key[] = "key expansion"; |
ashleymills | 0:ff9ebe0cf0e9 | 126 | static const unsigned char prf_label_client[] = "client"; |
ashleymills | 0:ff9ebe0cf0e9 | 127 | static const unsigned char prf_label_server[] = "server"; |
ashleymills | 0:ff9ebe0cf0e9 | 128 | static const unsigned char prf_label_finished[] = " finished"; |
ashleymills | 0:ff9ebe0cf0e9 | 129 | |
ashleymills | 0:ff9ebe0cf0e9 | 130 | /* first part of Raw public key, the is the start of the Subject Public Key */ |
ashleymills | 0:ff9ebe0cf0e9 | 131 | static const unsigned char cert_asn1_header[] = { |
ashleymills | 0:ff9ebe0cf0e9 | 132 | 0x30, 0x59, /* SEQUENCE, length 89 bytes */ |
ashleymills | 0:ff9ebe0cf0e9 | 133 | 0x30, 0x13, /* SEQUENCE, length 19 bytes */ |
ashleymills | 0:ff9ebe0cf0e9 | 134 | 0x06, 0x07, /* OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) */ |
ashleymills | 0:ff9ebe0cf0e9 | 135 | 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, |
ashleymills | 0:ff9ebe0cf0e9 | 136 | 0x06, 0x08, /* OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) */ |
ashleymills | 0:ff9ebe0cf0e9 | 137 | 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, |
ashleymills | 0:ff9ebe0cf0e9 | 138 | 0x03, 0x42, 0x00, /* BIT STRING, length 66 bytes, 0 bits unused */ |
ashleymills | 0:ff9ebe0cf0e9 | 139 | 0x04 /* uncompressed, followed by the r und s values of the public key */ |
ashleymills | 0:ff9ebe0cf0e9 | 140 | }; |
ashleymills | 0:ff9ebe0cf0e9 | 141 | |
ashleymills | 0:ff9ebe0cf0e9 | 142 | static dtls_context_t the_dtls_context; |
ashleymills | 0:ff9ebe0cf0e9 | 143 | |
ashleymills | 0:ff9ebe0cf0e9 | 144 | #ifdef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 145 | PROCESS(dtls_retransmit_process, "DTLS retransmit process"); |
ashleymills | 0:ff9ebe0cf0e9 | 146 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 147 | |
ashleymills | 0:ff9ebe0cf0e9 | 148 | void |
ashleymills | 0:ff9ebe0cf0e9 | 149 | dtls_init() { |
ashleymills | 0:ff9ebe0cf0e9 | 150 | dtls_clock_init(); |
ashleymills | 0:ff9ebe0cf0e9 | 151 | netq_init(); |
ashleymills | 0:ff9ebe0cf0e9 | 152 | crypto_init(); |
ashleymills | 0:ff9ebe0cf0e9 | 153 | peer_init(); |
ashleymills | 0:ff9ebe0cf0e9 | 154 | } |
ashleymills | 0:ff9ebe0cf0e9 | 155 | |
ashleymills | 0:ff9ebe0cf0e9 | 156 | /* Calls cb_alert() with given arguments if defined, otherwise an |
ashleymills | 0:ff9ebe0cf0e9 | 157 | * error message is logged and the result is -1. This is just an |
ashleymills | 0:ff9ebe0cf0e9 | 158 | * internal helper. |
ashleymills | 0:ff9ebe0cf0e9 | 159 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 160 | #define CALL(Context, which, ...) \ |
ashleymills | 0:ff9ebe0cf0e9 | 161 | ((Context)->h && (Context)->h->which \ |
ashleymills | 0:ff9ebe0cf0e9 | 162 | ? (Context)->h->which((Context), ##__VA_ARGS__) \ |
ashleymills | 0:ff9ebe0cf0e9 | 163 | : -1) |
ashleymills | 0:ff9ebe0cf0e9 | 164 | |
ashleymills | 0:ff9ebe0cf0e9 | 165 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 166 | * Sends the fragment of length \p buflen given in \p buf to the |
ashleymills | 0:ff9ebe0cf0e9 | 167 | * specified \p peer. The data will be MAC-protected and encrypted |
ashleymills | 0:ff9ebe0cf0e9 | 168 | * according to the selected cipher and split into one or more DTLS |
ashleymills | 0:ff9ebe0cf0e9 | 169 | * records of the specified \p type. This function returns the number |
ashleymills | 0:ff9ebe0cf0e9 | 170 | * of bytes that were sent, or \c -1 if an error occurred. |
ashleymills | 0:ff9ebe0cf0e9 | 171 | * |
ashleymills | 0:ff9ebe0cf0e9 | 172 | * \param ctx The DTLS context to use. |
ashleymills | 0:ff9ebe0cf0e9 | 173 | * \param peer The remote peer. |
ashleymills | 0:ff9ebe0cf0e9 | 174 | * \param type The content type of the record. |
ashleymills | 0:ff9ebe0cf0e9 | 175 | * \param buf The data to send. |
ashleymills | 0:ff9ebe0cf0e9 | 176 | * \param buflen The actual length of \p buf. |
ashleymills | 0:ff9ebe0cf0e9 | 177 | * \return Less than zero on error, the number of bytes written otherwise. |
ashleymills | 0:ff9ebe0cf0e9 | 178 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 179 | static int dtls_send(dtls_context_t *ctx, dtls_peer_t *peer, unsigned char type, |
ashleymills | 0:ff9ebe0cf0e9 | 180 | uint8 *buf, size_t buflen); |
ashleymills | 0:ff9ebe0cf0e9 | 181 | |
ashleymills | 0:ff9ebe0cf0e9 | 182 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 183 | * Stops ongoing retransmissions of handshake messages for @p peer. |
ashleymills | 0:ff9ebe0cf0e9 | 184 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 185 | static void dtls_stop_retransmission(dtls_context_t *context, dtls_peer_t *peer); |
ashleymills | 0:ff9ebe0cf0e9 | 186 | |
ashleymills | 0:ff9ebe0cf0e9 | 187 | dtls_peer_t * |
ashleymills | 0:ff9ebe0cf0e9 | 188 | dtls_get_peer(const dtls_context_t *ctx, const session_t *session) { |
ashleymills | 0:ff9ebe0cf0e9 | 189 | dtls_peer_t *p = NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 190 | |
ashleymills | 0:ff9ebe0cf0e9 | 191 | #ifndef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 192 | HASH_FIND_PEER(ctx->peers, session, p); |
ashleymills | 0:ff9ebe0cf0e9 | 193 | #else /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 194 | for (p = list_head(ctx->peers); p; p = list_item_next(p)) |
ashleymills | 0:ff9ebe0cf0e9 | 195 | if (dtls_session_equals(&p->session, session)) |
ashleymills | 0:ff9ebe0cf0e9 | 196 | return p; |
ashleymills | 0:ff9ebe0cf0e9 | 197 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 198 | |
ashleymills | 0:ff9ebe0cf0e9 | 199 | return p; |
ashleymills | 0:ff9ebe0cf0e9 | 200 | } |
ashleymills | 0:ff9ebe0cf0e9 | 201 | |
ashleymills | 0:ff9ebe0cf0e9 | 202 | static void |
ashleymills | 0:ff9ebe0cf0e9 | 203 | dtls_add_peer(dtls_context_t *ctx, dtls_peer_t *peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 204 | #ifndef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 205 | HASH_ADD_PEER(ctx->peers, session, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 206 | #else /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 207 | list_add(ctx->peers, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 208 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 209 | } |
ashleymills | 0:ff9ebe0cf0e9 | 210 | |
ashleymills | 0:ff9ebe0cf0e9 | 211 | int |
ashleymills | 0:ff9ebe0cf0e9 | 212 | dtls_write(struct dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 213 | session_t *dst, uint8 *buf, size_t len) { |
ashleymills | 0:ff9ebe0cf0e9 | 214 | |
ashleymills | 0:ff9ebe0cf0e9 | 215 | dtls_peer_t *peer = dtls_get_peer(ctx, dst); |
ashleymills | 0:ff9ebe0cf0e9 | 216 | |
ashleymills | 0:ff9ebe0cf0e9 | 217 | /* Check if peer connection already exists */ |
ashleymills | 0:ff9ebe0cf0e9 | 218 | if (!peer) { /* no ==> create one */ |
ashleymills | 0:ff9ebe0cf0e9 | 219 | int res; |
ashleymills | 0:ff9ebe0cf0e9 | 220 | |
ashleymills | 0:ff9ebe0cf0e9 | 221 | /* dtls_connect() returns a value greater than zero if a new |
ashleymills | 0:ff9ebe0cf0e9 | 222 | * connection attempt is made, 0 for session reuse. */ |
ashleymills | 0:ff9ebe0cf0e9 | 223 | res = dtls_connect(ctx, dst); |
ashleymills | 0:ff9ebe0cf0e9 | 224 | |
ashleymills | 0:ff9ebe0cf0e9 | 225 | return (res >= 0) ? 0 : res; |
ashleymills | 0:ff9ebe0cf0e9 | 226 | } else { /* a session exists, check if it is in state connected */ |
ashleymills | 0:ff9ebe0cf0e9 | 227 | |
ashleymills | 0:ff9ebe0cf0e9 | 228 | if (peer->state != DTLS_STATE_CONNECTED) { |
ashleymills | 0:ff9ebe0cf0e9 | 229 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 230 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 231 | return dtls_send(ctx, peer, DTLS_CT_APPLICATION_DATA, buf, len); |
ashleymills | 0:ff9ebe0cf0e9 | 232 | } |
ashleymills | 0:ff9ebe0cf0e9 | 233 | } |
ashleymills | 0:ff9ebe0cf0e9 | 234 | } |
ashleymills | 0:ff9ebe0cf0e9 | 235 | |
ashleymills | 0:ff9ebe0cf0e9 | 236 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 237 | dtls_get_cookie(uint8 *msg, int msglen, uint8 **cookie) { |
ashleymills | 0:ff9ebe0cf0e9 | 238 | /* To access the cookie, we have to determine the session id's |
ashleymills | 0:ff9ebe0cf0e9 | 239 | * length and skip the whole thing. */ |
ashleymills | 0:ff9ebe0cf0e9 | 240 | if (msglen < DTLS_HS_LENGTH + DTLS_CH_LENGTH + sizeof(uint8)) |
ashleymills | 0:ff9ebe0cf0e9 | 241 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 242 | |
ashleymills | 0:ff9ebe0cf0e9 | 243 | if (dtls_uint16_to_int(msg + DTLS_HS_LENGTH) != DTLS_VERSION) |
ashleymills | 0:ff9ebe0cf0e9 | 244 | return dtls_alert_fatal_create(DTLS_ALERT_PROTOCOL_VERSION); |
ashleymills | 0:ff9ebe0cf0e9 | 245 | |
ashleymills | 0:ff9ebe0cf0e9 | 246 | msglen -= DTLS_HS_LENGTH + DTLS_CH_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 247 | msg += DTLS_HS_LENGTH + DTLS_CH_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 248 | |
ashleymills | 0:ff9ebe0cf0e9 | 249 | SKIP_VAR_FIELD(msg, msglen, uint8); /* skip session id */ |
ashleymills | 0:ff9ebe0cf0e9 | 250 | |
ashleymills | 0:ff9ebe0cf0e9 | 251 | if (msglen < (*msg & 0xff) + sizeof(uint8)) |
ashleymills | 0:ff9ebe0cf0e9 | 252 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 253 | |
ashleymills | 0:ff9ebe0cf0e9 | 254 | *cookie = msg + sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 255 | return dtls_uint8_to_int(msg); |
ashleymills | 0:ff9ebe0cf0e9 | 256 | |
ashleymills | 0:ff9ebe0cf0e9 | 257 | error: |
ashleymills | 0:ff9ebe0cf0e9 | 258 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 259 | } |
ashleymills | 0:ff9ebe0cf0e9 | 260 | |
ashleymills | 0:ff9ebe0cf0e9 | 261 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 262 | dtls_create_cookie(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 263 | session_t *session, |
ashleymills | 0:ff9ebe0cf0e9 | 264 | uint8 *msg, int msglen, |
ashleymills | 0:ff9ebe0cf0e9 | 265 | uint8 *cookie, int *clen) { |
ashleymills | 0:ff9ebe0cf0e9 | 266 | unsigned char buf[DTLS_HMAC_MAX]; |
ashleymills | 0:ff9ebe0cf0e9 | 267 | size_t len, e; |
ashleymills | 0:ff9ebe0cf0e9 | 268 | |
ashleymills | 0:ff9ebe0cf0e9 | 269 | /* create cookie with HMAC-SHA256 over: |
ashleymills | 0:ff9ebe0cf0e9 | 270 | * - SECRET |
ashleymills | 0:ff9ebe0cf0e9 | 271 | * - session parameters (only IP address?) |
ashleymills | 0:ff9ebe0cf0e9 | 272 | * - client version |
ashleymills | 0:ff9ebe0cf0e9 | 273 | * - random gmt and bytes |
ashleymills | 0:ff9ebe0cf0e9 | 274 | * - session id |
ashleymills | 0:ff9ebe0cf0e9 | 275 | * - cipher_suites |
ashleymills | 0:ff9ebe0cf0e9 | 276 | * - compression method |
ashleymills | 0:ff9ebe0cf0e9 | 277 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 278 | |
ashleymills | 0:ff9ebe0cf0e9 | 279 | /* We use our own buffer as hmac_context instead of a dynamic buffer |
ashleymills | 0:ff9ebe0cf0e9 | 280 | * created by dtls_hmac_new() to separate storage space for cookie |
ashleymills | 0:ff9ebe0cf0e9 | 281 | * creation from storage that is used in real sessions. Note that |
ashleymills | 0:ff9ebe0cf0e9 | 282 | * the buffer size must fit with the default hash algorithm (see |
ashleymills | 0:ff9ebe0cf0e9 | 283 | * implementation of dtls_hmac_context_new()). */ |
ashleymills | 0:ff9ebe0cf0e9 | 284 | |
ashleymills | 0:ff9ebe0cf0e9 | 285 | dtls_hmac_context_t hmac_context; |
ashleymills | 0:ff9ebe0cf0e9 | 286 | dtls_hmac_init(&hmac_context, ctx->cookie_secret, DTLS_COOKIE_SECRET_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 287 | |
ashleymills | 0:ff9ebe0cf0e9 | 288 | dtls_hmac_update(&hmac_context, |
ashleymills | 0:ff9ebe0cf0e9 | 289 | (unsigned char *)&session->addr, session->size); |
ashleymills | 0:ff9ebe0cf0e9 | 290 | |
ashleymills | 0:ff9ebe0cf0e9 | 291 | /* feed in the beginning of the Client Hello up to and including the |
ashleymills | 0:ff9ebe0cf0e9 | 292 | session id */ |
ashleymills | 0:ff9ebe0cf0e9 | 293 | e = sizeof(dtls_client_hello_t); |
ashleymills | 0:ff9ebe0cf0e9 | 294 | e += (*(msg + DTLS_HS_LENGTH + e) & 0xff) + sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 295 | if (e + DTLS_HS_LENGTH > msglen) |
ashleymills | 0:ff9ebe0cf0e9 | 296 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 297 | |
ashleymills | 0:ff9ebe0cf0e9 | 298 | dtls_hmac_update(&hmac_context, msg + DTLS_HS_LENGTH, e); |
ashleymills | 0:ff9ebe0cf0e9 | 299 | |
ashleymills | 0:ff9ebe0cf0e9 | 300 | /* skip cookie bytes and length byte */ |
ashleymills | 0:ff9ebe0cf0e9 | 301 | e += *(uint8 *)(msg + DTLS_HS_LENGTH + e) & 0xff; |
ashleymills | 0:ff9ebe0cf0e9 | 302 | e += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 303 | if (e + DTLS_HS_LENGTH > msglen) |
ashleymills | 0:ff9ebe0cf0e9 | 304 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 305 | |
ashleymills | 0:ff9ebe0cf0e9 | 306 | dtls_hmac_update(&hmac_context, |
ashleymills | 0:ff9ebe0cf0e9 | 307 | msg + DTLS_HS_LENGTH + e, |
ashleymills | 0:ff9ebe0cf0e9 | 308 | dtls_get_fragment_length(DTLS_HANDSHAKE_HEADER(msg)) - e); |
ashleymills | 0:ff9ebe0cf0e9 | 309 | |
ashleymills | 0:ff9ebe0cf0e9 | 310 | len = dtls_hmac_finalize(&hmac_context, buf); |
ashleymills | 0:ff9ebe0cf0e9 | 311 | |
ashleymills | 0:ff9ebe0cf0e9 | 312 | if (len < *clen) { |
ashleymills | 0:ff9ebe0cf0e9 | 313 | memset(cookie + len, 0, *clen - len); |
ashleymills | 0:ff9ebe0cf0e9 | 314 | *clen = len; |
ashleymills | 0:ff9ebe0cf0e9 | 315 | } |
ashleymills | 0:ff9ebe0cf0e9 | 316 | |
ashleymills | 0:ff9ebe0cf0e9 | 317 | memcpy(cookie, buf, *clen); |
ashleymills | 0:ff9ebe0cf0e9 | 318 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 319 | } |
ashleymills | 0:ff9ebe0cf0e9 | 320 | |
ashleymills | 0:ff9ebe0cf0e9 | 321 | #ifdef DTLS_CHECK_CONTENTTYPE |
ashleymills | 0:ff9ebe0cf0e9 | 322 | /* used to check if a received datagram contains a DTLS message */ |
ashleymills | 0:ff9ebe0cf0e9 | 323 | static char const content_types[] = { |
ashleymills | 0:ff9ebe0cf0e9 | 324 | DTLS_CT_CHANGE_CIPHER_SPEC, |
ashleymills | 0:ff9ebe0cf0e9 | 325 | DTLS_CT_ALERT, |
ashleymills | 0:ff9ebe0cf0e9 | 326 | DTLS_CT_HANDSHAKE, |
ashleymills | 0:ff9ebe0cf0e9 | 327 | DTLS_CT_APPLICATION_DATA, |
ashleymills | 0:ff9ebe0cf0e9 | 328 | 0 /* end marker */ |
ashleymills | 0:ff9ebe0cf0e9 | 329 | }; |
ashleymills | 0:ff9ebe0cf0e9 | 330 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 331 | |
ashleymills | 0:ff9ebe0cf0e9 | 332 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 333 | * Checks if \p msg points to a valid DTLS record. If |
ashleymills | 0:ff9ebe0cf0e9 | 334 | * |
ashleymills | 0:ff9ebe0cf0e9 | 335 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 336 | static unsigned int |
ashleymills | 0:ff9ebe0cf0e9 | 337 | is_record(uint8 *msg, int msglen) { |
ashleymills | 0:ff9ebe0cf0e9 | 338 | DBG("is_record"); |
ashleymills | 0:ff9ebe0cf0e9 | 339 | unsigned int rlen = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 340 | |
ashleymills | 0:ff9ebe0cf0e9 | 341 | if (msglen >= DTLS_RH_LENGTH /* FIXME allow empty records? */ |
ashleymills | 0:ff9ebe0cf0e9 | 342 | #ifdef DTLS_CHECK_CONTENTTYPE |
ashleymills | 0:ff9ebe0cf0e9 | 343 | && strchr(content_types, msg[0]) |
ashleymills | 0:ff9ebe0cf0e9 | 344 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 345 | && msg[1] == HIGH(DTLS_VERSION) |
ashleymills | 0:ff9ebe0cf0e9 | 346 | && msg[2] == LOW(DTLS_VERSION)) |
ashleymills | 0:ff9ebe0cf0e9 | 347 | { |
ashleymills | 0:ff9ebe0cf0e9 | 348 | rlen = DTLS_RH_LENGTH + |
ashleymills | 0:ff9ebe0cf0e9 | 349 | dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->length); |
ashleymills | 0:ff9ebe0cf0e9 | 350 | |
ashleymills | 0:ff9ebe0cf0e9 | 351 | /* we do not accept wrong length field in record header */ |
ashleymills | 0:ff9ebe0cf0e9 | 352 | if (rlen > msglen) |
ashleymills | 0:ff9ebe0cf0e9 | 353 | rlen = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 354 | } |
ashleymills | 0:ff9ebe0cf0e9 | 355 | return rlen; |
ashleymills | 0:ff9ebe0cf0e9 | 356 | } |
ashleymills | 0:ff9ebe0cf0e9 | 357 | |
ashleymills | 0:ff9ebe0cf0e9 | 358 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 359 | * Initializes \p buf as record header. The caller must ensure that \p |
ashleymills | 0:ff9ebe0cf0e9 | 360 | * buf is capable of holding at least \c sizeof(dtls_record_header_t) |
ashleymills | 0:ff9ebe0cf0e9 | 361 | * bytes. Increments sequence number counter of \p peer. |
ashleymills | 0:ff9ebe0cf0e9 | 362 | * \return pointer to the next byte after the written header |
ashleymills | 0:ff9ebe0cf0e9 | 363 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 364 | static inline uint8 * |
ashleymills | 0:ff9ebe0cf0e9 | 365 | dtls_set_record_header(uint8 type, dtls_peer_t *peer, uint8 *buf) { |
ashleymills | 0:ff9ebe0cf0e9 | 366 | |
ashleymills | 0:ff9ebe0cf0e9 | 367 | dtls_int_to_uint8(buf, type); |
ashleymills | 0:ff9ebe0cf0e9 | 368 | buf += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 369 | |
ashleymills | 0:ff9ebe0cf0e9 | 370 | dtls_int_to_uint16(buf, DTLS_VERSION); |
ashleymills | 0:ff9ebe0cf0e9 | 371 | buf += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 372 | |
ashleymills | 0:ff9ebe0cf0e9 | 373 | if (peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 374 | memcpy(buf, &peer->epoch, sizeof(uint16) + sizeof(uint48)); |
ashleymills | 0:ff9ebe0cf0e9 | 375 | |
ashleymills | 0:ff9ebe0cf0e9 | 376 | /* increment record sequence counter by 1 */ |
ashleymills | 0:ff9ebe0cf0e9 | 377 | inc_uint(uint48, peer->rseq); |
ashleymills | 0:ff9ebe0cf0e9 | 378 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 379 | memset(buf, 0, sizeof(uint16) + sizeof(uint48)); |
ashleymills | 0:ff9ebe0cf0e9 | 380 | } |
ashleymills | 0:ff9ebe0cf0e9 | 381 | |
ashleymills | 0:ff9ebe0cf0e9 | 382 | buf += sizeof(uint16) + sizeof(uint48); |
ashleymills | 0:ff9ebe0cf0e9 | 383 | |
ashleymills | 0:ff9ebe0cf0e9 | 384 | memset(buf, 0, sizeof(uint16)); |
ashleymills | 0:ff9ebe0cf0e9 | 385 | return buf + sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 386 | } |
ashleymills | 0:ff9ebe0cf0e9 | 387 | |
ashleymills | 0:ff9ebe0cf0e9 | 388 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 389 | * Initializes \p buf as handshake header. The caller must ensure that \p |
ashleymills | 0:ff9ebe0cf0e9 | 390 | * buf is capable of holding at least \c sizeof(dtls_handshake_header_t) |
ashleymills | 0:ff9ebe0cf0e9 | 391 | * bytes. Increments message sequence number counter of \p peer. |
ashleymills | 0:ff9ebe0cf0e9 | 392 | * \return pointer to the next byte after \p buf |
ashleymills | 0:ff9ebe0cf0e9 | 393 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 394 | static inline uint8 * |
ashleymills | 0:ff9ebe0cf0e9 | 395 | dtls_set_handshake_header(uint8 type, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 396 | int length, |
ashleymills | 0:ff9ebe0cf0e9 | 397 | int frag_offset, int frag_length, |
ashleymills | 0:ff9ebe0cf0e9 | 398 | uint8 *buf) { |
ashleymills | 0:ff9ebe0cf0e9 | 399 | |
ashleymills | 0:ff9ebe0cf0e9 | 400 | dtls_int_to_uint8(buf, type); |
ashleymills | 0:ff9ebe0cf0e9 | 401 | buf += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 402 | |
ashleymills | 0:ff9ebe0cf0e9 | 403 | dtls_int_to_uint24(buf, length); |
ashleymills | 0:ff9ebe0cf0e9 | 404 | buf += sizeof(uint24); |
ashleymills | 0:ff9ebe0cf0e9 | 405 | |
ashleymills | 0:ff9ebe0cf0e9 | 406 | if (peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 407 | /* increment handshake message sequence counter by 1 */ |
ashleymills | 0:ff9ebe0cf0e9 | 408 | inc_uint(uint16, peer->hs_state.mseq); |
ashleymills | 0:ff9ebe0cf0e9 | 409 | |
ashleymills | 0:ff9ebe0cf0e9 | 410 | /* and copy the result to buf */ |
ashleymills | 0:ff9ebe0cf0e9 | 411 | memcpy(buf, &peer->hs_state.mseq, sizeof(uint16)); |
ashleymills | 0:ff9ebe0cf0e9 | 412 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 413 | memset(buf, 0, sizeof(uint16)); |
ashleymills | 0:ff9ebe0cf0e9 | 414 | } |
ashleymills | 0:ff9ebe0cf0e9 | 415 | buf += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 416 | |
ashleymills | 0:ff9ebe0cf0e9 | 417 | dtls_int_to_uint24(buf, frag_offset); |
ashleymills | 0:ff9ebe0cf0e9 | 418 | buf += sizeof(uint24); |
ashleymills | 0:ff9ebe0cf0e9 | 419 | |
ashleymills | 0:ff9ebe0cf0e9 | 420 | dtls_int_to_uint24(buf, frag_length); |
ashleymills | 0:ff9ebe0cf0e9 | 421 | buf += sizeof(uint24); |
ashleymills | 0:ff9ebe0cf0e9 | 422 | |
ashleymills | 0:ff9ebe0cf0e9 | 423 | return buf; |
ashleymills | 0:ff9ebe0cf0e9 | 424 | } |
ashleymills | 0:ff9ebe0cf0e9 | 425 | |
ashleymills | 0:ff9ebe0cf0e9 | 426 | /** only one compression method is currently defined */ |
ashleymills | 0:ff9ebe0cf0e9 | 427 | static uint8 compression_methods[] = { |
ashleymills | 0:ff9ebe0cf0e9 | 428 | TLS_COMPRESSION_NULL |
ashleymills | 0:ff9ebe0cf0e9 | 429 | }; |
ashleymills | 0:ff9ebe0cf0e9 | 430 | |
ashleymills | 0:ff9ebe0cf0e9 | 431 | static inline int is_psk_supported(dtls_context_t *ctx){ |
ashleymills | 0:ff9ebe0cf0e9 | 432 | return ctx && ctx->h && ctx->h->get_psk_key; |
ashleymills | 0:ff9ebe0cf0e9 | 433 | } |
ashleymills | 0:ff9ebe0cf0e9 | 434 | |
ashleymills | 0:ff9ebe0cf0e9 | 435 | static inline int is_ecdsa_supported(dtls_context_t *ctx, int is_client){ |
ashleymills | 0:ff9ebe0cf0e9 | 436 | return ctx && ctx->h && ((!is_client && ctx->h->get_ecdsa_key) || |
ashleymills | 0:ff9ebe0cf0e9 | 437 | (is_client && ctx->h->verify_ecdsa_key)); |
ashleymills | 0:ff9ebe0cf0e9 | 438 | } |
ashleymills | 0:ff9ebe0cf0e9 | 439 | |
ashleymills | 0:ff9ebe0cf0e9 | 440 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 441 | * Returns @c 1 if @p code is a cipher suite other than @c |
ashleymills | 0:ff9ebe0cf0e9 | 442 | * TLS_NULL_WITH_NULL_NULL that we recognize. |
ashleymills | 0:ff9ebe0cf0e9 | 443 | * |
ashleymills | 0:ff9ebe0cf0e9 | 444 | * @param ctx The current DTLS context |
ashleymills | 0:ff9ebe0cf0e9 | 445 | * @param code The cipher suite identifier to check |
ashleymills | 0:ff9ebe0cf0e9 | 446 | * @param is_client 1 for a dtls client, 0 for server |
ashleymills | 0:ff9ebe0cf0e9 | 447 | * @return @c 1 iff @p code is recognized, |
ashleymills | 0:ff9ebe0cf0e9 | 448 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 449 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 450 | known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { |
ashleymills | 0:ff9ebe0cf0e9 | 451 | int psk; |
ashleymills | 0:ff9ebe0cf0e9 | 452 | int ecdsa; |
ashleymills | 0:ff9ebe0cf0e9 | 453 | |
ashleymills | 0:ff9ebe0cf0e9 | 454 | psk = is_psk_supported(ctx); |
ashleymills | 0:ff9ebe0cf0e9 | 455 | ecdsa = is_ecdsa_supported(ctx, is_client); |
ashleymills | 0:ff9ebe0cf0e9 | 456 | return (psk && code == TLS_PSK_WITH_AES_128_CCM_8) || |
ashleymills | 0:ff9ebe0cf0e9 | 457 | (ecdsa && code == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); |
ashleymills | 0:ff9ebe0cf0e9 | 458 | } |
ashleymills | 0:ff9ebe0cf0e9 | 459 | |
ashleymills | 0:ff9ebe0cf0e9 | 460 | static void dtls_debug_keyblock(dtls_security_parameters_t *config) |
ashleymills | 0:ff9ebe0cf0e9 | 461 | { |
ashleymills | 0:ff9ebe0cf0e9 | 462 | DBG("key_block (%d bytes):", dtls_kb_size(config, peer->role)); |
ashleymills | 0:ff9ebe0cf0e9 | 463 | dtls_dsrv_hexdump_log(LOG_DEBUG, " client_MAC_secret", |
ashleymills | 0:ff9ebe0cf0e9 | 464 | dtls_kb_client_mac_secret(config, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 465 | dtls_kb_mac_secret_size(config, peer->role), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 466 | |
ashleymills | 0:ff9ebe0cf0e9 | 467 | dtls_dsrv_hexdump_log(LOG_DEBUG, " server_MAC_secret", |
ashleymills | 0:ff9ebe0cf0e9 | 468 | dtls_kb_server_mac_secret(config, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 469 | dtls_kb_mac_secret_size(config, peer->role), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 470 | |
ashleymills | 0:ff9ebe0cf0e9 | 471 | dtls_dsrv_hexdump_log(LOG_DEBUG, " client_write_key", |
ashleymills | 0:ff9ebe0cf0e9 | 472 | dtls_kb_client_write_key(config, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 473 | dtls_kb_key_size(config, peer->role), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 474 | |
ashleymills | 0:ff9ebe0cf0e9 | 475 | dtls_dsrv_hexdump_log(LOG_DEBUG, " server_write_key", |
ashleymills | 0:ff9ebe0cf0e9 | 476 | dtls_kb_server_write_key(config, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 477 | dtls_kb_key_size(config, peer->role), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 478 | |
ashleymills | 0:ff9ebe0cf0e9 | 479 | dtls_dsrv_hexdump_log(LOG_DEBUG, " client_IV", |
ashleymills | 0:ff9ebe0cf0e9 | 480 | dtls_kb_client_iv(config, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 481 | dtls_kb_iv_size(config, peer->role), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 482 | |
ashleymills | 0:ff9ebe0cf0e9 | 483 | dtls_dsrv_hexdump_log(LOG_DEBUG, " server_IV", |
ashleymills | 0:ff9ebe0cf0e9 | 484 | dtls_kb_server_iv(config, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 485 | dtls_kb_iv_size(config, peer->role), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 486 | } |
ashleymills | 0:ff9ebe0cf0e9 | 487 | |
ashleymills | 0:ff9ebe0cf0e9 | 488 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 489 | calculate_key_block(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 490 | dtls_handshake_parameters_t *handshake, |
ashleymills | 0:ff9ebe0cf0e9 | 491 | dtls_security_parameters_t *security, |
ashleymills | 0:ff9ebe0cf0e9 | 492 | session_t *session) { |
ashleymills | 0:ff9ebe0cf0e9 | 493 | unsigned char *pre_master_secret; |
ashleymills | 0:ff9ebe0cf0e9 | 494 | size_t pre_master_len = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 495 | pre_master_secret = security->key_block; |
ashleymills | 0:ff9ebe0cf0e9 | 496 | uint8 master_secret[DTLS_MASTER_SECRET_LENGTH]; |
ashleymills | 0:ff9ebe0cf0e9 | 497 | int err; |
ashleymills | 0:ff9ebe0cf0e9 | 498 | |
ashleymills | 0:ff9ebe0cf0e9 | 499 | switch (handshake->cipher) { |
ashleymills | 0:ff9ebe0cf0e9 | 500 | case TLS_PSK_WITH_AES_128_CCM_8: { |
ashleymills | 0:ff9ebe0cf0e9 | 501 | const dtls_psk_key_t *psk; |
ashleymills | 0:ff9ebe0cf0e9 | 502 | |
ashleymills | 0:ff9ebe0cf0e9 | 503 | err = CALL(ctx, get_psk_key, session, handshake->keyx.psk.identity, |
ashleymills | 0:ff9ebe0cf0e9 | 504 | handshake->keyx.psk.id_length, &psk); |
ashleymills | 0:ff9ebe0cf0e9 | 505 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 506 | DBG("no psk key for session available"); |
ashleymills | 0:ff9ebe0cf0e9 | 507 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 508 | } |
ashleymills | 0:ff9ebe0cf0e9 | 509 | /* Temporarily use the key_block storage space for the pre master secret. */ |
ashleymills | 0:ff9ebe0cf0e9 | 510 | pre_master_len = dtls_psk_pre_master_secret(psk->key, psk->key_length, |
ashleymills | 0:ff9ebe0cf0e9 | 511 | pre_master_secret); |
ashleymills | 0:ff9ebe0cf0e9 | 512 | |
ashleymills | 0:ff9ebe0cf0e9 | 513 | dtls_dsrv_hexdump_log(LOG_DEBUG, "psk", psk->key, psk->key_length, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 514 | |
ashleymills | 0:ff9ebe0cf0e9 | 515 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 516 | } |
ashleymills | 0:ff9ebe0cf0e9 | 517 | case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: { |
ashleymills | 0:ff9ebe0cf0e9 | 518 | pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecdsa.own_eph_priv, |
ashleymills | 0:ff9ebe0cf0e9 | 519 | handshake->keyx.ecdsa.other_eph_pub_x, |
ashleymills | 0:ff9ebe0cf0e9 | 520 | handshake->keyx.ecdsa.other_eph_pub_y, |
ashleymills | 0:ff9ebe0cf0e9 | 521 | sizeof(handshake->keyx.ecdsa.own_eph_priv), |
ashleymills | 0:ff9ebe0cf0e9 | 522 | pre_master_secret); |
ashleymills | 0:ff9ebe0cf0e9 | 523 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 524 | } |
ashleymills | 0:ff9ebe0cf0e9 | 525 | default: |
ashleymills | 0:ff9ebe0cf0e9 | 526 | DBG("calculate_key_block: unknown cipher"); |
ashleymills | 0:ff9ebe0cf0e9 | 527 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 528 | } |
ashleymills | 0:ff9ebe0cf0e9 | 529 | |
ashleymills | 0:ff9ebe0cf0e9 | 530 | dtls_dsrv_hexdump_log(LOG_DEBUG, "client_random", handshake->tmp.random.client, |
ashleymills | 0:ff9ebe0cf0e9 | 531 | DTLS_RANDOM_LENGTH, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 532 | dtls_dsrv_hexdump_log(LOG_DEBUG, "server_random", handshake->tmp.random.server, |
ashleymills | 0:ff9ebe0cf0e9 | 533 | DTLS_RANDOM_LENGTH, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 534 | dtls_dsrv_hexdump_log(LOG_DEBUG, "pre_master_secret", pre_master_secret, |
ashleymills | 0:ff9ebe0cf0e9 | 535 | pre_master_len, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 536 | |
ashleymills | 0:ff9ebe0cf0e9 | 537 | dtls_prf(pre_master_secret, pre_master_len, |
ashleymills | 0:ff9ebe0cf0e9 | 538 | PRF_LABEL(master), PRF_LABEL_SIZE(master), |
ashleymills | 0:ff9ebe0cf0e9 | 539 | handshake->tmp.random.client, DTLS_RANDOM_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 540 | handshake->tmp.random.server, DTLS_RANDOM_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 541 | master_secret, |
ashleymills | 0:ff9ebe0cf0e9 | 542 | DTLS_MASTER_SECRET_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 543 | |
ashleymills | 0:ff9ebe0cf0e9 | 544 | dtls_dsrv_hexdump_log(LOG_DEBUG, "master_secret", master_secret, |
ashleymills | 0:ff9ebe0cf0e9 | 545 | DTLS_MASTER_SECRET_LENGTH, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 546 | |
ashleymills | 0:ff9ebe0cf0e9 | 547 | /* create key_block from master_secret |
ashleymills | 0:ff9ebe0cf0e9 | 548 | * key_block = PRF(master_secret, |
ashleymills | 0:ff9ebe0cf0e9 | 549 | "key expansion" + tmp.random.server + tmp.random.client) */ |
ashleymills | 0:ff9ebe0cf0e9 | 550 | |
ashleymills | 0:ff9ebe0cf0e9 | 551 | dtls_prf(master_secret, |
ashleymills | 0:ff9ebe0cf0e9 | 552 | DTLS_MASTER_SECRET_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 553 | PRF_LABEL(key), PRF_LABEL_SIZE(key), |
ashleymills | 0:ff9ebe0cf0e9 | 554 | handshake->tmp.random.server, DTLS_RANDOM_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 555 | handshake->tmp.random.client, DTLS_RANDOM_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 556 | security->key_block, |
ashleymills | 0:ff9ebe0cf0e9 | 557 | dtls_kb_size(security, peer->role)); |
ashleymills | 0:ff9ebe0cf0e9 | 558 | |
ashleymills | 0:ff9ebe0cf0e9 | 559 | memcpy(handshake->tmp.master_secret, master_secret, DTLS_MASTER_SECRET_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 560 | dtls_debug_keyblock(security); |
ashleymills | 0:ff9ebe0cf0e9 | 561 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 562 | } |
ashleymills | 0:ff9ebe0cf0e9 | 563 | |
ashleymills | 0:ff9ebe0cf0e9 | 564 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 565 | * Releases the storage allocated for read_cipher and write_cipher and |
ashleymills | 0:ff9ebe0cf0e9 | 566 | * sets both fields to NULL. |
ashleymills | 0:ff9ebe0cf0e9 | 567 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 568 | static void |
ashleymills | 0:ff9ebe0cf0e9 | 569 | invalidate_ciphers(dtls_security_parameters_t *config) { |
ashleymills | 0:ff9ebe0cf0e9 | 570 | if (config->read_cipher) { |
ashleymills | 0:ff9ebe0cf0e9 | 571 | dtls_cipher_free(config->read_cipher); |
ashleymills | 0:ff9ebe0cf0e9 | 572 | config->read_cipher = NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 573 | } |
ashleymills | 0:ff9ebe0cf0e9 | 574 | |
ashleymills | 0:ff9ebe0cf0e9 | 575 | if (config->write_cipher) { |
ashleymills | 0:ff9ebe0cf0e9 | 576 | dtls_cipher_free(config->write_cipher); |
ashleymills | 0:ff9ebe0cf0e9 | 577 | config->write_cipher = NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 578 | } |
ashleymills | 0:ff9ebe0cf0e9 | 579 | } |
ashleymills | 0:ff9ebe0cf0e9 | 580 | |
ashleymills | 0:ff9ebe0cf0e9 | 581 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 582 | init_cipher(dtls_handshake_parameters_t *handshake, dtls_security_parameters_t *config, dtls_peer_type role) |
ashleymills | 0:ff9ebe0cf0e9 | 583 | { |
ashleymills | 0:ff9ebe0cf0e9 | 584 | /* set crypto context for TLS_PSK_WITH_AES_128_CCM_8 */ |
ashleymills | 0:ff9ebe0cf0e9 | 585 | dtls_cipher_free(config->read_cipher); |
ashleymills | 0:ff9ebe0cf0e9 | 586 | |
ashleymills | 0:ff9ebe0cf0e9 | 587 | assert(handshake->cipher != TLS_NULL_WITH_NULL_NULL); |
ashleymills | 0:ff9ebe0cf0e9 | 588 | config->read_cipher = dtls_cipher_new(handshake->cipher, |
ashleymills | 0:ff9ebe0cf0e9 | 589 | dtls_kb_remote_write_key(config, role), |
ashleymills | 0:ff9ebe0cf0e9 | 590 | dtls_kb_key_size(config, role)); |
ashleymills | 0:ff9ebe0cf0e9 | 591 | |
ashleymills | 0:ff9ebe0cf0e9 | 592 | if (!config->read_cipher) { |
ashleymills | 0:ff9ebe0cf0e9 | 593 | WARN("cannot create read cipher"); |
ashleymills | 0:ff9ebe0cf0e9 | 594 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 595 | } |
ashleymills | 0:ff9ebe0cf0e9 | 596 | |
ashleymills | 0:ff9ebe0cf0e9 | 597 | dtls_cipher_free(config->write_cipher); |
ashleymills | 0:ff9ebe0cf0e9 | 598 | |
ashleymills | 0:ff9ebe0cf0e9 | 599 | config->write_cipher = dtls_cipher_new(handshake->cipher, |
ashleymills | 0:ff9ebe0cf0e9 | 600 | dtls_kb_local_write_key(config, role), |
ashleymills | 0:ff9ebe0cf0e9 | 601 | dtls_kb_key_size(config, role)); |
ashleymills | 0:ff9ebe0cf0e9 | 602 | |
ashleymills | 0:ff9ebe0cf0e9 | 603 | if (!config->write_cipher) { |
ashleymills | 0:ff9ebe0cf0e9 | 604 | WARN("cannot create write cipher"); |
ashleymills | 0:ff9ebe0cf0e9 | 605 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 606 | } |
ashleymills | 0:ff9ebe0cf0e9 | 607 | |
ashleymills | 0:ff9ebe0cf0e9 | 608 | config->cipher = handshake->cipher; |
ashleymills | 0:ff9ebe0cf0e9 | 609 | config->compression = handshake->compression; |
ashleymills | 0:ff9ebe0cf0e9 | 610 | |
ashleymills | 0:ff9ebe0cf0e9 | 611 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 612 | error: |
ashleymills | 0:ff9ebe0cf0e9 | 613 | |
ashleymills | 0:ff9ebe0cf0e9 | 614 | invalidate_ciphers(config); |
ashleymills | 0:ff9ebe0cf0e9 | 615 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 616 | } |
ashleymills | 0:ff9ebe0cf0e9 | 617 | |
ashleymills | 0:ff9ebe0cf0e9 | 618 | /* TODO: add a generic method which iterates over a list and searches for a specific key */ |
ashleymills | 0:ff9ebe0cf0e9 | 619 | static int verify_ext_eliptic_curves(uint8 *data, size_t data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 620 | int i, curve_name; |
ashleymills | 0:ff9ebe0cf0e9 | 621 | |
ashleymills | 0:ff9ebe0cf0e9 | 622 | /* length of curve list */ |
ashleymills | 0:ff9ebe0cf0e9 | 623 | i = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 624 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 625 | if (i + sizeof(uint16) != data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 626 | WARN("the list of the supported elliptic curves should be tls extension length - 2"); |
ashleymills | 0:ff9ebe0cf0e9 | 627 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 628 | } |
ashleymills | 0:ff9ebe0cf0e9 | 629 | |
ashleymills | 0:ff9ebe0cf0e9 | 630 | for (i = data_length - sizeof(uint16); i > 0; i -= sizeof(uint16)) { |
ashleymills | 0:ff9ebe0cf0e9 | 631 | /* check if this curve is supported */ |
ashleymills | 0:ff9ebe0cf0e9 | 632 | curve_name = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 633 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 634 | |
ashleymills | 0:ff9ebe0cf0e9 | 635 | if (curve_name == TLS_EXT_ELLIPTIC_CURVES_SECP256R1) |
ashleymills | 0:ff9ebe0cf0e9 | 636 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 637 | } |
ashleymills | 0:ff9ebe0cf0e9 | 638 | |
ashleymills | 0:ff9ebe0cf0e9 | 639 | WARN("no supported elliptic curve found"); |
ashleymills | 0:ff9ebe0cf0e9 | 640 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 641 | } |
ashleymills | 0:ff9ebe0cf0e9 | 642 | |
ashleymills | 0:ff9ebe0cf0e9 | 643 | static int verify_ext_cert_type(uint8 *data, size_t data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 644 | int i, cert_type; |
ashleymills | 0:ff9ebe0cf0e9 | 645 | |
ashleymills | 0:ff9ebe0cf0e9 | 646 | /* length of cert type list */ |
ashleymills | 0:ff9ebe0cf0e9 | 647 | i = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 648 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 649 | if (i + sizeof(uint8) != data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 650 | WARN("the list of the supported certificate types should be tls extension length - 1"); |
ashleymills | 0:ff9ebe0cf0e9 | 651 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 652 | } |
ashleymills | 0:ff9ebe0cf0e9 | 653 | |
ashleymills | 0:ff9ebe0cf0e9 | 654 | for (i = data_length - sizeof(uint8); i > 0; i -= sizeof(uint8)) { |
ashleymills | 0:ff9ebe0cf0e9 | 655 | /* check if this cert type is supported */ |
ashleymills | 0:ff9ebe0cf0e9 | 656 | cert_type = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 657 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 658 | |
ashleymills | 0:ff9ebe0cf0e9 | 659 | if (cert_type == TLS_CERT_TYPE_OOB) |
ashleymills | 0:ff9ebe0cf0e9 | 660 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 661 | } |
ashleymills | 0:ff9ebe0cf0e9 | 662 | |
ashleymills | 0:ff9ebe0cf0e9 | 663 | WARN("no supported certificate type found"); |
ashleymills | 0:ff9ebe0cf0e9 | 664 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 665 | } |
ashleymills | 0:ff9ebe0cf0e9 | 666 | |
ashleymills | 0:ff9ebe0cf0e9 | 667 | static int verify_ext_ec_point_formats(uint8 *data, size_t data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 668 | int i, cert_type; |
ashleymills | 0:ff9ebe0cf0e9 | 669 | |
ashleymills | 0:ff9ebe0cf0e9 | 670 | /* length of ec_point_formats list */ |
ashleymills | 0:ff9ebe0cf0e9 | 671 | i = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 672 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 673 | if (i + sizeof(uint8) != data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 674 | WARN("the list of the supported ec_point_formats should be tls extension length - 1"); |
ashleymills | 0:ff9ebe0cf0e9 | 675 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 676 | } |
ashleymills | 0:ff9ebe0cf0e9 | 677 | |
ashleymills | 0:ff9ebe0cf0e9 | 678 | for (i = data_length - sizeof(uint8); i > 0; i -= sizeof(uint8)) { |
ashleymills | 0:ff9ebe0cf0e9 | 679 | /* check if this ec_point_format is supported */ |
ashleymills | 0:ff9ebe0cf0e9 | 680 | cert_type = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 681 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 682 | |
ashleymills | 0:ff9ebe0cf0e9 | 683 | if (cert_type == TLS_EXT_EC_POINT_FORMATS_UNCOMPRESSED) |
ashleymills | 0:ff9ebe0cf0e9 | 684 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 685 | } |
ashleymills | 0:ff9ebe0cf0e9 | 686 | |
ashleymills | 0:ff9ebe0cf0e9 | 687 | WARN("no supported ec_point_format found"); |
ashleymills | 0:ff9ebe0cf0e9 | 688 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 689 | } |
ashleymills | 0:ff9ebe0cf0e9 | 690 | |
ashleymills | 0:ff9ebe0cf0e9 | 691 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 692 | dtls_check_tls_extension(dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 693 | uint8 *data, size_t data_length, int client_hello) |
ashleymills | 0:ff9ebe0cf0e9 | 694 | { |
ashleymills | 0:ff9ebe0cf0e9 | 695 | int i, j; |
ashleymills | 0:ff9ebe0cf0e9 | 696 | int ext_elliptic_curve = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 697 | int ext_client_cert_type = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 698 | int ext_server_cert_type = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 699 | int ext_ec_point_formats = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 700 | dtls_handshake_parameters_t *handshake = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 701 | |
ashleymills | 0:ff9ebe0cf0e9 | 702 | if (data_length < sizeof(uint16)) { |
ashleymills | 0:ff9ebe0cf0e9 | 703 | /* no tls extensions specified */ |
ashleymills | 0:ff9ebe0cf0e9 | 704 | if (handshake->cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 705 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 706 | } |
ashleymills | 0:ff9ebe0cf0e9 | 707 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 708 | } |
ashleymills | 0:ff9ebe0cf0e9 | 709 | |
ashleymills | 0:ff9ebe0cf0e9 | 710 | /* get the length of the tls extension list */ |
ashleymills | 0:ff9ebe0cf0e9 | 711 | j = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 712 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 713 | data_length -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 714 | |
ashleymills | 0:ff9ebe0cf0e9 | 715 | if (data_length < j) |
ashleymills | 0:ff9ebe0cf0e9 | 716 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 717 | |
ashleymills | 0:ff9ebe0cf0e9 | 718 | /* check for TLS extensions needed for this cipher */ |
ashleymills | 0:ff9ebe0cf0e9 | 719 | while (data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 720 | if (data_length < sizeof(uint16) * 2) |
ashleymills | 0:ff9ebe0cf0e9 | 721 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 722 | |
ashleymills | 0:ff9ebe0cf0e9 | 723 | /* get the tls extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 724 | i = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 725 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 726 | data_length -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 727 | |
ashleymills | 0:ff9ebe0cf0e9 | 728 | /* get the length of the tls extension */ |
ashleymills | 0:ff9ebe0cf0e9 | 729 | j = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 730 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 731 | data_length -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 732 | |
ashleymills | 0:ff9ebe0cf0e9 | 733 | if (data_length < j) |
ashleymills | 0:ff9ebe0cf0e9 | 734 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 735 | |
ashleymills | 0:ff9ebe0cf0e9 | 736 | switch (i) { |
ashleymills | 0:ff9ebe0cf0e9 | 737 | case TLS_EXT_ELLIPTIC_CURVES: |
ashleymills | 0:ff9ebe0cf0e9 | 738 | ext_elliptic_curve = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 739 | if (verify_ext_eliptic_curves(data, j)) |
ashleymills | 0:ff9ebe0cf0e9 | 740 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 741 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 742 | case TLS_EXT_CLIENT_CERIFICATE_TYPE: |
ashleymills | 0:ff9ebe0cf0e9 | 743 | ext_client_cert_type = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 744 | if (client_hello) { |
ashleymills | 0:ff9ebe0cf0e9 | 745 | if (verify_ext_cert_type(data, j)) |
ashleymills | 0:ff9ebe0cf0e9 | 746 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 747 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 748 | if (dtls_uint8_to_int(data) != TLS_CERT_TYPE_OOB) |
ashleymills | 0:ff9ebe0cf0e9 | 749 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 750 | } |
ashleymills | 0:ff9ebe0cf0e9 | 751 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 752 | case TLS_EXT_SERVER_CERIFICATE_TYPE: |
ashleymills | 0:ff9ebe0cf0e9 | 753 | ext_server_cert_type = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 754 | if (client_hello) { |
ashleymills | 0:ff9ebe0cf0e9 | 755 | if (verify_ext_cert_type(data, j)) |
ashleymills | 0:ff9ebe0cf0e9 | 756 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 757 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 758 | if (dtls_uint8_to_int(data) != TLS_CERT_TYPE_OOB) |
ashleymills | 0:ff9ebe0cf0e9 | 759 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 760 | } |
ashleymills | 0:ff9ebe0cf0e9 | 761 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 762 | case TLS_EXT_EC_POINT_FORMATS: |
ashleymills | 0:ff9ebe0cf0e9 | 763 | ext_ec_point_formats = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 764 | if (verify_ext_ec_point_formats(data, j)) |
ashleymills | 0:ff9ebe0cf0e9 | 765 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 766 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 767 | default: |
ashleymills | 0:ff9ebe0cf0e9 | 768 | WARN("unsupported tls extension: %i", i); |
ashleymills | 0:ff9ebe0cf0e9 | 769 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 770 | } |
ashleymills | 0:ff9ebe0cf0e9 | 771 | data += j; |
ashleymills | 0:ff9ebe0cf0e9 | 772 | data_length -= j; |
ashleymills | 0:ff9ebe0cf0e9 | 773 | } |
ashleymills | 0:ff9ebe0cf0e9 | 774 | if (handshake->cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 775 | if (!ext_elliptic_curve && !ext_client_cert_type && !ext_server_cert_type |
ashleymills | 0:ff9ebe0cf0e9 | 776 | && !ext_ec_point_formats) { |
ashleymills | 0:ff9ebe0cf0e9 | 777 | WARN("not all required tls extensions found in client hello"); |
ashleymills | 0:ff9ebe0cf0e9 | 778 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 779 | } |
ashleymills | 0:ff9ebe0cf0e9 | 780 | } |
ashleymills | 0:ff9ebe0cf0e9 | 781 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 782 | |
ashleymills | 0:ff9ebe0cf0e9 | 783 | error: |
ashleymills | 0:ff9ebe0cf0e9 | 784 | if (client_hello && peer->state == DTLS_STATE_CONNECTED) { |
ashleymills | 0:ff9ebe0cf0e9 | 785 | return dtls_alert_create(DTLS_ALERT_LEVEL_WARNING, DTLS_ALERT_NO_RENEGOTIATION); |
ashleymills | 0:ff9ebe0cf0e9 | 786 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 787 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 788 | } |
ashleymills | 0:ff9ebe0cf0e9 | 789 | } |
ashleymills | 0:ff9ebe0cf0e9 | 790 | |
ashleymills | 0:ff9ebe0cf0e9 | 791 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 792 | * Updates the security parameters of given \p peer. As this must be |
ashleymills | 0:ff9ebe0cf0e9 | 793 | * done before the new configuration is activated, it changes the |
ashleymills | 0:ff9ebe0cf0e9 | 794 | * OTHER_CONFIG only. When the ClientHello handshake message in \p |
ashleymills | 0:ff9ebe0cf0e9 | 795 | * data does not contain a cipher suite or compression method, it is |
ashleymills | 0:ff9ebe0cf0e9 | 796 | * copied from the CURRENT_CONFIG. |
ashleymills | 0:ff9ebe0cf0e9 | 797 | * |
ashleymills | 0:ff9ebe0cf0e9 | 798 | * \param ctx The current DTLS context. |
ashleymills | 0:ff9ebe0cf0e9 | 799 | * \param peer The remote peer whose security parameters are about to change. |
ashleymills | 0:ff9ebe0cf0e9 | 800 | * \param data The handshake message with a ClientHello. |
ashleymills | 0:ff9ebe0cf0e9 | 801 | * \param data_length The actual size of \p data. |
ashleymills | 0:ff9ebe0cf0e9 | 802 | * \return \c 0 if an error occurred, \c 1 otherwise. |
ashleymills | 0:ff9ebe0cf0e9 | 803 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 804 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 805 | dtls_update_parameters(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 806 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 807 | uint8 *data, size_t data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 808 | int i, j; |
ashleymills | 0:ff9ebe0cf0e9 | 809 | int ok; |
ashleymills | 0:ff9ebe0cf0e9 | 810 | dtls_handshake_parameters_t *config = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 811 | dtls_security_parameters_t *security = &peer->security_params; |
ashleymills | 0:ff9ebe0cf0e9 | 812 | |
ashleymills | 0:ff9ebe0cf0e9 | 813 | assert(config); |
ashleymills | 0:ff9ebe0cf0e9 | 814 | assert(data_length > DTLS_HS_LENGTH + DTLS_CH_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 815 | |
ashleymills | 0:ff9ebe0cf0e9 | 816 | /* DBG("dtls_update_parameters: msglen is %d", data_length); */ |
ashleymills | 0:ff9ebe0cf0e9 | 817 | |
ashleymills | 0:ff9ebe0cf0e9 | 818 | /* skip the handshake header and client version information */ |
ashleymills | 0:ff9ebe0cf0e9 | 819 | data += DTLS_HS_LENGTH + sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 820 | data_length -= DTLS_HS_LENGTH + sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 821 | |
ashleymills | 0:ff9ebe0cf0e9 | 822 | /* store client random in config |
ashleymills | 0:ff9ebe0cf0e9 | 823 | * FIXME: if we send the ServerHello here, we do not need to store |
ashleymills | 0:ff9ebe0cf0e9 | 824 | * the client's random bytes */ |
ashleymills | 0:ff9ebe0cf0e9 | 825 | memcpy(config->tmp.random.client, data, DTLS_RANDOM_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 826 | data += DTLS_RANDOM_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 827 | data_length -= DTLS_RANDOM_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 828 | |
ashleymills | 0:ff9ebe0cf0e9 | 829 | /* Caution: SKIP_VAR_FIELD may jump to error: */ |
ashleymills | 0:ff9ebe0cf0e9 | 830 | SKIP_VAR_FIELD(data, data_length, uint8); /* skip session id */ |
ashleymills | 0:ff9ebe0cf0e9 | 831 | SKIP_VAR_FIELD(data, data_length, uint8); /* skip cookie */ |
ashleymills | 0:ff9ebe0cf0e9 | 832 | |
ashleymills | 0:ff9ebe0cf0e9 | 833 | i = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 834 | if (data_length < i + sizeof(uint16)) { |
ashleymills | 0:ff9ebe0cf0e9 | 835 | /* Looks like we do not have a cipher nor compression. This is ok |
ashleymills | 0:ff9ebe0cf0e9 | 836 | * for renegotiation, but not for the initial handshake. */ |
ashleymills | 0:ff9ebe0cf0e9 | 837 | |
ashleymills | 0:ff9ebe0cf0e9 | 838 | if (security->cipher == TLS_NULL_WITH_NULL_NULL) |
ashleymills | 0:ff9ebe0cf0e9 | 839 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 840 | |
ashleymills | 0:ff9ebe0cf0e9 | 841 | config->cipher = security->cipher; |
ashleymills | 0:ff9ebe0cf0e9 | 842 | config->compression = security->compression; |
ashleymills | 0:ff9ebe0cf0e9 | 843 | |
ashleymills | 0:ff9ebe0cf0e9 | 844 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 845 | } |
ashleymills | 0:ff9ebe0cf0e9 | 846 | |
ashleymills | 0:ff9ebe0cf0e9 | 847 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 848 | data_length -= sizeof(uint16) + i; |
ashleymills | 0:ff9ebe0cf0e9 | 849 | |
ashleymills | 0:ff9ebe0cf0e9 | 850 | ok = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 851 | while (i && !ok) { |
ashleymills | 0:ff9ebe0cf0e9 | 852 | config->cipher = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 853 | ok = known_cipher(ctx, config->cipher, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 854 | i -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 855 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 856 | } |
ashleymills | 0:ff9ebe0cf0e9 | 857 | |
ashleymills | 0:ff9ebe0cf0e9 | 858 | /* skip remaining ciphers */ |
ashleymills | 0:ff9ebe0cf0e9 | 859 | data += i; |
ashleymills | 0:ff9ebe0cf0e9 | 860 | |
ashleymills | 0:ff9ebe0cf0e9 | 861 | if (!ok) { |
ashleymills | 0:ff9ebe0cf0e9 | 862 | /* reset config cipher to a well-defined value */ |
ashleymills | 0:ff9ebe0cf0e9 | 863 | config->cipher = TLS_NULL_WITH_NULL_NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 864 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 865 | } |
ashleymills | 0:ff9ebe0cf0e9 | 866 | |
ashleymills | 0:ff9ebe0cf0e9 | 867 | if (data_length < sizeof(uint8)) { |
ashleymills | 0:ff9ebe0cf0e9 | 868 | /* no compression specified, take the current compression method */ |
ashleymills | 0:ff9ebe0cf0e9 | 869 | config->compression = security->compression; |
ashleymills | 0:ff9ebe0cf0e9 | 870 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 871 | } |
ashleymills | 0:ff9ebe0cf0e9 | 872 | |
ashleymills | 0:ff9ebe0cf0e9 | 873 | i = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 874 | if (data_length < i + sizeof(uint8)) |
ashleymills | 0:ff9ebe0cf0e9 | 875 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 876 | |
ashleymills | 0:ff9ebe0cf0e9 | 877 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 878 | data_length -= sizeof(uint8) + i; |
ashleymills | 0:ff9ebe0cf0e9 | 879 | |
ashleymills | 0:ff9ebe0cf0e9 | 880 | ok = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 881 | while (i && !ok) { |
ashleymills | 0:ff9ebe0cf0e9 | 882 | for (j = 0; j < sizeof(compression_methods) / sizeof(uint8); ++j) |
ashleymills | 0:ff9ebe0cf0e9 | 883 | if (dtls_uint8_to_int(data) == compression_methods[j]) { |
ashleymills | 0:ff9ebe0cf0e9 | 884 | config->compression = compression_methods[j]; |
ashleymills | 0:ff9ebe0cf0e9 | 885 | ok = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 886 | } |
ashleymills | 0:ff9ebe0cf0e9 | 887 | i -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 888 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 889 | } |
ashleymills | 0:ff9ebe0cf0e9 | 890 | |
ashleymills | 0:ff9ebe0cf0e9 | 891 | if (!ok) { |
ashleymills | 0:ff9ebe0cf0e9 | 892 | /* reset config cipher to a well-defined value */ |
ashleymills | 0:ff9ebe0cf0e9 | 893 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 894 | } |
ashleymills | 0:ff9ebe0cf0e9 | 895 | |
ashleymills | 0:ff9ebe0cf0e9 | 896 | return dtls_check_tls_extension(peer, data, data_length, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 897 | error: |
ashleymills | 0:ff9ebe0cf0e9 | 898 | WARN("ClientHello too short (%d bytes)", data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 899 | if (peer->state == DTLS_STATE_CONNECTED) { |
ashleymills | 0:ff9ebe0cf0e9 | 900 | return dtls_alert_create(DTLS_ALERT_LEVEL_WARNING, DTLS_ALERT_NO_RENEGOTIATION); |
ashleymills | 0:ff9ebe0cf0e9 | 901 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 902 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 903 | } |
ashleymills | 0:ff9ebe0cf0e9 | 904 | } |
ashleymills | 0:ff9ebe0cf0e9 | 905 | |
ashleymills | 0:ff9ebe0cf0e9 | 906 | static inline int |
ashleymills | 0:ff9ebe0cf0e9 | 907 | check_client_keyexchange(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 908 | dtls_handshake_parameters_t *handshake, |
ashleymills | 0:ff9ebe0cf0e9 | 909 | uint8 *data, size_t length) { |
ashleymills | 0:ff9ebe0cf0e9 | 910 | |
ashleymills | 0:ff9ebe0cf0e9 | 911 | if (handshake->cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 912 | |
ashleymills | 0:ff9ebe0cf0e9 | 913 | if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { |
ashleymills | 0:ff9ebe0cf0e9 | 914 | DBG("The client key exchange is too short"); |
ashleymills | 0:ff9ebe0cf0e9 | 915 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 916 | } |
ashleymills | 0:ff9ebe0cf0e9 | 917 | data += DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 918 | |
ashleymills | 0:ff9ebe0cf0e9 | 919 | if (dtls_uint8_to_int(data) != 65) { |
ashleymills | 0:ff9ebe0cf0e9 | 920 | DBG("expected 65 bytes long public point"); |
ashleymills | 0:ff9ebe0cf0e9 | 921 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 922 | } |
ashleymills | 0:ff9ebe0cf0e9 | 923 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 924 | |
ashleymills | 0:ff9ebe0cf0e9 | 925 | if (dtls_uint8_to_int(data) != 4) { |
ashleymills | 0:ff9ebe0cf0e9 | 926 | DBG("expected uncompressed public point"); |
ashleymills | 0:ff9ebe0cf0e9 | 927 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 928 | } |
ashleymills | 0:ff9ebe0cf0e9 | 929 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 930 | |
ashleymills | 0:ff9ebe0cf0e9 | 931 | memcpy(handshake->keyx.ecdsa.other_eph_pub_x, data, |
ashleymills | 0:ff9ebe0cf0e9 | 932 | sizeof(handshake->keyx.ecdsa.other_eph_pub_x)); |
ashleymills | 0:ff9ebe0cf0e9 | 933 | data += sizeof(handshake->keyx.ecdsa.other_eph_pub_x); |
ashleymills | 0:ff9ebe0cf0e9 | 934 | |
ashleymills | 0:ff9ebe0cf0e9 | 935 | memcpy(handshake->keyx.ecdsa.other_eph_pub_y, data, |
ashleymills | 0:ff9ebe0cf0e9 | 936 | sizeof(handshake->keyx.ecdsa.other_eph_pub_y)); |
ashleymills | 0:ff9ebe0cf0e9 | 937 | data += sizeof(handshake->keyx.ecdsa.other_eph_pub_y); |
ashleymills | 0:ff9ebe0cf0e9 | 938 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 939 | int id_length; |
ashleymills | 0:ff9ebe0cf0e9 | 940 | |
ashleymills | 0:ff9ebe0cf0e9 | 941 | if (length < DTLS_HS_LENGTH + DTLS_CKXPSK_LENGTH_MIN) { |
ashleymills | 0:ff9ebe0cf0e9 | 942 | DBG("The client key exchange is too short"); |
ashleymills | 0:ff9ebe0cf0e9 | 943 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 944 | } |
ashleymills | 0:ff9ebe0cf0e9 | 945 | data += DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 946 | |
ashleymills | 0:ff9ebe0cf0e9 | 947 | id_length = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 948 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 949 | |
ashleymills | 0:ff9ebe0cf0e9 | 950 | if (DTLS_HS_LENGTH + DTLS_CKXPSK_LENGTH_MIN + id_length != length) { |
ashleymills | 0:ff9ebe0cf0e9 | 951 | DBG("The identity has a wrong length"); |
ashleymills | 0:ff9ebe0cf0e9 | 952 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 953 | } |
ashleymills | 0:ff9ebe0cf0e9 | 954 | |
ashleymills | 0:ff9ebe0cf0e9 | 955 | if (id_length > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { |
ashleymills | 0:ff9ebe0cf0e9 | 956 | WARN("please use a smaller client identity"); |
ashleymills | 0:ff9ebe0cf0e9 | 957 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 958 | } |
ashleymills | 0:ff9ebe0cf0e9 | 959 | |
ashleymills | 0:ff9ebe0cf0e9 | 960 | handshake->keyx.psk.id_length = id_length; |
ashleymills | 0:ff9ebe0cf0e9 | 961 | memcpy(handshake->keyx.psk.identity, data, id_length); |
ashleymills | 0:ff9ebe0cf0e9 | 962 | } |
ashleymills | 0:ff9ebe0cf0e9 | 963 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 964 | } |
ashleymills | 0:ff9ebe0cf0e9 | 965 | |
ashleymills | 0:ff9ebe0cf0e9 | 966 | static inline void |
ashleymills | 0:ff9ebe0cf0e9 | 967 | update_hs_hash(dtls_peer_t *peer, uint8 *data, size_t length) { |
ashleymills | 0:ff9ebe0cf0e9 | 968 | dtls_dsrv_hexdump_log(LOG_DEBUG, "add MAC data", data, length, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 969 | dtls_hash_update(&peer->hs_state.hs_hash, data, length); |
ashleymills | 0:ff9ebe0cf0e9 | 970 | } |
ashleymills | 0:ff9ebe0cf0e9 | 971 | |
ashleymills | 0:ff9ebe0cf0e9 | 972 | static void |
ashleymills | 0:ff9ebe0cf0e9 | 973 | copy_hs_hash(dtls_peer_t *peer, dtls_hash_ctx *hs_hash) { |
ashleymills | 0:ff9ebe0cf0e9 | 974 | memcpy(hs_hash, &peer->hs_state.hs_hash, sizeof(peer->hs_state.hs_hash)); |
ashleymills | 0:ff9ebe0cf0e9 | 975 | } |
ashleymills | 0:ff9ebe0cf0e9 | 976 | |
ashleymills | 0:ff9ebe0cf0e9 | 977 | static inline size_t |
ashleymills | 0:ff9ebe0cf0e9 | 978 | finalize_hs_hash(dtls_peer_t *peer, uint8 *buf) { |
ashleymills | 0:ff9ebe0cf0e9 | 979 | return dtls_hash_finalize(buf, &peer->hs_state.hs_hash); |
ashleymills | 0:ff9ebe0cf0e9 | 980 | } |
ashleymills | 0:ff9ebe0cf0e9 | 981 | |
ashleymills | 0:ff9ebe0cf0e9 | 982 | static inline void |
ashleymills | 0:ff9ebe0cf0e9 | 983 | clear_hs_hash(dtls_peer_t *peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 984 | assert(peer); |
ashleymills | 0:ff9ebe0cf0e9 | 985 | DBG("clear MAC"); |
ashleymills | 0:ff9ebe0cf0e9 | 986 | dtls_hash_init(&peer->hs_state.hs_hash); |
ashleymills | 0:ff9ebe0cf0e9 | 987 | } |
ashleymills | 0:ff9ebe0cf0e9 | 988 | |
ashleymills | 0:ff9ebe0cf0e9 | 989 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 990 | *Checks if \p record + \p data contain a Finished message with valid |
ashleymills | 0:ff9ebe0cf0e9 | 991 | * verify_data. |
ashleymills | 0:ff9ebe0cf0e9 | 992 | * |
ashleymills | 0:ff9ebe0cf0e9 | 993 | * \param ctx The current DTLS context. |
ashleymills | 0:ff9ebe0cf0e9 | 994 | * \param peer The remote peer of the security association. |
ashleymills | 0:ff9ebe0cf0e9 | 995 | * \param record The message record header. |
ashleymills | 0:ff9ebe0cf0e9 | 996 | * \param rlen The actual length of \p record. |
ashleymills | 0:ff9ebe0cf0e9 | 997 | * \param data The cleartext payload of the message. |
ashleymills | 0:ff9ebe0cf0e9 | 998 | * \param data_length Actual length of \p data. |
ashleymills | 0:ff9ebe0cf0e9 | 999 | * \return \c 1 if the Finished message is valid, \c 0 otherwise. |
ashleymills | 0:ff9ebe0cf0e9 | 1000 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1001 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1002 | check_finished(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1003 | uint8 *record, uint8 *data, size_t data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 1004 | |
ashleymills | 0:ff9ebe0cf0e9 | 1005 | DBG("check_finished"); |
ashleymills | 0:ff9ebe0cf0e9 | 1006 | size_t digest_length, label_size; |
ashleymills | 0:ff9ebe0cf0e9 | 1007 | const unsigned char *label; |
ashleymills | 0:ff9ebe0cf0e9 | 1008 | unsigned char buf[DTLS_HMAC_MAX]; |
ashleymills | 0:ff9ebe0cf0e9 | 1009 | |
ashleymills | 0:ff9ebe0cf0e9 | 1010 | if (data_length < DTLS_HS_LENGTH + DTLS_FIN_LENGTH) |
ashleymills | 0:ff9ebe0cf0e9 | 1011 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 1012 | |
ashleymills | 0:ff9ebe0cf0e9 | 1013 | /* Use a union here to ensure that sufficient stack space is |
ashleymills | 0:ff9ebe0cf0e9 | 1014 | * reserved. As statebuf and verify_data are not used at the same |
ashleymills | 0:ff9ebe0cf0e9 | 1015 | * time, we can re-use the storage safely. |
ashleymills | 0:ff9ebe0cf0e9 | 1016 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1017 | union { |
ashleymills | 0:ff9ebe0cf0e9 | 1018 | unsigned char statebuf[DTLS_HASH_CTX_SIZE]; |
ashleymills | 0:ff9ebe0cf0e9 | 1019 | unsigned char verify_data[DTLS_FIN_LENGTH]; |
ashleymills | 0:ff9ebe0cf0e9 | 1020 | } b; |
ashleymills | 0:ff9ebe0cf0e9 | 1021 | |
ashleymills | 0:ff9ebe0cf0e9 | 1022 | /* temporarily store hash status for roll-back after finalize */ |
ashleymills | 0:ff9ebe0cf0e9 | 1023 | memcpy(b.statebuf, &peer->hs_state.hs_hash, DTLS_HASH_CTX_SIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 1024 | |
ashleymills | 0:ff9ebe0cf0e9 | 1025 | digest_length = finalize_hs_hash(peer, buf); |
ashleymills | 0:ff9ebe0cf0e9 | 1026 | /* clear_hash(); */ |
ashleymills | 0:ff9ebe0cf0e9 | 1027 | |
ashleymills | 0:ff9ebe0cf0e9 | 1028 | /* restore hash status */ |
ashleymills | 0:ff9ebe0cf0e9 | 1029 | memcpy(&peer->hs_state.hs_hash, b.statebuf, DTLS_HASH_CTX_SIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 1030 | |
ashleymills | 0:ff9ebe0cf0e9 | 1031 | if (peer->role == DTLS_CLIENT) { |
ashleymills | 0:ff9ebe0cf0e9 | 1032 | label = PRF_LABEL(server); |
ashleymills | 0:ff9ebe0cf0e9 | 1033 | label_size = PRF_LABEL_SIZE(server); |
ashleymills | 0:ff9ebe0cf0e9 | 1034 | } else { /* client */ |
ashleymills | 0:ff9ebe0cf0e9 | 1035 | label = PRF_LABEL(client); |
ashleymills | 0:ff9ebe0cf0e9 | 1036 | label_size = PRF_LABEL_SIZE(client); |
ashleymills | 0:ff9ebe0cf0e9 | 1037 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1038 | |
ashleymills | 0:ff9ebe0cf0e9 | 1039 | dtls_prf(peer->handshake_params.tmp.master_secret, |
ashleymills | 0:ff9ebe0cf0e9 | 1040 | DTLS_MASTER_SECRET_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 1041 | label, label_size, |
ashleymills | 0:ff9ebe0cf0e9 | 1042 | PRF_LABEL(finished), PRF_LABEL_SIZE(finished), |
ashleymills | 0:ff9ebe0cf0e9 | 1043 | buf, digest_length, |
ashleymills | 0:ff9ebe0cf0e9 | 1044 | b.verify_data, sizeof(b.verify_data)); |
ashleymills | 0:ff9ebe0cf0e9 | 1045 | |
ashleymills | 0:ff9ebe0cf0e9 | 1046 | dtls_dsrv_hexdump_log(LOG_DEBUG, "d:", data + DTLS_HS_LENGTH, sizeof(b.verify_data), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1047 | dtls_dsrv_hexdump_log(LOG_DEBUG, "v:", b.verify_data, sizeof(b.verify_data), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1048 | return memcmp(data + DTLS_HS_LENGTH, b.verify_data, sizeof(b.verify_data)); |
ashleymills | 0:ff9ebe0cf0e9 | 1049 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1050 | |
ashleymills | 0:ff9ebe0cf0e9 | 1051 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 1052 | * Prepares the payload given in \p data for sending with |
ashleymills | 0:ff9ebe0cf0e9 | 1053 | * dtls_send(). The \p data is encrypted and compressed according to |
ashleymills | 0:ff9ebe0cf0e9 | 1054 | * the current security parameters of \p peer. The result of this |
ashleymills | 0:ff9ebe0cf0e9 | 1055 | * operation is put into \p sendbuf with a prepended record header of |
ashleymills | 0:ff9ebe0cf0e9 | 1056 | * type \p type ready for sending. As some cipher suites add a MAC |
ashleymills | 0:ff9ebe0cf0e9 | 1057 | * before encryption, \p data must be large enough to hold this data |
ashleymills | 0:ff9ebe0cf0e9 | 1058 | * as well (usually \c dtls_kb_digest_size(CURRENT_CONFIG(peer)). |
ashleymills | 0:ff9ebe0cf0e9 | 1059 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1060 | * \param peer The remote peer the packet will be sent to. |
ashleymills | 0:ff9ebe0cf0e9 | 1061 | * \param type The content type of this record. |
ashleymills | 0:ff9ebe0cf0e9 | 1062 | * \param data The payload to send. |
ashleymills | 0:ff9ebe0cf0e9 | 1063 | * \param data_length The size of \p data. |
ashleymills | 0:ff9ebe0cf0e9 | 1064 | * \param sendbuf The output buffer where the encrypted record |
ashleymills | 0:ff9ebe0cf0e9 | 1065 | * will be placed. |
ashleymills | 0:ff9ebe0cf0e9 | 1066 | * \param rlen This parameter must be initialized with the |
ashleymills | 0:ff9ebe0cf0e9 | 1067 | * maximum size of \p sendbuf and will be updated |
ashleymills | 0:ff9ebe0cf0e9 | 1068 | * to hold the actual size of the stored packet |
ashleymills | 0:ff9ebe0cf0e9 | 1069 | * on success. On error, the value of \p rlen is |
ashleymills | 0:ff9ebe0cf0e9 | 1070 | * undefined. |
ashleymills | 0:ff9ebe0cf0e9 | 1071 | * \return Less than zero on error, or greater than zero success. |
ashleymills | 0:ff9ebe0cf0e9 | 1072 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1073 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1074 | dtls_prepare_record(dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1075 | unsigned char type, |
ashleymills | 0:ff9ebe0cf0e9 | 1076 | uint8 *data_array[], size_t data_len_array[], |
ashleymills | 0:ff9ebe0cf0e9 | 1077 | size_t data_array_len, |
ashleymills | 0:ff9ebe0cf0e9 | 1078 | uint8 *sendbuf, size_t *rlen) { |
ashleymills | 0:ff9ebe0cf0e9 | 1079 | DBG("dtls_prepare_record"); |
ashleymills | 0:ff9ebe0cf0e9 | 1080 | |
ashleymills | 0:ff9ebe0cf0e9 | 1081 | uint8 *p, *start; |
ashleymills | 0:ff9ebe0cf0e9 | 1082 | int res; |
ashleymills | 0:ff9ebe0cf0e9 | 1083 | int i; |
ashleymills | 0:ff9ebe0cf0e9 | 1084 | dtls_security_parameters_t *security = &peer->security_params; |
ashleymills | 0:ff9ebe0cf0e9 | 1085 | |
ashleymills | 0:ff9ebe0cf0e9 | 1086 | p = dtls_set_record_header(type, peer, sendbuf); |
ashleymills | 0:ff9ebe0cf0e9 | 1087 | start = p; |
ashleymills | 0:ff9ebe0cf0e9 | 1088 | |
ashleymills | 0:ff9ebe0cf0e9 | 1089 | if (!peer || security->cipher == TLS_NULL_WITH_NULL_NULL) { |
ashleymills | 0:ff9ebe0cf0e9 | 1090 | /* no cipher suite */ |
ashleymills | 0:ff9ebe0cf0e9 | 1091 | |
ashleymills | 0:ff9ebe0cf0e9 | 1092 | res = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1093 | for (i = 0; i < data_array_len; i++) { |
ashleymills | 0:ff9ebe0cf0e9 | 1094 | /* check the minimum that we need for packets that are not encrypted */ |
ashleymills | 0:ff9ebe0cf0e9 | 1095 | if (*rlen < (p - start) + data_len_array[i]) { |
ashleymills | 0:ff9ebe0cf0e9 | 1096 | DBG("dtls_prepare_record: send buffer too small"); |
ashleymills | 0:ff9ebe0cf0e9 | 1097 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1098 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1099 | |
ashleymills | 0:ff9ebe0cf0e9 | 1100 | memcpy(p, data_array[i], data_len_array[i]); |
ashleymills | 0:ff9ebe0cf0e9 | 1101 | p += data_len_array[i]; |
ashleymills | 0:ff9ebe0cf0e9 | 1102 | res += data_len_array[i]; |
ashleymills | 0:ff9ebe0cf0e9 | 1103 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1104 | } else { /* TLS_PSK_WITH_AES_128_CCM_8 */ |
ashleymills | 0:ff9ebe0cf0e9 | 1105 | dtls_cipher_context_t *cipher_context; |
ashleymills | 0:ff9ebe0cf0e9 | 1106 | |
ashleymills | 0:ff9ebe0cf0e9 | 1107 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 1108 | * length of additional_data for the AEAD cipher which consists of |
ashleymills | 0:ff9ebe0cf0e9 | 1109 | * seq_num(2+6) + type(1) + version(2) + length(2) |
ashleymills | 0:ff9ebe0cf0e9 | 1110 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1111 | #define A_DATA_LEN 13 |
ashleymills | 0:ff9ebe0cf0e9 | 1112 | unsigned char nonce[DTLS_CCM_BLOCKSIZE]; |
ashleymills | 0:ff9ebe0cf0e9 | 1113 | unsigned char A_DATA[A_DATA_LEN]; |
ashleymills | 0:ff9ebe0cf0e9 | 1114 | |
ashleymills | 0:ff9ebe0cf0e9 | 1115 | if (security->cipher == TLS_PSK_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 1116 | DBG("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_8"); |
ashleymills | 0:ff9ebe0cf0e9 | 1117 | } else if (security->cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 1118 | DBG("dtls_prepare_record(): encrypt using TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"); |
ashleymills | 0:ff9ebe0cf0e9 | 1119 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 1120 | DBG("dtls_prepare_record(): encrypt using unknown cipher"); |
ashleymills | 0:ff9ebe0cf0e9 | 1121 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1122 | |
ashleymills | 0:ff9ebe0cf0e9 | 1123 | /* set nonce |
ashleymills | 0:ff9ebe0cf0e9 | 1124 | from http://tools.ietf.org/html/draft-mcgrew-tls-aes-ccm-03: |
ashleymills | 0:ff9ebe0cf0e9 | 1125 | struct { |
ashleymills | 0:ff9ebe0cf0e9 | 1126 | case client: |
ashleymills | 0:ff9ebe0cf0e9 | 1127 | uint32 client_write_IV; // low order 32-bits |
ashleymills | 0:ff9ebe0cf0e9 | 1128 | case server: |
ashleymills | 0:ff9ebe0cf0e9 | 1129 | uint32 server_write_IV; // low order 32-bits |
ashleymills | 0:ff9ebe0cf0e9 | 1130 | uint64 seq_num; |
ashleymills | 0:ff9ebe0cf0e9 | 1131 | } CCMNonce. |
ashleymills | 0:ff9ebe0cf0e9 | 1132 | |
ashleymills | 0:ff9ebe0cf0e9 | 1133 | In DTLS, the 64-bit seq_num is the 16-bit epoch concatenated with the |
ashleymills | 0:ff9ebe0cf0e9 | 1134 | 48-bit seq_num. |
ashleymills | 0:ff9ebe0cf0e9 | 1135 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1136 | |
ashleymills | 0:ff9ebe0cf0e9 | 1137 | memcpy(p, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); |
ashleymills | 0:ff9ebe0cf0e9 | 1138 | p += 8; |
ashleymills | 0:ff9ebe0cf0e9 | 1139 | res = 8; |
ashleymills | 0:ff9ebe0cf0e9 | 1140 | |
ashleymills | 0:ff9ebe0cf0e9 | 1141 | for (i = 0; i < data_array_len; i++) { |
ashleymills | 0:ff9ebe0cf0e9 | 1142 | /* check the minimum that we need for packets that are not encrypted */ |
ashleymills | 0:ff9ebe0cf0e9 | 1143 | if (*rlen < res + data_len_array[i]) { |
ashleymills | 0:ff9ebe0cf0e9 | 1144 | DBG("dtls_prepare_record: send buffer too small"); |
ashleymills | 0:ff9ebe0cf0e9 | 1145 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1146 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1147 | |
ashleymills | 0:ff9ebe0cf0e9 | 1148 | memcpy(p, data_array[i], data_len_array[i]); |
ashleymills | 0:ff9ebe0cf0e9 | 1149 | p += data_len_array[i]; |
ashleymills | 0:ff9ebe0cf0e9 | 1150 | res += data_len_array[i]; |
ashleymills | 0:ff9ebe0cf0e9 | 1151 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1152 | |
ashleymills | 0:ff9ebe0cf0e9 | 1153 | memset(nonce, 0, DTLS_CCM_BLOCKSIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 1154 | memcpy(nonce, dtls_kb_local_iv(security, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 1155 | dtls_kb_iv_size(security, peer->role)); |
ashleymills | 0:ff9ebe0cf0e9 | 1156 | memcpy(nonce + dtls_kb_iv_size(security, peer->role), start, 8); /* epoch + seq_num */ |
ashleymills | 0:ff9ebe0cf0e9 | 1157 | |
ashleymills | 0:ff9ebe0cf0e9 | 1158 | cipher_context = security->write_cipher; |
ashleymills | 0:ff9ebe0cf0e9 | 1159 | |
ashleymills | 0:ff9ebe0cf0e9 | 1160 | if (!cipher_context) { |
ashleymills | 0:ff9ebe0cf0e9 | 1161 | WARN("no write_cipher available!"); |
ashleymills | 0:ff9ebe0cf0e9 | 1162 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1163 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1164 | |
ashleymills | 0:ff9ebe0cf0e9 | 1165 | dtls_dsrv_hexdump_log(LOG_DEBUG, "nonce:", nonce, DTLS_CCM_BLOCKSIZE, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1166 | dtls_dsrv_hexdump_log(LOG_DEBUG, "key:", |
ashleymills | 0:ff9ebe0cf0e9 | 1167 | dtls_kb_local_write_key(security, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 1168 | dtls_kb_key_size(security, peer->role), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1169 | |
ashleymills | 0:ff9ebe0cf0e9 | 1170 | /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3: |
ashleymills | 0:ff9ebe0cf0e9 | 1171 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1172 | * additional_data = seq_num + TLSCompressed.type + |
ashleymills | 0:ff9ebe0cf0e9 | 1173 | * TLSCompressed.version + TLSCompressed.length; |
ashleymills | 0:ff9ebe0cf0e9 | 1174 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1175 | memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */ |
ashleymills | 0:ff9ebe0cf0e9 | 1176 | memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */ |
ashleymills | 0:ff9ebe0cf0e9 | 1177 | dtls_int_to_uint16(A_DATA + 11, res - 8); /* length */ |
ashleymills | 0:ff9ebe0cf0e9 | 1178 | |
ashleymills | 0:ff9ebe0cf0e9 | 1179 | res = dtls_encrypt(cipher_context, start + 8, res - 8, start + 8, nonce, |
ashleymills | 0:ff9ebe0cf0e9 | 1180 | A_DATA, A_DATA_LEN); |
ashleymills | 0:ff9ebe0cf0e9 | 1181 | |
ashleymills | 0:ff9ebe0cf0e9 | 1182 | if (res < 0) |
ashleymills | 0:ff9ebe0cf0e9 | 1183 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1184 | |
ashleymills | 0:ff9ebe0cf0e9 | 1185 | res += 8; /* increment res by size of nonce_explicit */ |
ashleymills | 0:ff9ebe0cf0e9 | 1186 | dtls_dsrv_hexdump_log(LOG_DEBUG, "message:", start, res, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1187 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1188 | |
ashleymills | 0:ff9ebe0cf0e9 | 1189 | /* fix length of fragment in sendbuf */ |
ashleymills | 0:ff9ebe0cf0e9 | 1190 | dtls_int_to_uint16(sendbuf + 11, res); |
ashleymills | 0:ff9ebe0cf0e9 | 1191 | |
ashleymills | 0:ff9ebe0cf0e9 | 1192 | *rlen = DTLS_RH_LENGTH + res; |
ashleymills | 0:ff9ebe0cf0e9 | 1193 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1194 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1195 | |
ashleymills | 0:ff9ebe0cf0e9 | 1196 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1197 | dtls_send_handshake_msg_hash(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 1198 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1199 | session_t *session, |
ashleymills | 0:ff9ebe0cf0e9 | 1200 | uint8 header_type, |
ashleymills | 0:ff9ebe0cf0e9 | 1201 | uint8 *data, size_t data_length, |
ashleymills | 0:ff9ebe0cf0e9 | 1202 | int add_hash) |
ashleymills | 0:ff9ebe0cf0e9 | 1203 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1204 | DBG("dtls_send_handshake_msg_hash"); |
ashleymills | 0:ff9ebe0cf0e9 | 1205 | uint8 buf[DTLS_HS_LENGTH]; |
ashleymills | 0:ff9ebe0cf0e9 | 1206 | uint8 *data_array[2]; |
ashleymills | 0:ff9ebe0cf0e9 | 1207 | size_t data_len_array[2]; |
ashleymills | 0:ff9ebe0cf0e9 | 1208 | int i = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1209 | uint8 sendbuf[DTLS_MAX_BUF]; |
ashleymills | 0:ff9ebe0cf0e9 | 1210 | size_t len = sizeof(sendbuf); |
ashleymills | 0:ff9ebe0cf0e9 | 1211 | |
ashleymills | 0:ff9ebe0cf0e9 | 1212 | dtls_set_handshake_header(header_type, (add_hash) ? peer : NULL, data_length, 0, |
ashleymills | 0:ff9ebe0cf0e9 | 1213 | data_length, buf); |
ashleymills | 0:ff9ebe0cf0e9 | 1214 | |
ashleymills | 0:ff9ebe0cf0e9 | 1215 | if (add_hash) { |
ashleymills | 0:ff9ebe0cf0e9 | 1216 | update_hs_hash(peer, buf, sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 1217 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1218 | data_array[i] = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 1219 | data_len_array[i] = sizeof(buf); |
ashleymills | 0:ff9ebe0cf0e9 | 1220 | i++; |
ashleymills | 0:ff9ebe0cf0e9 | 1221 | |
ashleymills | 0:ff9ebe0cf0e9 | 1222 | if (data != NULL) { |
ashleymills | 0:ff9ebe0cf0e9 | 1223 | if (add_hash) { |
ashleymills | 0:ff9ebe0cf0e9 | 1224 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 1225 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1226 | data_array[i] = data; |
ashleymills | 0:ff9ebe0cf0e9 | 1227 | data_len_array[i] = data_length; |
ashleymills | 0:ff9ebe0cf0e9 | 1228 | i++; |
ashleymills | 0:ff9ebe0cf0e9 | 1229 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1230 | i = dtls_prepare_record(peer, DTLS_CT_HANDSHAKE, data_array, data_len_array, |
ashleymills | 0:ff9ebe0cf0e9 | 1231 | i, sendbuf, &len); |
ashleymills | 0:ff9ebe0cf0e9 | 1232 | if (i < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1233 | return i; |
ashleymills | 0:ff9ebe0cf0e9 | 1234 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1235 | |
ashleymills | 0:ff9ebe0cf0e9 | 1236 | return CALL(ctx, write, session, sendbuf, len); |
ashleymills | 0:ff9ebe0cf0e9 | 1237 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1238 | |
ashleymills | 0:ff9ebe0cf0e9 | 1239 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1240 | dtls_send_handshake_msg(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 1241 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1242 | uint8 header_type, |
ashleymills | 0:ff9ebe0cf0e9 | 1243 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 1244 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1245 | return dtls_send_handshake_msg_hash(ctx, peer, &peer->session, |
ashleymills | 0:ff9ebe0cf0e9 | 1246 | header_type, data, data_length, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 1247 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1248 | |
ashleymills | 0:ff9ebe0cf0e9 | 1249 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 1250 | * Returns true if the message @p Data is a handshake message that |
ashleymills | 0:ff9ebe0cf0e9 | 1251 | * must be included in the calculation of verify_data in the Finished |
ashleymills | 0:ff9ebe0cf0e9 | 1252 | * message. |
ashleymills | 0:ff9ebe0cf0e9 | 1253 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1254 | * @param Type The message type. Only handshake messages but the initial |
ashleymills | 0:ff9ebe0cf0e9 | 1255 | * Client Hello and Hello Verify Request are included in the hash, |
ashleymills | 0:ff9ebe0cf0e9 | 1256 | * @param Data The PDU to examine. |
ashleymills | 0:ff9ebe0cf0e9 | 1257 | * @param Length The length of @p Data. |
ashleymills | 0:ff9ebe0cf0e9 | 1258 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1259 | * @return @c 1 if @p Data must be included in hash, @c 0 otherwise. |
ashleymills | 0:ff9ebe0cf0e9 | 1260 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1261 | * @hideinitializer |
ashleymills | 0:ff9ebe0cf0e9 | 1262 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1263 | #define MUST_HASH(Type, Data, Length) \ |
ashleymills | 0:ff9ebe0cf0e9 | 1264 | ((Type) == DTLS_CT_HANDSHAKE && \ |
ashleymills | 0:ff9ebe0cf0e9 | 1265 | ((Data) != NULL) && ((Length) > 0) && \ |
ashleymills | 0:ff9ebe0cf0e9 | 1266 | ((Data)[0] != DTLS_HT_HELLO_VERIFY_REQUEST) && \ |
ashleymills | 0:ff9ebe0cf0e9 | 1267 | ((Data)[0] != DTLS_HT_CLIENT_HELLO || \ |
ashleymills | 0:ff9ebe0cf0e9 | 1268 | ((Length) >= HS_HDR_LENGTH && \ |
ashleymills | 0:ff9ebe0cf0e9 | 1269 | (dtls_uint16_to_int(DTLS_RECORD_HEADER(Data)->epoch > 0) || \ |
ashleymills | 0:ff9ebe0cf0e9 | 1270 | (dtls_uint16_to_int(HANDSHAKE(Data)->message_seq) > 0))))) |
ashleymills | 0:ff9ebe0cf0e9 | 1271 | |
ashleymills | 0:ff9ebe0cf0e9 | 1272 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 1273 | * Sends the data passed in @p buf as a DTLS record of type @p type to |
ashleymills | 0:ff9ebe0cf0e9 | 1274 | * the given peer. The data will be encrypted and compressed according |
ashleymills | 0:ff9ebe0cf0e9 | 1275 | * to the security parameters for @p peer. |
ashleymills | 0:ff9ebe0cf0e9 | 1276 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1277 | * @param ctx The DTLS context in effect. |
ashleymills | 0:ff9ebe0cf0e9 | 1278 | * @param peer The remote party where the packet is sent. |
ashleymills | 0:ff9ebe0cf0e9 | 1279 | * @param type The content type of this record. |
ashleymills | 0:ff9ebe0cf0e9 | 1280 | * @param buf The data to send. |
ashleymills | 0:ff9ebe0cf0e9 | 1281 | * @param buflen The number of bytes to send from @p buf. |
ashleymills | 0:ff9ebe0cf0e9 | 1282 | * @return Less than zero in case of an error or the number of |
ashleymills | 0:ff9ebe0cf0e9 | 1283 | * bytes that have been sent otherwise. |
ashleymills | 0:ff9ebe0cf0e9 | 1284 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1285 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1286 | dtls_send(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1287 | unsigned char type, |
ashleymills | 0:ff9ebe0cf0e9 | 1288 | uint8 *buf, size_t buflen) { |
ashleymills | 0:ff9ebe0cf0e9 | 1289 | |
ashleymills | 0:ff9ebe0cf0e9 | 1290 | /* We cannot use ctx->sendbuf here as it is reserved for collecting |
ashleymills | 0:ff9ebe0cf0e9 | 1291 | * the input for this function, i.e. buf == ctx->sendbuf. |
ashleymills | 0:ff9ebe0cf0e9 | 1292 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1293 | * TODO: check if we can use the receive buf here. This would mean |
ashleymills | 0:ff9ebe0cf0e9 | 1294 | * that we might not be able to handle multiple records stuffed in |
ashleymills | 0:ff9ebe0cf0e9 | 1295 | * one UDP datagram */ |
ashleymills | 0:ff9ebe0cf0e9 | 1296 | unsigned char sendbuf[DTLS_MAX_BUF]; |
ashleymills | 0:ff9ebe0cf0e9 | 1297 | size_t len = sizeof(sendbuf); |
ashleymills | 0:ff9ebe0cf0e9 | 1298 | int res; |
ashleymills | 0:ff9ebe0cf0e9 | 1299 | |
ashleymills | 0:ff9ebe0cf0e9 | 1300 | res = dtls_prepare_record(peer, type, &buf, &buflen, 1, sendbuf, &len); |
ashleymills | 0:ff9ebe0cf0e9 | 1301 | |
ashleymills | 0:ff9ebe0cf0e9 | 1302 | if (res < 0) |
ashleymills | 0:ff9ebe0cf0e9 | 1303 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1304 | |
ashleymills | 0:ff9ebe0cf0e9 | 1305 | /* if (peer && MUST_HASH(peer, type, buf, buflen)) */ |
ashleymills | 0:ff9ebe0cf0e9 | 1306 | /* update_hs_hash(peer, buf, buflen); */ |
ashleymills | 0:ff9ebe0cf0e9 | 1307 | |
ashleymills | 0:ff9ebe0cf0e9 | 1308 | dtls_dsrv_hexdump_log(LOG_DEBUG, "send header", sendbuf, |
ashleymills | 0:ff9ebe0cf0e9 | 1309 | sizeof(dtls_record_header_t), 1); |
ashleymills | 0:ff9ebe0cf0e9 | 1310 | dtls_dsrv_hexdump_log(LOG_DEBUG, "send unencrypted", buf, buflen, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 1311 | |
ashleymills | 0:ff9ebe0cf0e9 | 1312 | if (type == DTLS_CT_HANDSHAKE && buf[0] != DTLS_HT_HELLO_VERIFY_REQUEST) { |
ashleymills | 0:ff9ebe0cf0e9 | 1313 | /* copy handshake messages other than HelloVerify into retransmit buffer */ |
ashleymills | 0:ff9ebe0cf0e9 | 1314 | netq_t *n = netq_node_new(); |
ashleymills | 0:ff9ebe0cf0e9 | 1315 | if (n) { |
ashleymills | 0:ff9ebe0cf0e9 | 1316 | dtls_tick_t now; |
ashleymills | 0:ff9ebe0cf0e9 | 1317 | dtls_ticks(&now); |
ashleymills | 0:ff9ebe0cf0e9 | 1318 | n->t = now + 2 * CLOCK_SECOND; |
ashleymills | 0:ff9ebe0cf0e9 | 1319 | n->retransmit_cnt = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1320 | n->timeout = 2 * CLOCK_SECOND; |
ashleymills | 0:ff9ebe0cf0e9 | 1321 | n->peer = peer; |
ashleymills | 0:ff9ebe0cf0e9 | 1322 | n->length = buflen; |
ashleymills | 0:ff9ebe0cf0e9 | 1323 | memcpy(n->data, buf, buflen); |
ashleymills | 0:ff9ebe0cf0e9 | 1324 | |
ashleymills | 0:ff9ebe0cf0e9 | 1325 | if (!netq_insert_node((netq_t **)ctx->sendqueue, n)) { |
ashleymills | 0:ff9ebe0cf0e9 | 1326 | WARN("cannot add packet to retransmit buffer"); |
ashleymills | 0:ff9ebe0cf0e9 | 1327 | netq_node_free(n); |
ashleymills | 0:ff9ebe0cf0e9 | 1328 | #ifdef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 1329 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 1330 | /* must set timer within the context of the retransmit process */ |
ashleymills | 0:ff9ebe0cf0e9 | 1331 | PROCESS_CONTEXT_BEGIN(&dtls_retransmit_process); |
ashleymills | 0:ff9ebe0cf0e9 | 1332 | etimer_set(&ctx->retransmit_timer, n->timeout); |
ashleymills | 0:ff9ebe0cf0e9 | 1333 | PROCESS_CONTEXT_END(&dtls_retransmit_process); |
ashleymills | 0:ff9ebe0cf0e9 | 1334 | #else /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 1335 | DBG("copied to sendqueue"); |
ashleymills | 0:ff9ebe0cf0e9 | 1336 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 1337 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1338 | } else |
ashleymills | 0:ff9ebe0cf0e9 | 1339 | WARN("retransmit buffer full"); |
ashleymills | 0:ff9ebe0cf0e9 | 1340 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1341 | |
ashleymills | 0:ff9ebe0cf0e9 | 1342 | /* FIXME: copy to peer's sendqueue (after fragmentation if |
ashleymills | 0:ff9ebe0cf0e9 | 1343 | * necessary) and initialize retransmit timer */ |
ashleymills | 0:ff9ebe0cf0e9 | 1344 | res = CALL(ctx, write, &peer->session, sendbuf, len); |
ashleymills | 0:ff9ebe0cf0e9 | 1345 | |
ashleymills | 0:ff9ebe0cf0e9 | 1346 | /* Guess number of bytes application data actually sent: |
ashleymills | 0:ff9ebe0cf0e9 | 1347 | * dtls_prepare_record() tells us in len the number of bytes to |
ashleymills | 0:ff9ebe0cf0e9 | 1348 | * send, res will contain the bytes actually sent. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1349 | return res <= 0 ? res : buflen - (len - res); |
ashleymills | 0:ff9ebe0cf0e9 | 1350 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1351 | |
ashleymills | 0:ff9ebe0cf0e9 | 1352 | static inline int |
ashleymills | 0:ff9ebe0cf0e9 | 1353 | dtls_alert(dtls_context_t *ctx, dtls_peer_t *peer, dtls_alert_level_t level, |
ashleymills | 0:ff9ebe0cf0e9 | 1354 | dtls_alert_t description) { |
ashleymills | 0:ff9ebe0cf0e9 | 1355 | uint8_t msg[] = { level, description }; |
ashleymills | 0:ff9ebe0cf0e9 | 1356 | |
ashleymills | 0:ff9ebe0cf0e9 | 1357 | dtls_send(ctx, peer, DTLS_CT_ALERT, msg, sizeof(msg)); |
ashleymills | 0:ff9ebe0cf0e9 | 1358 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1359 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1360 | |
ashleymills | 0:ff9ebe0cf0e9 | 1361 | int |
ashleymills | 0:ff9ebe0cf0e9 | 1362 | dtls_close(dtls_context_t *ctx, const session_t *remote) { |
ashleymills | 0:ff9ebe0cf0e9 | 1363 | int res = -1; |
ashleymills | 0:ff9ebe0cf0e9 | 1364 | dtls_peer_t *peer; |
ashleymills | 0:ff9ebe0cf0e9 | 1365 | |
ashleymills | 0:ff9ebe0cf0e9 | 1366 | peer = dtls_get_peer(ctx, remote); |
ashleymills | 0:ff9ebe0cf0e9 | 1367 | |
ashleymills | 0:ff9ebe0cf0e9 | 1368 | if (peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 1369 | res = dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_CLOSE_NOTIFY); |
ashleymills | 0:ff9ebe0cf0e9 | 1370 | /* indicate tear down */ |
ashleymills | 0:ff9ebe0cf0e9 | 1371 | peer->state = DTLS_STATE_CLOSING; |
ashleymills | 0:ff9ebe0cf0e9 | 1372 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1373 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1374 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1375 | |
ashleymills | 0:ff9ebe0cf0e9 | 1376 | static void dtls_destory_peer(dtls_context_t *ctx, dtls_peer_t *peer, int unlink) |
ashleymills | 0:ff9ebe0cf0e9 | 1377 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1378 | if (peer->state != DTLS_STATE_CLOSED) |
ashleymills | 0:ff9ebe0cf0e9 | 1379 | dtls_close(ctx, &peer->session); |
ashleymills | 0:ff9ebe0cf0e9 | 1380 | if (unlink) { |
ashleymills | 0:ff9ebe0cf0e9 | 1381 | #ifndef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 1382 | HASH_DEL_PEER(ctx->peers, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 1383 | #else /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 1384 | list_remove(ctx->peers, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 1385 | |
ashleymills | 0:ff9ebe0cf0e9 | 1386 | #ifndef NDEBUG |
ashleymills | 0:ff9ebe0cf0e9 | 1387 | PRINTF("removed peer ["); |
ashleymills | 0:ff9ebe0cf0e9 | 1388 | PRINT6ADDR(&peer->session.addr); |
ashleymills | 0:ff9ebe0cf0e9 | 1389 | PRINTF("]:%d", uip_ntohs(peer->session.port)); |
ashleymills | 0:ff9ebe0cf0e9 | 1390 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 1391 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 1392 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1393 | dtls_free_peer(peer); |
ashleymills | 0:ff9ebe0cf0e9 | 1394 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1395 | |
ashleymills | 0:ff9ebe0cf0e9 | 1396 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 1397 | * Checks a received Client Hello message for a valid cookie. When the |
ashleymills | 0:ff9ebe0cf0e9 | 1398 | * Client Hello contains no cookie, the function fails and a Hello |
ashleymills | 0:ff9ebe0cf0e9 | 1399 | * Verify Request is sent to the peer (using the write callback function |
ashleymills | 0:ff9ebe0cf0e9 | 1400 | * registered with \p ctx). The return value is \c -1 on error, \c 0 when |
ashleymills | 0:ff9ebe0cf0e9 | 1401 | * undecided, and \c 1 if the Client Hello was good. |
ashleymills | 0:ff9ebe0cf0e9 | 1402 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1403 | * \param ctx The DTLS context. |
ashleymills | 0:ff9ebe0cf0e9 | 1404 | * \param peer The remote party we are talking to, if any. |
ashleymills | 0:ff9ebe0cf0e9 | 1405 | * \param session Transport address of the remote peer. |
ashleymills | 0:ff9ebe0cf0e9 | 1406 | * \param msg The received datagram. |
ashleymills | 0:ff9ebe0cf0e9 | 1407 | * \param msglen Length of \p msg. |
ashleymills | 0:ff9ebe0cf0e9 | 1408 | * \return \c 1 if msg is a Client Hello with a valid cookie, \c 0 or |
ashleymills | 0:ff9ebe0cf0e9 | 1409 | * \c -1 otherwise. |
ashleymills | 0:ff9ebe0cf0e9 | 1410 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 1411 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1412 | dtls_verify_peer(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 1413 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1414 | session_t *session, |
ashleymills | 0:ff9ebe0cf0e9 | 1415 | uint8 *record, |
ashleymills | 0:ff9ebe0cf0e9 | 1416 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 1417 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1418 | |
ashleymills | 0:ff9ebe0cf0e9 | 1419 | DBG("dtls_verify_peer"); |
ashleymills | 0:ff9ebe0cf0e9 | 1420 | |
ashleymills | 0:ff9ebe0cf0e9 | 1421 | uint8 buf[DTLS_HV_LENGTH + DTLS_COOKIE_LENGTH]; |
ashleymills | 0:ff9ebe0cf0e9 | 1422 | uint8 *p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 1423 | int len = DTLS_COOKIE_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 1424 | uint8 *cookie; |
ashleymills | 0:ff9ebe0cf0e9 | 1425 | int err; |
ashleymills | 0:ff9ebe0cf0e9 | 1426 | #undef mycookie |
ashleymills | 0:ff9ebe0cf0e9 | 1427 | #define mycookie (buf + DTLS_HV_LENGTH) |
ashleymills | 0:ff9ebe0cf0e9 | 1428 | |
ashleymills | 0:ff9ebe0cf0e9 | 1429 | /* Store cookie where we can reuse it for the HelloVerify request. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1430 | err = dtls_create_cookie(ctx, session, data, data_length, mycookie, &len); |
ashleymills | 0:ff9ebe0cf0e9 | 1431 | if (err < 0) |
ashleymills | 0:ff9ebe0cf0e9 | 1432 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 1433 | |
ashleymills | 0:ff9ebe0cf0e9 | 1434 | dtls_dsrv_hexdump_log(LOG_DEBUG, "create cookie", mycookie, len, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1435 | |
ashleymills | 0:ff9ebe0cf0e9 | 1436 | assert(len == DTLS_COOKIE_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 1437 | |
ashleymills | 0:ff9ebe0cf0e9 | 1438 | /* Perform cookie check. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1439 | len = dtls_get_cookie(data, data_length, &cookie); |
ashleymills | 0:ff9ebe0cf0e9 | 1440 | if (len < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1441 | WARN("error while fetching the cookie, err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 1442 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 1443 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1444 | |
ashleymills | 0:ff9ebe0cf0e9 | 1445 | dtls_dsrv_hexdump_log(LOG_DEBUG, "compare with cookie", cookie, len, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1446 | |
ashleymills | 0:ff9ebe0cf0e9 | 1447 | /* check if cookies match */ |
ashleymills | 0:ff9ebe0cf0e9 | 1448 | if (len == DTLS_COOKIE_LENGTH && memcmp(cookie, mycookie, len) == 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1449 | DBG("found matching cookie"); |
ashleymills | 0:ff9ebe0cf0e9 | 1450 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1451 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1452 | |
ashleymills | 0:ff9ebe0cf0e9 | 1453 | if (len > 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1454 | dtls_dsrv_hexdump_log(LOG_DEBUG, "invalid cookie", cookie, len, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1455 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 1456 | DBG("cookie len is 0!"); |
ashleymills | 0:ff9ebe0cf0e9 | 1457 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1458 | |
ashleymills | 0:ff9ebe0cf0e9 | 1459 | /* ClientHello did not contain any valid cookie, hence we send a |
ashleymills | 0:ff9ebe0cf0e9 | 1460 | * HelloVerify request. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1461 | |
ashleymills | 0:ff9ebe0cf0e9 | 1462 | dtls_int_to_uint16(p, DTLS_VERSION); |
ashleymills | 0:ff9ebe0cf0e9 | 1463 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1464 | |
ashleymills | 0:ff9ebe0cf0e9 | 1465 | dtls_int_to_uint8(p, DTLS_COOKIE_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 1466 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1467 | |
ashleymills | 0:ff9ebe0cf0e9 | 1468 | assert(p == mycookie); |
ashleymills | 0:ff9ebe0cf0e9 | 1469 | |
ashleymills | 0:ff9ebe0cf0e9 | 1470 | p += DTLS_COOKIE_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 1471 | |
ashleymills | 0:ff9ebe0cf0e9 | 1472 | err = dtls_send_handshake_msg_hash(ctx, peer, session, |
ashleymills | 0:ff9ebe0cf0e9 | 1473 | DTLS_HT_HELLO_VERIFY_REQUEST, |
ashleymills | 0:ff9ebe0cf0e9 | 1474 | buf, p - buf, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1475 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1476 | WARN("cannot send HelloVerify request"); |
ashleymills | 0:ff9ebe0cf0e9 | 1477 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1478 | return err; /* HelloVerify is sent, now we cannot do anything but wait */ |
ashleymills | 0:ff9ebe0cf0e9 | 1479 | |
ashleymills | 0:ff9ebe0cf0e9 | 1480 | #undef mycookie |
ashleymills | 0:ff9ebe0cf0e9 | 1481 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1482 | |
ashleymills | 0:ff9ebe0cf0e9 | 1483 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1484 | check_client_certificate_verify(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 1485 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1486 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 1487 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1488 | DBG("check_client_certificate_verify"); |
ashleymills | 0:ff9ebe0cf0e9 | 1489 | |
ashleymills | 0:ff9ebe0cf0e9 | 1490 | dtls_handshake_parameters_t *config = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 1491 | int i; |
ashleymills | 0:ff9ebe0cf0e9 | 1492 | unsigned char *result_r; |
ashleymills | 0:ff9ebe0cf0e9 | 1493 | unsigned char *result_s; |
ashleymills | 0:ff9ebe0cf0e9 | 1494 | dtls_hash_ctx hs_hash; |
ashleymills | 0:ff9ebe0cf0e9 | 1495 | unsigned char sha256hash[DTLS_HMAC_DIGEST_SIZE]; |
ashleymills | 0:ff9ebe0cf0e9 | 1496 | |
ashleymills | 0:ff9ebe0cf0e9 | 1497 | assert(config->cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); |
ashleymills | 0:ff9ebe0cf0e9 | 1498 | |
ashleymills | 0:ff9ebe0cf0e9 | 1499 | data += DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 1500 | |
ashleymills | 0:ff9ebe0cf0e9 | 1501 | if (data_length < DTLS_HS_LENGTH + DTLS_CV_LENGTH) { |
ashleymills | 0:ff9ebe0cf0e9 | 1502 | DBG("the package length does not match the expected"); |
ashleymills | 0:ff9ebe0cf0e9 | 1503 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1504 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1505 | |
ashleymills | 0:ff9ebe0cf0e9 | 1506 | if (dtls_uint8_to_int(data) != TLS_EXT_SIG_HASH_ALGO_SHA256) { |
ashleymills | 0:ff9ebe0cf0e9 | 1507 | DBG("only sha256 is supported in certificate verify"); |
ashleymills | 0:ff9ebe0cf0e9 | 1508 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 1509 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1510 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1511 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1512 | |
ashleymills | 0:ff9ebe0cf0e9 | 1513 | if (dtls_uint8_to_int(data) != TLS_EXT_SIG_HASH_ALGO_ECDSA) { |
ashleymills | 0:ff9ebe0cf0e9 | 1514 | DBG("only ecdsa signature is supported in client verify"); |
ashleymills | 0:ff9ebe0cf0e9 | 1515 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 1516 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1517 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1518 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1519 | |
ashleymills | 0:ff9ebe0cf0e9 | 1520 | if (data_length < dtls_uint16_to_int(data)) { |
ashleymills | 0:ff9ebe0cf0e9 | 1521 | DBG("signature length wrong"); |
ashleymills | 0:ff9ebe0cf0e9 | 1522 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1523 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1524 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1525 | data_length -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1526 | |
ashleymills | 0:ff9ebe0cf0e9 | 1527 | if (dtls_uint8_to_int(data) != 0x30) { |
ashleymills | 0:ff9ebe0cf0e9 | 1528 | DBG("wrong ASN.1 struct, expected SEQUENCE"); |
ashleymills | 0:ff9ebe0cf0e9 | 1529 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1530 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1531 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1532 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1533 | |
ashleymills | 0:ff9ebe0cf0e9 | 1534 | if (data_length < dtls_uint8_to_int(data)) { |
ashleymills | 0:ff9ebe0cf0e9 | 1535 | DBG("signature length wrong"); |
ashleymills | 0:ff9ebe0cf0e9 | 1536 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1537 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1538 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1539 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1540 | |
ashleymills | 0:ff9ebe0cf0e9 | 1541 | if (dtls_uint8_to_int(data) != 0x02) { |
ashleymills | 0:ff9ebe0cf0e9 | 1542 | DBG("wrong ASN.1 struct, expected Integer"); |
ashleymills | 0:ff9ebe0cf0e9 | 1543 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1544 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1545 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1546 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1547 | |
ashleymills | 0:ff9ebe0cf0e9 | 1548 | i = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 1549 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1550 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1551 | |
ashleymills | 0:ff9ebe0cf0e9 | 1552 | /* Sometimes these values have a leeding 0 byte */ |
ashleymills | 0:ff9ebe0cf0e9 | 1553 | result_r = data + i - DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 1554 | |
ashleymills | 0:ff9ebe0cf0e9 | 1555 | data += i; |
ashleymills | 0:ff9ebe0cf0e9 | 1556 | data_length -= i; |
ashleymills | 0:ff9ebe0cf0e9 | 1557 | |
ashleymills | 0:ff9ebe0cf0e9 | 1558 | if (dtls_uint8_to_int(data) != 0x02) { |
ashleymills | 0:ff9ebe0cf0e9 | 1559 | DBG("wrong ASN.1 struct, expected Integer"); |
ashleymills | 0:ff9ebe0cf0e9 | 1560 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1561 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1562 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1563 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1564 | |
ashleymills | 0:ff9ebe0cf0e9 | 1565 | i = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 1566 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1567 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1568 | |
ashleymills | 0:ff9ebe0cf0e9 | 1569 | /* Sometimes these values have a leeding 0 byte */ |
ashleymills | 0:ff9ebe0cf0e9 | 1570 | result_s = data + i - DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 1571 | |
ashleymills | 0:ff9ebe0cf0e9 | 1572 | data += i; |
ashleymills | 0:ff9ebe0cf0e9 | 1573 | data_length -= i; |
ashleymills | 0:ff9ebe0cf0e9 | 1574 | |
ashleymills | 0:ff9ebe0cf0e9 | 1575 | copy_hs_hash(peer, &hs_hash); |
ashleymills | 0:ff9ebe0cf0e9 | 1576 | |
ashleymills | 0:ff9ebe0cf0e9 | 1577 | dtls_hash_finalize(sha256hash, &hs_hash); |
ashleymills | 0:ff9ebe0cf0e9 | 1578 | |
ashleymills | 0:ff9ebe0cf0e9 | 1579 | i = dtls_ecdsa_verify_sig_hash(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y, |
ashleymills | 0:ff9ebe0cf0e9 | 1580 | sizeof(config->keyx.ecdsa.other_pub_x), |
ashleymills | 0:ff9ebe0cf0e9 | 1581 | sha256hash, sizeof(sha256hash), |
ashleymills | 0:ff9ebe0cf0e9 | 1582 | result_r, result_s); |
ashleymills | 0:ff9ebe0cf0e9 | 1583 | |
ashleymills | 0:ff9ebe0cf0e9 | 1584 | if (i < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1585 | DBG("wrong signature err: %i", i); |
ashleymills | 0:ff9ebe0cf0e9 | 1586 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 1587 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1588 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1589 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1590 | |
ashleymills | 0:ff9ebe0cf0e9 | 1591 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1592 | dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) |
ashleymills | 0:ff9ebe0cf0e9 | 1593 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1594 | /* Ensure that the largest message to create fits in our source |
ashleymills | 0:ff9ebe0cf0e9 | 1595 | * buffer. (The size of the destination buffer is checked by the |
ashleymills | 0:ff9ebe0cf0e9 | 1596 | * encoding function, so we do not need to guess.) */ |
ashleymills | 0:ff9ebe0cf0e9 | 1597 | uint8 buf[DTLS_SH_LENGTH + 2 + 5 + 5 + 8 + 6]; |
ashleymills | 0:ff9ebe0cf0e9 | 1598 | uint8 *p; |
ashleymills | 0:ff9ebe0cf0e9 | 1599 | int ecdsa; |
ashleymills | 0:ff9ebe0cf0e9 | 1600 | uint8 extension_size; |
ashleymills | 0:ff9ebe0cf0e9 | 1601 | dtls_handshake_parameters_t *handshake = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 1602 | dtls_tick_t now; |
ashleymills | 0:ff9ebe0cf0e9 | 1603 | |
ashleymills | 0:ff9ebe0cf0e9 | 1604 | ecdsa = handshake->cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; |
ashleymills | 0:ff9ebe0cf0e9 | 1605 | |
ashleymills | 0:ff9ebe0cf0e9 | 1606 | extension_size = (ecdsa) ? 2 + 5 + 5 + 8 + 6 : 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1607 | |
ashleymills | 0:ff9ebe0cf0e9 | 1608 | /* Handshake header */ |
ashleymills | 0:ff9ebe0cf0e9 | 1609 | p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 1610 | |
ashleymills | 0:ff9ebe0cf0e9 | 1611 | /* ServerHello */ |
ashleymills | 0:ff9ebe0cf0e9 | 1612 | dtls_int_to_uint16(p, DTLS_VERSION); |
ashleymills | 0:ff9ebe0cf0e9 | 1613 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1614 | |
ashleymills | 0:ff9ebe0cf0e9 | 1615 | /* Set server random: First 4 bytes are the server's Unix timestamp, |
ashleymills | 0:ff9ebe0cf0e9 | 1616 | * followed by 28 bytes of generate random data. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1617 | dtls_ticks(&now); |
ashleymills | 0:ff9ebe0cf0e9 | 1618 | dtls_int_to_uint32(handshake->tmp.random.server, now / CLOCK_SECOND); |
ashleymills | 0:ff9ebe0cf0e9 | 1619 | prng(handshake->tmp.random.server + 4, 28); |
ashleymills | 0:ff9ebe0cf0e9 | 1620 | |
ashleymills | 0:ff9ebe0cf0e9 | 1621 | memcpy(p, handshake->tmp.random.server, DTLS_RANDOM_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 1622 | p += DTLS_RANDOM_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 1623 | |
ashleymills | 0:ff9ebe0cf0e9 | 1624 | *p++ = 0; /* no session id */ |
ashleymills | 0:ff9ebe0cf0e9 | 1625 | |
ashleymills | 0:ff9ebe0cf0e9 | 1626 | if (handshake->cipher != TLS_NULL_WITH_NULL_NULL) { |
ashleymills | 0:ff9ebe0cf0e9 | 1627 | /* selected cipher suite */ |
ashleymills | 0:ff9ebe0cf0e9 | 1628 | dtls_int_to_uint16(p, handshake->cipher); |
ashleymills | 0:ff9ebe0cf0e9 | 1629 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1630 | |
ashleymills | 0:ff9ebe0cf0e9 | 1631 | /* selected compression method */ |
ashleymills | 0:ff9ebe0cf0e9 | 1632 | if (handshake->compression >= 0) |
ashleymills | 0:ff9ebe0cf0e9 | 1633 | *p++ = compression_methods[handshake->compression]; |
ashleymills | 0:ff9ebe0cf0e9 | 1634 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1635 | |
ashleymills | 0:ff9ebe0cf0e9 | 1636 | if (extension_size) { |
ashleymills | 0:ff9ebe0cf0e9 | 1637 | /* length of the extensions */ |
ashleymills | 0:ff9ebe0cf0e9 | 1638 | dtls_int_to_uint16(p, extension_size - 2); |
ashleymills | 0:ff9ebe0cf0e9 | 1639 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1640 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1641 | |
ashleymills | 0:ff9ebe0cf0e9 | 1642 | if (ecdsa) { |
ashleymills | 0:ff9ebe0cf0e9 | 1643 | /* client certificate type extension */ |
ashleymills | 0:ff9ebe0cf0e9 | 1644 | dtls_int_to_uint16(p, TLS_EXT_CLIENT_CERIFICATE_TYPE); |
ashleymills | 0:ff9ebe0cf0e9 | 1645 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1646 | |
ashleymills | 0:ff9ebe0cf0e9 | 1647 | /* length of this extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 1648 | dtls_int_to_uint16(p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 1649 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1650 | |
ashleymills | 0:ff9ebe0cf0e9 | 1651 | dtls_int_to_uint8(p, TLS_CERT_TYPE_OOB); |
ashleymills | 0:ff9ebe0cf0e9 | 1652 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1653 | |
ashleymills | 0:ff9ebe0cf0e9 | 1654 | /* client certificate type extension */ |
ashleymills | 0:ff9ebe0cf0e9 | 1655 | dtls_int_to_uint16(p, TLS_EXT_SERVER_CERIFICATE_TYPE); |
ashleymills | 0:ff9ebe0cf0e9 | 1656 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1657 | |
ashleymills | 0:ff9ebe0cf0e9 | 1658 | /* length of this extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 1659 | dtls_int_to_uint16(p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 1660 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1661 | |
ashleymills | 0:ff9ebe0cf0e9 | 1662 | dtls_int_to_uint8(p, TLS_CERT_TYPE_OOB); |
ashleymills | 0:ff9ebe0cf0e9 | 1663 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1664 | |
ashleymills | 0:ff9ebe0cf0e9 | 1665 | /* elliptic_curves */ |
ashleymills | 0:ff9ebe0cf0e9 | 1666 | dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES); |
ashleymills | 0:ff9ebe0cf0e9 | 1667 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1668 | |
ashleymills | 0:ff9ebe0cf0e9 | 1669 | /* length of this extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 1670 | dtls_int_to_uint16(p, 4); |
ashleymills | 0:ff9ebe0cf0e9 | 1671 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1672 | |
ashleymills | 0:ff9ebe0cf0e9 | 1673 | /* length of the list */ |
ashleymills | 0:ff9ebe0cf0e9 | 1674 | dtls_int_to_uint16(p, 2); |
ashleymills | 0:ff9ebe0cf0e9 | 1675 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1676 | |
ashleymills | 0:ff9ebe0cf0e9 | 1677 | dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES_SECP256R1); |
ashleymills | 0:ff9ebe0cf0e9 | 1678 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1679 | |
ashleymills | 0:ff9ebe0cf0e9 | 1680 | /* ec_point_formats */ |
ashleymills | 0:ff9ebe0cf0e9 | 1681 | dtls_int_to_uint16(p, TLS_EXT_EC_POINT_FORMATS); |
ashleymills | 0:ff9ebe0cf0e9 | 1682 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1683 | |
ashleymills | 0:ff9ebe0cf0e9 | 1684 | /* length of this extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 1685 | dtls_int_to_uint16(p, 2); |
ashleymills | 0:ff9ebe0cf0e9 | 1686 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1687 | |
ashleymills | 0:ff9ebe0cf0e9 | 1688 | /* number of supported formats */ |
ashleymills | 0:ff9ebe0cf0e9 | 1689 | dtls_int_to_uint8(p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 1690 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1691 | |
ashleymills | 0:ff9ebe0cf0e9 | 1692 | dtls_int_to_uint8(p, TLS_EXT_EC_POINT_FORMATS_UNCOMPRESSED); |
ashleymills | 0:ff9ebe0cf0e9 | 1693 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1694 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1695 | |
ashleymills | 0:ff9ebe0cf0e9 | 1696 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 1697 | |
ashleymills | 0:ff9ebe0cf0e9 | 1698 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_HELLO, |
ashleymills | 0:ff9ebe0cf0e9 | 1699 | buf, p - buf); |
ashleymills | 0:ff9ebe0cf0e9 | 1700 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1701 | |
ashleymills | 0:ff9ebe0cf0e9 | 1702 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1703 | dtls_send_certificate_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1704 | const dtls_ecdsa_key_t *key) |
ashleymills | 0:ff9ebe0cf0e9 | 1705 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1706 | DBG("dtls_send_certificate_ecdsa"); |
ashleymills | 0:ff9ebe0cf0e9 | 1707 | uint8 buf[DTLS_CE_LENGTH]; |
ashleymills | 0:ff9ebe0cf0e9 | 1708 | uint8 *p; |
ashleymills | 0:ff9ebe0cf0e9 | 1709 | |
ashleymills | 0:ff9ebe0cf0e9 | 1710 | /* Certificate |
ashleymills | 0:ff9ebe0cf0e9 | 1711 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1712 | * Start message construction at beginning of buffer. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1713 | p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 1714 | |
ashleymills | 0:ff9ebe0cf0e9 | 1715 | dtls_int_to_uint24(p, 94); |
ashleymills | 0:ff9ebe0cf0e9 | 1716 | p += sizeof(uint24); |
ashleymills | 0:ff9ebe0cf0e9 | 1717 | |
ashleymills | 0:ff9ebe0cf0e9 | 1718 | dtls_int_to_uint24(p, 91); |
ashleymills | 0:ff9ebe0cf0e9 | 1719 | p += sizeof(uint24); |
ashleymills | 0:ff9ebe0cf0e9 | 1720 | |
ashleymills | 0:ff9ebe0cf0e9 | 1721 | memcpy(p, &cert_asn1_header, sizeof(cert_asn1_header)); |
ashleymills | 0:ff9ebe0cf0e9 | 1722 | p += sizeof(cert_asn1_header); |
ashleymills | 0:ff9ebe0cf0e9 | 1723 | |
ashleymills | 0:ff9ebe0cf0e9 | 1724 | memcpy(p, key->pub_key_x, DTLS_EC_KEY_SIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 1725 | p += DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 1726 | |
ashleymills | 0:ff9ebe0cf0e9 | 1727 | memcpy(p, key->pub_key_y, DTLS_EC_KEY_SIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 1728 | p += DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 1729 | |
ashleymills | 0:ff9ebe0cf0e9 | 1730 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 1731 | |
ashleymills | 0:ff9ebe0cf0e9 | 1732 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_CERTIFICATE, |
ashleymills | 0:ff9ebe0cf0e9 | 1733 | buf, p - buf); |
ashleymills | 0:ff9ebe0cf0e9 | 1734 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1735 | |
ashleymills | 0:ff9ebe0cf0e9 | 1736 | static uint8 * |
ashleymills | 0:ff9ebe0cf0e9 | 1737 | dtls_add_ecdsa_signature_elem(uint8 *p, uint32_t *point_r, uint32_t *point_s) |
ashleymills | 0:ff9ebe0cf0e9 | 1738 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1739 | int len_r; |
ashleymills | 0:ff9ebe0cf0e9 | 1740 | int len_s; |
ashleymills | 0:ff9ebe0cf0e9 | 1741 | |
ashleymills | 0:ff9ebe0cf0e9 | 1742 | #define R_KEY_OFFSET (2 + 1 + 1 + 1 + 1) |
ashleymills | 0:ff9ebe0cf0e9 | 1743 | #define S_KEY_OFFSET(len_s) (R_KEY_OFFSET + (len_s) + 1 + 1) |
ashleymills | 0:ff9ebe0cf0e9 | 1744 | /* store the pointer to the r component of the signature and make space */ |
ashleymills | 0:ff9ebe0cf0e9 | 1745 | len_r = dtls_ec_key_from_uint32_asn1(point_r, DTLS_EC_KEY_SIZE, p + R_KEY_OFFSET); |
ashleymills | 0:ff9ebe0cf0e9 | 1746 | len_s = dtls_ec_key_from_uint32_asn1(point_s, DTLS_EC_KEY_SIZE, p + S_KEY_OFFSET(len_r)); |
ashleymills | 0:ff9ebe0cf0e9 | 1747 | |
ashleymills | 0:ff9ebe0cf0e9 | 1748 | #undef R_KEY_OFFSET |
ashleymills | 0:ff9ebe0cf0e9 | 1749 | #undef S_KEY_OFFSET |
ashleymills | 0:ff9ebe0cf0e9 | 1750 | |
ashleymills | 0:ff9ebe0cf0e9 | 1751 | /* length of signature */ |
ashleymills | 0:ff9ebe0cf0e9 | 1752 | dtls_int_to_uint16(p, len_r + len_s + 2 + 2 + 2); |
ashleymills | 0:ff9ebe0cf0e9 | 1753 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1754 | |
ashleymills | 0:ff9ebe0cf0e9 | 1755 | /* ASN.1 SEQUENCE */ |
ashleymills | 0:ff9ebe0cf0e9 | 1756 | dtls_int_to_uint8(p, 0x30); |
ashleymills | 0:ff9ebe0cf0e9 | 1757 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1758 | |
ashleymills | 0:ff9ebe0cf0e9 | 1759 | dtls_int_to_uint8(p, len_r + len_s + 2 + 2); |
ashleymills | 0:ff9ebe0cf0e9 | 1760 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1761 | |
ashleymills | 0:ff9ebe0cf0e9 | 1762 | /* ASN.1 Integer r */ |
ashleymills | 0:ff9ebe0cf0e9 | 1763 | dtls_int_to_uint8(p, 0x02); |
ashleymills | 0:ff9ebe0cf0e9 | 1764 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1765 | |
ashleymills | 0:ff9ebe0cf0e9 | 1766 | dtls_int_to_uint8(p, len_r); |
ashleymills | 0:ff9ebe0cf0e9 | 1767 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1768 | |
ashleymills | 0:ff9ebe0cf0e9 | 1769 | /* the pint r was added here */ |
ashleymills | 0:ff9ebe0cf0e9 | 1770 | p += len_r; |
ashleymills | 0:ff9ebe0cf0e9 | 1771 | |
ashleymills | 0:ff9ebe0cf0e9 | 1772 | /* ASN.1 Integer s */ |
ashleymills | 0:ff9ebe0cf0e9 | 1773 | dtls_int_to_uint8(p, 0x02); |
ashleymills | 0:ff9ebe0cf0e9 | 1774 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1775 | |
ashleymills | 0:ff9ebe0cf0e9 | 1776 | dtls_int_to_uint8(p, len_s); |
ashleymills | 0:ff9ebe0cf0e9 | 1777 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1778 | |
ashleymills | 0:ff9ebe0cf0e9 | 1779 | /* the pint s was added here */ |
ashleymills | 0:ff9ebe0cf0e9 | 1780 | p += len_s; |
ashleymills | 0:ff9ebe0cf0e9 | 1781 | |
ashleymills | 0:ff9ebe0cf0e9 | 1782 | return p; |
ashleymills | 0:ff9ebe0cf0e9 | 1783 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1784 | |
ashleymills | 0:ff9ebe0cf0e9 | 1785 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1786 | dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1787 | const dtls_ecdsa_key_t *key) |
ashleymills | 0:ff9ebe0cf0e9 | 1788 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1789 | /* The ASN.1 Integer representation of an 32 byte unsigned int could be |
ashleymills | 0:ff9ebe0cf0e9 | 1790 | * 33 bytes long add space for that */ |
ashleymills | 0:ff9ebe0cf0e9 | 1791 | uint8 buf[DTLS_SKEXEC_LENGTH + 2]; |
ashleymills | 0:ff9ebe0cf0e9 | 1792 | uint8 *p; |
ashleymills | 0:ff9ebe0cf0e9 | 1793 | uint8 *key_params; |
ashleymills | 0:ff9ebe0cf0e9 | 1794 | uint8 *ephemeral_pub_x; |
ashleymills | 0:ff9ebe0cf0e9 | 1795 | uint8 *ephemeral_pub_y; |
ashleymills | 0:ff9ebe0cf0e9 | 1796 | uint32_t point_r[9]; |
ashleymills | 0:ff9ebe0cf0e9 | 1797 | uint32_t point_s[9]; |
ashleymills | 0:ff9ebe0cf0e9 | 1798 | dtls_handshake_parameters_t *config = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 1799 | |
ashleymills | 0:ff9ebe0cf0e9 | 1800 | /* ServerKeyExchange |
ashleymills | 0:ff9ebe0cf0e9 | 1801 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1802 | * Start message construction at beginning of buffer. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1803 | p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 1804 | |
ashleymills | 0:ff9ebe0cf0e9 | 1805 | key_params = p; |
ashleymills | 0:ff9ebe0cf0e9 | 1806 | /* ECCurveType curve_type: named_curve */ |
ashleymills | 0:ff9ebe0cf0e9 | 1807 | dtls_int_to_uint8(p, 3); |
ashleymills | 0:ff9ebe0cf0e9 | 1808 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1809 | |
ashleymills | 0:ff9ebe0cf0e9 | 1810 | /* NamedCurve namedcurve: secp256r1 */ |
ashleymills | 0:ff9ebe0cf0e9 | 1811 | dtls_int_to_uint16(p, 23); |
ashleymills | 0:ff9ebe0cf0e9 | 1812 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1813 | |
ashleymills | 0:ff9ebe0cf0e9 | 1814 | dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 1815 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1816 | |
ashleymills | 0:ff9ebe0cf0e9 | 1817 | /* This should be an uncompressed point, but I do not have access to the sepc. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1818 | dtls_int_to_uint8(p, 4); |
ashleymills | 0:ff9ebe0cf0e9 | 1819 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1820 | |
ashleymills | 0:ff9ebe0cf0e9 | 1821 | /* store the pointer to the x component of the pub key and make space */ |
ashleymills | 0:ff9ebe0cf0e9 | 1822 | ephemeral_pub_x = p; |
ashleymills | 0:ff9ebe0cf0e9 | 1823 | p += DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 1824 | |
ashleymills | 0:ff9ebe0cf0e9 | 1825 | /* store the pointer to the y component of the pub key and make space */ |
ashleymills | 0:ff9ebe0cf0e9 | 1826 | ephemeral_pub_y = p; |
ashleymills | 0:ff9ebe0cf0e9 | 1827 | p += DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 1828 | |
ashleymills | 0:ff9ebe0cf0e9 | 1829 | dtls_ecdsa_generate_key(config->keyx.ecdsa.own_eph_priv, |
ashleymills | 0:ff9ebe0cf0e9 | 1830 | ephemeral_pub_x, ephemeral_pub_y, |
ashleymills | 0:ff9ebe0cf0e9 | 1831 | DTLS_EC_KEY_SIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 1832 | |
ashleymills | 0:ff9ebe0cf0e9 | 1833 | /* sign the ephemeral and its paramaters */ |
ashleymills | 0:ff9ebe0cf0e9 | 1834 | dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE, |
ashleymills | 0:ff9ebe0cf0e9 | 1835 | config->tmp.random.client, DTLS_RANDOM_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 1836 | config->tmp.random.server, DTLS_RANDOM_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 1837 | key_params, p - key_params, |
ashleymills | 0:ff9ebe0cf0e9 | 1838 | point_r, point_s); |
ashleymills | 0:ff9ebe0cf0e9 | 1839 | |
ashleymills | 0:ff9ebe0cf0e9 | 1840 | p = dtls_add_ecdsa_signature_elem(p, point_r, point_s); |
ashleymills | 0:ff9ebe0cf0e9 | 1841 | |
ashleymills | 0:ff9ebe0cf0e9 | 1842 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 1843 | |
ashleymills | 0:ff9ebe0cf0e9 | 1844 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE, |
ashleymills | 0:ff9ebe0cf0e9 | 1845 | buf, p - buf); |
ashleymills | 0:ff9ebe0cf0e9 | 1846 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1847 | |
ashleymills | 0:ff9ebe0cf0e9 | 1848 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1849 | dtls_send_server_key_exchange_psk(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 1850 | const dtls_psk_key_t *key) |
ashleymills | 0:ff9ebe0cf0e9 | 1851 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1852 | uint8 buf[DTLS_SKEXECPSK_LENGTH_MAX]; |
ashleymills | 0:ff9ebe0cf0e9 | 1853 | uint8 *p; |
ashleymills | 0:ff9ebe0cf0e9 | 1854 | |
ashleymills | 0:ff9ebe0cf0e9 | 1855 | p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 1856 | |
ashleymills | 0:ff9ebe0cf0e9 | 1857 | if (key->id_length > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { |
ashleymills | 0:ff9ebe0cf0e9 | 1858 | WARN("psk identity hint is too long"); |
ashleymills | 0:ff9ebe0cf0e9 | 1859 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 1860 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1861 | |
ashleymills | 0:ff9ebe0cf0e9 | 1862 | dtls_int_to_uint16(p, key->id_length); |
ashleymills | 0:ff9ebe0cf0e9 | 1863 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1864 | |
ashleymills | 0:ff9ebe0cf0e9 | 1865 | memcpy(p, key->id, key->id_length); |
ashleymills | 0:ff9ebe0cf0e9 | 1866 | p += key->id_length; |
ashleymills | 0:ff9ebe0cf0e9 | 1867 | |
ashleymills | 0:ff9ebe0cf0e9 | 1868 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 1869 | |
ashleymills | 0:ff9ebe0cf0e9 | 1870 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE, |
ashleymills | 0:ff9ebe0cf0e9 | 1871 | buf, p - buf); |
ashleymills | 0:ff9ebe0cf0e9 | 1872 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1873 | |
ashleymills | 0:ff9ebe0cf0e9 | 1874 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1875 | dtls_send_server_certificate_request(dtls_context_t *ctx, dtls_peer_t *peer) |
ashleymills | 0:ff9ebe0cf0e9 | 1876 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1877 | uint8 buf[8]; |
ashleymills | 0:ff9ebe0cf0e9 | 1878 | uint8 *p; |
ashleymills | 0:ff9ebe0cf0e9 | 1879 | |
ashleymills | 0:ff9ebe0cf0e9 | 1880 | /* ServerHelloDone |
ashleymills | 0:ff9ebe0cf0e9 | 1881 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1882 | * Start message construction at beginning of buffer. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1883 | p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 1884 | |
ashleymills | 0:ff9ebe0cf0e9 | 1885 | /* certificate_types */ |
ashleymills | 0:ff9ebe0cf0e9 | 1886 | dtls_int_to_uint8(p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 1887 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1888 | |
ashleymills | 0:ff9ebe0cf0e9 | 1889 | /* ecdsa_sign */ |
ashleymills | 0:ff9ebe0cf0e9 | 1890 | dtls_int_to_uint8(p, 64); |
ashleymills | 0:ff9ebe0cf0e9 | 1891 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1892 | |
ashleymills | 0:ff9ebe0cf0e9 | 1893 | /* supported_signature_algorithms */ |
ashleymills | 0:ff9ebe0cf0e9 | 1894 | dtls_int_to_uint16(p, 2); |
ashleymills | 0:ff9ebe0cf0e9 | 1895 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1896 | |
ashleymills | 0:ff9ebe0cf0e9 | 1897 | /* sha256 */ |
ashleymills | 0:ff9ebe0cf0e9 | 1898 | dtls_int_to_uint8(p, TLS_EXT_SIG_HASH_ALGO_SHA256); |
ashleymills | 0:ff9ebe0cf0e9 | 1899 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1900 | |
ashleymills | 0:ff9ebe0cf0e9 | 1901 | /* ecdsa */ |
ashleymills | 0:ff9ebe0cf0e9 | 1902 | dtls_int_to_uint8(p, TLS_EXT_SIG_HASH_ALGO_ECDSA); |
ashleymills | 0:ff9ebe0cf0e9 | 1903 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 1904 | |
ashleymills | 0:ff9ebe0cf0e9 | 1905 | /* certificate_authoritiess */ |
ashleymills | 0:ff9ebe0cf0e9 | 1906 | dtls_int_to_uint16(p, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1907 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 1908 | |
ashleymills | 0:ff9ebe0cf0e9 | 1909 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 1910 | |
ashleymills | 0:ff9ebe0cf0e9 | 1911 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_CERTIFICATE_REQUEST, |
ashleymills | 0:ff9ebe0cf0e9 | 1912 | buf, p - buf); |
ashleymills | 0:ff9ebe0cf0e9 | 1913 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1914 | |
ashleymills | 0:ff9ebe0cf0e9 | 1915 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1916 | dtls_send_server_hello_done(dtls_context_t *ctx, dtls_peer_t *peer) |
ashleymills | 0:ff9ebe0cf0e9 | 1917 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1918 | |
ashleymills | 0:ff9ebe0cf0e9 | 1919 | /* ServerHelloDone |
ashleymills | 0:ff9ebe0cf0e9 | 1920 | * |
ashleymills | 0:ff9ebe0cf0e9 | 1921 | * Start message construction at beginning of buffer. */ |
ashleymills | 0:ff9ebe0cf0e9 | 1922 | |
ashleymills | 0:ff9ebe0cf0e9 | 1923 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_HELLO_DONE, |
ashleymills | 0:ff9ebe0cf0e9 | 1924 | NULL, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 1925 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1926 | |
ashleymills | 0:ff9ebe0cf0e9 | 1927 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 1928 | dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) |
ashleymills | 0:ff9ebe0cf0e9 | 1929 | { |
ashleymills | 0:ff9ebe0cf0e9 | 1930 | int res; |
ashleymills | 0:ff9ebe0cf0e9 | 1931 | |
ashleymills | 0:ff9ebe0cf0e9 | 1932 | res = dtls_send_server_hello(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 1933 | |
ashleymills | 0:ff9ebe0cf0e9 | 1934 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1935 | DBG("dtls_server_hello: cannot prepare ServerHello record"); |
ashleymills | 0:ff9ebe0cf0e9 | 1936 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1937 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1938 | |
ashleymills | 0:ff9ebe0cf0e9 | 1939 | if (peer->handshake_params.cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 1940 | const dtls_ecdsa_key_t *ecdsa_key; |
ashleymills | 0:ff9ebe0cf0e9 | 1941 | |
ashleymills | 0:ff9ebe0cf0e9 | 1942 | res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); |
ashleymills | 0:ff9ebe0cf0e9 | 1943 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1944 | DBG("no ecdsa certificate to send in certificate"); |
ashleymills | 0:ff9ebe0cf0e9 | 1945 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1946 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1947 | |
ashleymills | 0:ff9ebe0cf0e9 | 1948 | res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key); |
ashleymills | 0:ff9ebe0cf0e9 | 1949 | |
ashleymills | 0:ff9ebe0cf0e9 | 1950 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1951 | DBG("dtls_server_hello: cannot prepare Certificate record"); |
ashleymills | 0:ff9ebe0cf0e9 | 1952 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1953 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1954 | |
ashleymills | 0:ff9ebe0cf0e9 | 1955 | res = dtls_send_server_key_exchange_ecdh(ctx, peer, ecdsa_key); |
ashleymills | 0:ff9ebe0cf0e9 | 1956 | |
ashleymills | 0:ff9ebe0cf0e9 | 1957 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1958 | DBG("dtls_server_hello: cannot prepare Server Key Exchange record"); |
ashleymills | 0:ff9ebe0cf0e9 | 1959 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1960 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1961 | |
ashleymills | 0:ff9ebe0cf0e9 | 1962 | if (peer->handshake_params.cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 && |
ashleymills | 0:ff9ebe0cf0e9 | 1963 | ctx && ctx->h && ctx->h->verify_ecdsa_key) { |
ashleymills | 0:ff9ebe0cf0e9 | 1964 | res = dtls_send_server_certificate_request(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 1965 | |
ashleymills | 0:ff9ebe0cf0e9 | 1966 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1967 | DBG("dtls_server_hello: cannot prepare certificate Request record"); |
ashleymills | 0:ff9ebe0cf0e9 | 1968 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1969 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1970 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1971 | } else if (peer->handshake_params.cipher == TLS_PSK_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 1972 | const dtls_psk_key_t *psk; |
ashleymills | 0:ff9ebe0cf0e9 | 1973 | |
ashleymills | 0:ff9ebe0cf0e9 | 1974 | res = CALL(ctx, get_psk_key, &peer->session, NULL, 0, &psk); |
ashleymills | 0:ff9ebe0cf0e9 | 1975 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1976 | DBG("no psk or identity found for this session"); |
ashleymills | 0:ff9ebe0cf0e9 | 1977 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1978 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1979 | |
ashleymills | 0:ff9ebe0cf0e9 | 1980 | if (psk->id_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 1981 | res = dtls_send_server_key_exchange_psk(ctx, peer, psk); |
ashleymills | 0:ff9ebe0cf0e9 | 1982 | |
ashleymills | 0:ff9ebe0cf0e9 | 1983 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1984 | DBG("dtls_server_key_exchange_psk: cannot send server key exchange record"); |
ashleymills | 0:ff9ebe0cf0e9 | 1985 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1986 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1987 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1988 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1989 | |
ashleymills | 0:ff9ebe0cf0e9 | 1990 | res = dtls_send_server_hello_done(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 1991 | |
ashleymills | 0:ff9ebe0cf0e9 | 1992 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 1993 | DBG("dtls_server_hello: cannot prepare ServerHelloDone record"); |
ashleymills | 0:ff9ebe0cf0e9 | 1994 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 1995 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1996 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 1997 | } |
ashleymills | 0:ff9ebe0cf0e9 | 1998 | |
ashleymills | 0:ff9ebe0cf0e9 | 1999 | static inline int |
ashleymills | 0:ff9ebe0cf0e9 | 2000 | dtls_send_ccs(dtls_context_t *ctx, dtls_peer_t *peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 2001 | uint8 buf[1]; |
ashleymills | 0:ff9ebe0cf0e9 | 2002 | buf[0] = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 2003 | |
ashleymills | 0:ff9ebe0cf0e9 | 2004 | return dtls_send(ctx, peer, DTLS_CT_CHANGE_CIPHER_SPEC, buf, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 2005 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2006 | |
ashleymills | 0:ff9ebe0cf0e9 | 2007 | |
ashleymills | 0:ff9ebe0cf0e9 | 2008 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2009 | dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) |
ashleymills | 0:ff9ebe0cf0e9 | 2010 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2011 | uint8 buf[DTLS_CKXEC_LENGTH]; |
ashleymills | 0:ff9ebe0cf0e9 | 2012 | uint8 *p; |
ashleymills | 0:ff9ebe0cf0e9 | 2013 | int err; |
ashleymills | 0:ff9ebe0cf0e9 | 2014 | dtls_handshake_parameters_t *handshake = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2015 | |
ashleymills | 0:ff9ebe0cf0e9 | 2016 | p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 2017 | |
ashleymills | 0:ff9ebe0cf0e9 | 2018 | switch (handshake->cipher) { |
ashleymills | 0:ff9ebe0cf0e9 | 2019 | case TLS_PSK_WITH_AES_128_CCM_8: { |
ashleymills | 0:ff9ebe0cf0e9 | 2020 | const dtls_psk_key_t *psk; |
ashleymills | 0:ff9ebe0cf0e9 | 2021 | |
ashleymills | 0:ff9ebe0cf0e9 | 2022 | err = CALL(ctx, get_psk_key, &peer->session, handshake->keyx.psk.identity, |
ashleymills | 0:ff9ebe0cf0e9 | 2023 | handshake->keyx.psk.id_length, &psk); |
ashleymills | 0:ff9ebe0cf0e9 | 2024 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2025 | DBG("no psk key to send in kx"); |
ashleymills | 0:ff9ebe0cf0e9 | 2026 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 2027 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2028 | |
ashleymills | 0:ff9ebe0cf0e9 | 2029 | if (psk->id_length + sizeof(uint16) > DTLS_CKXEC_LENGTH) { |
ashleymills | 0:ff9ebe0cf0e9 | 2030 | WARN("the psk identity is too long"); |
ashleymills | 0:ff9ebe0cf0e9 | 2031 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2032 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2033 | |
ashleymills | 0:ff9ebe0cf0e9 | 2034 | dtls_int_to_uint16(p, psk->id_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2035 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2036 | |
ashleymills | 0:ff9ebe0cf0e9 | 2037 | memcpy(p, psk->id, psk->id_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2038 | p += psk->id_length; |
ashleymills | 0:ff9ebe0cf0e9 | 2039 | |
ashleymills | 0:ff9ebe0cf0e9 | 2040 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 2041 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2042 | case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: { |
ashleymills | 0:ff9ebe0cf0e9 | 2043 | uint8 *ephemeral_pub_x; |
ashleymills | 0:ff9ebe0cf0e9 | 2044 | uint8 *ephemeral_pub_y; |
ashleymills | 0:ff9ebe0cf0e9 | 2045 | |
ashleymills | 0:ff9ebe0cf0e9 | 2046 | dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 2047 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2048 | |
ashleymills | 0:ff9ebe0cf0e9 | 2049 | /* This should be an uncompressed point, but I do not have access to the sepc. */ |
ashleymills | 0:ff9ebe0cf0e9 | 2050 | dtls_int_to_uint8(p, 4); |
ashleymills | 0:ff9ebe0cf0e9 | 2051 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2052 | |
ashleymills | 0:ff9ebe0cf0e9 | 2053 | ephemeral_pub_x = p; |
ashleymills | 0:ff9ebe0cf0e9 | 2054 | p += DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 2055 | ephemeral_pub_y = p; |
ashleymills | 0:ff9ebe0cf0e9 | 2056 | p += DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 2057 | |
ashleymills | 0:ff9ebe0cf0e9 | 2058 | dtls_ecdsa_generate_key(peer->handshake_params.keyx.ecdsa.own_eph_priv, |
ashleymills | 0:ff9ebe0cf0e9 | 2059 | ephemeral_pub_x, ephemeral_pub_y, |
ashleymills | 0:ff9ebe0cf0e9 | 2060 | DTLS_EC_KEY_SIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 2061 | |
ashleymills | 0:ff9ebe0cf0e9 | 2062 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 2063 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2064 | default: |
ashleymills | 0:ff9ebe0cf0e9 | 2065 | DBG("cipher not supported"); |
ashleymills | 0:ff9ebe0cf0e9 | 2066 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2067 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2068 | |
ashleymills | 0:ff9ebe0cf0e9 | 2069 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 2070 | |
ashleymills | 0:ff9ebe0cf0e9 | 2071 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_CLIENT_KEY_EXCHANGE, |
ashleymills | 0:ff9ebe0cf0e9 | 2072 | buf, p - buf); |
ashleymills | 0:ff9ebe0cf0e9 | 2073 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2074 | |
ashleymills | 0:ff9ebe0cf0e9 | 2075 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2076 | dtls_send_certificate_verify_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2077 | const dtls_ecdsa_key_t *key) |
ashleymills | 0:ff9ebe0cf0e9 | 2078 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2079 | /* The ASN.1 Integer representation of an 32 byte unsigned int could be |
ashleymills | 0:ff9ebe0cf0e9 | 2080 | * 33 bytes long add space for that */ |
ashleymills | 0:ff9ebe0cf0e9 | 2081 | uint8 buf[DTLS_CV_LENGTH + 2]; |
ashleymills | 0:ff9ebe0cf0e9 | 2082 | uint8 *p; |
ashleymills | 0:ff9ebe0cf0e9 | 2083 | uint32_t point_r[9]; |
ashleymills | 0:ff9ebe0cf0e9 | 2084 | uint32_t point_s[9]; |
ashleymills | 0:ff9ebe0cf0e9 | 2085 | dtls_hash_ctx hs_hash; |
ashleymills | 0:ff9ebe0cf0e9 | 2086 | unsigned char sha256hash[DTLS_HMAC_DIGEST_SIZE]; |
ashleymills | 0:ff9ebe0cf0e9 | 2087 | |
ashleymills | 0:ff9ebe0cf0e9 | 2088 | /* ServerKeyExchange |
ashleymills | 0:ff9ebe0cf0e9 | 2089 | * |
ashleymills | 0:ff9ebe0cf0e9 | 2090 | * Start message construction at beginning of buffer. */ |
ashleymills | 0:ff9ebe0cf0e9 | 2091 | p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 2092 | |
ashleymills | 0:ff9ebe0cf0e9 | 2093 | /* sha256 */ |
ashleymills | 0:ff9ebe0cf0e9 | 2094 | dtls_int_to_uint8(p, TLS_EXT_SIG_HASH_ALGO_SHA256); |
ashleymills | 0:ff9ebe0cf0e9 | 2095 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2096 | |
ashleymills | 0:ff9ebe0cf0e9 | 2097 | /* ecdsa */ |
ashleymills | 0:ff9ebe0cf0e9 | 2098 | dtls_int_to_uint8(p, TLS_EXT_SIG_HASH_ALGO_ECDSA); |
ashleymills | 0:ff9ebe0cf0e9 | 2099 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2100 | |
ashleymills | 0:ff9ebe0cf0e9 | 2101 | copy_hs_hash(peer, &hs_hash); |
ashleymills | 0:ff9ebe0cf0e9 | 2102 | |
ashleymills | 0:ff9ebe0cf0e9 | 2103 | dtls_hash_finalize(sha256hash, &hs_hash); |
ashleymills | 0:ff9ebe0cf0e9 | 2104 | |
ashleymills | 0:ff9ebe0cf0e9 | 2105 | /* sign the ephemeral and its paramaters */ |
ashleymills | 0:ff9ebe0cf0e9 | 2106 | dtls_ecdsa_create_sig_hash(key->priv_key, DTLS_EC_KEY_SIZE, |
ashleymills | 0:ff9ebe0cf0e9 | 2107 | sha256hash, sizeof(sha256hash), |
ashleymills | 0:ff9ebe0cf0e9 | 2108 | point_r, point_s); |
ashleymills | 0:ff9ebe0cf0e9 | 2109 | |
ashleymills | 0:ff9ebe0cf0e9 | 2110 | p = dtls_add_ecdsa_signature_elem(p, point_r, point_s); |
ashleymills | 0:ff9ebe0cf0e9 | 2111 | |
ashleymills | 0:ff9ebe0cf0e9 | 2112 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 2113 | |
ashleymills | 0:ff9ebe0cf0e9 | 2114 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_CERTIFICATE_VERIFY, |
ashleymills | 0:ff9ebe0cf0e9 | 2115 | buf, p - buf); |
ashleymills | 0:ff9ebe0cf0e9 | 2116 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2117 | |
ashleymills | 0:ff9ebe0cf0e9 | 2118 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2119 | dtls_send_finished(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2120 | const unsigned char *label, size_t labellen) |
ashleymills | 0:ff9ebe0cf0e9 | 2121 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2122 | int length; |
ashleymills | 0:ff9ebe0cf0e9 | 2123 | uint8 hash[DTLS_HMAC_MAX]; |
ashleymills | 0:ff9ebe0cf0e9 | 2124 | uint8 buf[DTLS_FIN_LENGTH]; |
ashleymills | 0:ff9ebe0cf0e9 | 2125 | dtls_hash_ctx hs_hash; |
ashleymills | 0:ff9ebe0cf0e9 | 2126 | uint8 *p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 2127 | |
ashleymills | 0:ff9ebe0cf0e9 | 2128 | copy_hs_hash(peer, &hs_hash); |
ashleymills | 0:ff9ebe0cf0e9 | 2129 | |
ashleymills | 0:ff9ebe0cf0e9 | 2130 | length = dtls_hash_finalize(hash, &hs_hash); |
ashleymills | 0:ff9ebe0cf0e9 | 2131 | |
ashleymills | 0:ff9ebe0cf0e9 | 2132 | dtls_prf(peer->handshake_params.tmp.master_secret, |
ashleymills | 0:ff9ebe0cf0e9 | 2133 | DTLS_MASTER_SECRET_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 2134 | label, labellen, |
ashleymills | 0:ff9ebe0cf0e9 | 2135 | PRF_LABEL(finished), PRF_LABEL_SIZE(finished), |
ashleymills | 0:ff9ebe0cf0e9 | 2136 | hash, length, |
ashleymills | 0:ff9ebe0cf0e9 | 2137 | p, DTLS_FIN_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 2138 | |
ashleymills | 0:ff9ebe0cf0e9 | 2139 | dtls_dsrv_hexdump_log(LOG_DEBUG, "server finished MAC", p, DTLS_FIN_LENGTH, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2140 | |
ashleymills | 0:ff9ebe0cf0e9 | 2141 | p += DTLS_FIN_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2142 | |
ashleymills | 0:ff9ebe0cf0e9 | 2143 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 2144 | |
ashleymills | 0:ff9ebe0cf0e9 | 2145 | return dtls_send_handshake_msg(ctx, peer, DTLS_HT_FINISHED, |
ashleymills | 0:ff9ebe0cf0e9 | 2146 | buf, p - buf); |
ashleymills | 0:ff9ebe0cf0e9 | 2147 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2148 | |
ashleymills | 0:ff9ebe0cf0e9 | 2149 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2150 | dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2151 | uint8 cookie[], size_t cookie_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 2152 | DBG("dtls_send_client_hello"); |
ashleymills | 0:ff9ebe0cf0e9 | 2153 | uint8 buf[DTLS_CH_LENGTH_MAX]; |
ashleymills | 0:ff9ebe0cf0e9 | 2154 | uint8 *p = buf; |
ashleymills | 0:ff9ebe0cf0e9 | 2155 | uint8_t cipher_size; |
ashleymills | 0:ff9ebe0cf0e9 | 2156 | uint8_t extension_size; |
ashleymills | 0:ff9ebe0cf0e9 | 2157 | int psk; |
ashleymills | 0:ff9ebe0cf0e9 | 2158 | int ecdsa; |
ashleymills | 0:ff9ebe0cf0e9 | 2159 | dtls_handshake_parameters_t *handshake = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2160 | dtls_tick_t now; |
ashleymills | 0:ff9ebe0cf0e9 | 2161 | |
ashleymills | 0:ff9ebe0cf0e9 | 2162 | psk = is_psk_supported(ctx); |
ashleymills | 0:ff9ebe0cf0e9 | 2163 | ecdsa = is_ecdsa_supported(ctx, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 2164 | |
ashleymills | 0:ff9ebe0cf0e9 | 2165 | cipher_size = 2 + ((ecdsa) ? 2 : 0) + ((psk) ? 2 : 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2166 | extension_size = (ecdsa) ? 2 + 6 + 6 + 8 + 6: 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2167 | |
ashleymills | 0:ff9ebe0cf0e9 | 2168 | if (cipher_size == 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2169 | DBG("no cipher callbacks implemented"); |
ashleymills | 0:ff9ebe0cf0e9 | 2170 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2171 | |
ashleymills | 0:ff9ebe0cf0e9 | 2172 | dtls_int_to_uint16(p, DTLS_VERSION); |
ashleymills | 0:ff9ebe0cf0e9 | 2173 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2174 | |
ashleymills | 0:ff9ebe0cf0e9 | 2175 | if (cookie_length > DTLS_COOKIE_LENGTH_MAX) { |
ashleymills | 0:ff9ebe0cf0e9 | 2176 | WARN("the cookie is too long"); |
ashleymills | 0:ff9ebe0cf0e9 | 2177 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 2178 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2179 | |
ashleymills | 0:ff9ebe0cf0e9 | 2180 | if (cookie_length == 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2181 | /* Set client random: First 4 bytes are the client's Unix timestamp, |
ashleymills | 0:ff9ebe0cf0e9 | 2182 | * followed by 28 bytes of generate random data. */ |
ashleymills | 0:ff9ebe0cf0e9 | 2183 | dtls_ticks(&now); |
ashleymills | 0:ff9ebe0cf0e9 | 2184 | dtls_int_to_uint32(&handshake->tmp.random.client, now / CLOCK_SECOND); |
ashleymills | 0:ff9ebe0cf0e9 | 2185 | prng(handshake->tmp.random.client + sizeof(uint32), |
ashleymills | 0:ff9ebe0cf0e9 | 2186 | DTLS_RANDOM_LENGTH - sizeof(uint32)); |
ashleymills | 0:ff9ebe0cf0e9 | 2187 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2188 | /* we must use the same Client Random as for the previous request */ |
ashleymills | 0:ff9ebe0cf0e9 | 2189 | memcpy(p, handshake->tmp.random.client, DTLS_RANDOM_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 2190 | p += DTLS_RANDOM_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2191 | |
ashleymills | 0:ff9ebe0cf0e9 | 2192 | /* session id (length 0) */ |
ashleymills | 0:ff9ebe0cf0e9 | 2193 | dtls_int_to_uint8(p, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2194 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2195 | |
ashleymills | 0:ff9ebe0cf0e9 | 2196 | /* cookie */ |
ashleymills | 0:ff9ebe0cf0e9 | 2197 | dtls_int_to_uint8(p, cookie_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2198 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2199 | if (cookie_length != 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2200 | memcpy(p, cookie, cookie_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2201 | p += cookie_length; |
ashleymills | 0:ff9ebe0cf0e9 | 2202 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2203 | |
ashleymills | 0:ff9ebe0cf0e9 | 2204 | /* add known cipher(s) */ |
ashleymills | 0:ff9ebe0cf0e9 | 2205 | dtls_int_to_uint16(p, cipher_size - 2); |
ashleymills | 0:ff9ebe0cf0e9 | 2206 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2207 | |
ashleymills | 0:ff9ebe0cf0e9 | 2208 | if (ecdsa) { |
ashleymills | 0:ff9ebe0cf0e9 | 2209 | dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); |
ashleymills | 0:ff9ebe0cf0e9 | 2210 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2211 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2212 | if (psk) { |
ashleymills | 0:ff9ebe0cf0e9 | 2213 | dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8); |
ashleymills | 0:ff9ebe0cf0e9 | 2214 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2215 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2216 | |
ashleymills | 0:ff9ebe0cf0e9 | 2217 | /* compression method */ |
ashleymills | 0:ff9ebe0cf0e9 | 2218 | dtls_int_to_uint8(p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 2219 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2220 | |
ashleymills | 0:ff9ebe0cf0e9 | 2221 | dtls_int_to_uint8(p, TLS_COMPRESSION_NULL); |
ashleymills | 0:ff9ebe0cf0e9 | 2222 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2223 | |
ashleymills | 0:ff9ebe0cf0e9 | 2224 | if (extension_size) { |
ashleymills | 0:ff9ebe0cf0e9 | 2225 | /* length of the extensions */ |
ashleymills | 0:ff9ebe0cf0e9 | 2226 | dtls_int_to_uint16(p, extension_size - 2); |
ashleymills | 0:ff9ebe0cf0e9 | 2227 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2228 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2229 | |
ashleymills | 0:ff9ebe0cf0e9 | 2230 | if (ecdsa) { |
ashleymills | 0:ff9ebe0cf0e9 | 2231 | /* client certificate type extension */ |
ashleymills | 0:ff9ebe0cf0e9 | 2232 | dtls_int_to_uint16(p, TLS_EXT_CLIENT_CERIFICATE_TYPE); |
ashleymills | 0:ff9ebe0cf0e9 | 2233 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2234 | |
ashleymills | 0:ff9ebe0cf0e9 | 2235 | /* length of this extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 2236 | dtls_int_to_uint16(p, 2); |
ashleymills | 0:ff9ebe0cf0e9 | 2237 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2238 | |
ashleymills | 0:ff9ebe0cf0e9 | 2239 | /* length of the list */ |
ashleymills | 0:ff9ebe0cf0e9 | 2240 | dtls_int_to_uint8(p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 2241 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2242 | |
ashleymills | 0:ff9ebe0cf0e9 | 2243 | dtls_int_to_uint8(p, TLS_CERT_TYPE_OOB); |
ashleymills | 0:ff9ebe0cf0e9 | 2244 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2245 | |
ashleymills | 0:ff9ebe0cf0e9 | 2246 | /* client certificate type extension */ |
ashleymills | 0:ff9ebe0cf0e9 | 2247 | dtls_int_to_uint16(p, TLS_EXT_SERVER_CERIFICATE_TYPE); |
ashleymills | 0:ff9ebe0cf0e9 | 2248 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2249 | |
ashleymills | 0:ff9ebe0cf0e9 | 2250 | /* length of this extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 2251 | dtls_int_to_uint16(p, 2); |
ashleymills | 0:ff9ebe0cf0e9 | 2252 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2253 | |
ashleymills | 0:ff9ebe0cf0e9 | 2254 | /* length of the list */ |
ashleymills | 0:ff9ebe0cf0e9 | 2255 | dtls_int_to_uint8(p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 2256 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2257 | |
ashleymills | 0:ff9ebe0cf0e9 | 2258 | dtls_int_to_uint8(p, TLS_CERT_TYPE_OOB); |
ashleymills | 0:ff9ebe0cf0e9 | 2259 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2260 | |
ashleymills | 0:ff9ebe0cf0e9 | 2261 | /* elliptic_curves */ |
ashleymills | 0:ff9ebe0cf0e9 | 2262 | dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES); |
ashleymills | 0:ff9ebe0cf0e9 | 2263 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2264 | |
ashleymills | 0:ff9ebe0cf0e9 | 2265 | /* length of this extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 2266 | dtls_int_to_uint16(p, 4); |
ashleymills | 0:ff9ebe0cf0e9 | 2267 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2268 | |
ashleymills | 0:ff9ebe0cf0e9 | 2269 | /* length of the list */ |
ashleymills | 0:ff9ebe0cf0e9 | 2270 | dtls_int_to_uint16(p, 2); |
ashleymills | 0:ff9ebe0cf0e9 | 2271 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2272 | |
ashleymills | 0:ff9ebe0cf0e9 | 2273 | dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES_SECP256R1); |
ashleymills | 0:ff9ebe0cf0e9 | 2274 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2275 | |
ashleymills | 0:ff9ebe0cf0e9 | 2276 | /* ec_point_formats */ |
ashleymills | 0:ff9ebe0cf0e9 | 2277 | dtls_int_to_uint16(p, TLS_EXT_EC_POINT_FORMATS); |
ashleymills | 0:ff9ebe0cf0e9 | 2278 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2279 | |
ashleymills | 0:ff9ebe0cf0e9 | 2280 | /* length of this extension type */ |
ashleymills | 0:ff9ebe0cf0e9 | 2281 | dtls_int_to_uint16(p, 2); |
ashleymills | 0:ff9ebe0cf0e9 | 2282 | p += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2283 | |
ashleymills | 0:ff9ebe0cf0e9 | 2284 | /* number of supported formats */ |
ashleymills | 0:ff9ebe0cf0e9 | 2285 | dtls_int_to_uint8(p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 2286 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2287 | |
ashleymills | 0:ff9ebe0cf0e9 | 2288 | dtls_int_to_uint8(p, TLS_EXT_EC_POINT_FORMATS_UNCOMPRESSED); |
ashleymills | 0:ff9ebe0cf0e9 | 2289 | p += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2290 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2291 | |
ashleymills | 0:ff9ebe0cf0e9 | 2292 | assert(p - buf <= sizeof(buf)); |
ashleymills | 0:ff9ebe0cf0e9 | 2293 | |
ashleymills | 0:ff9ebe0cf0e9 | 2294 | if (cookie_length != 0) |
ashleymills | 0:ff9ebe0cf0e9 | 2295 | clear_hs_hash(peer); |
ashleymills | 0:ff9ebe0cf0e9 | 2296 | |
ashleymills | 0:ff9ebe0cf0e9 | 2297 | return dtls_send_handshake_msg_hash(ctx, peer, &peer->session, |
ashleymills | 0:ff9ebe0cf0e9 | 2298 | DTLS_HT_CLIENT_HELLO, |
ashleymills | 0:ff9ebe0cf0e9 | 2299 | buf, p - buf, cookie_length != 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2300 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2301 | |
ashleymills | 0:ff9ebe0cf0e9 | 2302 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2303 | check_server_hello(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 2304 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2305 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 2306 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2307 | dtls_handshake_parameters_t *handshake = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2308 | |
ashleymills | 0:ff9ebe0cf0e9 | 2309 | /* This function is called when we expect a ServerHello (i.e. we |
ashleymills | 0:ff9ebe0cf0e9 | 2310 | * have sent a ClientHello). We might instead receive a HelloVerify |
ashleymills | 0:ff9ebe0cf0e9 | 2311 | * request containing a cookie. If so, we must repeat the |
ashleymills | 0:ff9ebe0cf0e9 | 2312 | * ClientHello with the given Cookie. |
ashleymills | 0:ff9ebe0cf0e9 | 2313 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 2314 | if (data_length < DTLS_HS_LENGTH + DTLS_HS_LENGTH) |
ashleymills | 0:ff9ebe0cf0e9 | 2315 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2316 | |
ashleymills | 0:ff9ebe0cf0e9 | 2317 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2318 | |
ashleymills | 0:ff9ebe0cf0e9 | 2319 | /* FIXME: check data_length before accessing fields */ |
ashleymills | 0:ff9ebe0cf0e9 | 2320 | |
ashleymills | 0:ff9ebe0cf0e9 | 2321 | /* Get the server's random data and store selected cipher suite |
ashleymills | 0:ff9ebe0cf0e9 | 2322 | * and compression method (like dtls_update_parameters(). |
ashleymills | 0:ff9ebe0cf0e9 | 2323 | * Then calculate master secret and wait for ServerHelloDone. When received, |
ashleymills | 0:ff9ebe0cf0e9 | 2324 | * send ClientKeyExchange (?) and ChangeCipherSpec + ClientFinished. */ |
ashleymills | 0:ff9ebe0cf0e9 | 2325 | |
ashleymills | 0:ff9ebe0cf0e9 | 2326 | /* check server version */ |
ashleymills | 0:ff9ebe0cf0e9 | 2327 | data += DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2328 | data_length -= DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2329 | |
ashleymills | 0:ff9ebe0cf0e9 | 2330 | if (dtls_uint16_to_int(data) != DTLS_VERSION) { |
ashleymills | 0:ff9ebe0cf0e9 | 2331 | DBG("unknown DTLS version"); |
ashleymills | 0:ff9ebe0cf0e9 | 2332 | return dtls_alert_fatal_create(DTLS_ALERT_PROTOCOL_VERSION); |
ashleymills | 0:ff9ebe0cf0e9 | 2333 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2334 | |
ashleymills | 0:ff9ebe0cf0e9 | 2335 | data += sizeof(uint16); /* skip version field */ |
ashleymills | 0:ff9ebe0cf0e9 | 2336 | data_length -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2337 | |
ashleymills | 0:ff9ebe0cf0e9 | 2338 | /* store server random data */ |
ashleymills | 0:ff9ebe0cf0e9 | 2339 | memcpy(handshake->tmp.random.server, data, DTLS_RANDOM_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 2340 | /* skip server random */ |
ashleymills | 0:ff9ebe0cf0e9 | 2341 | data += DTLS_RANDOM_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2342 | data_length -= DTLS_RANDOM_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2343 | |
ashleymills | 0:ff9ebe0cf0e9 | 2344 | SKIP_VAR_FIELD(data, data_length, uint8); /* skip session id */ |
ashleymills | 0:ff9ebe0cf0e9 | 2345 | |
ashleymills | 0:ff9ebe0cf0e9 | 2346 | /* Check cipher suite. As we offer all we have, it is sufficient |
ashleymills | 0:ff9ebe0cf0e9 | 2347 | * to check if the cipher suite selected by the server is in our |
ashleymills | 0:ff9ebe0cf0e9 | 2348 | * list of known cipher suites. Subsets are not supported. */ |
ashleymills | 0:ff9ebe0cf0e9 | 2349 | handshake->cipher = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2350 | if (!known_cipher(ctx, handshake->cipher, 1)) { |
ashleymills | 0:ff9ebe0cf0e9 | 2351 | DBG("unsupported cipher 0x%02x 0x%02x", |
ashleymills | 0:ff9ebe0cf0e9 | 2352 | data[0], data[1]); |
ashleymills | 0:ff9ebe0cf0e9 | 2353 | return dtls_alert_fatal_create(DTLS_ALERT_INSUFFICIENT_SECURITY); |
ashleymills | 0:ff9ebe0cf0e9 | 2354 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2355 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2356 | data_length -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2357 | |
ashleymills | 0:ff9ebe0cf0e9 | 2358 | /* Check if NULL compression was selected. We do not know any other. */ |
ashleymills | 0:ff9ebe0cf0e9 | 2359 | if (dtls_uint8_to_int(data) != TLS_COMPRESSION_NULL) { |
ashleymills | 0:ff9ebe0cf0e9 | 2360 | DBG("unsupported compression method 0x%02x", data[0]); |
ashleymills | 0:ff9ebe0cf0e9 | 2361 | return dtls_alert_fatal_create(DTLS_ALERT_INSUFFICIENT_SECURITY); |
ashleymills | 0:ff9ebe0cf0e9 | 2362 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2363 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2364 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2365 | |
ashleymills | 0:ff9ebe0cf0e9 | 2366 | return dtls_check_tls_extension(peer, data, data_length, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2367 | |
ashleymills | 0:ff9ebe0cf0e9 | 2368 | error: |
ashleymills | 0:ff9ebe0cf0e9 | 2369 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2370 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2371 | |
ashleymills | 0:ff9ebe0cf0e9 | 2372 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2373 | check_server_hello_verify_request(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 2374 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2375 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 2376 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2377 | DBG("check_server_hello_verify_request"); |
ashleymills | 0:ff9ebe0cf0e9 | 2378 | dtls_hello_verify_t *hv; |
ashleymills | 0:ff9ebe0cf0e9 | 2379 | int res; |
ashleymills | 0:ff9ebe0cf0e9 | 2380 | |
ashleymills | 0:ff9ebe0cf0e9 | 2381 | if (data_length < DTLS_HS_LENGTH + DTLS_HV_LENGTH) |
ashleymills | 0:ff9ebe0cf0e9 | 2382 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2383 | |
ashleymills | 0:ff9ebe0cf0e9 | 2384 | hv = (dtls_hello_verify_t *)(data + DTLS_HS_LENGTH); |
ashleymills | 0:ff9ebe0cf0e9 | 2385 | |
ashleymills | 0:ff9ebe0cf0e9 | 2386 | res = dtls_send_client_hello(ctx, peer, hv->cookie, hv->cookie_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2387 | |
ashleymills | 0:ff9ebe0cf0e9 | 2388 | if (res < 0) |
ashleymills | 0:ff9ebe0cf0e9 | 2389 | WARN("cannot send ClientHello"); |
ashleymills | 0:ff9ebe0cf0e9 | 2390 | |
ashleymills | 0:ff9ebe0cf0e9 | 2391 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 2392 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2393 | |
ashleymills | 0:ff9ebe0cf0e9 | 2394 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2395 | check_server_certificate(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 2396 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2397 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 2398 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2399 | DBG("check_server_certificate"); |
ashleymills | 0:ff9ebe0cf0e9 | 2400 | int err; |
ashleymills | 0:ff9ebe0cf0e9 | 2401 | dtls_handshake_parameters_t *config = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2402 | |
ashleymills | 0:ff9ebe0cf0e9 | 2403 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2404 | |
ashleymills | 0:ff9ebe0cf0e9 | 2405 | assert(config->cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); |
ashleymills | 0:ff9ebe0cf0e9 | 2406 | |
ashleymills | 0:ff9ebe0cf0e9 | 2407 | data += DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2408 | |
ashleymills | 0:ff9ebe0cf0e9 | 2409 | if (dtls_uint24_to_int(data) != 94) { |
ashleymills | 0:ff9ebe0cf0e9 | 2410 | DBG("expect length of 94 bytes for server certificate message"); |
ashleymills | 0:ff9ebe0cf0e9 | 2411 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2412 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2413 | data += sizeof(uint24); |
ashleymills | 0:ff9ebe0cf0e9 | 2414 | |
ashleymills | 0:ff9ebe0cf0e9 | 2415 | if (dtls_uint24_to_int(data) != 91) { |
ashleymills | 0:ff9ebe0cf0e9 | 2416 | DBG("expect length of 91 bytes for certificate"); |
ashleymills | 0:ff9ebe0cf0e9 | 2417 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2418 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2419 | data += sizeof(uint24); |
ashleymills | 0:ff9ebe0cf0e9 | 2420 | |
ashleymills | 0:ff9ebe0cf0e9 | 2421 | if (memcmp(data, cert_asn1_header, sizeof(cert_asn1_header))) { |
ashleymills | 0:ff9ebe0cf0e9 | 2422 | DBG("got an unexpected Subject public key format"); |
ashleymills | 0:ff9ebe0cf0e9 | 2423 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2424 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2425 | data += sizeof(cert_asn1_header); |
ashleymills | 0:ff9ebe0cf0e9 | 2426 | |
ashleymills | 0:ff9ebe0cf0e9 | 2427 | memcpy(config->keyx.ecdsa.other_pub_x, data, |
ashleymills | 0:ff9ebe0cf0e9 | 2428 | sizeof(config->keyx.ecdsa.other_pub_x)); |
ashleymills | 0:ff9ebe0cf0e9 | 2429 | data += sizeof(config->keyx.ecdsa.other_pub_x); |
ashleymills | 0:ff9ebe0cf0e9 | 2430 | |
ashleymills | 0:ff9ebe0cf0e9 | 2431 | memcpy(config->keyx.ecdsa.other_pub_y, data, |
ashleymills | 0:ff9ebe0cf0e9 | 2432 | sizeof(config->keyx.ecdsa.other_pub_y)); |
ashleymills | 0:ff9ebe0cf0e9 | 2433 | data += sizeof(config->keyx.ecdsa.other_pub_y); |
ashleymills | 0:ff9ebe0cf0e9 | 2434 | |
ashleymills | 0:ff9ebe0cf0e9 | 2435 | err = CALL(ctx, verify_ecdsa_key, &peer->session, |
ashleymills | 0:ff9ebe0cf0e9 | 2436 | config->keyx.ecdsa.other_pub_x, |
ashleymills | 0:ff9ebe0cf0e9 | 2437 | config->keyx.ecdsa.other_pub_y, |
ashleymills | 0:ff9ebe0cf0e9 | 2438 | sizeof(config->keyx.ecdsa.other_pub_x)); |
ashleymills | 0:ff9ebe0cf0e9 | 2439 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2440 | WARN("The certificate was not accepted"); |
ashleymills | 0:ff9ebe0cf0e9 | 2441 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 2442 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2443 | |
ashleymills | 0:ff9ebe0cf0e9 | 2444 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2445 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2446 | |
ashleymills | 0:ff9ebe0cf0e9 | 2447 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2448 | check_server_key_exchange_ecdsa(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 2449 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2450 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 2451 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2452 | DBG("check_server_key_exchange_ecdsa"); |
ashleymills | 0:ff9ebe0cf0e9 | 2453 | |
ashleymills | 0:ff9ebe0cf0e9 | 2454 | dtls_handshake_parameters_t *config = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2455 | int i; |
ashleymills | 0:ff9ebe0cf0e9 | 2456 | unsigned char *result_r; |
ashleymills | 0:ff9ebe0cf0e9 | 2457 | unsigned char *result_s; |
ashleymills | 0:ff9ebe0cf0e9 | 2458 | unsigned char *key_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2459 | |
ashleymills | 0:ff9ebe0cf0e9 | 2460 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2461 | |
ashleymills | 0:ff9ebe0cf0e9 | 2462 | assert(config->cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); |
ashleymills | 0:ff9ebe0cf0e9 | 2463 | |
ashleymills | 0:ff9ebe0cf0e9 | 2464 | data += DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2465 | |
ashleymills | 0:ff9ebe0cf0e9 | 2466 | if (data_length < DTLS_HS_LENGTH + DTLS_SKEXEC_LENGTH) { |
ashleymills | 0:ff9ebe0cf0e9 | 2467 | DBG("the package length does not match the expected"); |
ashleymills | 0:ff9ebe0cf0e9 | 2468 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2469 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2470 | key_params = data; |
ashleymills | 0:ff9ebe0cf0e9 | 2471 | |
ashleymills | 0:ff9ebe0cf0e9 | 2472 | if (dtls_uint8_to_int(data) != 3) { |
ashleymills | 0:ff9ebe0cf0e9 | 2473 | DBG("Only named curves supported"); |
ashleymills | 0:ff9ebe0cf0e9 | 2474 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 2475 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2476 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2477 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2478 | |
ashleymills | 0:ff9ebe0cf0e9 | 2479 | if (dtls_uint16_to_int(data) != 23) { |
ashleymills | 0:ff9ebe0cf0e9 | 2480 | DBG("secp256r1 supported"); |
ashleymills | 0:ff9ebe0cf0e9 | 2481 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 2482 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2483 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2484 | data_length -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2485 | |
ashleymills | 0:ff9ebe0cf0e9 | 2486 | if (dtls_uint8_to_int(data) != 65) { |
ashleymills | 0:ff9ebe0cf0e9 | 2487 | DBG("expected 65 bytes long public point"); |
ashleymills | 0:ff9ebe0cf0e9 | 2488 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 2489 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2490 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2491 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2492 | |
ashleymills | 0:ff9ebe0cf0e9 | 2493 | if (dtls_uint8_to_int(data) != 4) { |
ashleymills | 0:ff9ebe0cf0e9 | 2494 | DBG("expected uncompressed public point"); |
ashleymills | 0:ff9ebe0cf0e9 | 2495 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2496 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2497 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2498 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2499 | |
ashleymills | 0:ff9ebe0cf0e9 | 2500 | memcpy(config->keyx.ecdsa.other_eph_pub_x, data, sizeof(config->keyx.ecdsa.other_eph_pub_y)); |
ashleymills | 0:ff9ebe0cf0e9 | 2501 | data += sizeof(config->keyx.ecdsa.other_eph_pub_y); |
ashleymills | 0:ff9ebe0cf0e9 | 2502 | data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y); |
ashleymills | 0:ff9ebe0cf0e9 | 2503 | |
ashleymills | 0:ff9ebe0cf0e9 | 2504 | memcpy(config->keyx.ecdsa.other_eph_pub_y, data, sizeof(config->keyx.ecdsa.other_eph_pub_y)); |
ashleymills | 0:ff9ebe0cf0e9 | 2505 | data += sizeof(config->keyx.ecdsa.other_eph_pub_y); |
ashleymills | 0:ff9ebe0cf0e9 | 2506 | data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y); |
ashleymills | 0:ff9ebe0cf0e9 | 2507 | |
ashleymills | 0:ff9ebe0cf0e9 | 2508 | |
ashleymills | 0:ff9ebe0cf0e9 | 2509 | if (data_length < dtls_uint16_to_int(data)) { |
ashleymills | 0:ff9ebe0cf0e9 | 2510 | DBG("signature length wrong"); |
ashleymills | 0:ff9ebe0cf0e9 | 2511 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2512 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2513 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2514 | data_length -= sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2515 | |
ashleymills | 0:ff9ebe0cf0e9 | 2516 | if (dtls_uint8_to_int(data) != 0x30) { |
ashleymills | 0:ff9ebe0cf0e9 | 2517 | DBG("wrong ASN.1 struct, expected SEQUENCE"); |
ashleymills | 0:ff9ebe0cf0e9 | 2518 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2519 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2520 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2521 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2522 | |
ashleymills | 0:ff9ebe0cf0e9 | 2523 | if (data_length < dtls_uint8_to_int(data)) { |
ashleymills | 0:ff9ebe0cf0e9 | 2524 | DBG("signature length wrong"); |
ashleymills | 0:ff9ebe0cf0e9 | 2525 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2526 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2527 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2528 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2529 | |
ashleymills | 0:ff9ebe0cf0e9 | 2530 | if (dtls_uint8_to_int(data) != 0x02) { |
ashleymills | 0:ff9ebe0cf0e9 | 2531 | DBG("wrong ASN.1 struct, expected Integer"); |
ashleymills | 0:ff9ebe0cf0e9 | 2532 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2533 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2534 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2535 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2536 | |
ashleymills | 0:ff9ebe0cf0e9 | 2537 | i = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2538 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2539 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2540 | |
ashleymills | 0:ff9ebe0cf0e9 | 2541 | /* Sometimes these values have a leeding 0 byte */ |
ashleymills | 0:ff9ebe0cf0e9 | 2542 | result_r = data + i - DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 2543 | |
ashleymills | 0:ff9ebe0cf0e9 | 2544 | data += i; |
ashleymills | 0:ff9ebe0cf0e9 | 2545 | data_length -= i; |
ashleymills | 0:ff9ebe0cf0e9 | 2546 | |
ashleymills | 0:ff9ebe0cf0e9 | 2547 | if (dtls_uint8_to_int(data) != 0x02) { |
ashleymills | 0:ff9ebe0cf0e9 | 2548 | DBG("wrong ASN.1 struct, expected Integer"); |
ashleymills | 0:ff9ebe0cf0e9 | 2549 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2550 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2551 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2552 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2553 | |
ashleymills | 0:ff9ebe0cf0e9 | 2554 | i = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2555 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2556 | data_length -= sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2557 | |
ashleymills | 0:ff9ebe0cf0e9 | 2558 | /* Sometimes these values have a leeding 0 byte */ |
ashleymills | 0:ff9ebe0cf0e9 | 2559 | result_s = data + i - DTLS_EC_KEY_SIZE; |
ashleymills | 0:ff9ebe0cf0e9 | 2560 | |
ashleymills | 0:ff9ebe0cf0e9 | 2561 | data += i; |
ashleymills | 0:ff9ebe0cf0e9 | 2562 | data_length -= i; |
ashleymills | 0:ff9ebe0cf0e9 | 2563 | |
ashleymills | 0:ff9ebe0cf0e9 | 2564 | i = dtls_ecdsa_verify_sig(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y, |
ashleymills | 0:ff9ebe0cf0e9 | 2565 | sizeof(config->keyx.ecdsa.other_pub_x), |
ashleymills | 0:ff9ebe0cf0e9 | 2566 | config->tmp.random.client, DTLS_RANDOM_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 2567 | config->tmp.random.server, DTLS_RANDOM_LENGTH, |
ashleymills | 0:ff9ebe0cf0e9 | 2568 | key_params, |
ashleymills | 0:ff9ebe0cf0e9 | 2569 | 1 + 2 + 1 + 1 + (2 * DTLS_EC_KEY_SIZE), |
ashleymills | 0:ff9ebe0cf0e9 | 2570 | result_r, result_s); |
ashleymills | 0:ff9ebe0cf0e9 | 2571 | |
ashleymills | 0:ff9ebe0cf0e9 | 2572 | if (i < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2573 | DBG("wrong signature"); |
ashleymills | 0:ff9ebe0cf0e9 | 2574 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 2575 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2576 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2577 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2578 | |
ashleymills | 0:ff9ebe0cf0e9 | 2579 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2580 | check_server_key_exchange_psk(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 2581 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2582 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 2583 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2584 | DBG("check_server_key_exchange_psk"); |
ashleymills | 0:ff9ebe0cf0e9 | 2585 | dtls_handshake_parameters_t *config = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2586 | int len; |
ashleymills | 0:ff9ebe0cf0e9 | 2587 | |
ashleymills | 0:ff9ebe0cf0e9 | 2588 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2589 | |
ashleymills | 0:ff9ebe0cf0e9 | 2590 | assert(config->cipher == TLS_PSK_WITH_AES_128_CCM_8); |
ashleymills | 0:ff9ebe0cf0e9 | 2591 | |
ashleymills | 0:ff9ebe0cf0e9 | 2592 | data += DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2593 | |
ashleymills | 0:ff9ebe0cf0e9 | 2594 | if (data_length < DTLS_HS_LENGTH + DTLS_SKEXECPSK_LENGTH_MIN) { |
ashleymills | 0:ff9ebe0cf0e9 | 2595 | DBG("the package length does not match the expected"); |
ashleymills | 0:ff9ebe0cf0e9 | 2596 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2597 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2598 | |
ashleymills | 0:ff9ebe0cf0e9 | 2599 | len = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2600 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2601 | |
ashleymills | 0:ff9ebe0cf0e9 | 2602 | if (len != data_length - DTLS_HS_LENGTH - sizeof(uint16)) { |
ashleymills | 0:ff9ebe0cf0e9 | 2603 | WARN("the length of the server identity hint is worng"); |
ashleymills | 0:ff9ebe0cf0e9 | 2604 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2605 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2606 | |
ashleymills | 0:ff9ebe0cf0e9 | 2607 | if (len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { |
ashleymills | 0:ff9ebe0cf0e9 | 2608 | WARN("please use a smaller server identity hint"); |
ashleymills | 0:ff9ebe0cf0e9 | 2609 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2610 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2611 | |
ashleymills | 0:ff9ebe0cf0e9 | 2612 | config->keyx.psk.id_length = len; |
ashleymills | 0:ff9ebe0cf0e9 | 2613 | memcpy(config->keyx.psk.identity, data, len); |
ashleymills | 0:ff9ebe0cf0e9 | 2614 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2615 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2616 | |
ashleymills | 0:ff9ebe0cf0e9 | 2617 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2618 | check_certificate_request(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 2619 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2620 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 2621 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2622 | DBG("check_certificate_request"); |
ashleymills | 0:ff9ebe0cf0e9 | 2623 | int i; |
ashleymills | 0:ff9ebe0cf0e9 | 2624 | int auth_alg; |
ashleymills | 0:ff9ebe0cf0e9 | 2625 | int sig_alg; |
ashleymills | 0:ff9ebe0cf0e9 | 2626 | int hash_alg; |
ashleymills | 0:ff9ebe0cf0e9 | 2627 | |
ashleymills | 0:ff9ebe0cf0e9 | 2628 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2629 | |
ashleymills | 0:ff9ebe0cf0e9 | 2630 | assert(peer->handshake_params.cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); |
ashleymills | 0:ff9ebe0cf0e9 | 2631 | |
ashleymills | 0:ff9ebe0cf0e9 | 2632 | data += DTLS_HS_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 2633 | |
ashleymills | 0:ff9ebe0cf0e9 | 2634 | if (data_length < DTLS_HS_LENGTH + 5) { |
ashleymills | 0:ff9ebe0cf0e9 | 2635 | DBG("the package length does not match the expected"); |
ashleymills | 0:ff9ebe0cf0e9 | 2636 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2637 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2638 | |
ashleymills | 0:ff9ebe0cf0e9 | 2639 | i = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2640 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2641 | if (i + 1 > data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 2642 | DBG("the cerfificate types are too long"); |
ashleymills | 0:ff9ebe0cf0e9 | 2643 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2644 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2645 | |
ashleymills | 0:ff9ebe0cf0e9 | 2646 | auth_alg = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2647 | for (; i > 0 ; i -= sizeof(uint8)) { |
ashleymills | 0:ff9ebe0cf0e9 | 2648 | if (dtls_uint8_to_int(data) == 64 && auth_alg == 0) |
ashleymills | 0:ff9ebe0cf0e9 | 2649 | auth_alg = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2650 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2651 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2652 | |
ashleymills | 0:ff9ebe0cf0e9 | 2653 | if (auth_alg != 64) { |
ashleymills | 0:ff9ebe0cf0e9 | 2654 | DBG("the request authentication algorithem is not supproted"); |
ashleymills | 0:ff9ebe0cf0e9 | 2655 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 2656 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2657 | |
ashleymills | 0:ff9ebe0cf0e9 | 2658 | i = dtls_uint16_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2659 | data += sizeof(uint16); |
ashleymills | 0:ff9ebe0cf0e9 | 2660 | if (i + 1 > data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 2661 | DBG("the signature and hash algorithm list is too long"); |
ashleymills | 0:ff9ebe0cf0e9 | 2662 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2663 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2664 | |
ashleymills | 0:ff9ebe0cf0e9 | 2665 | hash_alg = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2666 | sig_alg = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2667 | for (; i > 0 ; i -= sizeof(uint16)) { |
ashleymills | 0:ff9ebe0cf0e9 | 2668 | int current_hash_alg; |
ashleymills | 0:ff9ebe0cf0e9 | 2669 | int current_sig_alg; |
ashleymills | 0:ff9ebe0cf0e9 | 2670 | |
ashleymills | 0:ff9ebe0cf0e9 | 2671 | current_hash_alg = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2672 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2673 | current_sig_alg = dtls_uint8_to_int(data); |
ashleymills | 0:ff9ebe0cf0e9 | 2674 | data += sizeof(uint8); |
ashleymills | 0:ff9ebe0cf0e9 | 2675 | |
ashleymills | 0:ff9ebe0cf0e9 | 2676 | if (current_hash_alg == 4 && hash_alg == 0 && |
ashleymills | 0:ff9ebe0cf0e9 | 2677 | current_sig_alg == 3 && sig_alg == 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2678 | hash_alg = current_hash_alg; |
ashleymills | 0:ff9ebe0cf0e9 | 2679 | sig_alg = current_sig_alg; |
ashleymills | 0:ff9ebe0cf0e9 | 2680 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2681 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2682 | |
ashleymills | 0:ff9ebe0cf0e9 | 2683 | if (hash_alg != 4 || sig_alg != 3) { |
ashleymills | 0:ff9ebe0cf0e9 | 2684 | DBG("no supported hash and signature algorithem"); |
ashleymills | 0:ff9ebe0cf0e9 | 2685 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 2686 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2687 | |
ashleymills | 0:ff9ebe0cf0e9 | 2688 | /* common names are ignored */ |
ashleymills | 0:ff9ebe0cf0e9 | 2689 | |
ashleymills | 0:ff9ebe0cf0e9 | 2690 | peer->handshake_params.do_client_auth = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 2691 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2692 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2693 | |
ashleymills | 0:ff9ebe0cf0e9 | 2694 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2695 | check_server_hellodone(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 2696 | dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2697 | uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 2698 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2699 | int res; |
ashleymills | 0:ff9ebe0cf0e9 | 2700 | const dtls_ecdsa_key_t *ecdsa_key; |
ashleymills | 0:ff9ebe0cf0e9 | 2701 | dtls_handshake_parameters_t *handshake = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2702 | dtls_security_parameters_t *security = &peer->security_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2703 | DBG("check_server_hellodone"); |
ashleymills | 0:ff9ebe0cf0e9 | 2704 | /* calculate master key, send CCS */ |
ashleymills | 0:ff9ebe0cf0e9 | 2705 | |
ashleymills | 0:ff9ebe0cf0e9 | 2706 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2707 | |
ashleymills | 0:ff9ebe0cf0e9 | 2708 | if (handshake->do_client_auth) { |
ashleymills | 0:ff9ebe0cf0e9 | 2709 | |
ashleymills | 0:ff9ebe0cf0e9 | 2710 | res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); |
ashleymills | 0:ff9ebe0cf0e9 | 2711 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2712 | DBG("no ecdsa certificate to send in certificate"); |
ashleymills | 0:ff9ebe0cf0e9 | 2713 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 2714 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2715 | |
ashleymills | 0:ff9ebe0cf0e9 | 2716 | res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key); |
ashleymills | 0:ff9ebe0cf0e9 | 2717 | |
ashleymills | 0:ff9ebe0cf0e9 | 2718 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2719 | DBG("dtls_server_hello: cannot prepare Certificate record"); |
ashleymills | 0:ff9ebe0cf0e9 | 2720 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 2721 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2722 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2723 | |
ashleymills | 0:ff9ebe0cf0e9 | 2724 | /* send ClientKeyExchange */ |
ashleymills | 0:ff9ebe0cf0e9 | 2725 | res = dtls_send_client_key_exchange(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 2726 | |
ashleymills | 0:ff9ebe0cf0e9 | 2727 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2728 | DBG("cannot send KeyExchange message"); |
ashleymills | 0:ff9ebe0cf0e9 | 2729 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 2730 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2731 | |
ashleymills | 0:ff9ebe0cf0e9 | 2732 | if (handshake->do_client_auth) { |
ashleymills | 0:ff9ebe0cf0e9 | 2733 | |
ashleymills | 0:ff9ebe0cf0e9 | 2734 | res = dtls_send_certificate_verify_ecdh(ctx, peer, ecdsa_key); |
ashleymills | 0:ff9ebe0cf0e9 | 2735 | |
ashleymills | 0:ff9ebe0cf0e9 | 2736 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2737 | DBG("dtls_server_hello: cannot prepare Certificate record"); |
ashleymills | 0:ff9ebe0cf0e9 | 2738 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 2739 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2740 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2741 | |
ashleymills | 0:ff9ebe0cf0e9 | 2742 | /* and switch cipher suite */ |
ashleymills | 0:ff9ebe0cf0e9 | 2743 | res = dtls_send_ccs(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 2744 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2745 | DBG("cannot send CCS message"); |
ashleymills | 0:ff9ebe0cf0e9 | 2746 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 2747 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2748 | |
ashleymills | 0:ff9ebe0cf0e9 | 2749 | res = calculate_key_block(ctx, handshake, security, |
ashleymills | 0:ff9ebe0cf0e9 | 2750 | &peer->session); |
ashleymills | 0:ff9ebe0cf0e9 | 2751 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2752 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 2753 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2754 | |
ashleymills | 0:ff9ebe0cf0e9 | 2755 | res = init_cipher(handshake, security, peer->role); |
ashleymills | 0:ff9ebe0cf0e9 | 2756 | if (res < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2757 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 2758 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2759 | |
ashleymills | 0:ff9ebe0cf0e9 | 2760 | inc_uint(uint16, peer->epoch); |
ashleymills | 0:ff9ebe0cf0e9 | 2761 | memset(peer->rseq, 0, sizeof(peer->rseq)); |
ashleymills | 0:ff9ebe0cf0e9 | 2762 | |
ashleymills | 0:ff9ebe0cf0e9 | 2763 | dtls_debug_keyblock(security); |
ashleymills | 0:ff9ebe0cf0e9 | 2764 | |
ashleymills | 0:ff9ebe0cf0e9 | 2765 | /* Client Finished */ |
ashleymills | 0:ff9ebe0cf0e9 | 2766 | DBG("send Finished"); |
ashleymills | 0:ff9ebe0cf0e9 | 2767 | return dtls_send_finished(ctx, peer, PRF_LABEL(client), PRF_LABEL_SIZE(client)); |
ashleymills | 0:ff9ebe0cf0e9 | 2768 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2769 | |
ashleymills | 0:ff9ebe0cf0e9 | 2770 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2771 | decrypt_verify(dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 2772 | uint8 *packet, size_t length, |
ashleymills | 0:ff9ebe0cf0e9 | 2773 | uint8 **cleartext, size_t *clen) { |
ashleymills | 0:ff9ebe0cf0e9 | 2774 | int ok = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2775 | dtls_security_parameters_t *security = &peer->security_params; |
ashleymills | 0:ff9ebe0cf0e9 | 2776 | |
ashleymills | 0:ff9ebe0cf0e9 | 2777 | *cleartext = (uint8 *)packet + sizeof(dtls_record_header_t); |
ashleymills | 0:ff9ebe0cf0e9 | 2778 | *clen = length - sizeof(dtls_record_header_t); |
ashleymills | 0:ff9ebe0cf0e9 | 2779 | |
ashleymills | 0:ff9ebe0cf0e9 | 2780 | if (security->cipher == TLS_NULL_WITH_NULL_NULL) { |
ashleymills | 0:ff9ebe0cf0e9 | 2781 | /* no cipher suite selected */ |
ashleymills | 0:ff9ebe0cf0e9 | 2782 | return 1; |
ashleymills | 0:ff9ebe0cf0e9 | 2783 | } else { /* TLS_PSK_WITH_AES_128_CCM_8 */ |
ashleymills | 0:ff9ebe0cf0e9 | 2784 | dtls_cipher_context_t *cipher_context; |
ashleymills | 0:ff9ebe0cf0e9 | 2785 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 2786 | * length of additional_data for the AEAD cipher which consists of |
ashleymills | 0:ff9ebe0cf0e9 | 2787 | * seq_num(2+6) + type(1) + version(2) + length(2) |
ashleymills | 0:ff9ebe0cf0e9 | 2788 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 2789 | #define A_DATA_LEN 13 |
ashleymills | 0:ff9ebe0cf0e9 | 2790 | unsigned char nonce[DTLS_CCM_BLOCKSIZE]; |
ashleymills | 0:ff9ebe0cf0e9 | 2791 | unsigned char A_DATA[A_DATA_LEN]; |
ashleymills | 0:ff9ebe0cf0e9 | 2792 | long int len; |
ashleymills | 0:ff9ebe0cf0e9 | 2793 | |
ashleymills | 0:ff9ebe0cf0e9 | 2794 | |
ashleymills | 0:ff9ebe0cf0e9 | 2795 | if (*clen < 16) /* need at least IV and MAC */ |
ashleymills | 0:ff9ebe0cf0e9 | 2796 | return -1; |
ashleymills | 0:ff9ebe0cf0e9 | 2797 | |
ashleymills | 0:ff9ebe0cf0e9 | 2798 | memset(nonce, 0, DTLS_CCM_BLOCKSIZE); |
ashleymills | 0:ff9ebe0cf0e9 | 2799 | memcpy(nonce, dtls_kb_remote_iv(security, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 2800 | dtls_kb_iv_size(security, peer->role)); |
ashleymills | 0:ff9ebe0cf0e9 | 2801 | |
ashleymills | 0:ff9ebe0cf0e9 | 2802 | /* read epoch and seq_num from message */ |
ashleymills | 0:ff9ebe0cf0e9 | 2803 | memcpy(nonce + dtls_kb_iv_size(security, peer->role), *cleartext, 8); |
ashleymills | 0:ff9ebe0cf0e9 | 2804 | *cleartext += 8; |
ashleymills | 0:ff9ebe0cf0e9 | 2805 | *clen -= 8; |
ashleymills | 0:ff9ebe0cf0e9 | 2806 | |
ashleymills | 0:ff9ebe0cf0e9 | 2807 | cipher_context = security->read_cipher; |
ashleymills | 0:ff9ebe0cf0e9 | 2808 | |
ashleymills | 0:ff9ebe0cf0e9 | 2809 | if (!cipher_context) { |
ashleymills | 0:ff9ebe0cf0e9 | 2810 | WARN("no read_cipher available!"); |
ashleymills | 0:ff9ebe0cf0e9 | 2811 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2812 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2813 | |
ashleymills | 0:ff9ebe0cf0e9 | 2814 | dtls_dsrv_hexdump_log(LOG_DEBUG, "nonce", nonce, DTLS_CCM_BLOCKSIZE, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2815 | dtls_dsrv_hexdump_log(LOG_DEBUG, "key", |
ashleymills | 0:ff9ebe0cf0e9 | 2816 | dtls_kb_remote_write_key(security, peer->role), |
ashleymills | 0:ff9ebe0cf0e9 | 2817 | dtls_kb_key_size(security, peer->role), 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2818 | dtls_dsrv_hexdump_log(LOG_DEBUG, "ciphertext", *cleartext, *clen, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2819 | |
ashleymills | 0:ff9ebe0cf0e9 | 2820 | /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3: |
ashleymills | 0:ff9ebe0cf0e9 | 2821 | * |
ashleymills | 0:ff9ebe0cf0e9 | 2822 | * additional_data = seq_num + TLSCompressed.type + |
ashleymills | 0:ff9ebe0cf0e9 | 2823 | * TLSCompressed.version + TLSCompressed.length; |
ashleymills | 0:ff9ebe0cf0e9 | 2824 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 2825 | memcpy(A_DATA, &DTLS_RECORD_HEADER(packet)->epoch, 8); /* epoch and seq_num */ |
ashleymills | 0:ff9ebe0cf0e9 | 2826 | memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(packet)->content_type, 3); /* type and version */ |
ashleymills | 0:ff9ebe0cf0e9 | 2827 | dtls_int_to_uint16(A_DATA + 11, *clen - 8); /* length without nonce_explicit */ |
ashleymills | 0:ff9ebe0cf0e9 | 2828 | |
ashleymills | 0:ff9ebe0cf0e9 | 2829 | len = dtls_decrypt(cipher_context, *cleartext, *clen, *cleartext, nonce, |
ashleymills | 0:ff9ebe0cf0e9 | 2830 | A_DATA, A_DATA_LEN); |
ashleymills | 0:ff9ebe0cf0e9 | 2831 | |
ashleymills | 0:ff9ebe0cf0e9 | 2832 | ok = len >= 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2833 | if (!ok) |
ashleymills | 0:ff9ebe0cf0e9 | 2834 | WARN("decryption failed"); |
ashleymills | 0:ff9ebe0cf0e9 | 2835 | else { |
ashleymills | 0:ff9ebe0cf0e9 | 2836 | #ifndef NDEBUG |
ashleymills | 0:ff9ebe0cf0e9 | 2837 | printf("decrypt_verify(): found %ld bytes cleartext", len); |
ashleymills | 0:ff9ebe0cf0e9 | 2838 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 2839 | *clen = len; |
ashleymills | 0:ff9ebe0cf0e9 | 2840 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2841 | dtls_dsrv_hexdump_log(LOG_DEBUG, "cleartext", *cleartext, *clen, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2842 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2843 | |
ashleymills | 0:ff9ebe0cf0e9 | 2844 | return ok; |
ashleymills | 0:ff9ebe0cf0e9 | 2845 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2846 | |
ashleymills | 0:ff9ebe0cf0e9 | 2847 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2848 | dtls_send_hello_request(dtls_context_t *ctx, dtls_peer_t *peer) |
ashleymills | 0:ff9ebe0cf0e9 | 2849 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2850 | return dtls_send_handshake_msg_hash(ctx, peer, &peer->session, |
ashleymills | 0:ff9ebe0cf0e9 | 2851 | DTLS_HT_HELLO_REQUEST, |
ashleymills | 0:ff9ebe0cf0e9 | 2852 | NULL, 0, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2853 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2854 | |
ashleymills | 0:ff9ebe0cf0e9 | 2855 | int |
ashleymills | 0:ff9ebe0cf0e9 | 2856 | dtls_renegotiate(dtls_context_t *ctx, const session_t *dst) |
ashleymills | 0:ff9ebe0cf0e9 | 2857 | { |
ashleymills | 0:ff9ebe0cf0e9 | 2858 | dtls_peer_t *peer = NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 2859 | int err; |
ashleymills | 0:ff9ebe0cf0e9 | 2860 | |
ashleymills | 0:ff9ebe0cf0e9 | 2861 | peer = dtls_get_peer(ctx, dst); |
ashleymills | 0:ff9ebe0cf0e9 | 2862 | |
ashleymills | 0:ff9ebe0cf0e9 | 2863 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 2864 | return -1; |
ashleymills | 0:ff9ebe0cf0e9 | 2865 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2866 | if (peer->state != DTLS_STATE_CONNECTED) |
ashleymills | 0:ff9ebe0cf0e9 | 2867 | return -1; |
ashleymills | 0:ff9ebe0cf0e9 | 2868 | |
ashleymills | 0:ff9ebe0cf0e9 | 2869 | if (peer->role == DTLS_CLIENT) { |
ashleymills | 0:ff9ebe0cf0e9 | 2870 | /* send ClientHello with empty Cookie */ |
ashleymills | 0:ff9ebe0cf0e9 | 2871 | err = dtls_send_client_hello(ctx, peer, NULL, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 2872 | if (err < 0) |
ashleymills | 0:ff9ebe0cf0e9 | 2873 | WARN("cannot send ClientHello"); |
ashleymills | 0:ff9ebe0cf0e9 | 2874 | else |
ashleymills | 0:ff9ebe0cf0e9 | 2875 | peer->state = DTLS_STATE_CLIENTHELLO; |
ashleymills | 0:ff9ebe0cf0e9 | 2876 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 2877 | } else if (peer->role == DTLS_SERVER) { |
ashleymills | 0:ff9ebe0cf0e9 | 2878 | return dtls_send_hello_request(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 2879 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2880 | |
ashleymills | 0:ff9ebe0cf0e9 | 2881 | return -1; |
ashleymills | 0:ff9ebe0cf0e9 | 2882 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2883 | |
ashleymills | 0:ff9ebe0cf0e9 | 2884 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 2885 | handle_handshake(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, |
ashleymills | 0:ff9ebe0cf0e9 | 2886 | const dtls_peer_type role, const dtls_state_t state, |
ashleymills | 0:ff9ebe0cf0e9 | 2887 | uint8 *record_header, uint8 *data, size_t data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 2888 | |
ashleymills | 0:ff9ebe0cf0e9 | 2889 | int err = 0; |
ashleymills | 0:ff9ebe0cf0e9 | 2890 | |
ashleymills | 0:ff9ebe0cf0e9 | 2891 | if (data_length < DTLS_HS_LENGTH) { |
ashleymills | 0:ff9ebe0cf0e9 | 2892 | WARN("handshake message too short"); |
ashleymills | 0:ff9ebe0cf0e9 | 2893 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 2894 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2895 | |
ashleymills | 0:ff9ebe0cf0e9 | 2896 | if (!peer && data[0] != DTLS_HT_CLIENT_HELLO) { |
ashleymills | 0:ff9ebe0cf0e9 | 2897 | WARN("If there is no peer only ClientHello is allowed"); |
ashleymills | 0:ff9ebe0cf0e9 | 2898 | return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); |
ashleymills | 0:ff9ebe0cf0e9 | 2899 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2900 | /* The following switch construct handles the given message with |
ashleymills | 0:ff9ebe0cf0e9 | 2901 | * respect to the current internal state for this peer. In case of |
ashleymills | 0:ff9ebe0cf0e9 | 2902 | * error, it is left with return 0. */ |
ashleymills | 0:ff9ebe0cf0e9 | 2903 | |
ashleymills | 0:ff9ebe0cf0e9 | 2904 | switch (data[0]) { |
ashleymills | 0:ff9ebe0cf0e9 | 2905 | |
ashleymills | 0:ff9ebe0cf0e9 | 2906 | /************************************************************************ |
ashleymills | 0:ff9ebe0cf0e9 | 2907 | * Client states |
ashleymills | 0:ff9ebe0cf0e9 | 2908 | ************************************************************************/ |
ashleymills | 0:ff9ebe0cf0e9 | 2909 | case DTLS_HT_HELLO_VERIFY_REQUEST: |
ashleymills | 0:ff9ebe0cf0e9 | 2910 | |
ashleymills | 0:ff9ebe0cf0e9 | 2911 | DBG("DTLS_HT_HELLO_VERIFY_REQUEST"); |
ashleymills | 0:ff9ebe0cf0e9 | 2912 | if (state != DTLS_STATE_CLIENTHELLO) { |
ashleymills | 0:ff9ebe0cf0e9 | 2913 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 2914 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2915 | |
ashleymills | 0:ff9ebe0cf0e9 | 2916 | err = check_server_hello_verify_request(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2917 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2918 | WARN("error in check_server_hello_verify_request err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 2919 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 2920 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2921 | |
ashleymills | 0:ff9ebe0cf0e9 | 2922 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 2923 | case DTLS_HT_SERVER_HELLO: |
ashleymills | 0:ff9ebe0cf0e9 | 2924 | |
ashleymills | 0:ff9ebe0cf0e9 | 2925 | DBG("DTLS_HT_SERVER_HELLO"); |
ashleymills | 0:ff9ebe0cf0e9 | 2926 | if (state != DTLS_STATE_CLIENTHELLO) { |
ashleymills | 0:ff9ebe0cf0e9 | 2927 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 2928 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2929 | |
ashleymills | 0:ff9ebe0cf0e9 | 2930 | err = check_server_hello(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2931 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2932 | WARN("error in check_server_hello err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 2933 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 2934 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2935 | if (peer->handshake_params.cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) |
ashleymills | 0:ff9ebe0cf0e9 | 2936 | peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; |
ashleymills | 0:ff9ebe0cf0e9 | 2937 | else |
ashleymills | 0:ff9ebe0cf0e9 | 2938 | peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; |
ashleymills | 0:ff9ebe0cf0e9 | 2939 | /* update_hs_hash(peer, data, data_length); */ |
ashleymills | 0:ff9ebe0cf0e9 | 2940 | |
ashleymills | 0:ff9ebe0cf0e9 | 2941 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 2942 | |
ashleymills | 0:ff9ebe0cf0e9 | 2943 | case DTLS_HT_CERTIFICATE: |
ashleymills | 0:ff9ebe0cf0e9 | 2944 | DBG("DTLS_HT_CERTIFICATE"); |
ashleymills | 0:ff9ebe0cf0e9 | 2945 | |
ashleymills | 0:ff9ebe0cf0e9 | 2946 | if ((role == DTLS_CLIENT && state != DTLS_STATE_WAIT_SERVERCERTIFICATE) || |
ashleymills | 0:ff9ebe0cf0e9 | 2947 | (role == DTLS_SERVER && state != DTLS_STATE_WAIT_CLIENTCERTIFICATE)) { |
ashleymills | 0:ff9ebe0cf0e9 | 2948 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 2949 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2950 | err = check_server_certificate(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2951 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2952 | WARN("error in check_server_certificate err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 2953 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 2954 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2955 | if (role == DTLS_CLIENT) { |
ashleymills | 0:ff9ebe0cf0e9 | 2956 | peer->state = DTLS_STATE_WAIT_SERVERKEYEXCHANGE; |
ashleymills | 0:ff9ebe0cf0e9 | 2957 | } else if (role == DTLS_SERVER){ |
ashleymills | 0:ff9ebe0cf0e9 | 2958 | peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; |
ashleymills | 0:ff9ebe0cf0e9 | 2959 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2960 | /* update_hs_hash(peer, data, data_length); */ |
ashleymills | 0:ff9ebe0cf0e9 | 2961 | |
ashleymills | 0:ff9ebe0cf0e9 | 2962 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 2963 | |
ashleymills | 0:ff9ebe0cf0e9 | 2964 | case DTLS_HT_SERVER_KEY_EXCHANGE: |
ashleymills | 0:ff9ebe0cf0e9 | 2965 | |
ashleymills | 0:ff9ebe0cf0e9 | 2966 | DBG("DTLS_HT_SERVER_KEY_EXCHANGE"); |
ashleymills | 0:ff9ebe0cf0e9 | 2967 | |
ashleymills | 0:ff9ebe0cf0e9 | 2968 | if (peer->handshake_params.cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 2969 | DBG("TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"); |
ashleymills | 0:ff9ebe0cf0e9 | 2970 | if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { |
ashleymills | 0:ff9ebe0cf0e9 | 2971 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 2972 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2973 | err = check_server_key_exchange_ecdsa(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2974 | } else if (peer->handshake_params.cipher == TLS_PSK_WITH_AES_128_CCM_8) { |
ashleymills | 0:ff9ebe0cf0e9 | 2975 | DBG("TLS_PSK_WITH_AES_128_CCM_8"); |
ashleymills | 0:ff9ebe0cf0e9 | 2976 | if (state != DTLS_STATE_WAIT_SERVERHELLODONE) { |
ashleymills | 0:ff9ebe0cf0e9 | 2977 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 2978 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2979 | err = check_server_key_exchange_psk(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 2980 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 2981 | assert(0); |
ashleymills | 0:ff9ebe0cf0e9 | 2982 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2983 | |
ashleymills | 0:ff9ebe0cf0e9 | 2984 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 2985 | WARN("error in check_server_key_exchange err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 2986 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 2987 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2988 | peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; |
ashleymills | 0:ff9ebe0cf0e9 | 2989 | /* update_hs_hash(peer, data, data_length); */ |
ashleymills | 0:ff9ebe0cf0e9 | 2990 | DBG("Set state to DTLS_STATE_WAIT_SERVERHELLODONE"); |
ashleymills | 0:ff9ebe0cf0e9 | 2991 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 2992 | |
ashleymills | 0:ff9ebe0cf0e9 | 2993 | case DTLS_HT_SERVER_HELLO_DONE: |
ashleymills | 0:ff9ebe0cf0e9 | 2994 | |
ashleymills | 0:ff9ebe0cf0e9 | 2995 | DBG("DTLS_HT_SERVER_HELLO_DONE"); |
ashleymills | 0:ff9ebe0cf0e9 | 2996 | if (state != DTLS_STATE_WAIT_SERVERHELLODONE) { |
ashleymills | 0:ff9ebe0cf0e9 | 2997 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 2998 | } |
ashleymills | 0:ff9ebe0cf0e9 | 2999 | |
ashleymills | 0:ff9ebe0cf0e9 | 3000 | err = check_server_hellodone(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3001 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3002 | WARN("error in check_server_hellodone err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 3003 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3004 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3005 | peer->state = DTLS_STATE_WAIT_SERVERFINISHED; |
ashleymills | 0:ff9ebe0cf0e9 | 3006 | /* update_hs_hash(peer, data, data_length); */ |
ashleymills | 0:ff9ebe0cf0e9 | 3007 | |
ashleymills | 0:ff9ebe0cf0e9 | 3008 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3009 | |
ashleymills | 0:ff9ebe0cf0e9 | 3010 | case DTLS_HT_CERTIFICATE_REQUEST: |
ashleymills | 0:ff9ebe0cf0e9 | 3011 | |
ashleymills | 0:ff9ebe0cf0e9 | 3012 | DBG("DTLS_HT_CERTIFICATE_REQUEST"); |
ashleymills | 0:ff9ebe0cf0e9 | 3013 | if (state != DTLS_STATE_WAIT_SERVERHELLODONE) { |
ashleymills | 0:ff9ebe0cf0e9 | 3014 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 3015 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3016 | |
ashleymills | 0:ff9ebe0cf0e9 | 3017 | err = check_certificate_request(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3018 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3019 | WARN("error in check_certificate_request err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 3020 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3021 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3022 | |
ashleymills | 0:ff9ebe0cf0e9 | 3023 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3024 | |
ashleymills | 0:ff9ebe0cf0e9 | 3025 | case DTLS_HT_FINISHED: |
ashleymills | 0:ff9ebe0cf0e9 | 3026 | /* expect a Finished message from server */ |
ashleymills | 0:ff9ebe0cf0e9 | 3027 | |
ashleymills | 0:ff9ebe0cf0e9 | 3028 | DBG("DTLS_HT_FINISHED"); |
ashleymills | 0:ff9ebe0cf0e9 | 3029 | if ((role == DTLS_CLIENT && state != DTLS_STATE_WAIT_SERVERFINISHED) || |
ashleymills | 0:ff9ebe0cf0e9 | 3030 | (role == DTLS_SERVER && state != DTLS_STATE_WAIT_FINISHED)) { |
ashleymills | 0:ff9ebe0cf0e9 | 3031 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 3032 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3033 | |
ashleymills | 0:ff9ebe0cf0e9 | 3034 | err = check_finished(ctx, peer, record_header, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3035 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3036 | WARN("error in check_finished err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 3037 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3038 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3039 | if (role == DTLS_SERVER) { |
ashleymills | 0:ff9ebe0cf0e9 | 3040 | /* send ServerFinished */ |
ashleymills | 0:ff9ebe0cf0e9 | 3041 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3042 | |
ashleymills | 0:ff9ebe0cf0e9 | 3043 | if (dtls_send_finished(ctx, peer, PRF_LABEL(server), |
ashleymills | 0:ff9ebe0cf0e9 | 3044 | PRF_LABEL_SIZE(server)) > 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3045 | peer->state = DTLS_STATE_CONNECTED; |
ashleymills | 0:ff9ebe0cf0e9 | 3046 | } else if (role == DTLS_CLIENT) { |
ashleymills | 0:ff9ebe0cf0e9 | 3047 | WARN("sending server Finished failed"); |
ashleymills | 0:ff9ebe0cf0e9 | 3048 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3049 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 3050 | peer->state = DTLS_STATE_CONNECTED; |
ashleymills | 0:ff9ebe0cf0e9 | 3051 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3052 | |
ashleymills | 0:ff9ebe0cf0e9 | 3053 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3054 | |
ashleymills | 0:ff9ebe0cf0e9 | 3055 | /************************************************************************ |
ashleymills | 0:ff9ebe0cf0e9 | 3056 | * Server states |
ashleymills | 0:ff9ebe0cf0e9 | 3057 | ************************************************************************/ |
ashleymills | 0:ff9ebe0cf0e9 | 3058 | |
ashleymills | 0:ff9ebe0cf0e9 | 3059 | case DTLS_HT_CLIENT_KEY_EXCHANGE: |
ashleymills | 0:ff9ebe0cf0e9 | 3060 | /* handle ClientHello, update msg and msglen and goto next if not finished */ |
ashleymills | 0:ff9ebe0cf0e9 | 3061 | |
ashleymills | 0:ff9ebe0cf0e9 | 3062 | DBG("DTLS_HT_CLIENT_KEY_EXCHANGE"); |
ashleymills | 0:ff9ebe0cf0e9 | 3063 | |
ashleymills | 0:ff9ebe0cf0e9 | 3064 | if (state != DTLS_STATE_WAIT_CLIENTKEYEXCHANGE) { |
ashleymills | 0:ff9ebe0cf0e9 | 3065 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 3066 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3067 | |
ashleymills | 0:ff9ebe0cf0e9 | 3068 | err = check_client_keyexchange(ctx, &peer->handshake_params, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3069 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3070 | WARN("error in check_client_keyexchange err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 3071 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3072 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3073 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3074 | |
ashleymills | 0:ff9ebe0cf0e9 | 3075 | if (peer->handshake_params.cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 && |
ashleymills | 0:ff9ebe0cf0e9 | 3076 | ctx && ctx->h && ctx->h->verify_ecdsa_key) |
ashleymills | 0:ff9ebe0cf0e9 | 3077 | peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; |
ashleymills | 0:ff9ebe0cf0e9 | 3078 | else |
ashleymills | 0:ff9ebe0cf0e9 | 3079 | peer->state = DTLS_STATE_WAIT_CLIENTCHANGECIPHERSPEC; |
ashleymills | 0:ff9ebe0cf0e9 | 3080 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3081 | |
ashleymills | 0:ff9ebe0cf0e9 | 3082 | case DTLS_HT_CERTIFICATE_VERIFY: |
ashleymills | 0:ff9ebe0cf0e9 | 3083 | |
ashleymills | 0:ff9ebe0cf0e9 | 3084 | DBG("DTLS_HT_CERTIFICATE_VERIFY"); |
ashleymills | 0:ff9ebe0cf0e9 | 3085 | if (state != DTLS_STATE_WAIT_CERTIFICATEVERIFY) { |
ashleymills | 0:ff9ebe0cf0e9 | 3086 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 3087 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3088 | |
ashleymills | 0:ff9ebe0cf0e9 | 3089 | err = check_client_certificate_verify(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3090 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3091 | WARN("error in check_client_certificate_verify err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 3092 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3093 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3094 | |
ashleymills | 0:ff9ebe0cf0e9 | 3095 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3096 | peer->state = DTLS_STATE_WAIT_CLIENTCHANGECIPHERSPEC; |
ashleymills | 0:ff9ebe0cf0e9 | 3097 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3098 | |
ashleymills | 0:ff9ebe0cf0e9 | 3099 | case DTLS_HT_CLIENT_HELLO: |
ashleymills | 0:ff9ebe0cf0e9 | 3100 | /* At this point, we have a good relationship with this peer. This |
ashleymills | 0:ff9ebe0cf0e9 | 3101 | * state is left for re-negotiation of key material. */ |
ashleymills | 0:ff9ebe0cf0e9 | 3102 | |
ashleymills | 0:ff9ebe0cf0e9 | 3103 | DBG("DTLS_HT_CLIENT_HELLO"); |
ashleymills | 0:ff9ebe0cf0e9 | 3104 | if ((peer && state != DTLS_STATE_CONNECTED) || |
ashleymills | 0:ff9ebe0cf0e9 | 3105 | (!peer && state != DTLS_STATE_WAIT_CLIENTHELLO)) { |
ashleymills | 0:ff9ebe0cf0e9 | 3106 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 3107 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3108 | |
ashleymills | 0:ff9ebe0cf0e9 | 3109 | /* When no DTLS state exists for this peer, we only allow a |
ashleymills | 0:ff9ebe0cf0e9 | 3110 | Client Hello message with |
ashleymills | 0:ff9ebe0cf0e9 | 3111 | |
ashleymills | 0:ff9ebe0cf0e9 | 3112 | a) a valid cookie, or |
ashleymills | 0:ff9ebe0cf0e9 | 3113 | b) no cookie. |
ashleymills | 0:ff9ebe0cf0e9 | 3114 | |
ashleymills | 0:ff9ebe0cf0e9 | 3115 | Anything else will be rejected. Fragementation is not allowed |
ashleymills | 0:ff9ebe0cf0e9 | 3116 | here as it would require peer state as well. |
ashleymills | 0:ff9ebe0cf0e9 | 3117 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 3118 | err = dtls_verify_peer(ctx, peer, session, record_header, data, |
ashleymills | 0:ff9ebe0cf0e9 | 3119 | data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3120 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3121 | WARN("error in dtls_verify_peer err: %i", err); |
ashleymills | 0:ff9ebe0cf0e9 | 3122 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3123 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3124 | |
ashleymills | 0:ff9ebe0cf0e9 | 3125 | if (err > 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3126 | DBG("server hello verify was sent"); |
ashleymills | 0:ff9ebe0cf0e9 | 3127 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3128 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3129 | |
ashleymills | 0:ff9ebe0cf0e9 | 3130 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3131 | |
ashleymills | 0:ff9ebe0cf0e9 | 3132 | /* msg contains a Client Hello with a valid cookie, so we can |
ashleymills | 0:ff9ebe0cf0e9 | 3133 | * safely create the server state machine and continue with |
ashleymills | 0:ff9ebe0cf0e9 | 3134 | * the handshake. */ |
ashleymills | 0:ff9ebe0cf0e9 | 3135 | peer = dtls_new_peer(session); |
ashleymills | 0:ff9ebe0cf0e9 | 3136 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3137 | DBG("cannot create peer"); |
ashleymills | 0:ff9ebe0cf0e9 | 3138 | return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 3139 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3140 | peer->role = DTLS_SERVER; |
ashleymills | 0:ff9ebe0cf0e9 | 3141 | |
ashleymills | 0:ff9ebe0cf0e9 | 3142 | /* Initialize record sequence number to 1 for new peers. The first |
ashleymills | 0:ff9ebe0cf0e9 | 3143 | * record with sequence number 0 is a stateless Hello Verify Request. |
ashleymills | 0:ff9ebe0cf0e9 | 3144 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 3145 | peer->rseq[5] = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 3146 | dtls_add_peer(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3147 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3148 | |
ashleymills | 0:ff9ebe0cf0e9 | 3149 | clear_hs_hash(peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3150 | |
ashleymills | 0:ff9ebe0cf0e9 | 3151 | /* First negotiation step: check for PSK |
ashleymills | 0:ff9ebe0cf0e9 | 3152 | * |
ashleymills | 0:ff9ebe0cf0e9 | 3153 | * Note that we already have checked that msg is a Handshake |
ashleymills | 0:ff9ebe0cf0e9 | 3154 | * message containing a ClientHello. dtls_get_cipher() therefore |
ashleymills | 0:ff9ebe0cf0e9 | 3155 | * does not check again. |
ashleymills | 0:ff9ebe0cf0e9 | 3156 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 3157 | err = dtls_update_parameters(ctx, peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3158 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3159 | |
ashleymills | 0:ff9ebe0cf0e9 | 3160 | WARN("error updating security parameters"); |
ashleymills | 0:ff9ebe0cf0e9 | 3161 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3162 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3163 | |
ashleymills | 0:ff9ebe0cf0e9 | 3164 | /* update finish MAC */ |
ashleymills | 0:ff9ebe0cf0e9 | 3165 | update_hs_hash(peer, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3166 | |
ashleymills | 0:ff9ebe0cf0e9 | 3167 | err = dtls_send_server_hello_msgs(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3168 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3169 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3170 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3171 | if (peer->handshake_params.cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 && |
ashleymills | 0:ff9ebe0cf0e9 | 3172 | ctx && ctx->h && ctx->h->verify_ecdsa_key) |
ashleymills | 0:ff9ebe0cf0e9 | 3173 | peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; |
ashleymills | 0:ff9ebe0cf0e9 | 3174 | else |
ashleymills | 0:ff9ebe0cf0e9 | 3175 | peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; |
ashleymills | 0:ff9ebe0cf0e9 | 3176 | |
ashleymills | 0:ff9ebe0cf0e9 | 3177 | /* after sending the ServerHelloDone, we expect the |
ashleymills | 0:ff9ebe0cf0e9 | 3178 | * ClientKeyExchange (possibly containing the PSK id), |
ashleymills | 0:ff9ebe0cf0e9 | 3179 | * followed by a ChangeCipherSpec and an encrypted Finished. |
ashleymills | 0:ff9ebe0cf0e9 | 3180 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 3181 | |
ashleymills | 0:ff9ebe0cf0e9 | 3182 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3183 | |
ashleymills | 0:ff9ebe0cf0e9 | 3184 | case DTLS_HT_HELLO_REQUEST: |
ashleymills | 0:ff9ebe0cf0e9 | 3185 | |
ashleymills | 0:ff9ebe0cf0e9 | 3186 | DBG("DTLS_HT_HELLO_REQUEST"); |
ashleymills | 0:ff9ebe0cf0e9 | 3187 | if (state != DTLS_STATE_CONNECTED) { |
ashleymills | 0:ff9ebe0cf0e9 | 3188 | /* we should just ignore such packages when in handshake */ |
ashleymills | 0:ff9ebe0cf0e9 | 3189 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 3190 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3191 | |
ashleymills | 0:ff9ebe0cf0e9 | 3192 | /* send ClientHello with empty Cookie */ |
ashleymills | 0:ff9ebe0cf0e9 | 3193 | err = dtls_send_client_hello(ctx, peer, NULL, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 3194 | if (err < 0) |
ashleymills | 0:ff9ebe0cf0e9 | 3195 | WARN("cannot send ClientHello"); |
ashleymills | 0:ff9ebe0cf0e9 | 3196 | else |
ashleymills | 0:ff9ebe0cf0e9 | 3197 | peer->state = DTLS_STATE_CLIENTHELLO; |
ashleymills | 0:ff9ebe0cf0e9 | 3198 | |
ashleymills | 0:ff9ebe0cf0e9 | 3199 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3200 | default: |
ashleymills | 0:ff9ebe0cf0e9 | 3201 | DBG("unhandled message %d", data[0]); |
ashleymills | 0:ff9ebe0cf0e9 | 3202 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 3203 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3204 | |
ashleymills | 0:ff9ebe0cf0e9 | 3205 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3206 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3207 | |
ashleymills | 0:ff9ebe0cf0e9 | 3208 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 3209 | handle_ccs(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 3210 | uint8 *record_header, uint8 *data, size_t data_length) |
ashleymills | 0:ff9ebe0cf0e9 | 3211 | { |
ashleymills | 0:ff9ebe0cf0e9 | 3212 | int err; |
ashleymills | 0:ff9ebe0cf0e9 | 3213 | dtls_handshake_parameters_t *handshake = &peer->handshake_params; |
ashleymills | 0:ff9ebe0cf0e9 | 3214 | dtls_security_parameters_t *security = &peer->security_params; |
ashleymills | 0:ff9ebe0cf0e9 | 3215 | |
ashleymills | 0:ff9ebe0cf0e9 | 3216 | /* A CCS message is handled after a KeyExchange message was |
ashleymills | 0:ff9ebe0cf0e9 | 3217 | * received from the client. When security parameters have been |
ashleymills | 0:ff9ebe0cf0e9 | 3218 | * updated successfully and a ChangeCipherSpec message was sent |
ashleymills | 0:ff9ebe0cf0e9 | 3219 | * by ourself, the security context is switched and the record |
ashleymills | 0:ff9ebe0cf0e9 | 3220 | * sequence number is reset. */ |
ashleymills | 0:ff9ebe0cf0e9 | 3221 | |
ashleymills | 0:ff9ebe0cf0e9 | 3222 | if (!peer || peer->state != DTLS_STATE_WAIT_CLIENTCHANGECIPHERSPEC) { |
ashleymills | 0:ff9ebe0cf0e9 | 3223 | WARN("expected ChangeCipherSpec during handshake"); |
ashleymills | 0:ff9ebe0cf0e9 | 3224 | return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 3225 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3226 | |
ashleymills | 0:ff9ebe0cf0e9 | 3227 | if (data_length < 1 || data[0] != 1) |
ashleymills | 0:ff9ebe0cf0e9 | 3228 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 3229 | |
ashleymills | 0:ff9ebe0cf0e9 | 3230 | /* send change cipher spec message and switch to new configuration */ |
ashleymills | 0:ff9ebe0cf0e9 | 3231 | err = dtls_send_ccs(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3232 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3233 | WARN("cannot send CCS message"); |
ashleymills | 0:ff9ebe0cf0e9 | 3234 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3235 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3236 | |
ashleymills | 0:ff9ebe0cf0e9 | 3237 | err = calculate_key_block(ctx, handshake, security, |
ashleymills | 0:ff9ebe0cf0e9 | 3238 | &peer->session); |
ashleymills | 0:ff9ebe0cf0e9 | 3239 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3240 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3241 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3242 | |
ashleymills | 0:ff9ebe0cf0e9 | 3243 | err = init_cipher(handshake, security, peer->role); |
ashleymills | 0:ff9ebe0cf0e9 | 3244 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3245 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3246 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3247 | |
ashleymills | 0:ff9ebe0cf0e9 | 3248 | inc_uint(uint16, peer->epoch); |
ashleymills | 0:ff9ebe0cf0e9 | 3249 | memset(peer->rseq, 0, sizeof(peer->rseq)); |
ashleymills | 0:ff9ebe0cf0e9 | 3250 | |
ashleymills | 0:ff9ebe0cf0e9 | 3251 | peer->state = DTLS_STATE_WAIT_FINISHED; |
ashleymills | 0:ff9ebe0cf0e9 | 3252 | |
ashleymills | 0:ff9ebe0cf0e9 | 3253 | dtls_debug_keyblock(security); |
ashleymills | 0:ff9ebe0cf0e9 | 3254 | |
ashleymills | 0:ff9ebe0cf0e9 | 3255 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 3256 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3257 | |
ashleymills | 0:ff9ebe0cf0e9 | 3258 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 3259 | * Handles incoming Alert messages. This function returns \c 1 if the |
ashleymills | 0:ff9ebe0cf0e9 | 3260 | * connection should be closed and the peer is to be invalidated. |
ashleymills | 0:ff9ebe0cf0e9 | 3261 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 3262 | static int |
ashleymills | 0:ff9ebe0cf0e9 | 3263 | handle_alert(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 3264 | uint8 *record_header, uint8 *data, size_t data_length) { |
ashleymills | 0:ff9ebe0cf0e9 | 3265 | int free_peer = 0; /* indicates whether to free peer */ |
ashleymills | 0:ff9ebe0cf0e9 | 3266 | |
ashleymills | 0:ff9ebe0cf0e9 | 3267 | if (data_length < 2) |
ashleymills | 0:ff9ebe0cf0e9 | 3268 | return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 3269 | |
ashleymills | 0:ff9ebe0cf0e9 | 3270 | INFO("** Alert: level %d, description %d", data[0], data[1]); |
ashleymills | 0:ff9ebe0cf0e9 | 3271 | |
ashleymills | 0:ff9ebe0cf0e9 | 3272 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3273 | WARN("got an alert for an unknown peer, we probably already removed it, ignore it"); |
ashleymills | 0:ff9ebe0cf0e9 | 3274 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 3275 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3276 | |
ashleymills | 0:ff9ebe0cf0e9 | 3277 | /* The peer object is invalidated for FATAL alerts and close |
ashleymills | 0:ff9ebe0cf0e9 | 3278 | * notifies. This is done in two steps.: First, remove the object |
ashleymills | 0:ff9ebe0cf0e9 | 3279 | * from our list of peers. After that, the event handler callback is |
ashleymills | 0:ff9ebe0cf0e9 | 3280 | * invoked with the still existing peer object. Finally, the storage |
ashleymills | 0:ff9ebe0cf0e9 | 3281 | * used by peer is released. |
ashleymills | 0:ff9ebe0cf0e9 | 3282 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 3283 | if (data[0] == DTLS_ALERT_LEVEL_FATAL || data[1] == DTLS_ALERT_CLOSE_NOTIFY) { |
ashleymills | 0:ff9ebe0cf0e9 | 3284 | DBG("%d invalidate peer", data[1]); |
ashleymills | 0:ff9ebe0cf0e9 | 3285 | |
ashleymills | 0:ff9ebe0cf0e9 | 3286 | #ifndef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 3287 | HASH_DEL_PEER(ctx->peers, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3288 | #else /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 3289 | list_remove(ctx->peers, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3290 | |
ashleymills | 0:ff9ebe0cf0e9 | 3291 | #ifndef NDEBUG |
ashleymills | 0:ff9ebe0cf0e9 | 3292 | PRINTF("removed peer ["); |
ashleymills | 0:ff9ebe0cf0e9 | 3293 | PRINT6ADDR(&peer->session.addr); |
ashleymills | 0:ff9ebe0cf0e9 | 3294 | PRINTF("]:%d", uip_ntohs(peer->session.port)); |
ashleymills | 0:ff9ebe0cf0e9 | 3295 | #endif |
ashleymills | 0:ff9ebe0cf0e9 | 3296 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 3297 | |
ashleymills | 0:ff9ebe0cf0e9 | 3298 | free_peer = 1; |
ashleymills | 0:ff9ebe0cf0e9 | 3299 | |
ashleymills | 0:ff9ebe0cf0e9 | 3300 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3301 | |
ashleymills | 0:ff9ebe0cf0e9 | 3302 | (void)CALL(ctx, event, &peer->session, |
ashleymills | 0:ff9ebe0cf0e9 | 3303 | (dtls_alert_level_t)data[0], (unsigned short)data[1]); |
ashleymills | 0:ff9ebe0cf0e9 | 3304 | switch (data[1]) { |
ashleymills | 0:ff9ebe0cf0e9 | 3305 | case DTLS_ALERT_CLOSE_NOTIFY: |
ashleymills | 0:ff9ebe0cf0e9 | 3306 | /* If state is DTLS_STATE_CLOSING, we have already sent a |
ashleymills | 0:ff9ebe0cf0e9 | 3307 | * close_notify so, do not send that again. */ |
ashleymills | 0:ff9ebe0cf0e9 | 3308 | if (peer->state != DTLS_STATE_CLOSING) { |
ashleymills | 0:ff9ebe0cf0e9 | 3309 | peer->state = DTLS_STATE_CLOSING; |
ashleymills | 0:ff9ebe0cf0e9 | 3310 | dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_CLOSE_NOTIFY); |
ashleymills | 0:ff9ebe0cf0e9 | 3311 | } else |
ashleymills | 0:ff9ebe0cf0e9 | 3312 | peer->state = DTLS_STATE_CLOSED; |
ashleymills | 0:ff9ebe0cf0e9 | 3313 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3314 | default: |
ashleymills | 0:ff9ebe0cf0e9 | 3315 | ; |
ashleymills | 0:ff9ebe0cf0e9 | 3316 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3317 | |
ashleymills | 0:ff9ebe0cf0e9 | 3318 | if (free_peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3319 | dtls_stop_retransmission(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3320 | dtls_destory_peer(ctx, peer, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 3321 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3322 | |
ashleymills | 0:ff9ebe0cf0e9 | 3323 | return free_peer; |
ashleymills | 0:ff9ebe0cf0e9 | 3324 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3325 | |
ashleymills | 0:ff9ebe0cf0e9 | 3326 | static int dtls_alert_send_from_err(dtls_context_t *ctx, dtls_peer_t *peer, |
ashleymills | 0:ff9ebe0cf0e9 | 3327 | session_t *session, int err) |
ashleymills | 0:ff9ebe0cf0e9 | 3328 | { |
ashleymills | 0:ff9ebe0cf0e9 | 3329 | int level; |
ashleymills | 0:ff9ebe0cf0e9 | 3330 | int desc; |
ashleymills | 0:ff9ebe0cf0e9 | 3331 | |
ashleymills | 0:ff9ebe0cf0e9 | 3332 | if (err < -(1 << 8) && err > -(3 << 8)) { |
ashleymills | 0:ff9ebe0cf0e9 | 3333 | level = ((-err) & 0xff00) >> 8; |
ashleymills | 0:ff9ebe0cf0e9 | 3334 | desc = (-err) & 0xff; |
ashleymills | 0:ff9ebe0cf0e9 | 3335 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3336 | peer = dtls_get_peer(ctx, session); |
ashleymills | 0:ff9ebe0cf0e9 | 3337 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3338 | if (peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3339 | return dtls_alert(ctx, peer, level, desc); |
ashleymills | 0:ff9ebe0cf0e9 | 3340 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3341 | } else if (err == -1) { |
ashleymills | 0:ff9ebe0cf0e9 | 3342 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3343 | peer = dtls_get_peer(ctx, session); |
ashleymills | 0:ff9ebe0cf0e9 | 3344 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3345 | if (peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3346 | return dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_INTERNAL_ERROR); |
ashleymills | 0:ff9ebe0cf0e9 | 3347 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3348 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3349 | return -1; |
ashleymills | 0:ff9ebe0cf0e9 | 3350 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3351 | |
ashleymills | 0:ff9ebe0cf0e9 | 3352 | /** |
ashleymills | 0:ff9ebe0cf0e9 | 3353 | * Handles incoming data as DTLS message from given peer. |
ashleymills | 0:ff9ebe0cf0e9 | 3354 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 3355 | int |
ashleymills | 0:ff9ebe0cf0e9 | 3356 | dtls_handle_message(dtls_context_t *ctx, |
ashleymills | 0:ff9ebe0cf0e9 | 3357 | session_t *session, |
ashleymills | 0:ff9ebe0cf0e9 | 3358 | uint8 *msg, int msglen) { |
ashleymills | 0:ff9ebe0cf0e9 | 3359 | dtls_peer_t *peer = NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 3360 | unsigned int rlen; /* record length */ |
ashleymills | 0:ff9ebe0cf0e9 | 3361 | uint8 *data; /* (decrypted) payload */ |
ashleymills | 0:ff9ebe0cf0e9 | 3362 | size_t data_length; /* length of decrypted payload |
ashleymills | 0:ff9ebe0cf0e9 | 3363 | (without MAC and padding) */ |
ashleymills | 0:ff9ebe0cf0e9 | 3364 | int err; |
ashleymills | 0:ff9ebe0cf0e9 | 3365 | |
ashleymills | 0:ff9ebe0cf0e9 | 3366 | /* check if we have DTLS state for addr/port/ifindex */ |
ashleymills | 0:ff9ebe0cf0e9 | 3367 | peer = dtls_get_peer(ctx, session); |
ashleymills | 0:ff9ebe0cf0e9 | 3368 | |
ashleymills | 0:ff9ebe0cf0e9 | 3369 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3370 | DBG("dtls_handle_message: PEER NOT FOUND"); |
ashleymills | 0:ff9ebe0cf0e9 | 3371 | dtls_dsrv_log_addr(LOG_DEBUG, "peer addr", session); |
ashleymills | 0:ff9ebe0cf0e9 | 3372 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 3373 | DBG("dtls_handle_message: FOUND PEER"); |
ashleymills | 0:ff9ebe0cf0e9 | 3374 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3375 | |
ashleymills | 0:ff9ebe0cf0e9 | 3376 | /* FIXME: check sequence number of record and drop message if the |
ashleymills | 0:ff9ebe0cf0e9 | 3377 | * number is not exactly the last number that we have responded to + 1. |
ashleymills | 0:ff9ebe0cf0e9 | 3378 | * Otherwise, stop retransmissions for this specific peer and |
ashleymills | 0:ff9ebe0cf0e9 | 3379 | * continue processing. */ |
ashleymills | 0:ff9ebe0cf0e9 | 3380 | if (peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3381 | dtls_stop_retransmission(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3382 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3383 | |
ashleymills | 0:ff9ebe0cf0e9 | 3384 | while ((rlen = is_record(msg,msglen))) { |
ashleymills | 0:ff9ebe0cf0e9 | 3385 | dtls_peer_type role; |
ashleymills | 0:ff9ebe0cf0e9 | 3386 | dtls_state_t state; |
ashleymills | 0:ff9ebe0cf0e9 | 3387 | |
ashleymills | 0:ff9ebe0cf0e9 | 3388 | DBG("got packet %d (%d bytes)", msg[0], rlen); |
ashleymills | 0:ff9ebe0cf0e9 | 3389 | if (peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3390 | /* skip packet if it is from a different epoch */ |
ashleymills | 0:ff9ebe0cf0e9 | 3391 | if (memcmp(DTLS_RECORD_HEADER(msg)->epoch, |
ashleymills | 0:ff9ebe0cf0e9 | 3392 | peer->epoch, sizeof(uint16)) != 0) |
ashleymills | 0:ff9ebe0cf0e9 | 3393 | goto next; |
ashleymills | 0:ff9ebe0cf0e9 | 3394 | |
ashleymills | 0:ff9ebe0cf0e9 | 3395 | if (!decrypt_verify(peer, msg, rlen, &data, &data_length)) { |
ashleymills | 0:ff9ebe0cf0e9 | 3396 | INFO("decrypt_verify() failed"); |
ashleymills | 0:ff9ebe0cf0e9 | 3397 | goto next; |
ashleymills | 0:ff9ebe0cf0e9 | 3398 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3399 | role = peer->role; |
ashleymills | 0:ff9ebe0cf0e9 | 3400 | state = peer->state; |
ashleymills | 0:ff9ebe0cf0e9 | 3401 | } else { |
ashleymills | 0:ff9ebe0cf0e9 | 3402 | /* is_record() ensures that msg contains at least a record header */ |
ashleymills | 0:ff9ebe0cf0e9 | 3403 | data = msg + DTLS_RH_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 3404 | data_length = rlen - DTLS_RH_LENGTH; |
ashleymills | 0:ff9ebe0cf0e9 | 3405 | state = DTLS_STATE_WAIT_CLIENTHELLO; |
ashleymills | 0:ff9ebe0cf0e9 | 3406 | role = DTLS_SERVER; |
ashleymills | 0:ff9ebe0cf0e9 | 3407 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3408 | |
ashleymills | 0:ff9ebe0cf0e9 | 3409 | dtls_dsrv_hexdump_log(LOG_DEBUG, "receive header", msg, |
ashleymills | 0:ff9ebe0cf0e9 | 3410 | sizeof(dtls_record_header_t), 1); |
ashleymills | 0:ff9ebe0cf0e9 | 3411 | dtls_dsrv_hexdump_log(LOG_DEBUG, "receive unencrypted", data, data_length, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 3412 | |
ashleymills | 0:ff9ebe0cf0e9 | 3413 | /* Handle received record according to the first byte of the |
ashleymills | 0:ff9ebe0cf0e9 | 3414 | * message, i.e. the subprotocol. We currently do not support |
ashleymills | 0:ff9ebe0cf0e9 | 3415 | * combining multiple fragments of one type into a single |
ashleymills | 0:ff9ebe0cf0e9 | 3416 | * record. */ |
ashleymills | 0:ff9ebe0cf0e9 | 3417 | |
ashleymills | 0:ff9ebe0cf0e9 | 3418 | switch (msg[0]) { |
ashleymills | 0:ff9ebe0cf0e9 | 3419 | |
ashleymills | 0:ff9ebe0cf0e9 | 3420 | case DTLS_CT_CHANGE_CIPHER_SPEC: |
ashleymills | 0:ff9ebe0cf0e9 | 3421 | err = handle_ccs(ctx, peer, msg, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3422 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3423 | WARN("error while handling ChangeCipherSpec package"); |
ashleymills | 0:ff9ebe0cf0e9 | 3424 | dtls_alert_send_from_err(ctx, peer, session, err); |
ashleymills | 0:ff9ebe0cf0e9 | 3425 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3426 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3427 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3428 | |
ashleymills | 0:ff9ebe0cf0e9 | 3429 | case DTLS_CT_ALERT: |
ashleymills | 0:ff9ebe0cf0e9 | 3430 | err = handle_alert(ctx, peer, msg, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3431 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3432 | WARN("received wrong package"); |
ashleymills | 0:ff9ebe0cf0e9 | 3433 | /* handle alert has invalidated peer */ |
ashleymills | 0:ff9ebe0cf0e9 | 3434 | peer = NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 3435 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3436 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3437 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3438 | |
ashleymills | 0:ff9ebe0cf0e9 | 3439 | case DTLS_CT_HANDSHAKE: |
ashleymills | 0:ff9ebe0cf0e9 | 3440 | err = handle_handshake(ctx, peer, session, role, state, msg, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3441 | DBG("Returned from handle_handshake: %d",err); |
ashleymills | 0:ff9ebe0cf0e9 | 3442 | if (err < 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3443 | WARN("error while handling handshake package"); |
ashleymills | 0:ff9ebe0cf0e9 | 3444 | dtls_alert_send_from_err(ctx, peer, session, err); |
ashleymills | 0:ff9ebe0cf0e9 | 3445 | return err; |
ashleymills | 0:ff9ebe0cf0e9 | 3446 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3447 | if (peer && peer->state == DTLS_STATE_CONNECTED) { |
ashleymills | 0:ff9ebe0cf0e9 | 3448 | DBG("DTLS_STATE_CONNECTED"); |
ashleymills | 0:ff9ebe0cf0e9 | 3449 | /* stop retransmissions */ |
ashleymills | 0:ff9ebe0cf0e9 | 3450 | dtls_stop_retransmission(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3451 | CALL(ctx, event, &peer->session, 0, DTLS_EVENT_CONNECTED); |
ashleymills | 0:ff9ebe0cf0e9 | 3452 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3453 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3454 | |
ashleymills | 0:ff9ebe0cf0e9 | 3455 | case DTLS_CT_APPLICATION_DATA: |
ashleymills | 0:ff9ebe0cf0e9 | 3456 | INFO("** application data:"); |
ashleymills | 0:ff9ebe0cf0e9 | 3457 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3458 | WARN("no peer available, send an alert"); |
ashleymills | 0:ff9ebe0cf0e9 | 3459 | dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_UNEXPECTED_MESSAGE); |
ashleymills | 0:ff9ebe0cf0e9 | 3460 | return -1; |
ashleymills | 0:ff9ebe0cf0e9 | 3461 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3462 | CALL(ctx, read, &peer->session, data, data_length); |
ashleymills | 0:ff9ebe0cf0e9 | 3463 | break; |
ashleymills | 0:ff9ebe0cf0e9 | 3464 | default: |
ashleymills | 0:ff9ebe0cf0e9 | 3465 | INFO("dropped unknown message of type %d",msg[0]); |
ashleymills | 0:ff9ebe0cf0e9 | 3466 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3467 | |
ashleymills | 0:ff9ebe0cf0e9 | 3468 | next: |
ashleymills | 0:ff9ebe0cf0e9 | 3469 | /* advance msg by length of ciphertext */ |
ashleymills | 0:ff9ebe0cf0e9 | 3470 | msg += rlen; |
ashleymills | 0:ff9ebe0cf0e9 | 3471 | msglen -= rlen; |
ashleymills | 0:ff9ebe0cf0e9 | 3472 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3473 | DBG("Leaving dtls_handle_message"); |
ashleymills | 0:ff9ebe0cf0e9 | 3474 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 3475 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3476 | |
ashleymills | 0:ff9ebe0cf0e9 | 3477 | dtls_context_t * |
ashleymills | 0:ff9ebe0cf0e9 | 3478 | dtls_new_context(void *app_data) { |
ashleymills | 0:ff9ebe0cf0e9 | 3479 | dtls_context_t *c; |
ashleymills | 0:ff9ebe0cf0e9 | 3480 | dtls_tick_t now; |
ashleymills | 0:ff9ebe0cf0e9 | 3481 | #ifndef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 3482 | FILE *urandom = fopen("/dev/urandom", "r"); |
ashleymills | 0:ff9ebe0cf0e9 | 3483 | unsigned char buf[sizeof(unsigned long)]; |
ashleymills | 0:ff9ebe0cf0e9 | 3484 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 3485 | |
ashleymills | 0:ff9ebe0cf0e9 | 3486 | dtls_ticks(&now); |
ashleymills | 0:ff9ebe0cf0e9 | 3487 | #ifdef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 3488 | /* FIXME: need something better to init PRNG here */ |
ashleymills | 0:ff9ebe0cf0e9 | 3489 | prng_init(now); |
ashleymills | 0:ff9ebe0cf0e9 | 3490 | #else /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 3491 | /* |
ashleymills | 0:ff9ebe0cf0e9 | 3492 | if (!urandom) { |
ashleymills | 0:ff9ebe0cf0e9 | 3493 | DBG("cannot initialize PRNG"); |
ashleymills | 0:ff9ebe0cf0e9 | 3494 | return NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 3495 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3496 | |
ashleymills | 0:ff9ebe0cf0e9 | 3497 | if (fread(buf, 1, sizeof(buf), urandom) != sizeof(buf)) { |
ashleymills | 0:ff9ebe0cf0e9 | 3498 | dsrv_log(LOG_EMERG, "cannot initialize PRNG"); |
ashleymills | 0:ff9ebe0cf0e9 | 3499 | return NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 3500 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3501 | |
ashleymills | 0:ff9ebe0cf0e9 | 3502 | fclose(urandom); |
ashleymills | 0:ff9ebe0cf0e9 | 3503 | prng_init((unsigned long)*buf); |
ashleymills | 0:ff9ebe0cf0e9 | 3504 | */ |
ashleymills | 0:ff9ebe0cf0e9 | 3505 | // just randomly flip some bits |
ashleymills | 0:ff9ebe0cf0e9 | 3506 | unsigned long mask = 0x0000; |
ashleymills | 0:ff9ebe0cf0e9 | 3507 | for(int i=0; i<sizeof(buf); i++) { |
ashleymills | 0:ff9ebe0cf0e9 | 3508 | // XXX need to flip some bits |
ashleymills | 0:ff9ebe0cf0e9 | 3509 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3510 | prng_init((unsigned long)*buf); |
ashleymills | 0:ff9ebe0cf0e9 | 3511 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 3512 | |
ashleymills | 0:ff9ebe0cf0e9 | 3513 | c = &the_dtls_context; |
ashleymills | 0:ff9ebe0cf0e9 | 3514 | |
ashleymills | 0:ff9ebe0cf0e9 | 3515 | memset(c, 0, sizeof(dtls_context_t)); |
ashleymills | 0:ff9ebe0cf0e9 | 3516 | c->app = app_data; |
ashleymills | 0:ff9ebe0cf0e9 | 3517 | |
ashleymills | 0:ff9ebe0cf0e9 | 3518 | LIST_STRUCT_INIT(c, sendqueue); |
ashleymills | 0:ff9ebe0cf0e9 | 3519 | |
ashleymills | 0:ff9ebe0cf0e9 | 3520 | #ifdef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 3521 | LIST_STRUCT_INIT(c, peers); |
ashleymills | 0:ff9ebe0cf0e9 | 3522 | /* LIST_STRUCT_INIT(c, key_store); */ |
ashleymills | 0:ff9ebe0cf0e9 | 3523 | |
ashleymills | 0:ff9ebe0cf0e9 | 3524 | process_start(&dtls_retransmit_process, (char *)c); |
ashleymills | 0:ff9ebe0cf0e9 | 3525 | PROCESS_CONTEXT_BEGIN(&dtls_retransmit_process); |
ashleymills | 0:ff9ebe0cf0e9 | 3526 | /* the retransmit timer must be initialized to some large value */ |
ashleymills | 0:ff9ebe0cf0e9 | 3527 | etimer_set(&c->retransmit_timer, 0xFFFF); |
ashleymills | 0:ff9ebe0cf0e9 | 3528 | PROCESS_CONTEXT_END(&coap_retransmit_process); |
ashleymills | 0:ff9ebe0cf0e9 | 3529 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 3530 | |
ashleymills | 0:ff9ebe0cf0e9 | 3531 | if (prng(c->cookie_secret, DTLS_COOKIE_SECRET_LENGTH)) |
ashleymills | 0:ff9ebe0cf0e9 | 3532 | c->cookie_secret_age = now; |
ashleymills | 0:ff9ebe0cf0e9 | 3533 | else |
ashleymills | 0:ff9ebe0cf0e9 | 3534 | goto error; |
ashleymills | 0:ff9ebe0cf0e9 | 3535 | |
ashleymills | 0:ff9ebe0cf0e9 | 3536 | return c; |
ashleymills | 0:ff9ebe0cf0e9 | 3537 | |
ashleymills | 0:ff9ebe0cf0e9 | 3538 | error: |
ashleymills | 0:ff9ebe0cf0e9 | 3539 | DBG("cannot create DTLS context"); |
ashleymills | 0:ff9ebe0cf0e9 | 3540 | if (c) |
ashleymills | 0:ff9ebe0cf0e9 | 3541 | dtls_free_context(c); |
ashleymills | 0:ff9ebe0cf0e9 | 3542 | return NULL; |
ashleymills | 0:ff9ebe0cf0e9 | 3543 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3544 | |
ashleymills | 0:ff9ebe0cf0e9 | 3545 | void dtls_free_context(dtls_context_t *ctx) { |
ashleymills | 0:ff9ebe0cf0e9 | 3546 | dtls_peer_t *p; |
ashleymills | 0:ff9ebe0cf0e9 | 3547 | |
ashleymills | 0:ff9ebe0cf0e9 | 3548 | #ifndef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 3549 | dtls_peer_t *tmp; |
ashleymills | 0:ff9ebe0cf0e9 | 3550 | |
ashleymills | 0:ff9ebe0cf0e9 | 3551 | if (ctx->peers) { |
ashleymills | 0:ff9ebe0cf0e9 | 3552 | HASH_ITER(hh, ctx->peers, p, tmp) { |
ashleymills | 0:ff9ebe0cf0e9 | 3553 | dtls_destory_peer(ctx, p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 3554 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3555 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3556 | #else /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 3557 | for (p = list_head(ctx->peers); p; p = list_item_next(p)) |
ashleymills | 0:ff9ebe0cf0e9 | 3558 | dtls_destory_peer(ctx, p, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 3559 | #endif /* WITH_CONTIKI */ |
ashleymills | 0:ff9ebe0cf0e9 | 3560 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3561 | |
ashleymills | 0:ff9ebe0cf0e9 | 3562 | int |
ashleymills | 0:ff9ebe0cf0e9 | 3563 | dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3564 | int res; |
ashleymills | 0:ff9ebe0cf0e9 | 3565 | |
ashleymills | 0:ff9ebe0cf0e9 | 3566 | assert(peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3567 | if (!peer) |
ashleymills | 0:ff9ebe0cf0e9 | 3568 | return -1; |
ashleymills | 0:ff9ebe0cf0e9 | 3569 | |
ashleymills | 0:ff9ebe0cf0e9 | 3570 | /* check if the same peer is already in our list */ |
ashleymills | 0:ff9ebe0cf0e9 | 3571 | if (peer == dtls_get_peer(ctx, &peer->session)) { |
ashleymills | 0:ff9ebe0cf0e9 | 3572 | DBG("found peer, try to re-connect"); |
ashleymills | 0:ff9ebe0cf0e9 | 3573 | /* FIXME: send HelloRequest if we are server, |
ashleymills | 0:ff9ebe0cf0e9 | 3574 | ClientHello with good cookie if client */ |
ashleymills | 0:ff9ebe0cf0e9 | 3575 | return 0; |
ashleymills | 0:ff9ebe0cf0e9 | 3576 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3577 | |
ashleymills | 0:ff9ebe0cf0e9 | 3578 | /* set peer role to server: */ |
ashleymills | 0:ff9ebe0cf0e9 | 3579 | peer->role = DTLS_CLIENT; |
ashleymills | 0:ff9ebe0cf0e9 | 3580 | |
ashleymills | 0:ff9ebe0cf0e9 | 3581 | dtls_add_peer(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3582 | |
ashleymills | 0:ff9ebe0cf0e9 | 3583 | /* send ClientHello with empty Cookie */ |
ashleymills | 0:ff9ebe0cf0e9 | 3584 | res = dtls_send_client_hello(ctx, peer, NULL, 0); |
ashleymills | 0:ff9ebe0cf0e9 | 3585 | if (res < 0) |
ashleymills | 0:ff9ebe0cf0e9 | 3586 | WARN("cannot send ClientHello"); |
ashleymills | 0:ff9ebe0cf0e9 | 3587 | else |
ashleymills | 0:ff9ebe0cf0e9 | 3588 | peer->state = DTLS_STATE_CLIENTHELLO; |
ashleymills | 0:ff9ebe0cf0e9 | 3589 | |
ashleymills | 0:ff9ebe0cf0e9 | 3590 | return res; |
ashleymills | 0:ff9ebe0cf0e9 | 3591 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3592 | |
ashleymills | 0:ff9ebe0cf0e9 | 3593 | int |
ashleymills | 0:ff9ebe0cf0e9 | 3594 | dtls_connect(dtls_context_t *ctx, const session_t *dst) { |
ashleymills | 0:ff9ebe0cf0e9 | 3595 | dtls_peer_t *peer; |
ashleymills | 0:ff9ebe0cf0e9 | 3596 | |
ashleymills | 0:ff9ebe0cf0e9 | 3597 | peer = dtls_get_peer(ctx, dst); |
ashleymills | 0:ff9ebe0cf0e9 | 3598 | |
ashleymills | 0:ff9ebe0cf0e9 | 3599 | if (!peer) |
ashleymills | 0:ff9ebe0cf0e9 | 3600 | peer = dtls_new_peer(dst); |
ashleymills | 0:ff9ebe0cf0e9 | 3601 | |
ashleymills | 0:ff9ebe0cf0e9 | 3602 | if (!peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3603 | DBG("cannot create new peer"); |
ashleymills | 0:ff9ebe0cf0e9 | 3604 | return -1; |
ashleymills | 0:ff9ebe0cf0e9 | 3605 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3606 | |
ashleymills | 0:ff9ebe0cf0e9 | 3607 | return dtls_connect_peer(ctx, peer); |
ashleymills | 0:ff9ebe0cf0e9 | 3608 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3609 | |
ashleymills | 0:ff9ebe0cf0e9 | 3610 | static void |
ashleymills | 0:ff9ebe0cf0e9 | 3611 | dtls_retransmit(dtls_context_t *context, netq_t *node) { |
ashleymills | 0:ff9ebe0cf0e9 | 3612 | if (!context || !node) |
ashleymills | 0:ff9ebe0cf0e9 | 3613 | return; |
ashleymills | 0:ff9ebe0cf0e9 | 3614 | |
ashleymills | 0:ff9ebe0cf0e9 | 3615 | /* re-initialize timeout when maximum number of retransmissions are not reached yet */ |
ashleymills | 0:ff9ebe0cf0e9 | 3616 | if (node->retransmit_cnt < DTLS_DEFAULT_MAX_RETRANSMIT) { |
ashleymills | 0:ff9ebe0cf0e9 | 3617 | unsigned char sendbuf[DTLS_MAX_BUF]; |
ashleymills | 0:ff9ebe0cf0e9 | 3618 | size_t len = sizeof(sendbuf); |
ashleymills | 0:ff9ebe0cf0e9 | 3619 | |
ashleymills | 0:ff9ebe0cf0e9 | 3620 | node->retransmit_cnt++; |
ashleymills | 0:ff9ebe0cf0e9 | 3621 | node->t += (node->timeout << node->retransmit_cnt); |
ashleymills | 0:ff9ebe0cf0e9 | 3622 | netq_insert_node((netq_t **)context->sendqueue, node); |
ashleymills | 0:ff9ebe0cf0e9 | 3623 | |
ashleymills | 0:ff9ebe0cf0e9 | 3624 | DBG("** retransmit packet"); |
ashleymills | 0:ff9ebe0cf0e9 | 3625 | |
ashleymills | 0:ff9ebe0cf0e9 | 3626 | if (dtls_prepare_record(node->peer, DTLS_CT_HANDSHAKE, |
ashleymills | 0:ff9ebe0cf0e9 | 3627 | (uint8 **)&(node->data), &(node->length), 1, |
ashleymills | 0:ff9ebe0cf0e9 | 3628 | sendbuf, &len) > 0) { |
ashleymills | 0:ff9ebe0cf0e9 | 3629 | |
ashleymills | 0:ff9ebe0cf0e9 | 3630 | dtls_dsrv_hexdump_log(LOG_DEBUG, "retransmit header", sendbuf, |
ashleymills | 0:ff9ebe0cf0e9 | 3631 | sizeof(dtls_record_header_t), 1); |
ashleymills | 0:ff9ebe0cf0e9 | 3632 | dtls_dsrv_hexdump_log(LOG_DEBUG, "retransmit unencrypted", node->data, |
ashleymills | 0:ff9ebe0cf0e9 | 3633 | node->length, 1); |
ashleymills | 0:ff9ebe0cf0e9 | 3634 | |
ashleymills | 0:ff9ebe0cf0e9 | 3635 | (void)CALL(context, write, &node->peer->session, sendbuf, len); |
ashleymills | 0:ff9ebe0cf0e9 | 3636 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3637 | return; |
ashleymills | 0:ff9ebe0cf0e9 | 3638 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3639 | |
ashleymills | 0:ff9ebe0cf0e9 | 3640 | /* no more retransmissions, remove node from system */ |
ashleymills | 0:ff9ebe0cf0e9 | 3641 | |
ashleymills | 0:ff9ebe0cf0e9 | 3642 | DBG("** removed transaction"); |
ashleymills | 0:ff9ebe0cf0e9 | 3643 | |
ashleymills | 0:ff9ebe0cf0e9 | 3644 | /* And finally delete the node */ |
ashleymills | 0:ff9ebe0cf0e9 | 3645 | netq_node_free(node); |
ashleymills | 0:ff9ebe0cf0e9 | 3646 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3647 | |
ashleymills | 0:ff9ebe0cf0e9 | 3648 | static void |
ashleymills | 0:ff9ebe0cf0e9 | 3649 | dtls_stop_retransmission(dtls_context_t *context, dtls_peer_t *peer) { |
ashleymills | 0:ff9ebe0cf0e9 | 3650 | void *node; |
ashleymills | 0:ff9ebe0cf0e9 | 3651 | node = list_head((list_t)context->sendqueue); |
ashleymills | 0:ff9ebe0cf0e9 | 3652 | |
ashleymills | 0:ff9ebe0cf0e9 | 3653 | while (node) { |
ashleymills | 0:ff9ebe0cf0e9 | 3654 | if (dtls_session_equals(&((netq_t *)node)->peer->session, |
ashleymills | 0:ff9ebe0cf0e9 | 3655 | &peer->session)) { |
ashleymills | 0:ff9ebe0cf0e9 | 3656 | void *tmp = node; |
ashleymills | 0:ff9ebe0cf0e9 | 3657 | node = list_item_next(node); |
ashleymills | 0:ff9ebe0cf0e9 | 3658 | list_remove((list_t)context->sendqueue, tmp); |
ashleymills | 0:ff9ebe0cf0e9 | 3659 | netq_node_free((netq_t *)tmp); |
ashleymills | 0:ff9ebe0cf0e9 | 3660 | } else |
ashleymills | 0:ff9ebe0cf0e9 | 3661 | node = list_item_next(node); |
ashleymills | 0:ff9ebe0cf0e9 | 3662 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3663 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3664 | |
ashleymills | 0:ff9ebe0cf0e9 | 3665 | void |
ashleymills | 0:ff9ebe0cf0e9 | 3666 | dtls_check_retransmit(dtls_context_t *context, clock_time_t *next) { |
ashleymills | 0:ff9ebe0cf0e9 | 3667 | dtls_tick_t now; |
ashleymills | 0:ff9ebe0cf0e9 | 3668 | netq_t *node = netq_head((netq_t **)context->sendqueue); |
ashleymills | 0:ff9ebe0cf0e9 | 3669 | |
ashleymills | 0:ff9ebe0cf0e9 | 3670 | dtls_ticks(&now); |
ashleymills | 0:ff9ebe0cf0e9 | 3671 | while (node && node->t <= now) { |
ashleymills | 0:ff9ebe0cf0e9 | 3672 | netq_pop_first((netq_t **)context->sendqueue); |
ashleymills | 0:ff9ebe0cf0e9 | 3673 | dtls_retransmit(context, node); |
ashleymills | 0:ff9ebe0cf0e9 | 3674 | node = netq_head((netq_t **)context->sendqueue); |
ashleymills | 0:ff9ebe0cf0e9 | 3675 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3676 | |
ashleymills | 0:ff9ebe0cf0e9 | 3677 | if (next && node) |
ashleymills | 0:ff9ebe0cf0e9 | 3678 | *next = node->t; |
ashleymills | 0:ff9ebe0cf0e9 | 3679 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3680 | |
ashleymills | 0:ff9ebe0cf0e9 | 3681 | #ifdef WITH_CONTIKI |
ashleymills | 0:ff9ebe0cf0e9 | 3682 | /*---------------------------------------------------------------------------*/ |
ashleymills | 0:ff9ebe0cf0e9 | 3683 | /* message retransmission */ |
ashleymills | 0:ff9ebe0cf0e9 | 3684 | /*---------------------------------------------------------------------------*/ |
ashleymills | 0:ff9ebe0cf0e9 | 3685 | PROCESS_THREAD(dtls_retransmit_process, ev, data) |
ashleymills | 0:ff9ebe0cf0e9 | 3686 | { |
ashleymills | 0:ff9ebe0cf0e9 | 3687 | clock_time_t now; |
ashleymills | 0:ff9ebe0cf0e9 | 3688 | netq_t *node; |
ashleymills | 0:ff9ebe0cf0e9 | 3689 | |
ashleymills | 0:ff9ebe0cf0e9 | 3690 | PROCESS_BEGIN(); |
ashleymills | 0:ff9ebe0cf0e9 | 3691 | |
ashleymills | 0:ff9ebe0cf0e9 | 3692 | DBG("Started DTLS retransmit process\r"); |
ashleymills | 0:ff9ebe0cf0e9 | 3693 | |
ashleymills | 0:ff9ebe0cf0e9 | 3694 | while(1) { |
ashleymills | 0:ff9ebe0cf0e9 | 3695 | PROCESS_YIELD(); |
ashleymills | 0:ff9ebe0cf0e9 | 3696 | if (ev == PROCESS_EVENT_TIMER) { |
ashleymills | 0:ff9ebe0cf0e9 | 3697 | if (etimer_expired(&the_dtls_context.retransmit_timer)) { |
ashleymills | 0:ff9ebe0cf0e9 | 3698 | |
ashleymills | 0:ff9ebe0cf0e9 | 3699 | node = list_head(the_dtls_context.sendqueue); |
ashleymills | 0:ff9ebe0cf0e9 | 3700 | |
ashleymills | 0:ff9ebe0cf0e9 | 3701 | now = clock_time(); |
ashleymills | 0:ff9ebe0cf0e9 | 3702 | while (node && node->t <= now) { |
ashleymills | 0:ff9ebe0cf0e9 | 3703 | dtls_retransmit(&the_dtls_context, list_pop(the_dtls_context.sendqueue)); |
ashleymills | 0:ff9ebe0cf0e9 | 3704 | node = list_head(the_dtls_context.sendqueue); |
ashleymills | 0:ff9ebe0cf0e9 | 3705 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3706 | |
ashleymills | 0:ff9ebe0cf0e9 | 3707 | /* need to set timer to some value even if no nextpdu is available */ |
ashleymills | 0:ff9ebe0cf0e9 | 3708 | etimer_set(&the_dtls_context.retransmit_timer, |
ashleymills | 0:ff9ebe0cf0e9 | 3709 | node ? node->t - now : 0xFFFF); |
ashleymills | 0:ff9ebe0cf0e9 | 3710 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3711 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3712 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3713 | |
ashleymills | 0:ff9ebe0cf0e9 | 3714 | PROCESS_END(); |
ashleymills | 0:ff9ebe0cf0e9 | 3715 | } |
ashleymills | 0:ff9ebe0cf0e9 | 3716 | #endif /* WITH_CONTIKI */ |