#![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] #![deny(unsafe_code)] #![warn( clippy::integer_arithmetic, clippy::mod_module_files, clippy::panic, clippy::panic_in_result_fn, clippy::unwrap_used, missing_docs, rust_2018_idioms, unused_lifetimes, unused_qualifications )] //! # Usage //! #![cfg_attr(feature = "std", doc = " ```")] #![cfg_attr(not(feature = "std"), doc = " ```ignore")] //! # fn main() -> Result<(), Box> { //! /// Example PEM document //! /// NOTE: do not actually put private key literals into your source code!!! //! let example_pem = "\ //! -----BEGIN PRIVATE KEY----- //! MC4CAQAwBQYDK2VwBCIEIBftnHPp22SewYmmEoMcX8VwI4IHwaqd+9LFPj/15eqF //! -----END PRIVATE KEY----- //! "; //! //! // Decode PEM //! let (type_label, data) = pem_rfc7468::decode_vec(example_pem.as_bytes())?; //! assert_eq!(type_label, "PRIVATE KEY"); //! assert_eq!( //! data, //! &[ //! 48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 23, 237, 156, 115, 233, 219, //! 100, 158, 193, 137, 166, 18, 131, 28, 95, 197, 112, 35, 130, 7, 193, 170, 157, 251, //! 210, 197, 62, 63, 245, 229, 234, 133 //! ] //! ); //! //! // Encode PEM //! use pem_rfc7468::LineEnding; //! let encoded_pem = pem_rfc7468::encode_string(type_label, LineEnding::default(), &data)?; //! assert_eq!(&encoded_pem, example_pem); //! # Ok(()) //! # } //! ``` #[cfg(feature = "alloc")] #[macro_use] extern crate alloc; #[cfg(feature = "std")] extern crate std; mod decoder; mod encoder; mod error; mod grammar; pub use crate::{ decoder::{decode, decode_label, Decoder}, encoder::{encapsulated_len, encapsulated_len_wrapped, encode, encoded_len, Encoder}, error::{Error, Result}, }; pub use base64ct::LineEnding; #[cfg(feature = "alloc")] pub use crate::{decoder::decode_vec, encoder::encode_string}; /// The pre-encapsulation boundary appears before the encapsulated text. /// /// From RFC 7468 Section 2: /// > There are exactly five hyphen-minus (also known as dash) characters ("-") /// > on both ends of the encapsulation boundaries, no more, no less. const PRE_ENCAPSULATION_BOUNDARY: &[u8] = b"-----BEGIN "; /// The post-encapsulation boundary appears immediately after the encapsulated text. const POST_ENCAPSULATION_BOUNDARY: &[u8] = b"-----END "; /// Delimiter of encapsulation boundaries. const ENCAPSULATION_BOUNDARY_DELIMITER: &[u8] = b"-----"; /// Width at which the Base64 body of RFC7468-compliant PEM is wrapped. /// /// From [RFC7468 § 2]: /// /// > Generators MUST wrap the base64-encoded lines so that each line /// > consists of exactly 64 characters except for the final line, which /// > will encode the remainder of the data (within the 64-character line /// > boundary), and they MUST NOT emit extraneous whitespace. Parsers MAY /// > handle other line sizes. /// /// [RFC7468 § 2]: https://datatracker.ietf.org/doc/html/rfc7468#section-2 pub const BASE64_WRAP_WIDTH: usize = 64; /// Buffered Base64 decoder type. pub type Base64Decoder<'i> = base64ct::Decoder<'i, base64ct::Base64>; /// Buffered Base64 encoder type. pub type Base64Encoder<'o> = base64ct::Encoder<'o, base64ct::Base64>; /// Marker trait for types with an associated PEM type label. pub trait PemLabel { /// Expected PEM type label for a given document, e.g. `"PRIVATE KEY"` const PEM_LABEL: &'static str; /// Validate that a given label matches the expected label. fn validate_pem_label(actual: &str) -> Result<()> { if Self::PEM_LABEL == actual { Ok(()) } else { Err(Error::UnexpectedTypeLabel { expected: Self::PEM_LABEL, }) } } }