Several times in my professional life I faced with the problem of using digital signatures or encryption in a web environment. The first time was long time ago, in 2003, when I participated in the development of a PKCS#11 module to be used with Sun Rays and CERES/FNMT CRYPTOcard. This module let people from Hoyo de Pinares vote using a Sun Ray environment in one of the first electronic voting events in Spain. This is a report of the event in the Spanish public television, so it is in Spanish . This project was my first important work and I remembered it with great affection. For this reason this topic is something I have always been interested in.
Around digital signatures and encryption there are some concepts which need to be understood before anything else.
Pubic and private key pair. Public key cryptography is a mathematical algorithm technique that lets encrypt and decrypt data using a pair of cryptographic keys (public and private). The private key is kept secret (no one has to know it) whilst the public key may be widely distributed. Data encrypted using the private key can only be decrypted using its associated public key and vice-versa. So any information encrypted with my secret private key can be decrypted by any person who previously has my public key but something encrypted using my public key can only be decrypted by me (by my private key). RSA and DSA are examples or types of public/private key algorithms.
A public key. Yes, exactly the one explained in the previous paragraph.
Information of the identity. In a personal certificate this part contains data of the person (name, surnames, address, birth date and so forth), very similar to the one that appears in a national identity card or driver license.
A signature of the previous data. This is the complicated part. The idea of this signature is somebody is assuring the two previous points are reliable. There are some certification authorities or CAs throughout the world whose job is just issuing trusted certificates.
So, in a little summary, my certificate is a reliable piece of information of myself (my public key is a compulsory part of this info), and it is reliable cos it is signed by someone you can trust (a CA). And obviously my certificate is the perfect way to spread my public key to anyone I want to.
Encryption and decryption. Encryption is a mechanism by which a message is transformed so that only the sender and recipient can see (privacy). Using public/private key algorithms the mechanism is quite easy, the sender encrypts the message using recipient's public key (sender needs to know recipient's public key before). This way, as private key is only known by the recipient, he is the only person who can decrypt the sent message. Privacy needs public key encryption.
Digital signature. A digital signature is a way of demonstrating the authenticity of a digital message or document (an email, a file or whatever). The technique is more complex but I am going to try to explain it. The data of the message is summarized in a little (much sorter) message. This is a hash (another mathematical algorithm) and again it can be of many different types (MD5 or SHA1 for example). This hash is later encrypted with the private key of the sender. This encrypted hash is attached with other info (the certificate of the sender, the hash algorithm name and other data) to the original message. This way when the recipient receives the message he can compute again the hash and contrast it with the decrypted one. So digital signatures use private key encryption.
Definitely the recipient can be sure of two things:
The message has not been modified since the sender composed it (cos any modification would produce a different hash). Reliability.
The message has been sent by the person the signature says (cos no one else has his private key). Non-repudiation.
The standard that governs email signature formats is PKCS#7 and it can be considered as a particular case of digital signature.
First and most important, certificates have to be used in the client side cos the private key is secret and cannot be sent to the server. Consequently the only element which has access to the certificate and private key is the browser and other coupled applications (flash, Java applets,...).
At this point I am going to say I am a little frustrated, since 2003 there is no standard way to access browser certificate store using the browser itself. Firefox and other mozilla based browsers have the crypto object which gives some cryptographic methods like singtext to be used in javascript. Explorer and Windows gave old CAPICOM which could be used in a visual basic script inside explorer. I think now CAPICOM has been deprecated and .NET does the same stuff, but I do not know if the new solution uses javascript or something different. Besides the new HTML5 specification seems to not add anything new, which is a real pity. So, much to my sorrow, browser is not the best way to access certificates nowadays.
Other possible solution could be a complete independent desktop application. I think a kind of a daemon which manages the user certificate store would be an elegant solution. Any other program with cryptographic needs could contact to this daemon in order to list certificates, sign or encrypt data or any other functionalities. But in our case the program with these needs is the browser and I am not sure how to fully implement this solution. But what it is for sure is that this solution would be a complex and long-term project and it is not suitable for a little example as the one I am going to present here.
Right now, from my point of view, a much less worse solution is using Java applets. An applet is a standalone Java application which runs inside a browser and has some interaction with it. Now Java applets are out of date, they have been replaced by AJAX or Java Web Start applications. First solutions are ideal for web/thin applications and second ones are perfect for desktop/heavy applications, so applets are now out of place. But, as I have explained before, I think they are at the moment the least worst solution for this topic.
Using an applet our solution has a complete Java Runtime Environment (JRE) for our purposes and Java Cryptography Architecture (JCA) is at our disposal. The JCA is a standard API in the Java language to deal with digital signatures, message digests, certificates and certificate validation, encryption, key generation and management, secure random number generation and many other security and cryptographic techniques. The JCA is designed to be interoperable and extensible. This way it gives an API which has several implementations (providers) behind. Each provider can implement its own certificate and key store and its own cryptographic algorithms. There are several providers by default in the JCA and you can use/configure the one you prefer. JCA sometimes separates the certificate store provider from the algorithm provider (this way you can use JKS provider as file certificate store but SunJSSE as algorithm provider) but it is not compulsory (for example a PKCS#11 provider manages both things). It is clear JCA is a separate way of dealing with certificates and it does not use browser certificates or algorithms at all.
Our applet is going to be designed using the following principles:
The applet uses its own JCA implementation. So certificate store is independent of the browser (they can be different). Of course it would be nice both stores were the same, but this has to be configured.
Any JCA provider needs some configuration (the providers that the applet is using, the file where the certificate store is,...). The user needs to previously configure this information in order to use the applet. In our little example there is no configuration repository and this information is just in the HTML generated page (but it is clear a DDBB, LDAP or whatever can be used for this purpose).
The applet is intended to be as simple as possible. It is a good thing the applet just signs and encrypts but nothing else, so it receives a byte array and returns a byte array, the returning array is the signature or the encryption of the first one.
Although simplicity is the key, the applet has to request passwords for the user and present its certificates. This functionality requires some little gui in which the user can choose the certificate to use in each operation.
The applet must be extensible to support any new JCA providers (just in case).
The applet returns the data using javascript applet interaction with the browser. Usually a hidden input is the perfect place to set the signature.
For security reasons applets are restricted to the browser and they cannot access by default any resource out of the browser and in the client box. Because of certificate store our applet needs access to client computer file system or any other devices in case of complex crypto-devices. To do that the applet must be signed (a signature again). I self-signed my applet following this old good tutorial.
Following these main ideas I have implemented a little application which sends digitally signed emails (just a text plain email with the PKCS#7 associated signature). Main client side files are the following:
Signer.java: This is an interface that uses the applet to sign independently of the JCA providers used. In order to support a new JCA provider (no matter how different the provider was) just a new implementation has to be provided. The signer has some properties to configure the used provider(s), this properties are passed previously to the applet. The signer interface has a signPlainTextEmailSHA1 method to sign emails.
JCESigner.java: Generic Signer implementation that suites almost all JCA providers. The signPlainTextEmailSHA1 method is implemented using bouncy castle smime implementation. This is contradictory with our simplicity applet design but implementing a complete PKCS#7 server side attachment is painful and clearly not necessary for our PoC. The PKCS#7 is the standard that rules how the signature is created and attached to an email. It requires some complex encoding and that is the reason I decided to use bcmail library. It is clear a real solution would never process mail composing in the applet/client side, but the complexity of generating the PKCS#7 in the server and just the signature in the applet made me to follow this way.
SignApplet.java: A simple applet implementation that initializes the Signer using its parameters, logs the user in the store and shows the certificates in it. After the user chooses one of the presented certificates the signature is performed as described above. The PKCS#7 attachment is finally sent to the server.
The PoC functionality is as follows. The applet generates the complete mail and just returns the attached PKCS#7 mail body part. The server side receives this PKCS#7 part and generates the mail following the same procedure but attaching the sent signature. Finally the generated signed mail is sent to the SMTP server.
In this first entry I am going to use the most common Java providers. For example in order to use a JKS certificate store and SunJSSE algorithm provider (this provider supports all necessary algorithms for a RSA/SHA1 signature) the applet must be instantiated this way.
<applet id="signApplet" code="sample.applet.SignApplet" archive="SSignApplet.jar,Sbcmail-jdk16-145.jar,Sbcprov-jdk16-145.jar,Smail-1.4.3.jar" width="350" height="200">
<param name="text" value="This is a sample text to sign!"/>
<param name="clazz" value="sample.applet.JCESigner"/>
<param name="param0" value="sample.applet.keyStoreType###JKS"/>
<param name="param1" value="sample.applet.keyProviderType###SunJSSE"/>
<param name="param2" value="sample.applet.keyStoreFilePath###/home/blog/certs/my-keystore.jks"/>
</applet>
The applet receives the text to sign in a text param. The class to use as Signer interface is specified in clazz parameter (in this case common JCESigner class is used) and all the rest of parameters are passed as paramX and they are used to initialize the Signer. For example, in this example, the /home/blog/certs/my-keystore.jks file is set as certificate store (previously my user certificate has been imported inside it). The other two properties just indicates the providers used for certificate store (JKS) and algorithms (SunJSSE).
In case our preferred store implementation was a PKCS#12 file the applet needs to be instantiated in a very similar way.
<applet id="signApplet" code="sample.applet.SignApplet" archive="SSignApplet.jar,Sbcmail-jdk16-145.jar,Sbcprov-jdk16-145.jar,Smail-1.4.3.jar" width="350" height="200">
<param name="text" value="This is a sample text to sign!"/>
<param name="clazz" value="sample.applet.JCESigner"/>
<param name="param0" value="sample.applet.keyStoreType###pkcs12"/>
<param name="param1" value="sample.applet.keyProviderType###SunJSSE"/>
<param name="param2" value="sample.applet.keyStoreFilePath###/home/blog/certs/my-keystore.p12"/>
</applet>
Only properties for sample.applet.keyStoreFilePath and sample.applet.keyStoreType are changed, now the Signer reads the certificates and keys from a standard PKCS#12 store located in /home/blog/certs/my-keystore.p12.
Finally I present a video where the first example (JKS + SunJSSE) is used. I send an email to myself and when the compulsory data is filled the applet is shown in order to pick the certificate up and perform the signature. When the PKCS#7 attachment is generated in the client side it is sent to the server. Application server composes the real email which is finally sent to the SMTP server. When the mail is received my thunderbird shows it is perfectly signed.
As you can see the problem here is the certificates used by the applet are different from the ones used by the browser. In the video applet certificates are in my-keystore.jks file and clearly they are not in the PKCS#11 repository firefox/iceweasel uses. In the next post we extend our little PoC to deal with the certificate stores of the two most popular browsers (firefox and IE). This way although applet and browser use certificates independently both of them use the same store and consequently the same certificates.
First of all thank you very much for posting such a wonderful and less available resource..
I am facing one issue on my Windows platform for setting nssSecmodDirectory value. it's "C:/Documents and Settings/eopl/Application Data/Mozilla/Firefox/Profiles/eeke6lvo.default".
It throws and Exception that 'and' is not parsable..
I think its due to a space between the words.. but dont know how to resolve this problem
In my opinion, other approach to achieve the same functionality that achieved with applet it could be implement a plugin browser, isn't it?
The main problem is that you had to implement so many plugins as browser you wanted support, but it could be a tighter couple solution.
Comments