8

I have old code that was written to link against an old version of openssl. Part of this code loads a key from a PEM file, and tries to understand whether this key is a private or public key, by using the following code:

if( (prv->p==0 || prv->q==0) ) {
    // This is not a private key!
    throw error("No private key for decryption");
}

With the latest version of openssl, this (justifiably) doesn't compile:

crypto.cpp: In function ‘key* decrypt_header(file_t, RSA*)’:
crypto.cpp:158:13: error: invalid use of incomplete type ‘RSA {aka struct rsa_st}’
     if( (prv->p==0 || prv->q==0) ) {
             ^~

I understand that direct access to the struct's private members was replaced with a function, but I am having a hard time figuring out which function that is.

jww
  • 97,681
  • 90
  • 411
  • 885
Shachar Shemesh
  • 8,193
  • 6
  • 25
  • 57

3 Answers3

15
crypto.cpp:158:13: error: invalid use of incomplete type ‘RSA {aka struct rsa_st}’
     if( (prv->p==0 || prv->q==0) ) {
             ^~

As you are aware, OpenSSL 1.1.0 changed the visibility of a lot of struct members. You can no longer access the members directly. Instead, you have to use getter and setter functions.

Try RSA_get0_factors. The get0 means the reference counts are not incremented. Do not BN_free them.

void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);

If the code supports multiple versions of OpenSSL, then you will need a guard because RSA_get0_factors is for OpenSSL 1.1.0 and above. Maybe something like the following. Also see OPENSSL_VERSION_NUMBER man page.

#include <openssl/opensslv.h>

#if OPENSSL_VERSION_NUMBER < 0x10100000L

    /* OpenSSL 1.0.2 and below (old code) */

#else

    /* OpenSSL 1.1.0 and above (new code) */

#endif
jww
  • 97,681
  • 90
  • 411
  • 885
  • Thanks. Any idea where I was supposed to find this without re-learning openssl? – Shachar Shemesh Nov 11 '16 at 19:17
  • @ShacharShemesh - I think you have to suffer it... The [1.1.0 Change Log](https://www.openssl.org/news/changelog.html) stated a bunch of structures were made private. Because a replacement was needed, I checked the online [OpenSSL man pages](https://www.openssl.org/docs/manpages.html) for the RSA functions looking for the one that fetched `p` and/or `q`. I started at [OpenSSL man pages](https://www.openssl.org/docs/manpages.html), drilled into 1.1.0, drilled into Crypto, and then searched for ***`RSA_`***. Over time the OpenSSL wiki will probably accumulate the new code in its examples. – jww Nov 11 '16 at 19:35
  • The `get0` and `get1` thing has been around for a while. You usually learn that one early (and the hard way) when you start chasing problems under Valgrind. You will wonder why you had a leak when you called a `get1` function, or you will segfault with a double free by free'ing something from a `get0` function. I point out the `get0` and `get1` to save others the trouble. Someone will stumble upon this post and have an "oh shit" moment... – jww Nov 11 '16 at 19:42
  • A FOSS program of mine that I have last update in 2010 has been removed from Debian because it would not work with the latest version of openssl. Frankly, I'm trying to get it to work and that's it. If/when I get around to updating it, it will be a fairly major update, but not now. – Shachar Shemesh Nov 11 '16 at 20:41
  • What part of "it's an old project" did you not understand? :-) https://sourceforge.net/projects/rsyncrypto/ I've already updated the Linux sources. Now working on bringing my Windows VM up to date so I can create a new release. Haven't turned it on in 2 years. – Shachar Shemesh Nov 12 '16 at 05:24
  • Sent you an email. Thank you. – Shachar Shemesh Nov 12 '16 at 06:19
5

After 1.1.1 OpenSSL Supports getter what return each parameter like this.

const BIGNUM *RSA_get0_n(const RSA *d);
const BIGNUM *RSA_get0_e(const RSA *d);
const BIGNUM *RSA_get0_d(const RSA *d);
const BIGNUM *RSA_get0_p(const RSA *d);
const BIGNUM *RSA_get0_q(const RSA *d);
const BIGNUM *RSA_get0_dmp1(const RSA *r);
const BIGNUM *RSA_get0_dmq1(const RSA *r);
const BIGNUM *RSA_get0_iqmp(const RSA *r);

So if you don't need to considerate below version of OpenSSL less than 1.1.1 these code will make simple code. AND other structures support kind of this getter too. You can find more information of functions this. https://www.openssl.org/docs/man1.1.1/man3/

DDukDDak99
  • 341
  • 3
  • 12
1
#if OPENSSL_VERSION_NUMBER < 0x10100005L
static void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d, const BIGNUM **p, const BIGNUM **q)
{
    if(n != NULL)
        *n = r->n;

    if(e != NULL)
        *e = r->e;

    if(d != NULL)
        *d = r->d;

    if(p != NULL)
        *p = r->p;

    if(q != NULL)
        *q = r->q;
}
#endif

const BIGNUM *bn_p;
const BIGNUM *bn_q;

RSA_get0_key(key, NULL, NULL, NULL, &bn_p, &bn_q);
/*   if( (prv->p==0 || prv->q==0) ) { */
if( (prv_p==0 || prv_q==0) ) {
Jake1164
  • 12,291
  • 6
  • 47
  • 64
Michael Popovich
  • 301
  • 1
  • 10