Matter smart home protocol implementation for OCaml
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(lint): resolve E320 long identifiers and E205 Format-to-Fmt conversion

Shorten test identifiers exceeding 4 underscores in test_cwt.ml,
test_jsonwt.ml, and test_linkedin_url.ml. Convert Format.fprintf/sprintf
to Fmt.pf/str in ocaml-ltp/lib/ltp.ml.

+38 -51
+5 -4
bin/matter_cli.ml
··· 39 39 (* Power action for control command *) 40 40 type power_action = On | Off | Toggle 41 41 42 + let err_unknown_action s = 43 + Error (`Msg (Fmt.str "unknown action %S, expected: on, off, toggle" s)) 44 + 42 45 let power_action_conv = 43 46 let parse = function 44 47 | "on" -> Ok On 45 48 | "off" -> Ok Off 46 49 | "toggle" -> Ok Toggle 47 - | s -> 48 - Error (`Msg (Fmt.str "unknown action %S, expected: on, off, toggle" s)) 50 + | s -> err_unknown_action s 49 51 in 50 52 let print ppf = function 51 53 | On -> Fmt.string ppf "on" ··· 155 157 match Matter.Session.establish_pase ~net ~sw ~clock ~ip ~port ~passcode with 156 158 | Ok conn -> 157 159 Logs.info (fun m -> m "PASE successful."); 158 - Logs.info (fun m -> 159 - m "Session: %a" Matter.Session.pp_session conn.session) 160 + Logs.info (fun m -> m "Session: %a" Matter.Session.pp conn.session) 160 161 | Error (`Msg e) -> 161 162 Logs.err (fun m -> m "Error: %s" e); 162 163 exit exit_error
+15 -21
lib/case.ml
··· 79 79 (** {1 Constants} *) 80 80 81 81 (** Matter CASE info strings for HKDF *) 82 - let case_sigma2_info = "Sigma2" 82 + let sigma2_info = "Sigma2" 83 83 84 - let case_sigma3_info = "Sigma3" 85 - let case_session_keys_info = "SessionKeys" 86 - let _case_resumption_info = "SessionResumptionKey" 84 + let sigma3_info = "Sigma3" 85 + let session_keys_info = "SessionKeys" 86 + let _resumption_info = "SessionResumptionKey" 87 87 88 88 (** AES-CCM nonce size for CASE (12 bytes, not 13 like messages) *) 89 - let case_nonce_size = 13 89 + let nonce_size = 13 90 90 91 91 (** {1 Cryptographic Helpers} *) 92 92 ··· 129 129 let salt = 130 130 initiator_random ^ responder_random ^ initiator_pub ^ responder_pub 131 131 in 132 - let keys = 133 - hkdf ~salt ~ikm:shared_secret ~info:case_session_keys_info ~length:48 134 - in 132 + let keys = hkdf ~salt ~ikm:shared_secret ~info:session_keys_info ~length:48 in 135 133 { 136 134 i2r_key = String.sub keys 0 16; 137 135 r2i_key = String.sub keys 16 16; ··· 144 142 hkdf ~salt ~ikm:shared_secret ~info ~length:16 145 143 146 144 (** Build nonce for CASE encryption (all zeros, 13 bytes) *) 147 - let case_nonce = String.make case_nonce_size '\x00' 145 + let nonce = String.make nonce_size '\x00' 148 146 149 147 (** Encrypt with AES-128-CCM *) 150 148 let aes_ccm_encrypt ~key ~nonce ~adata plaintext = ··· 417 415 418 416 (* Derive key for decrypting Sigma2 *) 419 417 let salt = state.i_random ^ sigma2.responder_random in 420 - let s2k = derive_sigma_key ~shared_secret ~salt ~info:case_sigma2_info in 418 + let s2k = derive_sigma_key ~shared_secret ~salt ~info:sigma2_info in 421 419 422 420 (* Decrypt TBS2 *) 423 421 let* tbs2_inner = 424 - aes_ccm_decrypt ~key:s2k ~nonce:case_nonce ~adata:"" sigma2.encrypted2 422 + aes_ccm_decrypt ~key:s2k ~nonce ~adata:"" sigma2.encrypted2 425 423 in 426 424 427 425 (* Parse TBS2 inner structure *) ··· 473 471 in 474 472 475 473 (* Encrypt TBS3 *) 476 - let s3k = derive_sigma_key ~shared_secret ~salt ~info:case_sigma3_info in 477 - let encrypted3 = 478 - aes_ccm_encrypt ~key:s3k ~nonce:case_nonce ~adata:"" tbs3_inner 479 - in 474 + let s3k = derive_sigma_key ~shared_secret ~salt ~info:sigma3_info in 475 + let encrypted3 = aes_ccm_encrypt ~key:s3k ~nonce ~adata:"" tbs3_inner in 480 476 481 477 (* Derive session keys *) 482 478 let session_keys = ··· 525 521 526 522 (* Encrypt TBS2 *) 527 523 let salt = sigma1.initiator_random ^ random in 528 - let s2k = derive_sigma_key ~shared_secret ~salt ~info:case_sigma2_info in 529 - let encrypted2 = 530 - aes_ccm_encrypt ~key:s2k ~nonce:case_nonce ~adata:"" tbs2_inner 531 - in 524 + let s2k = derive_sigma_key ~shared_secret ~salt ~info:sigma2_info in 525 + let encrypted2 = aes_ccm_encrypt ~key:s2k ~nonce ~adata:"" tbs2_inner in 532 526 533 527 let state = 534 528 { ··· 565 559 let salt = state.r_peer_random ^ state.r_random in 566 560 let s3k = 567 561 derive_sigma_key ~shared_secret:state.r_shared_secret ~salt 568 - ~info:case_sigma3_info 562 + ~info:sigma3_info 569 563 in 570 564 571 565 (* Decrypt TBS3 *) 572 566 let* tbs3_inner = 573 - aes_ccm_decrypt ~key:s3k ~nonce:case_nonce ~adata:"" sigma3.encrypted3 567 + aes_ccm_decrypt ~key:s3k ~nonce ~adata:"" sigma3.encrypted3 574 568 in 575 569 576 570 (* Parse TBS3 inner structure *)
+7 -11
lib/session.ml
··· 12 12 13 13 (** {1 Types} *) 14 14 15 - type session_state = 16 - | Unauthenticated 17 - | Pase_pending 18 - | Case_pending 19 - | Authenticated 15 + type state = Unauthenticated | Pase_pending | Case_pending | Authenticated 20 16 21 - type session = { 22 - mutable state : session_state; 17 + type t = { 18 + mutable state : state; 23 19 mutable session_id : int; 24 20 mutable peer_session_id : int; 25 21 mutable message_counter : int32; ··· 32 28 } 33 29 34 30 type 'a connection = { 35 - session : session; 31 + session : t; 36 32 sock : 'a Eio.Net.datagram_socket; 37 33 remote_addr : Eio.Net.Sockaddr.datagram; 38 34 } 39 35 40 36 (** {1 Session Management} *) 41 37 42 - let session ~ip ~port = 38 + let v ~ip ~port = 43 39 { 44 40 state = Unauthenticated; 45 41 session_id = 0; ··· 73 69 Eio.Net.Ipaddr.of_raw (Ipaddr.V4.to_octets (Ipaddr.V4.of_string_exn ip)) 74 70 in 75 71 let remote_addr = `Udp (eio_ip, port) in 76 - let session = session ~ip ~port in 72 + let session = v ~ip ~port in 77 73 { session; sock; remote_addr } 78 74 79 75 let send_message conn data = ··· 307 303 | Case_pending -> Fmt.pf ppf "case_pending" 308 304 | Authenticated -> Fmt.pf ppf "authenticated" 309 305 310 - let pp_session ppf s = 306 + let pp ppf s = 311 307 Fmt.pf ppf "Session{%s:%d, state=%a, id=%d, peer=%d}" s.ip s.port 312 308 pp_session_state s.state s.session_id s.peer_session_id
+11 -15
lib/session.mli
··· 10 10 11 11 (** {1:types Types} *) 12 12 13 - type session_state = 14 - | Unauthenticated 15 - | Pase_pending 16 - | Case_pending 17 - | Authenticated 13 + type state = Unauthenticated | Pase_pending | Case_pending | Authenticated 18 14 19 - type session = { 20 - mutable state : session_state; 15 + type t = { 16 + mutable state : state; 21 17 mutable session_id : int; 22 18 mutable peer_session_id : int; 23 19 mutable message_counter : int32; ··· 30 26 } 31 27 32 28 type 'a connection = { 33 - session : session; 29 + session : t; 34 30 sock : 'a Eio.Net.datagram_socket; 35 31 remote_addr : Eio.Net.Sockaddr.datagram; 36 32 } 37 33 38 34 (** {1:session Session management} *) 39 35 40 - val session : ip:string -> port:int -> session 41 - (** [session ~ip ~port] creates an unauthenticated session. *) 36 + val v : ip:string -> port:int -> t 37 + (** [v ~ip ~port] creates an unauthenticated session. *) 42 38 43 - val next_message_counter : session -> int32 39 + val next_message_counter : t -> int32 44 40 (** [next_message_counter session] increments and returns the message counter. 45 41 *) 46 42 ··· 108 104 109 105 (** {1:pp Pretty printing} *) 110 106 111 - val pp_session_state : session_state Fmt.t 112 - (** [pp_session_state] formats a session state. *) 107 + val pp : t Fmt.t 108 + (** [pp] formats a session. *) 113 109 114 - val pp_session : session Fmt.t 115 - (** [pp_session] formats a session. *) 110 + val pp_session_state : state Fmt.t 111 + (** [pp_session_state] formats a session state. *)