Re: Verify Signature on received PKIMessage fails

David Hook <dgh-rTAZ0PM/[email protected]> Fri, 6 Dec 2019 08:42:34 +1100
Newsgroups gmane.comp.encryption.bouncy-castle.devel
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--------------55B3F0257ED01106963FE002
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: 8bit


Hmmm... I don't if I'd describe that as a feature, thanks for letting me
know, I might look into that one.

You can find the rules in 11.7.3 of
https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
it's worth them fixing it - opening the door to arbitrary data for
signed encodings is an excellent way to allow people to tamper.

Thanks,

David

On 6/12/19 1:10 am, Sebastian Hempel wrote:
> Thanks for the awnser.
>
> I tried your alternative solution to verify the signature. But this
> solution also fails on validating responses with a trailing 0 in
> GeneralizedTime entries. I think the reason for this is, that the
> method toDLObject in the class ASN1GeneralizedTime also returns a
> DERGEneralizedTime.
>
> Do you have any links to a document, that describes the conventions /
> rules howto DER encode a generalized time? I would like to talk to the
> producer of the CMP handler. It would be easier to give him a kind of
> refrence about the problen then saying, bouncy castle does not like
> his encoded PKIMessage. ;-)
>
> Best regards
> Sebastian
>
> Am Do, Dez 5, 2019 at 10:12 schrieb David Hook <dgh-rTAZ0PM/[email protected]>:
>>
>> Yes, this would be expected, the signatures in the failing cases are
>> not being properly calculated.
>>
>> Assuming you can't get whoever is generating these to mend their
>> ways, you could provide an alternate verify method which read
>> something like:
>>
>> private boolean verifySignature(byte[] signature, ContentVerifier verifier)
>>     throws IOException
>> {
>>     ASN1EncodableVector v = new ASN1EncodableVector();
>>
>>     v.add(pkiMessage.getHeader());
>>     v.add(pkiMessage.getBody());
>>
>>     OutputStream sOut = verifier.getOutputStream();
>>
>>     sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DL));
>>
>>     sOut.close();
>>
>>     return verifier.verify(signature);
>> }
>>
>> If I have understood correctly that should work. Note I would still not make this the default - it would be better if the faulty signatures were corrected.
>>
>> Regards,
>>
>> David
>> On 5/12/19 1:30 am, Sebastian Hempel wrote:
>>> Hi,
>>>
>>> I'm using BouncyCastle (bc) to communicate with a CMP handler. The
>>> source code was first implemented using BouncyCastle 1.51. I want
>>> update to the latest version 1.64 of bc. All works well for bc
>>> versions including 1.58. Starting with version 1.59 I get an error
>>> verifying the signature of the received PKIMessage.
>>>
>>> I digged down the source code and found the following reason.
>>>
>>> A PKIMessage consists of a PKIHeader, PKIBody, a DERBitString for
>>> the signature (protection) and a sequence of extra certificates. To
>>> validate the signature I take the PKIHeader and the PKIBody of the
>>> PKIMessage and use the sequence of these to objects to verify the
>>> signature that is contained in the field protection. The
>>> verification sometimes succeeds and sometime fails. Rolling back to
>>> version 1.58 everything works fine.
>>>
>>> I found out, that the result of getting the header of the PKIMessage
>>> differs from the bytes received from the CMP handler. The field
>>> messageTime of the header was changed by bc when getting / encoding
>>> the field to DER.
>>>
>>> There was a change in the class DERGeneralizedTime in 1.59. The
>>> class now contains a method getDERTime to (re-)encode the timestamp.
>>> In all versions before 1.59 the byte array was returned directly.
>>> All versions starting with 1.59 return the result of the getDERTime
>>> method. This method eleminates trailing 0 in the fraction part of
>>> the time.
>>>
>>> Timestamps directly received from the CMP handler:
>>>
>>> 20191127144414.20Z
>>> 20191127150803.570Z
>>> 20191127150848.630Z
>>> 20191127151008.290Z
>>> 20191127151157.630Z
>>>
>>> The method getDERTime returns a different encoding:
>>>
>>> 20191127144414.2Z
>>> 20191127150803.57Z
>>> 20191127150848.63Z
>>> 20191127151008.29Z
>>> 20191127151157.63Z
>>>
>>> When calculating the hash for the "new" timestamp there will be no
>>> change to get the same value as using the "original" timestamps.
>>>
>>> Is this behaviour expected? Is there a way to get the original
>>> encoding of the header / messageTime to calculate the hash?
>>>
>>> Best regards
>>> Sebastian
>>> -- 
>>> Sebastian Hempel
>>> Veilchenweg 4 · 95195 Röslau · Germany
>>> eMail: [email protected]
>>> GnuPG Fingerprint: 9396 67A0 D3F3 6EBB BD7C 783D 34D8 65FE 9EB7 B49F
>>>
>>>
>>>
>>>
>>>
>>


--------------55B3F0257ED01106963FE002
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: 8bit

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;
      charset=windows-1252">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <div class="moz-cite-prefix"><br>
    </div>
    <div class="moz-cite-prefix">Hmmm... I don't if I'd describe that as
      a feature, thanks for letting me know, I might look into that one.<br>
    </div>
    <div class="moz-cite-prefix"><br>
    </div>
    <div class="moz-cite-prefix">You can find the rules in 11.7.3 of
      <a class="moz-txt-link-freetext" href="https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf">https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf</a>
      it's worth them fixing it - opening the door to arbitrary data for
      signed encodings is an excellent way to allow people to tamper.</div>
    <div class="moz-cite-prefix"><br>
    </div>
    <div class="moz-cite-prefix">Thanks,</div>
    <div class="moz-cite-prefix"><br>
    </div>
    <div class="moz-cite-prefix">David<br>
    </div>
    <div class="moz-cite-prefix"><br>
    </div>
    <div class="moz-cite-prefix">On 6/12/19 1:10 am, Sebastian Hempel
      wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:1575555008.68491.11-rAdnlYiPdi3F0L99lGCudLNAH6kLmebB@public.gmane.org">
      <meta http-equiv="content-type" content="text/html;
        charset=windows-1252">
      <div id="geary-body" dir="auto">
        <div>Thanks for the awnser.</div>
        <div><br>
        </div>
        <div>I tried your alternative solution to verify the signature.
          But this solution also fails on validating responses with a
          trailing 0 in GeneralizedTime entries. I think the reason for
          this is, that the method toDLObject in the class
          ASN1GeneralizedTime also returns a DERGEneralizedTime.</div>
        <div><br>
        </div>
        <div>Do you have any links to a document, that describes the
          conventions / rules howto DER encode a generalized time? I
          would like to talk to the producer of the CMP handler. It
          would be easier to give him a kind of refrence about the
          problen then saying, bouncy castle does not like his encoded
          PKIMessage. ;-)</div>
        <div><br>
        </div>
        <div>Best regards</div>
        <div>Sebastian</div>
      </div>
      <div id="geary-quote" dir="auto"><br>
        Am Do, Dez 5, 2019 at 10:12 schrieb David Hook
        <a class="moz-txt-link-rfc2396E" href="mailto:dgh-rTAZ0PM/[email protected]">&lt;dgh-rTAZ0PM/[email protected]&gt;</a>:<br>
        <blockquote type="cite">
          <meta http-equiv="Content-Type" content="text/html;
            charset=windows-1252">
          <div class="moz-cite-prefix"><br>
          </div>
          <div class="moz-cite-prefix">Yes, this would be expected, the
            signatures in the failing cases are not being properly
            calculated.</div>
          <div class="moz-cite-prefix"><br>
          </div>
          <div class="moz-cite-prefix">Assuming you can't get whoever is
            generating these to mend their ways, you could provide an
            alternate verify method which read something like:</div>
          <div class="moz-cite-prefix"><br>
          </div>
          <div class="moz-cite-prefix">
            <pre style="background-color:#ffffff;color:#000000;font-family:'DejaVu Sans Mono';font-size:11.3pt;"><span style="color:#000080;font-weight:bold;">private boolean </span>verifySignature(<span style="color:#000080;font-weight:bold;">byte</span>[] signature, ContentVerifier verifier)
    <span style="color:#000080;font-weight:bold;">throws </span>IOException
{
    ASN1EncodableVector v = <span style="color:#000080;font-weight:bold;">new </span>ASN1EncodableVector();

    v.add(<span style="color:#660e7a;font-weight:bold;">pkiMessage</span>.getHeader());
    v.add(<span style="color:#660e7a;font-weight:bold;">pkiMessage</span>.getBody());

    OutputStream sOut = verifier.getOutputStream();

    sOut.write(<span style="color:#000080;font-weight:bold;">new </span>DERSequence(v).getEncoded(ASN1Encoding.<span style="color:#660e7a;font-weight:bold;font-style:italic;">DL</span>));

    sOut.close();

    <span style="color:#000080;font-weight:bold;">return </span>verifier.verify(signature);
}

If I have understood correctly that should work. Note I would still not make this the default - it would be better if the faulty signatures were corrected.

Regards,

David
</pre>
          </div>
          <div class="moz-cite-prefix">On 5/12/19 1:30 am, Sebastian
            Hempel wrote:<br>
          </div>
          <blockquote type="cite"
            cite="mid:1575469839.68491.6-rAdnlYiPdi3F0L99lGCudLNAH6kLmebB@public.gmane.org">Hi, <br>
            <br>
            I'm using BouncyCastle (bc) to communicate with a CMP
            handler. The source code was first implemented using
            BouncyCastle 1.51. I want update to the latest version 1.64
            of bc. All works well for bc versions including 1.58.
            Starting with version 1.59 I get an error verifying the
            signature of the received PKIMessage. <br>
            <br>
            I digged down the source code and found the following
            reason. <br>
            <br>
            A PKIMessage consists of a PKIHeader, PKIBody, a
            DERBitString for the signature (protection) and a sequence
            of extra certificates. To validate the signature I take the
            PKIHeader and the PKIBody of the PKIMessage and use the
            sequence of these to objects to verify the signature that is
            contained in the field protection. The verification
            sometimes succeeds and sometime fails. Rolling back to
            version 1.58 everything works fine. <br>
            <br>
            I found out, that the result of getting the header of the
            PKIMessage differs from the bytes received from the CMP
            handler. The field messageTime of the header was changed by
            bc when getting / encoding the field to DER. <br>
            <br>
            There was a change in the class DERGeneralizedTime in 1.59.
            The class now contains a method getDERTime to (re-)encode
            the timestamp. In all versions before 1.59 the byte array
            was returned directly. All versions starting with 1.59
            return the result of the getDERTime method. This method
            eleminates trailing 0 in the fraction part of the time. <br>
            <br>
            Timestamps directly received from the CMP handler: <br>
            <br>
            20191127144414.20Z <br>
            20191127150803.570Z <br>
            20191127150848.630Z <br>
            20191127151008.290Z <br>
            20191127151157.630Z <br>
            <br>
            The method getDERTime returns a different encoding: <br>
            <br>
            20191127144414.2Z <br>
            20191127150803.57Z <br>
            20191127150848.63Z <br>
            20191127151008.29Z <br>
            20191127151157.63Z <br>
            <br>
            When calculating the hash for the "new" timestamp there will
            be no change to get the same value as using the "original"
            timestamps. <br>
            <br>
            Is this behaviour expected? Is there a way to get the
            original encoding of the header / messageTime to calculate
            the hash? <br>
            <br>
            Best regards <br>
            Sebastian <br>
            -- <br>
            Sebastian Hempel <br>
            Veilchenweg 4 · 95195 Röslau · Germany <br>
            eMail: <a class="moz-txt-link-abbreviated"
              href="mailto:[email protected]"
              moz-do-not-send="true">[email protected]</a> <br>
            GnuPG Fingerprint: 9396 67A0 D3F3 6EBB BD7C 783D 34D8 65FE
            9EB7 B49F <br>
            <br>
            <br>
            <br>
            <br>
            <br>
          </blockquote>
          <p><br>
          </p>
        </blockquote>
      </div>
    </blockquote>
    <p><br>
    </p>
  </body>
</html>

--------------55B3F0257ED01106963FE002--