This step-by-step guide shows the way to smoothly build FIPS capable OpenSSL library for use in the FIPS 140-2 compliant Tomcat server on Windows machines.

What is FIPS 140-2?

The Federal Information Processing Standard 140-2 is a security standard published by the National Institute of Standards and Technology (NIST), covering specification of security requirements for implementing cryptographic modules. Cryptographic module may be either a library, a component of a product or application, or a complete product.

The specifications include e.g. a list of approved algorithms, module inputs and outputs, physical security, cryptographic key management and more areas related to the secure design.

NIST manages a list of FIPS 140-1 and FIPS 140-2 validated cryptographic modules, i.e. modules tested, validated and certified under the Cryptographic Module Validation Program. The complete list can be found here: http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140val-all.htm.

FIPS 140-2 compliant Tomcat

The compliance (unlike FIPS validation) means that only FIPS approved algorithms and validated modules are used in the product, but the product itself was not validated.

Apache Tomcat, an open source Java application server, can use two different implementations of the SSL/TLS protocol, and thus there are two options for achieving FIPS 140-2 compliance:

  • JSSE, the Java implementation – it is needed to have enabled only FIPS validated Java cryptographic providers along with the correct setting of the ciphers and algorithms in the Tomcat HTTPS connector
  • Apache Portable Runtime, the OpenSSL implementation – if FIPS 140-2 is supported by the linked OpenSSL library, so called FIPS Mode can be enabled in the Tomcat settings

OpenSSL FIPS Object Module

OpenSSL library is not FIPS validated. A special software component called OpenSSL FIPS Object Module was created instead.

OpenSSL being compiled with the OpenSSL FIPS Object Module embedded inside is so called FIPS capable OpenSSL. It provides the standard, non-FIPS API as well as a FIPS 140-2 Approved Mode, a setting in products using this library in which only FIPS 140-2 validated cryptography is used and non-FIPS approved algorithms are disabled.

Current version of OpenSSL FIPS Object Module is 2.0 and is compatible with standard OpenSSL 1.0.1 and 1.0.2 distributions.

Step zero: Prerequisites

For the whole following building process, the Developer Command Prompt for Visual Studio is required. It is one of the optional choices offered during VS installation. When installing VS, check the following option (example for VS 2015):

  • Programming languages\Visual C++\Common Tools for Visual C++ 2015

In case Visual Studio is already installed without Developer Command Prompt, you can add this feature by program modification:

Start -> Programs and Features -> Microsoft Visual Studio 2015 -> Change -> Modify

The following window should appear. Again, check the aforementioned option.

The guide was tested using Visual Studio Professional 2015. Both, the aforementioned option for the Developer Command Prompt for Visual Studio installation and batch files needed in the following process, may differ in other versions.

Step one: Getting the source codes

Download the Windows sources for:

Unpack:

  • Tomcat Native
  • OpenSSL FIPS Object Module to a directory outside Tomcat Native.
  • OpenSSL sources to tomcat-native-X\native\srclib\openssl
  • Apache Portable Runtime sources to tomcat-native-X\native\srclib\apr

Step two: Building the OpenSSL FIPS Object Module

Prerequisites:

  • Developer Command Prompt for Visual Studio
  • Extracted OpenSSL FIPS Object Module files
  • Perl installed and location added to the PATH system variable

Compilation (64-bit version):

  1. Open Developer Command Prompt:
    Start -> Developer Command Prompt for VS2015
  2. Add variables for desired environment:
    cd vc
    vcvarsall x64
    
  3. Navigate to the extracted OpenSSL FIPS Object Module sources:
    cd openssl-fips-X\
    
  4. Set needed variables:
    Set PROCESSOR_ARCHITECTURE=AMD64
    Set FIPSDIR=absolute\path\to\Openssl-fips-X
    
  5. [Optional] In case you use Cygwin Perl, you may encounter an error (“No rule for …”) during the build process. In order to prevent this issue, open the openssl-fips-X\util\mk1mf.pl file in text editor, find the first chop; command and add the following to the next row:
    s/\s*$//;
    
  6. Build the OpenSSL FIPS Object Module
    ms\do_fips
    

The compilation process for the 32-bit version:

cd vc
vcvarsall x86
cd openssl-fips-X\
Set PROCESSOR_ARCHITECTURE=x86
Set FIPSDIR=absolute\path\to\Openssl-fips-X
ms\do_fips

Step three: Building the FIPS capable OpenSSL

Prerequisites:

  • Developer Command Prompt for Visual Studio
  • Compiled FIPS module
  • OpenSSL 1.0.1 or 1.0.2 sources extracted in the tomcat-native-X\native\srclib\openssl folder
  • Perl installed and location added to the PATH system variable (note that Cygwin Perl may have issues with backslash in addresses)
  • NASM (Netwide Assembler)  installed and location added to the PATH system variable

Compilation (64-bit version):

  1. Open Developer Command Prompt:
    Start -> Developer Command Prompt for VS2015
  2. Add variables for desired environment:
    cd vc
    vcvarsall x64
    
  3. Navigate to the extracted OpenSSL sources:
    cd native\srclib\openssl\
    
  4. Configure and make:
    perl Configure VC-WIN64A fips --with-fipsdir=absolute\path\to\Openssl-fips-X
    ms\do_win64a
    nmake -f ms\nt.mak
    

The compilation process for the 32-bit version:

cd vc
vcvarsall x86
cd native\srclib\openssl\
perl Configure VC-WIN32 fips --with-fipsdir=absolute\path\to\Openssl-fips-X
ms\do_nasm
nmake -f ms\nt.mak

Version check:

FIPS capable OpenSSL contains information about this fact in its version info. Check the version of your compiled OpenSSL library:

Step four: Building APR

Prerequisites:

  • Developer Command Prompt for Visual Studio
  • Apache Portable Runtime sources extracted in the tomcat-native-X\native\srclib\apr folder

Compilation (64-bit version):

  1. Open Developer Command Prompt:
    Start -> Developer Command Prompt for VS2015
  2. Add variables for desired environment:
    cd vc
    vcvarsall x64
    
  3. Navigate to the extracted APR sources:
    cd native\srclib\apr\
    
  4. Build Apache Portable Runtime:
    nmake -f NMAKEmakefile BUILD_CPU=x64 APR_DECLARE_STATIC=1
    nmake -f NMAKEmakefile BUILD_CPU=x64 APR_DECLARE_STATIC=1 install
    

The compilation process for the 32-bit version:

cd vc
vcvarsall x86
cd native\srclib\apr\
nmake -f NMAKEmakefile BUILD_CPU=x86 APR_DECLARE_STATIC=1
nmake -f NMAKEmakefile BUILD_CPU=x86 APR_DECLARE_STATIC=1 install

By default, the compiled files should appear in C:\include\ and C:\lib\ folders.

Step four and a half: Cleaning the mess

It is recommended to create an appropriate file system structure before proceeding to the compilation of the Tomcat Native library.

Create the following folders:

  • deps
  • deps\openssl
  • deps\openssl\lib
  • deps\openssl\include
  • deps\apr
  • deps\apr\lib
  • deps\apr\include

And copy the following files:

  • native\srclib\openssl\out32\openssl.exe to deps\openssl
  • native\srclib\openssl\out32\ssleay32.lib, native\srclib\openssl\out32\libeayfips32.lib and native\srclib\openssl\out32\libeaycompat32.lib to deps\openssl\lib
  • content of native\srclib\openssl\inc32\ to deps\openssl\include
  • C:\lib\apr-1.lib to deps\apr-1\lib
  • content of C:\include\apr-1\ to deps\apr\include

Step five: Building Tomcat Native library

Prerequisites:

  • Developer Command Prompt for Visual Studio
  • Compiled FIPS capable OpenSSL and APR
  • Java installed and JAVA_HOME system variable leading to the location set

Compilation (64-bit version):

  1. Open Developer Command Prompt:
    Start -> Developer Command Prompt for VS2015
  2. Add variables for desired environment:
    cd vc
    vcvarsall x64
    
  3. Navigate to the extracted Tomcat Native sources:
    cd tomcat-native-X\native\
    
  4. Set needed variables:
    Set CPU=X64
    Set FIPSDIR=absolute\path\to\Openssl-fips-X
    
  5. Build FIPS capable Tomcat Native library
    nmake -f NMAKEMakefile WITH_APR=path\to\deps\apr WITH_OPENSSL=path\to\deps\openssl APR_DECLARE_STATIC=1 [ENABLE_OCSP=1] WITH_FIPS=1
    

The compilation process for the 32-bit version:

cd vc
vcvarsall x86
cd tomcat-native-X\native\
Set CPU=X86
Set FIPSDIR=absolute\path\to\Openssl-fips-X
nmake -f NMAKEMakefile WITH_APR=path\to\deps\apr WITH_OPENSSL=path\to\deps\openssl APR_DECLARE_STATIC=1 [ENABLE_OCSP=1] WITH_FIPS=1

Compiled files should appear in the tomcat-native-X\native\WINXP_X64_DLL_RELEASE or tomcat-native-X\native\WINXP_X86_DLL_RELEASE folder.

Tomcat settings

Now that we have FIPS capable Tomcat Native library, the last action needed is the configuration of Tomcat to use the FIPS validated implementation.

  1. Copy the compiled tcnative-1.dll to your tomcat\bin folder.
  2. In the tomcat\conf\server.xml file edit following tags:
    Enable FIPS Mode for the APR listener:

    <Listener
        className="org.apache.catalina.core.AprLifecycleListener"
        SSLEngine="on"
        FIPSMode="on"
    />
    

    Configure the HTTPS connector to use Native (OpenSSL) implementation of SSL/TLS protocol:

    <Connector
        protocol="org.apache.coyote.http11.Http11AprProtocol"
        …
    />
    
  3. Restart the Apache Tomcat service

And that’s it! Your Tomcat is now using only FIPS approved algorithms and FIPS validated implementations.

Highest tested versions

This guide was tested with the following component versions:

  • Apache Portable Runtime 1.5.2
  • OpenSSL 1.0.2l
  • OpenSSL FIPS Object Module 2.0.16
  • Tomcat Native 1.2.12

I study Faculty of Information Technology at VUT in Brno and the main aim of my bachelor thesis is a research of developing the cross-platform desktop applications. The adult spends approximately 2.5 hours per day on desktop computers as shown by the statistics that took place between 2008 and 2015. While the time spent on mobile phones increases, the time spent on desktop computers is, on the other hand, not decreasing. In my opinion, this has a great potential in developing a single desktop application that can be run on all major operating systems. An application such as this that can be built via Electron framework.

Electron

It is an open-source framework that allows the creation of native desktop applications on Linux, Windows and macOS platforms with web technologies like JavaScript, HTML, and CSS. A combination of Chromium and Node.js makes this possible. The application that is created by Electron has all the benefits of a native desktop application, such as access to the file system or system notifications. It is recommended to use the npm package manager of Node.js while developing the application. With the npm, a developer can record the necessary modules during development into the package.json file, run the application itself, etc.

Processes

In the Electron application, there are two types of processes: the main process and the renderer process. Each one has its own unique role. The process that runs script specified in the package.json as the main one is called the main process. The main process runs renderer processes and takes care of communicating with the API of the operating system. It allows developing the application with OS’s native GUI. Each renderer process renders the content of one web page. The renderer process runs in isolation from other renderer processes.

Development basic application

To develop basic Electron application, it is necessary to create three files: firstly, package.json with information about the application. Secondly, JavaScript file which will be run as the first one and, lastly, HTML file for creating GUI of application (i.e. the web page). The folder-structure of basic application can look like:

app/
├── package.json
├── main.js
└── index.html

To run the application, you can download last Electron release from the web and copy app folder to the downloaded application as below and execute binary electron (electron.exe on Windows, etc.).

Folder-structure of Electron application on macOS

electron/Electron.app/Contents/Resources/
└── app/

Folder-structure of Electron application on Windows and Linux

electron/resources/
└── app/

Application distribution

After the application is developed, the developer can package the app folder into asar archive instead of distributing the app’s source code. In such a case, the app folder can be replaced, which includes the source code with app.asar package.

There are three options for distribution. The first one is to manually download all the latest versions of Electron for the necessary platforms and copy the application to the appropriate folder. Using the command line, a third-party tool Electron-packager creates also these packages. The second option, which includes creating install files, is to use the tools also from third parties: Electron-builder or Electron-windows-store.The last option, which includes distributing source code instead of package asar, is to use npm package manager.

The tool Electron-builder uses Electron-packager and creates the file needed to install the application. The format of the installer, that Electron-builder supports for Windows is NSIS. The most widely used packages for Linux are the deb, rpm, freebsd and apk. Similarly, for macOS there are dmg, pkg and mas. Electron-builder also supports automatic updates. If there are dependencies to the native operating system, compilation is required on this system. Otherwise, it is possible to compile application on a selected operating system or use some build server such as AppVeyor for Windows and Travis for Linux and macOS.

Other tool developed by Microsoft for compiling Electron applications into the .appx package is called Electron-windows-store. The tool is available from Microsoft PowerShell. Electron-windows-store can be used only in the operating system Windows 10 with Anniversary Update. Application format for windows store will be generated from the package of the Electron-packager tool. Requirements to compile application:

  • You must have a certificate that supports the application
  • The Windows 10 SDK
  • Node.js with a minimum version of 4.

The last option is to distribute only the source code and use the npm package manager to install dependencies and run the application. It is necessary to have all dependencies in the package.json file. Then, user just downloads the source code and executes these commands:

#to install all dependencies
$npm install
#to run application
$npm start

What we do

We create intelligent enterprise office solutions that build smart business and empower employees to be more productive and creative.

Our YSoft SafeQ Workflow Solutions Platform is used by more than 14,000 corporations and SMB organizations from over 120 countries to manage, optimize and secure their print and digital processes and workflows. Our 3D print solutions are focused in the Education sector where they provide unique workflow and cost recovery benefits.

Through YSoft Labs, we experiment with new technologies for potential new products. We accelerate the technology growth of other innovative companies through Y Soft Ventures, our in-house investment arm.

 

Our Culture

Y Soft culture is defined by our 6 attitudes. We don’t say they are right or better. We say they are ours – created by employees for employees. We are always seeking people who share similar attitudes because our culture should live on through all Y Softers.

 

values

Headquartered in the Czech Republic, we employ over 370 dedicated people around the world. Our R&D centers are in Brno, Prague and Ostrava, Czech Republic, but you can also meet Y Softers in North and Latin America, Dubai, Singapore, Japan or Australia. Together we have 17 offices in 16 countries.

 mapa

R&D – At Y Soft it is a CRAFT

Unlike other technology companies, whose R&D departments only implement the vision of others, Y Soft employees regularly contribute ideas and help shape the direction of new products.
For us, R&D is a craft — a craft we continuously build upon to expand the R&D know-how in the Czech Republic. We believe in DevOps and have finished the first stage in building our own production grade environment. We are also building a core competency in UI design. Our developers transform their talent into solutions with high added value that impress our customers around the world. We inspire each other with our dedication to quality, by using the most up to date technologies, and in designing, developing and integrating our own hardware and software. We challenge ourselves daily to change the world.img_8833

We are building large-scale connected, global systems for demanding customers (nearly 25% of the Fortune Global 500 use Y Soft’s solutions). This level of customer satisfaction is achieved through R&D’s open access to customers and the opportunity to meet with company executives to discuss and influence R&D direction.

We also work with many young startups through our in-house venture arm, which exposes you to new ideas and mentors to see if entrepreneurship is a future path for you. We offer opportunities to work with thesis students at local universities and reward employees who contribute to our intern’s success.

img_9543

Want more from Y Soft?

We are growing and can offer you an exciting, rewarding career with a wide range of opportunities to utilize your skills and to grow personally and professionally.

In latest project we came across the problem of securing communication, where peers don’t share backend language. Our goal was to securely generate shared secret between Java server and .NET client. Each language supports all features needed for the key agreement, but these features aren’t always compatible, due to different encoding or data representation.

This article should be quick and easy solution how to agree on shared secret between such server and client with hand-on examples. Each subchapter contains concrete example on how to send, receive and process data needed for respected operation. Authentication and signature scheme are similar to guides published internet-wide, the main topic- key agreement is presented with our insights and comments on how to make it work.

The reason I have included all the code snippets even if they are “straight from internet” is that I wanted to simply group all these schemes to one place, so that you don’t have to find examples on Oracle, CodeRanch, StrackOverflow, MSDN Microsoft documentation, … Honestly it was a little bit frustrating for me, so there you go 🙂

If you are interested just in key agreement, feel free to skip right to the key agreement example, as I would like to discuss authentication and signature schemes first in order to prevent attacks on anonymous key agreement.

Please beware of incautious use of the published code. Your protocol might require different configuration and by simple copy-pasting you may introduce some security issues or errors to it.

Certificate based authentication

Consider each peer to have certificate signed by some root CA.

In my examples I’ll be working mostly with byte arrays as it is most universal way to represent data.

In most cases whole certificate chain is transferred to other side. Using one certificate (self-signed) is just simplification of process below.

.NET authentication

Java peer can transform certificate into byte array using Certificate.getEncoded() method. Byte array is then sent to counterpart.

.NET peer parses certificate chain data and stores parsed certificates into List<byte[]> to ease processing.

Code below shows the authentication process. Process differs from standard validation in a way, that we are sending only certificate chain. From the chain peers certificate is extracted. From the rest of received certificate chain we create subchain and check if we were able to create complete chain from peer to Certificate Authority.

For simplicity revocation checks and certificate usage field (OID of the field – 2.5.29.15) are being ignored. In real environment you should definitely check this list and field, but in this article it is not really necessary.

/**
* receivedCertificateChain previously transformed byte array containing whole certificate chain. This chain is transformed
*                          into list of separate certificates from chain 
*/
public bool certificateChainValidation(List<byte[]> receivedCertificateChain)
{
  var otherSideCertificate = new X509Certificate2(receivedCertificateChain[0]);
  var chain = new X509Chain { ChainPolicy = { RevocationMode = X509RevocationMode.NoCheck, VerificationFlags = X509VerificationFlags.IgnoreWrongUsage } };
  chain.ChainPolicy.ExtraStore.AddRange(receivedCertificateChain.Skip(1).Select(c => new X509Certificate2(c)).ToArray());

  return chain.Build(otherSideCertificate));
}

Root CA certificate must be trusted by your system to be successfully validated.

Java authentication

.NET peer can transform each certificate into byte array using X509Certificate2.RawData property and send it to counterpart.

First, Java peer needs to define validation parameters and Trust anchor. In this case it’s root CA.

After that, you validate received certificate chain. If method validate(CertPath, PKIXParameters) is processed without any exception, you can consider received certificate chain correctly validated.

/**
* certificatePath received data of certificate chain from counterpart 
*/
public boolean certificateChainValidation(byte[] certificatePath) {
  try {
    //generate Certificate Path from obtained byte array
    CertificateFactory cf = CertificateFactory.getInstance(“X.509”);
    CertPath received = cf.generateCertPath(new ByteArrayInputStream(certificatePath));

    //get all trusted entities from dedicated truststore
    Set<TrustAnchor> trustedCAs = getAnchors();

    //set the list of trusted entities and turn off the revocation check
    //revocation is by default set to true, so if you don't turn it off explicitly, exceptions will bloom
    PKIXParameters params = new PKIXParameters(trustedCAs);
    params.setRevocationEnabled(false);

    CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
    //if no exception is thrown during validation process, validation is successful
    cpv.validate(received, params);
  } catch (CertificateException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | CertPathValidatorException e ) {
    throw new CertificateException("Could not validate certificate", e);
    return false;
  }
  return true;
}

getAnchors() is a method which simply loads all entries from dedicated truststore and returns them as Set<TrustAnchors>.

Signatures

Without correct signature scheme whole authentication scheme would be compromised, as any attacker would be able to replay intercepted certificate chain. Therefore while sending outgoing certificate chain, each peer has to include signature to it. It is sufficient for such signature to be reasonably short (resp. long) nonce. This nonce should be freshly generated by the communication counterpart and can be sent before authentication attempt (or as an authentication challenge). Nonce could be any-random value or  static counter, but must be definitely unique.

During the key agreement phase, signatures are used to sign public keys that are exchanged between peers to ensure the integrity of data.

.NET signature generation

First you need to use certificate with included private key – PKCS#12 certificates.

Flags as PersistKeySet and Exportable have to be included to certificate loading, as without them you are not able to obtain private key for signatures from the keystore. PersistKeySet flag ensures that while importing certificate from .pfx or .p12 file, you import private key with it. Exportable flag means that you can export imported keys (mainly private key).

As mentioned in this comment we need a little workaround to force crypto provider to use SHA256 hashes.

public byte[] signData(byte[] dataToSign)
{
  X509Certificate2 cert = new X509Certificate2(PATH_TO_CERTIFICATE, PASSWORD, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
  RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)cert.PrivateKey;
 
  RSACryptoServiceProvider rsaClear = new RSACryptoServiceProvider();
  // Export RSA parameters from 'privateKey' and import them into 'rsaClear'
  // Workaround to force RSACryptoServiceProvider use SHA256 hash
  rsaClear.ImportParameters(privateKey.ExportParameters(true));
  return rsaClear.SignData(dataToSign, "SHA256");
}

Java signature generation

Straight-forward example presented internet-wide.

/**
* data       data to be signed
* privateKey private key imported from key pair storage
*/
public byte[] signData(byte[] data, PrivateKey privateKey) {
  try {
    Signature signature = Signature.getInstance(signatureType);
    signature.initSign(privateKey);
    signature.update(data);
    return signature.sign();
  } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
    throw new SignatureException(“Could not create signature”, e);
    return null;
  }
}

.NET signature verification

First thing to mention is, that you shouldn’t create X509Certificate2 object directly from byte arrays (5th tip in this article). Depending on use of your protocol it might result into stalling and slowing whole protocol, what you definitely don’t want. But again, for simplicity I’m creating object from byte array directly. Mitigation of mentioned problem can be seen in linked article.

/**
* signature    signature of received data
* receivedData data received from counterpart. These data were also signed by counterpart to ensure integrity
*/
public bool verifySignature(byte[] signature, byte[] receivedData)
{
  X509Certificate2 cert = new X509Certificate2(PATH_TO_CERTIFICATE);

  RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
  return publicKey.VerifyData(receivedData, "SHA256", signature);
}

Java signature verification

Straight-forward example presented internet-wide.

/**
* receivedData data received from counterpart
* signature    signature of receivedData
* publicKey    public key associated with privateKey object from "Java signature generation"
*/
public boolean verifyData(byte[] receivedData, byte[] signature, PublicKey publicKey) {
  try {
    Signature signature = Signature.getInstance(“SHA256withRSA”);
    signature.initVerify(publicKey);
    signature.update(receivedData);
    return signature.verify(signature);
  } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
    throw new SignatureException(“Could not validate signature”, e);
    return false;
  }
}

 

Key pair generation

Both, key pair generation and key agreement use BouncyCastle library (BC) for the crypto operations. During key generation phase, you need to specify key agreement algorithm. In this project we used elliptic curve Diffie-Hellmann (“ECDH”) key agreement. Elliptic curves were used to generate key pair mainly due to their advantages (performance, key size).

.NET key pair generation

The only difference from standard key generation is encoding of generated public key in a way that Java will accept the key and is able to create PublicKey object.

private static AsymmetricCipherKeyPair generateKeypair()
{
  var keyPairGenerator = GeneratorUtilities.GetKeyPairGenerator("ECDH");
  var ellipticCurve = SecNamedCurves.GetByName(ELLIPTIC_CURVE_NAME);
  var parameters = new ECDomainParameters(ellipticCurve.Curve, ellipticCurve.G, ellipticCurve.N, ellipticCurve.H, ellipticCurve.GetSeed());
  keyPairGenerator.Init(new ECKeyGenerationParameters(parameters, new SecureRandom()));
  return keyPairGenerator.GenerateKeyPair();
}

Now you need to send public key to other peer. Unfortunately, it is necessary to format public key in following way, otherwise Java peer will not be able to correctly create PublicKey object and create shared secret.

AsymmetricCipherKeyPair keyPair = generateKeypair();
byte[] publicKeyData = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public).GetDerEncoded();

Java key pair generation

public static KeyPair generateKeyPair() {
  try {
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
 
    ECNamedCurveParameterSpec ecNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec(ELLIPTIC_CURVE_NAME);
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDH", PROVIDER);
    keyPairGenerator.initialize(ecNamedCurveParameterSpec);
    return keyPairGenerator.generateKeyPair();
  } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchProviderException e) {
    throw new EncryptionException("Could not generate key pair", e);
  }
}

 

Key agreement

.NET key agreement

At this step, you need to beware the issue in C# BoucyCastle library, which results into failed key agreement even if you have correct keys (correct means same data, but different indentation => 0x0059534F4654 is different from 0x59534F4654).

Problem is that BC library creates shared secret as BigInteger. BigIntegers trims all leading zeroes and at conversion from it to byte array these zeroes aren’t included into array.

Unfortunately until publication day issue wasn’t still fixed in BC and you need to check key lengths by yourselves.


private static byte[] DeriveKey(AsymmetricCipherKeyPair myKeyPair, byte[] otherPartyPublicKey)
{
  IBasicAgreement keyAgreement = AgreementUtilities.GetBasicAgreement(KEY_AGREEMENT_ALGORITHM);
  keyAgreement.Init(myKeyPair.Private);

  //check otherPartyPublicKey length

  //shared secret generation
  var fullKey = keyAgreement.CalculateAgreement(PublicKeyFactory.CreateKey(otherPartyPublicKey)).ToByteArrayUnsigned();  
  return fullKey;
}

Java key agreement

Straight-forward example presented internet-wide.

public SecretKey secretDerivation(PublicKey receivedPublicKey, PrivateKey myPrivateKey) {
  try {
    KeyAgreement keyAgreement = KeyAgreement.getInstance(KEY_AGREEMENT_ALGORITHM, PROVIDER);
    keyAgreement.init(privateKey);
    keyAgreement.doPhase(publicKey, true);
    return keyAgreement.generateSecret(“AES”);
  } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException e) {
    throw new EncryptionException("Could not generate secret", e);
  }
}

 

From these examples You might gain bad feeling as all examples are rather brute and messages aren’t sent/received in no standard way- only as byte arrays. Best way is to exchange protocol messages in more standardized way. By doing so, you start heavily relying on third party library.

More standardized version of protocol should use Cryptographic Message Syntax. We will have a closer look on this option in next blog article.

This is an introduction to UAM project – management server for Universal appliances (new TPv4, eDee and SafeQube) and the Vert.x framework on which it is developed.

There was a need for easy installation and upgrade of OS and applications running on an UA so we needed a system to manage UAs with as little user interaction as possible.
The main requirements are robustness (we will deal with unrealiable networks and possible power outages), small executables (there is limited storage on the SafeQube) and little disk access (we don’t want to wear out our SafeQube flashdisks).

UAThe system has 2 parts:

  • UA management server – server application which will be deployed next to CML and will contain APIs for system administration
  • UA management server proxy – application cluster which will be deployed on SafeQubes and will cache application binaries and configuration

Both applications are developed using Vert.x framework. UAM server uses also database as configuration storage and proxy applications use Hazelcast for clustering.

Vert.x is an application framework for programming servers (especially web servers). It is built on top of Netty so no application container like Tomcat or Jetty is necessary.

I will show several examples of working with Vert.x so you can try out writing your own applications.

Starting a web server is simple:

vertx.createHttpServer()
    .requestHandler(request -> {
        System.out.println("Received request from " + request.remoteAddress().host());
    })
    .listen(80);

Using this approach is fast, but you have to handle which business logic to call for which endpoint and it can get quite messy.
Fortunately, we can do better using Vert.x web module:

Router router = Router.router(vertx);
router.route("/hello").handler(context -> {
    String name = context.request().getParam("name");
    context.response().end("Hello " + name);
});

router.get("/ping").handler(context -> {
    context.response().end("Pong!");
});

vertx.createHttpServer()
     .requestHandler(router::accept)
     .listen(80);

This way, we can easily separate business logic for our endpoints.

Do you need request logging or security? You can add more routes for same endpoints. Routes are then processed in the order of addition to the router and can call next route in the chain or just end the response.

Router router = Router.router(vertx);
router.route().handler(CookieHandler.create());
router.get("/secured-resource").handler(context -> {
    if ("password".equals(context.getCookie("securityToken"))) {
        context.next();
    } else {
        context.response().setStatusCode(401).end("sorry, you are not authorized to see the secured stuff");
    }
});

router.get("/secured-resource").handler(context -> {
    context.response().end("top secret stuff");
});

Do you want more than just APIs? There are template engines for Handlebars, MVEL, Thymeleaf or Jade if you want to use their functionality.

router.get().handler(TemplateHandler.create(JadeTemplateEngine.create()));

Things get more interesting when you configure Vert.x instances to form a cluster. Currently, the only production ready cluster manager is built on top of Hazelcast, so we will use it.

VertxOptions options = new VertxOptions();
options.setClustered(true);
options.setClusterHost("192.168.1.2");

Vertx.clusteredVertx(options, result -> {
    if (result.succeeded()) {
        Vertx vertx = result.result();
        //initialize what we need
    } else {
        LOGGER.error("Failed to start vertx cluster", result.cause());
    }
});

As you can see, starting Vert.x cluster isn’t that complicated. Just be careful to set correct cluster host address or you may find out that the cluster doesn’t behave how you would expect.
And what functionality is available for clustered applications? There is clustered event bus, where you can use point-to-point or publish-subscribe messaging. Just register your consumers and send them messages to logical addresses without ever caring on which node the consumer resides.

vertx.eventBus().consumer("/echo", message -> {
    message.reply(message.body());
});

vertx.eventBus().send("/echo", "ping");

I hope this short introduction to Vert.x will make you curious to look at its documentation and start writing your own applications on top of it.

One of the systems our team develops is UI for end-users, where users can view and manage their print related data.

The system is designed as a simple web application, where we make AJAX calls to Spring controllers which delegate the calls to two other systems, no database is present.

One of the requirements on the system was to support about 1000 concurrent users. Since Tomcat has by default 200 threads and the calls to the other systems may take long (fortunately it’s not the case at the moment), we have decided to make use of Servlet 3.0 async. This way, each AJAX call from the browser uses up Tomcat thread only for preparation of a call to other system. The calls are handled by our asynchronous library for communication with SafeQ and asynchronous http client for communication with Payment System which both have own threadpools and fill in the response when they get a reply.

Since we depend so much on other systems’ performance, we wanted to monitor the execution time of the requests for better tracking and debugging of production problems.

There are several endpoints for each system and more can come later, so in order to avoid duplication, we have decided to leverage Spring aspect programming support. We have created an aspect for each business service (one for SafeQ, one for Payment System) and it was time to implement the measurement business logic.

In synchronous scenario, things are pretty simple. Just intercept the call, note start and end time and if it took too long, just log it in a logfile.

@Around("remoteServiceMethod()")
public Object restTimingAspect(ProceedingJoinPoint joinPoint) throws Throwable {
    long start = System.currentTimeMillis();

    Object result = joinPoint.proceed();

    long end = System.currentTimeMillis();

    long executionInMillis = end - start;
    if (executionInMillis &gt; remoteServiceCallDurationThresholdInMillis) {
        LOGGER.warn("Execution of {} took {} ms.", joinPoint, executionInMillis);
    }

    return result;
}

This won’t work in our asynchronous case. The call to joinPoint.proceed(), which will make call to other system returns immediately without waiting for a reply. Reply is processed in a callback provided to one of async communication libraries. So we have to do a bit more.

We know the signature of our business methods. One of the arguments is always callback, which will process the reply.

public void getEntitlement(ListenableFutureCallback callback, String userGuid, Long costCenterId)

If we want to add our monitoring logic in a transparent way, we have to create special callback implementation, which will wrap the original callback and track the total time execution.

class TimingListenableFutureCallback implements ListenableFutureCallback {

    private ListenableFutureCallback delegate;
    private StopWatch timer = new StopWatch();
    private String joinPoint;

    public TimingListenableFutureCallback(ListenableFutureCallback delegate, String joinPoint) {
        this.delegate = delegate;
        this.joinPoint = joinPoint;
        timer.start();
    }
        
    @Override
    public void onSuccess(Object result) {
        logExecution(timer, joinPoint);
        delegate.onSuccess(result);
    }

    @Override
    public void onFailure(Throwable ex) {
        logExecution(timer, joinPoint);
        delegate.onFailure(ex);
    }
}

And then we have to call the target business method with properly wrapped callback argument.

@Around("remoteServiceMethod() && args(callback,..)")
public Object restTimingAspect(ProceedingJoinPoint joinPoint, ListenableFutureCallback callback) throws Throwable {
    String joinPointName = computeJoinPointName(joinPoint);
    
    Object[] wrappedArgs = Arrays.stream(joinPoint.getArgs()).map(arg -> {
        return arg instanceof ListenableFutureCallback ? wrapCallback((ListenableFutureCallback) arg, joinPointName) : arg;
    }).toArray();
    
    LOGGER.trace("Calling remote service operation {}.", joinPointName);
    
    return joinPoint.proceed(wrappedArgs);
}

There is similar implementation for the other async messaging library.

I hope this solution will help you solve similar problems in your applications in an elegant manner 🙂