OpenSSL für Webassembly compilieren

Submitted by admin on Fr., 13.04.2018 - 09:19

Mit dem folgenden Skript kann man OpenSSL für Webassembly compilieren.

Voraussetzungen

Das Skript mk-openssl-webassemby.sh:

#!/bin/bash

#######################################################################################
# prerequisites
# * Emscripten
#######################################################################################

GIT=0

# ==> Select latest version for security reasons
OPENSSL_VERSION="1.1.0h"
#OPENSSL_VERSION="1.1.1-pre8"

if [ "$GIT" -eq 1 ]; then
  if [ ! -d openssl ]; then
    git clone --depth 10 https://github.com/openssl/openssl.git
  fi
  cd openssl || exit 1
  git pull
else
  if [ ! -f openssl-${OPENSSL_VERSION}.tar.gz ]; then
    wget https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
  fi

  rm -rf "openssl"
  mkdir openssl
  tar xvf "openssl-${OPENSSL_VERSION}.tar.gz" --strip-components=1 --directory=openssl
  cd openssl
fi

export CC=emcc
export CXX=emcc
export LINK=${CXX}
export ARCH_FLAGS=""
export ARCH_LINK=""
export CPPFLAGS=" ${ARCH_FLAGS} "
export CXXFLAGS=" ${ARCH_FLAGS} "
export CFLAGS=" ${ARCH_FLAGS} "
export LDFLAGS=" ${ARCH_LINK} "
echo  $OSTYPE | grep -i darwin > /dev/null 2> /dev/null
if [ $? -eq 0 ]; then
  OLD=$(pwd)
  HOMEBREW_PREFIX="/usr/local/Cellar/binutils"
  cd $HOMEBREW_PREFIX || exit 1
  TARGET=$(find . -name ar)
  export AR=${HOMEBREW_PREFIX}/${TARGET}
  cd "$OLD"
fi

./Configure \
  purify \
  --openssldir=/tmp \
  --api=1.1.0 \
  no-engine no-dso no-dgram no-sock no-srtp no-stdio no-ui no-err no-ocsp no-psk no-stdio no-ts

PATH=$TOOLCHAIN_PATH:$PATH make

 

Die generierten Files in dem Verzeichnis kann man nun für die eigene Webassembly Anwendung verwenden.

Anwendung

hello.cpp

#include <stdio.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#include <time.h>

#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>

#include "ssl.h"


using namespace std;


void sha256(char *string, char outputBuffer[SHA256_DIGEST_LENGTH+1]) {
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, string, strlen(string));
    SHA256_Final(hash, &sha256);
    int i = 0;
    for(i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
    }
    outputBuffer[SHA256_DIGEST_LENGTH] = 0;
}


string getTime() {
    static char buf[256];
    char fmt[] = "%a %b %d %H:%M:%S %Z %Y";
    time_t now = time(NULL);
    struct tm *tp;
    tp = localtime(&now);
    strftime(buf, sizeof(buf), fmt, tp);
    return buf;
}

int main(int argc, char **argv) {
    static string hello="Hello OpenSSL world "+getTime();
    static unsigned char buffer[65];

    char *chello = new char [hello.length()+1];
    std::strcpy (chello, hello.c_str());
    printf("%s\n", chello);
    sha256(chello, (char *)buffer);
    printf("sha256: %s\n", buffer);

    doTest();

    return 0;
}

ssl.cpp

#include <cstdio>
#include <iostream>
#include <openssl/pem.h>
#include <openssl/x509.h>

/* Generates a 2048-bit RSA key. */
EVP_PKEY * generate_key(int keySize)
{
    /* Allocate memory for the EVP_PKEY structure. */
    EVP_PKEY * pkey = EVP_PKEY_new();
    if(!pkey)
    {
        return NULL;
    }
    
    /* Generate the RSA key and assign it to pkey. */
    RSA * rsa = RSA_generate_key(keySize, RSA_F4, NULL, NULL);
    if(!EVP_PKEY_assign_RSA(pkey, rsa))
    {
        EVP_PKEY_free(pkey);
        return NULL;
    }
    
    /* The key has been generated, return it. */
    return pkey;
}

/* Generates a self-signed x509 certificate. */
X509 * generate_x509(EVP_PKEY * pkey)
{
    /* Allocate memory for the X509 structure. */
    X509 * x509 = X509_new();
    if(!x509)
    {
        return NULL;
    }
    
    /* Set the serial number. */
    ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
    
    /* This certificate is valid from now until exactly one year from now. */
    X509_gmtime_adj(X509_get_notBefore(x509), 0);
    X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
    
    /* Set the public key for our certificate. */
    X509_set_pubkey(x509, pkey);
    
    /* We want to copy the subject name to the issuer name. */
    X509_NAME * name = X509_get_subject_name(x509);
    
    /* Set the country code and common name. */
    X509_NAME_add_entry_by_txt(name, "C",  MBSTRING_ASC, (unsigned char *)"CA",        -1, -1, 0);
    X509_NAME_add_entry_by_txt(name, "O",  MBSTRING_ASC, (unsigned char *)"MyCompany", -1, -1, 0);
    X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"localhost", -1, -1, 0);
    
    /* Now set the issuer name. */
    X509_set_issuer_name(x509, name);
    
    /* Actually sign the certificate with our key. */
    if(!X509_sign(x509, pkey, EVP_sha256()))
    {
        X509_free(x509);
        return NULL;
    }
    
    return x509;
}

bool write_to_stdout(EVP_PKEY * pkey, X509 * x509)
{
    /* Write the key to disk. */
    bool ret = PEM_write_PrivateKey(stdout, pkey, NULL, NULL, 0, NULL, NULL);
    
    if(!ret)
    {
        return false;
    }
    
    /* Write the certificate to disk. */
    ret = PEM_write_X509(stdout, x509);
    
    if(!ret)
    {
        return false;
    }
    
    return true;
}


int doTest(void)
{
    /* Generate the key. */
    std::cout << "Generating RSA key..." << std::endl;
    
    EVP_PKEY * pkey = generate_key(2048);
    if(!pkey)
        return 1;
    
    /* Generate the certificate. */
    std::cout << "Generating x509 certificate..." << std::endl;
    
    X509 * x509 = generate_x509(pkey);
    if(!x509)
    {
        EVP_PKEY_free(pkey);
        return 1;
    }
    
    /* Write the private key and certificate out to disk. */
    std::cout << "Writing key and certificate to stdout..." << std::endl;
    
    bool ret = write_to_stdout(pkey, x509);
    EVP_PKEY_free(pkey);
    X509_free(x509);
    
    if(ret)
    {
        std::cout << "Success!" << std::endl;
        return 0;
    }
    else
        return 1;
}

 

Makefile

all: hello.html

hello.html: hello.cpp ssl.cpp
	emcc -L./openssl-1.1.0h -I./openssl-1.1.0h/include hello.cpp ssl.cpp -s WASM=1 -o hello.html -lssl -lcrypto --emrun

clean:
	rm hello.html hello.wasm hello.js 

 

Mit make lässt sich das compilieren, dabei entsteht unter Anderem eine Datei hello.html, die man mit einem aktuellen Browser ansehen kann.

In Kürze erscheint auf Github eine komplette Anwendung, die Democode für CMS Verschlüsselung und Signaturen enthält.