Skip to main content

sequoia_openpgp/parse/
mpis.rs

1//! Functions for parsing MPIs.
2
3use std::io::Read;
4use buffered_reader::BufferedReader;
5use crate::{
6    Result,
7    Error,
8    PublicKeyAlgorithm,
9    SymmetricAlgorithm,
10    HashAlgorithm,
11};
12use crate::types::Curve;
13use crate::crypto::{
14    mem::Protected,
15    mpi::{self, MPI, ProtectedMPI},
16};
17use crate::parse::{
18    PacketHeaderParser,
19    Cookie,
20};
21
22impl mpi::PublicKey {
23    /// Parses a set of OpenPGP MPIs representing a public key.
24    ///
25    /// See [Section 3.2 of RFC 9580] for details.
26    ///
27    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
28    pub fn parse<R: Read + Send + Sync>(algo: PublicKeyAlgorithm, reader: R) -> Result<Self>
29    {
30        let bio = buffered_reader::Generic::with_cookie(
31            reader, None, Cookie::default());
32        let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
33        Self::_parse(algo, &mut php)
34    }
35
36    /// Parses a set of OpenPGP MPIs representing a public key.
37    ///
38    /// See [Section 3.2 of RFC 9580] for details.
39    ///
40    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
41    pub(crate) fn _parse(
42        algo: PublicKeyAlgorithm,
43        php: &mut PacketHeaderParser<'_>)
44        -> Result<Self>
45    {
46        use crate::PublicKeyAlgorithm::*;
47
48        #[allow(deprecated)]
49        match algo {
50            RSAEncryptSign | RSAEncrypt | RSASign => {
51                let n = MPI::parse("rsa_public_n_len", "rsa_public_n", php)?;
52                let e = MPI::parse("rsa_public_e_len", "rsa_public_e", php)?;
53
54                Ok(mpi::PublicKey::RSA { e, n })
55            }
56
57            DSA => {
58                let p = MPI::parse("dsa_public_p_len", "dsa_public_p", php)?;
59                let q = MPI::parse("dsa_public_q_len", "dsa_public_q", php)?;
60                let g = MPI::parse("dsa_public_g_len", "dsa_public_g", php)?;
61                let y = MPI::parse("dsa_public_y_len", "dsa_public_y", php)?;
62
63                Ok(mpi::PublicKey::DSA {
64                    p,
65                    q,
66                    g,
67                    y,
68                })
69            }
70
71            ElGamalEncrypt | ElGamalEncryptSign => {
72                let p = MPI::parse("elgamal_public_p_len", "elgamal_public_p",
73                                   php)?;
74                let g = MPI::parse("elgamal_public_g_len", "elgamal_public_g",
75                                   php)?;
76                let y = MPI::parse("elgamal_public_y_len", "elgamal_public_y",
77                                   php)?;
78
79                Ok(mpi::PublicKey::ElGamal {
80                    p,
81                    g,
82                    y,
83                })
84            }
85
86            EdDSA => {
87                let curve_len = php.parse_u8("curve_len")? as usize;
88                let curve = php.parse_bytes("curve", curve_len)?;
89                let q = MPI::parse("eddsa_public_len", "eddsa_public", php)?;
90
91                Ok(mpi::PublicKey::EdDSA {
92                    curve: Curve::from_oid(&curve),
93                    q
94                })
95            }
96
97            ECDSA => {
98                let curve_len = php.parse_u8("curve_len")? as usize;
99                let curve = php.parse_bytes("curve", curve_len)?;
100                let q = MPI::parse("ecdsa_public_len", "ecdsa_public", php)?;
101
102                Ok(mpi::PublicKey::ECDSA {
103                    curve: Curve::from_oid(&curve),
104                    q
105                })
106            }
107
108            ECDH => {
109                let curve_len = php.parse_u8("curve_len")? as usize;
110                let curve = php.parse_bytes("curve", curve_len)?;
111                let q = MPI::parse("ecdh_public_len", "ecdh_public", php)?;
112                let kdf_len = php.parse_u8("kdf_len")?;
113
114                if kdf_len != 3 {
115                    return Err(Error::MalformedPacket(
116                            "wrong kdf length".into()).into());
117                }
118
119                let reserved = php.parse_u8("kdf_reserved")?;
120                if reserved != 1 {
121                    return Err(Error::MalformedPacket(
122                            format!("Reserved kdf field must be 0x01, \
123                                     got 0x{:x}", reserved)).into());
124                }
125                let hash: HashAlgorithm = php.parse_u8("kdf_hash")?.into();
126                let sym: SymmetricAlgorithm = php.parse_u8("kek_symm")?.into();
127
128                Ok(mpi::PublicKey::ECDH {
129                    curve: Curve::from_oid(&curve),
130                    q,
131                    hash,
132                    sym
133                })
134            }
135
136            X25519 => {
137                let mut u = [0; 32];
138                php.parse_bytes_into("x25519_public", &mut u)?;
139                Ok(mpi::PublicKey::X25519 { u })
140            },
141
142            X448 => {
143                let mut u = [0; 56];
144                php.parse_bytes_into("x448_public", &mut u)?;
145                Ok(mpi::PublicKey::X448 { u: Box::new(u) })
146            },
147
148            Ed25519 => {
149                let mut a = [0; 32];
150                php.parse_bytes_into("ed25519_public", &mut a)?;
151                Ok(mpi::PublicKey::Ed25519 { a })
152            },
153
154            Ed448 => {
155                let mut a = [0; 57];
156                php.parse_bytes_into("ed448_public", &mut a)?;
157                Ok(mpi::PublicKey::Ed448 { a: Box::new(a) })
158            },
159
160            MLDSA65_Ed25519 => Ok(mpi::PublicKey::MLDSA65_Ed25519 {
161                eddsa: {
162                    let mut a = Box::new([0; 32]);
163                    php.parse_bytes_into("ed25519_public", &mut a[..])?;
164                    a
165                },
166                mldsa: {
167                    let mut a = Box::new([0; 1952]);
168                    php.parse_bytes_into("mldsa65_public", &mut a[..])?;
169                    a
170                },
171            }),
172
173            MLDSA87_Ed448 => Ok(mpi::PublicKey::MLDSA87_Ed448 {
174                eddsa: {
175                    let mut a = Box::new([0; 57]);
176                    php.parse_bytes_into("ed448_public", &mut a[..])?;
177                    a
178                },
179                mldsa: {
180                    let mut a = Box::new([0; 2592]);
181                    php.parse_bytes_into("mldsa87_public", &mut a[..])?;
182                    a
183                },
184            }),
185
186            SLHDSA128s => Ok(mpi::PublicKey::SLHDSA128s {
187                public: {
188                    let mut a = [0; 32];
189                    php.parse_bytes_into("public", &mut a[..])?;
190                    a
191                },
192            }),
193
194            SLHDSA128f => Ok(mpi::PublicKey::SLHDSA128f {
195                public: {
196                    let mut a = [0; 32];
197                    php.parse_bytes_into("public", &mut a[..])?;
198                    a
199                },
200            }),
201
202            SLHDSA256s => Ok(mpi::PublicKey::SLHDSA256s {
203                public: {
204                    let mut a = Box::new([0; 64]);
205                    php.parse_bytes_into("public", &mut a[..])?;
206                    a
207                },
208            }),
209
210            MLKEM768_X25519 => {
211                let mut ecdh = Box::new([0; 32]);
212                php.parse_bytes_into("x25519_public", ecdh.as_mut())?;
213                let mut mlkem = Box::new([0; 1184]);
214                php.parse_bytes_into("mlkem768_public", mlkem.as_mut())?;
215                Ok(mpi::PublicKey::MLKEM768_X25519 { ecdh, mlkem })
216            },
217
218            MLKEM1024_X448 => {
219                let mut ecdh = Box::new([0; 56]);
220                php.parse_bytes_into("x448_public", ecdh.as_mut())?;
221                let mut mlkem = Box::new([0; 1568]);
222                php.parse_bytes_into("mlkem1024_public", mlkem.as_mut())?;
223                Ok(mpi::PublicKey::MLKEM1024_X448 { ecdh, mlkem })
224            },
225
226            Unknown(_) | Private(_) => {
227                let mut mpis = Vec::new();
228                while let Ok(mpi) = MPI::parse("unknown_len",
229                                               "unknown", php) {
230                    mpis.push(mpi);
231                }
232                let rest = php.parse_bytes_eof("rest")?;
233
234                Ok(mpi::PublicKey::Unknown {
235                    mpis: mpis.into_boxed_slice(),
236                    rest: rest.into_boxed_slice(),
237                })
238            }
239        }
240    }
241}
242
243impl mpi::SecretKeyMaterial {
244    /// Parses secret key MPIs for `algo` plus their SHA1 checksum.
245    ///
246    /// Fails if the checksum is wrong.
247    #[deprecated(
248        since = "1.14.0",
249        note = "Leaks secrets into the heap, use [`SecretKeyMaterial::from_bytes_with_checksum`]")]
250    pub fn parse_with_checksum<R: Read + Send + Sync>(algo: PublicKeyAlgorithm,
251                                        reader: R,
252                                        checksum: mpi::SecretKeyChecksum)
253                                        -> Result<Self> {
254        let bio = buffered_reader::Generic::with_cookie(
255            reader, None, Cookie::default());
256        let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
257        Self::_parse(algo, &mut php, Some(checksum))
258    }
259
260    /// Parses secret key MPIs for `algo` plus their SHA1 checksum.
261    ///
262    /// Fails if the checksum is wrong.
263    pub fn from_bytes_with_checksum(algo: PublicKeyAlgorithm,
264                                    bytes: &[u8],
265                                    checksum: mpi::SecretKeyChecksum)
266                                    -> Result<Self> {
267        let bio = buffered_reader::Memory::with_cookie(
268            bytes, Cookie::default());
269        let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
270        Self::_parse(algo, &mut php, Some(checksum))
271    }
272
273    /// Parses a set of OpenPGP MPIs representing a secret key.
274    ///
275    /// See [Section 3.2 of RFC 9580] for details.
276    ///
277    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
278    #[deprecated(
279        since = "1.14.0",
280        note = "Leaks secrets into the heap, use [`SecretKeyMaterial::from_bytes`]")]
281    pub fn parse<R: Read + Send + Sync>(algo: PublicKeyAlgorithm, reader: R) -> Result<Self>
282    {
283        let bio = buffered_reader::Generic::with_cookie(
284            reader, None, Cookie::default());
285        let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
286        Self::_parse(algo, &mut php, None)
287    }
288
289    /// Parses a set of OpenPGP MPIs representing a secret key.
290    ///
291    /// See [Section 3.2 of RFC 9580] for details.
292    ///
293    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
294    pub fn from_bytes(algo: PublicKeyAlgorithm, buf: &[u8]) -> Result<Self> {
295        let bio = buffered_reader::Memory::with_cookie(
296            buf, Cookie::default());
297        let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
298        Self::_parse(algo, &mut php, None)
299    }
300
301    /// Parses a set of OpenPGP MPIs representing a secret key.
302    ///
303    /// See [Section 3.2 of RFC 9580] for details.
304    ///
305    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
306    pub(crate) fn _parse(
307        algo: PublicKeyAlgorithm,
308        php: &mut PacketHeaderParser<'_>,
309        checksum: Option<mpi::SecretKeyChecksum>,
310    )
311        -> Result<Self>
312    {
313        use crate::PublicKeyAlgorithm::*;
314
315        // We want to get the data we are going to read next as raw
316        // bytes later.  To do so, we remember the cursor position now
317        // before reading the MPIs.
318        let mpis_start = php.reader.total_out();
319
320        #[allow(deprecated)]
321        let mpis: Result<Self> = match algo {
322            RSAEncryptSign | RSAEncrypt | RSASign => {
323                Ok(mpi::SecretKeyMaterial::RSA {
324                    d: ProtectedMPI::parse(
325                        "rsa_secret_d_len", "rsa_secret_d", php)?,
326                    p: ProtectedMPI::parse(
327                        "rsa_secret_p_len", "rsa_secret_p", php)?,
328                    q: ProtectedMPI::parse(
329                        "rsa_secret_q_len", "rsa_secret_q", php)?,
330                    u: ProtectedMPI::parse(
331                        "rsa_secret_u_len", "rsa_secret_u", php)?,
332                })
333            }
334
335            DSA => {
336                Ok(mpi::SecretKeyMaterial::DSA {
337                    x: ProtectedMPI::parse(
338                        "dsa_secret_len", "dsa_secret", php)?,
339                })
340            }
341
342            ElGamalEncrypt | ElGamalEncryptSign => {
343                Ok(mpi::SecretKeyMaterial::ElGamal {
344                    x: ProtectedMPI::parse(
345                        "elgamal_secret_len", "elgamal_secret", php)?,
346                })
347            }
348
349            EdDSA => {
350                Ok(mpi::SecretKeyMaterial::EdDSA {
351                    scalar: ProtectedMPI::parse(
352                        "eddsa_secret_len", "eddsa_secret", php)?,
353                })
354            }
355
356            ECDSA => {
357                Ok(mpi::SecretKeyMaterial::ECDSA {
358                    scalar: ProtectedMPI::parse(
359                        "ecdsa_secret_len", "ecdsa_secret", php)?,
360                })
361            }
362
363            ECDH => {
364                Ok(mpi::SecretKeyMaterial::ECDH {
365                    scalar: ProtectedMPI::parse(
366                        "ecdh_secret_len", "ecdh_secret", php)?,
367                })
368            }
369
370            X25519 => {
371                let mut x: Protected = vec![0; 32].into();
372                php.parse_bytes_into("x25519_secret", &mut x)?;
373                Ok(mpi::SecretKeyMaterial::X25519 { x })
374            },
375
376            X448 => {
377                let mut x: Protected = vec![0; 56].into();
378                php.parse_bytes_into("x448_secret", &mut x)?;
379                Ok(mpi::SecretKeyMaterial::X448 { x })
380            },
381
382            Ed25519 => {
383                let mut x: Protected = vec![0; 32].into();
384                php.parse_bytes_into("ed25519_secret", &mut x)?;
385                Ok(mpi::SecretKeyMaterial::Ed25519 { x })
386            },
387
388            Ed448 => {
389                let mut x: Protected = vec![0; 57].into();
390                php.parse_bytes_into("ed448_secret", &mut x)?;
391                Ok(mpi::SecretKeyMaterial::Ed448 { x })
392            },
393
394            MLDSA65_Ed25519 => {
395                let mut eddsa: Protected = vec![0; 32].into();
396                php.parse_bytes_into("ed25519_secret", &mut eddsa)?;
397                let mut mldsa: Protected = vec![0; 32].into();
398                php.parse_bytes_into("mldsa_secret", &mut mldsa)?;
399                Ok(mpi::SecretKeyMaterial::MLDSA65_Ed25519 { eddsa, mldsa })
400            },
401
402            MLDSA87_Ed448 => {
403                let mut eddsa: Protected = vec![0; 57].into();
404                php.parse_bytes_into("ed448_secret", &mut eddsa)?;
405                let mut mldsa: Protected = vec![0; 32].into();
406                php.parse_bytes_into("mldsa_secret", &mut mldsa)?;
407                Ok(mpi::SecretKeyMaterial::MLDSA87_Ed448 { eddsa, mldsa })
408            },
409
410            SLHDSA128s => Ok(mpi::SecretKeyMaterial::SLHDSA128s {
411                secret: {
412                    let mut a: Protected = vec![0; 64].into();
413                    php.parse_bytes_into("secret", &mut a[..])?;
414                    a
415                },
416            }),
417
418            SLHDSA128f => Ok(mpi::SecretKeyMaterial::SLHDSA128f {
419                secret: {
420                    let mut a: Protected = vec![0; 64].into();
421                    php.parse_bytes_into("secret", &mut a[..])?;
422                    a
423                },
424            }),
425
426            SLHDSA256s => Ok(mpi::SecretKeyMaterial::SLHDSA256s {
427                secret: {
428                    let mut a: Protected = vec![0; 128].into();
429                    php.parse_bytes_into("secret", &mut a[..])?;
430                    a
431                },
432            }),
433
434            MLKEM768_X25519 => {
435                let mut ecdh: Protected = vec![0; 32].into();
436                php.parse_bytes_into("x25519_secret", &mut ecdh)?;
437                let mut mlkem: Protected = vec![0; 64].into();
438                php.parse_bytes_into("mlkem_secret", &mut mlkem)?;
439                Ok(mpi::SecretKeyMaterial::MLKEM768_X25519 { ecdh, mlkem })
440            },
441
442            MLKEM1024_X448 => {
443                let mut ecdh: Protected = vec![0; 56].into();
444                php.parse_bytes_into("x448_secret", &mut ecdh)?;
445                let mut mlkem: Protected = vec![0; 64].into();
446                php.parse_bytes_into("mlkem_secret", &mut mlkem)?;
447                Ok(mpi::SecretKeyMaterial::MLKEM1024_X448 { ecdh, mlkem })
448            },
449
450            Unknown(_) | Private(_) => {
451                let mut mpis = Vec::new();
452                while let Ok(mpi) = ProtectedMPI::parse("unknown_len",
453                                               "unknown", php) {
454                    mpis.push(mpi);
455                }
456                let rest = php.parse_bytes_eof("rest")?;
457
458                Ok(mpi::SecretKeyMaterial::Unknown {
459                    mpis: mpis.into_boxed_slice(),
460                    rest: rest.into(),
461                })
462            }
463        };
464        let mpis = mpis?;
465
466        if let Some(checksum) = checksum {
467            // We want to get the data we are going to read next as
468            // raw bytes later.  To do so, we remember the cursor
469            // position now after reading the MPIs and compute the
470            // length.
471            let mpis_len = php.reader.total_out() - mpis_start;
472
473            // We do a bit of acrobatics to avoid copying the secrets.
474            // We read the checksum now, so that we can freely
475            // manipulate the Dup reader and get a borrow of the raw
476            // MPIs.
477            let their_chksum = php.parse_bytes("checksum", checksum.len())?;
478
479            // Remember how much we read in total for a sanity check.
480            let total_out = php.reader.total_out();
481
482            // Now get the secrets as raw byte slice.
483            php.reader.rewind();
484            php.reader.consume(mpis_start);
485            let data = &php.reader.data_consume_hard(mpis_len)?[..mpis_len];
486
487            let good = match checksum {
488                mpi::SecretKeyChecksum::SHA1 => {
489                    // Compute SHA1 hash.
490                    let mut hsh = HashAlgorithm::SHA1.context().unwrap()
491                        .for_digest();
492                    hsh.update(data);
493                    let mut our_chksum = [0u8; 20];
494                    let _ = hsh.digest(&mut our_chksum);
495
496                    our_chksum == their_chksum[..]
497                },
498
499                mpi::SecretKeyChecksum::Sum16 => {
500                    // Compute sum.
501                    let our_chksum = data.iter()
502                        .fold(0u16, |acc, v| acc.wrapping_add(*v as u16))
503                        .to_be_bytes();
504
505                    our_chksum == their_chksum[..]
506                },
507            };
508
509            // Finally, consume the checksum to fix the state of the
510            // Dup reader.
511            php.reader.consume(checksum.len());
512
513            // See if we got the state right.
514            debug_assert_eq!(total_out, php.reader.total_out());
515
516            if good {
517                Ok(mpis)
518            } else {
519                Err(Error::MalformedMPI("checksum wrong".to_string()).into())
520            }
521        } else {
522            Ok(mpis)
523        }
524    }
525}
526
527impl mpi::Ciphertext {
528    /// Parses a set of OpenPGP MPIs representing a ciphertext.
529    ///
530    /// Expects MPIs for a public key algorithm `algo`s ciphertext.
531    /// See [Section 3.2 of RFC 9580] for details.
532    ///
533    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
534    pub fn parse<R: Read + Send + Sync>(algo: PublicKeyAlgorithm, reader: R) -> Result<Self>
535    {
536        let bio = buffered_reader::Generic::with_cookie(
537            reader, None, Cookie::default());
538        let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
539        Self::_parse(algo, &mut php)
540    }
541
542    /// Parses a set of OpenPGP MPIs representing a ciphertext.
543    ///
544    /// Expects MPIs for a public key algorithm `algo`s ciphertext.
545    /// See [Section 3.2 of RFC 9580] for details.
546    ///
547    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
548    pub(crate) fn _parse(
549        algo: PublicKeyAlgorithm,
550        php: &mut PacketHeaderParser<'_>)
551        -> Result<Self> {
552        use crate::PublicKeyAlgorithm::*;
553
554        #[allow(deprecated)]
555        match algo {
556            RSAEncryptSign | RSAEncrypt => {
557                let c = MPI::parse("rsa_ciphertxt_len", "rsa_ciphertxt",
558                                   php)?;
559
560                Ok(mpi::Ciphertext::RSA {
561                    c,
562                })
563            }
564
565            ElGamalEncrypt | ElGamalEncryptSign => {
566                let e = MPI::parse("elgamal_e_len", "elgamal_e", php)?;
567                let c = MPI::parse("elgamal_c_len", "elgamal_c", php)?;
568
569                Ok(mpi::Ciphertext::ElGamal {
570                    e,
571                    c,
572                })
573            }
574
575            ECDH => {
576                let e = MPI::parse("ecdh_e_len", "ecdh_e", php)?;
577                let key_len = php.parse_u8("ecdh_esk_len")? as usize;
578                let key = Vec::from(&php.parse_bytes("ecdh_esk", key_len)?
579                                    [..key_len]);
580
581                Ok(mpi::Ciphertext::ECDH {
582                    e, key: key.into_boxed_slice()
583                })
584            }
585
586            X25519 => {
587                let mut e = [0; 32];
588                php.parse_bytes_into("x25519_e", &mut e)?;
589                let key_len = php.parse_u8("x25519_esk_len")? as usize;
590                let key = Vec::from(&php.parse_bytes("x25519_esk", key_len)?
591                                    [..key_len]);
592                Ok(mpi::Ciphertext::X25519 { e: Box::new(e), key: key.into() })
593            },
594
595            X448 => {
596                let mut e = [0; 56];
597                php.parse_bytes_into("x448_e", &mut e)?;
598                let key_len = php.parse_u8("x448_esk_len")? as usize;
599                let key = Vec::from(&php.parse_bytes("x448_esk", key_len)?
600                                    [..key_len]);
601                Ok(mpi::Ciphertext::X448 { e: Box::new(e), key: key.into() })
602            },
603
604            MLKEM768_X25519 => {
605                let mut ecdh = Box::new([0; 32]);
606                php.parse_bytes_into("x25519_ciphertext", ecdh.as_mut())?;
607                let mut mlkem = Box::new([0; 1088]);
608                php.parse_bytes_into("mlkem768_ciphertext", mlkem.as_mut())?;
609                let esk_len = php.parse_u8("esk_len")? as usize;
610                let esk = Vec::from(&php.parse_bytes("esk", esk_len)?
611                                    [..esk_len]).into();
612                Ok(mpi::Ciphertext::MLKEM768_X25519 { ecdh, mlkem, esk })
613            },
614
615            MLKEM1024_X448 => {
616                let mut ecdh = Box::new([0; 56]);
617                php.parse_bytes_into("x448_ciphertext", ecdh.as_mut())?;
618                let mut mlkem = Box::new([0; 1568]);
619                php.parse_bytes_into("mlkem1024_ciphertext", mlkem.as_mut())?;
620                let esk_len = php.parse_u8("esk_len")? as usize;
621                let esk = Vec::from(&php.parse_bytes("esk", esk_len)?
622                                    [..esk_len]).into();
623                Ok(mpi::Ciphertext::MLKEM1024_X448 { ecdh, mlkem, esk })
624            },
625
626            Unknown(_) | Private(_) => {
627                let mut mpis = Vec::new();
628                while let Ok(mpi) = MPI::parse("unknown_len",
629                                               "unknown", php) {
630                    mpis.push(mpi);
631                }
632                let rest = php.parse_bytes_eof("rest")?;
633
634                Ok(mpi::Ciphertext::Unknown {
635                    mpis: mpis.into_boxed_slice(),
636                    rest: rest.into_boxed_slice(),
637                })
638            }
639
640            RSASign | DSA | EdDSA | ECDSA | Ed25519 | Ed448
641                | MLDSA65_Ed25519 | MLDSA87_Ed448
642                | SLHDSA128s | SLHDSA128f | SLHDSA256s
643                => Err(Error::InvalidArgument(
644                    format!("not an encryption algorithm: {:?}", algo)).into()),
645        }
646    }
647}
648
649impl mpi::Signature {
650    /// Parses a set of OpenPGP MPIs representing a signature.
651    ///
652    /// Expects MPIs for a public key algorithm `algo`s signature.
653    /// See [Section 3.2 of RFC 9580] for details.
654    ///
655    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
656    pub fn parse<R: Read + Send + Sync>(algo: PublicKeyAlgorithm, reader: R) -> Result<Self>
657    {
658        let bio = buffered_reader::Generic::with_cookie(
659            reader, None, Cookie::default());
660        let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
661        Self::_parse(algo, &mut php)
662    }
663
664    /// Parses a set of OpenPGP MPIs representing a signature.
665    ///
666    /// Expects MPIs for a public key algorithm `algo`s signature.
667    /// See [Section 3.2 of RFC 9580] for details.
668    ///
669    ///   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
670    pub(crate) fn _parse(
671        algo: PublicKeyAlgorithm,
672        php: &mut PacketHeaderParser<'_>)
673        -> Result<Self> {
674        use crate::PublicKeyAlgorithm::*;
675
676        #[allow(deprecated)]
677        match algo {
678            RSAEncryptSign | RSASign => {
679                let s = MPI::parse("rsa_signature_len", "rsa_signature", php)?;
680
681                Ok(mpi::Signature::RSA {
682                    s,
683                })
684            }
685
686            DSA => {
687                let r = MPI::parse("dsa_sig_r_len", "dsa_sig_r",
688                                   php)?;
689                let s = MPI::parse("dsa_sig_s_len", "dsa_sig_s",
690                                   php)?;
691
692                Ok(mpi::Signature::DSA {
693                    r,
694                    s,
695                })
696            }
697
698            ElGamalEncryptSign => {
699                let r = MPI::parse("elgamal_sig_r_len",
700                                   "elgamal_sig_r", php)?;
701                let s = MPI::parse("elgamal_sig_s_len",
702                                   "elgamal_sig_s", php)?;
703
704                Ok(mpi::Signature::ElGamal {
705                    r,
706                    s,
707                })
708            }
709
710            EdDSA => {
711                let r = MPI::parse("eddsa_sig_r_len", "eddsa_sig_r",
712                                   php)?;
713                let s = MPI::parse("eddsa_sig_s_len", "eddsa_sig_s",
714                                   php)?;
715
716                Ok(mpi::Signature::EdDSA {
717                    r,
718                    s,
719                })
720            }
721
722            ECDSA => {
723                let r = MPI::parse("ecdsa_sig_r_len", "ecdsa_sig_r",
724                                   php)?;
725                let s = MPI::parse("ecdsa_sig_s_len", "ecdsa_sig_s",
726                                   php)?;
727
728                Ok(mpi::Signature::ECDSA {
729                    r,
730                    s,
731                })
732            }
733
734            Ed25519 => {
735                let mut s = [0; 64];
736                php.parse_bytes_into("ed25519_sig", &mut s)?;
737                Ok(mpi::Signature::Ed25519 { s: Box::new(s) })
738            },
739
740            Ed448 => {
741                let mut s = [0; 114];
742                php.parse_bytes_into("ed448_sig", &mut s)?;
743                Ok(mpi::Signature::Ed448 { s: Box::new(s) })
744            },
745
746            MLDSA65_Ed25519 => Ok(mpi::Signature::MLDSA65_Ed25519 {
747                eddsa: {
748                    let mut s = Box::new([0; 64]);
749                    php.parse_bytes_into("ed25519_sig", &mut s[..])?;
750                    s
751                },
752                mldsa: {
753                    let mut s = Box::new([0; 3309]);
754                    php.parse_bytes_into("mldsa65_sig", &mut s[..])?;
755                    s
756                },
757            }),
758
759            MLDSA87_Ed448 => Ok(mpi::Signature::MLDSA87_Ed448 {
760                eddsa: {
761                    let mut s = Box::new([0; 114]);
762                    php.parse_bytes_into("ed448_sig", &mut s[..])?;
763                    s
764                },
765                mldsa: {
766                    let mut s = Box::new([0; 4627]);
767                    php.parse_bytes_into("mldsa87_sig", &mut s[..])?;
768                    s
769                },
770            }),
771
772            SLHDSA128s => Ok(mpi::Signature::SLHDSA128s {
773                sig: {
774                    let mut a = Box::new([0; 7856]);
775                    php.parse_bytes_into("sig", &mut a[..])?;
776                    a
777                },
778            }),
779
780            SLHDSA128f => Ok(mpi::Signature::SLHDSA128f {
781                sig: {
782                    let mut a = Box::new([0; 17088]);
783                    php.parse_bytes_into("sig", &mut a[..])?;
784                    a
785                },
786            }),
787
788            SLHDSA256s => Ok(mpi::Signature::SLHDSA256s {
789                sig: {
790                    let mut a = Box::new([0; 29792]);
791                    php.parse_bytes_into("sig", &mut a[..])?;
792                    a
793                },
794            }),
795
796            Unknown(_) | Private(_) => {
797                let mut mpis = Vec::new();
798                while let Ok(mpi) = MPI::parse("unknown_len",
799                                               "unknown", php) {
800                    mpis.push(mpi);
801                }
802                let rest = php.parse_bytes_eof("rest")?;
803
804                Ok(mpi::Signature::Unknown {
805                    mpis: mpis.into_boxed_slice(),
806                    rest: rest.into_boxed_slice(),
807                })
808            }
809
810            RSAEncrypt | ElGamalEncrypt | ECDH | X25519 | X448
811                | MLKEM768_X25519
812                | MLKEM1024_X448
813                => Err(Error::InvalidArgument(
814                    format!("not a signature algorithm: {:?}", algo)).into()),
815        }
816    }
817}
818
819#[test]
820fn mpis_parse_test() {
821    use std::io::Cursor;
822    use super::Parse;
823    use crate::PublicKeyAlgorithm::*;
824    use crate::serialize::MarshalInto;
825
826    // Dummy RSA public key.
827    {
828        let buf = Cursor::new("\x00\x01\x01\x00\x02\x02");
829        let mpis = mpi::PublicKey::parse(RSAEncryptSign, buf).unwrap();
830
831        //assert_eq!(mpis.serialized_len(), 6);
832        match &mpis {
833            &mpi::PublicKey::RSA{ ref n, ref e } => {
834                assert_eq!(n.bits(), 1);
835                assert_eq!(n.value()[0], 1);
836                assert_eq!(n.value().len(), 1);
837                assert_eq!(e.bits(), 2);
838                assert_eq!(e.value()[0], 2);
839                assert_eq!(e.value().len(), 1);
840            }
841
842            _ => assert!(false),
843        }
844    }
845
846    // The number 2.
847    {
848        let buf = Cursor::new("\x00\x02\x02");
849        let mpis = mpi::Ciphertext::parse(RSAEncryptSign, buf).unwrap();
850
851        assert_eq!(mpis.serialized_len(), 3);
852    }
853
854    // The number 511.
855    let mpi = MPI::from_bytes(b"\x00\x09\x01\xff").unwrap();
856    assert_eq!(mpi.value().len(), 2);
857    assert_eq!(mpi.bits(), 9);
858    assert_eq!(mpi.value()[0], 1);
859    assert_eq!(mpi.value()[1], 0xff);
860
861    // The number 1, incorrectly encoded (the length should be 1,
862    // not 2).
863    assert!(MPI::from_bytes(b"\x00\x02\x01").is_err());
864}