|
3 | 3 | use crate::{Encoder, Header, Length, Result, Tagged, Writer}; |
4 | 4 |
|
5 | 5 | #[cfg(feature = "alloc")] |
6 | | -use {crate::ErrorKind, alloc::vec::Vec, core::iter}; |
| 6 | +use {alloc::vec::Vec, core::iter}; |
7 | 7 |
|
8 | 8 | #[cfg(feature = "pem")] |
9 | 9 | use { |
| 10 | + crate::PemWriter, |
10 | 11 | alloc::string::String, |
11 | 12 | pem_rfc7468::{self as pem, LineEnding, PemLabel}, |
12 | | - zeroize::Zeroizing, |
13 | 13 | }; |
14 | 14 |
|
| 15 | +#[cfg(any(feature = "alloc", feature = "pem"))] |
| 16 | +use crate::ErrorKind; |
| 17 | + |
15 | 18 | #[cfg(doc)] |
16 | 19 | use crate::Tag; |
17 | 20 |
|
@@ -95,10 +98,30 @@ pub trait EncodePem: Encode + PemLabel { |
95 | 98 | #[cfg(feature = "pem")] |
96 | 99 | #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] |
97 | 100 | impl<T: Encode + PemLabel> EncodePem for T { |
| 101 | + #[allow(clippy::integer_arithmetic)] |
98 | 102 | fn to_pem(&self, line_ending: LineEnding) -> Result<String> { |
99 | | - // TODO(tarcieri): support for encoding directly from PEM (instead of two-pass) |
100 | | - let der = Zeroizing::new(self.to_vec()?); |
101 | | - Ok(pem::encode_string(Self::PEM_LABEL, line_ending, &der)?) |
| 103 | + // TODO(tarcieri): checked arithmetic, maybe extract this into `base64ct::base64_len`? |
| 104 | + let der_len = usize::try_from(self.encoded_len()?)?; |
| 105 | + let mut base64_len = (((der_len * 4) / 3) + 3) & !3; |
| 106 | + |
| 107 | + // Add the length of the line endings which will be inserted when |
| 108 | + // encoded Base64 is line wrapped |
| 109 | + // TODO(tarcieri): factor this logic into `pem-rfc7468` |
| 110 | + base64_len += base64_len |
| 111 | + .saturating_sub(1) |
| 112 | + .checked_div(64) |
| 113 | + .and_then(|len| len.checked_add(line_ending.len())) |
| 114 | + .ok_or(ErrorKind::Overflow)?; |
| 115 | + |
| 116 | + let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, base64_len)?; |
| 117 | + |
| 118 | + let mut buf = vec![0u8; pem_len]; |
| 119 | + let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?; |
| 120 | + self.encode(&mut writer)?; |
| 121 | + |
| 122 | + let actual_len = writer.finish()?; |
| 123 | + buf.truncate(actual_len); |
| 124 | + Ok(String::from_utf8(buf)?) |
102 | 125 | } |
103 | 126 | } |
104 | 127 |
|
|
0 commit comments