From 94573d7ce5f7cf7755f7ad7646363fc4b8a9c59d Mon Sep 17 00:00:00 2001 From: Kraemii Date: Mon, 19 Aug 2024 07:46:57 +0200 Subject: [PATCH] Add: NASL bultin functions for certificate handling Added functions: cert_open, cert_query, cert_close --- rust/Cargo.lock | 302 ++++++++++++++++----- rust/Cargo.toml | 1 + rust/nasl-builtin-cert/Cargo.toml | 19 ++ rust/nasl-builtin-cert/README.md | 6 + rust/nasl-builtin-cert/src/lib.rs | 419 ++++++++++++++++++++++++++++++ rust/nasl-builtin-std/Cargo.toml | 1 + rust/nasl-builtin-std/src/lib.rs | 3 +- rust/typos.toml | 8 +- 8 files changed, 687 insertions(+), 72 deletions(-) create mode 100644 rust/nasl-builtin-cert/Cargo.toml create mode 100644 rust/nasl-builtin-cert/README.md create mode 100644 rust/nasl-builtin-cert/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 40134830a..118ac5ad1 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -139,9 +133,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" [[package]] name = "ascii-canvas" @@ -152,6 +146,45 @@ dependencies = [ "term", ] +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "async-trait" version = "0.1.82" @@ -177,9 +210,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "aws-lc-rs" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae74d9bd0a7530e8afd1770739ad34b36838829d6ad61818f9230f683f5ad77" +checksum = "2f95446d919226d587817a7d21379e6eb099b97b45110a7f272a444ca5c54070" dependencies = [ "aws-lc-sys", "mirai-annotations", @@ -189,9 +222,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0e249228c6ad2d240c2dc94b714d711629d52bad946075d8e9b2f5391f0703" +checksum = "5055edc4a9a1b2a917a818258cdfb86a535947feebd9981adc99667a062c6f85" dependencies = [ "bindgen", "cc", @@ -204,17 +237,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -235,6 +268,16 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bcder" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627747a6774aab38beb35990d88309481378558875a41da1a4b2e373c906ef0" +dependencies = [ + "bytes", + "smallvec", +] + [[package]] name = "bindgen" version = "0.69.4" @@ -390,9 +433,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" dependencies = [ "jobserver", "libc", @@ -501,9 +544,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -511,9 +554,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -605,9 +648,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -727,6 +770,12 @@ dependencies = [ "cipher", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "dbl" version = "0.3.2" @@ -758,6 +807,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.3.11" @@ -972,7 +1035,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -1154,9 +1217,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "glob" @@ -1389,9 +1452,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", @@ -1408,9 +1471,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" dependencies = [ "bytes", "futures-channel", @@ -1627,9 +1690,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "ipnetwork" @@ -1994,15 +2057,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -2042,6 +2096,20 @@ dependencies = [ "uuid", ] +[[package]] +name = "nasl-builtin-cert" +version = "0.1.0" +dependencies = [ + "nasl-builtin-string", + "nasl-builtin-utils", + "nasl-function-proc-macro", + "nasl-interpreter", + "nasl-syntax", + "storage", + "x509-certificate", + "x509-parser", +] + [[package]] name = "nasl-builtin-cryptographic" version = "0.1.0" @@ -2206,6 +2274,7 @@ name = "nasl-builtin-std" version = "0.1.0" dependencies = [ "models", + "nasl-builtin-cert", "nasl-builtin-cryptographic", "nasl-builtin-description", "nasl-builtin-host", @@ -2351,12 +2420,31 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2385,6 +2473,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -2488,7 +2585,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls 0.27.3", "hyper-util", "infisto", "lazy_static", @@ -2600,6 +2697,16 @@ dependencies = [ "windows-sys 0.36.1", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -2701,9 +2808,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -2714,15 +2821,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -3117,11 +3224,20 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" dependencies = [ "bitflags 2.6.0", "errno 0.3.9", @@ -3151,7 +3267,7 @@ dependencies = [ "log", "ring", "rustls-pki-types", - "rustls-webpki 0.102.7", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -3166,16 +3282,16 @@ dependencies = [ "log", "once_cell", "rustls-pki-types", - "rustls-webpki 0.102.7", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", "rustls-pemfile 2.1.3", @@ -3221,9 +3337,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.7" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "aws-lc-rs", "ring", @@ -3288,11 +3404,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3404,18 +3520,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -3424,9 +3540,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -3527,6 +3643,15 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -3776,6 +3901,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", @@ -3906,9 +4032,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -4606,6 +4732,42 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "x509-certificate" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66534846dec7a11d7c50a74b7cdb208b9a581cad890b7866430d438455847c85" +dependencies = [ + "bcder", + "bytes", + "chrono", + "der", + "hex", + "pem", + "ring", + "signature", + "spki", + "thiserror", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + [[package]] name = "xxhash-rust" version = "0.8.12" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6aff1f507..6ba0a6524 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,7 @@ [workspace] resolver = "2" members = [ + "nasl-builtin-cert", "nasl-builtin-knowledge-base", "nasl-builtin-raw-ip", "nasl-builtin-cryptographic", diff --git a/rust/nasl-builtin-cert/Cargo.toml b/rust/nasl-builtin-cert/Cargo.toml new file mode 100644 index 000000000..56b964b0d --- /dev/null +++ b/rust/nasl-builtin-cert/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "nasl-builtin-cert" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nasl-builtin-utils = { path = "../nasl-builtin-utils" } +nasl-builtin-string = { path = "../nasl-builtin-string" } +nasl-function-proc-macro = { path = "../nasl-function-proc-macro" } +nasl-syntax = { path = "../nasl-syntax" } +storage = { path = "../storage" } + +x509-certificate = "0.23.1" +x509-parser = "0.16.0" + +[dev-dependencies] +nasl-interpreter = { path = "../nasl-interpreter" } diff --git a/rust/nasl-builtin-cert/README.md b/rust/nasl-builtin-cert/README.md new file mode 100644 index 000000000..82117fdce --- /dev/null +++ b/rust/nasl-builtin-cert/README.md @@ -0,0 +1,6 @@ +## Implements +- cert_close +- cert_open +- cert_query + +## Missing diff --git a/rust/nasl-builtin-cert/src/lib.rs b/rust/nasl-builtin-cert/src/lib.rs new file mode 100644 index 000000000..ab9a11ee7 --- /dev/null +++ b/rust/nasl-builtin-cert/src/lib.rs @@ -0,0 +1,419 @@ +// SPDX-FileCopyrightText: 2024 Greenbone AG +// +// SPDX-License-Identifier: GPL-2.0-or-later + +use std::sync::RwLock; + +use nasl_builtin_string::encode_hex; +use nasl_builtin_utils::error::FunctionErrorKind; +use nasl_builtin_utils::function_set; +use nasl_function_proc_macro::nasl_function; +use nasl_syntax::NaslValue; +use x509_certificate::X509Certificate; +use x509_parser::prelude::GeneralName; + +#[derive(Default)] +struct Handles { + certs: Vec>, + closed_fd: Vec, +} + +#[derive(Default)] +pub struct NaslCerts(RwLock); + +fn sign_alg_oid_to_name(oid: &str) -> String { + match oid { + "1.2.840.10040.4.1" => "id-dsa", + "1.2.840.10046.2.1" => "dhpublicnumber", + "2.16.840.1.101.2.1.1.22" => "id-keyExchangeAlgorithm", + "1.2.840.10045.1.1" => "prime-field", + "1.2.840.10045.2.1" => "id-ecPublicKey", + "1.2.840.10045.4.1" => "ecdsa-with-SHA1", + "1.2.840.10045.4.3.1" => "ecdsa-with-SHA224", + "1.2.840.10045.4.3.2" => "ecdsa-with-SHA256", + "1.2.840.10045.4.3.3" => "ecdsa-with-SHA384", + "1.2.840.10045.4.3.4" => "ecdsa-with-SHA512", + "1.3.132.1.12" => "id-ecDH", + "1.2.840.10045.2.13" => "id-ecMQV", + "1.2.840.113549.1.1.10" => "id-RSASSA-PSS", + "1.2.840.113549.1.1.11" => "sha256WithRSAEncryption", + "1.2.840.113549.1.1.12" => "sha384WithRSAEncryption", + "1.2.840.113549.1.1.13" => "sha512WithRSAEncryption", + "1.2.840.113549.1.1.14" => "sha224WithRSAEncryption", + "1.2.840.113549.1.1.8" => "id-mgf1", + "1.2.840.113549.2.2" => "md2", + "1.2.840.113549.2.4" => "md4", + "1.2.840.113549.2.5" => "md5", + "1.2.840.113549.1.1.1" => "rsaEncryption", + "1.2.840.113549.1.1.2" => "md2WithRSAEncryption", + "1.2.840.113549.1.1.3" => "md4WithRSAEncryption", + "1.2.840.113549.1.1.4" => "md5WithRSAEncryption", + "1.2.840.113549.1.1.6" => "rsaOAEPEncryptionSET", + "1.2.840.10045.3.1.1" => "secp192r1", + "1.3.132.0.1" => "sect163k1", + "1.3.132.0.15" => "sect163r2", + "1.3.132.0.33" => "secp224r1", + "1.3.132.0.26" => "sect233k1", + "1.3.132.0.27" => "sect233r1", + "1.2.840.10045.3.1.7" => "secp256r1", + "1.3.132.0.16" => "sect283k1", + "1.3.132.0.17" => "sect283r1", + "1.3.132.0.34" => "secp384r1", + "1.3.132.0.36" => "sect409k1", + "1.3.132.0.37" => "sect409r1", + "1.3.132.0.35" => "sect521r1", + "1.3.132.0.38" => "sect571k1", + "1.3.132.0.39" => "sect571r1", + "2.16.840.1.101.3.4.3.1" => "id-dsa-with-sha224", + "2.16.840.1.101.3.4.3.2" => "id-dsa-with-sha256", + "2.16.840.1.101.3.4.2.1" => "sha256", + "2.16.840.1.101.3.4.2.2" => "sha384", + "2.16.840.1.101.3.4.2.3" => "sha512", + "2.16.840.1.101.3.4.2.4" => "sha224", + _ => "unknown", + } + .to_string() +} + +fn pub_key_alg_oid_to_name(name: &str) -> String { + match name { + "1.2.840.113549.1.1.1" => "RSA", + "2.5.8.1.1" => "RSA (X.509)", + "1.2.840.113549.1.1.4" => "RSA (MD5)", + "1.2.840.113549.1.1.5" => "RSA (SHA1)", + "1.2.840.10040.4.1" => "DSA", + "1.2.643.2.2.19" => "GOST R 34.10-2001", + "1.2.643.2.2.20" => "GOST R 34.10-94", + "1.2.840.10045.2.1" => "EC", + _ => "unknown", + } + .to_string() +} + +fn subject_oid_to_name(oid: &str) -> String { + match oid { + "2.5.4.6" => "C", + "2.5.4.8" => "ST", + "2.5.4.7" => "L", + "2.5.4.10" => "O", + "2.5.4.3" => "CN", + "2.5.4.11" => "OU", + "2.5.4.12" => "T", + "2.5.4.42" => "GN", + "2.5.4.43" => "I", + "2.5.4.4" => "SN", + _ => oid, + } + .to_string() +} + +impl NaslCerts { + /// Create a certificate object. + /// + /// Takes a string/data as unnamed argument and returns an identifier + /// used with the other cert functions. The data is usually the BER + /// encoded certificate but the function will also try a PEM encoding + /// on failure to parse BER encoded one. + /// + /// On success the function returns a cert identifier that can be used + /// for further operations. + #[nasl_function] + fn cert_open(&self, cert: &[u8]) -> Result { + if let Ok(cert) = X509Certificate::from_der(cert) { + let mut handle = self.0.write().unwrap(); + if let Some(fd) = handle.closed_fd.pop() { + handle.certs[fd] = Some(cert); + return Ok(fd); + } + handle.certs.push(Some(cert)); + return Ok(handle.certs.len() - 1); + } + + Err(FunctionErrorKind::WrongArgument( + "The given string is not a valid DER encoded X.509 certificate.".to_string(), + )) + } + + /// Release a certificate object. + /// + /// Takes a cert identifier as returned by cert_open and releases the + /// associated resources. + #[nasl_function] + fn cert_close(&self, fd: usize) -> Result<(), FunctionErrorKind> { + let mut handle = self.0.write().unwrap(); + match handle.certs.get(fd) { + Some(Some(_)) => { + handle.certs[fd] = None; + handle.closed_fd.push(fd); + } + Some(None) => { + return Err(FunctionErrorKind::WrongArgument( + "The given file descriptor is already closed.".to_string(), + )); + } + None => { + return Err(FunctionErrorKind::WrongArgument( + "The given file descriptor is not valid.".to_string(), + )); + } + }; + Ok(()) + } + + fn subject(cert: &X509Certificate, idx: usize) -> Option { + // The error originates from the io::Write trait. Internally a Vec is used, which + // implementation of that trait is infallible. Therefore we can unwrap here. + let der = cert.encode_der().unwrap(); + let (_, cert) = x509_parser::parse_x509_certificate(&der).unwrap(); + + if idx == 0 { + Some(cert.subject.to_string()) + } else { + cert.subject_alternative_name() + .ok() + .flatten() + .and_then(|san| san.value.general_names.get(idx - 1)) + .map(|san| Some(san.to_string())) + .unwrap_or(None) + } + } + + fn issuer(cert: &X509Certificate, idx: usize) -> Option { + let subject = cert.issuer_name(); + subject.get(idx).map(|entry| { + entry + .iter() + .filter_map(|val| { + val.value.to_string().ok().map(|value| { + format!("{}={}", subject_oid_to_name(&val.typ.to_string()), value) + }) + }) + .collect::>() + .join(", ") + }) + } + + fn hostnames(cert: &X509Certificate) -> Vec { + let mut ret = vec![]; + if let Some(cn) = cert.subject_common_name() { + ret.push(cn); + } + + let der = cert.encode_der().unwrap(); + let (_, cert) = x509_parser::parse_x509_certificate(&der).unwrap(); + + if let Ok(Some(san)) = cert.subject_alternative_name() { + for name in san.value.general_names.iter() { + if let GeneralName::DNSName(dns) = name { + ret.push(dns.to_string()); + } + } + } + + ret + } + + fn key_size(cert: &X509Certificate) -> Option { + if let Some(algorithm) = cert.key_algorithm() { + match algorithm { + x509_certificate::KeyAlgorithm::Rsa => { + if let Ok(data) = cert.rsa_public_key_data() { + return Some(((data.modulus.into_bytes().len() - 1) * 8) as i64); + } + } + _ => { + if let Ok(data) = cert.rsa_public_key_data() { + return Some((data.public_exponent.into_bytes().len() * 8) as i64); + } + } + } + } + None + } + + /// Query a certificate object. + /// + /// Takes a cert identifier as first unnamed argument and a command + /// string as second argument. That command is used to select specific + /// information from the certificate. For certain commands the named + /// argument @a idx is used as well. Depending on this command the + /// return value may be a number, a string, or an array of strings. + /// Supported commands are: + /// + /// - serial The serial number of the certificate as a hex string. + /// + /// - issuer Returns the issuer. The returned value is a string in + /// rfc-2253 format. + + /// - subject Returns the subject. The returned value is a string in + /// rfc-2253 format. To query the subjectAltName the + /// named parameters @a idx with values starting at 1 can + /// be used. In this case the format is either an rfc2253 + /// string as used above, an rfc2822 mailbox name + /// indicated by the first character being a left angle + /// bracket or an S-expression in advanced format for all + /// other types of subjectAltnames which is indicated by + /// an opening parentheses. + /// + /// - not-before The notBefore time as UTC value in ISO time format + /// (e.g. "20120930T143521"). + /// + /// - not-after The notAfter time as UTC value in ISO time format + /// (e.g. "20280929T143520"). + /// + /// - all Return all available information in a human readable + /// format. Not yet implemented. + /// + /// - hostnames Return an array with all hostnames listed in the + /// certificates, i.e. the CN part of the subject and all dns-name + /// type subjectAltNames. + /// + /// - fpr-sha-256 The SHA-256 fingerprint of the certificate. The + /// fingerprint is, as usual, computed over the entire + /// DER encode certificate. + /// + /// - fpr-sha-1 The SHA-1 fingerprint of the certificate. The + /// fingerprint is, as usual, computed over the entire + /// DER encode certificate. + /// + /// - image Return the entire certificate as binary data. + /// + /// - algorithm-name Same as signature-algorithm-name. TODO: Remove it and + /// leave only signature-algorithm-name. + /// + /// - signature-algorithm-name Return the algorithm name used to sign the + /// certificate. Get the OID of the digest + /// algorithm and translated to a name from a + /// list from Wireshark. + /// See epan/dissectors/packet-pkcs1.c + /// + /// - public-key-algorithm-name Return the algorithm name of the public key. + /// + /// - modulus Return the RSA public key's modulus found in the + /// structure of the given cert. + /// + /// - exponent Return the RSA public key's exponent found in + /// the structure of the given cert. + /// + /// - key-size Return the size to hold the parameters size in bits. + /// For RSA the bits returned is the modulus. + /// For DSA the bits returned are of the public exponent. + /// + /// + /// The following arguments are required: + /// - pos(0): Object id of the certificate. + /// + /// - pos(1): A string with the command to select what to return; see above. + /// + /// The following arguments are optional: + /// - idx Used by certain commands to select the n-th value of a set + /// of values. If not given 0 is assumed. + /// + /// A NASL type depending on the used command. + #[nasl_function(named(idx))] + fn cert_query( + &self, + fd: usize, + query: &str, + idx: Option, + ) -> Result { + let idx = idx.unwrap_or(0); + let handle = self.0.read().unwrap(); + if fd >= handle.certs.len() { + return Err(FunctionErrorKind::WrongArgument( + "The given file descriptor is not valid.".to_string(), + )); + } + let cert = handle.certs[fd].as_ref().ok_or_else(|| { + FunctionErrorKind::WrongArgument("The given file descriptor is not valid.".to_string()) + })?; + let result = match query { + "serial" => { + let serial = cert.serial_number_asn1().clone().into_bytes(); + NaslValue::String(encode_hex(&serial)) + } + "subject" => Self::subject(cert, idx) + .map(|x| NaslValue::String(x)) + .unwrap_or(NaslValue::Null), + "issuer" => Self::issuer(cert, idx) + .map(|x| NaslValue::String(x)) + .unwrap_or(NaslValue::Null), + "not-before" => { + let not_before = cert.validity_not_before().format("%Y%m%dT%H%M%S"); + NaslValue::String(not_before.to_string()) + } + "not-after" => { + let not_after = cert.validity_not_after().format("%Y%m%dT%H%M%S"); + NaslValue::String(not_after.to_string()) + } + "fpr-sha-256" => cert + .sha256_fingerprint() + .map(|fpr| NaslValue::String(encode_hex(fpr.as_ref()))) + .map_err(|_| { + FunctionErrorKind::Diagnostic( + "Unable to calculate SHA256 fingerprint".to_string(), + None, + ) + })?, + "fpr-sha-1" => cert + .sha1_fingerprint() + .map(|fpr| NaslValue::String(encode_hex(fpr.as_ref()))) + .map_err(|_| { + FunctionErrorKind::Diagnostic( + "Unable to calculate SHA1 fingerprint".to_string(), + None, + ) + })?, + "all" => { + return Err(FunctionErrorKind::Diagnostic( + "Query parameter 'all' is not implemented yet".to_string(), + None, + )) + } + "hostnames" => NaslValue::Array( + Self::hostnames(cert) + .into_iter() + .map(|x| NaslValue::String(x)) + .collect::>(), + ), + "image" => NaslValue::Data(cert.encode_der().unwrap_or_default()), + "algorithm-name" | "signature-algorithm-name" => { + let signature_algorithm = + sign_alg_oid_to_name(&cert.signature_algorithm_oid().to_string()); + NaslValue::String(signature_algorithm) + } + "public-key-algorithm-name" => { + let public_key_algorithm = + pub_key_alg_oid_to_name(&cert.key_algorithm_oid().to_string()); + NaslValue::String(public_key_algorithm) + } + "modulus" => cert + .rsa_public_key_data() + .map(|data| NaslValue::Data(data.modulus.into_bytes().to_vec())) + .unwrap_or(NaslValue::Null), + "exponent" => cert + .rsa_public_key_data() + .map(|data| NaslValue::Data(data.public_exponent.into_bytes().to_vec())) + .unwrap_or(NaslValue::Null), + "key-size" => Self::key_size(cert) + .map(|size| NaslValue::Number(size)) + .unwrap_or(NaslValue::Null), + _ => { + return Err(FunctionErrorKind::WrongArgument( + "The given query is not valid.".to_string(), + )) + } + }; + Ok(result) + } +} + +function_set! { + NaslCerts, + sync_stateful, + ( + (NaslCerts::cert_open, "cert_open"), + (NaslCerts::cert_close, "cert_close"), + (NaslCerts::cert_query, "cert_query"), + ) +} diff --git a/rust/nasl-builtin-std/Cargo.toml b/rust/nasl-builtin-std/Cargo.toml index ede35f31b..8e5e118be 100644 --- a/rust/nasl-builtin-std/Cargo.toml +++ b/rust/nasl-builtin-std/Cargo.toml @@ -17,6 +17,7 @@ nasl-builtin-network = { path = "../nasl-builtin-network" } nasl-builtin-misc = { path = "../nasl-builtin-misc" } nasl-builtin-regex = { path = "../nasl-builtin-regex" } nasl-builtin-isotime = { path = "../nasl-builtin-isotime" } +nasl-builtin-cert = { path = "../nasl-builtin-cert" } nasl-function-proc-macro = { path = "../nasl-function-proc-macro" } storage = { path = "../storage" } models = { path = "../models" } diff --git a/rust/nasl-builtin-std/src/lib.rs b/rust/nasl-builtin-std/src/lib.rs index 40eb7e43d..1b42d81fa 100644 --- a/rust/nasl-builtin-std/src/lib.rs +++ b/rust/nasl-builtin-std/src/lib.rs @@ -31,7 +31,8 @@ pub fn nasl_std_functions() -> Executor { .add_set(nasl_builtin_regex::RegularExpressions) .add_set(nasl_builtin_cryptographic::Cryptographic) .add_set(nasl_builtin_description::Description) - .add_set(nasl_builtin_isotime::NaslIsotime); + .add_set(nasl_builtin_isotime::NaslIsotime) + .add_set(nasl_builtin_cert::NaslCerts::default()); #[cfg(feature = "nasl-builtin-ssh")] executor.add_set(nasl_builtin_ssh::Ssh::default()); diff --git a/rust/typos.toml b/rust/typos.toml index db9381b1d..e08d06cf7 100644 --- a/rust/typos.toml +++ b/rust/typos.toml @@ -5,6 +5,12 @@ des_ede_cbc_encrypt = "des_ede_cbc_encrypt" [default.extend-words] hd = "hd" guid = "guid" +GOST = "GOST" +fpr = "fpr" [files] -extend-exclude = ["osp/tests/response_*.xml", "smoketest/configs/client_sample.cert", "*.notus"] +extend-exclude = [ + "osp/tests/response_*.xml", + "smoketest/configs/client_sample.cert", + "*.notus", +]