From 55549ac5bb137a43a3a18a378eb40f8f9dc937c4 Mon Sep 17 00:00:00 2001 From: shuibing <191098191@smail.nju.edu.cn> Date: Wed, 8 Nov 2023 15:25:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0crate-spec=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crate-spec/Cargo.toml | 11 + crate-spec/LICENSE-APACHE | 201 ++++++++++ crate-spec/LICENSE-MIT | 21 + crate-spec/LICENSE-THIRD-PARTY | 0 crate-spec/README.md | 132 ++++++ crate-spec/src/lib.rs | 1 + crate-spec/src/main.rs | 111 ++++++ crate-spec/src/pack.rs | 88 ++++ crate-spec/src/unpack.rs | 60 +++ crate-spec/src/utils/context.rs | 373 +++++++++++++++++ crate-spec/src/utils/decode.rs | 222 +++++++++++ crate-spec/src/utils/encode.rs | 160 ++++++++ crate-spec/src/utils/from_toml.rs | 101 +++++ crate-spec/src/utils/mod.rs | 6 + crate-spec/src/utils/package/bin.rs | 54 +++ crate-spec/src/utils/package/gen_bincode.rs | 419 ++++++++++++++++++++ crate-spec/src/utils/package/mod.rs | 354 +++++++++++++++++ crate-spec/src/utils/pkcs.rs | 181 +++++++++ crate-spec/test/args.txt | 2 + crate-spec/test/cert.pem | 19 + crate-spec/test/cert1.pem | 19 + crate-spec/test/example/decode_crate.sh | 5 + crate-spec/test/example/encode_crate.sh | 7 + crate-spec/test/example/hack.py | 25 ++ crate-spec/test/example/hack_file.sh | 4 + crate-spec/test/key.pem | 28 ++ crate-spec/test/root-ca.pem | 21 + crate-spec/test/test.toml | 12 + 28 files changed, 2637 insertions(+) create mode 100644 crate-spec/Cargo.toml create mode 100644 crate-spec/LICENSE-APACHE create mode 100644 crate-spec/LICENSE-MIT create mode 100644 crate-spec/LICENSE-THIRD-PARTY create mode 100644 crate-spec/README.md create mode 100644 crate-spec/src/lib.rs create mode 100644 crate-spec/src/main.rs create mode 100644 crate-spec/src/pack.rs create mode 100644 crate-spec/src/unpack.rs create mode 100644 crate-spec/src/utils/context.rs create mode 100644 crate-spec/src/utils/decode.rs create mode 100644 crate-spec/src/utils/encode.rs create mode 100644 crate-spec/src/utils/from_toml.rs create mode 100644 crate-spec/src/utils/mod.rs create mode 100644 crate-spec/src/utils/package/bin.rs create mode 100644 crate-spec/src/utils/package/gen_bincode.rs create mode 100644 crate-spec/src/utils/package/mod.rs create mode 100644 crate-spec/src/utils/pkcs.rs create mode 100644 crate-spec/test/args.txt create mode 100644 crate-spec/test/cert.pem create mode 100644 crate-spec/test/cert1.pem create mode 100644 crate-spec/test/example/decode_crate.sh create mode 100644 crate-spec/test/example/encode_crate.sh create mode 100644 crate-spec/test/example/hack.py create mode 100644 crate-spec/test/example/hack_file.sh create mode 100644 crate-spec/test/key.pem create mode 100644 crate-spec/test/root-ca.pem create mode 100644 crate-spec/test/test.toml diff --git a/crate-spec/Cargo.toml b/crate-spec/Cargo.toml new file mode 100644 index 00000000..0df302aa --- /dev/null +++ b/crate-spec/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "crate-spec" +version = "0.1.0" +edition = "2021" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bincode = {version = "2.0.0-rc.3", features = ["serde", "alloc"]} +openssl = "0.10.53" +toml = "0.7.4" +clap = {version = "4.3.0", features = ["derive"]} \ No newline at end of file diff --git a/crate-spec/LICENSE-APACHE b/crate-spec/LICENSE-APACHE new file mode 100644 index 00000000..b651cf1c --- /dev/null +++ b/crate-spec/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/LICENSE-2.0 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2022 Open Rust Initiative + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/crate-spec/LICENSE-MIT b/crate-spec/LICENSE-MIT new file mode 100644 index 00000000..91127361 --- /dev/null +++ b/crate-spec/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Open Rust Initiative + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crate-spec/LICENSE-THIRD-PARTY b/crate-spec/LICENSE-THIRD-PARTY new file mode 100644 index 00000000..e69de29b diff --git a/crate-spec/README.md b/crate-spec/README.md new file mode 100644 index 00000000..12e7ac07 --- /dev/null +++ b/crate-spec/README.md @@ -0,0 +1,132 @@ +# crate-spec +`crate-spec` is a new file format we've designed for Rust, characterized by its safety, reliability, and robustness. This brand-new file format allows Crate files to be mirrored and cached anywhere while providing end-to-end data integrity assurance and authentication capabilities. + +We provide an application(crate-spec) to generate (encode) and decode new crate file. +## Encode +When using the encode (`-e`) option, the program will invoke the `cargo package` command to check and package the Rust project and perform additional operations such as signing it, ultimately generating a `.scrate` file. + +You may use the following options. +* -e (**must provide**) + +This tells the application to encode Rust project to `.scrate` file. +* -r (**must provide**) + +This provides the path to the root certificate authority (CA) files (`.pem`). +* -c (**must provide**) + +This provides the publisher's certificate (`.pem`). +* -p (**must provide**) + +This provides the publisher's private key for signing the file (`.pem`). +* -o (**must provide**) + +This specifies the directory path for dumping the `.scrate` file. + +* \ (**must provide**) + +This is provided at the end of the command to specify the Rust project for encoding. + +Here's an encoding example, which you can also find in `test/example/encode_crate.sh` + +```bash +crate-spec -e \ + -r test/root-ca.pem \ + -c test/cert.pem \ + -p test/key.pem \ + -o test/output \ + ../crate-spec +``` + + +## Decode + +When using the decode (`-d`) option for decoding, the program will decode the .scrate file, verifying its integrity and source. Once the verification passes, it will decode the file back into the original `.crate` file, which is used by Cargo, and also dump the package's metadata to `{crate_name}-{version}-metadata.txt`. + +You may use the following options. + +* -d (**must provide**) + +This tells the application to decode `.scrate` file. + +* -r (**must provide**) + +This provides the path to the root certificate authority (CA) files (`.pem`). + +* -o (**must provide**) + +This specifies the directory path for decode the `.scrate` file. + +* \<`.scrate` file path\> (**must provide**) + +This is provided at the end of the command to specify the Rust `.scrate` file for decoding. + +Here's a decoding example, which you can also find in `test/example/decode_crate.sh` + +```bash +crate-spec -d \ + -r test/root-ca.pem \ + -o test/output \ + test/output/crate-spec-0.1.0.scrate +``` + +## Examples +You can find the example in `test/example`. + +### 1. encode Rust project +```bash +sh encode_crate.sh +``` + +This will encode this project (`crate-spec`) to `crate-spec-0.1.0.scrate` file in `test/output`. + +---------------- +### 2. decode `.scrate` file +```bash +sh decode_crate.sh +``` + +This will decode the `.scrate` file to original crate file `crate-spec-0.1.0.crate` and dump the metadata file `crate-spec-0.1.0-metadata.txt` in `test/output`. + +------- + +### 3. check integrity + +- **The situations of file transfer errors** + +**a.** First you generate the `.scarte` file. +```bash +sh encode_crate.sh +``` + +**b.** Assuming that during the scrate file transfer process, some bytes have encountered errors. +```bash +sh hack_file.sh 0 +``` +This will change some bytes in `crate-spec-0.1.0.scrate` file. + +**c.** Following this step, when you execute decode_crate.sh, you will encounter the subsequent error message: + +```bash +>> sh decode_crate.sh +fingerprint not right +``` + +- **The situation of intentionally tampering with files** + +**a.** First you generate the `.scarte` file again. +```bash +sh encode_crate.sh +``` + +**b.** Assuming someone has modified the file and recalculated the fingerprint. +```bash +sh hack_file.sh 1 +``` +This will change some bytes in `crate-spec-0.1.0.scrate` file and recalculate the fingerprint. + +**c.** Following this step, when you execute decode_crate.sh, you will encounter the subsequent error message: + +```bash +>> sh decode_crate.sh +file sig not right +``` \ No newline at end of file diff --git a/crate-spec/src/lib.rs b/crate-spec/src/lib.rs new file mode 100644 index 00000000..fab870e3 --- /dev/null +++ b/crate-spec/src/lib.rs @@ -0,0 +1 @@ +pub mod utils; \ No newline at end of file diff --git a/crate-spec/src/main.rs b/crate-spec/src/main.rs new file mode 100644 index 00000000..45b8ccff --- /dev/null +++ b/crate-spec/src/main.rs @@ -0,0 +1,111 @@ +use std::fs; +use std::path::PathBuf; +use std::str::FromStr; +use clap::{Parser}; +use crate_spec::utils::context::SIGTYPE; +use crate_spec::utils::pkcs::PKCS; +use crate::pack::{get_pack_context, get_pack_name}; +use crate::unpack::get_unpack_context; + +pub mod pack; +pub mod unpack; +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args{ + ///encode crate + #[clap(short, long, required=false)] + encode: bool, + ///decode crate + #[clap(short, long, required=false)] + decode: bool, + ///root-ca file paths + #[clap(short, long, required=false)] + root_ca_paths: Vec, + ///certification file path + #[clap(short, long, required=false)] + cert_path: Option, + ///private key path + #[clap(short, long, required=false)] + pkey_path:Option, + ///output file path + #[clap(short, long)] + output:String, + #[clap()] + input:String, +} + + +fn main() { + let args = Args::parse(); + if args.encode && !args.decode{ + //check args + if args.cert_path.is_none(){ + eprintln!("certificate not provided!"); + return; + } + if args.pkey_path.is_none(){ + eprintln!("pkey not provided!"); + return; + } + if args.root_ca_paths.is_empty(){ + eprintln!("root-ca not provided!"); + return; + } + + //check input file + let p = PathBuf::from_str(&args.input).unwrap(); + if !p.exists(){ + eprintln!("input files not found!"); + return; + } + + //pack package + let mut pack_context = get_pack_context(&args.input); + + //sign package + let mut pkcs = PKCS::new(); + pkcs.load_from_file_writer(args.cert_path.unwrap(), args.pkey_path.unwrap(), args.root_ca_paths); + pack_context.add_sig(pkcs, SIGTYPE::CRATEBIN); + + //encode package to binary + let (_, _, bin) = pack_context.encode_to_crate_package(); + + //dump binary path/.scrate + let mut bin_path = PathBuf::from_str(args.output.as_str()).unwrap(); + bin_path.push(get_pack_name(&pack_context)); + fs::write(bin_path, bin).unwrap(); + }else if !args.encode && args.decode{ + //check args + if args.root_ca_paths.is_empty(){ + eprintln!("root-ca not provided!"); + return; + } + + //check input file + let p = PathBuf::from_str(&args.input).unwrap(); + if !p.exists(){ + eprintln!("input files not found!"); + return; + } + + //decode package from binary + let pack_context = get_unpack_context(args.input.as_str(), args.root_ca_paths); + if pack_context.is_err(){ + eprintln!("{}", pack_context.unwrap_err()); + return; + } + let pack_context = pack_context.unwrap(); + //extract crate bin file + let mut bin_path = PathBuf::from_str(args.output.as_str()).unwrap(); + bin_path.push(format!("{}-{}.crate", pack_context.pack_info.name, pack_context.pack_info.version)); + fs::write(bin_path, pack_context.crate_binary.bytes).unwrap(); + + //dump scrate metadata + let mut metadata_path = PathBuf::from_str(args.output.as_str()).unwrap(); + metadata_path.push(format!("{}-{}-metadata.txt", pack_context.pack_info.name, pack_context.pack_info.version)); + fs::write(metadata_path, format!("{:#?}\n{:#?}", pack_context.pack_info, pack_context.dep_infos)).unwrap(); + }else{ + eprintln!("-e or -d not found!"); + return; + } +} \ No newline at end of file diff --git a/crate-spec/src/pack.rs b/crate-spec/src/pack.rs new file mode 100644 index 00000000..fb55915a --- /dev/null +++ b/crate-spec/src/pack.rs @@ -0,0 +1,88 @@ +use std::path::{PathBuf}; +use std::process::Command; +use std::{fs}; +use std::str::FromStr; +use crate_spec::utils::context::PackageContext; +use crate_spec::utils::from_toml::CrateToml; + +fn run_cmd(cmd:&str, args:Vec<&str>, cur_dir:Option<&PathBuf>)->Result{ + let mut output = Command::new(cmd); + if !args.is_empty(){ + output.args(args); + } + if cur_dir.is_some(){ + output.current_dir(cur_dir.unwrap()); + } + let output = output.output().expect(format!("error run cmd {}", cmd).as_str()); + return if output.status.success() { + let stdout = String::from_utf8_lossy(&output.stdout); + Ok(stdout.to_string()) + } else { + let stderr = String::from_utf8_lossy(&output.stderr); + Err(stderr.to_string()) + } +} +struct Packing { + pack_context:PackageContext, + crate_path: PathBuf, +} + +impl Packing { + fn new(crate_path:&str)->Self{ + Packing { + pack_context: PackageContext::new(), + crate_path: PathBuf::from_str(crate_path).unwrap() + } + } + + fn cmd_cargo_package(&self){ + let res = run_cmd("cargo",["package", "--allow-dirty"].to_vec(), Some(&self.crate_path)); + if res.is_err(){ + panic!("{}", res.unwrap_err()); + }else{ + println!("{}", res.unwrap()); + } + } + + fn read_crate(&mut self){ + //parse crate toml file + let mut toml_path = self.crate_path.clone(); + toml_path.push("Cargo.toml"); + let toml_path = fs::canonicalize(toml_path).unwrap(); + let toml = CrateToml::from_file(toml_path.to_str().unwrap().to_string()); + toml.write_info_to_package_context(&mut self.pack_context); + + //read crate binary + let crate_bin_file = format!("{}-{}.crate", self.pack_context.pack_info.name, self.pack_context.pack_info.version); + let mut crate_bin_path = self.crate_path.clone(); + crate_bin_path.push(format!("target/package/{}", crate_bin_file)); + let crate_bin_path = fs::canonicalize(crate_bin_path).unwrap(); + assert!(crate_bin_path.exists()); + let bin = fs::read(crate_bin_path).unwrap(); + + //write to pack_context + self.pack_context.add_crate_bin(bin); + } + + fn get_pack_context(mut self)->PackageContext{ + self.cmd_cargo_package(); + self.read_crate(); + self.pack_context + } + +} + +pub fn get_pack_context(path:&str)->PackageContext{ + Packing::new(path).get_pack_context() +} + +pub fn get_pack_name(pack: &PackageContext)->String{ + format!("{}-{}.scrate", pack.pack_info.name, pack.pack_info.version) +} + + +#[test] +fn test_cmd_cargo_package(){ + let pac = get_pack_context("../crate-spec"); + println!("{:#?}", pac); +} diff --git a/crate-spec/src/unpack.rs b/crate-spec/src/unpack.rs new file mode 100644 index 00000000..221ac6f8 --- /dev/null +++ b/crate-spec/src/unpack.rs @@ -0,0 +1,60 @@ +use std::fs; +use std::path::PathBuf; +use std::str::FromStr; +use crate_spec::utils::context::{PackageContext}; +use crate_spec::utils::pkcs::PKCS; + +struct Unpacking { + file_path: PathBuf, + cas_path: Vec +} + +impl Unpacking { + pub fn new(path:&str)-> Unpacking { + Unpacking{ + file_path: PathBuf::from_str(path).unwrap(), + cas_path: Vec::new() + } + } + + pub fn add_ca_from_file(&mut self, path:&str){ + let file_path = fs::canonicalize(PathBuf::from_str(path).unwrap()).unwrap(); + self.cas_path.push(file_path.to_str().unwrap().to_string()); + } + + pub fn get_unpack_context(self)->Result{ + let mut package_context_new = PackageContext::new(); + package_context_new.set_root_cas_bin(PKCS::get_root_ca_bins(self.cas_path)); + let bin = fs::read(self.file_path).unwrap(); + let (_crate_package_new, _str_table) = package_context_new.decode_from_crate_package(bin.as_slice())?; + Ok(package_context_new) + } +} + +pub fn get_unpack_context(file_path:&str, cas_path:Vec) ->Result{ + let mut unpack = Unpacking::new(file_path); + cas_path.iter().for_each(|ca_path|unpack.add_ca_from_file(ca_path.as_str())); + unpack.get_unpack_context() +} + +#[test] +fn test_unpack(){ + use crate::pack::get_pack_context; + use crate_spec::utils::context::{SIGTYPE}; + let mut pack_context = get_pack_context("../crate-spec"); + fn get_sign()->PKCS{ + let mut pkcs1 = PKCS::new(); + pkcs1.load_from_file_writer("test/cert.pem".to_string(), "test/key.pem".to_string(), ["test/root-ca.pem".to_string()].to_vec()); + pkcs1 + } + pack_context.add_sig(get_sign(), SIGTYPE::CRATEBIN); + + let (_, _, bin) = pack_context.encode_to_crate_package(); + fs::write(PathBuf::from_str("test/crate-spec.cra").unwrap(), bin).unwrap(); + + let pack_context_decode = get_unpack_context("test/crate-spec.cra", vec!["test/root-ca.pem".to_string()]); + + assert_eq!(pack_context_decode.pack_info, pack_context.pack_info); + assert_eq!(pack_context_decode.dep_infos, pack_context.dep_infos); + assert_eq!(pack_context_decode.crate_binary, pack_context.crate_binary); +} \ No newline at end of file diff --git a/crate-spec/src/utils/context.rs b/crate-spec/src/utils/context.rs new file mode 100644 index 00000000..13ac15cd --- /dev/null +++ b/crate-spec/src/utils/context.rs @@ -0,0 +1,373 @@ +use std::collections::{HashMap}; +use crate::utils::package::{CrateBinarySection, DepTableEntry, LenArrayType, PackageSection, RawArrayType, SigStructureSection, Size, Type}; +use crate::utils::pkcs::PKCS; + +pub const NOT_SIG_NUM:usize = 3; + +pub enum SIGTYPE { + FILE, + CRATEBIN, +} + +pub enum DATASECTIONTYPE{ + PACK = 0, + DEPTABLE = 1, + CRATEBIN = 3, + SIGSTRUCTURE = 4, +} + + +///package context contains package's self and dependency package info +#[derive(Debug, PartialEq)] +pub struct PackageContext { + pub pack_info: PackageInfo, + pub dep_infos: Vec, + pub crate_binary: CrateBinary, + pub sigs: Vec, + pub root_cas: Vec> +} + +impl PackageContext { + pub fn new() -> Self { + Self { + pack_info: PackageInfo::default(), + crate_binary: CrateBinary::new(), + dep_infos: vec![], + sigs: vec![], + root_cas: vec![], + } + } + + pub fn set_package_info(&mut self, name:String, version:String, license:String, authors:Vec){ + self.pack_info = PackageInfo{name, version, license, authors} + } + + pub fn add_dep_info(&mut self, name:String, ver_req:String, src:SrcTypePath, src_platform:String){ + self.dep_infos.push( + DepInfo{ + name, + ver_req, + src, + src_platform, + dump: true, + } + ); + } + + pub fn get_dep_num(&self)-> usize{ + self.dep_infos.len() + } + + pub fn add_sig(&mut self, pkcs: PKCS, sign_type: SIGTYPE) -> usize { + let mut siginfo = SigInfo::new(); + siginfo.pkcs = pkcs; + match sign_type { + SIGTYPE::FILE => siginfo.typ = 0, + SIGTYPE::CRATEBIN => siginfo.typ = 1 + } + self.sigs.push(siginfo); + self.sigs.len() - 1 + } + + pub fn get_sig_num(&self) -> usize { + return self.sigs.len(); + } + + pub fn set_root_cas_bin(&mut self, root_ca_bins: Vec>) { + self.root_cas = root_ca_bins; + } + + pub fn add_root_cas(&mut self, root_ca:Vec){ + self.root_cas.push(root_ca); + } + + pub fn add_crate_bin(&mut self, bin:Vec){ + let mut c = CrateBinary::new(); + c.set_bin(bin); + self.crate_binary = c; + } +} + + +///package's info +#[derive(Debug, PartialEq)] +pub struct PackageInfo { + pub name: String, + pub version: String, + pub license: String, + pub authors: Vec +} + +impl PackageInfo{ + pub fn default()->Self{ + Self{ + name: "".to_string(), + version: "".to_string(), + license: "".to_string(), + authors: vec![], + } + } + + pub fn new(name: String, version:String, lisense:String, authors:Vec)->Self{ + Self{ + name, + version, + license: lisense, + authors + } + } + + pub fn write_to_package_section(&self, ps: &mut PackageSection, str_table: &mut StringTable){ + ps.pkg_name = str_table.insert_str(self.name.clone()); + ps.pkg_version = str_table.insert_str(self.version.clone()); + ps.pkg_license = str_table.insert_str(self.license.clone()); + let mut authors_off = vec![]; + self.authors.iter().for_each(|author|{ + authors_off.push(str_table.insert_str(author.clone())); + }); + ps.pkg_authors = LenArrayType::copy_from_vec(&authors_off); + } + + pub fn read_from_package_section(&mut self, ps: &PackageSection, str_table: & StringTable){ + self.name = str_table.get_str_by_off(&ps.pkg_name); + self.version = str_table.get_str_by_off(&ps.pkg_version); + self.license = str_table.get_str_by_off(&ps.pkg_license); + let authors_off = ps.pkg_authors.to_vec(); + authors_off.iter().for_each(|author_off|{ + self.authors.push(str_table.get_str_by_off(author_off)); + }); + } +} + +///dependencies' info +#[derive(Debug, PartialEq)] +pub struct DepInfo { + pub name: String, + pub ver_req: String, + pub src: SrcTypePath, + pub src_platform: String, + ///only dump dependency that can be written to crate dependency table section + pub dump: bool +} + +impl DepInfo{ + pub fn default()->Self{ + Self{ + name: "".to_string(), + ver_req: "default".to_string(), + src: SrcTypePath::CratesIo, + src_platform: "default".to_string(), + dump: true, + } + } + + pub fn new(name: String, ver_req:String, src: SrcTypePath, src_platform: String, dump:bool)->Self{ + Self{ + name, + ver_req, + src, + src_platform, + dump + } + } + + pub fn write_to_dep_table_entry(&self, dte: &mut DepTableEntry, str_table: &mut StringTable){ + dte.dep_name = str_table.insert_str(self.name.clone()); + dte.dep_verreq = str_table.insert_str(self.ver_req.clone()); + match &self.src{ + SrcTypePath::CratesIo =>{ + dte.dep_srctype = 0; + dte.dep_srcpath = str_table.insert_str("".to_string()); + } + SrcTypePath::Git(str)=>{ + dte.dep_srctype = 1; + dte.dep_srcpath = str_table.insert_str(str.clone()); + } + SrcTypePath::Url(str)=>{ + dte.dep_srctype = 2; + dte.dep_srcpath = str_table.insert_str(str.clone()); + } + SrcTypePath::Registry(str)=>{ + dte.dep_srctype = 3; + dte.dep_srcpath = str_table.insert_str(str.clone()); + } + SrcTypePath::P2p(str)=>{ + dte.dep_srctype = 4; + dte.dep_srcpath = str_table.insert_str(str.clone()); + } + } + dte.dep_platform = str_table.insert_str(self.src_platform.to_string()); + } + + pub fn read_from_dep_table_entry(&mut self, dte: & DepTableEntry, str_table: &StringTable){ + self.dump = true; + self.name = str_table.get_str_by_off(&dte.dep_name); + self.ver_req = str_table.get_str_by_off(&dte.dep_verreq); + match dte.dep_srctype{ + 0 => { + self.src = SrcTypePath::CratesIo; + } + 1 => { + self.src = SrcTypePath::Git(str_table.get_str_by_off(&dte.dep_srcpath)); + } + 2 => { + self.src = SrcTypePath::Url(str_table.get_str_by_off(&dte.dep_srcpath)); + } + 3 => { + self.src = SrcTypePath::Registry(str_table.get_str_by_off(&dte.dep_srcpath)); + } + 4 => { + self.src = SrcTypePath::P2p(str_table.get_str_by_off(&dte.dep_srcpath)); + } + _ => { + panic!("dep_srctype not valid!") + } + } + self.src_platform = str_table.get_str_by_off(&dte.dep_platform); + } +} + +///dependencies' src type and path +#[derive(Debug, PartialEq)] +pub enum SrcTypePath{ + CratesIo, + Git(String), + Url(String), + Registry(String), + P2p(String) +} + +///StringTable +pub struct StringTable{ + str2off: HashMap, + off2str: HashMap, + total_bytes: u32 +} + +impl StringTable{ + pub fn default()->Self{ + Self::new() + } + + pub fn new()->Self{ + let mut new_str_table = Self{ + str2off: Default::default(), + off2str: Default::default(), + total_bytes: 0, + }; + new_str_table.insert_str("".to_string()); + new_str_table + } + + pub fn insert_str(&mut self, st:String)->u32{ + return if self.str2off.contains_key(&st) { + self.str2off.get(&st).unwrap().clone() + } else { + let st_len = st.as_bytes().len() as u32; + let ret_val = self.total_bytes; + self.str2off.insert(st.clone(), self.total_bytes); + self.off2str.insert(self.total_bytes, st.clone()); + self.total_bytes += 4 + st_len; + ret_val + } + } + + pub fn contains_str(&self, st: &String)->bool{ + self.str2off.contains_key(st) + } + + pub fn get_off_by_str(&self, st: &String)-> u32{ + *self.str2off.get(st).unwrap() + } + + pub fn get_str_by_off(&self, off: &u32)->String{ + self.off2str.get(off).unwrap().clone() + } + + ///dump string table to bytes + pub fn to_bytes(&self)->Vec{ + let mut offs:Vec<_> = self.off2str.keys().cloned().collect(); + offs.sort(); + let mut bytes = vec![]; + for off in offs{ + //FIXME we use little endian + let st = self.off2str.get(&off).unwrap().bytes().clone(); + bytes.extend((st.len() as u32).to_le_bytes()); + bytes.extend(st); + } + return bytes; + } + + ///parse string table from bytes + pub fn read_bytes(&mut self, bytes: &[u8]){ + let mut i = 0; + while i < bytes.len(){ + let mut len_bytes:[u8; 4]= [0;4]; + len_bytes.copy_from_slice(bytes[i..i+4].as_ref()); + let len = u32::from_le_bytes(len_bytes) as usize; + let st = String::from_utf8(bytes[i + 4..i + 4 + len].to_vec()).unwrap(); + self.str2off.insert(st.clone(), i as u32); + self.off2str.insert(i as u32, st); + i += 4 + len; + self.total_bytes = i as u32; + } + } +} +#[derive(Debug, PartialEq)] +pub struct CrateBinary { + //FIXME this maybe change to for fast read + pub bytes:Vec, +} + +impl CrateBinary{ + pub fn new()->Self{ + Self{ + bytes:vec![] + } + } + + pub fn set_bin(&mut self, bytes:Vec){ + self.bytes = bytes; + } + + pub fn write_to_crate_binary_section(&self, cbs: &mut CrateBinarySection){ + cbs.bin.arr = self.bytes.to_vec(); + } + + pub fn read_from_crate_biary_section(&mut self, cbs:& CrateBinarySection){ + self.bytes = cbs.bin.arr.to_vec(); + } +} + +#[derive(Debug, PartialEq)] +pub struct SigInfo{ + pub typ:u32, + pub size:usize, + pub bin: Vec, + pub pkcs: PKCS, +} + +impl SigInfo{ + pub fn new()->Self{ + SigInfo{ + typ: 0, + size: 0, + bin: vec![], + pkcs: PKCS::new(), + } + } + + pub fn read_from_sig_structure_section(&mut self, sig: & SigStructureSection){ + //FIXME current it's not right + self.typ = sig.sigstruct_type as u32; + self.size = sig.sigstruct_size as usize; + self.bin = sig.sigstruct_sig.arr.clone(); + } + + pub fn write_to_sig_structure_section(&self, sig: &mut SigStructureSection){ + //FIXME current it's not right + sig.sigstruct_type = self.typ as Type; + sig.sigstruct_size = self.size as Size; + sig.sigstruct_sig = RawArrayType::from_vec(self.bin.clone()); + } +} diff --git a/crate-spec/src/utils/decode.rs b/crate-spec/src/utils/decode.rs new file mode 100644 index 00000000..923fdf65 --- /dev/null +++ b/crate-spec/src/utils/decode.rs @@ -0,0 +1,222 @@ +use crate::utils::context::{DepInfo, PackageContext, SigInfo, StringTable}; +use crate::utils::package::{CrateBinarySection, CratePackage, DataSection, DepTableSection, FINGERPRINT_LEN, PackageSection, SectionIndex, SigStructureSection}; + +use crate::utils::pkcs::PKCS; + + +impl SectionIndex{ + pub fn get_section_id_by_typ(&self, typ:usize)->usize{ + for (i, entry) in self.entries.arr.iter().enumerate(){ + if entry.sh_type as usize == typ{ + return i; + } + } + panic!("section typ not found") + } +} + + +impl CratePackage{ + pub fn get_data_section_by_id(&self, id:usize)->&DataSection{ + &self.data_sections.col.arr[id] + } + + pub fn get_data_section_by_typ(&self, typ:usize)->&DataSection{ + self.get_data_section_by_id(self.section_index.get_section_id_by_typ(typ)) + } + + pub fn get_package_section(&self)->&PackageSection{ + //FIXME: 0 should be constant + match self.get_data_section_by_typ(0){ + DataSection::PackageSection(pak)=>{pak} + _ => {panic!("package section not found!")} + } + } + + pub fn get_dep_table_section(&self)->&DepTableSection{ + match self.get_data_section_by_typ(1){ + DataSection::DepTableSection(dep) => {dep}, + _ => {panic!("dep table section not found!")} + } + } + + pub fn get_crate_binary_section(&self)->&CrateBinarySection{ + match self.get_data_section_by_typ(3){ + DataSection::CrateBinarySection(cra) => {cra}, + _ => {panic!("crate binary section not found!")} + } + } + + pub fn get_sig_structure_section(&self, no: usize)-> &SigStructureSection{ + let base = self.section_index.get_section_id_by_typ(4); + match self.get_data_section_by_id(no + base){ + DataSection::SigStructureSection(sig) => {sig}, + _ => {panic!("sig structure section not found!")} + } + } + +} +impl PackageContext{ + pub fn get_binary_before_sig(&self, crate_package: &CratePackage, bin:&[u8]) -> Vec { + //FIXME + let ds_size = crate_package.section_index.get_datasection_size_without_sig(); + let total_size = crate_package.crate_header.ds_offset as usize + ds_size; + if crate_package.section_index.get_sig_num() != self.sigs.len() && self.sigs.len() > 0{ + assert_eq!(crate_package.section_index.get_sig_num(), 0); + + }else{ + + } + let mut buf = bin[..total_size].to_vec(); + let zero_begin = crate_package.crate_header.si_offset as usize + crate_package.section_index.get_none_sig_size(); + let zero_end = crate_package.crate_header.si_offset as usize + crate_package.crate_header.si_size as usize; + //FIXME this is not efficient + for i in zero_begin..zero_end{ + buf[i] = 0; + } + + buf + } + + pub fn get_binary_before_digest(&self, bin:&[u8])-> Vec{ + bin[..bin.len() - FINGERPRINT_LEN].to_vec() + } + + fn get_pack_info(&mut self, crate_package: &CratePackage, str_table: &StringTable){ + self.pack_info.read_from_package_section(crate_package.get_package_section(), &str_table); + } + + + fn get_deps(&mut self, crate_package: &CratePackage, str_table: &StringTable){ + for entry in crate_package.get_dep_table_section().entries.arr.iter(){ + let mut dep_info = DepInfo::default(); + dep_info.read_from_dep_table_entry(entry, str_table); + self.dep_infos.push(dep_info); + } + } + + fn get_binary(&mut self, crate_package: &CratePackage){ + self.crate_binary.bytes = crate_package.get_crate_binary_section().bin.arr.clone(); + } + + fn get_sigs(&mut self, crate_package: &CratePackage){ + let sig_num = crate_package.section_index.get_sig_num(); + for no in 0.. sig_num{ + let sig = crate_package.get_sig_structure_section(no); + let mut sig_info = SigInfo::new(); + sig_info.bin = sig.sigstruct_sig.arr.clone(); + sig_info.size = sig.sigstruct_size as usize; + sig_info.typ = sig.sigstruct_type as u32; + self.sigs.push(sig_info); + } + } + + fn check_fingerprint(&self, bin_all:&[u8])->bool{ + PKCS::new().gen_digest_256(&bin_all[..bin_all.len() - FINGERPRINT_LEN]) == bin_all[bin_all.len() - FINGERPRINT_LEN..] + } + + fn check_sigs(&self, crate_package: &CratePackage, bin_all:&[u8])->bool{ + let bin_all = self.get_binary_before_sig(crate_package, bin_all); + let bin_crate = crate_package.get_crate_binary_section().bin.arr.as_slice(); + for siginfo in self.sigs.iter(){ + let actual_digest ; + //FIXME this should be encapsulated as it's used in encode as well + match siginfo.typ { + 0 => { + actual_digest = siginfo.pkcs.gen_digest_256(bin_all.as_slice()); + } + 1 => { + actual_digest = siginfo.pkcs.gen_digest_256(bin_crate); + } + _ => {panic!("sig type is not right!")} + } + let expect_digest = PKCS::decode_pkcs_bin(siginfo.bin.as_slice(), &self.root_cas); + if actual_digest != expect_digest { + return false + }; + } + true + } + + pub fn decode_from_crate_package(&mut self, bin:&[u8])->Result<(CratePackage, StringTable), String>{ + if self.check_fingerprint( bin) == false{ + return Err("fingerprint not right".to_string()); + } + let crate_package = CratePackage::decode_from_slice(bin)?; + let mut str_table = StringTable::new(); + str_table.read_bytes(crate_package.string_table.arr.as_slice()); + self.get_pack_info(&crate_package, &str_table); + self.get_deps(&crate_package, &str_table); + self.get_binary(&crate_package); + self.get_sigs(&crate_package); + if self.check_sigs(&crate_package, bin) == false{ + return Err("file sig not right".to_string()); + } + return Ok((crate_package, str_table)); + } +} + +#[test] +fn test_encode_decode() { + use crate::utils::context::{PackageInfo, SIGTYPE, SrcTypePath}; + fn get_pack_info()->PackageInfo{ + PackageInfo{ + name: "rust-crate".to_string(), + version: "1.0.0".to_string(), + license: "MIT".to_string(), + authors: vec!["shuibing".to_string(), "rust".to_string()], + } + } + + fn get_dep_info1()->DepInfo{ + DepInfo{ + name: "toml".to_string(), + ver_req: "1.0.0".to_string(), + src: SrcTypePath::CratesIo, + src_platform: "ALL".to_string(), + dump: true, + } + } + + + fn get_dep_info2()->DepInfo{ + DepInfo{ + name: "crate-spec".to_string(), + ver_req: ">=0.8.0".to_string(), + src: SrcTypePath::Git("http://git.com".to_string()), + src_platform: "windows".to_string(), + dump: true, + } + } + + fn get_crate_binary()->Vec{ + [15;100].to_vec() + } + + fn get_sign()->PKCS{ + let mut pkcs1 = PKCS::new(); + pkcs1.load_from_file_writer("test/cert.pem".to_string(), "test/key.pem".to_string(), ["test/root-ca.pem".to_string()].to_vec()); + pkcs1 + } + + let mut package_context = PackageContext::new(); + + package_context.pack_info = get_pack_info(); + package_context.dep_infos.push(get_dep_info1()); + package_context.dep_infos.push(get_dep_info2()); + package_context.crate_binary.bytes = get_crate_binary(); + package_context.add_sig(get_sign(), SIGTYPE::CRATEBIN); + package_context.add_sig(get_sign(), SIGTYPE::FILE); + + let (_crate_package, _str_table, bin) = package_context.encode_to_crate_package(); + + + let mut package_context_new = PackageContext::new(); + package_context_new.set_root_cas_bin(PKCS::get_root_ca_bins(["test/root-ca.pem".to_string()].to_vec())); + let (_crate_package_new, _str_table) = package_context_new.decode_from_crate_package(bin.as_slice()).unwrap(); + + assert_eq!(get_pack_info(), package_context_new.pack_info); + assert_eq!(get_dep_info1(), package_context_new.dep_infos[0]); + assert_eq!(get_dep_info2(), package_context_new.dep_infos[1]); + assert_eq!(get_crate_binary(), package_context_new.crate_binary.bytes); +} \ No newline at end of file diff --git a/crate-spec/src/utils/encode.rs b/crate-spec/src/utils/encode.rs new file mode 100644 index 00000000..dfb1b5c9 --- /dev/null +++ b/crate-spec/src/utils/encode.rs @@ -0,0 +1,160 @@ + +use crate::utils::context::{NOT_SIG_NUM, PackageContext, StringTable}; +use crate::utils::package::{CrateBinarySection, CratePackage, CRATEVERSION, DataSection, DataSectionCollectionType, DepTableEntry, DepTableSection, FINGERPRINT_LEN, get_datasection_type, LenArrayType, MAGIC_NUMBER, Off, PackageSection, RawArrayType, SectionIndexEntry, SigStructureSection, Size}; + +use crate::utils::package::gen_bincode::{encode2vec_by_bincode, encode_size_by_bincode}; +use crate::utils::pkcs::PKCS; + + +impl CratePackage{ + pub fn set_section_index(&mut self){ + self.section_index.entries.arr = vec![]; + for (i, (_size, _off)) in self.data_sections.encode_size_offset().iter().enumerate(){ + let size = *_size; + let off = *_off; + let typ = get_datasection_type(&self.data_sections.col.arr[i]); + self.section_index.entries.arr.push(SectionIndexEntry::new(typ, off as Off, size as Size)); + } + } + + pub fn set_string_table(&mut self, str_table: & StringTable){ + self.string_table = RawArrayType::from_vec(str_table.to_bytes()); + } + + + pub fn set_crate_header(&mut self, fake_num: usize){ + self.crate_header.c_version = CRATEVERSION; + self.crate_header.strtable_size = self.string_table.get_size() as Size; + self.crate_header.strtable_offset = (self.crate_header.get_size() + self.magic_number.len()) as Size; + self.crate_header.si_size = self.section_index.get_size() as Size + (fake_num * SectionIndexEntry::default().get_size()) as Size; + self.crate_header.si_num = self.section_index.get_num() as Size + fake_num as Size; + self.crate_header.si_offset = self.crate_header.strtable_offset + self.crate_header.strtable_size; + self.crate_header.ds_offset = self.crate_header.si_offset + self.crate_header.si_size; + } + + pub fn set_magic_numer(&mut self){ + self.magic_number = MAGIC_NUMBER; + } + + pub fn set_finger_print(&mut self, fp: Vec){ + self.finger_print.copy_from_slice(fp.as_slice()); + } +} + + +impl PackageContext{ + fn write_to_data_section_collection_without_sig(&self, dsc: &mut DataSectionCollectionType, str_table: &mut StringTable) { + let mut package_section = PackageSection::new(); + self.write_to_package_section(&mut package_section, str_table); + dsc.col.arr.push(DataSection::PackageSection(package_section)); + + + let mut dep_table_section = DepTableSection::new(); + self.write_to_dep_table_section(&mut dep_table_section, str_table); + dsc.col.arr.push(DataSection::DepTableSection(dep_table_section)); + + let mut binary_section = CrateBinarySection::new(); + self.write_to_crate_binary_section(&mut binary_section); + dsc.col.arr.push(DataSection::CrateBinarySection(binary_section)); + } + + pub fn write_to_data_section_collection_sig(&self, dsc: &mut DataSectionCollectionType) { + for siginfo in self.sigs.iter() { + let mut sig = SigStructureSection::new(); + siginfo.write_to_sig_structure_section(&mut sig); + dsc.col.arr.push(DataSection::SigStructureSection(sig)); + } + } + + fn write_to_package_section(&self, ps: &mut PackageSection, str_table: &mut StringTable){ + self.pack_info.write_to_package_section(ps, str_table); + encode_size_by_bincode(ps); + } + + + fn write_to_dep_table_section(&self, dts:&mut DepTableSection, str_table: &mut StringTable){ + let mut entries = vec![]; + self.dep_infos.iter().for_each(|dep_info|{ + let mut dte = DepTableEntry::new(); + dep_info.write_to_dep_table_entry(&mut dte, str_table); + entries.push(dte); + }); + dts.entries = LenArrayType::from_vec(entries); + } + + + fn write_to_crate_binary_section(&self, cbs: &mut CrateBinarySection){ + self.crate_binary.write_to_crate_binary_section(cbs); + } + fn set_sigs(&self, crate_package: &mut CratePackage, non_sig_num:usize){ + crate_package.data_sections.col.arr.truncate(non_sig_num); + self.write_to_data_section_collection_sig(&mut crate_package.data_sections); + } + + fn set_pack_dep_bin(&self, crate_package: &mut CratePackage, str_table: &mut StringTable){ + self.write_to_data_section_collection_without_sig(&mut crate_package.data_sections, str_table); + } + + fn calc_sigs(&mut self, crate_package: &CratePackage){ + let bin_all = encode2vec_by_bincode(crate_package); + let bin_all = self.get_binary_before_sig(crate_package, bin_all.as_slice()); + let bin_crate = crate_package.get_crate_binary_section().bin.arr.as_slice(); + self.sigs.iter_mut().for_each(|siginfo|{ + let digest; + match siginfo.typ { + 0 => { + digest = siginfo.pkcs.gen_digest_256(bin_all.as_slice()); + } + 1 => { + digest = siginfo.pkcs.gen_digest_256(bin_crate); + } + _ => {panic!("sig type is not right!")} + } + siginfo.bin = siginfo.pkcs.encode_pkcs_bin(digest.as_slice()); + siginfo.size = siginfo.bin.len(); + }); + } + + fn calc_fingerprint(&self, crate_package: &CratePackage)->Vec{ + let bin_all = encode2vec_by_bincode(crate_package); + PKCS::new().gen_digest_256(&bin_all[..bin_all.len() - FINGERPRINT_LEN]) + } + + //1 before sig + fn encode_to_crate_package_before_sig(&self, str_table: &mut StringTable, crate_package: &mut CratePackage){ + crate_package.set_magic_numer(); + self.set_pack_dep_bin(crate_package, str_table); + //this is setting fake sigsection + self.set_sigs(crate_package, NOT_SIG_NUM); + crate_package.set_section_index(); + crate_package.set_string_table(str_table); + crate_package.set_crate_header(0); + } + + //2 sig + fn encode_sig_to_crate_package(&mut self, crate_package: &mut CratePackage){ + self.calc_sigs(crate_package); + //this is setting true sigsection + self.set_sigs(crate_package, NOT_SIG_NUM); + } + + //3 after sig + fn encode_to_crate_package_after_sig(&self, crate_package: &mut CratePackage){ + crate_package.set_section_index(); + crate_package.set_crate_header(0); + let finger_print = self.calc_fingerprint(crate_package); + crate_package.set_finger_print(finger_print); + } + + + //1 2 3 + pub fn encode_to_crate_package(&mut self)->(CratePackage, StringTable, Vec){ + let mut crate_package = CratePackage::new(); + let mut str_table = StringTable::new(); + self.encode_to_crate_package_before_sig(&mut str_table, &mut crate_package, ); + self.encode_sig_to_crate_package(&mut crate_package); + self.encode_to_crate_package_after_sig(&mut crate_package); + let bin = encode2vec_by_bincode(&crate_package); + (crate_package, str_table, bin) + } +} diff --git a/crate-spec/src/utils/from_toml.rs b/crate-spec/src/utils/from_toml.rs new file mode 100644 index 00000000..a1742af9 --- /dev/null +++ b/crate-spec/src/utils/from_toml.rs @@ -0,0 +1,101 @@ +use std::collections::HashSet; +use std::fs; +use std::path::Path; +use std::str::FromStr; +use toml::Table; +use crate::utils::context::{DepInfo, PackageContext, SrcTypePath}; + +pub struct CrateToml{ + t:Table +} + +impl CrateToml{ + pub fn default()->Self{ + CrateToml{ + t: Default::default(), + } + } + pub fn from_file(path:String)->CrateToml{ + let f = fs::read(Path::new(path.as_str())).unwrap(); + CrateToml::from_vec(f) + } + + pub fn from_vec(st_vec: Vec)->CrateToml{ + CrateToml::from_str(String::from_utf8(st_vec).unwrap().as_str()) + } + + pub fn from_str(st: &str)->CrateToml{ + CrateToml{ + t:Table::from_str(st).unwrap() + } + } +} + +impl CrateToml{ + fn write_package_info_to_package_context(&self, package_context: &mut PackageContext, package: &Table){ + let name = package["name"].as_str().unwrap().to_string(); + let version = package["version"].as_str().unwrap().to_string(); + let mut license="".to_string(); + let mut authors = Vec::::new(); + if package.contains_key("license"){ + license = package["license"].as_str().unwrap().to_string(); + } + if package.contains_key("authors"){ + authors = package["authors"].as_array().unwrap().iter().map(|x|x.as_str().unwrap().to_string()).collect(); + } + package_context.set_package_info(name, version, license, authors); + } + + fn write_dep_info_to_package_context(&self, package_context: &mut PackageContext, deps: &Table, platform:String)->Vec{ + let mut irresolve_depinfos = vec![]; + for dep in deps.iter(){ + let mut dep_info = DepInfo::default(); + dep_info.src_platform = platform.to_string(); + dep_info.name = dep.0.to_string(); + let val = dep.1; + if val.is_str(){ + dep_info.ver_req = val.as_str().unwrap().to_string(); + }else{ + let attri_map = val.as_table().unwrap(); + let allow_keys = HashSet::from(["version".to_string(), "git".to_string(), "registry".to_string()]); + for attri in attri_map.keys(){ + if !allow_keys.contains(attri){ + dep_info.dump = false; + } + } + if attri_map.contains_key("version") { + dep_info.ver_req = attri_map["version"].as_str().unwrap().to_string(); + } + if attri_map.contains_key("git"){ + dep_info.src = SrcTypePath::Git(attri_map["git"].as_str().unwrap().to_string()); + } + if attri_map.contains_key("registry"){ + dep_info.src = SrcTypePath::Registry(attri_map["registry"].as_str().unwrap().to_string()); + } + } + if dep_info.dump{ + package_context.add_dep_info(dep_info.name, dep_info.ver_req, dep_info.src, dep_info.src_platform); + }else{ + irresolve_depinfos.push(dep_info.name); + } + } + return irresolve_depinfos; + } + + pub fn write_info_to_package_context(&self, package_context: &mut PackageContext)->Vec{ + assert!(self.t.contains_key("package")); + self.write_package_info_to_package_context(package_context, self.t.get("package").unwrap().as_table().unwrap()); + let excluded_crate; + //FIXME current platform is not considered, we only consider [dependencies], see https://course.rs/cargo/reference/specify-deps.html#build-dependencies + excluded_crate = self.write_dep_info_to_package_context(package_context, self.t.get("dependencies").unwrap().as_table().unwrap(), "".to_string()); + excluded_crate + } +} + +#[test] +fn test_toml(){ + let toml = CrateToml::from_file("test/test.toml".to_string()); + let mut pack_context = PackageContext::new(); + println!("{:?}", toml.write_info_to_package_context(&mut pack_context)); + println!("{:#?}", pack_context); +} \ No newline at end of file diff --git a/crate-spec/src/utils/mod.rs b/crate-spec/src/utils/mod.rs new file mode 100644 index 00000000..6cce3374 --- /dev/null +++ b/crate-spec/src/utils/mod.rs @@ -0,0 +1,6 @@ +pub mod package; +pub mod encode; +pub mod decode; +pub mod context; +pub mod pkcs; +pub mod from_toml; diff --git a/crate-spec/src/utils/package/bin.rs b/crate-spec/src/utils/package/bin.rs new file mode 100644 index 00000000..98b5e43a --- /dev/null +++ b/crate-spec/src/utils/package/bin.rs @@ -0,0 +1,54 @@ +use std::io::{BufRead, Write}; +use std::mem::size_of; +use std::{vec}; +use bincode; +use bincode::{enc}; + +use crate::utils::package::{*}; +use crate::utils::package::gen_bincode::{create_bincode_slice_decoder, encode2vec_by_bincode}; + +pub trait Encode{ + fn encode(&self)->Vec; + fn encode_to_vec(&self)->Vec{ + self.encode() + } + fn encode_to_writer (&self, writer: &mut W)->usize{ + writer.write(&self.encode()).unwrap() + } +} + +pub trait Decode{ + type Output; + fn decode(bin: &[u8])->Self::Output; + fn decode_from_vec(bin: &Vec)->Self::Output{ + Self::decode(bin.as_slice()) + } + fn decode_from_slice(bin: &[u8])->Self::Output{ + Self::decode(bin) + } + fn decode_from_reader(reader: &mut W, size: usize)->Self::Output{ + let mut buf = vec![0u8; size]; + reader.read(buf.as_mut_slice()).unwrap(); + Self::decode(buf.as_mut_slice()) + } +} + +impl Encode for RawArrayType{ + fn encode(&self) -> Vec { + encode2vec_by_bincode(self) + } +} + +impl Decode for RawArrayType { + type Output = RawArrayType; + fn decode(bin: &[u8]) -> Self::Output { + let mut decoder = create_bincode_slice_decoder(bin); + let mut output = RawArrayType::new(); + let len = bin.len() / size_of::(); + for _i in 0..len{ + output.arr.push(bincode::Decode::decode(&mut decoder).unwrap()); + } + output + } +} + diff --git a/crate-spec/src/utils/package/gen_bincode.rs b/crate-spec/src/utils/package/gen_bincode.rs new file mode 100644 index 00000000..49335414 --- /dev/null +++ b/crate-spec/src/utils/package/gen_bincode.rs @@ -0,0 +1,419 @@ + + + +use bincode; +use bincode::config::{Configuration, Fixint, legacy, LittleEndian, NoLimit}; +use bincode::{BorrowDecode, Decode, enc, Encode}; +use bincode::de::{Decoder, DecoderImpl}; +use bincode::de::read::{Reader, SliceReader}; +use bincode::enc::Encoder; + +use bincode::error::{DecodeError, EncodeError}; + +use crate::utils::package::{DataSection, LenArrayType, PackageSection, RawArrayType, DataSectionCollectionType, Size, DepTableSection, CrateBinarySection, Uchar, Type, SigStructureSection, CratePackage, SectionIndex, SectionIndexEntry, MAGIC_NUMBER, CrateHeader, FINGERPRINT_LEN, MagicNumberType, FingerPrintType}; + + + +pub const BINCODE_CONFIG: Configuration = legacy(); + + +pub fn encode_size_by_bincode(val: &T) -> usize{ + let mut size_encoder = enc::EncoderImpl::new(enc::write::SizeWriter::default(), BINCODE_CONFIG.clone()); + val.encode(&mut size_encoder).unwrap(); + size_encoder.into_writer().bytes_written +} + +pub fn encode2vec_by_bincode(val: &T)-> Vec{ + let mut buffer = vec![0; encode_size_by_bincode(val)]; + let mut encoder = enc::EncoderImpl::new(enc::write::SliceWriter::new(buffer.as_mut_slice()), BINCODE_CONFIG.clone()); + val.encode(&mut encoder).unwrap(); + buffer +} + +pub fn decode_slice_by_bincode(bin: &[u8])-> T{ + let (res, _) = bincode::decode_from_slice(bin, BINCODE_CONFIG.clone()).unwrap(); + res +} + +pub fn create_bincode_slice_decoder(bin: &[u8])-> DecoderImpl>{ + DecoderImpl::new(SliceReader::new(bin), BINCODE_CONFIG.clone()) +} + + +//===============custom Encode, Decode=============== + +//LenArrayType Encode+Decode +impl Encode for LenArrayType{ + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + Encode::encode(&self.len, encoder)?; + for elem in self.arr.iter(){ + elem.encode(encoder)?; + } + Ok(()) + } +} + +impl Decode for LenArrayType{ + fn decode(decoder: &mut D) -> Result { + let mut len_array = LenArrayType::::new(); + len_array.len = bincode::Decode::decode(decoder)?; + for _i in 0..len_array.len{ + len_array.arr.push(Decode::decode(decoder)?); + } + Ok(len_array) + } +} + +impl<'de, T: BorrowDecode<'de> + 'static> BorrowDecode<'de> for LenArrayType{ + fn borrow_decode>(decoder: &mut D) -> Result { + let mut len_array = LenArrayType::::new(); + len_array.len = bincode::BorrowDecode::borrow_decode(decoder)?; + for _i in 0..len_array.len{ + len_array.arr.push(BorrowDecode::borrow_decode(decoder)?); + } + Ok(len_array) + } +} + +//RawArray Encode +impl Encode for RawArrayType{ + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + //TODO FIXME!!! + // if TypeId::of::() == TypeId::of::() || TypeId::of::() == TypeId::of::() || TypeId::of::() == TypeId::of::(){ + // let vec_u8: &[u8] = unsafe { core::mem::transmute(self.arr.as_slice())}; + // encoder.writer().write(vec_u8).unwrap(); + // return Ok(()) + // } + for elem in self.arr.iter(){ + elem.encode(encoder)? + } + Ok(()) + } +} + +///RawArray Decode +impl RawArrayType{ + pub fn decode(decoder: &mut D, elem_num:usize) -> Result { + //TODO FIXME + // if TypeId::of::() == TypeId::of::() || TypeId::of::() == TypeId::of::() || TypeId::of::() == TypeId::of::(){ + // let mut buf = vec![0 as u8; 8 * elem_num]; + // decoder.reader().read(buf.as_mut_slice()).unwrap(); + // let vec_t: Vec = unsafe{Vec::from_raw_parts(buf.as_ptr() as *mut T, buf.len(), buf.len())}; + // return Ok(RawArrayType::from_vec(vec_t)); + // } + let mut raw_array = RawArrayType::::new(); + for _i in 0..elem_num{ + raw_array.arr.push(Decode::decode(decoder)?); + } + Ok(raw_array) + } +} + +#[test] +fn test_raw_array_type(){ + let a= RawArrayType::{arr: [1,2,3].to_vec()}; + let encode_vec = encode2vec_by_bincode(&a); + println!("{:?}", encode_vec); + let mut decoder = create_bincode_slice_decoder(encode_vec.as_slice()); + let raw_array = RawArrayType::::decode(&mut decoder, 3).unwrap(); + // let decode = RawArrayType:: + println!("{:?}", raw_array); +} + + +// //PKCS7Struct Encode +// impl Encode for PKCS7Struct{ +// fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { +// let mut vec= vec![]; +// let _size = self.cms.encode_to_vec(&mut vec).unwrap(); +// encoder.writer().write(vec.as_slice()).unwrap(); +// Ok(()) +// } +// } + + +//datasection Encode +impl Encode for DataSection{ + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + match &self{ + DataSection::PackageSection(x) =>{x.encode(encoder)?} + DataSection::DepTableSection(x) =>{x.encode(encoder)?} + DataSection::CrateBinarySection(x) =>{x.encode(encoder)?} + DataSection::SigStructureSection(x) =>{x.encode(encoder)?} + //_ => {panic!("section type error")} + } + Ok(()) + } +} + + +impl Decode for SigStructureSection{ + fn decode(decoder: &mut D) -> Result { + let sigstruct_size:Size = Decode::decode(decoder)?; + let sigstruct_type:Type = Decode::decode(decoder)?; + let sigstruct_sig = RawArrayType::::decode(decoder, sigstruct_size as usize)?; + //let sigstruct_sig:PKCS7Struct = PKCS7Struct::decode(decoder, sigstruct_size as usize)?; + Ok(Self{ + sigstruct_size, + sigstruct_type, + sigstruct_sig + }) + } +} +// non-self decode + +fn is_magic_number(mn:&MagicNumberType)->bool{ + for i in 0..MAGIC_NUMBER.len(){ + if mn[i] != MAGIC_NUMBER[i]{ + return false; + } + } + true +} + +macro_rules! early_return { + ($condition:expr, $value:expr) => { + if !$condition { + return Err(DecodeError::Other($value)); + } + }; +} + +impl CratePackage{ + pub fn encode_to_vec(&self)->Vec{ + encode2vec_by_bincode(self) + } + + pub fn decode_from_slice(bin:&[u8])->Result{ + return match Self::decode(&mut create_bincode_slice_decoder(bin), bin) { + Ok(t) => Ok(t), + Err(DecodeError::Other(s)) => Err(s.to_string()), + Err(_) => Err("file format not right! - others".to_string()) + } + } + + + pub fn decode(decoder: &mut D, bin: &[u8]) -> Result{ + let magic_number:MagicNumberType = Decode::decode(decoder).unwrap(); + if !is_magic_number(&magic_number){ + return Err(DecodeError::Other("magic not right!")) + } + + let crate_header:CrateHeader = Decode::decode(decoder)?; + + + early_return!(bin.len() > (crate_header.strtable_size + crate_header.strtable_offset) as usize, "file format not right! - strtable"); + let string_table_bin = &bin[crate_header.strtable_offset as usize .. (crate_header.strtable_size + crate_header.strtable_offset) as usize]; + let string_table:RawArrayType = RawArrayType::::decode(&mut create_bincode_slice_decoder(string_table_bin), string_table_bin.len())?; + + early_return!(bin.len() > (crate_header.si_offset + crate_header.si_size) as usize, "file format not right! - si"); + let section_index_bin = &bin[crate_header.si_offset as usize .. (crate_header.si_offset + crate_header.si_size) as usize]; + let section_index:SectionIndex = SectionIndex::decode(&mut create_bincode_slice_decoder(section_index_bin), crate_header.si_num as usize)?; + + let mut enum_size_off_in_bytes = vec![]; + section_index.entries.arr.iter().for_each(|index_entry| enum_size_off_in_bytes.push((index_entry.sh_type as i32, index_entry.sh_size as usize, index_entry.sh_offset as usize))); + + early_return!(bin.len() > crate_header.ds_offset as usize, "file format not right! - ds"); + let datasections_bin = &bin[crate_header.ds_offset as usize ..]; + let data_sections = DataSectionCollectionType::decode(&mut create_bincode_slice_decoder(datasections_bin), enum_size_off_in_bytes)?; + + early_return!(bin[bin.len() - FINGERPRINT_LEN ..].len() == FINGERPRINT_LEN, "file format not right! - fingerprint"); + let fingerprint_bin = &bin[bin.len() - FINGERPRINT_LEN ..]; + let finger_print:FingerPrintType = Decode::decode(&mut create_bincode_slice_decoder(fingerprint_bin))?; + + Ok(Self{ + magic_number, + crate_header, + string_table, + section_index, + data_sections, + finger_print, + }) + } + +} + +///SectionIndex Decode +impl SectionIndex{ + pub fn decode(decoder: &mut D, elem_num:usize) -> Result{ + Ok(Self{ + entries: RawArrayType::::decode(decoder, elem_num)? + }) + } +} + +///RawCollection Decode +impl DataSectionCollectionType{ + pub fn decode(decoder: &mut D, enum_size_offset_in_bytes:Vec<(i32, usize, usize)>) -> Result { + let mut raw_col = DataSectionCollectionType::new(); + let mut consume_size = 0; + for (type_id, size, offset) in enum_size_offset_in_bytes.into_iter(){ + if consume_size > offset{ + return Err(DecodeError::Other("file format not right!")) + } + if consume_size < offset{ + decoder.reader().consume(offset - consume_size); + consume_size = offset; + } + match type_id{ + 0 => { + let pack_sec:PackageSection = Decode::decode(decoder)?; + raw_col.col.arr.push(DataSection::PackageSection(pack_sec)); + } + 1 => { + let dep_table:DepTableSection = Decode::decode(decoder)?; + raw_col.col.arr.push(DataSection::DepTableSection(dep_table)); + } + 3 => { + let crate_binary:CrateBinarySection = CrateBinarySection::decode(decoder, size)?; + raw_col.col.arr.push(DataSection::CrateBinarySection(crate_binary)); + } + 4 => { + let sig_structure:SigStructureSection = Decode::decode(decoder)?; + raw_col.col.arr.push(DataSection::SigStructureSection(sig_structure)); + } + _ => {return Err(DecodeError::Other("file format not right!"))} + } + consume_size += size; + } + Ok(raw_col) + } + + pub fn encode_size_offset(&self)->Vec<(usize, usize)>{ + let mut v = vec![]; + let mut offset:usize = 0; + self.col.arr.iter().for_each(|x|{ + let size = encode_size_by_bincode(x); + v.push((size, offset)); + offset += size; + }); + v + } + + pub fn encode_fake_to_vec(&self, trunc_len:usize)->Vec{ + let mut buf = encode2vec_by_bincode(self); + buf.truncate(trunc_len); + buf + } +} + + +//CrateBinarySection decode +impl CrateBinarySection{ + pub fn decode(decoder: &mut D, size_in_bytes:usize) -> Result { + let mut dep_table = CrateBinarySection::new(); + dep_table.bin = RawArrayType::::decode(decoder, size_in_bytes)?; + Ok(dep_table) + } +} + +//PKCS7Struct decode +// impl PKCS7Struct{ +// fn decode(decoder: &mut D, size_in_bytes:usize) -> Result { +// let mut der_reader = der::SliceReader::new(decoder.reader().peek_read(size_in_bytes).unwrap()).unwrap(); +// let cms = SignedData::decode(&mut der_reader).unwrap(); +// decoder.reader().consume(size_in_bytes); +// Ok(Self{ +// cms +// }) +// } +// } + + +//get_size +impl CrateHeader{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } +} + +impl RawArrayType{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } +} + +impl SectionIndex{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } + + pub fn get_num(&self)->usize{ + self.entries.arr.len() + } + + pub fn get_none_sig_size(&self)->usize{ + let mut total_len = 0; + self.entries.arr.iter().for_each(|x|{ + if x.sh_type != 4{ + total_len += x.get_size(); + } + }); + total_len + } + + pub fn get_none_sig_num(&self)->usize{ + let mut total_len = 0; + self.entries.arr.iter().for_each(|x|{ + if x.sh_type != 4{ + total_len += 1; + } + }); + total_len + } + + pub fn get_sig_num(&self)->usize{ + self.get_num() - self.get_none_sig_num() + } + + pub fn get_sig_size(&self)->usize{ + self.get_size() - self.get_none_sig_size() + } + + pub fn encode_fake_to_vec(&self, no_sig_size:usize, size: usize)->Vec{ + let mut buf = encode2vec_by_bincode(self); + buf.truncate(no_sig_size); + buf.extend(vec![0; size - no_sig_size]); + buf + } + + pub fn get_datasection_size_without_sig(&self)->usize{ + (self.entries.arr[self.get_none_sig_num() - 1].sh_offset + self.entries.arr[self.get_none_sig_num() - 1].sh_size) as usize + } +} + +impl DataSectionCollectionType{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } +} + +impl PackageSection{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } +} + +impl DepTableSection{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } +} + +impl CrateBinarySection{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } +} + +impl SigStructureSection{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } +} + +impl SectionIndexEntry{ + pub fn get_size(&self)->usize{ + encode_size_by_bincode(self) + } +} diff --git a/crate-spec/src/utils/package/mod.rs b/crate-spec/src/utils/package/mod.rs new file mode 100644 index 00000000..6b9e2fcc --- /dev/null +++ b/crate-spec/src/utils/package/mod.rs @@ -0,0 +1,354 @@ +//!package definition +pub mod bin; +pub mod gen_bincode; + +use bincode::{Decode, Encode}; + + +//Types used in CratePackage + +///Unsigned file offset +pub type Off = u32; + +///Unsigned file size +pub type Size = u32; + +///Unsigned type id +pub type Type=u8; + +///Unsigned small int +pub type Uchar=u8; + +///Unsigned str offset +type StrOff = u32; + +//custom Encode +//custom Decode +///len + array +#[derive(Debug)] +pub struct LenArrayType{ + pub len:Size, + pub arr:Vec +} + +impl LenArrayType{ + pub fn new()->Self{ + LenArrayType{ + len: Default::default(), + arr: vec![], + } + } + + pub fn from_vec(arr: Vec)->Self{ + Self{ + len: arr.len() as Size, + arr, + } + } +} + +impl LenArrayType { + pub fn copy_from_vec(v: &Vec) ->Self{ + let mut len_array = Self::new(); + len_array.arr = v.to_vec(); + len_array.len = v.len() as Size; + len_array + } + + pub fn to_vec(&self)->Vec{ + self.arr.to_vec() + } +} +/// array +/// custom Encode +/// non-self Decode +#[derive(Debug)] +pub struct RawArrayType{ + pub arr:Vec +} + +impl RawArrayType{ + pub fn new()->Self{ + Self{ + arr: vec![], + } + } + + pub fn from_vec(arr: Vec)->Self{ + Self{ + arr + } + } +} + +/// auto encode +/// self decode +/// collections(array whose elem is enum) +#[derive(Encode, Debug)] +pub struct DataSectionCollectionType{ + pub col:RawArrayType +} + +impl DataSectionCollectionType{ + pub fn new()->Self{ + Self{ + col: RawArrayType::new() + } + } +} + +// /// custom Encode +// /// non-self Decode +// pub struct PKCS7Struct{ +// pub cms: SignedData +// } +// +// impl PKCS7Struct{ +// pub fn new(sd: SignedData)->Self{ +// Self{ +// cms: sd +// } +// } +// } + +//constant val +pub const MAGIC_NUMBER_LEN:usize=5; +pub type MagicNumberType = [Uchar; MAGIC_NUMBER_LEN]; +pub const MAGIC_NUMBER:MagicNumberType=[0x43, 0x52, 0x41, 0x54, 0x45]; +pub const FINGERPRINT_LEN:usize = 32; +pub type FingerPrintType = [Uchar; FINGERPRINT_LEN]; +pub const CRATEVERSION:Uchar = 0; + +//package structure + +//auto encode +//non-self decode +///top-level package structure +#[derive(Encode, Debug)] +pub struct CratePackage{ + pub magic_number: MagicNumberType, + pub crate_header: CrateHeader, + pub string_table: RawArrayType, + pub section_index: SectionIndex, + pub data_sections: DataSectionCollectionType, + pub finger_print: FingerPrintType +} + +impl CratePackage { + pub fn new()->Self{ + Self{ + magic_number: MAGIC_NUMBER, + crate_header: CrateHeader::new(), + string_table: RawArrayType::new(), + section_index: SectionIndex::new(), + data_sections: DataSectionCollectionType::new(), + finger_print: [0; FINGERPRINT_LEN] + } + } + + +} + +//auto encode +//auto decode +///crate header structure +#[derive(Encode, Decode, Debug)] +pub struct CrateHeader{ + pub c_version: Uchar, + pub strtable_size: Size, + pub strtable_offset: Off, + pub si_size: Size, + pub si_offset: Off, + pub si_num: Size, + // pub si_not_sig_num: Size, + // pub si_not_sig_size: Size, + pub ds_offset: Off, +} + +impl CrateHeader{ + pub fn new()->Self{ + Self{ + c_version: Default::default(), + strtable_size: Default::default(), + strtable_offset: Default::default(), + si_num: Default::default(), + si_size: Default::default(), + // si_not_sig_size:Default::default(), + // si_not_sig_num: Default::default(), + si_offset: Default::default(), + ds_offset: Default::default(), + } + } +} + +//auto encode +//self decode +///section index structure +#[derive(Encode, Debug)] +pub struct SectionIndex{ + pub entries: RawArrayType +} + +impl SectionIndex{ + pub fn new()->Self{ + Self{ + entries: RawArrayType::new(), + } + } + + pub fn section_num(&self)->Size{ + self.entries.arr.len() as Size + } +} +//auto encode +//auto decode +///section index entry structure +#[derive(Encode, Decode, Debug)] +pub struct SectionIndexEntry{ + /* +FIXME In RFC0.1 there are no alignment requirements for the struct. +SectionIndexEntry's size is 9 bytes, 9 is not a multiple of 4 +we may padding 3 bytes of 0 after each SectionIndexEntry, +so here, we use a user-defined encoder to implement the serialization of SectionIndex. + */ + pub sh_type: Type, + pub sh_offset: Off, + pub sh_size: Size +} + +impl SectionIndexEntry{ + pub fn default()->Self{ + Self{ + sh_type: 0, + sh_offset: 0, + sh_size: 0, + } + } + + pub fn new(sh_type:Type, sh_offset:Off, sh_size:Size)->Self{ + Self{ + sh_type, + sh_offset, + sh_size + } + } +} +//custom encode +//non-self decode +//data sections +#[derive(Debug)] +pub enum DataSection{ + //0 + PackageSection(PackageSection), + //1 + DepTableSection(DepTableSection), + //3 + CrateBinarySection(CrateBinarySection), + //4 + SigStructureSection(SigStructureSection) +} + +pub fn get_datasection_type(d:&DataSection)->Type{ + match d{ + DataSection::PackageSection(_) => {0} + DataSection::DepTableSection(_) => {1} + DataSection::CrateBinarySection(_) => {3} + DataSection::SigStructureSection(_) => {4} + } +} +//auto encode +//auto decode +///package section structure +#[derive(Encode, Decode, Debug)] +pub struct PackageSection{ + pub pkg_name: StrOff, + pub pkg_version: StrOff, + pub pkg_license: StrOff, + pub pkg_authors: LenArrayType +} + +impl PackageSection{ + pub fn new()->Self{ + Self{ + pkg_name: 0, + pkg_version: 0, + pkg_license: 0, + pkg_authors: LenArrayType::new(), + } + } + +} +//auto encode +//auto decode +///Dependency table entry structure +#[derive(Encode, Decode, Debug)] +pub struct DepTableEntry{ + pub dep_name : StrOff, + pub dep_verreq: StrOff, + pub dep_srctype: Type, + pub dep_srcpath: StrOff, + pub dep_platform: StrOff +} + +impl DepTableEntry { + pub fn new()->Self{ + Self{ + dep_name: 0, + dep_verreq: 0, + dep_srctype: 0, + dep_srcpath: 0, + dep_platform: 0, + } + } +} +//auto encode +//non-self decode +///Dependency table section structure +#[derive(Encode, Decode, Debug)] +pub struct DepTableSection{ + pub entries:LenArrayType +} + + +impl DepTableSection{ + pub fn new()->Self{ + Self{ + entries: LenArrayType::new() + } + } +} +//auto encode +//non-self decode +#[derive(Encode, Debug)] +pub struct CrateBinarySection{ + pub bin: RawArrayType +} + +impl CrateBinarySection{ + pub fn new()->Self{ + Self{ + bin:RawArrayType::new() + } + } +} + +//auto encode +//custom decode +///Signature section structure +#[derive(Encode, Debug)] +pub struct SigStructureSection{ + pub sigstruct_size: Size, + pub sigstruct_type: Type, + pub sigstruct_sig: RawArrayType +} + +impl SigStructureSection{ + pub fn new()->Self{ + Self{ + sigstruct_size: 0, + sigstruct_type: 0, + sigstruct_sig: RawArrayType::new(), + } + } +} + diff --git a/crate-spec/src/utils/pkcs.rs b/crate-spec/src/utils/pkcs.rs new file mode 100644 index 00000000..739e0a9c --- /dev/null +++ b/crate-spec/src/utils/pkcs.rs @@ -0,0 +1,181 @@ +use std::fmt::{Debug, Formatter}; +use std::fs; +use std::path::Path; +use openssl::hash::{hash, MessageDigest}; + +use openssl::pkcs7::Pkcs7; +use openssl::pkcs7::Pkcs7Flags; +use openssl::pkey::PKey; +use openssl::stack::Stack; +use openssl::x509::store::X509StoreBuilder; +use openssl::x509::X509; + + +#[derive(PartialEq)] +pub struct PKCS{ + cert_bin: Vec, + pkey_bin: Vec, + root_ca_bins: Vec> +} + +impl Debug for PKCS{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("") + } +} + +impl PKCS{ + pub fn new()->Self{ + Self{ + cert_bin: vec![], + pkey_bin: vec![], + root_ca_bins: vec![], + } + } + pub fn get_root_ca_bins(ca_paths: Vec)->Vec>{ + let mut root_ca_bins = vec![]; + for ca_path in ca_paths{ + root_ca_bins.push(fs::read(Path::new(ca_path.as_str())).unwrap()); + } + root_ca_bins + } + + pub fn load_from_file_writer(&mut self, cert_path: String, pkey_path: String, ca_paths: Vec){ + //just for demo + self.cert_bin = fs::read(Path::new(cert_path.as_str())).unwrap(); + self.pkey_bin = fs::read(Path::new(pkey_path.as_str())).unwrap(); + for ca_path in ca_paths{ + self.root_ca_bins.push(fs::read(Path::new(ca_path.as_str())).unwrap()); + } + } + + pub fn load_from_file_reader(&mut self, ca_paths: Vec){ + //just for demo + for ca_path in ca_paths{ + self.root_ca_bins.push(fs::read(Path::new(ca_path.as_str())).unwrap()); + } + } + + pub fn encode_pkcs_bin(&self, message:&[u8])->Vec{ + //FIXME current we don't support middle certs + let cert = X509::from_pem(self.cert_bin.as_slice()).unwrap(); + let certs = Stack::new().unwrap(); + let flags = Pkcs7Flags::STREAM; + let pkey = PKey::private_key_from_pem(self.pkey_bin.as_slice()).unwrap(); + let mut store_builder = X509StoreBuilder::new().expect("should succeed"); + + for root_ca_bin in self.root_ca_bins.iter() { + let root_ca = X509::from_pem(root_ca_bin.as_slice()).unwrap(); + store_builder.add_cert(root_ca).expect("should succeed"); + } + + let _store = store_builder.build(); + + let pkcs7 = + Pkcs7::sign(&cert, &pkey, &certs, message, flags).expect("should succeed"); + + let signed = pkcs7 + .to_smime(message, flags) + .expect("should succeed"); + signed + } + + pub fn decode_pkcs_bin(signed_bin:&[u8], root_ca_bins: &Vec>)->Vec{ + //FIXME maybe all pkcs section should share same root cas + let certs = Stack::new().unwrap(); + let flags = Pkcs7Flags::STREAM; + let mut store_builder = X509StoreBuilder::new().expect("should succeed"); + + for root_ca_bin in root_ca_bins.iter() { + let root_ca = X509::from_pem(root_ca_bin.as_slice()).unwrap(); + store_builder.add_cert(root_ca).expect("should succeed"); + } + + let store = store_builder.build(); + + let (pkcs7_decoded, _content) = + Pkcs7::from_smime(signed_bin).expect("should succeed"); + + let mut output = Vec::new(); + pkcs7_decoded + .verify(&certs, &store, None, Some(&mut output), flags) + .expect("should succeed"); + output + } + + pub fn gen_digest_256(&self, bin:&[u8])->Vec{ + let res = hash(MessageDigest::sha256(), bin).unwrap(); + res.to_vec() + } +} + +// #[test] +// fn test_pkcs(){ +// let mut pkcs = PKCS::new(); +// pkcs.load_from_file_writer("test/cert.pem".to_string(), "test/key.pem".to_string(), ["test/root-ca.pem".to_string()].to_vec()); +// let bin = "Hello rust!".to_string(); +// let digest = pkcs.gen_digest_256(bin.as_bytes()); +// let _signed_data = pkcs.encode_pkcs_bin(digest.as_slice()); +// // let digest_de = pkcs.decode_pkcs_bin(_signed_data.as_slice()); +// // assert_eq!(digest, digest_de); +// } +// +// #[test] +// fn test_pkcs7(){ +// let cert = include_bytes!("../../test/cert.pem"); +// let cert = X509::from_pem(cert).unwrap(); +// let mut certs = Stack::new().unwrap(); +// certs.push(X509::from_pem(include_bytes!("../../test/cert1.pem")).unwrap()).unwrap(); +// +// let message = "foo"; +// let flags = Pkcs7Flags::STREAM; +// let pkey = include_bytes!("../../test/key.pem"); +// let pkey = PKey::private_key_from_pem(pkey).unwrap(); +// let mut store_builder = X509StoreBuilder::new().expect("should succeed"); +// +// let root_ca = include_bytes!("../../test/root-ca.pem"); +// let root_ca = X509::from_pem(root_ca).unwrap(); +// store_builder.add_cert(root_ca).expect("should succeed"); +// +// let _store = store_builder.build(); +// +// let pkcs7 = +// Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed"); +// +// let signed = pkcs7 +// .to_smime(message.as_bytes(), flags) +// .expect("should succeed"); +// +// let (pkcs7_decoded, content) = +// Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); +// +// let mut output = Vec::new(); +// let certs = Stack::new().unwrap(); +// +// let mut store_builder = X509StoreBuilder::new().expect("should succeed"); +// let root_ca = include_bytes!("../../test/cert1.pem"); +// let _root_ca = X509::from_pem(root_ca).unwrap(); +// let root_ca = include_bytes!("../../test/root-ca.pem"); +// let root_ca = X509::from_pem(root_ca).unwrap(); +// store_builder.add_cert(root_ca).expect("should succeed"); +// let store = store_builder.build(); +// +// pkcs7_decoded +// .verify(&certs, &store, None, Some(&mut output), flags) +// .expect("should succeed"); +// +// assert_eq!(output, message.as_bytes()); +// assert!(content.is_none()); +// } +// +// #[test] +// fn test_hash() -> Result<(), Box> { +// use openssl::hash::{hash, MessageDigest}; +// +// let data = b"\x42\xF4\x97\xE0"; +// //let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; +// let res = hash(MessageDigest::sha256(), data)?; +// println!("{:?}", &*res); +// //assert_eq!(&*res, spec); +// Ok(()) +// } \ No newline at end of file diff --git a/crate-spec/test/args.txt b/crate-spec/test/args.txt new file mode 100644 index 00000000..7d14f632 --- /dev/null +++ b/crate-spec/test/args.txt @@ -0,0 +1,2 @@ +run -- -e -c test/cert.pem -r test/root-ca.pem -p test/key.pem -o test/output/ ../crate-spec +run -- -d -r test/root-ca.pem -o test/output/ test/output/crate-spec-0.1.0.scrate \ No newline at end of file diff --git a/crate-spec/test/cert.pem b/crate-spec/test/cert.pem new file mode 100644 index 00000000..032fe60e --- /dev/null +++ b/crate-spec/test/cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub +3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ +mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 +TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI +ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y +euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM +6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE +wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY +oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 +dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp +HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== +-----END CERTIFICATE----- diff --git a/crate-spec/test/cert1.pem b/crate-spec/test/cert1.pem new file mode 100644 index 00000000..350ca385 --- /dev/null +++ b/crate-spec/test/cert1.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub +3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ +mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 +TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI +ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y +euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEASvYHlll5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM +6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE +wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY +oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 +dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp +HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== +-----END CERTIFICATE----- diff --git a/crate-spec/test/example/decode_crate.sh b/crate-spec/test/example/decode_crate.sh new file mode 100644 index 00000000..2ad2403f --- /dev/null +++ b/crate-spec/test/example/decode_crate.sh @@ -0,0 +1,5 @@ +script_dir=$(cd "$(dirname "$0")" && pwd) +test_dir=$(dirname "$script_dir") +cd "$script_dir" || exit +cargo build || exit +cargo run -- -d -r "$test_dir"/root-ca.pem -o "$test_dir"/output/ "$test_dir"/output/crate-spec-0.1.0.scrate || exit diff --git a/crate-spec/test/example/encode_crate.sh b/crate-spec/test/example/encode_crate.sh new file mode 100644 index 00000000..0c877a7e --- /dev/null +++ b/crate-spec/test/example/encode_crate.sh @@ -0,0 +1,7 @@ +script_dir=$(cd "$(dirname "$0")" && pwd) +test_dir=$(dirname "$script_dir") +crate_dir=$(dirname "$test_dir") +mkdir -p "$test_dir"/output +cd "$script_dir" || exit +cargo build || exit +cargo run -- -e -c "$test_dir"/cert.pem -r "$test_dir"/root-ca.pem -p "$test_dir"/key.pem -o "$test_dir"/output/ "$crate_dir" || exit \ No newline at end of file diff --git a/crate-spec/test/example/hack.py b/crate-spec/test/example/hack.py new file mode 100644 index 00000000..92ad9f29 --- /dev/null +++ b/crate-spec/test/example/hack.py @@ -0,0 +1,25 @@ +import os +from os import path +import sys +import hashlib +file_dir = path.dirname(path.abspath(__file__)) +os.chdir(file_dir) +args = sys.argv[1:] + +with open("../output/crate-spec-0.1.0.scrate", "rb") as fp: + bin = bytearray(fp.read()) + + +with open("../output/crate-spec-0.1.0.scrate", "wb") as fp: + opt = int(args[0]) + if opt == 0: + bin[200:202] = [10, 20, 30] + fp.write(bin) + else: + bin = bin[:-32] + bin[400] = 0x52 + data_sha = hashlib.sha256(bin).digest() + fp.write(bin) + fp.write(data_sha) + + diff --git a/crate-spec/test/example/hack_file.sh b/crate-spec/test/example/hack_file.sh new file mode 100644 index 00000000..fabd67f9 --- /dev/null +++ b/crate-spec/test/example/hack_file.sh @@ -0,0 +1,4 @@ +script_dir=$(cd "$(dirname "$0")" && pwd) +test_dir=$(dirname "$script_dir") + +python3 "$script_dir"/hack.py "$1" \ No newline at end of file diff --git a/crate-spec/test/key.pem b/crate-spec/test/key.pem new file mode 100644 index 00000000..d381795d --- /dev/null +++ b/crate-spec/test/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo9CWMRLMXo1CF +/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 +kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS +wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM +jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT +Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt +OzboKgs1AgMBAAECggEBAKLj6IOJBKXolczpzb8UkyAjAkGBektcseV07gelJ/fk +3z0LuWPv5p12E/HlXB24vU2x/ikUbbP3eMsawRzDEahQqmNmPEkYAYUAy/Qpi9GN +DYvn3LqDec4jVgeQKS+p9H2DzUpTogp8zR2//yzbuWBg2+F//xh7vU0S0RQCziPM +x7RSBgbhxSfChfEJbS2sDnzfh0jRQmoY95iFv7puet1FJtzdZ4fgCd1RqmC2lFM5 +H0eZtN/Cz19lieVs0b996DErdEBqClVZO00eYbRozCDaBzRU3ybB/dMrGJxhkkXm +wb3kWMtziH9qOYsostuHIFu8eKFLloKxFnq2R4DGxOECgYEA2KUIZISOeGJSBcLJ +JAUK2gvgXPNo4HHWIwOA9xeN3ZJlsnPlffXQNnm6t1st1V2gfMm9I2n0m/F0y2B/ +n/XGSa8bghfPA9l0c2h58lkL3JQJR/paa8ycTz+YZPrznEyN7Qa0RrJXUvZv9lQL +Hc3+FHcSHgMqDV2f2bHAEu9YGi0CgYEAx6VEIPNvrHFgjo/jk1RTuk+m0xEWQsZL +Cs+izQMr2TaeJn8LG+93AvFuYn0J0nT3WuStLPrUg8i4IhSS6lf1tId5ivIZPm4r +YwMyblBJXhnHbk7Uqodjfw/3s6V2HAu++B7hTdyVr9DFuST9uv4m8bkPV8rfX1jE +I2rAPVWvgikCgYB+wNAQP547wQrMZBLbCDg5KwmyWJfb+b6X7czexOEz6humNTjo +YZHYzY/5B1fhpk3ntQD8X1nGg5caBvOk21+QbOtjShrM3cXMYCw5JvBRtitX+Zo9 +yBEMLOE0877ki8XeEDYZxu5gk98d+D4oygUGZEQtWxyXhVepPt5qNa8OYQKBgQDH +RVgZI6KFlqzv3wMh3PutbS9wYQ+9GrtwUQuIYe/0YSW9+vSVr5E0qNKrD28sV39F +hBauXLady0yvB6YUrjMbPFW+sCMuQzyfGWPO4+g3OrfqjFiM1ZIkE0YEU9Tt7XNx +qTDtTI1D7bhNMnTnniI1B6ge0und+3XafAThs5L48QKBgQCTTpfqMt8kU3tcI9sf +0MK03y7kA76d5uw0pZbWFy7KI4qnzWutCzb+FMPWWsoFtLJLPZy//u/ZCUVFVa4d +0Y/ASNQIESVPXFLAltlLo4MSmsg1vCBsbviEEaPeEjvMrgki93pYtd/aOSgkYC1T +mEq154s5rmqh+h+XRIf7Au0SLw== +-----END PRIVATE KEY----- diff --git a/crate-spec/test/root-ca.pem b/crate-spec/test/root-ca.pem new file mode 100644 index 00000000..4ec2f538 --- /dev/null +++ b/crate-spec/test/root-ca.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G +ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV +eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr +7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92 +aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc +klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN +XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn +BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv +Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3 +AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy +OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3 +mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9 +GA== +-----END CERTIFICATE----- diff --git a/crate-spec/test/test.toml b/crate-spec/test/test.toml new file mode 100644 index 00000000..7e6a812c --- /dev/null +++ b/crate-spec/test/test.toml @@ -0,0 +1,12 @@ +[package] +name = "crate-spec" +version = "0.1.0" +license = "MIT" +authors = ["shuibing", "rust"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bincode = {version = "2.0.0-rc.3", features = ["serde", "alloc"]} +openssl = {version = "0.10.53", registry = "rust"} +toml = "0.7.4" \ No newline at end of file -- Gitee