up
100
作者 jokin 2015-02-27 15:55:50
写了0文章0获得了0条评论
暂无说说 · 评论
how to do http & https request with openssl
字数·6555 评论0 喜欢0 转发0

1, do http request

/* filename nossl.c */
#include "stdio.h"
#include "string.h"

#include "openssl/ssl.h"
#include "openssl/bio.h"
#include "openssl/err.h"

int main()
{
    BIO * bio;
    char resp[1024];
    int  ret;

    //char * request = "GET /cas/login?service=https%3A%2F%2Fweb.corp.ema-tech.com%3A8888%2F HTTP/1.1\x0D\x0AHost: web.corp.ema-tech.com\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A";
    char * request = "GET / HTTP/1.1\x0D\x0AHost: www.verisign.com\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A";

    /* Set up the library */
    ERR_load_BIO_strings();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();

    /* Create and setup the connection */
    //bio = BIO_new_connect("web.corp.ema-tech.com:8888");
    bio = BIO_new_connect("www.verisign.com:80");
    if(bio == NULL) {
        fprintf(stderr, "BIO is null\n");
        return 1;
    }

    if(BIO_do_connect(bio) <= 0) {
        ERR_print_errors_fp(stderr);
        BIO_free_all(bio);
        return;
    }

    /* Send the request */
    BIO_write(bio, request, strlen(request));

    /* Read in the response */
    for(;;) {
        ret = BIO_read(bio, resp, 1023);
        if(ret <= 0) break;
        resp[ret] = 0;
        printf("%s", resp);
    }

    /* Close the connection and free the context */
    BIO_free_all(bio);

    return 0;
}

2, do https request

/* filename withssl.c */
#include "stdio.h"
#include "string.h"

#include "openssl/ssl.h"
#include "openssl/bio.h"
#include "openssl/err.h"

int main(int argc, char *argv[])
{
    BIO * bio;
    SSL * ssl;
    SSL_CTX * ctx;

    char resp[1024];
    int  ret;

    char * request = "GET / HTTP/1.1\x0D\x0AHost: www.verisign.com\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A";
    //char * request = "GET / HTTP/1.1\x0D\x0AHost: worktile.com\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A";
    //char * request = "GET /cas/login?service=https%3A%2F%2Fweb.corp.ema-tech.com%3A8888%2F HTTP/1.1\x0D\x0AHost: web.corp.ema-tech.com\x0D\x0A""Connection: Close\x0D\x0A\x0D\x0A";

    /* Attention: "\x43" is "C", why is "\x43onnection" but not "Connection" ?
       because "\x0AC" in "\x0D\x0AConnection" is taken as a hex value, not the string "\nConnection"
       also, "\x0D""C" can avoid upper problem too.
     */

    /* Init SSL library */
    SSL_library_init();

    /* Set up the library */
    ERR_load_BIO_strings();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();

    /* Set up the SSL context */
    const SSL_METHOD *method = SSLv23_client_method();	/* SSLv3 but can rollback to v2 */
    if (! method) {
        fprintf(stderr, "SSL client method failed\n");
        return 1;
    }
    printf("Method version: %d\n", method->version);

    ctx = SSL_CTX_new(method);
    if (! ctx) {
        fprintf(stderr, "SSL context is NULL\n");
        ERR_print_errors_fp(stderr);
        return 1;
    }

    /* Load the trust store */
    if(! SSL_CTX_load_verify_locations(ctx, argv[1], NULL)) {
        fprintf(stderr, "Error loading trust store\n");
        ERR_print_errors_fp(stderr);
        SSL_CTX_free(ctx);
        return 0;
    }

    /* Setup the connection */
    bio = BIO_new_ssl_connect(ctx);

    /* Set the SSL_MODE_AUTO_RETRY flag */
    BIO_get_ssl(bio, &ssl);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

    /* Create and setup the connection */
    BIO_set_conn_hostname(bio, "www.verisign.com:https");
    //BIO_set_conn_hostname(bio, "worktile.com:https");
    //BIO_set_conn_hostname(bio, "web.corp.ema-tech.com:8888");

    if(BIO_do_connect(bio) <= 0) {
        fprintf(stderr, "Error attempting to connect\n");
        ERR_print_errors_fp(stderr);
        BIO_free_all(bio);
        SSL_CTX_free(ctx);
        return 0;
    }

    /* Check the certificate */
    if(SSL_get_verify_result(ssl) != X509_V_OK)
    {
        fprintf(stderr, "Certificate verification error: %ld\n", SSL_get_verify_result(ssl));
        /*
          Error Tip "error : 19 self signed certificate in certificate chain" means:
          This means the certificate chain returned by the server ends with a ‘self signed certificate’.
          Since the self-signed certificate is not a trusted certificate, it is reported as an error.
          You can make the problem go away by specifying a trusted root CA (certificate authority)
         */
        fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
        ERR_print_errors_fp(stderr);
        BIO_free_all(bio);
        SSL_CTX_free(ctx);
        return 0;
    }

    /* Send the request */
    BIO_write(bio, request, strlen(request));

    /* Read in the response */
    for(;;) {
        ret = BIO_read(bio, resp, 1023);
        if(ret <= 0) break;
        resp[ret] = 0;
        printf("%s", resp);
    }

    /* Close the connection and free the context */
    BIO_free_all(bio);
    SSL_CTX_free(ctx);
    return 0;
}

3, build & test

gcc -o nossl nossl.c -lssl  
gcc -o withssl withssl.c -lssl
./nossl
./withssl ./XXX.pem

4, got a certification verify failed

if you got a certification verify failed, do
- get the trust certification from the server
- tranform into pem format file
- run again

Following is about how to generate a pem file

1, what is pem ?
PEM (short for Privacy Enhanced Mail) is one of the storetypes of CAcerts,
the other one is called DER.

PEM always formated like:

—–BEGIN CERTIFICATE—–
Base64 data flow
—–END CERTIFICATE—–

—–BEGIN CERTIFICATE—–
Base64 data flow
—–END CERTIFICATE—–

DER is another store type, formated like:

binary… binary… binary…

@NOTE the Certificates in a pem is repeatable and not have to be in order

2, how to create a pem ?
2.1, use browser.

  • open the https website with a browser, and click the menu to view Certificate.
  • then export the Certificate to afile use base64-encoded-x509.
  • then you got a pem formated Certificate file.

    @NOTE i use chromium-browser in ubuntu, but the pem files exported is not completed!
    also i use it in windows, those exported is not completed too, But it’s correct
    when use it to connect to website! You can merge them to get a completed pem file.

2.2, use java tools.
TOOLS: keytool InstallCert

    java InstallCert host:port   
    // Have to add all Certificates that printout, it would verify failed even only lack of one Certificate
    keytool -list -rfc -keystore ./jssecacerts -storepass changeit > XXX.pem
    // This would include Certificates of other websites stored in /home/ema/jdk1.7/jre/lib/security/cacerts

2.3, use openssl command line.

    openssl s_client -showcerts -connect host.host:9999 < /dev/null > XXX.pem
    // Also all the Certificates printout should add into the XXX.pem