diff options
author | Endi Sukma Dewata <edewata@redhat.com> | 2012-03-24 02:27:47 -0500 |
---|---|---|
committer | Endi Sukma Dewata <edewata@redhat.com> | 2012-03-26 11:43:54 -0500 |
commit | 621d9e5c413e561293d7484b93882d985b3fe15f (patch) | |
tree | 638f3d75761c121d9a8fb50b52a12a6686c5ac5c /base/tps/src/processor | |
parent | 40d3643b8d91886bf210aa27f711731c81a11e49 (diff) | |
download | pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.gz pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.xz pki-621d9e5c413e561293d7484b93882d985b3fe15f.zip |
Removed unnecessary pki folder.
Previously the source code was located inside a pki folder.
This folder was created during svn migration and is no longer
needed. This folder has now been removed and the contents have
been moved up one level.
Ticket #131
Diffstat (limited to 'base/tps/src/processor')
-rw-r--r-- | base/tps/src/processor/RA_Enroll_Processor.cpp | 5194 | ||||
-rw-r--r-- | base/tps/src/processor/RA_Format_Processor.cpp | 70 | ||||
-rw-r--r-- | base/tps/src/processor/RA_Pin_Reset_Processor.cpp | 1013 | ||||
-rw-r--r-- | base/tps/src/processor/RA_Processor.cpp | 3506 | ||||
-rw-r--r-- | base/tps/src/processor/RA_Renew_Processor.cpp | 57 | ||||
-rw-r--r-- | base/tps/src/processor/RA_Unblock_Processor.cpp | 58 |
6 files changed, 9898 insertions, 0 deletions
diff --git a/base/tps/src/processor/RA_Enroll_Processor.cpp b/base/tps/src/processor/RA_Enroll_Processor.cpp new file mode 100644 index 000000000..d88d84087 --- /dev/null +++ b/base/tps/src/processor/RA_Enroll_Processor.cpp @@ -0,0 +1,5194 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +/** + * RA_Enroll_Processor handles initialization and enrollment of the token + */ + + +/* variable naming convention: + * a_ passed as an 'in' argument to a method + * o_ passed as an 'out' argument to a method + * m_ member variable + */ + + +#include <string.h> +#include <time.h> +#include "pkcs11.h" + +// for public key processing +#include "secder.h" +#include "pk11func.h" +#include "cryptohi.h" +#include "keyhi.h" +#include "base64.h" +#include "nssb64.h" +#include "prlock.h" + +#include "cert.h" +#include "main/RA_Session.h" +#include "main/RA_Msg.h" +#include "main/Buffer.h" +#include "main/Util.h" +#include "main/PKCS11Obj.h" +#include "engine/RA.h" +#include "channel/Secure_Channel.h" +#include "msg/RA_SecureId_Request_Msg.h" +#include "msg/RA_SecureId_Response_Msg.h" +#include "msg/RA_New_Pin_Request_Msg.h" +#include "msg/RA_New_Pin_Response_Msg.h" +#include "processor/RA_Processor.h" +#include "processor/RA_Enroll_Processor.h" +#include "tus/tus_db.h" + +#include "cms/CertEnroll.h" +#include "httpClient/httpc/response.h" +#include "main/Memory.h" + +#define OP_PREFIX "op.enroll" + +#ifdef XP_WIN32 +#define TPS_PUBLIC __declspec(dllexport) +#else /* !XP_WIN32 */ +#define TPS_PUBLIC +#endif /* !XP_WIN32 */ + +SECStatus PK11_GenerateRandom(unsigned char *,int); +void PrintPRTime(PRTime, const char *); + + +// This parameter is read from the config file. It is the +// applet build ID which the administrator wants to set as +// the 'latest applet' to upgrade to. +static const char *g_applet_target_version = NULL; + + +/** + * this function returns a new allocated string + * @param cuid a 20 character string. Usually this is 20 hex + * digits representing a token CUID. + * @returns a new string which is basically a copy of the input, but + * with extra colons. The caller is responsible for freeing the + * returned string with PR_Free(). + */ + +static char *GetPrettyPrintCUID(const char *cuid) +{ + int i,j; + char *ret = NULL; + + if (cuid == NULL) + return NULL; + if (strlen(cuid) != 20) + return NULL; + ret = (char *)PR_Malloc(20+4+1); + j = 0; + for (i = 0; i < 24; i++) { + if (i == 4 || i == 9 || i == 14 || i == 19) { + ret[i] = '-'; + } else { + ret[i] = cuid[j]; + j++; + } + } + ret[24] = '\0'; + return ret; +} + +static SECItem * +PK11_GetPubIndexKeyID(CERTCertificate *cert) { + SECKEYPublicKey *pubk; + SECItem *newItem = NULL; + + pubk = CERT_ExtractPublicKey(cert); + if (pubk == NULL) return NULL; + + switch (pubk->keyType) { + case rsaKey: + newItem = SECITEM_DupItem(&pubk->u.rsa.modulus); + break; + case dsaKey: + newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue); + break; + case dhKey: + newItem = SECITEM_DupItem(&pubk->u.dh.publicValue); + break; + case ecKey: + newItem = SECITEM_DupItem(&pubk->u.ec.publicValue); + break; + case fortezzaKey: + default: + newItem = NULL; /* Fortezza Fix later... */ + } + SECKEY_DestroyPublicKey(pubk); + /* make hash of it */ + return newItem; +} + + +/** + * Constructs a processor for handling enrollment operation. + */ +TPS_PUBLIC RA_Enroll_Processor::RA_Enroll_Processor () +{ +} + +/** + * Destructs enrollment processor. + */ +TPS_PUBLIC RA_Enroll_Processor::~RA_Enroll_Processor () +{ +} + +RA_Status RA_Enroll_Processor::DoEnrollment(AuthParams *login, RA_Session *session, + CERTCertificate **certificates, + char **origins, + char **ktypes, + int pkcs11obj_enable, + PKCS11Obj *pkcs_objx, + NameValueSet *extensions, + int index, int keyTypeNum, + int start_progress, + int end_progress, + Secure_Channel *channel, Buffer *wrapped_challenge, + const char *tokenType, + const char *keyType, + Buffer *key_check, + Buffer *plaintext_challenge, + const char *cuid, + const char *msn, + const char *khex, + TokenKeyType key_type, + const char *profileId, + const char *userid, + const char *cert_id, + const char *publisher_id, + const char *cert_attr_id, + const char *pri_attr_id, + const char *pub_attr_id, + BYTE se_p1, BYTE se_p2, int keysize, const char *connid, const char *keyTypePrefix,char * applet_version) +{ + RA_Status status = STATUS_NO_ERROR; + int rc = -1; + int len = 0; + int publish_result = -1; + Buffer *public_key = NULL; + SECItem si_mod; + Buffer *modulus=NULL; + SECItem *si_kid = NULL; + Buffer *keyid=NULL; + SECItem si_exp; + Buffer *exponent=NULL; + CertEnroll *certEnroll = NULL; + Buffer *cert = NULL; + Buffer CUID = channel->GetKeyDiversificationData(); + const char *label = NULL; + const char *cuid_label = NULL; + const char *pattern; + char configname[256]; + NameValueSet nv; + const char *pretty_cuid = NULL; + + const char *FN="RA_Enroll_Processor::DoEnrollment"; + + char *cert_string = NULL; + SECItem* encodedPublicKeyInfo = NULL; + SECItem **ppEncodedPublicKeyInfo = NULL; + CERTSubjectPublicKeyInfo* spkix = NULL; + + char *pKey = NULL; + char *ivParam = NULL; + char *wrappedPrivKey = NULL; + + const char *drmconnid = NULL; + bool serverKeygen = false; + SECKEYPublicKey *pk_p = NULL; + + char audit_msg[512] = ""; + char *keyVersion = NULL; + char cert_serial[2048] = ""; + char activity_msg[4096] = ""; + + float progress_block_size = (float) (end_progress - start_progress) / keyTypeNum; + RA::Debug(LL_PER_CONNECTION,FN, + "Start of keygen/certificate enrollment"); + + // get key version for audit logs + if (channel != NULL) { + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + keyVersion = Util::Buffer2String(channel->GetKeyInfoData()); + } + + // check if we need to do key generation (by default, overwrite everything) + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.%s.overwrite", + OP_PREFIX, tokenType, keyType); + RA::Debug(LL_PER_CONNECTION,FN, + "looking for config %s", configname); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 1)) { + // do nothing + RA::Debug(LL_PER_CONNECTION,FN, + "do overwrite"); + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "do not overwrite, if %s exists", cert_id); + int num_objs = pkcs_objx->PKCS11Obj::GetObjectSpecCount(); + char b[3]; + bool foundObj = false; + for (int i = 0; i< num_objs; i++) { + ObjectSpec* os = pkcs_objx->GetObjectSpec(i); + unsigned long oid = os->GetObjectID(); + b[0] = (char)((oid >> 24) & 0xff); + b[1] = (char)((oid >> 16) & 0xff); + b[2] = '\0'; + /* + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "object id =%c:%c b=%s",b[0], b[1], b); + */ + if (PL_strcasecmp(cert_id, b) == 0) { + foundObj = true; + break; + } + } + + + if (foundObj) { + // we already have a certificate there, skip enrollment + RA::Debug(LL_PER_CONNECTION,FN, + "Found certficate. Will not overwrite. Skipped enrollment"); + return status; + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "Certficate not found. Continuing with enrollment"); + } + } + + StatusUpdate(session, extensions, + start_progress + (index * progress_block_size) + + (progress_block_size * 15/100) /* progress */, + "PROGRESS_KEY_GENERATION"); + + if (key_type == KEY_TYPE_ENCRYPTION) {// do serverSide keygen? + + PR_snprintf((char *)configname, 256, "%s.serverKeygen.enable", keyTypePrefix); + RA::Debug(LL_PER_CONNECTION,FN, + "looking for config %s", configname); + serverKeygen = RA::GetConfigStore()->GetConfigAsBool(configname, false); + } + + certEnroll = new CertEnroll(); + + if (serverKeygen) { + RA::Debug(LL_PER_CONNECTION,FN, + "Private key is to be generated on server"); + + PR_snprintf((char *)configname, 256, "%s.serverKeygen.drm.conn", keyTypePrefix); + RA::Debug(LL_PER_CONNECTION,FN, + "looking for config %s", configname); + drmconnid = RA::GetConfigStore()->GetConfigAsString(configname); + + PR_snprintf((char *)configname, 256, "%s.serverKeygen.archive", keyTypePrefix); + bool archive = RA::GetConfigStore()->GetConfigAsBool(configname, true); + + RA::Debug(LL_PER_CONNECTION,FN, + "calling ServerSideKeyGen with userid =%s, archive=%s", userid, archive? "true":"false"); + + RA::ServerSideKeyGen(session, cuid, userid, + channel->getDrmWrappedDESKey(), &pKey, + &wrappedPrivKey, &ivParam, drmconnid, + archive, keysize); + + if (pKey == NULL) { + RA::Error(LL_PER_CONNECTION,FN, + "Failed to generate key on server. Please check DRM."); + RA::Debug(LL_PER_CONNECTION,FN, + "ServerSideKeyGen called, pKey is NULL"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + + PR_snprintf(audit_msg, 512, "ServerSideKeyGen called, failed to generate key on server"); + goto loser; + } else + RA::Debug(LL_PER_CONNECTION,FN, + "key value = %s", pKey); + + + if (wrappedPrivKey == NULL) { + RA::Debug(LL_PER_CONNECTION,FN, + "ServerSideKeyGen called, wrappedPrivKey is NULL"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "ServerSideKeyGen called, wrappedPrivKey is NULL"); + goto loser; + } else + RA::Debug(LL_PER_CONNECTION,FN, + "wrappedPrivKey = %s", wrappedPrivKey); + + if (ivParam == NULL) { + RA::Debug(LL_PER_CONNECTION,FN, + "ServerSideKeyGen called, ivParam is NULL"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "ServerSideKeyGen called, ivParam is NULL"); + goto loser; + } else + RA::Debug(LL_PER_CONNECTION,FN, + "ivParam = %s", ivParam); + + /* + * the following code converts b64-encoded public key info into SECKEYPublicKey + */ + SECStatus rv; + SECItem der; + CERTSubjectPublicKeyInfo* spki = NULL; + + der.type = (SECItemType) 0; /* initialize it, since convertAsciiToItem does not set it */ + rv = ATOB_ConvertAsciiToItem (&der, pKey); + if (rv != SECSuccess){ + RA::Debug(LL_PER_CONNECTION,FN, + "failed to convert b64 private key to binary"); + SECITEM_FreeItem(&der, PR_FALSE); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "ServerSideKeyGen: failed to convert b64 private key to binary"); + goto loser; + }else { + RA::Debug(LL_PER_CONNECTION,FN, + "decoded private key as: secitem (len=%d)",der.len); + + spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der); + + if (spki != NULL) { + RA::Debug(LL_PER_CONNECTION,FN, + "Successfully decoded DER SubjectPublicKeyInfo structure"); + pk_p = SECKEY_ExtractPublicKey(spki); + if (pk_p != NULL) + RA::Debug(LL_PER_CONNECTION,FN, + "Successfully extracted public key from SPKI structure"); + else + RA::Debug(LL_PER_CONNECTION,FN, + "Failed to extract public key from SPKI"); + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "Failed to decode SPKI structure"); + } + + SECITEM_FreeItem(&der, PR_FALSE); + SECKEY_DestroySubjectPublicKeyInfo(spki); + + } + + } else { //generate keys on token + + RA::Debug(LL_PER_CONNECTION,FN, + "Private key is to be generated on token"); + + BYTE alg = 0x80; + + if(key_check && key_check->size()) + alg = 0x81; + + len = channel->StartEnrollment( + se_p1, se_p2, + wrapped_challenge, + key_check, + alg /* alg */, keysize, + 0x00 /* option */); + + RA::Debug(LL_PER_CONNECTION,FN, + "channel->StartEnrollment returned length of public key blob: len=%d", len); + + StatusUpdate(session, extensions, + start_progress + (index * progress_block_size) + + (progress_block_size * 45/100) /* progress */, + "PROGRESS_READ_PUBLIC_KEY"); + + /* read the public key from buffer */ + if (len <= 0) { + RA::Error(LL_PER_CONNECTION,FN, + "Error generating key on token."); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "Error generating key on token"); + goto loser; + } + + RA::Debug(LL_PER_CONNECTION,FN, + "Reading public key buffer from token"); + + BYTE iobuf[4]; + iobuf[0] = 0xff; + iobuf[1] = 0xff; + iobuf[2] = 0xff; + iobuf[3] = 0xff; + /* use ReadObject to read IO buffer */ + public_key = channel->ReadObject(iobuf, 0, len); + if (public_key == NULL) { + RA::Error(LL_PER_CONNECTION,FN, + "Unable to read public key buffer from token"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "Unable to read public key buffer from token"); + goto loser; + } + RA::Debug(LL_PER_CONNECTION,FN, + "Successfully read public key buffer"); + + RA::DebugBuffer(LL_PER_CONNECTION,FN, + "public_key = ", public_key); + + //got public key blob + // parse public key blob and check POP + + RA::Debug(LL_PER_CONNECTION,FN, + "challenge size=%d",plaintext_challenge->size()); + RA::DebugBuffer("RA_Enroll_Processor::process", "challenge = ", + plaintext_challenge); + + + // send status update to the client + StatusUpdate(session, extensions, + start_progress + (index * progress_block_size) + + (progress_block_size * 55/100) /* progress */, + "PROGRESS_PARSE_PUBLIC_KEY"); + + RA::Debug(LL_PER_CONNECTION,FN, + "About to Parse Public Key"); + + pk_p = certEnroll->ParsePublicKeyBlob( + (unsigned char *)(BYTE *)*public_key /*blob*/, + plaintext_challenge); + + if (pk_p == NULL) { + RA::Error(LL_PER_CONNECTION,FN, + "Failed to parse public key"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "Failed to parse public key"); + goto loser; + } + + } //serverKeygen or not + + RA::Debug(LL_PER_CONNECTION,FN, + "Keys generated. Proceeding with certificate enrollment"); + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + applet_version != NULL ? applet_version : "", + keyVersion != NULL? keyVersion : "", + "keys generated"); + + if(publisher_id != NULL) + { + ppEncodedPublicKeyInfo = &encodedPublicKeyInfo; + + } + + pretty_cuid = GetPrettyPrintCUID(cuid); + + nv.Add("pretty_cuid", pretty_cuid); + nv.Add("cuid", cuid); + nv.Add("msn", msn); + nv.Add("userid", userid); + nv.Add("profileId", profileId); + + /* populate auth parameters output to nv also */ + /* so we can reference to the auth parameter by */ + /* using $auth.cn$, or $auth.mail$ */ + if (login != NULL) { + int s = login->Size(); + for (int x = 0; x < s; x++) { + char namebuf[2048]; + char *name = login->GetNameAt(x); + sprintf(namebuf, "auth.%s", name); + nv.Add(namebuf, login->GetValue(name)); + } + } + + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.%s.cuid_label", + OP_PREFIX, tokenType, keyType); + + RA::Debug(LL_PER_CONNECTION,FN, + "Certificate label '%s'", configname); + + pattern = RA::GetConfigStore()->GetConfigAsString(configname, "$cuid$"); + cuid_label = MapPattern(&nv, (char *) pattern); + + StatusUpdate(session, extensions, + start_progress + (index * progress_block_size) + + (progress_block_size * 60/100) /* progress */, + "PROGRESS_ENROLL_CERT"); + + cert = certEnroll->EnrollCertificate( + pk_p, profileId, userid, cuid_label, + connid, audit_msg, ppEncodedPublicKeyInfo); + + if (cert == NULL) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC_CERT_REQ, + userid, cuid, msn, "failure", "enrollment", applet_version, + keyVersion != NULL ? keyVersion : "", + "", connid, audit_msg); + goto loser; + } + + si_mod = pk_p->u.rsa.modulus; + modulus = new Buffer((BYTE*) si_mod.data, si_mod.len); + + /* + * RFC 3279 + * The keyIdentifier is composed of the 160-bit SHA-1 hash of the + * value of the BIT STRING subjectPublicKey (excluding the tag, + * length, and number of unused bits). + */ + spkix = SECKEY_CreateSubjectPublicKeyInfo(pk_p); + + /* + * NSS magically multiply the length with 2^3 in cryptohi/seckey.c + * Hack: + */ + spkix->subjectPublicKey.len >>= 3; + si_kid = PK11_MakeIDFromPubKey(&spkix->subjectPublicKey); + spkix->subjectPublicKey.len <<= 3; + + + keyid = new Buffer((BYTE*) si_kid->data, si_kid->len); + + si_exp = pk_p->u.rsa.publicExponent; + exponent = new Buffer((BYTE*) si_exp.data, si_exp.len); + + RA::Debug(LL_PER_CONNECTION,FN, + "Keyid, modulus and exponent have been extracted from public key"); + + SECKEY_DestroySubjectPublicKeyInfo(spkix); + + cert_string = (char *) cert->string(); + certificates[index] = CERT_DecodeCertFromPackage((char *) cert_string, + (int) cert->size()); + if (certificates[index] != NULL) { + RA::ra_tus_print_integer(cert_serial, &certificates[index]->serialNumber); + RA::Debug("DoEnrollment", "Received Certificate"); + RA::Debug("DoEnrollment", cert_serial); + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC_CERT_REQ, + userid, cuid, msn, "success", "enrollment", applet_version, + (keyVersion != NULL) ? keyVersion : "", cert_serial, connid, "certificate received"); + } + free(cert_string); + ktypes[index] = PL_strdup(keyType); + origins[index] = PL_strdup(cuid); + + if (serverKeygen) { + //do PKCS#8 + + BYTE objid[4]; + + objid[0] = 0xFF; + objid[1] = 0x00; + objid[2] = 0xFF; + objid[3] = 0xF3; + Buffer priv_keyblob; + /* url decode wrappedPrivKey */ + { + Buffer *decodeKey = Util::URLDecode(wrappedPrivKey); + // RA::DebugBuffer("cfu debug"," private key =",decodeKey); + priv_keyblob = + Buffer(1, 0x01) + // encryption + Buffer(1, 0x09)+ // keytype is RSAPKCS8Pair + Buffer(1,(BYTE)(keysize/256)) + // keysize is two bytes + Buffer(1,(BYTE)(keysize%256)) + + Buffer((BYTE*) *decodeKey, decodeKey->size()); + delete decodeKey; + } + + //inject PKCS#8 private key + BYTE perms[6]; + + perms[0] = 0x40; + perms[1] = 0x00; + perms[2] = 0x40; + perms[3] = 0x00; + perms[4] = 0x40; + perms[5] = 0x00; + + if (channel->CreateObject(objid, perms, priv_keyblob.size()) != 1) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "ServerSideKeyGen: store keys in token failed, channel create object error"); + goto loser; + } + + + if (channel->WriteObject(objid, (BYTE*)priv_keyblob, priv_keyblob.size()) != 1) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "ServerSideKeyGen: store keys in token failed, channel write object error"); + goto loser; + } + + + /* url decode the wrapped kek session key and keycheck*/ + Buffer data; + { + + /* + RA::Debug(LL_PER_PDU, "", "getKekWrappedDESKey() returns =%s", channel->getKekWrappedDESKey()); + RA::Debug(LL_PER_PDU, "", "getKeycheck() returns =%s", channel->getKeycheck()); + */ + Buffer *decodeKey = Util::URLDecode(channel->getKekWrappedDESKey()); + + /* + RA::Debug(LL_PER_PDU, "", "des key item len=%d", + decodeKey->size()); + RA::DebugBuffer("cfu debug", "DES key =", decodeKey); + */ + char *keycheck = channel->getKeycheck(); + Buffer *decodeKeyCheck = Util::URLDecode(keycheck); + if (keycheck) + PL_strfree(keycheck); + + /* + RA::Debug(LL_PER_PDU, "", "keycheck item len=%d", + decodeKeyCheck->size()); + RA::DebugBuffer("cfu debug", "key check=", decodeKeyCheck); + */ + + //XXX need randomize this later + + // BYTE iv[] = {0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01}; + // get ivParam + Buffer *iv_decoded = Util::URLDecode(ivParam); + if (ivParam) { + PL_strfree(ivParam); + } + + if(iv_decoded == NULL) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "ServerSideKeyGen: store keys in token failed, iv data not found"); + delete decodeKey; + delete decodeKeyCheck; + goto loser; + } + + BYTE alg = 0x80; + if(decodeKey && decodeKey->size()) { + alg = 0x81; + } + + data = + Buffer((BYTE*)objid, 4)+ // object id + Buffer(1,alg) + + Buffer(1, (BYTE) decodeKey->size()) + // 1 byte length + Buffer((BYTE *) *decodeKey, decodeKey->size())+ // key -encrypted to 3des block + // check size + // key check + Buffer(1, (BYTE) decodeKeyCheck->size()) + //keycheck size + Buffer((BYTE *) *decodeKeyCheck , decodeKeyCheck->size())+ // keycheck + Buffer(1, iv_decoded->size())+ // IV_Length + Buffer((BYTE*)*iv_decoded, iv_decoded->size()); + + delete iv_decoded; + // RA::DebugBuffer("cfu debug", "ImportKeyEnc data buffer =", &data); + + delete decodeKey; + delete decodeKeyCheck; + } + + if (channel->ImportKeyEnc(se_p1, se_p2, &data) != 1) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "ServerSideKeyGen: store keys in token failed, channel import key error"); + goto loser; + } + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + applet_version != NULL ? applet_version : "", + keyVersion != NULL? keyVersion : "", + "server generated keys stored in token"); + + + /* + * After keys are injected successfully, then write certificate object apdu + * to token + */ + + } // serverKeygen + + + StatusUpdate(session, extensions, + start_progress + (index * progress_block_size) + + (progress_block_size * 70/100) /* progress */, + "PROGRESS_PUBLISH_CERT"); + + //Attempt publish if relevant + if(ppEncodedPublicKeyInfo) + { + + publish_result = DoPublish(cuid,encodedPublicKeyInfo,cert,publisher_id,applet_version); + + } + + if(ppEncodedPublicKeyInfo) + { + RA::Debug(LL_PER_CONNECTION,FN, + "Deleting PublicKeyInfo object."); + + SECITEM_FreeItem(*ppEncodedPublicKeyInfo, PR_TRUE); + } + + if(publish_result == 0) + { + status = STATUS_ERROR_PUBLISH; + + RA::Error(LL_PER_CONNECTION,FN, + "Enroll Certificate Publish Failure %d", status); + + RA::Debug(LL_PER_CONNECTION,FN, + "Enroll Certificate Publish Failure %d",status); + PR_snprintf(audit_msg, 512, "publish certificate error"); + goto loser; + } + + if (cert != NULL) { + RA::Debug(LL_PER_CONNECTION,FN, + "Enroll Certificate Finished"); + } else { + RA::Error(LL_PER_CONNECTION,FN, + "Enroll Certificate Failure"); + + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "cert is null"); + goto loser; + } + + StatusUpdate(session, extensions, + start_progress + (index * progress_block_size) + + (progress_block_size * 80/100) /* progress */, + "PROGRESS_IMPORT_CERT"); + + /* write certificate from CA to netkey */ + if (pkcs11obj_enable) { + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (cert_id[0] << 24) + + (cert_id[1] << 16), + cert); + pkcs_objx->AddObjectSpec(objSpec); + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "About to create certificate object on token"); + rc = channel->CreateCertificate(cert_id, cert); + if (rc == -1) { + RA::Error(LL_PER_CONNECTION,FN, + "Failed to create certificate object on token"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "Failed to create certificate object on token"); + goto loser; + } + } + + // build label + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.%s.label", + OP_PREFIX, tokenType, keyType); + RA::Debug(LL_PER_CONNECTION,FN, + "label '%s'", configname); + pattern = RA::GetConfigStore()->GetConfigAsString(configname); + label = MapPattern(&nv, (char *) pattern); + + if (pkcs11obj_enable) { + Buffer b = channel->CreatePKCS11CertAttrsBuffer( + key_type, cert_attr_id, label, keyid); + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (cert_attr_id[0] << 24) + + (cert_attr_id[1] << 16), + &b); + pkcs_objx->AddObjectSpec(objSpec); + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "About to create PKCS#11 certificate Attributes"); + rc = channel->CreatePKCS11CertAttrs(key_type, cert_attr_id, label, keyid); + if (rc == -1) { + RA::Error(LL_PER_CONNECTION,FN, + "PKCS11 Certificate attributes creation failed"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "PKCS11 Certificate attributes creation failed"); + goto loser; + } + } + + if (pkcs11obj_enable) { + RA::Debug(LL_PER_CONNECTION,FN, + "Create PKCS11 Private Key Attributes Buffer"); + Buffer b = channel->CreatePKCS11PriKeyAttrsBuffer(key_type, + pri_attr_id, label, keyid, modulus, OP_PREFIX, + tokenType, keyTypePrefix); + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (pri_attr_id[0] << 24) + + (pri_attr_id[1] << 16), + &b); + pkcs_objx->AddObjectSpec(objSpec); + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "Create PKCS11 Private Key Attributes"); + rc = channel->CreatePKCS11PriKeyAttrs(key_type, pri_attr_id, label, keyid, modulus, OP_PREFIX, tokenType, keyTypePrefix); + if (rc == -1) { + RA::Error(LL_PER_CONNECTION,FN, + "PKCS11 private key attributes creation failed"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "PKCS11 private key attributes creation failed"); + goto loser; + } + } + + if (pkcs11obj_enable) { + Buffer b = channel->CreatePKCS11PubKeyAttrsBuffer(key_type, + pub_attr_id, label, keyid, + exponent, modulus, OP_PREFIX, tokenType, keyTypePrefix); + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (pub_attr_id[0] << 24) + + (pub_attr_id[1] << 16), + &b); + pkcs_objx->AddObjectSpec(objSpec); + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "Create PKCS11 Public Key Attributes"); + rc = channel->CreatePKCS11PubKeyAttrs(key_type, pub_attr_id, label, keyid, + exponent, modulus, OP_PREFIX, tokenType, keyTypePrefix); + if (rc == -1) { + RA::Error(LL_PER_CONNECTION,FN, + "PKCS11 public key attributes creation failed"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "PKCS11 public key attributes creation failed"); + goto loser; + } + } + RA::Debug(LL_PER_CONNECTION,FN, "End of keygen/certificate enrollment"); + + PR_snprintf(activity_msg, 4096, "certificate %s stored on token", cert_serial); + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + applet_version != NULL ? applet_version : "", + keyVersion != NULL? keyVersion : "", + activity_msg); + + RA::tdb_activity(session->GetRemoteIP(), + (char *) cuid, + "enrollment", + "success", + activity_msg, + userid != NULL? userid : "", + tokenType); + +loser: + if (strlen(audit_msg) > 0) { // a failure occurred + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "failure", + "enrollment", + applet_version != NULL ? applet_version : "", + keyVersion != NULL? keyVersion : "", + audit_msg); + + if ((cuid != NULL) && (tokenType != NULL)) { + RA::tdb_activity(session->GetRemoteIP(), + (char *) cuid, + "enrollment", + "failure", + audit_msg, + userid != NULL? userid : "", + tokenType); + } + } + + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + + if( modulus != NULL ) { + delete modulus; + modulus = NULL; + } + if( keyid != NULL ) { + delete keyid; + keyid = NULL; + } + if( exponent != NULL ) { + delete exponent; + exponent = NULL; + } + if( cert != NULL ) { + delete cert; + cert = NULL; + } + if( public_key != NULL ) { + delete public_key; + public_key = NULL; + } + + if (pKey !=NULL) + PR_Free(pKey); + + if (wrappedPrivKey !=NULL) + PR_Free(wrappedPrivKey); + + if( si_kid != NULL ) { + SECITEM_FreeItem( si_kid, PR_TRUE ); + si_kid = NULL; + } + if( certEnroll != NULL ) { + delete certEnroll; + certEnroll = NULL; + } + if( label != NULL ) { + PL_strfree( (char *) label ); + label = NULL; + } + if( cuid_label != NULL ) { + PL_strfree( (char *) cuid_label ); + cuid_label = NULL; + } + if( pretty_cuid != NULL ) { + PR_Free( (char *) pretty_cuid ); + pretty_cuid = NULL; + } + if (pk_p != NULL) { + if (serverKeygen) { + SECKEY_DestroyPublicKey(pk_p); + } else { + free(pk_p); + } + pk_p = NULL; + } + return status; +} + +SECStatus getRandomNumber(unsigned long *number) { + SECStatus rv; + + if (number == NULL) { + return SECFailure; + } + + rv = PK11_GenerateRandom((unsigned char *) number, sizeof(unsigned long)); + return rv; +} + + +/** + * @return true if successfull + */ +bool RA_Enroll_Processor::GetCardManagerAppletInfo( + RA_Session *a_session, /* in */ + Buffer *a_cardmanagerAID, /* in */ + RA_Status &a_status, /* out */ + char * &msn, /* out */ + char * &cuid, /* out */ + Buffer &token_cuid /* out */ +) +{ + bool r = true; // result + Buffer *cplc_data = NULL; + Buffer token_msn; + + SelectApplet(a_session, 0x04, 0x00, a_cardmanagerAID); + cplc_data = GetData(a_session); + if (cplc_data == NULL) { + RA::Error("RA_Enroll_Processor::Process", + "Get Data Failed"); + a_status = STATUS_ERROR_SECURE_CHANNEL; + r = false; + goto loser; + } + RA::DebugBuffer("RA_Enroll_Processor::process", "CPLC Data = ", + cplc_data); + if (cplc_data->size() < 47) { + RA::Error("RA_Format_Processor::Process", + "Invalid CPLC Size"); + a_status = STATUS_ERROR_SECURE_CHANNEL; + r = false; + goto loser; + } + token_cuid = Buffer(cplc_data->substr(3,4)) + + Buffer(cplc_data->substr(19,2)) + + Buffer(cplc_data->substr(15,4)); + RA::DebugBuffer("RA_Enroll_Processor::process", "Token CUID= ", + &token_cuid); + cuid = Util::Buffer2String(token_cuid); + RA::Debug("RA_Enroll_Processor::process", "CUID(String)= '%s'", + cuid); + token_msn = Buffer(cplc_data->substr(41, 4)); + RA::DebugBuffer("RA_Enroll_Processor::process", "Token MSN= ", + &token_msn); + msn = Util::Buffer2String(token_msn); + RA::Debug("RA_Enroll_Processor::process", "MSN(String)= '%s'", + msn); + loser: + if( cplc_data != NULL ) { + delete cplc_data; + } + + return r; +} + +bool RA_Enroll_Processor::GetAppletInfo( + RA_Session *a_session, /* in */ + Buffer *a_aid , /* in */ + BYTE &o_major_version, + BYTE &o_minor_version, + BYTE &o_app_major_version, + BYTE &o_app_minor_version) +{ + int total_mem = 0; + int free_mem = 0; + Buffer *token_status = NULL; + SelectApplet(a_session, 0x04, 0x00, a_aid); + token_status = GetStatus(a_session, 0x00, 0x00); + if (token_status == NULL) { + o_major_version = 0x0; + o_minor_version = 0x0; + o_app_major_version = 0x0; + o_app_minor_version = 0x0; + } else { + o_major_version = ((BYTE*)*token_status)[0]; // is this protocol version? + o_minor_version = ((BYTE*)*token_status)[1]; + o_app_major_version = ((BYTE*)*token_status)[2]; // and this applet version? + o_app_minor_version = ((BYTE*)*token_status)[3]; + + BYTE tot_high = ((BYTE*)*token_status)[6]; + BYTE tot_low = ((BYTE*)*token_status)[7]; + + BYTE free_high = ((BYTE*)*token_status)[10]; + BYTE free_low = ((BYTE*)*token_status)[11]; + + total_mem = (tot_high << 8) + tot_low; + free_mem = (free_high << 8) + free_low; + + totalAvailableMemory = total_mem; + totalFreeMemory = free_mem; + + RA::DebugBuffer("RA_Enroll_Processor::Process AppletInfo Data", "Data=", token_status); + delete token_status; + } + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Major=%d Minor=%d Applet Major=%d Applet Minor=%d Total Mem %d Free Mem %d", + o_major_version, o_minor_version, o_app_major_version, o_app_minor_version,total_mem,free_mem); + return true; +} + + +/** + * Query applet for build ID info + * 'Pretty'-print it into useful format, along with version info + * example input: + * a_app_major_version = 1 + * a_app_minor_version = 3 + * Examples for the following outputs: + * o_av = "1.3.45FC0218" + * The caller is responsible for free'ing (o_av) + */ +bool RA_Enroll_Processor::FormatAppletVersionInfo( + RA_Session *a_session, + const char *a_tokenType, + char *a_cuid, + BYTE a_app_major_version, + BYTE a_app_minor_version, + RA_Status &o_status, // out + char * &o_av // out. +) +{ + bool r=true; + char configname[256]; + char *av=NULL; + + // retrieve the 4-byte applet ID from the token + Buffer *tokenBuildID = GetAppletVersion(a_session); + + if (tokenBuildID == NULL) { + // If there was no applet on the token + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.emptyToken.enable", OP_PREFIX, + a_tokenType); + // XXX checks if emptyToken is enabled. This should probably get moved + // to the applet update function, and leave this fn only for getting + // the version information + if (!RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + RA::Error("RA_Enroll_Processor::Process", + "no applet found and applet upgrade not enabled"); + o_status = STATUS_ERROR_SECURE_CHANNEL; // XXX incorrect error message + r=false; + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "secure channel not established", "", a_tokenType); // XXX incorrect error message + goto loser; + } + } else { + // if there was an applet on the token: + char * bid_string = Util::Buffer2String(*tokenBuildID); + RA::Debug("RA_Enroll_Processor", "buildid = %s", bid_string); + av = PR_smprintf( "%x.%x.%s", + a_app_major_version, a_app_minor_version, bid_string); + PR_Free(bid_string); + } + o_av = (av == NULL) ? strdup("") : av; + + RA::Debug("RA_Enroll_Processor", "final_applet_version = %s", o_av); +loser: + if( tokenBuildID != NULL ) { + delete tokenBuildID; + } + return r; +} + +/** + * Checks if we need to upgrade applet. + * The version of the current token is passed IN to this function + * in o_current_applet_on_token. If the applet is upgraded, this + * out parameter will be set to the new applet version id. + * maj/minor versions will be also updated if the applet was updated. + */ +bool RA_Enroll_Processor::CheckAndUpgradeApplet( + RA_Session *a_session, + NameValueSet *a_extensions, + char *a_cuid, + const char *a_tokenType, + char *&o_current_applet_on_token, + BYTE &o_major_version, + BYTE &o_minor_version, + Buffer *a_aid, + const char *a_msn, + const char *a_userid, + RA_Status &o_status, + char **keyVersion ) +{ + int rc = 0; + const char *FN = "RA_Enroll_Processor::CheckAndUpgradeApplet"; + bool r = true; + const char *applet_dir=NULL; + const char *connid = NULL; + Buffer *token_status = NULL; + char configname[256]; + + // You specify the following parameters to get applet upgrade working + // *.update.applet.enable=true + // *.update.applet.requiredVersion=maj.min.xxxxxxxx + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.encryption", OP_PREFIX, a_tokenType); + SecurityLevel security_level = SECURE_MSG_MAC; + if (RA::GetConfigStore()->GetConfigAsBool(configname, true)) + security_level = SECURE_MSG_MAC_ENC; + + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.enable", OP_PREFIX, a_tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.requiredVersion", OP_PREFIX, a_tokenType); + g_applet_target_version = RA::GetConfigStore()->GetConfigAsString(configname); + if (g_applet_target_version == NULL) { + RA::Error(FN, "upgrade.version not found"); + o_status = STATUS_ERROR_MISCONFIGURATION; + r = false; + goto loser; + } + /* Bugscape #55826: used case-insensitive check below */ + if (PL_strcasecmp(g_applet_target_version, o_current_applet_on_token) != 0) { + RA::Debug(LL_PER_CONNECTION, FN, "tokenType=%s before updating applet", a_tokenType); + /* upgrade applet */ + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.directory", OP_PREFIX, a_tokenType); + applet_dir = RA::GetConfigStore()->GetConfigAsString(configname); + if (applet_dir == NULL || strlen(applet_dir) == 0) { + RA::Error(LL_PER_CONNECTION, FN, + "Failed to read applet directory parameter %s", configname); + o_status = STATUS_ERROR_MISCONFIGURATION; + r = false; + goto loser; + } + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, a_tokenType); + connid = RA::GetConfigStore()->GetConfigAsString(configname); + RA::Debug(FN, "TKS connection id =%s", connid); + //StatusUpdate(a_session, a_extensions, 5, "PROGRESS_UPGRADE_APPLET"); + + if (rc = UpgradeApplet(a_session, (char *) OP_PREFIX, (char*) a_tokenType, + o_major_version, o_minor_version, + g_applet_target_version, + applet_dir, security_level, + connid, a_extensions, + 5, + 12, + keyVersion) != 1) { + + RA::Debug(FN, "applet upgrade failed"); + /** + * Bugscape #55709: Re-select Net Key Applet ONLY on failure. + */ + SelectApplet(a_session, 0x04, 0x00, a_aid); + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "applet upgrade error", "", a_tokenType); + o_status = STATUS_ERROR_UPGRADE_APPLET; + r = false; + + if (rc == -1) { + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + a_userid, a_cuid, a_msn, "Failure", "enrollment", + *keyVersion != NULL? *keyVersion : "", o_current_applet_on_token, g_applet_target_version, "failed to setup secure channel"); + } else { + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + a_userid, a_cuid, a_msn, "Success", "enrollment", + *keyVersion != NULL? *keyVersion : "", o_current_applet_on_token, g_applet_target_version, "setup secure channel"); + } + + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + a_userid, a_cuid, a_msn, "Failure", "enrollment", + *keyVersion != NULL? *keyVersion : "", + o_current_applet_on_token, g_applet_target_version, + "applet upgrade"); + + goto loser; + } else { + // there may be a better place to do this, but worth testing here + // RA::tdb_update(a_cuid, g_applet_target_version); + } + + // Upgrade Applet reported success + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + a_userid, a_cuid, a_msn, "Success", "enrollment", + *keyVersion != NULL? *keyVersion : "", o_current_applet_on_token, g_applet_target_version, "setup secure channel"); + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + a_userid, a_cuid, a_msn, "Success", "enrollment", + *keyVersion != NULL? *keyVersion : "", + o_current_applet_on_token, g_applet_target_version, + "applet upgrade"); + + o_current_applet_on_token = strdup(g_applet_target_version); + + token_status = GetStatus(a_session, 0x00, 0x00); + if (token_status == NULL) { + RA::Error(FN, "Get Status Failed"); + o_status = STATUS_ERROR_SECURE_CHANNEL; // XXX + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "secure channel error", "", a_tokenType); + r = false; + goto loser; + } + + o_major_version = ((BYTE*)*token_status)[2]; // applet version + o_minor_version = ((BYTE*)*token_status)[3]; // not protocol version +loser: + if( token_status != NULL ) { + delete token_status; + } + } + } else { + RA::Debug(FN, "Applet Upgrade has been disabled."); + } + return r; +} + +/** + * Authenticate user with LDAP plugin + * @return true if authentication was successful + */ +bool RA_Enroll_Processor::AuthenticateUserLDAP( + RA_Session *a_session, + NameValueSet *a_extensions, + char *a_cuid, + AuthenticationEntry *a_auth, + AuthParams *&login, + RA_Status &o_status, + const char *a_token_type +) +{ + const char *FN = "RA_Enroll_Processor::AuthenticateUserLDAP"; + int retry_limit = a_auth->GetAuthentication()->GetNumOfRetries(); + int retries = 0; + int rc; + bool r=false; + + RA::Debug(LL_PER_PDU, FN, "LDAP_Authentication is invoked."); + rc = a_auth->GetAuthentication()->Authenticate(login); + + RA::Debug(FN, "Authenticate returned: %d", rc); + + // rc: (0:login correct) (-1:LDAP error) (-2:User not found) (-3:Password error) + + // XXX replace with proper enums + // XXX evaluate rc==0 as specific case - this is success, it shouldn't be the default + + while ((rc == TPS_AUTH_ERROR_USERNOTFOUND || + rc == TPS_AUTH_ERROR_PASSWORDINCORRECT ) + && (retries < retry_limit)) { + login = RequestLogin(a_session, 0 /* invalid_pw */, 0 /* blocked */); + retries++; + if (login != NULL) + rc = a_auth->GetAuthentication()->Authenticate(login); + } + + switch (rc) { + case TPS_AUTH_OK: + RA::Debug(LL_PER_PDU, FN, "Authentication successful."); + r=true; + break; + case TPS_AUTH_ERROR_LDAP: + RA::Error(FN, "Authentication failed. LDAP Error"); + o_status = STATUS_ERROR_LDAP_CONN; + RA::Debug(LL_PER_PDU, FN, "Authentication status=%d rc=%d", o_status,rc); + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "authentication error", "", a_token_type); + r = false; + break; + case TPS_AUTH_ERROR_USERNOTFOUND: + RA::Error(FN, "Authentication failed. User not found"); + o_status = STATUS_ERROR_LOGIN; + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "authentication error", "", a_token_type); + r = false; + break; + case TPS_AUTH_ERROR_PASSWORDINCORRECT: + RA::Error(FN, "Authentication failed. Password Incorrect"); + o_status = STATUS_ERROR_LOGIN; + RA::Debug(LL_PER_PDU, FN, "Authentication status=%d rc=%d", o_status,rc); + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "authentication error", "", a_token_type); + r = false; + break; + default: + RA::Error(FN, "Undefined LDAP Auth Error."); + r = false; + break; + } + + return r; +} + +/** + * Request Login info and user id from user, if necessary + * This call will allocate a new Login structure, + * and a char* for the user id. The caller is responsible + * for freeing this memory + * @return true of success, false if failure + */ +bool RA_Enroll_Processor::RequestUserId( + RA_Session * a_session, + NameValueSet *a_extensions, + const char * a_configname, + const char * a_tokenType, + char *a_cuid, + AuthParams *& o_login, const char *&o_userid, RA_Status &o_status) +{ + + if (RA::GetConfigStore()->GetConfigAsBool(a_configname, 1)) { + if (a_extensions != NULL && + a_extensions->GetValue("extendedLoginRequest") != NULL) + { + // XXX - extendedLoginRequest + RA::Debug("RA_Enroll_Processor::RequestUserId", + "Extended Login Request detected"); + AuthenticationEntry *entry = GetAuthenticationEntry( + OP_PREFIX, a_configname, a_tokenType); + char **params = NULL; + char pb[1024]; + char *locale = NULL; + if (a_extensions != NULL && + a_extensions->GetValue("locale") != NULL) + { + locale = a_extensions->GetValue("locale"); + } else { + locale = ( char * ) "en"; /* default to english */ + } + int n = entry->GetAuthentication()->GetNumOfParamNames(); + if (n > 0) { + RA::Debug("RA_Enroll_Processor::RequestUserId", + "Extended Login Request detected n=%d", n); + params = (char **) PR_Malloc(n); + for (int i = 0; i < n; i++) { + sprintf(pb,"id=%s&name=%s&desc=%s&type=%s&option=%s", + entry->GetAuthentication()->GetParamID(i), + entry->GetAuthentication()->GetParamName(i, locale), + entry->GetAuthentication()->GetParamDescription(i, locale), + entry->GetAuthentication()->GetParamType(i), + entry->GetAuthentication()->GetParamOption(i) + ); + params[i] = PL_strdup(pb); + RA::Debug("RA_Enroll_Processor::RequestUserId", + "params[i]=%s", params[i]); + } + } + RA::Debug("RA_Enroll_Processor::RequestUserId", "Extended Login Request detected calling RequestExtendedLogin() locale=%s", locale); + + char *title = PL_strdup(entry->GetAuthentication()->GetTitle(locale)); + RA::Debug("RA_Enroll_Processor::RequestUserId", "title=%s", title); + char *description = PL_strdup(entry->GetAuthentication()->GetDescription(locale)); + RA::Debug("RA_Enroll_Processor::RequestUserId", "description=%s", description); + o_login = RequestExtendedLogin(a_session, 0 /* invalid_pw */, 0 /* blocked */, params, n, title, description); + + if (params != NULL) { + for (int nn=0; nn < n; nn++) { + if (params[nn] != NULL) { + PL_strfree(params[nn]); + params[nn] = NULL; + } + } + free(params); + params = NULL; + } + + if (title != NULL) { + PL_strfree(title); + title = NULL; + } + + if (description != NULL) { + PL_strfree(description); + description = NULL; + } + + if (o_login == NULL) { + RA::Error("RA_Enroll_Processor::Process", + "login not provided"); + o_status = STATUS_ERROR_LOGIN; + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, + "enrollment", "failure", "login not found", "", a_tokenType); + return false; + } + + RA::Debug("RA_Enroll_Processor::RequestUserId", + "Extended Login Request detected calling RequestExtendedLogin() login=%x", o_login); + o_userid = PL_strdup( o_login->GetUID() ); + RA::Debug("RA_Enroll_Processor::Process", + "userid = '%s'", o_userid); + } else { + o_login = RequestLogin(a_session, 0 /* invalid_pw */, 0 /* blocked */); + if (o_login == NULL) { + RA::Error("RA_Enroll_Processor::Process", + "login not provided"); + o_status = STATUS_ERROR_LOGIN; + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, + "enrollment", "failure", "login not found", o_userid, a_tokenType); + return false; + } + o_userid = PL_strdup( o_login->GetUID() ); + RA::Debug("RA_Enroll_Processor::Process", + "userid = '%s'", o_userid); + } + } + return true; +} + +/** + * Authenticate the user with the configured authentication plugin + * @return true if authentication successful + */ + +bool RA_Enroll_Processor::AuthenticateUser( + RA_Session * a_session, + const char * a_configname, + char *a_cuid, + NameValueSet *a_extensions, + const char *a_tokenType, + AuthParams *& a_login, const char *&o_userid, RA_Status &o_status + ) +{ + bool r=false; + + RA::Debug("RA_Enroll_Processor::AuthenticateUser", "started"); + if (RA::GetConfigStore()->GetConfigAsBool(a_configname, false)) { + if (a_login == NULL) { + RA::Error("RA_Enroll_Processor::AuthenticateUser", "Login Request Disabled. Authentication failed."); + o_status = STATUS_ERROR_LOGIN; + goto loser; + } + + RA::Debug("RA_Enroll_Processor::AuthenticateUser", + "Authentication enabled"); + char configname[256]; + PR_snprintf((char *)configname, 256, "%s.%s.auth.id", OP_PREFIX, a_tokenType); + const char *authid = RA::GetConfigStore()->GetConfigAsString(configname); + if (authid == NULL) { + o_status = STATUS_ERROR_LOGIN; + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "login not found", "", a_tokenType); + goto loser; + } + AuthenticationEntry *auth = RA::GetAuth(authid); + + if (auth == NULL) { + o_status = STATUS_ERROR_LOGIN; + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "authentication error", "", a_tokenType); + goto loser; + } + + StatusUpdate(a_session, a_extensions, 2, "PROGRESS_START_AUTHENTICATION"); + + char *type = auth->GetType(); + if (type == NULL) { + o_status = STATUS_ERROR_LOGIN; + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "authentication is missing param type", "", a_tokenType); + r = false; + goto loser; + } + + if (strcmp(type, "LDAP_Authentication") == 0) { + RA::Debug("RA_Enroll_Processor::AuthenticateUser", "LDAP started"); + r = AuthenticateUserLDAP(a_session, a_extensions, a_cuid, auth, a_login, o_status, a_tokenType); + o_status = STATUS_ERROR_LOGIN; + goto loser; + } else { + RA::Error("RA_Enroll_Processor::AuthenticateUser", "No Authentication type was found."); + o_status = STATUS_ERROR_LOGIN; + RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, "enrollment", "failure", "authentication error", "", a_tokenType); + r = false; + goto loser; + } + } else { + r = true; + RA::Debug("RA_Enroll_Processor::AuthenticateUser", + "Authentication has been disabled."); + } + loser: + return r; +} + + + + + /** + * Checks if the token has the required key version. + * If not, we can swap out the keys on the token with another + * set of keys + */ + +/* XXX AID's should be member variables */ +bool RA_Enroll_Processor::CheckAndUpgradeSymKeys( + //RA_Session * a_session, + //NameValueSet *a_extensions, + //const char * a_configname, + //char *a_cuid, + RA_Session *a_session, + NameValueSet* a_extensions, + char *a_cuid, + const char *a_tokenType, + char *a_msn, + const char *a_applet_version, + const char *a_userid, + const char *a_key_version, + Buffer *a_cardmanagerAID, /* in */ + Buffer *a_appletAID, /* in */ + Secure_Channel *&o_channel, /* out */ + RA_Status &o_status /* out */ + ) +{ + char *FN = ( char * ) "RA_EnrollProcessor::CheckAndUpgradeSymKeys"; + char configname[256]; + const char *connid = NULL; + const char *tksid = NULL; + int rc; + bool r = false; + Buffer key_data_set; + char audit_msg[512] = ""; + char curVer[10]; + char newVer[10]; + + char *curKeyInfoStr = NULL; + char *newVersionStr = NULL; + + // the TKS is responsible for doing much of the symmetric keys update + // so lets find which TKS we're talking about TKS now. + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, a_tokenType); + tksid = RA::GetConfigStore()->GetConfigAsString(configname); + + PR_snprintf((char *)configname, 256,"%s.%s.update.symmetricKeys.enable", OP_PREFIX, a_tokenType); + + RA::Debug(FN, "Symmetric Keys %s", configname); + + if (RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + + RA::Debug(LL_PER_CONNECTION, FN, + "tokenType=%s configured to update symmetric keys", a_tokenType); + + // the requiredVersion config parameter indicates what key version + // the token should have before further operations. If the token + // has an older version, we try to change it. + PR_snprintf((char *)configname, 256, + "%s.%s.update.symmetricKeys.requiredVersion", OP_PREFIX, a_tokenType); + + int requiredV = RA::GetConfigStore()->GetConfigAsInt(configname, 0x00); + + // If there was a secure channel set up, let's clear it out + if( o_channel != NULL ) { + delete o_channel; + o_channel = NULL; + } + // try to make a secure channel with the 'requiredVersion' keys + // If this fails, we know we will have to attempt an upgrade + // of the keys + PR_snprintf((char *)configname, 256,"channel.defKeyIndex"); + int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + o_channel = SetupSecureChannel(a_session, + requiredV, + defKeyIndex /* default key index */, tksid); + + // If that failed, we need to find out what version of keys + // are on the token + if (o_channel != NULL) { + r = true; + } else { + /** + * Select Card Manager for Put Key operation. + */ + SelectApplet(a_session, 0x04, 0x00, a_cardmanagerAID); + /* if the key of the required version is + * not found, create them. + */ + // This sends a InitializeUpdate request to the token. + // We tell the token to use whatever it thinks is the + // default key version (0). It will return the version + // of the key it actually used later. (This is accessed + // with GetKeyInfoData below) + // [ Note: This is not explained very well in the manual + // The token can have multiple sets of symmetric keys + // Each set is given a version number, which I think is + // better thought of as a SLOT. One key slot is populated + // with a set of keys when the token is manufactured. + // This is then designated as the default key set version. + // Later, we will write a new key set with PutKey, and + // set it to be the new default] + PR_snprintf((char *)configname, 256,"channel.defKeyVersion"); + int defKeyVer = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + PR_snprintf((char *)configname, 256,"channel.defKeyIndex"); + int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + o_channel = SetupSecureChannel(a_session, + defKeyVer, /* default key version */ + defKeyIndex /* default key index */, tksid); + + if (o_channel == NULL) { + PR_snprintf(audit_msg, 512, "enrollment processing, failed to create secure channel"); + + RA::Error(FN, "failed to establish secure channel"); + o_status = STATUS_ERROR_SECURE_CHANNEL; + goto loser; + } + + /* Complete the secure channel handshake */ + /* XXX need real enumeration of error codes here */ + rc = o_channel->ExternalAuthenticate(); + if (rc != 1) { + RA::Error(FN, "External authentication in secure channel failed"); + o_status = STATUS_ERROR_EXTERNAL_AUTH; + /* XXX should print out error codes */ + PR_snprintf(audit_msg, 512, "enrollment processing, external authentication error"); + goto loser; + } + + // Assemble the Buffer with the version information + // The second byte is the key offset, which is always 1 + BYTE nv[2] = { requiredV, 0x01 }; + Buffer newVersion(nv, 2); + + // GetKeyInfoData will return a buffer which is bytes 11,12 of + // the data structure on page 89 of Cyberflex Access Programmer's + // Guide + // Byte 0 is the key set version. + // Byte 1 is the index into that key set + Buffer curKeyInfo = o_channel->GetKeyInfoData(); + + + // This code makes a call to the TKS to get a new key set for + // the token. The new key set data is written to the Buffer + // key_data_set. + PR_snprintf((char *)configname, 256,"%s.%s.tks.conn", OP_PREFIX, a_tokenType); + connid = RA::GetConfigStore()->GetConfigAsString(configname); + + rc = CreateKeySetData( + o_channel->GetKeyDiversificationData(), + curKeyInfo, + newVersion, + key_data_set, connid); + if (rc != 1) { + RA::Error(FN, "failed to create new key set"); + o_status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512, "enrollment processing, create card key error"); + goto loser; + } + + StatusUpdate(a_session, a_extensions, 13, "PROGRESS_PUT_KEY"); + + // sends a PutKey PDU with the new key set to change the + // keys on the token + BYTE curVersion = ((BYTE*)curKeyInfo)[0]; + BYTE curIndex = ((BYTE*)curKeyInfo)[1]; + rc = o_channel->PutKeys(a_session, + curVersion, + curIndex, + &key_data_set); + + + curKeyInfoStr = Util::Buffer2String(curKeyInfo); + newVersionStr = Util::Buffer2String(newVersion); + + if(curKeyInfoStr != NULL && strlen(curKeyInfoStr) >= 2) { + curVer[0] = curKeyInfoStr[0]; curVer[1] = curKeyInfoStr[1]; curVer[2] = 0; + } + else { + curVer[0] = 0; + } + + if(newVersionStr != NULL && strlen(newVersionStr) >= 2) { + newVer[0] = newVersionStr[0] ; newVer[1] = newVersionStr[1] ; newVer[2] = 0; + } + else { + newVer[0] = 0; + } + + + if (rc!=0) { + RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER, + a_userid != NULL ? a_userid : "", a_cuid != NULL ? a_cuid : "", a_msn != NULL ? a_msn : "", "Failure", "enrollment", + a_applet_version != NULL ? a_applet_version : "", curVer, newVer, + "key changeover"); + + if ((a_cuid != NULL) && (a_tokenType != NULL)) { + RA::tdb_activity(a_session->GetRemoteIP(), + a_cuid, + "enrollment", + "failure", + "key changeover failed", + a_userid != NULL? a_userid : "", + a_tokenType); + } + goto loser; + } else { + RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER, + a_userid != NULL ? a_userid : "", a_cuid != NULL ? a_cuid : "", a_msn != NULL ? a_msn : "", "Success", "enrollment", + a_applet_version != NULL ? a_applet_version : "", curVer, newVer, + "key changeover"); + } + + /** + * Re-select the Applet. + */ + SelectApplet(a_session, 0x04, 0x00, a_appletAID); + if( o_channel != NULL ) { + delete o_channel; + o_channel = NULL; + } + + // Make a new secure channel with the new symmetric keys + o_channel = SetupSecureChannel(a_session, requiredV, + defKeyIndex /* default key index */, tksid); + if (o_channel == NULL) { + RA::Error(FN, "failed to establish secure channel after reselect"); + o_status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512, "enrollment processing, secure channel setup error after reselect"); + goto loser; + } else { + RA::Debug(FN, "Key Upgrade has completed successfully."); + r = true; // Success!! + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + a_userid != NULL ? a_userid : "", a_cuid != NULL ? a_cuid : "", + a_msn != NULL ? a_msn : "", "success", "enrollment", a_applet_version != NULL ? a_applet_version : "", + newVer, "enrollment processing, key upgrade completed"); + } + + } + } else { + + RA::Debug(FN, "Key Upgrade has been disabled."); + + if( o_channel != NULL ) { + delete o_channel; + o_channel = NULL; + } + PR_snprintf((char *)configname, 256,"channel.defKeyVersion"); + int defKeyVer = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + PR_snprintf((char *)configname, 256,"channel.defKeyIndex"); + int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + o_channel = SetupSecureChannel(a_session, + defKeyVer, + defKeyIndex /* default key index */, tksid); + r = true; // Sucess!! + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + a_userid, a_cuid, a_msn, "success", "enrollment", a_applet_version, + a_key_version != NULL? a_key_version: "", + "enrollment processing, key upgrade disabled"); + } +loser: + + if (curKeyInfoStr != NULL) { + PR_Free( (char *) curKeyInfoStr); + curKeyInfoStr = NULL; + } + + if (newVersionStr != NULL) { + PR_Free( (char *) newVersionStr); + newVersionStr = NULL; + } + + if (strlen(audit_msg) > 0) { // a failure occurred + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + a_userid != NULL ? a_userid : "", + a_cuid != NULL ? a_cuid : "", + a_msn != NULL ? a_msn : "", + "failure", + "enrollment", + a_applet_version != NULL ? a_applet_version : "", + a_key_version != NULL? a_key_version : "", + audit_msg); + + if ((a_cuid != NULL) && (a_tokenType != NULL)) { + RA::tdb_activity(a_session->GetRemoteIP(), + a_cuid, + "enrollment", + "failure", + audit_msg, + a_userid != NULL? a_userid : "", + a_tokenType); + } + } + + return r; +} + +/** + * Processes the current session. + */ +TPS_PUBLIC RA_Status RA_Enroll_Processor::Process(RA_Session *session, NameValueSet *extensions) +{ + char *FN = ( char * ) "RA_Enroll_Processor::Process"; + char configname[256]; + char *cuid = NULL; + char *msn = NULL; + PRIntervalTime start, end; + RA_Status status = STATUS_NO_ERROR; + int rc = -1; + Secure_Channel *channel = NULL; + Buffer kdd; + AuthParams *login = NULL; + char *new_pin = NULL; +#define PLAINTEXT_CHALLENGE_SIZE 16 +#define WRAPPED_CHALLENGE_SIZE 16 + Buffer *plaintext_challenge = + new Buffer(PLAINTEXT_CHALLENGE_SIZE, (BYTE)0); + Buffer *wrapped_challenge = new Buffer(WRAPPED_CHALLENGE_SIZE, (BYTE)0); + Buffer *key_check = new Buffer(0, (BYTE)0); + const char *tokenType = NULL; + + //SecurityLevel security_level = SECURE_MSG_MAC_ENC; + BYTE major_version = 0x0; + BYTE minor_version = 0x0; + BYTE app_major_version = 0x0; + BYTE app_minor_version = 0x0; + int isPinPresent = 0; + Buffer *object = NULL; + int seq = 0x00; + unsigned long lastFormatVersion = 0x00; + unsigned long lastObjectVersion = 0x00; + int foundLastObjectVersion = 0; + int pkcs11obj_enable = 0; + int compress = 0; + NameValueSet nv; + int o_certNums = 0; + + CertEnroll *certEnroll = NULL; + + Buffer *token_status = NULL; + char* appletVersion = NULL; + char *final_applet_version = NULL; + + char *keyVersion = PL_strdup( "" ); + const char *userid = PL_strdup( "" ); + char *token_state = PL_strdup("inactive"); + char *khex = NULL; + + Buffer host_challenge = Buffer(8, (BYTE)0); + Buffer key_diversification_data; + Buffer key_info_data; + Buffer card_challenge; + Buffer card_cryptogram; + const char *connid = NULL; + const char *tksid = NULL; + const char *authid = NULL; + PKCS11Obj *pkcs11objx = NULL; + Buffer labelBuffer; + char activity_msg[4096]; + char audit_msg[512] = ""; + + Buffer *CardManagerAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_CARDMGR_INSTANCE_AID, + RA::CFG_DEF_CARDMGR_INSTANCE_AID); + Buffer *NetKeyAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_NETKEY_INSTANCE_AID, + RA::CFG_DEF_NETKEY_INSTANCE_AID); + Buffer token_cuid; + int maxRetries = 3; + const char *pattern = NULL; + char *label = NULL; + CERTCertificate **certificates = NULL; + char **ktypes = NULL; + char **origins = NULL; + char **tokenTypes = NULL; + char *tokentype = NULL; + char *profile_state = NULL; + RA_Status st; + bool renewed = false; + bool do_force_format = false; + + RA::Debug("RA_Enroll_Processor::Process", "Client %s", + session->GetRemoteIP()); + RA::Debug(LL_PER_PDU, FN, "Begin enroll process"); + + // XXX need to validate all user input (convert to 'string' types) + // to ensure that no buffer overruns + start = PR_IntervalNow(); + + /* Get the card serial number */ + if (!GetCardManagerAppletInfo(session, CardManagerAID, st, msn, cuid, token_cuid)) goto loser; + + /* Get the applet version information */ + if (!GetAppletInfo(session, NetKeyAID, + /*by ref*/ major_version, minor_version, + app_major_version, app_minor_version )) goto loser; + + if (!GetTokenType(OP_PREFIX, major_version, minor_version, + cuid, msn, extensions, + status, tokenType)) { /* last two are 'out' params */ + /* ADE figure out what to do here for this line*/ + // RA::tdb_activity(session->GetRemoteIP(), cuid, "enrollment", "failure", "token type not found", ""); + goto loser; + } + + // check if profile is enabled here + PR_snprintf((char *)configname, 256, "config.Profiles.%s.state", tokenType); + profile_state = (char *) RA::GetConfigStore()->GetConfigAsString(configname); + if ((profile_state != NULL) && (PL_strcmp(profile_state, "Enabled") != 0)) { + RA::Error(FN, "Profile %s Disabled for CUID %s", tokenType, cuid); + status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + PR_snprintf(audit_msg, 512, "profile %s disabled", tokenType); + goto loser; + } + + if (RA::ra_is_token_present(cuid)) { + RA::Debug(FN, "Found token %s", cuid); + if (RA::ra_is_tus_db_entry_disabled(cuid)) { + RA::Error(FN, "CUID %s Disabled", cuid); + status = STATUS_ERROR_DISABLED_TOKEN; + PR_snprintf(audit_msg, 512, "token disabled"); + goto loser; + } + + // at this point, token is either active or uninitialized (formatted) + // or the adminstrator has called for a force format. + + do_force_format = RA::ra_force_token_format(cuid); + + RA::Debug("RA_Enroll_Processor::Process","force format flag %d", do_force_format); + + if (!RA::ra_allow_token_reenroll(cuid) && + !RA::ra_allow_token_renew(cuid) && + !do_force_format) { + RA::Error(FN, "CUID %s Re-Enrolled Disallowed", cuid); + status = STATUS_ERROR_DISABLED_TOKEN; + PR_snprintf(audit_msg, 512, "token re-enrollment or renewal disallowed"); + goto loser; + } + } else { + RA::Debug(FN, "Not Found token %s", cuid); + // This is a new token. We need to check our policy to see + // if we should allow enrollment. raidzilla #57414 + PR_snprintf((char *)configname, 256, "%s.allowUnknownToken", + OP_PREFIX); + if (!RA::GetConfigStore()->GetConfigAsBool(configname, 1)) { + RA::Error(FN, "CUID %s Enroll Unknown Token", cuid); + status = STATUS_ERROR_DISABLED_TOKEN; + PR_snprintf(audit_msg, 512, "unknown token disallowed"); + goto loser; + } + } + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL ? keyVersion : "", + "token enabled"); + + + /* XXX - this comment does not belong here + * + * This is very risky to call initialize and then + * external authenticate later on. + * The token will be locked if no external authenticate + * follows the initialize update. + */ + + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", + OP_PREFIX, tokenType); + tksid = RA::GetConfigStore()->GetConfigAsString(configname); + if (tksid == NULL) { + RA::Error(FN, "TKS Connection Parameter %s Not Found", configname); + status = STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND; + PR_snprintf(audit_msg, 512, "token type TKS connection parameter not found"); + goto loser; + } + + /* figure some more information about the applet version */ + /* XXX should probably move this further down, since the results + of this function aren't used til much later */ + if (!FormatAppletVersionInfo(session, tokenType, cuid, + app_major_version, app_minor_version, + status, + final_applet_version /*out */)) { + PR_snprintf(audit_msg, 512, "FormatAppletVersionInfo error"); + goto loser; + } + + PR_snprintf((char *)configname, 256, "%s.%s.loginRequest.enable", OP_PREFIX, tokenType); + if (!RequestUserId(session, extensions, configname, tokenType, cuid, login, userid, status)){ + PR_snprintf(audit_msg, 512, "RequestUserId error"); + goto loser; + } + + PR_snprintf((char *)configname, 256, "%s.%s.auth.enable", OP_PREFIX, tokenType); + + if (!AuthenticateUser(session, configname, cuid, extensions, + tokenType, login, userid, status)){ + PR_snprintf(audit_msg, 512, "AuthenticateUser error"); + goto loser; + } + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL ? keyVersion : "", + "token login successful"); + + // get authid for audit log + PR_snprintf((char *)configname, 256, "%s.%s.auth.id", OP_PREFIX, tokenType); + authid = RA::GetConfigStore()->GetConfigAsString(configname); + + StatusUpdate(session, extensions, 4, "PROGRESS_APPLET_UPGRADE"); + + if(do_force_format) { + bool skip_auth = true; + if(Format(session,extensions,skip_auth) != STATUS_NO_ERROR ) { + PR_snprintf(audit_msg,512, "ForceUpgradeApplet error"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + goto loser; + } else { + RA::Debug(LL_PER_CONNECTION, "RA_Enroll_Processor::Process", + "after Successful ForceUpdgradeApplet, succeeded!"); + + PR_snprintf(audit_msg,512, "ForceUpgradeApplet succeeded as per policy."); + status = STATUS_NO_ERROR; + goto loser; + + } + } else { + if (! CheckAndUpgradeApplet( + session, + extensions, + cuid, + tokenType, + final_applet_version, + app_major_version, app_minor_version, + //appletVersion, + NetKeyAID, + msn, + userid, + status, + &keyVersion)) { + PR_snprintf(audit_msg, 512, "CheckAndUpgradeApplet error"); + goto loser; + } + } + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL ? keyVersion : "", + "applet upgraded successfully"); + + isPinPresent = IsPinPresent(session, 0x0); + + StatusUpdate(session, extensions, 12, "PROGRESS_KEY_UPGRADE"); + + if (!CheckAndUpgradeSymKeys( + session, + extensions, + cuid, + tokenType, + msn, + final_applet_version, + userid, + keyVersion, + CardManagerAID, + NetKeyAID, + channel, + status)) + { + PR_snprintf(audit_msg, 512, "CheckAndUpgradeSymKeys error"); + goto loser; + } + + /* we should have a good channel here */ + if (channel == NULL) { + RA::Error(FN, "no good channel"); + status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512, "secure channel setup error"); + goto loser; + } + + if (channel != NULL) { + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + keyVersion = Util::Buffer2String(channel->GetKeyInfoData()); + } + + StatusUpdate(session, extensions, 14, "PROGRESS_TOKEN_AUTHENTICATION"); + + rc = channel->ExternalAuthenticate(); + if (rc == -1) { + RA::Error(FN, "external authenticate failed"); + status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512, "external authentication error"); + goto loser; + } + + RA::Debug(LL_PER_CONNECTION, FN, "after SetupSecureChannel, succeeded"); + + PR_snprintf((char *)configname, 256, "%s.%s.pinReset.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 1)) { + + PR_snprintf((char *)configname, 256, "%s.%s.pinReset.pin.minLen", OP_PREFIX, tokenType); + unsigned int minlen = RA::GetConfigStore()->GetConfigAsUnsignedInt(configname, 4); + PR_snprintf((char *)configname, 256,"%s.%s.pinReset.pin.maxLen", OP_PREFIX, tokenType); + unsigned int maxlen = RA::GetConfigStore()->GetConfigAsUnsignedInt(configname, 10); + + new_pin = RequestNewPin(session, minlen, maxlen); + if (new_pin == NULL) { + RA::Error(FN, "new pin request failed"); + + status = STATUS_ERROR_MAC_RESET_PIN_PDU; + PR_snprintf(audit_msg, 512, "new pin request error"); + goto loser; + } + RA::Debug(LL_PER_CONNECTION, "RA_Enroll_Processor::Process", + "after RequestNewPin, succeeded"); + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL ? keyVersion : "", + "RequestNewPin completed successfully"); + + PR_snprintf((char *)configname, 256, "%s.%s.pinReset.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 1)) { + if (!isPinPresent) { + PR_snprintf((char *)configname, 256, "%s.%s.pinReset.pin.maxRetries", OP_PREFIX, tokenType); + maxRetries = RA::GetConfigStore()->GetConfigAsInt(configname, 0x7f); + RA::Debug(LL_PER_CONNECTION, FN, + "param=%s maxRetries=%d", configname, maxRetries); + rc = channel->CreatePin(0x0, + maxRetries, + RA::GetConfigStore()->GetConfigAsString("create_pin.string", "password")); + if (rc == -1) { + RA::Error("RA_Enroll_Processor::Process", + "create pin failed"); + + status = STATUS_ERROR_MAC_RESET_PIN_PDU; + PR_snprintf(audit_msg, 512, "create pin request error"); + goto loser; + } + + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL ? keyVersion : "", + "CreatePin completed successfully"); + + } + } + + rc = channel->ResetPin(0x0, new_pin); + if (rc == -1) { + RA::Error("RA_Enroll_Processor::Process", + "reset pin failed"); + + status = STATUS_ERROR_MAC_RESET_PIN_PDU; + PR_snprintf(audit_msg, 512, "reset pin request error"); + goto loser; + } + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL ? keyVersion : "", + "ResetPin completed successfully"); + } + + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "after ResetPin, succeeded"); + + // to help testing, we may use fix challenge + PR_snprintf((char *)configname, 256, "%s.%s.generateChallenge", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 1)) { + /* generate challenge for enrollment */ + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Generate Challenge"); +/* + random number generation moved to TKS + rc = Util::GetRandomChallenge(*plaintext_challenge); + if (rc == -1) { + RA::Error("RA_Enroll_Processor::Process", + "random challenge creation failed"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + RA::tdb_activity(session->GetRemoteIP(), cuid, "enrollment", "failure", "general challenge error", "", tokenType); + goto loser; + } +*/ + + } + kdd = channel->GetKeyDiversificationData(); + khex = kdd.toHex(); + RA::Debug("RA_Enroll_Processor::Process", "cuid=%s", khex); + + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + connid = RA::GetConfigStore()->GetConfigAsString(configname); + /* wrap challenge with KEK key */ + rc = EncryptData(kdd, + channel->GetKeyInfoData(), *plaintext_challenge, *wrapped_challenge, connid); + if (rc == -1) { + RA::Error("RA_Enroll_Processor::Process", + "encryt data failed"); + status = STATUS_ERROR_MAC_ENROLL_PDU; + PR_snprintf(audit_msg, 512, "challenge encryption error"); + goto loser; + } + // read objects back + PR_snprintf((char *)configname, 256, "%s.%s.pkcs11obj.enable", + OP_PREFIX, tokenType); + pkcs11obj_enable = RA::GetConfigStore()->GetConfigAsBool(configname, 1); + + if (pkcs11obj_enable) { + pkcs11objx = new PKCS11Obj(); + + // read old objects + seq = 0x00; + lastFormatVersion = 0x0100; + // lastObjectVersion = 0; + if (getRandomNumber(&lastObjectVersion) != SECSuccess) { + RA::Error(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Could not generate a random version number...assigning 0x00"); + lastObjectVersion = 0x00; + } else { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "got random version numer: %ul", lastObjectVersion); + } + + foundLastObjectVersion = 0; + do { + object = ListObjects(session, seq); + if (object == NULL) { + seq = 0; + } else { + seq = 1; // get next entry + Buffer objectID = object->substr(0, 4); + Buffer objectLen = object->substr(4, 4); + unsigned long objectIDVal = + ((((BYTE *)objectID)[0] << 24)) + + ((((BYTE *)objectID)[1] << 16)) + + ((((BYTE *)objectID)[2] << 8)) + + ((((BYTE *)objectID)[3])); + unsigned long objectLenVal = + ((((BYTE *)objectLen)[0] << 24)) + + ((((BYTE *)objectLen)[1] << 16)) + + ((((BYTE *)objectLen)[2] << 8)) + + ((((BYTE *)objectLen)[3])); + + Buffer *o = channel->ReadObject((BYTE*)objectID, 0, + (int)objectLenVal); + if (o == NULL) { + status = STATUS_ERROR_CREATE_TUS_TOKEN_ENTRY; + PR_snprintf(audit_msg, 512, "error in creating token entry"); + goto loser; + } + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "object read from token"); + + if (((unsigned char *)objectID)[0] == 'z' && + ((unsigned char *)objectID)[1] == '0') { + lastFormatVersion = (((BYTE*)*o)[0] << 8) + + (((BYTE*)*o)[1]); + lastObjectVersion = (((BYTE*)*o)[2] << 8) + + (((BYTE*)*o)[3]); + foundLastObjectVersion = 1; + + // + delete pkcs11objx; + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "parsing pkcs11obj read from token"); + pkcs11objx = PKCS11Obj::Parse(o, 0); + seq = 0; + } else { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "new pkcs11obj"); + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData(objectIDVal, o); + if (objSpec != NULL) { + pkcs11objx->AddObjectSpec(objSpec); + } + } + + delete o; + delete object; + } + } while (seq != 0); + + } + + rc = RA::tdb_add_token_entry((char *)userid, cuid, "uninitialized", tokenType); + if (rc == -1) { + status = STATUS_ERROR_CREATE_TUS_TOKEN_ENTRY; + PR_snprintf(audit_msg, 512, "error in creating uninitialized token entry"); + goto loser; + } + + StatusUpdate(session, extensions, 15, "PROGRESS_PROCESS_PROFILE"); + + tokentype = (char *)malloc(256 * sizeof(char)) ; + PL_strcpy(tokentype, tokenType); + /* generate signing key on netkey */ + if (!GenerateCertsAfterRecoveryPolicy(login, session, origins, ktypes, tokentype, pkcs11objx, + pkcs11obj_enable, extensions, channel, wrapped_challenge, + key_check, plaintext_challenge, cuid, msn, final_applet_version, + khex, userid, status, certificates, o_certNums, tokenTypes)) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process"," - GenerateCertsAfterRecoveryPolicy returns false"); + goto loser; + } else { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process"," - GenerateCertsAfterRecoveryPolicy returns true"); + if (status == STATUS_NO_ERROR) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process"," - after GenerateCertsAfterRecoveryPolicy", "status is STATUS_NO_ERROR"); + if (!GenerateCertificates(login, session, origins, ktypes, tokentype, pkcs11objx, + pkcs11obj_enable, extensions, channel, wrapped_challenge, + key_check, plaintext_challenge, cuid, msn, final_applet_version, + khex, userid, status, certificates, o_certNums, tokenTypes)) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process - after GenerateCertificates"," returns false might as well clean up token."); + bool skip_auth = true; + Format(session,extensions,skip_auth); + goto loser; + } else { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process - after GenerateCertificates"," returns true"); + } + } else { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process - after GenerateCertsAfterRecoveryPolicy", "status is %d", status); + } + } + + if ((status == STATUS_ERROR_RENEWAL_IS_PROCESSED) && + RA::ra_allow_token_renew(cuid)) { + renewed = true; + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "renewal happened.. "); + } + + // read objects back + if (pkcs11obj_enable) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "pkcs11obj enabled"); + pkcs11objx->SetFormatVersion(lastFormatVersion); + if (foundLastObjectVersion) { + while (lastObjectVersion == 0xff) { + if (getRandomNumber(&lastObjectVersion) != SECSuccess) { + RA::Error(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Encounter 0xff, could not generate a random version number...assigning 0x00"); + lastObjectVersion = 0x00; + } else { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Encounter 0xff, got random version numer: %ul", lastObjectVersion); + } + } + + pkcs11objx->SetObjectVersion(lastObjectVersion+1); + } else { + pkcs11objx->SetObjectVersion(lastObjectVersion); + } + pkcs11objx->SetCUID(token_cuid); + + /* add additional certificate objects */ + PR_snprintf((char *)configname, 256, "%s.certificates.num", + OP_PREFIX); + int certNum = RA::GetConfigStore()->GetConfigAsInt(configname); + if (certNum > 0) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "about to write certificate chain"); + } + for (int i = 0; i < certNum; i++) { + + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "root certificate #%d", i); + + PR_snprintf((char *)configname, 256, "%s.certificates.value.%d", + OP_PREFIX, i); + char *certName = (char *)RA::GetConfigStore()->GetConfigAsString(configname); + + /* retrieve certificate info */ + PR_snprintf((char *)configname, 256, "%s.certificates.%s.nickName", + OP_PREFIX, certName); + char *certNickName = (char *)RA::GetConfigStore()->GetConfigAsString(configname); + PR_snprintf((char *)configname, 256, "%s.certificates.%s.certId", + OP_PREFIX, certName); + char *certId = (char *) + RA::GetConfigStore()->GetConfigAsString(configname, "C0"); + +/* +op.enroll.certificates.num=1 +op.enroll.certificates.value.0=caCert +op.enroll.certificates.caCert.nickName=caCert0 fpki-tps +op.enroll.certificates.caCert.certId=C5 +op.enroll.certificates.caCert.certAttrId=c5 +op.enroll.certificates.caCert.label=caCert Label + */ + + /* retrieve certificate */ + CERTCertificate *cert = CERT_FindCertByNickname( + CERT_GetDefaultCertDB(), certNickName); + + if (cert == NULL) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Cannot find certificate %s", certNickName); + } else { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Found certificate %s", certNickName); + + /* add certificate to z object */ + Buffer *certBuf = new Buffer((BYTE*)cert->derCert.data, + (unsigned int)cert->derCert.len); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Certificate buffer created"); + ObjectSpec *objSpec = ObjectSpec::ParseFromTokenData( + (certId[0] << 24) + + (certId[1] << 16), certBuf); + pkcs11objx->AddObjectSpec(objSpec); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Certificate object Added to PKCS11 Object"); + + /* add PK11 attributes */ + PR_snprintf((char *)configname, 256, "%s.certificates.%s.label", + OP_PREFIX, certName); + char *certLabel = (char *)RA::GetConfigStore()->GetConfigAsString(configname); + PR_snprintf((char *)configname, 256, "%s.certificates.%s.certAttrId", + OP_PREFIX, certName); + char *certAttrId = (char *) + RA::GetConfigStore()->GetConfigAsString(configname, "c0"); + + Buffer *keyid = NULL; + if (cert->subjectKeyID.data != NULL) { + keyid = new Buffer((BYTE*)cert->subjectKeyID.data, + (unsigned int)cert->subjectKeyID.len); + } else { + SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert) ; + SECItem *tmpitem = PK11_MakeIDFromPubKey(pubKeyData); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Got Key ID"); + + + keyid = new Buffer((BYTE*)tmpitem->data, + (unsigned int)tmpitem->len); + } + + Buffer b = channel->CreatePKCS11CertAttrsBuffer( + KEY_TYPE_ENCRYPTION /* not being used */, + certAttrId, certLabel, keyid); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Created buffer for PKCS11 cert attributes"); + objSpec = ObjectSpec::ParseFromTokenData( + (certAttrId[0] << 24) + + (certAttrId[1] << 16), + &b); + pkcs11objx->AddObjectSpec(objSpec); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Added PKCS11 certificate attribute"); + } + } + + // build label + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.tokenName", + OP_PREFIX, tokentype); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "tokenName '%s'", + configname); + pattern = RA::GetConfigStore()->GetConfigAsString(configname, "$cuid$"); + nv.Add("cuid", cuid); + nv.Add("msn", msn); + nv.Add("userid", userid); + nv.Add("profileId", tokenType); + + /* populate auth parameters output to nv also */ + /* so we can reference to the auth parameter by */ + /* using $auth.cn$, or $auth.mail$ */ + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "Check login"); + if (login != NULL) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "Found login"); + int s = login->Size(); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "login size=%d", s); + for (int x = 0; x < s; x++) { + char namebuf[2048]; + char *name = login->GetNameAt(x); + sprintf(namebuf, "auth.%s", name); + if (strcmp(name,"PASSWORD") != 0) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "Exposed %s=%s", namebuf, login->GetValue(name)); + } + nv.Add(namebuf, login->GetValue(name)); + } + } + label = MapPattern(&nv, (char *) pattern); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "labelName '%s'", + label); + labelBuffer = Buffer((BYTE*)label, strlen(label)); + pkcs11objx->SetTokenName(labelBuffer); + + // write PKCS11 Obj + BYTE objid[4]; + + objid[0] = 'z'; + objid[1] = '0'; + objid[2] = 0; + objid[3] = 0; + Buffer xb; + + PR_snprintf((char *)configname, 256, "%s.%s.pkcs11obj.compress.enable", + OP_PREFIX, tokentype); + compress = RA::GetConfigStore()->GetConfigAsBool(configname, 1); + + if (compress) { + xb = pkcs11objx->GetCompressedData(); + RA::Debug("RA_Enroll_Processor::Process PKCSData", "Compressed Data"); + } else { + xb = pkcs11objx->GetData(); + RA::Debug("RA_Enroll_Processor::Process PKCSData", "Uncompressed Data"); + } + RA::DebugBuffer("RA_Enroll_Processor::Process PKCSData", "PKCS Data=", &xb); + + + if(xb.size() == 0) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + RA::Debug("RA_Enroll_Processor::Failure to get token object!"," failed"); + PR_snprintf(audit_msg, 512, "channel createObject failed"); + goto loser; + } + + if((int) xb.size() > totalAvailableMemory) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + RA::Debug("RA_Enroll_Processor::Failure pkcs11 object may exceed applet memory"," failed"); + PR_snprintf(audit_msg, 512, "Applet memory exceeded when writing out final token data"); + bool skip_auth = true; + if(!renewed) { //Renewal should leave what they have on the token. + Format(session,extensions,skip_auth); + } + goto loser; + } + + BYTE perms[6]; + + perms[0] = 0xff; + perms[1] = 0xff; + perms[2] = 0x40; + perms[3] = 0x00; + perms[4] = 0x40; + perms[5] = 0x00; + + if (channel->CreateObject(objid, perms, xb.size()) != 1) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + RA::Debug("RA_Enroll_Processor::channel createObject"," failed"); + PR_snprintf(audit_msg, 512, "channel createObject failed"); + goto loser; + } + // channel->CreateObject(objid, xb.size()); + if (channel->WriteObject(objid, (BYTE*)xb, xb.size()) != 1) { + status = STATUS_ERROR_MAC_ENROLL_PDU; + RA::Debug("RA_Enroll_Processor::channel writeObject"," failed"); + PR_snprintf(audit_msg, 512, "channel writeObject failed"); + goto loser; + } + } + + StatusUpdate(session, extensions, 90, "PROGRESS_SET_LIFE_CYCLE_STATE"); + + // add issuer info to the token + PR_snprintf((char *)configname, 256, "%s.%s.issuerinfo.enable", + OP_PREFIX, tokenType); + RA::Debug("RA_Enroll_Processor", "Getting %s", configname); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + if (channel != NULL) { + char issuer[224]; + for (int i = 0; i < 224; i++) { + issuer[i] = 0; + } + PR_snprintf((char *)configname, 256, "%s.%s.issuerinfo.value", + OP_PREFIX, tokenType); + char *issuer_val = (char*)RA::GetConfigStore()->GetConfigAsString( + configname); + RA::Debug("RA_Enroll_Processor", + "Before pattern substitution mapping is %s", issuer_val); + issuer_val = MapPattern(&nv, (char *) issuer_val); + RA::Debug("RA_Enroll_Processor", + "After pattern substitution mapping is %s", issuer_val); + sprintf(issuer, "%s", issuer_val); + RA::Debug("RA_Enroll_Processor", "Set Issuer Info %s", issuer_val); + Buffer *info = new Buffer((BYTE*)issuer, 224); + rc = channel->SetIssuerInfo(info); + + if (info != NULL) { + delete info; + info = NULL; + } + } + } + /* write lifecycle bit */ + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "Set Lifecycle State"); + rc = channel->SetLifecycleState(0x0f); + if (rc == -1) { + RA::Error("RA_Enroll_Processor::Process", + "Set life cycle state failed"); + status = STATUS_ERROR_MAC_LIFESTYLE_PDU; + PR_snprintf(audit_msg, 512, "set life cycle state error"); + goto loser; + } + + rc = channel->Close(); + if (rc == -1) { + RA::Error("RA_Enroll_Processor::Process", + "Failed to close channel"); + status = STATUS_ERROR_CONNECTION; + PR_snprintf(audit_msg, 512, "channel not closed"); + goto loser; + } + + StatusUpdate(session, extensions, 100, "PROGRESS_DONE"); + + status = STATUS_NO_ERROR; + + sprintf(activity_msg, "applet_version=%s tokenType=%s userid=%s", + final_applet_version, tokentype, userid); + + if (renewed) { + RA::tdb_activity(session->GetRemoteIP(), cuid, "renewal", "success", activity_msg, userid, tokenType); + } else { + RA::tdb_activity(session->GetRemoteIP(), cuid, "enrollment", "success", activity_msg, userid, tokenType); + } + RA::tdb_update((char *)userid, cuid, (char *)final_applet_version, (char *)keyVersion, "active", "", tokenType); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "after tdb_update()"); + + RA::tdb_update_certificates(cuid, tokenTypes, (char*)userid, certificates, ktypes, origins, o_certNums); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "after tdb_update_certificates()"); + + rc = 1; + + end = PR_IntervalNow(); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "after end"); + + /* audit log for successful enrollment */ + if (renewed) { + if (authid != NULL) { + PR_snprintf(activity_msg, 4096, "renewal processing completed, authid = %s", authid); + } else { + PR_snprintf(activity_msg, 4096, "renewal processing completed"); + } + RA::Audit(EV_RENEWAL, AUDIT_MSG_PROC, + userid, cuid, msn, "success", "renewal", final_applet_version, keyVersion, activity_msg); + } else { + if (authid != NULL) { + PR_snprintf(activity_msg, 4096, "enrollment processing completed, authid = %s", authid); + } else { + PR_snprintf(activity_msg, 4096, "enrollment processing completed"); + } + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid, cuid, msn, "success", "enrollment", final_applet_version, keyVersion, activity_msg); + } + + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "after audit, o_certNums=%d",o_certNums); + +loser: + + if (strlen(audit_msg) > 0) { // a failure occurred + if (renewed) { + RA::Audit(EV_RENEWAL, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "failure", + "renewal", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL ? keyVersion : "", + audit_msg); + + if ((cuid != NULL) && (tokenType != NULL)) { + RA::tdb_activity(session->GetRemoteIP(), + cuid, + "renewal", + "failure", + audit_msg, + userid != NULL? userid : "", + tokenType); + } + } else { + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "failure", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL ? keyVersion : "", + audit_msg); + + if ((cuid != NULL) && (tokenType != NULL)) { + RA::tdb_activity(session->GetRemoteIP(), + cuid, + "enrollment", + "failure", + audit_msg, + userid != NULL? userid : "", + tokenType); + } + } + } + + if (tokenTypes != NULL) { + for (int nn=0; nn<o_certNums; nn++) { + if (tokenTypes[nn] != NULL) + PL_strfree(tokenTypes[nn]); + tokenTypes[nn] = NULL; + } + free(tokenTypes); + tokenTypes = NULL; + } + if (certificates != NULL) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "before CERT_DestroyCertificate. certNums=%d", o_certNums); + for (int i=0;i < o_certNums; i++) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "CERT_DestroyCertificate: i=%d", i); + if (certificates[i] != NULL) { + CERT_DestroyCertificate(certificates[i]); + } + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "CERT_DestroyCertificate: i=%i done", i); + } + free(certificates); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "after CERT_DestroyCertificate"); + } + + if( certEnroll != NULL ) { + delete certEnroll; + certEnroll = NULL; + } + + if (ktypes != NULL) { + for (int nn=0; nn < o_certNums; nn++) { + if (ktypes[nn] != NULL) + PL_strfree(ktypes[nn]); + ktypes[nn] = NULL; + } + free(ktypes); + ktypes = NULL; + } + + if (origins != NULL) { + for (int nn=0; nn < o_certNums; nn++) { + if (origins[nn] != NULL) + PL_strfree(origins[nn]); + origins[nn] = NULL; + } + free(origins); + origins = NULL; + } + + if( CardManagerAID != NULL ) { + delete CardManagerAID; + CardManagerAID = NULL; + } + + if( NetKeyAID != NULL ) { + delete NetKeyAID; + NetKeyAID = NULL; + } + + if( login != NULL ) { + delete login; + login = NULL; + } + + if( channel != NULL ) { + delete channel; + channel = NULL; + } + + if( new_pin != NULL ) { + PL_strfree( new_pin ); + new_pin = NULL; + } + + if( key_check != NULL ) { + delete key_check; + key_check = NULL; + } + + if( wrapped_challenge != NULL ) { + delete wrapped_challenge; + wrapped_challenge = NULL; + } + + if( plaintext_challenge != NULL ) { + delete plaintext_challenge; + plaintext_challenge = NULL; + } + + if( token_status != NULL ) { + delete token_status; + token_status = NULL; + } + + if( final_applet_version != NULL ) { + PR_Free( (char *) final_applet_version ); + final_applet_version = NULL; + } + + if( appletVersion != NULL ) { + PR_Free( (char *) appletVersion ); + appletVersion = NULL; + } + if( khex != NULL ) { + PR_Free( khex ); + khex = NULL; + } + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + if( userid != NULL ) { + PR_Free( (char *) userid ); + userid = NULL; + } + if (token_state != NULL) { + PR_Free((char *)token_state); + token_state = NULL; + } + if( cuid != NULL ) { + PR_Free( cuid ); + cuid = NULL; + } + if( msn != NULL ) { + PR_Free( msn ); + msn = NULL; + } + if( label != NULL ) { + PL_strfree( (char *) label ); + label = NULL; + } + if (tokentype != NULL) { + PR_Free(tokentype); + } + if (pkcs11objx != NULL) { + delete pkcs11objx; + } + +#ifdef MEM_PROFILING + MEM_dump_unfree(); +#endif + + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", "returning status"); + return status; +} + + +bool RA_Enroll_Processor::GenerateCertificates(AuthParams *login, RA_Session *session, char **&origins, char **&ktypes, + char *tokenType, PKCS11Obj *pkcs11objx, int pkcs11obj_enable, + NameValueSet *extensions, Secure_Channel *channel, Buffer *wrapped_challenge, + Buffer *key_check, Buffer *plaintext_challenge, char *cuid, char *msn, + const char *final_applet_version, char *khex, const char *userid, RA_Status &o_status, + CERTCertificate **&certificates, int &o_certNums, char **&tokenTypes) { + + bool noFailedCerts = true; + bool r=true; + int keyTypeNum = 0; + int i = 0; + char configname[256]; + const char *FN = "RA_Enroll_Processor::GenerateCertificates"; + RA_Status lastErrorStatus = STATUS_NO_ERROR; + + + RA::Debug(LL_PER_CONNECTION,FN, "tokenType=%s", tokenType); + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.keyType.num", OP_PREFIX, tokenType); + keyTypeNum = RA::GetConfigStore()->GetConfigAsInt(configname); + if (keyTypeNum == 0) { + r = false; + RA::Error(LL_PER_CONNECTION,FN, + "Profile parameters are not found"); + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + goto loser; + } + + ktypes = (char **) malloc (sizeof(char *) * keyTypeNum); + origins = (char **) malloc (sizeof(char *) * keyTypeNum); + tokenTypes = (char **) malloc (sizeof(char *) * keyTypeNum); + + certificates = (CERTCertificate **) malloc (sizeof(CERTCertificate *) * keyTypeNum); + o_certNums = keyTypeNum; + for (i=0; i<keyTypeNum; i++) { + certificates[i] = NULL; + ktypes[i] = NULL; + origins[i] = NULL; + tokenTypes[i] = NULL; + + } + for (i=0; i<keyTypeNum; i++) { + + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.keyType.value.%d", OP_PREFIX, tokenType, i); + const char *keyTypeValue = RA::GetConfigStore()->GetConfigAsString(configname, "signing"); + + r = GenerateCertificate(login,keyTypeNum, keyTypeValue, i, session, origins, ktypes, tokenType, + pkcs11objx, pkcs11obj_enable, extensions, channel, wrapped_challenge, + key_check, plaintext_challenge, cuid, msn, final_applet_version, + khex, userid, o_status, certificates); + + RA::Debug("GenerateCertificates","configname %s result %d",configname,r); + + tokenTypes[i] = PL_strdup(tokenType); + if(r == false) { + noFailedCerts = false; + lastErrorStatus = o_status; + break; + } + + } + + if (noFailedCerts == true) { + //In this special case of re-enroll + //Revoke current certs for this token + // before the just enrolled certs are written to the db + char error_msg[512]; + bool success = RevokeCertificates(session, cuid,error_msg,(char *)final_applet_version, + NULL,(char *)tokenType,(char *)userid,o_status + ); + + RA::Debug("GenerateCertificates","Revoke result %d ",(int) success); + + if (!success) { + //Don't blow the whole thing up for this. + RA::Debug("GenerateCertificates","Revocation failure %s ",error_msg); + } + + } + loser: + if(lastErrorStatus != STATUS_NO_ERROR) { + o_status = lastErrorStatus; + } + return noFailedCerts; +} + +bool RA_Enroll_Processor::GenerateCertificate(AuthParams *login, int keyTypeNum, const char *keyTypeValue, int i, RA_Session *session, + char **origins, char **ktypes, char *tokenType, PKCS11Obj *pkcs11objx, int pkcs11obj_enable, + NameValueSet *extensions, Secure_Channel *channel, Buffer *wrapped_challenge, + Buffer *key_check, Buffer *plaintext_challenge, char *cuid, char *msn, + const char *final_applet_version, char *khex, const char *userid, + RA_Status &o_status, CERTCertificate **certificates) +{ + bool r = true; + char configname[256]; + char keyTypePrefix[200]; + const char *FN="RA_Enroll_Processor::GenerateCertificate"; + + PR_snprintf((char *)keyTypePrefix, 256, "%s.%s.keyGen.%s", OP_PREFIX, tokenType, keyTypeValue); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::GenerateCertificate","keyTypePrefix is %s",keyTypePrefix); + PR_snprintf((char *)configname, 256, "%s.ca.profileId", keyTypePrefix); + const char *profileId = RA::GetConfigStore()->GetConfigAsString(configname, ""); + PR_snprintf((char *)configname, 256,"%s.certId", keyTypePrefix); + const char *certId = RA::GetConfigStore()->GetConfigAsString(configname, "C0"); + PR_snprintf((char *)configname, 256, "%s.certAttrId", keyTypePrefix); + const char *certAttrId = RA::GetConfigStore()->GetConfigAsString(configname, "c0"); + PR_snprintf((char *)configname, 256, "%s.privateKeyAttrId", keyTypePrefix); + const char *priKeyAttrId = RA::GetConfigStore()->GetConfigAsString(configname, "k0"); + PR_snprintf((char *)configname, 256,"%s.publicKeyAttrId", keyTypePrefix); + const char *pubKeyAttrId = RA::GetConfigStore()->GetConfigAsString(configname, "k1"); + PR_snprintf((char *)configname, 256, "%s.keySize", keyTypePrefix); + int keySize = RA::GetConfigStore()->GetConfigAsInt(configname, 1024); + + PR_snprintf((char *)configname, 256, "%s.publisherId", keyTypePrefix); + const char *publisherId = RA::GetConfigStore()->GetConfigAsString(configname, NULL); + + PR_snprintf((char *)configname, 256, "%s.keyUsage", keyTypePrefix); + int keyUsage = RA::GetConfigStore()->GetConfigAsInt(configname, 0); + PR_snprintf((char *)configname, 256, "%s.keyUser", keyTypePrefix); + int keyUser = RA::GetConfigStore()->GetConfigAsInt(configname, 0); + PR_snprintf((char *)configname, 256, "%s.privateKeyNumber", keyTypePrefix); + int priKeyNumber = RA::GetConfigStore()->GetConfigAsInt(configname, 0); + PR_snprintf((char *)configname, 256, "%s.publicKeyNumber", keyTypePrefix); + int pubKeyNumber = RA::GetConfigStore()->GetConfigAsInt(configname, 1); + + + // get key capabilites to determine if the key type is SIGNING, + // ENCRYPTION, or SIGNING_AND_ENCRYPTION + PR_snprintf((char *)configname, 256, "%s.private.keyCapabilities.sign", keyTypePrefix); + bool isSigning = RA::GetConfigStore()->GetConfigAsBool(configname); + PR_snprintf((char *)configname, 256, "%s.public.keyCapabilities.encrypt", keyTypePrefix); + bool isEncrypt = RA::GetConfigStore()->GetConfigAsBool(configname); + int keyTypeEnum = 0; + + if ((isSigning) && + (isEncrypt)) { + keyTypeEnum = KEY_TYPE_SIGNING_AND_ENCRYPTION; + } else if (isSigning) { + keyTypeEnum = KEY_TYPE_SIGNING; + } else if (isEncrypt) { + keyTypeEnum = KEY_TYPE_ENCRYPTION; + } + RA::Debug(LL_PER_CONNECTION,FN, + "key type is %d",keyTypeEnum); + + PR_snprintf((char *)configname, 256, "%s.ca.conn", keyTypePrefix); + const char *caconnid = RA::GetConfigStore()->GetConfigAsString(configname); + certificates[i] = NULL; + ktypes[i] = NULL; + origins[i] = NULL; + + o_status = DoEnrollment(login, session, certificates, origins, ktypes, pkcs11obj_enable, + pkcs11objx, extensions, i, keyTypeNum, + 15 /* start progress */, + 90 /* end progress */, channel, wrapped_challenge, + tokenType, + keyTypeValue, + key_check, + plaintext_challenge, + cuid, + msn, + khex, (TokenKeyType)keyTypeEnum, profileId, userid, certId,publisherId, certAttrId, priKeyAttrId, + pubKeyAttrId, (keyUser << 4)+priKeyNumber, + (keyUsage << 4)+pubKeyNumber, keySize, caconnid, keyTypePrefix,(char *)final_applet_version); + + if (o_status != STATUS_NO_ERROR) { + r = false; + + RA::Debug(LL_PER_CONNECTION,FN, + "Got a status error from DoEnrollment: %d", o_status); + RA::tdb_activity(session->GetRemoteIP(), cuid, "enrollment", "failure", "enrollment error", "", tokenType); + goto loser; + } + + loser: + + return r; +} + +bool RA_Enroll_Processor::GenerateCertsAfterRecoveryPolicy(AuthParams *login, RA_Session *session, char **&origins, char **&ktypes, + char *&tokenType, PKCS11Obj *pkcs11objx, int pkcs11obj_enable, + NameValueSet *extensions, Secure_Channel *channel, Buffer *wrapped_challenge, + Buffer *key_check, Buffer *plaintext_challenge, char *cuid, char *msn, + const char *final_applet_version, char *khex, const char *userid, RA_Status &o_status, + CERTCertificate **&certificates, int &o_certNums, char **&tokenTypes) +{ + LDAPMessage *ldapResult = NULL; + LDAPMessage *e = NULL; + int nEntries = 0; + char filter[512]; + char configname[512]; + char tokenStatus[100]; + char *tokenid = NULL; + int rc = -1; + bool r=true; + o_status = STATUS_NO_ERROR; + char *origTokenType = NULL; + + const char *FN="RA_Enroll_Process::GenerateCertsAfterRecoveryPolicy"; + PR_snprintf(filter, 512, "tokenUserID=%s", userid); + + rc = RA::ra_find_tus_token_entries_no_vlv(filter, &ldapResult, 1); + + if (rc != LDAP_SUCCESS) { + RA::Debug(LL_PER_CONNECTION,FN, + "Cant find any tokens associated with the userid=%s. " + "There should be at least one token.", userid); + r = false; + o_status = STATUS_ERROR_INACTIVE_TOKEN_NOT_FOUND; + goto loser; + } else { + nEntries = RA::ra_get_number_of_entries(ldapResult); + for (e = RA::ra_get_first_entry(ldapResult); e != NULL; e = RA::ra_get_next_entry(e)) { + struct berval ** attr_values = RA::ra_get_attribute_values(e, "tokenStatus"); + + if ((attr_values == NULL) || (attr_values[0] == NULL)) { + RA::Debug(LL_PER_CONNECTION,FN, "Error obtaining token status"); + r = false; + o_status = STATUS_ERROR_BAD_STATUS; + if (attr_values != NULL) { + RA::ra_free_values(attr_values); + attr_values = NULL; + } + goto loser; + } + + RA::Debug(LL_PER_CONNECTION,FN, "tokenStatus = %s", + attr_values[0]->bv_val); + + strncpy(tokenStatus, attr_values[0]->bv_val, 100); + // free attr_values + if (attr_values != NULL) { + RA::ra_free_values(attr_values); + attr_values = NULL; + } + tokenid = RA::ra_get_token_id(e); + RA::Debug(LL_PER_CONNECTION,FN, "tokenID = %s", tokenid); + int cmp_result = PL_strcasecmp(tokenid, cuid); + free(tokenid); + if (cmp_result == 0) { + if (PL_strcasecmp(tokenStatus, "uninitialized") == 0 ) { + if (nEntries == 1) { + // need to do enrollment outside + break; + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "There are multiple token entries for user %s.", userid); + + if (RA::ra_tus_has_active_tokens((char *)userid) == 0) { + r = false; + o_status = STATUS_ERROR_HAS_AT_LEAST_ONE_ACTIVE_TOKEN; + RA::Debug(LL_PER_CONNECTION,FN, "User already has one active token."); + goto loser; + } else { + // 1) current token is in active state + // 2) there are no other active tokens for this user + // 3) that means the previous one is the lost one + // get the most recent previous token: + LDAPMessage *prev = RA::ra_get_next_entry(e); + char *reason = RA::ra_get_token_reason(prev); + char *lostTokenCUID = RA::ra_get_token_id(prev); + + // if the previous one is lost, then check lost reason + origTokenType = PL_strdup(tokenType); + if (PL_strcasecmp(reason, "keyCompromise") == 0) { + r = ProcessRecovery(login, reason, session, origins, ktypes, + tokenType, pkcs11objx, pkcs11obj_enable, + extensions, channel, wrapped_challenge, + key_check, plaintext_challenge, cuid, msn, + final_applet_version, khex, userid, + o_status, certificates, lostTokenCUID, o_certNums, tokenTypes, origTokenType); + + break; + } else if (PL_strcasecmp(reason, "onHold") == 0) { + // then the inactive one becomes the temp token + // No recovery scheme, basically we are going to + // do the brand new enrollment + PR_snprintf(configname, 512, "op.enroll.%s.temporaryToken.tokenType", tokenType); + char *tempTokenType = (char *)(RA::GetConfigStore()->GetConfigAsString(configname, "userKeyTemporary")); + RA::Debug(LL_PER_CONNECTION,FN, + "Token type for temporary token: %s", tempTokenType); + PL_strcpy(tokenType, tempTokenType); + r = ProcessRecovery(login, reason, session, origins, ktypes, + tokenType, pkcs11objx, pkcs11obj_enable, + extensions, channel, wrapped_challenge, + key_check, plaintext_challenge, cuid, msn, + final_applet_version, khex, userid, + o_status, certificates, lostTokenCUID, o_certNums, tokenTypes, origTokenType); + + break; + } else if (PL_strcasecmp(reason, "destroyed") == 0) { + r = ProcessRecovery(login, reason, session, origins, ktypes, + tokenType, pkcs11objx, pkcs11obj_enable, + extensions, channel, wrapped_challenge, + key_check, plaintext_challenge, cuid, msn, + final_applet_version, khex, userid, + o_status, certificates, lostTokenCUID, o_certNums, tokenTypes, origTokenType); + + break; + } else { + r = false; + o_status = STATUS_ERROR_NO_SUCH_LOST_REASON; + RA::Debug(LL_PER_CONNECTION,FN, + "No such lost reason=%s for this cuid=%s", + reason, cuid); + goto loser; + } + } + } + } else if (strcmp(tokenStatus, "active") == 0) { + r = true; + RA::Debug(LL_PER_CONNECTION,FN, + "This is the active token. You can re-enroll if the re-enroll=true; or renew if renew=true."); + if (RA::ra_allow_token_renew(cuid)) { + // renewal allowed instead of re-enroll + r = ProcessRenewal(login, session, ktypes, origins, + tokenType, pkcs11objx, pkcs11obj_enable, + channel, + cuid, msn, + final_applet_version, userid, + o_status, certificates, o_certNums, + tokenTypes); + if (r == true) { + RA::Debug(LL_PER_CONNECTION,FN, "ProcessRenewal returns true"); + } else + goto loser; + } + break; + } else if (strcmp(tokenStatus, "terminated") == 0) { + RA::Debug(LL_PER_CONNECTION,FN, + "terminated token cuid=%s", cuid); + r = false; + o_status = STATUS_ERROR_CONTACT_ADMIN; + goto loser; + } else if (strcmp(tokenStatus, "lost") == 0) { + char *reason = RA::ra_get_token_reason(e); + if (strcmp(reason, "keyCompromise") == 0) { + r = false; + o_status = STATUS_ERROR_UNUSABLE_TOKEN_KEYCOMPROMISE; + RA::Debug(LL_PER_CONNECTION,FN, + "This token cannot be reused because it has been reported lost"); + goto loser; + } else if (strcmp(reason, "onHold") == 0) { + if (RA::ra_tus_has_active_tokens((char *)userid) == 0) { + r = false; + o_status = STATUS_ERROR_HAS_AT_LEAST_ONE_ACTIVE_TOKEN; + RA::Debug(LL_PER_CONNECTION,FN, + "User already has an active token."); + goto loser; + } else { // change it back to active token + r = false; + o_status = STATUS_ERROR_CONTACT_ADMIN; + RA::Debug(LL_PER_CONNECTION,FN, + "User needs to contact administrator to report lost token (it should be put on Hold)."); + break; + } + } else if (strcmp(reason, "destroyed") == 0) { + r = false; + RA::Debug(LL_PER_CONNECTION,FN, + "This destroyed lost case should not be executed because the token is so damaged. It should not get here"); + o_status = STATUS_ERROR_TOKEN_DISABLED; + goto loser; + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "No such lost reason=%s for this cuid=%s", reason, cuid); + r = false; + o_status = STATUS_ERROR_NO_SUCH_LOST_REASON; + goto loser; + } + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "No such token status for this cuid=%s", cuid); + r = false; + o_status = STATUS_ERROR_NO_SUCH_TOKEN_STATE; + goto loser; + } + } else { // cuid != cuid of the current token + continue; +/* + if (RA::ra_tus_has_active_tokens((char *)userid) == 0) { + r = false; + o_status = STATUS_ERROR_HAS_AT_LEAST_ONE_ACTIVE_TOKEN; + RA::Debug("RA_Enroll_Processor::GenerateCertsAfterRecoveryPolicy", "You already have one active token."); + goto loser; + } else + continue; +*/ + } + } + } + + loser: + if (origTokenType != NULL) { + PL_strfree(origTokenType); + origTokenType = NULL; + } + if (rc == 0) + if (ldapResult != NULL) + ldap_msgfree(ldapResult); + + +RA::Debug("RA_Enroll_Processor::GenerateCertsAfterRecoveryPolicy", "returning boolean = %d", r); + return r; +} + +/* + * cfu - check if a cert is within the renewal grace period + * utilize passed in grace period values. + */ +bool RA_Enroll_Processor::isCertRenewable(CERTCertificate *cert, int graceBefore, int graceAfter){ + PRTime timeBefore, timeAfter, now; + + //Grace period input in days + RA::Debug("RA_Enroll_Processor::isCertRenewable","graceBefore %d graceAfter %d",graceBefore,graceAfter); + PRTime graceBefore64, graceAfter64,microSecondsPerSecond; + PRInt64 graceBeforeSeconds,graceAfterSeconds; + + LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC); + + //Get number of microseconds in each grace period value. + LL_I2L(graceBeforeSeconds, graceBefore * 60 * 60 * 24); + LL_I2L(graceAfterSeconds,graceAfter * 60 * 60 * 24); + + LL_MUL(graceBefore64, microSecondsPerSecond,graceBeforeSeconds); + LL_MUL(graceAfter64, microSecondsPerSecond,graceAfterSeconds); + + PRTime lowerBound, upperBound; + + DER_DecodeTimeChoice(&timeBefore, &cert->validity.notBefore); + DER_DecodeTimeChoice(&timeAfter, &cert->validity.notAfter); + + PrintPRTime(timeBefore,"timeBefore"); + PrintPRTime(timeAfter,"timeAfter"); + + now = PR_Now(); + + //Calculate lower and upper legal bounds for time + LL_SUB(lowerBound,timeAfter, graceBefore64); + LL_ADD(upperBound,timeAfter,graceAfter64); + + PrintPRTime(lowerBound,"lowerBound"); + PrintPRTime(now,"now"); + PrintPRTime(upperBound,"upperBound"); + + if(LL_CMP(now,>=, lowerBound) && LL_CMP(now,<=,upperBound)) { + RA::Debug("RA_Enroll_Processor::isCertRenewable","returning true!"); + return true; + } + + RA::Debug("RA_Enroll_Processor::isCertRenewable","returning false!"); + + return false; +} + +/* + * cfu + * DoRenewal - use i_cert's serial number for renewal + * i_cert - cert to renew + * o_cert - cert newly issued + */ +bool RA_Enroll_Processor::DoRenewal(const char *connid, const char *profileId, CERTCertificate *i_cert, +CERTCertificate **o_cert, char *error_msg, int *error_code) +{ + RA_Status status = STATUS_NO_ERROR; + bool r = true; + CertEnroll *certRenewal = NULL; + Buffer *cert = NULL; + char *cert_string = NULL; + + error_msg[0] =0; + *error_code=0; //assume undefined + + PRUint64 snum = DER_GetInteger(&(i_cert)->serialNumber); + RA::Debug("RA_Enroll_Processor::DoRenewal", "begins renewal for serial number %u with profileId=%s", (int)snum, profileId); + + certRenewal = new CertEnroll(); + cert = certRenewal->RenewCertificate(snum, connid, profileId, error_msg); + + if (error_msg[0] != 0) { // We can assume a non grace period error here. + *error_code = 1; + } +// this is where renewal happens .. audit log for fail/ success here? + if (cert == NULL) { + r = false; + RA::Debug("RA_Enroll_Processor::DoRenewal", "Renewal failed for serial number %d", snum); + status = STATUS_ERROR_MAC_ENROLL_PDU; + goto loser; + } + RA::Debug("RA_Enroll_Processor::DoRenewal", "Renewal suceeded for serial number %d", snum); + + cert_string = (char *) cert->string(); + *o_cert = CERT_DecodeCertFromPackage((char *) cert_string, + (int) cert->size()); + if (o_cert != NULL) { + char msg[2048]; + RA::ra_tus_print_integer(msg, &(o_cert[0])->serialNumber); + RA::Debug("DoRenewal", "Received newly issued Certificate"); + RA::Debug("DoRenewal serial=", msg); + RA::Debug("DoRenewal", "yes"); + } else { + r = false; + } + free(cert_string); + +loser: + if( certRenewal != NULL ) { + delete certRenewal; + certRenewal = NULL; + } + if( cert != NULL ) { + delete cert; + cert = NULL; + } + return r; +} + +#define RENEWAL_FAILURE 1 +#define RENEWAL_FAILURE_GRACE 2 + +/* +* Renewal logic +* 1. Create Optional local TPS grace period per token profile, +* per token type, such as signing or encryption. +* This grace period must match how the CA is configured. Ex: +* op.enroll.userKey.renewal.encryption.enable=true +* op.enroll.userKey.renewal.encryption.gracePeriod.enable=true +* op.enroll.userKey.renewal.encryption.gracePeriod.before=30 +* op.enroll.userKey.renewal.encryption.gracePeriod.after=30 +* 2. In case of a grace period failure the code will go on +* and attempt to renew the next certificate in the list. +* 3. In case of any other code failure, the code will abort +* and leave the token untouched, while informing the user +* with an error message. +* +* +*/ +bool RA_Enroll_Processor::ProcessRenewal(AuthParams *login, RA_Session *session, char **&ktypes, + char **&origins, + char *tokenType, PKCS11Obj *pkcs11objx, int pkcs11obj_enable, + Secure_Channel *channel, + const char *cuid, char *msn, + const char *final_applet_version, const char *userid, + RA_Status &o_status, CERTCertificate **&certificates, + int &o_certNums, char **&tokenTypes) +{ + bool r = true; + o_status = STATUS_ERROR_RENEWAL_IS_PROCESSED; + char keyTypePrefix[256]; + char configname[256]; + char filter[256]; + LDAPMessage *result = NULL; + const char *pretty_cuid = NULL; + char audit_msg[512] = ""; + char *keyVersion = NULL; + int renewal_failure_found = 0; + + int maxCertUpdate = 25; + char *renewedCertUpdateList[25]; + int renewedCertUpdateCount = 0; + int renew_error = 0; + + int i = 0; + const char *FN="RA_Enroll_Processor::ProcessRenewal"; + + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "starts"); + + // get key version for audit logs + if (channel != NULL) { + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + keyVersion = Util::Buffer2String(channel->GetKeyInfoData()); + } + + // e.g. op.enroll.userKey.renewal.keyType.num + // renewal params will just have to match that of the previous + // enrollment tps profile. Will try to be smarter later... + PR_snprintf(configname, 256, "op.enroll.%s.renewal.keyType.num", + tokenType); + int keyTypeNum = RA::GetConfigStore()->GetConfigAsInt(configname, -1); + if (keyTypeNum == -1) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + PR_snprintf(audit_msg, 512, "Missing the configuration parameter for %s", configname); + goto loser; + } + + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "keyType.num=%d", keyTypeNum); + + o_certNums = keyTypeNum; + certificates = (CERTCertificate **) malloc (sizeof(CERTCertificate *) * keyTypeNum); + ktypes = (char **) malloc (sizeof(char *) * keyTypeNum); + origins = (char **) malloc (sizeof(char *) * keyTypeNum); + tokenTypes = (char **) malloc (sizeof(char *) * keyTypeNum); + + for (i=0; i<keyTypeNum; i++) { + certificates[i] = NULL; + ktypes[i] = NULL; + origins[i] = NULL; + tokenTypes[i] = NULL; + } + + for (i=0; i<keyTypeNum; i++) { + bool renewable = true; + // e.g. op.enroll.userKey.renewal.keyType.value.0=signing + // e.g. op.enroll.userKey.renewal.keyType.value.1=encryption + PR_snprintf(configname, 256, "op.enroll.%s.renewal.keyType.value.%d", tokenType, i); + const char *keyTypeValue = (char *)(RA::GetConfigStore()->GetConfigAsString(configname)); + + if (keyTypeValue == NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + PR_snprintf(audit_msg, 512, "Missing the configuration parameter for %s", configname); + goto loser; + } + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "keyType == %s ", keyTypeValue); + TokenKeyType key_type = KEY_TYPE_ENCRYPTION; + if (strcmp(keyTypeValue, "signing") == 0) + key_type = KEY_TYPE_SIGNING; + else if (strcmp(keyTypeValue, "encryption") == 0) + key_type = KEY_TYPE_ENCRYPTION; + else + key_type = KEY_TYPE_SIGNING_AND_ENCRYPTION; + + // e.g. op.enroll.userKey.renewal.signing.enable=true + PR_snprintf(configname, 256, "op.enroll.%s.renewal.%s.enable", tokenType, keyTypeValue); + renewable = RA::GetConfigStore()->GetConfigAsBool(configname); + + if (!renewable) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "renewal not enabled"); + continue; + } + + // set allowable $$ config patterns + NameValueSet nv; + pretty_cuid = GetPrettyPrintCUID(cuid); + + nv.Add("pretty_cuid", pretty_cuid); + nv.Add("cuid", cuid); + nv.Add("msn", msn); + nv.Add("userid", userid); + //nv.Add("profileId", profileId); + + /* populate auth parameters output to nv also */ + /* so we can reference to the auth parameter by */ + /* using $auth.cn$, or $auth.mail$ */ + if (login != NULL) { + int s = login->Size(); + for (int x = 0; x < s; x++) { + char namebuf[2048]; + char *name = login->GetNameAt(x); + sprintf(namebuf, "auth.%s", name); + nv.Add(namebuf, login->GetValue(name)); + } + } + + /* + * Get certs from the tokendb for this token to find out about + * renewal possibility + */ + + + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "Renew the certs for %s", keyTypeValue); + PR_snprintf(filter, 256, "(&(tokenKeyType=%s)(tokenID=%s))", + keyTypeValue, cuid); + int rc = RA::ra_find_tus_certificate_entries_by_order_no_vlv(filter, + &result, 1); + + tokenTypes[i] = PL_strdup(tokenType); + if (rc == LDAP_SUCCESS) { + bool renewed = false; + const char *caconnid; + const char *profileId; + PR_snprintf(keyTypePrefix, 256, "op.enroll.%s.keyGen.%s", tokenType,keyTypeValue); + PR_snprintf(configname, 256, "op.enroll.%s.renewal.%s.enable", tokenType, keyTypeValue); + PR_snprintf((char *)configname, 256,"op.enroll.%s.renewal.%s.certId", tokenType, keyTypeValue); + char *certId = (char *)RA::GetConfigStore()->GetConfigAsString(configname, "C0"); + PR_snprintf((char *)configname, 256, "op.enroll.%s.renewal.%s.certAttrId", tokenType, keyTypeValue); + char *certAttrId = (char *)RA::GetConfigStore()->GetConfigAsString(configname, "c0"); + //PR_snprintf((char *)configname, 256, "%s.privateKeyAttrId", keyTypePrefix); + //const char *priKeyAttrId = RA::GetConfigStore()->GetConfigAsString(configname, "k0"); + //PR_snprintf((char *)configname, 256,"%s.publicKeyAttrId", keyTypePrefix); + //const char *pubKeyAttrId = RA::GetConfigStore()->GetConfigAsString(configname, "k1"); + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "certId=%s, certAttrId=%s",certId, certAttrId); + + char finalCertId[3]; + char finalCertAttrId[3]; + + finalCertId[0] = certId[0]; + finalCertId[1] = certId[1]; + finalCertId[2] = 0; + + finalCertAttrId[0] = certAttrId[0]; + finalCertAttrId[1] = certAttrId[1]; + finalCertAttrId[2] = 0; + + LDAPMessage *e= NULL; + char *attr_status = NULL; + for( e = RA::ra_get_first_entry( result ); + e != NULL; + e = RA::ra_get_next_entry( e ) ) { + attr_status = RA::ra_get_cert_status( e ); + if( (strcmp( attr_status, "revoked" ) == 0) || + (strcmp( attr_status, "renewed" ) == 0) ) { + if (attr_status != NULL) { + PL_strfree(attr_status); + attr_status = NULL; + } + continue; + } + + const char *label= NULL; + const char *pattern= NULL; + Buffer *certbuf = NULL; + + // retrieve the most recent certificate to start + + CERTCertificate **certs = RA::ra_get_certificates(e); + CERTCertificate *o_cert = NULL; + SECKEYPublicKey *pk_p = NULL; + SECItem si_mod; + Buffer *modulus=NULL; + SECItem *si_kid = NULL; + Buffer *keyid=NULL; + SECItem si_exp; + Buffer *exponent=NULL; + CERTSubjectPublicKeyInfo* spkix = NULL; + + bool graceEnabled = false; + int graceBefore = 0; + int graceAfter = 0; + + if (certs[0] != NULL) { + + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "Certificate to check for renew"); + + // check if renewable (note: CA makes the final decision) + /* testing...pass through for now + if (!isCertRenewable(certs[0])) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "Cert outside of renewal period"); + r = false; + goto rloser; + } + */ + + // op.enroll.userKey.renewal.signing.ca.conn + // op.enroll.userKey.renewal.encryption.ca.conn + PR_snprintf(configname, 256, + "op.enroll.%s.renewal.%s.ca.conn", tokenType, keyTypeValue); + caconnid = RA::GetConfigStore()->GetConfigAsString(configname); + if (caconnid == NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + PR_snprintf(audit_msg, 512, "Missing the configuration parameter for %s", configname); + goto rloser; + } + + // op.enroll.userKey.renewal.signing.ca.profileId + // op.enroll.userKey.renewal.encryption.ca.profileId + PR_snprintf(configname, 256, + "op.enroll.%s.renewal.%s.ca.profileId", tokenType, keyTypeValue); + profileId = RA::GetConfigStore()->GetConfigAsString(configname); + if (profileId == NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + PR_snprintf(audit_msg, 512, "Missing the configuration parameter for %s", configname); + goto rloser; + } + + RA::Debug("RA_Enroll_Processor::ProcessRenewal","got profileId=%s",profileId); + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "begin renewal"); + + + PR_snprintf(configname,256, + "op.enroll.%s.renewal.%s.gracePeriod.enable",tokenType,keyTypeValue); + + graceEnabled = RA::GetConfigStore()->GetConfigAsBool(configname,0); + + if(graceEnabled) { + + PR_snprintf(configname,256, + "op.enroll.%s.renewal.%s.gracePeriod.before",tokenType,keyTypeValue); + + graceBefore = RA::GetConfigStore()->GetConfigAsInt(configname,0); + + PR_snprintf(configname,256, + "op.enroll.%s.renewal.%s.gracePeriod.after",tokenType,keyTypeValue); + + graceAfter = RA::GetConfigStore()->GetConfigAsInt(configname,0); + // check if renewable (note: CA makes the final decision) + if (!isCertRenewable(certs[0],graceBefore,graceAfter)) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "Cert outside of renewal period"); + renewal_failure_found = RENEWAL_FAILURE_GRACE; + //Since this is merely a grace period failure for one cert + //let's keep going. + r = true; + goto rloser; + } + + } + + // send renewal request to CA + // o_cert is the cert gotten back + r = DoRenewal(caconnid, profileId, certs[0], &o_cert, audit_msg, &renew_error); + if (r == false) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "after DoRenewal failure. o_cert %p renew_error %d",o_cert,renew_error); + o_status = STATUS_ERROR_MAC_ENROLL_PDU; + //Assume a renewal grace failure here since we can't obtain the reason. + //This is the most likely error and there is a chance the next renewal may succeed. + if ( renew_error == 0) { //Assume undefined error is error coming from CA + renewal_failure_found = RENEWAL_FAILURE_GRACE; + } else { + renewal_failure_found = RENEWAL_FAILURE; + } + char snum[2048]; + RA::ra_tus_print_integer(snum, &(certs[0])->serialNumber); + RA::Audit(EV_RENEWAL, AUDIT_MSG_PROC_CERT_REQ, + userid, cuid, msn, "failure", "renewal", final_applet_version, + keyVersion != NULL ? keyVersion : "", + snum, caconnid, audit_msg); + //Since this is merely a grace period or renewal failure for one cert + //let's keep it going + + if (renew_error == 0) { //undefined error means probably grace period, forgive that. + r = true; + } + goto rloser; + } + + // got cert... + + // build label + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.%s.label", + OP_PREFIX, tokenType, keyTypeValue); + RA::Debug(LL_PER_CONNECTION,FN, + "label '%s'", configname); + pattern = RA::GetConfigStore()->GetConfigAsString(configname); + + if(pattern == NULL) + { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "no configured cert label!"); + renewal_failure_found = RENEWAL_FAILURE; + PR_snprintf(audit_msg,512, "No cert label configured for cert!"); + goto rloser; + } + + RA::Debug(LL_PER_CONNECTION,FN, + "pattern '%s'",pattern); + + label = MapPattern(&nv, (char *) pattern); + + RA::Debug(LL_PER_CONNECTION,FN, + "label '%s'",label); + + if (o_cert != NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "got cert!!"); +// tmp_c = NSSBase64_EncodeItem(0, 0, 0, &(o_cert)->derCert); +// RA::Debug("RA_Enroll_Processor::ProcessRenewal", "after NSSBase64_EncodeItem"); + + char snum[2048]; + RA::ra_tus_print_integer(snum, &o_cert->serialNumber); + RA::Audit(EV_RENEWAL, AUDIT_MSG_PROC_CERT_REQ, + userid, cuid, msn, "success", "renewal", final_applet_version, + keyVersion != NULL ? keyVersion : "", + snum, caconnid, "certificate renewed"); + } else { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "no cert!!"); + PR_snprintf(audit_msg, 512, "No cert returned from DoRenewal"); + goto rloser; + } + + ktypes[i] = PL_strdup(keyTypeValue); + origins[i] = PL_strdup(cuid); + certificates[i] = o_cert; + //o_certNums++; + + // For the encrytion cert we actually need to calculate the proper certId and certAttrId + // since we now leave previous encryption certs on the token to allow dencryption of old + // Emails by the user. + + if( key_type == KEY_TYPE_ENCRYPTION) { + + int new_cert_id = GetNextFreeCertIdNumber(pkcs11objx); + + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "Encryption cert, calculated new cert id: %d",new_cert_id); + + //Is the calculated cert id reasonable based on the current state of the + // token and the expected renewal configuration. + if( !(new_cert_id > keyTypeNum ) || new_cert_id > 9) { + RA::Debug(LL_PER_CONNECTION,FN, + "RA_Enroll_Processor::ProcessRenewal","Possible misconfiguration or out of sync token!"); + PR_snprintf(audit_msg, 512, "Renewal of cert failed, misconfiguration or out of sync token!"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; + + } + + finalCertId[0]= 'C'; + finalCertId[1] = '0' + new_cert_id; + + finalCertAttrId[0] = 'c'; + finalCertAttrId[1] = '0' + new_cert_id; + + RA::Debug(LL_PER_CONNECTION,FN, + "finalCertId %s finalCertAttrId %s", finalCertId, finalCertAttrId); + } + + // write certificate to token + certbuf = new Buffer(o_cert->derCert.data, o_cert->derCert.len); + if (pkcs11obj_enable) + { + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (finalCertId[0] << 24) + + (finalCertId[1] << 16), + certbuf); + pkcs11objx->AddObjectSpec(objSpec); + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "Not implemented"); + renewal_failure_found = RENEWAL_FAILURE; + PR_snprintf(audit_msg, 512, "Write cert to token failed: pkcs11obj_enable = false not implemented"); + goto rloser; +/* + RA::Debug(LL_PER_CONNECTION,FN, + "About to create certificate object on token"); + rc = channel->CreateCertificate(certId, certbuf); + if (rc == -1) { + RA::Error(LL_PER_CONNECTION,FN, + "Failed to create certificate object on token"); + + o_status = STATUS_ERROR_MAC_ENROLL_PDU; + goto rloser; + } +*/ + } + + if (o_cert->subjectKeyID.data != NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "subjectKeyID found in cert"); +//later, add code to check if keys really exist on token! + keyid = new Buffer((BYTE*)o_cert->subjectKeyID.data, + (unsigned int)o_cert->subjectKeyID.len); + + } else {// should always have keyid +//use existing original keyid + RA::Debug("RA_Enroll_Processor::ProcessRenewal", "no subjectKeyID found in cert, use existing"); + keyid = new Buffer((BYTE*)certs[0]->subjectKeyID.data, + (unsigned int)certs[0]->subjectKeyID.len); + } + + if (pkcs11obj_enable) + { + Buffer b = channel->CreatePKCS11CertAttrsBuffer( + key_type , finalCertAttrId, label, keyid); + if (b == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: CreatePKCS11CertAttrsBuffer returns null"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; + } + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (finalCertAttrId[0] << 24) + + (finalCertAttrId[1] << 16), + &b); + if (objSpec == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: ParseFromTokenData returns null"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; + } + + //We need to massage the fixedAttributes of this object to allow the CKA_ID value + //of the original encryption cert to be available for coolkey to read. + // Coolkey only deals in a one byte index 0 - n, ex: "01". + // Coolkey uses the final byte of the "fixedAttributes" property of each object + // to identify the object. This value needs to be the same for each cert and its + // corresponding key pair. See ObjectSpec::ParseAttributes. + + if (key_type == KEY_TYPE_ENCRYPTION) { + + unsigned long currentFixedAttributes = objSpec->GetFixedAttributes(); + unsigned long modifiedFixedAttributes = currentFixedAttributes; + + // Here we want the original encryption cert's id number. + int val = (certId[1] - '0'); + + modifiedFixedAttributes &= (BYTE) 0xFFFFFFF0; + modifiedFixedAttributes |= (BYTE) val; + objSpec->SetFixedAttributes(modifiedFixedAttributes); + + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "original fixed Attributes %lu modified ones %lu", + currentFixedAttributes,modifiedFixedAttributes); + } + + pkcs11objx->AddObjectSpec(objSpec); + } else { + RA::Debug(LL_PER_CONNECTION,FN, + "Not implemented"); + PR_snprintf(audit_msg, 512, "Write cert to token failed: pkcs11obj_enable = false not implemented"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; +/* + RA::Debug(LL_PER_CONNECTION,FN, + "About to create PKCS#11 certificate Attributes"); + rc = channel->CreatePKCS11CertAttrs(keyTypeValue, certAttrId, label, keyid); + if (rc == -1) { + RA::Error(LL_PER_CONNECTION,FN, + "PKCS11 Certificate attributes creation failed"); + o_status = STATUS_ERROR_MAC_ENROLL_PDU; + goto rloser; + } +*/ + } + + spkix = &(o_cert->subjectPublicKeyInfo); + if (spkix == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: subjectPublicKeyInfo is null"); + goto rloser; + } + pk_p = SECKEY_ExtractPublicKey(spkix); + if (pk_p == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: ExtractPublicKey is null"); + goto rloser; + } + SECKEY_DestroySubjectPublicKeyInfo(spkix); + + /* fill in keyid, modulus, and exponent */ + + si_mod = pk_p->u.rsa.modulus; + modulus = new Buffer((BYTE*) si_mod.data, si_mod.len); + if (modulus == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: modulus is null"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; + } + spkix = SECKEY_CreateSubjectPublicKeyInfo(pk_p); + if (spkix == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: CreateSubjectPublicKeyInfo returns null"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; + } + + /* + * RFC 3279 + * The keyIdentifier is composed of the 160-bit SHA-1 hash of the + * value of the BIT STRING subjectPublicKey (excluding the tag, + * length, and number of unused bits). + */ + spkix->subjectPublicKey.len >>= 3; + si_kid = PK11_MakeIDFromPubKey(&spkix->subjectPublicKey); + if (si_kid == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: si_kid is null"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; + } + spkix->subjectPublicKey.len <<= 3; + SECKEY_DestroySubjectPublicKeyInfo(spkix); + + if (keyid == NULL) + keyid = new Buffer((BYTE*) si_kid->data, si_kid->len); + if (keyid == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: keyid is null"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; + } + si_exp = pk_p->u.rsa.publicExponent; + exponent = new Buffer((BYTE*) si_exp.data, si_exp.len); + if (exponent == NULL) { + PR_snprintf(audit_msg, 512, "Write cert to token failed: exponent is null"); + renewal_failure_found = RENEWAL_FAILURE; + goto rloser; + } + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "Keyid, modulus and exponent have been extracted from public key"); + + renewed = true; + + RA::Audit(EV_RENEWAL, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "renewal", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "Cert written to token successfully"); + + + rloser: + + if( keyid != NULL ) { + delete keyid; + keyid = NULL; + } + if( label != NULL ) { + PL_strfree( (char *) label ); + label = NULL; + } + if(renewal_failure_found == RENEWAL_FAILURE) { + RA::Debug("RA_Enroll_Processor_ProcessRenewal", "A renewal in list failed other than grace period error, aborting."); + goto loser; + } + } + break; + } //for + if((strcmp( attr_status, "active" ) == 0) && + renewed) { + char *cn = RA::ra_get_cert_cn(e); + if(renewedCertUpdateCount < ( maxCertUpdate -1)) //unlikely scenario this fails + renewedCertUpdateList[renewedCertUpdateCount++] = PL_strdup(cn); + // Let's hold off on the celebration until the end. + // RA::ra_update_cert_status(cn, "renewed"); + if (cn != NULL) { + PL_strfree(cn); + cn = NULL; + } + } + if( attr_status != NULL ) { + PL_strfree( attr_status ); + attr_status = NULL; + } + } else { + r = false; + o_status = STATUS_ERROR_LDAP_CONN; + goto loser; + } + RA::Debug("RA_Enroll_Processor::ProcessRenewal", + "Filter to find certificates = %s", filter); + } + +loser: + if (strlen(audit_msg) > 0) { // a failure occurred + RA::Audit(EV_RENEWAL, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "failure", + "renewal", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + audit_msg); + } + + //Let's wait until all the certs are processed to actually update the renewal status + RA::Debug("RA_Enroll_Process::ProcessRenewal","renewedCertUpdateCount %d", renewedCertUpdateCount); + if(renewedCertUpdateCount > 0) { + for(int rr = 0; rr < renewedCertUpdateCount; rr++) { + if(renewedCertUpdateList[rr]) { + if(renewal_failure_found != RENEWAL_FAILURE) { + RA::Debug("RA_Enroll_Process::ProcessRenewal","updating to renewed status of cn= %s", renewedCertUpdateList[rr]); + RA::ra_update_cert_status(renewedCertUpdateList[rr],"renewed"); + } + PL_strfree(renewedCertUpdateList[rr]); + renewedCertUpdateList[rr] = NULL; + } + } + } else { + // All certs failed to renew + RA::Debug("RA_Enroll_Process::ProcessRenewal","All certs failed to renew, bailing with error"); + o_status = STATUS_ERROR_MAC_ENROLL_PDU; + r = false; + + } + + if( pretty_cuid != NULL ) { + PR_Free( (char *) pretty_cuid ); + pretty_cuid = NULL; + } + if( result != NULL ) { + ldap_msgfree( result ); + } + + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + + return r; +} + +bool RA_Enroll_Processor::ProcessRecovery(AuthParams *login, char *reason, RA_Session *session, char **&origins, char **&ktypes, + char *tokenType, PKCS11Obj *pkcs11objx, int pkcs11obj_enable, + NameValueSet *extensions, Secure_Channel *channel, Buffer *wrapped_challenge, + Buffer *key_check, Buffer *plaintext_challenge, char *cuid, char *msn, + const char *final_applet_version, char *khex, const char *userid, + RA_Status &o_status, CERTCertificate **&certificates, char *lostTokenCUID, + int &o_certNums, char **&tokenTypes, char *origTokenType) +{ + bool r = true; + o_status = STATUS_ERROR_RECOVERY_IS_PROCESSED; + char keyTypePrefix[256]; + char configname[256]; + char filter[256]; + LDAPMessage *result = NULL; + LDAPMessage *e = NULL; + char *o_pub = NULL; + char *o_priv = NULL; + const char *connid = NULL; + bool tksServerKeygen = false; + bool serverKeygen = false; + bool archive = false; + const char *pretty_cuid = NULL; + char audit_msg[512] = ""; + char *keyVersion = NULL; + char *ivParam = NULL; + + int i = 0; + int totalNumCerts = 0; + int actualCertIndex = 0; + int legalScheme = 0; + int isGenerateandRecover = 0; + const char *FN="RA_Enroll_Processor::ProcessRecovery"; + + RA::Debug("RA_Enroll_Processor::ProcessRecovery","entering..."); + // get key version for audit logs + if (channel != NULL) { + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + keyVersion = Util::Buffer2String(channel->GetKeyInfoData()); + } + + PR_snprintf(configname, 256, "op.enroll.%s.keyGen.recovery.%s.keyType.num", + tokenType, reason); + int keyTypeNum = RA::GetConfigStore()->GetConfigAsInt(configname, -1); + if (keyTypeNum == -1) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + goto loser; + } + + //We will have to rifle through the configuration to see if there any recovery operations with + //scheme "GenerateNewKeyandRecoverLast" which allows for recovering the old key AND generating a new + // one for the encryption type only. If this scheme is present, the number of certs for bump by + // 1 for each occurance. + + totalNumCerts = 0; + for(i = 0; i<keyTypeNum; i++) { + PR_snprintf(configname, 256, "op.enroll.%s.keyGen.recovery.%s.keyType.value.%d", tokenType, reason, i); + const char *keyTypeValue = (char *)(RA::GetConfigStore()->GetConfigAsString(configname)); + + if (keyTypeValue == NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + goto loser; + } + PR_snprintf(configname, 256, "op.enroll.%s.keyGen.%s.recovery.%s.scheme", tokenType, keyTypeValue, reason); + char *scheme = (char *)(RA::GetConfigStore()->GetConfigAsString(configname)); + if (scheme == NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + goto loser; + } + + //If we are doing "GenerateNewKeyandRecoverLast, we will create two certificates + //for that particular round. + if(PL_strcasecmp(scheme, "GenerateNewKeyandRecoverLast") == 0) { + + //Make sure someone doesn't try "GenerateNewKeyandRecoverLast" with a signing key. + + if(PL_strcasecmp(keyTypeValue,"encryption" ) != 0) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Invalid config param for %s. Can't use GenerateNewKeyandRecoveLaste scheme with non encryption key", + configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + goto loser; + } + totalNumCerts ++; + } + totalNumCerts ++; + } + + RA::Debug("RA_Enroll_Processor::ProcessRecovery","totalNumCerts %d ",totalNumCerts); + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "keyTypenum=%d", keyTypeNum); + + + if(!(totalNumCerts > keyTypeNum)) { + totalNumCerts = keyTypeNum; + } + + o_certNums = totalNumCerts; + certificates = (CERTCertificate **) malloc (sizeof(CERTCertificate *) * totalNumCerts); + ktypes = (char **) malloc (sizeof(char *) * totalNumCerts); + origins = (char **) malloc (sizeof(char *) * totalNumCerts); + tokenTypes = (char **) malloc (sizeof(char *) * totalNumCerts); + + for(i = 0; i < totalNumCerts; i++) { + ktypes[i] = NULL; + origins[i] = NULL; + tokenTypes[i] = NULL; + certificates[i] = NULL; + } + + //Iterate through number of key types. Iteration will be modified in case we have to insert extra + //certificates due to the "GenerateNewKeyandRecoverLast" scheme. + + actualCertIndex = 0; + legalScheme = 0; + for (i=0; i<keyTypeNum; i++) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery","Top cert loop: i %d actualCertIndex %d",i,actualCertIndex); + PR_snprintf(configname, 256, "op.enroll.%s.keyGen.recovery.%s.keyType.value.%d", tokenType, reason, i); + const char *keyTypeValue = (char *)(RA::GetConfigStore()->GetConfigAsString(configname)); + + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "keyType == %s ", keyTypeValue); + + if (keyTypeValue == NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + goto loser; + } + PR_snprintf(configname, 256, "op.enroll.%s.keyGen.%s.recovery.%s.scheme", tokenType, keyTypeValue, reason); + char *scheme = (char *)(RA::GetConfigStore()->GetConfigAsString(configname)); + if (scheme == NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + goto loser; + } + + // set allowable $$ config patterns + NameValueSet nv; + pretty_cuid = GetPrettyPrintCUID(cuid); + + nv.Add("pretty_cuid", pretty_cuid); + nv.Add("cuid", cuid); + nv.Add("msn", msn); + nv.Add("userid", userid); + //nv.Add("profileId", profileId); + + /* populate auth parameters output to nv also */ + /* so we can reference to the auth parameter by */ + /* using $auth.cn$, or $auth.mail$ */ + if (login != NULL) { + int s = login->Size(); + for (int x = 0; x < s; x++) { + char namebuf[2048]; + char *name = login->GetNameAt(x); + sprintf(namebuf, "auth.%s", name); + nv.Add(namebuf, login->GetValue(name)); + } + } + //Check for the special scheme where we generate a new cert and + //recover the last one. + + if(PL_strcasecmp(scheme, "GenerateNewKeyandRecoverLast") == 0) { + isGenerateandRecover = 1; + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Scheme %s: GenerateNewKeyandRecoverLast case!",scheme); + } else { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Scheme %s: Not GenerateNewKeyandRecoverLast case!",scheme); + isGenerateandRecover = 0; + } + + if ((PL_strcasecmp(scheme, "GenerateNewKey") == 0) || isGenerateandRecover) { + legalScheme = 1; + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "Generate new key for %s", keyTypeValue); + r = GenerateCertificate(login, keyTypeNum, keyTypeValue, actualCertIndex, session, origins, ktypes, tokenType, + pkcs11objx, pkcs11obj_enable, extensions, channel, wrapped_challenge, + key_check, plaintext_challenge, cuid, msn, final_applet_version, + khex, userid, o_status, certificates); + tokenTypes[actualCertIndex] = PL_strdup(tokenType); + if (o_status == STATUS_NO_ERROR) + o_status = STATUS_ERROR_RECOVERY_IS_PROCESSED; + } + + if ((PL_strcasecmp(scheme, "RecoverLast") == 0) || isGenerateandRecover) { + RA::Debug("RA_Enroll_Processor::RecoverLast", "Recover the key for %s", keyTypeValue); + // Special case for GenerateandRecover scenario. + + legalScheme = 1; + if(isGenerateandRecover) { + RA::Debug("RA_Enroll_Processor::RecoverLast", + "Generate extra recoverd cert for GenerateNewKeyandRecoverLast"); + + actualCertIndex ++; + } + PR_snprintf(filter, 256, "(&(tokenKeyType=%s)(tokenID=%s))", + keyTypeValue, lostTokenCUID); + int rc = RA::ra_find_tus_certificate_entries_by_order_no_vlv(filter, + &result, 1); + + tokenTypes[actualCertIndex] = PL_strdup(origTokenType); + char **attr = (char **) malloc (sizeof(char *) * totalNumCerts); + if (rc == LDAP_SUCCESS) { + // retrieve the most recent certificate, we just recover the most + // recent one + e = RA::ra_get_first_entry(result); + if (e != NULL) { + CERTCertificate **certs = RA::ra_get_certificates(e); + if (certs[0] != NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Certificate used to restore the private key"); + PR_snprintf(configname, 256, + "op.enroll.%s.keyGen.%s.serverKeygen.drm.conn", tokenType, keyTypeValue); + const char *drmconnid = RA::GetConfigStore()->GetConfigAsString(configname); + if (drmconnid == NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Missing the configuration parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + PR_snprintf(audit_msg, 512, "Key Recovery failed. Missing the configuration parameter for %s", configname); + goto loser; + } + + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "begin recovery code"); + + SECKEYPublicKey *pk_p = NULL; + SECItem si_mod; + Buffer *modulus=NULL; + SECItem *si_kid = NULL; + Buffer *keyid=NULL; + SECItem si_exp; + Buffer *exponent=NULL; + CERTSubjectPublicKeyInfo* spkix = NULL; + + //Now we have to get the original config params for the encryption cert and keys + + //XXX these attr functions shouldn't take config params + PR_snprintf(keyTypePrefix, 256, "op.enroll.%s.keyGen.encryption", tokenType); + + PR_snprintf((char *)configname, 256, "%s.keySize", keyTypePrefix); + int keysize = RA::GetConfigStore()->GetConfigAsInt(configname, 1024); + + PR_snprintf((char *)configname, 256, "%s.keyUsage", keyTypePrefix); + int keyUsage = RA::GetConfigStore()->GetConfigAsInt(configname, 0); + PR_snprintf((char *)configname, 256, "%s.keyUser", keyTypePrefix); + int keyUser = RA::GetConfigStore()->GetConfigAsInt(configname, 0); + + PR_snprintf((char *)configname, 256, "%s.certId",keyTypePrefix); + + const char *origCertId = RA::GetConfigStore()->GetConfigAsString(configname, "C0"); + + //actually adjust the crucial values based on this extra certificate + //being generated. + + int highestCertId = 0; + int newCertId = 0; + if(isGenerateandRecover) { + //find highest cert id number. + for(int j=0; j < keyTypeNum; j++) { + PR_snprintf((char *)configname, 256,"%s.certId", keyTypePrefix); + const char *cId = RA::GetConfigStore()->GetConfigAsString(configname, "C0"); + int id_int = 0; + if(cId) { + id_int = cId[1] - '0'; + } + + if (id_int > highestCertId) + highestCertId = id_int; + } + highestCertId++; + } else { + highestCertId = origCertId[1] - '0'; + } + + newCertId = highestCertId; + + RA::Debug("RA_Enroll_Processor::ProcessRecovery","Calculated new CertID %d.",newCertId); + + char certId[3]; + char certAttrId[3]; + char privateKeyAttrId[3]; + char publicKeyAttrId[3]; + int pubKeyNumber=0; + int priKeyNumber=0; + + certId[0] = 'C'; + certId[1] = '0' + newCertId; + certId[2] = 0; + + certAttrId[0] = 'c'; + certAttrId[1] = '0' + newCertId; + certAttrId[2] = 0; + + pubKeyNumber = 2 * newCertId + 1; + priKeyNumber = 2 * newCertId; + + privateKeyAttrId[0] = 'k'; + privateKeyAttrId[1] = '0' + priKeyNumber; + privateKeyAttrId[2] = 0; + + publicKeyAttrId[0] = 'k'; + publicKeyAttrId[1] = '0' + pubKeyNumber; + publicKeyAttrId[2] = 0; + + RA::Debug( + "RA_Enroll_Processor::ProcessRecovery", + "certId %s certAttrId %s privateKeyAttrId %s publicKeyAtrId %s priKeyNum %d pubKeyNum %d", + certId,certAttrId,privateKeyAttrId,publicKeyAttrId,priKeyNumber, pubKeyNumber); + + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.%s.label", + OP_PREFIX, tokenType, keyTypeValue); + RA::Debug(LL_PER_CONNECTION,FN, + "label '%s'", configname); + const char *pattern = RA::GetConfigStore()->GetConfigAsString(configname); + const char* label = MapPattern(&nv, (char *) pattern); + + BYTE objid[4]; + + objid[0] = 0xFF; + objid[1] = 0x00; + objid[2] = 0xFF; + objid[3] = 0xF3; + + char *tmp_c = NULL; + if (certs[0] != NULL) { + tmp_c = NSSBase64_EncodeItem(0, 0, 0, &(certs[0]->derCert)); + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "after NSSBase64_EncodeItem"); + } else { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "no cert!!"); + PR_snprintf(audit_msg, 512, "Key Recovery failed. no cert"); + goto rloser; + } + + if ((tmp_c == NULL) || (strcmp(tmp_c,"")==0)) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "NSSBase64_EncodeItem failed"); + PR_snprintf(audit_msg, 512, "Key Recovery failed. NSSBase64_EncodeItem failed"); + goto rloser; + } + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "NSSBase64_EncodeItem succeeded"); + attr[0] = PL_strdup(tmp_c); + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "b64 encoded cert =%s",attr[0]); + + if( newCertId > 9) { + + RA::Debug(LL_PER_CONNECTION,FN, + "RA_Enroll_Processor::ProcessRecovery","Possible misconfiguration or out of sync token!"); + PR_snprintf(audit_msg, 512, + "Renewal of cert failed, misconfiguration or out of sync token!"); + goto rloser; + } + + // get serverKeygen and archive, check if they are enabled. + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.%s.serverKeygen.enable", + OP_PREFIX, tokenType, keyTypeValue); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "looking for config %s", configname); + serverKeygen = RA::GetConfigStore()->GetConfigAsBool(configname, 0); + PR_snprintf((char *)configname, 256, "%s.%s.keyGen.%s.serverKeygen.archive", + OP_PREFIX, tokenType, keyTypeValue); + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + "looking for config %s", configname); + archive = RA::GetConfigStore()->GetConfigAsBool(configname, 0); + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + connid = RA::GetConfigStore()->GetConfigAsString(configname); + tksServerKeygen = false; + if (connid != NULL) { + PR_snprintf((char *)configname, 256, "conn.%s.serverKeygen", connid); + tksServerKeygen = RA::GetConfigStore()->GetConfigAsBool(configname, 0); + } else { + r = false; + o_status = STATUS_ERROR_NO_TKS_CONNID; + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::ProcessRecovery", "Missing tks.connid"); + PR_snprintf(audit_msg, 512, "Key Recovery failed. Missing tks.connid"); + goto rloser; + } + + if (tksServerKeygen && archive && serverKeygen) { + RA::RecoverKey(session, lostTokenCUID, userid, + channel->getDrmWrappedDESKey(), + attr[0], &o_pub, &o_priv, + (char *)drmconnid,&ivParam); + } else { + r = false; + o_status = STATUS_ERROR_KEY_ARCHIVE_OFF; + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::ProcessRecovery", "Archival is turned off"); + PR_snprintf(audit_msg, 512, "Key Recovery failed. Archival is turned off"); + goto rloser; + } + + if (o_pub == NULL) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::DoEnrollment()", "RecoverKey called, o_pub is NULL"); + r = false; + o_status = STATUS_ERROR_RECOVERY_FAILED; + PR_snprintf(audit_msg, 512, "Key Recovery failed. o_pub is NULL"); + goto rloser; + } else + RA::Debug(LL_PER_PDU, "DoEnrollment", "o_pub = %s", o_pub); + + + if (o_priv == NULL) { + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::DoEnrollment()", "RecoverKey called, o_priv is NULL"); + /* XXX + r = false; + o_status = STATUS_ERROR_RECOVERY_FAILED; + goto rloser; + */ + } else + RA::Debug(LL_PER_PDU, "DoEnrollment", "o_priv = %s", o_priv); + + if (ivParam == NULL) { + RA::Debug(LL_PER_CONNECTION,"RA_Enroll_Processor::ProcessRecovery", + "ProcessRecovery called, ivParam is NULL"); + r = false; + o_status = STATUS_ERROR_RECOVERY_FAILED; + PR_snprintf(audit_msg, 512, "RA_Enroll_Processor::ProcessRecovery called, ivParam is NULL"); + goto rloser; + } else { + RA::Debug(LL_PER_CONNECTION,"ProcessRecovery", + "ivParam = %s", ivParam); + } + + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::ProcessRecovery()", "key injection for RecoverKey occurs here"); + /* + * the following code converts b64-encoded public key info into SECKEYPublicKey + */ + SECStatus rv; + SECItem der; + CERTSubjectPublicKeyInfo* spki; + + der.type = (SECItemType) 0; /* initialize it, since convertAsciiToItem does not set it */ + rv = ATOB_ConvertAsciiToItem (&der, o_pub); + if (rv != SECSuccess){ + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "after converting public key, rv is failure"); + SECITEM_FreeItem(&der, PR_FALSE); + r = false; + o_status = STATUS_ERROR_RECOVERY_FAILED; + PR_snprintf(audit_msg, 512, "Key Recovery failed. after converting public key, rv is failure"); + goto rloser; + }else { + RA::Debug(LL_PER_PDU, "ProcessRecovery", "item len=%d, item type=%d",der.len, der.type); + + spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der); + SECITEM_FreeItem(&der, PR_FALSE); + + if (spki != NULL) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "after converting public key spki is not NULL"); + pk_p = SECKEY_ExtractPublicKey(spki); + if (pk_p != NULL) + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "after converting public key pk_p is not NULL"); + else + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "after converting public key, pk_p is NULL"); + } else + RA::Debug("RA_Enroll_Processor::ProcessRecovery", "after converting public key, spki is NULL"); + + } + SECKEY_DestroySubjectPublicKeyInfo(spki); + + if( pk_p == NULL ) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "pk_p is NULL; unable to continue"); + r = false; + o_status = STATUS_ERROR_RECOVERY_FAILED; + PR_snprintf(audit_msg, 512, "Key Recovery failed. pk_p is NULL; unable to continue"); + goto rloser; + } + + // XXX - Add serial number and public key to audit log + //get serial number for audit log + //char msg[2048]; + //RA::ra_tus_print_integer(msg, &certs[0]->serialNumber); + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "key recovered successfully"); + + + /* fill in keyid, modulus, and exponent */ + + si_mod = pk_p->u.rsa.modulus; + modulus = new Buffer((BYTE*) si_mod.data, si_mod.len); + + spkix = SECKEY_CreateSubjectPublicKeyInfo(pk_p); + + /* + * RFC 3279 + * The keyIdentifier is composed of the 160-bit SHA-1 hash of the + * value of the BIT STRING subjectPublicKey (excluding the tag, + * length, and number of unused bits). + */ + spkix->subjectPublicKey.len >>= 3; + si_kid = PK11_MakeIDFromPubKey(&spkix->subjectPublicKey); + spkix->subjectPublicKey.len <<= 3; + SECKEY_DestroySubjectPublicKeyInfo(spkix); + + keyid = new Buffer((BYTE*) si_kid->data, si_kid->len); + si_exp = pk_p->u.rsa.publicExponent; + exponent = new Buffer((BYTE*) si_exp.data, si_exp.len); + + RA::Debug(LL_PER_PDU, "RA_Enroll_Processor::Process", + " keyid, modulus and exponent are retrieved"); + + ktypes[actualCertIndex] = PL_strdup(keyTypeValue); + // We now store the token id of the original token + // that generates this certificate so we can + // tell if the certificate should be operated + // on or not during formation operation + origins[actualCertIndex] = PL_strdup(lostTokenCUID); + certificates[actualCertIndex] = certs[0]; + + + // Create KeyBlob for private key, but first b64 decode it + /* url decode o_priv */ + { + Buffer priv_keyblob; + Buffer *decodeKey = Util::URLDecode(o_priv); + //RA::DebugBuffer("cfu debug"," private key =",decodeKey); + priv_keyblob = + Buffer(1, 0x01) + // encryption + Buffer(1, 0x09)+ // keytype is RSAPKCS8Pair + Buffer(1,(BYTE)(keysize/256)) + // keysize is two bytes + Buffer(1,(BYTE)(keysize%256)) + + Buffer((BYTE*) *decodeKey, decodeKey->size()); + delete decodeKey; + + //inject PKCS#8 private key + BYTE perms[6]; + + perms[0] = 0x40; + perms[1] = 0x00; + perms[2] = 0x40; + perms[3] = 0x00; + perms[4] = 0x40; + perms[5] = 0x00; + + if (channel->CreateObject(objid, perms, priv_keyblob.size()) != 1) { + r = false; + PR_snprintf(audit_msg, 512, "Failed to write key to token. CreateObject failed."); + goto rloser; + } + + if (channel->WriteObject(objid, (BYTE*)priv_keyblob, priv_keyblob.size()) != 1) { + r = false; + PR_snprintf(audit_msg, 512, "Failed to write key to token. WriteObject failed."); + goto rloser; + } + } + + /* url decode the wrapped kek session key and keycheck*/ + { + Buffer data; + /* + RA::Debug(LL_PER_PDU, "", "getKekWrappedDESKey() returns =%s", channel->getKekWrappedDESKey()); + RA::Debug(LL_PER_PDU, "", "getKeycheck() returns =%s", channel->getKeycheck()); + */ + Buffer *decodeKey = Util::URLDecode(channel->getKekWrappedDESKey()); + + /* + RA::Debug(LL_PER_PDU, "", "des key item len=%d", + decodeKey->size()); + RA::DebugBuffer("cfu debug", "DES key =", decodeKey); + */ + char *keycheck = channel->getKeycheck(); + Buffer *decodeKeyCheck = Util::URLDecode(keycheck); + if (keycheck) + PL_strfree(keycheck); + + /* + RA::Debug(LL_PER_PDU, "", "keycheck item len=%d", + decodeKeyCheck->size()); + RA::DebugBuffer("cfu debug", "key check=", decodeKeyCheck); + */ + + BYTE alg = 0x80; + if(decodeKey && decodeKey->size()) { + alg = 0x81; + } + + //Get iv data returned by DRM + + Buffer *iv_decoded = Util::URLDecode(ivParam); + if (ivParam) { + PL_strfree(ivParam); + } + + if(iv_decoded == NULL) { + r = false; + PR_snprintf(audit_msg, 512, "ProcessRecovery: store keys in token failed, iv data not found"); + delete decodeKey; + delete decodeKeyCheck; + goto rloser; + } + + data = + Buffer((BYTE*)objid, 4)+ // object id + Buffer(1,alg) + + //Buffer(1, 0x08) + // key type is DES3: 8 + Buffer(1, (BYTE) decodeKey->size()) + // 1 byte length + Buffer((BYTE *) *decodeKey, decodeKey->size())+ // key -encrypted to 3des block + // check size + // key check + Buffer(1, (BYTE) decodeKeyCheck->size()) + //keycheck size + Buffer((BYTE *) *decodeKeyCheck , decodeKeyCheck->size())+ // keycheck + Buffer(1, iv_decoded->size())+ // IV_Length + Buffer((BYTE*)*iv_decoded, iv_decoded->size()); + + //RA::DebugBuffer("cfu debug", "ImportKeyEnc data buffer =", &data); + + delete decodeKey; + delete decodeKeyCheck; + delete iv_decoded; + + if (channel->ImportKeyEnc((keyUser << 4)+priKeyNumber, + (keyUsage << 4)+pubKeyNumber, &data) != 1) { + r = false; + PR_snprintf(audit_msg, 512, "Failed to write key to token. ImportKeyEnc failed."); + goto rloser; + } + } + + { + Buffer *certbuf = new Buffer(certs[0]->derCert.data, certs[0]->derCert.len); + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (certId[0] << 24) + + (certId[1] << 16), + certbuf); + pkcs11objx->AddObjectSpec(objSpec); + } + { + Buffer b = channel->CreatePKCS11CertAttrsBuffer( + KEY_TYPE_ENCRYPTION , certAttrId, label, keyid); + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (certAttrId[0] << 24) + + (certAttrId[1] << 16), + &b); + pkcs11objx->AddObjectSpec(objSpec); + } + + { + Buffer b = channel->CreatePKCS11PriKeyAttrsBuffer(KEY_TYPE_ENCRYPTION, + privateKeyAttrId, label, keyid, modulus, OP_PREFIX, + tokenType, keyTypePrefix); + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (privateKeyAttrId[0] << 24) + + (privateKeyAttrId[1] << 16), + &b); + pkcs11objx->AddObjectSpec(objSpec); + } + + { + Buffer b = channel->CreatePKCS11PubKeyAttrsBuffer(KEY_TYPE_ENCRYPTION, + publicKeyAttrId, label, keyid, + exponent, modulus, OP_PREFIX, tokenType, keyTypePrefix); + ObjectSpec *objSpec = + ObjectSpec::ParseFromTokenData( + (publicKeyAttrId[0] << 24) + + (publicKeyAttrId[1] << 16), + &b); + pkcs11objx->AddObjectSpec(objSpec); + } + + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "key written to token successfully"); + + rloser: + + if( modulus != NULL ) { + delete modulus; + modulus = NULL; + } + if( keyid != NULL ) { + delete keyid; + keyid = NULL; + } + if( exponent != NULL ) { + delete exponent; + exponent = NULL; + } + if( attr[0] != NULL ) { + PR_Free(attr[0]); + attr[0] = NULL; + } + if( o_pub != NULL ) { + PR_Free(o_pub); + o_pub = NULL; + } + + if (o_priv !=NULL) { + PR_Free(o_priv); + o_priv = NULL; + } + + if( si_kid != NULL ) { + SECITEM_FreeItem( si_kid, PR_TRUE ); + si_kid = NULL; + } + if( label != NULL ) { + PL_strfree( (char *) label ); + label = NULL; + } + + } + } + } else { + r = false; + o_status = STATUS_ERROR_LDAP_CONN; + goto loser; + } + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Filter to find certificates = %s", filter); + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Recover key for %s", keyTypeValue); + + //Unrevoke this successfully recovered certificate + if ( o_status == STATUS_ERROR_RECOVERY_IS_PROCESSED && e != NULL) { + char *statusString = NULL; + int statusNum = UnrevokeRecoveredCert(e, statusString); + + // Error from the CA log and get out + if (statusNum != 0) { + r = false; + o_status = STATUS_ERROR_RECOVERY_FAILED; + if (statusString == NULL || strlen(statusString) == 0) { + statusString = PL_strdup("Unknown Key Recovery Error."); + } + RA::Debug("RA_Enroll::Prcessor::ProcessRecovery", "Unrevoke statusString: %s",statusString); + PR_snprintf(audit_msg, 512, "Key Recovery failed. Can not unrevoke recovered certificate! %s",statusString); + if (statusString) { + PL_strfree(statusString); + } + goto loser; + } + + if (statusString) { + PL_strfree(statusString); + } + } + } + if( !legalScheme) { + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "Misconfigure parameter for %s", configname); + r = false; + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + goto loser; + } + + actualCertIndex++; + RA::Debug("RA_Enroll_Processor::ProcessRecovery","leaving cert loop... "); + } + + loser: + if (strlen(audit_msg) > 0) { // a failure occurred + RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "failure", + "enrollment", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + audit_msg); + } + + if( pretty_cuid != NULL ) { + PR_Free( (char *) pretty_cuid ); + pretty_cuid = NULL; + } + if( result != NULL ) { + ldap_msgfree( result ); + } + + + RA::Debug("RA_Enroll_Processor::ProcessRecovery","leaving whole function..."); + return r; +} + +int RA_Enroll_Processor::DoPublish(const char *cuid,SECItem *encodedPublicKeyInfo,Buffer *cert,const char *publisher_id,char *applet_version) +{ + + int res = 0; + + CERTCertificate *certObj = NULL; + const char *FN="DoPublish"; + + unsigned char *public_key_data = NULL; + int public_key_len = 0; + PRTime not_before,not_after; + + // 1980 epoch offset + + PRTime ul_1980 = ((365 * 10 + 2) * 86400); + + + if(! encodedPublicKeyInfo) + { + return 0; + } + + + RA::Debug(LL_PER_CONNECTION,FN, "1980 epoch offset %u ",ul_1980); + + PRUint32 ul_not_before, ul_not_after; + + int key_type = 1; + + RA::Debug(LL_PER_CONNECTION,FN, "We got a public key back. Now attempt publish operation."); + + public_key_data = encodedPublicKeyInfo->data; + public_key_len = encodedPublicKeyInfo->len; + + unsigned long applet_version_long = 0; + + char *end = NULL; + + if(applet_version) + { + applet_version_long = (unsigned long) strtol((const char *)applet_version,&end,16); + } + if(cuid) + { + RA::Debug(LL_PER_CONNECTION,FN, + "cuid %s public_key_len %ud",cuid,public_key_len); + + } + if(cert) + { + RA::Debug(LL_PER_CONNECTION,FN, + "cert.size() %ld. cert %s",cert->size(),(char *) (BYTE *) cert); + + certObj = CERT_DecodeCertFromPackage((char *) cert->string(), (int) cert->size()); + } + RA::Debug(LL_PER_CONNECTION,FN, + "certObj %p.",certObj); + + if(certObj && cuid != NULL) + { + RA::Debug(LL_PER_CONNECTION,FN, + "We got pointer to Certificate data."); + CERT_GetCertTimes (certObj, ¬_before, ¬_after); + + ul_not_before = ( PRUint32 )( not_before/1000000 ); + ul_not_after = ( PRUint32 )( not_after/1000000 ); + + RA::Debug(LL_PER_CONNECTION,FN, + "Cert date not_before %u not_after %u.",ul_not_before,ul_not_after); + + // Convert to 1980 epoch time + + ul_not_before -= (PRUint32) ul_1980; + ul_not_after -= (PRUint32) ul_1980; + + + RA::Debug(LL_PER_CONNECTION,FN, + "Cert date, after 1980 translation, not_before %ul not_after %ul.",ul_not_before,ul_not_after); + + + PublisherEntry *publish = RA::getPublisherById(publisher_id); + + if(publish != NULL) + { + RA::Debug(LL_PER_CONNECTION,FN, + "publisher %s ",publish->id); + } + else + { + RA::Debug(LL_PER_CONNECTION,FN, + "publisher %s not found ",publisher_id); + + } + + res = 0; + if(publish && publish->publisher ) + { + IPublisher *pb = publish->publisher; + RA::Debug(LL_PER_CONNECTION,FN, + "publisher %p ",pb); + res = pb->publish((unsigned char *) cuid,(int) strlen(cuid),(long) key_type,(unsigned char *) public_key_data,(int) public_key_len,(unsigned long)ul_not_before,(unsigned long) ul_not_after,applet_version_long,applet_version_long - ul_1980); + + } + if(!res) + { + RA::Debug(LL_PER_CONNECTION,FN, + "Publish failed."); + } + else + { + RA::Debug(LL_PER_CONNECTION,FN, + "Publish success."); + } + } + else + { + RA::Debug(LL_PER_CONNECTION,FN, + "No Publish failed Either cuid or certObj is NULL."); + } + + if(certObj) + { + + CERT_DestroyCertificate(certObj); + } + return res; +} + +int RA_Enroll_Processor::GetNextFreeCertIdNumber(PKCS11Obj *pkcs11objx) +{ + if(!pkcs11objx) + return 0; + + //Look through the objects actually currently on the token + //to determine an appropriate free certificate id + + int num_objs = pkcs11objx->PKCS11Obj::GetObjectSpecCount(); + char objid[2]; + + int highest_cert_id = 0; + for (int i = 0; i< num_objs; i++) { + ObjectSpec* os = pkcs11objx->GetObjectSpec(i); + unsigned long oid = os->GetObjectID(); + objid[0] = (char)((oid >> 24) & 0xff); + objid[1] = (char)((oid >> 16) & 0xff); + + if(objid[0] == 'C') { //found a certificate + + int id_int = objid[1] - '0'; + + if(id_int > highest_cert_id) { + highest_cert_id = id_int; + } + } + } + + RA::Debug(LL_PER_CONNECTION, + "RA_Enroll_Processor::GetNextFreeCertIdNumber", + "returning id number: %d", highest_cert_id + 1); + return highest_cert_id + 1; +} + +//Unrevoke a cert that has been recovered +int RA_Enroll_Processor::UnrevokeRecoveredCert(const LDAPMessage *e, char *&statusString) +{ + char configname[256]; + CertEnroll certEnroll; + //Default to error return + int statusNum = 0; + char serial[100]=""; + + RA::Debug("RA_Enroll_Processor::ProcessRecovery", + "About to unrevoke recovered certificate."); + + if (e == NULL) { + return 1; + } + + char *attr_serial= RA::ra_get_cert_serial( (LDAPMessage *) e ); + char *attr_tokenType = RA::ra_get_cert_tokenType( (LDAPMessage *) e ); + char *attr_keyType = RA::ra_get_cert_type( (LDAPMessage *) e ); + + // does the config say we have to revoke this cert? + PR_snprintf( ( char * ) configname, 256, + "op.enroll.%s.keyGen.%s.recovery." + "onHold.revokeCert", + attr_tokenType, attr_keyType ); + + RA::Debug("RA_Enroll_Processor::UnrevokeRecoveredCert", + "Recovered Cert Unrevoke config value %s \n", configname); + bool revokeCert = RA::GetConfigStore()-> + GetConfigAsBool( configname, false ); + if( revokeCert ) { + // Assume the worst + statusNum = 1; + // Get the conn to the CA + PR_snprintf( ( char * ) configname, 256, + "op.enroll.%s.keyGen.%s.ca.conn", + attr_tokenType, attr_keyType ); + + char *connid = ( char * ) + RA::GetConfigStore()-> + GetConfigAsString( configname ); + + if (connid) { + PR_snprintf( serial, 100, "0x%s", attr_serial ); + + //Actually make call to the CA to unrevoke + statusNum = certEnroll.UnrevokeCertificate(serial, connid, statusString); + + RA::Debug("RA_Enroll_Processor::UnrevokeRecoveredCert", + "Recovered Cert statusNum %d statusString %s \n", statusNum, statusString); + } + } + + if (attr_serial) { + PL_strfree(attr_serial); + } + + if (attr_tokenType) { + PL_strfree(attr_tokenType); + } + + if (attr_keyType) { + PL_strfree(attr_keyType); + } + return statusNum; +} + +void PrintPRTime(PRTime theTime, const char *theName) +{ + struct tm t; + PRExplodedTime explode; + char buffer[256]; + + if(!theName) + return; + + PR_ExplodeTime (theTime, PR_LocalTimeParameters, &explode); + + t.tm_sec = explode.tm_sec; + t.tm_min = explode.tm_min; + t.tm_hour = explode.tm_hour; + t.tm_mday = explode.tm_mday; + t.tm_mon = explode.tm_month; + t.tm_year = explode.tm_year - 1900; + t.tm_wday = explode.tm_wday; + t.tm_yday = explode.tm_yday; + + PL_strncpy(buffer, asctime (&t), 256); + buffer[256 - 1] = 0; + + RA::Debug("PrintPRTime","Date/Time: %s %s",theName,buffer); +} diff --git a/base/tps/src/processor/RA_Format_Processor.cpp b/base/tps/src/processor/RA_Format_Processor.cpp new file mode 100644 index 000000000..b09a7495b --- /dev/null +++ b/base/tps/src/processor/RA_Format_Processor.cpp @@ -0,0 +1,70 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#include <string.h> + +#include "main/RA_Session.h" +#include "main/RA_Msg.h" +#include "main/Buffer.h" +#include "main/Util.h" +#include "engine/RA.h" +#include "channel/Secure_Channel.h" +#include "msg/RA_SecureId_Request_Msg.h" +#include "msg/RA_SecureId_Response_Msg.h" +#include "msg/RA_New_Pin_Request_Msg.h" +#include "msg/RA_New_Pin_Response_Msg.h" +#include "processor/RA_Processor.h" +#include "processor/RA_Format_Processor.h" +#include "cms/CertEnroll.h" +#include "httpClient/httpc/response.h" +#include "main/Memory.h" +#include "tus/tus_db.h" +#include "ldap.h" + +#define OP_PREFIX "op.format" + +#ifdef XP_WIN32 +#define TPS_PUBLIC __declspec(dllexport) +#else /* !XP_WIN32 */ +#define TPS_PUBLIC +#endif /* !XP_WIN32 */ + +/** + * Constructs a processor for handling upgrade operation. + */ +TPS_PUBLIC RA_Format_Processor::RA_Format_Processor () +{ +} + +/** + * Destructs upgrade processor. + */ +TPS_PUBLIC RA_Format_Processor::~RA_Format_Processor () +{ +} + +/** + * Processes the current session. + */ +TPS_PUBLIC RA_Status RA_Format_Processor::Process(RA_Session *session, NameValueSet *extensions) +{ + bool skip_auth = false; + return Format(session,extensions,skip_auth); +} diff --git a/base/tps/src/processor/RA_Pin_Reset_Processor.cpp b/base/tps/src/processor/RA_Pin_Reset_Processor.cpp new file mode 100644 index 000000000..b776b55a4 --- /dev/null +++ b/base/tps/src/processor/RA_Pin_Reset_Processor.cpp @@ -0,0 +1,1013 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#include "engine/RA.h" +#include "main/Util.h" +#include "main/RA_Msg.h" +#include "main/RA_Session.h" +#include "channel/Secure_Channel.h" +#include "processor/RA_Processor.h" +#include "processor/RA_Pin_Reset_Processor.h" +#include "main/Memory.h" +#include "tus/tus_db.h" +#define OP_PREFIX "op.pinReset" +static const char *expected_version = NULL; + +#ifdef XP_WIN32 +#define TPS_PUBLIC __declspec(dllexport) +#else /* !XP_WIN32 */ +#define TPS_PUBLIC +#endif /* !XP_WIN32 */ + +/** + * Constructs a processor for hanlding pin reset operation. + */ +TPS_PUBLIC RA_Pin_Reset_Processor::RA_Pin_Reset_Processor() +{ +} + +/** + * Destructs pin reset processor. + */ +TPS_PUBLIC RA_Pin_Reset_Processor::~RA_Pin_Reset_Processor() +{ +} + +/** + * Process the current session. + */ +TPS_PUBLIC RA_Status RA_Pin_Reset_Processor::Process(RA_Session *session, NameValueSet *extensions) +{ + struct berval **tokenOwner=NULL; + char configname[256]; + const char *tokenType = NULL; + char *cuid = NULL; + const char *msn = NULL; + PRIntervalTime start, end; + RA_Status status = STATUS_NO_ERROR; + int rc = -1; + AuthParams *login = NULL; + Secure_Channel *channel = NULL; + char *new_pin = NULL; + unsigned int minlen = 0, maxlen = 0; + const char *applet_dir; + bool upgrade_enc = false; + char curVer[10]; + char newVer[10]; + + char *curKeyInfoStr = NULL; + char *newVersionStr = NULL; + + SecurityLevel security_level = SECURE_MSG_MAC_ENC; + Buffer *CardManagerAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_CARDMGR_INSTANCE_AID, + RA::CFG_DEF_CARDMGR_INSTANCE_AID); + Buffer *NetKeyAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_NETKEY_INSTANCE_AID, + RA::CFG_DEF_NETKEY_INSTANCE_AID); + + int i; + Buffer key_data_set; + Buffer *token_status = NULL; + Buffer *buildID = NULL; + char *policy = NULL; + char *tmp_policy = NULL; + const char* required_version = NULL; + const char *appletVersion = NULL; + const char *final_applet_version = NULL; + char *keyVersion = PL_strdup( "" ); + const char *userid = PL_strdup( "" ); + BYTE major_version = 0x0; + BYTE minor_version = 0x0; + BYTE app_major_version = 0x0; + BYTE app_minor_version = 0x0; + char *token_userid = NULL; + + Buffer host_challenge = Buffer(8, (BYTE)0); + Buffer key_diversification_data; + Buffer key_info_data; + Buffer card_challenge; + Buffer card_cryptogram; + Buffer token_cuid; + Buffer token_msn; + const char *connId = NULL; + const char *connid = NULL; + const char *tksid = NULL; + const char *authid = NULL; + AuthParams *authParams = NULL; + start = PR_IntervalNow(); + Buffer *cplc_data = NULL; + char activity_msg[4096]; + LDAPMessage *e = NULL; + LDAPMessage *ldapResult = NULL; + int maxReturns = 10; + char audit_msg[512] = ""; + char *profile_state = NULL; + int key_change_over_success = 0; + + + RA::Debug("RA_Pin_Reset_Processor::Process", "Client %s", session->GetRemoteIP()); + + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "RA_Pin_Reset_Processor::Process"); + + + SelectApplet(session, 0x04, 0x00, CardManagerAID); + cplc_data = GetData(session); + if (cplc_data == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", + "Get Data Failed"); + status = STATUS_ERROR_SECURE_CHANNEL; + PR_snprintf(audit_msg, 512, "Get Data Failed, status = STATUS_ERROR_SECURE_CHANNEL"); + goto loser; + } + RA::DebugBuffer("RA_Pin_Reset_Processor::process", "CPLC Data = ", + cplc_data); + if (cplc_data->size() < 47) { + RA::Error("RA_Format_Processor::Process", + "Invalid CPLC Size"); + status = STATUS_ERROR_SECURE_CHANNEL; + PR_snprintf(audit_msg, 512, "Invalid CPLC Size, status = STATUS_ERROR_SECURE_CHANNEL"); + goto loser; + } + token_cuid = Buffer(cplc_data->substr(3,4)) + + Buffer(cplc_data->substr(19,2)) + + Buffer(cplc_data->substr(15,4)); + RA::DebugBuffer("RA_Pin_Reset_Processor::process", "Token CUID= ", + &token_cuid); + cuid = Util::Buffer2String(token_cuid); + + token_msn = Buffer(cplc_data->substr(41, 4)); + RA::DebugBuffer("RA_Pin_Reset_Processor::process", "Token MSN= ", + &token_msn); + msn = Util::Buffer2String(token_msn); + + /** + * Checks if the netkey has the required applet version. + */ + SelectApplet(session, 0x04, 0x00, NetKeyAID); + token_status = GetStatus(session, 0x00, 0x00); + if (token_status == NULL) { + major_version = 0x0; + minor_version = 0x0; + app_major_version = 0x0; + app_minor_version = 0x0; + } else { + major_version = ((BYTE*)*token_status)[0]; + minor_version = ((BYTE*)*token_status)[1]; + app_major_version = ((BYTE*)*token_status)[2]; + app_minor_version = ((BYTE*)*token_status)[3]; + } + + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "Major=%d Minor=%d", major_version, minor_version); + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "Applet Major=%d Applet Minor=%d", app_major_version, app_minor_version); + + if (!RA::ra_is_token_present(cuid)) { + RA::Error("RA_Pin_Reset_Processor::Process", + "CUID %s Not Present", cuid); + status = STATUS_ERROR_DB; + PR_snprintf(audit_msg, 512, "CUID Not Present, status = STATUS_ERROR_DB"); + goto loser; + } + + // retrieve CUID + + if (!GetTokenType(OP_PREFIX, major_version, + minor_version, cuid, msn, + extensions, status, tokenType)) { + PR_snprintf(audit_msg, 512, "Failed to get token type"); + goto loser; + } + + // check if profile is enabled + PR_snprintf((char *)configname, 256, "config.Profiles.%s.state", tokenType); + profile_state = (char *) RA::GetConfigStore()->GetConfigAsString(configname); + if ((profile_state != NULL) && (PL_strcmp(profile_state, "Enabled") != 0)) { + RA::Error("RA_Pin_Reset_Processor::Process", "Profile %s Disabled for CUID %s", tokenType, cuid); + status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + PR_snprintf(audit_msg, 512, "profile %s disabled", tokenType); + goto loser; + } + + if (RA::ra_is_tus_db_entry_disabled(cuid)) { + RA::Error("RA_Pin_Reset_Processor::Process", + "CUID %s Disabled", cuid); + status = STATUS_ERROR_DISABLED_TOKEN; + PR_snprintf(audit_msg, 512, "Token disabled, status = STATUS_ERROR_DISABLED_TOKEN"); + goto loser; + } + + // we know cuid and msn here + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "pin_reset", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "token enabled"); + + if (!RA::ra_is_token_pin_resetable(cuid)) { + RA::Error("RA_Pin_Reset_Processor::Process", + "CUID %s Cannot Pin Reset", cuid); + status = STATUS_ERROR_NOT_PIN_RESETABLE; + PR_snprintf(audit_msg, 512, "token cannot pin reset, status = STATUS_ERROR_PIN_RESETABLE"); + goto loser; + } + + // we know cuid and msn here + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "pin_reset", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "pin reset allowed"); + + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", + OP_PREFIX, tokenType); + tksid = RA::GetConfigStore()->GetConfigAsString(configname); + if (tksid == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", + "TKS Connection Parameter %s Not Found", configname); + status = STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND; + PR_snprintf(audit_msg, 512, "TKS Connection Parameter %s Not Found, status = STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND", configname); + goto loser; + } + + buildID = GetAppletVersion(session); + if (buildID == NULL) { + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.emptyToken.enable", OP_PREFIX, + tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + appletVersion = PL_strdup( "unknown" ); + } else { + RA::Error("RA_Pin_Reset_Processor::Process", + "no applet found and applet upgrade not enabled"); + status = STATUS_ERROR_SECURE_CHANNEL; + PR_snprintf(audit_msg, 512, "no applet found and applet upgrade not enabled, status = STATUS_ERROR_SECURE_CHANNEL"); + goto loser; + } + } else { + char * buildid = Util::Buffer2String(*buildID); + RA::Debug("RA_Pin_Reset_Processor", "buildid = %s", buildid); + char version[13]; + PR_snprintf((char *) version, 13, + "%x.%x.%s", app_major_version, app_minor_version, + buildid); + appletVersion = strdup(version); + if (buildid != NULL) { + PR_Free(buildid); + buildid = NULL; + } + } + + final_applet_version = strdup(appletVersion); + RA::Debug("RA_Pin_Reset_Processor", "final_applet_version = %s", final_applet_version); + + /** + * Checks if we need to upgrade applet. + */ + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.requiredVersion", OP_PREFIX, tokenType); + required_version = RA::GetConfigStore()->GetConfigAsString(configname); + expected_version = PL_strdup(required_version); + + if (expected_version == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", + "misconfiguration for upgrade"); + status = STATUS_ERROR_MISCONFIGURATION; + PR_snprintf(audit_msg, 512, "misconfiguration for upgrade, status = STATUS_ERROR_MISCONFIGURATION"); + goto loser; + } + /* Bugscape #55826: used case-insensitive check below */ + if (PL_strcasecmp(expected_version, appletVersion) != 0) { + /* upgrade applet */ + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.directory", OP_PREFIX, tokenType); + applet_dir = RA::GetConfigStore()->GetConfigAsString(configname); + if (applet_dir == NULL || strlen(applet_dir) == 0) { + RA::Error(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "Failed to get %s", applet_dir); + PR_snprintf(audit_msg, 512, "Failed to get %s", applet_dir); + goto loser; + } + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.encryption", OP_PREFIX, tokenType); + upgrade_enc = RA::GetConfigStore()->GetConfigAsBool(configname, true); + if (!upgrade_enc) + security_level = SECURE_MSG_MAC; + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + connid = RA::GetConfigStore()->GetConfigAsString(configname); + int upgrade_rc = UpgradeApplet(session, (char *) OP_PREFIX, (char*)tokenType, major_version, minor_version, + expected_version, applet_dir, security_level, connid, extensions, 30, 70, &keyVersion); + if (upgrade_rc != 1) { + RA::Error("RA_Pin_Reset_Processor::Process", + "upgrade failure"); + status = STATUS_ERROR_UPGRADE_APPLET; + /** + * Bugscape #55709: Re-select Net Key Applet ONLY on failure. + */ + SelectApplet(session, 0x04, 0x00, NetKeyAID); + + if (upgrade_rc == -1) { + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Failure", "pin_reset", + keyVersion != NULL? keyVersion : "", appletVersion, expected_version, "failed to setup secure channel"); + } else { + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Success", "pin_reset", + keyVersion != NULL? keyVersion : "", appletVersion, expected_version, "setup secure channel"); + } + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Failure", "pin_reset", + keyVersion != NULL? keyVersion : "", + appletVersion, expected_version, "applet upgrade"); + goto loser; + } + + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Success", "pin_reset", + keyVersion != NULL? keyVersion : "", appletVersion, expected_version, "setup secure channel"); + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Success", "pin_reset", + keyVersion != NULL? keyVersion : "", + appletVersion, expected_version, "applet upgrade"); + + final_applet_version = expected_version; + } + } + + /** + * Checks if the netkey has the required key version. + */ + PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.requiredVersion", OP_PREFIX, tokenType); + int requiredVersion = RA::GetConfigStore()->GetConfigAsInt(configname, 0x00); + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + connId = RA::GetConfigStore()->GetConfigAsString(configname); + if( channel != NULL ) { + delete channel; + channel = NULL; + } + channel = SetupSecureChannel(session, requiredVersion, + 0x00 /* default key index */, connId); + if (channel == NULL) { + + /* if version 0x02 key not found, create them */ + SelectApplet(session, 0x04, 0x00, CardManagerAID); + channel = SetupSecureChannel(session, + 0x00, /* default key version */ + 0x00 /* default key index */, connId); + + if (channel == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", + "setup secure channel failure"); + status = STATUS_ERROR_SECURE_CHANNEL; + PR_snprintf(audit_msg, 512, "setup secure channel failure, status = STATUS_ERROR_SECURE_CHANNEL"); + goto loser; + } + + rc = channel->ExternalAuthenticate(); + if (rc != 1) { + RA::Error("RA_Pin_Reset_Processor::Process", + "External authentication in secure channel failed"); + status = STATUS_ERROR_EXTERNAL_AUTH; + PR_snprintf(audit_msg, 512, "External authentication in secure channel failed, status = STATUS_ERROR_EXTERNAL_AUTH"); + goto loser; + } + + PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.requiredVersion", OP_PREFIX, tokenType); + int v = RA::GetConfigStore()->GetConfigAsInt(configname, 0x00); + Buffer curKeyInfo = channel->GetKeyInfoData(); + BYTE nv[2] = { v, 0x01 }; + Buffer newVersion(nv, 2); + PR_snprintf((char *)configname, 256,"%s.%s.tks.conn", OP_PREFIX, tokenType); + connid = RA::GetConfigStore()->GetConfigAsString(configname); + rc = CreateKeySetData( + channel->GetKeyDiversificationData(), + curKeyInfo, + newVersion, + key_data_set, connid); + if (rc != 1) { + RA::Error("RA_Pin_Reset_Processor::Process", + "failed to create new key set"); + status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512, "failed to create new key set, status = STATUS_ERROR_CREATE_CARDMGR"); + goto loser; + } + + + BYTE curVersion = ((BYTE*)curKeyInfo)[0]; + BYTE curIndex = ((BYTE*)curKeyInfo)[1]; + rc = channel->PutKeys(session, + curVersion, + curIndex, + &key_data_set); + + curKeyInfoStr = Util::Buffer2String(curKeyInfo); + newVersionStr = Util::Buffer2String(newVersion); + + if(curKeyInfoStr != NULL && strlen(curKeyInfoStr) >= 2) { + curVer[0] = curKeyInfoStr[0]; curVer[1] = curKeyInfoStr[1]; curVer[2] = 0; + } + else { + curVer[0] = 0; + } + + if(newVersionStr != NULL && strlen(newVersionStr) >= 2) { + newVer[0] = newVersionStr[0] ; newVer[1] = newVersionStr[1] ; newVer[2] = 0; + } + else { + newVer[0] = 0; + } + + if (rc!=0) { + RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER, + userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "Failure", "pin_reset", + final_applet_version != NULL ? final_applet_version : "", curVer, newVer, + "key changeover failed"); + } + + SelectApplet(session, 0x04, 0x00, NetKeyAID); + PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.requiredVersion", OP_PREFIX, tokenType); + if( channel != NULL ) { + delete channel; + channel = NULL; + } + + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + connId = RA::GetConfigStore()->GetConfigAsString(configname); + channel = SetupSecureChannel(session, + RA::GetConfigStore()->GetConfigAsInt(configname, 0x00), + 0x00 /* default key index */, connId); + if (channel == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", + "setup secure channel failure"); + status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512, "setup secure channel failure, status = STATUS_ERROR_CREATE_CARDMGR"); + goto loser; + } + + RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER, + userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "Success", "pin_reset", + final_applet_version != NULL ? final_applet_version : "", curVer, newVer, + "key changeover"); + key_change_over_success = 1; + } else { key_change_over_success = 1; } + } else { + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + connId = RA::GetConfigStore()->GetConfigAsString(configname); + if( channel != NULL ) { + delete channel; + channel = NULL; + } + channel = SetupSecureChannel(session, + 0x00, + 0x00 /* default key index */, connId); + } + + /* we should have a good channel here */ + if (channel == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", + "no channel creation failure"); + status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512, "no channel creation failure, status = STATUS_ERROR_CREATE_CARDMGR"); + goto loser; + } + + if (channel != NULL) { + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + keyVersion = Util::Buffer2String(channel->GetKeyInfoData()); + } + + PR_snprintf((char *)configname, 256, "%s.%s.loginRequest.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 1)) { + if (extensions != NULL && + extensions->GetValue("extendedLoginRequest") != NULL) + { + RA::Debug("RA_Enroll_Processor::RequestUserId", + "Extended Login Request detected"); + AuthenticationEntry *entry = GetAuthenticationEntry( + OP_PREFIX, configname, tokenType); + char **params = NULL; + char pb[1024]; + char *locale = NULL; + if (extensions != NULL && + extensions->GetValue("locale") != NULL) + { + locale = extensions->GetValue("locale"); + } else { + locale = ( char * ) "en"; /* default to english */ + } + int n = entry->GetAuthentication()->GetNumOfParamNames(); + if (n > 0) { + RA::Debug("RA_Enroll_Processor::RequestUserId", + "Extended Login Request detected n=%d", n); + params = (char **) PR_Malloc(n); + for (int i = 0; i < n; i++) { + sprintf(pb,"id=%s&name=%s&desc=%s&type=%s&option=%s", + entry->GetAuthentication()->GetParamID(i), + entry->GetAuthentication()->GetParamName(i, locale), + entry->GetAuthentication()->GetParamDescription(i, +locale), + entry->GetAuthentication()->GetParamType(i), + entry->GetAuthentication()->GetParamOption(i) + ); + params[i] = PL_strdup(pb); + RA::Debug("RA_Enroll_Processor::RequestUserId", + "params[i]=%s", params[i]); + } + } + RA::Debug("RA_Enroll_Processor::RequestUserId", "Extended Login Request detected calling RequestExtendedLogin() locale=%s", locale); + + char *title = PL_strdup(entry->GetAuthentication()->GetTitle(locale)); + RA::Debug("RA_Enroll_Processor::RequestUserId", "title=%s", title); + char *description = PL_strdup(entry->GetAuthentication()->GetDescription(locale)); + RA::Debug("RA_Enroll_Processor::RequestUserId", "description=%s", description); + login = RequestExtendedLogin(session, 0 /* invalid_pw */, 0 /* blocked */, params, n, title, description); + + RA::Debug("RA_Enroll_Processor::RequestUserId", + "Extended Login Request detected calling RequestExtendedLogin() login=%x", login); + + if (params != NULL) { + for (int nn=0; nn < n; nn++) { + if (params[nn] != NULL) { + PL_strfree(params[nn]); + params[nn] = NULL; + } + } + free(params); + params = NULL; + } + + if (title != NULL) { + PL_strfree(title); + title = NULL; + } + + if (description != NULL) { + PL_strfree(description); + description = NULL; + } + + } else { + login = RequestLogin(session, 0 /* invalid_pw */, 0 /* blocked */); + } + if (login == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", + "login not provided"); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "login not provided, status = STATUS_ERROR_LOGIN"); + + goto loser; + } + if( userid != NULL ) { + PR_Free( (char *) userid ); + userid = NULL; + } + userid = PL_strdup( login->GetUID() ); + } + + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 30 /* progress */, + "PROGRESS_START_AUTHENTICATION"); + } + + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "pin_reset", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "userid obtained"); + + PR_snprintf(configname, 256, "cn=%s", cuid); + rc = RA::ra_find_tus_token_entries(configname, maxReturns, &ldapResult, 0); + + if (rc == 0) { + for (e = RA::ra_get_first_entry(ldapResult); e != NULL; + e = RA::ra_get_next_entry(e)) { + tokenOwner = RA::ra_get_attribute_values(e, "tokenUserID"); + if ((tokenOwner != NULL) && (tokenOwner[0] != NULL) && + (tokenOwner[0]->bv_val != NULL) && (strlen(tokenOwner[0]->bv_val) > 0) && + (strcmp(userid, tokenOwner[0]->bv_val) != 0)) { + status = STATUS_ERROR_NOT_TOKEN_OWNER; + PR_snprintf(audit_msg, 512, "token owner mismatch, status = STATUS_ERROR_NOT_TOKEN_OWNER"); + goto loser; + } + } + } else { + RA::Error("RA_Pin_Reset_Processor::Process", "Error in ldap connection with token database."); + status = STATUS_ERROR_LDAP_CONN; + PR_snprintf(audit_msg, 512, "Error in ldap connection with token database, status = STATUS_ERROR_LDAP_CONN"); + goto loser; + } + + PR_snprintf((char *)configname, 256, "%s.%s.auth.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, false)) { + if (login == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", "Login Request Disabled. Authentication failed."); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "Login Request Disabled. status = STATUS_ERROR_LOGIN"); + goto loser; + } + + + PR_snprintf((char *)configname, 256, "%s.%s.auth.id", OP_PREFIX, tokenType); + authid = RA::GetConfigStore()->GetConfigAsString(configname); + if (authid == NULL) { + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "authid is null, status = STATUS_ERROR_LOGIN"); + goto loser; + } + AuthenticationEntry *auth = RA::GetAuth(authid); + + if(auth == NULL) + { + RA::Error("RA_Pin_Reset_Processor::Process", "Authentication manager is NULL . Authentication failed."); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "Authentication manager is NULL, status = STATUS_ERROR_LOGIN"); + goto loser; + } + + char *type = auth->GetType(); + if (type == NULL) { + status = STATUS_ERROR_LOGIN; + RA::tdb_activity(session->GetRemoteIP(), cuid, "enrollment", "failure", "authentication is missing param type", "", tokenType); + PR_snprintf(audit_msg, 512, "authentication is missing param type, status = STATUS_ERROR_LOGIN"); + goto loser; + } + if (strcmp(type, "LDAP_Authentication") == 0) { + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "LDAP_Authentication is invoked."); + int passwd_retries = auth->GetAuthentication()->GetNumOfRetries(); + int retries = 0; + authParams = new AuthParams(); + authParams->SetUID(login->GetUID()); + authParams->SetPassword(login->GetPassword()); + rc = auth->GetAuthentication()->Authenticate(authParams); + + RA::Debug("RA_Pin_Reset_Processor::Process", + "Authenticate returns: %d", rc); + + while ((rc == -2 || rc == -3) && (retries < passwd_retries)) { + login = RequestLogin(session, 0 /* invalid_pw */, 0 /* blocked */); + if (login == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", "Login Request Disabled. Authentication failed."); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "Login Request Disabled, r=-2 or -3. status= STATUS_ERROR_LOGIN"); + goto loser; + } + retries++; + authParams->SetUID(login->GetUID()); + authParams->SetPassword(login->GetPassword()); + rc = auth->GetAuthentication()->Authenticate(authParams); + } + + if (rc == -1) { + RA::Error("RA_Pin_Reset_Processor::Process", "Authentication failed."); + status = STATUS_ERROR_LDAP_CONN; + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", "Authentication status = %d", status); + PR_snprintf(audit_msg, 512, "authentication failed, rc=-1, status = STATUS_ERROR_LDAP_CONN"); + goto loser; + } + + if (rc == -2 || rc == -3) { + RA::Error("RA_Pin_Reset_Processor::Process", "Authentication failed."); + status = STATUS_ERROR_LOGIN; + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", "Authentication status = %d", status); + PR_snprintf(audit_msg, 512, "authentication failed, rc=-2 or rc=-3, status = STATUS_ERROR_LOGIN"); + goto loser; + } + + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", "Authentication successful."); + } else { + RA::Error("RA_Pin_Reset_Processor::Process", "No Authentication type was found."); + status = STATUS_ERROR_LOGIN; + RA::tdb_activity(session->GetRemoteIP(), cuid, "enrollment", "failure", "authentication error", "", tokenType); + PR_snprintf(audit_msg, 512, "No Authentication type was found. status = STATUS_ERROR_LOGIN"); + goto loser; + } + } else { + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "Authentication has been disabled."); + } + + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "pin_reset", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "authentication successful"); + + + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "SetupSecureChannel"); + +#if 0 + if (RA::GetConfigStore()->GetConfigAsBool("tus.enable", 0)) { + if (IsTokenDisabledByTus(channel)) { + status = STATUS_ERROR_TOKEN_DISABLED; + goto loser; + } + } +#endif + + /* check if the user owns the token */ + token_userid = RA::ra_get_token_userid(cuid); + if (token_userid == NULL) { + RA::Error(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "No user owns the token '%s'", cuid); + status = STATUS_ERROR_TOKEN_DISABLED; + PR_snprintf(audit_msg, 512, "No user owns the token, status = STATUS_ERROR_TOKEN_DISABLED"); + goto loser; + } else { + if (strcmp(token_userid, userid) != 0) { + RA::Error(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "User does not own the token '%s'", cuid); + status = STATUS_ERROR_TOKEN_DISABLED; + PR_snprintf(audit_msg, 512, "User does not own the token. status = STATUS_ERROR_TOKEN_DISABLED"); + goto loser; + } + } + + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "pin_reset", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "login successful"); + + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "ExternalAuthenticate"); + rc = channel->ExternalAuthenticate(); + if (rc == -1) { + RA::Error("RA_Pin_Reset_Processor::Process", + "External Authenticate failed."); + status = STATUS_ERROR_CREATE_CARDMGR; + RA::tdb_activity(session->GetRemoteIP(), cuid, "pin reset", "failure", "external authentication error", "", tokenType); + PR_snprintf(audit_msg, 512, "External Authenticate failed, status = STATUS_ERROR_CREATE_CARDMGR"); + goto loser; + } + RA::Debug(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "RequestNewPin"); + PR_snprintf((char *)configname, 256, "%s.%s.pinReset.pin.minLen", OP_PREFIX, tokenType); + minlen = RA::GetConfigStore()->GetConfigAsUnsignedInt(configname, 4); + PR_snprintf((char *)configname, 256, "%s.%s.pinReset.pin.maxLen", OP_PREFIX, tokenType); + maxlen = RA::GetConfigStore()->GetConfigAsUnsignedInt(configname, 10); + new_pin = RequestNewPin(session, minlen, maxlen); + if (new_pin == NULL) { + RA::Error("RA_Pin_Reset_Processor::Process", + "Set Pin failed."); + status = STATUS_ERROR_MAC_RESET_PIN_PDU; + RA::tdb_activity(session->GetRemoteIP(), cuid, "pin reset", "failure", "request new pin error", "", tokenType); + PR_snprintf(audit_msg, 512, "RequestNewPin failed, status = STATUS_ERROR_MAC_RESET_PIN_PDU"); + goto loser; + } + + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 70 /* progress */, + "PROGRESS_PIN_RESET"); + } + + rc = channel->ResetPin(0x0, new_pin); + if (rc == -1) { + status = STATUS_ERROR_MAC_RESET_PIN_PDU; + RA::tdb_activity(session->GetRemoteIP(), cuid, "pin reset", "failure", "ereset pin error", "", tokenType); + PR_snprintf(audit_msg, 512, "ResetPin failed, status = STATUS_ERROR_MAC_RESET_PIN_PDU"); + goto loser; + } + + rc = channel->Close(); + if (rc == -1) { + RA::Error("RA_Pin_Reset_Processor::Process", + "Failed to close channel"); + status = STATUS_ERROR_CONNECTION; + RA::tdb_activity(session->GetRemoteIP(), cuid, "pin reset", "failure", "secure channel close error", "", tokenType); + PR_snprintf(audit_msg, 512, "Failed to close channel, status = STATUS_ERROR_CONNECTION"); + goto loser; + } + + + //Update the KeyInfo in case of successful key changeover + if (key_change_over_success != 0) { + RA::tdb_update( userid != NULL ? userid : (char *) "", + cuid != NULL ? cuid : (char *) "" , + final_applet_version != NULL ? (char *) final_applet_version : (char *) "" , + keyVersion != NULL ? keyVersion : (char *) "","active", "", + tokenType != NULL ? tokenType : (char *) ""); + } + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "pin_reset", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "ResetPin successful"); + + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 100 /* progress */, + "PROGRESS_DONE"); + } + + end = PR_IntervalNow(); + + rc = 1; + + if (RA::ra_is_token_present(cuid)) { + /* + * we want to have a tus policy to change PIN_RESET=YES + * parameter to PIN_RESET=NO + */ + if (RA::ra_is_token_pin_resetable(cuid)) { + policy = RA::ra_get_token_policy(cuid); + RA::Error("RA_Pin_Reset_Processor::Process", + "Policy %s is %s", cuid, policy); + tmp_policy = PL_strstr(policy, "PIN_RESET=YES"); + if (tmp_policy != NULL) { + tmp_policy[10] = 'N'; + tmp_policy[11] = 'O'; + for (i = 12; tmp_policy[i] != '\0'; i++) + tmp_policy[i] = tmp_policy[i+1]; + rc = RA::ra_update_token_policy(cuid, policy); + if (rc != 0) { + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "failure", + "pin_reset", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "failed to reset token policy"); + } + } + } + } + + sprintf(activity_msg, "applet_version=%s tokenType=%s", + (char *)final_applet_version, tokenType); + RA::tdb_activity(session->GetRemoteIP(), (char *)cuid, "pin reset", "success", activity_msg, userid, tokenType); + + /* audit log for successful pin reset */ + if (authid != NULL) { + sprintf(activity_msg, "pin_reset processing completed, authid = %s", authid); + } else { + sprintf(activity_msg, "pin_reset processing completed"); + } + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid, cuid, msn, "success", "pin_reset", final_applet_version, keyVersion!=NULL? keyVersion: "", activity_msg); + +loser: + if (strlen(audit_msg) > 0) { + RA::Audit(EV_PIN_RESET, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "failure", + "pin_reset", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + audit_msg); + + if ((cuid != NULL) && (tokenType != NULL)) { + RA::tdb_activity(session->GetRemoteIP(), + cuid, + "pin_reset", + "failure", + audit_msg, + userid != NULL ? userid : "", + tokenType); + } + } + + if (curKeyInfoStr != NULL) { + PR_Free( (char *) curKeyInfoStr); + curKeyInfoStr = NULL; + } + + if (newVersionStr != NULL) { + PR_Free( (char *) newVersionStr); + newVersionStr = NULL; + } + + if( token_status != NULL ) { + delete token_status; + token_status = NULL; + } + if( CardManagerAID != NULL ) { + delete CardManagerAID; + CardManagerAID = NULL; + } + if( NetKeyAID != NULL ) { + delete NetKeyAID; + NetKeyAID = NULL; + } + if( login != NULL ) { + delete login; + login = NULL; + } + if( new_pin != NULL ) { + PL_strfree( new_pin ); + new_pin = NULL; + } + if( channel != NULL ) { + delete channel; + channel = NULL; + } + if( cuid != NULL ) { + PR_Free( (char *) cuid ); + cuid = NULL; + } + if( msn != NULL ) { + PR_Free( (char *) msn ); + msn = NULL; + } + if( buildID != NULL ) { + delete buildID; + buildID = NULL; + } + if( appletVersion != NULL ) { + PR_Free( (char *) appletVersion ); + appletVersion = NULL; + } + if( final_applet_version != NULL ) { + PR_Free( (char *) final_applet_version ); + final_applet_version = NULL; + } + if( keyVersion != NULL ) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + if( userid != NULL ) { + PR_Free( (char *) userid ); + userid = NULL; + } + if( authParams != NULL ) { + delete authParams; + authParams = NULL; + } + if( cplc_data != NULL ) { + delete cplc_data; + cplc_data = NULL; + } + + if (tokenOwner != NULL) { + ldap_value_free_len(tokenOwner); + tokenOwner = NULL; + } + + if (ldapResult != NULL) { + ldap_msgfree(ldapResult); + ldapResult = NULL; + } + +#ifdef MEM_PROFILING + MEM_dump_unfree(); +#endif + + return status; +} /* Process */ diff --git a/base/tps/src/processor/RA_Processor.cpp b/base/tps/src/processor/RA_Processor.cpp new file mode 100644 index 000000000..a9947555b --- /dev/null +++ b/base/tps/src/processor/RA_Processor.cpp @@ -0,0 +1,3506 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "plstr.h" +#include "engine/RA.h" +#include "main/Buffer.h" +#include "main/Base.h" +#include "main/Util.h" +#include "main/RA_Session.h" +#include "main/RA_Msg.h" +#include "main/Login.h" +#include "main/SecureId.h" +#include "main/Util.h" +#include "httpClient/httpc/http.h" +#include "httpClient/httpc/request.h" +#include "httpClient/httpc/response.h" +#include "httpClient/httpc/engine.h" +#include "processor/RA_Processor.h" +#include "cms/HttpConnection.h" +#include "cms/CertEnroll.h" +#include "msg/RA_Status_Update_Request_Msg.h" +#include "msg/RA_Status_Update_Response_Msg.h" +#include "msg/RA_Login_Request_Msg.h" +#include "msg/RA_Login_Response_Msg.h" +#include "msg/RA_Extended_Login_Request_Msg.h" +#include "msg/RA_Extended_Login_Response_Msg.h" +#include "msg/RA_ASQ_Request_Msg.h" +#include "msg/RA_ASQ_Response_Msg.h" +#include "msg/RA_New_Pin_Request_Msg.h" +#include "msg/RA_New_Pin_Response_Msg.h" +#include "msg/RA_SecureId_Request_Msg.h" +#include "msg/RA_SecureId_Response_Msg.h" +#include "msg/RA_Token_PDU_Request_Msg.h" +#include "msg/RA_Token_PDU_Response_Msg.h" +#include "apdu/Lifecycle_APDU.h" +#include "apdu/Format_Muscle_Applet_APDU.h" +#include "apdu/Initialize_Update_APDU.h" +#include "apdu/Get_Version_APDU.h" +#include "apdu/External_Authenticate_APDU.h" +#include "apdu/Create_Object_APDU.h" +#include "apdu/Get_Status_APDU.h" +#include "apdu/Get_Data_APDU.h" +#include "apdu/Set_Pin_APDU.h" +#include "apdu/Read_Buffer_APDU.h" +#include "apdu/Write_Object_APDU.h" +#include "apdu/List_Objects_APDU.h" +#include "apdu/Generate_Key_APDU.h" +#include "apdu/List_Pins_APDU.h" +#include "apdu/Create_Pin_APDU.h" +#include "apdu/Put_Key_APDU.h" +#include "apdu/Select_APDU.h" +#include "apdu/APDU_Response.h" +#include "channel/Secure_Channel.h" +#include "main/Memory.h" + +#if 0 +#ifdef __cplusplus +extern "C" +{ +#endif +#include "tus/tus_db.h" +#ifdef __cplusplus +} +#endif +#endif + +/** + * Constructs a base processor. + */ +RA_Processor::RA_Processor () +{ + totalAvailableMemory = 0; + totalFreeMemory = 0; +} + + +/** + * Destructs processor. + */ +RA_Processor::~RA_Processor () +{ +} + +AuthenticationEntry *RA_Processor::GetAuthenticationEntry( + const char *prefix, const char * a_configname, const char *a_tokenType) +{ + AuthenticationEntry *auth = NULL; + + if (!RA::GetConfigStore()->GetConfigAsBool(a_configname, false)) + return NULL; + + RA::Debug("RA_Enroll_Processor::AuthenticateUser", + "Authentication enabled"); + char configname[256]; + PR_snprintf((char *)configname, 256, "%s.%s.auth.id", prefix, a_tokenType); + const char *authid = RA::GetConfigStore()->GetConfigAsString(configname); + if (authid == NULL) { + goto loser; + } + auth = RA::GetAuth(authid); + return auth; +loser: + return NULL; +} + + +void RA_Processor::StatusUpdate(RA_Session *a_session, + NameValueSet *a_extensions, + int a_status, const char *a_info) +{ + if (a_extensions != NULL) { + if (a_extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(a_session, a_status, a_info); + } + } +} + +void RA_Processor::StatusUpdate(RA_Session *session, + int status, const char *info) +{ + RA_Status_Update_Request_Msg *status_update_request_msg = NULL; + RA_Status_Update_Response_Msg *status_update_response_msg = NULL; + + RA::Debug(LL_PER_PDU, "RA_Processor::StatusUpdate", + "RA_Processor::StatusUpdate"); + + status_update_request_msg = new RA_Status_Update_Request_Msg( + status, info); + session->WriteMsg(status_update_request_msg); + + RA::Debug(LL_PER_PDU, "RA_Processor::StatusUpdate", + "Sent status_update_msg"); + + status_update_response_msg = (RA_Status_Update_Response_Msg *) + session->ReadMsg(); + if (status_update_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::StatusUpdate", + "No Status Update Response Msg Received"); + goto loser; + } + if (status_update_response_msg->GetType() != MSG_STATUS_UPDATE_RESPONSE) { + RA::Error("Secure_Channel::StatusUpdate", + "Invalid Msg Type"); + goto loser; + } + +loser: + if( status_update_request_msg != NULL ) { + delete status_update_request_msg; + status_update_request_msg = NULL; + } + if( status_update_response_msg != NULL ) { + delete status_update_response_msg; + status_update_response_msg = NULL; + } + +} /* StatusUpdate */ + +/** + * Requests login ID and password from user. + */ +AuthParams *RA_Processor::RequestExtendedLogin(RA_Session *session, + int invalid_pw, int blocked, + char **parameters, int len, char *title, char *description) +{ + RA_Extended_Login_Request_Msg *login_request_msg = NULL; + RA_Extended_Login_Response_Msg *login_response_msg = NULL; + AuthParams *login = NULL; + AuthParams *c = NULL; + int i = 0; + + RA::Debug(LL_PER_PDU, "RA_Processor::RequestExtendedLogin", + "RA_Processor::RequestExtendedLogin %s %s", + title, description); + + login_request_msg = new RA_Extended_Login_Request_Msg( + invalid_pw, blocked, parameters, len, title, description); + session->WriteMsg(login_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::RequestExtendedLogin", + "Sent login_request_msg"); + + login_response_msg = (RA_Extended_Login_Response_Msg *) + session->ReadMsg(); + if (login_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::RequestExtendedLogin", + "No Extended Login Response Msg Received"); + goto loser; + } + if (login_response_msg->GetType() != MSG_EXTENDED_LOGIN_RESPONSE) { + RA::Error("Secure_Channel::Login_Request", + "Invalid Msg Type"); + goto loser; + } + + login = new AuthParams(); + c = login_response_msg->GetAuthParams(); + for (i = 0; i < c->Size(); i++) { + login->Add(c->GetNameAt(i), c->GetValue(c->GetNameAt(i))); + } + +loser: + if( login_request_msg != NULL ) { + delete login_request_msg; + login_request_msg = NULL; + } + if( login_response_msg != NULL ) { + delete login_response_msg; + login_response_msg = NULL; + } + + return login; +} /* RequestExtendedLogin */ + +/** + * Requests login ID and password from user. + */ +AuthParams *RA_Processor::RequestLogin(RA_Session *session, + int invalid_pw, int blocked) +{ + RA_Login_Request_Msg *login_request_msg = NULL; + RA_Login_Response_Msg *login_response_msg = NULL; + AuthParams *login = NULL; + + RA::Debug(LL_PER_PDU, "RA_Processor::Login_Request", + "RA_Processor::Login_Request"); + + login_request_msg = new RA_Login_Request_Msg( + invalid_pw, blocked); + session->WriteMsg(login_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::Login_Request", + "Sent login_request_msg"); + + login_response_msg = (RA_Login_Response_Msg *) + session->ReadMsg(); + if (login_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::Login_Request", + "No Login Response Msg Received"); + goto loser; + } + if (login_response_msg->GetType() != MSG_LOGIN_RESPONSE) { + RA::Error("Secure_Channel::Login_Request", + "Invalid Msg Type"); + goto loser; + } + login = new AuthParams(); + login->Add("UID", login_response_msg->GetUID()); + login->Add("PASSWORD", login_response_msg->GetPassword()); + +loser: + if( login_request_msg != NULL ) { + delete login_request_msg; + login_request_msg = NULL; + } + if( login_response_msg != NULL ) { + delete login_response_msg; + login_response_msg = NULL; + } + + return login; +} /* RequestLogin */ + +/** + * Upgrade the applet to the current session with the new version. + */ +int RA_Processor::UpgradeApplet(RA_Session *session, char *prefix, char *tokenType, BYTE major_version, BYTE minor_version, const char *new_version, const char *applet_dir, SecurityLevel security_level, const char *connid, + NameValueSet *extensions, + int start_progress, + int end_progress, + char **key_version) +{ + Buffer *NetKeyAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_NETKEY_INSTANCE_AID, + RA::CFG_DEF_NETKEY_INSTANCE_AID); + Buffer *OldAAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_NETKEY_OLD_INSTANCE_AID, + RA::CFG_DEF_NETKEY_OLD_INSTANCE_AID); + Buffer *OldPAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_NETKEY_OLD_FILE_AID, + RA::CFG_DEF_NETKEY_OLD_FILE_AID); + Buffer *NetKeyPAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_NETKEY_FILE_AID, + RA::CFG_DEF_NETKEY_FILE_AID); + Buffer *PIN = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_SO_PIN, + RA::CFG_DEF_APPLET_SO_PIN); + Buffer empty; + PRFileDesc *f = NULL; + char path[4096]; + char configname[4096]; + PRFileInfo info; + PRStatus status; + int rc = 0; + Secure_Channel *channel = NULL; + int size_to_send = 0; + char *dataf = NULL; + int block_size; + BYTE refControl; + int count; + Buffer programFile; + Buffer tag; + Buffer length; + Buffer tbsProgramFile; + unsigned int totalLen; + int num_loops; + float progress_block_size; + int x_blocksize; + int instance_size; + int applet_memory_size; + int defKeyVer; + int defKeyIndex; + char *ext; + + if (applet_dir == NULL) { + RA::Error(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "Failed to get upgrade.directory"); + goto loser; + } + sprintf(configname, "general.applet_ext"); + ext = (char*)RA::GetConfigStore()->GetConfigAsString(configname, "ijc"); + sprintf(path, "%s/%s.%s", applet_dir, new_version, ext); + RA::Debug("RA_Processor::UpgradeApplet", "path = %s", path); + status = PR_GetFileInfo(path, &info); + if (status != PR_SUCCESS) { + RA::Error(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "Failed to get file info"); + goto loser; + } + f = PR_Open(path, PR_RDONLY, 400); + if (f == NULL) { + RA::Error(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "Failed to open '%s'", path); + goto loser; + } + dataf = (char *)malloc(info.size); + PR_Read(f, dataf, info.size); + if( f != NULL ) { + PR_Close( f ); + f = NULL; + } + + /* Select Applet - Select Card manager */ + SelectCardManager(session, prefix, tokenType); + + PR_snprintf((char *)configname, 256,"channel.blockSize"); + x_blocksize = RA::GetConfigStore()->GetConfigAsInt(configname, 0xf8); + PR_snprintf((char *)configname, 256,"channel.instanceSize"); + instance_size = RA::GetConfigStore()->GetConfigAsInt(configname, 18000); + + PR_snprintf((char *)configname, 256,"channel.appletMemorySize"); + + applet_memory_size = RA::GetConfigStore()->GetConfigAsInt(configname, 5000); + + PR_snprintf((char *)configname, 256,"channel.defKeyVersion"); + defKeyVer = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + PR_snprintf((char *)configname, 256,"channel.defKeyIndex"); + defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + channel = SetupSecureChannel(session, defKeyVer, defKeyIndex, security_level, connid); + if (channel == NULL) { + RA::Error(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "channel creation failure"); + rc = -1; + goto loser; + } + + // get keyVersion + if (channel != NULL) { + *key_version = Util::Buffer2String(channel->GetKeyInfoData()); + } + + if (channel->ExternalAuthenticate() == -1) { + RA::Error(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "failed to external authenticate during upgrade"); + goto loser; + } + + /* Delete File - Delete 627601ff000000 (CoolKey Instance) */ + rc = channel->DeleteFileX(session, NetKeyAID); + if (rc != 1) { + /* it is ok to fail to delete file */ + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "Warning: failed to delete file", NetKeyAID); + } + + if (RA::GetConfigStore()->GetConfigAsBool(RA::CFG_APPLET_DELETE_NETKEY_OLD, true)) { + /* Delete File - Delete a00000000101 */ + rc = channel->DeleteFileX(session, OldAAID); + if (rc != 1) { + /* it is ok to fail to delete file */ + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "Warning: failed to delete file", OldAAID); + } + /* Delete File - Delete a000000001 */ + rc = channel->DeleteFileX(session, OldPAID); + if (rc != 1) { + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::UpgradeApplet", + "Warning: failed to delete file", OldPAID); + } + } + + /* Delete File - Delete 627601ff0000 */ + channel->DeleteFileX(session, NetKeyPAID); + + /* Install Applet - Install applet instance */ + channel->InstallLoad(session, + *NetKeyPAID, + empty, + info.size); + + /* Multiple Load Program File - Load 627601ff0000 */ + programFile = Buffer ((BYTE *)dataf, info.size); + if( dataf != NULL ) { + free( dataf ); + dataf = NULL; + } + tag = Buffer(1, 0xC4); + tbsProgramFile = tag + length + programFile; + totalLen = tbsProgramFile.size(); + if( programFile.size() < 128 ) { + length = Buffer(1, programFile.size()); + } else if( programFile.size() <= 255 ) { + length = Buffer(2, 0); + ((BYTE*)length)[0] = 0x81; + ((BYTE*)length)[1] = programFile.size(); + } else { + length = Buffer(3, 0); + ((BYTE*)length)[0] = 0x82; + ((BYTE*)length)[1] = (programFile.size() >> 8) & 0xff; + ((BYTE*)length)[2] = programFile.size() & 0xff; + } + tbsProgramFile = tag + length + programFile; + totalLen = tbsProgramFile.size(); + + size_to_send = totalLen; + if (security_level == SECURE_MSG_MAC_ENC) { + // need leave room for possible encryption padding + block_size = x_blocksize - 0x10; + } else { + block_size = x_blocksize - 8; + } + + // rough number is good enough + num_loops = size_to_send / block_size; + progress_block_size = (float) (end_progress - start_progress) / num_loops; + + count = 0; + refControl = 0x00; // intermediate block + do { + if (size_to_send < block_size) { + block_size = size_to_send; + // last block + refControl = 0x80; + } + if (size_to_send - block_size == 0) { + // last block + refControl = 0x80; + } + Buffer d = tbsProgramFile.substr(totalLen - size_to_send, block_size); + channel->LoadFile(session, (BYTE)refControl, (BYTE)count, &d); + + size_to_send -= block_size; + + // send status update to the client + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, + start_progress + (count * progress_block_size) /* progress */, + "PROGRESS_APPLET_BLOCK"); + } + count++; + } while (size_to_send > 0); + + + /* Install Applet - Install applet instance */ + channel->InstallApplet(session, + *NetKeyPAID, + *NetKeyAID, + 0 /* appPrivileges */, + instance_size /* instanceSize */, + applet_memory_size /* appletMemorySize */); + + /* Select File - Select 627601ff000000 */ + SelectApplet(session, 0x04, 0x00, NetKeyAID); + + rc = 1; +loser: + if( NetKeyAID != NULL ) { + delete NetKeyAID; + NetKeyAID = NULL; + } + if( OldAAID != NULL ) { + delete OldAAID; + OldAAID = NULL; + } + if( OldPAID != NULL ) { + delete OldPAID; + OldPAID = NULL; + } + if( NetKeyPAID != NULL ) { + delete NetKeyPAID; + NetKeyPAID = NULL; + } + if( PIN != NULL ) { + delete PIN; + PIN = NULL; + } + if( channel != NULL ) { + delete channel; + channel = NULL; + } + if( dataf != NULL ) { + free( dataf ); + dataf = NULL; + } + + return rc; +} + +char *RA_Processor::MapPattern(NameValueSet *nv, char *pattern) +{ + int i=0,x=0,j=0,z=0; + unsigned int q = 0; + char token[4096]; + char result[4096]; + char *value; + + if (pattern == NULL) + return NULL; + i = strlen(pattern); + for (x = 0; x < i; x++) { + if (pattern[x] == '$') { + if (pattern[x+1] == '$') { + result[z] = pattern[x]; + z++; + x++; + } else { + x++; + j = 0; + while (pattern[x] != '$') { + token[j] = pattern[x]; + j++; + x++; + } + token[j] = '\0'; + value = nv->GetValue(token); + if (value != NULL) { + for (q = 0; q < strlen(value); q++) { + result[z] = value[q]; + z++; + } + + } + } + } else { + result[z] = pattern[x]; + z++; + } + } + result[z] = '\0'; + + return PL_strdup(result); +} + +int RA_Processor::FormatMuscleApplet(RA_Session *session, + unsigned short memSize, + Buffer &PIN0, BYTE pin0Tries, + Buffer &unblockPIN0, BYTE unblock0Tries, + Buffer &PIN1, BYTE pin1Tries, + Buffer &unblockPIN1, BYTE unblock1Tries, + unsigned short objCreationPermissions, + unsigned short keyCreationPermissions, + unsigned short pinCreationPermissions) +{ + int rc = 0; + APDU_Response *format_response = NULL; + RA_Token_PDU_Request_Msg *format_request_msg = NULL; + RA_Token_PDU_Response_Msg *format_response_msg = NULL; + Format_Muscle_Applet_APDU *format_apdu = NULL; + // Buffer *mac = NULL; + + RA::Debug(LL_PER_PDU, "RA_Processor::FormatMuscle", + "RA_Processor::FormatMuscle"); + + format_apdu = new Format_Muscle_Applet_APDU(memSize, PIN0, pin0Tries, + unblockPIN0, unblock0Tries, + PIN1, pin1Tries, + unblockPIN1, unblock1Tries, + objCreationPermissions, + keyCreationPermissions, + pinCreationPermissions); + format_request_msg = + new RA_Token_PDU_Request_Msg(format_apdu); + session->WriteMsg(format_request_msg); + + RA::Debug(LL_PER_PDU, "RA_Processor::FormatMuscle", + "Sent format_request_msg"); + + format_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (format_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::FormatMuscle", + "No Token PDU Response Msg Received"); + goto loser; + } + if (format_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::FormatMuscle", + "Invalid Message Type"); + goto loser; + } + format_response = format_response_msg->GetResponse(); + if (!(format_response->GetSW1() == 0x90 && + format_response->GetSW2() == 0x00)) { + RA::Error(LL_PER_PDU, "RA_Processor::FormatMuscle", + "Bad Response"); + goto loser; + } + rc = 1; + +loser: + if( format_request_msg != NULL ) { + delete format_request_msg; + format_request_msg = NULL; + } + if( format_response_msg != NULL ) { + delete format_response_msg; + format_response_msg = NULL; + } + + return rc; +} + +/** + * Determine the Token Type. The user can set up mapping rules in the + * config file which allow different operations depending on the + * CUID, applet version, ATR, etc. + */ +bool RA_Processor::GetTokenType(const char *prefix, int major_version, int minor_version, const char *cuid, const char *msn, NameValueSet *extensions, + RA_Status &o_status /* out */, const char *&o_tokenType /* out */) +{ + const char *e_tokenATR = NULL; + const char *tokenATR = NULL; + const char *e_tokenType = NULL; + const char *tokenType = NULL; + const char *tokenCUIDStart = NULL; + const char *tokenCUIDEnd = NULL; + const char *targetTokenType = NULL; + const char *majorVersion = NULL; + const char *minorVersion = NULL; + const char *order = NULL; + char *order_x = NULL; + const char *mappingId = NULL; + char configname[256]; + int start_pos = 0, done = 0; + unsigned int end_pos = 0; + const char *cuid_x = NULL; + int rc=0; + + cuid_x = cuid; + + sprintf(configname, "%s.mapping.order", prefix); + order = RA::GetConfigStore()->GetConfigAsString(configname); + if (order == NULL) { + RA::Error("RA_Processor::GetTokenType", "Token type is not found"); + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND; + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "cannot find config ", configname); + return false; /* no mapping found */ + } + + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "Starting:"); + order_x = PL_strdup(order); + + start_pos = 0; + end_pos = 0; + done = 0; + while (1) + { + if (done) { + break; + } + end_pos = start_pos; + while ((end_pos < strlen(order)) && (order_x[end_pos] != ',')) { + end_pos++; + } + if (end_pos < strlen(order)) { + order_x[end_pos] = '\0'; + done = 0; + } else { + done = 1; + } + mappingId = &order_x[start_pos]; + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "mappingId='%s'", mappingId); + + start_pos = end_pos + 1; + + sprintf(configname, "%s.mapping.%s.target.tokenType", prefix, + mappingId); + targetTokenType = RA::GetConfigStore()->GetConfigAsString(configname); + + + if (targetTokenType == NULL) { + break; + } + sprintf(configname, "%s.mapping.%s.filter.tokenType", prefix, + mappingId); + tokenType = RA::GetConfigStore()->GetConfigAsString(configname); + + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "tokenType: %s",tokenType); + + if (tokenType != NULL && strlen(tokenType) > 0) { + if (extensions == NULL) { + continue; /* mapping not matched, next mapping */ + } + e_tokenType = extensions->GetValue("tokenType"); + if (e_tokenType == NULL) { + continue; /* mapping not matched, next mapping */ + } + if (strcmp(tokenType, e_tokenType) != 0) { + continue; /* mapping not matched, next mapping */ + } + } + sprintf(configname, "%s.mapping.%s.filter.tokenATR", prefix, + mappingId); + tokenATR = RA::GetConfigStore()->GetConfigAsString(configname); + if (tokenATR != NULL && strlen(tokenATR) > 0) { + if (extensions == NULL) { + continue; /* mapping not matched, next mapping */ + } + e_tokenATR = extensions->GetValue("tokenATR"); + if (e_tokenATR == NULL) { + continue; /* mapping not matched, next mapping */ + } + if (strcmp(tokenATR, e_tokenATR) != 0) { + continue; /* mapping not matched, next mapping */ + } + } + sprintf(configname, "%s.mapping.%s.filter.tokenCUID.start", prefix, + mappingId); + tokenCUIDStart = RA::GetConfigStore()->GetConfigAsString(configname); + if (tokenCUIDStart != NULL && strlen(tokenCUIDStart) > 0) { + if (cuid_x == NULL) { + continue; /* mapping not matched, next mapping */ + } + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "cuid_x=%s tokenCUIDStart=%s %d", cuid_x, tokenCUIDStart, + PL_strcasecmp(cuid_x, tokenCUIDStart)); + + if(strlen(tokenCUIDStart) != 20) + { + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "Invalid tokenCUIDStart: %s",tokenCUIDStart); + continue; + } + + char *pend = NULL; + rc = strtol((const char *) tokenCUIDStart, &pend, 16); + + if(*pend != '\0') + { + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "Invalid tokenCUIDStart: %s",tokenCUIDStart); + + continue; + } + + if (PL_strcasecmp(cuid_x, tokenCUIDStart) < 0) { + continue; /* mapping not matched, next mapping */ + } + } + sprintf(configname, "%s.mapping.%s.filter.tokenCUID.end", prefix, + mappingId); + tokenCUIDEnd = RA::GetConfigStore()->GetConfigAsString(configname); + if (tokenCUIDEnd != NULL && strlen(tokenCUIDEnd) > 0) { + if (cuid_x == NULL) { + continue; /* mapping not matched, next mapping */ + } + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "cuid_x=%s tokenCUIDEnd=%s %d", cuid_x, tokenCUIDEnd, + PL_strcasecmp(cuid_x, tokenCUIDEnd)); + + if(strlen(tokenCUIDEnd) != 20) + { + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "Invalid tokenCUIDEnd: %s",tokenCUIDEnd); + continue; + } + + char *pend = NULL; + rc = strtol((const char *) tokenCUIDEnd, &pend, 16); + + if(*pend != '\0') + { + + RA::Debug(LL_PER_PDU, "RA_Processor::GetTokenType", + "Invalid tokenCUIDEnd: %s",tokenCUIDEnd); + + continue; + } + + if (PL_strcasecmp(cuid_x, tokenCUIDEnd) > 0) { + continue; /* mapping not matched, next mapping */ + } + } + sprintf(configname, "%s.mapping.%s.filter.appletMajorVersion", + prefix, mappingId); + majorVersion = RA::GetConfigStore()->GetConfigAsString(configname); + if (majorVersion != NULL && strlen(majorVersion) > 0) { + if (major_version != atoi(majorVersion)) { + continue; /* mapping not matched, next mapping */ + } + } + sprintf(configname, "%s.mapping.%s.filter.appletMinorVersion", + prefix, mappingId); + minorVersion = RA::GetConfigStore()->GetConfigAsString(configname); + if (minorVersion != NULL && strlen(minorVersion) > 0) { + if (minor_version != atoi(minorVersion)) { + continue; /* mapping not matched, next mapping */ + } + } + + if( order_x != NULL ) { + PL_strfree( order_x ); + order_x = NULL; + } + RA::Debug("RA_Processor::GetTokenType", + "Selected Token type is '%s'", targetTokenType); + o_tokenType = targetTokenType; + return true; + } + + + if( order_x != NULL ) { + PL_strfree( order_x ); + order_x = NULL; + } + RA::Error("RA_Processor::GetTokenType", "Token type is not found"); + o_status = STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND; + + return false; +} + +int RA_Processor::SelectCardManager(RA_Session *session, char *prefix, char *tokenType) +{ + char configname[256]; + int rc; + PR_snprintf((char *)configname, 256, "%s.%s.cardmgr_instance", prefix, tokenType); + const char *cardmgr_instance = + RA::GetConfigStore()->GetConfigAsString(configname); + Buffer *CardManagerAID = RA::GetConfigStore()->GetConfigAsBuffer( + cardmgr_instance, RA::CFG_DEF_CARDMGR_INSTANCE_AID); + rc = SelectApplet(session, 0x04, 0x00, CardManagerAID); + if( CardManagerAID != NULL ) { + delete CardManagerAID; + CardManagerAID = NULL; + } + return rc; +} + +/** + * GetData + */ +Buffer *RA_Processor::GetData(RA_Session *session) +{ + Buffer data; + Buffer *status = NULL; + APDU_Response *get_data_response = NULL; + RA_Token_PDU_Request_Msg *get_data_request_msg = NULL; + RA_Token_PDU_Response_Msg *get_data_response_msg = NULL; + Get_Data_APDU *get_data_apdu = NULL; + Buffer get_status_data; + + get_data_apdu = + new Get_Data_APDU(); + get_data_request_msg = + new RA_Token_PDU_Request_Msg(get_data_apdu); + session->WriteMsg(get_data_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::GetData", + "Sent get_data_request_msg"); + + get_data_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (get_data_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::GetData", + "No Token PDU Response Msg Received"); + goto loser; + } + if (get_data_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::GetData", + "Invalid Message Type"); + goto loser; + } + get_data_response = + get_data_response_msg->GetResponse(); + if (get_data_response == NULL) { + RA::Error(LL_PER_PDU, "Secure_Channel::GetData", + "No Response From Token"); + goto loser; + } + data = get_data_response->GetData(); + + if (!(get_data_response->GetSW1() == 0x90 && + get_data_response->GetSW2() == 0x00)) { + RA::Error(LL_PER_PDU, "RA_Processor::GetData", + "Bad Response"); + goto loser; + } + + status = new Buffer(data.substr(0, data.size())); + +loser: + + if( get_data_request_msg != NULL ) { + delete get_data_request_msg; + get_data_request_msg = NULL; + } + if( get_data_response_msg != NULL ) { + delete get_data_response_msg; + get_data_response_msg = NULL; + } + + return status; +} + +Buffer *RA_Processor::ListObjects(RA_Session *session, BYTE seq) +{ + Buffer data; + Buffer *status = NULL; + APDU_Response *response = NULL; + RA_Token_PDU_Request_Msg *request_msg = NULL; + RA_Token_PDU_Response_Msg *response_msg = NULL; + List_Objects_APDU *list_objects_apdu = NULL; + Buffer get_status_data; + + list_objects_apdu = + new List_Objects_APDU(seq); + request_msg = + new RA_Token_PDU_Request_Msg(list_objects_apdu); + session->WriteMsg(request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::ListObjects", + "Sent request_msg"); + + response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::ListObjects", + "No Token PDU Response Msg Received"); + goto loser; + } + if (response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::ListObjects", + "Invalid Message Type"); + goto loser; + } + response = response_msg->GetResponse(); + if (response == NULL) { + RA::Error(LL_PER_PDU, "Secure_Channel::ListObjects", + "No Response From Token"); + goto loser; + } + + if (!(response->GetSW1() == 0x90 && + response->GetSW2() == 0x00)) { + // RA::Error(LL_PER_PDU, "RA_Processor::ListObjects", + // "Bad Response"); + goto loser; + } + + data = response->GetData(); + + status = new Buffer(data.substr(0, data.size())); + +loser: + + if( request_msg != NULL ) { + delete request_msg; + request_msg = NULL; + } + if( response_msg != NULL ) { + delete response_msg; + response_msg = NULL; + } + + return status; +} + +/** + * GetStatus + */ +Buffer *RA_Processor::GetStatus(RA_Session *session, BYTE p1, BYTE p2) +{ + Buffer data; + Buffer *status = NULL; + APDU_Response *get_status_response = NULL; + RA_Token_PDU_Request_Msg *get_status_request_msg = NULL; + RA_Token_PDU_Response_Msg *get_status_response_msg = NULL; + Get_Status_APDU *get_status_apdu = NULL; + Buffer get_status_data; + + get_status_apdu = + new Get_Status_APDU(); + get_status_request_msg = + new RA_Token_PDU_Request_Msg(get_status_apdu); + session->WriteMsg(get_status_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::GetStatus", + "Sent get_status_request_msg"); + + get_status_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (get_status_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::GetStatus", + "No Token PDU Response Msg Received"); + goto loser; + } + if (get_status_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::GetStatus", + "Invalid Message Type"); + goto loser; + } + get_status_response = + get_status_response_msg->GetResponse(); + if (get_status_response == NULL) { + RA::Error(LL_PER_PDU, "Secure_Channel::GetStatus", + "No Response From Token"); + goto loser; + } + data = get_status_response->GetData(); + + if (!(get_status_response->GetSW1() == 0x90 && + get_status_response->GetSW2() == 0x00)) { + RA::Error(LL_PER_PDU, "RA_Processor::GetStatus", + "Bad Response"); + goto loser; + } + + status = new Buffer(data.substr(0, data.size())); + +loser: + + if( get_status_request_msg != NULL ) { + delete get_status_request_msg; + get_status_request_msg = NULL; + } + if( get_status_response_msg != NULL ) { + delete get_status_response_msg; + get_status_response_msg = NULL; + } + + return status; +} + +int RA_Processor::CreatePin(RA_Session *session, BYTE pin_number, + BYTE max_retries, char *pin) +{ + int rc = -1; + Create_Pin_APDU *create_pin_apdu = NULL; + APDU_Response *response = NULL; + RA_Token_PDU_Request_Msg *token_pdu_request_msg = NULL; + RA_Token_PDU_Response_Msg *token_pdu_response_msg = NULL; + Buffer *mac = NULL; + + RA::Debug("Secure_Channel::IsPinPresent", + "Secure_Channel::IsPinPresent"); + Buffer pin_buffer = Buffer((BYTE*)pin, strlen(pin)); + create_pin_apdu = new Create_Pin_APDU(pin_number, max_retries, + pin_buffer); + + /* + mac = ComputeAPDUMac(set_pin_apdu); + set_pin_apdu->SetMAC(*mac); + */ + token_pdu_request_msg = new RA_Token_PDU_Request_Msg( + create_pin_apdu); + session->WriteMsg(token_pdu_request_msg); + RA::Debug("Secure_Channel::CreatePin", + "Sent token_pdu_request_msg"); + + token_pdu_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (token_pdu_response_msg == NULL) + { + RA::Error("Secure_Channel::CreatePin", + "No Token PDU Response Msg Received"); + goto loser; + } + if (token_pdu_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::CreatePin", + "Invalid Message Type"); + goto loser; + } + response = token_pdu_response_msg->GetResponse(); + if (response == NULL) { + RA::Error("Secure_Channel::CreatePin", + "No Response From Token"); + goto loser; + } + + rc = 1; +loser: + if( mac != NULL ) { + delete mac; + mac = NULL; + } + if( token_pdu_request_msg != NULL ) { + delete token_pdu_request_msg; + token_pdu_request_msg = NULL; + } + if( token_pdu_response_msg != NULL ) { + delete token_pdu_response_msg; + token_pdu_response_msg = NULL; + } + + return rc; +} +int RA_Processor::IsPinPresent(RA_Session *session, BYTE pin_number) +{ + int rc = -1; + Buffer data; + List_Pins_APDU *list_pins_apdu = NULL; + APDU_Response *response = NULL; + RA_Token_PDU_Request_Msg *token_pdu_request_msg = NULL; + RA_Token_PDU_Response_Msg *token_pdu_response_msg = NULL; + Buffer *mac = NULL; + + RA::Debug("Secure_Channel::IsPinPresent", + "Secure_Channel::IsPinPresent"); + list_pins_apdu = new List_Pins_APDU(2); + + /* + mac = ComputeAPDUMac(set_pin_apdu); + set_pin_apdu->SetMAC(*mac); + */ + token_pdu_request_msg = new RA_Token_PDU_Request_Msg( + list_pins_apdu); + session->WriteMsg(token_pdu_request_msg); + RA::Debug("Secure_Channel::IsPinPresent", + "Sent token_pdu_request_msg"); + + token_pdu_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (token_pdu_response_msg == NULL) + { + RA::Error("Secure_Channel::IsPinReset", + "No Token PDU Response Msg Received"); + goto loser; + } + if (token_pdu_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::IsPinReset", + "Invalid Message Type"); + goto loser; + } + response = token_pdu_response_msg->GetResponse(); + if (response == NULL) { + RA::Error("Secure_Channel::IsPinReset", + "No Response From Token"); + goto loser; + } + data = response->GetData(); + if (data.size() < 2) { + RA::Error(LL_PER_PDU, "Secure_Channel::IsPinReset", + "Invalid Response From Token"); + goto loser; + } + + if (pin_number < 8) { + rc = ((((BYTE*)data)[1] & (1 << pin_number)) > 0); + } else { + rc = ((((BYTE*)data)[0] & (1 << (pin_number - 8))) > 0); + } + +loser: + if( mac != NULL ) { + delete mac; + mac = NULL; + } + if( token_pdu_request_msg != NULL ) { + delete token_pdu_request_msg; + token_pdu_request_msg = NULL; + } + if( token_pdu_response_msg != NULL ) { + delete token_pdu_response_msg; + token_pdu_response_msg = NULL; + } + + return rc; +} + +/** + * Select applet. + * + * Global Platform Open Platform Card Specification + * Version 2.0.1 Page 9-22 + * + * Sample Data: + * + * _____________ CLA + * | __________ INS + * | | _______ P1 + * | | | ____ P2 + * | | | | _ Len + * | | | | | + * 00 A4 04 00 07 + * 53 4C 42 47 49 4E 41 + */ +int RA_Processor::SelectApplet(RA_Session *session, BYTE p1, BYTE p2, Buffer *aid) +{ + int rc = 0; + APDU_Response *select_response = NULL; + RA_Token_PDU_Request_Msg *select_request_msg = NULL; + RA_Token_PDU_Response_Msg *select_response_msg = NULL; + Select_APDU *select_apdu = NULL; + + if (aid != NULL) { + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::SelectApplet", + "RA_Processor::SelectApplet with aid= ", aid); + } + + select_apdu = new Select_APDU(p1, p2, *aid); + select_request_msg = + new RA_Token_PDU_Request_Msg(select_apdu); + session->WriteMsg(select_request_msg); + + RA::Debug(LL_PER_PDU, "RA_Processor::SelectApplet", + "Sent select_request_msg"); + + select_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (select_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::SelectApplet", + "No Token PDU Response Msg Received"); + goto loser; + } + if (select_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "Secure_Channel::SelectApplet", + "Invalid Message Type"); + goto loser; + } + select_response = select_response_msg->GetResponse(); + if (select_response == NULL) { + RA::Error(LL_PER_PDU, "Secure_Channel::SelectApplet", + "No Response From Token"); + goto loser; + } + if (select_response->GetData().size() < 2) { + RA::Error(LL_PER_PDU, "Secure_Channel::SelectApplet", + "Invalid Response From Token"); + goto loser; + } + if (!(select_response->GetSW1() == 0x90 && + select_response->GetSW2() == 0x00)) { + RA::Error(LL_PER_PDU, "RA_Processor::SelectApplet", + "Bad Response"); + goto loser; + } + + +loser: + if( select_request_msg != NULL ) { + delete select_request_msg; + select_request_msg = NULL; + } + if( select_response_msg != NULL ) { + delete select_response_msg; + select_response_msg = NULL; + } + + return rc; +} + +/** + * Get Build ID from Net Key Applet. + * @returns a buffer with 4 bytes of data. This is the applet ID. + * The caller is responsible for freeing the buffer with + * the 'delete' operator. + */ +Buffer *RA_Processor::GetAppletVersion(RA_Session *session) +{ + Buffer data; + Buffer *buildID = NULL; + APDU_Response *get_version_response = NULL; + RA_Token_PDU_Request_Msg *get_version_request_msg = NULL; + RA_Token_PDU_Response_Msg *get_version_response_msg = NULL; + Get_Version_APDU *get_version_apdu = NULL; + Buffer get_version_data; + + get_version_apdu = + new Get_Version_APDU(); + get_version_request_msg = + new RA_Token_PDU_Request_Msg(get_version_apdu); + session->WriteMsg(get_version_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::GetAppletVersion", + "Sent get_version_request_msg"); + + get_version_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (get_version_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::GetAppletVersion", + "No Token PDU Response Msg Received"); + goto loser; + } + if (get_version_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::GetAppletVersion", + "Invalid Message Type"); + goto loser; + } + get_version_response = + get_version_response_msg->GetResponse(); + if (get_version_response == NULL) { + RA::Error(LL_PER_PDU, "Secure_Channel::GetAppletVersion", + "No Response From Token"); + goto loser; + } + data = get_version_response->GetData(); + if (!(get_version_response->GetSW1() == 0x90 && + get_version_response->GetSW2() == 0x00)) { + RA::Error(LL_PER_PDU, "RA_Processor::GetAppletVersion", + "Bad Response"); + goto loser; + } + + /* Sample: 3FBAB4BF9000 */ + if (data.size() != 6) { + RA::Error(LL_PER_PDU, "Secure_Channel::GetAppletVersion", + "Invalid Applet Version"); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::GetAppletVersion", + "Bad Applet Version: ", + &data); + goto loser; + } + + buildID = new Buffer(data.substr(0, 4)); + +/* + buildID = (get_version_data[0] << 24) | (get_version_data[1] << 16) | + (get_version_data[2] << 8) | get_version_data[3]; + +*/ + +loser: + + if( get_version_request_msg != NULL ) { + delete get_version_request_msg; + get_version_request_msg = NULL; + } + if( get_version_response_msg != NULL ) { + delete get_version_response_msg; + get_version_response_msg = NULL; + } + return buildID; +} + +/* + * this one sets the security level + */ +Secure_Channel *RA_Processor::SetupSecureChannel(RA_Session *session, + BYTE key_version, BYTE key_index, SecurityLevel security_level, + const char *connId) +{ + Secure_Channel *channel = SetupSecureChannel(session, key_version, key_index, connId); + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel","Resetting security level ..."); + + /* Bugscape Bug #55774: Prevent NetKey RA from crashing . . . */ + if( channel != NULL ) { + channel->SetSecurityLevel(security_level); + } else { + RA::Error( LL_PER_PDU, "RA_Processor::SetupSecureChannel", "%s %s", + "Failed to create a secure channel - potentially due to an", + "RA/TKS key mismatch or differing RA/TKS key versions." ); + } + return channel; + +} + +int RA_Processor::InitializeUpdate(RA_Session *session, + BYTE key_version, BYTE key_index, + Buffer &key_diversification_data, + Buffer &key_info_data, + Buffer &card_challenge, + Buffer &card_cryptogram, + Buffer &host_challenge, const char *connId) +{ + int rc = -1; + APDU_Response *initialize_update_response = NULL; + RA_Token_PDU_Request_Msg *initialize_update_request_msg = NULL; + RA_Token_PDU_Response_Msg *initialize_update_response_msg = NULL; + Initialize_Update_APDU *initialize_update_apdu = NULL; + Buffer update_response_data; + char configname[256]; + + RA::Debug(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "RA_Processor::InitializeUpdate"); + + + PR_snprintf((char *) configname, 256, "conn.%s.generateHostChallenge", connId); + bool gen_host_challenge_tks = RA::GetConfigStore()->GetConfigAsBool(configname, true); + + if(gen_host_challenge_tks) { + RA::Debug(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Generate host challenge on TKS."); + rc = ComputeRandomData(host_challenge, (int) host_challenge.size(), connId); + } else { + rc = Util::GetRandomChallenge(host_challenge); + } + + if(rc == -1) { + RA::Debug(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Failed to generate host challenge"); + goto loser; + + } + + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Generated Host Challenge", + &host_challenge); + + initialize_update_apdu = + new Initialize_Update_APDU(key_version, key_index, host_challenge); + initialize_update_request_msg = + new RA_Token_PDU_Request_Msg(initialize_update_apdu); + session->WriteMsg(initialize_update_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Sent initialize_update_request_msg"); + + initialize_update_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (initialize_update_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "No Token PDU Response Msg Received"); + goto loser; + } + if (initialize_update_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Invalid Message Type"); + goto loser; + } + initialize_update_response = + initialize_update_response_msg->GetResponse(); + update_response_data = initialize_update_response->GetData(); + + if (!(initialize_update_response->GetSW1() == 0x90 && + initialize_update_response->GetSW2() == 0x00)) { + RA::Debug(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Key version mismatch - key changeover to follow"); + goto loser; + } + + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Update Response Data", &update_response_data); + + /** + * Initialize Update response: + * Key Diversification Data - 10 bytes + * Key Information Data - 2 bytes + * Card Challenge - 8 bytes + * Card Cryptogram - 8 bytes + */ + if (initialize_update_response->GetData().size() < 10) { + RA::Error(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Invalid Initialize Update Response Size"); + goto loser; + } + key_diversification_data = Buffer(update_response_data.substr(0, 10)); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Key Diversification Data", &key_diversification_data); + key_info_data = Buffer(update_response_data.substr(10, 2)); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Key Info Data", &key_info_data); + card_challenge = Buffer(update_response_data.substr(12, 8)); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Card Challenge", &card_challenge); + card_cryptogram = Buffer(update_response_data.substr(20, 8)); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::InitializeUpdate", + "Card Cryptogram", &card_cryptogram); + + rc = 1; + +loser: + if( initialize_update_request_msg != NULL ) { + delete initialize_update_request_msg; + initialize_update_request_msg = NULL; + } + if( initialize_update_response_msg != NULL ) { + delete initialize_update_response_msg; + initialize_update_response_msg = NULL; + } + + return rc; +} + +/** + * Setup secure channel between RA and the token. + */ +Secure_Channel *RA_Processor::SetupSecureChannel(RA_Session *session, + BYTE key_version, BYTE key_index, const char *connId) +{ + Secure_Channel *channel = NULL; + APDU_Response *initialize_update_response = NULL; + RA_Token_PDU_Request_Msg *initialize_update_request_msg = NULL; + RA_Token_PDU_Response_Msg *initialize_update_response_msg = NULL; + Initialize_Update_APDU *initialize_update_apdu = NULL; + Buffer update_response_data; + Buffer host_challenge = Buffer(8, (BYTE)0); + Buffer key_diversification_data; + Buffer key_info_data; + Buffer card_challenge; + Buffer card_cryptogram; + char configname[256]; + + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::Setup_Secure_Channel"); + + PR_snprintf((char *) configname, 256, "conn.%s.generateHostChallenge", connId); + bool gen_host_challenge_tks = RA::GetConfigStore()->GetConfigAsBool(configname, false); + + int rc = 0; + if(gen_host_challenge_tks) { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Generate host challenge on TKS."); + rc = ComputeRandomData(host_challenge, (int) host_challenge.size(), connId); + } else { + rc = Util::GetRandomChallenge(host_challenge); + } + + if(rc == -1) { + RA::Debug(LL_PER_PDU, "RA_Processor::SetupSecureChannel", + "Failed to generate host challenge"); + goto loser; + + } + + + + /* if (Util::GetRandomChallenge(host_challenge) != PR_SUCCESS) + { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Failed to generate host challenge"); + goto loser; + } + +*/ + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Generated Host Challenge", + &host_challenge); + + initialize_update_apdu = + new Initialize_Update_APDU(key_version, key_index, host_challenge); + initialize_update_request_msg = + new RA_Token_PDU_Request_Msg(initialize_update_apdu); + session->WriteMsg(initialize_update_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Sent initialize_update_request_msg"); + + initialize_update_response_msg = (RA_Token_PDU_Response_Msg *) + session->ReadMsg(); + if (initialize_update_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "No Token PDU Response Msg Received"); + goto loser; + } + if (initialize_update_response_msg->GetType() != MSG_TOKEN_PDU_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Invalid Message Type"); + goto loser; + } + initialize_update_response = + initialize_update_response_msg->GetResponse(); + update_response_data = initialize_update_response->GetData(); + + if (!(initialize_update_response->GetSW1() == 0x90 && + initialize_update_response->GetSW2() == 0x00)) { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Key version mismatch - key changeover to follow"); + goto loser; + } + + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Update Response Data", &update_response_data); + + /** + * Initialize Update response: + * Key Diversification Data - 10 bytes + * Key Information Data - 2 bytes + * Card Challenge - 8 bytes + * Card Cryptogram - 8 bytes + */ + if (initialize_update_response->GetData().size() < 28) { + RA::Error(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Invalid Initialize Update Response Size"); + goto loser; + } + key_diversification_data = Buffer(update_response_data.substr(0, 10)); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Key Diversification Data", &key_diversification_data); + key_info_data = Buffer(update_response_data.substr(10, 2)); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Key Info Data", &key_info_data); + card_challenge = Buffer(update_response_data.substr(12, 8)); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Card Challenge", &card_challenge); + card_cryptogram = Buffer(update_response_data.substr(20, 8)); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "Card Cryptogram", &card_cryptogram); + + channel = GenerateSecureChannel( + session, connId, + key_diversification_data, + key_info_data, + card_challenge, + card_cryptogram, + host_challenge); + +loser: + if( initialize_update_request_msg != NULL ) { + delete initialize_update_request_msg; + initialize_update_request_msg = NULL; + } + if( initialize_update_response_msg != NULL ) { + delete initialize_update_response_msg; + initialize_update_response_msg = NULL; + } + + return channel; +} /* SetupSecureChannel */ + +/** + * Requests secure ID. + */ +SecureId *RA_Processor::RequestSecureId(RA_Session *session) +{ + SecureId *secure_id = NULL; + RA_SecureId_Request_Msg *secureid_request_msg = NULL; + RA_SecureId_Response_Msg *secureid_response_msg = NULL; + char *value; + char *pin; + + RA::Debug(LL_PER_PDU, "RA_Processor::SecureId_Request", + "RA_Processor::SecureId_Request"); + + secureid_request_msg = new RA_SecureId_Request_Msg( + 0 /* pin_required */, 0 /* next_value */); + session->WriteMsg(secureid_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::SecureId_Request", + "Sent secureid_request_msg"); + + secureid_response_msg = (RA_SecureId_Response_Msg *) + session->ReadMsg(); + if (secureid_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::SecureId_Request", + "No SecureID Response Msg Received"); + goto loser; + } + + if (secureid_response_msg->GetType() != MSG_SECUREID_RESPONSE) { + RA::Error("Secure_Channel::SecureId_Request", + "Invalid Msg Type"); + goto loser; + } + + value = secureid_response_msg->GetValue(); + pin = secureid_response_msg->GetPIN(); + + secure_id = new SecureId(value, pin); + +loser: + + if( secureid_request_msg != NULL ) { + delete secureid_request_msg; + secureid_request_msg = NULL; + } + if( secureid_response_msg != NULL ) { + delete secureid_response_msg; + secureid_response_msg = NULL; + } + return secure_id; +} /* RequestSecureId */ + +/** + * Requests new pin for token. + */ +char *RA_Processor::RequestNewPin(RA_Session *session, unsigned int min, unsigned int max) +{ + char *new_pin = NULL; + RA_New_Pin_Request_Msg *new_pin_request_msg = NULL; + RA_New_Pin_Response_Msg *new_pin_response_msg = NULL; + + RA::Debug(LL_PER_PDU, "RA_Processor::New_Pin_Request", + "RA_Processor::New_Pin_Request"); + + new_pin_request_msg = new RA_New_Pin_Request_Msg( + min, max); + session->WriteMsg(new_pin_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::New_Pin_Request", + "Sent new_pin_request_msg"); + + new_pin_response_msg = (RA_New_Pin_Response_Msg *) + session->ReadMsg(); + if (new_pin_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::New_Pin_Request", + "No New Pin Response Msg Received"); + goto loser; + } + + if (new_pin_response_msg->GetType() != MSG_NEW_PIN_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::New_Pin_Request", + "Invalid Message Type"); + goto loser; + } + + if (new_pin_response_msg->GetNewPIN() == NULL) { + RA::Error(LL_PER_PDU, "RA_Processor::New_Pin_Request", + "No New Pin"); + goto loser; + } + + new_pin = PL_strdup(new_pin_response_msg->GetNewPIN()); + + if (strlen(new_pin) < min) { + RA::Error(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "The length of the new pin is shorter than the mininum length (%d)", min); + if( new_pin != NULL ) { + PL_strfree( new_pin ); + new_pin = NULL; + } + new_pin = NULL; + goto loser; + } else if (strlen(new_pin) > max) { + RA::Error(LL_PER_PDU, "RA_Pin_Reset_Processor::Process", + "The length of the new pin is longer than the maximum length (%d)", max); + if( new_pin != NULL ) { + PL_strfree( new_pin ); + new_pin = NULL; + } + new_pin = NULL; + goto loser; + } + +loser: + + if( new_pin_request_msg != NULL ) { + delete new_pin_request_msg; + new_pin_request_msg = NULL; + } + if( new_pin_response_msg != NULL ) { + delete new_pin_response_msg; + new_pin_response_msg = NULL; + } + + return new_pin; +} /* RequestNewPin */ + +/** + * Requests A Security Question (ASQ) from user. + */ +char *RA_Processor::RequestASQ(RA_Session *session, char *question) +{ + char *answer = NULL; + RA_ASQ_Request_Msg *asq_request_msg = NULL; + RA_ASQ_Response_Msg *asq_response_msg = NULL; + + RA::Debug(LL_PER_PDU, "RA_Processor::ASQ_Request", + "RA_Processor::ASQ_Request"); + + asq_request_msg = new RA_ASQ_Request_Msg(question); + session->WriteMsg(asq_request_msg); + RA::Debug(LL_PER_PDU, "RA_Processor::ASQ_Request", + "Sent asq_request_msg"); + + asq_response_msg = (RA_ASQ_Response_Msg *) + session->ReadMsg(); + if (asq_response_msg == NULL) + { + RA::Error(LL_PER_PDU, "RA_Processor::ASQ_Request", + "No ASQ Response Msg Received"); + goto loser; + } + if (asq_response_msg->GetType() != MSG_ASQ_RESPONSE) { + RA::Error(LL_PER_PDU, "RA_Processor::ASQ_Request", + "Invalid Message Type"); + goto loser; + } + + if (asq_response_msg->GetAnswer() == NULL) { + RA::Error(LL_PER_PDU, "RA_Processor::ASQ_Request", + "No ASQ Answer"); + goto loser; + } + answer = PL_strdup(asq_response_msg->GetAnswer()); + +loser: + if( asq_request_msg != NULL ) { + delete asq_request_msg; + asq_request_msg = NULL; + } + if( asq_response_msg != NULL ) { + delete asq_response_msg; + asq_response_msg = NULL; + } + + return answer; +} /* RequestASQ */ + +/** + * Creates a secure channel between RA and the token. + * challenges are sent to TKS which generates + * host cryptogram, and session key. + */ +Secure_Channel *RA_Processor::GenerateSecureChannel( + RA_Session *session, const char *connId, + Buffer &key_diversification_data, /* CUID */ + Buffer &key_info_data, + Buffer &card_challenge, + Buffer &card_cryptogram, + Buffer &host_challenge) +{ + PK11SymKey *session_key = NULL; + Buffer *host_cryptogram = NULL; + char configname[256]; + + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel"); + + PK11SymKey *enc_session_key = NULL; + + + // desKey_s will be assigned to channel and will be destroyed when channel closed + char *drm_desKey_s = NULL; + char *kek_desKey_s = NULL; + char *keycheck_s = NULL; + + session_key = RA::ComputeSessionKey(session, key_diversification_data, + key_info_data, card_challenge, + host_challenge, &host_cryptogram, + card_cryptogram, &enc_session_key, + &drm_desKey_s, &kek_desKey_s, + &keycheck_s, connId); + if (session_key == NULL) { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - did not get session_key"); + return NULL; + } + + // is serversideKeygen on? + PR_snprintf((char *) configname, 256, "conn.%s.serverKeygen", connId); + bool serverKeygen = RA::GetConfigStore()->GetConfigAsBool(configname, false); + + if (serverKeygen) { + if ((drm_desKey_s == NULL) || (strcmp(drm_desKey_s, "")==0)) { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - did not get drm_desKey_s"); + return NULL; + } else { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - drm_desKey_s = %s", drm_desKey_s); + } + if ((kek_desKey_s == NULL) || (strcmp(kek_desKey_s,"")==0)) { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - did not get kek_desKey_s"); + return NULL; + } else { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - kek_desKey_s = %s", kek_desKey_s); + } + if ((keycheck_s == NULL) || (strcmp(keycheck_s,"")==0)) { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - did not get keycheck_s"); + return NULL; + } + + if (enc_session_key == NULL) { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - did not get enc_session_key"); + return NULL; + } + if (host_cryptogram == NULL) { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - did not get host_cryptogram"); + return NULL; + } else { + RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel", + "RA_Processor::GenerateSecureChannel - keycheck_s = %s", keycheck_s); + } + } +/* + host_cryptogram = RA::ComputeHostCryptogram( + card_challenge, host_challenge); +*/ + + + Secure_Channel *channel = new Secure_Channel(session, session_key, + enc_session_key, + drm_desKey_s, kek_desKey_s, keycheck_s, + key_diversification_data, key_info_data, + card_challenge, card_cryptogram, + host_challenge, *host_cryptogram); + + if( host_cryptogram != NULL ) { + delete host_cryptogram; + host_cryptogram = NULL; + } + + if (channel != NULL) { + // this can be overridden by individual processor later + channel->SetSecurityLevel(RA::GetGlobalSecurityLevel()); + } else { + if( session_key != NULL ) { + PK11_FreeSymKey( session_key ); + session_key = NULL; + } + if( enc_session_key != NULL ) { + PK11_FreeSymKey( enc_session_key ); + enc_session_key = NULL; + } + + } + + RA::Debug(LL_PER_PDU, "RA_Processor::GenerateSecureChannel", "complete"); + return channel; +} /* GenerateSecureChannel */ + +int RA_Processor::CreateKeySetData(Buffer &CUID, Buffer &version, + Buffer &NewMasterVer, Buffer &out, const char *connid) +{ + char body[5000]; + char configname[256]; + HttpConnection *tksConn = NULL; + tksConn = RA::GetTKSConn(connid); + if (tksConn == NULL) { + RA::Debug(LL_PER_PDU, "RA_Processor::CreateKeySetData", "Failed to get TKSConnection %s", connid); + RA::Error(LL_PER_PDU, "RA_Processor::CreateKeySetData", "Failed to get TKSConnection %s", connid); + return -1; + } else { + // PRLock *tks_lock = RA::GetTKSLock(); + int tks_curr = RA::GetCurrentIndex(tksConn); + int currRetries = 0; + char *cuid = Util::SpecialURLEncode(CUID); + char *versionID = Util::SpecialURLEncode(version); + char *masterV = Util::SpecialURLEncode(NewMasterVer); + + PR_snprintf((char *)configname, 256, "conn.%s.keySet", connid); + const char *keySet = RA::GetConfigStore()->GetConfigAsString(configname); + + PR_snprintf((char *)body, 5000, + "newKeyInfo=%s&CUID=%s&KeyInfo=%s&keySet=%s", masterV, cuid, versionID,keySet); + + PR_snprintf((char *)configname, 256, "conn.%s.servlet.createKeySetData", connid); + const char *servletID = RA::GetConfigStore()->GetConfigAsString(configname); + + if( cuid != NULL ) { + PR_Free( cuid ); + cuid = NULL; + } + if( versionID != NULL ) { + PR_Free( versionID ); + versionID = NULL; + } + if( masterV != NULL ) { + PR_Free( masterV ); + masterV = NULL; + } + + tks_curr = RA::GetCurrentIndex(tksConn); + + PSHttpResponse * response = tksConn->getResponse(tks_curr, servletID, body); + ConnectionInfo *connInfo = tksConn->GetFailoverList(); + char **hostport = connInfo->GetHostPortList(); + + if (response == NULL) + RA::Debug(LL_PER_PDU, "The CreateKeySetData response from TKS ", + "at %s is NULL.", hostport[tks_curr]); + else + RA::Debug(LL_PER_PDU, "The CreateKeySetData response from TKS ", + "at % is not NULL.", hostport[tks_curr]); + + while (response == NULL) { + RA::Failover(tksConn, connInfo->GetHostPortListLen()); + tks_curr = RA::GetCurrentIndex(tksConn); + + RA::Debug(LL_PER_PDU, "RA is reconnecting to TKS ", + "at %s for createKeySetData.", hostport[tks_curr]); + + if (++currRetries >= tksConn->GetNumOfRetries()) { + RA::Debug(LL_PER_PDU, "Used up all the retries. Response is NULL",""); + RA::Error(LL_PER_PDU, "RA_Processor::CreateKeySetData","Failed connecting to TKS after %d retries", currRetries); + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + return -1; + } + response = tksConn->getResponse(tks_curr, servletID, body); + } + + int status = 0; + + Buffer *keydataset = NULL; + if (response != NULL) { + RA::Debug(LL_PER_PDU,"Response is not ","NULL"); + char * content = response->getContent(); + if (content == NULL) { + RA::Debug(LL_PER_PDU,"TKSConnection::CreateKeySetData","Content Is NULL"); + } else { + RA::Debug(LL_PER_PDU,"TKSConnection::CreateKeySetData","Content Is '%s'", + content); + } + if (content != NULL) { + char *statusStr = strstr((char *)content, "status=0&"); + if (statusStr == NULL) { + status = 1; + char *p = strstr((char *)content, "status="); + if(p != NULL) { + status = int(p[7]) - 48; + } else { + status = 4; + return -1; + } + } else { + status = 0; + char *p = &content[9]; + char *rcStr = strstr((char *)p, "keySetData="); + if (rcStr != NULL) { + rcStr = &rcStr[11]; + if (!strcmp(rcStr, "%00")) { + return -1; + } + keydataset = Util::URLDecode(rcStr); + } + } + } + } + + if (keydataset == NULL) + { + RA::Debug(LL_PER_PDU, "RA_Processor:CreateKeySetData", + "Key Set Data is NULL"); + + return -1; + } + + RA::Debug(LL_PER_PDU, "RA_Processor:CreateKeySetData", "Status of CreateKeySetData=%d", status); + RA::Debug(LL_PER_PDU, "finish CreateKeySetData", ""); + + if (status > 0) { + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + return -1; + } else { + out = *keydataset; + if( keydataset != NULL ) { + delete keydataset; + keydataset = NULL; + } + } + + if( response != NULL ) { + response->freeContent(); + delete response; + response = NULL; + } + + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + return 1; + } + BYTE kek_key[] = { + 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f + }; + BYTE key[] = { + 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f + }; + Buffer old_kek_key(kek_key, 16); + Buffer new_auth_key(key, 16); + Buffer new_mac_key(key, 16); + Buffer new_kek_key(key, 16); + + + Util::CreateKeySetData( + NewMasterVer, + old_kek_key, + new_auth_key, + new_mac_key, + new_kek_key, + out); + + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + return 1; +} + + +/** + * Input data wrapped by KEK key in TKS. + */ +int RA_Processor::EncryptData(Buffer &CUID, Buffer &version, Buffer &in, Buffer &out, const char *connid) +{ + char body[5000]; + char configname[256]; +#define PLAINTEXT_CHALLENGE_SIZE 16 + // khai, here we wrap the input with the KEK key + // in TKS + HttpConnection *tksConn = NULL; + char kek_key[16] = { + 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f + }; + int status = 0; + + tksConn = RA::GetTKSConn(connid); + if (tksConn == NULL) { + RA::Debug(LL_PER_PDU, "RA_Processor::EncryptData", "Failed to get TKSConnection %s", connid); + RA::Debug(LL_PER_PDU, "RA_Processor::EncryptData", "Failed to get TKSConnection %s", connid); + return -1; + } else { + int tks_curr = RA::GetCurrentIndex(tksConn); + int currRetries = 0; + char *data = NULL; + Buffer *zerob = new Buffer(PLAINTEXT_CHALLENGE_SIZE, (BYTE)0); + if (!(in == *zerob)) + data = Util::SpecialURLEncode(in); + else + RA::Debug(LL_PER_PDU, "RA_Processor::EncryptData","Challenge to be generated on TKS"); + + if (zerob != NULL) { + delete zerob; + } + + char *cuid = Util::SpecialURLEncode(CUID); + char *versionID = Util::SpecialURLEncode(version); + + PR_snprintf((char *)configname, 256, "conn.%s.keySet", connid); + const char *keySet = RA::GetConfigStore()->GetConfigAsString(configname); + + PR_snprintf((char *)body, 5000, "data=%s&CUID=%s&KeyInfo=%s&keySet=%s", + ((data != NULL)? data:""), cuid, versionID,keySet); + PR_snprintf((char *)configname, 256, "conn.%s.servlet.encryptData", connid); + const char *servletID = RA::GetConfigStore()->GetConfigAsString(configname); + + if( cuid != NULL ) { + PR_Free( cuid ); + cuid = NULL; + } + if( versionID != NULL ) { + PR_Free( versionID ); + versionID = NULL; + } + + PSHttpResponse *response = tksConn->getResponse(tks_curr, servletID, body); + ConnectionInfo *connInfo = tksConn->GetFailoverList(); + char **hostport = connInfo->GetHostPortList(); + if (response == NULL) + RA::Debug(LL_PER_PDU, "The encryptedData response from TKS ", + "at %s is NULL.", hostport[tks_curr]); + else + RA::Debug(LL_PER_PDU, "The encryptedData response from TKS ", + "at %s is not NULL.", hostport[tks_curr]); + + while (response == NULL) { + RA::Failover(tksConn, connInfo->GetHostPortListLen()); + tks_curr = RA::GetCurrentIndex(tksConn); + RA::Debug(LL_PER_PDU, "RA is reconnecting to TKS ", + "at %s for encryptData.", hostport[tks_curr]); + + if (++currRetries >= tksConn->GetNumOfRetries()) { + RA::Debug(LL_PER_PDU, "Used up all the retries. Response is NULL",""); + RA::Error(LL_PER_PDU, "RA_Processor::EncryptData", "Failed connecting to TKS after %d retries", currRetries); + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + return -1; + } + response = tksConn->getResponse(tks_curr, servletID, body); + } + + Buffer *encryptedData = NULL; + // preEncData is only useful when data is null, and data is to be randomly + // generated on TKS + Buffer *preEncData = NULL; + status = 0; + if (response != NULL) { + RA::Debug(LL_PER_PDU, "EncryptData Response is not ","NULL"); + char *content = response->getContent(); + if (content != NULL) { + char *statusStr = strstr((char *)content, "status=0&"); + if (statusStr == NULL) { + char *p = strstr((char *)content, "status="); + + if(p != NULL) { + status = int(p[7]) - 48; + } else { + status = 4; + return -1; + } + } else { + status = 0; + char *p = &content[9]; + // get pre-encryption data + char *preStr = strstr((char *)p, "data="); + if (preStr != NULL) { + p = &preStr[5]; + char pstr[PLAINTEXT_CHALLENGE_SIZE*3+1]; + strncpy(pstr, p, PLAINTEXT_CHALLENGE_SIZE*3); + pstr[PLAINTEXT_CHALLENGE_SIZE*3] = '\0'; + preEncData = Util::URLDecode(pstr); +//RA::DebugBuffer("RA_Processor::EncryptData", "preEncData=", preEncData); + } + + // get encrypted data + p = &content[9]; + char *rcStr = strstr((char *)p, "encryptedData="); + if (rcStr != NULL) { + rcStr = &rcStr[14]; + encryptedData = Util::URLDecode(rcStr); +//RA::DebugBuffer("RA_Processor::EncryptData", "encryptedData=", encryptedData); + } + } + } + } + if (encryptedData == NULL) + RA::Debug(LL_PER_PDU, "RA_Processor:GetEncryptedData", + "Encrypted Data is NULL"); + + RA::Debug(LL_PER_PDU, "EncryptedData ", "status=%d", status); + RA::Debug(LL_PER_PDU, "finish EncryptedData", ""); + if ((status > 0) || (preEncData == NULL) || (encryptedData == NULL)) { + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + if( data != NULL ) { + PR_Free( data ); + data = NULL; + } + return -1; + } else { + out = *encryptedData; + if( encryptedData != NULL ) { + delete encryptedData; + encryptedData = NULL; + } + if (data != NULL) { + RA::Debug(LL_PER_PDU, "EncryptedData ", "challenge overwritten by TKS"); + PR_Free( data ); + data = NULL; + } + in = *preEncData; + + if( preEncData != NULL ) { + delete preEncData; + preEncData = NULL; + } + } + if( response != NULL ) { + response->freeContent(); + delete response; + response = NULL; + } + + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + return 1; + } + + Buffer kek_buffer = Buffer((BYTE*)kek_key, 16); + status = Util::EncryptData(kek_buffer, in, out); +#if 0 + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::EncryptData", "Encrypted Data", + &out); + Buffer out1 = Buffer(16, (BYTE)0); + status = Util::DecryptData(kek_buffer, out, out1); + RA::DebugBuffer(LL_PER_PDU, "RA_Processor::EncryptData", "Clear Data", + &out1); +#endif + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + return status; +} + +int RA_Processor::ComputeRandomData(Buffer &data_out, int dataSize, const char *connid) +{ + char body[5000]; + char configname[256]; + HttpConnection *tksConn = NULL; + int status = -1; + Buffer *decodedRandomData = NULL; + PSHttpResponse *response = NULL; + + //check for absurd dataSize values + if(dataSize <= 0 || dataSize > 1024) { + RA::Debug(LL_PER_PDU, "RA_Processor::ComputeRandomData", "Invalid dataSize requested %d", dataSize); + return -1; + } + + tksConn = RA::GetTKSConn(connid); + if (tksConn == NULL) { + RA::Debug(LL_PER_PDU, "RA_Processor::ComputeRandomData", "Failed to get TKSConnection %s", connid); + return -1; + } else { + int tks_curr = RA::GetCurrentIndex(tksConn); + int currRetries = 0; + + PR_snprintf((char *)body, 5000, "dataNumBytes=%d" + , dataSize ); + + PR_snprintf((char *)configname, 256, "conn.%s.servlet.computeRandomData", connid); + const char *servletID = RA::GetConfigStore()->GetConfigAsString(configname); + + response = tksConn->getResponse(tks_curr, servletID, body); + ConnectionInfo *connInfo = tksConn->GetFailoverList(); + char **hostport = connInfo->GetHostPortList(); + if (response == NULL) + RA::Debug(LL_PER_PDU, "The ComputeRandomData response from TKS ", + "at %s is NULL.", hostport[tks_curr]); + else + RA::Debug(LL_PER_PDU, "The ComputeRandomData response from TKS ", + "at %s is not NULL.", hostport[tks_curr]); + + while (response == NULL) { + RA::Failover(tksConn, connInfo->GetHostPortListLen()); + tks_curr = RA::GetCurrentIndex(tksConn); + RA::Debug(LL_PER_PDU, "RA_Processor::ComputeRandomData: RA is reconnecting to TKS ", + "at %s for ComputeRandomData.", hostport[tks_curr]); + + if (++currRetries >= tksConn->GetNumOfRetries()) { + RA::Debug(LL_PER_PDU, "RA_Processor::ComputeRandomData: Used up all the retries. Response is NULL",""); + RA::Error(LL_PER_PDU, "RA_Processor::ComputeRandomData", "Failed connecting to TKS after %d retries", currRetries); + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + status = -1; + goto loser; + } + response = tksConn->getResponse(tks_curr, servletID, body); + } + + status = 0; + if (response != NULL) { + RA::Debug(LL_PER_PDU, "RA_Processor::ComputeRandomData Response is not ","NULL"); + char *content = response->getContent(); + if (content != NULL) { + char *statusStr = strstr((char *)content, "status=0&"); + if (statusStr == NULL) { + char *p = strstr((char *)content, "status="); + + if(p != NULL) { + status = int(p[7]) - 48; + + RA::Debug(LL_PER_PDU, "RA_Processor::ComputeRandomData status from TKS is ","status %d",status); + status = -1; + } else { + status = -1; + goto loser; + } + } else { + status = 0; + // skip over "status=0&" + char *p = &content[9]; + + // get random data + char *dataStr = strstr((char *)p, "DATA="); + if (dataStr != NULL) { + // skip over "DATA=" + p = &dataStr[5]; + + char *dstr = new char[ dataSize *3 + 1]; + if(!dstr) { + status = -1; + goto loser; + } + strncpy(dstr, p, dataSize * 3); + dstr[dataSize*3] = '\0'; + decodedRandomData = Util::URLDecode(dstr); + RA::DebugBuffer("RA_Processor::ComputeRandomData", "decodedRandomData=", decodedRandomData); + + if(dstr) { + data_out = *decodedRandomData; + delete [] dstr; + dstr = NULL; + } + if(decodedRandomData) { + delete decodedRandomData; + decodedRandomData = NULL; + } + } + } + } + } + } +loser: + if( response != NULL ) { + response->freeContent(); + delete response; + response = NULL; + } + + if (tksConn != NULL) { + RA::ReturnTKSConn(tksConn); + } + + return status; +} + +bool RA_Processor::RevokeCertificates(RA_Session *session, char *cuid,char *audit_msg, + char *final_applet_version, + char *keyVersion, + char *tokenType, + char *userid, + RA_Status &status ) +{ + const char *OP_PREFIX = "op.format"; + char *statusString = NULL; + char configname[256]; + char filter[512]; + char activity_msg[512]; + char serial[100]; + int rc = 0; + int statusNum; + LDAPMessage *result = NULL; + LDAPMessage *e = NULL; + bool revocation_failed = false; + + RA::Debug("RA_Processor::RevokeCertificates","RevokeCertificates! cuid %s",cuid); + PR_snprintf((char *)filter, 256, "(tokenID=%s)", cuid); + rc = RA::ra_find_tus_certificate_entries_by_order(filter, 100, &result, 1); + if (rc == 0) { + CertEnroll *certEnroll = new CertEnroll(); + for (e = RA::ra_get_first_entry(result); e != NULL; e = RA::ra_get_next_entry(e)) { + char *attr_status = RA::ra_get_cert_status(e); + if (strcmp(attr_status, "revoked") == 0) { + if (attr_status != NULL) { + PL_strfree(attr_status); + attr_status = NULL; + } + rc = RA::ra_delete_certificate_entry(e); + continue; + } + char *attr_serial= RA::ra_get_cert_serial(e); + ///////////////////////////////////////////////// + // Raidzilla Bug #57803: + // If the certificate is not originally created for this + // token, we should not revoke the certificate here. + // + // To figure out if this certificate is originally created + // for this token, we check the tokenOrigin attribute. + ///////////////////////////////////////////////// + char *origin = RA::ra_get_cert_attr_byname(e, "tokenOrigin"); + if (origin != NULL) { + RA::Debug("RA_Processor::RevokeCertificates", "Origin is %s, Current is %s", origin, cuid); + if (strcmp(origin, cuid) != 0) { + // skip this certificate, no need to do nothing + // We did not create this originally + + rc = RA::ra_delete_certificate_entry(e); + continue; + } + } else { + RA::Debug("RA_Processor::RevokeCertificates", "Origin is not present"); + } + + PR_snprintf((char *)configname, 256, "%s.%s.revokeCert", OP_PREFIX, tokenType); + bool revokeCert = RA::GetConfigStore()->GetConfigAsBool(configname, true); + if (revokeCert) { + char *attr_cn = RA::ra_get_cert_cn(e); + PR_snprintf((char *)configname, 256, "%s.%s.ca.conn", OP_PREFIX, + tokenType); + char *connid = (char *)(RA::GetConfigStore()->GetConfigAsString(configname)); + if (connid == NULL) { + RA::Debug(LL_PER_PDU, "RA_Processor::RevokeCertificates", "Failed to get connection."); + status = STATUS_ERROR_REVOKE_CERTIFICATES_FAILED; + PR_snprintf(audit_msg, 512, "Failed to connect to CA, status = STATUS_ERROR_REVOKE_CERTIFICATES_FAILED"); + + revocation_failed = true; + goto loser; + } + PR_snprintf(serial, 100, "0x%s", attr_serial); + + // if the certificates are revoked_on_hold, dont do + // anything because the certificates may be referenced + // by more than one token. + if (strcmp(attr_status, "revoked_on_hold") == 0) { + RA::Debug("RA_Processor::RevokeCertificates", "This is revoked_on_hold certificate, skip it."); + if (attr_status != NULL) { + PL_strfree(attr_status); + attr_status = NULL; + } + if (attr_serial != NULL) { + PL_strfree(attr_serial); + attr_serial = NULL; + } + if (attr_cn != NULL) { + PL_strfree(attr_cn); + attr_cn = NULL; + } + + rc = RA::ra_delete_certificate_entry(e); + continue; + } + statusNum = certEnroll->RevokeCertificate("1", serial, connid, statusString); + RA::Debug("RA_Processor::RevokeCertificates", "Revoke cert %s status %d",serial,statusNum); + + if (statusNum == 0) { + RA::Audit(EV_FORMAT, AUDIT_MSG_CERT_STATUS_CHANGE, userid, + "Success", "revoke", serial, connid, ""); + PR_snprintf(activity_msg, 512, "certificate %s revoked", serial); + RA::tdb_activity(session->GetRemoteIP(), cuid, "format", "success", activity_msg, "", tokenType); + RA::ra_update_cert_status(attr_cn, "revoked"); + } else { + RA::Audit(EV_FORMAT, AUDIT_MSG_CERT_STATUS_CHANGE, userid, + "Failure", "revoke", serial, connid, statusString); + PR_snprintf(activity_msg, 512, "error in revoking certificate %s: %s", serial, statusString); + RA::tdb_activity(session->GetRemoteIP(), cuid, "format", "failure", activity_msg, "", tokenType); + revocation_failed = true; + } + + if (attr_status != NULL) { + PL_strfree(attr_status); + attr_status = NULL; + } + if (attr_serial != NULL) { + PL_strfree(attr_serial); + attr_serial = NULL; + } + if (attr_cn != NULL) { + PL_strfree(attr_cn); + attr_cn = NULL; + } + if (statusString != NULL) { + PR_Free(statusString); + statusString = NULL; + } + } + rc = RA::ra_delete_certificate_entry(e); + } + if (result != NULL) + ldap_msgfree(result); + if (certEnroll != NULL) + delete certEnroll; + } else { + RA::Debug(LL_PER_PDU, "RA_Processor::RevokeCertificates", "Failed to revoke certificates on this token. Certs not found."); + status = STATUS_ERROR_REVOKE_CERTIFICATES_FAILED; + PR_snprintf(audit_msg, 512, "Failed to revoke certificates on this token. Certs not found. status = STATUS_ERROR_REVOKE_CERTIFICATES_FAILED"); + revocation_failed = true; + goto loser; + } + + rc = 0; + if (keyVersion != NULL) { + rc = RA::tdb_update("", cuid, (char *)final_applet_version, keyVersion, "uninitialized", "", tokenType); + } + + if (rc != 0) { + RA::Debug(LL_PER_PDU, "RA_Processor::RevokeCertificates", + "Failed to update the token database"); + status = STATUS_ERROR_UPDATE_TOKENDB_FAILED; + PR_snprintf(audit_msg, 512, "Revoked certificates but failed to update the token database, status = STATUS_ERROR_UPDATE_TOKENDB_FAILED"); + goto loser; + } + +loser: + + return !revocation_failed; +} + +RA_Status RA_Processor::Format(RA_Session *session, NameValueSet *extensions, bool skipAuth) +{ + const char *OP_PREFIX="op.format"; + char configname[256]; + char *cuid = NULL; + char *msn = NULL; + const char *tokenType = NULL; + PRIntervalTime start, end; + RA_Status status = STATUS_NO_ERROR; + int rc = -1; + Secure_Channel *channel = NULL; + Buffer kdd; + AuthParams *login = NULL; + // char *new_pin = NULL; + const char *applet_dir; + bool upgrade_enc = false; + SecurityLevel security_level = SECURE_MSG_MAC_ENC; + + Buffer *buildID = NULL; + Buffer *token_status = NULL; + const char* required_version = NULL; + const char *appletVersion = NULL; + const char *final_applet_version = NULL; + const char *userid = PL_strdup( "" ); + // BYTE se_p1 = 0x00; + // BYTE se_p2 = 0x00; + const char *expected_version; + int requiredV = 0; + const char *tksid = NULL; + const char *authid = NULL; + AuthParams *authParams = NULL; + Buffer host_challenge = Buffer(8, (BYTE)0); + Buffer key_diversification_data; + Buffer key_info_data; + Buffer card_challenge; + Buffer card_cryptogram; + Buffer *cplc_data = NULL; + char activity_msg[4096]; + LDAPMessage *ldapResult = NULL; + LDAPMessage *e = NULL; + LDAPMessage *result = NULL; + char filter[512]; + Buffer curKeyInfo; + BYTE curVersion; + char *curKeyInfoStr = NULL; + char *newVersionStr = NULL; + bool tokenFound = false; + int finalKeyVersion = 0; + char *keyVersion = NULL; + char *xuserid = NULL; + char audit_msg[512] = ""; + char *profile_state = NULL; + + Buffer *CardManagerAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_CARDMGR_INSTANCE_AID, + RA::CFG_DEF_CARDMGR_INSTANCE_AID); + Buffer *NetKeyAID = RA::GetConfigStore()->GetConfigAsBuffer( + RA::CFG_APPLET_NETKEY_INSTANCE_AID, + RA::CFG_DEF_NETKEY_INSTANCE_AID); + Buffer key_data_set; + Buffer token_cuid; + Buffer token_msn; + RA::Debug(LL_PER_PDU, "RA_Processor::Format", + "Begin upgrade process"); + + BYTE major_version = 0x0; + BYTE minor_version = 0x0; + BYTE app_major_version = 0x0; + BYTE app_minor_version = 0x0; + const char *connid = NULL; + int upgrade_rc; + + start = PR_IntervalNow(); + + RA::Debug("RA__Processor::Format", "Client %s", session->GetRemoteIP()); + + + SelectApplet(session, 0x04, 0x00, CardManagerAID); + cplc_data = GetData(session); + if (cplc_data == NULL) { + RA::Error("RA_Format_Processor::Process", + "Get Data Failed"); + status = STATUS_ERROR_SECURE_CHANNEL; + PR_snprintf(audit_msg, 512, "Get Data Failed, status = STATUS_ERROR_SECURE_CHANNEL"); + goto loser; + } + RA::DebugBuffer("RA_Processor::Format", "CPLC Data = ", + cplc_data); + if (cplc_data->size() < 47) { + RA::Error("RA_Format_Processor::Process", + "Invalid CPLC Size"); + status = STATUS_ERROR_SECURE_CHANNEL; + PR_snprintf(audit_msg, 512, "Invalid CPLC Size, status = STATUS_ERROR_SECURE_CHANNEL"); + goto loser; + } + token_cuid = Buffer(cplc_data->substr(3,4)) + + Buffer(cplc_data->substr(19,2)) + + Buffer(cplc_data->substr(15,4)); + RA::DebugBuffer("RA_Processor::Format", "Token CUID= ", + &token_cuid); + cuid = Util::Buffer2String(token_cuid); + + token_msn = Buffer(cplc_data->substr(41, 4)); + RA::DebugBuffer("RA_Processor::Format", "Token MSN= ", + &token_msn); + msn = Util::Buffer2String(token_msn); + + + /** + * Checks if the netkey has the required applet version. + */ + SelectApplet(session, 0x04, 0x00, NetKeyAID); + token_status = GetStatus(session, 0x00, 0x00); + if (token_status == NULL) { + major_version = 0; + minor_version = 0; + app_major_version = 0x0; + app_minor_version = 0x0; + } else { + major_version = ((BYTE*)*token_status)[0]; + minor_version = ((BYTE*)*token_status)[1]; + app_major_version = ((BYTE*)*token_status)[2]; + app_minor_version = ((BYTE*)*token_status)[3]; + } + + RA::Debug(LL_PER_PDU, "RA_Processor::Format", + "Major=%d Minor=%d", major_version, minor_version); + RA::Debug(LL_PER_PDU, "RA_Processor::Format", + "Applet Major=%d Applet Minor=%d", app_major_version, app_minor_version); + + if (!GetTokenType(OP_PREFIX, major_version, + minor_version, cuid, msn, + extensions, status, tokenType)) { + PR_snprintf(audit_msg, 512, "Failed to get token type"); + goto loser; + } + + // check if profile is enabled + PR_snprintf((char *)configname, 256, "config.Profiles.%s.state", tokenType); + profile_state = (char *) RA::GetConfigStore()->GetConfigAsString(configname); + if ((profile_state != NULL) && (PL_strcmp(profile_state, "Enabled") != 0)) { + RA::Error("RA_Format_Processor::Process", "Profile %s Disabled for CUID %s", tokenType, cuid); + status = STATUS_ERROR_DEFAULT_TOKENTYPE_PARAMS_NOT_FOUND; + PR_snprintf(audit_msg, 512, "profile %s disabled", tokenType); + goto loser; + } + + if (RA::ra_is_token_present(cuid)) { + RA::Debug("RA_Processor::Format", + "Found token %s", cuid); + + if (RA::ra_is_tus_db_entry_disabled(cuid)) { + RA::Error("RA_Format_Processor::Process", + "CUID %s Disabled", cuid); + status = STATUS_ERROR_DISABLED_TOKEN; + PR_snprintf(audit_msg, 512, "CUID %s Disabled, status=STATUS_ERROR_DISABLED_TOKEN", cuid); + goto loser; + } + } else { + RA::Debug("RA_Processor::Format", + "Not Found token %s", cuid); + // This is a new token. We need to check our policy to see + // if we should allow enrollment. raidzilla #57414 + PR_snprintf((char *)configname, 256, "%s.allowUnknownToken", + OP_PREFIX); + if (!RA::GetConfigStore()->GetConfigAsBool(configname, 1)) { + RA::Error("Process", "CUID %s Format Unknown Token", cuid); + status = STATUS_ERROR_DISABLED_TOKEN; + PR_snprintf(audit_msg, 512, "Unknown token disallowed, status=STATUS_ERROR_DISABLED_TOKEN"); + goto loser; + } + + } + + // we know cuid and msn here + RA::Audit(EV_FORMAT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "format", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "token enabled"); + + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", + OP_PREFIX, tokenType); + tksid = RA::GetConfigStore()->GetConfigAsString(configname); + if (tksid == NULL) { + RA::Error("RA_Format_Processor::Process", + "TKS Connection Parameter %s Not Found", configname); + status = STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND; + PR_snprintf(audit_msg, 512, "TKS Connection Parameter %s Not Found, status = STATUS_ERROR_DEFAULT_TOKENTYPE_NOT_FOUND", configname); + goto loser; + } + + buildID = GetAppletVersion(session); + if (buildID == NULL) { + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.emptyToken.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + appletVersion = PL_strdup( "" ); + } else { + RA::Error("RA_Format_Processor::Process", + "no applet found and applet upgrade not enabled"); + status = STATUS_ERROR_SECURE_CHANNEL; + PR_snprintf(audit_msg, 512, "No applet found and applet upgrade not enabled, status = STATUS_ERROR_SECURE_CHANNEL"); + goto loser; + } + } else { + char * buildid = Util::Buffer2String(*buildID); + RA::Debug("RA_Processor::Format", "buildid = %s", buildid); + char version[13]; + PR_snprintf((char *) version, 13, + "%x.%x.%s", app_major_version, app_minor_version, + buildid); + appletVersion = strdup(version); + if (buildid != NULL) { + PR_Free(buildid); + buildid=NULL; + } + } + + final_applet_version = strdup(appletVersion); + RA::Debug("RA_Processor::Format", "final_applet_version = %s", final_applet_version); + + /** + * Checks if we need to upgrade applet. + */ + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.requiredVersion", OP_PREFIX, tokenType); + + required_version = RA::GetConfigStore()->GetConfigAsString( + configname); + expected_version = PL_strdup(required_version); + + if (expected_version == NULL) { + RA::Error("RA_Format_Processor::Process", + "upgrade.version not found"); + status = STATUS_ERROR_MISCONFIGURATION; + PR_snprintf(audit_msg, 512, "Upgrade version not found, status = STATUS_ERROR_MISCONFIGURATION"); + goto loser; + } + /* upgrade applet */ + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.directory", OP_PREFIX, tokenType); + applet_dir = RA::GetConfigStore()->GetConfigAsString(configname); + if (applet_dir == NULL || strlen(applet_dir) == 0) { + RA::Error(LL_PER_PDU, "RA_Processor::UpdateApplet", + "Failed to get %s", applet_dir); + status = STATUS_ERROR_MISCONFIGURATION; + PR_snprintf(audit_msg, 512, "Failed to get %s, status = STATUS_ERROR_MISCONFIGURATION", applet_dir); + goto loser; + } + + PR_snprintf((char *)configname, 256, "%s.%s.loginRequest.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 1) && !skipAuth) { + if (extensions != NULL && + extensions->GetValue("extendedLoginRequest") != NULL) + { + RA::Debug("RA_rocessor::Format", + "Extended Login Request detected"); + AuthenticationEntry *entry = GetAuthenticationEntry( + OP_PREFIX, configname, tokenType); + char **params = NULL; + char pb[1024]; + char *locale = NULL; + if (extensions != NULL && + extensions->GetValue("locale") != NULL) + { + locale = extensions->GetValue("locale"); + } else { + locale = ( char * ) "en"; /* default to english */ + } + int n = entry->GetAuthentication()->GetNumOfParamNames(); + if (n > 0) { + RA::Debug("RA_Processor::Format", + "Extended Login Request detected n=%d", n); + params = (char **) PR_Malloc(n); + for (int i = 0; i < n; i++) { + sprintf(pb,"id=%s&name=%s&desc=%s&type=%s&option=%s", + entry->GetAuthentication()->GetParamID(i), + entry->GetAuthentication()->GetParamName(i, locale), + entry->GetAuthentication()->GetParamDescription(i, +locale), + entry->GetAuthentication()->GetParamType(i), + entry->GetAuthentication()->GetParamOption(i) + ); + params[i] = PL_strdup(pb); + RA::Debug("RA_Processor::Format", + "params[i]=%s", params[i]); + } + } + RA::Debug("RA_rocessor::Format", "Extended Login Request detected calling RequestExtendedLogin() locale=%s", locale); + + char *title = PL_strdup(entry->GetAuthentication()->GetTitle(locale)); + RA::Debug("RA_Processor::Format", "title=%s", title); + char *description = PL_strdup(entry->GetAuthentication()->GetDescription(locale)); + RA::Debug("RA_Processor::Format", "description=%s", description); + login = RequestExtendedLogin(session, 0 /* invalid_pw */, 0 /* blocked */, params, n, title, description); + + if (params != NULL) { + for (int nn=0; nn < n; nn++) { + if (params[nn] != NULL) { + PL_strfree(params[nn]); + params[nn] = NULL; + } + } + free(params); + params = NULL; + } + + if (title != NULL) { + PL_strfree(title); + title = NULL; + } + + if (description != NULL) { + PL_strfree(description); + description = NULL; + } + + + RA::Debug("RA_Processor::Format", + "Extended Login Request detected calling RequestExtendedLogin() login=%x", login); + } else { + login = RequestLogin(session, 0 /* invalid_pw */, 0 /* blocked */); + } + if (login == NULL) { + RA::Error("RA_Format_Processor::Process", + "login not provided"); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "login not provided, status = STATUS_ERROR_LOGIN"); + goto loser; + } + if( userid != NULL ) { + PR_Free( (char *) userid ); + userid = NULL; + } + if (login->GetUID() == NULL) { + userid = NULL; + } else { + userid = PL_strdup( login->GetUID() ); + } + } + + // send status update to the client + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 2 /* progress */, + "PROGRESS_START_AUTHENTICATION"); + } + + PR_snprintf((char *)configname, 256, "%s.%s.auth.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, false) && !skipAuth) { + if (login == NULL) { + RA::Error("RA_Format_Processor::Process", "Login Request Disabled. Authentication failed."); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "login request disabled, status = STATUS_ERROR_LOGIN"); + goto loser; + } + + PR_snprintf((char *)configname, 256, "%s.%s.auth.id", OP_PREFIX, tokenType); + authid = RA::GetConfigStore()->GetConfigAsString(configname); + if (authid == NULL) { + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "login not found, status = STATUS_ERROR_LOGIN"); + goto loser; + } + AuthenticationEntry *auth = RA::GetAuth(authid); + + if(auth == NULL) + { + RA::Error("RA_Format_Processor::Process", "Authentication manager is NULL . Authentication failed."); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "authentication manager is NULL, status = STATUS_ERROR_LOGIN"); + goto loser; + } + + char *type = auth->GetType(); + if (type == NULL) { + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "authentication is missing param type, status = STATUS_ERROR_LOGIN"); + goto loser; + } + if (strcmp(type, "LDAP_Authentication") == 0) { + RA::Debug(LL_PER_PDU, "RA_Format_Processor::Process", + "LDAP_Authentication is invoked."); + int passwd_retries = auth->GetAuthentication()->GetNumOfRetries(); + int retries = 0; + authParams = new AuthParams(); + authParams->SetUID(login->GetUID()); + authParams->SetPassword(login->GetPassword()); + rc = auth->GetAuthentication()->Authenticate(authParams); + + RA::Debug("RA_Format_Processor::Process", + "Authenticate returns: %d", rc); + + while ((rc == -2 || rc == -3) && (retries < passwd_retries)) { + login = RequestLogin(session, 0 /* invalid_pw */, 0 /* blocked */); + retries++; + if (login == NULL || login->GetUID() == NULL) { + RA::Error("RA_Format_Processor::Process", "Authentication failed."); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "authentication failed, status = STATUS_ERROR_LOGIN"); + goto loser; + } + authParams->SetUID(login->GetUID()); + authParams->SetPassword(login->GetPassword()); + rc = auth->GetAuthentication()->Authenticate(authParams); + } + + if (rc == -1) { + RA::Error("RA_Format_Processor::Process", "Authentication failed."); + status = STATUS_ERROR_LDAP_CONN; + RA::Debug(LL_PER_PDU, "RA_Processor::Format", "Authentication status = %d", status); + PR_snprintf(audit_msg, 512, "Authentication failed, status = STATUS_ERROR_LDAP_CONN"); + goto loser; + } + + if (rc == -2 || rc == -3) { + RA::Error("RA_Format_Processor::Process", "Authentication failed."); + status = STATUS_ERROR_LOGIN; + RA::Debug(LL_PER_PDU, "RA_Processor::Format", "Authentication status = %d", status); + PR_snprintf(audit_msg, 512, "Authentication failed, rc=-2 or -3, status = STATUS_ERROR_LOGIN"); + goto loser; + } + + RA::Debug(LL_PER_PDU, "RA_Processor::Format", "Authentication successful."); + } else { + RA::Error("RA_Format_Processor::Process", "No Authentication type was found."); + status = STATUS_ERROR_LOGIN; + PR_snprintf(audit_msg, 512, "No Authentication type found, status = STATUS_ERROR_LOGIN"); + goto loser; + } + } else { + RA::Debug(LL_PER_PDU, "RA_Processor::Format", + "Authentication has been disabled."); + } + + // check if it is the token owner + xuserid = RA::ra_get_token_userid(cuid); + if (xuserid != NULL && strcmp(xuserid, "") != 0) { + if (login != NULL) { + if (strcmp(login->GetUID(), xuserid) != 0) { + RA::Debug(LL_PER_PDU, "RA_Processor::Format", + "Token owner mismatched"); + status = STATUS_ERROR_NOT_TOKEN_OWNER; + PR_snprintf(audit_msg, 512, "Token owner mismatched, status = STATUS_ERROR_NOT_TOKEN_OWNER"); + goto loser; + } + } + } + + // we know cuid, msn and userid here + RA::Audit(EV_FORMAT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "success", + "format", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + "logged into token"); + + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 10 /* progress */, + "PROGRESS_APPLET_UPGRADE"); + } + + PR_snprintf((char *)configname, 256, "%s.%s.update.applet.encryption", OP_PREFIX, tokenType); + upgrade_enc = RA::GetConfigStore()->GetConfigAsBool(configname, true); + if (!upgrade_enc) + security_level = SECURE_MSG_MAC; + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + connid = RA::GetConfigStore()->GetConfigAsString(configname); + upgrade_rc = UpgradeApplet(session,(char *) OP_PREFIX, (char*)tokenType, major_version, + minor_version, expected_version, applet_dir, security_level, connid, + extensions, 10, 90, &keyVersion); + if (upgrade_rc != 1) { + RA::Debug("RA_Processor::Format", + "applet upgrade failed"); + status = STATUS_ERROR_UPGRADE_APPLET; + /** + * Bugscape #55709: Re-select Net Key Applet ONLY on failure. + */ + SelectApplet(session, 0x04, 0x00, NetKeyAID); + RA::tdb_activity(session->GetRemoteIP(), cuid, "format", "failure", "applet upgrade error", "", tokenType); + // rc = -1 denotes Secure Channel Failure + + if (rc == -1) { + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Failure", "format", + keyVersion != NULL? keyVersion : "", appletVersion, expected_version, "failed to setup secure channel"); + } else { + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Success", "format", + keyVersion != NULL? keyVersion : "", appletVersion, expected_version, "setup secure channel"); + } + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Failure", "format", + keyVersion != NULL? keyVersion : "", appletVersion, expected_version, "applet upgrade"); + + goto loser; + } + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Success", "format", + keyVersion != NULL? keyVersion : "", appletVersion, expected_version, "setup secure channel"); + + RA::Audit(EV_APPLET_UPGRADE, AUDIT_MSG_APPLET_UPGRADE, + userid, cuid, msn, "Success", "format", + keyVersion != NULL? keyVersion : "", appletVersion, expected_version, "applet upgrade"); + + if( final_applet_version != NULL ) { + PR_Free( (char *) final_applet_version ); + final_applet_version = NULL; + } + + final_applet_version = expected_version; + + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 90 /* progress */, + "PROGRESS_KEY_UPGRADE"); + } + + // add issuer info to the token + PR_snprintf((char *)configname, 256, "%s.%s.issuerinfo.enable", + OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 0)) { + PR_snprintf((char *)configname, 256,"channel.defKeyIndex"); + int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + channel = SetupSecureChannel(session, 0x00, + defKeyIndex /* default key index */, connid); + rc = channel->ExternalAuthenticate(); + if (channel != NULL) { + char issuer[224]; + for (int i = 0; i < 224; i++) { + issuer[i] = 0; + } + PR_snprintf((char *)configname, 256, "%s.%s.issuerinfo.value", + OP_PREFIX, tokenType); + char *issuer_val = (char*)RA::GetConfigStore()->GetConfigAsString( + configname); + sprintf(issuer, "%s", issuer_val); + RA::Debug("RA_Processor::Format", "Set Issuer Info %s", issuer_val); + Buffer *info = new Buffer((BYTE*)issuer, 224); + rc = channel->SetIssuerInfo(info); + + if (info != NULL) { + delete info; + info = NULL; + } + } + } + + /** + * Checks if the netkey has the required key version. + */ + PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.enable", OP_PREFIX, tokenType); + if (RA::GetConfigStore()->GetConfigAsBool(configname, 1)) { + + PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.requiredVersion", OP_PREFIX, tokenType); + requiredV = RA::GetConfigStore()->GetConfigAsInt(configname, 0x00); + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + tksid = RA::GetConfigStore()->GetConfigAsString(configname); + PR_snprintf((char *)configname, 256,"channel.defKeyIndex"); + int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + channel = SetupSecureChannel(session, requiredV, + defKeyIndex /* default key index */, tksid); + if (channel == NULL) { + /** + * Select Card Manager for Put Key operation. + */ + SelectApplet(session, 0x04, 0x00, CardManagerAID); + // send status update to the client + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 92 /* progress */, + "PROGRESS_SETUP_SECURE_CHANNEL"); + } + /* if the key of the required version is + * not found, create them. + */ + PR_snprintf((char *)configname, 256,"channel.defKeyVersion"); + int defKeyVer = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + PR_snprintf((char *)configname, 256,"channel.defKeyIndex"); + int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0); + channel = SetupSecureChannel(session, + defKeyVer, /* default key version */ + defKeyIndex /* default key index */, tksid); + + if (channel == NULL) { + RA::Error("RA_Upgrade_Processor::Process", + "failed to establish secure channel"); + status = STATUS_ERROR_SECURE_CHANNEL; + PR_snprintf(audit_msg, 512, "Failed to establish secure channel"); + goto loser; + } + + // send status update to the client + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 94 /* progress */, + "PROGRESS_EXTERNAL_AUTHENTICATE"); + } + + rc = channel->ExternalAuthenticate(); + + PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.requiredVersion", OP_PREFIX, tokenType); + int v = RA::GetConfigStore()->GetConfigAsInt(configname, 0x00); + curKeyInfo = channel->GetKeyInfoData(); + BYTE nv[2] = { v, 0x01 }; + Buffer newVersion(nv, 2); + PR_snprintf((char *)configname, 256,"%s.%s.tks.conn", OP_PREFIX, tokenType); + connid = RA::GetConfigStore()->GetConfigAsString(configname); + rc = CreateKeySetData( + channel->GetKeyDiversificationData(), + curKeyInfo, + newVersion, + key_data_set, connid); + if (rc != 1) { + RA::Error("RA_Format_Processor::Process", + "failed to create new key set"); + status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512, "create key set error, status = STATUS_ERROR_CREATE_CARDMGR"); + goto loser; + } + + curVersion = ((BYTE*)curKeyInfo)[0]; + + + // send status update to the client + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 96 /* progress */, + "PROGRESS_PUT_KEYS"); + } + + BYTE curIndex = ((BYTE*)curKeyInfo)[1]; + rc = channel->PutKeys(session, + curVersion, + curIndex, + &key_data_set); + + + // need to check return value of rc + // and create audit log for failure + + curKeyInfoStr = Util::Buffer2String(curKeyInfo); + newVersionStr = Util::Buffer2String(newVersion); + + char curVer[10]; + char newVer[10]; + + if(curKeyInfoStr != NULL && strlen(curKeyInfoStr) >= 2) { + curVer[0] = curKeyInfoStr[0]; curVer[1] = curKeyInfoStr[1]; curVer[2] = 0; + } + else { + curVer[0] = 0; + } + + if(newVersionStr != NULL && strlen(newVersionStr) >= 2) { + newVer[0] = newVersionStr[0] ; newVer[1] = newVersionStr[1] ; newVer[2] = 0; + } + else { + newVer[0] = 0; + } + + if (rc != 0) { + RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER, + userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "Failure", "format", + final_applet_version != NULL ? final_applet_version : "", curVer, newVer, + "key changeover failed"); + // do we goto loser here? + } + + finalKeyVersion = ((int) ((BYTE *)newVersion)[0]); + /** + * Re-select Net Key Applet. + */ + SelectApplet(session, 0x04, 0x00, NetKeyAID); + PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.requiredVersion", OP_PREFIX, tokenType); + requiredV = RA::GetConfigStore()->GetConfigAsInt(configname, 0x00); + PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType); + tksid = RA::GetConfigStore()->GetConfigAsString(configname); + if( channel != NULL ) { + delete channel; + channel = NULL; + } + // send status update to the client + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 98 /* progress */, + "PROGRESS_SETUP_SECURE_CHANNEL"); + } + + + channel = SetupSecureChannel(session, requiredV, + defKeyIndex /* default key index */, tksid); + if (channel == NULL) { + RA::Error("RA_Format_Processor::Process", + "failed to establish secure channel after reselect"); + status = STATUS_ERROR_CREATE_CARDMGR; + PR_snprintf(audit_msg, 512,"failed to establish secure channel after reselect, status = STATUS_ERROR_CREATE_CARDMGR"); + goto loser; + } + + RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER, + userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "Success", "format", + final_applet_version != NULL ? final_applet_version : "", curVer, newVer, + "key changeover"); + + } + } + + PR_snprintf((char *)filter, 256, "(cn=%s)", cuid); + rc = RA::ra_find_tus_token_entries(filter, 100, &result, 0); + if (rc == 0) { + for (e = RA::ra_get_first_entry(result); e != NULL; e = RA::ra_get_next_entry(e)) { + tokenFound = true; + break; + } + if (result != NULL) + ldap_msgfree(result); + } + + // get keyVersion + if (channel != NULL) { + if (keyVersion != NULL) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + keyVersion = Util::Buffer2String(channel->GetKeyInfoData()); + } + + // need to revoke all the certificates on this token + if (tokenFound) { + + //Now we call a separate function, the audit_msg will get filled in there if needed. + + bool success = RevokeCertificates(session, cuid,audit_msg,(char *)final_applet_version, + keyVersion,(char *)tokenType,(char *)userid,status + ); + + if(!success) { + goto loser; + } + + } else { + rc = RA::tdb_update("", cuid, (char *)final_applet_version, keyVersion, "uninitialized", "", tokenType); + if (rc != 0) { + RA::Debug(LL_PER_PDU, "RA_Processor::Format", + "Failed to update the token database"); + status = STATUS_ERROR_UPDATE_TOKENDB_FAILED; + PR_snprintf(audit_msg, 512, "Failed to update the token database, status = STATUS_ERROR_UPDATE_TOKENDB_FAILED"); + goto loser; + } + } + + // send status update to the client + if (extensions != NULL && + extensions->GetValue("statusUpdate") != NULL) { + StatusUpdate(session, 100 /* progress */, + "PROGRESS_DONE"); + } + + status = STATUS_NO_ERROR; + rc = 1; + + end = PR_IntervalNow(); + + sprintf(activity_msg, "applet_version=%s tokenType=%s", + final_applet_version, tokenType); + RA::tdb_activity(session->GetRemoteIP(), cuid, "format", "success", activity_msg, userid, tokenType); + + /* audit log for successful format */ + if (authid != NULL) { + sprintf(activity_msg, "format processing complete, authid = %s", authid); + } else { + sprintf(activity_msg, "format processing complete"); + } + RA::Audit(EV_FORMAT, AUDIT_MSG_PROC, + userid, cuid, msn, "success", "format", final_applet_version, + keyVersion != NULL? keyVersion : "", activity_msg); + +loser: + if (strlen(audit_msg) > 0) { // a failure occurred + RA::Audit(EV_FORMAT, AUDIT_MSG_PROC, + userid != NULL ? userid : "", + cuid != NULL ? cuid : "", + msn != NULL ? msn : "", + "failure", + "format", + final_applet_version != NULL ? final_applet_version : "", + keyVersion != NULL? keyVersion : "", + audit_msg); + + if ((cuid != NULL) && (tokenType != NULL)) { + RA::tdb_activity(session->GetRemoteIP(), + cuid, + "format", + "failure", + audit_msg, + userid != NULL? userid : "", + tokenType); + } + } + + if (curKeyInfoStr != NULL) { + PR_Free( (char *) curKeyInfoStr); + curKeyInfoStr = NULL; + } + + if (newVersionStr != NULL) { + PR_Free( (char *) newVersionStr); + newVersionStr = NULL; + } + + if (keyVersion != NULL) { + PR_Free( (char *) keyVersion ); + keyVersion = NULL; + } + + if (ldapResult != NULL) { + ldap_msgfree(ldapResult); + } + + if( cplc_data != NULL ) { + delete cplc_data; + cplc_data = NULL; + } + if( CardManagerAID != NULL ) { + delete CardManagerAID; + CardManagerAID = NULL; + } + if( NetKeyAID != NULL ) { + delete NetKeyAID; + NetKeyAID = NULL; + } + if( channel != NULL ) { + delete channel; + channel = NULL; + } + if( token_status != NULL ) { + delete token_status; + token_status = NULL; + } + if( buildID != NULL ) { + delete buildID; + buildID = NULL; + } + if( appletVersion != NULL ) { + PR_Free( (char *) appletVersion ); + appletVersion = NULL; + } + if( final_applet_version != NULL ) { + PR_Free( (char *) final_applet_version ); + final_applet_version = NULL; + } + if( userid != NULL ) { + PR_Free( (char *) userid ); + userid = NULL; + } + if( cuid != NULL ) { + PR_Free( cuid ); + cuid = NULL; + } + if( msn != NULL ) { + PR_Free( msn ); + msn = NULL; + } + if( authParams != NULL ) { + delete authParams; + authParams = NULL; + } + if( login != NULL ) { + delete login; + login = NULL; + } + +#ifdef MEM_PROFILING + MEM_dump_unfree(); +#endif + + RA::Debug("RA_Processor::Format"," returning status %d", status); + return status; +} + +/** + * Process the current session. It does nothing in the base + * class. + */ +RA_Status RA_Processor::Process(RA_Session *session, NameValueSet *extensions) +{ + return STATUS_NO_ERROR; +} /* Process */ + diff --git a/base/tps/src/processor/RA_Renew_Processor.cpp b/base/tps/src/processor/RA_Renew_Processor.cpp new file mode 100644 index 000000000..5caa329b4 --- /dev/null +++ b/base/tps/src/processor/RA_Renew_Processor.cpp @@ -0,0 +1,57 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#include "engine/RA.h" +#include "main/RA_Msg.h" +#include "main/RA_Session.h" +#include "processor/RA_Processor.h" +#include "processor/RA_Renew_Processor.h" +#include "main/Memory.h" + +#ifdef XP_WIN32 +#define TPS_PUBLIC __declspec(dllexport) +#else /* !XP_WIN32 */ +#define TPS_PUBLIC +#endif /* !XP_WIN32 */ + +/** + * Constructs a renew processor. + */ +TPS_PUBLIC RA_Renew_Processor::RA_Renew_Processor() +{ +} + +/** + * Destructs a renew processor. + */ +TPS_PUBLIC RA_Renew_Processor::~RA_Renew_Processor() +{ +} + +/** + * Processes the current session. + */ +TPS_PUBLIC RA_Status RA_Renew_Processor::Process(RA_Session *session, NameValueSet *extensions) +{ + RA::Debug("RA_Renew_Processor::Process", + "RA_Renew_Processor::Process"); + + return STATUS_NO_ERROR; +} diff --git a/base/tps/src/processor/RA_Unblock_Processor.cpp b/base/tps/src/processor/RA_Unblock_Processor.cpp new file mode 100644 index 000000000..0bdbcfa2b --- /dev/null +++ b/base/tps/src/processor/RA_Unblock_Processor.cpp @@ -0,0 +1,58 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#include "engine/RA.h" +#include "main/RA_Msg.h" +#include "main/RA_Session.h" +#include "processor/RA_Processor.h" +#include "processor/RA_Unblock_Processor.h" +#include "main/Memory.h" + +#ifdef XP_WIN32 +#define TPS_PUBLIC __declspec(dllexport) +#else /* !XP_WIN32 */ +#define TPS_PUBLIC +#endif /* !XP_WIN32 */ + +/** + * Constructs the unblock processor. + */ +TPS_PUBLIC RA_Unblock_Processor::RA_Unblock_Processor() +{ +} /* RA_Unblock_Processor */ + +/** + * Destructs the unblock processor. + */ +TPS_PUBLIC RA_Unblock_Processor::~RA_Unblock_Processor() +{ +} /* RA_Unblock_Processor */ + +/** + * Processes the current session. + */ +TPS_PUBLIC RA_Status RA_Unblock_Processor::Process(RA_Session *session, NameValueSet *extensions) +{ + RA::Debug("RA_Unblock_Processor::Process", "Client %s", session->GetRemoteIP()); + + RA::Debug("RA_Unblock_Processor::Process", + "RA_Unblock_Processor::Process"); + return STATUS_NO_ERROR; +} /* Process */ |