There are several ways in which this problem could have been prevented. Let’s take a look at some of them.
Several people have pointed out the use of goto in the code. Although this is generally a bad practice, I tried modifying similar code and using “better” coding constructs instead. I never got a compiler error, and the code was not necessarily a lot easier to read. I don’t believe that the use of goto significantly contributed to this problem.
Manual code reviews are a great way to catch these types of problems. The indentation issue does make the code more difficult to read. This is precisely why whenever I manually review code, I use the IDE to automatically fix indentation before I start looking at it. This doesn’t guarantee that the reviewer will catch every problem, but it does make code easier to read and understand. If you perform manual code reviews, I would highly recommend doing this.
If you’re implementing security protocols, you need to have test cases that test every step of the protocol. Some commercial SSL/TLS fuzzing tools may have test cases for this problem already. If they don’t, I’m sure they will in the near future. Use these tools, or implement your own.
I was thinking about whether this issue would have been a less severe problem if the SSL/TLS protocol worked slightly differently. For example, if the client sent its Diffie-Hellman parameters to the server encrypted with the server’s public key, this vulnerability wouldn’t have had any impact. The client’s Diffie-Hellman parameter would not be visible to the attacker, and so, the attacker couldn’t establish a SSL/TLS session with the client. This is of course only relevant if the server has a RSA key.
The client side always encrypts the pre-master secret using the server’s public key when RSA is used for key exchange. So why doesn’t it do it for Diffie-Hellman cipher suites? The only explanation I could come up with was that if the SSL/TLS implementation is correct, this is unnecessary and adds unnecessary overhead to the handshake. When Diffie-Hellman is used for key negotiation, the server already has to perform quite a bit of work; it has to generate Diffie-Hellman parameters, sign them, and then combine them with the client’s Diffie-Hellman parameter. These are all slow operations. Adding decryption of the client’s parameter would add one more slow operation to the protocol. Also, this wouldn’t work if the server had a DSA key.