mirror of https://github.com/ctz/rustls
Merge pki-types history into rustls monorepo
This commit is contained in:
commit
047658675c
|
@ -1710,7 +1710,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"ring 0.17.5",
|
"ring 0.17.5",
|
||||||
"rustls-pemfile 2.0.0-alpha.1",
|
"rustls-pemfile 2.0.0-alpha.1",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustls-webpki 0.102.0-alpha.6",
|
"rustls-webpki 0.102.0-alpha.6",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"subtle",
|
"subtle",
|
||||||
|
@ -1730,7 +1730,7 @@ dependencies = [
|
||||||
"rayon",
|
"rayon",
|
||||||
"rustls 0.22.0-alpha.4",
|
"rustls 0.22.0-alpha.4",
|
||||||
"rustls-pemfile 2.0.0-alpha.1",
|
"rustls-pemfile 2.0.0-alpha.1",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1754,7 +1754,7 @@ dependencies = [
|
||||||
"rcgen",
|
"rcgen",
|
||||||
"rustls 0.22.0-alpha.4",
|
"rustls 0.22.0-alpha.4",
|
||||||
"rustls-pemfile 2.0.0-alpha.1",
|
"rustls-pemfile 2.0.0-alpha.1",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"webpki-roots 0.26.0-alpha.1",
|
"webpki-roots 0.26.0-alpha.1",
|
||||||
|
@ -1776,9 +1776,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4aaa4fe93b39faddb6a8f99568c3e5880680156da0d46818e884a071381f67fe"
|
checksum = "4aaa4fe93b39faddb6a8f99568c3e5880680156da0d46818e884a071381f67fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "0.2.1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1804,7 +1808,7 @@ dependencies = [
|
||||||
"rcgen",
|
"rcgen",
|
||||||
"rsa",
|
"rsa",
|
||||||
"rustls 0.22.0-alpha.4",
|
"rustls 0.22.0-alpha.4",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustls-webpki 0.102.0-alpha.6",
|
"rustls-webpki 0.102.0-alpha.6",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -1832,7 +1836,7 @@ checksum = "34d9ed3a8267782ba32d257ff5b197b63eef19a467dbd1be011caaae35ee416e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
"ring 0.17.5",
|
"ring 0.17.5",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"untrusted 0.9.0",
|
"untrusted 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2326,7 +2330,7 @@ version = "0.26.0-alpha.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42157929d7ca9c353222a4d1763c52ef86d25d0fd2eca66076df5975fd4e25ed"
|
checksum = "42157929d7ca9c353222a4d1763c52ef86d25d0fd2eca66076df5975fd4e25ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls-pki-types",
|
"rustls-pki-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -6,6 +6,8 @@ members = [
|
||||||
"connect-tests",
|
"connect-tests",
|
||||||
# tests and example code
|
# tests and example code
|
||||||
"examples",
|
"examples",
|
||||||
|
# the pki-types library
|
||||||
|
"pki-types",
|
||||||
# the main library and tests
|
# the main library and tests
|
||||||
"rustls",
|
"rustls",
|
||||||
# example of custom provider
|
# example of custom provider
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "0.2.1"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.60"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
description = "Shared types for the rustls PKI ecosystem"
|
||||||
|
documentation = "https://docs.rs/rustls-pki-types"
|
||||||
|
homepage = "https://github.com/rustls/pki-types"
|
||||||
|
repository = "https://github.com/rustls/pki-types"
|
||||||
|
categories = ["network-programming", "data-structures", "cryptography"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["alloc"]
|
||||||
|
alloc = []
|
||||||
|
std = ["alloc"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
|
@ -0,0 +1,201 @@
|
||||||
|
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 2023 Dirkjan Ochtman
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) 2023 Dirkjan Ochtman <dirkjan@ochtman.nl>
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,40 @@
|
||||||
|
# rustls-pki-types
|
||||||
|
|
||||||
|
[![Build Status](https://github.com/rustls/pki-types/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/rustls/pki-types/actions/workflows/ci.yml?query=branch%3Amain)
|
||||||
|
[![Documentation](https://docs.rs/rustls-pki-types/badge.svg)](https://docs.rs/rustls-pki-types/)
|
||||||
|
[![Chat](https://img.shields.io/discord/976380008299917365?logo=discord)](https://discord.gg/MCSB76RU96)
|
||||||
|
|
||||||
|
This crate provides types for representing X.509 certificates, keys and other types as commonly
|
||||||
|
used in the rustls ecosystem. It is intended to be used by crates that need to work with such X.509
|
||||||
|
types, such as [rustls](https://crates.io/crates/rustls),
|
||||||
|
[rustls-webpki](https://crates.io/crates/rustls-webpki),
|
||||||
|
[rustls-pemfile](https://crates.io/crates/rustls-pemfile), and others.
|
||||||
|
|
||||||
|
Some of these crates used to define their own trivial wrappers around DER-encoded bytes.
|
||||||
|
However, in order to avoid inconvenient dependency edges, these were all disconnected. By
|
||||||
|
using a common low-level crate of types with long-term stable API, we hope to avoid the
|
||||||
|
downsides of unnecessary dependency edges while providing interoperability between crates.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Interoperability between different crates in the rustls ecosystem
|
||||||
|
- Long-term stable API
|
||||||
|
- No dependencies
|
||||||
|
- Support for `no_std` contexts, with optional support for `alloc`
|
||||||
|
|
||||||
|
## DER and PEM
|
||||||
|
|
||||||
|
Many of the types defined in this crate represent DER-encoded data. DER is a binary encoding of
|
||||||
|
the ASN.1 format commonly used in web PKI specifications. It is a binary encoding, so it is
|
||||||
|
relatively compact when stored in memory. However, as a binary format, it is not very easy to
|
||||||
|
work with for humans and in contexts where binary data is inconvenient. For this reason,
|
||||||
|
many tools and protocols use a ASCII-based encoding of DER, called PEM. In addition to the
|
||||||
|
base64-encoded DER, PEM objects are delimited by header and footer lines which indicate the type
|
||||||
|
of object contained in the PEM blob.
|
||||||
|
|
||||||
|
The [rustls-pemfile](https://docs.rs/rustls-pemfile) crate can be used to parse PEM files.
|
||||||
|
|
||||||
|
## Creating new certificates and keys
|
||||||
|
|
||||||
|
This crate does not provide any functionality for creating new certificates or keys. However,
|
||||||
|
the [rcgen](https://docs.rs/rcgen) crate can be used to create new certificates and keys.
|
|
@ -0,0 +1,491 @@
|
||||||
|
//! This crate provides types for representing X.509 certificates, keys and other types as
|
||||||
|
//! commonly used in the rustls ecosystem. It is intended to be used by crates that need to work
|
||||||
|
//! with such X.509 types, such as [rustls](https://crates.io/crates/rustls),
|
||||||
|
//! [rustls-webpki](https://crates.io/crates/rustls-webpki),
|
||||||
|
//! [rustls-pemfile](https://crates.io/crates/rustls-pemfile), and others.
|
||||||
|
//!
|
||||||
|
//! Some of these crates used to define their own trivial wrappers around DER-encoded bytes.
|
||||||
|
//! However, in order to avoid inconvenient dependency edges, these were all disconnected. By
|
||||||
|
//! using a common low-level crate of types with long-term stable API, we hope to avoid the
|
||||||
|
//! downsides of unnecessary dependency edges while providing good interoperability between crates.
|
||||||
|
//!
|
||||||
|
//! ## DER and PEM
|
||||||
|
//!
|
||||||
|
//! Many of the types defined in this crate represent DER-encoded data. DER is a binary encoding of
|
||||||
|
//! the ASN.1 format commonly used in web PKI specifications. It is a binary encoding, so it is
|
||||||
|
//! relatively compact when stored in memory. However, as a binary format, it is not very easy to
|
||||||
|
//! work with for humans and in contexts where binary data is inconvenient. For this reason,
|
||||||
|
//! many tools and protocols use a ASCII-based encoding of DER, called PEM. In addition to the
|
||||||
|
//! base64-encoded DER, PEM objects are delimited by header and footer lines which indicate the type
|
||||||
|
//! of object contained in the PEM blob.
|
||||||
|
//!
|
||||||
|
//! The [rustls-pemfile](https://docs.rs/rustls-pemfile) crate can be used to parse PEM files.
|
||||||
|
//!
|
||||||
|
//! ## Creating new certificates and keys
|
||||||
|
//!
|
||||||
|
//! This crate does not provide any functionality for creating new certificates or keys. However,
|
||||||
|
//! the [rcgen](https://docs.rs/rcgen) crate can be used to create new certificates and keys.
|
||||||
|
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
#![warn(unreachable_pub, clippy::use_self)]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::fmt;
|
||||||
|
use core::ops::Deref;
|
||||||
|
use core::time::Duration;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
/// A DER-encoded X.509 private key, in one of several formats
|
||||||
|
///
|
||||||
|
/// See variant inner types for more detailed information.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum PrivateKeyDer<'a> {
|
||||||
|
/// An RSA private key
|
||||||
|
Pkcs1(PrivatePkcs1KeyDer<'a>),
|
||||||
|
/// A Sec1 private key
|
||||||
|
Sec1(PrivateSec1KeyDer<'a>),
|
||||||
|
/// A PKCS#8 private key
|
||||||
|
Pkcs8(PrivatePkcs8KeyDer<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PrivateKeyDer<'a> {
|
||||||
|
/// Yield the DER-encoded bytes of the private key
|
||||||
|
pub fn secret_der(&self) -> &[u8] {
|
||||||
|
match self {
|
||||||
|
PrivateKeyDer::Pkcs1(key) => key.secret_pkcs1_der(),
|
||||||
|
PrivateKeyDer::Sec1(key) => key.secret_sec1_der(),
|
||||||
|
PrivateKeyDer::Pkcs8(key) => key.secret_pkcs8_der(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<PrivatePkcs1KeyDer<'a>> for PrivateKeyDer<'a> {
|
||||||
|
fn from(key: PrivatePkcs1KeyDer<'a>) -> Self {
|
||||||
|
Self::Pkcs1(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<PrivateSec1KeyDer<'a>> for PrivateKeyDer<'a> {
|
||||||
|
fn from(key: PrivateSec1KeyDer<'a>) -> Self {
|
||||||
|
Self::Sec1(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<PrivatePkcs8KeyDer<'a>> for PrivateKeyDer<'a> {
|
||||||
|
fn from(key: PrivatePkcs8KeyDer<'a>) -> Self {
|
||||||
|
Self::Pkcs8(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A DER-encoded plaintext RSA private key; as specified in PKCS#1/RFC 3447
|
||||||
|
///
|
||||||
|
/// RSA private keys are identified in PEM context as `RSA PRIVATE KEY` and when stored in a
|
||||||
|
/// file usually use a `.pem` or `.key` extension. For more on PEM files, refer to the crate
|
||||||
|
/// documentation.
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub struct PrivatePkcs1KeyDer<'a>(Der<'a>);
|
||||||
|
|
||||||
|
impl PrivatePkcs1KeyDer<'_> {
|
||||||
|
/// Yield the DER-encoded bytes of the private key
|
||||||
|
pub fn secret_pkcs1_der(&self) -> &[u8] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [u8]> for PrivatePkcs1KeyDer<'a> {
|
||||||
|
fn from(slice: &'a [u8]) -> Self {
|
||||||
|
Self(Der(DerInner::Borrowed(slice)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
impl<'a> From<Vec<u8>> for PrivatePkcs1KeyDer<'a> {
|
||||||
|
fn from(vec: Vec<u8>) -> Self {
|
||||||
|
Self(Der(DerInner::Owned(vec)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for PrivatePkcs1KeyDer<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("PrivatePkcs1KeyDer")
|
||||||
|
.field(&"[secret key elided]")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Sec1-encoded plaintext private key; as specified in RFC 5915
|
||||||
|
///
|
||||||
|
/// Sec1 private keys are identified in PEM context as `EC PRIVATE KEY` and when stored in a
|
||||||
|
/// file usually use a `.pem` or `.key` extension. For more on PEM files, refer to the crate
|
||||||
|
/// documentation.
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub struct PrivateSec1KeyDer<'a>(Der<'a>);
|
||||||
|
|
||||||
|
impl PrivateSec1KeyDer<'_> {
|
||||||
|
/// Yield the DER-encoded bytes of the private key
|
||||||
|
pub fn secret_sec1_der(&self) -> &[u8] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [u8]> for PrivateSec1KeyDer<'a> {
|
||||||
|
fn from(slice: &'a [u8]) -> Self {
|
||||||
|
Self(Der(DerInner::Borrowed(slice)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
impl<'a> From<Vec<u8>> for PrivateSec1KeyDer<'a> {
|
||||||
|
fn from(vec: Vec<u8>) -> Self {
|
||||||
|
Self(Der(DerInner::Owned(vec)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for PrivateSec1KeyDer<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("PrivatePkcs1KeyDer")
|
||||||
|
.field(&"[secret key elided]")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A DER-encoded plaintext private key; as specified in PKCS#8/RFC 5958
|
||||||
|
///
|
||||||
|
/// PKCS#8 private keys are identified in PEM context as `PRIVATE KEY` and when stored in a
|
||||||
|
/// file usually use a `.pem` or `.key` extension. For more on PEM files, refer to the crate
|
||||||
|
/// documentation.
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub struct PrivatePkcs8KeyDer<'a>(Der<'a>);
|
||||||
|
|
||||||
|
impl PrivatePkcs8KeyDer<'_> {
|
||||||
|
/// Yield the DER-encoded bytes of the private key
|
||||||
|
pub fn secret_pkcs8_der(&self) -> &[u8] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [u8]> for PrivatePkcs8KeyDer<'a> {
|
||||||
|
fn from(slice: &'a [u8]) -> Self {
|
||||||
|
Self(Der(DerInner::Borrowed(slice)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
impl<'a> From<Vec<u8>> for PrivatePkcs8KeyDer<'a> {
|
||||||
|
fn from(vec: Vec<u8>) -> Self {
|
||||||
|
Self(Der(DerInner::Owned(vec)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for PrivatePkcs8KeyDer<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("PrivatePkcs1KeyDer")
|
||||||
|
.field(&"[secret key elided]")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trust anchor (a.k.a. root CA)
|
||||||
|
///
|
||||||
|
/// Traditionally, certificate verification libraries have represented trust anchors as full X.509
|
||||||
|
/// root certificates. However, those certificates contain a lot more data than is needed for
|
||||||
|
/// verifying certificates. The [`TrustAnchor`] representation allows an application to store
|
||||||
|
/// just the essential elements of trust anchors.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct TrustAnchor<'a> {
|
||||||
|
/// Value of the `subject` field of the trust anchor
|
||||||
|
pub subject: Der<'a>,
|
||||||
|
/// Value of the `subjectPublicKeyInfo` field of the trust anchor
|
||||||
|
pub subject_public_key_info: Der<'a>,
|
||||||
|
/// Value of DER-encoded `NameConstraints`, containing name constraints to the trust anchor, if any
|
||||||
|
pub name_constraints: Option<Der<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrustAnchor<'_> {
|
||||||
|
/// Yield a `'static` lifetime of the `TrustAnchor` by allocating owned `Der` variants
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub fn to_owned(&self) -> TrustAnchor<'static> {
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
TrustAnchor {
|
||||||
|
subject: self.subject.as_ref().to_owned().into(),
|
||||||
|
subject_public_key_info: self
|
||||||
|
.subject_public_key_info
|
||||||
|
.as_ref()
|
||||||
|
.to_owned()
|
||||||
|
.into(),
|
||||||
|
name_constraints: self
|
||||||
|
.name_constraints
|
||||||
|
.as_ref()
|
||||||
|
.map(|nc| nc.as_ref().to_owned().into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Certificate Revocation List; as specified in RFC 5280
|
||||||
|
///
|
||||||
|
/// Certificate revocation lists are identified in PEM context as `X509 CRL` and when stored in a
|
||||||
|
/// file usually use a `.crl` extension. For more on PEM files, refer to the crate documentation.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct CertificateRevocationListDer<'a>(Der<'a>);
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for CertificateRevocationListDer<'_> {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for CertificateRevocationListDer<'_> {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [u8]> for CertificateRevocationListDer<'a> {
|
||||||
|
fn from(slice: &'a [u8]) -> Self {
|
||||||
|
Self(Der::from(slice))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
impl<'a> From<Vec<u8>> for CertificateRevocationListDer<'a> {
|
||||||
|
fn from(vec: Vec<u8>) -> Self {
|
||||||
|
Self(Der::from(vec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A DER-encoded X.509 certificate; as specified in RFC 5280
|
||||||
|
///
|
||||||
|
/// Certificates are identified in PEM context as `CERTIFICATE` and when stored in a
|
||||||
|
/// file usually use a `.pem`, `.cer` or `.crt` extension. For more on PEM files, refer to the
|
||||||
|
/// crate documentation.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct CertificateDer<'a>(Der<'a>);
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for CertificateDer<'_> {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for CertificateDer<'_> {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [u8]> for CertificateDer<'a> {
|
||||||
|
fn from(slice: &'a [u8]) -> Self {
|
||||||
|
Self(Der::from(slice))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
impl<'a> From<Vec<u8>> for CertificateDer<'a> {
|
||||||
|
fn from(vec: Vec<u8>) -> Self {
|
||||||
|
Self(Der::from(vec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An abstract signature verification algorithm.
|
||||||
|
///
|
||||||
|
/// One of these is needed per supported pair of public key type (identified
|
||||||
|
/// with `public_key_alg_id()`) and `signatureAlgorithm` (identified with
|
||||||
|
/// `signature_alg_id()`). Note that both of these `AlgorithmIdentifier`s include
|
||||||
|
/// the parameters encoding, so separate `SignatureVerificationAlgorithm`s are needed
|
||||||
|
/// for each possible public key or signature parameters.
|
||||||
|
pub trait SignatureVerificationAlgorithm: Send + Sync {
|
||||||
|
/// Verify a signature.
|
||||||
|
///
|
||||||
|
/// `public_key` is the `subjectPublicKey` value from a `SubjectPublicKeyInfo` encoding
|
||||||
|
/// and is untrusted. The key's `subjectPublicKeyInfo` matches the [`AlgorithmIdentifier`]
|
||||||
|
/// returned by `public_key_alg_id()`.
|
||||||
|
///
|
||||||
|
/// `message` is the data over which the signature was allegedly computed.
|
||||||
|
/// It is not hashed; implementations of this trait function must do hashing
|
||||||
|
/// if that is required by the algorithm they implement.
|
||||||
|
///
|
||||||
|
/// `signature` is the signature allegedly over `message`.
|
||||||
|
///
|
||||||
|
/// Return `Ok(())` only if `signature` is a valid signature on `message`.
|
||||||
|
///
|
||||||
|
/// Return `Err(InvalidSignature)` if the signature is invalid, including if the `public_key`
|
||||||
|
/// encoding is invalid. There is no need or opportunity to produce errors
|
||||||
|
/// that are more specific than this.
|
||||||
|
fn verify_signature(
|
||||||
|
&self,
|
||||||
|
public_key: &[u8],
|
||||||
|
message: &[u8],
|
||||||
|
signature: &[u8],
|
||||||
|
) -> Result<(), InvalidSignature>;
|
||||||
|
|
||||||
|
/// Return the `AlgorithmIdentifier` that must equal a public key's
|
||||||
|
/// `subjectPublicKeyInfo` value for this `SignatureVerificationAlgorithm`
|
||||||
|
/// to be used for signature verification.
|
||||||
|
fn public_key_alg_id(&self) -> AlgorithmIdentifier;
|
||||||
|
|
||||||
|
/// Return the `AlgorithmIdentifier` that must equal the `signatureAlgorithm` value
|
||||||
|
/// on the data to be verified for this `SignatureVerificationAlgorithm` to be used
|
||||||
|
/// for signature verification.
|
||||||
|
fn signature_alg_id(&self) -> AlgorithmIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A detail-less error when a signature is not valid.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct InvalidSignature;
|
||||||
|
|
||||||
|
/// A DER encoding of the PKIX AlgorithmIdentifier type:
|
||||||
|
///
|
||||||
|
/// ```ASN.1
|
||||||
|
/// AlgorithmIdentifier ::= SEQUENCE {
|
||||||
|
/// algorithm OBJECT IDENTIFIER,
|
||||||
|
/// parameters ANY DEFINED BY algorithm OPTIONAL }
|
||||||
|
/// -- contains a value of the type
|
||||||
|
/// -- registered for use with the
|
||||||
|
/// -- algorithm object identifier value
|
||||||
|
/// ```
|
||||||
|
/// (from <https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.2>)
|
||||||
|
///
|
||||||
|
/// The outer sequence encoding is *not included*, so this is the DER encoding
|
||||||
|
/// of an OID for `algorithm` plus the `parameters` value.
|
||||||
|
///
|
||||||
|
/// For example, this is the `rsaEncryption` algorithm:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let rsa_encryption = rustls_pki_types::AlgorithmIdentifier::from_slice(
|
||||||
|
/// &[
|
||||||
|
/// // algorithm: 1.2.840.113549.1.1.1
|
||||||
|
/// 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
|
||||||
|
/// // parameters: NULL
|
||||||
|
/// 0x05, 0x00
|
||||||
|
/// ]
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct AlgorithmIdentifier(&'static [u8]);
|
||||||
|
|
||||||
|
impl AlgorithmIdentifier {
|
||||||
|
/// Makes a new `AlgorithmIdentifier` from a static octet slice.
|
||||||
|
///
|
||||||
|
/// This does not validate the contents of the slice.
|
||||||
|
pub const fn from_slice(bytes: &'static [u8]) -> Self {
|
||||||
|
Self(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for AlgorithmIdentifier {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for AlgorithmIdentifier {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A timestamp, tracking the number of non-leap seconds since the Unix epoch.
|
||||||
|
///
|
||||||
|
/// The Unix epoch is defined January 1, 1970 00:00:00 UTC.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
|
||||||
|
pub struct UnixTime(u64);
|
||||||
|
|
||||||
|
impl UnixTime {
|
||||||
|
/// The current time, as a `UnixTime`
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn now() -> Self {
|
||||||
|
Self::since_unix_epoch(
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.unwrap(), // Safe: this code did not exist before 1970.
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a `Duration` since the start of 1970 to a `UnixTime`
|
||||||
|
///
|
||||||
|
/// The `duration` must be relative to the Unix epoch.
|
||||||
|
pub fn since_unix_epoch(duration: Duration) -> Self {
|
||||||
|
Self(duration.as_secs())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Number of seconds since the Unix epoch
|
||||||
|
pub fn as_secs(&self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DER-encoded data, either owned or borrowed
|
||||||
|
///
|
||||||
|
/// This wrapper type is used to represent DER-encoded data in a way that is agnostic to whether
|
||||||
|
/// the data is owned (by a `Vec<u8>`) or borrowed (by a `&[u8]`). Support for the owned
|
||||||
|
/// variant is only available when the `alloc` feature is enabled.
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct Der<'a>(DerInner<'a>);
|
||||||
|
|
||||||
|
impl<'a> Der<'a> {
|
||||||
|
/// A const constructor to create a `Der` from a borrowed slice
|
||||||
|
pub const fn from_slice(der: &'a [u8]) -> Self {
|
||||||
|
Self(DerInner::Borrowed(der))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Der<'_> {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
match &self.0 {
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
DerInner::Owned(vec) => vec.as_ref(),
|
||||||
|
DerInner::Borrowed(slice) => slice,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Der<'_> {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [u8]> for Der<'a> {
|
||||||
|
fn from(slice: &'a [u8]) -> Self {
|
||||||
|
Self(DerInner::Borrowed(slice))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
impl From<Vec<u8>> for Der<'static> {
|
||||||
|
fn from(vec: Vec<u8>) -> Self {
|
||||||
|
Self(DerInner::Owned(vec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Der<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("Der")
|
||||||
|
.field(&self.as_ref())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
enum DerInner<'a> {
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
Owned(Vec<u8>),
|
||||||
|
Borrowed(&'a [u8]),
|
||||||
|
}
|
Loading…
Reference in New Issue