Sunday, August 25, 2013

TCP Echo Server using epoll, an example for Event Driven Server

Description: Implementation of tcp echo server using epoll. The server accepts connections from clients, reads data and echo's the same data back to the clients. All the operations accepting connections from clients, reading and writing data are done in a non-blocking manner.


server.h

/*
 * Contains definitions of constants and data structures used.
 */

#define SERVERPORT 8080

#define MAXCONN 200

#define MAXEVENTS 100

#define MAXLEN 255

struct EchoEvent
{
    int fd;
    uint32_t event;
    char data[MAXLEN];
    int length;
    int offset;

};

server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include "server.h"

int epollfd;

void modifyEpollContext(int epollfd, int operation, int fd, uint32_t events, void* data)
{
    struct epoll_event server_listen_event;

    server_listen_event.events = events;

    server_listen_event.data.ptr = data;

    if(-1 == epoll_ctl(epollfd, operation, fd, &server_listen_event))
    {
        printf("Failed to add an event for socket%d Error:%s", fd, strerror(errno));
        exit(1);       
    }
   
}
void* handle(void* ptr)
{
    struct EchoEvent* echoEvent = ptr;

    if(EPOLLIN == echoEvent->event)
    {
        int n = read(echoEvent->fd, echoEvent->data, MAXLEN);
   
        if(0 == n)
        {
            /*
             * Client closed connection.
             */

            printf("\nClient closed connection.\n");
            close(echoEvent->fd);
            free(echoEvent);
        }
        else if(-1 == n)
        {
           
            close(echoEvent->fd);
            free(echoEvent);
        }
        else
        {
            echoEvent->length = n;
       
            printf("\nRead data:%s Length:%d", echoEvent->data , n);           
            printf("\nAdding write event.\n");
            /*
             * We have read the data. Add an write event so that we can
             * write data whenever the socket is ready to be written.
             */

            modifyEpollContext(epollfd, EPOLL_CTL_ADD, echoEvent->fd, EPOLLOUT, echoEvent);
        }       
   
    }
    else if(EPOLLOUT == echoEvent->event)
    {
        int ret;

         ret = write(echoEvent->fd, (echoEvent->data) + (echoEvent->offset), echoEvent->length);
       
        if( (-1 == ret && EINTR == errno) || ret < echoEvent->length)
        {
            /*
             * We either got EINTR or write only sent partial data.
             * Add an write event. We still need to write data.
             */           
   
           
            modifyEpollContext(epollfd, EPOLL_CTL_ADD, echoEvent->fd, EPOLLOUT, echoEvent);
           
            if(-1 != ret)
            {
               /*
               * The previous write wrote only partial data to the socket.
               */

                echoEvent->length = echoEvent->length - ret;
                echoEvent->offset = echoEvent->offset + ret;   
            }
           
        }
        else if(-1 == ret)
        {
           /*
            * Some other error occured.
            */
            close(echoEvent->fd);
            free(echoEvent);
        }
       
        else
        {   
       
          /*
           * The entire data was written. Add an read event,
           * to read more data from the socket.
           */
            printf("\nAdding Read Event.\n");   
            modifyEpollContext(epollfd, EPOLL_CTL_ADD, echoEvent->fd, EPOLLIN, echoEvent);
        }
    }

}


void makeSocketNonBlocking(int fd)
{
    int flags;
   
    flags = fcntl(fd, F_GETFL, NULL);

    if(-1 == flags)
    {
        printf("fcntl F_GETFL failed.%s", strerror(errno));
        exit(1);
    }

    flags |= O_NONBLOCK;

    if(-1 == fcntl(fd, F_SETFL, flags))   
    {
        printf("fcntl F_SETFL failed.%s", strerror(errno));
        exit(1);
    }       
}


int main(int argc, char** argv)
{
   
    int serverfd;

    struct sockaddr_in server_addr;

    struct sockaddr_in clientaddr;
    socklen_t clientlen = sizeof(clientaddr);

   /*
    * Create server socket. Specify the nonblocking socket option.
    *
    */   
    serverfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);

    if(-1 == serverfd)
    {
        printf("Failed to create socket.%s", strerror(errno));
        exit(1);
    }   
   
    bzero(&server_addr, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVERPORT);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
   
   /*
    * Bind the server socket to the required ip-address and port.
    *
    */

    if(-1 == bind(serverfd, (struct sockaddr*)&server_addr, sizeof(server_addr)))
    {
        printf("Failed to bind.%s", strerror(errno));
        exit(1);
    }

   /*
    * Mark the server socket has a socket that will be used to .
    * accept incoming connections.
    */
  
  if(-1 == listen(serverfd, MAXCONN))
    {
        printf("Failed to listen.%s", strerror(errno));
        exit(1);
    }

   /*
    * Create epoll context.
    */
  
 
    epollfd = epoll_create(MAXCONN);

    if(-1 == epollfd)
    {
        printf("Failed to create epoll context.%s", strerror(errno));
        exit(1);
    }

   /*
    * Create read event for server socket.
    */
  
modifyEpollContext(epollfd, EPOLL_CTL_ADD, serverfd, EPOLLIN, &serverfd);

   /*
    * Main loop that listens for event.
    */
    struct epoll_event *events = calloc(MAXEVENTS, sizeof(struct epoll_event));
    while(1)
    {
        int n = epoll_wait(epollfd, events, MAXEVENTS, -1);

        if(-1 == n)               
        {
            printf("Failed to wait.%s", strerror(errno));
            exit(1);
        }
       
        int i;
        for(i = 0; i < n; i++)
        {
            if(events[i].data.ptr == &serverfd)
            {
                if(events[i].events & EPOLLHUP || events[i].events & EPOLLERR)
                {
                  /*
                   * EPOLLHUP and EPOLLERR are always monitored.
                   */
   
                close(serverfd);
                     exit(1);
                }   

               /*
               * New client connection is available. Call accept.
               * Make connection socket non blocking.
               * Add read event for the connection socket.
               */
   
            int connfd = accept(serverfd, (struct sockaddr*)&clientaddr, &clientlen);

                if(-1 == connfd)
                {
                    printf("Accept failed.%s", strerror(errno));
                    exit(1);
                }
                else
                {
                    printf("Accepted connection.Sleeping for minute.\n");
                   
                    makeSocketNonBlocking(connfd);
               
                    sleep(60);
               
                    printf("Adding a read event\n");

                    struct EchoEvent* echoEvent = calloc(1, sizeof(struct EchoEvent));

                    echoEvent->fd = connfd;
                   
                  /*
                  * Add a read event.
                  */
      
              modifyEpollContext(epollfd, EPOLL_CTL_ADD, echoEvent->fd, EPOLLIN, echoEvent);
                }   
            }
            else
            {
                /*
                 *A event has happend for one of the connection sockets.
                 *Remove the connection socket from the epoll context.
                 * When the event is handled by handle() function ,
                 *it will add the required event to listen for this 
                 *connection socket again to epoll
                 *context
                 */   


                if(events[i].events & EPOLLHUP || events[i].events & EPOLLERR)
                {
                    struct EchoEvent* echoEvent = (struct EchoEvent*) events[i].data.ptr;
                    printf("\nClosing connection socket\n");
                    close(echoEvent->fd);
                    free(echoEvent);
                }
                else if(EPOLLIN == events[i].events)   
                {
                    struct EchoEvent* echoEvent = (struct EchoEvent*) events[i].data.ptr;
                   
                    echoEvent->event = EPOLLIN;
                  /*
                 * Delete the read event.
                 */   
          
          modifyEpollContext(epollfd, EPOLL_CTL_DEL, echoEvent->fd, 0, 0);

                    handle(echoEvent);
                }
                else if(EPOLLOUT == events[i].events)   
                {
                    struct EchoEvent* echoEvent = (struct EchoEvent*) events[i].data.ptr;
                   
                    echoEvent->event = EPOLLOUT;
                   
                    /*
                   * Delete the write event.
                   */       
               
    modifyEpollContext(epollfd, EPOLL_CTL_DEL, echoEvent->fd, 0, 0);

                    handle(echoEvent);
                }
            }
           
        }
    }

    free(events);
    exit(0);
}


/*
 *About Level Trigerred:
 * We have added an fd for event EPOLLIN and then data is available for read in fd. epoll_wait will continuously report EPOLLIN event still all data is read.
 *
 *About Edge Trigerred:
 * In the above case, epoll_wait will report only once. When it reports we have to read all data. If without reading all data if we call epoll_wait
 * it will not report again. Also lets say fd is already readable, you are adding an event EPOLLIN | EPOLLET and calling epoll_wait, it will report EP * OLLIN.
 *
 * Default behaviour is level trigerred. To enable EdgeTrigerred use EPOLLET option while adding events.
 */

Thursday, August 15, 2013

Example nginx module for reading request body.

Description:

    The module reads the contents  from PUT/POST request body, saves it on the disk  and returns HTTP 202 (Accepted) status code if successful and returns the URI which the user can use to retrieve back the contents in "Location" response header and the name of the file in which the contents were saved in the response body.


Module Source Code:

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

const char*  documentRoot = "/usr/local/nginx/html/";


static void ngx_http_sample_put_handler(ngx_http_request_t *r)
{
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "put handler called");

    char filename[200] = { '\0' };

    struct timeval tv;

    gettimeofday(&tv, NULL);

    sprintf(filename, "%s%ld.%ld", documentRoot, tv.tv_sec, tv.tv_usec);



    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "FileName:%s", filename);

    int fd = creat(filename, 0644);

    if(-1 == fd)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to create mail file.%s", strerror(errno));
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;

    }

    if(NULL == r->request_body->temp_file)
    {
        /*
         * The entire request body is available in the list of buffers pointed by r->request_body->bufs.
         *
         * The list can have a maixmum of two buffers. One buffer contains the request body that was pre-read along with the request headers.
         * The other buffer contains the rest of the request body. The maximum size of the buffer is controlled by 'client_body_buffer_size' directive.
         * If the request body cannot be contained within these two buffers, the entire body  is writtin to the temp file and the buffers are cleared.
         */
        ngx_buf_t    *buf;

        ngx_chain_t  *cl;


        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Writing data from buffers.");
        cl = r->request_body->bufs;
        for( ;NULL != cl; cl = cl->next )
        {
            buf = cl->buf;
            if(write(fd, buf->pos, buf->last - buf->pos) < 0)
            {

                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                close(fd);
                return;
            }
        }
    }
    else
    {
        /**
         * The entire request body is available in the temporary file.
         *
         */
        size_t ret;
        size_t offset = 0;
        unsigned char data[4096];

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Writing data from temp file.");

        while(  (ret = ngx_read_file(&r->request_body->temp_file->file, data, 4096, offset)) > 0)
        {
            if(write(fd, data, ret) < 0)
            {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                close(fd);
                return;
            }
            offset = offset + ret;
        }
    }

    close(fd);

    unsigned char* data;

    data = ngx_pcalloc(r->pool, strlen(filename));
    if (data == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }

    ngx_memcpy(data, filename + strlen(documentRoot), strlen(filename) - strlen(documentRoot));

    r->headers_out.status = NGX_HTTP_ACCEPTED;

    r->headers_out.content_length_n = strlen(filename) - strlen(documentRoot);
    r->headers_out.content_type.len = sizeof("text/plain") - 1;
    r->headers_out.content_type.data = (u_char *) "text/plain";

    r->headers_out.location = ngx_list_push(&r->headers_out.headers);

    if (NULL == r->headers_out.location) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }
    r->headers_out.location->hash = 1;
    r->headers_out.location->key.len = sizeof("Location") - 1;
    r->headers_out.location->key.data = (u_char *) "Location";
    r->headers_out.location->value.len = strlen(filename) - strlen(documentRoot);
    r->headers_out.location->value.data = data;
    ngx_http_send_header(r);


    ngx_int_t rc;

    rc = ngx_http_send_header(r);

    if(rc == NGX_ERROR || rc > NGX_OK)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Sending headers failed.");
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }

    ngx_buf_t *b;
    ngx_chain_t out;

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }


    b->pos = data;

    b->last = data + (strlen(filename));

    b->memory = 1;

    b->last_buf = 1;

    out.buf = b;

    out.next = NULL;

    ngx_http_finalize_request(r, ngx_http_output_filter(r, &out));

    return;

}



static ngx_int_t
ngx_http_sample_handler(ngx_http_request_t *r)
{
    ngx_int_t     rc;

   /**
    * Specify the handler function to be called after reading the request body.
    */
    rc = ngx_http_read_client_request_body(r, ngx_http_sample_put_handler);

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE){
            return rc;
    }

   return NGX_DONE;
}

static char *
ngx_http_sample(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t  *clcf;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

    /**
     * Get the location configuration and specify the function
     * that would hanlde requests for this location.
     */

    clcf->handler = ngx_http_sample_handler;


    return NGX_CONF_OK;
}

static ngx_command_t  ngx_http_sample_commands[] = {
    { ngx_string("sample"),
      NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
      ngx_http_sample,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

      ngx_null_command
};


static ngx_http_module_t  ngx_http_sample_module_ctx = {
    NULL,                          /* preconfiguration */
    NULL,                          /* postconfiguration */

    NULL,                          /* create main configuration */
    NULL,                          /* init main configuration */
    NULL,                          /* create server configuration */
    NULL,                          /* merge server configuration */

    NULL,  /* create location configuration */
    NULL /* merge location configuration */
};


ngx_module_t  ngx_http_sample_module = {
    NGX_MODULE_V1,
    &ngx_http_sample_module_ctx, /* module context */
    ngx_http_sample_commands,   /* module directives */
    NGX_HTTP_MODULE,               /* module type */
    NULL,                          /* init master */
    NULL,                          /* init module */
    NULL,                          /* init process */
    NULL,                          /* init thread */
    NULL,                          /* exit thread */
    NULL,                          /* exit process */
    NULL,                          /* exit master */
    NGX_MODULE_V1_PADDING
};

Module configuration:
http {

        location /samples {

            sample;
        }

}

Testing the module:

i) Create a sample file to send in the request.

# echo "Sample Module" > input_file
# cat input_file
Sample Module

ii) Send the http request.

# curl -T ./input_file  -D header http://192.168.1.3/samples
1376574012.497879

iii) The reqest and response headers received.
# cat header
HTTP/1.1 100 Continue

HTTP/1.1 202 Accepted
Server: nginx/1.4.2
Date: Thu, 15 Aug 2013 13:40:12 GMT
Content-Type: text/plain
Content-Length: 17
Connection: keep-alive
Location: 1376574012.497879

iv) Use the filename specified in the "Location" response header field / in the response body to retrieve it.

# wget http://192.168.1.3/1376574012.497879
--2013-08-15 19:11:55--  http://192.168.1.3/1376574012.497879
Connecting to 192.168.1.3:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14 [application/octet-stream]
Saving to: `1376574012.497879'

100%[==============================================================================================================================>] 14          --.-K/s   in 0s

2013-08-15 19:11:55 (66.4 KB/s) - `1376574012.497879' saved [14/14]

v) The retrieved file is the same as the contents sent in the first http request.
# cat 1376574012.497879
Sample Module


Reference:


Tuesday, August 13, 2013

Working with openssl utility.

Working with 'openssl' utility.

'openssl' utility provides various useful commands for performing different opertions on certificates and private key files. Using the 'req' command we can create self-signed certs and certificate requests.

Creating a selfsigned certificate using openssl.
The 'req' command of openssl utility can be used to create self signed certs.
 
 
root@bala-VirtualBox:/home/bala/# openssl req -new -x509 -days 365 -sha1 -newkey rsa:1024 -nodes -keyout server.key -out server.pem -subj '/O=Company/OU=Department/CN=www.example-ca.com'
Generating a 1024 bit RSA private key
.....................++++++
.........++++++
writing new private key to 'server.key'
 
Running the above commands creates two files the public certificate(server.pem) and private certificate / private key(server.key)
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# ls
server.key  server.pem
 
Let us look at  what the options used in the above command mean:
 
-x509 identifies that a certificate is required, rather than just a certificate request (see below). 
 
-days 365 sets the certificate to expire in a year. You may want to extend this period. Make a note of the expiry date so that you can renew it when necessary! 
 
-sha1 specifies that SHA1 encryption should be used. 
 
-newkey rsa:1024 sets the key as 1024 bit RSA. 
 
-nodes specifies no passphrase.  (Otherwise apache would ask for a password everytime it restarts).
 
-keyout and -out specify where to store the certificate and key. The key should be root-readable only; the certificate can be world-readable, and must be readable by the user that Apache runs as. 
 
-subj flag sets the company name, department name, and the web site address. If you leave these out, you'll be prompted for them. The CN must be the same as the address of your web site, otherwise the certificate won't match and users will receive a warning when connecting. Make sure you don't use a challenge password.
 
What does the public certificate and private key files look like.
 
The above command created the public certificate and private key's in PEM format which is a Base64 encoded version of the certificate and the key's content.
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# cat server.pem 
-----BEGIN CERTIFICATE-----
MIICVjCCAb+gAwIBAgIJAKK+9tt+i9P+MA0GCSqGSIb3DQEBBQUAMEQxEDAOBgNV
BAoMB0NvbXBhbnkxEzARBgNVBAsMCkRlcGFydG1lbnQxGzAZBgNVBAMMEnd3dy5l
eGFtcGxlLWNhLmNvbTAeFw0xMzA3MzExNDUwMTNaFw0xNDA3MzExNDUwMTNaMEQx
EDAOBgNVBAoMB0NvbXBhbnkxEzARBgNVBAsMCkRlcGFydG1lbnQxGzAZBgNVBAMM
End3dy5leGFtcGxlLWNhLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ro1wW5/+ID5OaJNbG/ecMWnHZgcDIJED2uTCIDbe5tIubPaMs2Tj1GJ3hiNrsC0Y
IY7SY5USoTeN0Q0exb0DRP4X3hh1Y3HLtF8yCh/aUhXqxcd8kSLKLdIX8vKcOLLF
mXWk2wqFPXkHatZBFZw4aBfmPA164cznGqI5ELNlkSsCAwEAAaNQME4wHQYDVR0O
BBYEFAu63UbEF+ea6/teGZGvtB8DqYtsMB8GA1UdIwQYMBaAFAu63UbEF+ea6/te
GZGvtB8DqYtsMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAe+tDrTNe
/oj77pI2o3k8u29HX/cxhxZpDzvvbVP+ezGL2KRweHsJg9J1d40dpoCZFaHDCHga
GLxI8ecC/lWZYOr/yJcCurF0+zAXsGRZ3d35xF/ITP1enKCb+XaDIoOP/LKNglwk
qeHouhABGWyTENS+X8rT5TqpyNy69IuFkZs=
-----END CERTIFICATE-----
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# cat server.key 
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK6NcFuf/iA+TmiT
Wxv3nDFpx2YHAyCRA9rkwiA23ubSLmz2jLNk49Rid4Yja7AtGCGO0mOVEqE3jdEN
HsW9A0T+F94YdWNxy7RfMgof2lIV6sXHfJEiyi3SF/LynDiyxZl1pNsKhT15B2rW
QRWcOGgX5jwNeuHM5xqiORCzZZErAgMBAAECgYEAni7hFreL9a5hIhX/5/1hl8oT
gJt0MwwX4UOTxNvU7nqkxew8n8obSXoedPoeeh6zkp26fbI3mtAcfcmVDH94uIqk
hOkq7AFWbkDmFCAwJB6CJWdaLdicP3Qrzpyz7emq0qsHtjxlFS4OHBuPtthTh8fJ
Ey0rsA+B2VTI056NIaECQQDefpHSIm1omTY1U8LQI1AnM76nihkgCl5y0xRNrSAb
07aVP604DdPRcsMFMJ9CZ46JtlR58YrwytDBfaVJfS3xAkEAyNamaUPZFyGFKYjx
83drQBt/7kNERywjoWBz98YHLnzDGuc4BSa6U+oLUMCoUSiskyl3CfPuPIxAm5RT
oI+E2wJAWwZ1Kf8ju7NS1iZagUSxOhiVW33IIa+cTGXG3LCDfl7zR8QxXclqazoE
R09JGKW9TuHlVa5YJYMUPNTmllY8QQJBAKjarza5cH/eEtME7EdCE83mUPzFWVZt
add3/IhI2ijfhDnORG8wTF/Y2oKeN+VkSRPBPPAFQjttv7QOVPEdORkCQGexGcqN
qVgmGIf9LGaumvJzEiNwKmRW/s1/ypqQNLr3LuPw9P96BlbFQCLFWbB1nfCfZ0q5
ObHpOPjys7zWy6M=
-----END PRIVATE KEY-----
 
To actually look at what information is contained in these files, we can use -text option of the openssl commands 'x509' and 'rsa' respectively.
 
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# openssl x509 -in server.pem -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            a2:be:f6:db:7e:8b:d3:fe
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: O=Company, OU=Department, CN=www.example-ca.com
        Validity
            Not Before: Jul 31 14:50:13 2013 GMT
            Not After : Jul 31 14:50:13 2014 GMT
        Subject: O=Company, OU=Department, CN=www.example-ca.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1024 bit)
                Modulus:
                    00:ae:8d:70:5b:9f:fe:20:3e:4e:68:93:5b:1b:f7:
                    9c:31:69:c7:66:07:03:20:91:03:da:e4:c2:20:36:
                    de:e6:d2:2e:6c:f6:8c:b3:64:e3:d4:62:77:86:23:
                    6b:b0:2d:18:21:8e:d2:63:95:12:a1:37:8d:d1:0d:
                    1e:c5:bd:03:44:fe:17:de:18:75:63:71:cb:b4:5f:
                    32:0a:1f:da:52:15:ea:c5:c7:7c:91:22:ca:2d:d2:
                    17:f2:f2:9c:38:b2:c5:99:75:a4:db:0a:85:3d:79:
                    07:6a:d6:41:15:9c:38:68:17:e6:3c:0d:7a:e1:cc:
                    e7:1a:a2:39:10:b3:65:91:2b
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                0B:BA:DD:46:C4:17:E7:9A:EB:FB:5E:19:91:AF:B4:1F:03:A9:8B:6C
            X509v3 Authority Key Identifier: 
                keyid:0B:BA:DD:46:C4:17:E7:9A:EB:FB:5E:19:91:AF:B4:1F:03:A9:8B:6C
 
            X509v3 Basic Constraints: 
                CA:TRUE
    Signature Algorithm: sha1WithRSAEncryption
        7b:eb:43:ad:33:5e:fe:88:fb:ee:92:36:a3:79:3c:bb:6f:47:
        5f:f7:31:87:16:69:0f:3b:ef:6d:53:fe:7b:31:8b:d8:a4:70:
        78:7b:09:83:d2:75:77:8d:1d:a6:80:99:15:a1:c3:08:78:1a:
        18:bc:48:f1:e7:02:fe:55:99:60:ea:ff:c8:97:02:ba:b1:74:
        fb:30:17:b0:64:59:dd:dd:f9:c4:5f:c8:4c:fd:5e:9c:a0:9b:
        f9:76:83:22:83:8f:fc:b2:8d:82:5c:24:a9:e1:e8:ba:10:01:
        19:6c:93:10:d4:be:5f:ca:d3:e5:3a:a9:c8:dc:ba:f4:8b:85:
        91:9b
-----BEGIN CERTIFICATE-----
MIICVjCCAb+gAwIBAgIJAKK+9tt+i9P+MA0GCSqGSIb3DQEBBQUAMEQxEDAOBgNV
BAoMB0NvbXBhbnkxEzARBgNVBAsMCkRlcGFydG1lbnQxGzAZBgNVBAMMEnd3dy5l
eGFtcGxlLWNhLmNvbTAeFw0xMzA3MzExNDUwMTNaFw0xNDA3MzExNDUwMTNaMEQx
EDAOBgNVBAoMB0NvbXBhbnkxEzARBgNVBAsMCkRlcGFydG1lbnQxGzAZBgNVBAMM
End3dy5leGFtcGxlLWNhLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ro1wW5/+ID5OaJNbG/ecMWnHZgcDIJED2uTCIDbe5tIubPaMs2Tj1GJ3hiNrsC0Y
IY7SY5USoTeN0Q0exb0DRP4X3hh1Y3HLtF8yCh/aUhXqxcd8kSLKLdIX8vKcOLLF
mXWk2wqFPXkHatZBFZw4aBfmPA164cznGqI5ELNlkSsCAwEAAaNQME4wHQYDVR0O
BBYEFAu63UbEF+ea6/teGZGvtB8DqYtsMB8GA1UdIwQYMBaAFAu63UbEF+ea6/te
GZGvtB8DqYtsMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAe+tDrTNe
/oj77pI2o3k8u29HX/cxhxZpDzvvbVP+ezGL2KRweHsJg9J1d40dpoCZFaHDCHga
GLxI8ecC/lWZYOr/yJcCurF0+zAXsGRZ3d35xF/ITP1enKCb+XaDIoOP/LKNglwk
qeHouhABGWyTENS+X8rT5TqpyNy69IuFkZs=
-----END CERTIFICATE-----
 
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# openssl rsa -in server.key -text
Private-Key: (1024 bit)
modulus:
    00:ae:8d:70:5b:9f:fe:20:3e:4e:68:93:5b:1b:f7:
    9c:31:69:c7:66:07:03:20:91:03:da:e4:c2:20:36:
    de:e6:d2:2e:6c:f6:8c:b3:64:e3:d4:62:77:86:23:
    6b:b0:2d:18:21:8e:d2:63:95:12:a1:37:8d:d1:0d:
    1e:c5:bd:03:44:fe:17:de:18:75:63:71:cb:b4:5f:
    32:0a:1f:da:52:15:ea:c5:c7:7c:91:22:ca:2d:d2:
    17:f2:f2:9c:38:b2:c5:99:75:a4:db:0a:85:3d:79:
    07:6a:d6:41:15:9c:38:68:17:e6:3c:0d:7a:e1:cc:
    e7:1a:a2:39:10:b3:65:91:2b
publicExponent: 65537 (0x10001)
privateExponent:
    00:9e:2e:e1:16:b7:8b:f5:ae:61:22:15:ff:e7:fd:
    61:97:ca:13:80:9b:74:33:0c:17:e1:43:93:c4:db:
    d4:ee:7a:a4:c5:ec:3c:9f:ca:1b:49:7a:1e:74:fa:
    1e:7a:1e:b3:92:9d:ba:7d:b2:37:9a:d0:1c:7d:c9:
    95:0c:7f:78:b8:8a:a4:84:e9:2a:ec:01:56:6e:40:
    e6:14:20:30:24:1e:82:25:67:5a:2d:d8:9c:3f:74:
    2b:ce:9c:b3:ed:e9:aa:d2:ab:07:b6:3c:65:15:2e:
    0e:1c:1b:8f:b6:d8:53:87:c7:c9:13:2d:2b:b0:0f:
    81:d9:54:c8:d3:9e:8d:21:a1
prime1:
    00:de:7e:91:d2:22:6d:68:99:36:35:53:c2:d0:23:
    50:27:33:be:a7:8a:19:20:0a:5e:72:d3:14:4d:ad:
    20:1b:d3:b6:95:3f:ad:38:0d:d3:d1:72:c3:05:30:
    9f:42:67:8e:89:b6:54:79:f1:8a:f0:ca:d0:c1:7d:
    a5:49:7d:2d:f1
prime2:
    00:c8:d6:a6:69:43:d9:17:21:85:29:88:f1:f3:77:
    6b:40:1b:7f:ee:43:44:47:2c:23:a1:60:73:f7:c6:
    07:2e:7c:c3:1a:e7:38:05:26:ba:53:ea:0b:50:c0:
    a8:51:28:ac:93:29:77:09:f3:ee:3c:8c:40:9b:94:
    53:a0:8f:84:db
exponent1:
    5b:06:75:29:ff:23:bb:b3:52:d6:26:5a:81:44:b1:
    3a:18:95:5b:7d:c8:21:af:9c:4c:65:c6:dc:b0:83:
    7e:5e:f3:47:c4:31:5d:c9:6a:6b:3a:04:47:4f:49:
    18:a5:bd:4e:e1:e5:55:ae:58:25:83:14:3c:d4:e6:
    96:56:3c:41
exponent2:
    00:a8:da:af:36:b9:70:7f:de:12:d3:04:ec:47:42:
    13:cd:e6:50:fc:c5:59:56:6d:69:d7:77:fc:88:48:
    da:28:df:84:39:ce:44:6f:30:4c:5f:d8:da:82:9e:
    37:e5:64:49:13:c1:3c:f0:05:42:3b:6d:bf:b4:0e:
    54:f1:1d:39:19
coefficient:
    67:b1:19:ca:8d:a9:58:26:18:87:fd:2c:66:ae:9a:
    f2:73:12:23:70:2a:64:56:fe:cd:7f:ca:9a:90:34:
    ba:f7:2e:e3:f0:f4:ff:7a:06:56:c5:40:22:c5:59:
    b0:75:9d:f0:9f:67:4a:b9:39:b1:e9:38:f8:f2:b3:
    bc:d6:cb:a3
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCujXBbn/4gPk5ok1sb95wxacdmBwMgkQPa5MIgNt7m0i5s9oyz
ZOPUYneGI2uwLRghjtJjlRKhN43RDR7FvQNE/hfeGHVjccu0XzIKH9pSFerFx3yR
Isot0hfy8pw4ssWZdaTbCoU9eQdq1kEVnDhoF+Y8DXrhzOcaojkQs2WRKwIDAQAB
AoGBAJ4u4Ra3i/WuYSIV/+f9YZfKE4CbdDMMF+FDk8Tb1O56pMXsPJ/KG0l6HnT6
Hnoes5Kdun2yN5rQHH3JlQx/eLiKpITpKuwBVm5A5hQgMCQegiVnWi3YnD90K86c
s+3pqtKrB7Y8ZRUuDhwbj7bYU4fHyRMtK7APgdlUyNOejSGhAkEA3n6R0iJtaJk2
NVPC0CNQJzO+p4oZIApectMUTa0gG9O2lT+tOA3T0XLDBTCfQmeOibZUefGK8MrQ
wX2lSX0t8QJBAMjWpmlD2RchhSmI8fN3a0Abf+5DREcsI6Fgc/fGBy58wxrnOAUm
ulPqC1DAqFEorJMpdwnz7jyMQJuUU6CPhNsCQFsGdSn/I7uzUtYmWoFEsToYlVt9
yCGvnExlxtywg35e80fEMV3Jams6BEdPSRilvU7h5VWuWCWDFDzU5pZWPEECQQCo
2q82uXB/3hLTBOxHQhPN5lD8xVlWbWnXd/yISNoo34Q5zkRvMExf2NqCnjflZEkT
wTzwBUI7bb+0DlTxHTkZAkBnsRnKjalYJhiH/SxmrprycxIjcCpkVv7Nf8qakDS6
9y7j8PT/egZWxUAixVmwdZ3wn2dKuTmx6Tj48rO81suj
-----END RSA PRIVATE KEY-----
 
 
Creating certificate chains. 
We will use the above created self-signed certificate to create a certificate chain.
 
First create a certificate signing request (csr).
 
#> openssl req -new  -days 365 -sha1 -newkey rsa:1024 -nodes -keyout client.key -out client.csr -subj '/O=Company/OU=Department/CN=www.example-client.com'
Generating a 1024 bit RSA private key
......++++++
...............++++++
writing new private key to 'client.key'
-----
 
#> cat client.csr
-----BEGIN CERTIFICATE REQUEST-----
MIIBhzCB8QIBADBIMRAwDgYDVQQKDAdDb21wYW55MRMwEQYDVQQLDApEZXBhcnRt
ZW50MR8wHQYDVQQDDBZ3d3cuZXhhbXBsZS1jbGllbnQuY29tMIGfMA0GCSqGSIb3
DQEBAQUAA4GNADCBiQKBgQDO8uP/6oKzRaEJNdMCj/CbiJ0hcXq9WOGfp2lr1i5g
5IJmXiyiAbt2pKMWr/mU8+C0KoRd9ki+S5tVmTV9PHP0CwlKVdYGv6GWhw6/ZrUv
CUF/2GVtM2bQUPyXbloR+r/Y5o6oxHWbRdcPi+0fytz5SIglebjltmoUhP8UqUeG
yQIDAQABoAAwDQYJKoZIhvcNAQEFBQADgYEALLfrFNqbOfpY50RCR2aSRe5gi1Bf
Vj2RlvqkuWSbNV57MYZMn75bFMWerR3PJPmiFpbj2HnW+UWfKbYepVIqSWl6fio8
InXN379DWzJebqCvHiVHZRg/Fz4HG4WwqEAkfCSuq7UpSHVvQgPoqtnH1bylK9Zm
Ti0eDr8oqeuWxCg=
-----END CERTIFICATE REQUEST-----
 
Now we will use the self-signed  cert as the root cert to sign the above csr.
 
 
#> openssl x509 -req -CA server.pem -CAkey server.key -set_serial 1 -in client.csr -out client.pem -outform PEM
Signature ok
subject=/O=Company/OU=Department/CN=www.example-client.com
Getting CA Private Key
#> openssl x509 -in client.pem  -text
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 1 (0x1)
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: O=Company, OU=Department, CN=www.example-ca.com
        Validity
            Not Before: Aug 13 13:57:55 2013 GMT
            Not After : Sep 12 13:57:55 2013 GMT
        Subject: O=Company, OU=Department, CN=www.example-client.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1024 bit)
 
 
 
Converting PEM format to DER format.
 
The following command converts the certificates and private key files from PEM format to DER format. DER format is just the binary version(Base64 decoded) of the PEM format.
 
#> openssl x509 -in server.pem -inform PEM -out server.der -outform DER
#> openssl rsa -in server.key -inform PEM -out server.key.der -outform DER
writing RSA key
#> ls
server.der  server.key  server.key.der  server.pem
 
If you open the .der file the contents will be in binary form, unlike the .pem files which contained Base64 encoded content.
 
Adding passphrase to the private key.
The private key files created so far were not password protected. We can add passphrase to existing private key files. For example, the following command createa new private key file "server.key.2" with the passphrase "changeit" from the existing file "server.key"
 
#> openssl rsa -des3 -in server.key -inform PEM -out server.key.2 -outform PEM -passout pass:changeit
writing RSA key
#> openssl rsa -in server.key.2 -text
Enter pass phrase for server.key.2:
 
 
Creating PKCS12 file.
A "pkcs12" file format allows you to have both the public certificate and the private key within a single file. 'pkcs12' command allows you to create pkcs12 files from existing certs and private keys.
 
# > openssl pkcs12 -export -in server.pem -inkey server.key -out server.pkcs12
Enter Export Password:
Verifying - Enter Export Password:
#> ls
server.der  server.key  server.key.2  server.key.der  server.pem  server.pkcs12
 
Separating public certificates from pkcs12 file.
 
#> openssl pkcs12 -in server.pkcs12 -clcerts -nokeys -out server_cert_from_pkcs12_file
Enter Import Password:
MAC verified OK
# >ls
server_cert_from_pkcs12_file    server_key_from_pkcs12_file  server.pem  server.pkcs12
 
 
When prompted for password enter the same passphrase given during the creation of pkcs12 file. -clcerts option tells to output only client certificates. -nokeys option tells not to output any private keys. By default the certficate will be created in PEM format.
 
Separating private key from pkcs12 file.
 
#> openssl pkcs12 -in server.pkcs12 -nocerts -out server_key_from_pkcs12_file -nodes
Enter Import Password:
MAC verified OK
 
# >ls
server_cert_from_pkcs12_file    server_key_from_pkcs12_file  server.pem  server.pkcs12