[Cryptography] Heartbleed and fundamental crypto programming practices

ianG iang at iang.org
Sun Apr 27 10:30:05 EDT 2014


On 26/04/2014 13:10 pm, Jerry Leichter wrote:
> On Apr 25, 2014, at 8:34 AM, Phillip Hallam-Baker wrote:
...
>> What if Length2 is given as greater than the length of value2?
> Again, this is true of any TLV-like encoding.

Right, you have to check.

> I've implemented many such things, and very long ago realized that the parser can be recursive descent, but it must have the following form:
> 
> 	v = Decode_T(TLV-encoded-field, Length(Container));
> 
> Where Entity is the Container is the V field of the surrounding entity.  Then every Decode_T() starts off as:
> 
> 	Decode_T(TLV tlv, int len) {
> 		T t = Tag(tlv);
> 		if (t != T) abort(WrongType);
> 		l = Decode(Length(tlv), len);  // Length field must fit in len!
> 		if (l > len) abort(FieldOverrunsContainer);
> 		...extract V and process...
> 	}


Yes, this is where OO wins.

> Yes, writing that out by hand every time is boring and leads to shortcuts and errors.

On the first point, it comes down I think to control.  Do you want
control over everything you do, or do you trust some tool to do the job
for you?  I guess that's a personal opinion, and a resources question.

On the second point, there is a way to lock down the errors.  It
involves a bit more work, but generates much more confidence.

This is what I call the Ouroboros method.  You define a couple of extra
methods:

equals() which checks two objects for wire equality (similar to OO
equality but more precisely defined).

example() which generates a random object with all fields filled in some
random amount.  E.g.:

    example() {
        int a = rand();
        byte[] b = Example.randombytes();
        X x = new X(a, b);
        return x;
    }

Then you write a method to create a million examples, encode them,
decode them, and compare the output object to the input object.

This catches "positive" failures over time.  To catch negative failures,
you'd need to extend the technique to do fuzzing which is a bit more
complicated.



> You want a generator to do this for you or you, or some successor, will eventually get it wrong.


I think if one is working in a big team then one might want that.
Successor is a good word.

If one is paranoid then one prefers to do it oneself...  Paranoia lives
forever, succession isn't an issue.


>> Unless the decoding logic is just right, the decoder can end up with a
>> buffer overrun. And getting the logic right requires a lot of
>> discipline. A lot of decoders will blindly accept the input as valid
>> and the world is lost...
> The problem isn't with TLV encodings - ASN.1 or otherwise.  The problem is that after all these years, we're still writing this stuff by hand - and on top of it, when it's written in C, it's pretty much guaranteed that things what's being passed around is a raw buffer pointer - and often no one bothers to pass the length along, at least when the "know" it doesn't matter (e.g., the decoder for the L field will probably get just a raw pointer, because how long can a length field be?)

Right.



iang


More information about the cryptography mailing list