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