EJBCA Development

Remember this, shortlist

For all non-trivial commits to EJBCA (mostly doc and whitespace changes count as trivial):

  • A JIRA issue must exist for what you are doing

  • Commits should have "ECA-xxx", where xxx is the JIRA issue number in the svn comment. This allows Jira to track svn commits for the issue.

  • Only one issue per commit. Work on one feature at a time. This is critical for tracability and to be able to make good change logs.

  • JUnit tests must be there for all new features. Add also for bugfixes if possible. Backwards compatibility. All new features must be upgradeable from old version.

  • Either no upgrade is needed.

    • Profiles etc (all UpgradeableDataHashMap) have auto-upgrade features.

    • 'ant upgrade' framework for database changes.

    • Avoid code duplication, parameterize and re-factor code instead.

  • Keep whitespace patches and commits separate from feature patches, so the whitespace changes does not clutter up and hide the feature diffs.

  • Think quality.

Using the Issue Tracker

All check-ins to SVN must be followed by an issue in the issue tracker at https://jira.primekey.se/secure/Dashboard.jspa. This is needed to keep a good changelog, which is vital for a successful release.

The only exceptions to this rule are trivial internal fixes like typos, or removal of unused imports, constants and the like. Also documentation fixes do not need to be tracked in JIRA.

If submitting patches to EJBCA committers, they should be able to create JIRA issues if none exist.

Getting Started with EJBCA Development

Development Tools

  • An operating system that can run Java (Linux, OSX, Windows..). Most developers use Ubuntu/Debian.

  • Eclipse JEE edition with an additional Subversion (SVN) plugin installed. OpenJDK

  • Apache Ant 1.9.x (with all the extras that comes with the zip from apache.org or 'ant-optional' Ubuntu package)

  • A supported application server

  • A favorite database supported by EJBCA that is easy to work with (MariaDB, MySQL, PostgreSQL, ...).

  • A virtualization solution for testing additional combinations of application servers and databases and external OCSP responders etc.

  • Changes that affect the database requires more databases to test with, changes that affect the EJBs or setup requires additional application servers etc..

What you need to know to develop EJBCA

  • The tools described in the last section

  • Public Key Infrastructure and related technologies

  • Java

  • Java Enterprise Edition, excluding message beans

    • Java Persistence API

    • Servlets, Java Server Faces (and still Java Server Pages)

  • SQL databases

  • Web Services

Sending Patches

If you are not a committer in SVN we are glad to accept patches. You can send us patches either in diff format (svn diff) or created with Eclipse.

You can also send us you complete files that you changed, we can see the diffs in Eclipse.

Follow these guidelines when submitting patches:

  • Keep the patch limited, only change the parts related to your patch.

  • Do not change other lines, such as whitespace, adding line breaks to java doc etc. It will make it very very hard for us to review the patch.

Using Subversion

How to connect to the EJBCA SVN repository is explained over at ejbca.org, https://www.ejbca.org/repository.html.

If you are using Eclipse we recommend the Subversive plug-in, now part of eclipse plug-in repositories.

Checking in to SVN

When checking in to SVN, make sure the following conditions are met:

  • The checkin can be tracked to a JIRA issue

  • There is JUnit test coverage for the code.

  • There is sufficient documentation for the feature.

When checking in to SVN you must use a checkin comment starting with JIRA issue (all commits should be linked to a JIRA issue). For example:

    ECA-113: my comment here 

In this way JIRA can make a reference from an issue to specified SVN checkins, something that is very very useful.

When adding new files to SVN you must add a version header to the class javadoc header:

    @version $Id$

You must then set the Id keyword property:

    svn propset svn:keywords 'Id' filename.java

or for all files

    find . -name "*.java" -exec svn propset svn:keywords "Id" {} \;

or in Eclipse using Team→Keywords.

Eclipse

To build successfully using Eclipse, there are .classpath and .project files in svn. Simply check out EJBCA as a project, from svn, and you're almost set. To check out code you must first install the Subversive SVN plug-in in Eclipse. After this you can define a new SVN repository with repository location as found above. In the repository, browse to the desired branch or tag, right click on 'ejbca' and check out.

You must define the variable JBOSS7_HOME in Window->Preferences->Java->Build Path->Classpath Variables.

Some classes are generated during build, so you must also do an 'ant' for Eclipse to find all classes needed to build the project. After checking out the project, defining JBOSS7_HOME and running 'ant', you should simply refresh the project in Eclipse and voila!

To run 'ant' from the command line you still have to define the environment variable APPSRV_HOME, just like when you build from the distribution zip file.

You can build javadoc on all APIs used with

ant javadoc

If using the J2EE version of eclipse it tries to validate JSP ans JSP fragments. Unfortunately it fails miserably at this because it is not able to see relationships between JSP and JSP fragments.

In Eclipse you can disable JSP validation in Window->Preferences->Validation. I have disabled all Build validation for all JSF, JSP, XML, HTML and Seam.

You can configure the .classpath to work with different appservers. By default .classpath is configured for JBoss 7.1.1.GA.

Since appserver classpaths change frequently, there is no point in showing different configurations for different application server here. You have to experiment.

Debugging

You might notice that there is a j2ee:debug target, it will start JBoss in debug mode. Just fire up your debugger to the default transport and address display on your console and you're set. You can now debug your application.

You can also run JBoss from within Eclipse, this is perhaps even better.

Database Development and Changes

See the Database Integration section.

BouncyCastle Provider

EJBCA uses the BouncyCastle (BC) JCE provider.

To install the provider you must use the static method:
CertTools.installBCProvider()

This is done automatically when EJBCA starts from the StartServicesServlet, so if you are developing in EJBCA you don't have to bother with this.

API Documentation

Being open source, EJBCA comes with the best API documentation there is for developers, source code.

Developers shouldn't need lengthy paper descriptions or UML diagrams. Source code and good examples are the best tools.

Getting familiar with the concepts are always good though, so read up on this site and ejbca.org first and familiarize yourself with the concepts and workings of EJBCA.

EJB API

The EJB API can be called from command line tools, web applications or other EJB applications.

Good samples can be found in the EJBCA command line interface: src/java/org/ejbca/ui/cli. The java classes are named logically so you should be able to figure out what they do simply by the name.

Another good sample is the EJBCA public web pages, or the servlets that drives it: src/java/org/ejbca/ui/web/pub.

Webservice API

The webservice API can be called fom any webservice client, locally or remotely. Good sample code can be found in the EJBCA webservice command line interface. src/java/org/ejbca/core/protocol/ws/client. Also here the java classes are named logically.

There is javadoc of the WebService API built when you run ant doc, look under tmp/htdocs/ws. It is also available online at https://www.ejbca.org/docs/ws/index.html.

JUnit tests

The last source of good example code is the JUnit tests. If you plan to contribute to EJBCA you should also learn to write your own JUnit tests.

Look in the directory src/test, there are plenty of java files under there.

Subject and Issuer DNs

Handling of subject and issuer DNs must be done in an extremely predictable way, and in the same way everywhere. Issue are ordering of DN elements, handling of localized strings (UTF8) etc. Because of this, there are a few methods in se.anatom.ejbca.util.CertTools that MUST be used when handling DNs:

  • stringToBCDNString() - when handling user input of a DN string to store od match

  • getSubjectDN(cert) - extracts subject DN from a certificate getIssuerDN(cert) - extracts issuer DN from a certificate

  • getIssuerDN(crl) - extracts issuer DN from a CRL

Logging

Straight console output (System.out) MUST not be used in EJBCA except in cases of console admin utilities.

There are two types of logging in EJBCA:

  • CA logs, defining important events. These logs end up in the database and can be searched through the administration Web-GUI.

  • Error and debug logs. These logs use Log4j and end up in a log file defined in JBoss.

Use the Utils

For the most mundane repetitive tasks there are usually util classes in either org.ejbca.util or in the Apache commons classes that help avoid the same code being copied everywhere.

CA Logs

There are three important classes:

  • Admin: Defines the administrator that performed the action.

  • LogEntry: Represents a line in the log database. Only the constants defined here are used.

  • ILogSessionRemote/Local: The log functionality itself.

To perform logging, first acquire the remote interface to the log session:

ILogSessionLocalHome logsessionhome = (ILogSessionLocalHome) getLocator().getLocalHome(ILogSessionLocalHome.COMP_NAME); logsession = logsessionhome.create(); 

Next step is to log using the function 'log'. Parameters to the log function are:

Parameter

Description

admin

Of the class Admin and is created according to the following criteria:

  • In case a client certificate exists, new Admin(certificate)

  • In other cases one of the types defined in Admin.TYPE_…
    For example: new Admin(Admin.TYPE_RACOMMANDLINE_USER, ip-adress). If possible, the IP adress should be passed.

module

One of the LogEntry.MODULE_ constants and defines in which module the event occurred.

ex

LogEntry.MODULE_CA.

time

Time of the event.

username

User (endentity) that is involved in the event. null in case no user can be considered to be involved.

certificate

Certificate involved in the event. null in case no certificate can be considered to be involved.

event

One of the LogEntry.EVENT_ constants and defines which type of event occurred.

comment

A comment to the event.

If there are events that are not defined, add new events according to the following:

  1. Add an EVENT_INFO/ERROR constant to LogEntry

  2. Add corresponding text in the constant LogEntry.EVENTNAMES_INFO/ERROR

  3. Open the file src/ra/web/raadmin/languages/languagefile.en.properties in a text editor. Go through the constants until you come to the EVENT_INFO/ERROR… constants and add the English translation. Try to keep the list sorted in alphabetical order.

If these steps are followed, the Web GUI will be automatically updated.

Error and debug logs

EJBCA uses the Apache Log4J package for debug-logging. This means that any class that wants to do logging or console output MUST define:

/** Log4j instance */
 private static Logger log = Logger.getLogger(<class>.class); 

Logging is then added in the following:

log.error("message");
 log.info("message");
 log.debug("message"); 

There is also a version of the command that takes an additional Exception as argument, were the exception stack will be printed to the log.
Where the log ends up is defined in 'log4j.properties'.
Some classes have special pre-prepared logging constructs. They are:

BaseSessionBean.java
BaseAdminCommand.java 

This means that classes inheriting from one of these classes do not have to define their own logger, but can use:

error("message");
info("message");
debug("message");

Debugging output for entrance and exit in methods can be added in the following way:

public int myMethod(int arg) {
if (log.isTraceEnabled()) {
log.trace(">myMethod("arg")");
}
int ret = 0;
...
if (log.isTraceEnabled()) {
log.trace("<myMethod: return " + ret);
}
return ret;
}

Checking if trace is enabled first (it is rarely so) will avoid doing the String concatenations.

To add a new call to EjbcaWS in EJBCA 3.10 and later

  1. Add an abstract method to IEjbcaWS.java

  2. Implement the method in EJbcaWS.java

  3. run 'ant ejbca-ws-generate'

  4. Redeploy EJBCA

  5. Create JUnit tests.

Clear or Hashed Passwords

Passwords for users are normally stored BCrypt:ed in the database.

You can retrieve and use the password IF it is stored in clear text. Clear text password are however encrypted/obfuscated using the key conf/ejbca.properties#password.encryption.key

Use something like this to get the password (snip from BatchMakeP12.java):

IUserAdminSessionRemote admin = adminhome.create();
UserAdminData data = admin.findUser(administrator, username);
if ((data.getPassword() != null) && (data.getPassword().length() > 0) {
...
}

When creating the user, you must specify that the password should be in clear text, otherwise it will be stored in hashed form, which will obvoiusly be of no use to you.

  • If using the Web-GUI there is a checkbox for storing the password in clear format.

  • If using the command line gui there is a command

    ra setclearpwd
  • If using programatically: In IUserAdminSession there is a flag clearpwd to the method addUser, or you can use the method setOpenPassword on the UserDataBean object returned from findUser.

Setting up a Utimaco HSM Emulator

Utimaco have an emulator for their Cryptoserver LAN HSM, it works very good for testing and development.

CryptoServer PKCS#11 Emulation installation:

  1. Install Windows in VmWare, or on your machine if you are running on windows. This will emulate the CryptoServer LAN module.

  2. Run CESetup-2.4.exe in the Windows machine. After this the CryptoServer emulator will run in a DOS Window.

  3. The CryptoServer LAN can now be reached at <ip-of-emulation-machine>:3001 The CryptoServer LAN emulator is already initialized for PKCS#11 usage.

  4. Setup software and initialize pkcs11 slot:

    • cd <p11 directory>

    • cp <Utimaco-CD>/Software/PKCS#11/lib/linux/* .

    • cp <Utimaco-CD>/Software/PKCS#11/p11tool/linux/p11tool . ln -s libcs2_pkcs11-1.4.0.so libcs2_pkcs11.so

    • vi cs2_pkcs11.ini

    • Device = TCP:3001@172.16.175.128

    • AppTimeout = 172800

    • sudo cp cs2_pkcs11.ini /etc/utimaco (location can also be set with environment variable CS2_PKCS11_INI)

    • ./p11tool lib=./libcs2_pkcs11.so slot=1 InitToken=officer1

    • ./p11tool lib=./libcs2_pkcs11.so slot=1 loginSO=officer1 initpin=user1

  5. Generate keys (password is user1 as initialized above):
    $EJBCA_HOME/bin/pkcs11HSM.sh generate ./libcs2_pkcs11.so 2048 defaultKey 1 $EJBCA_HOME/bin/pkcs11HSM.sh generate ./libcs2_pkcs11.so 2048 signKey 1 $EJBCA_HOME/bin/pkcs11HSM.sh generate ./libcs2_pkcs11.so 512 testKey 1

  6. Create a CA in EJBCA:
    Restart JBoss if it was started. Important, you will get PKCS#11 error unless you restart JBoss after generating the keys.

  7. Create a new CA in EJBCA with the following properties:

  8. dfg

  • slot 1

  • defaultKey defaultKey certSignKey signKey crlSignKey signKey testKey testKey

  • pin user1

  • sharedLibrary <p11 directory>/libcs2_pkcs11.so

JBoss PermGenSpace

Relevant for JDK 7 only. PermGenSpace is not used in JDK 8.

When re-deploying EJBCA in JBoss, and also other application servers, they soon run out of PermGenSpace, so the whole application server must be restarted. Often even a hard kill must be done. To avoid this you can add the following to the JAVA_OPTS in run.conf in JBoss (or similar place for other app servers):

-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=1024M

JBoss Hot Re-Deploy with both EJBCA and SignServer

Both EJBCA and SignServer deploys some libraries such as the BouncyCastle and various commons-* libraries. In the default configuration of JBoss 4.2.3 (and other versions?) those are shared between the two applications (See JBossClassLoadingUseCases ). This can cause problem if one of the applications is re-deployed. The result is that some Servlets fails during initialization and throws either an IllegalStateException (See JBAS-7183 ) or a ClassNotFoundException with something like "Invalid use of destroyed classloader, UCL destroyed". The workaround is to first undeploy the other application or simply to restart JBoss.

Adding Certificate Extensions

  1. Add a new class with the OID and the ASN.1 encoding in org.ejbca.core.model.ca.certextensions.standard

  2. Add the new extension to the HashMap standardCertificateExtensions in org.ejbca.core.model.ca.certextensions.CertificateExtensionFactory

  3. Add the new extension to the HashMap useStandardCertificateExtensions in org.ejbca.core.model.ca.certificateprofiles.CertificateProfile

  4. Add GUI stuff for selecting if the extension should be used or not, and if some values should be entered when registering users.

Adding a New Signature Algorithm for CAs

To make support for a new signature algorithm when creating CAs in the admin GUI is really simple.

  1. A a new constant in AlgorithmConstants

  2. Add the new constant for AVAILABLE_SIGALGS in AlgorithmConstants

  3. Check that AlgorithmTool returns the correct value.

You can also play around with EC curve names. This is done in AlgorithmTools.getNamedEcCurvesMap.

Build Scripts

EJBCA uses Apache Ant or later.

EJBCA 3.10 introduced improved modularisation. It should be possible to build each module separately and it should be clear what other modules it depends on.

EJBCA_HOME/build.xml: hold all references to all build targets regular EJBCA users should be exposed to. Invoking a build target from this file invokes the corresponding target in EJBCA_HOME/modules/build.xml EJBCA_HOME/modules/build.xml: keeps track of all target for building different modules and the dependencies required to build a specific module.

  • EJBCA_HOME/modules/build-properties.xml: Holds build variables, like the directories of different modules, location of resulting distributables, variables loaded from property files and path-declarations for different sets of libraries.

  • EJBCA_HOME/modules/module-name/build.xml: Build file for the module "module-name". At least contains a default "build" target and a "clean" target.

Module dependencies have to be added both to the module's target in modules/build.xml and the "build"-target in the modules directory.

Archive Standard Compliance Verification

Applies only to legacy versions on JEE5

Glassfish contains a archive verification utility, which can take enterprise application and web archives (EAR, WAR, RAR, etc) and verify that they follow standard. To use it:

  1. Download Glassfish 2.1.1 from GlassFish and follow the installation instructions.

  2. Build EJBCA and run the following:

$ /path-to-glassfish/bin/verifier -v /path-to-ejbca/dist/ejbca.ear

Plug-ins, Add-ons and Customization

There are several plug-in interfaces where you can extend functionality using your own classes. For more information on customizing EJBCA, see Customizing EJBCA.