4. MATERIALES Y MÉTODOS
4.1. OBTENCIÓN DE ANTÍGENOS
4.2.2. COMPARACIÓN DE LOS ANTIGENOS 2B2t, B2t Y LH EN ELISA Y UN KIT
To implement the system design, several technology choices had to be made. First of all, Java[42] was selected as the programming language, partly be- cause of the level of proficiency of the implementor, and partly because of the availability of libraries, particularly a freely available CMP implementation. The version of Java used is J2SE 1.5.0 02, and the CMP implementation used is the NOVOSEC extensions[47] to the Bouncy Castle Crypto APIs[40]. Release 101 of the NOVOSEC extensions and version 1.27 of the Bouncy
Castle Crypto APIs are used. The selected transport mechanism for CMP is HTTP (Content-Type: application/pkixcmp), which makes it extremely easy to scale horizontally by using existing solutions for load balancing of web servers. The AS is implemented as a Java Servlet, and Jakarta Tomcat[55] version 5.5.9 is used as the Servlet container. A short description of the Tomcat configuration is presented in appendix A.
The first iteration of the implementation - test cycle was to provide a func- tional implementation using DSA as the signature algorithm. Furthermore, to generate CA certificates and server certificates for functionality testing, the Java classes in appendices E and F were used, for DSA and RSA certificates respectively. The difference between CA certificates and server certificates is that the CA certificates are self-signed, as illustrated in the Java class in appendix F. The reason for generating server certificates is that, even if the ordinary servers are defined as out-of-scope for this thesis, server certificates are a prerequisite for functionality testing using third party software.
The Java class in appendix G was used to generate the moduli used for SPEKE. This rather naive method of finding a safe prime is very time- consuming, but it got the job done. Generation of the 2048-bit modulus took over three hours on a server with two Intel Xeon 2.8 GHz CPUs.
The client and server were run on the same physical system, and the server implementation was basically just a doGet() method in a Java Servlet, while the client was run from the command line. All values were hard-coded, so recompilation was needed for configuration changes. Although the system as such was crude, it did provide the desired functionality. The user entered the user name and password into the client software, the client then initiated SPEKE and got its signed certificate from the server. Keys and certificates were stored as ordinary system files.
Quality assurance of the functionality was performed in several stages: First, the output of debug routines in the software was inspected, as shown in appendix B. Next, the resulting certificates and messages were inspected using the ’openssl asn1parse’ command, see appendix C for an example. Finally, the client private key and signed certificate were used to set up SSL connections to an OpenVPN[48] server. This last experiment was performed to assure that the certificates and keys produced by the system could be used with third-party software, and example results are presented in appendix D. Having completed a functional system, the time had come to stress test it. An ordinary workstation with an AMD Athlon XP 1800 CPU was set up as the server, and another workstation, with a VIA Eden 500 MHz CPU, was configured to just read a PKIMessage from disk and then spawn 10 threads that fired requests at the server as quickly as possible. The result was that the Java runtime environment on the server ran out of heap memory, the
garbage collector was simply not able to remove dereferenced objects quickly enough. The end result was that the server was unable to respond to any more queries.
The next iteration of the development focused on the scalability of the server. Initial instantiation of shared objects in the Servlet were moved from the doGet() method to the init() method. After these adjustments, the server performed better under heavy loads, at least it did not run out of memory. To test the performance of the system using realistic server hardware, two Dell PowerEdge 2650 machines were used, one as server and the other as client. The server and client operating system was SUSE Linux Enterprise Server 9. This setup was used for all the subsequent performance tests. Hardware specifications for the Dell servers are listed in appendix P.
During the tests, several errors occurred. This was traced back to certain objects, particularly Cipher and SHA1Digest, being instantiated in the init() method, which means that they were shared among several Servlet instances. The problem was the way that the objects were used, each Servlet had to make several method calls in sequence to the object. This is illustrated by the example code from the server in table 5.7. As an example, if one Servlet calls the Cipher.init() method just before another Servlet calls the doFinal() method, the second Servlet will experience a “java.lang.IllegalStateException: Cipher not initialized”, because the state of the myCipher object is different from what the second Servlet expected.
In the init() method:
Cipher myCipher =
Cipher.getInstance("AES/CBC/PKCS7Padding" , bcProvider);
In the doGet() method:
myCipher.init(Cipher.ENCRYPT_MODE , myAESKeySpec , secureRandom); byte[] myAESIV = myCipher.getIV();
byte[] encryptedValue = myCipher.doFinal(myX509Cert.getEncoded());
Table 5.7: State problems with the Cipher object
This problem might not be detected on a single-threaded system, but it was definitely noticeable on an SMP system with hyper threading, where several Servlets were executed simultaneously and interfered with each other. The instantiation of the objects in question was moved to the doGet() method, such that they were instantiated once per request, and this solved the prob- lem. The lesson learned was that one must be very careful when deciding which objects should be instantiated in the init() method, and which objects
should be instantiated once per request. If a Servlet does more than one method call in sequence to an object while depending on the state of said object, it must instantiate its own object for every request.
When the system performed well under heavy load, the next step was to modularize it and to add support for the RSA signature algorithm. After this had been successfully implemented, the time had come to stress test the system thoroughly to gather performance statistics for different key lengths and algorithms. Such statistics are useful for future consideration of hardware needs for the AS. Before initiating stress tests with different configuration parameters, the client and server were modified to read their configuration parameters from file during run-time, to avoid having to recompile the whole system for each round of testing. An example AS configuration file is listed in appendix J, and the corresponding client configuration file in appendix K. The finished AS implementation is included as appendix H, and the client implementation as appendix I. An in-depth description of the testing methodology and the results is presented in section 5.6.