How to get the number of bits in an OpenSSL key

Posted on December 16, 2013
Tags:

So, I had this innocent little line of code:

ret = SSL_CTX_use_PrivateKey_file (ctx, private_key, SSL_FILETYPE_PEM);

But I had one more thing I wanted to do. I wanted to know the size of the key (in bits) that I had just loaded into my context. Should be simple, right? Well, turns out it is and it isn’t.

The reason it isn’t simple is that there doesn’t appear to be any way to get the private key out of a context. (Which itself seems like a failing right there: why have a setter without a getter?) SSL_CTX_use_PrivateKey_file loads the private key from the file and puts it in my context, without ever letting me see the key. To see the key, I have to break open the sugar that is SSL_CTX_use_PrivateKey_file, and perform the steps “manually.” Which ends up looking like this:

  BIO *bio;
  EVP_PKEY *pkey;

  bio = BIO_new_file (private_key, "r");
  if (! bio)
    goto bad;

  pkey = PEM_read_bio_PrivateKey (bio, NULL,
                                  ctx->default_passwd_callback,
                                  ctx->default_passwd_callback_userdata);

  BIO_free (bio);
  if (! pkey)
    goto bad;

  ret = SSL_CTX_use_PrivateKey (ctx, pkey);
  EVP_PKEY_free (pkey);

After this, getting the number of bits in the key is pretty simple, except that you have to get the number of bits separately depending on the type of key. That’s understandable, though, since it doesn’t really make sense to talk about the number of bits in a key unless you know what kind of key you’re talking about. Bits in an RSA key are apples and bits in an elliptic curve key are oranges. So, it comes out looking like this:

  BIO *bio;
  EVP_PKEY *pkey;

  bio = BIO_new_file (private_key, "r");
  if (! bio)
    goto bad;

  pkey = PEM_read_bio_PrivateKey (bio, NULL,
                                  ctx->default_passwd_callback,
                                  ctx->default_passwd_callback_userdata);

  BIO_free (bio);
  if (! pkey)
    goto bad;

  /* for non-RSA keys, bits_out remains unchanged */
  if (EVP_PKEY_RSA == EVP_PKEY_type (pkey->type))
    { RSA *rsa = EVP_PKEY_get1_RSA (pkey);
      /* because RSA_size is in bytes! */
      *bits_out = 8 * RSA_size (rsa);
      RSA_free (rsa);
    }

  ret = SSL_CTX_use_PrivateKey (ctx, pkey);
  EVP_PKEY_free (pkey);