Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
parse.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426open Types module Wire = struct open Angstrom let byte = any_uint8 let boolean = any_char >>| ((<>) '\000') let uint32 = BE.any_int32 let uint64 = BE.any_int64 (* XXX: int32 -> int coercion *) let string = BE.any_int32 >>= fun string_len -> take (Int32.to_int string_len) (* XXX: int32 -> int coercion *) (* FIXME: negative numbers *) let mpint = BE.any_int32 >>= fun mpint_len -> if mpint_len = 0l then return Z.zero else take (Int32.to_int mpint_len) >>= fun mpint -> return (Mirage_crypto_pk.Z_extra.of_cstruct_be (Cstruct.of_string mpint)) let name_list = string >>| String.split_on_char ',' end (* Angstrom helpers *) let take32 n = Angstrom.take (Int32.to_int n) let count32 n = Angstrom.count (Int32.to_int n) let parse_lift p1 p2 = let open Angstrom in p1 >>= fun s -> match parse_string ~consume:Consume.All p2 s with | Ok a -> Angstrom.return a | Error e -> Angstrom.fail e let angstrom_of_result source r = match r with | Error (`Msg e) -> Angstrom.fail (source ^ ": " ^ e) | Ok v -> Angstrom.return v let mirage_crypto_ec_error_to_msg e = `Msg (Format.asprintf "%a" Mirage_crypto_ec.pp_error e) let pub_ssh_dss = let open Angstrom in Wire.mpint >>= fun p -> Wire.mpint >>= fun q -> Wire.mpint >>= fun gg -> Wire.mpint >>= fun y -> Mirage_crypto_pk.Dsa.pub ~p ~q ~gg ~y () |> angstrom_of_result "Mirage_crypto_pk.Dsa.pub" let pub_ssh_rsa = let open Angstrom in Wire.mpint >>= fun e -> Wire.mpint >>= fun n -> Mirage_crypto_pk.Rsa.pub ~e ~n |> angstrom_of_result "Mirage_crypto_pk.Rsa.pub" let pub_ssh_ed25519 = let open Angstrom in (* https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5 *) Wire.string >>= fun key -> Mirage_crypto_ec.Ed25519.pub_of_cstruct (Cstruct.of_string key) |> Result.map_error mirage_crypto_ec_error_to_msg |> angstrom_of_result "Mirage_crypto_ec.Ed25519.pub_of_cstruct" let string_tuple = let open Angstrom in Wire.string >>= fun name -> Wire.string >>= fun data -> return (name, data) let pub_blob key_type = Angstrom.(take_while (fun _ -> true) >>= fun key_blob -> return @@ Pubkey.Blob { key_type; key_blob; }) let rec pub_ssh_rsa_cert () = let open Angstrom in Wire.string >>= fun nonce -> pub_ssh_rsa >>= fun pubkey_to_be_signed -> Wire.uint64 >>= fun serial -> Wire.uint32 >>= fun typ -> match Protocol_number.int_to_ssh_cert_type typ with | None -> Angstrom.fail ("Unknown ssh cert type " ^ Int32.to_string typ) | Some typ -> Wire.string >>= fun key_id -> parse_lift Wire.string (many Wire.string) >>= fun valid_principals -> Wire.uint64 >>= fun valid_before -> Wire.uint64 >>= fun valid_after -> parse_lift Wire.string (many string_tuple) >>= fun critical_options -> parse_lift Wire.string (many string_tuple) >>= fun extensions -> Wire.string >>= fun reserved -> parse_lift Wire.string (pubkey false) >>= fun signature_key -> Wire.string >>= fun signature -> return { Pubkey.to_be_signed = { Pubkey.nonce; pubkey = pubkey_to_be_signed; serial; typ; key_id; valid_principals; valid_after; valid_before; critical_options; extensions; reserved; signature_key; }; signature; } and pubkey can_be_cert = let open Angstrom in Wire.string >>= function | "ssh-dss" -> pub_ssh_dss >>= fun pubkey -> return (Pubkey.Ssh_dss pubkey) | "ssh-rsa" -> pub_ssh_rsa >>= fun pubkey -> return (Pubkey.Ssh_rsa pubkey) | "ssh-rsa-cert-v01@openssh.com" -> if can_be_cert then pub_ssh_rsa_cert () >>= fun ssh_rsa_cert -> return (Pubkey.Ssh_rsa_cert ssh_rsa_cert) else fail "ssh-rsa-cert-v01@openssh.com where certificates are disallowed" | "ssh-ed25519" -> pub_ssh_ed25519 >>= fun pubkey -> return (Pubkey.Ssh_ed25519 pubkey) | key_type -> pub_blob key_type let ssh_dss = let open Angstrom in Wire.mpint >>= fun p -> Wire.mpint >>= fun q -> Wire.mpint >>= fun gg -> Wire.mpint >>= fun y -> Wire.mpint >>= fun x -> Mirage_crypto_pk.Dsa.priv ~p ~q ~gg ~y ~x () |> angstrom_of_result "Mirage_crypto_pk.Dsa.priv" let ssh_rsa = let open Angstrom in Wire.mpint >>= fun _n -> Wire.mpint >>= fun e -> Wire.mpint >>= fun _d -> Wire.mpint >>= fun _iqmp -> Wire.mpint >>= fun p -> Wire.mpint >>= fun q -> (* FIXME: How do the parameters correspond to Mirage_crypto_pk.Rsa.priv ? *) Mirage_crypto_pk.Rsa.priv_of_primes ~e ~p ~q |> angstrom_of_result "Mirage_crypto_pk.Rsa.priv_of_primes" let ssh_rsa_cert = let open Angstrom in parse_lift Wire.string ( Wire.string >>= function | "ssh-rsa-cert-v01@openssh.com" -> pub_ssh_rsa_cert () | _ as keytype -> fail ("Wrong pubkey type: " ^ String.escaped keytype)) >>= fun cert -> Wire.mpint >>= fun _d -> Wire.mpint >>= fun _iqmp -> Wire.mpint >>= fun p -> Wire.mpint >>= fun q -> let e = cert.Pubkey.to_be_signed.Pubkey.pubkey.e in Mirage_crypto_pk.Rsa.priv_of_primes ~e ~p ~q |> angstrom_of_result "Mirage_crypto_pk.Rsa.priv_of_primes" >>= fun priv -> return (priv, cert) let ssh_ed25519 = let open Angstrom in Wire.string >>= fun pubkey -> Wire.string >>= fun privkey_pubkey -> let* () = if String.length pubkey <> 32 then fail "bad ssh-ed25519 key" else if String.length privkey_pubkey <> 64 then fail "bad ssh-ed25519 key" else return () in let pubkey' = String.sub privkey_pubkey 32 32 in let privkey = String.sub privkey_pubkey 0 32 in let* () = if not (String.equal pubkey pubkey') then fail "bad ssh-ed25519 key" else return () in let* privkey = Mirage_crypto_ec.Ed25519.priv_of_cstruct (Cstruct.of_string privkey) |> Result.map_error mirage_crypto_ec_error_to_msg |> angstrom_of_result "bad ssh-ed25519 key" in let pubkey' = Mirage_crypto_ec.Ed25519.pub_of_priv privkey in let* () = if Cstruct.equal (Cstruct.of_string pubkey) (Mirage_crypto_ec.Ed25519.pub_to_cstruct pubkey') then return () else fail "bad ssh-ed25519 key" in return privkey let blob key_type = let open Angstrom in take_while (fun _ -> true) >>= fun key_blob -> return (Privkey.Blob { key_type; key_blob }) let privkey = let open Angstrom in Wire.string >>= function | "ssh-dss" -> ssh_dss >>= fun priv -> return (Privkey.Ssh_dss priv) | "ssh-rsa" -> ssh_rsa >>= fun priv -> return (Privkey.Ssh_rsa priv) | "ssh-rsa-cert-v01@openssh.com" -> ssh_rsa_cert >>= fun (priv, cert) -> return (Privkey.Ssh_rsa_cert (priv, cert)) | "ssh-ed25519" -> ssh_ed25519 >>= fun priv -> return (Privkey.Ssh_ed25519 priv) | key_type -> blob key_type let comment = Wire.string let id_entry = let open Angstrom in parse_lift Wire.string (pubkey true) >>= fun pubkey -> Wire.string >>= fun comment -> return { pubkey; comment } let ssh_agent_identities_answer = let open Angstrom in BE.any_int32 >>= fun nkeys -> count32 nkeys id_entry let ssh_agent_sign_response = let open Angstrom in Wire.string >>= fun signature -> return (Ssh_agent_sign_response signature) let ssh_agent_extension_failure = let open Angstrom in Angstrom.any_uint8 >>| Protocol_number.int_to_ssh_agent >>= let open Protocol_number in function | Some SSH_AGENT_FAILURE -> return (Any_response Ssh_agent_failure) | Some SSH_AGENT_EXTENSION_FAILURE -> return (Any_response Ssh_agent_extension_failure) | _ -> fail "Goto extension blob" let ssh_agent_message_type extension = let open Angstrom in if extension then ssh_agent_extension_failure <|> (take_while (fun _ -> true) >>= fun data -> return (Any_response (Ssh_agent_extension_blob data))) else Angstrom.any_uint8 >>| Protocol_number.int_to_ssh_agent >>= let open Protocol_number in function | Some SSH_AGENT_FAILURE -> return (Any_response Ssh_agent_failure) | Some SSH_AGENT_SUCCES -> return (Any_response Ssh_agent_success) | Some SSH_AGENT_IDENTITIES_ANSWER -> ssh_agent_identities_answer >>| fun identities -> Any_response (Ssh_agent_identities_answer identities) | Some SSH_AGENT_SIGN_RESPONSE -> ssh_agent_sign_response >>| fun r -> Any_response r | Some SSH_AGENT_EXTENSION_FAILURE -> return (Any_response (Ssh_agent_extension_failure)) | Some protocol_number -> fail ("Unimplemeted protocol number: " ^ ssh_agent_to_string protocol_number) | None -> fail "Unknown ssh-agent protocol number" let ssh_agent_message ~extension = let open Angstrom in BE.any_int32 >>= fun msg_len -> parse_lift (take32 msg_len) (ssh_agent_message_type extension) let ssh_agentc_sign_request = let open Angstrom in parse_lift Wire.string (pubkey true) >>= fun pubkey -> Wire.string >>= fun data -> Wire.uint32 >>= fun mask -> let flags = Protocol_number.mask_to_sign_flags (Int32.to_int mask) in return (Ssh_agentc_sign_request (pubkey, data, flags)) let key_constraint = let open Angstrom in any_uint8 >>= function | 1 -> Wire.uint32 >>= fun secs -> return (Lifetime secs) | 2 -> return Confirm | _ -> fail "Unsupported key constraint type" let ssh_agentc_add_identity = let open Angstrom in privkey >>= fun privkey -> Wire.string >>= fun key_comment -> return (Ssh_agentc_add_identity { privkey; key_comment }) let ssh_agentc_add_id_constrained = let open Angstrom in privkey >>= fun privkey -> Wire.string >>= fun key_comment -> many key_constraint >>= fun key_constraints -> return (Ssh_agentc_add_id_constrained { privkey; key_comment; key_constraints }) let ssh_agentc_remove_identity = let open Angstrom in parse_lift Wire.string (pubkey true) >>= fun pubkey -> return (Ssh_agentc_remove_identity pubkey) let ssh_agentc_add_smartcard_key = let open Angstrom in Wire.string >>= fun smartcard_id -> Wire.string >>= fun smartcard_pin -> return (Ssh_agentc_add_smartcard_key { smartcard_id; smartcard_pin }) let ssh_agentc_add_smartcard_key_constrained = let open Angstrom in Wire.string >>= fun smartcard_id -> Wire.string >>= fun smartcard_pin -> many key_constraint >>= fun smartcard_constraints -> return (Ssh_agentc_add_smartcard_key_constrained { smartcard_id; smartcard_pin; smartcard_constraints }) let ssh_agentc_remove_smartcard_key = let open Angstrom in Wire.string >>= fun smartcard_reader_id -> Wire.string >>= fun smartcard_reader_pin -> return (Ssh_agentc_remove_smartcard_key { smartcard_reader_id; smartcard_reader_pin }) let ssh_agentc_lock = let open Angstrom in Wire.string >>= fun passphrase -> return (Ssh_agentc_lock passphrase) let ssh_agentc_unlock = let open Angstrom in Wire.string >>= fun passphrase -> return (Ssh_agentc_unlock passphrase) let ssh_agentc_extension = let open Angstrom in Wire.string >>= fun extension_type -> take_while (fun _ -> true) >>= fun extension_contents -> return (Ssh_agentc_extension { extension_type; extension_contents }) let ssh_agentc_message_type = let open Angstrom in let req p = p >>| fun r -> Any_request r in any_uint8 >>| Protocol_number.int_to_ssh_agent >>= let open Protocol_number in function | Some SSH_AGENTC_REQUEST_IDENTITIES -> return (Any_request Ssh_agentc_request_identities) | Some SSH_AGENTC_SIGN_REQUEST -> req ssh_agentc_sign_request | Some SSH_AGENTC_ADD_IDENTITY -> req ssh_agentc_add_identity | Some SSH_AGENTC_REMOVE_IDENTITY -> req ssh_agentc_remove_identity | Some SSH_AGENTC_REMOVE_ALL_IDENTITIES -> return (Any_request Ssh_agentc_remove_all_identities) | Some SSH_AGENTC_ADD_SMARTCARD_KEY -> req ssh_agentc_add_smartcard_key | Some SSH_AGENTC_REMOVE_SMARTCARD_KEY -> req ssh_agentc_remove_smartcard_key | Some SSH_AGENTC_LOCK -> req ssh_agentc_lock | Some SSH_AGENTC_UNLOCK -> req ssh_agentc_unlock | Some SSH_AGENTC_ADD_ID_CONSTRAINED -> req ssh_agentc_add_id_constrained | Some SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED -> req ssh_agentc_add_smartcard_key_constrained | Some SSH_AGENTC_EXTENSION -> req ssh_agentc_extension | None | Some _ -> fail "Not an ssh-agent request" let ssh_agentc_message = let open Angstrom in BE.any_int32 >>= fun msg_len -> parse_lift (take32 msg_len) ssh_agentc_message_type