pavan
pavan

Reputation: 1135

convert rsa private key from .DER format to .PEM format programatically using opensl

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

Answers (1)

Memos Electron
Memos Electron

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:

  • The distinguished name of the owner of the public key, also called the subject's name
  • The distinguished name of the issuer of the certificate, also called the issuer's name
  • The public key itself
  • The time period during which the certificate is valid, also called the validity period
  • The certificate's serial number as designated by the issuer
  • The issuer's digital signature.

source http://publib.boulder.ibm.com/infocenter/zos/v1r11/index.jsp?topic=/com.ibm.zos.r11.icha700/xcerts.htm

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

Related Questions