blob: 22ea80a4bc996cd6ae6ac766e19e0937436a2e2f [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2 <:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7 Unless you and Broadcom execute a separate written software license
8 agreement governing use of this software, this software is licensed
9 to you under the terms of the GNU General Public License version 2
10 (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11 with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22 Not withstanding the above, under no circumstances may you combine
23 this software in any way with any other Broadcom software provided
24 under a license other than the GPL, without Broadcom's express prior
25 written consent.
26
27 :>
28*/
29
30#include "dpoe_eap_tls.h"
31#include "bcmolt_buf.h"
32#include "dpoe_sec_fsm.h"
33
34/* The destination multicast MAC address for EAPOL packets. */
35static const bcmos_mac_address eapol_dst_mac = { { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 } };
36
37/* The length of the RSA key used in the server_key_exchange TLS message sent to the ONU during DPoE bi-directional
38 authentication. */
39#define DPOE_BI_RSA_KEY_SIZE 2048
40
41/* 2 1200 byte certs + some overhead.... */
42#define EAPOL_PKT_SIZE 5000
43
44typedef enum
45{
46 EAP_CODE_REQUEST = 1,
47 EAP_CODE_RESPONSE,
48 EAP_CODE_SUCCESS,
49 EAP_CODE_FAILURE
50} eap_code;
51
52typedef struct
53{
54 uint8_t eap_code;
55 uint8_t id;
56 uint16_t length;
57} eap_frame;
58
59#define EAP_FRAME_SIZE 4
60
61typedef enum
62{
63 EAP_TYPE_IDENTITY = 1,
64 EAP_TYPE_NOTIFICATION,
65 EAP_TYPE_NAK,
66 EAP_TYPE_MD5,
67 EAP_TYPE_OTP,
68 EAP_TYPE_GENERIC_TOKEN_CARD,
69 EAP_TYPE_TLS = 13
70} eap_type;
71
72#define TLS_MAJOR_VERSION 3
73#define TLS_MINOR_VERSION 2
74
75/* First the EAP structures.... */
76typedef struct
77{
78 uint8_t auth_sub_type;
79 uint8_t eap_tls_flags;
80} eap_tls_hdr;
81
82#define EAP_TLS_HDR_SIZE 2
83
84#define EAP_HDR_SIZE (EAP_FRAME_SIZE + EAP_TLS_HDR_SIZE)
85
86typedef enum
87{
88 TLS_CHANGE_CIPHER_SPEC_ID = 20,
89 TLS_ALERT_ID = 21,
90 TLS_HANDSHAKE_ID = 22,
91 TLS_APPLICATION_DATA_ID = 23,
92} tls_content_type;
93
94typedef struct
95{
96 uint8_t content_type;
97 tls_protocol_version tls_version;
98 uint16_t tls_record_length;
99} tls_record_hdr;
100
101#define TLS_RECORD_HDR_SIZE (3 + PROTOCOL_VERSION_SIZE)
102
103#define EAP_TLS_FLAG_LENGTH_OFFSET 7
104#define EAP_TLS_FLAG_MORE_OFFSET 6
105#define EAP_TLS_FLAG_START_OFFSET 5
106#define EAP_TLS_FLAG_LENGTH_BIT (1U << EAP_TLS_FLAG_LENGTH_OFFSET)
107#define EAP_TLS_FLAG_MORE_BIT (1U << EAP_TLS_FLAG_MORE_OFFSET)
108#define EAP_TLS_FLAG_START_BIT (1U << EAP_TLS_FLAG_START_OFFSET)
109
110typedef struct
111{
112 eap_frame hdr;
113 eap_tls_hdr tls;
114} eap_msg_buf;
115
116typedef struct
117{
118 eapol_msg_hdr hdr;
119 eap_msg_buf eap_msg;
120} eapol_msg;
121
122/* Now the TLS records. */
123typedef struct tls_session_id
124{
125 uint8_t length;
126 uint8_t session_id[SIZE_OF_TLS_SESSION_ID];
127} tls_session_id;
128
129typedef enum
130{
131 cm_null = 0
132} compression_method;
133
134typedef struct
135{
136 uint8_t length;
137 uint8_t compression_method;
138} compression_methods;
139
140typedef enum
141{
142 RSA_SIGN = 1,
143 DSS_SIGN = 2,
144 RSA_FIXED_DH = 3,
145 DSS_FIXED_DH = 4,
146 RSA_EPHEMERAL_DH_RESERVED = 5,
147 DSS_EPHEMERAL_DH_RESERVED = 6,
148 FORTEZZA_DMS_RESERVED = 20,
149} client_certificate_type;
150
151/* For 2048 bit RSA key */
152#define SIZE_OF_RSA_MODULUS 256
153#define SIZE_OF_RSA_EXPONENT 3
154
155typedef enum
156{
157 HS_HELLO_REQUEST = 0,
158 HS_CLIENT_HELLO = 1,
159 HS_SERVER_HELLO = 2,
160 HS_CERTIFICATE = 11,
161 HS_SERVER_KEY_EXCHANGE = 12,
162 HS_CERTIFICATE_REQUEST = 13,
163 HS_SERVER_HELLO_DONE = 14,
164 HS_CERTIFICATE_VERIFY = 15,
165 HS_CLIENT_KEY_EXCHANGE = 16,
166 HS_FINISHED = 20,
167} handshake_type;
168
169typedef struct
170{
171 uint8_t msg_id;
172 uint32_t msg_length; /* actually U24 */
173} tls_handshake;
174
175#define TLS_HANDSHAKE_SIZE 4
176
177typedef struct
178{
179 uint8_t *eapol;
180 uint8_t *eap;
181 uint8_t *eap_tls;
182 uint8_t *tls_rec;
183} eap_length_fields;
184
185static f_dpoe_sec_cert_trust_cb _cert_trust;
186static f_dpoe_sec_auth_cb _auth_complete;
187
188static void _buffer_hash_data(dpoe_sec_link_rec *link_rec, const uint8_t *buf, uint32_t len)
189{
190 /* Parameter checks. */
191 BUG_ON(link_rec == NULL);
192 BUG_ON(buf == NULL);
193
194 dpoe_sec_sha1_update(&link_rec->auth_ctrl.trans_data.sha1_hash, buf, len);
195 dpoe_sec_md5_update(&link_rec->auth_ctrl.trans_data.md5_hash, buf, len);
196}
197
198static void _dpoe_eap_tls_compute_master_session_key(auth_trans_data *trans_data)
199{
200 uint8_t seed[(2* COUNT_OF_RANDOM_BYTES)];
201 uint32_t seed_len = 0;
202
203 /* Parameter checks. */
204 BUG_ON(trans_data == NULL);
205
206 /* The seed to the PRF is the client random value concatenated with the server random value. */
207 memcpy(&seed[seed_len], trans_data->client_random, COUNT_OF_RANDOM_BYTES);
208 seed_len += COUNT_OF_RANDOM_BYTES;
209 memcpy(&seed[seed_len], trans_data->server_random, COUNT_OF_RANDOM_BYTES);
210 seed_len += COUNT_OF_RANDOM_BYTES;
211
212 dpoe_sec_prf_expand_4346(
213 trans_data->pre_master_secret,
214 sizeof(trans_data->pre_master_secret),
215 (const uint8_t *)"master secret",
216 strlen("master secret"),
217 seed,
218 seed_len,
219 trans_data->master_secret,
220 sizeof(trans_data->master_secret));
221 dpoe_sec_prf_expand_4346(
222 trans_data->master_secret,
223 sizeof(trans_data->master_secret),
224 (const uint8_t *)"client EAP encryption",
225 strlen("client EAP encryption"),
226 seed,
227 seed_len,
228 trans_data->key_material,
229 sizeof(trans_data->key_material));
230
231 memcpy(trans_data->master_session_key, trans_data->key_material, sizeof(trans_data->master_session_key));
232}
233
234static bcmos_bool _dpoe_eap_tls_prepare_security_data(dpoe_sec_link_rec *link_rec)
235{
236 /* Parameter checks. */
237 BUG_ON(link_rec == NULL);
238
239 /* If bidirectional, compute the master session key and generate the RSA public/private key pair */
240 if (link_rec->cfg.enc_mode == BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_BI)
241 {
242 _dpoe_eap_tls_compute_master_session_key(&link_rec->auth_ctrl.trans_data);
243 }
244
245 return BCMOS_TRUE;
246}
247
248static bcmos_bool _dpoe_eap_tls_skip_length(bcmolt_buf *buf, uint32_t skip, uint8_t** len)
249{
250 *len = bcmolt_buf_snap_get(buf);
251 return bcmolt_buf_skip(buf, skip);
252}
253
254static bcmos_bool _dpoe_eap_tls_init_eap_hdr(
255 dpoe_sec_link_rec *link_rec,
256 bcmolt_buf *buf,
257 eap_code code,
258 eap_length_fields *lf)
259{
260 /* Parameter checks. */
261 BUG_ON(link_rec == NULL);
262 BUG_ON(buf == NULL);
263
264 return
265 bcmolt_buf_write_mac_address(buf, eapol_dst_mac) &&
266 bcmolt_buf_write_mac_address(buf, link_rec->ni_mac) &&
267 bcmolt_buf_write_u16_be(buf, ETHERTYPE_EAPOL) &&
268 bcmolt_buf_write_u8(buf, EAPOL_PROTOCOL_VERSION_DPOE) &&
269 bcmolt_buf_write_u8(buf, EAPOL_TYPE_PACKET) &&
270 /* Eapol Length - we re-compute this after building the packet */
271 _dpoe_eap_tls_skip_length(buf, sizeof(uint16_t), &lf->eapol) &&
272 /* EAP layer headers */
273 bcmolt_buf_write_u8(buf, code) &&
274 bcmolt_buf_write_u8(buf, link_rec->auth_ctrl.current_packet_id++) &&
275 /* EAP length - again, computed when the packet is packed! */
276 _dpoe_eap_tls_skip_length(buf, sizeof(uint16_t), &lf->eap);
277}
278
279static bcmos_bool _dpoe_eap_tls_init_tls_hdr(bcmolt_buf *buf, uint8_t eapTlsFlags, eap_length_fields *lf)
280{
281 bcmos_bool rc = BCMOS_FALSE;
282
283 /* Parameter checks. */
284 BUG_ON(buf == NULL);
285
286 if (bcmolt_buf_write_u8(buf, EAP_TYPE_TLS) &&
287 bcmolt_buf_write_u8(buf, eapTlsFlags))
288 {
289 if ((eapTlsFlags & EAP_TLS_FLAG_LENGTH_BIT) == EAP_TLS_FLAG_LENGTH_BIT)
290 {
291 /* EAP-TLS length - computed at pack completion only allocate room for this if EapTlsFlagLengthBit is set
292 But if the EapTlsFlagLengthBit is set, we also write the TLS Record header. */
293 if (_dpoe_eap_tls_skip_length(buf, sizeof(uint32_t), &lf->eap_tls) &&
294 bcmolt_buf_write_u8(buf, TLS_HANDSHAKE_ID) &&
295 bcmolt_buf_write_u8(buf, TLS_MAJOR_VERSION) &&
296 bcmolt_buf_write_u8(buf, TLS_MINOR_VERSION) &&
297 /* Another length field, the TLS record length */
298 _dpoe_eap_tls_skip_length(buf, sizeof(uint16_t), &lf->tls_rec))
299 {
300 rc = BCMOS_TRUE;
301 }
302 }
303 else
304 {
305 rc = BCMOS_TRUE;
306 }
307 }
308
309 return rc;
310}
311
312static void _dpoe_eap_tls_pack_handshake_length(
313 dpoe_sec_link_rec *link_rec,
314 bcmolt_buf *buf,
315 uint8_t *start,
316 uint8_t *len)
317{
318 uint32_t rec_len;
319 uint8_t *end;
320
321 /* Now go back and fill in the length field. This is the length of the TlsHandshake record */
322 end = bcmolt_buf_snap_get(buf);
323 rec_len = end - start;
324 bcmolt_buf_snap_restore(buf, len);
325 bcmolt_buf_write_u24(buf, uint32_to_24(rec_len - TLS_HANDSHAKE_SIZE));
326 bcmolt_buf_snap_restore(buf, end);
327 _buffer_hash_data(link_rec, start, rec_len);
328}
329
330static bcmos_bool _dpoe_eap_tls_pack_server_hello_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
331{
332 uint8_t *start;
333 uint8_t *len;
334
335 /* Parameter checks. */
336 BUG_ON(link_rec == NULL);
337 BUG_ON(buf == NULL);
338
339 start = bcmolt_buf_snap_get(buf);
340 if (bcmolt_buf_write_u8(buf, HS_SERVER_HELLO) &&
341 (len = bcmolt_buf_snap_get(buf), bcmolt_buf_skip(buf, sizeof(uint24_t))) &&
342 bcmolt_buf_write_u8(buf, link_rec->auth_ctrl.version.major) &&
343 bcmolt_buf_write_u8(buf, link_rec->auth_ctrl.version.minor) &&
344 bcmolt_buf_write(buf, link_rec->auth_ctrl.trans_data.server_random, COUNT_OF_RANDOM_BYTES) &&
345 bcmolt_buf_write_u8(buf, COUNT_OF_RANDOM_BYTES) &&
346 bcmolt_buf_write(buf, link_rec->auth_ctrl.trans_data.server_random, COUNT_OF_RANDOM_BYTES) &&
347
348 /* Cipher Suites - we write 0 as the length of the Cipher Suites
349 Short circuit if using pre-release authentication */
350 ((link_rec->auth_ctrl.version.minor == 3) || bcmolt_buf_write_u16_be(buf, 0)) &&
351
352 /* CompressionMethods also write 0 as the length */
353 bcmolt_buf_write_u8(buf, 0))
354 {
355 _dpoe_eap_tls_pack_handshake_length(link_rec, buf, start, len);
356 return BCMOS_TRUE;
357 }
358 return BCMOS_FALSE;
359}
360
361static bcmos_bool _dpoe_eap_tls_pack_server_key_exchange_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
362{
363 uint8_t *start;
364 uint8_t *len;
365 uint8_t rsa_modulus[SIZE_OF_RSA_MODULUS] = {};
366 uint8_t rsa_exponent[SIZE_OF_RSA_EXPONENT] = {};
367
368 /* Parameter checks. */
369 BUG_ON(link_rec == NULL);
370 BUG_ON(buf == NULL);
371
372 /* If not bidirectional, just return BCMOS_TRUE */
373 if (link_rec->cfg.enc_mode != BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_BI)
374 {
375 return BCMOS_TRUE;
376 }
377
378 /* Verify that the length of the public key (modulus) of the private key matches the expected length. Also, verify
379 that the modulus is successfully read from the RSA key. */
380 start = bcmolt_buf_snap_get(buf);
381 if ((dpoe_sec_rsa_public_get(link_rec->auth_ctrl.trans_data.rsa, rsa_modulus, rsa_exponent)) &&
382 bcmolt_buf_write_u8(buf, HS_SERVER_KEY_EXCHANGE) &&
383 (len = bcmolt_buf_snap_get(buf), bcmolt_buf_skip(buf, sizeof(uint24_t))) &&
384 bcmolt_buf_write(buf, rsa_modulus, sizeof(rsa_modulus)) &&
385 bcmolt_buf_write(buf, rsa_exponent, sizeof(rsa_exponent)))
386 {
387 _dpoe_eap_tls_pack_handshake_length(link_rec, buf, start, len);
388 return BCMOS_TRUE;
389 }
390 return BCMOS_FALSE;
391}
392
393static bcmos_bool _dpoe_eap_tls_pack_cert_req_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
394{
395 uint8_t *start;
396 uint8_t *len;
397
398 /* Parameter checks. */
399 BUG_ON(link_rec == NULL);
400 BUG_ON(buf == NULL);
401
402 start = bcmolt_buf_snap_get(buf);
403 if (bcmolt_buf_write_u8(buf, HS_CERTIFICATE_REQUEST) &&
404 (len = bcmolt_buf_snap_get(buf), bcmolt_buf_skip(buf, sizeof(uint24_t))) &&
405 bcmolt_buf_write_u8(buf, 1) && /* length of 'Certificate Type' */
406 bcmolt_buf_write_u8(buf, RSA_SIGN) && /* Certificate Type */
407 bcmolt_buf_write_u16_be(buf, 0)) /* zero length for cert authorities */
408 {
409 _dpoe_eap_tls_pack_handshake_length(link_rec, buf, start, len);
410 return BCMOS_TRUE;
411 }
412 return BCMOS_FALSE;
413}
414
415static bcmos_bool _dpoe_eap_tls_pack_server_hello_done_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
416{
417 uint8_t *start;
418 uint8_t *len;
419
420 /* Parameter checks. */
421 BUG_ON(link_rec == NULL);
422 BUG_ON(buf == NULL);
423
424 start = bcmolt_buf_snap_get(buf);
425 if (bcmolt_buf_write_u8(buf, HS_SERVER_HELLO_DONE) &&
426 (len = bcmolt_buf_snap_get(buf), bcmolt_buf_skip(buf, sizeof(uint24_t))))
427 {
428 _dpoe_eap_tls_pack_handshake_length(link_rec, buf, start, len);
429 return BCMOS_TRUE;
430 }
431 return BCMOS_FALSE;
432}
433
434static bcmos_bool _dpoe_eap_tls_pack_finished_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
435{
436 uint8_t *start;
437 uint8_t *len;
438
439 start = bcmolt_buf_snap_get(buf);
440 if (bcmolt_buf_write_u8(buf, HS_FINISHED) &&
441 (len = bcmolt_buf_snap_get(buf), bcmolt_buf_skip(buf, sizeof(uint24_t))))
442 {
443 _dpoe_eap_tls_pack_handshake_length(link_rec, buf, start, len);
444 return BCMOS_TRUE;
445 }
446 return BCMOS_FALSE;
447}
448
449static bcmos_bool _dpoe_eap_tls_pack_msg_lengths(bcmolt_buf *buf, uint8_t eap_tls_flags, eap_length_fields *lf)
450{
451 uint16_t eapol_length;
452 uint32_t eap_tls_length;
453 uint8_t *snap = bcmolt_buf_snap_get(buf);
454
455 /* Parameter checks. */
456 BUG_ON(buf == NULL);
457 BUG_ON(lf == NULL);
458
459 eapol_length = bcmolt_buf_get_used(buf) - EAPOL_MSG_HDR_SIZE;
460
461 /* Seems odd that these two would be the same. But eapolLength is defined as the length of the body fields of the
462 Eapol buffer, which does not include the Eapol header. EAP is different, the EAP length is define to include the
463 entire EAP packet, including the header. */
464 bcmolt_buf_snap_restore(buf, lf->eapol);
465 if (!bcmolt_buf_write_u16_be(buf, eapol_length))
466 {
467 bcmolt_buf_snap_restore(buf, snap);
468 return BCMOS_FALSE;
469 }
470
471 bcmolt_buf_snap_restore(buf, lf->eap);
472 if (!bcmolt_buf_write_u16_be(buf, eapol_length))
473 {
474 bcmolt_buf_snap_restore(buf, snap);
475 return BCMOS_FALSE;
476 }
477
478 if ((eap_tls_flags & EAP_TLS_FLAG_LENGTH_BIT) == EAP_TLS_FLAG_LENGTH_BIT)
479 {
480 /* The TLS message length - take away the EapTlsHdr, AND the EapMsgHdr which, surprisingly was not removed in
481 the previous step. */
482 eap_tls_length = eapol_length - (EAP_FRAME_SIZE + EAP_TLS_HDR_SIZE + sizeof(uint32_t));
483
484 bcmolt_buf_snap_restore(buf, lf->eap_tls);
485 if (!bcmolt_buf_write_u32_be(buf, eap_tls_length))
486 {
487 bcmolt_buf_snap_restore(buf, snap);
488 return BCMOS_FALSE;
489 }
490
491 bcmolt_buf_snap_restore(buf, lf->tls_rec);
492 if (!bcmolt_buf_write_u16_be(buf, (uint16_t)eap_tls_length - TLS_RECORD_HDR_SIZE))
493 {
494 bcmolt_buf_snap_restore(buf, snap);
495 return BCMOS_FALSE;
496 }
497 }
498
499 bcmolt_buf_snap_restore(buf, snap);
500 return BCMOS_TRUE;
501}
502
503static bcmos_errno _dpoe_eap_tls_pack_start(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
504{
505 bcmos_errno rc = BCM_ERR_NOMEM;
506 uint8_t flags = EAP_TLS_FLAG_START_BIT;
507 eap_length_fields lf;
508
509 /* Parameter checks. */
510 BUG_ON(link_rec == NULL);
511 BUG_ON(buf == NULL);
512
513 if (_dpoe_eap_tls_init_eap_hdr(link_rec, buf, EAP_CODE_REQUEST, &lf) &&
514 _dpoe_eap_tls_init_tls_hdr(buf, flags, &lf) &&
515 _dpoe_eap_tls_pack_msg_lengths(buf, flags, &lf))
516 {
517 rc = BCM_ERR_OK;
518 }
519
520 return rc;
521}
522
523static bcmos_bool _dpoe_eap_tls_send_cert_request(dpoe_sec_link_rec *link_rec)
524{
525 bcmos_bool rc = BCMOS_FALSE;
526 bcmos_errno err;
527 bcmolt_buf buf;
528 uint8_t *msg = NULL;
529 eap_length_fields lf;
530
531 /* Parameter checks. */
532 BUG_ON(link_rec == NULL);
533
534 msg = bcmos_calloc(EAPOL_PKT_SIZE);
535 if (msg == NULL)
536 {
537 return BCMOS_FALSE;
538 }
539
540 /* Initialize the maximum supported length EAP-TLS message buffer. The various TLS records contained in an EAP-TLS
541 message are variable size. However, this can only be a combined maximum length. */
542 bcmolt_buf_init(&buf, EAPOL_PKT_SIZE, msg, BCMOLT_BUF_ENDIAN_FIXED);
543 if (_dpoe_eap_tls_init_eap_hdr(link_rec, &buf, EAP_CODE_REQUEST, &lf) &&
544 _dpoe_eap_tls_init_tls_hdr(&buf, EAP_TLS_FLAG_LENGTH_BIT, &lf))
545 {
546 /* The Cert request contains 3 or 4 TLS records (3 for DS-only and 4 for bi-directional). The TLS records are
547 ordered as:
548 - Server Hello
549 - Server Key Exchange (if bi-directional)
550 - Certificate Request
551 - Server Hello Done */
552 if (_dpoe_eap_tls_pack_server_hello_hs(link_rec, &buf) &&
553 _dpoe_eap_tls_pack_server_key_exchange_hs(link_rec, &buf) &&
554 _dpoe_eap_tls_pack_cert_req_hs(link_rec, &buf) &&
555 _dpoe_eap_tls_pack_server_hello_done_hs(link_rec, &buf))
556 {
557 _dpoe_eap_tls_pack_msg_lengths(&buf, EAP_TLS_FLAG_LENGTH_BIT, &lf);
558
559 /* Send the message */
560 err = dpoe_sec_send_eapol(link_rec->device, &link_rec->key, msg, bcmolt_buf_get_used(&buf));
561 if (err != BCM_ERR_OK)
562 {
563 bcmos_free(msg);
564 return BCMOS_FALSE;
565 }
566
567 /* Authentication has begun. */
568 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_EAP_START;
569 rc = BCMOS_TRUE;
570 }
571 }
572
573 /* Free the message. */
574 bcmos_free(msg);
575
576 return rc;
577}
578
579static bcmos_errno _dpoe_eap_tls_send_finished_hs(dpoe_sec_link_rec *link_rec)
580{
581 bcmos_errno rc = BCM_ERR_OVERFLOW;
582 bcmolt_buf buf;
583 uint8_t *msg = NULL;
584 eap_length_fields lf;
585
586 /* Parameter checks. */
587 BUG_ON(link_rec == NULL);
588
589 msg = bcmos_calloc(EAPOL_PKT_SIZE);
590 if (msg == NULL)
591 {
592 return BCM_ERR_NOMEM;
593 }
594
595 /* Initialize the EAP-TLS message buffer. */
596 bcmolt_buf_init(&buf, EAPOL_PKT_SIZE, msg, BCMOLT_BUF_ENDIAN_FIXED);
597 if (_dpoe_eap_tls_init_eap_hdr(link_rec, &buf, EAP_CODE_REQUEST, &lf) &&
598 _dpoe_eap_tls_init_tls_hdr(&buf, EAP_TLS_FLAG_LENGTH_BIT, &lf) &&
599 _dpoe_eap_tls_pack_finished_hs(link_rec, &buf))
600 {
601 _dpoe_eap_tls_pack_msg_lengths(&buf, EAP_TLS_FLAG_LENGTH_BIT, &lf);
602 /* No error detection here. We have already authenticated. this message is just for standards compliance */
603 rc = dpoe_sec_send_eapol(link_rec->device, &link_rec->key, msg, bcmolt_buf_get_used(&buf));
604 }
605
606 /* Free the message. */
607 bcmos_free(msg);
608
609 return rc;
610}
611
612static bcmos_errno _dpoe_eap_tls_send_result(dpoe_sec_link_rec *link_rec, eap_code result)
613{
614 uint8_t *msg;
615 bcmolt_buf buf;
616 bcmos_errno rc = BCM_ERR_INTERNAL;
617 eap_length_fields lf;
618
619 /* Parameter checks */
620 BUG_ON(link_rec == NULL);
621
622 msg = bcmos_calloc(EAPOL_PKT_SIZE);
623 if (msg == NULL)
624 {
625 return BCM_ERR_NOMEM;
626 }
627
628 /* Initialize the EAP-TLS message buffer. */
629 bcmolt_buf_init(&buf, EAPOL_PKT_SIZE, msg, BCMOLT_BUF_ENDIAN_FIXED);
630 /* Encode the EAP-Success message to the buffer. */
631 if (_dpoe_eap_tls_init_eap_hdr(link_rec, &buf, result, &lf) &&
632 _dpoe_eap_tls_pack_msg_lengths(&buf, 0, &lf))
633 {
634 rc = dpoe_sec_send_eapol(link_rec->device, &link_rec->key, msg, bcmolt_buf_get_used(&buf));
635 }
636
637 bcmos_free(msg);
638
639 return rc;
640}
641
642static bcmos_bool _dpoe_eap_tls_parse_certificate(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
643{
644 bcmos_bool rc = BCMOS_FALSE;
645 uint24_t length;
646
647 /* Parameter checks. */
648 BUG_ON(link_rec == NULL);
649 BUG_ON(buf == NULL);
650
651 link_rec->auth_ctrl.certificate = bcmos_calloc(EAPOL_PKT_SIZE);
652 if (link_rec->auth_ctrl.certificate == NULL)
653 {
654 return BCMOS_FALSE;
655 }
656
657 if (bcmolt_buf_read_u24(buf, &length) &&
658 ((link_rec->auth_ctrl.certLen = (uint16_t)uint24_to_32(length)), (link_rec->auth_ctrl.certLen <= EAPOL_PKT_SIZE)) &&
659 bcmolt_buf_read(buf, link_rec->auth_ctrl.certificate, link_rec->auth_ctrl.certLen))
660 {
661 rc = BCMOS_TRUE;
662 }
663
664 return rc;
665}
666
667static bcmos_bool _dpoe_eap_tls_parse_client_key_exchange(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
668{
669 bcmos_bool rc = BCMOS_FALSE;
670 uint16_t length;
671 uint8_t encrypted_buf[SIZE_OF_RSA_ENCRYPTED_BLOCK] = {};
672
673 /* Parameter checks. */
674 BUG_ON(link_rec == NULL);
675 BUG_ON(buf == NULL);
676
677 if (bcmolt_buf_read_u16_be(buf, &length) &&
678 (length == (SIZE_OF_RSA_ENCRYPTED_BLOCK)) &&
679 bcmolt_buf_read(buf, encrypted_buf, sizeof(encrypted_buf)))
680 {
681 int val;
682
683 val = dpoe_sec_rsa_private_decrypt(
684 sizeof(encrypted_buf),
685 encrypted_buf,
686 link_rec->auth_ctrl.trans_data.pre_master_secret,
687 link_rec->auth_ctrl.trans_data.rsa);
688
689 if (val == SIZE_OF_PRE_MASTER_SECRET)
690 {
691 /* We now need the security data - we have the "client random", "server random", and "pre master secret". */
692 _dpoe_eap_tls_prepare_security_data(link_rec);
693 rc = BCMOS_TRUE;
694 }
695 else
696 {
697 DPOE_SEC_LINK_LOG(ERROR, link_rec, "RSA decrypt pre-master secret failed: %d\n", val);
698 }
699 }
700 else
701 {
702 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Failed to parse client key exchange: %u\n", length);
703 }
704
705 return rc;
706}
707
708static bcmos_bool _dpoe_eap_tls_parse_cert_verify(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
709{
710 uint16_t length;
711 bcmos_bool ret = BCMOS_FALSE;
712
713 if (bcmolt_buf_read_u16_be(buf, &length) &&
714 (length <= (2 * SIZE_OF_RSA_ENCRYPTED_BLOCK)))
715 {
716 bcmolt_buf cert_buf;
717 uint24_t temp;
718 const uint8_t *cert;
719 uint32_t cert_len = 0;
720 uint8_t cert_verify[sizeof(dpoe_sec_sha1_digest) + sizeof(dpoe_sec_md5_digest)];
721 uint8_t *enc_buf;
722 dpoe_sec_rsa_key *rsa;
723
724 bcmolt_buf_init(&cert_buf, link_rec->auth_ctrl.certLen, link_rec->auth_ctrl.certificate, BCMOLT_BUF_ENDIAN_FIXED);
725
726 /* Get the pointer to the ONU cert and its length */
727 bcmolt_buf_read_u24(&cert_buf, &temp);
728 cert_len = uint24_to_32(temp);
729 cert = bcmolt_buf_snap_get(&cert_buf);
730
731 enc_buf = bcmolt_buf_snap_get(buf);
732 bcmolt_buf_skip(buf, length);
733
734 /* Get the public key from the ONU cert. */
735 rsa = dpoe_sec_x509_pub_key_get(cert, cert_len);
736
737 /* decrypt the remainder of the buf with the ONU cert. */
738 if (rsa != NULL)
739 {
740 if (dpoe_sec_rsa_public_decrypt(length, enc_buf, cert_verify, rsa) >= 0)
741 {
742 /* RSA_size() returns the size of the modulus in bytes. Convert to bits. */
743 link_rec->auth_ctrl.onu_cert_key_size = dpoe_sec_rsa_size(rsa) * 8;
744
745 /* Compare the output (should be 36 bytes) to sha1/md5 messages digests If they match, we are good */
746 if ((memcmp(&cert_verify[0],
747 link_rec->auth_ctrl.trans_data.md5_digest,
748 sizeof(dpoe_sec_md5_digest)) == 0) &&
749 (memcmp(&cert_verify[sizeof(dpoe_sec_md5_digest)],
750 link_rec->auth_ctrl.trans_data.sha1_digest,
751 sizeof(dpoe_sec_sha1_digest)) == 0))
752 {
753 bcmolt_buf_init(&cert_buf, link_rec->auth_ctrl.certLen, link_rec->auth_ctrl.certificate, BCMOLT_BUF_ENDIAN_FIXED);
754
755 /* Get the pointer to the ONU certificate. */
756 bcmolt_buf_read_u24(&cert_buf, &temp);
757 link_rec->auth_ctrl.onu_cert_len = uint24_to_32(temp);
758 link_rec->auth_ctrl.onu_cert = bcmolt_buf_snap_get(&cert_buf);
759
760 bcmolt_buf_skip(&cert_buf, link_rec->auth_ctrl.onu_cert_len);
761
762 /* Get the pointer to the Manufacturer CA certificate. */
763 bcmolt_buf_read_u24(&cert_buf, &temp);
764 link_rec->auth_ctrl.mfg_cert_len = uint24_to_32(temp);
765 link_rec->auth_ctrl.mfg_cert = bcmolt_buf_snap_get(&cert_buf);
766
767 ret = BCMOS_TRUE;
768 }
769 else
770 {
771 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Cert Verify failed\n");
772 }
773 }
774 else
775 {
776 DPOE_SEC_LINK_LOG(ERROR, link_rec, "RSA public decrypt/verify failed\n");
777 }
778 }
779 else
780 {
781 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Failed to retrieve RSA key\n");
782 }
783
784 dpoe_sec_rsa_key_free(rsa);
785 }
786
787 return ret;
788}
789
790static bcmos_bool _dpoe_eap_tls_parse_verify_data(dpoe_sec_link_rec *link_rec)
791{
792 bcmos_bool rc = BCMOS_FALSE;
793
794 /* Parameter checks. */
795 BUG_ON(link_rec == NULL);
796
797 if (link_rec->auth_ctrl.version.minor == TLS_MINOR_VERSION)
798 {
799 /* This version of authentication does not parse verify data */
800 rc = BCMOS_TRUE;
801 }
802 return rc;
803}
804
805static bcmos_bool _dpoe_eap_tls_parse_client_hello(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
806{
807 tls_protocol_version version;
808 tls_session_id session_id;
809
810 /* Parameter checks. */
811 BUG_ON(link_rec == NULL);
812 BUG_ON(buf == NULL);
813
814 if (bcmolt_buf_read_u8(buf, &version.major) &&
815 (version.major == TLS_MAJOR_VERSION) &&
816 bcmolt_buf_read_u8(buf, &version.minor) &&
817 (version.minor >= TLS_MINOR_VERSION) &&
818 bcmolt_buf_read(buf, link_rec->auth_ctrl.trans_data.client_random, COUNT_OF_RANDOM_BYTES) &&
819 bcmolt_buf_read_u8(buf, &session_id.length) &&
820 (session_id.length <= sizeof(session_id.session_id)) &&
821 bcmolt_buf_read(buf, session_id.session_id, session_id.length))
822 {
823 compression_methods comp_methods;
824 uint16_t tlvLen;
825 uint8_t cipher_suites[2];
826 uint8_t *cm_snap = bcmolt_buf_snap_get(buf);
827
828 memset(&comp_methods, 0, sizeof(comp_methods));
829
830 /* Cipher Suites may be present -if so parse over it and it will be ignored. Still check that comp methods is
831 NULL */
832 if (bcmolt_buf_read_u16_be(buf, &tlvLen) && /* Cipher Suites */
833 (tlvLen <= sizeof(uint16_t)) &&
834 bcmolt_buf_read(buf, cipher_suites, tlvLen) &&
835 bcmolt_buf_read_u8(buf, &comp_methods.length) && /* Compression Methods */
836 (comp_methods.length == sizeof(comp_methods.compression_method)) &&
837 bcmolt_buf_read(buf, &comp_methods.compression_method, comp_methods.length) &&
838 (comp_methods.compression_method == cm_null) )
839 {
840 link_rec->auth_ctrl.version.major = version.major;
841 link_rec->auth_ctrl.version.minor = version.minor;
842 return BCMOS_TRUE;
843 }
844
845 /* No cipher suites, check that comp method is null */
846 memset(&comp_methods, 0, sizeof(comp_methods));
847 bcmolt_buf_snap_restore(buf, cm_snap);
848 if (bcmolt_buf_read_u8(buf, &comp_methods.length) && /* Compression Methods */
849 (comp_methods.length == sizeof(comp_methods.compression_method)) &&
850 bcmolt_buf_read(buf, &comp_methods.compression_method, comp_methods.length) &&
851 (comp_methods.compression_method == cm_null) )
852 {
853 link_rec->auth_ctrl.version.major = version.major;
854 link_rec->auth_ctrl.version.minor = version.minor;
855 return BCMOS_TRUE;
856 }
857
858 /* Ok we failed to decode what was sent as cipher suites and comp methods. Do we care? Absolutely Not! */
859 link_rec->auth_ctrl.version.major = version.major;
860 link_rec->auth_ctrl.version.minor = version.minor;
861 return BCMOS_TRUE;
862 }
863
864 return BCMOS_FALSE;
865}
866
867static bcmos_bool _dpoe_eap_tls_handle_client_hello_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
868{
869 /* Parameter checks. */
870 BUG_ON(link_rec == NULL);
871 BUG_ON(buf == NULL);
872
873 if (_dpoe_eap_tls_parse_client_hello(link_rec, buf))
874 {
875 /* We now have the data, build the EAP session ID (see RFC 5216) */
876 link_rec->auth_ctrl.trans_data.session_id[0] = 0xd;
877 memcpy(
878 &link_rec->auth_ctrl.trans_data.session_id[1],
879 link_rec->auth_ctrl.trans_data.client_random,
880 COUNT_OF_RANDOM_BYTES);
881 memcpy(
882 &link_rec->auth_ctrl.trans_data.session_id[COUNT_OF_RANDOM_BYTES + 1],
883 link_rec->auth_ctrl.trans_data.server_random,
884 COUNT_OF_RANDOM_BYTES);
885
886 if (_dpoe_eap_tls_send_cert_request(link_rec))
887 {
888 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_CERT_REQUEST;
889 return BCMOS_TRUE;
890 }
891 }
892
893 return BCMOS_FALSE;
894}
895
896static bcmos_bool _dpoe_eap_tls_handle_certificate_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
897{
898 /* Parameter checks. */
899 BUG_ON(link_rec == NULL);
900 BUG_ON(buf == NULL);
901
902 if (_dpoe_eap_tls_parse_certificate(link_rec, buf))
903 {
904 if (link_rec->auth_ctrl.version.minor == TLS_MINOR_VERSION)
905 {
906 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_CERT_RECEIVED;
907 return BCMOS_TRUE;
908 }
909 }
910 return BCMOS_FALSE;
911}
912
913/******************************************************************************/
914static bcmos_bool _dpoe_eap_tls_handle_client_key_exchange_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
915{
916 /* Parameter checks. */
917 BUG_ON(link_rec == NULL);
918 BUG_ON(buf == NULL);
919
920 if (_dpoe_eap_tls_parse_client_key_exchange(link_rec, buf))
921 {
922 if (link_rec->auth_ctrl.version.minor == TLS_MINOR_VERSION)
923 {
924 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_CLIENT_KEY_RECEIVED;
925 return BCMOS_TRUE;
926 }
927 else
928 {
929 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Wrong TLS version in client key exchange: %u\n",
930 link_rec->auth_ctrl.version.minor);
931 }
932 }
933 else
934 {
935 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Failed to parse client key exchange\n");
936 }
937
938 return BCMOS_FALSE;
939}
940
941static bcmos_bool _dpoe_eap_tls_handle_cert_verify_hs(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
942{
943 bcmos_bool success;
944
945 /* Parameter checks. */
946 BUG_ON(link_rec == NULL);
947 BUG_ON(buf == NULL);
948
949 success = _dpoe_eap_tls_parse_cert_verify(link_rec, buf);
950
951 if (success)
952 {
953 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_CERT_VALIDATED;
954 }
955 else
956 {
957 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_FAILED;
958 if (_auth_complete != NULL)
959 {
960 _auth_complete(link_rec, BCM_ERR_ONU_ERR_RESP);
961 }
962 }
963
964 return success;
965}
966
967static bcmos_bool _dpoe_eap_tls_handle_finished_hs(dpoe_sec_link_rec *link_rec)
968{
969 bcmos_bool success;
970
971 /* Parameter checks. */
972 BUG_ON(link_rec == NULL);
973
974 success = _dpoe_eap_tls_parse_verify_data(link_rec);
975
976 /* And send the final Finished Hs to the ONU */
977 if (link_rec->auth_ctrl.version.minor == TLS_MINOR_VERSION)
978 {
979 _dpoe_eap_tls_send_finished_hs(link_rec);
980 }
981
982 if (success)
983 {
984 if ((_cert_trust == NULL) || (_cert_trust(link_rec)))
985 {
986 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_AUTHENTICATED;
987 _dpoe_eap_tls_send_result(link_rec, EAP_CODE_SUCCESS);
988 if (_auth_complete != NULL)
989 {
990 _auth_complete(link_rec, BCM_ERR_OK);
991 }
992 }
993 else
994 {
995 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_FAILED;
996 _dpoe_eap_tls_send_result(link_rec, EAP_CODE_FAILURE);
997 success = BCMOS_FALSE;
998 if (_auth_complete != NULL)
999 {
1000 _auth_complete(link_rec, BCM_ERR_INTERNAL);
1001 }
1002 }
1003 }
1004 else
1005 {
1006 /* Reset ALL the state variables! */
1007 memset(&link_rec->auth_ctrl, 0, sizeof(link_rec->auth_ctrl));
1008 }
1009
1010 return success;
1011}
1012
1013static bcmos_bool _dpoe_eap_tls_alloc_tls_frag_buffer(onu_auth_control *auth_ctrl)
1014{
1015 /* Parameter checks. */
1016 BUG_ON(auth_ctrl == NULL);
1017
1018 if (auth_ctrl->tls_frag_buffer == NULL)
1019 {
1020 auth_ctrl->tls_frag_buffer = bcmos_calloc(EAPOL_PKT_SIZE);
1021 auth_ctrl->tls_frag_length = 0;
1022 auth_ctrl->tls_total_length = 0;
1023 }
1024
1025 if (auth_ctrl->tls_frag_buffer == NULL)
1026 {
1027 return BCMOS_FALSE;
1028 }
1029
1030 return BCMOS_TRUE;
1031}
1032
1033static void _dpoe_eap_tls_free_tls_frag_buffer(onu_auth_control *auth_ctrl)
1034{
1035 /* Parameter checks. */
1036 BUG_ON(auth_ctrl == NULL);
1037
1038 if (auth_ctrl->tls_frag_buffer != NULL)
1039 {
1040 bcmos_free(auth_ctrl->tls_frag_buffer);
1041 auth_ctrl->tls_frag_buffer = NULL;
1042 auth_ctrl->tls_frag_length = 0;
1043 auth_ctrl->tls_total_length = 0;
1044 }
1045}
1046
1047static bcmos_errno _dpoe_eap_tls_send_tls_frag_ack_to_onu(dpoe_sec_link_rec *link_rec)
1048{
1049 bcmos_errno rc;
1050 bcmolt_buf buf;
1051 uint8_t *msg;
1052 eap_length_fields lf;
1053
1054 /* Parameter checks. */
1055 BUG_ON(link_rec == NULL);
1056
1057 /* Allocate a message buffer */
1058 msg = bcmos_calloc(EAPOL_PKT_SIZE);
1059 if (NULL == msg)
1060 {
1061 return BCM_ERR_NOMEM;
1062 }
1063
1064 /* Initialize the EAP-TLS buffer. */
1065 bcmolt_buf_init(&buf, EAPOL_PKT_SIZE, msg, BCMOLT_BUF_ENDIAN_FIXED);
1066 if (_dpoe_eap_tls_init_eap_hdr(link_rec, &buf, EAP_CODE_REQUEST, &lf) &&
1067 _dpoe_eap_tls_init_tls_hdr(&buf, 0, &lf) &&
1068 _dpoe_eap_tls_pack_msg_lengths(&buf, 0, &lf))
1069 {
1070 /* Send the message */
1071 rc = dpoe_sec_send_eapol(link_rec->device, &link_rec->key, msg, bcmolt_buf_get_used(&buf));
1072 if (rc != BCM_ERR_OK)
1073 {
1074 bcmos_free(msg);
1075 return rc;
1076 }
1077 }
1078 else
1079 {
1080 rc = BCM_ERR_OVERFLOW;
1081 }
1082
1083 bcmos_free(msg);
1084
1085 return rc;
1086}
1087
1088static bcmos_bool _dpoe_eap_tls_unpack_tls_handshake(bcmolt_buf *buf, tls_handshake* hs)
1089{
1090 uint24_t temp;
1091 bcmos_bool rc = BCMOS_FALSE;
1092
1093 if (bcmolt_buf_read_u8(buf, &hs->msg_id) &&
1094 bcmolt_buf_read_u24(buf, &temp))
1095 {
1096 hs->msg_length = uint24_to_32(temp);
1097 rc = BCMOS_TRUE;
1098 }
1099
1100 return rc;
1101}
1102
1103static bcmos_errno _dpoe_eap_tls_run_auth_state_machine(dpoe_sec_link_rec *link_rec, bcmolt_buf *buf)
1104{
1105 bcmos_errno rc = BCM_ERR_OK;
1106 uint8_t *hs_snap;
1107 tls_handshake handshake;
1108
1109 /* Parameter checks. */
1110 BUG_ON(link_rec == NULL);
1111
1112 while (hs_snap = bcmolt_buf_snap_get(buf), _dpoe_eap_tls_unpack_tls_handshake(buf, &handshake))
1113 {
1114 bcmos_bool success = BCMOS_TRUE;
1115
1116 if (handshake.msg_length > EAPOL_PKT_SIZE)
1117 {
1118 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "Handshake length is insane: msg %u, len %u\n",
1119 handshake.msg_id, handshake.msg_length);
1120 return BCM_ERR_PARSE;
1121 }
1122
1123 if ((handshake.msg_id == HS_CLIENT_HELLO) &&
1124 (link_rec->auth_ctrl.onu_auth_state == DPOE_ONU_AUTH_STATE_EAP_START))
1125 {
1126 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "EAP TLS RX msg %u in state %u\n",
1127 handshake.msg_id, link_rec->auth_ctrl.onu_auth_state);
1128 _buffer_hash_data(link_rec, hs_snap, handshake.msg_length + TLS_HANDSHAKE_SIZE);
1129 success = _dpoe_eap_tls_handle_client_hello_hs(link_rec, buf);
1130 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "New auth state %u\n", link_rec->auth_ctrl.onu_auth_state);
1131 }
1132 else if ((handshake.msg_id == HS_CERTIFICATE) &&
1133 (link_rec->auth_ctrl.onu_auth_state == DPOE_ONU_AUTH_STATE_CERT_REQUEST))
1134 {
1135 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "EAP TLS RX msg %u in state %u\n",
1136 handshake.msg_id, link_rec->auth_ctrl.onu_auth_state);
1137 _buffer_hash_data(link_rec, hs_snap, handshake.msg_length + TLS_HANDSHAKE_SIZE);
1138 success = _dpoe_eap_tls_handle_certificate_hs(link_rec, buf);
1139 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "New auth state %u\n", link_rec->auth_ctrl.onu_auth_state);
1140 }
1141 else if ((handshake.msg_id == HS_CLIENT_KEY_EXCHANGE) &&
1142 (link_rec->auth_ctrl.onu_auth_state == DPOE_ONU_AUTH_STATE_CERT_RECEIVED))
1143 {
1144 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "EAP TLS RX msg %u in state %u\n",
1145 handshake.msg_id, link_rec->auth_ctrl.onu_auth_state);
1146 _buffer_hash_data(link_rec, hs_snap, handshake.msg_length + TLS_HANDSHAKE_SIZE);
1147 success = _dpoe_eap_tls_handle_client_key_exchange_hs(link_rec, buf);
1148 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "New auth state %u\n", link_rec->auth_ctrl.onu_auth_state);
1149 }
1150 else if ((handshake.msg_id == HS_CERTIFICATE_VERIFY) &&
1151 ((link_rec->auth_ctrl.onu_auth_state == DPOE_ONU_AUTH_STATE_CERT_RECEIVED) ||
1152 (link_rec->auth_ctrl.onu_auth_state == DPOE_ONU_AUTH_STATE_CLIENT_KEY_RECEIVED)))
1153
1154 {
1155 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "EAP TLS RX msg %u in state %u\n",
1156 handshake.msg_id, link_rec->auth_ctrl.onu_auth_state);
1157 dpoe_sec_sha1_final(link_rec->auth_ctrl.trans_data.sha1_digest, &link_rec->auth_ctrl.trans_data.sha1_hash);
1158 dpoe_sec_md5_final(link_rec->auth_ctrl.trans_data.md5_digest, &link_rec->auth_ctrl.trans_data.md5_hash);
1159 success = _dpoe_eap_tls_handle_cert_verify_hs(link_rec, buf);
1160 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "New auth state %u\n", link_rec->auth_ctrl.onu_auth_state);
1161 }
1162 else if ((handshake.msg_id == HS_FINISHED) &&
1163 (link_rec->auth_ctrl.onu_auth_state == DPOE_ONU_AUTH_STATE_CERT_VALIDATED))
1164 {
1165 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "EAP TLS RX msg %u in state %u\n",
1166 handshake.msg_id, link_rec->auth_ctrl.onu_auth_state);
1167 success = _dpoe_eap_tls_handle_finished_hs(link_rec);
1168 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "New auth state %u\n", link_rec->auth_ctrl.onu_auth_state);
1169 }
1170 else
1171 {
1172 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "EAP TLS RX msg %u in state %u\n",
1173 handshake.msg_id, link_rec->auth_ctrl.onu_auth_state);
1174 success = BCMOS_FALSE;
1175 }
1176
1177 if (!success)
1178 {
1179 /* Something went wrong, just abort... */
1180 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "EAP TLS handshake processing failed: %u\n", handshake.msg_id);
1181 rc = BCM_ERR_PARSE;
1182 }
1183 }
1184
1185 return rc;
1186}
1187
1188static bcmos_bool _dpoe_eap_tls_unpack_tls_record_hdr(bcmolt_buf *buf, tls_record_hdr *msg)
1189{
1190 return bcmolt_buf_read_u8(buf, &msg->content_type) &&
1191 bcmolt_buf_read_u8(buf, &msg->tls_version.major) &&
1192 bcmolt_buf_read_u8(buf, &msg->tls_version.minor) &&
1193 bcmolt_buf_read_u16_be(buf, &msg->tls_record_length);
1194}
1195
1196static bcmos_errno _dpoe_eap_tls_process_tls_records(dpoe_sec_link_rec *link_rec)
1197{
1198 bcmos_errno rc = BCM_ERR_OK;
1199 bcmolt_buf buf;
1200 tls_record_hdr tls_hdr;
1201
1202 /* Parameter checks. */
1203 BUG_ON(link_rec == NULL);
1204
1205 bcmolt_buf_init(&buf, link_rec->auth_ctrl.tls_frag_length, link_rec->auth_ctrl.tls_frag_buffer, BCMOLT_BUF_ENDIAN_FIXED);
1206 while ((rc == BCM_ERR_OK) && _dpoe_eap_tls_unpack_tls_record_hdr(&buf, &tls_hdr))
1207 {
1208 rc = _dpoe_eap_tls_run_auth_state_machine(link_rec, &buf);
1209 }
1210
1211 return rc;
1212}
1213
1214static bcmos_bool _dpoe_eap_tls_check_tls_version(const tls_record_hdr *tls_rec_hdr)
1215{
1216 /* Parameter checks. */
1217 BUG_ON(tls_rec_hdr == NULL);
1218
1219 if ((tls_rec_hdr->content_type != TLS_HANDSHAKE_ID) ||
1220 (tls_rec_hdr->tls_version.major != TLS_MAJOR_VERSION) ||
1221 (tls_rec_hdr->tls_version.minor < TLS_MINOR_VERSION))
1222 {
1223 return BCMOS_TRUE;
1224 }
1225 return BCMOS_FALSE;
1226}
1227
1228static void _dpoe_eap_tls_buffer_tls_data(dpoe_sec_link_rec *link_rec, const void *data, uint32_t length)
1229{
1230 /* Parameter checks. */
1231 BUG_ON(link_rec == NULL);
1232 BUG_ON(data == NULL);
1233
1234 /* do not overrun the buffer, no matter how much data received */
1235 if ((link_rec->auth_ctrl.tls_frag_length + length) > EAPOL_PKT_SIZE)
1236 {
1237 length = EAPOL_PKT_SIZE - link_rec->auth_ctrl.tls_frag_length;
1238 }
1239
1240 memcpy(&link_rec->auth_ctrl.tls_frag_buffer[link_rec->auth_ctrl.tls_frag_length], data, length);
1241 link_rec->auth_ctrl.tls_frag_length += length;
1242}
1243
1244static bcmos_bool _dpoe_eap_tls_unpack_msg(bcmolt_buf *buf, eapol_msg *msg)
1245{
1246 return dpoe_sec_eapol_unpack(buf, &msg->hdr) &&
1247 bcmolt_buf_read_u8(buf, &msg->eap_msg.hdr.eap_code) &&
1248 bcmolt_buf_read_u8(buf, &msg->eap_msg.hdr.id) &&
1249 bcmolt_buf_read_u16_be(buf, &msg->eap_msg.hdr.length) &&
1250 bcmolt_buf_read_u8(buf, &msg->eap_msg.tls.auth_sub_type) &&
1251 bcmolt_buf_read_u8(buf, &msg->eap_msg.tls.eap_tls_flags);
1252}
1253
1254static bcmos_errno _dpoe_eap_tls_gen_key(auth_trans_data *trans_data)
1255{
1256 bcmos_errno rc = BCM_ERR_OK;
1257 dpoe_sec_rsa_key *rsa = NULL;
1258
1259 /* Parameter checks */
1260 BUG_ON(trans_data == NULL);
1261
1262 /* Generate the RSA key to be used in the ServerKeyExchange and ClientKeyExchange */
1263 rsa = dpoe_sec_rsa_generate_key(DPOE_BI_RSA_KEY_SIZE);
1264 if (rsa == NULL)
1265 {
1266 rc = BCM_ERR_INTERNAL;
1267 }
1268 else
1269 {
1270 /* Store the pointer to the key. */
1271 trans_data->rsa = rsa;
1272 }
1273
1274 return rc;
1275}
1276
1277bcmos_errno dpoe_eap_tls_send_start(dpoe_sec_link_rec *link_rec)
1278{
1279 bcmos_errno rc = BCM_ERR_OK;
1280 bcmolt_buf buf;
1281 uint8_t *msg;
1282 time_t unix_time;
1283
1284 /* Parameter checks */
1285 BUG_ON(link_rec == NULL);
1286
1287 /* Initialize the authentication control data. */
1288 memset(&link_rec->auth_ctrl, 0, sizeof(link_rec->auth_ctrl));
1289 dpoe_sec_sha1_init(&link_rec->auth_ctrl.trans_data.sha1_hash);
1290 dpoe_sec_md5_init(&link_rec->auth_ctrl.trans_data.md5_hash);
1291
1292 /* Per standard, the first four bytes of the server random value should be "unix time" */
1293 unix_time = time(NULL);
1294 memcpy(link_rec->auth_ctrl.trans_data.server_random, &unix_time, sizeof(unix_time));
1295 dpoe_sec_generate_n_byte_random_number(&link_rec->auth_ctrl.trans_data.server_random[sizeof(unix_time)], COUNT_OF_RANDOM_BYTES - sizeof(unix_time));
1296
1297 /* If bidirectional, generate the RSA public/private key pair for the ServerKeyExchange and ClientKeyExchange. */
1298 if (link_rec->cfg.enc_mode == BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_BI)
1299 {
1300 rc = _dpoe_eap_tls_gen_key(&link_rec->auth_ctrl.trans_data);
1301 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != rc, rc);
1302 }
1303
1304 /* Allocate a message buffer */
1305 msg = bcmos_calloc(EAPOL_PKT_SIZE);
1306 if (NULL == msg)
1307 {
1308 return BCM_ERR_NOMEM;
1309 }
1310
1311 /* Initialize the EAP-TLS buffer. */
1312 bcmolt_buf_init(&buf, EAPOL_PKT_SIZE, msg, BCMOLT_BUF_ENDIAN_FIXED);
1313
1314 /* Encode the EAP-TLS Start message to the buffer. */
1315 _dpoe_eap_tls_pack_start(link_rec, &buf);
1316
1317 /* Send the message */
1318 rc = dpoe_sec_send_eapol(link_rec->device, &link_rec->key, msg, bcmolt_buf_get_used(&buf));
1319 bcmos_free(msg);
1320 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != rc, rc);
1321
1322 /* Authentication has begun. */
1323 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_EAP_START;
1324
1325 return rc;
1326}
1327
1328bcmos_errno dpoe_eap_tls_process_eapol_pkt(dpoe_sec_link_rec *link_rec, uint8_t *msg, uint32_t msg_len)
1329{
1330 bcmos_errno rc = BCM_ERR_INTERNAL;
1331 uint32_t eap_tls_length;
1332 tls_record_hdr tls_rec_hdr;
1333 eapol_msg unpacked_msg;
1334 bcmolt_buf buf;
1335
1336 /* Parameter checks */
1337 BUG_ON(link_rec == NULL);
1338 BUG_ON(msg == NULL);
1339
1340 bcmolt_buf_init(&buf, msg_len, msg, BCMOLT_BUF_ENDIAN_FIXED);
1341 _dpoe_eap_tls_unpack_msg(&buf, &unpacked_msg);
1342
1343 if (unpacked_msg.eap_msg.tls.auth_sub_type == EAP_TYPE_NAK)
1344 {
1345 link_rec->auth_ctrl.onu_auth_state = DPOE_ONU_AUTH_STATE_FAILED;
1346 return BCM_ERR_ONU_ERR_RESP;
1347 }
1348
1349 if (unpacked_msg.hdr.eapol_length != unpacked_msg.eap_msg.hdr.length)
1350 {
1351 return BCM_ERR_PARSE;
1352 }
1353
1354 /* We should only read the length if the length bit is set. */
1355 if ((unpacked_msg.eap_msg.tls.eap_tls_flags & EAP_TLS_FLAG_LENGTH_BIT) != 0)
1356 {
1357 bcmolt_buf_read_u32_be(&buf, &eap_tls_length);
1358 uint8_t *tls_data = bcmolt_buf_snap_get(&buf);
1359 _dpoe_eap_tls_unpack_tls_record_hdr(&buf, &tls_rec_hdr);
1360 if (_dpoe_eap_tls_check_tls_version(&tls_rec_hdr))
1361 {
1362 /* Invalid TLS record, discard... */
1363 return BCM_ERR_PARSE;
1364 }
1365
1366 /* Allocate the fragmentation buffer. Multiple calls to the frag alloc function is allowed since it allocates a
1367 new buffer only if there is no frag buffer currently allocated. The frag buffer is also freed if the EAP-TLS
1368 session goes down for some reason. */
1369 if (!_dpoe_eap_tls_alloc_tls_frag_buffer(&link_rec->auth_ctrl))
1370 {
1371 return BCM_ERR_NOMEM;
1372 }
1373
1374 /* If the length bit is set, and the more bit is not, this is likely a single fragment packet. In that case
1375 the TlsMsg length must be present, and match the size of the buffer. It is also possible that this is a
1376 subsequent fragment and the client always adds the length (which per standard is the length of the set of
1377 fragments), in which case we cannot validate this now. The best we can do is save this size, and validate
1378 when all fragments have been received. */
1379 if (link_rec->auth_ctrl.tls_total_length == 0)
1380 {
1381 link_rec->auth_ctrl.tls_total_length = eap_tls_length;
1382 }
1383
1384 if (link_rec->auth_ctrl.tls_total_length != eap_tls_length)
1385 {
1386 return BCM_ERR_PARSE;
1387 }
1388
1389 _dpoe_eap_tls_buffer_tls_data(
1390 link_rec,
1391 tls_data,
1392 unpacked_msg.hdr.eapol_length - (EAP_FRAME_SIZE + EAP_TLS_HDR_SIZE + sizeof(uint32_t)));
1393
1394 if ((unpacked_msg.eap_msg.tls.eap_tls_flags & EAP_TLS_FLAG_MORE_BIT) != 0)
1395 {
1396 /* Need to acknowledge the fragment */
1397 _dpoe_eap_tls_send_tls_frag_ack_to_onu(link_rec);
1398 rc = BCM_ERR_IN_PROGRESS;
1399 }
1400 else
1401 {
1402 /* Either a single fragment packet, or the last fragment of a multi-fragment packet. If it is the last
1403 fragment of a multi-fragment, then all we can check is that eapTlsLength is one TlsRecordHdr bigger than
1404 the buffered (authCtrl->tlsFragLen) data stream. The same logic works on a single frag packet. */
1405 if ((eap_tls_length != link_rec->auth_ctrl.tls_total_length) ||
1406 (eap_tls_length != link_rec->auth_ctrl.tls_frag_length))
1407 {
1408 return BCM_ERR_PARSE;
1409 }
1410
1411 rc = _dpoe_eap_tls_process_tls_records(link_rec);
1412 _dpoe_eap_tls_free_tls_frag_buffer(&link_rec->auth_ctrl);
1413 }
1414 }
1415 else
1416 {
1417 uint8_t *tls_data = bcmolt_buf_snap_get(&buf);
1418
1419 /* No length field - must be fragmented, and not first */
1420 if (link_rec->auth_ctrl.tls_frag_buffer == NULL)
1421 {
1422 return BCM_ERR_OUT_OF_SYNC;
1423 }
1424
1425 _dpoe_eap_tls_buffer_tls_data(
1426 link_rec,
1427 tls_data,
1428 unpacked_msg.hdr.eapol_length - (EAP_FRAME_SIZE + EAP_TLS_HDR_SIZE));
1429
1430 /* If the more bit is set, wait for the next fragment. Otherwise dump what we have into the state machine. */
1431 if ((unpacked_msg.eap_msg.tls.eap_tls_flags & EAP_TLS_FLAG_MORE_BIT) != 0)
1432 {
1433 /* Need to acknowledge the fragment? The standard does not define a message set that will get us here. */
1434 _dpoe_eap_tls_send_tls_frag_ack_to_onu(link_rec);
1435 rc = BCM_ERR_IN_PROGRESS;
1436 }
1437 else
1438 {
1439 if (link_rec->auth_ctrl.tls_total_length != link_rec->auth_ctrl.tls_frag_length)
1440 {
1441 return BCM_ERR_PARSE;
1442 }
1443
1444 rc = _dpoe_eap_tls_process_tls_records(link_rec);
1445 _dpoe_eap_tls_free_tls_frag_buffer(&link_rec->auth_ctrl);
1446 }
1447 }
1448
1449 return rc;
1450}
1451
1452void dpoe_eap_tls_cleanup(dpoe_sec_link_rec *link_rec)
1453{
1454 /* Parameter checks */
1455 BUG_ON(link_rec == NULL);
1456
1457 // We are done with this.
1458 if (link_rec->auth_ctrl.certificate != NULL)
1459 {
1460 bcmos_free(link_rec->auth_ctrl.certificate);
1461 }
1462
1463 if (link_rec->auth_ctrl.trans_data.rsa != NULL)
1464 {
1465 dpoe_sec_rsa_key_free(link_rec->auth_ctrl.trans_data.rsa);
1466 link_rec->auth_ctrl.trans_data.rsa = NULL;
1467 }
1468
1469 link_rec->auth_ctrl.certLen = 0;
1470
1471 _dpoe_eap_tls_free_tls_frag_buffer(&link_rec->auth_ctrl);
1472
1473 memset(&link_rec->auth_ctrl, 0, sizeof(link_rec->auth_ctrl));
1474}
1475
1476bcmos_errno dpoe_eap_tls_init(f_dpoe_sec_auth_cb auth_cb, f_dpoe_sec_cert_trust_cb cert_trust_cb)
1477{
1478 _auth_complete = auth_cb;
1479 _cert_trust = cert_trust_cb;
1480
1481 return dpoe_sec_rng_seed();
1482}
1483