Reputation: 1135
How to convert rsa private key from .DER format to .PEM format programatically using openssl api. Manually I am able to convert using openssl exe. Kindly suggest programtically how to do this.
Upvotes: 1
Views: 5930
Reputation: 660
There are some functions in C OpenSSL API with name i2d_*
to parse an internal type (for the c programming language are structures with name X509,RSA ...) to DER and d2i_*
to parse DER to an internal type and this is how you can convert an x509 certificate file from DER format to PEM with the c programming language.
#include <stdio.h>
#include <openssl/x509.h>
int main(int argc,char* argv[]){
if(argc != 3) {
printf("Usage: der2pem derfile pemfile\n");
return 1;
}
// try open the derfile
FILE* derfile = fopen(argv[1],"r");
if(derfile) {
// try open or create the pemfile
FILE* pemfile = fopen(argv[2],"w+");
if(pemfile) {
// parse DER to internal X509 structure
// d2i is d for DER and i for internal which means c data
X509* internal = d2i_X509_fp(derfile,NULL);
if(internal) {
// write from the internal X509 to pemfile
PEM_write_X509(pemfile,internal);
}
else {
printf("wasn't possible to parse to X509 from the 'derfile'\n");
}
fclose(pemfile);
}
else {
printf("can't create or open the 'pemfile' file\n");
return 1;
}
fclose(derfile);
}
else {
printf("can't open the 'derfile' file\n");
return 1;
}
return 0;
}
The X.509 digital certificate is a data structure that contains, at minimum, the following fields:
Which means this example is not for private keys of any type, certificate requests, certificate revocation lists. If you need to convert from these types of DER files you have to dive more into the OpenSSL API, because for example the private keys have to do with encryption and decryption.
Something @owlstead said and that is true ... the PEM format is the base64
encoding of the DER format plus the header and footer. Then i wrote one more example in c, but you need to know the right header and footer to create a complete PEM file:
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
int main(int argc,char* argv[]){
if(argc != 5) {
printf("Usage: der2pem_simple derfile pemfile \"-----BEGIN CERTIFICATE-----\" \"-----END CERTIFICATE-----\"\n");
return 1;
}
// to create a buffer as small as possible
// we need the size of the input file
struct stat fistat;
if(stat(argv[1],&fistat)<0) {
printf("derfile not found\n");
return 1;
}
// open the derfile
FILE* derfile = fopen(argv[1],"r");
if (!derfile){
printf("can't open derfile\n");
return 1;
}
char buff[fistat.st_size];
// write the derfile to the buffer
fread(buff,fistat.st_size,1,derfile);
fclose(derfile);
// open pemfile
FILE* pemfile = fopen(argv[2],"w+");
if (!pemfile){
printf("can't open or create pemfile\n");
return 1;
}
// create a BIO context with base64 filter
BIO* bio_base64 = BIO_new(BIO_f_base64());
// create a BIO for the pemfile
BIO* bio_out = BIO_new_fp(pemfile,BIO_NOCLOSE);
// write the header
BIO_write(bio_out,argv[3],strlen(argv[3]));
BIO_write(bio_out,"\n",1);
// combine bio_base64->bio_out : enables base64 filter
bio_out = BIO_push(bio_base64,bio_out);
// write the buffer
BIO_write(bio_out,buff,fistat.st_size);
// flush before disable base64 filter
BIO_flush(bio_out);
// uncombine bio_base64 X bio_out : disables base64 filter
bio_out = BIO_pop(bio_base64);
// write the footer
BIO_write(bio_out,argv[4],strlen(argv[4]));
// flush to free the BIO resources
BIO_flush(bio_out);
BIO_free_all(bio_out);
fclose(pemfile);
}
and this example in Java:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.commons.codec.binary.Base64;
//import org.apache.commons.codec.binary.Base64OutputStream;
public class der2pem {
public static void main(String args[]) {
if(args.length < 4) {
System.out.println("Usage: der2pem_simple derfile pemfile \"-----BEGIN CERTIFICATE-----\" \"-----END CERTIFICATE-----\"");
return;
}
FileOutputStream pemfile;
try {
// open the pemfile
pemfile = new FileOutputStream(args[1]);
} catch (FileNotFoundException e) {
try {
// try to create if not found
new File(args[1]).createNewFile();
} catch (IOException e1) {
System.out.println(e1.getMessage());
return;
}
try {
// if created open it
pemfile = new FileOutputStream(args[1]);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
return;
}
}
FileInputStream derfile;
try {
// open the derfile
derfile = new FileInputStream(args[0]);
} catch (FileNotFoundException e) {
// if not found print error and get out
System.out.println(e.getMessage());
try {
pemfile.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return;
}
try {
//---- last part
// write the header to pemfile
pemfile.write(args[2].getBytes());
pemfile.write('\n');
// get the size of the derfile and create a buff that fits to this file
int derf_size = (int) new File(args[0]).length();
byte[] buffer = new byte[derf_size];
// read from derfile and write to buffer
derfile.read(buffer);
// create the Base64 object for the encoding
Base64 base64 = new Base64(64,"\n".getBytes());
// encode and write to pemfile
pemfile.write(base64.encode(buffer));
// write the footer to pemfile
pemfile.write(args[3].getBytes());
// flush to cleanup
pemfile.flush();
pemfile.close();
derfile.close();
//---- last part end
} catch (IOException e) {
e.printStackTrace();
}
}
}
I tried to use a method with Base64OutputStream
but has some unexpected results on the PEM file. If you wanna check just replace the last part
with this:
// write the header to pemfile
pemfile.write(args[2].getBytes());
pemfile.write('\n');
// get the size of the derfile and create a buff that fits to this file
int derf_size = (int) new File(args[0]).length();
byte[] buffer = new byte[derf_size];
// read from derfile and write to buffer
derfile.read(buffer);
// create the Base64OutputStream object for the encoding
Base64OutputStream b64f_pemfile = new Base64OutputStream(pemfile,true,64,"\n".getBytes());
// write to b64f_pemfile which encodes to base64
b64f_pemfile.write(buffer);
// flush before write the footer
b64f_pemfile.flush();
// write the footer
pemfile.write('\n');
pemfile.write(args[3].getBytes());
// flush to cleanup
pemfile.flush();
b64f_pemfile.close();
pemfile.close();
derfile.close();
I compiled it with:
javac der2pem.java -classpath "$CLASSPATH:/usr/share/java/commons-codec.jar"
and ran with:
java -classpath "$CLASSPATH:/usr/share/java/commons-codec.jar" der2pem test.der tttttt "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"
something similar you have to do in your system.
Upvotes: 3