3

I am trying to load a rsa object from a generated public key. I used PEM_write_bio_RSAPublicKey to generate the public key string. Then I used PEM_read_bio_RSA_PUBKEY to load the rsa object from the public key string. The problem is the rsa object is null. The generated string looks okay as far as I can tell. Any ideas?

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAxIReUspesPy6a4CPBjt/4Jt+H13q9MekMiutzNKdNO1uuwqcdqDX
pKPeTKXyUH6oCyRdUxkk6IVXGlBlxtW7OsxaYWhpfl9z3CCERCEpFmzN++dvlK2v
mckFL66e9q6Y+HwgyP1LJqrszeqlg2d29TCVKfD/UURVNmc/nPPjs9nO+IDhh7+P
NTQ2OqGBq8ghwVL5ZZyW3yVO5OAbRB6pjKBe9+j4B2TGnD5JO9Nu0jlFANZOKFJu
HDVE3XuTvOkuzL2i8Lwp4Myk42tbIgcCe4G58vKFddL651rWhg4hN3fRSx5YtDnQ
r5cgfNBOAww58S8lwXgU8lvzvEoNV+WMgwIDAQAB
-----END RSA PUBLIC KEY-----

gcc test_public_private_key.c -lcrypto -o test

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>

char* get_public_key() {

        RSA* rsa = RSA_new();
        int kbits = 2048;
        BIGNUM* bne = BN_new();
        BN_set_word(bne, RSA_F4);

        int status = RSA_generate_key_ex(rsa, kbits, bne, NULL);
        if(status == 0) {
                fprintf(stderr, "rsa key generation failed\n");
        }


        BIO *bio = BIO_new(BIO_s_mem());
        PEM_write_bio_RSAPublicKey(bio, rsa);

        int length = BIO_pending(bio);

        char* pem_key = malloc(length+1);
        memset(pem_key, '\0', length+1);

        BIO_read(bio, pem_key, length);

        return pem_key;

}

int main(int argc, char* argv[]) {

        char* public_key = get_public_key();

        printf("%s", public_key);

        BIO* keybio = BIO_new_mem_buf(public_key, -1);

        if (keybio == NULL) {
                fprintf(stderr, "failed to create key BIO");
        }

        printf("keybio: %p\n", keybio);
        RSA* rsa = PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL);
        printf("rsa result %p\n", rsa);
        BIO_free(keybio);

        free(public_key);

        return 0;
}
dbush
  • 205,898
  • 23
  • 218
  • 273
eat_a_lemon
  • 3,158
  • 11
  • 34
  • 50
  • I remember seeing a working example with the ```BIO_FLAGS_BASE64_NO_NL``` flag set. Maybe try setting this flag with ```BIO_set_flags( bio, BIO_FLAGS_BASE64_NO_NL );``` – Daniel Jul 16 '17 at 02:00
  • @Daniel I am not sure if it should contain the word RSA....its the library's own function that generates the string. I saw the NL example through my google searches but wouldn't that mean that I should strip the new lines from the generated string if I use that option. – eat_a_lemon Jul 16 '17 at 02:03
  • I tried the NO_NL option with and without stripping the newlines and it still did not work. – eat_a_lemon Jul 16 '17 at 02:11
  • After looking a bit more I'm pretty certain that the RSA word should be there. As for the flag, I saw it used with a key that had new lines, but looking at it again and reading what BIO_set_flags does i think it might be irrelevant since I think it's used only in BIO_write methods. You can try it anyways and see if it works. You should also try using a key generated with the openssl commands and hardcode it and see if it works with it – Daniel Jul 16 '17 at 02:11
  • I used the open ssl command to generate a public key and the RSA word was not there. I tried that and I am getting the same null result. – eat_a_lemon Jul 16 '17 at 02:20
  • I got it! I used the openssl command and added newlines to the output. I didn't use the NL option. It must be the RSA word. It comes from there own api! – eat_a_lemon Jul 16 '17 at 02:26
  • Interesting, I was about to suggest that u try using ```PEM_read_RSAPublicKey``` instead of ```PEM_read_bio_RSA_PUBKEY``` and that ought to solve it for u for the first key. refer to Nikolai's comment here: https://stackoverflow.com/a/7825076/5513449 He talks exactly about what we just discussed. – Daniel Jul 16 '17 at 02:28
  • Related, see [Use OpenSSL RSA key with .Net](https://stackoverflow.com/q/30475758/608639). It goes through the four types of key/encoding combinations. The founr combinations are {ASN.1, DER} x {PublicKey, subjectPublicKeyInfo}. – jww Jul 16 '17 at 19:52

1 Answers1

3

I thought it would be good to add that the reason this didn't work is because PEM_read_RSA_PUBKEY expects a SubjectPublicKeyInfo structure, which starts with BEGIN PUBLIC KEY, while PEM_read_RSAPublicKey expects a RSAPublicKey structure, which starts with BEGIN RSA PUBLIC KEY.
PEM_write_bio_RSAPublicKey generated the latter which corresponds to the second function, PEM_read_RSAPublicKey.

Daniel
  • 631
  • 9
  • 20
  • `RSA_generate_key_ex` creates the in-memory form; it is `PEM_write_[bio_]RSAPublicKey` (in OP's `get_public_key`) that creates the PKCS1 form which is readable by `PEM_read_[bio_]RSAPublicKey` but not `PEM_read_[bio_][RSA_]PUBKEY` – dave_thompson_085 Jul 17 '17 at 00:55
  • @dave_thompson_085 Ah yes, my bad. Edited my answer, thank you very much. – Daniel Jul 17 '17 at 01:02