1 //! Digest algorithm and operations.
2 
3 use std::io;
4 use std::io::Read;
5 use std::fs::File;
6 use std::path::Path;
7 use ring::digest;
8 use bcder::{decode, encode};
9 use bcder::encode::PrimitiveContent;
10 use bcder::Tag;
11 use super::super::oid;
12 
13 // Re-export the things from ring for actual digest generation.
14 pub use ring::digest::Digest;
15 
16 
17 //------------ DigestAlgorithm -----------------------------------------------
18 
19 /// The digest algorithms used by RPKI.
20 ///
21 /// These are the algorithms used by the signature algorithms. For use in
22 /// RPKI, [RFC 7935] limits them to exactly one, SHA-256. Because of
23 /// that, this type is currently a zero-sized struct. If additional
24 /// algorithms are ever introduced in the future, it will change into an enum.
25 ///
26 /// [RFC 7935]: https://tools.ietf.org/html/rfc7935
27 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
28 pub struct DigestAlgorithm(());
29 
30 impl DigestAlgorithm {
31     /// Creates a value representing the SHA-256 algorithm.
sha256() -> Self32     pub fn sha256() -> Self {
33         DigestAlgorithm(())
34     }
35 
36     /// Returns whether the algorithm is in fact SHA-256.
is_sha256(self) -> bool37     pub fn is_sha256(self) -> bool {
38         true
39     }
40 
41     /// Returns the digest size in octets for this algorithm.
digest_len(&self) -> usize42     pub fn digest_len(&self) -> usize {
43         32
44     }
45 }
46 
47 /// # Creating Digest Values
48 ///
49 impl DigestAlgorithm {
50     /// Returns the digest of `data` using this algorithm.
digest(self, data: &[u8]) -> Digest51     pub fn digest(self, data: &[u8]) -> Digest {
52         digest::digest(&digest::SHA256, data)
53     }
54 
55     /// Calculates the digest for the content of a file.
digest_file( self, path: impl AsRef<Path> ) -> Result<Digest, io::Error>56     pub fn digest_file(
57         self, path: impl AsRef<Path>
58     ) -> Result<Digest, io::Error> {
59         let mut file = File::open(path)?;
60         let mut buf = [0u8; 8 * 1024];
61         let mut ctx = self.start();
62         loop {
63             let read = file.read(&mut buf)?;
64             if read == 0 {
65                 break;
66             }
67             ctx.update(&buf[..read]);
68         }
69         Ok(ctx.finish())
70     }
71 
72     /// Returns a digest context for multi-step calculation of the digest.
start(self) -> Context73     pub fn start(self) -> Context {
74         Context(digest::Context::new(&digest::SHA256))
75     }
76 }
77 
78 
79 /// # ASN.1 Values
80 ///
81 /// Digest algorithms appear in CMS either alone or in sets with the following
82 /// syntax:
83 ///
84 /// ```txt
85 /// DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
86 /// DigestAlgorithmIdentifier  ::= AlgorithmIdentifier
87 /// AlgorithmIdentifier        ::= SEQUENCE {
88 ///      algorithm                 OBJECT IDENTIFIER,
89 ///      parameters                ANY DEFINED BY algorithm OPTIONAL }
90 /// ```
91 ///
92 /// In RPKI signed objects, a set is limited to exactly one identifer. The
93 /// allowed algorithms are limited, too. In particular, [RFC 7935] only
94 /// allows SHA-256. Its algorithm identifier is defined in [RFC 5754]. The
95 /// object identifier to be used is `id-sha256`. When encoding, the
96 /// _parameters_ field must be absent, whereas when decoding, it may either
97 /// be absent or `NULL`.
98 ///
99 /// Note that this differs from [`SignatureAlgorithm`] identifiers where
100 /// the `NULL` must be present when encoding.
101 ///
102 /// The functions and methods in this section allow decoding and encoding
103 /// such values.
104 ///
105 /// [`SignatureAlgorithm`]: ../signature/struct.SignatureAlgorithm.html
106 /// [RFC 5754]: https://tools.ietf.org/html/rfc5754
107 /// [RFC 7935]: https://tools.ietf.org/html/rfc7935
108 impl DigestAlgorithm {
109     /// Takes and returns a single digest algorithm identifier.
110     ///
111     /// Returns a malformed error if the algorithm isn’t one of the allowed
112     /// algorithms or if the value isn’t correctly encoded.
take_from<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Self, S::Err>113     pub fn take_from<S: decode::Source>(
114         cons: &mut decode::Constructed<S>
115     ) -> Result<Self, S::Err> {
116         cons.take_sequence(Self::from_constructed)
117     }
118 
119     /// Takes and returns an optional digest algorithm identifier.
120     ///
121     /// Returns `Ok(None)` if the next value isn’t a sequence.
122     /// Returns a malformed error if the sequence isn’t a correctly encoded
123     /// algorithm identifier or if algorithm isn’t one of the allowed
124     /// algorithms.
take_opt_from<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Option<Self>, S::Err>125     pub fn take_opt_from<S: decode::Source>(
126         cons: &mut decode::Constructed<S>
127     ) -> Result<Option<Self>, S::Err> {
128         cons.take_opt_sequence(Self::from_constructed)
129     }
130 
131     /// Takes and returns a set of digest algorithm identifiers.
132     ///
133     /// The set must contain exactly one identifier as required everywhere for
134     /// RPKI. If it contains more than one or identifiers that are not
135     /// allowed, a malformed error is returned.
take_set_from<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Self, S::Err>136     pub fn take_set_from<S: decode::Source>(
137         cons: &mut decode::Constructed<S>
138     ) -> Result<Self, S::Err> {
139         cons.take_set(Self::take_from)
140     }
141 
142     /// Parses the algorithm identifier from the contents of its sequence.
from_constructed<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Self, S::Err>143     fn from_constructed<S: decode::Source>(
144         cons: &mut decode::Constructed<S>
145     ) -> Result<Self, S::Err> {
146         oid::SHA256.skip_if(cons)?;
147         cons.take_opt_null()?;
148         Ok(DigestAlgorithm::default())
149     }
150 
151     /// Parses a SET OF DigestAlgorithmIdentifiers.
152     ///
153     /// This is used in the digestAlgorithms field of the SignedData
154     /// container. It provides all the digest algorithms used later on, so
155     /// that the data can be read over. We don’t really need this, so this
156     /// function returns `()` on success.
157     ///
158     /// Section 2.1.2. of RFC 6488 requires there to be exactly one element
159     /// chosen from the allowed values.
skip_set<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<(), S::Err>160     pub fn skip_set<S: decode::Source>(
161         cons: &mut decode::Constructed<S>
162     ) -> Result<(), S::Err> {
163         cons.take_constructed_if(Tag::SET, |cons| {
164             while Self::take_opt_from(cons)?.is_some() { }
165             Ok(())
166         })
167     }
168 
169     /// Takes a single algorithm object identifier from a constructed value.
take_oid_from<S: decode::Source>( cons: &mut decode::Constructed<S>, ) -> Result<Self, S::Err>170     pub fn take_oid_from<S: decode::Source>(
171         cons: &mut decode::Constructed<S>,
172     ) -> Result<Self, S::Err> {
173         oid::SHA256.skip_if(cons)?;
174         Ok(Self::default())
175     }
176 
177     /// Provides an encoder for a single algorithm identifier.
encode(self) -> impl encode::Values178     pub fn encode(self) -> impl encode::Values {
179         encode::sequence(oid::SHA256.encode())
180     }
181 
182     /// Provides an encoder for a indentifer as the sole value of a set.
encode_set(self) -> impl encode::Values183     pub fn encode_set(self) -> impl encode::Values {
184         encode::set(
185             self.encode()
186         )
187     }
188 
189     /// Provides an encoder for just the object identifier of the algorithm.
encode_oid(self) -> impl encode::Values190     pub fn encode_oid(self) -> impl encode::Values {
191         oid::SHA256.encode()
192     }
193 }
194 
195 
196 //------------ Sha1 ----------------------------------------------------------
197 
sha1_digest(data: &[u8]) -> Digest198 pub fn sha1_digest(data: &[u8]) -> Digest {
199     digest::digest(&digest::SHA1_FOR_LEGACY_USE_ONLY, data)
200 }
201 
start_sha1() -> Context202 pub fn start_sha1() -> Context {
203     Context(digest::Context::new(&digest::SHA1_FOR_LEGACY_USE_ONLY))
204 }
205 
206 
207 //------------ Context -------------------------------------------------------
208 
209 #[derive(Clone)]
210 pub struct Context(digest::Context);
211 
212 impl Context {
update(&mut self, data: &[u8])213     pub fn update(&mut self, data: &[u8]) {
214         self.0.update(data)
215     }
216 
finish(self) -> Digest217     pub fn finish(self) -> Digest {
218         self.0.finish()
219     }
220 }
221 
222 impl io::Write for Context {
write(&mut self, buf: &[u8]) -> Result<usize, io::Error>223     fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
224         self.update(buf);
225         Ok(buf.len())
226     }
227 
flush(&mut self) -> Result<(), io::Error>228     fn flush(&mut self) -> Result<(), io::Error> {
229         Ok(())
230     }
231 }
232 
233