Commit
Author: Mauro D [mauro@stalw.art]
Committer: GitHub [noreply@github.com] Fri, 14 Apr 2023 11:03:46 +0000
Hash: eb20e4161937da20c58d238b4436a429ae0039ad
Timestamp: Fri, 14 Apr 2023 11:03:46 +0000 (1 year ago)

+24 -21 +/-2 browse
Merge pull request #17 from InstantDomain/no-rsa-key-panic
Merge pull request #17 from InstantDomain/no-rsa-key-panic

Avoid panicking on invalid RSA key input
1diff --git a/fuzz/fuzz_targets/mail_auth.rs b/fuzz/fuzz_targets/mail_auth.rs
2index 214ff0b..0c6bb02 100644
3--- a/fuzz/fuzz_targets/mail_auth.rs
4+++ b/fuzz/fuzz_targets/mail_auth.rs
5 @@ -14,7 +14,8 @@ use libfuzzer_sys::fuzz_target;
6 use mail_auth::{
7 arc,
8 common::parse::TxtRecordParser,
9- dkim::{self, Atps, DomainKey, DomainKeyReport},
10+ common::verify::DomainKey,
11+ dkim::{self, Atps, DomainKeyReport},
12 dmarc::Dmarc,
13 report::{Feedback, Report},
14 spf::{Macro, Spf},
15 diff --git a/src/common/crypto/ring_impls.rs b/src/common/crypto/ring_impls.rs
16index 284bf1c..dd93c41 100644
17--- a/src/common/crypto/ring_impls.rs
18+++ b/src/common/crypto/ring_impls.rs
19 @@ -139,7 +139,7 @@ impl RsaPublicKey {
20 pub(crate) fn verifying_key_from_bytes(
21 bytes: &[u8],
22 ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
23- let key = try_strip_rsa_prefix(bytes);
24+ let key = try_strip_rsa_prefix(bytes).unwrap_or(bytes);
25 Ok(Box::new(Self {
26 sha1: UnparsedPublicKey::new(
27 &RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
28 @@ -156,43 +156,45 @@ impl RsaPublicKey {
29 /// Try to strip an ASN.1 DER-encoded RSA public key prefix
30 ///
31 /// Returns the original slice if the prefix is not found.
32- fn try_strip_rsa_prefix(bytes: &[u8]) -> &[u8] {
33- let orig = bytes;
34- if bytes[0] != DER_SEQUENCE_TAG {
35- return orig;
36+ fn try_strip_rsa_prefix(bytes: &[u8]) -> Option<&[u8]> {
37+ if *bytes.first()? != DER_SEQUENCE_TAG {
38+ return None;
39 }
40
41- let (_, bytes) = decode_multi_byte_len(&bytes[1..]);
42- if bytes[0] != DER_SEQUENCE_TAG {
43- return orig;
44+ let (_, bytes) = decode_multi_byte_len(&bytes[1..])?;
45+ if *bytes.first()? != DER_SEQUENCE_TAG {
46+ return None;
47 }
48
49- let (byte_len, bytes) = decode_multi_byte_len(&bytes[1..]);
50- if bytes[0] != DER_OBJECT_ID_TAG || byte_len != 13 {
51- return orig;
52+ let (byte_len, bytes) = decode_multi_byte_len(&bytes[1..])?;
53+ if *bytes.first()? != DER_OBJECT_ID_TAG || byte_len != 13 {
54+ return None;
55 }
56
57- let bytes = &bytes[13..]; // skip the RSA encryption OID
58- if bytes[0] != DER_BIT_STRING_TAG {
59- return orig;
60+ let bytes = bytes.get(13..)?; // skip the RSA encryption OID
61+ if *bytes.first()? != DER_BIT_STRING_TAG {
62+ return None;
63 }
64
65- let (_, bytes) = decode_multi_byte_len(&bytes[1..]);
66- &bytes[1..] // skip the unused bits byte
67+ decode_multi_byte_len(&bytes[1..]).and_then(|(_, bytes)| bytes.get(1..)) // skip the unused bits byte
68 }
69
70- fn decode_multi_byte_len(bytes: &[u8]) -> (usize, &[u8]) {
71- if bytes[0] & 0x80 == 0 {
72- return (bytes[0] as usize, &bytes[1..]);
73+ fn decode_multi_byte_len(bytes: &[u8]) -> Option<(usize, &[u8])> {
74+ if bytes.first()? & 0x80 == 0 {
75+ return Some((bytes[0] as usize, &bytes[1..]));
76 }
77
78 let len_len = (bytes[0] & 0x7f) as usize;
79+ if bytes.len() < len_len + 1 {
80+ return None;
81+ }
82+
83 let mut len = 0;
84 for i in 0..len_len {
85 len = (len << 8) | bytes[1 + i] as usize;
86 }
87
88- (len, &bytes[len_len + 1..])
89+ Some((len, &bytes[len_len + 1..]))
90 }
91
92 const DER_OBJECT_ID_TAG: u8 = 0x06;