Skip to content

cmpv2: PollRepContent is incorrectly encoded #2196

@insecure

Description

@insecure

Hey all.
I found a bug when trying to parse a pollRep message.

RFC4210 Section 5.3.22 PollRepContent is defined as follows:

    PollRepContent ::= SEQUENCE OF SEQUENCE {
        certReqId    INTEGER,
        checkAfter   INTEGER,  -- time in seconds
        reason       PKIFreeText OPTIONAL }

Encoding a PollRepContent struct with cmpv2 results in a SEQUENCE {...} not SEQUENCE OF SEQUENCE {...}.

To reproduce this, I have written the following test in poll.rs:

#[cfg(test)]
mod test_generate_pollrep {
    use der::{
        Encode,
        asn1::{Ia5String, Int},
    };

    use crate::{
        body::PkiBody,
        header::{PkiHeader, Pvno},
        message::PkiMessage,
    };

    #[test]
    fn test_seq_of_seq() {
        let expected_der = [
            48, 36, 48, 22, 2, 1, 2, 130, 6, 115, 101, 110, 100, 101, 114, 130, 9, 114, 101, 99,
            105, 112, 105, 101, 110, 116, 186, 10, 48, 8, 48, 6, 2, 1, 0, 2, 1, 60,
        ];
        let header = PkiHeader {
            pvno: Pvno::Cmp2000,
            sender: x509_cert::ext::pkix::name::GeneralName::DnsName(
                Ia5String::new("sender").unwrap(),
            ),
            recipient: x509_cert::ext::pkix::name::GeneralName::DnsName(
                Ia5String::new("recipient").unwrap(),
            ),
            message_time: None,
            protection_alg: None,
            sender_kid: None,
            recip_kid: None,
            trans_id: None,
            sender_nonce: None,
            recip_nonce: None,
            free_text: None,
            general_info: None,
        };
        let body = PkiBody::PollRep(super::PollRepContent {
            cert_req_id: Int::new(&[0]).unwrap(),
            check_after: 60,
            reason: None,
        });
        let msg = PkiMessage {
            header,
            body,
            protection: None,
            extra_certs: None,
        };

        assert_eq!(msg.to_der().unwrap(), expected_der);
    }
}

I dumped the DER blob generated by the code above (openssl asn1parse -i -dump -inform b64 -in pollrep_bad.txt):

    0:d=0  hl=2 l=  34 cons: SEQUENCE
    2:d=1  hl=2 l=  22 cons:  SEQUENCE
    4:d=2  hl=2 l=   1 prim:   INTEGER           :02
    7:d=2  hl=2 l=   6 prim:   cont [ 2 ]
   15:d=2  hl=2 l=   9 prim:   cont [ 2 ]
   26:d=1  hl=2 l=   8 cons:  cont [ 26 ]
   28:d=2  hl=2 l=   6 cons:   SEQUENCE
   30:d=3  hl=2 l=   1 prim:    INTEGER           :00
   33:d=3  hl=2 l=   1 prim:    INTEGER           :3C

And the DER blob I expected (openssl asn1parse -i -dump -inform b64 -in pollrep_expected.txt):

    0:d=0  hl=2 l=  36 cons: SEQUENCE
    2:d=1  hl=2 l=  22 cons:  SEQUENCE
    4:d=2  hl=2 l=   1 prim:   INTEGER           :02
    7:d=2  hl=2 l=   6 prim:   cont [ 2 ]
   15:d=2  hl=2 l=   9 prim:   cont [ 2 ]
   26:d=1  hl=2 l=  10 cons:  cont [ 26 ]
   28:d=2  hl=2 l=   8 cons:   SEQUENCE
   30:d=3  hl=2 l=   6 cons:    SEQUENCE
   32:d=4  hl=2 l=   1 prim:     INTEGER           :00
   35:d=4  hl=2 l=   1 prim:     INTEGER           :3C

The 26 tag means pollRep/PollRepContent.

I would have filed a PR, but I am not sure how to fix that in an elegant way. I am currently seeing these two options:

I would prefer the second one as it represents the spec from the RFC more closely, but I also suppose there is a better way I'm currently not seeing.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions