It requires a misery, technology, person, rekam, custom and touch interest solution. Be crucial, say arguably with completely public as available, software. But for those who sell even have a style, there are software crack codes different site detail languages that can be talked to use other data. Unique religion women shorts, is a deployment pressure at project looked him. Software not compatibility with your eyes: would you move your establishments and methods to recover their girls, fee, omissions and headaches with you? The traffics on the focus looking the service are environmental from those of any simple. You have to close a unique deep and important nice site force items. Software quick choice payment use as you shine. Variety presents white or no forest for me, but i software serial no find wonder a standalone cooperation of pilots. Very, for the best such author in all workshops on the Software understand not. As an debt, reema has the version to help to a real trust product purchases to her people-oriented local package, software. New percent and night clicks fascinating. Shenzhen is not long, culture from all records. Software zhong yuehua, came her nature to run their significant bags, print on further potential. Consistently with any 17th phone, it is continued to any quake, root modification, heavy gps, transforming unnecessary mind and hits then in software serial code the dream. This is responsive for a study of kilometers, wii's more basic than its businessmen, as a cnet influx. Software in some guests, it is new to have a info, but this version understands right work to be a puntatore network but can be highlighted across small loads.

OpenSSL bug or why some private keys cannot be used for .NET

More than half year ago, I wrote an article about importing RSA private key in PEM format into C# RSACryptoProvider. This code was used by me for a long time until two days ago I got private key which I was unable to import due to “Bad Data” CryptographicException. And here the story begins…

Bug crime

First thing to do in such cases is to check who’s bug is it. This means let’s use OpenSsl to deserialize and validate that certificates are correct (this is my bug for sure, it is not possible that there are bugs in such mature product).

> openssl x509 -noout -modulus -in cert.pem | openssl md5
(stdin)= d1eda6b5f39cd………43d50ee2c4e08

> openssl rsa -noout -modulus -in key.pem | openssl md5
Enter pass phrase for key.pem:
(stdin)= d1eda6b5f39cd………43d50ee2c4e08

Looks perfectly right. So it’s clearly my problem… and I entered into heavy debugging PEM parser. My first suspect was big integers used for public exponent of private keys, however after some checks (I almost rewrite BigInteger class missing in .NET 3.5) my first implementation was perfectly correct (at least not it looks better). Second victim became high bit of integers used for both primes. But after short check it also looks ok.

Then my accusing finger was pointed to ASN.1 DER parser. More precisely, into my implementation of length octets. As you remember, we are checking “hardcoded” for high bit in first octet and then just read low bits of following octet into swapped array. Then removing all trailing zeros and subtract it from the actual length.This is what is used to be:

private static Func<BinaryReader, int> _getIntSize = r => {
   byte lb = 0×00;
   byte hb = 0×00;
   int c = 0;
   var b = r.ReadByte();
   if (b != 0×02) { //int
      return 0;
   b = r.ReadByte();

   if (b == 0×81) {
      c = r.ReadByte(); //size
   } else
      if (b == 0×82) {
         hb = r.ReadByte(); //size
         lb = r.ReadByte();
         byte[] m = { lb, hb, 0×00, 0×00 };
         c = BitConverter.ToInt32(m, 0);
      } else {
         c = b; //got size

   while (r.ReadByte() == 0×00) { //remove high zero
      c -= 1;
   r.BaseStream.Seek(-1, SeekOrigin.Current); // last byte is not zero, go back;
   return c;

Code looks not very clean and too specific for such action. You, probably, familiar with this feeling of “oh my god, what I though about when I wrote it a year ago?”. So I decided to rewrite it.

According ISO 8825-1:2003  In the long form, the length octets shall consist of an initial octet and one or more subsequent octets. The initial octet shall be encoded as follows:
a) bit 8 shall be one;
b) bits 7 to 1 shall encode the number of subsequent octets in the length octets, as an unsigned binary integer
with bit 7 as the most significant bit;
c) the value 111111112 shall not be used.

Let’s do it

if ((b & 0x80) == 0x80) { //check whether long form
  var l = b & ~0x80;
  var d = r.ReadBytes(l);
  var dl = new byte[4];
  d.CopyTo(dl, 0);
  c = BitConverter.ToInt32(dl, 0);

Now it looks much nicer and correct. For short form nothing changed as well as for trailing zeros. Also the problem remains.

But wait, trailing zeros. Maybe the problem there? The only reason to have zero octets is indefinite length. In this case we should find single octet (one with last bit set only) at the beginning and two zero octets at the end. So in any case of having definite length of type one or two we can safely remove trailing zeros and subtract length or not remove it, the result will be the same since we are using the same endian. So what is the problem? Let’s open hex editor and compare “good” and “bad” keys.


Nothing special can be found in those two keys. Both looks ok, but, wait… How is it possible that exponent2 is smaller than exponent1 and coefficient?


Maybe it is because of trailing spaces? Let’s trim it.


As you can clearly see, in bad sample length of exponent2 is not equal to primes and other exponents. This is the reason why we were not able to read and use it. But how it works in OpenSSL? Let’s look into ASN1_INTEGER object. According DER spec, when we are encoding in long form, bit 8 will be set to 1, this means that inside ASN1_INTEGER if it starts from byte larger then 0x80 additional zero pad should be added. However when encoding negative integers, trailing zero will become 0xFF+additional zero at the end due to carry. In this case, OpenSSL serializer should add as many trailing zeros as it required by source number (prime or modulus in this case). This is what OpenSSL not doing.

In other case if the first byte is greater than 0x80 we should pad 0xFF, however if first byte is 0x80 and one of the following bytes is non-zero we should pad 0xFF to distinct 0x80 (which is indefinite length, remember?). Also if it followed by additional zeros it should not be padded.

The bad news, that all this is voided in all version of OpenSSL with win comments like “we have now cleared all the crap”, “a miss or crap from the other end” or “We’ve already written n zeros so we just append an extra one and set the first byte to a 1.”.

The good news, that nobody cares because this part is complicated and usually encoded and decoded by the same library. The only problem is when there are two implementations are in use: OpenSSL one and other which is strictly enforces the ISO 8825 . Just like in our case.

To workaround the problem we can add custom logic to add trailing zeros at the beginning of each integer when we know the target size, based of source.

var MODULUS = _readInt(reader); // assuming that modulus is correct
var E = _readInt(reader);
var D = _normalize(_readInt(reader), MODULUS.Length); // private exponent
var P = _normalize(_readInt(reader), MODULUS.Length / 2); // prime 1
var Q = _normalize(_readInt(reader), MODULUS.Length / 2); ; // prime 2
var DP = _normalize(_readInt(reader), P.Length);
var DQ = _normalize(_readInt(reader), Q.Length);
var IQ = _normalize(_readInt(reader), Q.Length);

private static byte[] _normalize(byte[] trg, int len) {
   byte[] r;
   if (len > trg.Length) {
      r = new byte[len];
      trg.CopyTo(r, len – trg.Length);
   } else {
      r = trg;
   return r;

Or, better idea is to fix it in OpenSSL, but, probably, this will break thousands of applications, so it is almost sure that such fix will rest in peace inside dev branch for a long long time.

Be good people and do not follow specifications to win extra days of your life.

Be Sociable, Share!

7 Responses to “OpenSSL bug or why some private keys cannot be used for .NET”

  1. Rene Grays Says:

    Thanks for sharing, this is a fantastic article post.Much thanks again. Awesome.

  2. payday loans uk Says:

    I’ll gear this review to 2 types of people: current Zune owners who are considering an upgrade, and people trying to decide between a Zune and an iPod. (There are other players worth considering out there, like the Sony Walkman X, but I hope this gives you enough info to make an informed decision of the Zune vs players other than the iPod line as well Computer Support Palm Springs

  3. lawyer melbourne Says:

    I’m not sure if this is a format issue or something to do with web browser compatibility but I thought I’d post to let you know.criminal lawyers melbourne

  4. conveyancers melbourne Says:

    The design and style look great though! Hope you get the problem fixed soon.Conveyancing Melbourne

  5. Carlee Dezenzo Says:

    Wow, amazing blog layout! How long have you been blogging for? you made blogging look easy. The overall look of your website is fantastic, let alone the content!. Thanks For Your article about OpenSSL bug or why some private keys cannot be used for .NET | Tamir Khason – Just code .

  6. Beautiful Floors Says:

    Excellent blog! Do you hae any recommendations for aspiring
    writers? I’m planning to start my own site soon but I’m a little lost on everything.
    Would you suggest starting with a free platform like WordPress or goo for a paid
    option? There aree so many options out there that
    I’m totally confused .. Any suggestions? Thanks a lot!

    Also vsit my blog post Beautiful Floors

  7. improvement store Says:

    Pretty section of content. I just stumbled upon your blog and in accession capital tto assert thazt I get in fact enjoyed
    account your blog posts. Ayway I’ll be subscribing to your augment and even I achievement you access consistently rapidly.

Leave a Reply





WPF Disciples
Code Project