I need to write a C program that generates an RSA key, and saves an X.509 public key in DER format and a PKCS#8 private key in DER format. I've used Google, but haven't really found much. What I have so far is this:
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
void main() {
int ret = 0;
RSA *r = NULL;
BIGNUM *bne = NULL;
BIO *bp_public = NULL, *bp_private = NULL;
int bits = 2048;
unsigned long e = RSA_F4;
// Generate the RSA key
printf("Generating RSA key...\n");
bne = BN_new();
ret = BN_set_word(bne, e);
if(ret != 1) {
goto free_all;
}
r = RSA_new();
ret = RSA_generate_key_ex(r, bits, bne, NULL);
if(ret != 1) {
goto free_all;
}
// Save the public key in PEM format
printf("Writing key files...\n");
bp_public = BIO_new_file("public.pem", "w+");
ret = PEM_write_bio_RSAPublicKey(bp_public, r);
if(ret != 1) {
goto free_all;
}
// Save the private key in PEM format
bp_private = BIO_new_file("private.pem", "w+");
ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
// Free everything
free_all:
BIO_free_all(bp_public);
BIO_free_all(bp_private);
RSA_free(r);
BN_free(bne);
printf("Done!\n");
}
This is obviously writing the keys in PEM format. I also need to be able to actually have the data in memory in the code, not just write it directly to a file, as there's some other stuff I need to do with the public key.
Thank you for any help
Your question is a little ambiguous in what you actually mean by "saves an X.509 public key in DER format". Assuming you actually mean "save it as a SubjectPublicKeyInfo structure" (which is the bit of an X.509 certificate that holds public keys) then you should use i2d_RSA_PUBKEY (or i2d_RSA_PUBKEY_fp or i2d_RSA_PUBKEY_bio) to write it out (no need to convert it to an EVP_PKEY first).
For the PKCS#8 private key in DER format, your current method is incorrect for PEM format. The PEM_write_bio_RSAPrivateKey() function will write this out in traditional format (not PKCS#8).
I assume you don't want to do anything complicated like encrypting the key first. For this one you will need to convert it to an EVP_PKEY (using EVP_PKEY_assign_RSA() as mentioned by @JawguyChooser). Next you obtain a PKCS8_PRIV_KEY_INFO structure using the (sadly undocumented) function EVP_PKEY2PKCS8.
PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey);
You need to free this structure when your done using PKCS8_PRIV_KEY_INFO_free(). Next write out the PKCS8 DER using i2d_PKCS8_PRIV_KEY_INFO() (or i2d_PKCS8_PRIV_KEY_INFO_fp() or i2d_PKCS8_PRIV_KEY_INFO_bio).
See the man page for info on various of these functions:
https://www.openssl.org/docs/man1.1.0/crypto/i2d_RSAPublicKey.html