sct-0.7.1/.cargo_vcs_info.json0000644000000001360000000000100116320ustar { "git": { "sha1": "1f5c7f296a5ec931acd7dffaf5c792b54c4e2efe" }, "path_in_vcs": "" }sct-0.7.1/.github/codecov.yml000064400000000000000000000001741046102023000141310ustar 00000000000000coverage: status: patch: default: threshold: 0.05% project: default: threshold: 0.05% sct-0.7.1/.github/dependabot.yml000064400000000000000000000003641046102023000146150ustar 00000000000000version: 2 updates: - package-ecosystem: cargo directory: "/" schedule: interval: daily open-pull-requests-limit: 10 - package-ecosystem: github-actions directory: "/" schedule: interval: weekly open-pull-requests-limit: 10 sct-0.7.1/.github/workflows/build.yml000064400000000000000000000057031046102023000156460ustar 00000000000000on: [push, pull_request] name: sct.rs jobs: build: name: Build+test runs-on: ${{ matrix.os }} strategy: matrix: # test a bunch of toolchains on ubuntu rust: - stable - beta - nightly - 1.61.0 # our MSRV os: [ubuntu-latest] # but only stable on macos/windows (slower platforms) include: - os: macos-latest rust: stable - os: windows-latest rust: stable steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install ${{ matrix.rust }} toolchain uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - name: cargo build (debug; default features) run: cargo build - name: cargo test (debug; default features) run: cargo test env: RUST_BACKTRACE: 1 - name: cargo test (debug; all features) run: cargo test --all-features env: RUST_BACKTRACE: 1 - name: cargo test (release; no run) run: cargo test --release --no-run coverage: name: Measure coverage runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install rust toolchain uses: dtolnay/rust-toolchain@nightly with: components: llvm-tools - name: Install cargo-llvm-cov run: cargo install cargo-llvm-cov - name: Measure coverage run: cargo llvm-cov --lcov --output-path ./lcov.info - name: Report to codecov.io uses: codecov/codecov-action@v3 with: files: ./lcov.info fail_ci_if_error: false minver: name: Check minimum versions runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install rust toolchain uses: dtolnay/rust-toolchain@nightly - name: cargo test (debug; all features; -Z minimal-versions) run: cargo -Z minimal-versions test --all-features format: name: Format runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable with: components: rustfmt - name: Check formatting run: cargo fmt -- --check clippy: name: Clippy runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable with: components: clippy - run: cargo clippy -- --deny warnings clippy-nightly: name: Clippy (Nightly) runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install rust toolchain uses: dtolnay/rust-toolchain@nightly with: components: clippy - run: cargo clippy sct-0.7.1/.gitignore000064400000000000000000000000501046102023000124050ustar 00000000000000Cargo.lock target/ *.gcda *.gcno *.info sct-0.7.1/Cargo.toml0000644000000017340000000000100076350ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.61" name = "sct" version = "0.7.1" authors = ["Joseph Birr-Pixton "] exclude = ["/admin/"] description = "Certificate transparency SCT verification library" homepage = "https://github.com/rustls/sct.rs" readme = "README.md" categories = [ "network-programming", "cryptography", ] license = "Apache-2.0 OR ISC OR MIT" repository = "https://github.com/rustls/sct.rs" [dependencies.ring] version = "0.17.0" [dependencies.untrusted] version = "0.9.0" sct-0.7.1/Cargo.toml.orig000064400000000000000000000010231046102023000133050ustar 00000000000000[package] name = "sct" version = "0.7.1" edition = "2021" rust-version = "1.61" authors = ["Joseph Birr-Pixton "] description = "Certificate transparency SCT verification library" license = "Apache-2.0 OR ISC OR MIT" readme = "README.md" homepage = "https://github.com/rustls/sct.rs" repository = "https://github.com/rustls/sct.rs" categories = ["network-programming", "cryptography"] exclude = ["/admin/"] [dependencies] ring = "0.17.0" untrusted = "0.9.0" # stick with the version that's used by current ring sct-0.7.1/LICENSE000064400000000000000000000004361046102023000114320ustar 00000000000000sct.rs is distributed under the following three licenses: - Apache License version 2.0. - MIT license. - ISC license. These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC respectively. You may use this software under the terms of any of these licenses, at your option. sct-0.7.1/LICENSE-APACHE000064400000000000000000000251371046102023000123560ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ 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 [yyyy] [name of copyright owner] 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 http://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. sct-0.7.1/LICENSE-ISC000064400000000000000000000014071046102023000120450ustar 00000000000000ISC License (ISC) Copyright (c) 2016, Joseph Birr-Pixton Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. sct-0.7.1/LICENSE-MIT000064400000000000000000000020721046102023000120570ustar 00000000000000Copyright (c) 2016 Joseph Birr-Pixton 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. sct-0.7.1/README.md000064400000000000000000000017261046102023000117070ustar 00000000000000# SCT.rs SCT.rs is a certificate transparency SCT verifier in Rust. It uses [*ring*](https://github.com/briansmith/ring) for cryptography. [![Build Status](https://github.com/rustls/sct.rs/workflows/sct.rs/badge.svg)](https://github.com/rustls/sct.rs/actions) [![Coverage Status (codecov.io)](https://codecov.io/gh/rustls/sct.rs/branch/main/graph/badge.svg)](https://codecov.io/gh/rustls/sct.rs/) [![Documentation](https://docs.rs/sct/badge.svg)](https://docs.rs/sct) [![crates.io](https://img.shields.io/crates/v/sct.svg)](https://crates.io/crates/sct) # Status Ready for use: - All intended features are implemented. - Tests achieve 100% line coverage and all reachable branches. # License SCT.rs is distributed under the following three licenses: - Apache License version 2.0. - MIT license. - ISC license. These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC respectively. You may use this software under the terms of any of these licenses, at your option. sct-0.7.1/src/lib.rs000064400000000000000000000167321046102023000123360ustar 00000000000000//! # SCT.rs: SCT verification library //! This library implements verification of Signed Certificate Timestamps. //! These are third-party assurances that a particular certificate has //! been included in a Certificate Transparency log. //! //! See RFC6962 for the details of the formats implemented here. //! //! It is intended to be useful to libraries which perform certificate //! validation, OCSP libraries, and TLS libraries. #![forbid(unsafe_code, unstable_features)] #![deny( trivial_casts, trivial_numeric_casts, missing_docs, unused_import_braces, unused_extern_crates, unused_qualifications )] #![no_std] extern crate alloc; use alloc::{vec, vec::Vec}; /// Describes a CT log /// /// This structure contains some metadata fields not used by the library. /// Rationale: it makes sense to keep this metadata with the other /// values for review purposes. #[derive(Debug)] pub struct Log<'a> { /// The operator's name/description of the log. /// This field is not used by the library. pub description: &'a str, /// The certificate submission url. /// This field is not used by the library. pub url: &'a str, /// Which entity operates the log. /// This field is not used by the library. pub operated_by: &'a str, /// Public key usable for verifying certificates. /// TODO: fixme format of this; should be a SPKI /// so the `id` is verifiable, but currently is a /// raw public key (like, an ECPoint or RSAPublicKey). pub key: &'a [u8], /// Key hash, which is SHA256 applied to the SPKI /// encoding. pub id: [u8; 32], /// The log's maximum merge delay. /// This field is not used by the library. pub max_merge_delay: usize, } /// How sct.rs reports errors. #[derive(Debug, PartialEq, Clone, Copy)] pub enum Error { /// The SCT was somehow misencoded, truncated or otherwise corrupt. MalformedSct, /// The SCT contained an invalid signature. InvalidSignature, /// The SCT was signed in the future. Clock skew? TimestampInFuture, /// The SCT had a version that this library does not handle. UnsupportedSctVersion, /// The SCT was refers to an unknown log. UnknownLog, } impl Error { /// Applies a suggested policy for error handling: /// /// Returns `true` if the error should end processing /// for whatever the SCT is attached to (like, abort a TLS /// handshake). /// /// Returns `false` if this error should be a 'soft failure' /// -- the SCT is unverifiable with this library and set of /// logs. pub fn should_be_fatal(&self) -> bool { !matches!(self, Error::UnknownLog | Error::UnsupportedSctVersion) } } fn lookup(logs: &[&Log], id: &[u8]) -> Result { for (i, l) in logs.iter().enumerate() { if id == l.id { return Ok(i); } } Err(Error::UnknownLog) } fn decode_u64(inp: untrusted::Input) -> u64 { let b = inp.as_slice_less_safe(); assert_eq!(b.len(), 8); (b[0] as u64) << 56 | (b[1] as u64) << 48 | (b[2] as u64) << 40 | (b[3] as u64) << 32 | (b[4] as u64) << 24 | (b[5] as u64) << 16 | (b[6] as u64) << 8 | (b[7] as u64) } fn decode_u16(inp: untrusted::Input) -> u16 { let b = inp.as_slice_less_safe(); assert_eq!(b.len(), 2); (b[0] as u16) << 8 | (b[1] as u16) } fn write_u64(v: u64, out: &mut Vec) { out.push((v >> 56) as u8); out.push((v >> 48) as u8); out.push((v >> 40) as u8); out.push((v >> 32) as u8); out.push((v >> 24) as u8); out.push((v >> 16) as u8); out.push((v >> 8) as u8); out.push(v as u8); } fn write_u24(v: u32, out: &mut Vec) { out.push((v >> 16) as u8); out.push((v >> 8) as u8); out.push(v as u8); } fn write_u16(v: u16, out: &mut Vec) { out.push((v >> 8) as u8); out.push(v as u8); } struct Sct<'a> { log_id: &'a [u8], timestamp: u64, sig_alg: u16, sig: &'a [u8], exts: &'a [u8], } const ECDSA_SHA256: u16 = 0x0403; const ECDSA_SHA384: u16 = 0x0503; const RSA_PKCS1_SHA256: u16 = 0x0401; const RSA_PKCS1_SHA384: u16 = 0x0501; const SCT_V1: u8 = 0u8; const SCT_TIMESTAMP: u8 = 0u8; const SCT_X509_ENTRY: [u8; 2] = [0, 0]; impl<'a> Sct<'a> { fn verify(&self, key: &[u8], cert: &[u8]) -> Result<(), Error> { let alg: &dyn ring::signature::VerificationAlgorithm = match self.sig_alg { ECDSA_SHA256 => &ring::signature::ECDSA_P256_SHA256_ASN1, ECDSA_SHA384 => &ring::signature::ECDSA_P384_SHA384_ASN1, RSA_PKCS1_SHA256 => &ring::signature::RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_SHA384 => &ring::signature::RSA_PKCS1_2048_8192_SHA384, _ => return Err(Error::InvalidSignature), }; let mut data = vec![SCT_V1, SCT_TIMESTAMP]; write_u64(self.timestamp, &mut data); data.extend_from_slice(&SCT_X509_ENTRY); write_u24(cert.len() as u32, &mut data); data.extend_from_slice(cert); write_u16(self.exts.len() as u16, &mut data); data.extend_from_slice(self.exts); let key = ring::signature::UnparsedPublicKey::new(alg, key); key.verify(&data, self.sig) .map_err(|_| Error::InvalidSignature) } fn parse(enc: &'a [u8]) -> Result, Error> { let inp = untrusted::Input::from(enc); inp.read_all(Error::MalformedSct, |rd| { let version = rd.read_byte().map_err(|_| Error::MalformedSct)?; if version != 0 { return Err(Error::UnsupportedSctVersion); } let id = rd.read_bytes(32).map_err(|_| Error::MalformedSct)?; let timestamp = rd .read_bytes(8) .map_err(|_| Error::MalformedSct) .map(decode_u64)?; let ext_len = rd .read_bytes(2) .map_err(|_| Error::MalformedSct) .map(decode_u16)?; let exts = rd .read_bytes(ext_len as usize) .map_err(|_| Error::MalformedSct)?; let sig_alg = rd .read_bytes(2) .map_err(|_| Error::MalformedSct) .map(decode_u16)?; let sig_len = rd .read_bytes(2) .map_err(|_| Error::MalformedSct) .map(decode_u16)?; let sig = rd .read_bytes(sig_len as usize) .map_err(|_| Error::MalformedSct)?; let ret = Sct { log_id: id.as_slice_less_safe(), timestamp, sig_alg, sig: sig.as_slice_less_safe(), exts: exts.as_slice_less_safe(), }; Ok(ret) }) } } /// Verifies that the SCT `sct` (a `SignedCertificateTimestamp` encoding) /// is a correctly signed timestamp for `cert` (a DER-encoded X.509 end-entity /// certificate) valid `at_time`. `logs` describe the CT logs trusted by /// the caller to sign such an SCT. /// /// On success, this function returns the log used as an index into `logs`. /// Otherwise, it returns an `Error`. pub fn verify_sct(cert: &[u8], sct: &[u8], at_time: u64, logs: &[&Log]) -> Result { let sct = Sct::parse(sct)?; let i = lookup(logs, sct.log_id)?; let log = logs[i]; sct.verify(log.key, cert)?; if sct.timestamp > at_time { return Err(Error::TimestampInFuture); } Ok(i) } #[cfg(test)] mod tests; #[cfg(test)] mod tests_generated; #[cfg(test)] mod tests_google; sct-0.7.1/src/testdata/ecdsa-prime256v1-pub.raw000064400000000000000000000001011046102023000172060ustar 00000000000000}i^BNNhtJ?f=^ Ͱ#,n4bVE5ޤRsct-0.7.1/src/testdata/ecdsa-secp384r1-pub.raw000064400000000000000000000001411046102023000170260ustar 00000000000000hDTnv{ ۪Eϟ3Kn 8^_~=4Gb6KyV0rQ+zh sct-0.7.1/src/testdata/ecdsa_p256-badsigalg-sct.bin000064400000000000000000000001661046102023000200540ustar 00000000000000q^ӈoI=3Zej85NԏOG0E!=r1`i <l=+eS Gic*N;1(I];[oㆫdsct-0.7.1/src/testdata/ecdsa_p256-basic-sct.bin000064400000000000000000000001671046102023000172210ustar 00000000000000q^ӈoI=3Zej85NԏOH0F! f'srqxa!j4H!N|N:GFcРJsct-0.7.1/src/testdata/ecdsa_p256-future-sct.bin000064400000000000000000000001661046102023000174510ustar 00000000000000q^ӈoI=3Zej85NԏOG0E!=r1`i <l=+eS Gic*N;1(I];[oㆫdsct-0.7.1/src/testdata/ecdsa_p256-junk-sct.bin000064400000000000000000000001671046102023000171070ustar 00000000000000q^ӈoI=3Zej85NԏOG0E!=r1`i <l=+eS Gic*N;1(I];[oㆫdasct-0.7.1/src/testdata/ecdsa_p256-short-sct.bin000064400000000000000000000001711046102023000172720ustar 00000000000000q^ӈoI=3Zej85NԏOABH0F!&3hfby.v!VG[G!]$`A2>%ŷsct-0.7.1/src/testdata/ecdsa_p256-version-sct.bin000064400000000000000000000001661046102023000176240ustar 00000000000000q^ӈoI=3Zej85NԏOG0E!=r1`i <l=+eS Gic*N;1(I];[oㆫdsct-0.7.1/src/testdata/ecdsa_p256-wrongcert-sct.bin000064400000000000000000000001651046102023000201500ustar 00000000000000q^ӈoI=3Zej85NԏOF0D p`(eGlfDuWo ܗ IF N녩rvce{Ot#"T{pC<sct-0.7.1/src/testdata/ecdsa_p256-wrongext-sct.bin000064400000000000000000000001671046102023000200150ustar 00000000000000q^ӈoI=3Zej85NԏOAG0E!=r1`i <l=+eS Gic*N;1(I];[oㆫdsct-0.7.1/src/testdata/ecdsa_p256-wrongid-sct.bin000064400000000000000000000001661046102023000176100ustar 00000000000000G0E!=r1`i <l=+eS Gic*N;1(I];[oㆫdsct-0.7.1/src/testdata/ecdsa_p256-wrongtime-sct.bin000064400000000000000000000001671046102023000201530ustar 00000000000000q^ӈoI=3Zej85NԏO{H0F! f'srqxa!j4H!N|N:GFcРJsct-0.7.1/src/testdata/ecdsa_p384-basic-sct.bin000064400000000000000000000002251046102023000172160ustar 00000000000000)=]L)M(FV7$Xff0d0)?{zt J}l"_L ɑ*Akً0-N=d)PDs]bֽƎk3柑[sct-0.7.1/src/testdata/ecdsa_p384-wrongcert-sct.bin000064400000000000000000000002271046102023000201510ustar 00000000000000)=]L)M(FV7$Xfh0f1v#;AO\-آiy{A $rQeA18Sã¨Y^wa% =Ӡ9^*Mٕsct-0.7.1/src/testdata/ecdsa_p384-wrongtime-sct.bin000064400000000000000000000002251046102023000201500ustar 00000000000000)=]L)M(FV7$Xf{f0d0)?{zt J}l"_L ɑ*Akً0-N=d)PDs]bֽƎk3柑[sct-0.7.1/src/testdata/google-cert.bin000064400000000000000000000036161046102023000157310ustar 0000000000000000r "0  *H  0I1 0 UUS10U  Google Inc1%0#UGoogle Internet Authority G20 170628092600Z 170920092600Z0f1 0 UUS10U California10U Mountain View10U Google Inc10U *.google.com0Y0*H=*H=BY7[׎MݛIiVW7(zjG|J:=R r&d1XW;åw"00U%0++0 U0U0Ԃ *.google.com *.android.com*.appengine.google.com*.cloud.google.com*.db833953.google.cn*.g.co*.gcp.gvt2.com*.google-analytics.com *.google.ca *.google.cl*.google.co.in*.google.co.jp*.google.co.uk*.google.com.ar*.google.com.au*.google.com.br*.google.com.co*.google.com.mx*.google.com.tr*.google.com.vn *.google.de *.google.es *.google.fr *.google.hu *.google.it *.google.nl *.google.pl *.google.pt*.googleadapis.com*.googleapis.cn*.googlecommerce.com*.googlevideo.com *.gstatic.cn *.gstatic.com *.gvt1.com *.gvt2.com*.metric.gstatic.com *.urchin.com*.url.google.com*.youtube-nocookie.com *.youtube.com*.youtubeeducation.com*.yt.be *.ytimg.comandroid.clients.google.com android.comdeveloper.android.google.cndevelopers.android.google.cng.cogoo.glgoogle-analytics.com google.comgooglecommerce.comsource.android.google.cn urchin.com www.goo.glyoutu.be youtube.comyoutubeeducation.comyt.be0h+\0Z0++0http://pki.google.com/GIAG2.crt0++0http://clients1.google.com/ocsp0U".8iS7 #]ܤ0 U00U#0JhvbZ/0!U 00  +y0g 00U)0'0%#!http://pki.google.com/GIAG2.crl0  *H  x7^ϮG${!{exO ւ7KgCnD]&у+ 67${p FV 1=3TdSw0Xtsg"G6&"gJ7ЈdS\}.`Uk y2kjg^{دOr N{:HP9P.Stbg1jѷ8:ִ`,Kjo ֕1(|y϶$sYsct-0.7.1/src/testdata/google-pilot-pubkey.bin000064400000000000000000000001011046102023000174020ustar 00000000000000}K)=Zw∳  AFKb6  5О@<-eALsct-0.7.1/src/testdata/google-sct0.bin000064400000000000000000000001661046102023000156420ustar 00000000000000 Xgp <5߸w \iG0E v`eSE\yVDL^U&j O!֊%ZܣPH} xsct-0.7.1/src/testdata/google-sct1.bin000064400000000000000000000001651046102023000156420ustar 00000000000000+z O hp~.\=Ͷ\iF0D y<Vs7_Qַ z.(>Ey 2kؐ/8.gHrSKl&语:_sct-0.7.1/src/testdata/rsa-2048-pub.raw000064400000000000000000000004161046102023000155020ustar 000000000000000 ˎ9>G-Rbtڠ hkS,̸s+Py|9 ʿ/:8uwUACpS_?Ox)3UĜH& mqoidEНu|ўJ ~XN[17'05Y-d t@xx*ß5ARƌC4Vo> Oy 0 )5oC:K%S$[v2^.:E_(QEh+n.}k b_sct-0.7.1/src/testdata/rsa-3072-pub.raw000064400000000000000000000006161046102023000155020ustar 000000000000000X΍YIfXVZ5C-RtvR%6F!A%$]üu-8 mt#g7,7/&gd"(&^Q6CB dVL7†-wZ$>XɺmV%Sol;0t|2iCl[NdxC?U EV =]b 94ya؞/DK)9˱QG;㜁@7&~RYsct-0.7.1/src/testdata/rsa3072-wrongcert-sct.bin000064400000000000000000000006571046102023000174240ustar 00000000000000tiYNuR{_$Y7eICuHo 3Er0T'\Α >%#{i2R3MLE?Aeᕗ"+SynV!wcj Ġ||Aɇ&s Ϡ?nk-' BF&bkA՗jo4M55>j EcJZ/*G4-sct-0.7.1/src/testdata/rsa3072-wrongtime-sct.bin000064400000000000000000000006571046102023000174250ustar 00000000000000tiYNuR{_$Y7eI{=7ƅʺ"ԋ<4O{g$KlUhtx(. IO&#{dnO#K3`ϙ[L}1knc46Fbt .g@þWm(qy`Q,UUz-I!Pl{15-j+<|CH4$G:tPU& _)N74E'd>^Q6CB dVL7†-wZ$>XɺmV%Sol;0t|2iCl[NdxC?U EV =]b 94ya؞/DK)9˱QG;㜁@7&~RYsct-0.7.1/src/testdata/rsa4096-basic-sct.bin000064400000000000000000000010571046102023000164750ustar 00000000000000V'v](+bq iA")*%+GoKJ⸆Oܚsċ gϭž|S)Z:H9!ֲS,+V(}+ٷaH?;i@bۿ$by!@¢ԩ%}.J0bz.E s`f׶Y,7?9R#7vd]ajc}a|t !-Q3E.L÷OTTv2nj)[`dy7YFXg)ds'ÉVxFEBQ= ?]8o:RyT Z]XqO%B䡗>3iH=eQ[]/qyJ;}NYstńJV\+3eMZ58{4@ZU^^Jsct-0.7.1/src/testdata/rsa4096-wrongcert-sct.bin000064400000000000000000000010571046102023000174260ustar 00000000000000V'v](+bq iA")l o;3UǾSaY=Xn{&V'eekG׷œ?M]@s,Ody.$) Rƅ?&e隢{#р O" @-"t^ EE:sϻ8[ۓ${m̏-2$ULԛZCś%I5 xZLݼ_&0դhLO ' hy3;G>T ,!,rLe NgPCvpEhuӄLJ@.ou"x#8iOmjNۥna 9nrNC5SrQvb91T%͕#F aS/e4 l"`#"RdMq/OS,!n e1ݜ1x)a$"Ow"#E6-}0*(5U}1eSre^svPFsNQsct-0.7.1/src/testdata/rsa4096-wrongtime-sct.bin000064400000000000000000000010571046102023000174270ustar 00000000000000V'v](+bq iA"){*%+GoKJ⸆Oܚsċ gϭž|S)Z:H9!ֲS,+V(}+ٷaH?;i@bۿ$by!@¢ԩ%}.J0bz.E s`f׶Y,7?9R#7vd]ajc}a|t !-Q3E.L÷OTTv2nj)[`dy7YFXg)ds'ÉVxFEBQ= ?]8o:RyT Z]XqO%B䡗>3iH=eQ[]/qyJ;}NYstńJV\+3eMZ58{4@ZU^^Jsct-0.7.1/src/testdata/symantec-log-pubkey.bin000064400000000000000000000001011046102023000174030ustar 00000000000000F U 'FWBp:i;۫lS?MB3Xkr*B/~(5v=!sct-0.7.1/src/tests.rs000064400000000000000000000006761046102023000127320ustar 00000000000000use super::Error; #[test] fn test_unknown_log_is_not_fatal() { assert!(!Error::UnknownLog.should_be_fatal()); } #[test] fn test_unknown_sct_version_is_not_fatal() { assert!(!Error::UnsupportedSctVersion.should_be_fatal()); } #[test] fn test_other_errors_are_fatal() { assert!(Error::MalformedSct.should_be_fatal()); assert!(Error::InvalidSignature.should_be_fatal()); assert!(Error::TimestampInFuture.should_be_fatal()); } sct-0.7.1/src/tests_generated.rs000064400000000000000000000205401046102023000147400ustar 00000000000000use super::{verify_sct, Error, Log}; static TEST_LOG_ECDSA_P256: Log = Log { description: "fake test ecdsa_p256 log", url: "", operated_by: "random python script", max_merge_delay: 0, key: include_bytes!("testdata/ecdsa-prime256v1-pub.raw"), id: [ 0x71, 0xdc, 0x5e, 0xdb, 0xf0, 0x13, 0xd3, 0x88, 0x8a, 0x14, 0x6f, 0x49, 0x3d, 0xbe, 0x33, 0x94, 0xbb, 0x5a, 0xdb, 0x65, 0xb2, 0x6a, 0x96, 0xe2, 0x38, 0x35, 0x4e, 0xd4, 0x8f, 0xeb, 0xb2, 0x4f, ], }; static TEST_LOG_ECDSA_P384: Log = Log { description: "fake test ecdsa_p384 log", url: "", operated_by: "random python script", max_merge_delay: 0, key: include_bytes!("testdata/ecdsa-secp384r1-pub.raw"), id: [ 0x29, 0xbb, 0xef, 0x00, 0xba, 0xd9, 0x3d, 0x5d, 0x4c, 0x03, 0xc7, 0x29, 0xe9, 0x4d, 0xb6, 0xac, 0x00, 0xe0, 0xfd, 0x28, 0xf6, 0x46, 0x56, 0x37, 0x24, 0xac, 0x58, 0xdc, 0x66, 0xb1, 0x99, 0xe9, ], }; static TEST_LOG_RSA2048: Log = Log { description: "fake test rsa2048 log", url: "", operated_by: "random python script", max_merge_delay: 0, key: include_bytes!("testdata/rsa-2048-pub.raw"), id: [ 0x6e, 0x56, 0xa6, 0x5e, 0x21, 0x40, 0x97, 0x71, 0xeb, 0xbd, 0x16, 0x67, 0xc3, 0x37, 0x39, 0xb3, 0x35, 0x0e, 0xb2, 0xee, 0x9f, 0x3a, 0x55, 0x4c, 0xf3, 0x37, 0x12, 0xc0, 0x6a, 0x1a, 0x72, 0x0a, ], }; static TEST_LOG_RSA3072: Log = Log { description: "fake test rsa3072 log", url: "", operated_by: "random python script", max_merge_delay: 0, key: include_bytes!("testdata/rsa-3072-pub.raw"), id: [ 0xb4, 0xcd, 0x74, 0xe7, 0x69, 0x59, 0xb3, 0x4e, 0xbb, 0x90, 0x80, 0xba, 0x9e, 0xaa, 0x08, 0xaf, 0x75, 0x8b, 0x52, 0x7b, 0xbb, 0x5f, 0xf7, 0x24, 0x59, 0x8f, 0xfa, 0xc7, 0x37, 0x65, 0x49, 0xb0, ], }; static TEST_LOG_RSA4096: Log = Log { description: "fake test rsa4096 log", url: "", operated_by: "random python script", max_merge_delay: 0, key: include_bytes!("testdata/rsa-4096-pub.raw"), id: [ 0xfb, 0x56, 0x27, 0x12, 0xec, 0xa0, 0xf0, 0xdc, 0x7f, 0x06, 0xda, 0x76, 0xab, 0xba, 0x5d, 0x88, 0x28, 0x2b, 0x62, 0xc5, 0x71, 0xf6, 0x0d, 0x69, 0x41, 0x94, 0x85, 0x16, 0xc8, 0x22, 0xf3, 0x29, ], }; #[test] pub fn ecdsa_p256_basic() { let sct = include_bytes!("testdata/ecdsa_p256-basic-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1235; assert_eq!(Ok(0), verify_sct(cert, sct, now, &logs)); } #[test] pub fn ecdsa_p256_wrongtime() { let sct = include_bytes!("testdata/ecdsa_p256-wrongtime-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn ecdsa_p256_wrongcert() { let sct = include_bytes!("testdata/ecdsa_p256-wrongcert-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn ecdsa_p384_basic() { let sct = include_bytes!("testdata/ecdsa_p384-basic-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P384]; let now = 1235; assert_eq!(Ok(0), verify_sct(cert, sct, now, &logs)); } #[test] pub fn ecdsa_p384_wrongtime() { let sct = include_bytes!("testdata/ecdsa_p384-wrongtime-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P384]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn ecdsa_p384_wrongcert() { let sct = include_bytes!("testdata/ecdsa_p384-wrongcert-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P384]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn rsa2048_basic() { let sct = include_bytes!("testdata/rsa2048-basic-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA2048]; let now = 1235; assert_eq!(Ok(0), verify_sct(cert, sct, now, &logs)); } #[test] pub fn rsa2048_wrongtime() { let sct = include_bytes!("testdata/rsa2048-wrongtime-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA2048]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn rsa2048_wrongcert() { let sct = include_bytes!("testdata/rsa2048-wrongcert-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA2048]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn rsa3072_basic() { let sct = include_bytes!("testdata/rsa3072-basic-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA3072]; let now = 1235; assert_eq!(Ok(0), verify_sct(cert, sct, now, &logs)); } #[test] pub fn rsa3072_wrongtime() { let sct = include_bytes!("testdata/rsa3072-wrongtime-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA3072]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn rsa3072_wrongcert() { let sct = include_bytes!("testdata/rsa3072-wrongcert-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA3072]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn rsa4096_basic() { let sct = include_bytes!("testdata/rsa4096-basic-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA4096]; let now = 1235; assert_eq!(Ok(0), verify_sct(cert, sct, now, &logs)); } #[test] pub fn rsa4096_wrongtime() { let sct = include_bytes!("testdata/rsa4096-wrongtime-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA4096]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn rsa4096_wrongcert() { let sct = include_bytes!("testdata/rsa4096-wrongcert-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_RSA4096]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn ecdsa_p256_junk() { let sct = include_bytes!("testdata/ecdsa_p256-junk-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1235; assert_eq!(Err(Error::MalformedSct), verify_sct(cert, sct, now, &logs)); } #[test] pub fn ecdsa_p256_wrongid() { let sct = include_bytes!("testdata/ecdsa_p256-wrongid-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1235; assert_eq!(Err(Error::UnknownLog), verify_sct(cert, sct, now, &logs)); } #[test] pub fn ecdsa_p256_version() { let sct = include_bytes!("testdata/ecdsa_p256-version-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1235; assert_eq!( Err(Error::UnsupportedSctVersion), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn ecdsa_p256_future() { let sct = include_bytes!("testdata/ecdsa_p256-future-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1233; assert_eq!( Err(Error::TimestampInFuture), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn ecdsa_p256_wrongext() { let sct = include_bytes!("testdata/ecdsa_p256-wrongext-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn ecdsa_p256_badsigalg() { let sct = include_bytes!("testdata/ecdsa_p256-badsigalg-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1235; assert_eq!( Err(Error::InvalidSignature), verify_sct(cert, sct, now, &logs) ); } #[test] pub fn ecdsa_p256_short() { let sct = include_bytes!("testdata/ecdsa_p256-short-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_ECDSA_P256]; let now = 1234; for l in 0..121 { assert_eq!( Err(Error::MalformedSct), verify_sct(cert, &sct[..l], now, &logs) ); } } sct-0.7.1/src/tests_google.rs000064400000000000000000000027551046102023000142660ustar 00000000000000use super::{verify_sct, Log}; static GOOGLE_PILOT: Log = Log { description: "Google 'Pilot' log", url: "ct.googleapis.com/pilot/", operated_by: "Google", key: include_bytes!("testdata/google-pilot-pubkey.bin"), id: [ 164, 185, 9, 144, 180, 24, 88, 20, 135, 187, 19, 162, 204, 103, 112, 10, 60, 53, 152, 4, 249, 27, 223, 184, 227, 119, 205, 14, 200, 13, 220, 16, ], max_merge_delay: 86400, }; static SYMANTEC_LOG: Log = Log { description: "Symantec log", url: "ct.ws.symantec.com/", operated_by: "Symantec", key: include_bytes!("testdata/symantec-log-pubkey.bin"), id: [ 221, 235, 29, 43, 122, 13, 79, 166, 32, 139, 129, 173, 129, 104, 112, 126, 46, 142, 157, 1, 213, 92, 136, 141, 61, 17, 196, 205, 182, 236, 190, 204, ], max_merge_delay: 86400, }; #[test] fn test_google_sct0() { let sct = include_bytes!("testdata/google-sct0.bin"); let cert = include_bytes!("testdata/google-cert.bin"); let logs = [&GOOGLE_PILOT, &SYMANTEC_LOG]; let now = 1499619463644; assert_eq!(0, verify_sct(cert, sct, now, &logs).unwrap()); } #[test] fn test_google_sct1() { let sct = include_bytes!("testdata/google-sct1.bin"); let cert = include_bytes!("testdata/google-cert.bin"); let logs = [&GOOGLE_PILOT, &SYMANTEC_LOG]; let now = 1499619463644; assert_eq!(1, verify_sct(cert, sct, now, &logs).unwrap()); } #[test] fn test_log_is_debug() { use alloc::format; format!("{:?}", GOOGLE_PILOT); } sct-0.7.1/test/ecdsa-prime256v1-priv.pem000064400000000000000000000004561046102023000157640ustar 00000000000000-----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHcCAQEEICTKRu8A1v2t6AxDTojfY6AyX4yUu8lMzxtPSWQ914VgoAoGCCqGSM49 AwEHoUQDQgAEfWkIq175Qk5Osoz7rwPe+2gEdLDcSsg/7utmoT2YgV4VwQnNsIcj LG7lmjSF/eCFk2LgVkU1E96kj6KFUs3CyQ== -----END EC PRIVATE KEY----- sct-0.7.1/test/ecdsa-prime256v1-pub.pem000064400000000000000000000002621046102023000155650ustar 00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfWkIq175Qk5Osoz7rwPe+2gEdLDc Ssg/7utmoT2YgV4VwQnNsIcjLG7lmjSF/eCFk2LgVkU1E96kj6KFUs3CyQ== -----END PUBLIC KEY----- sct-0.7.1/test/ecdsa-secp384r1-priv.pem000064400000000000000000000005471046102023000156010ustar 00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQAIg== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIGkAgEBBDAyNaltszKu2nciaS0iY2C86UQwXb0+uGAaxtIo2s0UPqiCXZzoMzrm 3HfP9rPjYCWgBwYFK4EEACKhZANiAARotsz+RFSg7G4BdqPu6nsNDq3bqkXPn5CQ M7riFksZbhQKnvkVkjicFZePgPvq916VD1/uwZJ+2j3Q/q7h9cM0R+6V1vLC2mI2 Agij9OZLedkXVh4EMHL+USsWGXporgw= -----END EC PRIVATE KEY----- sct-0.7.1/test/ecdsa-secp384r1-pub.pem000064400000000000000000000003271046102023000154030ustar 00000000000000-----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEaLbM/kRUoOxuAXaj7up7DQ6t26pFz5+Q kDO64hZLGW4UCp75FZI4nBWXj4D76vdelQ9f7sGSfto90P6u4fXDNEfuldbywtpi NgIIo/TmS3nZF1YeBDBy/lErFhl6aK4M -----END PUBLIC KEY----- sct-0.7.1/test/mktest.py000064400000000000000000000154771046102023000133000ustar 00000000000000import subprocess import struct import hashlib from os import path SIGALG_ECDSA_SHA256 = 0x0403 SIGALG_ECDSA_SHA384 = 0x0503 SIGALG_RSA_SHA256 = 0x0401 SIGALG_RSA_SHA384 = 0x0501 SIGALG_HASH = { SIGALG_RSA_SHA256: 'sha256', SIGALG_RSA_SHA384: 'sha384', SIGALG_ECDSA_SHA256: 'sha256', SIGALG_ECDSA_SHA384: 'sha384', } class SCT(object): def __init__(self): self.version = 0 self.type = 0 self.id = '\x11\x22\x33\x44' * 8 self.timestamp = 1234 self.enttype = 0 self.exts = '\x00\x00' self.sig = 0 def sign(self, key, alg, cert): to_sign = struct.pack('!BBQHBH', self.version, self.type, self.timestamp, self.enttype, 0, len(cert)) \ + cert + self.exts open('sigin.bin', 'w').write(to_sign) sig = subprocess.check_output(['openssl', 'dgst', '-' + SIGALG_HASH[alg], '-sign', key, 'sigin.bin']) self.sig = struct.pack('!HH', alg, len(sig)) + sig def encode(self): return struct.pack('!B32sQ', self.version, self.id, self.timestamp) + self.exts + self.sig def copy(self): c = SCT() c.__dict__ = self.__dict__.copy() return c def having(self, **kwargs): copy = self.copy() copy.__dict__.update(**kwargs) return copy def genrsa(len): priv, pub = 'rsa-%d-priv.pem' % len, 'rsa-%d-pub.pem' % len if not path.exists(pub): subprocess.check_call(['openssl', 'genrsa', '-out', priv, str(len)]) subprocess.check_call(['openssl', 'rsa', '-in', priv, '-pubout', '-out', pub]) return priv, pub def genecdsa(curve): priv, pub = 'ecdsa-%s-priv.pem' % curve, 'ecdsa-%s-pub.pem' % curve if not path.exists(pub): subprocess.check_call(['openssl', 'ecparam', '-genkey', '-name', curve, '-out', priv]) subprocess.check_call(['openssl', 'ec', '-in', priv, '-pubout', '-out', pub]) return priv, pub def convert_der(pub): der = pub.replace('.pem', '.der') subprocess.check_call(['openssl', 'asn1parse', '-in', pub, '-out', der], stdout = subprocess.PIPE) return der def keyhash(pub): der = convert_der(pub) return hashlib.sha256(open(der).read()).digest() def raw_public_key(spki): def take_byte(b): return ord(b[0]), b[1:] def take_len(b): v, b = take_byte(b) if v & 0x80: r = 0 for _ in range(v & 3): x, b = take_byte(b) r <<= 8 r |= x return r, b return v, b def take_seq(b): tag, b = take_byte(b) ll, b = take_len(b) assert tag == 0x30 return b[:ll], b[ll:] def take_bitstring(b): tag, b = take_byte(b) ll, b = take_len(b) bits, b = take_byte(b) assert tag == 0x03 assert bits == 0 return b[:ll-1], b[ll-1:] spki, rest = take_seq(spki) assert rest == '' id, data = take_seq(spki) keydata, rest = take_bitstring(data) assert rest == '' return keydata def format_bytes(b): return ', '.join(map(lambda x: '0x%02x' % ord(x), b)) keys = [ ('ecdsa_p256', genecdsa('prime256v1')), ('ecdsa_p384', genecdsa('secp384r1')), ('rsa2048', genrsa(2048)), ('rsa3072', genrsa(3072)), ('rsa4096', genrsa(4096)), ] algs = dict( rsa2048 = SIGALG_RSA_SHA256, rsa3072 = SIGALG_RSA_SHA384, rsa4096 = SIGALG_RSA_SHA384, ecdsa_p256 = SIGALG_ECDSA_SHA256, ecdsa_p384 = SIGALG_ECDSA_SHA384 ) print 'use super::{Log, Error, verify_sct};' print for name, (priv, pub) in keys: pubder = convert_der(pub) pubraw = pubder.replace('.der', '.raw') open('../src/testdata/' + pubraw, 'w').write(raw_public_key(open(pubder).read())) print """static TEST_LOG_%s: Log = Log { description: "fake test %s log", url: "", operated_by: "random python script", max_merge_delay: 0, key: include_bytes!("testdata/%s"), id: [%s], }; """ % (name.upper(), name, pubraw, format_bytes(keyhash(pub))) def emit_test(keyname, sctname, encoding, timestamp = 1235, expect = 'Ok(0)', extra = ''): open('../src/testdata/%s-%s-sct.bin' % (keyname, sctname), 'w').write(encoding) print """#[test] pub fn %(keyname)s_%(sctname)s() { let sct = include_bytes!("testdata/%(keyname)s-%(sctname)s-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_%(keyname_up)s]; let now = %(time)d; assert_eq!(%(expect)s, verify_sct(cert, sct, now, &logs)); } """ % dict(time = timestamp, sctname = sctname, keyname = keyname, keyname_up = keyname.upper(), expect = expect) def emit_short_test(keyname, sctname, encoding, expect): open('../src/testdata/%s-%s-sct.bin' % (keyname, sctname), 'w').write(encoding) print """#[test] pub fn %(keyname)s_%(sctname)s() { let sct = include_bytes!("testdata/%(keyname)s-%(sctname)s-sct.bin"); let cert = b"cert"; let logs = [&TEST_LOG_%(keyname_up)s]; let now = 1234; for l in 0..%(len)d { assert_eq!(%(expect)s, verify_sct(cert, &sct[..l], now, &logs)); } } """ % dict(sctname = sctname, keyname = keyname, keyname_up = keyname.upper(), expect = expect, len = len(encoding)) # basic tests of each key type for name, (priv, pub) in keys: sct = SCT() sct.sign(priv, algs[name], 'cert') sct.id = keyhash(pub) emit_test(name, 'basic', sct.encode()) emit_test(name, 'wrongtime', sct.having(timestamp = 123).encode(), expect = 'Err(Error::InvalidSignature)') sct.sign(priv, algs[name], 'adsqweqweqwekimqwelqwmel') emit_test(name, 'wrongcert', sct.encode(), expect = 'Err(Error::InvalidSignature)') # other tests, only for a particular key type name, (priv, pub) = keys[0] sct = SCT() sct.sign(priv, algs[name], 'cert') sct.id = keyhash(pub) emit_test(name, 'junk', sct.encode() + 'a', expect = 'Err(Error::MalformedSct)') emit_test(name, 'wrongid', sct.having(id = '\x00' * 32).encode(), expect = 'Err(Error::UnknownLog)') emit_test(name, 'version', sct.having(version = 1).encode(), expect = 'Err(Error::UnsupportedSctVersion)') emit_test(name, 'future', sct.encode(), timestamp = 1233, expect = 'Err(Error::TimestampInFuture)') emit_test(name, 'wrongext', sct.having(exts = '\x00\x01A').encode(), expect = 'Err(Error::InvalidSignature)') emit_test(name, 'badsigalg', sct.having(sig = '\x01\x02' + sct.sig[2:]).encode(), expect = 'Err(Error::InvalidSignature)') # emit length test with extension, so we test length handling sct_short = sct.having(exts = '\x00\x02AB') sct_short.sign(priv, algs[name], 'cert') emit_short_test(name, 'short', sct_short.encode(), expect = 'Err(Error::MalformedSct)') sct-0.7.1/test/rsa-2048-priv.pem000064400000000000000000000032131046102023000142410ustar 00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAy445PkeFs7+cAgTNLfWkUhfMYhJ0oIraoNsN1sto0mtTuyzM uHOyK1Cc/3l8p4s5k87WDcq/L/o6Fd44g5H5dXfjVUHZQ7Fw3lPmz1+Z5rl/u7O8 P094HCkzu7+eVcScSO8m9wnGGW0IcdJvaWRF0J11mcZ8lQ7t0Z6Fm+pKGgr4fpX2 WI9OvVu1Mcs3/ScwNRbIWZ7TLY2BZCAFs3RAvnjGeP5/KgTDnxg1QcnMUobhlhnz i9DaxoyRQzSmVm8+BSBPeQPK9+sN8+wwCin8NW9DOuiWSyVTJNtbB3YyXi6157w6 RV8oEFFF8uMDaOPZEyuhbi6QiB3ifclr7QtiXwIDAQABAoIBABnenGXO3y4l9uTG yXDC3DxWq/H22H2iyABTdqHKviqn2z9ZhTcX9RfOKfXJ8c61Qf8H9WpRTxUA3yry UApgneyQ7QJj2QHiZi7LSPUn+D47awFm6VC+f8xMbDe7NZs+3oHiavhQdK28jqsw jFo/lSPbLxv4/tJO0GioleBn2T0P19jtwA3i54J6mcpttl5giwMFR6pTL/Uf2FcF TPJm1bu82G9KTWzohGbMgEHu4bKleZg0jBwf6mQqvH8N2Z0BWmaNSyeuPvth4N9N 61/zmCcUxfHs9N6qHxYwF2v2IPATyOYaqPzhSwxwiSZTfbxC82DvGJQqXr5t0MTD oecD0yECgYEA5Gj82hg7gGD0GL6dsWiJbULZoZUATtSSA1s362cv6oCGYErol2DN 3ks1NyeDnxhZt5S5T8WrN5sc+9fgVUdUNzkXJI8KQOykdIt6XN+0dayoQFNe6gKJ DV4MAe65C6XOdTVBtB9usOmISE10P1b/ELWxtDHvkCYejAOsTbUenHECgYEA5CSr zGEvdshI3eqp84GQCpMSQO+/DsXa9ZoVcHXEaNmy9GwG0qIW3AFFeAy3HKzQ+r5G x/XZNj0iyOiRXldly3LhT+PgcDTdqKW9E4/L69G/NB88Amrhnt7mx+XyNGQy2z25 5hbeu6O1fG+3m7idhFmWxaOsm9oBFWv+XI/Wk88CgYBSeHHrkVpSlS8tjA3GE7ej IsMPq4wL6oa5/YKoVX6gjj12oTVwCvzqKX+SZYsJs7IZLfLnEbkrf68sY5rVT8bh lZR8l8UdAhSzG/VXeVJgNrIdX7zig33WvMFbJUXdJcXw3gTWM481A204pfa2NAQu lVwPcwRLqOfYqC7bc+0UkQKBgHpMnjwFrSgD3ev4q/p5bfn9NT/SRZ1puyMF4pBS 0WNTsHcOoemwMojltZPRXSfmDHEeJ1tyE2rcAxWodqUYPN1/TAFDq0D7VgfeMSmX YD2eRt1uEQFKwoAkBZsLTXeAbzLQOCN8BxKXg+adDNRRdz9Ht2djglhZ2VLefZCp GuJJAoGAQbBxu1FyAUWHieM9lzCss4Qgs0BAVvB30+0egTdEo2P+sJkfUiifAyx8 wMcoeI9cNIWhM1r9FHEF0R+u4n3LrWUqnsuvrzoWT0Td2LZZCKrd5Fif8Kgj/Z/w qqUuEqmvrQBz+OsNVDPpQNRwpJpGOqlhKZNAFOpUY6ve0b1dcA0= -----END RSA PRIVATE KEY----- sct-0.7.1/test/rsa-2048-pub.pem000064400000000000000000000007031046102023000140500ustar 00000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy445PkeFs7+cAgTNLfWk UhfMYhJ0oIraoNsN1sto0mtTuyzMuHOyK1Cc/3l8p4s5k87WDcq/L/o6Fd44g5H5 dXfjVUHZQ7Fw3lPmz1+Z5rl/u7O8P094HCkzu7+eVcScSO8m9wnGGW0IcdJvaWRF 0J11mcZ8lQ7t0Z6Fm+pKGgr4fpX2WI9OvVu1Mcs3/ScwNRbIWZ7TLY2BZCAFs3RA vnjGeP5/KgTDnxg1QcnMUobhlhnzi9DaxoyRQzSmVm8+BSBPeQPK9+sN8+wwCin8 NW9DOuiWSyVTJNtbB3YyXi6157w6RV8oEFFF8uMDaOPZEyuhbi6QiB3ifclr7Qti XwIDAQAB -----END PUBLIC KEY----- sct-0.7.1/test/rsa-3072-priv.pem000064400000000000000000000046331046102023000142460ustar 00000000000000-----BEGIN RSA PRIVATE KEY----- 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 -----END RSA PRIVATE KEY----- sct-0.7.1/test/rsa-3072-pub.pem000064400000000000000000000011611046102023000140450ustar 00000000000000-----BEGIN PUBLIC KEY----- MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyljOjVm0HqyPtEmylaq0 zsLuZuHHWPxWolo1Qy1Sm3R2UrsPPOHuaVeZJS3yC6uaXtmytCEyNyS6JorIZyfH YhCplohOCCNgPatS2rNhHejY+PrUkqRvN1h785uosE4hkPSbqxqPZsbnPawRX9vD 9ZhqHXNj2d4GE0Fxsb6uMncpUBdn0ulvdY4ZKDzRVZodfAuMLEKC9kQSlvV9Jp4v H/ewzHHts7VtmTlbmOsRdK+AXSgi2mzdcWfs6Gni0i9IGOi0Fn39YgtpwYjOz9Mc tnGd6g+oOyHiLcoJef+ZiczoKj28Iv2e7WXjPlleFhSg5EDStqLkVyABp2vF+h1Q faH5hMGMX8DSDBbtVzb3E8/5KlbkLkwU74YrA44LS4AOS2ojdcZR+cuIyTtzeN7W h91am75WOkNniOHrDndhbokLqxBCfGlYAnmQuWTG1TUS741bZxC60w4aF8ksl/Ev q6/8ySuRK84Xg+MZYIWDbjkzeM4wgvOrg/zK9sbvLhDJAgMBAAE= -----END PUBLIC KEY----- sct-0.7.1/test/rsa-4096-priv.pem000064400000000000000000000062531046102023000142550ustar 00000000000000-----BEGIN RSA PRIVATE KEY----- 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 -----END RSA PRIVATE KEY----- sct-0.7.1/test/rsa-4096-pub.pem000064400000000000000000000014401046102023000140540ustar 00000000000000-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlACszAz/ltbkpwgEVXAm 95KXFp0VXSzyFMwdRbko0gcVn3dIbHDuswpJkA2VWBeUwz5acgIRPHrQHwFE3b0G b2CLOlca+6FOha3t96w4HHXNRdfQ7/HZ7Zi1lNZQHk1eB4t1UvT/7oJcenftlmBQ sOYLrV7BWMfWvmHpSSkyqUlG959ZPkZA3H6QmEmiJAgUuh6jQa/Mj5hRQSi6MQt+ WyLiQWnUXVCfbKEPGzFuWqYeq8rvGS/t46pXWD+DEmOP576SI+L4Wy46dEYTpw97 S4DwS0OEDKs6mC6JpwL1zSLTrEYSH3lguVqObt5DaCRhmrmT3EHXkxBvGqRQszxK ADwtQgrC5WFxq3wp3TgAN0QE8E+mr7hBPiXZNoxG1iEQ0H9BJYmK/CQRXefBscXD vLavdYW9LZ2+hMMbOJsZDG3adCNntzcs/OidNy+P/hb8pSYGZ55kIigmjBGtHjzm VIW+Kf3wUA5VeRMHAnD72CcP8E/phmja6nF+gM/hTdyGhMVdKe7l1l8R97IxneNp H+ofW93iAZyA7aI1AnLXBvGjRF4ChFisC2tPYS48imF53n1dPZfOk3/FTAsehwEX 20POv11uR9OHjkayTy0WBqzaG+UbvpCQWvYmeZVPnnEA2hR5Z7Efn356ve9pZK4z 7QDQ6OpL8QEbv7Ekk4KJb1ECAwEAAQ== -----END PUBLIC KEY-----