Saturday, February 14. 2015
Back again with the WebCryptoAPI
If you usually follow the blog you already know about the Web Cryptography API, it is a new standard JavaScript API to perform cryptography operations inside the browser. I felt depressed the last time I tried to play with it, because it does not cover any of the typical scenarios I have faced in my professional life (digital signature mainly). The last months the Charles Engelke’s blog have been publishing some beautiful articles about the same subject, and I think that I have finally understood what the final goal of the API is.
Charles Engelke's last entry plays with WebCryptoAPI and X509 certificates. He parses a self-signed certificate, extracts its public key and signature and validates the latter (in a self-signed certificate the signature is signed by itself, by the private key associated with the certificate, so it is verified with its public key counterpart). In today's entry I decided to test it by myself but doing some minor changes.
A RSA key pair and a certificate were created using openssl.
$ openssl genrsa -des3 -out server.key 2048 $ openssl req -new -key server.key -out server.csr -x509 -subj "/C=ES/L=Madrid/O=Home/CN=TestSign" -days 7300
Finally I exported the key pair and the certificate to a PKCS12 file.
$ cat server.key server.csr > server.pem $ openssl pkcs12 -export -in server.pem -out server.pkcs12 -name testsign
In order to test that everything was working, a simple Sign.java class was implemented to perform a signature using the previously created key pair and then validating it.
$ java Sign "sample text" Singature:U72gD6t14VpCqKitUTEcBfa0TqXte/IPFLOF0wms+HfU+eTrEDQwZLZtZ0ju988JY/JsGElN9gxM apEKFnjiaS2O0qXMGrSSALgDKbGkSlvishFXysfYrWcYEn2/2mfuI3i9MYFqu2LgOTr1GC/jHqFm W0UW5NuRJCDaFEBbQBzedcuXuzKNcu18uFvUV2zJyHliuViU7L4m12vK9reFUTj7ghZBml62Lpxl g6CgjDdvBqy7tBh17k3OjHfINZiHLRb5ZA+3+YJRBAA2yOjUgaCWuGlwtqbLlWiuzxHF3XQxV/yh ad5Xw0RHdANLhiJixXuOTRbzEdLYHhBU7iL0Cw== Is signature OK? true
The class just loads the certificate and the key pair from the PKCS12 store and signs the text passed as the first argument. It shows the signature (in BASE64) and verifies it.
At this point I decided to change a bit what Charles was doing, instead of verifying the signature of the self-signed cert I was going to verify any signature (it is almost the same). So I collected all the JS code that Charles presented in the entry and prepared a static HTML page which is included at the end of the entry.
As you can see it is a simple page that places the certificate in PEM format, the text signed previously with the Java command and the resulting signature in three different text areas. If you have a browser that supports the WebCryptoAPI the signature can be verified clicking the button (following the notes from Engelke's blog the certificate is parsed to recover the public key and with it the signature is verified just using JavaScript).
So now I understand a bit more what this API is about. Right now the standard just implements the cryptographic operations in raw. All the operations are done using direct access to the keys (for example in this entry the public key is read from the certificate and then imported into the crypto object to be used). Therefore for the moment no hardware tokens can be used. Second thing I have clear now, the standard does not know anything about what a certificate is. The Engelke's code just parses a certificate (ASN.1 format) manually in order to obtain the real bits of its public key and it does not check certificate dates or the trusted chain (signature verification just performs the mathematical algorithm). Instead of verifying the signature a real signature could have been done but, as the private key is needed, the real bits of the private key should have been provided to the JS code (in another textarea for example). In other words, WebCryptoAPI can sign anything, but the RSA private key is needed to do that and, at this moment, there is no way to access to internal X509 user certificates and their associates keys (the private key should be passed to JavaScript directly).
As a result of this little PoC the WebCryptoAPI needs two things in order to properly handle with the signature use-case:
The API should offer operations to handle keys in hardware tokens (PKCS#11 or similar).
The API should provide methods to manage certificates (Engelke's methods are wonderful but you know, this is an API, please do it nicely) and to access the internal (browser) user certificate store (maybe it could be just incorporated as another token). Obviously this is a risky operation and some confirmation from the user should be requested. But this is not a strange behavior, exactly the same thing is done when mic or camera are requested in WebRTC or when a site requires a user certificate to log the user in. With those methods the JS code could recover the internal certificate and the private and public key associated with it.
I think that, more or less, both requests are already in mind of the W3C group as the report of the workshop states. Hardware token are specially important because the second point depends on it (nowadays a personal certificate is always inside a secure hardware token, for example a lot of national eIDs work this way). The second point is exactly what people of Inventive Designers demanded in their presentation.
Finally in order to present a more workable PoC I prepared a little restful WS application that has the self-signed certificate inside and can sign and verify using WS in the server. The idea is you can sign any text and verify it using internal (using WebCryptoAPI in a capable browser) or external method (using WS and executing in the server).
The following video shows the little application. Using the firefox developer edition (iceweasel in Jessie is version 31.4 and does not support the API yet) I access the main page. First the certificate is requested to the server. Then some sample text is signed and verified externally. When the verification is internally done, the browser parses the certificate, obtains the public key and verifies the signature using the WebCryptoAPI. If the text is modified but not signed (the previous signature is still in the textarea) both validation fails.
Here you can download the maven project for the application.
This entry is a little test I did just to understand what the WebCryptoAPI can and cannot do. After I read the interesting entries about the same subject done by Charles Engelke I finally understood the idea behind the API. It presents methods for typical cryptographic operations in a basic raw mode. Until now there are no certificates or hardware tokens and, therefore, direct access to real key bits are needed. So, in my opinion, this API is just an entry point to be completed by a second one or an extension of this one.
Stay tuned for news about the WebCryptoAPI!
Example page
Sunday, February 1. 2015
Command tool to display JMX attributes
This week a colleague asked to our engineers' mailing list how the jconsole tool retrieved the attributes that are shown in this graphical application. Her customer wanted to use the command line to obtain some data from one application instead of the graphical environment that jconsole shows. As you know the jconsole is a JMX (Java Management Extensions) client application that connects to a JMX server in order to display and plot the information provided by the different MBeans. A Managed Bean (usually just MBean) represents a resource running in the Java virtual machine which can be used to collect statistics, to get or set configuration properties and to notify events. It is also important that any Java application can be a JMX server just defining the com.sun.management.jmxremote property, in order to have its own monitoring it will need to register its own MBeans (if no custom beans are added only the default Java monitoring will be possible).
I knew that the technology provides also an API, so I supposed that the jconsole tool uses it to display all the data. Finally I decided to implement a little Java class that uses the API to obtain some sample data from any Java application with JMX activated. I sent to my colleague that little and shoddy main class file (just as an example of how JMX works). Today's entry is going to improve that class and presents a simple java command to display the attribute values of any MBean inside a JMX server.
Tomcat is going to be the JMX server. For that reason it is needed to configure the Servlet container to display JMX information. JMX monitoring was configured to request username and password in a plain (not SSL / TLS) connection adding the following properties to the startup catalina.sh file.
CATALINA_OPTS="${CATALINA_OPTS} -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access -Dcom.sun.management.jmxremote.ssl=false"
The two files specified contains the users and passwords (jmxremote.password) and the permissions for each user (jmxremote.access).
$ cat jmxremote.password monitorRole tomcat controlRole tomcat $ cat jmxremote.access monitorRole readonly controlRole readwrite
With those properties you can already execute the jconsole command and connect to the tomcat process in order to check if JMX is working. The JMX server displays a Catalina domain with a lot of internal tomcat information. For example in the MBeans tab, the object Catalina → Servlet → //localhost/sample-jersey2 → es.rickyepoderi.samplejersey2.Application → none → none → Attributes shows statistical information of the jersey servlet of the previous entry (which is still deployed in the tomcat server).
And now let's present the java program. I developed it mainly following the JMX tutorial. The JmxExplorer utility is a very simple program to read the attributes exposed for the different MBeans. But in order to find the correct bean some more options are available. First you just have to compile the java file (JDK 7 or newer is needed) and then the usage help is shown.
$ javac JmxExplorer.java $ java JmxExplorer Exception in thread "main" java.lang.IllegalArgumentException: ERROR: No command specified USAGE: java JmxExplorer options command options: -U|--url: JMX url to connect to (default: service:jmx:rmi:///jndi/rmi://:9010/jmxrmi) -u|--username: username for the JMX connection (deafult: null) Use "-" to request the password interactively -p|--password: password for the JMX connection (deafult: null) command: local: list the local JMVs in the machine (pid, JMX url and command line) "tools.jar" is needed, please add ${JAVA_HOME}/lib/tools.jar to the classpath domains: list the JMX domains that exist in the server mbeans [<pattern>]: list the mbeans in the server (if pattern is specified only the ones that matches it) info <mbean>: list the attribute names of the mbean specified attrs <mbean> [<attr>...]: list the attribute values of the mbean specified (if no attrs are specified all attributes are returned) at JmxExplorer.usage(JmxExplorer.java:149) at JmxExplorer.main(JmxExplorer.java:423)
The tool can show the local JMX url for the VMs that are running locally (it uses the Attach API for doing that). The problem is that this API is inside the tools.jar. So in order to execute that command the jar should be included in the execution classpath (the tool calls this API using reflection, so it is not needed for executing the rest of the commands or compilation).
$ java -cp /usr/lib/jvm/default-java/lib/tools.jar:. JmxExplorer local 4022 - JmxExplorer local 2388 - sun.tools.jconsole.JConsole 2712 - org.netbeans.Main --cachedir /home/ricky/.cache/netbeans/8.0.2 --userdir /home/ricky/.netbeans/8.0.2 --branding nb 2364 service:jmx:rmi://127.0.0.1/stub/rO0AB...Hg= org.apache.catalina.startup.Bootstrap start
In my machine were four JVMs executed but only tomcat is exposing a local JMX connection URL. Nevertheless all the following commands will use the typical host and port URL instead of the local one. The tool can also be used to display the JMX domains included in the server.
$ java JmxExplorer -u monitorRole -p tomcat domains JMImplementation Users com.sun.management Catalina java.nio java.lang java.util.logging
Using the mbeans argument the beans exposed by the server are displayed. The argument can have a pattern (the format is described in the JMX API but, if this pattern is not passed, all the MBeans are listed). This execution lists all the mbeans in the java.nio domain.
$ java JmxExplorer -u monitorRole -p tomcat mbeans "java.nio:*" java.nio:type=BufferPool,name=direct java.nio:type=BufferPool,name=mapped
And the following one lists all the servlet MBeans exposed in the jersey application presented in the previous entry (the application name was sample-jersey2).
$ java JmxExplorer -u monitorRole -p tomcat mbeans "Catalina:j2eeType=Servlet,WebModule=//localhost/sample-jersey2,*" Catalina:j2eeType=Servlet,WebModule=//localhost/sample-jersey2,name=jsp,J2EEApplication=none,J2EEServer=none Catalina:j2eeType=Servlet,WebModule=//localhost/sample-jersey2,name=es.rickyepoderi.samplejersey2.Application,J2EEApplication=none,J2EEServer=none Catalina:j2eeType=Servlet,WebModule=//localhost/sample-jersey2,name=default,J2EEApplication=none,J2EEServer=none
The command also displays the attributes that any MBean has, for example the jersey servlet displayed by the previous execution has the following attributes.
$ java JmxExplorer -u monitorRole -p tomcat info Catalina:j2eeType=Servlet,WebModule=//localhost/sample-jersey2,name=es.rickyepoderi.samplejersey2.Application,J2EEApplication=none,J2EEServer=none errorCount(int): Error count singleThreadModel(boolean): Does this servlet implement the SingleThreadModel interface? classLoadTime(int): Time taken to load the Servlet class available(long): The date and time at which this servlet will become available (in milliseconds since the epoch), or zero if the servlet is available. If this value equals Long.MAX_VALUE, the unavailability of this servlet is considered permanent. runAs(java.lang.String): The run-as identity for this servlet. backgroundProcessorDelay(int): The processor delay for this component. modelerType(java.lang.String): Type of the modeled resource. Can be set only once stateManageable(boolean): State management support for this managed object countAllocated(int): The count of allocations that are currently active (even if they are for the same instance, as will be true on a non-STM servlet). minTime(long): Minimum processing time of a request maxTime(long): Maximum processing time of a request loadTime(long): Time taken to load and initialise the Servlet stateName(java.lang.String): The name of the LifecycleState that this component is currently in objectName(java.lang.String): Name of the object servletClass(java.lang.String): The run-as identity for this servlet. asyncSupported(boolean): Async support loadOnStartup(int): The load-on-startup order value (negative value means load on first call) for this servlet. processingTime(long): Total execution time of the servlet's service method requestCount(int): Number of requests processed by this wrapper maxInstances(int): Maximum number of STM instances.
And finally the command can be used to retrieve the current value of any MBean attribute (the attrs option retrieves the values of all the bean attributes or only the ones specified in the command line).
$ java JmxExplorer -u monitorRole -p tomcat attrs Catalina:j2eeType=Servlet,WebModule=//localhost/sample-jersey2,name=es.rickyepoderi.samplejersey2.Application,J2EEApplication=none,J2EEServer=none minTime maxTime requestCount processingTime processingTime: 147 minTime: 2 requestCount: 6 maxTime: 115
So it is quite simple, the command is intended to be used to retrieve the values of the MBean attributes of a JMX server, but some more options are available to look for what attributes and what MBean are wanted. The JMX API can be more complicated (it can instantiate a MBean object for example, but for this task you need the class provided by the JMX server for that specific MBean), so I decided to operate exactly as jconsole does. The command only needs a JavaSE 7 JDK to run. I know it is a quite simple entry, but I have spent some time to develop the Java class and I do not want to lose it. The blog is the best place to keep it save and available for everyone.
Cheerio!
Comments