diff --git a/.github/workflows/tai64_update_leap_seconds.yml b/.github/workflows/tai64_update_leap_seconds.yml new file mode 100644 index 000000000..df0be3a87 --- /dev/null +++ b/.github/workflows/tai64_update_leap_seconds.yml @@ -0,0 +1,28 @@ +name: Update Leap Seconds +on: + schedule: + - cron: 0 0 * * 1 + +jobs: + update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Update leap seconds in code + run: | + curl -o leap_seconds_list -L https://data.iana.org/time-zones/data/leap-seconds.list + number=$(grep -v '^#' leap_seconds_list | tail -n1 | awk '{print $2}') + sed -i "s/\(1970-01-01 00:00:\)[0-9]\+ TAI/\1${number} TAI/" tai64/src/lib.rs + sed -i -E 's/(Self\()[0-9]+ \+ \(1 << 62\)\)/\1'"${number}"' + (1 << 62))/' tai64/src/lib.rs + rm leap_seconds_list + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + commit-message: update leap seconds in tai64 + title: Update leap seconds in tai64 + body: 'Following this source: https://data.iana.org/time-zones/data/leap-seconds.list, the leap seconds counter has been updated.' + branch: update-leap-seconds + base: master + delete-branch: true diff --git a/.github/workflows/tls_codec.yml b/.github/workflows/tls_codec.yml index 9354be5d5..d9aaa3037 100644 --- a/.github/workflows/tls_codec.yml +++ b/.github/workflows/tls_codec.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: rust: - - 1.70.0 # MSRV + - 1.74.0 # MSRV - stable target: - wasm32-unknown-unknown @@ -50,7 +50,7 @@ jobs: include: # 32-bit Linux - targets: i686-unknown-linux-gnu - rust: 1.70.0 # MSRV + rust: 1.74.0 # MSRV deps: sudo apt update && sudo apt install gcc-multilib - targets: i686-unknown-linux-gnu rust: stable @@ -58,7 +58,7 @@ jobs: # 64-bit Linux - targets: x86_64-unknown-linux-gnu - rust: 1.70.0 # MSRV + rust: 1.74.0 # MSRV - targets: x86_64-unknown-linux-gnu rust: stable steps: diff --git a/Cargo.lock b/Cargo.lock index 34b6f2fbc..4764d1557 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,58 +68,58 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.3.2" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.2" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "1.0.2" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] @@ -151,7 +151,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -203,18 +203,18 @@ dependencies = [ [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" @@ -224,18 +224,18 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" -version = "0.11.0-rc.2" +version = "0.11.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "939c0e62efa052fb0b2db2c0f7c479ad32e364c192c3aab605a7641de265a1a7" +checksum = "3fd016a0ddc7cb13661bf5576073ce07330a693f8608a1320b4e20561cc12cdc" dependencies = [ "hybrid-array", ] [[package]] name = "block-padding" -version = "0.4.0-rc.1" +version = "0.4.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cac2491ec009b98aa75f36cca2b50e3da7d212918fe953886f6a319042f6016" +checksum = "6868e23cd7a5b2e18fb2e9a583910b88b8d645dd21017aafc5d0439cf16ae6d6" dependencies = [ "hybrid-array", ] @@ -248,9 +248,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cast" @@ -312,18 +312,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.23" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03aef18ddf7d879c15ce20f04826ef8418101c7e528014c3eeea13321047dca3" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.3.23" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ce6fffb678c9b80a70b6b6de0aad31df727623a70fd9a842c30cd573e2fa98" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -333,9 +333,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "cmpv2" @@ -380,23 +380,25 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "const-oid" -version = "0.10.0-rc.2" +version = "0.10.0-rc.3" dependencies = [ "arbitrary", "hex-literal", + "proptest", + "regex", ] [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -521,9 +523,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", @@ -599,9 +601,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys 0.52.0", @@ -609,9 +611,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "ff" @@ -759,9 +761,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "group" @@ -796,9 +798,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hermit-abi" @@ -823,9 +825,9 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.2.0-rc.11" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5a41e5b0754cae5aaf7915f1df1147ba8d316fc6e019cfcc00fbaba96d5e030" +checksum = "f2d35805454dc9f8662a98d6d61886ffe26bd465f5960e0e55345c70d5c0d2a9" dependencies = [ "typenum", "zeroize", @@ -833,9 +835,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", @@ -843,9 +845,9 @@ dependencies = [ [[package]] name = "inout" -version = "0.2.0-rc.1" +version = "0.2.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ac07241f4d11c21b6d82f1fef1c05aec030c0bf568b35281efe453ea450a7" +checksum = "de49db00f5add6dad75a57946b75de0f26287a6fc95f4f277d48419200422beb" dependencies = [ "block-padding", "hybrid-array", @@ -862,6 +864,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -873,9 +881,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "keccak" @@ -897,15 +905,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.159" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linux-raw-sys" @@ -921,9 +929,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] @@ -983,9 +991,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -1045,9 +1053,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -1163,18 +1171,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", "bit-vec", @@ -1198,9 +1206,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1246,9 +1254,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1258,9 +1266,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1379,9 +1387,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", @@ -1455,15 +1463,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] @@ -1480,9 +1488,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -1491,9 +1499,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", @@ -1512,7 +1520,7 @@ dependencies = [ [[package]] name = "serdect" -version = "0.3.0-rc.0" +version = "0.3.0" dependencies = [ "base16ct", "bincode", @@ -1604,9 +1612,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -1616,9 +1624,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.79" +version = "2.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3" dependencies = [ "proc-macro2", "quote", @@ -1627,23 +1635,29 @@ dependencies = [ [[package]] name = "tai64" -version = "5.0.0-pre" +version = "4.1.0" dependencies = [ "serde", "zeroize", ] +[[package]] +name = "target-triple" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" + [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1657,9 +1671,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "num-conv", @@ -1722,9 +1736,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.40.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "pin-project-lite", @@ -1778,14 +1792,15 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" +checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" dependencies = [ "glob", "serde", "serde_derive", "serde_json", + "target-triple", "termcolor", "toml", ] @@ -1804,9 +1819,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "universal-hash" @@ -1864,16 +1879,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-sys 0.52.0", ] [[package]] @@ -1882,7 +1888,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1891,22 +1897,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -1915,46 +1906,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1967,48 +1940,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2017,9 +1966,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "e6f5bb5257f2407a5425c6e749bfd9692192a73e70a6060516ac04f889087d68" dependencies = [ "memchr", ] diff --git a/base32ct/Cargo.toml b/base32ct/Cargo.toml index 57124e529..6686e2efb 100644 --- a/base32ct/Cargo.toml +++ b/base32ct/Cargo.toml @@ -19,7 +19,7 @@ rust-version = "1.65" [dev-dependencies] base32 = "0.5" -proptest = { version = "1.5", default-features = false, features = ["std"] } +proptest = { version = "1.6", default-features = false, features = ["std"] } [features] alloc = [] diff --git a/base64ct/Cargo.toml b/base64ct/Cargo.toml index fae4f38a5..f07a13362 100644 --- a/base64ct/Cargo.toml +++ b/base64ct/Cargo.toml @@ -19,7 +19,7 @@ rust-version = "1.65" [dev-dependencies] base64 = "0.22" -proptest = { version = "1.5", default-features = false, features = ["std"] } +proptest = { version = "1.6", default-features = false, features = ["std"] } [features] alloc = [] diff --git a/base64ct/src/alphabet/bcrypt.rs b/base64ct/src/alphabet/bcrypt.rs index 4227dbfcf..b6eee8b66 100644 --- a/base64ct/src/alphabet/bcrypt.rs +++ b/base64ct/src/alphabet/bcrypt.rs @@ -8,7 +8,7 @@ use super::{Alphabet, DecodeStep, EncodeStep}; /// ./ [A-Z] [a-z] [0-9] /// 0x2e-0x2f, 0x41-0x5a, 0x61-0x7a, 0x30-0x39 /// ``` -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Base64Bcrypt; impl Alphabet for Base64Bcrypt { diff --git a/base64ct/src/alphabet/crypt.rs b/base64ct/src/alphabet/crypt.rs index 5d97c33ac..96eb0653b 100644 --- a/base64ct/src/alphabet/crypt.rs +++ b/base64ct/src/alphabet/crypt.rs @@ -8,7 +8,7 @@ use super::{Alphabet, DecodeStep, EncodeStep}; /// [.-9] [A-Z] [a-z] /// 0x2e-0x39, 0x41-0x5a, 0x61-0x7a /// ``` -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Base64Crypt; impl Alphabet for Base64Crypt { diff --git a/base64ct/src/alphabet/shacrypt.rs b/base64ct/src/alphabet/shacrypt.rs index ef8d362f9..fd3d742f0 100644 --- a/base64ct/src/alphabet/shacrypt.rs +++ b/base64ct/src/alphabet/shacrypt.rs @@ -12,7 +12,7 @@ use super::{Alphabet, DecodeStep, EncodeStep}; /// [.-9] [A-Z] [a-z] /// 0x2e-0x39, 0x41-0x5a, 0x61-0x7a /// ``` -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Base64ShaCrypt; impl Alphabet for Base64ShaCrypt { diff --git a/base64ct/src/alphabet/standard.rs b/base64ct/src/alphabet/standard.rs index 90eab69f1..0110aea21 100644 --- a/base64ct/src/alphabet/standard.rs +++ b/base64ct/src/alphabet/standard.rs @@ -8,7 +8,7 @@ use super::{Alphabet, DecodeStep, EncodeStep}; /// [A-Z] [a-z] [0-9] + / /// 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f /// ``` -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Base64; impl Alphabet for Base64 { @@ -25,7 +25,7 @@ impl Alphabet for Base64 { /// [A-Z] [a-z] [0-9] + / /// 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f /// ``` -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Base64Unpadded; impl Alphabet for Base64Unpadded { diff --git a/base64ct/src/alphabet/url.rs b/base64ct/src/alphabet/url.rs index 432edb852..55bbf9ceb 100644 --- a/base64ct/src/alphabet/url.rs +++ b/base64ct/src/alphabet/url.rs @@ -8,7 +8,7 @@ use super::{Alphabet, DecodeStep, EncodeStep}; /// [A-Z] [a-z] [0-9] - _ /// 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2d, 0x5f /// ``` -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Base64Url; impl Alphabet for Base64Url { @@ -25,7 +25,7 @@ impl Alphabet for Base64Url { /// [A-Z] [a-z] [0-9] - _ /// 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2d, 0x5f /// ``` -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Base64UrlUnpadded; impl Alphabet for Base64UrlUnpadded { diff --git a/cmpv2/src/body.rs b/cmpv2/src/body.rs index 829790c28..f656d6c09 100644 --- a/cmpv2/src/body.rs +++ b/cmpv2/src/body.rs @@ -69,7 +69,7 @@ pub enum PkiBody<'a> { #[asn1(context_specific = "6", tag_mode = "EXPLICIT", constructed = "true")] Popdecr(PopoDecKeyRespContent<'a>), #[asn1(context_specific = "7", tag_mode = "EXPLICIT", constructed = "true")] - KUr(CertReqMessages), + Kur(CertReqMessages), #[asn1(context_specific = "8", tag_mode = "EXPLICIT", constructed = "true")] Kup(CertRepMessage<'a>), #[asn1(context_specific = "9", tag_mode = "EXPLICIT", constructed = "true")] diff --git a/cmpv2/src/status.rs b/cmpv2/src/status.rs index 64bf11456..514063470 100644 --- a/cmpv2/src/status.rs +++ b/cmpv2/src/status.rs @@ -193,9 +193,9 @@ pub struct PkiStatusInfo<'a> { #[derive(Clone, Debug, Eq, PartialEq, Sequence)] #[allow(missing_docs)] pub struct ErrorMsgContent<'a> { - pki_status_info: PkiStatusInfo<'a>, - error_code: Option, - error_details: Option>, + pub pki_status_info: PkiStatusInfo<'a>, + pub error_code: Option, + pub error_details: Option>, } /// The `CertConfirmContent` type is defined in [RFC 4210 Section 5.2.18]. diff --git a/cms/Cargo.toml b/cms/Cargo.toml index 1ceaf952b..c027b9e27 100644 --- a/cms/Cargo.toml +++ b/cms/Cargo.toml @@ -43,7 +43,7 @@ rand = "0.8.5" rsa = { version = "=0.10.0-pre.3", features = ["sha2"] } ecdsa = { version = "=0.17.0-pre.9", features = ["digest", "pem"] } p256 = "=0.14.0-pre.2" -tokio = { version = "1.40.0", features = ["macros", "rt"] } +tokio = { version = "1.42.0", features = ["macros", "rt"] } x509-cert = { version = "=0.3.0-pre.0", features = ["pem"] } [features] diff --git a/const-oid/Cargo.toml b/const-oid/Cargo.toml index 50e7a878b..b11f9b91d 100644 --- a/const-oid/Cargo.toml +++ b/const-oid/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "const-oid" -version = "0.10.0-rc.2" +version = "0.10.0-rc.3" authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" description = """ @@ -18,10 +18,12 @@ edition = "2021" rust-version = "1.81" [dependencies] -arbitrary = { version = "1.2", optional = true, features = ["derive"] } +arbitrary = { version = "1.4", optional = true, features = ["derive"] } [dev-dependencies] hex-literal = "0.4" +proptest = "1" +regex = "1" [features] db = [] diff --git a/const-oid/src/arcs.rs b/const-oid/src/arcs.rs index 95cbbe0ef..7e5056cee 100644 --- a/const-oid/src/arcs.rs +++ b/const-oid/src/arcs.rs @@ -1,21 +1,21 @@ //! Arcs are integer values which exist within an OID's hierarchy. use crate::{Error, Result}; -use core::mem::size_of; #[cfg(doc)] use crate::ObjectIdentifier; -/// Type alias used to represent an "arc" (i.e. integer identifier value). +/// Type alias used to represent an "arc", i.e. integer identifier value, where an OID comprises a +/// sequence of arcs. /// -/// X.660 does not define a maximum size of an arc. +/// X.660 does not define a maximum size of an arc. We instead follow Mozilla* conventions for +/// maximum values of an arc, with a maximum value of 2^32-1 (4294967295), a.k.a. [`u32::MAX`] +/// with [`Arc`] being a type alias for [`u32`]. /// -/// The current representation is `u32`, which has been selected as being -/// sufficient to cover the current PKCS/PKIX use cases this library has been -/// used in conjunction with. +/// Note that this means we deliberately do *NOT* support UUIDs used as OIDs. /// -/// Future versions may potentially make it larger if a sufficiently important -/// use case is discovered. +/// *NOTE: please see this study for a survey of how various OID libraries handle maximum arcs: +/// pub type Arc = u32; /// Maximum value of the first arc in an OID. @@ -25,7 +25,10 @@ pub(crate) const ARC_MAX_FIRST: Arc = 2; pub(crate) const ARC_MAX_SECOND: Arc = 39; /// Maximum number of bytes supported in an arc. -const ARC_MAX_BYTES: usize = size_of::(); +/// +/// Note that OIDs are base 128 encoded (with continuation bits), so we must consider how many bytes +/// are required when each byte can only represent 7-bits of the input. +const ARC_MAX_BYTES: usize = (Arc::BITS as usize).div_ceil(7); /// Maximum value of the last byte in an arc. const ARC_MAX_LAST_OCTET: u8 = 0b11110000; // Max bytes of leading 1-bits diff --git a/const-oid/src/checked.rs b/const-oid/src/checked.rs index 7ff16a2a7..d8dacf3c7 100644 --- a/const-oid/src/checked.rs +++ b/const-oid/src/checked.rs @@ -5,7 +5,27 @@ macro_rules! checked_add { ($a:expr, $b:expr) => { match $a.checked_add($b) { Some(n) => n, - None => return Err(Error::Length), + None => return Err(Error::Overflow), + } + }; +} + +/// `const fn`-friendly checked subtraction helper. +macro_rules! checked_sub { + ($a:expr, $b:expr) => { + match $a.checked_sub($b) { + Some(n) => n, + None => return Err(Error::Overflow), + } + }; +} + +/// `const fn`-friendly checked multiplication helper. +macro_rules! checked_mul { + ($a:expr, $b:expr) => { + match $a.checked_mul($b) { + Some(n) => n, + None => return Err(Error::Overflow), } }; } diff --git a/const-oid/src/encoder.rs b/const-oid/src/encoder.rs index 3076a3499..c901e492a 100644 --- a/const-oid/src/encoder.rs +++ b/const-oid/src/encoder.rs @@ -24,7 +24,7 @@ enum State { /// Initial state - no arcs yet encoded. Initial, - /// First arc parsed. + /// First arc has been supplied and stored as the wrapped [`Arc`]. FirstArc(Arc), /// Encoding base 128 body of the OID. @@ -61,22 +61,20 @@ impl Encoder { self.state = State::FirstArc(arc); Ok(self) } - // Ensured not to overflow by `ARC_MAX_SECOND` check - #[allow(clippy::arithmetic_side_effects)] State::FirstArc(first_arc) => { if arc > ARC_MAX_SECOND { return Err(Error::ArcInvalid { arc }); } self.state = State::Body; - self.bytes[0] = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + arc as u8; + self.bytes[0] = checked_add!( + checked_mul!(checked_add!(ARC_MAX_SECOND, 1), first_arc), + arc + ) as u8; self.cursor = 1; Ok(self) } - State::Body => { - let nbytes = base128_len(arc); - self.encode_base128(arc, nbytes) - } + State::Body => self.encode_base128(arc), } } @@ -94,56 +92,48 @@ impl Encoder { Ok(ObjectIdentifier { ber }) } - /// Encode a single byte of a Base 128 value. - const fn encode_base128(mut self, n: u32, remaining_len: usize) -> Result { - if self.cursor >= MAX_SIZE { + /// Encode base 128. + const fn encode_base128(mut self, arc: Arc) -> Result { + let nbytes = base128_len(arc); + let end_pos = checked_add!(self.cursor, nbytes); + + if end_pos > MAX_SIZE { return Err(Error::Length); } - let mask = if remaining_len > 0 { 0b10000000 } else { 0 }; - let (hi, lo) = split_high_bits(n); - self.bytes[self.cursor] = hi | mask; - self.cursor = checked_add!(self.cursor, 1); - - match remaining_len.checked_sub(1) { - Some(len) => self.encode_base128(lo, len), - None => Ok(self), + let mut i = 0; + while i < nbytes { + // TODO(tarcieri): use `?` when stable in `const fn` + self.bytes[self.cursor] = match base128_byte(arc, i, nbytes) { + Ok(byte) => byte, + Err(e) => return Err(e), + }; + self.cursor = checked_add!(self.cursor, 1); + i = checked_add!(i, 1); } + + Ok(self) } } -/// Compute the length - 1 of an arc when encoded in base 128. +/// Compute the length of an arc when encoded in base 128. const fn base128_len(arc: Arc) -> usize { match arc { - 0..=0x7f => 0, - 0x80..=0x3fff => 1, - 0x4000..=0x1fffff => 2, - 0x200000..=0x1fffffff => 3, - _ => 4, + 0..=0x7f => 1, + 0x80..=0x3fff => 2, + 0x4000..=0x1fffff => 3, + 0x200000..=0x1fffffff => 4, + _ => 5, } } -/// Split the highest 7-bits of an [`Arc`] from the rest of an arc. -/// -/// Returns: `(hi, lo)` -// TODO(tarcieri): always use checked arithmetic -#[allow(clippy::arithmetic_side_effects)] -const fn split_high_bits(arc: Arc) -> (u8, Arc) { - if arc < 0x80 { - return (arc as u8, 0); - } - - let hi_bit = 32 - arc.leading_zeros(); - let hi_bit_mod7 = hi_bit % 7; - let upper_bit_pos = hi_bit - - if hi_bit > 0 && hi_bit_mod7 == 0 { - 7 - } else { - hi_bit_mod7 - }; - let upper_bits = arc >> upper_bit_pos; - let lower_bits = arc ^ (upper_bits << upper_bit_pos); - (upper_bits as u8, lower_bits) +/// Compute the big endian base 128 encoding of the given [`Arc`] at the given byte. +const fn base128_byte(arc: Arc, pos: usize, total: usize) -> Result { + debug_assert!(pos < total); + let last_byte = checked_add!(pos, 1) == total; + let mask = if last_byte { 0 } else { 0b10000000 }; + let shift = checked_sub!(checked_sub!(total, pos), 1) * 7; + Ok(((arc >> shift) & 0b1111111) as u8 | mask) } #[cfg(test)] @@ -155,6 +145,17 @@ mod tests { /// OID `1.2.840.10045.2.1` encoded as ASN.1 BER/DER const EXAMPLE_OID_BER: &[u8] = &hex!("2A8648CE3D0201"); + #[test] + fn base128_byte() { + let example_arc = 0x44332211; + assert_eq!(super::base128_len(example_arc), 5); + assert_eq!(super::base128_byte(example_arc, 0, 5).unwrap(), 0b10000100); + assert_eq!(super::base128_byte(example_arc, 1, 5).unwrap(), 0b10100001); + assert_eq!(super::base128_byte(example_arc, 2, 5).unwrap(), 0b11001100); + assert_eq!(super::base128_byte(example_arc, 3, 5).unwrap(), 0b11000100); + assert_eq!(super::base128_byte(example_arc, 4, 5).unwrap(), 0b10001); + } + #[test] fn encode() { let encoder = Encoder::<7>::new(); diff --git a/const-oid/src/error.rs b/const-oid/src/error.rs index faa01769b..263746c6f 100644 --- a/const-oid/src/error.rs +++ b/const-oid/src/error.rs @@ -37,6 +37,14 @@ pub enum Error { /// OID length is invalid (too short or too long). Length, + /// Arithmetic overflow (or underflow) errors. + /// + /// These generally indicate a bug in the `const-oid` crate. + Overflow, + + /// Repeated `..` characters in input data. + RepeatedDot, + /// Trailing `.` character at end of input. TrailingDot, } @@ -53,6 +61,8 @@ impl Error { Error::DigitExpected { .. } => panic!("OID expected to start with digit"), Error::Empty => panic!("OID value is empty"), Error::Length => panic!("OID length invalid"), + Error::Overflow => panic!("arithmetic calculation overflowed"), + Error::RepeatedDot => panic!("repeated consecutive '..' characters in OID"), Error::TrailingDot => panic!("OID ends with invalid trailing '.'"), } } @@ -69,6 +79,8 @@ impl fmt::Display for Error { } Error::Empty => f.write_str("OID value is empty"), Error::Length => f.write_str("OID length invalid"), + Error::Overflow => f.write_str("arithmetic calculation overflowed"), + Error::RepeatedDot => f.write_str("repeated consecutive '..' characters in OID"), Error::TrailingDot => f.write_str("OID ends with invalid trailing '.'"), } } diff --git a/const-oid/src/parser.rs b/const-oid/src/parser.rs index 41020f037..5b5155b36 100644 --- a/const-oid/src/parser.rs +++ b/const-oid/src/parser.rs @@ -8,7 +8,7 @@ use crate::{encoder::Encoder, Arc, Error, ObjectIdentifier, Result}; #[derive(Debug)] pub(crate) struct Parser { /// Current arc in progress - current_arc: Arc, + current_arc: Option, /// BER/DER encoder encoder: Encoder<{ ObjectIdentifier::MAX_SIZE }>, @@ -25,7 +25,7 @@ impl Parser { match bytes[0] { b'0'..=b'9' => Self { - current_arc: 0, + current_arc: None, encoder: Encoder::new(), } .parse_bytes(bytes), @@ -42,33 +42,51 @@ impl Parser { const fn parse_bytes(mut self, bytes: &[u8]) -> Result { match bytes { // TODO(tarcieri): use `?` when stable in `const fn` - [] => match self.encoder.arc(self.current_arc) { - Ok(encoder) => { - self.encoder = encoder; - Ok(self) - } - Err(err) => Err(err), + [] => match self.current_arc { + Some(arc) => match self.encoder.arc(arc) { + Ok(encoder) => { + self.encoder = encoder; + Ok(self) + } + Err(err) => Err(err), + }, + None => Err(Error::TrailingDot), }, - // TODO(tarcieri): checked arithmetic - #[allow(clippy::arithmetic_side_effects)] [byte @ b'0'..=b'9', remaining @ ..] => { let digit = byte.saturating_sub(b'0'); - self.current_arc = self.current_arc * 10 + digit as Arc; + let arc = match self.current_arc { + Some(arc) => arc, + None => 0, + }; + + // TODO(tarcieri): use `and_then` when const traits are stable + self.current_arc = match arc.checked_mul(10) { + Some(arc) => match arc.checked_add(digit as Arc) { + None => return Err(Error::ArcTooBig), + Some(arc) => Some(arc), + }, + None => return Err(Error::ArcTooBig), + }; self.parse_bytes(remaining) } [b'.', remaining @ ..] => { - if remaining.is_empty() { - return Err(Error::TrailingDot); - } + match self.current_arc { + Some(arc) => { + if remaining.is_empty() { + return Err(Error::TrailingDot); + } - // TODO(tarcieri): use `?` when stable in `const fn` - match self.encoder.arc(self.current_arc) { - Ok(encoder) => { - self.encoder = encoder; - self.current_arc = 0; - self.parse_bytes(remaining) + // TODO(tarcieri): use `?` when stable in `const fn` + match self.encoder.arc(arc) { + Ok(encoder) => { + self.encoder = encoder; + self.current_arc = None; + self.parse_bytes(remaining) + } + Err(err) => Err(err), + } } - Err(err) => Err(err), + None => Err(Error::RepeatedDot), } } [byte, ..] => Err(Error::DigitExpected { actual: *byte }), diff --git a/const-oid/tests/oid.rs b/const-oid/tests/oid.rs index bebbbadf5..92bfc49c4 100644 --- a/const-oid/tests/oid.rs +++ b/const-oid/tests/oid.rs @@ -29,52 +29,85 @@ const EXAMPLE_OID_LARGE_ARC_0: ObjectIdentifier = ObjectIdentifier::new_unwrap(crate::EXAMPLE_OID_LARGE_ARC_0_STR); /// Example OID value with a large arc -const EXAMPLE_OID_LARGE_ARC_1_STR: &str = "0.9.2342.19200300.100.1.1"; -const EXAMPLE_OID_LARGE_ARC_1_BER: &[u8] = &hex!("0992268993F22C640101"); +const EXAMPLE_OID_LARGE_ARC_1_STR: &str = "1.1.1.60817410.1"; +const EXAMPLE_OID_LARGE_ARC_1_BER: &[u8] = &hex!("29019D80800201"); const EXAMPLE_OID_LARGE_ARC_1: ObjectIdentifier = ObjectIdentifier::new_unwrap(EXAMPLE_OID_LARGE_ARC_1_STR); +/// Example OID value with a large arc (namely `u32::MAX`, the edge case) +const EXAMPLE_OID_LARGE_ARC_2_STR: &str = "1.2.4294967295"; +const EXAMPLE_OID_LARGE_ARC_2_BER: &[u8] = &hex!("2A8FFFFFFF7F"); +const EXAMPLE_OID_LARGE_ARC_2: ObjectIdentifier = + ObjectIdentifier::new_unwrap(crate::EXAMPLE_OID_LARGE_ARC_2_STR); + /// Create an OID from a string. pub fn oid(s: &str) -> ObjectIdentifier { ObjectIdentifier::new(s).unwrap() } +/// 0.9.2342.19200300.100.1.1 #[test] -fn from_bytes() { - let oid0 = ObjectIdentifier::from_bytes(EXAMPLE_OID_0_BER).unwrap(); - assert_eq!(oid0.arc(0).unwrap(), 0); - assert_eq!(oid0.arc(1).unwrap(), 9); - assert_eq!(oid0.arc(2).unwrap(), 2342); - assert_eq!(oid0, EXAMPLE_OID_0); +fn from_bytes_oid_0() { + let oid = ObjectIdentifier::from_bytes(EXAMPLE_OID_0_BER).unwrap(); + assert_eq!(oid, EXAMPLE_OID_0); + assert_eq!(oid.arc(0).unwrap(), 0); + assert_eq!(oid.arc(1).unwrap(), 9); + assert_eq!(oid.arc(2).unwrap(), 2342); +} - let oid1 = ObjectIdentifier::from_bytes(EXAMPLE_OID_1_BER).unwrap(); - assert_eq!(oid1.arc(0).unwrap(), 1); - assert_eq!(oid1.arc(1).unwrap(), 2); - assert_eq!(oid1.arc(2).unwrap(), 840); - assert_eq!(oid1, EXAMPLE_OID_1); +/// 1.2.840.10045.2.1 +#[test] +fn from_bytes_oid_1() { + let oid = ObjectIdentifier::from_bytes(EXAMPLE_OID_1_BER).unwrap(); + assert_eq!(oid, EXAMPLE_OID_1); + assert_eq!(oid.arc(0).unwrap(), 1); + assert_eq!(oid.arc(1).unwrap(), 2); + assert_eq!(oid.arc(2).unwrap(), 840); +} - let oid2 = ObjectIdentifier::from_bytes(EXAMPLE_OID_2_BER).unwrap(); - assert_eq!(oid2.arc(0).unwrap(), 2); - assert_eq!(oid2.arc(1).unwrap(), 16); - assert_eq!(oid2.arc(2).unwrap(), 840); - assert_eq!(oid2, EXAMPLE_OID_2); +/// 2.16.840.1.101.3.4.1.42 +#[test] +fn from_bytes_oid_2() { + let oid = ObjectIdentifier::from_bytes(EXAMPLE_OID_2_BER).unwrap(); + assert_eq!(oid, EXAMPLE_OID_2); + assert_eq!(oid.arc(0).unwrap(), 2); + assert_eq!(oid.arc(1).unwrap(), 16); + assert_eq!(oid.arc(2).unwrap(), 840); +} - let oid_largearc0 = ObjectIdentifier::from_bytes(EXAMPLE_OID_LARGE_ARC_0_BER).unwrap(); - assert_eq!(oid_largearc0.arc(0).unwrap(), 1); - assert_eq!(oid_largearc0.arc(1).unwrap(), 2); - assert_eq!(oid_largearc0.arc(2).unwrap(), 16384); - assert_eq!(oid_largearc0.arc(3), None); - assert_eq!(oid_largearc0, EXAMPLE_OID_LARGE_ARC_0); +/// 1.2.16384 +#[test] +fn from_bytes_oid_largearc_0() { + let oid = ObjectIdentifier::from_bytes(EXAMPLE_OID_LARGE_ARC_0_BER).unwrap(); + assert_eq!(oid, EXAMPLE_OID_LARGE_ARC_0); + assert_eq!(oid.arc(0).unwrap(), 1); + assert_eq!(oid.arc(1).unwrap(), 2); + assert_eq!(oid.arc(2).unwrap(), 16384); + assert_eq!(oid.arc(3), None); +} - let oid_largearc1 = ObjectIdentifier::from_bytes(EXAMPLE_OID_LARGE_ARC_1_BER).unwrap(); - assert_eq!(oid_largearc1.arc(0).unwrap(), 0); - assert_eq!(oid_largearc1.arc(1).unwrap(), 9); - assert_eq!(oid_largearc1.arc(2).unwrap(), 2342); - assert_eq!(oid_largearc1.arc(3).unwrap(), 19200300); - assert_eq!(oid_largearc1.arc(4).unwrap(), 100); - assert_eq!(oid_largearc1.arc(5).unwrap(), 1); - assert_eq!(oid_largearc1.arc(6).unwrap(), 1); - assert_eq!(oid_largearc1, EXAMPLE_OID_LARGE_ARC_1); +/// 1.1.1.60817410.1 +#[test] +fn from_bytes_oid_largearc_1() { + let oid = ObjectIdentifier::from_bytes(EXAMPLE_OID_LARGE_ARC_1_BER).unwrap(); + assert_eq!(oid, EXAMPLE_OID_LARGE_ARC_1); + assert_eq!(oid.arc(0).unwrap(), 1); + assert_eq!(oid.arc(1).unwrap(), 1); + assert_eq!(oid.arc(2).unwrap(), 1); + assert_eq!(oid.arc(3).unwrap(), 60817410); + assert_eq!(oid.arc(4).unwrap(), 1); + assert_eq!(oid.arc(5), None); +} + +/// 1.2.4294967295 +#[test] +fn from_bytes_oid_largearc_2() { + let oid = ObjectIdentifier::from_bytes(EXAMPLE_OID_LARGE_ARC_2_BER).unwrap(); + assert_eq!(oid, EXAMPLE_OID_LARGE_ARC_2); + assert_eq!(oid.arc(0).unwrap(), 1); + assert_eq!(oid.arc(1).unwrap(), 2); + assert_eq!(oid.arc(2).unwrap(), 4294967295); + assert_eq!(oid.arc(3), None); // Empty assert_eq!(ObjectIdentifier::from_bytes(&[]), Err(Error::Empty)); @@ -108,15 +141,21 @@ fn from_str() { let oid_largearc1 = EXAMPLE_OID_LARGE_ARC_1_STR .parse::() .unwrap(); - assert_eq!(oid_largearc1.arc(0).unwrap(), 0); - assert_eq!(oid_largearc1.arc(1).unwrap(), 9); - assert_eq!(oid_largearc1.arc(2).unwrap(), 2342); - assert_eq!(oid_largearc1.arc(3).unwrap(), 19200300); - assert_eq!(oid_largearc1.arc(4).unwrap(), 100); - assert_eq!(oid_largearc1.arc(5).unwrap(), 1); - assert_eq!(oid_largearc1.arc(6).unwrap(), 1); + assert_eq!(oid_largearc1.arc(0).unwrap(), 1); + assert_eq!(oid_largearc1.arc(1).unwrap(), 1); + assert_eq!(oid_largearc1.arc(2).unwrap(), 1); + assert_eq!(oid_largearc1.arc(3).unwrap(), 60817410); + assert_eq!(oid_largearc1.arc(4).unwrap(), 1); assert_eq!(oid_largearc1, EXAMPLE_OID_LARGE_ARC_1); + let oid_largearc2 = EXAMPLE_OID_LARGE_ARC_2_STR + .parse::() + .unwrap(); + assert_eq!(oid_largearc2.arc(0).unwrap(), 1); + assert_eq!(oid_largearc2.arc(1).unwrap(), 2); + assert_eq!(oid_largearc2.arc(2).unwrap(), 4294967295); + assert_eq!(oid_largearc2, EXAMPLE_OID_LARGE_ARC_2); + // Truncated assert_eq!( "1.2.840.10045.2.".parse::(), @@ -141,10 +180,18 @@ fn display() { assert_eq!(EXAMPLE_OID_0.to_string(), EXAMPLE_OID_0_STR); assert_eq!(EXAMPLE_OID_1.to_string(), EXAMPLE_OID_1_STR); assert_eq!(EXAMPLE_OID_2.to_string(), EXAMPLE_OID_2_STR); + assert_eq!( + EXAMPLE_OID_LARGE_ARC_0.to_string(), + EXAMPLE_OID_LARGE_ARC_0_STR + ); assert_eq!( EXAMPLE_OID_LARGE_ARC_1.to_string(), EXAMPLE_OID_LARGE_ARC_1_STR ); + assert_eq!( + EXAMPLE_OID_LARGE_ARC_2.to_string(), + EXAMPLE_OID_LARGE_ARC_2_STR + ); } #[test] @@ -207,6 +254,11 @@ fn parse_invalid_second_arc() { ); } +#[test] +fn parse_invalid_repeat_dots() { + assert_eq!(ObjectIdentifier::new("1.2..3.4"), Err(Error::RepeatedDot)) +} + #[test] fn parent() { let child = oid("1.2.3.4"); diff --git a/const-oid/tests/proptests.proptest-regressions b/const-oid/tests/proptests.proptest-regressions new file mode 100644 index 000000000..805e18453 --- /dev/null +++ b/const-oid/tests/proptests.proptest-regressions @@ -0,0 +1,13 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 1663923d2fb0c804c5b850d10dd0ded1cbfc06dddf3f88faa4abf149b8430831 # shrinks to s = "" +cc 829ba8833ee42816bc33d308b7a186452e36617f0fa0e771edea08fd07d78718 # shrinks to s = "0.40" +cc bc88f232a7e2e45d2b1325d4e02c09742aca7ad31903326fedb36c047533696c # shrinks to s = "0" +cc d90305406041ea5e4cf4d9e7849cad03391db1869d0b1329f60ccbf1fabaee91 # shrinks to s = "0..0" +cc 8ed8dde35d12a2c8e10cdde6d591a8f17f0cd6d6fdf90f1582536401364623bf # shrinks to s = "0.00" +cc ba5e3e3dc1a64870477e82054bbf6d8272f8b0d0c9094115bf7e8b5ff59f3c63 # shrinks to s = "00.1.1" +cc d211e943da9a0e3d0ee5097899b2435f784ca2b3d2f8d4790aae3744823a268a # shrinks to s = "1.1.1.60817410.1" diff --git a/const-oid/tests/proptests.rs b/const-oid/tests/proptests.rs new file mode 100644 index 000000000..5f398fbb5 --- /dev/null +++ b/const-oid/tests/proptests.rs @@ -0,0 +1,56 @@ +//! `proptest`-powered property-based tests. + +use const_oid::{Error, ObjectIdentifier}; +use proptest::prelude::*; +use regex::Regex; + +prop_compose! { + /// Produce a string of digits and dots, i.e. the component parts of OIDs. + /// + /// Note that this can be any permutation of digits-and-dots and does not necessarily + /// represent a valid OID. + fn oid_like_string()(bytes in any::>()) -> String { + // Create a digit or dot from a byte input + fn byte_to_char(byte: u8) -> char { + match byte % 11 { + n @ 0..=9 => (b'0' + n) as char, + 10 => '.', + _ => unreachable!() + } + } + + + let mut ret = String::with_capacity(bytes.len()); + for byte in bytes { + ret.push(byte_to_char(byte)); + } + ret + } +} + +proptest! { + #[test] + fn round_trip(s in oid_like_string()) { + match ObjectIdentifier::new(&s) { + Ok(oid) => { + // Leading zeros won't round trip, so ignore that case + // TODO(tarcieri): disallow leading zeros? + if !s.starts_with("0") && !s.contains(".0") { + let oid_string = oid.to_string(); + prop_assert_eq!(s, oid_string); + } + }, + Err(Error::ArcInvalid { .. }) | Err(Error::ArcTooBig) => (), + Err(e) => { + let re = Regex::new("^([0-2])\\.([0-3]?[0-9])((\\.0)|(\\.[1-9][0-9]*))+$").unwrap(); + + prop_assert!( + re.find(&s).is_none(), + "regex asserts OID `{}` is valid, but `const-oid`failed: {}", + &s, + &e + ); + } + } + } +} diff --git a/der/Cargo.toml b/der/Cargo.toml index 01f840b05..490d25522 100644 --- a/der/Cargo.toml +++ b/der/Cargo.toml @@ -17,7 +17,7 @@ edition = "2021" rust-version = "1.81" [dependencies] -arbitrary = { version = "1.3", features = ["derive"], optional = true } +arbitrary = { version = "1.4", features = ["derive"], optional = true } bytes = { version = "1", optional = true, default-features = false } const-oid = { version = "0.10.0-rc.0", optional = true } der_derive = { version = "0.8.0-rc.0", optional = true } diff --git a/der/src/referenced.rs b/der/src/referenced.rs index d7d34c028..22060b93b 100644 --- a/der/src/referenced.rs +++ b/der/src/referenced.rs @@ -38,7 +38,10 @@ impl OwnedToRef for Option where T: OwnedToRef, { - type Borrowed<'a> = Option> where T: 'a; + type Borrowed<'a> + = Option> + where + T: 'a; fn owned_to_ref(&self) -> Self::Borrowed<'_> { self.as_ref().map(|o| o.owned_to_ref()) diff --git a/pkcs5/src/pbes2/encryption.rs b/pkcs5/src/pbes2/encryption.rs index b5259e997..7413644f0 100644 --- a/pkcs5/src/pbes2/encryption.rs +++ b/pkcs5/src/pbes2/encryption.rs @@ -178,7 +178,7 @@ impl EncryptionKey { pub fn derive_from_password(password: &[u8], kdf: &Kdf, key_size: usize) -> Result { // if the kdf params defined a key length, ensure it matches the required key size if let Some(len) = kdf.key_length() { - if key_size != len.into() { + if key_size != usize::from(len) { return Err(kdf.to_alg_params_invalid()); } } diff --git a/sec1/Cargo.toml b/sec1/Cargo.toml index 60d05a128..18a680cd3 100644 --- a/sec1/Cargo.toml +++ b/sec1/Cargo.toml @@ -19,7 +19,7 @@ rust-version = "1.81" [dependencies] base16ct = { version = "0.2", optional = true, default-features = false } der = { version = "0.8.0-rc.0", optional = true, features = ["oid"] } -hybrid-array = { version = "0.2.0-rc.11", optional = true, default-features = false } +hybrid-array = { version = "0.2.3", optional = true, default-features = false } pkcs8 = { version = "0.11.0-rc.1", optional = true, default-features = false } serdect = { version = "0.3.0-rc.0", optional = true, default-features = false, features = ["alloc"] } subtle = { version = "2", optional = true, default-features = false } diff --git a/serdect/CHANGELOG.md b/serdect/CHANGELOG.md index b530cdeaf..56073de34 100644 --- a/serdect/CHANGELOG.md +++ b/serdect/CHANGELOG.md @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.3.0 (2025-01-06) + +NOTE: this release includes major breaking changes to the wire format, namely +all bytestrings now include a length prefix, even when serializing fixed-size +arrays. This is intended to work around deficiencies in the `serde` API +(see serde-rs/serde#2120) as well as serde-based format implementations which +have variable-time behavior when using `serialize_tuple`. + +Any binary data serialized with previous versions of `serdect` now needs a +length prefix prepended to the data, which will vary depending on the +particular data format. + +### Changed +- Switch to length-prefixed encoding using the `serialize_bytes` method ([#1112], [#1515]) +- MSRV 1.70 ([#1244]) + +[#1112]: https://github.com/RustCrypto/formats/pull/1112 +[#1515]: https://github.com/RustCrypto/formats/pull/1515 +[#1244]: https://github.com/RustCrypto/formats/pull/1244 + ## 0.2.0 (2023-02-26) ### Changed - MSRV 1.60 ([#802]) diff --git a/serdect/Cargo.toml b/serdect/Cargo.toml index 0a034167e..9a89e7a7a 100644 --- a/serdect/Cargo.toml +++ b/serdect/Cargo.toml @@ -4,7 +4,7 @@ description = """ Constant-time serde serializer/deserializer helpers for data that potentially contains secrets (e.g. cryptographic keys) """ -version = "0.3.0-rc.0" +version = "0.3.0" authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" homepage = "https://github.com/RustCrypto/formats/tree/master/serdect" @@ -19,7 +19,7 @@ rust-version = "1.70" base16ct = { version = "0.2", default-features = false } serde = { version = "1.0.184", default-features = false } -# optional features +# optional featuresw zeroize = { version = "1", optional = true, default-features = false } [dev-dependencies] diff --git a/serdect/src/common.rs b/serdect/src/common.rs index a5228b566..55441225e 100644 --- a/serdect/src/common.rs +++ b/serdect/src/common.rs @@ -7,7 +7,7 @@ use serde::{ }; #[cfg(feature = "alloc")] -use ::{alloc::vec::Vec, serde::Serialize}; +use {alloc::vec::Vec, serde::Serialize}; #[cfg(not(feature = "alloc"))] use serde::ser::Error as SerError; diff --git a/spki/Cargo.toml b/spki/Cargo.toml index fd952d0e7..0efaa4af1 100644 --- a/spki/Cargo.toml +++ b/spki/Cargo.toml @@ -19,7 +19,7 @@ rust-version = "1.81" der = { version = "0.8.0-rc.0", features = ["oid"] } # Optional dependencies -arbitrary = { version = "1.2", features = ["derive"], optional = true } +arbitrary = { version = "1.4", features = ["derive"], optional = true } base64ct = { version = "1", optional = true, default-features = false } sha2 = { version = "=0.11.0-pre.4", optional = true, default-features = false } diff --git a/tai64/CHANGELOG.md b/tai64/CHANGELOG.md index 6640511d5..38a8ecb69 100644 --- a/tai64/CHANGELOG.md +++ b/tai64/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 4.1.0 (2024-10-29) + +### Changed +- MSRV bump from 1.56 to 1.60 ([#802]) + +### Fixed +- fix TAI offset and verify with GH Action ([#1583]) + +[#802]: https://github.com/RustCrypto/formats/pull/802 +[#1583]: https://github.com/RustCrypto/formats/pull/1583 + ## 4.0.0 (2021-11-04) ### Changed - Upgrade to Rust 2021 edition; MSRV 1.56+ diff --git a/tai64/Cargo.toml b/tai64/Cargo.toml index 7f0a1afc9..5ada6e0ce 100644 --- a/tai64/Cargo.toml +++ b/tai64/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tai64" description = "TAI64 and TAI64N (i.e. Temps Atomique International) timestamp support for Rust" -version = "5.0.0-pre" +version = "4.1.0" authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" homepage = "https://github.com/RustCrypto/formats/tree/master/tai64" diff --git a/tai64/src/lib.rs b/tai64/src/lib.rs index d7f92d584..2ffcfc618 100644 --- a/tai64/src/lib.rs +++ b/tai64/src/lib.rs @@ -36,8 +36,8 @@ const NANOS_PER_SECOND: u32 = 1_000_000_000; pub struct Tai64(pub u64); impl Tai64 { - /// Unix epoch in `TAI64`: 1970-01-01 00:00:10 TAI. - pub const UNIX_EPOCH: Self = Self(10 + (1 << 62)); + /// Unix epoch in `TAI64`: 1970-01-01 00:00:37 TAI. + pub const UNIX_EPOCH: Self = Self(37 + (1 << 62)); /// Length of serialized `TAI64` timestamp in bytes. pub const BYTE_SIZE: usize = 8; @@ -151,7 +151,7 @@ impl Zeroize for Tai64N { } impl Tai64N { - /// Unix epoch in `TAI64N`: 1970-01-01 00:00:10 TAI. + /// Unix epoch in `TAI64N`: 1970-01-01 00:00:37 TAI. pub const UNIX_EPOCH: Self = Self(Tai64::UNIX_EPOCH, 0); /// Length of serialized `TAI64N` timestamp. diff --git a/tls_codec/CHANGELOG.md b/tls_codec/CHANGELOG.md index 3d6397e3a..1bdd6bcaa 100644 --- a/tls_codec/CHANGELOG.md +++ b/tls_codec/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- [#1628](https://github.com/RustCrypto/formats/pull/1628) Bump MSRV to 1.74 + ## 0.4.1 - [#1284](https://github.com/RustCrypto/formats/pull/1284): implement `U24`. A `U24` integer type can be used for length encoding in three bytes. diff --git a/tls_codec/Cargo.toml b/tls_codec/Cargo.toml index c37c6d9ca..3eaa5ddf0 100644 --- a/tls_codec/Cargo.toml +++ b/tls_codec/Cargo.toml @@ -9,7 +9,7 @@ readme = "README.md" homepage = "https://github.com/RustCrypto/formats/tree/master/tls_codec" repository = "https://github.com/RustCrypto/formats" edition = "2021" -rust-version = "1.70" +rust-version = "1.74" [dependencies] zeroize = { version = "1.8", default-features = false, features = [ @@ -18,15 +18,15 @@ zeroize = { version = "1.8", default-features = false, features = [ ] } # optional dependencies -arbitrary = { version = "1.3", features = ["derive"], optional = true } +arbitrary = { version = "1.4", features = ["derive"], optional = true } tls_codec_derive = { version = "=0.4.1", path = "./derive", optional = true } serde = { version = "1.0.184", features = ["derive"], optional = true } [dev-dependencies] -clap = "=4.3.23" # pinned to preserve MSRV -clap_lex = "=0.5.0" # pinned to preserve MSRV -anstyle = "=1.0.2" # pinned to preserve MSRV -anstyle-parse = "=0.2.1" # pinned to preserve MSRV +clap = "=4.5.23" # pinned to preserve MSRV +clap_lex = "=0.7.4" # pinned to preserve MSRV +anstyle = "=1.0.10" # pinned to preserve MSRV +anstyle-parse = "=0.2.6" # pinned to preserve MSRV criterion = { version = "0.5", default-features = false } regex = "1.8" diff --git a/tls_codec/README.md b/tls_codec/README.md index 1841d27fe..be0b94f89 100644 --- a/tls_codec/README.md +++ b/tls_codec/README.md @@ -37,7 +37,7 @@ serialization/deserialization ## Minimum Supported Rust Version -This crate requires **Rust 1.70.0** at a minimum. +This crate requires **Rust 1.74.0** at a minimum. We may change the MSRV in the future, but it will be accompanied by a minor version bump. @@ -68,7 +68,7 @@ dual licensed as above, without any additional terms or conditions. [RustCrypto]: https://github.com/rustcrypto [rfc 8446]: https://tools.ietf.org/html/rfc8446 -[mls]: https://messaginglayersecurity.rocks/mls-protocol/draft-ietf-mls-protocol.html +[mls]: https://www.rfc-editor.org/rfc/rfc9420.html [tls_codec-ci]: https://img.shields.io/github/actions/workflow/status/RustCrypto/formats/tls_codec.yml?branch=master&style=for-the-badge [tls_codec-ci-link]: https://github.com/RustCrypto/formats/actions/workflows/tls_codec.yml [tls_codec]: https://img.shields.io/crates/v/tls_codec?style=for-the-badge diff --git a/tls_codec/src/primitives.rs b/tls_codec/src/primitives.rs index 2677f6fc9..63e21d931 100644 --- a/tls_codec/src/primitives.rs +++ b/tls_codec/src/primitives.rs @@ -1,6 +1,6 @@ //! Codec implementations for unsigned integer primitives. -use alloc::vec::Vec; +use alloc::{boxed::Box, vec::Vec}; use crate::{DeserializeBytes, SerializeBytes, U24}; @@ -371,3 +371,40 @@ impl SerializeBytes for PhantomData { Ok(vec![]) } } + +impl Size for Box { + #[inline(always)] + fn tls_serialized_len(&self) -> usize { + self.as_ref().tls_serialized_len() + } +} + +impl Serialize for Box { + #[cfg(feature = "std")] + #[inline(always)] + fn tls_serialize(&self, writer: &mut W) -> Result { + self.as_ref().tls_serialize(writer) + } +} + +impl SerializeBytes for Box { + #[inline(always)] + fn tls_serialize(&self) -> Result, Error> { + self.as_ref().tls_serialize() + } +} + +impl Deserialize for Box { + #[cfg(feature = "std")] + #[inline(always)] + fn tls_deserialize(bytes: &mut R) -> Result { + T::tls_deserialize(bytes).map(Box::new) + } +} + +impl DeserializeBytes for Box { + #[inline(always)] + fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> { + T::tls_deserialize_bytes(bytes).map(|(v, r)| (Box::new(v), r)) + } +} diff --git a/x509-cert/Cargo.toml b/x509-cert/Cargo.toml index 799ad6b50..c2b3ae751 100644 --- a/x509-cert/Cargo.toml +++ b/x509-cert/Cargo.toml @@ -21,7 +21,7 @@ der = { version = "0.8.0-rc.0", features = ["alloc", "derive", "flagset", "oid"] spki = { version = "0.8.0-rc.0", features = ["alloc"] } # optional dependencies -arbitrary = { version = "1.3", features = ["derive"], optional = true } +arbitrary = { version = "1.4", features = ["derive"], optional = true } async-signature = { version = "=0.6.0-pre.4", features = ["digest", "rand_core"], optional = true } sha1 = { version = "0.11.0-pre.4", optional = true } signature = { version = "=2.3.0-pre.4", features = ["rand_core"], optional = true } @@ -36,7 +36,7 @@ p256 = "=0.14.0-pre.2" rstest = "0.23" sha2 = { version = "=0.11.0-pre.4", features = ["oid"] } tempfile = "3.5.0" -tokio = { version = "1.40.0", features = ["macros", "rt"] } +tokio = { version = "1.42.0", features = ["macros", "rt"] } x509-cert-test-support = { path = "./test-support" } [features] diff --git a/x509-cert/src/builder.rs b/x509-cert/src/builder.rs index 493cfaf7a..809e1a538 100644 --- a/x509-cert/src/builder.rs +++ b/x509-cert/src/builder.rs @@ -12,8 +12,6 @@ use spki::{ use crate::{ certificate::{Certificate, TbsCertificate, Version}, ext::{AsExtension, Extensions}, - name::Name, - request::{attributes::AsAttribute, CertReq, CertReqInfo, ExtensionReq}, serial_number::SerialNumber, time::Validity, AlgorithmIdentifier, SubjectPublicKeyInfo, @@ -29,7 +27,13 @@ use self::profile::BuilderProfile; )] pub use self::profile::BuilderProfile as Profile; -const NULL_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("0.0.0"); +#[deprecated( + since = "0.3.0", + note = "please use `x509_cert::request::RequestBuilder` instead" +)] +pub use crate::request::RequestBuilder; + +pub(crate) const NULL_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("0.0.0"); /// Error type #[derive(Debug)] @@ -212,90 +216,6 @@ where } } -/// Builder for X509 Certificate Requests -/// -/// ``` -/// # use p256::{pkcs8::DecodePrivateKey, NistP256, ecdsa::DerSignature}; -/// # const PKCS8_PRIVATE_KEY_DER: &[u8] = include_bytes!("../tests/examples/p256-priv.der"); -/// # fn ecdsa_signer() -> ecdsa::SigningKey { -/// # let secret_key = p256::SecretKey::from_pkcs8_der(PKCS8_PRIVATE_KEY_DER).unwrap(); -/// # ecdsa::SigningKey::from(secret_key) -/// # } -/// use x509_cert::{ -/// builder::{Builder, RequestBuilder}, -/// ext::pkix::{name::GeneralName, SubjectAltName}, -/// name::Name, -/// }; -/// use std::str::FromStr; -/// -/// use std::net::{IpAddr, Ipv4Addr}; -/// let subject = Name::from_str("CN=service.domination.world").unwrap(); -/// -/// let signer = ecdsa_signer(); -/// let mut builder = RequestBuilder::new(subject).expect("Create certificate request"); -/// builder -/// .add_extension(&SubjectAltName(vec![GeneralName::from(IpAddr::V4( -/// Ipv4Addr::new(192, 0, 2, 0), -/// ))])) -/// .unwrap(); -/// -/// let cert_req = builder.build::<_, DerSignature>(&signer).unwrap(); -/// ``` -pub struct RequestBuilder { - info: CertReqInfo, - extension_req: ExtensionReq, -} - -impl RequestBuilder { - /// Creates a new certificate request builder - pub fn new(subject: Name) -> Result { - let version = Default::default(); - - let algorithm = AlgorithmIdentifier { - oid: NULL_OID, - parameters: None, - }; - let public_key = SubjectPublicKeyInfo { - algorithm, - subject_public_key: BitString::from_bytes(&[]).expect("unable to parse empty object"), - }; - - let attributes = Default::default(); - let extension_req = Default::default(); - - Ok(Self { - info: CertReqInfo { - version, - subject, - public_key, - attributes, - }, - extension_req, - }) - } - - /// Add an extension to this certificate request - /// - /// Extensions need to implement [`AsExtension`], examples may be found in - /// in [`AsExtension` documentation](../ext/trait.AsExtension.html#examples) or - /// [the implementors](../ext/trait.AsExtension.html#implementors). - pub fn add_extension(&mut self, extension: &E) -> Result<()> { - let ext = extension.to_extension(&self.info.subject, &self.extension_req.0)?; - - self.extension_req.0.push(ext); - - Ok(()) - } - - /// Add an attribute to this certificate request - pub fn add_attribute(&mut self, attribute: &A) -> Result<()> { - let attr = attribute.to_attribute()?; - - self.info.attributes.insert(attr)?; - Ok(()) - } -} - /// Trait for X509 builders /// /// This trait defines the interface between builder and the signers. @@ -404,40 +324,6 @@ where } } -impl Builder for RequestBuilder { - type Output = CertReq; - - fn finalize(&mut self, signer: &S) -> Result> - where - S: Keypair + DynSignatureAlgorithmIdentifier, - S::VerifyingKey: EncodePublicKey, - { - let verifying_key = signer.verifying_key(); - let public_key = SubjectPublicKeyInfo::from_key(&verifying_key)?; - self.info.public_key = public_key; - - self.info - .attributes - .insert(self.extension_req.clone().try_into()?)?; - - self.info.to_der().map_err(Error::from) - } - - fn assemble(self, signature: BitString, signer: &S) -> Result - where - S: Keypair + DynSignatureAlgorithmIdentifier, - S::VerifyingKey: EncodePublicKey, - { - let algorithm = signer.signature_algorithm_identifier()?; - - Ok(CertReq { - info: self.info, - algorithm, - signature, - }) - } -} - /// Trait for async X509 builders /// /// This trait defines the interface between builder and the signers. diff --git a/x509-cert/src/request.rs b/x509-cert/src/request.rs index 9681be12a..0f1bdb1a1 100644 --- a/x509-cert/src/request.rs +++ b/x509-cert/src/request.rs @@ -19,6 +19,12 @@ use der::{ #[cfg(feature = "pem")] use der::pem::PemLabel; +#[cfg(feature = "builder")] +mod builder; + +#[cfg(feature = "builder")] +pub use self::builder::RequestBuilder; + /// Version identifier for certification request information. /// /// (RFC 2986 designates `0` as the only valid version) diff --git a/x509-cert/src/request/builder.rs b/x509-cert/src/request/builder.rs new file mode 100644 index 000000000..a87bd02e5 --- /dev/null +++ b/x509-cert/src/request/builder.rs @@ -0,0 +1,132 @@ +use alloc::vec; + +use der::{asn1::BitString, Encode}; +use signature::Keypair; +use spki::{ + AlgorithmIdentifier, DynSignatureAlgorithmIdentifier, EncodePublicKey, SubjectPublicKeyInfo, +}; + +use crate::{ + builder::{Builder, Error, Result, NULL_OID}, + ext::AsExtension, + name::Name, + request::{attributes::AsAttribute, CertReq, CertReqInfo, ExtensionReq}, +}; + +/// Builder for X509 Certificate Requests (CSR) +/// +/// ``` +/// # use p256::{pkcs8::DecodePrivateKey, NistP256, ecdsa::DerSignature}; +/// # const PKCS8_PRIVATE_KEY_DER: &[u8] = include_bytes!("../../tests/examples/p256-priv.der"); +/// # fn ecdsa_signer() -> ecdsa::SigningKey { +/// # let secret_key = p256::SecretKey::from_pkcs8_der(PKCS8_PRIVATE_KEY_DER).unwrap(); +/// # ecdsa::SigningKey::from(secret_key) +/// # } +/// use x509_cert::{ +/// builder::{Builder, RequestBuilder}, +/// ext::pkix::{name::GeneralName, SubjectAltName}, +/// name::Name, +/// }; +/// use std::str::FromStr; +/// +/// use std::net::{IpAddr, Ipv4Addr}; +/// let subject = Name::from_str("CN=service.domination.world").unwrap(); +/// +/// let signer = ecdsa_signer(); +/// let mut builder = RequestBuilder::new(subject).expect("Create certificate request"); +/// builder +/// .add_extension(&SubjectAltName(vec![GeneralName::from(IpAddr::V4( +/// Ipv4Addr::new(192, 0, 2, 0), +/// ))])) +/// .unwrap(); +/// +/// let cert_req = builder.build::<_, DerSignature>(&signer).unwrap(); +/// ``` +pub struct RequestBuilder { + info: CertReqInfo, + extension_req: ExtensionReq, +} + +impl RequestBuilder { + /// Creates a new certificate request builder + pub fn new(subject: Name) -> Result { + let version = Default::default(); + + let algorithm = AlgorithmIdentifier { + oid: NULL_OID, + parameters: None, + }; + let public_key = SubjectPublicKeyInfo { + algorithm, + subject_public_key: BitString::from_bytes(&[]).expect("unable to parse empty object"), + }; + + let attributes = Default::default(); + let extension_req = Default::default(); + + Ok(Self { + info: CertReqInfo { + version, + subject, + public_key, + attributes, + }, + extension_req, + }) + } + + /// Add an extension to this certificate request + /// + /// Extensions need to implement [`AsExtension`], examples may be found in + /// in [`AsExtension` documentation](../ext/trait.AsExtension.html#examples) or + /// [the implementors](../ext/trait.AsExtension.html#implementors). + pub fn add_extension(&mut self, extension: &E) -> Result<()> { + let ext = extension.to_extension(&self.info.subject, &self.extension_req.0)?; + + self.extension_req.0.push(ext); + + Ok(()) + } + + /// Add an attribute to this certificate request + pub fn add_attribute(&mut self, attribute: &A) -> Result<()> { + let attr = attribute.to_attribute()?; + + self.info.attributes.insert(attr)?; + Ok(()) + } +} + +impl Builder for RequestBuilder { + type Output = CertReq; + + fn finalize(&mut self, signer: &S) -> Result> + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, + { + let verifying_key = signer.verifying_key(); + let public_key = SubjectPublicKeyInfo::from_key(&verifying_key)?; + self.info.public_key = public_key; + + self.info + .attributes + .insert(self.extension_req.clone().try_into()?)?; + + self.info.to_der().map_err(Error::from) + } + + fn assemble(self, signature: BitString, signer: &S) -> Result + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, + { + let algorithm = signer.signature_algorithm_identifier()?; + + Ok(CertReq { + info: self.info, + algorithm, + signature, + }) + } +}