After my article on how to install Cryptlib with Java on Mac i received a few emails asking for more info so i thought it might be more useful to make the answers public instead of going for copy/paste once more
So here it is: my task was to create a small client/server CMP application with basic functionalities like:
- certificate request
- certificate renewal
- certificate revocation
- validity check
I decided to keep my application at the “Plug-and-play PKI” level since according to the manual “[it] is the easiest one to use and therefore the recommended one. At this level, cryptlib handles all certificate processing and management operations for you, requiring no special knowledge of certificate formats, protocols, or operations.”
That sounded pretty simple and straightforward even though i later found out that the manual was a bit misleading ![]()
Anyway on the server side, we need to create the CA’s certificate in order to sign all the certification requests from the clients and then start a CMP session (and optionally a RTCS session to check for validity) to listen for incoming requests.
To create the CA’s certificate (and save it in “saved_file_path”) use this code:
int context = crypt.CreateContext(crypt.UNUSED, crypt.ALGO_RSA);
crypt.SetAttributeString(context, crypt.CTXINFO_LABEL, "CA_Private_Key");
crypt.GenerateKey(context);
int certificate = crypt.CreateCert(crypt.UNUSED, crypt.CERTTYPE_CERTIFICATE);
crypt.SetAttribute(certificate, crypt.CERTINFO_SUBJECTPUBLICKEYINFO, context);
crypt.SetAttributeString(certificate, crypt.CERTINFO_COUNTRYNAME, "CA_COUNTRY_CODE");
crypt.SetAttributeString(certificate, crypt.CERTINFO_ORGANIZATIONNAME, "CA_ORG_NAME");
crypt.SetAttributeString(certificate, crypt.CERTINFO_ORGANIZATIONALUNITNAME, "CA_ORGUNIT_NAME");
crypt.SetAttributeString(certificate, crypt.CERTINFO_COMMONNAME, "CA_COMMONNAME");
crypt.SetAttribute(certificate, crypt.CERTINFO_SELFSIGNED, 1);
crypt.SetAttribute(certificate, crypt.CERTINFO_CA, 1);
crypt.SignCert(certificate, context);
int keyset = crypt.KeysetOpen(crypt.UNUSED, crypt.KEYSET_FILE, saved_file_path, crypt.KEYOPT_CREATE);
crypt.AddPrivateKey(keyset, context, "CA_Private_Password");
crypt.AddPublicKey(keyset, certificate);
crypt.KeysetClose(keyset);
crypt.DestroyContext(context);
crypt.DestroyCert(certificate);
After that we need the server to be able to listen for certification requests from the clients. So we create a CMP session using the CA certificate we just created:
while (true) {
int session = crypt.CreateSession(crypt.UNUSED, crypt.SESSION_CMP_SERVER);
int CACertificate = crypt.KeysetOpen(crypt.UNUSED, crypt.KEYSET_FILE, saved_file_path, crypt.KEYOPT_READONLY);
int CAPrivatePassword = crypt.GetPrivateKey(CACertificate, crypt.KEYID_NAME, "CA_Private_Key", "CA_Private_Password");
crypt.KeysetClose(CACertificate);
int certKeyset = crypt.KeysetOpen(crypt.UNUSED, crypt.KEYSET_ODBC_STORE, "username:password@ODBC_NAME", crypt.KEYOPT_NONE);
crypt.SetAttribute(session, crypt.SESSINFO_KEYSET, certKeyset);
crypt.SetAttribute(session, crypt.SESSINFO_PRIVATEKEY, CAPrivatePassword);
crypt.SetAttribute(session, crypt.SESSINFO_SERVER_PORT, 2000);
crypt.SetAttribute(session, crypt.SESSINFO_ACTIVE, 1);
crypt.KeysetClose(certKeyset);
crypt.DestroySession(session);
}
There are two things that are worth noting here:
- i used an odbc database to store incoming requests from the clients. Setting up an ODBC store is pretty easy on Mac OS X Leopard since you can find the “ODBC administrator tool in the utility folder”. On Snow Leopard, Apple did not include it by default but you can download it from here
- also, on line 11, we actually start the server by making it listen for incoming requests on port 2000. We have nothing else to do to issue a certificate since all the requests are handled by cryptlib for us.
Finally, we start the RTCS service on another port to check our CRL and respond to certificate validity requests:
while(true) {
int session = crypt.CreateSession(crypt.UNUSED, crypt.SESSION_RTCS_SERVER);
crypt.SetAttributeString(session, crypt.SESSINFO_SERVER_NAME, "localhost");
crypt.SetAttribute(session, crypt.SESSINFO_SERVER_PORT, 4000);
int certKeyset = crypt.KeysetOpen(crypt.UNUSED, crypt.KEYSET_ODBC, "username:password@ODBC_NAME", crypt.KEYOPT_READONLY);
crypt.SetAttribute(session, crypt.SESSINFO_KEYSET, certKeyset);
int CACertificate = crypt.KeysetOpen(crypt.UNUSED, crypt.KEYSET_FILE, CA_Certificate_path, crypt.KEYOPT_READONLY);
int CAPrivPass = crypt.GetPrivateKey(CACertificate, crypt.KEYID_NAME, "CA Private Key", "CA_Private_password");
crypt.SetAttribute(session, crypt.SESSINFO_PRIVATEKEY, CAPrivPass);
crypt.KeysetClose(CACertificate);
crypt.SetAttribute(session, crypt.SESSINFO_ACTIVE, 1);
crypt.KeysetClose(certKeyset);
crypt.DestroySession(session);
}
And that’s it! Now our server is ready to issue new certificates and check for their validity.
>> Continue to part II – Client
